mirrormagic-3.0.0/0000755000175000017500000000000013263214225013333 5ustar aeglosaeglosmirrormagic-3.0.0/INSTALL0000644000175000017500000000271413263212010014356 0ustar aeglosaeglos=============================================================================== Compiling and installing Rocks'n'Diamonds =============================================================================== To compile the game, you either need the new SDL2 library (recommended) or the old SDL 1.2 library. In addition, you also need the libraries SDL_image, SDL_mixer (including the SMPEG library if you want MP3 support) and SDL_net. Please install these libraries before building Rocks'n'Diamonds. ------------------------------------------------------------------------------- Linux and other Unix systems (including Mac OS X): ------------------------------------------------------------------------------- Just run "make" to build the game using either SDL2 or SDL (whatever being available). Run "make sdl" or "make sdl2" to explicitly use either SDL 1.2 or SDL2. ------------------------------------------------------------------------------- Windows with gcc (native or cross-compiling) ------------------------------------------------------------------------------- To build the game natively, just proceed as described above for Unix systems. To cross-compile the game for Windows, run "cross-win32". You probably have to adjust the path to the Windows cross-compiler defined in "CROSS_PATH_WIN32" in the top-level Makefile. That's all! If you have any comments, corrections or suggestions regarding the Makefiles, please let me know at "info@artsoft.org". Thanks! mirrormagic-3.0.0/ChangeLog0000644000175000017500000036606313263212010015111 0ustar aeglosaeglos2015-06-21 * extended automatic tape playing modes: - "autotest" to automatically test tapes (this was "autoplay" before) - "autoplay" to automatically play tapes (visibly) - "autoffwd" to automatically play tapes (visibly, with maximum speed) 2015-06-16 * fixed and enhanced screen fading and background/border handling 2015-05-31 * added setup option to enable/disable (now optional) snapshot buttons 2015-04-22 * added lag prevention to door/request/envelope animations 2015-04-15 * added option "program_icon_file" to run-time "special edition" support 2015-04-14 * added run-time "special edition" support; this change is especially targeted to the "R'n'D jue" special edition of R'n'D, which changed some defaults at compile-time in previous versions, like: - using a different default artwork set (with fallback artwork for classic artwork not existing in the special edition), - using a different default level set, - using a different program name and user data directory, - starting with different default setup values and - using custom artwork even at a very early stage of startup (like initial fonts and initial loading/busy animation); these changes can now all be accomplished at run-time by using a new program-specific configuration file in the same location and with the same name as the game binary (minus a potential binary file extension ".exe", plus a configuration file extension ".conf", so a binary file "rnd_jue.exe" would be complemented by a new file "rnd_jue.conf" in the same directory); this config file can contain all options found in "setup.conf" plus the following new, internal "special edition" default settings: - program_title (like "R'n'D jue") - program_author (like "Juergen Bonhagen") - program_email (like "jue@artsoft.org") - program_website (like "http://jue.artsoft.org/") - program_copyright (like "(c) 2015 by jue") - program_company (like "A game by jue") - default_graphics_set (like "jue0") - default_sounds_set (like "jue0") - default_music_set (like "jue0") - fallback_graphics_file (like "fallback.png") - fallback_sounds_file (like "fallback.wav") - fallback_music_file (like "fallback.wav") - default_level_series (like "jue_start") - choose_from_top_leveldir ("true" or "false") where the "default" artwork set definitions are used to specify new default artwork that replaces the "classic" artwork sets, while the "fallback" settings specify artwork files used for all artwork files that would exist in the classic artwork sets, but are not defined or cannot be found in the new default artwork set; the program title is used for things like window title, title screens and user data folder name, and the entry point for choosing a level set can be changed from the current level set location to the topmost level tree node 2015-04-07 * added sound definitions for pressing and releasing main menu buttons 2015-03-31 * fixed slow tape quick-loading due to unneeded tape area update 2015-03-30 * replaced stop/play buttons in game panel with save/load buttons 2015-03-24 * added step-based engine snapshots to undo/redo single steps in game 2015-03-19 * fixed (swapped) editor zoom directions for '-' and '+' (keypad) keys 2015-03-18 * added dynamically configurable graphics and layout of editor gadgets 2015-03-11 * fixed (swapped) editor zoom directions for left and right mouse button 2015-03-10 * added main menu backlink to level set selection screen 2015-03-07 * added support for gadget-like pressable menu buttons on main screen 2015-03-02 * added classic graphics, sounds and music to git repository * added classic level sets to git repository * added element description files to git repository * changed mouse cursor on title screens not being always invisible * added manually edited non-preset audio volume values to select list (if sound, loops or music volume was manually edited in "setup.conf") 2015-02-27 * fixed using "background.TOOLBOX", which was simply ignored before 2015-02-23 * added key pad '-', '+' and '0' keys to zoom function in level editor * changed editor key shortcut for undo/redo to 'u' and 'Shift-u' * fixed using 'PageUp' and 'PageDown' keys for element list in editor 2015-02-21 * added 1%, 2% and 5% to volume controls for sound and music settings 2015-02-14 * fixed bug with editor border element not adjusted after resizing level * changed unused playfield from "default" to "empty" after loading level * increased number of undo/redo steps in level editor from 10 to 64 2015-02-13 * added zoom functionality for playfield drawing area to level editor (use left, right and middle mouse buttons on new "zoom" toolbox button or use keys '-', '+' and '0' to zoom out, in or reset to default size) 2015-02-11 * fixed bug not updating game panel values in visible warp forward mode 2015-02-10 * changed position of CE/GE use/save template gadgets to be visually separated from other CE/GE gadgets (to prevent accidental use) * fixed bug in editor when using undo after rotating level repeatedly * added 'redo' functionality to editor (by pressing 'undo' with right mouse button or by using key shortcut "Shift-R") 2015-02-04 * added configurability of editor control buttons (toolbox buttons) 2015-02-03 * finished configurability of tape date and time display positions * fixed bug with game buttons in tape area not properly redrawn * fixed small graphical bug with default tape time display position * added optionally configurable game frame counter to tape display 2015-02-02 * fixed configurability of editor element palette (for columns != 4) 2015-01-29 * improved configurability of tape date and time display positions * added configurability of element properties button in editor * added build dependency for auto-conf files 2015-01-27 * added looking for editor element descriptions in level set directory (for example, in file "/docs/elements/custom_1.txt") 2015-01-25 * moved "element properties" button in editor from toolbox to palette * added "zoom level tile size" button in editor to toolbox (currently no function behind it; will be used to zoom level editor playfield) * added key shortcuts '1' to '3' to view properties of drawing elements * fixed gadget display bug in editor (door 1 area) after test playing * fixed bugs when changing drawing area gadgets (like group elements) 2015-01-19 * re-enabled editor palette element options in setup configuration file 2014-12-13 * fixed loading custom PCX image files with default artwork file names (like "RocksDoor.pcx") which are not redefined in artwork config file (this is a special fix for Zelda 2 and probably some other existing level sets which use new graphics which are not defined in the file "graphicsinfo.conf", but use a file name of one of default graphics (like "RocksScreen.pcx"); this did not work anymore for PCX files since the default graphics files have been changed to PNG files, so different file names are checked now (like "RocksScreen.png"), so if the PNG files cannot be found, the old PCX files are also checked) 2014-12-03 * added some more graphics customization options for the level editor: - editor.button.prev_level (position) - editor.button.next_level (position) - editor.input.level_number (position) - editor.palette.tile_size (tile size for palette elements) - editor.palette.element_left.tile_size (draw element tile size) - editor.palette.element_middle.tile_size (draw element tile size) - editor.palette.element_right.tile_size (draw element tile size) - editor.input.gfx.level_number (current level number input field) 2014-11-22 * fixed menu display bugs caused by drawing outside menu area (again) 2014-11-19 * fixed broken door animations when switching between custom graphics 2014-11-06 * fixed layout for "level set info" to support custom playfield size * fixed changing from title to info screen with custom playfield size 2014-11-02 * fixed bug with not updating default bitmap pointer for scaled images * fixed redraw/fade bugs when redefining the playfield size or position 2014-10-27 * fixed some smaller issues with loading custom artwork 2014-10-22 * added warnings when using undefined element and graphic names in custom artwork definitions (like ".crumbled_like" or ".clone_from") * added setting default filenames for all cloned graphics in static graphics configuration on startup (to be able to fall back later) 2014-10-20 * fixed using buttons on main screen with size other than 32x32 pixels * fixed some initialization bugs for scrollbars and main screen buttons * fixed bug when drawing non-element graphics (without separate in-game graphic/bitmap defined) while non-standard game tile size is defined 2014-10-17 * removed some remaining unused X11 stuff * fixed bug with potentially suppressed exit error message on startup 2014-10-16 * fixed bug not loading tape when selecting level from level selection screen (thanks to filbo for finding this bug and supplying a patch) 2014-10-15 * fixed menu display bugs (drawing outside menu area with draw offset) * fixed menu key navigation bugs (when using smaller menu list size) 2014-10-14 * added support for animated door parts during opening/closing movement 2014-10-13 * added automatic detection of normal/steel character elements in level editor when drawing text (depending on currently selected element) 2014-10-13 * eliminated historical ISO-8859-1 characters from source code files (but still using them internally for special character encodings) * changed output of special character for level sketch brushes to UTF-8 2014-10-08 * added handling of unselectable selectbox options and option headlines 2014-10-07 * fixed bug when changing between graphic sets with different tile size * cleanup of handling the various graphic sizes for different purposes (like 32x32, 16x16 etc.); this change was needed for the bugfix above 2014-10-02 * added virtual keyboard on Android port when entering player name 2014-10-01 * fixed "quick menu doors" and sounds for door and envelope requests 2014-09-29 * fixed display bugs with certain custom menu definitions regarding the hall of fame (high scores) and setup screens that require scrolling (these display bugs showed up with custom menu graphics of R'n'D jue) 2014-09-28 * fixed bug with animation frames per line with non-standard tile size (relevant for example for 64x64 sized frames continued on next row) 2014-09-22 * removed checking of file identifier tokens for configuration files 2014-09-19 * fixed bug where player actions were only mapped in team mode (this broke four tapes in automatic game engine unit test where old levels contained a non-yellow player, like rnd_abby_king, 011) 2014-09-15 * removed large parts of the preprocessor hell of old and unused code 2014-09-14 * updated source file headers (mainly author contact information) 2014-09-11 * added key shortcuts for window scaling and toggling fullscreen mode: - Ctrl-'+', Ctrl-'-' and Ctrl-'0' for up/downscaling and normal size - "F11" key for toggling fullscreen mode (in addition to Alt-Enter) 2014-09-10 * fixed some drawing bugs when scaling graphics due to "game.tile_size" * added some performance improvements when handling SDL surface scaling 2014-09-04 * added custom graphics property "game.tile_size" to define in-game tile size (this defines the tile size actually displayed on the playfield); tile graphics will either be scaled to the defined game tile size or have to be specified with the same image size (using ".tile_size") 2014-09-01 * added custom graphics property ".tile_size" to define tile image size for game element graphics (like "custom_1.tile_size"); non-standard sized images will then be scaled accordingly to standard tile size 2014-08-30 * fixed music still being played in Android version when in background 2014-08-30 * added Android "menu" button to be treated as "yes" requester button (while the Android "back" button was already treated as "no" button) 2014-08-28 * added command line options "--version" / "-V" to show program version (also shows SDL library versions when prefixed with "--debug" option) 2014-08-27 * error file set to unbuffered to prevent truncation in case of crashes 2014-08-19 * fixed bug causing wrong screen updates while playing (whole screen update from backbuffer instead of playfield buffer if REDRAW_ALL set) * fixed nasty (typo) bug in native EM engine causing broken player graphics when using different (redefined) playfield size 2014-08-18 * fixed bug causing EM/EMC graphics sets containing original 16x16 tiles to be displayed incorrectly (with broken scaling) when switching between small and normal game graphics (thanks a lot to filbo for analyzing and describing how to exactly reproduce this bug) 2014-05-15 * removed MS-DOS support * removed native X11 support (X11 now only supported via SDL/SDL2) 2014-05-14 * cleanup of functions RedrawPlayfield() and BlitScreenToBitmap() 2014-05-13 * fixed level redraw after quick-loading tape with small tile graphics 2014-03-03 * added compatibility code for existing request door animation settings 2014-03-01 * added ultra-generic, ultra-flexible request door animation handling 2014-02-18 * fixed major bugs in handling single-player and multi-player tapes (for details, see http://www.artsoft.org/forum/viewtopic.php?t=2086) 2014-02-13 * fixed various problems with playfield and requester/tape/editor doors defined to be at non-standard screen positions in artwork config file 2014-01-28 * added envelope style requester dialog (alternative to door requester) 2014-01-27 * fixed problems with window scaling and updating related setup value * added setup option to select anti-aliasing quality of scaled windows 2014-01-17 * improved speed of displaying progress when loading levels and artwork * changed fullscreen and window scaling changes in setup menu to have immediate effect (instead of being effective after leaving setup menu) 2014-01-15 * fixed toons stopping on continuous touch events on Mac OS X 2014-01-14 * fixed bug when displaying game envelope with even sized playfield * added graphic configuration options for request (dialog) buttons 2014-01-13 * fixed some redraw bugs with window scaling under Mac OS X 2014-01-10 * fixed problems with window scaling and updating related setup value 2014-01-07 * fixed problems related to fullscreen switching and window scaling 2014-01-06 * fixed inconsistent custom artwork constants numbering in src/main.h, src/screen.c and src/conf_gfx.c (this really should be cleaned up) (this bug caused custom artwork definition to set wrong variable) 2014-01-05 * fixed using fullscreen mode on Android instead of pseudo-window mode * fixed keeping desktop fullscreen mode when changing viewport size 2014-01-04 * fixed remaining text input problems for non-ASCII keys with modifier * added window scaling options to graphics setup menu 2014-01-03 * fixed key code problems with certain keys for SDL2 (keypad keys not being in numerical order; number of function keys) * fixed text input problems for text characters using modifier keys 2014-01-02 * fixed fullscreen option for SDL2 (using only desktop fullscreen now) 2013-12-28 * fixed graphical bugs when using renderer/texture based graphics 2013-12-23 * fixed playing certain sounds (menu navigation sound and counting score sound after solving a level) when "normal sounds" are disabled 2013-12-16 * continued porting Rocks'n'Diamonds to Android (levels now playable) 2013-12-12 * added SDL2 renderer/texture based graphics frame handling to allow for "desktop" style fullscreen mode and scaling of game screen/window 2013-12-11 * removed limitation of artwork files to selected file types (this means that every file type supported by SDL_image and SDL_mixer can be used) * changed default graphics from PCX to PNG (needed for Android version to prevent painfully slow image loading, although not compressing PCX files in the assets directory of the APK package might also work fine) * fixed bug with SDL_BlitSurface creating garbage when source and target surface are the same (this bug also existed in versions of SDL 1.2.x) 2013-12-07 * started porting Rocks'n'Diamonds to Android (already shows main menu) 2013-12-03 * ported Rocks'n'Diamonds to SDL2 (first simple version that works) 2013-12-01 * version number set to 3.3.1.3 2013-11-24 * version 3.3.1.2 released 2013-11-20 * improved error handling: display error message on screen (not only in the error file or on the console), and display path of the error file 2013-11-13 * fixed problem with R'n'D restarting with same level set that may have caused a problem (and therefore failing again and again); after an error, the last level set is now deactivated in file "levelsetup.conf" to restart with default level set (which should work without error) 2013-11-07 * fixed determining main game data directory on Mac OS X "Mavericks" 2013-11-04 * version number set to 3.3.1.2 2013-11-04 * version 3.3.1.1 released 2013-11-03 * added scripts directory to distribution package to enable building element definitions after editing artwork config source code files 2013-10-26 * added volume controls for sounds, loops and music to sound setup 2013-10-24 * version number set to 3.3.1.1 2013-10-23 * version 3.3.1.0 released 2013-10-21 * version number set to 3.3.1.0 2012-10-13 * fixed display of level time switching from ascending to descending when making use of the "time orb bug" (see element setting in editor) (see level 053 of set "rnd_equinox_tetrachloride_ii" for an example) * fixed graphics performance problems (especially on Mac OS X) by using whole-playfield redraw on SDL target, while still using the previous single-tile redraw method on X11 target (using redraw tiles threshold) 2011-10-07 * fixed code (esp. random/tape handling) when compiled on 64-bit systems (by replacing all "long" types by "int" types) 2010-11-19 * fixed nasty bug (affecting crumbled graphics) after adding new special graphics suffix ".TAPE" (and messing some things up in src/main.c) 2010-08-04 * fixed wrong argument order in DrawTextBuffer() in gadgets.c (this caused fonts in envelope config in level editor being invisible) 2010-07-19 * fixed some problems with half tile size and even tile sized playfields 2010-07-12 * added level selection screen (when clicking on main menu level number) * added level tracing (played, solved) for use in level selection screen (to display already played or solved levels in different font color) 2010-06-24 * added alternative game mode for playing with half size playfield tiles * fixed another memory violation bug in the native Supaplex game engine (this potential memory bug was also in the original Megaplex code, but apparently only occured under rare conditions triggered by using the additional added preceding playfield memory area to make a few strange levels using dirty off-playfield tricks (bugs) like "12s033.sp" also solvable (this all worked fine in the classic DOS version, of course)) 2010-06-23 * added graphics performance optimization to native Supaplex game engine * fixed bug with accidentally removing preceding buffer in SP engine * moved some editor graphics from "RocksDoor.pcx" to "RocksMore.pcx" (to prevent compatibility mapping of these newer graphics to older (custom) versions of "RocksDoor.pcx" which did not contain them yet) 2010-06-18 * added separately configurable game panel background to graphics config * fixed displaying Supaplex time (now based on 35 fps instead of 50 fps) 2010-06-16 * added tape panel graphics and screen positions to graphics config 2010-06-15 * added compatibility stuff for redefined "global.door" (which affects all parts of that image that have their own graphics definition now) 2010-06-14 * added sound button graphics to graphics config 2010-06-13 * added tape button graphics and screen positions to graphics config 2010-06-09 * improved single step mode in R'n'D, EM and SP engines 2010-06-08 * version number set to 3.3.0.2 2010-06-08 * version 3.3.0.1 released 2010-06-08 * added configurable key shortcuts for snap+direction player actions (probably most useful for recording tool-assisted speedrun (TAS) tapes using the single-step mode of the tape recorder) 2010-05-28 * version number set to 3.3.0.1 2010-05-25 * version 3.3.0.0 released 2010-05-22 * fixed missing memory allocation in SP engine when saving engine data for non-SP game engine snapshots (which also stores SP engine part) 2010-05-21 * fixed problem with scrolling in native EM engine in multi-user mode (this bug was just introduced with the experimental viewport stuff) * fixed animation of splashing acid in EM engine with classic artwork * fixed animation of cracking nut in EM engine with classic artwork * fixed (implemented) single step mode in native EM and SP engines * fixed "latest_engine" flag in classic levels (moved to single sets) * updated SDL library DLLs for Windows to the latest release versions (this fixed some mysterious crashes of the game on Windows systems) * replaced EM and SP set in classic level set with native level files * finally added a newly written "CREDITS" file to the game package * removed sampled music loops from classic music set 2010-04-20 * changed native Emerald Mine engine to support different viewport sizes 2010-04-19 * changed native Supaplex engine to support different viewport sizes 2010-04-07 * added initial, experimental support for different viewport properties (with "viewports" being menu/playfield area and doors; currently the size of the menu/playfield area and door positions can be redefined) 2010-04-02 * added initial, experimental support for different window sizes 2010-03-27 * added support for native Sokoban solution files in pure 'udlrUDLR' format with extension ".sln" instead of ".tape" for solution tapes 2010-03-26 * added image config suffix ".class" to be able to define classes of crumbled elements which are then separated against each others when drawing crumbled borders (class names can freely be defined) (Example: "sand.CRUMBLED.class: sand" and "emc_grass.CRUMBLED.class: emc_grass" results in sand and emc_grass being crumbled separately, even if directly adjacent on the playfield.) * added image config suffix ".style" to use two new features for crumbled graphics: - "accurate_borders": try to draw correctly crumbled corners (which means that a row of crumbled elements does not have two crumbled corners for each element in the row, but only at the "real" corners at the start and the end of the row of elements) - "inner_corners": also draw inner corners in concave constructions of several crumbled elements -- this is currently a big kludge: the number of frames for crumbled graphic must be "2", with the first frame as usual (crumbled graphic), while the second frame contains the graphic with inner (crumbled) corners for the crumbled graphic (These two features are mainly intended for bevelled walls, not for diggable elements like sand; "inner_corners" only works reliably for static walls, not for in-game dynamically changing walls using CEs.) 2010-03-16 * finished code cleanup of native Supaplex game engine 2010-03-14 * started code cleanup of native Supaplex game engine 2010-03-13 * integrated playing sound effects into native Supaplex game engine 2010-03-10 * added configurable key shortcuts for the tape recorder buttons 2010-03-09 * added (hidden) function to save native Supaplex levels with tape as native *.sp file containing level with demo (saved with a file name similar to native R'n'D levels, but with ".sp" extension instead of ".level"); to use this functionality, enter ":save-native-level" or ":snl" from the main menu with the native Supaplex level loaded and the appropriate tape loaded to the tape recorder * fixed potential crash bug caused by illegal array access in engine snapshot loading and saving code * changed setting permissions of score files to be world-writable if the program is not installed and running setgid to allow the program to modify existing score files when run as a different user (which allows cheating, of course, as the score files are not protected against modification in this case) * added (commented out) suggestions for RO_GAME_DIR and RW_GAME_DIR to the top level Makefile for Debian / Ubuntu installations * added saving read-only levels from editor into personal level set (thanks to Bela Lubkin for the above four patches) 2010-03-03 * added updating of game values on the panel to Supaplex game engine 2010-02-23 * finished integrating R'n'D graphics engine into Supaplex game engine (although some animations do not support full customizability yet) 2010-02-22 * done integrating R'n'D graphics engine into file "Infotron.c" * done integrating R'n'D graphics engine into file "OrangeDisk.c" 2010-02-19 * integrated engine snapshot functionality into Supaplex game engine 2010-02-16 * fixed bug in native Supaplex engine that broke several demo solutions * fixed bug with re-initializing already existing elements in function RelocatePlayer() in src/game.c (causing problems with Sokoban fields counted a second time, making the currently playing level unsolvable) * done integrating R'n'D graphics engine into file "SnikSnaks.c" * done integrating R'n'D graphics engine into file "Electrons.c" * done integrating R'n'D graphics engine into file "Zonk.c" 2010-02-14 * done integrating R'n'D graphics engine into file "Murphy.c" * done integrating R'n'D graphics engine into file "BugsTerminals.c" 2010-02-07 * started integrating R'n'D graphics engine into Supaplex game engine 2010-02-02 * added small kludge that allows transparent pushing animation over non-black background (by using "game.use_masked_pushing: true") * added editor flag to Sokoban field/object elements to automatically finish solved Sokoban style levels (even if they contain non-Sokoban elements, which prevents auto-enabling this feature for such levels) 2010-01-10 * added new element "from_level_template" which is replaced by element from level template at same playfield position when loaded (currently not accessible from level editor, but only used for special Sokoban level conversion when using "special_flags: load_xsb_to_ces") * added special behaviour for "special_flags: load_xsb_to_ces": global settings of individual level files are overwritten by template level (except playfield size, level name, level author and template flag) 2010-01-07 * added handling of gravity ports when converting Supaplex style R'n'D levels to native Supaplex levels for playing with Supaplex engine 2010-01-06 * fixed bug in Supaplex engine regarding initial screen scroll position 2009-12-17 * fixed EMC style pushing animations in the R'n'D graphics engine (when using ".2nd_movement_tile" for animations having start and end tile) * for this to work (look) properly for two-tile pushing animations with non-black (i.e. opaque) background, the pushing graphics drawing order was changed to first draw the pushed element, then the player (maybe this should be controlled by an ".anim_mode" flag yet to be added) * two-tile animations for moving or pushing should have 7 frames for normal speed, 15 frames for half speed etc. to display correct frames * two-tile animations are also displayed correctly with different speed settings for the player (for pushing animations) or moving elements 2009-12-16 * added searching for template level (file "template.level") not only inside the level set directory, but also in above level directories; this makes is possible to use the same single template level file (placed in a level group directory) for many level sub-directories 2009-12-10 * fixed bug with steel exit being destructible during opening phase * added token "special_flags" to "levelinfo.conf" (currently with the only recognized value "load_xsb_to_ces", doing the same as the flag "-Dload_xsb_to_ces" on the command line, but as a permanent flag for converting all elements in native (XSB) Sokoban level files to CEs) 2009-12-08 * fixed some problems with Supaplex engine when compiling for Windows 2009-12-05 * added special mode to convert elements of Sokoban XSB levels to CEs by adding "-Dload_xsb_to_ces" to the command line starting the game (also adding a dependency to a template level file "template.level") 2009-12-01 * added reading native Sokoban levels and level packages (XSB files) 2009-11-25 * fixed bugs in (auto)scrolling behaviour when passing ports or when wrapping around the playfield through "holes" in the playfield border 2009-11-24 * changed internal playfield bitmap handling from playfield sized bitmap to screen sized bitmap (visible scrolling area), therefore speeding up graphics operations (by eliminating bitmap updates in invisible areas) and removing playfield size limitations due to increasing bitmap size for larger playfield sizes (while the new implementation always uses a fixed playfield bitmap size for arbitrary internal playfield sizes) 2009-11-12 * fixed bug with single step mode (there were some cases where the game did not automatically return to pause mode, e.g. when trying to push things that cannot be pushed or when trying to run against a wall) 2009-11-01 * added support for loading Supaplex levels in MPX level file format 2009-10-31 * fixed SP engine to set "game over" not before lead out counter done 2009-10-30 * fixed (potential) compile error when using GCC option "-std=gnu99" (thanks to Tom "spot" Callaway) 2009-10-28 * fixed array allocation in native Supaplex engine to correctly handle preceding scratch buffers (needed because of missing border checking) * fixed playfield initialization to correctly add raw header bytes as subsequent scratch buffer (needed because of missing border checking) 2009-10-24 * most important parts of native Supaplex engine integration working: - native Supaplex levels can be played in native Supaplex engine - native Supaplex level/demo files ("*.sp" files) can be re-played - all 111 classic original Supaplex levels automatically solvable - native Supaplex engine can be selected and used from level editor - logic of re-playing Supaplex demos migrated to R'n'D tape logic 2009-09-25 * fixed another translation problem from VisualBasic to C (where "int" should be "short") causing unsolvable demos with bugs and terminals ("bugs" being related to the Supaplex "buggy base" element here ;-) ) 2009-09-23 * fixed bug when reading Supaplex single level files (preventing loader from seeking to level position like in Supaplex level package files) 2009-08-01 * first classic Supaplex level running and solved by solution/demo tape 2009-06-20 * started with integration of native Supaplex engine, using source code of Megaplex from Frank Schindler, based on original Supaplex engine 2009-06-16 * version number set to 3.2.6.2 2009-06-15 * version 3.2.6.1 released 2009-05-31 * fixed bug with element_info[e].gfx_element not being initialized in early game stage, causing native graphics in EMC level sets to be mapped completely to EL_EMPTY (causing a blank screen when playing) (this only happened when starting the program with an EMC set with native graphics, but not when switching to such a set at runtime) 2009-03-30 * deactivated blit-to-same-surface workaround again (see 2009-03-24) and using self-compiled, patched SDL.dll that solves this problem (interim solution until release of SDL 1.2.14 that should fix this) 2009-03-26 * extended backwards compatibility mode to allow already fixed bug with change actions (see "2008-02-05") for existing levels (especially the Zelda and Zelda II levels and other cool stuff by Alan Bond like FMV) 2009-03-24 * reactivated workaround to prevent program crashes due to blitting to the same SDL surface that apparently only occurs on Windows systems (this is no final solution; this problem needs further investigation) 2008-11-05 * version number set to 3.2.6.1 2008-11-04 * version 3.2.6.0 released 2008-10-11 * fixed behaviour of player option "no centering when relocating" which was incorrect when disabled and relocation target inside visible area and "no scrolling when relocating" enabled at the same time 2008-10-06 * fixed problems with re-mapping players on playfield to input devices: previously, players found on the level playfield were changed to the players connected to input devices (for example, player 3 in the level was changed to player 1 (using artwork of player 3, to be able to use a player with a different color)); this had the disadvantage that CE conditions using player elements did not work (because the players in the level definition are different to those effectively used in-game); the new system uses the same player elements as defined in the level playfield and re-maps the input devices of connected players to the corresponding player elements when playing the level (in the above example, player 3 now really exists in the game and is moved using the events from input device 1); level tapes still store the events from input devices 1 to 4, which are then re-mapped to players accordingly when re-playing the tape (just as it is done when playing the level) 2008-09-29 * fixed bug with player relocation while the player switches an element 2008-09-24 * fixed bug with EM/DC style exit and EM/DC style steel exit which was not walkable (and did not let the player enter) when in process of opening, but not fully open yet (which can cause the player not being able to enter the exit in EM/DC style levels in time) 2008-08-02 * fixed some bugs regarding the new level/CE random seed reset options 2008-07-14 * moved "level settings" and "editor settings" to two tabbed screens in level editor to gain space for additional level property settings * added level setting to start a level with always the same random seed * added CE action "set random seed" to re-initialize random seed in game (this is the only CE action that gets executed before the CE changes, which is needed to use the newly set random seed during the CE change) 2008-06-16 * fixed redraw problem of special editor door when playing from editor 2008-06-16 * fixed initialization of gfx_element for level sketch image creation 2008-06-15 * added switch for EM style dynamite "[ ] explodes with chain reaction" (with default set to "on" for existing levels, but "off" for all new levels), as EM style dynamite does not chain-explode in original EM 2008-02-05 * added optional initial inventory for players (pre-collected elements) * added change page actions "set player inventory" and "set CE artwork" * added recognition of "player" parameter on change pages when player actions are defined, but no trigger player in corresponding condition (this resulted in actions that only affected the first player before) * fixed bug with change actions being executed for newly created custom elements resulting from custom element changes, when the intention was only to check for change actions for the previous custom element 2008-02-03 * changed design and size of element drawing area in level editor * added "element used as action parameter" to element change actions 2008-01-27 * added possibility to reanimate player immediately after his death (for example, by "change to when explosion of ") 2008-01-25 * fixed bug with "gray" white door not being uncovered by magnifier * added score for collecting (any) key to the white key config page 2008-01-22 * added condition "deadly when " for custom elements that behaves a bit like the existing "deadly when ", but with the following differences: - it only kills players or friends when it was moving before it hits - it does not kill players or friends that try to run into it 2008-01-21 * fixed the following change conditions where a player element is used as the "element that is triggering the custom element change": - touching - hitting - explosion of - move of (the last two conditions already worked partially, but only for the first player, and not for the "Murphy" player when using "move of") 2008-01-20 * fixed crash bug caused by accessing invalid element (with value -1) in UpdateGameControlValues() * fixed graphical bug when using two-tile movement animations with EMC game engine without explicitly using native EMC graphics engine 2007-10-31 * fixed bug in new "can dig" feature (see below) so that an unsuccessful try to push something (due to push delay) does not cause a dig action 2007-10-29 * fixed bug with reference elements used as trigger elements on custom element change pages not being recognized * fixed bug with reference elements not being removed from the playfield * added engine functionality that allows custom elements that "can dig" other elements not only to do so when moving by themselves, but also when being pushed by the player (therefore adding the functionality to push one element over another element, replacing it with the new one) 2007-10-23 * added command line function to write level sketch images to directory 2007-10-20 * merged override and auto-override options into new override options with a new data type than can take the values "no", "yes" and "auto" 2007-10-18 * fixed growing steel wall to also leave behind steel wall instead of normal, destructible wall * fixed handling of rocks falling through stacks of quicksand with different speed (before, the rocks just got stuck in the quicksand) 2007-10-09 * fixed nasty bug with auto-override and normal override not working on program startup (especially when current level set has custom artwork) 2007-10-05 * version 3.2.5 released as special edition "R'n'D jue" 2007-10-05 * fixed X11 crash bug when blitting masked title screens over background 2007-10-04 * changed build system to support special editions (like "R'n'D jue") * added (hardcoded) loading graphics for "R'n'D jue" special edition * fixed X11 crash bug when scaling images with width/height less than 32 2007-09-27 * added "background.PLAYING" (only visible as two-pixel border in game) * added default level set for first start of special R'n'D version * changed door animations for editor always behaving like "quick doors" 2007-09-26 * added new custom artwork setup option "auto-override non-CE sets" for automatic artwork override that is only used for level sets without custom element artwork (as it does not make much sense to override any artwork that redefines custom element artwork for sets using CEs) * fixed default artwork for "special" R'n'D versions always using the "classic" artwork as the base if base artwork is not explicitly defined in "levelinfo.conf", regardless of different default artwork used by the special R'n'D version -- this is needed because any such custom artwork is designed using the "classic" artwork definitions as the base (including menu definitions and screen positions etc., which would otherwise be taken from the different special default artwork) 2007-09-17 * fixed drawing of animated "quicksand.filling" and "quicksand.emptying" for both EMC and R'n'D graphics engine (heavy workarounds needed due to massively broken handling of quicksand in R'n'D game engine) * fixed off-limits access to array in DrawLevelFieldCrumbledSandExt() * fixed crash bug (hopefully) when scrolling with cursor keys in editor 2007-09-16 * fixed small bug in toon drawing (introduced when fixing the crash bug) 2007-09-15 * added graphics definition "game.panel.highscore" to display the current levels current high score in the game panel 2007-09-13 * version number set to 3.2.5 2007-09-13 * version 3.2.4 released 2007-09-13 * fixed crash bug in toon drawing functions for large step offset values 2007-09-12 * fixed some problems with displaying game panel when quick-loading tape 2007-09-07 * fixed (experimental only) redrawing of every tile per frame (even if unneeded) for the extended (R'n'D based) EMC graphics engine * added optimization to only calculate element count for panel display if really needed (that is, if element count values defined on panel) * fixed problem with special editor door redraw when entering main menu 2007-09-03 * fixed bug with displaying background for title messages on info screen * some code cleanup for the extended (R'n'D based) EMC graphics engine 2007-09-01 * fixed bug with CE action "move player" always resulting in player 4 if there was a CE action with no trigger player (because the player element was calculated by using log_2() from trigger player bits with the value PLAYER_BITS_ANY) -- this is now fixed by also storing the triggering player bit mask and handling all players in "move player" * fixed bug when defined artwork cannot be found for artwork that has default artwork cloned from other artwork (without default filename) * added several fixes to the extended (R'n'D based) EMC graphics engine 2007-08-26 * fixed broken editor copy and paste for custom elements between levels 2007-08-25 * title messages are now also searched in graphics artwork directory; those found in graphics directory have precendence over those found in level directory -- this handles title messages stored in graphics directories as part of the artwork set, just like title images; this makes sense, as corresponding special font definitions for messages are usually defined in the same graphics artwork directory, and also because title images and title messages that are combined in a level set introduction should usually not be separated when the level set is used with a different artwork set (e.g. using "override graphics") * fixed problem with door borders on main screen by first drawing doors and then the corresponding border masks, but not vice versa * fixed problem with artwork config entries using the value "[DEFAULT]"; this does not what one might expect, but sets the value to an invalid value -- solution: simply ignore such entries, which results in this value keeping its previous (real) default value (in general, entries that should use their default value should just not be defined here) * fixed problem with wrong fading area size from main menu to setup menu 2007-08-22 * fixed problem with broken crumbled graphics after level set changes when using R'n'D custom artwork with level sets using the EMC engine 2007-05-07 * fixed invisible "joysticks deactivated ..." text on setup input screen 2007-04-27 * added use of hashes created from static lists (element tokens, image config, font tokens) to speed up lookup of configuration parameters * fixed bug where element and graphic config token lookup was mixed up 2007-04-26 * added "busy" animation when initializing program and loading artwork * added initialization profiling for program startup (debugging only) 2007-04-25 * fixed(?) very strange bug apparently triggered by memset() when code was cross-compiled with MinGW cross-compiler for Windows XP platform (this only happened when using SDL.dll also self-compiled with MinGW) 2007-04-19 * added graphics engine directive "border.draw_masked_when_fading" that enables/disables drawing of border mask over screen that is just faded 2007-04-18 * fixed small problem with separate fading definition for game screen 2007-04-14 * added additional configuration directives for setup screen draw offset menu.draw_xoffset.SETUP[XXX] and menu.draw_yoffset.SETUP[XXX] with XXX in GAME, EDITOR, GRAPHICS, SOUND, ARTWORK, INPUT, SHORTCUTS_1, SHORTCUTS_2, CHOOSE_ARTWORK, CHOOSE_OTHER (where "CHOOSE_ARTWORK" is used to define draw offset on custom artwork selection screens and "CHOOSE_OTHER" is used on all other list style selection screens, like choosing game speed or screen mode for fullscreen mode) * added additional configuration directives to define main menu buttons: - menu.button_name and menu.button_name.active - menu.button_levels and menu.button_levels.active - menu.button_scores and menu.button_scores.active - menu.button_editor and menu.button_editor.active - menu.button_info and menu.button_info.active - menu.button_game and menu.button_game.active - menu.button_setup and menu.button_setup.active - menu.button_quit and menu.button_quit.active * added eight pure decoration graphic definitions for the game panel 2007-04-08 * added support for accessing native Diamond Caves II level packages * fixed displaying of game panel values for Emerald Mine game engine * fixed displaying end-of-level time and score values on new game panel 2007-04-07 * added game panel control to display arbitrary elements on game panel * added game panel control to display custom element score (globally unique for identical custom elements) either as value or as element * added ".draw_masked" and ".draw_order" to game panel control drawing 2007-04-05 * fixed some general bugs with handling of ".active" elements and fonts 2007-04-04 * cleanup of game panel elements (some elements were not really needed) * added displaying of gravity state (on/off) as new game panel control * added animation for game panel elements (similar to game elements) 2007-04-03 * added new pseudo game mode "PANEL" to define panel fonts and graphics - panel fonts now use ".PANEL" suffix instead of ".PLAYING" suffix - panel graphics now use ".PANEL" suffix instead of ".DOOR" suffix (else graphics would have to use ".PLAYING", which would be confusing) * fixed bug when fading out to game screen with border mask defined 2007-04-02 * added attribute ".tile_size" for element style game panel controls 2007-04-01 * added key as additional valid key to use for confirm requester 2007-03-31 * improved menu fading, adding separate fading definitions for entering and leaving a "content" screen (in general), and optional definitions for the special "content" screens SCORES, EDITOR, INFO and PLAYING 2007-03-30 * added (currently invisible) setup option to define scroll delay value * fixed small bug in priority handling when auto-detecting level start position in levels without player element (but player from CE etc.) * added option "game.forced_scroll_delay_value" to override user choice of scroll delay value for certain level sets with "graphicsinfo.conf" * replaced setup option "scroll delay: on/off" by new setup option that directly allows selecting the desired scroll delay value from 0 to 8 2007-03-28 * added displaying of most game panel control elements (not animated) 2007-03-26 * added new configuration directives to display additional game engine values on the game control panel, like the following examples: - game.panel.time_hh/time_mm/time_ss - level time in HH/MM/SS format - game.panel.penguins - number of penguins to rescue - game.panel.level_name - level name of current level 2007-03-24 * added support for preview tile sizes "1" and "2" (1x1 and 2x2 pixels) 2007-03-23 * added new player option "no centering when relocating" for "invisible" teleportations to level areas that look exactly the same, giving the illusion that the player did not relocate at all (this was the default since 3.2.3, but caused visual problems with room creation in "Zelda") * added new menu fading effect "melt", shamelessly stolen from "DOOM" 2007-03-21 * improved menu fading, adding separate fading definitions for entering and leaving a menu and for fading between menu and "content" screens * fixed small bug with recognizing also ".font_xyz" style definitions 2007-03-20 * improved menu fading, adding separate fading definitions for fading between menu screens and fading between menu and "destination" screens 2007-03-19 * titlemessage_initial_x and titlemessage_x set to "[DEFAULT]" in static configuration (set from "[titlemessage_initial]" and "[titlemessage]") * fading settings of "[titlemessage_initial]" and "[titlemessage]" set to "[DEFAULT]" in static configuration (set from "[title_initial]" and "[title]") * improved title fading, allowing fading animation types "none", "fade" and "crossfade" (including cross-fading of last title to main menu) 2007-03-18 * added configurability of graphics, sounds and music for title screens, which are separated into initial title screens (only shown once at program startup) and title screens shown for a given level set; these title screens can be composed of up to five title images and up to five title text messages (each drawn using an optional background image), also using background music and/or sounds; aspects like background images, sounds and music of title screens can either be defined generally (valid for all title screens) or specifically (and therefore differently for each title screen) using these directives: to define a background image, sound or music file for all screens: - background.TITLE_INITIAL (for all title screens for game startup) - background.TITLE (for all title screens for level sets) to define a background image, sound or music file for a single screen: - background.titlescreen_initial_x (with x in 1,2,3,4,5) - background.titlescreen_x (with x in 1,2,3,4,5) - background.titlemessage_initial_x (with x in 1,2,3,4,5) - background.titlemessage_x (with x in 1,2,3,4,5) to define the title screen images: - titlescreen_initial_x (with x in 1,2,3,4,5) - titlescreen_x (with x in 1,2,3,4,5) to define the title text messages, place text files into the level set directory that have the following file names: - titlemessage_initial_x.txt (with x in 1,2,3,4,5) - titlemessage_x.txt (with x in 1,2,3,4,5) to define the properties of the text messages, either use directives that affect all text messages: - [titlemessage_initial]. - [titlemessage]. or use directives that affect single text messages: - titlemessage_initial_x. (with x in 1,2,3,4,5) - titlemessage_x. (with x in 1,2,3,4,5) valid values for are the same as for readme. below; use ".sort_priority" (default: 0) to define an arbitrary order for title images and title messages (which can therefore be mixed) 2007-03-14 * added full configurability of "readme.txt" screen appearance: - readme.x: - readme.y: - readme.width: - readme.height: - readme.chars: - readme.lines: - readme.align: left,center,right (default: center) - readme.top: top,middle,bottom (default: top) - readme.font: font name - readme.autowrap: true,false (default: true) - readme.centered: true,false (default: false) - readme.parse_comments: true,false (default: true) - readme.sort_priority: (not used here, but only for title screens) when "readme.chars" and/or "readme.lines" is set to "-1" (this is the default), they are automatically determined from "readme.width" and "readme.height" accordingly; when they are not "-1", they have precedence over "readme.width" and "readme.height" * added internal ad-hoc config settings for displaying text files like title messages or "readme.txt" style level set info files: - .font: font name (default: readme.font) - .autowrap: true,false (default: readme.autowrap) - .centered: true,false (default: readme.centered) - .parse_comments: true,false (default: readme.parse_comments) (the leading '.' and the separating ':' are mandatory here); to use these ad-hoc settings, they have to be written inside a comment, like "# .autowrap: false" or "# .centered: true"; these settings then override the above global settings (they can even be used more than once, like "# .centered: true", then some text that should be drawn centered, then "# .centered: false" to go back to non-centered text; important note: after using "# .parse_comments: false", or when using "readme.parse_comments: false", detecting and parsing comments inside the file is disabled and comments are just printed like normal text; also be aware that all automatic text size calculations are done with the font defined in "readme.font", while using different fonts using "# .font: " inside the text file may cause unexpected results 2007-03-08 * changed some numerical limits in the level editor from 255 to 999 2007-03-07 * added option "system.sdl_videodriver" to select SDL video driver * added output of SDL video and audio driver to "version info" page 2007-03-06 * added group element drawing to IntelliDraw drawing functions * fixed animation resetting problem again (last try broke Snake Bite) * fixed diagonal scrolling in screen scrolling (last try broke Pac Man) 2007-03-01 * added new (special) "include: " directive that works in all configuration files (like "graphicsinfo.conf") and that has the same effect as if that directive would be replaced with the content of the specified file (this can be useful to split large configuration files into several smaller ones and include them from one main file, or to store configuration settings that always stay the same into a separate file, while including it and only add those parts that really change) 2007-02-24 * fixed minor bug (screen redraw of player tiles) in EMC graphics engine 2007-02-23 * fixed bug in "InitMovingField()" where treating an integer array as boolean caused wrong resetting of animations while elements are moving * fixed problem with resetting animations when starting element change 2007-02-08 * added sort priority for order of title screens and title messages 2007-02-07 * changed end of game again: do not wait for the user to press a key anymore, but directly ask/confirm tape saving and go to hall of fame * re-enabled quitting of lost game by pressing space or return again * added blanking of mouse pointer when displaying title screens * added remaining menu draw offset definitions for info sub-screens 2007-02-05 * added setup option to select game speed (from very slow to very fast) * improved handling of title text messages (initial and for level set) 2007-02-03 * added new options "auto-wrap" and "centered" for DC2 style envelopes 2007-01-31 * fixed displaying and typing of player name when it is centered * added special characters to be allowed for player name (not only A-Z) 2007-01-25 * fixed blit in ScrollLevel() to same bitmap to not overlap anymore (newer versions of the SDL library seem to not like this anymore) 2007-01-23 * added code for configuration directives for control of game panel 2007-01-21 * fixed small cosmetical bug with underlining property tabs in editor 2007-01-20 * fixed small drawing bug in X11FadeRectangle * added new elements for newly supported Diamond Caves II levels: - EM/DC style exits that disappear after passing - white key and gate (one white key needed for each white gate) - fake gate (there is no key to open/pass this kind of gate!) - extended magic wall which also handles pearls and crystals - fast quicksand 2007-01-14 * changed maximum value for endless loop detection to a higher value (some levels really used very deep recursion without being endless) 2007-01-13 * added new elements for newly supported Diamond Caves II levels: - growing steel walls - snappable land mine 2007-01-08 * added new elements for newly supported Diamond Caves II levels: - steel text elements 2007-01-06 * added level file loader for native Diamond Caves II levels 2007-01-05 * version number set to 3.2.4 2007-01-05 * version 3.2.3 released 2007-01-04 * fixed malloc/free bug when updating EMC artwork entries in level list * added workaround (warning and request to quit the current game) when changing elements cause endless recursion loop (which would otherwise freeze the game, causing a crash-like program exit on some systems) 2006-12-16 * fixed nasty string overflow bug when entering too long envelope text 2006-12-05 * added feedback sounds for menu navigation "menu.item.activating" and "menu.item.selecting" (for highlighting and executing menu entries) 2006-12-03 * improved "no scrolling when relocating" to also consider scroll delay (meaning that the player is not automatically centered in this case; this makes it possible to "invisibly" relocate the player to a region of the level playfield which looks the same as the old level region) * fixed bug with not recognizing "main.input.name.align" when active 2006-12-02 * fixed bug with displaying masked borders over title screens when screen fading is disabled 2006-11-25 * fixed infinite loop / crash bug when killing the player while having a CE with the setting "kill player X when explosion of " * added special editor graphic for "char_space" to distinguish it from "empty_space" when editing a level (in-game graphics still the same) 2006-11-21 * fixed nasty bug with initialization only done for the first player 2006-11-19 * small change to handle loading empty element/content list micro chunks 2006-11-03 * uploaded pre-release (test) version 3.2.3-0 binary and source code 2006-11-01 * some optimizations on startup speed by reducing initial text output 2006-10-30 * added caching of custom artwork information for faster startup times 2006-10-29 * fixed graphical bug when using fewer menu entries on level selection screen than usual (with "menu.list_size.LEVELS" directive) * fixed crash bug (Windows/SDL only) caused by BlitBitmap blitting from the backbuffer to the backbuffer by error (with identical rectangle) 2006-10-28 * fixed bug when displaying titlescreen with size less than element tile * fixed bug that caused elements with "change when digging " event to change for _every_ digged element, not only those specified in * fixed bug that caused impact style collision when dropping element one tile over the player that can both fall down and smash players * fixed bug that caused impact style collision when element changed to falling/smashing element over the player immediately after movement 2006-10-24 * fixed bug that allowed making engine snapshots from the level editor 2006-10-22 * fixed bugs with player name and current level positions on main screen 2006-10-20 * added configuration directives for control of title screens: - "title.fade_delay" for fading time - "title.post_delay" for pause between screens (when not crossfading) - "title.auto_delay" to automatically continue after some time these settings can each be overridden by specifying them with titles: - "titlescreen_initial_{1-5}.{fade_delay,post_delay,auto_delay}" - "titlescreen_{1-5}.{fade_delay,post_delay,auto_delay}" fading mode can also be specified: - "titlescreen_initial_{1-5}.anim_mode: {fade,crossfade} - "titlescreen_{1-5}.anim_mode: {fade,crossfade} default is using normal fading for menues and initial title screens, while using cross-fading for level set title screens * fixed bug with background not drawn in Hall of Fame after game was won 2006-10-18 * added configuration directives for the remaining main menu items 2006-10-17 * added additional configuration directives for info screen draw offset: menu.draw_{x,y}offset.INFO[{ELEMENTS,MUSIC,CREDITS,PROGRAM,LEVELSET}] * added additional configuration directives for preview info text * limited mouse wheel sensitive screen area to scrollable screen area 2006-10-16 * added highlighted menu text entries to menu navigation when selected 2006-10-14 * fixed bug that prevented player from correctly being created in the top left corner by a custom element change in a level without player * fixed bug that prevented player from being killed when indestructible, non-walkable element is placed on player position by extended change * added configurable menu button, text and input positions to main menu 2006-10-13 * added page fading effects for remaining info sub-screens * fixed small bug that caused some delays when answering door request 2006-10-12 * added directives "border.draw_masked.*" for menu/playfield area and door areas to display overlapping/masked borders from "global.border" 2006-10-09 * fixed bug with CE with move speed "not moving" not being animated * when changing player artwork by CE action, reset animation frame 2006-10-03 * fixed bug with not unmapping main menu screen gadgets on other screens * fixed bug with un-pausing a paused game by releasing still pressed key * fixed bug with not redrawing screen when toggling to/from fullscreen mode while fast reloading tape (without redrawing playfield contents) * fixed bug with quick-saving tape snapshot despite answering with "no" 2006-08-30 * version number set to 3.2.3 2006-08-29 * version 3.2.2 released 2006-08-29 * fixed bug with redrawing screen in fullscreen mode after quick tape reloading when using the EMC game engine * changed token names from "last_ce_[1-8]" to "prev_ce_[1-8]" 2006-08-28 * fixed bug in GameWon() when level contains no exit (like in Sokoban) 2006-08-23 * added engine snapshot functionality for instant tape reloading (this only works for the last tape saved using "quick save", and does not work across program restarts, because it completely works in memory) 2006-08-21 * version number set to 3.2.2 2006-08-20 * version 3.2.1 released 2006-08-20 * fixed nasty bugs with handling error message file on Mac OS X systems 2006-08-19 * general code cleanup (removing many annoying "#if 0" blocks etc.) 2006-08-18 * fixed bug that caused broken tapes when manually appending to tapes using the "pause before death" functionality, followed by recording * added setup option to disable fading of screens for faster testing 2006-08-16 * code cleanup of new fading functions 2006-08-15 * changed behaviour after solved game -- do not immediately stop engine * added some more smooth screen fadings (game start, hall of fame etc.) 2006-08-14 * fixed bug with displaying pushed CE with value/score/delay anim_mode 2006-08-12 * added configurable level preview position, tile size and dimensions * added configurable game panel value positions (gems, time, score etc.) 2006-08-10 * fixed small bug with time displayed incorrectly when collecting CEs 2006-08-07 * fixed bug with bumpy scrolling with EM engine in double player mode 2006-08-05 * added compatibility code to fix "Snake Bite" style levels that were broken due to a bugfix regarding EL_SOKOBAN_FIELD_PLAYER in 3.2.0 2006-08-04 * fixed bug with scrollbars inside editor when using the Windows mouse enhancement tool "True X-Mouse" (which injects key events to the event queue to insert selected stuff into the Windows clipboard, which gets confused with the "Insert" key for jumping to the last editor cascade block in the element list) * added Rocks'n'Diamonds icon for use as window icon to SDL version * added key shortcut "Alt + Enter" to toggle fullscreen mode at any time 2006-08-01 * added selection of preferred fullscreen mode to setup / graphics menu (useful if default mode 800 x 600 does not match screen aspect ratio) 2006-07-30 * improved down-scaling of images for better editor and preview graphics * changed user data directory for Mac OS X from Unix style to new place 2006-07-26 * improved level number selection in main menu and player selection in setup menu (input devices section) by using standard button gadgets * added support for mouse scroll wheel (caused buggy behaviour before) * added support for scrolling horizontal scrollbars with mouse wheel by holding "Shift" key pressed while scrolling the wheel * added support for single step mouse wheel scrolling by holding "Alt" key pressed while scrolling the wheel (can be combined with "Shift") * changed output file "stderr.txt" on Windows platform now always to be created in the R'n'D sub-directory of the personal documents directory * added Windows message box to direct to "stderr.txt" after error aborts 2006-07-25 * improved general scrollbar handling (when jump-scrolling scrollbars) 2006-07-23 * changed scrollbars to always show last line as first after scrolling (that means jumping n - 1 screen lines instead of n screen lines) 2006-07-22 * fixed level versions of EMC level loader (from V4 to V1, V2 and V3) * fixed level time for EMC levels for V2 engine (V2 and V5 levels) * fixed special handling of vertically stacked acid becoming fake acid 2006-07-16 * fixed bug (very special case) with CE_SCORE_GETS_ZERO, which can affect multiple instances of the same CE, although this kind of change condition usually only affects one single custom element 2006-07-16 * version number set to 3.2.1 2006-07-16 * version 3.2.0 released 2006-06-23 * reorganized level editor element list a bit to match engines better 2006-06-21 * fixed newly introduced bug with wrongly initializing clipboard element 2006-06-19 * fixed bug with displaying visible/invisible level border in editor 2006-06-14 * reorganized some elements in the level editor element list 2006-06-06 * fixed bug with displaying any player as "yellow" when moving into acid * fixed bug with displaying running player when player stopped at border 2006-06-03 * fixed bug with player exploding when moving into acid * fixed bug with level settings being reset in editor and when playing (some compatibility settings being set not only after level loading) * fixed crash bug when number of custom graphic frames was set to zero * fixed bug with teleporting player on walkable tile not working anymore * added partial compatibility support for pre-release-only "CONF" chunk (to make Alan Bond's "color cycle" demo work again :-) ) 2006-05-30 * fixed some bugs when displaying title screens from info screen menu * fixed bug which caused EMC doors #5 to #8 to be passable without keys 2006-05-20 * changed file major version to 3 to reflect level file format changes * uploaded pre-release (test) version 3.2.0-8 binary and source code 2006-05-19 * added new chunk "NAME" to level file format for level name settings * added new chunk "NOTE" to level file format for envelope settings * changed name of chunk "CONF" to "ELEM" (for normal element settings) * updated magic(5) file to recognize changed and new level file chunks * removed change events "change when CE value/score changes" as unneeded 2006-05-17 * changed gravity (which only affects the player) from level property to player property (only makes a difference in multi-player levels) * added change events "change when CE value/score changes" * added change events "change when CE value/score changes of " 2006-05-16 * added new chunk "INFO" to level file format for global level settings * added all element settings from "HEAD" chunk to "CONF" chunk * added all global level settings from "HEAD" chunk to "INFO" chunk 2006-05-09 * changed level file format by adding two new chunks "CUSX" (for custom elements, replacing the previous "CUS4" chunk) and "GRPX" (for group elements, replacing the previous "GRP1" chunk); these new IFF style chunks use the new and flexible "micro chunks inside chunks" technique already used with the new "CONF" chunk (for normal element properties) which makes it possible to easily extend the existing level format (instead of using fixed-length chunks like before, which are either too big due to reserved bytes for future use, or too small when those reserved bytes have all been used and even more data should be stored, requiring the replacement by new and larger chunks just like it went with "CUS1" to "CUS4"); this whole problem now does not exist anymore 2006-05-06 * added credits pages to the "credits" section that were really missing * added some missing element descriptions to the level editor * added down position of switchgate switch to the level editor and allowed the use of both switch positions at the same time * changed use of "Insert" and "Delete" keys to navigate element list in level editor to start of previous or next cascading block of elements 2006-05-05 * added the possibility to view the title screen to the info screen menu * fixed some minor bugs with viewing title screens 2006-05-02 * fixed bug with title (cross)fading in/out when using fullscreen mode 2006-04-30 * fixed bug that forced re-defining of menu settings in local graphics config file which are already defined in existing base config file * fixed small bug that caused door sounds playing when music is enabled 2006-04-29 * added the possibility to define up to five title screens for each level set that are displayed after loading using (cross)fading in/out (this was added to display the various start images of the EMC sets) 2006-04-28 * added "CE score gets zero [of]" to custom element trigger conditions * added setup option to display element token name in level editor 2006-04-19 * added compatibility code for Juergen Bonhagen's menu artwork settings 2006-04-15 * fixed bug with displaying wrong animation frame 0 after CE changes * fixed bug with creating invisible elements when light switch is on 2006-04-06 * added selection between ECS and AGA graphics for EMC levels to setup 2006-04-04 * adjusted font handling for various narrow EMC style fonts 2006-04-03 * changed EM engine behaviour back to re-allow initial rolling springs 2006-04-02 * fixed handling of over-large selectboxes (less error-prone now) * fixed bug when creating GE with walkable element under the player 2006-04-01 * added use of "Insert" and "Delete" keys to navigate element list in level editor to start of custom elements or start of group elements * added virtual elements to access CE value and CE score of elements: - "CE value of triggering element" - "CE score of triggering element" - "CE value of current element" - "CE score of current element" 2006-03-30 * fixed "grass" to "sand" in older EM levels (up to file version V4) 2006-03-29 * changed behaviour of network games with internal errors (because of different client frame counters) from immediately terminating R'n'D to displaying an error message requester and stopping only the game (also to prevent impression of crashes under non command-line runs) * fixed playing network games with the EMC engine (did not work before) * fixed bug with not scrolling the screen in multi-player mode with the focus on player 1 when all players are moving in different directions * fixed bug with keeping pointer to gadget even after its deallocation * fixed bug with allowing "focus on all players" in network games * fixed bug with player focus when playing tapes from network games 2006-03-22 * uploaded pre-release (test) version 3.2.0-7 binary and source code 2006-03-19 * code cleanup for game action control for R'n'D and EMC game engine 2006-03-18 * fixed bug in multi-player movement with focus on both players * added option to control only the focussed player with all input 2006-03-14 * added player focus switching to level tape recording and re-playing 2006-03-13 * fixed some bugs in player focus switching in EMC and RND game engine 2006-03-11 * added special Supaplex animations for Murphy digging and snapping * added special Supaplex animations for Murphy being bored and sleeping 2006-03-10 * added four new yam yams with explicit start direction for EMC engine * fixed bug in src/libgame/text.c with printing text outside the window 2006-03-09 * fixed small bug in EMC level loader (copyright sign in EM II levels) 2006-03-08 * added delayed ignition of EM style dynamite when used in R'n'D engine * added limited movement range to EMC engine when focus on all players 2006-03-06 * fixed bug with missing (zero) score values for native Supaplex levels 2006-03-05 * added "continuous snapping" (snapping many elements while holding the snap key pressed, without releasing the snap key after each element) as a new player setting for more compatibility with the classic games 2006-03-04 * finished scrolling for "focus on all players" in EMC graphics engine 2006-02-28 * level sets with "levels: 0" are ignored for levels, but not artwork * fixed bug when scanning empty level group directories (endless loop) 2006-02-26 * fixed bug with explosion graphic for player using "Murphy" graphic * fixed bug with explosion graphic if player leaves explosion in time * changed some descriptive text in setup menu to use medium-width font * added key shortcut settings for switching player focus to setup menu 2006-02-25 * fixed bug with random value initialization when recording tapes * fixed bug with playing single player tapes when team mode activated 2006-02-22 * fixed little bug when trying to switch to player that does not exist 2006-02-19 * added player switching (visual and quick) to R'n'D and EM game engine * added setup option to select visual or quick in-game player switching 2006-02-16 * added use of "Home" and "End" keys to handle element list in editor 2006-02-15 * fixed bug with adding score when playing tape with EMC game engine * added steel wall border for levels using EMC engine without border * finally fixed delayed scrolling in EMC engine also for small levels 2006-02-12 * fixed potential crash bug in WarnBuggyBase() (missing boundary check) 2006-02-11 * fixed bug with CE change order in TestIfElementTouchesCustomElement() * fixed bug when displaying info element without action, but direction 2006-02-09 * fixed minor graphical problems with springs smashing and slurping (when using R'n'D style graphics instead of EMC style graphics) 2006-02-07 * added scroll delay (as configured in setup) to EMC graphics engine 2006-02-06 * improved screen redraw for EMC graphics engine (faster and smoother) * when not scrolling, do not redraw the whole playfield if not needed 2006-02-03 * added multi-player mode for EMC game engine (with up to four players) 2006-01-28 * added android (can clone elements) from EMC engine to R'n'D engine 2006-01-14 * added spring bumper (reflects spring) from EMC engine to R'n'D engine 2006-01-11 * added selectbox for initial player speed to player settings in editor 2006-01-11 * version 3.1.2 created that is basically version 3.1.1, but with a major bug fixed that prevented editing your own private levels * version 3.1.2 released 2006-01-09 * added magic ball (creates elements) from EMC engine to R'n'D engine 2006-01-07 * uploaded fixed pre-release version 3.2.0-6 binary and source code 2006-01-07 * fixed bug when using "CE can leave behind " * added new change condition "(after/when) creation of " * added new change condition "(after/when) digging " * fixed bug accessing invalid gadget that caused crashes under Windows * deactivated new possibility for multiple CE changes per frame 2006-01-04 * uploaded pre-release (test) version 3.2.0-6 binary and source code 2006-01-02 * added animation types "ce_value" and "ce_score" to graphicsinfo.conf * fixed bug with not keeping CE value for moving CEs with only action * changed CE action selectboxes in editor to be only reset when needed 2006-01-01 * added option "use artwork from element" for custom player artwork * added option "use explosion from element" for player explosions 2005-12-30 * added cascaded element lists in the level editor * added persistence for cascaded element lists by "editorcascade.conf" * added dynamic element list with all elements used in current level * added possibility for multiple CE changes per frame (experimental) 2005-12-28 * uploaded pre-release (test) version 3.2.0-5 binary and source code 2005-12-27 * changed "score for each 10 seconds/steps left" to "1 second/step" * added own score for collecting "extra time" instead of sharing it * added change events "switched by player" and "player switches " * added change events "snapped by player" and "player snaps " * added "set player artwork: " to CE action options * added change event "move of " 2005-12-22 * added "set player shield: off / normal / deadly" to CE action options * added new player option "use level start element" in level editor to set the correct focus at level start to elements from which the player is created later (this did not work before for cascaded CE changes resulting in creation of the player; it is now also possible to create the player from a yam yam which is smashed at level start) 2005-12-20 * added "set player speed: frozen (not moving)" to CE action options * added "move player: l/r/u/d/trigger/-trigger" to CE action options 2005-12-17 * added new player option "block snap field" (enabled by default) to make it possible to show a snapping animation like in Emerald Mine 2005-12-16 * added dynamic selectboxes to custom element action settings in editor * added "CE value" counter for custom elements (instead of "CE count") * added option to use the last "CE value" after custom element change * added option to use the "CE value" of other elements in CE actions * fixed odd behaviour when pressing time orb in levels w/o time limit * added checkbox "use time orb bug" for older levels that use this bug 2005-12-15 * added missing configuration settings for the following elements: - EL_TIMEGATE_SWITCH (time of open time gate) - EL_LIGHT_SWITCH_ACTIVE (time of light switched on) - EL_SHIELD_NORMAL (time of shield duration) - EL_SHIELD_DEADLY (time of shield duration) - EL_EXTRA_TIME (time added to level time) - EL_TIME_ORB_FULL (time added to level time) 2005-12-14 * added "wind direction" as a movement pattern for custom elements * added initial wind direction for balloon / custom elements to editor * added functionality for EL_BALLOON_SWITCH_NONE to R'n'D game engine 2005-12-13 * added parameters for "game of life" and "biomaze" elements to editor 2005-12-12 * added level file chunk "CONF" for generic level and element settings 2005-12-11 * uploaded pre-release (test) version 3.2.0-4 binary and source code 2005-12-11 * skip empty level sets (with "levels: 0"; may be artwork base sets) * added sound action ".page[1]" to ".page[32]" for each CE change page 2005-12-10 * added image config suffix ".clone_from" to copy whole image settings * fixed bug with invalid ("undefined") CE settings in old level files 2005-12-05 * fixed graphical bug with smashing elements falling faster than player 2005-12-03 * fixed major bug which prevented private levels from being edited * fixed bug with precedence of general and special font definitions 2005-12-02 * fixed graphical bug with player animation when player moves slowly 2005-11-29 * uploaded pre-release (test) version 3.2.0-3 binary and source code 2005-11-28 * fixed bug which prevented "global.num_toons: 0" from working 2005-11-27 * major code cleanup (removed all these annoying "#if 0" blocks) 2005-11-26 * added custom element actions for CE change page in level editor 2005-11-19 * fixed music initialization bug in init.c (thanks to David Binderman) * fixed mouse wheel "button" bug in editor (thanks to Tomi Belan) (this bug must probably be fixed at other places, too) 2005-10-16 * fixed buggy '#include "SDL.h"' statements in src/libgame/sdl.h (should be '#include ' instead) 2005-08-20 * fixed bug which prevented "walkable from no direction" from working (due to compatibility code overwriting this setting after loading) 2005-08-15 * fixed bug on Mac OS X (use of reserved name "Random") in EM engine 2005-08-07 * version number temporarily set to 3.1.1 (intermediate bugfix release) * version 3.1.1 released 2005-08-07 * changed some va_arg() arguments from 'long' to 'int', fixing problems on 64-bit architecture systems with LP64 data model 2005-08-06 * fixed bug with bombs not exploding when hitting the last level line (introduced after the release of 3.1.0) 2005-08-06 * added support for dumping small-sized level sketches from editor 2005-07-24 * added recognition of "trigger element" for "change digged element to" (this is not really what the "trigger element" was made for, but its use may seem obvious for leaving back digged elements unchanged) 2005-07-23 * fixed multiple warnings about failed joystick device initialization 2005-06-27 * fixed bug with dynamite dropped on top of just dropped custom element (collect dynamite, collect CE, drop CE => dynamite was also dropped); dynamite can still be dropped, but drop key must be released before 2005-06-27 * fixed bug with wrong start directory when started from file browser (due to this bug, R'n'D could not be started from KDE's Konqueror) 2005-06-26 * fixed bug causing "change when impact" on player not working * fixed wrong priority of "hitting something" over "hitting " * fixed wrong priority of "hit by something" over "hit by " 2005-06-14 * fixed graphical bug which caused the player (being Murphy) to show collecting animations although the element was collected by penguin 2005-06-08 * fixed two bugs causing wrong door background graphics in system.c (in functions "SetBackgroundBitmap()" and "DrawingOnBackground()") 2005-06-06 * fixed graphic bug with exploding bomb and R'n'D graphics in EM engine * added "no direction" to "walkable/passable from" selectbox options 2005-06-05 * enhanced tape autoplay to accept "autoplay [ ...]" format * in tape autoplay, not only report broken, but also missing tapes 2005-05-31 * uploaded pre-release (test) version 3.2.0-2 binary and source code 2005-05-27 * fixed small bug with "linear" animation not working for active lamp 2005-05-24 * fixed bug with moving up despite gravity due to "block last field" * fixed small bug with wrong draw offset when typing name in main menu * when reading user names from "passwd", ignore data after first comma * when creating new "levelinfo.conf", only write some selected entries 2005-04-28 * fixed displaying "imported from/by" on preview with empty string * fixed ignoring draw offset for fonts used for level preview texts 2005-04-24 * fixed a delay problem with SDL and too many mouse motion events * added setup option "skip levels" and level skipping functionality 2005-03-19 * added move speed "not moving" for non-moving CEs, but with direction 2005-03-06 * fixed mapping of obsolete element token names in "editorsetup.conf" * fixed bug with sound "acid.splashing" treated as a loop sound * fixed some little sound bugs in native EM engine 2005-02-20 * fixed small bug when dragging scrollbars to end positions 2005-02-14 * added editor element descriptions written by Aaron Davidson 2005-02-02 * improved fallback handling when configured artwork is not available (now using default artwork instead of exiting when files not found) 2005-02-01 * fixed bug on level selection screen when dragging scrollbar 2005-01-19 * fixed bug which caused broken tapes when appending to EM engine tapes 2005-01-17 * uploaded pre-release (test) version 3.2.0-1 binary and source code 2005-01-17 * added code to replace changed artwork config tokens with other tokens (needed for backwards compatibility, so that older tokens still work) 2005-01-16 * added native R'n'D graphics for some new EMC elements in EM engine 2005-01-15 * fixed some bugs in the EM engine integration code * changed EM engine code to allow diagonal movement * changed EM engine code to allow use of separate snap and drop keys 2005-01-03 * fixed some redraw bugs when using EM engine 2005-01-02 * fixed bug with not converting RND levels which are set to use native engine to native level structure when loading 2005-01-01 * uploaded pre-release (test) version 3.2.0-0 binary and source code 2005-01-01 * version number set to 3.2.0 2004-12-30 * level data now reset to defaults after attempt to load invalid file 2004-11-13 * added use of "editorsetup.conf" for different level sets 2004-10-26 * added auto-detection for various types of Emerald Mine level files 2004-10-17 * fixed bug with scrollbars getting too small when list is very large 2004-10-09 * fixed bug with 3+3 (cross) sized explosion not making explosion sound 2004-10-04 * added most level editor configuration gadgets for new EMC elements 2004-10-01 * added more element and graphic definitions for new EMC elements 2004-09-27 * modified native EM engine to use integrated R'n'D sound system 2004-09-21 * added SDL support to graphics functions in native EM engine (by always using generic libgame interface functions) 2004-09-20 * fixed bug in frame synchronization in native EM engine 2004-09-18 * added code to convert levels between R'n'D and native EM engine 2004-08-23 * new Emerald Mine engine can now play levels selected in main menu 2004-08-16 * fixed big memory leak in function "CreateBitmapWithSmallBitmaps()" (which creates scaled down graphics for level editor and preview); there's still a memory leak somewhere in the artwork handling code * added "scale image up" functionality to X11 version of zoom function 2004-08-14 * first attempts to integrate new, native Emerald Mine Club engine 2004-08-07 * fixed bug in gadget code which caused reset of CEs in level editor (example: pressing 'b' [grab brush] on CE config page erased values) (solution: check if gadgets in ClickOnGadget() are really mapped) * improved level change detection in editor (settings now also checked) * fixed bug with "can move into acid" and "don't collide with" state 2004-07-29 * fixed maze runner style CEs to use the configured move delay value 2004-06-27 * added Aaron Davidson's tutorial level set to the "Tutorials" section 2004-06-20 * fixed engine change that broke 3.0.8 levels like "Walpurgis Gardens" * fixed the above fix because it broke level set "machine" (*sigh*) * fixed random element placement in level editor to work as expected * fixed undefined graphic of runtime element "EL_AMOEBA_TO_DIAMOND" 2004-06-15 * re-recorded tape for BD2K3, level 010 (broken due to bugfix) 2004-06-13 * fixed bug (missing array boundary check) which caused broken tapes * fixed bug (when loading level template) which caused broken levels * fixed bug with new block last field code when using non-yellow player 2004-06-12 * fixed bug when pressing "stop, pause, stop, play" on tape recorder * internal change of how the player blocks the last field when moving * fixed blocking delay of last field for EM and SP style block delay * fixed bug where the player had to wait for the usual move delay after unsuccessfully trying to move, when he directly could move after that * the last two changes should make original Supaplex level 93 solvable * improved use of random number generator to make it less predictable * fixed behaviour of slippery SP elements to let slip left, then right 2004-06-11 * fixed bug with wrong door state after trying to quickload empty tape * fixed waste of static memory usage of the binary, making it smaller * fixed very little graphical bug in Supaplex explosion 2004-06-07 * version number set to 3.1.1 2004-06-07 * version 3.1.0 released 2004-06-07 * fixed bug with crash when writing user levelinfo.conf the first time 2004-06-06 * added option "convert LEVELDIR [NR]" to command line batch commands * re-converted Supaplex levels to apply latest engine fixes * changed "use graphic/sound of element" to "use graphic of element" due to compatibility problems with some levels ("bug machine" etc.) 2004-05-23 * fixed bug with CE change replacing player with same or other player 2004-05-16 * fixed bug with opaque font in envelope with background graphic when background graphic is not transparent itself 2004-05-12 * added "gravity on" and "gravity off" ports for Supaplex compatibility * corrected original Supaplex level loading code to use these new ports * also corrected Supaplex loader to auto-count infotrons if set to zero 2004-05-10 * fixed bug with missing initialization of "modified" flag for GEs 2004-05-09 * fixed bug that caused endless recursion loop when relocating player * fixed tape recorder bug in "step mode" when using "pause before end" * fixed tape recorder bug when changing from "warp forward" mode 2004-05-08 * fixed bug with "when touching" for pushed elements at last position 2004-05-05 * fixed bug that caused two activated toolbox buttons in level editor * fixed bug with exploding dynabomb under player due to other explosion 2004-05-02 * fixed bug with creating walkable custom element under player (again) * fixed bug with not copying explosion type when copying CEs in editor * fixed graphical bug when drawing player in setup menu (input devices) * fixed graphical bug when the player is pushing an accessible element * fixed bug with classic switchable elements triggering CE changes * fixed bug with entering/leaving walkable element in RelocatePlayer() * fixed crash bug when CE leaves behind the trigger player element 2004-04-30 * fixed bug with broken tubes after placing/exploding dynamite in them * fixed bug with exploding dynamite under player due to other explosion * fixed bug with not resetting push delay under certain circumstances 2004-04-27 * added option "handicap" for "levelinfo.conf" (thanks to Niko Böhm) * added network multiplayer code for Windows (thanks to Niko Böhm) 2004-04-25 * added option "reachable despite gravity" for gravity movement * changed gravity movement of most classic walkable and passable elements back to "not reachable" (for compatibility reasons) 2004-04-24 * fixed (removed) "indestructible" / "can explode" dependency in editor * fixed (removed) "accessible inside" / "protected" dependency * fixed (removed) "step mode" / "shield time" dependency 2004-04-23 * fixed dynabombs exploding now into anything diggable * fixed Supaplex style gravity movement into buggy base now impossible * added pressing key "space" as valid action to select menu options 2004-04-20 * added "replace when walkable" to relocate player to walkable element * added "enter"/"leave" event for elements affected by relocation * fixed "direct"/"indirect" change order also for "when change" event * fixed graphical bug when pushing things from elements walkable inside 2004-04-18 * fixed graphic bug when player is snapping while moving in old levels * fixed bug when a moving custom element leaves a player element behind * fixed bug with mole not disappearing when moving into acid pool * fixed bug with incomplete path setting when using "--basepath" option * moving CE can now leave walkable elements behind under the player * when relocating, player can be set on walkable element now * fixed another gravity movement bug 2004-04-12 * uploaded pre-release (test) version 3.1.0-2 binary and source code 2004-04-10 * added "collectible" and "removable" to extended replacement types (where "removable" replaces "diggable" and "collectible" elements) * added "collectible & throwable" (to throw element to the next field) * fixed bug with CEs digging elements that are just about to explode * changed mouse cursor now always being visible when game is paused 2004-04-09 * added possibility to push/press accessible elements from a side that is not accessible * fixed bug with not setting actual date when appending to tape 2004-04-07 * fixed bug with incorrectly initialized custom element editor graphics 2004-04-04 * corrected set "Contributions_1995-2000/rnd_kjell_kristiansson": - number of levels corrected from 18 to 17 in "levelinfo.conf" 2004-03-31 * fixed bug with destroyed robot wheel still attracting robots forever * fixed bug with time gate switch deactivating after robot wheel time (while the time gate itself is not affected by this misbehaviour) * changed behaviour of BD style amoeba to always get blocked by player (before it was different when there were non-BD elements in level) * fixed bug with player destroying indestructable elements with shield 2004-03-26 * added option to make growing elements grow into anything diggable (for the various amoeba types, biomaze and "game of life") 2004-03-24 * fixed bug with movable elements not moving after left behind by CEs * changed gravity movement to anything diggable, not only sand/base * optionally allowing passing to walkable element, not only empty space * added option "can pass to walkable element" for players * finally fixed gravity movement (hopefully) 2004-03-23 * fixed bug with movable elements not moving anymore after falling down 2004-03-22 * fixed another bug with custom elements digging and leaving elements * fixed bug with "along left/right side" and automatic start direction * trigger elements now also displayed when "more custom" deactivated * fixed bug with clipboard element initialized when loading new level * added option "drop delay" to set delay before dropping next element 2004-03-21 * uploaded pre-release (test) version 3.1.0-1 binary and source code 2004-03-20 * added copy and paste functions for custom change pages * enhanced graphical display and functionality of tape recorder * fixed bug with custom elements digging and leaving elements 2004-03-19 * added move speed faster than "very fast" for custom elements * fixed bug with 3+3 style explosions and missing border content * fixed little bug when copying custom elements in the editor * enhanced custom element changes by more side trigger actions 2004-03-16 * added option "no scrolling when relocating" for instant teleporting * uploaded pre-release (test) version 3.1.0-0 binary and source code 2004-03-15 * added trigger element and trigger player to use as target elements * added copy and paste functions for custom and group elements 2004-03-14 * fixed graphical bug when displaying explosion animations * fixed bug when appending to tapes, resulting in broken tapes * re-recorded a few tapes broken by fixing gravity checking bug 2004-03-13 * "can move into acid" property now for all elements independently * "can fall into acid" property for player stored in same bitfield now * added option for deadliness of Supaplex 'sniksnak' and 'electron' * version number set to 3.1.0 (finally!) 2004-03-09 * changed tape recording to only record input, not programmed actions 2004-03-08 * fixed totally broken (every 8th frame skipped) step-by-step recording * fixed bug with requester not displayed when quick-loading interrupted * added option "can fall into acid (with gravity)" for players * fixed bug with player not falling when snapping down with gravity 2004-03-07 * fixed bug which messed up key config when using keypad number keys 2004-03-03 * fixed bug which allowed moving upwards even when gravity was active * fixed bug with missing error handling when dumping levels or tapes 2004-03-02 * added different colored editor graphics for Supaplex gravity tubes 2004-03-01 * fixed bug that allowed solvable tapes for unsolvable levels 2004-02-28 * use unlimited number of droppable elements when "count" set to zero * added option to use step limit instead of time limit for level 2004-02-27 * added player and change page as trigger for custom element change 2004-02-24 * fixed bug with exploding amoeba (explosion 3x3 instead of 1x1) 2004-02-22 * fixed bug with dark yamyam changing to acid when moving over acid * fixed handling of levels with more than 999 seconds level time (example: level 76 of "Denmine") 2004-02-21 * "spring push bug" reintroduced as configurable element property * fixed bug with missing properties for "mole" * fixed bug that showed up when fixing the above "mole" properties bug * added option "can move into acid" for all movable elements * fixed graphical bug for elements moving into acid * changed event handling to handle all pending events before going on 2004-02-17 * fixed bug which caused all CE change pages to be ignored which had the same change event, but used a different element side (reported by Simon Forsberg) * fixed bug which caused elements that can move and fall and that are transported by a conveyor belt to continue moving into that direction after leaving the conveyor belt, regardless of their own movement type; only elements which can not move are transported now (reported by Simon Forsberg) * fixed bug which could cause an array overflow in RelocatePlayer() (reported by Niko Böhm) * changed Emerald Mine style "passable / over" elements to "protected" (fixing unsolvable level 10 of "Bondmine 9" with bug beside gate) * added new option to select from which side a "walkable/passable" element can be entered 2004-02-16 * added explosion and ignition delay for elements that can explode 2004-02-05 * fixed bug which caused player not being protected against enemies when a CE was "walkable / inside" and was not "indestructible" * added "walkable/passable" fields to be "protected/unprotected" against enemies, even if not accessible "inside" but "over/under" 2004-02-04 * corrected move pattern to 32 bit and initial move direction to 8 bit 2004-02-03 * added second custom element base configuration page 2004-02-02 * added some special EMC mappings to Emerald Mine level loader (also covering previously unknown element in level 0 of "Bondmine 8") 2004-01-30 * added option to block last field when player is moving (for Supaplex) * adjusted push delay of Supaplex elements * removed delays for envelopes etc. when replaying with maximum speed * fixed bug when dropping element on a field that just changed to empty 2004-01-29 * fixed bug: infotrons can now smash yellow disks * fixed bug: when gravity active, port above player can now be entered * removed "one white dot" mouse pointer which irritated some people 2004-01-26 * added "choice type" for group element selection 2004-01-25 * fixed bug with initial invulnerability of non-yellow player 2004-01-23 * added level loader for loading native Supaplex packed levels (including multi-part levels like the "splvls99" levels) 2004-01-19 * fixed bug which allowed creating emeralds by escaping explosions 2004-01-18 * custom elements can change (limited) or leave (unlimited) elements * finally added multiple matches using group elements * added shortcut to dump brush (type ":DB" in editor) for use in forum 2004-01-17 * added new start movement type "previous" for continued CE movement * added new start movement type "random" for random CE movement start 2004-01-17 * added new element "sokoban_field_player" needed for Sokoban levels (thanks to Ed Booker for pointing this out!) 2004-01-15 * added elements that can be digged or left behind by custom elements 2004-01-12 * added group elements for multiple matches and random element creation 2004-01-11 * fixed some graphical errors displayed in old levels 2004-01-10 * fixed wrong double speed movement after passing closing gates 2004-01-03 * added level loader for loading native Emerald Mine levels 2004-01-02 * changes for "shooting" style CE movement 2004-01-01 * Happy New Year! ;-) 2003-12-27 * changed default snap/drop keys from left/right Shift to Control keys 2003-12-27 * fixed bug with dead player getting reanimated from custom element 2003-12-14 * fixed bug with wrong penguin graphics (when entering exit) 2003-12-14 * fixed bug with wrong "Murphy" graphics (when digging etc.) 2003-12-14 * version number set to 3.0.9 2003-12-14 * version 3.0.8 released 2003-12-13 * added function checked_free() 2003-12-13 * fixed bug with double nut cracking sound (by eliminating "default element action sound" assignment in init.c) 2003-12-10 * fixed crash when no music info files are available 2003-12-07 * fixed boring and sleeping sounds 2003-12-05 * added "maze runner" and "maze hunter" movement types * added extended collision conditions for custom elements 2003-12-03 * added warnings for undefined token values in artwork config files 2003-12-02 * added menu entry for level set information to the info screen 2003-12-02 * fixed bug with wrong default impact sound for colored emeralds 2003-11-30 * added several sub-screens for the info screen * menu text now also clickable (not only blue/red sphere left of it) 2003-11-25 * added configurable "bored" and "sleeping" animations for the player * added "awakening" sound for player when waking up after sleeping 2003-11-22 * added "copy" and "exchange" functions for custom elements to editor 2003-11-21 * added configurable element animations for info screen 2003-11-20 * added configurable music credits for info screen 2003-11-19 * finally fixed tape recording when player is created from CE change 2003-11-18 * added "editorsetup.conf" for editor element list configuration 2003-11-16 * added "musicinfo.conf" for menu and level music configuration 2003-11-14 * fixed a very nasty bug in dragon turning code in TurnRoundExt() (that only showed up on Linux, but not on Windows systems) 2003-11-13 * fixed turning movement of butterflies and fireflies (no frame reset) * enhanced sniksnak turning movement (two steps instead of only one) 2003-11-10 * version number set to 3.0.8 2003-11-10 * version 3.0.7 released 2003-11-09 * fixed reset of player animation frame when, for example, walking, digging or collecting share the same animation * fixed CE with "deadly when touching" exploding when touching amoeba 2003-11-08 * fixed tape recording when player is created from CE element change 2003-11-04 * introduced "turning..." action graphic for elements with move delay (non-CE: bug, spaceship, sniksnak, mole, pacman, yamyam) * added turning animations for bug, spaceship and sniksnak 2003-11-03 * prevent "extended" changed elements from delay change in same frame 2003-11-02 * fixed bug when pushing element that can move away to the side (like pushing falling elements, but now with moving elements) 2003-11-01 * finally fixed serious bug in code for delayed element pushing (again) 2003-10-19 * unavailable setup options now marked as "n/a" instead of "off" * new boolean directive "latest_engine" for "levelinfo.conf": when set to "true", levels are always played with the latest game engine, which is desired for levels that are imported from other games; all other levels are played with the engine version stored in level file (which is normally the engine version the level was created with) 2003-10-18 * fixed serious bug in code for delayed element pushing * fixed little bug in animation frame selection for pushed elements * speed-up of reading config file for verbose output 2003-10-08 * added configuration option for opening and closing Supaplex exit * added configuration option for moving up/down animation for Murphy * fixed incorrectly displayed animation for attacking dragon * fixed bug with not setting initial gravity for each new game * fixed bug with teleportation of player by custom element change * fixed bug with player not getting smashed by rock sometimes 2003-10-06 * version number set to 3.0.7 2003-10-06 * version 3.0.6 released 2003-10-05 * added support for MP3 music for SDL version through SMPEG library 2003-10-03 * fixed bug when initializing font graphic structure * fixed bug with animation mode "pingpong" when using only 1 frame * fixed bug with extended change target introduced in 3.0.5 * fixed bug where passing over moving element doubles player speed * fixed bug with elements continuing to move into push direction * fixed bug with duplicated player when dropping bomb with shield on * added "switching" event for custom elements ("pressing" only once) * fixed switching bug (resetting flag when not switching but not idle) 2003-09-29 * fixed element tokens for certain file elements with ".active" etc. 2003-09-29 * version number set to 3.0.6 2003-09-29 * version 3.0.5 released 2003-09-28 * now four envelope elements available * font, background, animation and sound for envelope now configurable * main menu doors opening/closing animation type now configurable 2003-09-27 * active/inactive sides configurable for custom element changes * new movement type "move when pushed" available for custom elements 2003-09-20 * fixed bug in multiple config pages loader code that caused crashes 2003-09-13 * enhanced (remaining low-resolution) Supaplex graphics 2003-09-13 * version number set to 3.0.5 2003-09-13 * version 3.0.4 released 2003-09-12 src/tools.c * fixed bug in custom definition of crumbled element graphics 2003-09-11 src/files.c * fixed bug in multiple config pages code that caused crashes 2003-09-08 * version number set to 3.0.4 2003-09-08 * version 3.0.3 released 2003-09-07 * added music to Supaplex classic level set 2003-09-07 src/libgame/misc.c * added support for loading various music formats through SDL_mixer 2003-09-06 (various source files) * fixed several nasty bugs that may have caused crashes on some systems * added envelope content which gets displayed when collecting envelope * added multiple change event pages for custom elements 2003-08-24 src/game.c * fixed problem with player animation when snapping and moving 2003-08-23 src/screens.c, src/cartoons.c, src/libgame/toons.c * fixed problem with flickering when drawing toon animations 2003-08-23 src/libgame/sdl.c * fixed problem with setting mouse cursor in SDL version in fullscreen 2003-08-23 src/game.c * fixed bug (missing array boundary check) which could crash the game 2003-08-23 * version number set to 3.0.3 2003-08-22 * version 3.0.2 released 2003-08-21 src/game.c * fixed bug with creating inaccessible elements at player position 2003-08-20 src/init.c * fixed bug with not finding current level artwork directory 2003-08-20 src/files.c * fixed bug with choosing wrong engine version when playing tapes * fixed bug with messing up custom element properties in 3.0.0 levels 2003-08-18 * version number set to 3.0.2 2003-08-18 * version 3.0.1 released 2003-08-17 (no source files affected) * changed all "classic" PCX image files with 16 colors or less to 256 color (8 bit) storage format, because the Allegro game library cannot handle PCX files with less than 256 colors (contributed graphics are not affected and might look wrong in the DOS version) 2003-08-16 src/init.c * fixed bug which (for example) crashed the level editor when defining "dynamite.EDITOR: [NONE]", because graphics may not be undefined (only set to default) -- invalid graphics now set to default graphic 2003-08-16 src/init.c * fixed graphical bug of player digging/collecting/snapping element when no corresponding graphic/animation is defined for this action, resulting in player being drawn as EL_EMPTY (which should only be done to elements being collected, but not to the player) 2003-08-16 src/game.c * fixed small graphical bug of player not totally moving into exit 2003-08-16 src/libgame/setup.c * fixed bug with wrong MS-DOS 8.3 filename conversion 2003-08-16 src/tools.c * fixed bug with invisible mouse cursor when pressing ESC while playing 2003-08-16 (various source files) * added another 128 custom elements (disabled in editor by default) 2003-08-16 src/editor.c * fixed NULL string bug causing Solaris to crash in sprintf() 2003-08-16 src/screen.c * fixed drawing over scrollbar on level selection with custom fonts 2003-08-15 src/game.c * cleanup of simple sounds / loop sounds / music settings 2003-08-08 (various source files) * added custom element property for dropping collected elements 2003-08-08 src/conf_gfx.c * fixed bug with missing graphic for active red disk bomb 2003-08-07 src/files.c, src/editor.c src/game.c, src/main.h * extended variable "level.gravity" to "level.initial_gravity" and "game.current_gravity" to prevent level setting from being changed by playing the level (keeping the runtime value after playing) * fixed graphics bug when digging element that has 'crumbled' graphic definition, but not 'diggable' graphic definition 2003-08-06 * version number set to 3.0.1 2003-08-05 * version 3.0.0 released 2003-08-05 * various bug fixes; among others: - fixed bug with pushing spring over empty space - fixed bug with leaving tube while placing dynamite - fixed bug with explosion of smashed penguins - allow Murphy player graphic in levels with non-Supaplex elements 2003-04-07 * various changes * I have forgotten to document changes for some time 2002-12-31 * pre-release version 2.2.0rc1 released 2002-08-25 src/libgame/setup.c, src/libgame/sound.c * Level series artwork now configurable via level series config file. "levelinfo.conf" may now contain directives "graphics_set", "sounds_set" and "music_set" to select artwork sets which are globally defined or which are included into other level series. 2002-08-25 * version number set to 2.1.2 2002-08-13 * version 2.1.1 released 2002-08-10 src/libgame/system.h * Default "snap" and "bomb" keys for Mac OS X set to left control key and keypad enter key -- Macs seem not to distinguish between left and right modifier keys (both generate scan code for left key). :-( 2002-08-10 src/libgame/sound.c * Fixed small NetBSD compilation bug. Thanks to Adam Ciarcinski for the bug report. 2002-08-10 src/libgame/sound.c * Added support for audio device "/dev/sound/dsp" (devfs). Thanks to Christoph Bauer for the corresponding report. 2002-08-10 src/libgame/sound.c * Bug fixed that caused regular crashes under SDL/Windows version. Mixer_InsertSound(): Always stop music before playing new music, else "mixer_active_channels" can get fucked up. Thanks to Keith Peterston for the bug report. 2002-08-10 * version number set to 2.1.1 2002-08-05 * version 2.1.0 released 2002-05-31 src/libgame/image.c * Read_PCX_to_Pixmap(): Fixed bad memory leak by freeing "ximageinfo" and "image" after converting loaded PCX image file to X11 Pixmap. This really showed up when reloading custom artwork several times. 2002-05-20 src/libgame/sound.c * added support for 16 bit WAV sound files 2002-05-19 * version number set to 2.1.0 2002-04-03 to 2002-05-19 (various source files) * graphics, sounds and music now fully configurable * bug fixed that prevented walking through tubes when gravity on * added support for TrueColor PCX graphics files * enhanced sound system (especially regarding stereo and loop sounds) 2002-04-02 src/events.c, src/editor.c * Make Escape key less aggressive when playing or when editing level. This can be configured as an option in the setup menu. (Default is "less aggressive" which means "ask user if something can be lost" when pressing the Escape key.) 2002-04-02 src/screen.c * Added "graphics setup" screen. 2002-04-01 src/screen.c * Changed "choose level" setup screen stuff to be more generic (to make it easier to add more "choose from generic tree" setup screens). 2002-04-01 src/config.c, src/timestamp.h * Added source files "src/config.[ch]" and "src/timestamp.h" (which automatically gets created by "src/Makefile" and contains an actual compile-time timestamp to identify development versions of the game). 2002-04-01 src/libgame/misc.c * Added (currently incomplete) function "getKeyFromKeyName()" simply for orthogonality. When really needed, this function must be extended accordingly (analog to "getKeyFromX11KeyName()"). 2002-04-01 src/libgame/setup.c * Changed setup "TYPE_KEY" (internal, X11 style key symbol name) to "TYPE_KEY_X11" and added "TYPE_KEY" (human readable key symbol name). (This was needed for custom key setup handling in "src/screens.c".) 2002-03-31 src/tape.c, src/events.c * Added quick game/tape save/load functions to tape stuff which can be invoked by a keyboard shortcut. Default: "F1" saves game/tape, "F2" loads previously recorded tape and directly goes into recording mode from the end of the tape (therefore appending to the tape). 2002-03-31 src/tape.c * Added "index mark" function to tape recorder. When playing or recording, "eject" button changes to "index" button. Setting index mark is not yet implemented, but pressing index button when playing allows very quick advancing to end of tape (when normal playing), very fast forward mode (when playing with normal fast forward) or very fast reaching of "pause before end of tape" (when playing with "pause before end" playing mode). 2002-03-30 src/cartoons.c * Moved some stuff from cartoons.c to the new "src/libgame/toons.c". 2002-03-30 src/libgame/toons.c * New libgame source file "toons.c" for the program independant part of the toon stuff. 2002-03-29 src/screen.c * Changed setup screen stuff to be more generic (to make it easier to add more setup screens). 2002-03-29 src/libgame/setup.c * Changed "LoadLevelInfoFromLevelDir()" so that not only directories with level sub-directories are recognized, but also directories that directly contain level files. 2002-03-29 src/libgame/sound.c * Changed "boolean stereo = TRUE;" to "static boolean stereo = TRUE;". (This was a bug that showed up only when in mono audio mode.) 2002-03-24 src/libgame/x11.c, src/libgame/sdl.c, src/libgame/image.c * Changed image loading code to not exit on error, but set error by using "SetError()" accordingly. Image loading errors must now be catched by above layers (src/init.c for example). 2002-03-24 src/libgame/misc.c * New functions "SetError()" and "GetError()" to provide more flexible error handling. 2002-03-23 src/main.c, src/main.h * Various changes due to the introduction of the new libgame files "setup.c" and "joystick.c". 2002-03-23 src/files.c * Generic parts of "src/files.c" (mainly setup and level directory stuff) moved to new libgame file "src/libgame/setup.c". 2002-03-23 src/joystick.c * File "src/joystick.c" moved to libgame source tree, with correspondig changes. 2002-03-23 src/libgame/system.c, src/libgame/system.h * Various changes due to the introduction of the new files "setup.c" and "joystick.c". 2002-03-23 src/libgame/setup.c * New libgame source file "setup.c" that contains now most setup and level directory stuff previously handled in "src/files.c". 2002-03-23 src/libgame/joystick.c * New libgame source file "joystick.c" that contains now all joystick stuff previously handled in "src/joystick.c" of "Rocks'n'Diamonds". 2002-03-22 src/screens.c * "HandleChooseLevel()": Another bug in level series navigation fixed. (Wrong level series information displayed when entering main group.) 2002-03-22 src/editor.c * Slight change to support new gadget event "GD_EVENT_INFO_LEAVING". 2002-03-22 src/editor.c * Changed behaviour of "Escape" key in level editor to be more intuitive: When in "Element Properties" or "Level Info" mode, return to "Drawing Mode" instead of leaving the level editor. 2002-03-22 src/libgame/misc.c, src/libgame/sound.c * Added command line option "-s" / "--sounds" and "-m" / "--music" to specify alternative sound and music directories. (The former shortcut "-s" for "--serveronly" has changed accordingly.) 2002-03-22 src/libgame/gadgets.c * Added new gadget events for displaying gadget info texts: "GD_EVENT_INFO_ENTERING" and "GD_EVENT_INFO_LEAVING". Before, the info text callback function was only called when entering a gadget (implicit "GD_EVENT_INFO_ENTERING"). But the info text was never erased. This can now be done by checking the event type in the info callback function. 2002-03-21 src/game.c, src/editor.c, src/files.c * 2.0.1 introduced the corrected "Emerald Mine" style behaviour of gems (emeralds, diamonds, ...) slipping down from normal wall, steel wall and growing wall (as in E.M.C. style levels). Although the behaviour of contributed and private levels wasn't changed (due to the use of "level.game_version"; see previous entry), editing those levels will (of course) change the behaviour accordingly. This change seems a bit too hard after thinking about it, because the EM style behaviour is not the "expected" behaviour (gems would normally only slip down from "rounded" walls). Therefore this was now changed to an element property for gem style elements, with the default setting "off" (which means: no special EM style behaviour). To fix older converted levels, this flag is set to "on" for pre-2.0 levels that are neither contributed nor private levels. 2002-03-20 src/files.h * Corrected settings for "level.game_version" depending of level type. (Contributed and private levels always get played with game engine version they were created with, while converted levels always get played with the most recent version of the game engine, to let new corrections of the emulation behaviour take effect.) 2002-03-20 src/main.h * Added "#include ". This seems to be needed by "tape.c" for compiling the SDL version on some systems. Thanks to the several people who pointed this out. 2002-03-20 src/libgame/gadgets.c * "va_arg(ap, boolean)" changed to "(boolean)va_arg(ap, int)"; this caused problems especially on PowerPC architecture (although it is wrong on i386 and other architectures, too) 2002-03-20 src/libgame/pcx.c, src/libgame/image.c * Added support for loading and displaying true-color PCX files. 2002-03-20 src/libgame/misc.c, src/libgame/x11.c * Added command line option "-g" / "--graphics" to specify an alternative graphics directory. 2002-03-19 * Version number set to 2.0.2. 2002-03-19 * Version 2.0.1 released. 2002-03-19 src/libgame/system.c, src/libgame/sdl.c [src/tools.c] * Moved function "GetPixel()" from src/tools.c ("Mirror Magic" code) to libgame source files; needed for SDL fullscreen bug workaround to work correctly. 2002-03-18 src/screens.c * "HandleChooseLevel()": Small bug in level series navigation fixed. 2002-03-18 src/files.c [src/libgame/misc.c] * Moved some common functions from src/files.c to src/libgame/misc.c. 2002-03-18 src/files.c [src/libgame/misc.c] * Changed permissions for new directories and saved files (especially score files) according to suggestions of Debian users and mantainers. Thanks to Drew Parsons for the patch. 2002-03-18 src/libgame/misc.c [src/files.c] * Moved some common functions from src/files.c to src/libgame/misc.c. 2002-03-18 src/libgame/misc.c [src/files.c] * Changed permissions for new directories and saved files (especially score files) according to suggestions of Debian users and mantainers. Thanks to Drew Parsons for the patch. 2002-03-17 src/files.c * Changed "{Load|Save}{Level|Tape}()" to IFF style file format: Replaced "cookie" header string ("ROCKSNDIAMONDS_...\n") with real IFF style header "RND1....XXXX" (where "XXXX" is "CAVE" for levels and "TAPE" for tapes). Old "cookie" style format is still supported for reading. New level and tape files are written in new format. * New IFF chunk "VERS" contains version numbers for file and game (where "game version" is the version of the program that wrote the file, and "file version" is a version number to distinguish files with different format, for example after adding new features). 2002-03-17 src/libgame/sound.c * Bug in "StopMusic()" fixed: SDL_mixer functions may be called even when sound not available. Thanks to Drew Parsons for the patch. 2002-03-15 src/screen.c * "DrawHallOfFame()": "FadeSounds()" when entering the hall of fame. (Before, you heard a mixture of the in-game music and the hall-of-fame music.) 2002-03-15 src/libgame/sound.c, src/libgame/platform.h * Added /dev/dsp (streaming audio) support for NetBSD (instead of the /dev/audio (ulaw) based Unix audio interface). Thanks to Krister Walfridsson for the patches. 2002-03-15 src/libgame/sdl.c * Workaround for fullscreen bug in WIN32 version of SDL (at least in the currently actual version 1.2.3) by using "standard" screen resolutions like 800x600 and mapping all input (mouse events) and output (screen drawing) accordingly. 2002-03-14 src/events.c * Function "DumpTape()" (files.c) now available by pressing 't' from main menu (when in DEBUG mode). 2002-03-14 src/game.c * "GameWon()": When game was won playing a tape, now there is no delay raising the score and no corresponding sound is played. 2002-03-14 src/files.c * Changed "LoadTape()" for real chunk support and also adjusted "SaveTape()" accordingly. 2002-03-14 src/game.c, src/tape.c, src/files.c * Important changes to tape format: The old tape format stored all actions with a real effect with a corresponding delay between the stored actions. This had some major disadvantages (for example, push delays had to be ignored, pressing a button for some seconds mutated to several single button presses because of the non-action delays between two action frames etc.). The new tape format just stupidly records all device actions and replays them later. I really don't know why I haven't solved it that way before?! Old-style tapes (with tape file version less than 2.0) get converted to the new format on-the-fly when loading and can therefore still be played; only some minor parts of the old-style tape handling code was needed. (A perfect conversion is not possible, because there is information missing about the device actions between two action frames.) 2002-03-14 src/files.c * New function "DumpTape()" to dump the contents of the current tape in a human readable format. 2002-03-14 src/game.c * Small tape bug fixed: When automatically advancing to next level after a game was won, the tape from the previous level still was loaded as a tape for the new level. 2002-03-14 src/tape.c * Small graphical bug fixed: When pressing ""Record" or "Play" on tape, cartoons did not get completely removed because StopAnimation() was not called. 2002-03-13 src/files.c * Changed "LoadLevel()" and "SaveLevel()" to add new chunk "CNT2". Fixed bug of "CONT" and "BODY" (chunk size was set to 8-bit element size even when using 16-bit elements). Added new chunk "CNT2" for 16-bit amoeba content (previously written in 8-bit field in "HEAD" chunk even when content was 16-bit element). "CNT2" should now be able to store content for arbitrary elements (up to eight blocks of 3 x 3 element arrays). All "CNT2" elements will always be stored as 16-bit elements. "CONT" (with 8/16-bit elements) now obsolete. 2002-03-13 src/files.c * Changed "LoadLevel()" for real chunk support. 2002-03-12 src/game.c * Fixed problem (introduced after 2.0.0 release) with penguins not getting killed by enemies 2002-02-28 src/libgame/sound.c * Fixed small problem with new SDL_Mixer 1.2.1: Mix_VolumeMusic() must be called _after_ Mix_PlayMusic(), or it has no effect. 2002-02-24 src/game.c, src/main.h * Added "player->is_moving"; now "player->last_move_dir" does not contain any information if the player is just moving at the moment or not. Before, "player->last_move_dir" was misused for this purpose for the robot stuff (robots don't kill players when they are moving). But setting "player->last_move_dir" to MV_NO_MOVING broke tapes when walking through pipes! ("IS_MOVING()" uses "MovPos[][]", but this fails when it is 0 in a continuous movement. This fact is ignored for friends and enemies, though.) mirrormagic-3.0.0/levels/0000755000175000017500000000000013263214144014625 5ustar aeglosaeglosmirrormagic-3.0.0/levels/Classic_Games/0000775000175000017500000000000013251222062017317 5ustar aeglosaeglosmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/0000755000175000017500000000000013255703254023010 5ustar aeglosaeglosmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/052.level0000644000175000017500000000066013053577622024355 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 52AUTH Costa PanayiBODY313031313130313101000000000101313030303030313100000000000001400ÿ0000000þ0:100000000000001_1^0`0\0]0_0\1c101000000000101b1]0]1c1_1\0a1^mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/029.level0000644000175000017500000000066013053577622024361 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 29AUTH Costa PanayiBODYø111111111111111111111ø111ú11111111111121111ñ121121112Q21111;11211111211111,11111111111111ò11111ÿ11111ð110111111111111û151û111111111111mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/053.level0000644000175000017500000000066013053577622024356 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 53AUTH Costa PanayiBODY%21ó0000U12*////##00/,,,.00*000000>00000ú0*ò0000/////0/*0,0000/$0000/*0#//%L1%*///'*ú0?21%11%*$2+%ý00,////#!0%11+50/2110òü03129mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/008.level0000644000175000017500000000066013053577622024356 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 8AUTH Costa PanayiBODY7/###+%0#020?08*111"!000ó000'1211+00000000/%2221*,00000ü0301212030000ü00#%2121*#0000÷000-,,,,.0000000000000000100ñ02ú20ô00>mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/010.level0000644000175000017500000000066013053577622024347 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 10AUTH Costa PanayiBODYü1õ1ó0ü0ò1ø2ø0ö0û0ù1ö1÷0÷0þ0û2ù1þ2ÿ0ú0ô2ú1þ1ÿ0ø0û0ò0õ1ý0ó0ö1ñ0ö1ó0ó0ù0þ0ÿ1õ0ý0ô0ü1ý0ý1ò0ú0ò0ü0ò1ý0ø0ù0ô1õ0ú1û0÷0ý1ú1û0þ250ü0þ1õ2ø0÷1ý09mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/014.level0000644000175000017500000000066013053577622024353 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 14AUTH Costa PanayiBODY7811111111ü1120111111111û1111ý111111111111111111111111111ô111111111111111÷111111Q11111111111111111113111111111111111111211÷11111111112mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/011.level0000644000175000017500000000066013053577622024350 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 11AUTH Costa PanayiBODY;000ô0>01002020201-,000'200100ý0_0%000%0120010û01!000010002*,,,%b0ò0%0%000*111%0000#0+0ø0*131/00-0_00000/000%0%*00*,00#/0?0%ò1*0ó000ÿ06mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/021.level0000644000175000017500000000066013053577622024351 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 21AUTH Costa PanayiBODY3000000000001:000000003001000ú003010101000ø000000000000101000000000000000300000003001000000003000þ0000000÷0000000030ú00100050010001mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/003.level0000644000175000017500000000066013053577622024351 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 3AUTH Costa PanayiBODY11-000ö01*0010ù11"+00000*000,01130ð000,/%00%`11(.000000000-111'0000(,$0ö0"###!0/%3:'#0_00$100000"#%ü0,.0%00000c00+00##1-,0ü00001*5-,00mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/026.level0000644000175000017500000000066013053577622024356 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 26AUTH Costa PanayiBODY80>00000ø####000Z1V0*2ü131÷2Z000ö"ú1ú1û1ú00(,,,$1ù1ú1ø100.001-ó1ô2þ1õó00000*2ó2ù1ö11,,,$0*ú1ü1ñ2ü000000.1÷2ù1þ2?000ü06mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/044.level0000644000175000017500000000066013053577622024356 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 44AUTH Costa PanayiBODYô111111ò111111ö1112111011121111111111011111111111111511111111111ù12;21ù11111111111,1111111121111111111121111111111111111Q111111ò111111Kmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/007.level0000644000175000017500000000066013053577622024355 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 7AUTH Costa PanayiBODY10ù0#!ô000ô*8õ'#00100/0+0*#+001000,001*001*0,.#0*%0+$00ò0/000þ0001*'#000#000,,1000#010*00ð00"%0*00%/0*0ó,,00%1*0ý00001040õ0-,'100,,,,/mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/041.level0000644000175000017500000000066013053577622024353 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 41AUTH Costa PanayiBODY40ý000þ0%1ÿ*1?1/,00#%00%*0*112/00000_0+00/131%030-0,0000*111%000*0*0ü0b*###%200010000(0111100210*000*01N1001002.000#+111820110÷0>0ú*,,,mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/016.level0000644000175000017500000000066013053577622024355 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 16AUTH Costa PanayiBODY%00*001%=B021%01"00%0?00312%*0(*0*!/,0121%*0*00*00%02%*0.00*,0%ö00:%10%000*0+,'##+%01%00000*40ô0>@00%300ý0*0000*0ý0-,,001*<,C,Amirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/051.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 51AUTH Costa PanayiBODY######!ð(.1û2þ110000000.2ù1ý1÷20"###+0%ö1ñ1ÿ2%0000000%1ö2ÿ1÷+100'#%û0ü1÷1þ1"###!00000ó1ù1ó$ø00030þ1ú2%0^1b000(,,,,1,,,,05ý010:mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/020.level0000644000175000017500000000066013053577622024350 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 20AUTH Costa PanayiBODYõ1ô0ô0ñ0ý1ú0ú2ÿ0ó0ð0ó1ø0ò0ü1ð050ò0ÿ0÷0õ2ð1ü1÷0ð1ô0ö0P0ü0ø0ò0;0ö1ö0I2I1ú0ó1ö2ù0ò2ñ1D0ô1ö0ú1ñ0÷0ÿ0ö0õ0ý0ù0ñ0ù1ø1ù0ñ1ó0ý1ù1ô2ø2û1ö2ÿ0ú1þ0þmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/037.level0000644000175000017500000000066013053577622024360 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 37AUTH Costa PanayiBODY/###0201.0+0û06010000ú0%1*00##ö0+0/000%0*$0ü00+*01020001##00020ý0, 01000ú000,,þ00 00&%(,'?0%>00%100#0.0122-000-0000'#0,.9/00ó000ø0%ô001mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/048.level0000644000175000017500000000066013053577622024362 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 48AUTH Costa PanayiBODY'####%ø01/1þ0*/00100-0"#+/01.710/00+00÷000#+0#//0þ01(,.'0ñ*0ù0#-000"2/!00.00,0//0þ001000000/0100,000-000õ0+###//0ò0'0+-,ð00012*$1(%ó0%:mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/0000755000175000017500000000000013253546300024117 5ustar aeglosaeglosmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/022.tape0000644000175000017500000000107613247050637025307 0ustar aeglosaeglosRND1TAPEVERSHEADZ¬€j¿ìxINFOclassic_deflektorBODYàÿÿÿ‘    ÿÿÿÆ 6" ÿ¬  U  ?ÿÝ  %    ;  ]        3 ÿÉ ÿÿÿ× ÿÿÿÿÿ>mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/035.tape0000644000175000017500000000046613251071511025302 0ustar aeglosaeglosRND1TAPEVERSHEADZ³e¿ó6INFOclassic_deflektor#BODYØ  @#&08 4'9=;"! .V  >D7# %mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/006.tape0000644000175000017500000000202613120025223025264 0ustar aeglosaeglosRND1TAPEVERSHEADYV°¸šîINFOclassic_deflektorBODY¸S ((~eh77@;-$58  0 :   IQ ÿßH9     K     K$    .lmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/023.tape0000644000175000017500000000063613247050741025305 0ustar aeglosaeglosRND1TAPEVERSHEADZ´Ì<¿ìPINFOclassic_deflektorBODY@V=  )   *  A ( Q    #%1% ÿ¥È0@% * (!mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/056.tape0000644000175000017500000000144213253545057025315 0ustar aeglosaeglosRND1TAPEVERSHEADZö¿ú±INFOclassic_deflektor8BODYÄ  F 3 ? 8 :       582ÿ“1"/               ,   &I    2- ,   d    : [ Z v b  5  d +# n   mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/015.tape0000644000175000017500000000052613221512512025273 0ustar aeglosaeglosRND1TAPEVERSHEADZRœy>INFOclassic_deflektorBODYø3!  !(O  $04)G!1 3, , ( +1 U mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/034.tape0000644000175000017500000000155613247053365025316 0ustar aeglosaeglosRND1TAPEVERSHEADZËn¿ìÄINFOclassic_deflektor"BODYo(60 (#/ ÿY0 ‰     0    "   0    2 #*2 `D-@# ÿ^b\RU_[mLR[ Lx'V»DW[Kò/ žQ   0mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/014.tape0000644000175000017500000000172213221512433025273 0ustar aeglosaeglosRND1TAPEVERSHEADZhÓäœyÝINFOclassic_deflektorBODYt5Wÿ&-H= ÿi /+6*   0    # *        /       & 2   '  B« Ý             ÿΧ `     ?  M ÿ·n 2@ I N Jmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/051.tape0000644000175000017500000000101613253536631025303 0ustar aeglosaeglosRND1TAPEVERSHEADZÇ9å¿úlINFOclassic_deflektor3BODY°yN•†H!%   ß    D        ´    º 0. ; # ÿR )  f ×  6 - (       …  A ]mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/036.tape0000644000175000017500000000127213251071652025305 0ustar aeglosaeglosRND1TAPEVERSHEADZµ <¿ó—INFOclassic_deflektor$BODY\C*2 ÿÿÿ6        %     , %+  - 7.2&ŒVF0>)L(Ð ÿ ;#mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/027.tape0000644000175000017500000000107213247051736025311 0ustar aeglosaeglosRND1TAPEVERSHEADZµj ¿ìwINFOclassic_deflektorBODYÜÿß   ¾Oÿs%ÕÿÿÿÿÿIb³™SRX\Z_  ,     Á   ] ÿ y q Q F  \ U ˆ Q S L /mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/050.tape0000644000175000017500000000071613253536374025314 0ustar aeglosaeglosRND1TAPEVERSHEADZ¨¿ú\INFOclassic_deflektor2BODYp#5       0  #    !    0 *$7$\2# Z G-9&§mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/030.tape0000644000175000017500000000113613247052560025300 0ustar aeglosaeglosRND1TAPEVERSHEADZË+˜¿ì€INFOclassic_deflektorBODY8k$# C:&(7"*  *:ÿc  && ?(p     ,@   *U3  #    %mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/029.tape0000644000175000017500000000215213247052457025314 0ustar aeglosaeglosRND1TAPEVERSHEADZÅ ’¿ìINFOclassic_deflektorBODY L/" 7!K "JC  ) Œ  +     %  8  7 *2  "    %     $B ' 2 J € ;/XG+3 %       1 ÿ;-$+ N É'9Æ<+|tƒ0e%mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/037.tape0000644000175000017500000000440213251072234025301 0ustar aeglosaeglosRND1TAPEVERSHEADZª™Å¿ó)INFOclassic_deflektor%BODY¤ /      '       _  ÿ         +   0  :            >                 €             73 / !!) %A &ÿú(   !š½"=              :% N 1`,u  3  "ÿm   %Û       §  ÿ© "x+a5ÿ 4        =  L  ! w  %    ' )]@%mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/044.tape0000644000175000017500000000141213251073623025300 0ustar aeglosaeglosRND1TAPEVERSHEADZ·…”¿ó«INFOclassic_deflektor,BODY¬Q"5&(4!T9-D(ý/Q.R9* ß 2 L iÑÿ‰UPY_† %)  ­Q;  0: 5     @ "º-Bmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/011.tape0000644000175000017500000000065613221511412025271 0ustar aeglosaeglosRND1TAPEVERSHEADZWKœyTINFOclassic_deflektor BODYP' – "-  _! +8 )%:!° / & R:&mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/003.tape0000644000175000017500000000102213217006056025266 0ustar aeglosaeglosRND1TAPEVERSHEADZFÖnœqmINFOclassic_deflektorBODY´K  "      =  +        4,A  ’      8-ÿ –"ÿ£H>9mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/058.tape0000644000175000017500000000132213253546067025316 0ustar aeglosaeglosRND1TAPEVERSHEADZõU¿úINFOclassic_deflektor:BODYtÿƒIYUÿ1Èÿ•, :Îÿºh?Xd%¢#k3QZZw¾@Bt,A <Û; BCò – "! ( b 1  }   C C * z 8 I O  X   P Lmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/001.tape0000644000175000017500000000101213120024436025256 0ustar aeglosaeglosRND1TAPEVERSHEADYRê'škINFOclassic_deflektorBODY¬]8/+\©  —   &\'   /ÿ mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/017.tape0000644000175000017500000000370613221513205025300 0ustar aeglosaeglosRND1TAPEVERSHEADZ_&¦œyÚINFOclassic_deflektorBODYhK*,€4 9$ \       ( B       <#4  %  ! #  ' (j   >  (     A    ]7        3 8        0    -    -  U#!  B     #, 8"!  B% '  #  o " . A    '$ S3$ÿ1 ,zü '+J!, ) 2 4   mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/039.tape0000644000175000017500000000216613251072721025311 0ustar aeglosaeglosRND1TAPEVERSHEADZºU›¿óINFOclassic_deflektor'BODY8GE5'7#)'/$/*+" .    & 0 -     & I     ' ÿZ 5g   A7   '   8     (  "        !\ O§3        T D* {`8b      " ( mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/059.tape0000644000175000017500000000105213253546171025313 0ustar aeglosaeglosRND1TAPEVERSHEADZþ÷å¿úsINFOclassic_deflektor;BODYÌ6 4!%9 %-! * . !        7   %  $  "     ( % !C' /4   ¨ ( mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/008.tape0000644000175000017500000000152213217006336025301 0ustar aeglosaeglosRND1TAPEVERSHEADZMð÷œq½INFOclassic_deflektorBODYô(  5%K   8 ª       *    5%"$(   mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/025.tape0000644000175000017500000000071213247051153025300 0ustar aeglosaeglosRND1TAPEVERSHEADZ«Rò¿ì[INFOclassic_deflektorBODYlF$7)" 5< ;2+V(‹ —!~ "4 /   $ GÁ     &&  mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/002.tape0000644000175000017500000000327613217005662025304 0ustar aeglosaeglosRND1TAPEVERSHEADZGmãœq˜INFOclassic_deflektorBODY`&"4   6%                          "    (   $Œ5D9&    7 G< S)   *-´ ÿ                    *mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/060.tape0000644000175000017500000000021213253546300025272 0ustar aeglosaeglosRND1TAPEVERSHEAD[$š¿ú INFOclassic_deflektor     D    &J +,              "mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/043.tape0000644000175000017500000000130613251073445025303 0ustar aeglosaeglosRND1TAPEVERSHEADZÍ>§¿óšINFOclassic_deflektor+BODYh*   £         h     p   VPÿ« D  F o—    ÿ:'    ÿ    B"7)  : -20    )    }Jœ    ÿ   mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/052.tape0000644000175000017500000000036213253536702025306 0ustar aeglosaeglosRND1TAPEVERSHEADZÀš_¿ú%INFOclassic_deflektor4BODY”xM¾076 )   B 'Ù  d  mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/038.tape0000644000175000017500000000104213251072542025301 0ustar aeglosaeglosRND1TAPEVERSHEADZÀÚ2¿óqINFOclassic_deflektor&BODYÄ)'   ÿ/(ÿ<ÙÿGP <J)2& /ÿÿ ÿ ù-f ;*fmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/055.tape0000644000175000017500000000070213253537376025317 0ustar aeglosaeglosRND1TAPEVERSHEADZ¾¿úYINFOclassic_deflektor7BODYd  # )   (     *   $     7 8<+;E : - 3R    ™mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/049.tape0000644000175000017500000000131213251074567025314 0ustar aeglosaeglosRND1TAPEVERSHEADZÄÚP¿ó›INFOclassic_deflektor1BODYl6 "!6C+=!Kæ";& y  `"  ÿG@                        # § (  7mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/005.tape0000644000175000017500000000067613120024756025306 0ustar aeglosaeglosRND1TAPEVERSHEADY[ýÚšXINFOclassic_deflektorBODY`X  .58 50   _ O     >;- . 7  +(  c I         mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/047.tape0000644000175000017500000000163613251074336025315 0ustar aeglosaeglosRND1TAPEVERSHEADZ‹8¿óÐINFOclassic_deflektor/BODY@  )2  '      3          ) # E &             "   C  W  7,"          #        @û *)$(mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/045.tape0000644000175000017500000000051613251073737025313 0ustar aeglosaeglosRND1TAPEVERSHEADZÃ׿ó<INFOclassic_deflektor-BODYð/9 c L    . "  ) 1=$ =7)-I)/T(#%mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/031.tape0000644000175000017500000000205213247052752025302 0ustar aeglosaeglosRND1TAPEVERSHEADZÅÉx¿ìóINFOclassic_deflektorBODYÌ:,  !  L.+63j1]"0Š4ÿ0  37 "ÿx!Œ      Ì  5 ~% a/s= :9?%Š, e@     mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/040.tape0000644000175000017500000000063213251073007025273 0ustar aeglosaeglosRND1TAPEVERSHEADZÆèý¿óOINFOclassic_deflektor(BODY<*&H S +:n 7G A0+85)&2  +/r< mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/009.tape0000644000175000017500000000065613217006446025313 0ustar aeglosaeglosRND1TAPEVERSHEADZXeÍœqTINFOclassic_deflektor BODYPÿÿKÿŸ0< ÿ4e Œ  w‡¥  mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/024.tape0000644000175000017500000000110213247051055025272 0ustar aeglosaeglosRND1TAPEVERSHEADZ¬9¿ìyINFOclassic_deflektorBODYä6')&6H£ ;*ÿp  & È' §      />    ±! ‰Lmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/012.tape0000644000175000017500000000307213221512053025267 0ustar aeglosaeglosRND1TAPEVERSHEADZSXœywINFOclassic_deflektor BODYÜ<±0"$ (=; ;C* 5  3     $  68   G     . $ 1 2           £K,(™3d)  $ $#   !ÿ  ' ¸6   1                 8™  ‰ÿÿÿÿÿÿÿÿÿÿÿ      2     %           %  *            ¢ omirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/046.tape0000644000175000017500000000067213251074041025304 0ustar aeglosaeglosRND1TAPEVERSHEADZÉœ½¿óWINFOclassic_deflektor.BODY\0~ & ' $ @   -ÿÿ•ÅO>@)*t#z zmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/020.tape0000644000175000017500000000072613221513472025277 0ustar aeglosaeglosRND1TAPEVERSHEADZo列y^INFOclassic_deflektorBODYx=$ !#3*:2)Z  #*d% "0M  & + 3  * '     x&$  3mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/013.tape0000644000175000017500000000100213221512233025257 0ustar aeglosaeglosRND1TAPEVERSHEADZc½ŸœyiINFOclassic_deflektor BODY¤,!*4           i =   +"R 4.5    '. ™ Ÿ}@<mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/004.tape0000644000175000017500000000211613120024664025272 0ustar aeglosaeglosRND1TAPEVERSHEADYO1÷šüINFOclassic_deflektorBODYð$ % /  E  b- ÿÿ!40 4 -7 ! )      &  ,  =    !      ›                !   H              Cÿ    ,6 p                8  V    T              &  X    ÞV     }  è S…            Ì8\            6  = %mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/010.tape0000644000175000017500000000061613217006533025274 0ustar aeglosaeglosRND1TAPEVERSHEADZR[œqLINFOclassic_deflektor BODY08L5K 13 , "   " ! ;!"2ìU' 8 !  8%mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/057.tape0000644000175000017500000000367613253545633025331 0ustar aeglosaeglosRND1TAPEVERSHEADZùÜs¿úØINFOclassic_deflektor9BODY` 1'    "     '"ÿƒ!% 7    ÿÓ"v* …-4?/ ! *ÿw8"  #     %[&  +ÿÿ(  "*ÿ  ð           i'! 'ÿ¥ P ÿ   P ²   Î4¤ /   8! !ÿÿÿë +  #ÿ{ ;$ ,H8!ª% †mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/048.tape0000644000175000017500000000131213251074452025304 0ustar aeglosaeglosRND1TAPEVERSHEADZÁÕg¿ó›INFOclassic_deflektor0BODYl Y a  @ $+5:      [ 8 B  %ÿ$#”[* M:("°                 +&  ; mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/016.tape0000644000175000017500000000142213221512637025300 0ustar aeglosaeglosRND1TAPEVERSHEADZX¨eœy­INFOclassic_deflektorBODY´t     6 % Š  R  ¡ g     .                      6  &    W 5   e  º  ˆ $ ¯    (   E2M…          mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/019.tape0000644000175000017500000000137613221513377025315 0ustar aeglosaeglosRND1TAPEVERSHEADZp¾-œy¨INFOclassic_deflektorBODY  +    )  3 ;   ++@+ :Y 9 2  $3   T o,ÿ2mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/021.tape0000644000175000017500000000054613247050411025275 0ustar aeglosaeglosRND1TAPEVERSHEADZ£ÑJ¿ìBINFOclassic_deflektorBODYÿÿÿ9 m ÿÿö “ ä  % @ o  ÿ * Ž ÿX ÿ$ ÿ^ Ž ÿÿÿÉÿÿÿÿÿÿÿÿÿ´mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/028.tape0000644000175000017500000000140613247052254025307 0ustar aeglosaeglosRND1TAPEVERSHEADZ½¡E¿ìªINFOclassic_deflektorBODY¨(0# $R'7      6*%/ÿT ]1"?  † C # '"   # *@& Dÿ   ƒ¼Bk!mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/053.tape0000644000175000017500000000153213253537151025306 0ustar aeglosaeglosRND1TAPEVERSHEADZÇI¿ú¿INFOclassic_deflektor5BODYü( 1?BG       Ó   @   %          6   I žq $O‚• Ašn.tÿ§ i<>X“ÿÿö   !  š0    ,mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/018.tape0000644000175000017500000000124613221513274025304 0ustar aeglosaeglosRND1TAPEVERSHEADZl}Üœy’INFOclassic_deflektorBODYH !!* &   n )( e$(*   !- & |    =$mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/026.tape0000644000175000017500000000116613247051323025304 0ustar aeglosaeglosRND1TAPEVERSHEADZ«¸Ù¿ì†INFOclassic_deflektorBODY<       A        &ÿ>%f9e¹2-VÿM?Cu (Nÿ   ,ÿ¬ 5 2 <     F+ .     '" f %mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/032.tape0000644000175000017500000000101213247053040025265 0ustar aeglosaeglosRND1TAPEVERSHEADZÄÌ¿ìkINFOclassic_deflektor BODY¬k" (             z    ?& 7$&! U  ":< mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/054.tape0000644000175000017500000000111213253537314025302 0ustar aeglosaeglosRND1TAPEVERSHEADZÆJ ¿ú{INFOclassic_deflektor6BODYì!! W 1(g  ""ÿL& 0 ™s. "CWYÿa½ Mp$ h4AÿY  5F$6WQmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/033.tape0000644000175000017500000000142213247053171025300 0ustar aeglosaeglosRND1TAPEVERSHEADZºîï¿ì­INFOclassic_deflektor!BODY´F B    1,9ÿÿI¸   , 3 > !       * 4       ÿ                   *         +?    ! ,         ÿ A      $6mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/tapes/042.tape0000644000175000017500000000312613251073304025276 0ustar aeglosaeglosRND1TAPEVERSHEADZ¶ÚA¿ó~INFOclassic_deflektor*BODYøR =    % )(      -     S')                   *       1     +                 v '&@"            * [4VŒ%          1    > 5             ,  D  ,*' - „ / ',mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/018.level0000644000175000017500000000066013053577622024357 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 18AUTH Costa PanayiBODY400õ*!1"/%8*10ñ#+-0.0ñ0/10"/-0þ000+000#0010/0000ý0100ó0//0+00'00(/0$000+-010%ñ0.'#!10ð0/001-,000ó00-00/0ñ.'10/-,$0+00100/%ý01010ó*,,,,.mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/019.level0000644000175000017500000000066013053577622024360 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 19AUTH Costa PanayiBODY111121*/400þ112ø11112*121111111ÿ11%:/1111111111111111111111ÿ11111111211111111J111111111111111121111111111111111ý1111211121111111111111ûmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/027.level0000644000175000017500000000066013053577622024357 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 27AUTH Costa PanayiBODY÷0ôö0ú00000;00000000000000000000000000000000HPJLDRDDJKRQPHF00000020200000000000000000000000000000000011111151111110mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/024.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 24AUTH Costa PanayiBODY21111117111þ112111111101111111õ111111õ1111111111M1111111111111191þ1111111111111111ð111111111111ý1111111111111F1211111R11111112mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/059.level0000644000175000017500000000066013053577622024364 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 59AUTH Costa PanayiBODY1111111òûðöüý÷ùþóñ1þýóûùÿñ÷ýùý0þõòö2þ2ùôûð0ó0üþ2Jô1ðF2öú0ö0ðö÷õ2ñ2õþüø25ûðòøñôÿùòÿø91ÿ÷ÿüþõùóþòõ1111111mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/054.level0000644000175000017500000000066013053577622024357 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 54AUTH Costa PanayiBODY721111ÿ11111112011111111121111ÿ1111111111111ó1111111111111111111111111111111111ø111G11ð11111111'#+111111112111%9*111111111ô11-,.1211221mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/013.level0000644000175000017500000000066013053577622024352 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 13AUTH Costa PanayiBODY010,/0%01,'01/7S01%00%õ0%0.,/0000%÷0%00%ø(00ý000%00!*0,0*0/,0%00,00*,*000*#0%00%]00%*0"00õ0/*#!000%*03*+0/#0þ01/%*011*09/0100*1ò*011*1mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/057.level0000644000175000017500000000066013053577622024362 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 57AUTH Costa PanayiBODYõÿõ0<00###00ô06ñöô01*0þ÷û02,,,00002"%þúû0010@##+010-,,,.,,,,úù*1ò002:/00102õó*,,,,'#+1000000120000>*020úû=00A00ðó0'100÷ò1*10ó0ôð0%?10óþmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/055.level0000644000175000017500000000066013053577622024360 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 55AUTH Costa PanayiBODYû1R1P1ð2ø0þ1õ1ð2ð2ù0ó1÷1ü2ø2ÿ1ú1G0D0ü0ñ1þ0ú0ô2ú0þ0ð1ò0ó0ú0ø082I0L0ô2ú0÷0ñ062û0û0ö1ö0ÿ0ý0ý0ô1Q0O0þ0ö1÷0ð0ô2ù2ø0ô1ø1ü2ý2û1ý1R1E1ð0÷0ó1ÿ1ýmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/039.level0000644000175000017500000000066013053577622024362 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 39AUTH Costa PanayiBODY21131111ø1þ11121111121111111111^111111111ÿ111111111111111111þ11111131111111111111111111111111111111ý1111ý2111ú11111a1110921111111111115mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/022.level0000644000175000017500000000066013053577622024352 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 22AUTH Costa PanayiBODY10ö0100010÷0101002001000000000002000002 40300S00302 2000002000000000001002001010ù0109010ý01mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/040.level0000644000175000017500000000066013053577622024352 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 40AUTH Costa PanayiBODY82ø0ÿ0ÿ2ó1þ0ù072ù0ò1ø1ò0÷0õ1ó0ý1û0ö0ú0ö0ò0ý0ñ1ø0\1ÿ0\1þ0b0û0ð0÷1ù0ü0ô0õ1ø0ú1ø0^0ñ1\0ô0_0ø2ý1ú0ð2ó0ü1ý0ý1ÿ2ü0ñ1ú0ý1ø0ó2õ2ñ1û2ô1ô0þ2ý1÷1÷mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/levelinfo.conf0000644000175000017500000000054113252263553025642 0ustar aeglosaeglosname: Deflektor author: Costa Panayi imported_from: Original Deflektor levels: 60 first_level: 1 graphics_set: gfx_mirrormagic sounds_set: snd_mirrormagic music_set: mus_mirrormagic mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/033.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 33AUTH Costa PanayiBODY;####+200000õ0/1Z12*0ö000000*30022*00,,%000*01[2U*100100'3#30000"#!0010%1101W1W01*0/00!11300200V*0/000221130V00*0000##/110000õ"0ú*0ò06mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/034.level0000644000175000017500000000066013053577622024355 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 34AUTH Costa PanayiBODY21ø11111111112:111111111111112111111111E111111111ð1111111111111111111111111111111111111õ121û1111711111111111111011111111211111ò11111112mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/005.level0000644000175000017500000000066013053577622024353 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 5AUTH Costa PanayiBODYö1ô0÷0ô0÷1õ1ù0;1ø0ù0ÿ1ò0û0ù0ú2õ0ö0ô1ø0ù2ð0û1ÿ0ü1ñ0ò0ú0ÿ1þ1ñ0ð0õ1þ0ô0þ0û0ú0ñ0÷0ý0ñ1ú0õ1ð0õ0ô0ü0ù0ü0ý0ý0û1ÿ0õ1ò0ù0ÿ1õ0ÿ0ð150ô0ó1ÿ2ø0÷1û0ümirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/046.level0000644000175000017500000000066013053577622024360 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 46AUTH Costa PanayiBODY400ú0%ý02##+0û000000%00311*00A0<0@0%00011*10*-,.##%=*011*0108301%0*%11'0//0+//%11%00*112000*///!0%*23130ó00000012*112000ò12ø002*mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/043.level0000644000175000017500000000066013053577622024355 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 43AUTH Costa PanayiBODY210ó1%?1312/712201-,.0-,/0ö000003000ø000ó12201/0*000/,A10þ1/$*002%0ý1%*002%@2110>212%*$3*%0110#####!0%11+0030,/,0ð0%12*9mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/058.level0000644000175000017500000000066013053577622024363 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 58AUTH Costa PanayiBODY1111111711111111111111011111111111111011111111R1H1L202R1I1I1MOGHIRQDKIKSQGOM0Q0D00000D0I0M000000000000000090000óùòúmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/045.level0000644000175000017500000000066013053577622024357 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 45AUTH Costa PanayiBODYý2M1ô0ú2J0ñ1ö072ó0ö0ù1ó0ò0÷1ð0ö1ù1ÿ0ø0õ1Q0ð0ö2ñ0ñ1ø0ø2ð0ÿ0ö0ñ0ð0J0ð2:2û1ò0L1ó1÷0ù0þ2û0ÿ0ð1ù1ú0ò2ö0ó0P0þ2õ2û2÷0ü0û1ù0ø1ù2ý1D0ø1ø1M0ý1Q1ùmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/025.level0000644000175000017500000000066013053577622024355 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 25AUTH Costa PanayiBODYú1õ1û0õ0ð2þ0ý1ö0û2ò0ð1ð0÷0ý0ô2ÿ2ü0ñ1ð0ô2ù1ü1ó0ñ0ò0ñ0þ0÷1ý0ö140ó1ý0ÿ2÷0ò0ñ2:0ÿ0ù0ó1ý0þ0ñ0ð0ö0ý0ø0ñ0ð1ñ0þ1û0þ2ô1ý0ø1ô0ó2ð0÷1ø0ñ1ý2ñ0ð1þ1ómirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/helptext.conf0000664000175000017500000000263013255703254025517 0ustar aeglosaeglos# ============================================================================= # Mirror Magic / Deflektor element descriptions # ============================================================================= df_laser: Laser beam emitter: From here the laser is shot. df_receiver: Laser beam receptor: This is where the laser beam needs to get to. df_mirror_1: Rotatable mirror: Reflects the beam depending on its angle and can be turned. df_mirror_rotating_1: Auto-rotating mirror: Can be accelerated or temporarily stopped. df_refractor: Prism: Deflects the beam randomly. df_cell: Cells (balloons): Must all be destroyed with the laser beam to solve the level. df_mine: Mine: Explodes if hit with the laser beam for too long, and the game is over. df_steel_grid_fixed_1: Fixed, reflecting polarizer: Lets the beam through only in certain angles. df_wooden_grid_fixed_1: Fixed, absorbing polarizer: Lets the beam through only in certain angles. df_steel_grid_rotating_1: Auto-rotating, reflecting polarizer: Lets the beam through only in certain angles. df_wooden_grid_rotating_1: Auto-rotating, absorbing polarizer: Lets the beam through only in certain angles. df_fibre_optic_red_1: Glass fibre optic: Diverts the beam (you can only see the two ends). df_steel_wall: Reflecting wall: They reflect the laser beam like a mirror. df_wooden_wall: Absorbing wall: They do not reflect, but absorb the laser beam. mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/006.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 6AUTH Costa PanayiBODY40ð0%ù0$ô000003/,,0000%00^0\1020000/0%\002003%1(00/0%10`0`10%0*0100-,$00003%1/001001%_1\10%000*##00%10003%000000ÿ0%^1c1/0÷000002-,,,,9mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/049.level0000644000175000017500000000066013053577622024363 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 49AUTH Costa PanayiBODY÷111111111111121111111111111111111111ð111M111111P11111111111111111121111111ÿ111111111111ö1111112211111111111122111û112111ü0682111ø2mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/050.level0000644000175000017500000000066013053577622024353 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 50AUTH Costa PanayiBODY÷1ó0ú0ð0û1ñ0ô2ò0ÿ2ò1ô1þ0ð0L1ô0ñ1Y0ö0ø0÷2O1K1÷0ÿ1ñ0õ0L0ü0I0ò0;0õ1ù0E2E1ô0ò152ù0Q2ò1P0ø1ø0û1ñ0H0J0û0÷0þ0T0ñ0ú1D1÷0ý1ý0ø0ý1ô2ö2þ1÷2ð0ú1ø2ñmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/056.level0000644000175000017500000000066013053577622024361 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 56AUTH Costa PanayiBODY21111111ð1ÿ11121111111111111111111111111111þ111ý11111111111111111111111111111111111111211211111D11111111111111111121111181111111111ü06mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/004.level0000644000175000017500000000066013053577622024352 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 4AUTH Costa PanayiBODY21111111ø1ý11121111111111111111111111111111ø111ñ11111111111111111111111111111111111111211211111S11111111111111111121111181111111111û06mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/009.level0000644000175000017500000000066013053577622024357 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 9AUTH Costa PanayiBODY2113111711131121111211011211111111111ù1111111111111111111111111M1111111G1111111111111111111111111õ111111111112111121111211311191113112mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/017.level0000644000175000017500000000066013053577622024356 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 17AUTH Costa PanayiBODY8 0^00000000ñ0001000210`02   0÷00000ü00 000000`0ù00100000ÿ0 00100020_000 0ü0100010000 000000ý1 1002000_000000 05001002 1þ0 mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/038.level0000644000175000017500000000066013053577622024361 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 38AUTH Costa PanayiBODY/######%;A0ú03112212%?0000+111121+,000*221212130þ1$00.1122211'001%ø031112121-001%00#%11121130ü20@00#-21111'00>*,,,,,%5mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/015.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 15AUTH Costa PanayiBODYü1I0ö0ÿ0ù1õ0L1ÿ0ö0ù1ú1÷0ÿ0õ0ý0ô0ÿ0ù0ú0ý2ý1ø1ù1ÿ0ü0þ2ô1ü0÷0ö1ò0ó1ý090þ0R0þ0ö0ñ0û0ÿ1ö0ø0õ1ñ0ö0ð0þ0õ0ø1ý0þ0ð0û1ù1ô0õ1ö0÷1ó150ú0N1ú2÷0ò1ü2þmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/047.level0000644000175000017500000000066013053577622024361 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 47AUTH Costa PanayiBODY 2ö00012000;2000000\00200140ü000000_00ø0000000ù0 000^02000100 0ö0100010 00_010000 0_0000000ø0   210_0ö020001002ÿ0000100000ò1mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/helpanim.conf0000664000175000017500000000476113255703074025466 0ustar aeglosaeglos# ============================================================================= # Mirror Magic / Deflektor element animations # ============================================================================= df_laser.right: 50 df_laser.up: 50 df_laser.left: 50 df_laser.down: 50 end df_receiver.right: 50 df_receiver.up: 50 df_receiver.left: 50 df_receiver.down: 50 end df_mirror_1: 12 df_mirror_2: 6 df_mirror_3: 6 df_mirror_4: 6 df_mirror_5: 6 df_mirror_6: 6 df_mirror_7: 6 df_mirror_8: 6 df_mirror_9: 6 df_mirror_10: 6 df_mirror_11: 6 df_mirror_12: 6 df_mirror_13: 6 df_mirror_14: 6 df_mirror_15: 6 df_mirror_16: 6 df_mirror_1: 12 df_mirror_16: 6 df_mirror_15: 6 df_mirror_14: 6 df_mirror_13: 6 df_mirror_12: 6 df_mirror_11: 6 df_mirror_10: 6 df_mirror_9: 6 df_mirror_8: 6 df_mirror_7: 6 df_mirror_6: 6 df_mirror_5: 6 df_mirror_4: 6 df_mirror_3: 6 df_mirror_2: 6 end df_mirror_rotating_1: 6 df_mirror_rotating_16: 6 df_mirror_rotating_15: 6 df_mirror_rotating_14: 6 df_mirror_rotating_13: 6 df_mirror_rotating_12: 6 df_mirror_rotating_11: 6 df_mirror_rotating_10: 6 df_mirror_rotating_9: 6 df_mirror_rotating_8: 6 df_mirror_rotating_7: 6 df_mirror_rotating_6: 6 df_mirror_rotating_5: 6 df_mirror_rotating_4: 6 df_mirror_rotating_3: 6 df_mirror_rotating_2: 6 end df_cell: 100 df_cell.exploding: 12 empty_space: 10 end df_refractor: -1 end df_mine: -1 end df_steel_grid_fixed_1: 50 df_steel_grid_fixed_2: 50 df_steel_grid_fixed_3: 50 df_steel_grid_fixed_4: 50 df_steel_grid_fixed_5: 50 df_steel_grid_fixed_6: 50 df_steel_grid_fixed_7: 50 df_steel_grid_fixed_8: 50 end df_wooden_grid_fixed_1: 50 df_wooden_grid_fixed_2: 50 df_wooden_grid_fixed_3: 50 df_wooden_grid_fixed_4: 50 df_wooden_grid_fixed_5: 50 df_wooden_grid_fixed_6: 50 df_wooden_grid_fixed_7: 50 df_wooden_grid_fixed_8: 50 end df_steel_grid_rotating_1: 6 df_steel_grid_rotating_2: 6 df_steel_grid_rotating_3: 6 df_steel_grid_rotating_4: 6 df_steel_grid_rotating_5: 6 df_steel_grid_rotating_6: 6 df_steel_grid_rotating_7: 6 df_steel_grid_rotating_8: 6 end df_wooden_grid_rotating_1: 6 df_wooden_grid_rotating_2: 6 df_wooden_grid_rotating_3: 6 df_wooden_grid_rotating_4: 6 df_wooden_grid_rotating_5: 6 df_wooden_grid_rotating_6: 6 df_wooden_grid_rotating_7: 6 df_wooden_grid_rotating_8: 6 end df_fibre_optic_red_1: 50 df_fibre_optic_yellow_1: 50 df_fibre_optic_green_1: 50 df_fibre_optic_blue_1: 50 end df_steel_wall: -1 end df_wooden_wall: -1 end mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/023.level0000644000175000017500000000066013053577622024353 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 23AUTH Costa PanayiBODY/#####%##/0^1c0000?0%*00010130300ü%ú*000_1`1000*#%0*0ò00013130*9/5/000c0\1000"###!0000013130ÿ*,'00/0\0_1010000%ó0/0000313100>000/,,,.mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/042.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 42AUTH Costa PanayiBODY10ø100200ù02000ÿ00>00000ÿ800ü000000ø011,0(/%000000102/##000100ýò000?00%0000020000ö000%õ0ò000ú1200010,,,,100100ñ2,0,010205mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/060.level0000644000175000017500000000066013053577622024354 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 60AUTH Costa PanayiBODY1111111111111111313131;131313111111112111111113131313131313111111111111111113131313131313111111100011111113131353131311111111111mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/002.level0000644000175000017500000000066013053577622024350 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 2AUTH Costa PanayiBODYû1201"0001(020;0("1!")0ý000$1,!0"!20$$0$!2(000ú(0!,02001!1)02$10$0ù0!0)002000$0"00&010(""*7100ü0$0"0ý0"000!&20(1&00$"2$þý0(0"0(0ô00)(01mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/028.level0000644000175000017500000000066013053577622024360 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 28AUTH Costa PanayiBODYýõ00=*0ûð000ÿ*1ýð000*0øð00A(&1,,001*000?000111"000'#+,.#####8200ò%@00%>1111#####óõ00%10000210*0òñ00%20000*###00000%100ýò40ö000000%<00ôømirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/031.level0000644000175000017500000000066013053577622024352 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 31AUTH Costa PanayiBODY0##+7û00000ü*21//,0000000*10000ý?A000ñ*1###%0900000*1211>2010000`1113@,000Y0X00021111*00000101012111*00û0X0T0021212*0ù000000÷mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/001.level0000644000175000017500000000066013053577622024347 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 1AUTH Costa PanayiBODYú00011*ò0Z11*-011111*000100*01O13##000000011100000@000ÿ000]010000000÷00000000000ú00000000000200þ006*0000+1210A00%8*000ó*10,,$mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/032.level0000644000175000017500000000066013053577622024353 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 32AUTH Costa PanayiBODY100)0!ð0!0$040ö0"2$"00$1!02&(00ü00"0$0"0)0010%$$!100&0!00"000200)0(000õ01"2$&1(10020!(0!ù010(2("0"000($0"2õ"000ø0)"(1$!÷ÿ0"1!102:010210mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/035.level0000644000175000017500000000066013053577622024356 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 35AUTH Costa PanayiBODYö2ù1ö0ù2þ0ó0õ061?0ð0ü1÷0û0ú1ö0ñ1÷0ü0ý0ø0A0ò0þ2û0ú1ð2ù1û0ð0÷1û2ý0ö0ó0ù0ñ1ù0ò0ö1ø0ò0ü2þ0û0ú2÷1þ0@2þ1ú0ñ0õ1ô2ò0÷0û0ñ1ü0ÿ0>290û1ù1ñ0ñ2õ1ü1ûmirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/036.level0000644000175000017500000000066013053577622024357 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 36AUTH Costa PanayiBODY;1%û00111ú1%00ö400ü?0000000000000û000  00100÷00000000 000,0,20@>000A001110100000,,,21P10ô00%11#111011[0÷%1132mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/012.level0000644000175000017500000000066013053577622024351 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 12AUTH Costa PanayiBODYý020100200ú00100/01###0û1000214000õ0ô0000û0000200000$00?000ð÷0010%002001000000%0000010õ000/00÷00%:þ00000>0ñ010020ò002001ø001mirrormagic-3.0.0/levels/Classic_Games/classic_deflektor/030.level0000644000175000017500000000066013053577622024351 0ustar aeglosaeglosMMIICAVEVERSHEADP dDeflektor Level 30AUTH Costa PanayiBODYû1ó2õ2ý2ô1ù2þ2ø2ü0ò1ò1õ0ò0û1ø2ý1÷0ÿ0÷0ü1õ1ù1ò1û1ù0ø0÷1ù0û0þ2ÿ0÷0ÿ06082ö0ð0÷2ñ1þ0û1ú0ù1ÿ0ý2÷0÷0ý0ÿ0ô0ù0ù1þ2þ1ó1ö0ò1ú0õ1ù1þ1ó2ÿ2ò2û2õ1÷2ömirrormagic-3.0.0/levels/Classic_Games/levelinfo.conf0000644000175000017500000000032513251222041022144 0ustar aeglosaeglosname: Classic Original Games author: Several Authors imported_from: Several Games sort_priority: 100 level_group: true mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/0000755000175000017500000000000013262510460023131 5ustar aeglosaeglosmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/052.level0000644000175000017500000000050107204325211024461 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 52BODYÀ–mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/072.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 72BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/029.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 29BODYÀ‘‘‘‘‘‘‘‘‘‘“rr‘‘““‘‘rr“‘‘‘‘‘‘‘‘‘‘mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/066.level0000644000175000017500000000050107204325211024466 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 66BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/088.level0000644000175000017500000000050107204325211024472 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 88BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/053.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 53BODYÀ733333333333333;5(,(:5,.O,,,:5OOO‡w‡:5####"####:5”`:5:5aa:5:5:5:=<<<<<<<<<<<<<<>mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/008.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 8BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/084.level0000644000175000017500000000050107204325211024466 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 84BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/010.level0000644000175000017500000000050107204325211024453 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 10BODYÀŒ‡‡‡‡‡‡‡‹‡‡‡‡‡•'##/##+š333™˜%a/‘‘*5:‘˜%r“/‘“‘*5:˜%‘/‘‘‘*5:‘•-,,,/,,,.™<<<šxŒxŽvŽŽvv‡ŒvvŒŽvŽ””””””Œmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/000.level0000644000175000017500000000050107204325211024452 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 0BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/014.level0000644000175000017500000000050107204325211024457 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 14BODYÀ*X^_____]$^_,_*[_^^W__'[]^].W^.__,^__^_]W_[__[]/\_]__'[-_W._Qs^]_'[VZ[W_/U__^]__]&W_[W[_[W____T^W___"[WZ#_]R_W[VU-_Z_^.__\___WQ]_(____S-/_Wmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/083.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 83BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/091.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 91BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/011.level0000644000175000017500000000050107204325211024454 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 11BODYÀ•••••••••••••Ž‹‹‹‹‹‹‹‹‹‹‹‹‹Ž???????????????˜?‹‹‹‹‹?????????˜‹‹‹ŽŽ‹??‹??‹?Ž???‹‹‹Ž???‹??‹Ž????‹‹?ŽŽ‹Œ˜???????????????˜ŽŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹Œmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/021.level0000644000175000017500000000050107204325211024455 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 21BODYÀŒŽŽ/////SŒŽx/U//”‹,ˆˆˆˆŽx/ŒˆˆˆŒ`?????Žˆˆˆxx—•••//`?????ŽŒxx/////Ž”‡?????˜?///////?—?/???????////////mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/099.level0000644000175000017500000000050107204325211024474 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 50BODYÀ•aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa–––––––––––––––––––––––––––––––––––––mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/003.level0000644000175000017500000000050107204325211024455 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 3BODYÀOOOOOOOOOOOO///////OO///////s__________u//////////////s__________u//////////////s__________u//////////////s__________u//////////////s__________u//////////////mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/026.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 26BODYÀ??????3337333?‡—`——6:???•™66:??•?6‘˜:?•?˜‡64‡‘6:?˜?626??646?˜?56‘‡26‡˜?•?5˜‘6?•??566™•???57——`—‡?<<<><<= ÿ®  (, "j  gg                         Mg                . (            1(   ¢                #          r-4 { j.       mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/036.tape0000644000175000017500000000202713200707020025421 0ustar aeglosaeglosRND1TAPEVERSHEADZ!_ïœîINFOclassic_mindbender$BODY¸ % #&;. / <  J   !  K        ‰  T  %      '    5                                         v           (     ÿ ÒÿàÜ4          _    f  ‚        "      6    & %      Q                     mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/027.tape0000644000175000017500000000310313105154521025423 0ustar aeglosaeglosRND1TAPEVERSHEADY2Xd™«yINFOclassic_mindbenderBODYä<   ÿG é      ÿ r3  1             ³    '          &  ] V      <        A                                              "       ë        6  1 b                       ÿ à  E     W / ¾   ' '      J          <‰4) '                    mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/050.tape0000644000175000017500000000241313217005050025416 0ustar aeglosaeglosRND1TAPEVERSHEADZvõœq+INFOclassic_mindbender2BODY¬R (A$  (/  3)ÿPÑF›7, ÿ 3               #   “P0 0# )              4ï6         ÿ<)!   „|         8     G  mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/030.tape0000644000175000017500000000152313105303673025425 0ustar aeglosaeglosRND1TAPEVERSHEADY.¶î™¬½INFOclassic_mindbenderBODYô¥      )        1    #            &    ,    0    B  Z                     ^      « %    a5'#+)                      ÿ ¬<  6  /A .;mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/029.tape0000644000175000017500000000441313105303301025422 0ustar aeglosaeglosRND1TAPEVERSHEADY,—•™¬+INFOclassic_mindbenderBODY¬47 "% 1.  ) i%        7    *                      '  !           &    !                        " 0      ! /.&( $&             "       `      *Ôq*  "        {6      A  *                                &                1                *        h                        J# " 2!        Ê q                    g                 vÿ,:0mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/037.tape0000644000175000017500000000270313200707167025437 0ustar aeglosaeglosRND1TAPEVERSHEADZónœYINFOclassic_mindbender%BODYd;                    ' 7%          £    $Ô - å  *                      $          /    Do                                              .         " 7B ÿãmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/044.tape0000644000175000017500000000107313217001027025422 0ustar aeglosaeglosRND1TAPEVERSHEADZP›AœqwINFOclassic_mindbender,BODYÜÿíÿÿ•  +      />mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/011.tape0000644000175000017500000000130313066701677025434 0ustar aeglosaeglosRND1TAPEVERSHEADXûÉx˜õ™INFOclassic_mindbender BODYdNH          ø                                                        c  8*C:6B)'"Y­ 7mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/003.tape0000644000175000017500000000100313104663171025417 0ustar aeglosaeglosRND1TAPEVERSHEADXäô2™ªiINFOclassic_mindbenderBODY¤ÿÿÿÿÃ# %          E      #    )      % ÿKÿÿEmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/001.tape0000644000175000017500000000030713066700100025412 0ustar aeglosaeglosRND1TAPEVERSHEADXãÜ ˜õINFOclassic_mindbenderBODYh+) –±$mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/017.tape0000644000175000017500000000123713104702200025420 0ustar aeglosaeglosRND1TAPEVERSHEADY™…™ªINFOclassic_mindbenderBODY@G  #Yh ' T2C >         6    i      b$- É               mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/039.tape0000644000175000017500000000165313200710052025427 0ustar aeglosaeglosRND1TAPEVERSHEADZ/sœÓINFOclassic_mindbender'BODYL> ! SÿÿX  (   Y!  f    û '    –†  8         1ÿà2            h          ÿ™*1    /      "  Œ  ÿ    0             %   ¥   D   5.        #        8¤        Ž 6mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/008.tape0000644000175000017500000000063713104670744025444 0ustar aeglosaeglosRND1TAPEVERSHEADXõì@™ªPINFOclassic_mindbenderBODY@,  > *     1      *                       6      '                    mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/025.tape0000644000175000017500000000176313105153746025443 0ustar aeglosaeglosRND1TAPEVERSHEADY# ™«åINFOclassic_mindbenderBODY”ÿs+C7P3  P f3"!  ^ÿ8 ²              ÿ ÿ ÿ ¯    X    3            D    $    :    y  *    &    U    V         2    G  B           mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/002.tape0000644000175000017500000000255313103420456025425 0ustar aeglosaeglosRND1TAPEVERSHEADY&]ü™¦CINFOclassic_mindbenderBODY   1 @ )&                      6     0    ! 1    !   8  ! _+ # "      ,             7   "             >      '                        Z    P    .  B           mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/041.tape0000644000175000017500000000335713217000016025423 0ustar aeglosaeglosRND1TAPEVERSHEADZELלq¤INFOclassic_mindbender)BODYœ  $  &                 BD (S                            ÿ(    ÿÿ  *              2U  =         :½! .ÿÿ=5 %)ÿÿ    87/     #                 îPh#0í 0              mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/007.tape0000644000175000017500000000154713104670252025436 0ustar aeglosaeglosRND1TAPEVERSHEADY'¡Q™ªÂINFOclassic_mindbenderBODY      N   / 3          $ ;                 (         =                (                                       !    G                 !    "                        :                             mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/043.tape0000644000175000017500000000364313217000502025423 0ustar aeglosaeglosRND1TAPEVERSHEADZS‚œqÑINFOclassic_mindbender+BODYDÿÿ!      D> %   u P X "     $        ÿ         ( 1  q  A)   "%   /,    ./  $       " ¨@ #3 ÿÿÏ ' ^  6 m '  = !   "      & -" +! ®&#  ÿX E #   ( S  =     C +    +<  ù    P(  Q ;       ÿ/ ? 1  C &   3 -            %   " > & . ÿ (   - '  '  ©5 *   0     9      $  Ö    mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/038.tape0000644000175000017500000000435713200707621025442 0ustar aeglosaeglosRND1TAPEVERSHEADZœ$INFOclassic_mindbender&BODY. +ö              <    8        9  $    1  )    ÿ   *        9                    -                             ,   ÿ 2                        Ÿ    )9    >"      '+   +  ;    '  !  P  U        t                          Z (         | N (   ;!     E  ÿ J  ÿ‘ÿN,        ÿ             Q       N  O ç         ©        ð                 †         n        T$,        !ˆ!      Bÿ#      2      1        H       I ©            ;    ÿ Ü           ,  d  ©“mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/049.tape0000644000175000017500000000234313217002700025427 0ustar aeglosaeglosRND1TAPEVERSHEADZjüsœq!INFOclassic_mindbender1BODY„ÿÎ9ÿÌÕ aC! ("  "   K   U  & $&  & @   %      #           ÿΧÿ?   ¥  ´& i C         Œ  !       Õ        )  $  * ( $* -   ‚ÿ           0  $  - .mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/005.tape0000644000175000017500000000362713066700737025446 0ustar aeglosaeglosRND1TAPEVERSHEADXõÎINFOclassic_mindbenderBODY8u  4              0>-*M" &        #                           ?<  1*s     U6Q        x        x(   ˜   7Pó              `                º á  S' ÿU¤  1              "    ÿ C    v ) X    &    #R1                  >2 $        #mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/047.tape0000644000175000017500000000502713217002260025430 0ustar aeglosaeglosRND1TAPEVERSHEADZXuœqnINFOclassic_mindbender/BODY ¸¼((/> ,œ "9 À  &  1 & 2 /  F s(q   D k \!8 ÿ  !jMK nz Ö     !   b  §¾] Ls(<$#Ì3-&22$¸yN    |ÿBÿ          hž% B     ? 3 < ]% && Â! H+# O)   ÿ'1 $#G =    ÿ            qJ                                =ÿåF*$5‹U/€ '    ­…/ L)  4# 3 ', T    °    mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/045.tape0000644000175000017500000000140713217001166025430 0ustar aeglosaeglosRND1TAPEVERSHEADZWÉãœqªINFOclassic_mindbender-BODY¨€   ÿÿ‡                                       ï                (    l ,  Ö ® U°õmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/031.tape0000644000175000017500000000301313110110035025402 0ustar aeglosaeglosRND1TAPEVERSHEADY*yP™´kINFOclassic_mindbenderBODY¬   d!«`« á  '  ÿ         Ž  c    ÿ & ;  p@( !€  ÿ bþd"          œg  K ÿl&              °& R                    %                N                           q"~          P               mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/040.tape0000644000175000017500000000177713216774615025454 0ustar aeglosaeglosRND1TAPEVERSHEADZb¡œqèINFOclassic_mindbender(BODY  "  !      6- À $-     +'6      ÿ    / –     v     õ1) ! Ç Z       ` T              ) x %    - <;     mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/009.tape0000644000175000017500000000153713104671056025442 0ustar aeglosaeglosRND1TAPEVERSHEADXïÁS™ªÀINFOclassic_mindbender BODYQ $      7              +      +   #        (                    "        ö                !_X M9#<& ‡Z& ' —mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/024.tape0000644000175000017500000000256713105153572025442 0ustar aeglosaeglosRND1TAPEVERSHEADY'·°™«FINFOclassic_mindbenderBODY?& '  #  J’!41. !53$;*!ÿŠÿÿ;*ÿÙ¼R    *<          5"'                    @  L,/        N e        $   A:3,7#        57        ')2mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/012.tape0000644000175000017500000000074313104700315025421 0ustar aeglosaeglosRND1TAPEVERSHEADYö>™ªaINFOclassic_mindbender BODY„&  6    Å   h    ^  %uR .  ) à  /    0]mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/046.tape0000644000175000017500000000272313217001437025434 0ustar aeglosaeglosRND1TAPEVERSHEADZW–.œq]INFOclassic_mindbender.BODYtÿ    ò+0"+ ?                        WÿŸr /³    ©    !     ´    ¤ÿµ ÿÿ€        "    Q ;²                   Hÿ\! 3mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/020.tape0000644000175000017500000000260713104703066025427 0ustar aeglosaeglosRND1TAPEVERSHEADZÊ<™ªJINFOclassic_mindbenderBODY("Í       ÿŒ #(                                     €            3  -    F )   )  8  ù                7        &  _  B          vÖ              %  $  î  9  X    t  r  @  (        )                                §ÿL          Ú               mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/013.tape0000644000175000017500000000076713066702402025436 0ustar aeglosaeglosRND1TAPEVERSHEADYÍ‘˜õfINFOclassic_mindbender BODY˜g:)          UQ¤7ÿÿ        n=!.  N      ;            '      X    q       mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/099.tape0000644000175000017500000000016313072727074025453 0ustar aeglosaeglosRND1TAPEVERSHEADXþN¹™FINFOclassic_mindbender2BODYÿémirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/004.tape0000644000175000017500000000216713104663406025435 0ustar aeglosaeglosRND1TAPEVERSHEADY'½™ªINFOclassic_mindbenderBODY"<  $        $           #                    "   $   ! % 7<-2 ! ,2 C            )                        E        2K               mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/010.tape0000644000175000017500000000162313104671243025424 0ustar aeglosaeglosRND1TAPEVERSHEADXùÄ™ªÍINFOclassic_mindbender BODY4ÿÿÿÿÿ®~- j 8   D        - ) "0    &1        =  ^          '%  !$(0"  ÿëÿX   mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/048.tape0000644000175000017500000000164313217005254025437 0ustar aeglosaeglosRND1TAPEVERSHEADZLðþœqÑINFOclassic_mindbender0BODYDc +   &$     =B O$    ¡L  ,                         5 0ŒR­&            " ÿF 9    Gmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/016.tape0000644000175000017500000000176713104702072025436 0ustar aeglosaeglosRND1TAPEVERSHEADYoᙪæINFOclassic_mindbenderBODY˜Âk              g} , I      5 #G            &    #              (             6                   $*   ‘   @            %              ,                 % 'mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/019.tape0000644000175000017500000000130713066703703025440 0ustar aeglosaeglosRND1TAPEVERSHEADY Tz˜õšINFOclassic_mindbenderBODYh                      / ¿J5&H    *        !                  %   1                                      X                 ;   mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/021.tape0000644000175000017500000000236313104703301025417 0ustar aeglosaeglosRND1TAPEVERSHEADZ\²™ª%INFOclassic_mindbenderBODY”{                        ÿ  ÿ ÿ ª  -  !&  2 TÀ  å  {      ÿ ¯ &   B¹’    > ;V,  ˆ1«  W          `            ˆL       !"2           mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/028.tape0000644000175000017500000000214313105154664025437 0ustar aeglosaeglosRND1TAPEVERSHEADY(Ê™«INFOclassic_mindbenderBODYd" &        ¢  "   /"«&ÿew      g ±-ª“ #V(8        0     !    Q              (        +      %                  mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/018.tape0000644000175000017500000000254713104702543025440 0ustar aeglosaeglosRND1TAPEVERSHEADYã-™ªBINFOclassic_mindbenderBODY;A            2 <" $4%  ×   R  /  +# @                                    %                  ä        8;    ]  Ù      '      !T      +                        B  0 / O             [   ,    -1O, S           >        mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/026.tape0000644000175000017500000000247313105154253025435 0ustar aeglosaeglosRND1TAPEVERSHEADY1N癫7INFOclassic_mindbenderBODYÜ&$>        &    0!,                ÇH D      k  d «]' P5 =/X).!4            Y h    &         <  1                      t                          7        {  ‚  ÿ       (  [  (   '(                      '+mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/032.tape0000644000175000017500000000155713216773265025451 0ustar aeglosaeglosRND1TAPEVERSHEADZ]ö†œqÄINFOclassic_mindbender BODY   $  1Ö7<  Q} ÿ+ÿgDh 3   R        3 “ ' /              › Ñ        ' g        mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/033.tape0000644000175000017500000000214313200705543025425 0ustar aeglosaeglosRND1TAPEVERSHEADZuœINFOclassic_mindbender!BODY9/  !! **3&      (    +  ,  (        +Û / &           >   (3  4‡      '             ]#0        2           .  Q;(h     " ^      ÿ W+8      !   r  4 mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/tapes/042.tape0000644000175000017500000000227713217000131025422 0ustar aeglosaeglosRND1TAPEVERSHEADZQ†‡œqINFOclassic_mindbender*BODY`­  ' c  4 #                                        !                                    +  !      90#mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/092.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 92BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/077.level0000644000175000017500000000050107204325211024470 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 77BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/095.level0000644000175000017500000000050107204325211024470 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 95BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/063.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 63BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/096.level0000644000175000017500000000050107204325211024471 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 96BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/018.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 18BODYÀ——————————————˜š333333333333™˜˜58<<<4:˜˜58>Œ=4:˜˜58>wwwŽ=4:˜˜5:wwwww5:˜˜5:wwww5:˜˜5:wwwww5:˜˜52;ŽwwwŒ;1<:˜˜52;‹7‡<:˜˜™<<<>233315:>˜—————————————mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/064.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 64BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/019.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 19BODYÀs_________////////““““““_/__//_““““_//_““_//_““““_//_““““_/u/_“““_/ZU/_““““_/ZU/_“_/RQ/_““““““_///////_________mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/027.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 27BODYÀ?????????###+%??'##+?*%*/L??%*,*?*%"SC??!**?*WU ??*?*W^??#535#*WM[%#=45%%*UM[-,,,,%(%-.UT[_(,,$*]_['*%E"%'+__]^%"%E%%*###+-,,'#+,,,,,,,,mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/082.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 82BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/080.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 80BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/024.level0000644000175000017500000000050107204325211024460 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 24BODYÀŽOO‘‘‘‘CsL““X\\\TsLCX__SS[]CsL““_WZ_sLC“_X_QCsL__UsLC_U_]CsL“Z_TR_TsLC[_]_UCsL“S__Wmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/059.level0000644000175000017500000000050107204325211024470 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 59BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/054.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 54BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/013.level0000644000175000017500000000050107204325211024456 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 13BODYÀŒŽ??????•????????ŒŽ?`?ŒŽ?????????????????????—????`?•??˜•??˜????˜•—Œ?????˜•????Ž—??Ž—Œ?Ž————Œmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/057.level0000644000175000017500000000050107204325211024466 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 57BODYÀ_________usss__ssvvuv__vtvsv__uvtu__sus_________mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/065.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 65BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/055.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 55BODYÀ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŽ‹‹‹‹‹‹‹‹‹‹‹‹‹‹Ž‹‹‹‹‹‹‹‹‹‹‹‹‹‹Œmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/039.level0000644000175000017500000000050107204325211024466 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 39BODYÀ```````c``c‹`??•?///////?•???//??/??///////??`/??////////??””????////////???mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/022.level0000644000175000017500000000050107204325211024456 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 22BODYÀ5*s]\\.WSS[uWS[^_TUZEZt__UWSS[]\WCKML^RSUW[ZUJwU]^Z]\>]\\^_T^/uFZ__Q##+]I_SWS[[]TIW#S[UZ*R_WSS[5*]\^Z%Z]\\^mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/070.level0000644000175000017500000000050107204325211024461 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 70BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/040.level0000644000175000017500000000050107204325211024456 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 40BODYÀ?sssO•ODR______????•??˜=w;????_?_——އ?_?_——‡Ž?__——‡‡Ž_____O??˜????__Œ——————‡__˜??˜??˜‡_——Ž——‡__Ž——•——Œ__———Ž——Œ_________________mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/078.level0000644000175000017500000000050107204325211024471 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 78BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/levelinfo.conf0000644000175000017500000000050313253546431025770 0ustar aeglosaeglosname: Mindbender author: Holger Schemel imported_from: Original Mindbender levels: 51 graphics_set: gfx_mirrormagic sounds_set: snd_mirrormagic music_set: mus_mirrormagic mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/033.level0000644000175000017500000000050107204325211024460 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 33BODYÀa‹‡r“““r“waa‡–r–‘“a‰u–Œwrar“‘‘““a“–rw‹“Žr‡“‘‡–‹‹“r“urr‡w‘–‡y“ra“mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/061.level0000644000175000017500000000050107204325211024461 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 61BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/034.level0000644000175000017500000000050107204325211024461 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 34BODYÀ'####+'#+#+##+#+% ****“"*%*'#***#+,*-L,,,.%##*"##**'C+###########*%*JOOOE*-L.,,,,,,,,,,,,._C___[______[____Z[UWZQ[WW_W RZQZ _]\T^TX\^T[_]____^_______\_mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/005.level0000644000175000017500000000050107204325211024457 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 5BODYÀ‡‘‘‡‡‡••‡‡‘•‘•mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/087.level0000644000175000017500000000050107204325211024471 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 87BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/046.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 46BODYÀŒ————````ŒŽ?˜??•?•?•?•ŒŽ“?—````Œ?˜???????˜??˜?˜?˜?˜??Ž—————Œ?????????????“OsO““OtvOaOuO“Ž——————Ža“wŽ—————``—Œ——ŽŒmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/043.level0000644000175000017500000000055107223654331024477 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 43AUTH Holger SchemelBODYÀsv########'+(%*$#'+"!*%*X\T*%*ZU*%###$RSQ*%-*%(,,$B*%%"+%*%%*-,,.t%-,.umirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/058.level0000644000175000017500000000050107204325211024467 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 58BODYÀZ__XX[]TUZUTZWXZRYTZTR^UR_T^U[VXT_QRY_VSRmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/094.level0000644000175000017500000000050107204325211024467 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 94BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/045.level0000644000175000017500000000055107223654462024506 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 45AUTH Holger SchemelBODYÀX\\TX^____]TX__tttt__T^__OOOO__]X_uOOs_TZ_uOOs_UZ_uOOs_UR_uOOs_Q[__OOOO__WR__vvvv__QR[____WQRSSQmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/025.level0000644000175000017500000000050107204325211024461 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 25BODYÀŒ/”,,,,,,,,,,,,,,,‡””””””””””””””Ž//////////////////////mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/071.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 71BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/099.level.orig0000644000175000017500000000050107204325211025433 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 99BODYÀ73;'##//O”Ž52%,$/OO#O///58!%OOO%$*5:5b'####+/$=<>=<%*<<<<˜•——`O????%*???˜??b-,,,,.??•˜˜;7%‡,”3•Œ%/*/,/##+•=>•%/‡.-*–??ŽŒ////mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/helptext.conf0000664000175000017500000000524613256026304025650 0ustar aeglosaeglos# ============================================================================= # Mirror Magic / Mindbender element descriptions # ============================================================================= mm_mcduffin: Gregor McDuffin, the magician: He is casting his spells as magic rays of light. mm_exit_closed: Exit door: Direct the ray of light into it when it opens after collecting all kettles. mm_mirror_1: Gnome with rotatable mirror: Reflects the ray of light into different directions. mm_mirror_fixed_1: Stone gnome with fixed mirror: Directs the ray of light into one direction only. mm_kettle: Kettle with spell ingredient: All of them have to be collected by the ray of light. mm_prism: Random reflecting prism: Reflects the ray of light into arbitrary directions. mm_bomb: Light sensitive bomb: Kills the magician if the ray of light points to it for too long. mm_steel_grid_fixed_1: Fixed metallic (reflecting) polarizer: Lets the ray of light pass into a certain angle. mm_wooden_grid_fixed_1: Fixed wooden (absorbing) polarizer: Lets the ray of light pass into a certain angle. mm_polarizer_1: Rotatable one-way polarzer: Lets the ray of light pass into a selectable angle only. mm_polarizer_cross_1: Rotatable two-way polarizer: Lets the ray of light pass into a one of two angles. mm_steel_lock: Metallic (reflecting) lock: Can be destroyed if a key was collected before. mm_wooden_lock: Wooden (absorbing) lock: Can be destroyed if a key was collected before. mm_key: Golden key to open the locks: Collect it with the magic ray of light to open a lock. mm_steel_block: Movable metallic (reflecting) block: Can be moved away by the ray of light. mm_wooden_block: Movable wooden (absorbing) block: Can be moved away by the ray of light. mm_teleporter_1: Spell teleporter: Can transfer the ray of light to its twin of the same color. mm_fuse: Safety device: Stops the ray if it points to it for too long; can be re-activated. mm_lightball_red: Magic balloon gives bonus score: Collecting them gives some extra score. mm_gray_ball: Surprise balloon: Random objects will be released when melted by the ray of light. mm_lightbulb: Light bulb: All of them must be lit before a level can be solved. mm_steel_wall: Metallic wall: Reflects the magic ray of light. mm_wooden_wall: Wooden wall: Absorbs the magic ray of light. mm_ice_wall: Ice wall: Will be melted by the magic ray of light. mm_amoeba_wall: Amoeba wall: Will grow if the magic ray of light points to it for too long. mm_pacman: Moving cruncher: Moves around, trying to eat all kettles and all amoeba walls. mm_fuel_full: Spell amplifier: This gives some extra power to the magician's ray of light. mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/006.level0000644000175000017500000000050107204325211024460 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 6BODYÀbŒŽŒŽŒŽŒŽŒŽŒŽŒŽb•••ŽŒŒŽŽŒŒŽŽŒŒŽŽŒŒŽŽŒŒŽŒŽŒŽŒŽŒŽŒŽŒŽŒŽmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/049.level0000644000175000017500000000050107204325211024467 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 49BODYÀ#/%*/#OD!+,,%*,,'"HOM"-އ‡'+‡‡.!NOOO*‡‡‡‡‡‡‡‡%OOOOE*‡‡‡‡‡‡‡‡%JOOM"'‡‡'+‡‡+!NOOOOG(-‡‡-.‡‡.$KOOE*‡‡‡‡‡‡‡‡%JOOOO*‡‡‡‡‡‡‡‡%OOOG('‡‡-.‡‡+$KOA$.##%*##-(BO,/%*/,mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/050.level0000644000175000017500000000105213217004010024451 0ustar aeglosaeglosRND1CAVEVERSDATEá NAME Mindbender Level 99AUTH Holger SchemelINFOAB CD BODY€—“›‡ƒƒ}¯aqôqqî•a’…Œ„¯¯ƒ¯ð•ð˜…a¯¯}¯…ð„Šï•𚕇ƒƒƒƒ‹}a„aœžœ…aŠœœœœøuaõ÷a÷À¯aŸŸŸŸ…aŠŸŸŸ}øaŸŸÂŒŒŒŒŽŸŸõøø›—…açŒô}“õððì}…}}ŠŒƒƒ‹õžõ…}a}aç}ŽŠöŸaŸîqì}}y}aELEM -A24Bmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/056.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 56BODYÀ mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/004.level0000644000175000017500000000050107204325211024456 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 4BODYÀwwwwwwwwmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/009.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 9BODYÀ'#+73;33#333#33;%*528<<,<<4:-L.5w:'#+#+=L>%*=<>w:%bJ*W_'X/5“J-,.L.W^%[/5““J%*W^-+5“:%###+W^%.7C73;%w*W^%Z/5Ej:%w*_^-+=<=<>/*7C;/]"#####!*5://-,,,,,,/,,.=<>mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/098.level0000644000175000017500000000050107204325211024473 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 98BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/017.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 17BODYÀ73;3373;73;3373;5:5JE:=><<=>=.##->'C####C+5"CC!:%*5($:%“““*7+'\;'####+/=.-S>%*5"!:-L,LL,L.58:7;7;7C;##;5:“5n:5n:,,,:=<><<=<>=<>><=<>mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/038.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 38BODYÀ??/###+“[####+;/!%*^U*“+LN%*RO'“*,NOO,.X'!HOG *Z%“*#R_*]#+,,,,.,,,(,"'#+%*RSS*#%“(, '###$X,%%<,7#%"S!(,$%%-LL% %<,<,mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/062.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 62BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/015.level0000644000175000017500000000050107204325211024460 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 15BODYÀWSSSSSSS[_WSSSS_U;r>71OS“BMMZU7:OODBEJZU1NOG]rBaKMZUHOO_{X^_TZ_UGCRLLQZWBXJE^UrWLDV"##!rX_UZHOE†,,,__UQOOODr[_]T[U“BCOKyE[Z]\\\\\\\_]\\___^mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/047.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 47BODYÀŒŒ‹ŽŽŒŽŒ‹ŒŒŒŒŽŒ‹ŒŽŽŽŽŒ‹‹ŒŒŒŽŒ‹Œ‹‹Ž‹ŽŒŽŽŒŒ‹ŒŽŒ‹ŒŽŽŒŽŽŒŒŽŽŽ‹ŽŽŽŒŽŒŒŽŽŽŒŒ‹ŒŽŒŒŒŽŽŒŒ‹ŒŽŽŽŽ‹‹ŽŽŽŽ‹Ž‹Œ‹ŽŒŽ‹ŽŽŽŒŽŒŽ‹ŒŽŽŒŽ‹ŒŽrŒ‹ŽŽ‹‹‹ŒŽŽ‹ŽŽŽŒŒŒŽŒŒŽmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/helpanim.conf0000664000175000017500000000547313255704767025631 0ustar aeglosaeglos# ============================================================================= # Mirror Magic / Mindbender element animations # ============================================================================= mm_mcduffin.right: 24 mm_mcduffin.up: 24 mm_mcduffin.left: 24 mm_mcduffin.down: 24 end mm_exit_closed: 50 mm_exit.opening: 50 end mm_mirror_1: 6 mm_mirror_2: 6 mm_mirror_3: 6 mm_mirror_4: 6 mm_mirror_5: 6 mm_mirror_6: 6 mm_mirror_7: 6 mm_mirror_8: 6 mm_mirror_9: 6 mm_mirror_10: 6 mm_mirror_11: 6 mm_mirror_12: 6 mm_mirror_13: 6 mm_mirror_14: 6 mm_mirror_15: 6 mm_mirror_16: 6 end mm_mirror_fixed_1: 50 mm_mirror_fixed_2: 50 mm_mirror_fixed_3: 50 mm_mirror_fixed_4: 50 end mm_kettle 100 mm_kettle.exploding: 12 empty_space: 10 end mm_prism: -1 end mm_bomb: 100 mm_bomb.exploding: 16 empty_space: 10 end mm_steel_grid_fixed_1: 50 mm_steel_grid_fixed_3: 50 mm_steel_grid_fixed_2: 50 mm_steel_grid_fixed_4: 50 end mm_wooden_grid_fixed_1: 50 mm_wooden_grid_fixed_3: 50 mm_wooden_grid_fixed_2: 50 mm_wooden_grid_fixed_4: 50 end mm_polarizer_1: 6 mm_polarizer_2: 6 mm_polarizer_3: 6 mm_polarizer_4: 6 mm_polarizer_5: 6 mm_polarizer_6: 6 mm_polarizer_7: 6 mm_polarizer_8: 6 mm_polarizer_9: 6 mm_polarizer_10: 6 mm_polarizer_11: 6 mm_polarizer_12: 6 mm_polarizer_13: 6 mm_polarizer_14: 6 mm_polarizer_15: 6 mm_polarizer_16: 6 end mm_polarizer_cross_1: 6 mm_polarizer_cross_2: 6 mm_polarizer_cross_3: 6 mm_polarizer_cross_4: 6 end mm_steel_lock: -1 end mm_wooden_lock: -1 end mm_key: -1 end mm_steel_block: -1 end mm_wooden_block: -1 end mm_teleporter_1: 6 mm_teleporter_2: 6 mm_teleporter_3: 6 mm_teleporter_4: 6 mm_teleporter_5: 6 mm_teleporter_6: 6 mm_teleporter_7: 6 mm_teleporter_8: 6 mm_teleporter_9: 6 mm_teleporter_10: 6 mm_teleporter_11: 6 mm_teleporter_12: 6 mm_teleporter_13: 6 mm_teleporter_14: 6 mm_teleporter_15: 6 mm_teleporter_16: 6 end mm_fuse: 50 mm_fuse.active: 50 end mm_lightball_red: 32 mm_lightball_blue: 32 mm_lightball_yellow: 32 end mm_gray_ball: 100 mm_kettle 8 mm_gray_ball: 100 mm_mirror_12: 8 mm_gray_ball: 100 mm_pacman.down: 8 mm_gray_ball: 100 mm_polarizer_6: 8 mm_gray_ball: 100 mm_bomb: 8 mm_gray_ball: 100 mm_mirror_fixed_2: 8 mm_gray_ball: 100 mm_prism: 8 mm_gray_ball: 100 mm_polarizer_cross_2: 8 end mm_lightbulb: 50 mm_lightbulb.active: 50 end mm_steel_wall: -1 end mm_wooden_wall: -1 end mm_ice_wall: 100 mm_ice_wall.shrinking: 40 empty_space: 10 end mm_amoeba_wall: 100 mm_amoeba_wall.growing: 40 end mm_pacman.right: 16 mm_pacman.eating.right: 16 mm_pacman.up: 16 mm_pacman.eating.up: 16 mm_pacman.left: 16 mm_pacman.eating.left: 16 mm_pacman.down: 16 mm_pacman.eating.down: 16 end mm_fuel_full: 50 mm_fuel_empty: 50 end mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/023.level0000644000175000017500000000050107204325211024457 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 23BODYÀrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/042.level0000644000175000017500000000050107204325211024460 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 42BODYÀ““““““““““““““““““““““““ŒŽmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/089.level0000644000175000017500000000050107204325211024473 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 89BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/060.level0000644000175000017500000000050107204325211024460 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 60BODYÀ•mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/002.level0000644000175000017500000000050107204325211024454 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 2BODYÀ‘‘‘‡‘‡w‡‘??‘‡ww‡—Ž‘?˜‘‡w‡?˜‘‡?˜‘?˜‘?˜‘?mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/081.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 81BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/085.level0000644000175000017500000000050107204325211024467 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 85BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/090.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 90BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/028.level0000644000175000017500000000050107204325211024464 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 28BODYÀ'#+/#////#/'#+//%Jr#,X-+-,./,////,/./-y.GCKCCCOOKOGGKGyKEJAKrEJMLNLLLOOOLNOLMxN73#33#33????37x;5r#2[QE:=x<,<<,>?=,><=<>Wx__WQXR[_[[___[U[X]_TTW[]\,^_____^_^],]_mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/086.level0000644000175000017500000000050107204325211024470 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 86BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/031.level0000644000175000017500000000050107204325211024456 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 31BODYÀ?????v?v?v??????????˜?˜??—••??????˜?˜??ŒŽ?`?`?`?ŽŒŒ—ŽŽ•ŽŒ—————ŽŽŽ•Œˆ—`—`—`—`—Œ˜•˜Žˆ—————Ž˜˜•—Œ˜˜˜?t?t?t?t??˜˜Ž——————•Œmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/001.level0000644000175000017500000000050107204325211024453 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 1BODYÀ'##############+%“*%*%*%““*%“*%“*%“*%“*%“*%““*-,,,,,,,,,,,,,,.mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/032.level0000644000175000017500000000050107204325211024457 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 32BODYÀ'###+v?v?v?/s/%*_???/___/%($,._?L?L?//O/%*_/%"##+_7S3S;//%*_%“*//-,,,*_5://%**_%“*/L/\/%#+**_5:_“Ou%***_%“*/C/S/%*"*_5:///-.,.=,<,>///mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/035.level0000644000175000017500000000050107204325211024462 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 35BODYÀŒŽ?????????????Ž//”Ž??/”??/////”?Œ?Ž?????????????˜???Œ••??ŒŽ????????‘??Ž?svO‘??ŽŒ?uO‘‘‘?????????????????mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/036.level0000644000175000017500000000050107204325211024463 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 36BODYÀ=====5T;““:1[[V--%*“““**..]*/:??•?/%R—Q*/##2?#%—/•%—3/!???=”/=<<<<>/?33?LL///////‡/L5:OO/"!””‡/O?4```//””/???———Œ///////?mirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/012.level0000644000175000017500000000050107204325211024455 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 12BODYÀŒŽ////////////////////////////////ŒŽ/Ž///Œ//////ŒŽmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/074.level0000644000175000017500000000050107204325211024465 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 74BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/067.level0000644000175000017500000000050107204325211024467 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 67BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/068.level0000644000175000017500000000050107204325211024470 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 68BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/093.level0000644000175000017500000000050107204325211024466 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 93BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/097.level0000644000175000017500000000050107204325211024472 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 97BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/079.level0000644000175000017500000000050107204325211024472 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 79BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/069.level0000644000175000017500000000050107204325211024471 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 69BODYÀmirrormagic-3.0.0/levels/Classic_Games/classic_mindbender/030.level0000644000175000017500000000050107204325211024455 0ustar aeglosaeglosMIRRORMAGIC_LEVEL_FILE_VERSION_1.4 HEADP dMindbender Level 30BODYÀ\__SSQR_]/-$rR_JE[/#-$W^]usOZL/,ˆ#-$]\C/ˆ"+,ˆ#-$__W_Q\/ŽˆŽ"+,ˆ#-$[WRO/ŒˆŒˆˆ"+,ˆ#-$L/OOŒŽ"+,ˆ#-$C/Os_vŒˆˆŽˆ"+,ˆ#/__ŒˆˆŽˆŽˆ"+,/Ot_uOˆŽˆˆŒˆˆˆ"+/OOŽˆˆˆˆˆˆˆˆ/mirrormagic-3.0.0/levels/template.level0000644000175000017500000000065413252154007017475 0ustar aeglosaeglosRND1CAVEINFOAB CdD BODY€uymirrormagic-3.0.0/Makefile0000644000175000017500000001237613263212010014772 0ustar aeglosaeglos# ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1995-2015 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # Makefile # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- # command name of your favorite ANSI C compiler # (this must be set to "cc" for some systems) CC = gcc # command name of GNU make on your system # (this must be set to "gmake" for some systems) MAKE = make # directory for read-only game data (like graphics, sounds, levels) # (this directory is usually the game's installation directory) # default is '.' to be able to run program without installation # RO_GAME_DIR = . # use the following setting for Debian / Ubuntu installations: # RO_GAME_DIR = /usr/share/games/rocksndiamonds # directory for writable game data (like highscore files) # (if no "scores" directory exists, scores are saved in user data directory) # default is '.' to be able to run program without installation # RW_GAME_DIR = . # use the following setting for Debian / Ubuntu installations: # RW_GAME_DIR = /var/games/rocksndiamonds # uncomment if system has no joystick include file # JOYSTICK = -DNO_JOYSTICK # path for cross-compiling (only needed for non-native Windows build) CROSS_PATH_WIN32 = /usr/local/cross-tools/i386-mingw32msvc # ----------------------------------------------------------------------------- # there should be no need to change anything below # ----------------------------------------------------------------------------- .EXPORT_ALL_VARIABLES: SRC_DIR = src ANDROID_DIR ?= android MAKE_CMD = $(MAKE) -C $(SRC_DIR) MAKE_CMD_ANDROID = $(MAKE) -C $(ANDROID_DIR) # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: @$(MAKE_CMD) sdl: @$(MAKE_CMD) TARGET=sdl sdl2: @$(MAKE_CMD) TARGET=sdl2 mac: @$(MAKE_CMD) PLATFORM=macosx cross-win32: @PATH=$(CROSS_PATH_WIN32)/bin:${PATH} $(MAKE_CMD) PLATFORM=cross-win32 android-compile: @$(MAKE_CMD_ANDROID) compile android-package: @$(MAKE_CMD_ANDROID) package android-install: @$(MAKE_CMD_ANDROID) install android-assets-toc: @$(MAKE_CMD_ANDROID) assets-toc android-clean: @$(MAKE_CMD_ANDROID) clean android: android-package clean: @$(MAKE_CMD) clean clean-git: @$(MAKE_CMD) clean-git clean-android: android-clean # ----------------------------------------------------------------------------- # development targets # ----------------------------------------------------------------------------- MAKE_ENGINETEST = ./Scripts/make_enginetest.sh MAKE_LEVELSKETCH = ./Scripts/make_levelsketch_images.sh auto-conf: @$(MAKE_CMD) auto-conf run: all @$(MAKE_CMD) run gdb: all @$(MAKE_CMD) gdb valgrind: all @$(MAKE_CMD) valgrind tags: $(MAKE_CMD) tags depend dep: $(MAKE_CMD) depend enginetest: all $(MAKE_ENGINETEST) enginetestcustom: all $(MAKE_ENGINETEST) custom enginetestfast: all $(MAKE_ENGINETEST) fast enginetestnew: all $(MAKE_ENGINETEST) new leveltest: all $(MAKE_ENGINETEST) leveltest levelsketch_images: all $(MAKE_LEVELSKETCH) # ----------------------------------------------------------------------------- # distribution targets # ----------------------------------------------------------------------------- MAKE_DIST = ./Scripts/make_dist.sh dist-clean: @$(MAKE_CMD) dist-clean dist-clean-android: @$(MAKE_CMD_ANDROID) dist-clean dist-build-unix: @BUILD_DIST=TRUE $(MAKE) dist-build-win32: @BUILD_DIST=TRUE $(MAKE) cross-win32 dist-build-macosx: @BUILD_DIST=TRUE $(MAKE) dist-build-android: @BUILD_DIST=TRUE $(MAKE) android dist-package-unix: $(MAKE_DIST) package unix dist-package-win32: $(MAKE_DIST) package win dist-package-macosx: $(MAKE_DIST) package mac dist-package-android: $(MAKE_DIST) package android dist-copy-package-unix: $(MAKE_DIST) copy-package unix dist-copy-package-win32: $(MAKE_DIST) copy-package win dist-copy-package-macosx: $(MAKE_DIST) copy-package mac dist-copy-package-android: $(MAKE_DIST) copy-package android dist-upload-unix: $(MAKE_DIST) upload unix dist-upload-win32: $(MAKE_DIST) upload win dist-upload-macosx: $(MAKE_DIST) upload mac dist-upload-android: $(MAKE_DIST) upload android dist-package-all: $(MAKE) dist-package-unix $(MAKE) dist-package-win32 $(MAKE) dist-package-macosx $(MAKE) dist-package-android dist-copy-package-all: $(MAKE) dist-copy-package-unix $(MAKE) dist-copy-package-win32 $(MAKE) dist-copy-package-macosx $(MAKE) dist-copy-package-android dist-upload-all: $(MAKE) dist-upload-unix $(MAKE) dist-upload-win32 $(MAKE) dist-upload-macosx $(MAKE) dist-upload-android dist-release-all: dist-package-all dist-copy-package-all dist-upload-all package-all: dist-package-all copy-package-all: dist-copy-package_all upload-all: dist-upload-all release-all: dist-release-all mirrormagic-3.0.0/docs/0000755000175000017500000000000013263212010014251 5ustar aeglosaeglosmirrormagic-3.0.0/docs/elements/0000755000175000017500000000000013263212010016065 5ustar aeglosaeglosmirrormagic-3.0.0/docs/elements/emc_gate_7.txt0000644000175000017500000000044013263212010020616 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/em_gate_3_gray.txt0000644000175000017500000000061513263212010021475 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/df_refractor.txt0000644000175000017500000000007513263212010021270 0ustar aeglosaeglosRefractors reflect the laser beam into arbitrary directions. mirrormagic-3.0.0/docs/elements/amoeba_wet.txt0000644000175000017500000000042013263212010020725 0ustar aeglosaeglosDripping amoeba will grow in drops, and will not die even if surrounded. Amoeba will kill any bugs, flies, or spaceships that touch it. The amoeba growth value is the same for all types of amoeba. Amoeba will take between 0 and [25/(1-value)] seconds to attempt to grow. mirrormagic-3.0.0/docs/elements/emc_android.txt0000644000175000017500000000022313263212010021067 0ustar aeglosaeglosThe android has some special properties. Unless other elements, it can move diagonally. Additionally, it can clone other game elements it touches. mirrormagic-3.0.0/docs/elements/em_key_3.txt0000644000175000017500000000012113263212010020313 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/wall.txt0000644000175000017500000000007213263212010017564 0ustar aeglosaeglosThis is an average wall. It can't stand up to explosions. mirrormagic-3.0.0/docs/elements/expandable_wall.txt0000644000175000017500000000053413263212010021752 0ustar aeglosaeglosThis wall will grow on either side that is open. It will stop growing on one side if it is blocked by a wall, even if said wall is later destroyed. Gems and others, however, will stop it only temporarily. This particular growing wall is the only one that is visibly different to the player from a normal wall, at least under the default graphics. mirrormagic-3.0.0/docs/elements/df_mirror_rotating.txt0000644000175000017500000000014313263212010022516 0ustar aeglosaeglosThis automated mirror is permanently rotating to reflect the laser beam into different directions. mirrormagic-3.0.0/docs/elements/df_wooden_wall.txt0000644000175000017500000000004413263212010021607 0ustar aeglosaeglosWooden walls absorb the laser beam. mirrormagic-3.0.0/docs/elements/conveyor_belt_switch.txt0000644000175000017500000000032513263212010023061 0ustar aeglosaeglosPressing against this switch turns conveyor belts on and off. If it starts off, it will toggle from off to left to off to right. Switches (and therefore their belts) may also start turned on to the right or left. mirrormagic-3.0.0/docs/elements/empty_space.txt0000644000175000017500000000010113263212010021127 0ustar aeglosaeglosJust empty space. Everything can walk, move or fall through it. mirrormagic-3.0.0/docs/elements/mm_lightbulb.txt0000644000175000017500000000007613263212010021276 0ustar aeglosaeglosThe light bulbs must all be lit before a level can be solved. mirrormagic-3.0.0/docs/elements/quicksand_fast_full.txt0000644000175000017500000000016113263212010022645 0ustar aeglosaeglosThis quicksand already contains a rock which can slide through it and leave it if there is empty space below it. mirrormagic-3.0.0/docs/elements/wall_slippery.txt0000644000175000017500000000014013263212010021507 0ustar aeglosaeglosAs expected, objects slip off the round top of this wall. Otherwise, it's just an average wall. mirrormagic-3.0.0/docs/elements/dynamite.txt0000644000175000017500000000024113263212010020435 0ustar aeglosaeglosCollect the dynamite and use it later to blow up walls (which might contain gems), enemies or other things. Dynamite caught in an explosion will explode itself! mirrormagic-3.0.0/docs/elements/quicksand_fast_empty.txt0000644000175000017500000000031213263212010023037 0ustar aeglosaeglosA rock that is pushed or thrown on the quicksand sinks into it, passes it and again leaves it if there is empty space below it. Amoeba can grow into it, but other elements and the player can't pass it. mirrormagic-3.0.0/docs/elements/bug.txt0000644000175000017500000000030113263212010017375 0ustar aeglosaeglosBugs always try to follow the right side of a wall or other elements. Touching them is deadly. Bugs will explode into a diamond surrounded by 8 emeralds, even when caught in other explosions! mirrormagic-3.0.0/docs/elements/df_steel_grid_rotating.txt0000644000175000017500000000015413263212010023327 0ustar aeglosaeglosThis automated steel polarizer is permanently rotating to reflect the laser beam into different directions. mirrormagic-3.0.0/docs/elements/exit_closed.txt0000644000175000017500000000031013263212010021122 0ustar aeglosaeglosThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. mirrormagic-3.0.0/docs/elements/pearl.txt0000644000175000017500000000026613263212010017735 0ustar aeglosaeglosA pearl is worth 5 emeralds, but it's very fragile. Not only can it be crushed by rocks, but if it falls and lands on something, it'll break! At least you won't get crushed by it... mirrormagic-3.0.0/docs/elements/mm_gray_ball.txt0000644000175000017500000000014213263212010021250 0ustar aeglosaeglosThis gray ball contains random objects that will be released by melting it with the ray of light. mirrormagic-3.0.0/docs/elements/acid_pool_bottom.txt0000644000175000017500000000012013263212010022134 0ustar aeglosaeglosAcid pool walls are equivalent to steel walls, except some of them are rounded. mirrormagic-3.0.0/docs/elements/emc_magnifier.txt0000644000175000017500000000015513263212010021414 0ustar aeglosaeglosThe magnifier can be used to make fake grass visible and show the real color of gray doors for a short time. mirrormagic-3.0.0/docs/elements/gate_1_gray.txt0000644000175000017500000000015413263212010021010 0ustar aeglosaeglosGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/mm_amoeba_wall.txt0000644000175000017500000000011613263212010021560 0ustar aeglosaeglosAmoeba walls will grow if the magic ray of light points to them for too long. mirrormagic-3.0.0/docs/elements/steel_exit_closed.txt0000644000175000017500000000037313263212010022327 0ustar aeglosaeglosThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. This exit is made of steel and is indestructible. mirrormagic-3.0.0/docs/elements/sp_hardware_red.txt0000644000175000017500000000010513263212010021753 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/prev_ce.txt0000644000175000017500000000026713263212010020256 0ustar aeglosaeglosIf you use this reference element, it will be replaced by the custom element that is at an earlier position in the element list (with the distance as shown by the reference element). mirrormagic-3.0.0/docs/elements/robot_wheel.txt0000644000175000017500000000054113263212010021137 0ustar aeglosaeglosActivating the magic wheel attracts the robots for a short time and keeps them away from the player. When it stops running, the robots will again turn towards the player. The magic wheel can be activated again after it stopped running. You can also activate other magic wheels while one is spinning; the robots will go towards the latest active wheel. mirrormagic-3.0.0/docs/elements/quicksand_full.txt0000644000175000017500000000016113263212010021630 0ustar aeglosaeglosThis quicksand already contains a rock which can slide through it and leave it if there is empty space below it. mirrormagic-3.0.0/docs/elements/df_fibre_optic.txt0000644000175000017500000000012113263212010021556 0ustar aeglosaeglosFibre optics can redirect the laser beam to their counterpart of the same color. mirrormagic-3.0.0/docs/elements/mm_lightball.txt0000644000175000017500000000006213263212010021257 0ustar aeglosaeglosCollecting the light balls give some extra score. mirrormagic-3.0.0/docs/elements/emc_magic_ball.txt0000644000175000017500000000054313263212010021526 0ustar aeglosaeglosThe magic ball can create new elements when activated by the magic ball switch. It is possible to use up to eight magic balls which create different elements by using the eight content areas. Instead of creating all elements from the content area, it is also possible to let the magic ball create only one element randomly selected from the content area. mirrormagic-3.0.0/docs/elements/emc_spring_bumper.txt0000644000175000017500000000012613263212010022325 0ustar aeglosaeglosWhen a moving spring hits a spring bumper, it is reflected to the opposite direction. mirrormagic-3.0.0/docs/elements/em_gate_3.txt0000644000175000017500000000044013263212010020447 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/sp_hardware_base_3.txt0000644000175000017500000000010513263212010022335 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/df_receiver.txt0000644000175000017500000000016613263212010021106 0ustar aeglosaeglosThis is the laser receiver into which the laser beam must be directed after collecting all cells to finish the level. mirrormagic-3.0.0/docs/elements/emc_gate_7_gray.txt0000644000175000017500000000061513263212010021644 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/trigger_ce_value.txt0000644000175000017500000000040713263212010022135 0ustar aeglosaeglosThis can be used in custom element programming to refer to the CE value of the element that triggered the change being processed, but interpreted as an element itself (if the CE value was set to an element earlier). Don't use this element directly in your level. mirrormagic-3.0.0/docs/elements/player_3.txt0000644000175000017500000000002213263212010020336 0ustar aeglosaeglosThis is player 3. mirrormagic-3.0.0/docs/elements/em_steel_exit_closed.txt0000644000175000017500000000037313263212010023010 0ustar aeglosaeglosThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. This exit is made of steel and is indestructible. mirrormagic-3.0.0/docs/elements/bd_butterfly.txt0000644000175000017500000000042613263212010021315 0ustar aeglosaeglosButterflies always try to follow the right side of a wall or other elements. Touching them is deadly. They will explode in 9 BD style diamonds if smashed by a rock or BD style diamond. If dynabombed, they will become one BD style diamond. Other explosions simply destroy them. mirrormagic-3.0.0/docs/elements/df_cell.txt0000644000175000017500000000010513263212010020212 0ustar aeglosaeglosThese cells have to be collected by the laser beam to solve a level. mirrormagic-3.0.0/docs/elements/emc_fake_grass.txt0000644000175000017500000000023013263212010021552 0ustar aeglosaeglosThe fake grass looks like normal grass, but but cannot be digged. If the magnifier has been collected, the fake grass becomes visible for a short time. mirrormagic-3.0.0/docs/elements/satellite.txt0000644000175000017500000000057313263212010020621 0ustar aeglosaeglosSatellites will follow the player as best they can, and the only way to outrun them is with double speed. Satellites are harmless, and they can be pushed, but in multiples or with strategically placed walls, they can easily trap the player. When crushed or caught in an explosion, satellites will explode. Satellites can be used as a sort of moving platform when gravity is on. mirrormagic-3.0.0/docs/elements/timegate_open.txt0000644000175000017500000000007213263212010021445 0ustar aeglosaeglosAn open time gate will close as soon as the level starts. mirrormagic-3.0.0/docs/elements/sokoban_field_full.txt0000644000175000017500000000045613263212010022454 0ustar aeglosaeglosThis is a sokoban field that already has a sokoban object. Note that it's safe to blow up a full sokoban field without affecting your ability to open the exit. Also, if the exit is already open, it will never close up. However, disrupting the puzzle in any other way will mess up your chances to win. mirrormagic-3.0.0/docs/elements/biomaze.txt0000644000175000017500000000031213263212010020250 0ustar aeglosaeglosThe Biomaze is a variant of the Game of Life that tends to make crazy mazes. The players don't count as cells with Biomaze. Watch those corners; it may take annoyingly long for the corners to clear up. mirrormagic-3.0.0/docs/elements/acid_pool_topleft.txt0000644000175000017500000000012013263212010022305 0ustar aeglosaeglosAcid pool walls are equivalent to steel walls, except some of them are rounded. mirrormagic-3.0.0/docs/elements/sp_exit_closed.txt0000644000175000017500000000020013263212010021622 0ustar aeglosaeglosYou can enter and win with a Supaplex exit even if there are unlit lightbulbs or unsaved penguins. All you need is enough gems. mirrormagic-3.0.0/docs/elements/from_level_template.txt0000644000175000017500000000035513263212010022656 0ustar aeglosaeglosThis is a special element that can be used in levels using a level template. Every element of this kind in the playfield will be replaced with the element from the (otherwise unused) playfield of the level template at the same position. mirrormagic-3.0.0/docs/elements/timegate_closed.txt0000644000175000017500000000005113263212010021752 0ustar aeglosaeglosTime gates only open for a limited time. mirrormagic-3.0.0/docs/elements/emc_plant.txt0000644000175000017500000000007613263212010020573 0ustar aeglosaeglosThe plant is deadly to the player when he is running into it. mirrormagic-3.0.0/docs/elements/wall_pearl.txt0000644000175000017500000000016013263212010020745 0ustar aeglosaeglosThis wall contains a pearl which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/player_2.txt0000644000175000017500000000002213263212010020335 0ustar aeglosaeglosThis is player 2. mirrormagic-3.0.0/docs/elements/sp_infotron.txt0000644000175000017500000000005013263212010021161 0ustar aeglosaeglosInfotrons are the emeralds of Supaplex. mirrormagic-3.0.0/docs/elements/acid_pool_topright.txt0000644000175000017500000000012013263212010022470 0ustar aeglosaeglosAcid pool walls are equivalent to steel walls, except some of them are rounded. mirrormagic-3.0.0/docs/elements/trigger_ce_score.txt0000644000175000017500000000040713263212010022134 0ustar aeglosaeglosThis can be used in custom element programming to refer to the CE score of the element that triggered the change being processed, but interpreted as an element itself (if the CE score was set to an element earlier). Don't use this element directly in your level. mirrormagic-3.0.0/docs/elements/em_key_4.txt0000644000175000017500000000012113263212010020314 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/sign.txt0000644000175000017500000000004513263212010017565 0ustar aeglosaeglosJust a steel wall with a sign on it. mirrormagic-3.0.0/docs/elements/sp_port_any.txt0000644000175000017500000000005413263212010021162 0ustar aeglosaeglosYou can enter this port from ANY direction. mirrormagic-3.0.0/docs/elements/gate_3_gray.txt0000644000175000017500000000015413263212010021012 0ustar aeglosaeglosGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/mm_kettle.txt0000644000175000017500000000022613263212010020607 0ustar aeglosaeglosMagic kettles contain ingredients for Gregor MacDuffin's magic spells and must all be collected before the magic exit door opens to finish the level. mirrormagic-3.0.0/docs/elements/expandable_wall_any.txt0000644000175000017500000000025713263212010022623 0ustar aeglosaeglosUnlike other growing walls, this wall will never "die off" because of other walls. It will spread wherever there is adjacent space, following even the most complicated paths. mirrormagic-3.0.0/docs/elements/mm_mirror.txt0000644000175000017500000000022313263212010020626 0ustar aeglosaeglosThis mirror, held by one of Gregor McDuffin's helpful gnomes, can manually be rotated to reflect his magic ray of light into different directions. mirrormagic-3.0.0/docs/elements/steel_exit_open.txt0000644000175000017500000000052013263212010022011 0ustar aeglosaeglosThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. This exit is made of steel and is indestructible. mirrormagic-3.0.0/docs/elements/lamp.txt0000644000175000017500000000022213263212010017553 0ustar aeglosaeglosLightbulbs need to be turned on by touching them before the exit will open. Watch out! If they're crushed by a rock, you won't be able to escape! mirrormagic-3.0.0/docs/elements/trigger_player.txt0000644000175000017500000000023713263212010021647 0ustar aeglosaeglosThis can be used in custom element programming to refer to the player who triggered the change being processed. Don't use this element directly in your level. mirrormagic-3.0.0/docs/elements/landmine.txt0000644000175000017500000000017513263212010020420 0ustar aeglosaeglosIf you run into a land mine, you die. Otherwise, it's a normal, destructible wall that just happens to look kinda like dirt. mirrormagic-3.0.0/docs/elements/sp_buggy_base.txt0000644000175000017500000000010613263212010021434 0ustar aeglosaeglosTouching the buggy base when the electricity is arcing is bad news... mirrormagic-3.0.0/docs/elements/sp_port_vertical.txt0000644000175000017500000000003213263212010022200 0ustar aeglosaeglosThis port goes both ways. mirrormagic-3.0.0/docs/elements/sp_chip_top.txt0000644000175000017500000000005713263212010021137 0ustar aeglosaeglosThis is a normal, destructable, slippery wall. mirrormagic-3.0.0/docs/elements/mm_exit.txt0000644000175000017500000000021613263212010020267 0ustar aeglosaeglosThis magic exit door opens once all magic kettles have been collected. Redirect the magic ray of light into the exit door to finish the game. mirrormagic-3.0.0/docs/elements/sokoban_object.txt0000644000175000017500000000025213263212010021607 0ustar aeglosaeglosThese lightbulbs can be pushed around. The goal is to fill all the Sokoban fields at once. Only then will the exit open, assuming all other conditions have been met too. mirrormagic-3.0.0/docs/elements/trap.txt0000644000175000017500000000023013263212010017567 0ustar aeglosaeglosDigging this when the trap is open is fatal. Otherwise, it's just ordinary dirt. Snapping it when the trap is open will not kill the player, just fail. mirrormagic-3.0.0/docs/elements/bd_amoeba.txt0000644000175000017500000000054413263212010020522 0ustar aeglosaeglosThe BD style amoeba has some special properties: When it is completely surrounded, it instantly turns into the specified content. But if this cannot be achieved in a certain amount of time, this amoeba instantly turns to BD boulders instead. BD amoeba is the only amoeba that can be smothered by the player. All amoeba types must share the same settings. mirrormagic-3.0.0/docs/elements/frankie.txt0000644000175000017500000000015613263212010020247 0ustar aeglosaeglosThis is an average wall (that somehow reminds of Frankie Goes To Hollywood). It can't stand up to explosions. mirrormagic-3.0.0/docs/elements/game_of_life.txt0000644000175000017500000000056213263212010021225 0ustar aeglosaeglosThese walls behave like the well-known "Conway's Game of Life". They behave like normal walls; however, they may appear or disappear every half-second according to these rules: Cells that are surrounded by 2 or 3 cells are the only cells that survive. Space or dirt that is surrounded by exactly 3 cells grows into new cells. The player(s) is (are) counted as cells! mirrormagic-3.0.0/docs/elements/sp_hardware_green.txt0000644000175000017500000000010513263212010022301 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/arrow_left.txt0000644000175000017500000000012413263212010020767 0ustar aeglosaeglosThis acts as an average wall. Although it looks round, objects do not slide off it. mirrormagic-3.0.0/docs/elements/shield_normal.txt0000644000175000017500000000024413263212010021446 0ustar aeglosaeglosPicking this up will give the player 10 seconds of invulnerability. Additional shields will add 10 more seconds, and will not waste seconds the player already has. mirrormagic-3.0.0/docs/elements/bomb.txt0000644000175000017500000000020313263212010017540 0ustar aeglosaeglosBombs can be blown up either by throwing them down or by dropping a rock on them. Bombs caught in an explosion explode themselves. mirrormagic-3.0.0/docs/elements/emc_gate_8_gray.txt0000644000175000017500000000061513263212010021645 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/em_gate_2_gray.txt0000644000175000017500000000061513263212010021474 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/wall_emerald_red.txt0000644000175000017500000000016613263212010022113 0ustar aeglosaeglosThis wall contains a red emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/sp_murphy.txt0000644000175000017500000000016113263212010020652 0ustar aeglosaeglosMurphy is the hero of Supaplex. Note that other than his default settings, Murphy behaves exactly like Rockford. mirrormagic-3.0.0/docs/elements/gate_2.txt0000644000175000017500000000010113263212010017757 0ustar aeglosaeglosYou may only walk over a colored door if you have the right key. mirrormagic-3.0.0/docs/elements/emc_lenses.txt0000644000175000017500000000013413263212010020741 0ustar aeglosaeglosThe lenses can be used to make the invisible wall and the dripper visible for a short time. mirrormagic-3.0.0/docs/elements/sp_chip_right.txt0000644000175000017500000000005713263212010021452 0ustar aeglosaeglosThis is a normal, destructable, slippery wall. mirrormagic-3.0.0/docs/elements/sp_disk_orange.txt0000644000175000017500000000010413263212010021610 0ustar aeglosaeglosOrange disks are like stable bombs, only they can be pushed faster. mirrormagic-3.0.0/docs/elements/emc_key_6.txt0000644000175000017500000000012113263212010020461 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/yamyam.txt0000644000175000017500000000061313263212010020123 0ustar aeglosaeglosThe Yam Yam is one of the most exciting creatures. When it explodes (by dropping a rock on it, for example), it can turn to nine new elements. Further exploding Yam Yams can turn to other elements, up to eight different sets of new elements. Sometimes the last emerald you are looking for to finish the level is hidden in a Yam Yam! But be careful: Yam Yams will eat all diamonds in their way! mirrormagic-3.0.0/docs/elements/emc_fake_acid.txt0000644000175000017500000000007713263212010021344 0ustar aeglosaeglosThe fake acid looks like acid, but is walkable for the player. mirrormagic-3.0.0/docs/elements/em_gate_1_gray.txt0000644000175000017500000000061513263212010021473 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/mm_steel_lock.txt0000644000175000017500000000017013263212010021441 0ustar aeglosaeglosThis is a (reflecting) steel lock that will be vaporized by the magic ray of light if a key was collected by it before. mirrormagic-3.0.0/docs/elements/mm_prism.txt0000644000175000017500000000011413263212010020445 0ustar aeglosaeglosMagic prisms reflect the magician's ray of light into arbitrary directions. mirrormagic-3.0.0/docs/elements/sp_hardware_base_4.txt0000644000175000017500000000010513263212010022336 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/mm_steel_block.txt0000644000175000017500000000012513263212010021603 0ustar aeglosaeglosThis is a (reflecting) steel block that can be moved away by the magic ray of light. mirrormagic-3.0.0/docs/elements/self.txt0000644000175000017500000000036313263212010017561 0ustar aeglosaeglosThis is a placeholder for the custom element you are just editing. If an element should change to itself, you can use this "reference element" instead of the real element. If you copy your custom element, this elements still refers to itself. mirrormagic-3.0.0/docs/elements/df_mirror.txt0000644000175000017500000000013113263212010020604 0ustar aeglosaeglosThis mirror can manually be rotated to reflect the laser beam into different directions. mirrormagic-3.0.0/docs/elements/df_wooden_grid_rotating.txt0000644000175000017500000000015513263212010023507 0ustar aeglosaeglosThis automated wooden polarizer is permanently rotating to reflect the laser beam into different directions. mirrormagic-3.0.0/docs/elements/magic_wall.txt0000644000175000017500000000062613263212010020731 0ustar aeglosaeglosThis is a (EM style) magic wall. It gets activated for a limited time by rocks or gems that fall on it. Objects falling though it will be changed to other objects. After it has stopped running, it cannot be activated again. The duration is expressed in seconds. A duration of zero will let the wall run forever. All regular magic walls run together; however, BD style magic walls have a separate counter. mirrormagic-3.0.0/docs/elements/emerald.txt0000644000175000017500000000017613263212010020243 0ustar aeglosaeglosYour basic gem. Collect enough of these to open the exit. Rockfords give off 9 of the appropriate colored gems when they die. mirrormagic-3.0.0/docs/elements/invisible_sand.txt0000644000175000017500000000021413263212010021614 0ustar aeglosaeglosInvisible sand behaves exactly like normal sand, but is invisible. It can be made visible for a short time by activating the light switch. mirrormagic-3.0.0/docs/elements/sand.txt0000644000175000017500000000025013263212010017550 0ustar aeglosaeglosSand blocks pretty much everything except the player. The player digs through the sand, leaving behind empty space. Sand often makes up the vast majority of the level. mirrormagic-3.0.0/docs/elements/wall_emerald.txt0000644000175000017500000000016313263212010021256 0ustar aeglosaeglosThis wall contains an emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/speed_pill.txt0000644000175000017500000000013113263212010020741 0ustar aeglosaeglosTaking this pill will double the player's speed. Additional pills are only worth points. mirrormagic-3.0.0/docs/elements/df_mine.txt0000644000175000017500000000010013263212010020216 0ustar aeglosaeglosMines will destroy the laser if it points to them for too long. mirrormagic-3.0.0/docs/elements/timegate_switch.txt0000644000175000017500000000020213263212010022000 0ustar aeglosaeglosAs long as a single time gate switch is spinning, all time gates will be open. Each switch spins for a certain time when touched. mirrormagic-3.0.0/docs/elements/df_laser.txt0000644000175000017500000000015013263212010020401 0ustar aeglosaeglosThis is the laser cannon that is emitting the laser beam used to collect all cells to finish the level. mirrormagic-3.0.0/docs/elements/em_steel_exit_open.txt0000644000175000017500000000060513263212010022476 0ustar aeglosaeglosThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. This exit is made of steel and is indestructible. It disappears when the player is passing through it. mirrormagic-3.0.0/docs/elements/balloon.txt0000644000175000017500000000017413263212010020256 0ustar aeglosaeglosBalloons can be pushed by the player. Their more useful properties are only available in conjection with the wind switches. mirrormagic-3.0.0/docs/elements/gate_2_gray.txt0000644000175000017500000000015413263212010021011 0ustar aeglosaeglosGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/emc_magic_ball_switch.txt0000644000175000017500000000007713263212010023111 0ustar aeglosaeglosUse the magic ball switch to enable or disable the magic ball. mirrormagic-3.0.0/docs/elements/sp_gravity_off_port.txt0000644000175000017500000000014513263212010022713 0ustar aeglosaeglosThese ports look like ordinary ports in-game, but when you go through them, gravity is switched off. mirrormagic-3.0.0/docs/elements/tube.txt0000644000175000017500000000017613263212010017571 0ustar aeglosaeglosA tube is just something to crawl around in and get lost. Things outside the tube can't affect things inside, and vice versa. mirrormagic-3.0.0/docs/elements/sp_zonk.txt0000644000175000017500000000020313263212010020304 0ustar aeglosaeglosThe Zonk is the Supaplex equivalent of the rock. Note that it can be pushed quicker than rocks, resulting in some clever tricks... mirrormagic-3.0.0/docs/elements/mm_steel_grid_fixed.txt0000644000175000017500000000015013263212010022613 0ustar aeglosaeglosThis is a fixed (reflecting) steel polarizer that lets the ray of light pass into a certain angle only. mirrormagic-3.0.0/docs/elements/sp_sniksnak.txt0000644000175000017500000000011713263212010021150 0ustar aeglosaeglosSnik snaks are basically spaceships, except you must collide with them to die. mirrormagic-3.0.0/docs/elements/df_wooden_grid_fixed.txt0000644000175000017500000000015513263212010022757 0ustar aeglosaeglosThis is a fixed (non-reflecting) wooden polarizer that lets the ray of light pass into a certain angle only. mirrormagic-3.0.0/docs/elements/light_switch.active.txt0000644000175000017500000000010713263212010022566 0ustar aeglosaeglosAn active light switch will last for 10 seconds when the level starts. mirrormagic-3.0.0/docs/elements/balloon_switch_any.txt0000644000175000017500000000061113263212010022502 0ustar aeglosaeglosPressing this switch in a certain direction will cause all balloons and custom elements that react on wind in this level to constantly move in that direction if possible until another wind switch is pressed. The balloons may still be pushed in any direction, including against their automatic movement direction, but they will try to move in the appropriate wind direction whenever they can. mirrormagic-3.0.0/docs/elements/black_orb.txt0000644000175000017500000000025513263212010020546 0ustar aeglosaeglosBlack Orb Bombs are floating explosives. They cannot be set off by anything other than another explosion, but once set off, a chain of them will explode at lightning speed! mirrormagic-3.0.0/docs/elements/arrow_down.txt0000644000175000017500000000012413263212010021004 0ustar aeglosaeglosThis acts as an average wall. Although it looks round, objects do not slide off it. mirrormagic-3.0.0/docs/elements/emc_gate_5_gray.txt0000644000175000017500000000061513263212010021642 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/sp_port.txt0000644000175000017500000000007313263212010020314 0ustar aeglosaeglosPorts allow one way passage, as long as the path is clear. mirrormagic-3.0.0/docs/elements/em_gate_4.txt0000644000175000017500000000044013263212010020450 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/rock.txt0000644000175000017500000000024113263212010017561 0ustar aeglosaeglosRocks are round, heavy, they fall, and they smash stuff. They don't smash anything unless being already in motion first. The player can push one rock at a time. mirrormagic-3.0.0/docs/elements/emc_dripper.txt0000644000175000017500000000022113263212010021112 0ustar aeglosaeglosThis element can create new amoeba drops and is otherwise invisible. If the lenses have been collected, the dripper is visible for a short time. mirrormagic-3.0.0/docs/elements/mm_ice_wall.txt0000644000175000017500000000005613263212010021077 0ustar aeglosaeglosIce walls will be melted by the ray of light. mirrormagic-3.0.0/docs/elements/unknown.txt0000644000175000017500000000002113263212010020316 0ustar aeglosaeglosUnknown element. mirrormagic-3.0.0/docs/elements/stoneblock.txt0000644000175000017500000000007213263212010020770 0ustar aeglosaeglosThis is an average wall. It can't stand up to explosions. mirrormagic-3.0.0/docs/elements/key_1.txt0000644000175000017500000000025513263212010017640 0ustar aeglosaeglosYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. mirrormagic-3.0.0/docs/elements/bd_firefly.txt0000644000175000017500000000025013263212010020730 0ustar aeglosaeglosFireflies always try to follow the left side of a wall or other elements. Touching them is deadly. Fireflies can be smashed by BD style diamonds in addition to rocks. mirrormagic-3.0.0/docs/elements/steelwall_slippery.txt0000644000175000017500000000004713263212010022552 0ustar aeglosaeglosThis is a steel wall that is slippery. mirrormagic-3.0.0/docs/elements/key_4.txt0000644000175000017500000000025513263212010017643 0ustar aeglosaeglosYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. mirrormagic-3.0.0/docs/elements/conveyor_belt.txt0000644000175000017500000000034313263212010021500 0ustar aeglosaeglosConveyor belts will move around any object that can fall. The edges of the belts aren't round, they just make your belt nicer. Each colored switch controls all of that color conveyor belt. Belts can be made of multiple colors. mirrormagic-3.0.0/docs/elements/steelwall.txt0000644000175000017500000000010513263212010020616 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/sp_base.txt0000644000175000017500000000013613263212010020242 0ustar aeglosaeglosThe base is the Supaplex equivalent of dirt. Bases will block Dark Yam Yams, but not amoeba. mirrormagic-3.0.0/docs/elements/dx_supabomb.txt0000644000175000017500000000007613263212010021134 0ustar aeglosaeglosThe stable bomb won't roll or have other objects roll off it. mirrormagic-3.0.0/docs/elements/current_ce_value.txt0000644000175000017500000000034513263212010022155 0ustar aeglosaeglosThis can be used in custom element programming to refer to the CE value of the current element, but interpreted as an element itself (if the CE value was set to an element earlier). Don't use this element directly in your level. mirrormagic-3.0.0/docs/elements/mm_steel_wall.txt0000644000175000017500000000004613263212010021452 0ustar aeglosaeglosSteel walls reflect the ray of light. mirrormagic-3.0.0/docs/elements/sp_hardware_base_2.txt0000644000175000017500000000010513263212010022334 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/sp_terminal.txt0000644000175000017500000000016413263212010021144 0ustar aeglosaeglosPress a terminal, and all the yellow disks on the level will explode! Otherwise, it's a normal wall all over again. mirrormagic-3.0.0/docs/elements/em_gate_4_gray.txt0000644000175000017500000000061513263212010021476 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/sokoban_field_empty.txt0000644000175000017500000000052113263212010022641 0ustar aeglosaeglosThis is an empty sokoban field. Only the player and sokoban objects can pass onto these fields. Watch out, the fields will be destroyed by explosions! Note that spare fields will prevent the exit from opening, but spare objects won't. Also, sometimes it is necessary to push sokoban objects off of fields to make room for other things. mirrormagic-3.0.0/docs/elements/emc_grass.txt0000644000175000017500000000004413263212010020567 0ustar aeglosaeglosGrass behaves just exactly as sand. mirrormagic-3.0.0/docs/elements/player_1.txt0000644000175000017500000000017413263212010020344 0ustar aeglosaeglosThis is the player. You'll probably want to have one of these each level. If you have more than one, only one will be used. mirrormagic-3.0.0/docs/elements/spaceship.txt0000644000175000017500000000023413263212010020604 0ustar aeglosaeglosSpaceships always try to follow the left side of a wall or other elements. Touching them is deadly. Spaceships will not explode when caught in explosions. mirrormagic-3.0.0/docs/elements/em_gate_2.txt0000644000175000017500000000044013263212010020446 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/sp_hardware_gray.txt0000644000175000017500000000010513263212010022143 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/emc_gate_8.txt0000644000175000017500000000044013263212010020617 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/amoeba_to_diamond.txt0000644000175000017500000000012113263212010022241 0ustar aeglosaeglosThe "amoeba_to_diamond" element is a runtime element and should be removed here. mirrormagic-3.0.0/docs/elements/char_space.txt0000644000175000017500000000032613263212010020717 0ustar aeglosaeglosThe space character is tricky. It's basically like an invisible normal wall, but it won't light up when a light switch is flicked on. Watch out for these in the editor; they can often be confused for empty space. mirrormagic-3.0.0/docs/elements/crystal.txt0000644000175000017500000000010113263212010020277 0ustar aeglosaeglosCrystals are indestructable and are worth a whopping 8 emeralds! mirrormagic-3.0.0/docs/elements/amoeba_drop.txt0000644000175000017500000000016713263212010021102 0ustar aeglosaeglosAn amoeba drop will become a dripping amoeba when it lands. It would be wise to stay out from underneath these things. mirrormagic-3.0.0/docs/elements/bd_diamond.txt0000644000175000017500000000014213263212010020703 0ustar aeglosaeglosBD style levels require a certain amount of these diamonds to be collected to complete the level. mirrormagic-3.0.0/docs/elements/mm_wooden_block.txt0000644000175000017500000000013213263212010021760 0ustar aeglosaeglosThis is a (non-reflecting) wooden block that can be moved away by the magic ray of light. mirrormagic-3.0.0/docs/elements/em_key_1.txt0000644000175000017500000000012113263212010020311 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/switchgate_switch.txt0000644000175000017500000000022613263212010022351 0ustar aeglosaeglosThis is the switch for switching the switch gates. When you switch the switch that controls the switching of the switch gates... okay, I'll stop. :-) mirrormagic-3.0.0/docs/elements/balloon_switch_up.txt0000644000175000017500000000025113263212010022337 0ustar aeglosaeglosNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. mirrormagic-3.0.0/docs/elements/df_steel_wall.txt0000644000175000017500000000004413263212010021430 0ustar aeglosaeglosSteel walls reflect the laser beam. mirrormagic-3.0.0/docs/elements/mm_fuse.txt0000644000175000017500000000027613263212010020266 0ustar aeglosaeglosFuses will interrupt the magic power of Gregor McDuffin's ray of light if it points to them for too long. They have to be activated again to bring back the magic power for the ray of light. mirrormagic-3.0.0/docs/elements/mm_mcduffin.txt0000644000175000017500000000024613263212010021114 0ustar aeglosaeglosThis is our hero and magician Gregor McDuffin, who casts spells in the form of magic rays of light to collect all magic kettles (containing magic spell ingredients). mirrormagic-3.0.0/docs/elements/light_switch.txt0000644000175000017500000000024313263212010021315 0ustar aeglosaeglosTouching a light switch will make all invisible things visible for 10 seconds. The invisible things will still be easy to tell apart from visible things, however. mirrormagic-3.0.0/docs/elements/sp_electron.txt0000644000175000017500000000022013263212010021135 0ustar aeglosaeglosThe electron produces 9 infotrons when smashed, and is only deadly if you collide with it. It follows the *left* wall, just like the snik snak. mirrormagic-3.0.0/docs/elements/wall_emerald_purple.txt0000644000175000017500000000017113263212010022644 0ustar aeglosaeglosThis wall contains a purple emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/em_exit_open.txt0000644000175000017500000000053213263212010021301 0ustar aeglosaeglosThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. This exit disappears when the player is passing through it. mirrormagic-3.0.0/docs/elements/dc_gate_white_gray.txt0000644000175000017500000000015413263212010022436 0ustar aeglosaeglosGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/diamond.txt0000644000175000017500000000011613263212010020237 0ustar aeglosaeglosDiamonds are worth 3 gems, but unlike emeralds, they can be crushed by rocks. mirrormagic-3.0.0/docs/elements/emc_gate_5.txt0000644000175000017500000000044013263212010020614 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/sp_hardware_yellow.txt0000644000175000017500000000010513263212010022514 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/time_orb_empty.txt0000644000175000017500000000007413263212010021645 0ustar aeglosaeglosAn empty time orb behaves like a nut that can't be cracked. mirrormagic-3.0.0/docs/elements/sp_chip_bottom.txt0000644000175000017500000000005713263212010021641 0ustar aeglosaeglosThis is a normal, destructable, slippery wall. mirrormagic-3.0.0/docs/elements/emc_gate_6.txt0000644000175000017500000000044013263212010020615 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/sp_chip_left.txt0000644000175000017500000000005713263212010021267 0ustar aeglosaeglosThis is a normal, destructable, slippery wall. mirrormagic-3.0.0/docs/elements/mm_polarizer.txt0000644000175000017500000000013713263212010021327 0ustar aeglosaeglosThis polarizer can manually be rotated to let the ray of light pass into a certain angle only. mirrormagic-3.0.0/docs/elements/em_gate_1.txt0000644000175000017500000000044013263212010020445 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. mirrormagic-3.0.0/docs/elements/gate_4.txt0000644000175000017500000000010113263212010017761 0ustar aeglosaeglosYou may only walk over a colored door if you have the right key. mirrormagic-3.0.0/docs/elements/mm_polarizer_cross.txt0000644000175000017500000000014113263212010022533 0ustar aeglosaeglosThis polarizer can manually be rotated to let the ray of light pass into one of two angles only. mirrormagic-3.0.0/docs/elements/expandable_wall_horizontal.txt0000644000175000017500000000031513263212010024220 0ustar aeglosaeglosThis wall will grow on either side that is open. It will stop growing on one side if it is blocked by a wall, even if said wall is later destroyed. Gems and others, however, will stop it only temporarily. mirrormagic-3.0.0/docs/elements/time_orb_full.txt0000644000175000017500000000031513263212010021447 0ustar aeglosaeglosPressing against a time orb gives you ten extra units of time. Look out, however... in an untimed level, a time orb will give you 10 seconds/steps to complete the level! Orbs can fall and hurt the player. mirrormagic-3.0.0/docs/elements/key_3.txt0000644000175000017500000000025513263212010017642 0ustar aeglosaeglosYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. mirrormagic-3.0.0/docs/elements/emc_key_7.txt0000644000175000017500000000012113263212010020462 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/sokoban_field_player.txt0000644000175000017500000000032613263212010023002 0ustar aeglosaeglosThis is the player standing on a sokoban field. If a level contains *only* sokoban elements (those in the sokoban section, steel walls, and empty space), it will be completed as soon the sokoban puzzle is solved. mirrormagic-3.0.0/docs/elements/current_ce_score.txt0000644000175000017500000000034513263212010022154 0ustar aeglosaeglosThis can be used in custom element programming to refer to the CE score of the current element, but interpreted as an element itself (if the CE score was set to an element earlier). Don't use this element directly in your level. mirrormagic-3.0.0/docs/elements/nut.txt0000644000175000017500000000012113263212010017426 0ustar aeglosaeglosThis nut contains an emerald. To get it, crack the nut by dropping a rock on it. mirrormagic-3.0.0/docs/elements/sp_port_horizontal.txt0000644000175000017500000000003213263212010022560 0ustar aeglosaeglosThis port goes both ways. mirrormagic-3.0.0/docs/elements/mm_mirror_fixed.txt0000644000175000017500000000014713263212010022012 0ustar aeglosaeglosThis fixed mirror, held by a petrified gnome, reflects the magic ray of light into one direction only. mirrormagic-3.0.0/docs/elements/dynamite.active.txt0000644000175000017500000000010313263212010021704 0ustar aeglosaeglosAlready burning dynamite will explode in a few seconds. Stay away! mirrormagic-3.0.0/docs/elements/emc_key_8.txt0000644000175000017500000000012113263212010020463 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/dc_gate_white.txt0000644000175000017500000000021513263212010021412 0ustar aeglosaeglosYou may only walk over a white gate if you have collected a white key. For each time to pass a white gate, you need to collect a white key. mirrormagic-3.0.0/docs/elements/gate_3.txt0000644000175000017500000000010113263212010017760 0ustar aeglosaeglosYou may only walk over a colored door if you have the right key. mirrormagic-3.0.0/docs/elements/shield_deadly.txt0000644000175000017500000000057413263212010021426 0ustar aeglosaeglosThis not only makes the player invincible, but also allows him to kill enemies just by pressing against them. Extra deadly shields will add more time without wasting any time already acquired. Picking up a deadly shield when you already have a normal shield (or vice versa) will not waste the normal shield; the player will use the normal shield when the deadly shield runs out. mirrormagic-3.0.0/docs/elements/acid.txt0000644000175000017500000000041313263212010017524 0ustar aeglosaeglosThings that fall into acid will be destroyed. If the player touches acid from the bottom or sides, he will die (although acid tends to look ugly if not enclosed in a pool). Most animate objects have a checkbox that determines whether or not they will move into acid. mirrormagic-3.0.0/docs/elements/char.txt0000644000175000017500000000010513263212010017537 0ustar aeglosaeglosLetter walls are like normal walls, except they can spell out words. mirrormagic-3.0.0/docs/elements/gate_4_gray.txt0000644000175000017500000000015413263212010021013 0ustar aeglosaeglosGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/wall_crystal.txt0000644000175000017500000000016213263212010021325 0ustar aeglosaeglosThis wall contains a crystal which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/dynabomb_increase_power.txt0000644000175000017500000000070113263212010023504 0ustar aeglosaeglosDynabombs are an infinite supply of bombs that the player can drop at any time he doesn't have anything else to drop. They explode in a cross shaped pattern, and may have strange results when they kill enemies. (For example, Yam Yams will only give off the center element of their pattern.) This pickup allows Dynabomb explosions to destroy brick walls, rather than stopping at the first wall. Picking up 2 of these will only get you extra points. mirrormagic-3.0.0/docs/elements/dc_key_white.txt0000644000175000017500000000035313263212010021265 0ustar aeglosaeglosYou need a white key to pass through a white gate. For each time to pass a white gate, you need to collect another white key. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. mirrormagic-3.0.0/docs/elements/wall_bd_diamond.txt0000644000175000017500000000017513263212010021730 0ustar aeglosaeglosThis wall contains a (BD style) diamond which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/quicksand_empty.txt0000644000175000017500000000031213263212010022022 0ustar aeglosaeglosA rock that is pushed or thrown on the quicksand sinks into it, passes it and again leaves it if there is empty space below it. Amoeba can grow into it, but other elements and the player can't pass it. mirrormagic-3.0.0/docs/elements/mm_wooden_grid_fixed.txt0000644000175000017500000000015513263212010022777 0ustar aeglosaeglosThis is a fixed (non-reflecting) wooden polarizer that lets the ray of light pass into a certain angle only. mirrormagic-3.0.0/docs/elements/dark_yamyam.txt0000644000175000017500000000022313263212010021121 0ustar aeglosaeglosThe Dark Yam Yam doesn't contain anything, but it can devour just about anything, including dirt, gems, amoeba, enemies... and especially players! mirrormagic-3.0.0/docs/elements/bd_rock.txt0000644000175000017500000000016013263212010020226 0ustar aeglosaeglosThis is a BD style rock. It's not much different from a regular rock, but it can be jump-pushed by snapping it. mirrormagic-3.0.0/docs/elements/amoeba_full.txt0000644000175000017500000000021213263212010021067 0ustar aeglosaeglosWhen this amoeba is completely surrounded, it gradually turns into the specified content. All amoeba types must share the same settings. mirrormagic-3.0.0/docs/elements/dynabomb_increase_size.txt0000644000175000017500000000063213263212010023325 0ustar aeglosaeglosDynabombs are an infinite supply of bombs that the player can drop at any time he doesn't have anything else to drop. They explode in a cross shaped pattern, and may have strange results when they kill enemies. (For example, Yam Yams will only give off the center element of their pattern.) This pickup increases the length of the explosion. At first, the explosion only reaches one square in each direction. mirrormagic-3.0.0/docs/elements/robot.txt0000644000175000017500000000034013263212010017750 0ustar aeglosaeglosRobots try to follow the player everywhere, taking the direct route. They're not very bright. Touching them for a short time (running side by side to them, for example) is not deadly, but don't let them run into the player! mirrormagic-3.0.0/docs/elements/acid_pool_bottomright.txt0000644000175000017500000000012013263212010023172 0ustar aeglosaeglosAcid pool walls are equivalent to steel walls, except some of them are rounded. mirrormagic-3.0.0/docs/elements/emc_key_5.txt0000644000175000017500000000012113263212010020460 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/penguin.txt0000644000175000017500000000051613263212010020275 0ustar aeglosaeglosPenguins follow the player as best they can. If they are next to an open exit, they will leave the level. All the penguins *must* exit before the player exits, or the player will not win the level. If a penguin is smashed, it'll produce one purple gem, but the level will then be unsolvable. Penguins can collect gems for the player. mirrormagic-3.0.0/docs/elements/sp_hardware_base_6.txt0000644000175000017500000000010513263212010022340 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/bd_magic_wall.txt0000644000175000017500000000056113263212010021374 0ustar aeglosaeglosThis is a (BD style) magic wall. It gets activated for about 10 seconds by rocks or gems that fall on it. Rocks that fall through it become BD style diamonds, and gems that fall through it become BD style rocks. After it has stopped running, it cannot be activated again. All BD magic walls run on the same timer; however, regular magic walls run on a seperate timer. mirrormagic-3.0.0/docs/elements/dc_magic_wall.txt0000644000175000017500000000062613263212010021377 0ustar aeglosaeglosThis is a (DC style) magic wall. It gets activated for a limited time by rocks or gems that fall on it. Objects falling though it will be changed to other objects. After it has stopped running, it cannot be activated again. The duration is expressed in seconds. A duration of zero will let the wall run forever. All regular magic walls run together; however, BD style magic walls have a separate counter. mirrormagic-3.0.0/docs/elements/em_exit_closed.txt0000644000175000017500000000031013263212010021603 0ustar aeglosaeglosThe exit of each level stays closed until enough emeralds have been collected by the player. Some levels also require some special switches (light bulbs, for example) to be activated before it opens. mirrormagic-3.0.0/docs/elements/envelope.txt0000644000175000017500000000020013263212010020433 0ustar aeglosaeglosEnvelopes can be configured to contain a text message for the player. All envelopes of the same color contain the same message. mirrormagic-3.0.0/docs/elements/sp_hardware_blue.txt0000644000175000017500000000010513263212010022130 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/sp_gravity_on_port.txt0000644000175000017500000000014413263212010022554 0ustar aeglosaeglosThese ports look like ordinary ports in-game, but when you go through them, gravity is switched on. mirrormagic-3.0.0/docs/elements/invisible_wall.txt0000644000175000017500000000022113263212010021624 0ustar aeglosaeglosAn invisible wall behaves exactly like a normal wall, but is invisible. It can be made visible for a short time by activating the light switch. mirrormagic-3.0.0/docs/elements/sp_hardware_base_1.txt0000644000175000017500000000010513263212010022333 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/mm_bomb.txt0000644000175000017500000000012713263212010020236 0ustar aeglosaeglosBombs will kill Gregor McDuffin if the magic ray of light points to them for too long. mirrormagic-3.0.0/docs/elements/wall_diamond.txt0000644000175000017500000000016213263212010021257 0ustar aeglosaeglosThis wall contains a diamond which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/extra_time.txt0000644000175000017500000000015613263212010020771 0ustar aeglosaeglosYou pick it up, it gives you 10 more units of time. It has no effect in an untimed level (other than points). mirrormagic-3.0.0/docs/elements/mole.txt0000644000175000017500000000040313263212010017557 0ustar aeglosaeglosThe mole moves like a Yam Yam, except it doesn't pause before changing direction. The mole will not harm the player, but it can trap him. The mole leaves behind dirt wherever it goes, and it can dig through amoeba. If crushed, it will produce 9 red emeralds. mirrormagic-3.0.0/docs/elements/gate_1.txt0000644000175000017500000000010113263212010017756 0ustar aeglosaeglosYou may only walk over a colored door if you have the right key. mirrormagic-3.0.0/docs/elements/any_element.txt0000644000175000017500000000011413263212010021122 0ustar aeglosaeglosThis is a reference element that matches all (standard or custom) elements. mirrormagic-3.0.0/docs/elements/lamp.active.txt0000644000175000017500000000015213263212010021027 0ustar aeglosaeglosAlready on lightbulbs can be safely shattered with rocks, without ruining your ability to exit the level. mirrormagic-3.0.0/docs/elements/pig.txt0000644000175000017500000000032413263212010017404 0ustar aeglosaeglosThe pig follows a wall, but it will switch from side to side or even corner to corner if it is in a small corridor. The pig will steal any gems it gets its hands on. You can walk over the pig if it's not moving. mirrormagic-3.0.0/docs/elements/mm_fuel.txt0000644000175000017500000000017713263212010020257 0ustar aeglosaeglosThis extra energy ball gives some extra power for Gregor McDuffin's magic ray of light. There are full and empty energy balls. mirrormagic-3.0.0/docs/elements/steel_char.txt0000644000175000017500000000012113263212010020731 0ustar aeglosaeglosSteel letter walls are like normal steel walls, except they can spell out words. mirrormagic-3.0.0/docs/elements/amoeba_dead.txt0000644000175000017500000000022113263212010021022 0ustar aeglosaeglosDead ameoba won't grow, but it still retains its enemy-killing powers. It is often used as a wall that needs to be cleared by bugs, pacmen, etc. mirrormagic-3.0.0/docs/elements/sp_hardware_base_5.txt0000644000175000017500000000010513263212010022337 0ustar aeglosaeglosAn indestructable, flat wall. Nothing's getting through this sucker. mirrormagic-3.0.0/docs/elements/sp_gravity_port.txt0000644000175000017500000000015313263212010022060 0ustar aeglosaeglosThese ports look like ordinary ports in-game, but when you go through them, gravity is toggled on and off. mirrormagic-3.0.0/docs/elements/expandable_wall_vertical.txt0000644000175000017500000000032713263212010023643 0ustar aeglosaeglosThis wall will grow on the top and bottom if unobstructed. It will stop growing on one side if it is blocked by a wall, even if said wall is later destroyed. Gems and others, however, will stop it only temporarily. mirrormagic-3.0.0/docs/elements/df_steel_grid_fixed.txt0000644000175000017500000000015013263212010022573 0ustar aeglosaeglosThis is a fixed (reflecting) steel polarizer that lets the ray of light pass into a certain angle only. mirrormagic-3.0.0/docs/elements/balloon_switch_down.txt0000644000175000017500000000025113263212010022662 0ustar aeglosaeglosNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. mirrormagic-3.0.0/docs/elements/acid_pool_bottomleft.txt0000644000175000017500000000012013263212010023007 0ustar aeglosaeglosAcid pool walls are equivalent to steel walls, except some of them are rounded. mirrormagic-3.0.0/docs/elements/key_2.txt0000644000175000017500000000025513263212010017641 0ustar aeglosaeglosYou need a key of the right color to pass through a colored door. Keys are unaffected by gravity and block enemies. Extra keys of a single color are only worth more points. mirrormagic-3.0.0/docs/elements/dynabomb_increase_number.txt0000644000175000017500000000073213263212010023644 0ustar aeglosaeglosDynabombs are an infinite supply of bombs that the player can drop at any time he doesn't have anything else to drop. They explode in a cross shaped pattern, and may have strange results when they kill enemies. (For example, Yam Yams will only give off the center element of their pattern.) This pick-up will increase the number of Dynabombs the player can put on the field at one time. This number starts at zero, so the player must pick up one of these to use Dynabombs. mirrormagic-3.0.0/docs/elements/trigger_element.txt0000644000175000017500000000024113263212010021777 0ustar aeglosaeglosThis can be used in custom element programming to refer to the element that triggered the change being processed. Don't use this element directly in your level. mirrormagic-3.0.0/docs/elements/mm_wooden_lock.txt0000644000175000017500000000017513263212010021625 0ustar aeglosaeglosThis is a (non-reflecting) wooden lock that will be vaporized by the magic ray of light if a key was collected by it before. mirrormagic-3.0.0/docs/elements/mm_pacman.txt0000644000175000017500000000011013263212010020546 0ustar aeglosaeglosThe pacmen move around, trying to eat all kettles and all amoeba walls. mirrormagic-3.0.0/docs/elements/balloon_switch_none.txt0000644000175000017500000000025213263212010022653 0ustar aeglosaeglosPressing this switch will turn the wind off, stopping all moving balloons or other elements that are affected by wind (like custom elements that move in wind direction). mirrormagic-3.0.0/docs/elements/unused.txt0000644000175000017500000000002013263212010020121 0ustar aeglosaeglosUnused element. mirrormagic-3.0.0/docs/elements/mm_wooden_wall.txt0000644000175000017500000000004613263212010021631 0ustar aeglosaeglosWooden walls absorb the ray of light. mirrormagic-3.0.0/docs/elements/switchgate.txt0000644000175000017500000000025213263212010020767 0ustar aeglosaeglosSwitch gates can be passed through like ports or doors when they are open. When a switch gate switch is switched (switch!), *all* switch gates on the level toggle state. mirrormagic-3.0.0/docs/elements/arrow_right.txt0000644000175000017500000000012413263212010021152 0ustar aeglosaeglosThis acts as an average wall. Although it looks round, objects do not slide off it. mirrormagic-3.0.0/docs/elements/emc_gate_6_gray.txt0000644000175000017500000000061513263212010021643 0ustar aeglosaeglosEmerald Mine doors will fling you to the other side of the door, rather than letting you stand on it. If there is *any* object on the other side, the player cannot pass through the door. Note that creators may allow players to pass to anything walkable under the player object's options. Gray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. mirrormagic-3.0.0/docs/elements/pacman.txt0000644000175000017500000000013613263212010020065 0ustar aeglosaeglosPacman moves like a Yam Yam, but doesn't contain anything. However, it is able to eat amoeba. mirrormagic-3.0.0/docs/elements/wall_emerald_yellow.txt0000644000175000017500000000017113263212010022650 0ustar aeglosaeglosThis wall contains a yellow emerald which can be freed by blowing up the wall with dynamite, bombs or exploding enemies. mirrormagic-3.0.0/docs/elements/balloon_switch_left.txt0000644000175000017500000000025113263212010022645 0ustar aeglosaeglosNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. mirrormagic-3.0.0/docs/elements/dragon.txt0000644000175000017500000000047413263212010020105 0ustar aeglosaeglosThe fearsome dragon is completely harmless to the player; even their firey breath won't faze him. Dragons wander about aimlessly and will breathe fire if they aren't trapped, producing effects similar to explosions. Getting them to do something useful can be quite a challenge in a space bigger than 4 or 5 squares. mirrormagic-3.0.0/docs/elements/amoeba_dry.txt0000644000175000017500000000051513263212010020731 0ustar aeglosaeglosThis is regular amoeba. If, when it attempt to grow, it is blocked in all directions by something other than the player, it will die. Amoeba will kill any bugs, flies, or spaceships that touch it. The amoeba growth value is the same for all types of amoeba. Amoeba will take between 0 and [25/(1-value)] seconds to attempt to grow. mirrormagic-3.0.0/docs/elements/dc_landmine.txt0000644000175000017500000000026013263212010021061 0ustar aeglosaeglosIf you run into a land mine, you die. This type of land mine can be removed by snapping. Otherwise, it's a normal, destructible wall that just happens to look kinda like dirt. mirrormagic-3.0.0/docs/elements/mm_key.txt0000644000175000017500000000012413263212010020104 0ustar aeglosaeglosThis is a key that can be collected by the magic ray of light to later open a lock. mirrormagic-3.0.0/docs/elements/invisible_steelwall.txt0000644000175000017500000000023513263212010022666 0ustar aeglosaeglosAn invisible steel wall behaves exactly like a normal steel wall, but is invisible. It can be made visible for a short time by activating the light switch. mirrormagic-3.0.0/docs/elements/sp_disk_red.txt0000644000175000017500000000004213263212010021110 0ustar aeglosaeglosRed disks are just like dynamite. mirrormagic-3.0.0/docs/elements/exit_open.txt0000644000175000017500000000043513263212010020622 0ustar aeglosaeglosThe open exit lets the player leave a level. Some levels also require the player to guide some friends (penguins, for example) to the exit. In these levels, the player can leave through the exit, but the level is not solved before the last friend also left the level through the exit. mirrormagic-3.0.0/docs/elements/spring.txt0000644000175000017500000000021513263212010020126 0ustar aeglosaeglosOnce you push a spring, it will keep on going in that direction until it falls or hits a wall. It isn't slippery, and will crush the player. mirrormagic-3.0.0/docs/elements/custom.txt0000644000175000017500000000106613263212010020143 0ustar aeglosaeglosCustom elements can be configured to have user-defined properties, to behave in their own special way, to interact with other elements, to change their behaviour on certain conditions (by changing into other custom elements with different properties) or to trigger actions that influence the game. Each level has its own set of custom elements. To use the same custom elements within one level set, use the "copy and paste" functions or use "save as template" and "use template" to use the same custom elements from a single level template for all levels of a set. mirrormagic-3.0.0/docs/elements/arrow_up.txt0000644000175000017500000000012413263212010020461 0ustar aeglosaeglosThis acts as an average wall. Although it looks round, objects do not slide off it. mirrormagic-3.0.0/docs/elements/player_4.txt0000644000175000017500000000002213263212010020337 0ustar aeglosaeglosThis is player 4. mirrormagic-3.0.0/docs/elements/group.txt0000644000175000017500000000045613263212010017767 0ustar aeglosaeglosGroup elements are perhaps best described as groups *of* elements. When the level starts, they will be replaced with the elements in the group from left to right, and top to bottom, in a manner chosen in the element. Most useful is the random option; this can make your levels be different every time! mirrormagic-3.0.0/docs/elements/em_key_2.txt0000644000175000017500000000012113263212010020312 0ustar aeglosaeglosEmerald Mine style keys are identical to regular keys. They just look different. mirrormagic-3.0.0/docs/elements/bd_wall.txt0000644000175000017500000000025413263212010020233 0ustar aeglosaeglosThis is the BD style wall. Unlike most other walls, falling objects slip off this wall, although it does not look rounded or crumbled. It can be destroyed by explosions. mirrormagic-3.0.0/docs/elements/dc_gate_fake_gray.txt0000644000175000017500000000025513263212010022226 0ustar aeglosaeglosGray doors' real colors are kept hidden to the player, making him/her guess which color key opens the door. This door is special in that there is no key at all to open it. mirrormagic-3.0.0/docs/elements/sp_disk_yellow.txt0000644000175000017500000000025013263212010021652 0ustar aeglosaeglosYellow disks can be pushed around in any direction, and do not fall. They won't explode until a terminal is pressed, unless they are caught in an explosion themselves. mirrormagic-3.0.0/docs/elements/next_ce.txt0000644000175000017500000000026413263212010020255 0ustar aeglosaeglosIf you use this reference element, it will be replaced by the custom element that is at a later position in the element list (with the distance as shown by the reference element). mirrormagic-3.0.0/docs/elements/sp_chip_single.txt0000644000175000017500000000005713263212010021616 0ustar aeglosaeglosThis is a normal, destructable, slippery wall. mirrormagic-3.0.0/docs/elements/mm_teleporter.txt0000644000175000017500000000011313263212010021477 0ustar aeglosaeglosTeleporters can transfer the ray of light to their twin of the same color. mirrormagic-3.0.0/docs/elements/balloon_switch_right.txt0000644000175000017500000000025113263212010023030 0ustar aeglosaeglosNo matter from which direction you push this wind switch, the balloons and all other elements affected by wind direction will only move to the indicated wind direction. mirrormagic-3.0.0/build-scripts/0000755000175000017500000000000013263212010016105 5ustar aeglosaeglosmirrormagic-3.0.0/build-scripts/create_element_defs.pl0000755000175000017500000015526113263212010022434 0ustar aeglosaeglos#!/usr/bin/perl -w # ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1995-2014 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # create_element_defs.pl # ============================================================================= use strict; # ============================================================================= # C O N F I G U R A T I O N S E C T I O N # ============================================================================= my $base_path = "."; my $src_path = "$base_path/src"; if (-d "../src") # we're already inside "src" directory { $src_path = "."; } # ----------------------------------------------------------------------------- # global variables # ----------------------------------------------------------------------------- my $filename_header_tmpl = "$src_path/header.tmpl"; my $filename_conf_gfx_h = 'conf_gfx.h'; my $filename_conf_snd_h = 'conf_snd.h'; my $filename_conf_mus_h = 'conf_mus.h'; my $filename_conf_chr_c = 'conf_chr.c'; my $filename_conf_chr_h = 'conf_chr.h'; my $filename_conf_cus_c = 'conf_cus.c'; my $filename_conf_cus_h = 'conf_cus.h'; my $filename_conf_grp_c = 'conf_grp.c'; my $filename_conf_grp_h = 'conf_grp.h'; my $filename_conf_e2g_c = 'conf_e2g.c'; my $filename_conf_esg_c = 'conf_esg.c'; my $filename_conf_e2s_c = 'conf_e2s.c'; my $filename_conf_fnt_c = 'conf_fnt.c'; my $filename_conf_g2s_c = 'conf_g2s.c'; my $filename_conf_g2m_c = 'conf_g2m.c'; my $filename_conf_var_c = 'conf_var.c'; my $filename_conf_act_c = 'conf_act.c'; my $text_auto = 'this file was automatically generated -- do not edit by hand'; my $text_gfx_h = 'values for graphics configuration (normal elements)'; my $text_snd_h = 'values for sounds configuration'; my $text_mus_h = 'values for music configuration'; my $text_chr_c = 'values for graphics configuration (character elements)'; my $text_chr_h = 'values for elements configuration (character elements)'; my $text_cus_c = 'values for graphics configuration (custom elements)'; my $text_cus_h = 'values for elements configuration (custom elements)'; my $text_grp_c = 'values for graphics configuration (group elements)'; my $text_grp_h = 'values for elements configuration (group elements)'; my $text_e2g_c = 'values for element/graphics mapping configuration (normal)'; my $text_esg_c = 'values for element/graphics mapping configuration (special)'; my $text_e2s_c = 'values for element/sounds mapping configuration'; my $text_fnt_c = 'values for font/graphics mapping configuration'; my $text_g2s_c = 'values for gamemode/sound mapping configuration'; my $text_g2m_c = 'values for gamemode/music mapping configuration'; my $text_var_c = 'values for image and layout parameter configuration'; my $text_act_c = 'values for active states of elements and fonts'; my $num_custom_elements = 256; my $num_group_elements = 32; my $char_skip = '---[SKIP]---'; my @chars = ( 'SPACE', 'EXCLAM', 'QUOTEDBL', 'NUMBERSIGN', 'DOLLAR', 'PERCENT', 'AMPERSAND', 'APOSTROPHE', 'PARENLEFT', 'PARENRIGHT', 'ASTERISK', 'PLUS', 'COMMA', 'MINUS', 'PERIOD', 'SLASH', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'COLON', 'SEMICOLON', 'LESS', 'EQUAL', 'GREATER', 'QUESTION', 'AT', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'BRACKETLEFT', 'BACKSLASH', 'BRACKETRIGHT', 'ASCIICIRCUM', 'UNDERSCORE', 'COPYRIGHT', 'AUMLAUT', 'OUMLAUT', 'UUMLAUT', 'DEGREE', 'TRADEMARK', 'CURSOR', $char_skip, $char_skip, $char_skip, $char_skip, $char_skip, $char_skip, 'BUTTON', 'UP', 'DOWN', ); # ----------------------------------------------------------------------------- # start main program # ----------------------------------------------------------------------------- main(); exit 0; # ============================================================================= # F U N C T I O N S # ============================================================================= sub error { my ($error_msg) = @_; print STDERR "ERROR: "; print STDERR "$error_msg\n"; } sub fail { my ($error_msg) = @_; print STDERR "FATAL "; error("$error_msg"); exit 1; } sub contains_image_file { my ($line) = @_; return ($line =~ /\".+\.png\"/ || $line =~ /UNDEFINED_FILENAME/); } sub contains_sound_file { my ($line) = @_; return ($line =~ /\".+\.wav\"/ || $line =~ /UNDEFINED_FILENAME/); } sub contains_music_file { my ($line) = @_; return ($line =~ /\".+\.wav\"/ || $line =~ /\".+\.mod\"/ || $line =~ /\".+\.mp3\"/ || $line =~ /UNDEFINED_FILENAME/); } sub print_file_header { my ($filename, $comment) = @_; my $filename_tmpl = 'xxxxxxxx.x'; my $filename_text = $filename; my $filename_def = uc($filename); $filename_def =~ s/\./_/; $filename_text .= ' ' x (length($filename_tmpl) - length($filename_text)); open(FILE, "$filename_header_tmpl") || fail("cannot open file '$filename_header_tmpl' for reading"); while () { s/$filename_tmpl/$filename_text/; print; } close FILE; print "\n"; print "/* ----- $text_auto ----- */\n"; print "\n"; print "#ifndef $filename_def\n"; print "#define $filename_def\n"; print "\n"; print "/* $comment */\n"; print "\n"; } sub print_file_footer { my ($filename) = @_; my $filename_def = uc($filename); $filename_def =~ s/\./_/; print "\n"; print "#endif /* $filename_def */\n"; } sub get_tabs { my ($text, $max_num_tabs) = @_; my $num_tabs = $max_num_tabs - int(length($text) / 8); if ($num_tabs < 1) # at least one tab needed as separator { $num_tabs = 1; } return "\t" x $num_tabs; } sub print_graphics_list { my $filename = "$src_path/conf_gfx.c"; print_file_header($filename_conf_gfx_h, $text_gfx_h); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); my $max_num_tabs = 7; my $i = 0; while () { chomp; # cut trailing newline if (/^\#include "conf_chr.c"/) # dump list of character elements { foreach my $char (@chars) { my $prefix = $char; $prefix =~ s/^/#define IMG_CHAR_/; my $tabs = get_tabs($prefix, $max_num_tabs); if ($char ne $char_skip) { print "$prefix$tabs$i\n"; $i++; } if (lc($char) eq 'space') { $prefix =~ s/$/_EDITOR/; my $tabs = get_tabs($prefix, $max_num_tabs); print "$prefix$tabs$i\n"; $i++; } } foreach my $char (@chars) { my $prefix = $char; $prefix =~ s/^/#define IMG_STEEL_CHAR_/; my $tabs = get_tabs($prefix, $max_num_tabs); if ($char ne $char_skip) { print "$prefix$tabs$i\n"; $i++; } if (lc($char) eq 'space') { $prefix =~ s/$/_EDITOR/; my $tabs = get_tabs($prefix, $max_num_tabs); print "$prefix$tabs$i\n"; $i++; } } } if (/^\#include "conf_cus.c"/) # dump list of custom elements { for (my $nr = 0; $nr < $num_custom_elements; $nr++) { my $line = sprintf("#define IMG_CUSTOM_%d", $nr + 1); my $tabs = get_tabs($line, $max_num_tabs); print "$line$tabs$i\n"; $i++; $line = sprintf("#define IMG_CUSTOM_%d_EDITOR", $nr + 1); $tabs = get_tabs($line, $max_num_tabs); print "$line$tabs$i\n"; $i++; } } if (/^\#include "conf_grp.c"/) # dump list of group elements { for (my $nr = 0; $nr < $num_group_elements; $nr++) { my $line = sprintf("#define IMG_GROUP_%d", $nr + 1); my $tabs = get_tabs($line, $max_num_tabs); print "$line$tabs$i\n"; $i++; $line = sprintf("#define IMG_GROUP_%d_EDITOR", $nr + 1); $tabs = get_tabs($line, $max_num_tabs); print "$line$tabs$i\n"; $i++; } } if (!contains_image_file($_)) # skip all lines without image file { next; } s/(.*)/uc($1)/eg; # convert all characters to upper case s/\./_/g; # replace all '.' with '_' s/^ \{ \"/#define IMG_/; # convert line s/\",.*$//; # convert line # dirty hack for making "ABC[DEF]" work as a "special" suffix s/([^_])\[/$1_/; # dirty hack for making "[default]" work as an element name s/\[//; s/\]//; my $tabs = get_tabs($_, $max_num_tabs); print "$_$tabs$i\n"; $i++; } my $summary = '#define NUM_IMAGE_FILES'; my $tabs = get_tabs($summary, $max_num_tabs); print "\n$summary$tabs$i\n"; close FILE; print_file_footer($filename_conf_gfx_h); } sub print_sounds_list { my %known_element = get_known_element_definitions(); my $filename = "$src_path/conf_snd.c"; print_file_header($filename_conf_snd_h, $text_snd_h); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); my $max_num_tabs = 7; my $i = 0; while () { chomp; # cut trailing newline if (!contains_sound_file($_)) # skip all lines without sound file { next; } if (/\[not used\]/ || / TEST / || /wav[^\}]*$/) # skip all lines without sound file { next; } s/(.*)/uc($1)/eg; # convert all characters to upper case s/\./_/g; # replace all '.' with '_' s/^ \{ \"//; s/\",.*$//; my $sound = $_; if ($sound =~ /^\[.+\]/) { $sound =~ s/\[//; # element class sound; begin ... $sound =~ s/\]//; # ... and end of definition token $sound =~ s/^/CLASS_/; # add class identifier } $sound = "SND_$sound"; my $define_text = "#define $sound"; my $tabs = get_tabs($define_text, $max_num_tabs); print "$define_text$tabs$i\n"; $i++; } my $summary = '#define NUM_SOUND_FILES'; my $tabs = get_tabs($summary, $max_num_tabs); print "\n$summary$tabs$i\n"; close FILE; print_file_footer($filename_conf_snd_h); } sub print_music_list { my %known_prefix = get_known_music_prefix_definitions(); my $filename = "$src_path/conf_mus.c"; print_file_header($filename_conf_mus_h, $text_mus_h); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); my $max_num_tabs = 7; my $i = 0; while () { chomp; # cut trailing newline if (!contains_music_file($_)) # skip all lines without music file { next; } if (/\[not used\]/ || / TEST / || /wav[^\}]*$/) # skip all lines without music file { next; } s/(.*)/uc($1)/eg; # convert all characters to upper case s/\./_/g; # replace all '.' with '_' s/^ \{ \"//; s/\",.*$//; my $music = $_; $music = "MUS_$music"; my $define_text = "#define $music"; my $tabs = get_tabs($define_text, $max_num_tabs); print "$define_text$tabs$i\n"; $i++; } my $summary = '#define NUM_MUSIC_FILES'; my $tabs = get_tabs($summary, $max_num_tabs); print "\n$summary$tabs$i\n"; close FILE; print_file_footer($filename_conf_mus_h); } sub print_chars_elements_list { print_file_header($filename_conf_chr_h, $text_chr_h); my $i = 0; foreach my $char (@chars) { my $left = "#define EL_CHAR_$char"; my $tabs_left = get_tabs($left, 5); my $right = sprintf("(EL_CHAR_ASCII0 + %d)", $i + 32); if ($char ne $char_skip) { print "$left$tabs_left$right\n"; } $i++; } $i = 0; foreach my $char (@chars) { my $left = "#define EL_STEEL_CHAR_$char"; my $tabs_left = get_tabs($left, 5); my $right = sprintf("(EL_STEEL_CHAR_ASCII0 + %d)", $i + 32); if ($char ne $char_skip) { print "$left$tabs_left$right\n"; } $i++; } print_file_footer($filename_conf_chr_c); } sub print_chars_graphics_list_line { my ($token, $x, $y) = @_; my @extensions = ( '', '.xpos', '.ypos', '.frames', ); my $basename = ($token =~ /^steel_char/ ? 'RocksFontDC' : 'RocksFontEM' ); foreach my $ext (@extensions) { my $left = " \{ \"$token$ext\","; my $tabs_left = get_tabs($left, 6); my $right = ($ext eq '' ? $basename . '.png' : $ext eq '.frames' ? '1' : '0'); if ($ext eq '.xpos') { $right = $x; } elsif ($ext eq '.ypos') { $right = $y; } $right = "\"$right\""; my $tabs_right = get_tabs($right, 3); print "$left$tabs_left$right$tabs_right},\n"; } } sub print_chars_graphics_list { print_file_header($filename_conf_chr_c, $text_chr_c); my $i = 0; foreach my $char (@chars) { if ($char ne $char_skip) { my $x = $i % 16; my $y = int($i / 16); print_chars_graphics_list_line(lc("char_$char"), $x, $y); } if (lc($char) eq 'space') { print_chars_graphics_list_line("char_space.EDITOR", 7, 4); } if ($char ne $char_skip) { print "\n"; } $i++; } $i = 0; foreach my $char (@chars) { if ($char ne $char_skip) { my $x = $i % 16; my $y = int($i / 16); print_chars_graphics_list_line(lc("steel_char_$char"), $x, $y); } if (lc($char) eq 'space') { print_chars_graphics_list_line("steel_char_space.EDITOR", 7, 4); } if ($char ne $char_skip) { print "\n"; } $i++; } print_file_footer($filename_conf_chr_c); } sub print_custom_elements_list { print_file_header($filename_conf_cus_h, $text_cus_h); for (my $i = 0; $i < $num_custom_elements; $i++) { my $left = sprintf("#define EL_CUSTOM_%d", $i + 1); my $tabs_left = get_tabs($left, 5); my $right = "(EL_CUSTOM_START + $i)"; print "$left$tabs_left$right\n"; } print_file_footer($filename_conf_cus_c); } sub print_group_elements_list { print_file_header($filename_conf_grp_h, $text_grp_h); for (my $i = 0; $i < $num_group_elements; $i++) { my $left = sprintf("#define EL_GROUP_%d", $i + 1); my $tabs_left = get_tabs($left, 5); my $right = "(EL_GROUP_START + $i)"; print "$left$tabs_left$right\n"; } print_file_footer($filename_conf_grp_c); } sub print_custom_graphics_list { my @extensions1 = ( '', '.xpos', '.ypos', '.frames', ); my @extensions2 = ( '', '.xpos', '.ypos', ); print_file_header($filename_conf_cus_c, $text_cus_c); for (my $i = 0; $i < $num_custom_elements; $i++) { foreach my $ext (@extensions1) { my $left = sprintf(" \{ \"custom_%d$ext\",", $i + 1); my $tabs_left = get_tabs($left, 6); # my $right = ($ext eq '' ? 'RocksElements.png' : my $right = ($ext eq '' ? 'RocksCE.png' : $ext eq '.frames' ? '1' : '0'); if ($ext eq '.xpos') { # $right = 7; $right = int($i % 16); } elsif ($ext eq '.ypos') { # $right = 9; $right = int($i / 16); } $right = "\"$right\""; my $tabs_right = get_tabs($right, 3); print "$left$tabs_left$right$tabs_right},\n"; } foreach my $ext (@extensions2) { my $left = sprintf(" \{ \"custom_%d.EDITOR$ext\",", $i + 1); my $tabs_left = get_tabs($left, 6); # my $right = ($ext eq '' ? 'RocksElements.png' : '0'); my $right = ($ext eq '' ? 'RocksCE.png' : '0'); if ($ext eq '.xpos') { # $right = 15; $right = int($i % 16) + 16; } elsif ($ext eq '.ypos') { # $right = 13; $right = int($i / 16); } $right = "\"$right\""; my $tabs_right = get_tabs($right, 3); print "$left$tabs_left$right$tabs_right},\n"; } print "\n"; } print_file_footer($filename_conf_cus_c); } sub print_group_graphics_list { my @extensions1 = ( '', '.xpos', '.ypos', '.frames', ); my @extensions2 = ( '', '.xpos', '.ypos', ); print_file_header($filename_conf_grp_c, $text_grp_c); for (my $i = 0; $i < $num_group_elements; $i++) { foreach my $ext (@extensions1) { my $left = sprintf(" \{ \"group_%d$ext\",", $i + 1); my $tabs_left = get_tabs($left, 6); # my $right = ($ext eq '' ? 'RocksDC.png' : my $right = ($ext eq '' ? 'RocksCE.png' : $ext eq '.frames' ? '1' : '0'); if ($ext eq '.xpos') { # $right = 4; $right = int($i % 16); } elsif ($ext eq '.ypos') { # $right = 15; $right = int($i / 16) + int($num_custom_elements / 16); } $right = "\"$right\""; my $tabs_right = get_tabs($right, 3); print "$left$tabs_left$right$tabs_right},\n"; } foreach my $ext (@extensions2) { my $left = sprintf(" \{ \"group_%d.EDITOR$ext\",", $i + 1); my $tabs_left = get_tabs($left, 6); # my $right = ($ext eq '' ? 'RocksDC.png' : '0'); my $right = ($ext eq '' ? 'RocksCE.png' : '0'); if ($ext eq '.xpos') { # $right = 14; $right = int($i % 16) + 16; } elsif ($ext eq '.ypos') { # $right = 15; $right = int($i / 16) + int($num_custom_elements / 16); } $right = "\"$right\""; my $tabs_right = get_tabs($right, 3); print "$left$tabs_left$right$tabs_right},\n"; } print "\n"; } print_file_footer($filename_conf_grp_c); } sub get_known_element_definitions_ALTERNATIVE { my %known_element = (); my $filename = "$src_path/main.h"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); while () { chomp; # cut trailing newline # process line with element definition if (/^\#define (EL_[A-Z0-9_]+)\s/) { $known_element{$1} = 1; # print STDERR "known_element: '$1'\n"; } } close FILE; return %known_element; } sub get_known_element_definitions { my %known_element = (); my $filename = "$src_path/main.c"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); my $element_name = ''; my $line_is_element_name = 0; my $skip_line = 1; while () { chomp; # cut trailing newline if (/ELEMENT_INFO_START/) # keyword to start parsing file { $skip_line = 0; next; } elsif (/ELEMENT_INFO_END/) # keyword to stop parsing file { last; } elsif ($skip_line) { next; } if (/^\s+\{\s*$/) { $line_is_element_name = 1; } elsif ($line_is_element_name) { # process line with element name definition if (/^\s+\"(.+)\",?\s*$/) { $element_name = 'EL_' . uc($1); # dirty hack for making "[default]" work as an element name $element_name =~ s/\[//; $element_name =~ s/\]//; # change '.' to '_' for elements like "dynamite.active" $element_name =~ s/\./_/g; $known_element{$element_name} = 1; # printf STDERR "::: known element '$element_name'\n"; } $line_is_element_name = 0; } } close FILE; return %known_element; } sub get_known_element_class_definitions { my %known_element_class = (); my $filename = "$src_path/main.c"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); my $element_name = ''; my $element_class = ''; my $line_is_element_name = 0; my $line_is_element_class = 0; my $skip_line = 1; while () { chomp; # cut trailing newline if (/ELEMENT_INFO_START/) # keyword to start parsing file { $skip_line = 0; next; } elsif (/ELEMENT_INFO_END/) # keyword to stop parsing file { last; } elsif ($skip_line) { next; } if (/^\s+\{\s*$/) { $line_is_element_name = 1; } elsif ($line_is_element_name) { # process line with element name definition if (/^\s+\"(.+)\",?\s*$/) { $element_name = 'EL_' . uc($1); # dirty hack for making "[default]" work as an element name $element_name =~ s/\[//; $element_name =~ s/\]//; # change '.' to '_' for elements like "dynamite.active" $element_name =~ s/\./_/g; } $line_is_element_name = 0; $line_is_element_class = 1; } elsif ($line_is_element_class) { # process line with element class definition if (/^\s+\"(.+)\",?\s*$/) { $element_class = 'EL_CLASS_' . uc($1); if (!defined($known_element_class{$element_class})) { $known_element_class{$element_class} = $element_name; } $known_element_class{$element_name} = $element_class; # print STDERR "known_element_class: '$element_name' => '$element_class'\n"; } $line_is_element_class = 0; } } close FILE; return %known_element_class; } sub get_known_action_definitions { my %known_action = (); my $filename = "$src_path/main.h"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); while () { chomp; # cut trailing newline # process line with action definition if (/^\#define ACTION_([A-Z0-9_]+)\s/) { $known_action{$1} = 1; # print STDERR "known_action: '$1'\n"; } } close FILE; return %known_action; } sub get_known_special_arg_definitions { my %known_special_arg = (); my $filename = "$src_path/main.h"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); while () { chomp; # cut trailing newline # process line with special arg definition if (/^\#define GFX_SPECIAL_ARG_([A-Z0-9_]+)\s/) { if ($1 eq 'CRUMBLED') { next; } $known_special_arg{$1} = 1; # print STDERR "known_special_arg: '$1'\n"; } } close FILE; return %known_special_arg; } sub get_known_button_definitions { my %known_button = (); my $filename = "$src_path/conf_gfx.h"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); while () { chomp; # cut trailing newline # process line with button definition if (/^\#define (IMG_MENU_BUTTON[A-Z0-9_]*)\s/) { $known_button{$1} = 1; # print STDERR "known_button: '$1'\n"; } } close FILE; return %known_button; } sub get_known_font_definitions { my %known_font = (); my $filename = "$src_path/main.h"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); while () { chomp; # cut trailing newline # process line with font definition if (/^\#define (FONT_[A-Z0-9_]+)\s/) { $known_font{$1} = 1; # print STDERR "known_font: '$1'\n"; } } close FILE; return %known_font; } sub get_known_sound_prefix_definitions { my %known_sound_prefix = ( 'background' => 1 ); return %known_sound_prefix; } sub get_known_music_prefix_definitions { my %known_music_prefix = (); my $filename = "$src_path/main.c"; open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); my $prefix_name = ''; my $skip_line = 1; while () { chomp; # cut trailing newline if (/MusicPrefixInfo/) # keyword to start parsing file { $skip_line = 0; next; } elsif (/NULL/ && !$skip_line) # keyword to stop parsing file { last; } elsif ($skip_line) { next; } if (/^\s+{\s+\"(.+)\"/) { my $music_prefix = $1; $known_music_prefix{$music_prefix} = 1; # printf STDERR "::: known music prefix '$music_prefix'\n"; } } close FILE; return %known_music_prefix; } sub print_element_to_graphic_entry { my ($element, $action, $direction, $crumbled, $graphic) = @_; my $num_tabs = 5 - int((length($element) + 4 + 1) / 8); my $tabs = "\t" x $num_tabs; if ($tabs eq '') { $tabs = ' '; } $crumbled = ($crumbled == 1 ? 'TRUE' : 'FALSE'); print " {\n"; print " $element,$tabs$action, $direction, $crumbled,\n"; print " $graphic\n"; print " },\n"; } sub print_element_to_special_graphic_entry { my ($element, $special, $graphic) = @_; my $num_tabs = 6 - int((length($element) + 4 + 1) / 8); my $tabs = "\t" x $num_tabs; if ($tabs eq '') { $tabs = ' '; } print " {\n"; print " $element,$tabs$special,\n"; print " $graphic\n"; print " },\n"; } sub print_font_to_graphic_entry { my ($font, $special, $graphic) = @_; my $num_tabs = 6 - int((length($font) + 4 + 1) / 8); my $tabs = "\t" x $num_tabs; if ($tabs eq '') { $tabs = ' '; } print " {\n"; print " $font,$tabs$special,\n"; print " $graphic\n"; print " },\n"; } sub print_element_to_sound_entry { my ($element, $is_class, $action, $sound) = @_; my $element_plus_is_class = "$element, $is_class"; my $num_tabs = 6 - int((length($element_plus_is_class) + 4 + 1) / 8); my $tabs = "\t" x $num_tabs; if ($tabs eq '') { $tabs = ' '; } print " {\n"; print " $element_plus_is_class,$tabs$action,\n"; print " $sound\n"; print " },\n"; } sub print_gamemode_to_sound_entry { my ($gamemode, $sound) = @_; print " {\n"; print " $gamemode,\n"; print " $sound\n"; print " },\n"; } sub print_gamemode_to_music_entry { my ($gamemode, $music) = @_; print " {\n"; print " $gamemode,\n"; print " $music\n"; print " },\n"; } sub print_image_config_var_entry { my ($token, $var) = @_; print " {\n"; print " $token,\n"; print " $var\n"; print " },\n"; } sub print_active_state_entry { my ($token, $token_active) = @_; print " {\n"; print " $token,\n"; print " $token_active\n"; print " },\n"; } sub print_element_to_graphic_list { my %graphic_without_element = ( 'IMG_FLAMES_1_LEFT' => 1, 'IMG_FLAMES_2_LEFT' => 1, 'IMG_FLAMES_3_LEFT' => 1, 'IMG_FLAMES_1_RIGHT' => 1, 'IMG_FLAMES_2_RIGHT' => 1, 'IMG_FLAMES_3_RIGHT' => 1, 'IMG_FLAMES_1_UP' => 1, 'IMG_FLAMES_2_UP' => 1, 'IMG_FLAMES_3_UP' => 1, 'IMG_FLAMES_1_DOWN' => 1, 'IMG_FLAMES_2_DOWN' => 1, 'IMG_FLAMES_3_DOWN' => 1, 'IMG_TWINKLE_BLUE' => 1, 'IMG_TWINKLE_WHITE' => 1, ); my %additional_mappings = ( # file elements which are mapped to runtime elements when playing # 'EL_EM_KEY_1_FILE' => 'IMG_EM_KEY_1', # 'EL_EM_KEY_2_FILE' => 'IMG_EM_KEY_2', # 'EL_EM_KEY_3_FILE' => 'IMG_EM_KEY_3', # 'EL_EM_KEY_4_FILE' => 'IMG_EM_KEY_4', # new elements which still have no graphic # 'EL_DOOR_WHITE', => 'IMG_CHAR_QUESTION', # 'EL_DOOR_WHITE_GRAY', => 'IMG_CHAR_QUESTION', # 'EL_KEY_WHITE', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_RADIOACTIVITY', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_WHEELCHAIR', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_PARKING', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_ONEWAY', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_HEART', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_TRIANGLE', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_ROUND', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_EXIT', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_YINYANG', => 'IMG_CHAR_QUESTION', # 'EL_SIGN_OTHER', => 'IMG_CHAR_QUESTION', 'EL_SIGN_UNUSED_1', => 'IMG_CHAR_QUESTION', 'EL_SIGN_UNUSED_2', => 'IMG_CHAR_QUESTION', 'EL_DX_UNKNOWN_15', => 'IMG_CHAR_QUESTION', 'EL_DX_UNKNOWN_42', => 'IMG_CHAR_QUESTION', # file elements with direction which is not defined 'EL_BD_BUTTERFLY_LEFT' => 'IMG_BD_BUTTERFLY', 'EL_BD_BUTTERFLY_RIGHT' => 'IMG_BD_BUTTERFLY', 'EL_BD_BUTTERFLY_UP' => 'IMG_BD_BUTTERFLY', 'EL_BD_BUTTERFLY_DOWN' => 'IMG_BD_BUTTERFLY', 'EL_BD_FIREFLY_LEFT' => 'IMG_BD_FIREFLY', 'EL_BD_FIREFLY_RIGHT' => 'IMG_BD_FIREFLY', 'EL_BD_FIREFLY_UP' => 'IMG_BD_FIREFLY', 'EL_BD_FIREFLY_DOWN' => 'IMG_BD_FIREFLY', ); my @unknown_graphics = (); my %known_element = get_known_element_definitions(); my %known_action = get_known_action_definitions(); my %known_special_arg = get_known_special_arg_definitions(); my %known_direction = ( 'LEFT' => 1, 'RIGHT' => 1, 'UP' => 1, 'DOWN' => 1, 'UPLEFT' => 1, 'UPRIGHT' => 1, 'DOWNLEFT' => 1, 'DOWNRIGHT' => 1, ); # ---------- read graphic file definitions ---------- my $filename = "$src_path/conf_gfx.c"; print_file_header($filename_conf_e2g_c, $text_e2g_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "static struct\n"; print "{\n"; print " int element;\n"; print " int action;\n"; print " int direction;\n"; print " boolean crumbled;\n"; print "\n"; print " int graphic;\n"; print "}\n"; print "element_to_graphic[] =\n"; print "{\n"; while () { chomp; # cut trailing newline if (/NO_MORE_ELEMENT_IMAGES/) # keyword to stop parsing file { last; } if (!contains_image_file($_)) # skip all lines without image file { next; } s/^ \{ \"//; # cut all leading ... s/\",.*$//; # ... and trailing garbage s/\[(\d+)\]/_$1/; # convert "[1]" to "_1" etc. s/\[//; # dirty hack for making "[default]" ... s/\]//; # ... work as an element name my $token = $_; if ($token =~ /\.([^\.]+)$/ && defined($known_special_arg{$1})) { next; # skip all special definitions } $token = uc($token); # convert all characters to upper case my $gfx_action_default = '-1'; my $gfx_action = $gfx_action_default; my $gfx_direction_default = '-1'; my $gfx_direction = $gfx_direction_default; my $gfx_crumbled = '0'; my $object = $token; my $action = ''; my $direction = ''; my $crumbled = ''; if ($object =~ /^(.*)\.([A-Z0-9]+)$/ && $2 eq 'CRUMBLED') { $object = $1; $crumbled = $2; $gfx_crumbled = '1'; } if ($object =~ /^(.*)\.([A-Z0-9]+)$/ && defined($known_direction{$2})) { $object = $1; $direction = $2; $gfx_direction = "MV_BIT_$direction"; $gfx_direction_default = $gfx_direction; } if ($object =~ /^(.*)\.([A-Z0-9_]+)$/ && defined($known_action{$2})) { $object = $1; $action = $2; $gfx_action = "ACTION_$action"; $gfx_action_default = $gfx_action; } $token =~ s/\./_/g; $object =~ s/\./_/g; # needed for "invisible_sand.active.digging" # print STDERR "'$token' => '$object', '$action', '$direction'\n"; my $full_element = "EL_$token"; my $base_element = "EL_$object"; my $element = $base_element; my $graphic = "IMG_$token"; my $element_without_crumbled = $full_element; $element_without_crumbled =~ s/_$crumbled$//; my $element_without_direction = $element_without_crumbled; $element_without_direction =~ s/_$direction$//; my $element_without_action = $element_without_direction; $element_without_action =~ s/_$action$//; if (defined($known_element{$full_element})) { $element = $full_element; $gfx_action_default = '-1'; $gfx_direction_default = '-1'; } if ($element_without_action eq $element || $action eq '') { $element_without_action = ''; } if ($element_without_direction eq $element || $direction eq '') { $element_without_direction = ''; } if ($element_without_crumbled eq $element || $crumbled eq '') { $element_without_crumbled = ''; } if (defined($graphic_without_element{$graphic})) { next; } if (!defined($known_element{$element})) { # print STDERR "----- ERROR: unknown element '$element' -----\n"; push @unknown_graphics, $graphic; next; } if (defined($known_element{$element})) { print_element_to_graphic_entry($element, $gfx_action_default, $gfx_direction_default, $gfx_crumbled, $graphic); } if (defined($known_element{$element_without_action})) { print_element_to_graphic_entry($element_without_action, $gfx_action, $gfx_direction, $gfx_crumbled, $graphic); } if (defined($known_element{$element_without_direction})) { print_element_to_graphic_entry($element_without_direction, '-1', $gfx_direction, $gfx_crumbled, $graphic); } if (defined($known_element{$element_without_crumbled})) { print_element_to_graphic_entry($element_without_crumbled, '-1', '-1', $gfx_crumbled, $graphic); } } # dump list of additional elements foreach my $element (sort keys %additional_mappings) { print_element_to_graphic_entry($element, '-1', '-1', '-1', $additional_mappings{$element}); } # dump list of character elements foreach my $char (@chars) { my $element = "EL_CHAR_$char"; my $graphic = "IMG_CHAR_$char"; if ($char ne $char_skip) { print_element_to_graphic_entry($element, '-1', '-1', '-1',$graphic); } } foreach my $char (@chars) { my $element = "EL_STEEL_CHAR_$char"; my $graphic = "IMG_STEEL_CHAR_$char"; if ($char ne $char_skip) { print_element_to_graphic_entry($element, '-1', '-1', '-1',$graphic); } } # dump list of custom elements for (my $i = 0; $i < $num_custom_elements; $i++) { my $element = sprintf("EL_CUSTOM_%d", $i + 1); my $graphic = sprintf("IMG_CUSTOM_%d", $i + 1); print_element_to_graphic_entry($element, '-1', '-1', '-1', $graphic); } # dump list of group elements for (my $i = 0; $i < $num_group_elements; $i++) { my $element = sprintf("EL_GROUP_%d", $i + 1); my $graphic = sprintf("IMG_GROUP_%d", $i + 1); print_element_to_graphic_entry($element, '-1', '-1', '-1', $graphic); } print_element_to_graphic_entry('-1', '-1', '-1', '-1', '-1'); print "};\n"; close FILE; if (scalar(@unknown_graphics) > 0) { print STDERR "-" x 79 . "\n"; print STDERR "The following graphics cannot be associated with any element:\n"; foreach my $graphic (@unknown_graphics) { print STDERR "- $graphic\n"; } print STDERR "-" x 79 . "\n"; } print_file_footer($filename_conf_e2g_c); } sub print_element_to_special_graphic_list { my %graphic_without_element = ( 'IMG_GLOBAL_DOOR' => 1, ); my %additional_mappings = ( # old elements which are mapped to other elements when playing #'EL_BUG' => 'IMG_BUG_RIGHT', #'EL_SPACESHIP' => 'IMG_SPACESHIP_RIGHT', #'EL_PACMAN' => 'IMG_PACMAN_RIGHT', ); my @elements_with_editor_graphic = ( 'char_space' ); my @unknown_graphics = (); my %known_element = get_known_element_definitions(); my %known_special_arg = get_known_special_arg_definitions(); # ---------- read graphic file definitions ---------- my $filename = "$src_path/conf_gfx.c"; print_file_header($filename_conf_esg_c, $text_esg_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "static struct\n"; print "{\n"; print " int element;\n"; print " int special;\n"; print "\n"; print " int graphic;\n"; print "}\n"; print "element_to_special_graphic[] =\n"; print "{\n"; while () { chomp; # cut trailing newline if (/NO_MORE_ELEMENT_IMAGES/) # keyword to stop parsing file { last; } if (!contains_image_file($_)) # skip all lines without image file { next; } s/^ \{ \"//; # cut all leading ... s/\",.*$//; # ... and trailing garbage my $token = $_; my $object; my $special; if ($token =~ /^font\./) # skip all font definitions { next; } if ($token =~ /^background\./) # skip all background image definitions { next; } if ($token =~ /^(.*)\.([^\.]+)$/ && defined($known_special_arg{$2})) { $object = $1; $special = "GFX_SPECIAL_ARG_" . $2; } else { next; # skip all default definitions } $token =~ s/(.*)/uc($1)/eg; # convert all characters to upper case $object =~ s/(.*)/uc($1)/eg; # convert all characters to upper case $token =~ s/\./_/g; $object =~ s/\./_/g; # print STDERR "'$token' => '$object'\n"; my $element = "EL_$object"; my $graphic = "IMG_$token"; if (defined($graphic_without_element{$graphic})) { next; } if (!defined($known_element{$element})) { # print STDERR "----- ERROR: unknown element '$element' -----\n"; push @unknown_graphics, $graphic; next; } print_element_to_special_graphic_entry($element, $special, $graphic); } # dump list of additional elements foreach my $element (sort keys %additional_mappings) { print_element_to_special_graphic_entry($element, 'GFX_SPECIAL_ARG_EDITOR', $additional_mappings{$element}); print_element_to_special_graphic_entry($element, 'GFX_SPECIAL_ARG_PREVIEW', $additional_mappings{$element}); } # dump list of custom element editor graphics for (my $i = 0; $i < $num_custom_elements; $i++) { my $element = sprintf("EL_CUSTOM_%d", $i + 1); my $graphic = sprintf("IMG_CUSTOM_%d_EDITOR", $i + 1); print_element_to_special_graphic_entry($element, 'GFX_SPECIAL_ARG_EDITOR', $graphic); } # dump list of group element editor graphics for (my $i = 0; $i < $num_group_elements; $i++) { my $element = sprintf("EL_GROUP_%d", $i + 1); my $graphic = sprintf("IMG_GROUP_%d_EDITOR", $i + 1); print_element_to_special_graphic_entry($element, 'GFX_SPECIAL_ARG_EDITOR', $graphic); } # dump other special editor graphics foreach my $token (@elements_with_editor_graphic) { my $element = 'EL_' . uc($token); my $graphic = 'IMG_' . uc($token) . '_EDITOR'; print_element_to_special_graphic_entry($element, 'GFX_SPECIAL_ARG_EDITOR', $graphic); } print_element_to_special_graphic_entry('-1', '-1', '-1'); print "};\n"; close FILE; if (scalar(@unknown_graphics) > 0) { print STDERR "-" x 79 . "\n"; print STDERR "The following graphics cannot be associated with any element:\n"; foreach my $graphic (@unknown_graphics) { print STDERR "- $graphic\n"; } print STDERR "-" x 79 . "\n"; } print_file_footer($filename_conf_esg_c); } sub print_element_to_sound_list { my %sound_without_action = ( 'SND_AMOEBA_TURNING_TO_GEM' => 1, 'SND_AMOEBA_TURNING_TO_ROCK' => 1, 'SND_BD_AMOEBA_TURNING_TO_GEM' => 1, 'SND_BD_AMOEBA_TURNING_TO_ROCK' => 1, # no special case anymore after adding action ".splashing" # 'SND_ACID_SPLASHING' => 1, ); my @unknown_sounds = (); my %known_element = get_known_element_definitions(); my %known_element_class = get_known_element_class_definitions(); my %known_action = get_known_action_definitions(); # ---------- read sound file definitions ---------- my $filename = "$src_path/conf_snd.c"; print_file_header($filename_conf_e2s_c, $text_e2s_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "static struct\n"; print "{\n"; print " int element;\n"; print " boolean is_class;\n"; print " int action;\n"; print "\n"; print " int sound;\n"; print "}\n"; print "element_to_sound[] =\n"; print "{\n"; while () { chomp; # cut trailing newline if (/NO_MORE_ELEMENT_SOUNDS/) # keyword to stop parsing file { last; } if (!contains_sound_file($_)) # skip all lines without sound file { next; } s/^ \{ \"//; # cut all leading ... s/\",.*$//; # ... and trailing garbage my $token = $_; $token = uc($token); # convert all characters to upper case my $snd_action_default = '-1'; my $snd_action = $snd_action_default; my $object = $token; my $action = ''; if ($object =~ /^(.*)\.([A-Z0-9_]+)$/ && defined($known_action{$2})) { $object = $1; $action = $2; $snd_action = "ACTION_$action"; $snd_action_default = $snd_action; } $token =~ s/\./_/g; $object =~ s/\./_/g; # needed for "invisible_sand.active.digging" if ($object =~ /^\[(.+)\]$/) { $object = 'CLASS_' . $1; } # print STDERR "'$token' => '$object', '$action'\n"; my $full_element = "EL_$token"; my $base_element = "EL_$object"; my $element = $base_element; my $sound = $token; if ($sound =~ /^\[.+\]/) { $sound =~ s/\[//; # element class sound; begin ... $sound =~ s/\]//; # ... and end of definition token $sound =~ s/^/CLASS_/; # add class identifier } $sound = "SND_$sound"; my $element_without_action = $full_element; $element_without_action =~ s/_$action$//; my $element_class_without_action = $full_element; $element_without_action =~ s/_$action$//; if (defined($known_element_class{$full_element})) { $element = $full_element; $snd_action_default = '-1'; } if ($element_without_action eq $element || $action eq '') { $element_without_action = ''; } if (defined($sound_without_action{$sound})) { next; } if (!defined($known_element{$element}) && !defined($known_element_class{$element})) { # print STDERR "----- ERROR: unknown element '$element' -----\n"; push @unknown_sounds, $sound; next; } if (!($element =~ /_CLASS_/) && defined($known_element{$element})) { print_element_to_sound_entry($element, "FALSE", $snd_action_default, $sound); } if (!($element =~ /_CLASS_/) && defined($known_element{$element_without_action})) { print_element_to_sound_entry($element_without_action, "FALSE", $snd_action, $sound); } if ($element =~ /_CLASS_/ && defined($known_element_class{$element})) { my $class_element = $known_element_class{$element}; print_element_to_sound_entry($class_element, "TRUE", $snd_action_default, $sound); } if ($element =~ /_CLASS_/ && defined($known_element_class{$element_without_action})) { my $class_element = $known_element_class{$element_without_action}; print_element_to_sound_entry($class_element, "TRUE", $snd_action, $sound); } } print_element_to_sound_entry('-1', '-1', '-1', '-1'); print "};\n"; close FILE; if (scalar(@unknown_sounds) > 0) { print STDERR "-" x 79 . "\n"; print STDERR "The following sounds cannot be associated with any element or element class:\n"; foreach my $sound (@unknown_sounds) { print STDERR "- $sound\n"; } print STDERR "-" x 79 . "\n"; } print_file_footer($filename_conf_e2s_c); } sub print_font_to_graphic_list { my @unknown_graphics = (); my %known_font = get_known_font_definitions(); my %known_special_arg = get_known_special_arg_definitions(); # ---------- read graphic file definitions ---------- my $filename = "$src_path/conf_gfx.c"; print_file_header($filename_conf_fnt_c, $text_fnt_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "static struct\n"; print "{\n"; print " int font_nr;\n"; print " int special;\n"; print "\n"; print " int graphic;\n"; print "}\n"; print "font_to_graphic[] =\n"; print "{\n"; while () { chomp; # cut trailing newline if (!contains_image_file($_)) # skip all lines without image file { next; } s/^ \{ \"//; # cut all leading ... s/\",.*$//; # ... and trailing garbage my $token = $_; my $font; my $special; my $graphic; if ($token =~ /^(font\..*)$/) { $font = $token; $special = '-1'; if ($token =~ /^(.*)\.([^\.]+)$/ && defined($known_special_arg{$2})) { $font = $1; $special = "GFX_SPECIAL_ARG_" . $2; } } else { next; # skip all non-font definitions } $token =~ s/(.*)/uc($1)/eg; # convert all characters to upper case $font =~ s/(.*)/uc($1)/eg; # convert all characters to upper case $token =~ s/\./_/g; $font =~ s/\./_/g; # print STDERR "'$token' => '$font'\n"; $graphic = "IMG_$token"; if (!defined($known_font{$font})) { # print STDERR "----- ERROR: unknown font '$font' -----\n"; push @unknown_graphics, $graphic; next; } print_font_to_graphic_entry($font, $special, $graphic); } print_font_to_graphic_entry('-1', '-1', '-1'); print "};\n"; close FILE; if (scalar(@unknown_graphics) > 0) { print STDERR "-" x 79 . "\n"; print STDERR "The following graphics cannot be associated with any font:\n"; foreach my $graphic (@unknown_graphics) { print STDERR "- $graphic\n"; } print STDERR "-" x 79 . "\n"; } print_file_footer($filename_conf_fnt_c); } sub print_gamemode_to_sound_list { my %known_prefix = get_known_sound_prefix_definitions(); my %known_special_arg = get_known_special_arg_definitions(); # ---------- read music file definitions ---------- my $filename = "$src_path/conf_snd.c"; print_file_header($filename_conf_g2s_c, $text_g2s_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "static struct\n"; print "{\n"; print " int gamemode;\n"; print "\n"; print " int sound;\n"; print "}\n"; print "gamemode_to_sound[] =\n"; print "{\n"; while () { chomp; # cut trailing newline if (!contains_sound_file($_)) # skip all lines without sound file { next; } if (/\[not used\]/) { next; } s/^ \{ \"//; # cut all leading ... s/\",.*$//; # ... and trailing garbage my $token = $_; my $gamemode = -1; # my $level = -1; # ??? if (defined($known_prefix{$token})) { # no special arg defined } elsif ($token =~ /^(.*)\.([^\.]+)$/ && defined($known_prefix{$1}) && defined($known_special_arg{$2})) { $gamemode = "GFX_SPECIAL_ARG_" . $2; } else { next; } # if ($token =~ /^(.*)\./ && # !defined($known_prefix{$1})) # { # next; # } # # if ($token =~ /^(.*)\.([^\.]+)$/ && # defined($known_special_arg{$2})) # { # $gamemode = "GFX_SPECIAL_ARG_" . $2; # } $token =~ s/(.*)/uc($1)/eg; # convert all characters to upper case $token =~ s/\./_/g; my $sound = "SND_$token"; # print STDERR "'$token' => '$sound'\n"; print_gamemode_to_sound_entry($gamemode, $sound); } print_gamemode_to_sound_entry('-1', '-1'); print "};\n"; close FILE; print_file_footer($filename_conf_g2s_c); } sub print_gamemode_to_music_list { my %known_prefix = get_known_music_prefix_definitions(); my %known_special_arg = get_known_special_arg_definitions(); # ---------- read music file definitions ---------- my $filename = "$src_path/conf_mus.c"; print_file_header($filename_conf_g2m_c, $text_g2m_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "static struct\n"; print "{\n"; print " int gamemode;\n"; print "\n"; print " int music;\n"; print "}\n"; print "gamemode_to_music[] =\n"; print "{\n"; while () { chomp; # cut trailing newline if (!contains_music_file($_)) # skip all lines without music file { next; } s/^ \{ \"//; # cut all leading ... s/\",.*$//; # ... and trailing garbage my $token = $_; my $gamemode = -1; if (defined($known_prefix{$token})) { # no special arg defined } elsif ($token =~ /^(.*)\.([^\.]+)$/ && defined($known_prefix{$1}) && defined($known_special_arg{$2})) { $gamemode = "GFX_SPECIAL_ARG_" . $2; } else { next; } # my $prefix = $token; # $prefix =~ s/\..*$//; # ## if ($token =~ /^(.*)\./ && ## !defined($known_prefix{$1})) # if (!defined($known_prefix{$prefix})) # { # next; # } # # if ($token =~ /^(.*)\.([^\.]+)$/ && # defined($known_special_arg{$2})) # { # $gamemode = "GFX_SPECIAL_ARG_" . $2; # } $token =~ s/(.*)/uc($1)/eg; # convert all characters to upper case $token =~ s/\./_/g; my $music = "MUS_$token"; # print STDERR "'$token' => '$music'\n"; print_gamemode_to_music_entry($gamemode, $music); } print_gamemode_to_music_entry('-1', '-1'); print "};\n"; close FILE; print_file_footer($filename_conf_g2m_c); } sub print_image_config_vars { # ---------- read graphic file definitions ---------- my $filename = "$src_path/conf_gfx.c"; print_file_header($filename_conf_var_c, $text_var_c); open(FILE, "$filename") || fail("cannot open file '$filename' for reading"); print "struct TokenIntPtrInfo image_config_vars[] =\n"; print "{\n"; my $start_parsing = 0; while () { chomp; # cut trailing newline if (/CONFIG_VARS_START/) # keyword to start parsing file { $start_parsing = 1; } if (!$start_parsing) { next; } if (/^\s*\{\s*\"([^\"]+)\"/) # config token found { my $token = $1; my $var = $token; # --- some prefix replacements --- $var =~ s/^main\./menu.main./; $var =~ s/^\[player\]\./game.player_/; $var =~ s/^\[title_initial\]/title_initial_default/; $var =~ s/^\[title\]/title_default/; $var =~ s/^\[titlescreen_initial\]/titlescreen_initial_default/; $var =~ s/^\[titlescreen\]/titlescreen_default/; $var =~ s/^\[titlemessage_initial\]/titlemessage_initial_default/; $var =~ s/^\[titlemessage\]/titlemessage_default/; if ($var =~ /^titlescreen.*(\d)/ || $var =~ /^titlemessage.*(\d)/ || $var =~ /^game.panel.key_(\d)/ || $var =~ /^game.panel.inventory_first_(\d)/ || $var =~ /^game.panel.inventory_last_(\d)/ || $var =~ /^game.panel.conveyor_belt_(\d)\./ || $var =~ /^game.panel.element_(\d)\./ || $var =~ /^game.panel.graphic_(\d)\./ || $var =~ /^game.panel.ce_score_(\d)\./) { my $number = $1; my $array_pos = int($number) - 1; $var =~ s/_$number/\[$array_pos\]/; } elsif ($var =~ /^game.panel.conveyor_belt_(\d)(_switch)/ || $var =~ /^game.panel.element_(\d)(_count)/ || $var =~ /^game.panel.ce_score_(\d)(_element)/) { my $number = $1; my $suffix = $2; my $array_pos = int($number) - 1; $var =~ s/_$number$suffix/$suffix\[$array_pos\]/; } # --- some suffix replacements --- $var =~ s/^(menu\.main\..*)\.chars$/$1.size/; $var =~ s/^(tape\.text\..*)\.chars$/$1.size/; $var =~ s/^(game\.panel\..*)\.chars$/$1.size/; $var =~ s/^(game\.panel\..*)\.tile_size$/$1.size/; $var =~ s/^(request\.button\..*)\.tile_size$/$1.size/; $var =~ s/\.digits$/.size/; $var =~ s/\.2nd_offset$/.offset2/; $var =~ s/\.2nd_xoffset$/.xoffset2/; $var =~ s/\.2nd_yoffset$/.yoffset2/; $var =~ s/\.element$/.id/; $var =~ s/\.draw_order$/.sort_priority/; $var =~ s/\.font_[a-z]+$/.font_alt/; $var =~ s/\.INFO\[([A-Z]+)\]$/_info\[GFX_SPECIAL_ARG_INFO_$1\]/; $var =~ s/\.SETUP\[([A-Z0-9_]+)\]$/_setup\[GFX_SPECIAL_ARG_SETUP_$1\]/; $var =~ s/\.([A-Z]+)$/\[GFX_SPECIAL_ARG_$1\]/; $var =~ s/\.([A-Z]+)\./\[GFX_SPECIAL_ARG_$1\]./; if ($var =~ /^(menu.(enter|leave|next)_screen)(.[a-z_]+)$/) { $var = $1 . "[GFX_SPECIAL_ARG_DEFAULT]" . $3; } if ($var =~ /^menu.(draw_[xy]offset|list_size)$/) { $var .= "[GFX_SPECIAL_ARG_DEFAULT]"; } if ($var =~ /^(viewport.(window|playfield|door_[12]))(.[a-z_]+)$/) { $var = $1 . "[GFX_SPECIAL_ARG_DEFAULT]" . $3; } print_image_config_var_entry("\"$token\"", "&$var"); if ($var =~ /^(title)_default/ || $var =~ /^(title_initial)_default/ || $var =~ /^(titlescreen.*)\[\d\]/ || $var =~ /^(titlemessage.*)\[\d\]/) { my $prefix = $1; $var =~ s/^$prefix/${prefix}_first/; print_image_config_var_entry("\"$token\"", "&$var"); } } } print_image_config_var_entry('NULL', 'NULL'); print "};\n"; close FILE; print_file_footer($filename_conf_var_c); } sub print_active_states { # ---------- read graphic file definitions ---------- my %known_element = get_known_element_definitions(); my %known_button = get_known_button_definitions(); my %known_font = get_known_font_definitions(); print_file_header($filename_conf_act_c, $text_act_c); print "static struct\n"; print "{\n"; print " int element;\n"; print " int element_active;\n"; print "}\n"; print "element_with_active_state[] =\n"; print "{\n"; foreach my $element (sort keys %known_element) { my $element_active = $element . '_ACTIVE'; if (defined($known_element{$element_active})) { print_active_state_entry($element, $element_active); } } print_active_state_entry('-1', '-1'); print "};\n"; print "\n"; print "\n"; print "static struct\n"; print "{\n"; print " int button;\n"; print " int button_active;\n"; print "}\n"; print "button_with_active_state[] =\n"; print "{\n"; foreach my $button (sort keys %known_button) { my $button_active = $button . '_ACTIVE'; if (defined($known_button{$button_active})) { print_active_state_entry($button, $button_active); } } print_active_state_entry('-1', '-1'); print "};\n"; print "\n"; print "\n"; print "static struct\n"; print "{\n"; print " int font_nr;\n"; print " int font_nr_active;\n"; print "}\n"; print "font_with_active_state[] =\n"; print "{\n"; foreach my $font (sort keys %known_font) { my $font_active = $font . '_ACTIVE'; if (defined($known_font{$font_active})) { print_active_state_entry($font, $font_active); } } print_active_state_entry('-1', '-1'); print "};\n"; print_file_footer($filename_conf_act_c); } # ============================================================================= # M A I N - P R O G R A M # ============================================================================= sub main { my $argc = scalar(@ARGV); if ($argc == 0 || $ARGV[0] eq '-h' || $ARGV[0] eq '--help') { print "Usage: $0 \n\n"; print "Choose from the following list:\n"; print "- '$filename_conf_gfx_h'\n"; print "- '$filename_conf_snd_h'\n"; print "- '$filename_conf_mus_h'\n"; print "- '$filename_conf_chr_c'\n"; print "- '$filename_conf_chr_h'\n"; print "- '$filename_conf_cus_c'\n"; print "- '$filename_conf_cus_h'\n"; print "- '$filename_conf_grp_c'\n"; print "- '$filename_conf_grp_h'\n"; print "- '$filename_conf_e2g_c'\n"; print "- '$filename_conf_esg_c'\n"; print "- '$filename_conf_fnt_c'\n"; print "- '$filename_conf_g2s_c'\n"; print "- '$filename_conf_g2m_c'\n"; print "- '$filename_conf_var_c'\n"; print "- '$filename_conf_act_c'\n"; exit 1; } if ($ARGV[0] eq $filename_conf_gfx_h) { print_graphics_list(); } elsif ($ARGV[0] eq $filename_conf_snd_h) { print_sounds_list(); } elsif ($ARGV[0] eq $filename_conf_mus_h) { print_music_list(); } elsif ($ARGV[0] eq $filename_conf_chr_c) { print_chars_graphics_list(); } elsif ($ARGV[0] eq $filename_conf_chr_h) { print_chars_elements_list(); } elsif ($ARGV[0] eq $filename_conf_cus_c) { print_custom_graphics_list(); } elsif ($ARGV[0] eq $filename_conf_cus_h) { print_custom_elements_list(); } elsif ($ARGV[0] eq $filename_conf_grp_c) { print_group_graphics_list(); } elsif ($ARGV[0] eq $filename_conf_grp_h) { print_group_elements_list(); } elsif ($ARGV[0] eq $filename_conf_e2g_c) { print_element_to_graphic_list(); } elsif ($ARGV[0] eq $filename_conf_esg_c) { print_element_to_special_graphic_list(); } elsif ($ARGV[0] eq $filename_conf_e2s_c) { print_element_to_sound_list(); } elsif ($ARGV[0] eq $filename_conf_fnt_c) { print_font_to_graphic_list(); } elsif ($ARGV[0] eq $filename_conf_g2s_c) { print_gamemode_to_sound_list(); } elsif ($ARGV[0] eq $filename_conf_g2m_c) { print_gamemode_to_music_list(); } elsif ($ARGV[0] eq $filename_conf_var_c) { print_image_config_vars(); } elsif ($ARGV[0] eq $filename_conf_act_c) { print_active_states(); } else { print "Unknown option '$ARGV[0]'.\n"; exit 1; } exit 0; } mirrormagic-3.0.0/sounds/0000755000175000017500000000000013263214146014650 5ustar aeglosaeglosmirrormagic-3.0.0/sounds/snd_mirrormagic/0000775000175000017500000000000013252264735020040 5ustar aeglosaeglosmirrormagic-3.0.0/sounds/snd_mirrormagic/soundsinfo.conf0000664000175000017500000000057613262506203023074 0ustar aeglosaeglos# ============================================================================= # Mirror Magic / Mindbender # ============================================================================= name: Mirror Magic Sounds door_1.opening: oeffnen.wav door_1.closing: oeffnen.wav door_2.opening: [NONE] door_2.closing: [NONE] door.opening: [NONE] door.closing: [NONE] mirrormagic-3.0.0/sounds/snd_mirrormagic/oeffnen.wav0000644000175000017500000004115107172626011022170 0ustar aeglosaeglosRIFFaBWAVEfmt "V"Vdata=B‹‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆ‡‡‡‡‡‡‡‡ˆˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‹‹‹Š‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆ‡‡‡‡‡‡‡‡‡‡‡ˆˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‹ŒŽ‘‘‘‰…|wne^\Z_ly„Ž˜œ ¤¤¥£žš–’‹ˆ†‡‰‹“’Ž‹„}yˆ‘¨¦Ÿ—Ž„~„‹‘—™†~umljjlmtŠ’™   Ÿš˜”‘Ž‹ˆ†ƒ€‚‡Œ’™š—’ˆˆŠŒŽ‘‘‹†€ztv|…‰‹‡ƒ{wxz{~…‹”–—“ˆƒ~zvrqqqswzƒ‡Œ‘–£ª²¹²ª¢–Š€{uqmiiklmorz‚‰—¤ª¬®¬¡—‰ƒ†‰Œ‹‰„{qnooy…“–˜•’“™ž¦¯·±¬¥šˆ„€}zvtqoljo{‡’§Ÿ—‹†ˆ‘šž¡£’€pjdguƒ‹”†€€€„‹“•””Žˆ„†‰“™›››™–”‰…ƒ…‡Š‹‰ˆ†„‚€}{{{{‚Š•™š™—•“‘ŽŽ‰„xpkosz„Ž”˜œž ¡¡ Ÿžž”†yj\TbqŒ™š—”‘Ž’•˜™™”‹‚}yvy}ƒƒ‚‚„†‰”—”‘Œ…}‚…”—”‹„}zvsqnllllllt}‡˜žŸ¡¡  ›”Žˆ‚|voljhkpu|‚Š“£¥§¦¤¢œ—’Œ†ƒ€€€€}zwtqqtx{ƒ…‡‰ŠŒŽ“—šŸ˜ˆ‚{wvvutsrpptw}‡‘˜£¥¦§§¦¥£ œ–ˆ€zz{}€ƒ…‡ˆ‰ŠŒ”˜œ ž—‘‹„~zvspmmoqtwz~ƒ‡Š‹ˆ………†ˆŠŠŠŠˆ‡†‰‘–››š™–“‘”˜› ¤ ˜‡xxxxxxxxxxyz}€ƒ…†…„‚‚„…†‡ˆ‰‰ŠŠ‹‹‹‹“–šš™—•’‘”–™¡ ž›™—”‘‰…}yusqqv{ƒ‡‡††……………„ƒ‚€~}{zyyyz|ƒ‡Œ”—šž £¥¦§§¤Ÿ›–‘Ї„~|zxxwy€‡Œ‘•’‹ˆ…ƒ‚€~{yuplnpuŠ’”’ŒŽ‘”š¡¡œ—†~‚†‹’™š•Š…€…Š”™˜’‹†}€„ˆˆ‰…}tponxƒ’–—“ŽŽŽ’–™—•‘‹…ƒ€€‚„…‡‰‹“—šš—“‰†‚~{wwwwwwwxxz|…‹“–———•”’Ž‹…€yrjjmpx€‡‰‹Ž“••Žˆyrooonmllllmnt{ƒ‰“““’’’’’’Š„~zxwy|€ƒ…ˆŠ‹Ž“˜£©¡˜Ž€rjjjklnqsvy|‰—ž¤¤£¡Ÿœ™”Š„~ulcb`aku}…Œ‘•™ž£©°¶¶¯§šŒ}zwuvwtkcYNCSdv‰«³»ÂÉÐÌÈľ¹­™„scTRQQSUZclw‚œ«¸»¾½µ­¥ž—‘Œ†|si]QQYamz‡Œ•˜›¡ª²ºÁȼ°¤˜ƒ{sle^[WUY]j€•£®¹´®©¥¡žœ™“‹ƒvi_achqz€…Г𡩱¹´©ƒy{|~€€€€„ˆŒ“–˜™šš™–’Žˆ{rhcehnx‚‰—œ¢¦¦¦¤¢ ˜Ž„yngjlosv}†—Ÿ§¬±´µµªš‹€unprsuwxyz}€‚†ŠŽŽŽŒ‹Š‰‡†…„ƒ€}{ywtv}…–Ÿ¥«°µº»´®§ ™Žƒxpiflqw~„–ž¤ª®®¯­§¢˜Œyqjc][]^bglx…’¡°¶´²®©£—‘Œ†‚€~|{zˆ–œ ¢£¤¤¤Ÿš–‘Œ‡‚}xtplhfghkqw}ƒ‰•› ¢££ ›•އ~{wursx|€…‰‹Ž’”“’Œ‹Šˆ†„ƒ‚‚ƒ„…†‡ˆ‡†„~{xvtrpppppps‹™¨¸¼½½¾¾¼¶±«¤ž”ˆ|ribdfimqxŠ‘˜ž£©«ªª¥ž—“‹Šˆ…zri`bejrz~|ytoiov}‡•“Œ‰…ˆ’•™š•‹ˆ„†‰Œ†€|zwxz|}~†‹”ž§¦¥¢š’‹‰ˆ‡‡‚~yupnoopqqx~…‹‘—¤¨­±¯¬©¤ ›–‘‹„}tja`_cmx€ˆ•› ¡£££¢œ“Š}ocehlsz‚Š’›£¬±¶»¿Ã¿¶­¤›‘‹†€zuqolmoq~‹–ž¦©§¦¤£¢¡ ž—†zngc__`bipx‚Œ’—œ¡¦ª®±µ¹¼´¦˜Š}qqpomlkihjmrƒ•£«²¯¥›•‹‹‹ˆ‚|rfZ\agv…”˜™˜—™›ž¡¥£“„r^KOYcozƒ…‡‰‹Ž“™ ¤¨ª£—’‰…|xsojiknw‚‘•˜•“”š ©³½µ«¡troooopqrrsz‹œ¬»ËÄ»²ª¡˜‡~ulbYPNLNYdo{‡“ ¬´»ÁÁÁ¹«ˆr]]]`kv|~€€‰”Ÿ­º½µ­¤›‘ŽŠ‡ƒxphb\W_hqyˆŒ•™¡¥§£ ˜Œxsnnooonmjhmw€š¥£¡—‘Ї„‚wohb[^hq{„“™Ÿ¤©ª¨¦¢˜ƒyqjda]_bfpzƒŠ’™ ¦©ª«©§£š‘‡|pnnnqturolier…˜¨¸Ã»´¬¤–‘‹„|th[TRQ]n€Š“š™—˜¢©²»±¥—~dTRQV^fijkkkrˆµÏéáÔǹ«‘„xla][XXWX_emvŽŸ°·¿Ã½¶®£™Œ~pjc^\ZXWWWWWgxŠ¡¸ÇËÏÒÓÔÆ·¨˜ˆ€‚‚‚yphc_f|’¤´ÃÀ»·²­¨£ž—Ž…vgYQIDDCKXex¡«µ½ÂÇÁ´¨—…trpooolgb^ZXmƒ—ª¼À¶­§¢¡¦©¨¦Œ{nbVRNKOSZdoz„𥮱´´²°§›re\SLF?GUdsƒ’¡¯½ËØÜÚÙÓÍÅ­•m[ROKLMPZdoz…‘Ÿ¬µ½ÅÈËɽ²¡xkaVQLIIJLNPZgsŽ›§´ÀËÖÒÉÀ¸°¦—ˆyl^TKCA?AP`p‚”©ÁØÝáâÕȹ¨—†ucTF7, />Tn‰˜¦³¿ÊÐÎÍÌÊÉ»¬€p_OA4'1?LYgt‚«¹ÇÔáâäÞ˸§—ˆ|pdYND;23>HZn‚Ž™¤®·½ÀÄÇÊ̶ Šs\OLIGECFJNU[h{ °ÀÃÆÉÉÉÆÀ¹¯¤˜‡ue]UQRRTVX\`fr®·¾ÄÈÍϵ¨™‹ziWF5&/8AJSas†–¥´¼ÃÊÎÓÏÆ½³©Ÿ‘„wk`UJ@BGM]n}Š—¤¯»ÂÇÍÏÒÑÁ± Ž|ocWK?679;?CTi“§ºÈÕßåëß̹¦“€mZKB97:=FP[jzŠ›«¼ÍßÞÛ×Ë¿²¥—‰|ocWK@52AO]lzŒž±ÀÎÖÍﳫ¢™„xjVC73.:K[jy‡”¡¬µ¾ÅËÐö¦xh`WROMNOQSUaw¤¼ÓÊÀ¶«¡›š™–‘zgULCF\q€Œ˜–‘Ž“™¦³¶³°¢’‚zqje`][YVSRdw‹£»ÅÇÈÇÆÄ½¶¯§žu]J7&5DR`nz†‘›¦°·¿Ã¿º­˜„scSG;3:ANat…•¥³ÁÌÇü²¨ž“ˆ~tkfa]ZW]gq{„›¨³¼ÅĽ¶­¤›Žukb^]]^_afjpw~†˜Ÿ¦¬±¶·±ª¡•‰zsnhgmt{„’—œ ¤§¦¤¢ žš–‘ˆƒ~yuropsu|‚‹˜¥¬¬¬¢”‡zuuuuuuuuuˆ“¡¯µ°«¤›’Šxofchnsy†“𡧬²´µµ¬¡—„}wrnljlnqtx|€…‰‘”—š™˜—”‘ˆƒ}xrrqqqqsvy|ƒŽ™¤­··¯¦ž–Š…€{vqlffhjx‡•Ÿª²·¼¹±ª™ˆytnlnpppponoz†’ ®¯©¢šˆ„}zwtqonno{‡‘𢣠œ˜•‘ˆ„€{wsoqtw‚Œ“’‘‹‚yy}Š”™•‘‹‚zvutssrqonlkov|‚‰–ž¤©®®¬ª¤ž–†wjbYZ`els{„Œ•ž¦®µ½´©œ†pcefny„ˆŠš¤¯»Ç»«›~vz~„‡†„ƒ„…‰–¢ª­±§š‰„‚‰”–˜–“‘“—›™“Œ‚vkqwŒ™   š—¤«²ºµ¤’‚scjrz€‡‹’–™¡©°°±¬Ÿ’‹‡ƒˆ•–˜—”‘‘‘”˜š”†{qnqsx~„ˆ‘•šœœœœ”‹ƒ}vtvy|ƒ‰”•–‘†|wspu{€‚„…ƒ‚ƒ†ˆŽ“—’އ}rpppuy~„‹’˜Ÿ£¥§¨©§›ƒwkfca`_`ir{…›§´·º¹¨–‡}rlifffgjms~‰—§·¶³¯¢–Œ†€{xttuvwx|‚‰—žž›š˜–“Œˆ„xqpnoyƒ‹”“ŒŒŒŽ“™š˜•ކ}{yxz|}}}|zy†Ž— ¤Ÿš•‰‡…ƒ‚€~zwusrx€ˆ‘“ŒŠ‰ˆŠŽŒ…~|}}„””“‰ƒ€€€‚„†…„‚}€‡™£­¤›’‰€{{{zzzyxxyz‡”˜›•Žˆƒ}~~€‚…‡ŠŠŠ‰†„~{wspppprsx~„‹“šž¡¥©¬­¬¬ª§¤™Ž„{ssy„‰Ž‘“•—™šœ›š˜“‰†„ƒƒƒ€|xrkgikntyzzywtv‚›©¸³©ž’†}€‚„†‡€wmhcao}‰“œžœ›š™™š›š—”‡€}{y{|}||zxv|‚Š”Ÿ¥£ œ—’‹‰ˆ‡ˆ‰Š‹ŒŽŽŽ“—™™™‘‡}yut}†‹‹…‚†Œš§¬ª¨‚ƒ‡ˆ†„€|xƒŽš¨¶¹¯¤šŽƒˆŽ“˜šwogq}ˆ˜œš™šŸ§°·²­¡‹uiaY^ekmprsu{…œ©µ°«¤›‘Š…zuqsvx{~„Œ”›£©§¥¢Ÿ›–އ‚}yz{}€ƒ‡“˜›Ÿ  Ÿ›—“‡‚}yuqmljiiimt{ƒ‹’’“”””‘‰…}xsoljkpty„‹’˜›ž˜“Žˆƒ|upomnqsvz}€„‡ŠŒ’Ž‹‡ƒ{vrnifc`][[fpy‚‹‘•š¡£¢ Ÿ›—“‹‡„€|{{{}€ƒ‡‹”™›˜–’Œ‡ƒ|ywvwxz|~ƒ‰Ž”šœ™—”‘ŽŠ†‚|yxvvxyƒŽ˜Ÿ¥©§¤¡™”މ€wncWUX\hw…‹•˜š›™˜•’އwnfcgkosw|‡‹’““”””“’’’’’”–———•“ŽŠ‡€yty‡“Ÿ¤¤¤ ™—–”’‰…|y|ƒ†‰”—›žžžœš—”’’—ž¤§¨©¦¤ ›—’ˆ‡ˆŠŽ’””“‘Ž“––‰‚{ttvx{~€„ˆ‘•›¡§¨¨¥–‡|vot}†‰ŒŽŠ†„‡‰Ž”š—’‚wsz€‹˜¦¢›”Š€|‚‰‘™¢ž—‘‹…‚†ŠŽŠƒ{yvy†“œ¡¦Ÿ“ˆ…ˆ’Ž…ynnor|†‹‹‹‡‚~ƒ‰˜¡¤ œ–І‚~zvsrqpoooopqsv}„‰Ž’’‹‡‚}{yxz~€}{vqpqqvzƒˆŒ””‘‹‡ƒ‚€€~|{zzz€†Œ•“‹„~ytuwy|~…‰‹‹†yqkklouz‚Š“§®§ ˜Ž…~zvrommnoqs|‰•Ÿ©±«¥Ÿ™“Œ…}yurstvx{€†ŒŽ‘’’’І€{ywvvvy…ž®¾¸­£–‰‚ƒƒ‚€~~~€Š”œ£ª©¦£ œ˜”Œ‰…„ƒ‚„‡‹‘˜›š™”†ƒ€}|{{{{|}~„Š–œœ”Œƒyosy~ƒˆ‹‰ˆ‡††‡ŠŒŽ’•˜™š›š˜–“Š„~}‰‘™™˜•Žˆ„‚‚„„„………ˆ‘—œ¡š”†€~…‡ŠŒ‰…‚‚ˆ“–™•‘Œ‹Œ‘•–••Žˆƒ…‡— ¡œ˜Žƒ{}~‚‰‘Ž‹†€|‚†ŠŽŒ…ztpv}‚‡Œ“•›¡¦§©¤š‰ƒ|zxwwwwy{‚Š’ž«³°­§”ŽŠ†„|yvsosx}„Š‘“”–—”‹†}zvtrpqrsx|‰’™¢£¡ Ÿžžžž›–‰€wwwwz}€„‰’–›Ÿ¤¨­¬£š‘ˆxqje`^diou{…™Ÿ¥©¦£Ÿ›—’Œ†{uoijouž¢¦ªªª§¢—‘‹xne\Y`flsz‡“ «·»¶±¬¦ ”‡{sjfikmoquy~…Œ•¡­²²²¨“މ†ƒ€|vpjc^jv…–¨°²³³²±© ˜†}tjbZSVX\bgqŒ™¤°µº½»¹°¢”ˆ|qf\TRPPTXamxˆ—¤§ª«ªª¦¡˜”‡~vne`[WUTUfw‡•£¨¨¨¦£ —Ž…}ungabdgr}‡—ž£©¦£Ÿ–…|yxvtronmo{‡”¢±±®«¨¤ž’†{rhhlpsw{„‰‘•™ ¢£¢ —’Šxrmhfdejpyƒ‘•™œ  ž›™–“‹‚yphcfhjmouz€‡–£±¸¼À¯š†ykb`]^`bhov€‰” ¬°®¬¢–‹„}vqljkkmor‹˜§µº¶²®ª¥œ’ˆ€xrpmmmmw‹’™œ››™—–’Ž‹ˆ…‚€}|{{{{|ƒ†‹“˜œ¡¥©©¨§¤¢•†yz|}~€‚…ˆ”¡¬±·° „ypppomkifcir{Ž¢°²´±¨ž™”Їƒ|xtx~…Œ“𠦬±¶µ±®©£œŽsh^_ekrx‡—œ¢¤¥¥£¡Ÿš–’‰…}zvsqnnsx‡–ž¦®¶º¶±¬¥ž”‰~sibbbcegt„“¢°¼ÄÍÑÑÑ󣔄ugYPLGJPUbp~‘¤±¸¿ÃÆÈ½±£’reXK?25.&/E[o‚“ž¨¯³·«™ˆ{nc^YVTSUY\bgmv~†Œ“™Ÿ¥¢žš“ŒƒyodYMMMMPSYcny„Ž”™ž¡¤ “…ymb]ZVTRRUY_go~œ¡¦§Ÿ—Š„zurnjgdflr{…Ž‹‡ƒ|vrqpoonmlkkkp{‡™¡œ—‘‰…‚~zuqia[\^es€Œ–¡¨°µµ´°©¢š“‹ƒ|vxy|††ƒ€{wsy…‹‘ˆ|wt~‰’˜Ÿ™‹~unhr{ƒ‡Œ‹†‚„†™  ¡–ދЉ‹Ž‘’“““•–˜™››•ˆ€xx{}€‚ƒ|zyxƒ’¡«´¹­ –ކƒ‚~|ysnmqu€š£¬´¹¾¾¸²¨œŠ…€~{yvtrqow‹– ¦¤¡š–Š„{x{~‚…‰‘–—˜˜”ŒŒ•šš››—”•šž¦¯·²­§›Š‰‰ŠŒ‹ˆ†ƒ€‡“™Ÿ  Ÿœ—Ž…~xrtvy}†Œ’–›Ÿ ¡¡Ÿžš”’–š™˜–’‹‰ˆ‡‡†„~{xz‡–žžŸ   ›“‹„|utsrrruz€…‹”˜›››˜’ˆƒ}ytqux~†Ž‘’“’‘“•˜œš–’ˆ……†‡ˆ‰‰‰‰ˆˆ‡…„ƒƒƒ‡”—šœ•‰„{xuvwy€‡Ž•¤¬´³°­¤›‘ˆ~uj`bgls{‚Š’š¢ª¬¬««ª¦š‚xnnqtx|€‡”𠤧©¦¢œ‚yuqrvy|‚„†Š‘˜¢¬·±«£˜ƒ|unhbbcdegks{‚Š’•™œž Ÿ˜‘‹†€|xtttuz…Œ“¨±°®ªŸ•Œƒ{tmghilrwŠ•¡®¹·µ²­¨ •‹wljgeedhpx†ŒŽ’”–™œš—”ˆ|romnt{‚…‡ˆŠ”ž©·Äľ¸¬Ÿ“ŒŠˆ‡„}yvt~ˆ’›¤¦¤¢Ÿš”ŽˆypeZWUTan{„Ž–› £¤¥£¡ž—ˆ~trrruy~‰“Ÿ«·»¼¾¾¾¹©˜ˆxigjloqstvx{†™ž¢¤–Žˆzrkfa\[Y\cju‚ª·ÄÑÕÌͦ–„|tmgb\XSO`vŠž±¾¾¾½»º°¤™‚vi\TPKTamv€‰—œž¡¡ Ÿ–ƒvhbbbfkpyŠ“¤©®³¸½´©Ÿ”‰€ysmiemw€‰’˜œ ¢££œ“‹ƒ{sldcegsŠŽ“•”“”—™¢¥•‹€tsx}…Ž–˜šœŸžš—”Œ„}vpkkpuz…Œ”š •ˆƒ€‚‡’›¥ª¦¢›‘‡„ƒ‚ƒ„…ƒ~|yˆ‘š¤ª¡˜‘Š„…‰Ž‘“”…€~|ƒŽ™¡¢—Œ…ƒ€„Œ“”“’‹„~‚……ƒ‚€}|…‰Ž‘’““‘ŽŒŠ‡ƒ}{z~„ˆŒŽ‘”””“І„‚ƒ…‡‡†…‚€„‰‘›¥¢Ÿ›’‰ƒ~zvspppqrsy†“¡®¼¶­¤›“Šyrkegjmszƒ‘ ª°·³­§ž•Œvpmjlos{‚‹•Ÿ¢ ž˜‰yqi`]_`bdgy‹œ®Àž·°©¡–Š~tja[TSTTcsŽ›¥¬³µ´´ª —Ž…|tkgdbbcepz†“¡¦¨©¨§¥¡œ˜“†{oe[T]fnv~„ˆŒ”˜¢¥¤¢š€xqkklmoqswzŠ“Ÿ«±¨ ’pmnoty~‚†‰‘—Ÿ§¯·¼´¬£šƒte[RLU^fow€‰’š¡©®´µ¯©›‰wmd\[YZ_cipxŠ”ž©­¦Ÿ–ƒ{xvttvy|‚„†ˆ‰ŠŠ‡…ƒ‚‚…‰Ž†€~€‰“žŸž—‘Š„~ytoooptw{€„‰Ž“™ž¢§«©Ÿ”Š€vtrpnmjhefik“¦²¾Á¹°¦œ‘†zpmiinsz‚Š”ž¨ª¬­«¨Ÿ’…udUY^clt}…Ž—Ÿ¨¬±´¶¹¯žŒ}obcehmqz‡“¦°´¸º²«œ…od]W_gosw{}€ˆ“«¹Â¸­ŸŒzrnjgecgjnrvƒ”¤³ÁËÁ·­£˜Š{kc\Yhx†‘œ¡¤§§¦¥ ›”‹‚wi\]`doz…Ž˜¡©²²°­¨£›Œ~o_PWer€›ª¹ÆÐÚÓÆ¹ªš‰s]MC8?JVhyŒ¤¼ÌÓÛ×Ðɹ¨—ƒob[TSSS`n}£¯´¸º¼½³©ž“ˆ~tjb\Ucs„’¡«°´µ´´©‘ˆ~ungfikvƒš¤¯¸Á¾²¦‘{e`\Z]`fmt|…Ž—Ÿ¨±¹´£’qbhov{€€{wvvv†–£ª²±§œ“‰€vmeeehpx€‡Ž”šŸœ˜’Œ†€zuoklmnqsy‰‘™Ÿ›–’‹ˆ†„ƒ„‡‹Ž’—£¥¦§¢œ–…{pecdepzƒŠ‘–šŸ¡£¦¦§¥œ“‰}ronmmmntz…‹’•—˜—ƒ{uos{ƒ‰”–˜šœžžž˜’‹€tmllpv}„Œ”œ¤«®°²²²¦™Œ|mccbbcco|Š–£®¶½ÁÃijˆ{meinsx}ƒ‰–ž¦°¹¹±©–hc^\aglquz~Ÿ®¿ÐÒõ¥“yqibZZ`gnw–­ÃÎÚÖ¿§”‚qonmkifb^aiq„˜©©¨¡‘{yx}‚‡†„‚~y|ƒ‰’š¡™•Šƒ{tmgbehlrw‚Ÿ©²»¸´°«¦Ÿ—ކ~voidfhoyƒ‹“𡍭­¬©¥¡™‡}sjihhhhkosx|€ƒ‡‰ŒŽŒ‰†„ƒƒ‰•˜›š—”‘Œ‹‰ˆ…ƒ~|~€ƒŠ–˜››˜•’ŽˆvkaVZahpx~€ƒ…‡‰Ž”š¡¡š’‹…}}}~€ƒˆ’”“Ž‹‰‡†„„……‡‰ŠŒŒ‹‹‹‹‹‹‹ŒŒŽŽ‹‰‡†…………†‡Œ‘–˜››˜•“’‘“—™˜–“Žˆ„‚€€ƒ…ˆŠ’”•–—˜™š›œ™‘‰€wopqrsuz‚В𢤦¨¨¨¤œ•Žˆƒ|yvromklnpw†Œ’˜Ÿ¥¦¤¢œ–ˆ€xofdefilq~Œš©¸·­£š’‹‹‹ŠŠ‰†ƒ~}}ƒ‰Ž‘””‘‹ˆ†ƒ€}yuqlnrv‡’–˜šœœ›š™—“‹ƒ{rikqv|‚‡‡ˆ‰Š‹Ž’–™œ™•“‘‹ˆ‚|yyy}ƒŠˆ†ƒ{rnpqv|ƒ„†††……‡ˆŠ‹‹‰†ƒ€€‚„…‡‹”–™™“‰†„ˆŽ”•––‹‡…ƒ…‡ŠŠŠ‰‡…ƒƒƒƒƒƒƒ‚€€‚„‡ŠŒ‹Š‰‡ˆŠŒŽ‘’’““““““’‘‘ŽŒŒŒŒŽŽŒŠŠŠŠ‹ŒŽŽ‹‰†ˆ’𢩠˜Žƒwpmifcadhlos{†š£«¨¦£ ž›™—•”’’‘‘’”—œ Ÿœ™‘‰‚~{zzzz{{|}€‰’ª¶·³°ª¤œ}n`QNQTX\`iqz‚Š‘˜Ÿ£¨«ª¨¦£¡™•“‘‘“•˜››™˜–“‘Ž‹ˆ„‚ƒ„……ƒ€~{xuroligikmoquy}€ƒ†‡‰ŠŒŽ’“““’ŽŠ‰Š‹”˜šœžžžœ›™˜—“ˆ„€€€€€{vqlgc`^\[[clv~†Ž”™ž¡¥¢™•Œ†}zxy{}„Œ• ¬´¸½¾¾½´¬¢–Š‚~zwuszˆ–›ž¡£¥§“‰€wqnkjihmrw~†œ¨°·½¾¾¼¶±¨œˆzvrpqrtwz„‘ž®¿ÌËÉÇͧ—ˆyllllllpu{‚Š’£³¿ÅʱŸ“‡|zwtqmhc^dny¤µ¼ÂÄÂÁ¶©œŒ{me\UOHSdu‰«©§¤¡žžžžš–ydTJ@RnŠš©´ª ˜”މ‚zjZRUXcsƒ‹’˜œŸ¢¤¥¦¦¦™Š{jYOPRTVXdr€Œ˜   ž›“Šztonllllptx{}€‚„†ˆŠŒŽ‰„~ukhkovˆŽ”šŸ¥¦¢ž™”ƒwk`URY`gnu~ˆ‘—ž ›—’Œ‡~vmg`[VRU]dt…•¢°¼ÆÑÏÇ¿®›Šzj[K<8<@GNVj~’§¼ÄÂÁ¿½º«œ~o`PA:62FYkz‰”¦¨¨§“Š…|zx}„Š–¢¬¬­¬©¦Ÿ•Œwniea]Zcq€«°¶»½À´ {iXK=4/+4CSdvˆž³ÂÅǾ­œ’‰€|xsnhaYR]kz¥´´´±­¨ ˜†~ulc[TN_uŒž°¼·²¬§¡™†€ytrprx~‹›«±¶¸³®¨¡š”†~vne][agow€Ž¬¼ÌÑÈ¿´¨Ž~obUMMMPV\qˆž®¾ÈÇÅÀ¸± |vqpx‡Ž•œ£ª®³·»¿¶¥“|cMU\ft‚ŠŒ‘’”¢±¾ÇÐÁ›vW:2GZjz…‹™£­ÀÒßØÐº‘hUI>N`ou{ŠšªÃÜíר‡f]admv~~~‡” ©²¸¬Ÿ”‰wrlllmy†‘™ ¤¥¥¦¦¥¥¤ –‹|iVX^ezŽŸ¡ž˜’“—›¡§©ž“‡{ov˜¢¦˜‰}tku‡˜¡ª®œŠ}vpw†”—ššŽ{}~‰—¦¢–ƒqhknx†“’Œ…}|…Ž™¤°¯¬©¥ œ–‘‹†|wrqpt™¡¨£œ”І„}zwtqv{‚ŽšŸ›“‰~~ƒ…††‡‡‡—ž§¯¯¦œ“‹ƒ‡Œ‘”˜—‘‹‰ˆ‡’ž¨©«£‘~rjagnuvxwrmqy¡¯«¨ “†€€€‚†ˆ„€|wrw…’¡°¼­žƒwu{†‹‘’“”•—›Ÿœ—’‚se\SNMMQW]ht€ ±Ä×Ôɾ¨’xpkgcejnty€š¦²½¶§˜‹~sqpnmmosv{‡—¢¦¦¤¢˜Œ€lWJJIQ`n}‹™§´½»¸³«£”„sbPGPYcnx~‚†ŠŽ’–šŸ¡›“‹ˆ……•šœŸ™ˆ…ƒƒˆŽŽ‡wtrqrty‚Œ—¤±±°¯ª¦Ÿ”Šthikmorwˆ–žž›š–އ{usqpppqsvz~‚†‹’•—™›˜’Œ‚wmmmosx{}‚„„„……†ˆŒ“–˜“ŽŠ†‚‚…ˆ‰‰‰„zywzˆŠ‰‰~rjkmsŒ“˜œœœœž ¢¥§¡—Œqflqx‰’“•› ¥¨ª¥š‡y~‚†ˆ‹Š‡„‚€}yuof^`diw†‘˜Ÿ¢¤¥§¨ª«¬ªœ€o^_djqx~€‚ƒˆŽ“—ššƒ{vqy†“—››Œ~smfegilnpsv|†ž¯¿¾º¶«Ÿ—“ŽŒ‹„~vngdlt|…’–šž¡¤¥§§¥¤š…~wsvy|~„†‰‰‰ˆ†„ƒ…†ŠŽ’’’‘Ї…‚€~{yvspmou|ƒ‹“•—™›žžžœœ—’ŽŒ‹–Ÿ£¥§Ÿ•ˆ‚€€€€€€„‰˜ ¡œ˜…}}}ƒ‡ŠŒŽ’“Œˆ…ƒ‰”™˜”Œ‰‰Œ‘“–––——˜™š›™–“Œ…~€…ŠŽŽ‹‰†‚{wssrrrrx‚‹”œ¤¤¤£¡ ›”‡{xuuxz…“¢©°µ°«¥ ›•‹†|wrqv|…›˜“Ž„{ttttvwpg^TJH[n Ÿš•’ދЉ‡„{skjijs|ƒˆŒŽŒ‰…€{zyyz{|„†‰†ƒ€|ywyz|~…‹‘—œ   Ÿœ™–“Šˆ…„„„†Š‹‡‚‚„†Œ’——–”‹Š‹Œ’”Œ‡|yxxwvusqoons|†š¤©¯³³²©–„yphnu|‚ˆ‘•™œŸ¡¢¢—„ztpmkjjoty€‡Š‹ŒŽ•œ¡§¬¥—‰~sjry€†Œ‘“”””’‹‰‰‰‰Œ’™Ÿ¤¤¤¡œ–•”“““’‹…}tjlpt{†…ƒ}†“Ÿª´º²«¤œ•†zurtvx|…Œ’™ §¬²µ³²«¢˜’ˆ…‚{xtplrz‚™ž™”އ€„‰Ž“——Ž…~wpv}„ˆŒ‹‚yuts’¢©°³ª¡œ˜•–˜š”…wjdfhp{…ˆŒ’—¡«¶Á̸¤xaX`hov|wrmkin|Š“š¡’rleguƒŠŽ’‹‚{{{‰’”’‡~wxz}„‹‹ˆ„~wqw|‚‰…|sjbjqy††{xvt{‚‡Š‹ƒ|xurvz}}}{wstuw|………ƒ€}€…‰‘˜œ–ˆ~sqrsvxywusqpv‰—›•Ї„‡“–šœ˜”‹ˆ‡…………†ˆ‰Š‹ŒŽŽ‘’”–˜šœ™”Š„‚‚„†ˆŠŒ”™¡¥¢ž™”Žˆvqppy†”˜œž—’™Ÿœ˜“Š|}~‚ˆ‘•˜¡¡œ—’Œ‡‚}yurrzˆŽ”–˜š›œœš˜•’އ€yxvx†Ž–ž¨±ºº»º¶±©ž“‡zmkhghiq®½º¸´°¬£—‹€vlosvz~…‰Œ”›¢§§¦Ÿzuqw~…Е𠦫±¸¿Â³¥’zb\_ajs|‚‰•š¡§­²·¸¡‰tcSYmŽ›¤™ƒ~x{„‘‘…zrolnty}€„…†ˆŒ•š ›“Š}pgjlpv{~„†‰˜¢«³»°‹}nekpvz~€„ˆ‰‰‰…€{xurrqsy‰”Ÿžš”ˆ…ƒ€}yuqmiipw~†–Ÿ¨¯µ¶« –Œƒ~zutrqtw{„‰•—š›™–”’ŽŒ‹ŒŽ‘”’‹„zpfkpw€‰‘—ž¤ª¯¯®­«©£™†~usqpppt}†”šž¡££¢ ›–’ŽŠ†ƒ€€ƒ†ˆŠ‹Œ‡€zrjkpu{‚‰–£©¨¢œ—‘‹‚yrkedgjnrw~†’—›ž¡ ž›–‰‚zria^]]aflt|…šœœœ™–“Šxoeeilptwwxy{|€†‹Ž’ˆ„{xvttvw|…‡‰ˆ‡…‡‰Œ’—šš™–“‘‰‚{skmrw}‚‡‡‡ˆˆˆ‰ŠŒŒŒŠ‡ƒ~†‹Ž‘”–˜˜——”Œ‰†ƒ~€‚…‰’—œ¡§¥›‘†zmmmnoqsx|…Š™ª¹ÅÑÒÁ°¡“†‚|yvsqnorvƒ’ ¤©ª¤Ÿ›š˜™›œ–‰€wv|Œ—¡œ–ˆ}„ˆŒ‹†‚~{‰”œ¤«¤œ•Ї‡‡„~vnhlpz ª¯µ¯©£ œš˜–‰wngox‚›œ˜“†‚ˆ–£œ}rf^hs|ƒ‹Œ‰††‡ˆ’›¡¡ –…tqpq€ššš”‰~€ƒŒ•™“Œ‚vinx‚Ÿ¦›ƒviu‰¯ÀDZ›ˆximy…‰‹yfZVR`v‹”¢˜ˆ†ƒ„‡Š„}tfYSY_jw…‰Œ‹‡ƒ€}‡˜ ¨¨§¥£¡–‰ƒ~zwsrppqsw}ƒ™££¢Ÿ•Œ…€{wtponmmmq{…‘©¤ž˜‘Šˆ‹‘”–Œ‚xrlp𤭦•І„‚zvnf_cfn|Š‘•™—”‘ŽŒŠˆ„ysnilorw|€…Š”™¡¨¯³¸²¤—Œƒz|ƒ†‡‰ŠŠŠ‰‡„‚|yuqppprtw{~ƒ‡‹Œ‹‹ˆ…„‰’˜žœ–‘‹„†Œ’˜ž™•’Ž‘•—™š˜”‘Œ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‰†ƒ~yssuvz}~|yw{€…‹‘”””“’’’“”””“ŽŠ†‚€‚ƒ„……†ˆŠŒ”˜˜˜–‰„‚{xtoiins{„І‚|uv€‰”Ÿ«¥ž–Ї‰Š‹ŒŒŠ‡„‚€‚ƒ…†ˆ‹’“••–•’ˆzywx{~€€€€ƒˆŒ’˜˜”‹…€‚…‡‹ŽŽŽŽ’”–—™šššš”‹‡„ƒƒƒ„……‡‰‹‹‹Š‰ˆ‡††………‰’™Ÿ¢¢¢ Ÿœ“Š€vklszˆ‘“•—™šœŸ ¢¤¦§¦¤ž–Žˆƒ‚…Š•šŸ¤¨¬­¥’…wvx{‚‰ŽŽ‘”—™œœ—’ŽŠ†………„ƒ‚|{{{ƒŽ˜œ ¢™‘‹‡ƒƒ„…††††…†ŠŽ”œ£–‚uoqty€‡ˆŠ‹‹‹Ž”š ¦­¨¡š”‹Š‰ˆ‡†„‚‚„‰’› ¡¡™Žƒ|uokhinr|‡’—¢¦ª¨£•Œƒ~{ywz€‡Ž”››š™˜–’Œ…ztsrrrrsvy}ƒ‰•¡¬®°­¡•‹vmc[[\`hpx€ˆ—ž¥«²¸¾µ£‘|fSY_flsutttuv€‰‘—œ•Š…‚ƒ…†‡ˆŠ‹‹‹Š‡„}zxvz€…𢢣£¡ œ˜”‹†|wsns|…”š•Œ‰†‹“›ž Ÿ‘ƒxrlpz„ˆ‹ŽŠ‡†ŠŽ—¤°¬§ŸŽ|ruy‚œ˜’‹€tpy‚™¥Ÿ•‹€upw~…Љ€wsoo|‰’™ š‘‡…‚ˆ’‘‘‰€wxy}ˆ“™™™”‰Ž•œ§²³ª ”†xz|ƒ‡‡€ztnipx€†ŽŒŒŽ˜¢¬¬­§•ƒxqinu{‚………ˆŽ•Ÿª³¬¤šŠyqmjjjkklmmnv„’ ¯½³©Ÿ•Œ„~wrmhijmrx‚’¡ª°µ¬£š“Œ†‚}zwutsty~†˜™˜—’ˆ†…ƒ€~{xuqp}‰• «© —ކ€‚„††‡…‚~~~ˆ‘—˜™“ˆ}yvty~‚‚‚}z}…Œ“™™™™—•‹…€zvwxz|~€ƒ„……„‚€€€ƒ…ˆ“•••vronu|€~zuz…‘¢Ÿœ•„‡‹—Ÿž‘„ueUaq‘ ¦œ’Šƒ}‚Š’•˜–ˆzrmhs“˜—ƒ}zw{€„ƒ‚€zuwˆ•¥³¬¥œŽyzz}…„ƒ‚€„ˆ‹Ž‹‰‡…„„ƒƒƒ„…†‡‰Š‹Œ‹‰ˆ‚|wusrstvy{~„‹‘—Ÿ§¦Ÿ™‘ˆ€€‚„‡ˆ‰Š‹ŒŒŒŒ‹‰ˆˆˆ‰–›ž ž—Š…~|zxvusqtx}…Ž–šž ¡¡ žš˜––•”””“’‘‘‘‘‹‚ysmjs|„ŠŒ‰ˆˆˆ•˜˜˜’Š‚|z}€‚‚‚‚„‡‹‘—ššš˜—•–˜š  ™•’ŽŒŠ‡…ƒ€€‚‰‘™¡¢œ–‘Œˆ„€||||€ƒ‡Œ‘˜ž¥£¡ž—Šˆ…„ƒƒ€~{xvx†Ž—Ÿ›˜–“‘ŽŒŠ‡„~xrqos}ˆ–œ™–’Ž‹‡ƒ~zuqmifms|‹™ ¡¡—‘Ž‹‰‡…vmcYO]kz‰˜œ–Š…€ƒ……†…ƒ€€‹”œŸ¢Ÿ—Žˆƒ~{yvrnry€Žœ¦¡›’…yw{~…Œ‰‚zqhmz‡“ž¦™Œ€wnpx€‡’‘’–ššš™“ˆ†ƒ„‡‰‡„{tqv{ƒŽ˜˜–“‡„‰“›¢”‹‚yu}†Ž•œ˜ˆ‚|x|€ƒ…‡‡‡‡‰‹Ž•œ   ™‘ˆ„€~€|yupkpv}ˆ“ššš™—•“Ž‹‹‹‹ŒŒŒ’“•—™™™™“Œ…‚~ƒ‡‹Ž‘’’“““’’’Ž‹†}‚…‹‘“’’ŒŠŒ“–š™’‹„|uz…Š’’’““““’‘ŽŠ…€}{y{}€ƒ†‰ŒŒˆ……„„……†††‡‡‡Š‘–›žž™”Œ‡„~}}‡’›¢¨¨¡›–’Œ‹‰‰‰‰ŠŠŒ’—œŸžœ™”‘”˜š˜–“‹‹Œ’”—š £ œ˜”‰…|~‚…ˆ‹Ž‘’‘Œ†€~{z|ƒ„………ˆŠ‘”–”‘ŽŠ…‚€}|zwtqnjgjnrvz}~€‚ƒ‚€~|ywtqomklnpqsuwyz{{{{{|}~€‚„…†‡‡‡ƒztokhfdbadhknrvzƒ‡‹‹‰ˆ†ƒ~vmgb]afkosvy{}€‚†‰ŽŽŒŠ‰‡…‚€}{zxy{}€ƒ‡ŠŒ“–•‘Œˆ„€„ˆ‹Ž‰„€}{ƒ‹’–™™•‘ŽŽ“˜›š˜“‹‚€Š’™œ ¡  ¡¢£¦¨¨¢›”Œ„ƒ…‡‹Ž‘‰…‚€‡“ ©²¸®¤›•“—˜™™“ŠŠŠ— £¤¥ ›———˜œŸž›˜–””””••“‹‡ƒ‡Ž”›¢£¢¡¡  ¢¤¥¤¤ž˜‘Œ‡ƒƒƒƒƒƒƒƒƒˆ”Ÿ©°³µ±«¤Ÿš–’ŽŒŒŒŒŽ‘“”•––––––—˜š›œ›˜•’Ž”—˜šš–’‹‹‹‹‹Š‰‡…‡ŠŽ–Ÿ¨¨¨¥ž—‘Œ‡‚~yxwvvvzƒ‹•Ÿ©¤Ÿš”ŽŠ‡„~|{{{|}ˆ”˜›—’Ž‹‡………………†‡ˆŠ”˜™—–‘Œ‡€ztmgefgjmpv}ƒ‰”–˜š›œ–‰ƒ}xuqpppz„Œ’——’Їƒƒƒ‚}ytppsv~†ŽŽŒŠˆ†ƒ~|{zyz}‚…‡…ƒ€~{xtqnlkqvz~‚…‡ˆ‰‰‰‡„~{wsonllnpsvz~ƒˆŠ‹Œˆ„ztttttuvy{~€‚„†ˆ‰Š‰ƒ~zvsv{€‚‚}wtrqty~~~}yurqqrtvy|ƒ‡‹’–š™”Žˆ}|{zyxyz|}~ƒ„…†ƒ€|{yz}‚ƒ‚~~…‰‹‹‹‡‚~}{yyyy{|~€ƒ†‰‹Ž‘”–˜šœ™”Іƒ‚‚€}yuqomntz~‚……………†ˆŠŒ‹Š‰‚|wvuvy|}~€€€…‰Ž“™™—•‘ŠŠ‹ŒŽ‘‘‘‘ŽŠ‡„~{{{{|}ƒ†‰Œ’’‰ƒ}{{{~‚…‡Š‹Œ‘”—š›˜”Œ‡…„‚€‡’—œžŸŸŸž™•‘‰„zxvuy}‚‡Œ‘—œž ¡Ÿš–“І………†‡Š•›¢©¨§¥¢Ÿœ—’މ…†ˆŠŒ’“””“’Œ‹ŠŠŠŠŒŽ‘”–™ ¡Ÿ˜“Šˆ…„ƒƒ…†ˆŠŒŽ‘”˜›žžž˜’Œ‡‚€€€€…‰‘’‘‘Ž‹‰‡„„……ˆŒŽŽŽ‘’”•–——–•”’‘ŽŒŠ‡ƒ}{y…ŠŽ“–—™š›œ›™—“‹„~|{z~‚†‡ˆˆ‡‡ˆ‹Ž‘”–•”’ŽŽ’”•’‹‰‰Š‹ŒŠ†„‚€‚†‰Œ’”—™šš™–“Ї„‚‚ƒ„„………†‰Œ•š˜”‘Œ‡ƒƒƒƒƒƒ„„………†‰Œ‘”’Œ‹ŠŒŽŽ‹Š‰‰‰ŠŠŠŠˆ‡†††††‡ˆˆˆ‰‰‰ŠŒŽ‘“”””“’’ŽŒŠˆ‡‡‡ˆˆˆ‰Š‹ŒŽ’“•–•’ŽŠ†ƒƒ‚‚‚ƒ„……‡ˆŠ‹Ž’’’’‘ŽŒ‹‰…~{y|‚†‰‹‘’”””•••”’‘Ž‹‰„{xvuuuvwxz{}€„‡‹‘‘‘‘ŽŒŠ‰‡…ƒ€~|~€‚„†‰Œ“–˜–”’ŽŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹Š‰ˆ‡†„ƒ‚€€€€€€€‚ƒƒ†‰ŒŽ‘“Їƒ„†ˆ‰‹ŒŒŒŠˆ‡†…………†‡ˆŠŒŽŽŠˆ†……………„ƒ‚€~{xtpmnprvy~„Š‘˜Ÿœ™•‘Ž‹‹‹ŠŠŠˆ‡……„„…‡ˆˆˆˆ‡†††‡‰‹‹ŠŠ‡„‚„………„ƒ‚‚‚€€€„‡‹ŽŽ‹ˆ†ƒ‚„†‡ˆ‡…‚€„‡‰‹‹‰‡„~yttuw}ƒˆŠ‹Œˆ„€|xy|€ƒ‡‰ˆ‡‡‡‡‰Ž“•—™”މ†ƒƒ„†‡ˆˆ‡†……„ƒƒƒ~{xtrrsux{~ƒ†‰‹’“‘І‚€€€€€€~~}}}~€‚ƒ…†‡ˆ‰‰ŠŠ‰‰‡…ƒ€€‚ƒ†Š‘•—–•“‘Ž‹ˆ…ƒ€‚…ˆ‰‹Œ‰‡„‚€€€€€€‚ƒ„„…†‡‡ˆ‰‰‰ŠŠŠ‹‹‹‹‹‹‹‹ŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰ˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠ‰‰ˆ‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠ‰‰‰‰‰‰‰‰‰ŠŠ‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰ŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹ŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š†‚mirrormagic-3.0.0/sounds/snd_classic/0000755000175000017500000000000013263212010017121 5ustar aeglosaeglosmirrormagic-3.0.0/sounds/snd_classic/exit.wav0000644000175000017500000011266313263212010020622 0ustar aeglosaeglosRIFF«•WAVEfmt "V"Vdata‡•³±¯®­­­­­­®®­­­®¯±²³³³³³²±±±²³³³²±°¯¯«¦¤ª°¯ª¥©®±²²®©¦«±¯«¦¦¥ ——£ª¦£Ÿš–•“˜¢¬¨£ ž¡¦«¬®¨ž”Š€‚”¦ª«ª¢™˜™›¥®±®«¨¦¥§¨’u^q‚‰‡…–¨©‘zˆ °¤™Ž„|‘§®¤š›Ÿ¢¦¨©ª§¤¦¬²¯«¡Šu‚±¨žŸ¨°±²³³³“mOOOdƒ¡¨¯³³³®ªŸ…kfjl_RKKKLMQ[e~š±¨ž ©³³³³³³¦˜‹…€ŠŸ³³³¯§Ÿ€^FGGSbsŒ§¨•“¦£yODCAAAAAB[s€|xfPLx¤³³²¬¦¦¬²³³¤yLa²«¥¦¬²š‚}•­³³³³³³³²§œ‡gE@@Hex[@@@Wƒ¯³³«”}ˆŸ³³³§’~fO@@@JU[PEL]nvx^DVny`H`‹³³³°­©›Œˆ™ª°±²®ª¢–‹„r[Ee‘¯Ÿy\AAAELSt™¥zMFMVl€’ ®˜|”­e@@@DIMMMNQSaq}zw„œ³³³qE_€š¥°’g@@@McydNBGLORWj|Ž ³³³³³³aADGVj{dLNj„ƒ€ƒ˜­³³¬€THTan{~qd[TLGBTrއ€s[Df£yN_‹±§œ…eC@@ETb`YRKDZ†²†[R~¨Ÿ‰”ª°¬¦VJ_scOBGLJEAAAAAAj–£wK@@E]v‚ˆŽqRNn”•™¤¯™rMHCV®‹_Lr˜˜‰zcK@@@@@Kh„uXEZopeYYYULBf‘®ŒŠŽ” ¬¬ ””•———ž©¯”yvƒ’tTBGLJD@@@@@BnšŸsGSi|ƒŒ{\Eq³³³Š^@@@b«€TNghO@@@Uo‡™¬–k@@@HXg\LFZn{…‹nOXƒ°’p^lz{xz‘©³³³‰`MZg\MF^unWCp›³³³‹`@@@Qi|n`TKA@@P{¥“pVbohTACFFDA_‚Ÿ§°³³¯ƒWV€¬±²±ª¤§­³³³šoB@@JbzlT@@@IXf~•’lF@@HcuZ@@@PnŒtU@@@@@@@@Z…±ž‰yndWK@@@Phn]dˆ­ŽfGDA_‹³³³œpDLY`ZUNG@@@@@@@@DNXRHKw££ŠsolbRBPau§°±³³³£„gkr~”«d@@@@@A_~‘–œ•€eJ^‰±›„z|}hQ@@@@@ADFTkmVGDA@@@@@[†° „~wdP@@@Ph~€Œž±³³²°¯°±²«¥¦«°”x`RCd©~Q@@@@@@@@CFS|£¦˜Œ›«¡\ahq{„sgWG@@@Zt€uk€œ®˜‚wpk†£ŸwMEB@@@Ur‡kN@@@CFGDASk‚–ª™mA@@S«³³¨}PY€ {UU€ª°±¥zM@@@@@@@@@@Q}¨¨š‘Ÿ­³³²¤—”¢°¤“€eJ@@Doš©›ŒqTH_wlUEc–¤²¤”€dG@@BIQj޳³³³³³aG_xŒ ¯‚W@@@EJQZcnz‚}x‚š²‡\Q|¦Œb@@@[…­‚X@@@[y†iJ_‹°˜€€˜¯•ym—ž¡œwQ@@@b‚›¦°ŽcF`zŠ—¡€__„ª‰_AAAAA@@@Oj…Œ’š¥°ªŸ’{ci‚œ…ohv„qU@@@Ndx|€}pc}›±²²³³¯—€wz}{w~•­¯¬©­±˜l@@@T€««£“pLRl‚€}pYC@@G]rhSD\uŠž²¡Žz`FFN[€¤³³²™€l[JS`mz†Ž’—¡ª¡†lbY`„©³³°Šu[A@@R}¨–we…¦³³±„Y@@@@@My¥”iAAAXƒ¯ž‡ui\RI@@@@@@m˜­Ÿ‘y]IPWo¬W@@@h“³³³“hFrž¯©£’|‡””‘‰kMK\nx‚yommq€_AAAV®§›‚wy€ˆ•£’kBk—¢vJc®™ƒnWAYpynciqxz}yspŠ¥œqD@@@@@a‹­’ykfbktyyy€ˆ‘Ÿ­ž~^juueVs˜¬–€yy|‘¨¥Šp†¡®¢–‹v`J@@@fŒ¢Ÿ€{’ª¦’€”¨¥†iv‰š¤¯¢‹z¨¬ “‹‚|ws„³³³§“lYTbqcO@@@@@ACFRg}¤­šˆ€|sjv“±”v]PCPdrmho€–ž¥«²ž…o[HAAB[sˆ›¯‰^EQ^XK@@@Yƒ¯‰aQj{q]HNdycM@@@Ul‚—¬³³°“xlpucNO|§³³­ˆdOHASfy‹Ÿ¤§ xOW{œŒ|—¯±°¢yN@@C_zˆ‹Ž›©£xKJW_SFZ†²³³©’|ƒ‘ž§¯³³³³³«œŒ€srŽª“hC\tsZB@@@@@Sl€†ŒŠ‚{eNENXs‘ €_OGDpœ©•…™­ ‡rrsyƒŽrTLjˆƒuo‹§£‹s_LJax{zt^HDIQwxQPRXftˆŸ³³³§“€~|yvˆ ³³³¤Œvvw€’¦‡ŠŽ{\ACFZ} ¨®«•o`RKDOi‚•§³³³ž†tvyre[~ žsFN^ls{ˆ‹qUQdvdN@@@M\oЧ˜mAP`ga[u•­©¤§­±’ueeejp{“«³³¯’wdYNf‡uj^Z\]RGLe’¥³³³•jAHP\m~£ª—„q^OXav“±±¯§’~…‹Ž‘…oZdnkWCEJMKHQ`ntzƒ›¤­¬˜„}yy¨³³³±¯ªŸ•œ©³³³ªœŽˆ‚‚Š‘z]KXed[SSSUY]jw‚ŽšŽ}o{†‡|skipxoc\hsy}€”¨³³³³³³³³ ‡ruxyyyz{~ƒ‰…~|’©©šŠyrnjnsxy{~€‚€r[CRftx{Š ³³³¨“€~|yrk™¯°²£‹t}…‰†ƒ‰‘“…xw{}fNIYht€…lU@@@Oi‚•§²°¯­ª¥’€sh]ZVc†ª™€iWFQj€‡™¥²©ž•Œumƒ™¦¬²œ„y|Ž ¯°²«ž’ƒuoqsoihpy‰¬–ƒš±ž‰zwtx~ƒ„†xnv~|iW`nvgY]jy¦²°¯‰zvskb]w£ª¦Žwtw{ƒ‹ˆ~tz€ƒƒƒƒƒ~y€‹•ˆ{jVBRf{‘¨°±²®ªˆtj`^kwŠ¡°¥›‹xfnw{{{€†‰…€}zxxyyxx†—£¦¨ŒhJ]o„›²³³©’|xyu_IOf{xux‚‰ƒ~{wqkh}’ŠgCGORMISap}‰‡{nprz‰š£¬³³³©™Š…€€‰‘““–¢¯³³±¥˜•˜œ–Šˆ‡rW@@@CIN_qzvruz|tlsy«¬žuVIc|ˆ˜£®§‘|¥«–~‚—«¨—†s_V[aWJG_woWBP^kw|sv«®¨xQ@@@Wo€†ŒŽ­³³²²±°¯¯°±¬“{k_SLEIVda][`dghnЦ¬¡—¡¬¥„dXRLGBQkƒ‹’”‹ˆ…ˆ™«±±®š†|zx|€€vl`RGDBFPYm€…yl€³³³¨™‹—¢›€e_\^ly€†Œ›ª°¯¯°²«•€qd`‚¥¬¡–g[`eb][_d\NBUhv€‰‰ˆ‡‡‡•Ÿ¡’‡—¨³³³³³³³³¨—†‚~}€‚€{wurqqp`PIKMIDGZmu{|yxyyz{}€‚€~yoet’¯°²³³³¡~{w}ˆ‘…y~’§¦¤ž€th\TKRduuux…unoqswyxvusrxˆš­³³°–~suw‚•Œ„|vx{|}}}|wk_TIHf„€iTbpy|~~€‚Š”ž¦¯²±±›…{ƒŒŒ‰ˆ‘™›™—ž¥¥œ”©®Œ~oa^[^gqjc][Z_gow€vnz†‘’Ї‡‡€uj~‘™’‹ƒzz§¦š—Ÿ£££‘€zŽ£§¤ Ž}snjZJKe€~€•«¯¨¢’ƒŽ›†lWMCPf{…‘™ž¢“ƒ~ˆ”Š{kYHNe{|}~p\MKHP]k€—¥¬²«¢ ¢¤¦©©©¡”‡„€‰‘““‘‰‚†Š€wiWDUm‚žž˜‘rgc^`cfhiz¡”ˆ}rfxŠ’†z‡’‘Ž‹’™ ¨¯ª¢™sbUfw‰±©ž—————–‰ƒ}v~…ˆƒ}||}}yuh[Zhv|€|utuvxzzxvka[`d{—¬ ”Š‚|†•ž§¬¡–ކ€€‚…‰Žˆ}|zz{}Œ›¡Ÿ¤­¬™‡€}ywtvz~‡‘ŒrXX]a`^_`bipw†‚{wtrpnqtuuusolifs„•¡®³³²§”އ•¦³³³®¨¡utttuvy{„‘œ–‘Ї…ƒ€zsyƒ‰€yl\N\jsuwy||xskb[jxƒŒ–Ÿ¨­¨¤™ƒ„†‡‡‡— §¯¬§¤¨­¢}{yxyyqhbeitމ…|m^_`guƒ„€‚…„€|xusrrstvy|}}}}||~‡———„||}€‚Š’•Œ‚wnqtx|~~~~€‚€~{{{…™®§•Œ„}uutm`TZa`RDRi{{{}€‚€||€†ˆ‰‰…€~|z~…‰Ž“™£«²«¥ž–”™™‘ˆˆ‰‰ƒ~mWBZr~{xyz{{zsjaaabdemtz{{yut€’˜¢ª®²ªŸ”‡|xz|‡ˆ„€yrpv}}yurouƒ’–š—ˆyrmly…†€yxvvy{yvtx|‰œ¯°²°©£–ˆƒ‘Ÿ™‹|y|‚Š…{xvuuutrsvyhWQ[dhkmmmoqt|ƒ„€|ޤ³³³±°­¤›‘†|zxwwwqhdo{xmbjswww}‚‡ˆŠ‡}}}}||{z|‚‰‡‚€‰’§²¨™ §ž‘ˆŒ‘ކ~||~}{zz{{zz{}}||{{{xvmb[fqvww|€ƒƒƒˆŽ”𠤦©­°±­©•€qqqpomjgipwww{…Іƒ€€‚yoiiiklov}†’œ—‘ЇޗŸ¨°®¨ €xurpnhYKNW]\ZXVTany…‰Œ‡€„ˆ˜¢§«¯±²®¨¢™œ¥®¯¯¨—†€~xiYW\bhnk]OZitw{€ˆŽˆ‚znbaadjpuz€“¦§™‹Ž‘—¤°³³³³³¨—‡“‘‡}{zxrkfb^gov{‰•˜}yvx{{zzŠŒ…wokpvyz}’§ª™ˆ€wuˆ†€}Œ› ›—‹€}†ˆ|s}‡‡‚}vniiihgj|𥭗‚{‚ŠŒ’Ÿ«¥™ƒzuuubMGXjmmmjgintvxyxxyz~„Œ•Ÿ§•ƒ}€‚Œ–˜Š}…‹ŒŽŒ‡ƒ€~ytŒ”‡z{‚‹š¨­¥žš˜”Š€…‘œ•Žƒugnw|xty€ˆ™–Š€€‚€~{yvodZgu{{{yww{~ƒ‰Ž‹ˆƒ€wony„ƒ{{{€‡ª³³³¤“‡‡‡œ§–…{tneZQJCAADUfs}†‹‘Ž‹Œ„}z{||}}{zyy•«³³²§œ“‡Ž—𑉂}wwvuuui\V]dnx~yqjpvz|}}}znadnxy{†Žš¦¯°°¦—Š„€€ƒ†Š‰{liikoty~ƒ’¡ª®²³³²±¯¦™’•‘†|xtsy~€ƒ†‰†€zyyyxxoe_chhgeWIELS`ny~€~}…ŽŽ„|zxxyy|€ƒ„†…‚€’¥±²²³³³³³­¤œ“‹„zqhdkrroo|‰‹„~{wvxy}€‚{vpjmpsuwwvvx{€‡”š˜‡|xz{|}}zwrlfq|„‰Ž˜ ž–ކ~yxxz}€‚†„~€‡Ž‡€‡‰{wvvxz|}}sg`jt|ƒŠ…€†™¬¯¯«Ÿ’Š„}{|†‡‡‡‡‡š¡™’“–“Š€upljkmlkjnsvxyskd_[alvz~}|vqnqsvyœ ›–•“’š¨°¥š„{zx|„ŽŠ†‚|€…‹Ž‘Ž…~€„‡‰Šˆ…‚{xvsssuwy…Љ‡ƒ€{{zxvtsrog_`cfmsuuuwyywvuuvwyz{|‡‰†ƒ…ˆ‰ƒ}‡™¨¡š’ˆ€ƒ‡Œ‘•”‘ŽŒ‹„}€‚™¤ª°¥‘}{wsnrv}ˆ““Š…~~Š™¥«±§—Ї„€|wwvwz}|ywwvpibjruuuwxyvtpjfilqxyrnqsssu‡ˆƒ~|€Š•”‘‡€ƒ‰Ž‹ˆ†„ƒƒƒƒ…†„|ywvvwy|€…‹’•‰…€‡Ž•›¢¥§¥šŽ‹‹Šƒ}vpjd^]fosvx}Œ®¤™…}zwutrrtuuuvwwvuu{œ§˜‰€{v~…Œ’…~|~‚†ƒ€€‰‘š¢¦ž•Œƒ||}~~}{{{{zyyy€Žœ˜‚‡Œ“š˜‘Š„{zzyyyyxz}~|zvrpolgc`_^eklifjorssuvy„‡‰‹’™ ©±¯«¦œ’’“““ŽŠ…~}|||}€ƒ†‚~{xvwxzz{|~€‚…‡‡‡ˆ‰Œ•’Œ†‚}{zz{|~~{yxvuuulcairvy{{zyxxxyyyy|~€‚€~|€‹– ª©“~z{~Š——‡ˆŠ‹‹‹‹‹‰„€…Œ™§¨œ…|vxy{|}}}€‡Ž‹‡uw|}zxurv{|yvutux|}}~„‹‡ykloruwxyyyyyxxww|ˆ””‘‡€› œ—Ž…~|{zz|~€‚’£ªœŽ…~z…‘…|vqmmmortvy|€‚€ˆŽˆ’£¡—ƒzy€†‹„zxyz~ž®“yknqqqqpnic^dju…•¤¢Ž{€›‘‡Ÿ²ŸŠxgW`o€“¨­¨¢œ–Žƒyxy{€…Œ•›Žzxvqmiiit‚©¢x|€€zsx€†‚~€Ÿ¤š‹†}wuuutrpmjloz’¬žƒnqt€¢w~…ƒ€{ri^SIr™¤wplkryyvv¥ªŸ“Šzvry‚Ї„†Œ’Œ†„‡Š‹‹…q[c|’Šƒ„›¤­³³³¦•ˆ“š‹|{z|‚‰‚wou{wlbioy†”Œuuux{}wqmmmrvs]GN_nswz{{rhfq}{vsx}{tnˆ£³³³³³°¨Ÿ¢«³³³£ƒdp€eHRizbK@@@Tg{ŒŸŸš”Š€yqj~‘ ¨¯Ÿ‹~~Œ ²®ªˆsg[SPNORWkƒzyyŒš€w†—“„x€†‹Ž‚tihfimtŒ¥±²²³³³³³®¨ |}~ƒŠ”¢°¢Ž}ule_ZbieTBg’ª–‚{wtz€€~‹™—yZar}zlVAWmuj__`a`^VKDpœ¯©£–ˆ„”¤«®¯¡”“›¢‡kVLCTl~ytqomaTKFAKXhš§­±£•„p[_eo€’]CQ__SHhˆ—ˆz„•¤ª°–kBoš«š‰‚}“¨‘gBRbigfoy~{xpfcƒ¥³³³–zq‚“ž§¯°²¤Œx†•¡©²¢|bHNbq]JK_raMBGLl’° ‘…~v€Œ‡mRn“¨ˆiVK@@@@@@GN_ƒ¨§˜‹ŒŽ–£°ž‹†š®›~kˆ¥¡‰qaQFDBQdqnk}˜³³³³³³Ÿ‰|€‚€}v`JRpŽ€oiqzyvv€Šˆv{€x^Dg’­—lUC]wwn„ž¨•xpku|¦¯§ž¢©¥{P\‡°­ª¡‘jRFZni[MHCDLScsym`w—­‘u`PAm˜©‘zk]TX\k€qQ@@@GNSSS_n~‘¥£Žzޤ³³³¡‹}‘¦žƒj†¢¨wcODP]nqQLd{hQO{¦³³°›†‚Œ–wU@@@Vr„{qptxަ¬œ˜§¯¡“€iSKDLczm^QJBa³³³™nA@@BDGECEYltuvz}t\Dg“¦{N@@CUhty}}|t]F]ƒ¡–‹¡²³³³³³³³¨}P]‰±‘rhuyp^MFC@@@@@@SgmYFUoƒƒƒŽ ²£“…yl|’¤ª°§–†…ƒŠ˜§–‚vxy‰Ÿ¯–v{’¦¢wJPdx©£‹tx}€‚™Ÿ“‡rX@@@Ld{hPADGeŒ«uv‹¢•‡~{xgQEYnvwx¦ŸsG[yŒ‚yvwz§§’}‡” ¥¤Šqv“°­ª¡}hRE[pxzzdMQu˜˜’’ ®¤ƒŠ’š£ª®²±°©‹nt“²ª¡ŽkG@@F_w„†xihw…|ognt‹•ˆ|kWBAAIaxkTDXl}Œœ™•†jLXk”©¡‰t‰•£±š€pw~ƒ‰Œ}mb[Tw›¢vJcŽ«qkt~…Ž„eEf’³³³£Œxy{{zzwu|“¬³³±¦›~naU]‚© ‹~ˆ’aASdfTCPammm€š³³³³³³³³®¢–œ¨¯—€„›²²±¥‰ocZRJC@@B]yŽŸ°²±«šˆxrtvy|}y|‡”Œp\IFPZ^c`QCe‘¬‘weYMHCV®©ž•Žˆ“¤³³³³³³ˆ\BDGECIv¡³³²¯«ª¬®°±³³³§–†ww†‡‡€gNVixmbnЍ¬¯§Žwsvwuruz€‚…‚yo„Ÿ±«¤”€mgaXMAKVi‰ªžƒmmmqw}‘¦³³³™zh…¤‚jnsvwwxys]G`‹±£•€aBUkz|}Œ¡®“y}—²³³©‘zne[PD@@BVk€–¬•zis}„ƒiMSt•¡¬³³³©“—›“„v€‰ˆƒ’¥«su†•~fbt…~touzŠ ¯–srrzˆ’zZItž™vTcqth[w™®ŒuYDo™£wˆ‹€uw~€iR_ˆ²¢‘sdejq““’Šƒˆœ°³³«Žre_\t‹…eCKVe|‘†p`p€ °±²ª•€~€†Œ—¤¯–u~…‚}xrky ~wy{fOH\q‡Ÿ®”|svz‰™˜jvˆ–•“~^BXnxvtx|€…‰–¥²²±£Šsf[[o‚„zri^T_…¬ž…sokpzƒƒƒŒž±œƒtwyyxt_JMd{{zwogw‹œ˜”’«²°¯°±³³³¥‘€‡ƒzxww{~{{ˆ‘¨š‹€{udPIršª®¯˜usr€™Ž‚oVBKUapyrhZKOYcjq{†’¨¦‘}‚Ž•‰ƒ€||}~}z~•¬±°¬™…ztnz†“–“ŽŠ‰‡€wnquvrnw‚‰‚|‡ž°r_YTMFLp“£«°¡‘ˆ‚~‘¥­Ž†}xsojfv…’š¡“‚reX\hv¦¨“o^Yj{„„saan{‡Œ’‘Œ€vpliYIMhƒ•¦¬•|ˆ™ª³³³¡‚€~}|}‡’Œ{jmprtuŠ•¢®§”ƒƒƒ‹®¥˜Œ…~|}}}}ˆœ±¥—ˆubUJ@@@IWfkpw€‰” ¥˜‹„}{z{{„𤮣~qdbksŠ£°ª¤•ƒuroqv|}‡›¯¨œ‡‰Ÿ²®ª†p^LEQ^hrywux€†–¦«ž‘‰‚ydOFCAXovk_emsssަ®­¢—‘‹…~‹ °ª¥¥ª®œŠ€‚‘¤­‘wbQ@@@EOXhx‚€…Ž—œ œƒ{wvvuuw~„„€|{{ytnsz€€‚€}z€‡ˆƒ~¤±­ª~rgoˆ¡¥§¡zhVGGGRctvxz{{‡—¤©¯£}zwlWCPbmmmrx†Ž‡€£¯±²³³®™ƒ…—©©© Œyla\gr…±œ‡|yvspmmmt|…“¢«¯²³³²°¯¢“…~vohbmxs\EThy}zma^[\aer‡‡‡“¤³³³³³³œ†}„—¡¤ŽyeR@@@@@@LXft‚’£³³³ª™ˆ‰Œ‹€vhZOZeknr}ˆŠ€w{†‚€ƒˆ˜¨±±±±²²°¯£”‡”œ§²¤”ˆ‚}vogZMNXa^[cz–š™Œ€qbT]ebRBCFM_qutuŽ…~‚‡ ¯±°¯¯¯¯±@²¯«ª®²Ÿ‡z„”•–Œƒ~~qcWPIMT\jx…”¢ ž™Ž„xrmgeeedb\OCXq}wtsrtv{€†–§±­©«¯³³³¯©£’‚z}Š˜£¥¨œ‰vaL@@@Six|„Œ‘‡~xursup`QZjx{~ymbktxurv{Š“ž¨¯ƒWV®³³®žul€“‘~j„¡­Ÿ‘˜¥©Œq]NAeˆ–‡zl^Yoƒ}gSLD@@@GOXgvo`TX\cmwus{”­³³³³³§”ƒ–¨¨y€™¤¯²±±±²±­©ŒnVMC@@D[r~‚†…ƒƒƒƒˆŽ‘ˆ€ŠŸ±Œg[l}jRF[onc[fr‚™¯°¯§“€€ˆ‘Ÿ­¥ŽxŽ¥«š‰‘Ÿ©­±¦”‚teXMBTjvkau–²¬¥¡Ÿ€aWrŒ™¢¤‹s`QBWlx{}jRF[pz}~eMMg€Žš¢Ÿ‰p\jy|undZRMHEC@@@@@AZr€ƒ†ƒ€}}}{xv€Š–£±²±®¦ž€qpnnpqŠ£³³³³³³³³³³²±¯¥‘~uoiiiv‡”hcmwŒ£±­©™„tuw„›²³³¦ˆkltz{}}|{odXMB@@Nz¦•lHJLc‰°…wvv}†‰kM@@AYqyk\akxª¥‘€”¨£ƒeho{“¬¡ˆtx|qYAHOZjz¢¯š†t`Nk†˜šœ¤¬¬•†³³³ª™ˆ~tj]Qj‘³³³ªš‹‘˜™‘ˆ‘ž¡€`OHAAA@@@QdlYF^‰±±±±²²³³®¢–{[E`|‚zraQLV`{𱍠†cB_|ˆƒ~€ˆš­ž‚js{}zv|‚ƒzp`ODYmƒ›³³³¨ŽvbODRaq‚’…zjVCGNV_g~𲱝¯±²ˆ]Q}©©ŒmMOhjTN_ozƒ‹Ž‘”••ˆ{€—°³³¬˜„pZJXgdRA@@@@@KWbehnu|‡‘¡°³³³³³¤ŽycLW­£”‡|pz‰”†x–®š…˜®¦—Ї„sYBm—›qF@@Hb|rXDb€‰€vwxr\FRjzbJRqŽqS@@@e³³³¤Žz€‡„vgjp{“«šxXOEPm‰u]UjpV@@@Tt’†{~•¬±²¨|P^‰³³³¨’~gP@@@Pfyrlnu}|z—®Ÿ…v©¥Žyyy‚™¯³³ª‡ebn{Ÿ¥ž—‹~oZFHQ_€£³³³³³¦‡hir~”ª¦’wnlqwvslYFK[lˆ¤¨“¥¤xLN_ov}s]HhˆoNWju_IRm†vsuwƒ’–ls…˜£­³³³³³³³³®¨œwPGR]Ÿ­¡•‰~vz~}zwvt|Ž –ˆ~}ybKU{¡YQ}©©ŒmMELTu•¢‘‚‡†wgdghXIPpžª©‰jZPLk‰tŠ¢­£™Ÿª¬Žqfhihfs®aHe{cPo•…wx{xhX^mz|~uaNU]]PCd±«¥‹fCo™ª›Œƒ|uuuhTAAAGTaaa]PDb¯—€‚𲢑ž¯³³°£—‰{m[J@@@h“±«¤‘x`SFFR]q…—£°³³°¤˜€`AUjmXDe‘¯Ÿ•¤³³³­ ”žª±­ªœ‹}wpdSA@@I_uŠ °¢”‰ycMGUcvˆ–“”›¢œ–Ž…|wqhWE]‚ž‚ff|’‰€˜®¥”‰–¤¤•uS@@@Rg|’©¨š’Š{klot{yj`o}~tjiiknqux¢«¯²¦™˜¥±Œ`Mz¥³³°ž‹v\B@@Jc}~wv¥¢zz{r\ERf{’ª­¤œ|„y_PZceei†¥°­©œŠ’›£¬³³³¯©¢}iWDPcpjdaacxŒ’ˆŠ˜—qKHQ^  …jlpqonsz{bJ@@AYru\DUnƒ“£«¯³³³¦vvxz{{zwsdTWhyŽ¥°ª¤›’™¤«¯²²±±±±±²¬”}of\QFLbx|~}z{’©§“€zu|”®³³²²±”j@@@Mf€yxŒŒ‰€vpmjgcdlt†œ«š‰t[BVj–®«£™‹~‡ž± „€|jUM_px{|qf]VN[i{“­¥”…€|†œ²”wglqv{„˜¬Ÿƒjkmmmm~Ÿ¨°¤{w‚š²ž‰|xt€¢§•wYPF@@@Ul‚—¬£z„Ž—Ÿ¨„\H\pzƒŠ‹r_LH\p†Ÿ²±¯¢}|zƒ™°©ž”…¢²©¡˜‡nR@@@_‡¥’€€ŽœŽ€si_dmtuw}ƒŠ„{zzfPFZn„²²±¥}zx}Й𖕡®³³² zbKECCNZj~œ¨¥’zvsssssu‚‘†|£¨ydPF`yƒƒƒ——‹„Œ–¢®±°¯°²³³³›‚m_QXgu|ƒ‹”œš˜}is‚‘Ÿ­£ŠsbQO`qsso^MScs€ŒŽ„|{ztcR\o‚•¨±²²³³²±±Ÿ‹yk^[_bq€Š“›Œ{osx€Š‘†{usrjb][Z]bcUGHS^foy†”†ƒ—¬³³³³³«œŒ““ˆ}~~vmv‹¡—Š€xoqt|’©¯©¢’‚yyy}€{ttx{tmlpuhXQ\g^NEc–¤²³³«™†|qkqwwrnrw‚™¯©ž™£­±²³³³­¢—Ž…mUDWkk\NZfpv|yrjYHNbwŒ¢¯±²¨›}kb^[eosrr|‡“¡¯¤’{t€™²³³±­©¬°¯Ÿy\C[s|unrvyurld\QFK`t‹£³³³²±¬“{fSALWblv‡š¤|uttx}„›š˜”Œ…‹˜ |qnjrz~{xy|}yurpmljpŒš¨³³³®¨¢—Œ„z|~€‚Š”œ˜”™¦² Ž„‰Ž†}uutsrq^KDKR`mwvt{…Ž„|tmfhkv¨°±°¢”ŠzdNCKRaq”¨¯±²±¯©Ÿ”Š€{~€}|zxuri`\dlrw}‚ˆŠˆ†…ƒƒƒƒ†‹’ ®³³³³³¨‘|fQFVenu|}†Š…€„™®³³²±¯¦˜‹ŒŽ†r]XUSQNT]filoruhXScsz}•ª²±±©¡”€jdccjqv{ukirz{{€–¬­¤¤«¥‘€„ƒzpjebcejs{ywri_]]ao~‚€€‹– ©± Š}€…„|yxyy€‰‘’‘‘©¯±² ƒ…†up|†ƒxnxm\bklYGQh~Ž ŸŽ~¥³³³¡‹z€„€sfkptuuˆ ª‡ebo}’§­¢˜„pdkriZMMMPUYdovy{ƒŽ–“‘“ž¨¦”¢±±²³³²§œ€sx|w‚“¡”ˆ„‡Šš©ª“~vqmjginsdVOQSROLHCPewsos}†Ž—›—“œ¨°¤˜“•–ƒ~~}|}€‚€‡›®±²­›ˆ€|yy{}xrlgcXKCScigeXJI]puxxto™³³³³³³ž‡x{}ysmmmpsw€‰”¡¯³³°¦›ƒwwvx}‚~xqg]g|Ž‹‡|}~‚Ž™“†{tmp|†ˆŠ„saYRQ`py~‚€~zvŠ–¢¯²±¯™ƒxvt{ˆ‹Žqbiouzƒˆˆ‚}~€ƒƒƒƒ…†ƒ€ˆœ°³³¬•|†wpibZSPV\pˆž¦¯²°¯›†{yxxyveTOQTX[cp|{ywvv}†ž¬«‰‚†š®¬£š€{zyxvtoj`VOSXfz‹—£¡“„€|xsoquz€„…‚€tifp{|{z|€†ŽŽƒy™¤¯³³±™‚wvveTJQX^dkqx€‡Ž˜¢¢{zz~€~„€rd]WXiz…Ž———”‹ˆ…„‡Š”¡­«Ÿ“““Š„~wplgn{†}ss~‰ˆ…ƒ†Š‡~€{k[fszwttuutrrtuutw~…Ž–šŽƒŒ ³³³¬ž†~ungb^[dmrssmfenwŠ ³³³³³²™€ruwƒ’—maZUdt„˜­¡‘†„ƒ†‹’™¦²±¯§“€voihfhmqcUTboh\Xhxƒ———“‡„~xsv{}pccluoil~Š€z~ƒ…‡Š•£±³³¯¡“‰{vposwwvvy{yursu‚™°±±®©£•…wnedim^OQdw}€ƒ„†ƒ~yyxz‚‡Œ‘™¡•„}yyz„’ˆwofYLRbr|…’¡±³³±­ª£˜£®¦xvtrnjnsy„‡‡†}z{{†“Ÿ§°§–†|xvt{„~wrmjnrof^m}†„ƒƒƒ‚~yz‚~xvwwy|~~~|z~ƒƒƒŽš¡œ˜Ÿ©±¤˜•™œ‘…~ytka\grjXHYix†•”‘—¤­Ÿ‘†€xusrssdQCQ`fhipv}…Ž‹ˆ’£³³³³³³ ‹}||yuruxunfmu{‚„…‡ˆŠ”£²²±ª™‰…„€wmlpt|ƒ„€||}~|vry€‰–¢›“Š€vwzydPLSYUPR]hr|„ˆ”›¢š’•¡­¨¡™…ˆ”†xty}{yxyy~‚ˆŽ”›¢©­°³³³±°©•{{zm`[^aaaa_^ckrrsoibhnruwwwwwvwy{zxz~‚ƒƒ…šœ•Ž‹‹‹™©³³³°¬§ ™Œ{iZKAAAKXer‰“Ÿ¡Ÿ—‘™ —ˆ||}{vrokhc_gr}„‹“–’ˆ„€ˆ”ž¢§ŸƒˆŒ‡zkiihc_bhnu{~†Ž…|€‹”š œ‘‡Š‹„~|yvsoptx}€Š™§ž’Œ‘•Ÿ©²®ªŸ€{vobVX]a`^cktwz|~~}{xtvy{zxwwwyzzwtojgnu{€†‹˜¤°§™˜¥²®«§¥£¥§¦›‘†|rtvxz{}|wtuwy|€‚€~|z|~ƒ‡Šˆ‡€yrx}„–‹€xureTHJMKFBMWcnz}~~zuy€‡‡‡‡‡‡“ ª­°¢|yz‚†‰”› ¥¥—ˆ€|x{~‡Ž‘‡~‚†€yrjbhov|€}z{}vlglq‚˜¥•„€„‡ŠŒ…€ƒ‡‹‹‹Ž’–‘‹Ž–ž€~|ywvuutsrruy||}€‚€}|}}xrosv|†€ztmfmuyvtw|zuuwz{}‚†‰Œ’•——–‘†vx{}zxz}ƒ‹’–š—Š~zyz„Ž–¢™Šˆ‡Œ’–“Žˆ‚‚Š’‘‹xspnu{}}}~|tkloplginsssx€‰ŒŽ‹‡ƒ~zz{~‚†…„ƒƒƒ}}}}||{{~ƒ‰„|tnhlv€€‚|ywvy{|}}|zyyyyxy~€}veTWfv€‰”¡®®«§ ™›¢©­±¯©£—‹…”Žƒywuuwywutvwy||vpnprw|‚Š‘Š‡ŠŠƒ}zwwz}~~yuvz}zwwy{‡Šˆ‡…„„Š…}{yz€†‡‡†…ƒ€|vfUUdrx|~~€ƒ‡Šˆ}ruy€Š”“Ž‹ŒŽ’—œ˜•“““ª±«¤ž˜’‰‚|tvxz{{{zyvsme]ZVXblmmmljntzz{{{{zyzˆ‹‹‹Ž‘’Š…‚€~†‰‚|xvtvxywv{†…ƒ€€‡‰ƒ€|{„…‡‡‡ˆ‹Ž†}wwwy|€‘¢¦¡œš˜’‰€~{{ˆˆ…‚{{‚€|{‚†‹ŽŒ‹‰‡€qaUJDOZ`ejnsvwwz|}}}€ƒ†…ƒ†Œ’‘‘’Œ„~€‚ƒƒƒŠ’—šœ–†‚}}}}}}}}}|ztooqtuw{€†‰‹ƒ{|€‚{~„Љ‡…~~~~‚ˆ‹ŽŒ‰…{xuuuwy{ywuttwz|rieefnw†Œ‰†ƒ€ƒ‰’–œ¢—ˆ„†~{zzyyxurqqrvz{ywwvw{~}|‚‡’‰‚{rtvwvvx{…Œ‘’““‘Ž‹‰ˆ‡‡‡‘¡°¦œ’‰€ƒ‡Š‰‡„}{xvtx|€…‰ƒ{ttuvxyyxsg\]bgkpuz~|{{{‰“–”‘—Ÿ¡Ÿ‘†…Œ“”–‘ˆ|yxyy{|}{xwvvz~€‚{wutuvxy{|}}}}€ˆ‘““‘‹…€~€„‰’‹{{zyyzƒŽ‰ƒ{x{}|ywwvvxy{}}}}zwtuwwwx{~€‚…ˆŒ••”’‰‡‡‡‹Š„ytvy|€‚‡ŒŠ€utuxƒŽˆ‚|urtu|‚†„ƒ|rid`]]]fnuy}ƒŒ”¥ª­°£–“§¬°¯¡“Šƒ~~ˆŽ‰ƒ~~€ƒƒƒ€|xogdlty|zuohaaafoxyyzz{Š“”–˜šœ’†‹”šŸ ’ƒyqjpv|‚‰‹‹‰€yw{~„†„ƒ€|z|…ޖކ‚€€~}}€‚~~†”¢££zsov}{vsrrtvxy{{{{uppv{}~|rhghjotz€†ƒ€~ytsrsw|}}~~…“¡¥§¤•‡ytz€†Œ’““ˆ€‚‡Œ“š–Šƒ›“‡€€‚€|wrlnx‚‰‘“ˆ~yvtx|{wtw{€†‘”•‰‡‡†ƒ€‚Š‘‰vsoqw|€„…~€ƒƒƒ…ˆŠ„€|zxxyz}|ytoic]^it}„‰ƒ}…•¡—Œƒ~x‹¢°¯¯£“…€zxyyxvwz}{xuuuuuvwyyxxyz|‚„…‡ŠŒˆˆ‹Žˆ€}’¨£wwwy~‚ƒƒ„Š—¡“„‚›•Œ…yy{}vpkfbjrvrnoprsuvwwrmlqwyz|}„†€yvxy€‰Š|movztmmt{{{~ƒ‰—¦³³³³³²¬¦›‹|iVM`s{}€•©«†~{ƒŒŒ‹ŒŽŽŒ‹|k^SIYo~umkorw}}xr€›”ƒzrvz{zzrkir{ƒƒƒ†Œ’„vpu{yvv‚Ž›§³³³³³³³³®ž€rh~’‹jI_x~bGIT`mzymbt„Œ…~}qeoƒ”sRDKS`nq\FL\jpuwut{‚ž¯³³³³³³³²±¯¯±²²±±±±¡‹x‚‡r[ftweRYhx„‘–”“ŒŠˆ‡€xw©¨—†xl[JPZa`^`cdVGEOYeqyxx€‰“““‘Ž‹~qlqw‰¡®š†pX@@@IZklkrª©›•šš—“ž«­žŽŽ“˜£®³³²—}lifs‚Œƒ{qg`€¡©•‡˜¡˜‰~…{eN[imbVNFDYmqibfkqw~kSLx¤²±°«¥¡Ÿ¤­³³³¬¤˜wVP^mrwwogZLCNYr’±…YKcz‡ž®£{Š››Ž€iQG\pl_Vi|u[Ah¨¥£seƒ£¬§£¥§ Œzk]UZ`ZPGDBK`tngm‹«³³®—€|ƒŠ‡„„‰Ž™¥§‡is“²¤–€cDWq|bHPf|’¨¨”€ƒˆ«°±³³³§•ƒ•¨¨ydP@@@@@@@@V‚®—ziu€€¡§¥£XMošŸ›vPQk‚|usvyŒ¢§{OUtŽ„{x~‚“¦¨ˆjq…”†zhUAMZemvfQF^v‹Ÿ³³³¦‹qpru{xh[o‡€xtpke_fpz€„‡‰Šš©¡uIb‰¥•„‹Ÿ±‘rpŽ­±²¦zN@@BRbaRB[vtez˜²®ªŠwtpgYJYozaI@@@@@J]olfgy‰Œ‡kNOhugjŠ«Ÿ†x©³³²™~–¯¡Œw`HGQYOEV‚®©ž”ŠŠ›£{R@@@[wseejs¨¡„j†£²°¯°±³³³¤ŽycL@@@b…Ÿ¨°‘fCO\gq{{{zvrbOF^w‹Ÿ²¢“~aD@@G^u{{||}ueUi€Š‡“¤®–~w}‚jP@@@e­˜‚‰ž±‘r[OB@@FWhic`u‰ƒfIXjuuu‡Ÿ³³³¢‡n~›¦±­§žŒ|„œ±œ‡zrjœ¨’}}„œ¬°­©’ž¬¯¯ª–‚|}~„‹“–‡weVGAA@@@Mg€€|r\FVs‰‚}yyyk\TWYdq€•ª¤Œvy|zrkž°¥š†€“¨³³³³³«”‰ ³³³³³³¢‘uhZL@@@Rm†vty{w{’«®¨£¥§«®²¡|w{ƒmWKFAm™¨Žv|‰‚v›±ŸŒwn… ³³³§˜ˆvbao}gOP{¥žˆx}tZAQ`v‘®«£˜‡w‚›²©¡¡©²œƒmZGN_p€§²¥—‡s^cp~”ªž~_€ ³³³³³®Ÿ€sdVHMe~{wspnjeaaas®•}r~ˆ†€€”©—oGECAAAg“³³³®¨£¨¬¦—ˆ–§£xKb޲²±¢‰r’oMQ]gkp|Œ›‡tdZOMMUm„–›Œ~lWBk–«•€jS@@@GR^Ÿ¬tWAAAX|œ•Ž’¡±¦˜“¡¯ªŽoOGTaUHQ~©¥”„vgcfj†¢°ª£”ƒ{‰˜¢«±¢’…zoie]QDa³³³£ˆnidfr}}zxxyumg„¢©“~siaaaYLCWl|ˆ–xW@@@Pf{¥­«©‘‘ °¯«¤Žyqqrz‚~jVt˜³³³œ~cnz€‚”¦­œ‹’¢¬ ”‡{maUKFA@@Kx£®¨ {THXhnt•¬¬¤ž¦¯³³³¡Ž|jSE]v‹Ÿ²¦š‹zhs‚Šwdi{Š‚{|„Ž›©¨‡ghw‚€~{xtpx’­‘iJT^ZMBj’ Ž|yy•«œ|^adecbrƒ‹x…œ¬ž‘~fNIDNošŸ •ŠŠ‘–„|un^MG`x|vt¦©–„td\dlrx€•ª³³³±¯¦{yzzslkorw}ˆœ°£’…€{{|{dLNe|Š™œŠztssz€~sjwƒ†{ov€…}{{zcL@@@h”³³³³³¯™ƒ|‚ugblwxwupk{—²§‘„xwz‹˜¢«±š„xvtvxyvtx~‚~zxyy‚Œ€tsturomkk†£³³³š~hd_cltx|€‡Ž‡€–­°¬¦•„€‡Žˆ…™­±±¬˜„|xvxz†Ž„zpjcn€Ž†yvrx{aHSj~ƒˆˆƒ}{r^KKPWgv}~{x€˜°ŸŠ{wtsru§²±± Ž‚€~}|{xuvz~‹šŸ•Œ–¤©‘{uwyl`^hs‡Ÿ©˜‡vcVeu|~wokos}‰•¡®©šŠ€tmkjgdi„ «¯°—~mdZeqvk``cgs~Š–¢–Š€|wˆ ­–€’¢’oYC@@Ih…Œ‰†‚‚Œ–¡«³³³ ‡sssx€†—§­¦ž›˜–•“““’…znaU^iswzŠŸ±¦œ”‹ŒŽ‹ƒ{xwv|€v_Hb|‹‹‹…z{}‰¯°²§zdOG[piWJ]o”¨’|pv|ƒ„†ˆ‹Ž‹ˆŽŸ°³³®Œ‚}wusmdZQG@@@HQ[ivtgZPGCHMRYas„l[w“œŽ€ˆ”Ÿ§°§–ˆ’¦¬²²±©“}vsvލ³³³³³³³³³³®œ‰{naTGHXhv„’ž«’kIT`iouƒ’˜Œ€}|{wsfSALWcp}kSEVgs|ƒ’¡¢“„€ƒ—««£œ˜”™¦²³³°ª¤•„tdTYl€’¥°¯¯œ…reX\huŒ¤¦|…“–€k]QKg‚ˆ~ruyzwt€™‰zx€†}sy“¯§™•›¢©¯™ƒz{{gPDO[gt€‚…‡‡‡“ £–‰”¥³³³³³²›…wsng_XQJSdttuwz}†š£¬ž‡z¨²±±¢“‘ °¨œ‘‰xlaTG@@@Qdw‰ž˜’‘‡yjrz…˜ª Œ}yunf^r†’•œ€cg|ŽŠ…|gPJj‰““‘…{uuuwy}„€m_hptvxŽ¥¬œsV@@@JXguƒˆ‚~|{z|}{ww¤­«©¬°²±±ŽcJv¢³³²²±rGXtˆŒ‘‘|jr°•w`]ZRIAAAMbwŒ¡§“€…˜œ¡¦­³³³žsFEJMMM]t†‚‚Œ–¡«²±±ž…qnkr€ŽqRR~©ª¢–z^[gqh^aUKB@@G[ptso\IK`tmcgœ”€rsurlf~•›ˆw†ª—…‚†ˆlONi„zleoyƒ‰š« €_iv}{z‡š©­±°¬©«­¯°°±²§{OEMUcqy|n[SduiSD\s€‚†‰Œ’zZJw¢£Št‹£±²²ŒaFYltwxncbjs‰¡¦‡iv‘¢{RNdywu{Ÿ¨®¯¡“—¥±˜iVC@@H`x¡³³³¨”€‘¦§ˆiXKE_yxrrs}“«°±²±¯°±±˜€kZIEBFWiyˆ•‡z€™±ˆ]FVf}•©­±¯©¢”†‡›¯©Ÿ™£­•mI[mvxy|~„”¤©©©­±«”™˜“‡yoeWHDKRf|ƒgJ@@BRbp}‰™¨³³³•oOXbw”²³³³³³³³³³³­¥œ˜•˜¥±Œ`@@@Naqpn|–±•v^TJFCF^vаŸ„‡Š~ner~umjg_PB@@FWh€˜¯°²¦{ƒž¯¢Œ€”ª³³²†ZS€«©Ÿ˜Ÿ¦žŽ{vjVBAAKkŠ•™™€e`kwwv~•­ªŸ˜¢«¡Œwusqqqƒ™¥šŽx[BSewˆ›}pkglt“©¥Žxwwungy£¥¨gAZr}ytx|y`HN`t‹£­«©«­¯±²¢‹}“©«Ÿ“Ÿ«ª”€…’ž¦®œ|^kx~zvdODOZo‡™~ag‹°¯«¦Ÿ˜‘‰yqpuyyyxsnƒž±«¥£££©¯£acinqsohf„¤³³³¨“‰€†“›”™¢“ƒ|~†‘{et”¯‚WLd{hQ@@@KYj‡¥²°¯¡“ˆƒˆ—ŸŽ~zƒ‰˜¤±³³±«¤pUamqkf_XYj{nVCNYZTNU]\PCd¯ž€uic]bs„|xz}|{xncbiqƒ–¤©­°±±«¥š‹~zw–®¯«§ž–š§³³³¨“~lZSdu}‚‰š«²±±‰ƒ”¥•~gWG@@AVk{‰€sqŒ©­¤›mXCO_lszxro~Œ‚fI[os\EPdriahz‹’™ ©±a@@@^‰®–~|‘§¬°©q^N@@@LaubMAAAJUas„”¤²¬¦¥«²³³©†dSICXm|…މzjt†–“Š‚|xuv|€ƒ•¨¯±³³³¯¦ž~ZDQ^dgmˆ¥²°¯‹fMJHTdpjdfmskbh€˜Ÿ§°•jB_|‚q_mŒ‘•ž©±¦›ƒxz|}zxpf[PE@@AQ`igfœ³³³¥}}|€‹•¤¢}y|zcKHWeXI@@@@@GiЍ³³³³³³³³§{OIVcs‚’¢±†z‰vZDScmsyyxy|£³³³³³³³³žsFShwwv|†Ž‡€{xtdSGDAN_mhc\RH[n‚˜®²±¬˜„ŠŸ±œˆr[C@@G[puuv}ƒy^C]y ¯ªŸ˜¡«¯±³³³³³³§™•›¢«±š„Š•‘‹†‚€~}xbLK\m]K@@@IU_jt€Žœ™•’š¨­˜ƒo[Kn‘ž•‹™¨±­ª›ŠztmaQAHOZk|†——————¡«±²²³³³³³³³³³³­¢—Œ€s`LILMHCHUajr€—®³³²®ª«¯³³³«š‰oT@@@GQZ`gjlm^MFTbnzƒƒƒ€{v€Œ˜¤°¨œ•¢®³³±–|npq|†“¡¯¬¤›‘‡{kZPG@@@Qfwur“¨–…xoginx¨¡‰r_KK^rƒ–¡œ˜ž©¯˜wvvy}…•¥ŽnXo†‡}r}ˆ’𡍮¬•}ƒŒ›©±²²³³³³³›|`SFNe}~}vo{Š•‘Œ‡€|‹šœiQAAAYz˜¢¬±±±Ÿ‹}|yvtturlfilx“®œosx€‰“—šŒiEGNWcnƒœ±£•Œ‡ƒƒƒ}y‡ƒztqn{‡Š‡„‚ž–ŒoPEOXnƒ–£¯³³±¤˜Ž‡€{vuz~„‡ˆŠ™£©¯³³³­§žŒ{rnjqxŽ›¤­°§Ÿ}mjgfhiqyt]ECEJT^fmtx}…ŠpbSEOcv{€ƒ…†›£¦¨£œ•‰~|€‚xlm~©±«¥¦­³³³§ydOG]sˆŸ±¡’ˆ‚~„‘Ž‹yaMHC@@ALWakt~‡Š„ztokfw‰š¥¯±°®©¥£££¨¯­Žwmljx¨¤Ÿ™ˆ‡‡…}lV@@@Ni„–§³³³³³°¡‘‰†ƒ~ytqnbSK]owy{{zz|}}|xk^[\^adr‰ §­©“}rkgox|}}zwvxy„’œš—§°¦œ‘ƒwdODSaks{ ª®²³³³³³©„ytuu{€‚€~xrotz~‚†zl_QBN^mxƒ“¤³³³¬ “–š˜Š}xwtlegpz€†‰„€|xuuttuulb`gmu~‡–¤«¯³³³°­©¦¤¡œ˜‰xkpuy||xwy{~€ƒ„†}l^_ajz‰™¨±­ª™ƒqjdgq{ywtqnw‰„€~€€‚‚€€„ƒwj\MCXm‚š±³³°§Ÿ“‡}}}vhZPFCKRNFCLVbp~…ŽŽ…}ywy…“ž©³³³¯©£•†}{z•‰ƒz{}~€‚|tnoqy„އ€{tnlkmyƒ“¤³³³¯©£¥§¤—‰ˆ‰‰€vhXH\pytnpsvz~xlbhnsvy{|„‰‡‚…œ¡¦¨¥£˜Š{wodYPFDKRcvƒƒƒ…ˆŠ‡„Œž±³³²±±±±°ª¥¡ŸŽ€oZE@@@@@L_rtv|†‘ŽŠ‹œ­­¤œ—‘‘—œ£ª§“xwuutqmj_TPV\XRQ`nw~ƒƒƒ€}x…–¡›”›¨³³³³³³±¯¬¥ž›”‡{xtmaU`nzz{‚‡‡‡š§šŠ|peZPJ`v†Š‰‡†„ƒ€~||}{vq_LFQ\ciosxtmeb_bku€Ž—šœ›˜–‘’–‹€yyywtpjdfmtx}~~…™¤¯®¨£©¯±­©¦¤¤©­¨ž˜£®§“€~}{ztng\QXizz{{{{{{{zx{„Ž˜™’‹ˆ…ƒ…†{r]IBEGGGJQXcoz‚‹‘”—¡«¬¢˜”‘ŽŠ‡…„ƒˆŒ‰‚€‚zvvwwusqopw~„Š‘›¥ª¬­˜ƒxurx„‹‘Œ„ˆ’‘ˆ€~zqgghihfecbfkqx~ˆ”ž¢§©©§š…‚€„Œ›ª°±²²±°¯¯˜pf[[\]YUUWZj{ƒ…†€xof\amyŒŸª®²²±°¯¯©¢Ÿ¢™‰zfSINS]iqpnqx~Œ›¥©®¢”ˆ‚|{}€‰’”‹…€|yvutsssohbehjlmsy€‰“——–“Š‚ztnn}Š˜¦³³³²±±¤—Œ†€vka`^agmljq‚””‘Œƒ{wvuuttuu}…‹Ž‰{wsz‡–”‰}pry}{xpeZiw€ƒ„†€wme]br”¦³³³²±¯¨ ™’‹ye_ly{zwneky‡ˆŠ›§©©£‘€Š“—›•Œ…~}}}yuhTAThtwyribceghjy‡“–ƒm`iqŽž¦¯°­©˜‡„‰ˆ…ƒƒƒ‚€{vuz„Ї‹®¬ª¢•ˆ…„ƒƒƒ„…†€|xurtxwogghjmpojfjorssvy~ˆ““‰xf][Zm€“¡¯±°­¤›™ž¢”…~~{yyy{}wnknqzƒ– ›†‚}{z|~}|€…‹•Žtwz{xvrmiiiigfpz‡›®¢’…€ywvvz~…œš˜———•”‘‹…†Œ’‡|uuupjbTENdy‹ž¤œ“‹‚~„Œ’‰ƒ}v…—{z{ƒ‹‰z|~~{xtpou{|{z{}|zx|€ˆ›­±°®§ ™’‹€uoruwz{wsngaWMOas‰¡³³³±°¬—wvv}…‹ŽŒ‰†}xqjfcaaa`_`kv~„Ї„ƒ…†€xrtwwwxy{…𝱲¯¤™•”’ŒŠˆ‡‹…}|}|tlkor‚”¡©²¯«©©©œ‹~~|z{|~~}xttusmgZKDP]aabcegjmqux|¡³³³³³³ª¢š“Œ…yyxy{~~|voquy}ŽŸ®¬ªª­°¥—‹†‚|vof^gqx{}{xurokfaYRR]hiikqxvrntz|zx†—¤©­¯¯¬ ”ŽŒ‹„|~~…Œ…wjry}}}…•ˆ‰ŒŽˆ‰±¨ž’…ytsrw|€ƒ‡Š‹yvsm[HEIMMMUev~…‹‹‹…~y‡–¡¨°®ª§¢ž™–‘‡}xurtvsi_XRQ`ouw{ˆ• §®¨¡Ÿ¨°³³²«¥œƒ~yvwwrkglqyŠƒ}yxxwwwwvx{}|zxur{„‹‹‹‘›¡˜ˆƒ€€‚€xoqv|‡’…{xusrrv|Š”˜šœ—‘“š¢—Š„€}{‚‹Šƒ~wqmkjiiifca_^djmmmrv|‚ˆŒ’™¥²³³²±±¥–ˆ~rmmnquxyyocWMDM`rsu’¦©©ª®±³³²«¥šŒ~€„…€}zwvwywrnqtrjc_\\fpsrr~‰Š€vsppy€£³³³¯©£”†}zxsnjmptx{wtqqqqqqqq‘¢™˜šœ ¢¡žœ–‘Š‚|}~zvuuuroosvy|‚†‚}{ˆƒzrsuzŠ™¨±­©§¤¡–‹ƒ~wqjfhiloqnkpz‚€€„Š“”Œ……ˆŒ•ž¦¬²¨’‡|uojkmnpruy{yxwvvy|~{sjnrw{~‰—£ª°³³³ª¢™…€~{{{{zyndajrsrrrsw{€‚…‹“œ–‹‹‹ˆ…‚€~zurtuwxxtoptx‚“•–‘‹„{qry€€‚€~zŠœ©©©¡—ˆ~ttuvwwsnifccgiiirƒ”•”•ž¦¥¡Ÿ¡¥ª®¦œ”Žˆ…„‚€|xuttojglrsrrtvtmfltyurtw{‚‹‘’”–˜¡œ•†€|zwtpmmmlkkpv}ƒŠ…‚ˆŽ‘”˜¡Ÿš•Š€|}}…’Ž‹†wwvqh_gs~„Œ‹‡‚€~{xyz‡—£ª°²°¯¢–Œ†€zsmjghmqh^^itwxz{}ˆ—ŸŸ™“‡vsstuwy{}~~~~~|ukbjqvwwwvusruy~„‹•¢®¯¯®«©©©©©©¦¡œ‚{xvpjeb_cjrvz€ˆ’”••Žˆ„€}}|{yxwwx{}}||}~|z{}{unortvyyxx{~…І‚€ƒ†’¡­ ”‹…€‡Œ‰…€|yxwk`]elrx|‚‹—£££Ÿ™“‘ˆ„€}yyxy{}‰•›—“‡‚€}yuqmhhmsuvz€ˆ‡ƒ€‚Š’˜¡¡ž›‘‡‚€|xusrpold\XVT[bjr{ƒŒ’’˜œ•މ†ƒ~yvy{ˆ›¥£›’Œ†€}xwvvwyxvtwz~†‚}ywvwz}ƒ‹Š‡—š•–¡¦™‹‡‡†vqonortuwz}€„ˆ‰†ƒ…ˆŽš¦¢š‘Š‚€ƒ†…ƒ„‰Žˆ{{{zvsqojbZUQQ]jrx}}|{zz€‰“˜œ˜”— ¨¤Ÿ˜Ž„€|yvsstuuttvw}‚ˆ‘‹ˆ“¥ª®›‡zvrrstwz{zyyyz{{|}}|zxwuuuy€†ƒ€}zxz}€†Œ“–Š~z„œ©°¤—ކ~|xssuxŠŽŒ‹ˆ……”•”’Œ‡‚~}}~€‚€~|}~|zz{{zzuqmmmoqtuwxyy|~€‚€š€~|~ƒ‰‡‚~|xurokgblw~ysrsttux{{vuy}‚‰Ž‰„|…———•”“—›”‡{ywx~‚€}|€ˆŽ‡€ƒœ—’ˆ{{{~‚†€{wvv{†ƒ€}zwwvx~‚“¦±­ª ”‹ŒŽŒˆ†„ƒƒƒ‚{umea\^hrsrruyyyyyy~…އ€zwttuw‡„yngaalv~„Ї„€}|z}ƒŠ„~yyy~„‹’™¡©²³³«•€†–£¨­¥–‡‚~{zz„’šzvqqqsvyz{|~~|z{}€…Šƒ|xz{yuphaagnqu|†‘©¯Ÿ‡ƒ€…‹‹ƒ|xtqmjgdbgkpuyyyyxx{€ƒ†‰Šˆ‡Š•£°©ž”…€}zwusrqqsvy{|}xtuz|yupkpy€„‰†€z¥±²²¨›ˆ€|zxŠŠ‚z€‰–›–ŽˆŽ”ƒxeSN^ntwubNUj}}||~}wpopqpnnpq•’‘”˜£®¦|‡‘›¤¬²²±¤‘{xsojnrvww|†ƒ€~{xvtuy}ƒŒ’‘Іƒ€~~}}…Œ•Ÿ¨¦¤Ÿ—•ž‚nVCNYclu|‚„€{yy|†’”Šyuwyxwvwyxvty}…Š™¨¬š‡€‚–ª¥ŽxcM@@@Pcruxyxxy{Ž›’…}|zyxy‚ކ~ƒŠŽŒ‹—ž¦¯¦‘~‚‡ž¬­ªŸwOAABKU`mzyvqjdn€’•“‡—¨±­©›‰}‚ˆ‘©¬°®£˜”‘‘›¥¢˜Ž‡€ƒ›}YCJQ\ircTXj}}}~{vrtwzƒœm œ—œ£¥–‡†ŠŽƒytuu…–Ž€†•¡–‹x]AEJOTYRHF]uoXC^yŽŸ°Ÿ‰}Š˜“†}‰–¡©²²±­¡•™¡¤Œtnv}‰•š“Œvk^R\r‡˜©¦‹qt{~zusrs}†‚sbn{ˆ–¥™…vy|‚Œ–‹€z{{|}€‰“‡~fM@@@IS\dkrx|sjm|Š‚{wz}¢²²±ª –•“‡€¤²±¯­«¨ž”Ї–§¤yM@@Eb„ynkgjx„‡‡†…ƒ}sju€„€|{z~§­³³³³³³«¢˜‰{š‡vdRA@@@@@@@F^w}yw¤ª›Œ“œ¤ª±¡‡qnknu}Œ¥›‘‹†…‘›ƒ†‰‘ °œiXGRn†‚~€ˆ‘Œ„€‡‚qcr€¡²‡yyy{~™Š|‚Š‹y€Š•¦‹|‡}`C@@@@@IT_lx‡š®˜}”­ªŸ”‰~}†}‰•ž¨¬£šž©±‰|unprv~„„|dK@@@Qcpw~ƒŠ‘Ÿ­³³²§œ”‹˜§³³³³³±¢’‡|tkk{Š‘””‚qnv}tk`QC@@BIQ[htx}ˆœ°¦˜‹€uy‚Š‚{|‚Š“”Œ„†‹Ž‰„v_H[nyyy{~€†ŒŠ„ztty}zy~¢°ŸŽ~lZep€–­¢Œ|€…‚|uuu€—¯²±«—ƒŠŸ³³³¨’~gP@@@FMTZ_fow¤¥ƒaer€‘¢¤—¢¬«š‰€yw„’“Š€vu|‚wjj‚œ§­¬€TMcyz{ƒ™®³³®˜ƒ{zyvs|“«¯°ª‘yrsrh^ao}Š™›†spsx‡–Žv^kx~{xnb]lzƒ‹“›¤¡€}|~…Œ‘”–“”ž¨–uuutsn[HJZjqwufVcu€ui\NBQamt{Œ¡ªœŽŽ’˜£®³³³³³³³³³³±¨ •‰}{yxyyskix†…xz|}}}}}wbMILOZegb^SGCKRnާ ™–”’†zuwyŒ¢­˜ƒ‚‹‘†{usr—šœž¦¯™nAUizƒ„xp~ŠŒ‡ƒ‡Œ•£±¥–ˆzz}vnr‘‹„ƒ‘Ÿ”€rw|‰ž³¯«ª®²gKZhlkiYIBDGiޤ“ƒ~}|ˆ‹Žœªª”hRHn“¡Ÿœ’ˆ}xy|€‡‘~nioutspkghkqŠ¥©œŠ…€|wohcmvxvtuwz~‚™ •Š…„„—©³³³¯« ˆpgd`SFHTaehmu~‚‡‰„€€ƒ‡—¦¥zusrrsvy|€„Žž­™‚|“«±²¯›‡|wrfZXdoœš—Žv‡™œ}}}}}rbUanv{yrvŒ£ª­«™†Š±±²³³³¯«£{gSAKT\ciklnruwy|‚ˆ’–wV@@@QftdT\t‹”Ÿ—š§±±²³³°•{eTCReu€‹‘”˜£®²±±•{mw€†‹†€}}~~~|z~ƒ…}ukcw‰™¥²³³¤yMAA@@@ELSbq˜®¯¬£Šslpsqooru‚‘œš—…€”©³³³ŸŠ}}}†’‡dALWblvwwz„˜¡§zmkjpx~€‚†ŠŽ‹ˆ‡‰Šƒ|{…œ¨®˜†««š‰|oedbgnuuttuu}…‹‹‹m^ekpswogcfilorw|‰ž³³³°ª£›‘ž®« “sQBEGXjvxy|€‚~z}…Ž€rcSDPdtvyywv~†‡€z‡—¤ª±¤€”¨³³³¤•eHCELf€“£²ŸŠ€€sfgoy£ª¡˜‚{{z{}•©³³³¤”‰ƒ¡²²±›xSLEHYkrw}€…‰ŒŽ‡€r[CGNYj{nVBQ_eeerž¯©œ•Ÿªª£œ—’“§‰dIMR_p~|Ž›š˜’„weQBLUhœ~srr{…‡‰™©¬°°ª£¨®³³³³³°—€iVBWo|rhlv€“¦£~{yxyywtqqqrtvxzzwtvyˆ“˜š›Ž„–§¡˜ˆlOECDYowutŠ¢ªš‰zj[SJO[e^WV[ap€— Ÿ›—ž¥«®²³³°ª¤§­³³³¤Œuoiis|€„‹œ­³³±¢’‚q_dlqonkhe^W[huxz}†šž‰vmkj„Ÿ¯°°‡vsojfbmx‡›¯©¢›—”‡wjnrpibcehmrtuuuuƒš±±²®£˜›Ÿ¤ª±³³¯‘t^PBEJR^jsz€‚…‡‡‡|phebgnuy~}|}~{x‹¢³³³¨˜‹ŒŽ‘’”–“Šwkcjqsssssy„‡{tgWHR\l€””‘‹xwx{„Ž™¦²±¯®«©¬¯°¤—Š|maUOTYcmvz~ˆ–£©¯®¦Œzmifinpg^WRN_r€ˆ‘Œ…Šž±±²³³³ Šu_HL^ntz‚Œ–›ŸŽ{zywt{†’¨¨—†€Œ˜ž ¢—Œ…~‡‹Ž’„{cL@@@@@GXisz€‰“›¢¨‘‰†ƒ†‹Ž‹ˆ€tjouxz{~€„‹‘𥭢˜‘Ž‹ˆ„€vlfa\VPPUZdozƒŒ‰„}|}ŽŸª®²«¢œ™—“‹Ž‘’”™™…Š”ž¥¬€eeehlqsvx{~ƒ‰™££™…|smg`YUcpsnjiijlmsz‚’¢©©©¬¯±²²œƒlYFK[kvƒ~xvusrrqqs{ƒ °Ÿƒ…†‚~{ƒ‹”–“‘’–šž¢§ª¬¬–lWBCFN`qx{…Œ“–’Šˆ‡ˆ‰‰‚|xvsjbaiqx…”˜šŸ¡¥«°±²¬™‡oUADFLSZ`fp€˜žŸ€zyx{~…Š‹‹‰ƒ|yxz|€‡Ž”™š•‘• ª¬§¢ˆp^VOXdotz€‡’‚xww{ƒŒŒ}lfhimqx„™¢©©©¢˜Ž‹˜¡š‘…s_^difcfmuy}‡ˆ€xpiinsuwwtruy{yvwy|‹œ­°±±ª¤¤¦§š|eOU]enw{~€€‚Š–¢ž™–”“”•”‹‚|wrw}„Š‘‘Š‚}zv{€„‰Ž‚sgmsuttwz{zz}€|vqmjpv{‚ƒƒ‚€€~{yyxy{}ƒŠš¨³³³³³±•ykosw|€‚†ƒ~{„ŽŽ„|}~~{xpf\PEAAAO]m~˜ž¢ •ˆ~‚ˆ›§¡™ƒwtuv†‘œ¨ž’‰„€wkbglt€‹‹‹Œ’Š…€{|€‚|z{{zyy€…ˆ‰Š„€wj^SHHYjrw{xuuwyyywqjouz~ˆ–Œ‚€…Š˜¨³³³²±¯¥›‘‡~‹™£££££¡—Ž’©¬°¬œƒ|sj`VKBSemmmrvywvx{~~~~€„‹– —‰‚›Ž‚{rmmmqux{ƒ‰Š‚zjYR`ny‚Љ‡‰Ž’”–•‹‹‹‰„€ƒƒƒƒƒƒ€}|€…Œ›ª¬¥ywvqkeeejqxy{|~Š˜¤¨­£’ƒ†‰‰†ƒyvwwz}€€‚|obdhkoswz…Œ‹…ukaXO[j{Ž¢£š“”–———Ž…„—ª¯¯¬—ƒzwtpllt|zusx}†‘œ…„‚sc]]^hqwy{{{‡™¡¨£žŸ¤¨¬°¬›ŠŠ‘ˆ€€…Šxsssvxywtvy|~tj]PLWcjpw‡‘¨¢›“‰€„Šš©¢}|€†‹Ž‘”—œ ž—ˆ}}}uj_RFBEGGGOas~‡‘›¥«¯²¥™–œ¢—‹ƒ…†‰ŒŽ‹ˆxnljkossssqnptwtpi_U_lvwy~„‹ŒŽŠ‡Ž—™…†‹’“•–¤¥›Œ‹ŒŽ•Ÿ©¬¯«‡€vlaVKBMXcmw|€„‰”œ£¥¨¡”‡“›¥¯±²²®ª¡•Š€wl`UVX[_dghjkmmkje``flu‡Œ‘‹‡ˆŠ‹‹‹‰ˆˆŽ”’Œ†xtuuwxywvtsrx}‚ˆŽ‘•“‰€zuodXX_fmu~‡‘œ¦¯¯¯¥—‹Ž‘“““““’Ž‹ˆ…ƒƒƒ€|xvtsrrqqqlgd`^djoswxy|ƒŒ—¥°°¯¯±²«¢™~}|€…‰Ž’–šš•‹†„ˆ’—œš˜”‡{l_XPOQT]eiiit€ˆ‹Ž‘“—›‘…„Šš©¦šŽ†€xqj`UPX_it|sjfhimqtuux{€ŽšŒ|y{„•¡™‘‘”———˜šœŸ¡¤©­£”†‚}}}}|xpg\QGDBAABUg|“«§”‹ƒ‰Ž‹ˆ„€|}~}|€…‹ŒŽ’—œsbQIDCP]bdfox}{zwuw„’ž©³³³«š¦®«©Ÿ‘‰™¨­«©Ÿ”Ї”¤­Œ‚|uutrpnhb]]]YSNPR[jy‰Œ†€„‰–££˜Ž‹ˆ‹–¡Ÿš•‘Œ“”–‚ulc^`aeint{}||{zyyy‚˜Ÿ¦ž}|z}…‘’Œ’Š‚}yt|„ž­£’‚}xx|€…І€ymb[WT_krssuvy}‡’‘Їˆ‰ˆ{yxx}ƒƒƒwi\PCFNUZ`gqz{}{tnqu|‰˜ž ¢š’‘—œ¤­³³³³³³³³«Ÿ“‹ƒ‚‰‘𢧣ž“†yupmmmx‚Іƒyj^_afmuwyz|}€ƒ†ƒ€}|…˜¢¡žšŽ‚~|zwth\TWY]bgnv{}yrlifmw€„‰‹‹‹–¢¤š‹††’ž¡Ÿœ—‘‰€vx{€ˆ‘…}yyyyy}„Œ€rjc]]]_belr{†“ƒytpv…•›Ÿ ˜‰||}€‚€|wrrssokmrwwvqh_gr|ˆˆ…ƒ†‰™¢š‹‹‹–¤°­ª¤—› £££œ”‡}yuqllpu}…‰ƒzvrtvwutvz}…‰ŒŽ‰„„‡‹””އƒ{{zxwuuusojklmifeefiloruwy{‚‡Ž”š ¦­³³³²°¯£•‹‹‹‹‹Š‰‡‹“œ˜’Œ…}|||}~€‚ƒ…†‡‡…}ui[NPRW`hiijmquy~…Œ—¢žš“ˆ~}~~|zwtnihovvsplgintx{‚†‚{zz€‡—Ÿ¡Ÿ™•“““œ¨²±¯¯¯¯°²°ª¤™†…ƒ€~|zx~…ˆ{tle`\Z\]fpw{~}|€…Œ”Ÿ¡œ€|{z|~}{zxtmfhknqsssssrqqquy|~€ˆ˜ ¨¦¤ž“ˆ…„‡•¤£š’‘ŽŒ‹‰ˆ†„ƒ€~|€…‰Ž’‘“–†~zuqmi^SPTY[\`hqvy||}…–§œ…‚€€€‚‚€|yx{}}|zslmqvxz|}}€‚€€„‡Œ’‰‚€…‰•£¯¯¯­«©©©¡€|yxy{~€ƒ„†…‚€€‚€~{uph^TZahov{€ƒƒƒ…Š™£¥œ”Š…‚zvqkecfiklnpqrsttuwy{‚Š‘’Œƒ~…ˆŒŽ‹ˆƒ~‡‹ŒŽ‹‡ƒƒƒƒƒƒ€|yyy—œ¡¡Ÿš˜–”“Š…}ukaYRS`lsy}}}|{z|~ƒŠ’–šœ™—‘‰‚€~|zxxyyxxwvuuuuuvxz~†€ytuuwxyyxxz{}€…Š’›£¨­ª£œ™•Šƒ€||ƒŒ‘”–•“‰ƒƒƒ„‰‡~saOMWaehkosuxz|€ƒˆŽ•œ•†ƒ€|xsjbco{‚‰Œ†€~~€‚†Œ’ŒŠˆ‡ˆ‰‰…€~|z|~€‚†‰ŒŽ‰…„‡Š‰ˆ…~‚‰’•“†ƒ€~~{ri\OBDFKRY^bgntwy||}€…Š”•ŒŒŠ‚|ƒ…†„~}}}€‚€}||{zz~„‡Š…{zz{|~…‡‡‡‡‡‡‰Š‡‚‚ž¦ª®§ š”‰ƒ~zvuuunhfhimqux{}~€€‚‚€€‚…†„ƒ€|z|€‚€}|}}~€‚…ˆŠ…€€‚ƒƒƒ…ˆ‰…€~|zxyz|~~}{yxz{€„ˆ‹Ž‘”–•“‹‡‡‡…€|xtpjd^YSSSX`imqtwyyxx{~…œš“Œ‰ˆ‡‡‡ˆ‹ŽŠ…€~}}~€‚ƒƒƒ†‰Šˆ‡…„ƒƒƒ…ˆ‹‹‹‡‚~}|}€‚„…†ƒ€~zxz|}}}ƒ†Š‹‹‹Ž‘’І„‡Š‡‚ytk_TW[`flqux{~ƒ‹“““Œ‡‚|‚€}|zz{{{z|‚‰’ˆ„€}}||}}}|{{{zywusrssw{}}}€ƒƒƒ‡Ž–—————šŸ¡—ŽŠˆ‡ˆŠˆƒ~}}}}}zvqiaYQHOX`hotwz€‡’–”ˆƒŒ™¡™‘‹…~}}}}||}€‚€~~~€‚€{wwvvwwwwx{}‚€€ˆ‘“‹„€ƒ‰’‘“š¢ žš“Œˆ…‚{umf\SPV\cinqtuuvwyyxxyz‰“——•Œƒ€ƒ†‡‡…‚€„†…ƒ€}z|~‚Œ•”‘Ž‹†€{ywwy{}~€‚€~~„–——–”“““““““““““Œ‡ƒ€}}|yuqia]]]\[Z^aejnprvz}}}~ƒŠŽ‹ˆ„€~~~~}||}€‚€~}|zz{{zx©x{}†‹ŒŽ‘“—š›™—”‘•››™–‘Šˆ‡‹Š„€}zxurkebdeinrsuwxyyyz{{~€ƒ‡Š‰ˆ†ƒ€€ƒ†„€}||}~€‚ƒƒƒ„†‡‡‡„|ywwwwvuttvxz}€ƒˆŒ‘’–š›—“‘Ž‹‰†ƒƒƒ€~|{yyyxwuromkjhgfhimrv|€…ŠŽ‹‹Ž’•˜šœ˜•†|{z|~}|‚€€}{yyyyyz{}}{zxvvy{{{|†’މˆ‹Ž‘’‹‰ˆ‡‡‡‡‡‡‚~{{{|}}}}}|{zxupjiijmpsuxz|~€ƒƒƒ†Š’•”‹‹‹Šˆ‡ƒ€}}||}}}|}€‚†‹‰„ƒƒ‚€}{yxyz|}}ƒƒƒƒ…†ˆŠ‹ŽŒŠ‰‡…~}}}}}}{yvrnmmlifhknu{€ƒ†…ƒ‚€~ƒ„†Š‘–“Œ…€}zwwwxyyxvtqnsx|~€ƒ†‰‰†ƒ€€‚…ˆ‹‹‹‰ˆ‡ˆŠˆ„€„Š‘’Œ„}|zz|}€„…‚€~}|}}{xusrrsvxy{}~€€‚ƒƒƒ€€‚€€„ˆ‹ŽŒˆ„€{{|}}}}|{{{~†ˆ‰‰…€~}{zxwuttuvy{{{|„‡Š†‡‘‘‹…~|}€‚ƒƒ‚€~|{ytplifjnrssuxz|€‚…ˆŠ‰‡‡‰‹ŒŽŽŒ‹…€{zxwwxxyz{{€„ˆ‘“““”–“†}z{{~€ƒ„†‡‡†…ƒ‚€€€‚€~}}}}|{zz|~~|{yxxy{}~}}|zyxxyz|}}||~~~€„‡Š‰‡…~zwttuwy||}‚†‰ŒŽ‹‡ˆ‰Š„zxvvwx{}€ƒ†ƒ€ƒˆŠˆ‡…„ƒ„††„‚€€‚ƒƒ‚€~|{yxvwy{~€ƒ…†„€}{xxyy{}}||}~€€‚„…‡ˆŠ‹‹‹†€}yvwxzz{{{{}€„‰‹‹Š…€}||}~~|zxy{{{{zyxz{}~~~}||}}~~}}}€‚ƒƒ‚€~}}}}}~~~€‚…ˆŠ‰‡‡‡‡ˆŠ‹‹‹‡‚~|{{{{{|}}~„‡ˆŠ‰†ƒ€}}}|{yyxy{}€‚€€~~~€‚€€‚€|xwwwwwxyyyyyxxxyzz{~‚‡Šˆƒ}}}~€€‚„‡Š‰ˆ…€}|}}}||~…‡‰Š’‘Іƒ€~{xwvuuuuuvwyz{{|}~€‚…ˆŠ‡„|{zyyyz{{{{|}}}|{{{}~€€‚€€ƒƒƒƒƒ‚€~€‚„†…‚€~{zz{{{||}~€ƒ„†‡‡†…ƒ‚€€„‡‡‡„~||}}}}}||}~~}|zyxxwwwwwy{}}||}}~~||}}}}}||}~~}}~‚ˆ‹ŽŒ‰…}|||}€‚ƒƒ||}ƒˆ‹‹Š‡„ƒƒƒ€~{{z{|}}}}}}~€ƒ†Š’Œˆƒ€}{yyy{|~~~|yxvuuuwxz{}|zwwwxz{~€ƒƒƒ}}||}}€ƒƒƒ}}}}}~~~~€‚„…‡‡‡‡‰Š‹‹‰„€~}|||}}{zz{||}}}}}}}}}}|{{{}~€€‚ƒ…†„€~~}|{{{{zzz{|~~}}|{{|}…Š’Ž‹‰ˆ‡‡‡†„ƒ€~~}}~~~}}|{zzyxxy{}~~}||{zz|}†‹ŒŽŠ‡ƒ€}|{zyyy{}~}||{{{zxxyzz{|~†’ŒŠ…€ƒˆŒ’‡‚€}{{{{{{{{{{|~~}}}€„†„ƒ}}}}}}}}}}}}}~~‚†‹ŒŽŠ‡„~~}}~~€‚€}zxvsruxz|}{yy{}}|{zxxyz{}~„‡‰Š‰ˆ‡‡‡‡‡‡ƒ€~~}||}~}}|{{{|}}{xyz||}}}}~€ƒ†ˆ‰‹ŒŽ‘’‘Їƒ€}}||}}}}~}{yxvwxz{}~„‡‡‡„~}}}|zz{{~€ƒƒƒ€€€‚ƒƒƒƒƒ‚€€€‚„†‡‡‡„~|{yxxyz|}}}}}|{{|„‡Š†‚~}zxvutuwxyyyyyyyz{{{{|}~~€…‹‘•™œ˜”‘Ž‹‰‡†„ƒ}}||~}|}~€€‚€}|zz{{{{{zz{|}}||}}€‚€€€‚€~}|||}}}}|zxxyz|}}}~€‚€~}||~€ƒ†‰‹‹Š†€‚|{{||}~…‡‡‡‡‡†‚}||}~~~~~~~}}}}}~~~}}}}}}}|{{||}}{zyxxy{}~„‡ˆŠ‰†ƒ€~~}||}€‚€}{zz{||}}|||}~~}}}}}}}}~€€‚ƒƒƒ…ˆŠ‰‡„}{{}€‚€€~}}|{yxxyz{{|}}}}}|{{{|}}ƒ†‰‹‹‹ŒŽ‘’ŽŠ†„ƒ„…†…ƒ‚€€~|{{{{{{{{|~}zwursuxz|~€ƒƒƒ€€€‚ƒƒƒ€~}|{{{{zzyxxy{}~~}}}}}~€‚…ˆ‹‹‹‰†ƒ€€‚…ˆŠ‰‡‡‰Š‡„‚€€~||}~~~}zxwwxz}€ƒ†‰‹Ž‰ƒ~}}|{{{{{{{{zywwwxyyz{|~~}}}~„†…ƒ€~~€‚€€€‚‚€€~}}}~€ƒ„††„ƒ}}}}|||}€‚ƒƒ‚€~}}~€‚ƒƒƒƒƒ„‰ŽŒ‰†‚}{yyyyxxxyyyyyyyyyz{{{{{{{}~€€‚‚€€€ƒ†…„‚€€‚€~~}|{{{|}}}}€‚ƒƒ‚€~}|{{{}€ƒ„†‡‡‡„~~€ƒƒƒ€~{{zyyyyxwwwyz|ƒƒ‚€}}}~€„‰‹‹Š‡„€~}}‚…‡‡†…ƒ‚€€~~€‚€}||}}{zyxwwvwxz{}}}}}}~€ƒƒƒ‚€€€‚ƒƒƒ}}|{zyyyyyyz{||}~€‚ƒƒƒƒƒƒ„†‡‡†…ƒƒƒƒ€~}}}|zxwwxz{{{{{{|~~~}}~€‚ƒ…‡‡‡‡‡‡„~||}}}}}}}~€‚ƒƒ‚€}}}}|{yxyz||}~~}||}~€‚†ˆ‰Š‡„‚€€~}|||}}}}~~}|||}}}}}|{zxxyz|~€ƒ†‰ŒŒ‰†…ƒ‚€€€ƒ†…„‚€}zyxxyyyyyyz{{}~~~~€€‚ƒƒ‚€~}}|{yxxyz}€‚€~~~}|{zz{}~€€‚ƒƒƒ„…†…ƒ€€ƒ†ˆ‰Šˆ‡„~|{zzz{|}}}}}}|zxvvwy|€‚€„‡ˆŠŠˆ‡…„ƒ…†…„‚€~}||{{{zzxwvvwy{~~€‚€„†…ƒ‚€€~~€‚ƒ…‡‡‡…€|zwvwyyxwwvwy{|}~€€‚ƒƒƒ„†‡‰Šˆ…ƒƒƒƒƒ‚€~~}}}}}}|{{{|}}~~~~€‚‚€€~}}}}}}|zz{{}~~}}~€ƒƒƒ€~}}|{{{|}}||}~€ƒ„†‡‰Š†‚~|}~~~~~}||{{||}~€‚…†„ƒ€}|||}~€ƒƒƒ„††„ƒ}}}}}}}|{yxxyyyyz{{{{|}}}}~€‚€}}}~€‚„…†…ƒ‚€~~€‚€~}}|{{{~€ƒ…†…„‚€~|{zzyxxxyz{|}€ƒ†‡‡†ƒ€~~~€ƒ†…„|{zyyyyyyz{|}}~€ƒƒƒ€€‚€€‚€}zyxwvttvwy|~…‡‡†…ƒ€~}}~€‚…ˆŠ‰‡‡‡‡…ƒƒƒƒƒƒƒ†‰‰†‚€}{zyyyyyyxwwwxz{~€ƒ…†…„‚€~}}|{{||}~~}}|zywwwxz{}~€ƒ„††„ƒ€~~}}~~€„‡ˆŠ‰†ƒ€~~„‡‡‡†„ƒƒƒ‚€~}}}|zyxxxyz{{|}~~~}}}~€‚ƒƒ‚€~€‚‚€€~}}}}|||}}}}~€‚…‡‡†…ƒ€~}}}}}}}~~€‚€}{{zz|}}}}|zyyyyxy{}€ƒƒƒ€€‚€€€‚ƒ…†„~||}~€ƒƒƒ€~~~~||}}}|||}€…‹‹‹ˆƒ~}}~€‚†ŠŽ‹ˆ„€|{zywvwxyyyyxxxyz}‚‡Š‡„€~„…‚€~~~}||}€‚†‡‡‡‡‡ƒ€}{xwutuwx{}}}}}}€ƒ„†…~{yx{}}|{zx{€†“ ¥”Ї‡‡„€}yttyzsnoqtx|€„‡‡‡ˆ‰‹ŽŒ‰‡‡‡‡‡‡ƒ€~~|{yyy{}}ytx|~€ƒ†…ƒ€|xusv‚‹z{}~ƒˆ‰„€~}}|sfZbis‰…€{wt|ˆ“““˜£®ª¥ž‚wkcioxƒ’–Ÿ§›‹€€‚€}z|~€ƒ†‚}z}‚†Šƒ~uj^_al‡¢œŒ€„‰ˆƒ}{}…Œˆ€xtsrw}€ƒ†„‹”šŸ¡–‹‡‡‡…ƒ{cLSbnqtsnjmptx}zvuy~†’¥­«Ÿ“‹‚‚“¤«¯°Š†Œ’‰€yvt{ƒ‹ŒŽ‰€wustx}€„„}tponprtuuƒ’ž£§š†x}~ti\OFDAAAEUdkloŽ›¤­Šƒ˜­³³²²±±²²¥—Œ…}||„‡Šƒ|upjx‰”ˆ}ƒ”£©¯ª™ˆ‚}}†‰~tx|~‡‘•‹„|w|€tZATgk]P[lvqkntytpuƒ‘‰€~‹™£«±¤˜š¦²³³©‘zuuvx{{zz~€€~qdYYYh}Ž‹ˆ„€|{zz}€…‘ ›—¡¬ª•€rd\iuyyywusssˆ ª”€yxveUWi{‹ª®²²±­™…‰ž²”wc\U\fmljmqv’‡ufXY_gv„™¢££œ‰xux~“ª¯©¢|VENXerzuow…“”–’‡~Œ¤—ŠŽ™£ª°²±±¢”Ÿ® ‹|€…v[@@@GUco{ƒƒƒ€~{pfcfit€ˆ‹Ž™§±¦›„zxv–®³³³³³–kB\vzePax€dIZ~œ•Žˆƒ€}z€–­²±®¡”“›¢‹tr­§™‡jK@@Cp›¨‘|…“–‚o{“¦‘}€–­›†{‚‘£¯ž„€|‚ЇvdWJCOZdmv}ƒ‡‡‡~tkc\k‚•ˆ}{€†ƒ€„™®¢€‰“¨³³³ŸtG\|‚vtwz€‡‘–Š~}”¬—sVfvˆ²³³³³³¦—Œ“š†c@@@EOXbkqnjwŠš…pt¬¢”…ves‰ž¦¯©˜‡—¨ª”Œ¢­—kUAQanx“¥³³³ž‚mˆ¥§‘}yuxƒ‹z€„pbr…yltƒgJHS_q˜¢¨®¬˜„}yuutuwy„“ˆ~zyy‚‹†xjqx|~kS@@@Wy—¡ª¯±²³³­š‡€”©°¬©’„sadmrkddin„œ–oF@@G^v~€•©¦Žwy}…™­³³³³³¦|¥¨sqvyyyywucQKT\dly‘«³³°”zpuy¤£xKYy‘†|„š°™‚wz}Ž£­”|gSBSdptyŒ£­šˆqWCZq€†Ž‰‚w^FUn{tsuwrmv‘®¢Ž}sio~Œ›«²±±±²«•€‰Ÿ³³³¬Ÿ“†zuˆŽ““€ms‡œ€rg[QHLy¤³³±¥™Šygnw}zxˆŸ¯š†}||eNAAARfr`NRbq^K@@@Qdvƒ’‡•©³³³‰^@@@b²±¯¤‘€reairplm}ƒkSLDJ_s~‡ˆu`alvxzƒ’¢’€vxyxwx„‘•’Žˆ‚‡†}{’ª•jCl“•mEZw†xjuŠœ˜”“““›£¤—‰{z¦¯±³³³³³³ž…ssrpol[ILd{hQH^t…ˆwej€–wUMmŒ„tgow|€ƒ’ –oFOapzƒqg{œ§²­§—wVaz‹yfZTNp“¥”Š€~”ª³³±˜iVCQdlYFSl‚€}q]Ig‡˜Ž¢³³³³³³£”ƒp]v˜±«¥ŠeAAA@@@PahWFaŒ±¦œ„dBQb³w‘¬”nU|£«Ÿ“™ŸŸ—š¨§|P@@Doš±²²­§žŽ€zxutrgTA@@@@@Obu…–”…xˆ™Ÿ—~iWMDDIQxŸœqD\{Ї“¤®’viiimqqlgeek„Ÿ«¯²²±¥Šq„Ÿ³³³³³³³³œpD@@P|§¥’‚€}nXAZt‚€€€}whT@@@J]qbNIf‚Œ•š §®¡“ˆ{‡™¡zQNdz¥³³³³³¨|PK[jpvwpj`UVsއ|dL@@@^|”¢¯³³³³³¯©¢“ƒ„™¯bG_w~}|†Œ’o]QD@@@@@@@@@@@@@d³³³³³²¦™„eE@@@@@AACWjjVBIS]gqw|€€‚€~ƒŠŒ†€Œœ§£ž¢ª°„YFQ\w“£‘jTDf†|k[K@@@b޳³³®¥¡¦¢’£­”|gS@@@K`u‹¢³³³£Ž{{{ƒ’¢’€o]LVj|†’†}fNS€«­§™tN]‡«€WK`u~…‚fI@@Gsž°­©šŒ‰œ¯³³°¦›‚aAWmyyygQLw¡˜xYYYe{‘‹„x_G@@@@@Pk†mQR~ª¥”ƒvgu”³³³ŸtHd‹¥˜‹‡‡‡Œ™¥² Œw_GHQ^{–™‰z€†‹Žš¨³³³³³°„X@@@Tj{~Š”šidrkVJS[w—®•~x€‡‹’‹†}cIDINWajr{Ž£¬—‚uh]]]do{¥¯¤™’Œ…€zŠ—¡¬¯¦žr]HHS]]]cnxz{xlaVKHtŸ¦Žx…“›—“œ©²²±±²²ˆ|zxePG_x„ˆ’šˆwcNG[nojeb__beilq|…”¥°£—𧱓v_QB^“…xvz}zwx{zusvy”‡{‚š²³³ª–‚uh\SKLSYUPKFA]}…|jTFrž­¢—ƒocfintytou”™uXiƒ“‡|iTAFKXl€„…dH@@Fsž°­©¬°²±±§œs~˜³³³ª˜…nTCGLYj{‘§³³³Š_DMWs•³³³žzT\du­¥”Š›¬³³²šƒnYCg’©†dYYZ`fiiiou|„Œ“˜—wVFCAl˜©’|™¤¯³³±“vl{‰‘˜Ÿ¢ˆbFr©–„}vsvyz{{wssuwbMOs–€{’ª™rO`r…š°¦˜‹‡ƒ„†¡²ka…ª—vXND[‡²²±±²²ž†rbSJE@@@Rv™…kZ^ay—°œ‡Šž²”ueoyŒ¡¯œŠtZBnšŸsGf’­—‰Ÿ°’tc_Zftv_GVq„ue]]]~ž§‹o€œ±¨ ”‡|ƒŠˆzk{Ž’oL@@C[t}xtŠˆ€mUDZpŽœ¤¬°¯¯Ÿ€ˆ“•–އw]DTjz{{ŠŸ¯‘tipwww€–­¢Œzsl`PAa€Œpƒž­˜‚ukblv„˜¬ž‹…™­œ}dwŠŠzjƒŸ vJCEK^p…œ²±¯©ƒwiXFOdy§¥Šphb][Zs•³³³³³³³³³³³¬£ž§¯¥{gSM[h\MAAAM`pbTKFAEJ[©¬¤š‡uv„’›£˜qHe®œ‰vaN^m€˜¯¢€ypv€ˆqYR\emvt]FPctvy†œ³¥—‚dFTl}}}€ƒˆ™ª¨“~xty¨¡}{wrn}Œ’‡|z{~œœ‘†…ƒƒƒƒ„…„{qkhfmtuojbYV_gbWP_o‚š²³³³³³¨šŽ‹…}t€Œ‰s]VQRaqwx{¤¦•„lRFVeov}ƒ‹‹…€~‚‘ §®³³³²°­rk€””‘’ž«ž†qkdcfiqzƒ‘Ÿ§¬¬•~š²¦šŽ„{xwsjafs€”¨³³³ŸŠu_HHQXOE@@@ThpaQRXcƒ£±²³³³­¡•Š„ymov}ytpmjx‡–¡«°±°š„|}}ƒŠˆ„}trˆŸžŒ|ƒ…†{lfzŒ‰{noqrtulaYVTZbgWGSu–™›™…€€€‚…ŠŽ‡€…š®°¯©“~†ž±¥™‚x€‹ŠrZ^m|Ž¡¤›“™Ÿ˜€f{š³³³¨—†‚~ytnaRMau€…Š…}|€†Œ‘•ž¨°­ªŸ€{vx‚‡tfXVZ_tˆ‡€~xsdQ@@@L`tˆœ©©© ”›©£‘€€‚ˆ” Œran{‹Ÿ±±±©˜ˆ‰Œ“¡¯®¨ zv†|qhebw’©­±²°®›‰{qgo{}wz€…ylfhis}}yrkj‡¥³³³³³ª”€si_RE@@AWl˜¯¤“…€yvtrw{}}}lZPV\iw„Š„|€„ž¯³³³³³¦’}{{‚|totz‚‡™–Š~€„ž¯ªŸ“‚qcXNW`lzˆ}k`ir€Žœš˜’‰€jQ@@@BEGDBW§«­¯¯¯¡†˜ª±²²¯«ž…mkls‡œ¦¬­WGT`r‚“–ž©¯–~v{~}||Œ¡°¢”ŽŒ‹™§¦‘~£©†eSIBWksojd^]fosv{‘©§“€~|yrkgddnxwpk… ¯±²ž‡|‰˜“†~‘¥£Žyndbo|„Œ’‘ŽŒ‹€ty“®¥”„yngdbfkgXIWivy{Š“”–›¥® ‹˜¦›‰{zx{€‡“–”“Š€z~¡±¤–‰utuusrdQDZp|†‘œ¥«±³³¯ ‡{xtrssplmxƒ{sjb`dintwtruz}yuof^it|}}¢³³³³³²§œ›¥¯¡}wtsqnkmsytnhc_fp{„Ž’ˆ}zxqha`^[WUw—¡‘€‹™¤©¯±²°›†{vrleemv€Š“““‹€t~ˆ”¢°³³®Œ…„‚|{‚€~€’£€Œ— §®¯¯ªž‘Œ‰…€zxyyupfUDAACMVbnyvsqonhb`jstsqlho€’ž©°¯¯­ª¨£ž¢ª²§•’Ž‹…~xŠŒ‰…€}zyx{~€‚wigt€~€‚€|wk`cxŒ‰ƒ|xwvuroorubNCJR`q€Œ˜Ÿ¡¥ª°®«¦šŠˆ‡‡‡ˆ‹Ž†~xz{€ˆ}meeer‹˜¦Ž‚€}Œ–Š…~‚‰†€€…Š€wqonrx|~„‡ˆŠ‹‹‹™©­Ÿ‘Œ‰‡Šˆ~tx}~zvutz§ž†r{‚‡‡‡‚xlaVKEYmx|womu~}zy‚‹‰yxvvww~…‰ƒ}{{zoch}‘‹‚‚†„€€‚ˆ’œ¥­²±±±²®œ‰‚€€‡Ž‰ƒ|tmjf]RIT`^PAQboru~‰•¡­³³²£”Šˆ‡}ofilqv{zxvrnpsvy{‡™¦–†…œ–ˆ€y~„‹•™ž£§¬ªŸ”–š˜‡wuy}}}|yvxz{xvx{~~†”¢¥§§¢˜“‹zhbdea\Z\]eow|Œ›§—‡}wroldTEFMVi|€yr}‡Š‡”¥³³³°¬¨ —‚wuuuuutsqg^_juƒ’š“Œ’›£¥¨£™’•—šœ‘ƒywtvz‘¤©œ‰ƒ}vpaPAIP[jywurnjow€“§© —ž¤¤˜Œ‚yrvz€…І~|z{|~€‚ˆ•‹Š’Š‚|wr|ˆ‘ˆ€}}~‘¥« ””•–“Š„vnbRBReu€‹Š„€Œ—–‰~zvsrruz~~‡Ž‰ƒŠ”‘‰‚{ukbjsxurv{|y}…Ž‹‹Žš¨°¥š•‘’•Ž}lmqsqnptwvtyƒŽŒ„}yuruxqbTevƒšž¡¤¨­­«¨¡š’‰€~|xuohcluywvuttvw|ˆŽ”ƒxz|‚†zj`jt{‚~zy|}{z{{|}~……‚€~|~…Œ‰‰–£ª¬¯°²³³³¥–‹‹‹ˆ…‚~zxyy|~€‚†‹Ž‹ˆ‡‡‡ƒ€~zvtsqnkiijnqrpnkhfimmmme]^hqtvwvvutv…–˜‡‘œ¥«±³³³³³¬¡———–”“Š€{€…}na^[_juuuuuuwz{{{}€‚€}€Š•”‘…~}~|yxyy|~~~|zwpikt}ƒŠŒ„}ƒŽ˜¢«­«¨›Ž‰–˜››”‰ˆ†…ƒ€{vutmYFFMUcpy€†…ƒ|ƒŽ–“‰€x|€~zz{{zx‰”Ÿ«¦’€„‰•†€‡Œ€vutw€‰ŒŽ‹‡‚~„†„ƒƒƒ„ˆ†|qiaXLAO_kptx|€‰“˜š¡¦¦Ÿ˜‹~ssruz€›Ÿ—ˆ}||wpjpwywvtrsw{zwx‡–š–’‘”¡®¨ž™¤¯©›Ž„{vwwsmkorlbZ[]bksvz€‰”˜›š†‚€zuv€‰‡‚}z}‚‡ˆŠ’¢±§›ƒxwxxk_ezކz} «ž–œ•ŽŠˆ‡ƒ€|yuy€†|xvt|„ˆ€y‡‘Ÿ­¥z‰Œ…}|{{ztjbjquttvx|ˆ†€||}{xtsrsx|~€‚…‡‡‡ˆŠŽ˜¡™†ƒ€~~€€~xrouzxrnoqpmjnsx…‡‡‡ŠŽ‹ˆ‰–”‘’•›¢§—‡~|zyyyvtrol_SUcqv{}zx€—œ¡££¢™ˆ‚|~€‚€~}|}~~‡ˆ€yqicmw€‡ŽŠ…|ƒ‡Š‡}rtvy|~}}|zxwƒ–”“‰†ƒ…ˆŒ•ŸšŒ€yrke_dlsw||{z{}€‚yx€ˆ‰ˆ†ƒ€|xy‚Œ”œ¡™’’—œ™•–Ÿ§›‹~wpoqsqooqsvxyxxy|}vppv{|}}}}}}~~€ƒ‡“š¡§¥ ›˜””•–Œ}{zxwtokhge`\]ciotxyy‚”‰€|~…Šˆ…„Š‘‘Ž‹ˆ‡‰Š“œ€}|{zxwvvwyz|}|{z|„Ž—› ›‹{€†‹‹‹’‰‹”œ£ª¬¥ž˜“Ž‹ˆ‚{tvxxurkc]\Z\_aaabdelsx{}{wtx|€‚†ˆŠ‰†ƒ…ˆ‹•”‹ŒŽ‘’Œ„™›™–ކ~zwtruwwwx}€‚€€sf`hpw~†”£¦¡œ•ދޑ”•‘Œ†€ytppv{{{{xvuttwzzxvuuyƒ‹†~ywvvy|ƒ’¡š‘‰„{xvwy|‚ƒƒ‚€~~zusrrpnpu{}~€‚…‡‡‡“‘‡}{z{€…¨£Ÿ¡¨°®ªª­°®«§“Š‚{xutwyxurmgjpuoiioux{}||zwunhda^lz‚€€…Œ‘‹…ƒ…‡”¡¤šŒ‹‹‹„|ssrsuwz}~{xyz|€„‡‡‡‡‡„~wtss|ƒ‰Ž“““’‘”–•“Œ‚yyyyyywutvwyz{{{yurux}„‹†ƒƒƒ€|xy{†ŽŒ‰…}{{||}}}}€ƒ…†ˆ‰Š…€}yvy|}}}zvtvy~„‹’™—‹€|xusruy~…Š–”“–šŸ ”‡‚€€‚…†„ƒ€|zz{}~ztrtuvwxz{xrnswz{{}€‚‰•‰ˆŒŽ‹ˆƒ}vx{€‡Žˆ‚{yyyz{zwtw|€„‰ˆƒ€}{yvtsstuwy{~‚ˆ‹‹‹‹‹‰‚|tlflsx~‚~xtuuvwxy{|~…‹“–•”‘‹…†ŠŽŠ……‰ŽŒ‰„€„†…ƒ€~€ƒƒƒ…ˆ‰{wvvxz|~~}}|}~€€‚|{{|}}|zx{~†Š‘˜ ¢›’‰‚|~„‹’™—‹zusw|€‚€|zxyzyrklptx|}{zwutwyyy{ƒ‹‘’Œ‡€z|~€„‰†€ysmmsyyyz}€ƒ„†‡‡‡ˆŠŒ’‹‹‹Šˆ‡ˆŠ›§«®­¢–‹zz{|}}}|yrkhgflqsssqooswtpotz}~€‚……‚€€‚…ˆŠ‡„‚€€{vtwy…‹‹‹‹‹‹Ž‘‘Ž‹Œ‡€€‚€~€ƒƒƒ€{xz|~Š•Ÿ¦­ }zyyzƒ‡‡‡ƒ{zxz}}{ywvtsqqqsvxy{{{{~zz{}‚ˆ‹‹Š‰‡…~{y{†“’Œ†‚|yvvwwvvrmjnrvz}zvux{€†‹‹‹Šˆ‡ˆŠ‹Ž™¦¬¢™…}}|~‚†…ƒ|wutu{€ƒ…†ƒ€€…Šˆ…ƒ„†‡‡‡‹‡€~}|~}zwwvvxyupnpqv{~|yuuuwy{|}}}}}}}}}}||}~‡Š„~~€ˆ—¦©©¥•…†‹Ž‘Œ‡ƒ{{zz{|}~~|{yvtsrrrsx€†ƒ€~{xwwx{~‚‰Ž‹ˆ„€z|~~}}}|zyxxwvvwwwwxy{|}~€ƒ…†‘Ÿ¦ž•Œ‚z{}€‚‡‹ŽŠ‡„€€‚€~z|~~~{xvx{{zzz{{xvwz{{z{}€‡’…|vy{ƒ‡ˆŠ‰†ƒ€}|}~€€‚‚€}{z{{}~€‚†‡‡‡“’‰€„‰•‘‰‚{yyy{}~„†ƒ€~|z{}€‚€~{{{zyxz|~~}|}}ƒ„†ˆ‹Žˆ‚~~|ywwwxz|€„…~}}}}}|{yyyyyyz{{{{{zz{}€ƒ†…ƒ‚€€€‚€~}{{{{{{~€‚€€~}}}~|z{|~€‚ƒ…†ƒ€~~€„ˆŒ‘‘Ž‹ˆ„z|~€€ƒƒƒ‚€€|yxz{}~~|xvxz{{{~€‚€€€‚‚€€~}||{{|ƒƒƒ„†ˆ‹Ž‹†‚€~|zz{{{{{zz|~|{{{{{|~~{z|}|}}zxy{~€‚€€ƒ†ƒ€{{{|~~~…‡‡†ƒ€€…Ї‚€€‚„…†‚€…ŠŒ‹†‚€}{{{ywtqnqtxxyyyyyxy{}~„†‚}}}~~{xyz|}†Š‰‡†„ƒ…ˆŠ‡„‚€€€‚ƒ…†„~~~€‚…ˆ‰ƒ}|||}|yvwyz|}}}}}}~€‚……‚€€ƒ†„~|{{{}~~€ƒ‡ˆŠ‰†‚€}}}|{zz{{zyyyyyyz{|~~{zz{{{||}‚†‰ŒŽ‹ˆ…„‚€~}}}}}}}|{{{}~}}}}}}}}~~}||}}}~~€‚ƒƒ‚€~~~}|||}~€€‚ƒƒƒƒƒƒ…†„~}|||}~€ƒ…†„~~}}~~~€‚„…†…ƒƒƒƒ€~~~€‚€}zxxyyyyyyzz{{{{|}}}|{zz{}}{zyyz|}}}~~~~~€ƒƒƒƒƒƒƒƒ„‡Š‰ˆ†…ƒ€~||~€ƒ…†‡‡†…ƒ€~}}}}}}}~~~|{zzz{{{zxvtvx{}~~‚€€‚„†…‚€€„†ƒ€~~}}}}}~€€‚‚€€~}||}~~}}~~€ƒ„†„~}}}~~}||}}}}}|}€‚ƒƒ‚€~}}~~~~~~}}}}}}~~~}}~€‚€€~~}||}}}}~~~~~~~~}|||}~~€‚€€~}}}}}}}}}}}}}}}}~~~}}}}}~~||}}ƒƒƒƒƒƒƒƒ‚€€„†…ƒ€}}}~€‚€~}{z{}}}}~~|{{{{{|~~}}}}}~~~}{{{|}}}}€‚ƒƒ‚€€~}||}~€€‚‚€€„…‚€~}}}}}}}}~~~~~}}}}|||}~~~}}}}}}}}~€€‚‚€~~~~~~}}}}}~~}}}~€‚€~}}}}}}}}~~}}~~~~€‚‚€€‚mirrormagic-3.0.0/sounds/snd_classic/soundsinfo.conf0000644000175000017500000000014413263212010022156 0ustar aeglosaeglosname: Classic Sounds sort_priority: 100 mirrormagic-3.0.0/sounds/snd_classic/booom.wav0000644000175000017500000006705513263212010020770 0ustar aeglosaeglosRIFF%nWAVEfmt "V"Vdatan‹€w|•®®©ŸŠummmmlkkkƒŸ³³³³³° ‚vj}‘¡©±¯ª§¬±³³³³³³³³³³³³³³³³³³³³³¬¤—€haaaaafowoel‹¬™{aa`_^^€ ¤ƒbq†™¤¯³³³³³³³³³³¯¥›†nYYYYXXs£ª±³³³³³³³²®©˜yZUTSSSSSUfwveSQQQQQ`ro`n²³³±­©¬°³³³¬¡–‰|€˜°kONLKKKKJXs’—£°³³°¥™ƒeGGGGFFP\bVJGHLu³³³³³³³³³³³³³³³³”u]PCa‰¢zQL^p|‡•¢°³³³³³¢Št_K@@@Pbpw~nU@@@@@@@@@@@@@EYniT@@@@@@]™¤¯³³³³³³³³³³³³³³³¯›‡rYA@@@@@@@@@@GPZdnjWC@@My£’g@@@LavdOH[m„³³³³³³³³³³³¡‹€•«³³²¢“ˆƒ~|{yyy‚¢¦ €}{r[E@@CQ`w“±±²®£˜ ª³³³švV{ ¬žtU@@@@@@@@AAASfjWD@@EZo…œ³³³³³³³³­–€n]QxŸ³³³Š_GVeš³³³žyTxœ³³³Ÿ‡q]HGPYOF@@@@@@@@So„iN@@@@@IayyqgWGNd{Ž£sH@@Ip•££¢š“‹ƒ|sik‰©“hDVigUB@@@@@@@DWjwŠnQ@@@GNTX\VKCc‚˜¥±³³³³³³³±£•–¤²f\‚ª³³«†b\jwbMI\o† ³³³•jAAA@@@EJLGBNas}†‡€z†”lHcޱ±²°¬¨“kWC@@@@@Ncx§uKEBNwž«¯²²±˜mBAA@@@@@@@@Qkƒ–¨³³³³³³³³—qMHC@@@N\is}zsrŒ§™nBm™¬›ŠqU@@@@@@@@Syž[H_wmU@@@@@@Th~•­’iGDBY€¨–ƒyvtvyv_H@@Cjš‰ydO@@@@@@@@Md{xtrtueQ@@@@@AQalryŒ¢³³³³³³³³¢`SH@@@]‚ €yxxy{s\E@@@@@IXg€š¥ž— «­™…oVDh‹¡©²lQJB]ƒ¤ª°©˜‡q[KFAd±±²³³³³³³³³«£š”•¥³³³­¢—‡z`G@@E\t‰ž²‰`FDA@@BGLJE@@@@@@@@AAAAA@@@Tx›”Œ}bGSj•ª³³²£“bE@@@@@@@CgŠ¡©²³³³³³³³­ˆdhŒ±³³¤€[ROV}£³³³³³£€^QH@@@@@BVjw†‚{yxhR@@@@@@RcotyhR@@@Qkƒ–¨³³³”rWMC@@@@@@@@b… ¢…`@@@@@@@@AAAf‘®š†zqjw„’¡±iY€§³³³³³³³³“sYNC@@@@@@@Al–¯±²³³³³³œz\¡³³³³³«‘ydQ@@@@@@@@@@@@@@@@@@@@@J`vŒ¢³³³™uSLD@@@@@@@@@@@@@@@@d†—‰|hR@@@@@@@@@@@RepdWNG@@@CHMjˆŸ¨°®¨ž…lZNBUhuz|wu}„‘¢³³³§ŽwbOCJQn’®‡`KFAgŽ©©©‰b@@@@@@@@@@@^”qM@@@@@@@@@@Ko’ƒ`@@@@@@gª®²³³«†bj޲ „‡Š˜§¨UFCDl”ª®²‘mQJB@@@@@@@@^}”¢°“mLGB@@@@@@@@Tk€–¬–mKužœqDh’ vK@@@@@V}¢~X@@@@@@@@@@@@@@@@Wqˆš­³³³³³°­©™‰ƒŽš£«¬„^d‹²¥—Œ…Ž¢°£—_@@@@@@@@@@@Xz•ŒƒsZB@@ER_y—®¡”Іƒ€…𝳳°¨Ÿ…b@@@@@@@@Jh†™¦³³³³³³‘ofˆ«£{bJ@@@@@DKRMFDSaz—³³³³³³“qVMC@@Fl’”|bUH@@@@@BIQ[fruxpZD@@My¥³³¯ŠfPHA@@ETb[L@@@@@@@@@@@@@@@@DIMHC@@@`ƒ›˜”›¨³³³¢‚cVI@@@@@@@@@@@@@Os–¤¬³³³–kAAA@@@@@Ko’ƒ`@@@U{¡‡lVLCHR`‚¥˜mBn™¯¦ž[@@@@@@@@@@@h“£xLaŒ¬€T@@@e‹œŠywxz{}‰ž³³³¨wcO@@@BEI]pnXB@@ADGf³³³³³³±¯žtI@@EYnvwwvt|Ž ¨®§€Zi³³³³³³lQJBCEIUajs{{zyyy…Žž­™sPwž¢€^SLL[iwƒž¬³³³¯«šrJ@@@@@FPZdowz}|yr]H@@Ci¥¬²³³³³³¦•‰š«œsIp˜³³³•qRKC@@AHOYer†¯°²« •iXMB@@Ms˜¦¬¯¡”“–› ”oIKXh‡§—lAAA@@@@@@@@@@Ep›±±± Ž‰›®³³³³³®¥¥­£|U[kukaVK@@@T©°±§€Yi³³³tJEB@@@@@BLVTJ@@@@@@@@@@@L]o‰¤³³³³³³³³°¬¥uaQAj•±²²³³³³³³³³³³³³³³³³³³®¨¡“„}{zwtnbWNG@@@@@@@@GXjzŠ™¤®³³³³³£€_QH@@@Z€£©¯®¦}YGZm{‡”¡­³³³ Ž~qdgno\H@@@@@@@@@@@@@@@@@@@@@b…Ÿ¨°³³­ŠhTJA@@Pvœ‡gLGB@@@@@Qu˜¤¬­›ˆ¢®„[FCA@@@@@FMU_it€‹‹‹‘ °³³­™„nVALXblvyz{zzuogXH@@@@@@@@IT`mz}yv¥ xNk”¯¡“ˆ€v`KHXh‚Ÿ¤yMb°ŸŽx]A@@@@@@@Io”‹e@@@@@@@@Jn‘¢«¯q`]Zgv…—ª°±³³³²°¯°²³³³³³³³³§”hN@@@@@@@@@@@@@DLSvš³³³–rRKD@@@gŒ¥«±³³³³³±°®¥›‘„yqjl–¢ª°­ªª­° ŽzaGM]jotsniYJ@@@@@@@@@@AN[emuxz—­’gAAATx›Ÿ¡ ˜Œ‰‰–£«¯³³³³³³§™Š{kkr|‘§ŸxQID@@@@@@@@@@@N]qŽ­dAAAZ‚§€WAAAUl~~~}{rjb[TME@@@Uq‰š«³³³nVLB@@@@@X|›xTU€«±²­›ˆ‡” ­³³³³³³³³™y_hp{†“”–™ §£œ———ž¨³²¥™€uz‡‹Ž{`GDBHWelspZE@@@@@X~£©¯®£˜Š|mZG@@@@@@@@@@FUeow€”©³³³³³³³³³³®˜ƒ{{|‘§³³³³³³³³³³³³³³³³³³¦]cw‰š«›rHq™¤€[NF@@@@@@@@@@@AANz¥”iAAADLSMEOwŸª­«™†Šž²³³³³³§™Œ‚yhT@@@HXh[L@@@Qi~~rZBUk—­”nMHCBEHPYYNBL[mЍ³³³³³¬ž‰ƒ…™­³³³³³©˜‡mRFTblsu_IM`s_L@@@JU`jt†²±¯¤}gP@@@@@@@@@@@MZn¬dAAAZ‚§Œq\OB@@@@@Odu`KW€«°±³³³—rRKD@@@LWahptw}Š˜Ÿ¤¦WAAA@@@@@Z~›‘‡v\Bj”±²²–rRKC@@@@@Os–¤¬³³³®¨¢™’¡±³³³³³¤}l[\k{¥³³³³³®š…{vrsu|‹š¤¬³³³³³²²±¤‰phbZOD@@AAAZ…±¡Žz`F@@@@@@@@@@Pt—¤¬­›ˆ€}yyy„š±³³°ª¤™…”¢«¯²¨’…zfQ@@@@@@@@@@@@@@@@@@BKUl°³³³³³˜vXNENe{{{ytnv€€fJ]‡±±²³³³«¢Ÿ¨°³³®‰eg‹±‰^AAA@@@@@Z„¯°²³³³³³³³³œzYOE@@@@@@@@ITb‚¤­¢—Ž„…˜«°±°¤—…~’§²°¯™€iXF@@@@@HVd€ž³³³³³­ŠiTJAh¢’‚wmhtŽ¡³³³²±±‹aAAA@@Dk¦¬²«¢›•™§³³³yTLE@@@@@@@@Oe{§³³³³³³³³³³²®ªª¬®°±³³³³³³³³ž|ZhwvaKQ]bTE@@@@@@@@ISd„¥°±³³³®¥‰vsŠ£¬¯±¨ ”†ycM@@@@@@@@Usž«³³³³³­šˆ€”©³³³³³­Ÿ‘ˆw`I@@AO^ipvy|‚—¬–mIT`^PBN\o«°¬¦˜‰ ²³³³³³³³³³³²°¯°²³³³³³³³³®¨žyS@@@AAQ}¨³³²®ª–yZaipv|‚€}mV@@@@@@@@@@@@@C\t†š®³³¬‡bOHAO]_QCdޝ°²±°­š†rZCLYkŠª“hGtŸœsIEB@@@@@@@@@@@@@Pt—Ž~ncWPLGEB@@@@@AAAN_nprhUAQcgUDc¯°²³³³³³£€^QHEUeu„“—›–‰|fP@@@@@@@@HUa€ ³³³­§¡˜•‘« zRp–³³³³³³³³¬ “ˆ}uuuvw{‘§¥’gO@@@@@@@@SpŒ›ª³³³³³³³³³³³³³ ~[SLW€©¬£—yZJEAWmpZD@@@@@@@B[sˆœ±³³§‚^NGFo–«¯²³³ª“|rkcTF@@@@@FS`mz‡š­³³±¢’}`C@@@@@KYj‡¥™nBm˜³³³±°ª˜…~zy¦ŸwMl•³³³±°¬˜„~‚†Œ’‹jI@@@@@@@@@@@@@Vp‡™¬³³°†^FDAdŒª®±¨˜‡kN@@@@@@@@@@@@@IWfƒ¡³³³³³³³³³³³³³³³³¥•‚fIAAFq›—mB@@@@@@@HlŽ˜‘Š…€€„ŠsV@@@@@@@@@@@@@FXi€™¯°²³³³³³³³³•qRKC@@@@@@@@@@FZmfR@@@GTajsyyy‰ «€T[†²³³²°¯Ÿ~zuw~hN@@@b‡¢ ”‰vnaQA@@@@@@@@@@@@AUivxyˆšŸwO@@CiŽ¥¬²¨›‰jJ@@@@@FOYl€dG@@@@@@@@@@HYkortwz‰Ÿ¯†]\…®³³§‚^NGFo–«¯²³³©wcPCR`]N@@@@@@_‚Ÿ§°®¨£©¯ŸxQr˜°§Ÿ£«²²±˜nBAA@@@@@@@@@@@@@@@@JUg‡¨”iAAA@@@@@Mq”“‡}|z}†lQ@@@Rg}“ª–kAAAJ`u‹¢³³³˜tSKDU{ ƒcLGB@@@@@@@@@@ENXcm{’ª³³°‹gPIA@@@@@Z~š‡vdSA@@@@@@@@@@@@@@@@@@Zy‡iK@@@@@HVdXJ@@@@@FjˆeB@@@@@Qg|“ª³³³³³³³³³³­™…~€“¨tKEBIc}yu€Š’—œzV@@@AAHd€y\Cn™±²²³³³³³³³²±¯˜nC@@@@@DINPSi²†[J`vskbTF@@@@@@@@@@@@@Pf|’¨³³³‘pVLC@@@@@GR^fokWDKXiˆ¨•jAAA@@@a„Ÿ¨°®¨£¨¬¦—‡mR@@@M]fVG@@@@@CHMo–³³³« “sQ@@@@@FVepx‚–ª²°¯¢–”¢°³³³³³²°­‘u_QBf®¬©Œe@@@@@@Th~•­“jGDBX€¨¬°³³³³³«ˆfp’²²±œrGAAEUentwaK@@@@@@@@@@@@@@@AUjmXDSj{xuƒ›°†]\„®³³§‚^NGFn–«®²³³³³³¤‘~eK@@@@@EQ\zš³³³švSLD@@@@@CJR^ly…‘’Šƒ„†}bF@@DWjrtuj_WSN]oyoeYLBP^u’°ž‡r\F_†©«®–lA@@@@@@@Hl†c@@@I\oaNBGLXhutrv~†–§³³³–rZ£¬¡—Œ{zz‹¡³³³³³³³³­£˜Š}tx{‚ˆ“’‡~tgVD@@@@@Mauuuvxy~‚†…ƒ‰“¦®³³³£’cH`‹±±²³³³³³²°¯ˆs^I@@@@@@@@@@@@@@@@@@@@@@@ADGECCScz•²‡\AAAa‰©­±³³³³³³³³³³¬–€z{~’¨tJEBNwžŠb@@@@@@Uiy€‰tW@@@@@BXnƒ™°¯«uL@@BMXfv†—¨³³³–rXo…Š‚{pdcp}£ª‰iVK@@@@@@@@@@@GQ[gtˆ’”–•’™§«ƒ][r†}xvtux•«—nGEBU}¥–‚tokklkZH@@@AAGWf€œ³³³°¬¨Œq\OB@@DOZt”¯…\FCA@@@@@@@BMY]]]RG@@@@@F`zŽ¡³³³³³³³³°¨Ÿ•‹‚|uhUB@@@@@@@DYmjUA@@@@@@@@@@L]o‰¤³³³³³³³³³³³³³³³³’pVLC@@@@@GR]RGI[n†Ÿ¨|P^ˆ®ŽnXMB@@@@@GQ[iwˆ²³³³³³’iJUax•²•zcSC@@@@@Y}¦®³³³§›…|uoid`agmsxƒ™®‘hJWe`PAKT^gpqqqqqstvwyz|}¥³³³³³³³³³³³³³³³³³³³³³¥|eM@@@@@@@@@@CVj€˜±³³¥€\NGHp˜¦¡œŠxfUC@@@@@@@BQadYOWbrŽª³³°ŸŽ„€|‚ŠŒ†€~}}„‹“›£©¯¢{TIDKs› “†€{wutoiglptx|~tjZJ@@@@@@@@@@Bf‰ ©±³³³³³³³³³³³³³³³³³³—sRKDHUahotvwoe[PEAABN[p®³³§€YJE@@@DLSvš£xLAA@@@@@@@@@@@Tm~zugS@@@@@@@@@@@@@Ef‡œ§²³³¥€\NFDXliXGEB@@@@@BGLhޝƒXAAAeœtL`‹±±²vOID@@@@@@@@ELTyž³³³³³³³³³³³³³³³³³³³³³§˜ˆyi[NBl– uI@@@@@NdycMAAA@@@@@@@@@@DLS_kmYE@@DYnqeZPF@@@@@@@@@@AN[p¯³³³³³­¤™{\S^iklnqstuuuuƒ›²‰`FDA@@Im¢«²§œ’ˆ¤³³³£ybK@@@@@@@@@@Fc€z]@@@I^ruup\G@@BSe{•°‹`AAA^†£{S@@@JT]fptwyyylV@@@@@@@@@@@@@AFKUbpyŒ®³³³³³yTLE@@@_…¤ª°³³±ŽlUKBM[hpyŠŸ³³³¦ynd_bekry„¡²³³²±±¬§¤ª°²±°¡’‡€zwuqh`VJ@@@@@@@@@@@ITb~˜¦¬³³³³³³¯«¤|k\MHCRv™¤­¦€XJEFo–«®²³³²°¯c@@@@@@@@ENX_ekothS@@@Kbx£¦Xk‘±¦›„cA@@ER_x“§ ™¨³³³³³³³³³³³–mGEBCHMr˜³³³³³°¡‘•œ“‰y_E@@CLV`jt|‚ŽŸ°¨›‰jJ@@@@@@@@i“ŸvKb±±±±²³³³³³³³³³³³³³³³³£„eVI@@@JVf„¤³³³¯«£”†€}yvsk_SLE@@@@@DRap€Ž‹ˆz_CO_sŽ«³³³³³©˜‡mR@@@@@@@@M`tŒ¥³³³±°¯°²³³³³³¯©£•†}zx~‡’•†|vqgUDO`s©³³³³³³³³³³³³³³³²®ªŸŒ{eO@@@@@@@@CHMIC@@@^”qMNcxxy”¦¬°³³³šxXOEV¦—„r\F@@@@@@@AAAHWg\L@@@X|¦®ŸyRIDMvª¬­Ÿ‘ˆ‚~|zxurstq]I@@@@@Lh‚Š“““›§¯ˆaTbpg[Zn“¤°ŸŽƒ~xrmhebWKEYnƒ›±‡_FDAc‹¤–‡rX@@@@@@@@@@@@@@@@IWe‚ ¡vJAAJr𠓇‹˜¥±³³³³³œ~`SG@@@JS`t†’›œwP@@AHO]tŠš¨³³³³³²±¯¯±²³³¬”~y{~„‹‰taMBGLT[cmvrfYPF@@@JUbr{tvxŠ• «³³³³³®‹im±²±±²²³³³³³³³²mi‹­£}cI@@@@@Nj„–§­œ‹w`MHC@@@N]`RC@@@@@@@ASdptyfP@@@Qh€”¨©–„€„™­³³³³³³³³nau‡tW@@@@@@@@GUd€¦~TFC@@@@@@EJ\‚©‘fAAA@@AgŒ¥«±³³¯£—~^@@@@@@@@@@@@@CRby•±³³¥€\NFDSc`PAWmywvdP@@@@@@@@@@@O_n}‹™§³³³³³³ˆ]ENXbmq]H@@AQamv~kR@@@GQZeoiVBh’ªž’ˆ€yyx}…Ž‹€cF@@Io•ŠeCn™±²²«£˜‡w{‡“““‚cC@@Nt™§­¬‡cOHAk•¯±²³³°£—‹€t`K@@@EJX|ž«¯³³³®¥Œ|uˆ–¥±±²²±°…ZAAAVp‡š¬³³±œ‡rZC@@@@@@@@@@Tx›{WQ}§±²³³³³³²mULB@@@@@Y}œ’ˆv]C@@@@@@@CUfptwww€—®³³±«¥šŒfN@@@GNWdqx{~~†Š…€}||zywqlmsy€†ˆ‚}o_Wes{…kO@@@[z“ ®³³³³³ ~[zœ³³³³³³³³³³³³³¡xOEC@@@@@AP^ipweO@@@^…©©©’kBTinYE@@@@@SrŽxaPIB@@@@@@@@@@@@@@@@@@Qh“©³³³jQIB_„›uOK]nˆ¤³³³³³©†eSI@@@@@@@@GZmcP@@@Ng{vlXDFN\€¥³³²¢“~aD@@@@@IVe„£›pDAA@@@Z|“}gdoyyywqk\M@@@@@ALXm‹«°±³³³¦•ƒiNAAAGOYgvŠ ³³³³³³³³ª•€lWKZipsvvw{€†–§³³³³³­ƒZFCA@@CKRarƒ—«¢‡nqunYD@@@@@Y}™vR@@@Sh}”¬”kNx ¯©£ž™’‡~iR@@@@@@@@@@@LXj‰©³³°•{lifu„“¡¯³³³³³ž}Z|ž³³³³³³³³¢‰p^KT©°±¨ƒ^NG@@@@@@O_lt||yxxy|€‚yocSC@@@@@@@@@@Rv™}YNy¤±²­†`c‰±ˆ]AAA@@ADFaг³³³³³•sWMD\ƒ¥~U@@@@@Ie€“¤³³³³³³³³³³³³³³³³¨—†vqqqqqrtwyz{{{…›±³³¬—‚xpm€”¡ª²ŽjQIB@@@@@IUbehnx“¥³³³©›‹nO@@@@@DP[jz‰š«³³³škXDKXcksx{“§³³³³³¨…dr”³³³³³³ka…ª³³®˜‚lVAHOXblorsqndUGEB@@@@@@@@@@@@@HTadht¬³³³³³©š‹Ž‘“““š¢ª­±³³²©¡‹hDRekXE`Ь™‡rYA@@Li…tWDTd`P@@@@@@@@@@@QjvnaRBQbhVE@@Gm’š€gOCHMZjq\H@@ALXXMB@@@@@@@@@@DLS`m~•­²±®Ÿ‘”£³³³£ZMFJs𫝳³³²°¯¡‘…€{yyz~Ÿ²¨ŠjHObv¨³³²±¯¦‘}gRAAA@@@@@@@@M\n‡¡«®±±²³³³³³³³³©œŒmM@@‹ACFO`quxvj][\^goqkfmv~…™§³³³ªš‹t\LFAc¥{P]ˆ²¬¦›ŠzeP@@@@@Eqœ±²²³³³³³¢‹v`J@@@@@I\puxywt{‡“ ¬ zRIDMuª¬­Ž‡‡‡—¨³³³¢Œ{zx}…’•‘…zŠ¡³³³³³±›†€‹•——ŒkJ@@@@@FOYq‡›¥°©œ’ˆŠ–uS@@@@@Jq–‰cDp›±²²³³³³³³³¯•}gTA@@@@@@@CLVo‘³³³³³³³³©ˆht•±£•Œ‡ƒƒƒ{aG@@D\s‰²³³¯§žn^MUk€”¨³³³³³®¡“z\@@@@@@Vm‚˜­³³¬ŠhTJAYqu]Edޝ°²­¤šwS@@@@@@@@@@Frœ±²²§šŽtcPCNYdoz¦³³³³³³³³›zYOEK_thXLGCEJS{¡³³³³³³³³³³²®ªh@@@@@@@@@@@@@@@@@@@@@BGLjªS@@@@@@@@M]n•¢ª²Ÿ~sg€³³³³³³³³³³³¯«ª®²³³³³³³³³‘qYNC@@@@@IUbmx}{zŒ£¦}Te޳³³¤‰o]LGXjrx}}}€…Š„{{{¢³³³³³³³³³³³³³® ’y[@@@@@@_—£°³³®•}gT@@@GWg³³³ …mcYa{”ƒv^GKYgox‡œ²³³°ª¤–‡w`I@@AUix‚‚teVFL\jnrux{‚‰‘™¡š†€|…œ²³³³³³³³³³³³³³³³­£˜ «³³³ž‚hXHJ]pstnZE@@AAAOf~‘¦­¡•ˆ}o^MFCAP^p„𤭧€YJE@@@Tx›™•‡hH@@DUg~˜³³³¨wcO@@@@@BSez“¬™picr‰ž¦¯³³³³³³³³³³³³³³³±…ZAAA@@@@@@@@@@@@@@@DMWs•³³³³³³³³¯§ž€]CP]hr|‘§³³³³³³³³­¤™vR@@@GOYj{†–•“𦲋eZy—ž§¯³³³³³³³³³³³³³›{\QF@@@@@Kj‡™§³³³¨—†}yyyxwp\H@@@@@@@@GNWakaPADF\§¬°¤}Vl“¯ ‘‰†ƒ‘ ª®²‘kQaphSDp›±²²³³³³³¦•‚hM@@@@@@@@@@@@@@@@@@MhƒpT@@@@@BUhhUBVn™€n\I@@@@@Qy¡¬¯³³³³³°„YAAAh“¦zN@@Ek¥«°¦šˆ€‡“ž¦­—mBAAGWgr|}cJ@@ALXcmxŒ£³³³³³³³³³³³±¯©™Š”¥«Xa‰²£“bE@@@@@@@@@@GVdp|ˆ›­±°¯°²šoCAAPx «®°­ª¡–Š…€|zxePADGLS[iw‡œ±ŒdGDA_†©­±Ÿ}ZPFER_houuu„œ±‡^FDAd‹ cSIAAAL`tx{}{ziS@@@W}¢©¯¬›Š}pfilqx“§²°¯‰`FUet‚„|wutŠ£¤{Q\vЇ„Ž ³³³³³³³³²±¯š{]RF@@@EJQ\fe_[gtˆ’uU@@@@@AGLKFBQacSC@@@@@@@C^z„€|xtswzkTGrœ¤’€}|wrlf`WK@@@@@@@@Lw¡‘g@@@Tz €ZBGLk‘«€T[†²Ÿ‹v]E@@@@@@@AN[foxŒ¢³³³³³³³³³³³³³³³³•nMHC@@@@@@@@Pcxª®¨¢™ˆƒ~{ysbRJE@@@IYi„ ³³³˜vXNDAABVj€—¯³³¯¡“˜¦°ˆba‡¯³³¯¤™†qawŒœ§²³³³³³eAAA@@ANZoŽ®§™†iJ@@BP^hnsuv”«¨œ”¡­³³³¢‘„€{hRDR`]N@@@@@@`ƒž¢§ •ˆlOJ[lsxt]F@@@@@CHMdz®cAAA@@@@@Ryž\@@@@@@@@Twš|X@@@@@BLV[^bjsy||xsh]p’³³³³³³©ž“‰€}}€”©³³³³³¦ƒau–³³³¦‘}vnlryyyywtfS@@@@@@AAH\poe]]]cmwŒ£±²²³³³³³³³²¯«£˜Œˆ…ˆš­³³³³³ |VME@@@]‚œwQYƒ®˜lXD@@Hl¢ª³³³³³³¨›‡~sh\QF@@@@@LnŽŸª³³³³³³¦š…fF@@@@@Of}‘§³³³³³³³³¨˜ˆvb^hq{„‚kSJE@@@IWfƒ¡ uIf‘³³³³³³³³³³³³³³³³§˜Œ˜£«®²³³³³³³³³³³³³²£“bE@@@@@@@@@@@@@@@@@@@@@@@V|¢©¯³³³³³°¢”Œ‡ƒ†‰‘¡°³³³³³³³³³³³³³³³³³³šy\PE@@@@@GYjsyxaI@@BYq†›°³³³³³šx^€¢¢‚cVIGZmtwxrllquuuy‰—§³³³³³±›†qZC@@DOZkž¬§‘|fOMnŸª®™ƒnWAO]iqx‹¢³³³³³³³³³³³³³±ª¤™…—©±²²³³®¡•zZ@@@@@@@@@@@@@@@@@@@@@IXhs}‰›®³³³³³³³³³³³³³³³«ˆfo‘³³³³³³¦˜‡€}ytkb`eiƒ ³³³³³³³³²°¯ž€{uuvxz}}{xbL@@@@@AAAXx” ­³³³³³§…ew—³³³«Ÿ’sS@@@@@@@@@@@@@IZlpsskdx—³³³­¢—‰|}”­³³¬‰gTJ@@@@@@c‹ª­±³³³³³¬ ”eH@@@@@UyœzW@@@@@@@@@@@@@HZkquwww„—©­±³³³³³³³³©”Ÿª¯±²³³³³³³³³³³˜oGEB@@@@@@@@@@@@@HVeeeecbs‰ž§¯³³³³³³³³œiXG@@@@@Lc{¤¦}SFC@@@@@@c†—‰}hRCNYdnx†Œ’©²®ª›†r^K@@@@@DOZdlssr–®°²³³³¬£•rN@@AYp†›¯«£™Ž‚|xr^JPnŒ›©¦]NGE`|¡²³³³³³³³±¨ ¢ª³³³¨’|gQAAA@@BKUdy›©³³³ªŸ•‰ °±²³³³³³³³³¬¡•tR@@@@@@@@Pez¨œtJo˜® ’xY@@@@@@@@@@@@@EXkv}„–©³³³³³±ª¤‡b@@@X‚­°²³³³³³³³³²°®ƒY@@@cŠžvN@@@@@Rv™…kVMC@@DXm€”¨¬°²°¯ zbJ@@AHO\n€mS@@@IVcw‰‚cCi”¬Žƒzn[I@@@fŒ“nH`…¢ ž £§¬¯±²³³³³³³³°š…vlbZSLGB@@@@@Mcz{}}}}Ž£³³³³³³³³³³³³³³³³³³³³³³³³‹bGDA@@@@@HUblvr[D@@@@@@@Dpœ³³³³³³³³±°­¤›œ§²³³³³³³³±«¥›‚€|yyyyyt^HAAAIP[hvmaVMCQh“©³³³³³³³³³³±¨ •ˆ}}}}}}ƒ‰’ž«‘g@@@@@@O_s¬³³°¢”Š‚|¦³³³³³²®ª¡•Š€wpmj\L@@@GQ]z•šŠzeOEP[o„˜Ÿ¦¢–Ї„Н³³³³³œzYOESyŸœ”“–•””¡­²°¯…[@@@@@@@@Ndz¦§Œrg_a~™›„jN@@@@@@@@@@@@@@@@@@Nr•€]@@@@@@@@Qu—ž¡¤ª±³³³³³³³³³³­œ‹‹‘˜£®²±±Ÿ{fQIDCNYfs€ˆ’™¢§««¡–†udVG@@@@@@@@@@BNYeq}‘¦³³³³³±«¥˜‰|ƒŠ€bD@@FWif\SKD@@@MYdjpjaZ]`r¨š‹x_EN^qŒ©³³³³³¬žtUESby’§›‰†ƒ”§³³³³³³³³³³²˜€svyyyt^H@@Dp›±²²‘lQJB@@@@@IYi„¡¡vJAAIr™«¯±ŒhPIAEJR`o|‡’Š‚s[BKVi‰ª±°§}S@@@@@EP[l~ˆ}rbQAP^iqyƒŽš¤¯•lGDBHVe~˜šrJ@@@@@@@Aeˆ ©±³³³³³³³³³³¢aSH@@@@@Ec`Bj•±²²³³°¢”Šƒ}vncSC@@@@@@@@@@EOYk~ˆ{yy}’©³³³ŽjQIBaˆ©­±¥ŽycMAAA@@F[oyƒƒƒ€~xriZKEC@@@V}¢©¯ª”€si_RFGQZclu|‚“¥³³³²±¯‹€~zyy{€…“¤³³³³³³³³³³³³³±«¥›‘ˆ™ª³³³­§‹{gR@@@@@@@@@@@N_nsx}‡˜©³³³ŸˆscSJE@@@IZlsy|wstx~“©›sIEBPx ¢™†}lV@@@@@@Qez§¥—Ї„~zrko«³³±¤˜€aAEJQZdjqvwy‡³³³®£˜zY@@@@@@@@FQ]gqvpkfa_gpš²³³¨r_NF]s‡›¯°²¬žˆ€{{{ŠŸ³³³¨”€ƒˆŸ¯³³³³³³³³³³³³³gGDA@@ALXblv‹¢³³³³³³³³²°¯š„pZE@@@@@@@@@@@@@GNWcofS@@@@@@RfmYF@@CTfuŽœª³³³•qRKCSrއ€q[D@@DSaz—®‚WAAAfª®²•oMHCX€¨š‹y_E@@@@@@@@@@@@@CFKVbimt¦›pDk–³³³³³°¢”Š‚|xtjWD@@@@@@@@@@@@@Sg}”¬³³®‰e[iwz|„™®³³³³³¯©¢›“™¥¯°²³³³³³³³³¥•eH@@@@@Yƒ¯†\Q~©›~hr|‹Ÿ²žŠu\D@@@@@GQ[o’¢±³³® ’yZCUfqw}‘¦³³³ž…m[H@@AN[p®ŒaAAA@@BRbgb^hryyytlcUG@@@@@CKR^ju}„†„‚€~„Š‹‡‚€†Š™©³³³–rRKDX€©¬°³³³³³²²±§˜ŠteTB@@@@@Qh~“©¦{naVLCCEIRZagnqu~Œš¤¬³³³ž€dVH@@@@@@@@Wuž¬³³³³³³³³©œŒmM@@@@@OoŽ©³³³›yYOE@@@@@Lp“š€oXA@@@@@@@@@@BEHWffTC@@EUe}™³³³³³³’pVLCM\nЧ³³³²±±²²³³ªˆfp’³³³«œŒˆ……𣫳³³©˜‡wqqqqqqqq€—¯°²³³³³³¬”|rpoŠ¥rFTho[F@@@@@@@@Vl—®³³³³³§•‚iO@@@Ul‚—¬³³²²±›qEAA@@@@@D\sˆ²³³°ª¤–‡}„Œ—¥³³³³³³¨›ŠkJ@@BP_ly†–§³³³³³¯˜‚mWAUi–®³³³³³³³±Žlj‹®¢…š¢ª®™„oYB@@@@@Z|˜£®¥ŽwbM@@@@@DRay–²¤–‹ƒ|qf][Z\_clu…›±³³³³³³³³³³³³²£“ˆ‚|{{~†›§³³³ |WMFKm]@@@@@@h¢’‚uh]YUZdnˆ£ŸtHTjywttut_K@@@@@Ki‡yZGsž±²²™€jWDRh|…ކˆœ°³³³³³³³³³³¡€`SH@@@@@CScz–²²±¨’}yyzz{{ywpi_PB@@@@@_‰¯°²³³³³³³³³³³³³³ªœŽqR@@@@@@@@L]oŠ¥³³³‘mQJC@@Fl‘“w[PGAAAN]kqw}†ƒ€}yteTR|¥³³³³³¬ ”vV@@@@@BMYp²³³³³³ªŸ–•“‹†…ƒ„‡ŠsV@@@\„©­±³³³³³¬˜„mUBNY`einsvxy{|–«³³³³³¬žuV@@@@@@@@IYiƒ ³³³³³³³³³³³³³³³³³³³³³³³³³³³³³§›‰jJ@@@@@@@@@@@@@\€ž§¯³³³³³³³³«£—ƒp_OAKU^gqstqaRJEBO\n…œ¥­¤}Vm“³³³štMHC@@@@@DSan|‡Š‘—œ¤­³³³¢yjZRPNZfnqsuv}“ª³³³³³³³³³³°¨Ÿ ¤©­±ª›Œˆ…‰›®³³°¤˜ƒzdN@@@HR\iukU@@@GVdtƒ“¡®³³³³³³³³³³³³³˜vXND@@AgŒ¥ª°¢}cI@@@@@@@@@@CMWalvwyyyy{}šž¡¤ª°³³²žŠzm`dlrsux{~‚ˆ’ ¯¦šˆiI@@AAACEGEBBGLl’§}RAA@@@@@@_‚—ƒp_OBP_q…›¤­³³³˜wXNEHUalw…𝳳²²±§˜‹ŒŽŠ‡oT@@@@@BMXo°³³®¢•}`GEBDINPRSSS]iuŽ_@@@@@@`ƒŸ¨°³³°œˆrZB@@AAAAA@@@L`t”އƒyoeYMBO[emu‚’Ÿ¨°§˜Šƒ~yurokt­³³³³³¨—‡˜©¡{S[jqbRMMMHCEOY[\ZOC@@@@@Ng’¦³³³•q\€¥³³³³³³³³«£š†yraPFCA@@@@@@@Fhˆ¨²³³³³³³³¯ž‚{twz€Š••”“““›¨³³³³³³³³¯§ž’…”ª³³³³³¬sV@@@@@@@@IZl|‹š¥¯³³³³³³³³¯«¢‘€kS@@@@@@@@GWgou}Š˜¢«³³³³³³³³¬˜„nU@@@@@@HOYixƒŠ›¬³³³³³³³³±°©“~vutvxyyyyyyyy{|€•ª³³³³³³³³³³±¨ ¡©±±²³³³¨›‰jJ@@@@@K`t‹£³³³³³³³³¯©£Œwkos‡ ³³³«¡—¢­³³³³³¬˜„|xty}}|rh_WOJE@@@@@@@@@@@AAFWhry€”¨³³³³³³³³³³³³³›sILQ\sŠ™§³³³³³²£“‡wx{}}}{xvy|‡œ±³³³³³§˜‰‚}yxx{~„’ §®³³³¦’fNGUdjptvyyyyyyyyynbYYYt–³³³³³³³³¢yOECHjЍ²¤–‹ƒ|zywwwy{~~~|zqgeoy{{waJ@@AJT`q€’¤¨€VcŒ³³³³³³£’…€}{zyyyz|}xqhYKWj~“ª³³³³³²±±¡o_SIAHPW^etƒ‘™ §­³³³šoCAA@@@@@Geƒ—¥³³³³³³¯«¥˜‹xbMHDRqžª°ª¤˜Š{wtqnrw~‰”‘‹…}‡›¯°²¯¦žŒ{mjfiotwz}€‚”¦³³³³³³³³°¬©š‹Š¯³³²²±™vSLD@@@@@@@@JVcmw†œ±³³³³³±°®©¤£££¨­±±±§›‘‹……ˆ‹—££—ŒzgVMC@@@@@IYiv‚𦬝±¨ –Œ‚€}~†•¦³³³³³± z^C@@G[nuxyyyvpjZJAAA^ž§¯³³³³³¬œ„}wvtssty}„œ¤«±±±±±°­ª¤ž—„~{x‚‘ž§¯³³³³³³³³¢|uƒš¯°²¤‰ommw©°±° ‘†€ydNAAAAAAAADIMHC@@@@@@@@Odx‹Ÿ«®²³³³³³³³³³³³³³³³³³³£}cJAA@@@J]pˆ¡³³³³³³³³³³³›ƒuuuoh_RE@@@@@BDG^xž®³³³³³®¦€xyy|€…˜«³³³³³®¡•zY@@@DINYdkossrlYF@@BMXfv…–§³³³³³³³³³³³³³¯§ž—Žž­³³²©¡–‡ywwuj`VJ@@@@@@JSbz‘Ÿª³³³³³³³³­Ÿ‘‡~wwvuuvvw‚™°³³³³³³³°¡‘|_BSfu}…”¥³³³²°®”|fUC@@COZepz{}~ƒ‡‹‹‹‡~~}yvnfenx{|}|zyyz¦³³³¨›ŠkJ@@@@@@@@Qbq}ˆ–¦±¦›———¡¬³³³³³³³³³³²²±±²²³³³³³³³®‡`KFA@@ADG^{•¡­³³²£”‰„€~{z{}…‘¥¬±²²©ž’„weR@@@@@@P_lrxz{€”ª³³³³³³³³±°®¬©«¯³³³±­©šŠ~zwvwwvtjYHTakosfUGDBL_r‹¤³³³³³³³³³³²¬¦Ÿ—‚vhVEPdy¨³³³³³³³³³³³³³¢‰q^K@@@@@@@@@@@@@@@@JS^lzŒ¡³³³³³³³³¢|UID@@@@@@@@@@@Rfwƒ›¨³³³³³³³³³³³³³²±¯¯±³³³³³³«£–}bSI@@@@@@LYi€–£«­ˆdOHAg©©©¢™‘‡nW@@@@@@@@@@@JXfpz„›¤­³³³³³²«¥˜†t`MER_fmm[H@@@@@@@@GNWes„—©­±³³³³³³³³³³³³³³³³³³­Ÿ‘}eTX\r¯°²³³³„o^MFDDVi—±³³³³³³³²²±±²³³³©“}hRLw¡±²²¤–Š€w~‡“¡¯³³²®ªŸŽ~n^QIB@@DWjtx{xtpmjmrvx{‰Ÿ¯ˆba‡¯³³³³³³³­…_KFA@@@@@LZi{Œ™¤¯°²®£˜‘‹…‚ysnu|„œ’†}voaO@@@QnŠš©³³³³³²®ªŸ‘‚€}{zzyyyyytlfkou|‚”¦­žŽ„}w‚Žš¦²³³³³³¢Ž|kZOGAAALaw€†Š†ƒƒƒƒ‰™¥²¥—Œ„}zyvoh]O@@@@@@EJQap‚–©­±³³³³³³³³³³³³³³³³¢‘„€{yyyyyyyz{}}}}xriXF@@ACFFDBAA@@@@@D\sˆ²³³³³³³³³³³¥ŽycMGUd|•©«®¦šŽˆ‚}|€ƒŠ• ¦«¯°²³³³¢‘}aF@@@@@GPZfs‰• «³³³³³³³³³³³³³® ’‰‚}}}ˆ›¯°²­Ÿ‘‡r]H@@BUhsvy}€‚€~zvrsuz‚Š“Ÿ”‰ƒ€}}}~~|{zzxussrtwz{}€‚‰‘𥰳³­ƒZFCAWmƒ˜®³³³³³³³³³³³³³³³³³³³³°q[NB@@@@@@@@@@J\m‡¢³³³³³³³³°¬§ƒaKFA@@@@@M^nsy~‚†–§³³³³³°ŸŽƒz¥³³³³³³³³³³²¬¦‘lFAA@@@Narux|‚Š’”ŽˆrW@@@Mav€Œ”˜œ˜“ŠwdVKBWm}‰•Ÿ¨­¨¤˜‰~~‰ž²³³³³³³³²®ª¤—›  œ—‘‹†ƒ€|xsleq°³³¬—‚nYIOVTJA@@@@@KWfy‹Œ‚yvsv€‰˜§³³³³³³³³³³³ŸŠv^FL\jqw…œ²³³±­©™‡xrl_P@@@EOXhxˆš­ª’‰yrj[KETbjou€Š—¥²³³²°¯¦›‘‹…€€…‹•£±³³® ’z[AAAFPYblsw{zywwvwz~„‹Š‡…„‡š¬³³²©¡—‹€~}{zziS@@@Nf’¦«–ujf}”¢ª³³³³³³³³³³³®¨¡ŒxeSB@@H^t‰ ±© ™’‹‘˜ ¢§®³³³¨—…kPAAA@@@@@@@@@@GTa{–ª®²±°«˜…}{zyyyyy{|ƒ‰‰…ƒƒƒƒƒƒ€~}{{{†œ±³³³³³³³³³³ªœŽ|iYNBJU`jtyz|ƒŠ‹„~{xsi`\[]uŒœ§²³³²°¯°±³³³³³³³³³³³¥–ƒgJ@@@@@@@@Rez’¬³³³³³²°¯…[@@@@@@@@GP[}Ÿ³³³³³³³³ªž‘€n^PB@@LmŽŸ©³³³²±±±²³³³¬£—€jaabceiqy‹¡¯ª¤•Ž‹Œ’§¯¯¯°±³³³³³³¢‘|aE@@@@@@@@@@u@@@@@@@@DIPar…›±³³³³³³³²®ª‹zz{†‘”•‰…„‚€t[C@@@@@AADXl‚š²³³³³³³³³³³¬¡–€jcp~¤³³³³³³³³¨“ti]QEAA@@@@@@@@@@@[}™¤®³³³³³³³³¤“‚ufgpz¦¯¬©ž’‰ƒ|{yyyyyymaXSNYhu}„‘¢³³³³³³³³³³³°¬¨¡š™ž¢ž™™ §«¯³³³­¥œ„}zxrkglrw{}|„𥝳³²¬¥ŽhB@@@@@@@CNYk—› ¡Ÿ ¥¦šŽ‘𣍮­¥‘…}}}Œ¡³³³³³³¨”Žˆƒ€|tljlnsx{{{{zyyyyyyvshUB@@H_v†•¡–‹„€|xtpmjou{€…Š‘—¢­³³³³³°¨Ÿ•‹…—ª³³³³³³³³³³³³³³³³¯« ŠubOADGO[filoqsuvxyyyyyxvm^NIDGXjœ³³³³³²ª¡™ˆƒ||}}}}pdXMB@@@@@Ody¨³³³³³³³³³³³³³­¥¤¬±²²³³¯£—„}umhebm{ˆš¬§š–¤²³³©xdP@@@@@@@@AAA`ƒŸ§°³³±¥™vmdbnzŒ¡±«¥š€~||~†–•“‘‹ŒŽŽŒ‹‘˜š”ƒzrux„›±³³³³³®¨œvP@@AMZhxˆ‚yof]cr€’¥¦“tg`js…œ±±±¨—‡‚~|~~}ynbcktŒ¤³³³³³³³³³³²¬¦ž•‹xkYF@@DZp…›²²±¬ •œ©³³³©™Šs[Tcqˆ ³³³³³³³³³³³¦˜Œ„}tj_SF@@@@@@@@@@@@@ELT`msssqoorv†±±²³³³³³³³³³³²²±§—‡}yyy~‚ˆŒ‘™¤¯°²³³³³³®žzcMHC@@@EJScrjZMHCAABQatŒ¤¬°³³³³³³³³³³³³³¯¢–…~|yvgWMMMVajnrnf]RG@@@@@@@@M`tŒ¦³³³³³³³³³³°‹„‡Š‘˜—Š~xuqlgd`^jw†›°²±¯ª¤£££¨¬¬§£—‹~ztleeejry„›¦°±°«…~uuuvxyz{|}¡³³³§“gPGZm€“¢ ˜‘‹™¨±²²¯«¢†kYL@@@@@@Rfx…“‘‰‚€‡š®°²³³³³³°¤—„|¦³³³³³³³³³³²§œ“‡„|zuoib\VOHVdpv|‚‰Ž‹ˆƒypg^VOQV\eotwz{}~}{ui]RI@@@LauŒ¤³³³¯¬¤’€}‡—¨±±±±²³³³³³³³³®¦‘…{skmrz‘¨³³³³³³³³¬£›’Š„€{zxxyyz{{yxxyyyyyyyƒš¥°³³³³³³³²¯«¡Ž}ocYYYbn{‘§³³³³³±­ª›‰xqi`WNID@@@KWbceiovxzr[D@@AAAM^nprtvw‚Žš¥°³³²«¥¥ª®°²³³³³³³³³³³³³³³³³¥–ƒgJ@@@@@AAAThw{zsmjgp’Ÿ«°ª¤¦«®¬©£›“”–•’ˆ€zuoaP@@@@@@EJUl“¤³³³³³³³³³³³³³³³³¨™‰mPAAA@@ESajqxy{{yxqjgmrux{ˆ“¢°­ª¥œ”Š…}{zz{}}}}rf\XUd|ž¬³³³³³­Ÿ‘‡}uromkjmpu|’¥³³³®¨¡“……Š‘˜š“Œ…z{}‡›®°²³³³³³²²±¨›Ž†€{zz{|}}}|zwwvvxyyywoghknsxˆ’Ÿ«³³³³³³³³³³³³³³³³©ž–’‹‡‚{xurle_WOORSSSW\bpž®¦˜†€ysmgafx‰˜¨³³³³³³³³³³³³³³³³®§ ‘‚yqie`ajrw|‚ž§­²§œ‘†|xtkXF@@@@@BEG]r†š®±°¬ “‰‡“›¦±³³³³³³³³³³³³³¦˜Œƒ|yyz{}}}}|zyvtsrrux„—©­°³³³³³³³³³³³³³³³³¯«£’uj_SGAA@@@FS_q„“—›—ކ‚€}{zwurlg_VMHC@@@JSZ\]UJBIQ\kz¦³³³³³³³³³³²©¡˜‡‡‡†„ƒƒƒƒ„†„zwuux{Šž¯°²³³²¯«£˜Œˆ…ƒ†Š–¦®³³³³³³³³³³³³³ªš‹„~vogc``irwy{{{|}}~‹ž¯°²®¦’†~}}}~}{q[E@@@@@@@AFKUev‹¢³³³³³³³³³³³³³³³³³³³³³³³³³³­¡•‹ƒ|xsqqrrsnaUMF@@@@@@@@@@@CFN_p|†‘ª¬§¢™‹ŽŽ‹Œ‹…€}{xqkiikuŸ²³³³³³³³³³³³³³³³®£˜†teeejqyŒŸª®²³³³³³²±®Ÿ‘‡‚~|zz|}‚‰Ž‹Œ“”–›¦±³³®ŸwZ@@@@@@@@G[ovy||}}}}}}~€‚‰‘—————— ª©Ÿ”ŽŠŒ®³³³³³­¢—¤§¢ž“‡}|zyxwtporuwxxphc``€ž¯±²«¢—„spt{‘¨³³³³³°ª¤…`AAADINZgoswyz{{z{|~~ƒŒ– «³³³³³³³³³³³¬¦œŠyeQETdlquaLAAA@@EUes€Œœ«³³³¨ž•’™§³³³¬¡—ŠungZLBDGJOT`ksvy~ƒ‹›¬¨’Œ‹‹‹ŒŽ“¡¯³³³³³³³²¨’‡}wrmjgkrz…•’ˆ€{yxxyz~ƒ…†„€„†ƒ€€…‹Š‡„~}}}}}‰’žª³³³³³³³³³³³³³­Ÿ‘ˆ€yyyz{|€~xriWF@@ACFQexŠœ©¬®¤–‰‚|xur_L@@@Sj€•«³³²¦™”˜œ–Їƒƒƒ‚{vpjqx€ˆ‹yyx|ƒŠš©³³³³³°¨Ÿ˜‘Š…€}{ztnha[\_cr€Ÿ°¤—Œ†€xncUFIWfpz€ƒ†‡‡†ƒ€„ˆ™ª³³³³³¯¤™——˜£®³³³³³®¤™…}}}€ƒŠ’›¦±³³°¨Ÿ–Œ‚~xrjbiry|~}{{zumf\SLGA@@DVgry€ƒˆ˜¡¨®³³³³³²±¯¯±²³³³³³¥’€q`TJA@@EP[htƒ‰’ž©­°³³³³³³³³¥“qaWRNU]eoy‹¡³³³³³³³³¬sV@@@JXg›ª®²±°«ž’ˆ€ueUKFA@@ADGSbnsx}‡˜©³³³±°«ˆ…‚€}{zyyyxxyz{{{|}}‹™¥«±³³³³³³³²§•’‹†ƒ†Š•¥³³³²±±¦šˆ€}zwqlheb\WQIB@@ADGFC@@@Nm‹›©³³³³³³³³³³³³³³³³³³³³³®¥”Œ„€zwtplgaZSQOPTY\_bfigd`SF@@@MYgx‡–¦³³³³³²¬¦¥«±³³³³³³³³³³²°¯¢”Іƒzm`SF@@@@@@@@KWclty|~|ytnkhgmswy|„‡Š—£¯³³³³³³³³³³³³³³³³³³«ž’~iXMBPaorvpdYOEBEGZn‚—­³³³³³³³³±¯«¡˜šŸ¤©¯¬¤œŽ€wpjloqnjiiiiilrw‚Žš¥°³³³³³³³³³³³³³ªŸ“‚sbQ@@@@@@@@FWiptxz|€‡Žœª³³³³³³³³³³³³³³³³«£šŽ‚zqi^SKFA@@GYl{‡‘Š‚zpfeeglqsvy€ˆ‰…‚€}}}‡Š‡ƒ€}z{}€‡ŽŽŒ‹ˆ…‚{z{{¥³³³³³°£—š§³³³°©£§«ª›‹ƒ€~’¨³³³³³°§Ÿ’„v`J@@@@@GWgpx…Œ”–Šƒ|toihpw€Š““““•–‘Š…‚€‰—£©®ªž’Œ†{fQIDADGSdtwz|~‹™¤«±³³²®ª©©©¤Ÿš“Œ†}|zywuuuwy{‰’˜¦®³³³«¢š“Œ’Œ‰†ƒ€|zwtqqqrstuwy{}„Œ–¢¯³³²±¯§™Œ…€{{{~€ƒ†‰Œ’”–———‘‹…}ungbehkosvy}€…’£³³³³³³¨ž”Œ„€}ywtsstuwy|„ŠŽ‹Œ—ž¥ª°ª¢ ¤©©©ª¬®¦œ“‰€wphb\TJAFKQ[djotuwxyz~„‡Šˆ…ƒ‡Š—•ˆ|vqoswy|~~†‹Ž‘Šƒ€€‚†ŠŽ”ž©¯±²³³¬š‡|rjkmoru{€Šœ¯³³³³³³³³³³®£˜”‘‘˜ §­³³³³³³³³­œ‹„€„‰‹Ž‹ˆƒ~xrld\YYZcmokf_XWcntwz~ƒ…†ƒ€{uobSGGGP_n~›¦±¯«¦šŽ––‰‚}{{{{zyyyŠª®²³³²®ª£›’މ†„ƒƒƒƒ†‰–¡¥ª®±®¨ ‘zwtsrqqqstvwyz|~€~zyy}‡“¦¯¯¯§™Œ„~wqke_Z]`fnu{€Šœ¯³³±«¥œ‘†…ƒ„‡Š“”–—————™ž¢¨®³³³³³³³³ªœŽˆ‚zm`TIDTdmqvz}€ƒ†€ysrrsuwww{€†“ ¥”Žˆ‚{ywvy}‚Œ•”‘…~{{|€„†„ƒƒƒ‚€~ysmf`bjqtx—®³³³³³³³³³³³³³³³³³³³³³³³®¦–‰†ƒ„…‡ŒŽ†€vl`RC@@@@@L_r…˜¥©®¥š“““•™–Š~xrnqsrokYH@@@O]hov}‚Š—¤«¯³³³³³³³³³³³³³°ŸŽ„€|…𥰳³°¤˜‹‡‡‡†„ƒ}{xm]MIDJ]pyˆ‘Žˆ‚€}||…———Žƒ{xupkfilpty}€‚{yxxŠ•£±£’ƒzpmmnsw€Žœ¥­³³³³³³³³³³³³³³³³­§ ™‘Š„xqeSBCFGGGECBLUamy†” ¨±³³±«¥™Š}}|}€‚€}{xwvutrqqqrsux{‹¡³³³°¬©¤Ÿž£¨©©§£ž˜‘Š„{zztnjlmry€‚…„€|{{|~~ƒˆ™¢ž™š¤­°±³³³³³±¤–‹…€~}||ƒˆ“ž¦¬²³³°ª¤˜Š|ywusle`]Z[\^aeaZTY_foy{|}{zyyyyxxyy‚Œ—¤°®§ —ŽŒ“—š™ˆ‚||}‡•£©°³³³³³³³³³³±«¥£££©¯³³³­§ •Š‚{snhecb]WUX\bhnty~‚†„€~{xpf\SKNZfnw„™¯³³³³³±°®¥›———•”‘Š„€€‰’œ§²­¦Ÿ”‰ƒ{{zyyz{}€„Š‘‹…€~{zxwvvvwxyy{|~ƒˆ‘¨¬°³³³³³³³³¯¨¢™‰†ƒ€~{{{{{{{zyyyyyyyyyyzz{|}}zwmYD@@CNYdoz~€„‡Š“œ¤ª±³³³³³³³³³³³³³³³³³³ªœˆ‚|zri`XPT]fkqsssqonqsuvwwwwwwz~†š®³³³³³³³²¤—ˆƒ‰‘˜Ÿ¦£š’މЖ›Ÿ¡œ˜”‘Ž‹ˆ…‚€~~{xrcSKFBKT^gpuz‚•¨°±³³³³³³¤•‡~toljpu}…Žœª³³³³³°¢”‹„~|{{{zywwvuuvvwxyyyyyyywtrrsw}‚‘ ©¬®§ž•‰…}{yyy}€ˆ™«±²³³³³³³¯«£•†}|z}‡‹†|{yyyyxxxyyyyyyz{{~€ƒƒƒƒƒƒ€}zxwvuuuuuvwyz|}„Œ–¢®³³²§œ“‡…„‚€€„†ƒ€†Š‘–ž§¬¯³³³°¬¨‘‡€ywvvwy}‚ˆ˜©±²²«¢š‘‰€vk\NFDBFKSaox€Š›¬³³³³³³³³«£š†…ˆ‹’™–‹€{wtvwxyzz{{{{{{{{{xtn]MGGIZkv}‚“¥³³³®¨¡˜Ž•œŸ¡¥«±³³³³³²°®œ‰~zvwxz{}~~|zyxxyyyyzz{|~~~~€„‰‹‹Š†}|ƒˆŽ”‘Š‚€}}}€…‹‘•™œ˜”‹‡}wqkloruxz|}}}}}}‡Œ“𢫳³³³³³³³­œ‹€yruxz|}}|{{{{zyyyz|~€‹®±²³³³²±®š†ueTQOQZcc`]\Z`kvy}}|{{€•«³³³³³­¢˜‘‹†‚€ƒ‰•šš—“Œ‹Ž™§³³³³³²²±ª›…€{zxwvutriYIEBAAAHR[dmsvy„›¥°³³³³³²°®¢•Œ†€~~~„ˆ™ª³³³³³® ’‰{zxxyy{}}}}}}~~€„‡‡‡†„ƒ…ˆ‹‹‹‹‹‹‹‹‰†ƒ€~€†Œ–¢®¬ª¤˜ˆ…‚€}|yvspnkheeeecbiqy‚Œ˜¤¯°²³³²±¯§–…zneb_aejnrvzƒ‡Š†ƒˆ˜£®³³³¨˜¢§®³³³³³³³³n­¡”Š€ywtssssrpmjiijlmpsvwyz|}~€ƒ†Š’ŒŒ“Ÿ¬³³³³³²±¯¦šŽ‹‹‹‹…€|wsnifkprtuvwwwwwwxy{{{{{{{zzyy{€…©­±³³³²±¬Ÿ’‹†ƒƒƒˆ’Ÿ¡¢Ÿ™•’Œ’Œ‰†ƒ€}zxyz|}}|{{{zzyyyyyyxwwwwwwyz|}~}{{zz{{{{{zzyyz~‡–¡¬²±±ª£›–‘‰†ƒ€~~}}}|zxwvy|€‡Ž–¤©­¨ž–•“™£®°²³³³³³±¨ ˜‘Ї„€~yuncWVZ^dkpuy}€†š£«²®ª ‘ƒzocSCAADQ]fnvy|€„Š”˜›ž ¡˜‰†ƒƒƒƒƒƒ¢±±²³³²±¯¯¯¯°±²²±«¤œ“‹„€|zywvvwxz{}€‚…‰‰†ƒ}}|{ywwwxyyyxwwwxyzz{|~ƒ‡‹ŽŽ‹ˆ…‚€~|{zzyyyyyyyz~€…‹’”•™¤¯³³±§œ“‡‹–¡¬°±³³³³³³¦š‡‚‰˜ šŒ{xuuuuuvy}~~|{zzz{|~„†…ƒƒƒ‚~yqf[YYZ[]bhnrw~‡‘𣩬®°±³³³²°¯£–ˆ„~~€„‰”£±±²³³³§›‡€|{yxvvwwy{|}}}}}|zyyyyyz{{‚Œ•¦¡•Ї„€~}||}}†‹Ž‘•™œ¡¦§¢˜“’•™ž¢ž™–”“‡‚€~}|{{{{{{{{{zzyyz{}}||skgjmqvyyyyxxy{~†’Ÿª®±¨˜Šƒ}z|}~ƒ‰“—ž¤©¬®­ª©«®°±²±¯©œŒ‰†‚€~|yxvusrrstwy{|~~~}}}}}}||zywvttvw{~‡“˜š–’Œ‰†ƒ€€‚†Ž™¢ ž™’‹ˆ…‚€€„‡Ž”’Šƒ€|yyy{|…ŒŽ†€{yxwwwwwy{~„‹‘—œŸ¡£££¡žœ˜”•™¡¦¤˜‡‚~|{{{yvsrrv}„Ž˜˜‡„€€ƒ†…„‚€~}{yyyyyyyyz{}}}~~ƒŒ–Ÿ¨¯±²¨šŽ‡}|{zz|}}}}|zyxxxyyyy{|}}}}||}‚ˆŽ›©³³³³³±¦›š¡¨¬¯±²²³³¯¢”Š‚{zxwvvtsqqqoljosx~‚…ˆŒ’™¡©«®§›ˆ‚~~|{yyyz|~€…Œ’ª³³³±°­¢˜‰ƒ€}{zxwurooqtwz}€‚ƒƒƒ†‰ŒŽˆ‚}|zyxyy{|~„‹•¢®°²²°¯¤–‰„€}{ywuux{ƒ†ƒ€€‚…†„ƒ…ˆ‹‹‹‡‚~|{{{}ƒš£ª¯ª¥“І}|{{|}‚†‹•ž¥ª®£—Œ†€~~~~|{xrljlnqtvxyz{{{{{{|€„›¨¬°³³³³³²±¯§›ˆ}zxvusssuvxxyz|}ƒŠ“–———ž¥©©© ˜ˆ€}{{zyyyyyyyyyyz€‡‹ŽŒ‰†‚€€‚…ˆ‹ŽŠ…‚€~~€„‰’©¬°±­©¡™‘‹„€~}{{{{{{{{|}}~‚‡Œ“šŸ¤©©©£˜Œˆ…ƒ†Š‹‹Š‡„€~|{yyyxwvvwy{}~~~|{yxvuuvvwxz{}~€†”œ£££ ›—Ž„}|€ˆ•šž £§¬®«©©©©«®«§¢ž™™¢ ž™…€}xof[NAN\hovyz||}}}}}}~„ˆŒ‘”•–“ŽŒ‹ˆ…ƒƒƒƒƒƒƒƒ€~|zyyyyyz{}ˆ’•”އ„€„‰–¢¦ª¬®¯¯«¢™†~|{{{{{{{{{{{{{{zyyyz|}}}}}}}|{{zxvtsstuuwz|€…Š–¤ª®²³³³³³³³³³³°©£œ”ŽŠ‡„€„ˆŒ’‹ƒ|zxwvvwxz||}~„ˆŒ‘•™™’‹†€|wsmgbiosuwxyz{{{{|}„—› ž•Œ‡‚|ywwxz|€‡Ž‘”–”“‹‹‹‹‹‹‡„‚€€€‚…˜£©¯²±±¬¦ •Šƒ€{zxwwwxyyyyyyz~‡–› £££š…}{ywwwz€†‹’‹‹‹‹‹‹‹‹‹ˆ„ƒƒƒ„…†…ƒƒƒ‚€}}}~‚†‹ŒŽ‹„~|{z{{{{{zxwwwxyz{{{{||}€ƒ†‰‹‹‹ˆ…‚€€‚…ˆ‹Ž‘”™£¬°±³³³²°¯¤™‘Œ‡„~}|{{{{{{{{{{{{{|}€ƒ†‰ŒŽŒ‹‡‚~|{zzyyz|}†‹‹‹‰…‚€~~}}}}}}}~„‹–¤²³³²±±§™‡~~}}}}}}}}|zxvttuwy{€ƒˆ‘““’‰„€|{z{‚…ˆŠ‡„‚€~|{zz{|}}}|{yyy{‚…ˆ‹’™¡©«­¬§£ž™—————–“Ї‡‡…‚€~}{{zyyyyyyyy{|~€‚ƒƒ‚€}{zwutuuvwxxyz|~€…‹’Їƒ‡“—›Ÿ¤¨©©§¢žš–“”–™ž¢££¢Ÿ˜“‰„€}|zyxxxyzz{{{||}}||{{~…Œ‰†}{ywwvvxy{|~€‚‡“œ¤ª®²¯«¥™Ž‡ƒ~|{{{|}}{zyxxxyz{||}~„‡’¥«°¬¦ ˜‘‹†‚€}{{{{{}€‚‡Ž“““‘‹‹‹‰†ƒ}}}ˆ’•–”“ŽŠ…‚€~}{{zz|}ƒŠ“–——•‰…~|{{{{{{{zxwvvwxyyz{{{{{zyyyz|}ƒŠ‘–œ£¬³³³°¬¨œ‘ˆ„€„‡‡‡‰Œ”™Ÿ§¯¬§¡˜Žˆƒ~|{zzyyz{}€ƒƒƒ‚€€}|zywwvuuuwyyyyyyyyyyyz{}€‚ˆŽ‘ˆ…„„’¡ª¬®¦———œ£¨£Ÿ˜‡ƒ€~~~˜¢ª³³³°ª£›‘‰„}||}}{yyy|€ƒ„†…‚€~|{zzyxwwwwwwwwxyyz{~„Œ’˜œ“‹…‚€ƒ‡‹ŽŒ‹‹‹‹‹Š‡„‚€~}}}}}|{yxvwz}‡Š†ƒƒƒ„Ž˜¡¨°±²³³³±°¬¢—‹†ƒ€~~}}}}}}|||}€‚ˆŽ‘Œˆ„~|{zyyxwvvuuvwy{|~~€†Œ‹ˆ†„ƒ„…‡‡‡ˆŒŽ‹‰†ƒ€}|zyyyyyz|}~‡“˜ž¦¯³³³ª¢™‘ˆ‡‡†…ƒ‚€~|{zzyyyyyz{|}~~}}}}}~~}}~…Ž”˜œ›–Š„~|{{{|}~€‚…‡‡‡‡‡†„ƒ€~|{yxy{|~€‚…‹‘———“‡„}|{{|ƒƒƒ€~~}||‡–Š…‚€~~~ƒ‰’•“‡‡‡ˆ‘•™¢§¦¡–ˆ‚}zyxy{|~~~~}|{{zyyyyyyyyyyyyyyyy{|~ƒ‰•š˜‡„€†Š‡„…‹’©³³³²±°¨ ™’‹ˆ…‚€~~}|{zyyyyyyxvvwxz|€„ŠŒ•› ¤¨£Ÿ˜‡‚{yxwwxxyz{{{{|~„†ƒ€}{{{|~„Š•›š–“”–™ž¢›”ˆ„}}}~~}|||}}}}}}~~‚†‹ŒŽŽŒ‹†|z{|…ŒŒ‡‚€~|{zzyyyyy{|}}}}}}~€ƒ†‰Œ’•“†ƒ€€ƒ†Š“—›™•‘Œ‡…„ƒƒƒ€}|zywvuuvy}€†‹’™ž ¢ ž›—“І…ƒ‚€€~}}}}}}}}}}~~~}}}}|{{{{{{{{{{{{{|}€‚…‰–¤¦•‹‡‡‡†„ƒ€}{zyyz{}‚Š“›¤§¢˜“Ž‹ˆ„€ƒ†‰Œ†€~}{{zyyy{}~~}}}}}}}}}|zyyyyyz|}‡‹Ž‘”———“‡ƒ€}||}~~€„‡‡‡ˆ‹ŽŽ‹‹‹Š‡„ƒƒƒƒƒ‚€€~}{{zyyy{}€„Šˆ…ƒ„†‡‡†ƒ€~|zyyz{}€ƒƒƒƒƒƒƒƒƒ…†‡‡†…ƒƒƒƒ‰–Ÿ§£œ•‰„~|{{{{{{{{{{{{zyyyyyyyyyyz{}€ƒ‰“•–•”‘ˆ…„ƒƒƒ€~}}}||{{{{{{{{|}~ƒŠŽ‹ˆ…‚€€‚†…„‚€€ƒ†…„‚€~|{yyyz{{…‹‘Ї„ƒƒƒƒƒƒƒƒƒƒ‚€~}}}}}}~~}}}ƒŠ’™¡¡ž›–Š„~|{{{|}}}}~€„ˆ‹‹‹ˆ„‚€~|{zz{|}~€„‡Šˆ…‚€~|{yyyz|}‡‹‹‹Œ•𖉄€~{yyyz|}}|{{{}~ƒ‰‹…€~}{{{{{{{{|}}~€ƒ†‡‡‡Š’•————————•”“““‰ƒ€~{yxwvvwyz|}}}~€‚…ˆ‹‹‹ˆƒ~~ƒ‡‹Ž’•™Ÿ¡ ›—‘Š…‚€~}|zyyzz{{{{{zyyy{|~€ƒƒƒ€~}{{zyyyyyyyyyyyyyz{|}€ƒ†Œ’—————–•“‘Ž‹‹‹‹ŽŒ‰†ƒ€€ƒ†‡‡†…ƒƒƒƒƒƒƒƒƒ„…‡‡‡…„ƒƒƒƒ…†‡‡†„ƒ„…†…ƒ‚€€~||}}}}}}|{{|}~}{{zz{{{{|}}~„‡ŠŒ‡ƒ€}||{{|}‚†Š‡„€~}}~„‡Š‹‰†ƒ~~‚‡‹‹‹ˆ…‚€}}}}}~~~}}}}|{zyyyyyy{|~€‚…‰Ž’”–———•”’ˆ†„‚€}}}~€ƒ†‹“•–”‘Ž‹ˆ†„ƒƒƒ‚€€~}}}}}}}}~~~~}}}}}~~}}}~„†…ƒƒƒƒ„†‡‡‡‹“““Ї„ƒƒƒ€}{zyyz{}}}}}}}}}}}}}}~ƒ‡‹’Žˆ‚€}}}~€…ŠŒŽ‹‰†ƒ€~|{yyyz{{{{{{{|}~~†ŠŒŽˆƒ€}|{{{{{|}~€‚„‡ŠŒŽŽŒ‹ˆ…‚€~}}~€„‡Šˆ…‚€€€‚…†„ƒ€~~}}}}}}}}}}}}}}}~~„†…ƒƒƒƒƒƒƒƒƒ…ˆ‹ŒŽŽŒ‹ˆ„‚€~}}}}}~}|{zz{}€†‹Ž‘”˜œ˜’Ї‡‡‡‡‡†„ƒƒƒ‚€~}}~€‚ƒ…‡‡‡†„ƒ€~|{zzyyyyy{|}}}}}}}}}}}}}}}}}}}}}~„‡‡‡‡‡‡Š“–——–”“І…ƒ‚€~}}}}}}||{zyyyz{||}~‚‡‹‹‹‰†‚€~}}||~€ƒ†‡‡‡ŠŽŒ‹ˆ…ƒƒƒ‚€€ƒ†‡‡‡‡‡…„ƒƒƒ‚€€~}{zyyyyyyyyz{{{{}~„‡‡‡†„ƒƒƒƒƒƒƒƒƒ„†‡‡‡…ƒƒƒƒ}}|{{|}€ƒ†‡‡†„ƒƒƒƒƒƒƒƒƒ€}||{zzz{|}}}|{{{}~€‚…‡‡‡Š‘—œ›•Œ‰†…ƒƒƒƒƒƒƒƒƒƒƒ‚€~}}}}}}}}}}~~‚†‹ŒŽŠ‡…„‚€€~~}}}}}}|{{{{{|}€ƒ†…„ƒƒƒƒƒƒ„††„ƒ„…†„ƒ€~}|{{{|}}}}}}}€ƒ„††„ƒƒƒ‚€€„†…ƒƒƒƒƒƒƒ…†…„‚€€€ƒ†‡‡‡‡‡‡‡†…ƒ‚€~}}}}}}}}€ƒ„†…‚€~}}}}}}}}}|{{{{{||}~„‡‡‡…„‚€‚…‡‡‡‡‡‡‡‡‡‡‡ŠŽŒ‹†‚~}}}}}~~}}}}}}}}~„†…ƒƒƒ‚€€ƒ†…„ƒƒƒ‚€€€ƒ†…„ƒƒƒƒƒƒƒƒ‚€€~}}|{{{{{|}}~„†…ƒ‚€€€‚…†„ƒƒƒ‚€€‚…‡‡‡‡‡}†„ƒ€~}}}}}}}}}}}}}}}}}}}~€ƒ†‡‡†…ƒƒ…†ŠŽŒ‹ˆ…‚€~~|{yyyz{{{{{{{|}}}}}}~~€ƒ†…„ƒƒƒƒƒƒƒƒƒƒƒ€€ƒ†‰“–•”’Œ‰†‚€~~}|{{{{{{{{|}}~~}}~~€ƒ†…„ƒƒƒƒƒ‚€~}}}}}}}}~…†„ƒƒƒƒƒƒƒ…†…ƒƒƒƒƒƒƒƒƒ€„†‚€~}}}}}}}|{{{{{{{{{{||}~„‡ŠŽ‹‹‹‹‹‹Š†ƒƒƒƒƒƒƒ…†‡‡†„ƒ€€„†…ƒƒƒƒ}}||}}}}}}}}}}}}}}~~~~}|{{{{{{}€ƒ†‡‡‡ŠŽ‹‰†ƒƒƒƒƒƒƒƒ‚€~}{{{}~€ƒ†‡‡†…ƒ‚€€~}}}}}~~€ƒ‡‡‡‡‡‡„~}}}}}}}}~€ƒ†‡‡‡‡‡†„ƒƒƒƒƒƒ€~}}}}}}}}~†ŠŒŽŒ‹ˆ…‚€~}}}}}}}}}}~~€„†…ƒ‚€€€ƒ†…ƒƒƒƒƒƒƒƒƒƒƒ‚€~~}}~~~}}}}}}}}}}}}}}}~~ƒˆ‹ŽŒŠ‡„ƒƒƒƒƒ€~}}ƒ‰ŒŽ‹‰†ƒƒƒƒƒƒ„…†…ƒ‚€€~}||{{||}€ƒ„†‡‡‡…„ƒƒƒ€~}}}}}}}}~~~}}}}}~„†…ƒƒƒƒƒƒ‚€€~}}}}}}}}}}}~€‚…‡‡‡‡‡†„ƒ€‚…†„ƒƒƒ‚€~}}}}}~„‡ŠŽŒŠ‡„€~}}}}}}}~~€ƒ†‡‡‡‡‡‡‡†…ƒƒƒ‚€}}}}}}}}}}}}}}}}}}}}}~~~}|{{{|}~~„‡‡‡‡‡‡…ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚€€~}{{{|}}}}}}}}}~€‚…†„ƒƒƒƒƒƒƒƒƒ„††„ƒƒƒ‚€€€‚…†„ƒ€€‚…‡‡†…ƒƒƒƒ€€‚…‡‡‡‡‡‡‡‡…„ƒƒƒ€~}}}}}}~€‚…‡‡‡…„ƒƒƒ€~}}}}}}}}}}}}}}}}~…‡‡‡‡‡‡‡‡‡‡†…ƒƒƒƒ€~}}~~~~}}}}}}}}}}~€ƒ†…„ƒƒƒ„…‡‡‡†„ƒƒƒƒƒƒƒƒƒ„†‡‡‡…ƒƒƒƒ€~}}}}}}}}}}~€ƒ†‡‡†„ƒ€€‚…‡‡†…ƒ‚€€~}}}}}~~„‡‡‡‡‡‡‡‡†„ƒ€mirrormagic-3.0.0/sounds/snd_classic/zonkdown.wav0000644000175000017500000001203713263212010021514 0ustar aeglosaeglosRIFFWAVEfmt "V"Vdataó³³³©“}ˆš©­±£Œy¦³³³ž‡{…›¨¯˜€™±³³±­©«¯³³³²°¯°²¨y{‡‰Œ–¥²±¯®­­¯±®Ÿ‘—¦³³³®¥¥­³³³±®§Žukjj†¢²°¯°±°©¡{j‡¤§ysmqˆ •~n‰¦¨•ƒ•§¦†hp’Ÿ­­¥¥®ª–ƒ‘¥ªŠkw•±±²³³³³³³³³¤‘ƒ†¡²‘piЬ³³ªˆf`kwަ¬ž|gb„¨™wYdp|‡”šŸŸ––¦°Ÿ’¢²ic‡¬ªŸ˜ž¤ª®³³³®¤š•‘ŽŽž¬³³³Ži[v™ ¡~„›°™‚{‡”†tix†z`Je€€eJ]uui|™¬‚X]†¯ŸŠœ¯§˜’—¥¬Žri{Œ’ ®¢‰uƒ‘’…ywv{‰™‚_CSc`QAb‚”Žˆ–™‹|€ƒ‰Ž…}†“–lrƒ”Ÿ«¦‘}¤²°¯°±° ‘‰†ƒq^Zj{}|||}€‚€u`JOX`hotxzpfl’–š•€jjpvz~}yv~†‰†ƒ™¡˜šž¢™ˆ‚~iQOy£ ~„‹”ž¨Ÿ•‰{mq{yqptx{~„›‹xhb[]afpz‚Š’žª¬š‡yw¤¦–‡Š“–†zu€”¨¤ŸŸ£¨˜†yxv‚–¥„da{•…rgmrngclvz{{ywsmgq€™¤ž“§­ ”‹ƒ}}|}~€‹—Ÿ¤¨™‰~yuvz}|z~„‹Ž‘Œ|lmrvvwƒ–§znpqi`d…§£€€‚€{vŠ ¬¥ž–…|q~˜²—}mmmsz}qedgjkmr}†‚}{€…ƒ}…ŽŠ}nt{~zv™‹}„š®ª¥£££—‰{tnu|‘¥©ŽtszytgTAThx„ƒqi‡§²°®™…ƒ”¦š‰}|z~„‰yijz‰~oky‡‡‚zusssmfeltƒ•ž‹x›³³³§x„–›i`_^_afow‹¡©œŽƒzsz€€}z„”Žˆˆ‰‰…€wj_q…zot{…™­¥“ƒˆŒ†yje`dv‡}l`mzƒ‹’Šƒ’ —‰Š“”‘‚wsw{}~~zwx|}l[`uŠ‚{wz}{xvz~Š®–x†••”…{{ƒ„†ˆ‹Ž–Ÿ––¤­š‡†Šƒ|ungs‚Œwsrrsuwz}}}ž™‹zv{ˆ–‡xnpquz€‹—‘~jmpsw{{zyyx€‹–Š€|†‡‡‡‰ŠŒª¥|€„…€}ˆ„}‚“£©¯³³³³³°¥š›¢¥€[FCA@@@@@Up†…ƒ‡–¡¬³³³®§›uOIXeWHKczn[LGBJYfkqrnjt€‰’š‘‚x„‘–”“Ÿ«³³³c@@@]ˆ²‰t\DEJLGB^ˆ¯¯¯¤}zy€–­³³³³³©˜‡…ƒƒ…†ƒ€|vpmki^SKFA@@@@@Qiˆ’œ§²ˆ]@@@AAAAA@@ATg|•®³³³³³•jDpœ¨‘|nb[bhmqx‹Ÿ«®²²±±²²³³ª~R@@Bn™³³³…n[G@@AMXXMAUlzvsdQAAAAAA@@DNXu—³³³³³²¢“‚o\QHG]sxwwƒœ§²ž‡€—­—sWk˜¢•‡‡›¯³³³³³–kCo›¯¦ž£«¥}TLSXOEMcztkc\UNGAAATv–ƒqlzˆƒ|uutgTBP^c_ZmƒudQCWj€™±­¦ š”‡ylbW[gsg[Xdpy€…~vsrr|…œ§¤ Ÿ¨°žmˆ¤¤Œv‹¢±²²³³³³³²±±±²±­©§¤¤ª±£ŒwvtjVBISVMCCEK^q{}hOR~ª¯¬¤{gSAO^_QBISXTOLJLvž¨“£ª™‡t_MHCAAANZl„ž¨®®œ‰Ž¡²¤–Š‚zm^UY\bhq‹¦³³³³³±­©©©§“„sbfkfUCUmzbJAADn˜ª¡—Ž……™­ª€qnu}}||~Ž¢­’x~˜²˜€wƒ‘…uq©±°¬”~qonw€ˆ‘‹}’©¨–ƒ~y–®²±±±²³³²²±sGO^qŒ¨«£š…pecbVIH]rvspdXOHARcgUDO`mljmrx‚˜¥±³³³³³¤ «®²±°« •—£££œ‘†ƒ€u]E@@@@@Uu’‘Š‚zskn‹¨¨” «¤wŠ ¯±²³³®•}¢}WNmЉƒ|obfr’¦§”€|xy„‚mXNEHTat‡†gGWtŽ­°¬©¬°¨y‰¡«Žslpvަ©—„lRO|§šz_kv†›°nat‡„|vz~„Ž–Œ‚|zx‡›£|…±§œš¡¨¬°ª’{‡Ÿ³³³£ˆn‡¢¨xroov}}xsqommm^MH`wˆ…}ukbaaep{…‘¡Ÿ¤ª¤Œu†Ÿ«‹lgnutrtzjQMv”zckto^Nbv€zsstz‘©™pH\ptbP]p‚—¬¤Ž}Ž  €ž£‘€†• €xvtj`[^acdeeep€«¬œ…zz{‡˜¨““–Š~tqn`OAAACEGYktoj€œ²²±ž€g|‘ ©±Ÿˆ{ˆ–›€}ƒŠŒ“¡¯¨š†€€‚q^c‡¬Ÿˆ{‰—Žzg…£«œŒ†‚|zŒ˜¢¬™oD`‰rYNFGg†‡ublv}€‚€~€–«³³²¥™—Ÿ¨¬°±ª¤‰fHJLMMMV`ecb{™®™…r`Nm‹ ¥¢‰q_OC[s€ƒ†–§³³³ª ˜£®šnBb‚‘„xvwukabjqh_\`ev‰mLRj}eLLczrhi€—£«° ‘Œ’jk‹¬™zcjqv{€”¨³³³‹`ESahkq‹¦§“…†~n\P`orlfnwr[D@@@@@@@BWl}‡‘žª±ª¤§­³³³³³³¡Ž‰š««¦ŸŒ{yŠu`c…©‹aAAA@@BWk~¡¨®³³³’fGsŸ²°¯¥œš¤®§œƒvfS@@@HWggddoz|{|‘¨³³³‰^Oz¤°±°¡‘Ž•œ€eQIBFNVcopkfjo}–¯›€iWF`‹±¥˜‚cCTj{ƒŒ€mavŠ€aA@@JbyŽ£®œ‰‹—£©¯£„e`_ZOD@@@@@AAA]y‡€w‡Ÿ³³³¨—‡“’†{kZOW_`_`€ž¨œtUJgƒ„}y¨§“€hPQ~©¬£•sOOf{xtokfjpn[GIVdƒ£ |Wctx_GAAAAAIYiZKHYjkhl‰§¥‘~’§³³³³³±«¤§­¯qfnwusnbVcw‚gLHUakt|‚‰tWEZn„œ±˜iVDh“«“{{…𤫮²žˆ‚˜­ ˆr]I@@@@@Ps–€\Kx£–k«BMXmޝ³³²°¯fGsž¥Œu‰¡©“~hRE\sˆ² ‹°¤“†ƒ€Œ ²®ªª®²™}jnq€’ |iUBb‚ŠiG@@Jv¢—kBnš¦‹qrx€–¬³³±žŒ€}x…Šˆ‡‹‘˜£®¨•ƒŠ’Žzex“¢…hi{‹’™ŒiE^{diyƒiNLavpg]PDUq‰š«¨•ƒ•¨³³³³³¯¡“|]BZq†™¬ª¦¡œ˜‹|kZINf~hPOxŸ§¤¡—Žz]AVknYD@@He„{sŒ¥qEi”³³³£~“©šoBYsz`FN`nps‚š²œ‡„š¯aLx¢ª –ŒƒzpfXJMs™§­°ŸŽ¡²‡\ER_YOGDB\ˆ²žŠ„›†l^l{ŒŸ®’waQBTho^Lg³³³³³³¥—”¢°ŽcEYl|‰—¢­¬žuVFWhx†‘„xx‚ŽsUGVf]NGn“oMHCQz¢‡`EUd_OBVk€˜°œ„rlg[MFsž³³³œ„uuux{ˆ“‡mTfyzbK`~’‘Šƒ|dLV‚®™}q†œ§­±¤˜†qZ\`bdemx€Š“Œ}m\JOoŽƒgK`‹²²±«¡—‚~ƒ‰vYCSchebUHEP[k{€fKSp‹›ª©”€|{s]G_‹®VXƒ°³³£xKbޱ¦›¨²¢‘…€|xtmZG@@AQabRBSiq\GTo…zowާœƒ|s„ž®—€kV@@@S€«bLx£•jDo˜¨šŒ˜¨ªu~”¥Œumsyޤ¢vJRhzz{ˆ²Šd_…­aDSamy„•¦¯±²š€hVEa¯›‡xk^l{y`FLZl‰§©™‹’™–ˆ{ƒŽmKOdu`KKavyzyphdcclvyxx€‰‹y‰¡«ˆfSJB]yŽŸ°¢€sen€Ž‹„znt{w_FRi”ª¨•ƒ”¦¥‰n\MF^uŠŸ°‘rk~ˆ~o[FFMX}¡®¥|XR~©®§¤ª°¦’iTFDAXs€eJM`tŒ¦³³³‘mQJBFMY~¢³³³³³¢vJCEK[k”¨™‹Šœ® |obm‚—¡¬ª~jZOCObuލ¢†j„ ±²²cEYnutssrx†• «¦zNWw’Œ…†Œ’‹„w_FVsœª§—‡wgYNCd¬™…‹ ³³³¨“~gQJh†˜¦¯–}svyޤ¯¤™Ÿª³³³©šŠƒ|si_TIBGLOQUp‰’ˆƒŠ…gITp†€zy|Œš¥«±ž…rw|}|{dMT€¬«£—mn{…ylu’°©ž˜¡§­³³³²±±’t`]ZRHDR`jqx†”™’‹˜§¬”}{ƒˆlOIXhqxŸ§­­Šhbq~{uow‚‹Ž‘‘Š„zxvx{{tllptvxˆ’žªª“}wwxxyz{|Š™Ÿ•Œ‡‚|yˆ’މ„€zŒ£® ’nb‚£¡‚co~qaeo{Ž¡Šwoffq|„Œ’‘”›¡‰rkw}vpkguŠ›„}xty€}m]et€„†€ywz}…•‘Œ‡}wqpty‚Œ–¢®ž…uާ¨•ƒ}wv|€|kZ[fs‹¥¬žˆ€‹˜›ˆvpswz|zqhjpw~„|hTl„˜¤°¦–‰…€}xsollpu~‡“¡®¤}}|€†Ž†z}ƒ‰‡„’ ”‚vx{{zyvs|‘¦¡˜…|{||qfhs~~ƒŒ‘†}€‰“–š”‚prw}€…€wnu|u_IZn{xv‚“ ‘€‰’މ…€|ˆ‡xmbo|ƒ…†…„|uŽ›„{sj|–އŒ‘‹rsu~‘¥¥ ™‹wrnqtuttqoq|‡†€{xuxŠˆ…ˆ™ª Ž€ˆŠ|mmmu‡™™•€srx~†Ž‘Ž‹~pis}„†wtuuy}}vosz€„‰‹ŽŒ‹ˆ…|vvy|€yrtw{€…{uronpqw|‰‘‹‚}„ŒŽ‡€|zxˆ†€€†Š‡„‚€€{wv~…“¤°‹€|x{~}zx{~~~~~zvz€…Œ”„{{{€‰’““‡€}}}}}|yvxz{xvwxyyxz‚€}|‰ŽŠ‡‚}wwwz‚~yx…‡‡†‚‚–„~}||}€…І}|}~€‚€}|zywvtrruw{€‚€~€…‹”’‰€„…€zz}€€‚€}x|€‚|}~€€‚ƒƒƒ€|z}|yw~„…€€‚~z{~~zux~ƒ‰‡€‡”Žˆ„†Šxqonsz~|zxv{€|}~€‚~xwŒ‹†ƒ†‰‡|{{}€‚€{x{~~}|‚€€„І€€‚…†„ƒ€}|}}|yx{~†Š„{xvy}|xtx}}||}‚…„€~€‚€€~~„†}|~€ƒ†|y…„€}}}€…І€~}zx{~€‚‚€~~|yy{}{yy|~~€‚„…‡Š‹…€€‚€€~}||}}}}€~z{|}}}|zwwvw{~……„‚€€‚‚€€€‚€}~‚†‚~}€‚ƒƒƒ„†…„ƒƒƒƒƒƒ{y~€~{{{|}}|zz}~}}||~€€‚|€†Š‡„„…†‚€‚ƒƒ‚€€|yxyyƒ…‚€}|}~|z}€‚€|~€‚€}}€‚€~|}}~€€‚‚€€|z{~~~€‚€€~}|z{|~~€‚€~~{xw‡ˆƒ€‚……~~~}{z|~€‚€~~}||{{|ƒƒƒƒƒ‚€€~~~}}}}}~~~~~~€‚}}}}|{{{|}}‚€€ƒ†„€‚ƒƒ‚€}|~~~~}}~~~~~~|{{||}€‚€~~}}~~~||~~~~~}||}€€‚‚€€~~}|||}}}~€‚€€€‚€~~~}|}~€€‚|}~~}||}}wmirrormagic-3.0.0/sounds/snd_classic/bug.wav0000644000175000017500000001107613263212010020422 0ustar aeglosaeglosRIFF6WAVEfmt "V"Vdataqrs~•®ž…ssrqqsŒ¥±®«–€w‘«³³²ª¢ £¦¡œ”‡zˆ“ ­³³²—}vŠŸ“€yŒ —€k„žƒjž³³³fms€’¦¥£™k}𱩡zcccm•¡«®œŠ}of‚ž®°²§›~ngdaaaiu€zrt…—¢««‰hq’²š‚qf[x™©…blФž—𦲑mUUUVW[q…”¦«°³³³³³³³³³³°ŠdPQQST`ƒ¨¡ˆrfYg‹°³³³³³ªŸ”‰~tkaZTONNMMMMMLKIII]…®›kZJEEKvŸœtKiŠ¡©±¢ŒwbLSm„~‚”¦¬°³³³£Œxy{…›±©Ÿœ¦°§–‹›«ªš‹š©¡vJM]fVF\ˆ²œ†|~¤¦{OXy˜¢­³³³¤•ƒoYo“³³³¥vaMNoŸª³³³³³²®«ª®² ‹zl^r”®‚WY„°³³ª’{fQDYoxz{jXKFA@@Kw£§–†€yrjbYOGDA@@BKUTKAk–³³³eHq˜«¯²…Z@@@@@F]t…”£©¯³³³³³³³³³³¬€T@@@EJ\‚¨Žc@@@@@Bnš©’}gQHc’£°’uhnsqohWFM\ku„‡ŠoRH[ndTL`tmVAZrt\Dg’°¨Ÿ„aBO[l€•——‹jIb¯Šu[A@@HYjƒž¬pecc‚¢¤„e}œ¦zN`‹¯‘tlw‚€|€’¤‰bAAARoŠnQI\p‡ ³³³•j@@@Nk‡˜¨°§Ÿ£«­€ULcyޤ³³³‚npsrpn‚— œ—{YIiˆ›§³³³qEi”­š‡€zuplgb^XQLGB@@@@@GS]RG@@@M[fim€š±£•€aC@@H_vjTHtŸ°¬©†cSao…Ÿ³³³}_€¡³³³¤“†ƒ€¡°”z|–±¨ž}jy“¢zQAAAm™³³³ŽbF^uq_Oj„ƒdD@@Ny¤‘gAFK[usTLjˆpds…‚gO@@@dޤzOM`r€Œ“•–…saSDWu`Bk—³³³®§ ’„}yurokgb`_]]]_`aaa^VNPR`„©³³³³³³³³”uemv~„›©¯±³³³³³³³³¦{NWw‘†{}Œ›—’„gH@@CUfcRALWbmx†–šuNMauˆ Ž~gQJj‰‡xmˆ¥£‡kƒ ±­©œŒ}n`n² Š¯³³¬‘woqr^K@@@@@Nz¦³³²±¯© —Ž„†š®›~hw…~iSLENlŠvWCOZYSPlˆƒwwxtcRj‘¬€TQnŠ„~Œš£¬©~QW{œš˜ˆgE@@DSakt|‡Ž•œ£ª¯¯¯¯¯¯¯¯­«©¬°±­©ŠeGDAELTi}ŽŸ°­§žwne^WQLHECAAA@@Fh‰———¡«­¦ž€\@@@Mau¥¨z‹¢«“|gRCVity}¥³³³–rWi|zjZhwu]EIR\grƒš«€WJ]paNAAAXx”¡­³³³³³³³³dAGLVdqnktŒ¥†_Lt›¥¡¦®³³³¤•Ÿ®³³³³³¤‹r’™‘ˆ”¥«…ak²šƒ{‚‰‚ylYF_‹°–~rss‰¢³³³®¨ ’„~{xtplifdcaaabdeeec_Z^bnЍ±²²±¯£ŒwbNFTbmw¦¬³³³³³³³³¨|PMasnhgjmlkeUE@@Dc€`BYsrdo€‰kMPjƒ‡ŒŠsbOLw¢¢Œ{‘§¨“¤³³³©mv“²ª¢ ¨±³³®–kYGEB@@@@@Ly¤³³±¥™–œ¢‹sl‹ªœfkpj\N_qƒ˜¬¢‡™¬–kBošžsF@@@@@AAFkŸ™“žª§„b\__SFQnŠš©­Ÿ‘š¨³³³›vSLELd{ƒŠ–› ¤©©©©©©¦¤¢Ÿ›˜–•“““’~jaktˆ ª‡eSIDpœrEh”¥zNAA@@@@@@@@BDGECADFaвˆ_O`qcOFYmƒœ²§œš¡¨¬°³³³’f@@@@@@JTVLBYwŒ€rjc_€ ±­©š‰~€‚¢°“wx”°«¢—†vƒœ¯¨ ™”|ik‹¬‘hQ{£³³°„XDKSi‹t[n’³³³£‡kƒ £wKZ|”†yhTAe‡š•‘•¡¬”iCp›ª™ˆvb[rˆ‡~y§¢„gXJQ}©¤’‚{xvssrqqqqqrrssssss•¬¢”†zm~š³³³ €_~ž¢vJaˆ©­±³³²²±±²²¯«ª­±°¬¥}UW‚¯§›—£¯¨šŠlNLaurogUDJUe…¦³³³³³²±±±²¬“{}Š—ž¥“lCQbpy€€{cKX€¨€YCKRh€ƒxv{~|„˜¬‹dT~¦“h@@@X‚®±²¨Œp€›ªRMav¥£Zr—«pkt}’§¥ˆlpxž—ˆyeQO\id]bxŽl`‚¥—lAn™ŸtGIR]ky€†‹Ž‘“•–™›œ™—•”““““““†zsvyŠ¡­•}gTBoš¡zSo–©ˆhVKBMXZTNKIGDBAA@@@Z…²šuy}p`Why‹Ÿ²§œ”‡•¦±®ª”x\QF@@@LY]PD^ƒ €xurФ®£˜Žƒ{{{‰ž±’ut‘¯³³«’{}Š–‘‹‹‹|lmŒ«–r[€¤³³²mZ\]oƒŒrWh޲®ª™{]y›¥zN[›€mWAc†š•‘• ¬±²²±¯¨˜‰|ojz‰‡}v¦£ƒdVIO|§¥’‚{ywvtrqqqqqrrssssss}‘¦ž“ˆu‚š°°¯£‹uŠ¢¦]cw‰™ª±²²ŸŠ‚Œ•‹~y‘ª£Šssr}–¯«£Ÿ§°« ”}ebr‚wj]PCN_rŒ¨°¬©¬°ª–‚€„Šš¦±±²rETiy€…‚}vnek}ކ}€–­©œŽv]W\bmy‡›¯ƒuŽ~^BXn„š°¦˜‡~y¨ªš‹‰‡ž¯dJv¢—kAZr|un„Ÿ¬“{w{€•©³³³£’…‚€Ž¢­Œln‹¨…cUi||yvx{}€ƒ†‰‹Ž’‘ŽŒ‹‰ˆ‡‡‡„}l[h‹®s\OCQf{’ª¤ziWKFAh“©‹nlu}umy”±‘pVLCM]oЧ™qHr›±­©š‰znbaek{ŠŽ„zskjy†‚wq‡žª¬®žqdju~€‚„‡Š‡„x^D@@ADGd¯‚WW‚¯©žš¥° ‡smhlx‚wjn¬“lV| ”jB]y€p`TIKlŒ€_CZpwof€œ¨”€zyzˆ–¡ª²œ„wwwy|ydObŠ®‚X@@@M[eeehko~ŒŽ„|{zz}~}{{zyyz{}~„‡ˆŠ–¦®³³³¡Œ‚Ž™’ƒxxywrn†¡¯§ž€]E^v}{dM@@@OakaWUWZfrtmfhkq{„sXCWk€™² Ž~zŠ¡®™„€ƒ‡—¨£„fWJDSalu{dLAAAj•©Œqnst_JRpŽ~liz‹ˆv`IRm‡Š‹‚{|~}sip~‹‹‹‚scž«–‚lTADFTi}‘¦§Œrpstld`_`€¡žsG[wŒ‘•“‹ŒŽŠz{}€ˆ‘›¦©‹nm€’Œ†ƒƒƒƒƒ‚€~}}|{{{{zyyyxwunhc^Zdo~•­š{clt…œ²ª¡’za\[c„§£yyyƒ˜­°±ªu€™­¢—™¦²¢‘ž¯ž…w©³³±„YEOXfs|xsrsu€‹‡–§³³³¢|€…„€|¦¡uIe®˜‚}€kTTp‹}h[_d{˜²¬¥ŽjDUjxz{ƒŽ•‰„€~‘¦¤_cowwvx{~‚ˆeJm•²±±±²²±¯›yUw›³³³¢…Œˆv{€‡‘›™•“—›”‡{ocbjsvxz{{|}~~€‚ƒƒƒ„…‡Š—¥²£“ˆ‚|hQHe•¥®‚VGT`irxz{|}€•ª¬¢—¡¬®¡•œ©®š††‘›„np®Œ`Mz¥¢Šs_JQqžª­œ‹‚~}“©¥z{}}zxz}ƒ—«¥‘€”¨žrFWq|bHSm„“¢«®²—|s¨°±¯š…|zxŽ¥©“}…Œ“šmjgaXN[iqjccdgq{hPFVf_RLaw‚ˆŽ‹ˆƒ|u}‡’ ®¡ˆs~‰‘—œŽ€w{~€‚€~€ƒ†…„‚€~}}}}{zwtncWbxŠ…€}{zyxx{}se_¤¥vˆˆƒ’¤²®ªhC[sxgVX^a^Zcq€”©žwPd|‰„€~}|€…˜¢’‚pZDQeo[G@@Ca€Œ…€¢¥‡jx—¯—€uuuy}„’Ÿ¤§¥‘slfnw|~†”‰|}}xtsvy‰œŸ‚eeou`KL^qoks‹£™†www’¢œ–‰s]_eq© …mcXfН²±«™‡†‹‹u]f‡¨–‚z€…ƒ€}}||~~~}|{{{}~€‚„…‰•——”†yv{~|ytnszƒ—«}_r„‹„~}|vaMNVa~›ŸŒzŒ¡®«©ª­«™†taNuœ©“}{~}zwsor|…–§®ž–¥³³³¦z†”˜Š~Œ¡ª~RSrŽƒzrnjhghqz€ƒˆ˜¨¨˜ˆ€ysssy€…~uv†‡‡€o]u—°¢”‹„€‚…‰’‡†’Ÿœ“‰ss}†…„}yoc_¤¬¡—‚nfq{€„…}ˆž±œ†|}}}|}‚‰‡ƒ~}}|{{{zwsjagv‚€{wrqqt{€~}Œ››€ƒˆˆ€yz}~|nXBYp|wrw~~y~†œ¨£Œvˆ ª–‚ƒˆŒ‘—œ‘†~zvy||ywvv~†„vhltt^H_а—€|‹›¡¥¦Ÿ˜xy{vlbkt}‡‘Š…€{œ‚{{{Œ ¦†gdox{~}|zyxz{wrnsx€‹–Œ{zz~‚Š›«œ|^fm}•®¤•ˆ||€uhjzŠ…€‚†‚~z{}}}}}}}}}}}}}}~€„‰‘”•ˆ}y|}|}~–ny„ˆƒ~}|xma`cgt€ƒ~x‚Ž˜¡¡ž›‘‡|ob}—¦Ÿ˜†€‚……|yy|¤®Ÿ•¥²±¯¤{yywqkr~ƒmWZq†ŠŠ‡|wurv}ƒ†‰ˆ„€ƒ‡‰ƒ}|}~…‡‰Š†‚|zˆ­¢—‹†ƒ€}|}~{wuuvy|}}}…“ˆ~€‚}x|†’Œ‡vpmksz‰ž²žŠ}xruz}}}~}|xtvƒ““‘‰|wrw|~~„Œ•¦œ‹{xuvz€ƒ…†„€}}}Š’ˆ~wwwvutwzxsnu|~{x€ˆ‰„€{wwz}~‚Žš˜“މ„…ŠŽˆ}zxtposxz|~Š––ˆ{xwuttw{~{vrx‚€€wkcmw}€‚zxz{{{zuoqv|„ŽŽ„{|~~}{{zyyyyx{ƒŒŽ‹ˆ‰Ž’‡|wy{€†Œ“š”ˆ}sjly…‰Œ†€~~}}}}}}}~~‡Ž‡~xxy{|~‚ˆ‡€z|~~zvtssz€„‡Š„{zzz{|}~}yvx€‰Œ‹‡ƒ‹“’ˆ€~{xy|~~‚ˆŽ‹ˆ…‚€|wttux{}zww{„ˆ‘Žˆ‚€{xt{‚‡‡‡‡‡†ƒ€€ƒ‡Œ‹‚{{~™•‰~‚†„€‚†‹Ž‰…€|x|€‚€~}}~~€ƒƒƒƒ…†ƒ{zxy{}{y{€†…„}ywvvz~…‘œ„}zxy|~~–mirrormagic-3.0.0/sounds/snd_classic/klumpf.wav0000644000175000017500000001056013263212010021140 0ustar aeglosaeglosRIFFhWAVEfmt "V"Vdatañ€€€€€€€€€€€€€€€€€€€€€€€‚„…‡ˆ‰‰‰‘’Šƒzpe[QIJKP\gv‡˜«¿ÑÙáãßÛÐÁ²¡}m^PD91*$" !&+271/----035;@FNU\dlszˆ—ž¤©­±´¶¹¹¹¸¸·µ²°¬¨¤Ÿ›—”‘ŽŒ‹Š‰‰‰ˆ†„~{vqlgb]WRNJFDB@@@ABCEHJNRW^dkszˆ˜ ¨¯¶¼ÂÇÊÍÍÍÌÊÆÃ¾¹´®§ š“‡€{uojea^[XWUTTUVXZ\_bdgkosvy|~€‚…ˆ‰Š‹‹ŒŒŒŒŒŒ‹Š‰ˆ‡†…ƒ‚€~~~€€€€€€€€€€€€€€€‚‚‚ƒƒ„„…†‡ˆ‰‹Œ‡ƒ‹•™”‰ƒ}yvqke_XRNJGFEGILPUZ`gnv‡—¢®¹ÀÈÐØáäääääãßÜ×ÒÌĺ°§ž–„{skc\TNHB=940,)&#"  !#'+/49>CHMSX_gnu|ƒŠ‘—£©¯µ¹¾ÂÆÊÌÏÒÔÖØÚÜÝÞÞÝÝÜÛÙ×ÔÑÍÈÿº¶°«¥ž˜‰‚|vpjd^XSNIDA=:631/-,,,,,---./02468;>@CFJNRVY]adhlptx|‚†‰‘•˜›Ÿ¢¤§©¬®°²³´µ¶¸¸¸¸¹¹¹¸¸··¶µ´´²°¯­¬ª¨¦£¡Ÿ›˜—•“’ŽŒŒ‹‹‹ŠŠŠŠŠŠ‰‰ˆˆ‡†…„ƒ€~}{ywtqmkigda_\YVTQOMKJHFEDCBA@@@@@AAABCCDFGIJLMNPRTX[^adhlpsw{~„ˆ‹”™ ¤¨¬°³·º½ÀÂÅÇÉÊÌÍÎÎÎÎÌËÊÉÈÆÄÂÀ¾»¹¶³°­ª¦¢Ÿœ˜•’Œ‰†‚|zwtqnkifdca_]\[ZXWVUUTTTTTUUUVWYZ[\]_`bcefhjkmorsuvxy{|~€€‚ƒ„†‡ˆˆˆ‰ŠŠ‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹Š‰‰ˆˆ‡‡†…„„ƒ‚‚€€€€€€~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒƒ‚‚ƒƒ„„„„………†††††‡Š‹Šˆˆˆ‡†„yr„ ½­›Œ‡ƒ‡’™ˆŠŒ‹ƒ|z{|xtqqqohb_^^YTONMLJHHHHFDDGJKKKNPSVXZ^beginsy|~‚ˆ’—œŸ­»ÃÂÁÂÃÄÎØáâäãâáâäåääãããâàßÝÛØÖÔÒÎËÇÿºµ¯«¦¢ž™•‘Œ‡ƒ~zwsnifc`\XUQNKHFC@>;86531.+*)'&$$$$"! !"$&(*,.02469;>ADGILNQTW[]`dhlptx{~„‡Š‘”˜›ž¡¤§ª­°³µ·¹¼¾ÁÂÄÅÇÉÊËÌÎÏÑÒÓÔÖØ×רÙÛÛÛÛÜÝÞÝÝÜÜÜÜÜÜÛÙØ××ÖÒÏÌËÊÈÅÃÀ½»¹·´²¯¬©¦£ š˜”‹ˆ…|yvroljgc`^[XURPNLIGEB@><;97654320/..--,,,,,,,,,-----./00002355568:;<=>>?BDFGHJLOPRTVXY[\^acegiknoqrtwyz|}€‚ƒ„„‡‰‹‘“”–˜š›Ÿ ¢£¤¥¦§©ª«¬®°±²²³´´´´µ¶¶···¸¹¸·µ¶¸¹¸¸¸¹¹¸¸¸···¶µµµµ´´´³±°°°¯®¬«««ª©¨¦¥££¢¡  žœš™˜˜˜—•”“’‘‘ŽŒŒŒŒŒŒŒŒ‹‹‹ŠŠ‹‹‹ŠŠŠŠŠŠ‰ˆ‰‰Š‰ˆˆ‡‡‡†…………„ƒ‚€~}}|{zzxvtsrqpomkihgfedca`^]\ZYWVTSRRPOMMLKJIHHHGFEEDCCCBBBAAAAA@@@AAAAABBBCDDDDDDDEFGHHHIJLLLMMNOPQSTVXY[\\^`acdfikmoprtuwy{}€‚„†‡‰Š‹’•—™›Ÿ ¢¤¦¨ª«­°²µ¶¸¹»¼½¾¿ÁÂÄÄÅÆÈÉÊËÌÌÌÍÍÍÍÍÍÍÍÌÌÌËËËÊÊÊÉÈÇÆÄÃÂÁÀ¿¿½¼»º¸·µ´²±°­«©¨§¦¤£¡Ÿœ›š™—”“‘Ž‹Šˆ‡…ƒ‚€~|zyxwutrqpnmkkjigedcba`__^]\\[[ZZYXXXWWWVVUUUUUUUUUUUUUUVVVWWWXXYYYZ[[\\]^_```abcdeffghijkllmopqrsttuvvwxyyz{||}~€€€€‚‚ƒ„………††‡ˆˆˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆˆˆ‡‡‡†††……„„„ƒƒƒ‚‚€€€€€€€€€€€~~~~~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒƒƒƒƒ‚‚‚‚‚ƒ„„„„ƒƒƒ„„„……………………†††‡‡‡ˆˆ‰‹ŽŽ‹‰‡ˆ‰ˆ‡†…„„‰•}e[tŒ’†z‡™«Á×Ú·”yeRe–Ÿ§¨ —‘Ž‹‡ƒƒ‘ ¢–‰€xpz„‰‚{wvvxzzxurnijloruwk_WWV[bid^YSNLMNOQRPOLGBCGKLLLGCABDEGIJKLLLKKJLMORTUUTUWXZ]_bdeeefghlptuuvy|~€‚„†ŠŽ‘“•—›žœšš›Ÿ¥ª²»ÃÇËËû¹»¾ÁÅÈÊËÎÔÛàâåäãâàÞÞàâäääããääääääãããââááàßÞÞÝÜÜÚÙ×ÖÔÓÒÒÐÎÍËÉÇÆÄÃÁ¿¼¸´²°®¬ª¨¦¤¡Ÿœš˜–”’ŽŒ‰†ƒ€~|zxvurpnljhfdba_^\ZYWVTRPNLKJIHFEDDB@><:88877754210/.-+)(+--*'$" #&'&%##"! !!"!!!  !"#%&'(()*+,--./123445678:;=>@ABCDFGIJLMNOQRSTUWY[]_`bcefgjlnqsuwxz{}~‚„…‡ˆŠ‹’”•–—˜™›Ÿ¡¢¤¥¦¨©ª¬­¯°²³´µ¶·¹º»¼½¿ÀÁÁÂÃÅÆÇÈÈÈÉÊÊËÌÍÍÍÎÏÐÑÒÒÒÒÓÓÓÔÕÖרØÖÕÖÖÖ×ÙÚÜÝÝÜÚØØ×ÙÚÜÞààÞÝÛØÖרÙÜÞßÝÜÙ×ÔÕÖÖØÙØÖÔÓÑÐÏÎÌÌÌËÊÈÇÆÆÅÃÂÁ¿½¼»º¹¸·µ´³±°¯®­«ª¨§¦¤¢¡Ÿ›š˜—–•“‘Šˆ‡…„ƒ‚~|{ywusrpnmllljhfdb`^]\[[YXVUSRPONMKKJIHFEDDBA???>=<;987766654433310000///.....---,,,,,--.---,,,,,-./...---/0111222111112356776666679<=>???>>=>?@ABCDFGGGHHHJKLNOPPQRSTUUVWXZZZ[[[^`ccddddfikllmmmnopqqqtvxxxyzz{||~‚ƒƒƒƒ„„…†‡ˆ‰‹ŒŽ‘’””””•––˜™ššš›œžŸŸ ¡¢¢£¤¥¥¦§¨¨¨©©©ª«¬¬¬­®¯°°°±±±±±²²³´´´´´´´´µµ¶···¶µµ¶·¹¹¹¸·¶µ´´µ¶·¸¹¸¸¸·¶¶¶¶·¸¹¹¹¹·¶¶¶¶···¶¶¶µ´´´´´´´´´´´´³²°°°°°°¯¯¯®®®­¬¬«««««ªªª©¨§¥¤¤¤¤£¢¢¡    ŸŸŸžœœ›š˜˜˜˜˜˜˜——––•””””””“’‘‘ŽŽŽŒŒŒŒŒŒŒŒŒŒŒ‹Š‹‹ŒŒŒŒ‹‹‹ŠŠŠŠŠ‹ŒŒ‹‹‹Š‰ŠŠŠ‹‹‹ŠŠ‰‰ˆˆˆˆ‰ŠŠ‰‰‰‰‰ˆˆ‡ˆˆˆ‡‡††…„„„…††……„„ƒ‚‚‚€€€€~~~}||||{{{zyyxxwvutsstttrqoonmmmlkjihggggggfeccbaa`___^\[[[ZZYXXXVUTTTSSSRQQPONNMLLLLLKKJIIIHHHGGGGGFFFEEEDDDDDCCCCCCBBBBBBBBBBBAAAAABBBBBBBBBBBCCCCCCCCDDDDDDDDDDDEFFFFFGHHHHHHHIJKKLLLLMMMNNNNNOOPQRSTTUUUVXYZ[\\\]]]^_`abbcdeefghijkmmnoopqrstuvwxyzz{||}~€‚ƒƒ„…†‡ˆ‰‰‰ŠŒŽ‘’“”•–—˜˜™šœœžŸ ¡¢¢£¤¥¦¨©ªª«¬¬®¯±²³´´´µ¶¶¸¹ºº»¼¼¼½¾¿¿ÀÁÁÂÃÄÄÄÄÅÅÆÇÈÈÈÈÈÉÉÊÊÊËËËËËËÌÌÌÌÌÌÌÌÌÌÌÌÌËËËËËËÊÊÉÉÉÉÉÉÈÈÈÈÈÇÇÇÆÅÅÄÄÄÃÂÁÁÀ¿¿¿¾¾½½¼»»»º¹¸··¶¶µ´´´³±°¯¯®­¬«ª©¨¨¨§¦¥¥¤£¢¡ ŸŸžœ›š™™™˜˜—–•“’ŽŒ‹Š‰ˆˆˆ‡…„„ƒ‚€€€€~}|{zyxxxwwvuutsrrqpoonmmllllkjiihgffeeeddcccbaa```__^^^]\\\\[[[[[[ZZZYYXXXXXXXXXWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVWWWWWWXXXXXXXXXXXYZZZZ[[[\\\]]]]]^^^_````aaabbbcddeefffggghhhiijjjklllllmnooopppqrssstttuuuvvwwwxxxxxxyz{{{|||}}}~~€€€€€€€€‚‚‚ƒƒ„„„„„„………††‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆˆ‰‰‰ŠŠŠŠŠŠŠŠ‹‹‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠŠŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡††………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/whoosh.wav0000644000175000017500000001563413263212010021160 0ustar aeglosaeglosRIFF”WAVEfmt "V"Vdata………………………………………………………††‡‡‡ˆˆˆ‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡ˆ‰Š‹ŒŽ‘“”•—˜šœž ¢¤¥§§¨§¤¡™•’ŽŠ‡ƒ‚‚‚ƒ…‡‰‹Ž‘’”“’’‘ŽŒŽ‘•™ž¢§«°µº½¿Á¾»¸´°­©¥¢ž›˜–•“’‘ŽŒŠˆ†ƒ|yurolhebglqw~„‰–¤©®³·º¾ÁÄÈÌÑÔרÑÉÁ¸®¤›‘ˆvsqqvz„ˆ’—œ¡£¢ Ÿœ›š˜—–—˜™›ž¢¥©¬¯²µ¸»·¯¦•Œƒzqh_ZXWZ_chlptx|…ŠŽ“˜ž£¨­²¸½¼º¸²«¥ž˜‘‹…zuz~ƒˆŒ‘–›Ÿ¥ª¬­®®®®®®®®®¬«©¢š’‹„|umf^VVUVXZ\^_aceeec]WRLFA;60*(1:ES`mz‡” ¬±·µª –‹wmcYNLQV]gpx€ˆ˜ž¡¤ ™“‡{tnhadkqz‚Š“›£¬µ·¶¶«ž‘„xl_RE9,2;<>@ACEGJKLNNOMKIGFDB?=<:CScr‘¡±ÀÏÞçêíäØÍ¸­¢–Œwsrrponnmlkjloqw}‚ˆ“™Ÿ£¨¬¤œ”†wpiaY[\^elsz‡Ž•™ž“‡|peZNB7,#',3@N[hvƒ©´¾ÄËÐÔÙÞäêïõ÷ïèÞÑĸ­¢•‰~xru~‡‘𤭶¾ÈÑÒÎÊĽ¶¯§ ˜Š‡„ˆŽ“™Ÿ¥ª°µºÀÃÆÉËÌÎÑÔÖØÙÙÙÙÕÐÌÈÿ¼¹µ²®¥š„ynbWLB71+&&&'(*+-.../=KYguƒ«¸ÆÊÎÏÇ¿¸±©¢š’‹„‚‡’˜£©®´º½¼º¶¯¨ ˜‰‚{uonpsux{~„‡ŠŒŒŒ‹Š‰‡†„ƒ‚€ƒ…‡‰‹Ž’”‘ŽŠ„}wpjc\UQNKT^hs}ˆ’œ¦°ºÀÅÉÉÉÊËÍÎÐÑÑÑÐÎËÈÅ¿¼¸µ²°³¶º¾ÃÈÌÐÕÙÝÚ×ÑÁ° ~m\L;+$(/8BLU_hr{‚ztnga[TNHAAFKRZaipw‡Œ‹†€{uojd_YSSUWZ]`cfilopppnljhec`^[YWSOJGC@<83/+,-.4:@FLSY`flry€‡”›¡¨¯¶¼¹·´¬¤œ”‹ƒ{rlfdnxŒ– «µ¿ÉÐÍÊĸ¬¡–‹€uj`WPPONMMKJHHGJPW^gpy‚‹”œ¤ª°¯«¦¢˜”Œˆƒ„ˆŒ‘˜ž¥¬²¸¾ÄÈÌÊÇÅ¿½º·´±®©£–ˆzsmfa]Y]`dgknqtwz}{ywtqnkifcacegpx‰‘𢫴½ÄÀ¼¸µ±­ª¦£Ÿ›˜”‘ŽŒ‰‡„~{yvvvwxyyz{}}~}}}{ywusrpnljhjlnpqruwy{}‚…ˆŒ“–™ £¦¨¡˜Ž…{qh^UKA@CEOZeoy„Ž™¡©±®©¥¡œ˜”‹‡‚…‡Š•𠦫°¶»ÀÆÊÎÓÙßäèíòøüïâÔ°žŒ{iXF=43DUfwˆ™ªºËÜæÞÕÉ»¬ŽqbUNFHR\gq|†™¤®²­©£–‰‚|upnkmprux{}€ƒ…ˆˆ‡‡†…„ƒ‚€}zvpjd]WPJC=6/5>FNV^gpxŠŒ‡€ztmgaZTNJRZbjr{ƒ‹”œ¤¦§§£Ÿ›—”Œ‰†ƒƒˆ“™Ÿ¤ª°µº¿ÃÇÊÌÍÎÐÑÓÔÖ×ÙØÖÕÓÐÍËÊÈÇÅÃÀ½¹¶²®«§£ž›˜•“’‘ŽŽŒ‹Š‹ŒŒŽ‘’“”•—–”’‰ti^TI?4( '.8BLWalv‰—™š›œžŸ ¢£¤¡ž›˜•’ŒŠ‡„‚‚ƒ„…†‡ˆ‰Š‹“—œ¡¥ª®³¸»»º·°¨¡š“Œ…~wpmmnopqrsuvwy~ƒ‹”¦¯¹ÂËÔßéæÙË¿²¥™€th`]Y^djpu{€†‹•–––––––––––––––––––––––––—™šš›œžŸ žœš˜•“‹ˆ†„€€€€€€€€€€€|yvsokhd`\XVTUY^aeilptw{||{zxvtrpomlllouz€…Š•› ¦§¥¤¡™•‘ŽŠ†„‚€‚‚„…†‡ˆ‰Š‹Š‰‰ˆ†…„ƒ‚€ƒ†‰’œ¦°»ÅÍÖàêôñìèâÜÖÑËÅÀºµ¯©£˜’Œ†€ztnjkmoqstvxz|~…‰Ž”šŸ¥ª¯µ¹¾½°£–Š}pcWI<1.+,/26:>BEHMQV[aflqw}‚ˆ‘’“‘ŽŒŠˆ†…ƒ‚‚†‹–›¡¦«±¶¼¼¹¶°©£—Šƒ}xromjgdb_\YVSY_foxŠ’œ¥®µ»À¼¸µ±­ª¦¢Ÿ›˜”‹‡‚}xtokgc_\\[ZXWVUUSRSZahow‡— §©«©¡š“Œ…~wqjc`cegjloqtvyywtnf^ULD;3+"'1HR\eox‹•ž¨ª«¬¬¬¬¬¬­®®ª¦¢™‘ˆvmd[RHBGKPUZ_dinsx~…‹’š¡©±¸¿ÆÎÕÙÙÙØÖÕÓÒÐÏÍÌËÉÉÉÉÉÉÈÇÆÅÅÅ¿µ¬¢™†}tja]]]cjryˆ—ž¥­¬ª¨¥£¡Ÿœš˜•‘މ„~ytnid`\Yajry‰‘™¡©²°­«¤—Šƒ}vrnlrw}‚ˆŽ“™Ÿ¥©©¨§¥¢ š—•’І}yuqmiea`ceimrvzƒˆŒ‘‘Œ‹‰ˆ‡†„ƒ‚€~}|{zyyyz{{||}}~„‡Š“—𠢤¦§¨©©ª«¬¬­®®¬©§¦¤£¡žœ›™š›œ ¤¨¬±µ¹¾ÂÆÈ¼¶°ª¤ž˜’Œ†„€€€€€€€€€€€‚†‹”˜¢¦«¯±±°­©¥ ›–‘‰…€‚„†ˆŠŒŽ’“–™œ ¤¨¬¯³·º½¿Á½¹´¯ª¥Ÿš•Šˆ†…†‡ˆˆˆ‰‰‰ˆ‡‡{uoic]WQJDFJNTY_flrw}ƒ„~xrke^WPJD?BEIPV\bhnty„ˆŒ’•™œŸ¢¦ª«§£Ÿ™“މ„zusrsvy}€ƒ‡ŠŽ‘”“‹†‚}xtojecccgmtz…‹‘—¤¤¢ žœ™—•“‘Ž’”—™œž¡£¦©¬©¥¡™–’Œˆ„…†ˆŒ•™ž£§«°´¸³­¨¤Ÿš–’ˆ„‚€€€€€€€€€‚†‰‘”˜œ ¤§«®±³µ¶¸º¼¾ÀÁÁÁ¾¹´®¨¢—‘Œ†„„„†‰Œ‘”–™œŸ£§«°´¸½ÁÆËÏÓÑɸ¬¡–‹vkc]X\aflqv{†Œ‘“““’’‘‘‘“”›¡¨®µ»ÁÈÍÓÙÒËù¯¦œ“Š€wtrqw}ƒˆ“𠦫¯­«©¨¦¤¢ ›˜˜—˜˜™š›œžŸŸ ž™•Œ‡ƒzvrnmlmoprtwxz|}€€€‚‚„…††‡ˆ‰Š“˜¡¦ª¯´¹¼¿Á¾º·³°¬¨¥¡™–“Šˆ…ƒ€}zyxy~ƒˆ‘—œ¢§¬¯«§¡š“Œ…~wpieaafkpuy~ƒˆŒ‘““’‘‹‰‡…ƒ€~~~~~~~~~~~~}zxuspmjgeb`^]_abdeghjkmonnnmlkkkjjjklloqtvy{~€ƒ…‡ƒzvrnjea\WY[^fmu}…”œ£ª¯¬¨¤ œ—“‹‡ƒzupje_ZTNIEAAJS\enwˆ‘š¡£¥¥£¢ žœš™—–”•–—˜™š›žŸ Ÿœš—”‘Œ‰†„ƒ‚„…‡‰‹ŒŽ‘“’ŒŠ‡„|zwvtuvxxyz{|}~~€‚…‡‰‹’”—˜™š˜—•”’‘Œ‹Ž’•˜› £¥¨©ª©¤ œ˜•‘І‚~zwspmieb^ZXXY\aflqw}‚ˆŽ“•”“’‘‘ŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹’•—šœŸ¡¤§¦¤¢œ•Žˆ{tnhb\_dhlptx|…‰Œ‘“•—™›Ÿ¢¢¢¢›”‡€zsmf^WXYZ_dinrw{€ƒ‡ˆˆ‡†……„ƒ‚€ƒ„†‰‹Ž‘“–™œœ›—“‹‡ƒ{wspnlkjigfdcbbbbdhlorvy|ƒ‡ŠŒŽ’“•—™›š–“Œ‰…~zvsqoljgec`^[]_aiqz‚Š“œ¥®¶¾ºµ±¬§¡œ—‘Œ‡ƒ{xuspnkheb_^cglosw{€„ˆŒ’•˜›ž¡¤§«¯±³³¯«¨¥¢Ÿ›—”‘ŽŽŽ’“”–—˜˜™—•“‘Ž‹‰‡…ƒƒƒƒ„†‡‰‹Ž‘’“’‹‰ˆ†…ƒ|zwtqnkhfc`_]afjmqux|€ƒ‡‰‹Ž‘’“•–––•”’ŒŠˆ†„€~}|{zyxwvvvw{~„‡Š’•˜˜˜——————–––––——————˜˜˜˜˜—”’Ž‹ˆ†„‚€~}|||{{zzzyyxwvusrponmlklmmpsvy|‚…ˆŒ‘‘’“““”••”“‘ŒŠ‡„~{ywv|†Š”šŸ¤©®­¬«§£ œ˜”Ї†‡‰ŠŒŽ‘“””’‰†‚{wtpmjiiihhhhhhhhjnsx…‹‘—ž¤ª­±¯«¦£Ÿ›—“Œˆ†…„ƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒ…†‡‰ŠŒ’“’’’Œ‰†‚{xtrotx}‚ˆŽ“˜ž¤ª¬­­«©§¤¢ žœš—•‘ŽŠ‡ƒ{wspnoprx}ƒ‰”™Ÿ¥«¬©¥¢Ÿœ™–’Ї…ƒ}{xwusrpty…Е𠦬­¬¬¨£ž™”‹†‚~z{~€ƒ…‡‰‹’‘‹‰‡…ƒ€~|zyzz{{{|||}}}~~~~~€‚ƒ…‡‰‹Ž’””“’‘‹Šˆ†„‚€€‚„†ˆ‹’•˜š›œ›™˜—–•“’ދЉˆ‡…„‚€„‡ŠŽ‘”—›ž¢¥¤¢ ›˜–”’ŽŒ‰‡„~|yvtqnkilpsvz~…ˆŒ‘“••••••–––––•”“‘ŽŒ‹Šˆ‡†…„ƒ‚€~}}}…Š—£©®µ¼À¾¼¹³­§¢œ–‹‡ƒ‚…‡‰‹‘“•—™™™˜˜˜—–•••”’‘ŽŠ†‚}yuqmieefgjnqtwy|‚ƒ…ƒ~|zxvusqsux{~„‡Š‘’‘Ž‹‡ƒ|xtqmjmprvz}„ˆŒ’”–—˜™šš›œŸ Ÿ›—“ŽŠ†}ytppprux|ƒ‡ŠŽ‘”••”“’’‘‘ŽŽŒŠ‰‡†„ƒ€~€‚ƒ…†‡ˆ‰Š‹‘“•—™›Ÿ¢¤¦§¨©©ª««¬¬¬¬©¦¤ž˜’‡‚|vrnkosw{ƒˆŒ”———–”“‘ŽŒŠ‰‡…„„„ƒƒƒ‚‚‚‚‚€~}{zyxvutttuxz}€ƒ†‰ŒŽ‘‘‹‰‡…‚€~|zxvutrqonmlkjkmoqsux{}€‚„†‡†……„ƒ‚‚€‚ƒ†ˆŠŒ‘““““ŽŒŠ‡„‚}{yz|}~€ƒ„…‡ˆˆˆ‡‡†…„ƒ‚€€€‚‚ƒ„……†‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆŠŒ‘“•˜™››™—•‘І‚~zvspqtx{‚†‰Œ““““‘ŒŠˆ†…ƒ€€€€€€€€€€€€‚ƒ…‡ŠŒŽ‘“–™›œžœœœ›››ššš™—–•”“’ŽŒ‹ŒŽ‘’“”•–———————————––•”’‹‰‡…ƒ~}}}|||{{zzzyyyxwwvvuuuvxz|~„†ˆŠŒŽ‘’’“•––—˜™š™—–“Ї„~{yvy|‚…ˆ‹Ž‘”—˜™˜˜˜———–••””“’‘ŽŒ‹Š‰ˆ‡†…„ƒƒ‚~}}}}}}|||{{|||}~~€€‚ƒƒƒƒƒƒƒƒƒ‚‚‚‚‚€€€€€€€€‚„†ˆŠŒ‘“–•””“’ŽŒ‹‹‹ŒŽ‘’“”•–”’‹‰†„}|||‚…ˆŒ’•˜šš˜•’Ž‹ˆ…}zxwvvvwwwwwwwwxz|~ƒ…†ˆŠ’“”•–—˜™›œžœ™•’Ž‹ˆ…~{xxxz{}„…‡‰‹‹‰‡…ƒ€~|zxvwxy|‚…ˆ‹’•—™—•“‘‹‰‡„‚ƒ„„†ˆŠŒ‘’“”•”“’‘ŽŽŒ‹Š‰ˆ‡†…„„ƒ‚€€‚ƒƒ„………†‡ˆˆ‰Š‹ŒŽŽŽŒ‹‰ˆ†„‚€€€‚ƒƒ„…‡ˆ‰ŠŠŠ‰ˆ‡†……ƒ‚€~~}||{{zzyz{|~ƒ†ˆ‹“•˜–”“‘‹‰‡„‚€€‚‚‚ƒƒƒƒƒƒ‚‚€€€~~~}}}|||{{||}~€ƒ„…†ˆ‰ŠŒŒŽ‘‘’““““’‘Œ‹‹Š‰‰‰ˆ‡‡††……„ƒƒƒ‚‚‚€€€€‚…‡‰ŒŽ’”—š™˜˜–•“’ŽŒ‹Š‰‰ˆˆ‡†††………„ƒ‚‚‚€€‚ƒƒ„…†‡ˆ‰‰ŠŠŠŠŠ‹‹‹‹‹‹ŠŠ‰‡…„‚}|zyyz{|~€ƒ„†‡‰‰Š‰ˆˆ‡‡‡†…„„„ƒ‚‚€€€€ƒ…‡‰‹Ž’”–•”“’‘ŽŒ‹‹‹‹Ž‘’“”•–—˜–•“’‘ŽŒŠ‰ˆ‡‡††………„„„ƒƒƒ‚‚‚‚‚€€€€€‚‚‚ƒƒƒƒƒ‚‚€€€~~}|}~€‚ƒ„†‡‰ŠŒŽŒŒŒ‹‹ŠŠŠŠŠŠ‹ŒŒŽŽŽŽŽŽŒŒŒŒŒ‹‹‹Š‰ˆ‡†…„ƒ‚‚€€€‚‚ƒƒƒƒƒƒ‡’•—™™™•ˆ‡ˆ‰‹ŒŽŽŽŽŒŠˆ†ƒ}{xvxy{}€‚„…‡‰ŒŒŒŒŠ‰‡†„ƒ‚€}|}~€‚ƒ„†‡ˆ‰‰‰ˆ‡†„ƒ‚€~}}~€‚ƒ„…†‡ˆˆˆ‡‡†…„„ƒ‚€€€€€€€€€€€€€‚ƒƒ„„„……†††………„„„ƒƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒƒ„„„„„„„„„„„„„„†‡‰‹‘“•—™š››™—•“‘‹‰‡…†‡ˆ‰Š‹ŒŽŽ‹Šˆ‡…„‚€€‚„†ˆ‹‘’•———–•””“’‘ŽŽŒ‹Š‰ˆ‡†„ƒƒ‚€€€€€€€€€€€€€€€€‚‚‚ƒ„………††‡†††…„ƒƒ‚€~~~~~~€€€‚‚‚ƒƒƒƒƒ„„„………†‡ˆˆ‰Š‹‹ŒŒŒŒŒŒŒ‹‹‹ŠŠ‰ˆ‡†……„ƒƒ‚€‚‚ƒ„…†‡ˆ‰‰‰ˆ‡†…„„ƒ‚€€€€€€€‚‚‚‚‚‚ƒƒ„„„„„„„„„ƒ‚‚€€€€€€‚ƒ„…††‡ˆ‰‰ŠŠŠ‹‹ŒŒŒŒŒŒ‹‰ˆ‡†…„ƒ‚€‚ƒƒ„……†‡ˆˆˆˆ‡‡†……„ƒ‚‚‚ƒ„……†‡ˆ‰Š‹ŒŒŒŒŒ‹‹‹ŠŠŠ‰ˆˆ‡‡††…………†††‡‡‡ˆ‰‰‰‰ˆ‡‡†††…„ƒƒ‚ƒƒƒ„……‡ˆ‰‰Š‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡†††††………………………††‡‡ˆ‰‰‰ŠŠŠŠŠ‰‰‰ˆˆˆ‡‡‡†††††………„„„„„„„„„„„„„„„„„LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/halloffame.wav0000644000175000017500000032557413263212010021756 0ustar aeglosaeglosRIFFt«WAVEfmt "V"VdataþªŽŽŽŽŽŽŽ’‘ŽŽŽŽ’’’’‘ŽŽŽŽŽ‘’‘Ž‘’’’’’’’’’’‘ŽŽ‘’‘Ž’’’’ŽŽŽŽŽŽŽŽ’‘ŽŽŽŽŽŽŽŽŽŽŽŽŽŽ‘‘ŽŽŽŽŽŽŽŒŒŒŒŽŽŽŽŽŽŽŽ‘‘‘ŽŽŽŽŽ‘‘‘ŽŽŽŽŽŽŽŽ‘‘’‘Ž‘’’’’’’’‘ŽŽŽ’’’’’’’’’’’’’’’‘Ž’’’’’’’’’’’’’’’’’’’’’’’‘ŽŽŽŽŽŽŽŽŒŒŽŽŽŽŽŽŽŒŒŒŒŒŒŒŒŒŒ‹‰ˆ†„‚|yvstvx{‚‡‹’•˜šœžžžž ¥ª±»ÅÄÀ¼·²¬§¡œœš˜–‘Œ‡{y{|~„ˆ‹’•™Ÿ¤¥¤¤¤¤¥©¬¬§£Ÿš–‹…|xuqmjfda_][ZZZ\^`begjnonlkjjr|…Ž—ž£¨©¨¨¤ ››š™™˜—•”“’’’’“–™›ž¡¤§ª¬®®®®®®®®®®®¯±³²®ª¤—šžŸŸžŸ¡¢¤¦¨©ª©¦£¤¦¨£˜”˜ ¥§¨£œ–„}{ytldcddddcb````behovŠ– ¢›‘†“¡««ª©§¦¨«®©¤Ÿœ™™šš”‹ƒzqkklotz{zzyxxxxseW\kz‹ªœ‡‰Œ†|sz‚‡‰ŒŠ‡„†‡‰‹’‘ŽŒ‹‰~smorplhq{ƒƒ‚ƒ†‰†~wy}„ˆ‰‰ˆŠ˜¢«§£Ÿ›—™¡¦ª®§¡š”’Ÿ«°±²®ª§¤¡žœšž£¨¨¨©ª¬­®®®®®³·»ÁÆÇÅÄÊÓÜè”™Ÿ¨´À¿·°²³²¬¥ž”‹‹Ž’ˆƒ||‚‡‚xokhgmsuspnkhaZUZ_fpz‚†‰Š}pjpv|‚ˆŽ”›œžœš˜•’”•—™›™‘‰shilorvzˆŒ’”••“‘‘“•”‘Ž‘“žª«’zwˆ˜™•‘‘Žˆ‚~|zuojmoquy}…ƒ€~‚†‡„€€€€€€ƒ…‡‹‘”–™›ž›™–‘‹‰ŠŠ‰‡†’ž§¦¤¢ž›ž¤ª¤™œŸ£©®±²²§›“š¡¢œ——™š˜•••–˜š›–’›¤®¾ÎÒô­«ª¤™¡©¯±´¶¹¼¿ÂÅËÑ×àéçàÙÆ°›š˜—–”‘Œ†‡ˆ‡{pgebdfhjlou|{k[ZepolifbckshN48DPPPOKGJRZfs€wnijlmoptx|€„ˆŽ•šœžŸ  ¤¨§œ‘Іƒ‰“œ›š˜ˆŠ•¡¡œ˜ ¨¬¤œš ¥­´¥•‹ž±¹´¯¯°°§ž“€mhvƒŽ˜¡¢¢¡š–“‹ˆ„†‰‹‘—˜•‘‘’’’’“”–˜›ž˜’’—¤«­¬¬§¢Ÿ¢¥¦¦¦œ‹{ƒ­½Á­™“—™–’‘‘’‹€tv|„ˆˆƒ~~‚†ˆŠœ«¯—~oicfkpy‚‰‘”˜œš˜–––”އ‚€~€‚„†‡‡‡†‡ŠŒŒŒŒv`LE>=DJ_{—yYAQahdahs~„…‚}zx}„ŒŒŒŽŽŽŽŽ—ž¤¨­«¨¤¦§¨¨¨©ª¬­®®®®¯±³¹È×ÝßàØÐǽ´®®®®®®­¬«¦¡›“‹ˆˆˆš°Ã°Ž‰€wpjekry€‡‹ŒŒŽ‘•™›š˜“‹ƒ{rku…ƒ†‘œœœ›š›œž˜‚‚ƒ„Š••–“މ„z‰ŒŠ‡„‡‹Ž€siijp{‡ˆ…‚†ŠˆtaY^cmy…Œ“—•“‘Žˆ€x†‘–ž¦¦£ ž››£ª¯¯°²´¶¬¡–‹€’¤µÅÖÓÍÆ¼±§ ˜›£«§¢Ÿ§¯³°­ ‹wvwvfUO_n€”©œˆukaYXV^kx„™–’Žˆ‚zodfjo}Š“’‘’’•™››š›œž˜Ž„„…†„ƒ…›£¨­¨¡š„nalw€‡Žš¨¶¬¢˜’Œ“•––•”““’–¤ —Ž’œ¥«­®£“ƒ‘¡­§¡¡¦«¨£žœ¤«®®®®®®«¨¤š‹‹Œ“ž©­°±°®©›†ƒ€zsov|€€€}ytz…|smjgfffb^[]_cmvumen{‡˜›‘ˆƒ€‚ƒ…“¡©¦£¡  ¦¬³µ··´±¬¦Ÿœš—’‹Ž‘—¡ª¯²´œ„sw{zvr~œ™—••”—££¢¢Ÿ™‹}tqnprtwy|‚‰”™˜•’™¡¤›“‘–›žžžž™–”””–˜š…}‡“ž¨±¹ÃÌÕØÛØÐÇÁ¼¸³®©¦£ ž›–ŠŒŠ†zreS@70)% 7a‹š¤« •Š}qjgdgko{†Œ†€‚ˆŽ••–”‡†‰Œ‹Š‰‚{wxzˆŽ‹€tkhegkoz†’𢡇mfr}€€€€€‚„†ˆˆˆˆ— °ÀÆÃÀÂÃÄÉÍÎÉý¶°°²´·¹¹¹¸º¿Ã¶£Œ‹Œ“šŸ¡¢¡Ÿž £¥©®²¶¹·´°°°®¦–“‹ˆ„€}{ƒŠŠtj`WY\]]\WK?ALW]bi𬲏µ®§ž–—Ÿ¡›”–£¢¡¡£¥£š‘‘’“”“Œ‰ˆ†…„„†‡‡†…ƒ€}|||||}‚‚|vw|‰’š“Œ‰‰Š†€y|€„‚‚ˆŠ~su|‚Œ•Ÿ¡ž—‘“–›Ÿ¢¢¢Ÿ˜’Œ†€~}}€ƒ…‡ˆœ¨²¼ÅËÑ×ÝâàÚÔÎȺ²¬©§§©ª¤Ÿ™˜–‘…xoh`dgjjjihfgijnswz}yk]WUTeyŒ­´«¢¡§¬¤œ“Œ„|y}„‹ŒŒ‹†|vpoqrzƒ‹‚xohadnxŠ““”‘ˆ~wsoic][YZbillluŒ‡ƒ…‰‘•“Œ“™Ÿ£§±ÂÔÐź½¿ÂËÔÒÅ·­¥œžœš—”˜¢£¤¥ª®±²²°®¬¤œ˜£®°§Ÿ•‹~€ˆ‘‚tmjfhikmoj\MNW_abdo{|xrlszŠ“–“”œ¥´ÅÒÁ±¤¡Ÿ¢¦©¬­¥–’„vhsƒ‘Šƒ|yusqp‚™­©¥££¤¢ žœ›™Žƒ}~€ƒ‡‹Šˆ‡‰‹‹‰‡‰•—˜˜’ˆ€x}¢¢žšœœš–“‰~ruwwusqonqsvxy}‡’¡¶ÊÔÚà×ÏÉÌÏÎÉÅÈÎÔÄ´§§¨¢–Šƒ~znbY]bb\WZ_d^WT\dkpvobUQNN\jtyƒˆŒ‰†ƒ€}†Ž—¢­¯°¯¥œ“Œ…~†–†vow{nbm}›©­Ÿ†~wlaW]bjtˆ“’‘“–ž¥«±·¶´±®ª¨¨¨°¾ÍÎÍÌÑÕÙÜßÖ¯¦¢ž§°µ²¯«¦¡™†ˆ‰Œ”œ¥®¸³«¢Ÿœ™”ŽŽŽ‹‡„ƒ‚€vme_YXXXZ[]`c`XPYiysli{•Žˆukhghq{‚„Š”œ™–Ž…ƒ†Š”–—™œŸ¢¤§¬³¹ÂÌÒŸ«œŽˆˆˆ†„ƒ…‡‹”™Ž„…ˆ‰ˆ‡ˆŒ‘“””š¢§š†“’‡ŠŽ‘Šƒ}}|„‰‘™¡©²¹¼¿»²ªŸ”ŠŠŠ‹“’އ~vy|€†˜¨¸´ª ¬·ÃÍ×ÚÕÑÎÍÌÉÆÃ¿¼¶¯¨¤¢ •‰zvpibZQHS_jqxzvslcZ\]]\ZZZZ]bfs‚ŽŽ’”—𛕉„~zxvy|‡••–•””—šš€wtqsw|zxtfWQYahou{‡‹‘Œ—Ÿ ¡¨¯³±¯©¡™—–—™››š˜šœžœ›™—•’“œ¤©­°¯®«¢˜•––™œž³ÈÕɾ´­¦­¸Äº±¥yz“­°«¦•˜ Ÿ”‰„‚€†ŒŽ‰}quŠŽ““…vpsu}‡‘ˆ†š£«²°ª¤¨«¯±³·¿ÆÃ½¶«ž•–˜•…„‡Šƒ{uwy~‰”Žpf\SRPS\eoz…‡ˆ‰Œ“¦¨¥¢˜Œ„£ÃÓŶ¤z}†„|€¡¢¡“†{ywuttrqojea_]akt€š—””˜œªÂÚÙÐÈÿ»»º¶®¦©®´±¯¬¤œ“‰{zzodZTMQ_ni]PLHHR[ciomifmt{€…ˆˆˆ˜¢«´½ÃÉǺ®¨¦¤¢ŸŸ¥«ªŸ•‰|oy„™¢¢•‡€~|~xpq}‰’”’“˜œ ¥ ——¤±´·µ­¥¢¢¢¨°µ³±®¨¢¥®·µ±­¦Ÿ§°³±°­ª§œ‡ƒ€„ˆ—˜“Žˆ‚ƒ‰“–˜ˆ…™žžž–Œ‚~zxxxsj`gt€vmbTEI_vzxvj_W]bitƒ…†}snw…ˆŠ†€z~ƒ‰–£¬¯±±¯®ª¥£©¯¯ª¥ž•ŒŽ‘•¥¶¶›~ˆ‘¡²½ª–†}srux‹“‘“¡¯®¤›–“‘–›œ˜““•–›¡¥¥¤¢Ÿ›œŸ¢£¤¥¨¬®®®¬©¦ š“ŽŽ‘•†|†”¡™˜œ §±ºÂÉÏĸ²ºÁÆÉÌÆ¾¶³°­­¬¨¡™œ ¤—yf[YXVTRQPL=.*188761-,17@MZbglmnotz€‡ŽŽŽ‹ˆ……„…‡ˆ„zvsr}ˆŠ‚zsmflsy…„zqrx~re\dmxˆ˜Ÿ  š“”™ ©³²­¨¦¥¥°ºÀÀÀ½¹´¼ÄÌÌÌËÈÅÅÇÈÍÓ×ÔÒÍÆ¿¼¼¼¹µ³¶¸·¬¢š“• «³»º§•ŒŒŒ‘—›•އww{}zxyzzzzukbbdfnuyvsme\ZZZgt„ˆ…{qx…’€ncnx€ƒ†Š–›Ÿ¡¡ ¤«²¶¹¼º·´¨œ—™š ©²¤–ˆ€xy…‘Œˆ{ma_]]_`fpy€‡”š™Ž‚Œ£¹¨{zxz}†““’‘‘„{rg]cksvzztnie`dhmv€…„‚…‰Ž‡y‹œª±·ººº¹¸¹ÓíûðåßÝÜÔÊ¿»·³±¯«¦¡Ÿžž¤©¨š„€||||€„…}{zzupjot{‡”¤«©§¤ž˜“ˆ‹”žœ—’•˜™—•—œ¡–†unhfr~‚}yqh^[XUQNOV\ciph_[p„ŽŠ‡‡ˆˆzv…“š—“’’’“”–¥³¸°§¨­²·¼¿ºµ±±°¯®®¯°°°°­§ žžž¡¥§£Ÿš—“Œˆ‘œ¥–†Š”–”’•™›…}}|uj^o‡’†}zwtplyŠš˜—–––“‡„‚€ƒ…‡‰‹‰…ƒ…ˆ‘–œ¡¦ª­ª¥ Ÿž ©²½ÊØÌ´–¡²¹´¯£“ƒ‡ŒŽŠ‡Š”“’“˜œ ¤§¥¢ž˜“—ž£¥¦¡›”—𣩍’–¡­®®¬ ”‹‰†„~|{yyx{‚‰‹ŠŠŒ•› ¤©«­®±µ·°©¥¥¦«³»´«¡˜ˆ…}xslfaeijd^TG9CTc^XQF;79:BLV^elsy}€‚„†‰Œ‹‰‡…„ƒ‚‚…ˆŒ’—ž¦®¢|ywx‚‹’—›‘‚sw{€‡ŽŒrqux‹‘‘’•˜¢±¿¼¹·¼ÁÇÍÒÏÈÀ½º¹¼¿¾¸³µ¸¼ÀÅÇÄÁÂÆËËÉÈ»µ²¯¯¯°®¬ª¢™”¡®³ª¡ £¦Ÿ—‹†zst{‹•—‹‹Šƒvjkoqpoqywof[S[cku€~shdbafkpw}ƒ‡‹„zpsvwvtqmimsx‚–¥¦£ ¤¨¬¨¤¡Ÿžž¡£¦”t‰‹†|wruwy}€‰—¦¢–Š‘˜š——˜˜ž§°©¢›—”“””Š„ˆ‘•šš—•”””‰|qomkifo}‹Š‡‡ˆŠŸ®±®ª®³µµ´¹ÈÖÚ×ÔÛâçäáßÜÙÓÌž¶¯¤™‘‘‹ƒ{xwuutxƒŒvcN:::B^y„‚€|ws€”Œ‡{unhv„’”˜œžž•Œ…‚zrjfedgjkkje[QMLLORTTTTTT\fpuz€ˆ™¢«©£œ—“Œ‰Žœª®®®¬«««¬¯·¾ÀÀÀ¶¬£ ž£§¥ œžŸŸ ¡£¦¢œ–ˆyn“›˜šœžš—•šŸ£¤¦§©ª£œ•”’’’’Œˆ‰Š‹“™¡©¢}pe[dlu|ƒ‚}wy}‰‘•’‰€x~ˆ“¥·ÇÑÛáãäÚÍÀÆÌÏÌɾ©•˜¢¬£š”””‘‰ˆˆˆ„€|wrrw{ƒ†‡ˆ‹—¤¨¥¢ Ÿžœ›—‡wtŽ”–˜Š|rz‚ˆ‘‹ˆzl_][\aeecbo}‰‹‡‡‰Š„}{“«»»¼¸³®°³µµ¶»É×Ò²¡‘ƒ„†ƒ|unhcjt}~€„‡vl^PER_ks{ztou~‡ŠŒŒˆ„|rhjpu|ƒŒ—£®¸Âº®£§«®®®£wx€ˆ}rmu~ƒ…†‚}xyzxqikt~…Œ’•—›¦±¸¼¿½»¸µ³°«¥ª»ËÕÚàÓŹ¸¶ºÂÊÑÙàÞÝÙÈ·«¥Ÿœ™–—˜š¨µ¹´¯¬©¦•ƒsolp€‰‚~{wwv{†’™œ ˜‡…ƒ€yoeddccbdinoml^M?FLRUY`jupjekrx{|uoidabchs}ˆ’œ¦±¹´®«¯³³±°¨Ÿ—¤²¸­¡˜‘‰ˆˆˆ‘•—™”‰~yurtux}‚Š•Ÿ©±º¹¸¸¸¸´«¢¦­´¹½½²¨¡  ¡¢¢š’Ž‘’’‰}pliglp{‘§­«ª®³´©žœ¦¯¿ÓæáÚÓËÄÀÀÀÇÑÛÚÙÖËÀ¶¬¡š”Žˆ{xuuvx‹—‡s`O=9L_ecbgmsvy{~€€vj_YTQSV`rƒ‰Œˆ……„€xqv|ƒ‡‹‰xhbdfa[Wakof\UPKLNPPPTcs™—‘Œ–¡©©ª§¡›¡«´°¬««¬¯´¹ººººº»¿ÂÁ¼·¬Ÿ’•—™  ›—œ¤¬Ž{uy‰™žžžš•‘’𦱵¸¹¸¶´®©¢™‘Ž‹‹”§­²¶¦”…‹‘’ˆ‚{u{‚‰‹Š€vu{€}zwsnou|‹¢¸ÅÏ×ÎÆÁÄÇ¿°¡ª·ÅÆÇÁ¬—Œˆ„‡Š“šœ•…zne]WWXZ^bm~އ‚’¡¨œˆ…‚¡²£•‰ˆ†Œ˜£¤¢ ”‰‚„|wpib]YYdpwxx‡‹‰…‚‡–¦¬®°§˜ ¨©¤Ÿ¨µÃ¿º¶¶¶±¤˜Œ‚wj]SSTV[_djpbRC>9:CMTZ`ir|…Ž’ˆ‰’’’…ytz€ˆ“±ÈÚʹ²½È±¡£¨­½ÍÒ±£™Ž“›¡—„€|zzzxvuwy}…–¡¬°±³¹ÀÅÆÈ¶ª¬°´±¯«Ÿ“–¤³´³²§œ““’Šˆ‡†‡ˆ†|}ƒ‰’›¥«¨¥ ™’”™ž™”‘‘’”—š“ˆ~~~€Œ˜¡§­ª¤ž–„{sptwz}€„‰‰yiabbgnvvvw‡‰ƒ|wrnpqqlgb^YZ\^jx…•™—”𥝢‘~{†ªÍ̱–Œ†„†…}u{‰˜•‹‚xqomqyˆŽ•˜œ¡ª²´±®¨¢®ÀÉÁ¸²¯¬°µº½¿¾¸²¯®®£–ˆ‘““’Œ‰Œ”—™›Ÿ£¡›•Ÿ­¼ÂÈÊÅ¿¾ÁÄÂÁÀÀÀÁÂÄÄÄÄÅÇÈÁº±¥™Ž†~|||††q\MF@DMVNEBXozuqjbZYXYZ\ZWSUX\cksy€~€€zsmf^dž§¡œ|mv~kYYepmhc`\[\^\ZXdqˆ˜¢¦©¬¨¤¡¬¸ÁÄÇù°²¶¹¸·µ²¯®®®ª¦¢ª±·»¿½·±«¤žš–•˜›–‹‚‡Œ–¡¦ž–”—šœž–ŽŠ‘˜ž¢¥¬´¼¾¿¿º¶³±°¬§¢¥¨§›†}…‘žžŸ¥«¨›Ž…~vutuwyvlcekr€¥­±°®¯°°°°¯«¨¬½ÎÖÙÜе²¯¨–…{xtsrqkea^[WTP]l{ˆŠ‡ƒ…‰Žˆ‚}…‹’™•Š~||}~~xrlga]ZY]agr}…ŠŒˆ„~xv~…„}uzˆ–¤«¡—–¤¬³º´®¨¢›œ¤¬°±²´µ¶¶¶·¹º¶²®®®¬§¡™…€~|zy{ˆ•Ÿ ™„}vqv{zrjknrw|ƒ“£¨ž•Œ„|€…†wiftƒ‘ž«§¢œ™”Žq`chmsyyqidb`gow‚““ž¨¤ž˜˜˜š¡¥©®¯°±³µ·¹»½¿À¸¯¥ š—𢧭¯°¯¡”‰‡…„„„‡ŠŒŽ‘“•—˜ƒx}ypmopu{€€€zvw{„ˆŒ‰‡„~wrnkgebdehov}„Š‹ŠŠƒ}xxxuoigedlu ¨¤¡˜Œ†‘Ž’•¡²ÂÓâïìéäÚÏÍÏÐô©¯µº¼¿´¡ŽŠ‰‰Œ“”–—™šœž¡¡¢ š”œ­½½º·´²°°°ª –””“€m``````fmuuvtpljjjgdchnv…“Ÿ¨°¬¥ŸŸ ž–Ž‘•§¾Ô˹­¢žž¥®¶³°¬¦¡œ˜•ŒvmdcyŽ£©¥ š‘‡{xuttog`gmt}…Œ“‹~quz}wqlgchqz‹­²·³£“’—œƒhQUZ_elic\[Z\fpx{‚…ˆŠ‘“’‹•¦¸¼¾¿´©¥«²°ª¥®ºÃ´¦ž£«³ºÂÉÏÔѺ¤¡¦›‚…Ž–¢°½¸¯¥¡˜”‹†‰”ŸŸ ž™””—š¡«´µ¶µµ´¯¦œ“‰€p`\|°³¶¨”€}zvmdep{ui\fp{…—™š”Œ„„„ƒ|xsozŠ›°ÆÙÜßÚ˽·µ´ªŸ——˜”Š~~~zusz€†‹‘Šˆ‡†††‡ˆŠŽ”𣭴ªŸ™šœ˜’Œ‰†ƒ~ytpkmrx~„‹–¡¥œ“– ª£˜„zv{€¥¼¼¶±© ™—••—˜—–—›Ÿ£¦©¦ ™šœŸŸ ¡¤§§¦¦¢žšŠzosw}…މv{wmjnqstty~…“¡¦£ œ—’ˆ…ˆ‹ˆvrpny…•›žžžœ™–•”’‰q[EFP[cjr{…ˆƒ†‘¤©¬¤›’‰{zz…™““š §®®®­«©¦£Ÿžžž¥¬³³´³±®¬©¦¤£ ‘vvv“¥ª¬­¤š“Ž‘”“’‘†{uvx{€…Š““’•ž¨¯´¹¯ ‘‚silov‚ŽŒŠ‹Œ‹Šˆ…}zyx…‹Ž‘—¡¬«§¤šŠ‘˜™’Œ†‚~‹˜¤ª±³²²±¯®¬«©¨¦ “†zv}„Œ•Ÿ£ žš”Ž’—™•‰|pqx€“¨¸ªœ““’І…„ƒ}wrokhebfimptx|„‡Š‹ŒŠ|megjvŠŸ Ÿš–’Œ†‡‹— § ™””””””•–•“”˜¡¬¸°¤—‹y‚Š‘—”ˆ|||||||||€…Š“—›Ÿžš––––„ƒ‡ƒzpf[P_n~Ÿ¤›’—Ÿ¨¤ ˜”‰vdWNDQ^js{‚‚…‰Œ–¡©¨¦ ’„€€€Ž¨œ‘“˜ ¤­¸¿¸²«¦  £¦¬±µ²¯¯±´µ·¸¶µ±šƒrnivŒ£¨ª«¢™””””””””“Š‚{{z}€„†ˆ‰†‚~Š ¶®žzeX_er„–’‡}|{xrllptttsqopv|†‹•š—””™žŸžž•ˆ|‚ˆ¡²¹¸¸¼ÀÄÂÁ¾¸±¬©¦’†“›¦²¶²¯¬©¦¢Ÿž šŽ‚zup}‹—™›™”‘’–›™”Ž„{rjbjs{|~ˆŒˆ™ž‘„xndk|Ž˜¡§Ÿ—”—›ž¡¤Ÿš•“‘ŽŠ…‰‘™ ¨®®®«¥žŸ¢¦©¬­›Š|vpqv{voit‡‡ˆ‰‹Œ’•—™˜“ŽŽ’–™œ›™–‰…„„}sjfbbiotx|€„ˆ’¡˜„xmbWLGBBTfqst{ƒŒŽ’™ ¢ž›‚uy~ƒˆŽ‡ƒ‡Š—››š—’‰†‚‡Œ’š£ª­¯¯®®³¸º°¦™‰xz…‘œ§¯¨¢ŸŸ ¥­µ­¤¡¦¤šŒŒŒ—¤¯¬©§¥¢¢¢¢¦ª­§¢›’‰ˆŠŒ‰†ƒ€„‰‘–˜š›•І‚‰˜§¨¦¤¤¤¢š““˜—Ž…znjw„“™ ¢«´·­£›•ŒŒ†€€ ¦¢Ÿ¢¦ª¡˜‹…|oa\[Z]_ez–Š}€ˆ“•”Šytoje`bcfmtz~…ˆŒŠ‰†xja_^guƒ”§µ±¬¬±·ÁÎÛξ±²´® ‘ˆƒ~•°ÇÁ»¹º¼µªŸ¡¤¥ž˜’ˆ†††•››š£ª­¯°«¦¡™”Žˆ˜¤©¬®®®¨“}~¡u]_bb^Zar‚††‡‘›Ÿ—Ž‚rb_``ZUT\djmpv~†ˆ‰‰‰ˆ†‚}||wrr†š¡œ—¥®³·¹´°ª¡˜”‘Ž“˜›˜••––›¡¨«®®¦ž•Šxrlrx~Š•ž¤©©§¦ª­®¥›˜š˜Ž…xj`ku}~€ƒ†Š{i[^a`]Y[^ba`akv}~€‡’žž”Œ…‚~~~ƒ‰•œ£ª±°¨¡ªµ¿«˜Œ”˜›ž§²»º¹¼ËÙÞ󯃵£©°³±¯²¸¿ÆÍÔÒÑÏÎÌǾ´¬¥ž˜’Ї‰•”“’•˜›ž¡ž–Ž…}tokf`YWZ\^`bqŒ„|z~wgW^fnw‡‰Š‰‡†˜   ž™•’Ž…zsuwyyzŒ—‘Šƒ|vqolrzƒxk_\XSJAQp›¢§œ‘‰ˆ†‰’‘‹‹‘’’—¡œ—€pihhfec]XYhw„Ž˜Šwc\URX^acdn{‰—ž¤ªª¨¦§¨¨¤ œš™˜˜–”’–šž§°²¯¬¨£žŸ    ¢¦©­±´ÄÔààààààδ™›ž£²ÀÅÀ»³©ž§±¹¹º¸³¯¬©¦ž–‰ƒƒ‰Ž–ž¦¤¡Ÿ™“މƒ…ˆŒƒyndZSRPd„¤¨¨¥Œtc`]]_`bdgmszƒŒ–Ÿ©¬­­§ —ˆzvxz|~ukgpyƒŽš•…‚~}}~|zx|‚‡•¢­±µ²«£—‘‰ztnkihknpkggs~…††€xpkea]YXXX^elquwvtvy|sgZWUXlŒ’Žˆ‚‘¡°¸ÀÄÄÄÁ¼¸®¤›™—𤭼ÍßÚÔÎÆ¾¹¸¸³­¦¢Ÿ›™—••”𣫵¿Ç½»½À¿½¼¹¶²§›š¬½ÅÇȼµ¯©¡‘‚zwtx|rf__`gs~}yuj_VPJFB>CHM_q}|zsfXZ^aa`^YTTX\XSMKHIT_howrjbcdefhjnryƒŒ—¢ªªª¬®°¨ž”‹‚Œ™ž›˜–•”–—›¨µ»ºº·³°¯®«ž‘ŠŠŠ˜«¿·­¥¢ŸŸ¡¢¤§ª¨§¥¢Ÿœ™—¡²ÃÈÍÎÁ´¤{oibfikjhn~Ž—šžœ››¢¨ª§£š€‹š§”’¨©¦¢¨®³­§¢œ–—› ž ¢¦«°µº¿½º¹¹º·­¤ž›˜”Ž‹”ž£¢ Ÿžž£©­ “‡}soqrpnlquy}…‰‘•˜‹~qg]\dlrvzxwuut{Š˜žž—ˆzsnifc`lx€yrlgcir|yvv€Š…~{yx€ˆ‘“’Ž‹„|tx{ƒ†Œ”¨³¿¹±ªªª«­°¤|zz{‡‰‰ˆ„~xz}€‘¡© —ˆ‚ƒƒ}ww~…ž¬¬««¬­¬¨£ žœš™—”’’•™™—–›¡¥¡—ކƒ„„†ˆ‹”š Ÿ›— ­º²«¡|‰•—––™››˜•—œ¡§®´«¢š•Œ‰†‚}x‡Š‚zwyz}‚†ƒ€€‹–’|e`cfr~Š‘˜š•‘…ue`]YXV[fq{…‰‚}~€…‘žœ’‰Š‹‘““”‰‚†‹’–˜˜˜šœž£©­¡•˜¥²²±±´·¶°ª£œ•””““’“•˜”‡‡ˆ‡…ƒ€{vsqprtwwxy{}~~~…Ž•‹…|rs|„…„„‘¥¤¢¨µÁÄÄĽ·±±°±³´¯ª¤£¢££¤¥¨ª­¯²¹¿ÄÄĽ®žœŸ¢¦ª­®°­§¡›“ŒŽ–¥±¼¼¶°¨Ÿ—”‘”œ¤ž’‡xstvvvvsnjhggikjheca`bcc_ZVTQYfttstƒ’™’‹‚wmf`\kz‚{vpkihipw~„Ї~uwz}€‚†‹‘—Ÿ¦¦¦¢—‹ˆ‹Ž‘“—›™•™¢ª±·¼º¹µ¬¢Ÿ¡¢–‹‡…ˆ‹‹ŠŠ˜ ¤¨«°´µ³²ªŸ”Šˆ“¥«±³´´©ž•ŠŠš¨µ®¥›‹{x„—œ –‹ƒ‡Œ–›š—”˜›Ÿ¥«­«¨§¦¦ª­¯ª¥ ›–“’’”•—ž¤©«®¨ —ˆ~{{{|…І‚}umku~}voopoidbgllhdfhkry|wrkc[]`cdehnty~ƒˆŒ‘˜Ÿ£¡Ÿœ˜”“’’‰„}ww}ƒ‚€‘¢­­¬ª¦£Ÿ›˜“ŽŒ“›œ™–”“’‹ˆ…‡Ž”Ÿ­º·µ²¬¥ š£¯»´¬¥¢Ÿœ˜•‘ŒˆŠ‹‘‹‡„‚€‚ƒ…‡†{wtpty}„Š‘–œ ¢¤Ÿš•’ŽŒŒŒ’œ¥¤¡žŽ~v|‚…††š£›“’‘Ž“™ŸŸ ¡¢¤ž”ЉЋ’–𠍝°°±¶¼¿½»¸´°«¤–†zno{‡„}v„’žœ˜””””†xpv{‚‰‡whmqssrxƒŽŒ‡‚}yvsrrv|‚|{€„„€}}€ˆ‘𡍩¡š•ŒŒŒŽ™¤¨¥£ š”Œš¨¯­ª®³¸³®©¥¢Ÿžœž ¢©±¶¬¢š•‹ŠŒƒzrmheddlt}€„‰–oosutstw{„’ ¦ª­ª¦§®µ¹»¼¹¶³±®§˜‰…Š’”—›Ÿ¡¡ ¡¢¢¢¢¢˜‡‡†‰‘‘‰ƒƒ…††ž¬§£Ÿœ™™›œžž›™–‘‹ŠŽ‘Štld_begjlhc^dkojehu‚yrh]Wfu~~~|yvxy{ƒŠ’…}xsqqrpnklorw}ƒŒ•˜–“Œˆˆˆ‰ŒŠ‡„€}zzŒž§ž•ŽŒš«¹µ±¯°²µº¿¼¸µ·¹µ§˜Ž‰ƒ†Œ‘–œ   ¢¥¨®µ»¹¶°¤˜”˜œ›šš—”‘‡v‡ º±¨ ˜‰…ƒ…ˆŒ‘Ž’•šž¢™‘Œ“š¢ª²®¦ž™•‘‘“š Ÿš–•””””™¥°³±°¡‘…Œ“˜¡ šŽx€ˆ‹ˆ†‚|vx{{vqoprme]^acfjou|}{zskemu|€…shxŽ¡œ—‘‹„†Œ‘“”•§¸½¦…ƒ‚€~}Š—ž™”އˆ‘›¢©«£›˜˜˜Ÿ§­ “‰ˆ†„‚€ŽŸ°±²°¬¨¨ª¬®¯°³µ´®§§«¯µºÀ¶­£—ŠŒ­¬¥ž”Š~{{}~€€|xwy{Š“—˜˜Œ~u{ˆ‘™›šš‰wjs}~vi]bgmmnpv{wqjnquvxyyzxvtpkipx†ŽŒ†€Š–¡­¹¾ºµ°©£ ŸŸ¬¸¾¸²©’Љ‘™ ¥ª¥˜Œ‘™¡§¬®ª¦Ÿ–“›¡œ–Žqihhnu}‰•ŸŸ ž›˜”ŒŒŒ‹‡ƒ…Š“–˜•“‰ˆœ±³±®}{|‚ˆ˜•““—šž£§§¥¤¢¡   £¨­®®®¥›•˜›Ÿ œ–Ž‹Šˆ†ƒyncdegikmnnpsvxy{ƒ‹Ž‰ƒ}vomlny…•œ›šœŸª´»»¼µªŸœž¥¸Ìʸ§§«¯²´·¸º° ŒŒ””Š„yvuu…•¢§¬­«ªªªªªª©©¨©ªª¨¦¤–„yqlglszm`USQMHCIS\UMIJLScrxyzƒ“‘‘–››™˜—–•‘ŽŽ’•‘‹„€{xxxz}}yvzƒˆ‘’’‘ŽŠ…ƒŠ–™›•‹†‹’¨´ÁÏ˽¯­¬­°´¸½ÂÀ¹³®«©©ª­µ½»´­©¥¡ žœ—’ˆ‚|vq~‹“Ї„xi]hs}†Ž”˜œš˜••””””–™œž˜“‹‡ˆŠŒ”ž¨¢—†ƒ„„‰”Œ‹Ž‘”˜›žžžžžžžŸ¡¢Ÿ›˜”’‘–ž¦•‹‰„}vog`abccdb^[YWVVVXaksy~€€€xpkklx•²¸²¬¢—’•¥¢™‘’•–––˜›Ÿ¢¤¦¤¡Ÿœ™šŸ¤¨«®¨ › ¥¨¨¨©«¬¥•ˆ†‹±ÄÈÈǾ´°µº»¹¸»¾¿»·³°­¨¢›ž¢¦¦¦¢“…|xtsrrlfaa````cfhnt{…Šƒ~ytsrsw{}€‹šª˜†wqljjjgb^[YZdmpkgghhgfgjmpsvx{~}|}¨ÃËÉÈ»­£ª°¸ÁÉź¯®®­§¡ £§ª¬®®®­«©¦¡œ›ž™”‘’”•—š—”Š‡~uoonxŠ›œ›•ŽŒ“‹…‹”›˜–— ¨¦”“”•£°¶©œ—™š¡©¯®­«¨¥¥¦¦£ŸœœœŸ§°¶¹¼¹µ²°¯¬¦¡œš˜¢¯¼°¥ ££¢¢–‚sjouxxxqf\\\[XUW^dghhjmle^aq‹‘˜’Œ‰‹’›£¡›”‘Ž‹ŠˆˆˆˆŒ‘–‘Œ‡ƒ€}}|„š—“–žŸžž ¡¡š’‹ˆ•£©­ª¦¥¦¨¥¡œŸ£§ª¬°µºµ¨œ“Šƒ¢”†~{x{~„ˆˆ„€}||zyy~ƒˆ—œ ¤¢¡ œ˜•”’‰ƒ‡’‰€xsnmopmkheccfimt{|||‚ˆŠ€wty}|zxƒ–Œ„‰•¤³­§¡›••šŸ¤©®ª¥¡ ž¡¦«µÂÏÍÊÉÏÕÑÁ±®°²­¨¢’‚y{~‚ˆŽ“˜›“‹‚yorzƒ‰“Œ‹Œ‰†…ˆ‹“’Œ€sglqv|‚|w{€…Д𠢢¢—‘Œ–ž š¡ª±¦š“•—–”’•˜š¢©¬§¢˜“މƒ~|}~~|zx€‡Š„}{}~~~~ ¬£š’Š‚…”˜œ˜’ŽŽ“›¢¡ ž—Ž“—› ¤¢¡Ÿš–’Ž‹Ž”šœœŽ€yzz}‚†Š‘І„‚…ˆ’••”•–˜œ£©¦¡Ÿ¢¥¨«¯­§¢•‡yxvx~„‡ˆˆƒ~yxwwz}xoegjkighmrw{€‰”“‰ƒƒ„€zspnmy…Œ„}wqklmnswxsnkjjjjjklmoqqonoppzƒ‰‰ˆ‡„‚‰“œ¥­³±¯ª£œ¡¬¶¶¶³§›š¨¶½ÁÄ»±©¨¦¨¬¯±²²¯¬¨›‡††Œ•žœ›•ˆwtttŠ•–˜—–”‰‚‰•”’”–™™˜˜‹{nnnr|†“˜š›ž¡©±±®ª¦¢™•‰ŠŽ’“”•œ£©«­¨’ˆ}u„“›™“Š‚‚€}tjeddba`]ZY[]`cfc`^fmsuwuqmosv}ƒ‡…ƒ€€ˆ“ž£¨©œŒ”œ£¨®¦ž——––––žª¶¹»º°§ ›—žªµ´±¯«¨¨¬¯­¨¤©®³´¶µ²°­ª¦¬±·¼ÁÁ»´±°°¤—‹„~~‡‘“’’ˆƒ€€€€xpga[YYZbo|€‚…Š”™žœ•‘•——–”‡w`IKT]kzxppu{xtolhhnttrprtvpkjrz€€ƒ†ˆ•™•‘ŽŠ‡Š”—šš•’”š¢ªªª©©¨¤–¨´¹½¾·°¦˜ŠˆŠŒ•¡•‰„‡Š„{rqpsƒ“™’Œˆ…‚€€Š”™˜˜–“Œ‡ƒ‚€‚‡’˜ž£¨­²·ººº¾ÃÈþ¹´¯©¡™•“’•˜›ž¡¥«²±®ª§£¡¡¢¡¡ žœššš› ¥¦£Ÿ›–‘Œ†xniloomlw…‘‹„‚„|w}†ŽŒŠ‚zsokq{„‰Ž‰„€|y{‚€}{ywtryƒŒ“™›™•‹‡ƒ€†Œ’˜Ÿ¡žœ™”‰‚~ˆ‘™ž£œ‘‡Š‘”—›¢¨«­®¨¡›•”™žœ›› ¥©«®©¡™“‡xph_[ZZbksx}…‘Ÿ™”–˜™–“‘Œ‡€yvtsvxzzz{||}~}umiijihhknoonptx{}~„Š‘—ž¢¢¢ š¢«´¼Ãż²¬ª¨ª«¬µ¾ÃÀ½º·´¹¾ÄÂÁÀÀÀ¾»¸²ª¢™˜ž¥©¬®¤—Š~rjouŸ›‚‡‹Œvs{‚€{vwxwsportvy|‚‡‘–™œž›˜”‰‰ˆ‡…‚|xvuu{†ˆ‹‰…€„‰‹Šˆ‰ŒŽŽ‘”—šœ–ŒŠˆ…}pdZWSUY^aeijkntz~€‚€„ˆ‹‹Œ”™Ÿ¤ª­©¥ ™‘‰†‹“—›š—”–—˜“Ž•£©¯¯®®«¨§¨ª®´»º¸¶­¤œ ¢§¬²°¯¬¥ž›ž–‹€‹•Ÿ ¢¡Ÿžœ™–—˜š¢ª¬©§ ˜‹†}zunhda^^^_diotz‚Œ•—˜—•“‘Œ„xkjjkrz{righhmswsnjfacglhd``````enwyzyyxz}†“š¡§¢ššš™˜˜”‹–œ¤««¥Ÿ¢§¬¤œš¦²¶²®¬«ª£˜˜˜§²±­ªœŽƒ~z|ƒŠ‘”Œ‰†ƒ„‡Š‡…‚‡Œ’œ¥§¢š—”˜›¡¯¼ÈÏÖʵŸ¡¤§«®­¦ žžžœ™—–”•—˜š ¢¥¥ ›™™š˜–”𡦦¦£›“ŽŽŽŽ‰{mmu}{xutrqqptz‚„…zurooqrx€‡ˆ‰ˆƒ~|||}~}|{|„‹ŽŽŽŒŠ‡€yx…’“‹ƒ‚‚‚~zwsos~ˆ—ž˜’Ї‡‰Š‘𢍮±°®©¡˜•””•–˜¢¦ª­©¤žœž©³¾ËØÒõ¥•‰“–˜Œyglrusqqrrux|„“’Ž‹‰†ƒ€„‡‹Ž‘Œ‡„~|{{€…†‚}zxvtsqkeaa`acdmw~}}||||†’¦®±©¡›˜”—š ¢¥¦¨®¸ÂÁ½¹±¨£¥§ª®²¬¥™•‘Ž‘—¦¯¸´°¬¥Ÿ—Œ‚‚„†“šŸ¤ •‹†…„†‡‰ŠŒŒˆ„ƒ‚ƒ†‰˜¢¢ žš–“‘“œ¥¥ œ—’’•“‡ƒ|xsrz‚vkjlnruxxxwutrpnnnmmllllmoptw{}~|zx‚•Žˆ…ˆ‹ŽŽ“˜¤¬°°°±³´²°®®®®®®°²´¸¼¿¹´­¥¡¦¨ª«§£¡¡¢¤¦¨¯¸ÁÃÆÈÈÈû³´¶¸¶µ³±¯°²´ªŠ„‚„ˆ–Œ}nqtx‡Ž•œ¡£¦¡œ—’ŽŠ…‚‚}xtttvz}yqjklo€‘“„uppptw{{|zvsolhhhgdaabbcddfgikmlga_]\afigecb`cglnqsy„‡‹ŽŽŠ†zrr{„‰‹Œ”ž§©«ª¦¡£§¬©¦¥¥¦§ª­¯°°³¶¹½ÁÃÀ½·®¦Ÿ™“Œ‰‰ˆ–žžœš™˜š¢©±ºÂ¾¶®«©ª°µ¼ÃÊÐÔØÏÆ¿¾¼º¸¶³±®®®­¬ª«¬¬¨¤ œ˜”‰ˆŒŒ‹ŠŒ’™žž™“ŒŠ‡…‚{slkllnqstvx|zpgghijlmmnoppsvyz|{{z|~€‚……~xspmorvutv„“š”Ž‰„~ukcjqtqmnqty~€ƒŽ˜ ¥«¨¢—‹‰‡‡ˆˆ—Ÿ ¡¡¡ ¢¤¦¨ª¬¤œ•‘˜ «µÀ½»¹·µ²¯¬¥œ”‡ƒ†‰Œ’“””•–—šš˜–•”•–—›žŸžžœš˜”‘ŒŒŒŒ‹‰ˆƒ~{{|}€‚€€‚ƒƒ}wvz}€€…ŠŽŽŽ“–š §«©§¢š‘‘’—£¦©«­°­§¢ž›—Ž…„–™˜˜•‘Œ“–™œ–‰|oc\UTWZ`fmptwwxz}€…‹Œ‰ŠŒŽ‘“š¢ª®²°©¡žœš’‹‡‰‹–š–’—›˜”‘Žš¤ª¤›ž£ª°«§¢—’ŒŠ‡„€€€€€€€‚ƒ‚|uv€‰‡z„‰‰Šˆ…ƒˆ˜ §­¬ª¨¤Ÿ›˜”™ž£§¬¯°²¯¬¨¢›•Š€}…’”–”““•—™›ž¡¦¬¯²µ¹½¼¯£žžž ¢¥¨¬­­¬¨£˜”‘’“‘‰{vqrtw€Š“¨©¥¡™‘‰ƒ|wusqppmjhjkkjhc[RLHDUgrkc_^^aehpx}yvrolnpromkkjknpqstpmiebbehlqv{€……†ƒ~yy{|‹œ«¬®¬§££¤¤¨­±µº¿ÄÊÎÑÔÒÑÎù±°®±µº¼¿¿»¶¶¼ÂÇËÐÈÀ·¯§Ÿ˜‘Šƒ}yuszŠ—£¤ž™•‘•œ¢¨®¬§¡œ˜““’•¥¬±·µ±­§ ›—“Œˆ†…ƒ‚€€€}yusrrrru‚Ž‘‰‚{t~‡’•’‹„„†ˆŠ‹‹†‚~{x|€„ƒ‚‚‚‚€|yy{|…ˆˆˆ…yz|~†—š›š—’މ„…ˆ•œžžžœš‘‡€~{xƒŽ—Š…ƒ€…Œ“—š›š˜—–”“‘‹……Šš¤§¥¤ œ—•“–£¯°©£—““”˜£­·¿Çý·³¯ª¦¢ž›˜—––––—˜š—’Šˆ……„†“”‘Ž‹ˆ†Œ’—˜š–‰‡††††„ztnghijhgeca_^^`abiquqnjea```gmsvy|€ƒ†‰ŒŠ‡‡‹Ž”ž§­²¶³°­§¡š˜•ŒŽ’œ¦ª§£¡  Ÿžœš—‘Š…|wqkkjmu}…Œ“””“މДž¥©®¦ž•’ŽŽ”𣭏¶²­§¢›™–“ŽŒ‹“—šžžž›˜–––•”’”—š ¡ ŸŸŸ žœš–’ŽŒŠ‚ztpljihs~…€|}…†††‹’’’‘ŽŠ†‚‰•™œš˜™šš›œ››š¢§¬²¸°§Ÿžœš–“Œˆzvƒ—•”–™œ˜“Œ‰‰ŠŒ‹ŠŠˆ……ˆ‹Ž“˜¡¬·²«¥ž–‘Ž“–’މƒ}{~‰• ¢¢¢¢¢ ›–’Œ„zsw{ˆŽ‰ƒŠ“›‘‡~xrty~|zzz|ƒ‰ŒŒŒŠˆ‡‡ˆ‰ŠŒ‰„|{zwtty~}xsokhknqtw|‚‰ˆ†„}}|„‰ŠŠŠŽ’“ˆ‡ˆˆŒ‘–¡­µ±®ª§¤¥¦¦§¨§§¦¤¡Ÿª¼ÏÌÇ»´¬¢™•””Š…‚{unorvƒ’Ÿ ¢ ™™›œ¡¦«®±±°®­«ª¨¦¤¤¤¥§ª§£ž™“‡‚€…Ž—•‘”™š”Žˆƒ}zywqjl€“™•‰…‚~}€~|zxvvvwy{}~~|zx{~…‰ŒŽŽŒŠ‰ˆ‡‡†‡‰Š‰ˆˆŒ‰‚€€‡˜¡©¯®¬¨ ˜—˜˜™š˜’‹…~x|…Ž”šš—”‘ŽŽŽŒ‹Šˆ‡††‰Ž’ªµ½Äž¶¯§ŸžžŸ£¨§ ˜˜›ž ¡£¤¦¥£ ¢¥¨£—‘‹‰ŠŒ‘˜Ÿ¤¨«¤——–“Šˆ‡…{qlsz„‰ŠŠ‰ƒ|xxxvspnlihgghjigfghgecaa`acdfghlpsstuvvwxx€‡‹‡ƒ~wpqsvŠž¯²µµ²°¯®®¯°±²´°¨ Ÿ  ¨°·¼Â¿´©¢œ–’‹‡„~|{yx|„‘ž¨¬¯«¥žš•’’’“•˜™›œ›š››œ›š˜›ž¢ ›’‰„„„‡’–™¢§©§¤¢ ž™”‹‰‰ˆ›¦¦¤¡œ—’ˆ„‚€zsmquwussttx|ˆ“‹‰‡†‰‘–›œ˜”‘Ž’”•–•”’…|zzz‡” §¯®¨¡›˜†‚‹”“Š€|{z}‚‰•—˜“†…„ƒ|zzzŠ”—šž¡¨®¬§¢˜Ž…yx|‚„†„…ˆŒ•—˜˜–“‘Їƒ…ˆŒŒŒ”˜ž¤¡š“Ž‹…{{z|~€„ˆ’’‹‰‡†„ƒƒ…‡‰Œˆƒ{y€‡‰€xvy|yvu{‚„€|xvty…Š‘‰…€€€‹• £¥¦¦«±¶­¤œžž›—”™ž¡ ž¢ª²©›Œvoqsqjdflry€‡‡ˆ™¥¬²¸°¨¡Ÿž¡£¦©¬©¦£¢ ¤¬´µ³²© —“Œ”˜”‘‘“šªº»³«Ÿ“‰ŒŽŠ…ˆ•—˜™ž££œ•Šˆ†ƒ€||‚ˆ‰ˆˆƒ~{‚‰‰„…†‡‹Š„€|x}ƒ‰—›˜•‡}|}ƒŠ•šš—”—›ž¡£¡™Šˆ††††‡ˆ‡ƒ€„‡Œ”Š{{|{yxwvv†—£Ÿœ£©¸ËßÝÚÕÆ¸®ª§¨«®ª¥ ™’‘–›¡§®¨¡›•’•˜–•““’– «³¹À± ‘‰‚€xma[UQRTW_gga\XURRRSVY^digcabdfkpqppppqqrrrrpmjlnqx‡—–އ‚|yƒ™©¹¼µ­ª¨§°¹ÂÊÑ̼¬©ªª²º¿»·µ³²´µ¶³±®©¤ š–‘Œ—¢©©¨¥ž—£µÇþ¸²«¦¡™•’‘ކ~xurxŠŽ‘“Іƒ…ˆŒŒŒ‹‡‚‚‚Š–¡¤¥¥–”–™˜–”šŸ£ž™’‡|z|~ulc^YVVVX[^beggfju€~zupkkjlosvxzyxy|€…•šž¢—Š‚„…ƒ‚†Š‹Œ‹Š‰‰ŒŒˆƒ‚††‚~Š’š¢ª§¤¡ žœš˜›Ÿ¢ª²··¶µ´´µ¶¶ÁÌÓÎÊļ´°¯®¯°°°°ª”˜¤°¸°¨£ žœš˜™š›ž¡¥«°®©¤ž˜–Ÿ©¯±²®¨¢›”Œ„{smfo’ŠƒjQ@<7AQbjqukb]`ccbbglqx~~ulbWM[l}}~‚…ˆŠŒ†~wvuwŠ”˜€u}…Ž™¥«­®¢’…‡ŠŽ”𠧝®¬©™‰}}|~€‚†ŠŽŠ†‚~zvtryƒŒ–Ÿ¥¡—†‹“œ ¤¥£¡—‘ŽŒ‘–œ£ª§—‡{xk]Wq‹Ÿªµ´®¨ —’˜Ÿ¤©­­«ª¬­¯´¹ºµ±¯®®±´´ª –Ž…‡Ž–šŸ ’„‚Ÿ«µ¿ÉÓÛÐÆ»¬’Љ“¢§§ ™—˜˜Ÿ§­«©¦¢™–’‹‡…ƒƒ†‰„ynifemu|ƒƒ€‚ƒƒteYUQ\q‡‡{\=.Jfof^^`behmz†ˆy|†‡ˆ†~v{Ÿ­¸Ä·ªŸžœžž›™–•”–¡«¯­¬¨£žš–—£¯·¹º¸µ²«¤œš›œœ”Ї›¬¾Ã¸­¡“…~ws{‚„‚€€„‡‰yvx{xqjvƒ‡{skfdbglq}‰Ž‰„‡—£§¡›—–”•––™¡¤¦ª°¶³«£¡ Ÿ›—’ˆˆŒ”˜›™–’ŽŠ— ¦ª­¨£¦ºÎÔÍÅÂÁÀ¸°¨¤  ¢¤¢¡ ›•“—›¡«¶­Ÿ‚silot|„‚~z|}Œ˜—‰z}ˆ’‹…‚ˆ‰ƒƒ„„zoedbgs~wgWQLJRZ`ceinrx}‚‚‚€~{}€„~~Š— £§žŽ~€…Š–¢©§¤œ‚ŽŸ¯¹ÂÆÂ½³¥–˜œ¡¤§©ª¬¨¢›š™“ŽŒ“šŸ¤©±¹¿³¨Ÿžœ¢¬¶¶µ³¤•‹ŒŽ™¬À»¯£–‰~}||†“ ˜‘‹‡ƒ€|x{‚‡ŽŠ‚zz{|ˆ“¡¥¤Ÿ›–‘Œ‡ƒƒœž•Œ‡ƒ€se\cjqv{uk`SEFTco{ƒƒ‚‚‚‚ˆ˜ž¤©«­²¸¿½¹¶¡Œˆ‘—™ššššŠzoprx„‘ °À·­£•‡„Œ”žª¶©›Ž‰ƒ~~ƒ‹’™ §§¨¦¡š—”Œ˜£«®°©ž“‘’¡¯²¢’„ymnor}‰†~wogffgowˆ‘—¢˜Œƒ„†Š“œžœš”Œ…„‚‚‚‚‰“ž“„usqtŠ“–ƒ{ˆ•›”ˆ„€–±ÍØäæÔÁ´®§©¬®®®¬¤”‰~}~~…‹vkcZ^elzˆ‘Œˆ‡‰Š’œ¦©¬¯²µ½ÍÜÖɼµ¯§›Žˆˆˆƒ{tmgaa`dnw€‰’„tggfoƒ—œš˜††ŽŽ’˜ž©¶¾µ«¤Ÿ™•’Ž’•™¡¨¦•„}||…Ž–––“‹ƒ…Œ“˜œ¡¥ª©¢›•’ŽŒ‹‹‘—Ÿ­º¾»¸­ •—™ž¨²«˜…xmcr€Œ“™¢«¢–‰ˆ‡‰’œ¢¤¦Ÿ–І‚~zyzz„‘ž¤ª¬¥Ÿ™•‘–¤«±²¤•‹…}||ƒ‹‹vaSNIKMPV\__^][Zbnz~……†‹•Ÿ§¯¶¯¨¢¢¢£¤¤”Š„}wwvwz|vmea^]bglnqrrrvy}}~|yu¢¨«®®®­«¨£œ•’‘‹†ƒƒ‚„†ˆŠŒ†~{~„‡Š…€}Š—      ŸžŸ¡£¦©­³½ÆÅ¿³§ ¥ª©¤Ÿ ¡£¦ª«§££¤¤ž—œ¨±µ¹¶¯§¡š”™Ÿ¡œ˜”’‹ˆ“ž©µÂÁ±¢ ¢¤¨¬«Ÿ’— ª¬­ª–ƒ~Š–œž –Œƒ~zwvv{ˆˆˆ‡„€€€ƒˆŒŠ‰‡‚}ui\XXXYZ[_diqyqaPU]eltulcemuutux|€„‰‰ˆˆ€xoonsƒ’›ž¢ ž›˜–•—šž£©±¹¿¨’ƒ„†Ž«¤˜’˜š–’˜¡©§¥©¼ÏÔÍÅÇÊÌÎÏ̾±¥”‹‚zzz}‰””ˆ}upj{‹–‰ƒ|uvwx‰“ ­­Œ’˜™š›ž¡¥¬²°ª¤›‘‰ƒ}xtqy…‘Œ…~tjgovvtrqpog`]]^hw†‚{ti]WY\blu„”¡˜‘„wy„‰yyx|ˆ”–”’˜ž££¢Ÿ—‰„~}|}ƒŠ‘”€ttvy…œ§³¶³°§œ“§±¹ÁÅÇÈÍÓׯµ«µ¿ÃÁÀ¶©œ“ŠƒƒŒ–¡­¸²¬¦Ÿ——›Ÿ©´ÀÊÔØÈ¸¯­¬²¹Àµª£¨¬¦–…‚…ˆ‘•–˜•Žˆ{tx{€‰“šž¡™‹}‚ˆŽ—¡¤¡Ÿ™“Œ„|usqqsv|†Œ‡ƒ}{x€‹—‡~l[SZbpƒ•™š™’ŒŠŽ“˜Ÿ¥«±µ¯©£›“Œ…ytqy†††‚{uwz}‡‘–‰ˆŒŒ†ƒ—žžž˜Œ€yrkjijqw|~€‚ƒ„~ytmeejov}„„„†‹“””‘Ї„€zuv}„|vy{}€ƒ…††‡ˆˆ•£¬¢—•›¡ š•Ž—¡Ÿ„ˆ–Ÿ¡ ›—‘Š‚ˆ”””—Ÿ§¬¯²²²±«¥¦¯¹¹¶²Ã׿֯ºµ°²¹¿®™‡‰‹–›”“•‡yu…”ššš˜——¡«±±°­©¤ª°µ®§ ™”Œ…‚sgXF3'#+WXTOKGGOWXURNJGMT\ivŠ’Š}psuz†’—•”‘ŽŒ‹Š‰†ƒysnjfzœ“Š‚{tv{€…‰Ž”›¥²ÀÌÖàÝÚÕÈ»¸¿ÆÐÜèÝÑÇÄÁ½¶°­«ª¶ÂÎÕÜÝ×ÒÈ»¯¯°³ÄÖÝÕÎÆ¾¶ÃÐÚʺ³ºÂÊÓÛ̺¨™‹~ukmt{€…‡‚}{}€ƒ‰Žˆ‚{{zxuqlfa\XUX\^^^cluog```cjq€•ª©£˜“ƒxvz~‰–¡ ŸŸ¡£¦ª®¨¡šŸŸŸž•‚p_N>@AG\q…‹‚uhpw}~€ƒ‰•œ¢š’‘”Ž}mt„”–—™šœ•‡xzƒŒ‡‚ƒ†‹‘—–“…yomkqƒ” ¤™Žƒ~yx{}ƒ‰›¦®¢—ˆ‚vgXcrˆ‘™ž¤™…qu|ƒ‡ŒŒ‡‚‚‚~zupkiknry‡•‘‹‹Œ˜¬ÀËÔÝÞßÜÐż·±¯®¯³·¹¸¶´²°±²³¸½¾º¶²®ª£š’‰€wndbehr~Љˆ‡‡†Š’𣬴¹½¿¼¹±¤—Š}psvvpirŠ£’qPD:5ET`gnvˆ‰Š‰„€‚„В𣭲¥™‹{knxƒš¥ª¯±°°§™‹vp€”ŒƒŠšªª©§Ÿ—Ž‹‡ƒ~|{{…Ž‘‹„}vosx}‹˜›}‚ˆ–¥µ¾ÆÎÔÚÝßàÚÒ˸°ª¤­ÁÔÆ±ž¤¸Ë×ÛßÞÝÛÉ·§Ÿ–‘Ž‘”–™› £ ˜’–𢩬¥™˜˜–”’Œ‡znq‚“–”’‚reedk{Š‹‰†|rh]SLGC@=:BJUo‰Žyc]_`dinwƒ€|wrja[bhnru|„Œ‰†ƒ{truy…Œv\GKNRV[j—ˆtaZRWpˆ†r_afl†Ÿ²¶»º¸¶·¸¹½ÁÅÆÈÅÁ¼ÂÊÏËÇÃÂÀ½¸³¶¼¿½»¶¨š‡woiqy€„‹“‹†˜ ¤¨¬°´±­ª²º½µ¬¢–‹”£²¹¿¿©“‰ŠŠ’𢩬¯®©¥£¢¢©±´©ŸŸ©³«œ‘•š¢ª¯°°°°°°°¯¬©¥ ››ž™”Žƒxty}}{z|~re]\Z^djkljaXWesvspg]Wržžž¡¥ª§¤£ª°´´´®¥›œŸ¥ªªž“‹ŠŽ’—œ¡¡™‘…ue]WS]gpuzoW?CO[clu}…ŠŠ‰‹Ž’—œš“‹ˆ†„Ž—š‰xonnrw|„‹’›¤§¦¦¢˜Ž…}zw‚š³¶²®¡”§¿Ç¼±°²´±®ª£œ—––”‘ŽŽŽ‘“•—˜’‰€ˆ‘—–”ƒxpjdmx‚„†‰kVROP^lz‰˜Ÿ¡¢ž›—”‘•£±³°¬¤š”¤µº©™‹€v‚’   ž˜’І|wsompsvz~ƒ‰Œ–™••–——˜—–”Ÿ³Èĺ±³¶³ |wrmhw…‘”—™›œ›šš˜—•Œ“¤µ²¨ž{pzƒ¡±°©¢£¤¢˜Œ’Іƒ€„Š‹‰ˆwlszƒ…‚zrke^fnuz„Šˆ„|tp|‰—ª½ÆÉÌÊÉÇÆÄÆÈËÐÖÜÙÖÕÙÞßÞÜͳš­ÈßÜÙÓÅ·ªž’Š‚{xtu{‚‚|sh_ejrŒ•™ž˜’‹€ummls€‰{‚‰’Œ€ttvy~ƒ„}wsrrmgbcdcb`enx€ˆ‚tigeiqzxsnjfc`]]_`bdf{‘ —Žˆ„wk^gqzƒ‹‹wmdZYX[hu}€‚…ˆ{l```fv…“ ­¬«©¢œ™šœ¥²¿ÄÉÍÖßàØÏƼ³«¤ ±ÁȾ´±²²«£›˜”’’’”—𡣕‡ˆ˜¢¬µ½ÃÀ¾»¸µ³²²µ¹»º¹·¶´±­¨¡˜…{w€Š”˜šœ•Œ†††Š’š ¥ª¡˜‰ƒ‚„†Š”™ž•Œ„~wrmhijmz‡Š‚zrjba`bipw}ƒ|xoe]XRSZ`flruxxrkkszƒ—¢­·¹»½¿À½¸´¶·¹º¼ÀÈÑÑÌÈÁ¹°¤—”Ÿª©¢›–‘†~{|~€ƒ†Ž–’‡€€€ƒ†Š˜›™•…~wqv|ƒ— £§§¦¦¤£¡ Ÿ §­­©¤¦¨©¡™••–•””’pir|„Š‘’’’‘‹‰ˆˆŠŒŽ‹ˆˆŽ•›Ÿ£•Œrgda```XMB4%#-7DR_XPKMOT^gow~‚…Š’š›–‘–ž¦¨©«²¸»¸¶²­¨§¦§«°±±°­¨¤œ“‹‹Šˆ†ƒ…‰ŽŠ…€„œ¡£¤©¯´´´³²°±³´µ¶··¸·µ²¯¬¨¨¨©«­­ª§¤¡ž›—“‘Œ†€€„ˆ‘œ¥Ÿ˜–šžžœšŸ¦­¯²±§–”’•˜š£¬´»Á»ª˜“’’—›™•’Ž…zne\WY[`hpvz~€…ˆŽ•œœ™–™œŸ¤ª­®®³¹Àµ©¢¬¶´ ŒŠ–ž¦«¦¡œœ—‘Štieb__^afjklke__eloqrtuuromjgimr}Š•”’– ª¬ª¨ª«®¾ÍÓÄ´¬ª¨¢œ•’‘“•––’މˆ‡Š–£­¶¿¸¯¥£¡ž–”˜›–Ž•›˜Œ~~~‰”™‘ˆƒ€€€€‚ƒhRHKNPRT[cfa\`lyƒ†„ƒƒ„††††‰™£«°´´±®ª¤ž ¡¤­µ·¯¨ª¯´¦—‰†ƒ„ˆ‹•𒉀vliqy…“¡¤§§¤¡ž›—•””œ¥«¨¤¥«²®¥›”މ•¡¦£Ÿš“‹Š‰ˆ‡‡ˆŠŽ•›“‰~€„‰™¢ œ—•“‘ˆ€ysmiknrvzwmdiqy{~ƒ›š†Œ•ž‚y{}zsku„’𢤗‰‡‘œ¦±¼¹·´¯©¨­±µ¹¼ÅÍÓÐÍÏÕÛÞáäâáàààâåèæãàààÜ©—‘Œ‡‚~zuswzysnqx€~{yuromjfa\^_aejr€Ž„{pe]_aemuwutvwwqkgebhq{}~ƒ‡†|rszŠ’™˜—’‡|tlegjmrw|†ƒzqia[ahoy„ŠŒŽŒŠ‡wsw{{zz{||ŽŸ§–…}€®«©¤—‰€}z‰’˜ž¤ª±²¯¬¥›’‰‡‰‹‘œ§°¸À»·²ª¢œœ”‰~Œœ¥”ƒ{||‡˜©¬­­¬ª¤–‰‚€~ƒˆŽ˜¢ª®³®¥ž¡£¤¦«¹ÇÍÏÐǾµ²¯¯±´®¦¦²»¯£›˜•›§²´´µÄÒÓ¹Ÿ“’’Œ‹ŒŠ~sry}yvvvtqmmopke_ZUSSTRNJR[c_[XXX`o‚‚‚ŽšŸ“ˆ}rhny„š¯¿»·¼ÉÕ̼¬ •‹‰‡Œ—£¬´¼·³¯®¬«ªª¦¡œ™–“Žˆ‰•›£ª –š¤¡yux|}~‚…Š“››–’“”•™œŸ¡¤¬·Ãº¯¥ ›™™š–ˆŠ‹‹‹Š†znmptx|‚‘ ¥™…‚~vngw†‹~qhb]ZYY\^abdca`dhk_RLRX[\\`diijhd`gw‡“Ÿ««¬ª¤ž•‰}€‡Ž™£¨¤ ¥³ÁÄÄÄ·« —މˆˆ”¤´²±¯¯®«¤š˜–‘‰‡……††Š”‘—žŸ˜’‹…~†Ž“‡‰• šŒ}~…ˆ‰ˆˆŒ’˜¡ª¯‹…’ ¢Ÿœš™™¡¨¨ž”“–š §­°´¸½Â½±¥¨¬¯«¦¢ž™˜˜˜…{zx{…ŽŽ‡‚„…‚€}}|€ˆŠ„€‚„…††•¢§«®±®§Ÿ•‰Š– §­µ¾ÆÀ¶¬¦¡œ•‡ƒ„‹’Ÿ«²ª¢¤±½¸­¢Ÿ¡¥žŒ{trp~‹—™›˜†|qfedejnlcZ^gpx‰Ž’“’’Žˆ‚Š“˜‡~‰š«Ÿ’‡‹Ž†~wqjr{ƒ…‡ˆˆˆ‡††‚|||yslov}|{yupoopsw|xtolidYNVj€~{wsonlid_dksƒ“š—•””Œy}‡š£«³¸¼¿¼¸´°¬§¢ ¤¨±º¾¹´»ÍàÚÍÀ¶­¥¡˜’‹„|t|„Œ”œŸœš¡¤š‰Ž’’ŒŒŒŒ‚xqrtx‚‹“–™œžžžœ™—š ¦ ™–ž§«©¨ “‡“¢­­¬ª¥Ÿžžžš—– ª­§ ”…vojedbaa`fpy~ƒ€|yyx{~‚€Š“—–”ˆ†Œ“£²º¶±±³´«¡—‰‡˜ž¢¦µÇ×ÒÌÆ¿¹±©¡™—™›ž ¤¨«®°¨¡›™——˜˜‚v€‰‘”—“‹‚}yvoib[SSY_l}މ…„Š‘—£¨­²­¨££¢£¤¤¦©¬§¢Ÿ¢¥¨«­¨ ˜–“”œ¥¦œ“Ž‹ˆ„‚…ˆŒ‘ˆyjpy{vn`QLLLU^hr}„„„ziXTQQ\gptyvoi]QH_u…‡ŠŒ’Œ†€€€~|zwt‰¢¹µ±­«©¤œ•–——’Œ’˜¡¥®·¿º´®©¤¥©­¦œ’Œ†…‘œ š•Š”¡—Š‹„~ƒˆ‘•”‹‡…‚Œ–Ÿ¡£¨±º¾ÁĽ·³¸¾ÀÀÀº±¨£žœ¤¬³¹¾¾»¸¬ —ž¥¥Ÿš—––•””””|ja^Z_diqy€…Š…zoqtupkkrz„œœ›˜Œ€{ˆ”—𣩍ž”Š€uwz}„‹•£²·µ´¦–‡‡ˆ‹“›žžž¨´¿ºµ³·»½¿À¼·±ª£›™™›œ›šš”Žˆ„€vhYY\^hs|‚‡‰‡†zty}~xqu…”›Ÿ¢œ–‘‹†‰’œ•‡zyxwvtx†‹”‹Ž‹‰xnsx|||xmc\WRQPPPPUanux|yvrg\\kzƒ‡ŒŠ‰†|qlpu}ˆ“•–— ©±·¾¸¬ ¤ª¯®¬««ª­°´®¨¡›”’–›žž£©¯±³±©¡ªÁ×г¯«¦¡œ¢§¡™“”•˜ž¤¢›“Œ…~~~€†‹ŒŠˆ…‚€}{{{|€†– ª®²°Š‰±¯§ž—‰…‚ˆ™©­«ª¤ž™”Ž”™”‹‚„…ˆ•¡¤š‘†{qliea^]`bjwƒ†‡‡„{qfn”˜››™—”‘Ž‘”˜›Ÿ¢¥©±¹¼¼¼µ®§£ž›™–™¢§¬¯¦•‹‚„ˆŠŒ›¨¬Ÿ“™­ÀÂÁ¿½»¶«ŸŸ¨±¬¦Ÿ—ˆ‚|ywvtsqi`]enwЉ†„}vstvwyzŠ’—›Ÿ¤¨¥œ’‘’’‹†‚„†›¨¡›“‡zw}ƒ„„„‰Š†{uqlheb_YSQSTVY\`ehhhfcaekr|‡‘”—•Іƒ€{vsy†™š—”œ¥«¢™†|}…“˜ £ —އ„€†Ž•˜œ¡©±¸¾ÃÄÄú²¬¬¬­®®®®­¤œ“Œ…‰•¢œ‘‰—™†…Š‹‡|qosw€‰’•˜œ ¤ª²º¶¯¨¥¢   ¢¤¦«²¸¸¸·¶´²­©Ÿ”ˆ‘–Ÿ¨§œ‘„ugilmhd_YSUY\dmv|ƒ‰–™›œ¢¨­±¶¸¸¸´¯ª£œ—™›˜‘‰‰ŒŽ¢´´“rnz‡Š¢µ¼³©Ÿ“‡ˆ‰ŠŠŠ‹Ž‘•™ž¡¥§šŽƒzqquzwtqomh]RPSV[`emuxqko{ˆ‰ˆ‰²¼±¥™•–˜™•‘ŽŽŽ•£±ºÁȸ©ŸŸ ¡£¤«´¼¼¼»·³¯©£–Ž™£¦£ “‚plhis~|k[Z_d_ZWZ]gzŽŠ„ymefhijjmqtnga`^\VQONNV^h›¤—‰‡ŠŽ‹ˆˆ˜¨¶ÁÌÉ¿µ«¡™›ŸŸ ¦®·ÀÉμªœ™•’Œ“›¡ ž›“‹qbekq~Š’’’Œƒyz{}‰– ¥ª£”…€ukcb`chm™¯£—Œ†€}||}~~„ŠŽŒŠ‡ƒ€~}Š•˜”‘’“”Š‡ŠŒŒŽ’‡|ssrx„‘¢·Ë¸®¤››§³¾ÉÔÖ×ÖÏÈÁ¼·²¬¦­´½Ïáîó÷ëÖ¾»»ÀÅÈÈÈÆÃÀ²¢“Šˆˆˆ›§ºÎÞͼ­¢–’’’”—™™š™™˜zgWH;CKVfvvlaZTOYcmu}|wqpponmmoqrrr¡©±®“yoswz|„ˆŒŠ„|tttux{€ˆ‹‚ztnklns}ˆ‡…‚xncYOKNPay‘Š‚yj\OD9E[q‡¬¥ž•Œƒzrjotzƒ‹™­ÁÁ·­˜‚rz‚‰–šœžœ›˜Ž„‚„Œ™¥µÆÕÙÞÙÆ³±¸¿ÅËÑ×ÝßÞÜÍ´›ˆvgmsšµ½·²¤”‡‹™¬ÀÍÖßÒÁ°‰}‚‰” «¶ÁÍØÚȶ©¡™¢®ººº¸´°®®®¡‚„ˆŒˆ|pqtvka]ensttpkf[PF?9666DWjs|€yqgYLR`nƒ™¬¶¿¼©—Š~rqps„•œœ¤°¼¦}}~…”£¨¨¨ ˜ˆxsoz‹¬»ÉÏÕÑ¿®¤ž˜£°¼ÈÕÚØÕÌÀ³ª¡˜Ž„ƒŽš¤¬µ±¬¦ynx‚Ÿ®ª¤œ‰vgaZ]dkt|ƒ‚…yqx‹˜¥¬¦ žžž”ˆ{zy} ¡–Š‹ŽzeX_emv~‚ƒ„wiaab`\X]dj|›Ÿ£œ~tmfzŽ¡­º¼µ®ž‹xl_[p…ŒŠ”¢°§Ÿ–Œƒ‚‰–œ¢š‘‹Š|npy‚’¢±²´¯¤™Šxfny„› ›—’Ž‚uiebbdgq—¡¨š‹ƒ„†‘¢´³°­£š‚unljx‰—‡„‰ŽŠ†‹–¨»ÊÐÖØØØÔÐ˸¶ÁËÍÉÄÇÊË·¢“‘™¡š‘‡‚}|‚ˆ‚teirz}€…›   —‹€ ¯½Ê˸¯§ž‹wjot{…—œ¢¦ª©Ž•œ¢§¬›ˆ|…„{smfhim|‹—Ÿ¦œ‰wtsv©µ­¦¢ žœ›™’Œˆˆˆ‡††š ‘ƒxsmt‚Ї‚}vne^WQ`s…ˆŒ–œœœv‡™¦ª¯«£›¡£›“‹ˆ‡††††……„‚{ux‚ŒŒ‹{kaab_ZU\emcXUeu~„ubPX_k„¥””–˜“Š‚z{…𥰲³±¥˜‘™¤°¦œ•—™¤ªª¨¦šŽ†‹‘±ÆÆ½´ª œ°ÄÒÕØÌ¹§¦¦¤›“ŒŒ‹ŠŠ“œ£ž™“‹„†Œ’•˜™—•“‘ŽŠ„~ukcfimrx‹•‡wjyˆ™«½¿·¯°²³²°¯¯®¤•…‡‘‘Ž‹‡„~„…}xrllnpswyxwy‰Š‡„wgY[^evˆ–¢®¯®®³·¸±«Ÿ~‰ž²¼ÅÌÌÌij¢ ¢¤¦§¦¡œ™˜˜¢¨ ˜ˆ€‚™¢ª²¨ž”Œ„‡–¥¬®°¯®°¸ÀÀ¶­ “…Ž˜Ÿš–‡}€Š”›š˜–‹…xof]WQS^jw…“‹‡}tr{…Œ‘–—˜—•“”š ›„‡’’’‘‘Œ†ƒ†ˆˆˆ†|tj`YTOF<9@GPYba]YNB>IUct…Š‹’˜ž’{c`bdš°¸ÀÀ¸°¡‘€…‹’‰ƒ€~€~|~„Š’š˜—•’“œ¦¬²¸³®«­¯« •Žˆ‚œ©µÁž¸«š‰–¤±²´²®«¦¡œ™–’…xsz€‹˜¥ª­®¥›”‹—Ÿ¦­³·ºº·³¬¢™£©«­¯²µª—ƒ„ˆŒŒŒ‹‹Šˆ†„Š’–ƒobbbiu€†Š€sigeky†Ž”› ¥¬»Êɾ²¨Ÿ—Ÿ¨°·½ÂÅÈ´›‚†Š‹‰‡„€|}~~€€€€€€€„ˆŒ’˜™Œxxx‚œ£«²·½½·±¡Œw~†ž¬³²²¢Œuwy|…”™˜ˆˆˆ…s`WYZbo{‚‡‹„~vlciw…•¤ª«¦ ˜Ž…†‡‰’•—𖉓˜˜˜›¡¨§£ž ¡ “…t^GHXgv…‘Œ‡€ujhknxƒ•šŸ¡£¡˜Œ~qv|…˜ª´·º®Ÿ‹‹Ž‘”˜œž ¢“…{|~}{zŠ’œ§«¢˜‹ygkv‚Š’™œŸžš—‰‚yoimpw€Š‹‰ˆ}rlu~†”˜›žœ›™”ކwhiov†–£ž™’Š‚~|z€‡Ž™¤¯¼ÈĹ­§¢Ÿ ¢¦®·¼¾À´§›–‘‘™¡«·ÃÂÁ¿´ª¡™‘†ylou{…“Šyqiw‰›Ÿ£ª±²°®©£‘„€Žœ¨³¾½¹µ­¤œ–Œˆ„‹”›„{ywx|€ƒ‡Š‘˜ž¤ª¨¡™–”’™Ÿ§±»½¹µ²±°¦œ’‹ƒˆ˜¨¯±´§š‹’—œ ¤—Š}n`SJAAFJXfqqpqrrld\cjomkr†™™‡‚}}~ˆŽŒ‰†ƒ€„‰’ ­©¤žŒ{nid\TKMPT`lrokf_Y]cggfn‡ ¥•—›”Œ‹˜¦ª¨¦«°³­¨¡˜•›Ÿ¢£¡Ÿœ•–£©­«©§§¦ª±¹±¦œ¡¥«³¼º¯¤ž™”–——–”—£©®´°¬©¤ Ÿ¡¢ªµÀÂÃÀ¯‘‹…€|xz{{xuuxz}‚†ƒ~|‚‘ §«®®®¬£™˜¢«©£œ˜“Œ‰„yos~‰“ž¤–ˆ}vnpuzupkigfffks{zwwwx}Œšžœšž¢¥•” ««£›œ”Œ‰“œ˜“”–™¡ ”‡{vy}‡Ž‘‰‹•˜™™™˜šŸ¤©®³¯©¤§©©¦££¤¤¢ ž¤ª¬¦¡š“Œˆ‡†œ³À­›Šƒ{rvz}}~€€„ˆŒ’˜™Ž‚{zz~ƒˆŽ”—‘‹‹’˜ššš˜•’‹„„Œ”—˜˜¢­´ª ”…wsttpkgc`]\Z]bfjoqmhghjntzˆ“˜—‰…„„ˆ‹’”—›—Ž…|tkhdaa````^\[iw‚†ŠŽŽ“™Ÿ¡£¢˜œ¦°´µ¶¶¶µ´²±¯®®®®§ š•‘’‹ˆ•¡©¦£¡Ÿž¢§¬ž‡‰‹‹ŠŠ‰ˆˆ˜˜”ˆ‚€€€…‰‘”‘†{tnhjkmsy†ŒŒŠˆ’§®µ·¶¶¶¶¶¾ÆÊ¿´«¥ š•–›¡¤§¦£Ÿ¢¨®©£ ¯¿ÊÎÓÓÑÐËÅ¿¶­§§¦¨ª¬¥ž—“މ‚{{~‚…‰‹xw‡—š““—Ÿ§©¢›™›œ”‹ƒ…‡‰ŠŒŠˆ†€yqlfcfikmnhaZ`flqvvrnv€Š‹Œ‹†‚|unqv|…Š’š–‡xvwxofcr€‹‘—”ŒŽŠ‡ˆŒ’”–‘Œ‰Ž’”””’ŒŠ‰‡…ƒ~vnf^VSPP[fh`X^kwrmgc^bo}‡”‹‡€zvvv~Š—‘Šƒ~yy†‰‹Œ’“Œ„„‡›¦¥¡Ÿ¬¸ÁÄÇÁ·¬¦¢Ÿ ¡§¶ÅÊÇÄÆÇÇÿº´®®°²¹ÁÉÊËÌÌÌÆº®©¦¤¨¬¬¨¤Ÿš•ƒz…Œ™§§˜Š‹‘–‘‹†~v}”¬§™Šˆ‡…~zvsx†ƒ€|vopw~…‹’‹†€|yvsnjlmq€–“‘Œ‡‚|tkm}•šžžžŸ§¯® ‘”Ÿ«§¢—‘’ŽŒ‰†…ŠŒ‡Š–𡤧ª¯´¯¤š’Šƒ‚„›£¨­©£Ÿ¡£¢žššœž§²»°¥™•Œ|mgcahossrrrrnidgjp€š ™–”“Š…‹ž±¶¶¶ªŸ—š–†v{ˆ”™ž—‹ˆ†ŠŽ’™¡¥¥¤ ˜ˆ€xqjefhnz†’–ˆ€xpq{…‘ž«®¯®¥›omrv}„‰ztoiijjfa_cfiijhebfimptx~„‡‰Šwmf^]cjw‰›Ÿ Ÿ™”‘“–—™š›œ¤«®§¡œš˜Žƒyz{ˆ•—˜”‹‰†‡—Ÿ©²°¬¨¦¥£¡ŸŸ¡¢«µÀÀÀÁÂÄÁ»µ¸¼ÀÊÕÛÖÒ˸³±®¶¾Â½¸¶¶¶°¨ ™‘‹ˆ…‡Ž”—™š–“Žˆ|yvŒ™¢«±¬¨£›”Œˆ’¥–‹‡ˆŠŒ…~vgYS[cdb`fkqx~†‘œ¥¬³­¦Ÿš•“”–š¡§­³·®¥”‹„~yyz{ˆŽ’—”މ|maceecaenwtpkd]XXXaq~womjgfda\W[afnu{|~|xtrqp€›Ÿ£¢ž›œž ¡¡œ˜˜šœ—’Œ‘‘Ž‹‡{}„•™‰ypppxƒŽ–ž§´ÁÊÍÐÉÀ¶¶¶·»¾¾¹µ´´´±®ªŸ”Šyx{~‡’™—•“‘Ž—¦´²¯«£œšœŸš–›¡§¨ª¦œ’ŒŒŽ‹‰‰ŠŒ‡€yxxy|~}wpqtxz{{zyumehqzƒ‡ˆ‰ˆƒ~zvrtuw}„‰ŠŒŽ’†€}z|‹›£¥¦¦¦¦©««§£¡Ÿžœš˜”Œ‰……Œ’—›œ–Ž’•”“’•˜œ£ª­«ª¨¥¢§¬¯¯®¬©¦ž“‰†ƒƒˆˆƒ|tlkjlt|€€€‹›«´½Ã»´°°°«¥žœ››¤­³´¶­Ÿ’—ž¥¥¦¨®´²«¥›‘‰ŠŒŠ†~{xz|~~~€‚€€„ˆ”“‹ƒ}|ƒ‹““”•–˜•‘’“Žˆ‡‘›Ÿœ‘ƒv‹Œˆƒ{wtrpomljkllga\_a`WNLORUWZ`fmy†–œ›—”˜œœ™’Œ†€zupmsy{xvph`\YWY[]`bn‘¡²¾±¥œ˜•“’’”—™œŸ¥²¿À»¶°©¦µÃÊÆÁÄÊгtˆœ¤™Ž‡ƒ~‚†‹’š›˜—––•”•œ£¥•”–˜£§¡œš ¦¬±·±¨¡¢£¦©­´¿Ê·œƒ‘ §“”˜›Ÿ£¨­®ª¦¢ ž ¡¢¢¢ ˜Šˆ†–ž–‹ŒŽ“œ¦¡—Ž’œ¥¤™ŠŠŠyu„’›œœ|iaZUY\]\\_cfs“’Ž‹ŒŽŒ‡„„„‡–£ª™†x‚Œ”–™›ž}W:Yx‡ykilpqrsx}‚†‹‡€yurqy…‚vj^gt‡Œ’˜ž£¨­©£š––™¢§­¾ÒâÁ Œ™¦ª§¤¡›œ ¥ª¦›‹‡…ˆŒ’•™˜‘Š”¢žš”އ— œ˜•’‘•™˜–”•–“ˆ|wz|…œŒ{kaVNKHGFFOYbjr‚·ÀÀÀ©}€ƒ‡’—šž¦®³®© ’…„Š”—›£ª¤ŠpecbipurojbY[ckry}zwwxz‡•›ž‡qdinx†”•”•šŸ¡Ÿœ—‰ŠŒ“— ²Äꮥ——˜›£«±¶»ÇÔßÍ»¬¥Ÿ¡«´·¸·¨˜Ž“˜ž¥­®®®³·»¿ÃÀ¸°±´¶º¾¿¼¹²§›‘‰€ˆ••”‘Š„~yty}zv{‹›´Ñî×¼¤™Ž¬±²²¸¿Ã¿¼²žŠ~z†“š—Žzg_]\cjojebbbfkpmjgecccdo‚”„zoc`jtz}€‰“›˜•’‹‚tfgko}‹•–˜Ž~mihiqy~~~~~~€‚ƒ‚}umoy‚‘¡¯žŒ„‡‰‹Œˆƒ€„Œ““މ‰ŠŠ”£¡Ÿ˜Œyrlv‡†„€yrkf`ceeb_bip‹¯ÒÍÅ»¥Ž‰™©±¶º¾ÁÆÐÛÞÙÕÂ¨Ž“—£¦¦¦š‰wtqqv{‚…ˆŒ‘–™—•”””𤭝°®Œ…Œ”ž«¹¶±¯¶¼½¶¯¥š’–››œ£·Ìʹ©¡œ™ž£¨¬±²²²²²±¨ —„„Œ“•–•„tjotz‚‰‡ƒ‡Ž”˜œ˜‚~ƒ‡Žž­¨’{jZJ^q‚Š’€qib\]^__`abbv’­¸Áĵ¦œœš™˜š›ž¡¦«‡qsvz„˜ ¨žŽ}volu}„‡‰ŠŠŠ’›¡ žœ–‘“˜œžœ…|zw~Š—›ž¡¥¨«¬®§œ‘ŽŒŒŒ•®ÆÊÁ·Ÿƒl|Œ˜¢¡˜˜˜™¡¢ž™’ˆ~ƒ‹“–˜•†wqrrx…„ƒƒƒ„ˆŽ•’Œ‰Œ‘•¦¶¬›‰t_Uev…‰wld\WWXWVVUTT`m{¤ª¢š–•”œ¤«­¯±²²´¶¸°¨ —Žˆƒ‰™©›Œ~shgq{ƒ‰‹†ƒ‰–Ÿ§¦ š—”“•—™œž˜ˆŠ‹•œŸŸž¡¤¨¦£¡š”‘‘’“””œ¥«¦¡›“‹‘ž¬¦ž–––𣬴º¿¼¸³¬¥¢§¬¬ª¨£™Ÿ¦¬±¶´­§§¨¨¨¨¥ž—–˜š¡©°°°«œ†††‘Ÿ«¨¤Ÿ“‡‚‚‚€€{wv|ž°²°®¤™“˜œœ˜•–˜š  ›–‡~xsnopm]MEFFMXb\VPF;;GSY]`^[\grzƒ…‡ˆvq‚”¢¬µ¹ºº¹¸·°ª¤¡žž›˜”…ulllr|…xsz€‰—¥°¹Ã¿ºµ²¯¯±´²°® ƒˆ„{qdXY]_[WRKDFNUVVUNGCFIScs|ƒ‰ˆ‡††††††‚}y}‰›­¼ÇÒʾ²ºÂÊÑÙÚ×ÔÝéôòñíãÙÍÀ³ª¢šŸ£¤š‘‹ˆ†ŠŽ’‰xxxŽžž™”ž¨²·½º­ •‹€ ¯´¸¶¬£žœš™˜–‰|pe[Y[\bimidbbbl{ŠŽ‘—§ºÍÓÑÐÓÖ×Ξ¸²²µ¸°¦Ÿ¨±²§œƒv}ˆ‘ŠƒxfTVgw€†‹{k\PCHZmv}ƒ€~|||xsmhb]ZVW_gq}Ї€yxwx€‡†€y}ƒˆ‹‰ubZ]`[UPMJILOSX]fpzxwxŠ–¦¶´¬¤£¢¥±¾Â¿¼´©ž¦®¶¿ÇÏÕÛÙÔÐÖÜßÞÜÖȺº¿ÄÐÝçáÛÑÀ°´ÃÓÒÑÎĺ¸ÀÉÍÏÐÍÊÇ¿¸³±®±´¸«›’•™ ¨›ƒkjlox}cICJQ[fokg`UJ>1$-:GGHFC?@CF<1%$#'8IWdrx|†Œ‘”—šœžœ››ŸŸ›Žw_^bfnv{xunaUW^dltyuqrux„•¦¢žš‘ˆŒž¯»Ã̺¨˜“Œ’’’’’’“—š›šš˜•’Ž‹Œ£»Â´¦“|fu‡˜ ©®®®°²´·º»³¬¦¡›ž£¨±»Ã¾¹µµ´¼ÇÓÏÉÅÌÔÛâêáϽ³«¥¯º¾ºµ²°®ŸŽ‹—œžž¯Ä×Ǹ©›Œˆ‹Ž•ž§§¨ª®²»ÈÖÛÞßÚÔÑÔ×ÒȾ¨ŽscRJWdf^V>")6BE@;?FLSY\WRPPPTY^n~ˆ‚{o]KJOTPLLU^ht€{vpjj~‘Ÿ¦¬›€dfkpy‡ˆˆ‹”œ¥ª¡—“–˜ ­¹ÄÏÖɼ²­§­¸ÃÇÊ˹µ·ºµ®§ ™–«¿ÏÖÞÐµš‡‹”˜”ŒŒ‘—›…{qhca`m|‰ƒ|wtq{Ž¡¦¨©¦¢¢©¯®¦Ÿ“…wwvwz}yphjnsstuvxrh^hw†ŠŽŒ~oged€¦Ì¿³¦˜‰‡˜¡«´³²´¼ÄÉËÌÁ²¢™Š•—•”Œv}ƒ‹–¢¦¢Ÿ¥¯º·´°£—†€Ž¦¾º³«Ž‡‰Š‡„€~}zpfciplc[QG@Rcu‡™–†vojgr|„‰Ž”𠤍ª„ynnty‰œª›ŒwowŠ¥ª®®®¯°²µº¿¼¸³®©ª´¿¾´ª¡˜‘”˜™™˜˜˜˜œ¡§©¬¬¦ œ˜”¦½ÔÉ¿³ŸŒ~…ˆ‹–£§«¦Ÿ˜Ž„}}~‡‚q`_^`irx|…”˜œœš”†x|ˆ“ž¨­šˆ}||}~~€~|ywqkd_ZW[^gxŠŠ†{neinonlmopuz~~~zod_]\dluz~shlzˆ˜¨·½ÄÅ¿¸·¹º¼¾¾ª–‹“›£¬µ¥‘}xss{ƒ…ƒ‚†Š‘”˜œ™††ˆ‹¡¸ÇÄÁº°¦ ›–––˜ ¨­®®ª¦¢™•‘˜ ªµÀ±¢••”•—˜˜˜˜¡¥ª®±´¶±«¤®¸ÃÎÚ×°±²³³´µ¶¶´²°°°®¡“ŒŒŒ•¢¯®­©’|r|‡„zquz‚…ˆŠˆ€wohcjrwz}wla^]]gpy††„‚…ˆ‹ŒŽˆxgdkqx€„lTB?;?HQLD?GOW_goy‚~xqolp‚•¢¨¯§›‡~wtqrtvxz|†——˜¥®¯®®¸ÁIJ¡§²²±°´¸ºººººº¹¸¸°¨¦¸ÊÕרɳœœ¡¤£—•“’•˜™”ŒŒŒ–œ¢¨©–ƒwtrmg`ZUQUX\`eks{vokrx~€ƒƒ€{vt~‰”Ÿª®®®ª§£¢ •ŠŠŠ“¤‘~oibhu‚~xsuwz}Š™§œŒ{unnxƒ–Ÿ–‹‚ƒ…‡‰‹ŒŠˆ‡‰‹‘–œ£§«®¨£œ‚€†“š ¢££Ÿ› ¬·¹¸¸©š‘œ§²¿ÍÀª••–˜¢«®ª§£žšŸ£¥¢Ÿœ—“–› ¯¿ËÆÂ¼´¬¦¡œ–‹Ž‘“””–™œ˜•‘Ž““’’‰€y‰‘–œ¡¤¨¤¡š–ˆ{yx~…‰yn_POV]chmptutrw€‰†‚}wpp}‰žº×Í»©œ…‚|xtwz}‚ˆŒŒŒŽ‘”™Ÿ¥¨¬«£œ•‘Ž’Œ‰ˆ†‡‰Šˆ‡†|smrvƒ›²µ±®‚ˆŒ…~wrlhdeoz}xssuv‚Ž—’Œƒuffkponle^]bgmszˆŒŠ”šž ¢—Œƒ‰”˜›š £¬µ¸µ±®¬ªªª«­¯« ”ŽŽ’•—„{tmp{…‹“‹‰†’§¼¼¸³«£Ÿ ¢¥©®®®®®®¬¨¤¡Ÿž ¡£¥¨¨ ™‘‡~€…‹Ž’”–•”“‹Ž•¨´À´©¡¡¢¥©­®®®›ˆ{{|{yxxxx{~ƒ“¢¨£Ÿ”†x|€€~{xvsprux~…‰ŠŠ’–‘Œ‡ƒ€‚Œ•šœž—ŠŠŠˆ…~{xtomu}…Œ”‹yhilpz…Šˆ…€ztx{†Ž”—›ž ¢®¼Çº®£–Š……†‡Ž•™—”–šž ¡££¤¥¨«¥™Œ‡„ƒŒ–›™—˜›žœ›™™˜™™š˜–”›¤¬®¯®§Ÿ ¦­±´¶°ª£š‘”™—•’‘— ª™~cjryyz}„Šˆƒ~xroruwyz|~€‚€xpnqsvxzvsolijnqx€ˆ„{sllvwoeZUgyƒ~}||pcYbknlihhhov}ˆ“™–“”—š˜–••–”Žˆ…ƒ‚„…‡Œ‘—Ÿ§°¹Ã¸©¬ºÁ¹±´¿ÊĹ¯©¢¢®»¿½¼¿ÂÅÐÜãâàÝÙÕÔÔÔÔÔÑĸ®§ŸŸ  £¦§£Ÿ¨½Ó϶±¬©«­¯°°³µ¸Ÿ…qrtx†ˆˆˆˆˆ‡‡†€rdfnvrokigc^Y[`djquqlihhq~‹zeUY^```emuj\ONLR`ovxzuolz‰‘Ž‹ŠŠŠ‰…€~~~ztosy…ŒŒ‰•™“”™œœœž¢¦©¬­¢—“𡍭³±®«©§«¾ÐÏ¿¯«ª«¬­¬¦ –‡wttt|„ˆ{z~‚‡Ž”…ukosvxz‚˜†td]UYhv‡™¬¥›ª¸¹ªš—˜˜ ¨­¬ª©§¦¡™’“”“’Œ‚yz„‰Ž‘Šƒ…›£ª²«¤œ‚Š”¡®»»º¹³­²ÅÙÖǸ»À´¥š–‘‰~sstuz„‡‹–›¢ª¯§Ÿ››œš˜–”“‘‰ƒypmopkfa]Y[l}{k[YZ[_chlpj]OHC?LZfnu{ƒ °¶¼½°¤Ÿ¡¢¦ª®ª¦¢™Šˆ†Ž™¤¨¬°¶½½·±©Ÿ–Ÿ©±³µ´°­¥œ’’’”Ÿª¬¤œššš£­²ª¢œ—“›§³¸½¾´ª¢œ—›¡¨¥¢ž’‡Š¥¿½¬œ™˜—‡€xj]\\]djqw~‚„†“¡¯ºÅƶ¦¥¬³³²±®«©¦£Ÿœ˜„yrkkyˆ‘•š—“ƒxsz}obUG987=SjmaTRRSnŠ˜€i]\\agljifa\WRMMNNV^fmsxz|qcTTTV]egdb_]Z[\_jv|||}€“¦µµ´µ¶¶·¸¸¼Áº²¬§£¦«°¶¼¾±£¢¯¼ÃÈÌÉÆÆÎ×ÝßàÙÏÅÂÁÁÄÇËÒÚ×ÐÉÊËÎÜëíÚǽº¶ÁÍÖɼµ¶¸¸¸¸²¬¥ž–•Ÿ¨±¸¿º²«¤—–”‘Œ‡vbQRSZm€†ƒ€wlc€®Ÿ‘†~w‚Ÿ ¡ š”„|tldhlqy‚…ƒ‚}vpeZTY^acd`[VUTTTTTTTTTTY^dnwwlaZTN_pƒ~qdabb`_\TLMXcr…—’‹ˆ˜œœœ”‡{upmpsvz}{xtpkk‚𦢙–’ž¬·´±°°°»ÌÞÝÚ×ÎÅÃÊÑÙàçëîïëæâÜÖÐÊż²©£œ——–—˜˜–••«ÁÏÎÌÆ½´®ª§µÂÎÖÝÝÙÕÉ»­¨¢žžž £¦¦¦¦ta^[]cigdb[UOLIIJJPX`flrw|{uoh`XSNKNQK=.,/2+# '.47:Jaytminrx‚‹ŒŒ‡‚}}|}€‚„‡Šˆ…†š¢¦©§¢ž›˜—ž¤©«®³»ÃÂÁ¿½»¹¸¶ÀÏÞãæçÞÕÒÖÛÖËÁ»µ¯¥š”””—šž ¢¥ª¯µ½Åû³­§£¦¨©¦£ š”އzvvvz…—¬¿¢…pppqrry‚І‚~zskihhpwŒ˜žžž›™–•”–Ÿ¨«©¨¥¡ž›™š §¥œ’›«»»º¸®£œœ›™˜’Œ‡‡†…ƒ‚€~|~ƒ…‡Œ•›•ŽŒ‘””‘‰‚zvsolie_XXZ\iw‚q`X]beffp{‚sdYWTUVVWXXXX[ckprtnhccdgpy€…‹‰…ujdgkosx‹£¹·µ±¨ ˜“•¡­­®®®®¯±²¬¤œš™®ÀÍØâØÉº¾ÂÅÆÈÈÈÈÀµª£—–”•˜šœž °ÀÊÁ¸°©¢¡¢¢¦ª«¦ žžžš”Ž˜£«¦ ¢¬µ°¤™–•“ŒŠŠŠ‰ˆˆ†ƒƒƒ„ƒ€~}||Š™¤›’І„Š”™›–‘ˆzkgijgdcnx}|z€‰“Œ„{ywy†Œ“™•‰€vpppv‰•™–”Ž‚unjfkqw}„…{pnrvsokigiqy‡›¯£x{~ƒŒ–¡¥ ˜…zsvy}ƒ‰˜ ¨¯³±¯§˜ŠŒ“𣭲ª¢™†ƒ€‰“™™˜§±­¢˜™š©µ½¿ÀÀÀÀ´§ž¦®´·¹¼¾ÀÀÀÁÄÇĺ±±´¸»¾¿»¶«•~qjc_\\l|„zƒ”¦–‚quzˆ‘—¢š’‰yqkdit~‡——˜”Š€vlb^\[afhea]YTSRSUWY[]fv…€vkkjo“ž¡¤§ª¬ŠiPPPRUX`kvqmn{‰Œ‘–œ§²¹¹¸³ª ™”Ž’–šŸ¥§¦¦£žš–’’›¤©¬®±¶º­Ÿ““’•¤ª°¶´³³·º¸°¨«±¸ÂÌÕÙÞÚÌ¿¬—‚~{{|~†Œ˜¨¸¸·µ³±´¾ÈÒÚãâáÞÏÀ³ª¡žžž±ÈÚ̽²¯«¤›‘…ymlklpurkeddeefgghkpupjc]VT\chlpppof]USQSW[^_`lx‚„€zstvx|€„Œ””އ~shijmxƒ‹•”’ˆ€ywuz†“›£ª¥¡œ•ŽŒ’—Ÿ¦²¾ÇÆÄ½­ž¦®¬«¬µ¿Â¿½°Ÿvkjhilnw„‘Š€vsz‚Œ—£©®±ª¤œ“‰ƒzˆ˜¥Ÿ™™¡©¤—І…ƒzy{~~~~|zy|~‚†‹”™•‰†‚…“¢¯½ÊÎÏÏÁ²¤™„~wspoz„Ž”š“px‡–ž¥­¶ÀÆÉÌ÷¬¥Ÿ›Ÿ£¨¯¶±§ž–ˆ‚}€‹—¡©²ª¢™Ž‚{yx~…Œ•Ÿ¦¦¦žŒy{†•™ž¤«®®®¢‘re[]_^ZW^kw}‚„xmiotŒ™¡¨­ª§£›“Œ…~€ƒ…‹‘–˜›•‹|yutrqoljhfedegikklosx{{vv‚•™ž§²»´­¥š•›¢¨¯²¶»ÅÐʹ¨§ª­°´µ³±²µ¸³¬¦”’”—š §®«©¤•†‚‰ ²ÄÆÇÆÀ¹´±®®®®®®­ª§¡˜ŽŠˆ†‡ˆ‰Ž’–›Ÿ•…ui]UUVSMGJOTbpw]B:M`ffftƒ‘•˜˜“‹Š†ƒ‚ƒ…ˆƒ}vqlijlkjhjlnnnoruwz}€ƒ†„‚€€€~ƒ‹“Ÿ«·º¾¹¥‘„~y{~|}†ŽŽ‰ƒ{y†“Ÿ¡¤§ª¬®¯«§£¡Ÿœ™–ž§°¨¡—†tosw}ƒˆ–¤­­¬©¤Ÿ¢¦ª¯³·»¿ÁÃÄÀ»¶²®­¯±µ¼ÂÆÇȽ±¦Ÿ˜“Ž”œ¤£¢£§ªª§¤ š”¦°¸ÀÁ¼·¶¶¶±¬¦š™¤¢˜Š‡„„„€xog_WVVWXZ\aflqvwxwtqjYHEKPZdp€—‘Šthp|…xuwzvpkqyzustvxz|‚…ˆŒŒŠ†€y}ƒ‰Ž”–‰…„„…††’ž©²¼¾¼º¸¶´´´´´´·»¿¹±¨šŒƒ…‡‰ŠŠ’œ¦©«ª¢š”‹ˆ‡†‰‹‘އ€€ƒ†‹”¥¬°³°«¦©¬«œ‡–›ž¢£¤¥¨«©¡š•’ŽŠ‡……†„€{}‚†ˆ‹‹ˆ…{trrrvy}„Œ”ž¨­¯°§“Š„ynmrxtpmoqtx}|zxyz{€…Œ—££š‘‹…ˆ–šžœ”…}wwxz‡’—•’”˜›œžŸ¡¢¦ª®®®­©¥ š“–šž¥«¯¯®¦•„|wrw{~~~‚„‚€‚ƒ…ŠŽ• «¸ÆÓÒÑÎۧž ¥ª®±²©Ÿ™˜˜}mifcb`bhmkfbhmswz~‚‡…‚~ulegio{ˆš¯ÅÄ¿»´¬§¦¤ž“‰—›™šž£¢ ž›—““’•¥©«¬¢•‰†‚‚‡Œ‘•šƒwof_^\co|ˆ”¡¦«°´¸¹·¶´³²¶º¼¼¼ÁÌÖ˺ª«¬®´¹¶«¡w```]RGGPZ^_`abcfilqu‚’¡«µ»º¸µ¯© ”ˆ‰Š‰ƒ}wpj\L;,&8ELR_oƒ†‰ŒŽ›®ÂÓåóëäÝØÒÎËȼ®££¤£¢ ¦®·¼ÀÅÌÔÙÜßàààààßÕËÃÀ½ÁÈÏÎÍË¿´ª§££¥¦°½ÉËÎÐÐÐÓ×ÛÚÙÙÛÞÞÚÖË»«Ÿ”Š‚{vvvx{~tgZRKD=50-*=Vpx€‡‡ˆŠ™¦²»ÅÍÒÖÕÏÉü¶«Ÿ••”’Œ‰„€vlb[TLD<60*-0346:DMW`igdaZTPPPOMLZjzŠ™’†€}zl]OONSaopjdddc`\YYXXXX\`efhgdachny†““”–™›˜” ¯½Ê×àààâåèåâáãæëóüüöñëåߨÑÌÌÌÑÚâÝÔÌÇþº¶²°®¹ÆÔÏËŽ´¯®®²¶ºÂÊÒØÝàààÝÛØÈ¸«§¤¤§ª£š‹‡|phc_VJ>;85/)&&&0=KRY__`^YUSQPSV[o‚‘—œ¥¯¹®¡”„upyƒ~rea^]`cfjoonnopq{„‰ˆ†‚|v~†’•“†}x‡•œžš•ž°Á½µ®®®¬§¢¢¥¨œŽ~}}|€ˆ’”•‘‰†ƒ~xqv}„ˆŒ‰…wnrz‚‹”›œž¤¯¹ÅÑÜÓÊÿ»¾ÆÎÉ¿¶º¾ÁÄÇÈÈȾ°¢“ƒwy{zuqz‰— ¨­¨¤¡žœŸ¤¨®µ»¿Â¾»ÂÌ×͸¸¸»ÁÆÎ×ßÓÆ¹µ°°³·­›Šyh[`ehhhaWMJIIJLMMNOQRW\aejjfadjomjgdb```emumbWOGCEGNYdkqupjiqywogghir|„Œ“‘‡~xsnxŠ”˜šœ¡¨®­¬®´¹»¹¸³¬¦©««§£¥ª¯´¸¼¯¢šŸ¥¤œ”މ„—«¼ÆÏÍ¿°¤™ŽŒŽš¦®±´¶¹¼¶°ªŸ”Šˆ‹”ˆ|qifduާ¤—‘‹‹–”Š‘˜œ›™–™œ ›•‘”˜››œžž¥¬±«¥¤§«µÃÒÐÌǽ¸µ±¯®®©¤Ÿ”‰woie`fls{ƒŠŽ’’Ž…zpppu‡š¡Ÿžžžž›˜”‡‚€~yrlgc^XSONNOPPE:3468;>;96FVfw‡ˆƒˆ˜‰zle^]bgkorw|‚Œ—›šš•ˆ‹Ž‘‘’‘ŽŒ ±ÂÌÖÙÑÊÆÃÀÀÀÁÇÍÓØÞßÝÜÓÉ¿»¶¶º¿ÇÓßãæéêìèÞÔÌÆÀÇÎÕÛáãâàÚÐź®£–Š„}umf`YVRSZajt~}zy{}zoccmv‚Ž™Œusqnjfjnsx~vld]UUVV[_a]YUOID?:745?IYn„ˆ‡†„ƒukffflt|zyy~‚‹šª®®®°±±¯­©¤Ÿ›—”Œ”œž™•‘Œˆ’—𡍮°°°¬§£¡Ÿœ™•𤭮®¯¯°¯®¬¨¢œž¡£­¶»¸µ´´´­¥˜“Œ‰†„‚‡“”•——˜œ¢§£ž›ŸŸŸž £¦¶ÊÛ×ÓÍŽ·²­¨£Ÿ§°¶¶¶²«£ žŸ¡£¦©¥œ”Œ„|ri`YQRY`kx„‰„ypjcfkpsvwussvxtplgb`jstldju€~}}„ˆ‹‡zslfffghhiklgb_diouz€…Š‹Œ‘‘ޓ𢛓“˜ ©¦ž•“’‘Œ‡†Œ’•—˜–••—™››œŸ£¨®´¹¸·³¬¥œ’ˆ‰Œž¬µ´²®§¡š”’–›£«§œ’—›–‘“—œ¢©¥ž—‘Š…}wmdhpx€‡‘••””˜œ §­³³´°¨ ¢¦ª¥¡ ¥«³¼Æ¿´¨¢œ–„€€€ƒˆŒˆ…~{{~€ƒ‡ŠŽ‘“’’’’“”“Œ†~vnifb`][[Z_ityzz€‡‹†}|z{}~€xomu}{tmu‰•¡§¦¤¥¦¦¦¦§ª®±±²«¡–‘Ž‹ˆ†ƒ‚€‚†Šˆ‡‡Ž•›ž¡¢¢¢¥©«›Š~~~€‚„}{‡“žžžž—ކŒ’——˜”††‡ˆŒ“–™Ÿ©´±¬¦«°³°­§œ‘–¡¬§¢›‘†„Œ”’ˆŒ“•—™šš¢¦ ™”””–™›žž¡¤¥¤¢ ›—“ŽŠ—›—”Š„~„…‚ˆŠ€tl~‘–‡xv|‚xnehkntz~€‚…‰‹‰‡ƒ|uokfffgmrx}‚‚|‡‹ƒ{rfYVXZWSQYahnt{…ŽŒ‡ƒ‹’𢩩£œœœ¡¥§¥££¥¦¨©ªªª¨£žš—”˜¢™˜ž¥©¬®®®®§Ÿššš™–” ²ÃÀ½»ÀÆËÑ×ϵ°«§¢žŸ ¢¤¦²¾ÊÒÛÝÕÎĹ­¥ž—’‰‰ˆ••Œ…•œž¡¤¦¨¢›••”—Ÿ§¥•“’‘Ž‹‰‡„}xurqtxyyxurnqtupkf_YSNIFEC:0.:GR\fs|j_beimqqpppprzƒ‚‚†ŠŽ“—˜”Œ‰††††yuy}†–¦­¯²«£™–•—˜œ¡¦¡›Ÿ¢©³½¹®¤§ª«¦ Ÿ  ›“Œ•›«»ÆËÏǹ«¦¡š—”ŽŽ‹ˆ…yz‚‹’”›£©¢œ™›ž™‘‰“—•“‘ŒŽ‘”””•˜œžžžžžž¡¥§¤¢ž˜’‰„€|wrmheaix‡š®¿¼¸³© Ÿ¤©¢™Š„‚†Š‹ŠŠqer‰‰ŠŒ”‹vxyxqijqy|}~|{xphgkov~†š ›•‘Šƒ|}~|unknponnruy…Š“•––’‹ˆ…yru{‚Œ–žžž›•–£¯·¾Ã¿¼¸µ±¯®®³¸»·´´¹¾º°§ ™•–˜™›ž¡§¬¤š“–™—Ž…†Œ‘‘‘’“†|y{|†“Ÿ§¯²¬¦¡œ—˜š›˜”‰Œ‘—Œ~onmq‚’›ž£©­«©©ª¬¨ ˜™ Ÿžœš‘ppuz~‚…‡‰ŒŽ’“”’‘Œ‰‰ŠŠ…~xusswz~„Žœ©Ÿ•‹‰‡€tha]Z^cht€n]^fny…‘“—¢£¢¢¦©«£œ“‡zx{~woinsx}‚…††††‡“——˜˜˜˜—–•Žˆ€wnihhnt{‰—£ª±±®ªªª«®°±°®±¶»µ­¥™Ž‰“œ£¨­´º¿®žŠ„ysuy}…Œ™¦¤•…ˆ˜£®¸½ÂËØåêëìéæâÙÐÆ¼±©¤ž•Œ…}{zz}‚ˆŽ“•—˜˜˜•Œ“˜£®­Ÿ‹‰ˆ˜˜“މ…~ulcZQQPNKIC=62-+.16@KKFBHOUUVZcmw‹”£š‘ІwhZ`js‹–Ÿ¨®°²­§£ª±µ´²®¨£ Ÿ‘†€…Š’›¥±¿ËÊÉÆÀº·µ´¸¼ÁÅÉÍÎÐŲž˜–•¢°¹·µ¼ÊÙÓǼº¹¶®¦ žœ™•’‡|ri``hptvxƒŽ˜¢«²µ¸²«¤£¢¥¯º¾¹µ­¢˜›Ÿ¤ªª§¤Ÿ™’Œ‰†ƒ~ztnf^VH:9JZ```]ZYZ\^aekqxvssuwvql[D-.38COYbkw†”ކ}ytrrrpmjpx|l[MC:>KXbluwy{|~‚…ˆ‹“›¥µÅĵ§¤¤¥­¶¿ÉÔÚÝàààáâãàÓÆ¼¶¯³ºÀÈÏÌ«Š…š¯¸¼À¼¸¸½ÂÅÇÈÏ×àÛ×ÓÐÍÏÕÛÑô¯ª©³¾ÃÁÀ½¹¶³±®¦ž˜•’‘Ž“w^S[bb_\^aaZSRX]dmurmigegnvtnhd_]elt|…‹Ž’’’‘Œ‡……†ƒz{|}€ƒyZ;8J[gr{ywyƒŒ’”–“‘”˜œ™–†}zxx~„„‚€~|{„Ž’ŽŠ…€{€‡•œ›ˆuh`X\dlt{~wooty|}~yuqlhkt~€€€ysq}Š”œ¤§¨¨¬°³¹¾ÄËÒ×ÜàÛ×ÑÆº©x~’§´ÁÊ¿´©’’”œ¥¯ÂÕàààÛÔ̽¬Ÿ¢¥­½ÎÝê÷úûýþÿúïäØÍÁ»µ¯¯®£„dWUTY_enwyqiilpmjijlnrw{„zocSD>JU\_b_[XXXXXXY[\cks}‡Š‡~qc``amy~rfdksy„‰’–––›¢¨šŒ„‹“™Ÿ¥«²¸³¯®³¸¹¸¸»½ÀÃÆÇÁ¼±œˆƒ„„›£ ˜Ž…~ytqnnz†™¡¨­² Œyj[V_gou|~„š˜’Œ†€…Š—žseX_hrƒ”œ™“Ž‘”—˜š¦¯´·º¸¶²œ†}¨¯µÂÏÛÔÍÊÐÖÔÌÅÄÄÅËÐÒÎʾ¬š‘‹‡’¢œ––˜šœžŸœ˜——˜˜˜˜›ž Œxlptz‰„|tdTJS\]YUQOLORTTTPH@94.=L[jx|uncWJKLNU\ft‚Œ”œ”‹fMBLU^gpx€ˆ”Ÿ¨®³°ª¤¨­±¹ÀÇÌÒÇ´ –ˆ—¥°³·¸¸¸·¶µ°«¨¨¨±ÀÎÕÛÞȲ¥¥¦­¸ÃÌÔÛμ¿ÃÀºµµ¶µ´³´¹¾·¨™ƒlW_gntz~‚†…„…‡‰–ž¥«±³´³¯«¤”…ƒ––•”‰~y‚ŒŽ‹ˆ…~€„‘Ÿ¤¢ Žv^djq}ˆ‹Š‚xnhb`iry…„‚€‚ƒhQEHJR^insw|ˆ˜™˜˜”Ž”—‘†{qhbny‚…‰ŒŽ“–—’Œ‘–œ¢¨­³¶§˜Š€v|Œœ¤«¯¦š ¦ª¬®®®­¨£¢§¬®®® ‚„‰Ž’–š•‰ˆ‡ˆ’𥰴µµ±­¦šŽŠŒŽ”›¡›”‘”——––›¢¨¤ ¡®º¾¼º­Œ‡˜œœ—’Œ‹Šˆ~usz‰‘𣫰§ž”‡zy}€…Š‹‰Žš¦¬¯²²²±­ª©«¬¨£ž‡o[_bca`^\Z]`a\WW\bfilz‰•‘Œ…znpzƒŒ•šƒ|||}~~ytqtx~ˆ’™¢”„wy{}€ƒ…††€xs|„ˆƒ~„“¡£¢£©°±ª£›’‰’§¤ šƒ~~~‚†‹“Ÿ«´»Ãº®¢žšš¡§©¨¨ •Š’™—z]RY`m{Š™¨³±¯©Ÿ•’’’ž«³²°²¶¹ÂÍØÑɸ¯ªªª©§¦œ’ˆus{‚ƒ‚‚„…ˆ•£¥š”¡­¨£Ÿ¢¥œ„k]UMU^gkpqpnrx~|{zzz}‚ˆ–žžœ„{zxwutrpp€—Ž…|x€Š‘ŽŽŽ†wiilo‚•€tkbpƒ•‹ŠŽ’—£¨¬¯¤˜ŽŒ‘𢍭²© ™˜–‚uuxz{|€’£¨¡š}nsx‰“œ¤¬¯°°µ¹»¸µµ¶¶µ³²²²¯¤˜‹‡†††{oix‡’•—„ytqr‡­´º± –ž¦®¶¹¹¸ª”~Ž¡±­ª§¥¢£¤¤©®±«¥ ›–“’’’•™–‰‹Ž‘‘’“•˜™›œu…”Ÿ ¢š€{wuxz{xux…–›™•‹€ysmptwofbfjkih]OBFJOZenv~zsliggkou~ˆ†‚~Š•œ™“ŽŠ‡„{rhny„‡‰‰„€€…‰Ž“˜š›ž¥¶ÇÊÇÄ®–ƒ‡Š‘œ§§¤ ¯¿ÎØâäÚÏÇÀ¸ÀÉÑÔ×ÔÊ¿·¯§£ —‘’—Ÿ§£—•“”—›Ÿ£¨ –ŽŽŽ‘›¤ª¬®ž‹{ƒ…ƒ€~zvy} ¥—ˆ{pdeikifca_cltog_VMIS]jy‰Žˆ€yxvz‚Š”˜¤¯ºÀŶ«¦¤¢ ŸŸŸ ›’ˆ†††††…€|xtqw‚Œ‡‚}xrxˆ™¥¯º® •‰ˆ‹ˆ€x~„Š’›Ÿžž™’Š•›œžœ˜“Šsrrsuwxxx„–¨£›“‹ƒ€„‰”’‘‡}„‹”Ÿ©¢š““”—¡ªª¤Ÿ¢¦«³»¾¸²¦–……‰ŽŽ‰„‰” £¤£›“‹ƒ{~‰”™œ—‰€vtx|€…Š“œ£¥§¦¢ž ¡¢¦ª­­®ª£œ–‘Œ‘•—’ކzmxŒŸ£¦¥•†‚ˆ‘š˜—’~i`cfkqx|„‹’˜›š•Œ‰‡‹Ž‘’’‹‚yz{{xuqibp‰¡ž—…zx‹’—œ £¤—Šƒƒ„‹•Ÿœ—“މ‡ˆŠ‡„€~|{ƒ‹‹‚y~„ŠŠŠˆ‚|…™¬«¥Ÿ“ˆ~yt}‘¤«®¯¦œ•’’”–—™¤°»ÅÏÏÆ¾¿ÂÄÇÊËÊÈø®¥›’“”“‹‡ƒƒ†‰‹‰}pnv~ˆ“ž£§¦”‚y|~€€…‰Ž˜¡¢›”‘ŽŒ‰‰‘ŽŒ„yolkieb_^^gt€zutx{„›¢©«š‰}{x}„‹“•”’•š Ÿœ˜œ¡¥¦¨ª°¶±¥š†…‹Œ†€ƒŠ‘•˜™“ކ{pllls|…ˆŠˆzlkt}wois}‡‘œ£¨­®®®®®¬¨¤”Œ‚xnf_\cipw„ˆŒ’•˜›Ÿ¤©µÅÔÚàäääÙÁ© Ÿžžž›™—•”•––”““–™¢§®·Àº´¯®¬­°²¯«¨ª­®®®«¥ –ŠzuqmjcWL?1#"*379:743;CLT]htŒ˜¡ ž›’‰‰”“’“•—–’Ї„†‡‰Ž“œ¬½½°¤¥¨©£žœŸ£¨¯µÆÙëÛËÁÄÇÌÔÛ×ÑÍÎÏ˹§Ÿ  £§ª¯³´¯ª§¦¦©¬®«©¨¨¨£™Ž†~vk`WVTSQP[jzod_kx„›¢¨®¬«©¤žŸ¤©¬®°±²²²²²²²¯«¨£ž™–“Ž„{urnlkklnmllqywjaipx€‰Š†xiabdb`^`aa[UQQPQSTVWYZ\ZUPJD?>>=:88>DPcutpkhfix‡‘–›¢¨­¨¢Ÿ ¢¦®µÀÌ×ÐÉÆÎÕÕÏÉÐÚäçêëêèãÛÒÐÐÐÓÖØØØÚÝàâãäâáâèíñóôñïìØÄµ¸»º·´´´´¯ª¨³¾Á»µ²¯¬¬¬ª –Œ‚yqib^[Y^baZTG7'$#$2@M[hlll]L=713>JS[cmwˆŽunkhpy…Љ‚{rjaekqrtw}„Ž›¨­°±«¤¤®¸½¿À»¶±¨ž–“ŽŽŽ—¢«¥ž™˜–Ž~ojiis~„€|tj`aehov{~ƒ…†‚}xxxz‡’—–”’oa]YZ]`goxoecz‘žžžžžž®¿ÎÕÜÞÛØÐĸº»»¸µ¶¹¼º·´·º»»º»¾ÀÆÏØÒÍÈÈÈÇÅľµ­®¯±³µ»ÇÔÚÝàÙÒÍÕÜÛÎÁªpnooh`[ZXY[\dlsja[[Z`isy~tg\XSPLHMRULD@EJF;0)#*6BP^`XQSW[ahnrv~Š–‘ˆ€ƒ†‰‹‘–›¢©°¨¡™Žƒ†‹”˜¢§¨ª¬±µ»ÂÈÈÈËÖâêíðܾ¡®½ÈÈÈÉËÌÇ¿¸²¬¦•“™Ÿ£§ª¬­¬¡–…~‡ŽŒ‰†~vsttuwx|ƒ†‰ŒŽ‘Žˆ‚saT_ktvy~…‹‚vo‹¦¹º¼¸²­®¯¯¯®¨—…„ˆ’—šžŸŸžŸ¡¢¦ª®®®°µºÄÓá̯“›¤§”’•˜‘ˆ‡ŽŒˆŠ—šœž£§¨¢œ‘pptxvusqonnnprtld]YUX_f^QD8+$)/6=DO[hgfhr{„†ˆŠŒŒŒ’˜ŽqSWj}€‚‚‚€|yxxxurquz†Œ“–‚|Š˜£«³¹¼Àµ©¡·ÎÞâçæãàààáíøõؼ¶¾ÇÎÖÛÑÆ½´«¦£ ¥ª­«©©ª¬´ÃÒų¡š“ŒŠŠŠŠvmquyz|~„‹”¤«¯®¬£’‚ƒŠˆzsmgb]gt‚…‡‡ƒ€„‡‚{tj`Zdmtwzwuromnw€‡“’Œ‘•˜˜˜†_7:Qigdccdehjow~€„Œ”œ¥­¯®®¡’…|~†Ž‘“”’‘’¡¯»ÀÆÀ²¥«³¼ÈÔÖǸ«Ÿ“—¡˜”Žˆ‡‰Š” ©Ÿ”ŠxzƒŽŽ~pipw{}~ƒˆ”›¡£¥£Ÿš›œ¢¨®²¶³ª¢¤¨«¦¡œ•„vgs‡ššš™—•œ¬¼ÃÆÈº¬¡œ˜›¤®¯®®«¨¦¦¦¥¤¤œ’ˆ˜Ÿ¢¥œ…olqvƒ—‹tldfkpib]]^co{…ˆ†ƒ€vljs{}||rg_achqyvogghjy‡ŽŒ‡€y}‚…„‚€}yy{|‹« •ˆwgdjox€‡}rpz„–Ÿ  ¡¢£¦­´¸º¼·±­°´·¸º²£•Ž•¡Ÿ›™˜£©«­«£›šž¢¦ª®±´±ž‹‰—¥¬±¶®¦¡¢¤¥§¨€{wv}……yvutŠ”œ¤¤œ”ˆ‚‘ ¬¬¬­¯°´ºÀË×Ú·”‚‡‹ŽŽ‘ˆ€~ƒŠ’šœŸŸ ¤­µ³¬¤œ“‹Šˆ‚ug^WPPPQUXXVSQPPPPQ\gkd]bo|ƒˆ‹xsux~‡‘Ž‘•œ£§¨¨¥¡š–’Œ†~ulc[U`luy}}||‚ˆ›§­¥ž¤«­®®®®¬¦ ¡¦«³¼Ä¿¹´®©©­±¬¥ž‚{…’Œ‡€z„Š—¢§§¦¦£ ›™|hejnw„}vog`k~‘Š‚}„‹‘™ ¦¬²­¨£œ–•¤©¬°®««°µ·µ²«¡—‰…Œ’—˜šž¤ª¥ £©©£œ ¤¨¬±±²­Ÿ‘‹‰ˆŠ‹‹}ohlqtvxvtsy€…ˆ‹‰…€€€~‚…„~}|}ƒŠŒ‡‚znbhqzyxth\Y]adefZNIR\emvyzzxwx‡š¥¬°´±¯®®®©ž“‹ˆŒ‘Ž— ª¨§§ª­®®®°³¶ÃÑÙ̾·¹º¹¸¸­¢——–𣫬ª¨§¦§¬±³³²²²²³´³¬¦ ›–“’’™¡©¯µ³§›•“’–™š‰wmmnoppkeaabdhmquz|~€€€‚€~|zxwz~~|yuqqrrrrpiceox|}~vnf_Y^l{€‚…ˆ‰†ƒ‡šž ¢ ŸŸ£§¤œ”‹xwvx}‚†‹’”–˜™›Ÿ   ¡¢¢¨®°¤˜“–˜ «µ¬¡—”‘Ž‹‰Ž–ž”‰ƒ……„„‰–˜™™•’Šˆ…‚ƒ„…˜žžžžžžœ›”އ€yxz|zyy€†‰†ƒ‡™ ¨­ª¦¨´¿ÄÄÄÀ¼¸¸¸·¶´¯¦˜’’—œœš˜œ¡§­´´¥—‰{mqz‚€‚…‡ˆˆ”¤´¬¤Ÿ¢¥§©ª¥ž˜“Šƒ{yzz|}~|{{‚†Š’—œ£«®©£›ƒ~{x{}|voic]bktx{}voov|zupjeaejmnnkhdks{„‹–¢£ œœœ¢§¦œ’Šƒ}†‹Ž‘”—›˜’Œ“šŸ˜’“—¥­®®­§¢ŸŸ £¦ª¦¢Ÿ¢¦§§¦ª²¹ºº»¾ÂÁ·¬£›“‡ƒ†ŠŽ–žœš˜–”•–”Œ…†•˜šœ‹zpy‚„‚€‚‚…ˆ‰†ƒ„‡Š…€z{|~…ŒŽ‰…}tjoty„…‚€{sly†‹ˆ„~†Š†ƒƒ…‡ˆˆ‰‹Œ†{‚ƒ€~„Œ”’‘‘–›œ—‘‹„}„••–—™œš—”’’•••”›¦±·¼¿¸°ª¥ £«³®¨¡˜‡~uux|yvuz„‡‹†}tlfaabenv~ƒ‰ŠŠ‹’™ŸŸ £©¯ºÇÔò£›’ŽŒ‰‡‡‰‹–¢§¬©§©´¿Á½¹°¦œž ¥«¬§£›“Š‘–šœœœŸ¤¨¤¡™–”””™¡¨¤¡œ”Œ‰ŠŠ–ž˜“’‘ŽŒqa^[YXVX[_acd`][bhmortwzƒ––––––˜šœ¡¦©ž“ˆ~tmhbgmstux|ˆ‘›’…ypfbfjqzƒ‹“››œœœœœœœž £©°²¬¦ž“ˆ{m`_^]]\XQILPTZ`cb`guƒ–žžž ¦­±³´ÀÐàÛ×ÒÈ¿½ÂÇËÍÐÊÄÂÉÐÐǾ·¯¨«®±µ¸¹¶´¯©¢¢¢£§ª®±³´´´²¯«šˆ{upw…“˜¡¦«¬ª§¡›”˜¡©±··¸´­§œ…„‚ƒƒ„waKA937<<838AKXfqg^[dmrux|€…”¢ª§£¢¢¢§­±¯­®³¸·²­¢–‰„{zxvrnoppsux€‡š¤©¬®ª¦££¢”ŠŽ–žœ—‚mcefdb`bcfkqv{yqhhhilosyynd]WT[bhlou}„‡ŠŠtmkjqzƒŽ˜ŸŸžŸ¢¤ š”¨¯­«­µ½ÆÏ×ÑÊÅÈËÎÒ××ÕÔËÁ·¯§¤ª°ºÆÒØÜàààÜÒÈÁ¼¶¼ÂÇľ¸²¯®®©£Ÿ§¯³²°²´¶®£™“Œ…{pjgd]UMHB@DHLPTUVV\ac_[\^````cfhhhgffa[VlŠƒ€€€„‰Ž„{solihhijjjjigehov€‹–•”“Œˆ„}|†š£­±°°­ª¦­´ºººººº½ÀIJŸ–œŸŸž£«³¯ª¤•‡{tlov}†—¡ª¬¡–‰yjknoliijlpv{yvv‡˜¨²¼ÄÊÏÙãëÜÎÄÄÄÃÁÀ¼¸³®©¢”†ƒ„©©¨¦¢ž›™˜Ÿ§®²¶¹¼¿»²ª‚ƒ„‰°¼ÀÃËÔÜDz£¨¬ª¤—’Œ‰‡„yobTW`jihikmkfaZQHOU[]_acda]ZPF@ISWVVWYZXWWXZ]chou|„‹‘ƒnXTY^n€Ž‘–œ™‘‰ŠŒŠ‹ŽŒ‹‹Œœ§±ºÃÊÒ×ËÀ·´±¯®®¦•¥µ»­ž—•”¡±¿ºµ´¹¾½¸³´¶·µ²±´··µ´¬¢—†ƒ—ž¡¤¦¨ª£——–“‹‡ƒ€…‹’•Žpnpr€™šœš•‘…whlpstvx{~€ƒ†|z‚Š‘—¢¨®°±³µ·º½¿ÁÃÄÂÁ¿¹³¤…gSE7I^qv{ˆ‹€uy~yqmnppppkfcfimv‡Ž•šŸŸž›•މ„~sg]^___^]\\huƒ’¢®³¸·³®©£žžžŸŸ ¢¤¦¢—‰……†‰Ž“–˜›œŸ¡£¦ª®®®®±´¹ÄÏÐÉ·ªž¬ºÃ¾º¶³°ª¢š—”‘‹‰ˆ’˜˜˜–„ƒˆ“™ £¥¦¦¦¤¡ž £¦¤£¡›•Œ~pbRC@?@MYcinruxz{|||~‚‡Œ‘–ŒwrmkmpwƒŽ’—™—”’މƒ}sjdddb`^\ZZl~”››š”އ…ƒƒƒ„ƒ‚‚ƒ„ƒ~zwsv|ƒŸ¯¯°¯¯®¬ª¨¥¡œ›˜‰„‚€~}|‚„„„†‰Œ“–•”•˜›™•‘Œ‡‚‡Œ‹ŠŠŠ—©»±¦Ÿ¢¥¨¬¯³¸¼ÁÅÆ¾¶®¥œ“Š€zspz„Ž–žž›˜”‘‹‰‹‘–£ª£œ•”’‘Ž’—œš™š§´¿ÄÊÉÅÀ¾»¹´¯¨Ÿ•‘ŽŠ‡…Œ’˜›Ÿ›”Ž““”•—š˜•’‹‡‡†„zuqlnprrrtx|‚ˆŒ†ƒ„…ƒxmfc`ekqqrpjdcdddddgjnrvyzzunhknqtwz|~ƒŠ‚siijlorstt‹•™œžžžžžžœž£­·½ÁÄÆÇǽ¹·¶·¸¸·¶µ³±¯®®©£œš™š¥°¸½Ã¿¼¹¶³°­¦—ˆ„‡Š†ƒ„‡…|stz€~~~~€ƒ‡‹–•”•šŸ¡ž›—”އ‚‚— ¥«¡”‰ŒŽƒwnha]YW`jokggijpwˆ‘™›žžžœœ’‰wnlnpqrrtux‡‹Ž’–š—•–Ÿ¨©¢›Ÿ¢}oprpkgksz…‘™•’ŽŽ‘’Œ‰ˆ†…„„ƒ‚‚€}{y}ˆ’œ¦¯°°²ºÃ޵« •–—™¢«±²´¯¨¡©²¹´¯®±µ³­¨¬¯±°®­«¨§¥¤£¢¡žš›¡¨¯·¿¼¸³®©£š’‹†€€{wx‚‰yijns}‡’•”Œ‹Š‰tmmnqv{€„ˆ‚|umd```cgjosw|€„ˆ‹Ž’‹ƒ„ˆ†xsol~œ–Š…}yvpjghjnu|ƒ‹’“”’‰}€‡‘›Ÿ¢¤¤¤¢ž›’…yuronlq{†n^gr}‚‡‹ŒŽ’˜ž£©­ª¦¥§ª¬®°²³³«£š††“œ¤«©§¤¡žž›—“Œ…‚†Š’œ¦šŠ{‚‰–œ¢§­±´µ³±¯®¬¨¢›ž¢§¨©¨ ˜•—˜¡«¶¼ÁÃÂÀ½¸³¯«¨¤ œ–Šˆ†|n`dhn}Œ•˜š•ŽˆŠ‹ŽŠ}posv‡Š‡padp{„Œ“”–”Ž‘”Žˆƒ}wuwxwvvohcfimrx|~€‚ƒ……†…„‚…ˆŒ•Ÿ©¬°­ “”§§¦¥¥¤Ÿ“‡~|zwrmlpu{ƒ‹‡{yw{‰˜¢§­ª¦£¦¨¨¢œ–‰“™›šƒ{uoqtwŒ•—™›œœœœœ˜”“”–”‘ކ{ponr…—¤ª±¬¤œ›š™™˜•‰‹›§¯¯®¨šŒŽ–ž©³½Àý¹·¶¶¨š‰†…‡ˆ†ƒ€ztr€Ž˜œŸ   £¦§¡›•Љ‹Œ’—›š˜xa]dkszƒ…uikvyoecaacffffghilpu~‡”’‘ŽŠtmhchow€ˆ‰wfgv…Š‹˜¤©ž“‘—™’’•™¡¥©¡•Š€wu†—§´Á¼²¨¤ žžžœœ¡¨®ºÇÎÇ¿·®¤§¬²¹¿ÃÀ½½¿À¿½¼·²­¨¤¤©­¬ª¨ž“š¨±²²®©¤ž˜•™œ›”Ž”˜ ¨¯±³«–€y{|ƒŠŽŒˆ~tu|ƒ{rkklmnpomlgb_behntz‡…€~{wqh_chmv€‚xngc^chmmnmkio{ˆ„~yz{}…‹”œš•ybVfv†‹‘—œ•—¡¢œ•”””˜œŸ¢¥ ”‰Š”Ÿª±±°­¨£¦ª®©¥¡š—”’’’’…xpu{„’ ¦¨ªž’Š“›¡£¤Ÿ˜š¤®ºÅÊÅÁ¸«Ÿ£¨­®°­¥ššš˜—•‘Œˆ†ƒ‡Ž•’ˆ|ps“³½º¶µ´³¨™¢«©¢›‚wz~ƒŠ‘‡{wuŽ”Žˆ‡‰ŠŒ‡‚ƒˆ—˜˜—‰zl_RUgxƒ…ƒ€{pe\UMD;28>EP[enx~‚†˜ ¦­±²²¸ÀÈÕâëêèæãààààÒŵœƒy…‰Š„~tkjt}Œœ­«¨¨³¾ÉÓÝÜÖÐŹ²¾ÉÉ·¦˜‹ti^PB6.%-HVakmos{ƒ °°¯­ª¦©¸ÆÏÓØÌ½±´·¶³¯¬ª¨©ª«­¯±²´¼ËÙãìóðîåζ¯´¹¾ÄÇÀ¹³±¯¨ž”‹‰‰ŠŒ”›¥³ÁÁ½º³¬®ÃÙáÛÕɺ¬­®«¡—Š{lc\VJ?2!%+.19GVh{”—œ¢©±½ÉÑÙàо²¼ÆÇ¼±¥˜‹†|unhb]^`bbba`^ZQGOar„•¢™ŠŠŠ–˜‘‹ƒ{wy|}€ui_flmf_YUPRSU]eihfecbehjjjfZOLOR`rƒ„…‡‡ˆ†„‚…‰– §ª­³½ÆÏØßÚÔÕæ÷ÿÿÿöëàì÷ÿÿÿûôíîïðððíãÙÍ¿±¶ÁÌÜì÷òîêåáâãäääãâàààààààͺ¬´¼¾º·ªš‰€womke[QKFB>9542/)$ -BSPMJHEJT]^^\SJ@5*,4=GPY_em|‹ˆ|p`PCNYcluoaRUZ_fnsuxri_gq|¤¯¦”Š€„…‚€€‚…‰Ž”›£¦ª±ÁÑÚÝàÔŵ¥•Œ‘–•‘‰…‚†ŠŽ•›œ˜”†s`vŸ¡£ ˜‘’“—›™“Šˆ†Œ’••”›¨¶¼¾Àµ©¡¦ª°·¾¿½¼ÀÅÈÈÈÅ¿º®ž‰„†¨ËÞÙÕ˽¯°±³·º½¾À½º¶´±®¥œ˜š©¼ÎÌÇü´³¼ÅÇÅľ·±¬§¡›”‹t[?(7FRW\YRK@5+/37:=?ABCDEHJLLLQYaeik_SIGEGMSX]cehmv€‡‹‹…€yrs„•Ÿ¡¢š†•£®®®­«ª¥ šœ §¯²²²ºÅÐ×ßáÒĹ²¬«­®¢–Ž’œ¥®·Àº´±³µ½ÌÛàààÞÝÚÐÆ¼²©ž’‡‡ˆˆˆˆ†{wtpuz|n`YZ\bluvvvvvx|ˆ’›˜“Žsp‚“ ©³¦•…ymhntrkeinsstvy}‚‰¡µÉÏÔÖÒÎÎÑÔ×ÚÛÓÊÁ¹±«¦¡—ŒfJ8>DOar}†ŽŽŽ“—•‘Ž’‰„~ysokpw~„ЉqZI?545630,'! %)1976@KV`jt‰‹ŠŠ–£­¬ª¢wonnu|yqkkjgb^]\]bgmrx|~€~€›¨²¼¸«ž“‰…ŠŽ‰‚{‹¡µ¼ÃÇÄÁ½¸³¹ÁÉÒÚâæêîñôéÜÏĹ³·»ÂÌÖε« š¡§¬¯²®ª¦£ œ•ˆ„€yofv†”š¡Ÿ•Š”š—•‘‡}{€…ŠŽ’‹ƒƒ†‹‰†}skhejx†‰ˆˆŠ‹’——ˆ€xpuzƒˆ…xlijjhghq{ƒ†‡ˆˆ}pfffhkoqrreWIB:=Pcpx€…ŠŽ‹ˆ„…†‡™žžž•†vnhclv}~€Œ ´¼Àú²«ª¨«°µ°©¡“†zsmnv}‚‡‹‰†ƒƒ‚…‰ŽŽŽ“—œ¤¬ªŸ”ž­¼¾¿¿º¶´´´µ¶¶¶¶µ³±±´¶´³²¥˜‹€ts~‰‘™ ¤¨¬±·¹¶´²°®¯°±·½¾¹µ­¤š—””œ¥§Ÿ˜œ¥­®®«›Š|siqƒ”™œ–—Ÿ¥ª®¬©§”Š‚yxz|xusvy}†Œ„{|~~|yqimz†—’‡|oaZXV_jsle```acdfhid^[\^_``]ZY[^cmwzwtsrrx~ƒ†‰ŒŽ‹…€†Œ“§§Ÿ– °À±¢“†ysuv}…Ž“˜ž§°³°®®®®±³¶¿ÇËÉȾ°£¤§ª°··²­©¤ š—•“‰„‹˜¥­´¸©›“””—œ «¶ÂÌÖÝÞàßÝÜÔËü¶³´¶­ ’ˆ~wz~€€€‚„†‰‘”˜™™˜rv|xpg]TRVZ^bgkotx|ypgc`][YZagjjjgcafkorurle`\X^dkuƒ‚‚†ŠŽŒˆveairttt…•¤«³´¯«¢—Œ‘’’’–¤¤¢ œ˜™¦³·±«©¨¨«®¯ª¦¢ž››œœ¬¾Êü°žŒŒ•ž£¨«¤ž¥¬®®®¯°±±²´¹¿º±©œ…‹‘–˜›Ÿ   ¡¦«°µº¹µ°«¥   šŠyv|†Š“—¦¯±¯®ª¦£§«¬¦ žžž”‰}siep{~~{wuz„Š—ž¦¤ œ—“‹xeWMDEILT[afjmopkf`flqvz}~~zvraPEOZacdiqxxxyyzywvtqnkhglqnbVQPPZdnz…›¥¦£ š—•“‘Ž‘’†yow~‰™ª°°°§ž—› ¦±¼ÅÌÓÔÔÓÏÊÄ»±«§¢¨®µµ¶¶¶¶µ´´µ¶µµ´³²°¯®®®®­›Š„˜«¸½ÃÄÄþ¸³²°²µ¸¼ÀÃÂÁ½³©ƒ}zx{~€€€}yusrrrrt{ƒ‰•œ£ª•q}ŠŽŽ‘’ˆ~toihmqtwz{|}}~|xuog`hpw|€‚‚‚€}zxww|€…Š‘“”…teedjy‡Ž’މ„{rpyƒŠ”¡¯»º¸´«¡‘{eipwz}~~~}||~€ƒ‰•˜›ž ¢¢¢ Šsfjosw|„•‹†ƒ€„ˆ“™¢¬´¹¾¶£Šˆ‡˜Ÿ¡£¦ª®±´¶º¾ÀÀÀ¾¼º¹¸¸ªœ‘‘›¦¦¤¢¦ª©ž“’™ £¤¤œ”˜ £¢¢u[hw„Ž™ ¥©¤›’”•—œ¡¥§¨§¦¦¢—†vnswz}€‚ƒ‚vk`WONQTap{wtpnkY=!#)0;EJGCFLRVY]djnnnquzˆ™§¤ ›”Ž”™œš˜”†ƒ€ƒ‡‰ˆ‡Š˜¦®±´¡‰sŒ–› §±ºµ¬¥¯¹ÃÏÛÞÛØÔÐ̹­š‡€€‚„†ysnjgedku~†Ž–ž¦­³¹®žŽœ«¹ÉØàààßÝÜÑŽÀÿ¼½¿ÀÈÑÕŵ©£©¼ÏÓÖÖÌ·­£     ¡¥ª­®®§“{aL]nz~ƒŠ“›‹xjy‡“˜žŸœžŸŸ”‰{hUIB;=ACCBBBB?;6431.,.;GTcrŒ—‡…𙑉ˆˆ‰‘–œ¢¡™šœœ›—Ž„ymaiw„ˆŒŒ„|si`eox|€ƒ…‡‡††„‚€ujeoy}{z‚˜‡}{|…‡‰Š—¥±²´®¡”Œ†€†ŒŽˆ‚„„„„zw|‰”Ÿ¦¬²§œ“”–𥝵¸¼³ª£§ª¯´ºº·´ÅØèèèåàÚÊ´¤°»¾ÂÈÒÜØË¾¾¿ÁÄÇÊÎÓ×ÛàÛÕÏÆ¾·¶´®¥›•“šœš—’’˜žžžœ—’…pZ[bipwypf\PDGNTSRQPNRZbeff^WQLHIMQYajgdcegmxƒ„‚€ƒ…‡ˆŠ…{qg^T^homkq‘•””‘ЇВ𡧮ª¥ —‹ŒŒ”˜š›¥¬²µ·²©¡¢£¤¤¤¦¨«ŸŠuvy}„Š“¡¯«“™Ÿ ¢¡ žŸ¡¢ ž›”Žˆ„€€ƒ†‰Œ“”–𠥬²¹¿ÄÇÆÄÀ¹³´µ·¿ÇÇ·§›“‹vkhddinv€Š‹ŠŠ‡……‰” «¬«ª¢š’Œ‡‡Œ‘˜Ÿ¦®µ»¿ÃÅÇÈÀµª¥¡œ‘‡ƒ…†~rfedc^XTOKNTZ]_aceda^ZUPNKKRY]^^[XTVWYahmopjc[\]_gnv€‹ŒŒŠ‡…ƒ‚‡Œ’”𡧍ª§Ÿ—–˜š›œ¢§©¨¦ª±·¼ÀÅÌÓÙÜßÜÖÑÉÁ»ÀÅËÒÙßãèåâߨÑËÈÅÄÄÄÌÖßÔȼ¯¢Ÿ¥«©¥¢¥§¥›‘ˆywvv€‰‘•™¢§¡™†|uuv{„Ž‹ˆ…‚~tkd`]^adgjmoqoje`ZTPMM[hsx}€ƒ†„‚˜¢ª²°«¦œ’‰zusrnhb]XSOJN\krux{~‡‹ru€‹ˆƒ†‹Š~rry€€‚ƒ†‰‹ŒŒ‚vkbZVZ_dkqstuxz~ƒˆ—Ÿ¨±¹·´°¨¡›ššššššœ¤«¬¨¤¢ ž¤©«¨¥©±º¿ÂÄ¿»¹¾ÂÇÍÓÙÞäâáÝÓÉÀ¸°ª¥ £¦©¬¯«¢˜œ£ª¢š–Ÿ¨©¤Ÿ™“Œƒ{uz~†•¤¦£ ˜…whadfkrzwtpbTKJJOU\ckt|…‹‹ŒŒŒŒŠ‰‰ŠŒŽŒ…ytq|†‹ŠˆŽ—¡˜’„untz}~~…‡„‚‚„ˆŽ“š §­´·¶´ª˜…‚‚‚‚‚}yupkmps~Š•Ÿ©°´¸ÃÒàÝÚÓ¾ªœ•“–œ¢£š‹‰ˆ‡††„ƒ„Œ”—•””””–—–‰‹•Ÿ žœ™–“ŒŒŒ™¬¿»¶®œŠƒˆˆv{€ƒ‚€€€€„‰Ž‘’’’–ž¦¢š“•›¡¦¬ª¥ š“’‰”›¦±¹µ°©šŒ†††Œ’™¡©¨—‡}ytvx{~‚‡‘š˜Ž„|vqtvvqllptrpmg`[YWUSR_o‰“–†wqrrrrr}ˆŽ†xrke_ZXWWY[_eknprstuuvx{~‚†ŠŠŠ‹Ž‰…Š‘˜œ  —Ž‹ŒŒŽ’œ¦²ÄÖÛÑÇÄÄÄÆÇÊÓÛâçëèâÜͼ¯¯°±³´¶¹¼¹¶³±¯°²µµ´´½ÇÏËÆ½«™ŒˆŒ“›£¥ž—’ŽŒŒŒŒŽ“˜˜–”†ugghjoty~ƒ„„ƒ€~|||ƒˆ‘œ§²½Àµ©¡™ƒwuru†–—‹yvtqnkjhny„…„„|ut‚‘–”’‰~rnjijlmnnoppuy}~wpjfbehlqwxtqmifdcf|’›•’˜ž›˜••”–™›žž¡¤¤™Ž‡…„‚€~…•¤¦£ŸŸ¡¢¦«­¦ Ÿ¤ª©¦¢¦«­«©«´½ÀÀÀ¾¼¸«•—šŸ¦­«¨¥œ”‘™¡¤¤¤ª°·ÂÍÓÐÍǾµ®§Ÿ——¢¡—އ{yvuy}‚ˆŽŽ€rikmrx|wrw{}}|{zzyxx{~~xsnjgdb`bcfkqvz}€‚€{x|‰–ššš’Š‚yqjeaabbr„‘Šƒ„•’‰€„‡‹”•””Š„‰Ž’’’”˜Ÿ  œ™—™›ž£¨®µ»¸µ°¥™‘Œ“Ÿ«©¦£Ÿš™›žœœžŸ¡±ÁÍÎÐÑÓÔËÁ··¶¶¶¶´±®«§£¡ž›˜•–˜š”…€{z‚‰‘›¤£ ž¦­­š‡}{z{||†“¡§¦¦Ÿ•ŒŒŒ‹†‚|unptxsnkklqz„‹–—˜–‹zuqtz€{wspmpw~ƒ„‚‚‹“•†‚|yvuy|~~~zupjeaehlnqw‡‘›£œ–‚vpnliffv†Ž‹ˆŒ“–𠣦©¬ž‚ƒ…ˆ‹‰„‰–¡Ÿš—“–›¡¤¦§¤ ›“‹†ƒ€‰•¡¢£¥§©¦ ™“ˆ‰ŠŒ”›¡§­²¶º°¥ ¥ª¨ ˜•””—š›™—•””˜œ ª´¼¼¼¹³­«ªª§¥¥§©¨¤¡ž›˜ž¤©®²¶»¿¿½¼·²®®®±¸¾¶¦—¤¨ ˜’Œ‡Œ•¤©¯¯°¬¤›‚usrqjdacfdb`[UQW]clu}…‘”•…‚†‹‰„~sf[_cd^XX[^ciorttnhb[UX\acegikmnneYOTZbp~Š–¢£¢¢‘€uvx|ƒ‹€qby‘ š•“””™Ÿ¤®¹ÂËÔÔÍÆÀ¼¸¹º¹¹¸¸¸¸µ³°¹ÁÉÌÏÎËÈÇÅĸ¬£¥§«²¸±¤—ž§¬¤œ–’–£¯·¾Ã¿¼·±¬Švvyyxvvvvy~‚wlcdfhlqux|~€~€…Љ†‚zrkrxzupmlloru{€‚{si^`dir|€~€„ˆ~qec`ajrx|€~}vokklqz‚{odjptttsrrx†˜ ¦«±¶»¸´°´¸¹µ±¬¤œŸ¢’vˆ‘›¥§¦¦£ ŸŸ ¤¬´µ´´°­«°´¶¶¶¹½ÀÀÀÁÄÇÄ»³ª¢š—””Ÿª«Ÿ”˜£¯®«©¥¢£©°µ¸¼¿Âÿ¼¸¶³®©¤•…urnh_UMF?GQ\iw‚†‹Ž’ŽŠ‡Œ‘˜¢¬¹ÇÖßèïÙij¬¥¤§ª¦ ›…{rjeddb`]YUU_irx~}|†™¤¯±«¥ œ˜‰ƒ‚€t\DADF7)   !/>IT^is|ƒŠ˜ ¨³¾ÈÑÚÖÍĺ¯¥ œ¤ª¨£ž­¾ËÅ¿»¹¸¾ÇÏÖÛààààààáãäâáßÖÍÉÊÌÍÏÐɽÄÌÓÜåèèèêëëèåãâààààÖÊ¿¹²¨˜‡{skd^WI;34641.4;CJQZgt‚¢¤§©¬±¹ÁÄÄÄÂÁÀ½»¹µ±ª –Š~rtutmg_VLVfvhZQSUX\_cgjotwwvwyzzzz}€„Œ””†}rha[UPLKNPQRRTWWUSL=/09BDGIKMQX^abbipuqlklnw…“—šž¨²¼ÄÍÌÆÀÇÎÓÐÍÍÎÐÔÚàÛÕÑÔ×Ôɾ¾ÅËÑ×ÛÑÇÂÈÎÐÐÐÚåïîíëêèèèèׯÄÙéìïòõøòëäääãâàÝÙÕÎÇ¿´¨ŸŸžš“‹wlu~€p`TNGA;6436GXbfilmnqtsgZXajs{„‰Ž“”–“Œ†~ulhecfigb]SG;DOWWVWXXZ]`bcegijjje^V[`c^YY`hpy}xvˆŒŠ‡}ob\WTTTW^egedbaaceeb_^^^[XW[_ccdca`is}~‚ˆŽ—¢®ª¤Ÿªµ¾ÄÊÐØßààáâãæîõúüÿøðéð÷ùíá×ÎÆËÔÜåîõùýüöñòóôøüÿÿÿÿÿÿùðèãßÞåìò÷û÷òìåÝÖÑËÇÅÄ»¯¢›”Œ€tkd^^`b[TMHD?94.(",6;( "1"   0@@??BFGFDDDDLT]`cfimoqrz„ŒŒŒŽ‘•œ¦°°¯­«©«²¹ÀÈÏÔØÛÍ¿¶¶¶¸¼À¼·³¸½ÂÈÎËÁ¸¹½ÁÂÃÄÄÄÈÏ×ÔÐÌÌÌÊÄ¿¿ÅËɯčŒwz}€ƒ†ŠŽ’ˆ~toigijqz„~}€ƒ…ˆŠ…}v|‚ˆ’£¥¦Ÿ–ŒŽ’•— ¬·®¤¡¤¨®³¾ÌÛÞßÞÖÍÇÆÄÇÌÐÎÍ˹®ŒxaKOV^jv‡ŽŠ†…„…˜žžž›š—“†~yyz|~€ztm]M@:4.&!$'*-+'"+7CTfvƒ•””Œ‰‰Š‰‡…‚|€…Š€wrx}„Š‘•˜š’‹…€|yxx‡œ²¹¿ÆÍÔÛáçÞÑÄÉÍÓÞêðððëãÜÒÈ¿º¶¸¿ÆÐÜçèèæÜÒÉÁº¼ÂÈÆÅ·¬¥¤¤¤¤¤­¸¿½»µ¨›†lSRUW_gq|ˆŠˆ†††‡‹•œ£¥£¢¤¦¦•…vmdenw{yqib[RI?CHMT[^[WTRPF9/4:FcŒ†yqje`bhox‰tjbZ^l{ˆ•¢ Ÿš—•””’Žˆ‚€ƒ‰…whw†• ª¯­¬¦Ÿ˜“މ‡…‰’›žžž›˜”†„ˆ‹•¡­±´´©ž”Œ„~„‹‘”—•†xfTaq€‹– ¨±¬¡•œ¥«¥Ÿ¡®»¾¼ºÁÉÏÎÌÆ¶¦¦±»ÄÌÓÏÊÆÀº¹»¼ÂÊÑÕÙÛØÕÏÈÁº²­­®²½ÇËÉÈ»³±¯¬§¢§²¾ÀÀ¿·¯¤zv€ŠŒŒ‹ƒzqi`^bfilnrvz„‡‰Š|jXYZ[]_bdf]PD=71.+4I^]TJLMOPRRRR\jwyzwhZNE<:::CMWfu‡Œ…wijknz…š£¢˜ž£§¢¤¬ª¤žª¸ÅÎ×Ô¿ª©´¿ÀÀ¿»¶°§–ŠŒ•›Ÿ¢¥©¬°±²³µ·¹º¼¹¶²°¯­¥–“˜ª½ËØäääÜꦴÁÌ×ßÝÚÔÆ¸´¶¸´¯©£œ—•“•™”‡zxwz‡”›œœ–ˆ{tkbbjrtttmg`[UK<.19BLV\SJD?;:::::=O`nw€|tlgb`fmqrrqonnnoprrrryƒ—¢«¬®¥uqw~‰”œš—ˆƒz€‡Ž›¨±´·¼Âȼµ²¯´ÇÙÝÙÔÏÉÃÀ¾¹²««¯´¿Ì×ÔÒ̸®¤šž¤«°µ´¦˜“””›¤«£›™£®¯ª¥¡ž›“Іޕ› ¥£ ž“ˆ~|{zz|~€…‹’•‘‡|„‘ž¥«¯¯®§—ˆ|qfa]]gr|„Œ‘–š™˜—’Ž”§º¾¼º®¡——˜“‰|||‚‰ˆƒ}|{zz†“Ÿ¦¬§xgXILQSRPRV[es€‚‚€p`\kz~~uka^[YVSSTTcv‡‰‹Š‡ƒ„‡Š•› ¥¥›’Œ‰†„‚yrpv|†‹Ž‘€nhzª·µ®§›„}wuvv€š¢©¯¯°¬¦ŸŸ  ¬·¿¾¼º¶³¸ÀÈþººº¼ÀÃËÓÜÞßÛ뤲ÀÊÓÜ˺«¦ žžžœœ¨µ¿ºµ¯§ ›–’˜ž£©¯®¥•ކ„zutw{ƒŽ™–“Žohkov€‰†|ob\`efffffgqzƒ†…„„ƒ‚ƒš£¤¦ –‹‹Œ‹„}wvtpicdfipw†š«½ÈÓÛ¼ž†€zupkihiqy€‚{w{†ŠŽ’—œ™†|qfhihb]]bgq|ˆ•™™˜•‹—žžž›‚‚žœ“Ї„„Ž—ž£§¦¤¢˜Žˆ‘™¢¬µ¶³°­ª§§¦¤¡Ÿžžž¤©°¸¿Á¹±­¬¬µ¿Ç¿·¯¨ ¢§¬­®¯¯°±²´²°®¬«©¢š™ §«¬¬£˜’Š„€}z~‚…ƒ|qfbbblyƒƒ‚~sggpytngaZUSQT[c_YSSRTZ`dfhhhhd`__`[PFB@>HS[`deddgilv€Š”’ЂЗ¤¡žš•Ž“—ž¦®±´´ª¡¢¯¼ÇÑÜÒȾµ«¨¬¯®«¨¢œ™šœŸ§®±²²¸¿ÆÎ×ÝÞàÙÏÅÄÄÿº··¶¿ÍÚÞßÞÏÀµµ´¸¾ÄËÒÖÆ¶«ª¨ª¬®¨ ššš™—”—šž£¨­°²¶¼Â¼­Ÿ’‡{tme^WSQPV\ccdb]X^l{}|{vpibZTQNHA:1(':MY^ceffcabglprtplhmqsnjjmpx‚Œ””†„‰‘•˜”‘Œ‡ƒŽ™—‘Šwr{…’—šœž¡¤¥£¡¡£¤ž”‹‡„ztqqrz‡“˜Ÿ›˜›©·ÄÏÛÕÎÆº®«¹ÇÑØßо­­¬©£œ•އˆ‰‹”¥­µ³ª¡›–‘‰‚{upkr{…ˆŒ‘™¡¨­³­¥š–“‘ƒrcsƒ‘›¥«­®¬«ª­°±®«§¡›—”’–š™…{qfgknqtutrtwz‚Œ–™œŸ¤¨¬°³«ž•𠥫²¼Å¹°ºÄʾ²¦˜Š‚}xrke_YSKDM^o{ˆ’’’”–™¢­¹¹¸·°ª¨«¯°°°š‚kgb_^\VLC7*(17:=<9689;HT[YVWXXgx‰“¦«°¶½ÃÁ¾»º¹¸¸¸¶³°§›‰‚‹–¦½ÓÓÍÉÔàêðöòèÞÕÌÄÆÇÈÈÈ·¬§£ £¦©©ªªªª²½ÈÊËËÆÂÄÍÖÛÝàп°ª£˜“Œ„|oaXaikd^RD7665420-+-26Vy˜Ÿ¦¨¥£§®¶ÀËÓÍÇ¿²¤¢¥¨£ž˜ˆxlgbacd`]YVRUbopic`]]djoopi]RONOQSV[`cddlv}wrkaXVZ^\ZWLA;<>EQ^fmsmfdlsy…~tigehw…‹ŠŠ„|ty}ƒ‹”œ¤¬²¶ºÉÙåæèæãàåêðõùùíâÝßàäèìéæâÙÐÔæ÷ýþÿõìãâàààààààÒºÑçöúþùñèïöüüüøíãÜÖÐÖÛßÙÓÊ»«£žš›œšŽvlbaejgd`RC9862,&!(/47:2*#2ALQVWVV\dkklgVE<96ANZZZ^jw~„~{skedbgpxwsoibair}‰•Œ}n{‰”›¡¦©¬©¥¢­¸½´«žŽ~xwv{€{vw~…”§¹¹¸¶«¡›šš™—–…§­³¨–…’ ®·¿ÃÁÀ¼·²ÂÒáåêéáÚÕÐÌÔÝãßÚÔÌÃÃÈÌú°¦œ˜œ¡¡  ‘sz‚Œœ¬­¦Ÿ¨³½ÉÕÔ¼¤—‘Œ”œ¥§©¥˜‹Š•ž¦­¨£œ‘††‹‘Œ†sf]]\]_`WLCEGKT\^ZVWXY`gkjhfb^\[ZclpjeZL=FUdba^VNRapœ—“Ž„{tqnpqrtuyƒŽ˜ ¨ ‘ƒ‹• ´ÉÒÍɺ²»ÅÎÕÜÚ̾¹·¶µ´³¯¬§ š¡®»ÉØãâàÝØÒËļ¹¶³±¯®®®¨ž•އ„œ¥¦¨¡•‰€wqsuuutmbWl†”‹‚vkq„—§¶Ã¹¯£”„€„ˆ˜Ÿ“†|vprw}sfYYX]p‚ŒŽ‘“–›§³¶³°­ª¨»ÎØÊ»¯¥œœž›™”…vi`VUVV_hoprw€Š„ynhbalxƒ—•Žˆ…‚„‡‡„‚ymagnqcVG7'!0DU[aeffinr|‡‹‡€x|…n__^dt„ŒŽ‹†|wvy}|yvxy|Œœ§ª­°³¶ËåýþÿþûùóêáààáçìîèâÝÙÔɼ°°°´ÁÎÝìüúõïêäàààáãäÚÌÁÉÒÖÒÎÁ¬—ŽŠ†“¡©¦£˜„qdZPMKLU^ekq”¨—…vognƒ˜¡£¦›†xvy|~€‚{smljhdaSA/6>FR^b]YVSPRUXblty}zuplgaO=346>IUUTUVXZ^cjt}ƒ‰•›¡¦¬§œ‘Šƒ€›¦¬²¬ ”—œŸŸž ¤©¤š“™”Šp`bp~Œ›©¬®¯¬©ª®²µ¸¹µ±°·½ÂÅÈ·¢“›¤«±··¶¶­¤žžž›š §®¿ÐÕµ–Š‘˜ª¿ÔÚààÏ¿µ´´¶·¸¹º¹¹¸¸¸¸®Ÿ‘ŠŠ”¢¢¢œ”Œˆ…|xx{}xphv„Œv_QONU`kpsunhaZRKC;<=?ACIVcged`[Zl}Œ—¢ –„{splihfb[U_kuk`XUQYiy†“›™›£«°²´¯©£—ЄГ””‰|q‚’¡©±³±°¯®¯°±³³´¶¸ºÈÚìÕ¿ªšŠŒ¡µÊßôîèàÒþÁÄÆÇÈÅÂÀÀÀÂÅÈ· ‰”¡¬´¼½¶°ª¤ž›˜•Š„zqprtojdWKK[kxƒˆ{vqoppw‚’•™›¢­·¤^]`ew‰“’Œ‡‚~yvvvuutvy|‡Š}pe]UYeptuuk`[\^dny€†‹‚zw~…‹”‚kWfvƒ–—’Љ‡…ƒ~{ywv€Œ™œ žŽ{ƒŽš¦©¬©–ƒ{||€…Šˆ‡†††š§ “†ŠŽ“¡¯·¸¸³®¨¥¢¢©°²®«©¨¨­±±¢”‡}s}¡£¤¢˜Ž‡††‹“š §ª¢šœª¸ÅÒß»‘ow~Œ¦¿Ä¾¸¯¦Ÿ¢¥¥¥¤ š”›¢©­²¯£—Œ‚yƒ›¦°´±­¯³¸¼À÷«¡—ŽŒ’Ž‹tq~Œ“•–‡…‰‹‹Š†~wpjevˆ“‘ƒnYY_emu{|~…‰‘š¢Ÿœ–†vqw}ƒŠ~l_acm€“’‹„wj_][_juuqnid```_\ZUMFWhx~……~xwxx‹“”–˜›Ÿ  ¤§§”|Œ›¦¯¸´±­¥ž ®»»´¬Ÿ†˜žžžš•—ž¥¬´··¶²«¥¤¤¥­µººº¿ÇÏÖÞâÔź·³ºÈÖȵ£™Š–šž¢›“ŒŒŒ‘¢³¶®§ž•’˜›™—”Œ‰†…†‡‡…ƒ‚‚‚‚‚‚{tpppsy{uplhedb_YSQPPRSV\aa[UPKFNV^fnng``bdhlorux|ƒˆŒ†xndafkotx~…Œ”œ¤¬´°¨ šš¢ª®®®¨ž•¨±µ¸¹·´µ¶¶´³±°®®®®°³¶·¸·µ³³´¶µ³²ª —‘‹ˆˆˆ†ƒ€ƒ†‰–¢°ÂÔÓ󯮯·¿Â½¸¸¼À¼¶³¶º¼¼¼½¿ÀÃÆÇÅ¿¼¹·¶¶±«¦ž—‘‘ŽŠ†ƒ|‚…‡‰…}trrrrrpjc^YUW[^YUSWZ_dimrvqmid`bippnljggjmnnnjd^bejqxzvsmf^]\]^`acdeffiloqsx‚”™žš—“‡†‹Š…yyx{‚‰‹ŠŠŠŠ‹’𢝻»´­§¢Ÿ¦­±±°²´¶´²¯¯®®®®¯°°²³³°¬¨¤ Ÿ  ™•”“”™ž¤«³±®¬¬¬®³¸·±«¦¢žœ››Ÿœ”Œˆ‡†ˆ‰‡{nkqw‰’‘މƒƒˆ’˜žŸ ¡¥¨«®°®«¨ ˜‘ŽŒŒˆƒ~€…ˆ‹Ž’•˜š›™•†ˆ’–™›“‹„€{}€„~zoe][X\ciihilpv‰’›¥¦¦§§¨«´½½º¶±«¥¢ž˜‹~†“™š–””””””–——’‰…‚„†‡ˆ‡zusqomlieba`bjry}|z„“‘Šƒ|‚˜ §­®°¬£š•‘ŽŒ‹‡whacdkt~ƒ†”œ¤¬®®®¯°²»ÃÎÝìòõøòìçäáÜÓËÅÀ¼¸µ°§”‰yvry€‡‹ŽŽŒ“§£——–˜œ¡£¥¦¤£ ‘‚sg[OC80(! "(07K_oy‚‹“›£¬³±¯¯¯°°°°®¬©¥¡Ÿ ¢¤§ª©¨¨®³¸ÀÈÈ»µ®¨±ºÁÆÊÉÅÁ»¶°´¸¹¶³µº¿ÈÒÜÞßÞ×ÐÐ×ÞãèìììëêèéëìåÚÐĸ­¬ª¥›‘„ugc`]\ZWOHC>:J[m}𤭳¶ºÅÒÚÏÃÁÎÛàààãæçãÞÖȹ°«¦œ‘‰‹Œ‰…|pd]XUZ_cehgedinsvzzupkgbehic\VQLE<3,% %0<5) !#&)& )4?EGHIJJPV[^ahu¬°´·»¿ÃÉÏÔØÜÞßàààäëòîåÜÓËÅÊÎÓÙßâåèêëíîðñóôòïìòøýþÿþýüøòìêéçæäãáàáãäâáÞÒǾ»·´±®¢•‰ˆ†„}vne]UMGA<60-+*7ES_kqpnib[XWW\afmt|…•š—Š„~„‰„~wsojd^_dicZSX^dinnljhfdgiiihijjnrv|‚‡ˆŠŽ•œ£ª°­ª¥š‰†„€{vogccdgntz„}wrrrojea]ZZZ[_bc`^^^^beiijknpx„𤭳¹¾ÁÃÊÓÛàåéíòöøûûùøðçÞй¸¶ºÁÇÐÙßÞÜÚÖÑÕÜãéïõøûúöñëâÙØØÙÜÞáäççåäâáßÕËÁº³ªŸ”Œ†‹•–lejoiaYUQKC:6669<>CGIIHD>730.010'"$%'(*-39AKTWYZZZ]cikllifefhlu~…‹’‘”™œ™–¢¯»¿ÂÆÉËËÉÈÈÈÇÆÄ¼·µ´´º¿Ã¿¼»½À¸­¡—Žˆ—¥±¹ÁÀ¹³­§¡ ž ¦¬¬ª¨¡™‘‰yqijqw}ƒ‡„‚}umhd`ekquy}€ƒ‚~z}…–›—“Žˆ|wsw{‚œ¨³¾½¹¶ÁÌÖÞåéëìïòôö÷÷ôñíéåäääÜÕ̾¯£šˆ€x~„Š—–„‡Œ’’’‘Œˆƒ}wtqnsx}‚ˆ‡‚}sfYQJCA?;3,'" "&/7?FNRUZdnx‹ŽŽŽŒ‰‡‚}xvsld[]`cfigaZ[afjnqnjjmqux|ˆ—¥´ÂÏÖÝÜÖÑÎÍÍÖÞäääàØÑȽ³©Ÿ›¦±¾ËÙ×ÑËÊÉÆ¿¹·¹º½ÁÄÆÇÇÄÁ¾»¸¶µ´°¬§›†xqlfjns}‡Ž‘”™ ¦©¬¯¯°­¨£˜’ŽŠ‡…ƒ„‡Š‡‚~wqmmnkd^ZWTX]_^\[ZZVQLJIINSYahou|yvspmkkjf`Z\_agmrtw|ƒ‰’œ£ŸššŸ¤Ÿ”‰zuzƒ†‰‹ŒŒ’˜Ÿ¢¦§¦¤¢Ÿœ˜”‹‡†Œ’–šžžžŸ ¡¤¨¬²¸¿ÀÀÀÀÀ¾·±®®®®®®¬«§›‹ŒŒ•šŸ¡£¥¥£¢žš–œ¢§¨ª«®°¬¨¤£¢¤©®°°°²³´±¯¯²µ¹ÀÆÃ»´´´µº¾½¸³´¶¸´±¬¢˜‹‡‰Œ–›¡¤§§¥¤Ÿ˜‡~utrtw{xrlga]bgheadjponoruuros{ƒ~xqqpnid_ZTME>>>?BEKRY\^```beilptttsokgec`^\\\]^_ckswxx{~€†‹‘“”§²±°±²´±¬§¤¢ ©²¹¼¿ÃÉÏÎÍÌ¿²¦¡›˜˜˜˜˜˜š›››šž¥¬®®®·ÁÇÄÁ¹©™Œwvvuuty†’žªµº½¿½»»¾ÀÅÌÔÑÎËÊÈËÒÚØÒÌÆ¿¹¯¦ŸŸž›˜”‘Ž‘‰ŠŒŽ‘‘Ž‹ˆ…‚‚„†‡„€zmaYVRPNMSX`kw}~~zvqqpqqrrrrtuvvvuutqmitƒ’”•”Šˆˆˆ‚{tvwvmdbehnu|{zyyxz~…‡Š“œ¤ª±³²²°¯®¯°²»ÄÈÈÈý¶³°­§¡žžž¤­¶·¸¶­£›“ŒŽ“˜šš——™š˜•’’’‘‘Ž‹ˆ‹Ž‘‘’‘Œ‹‰ˆŠ‹‹†„€ztqnmt|„–Ÿ¦­¬ª§¡œ™™š—”‰{{|~…‹ŒŒŽ‘™¡§«¯­©¥¦¨«¬­«£š—˜˜Ž‚v|wmpŽ˜Ÿ¦¦¦¢‘€rg]ZZZ^bdddeghjlnswyyxtld_]ZYXVQKFB?GS`m{…ƒ|rio{‡Ž”—–”–›Ÿ¡¢¢ž›—–”’ŽŽ‹ˆˆ™ ¢¥¨«®®®­¦ š—““””—𣩝¶½ÃÇÌÌÌËÀµ±¹ÁÌÙæëîïîíêæáÞÛØÏŶ´²²²°­ªªª«­°°ª¤¡Ÿž›˜•’Ž‹ˆ…‚€~…Ž–ž¦©ž“ŒŒ‡€z{|{ywusruxzzzyvspnlgb\YWUTRQPPQRRW[_ejkihiklquyz|~‚…Œ”œ–‹„}|ˆ˜‹|okhgiju‡˜ž¡££¢ ž›–‘ŒŠ‰‡ƒ€€‚ˆ’›£«³³´°¥š’Œ††††††ˆ‹Ž‹ˆŠ‹ŒŒŒŠ„~€†‹ŒŒ‹‹ŠŒ“—› ž››š™–“މƒ~zw…’››š¢§¥¡žžžžžž¡§­®®®¯°¯«§¨«®¬ª¨ ˜“”–˜œŸ     ¡¦ª­°²¬¥ž›˜••”•—˜š ¥©­­®©ž“”™žžžœ˜Ž…ˆ‘š„{‚ƒ€‚…ˆŠ‹‹Šˆ…xqjcfinw€„}xqknsw‚’‹„{qnmkgb^[WWYZ]`clt|†‹•šž¡ Ÿ›™”‰…„‰‘™ ¦­©£›™—”‘’•˜¤ª¦¢ž—‘‘— ¢¤¤¤¥©­°³¶¼ÄÌÆÀ»¶²±²²¯­ª©¨©¬¯®«¨¤Ÿš™˜™›œ—“ŽŒ•Ÿ§¨ª©¦¤¢ ž£¨«¦¡žžž¢§¬œ‹zrjeb`]ZVUTVdr|‡…‚~zustvtrojd^bgjjjihfda^[XWXZ\bhmrx}‚…‚€€…Œ“–˜™”‹‹Š‘–Šƒ~{{z{||ƒŒ•—™™•‘”𡤥¦Ÿ˜‘‡}{ƒŠ‘˜†~yttx{zyxz{~‡™¢¬¬«ª¨§¨­³¸¼¿ÀÀÀÆÌÏÎÌÈ¿¶²°®¬«¨¢›™›œ¢ª²ª¢›—””™–Œ€€‚Ž™¢¨­®®®¯°±µ¸»½À¹®£ ¥¬®©¤ žœ›š™˜–••”–˜š ¦«§¢žš•’ŒŠˆ…ynd^XVVV\digefmssojnty†‰†ƒ‰–£´Ç×ÓÏȸ©•‘—›•ކvf^^^[XVSQRX]fs€€‚ƒ†‰Ž•œœ›š˜——™›š•‘ˆ~tgZNF>71++-.011.+.8AGLPXajv‚¡²ÁÎÛÞßßÙÓÒ×ÛÖÍŽ¶±´··¶´¯§Ÿ £¦±½ÇÎÖÚÝààààààÝÖÏËÉÈÄÀ»·²¬Ÿ“”ž©¬­¯±³³²°¯­¬¥—¥³»º¸³ª¡•‡{}€}o`RC558;AHJC=71+-03951,.9DLSYQG=<:>JV\_ba`adfku~€€{vsw{~~~|xtz‡†…‚~z|„‹–›Ÿ¢§¬µÁÍÊû±¦ ¤¨©¨¨¤Ÿš¥°»ÇÒÚÝàÖɼ¿ÂÆÏØ×ͽ¹¶µ´³²°²¶¹¹¸¸°¨Ÿtokqz„‡‰‰…‚‚‚„†ˆ‹Ž‘”—˜˜˜•’Ž‘”¢°°žŒ~sgjmokheedmz‡ƒ~{|~|yu £¤£—–› §¯·µ²¯¥š‡~umea][hu‚…ƒzwts|†Šƒ}xvtvx{€…ˆˆˆŒ”›¢¨­Ÿ„}wqmib[SQNNSX_irwz|‡‘š¢ª«¥Ÿ›—”™ŸŸž›š˜–”–—–ˆ{uy~„{yyz~†Žœ®¿ÉÑÚáèëéèæãàâãæðúúïãÖÆ·°ª¥ž˜–™›§·ÇÆÅý·®žŽ“¥¶¼Áú±ª¦¡¡£¤Ÿ™“Œ‰‡„wof^WZ^bfkmnnpqs{ƒ‡‡†„‚€€€zupmikpu‚‘†{pfcddb`]YUTX\`bda^]`djx†‹ŠŠ…zuqmkiijjkllhda^[\`cp€ŠŠ—ššš §®§Ÿ™”ŽŽŽ‹Š‘—ž¨³·µ´ªŠ…~{wpjkpt~ˆ‹ˆ‚zrx…‘›¤«£œ–“’˜ž£¨«£œ—–”–™œš——£¨¬±­¥›š›ž¢¦ª¯¯®®±´·¸¹¹¹¸·¶¶ÀÍÙÜÞÝÔËÈÈÈÊËËÀµ°µºÃÎÚÑõ­¤ ¤¨©¨¨£—–•““’Š‹ŒŒ‘…{peZURPIC?ACGLQZdnw€‡‡ˆ—¡¡Ÿœ‘…|||}€‚{rh^TMMNPSVSNJT^gjmlhehnt}†‡{sllnpsvxxx}‡’¨³²¯¯¯°³ºÂÆÉÌž·´±±±²¯©¤¡ž£©©£œ—”˜¢«µ¾Â¾¹±§œšš™•‘‹ˆŒ”›¡§«¨¤ š”•šŸ™‡wsuwy{|€…‹“›¡¡¢œ’ˆ‚~zƒ‡‡ˆŠŒŽ’”‘Œ†€„‡”š„}~€„–ž¦®¥“†yrrrpmjgddiond[OC7=DLWbgedca`bcdddflqyƒ’•—ˆ‚~y|†ˆ‹‘”–™›ž£©¯¯°­§ “osz‚§ª­©¢›œž¡§®±±°³¶ºÄÑÝÞßÝÔËÎØâæççÚÍÃÂÀ½¹´¯©¥©­±²´¯§Ÿ™“‘”—˜š˜–”–—˜›žŸžœž¡¤¨­²© ˜“Ž”™Ÿ¤ª¥ š“‹†ƒ€xmbUHAN[l–•Š€‚„‰‰ƒzodefedba``gpz†“Ÿ¡£¡š”’’’“”“Œ‡‚|vqlhcaceiovwvvsppŽ›¡¨¡‘‚~}{yvsoprt|†ŽŽŽŠ€vstt~‹•އ€zttx|zxw|‡Ž•˜˜˜”‹€vptx}……„……†ˆ’–˜šŸ¥ª«¬ª¦¢¡¢¢¨°¸·¶³©Ÿ”Š~€}zy}‰˜¦¬­®žŽ‚‚‚‰™©ª¤ž§±º¿Åø­§¢ž £¥©¬ª¡™“ŽŠ—¡¤¥¢ ¢¥¨¥¢   ¢¦«ª§¤™Žƒz€”¨¯®®®®­¤›”‹ˆ†„‰Ž“˜Ÿœ™“Šƒ†‡„}vopv{zywnd]]\bmx…‰†„ƒ„†‡‰Š‰ˆ‡€yuuvusrokipw~…‹’”—›ž¤ª¬¨¤ž—‹‡„{wsopsvŒ˜“Š…€„›œ›š—•–¤§¤¢ž˜’“”– ©­ª¨¡˜Ž‹ˆ‡ˆŠ“˜ž£¨ª­­ª§¥¢ ¤©®¬«¨œ‘Œ•Ÿ¬¹»¼½¾À½¸²¯®®§Ÿ™›¡ª³³¯ª¢˜‘—žš•’Œ’š¡¡¢ž‘…|uonnmjheedefffffffghjnsyzz{{|}…‚{snjgow{xurolnopjd^VNGA;AJR\ekfbacdlv€~~~~€…‰„}voiflsz‚Š‹‰ˆ‘•–˜š §±¼¾¿¿¾¼ºµ±µ¼ÄÊÐÒÊÁ»¸¶»ÁÈÊËÍÑÖÚÜßÙÏŽ¶°°°³¸¾ÀÀÀ¹²®ÁÔßÞÜÔȼ¹¸¹º¼·«Ÿ–‰Œ•˜›š”ŽŒŒŒŠˆ…‚~{zxz|~ƒˆ”˜Ÿ¥ª¬®§ž——˜˜˜˜“‹ƒ{skkjha[VRNLJHS^howyxxurpqrqmiijjlnplheb_`eihfdfgjpwxuruy|„Œ“˜œžžžœœ¤¬±±°©™‰ƒ€…Š’”™¡¤¨¤Ÿ›š˜šž£©¯¶´³±°®±·¾¼·²¥—‹‹Œ—ŸšŽ‚~{{‚ˆŒŒŒ“–—‘Š…ƒ€ƒˆŽ’“މysnic]WWVYdny„–šŸ ¡£§«ª¦¢­»ÉÑÚßÞÜ×ÎÆ»±¦ª®¬Ÿ’‚p]Z[\bhkgcgpz†“ §­´¹¾ÁÃÄÀ¼¸¸¸¶¯¨Ÿ–Œ}jWK?542* %2>IIJQbr‰£½ÍÜèèèçæäçìðíêæÛÏÆÄÁÃÇÌú³¶¹ÀÏÞäääâáßÞÜØÌÀ»¹¸¸¸¹ÃÎϵ´º¿ÌÛèèèèèèëïôðìçÞÖÑÔ×ÚÝàÕǹ¨–†{oklld[QG=9DOI4 "1;ERap“¤¬´¼ÂÉÑÛæëíðëçãâàÙ˾²§œ‘†|wqmjhfdbZRMRXXTQC12HYYXWTRXajpwzsld\TV[`ab`QC6.%%*.145420,'  %8JW^euˆ™ ¨««ª³ÂÒáñþüùõîçêôýÿÿþùóìáÕÒÕØÕÒÑÕÙàíùþýüðâÕÚàæîõúüÿÿÿÿÿÿÿÿÿüöñôúÿÿÿýöïîñôôôôëâÙ͸°¨Ÿ•Œ}ncint}†tX;& "4FYk}†”‹ueUSWZu’­¾ÎÒÄ·©›‘–˜‡|vme[RKLNS_lmjfedbP=9K]effmu~Š–›”‚vjtƒ‘ž¬²®©¡”ˆzk]ZVSRPNJFC@=<;=DKVdqoicRB5422229BKS\cfif^VX]bqŽž®¸º¼ÀÄÈÑÚàààæñüÿÿÿÿÿüóéãáààààÚÔÎÇÀÂÍÙáéðöûÿÿÿÿÿÿùñèëîñòôöúþýúøúûýþÿÿÿÿþýüèÒ»œ}cTDBGLRY[H6$ $3CJE@7-#   %,34+"  4EVg}”¦±¼ÇÓßÜ×ÓÊÁÁÎÛÞÛØÐÈ¿¸²¬§¢™‚xpiijiihgffc_]^_bhnld]cksvz{zxyzzvqmnome\QC558:742222229BJQWV>& #,6FVafkqv|ˆ“™Š|z‡”¥¶ÇÈÈÊÑØØÏÆÈÎÔßëôôôöúþÿÿÿÿÿþýüúõñôùÿþüùæÓÏáòúýÿÿÿÿÿÿÿÿÿþýüòæÚË»¹ËÝãáàÝÚÖȹ­¦Ÿ §­©¤Ÿ‘„xlaXRMGB=0# *8FG?71+%#5EP\[WU^gk`URTVY]`UKB;5/+'()*9IXiz…‹‘Štojiu‚‡…„š¦ž–“¡¯¸¼¿ÃÅÈÆÅÆÍÔо«ž“ˆ–¤±²´³°®¯°°¸ÁÈÈÈ¿ª•–¢­¹ÆÎÅ»´±¯§“މ‡ˆŠ„ue{§ÒÛÞáêóùúüøòìòùÿÿÿÿÿÿÿÿÿøïæÓÀ¯ ’Šˆ†Ž˜Ÿ–Ž‹“›¨¸ÉÒÚßÜÚÔɽ±¥˜˜š›š™ž±Ãʬ­±³³²®¡”„q^PC6301:DD>79637?HQYbdecYOGA;4-&# +1361--=MY_ejotz€ƒ‚€ƒˆ‰ƒ|tliv„—žŸžž•Œƒ|}…Œ‹ˆ„‹“­¾ÌÔÝàààÔÇ»¹·¸»¿¶§˜¦¸ÉÒÛßÜÙÑŹµ²±ºÃÊÎÓ̾°¨ ›œ¤¶ÈÌÆÁ¬”}zxtnhdb`hq{ƒ‹‘‘’Žˆug[gsypf`\Xh}’£´¾¸²§—†}vpz…‹Šˆ‡††Œ“𢩝´¸¹¶´½ÈÔÚàáÖÊÈÑÚÞßàààÜɶ|ZONN_pƒ†Žœª­«ª¢š‘‚sg`ZY[\]^]]\_gnv‡†…‚seYQIDA>6-(6DJE@FR_is{vqpv|€€|yunfhz‹œ­½´¦˜†tgdaenwtpmoqw‡—¢©¯¶½ÅÆÇÊÒÙàåëàÒÅÚðÿÿÿïϯ½ÙôéßÔǺ»ÈÕãñÿüùöïçÝÎÀ¶®¦¡œ™¡ª»Ìƹ¬­®¯´¸µ«¡v_I3"""3X~ƒzp}Š••–“‡{tfXMRV\dlic\enwwxumf^TKB95I^klnlifa\WRMNV_`^\XSRg{fNFHJWeqomib[WUTbsƒ“£ªŸ”—£®±²±§”Žˆsfs†—–•–œ¢®ÁÔÏĹ·µ³±¯§›¢¿Üʹ««ª²ÁÐɺ¬¯±±°®²ºÂÍÙäÕżÂÉËÉÈËÍÐÐÐ;°³ÊáÜ̽·²²ÆÙÛɶ°°°±²¯¢•™²ÌĬ” ®¼ÉÕÚÕÑÖßèÞÔÍÐÓÖÛß×É»¾Á²£“‚pgd`\WWn…ŒxdYUP\jurnou|tcRC4'5BE6('.5EVeca^[WTQNQTURNKJHMU]TI?BFLXehfdqŠ…ƒ„†‹”œ›—”ƒreb_\YV]gpqrv…”£°½ÉÕàààßÚÖÙãîôúÿû÷ôôôñëåØÈ¹»¾¿¹´¹ÈØÍ·¡Ÿž ¦­±³´²°®´»¾¶®²ÄÖ×ÐÈþººº³¡m\UPMRW[]`_^^emv‹““”—› }o…œ«¬®£’€ˆ”œš“jdfhgfgnuwmdcglw„‘‘’”›¡¨­³¼ÇÏÍÊÀ§Ž~xqmjg`YVZ^cio}œ„{xu{‰—¡ª²±°¯­«©¨¨µÇØÏÆ¿¼¹½ÇÒ̸¯¥›™œ£ª¢”†znguƒŒ’’’’š¢ª°·ÄÜô÷ïèØÆ»ÍÞæáÝÒ³«¤ ¨°¸ÁÉÁ° œ™š¢«®ª¥Ÿ˜‘ŽŽ­µµ´§“…™¡©¨˜ˆ}umsz„ˆˆ‚|umemxƒ‹“šŸ¤£ œ”‹{vv‹–Ÿ¨¬­­¦Ÿ–Š}sjb\WSSTV[`_YS\ht‚™šœš–’ŒŠ‰ˆ‡‡†„‚€}yvk`XXX]fpv{€‚€{uohb_^^djouz{xvxz|…••”ƒwpkfffea^]_`bdfhikmot|„‹‘˜–“‘ˆ…ƒ€}|||}ƒ‰™£§©ª­°±«¥¡ ž ¢¤¨«¯´¹ºµ°¯°°³¶¹¼¾ÂÆËÑØßààßÛ×ÑÈÀ½¿ÀÈÓÝáåçæäàÛÕÏÉÃÂÁ¿¼¹´®§¨ª¬­®®®®®®®¯°°®­ª¤ŸŸ£§£œ–“Œ†zxvz~‚…‡‡„}xssttvwxxxwutqlhaZRG<:CLPRTRQNF>=CHPX`hqyyz{}~}||wrmifcb`_]\^accdfkpx‚‹‹Š‹‹ŒŽ”šžž£¨«¤œš ¦®¸ÃÁ½¹·µ²­¨ —‹Š‹’™ §­®¬ª©¨©«­¬©¥¢Ÿœ™•’’’’’’”˜œ¢©°°°®©¤¦­µ³°®¯°±´·³¨ž›šš¤­¶¼ÁÇËÏǺ®«©§¥£Ÿš••––“‘ކ~xtqw€Š“”‰~si_\\\YVSRPPPPPPPNMKFABKS[ahlqsrpmhb_^^`accdfjoty~ƒˆ‹„~xrlntz|~€€€€€€‚„†Ž–žžžžžžœš˜’Š…†‡‹’™ž¢¦«±·º¾¿¼¹¸¸¸½ÃÉÎÔ×ÔÑÐÐÐÕÛàààààààààÓ²´µºÉÙßÝÜÕÌľ¸µµ¶¶¶¶¹½ÀÃÆÆÁ¼¸µ²³´´²±®©£œ“Ї…„ˆ‹’‰ƒ~xrkd]YVQJDJT_ju…‹ŒŽŽ~oc]VVXZ^cecaaabbbbfimsy{yvtqnmlkgbabdca`bccba```abbdfimquvxvrnqtw}„Œ–¡«³»¿Âÿ»µ­¥ž˜‘‹„}yuv„’–”’–šž¡££¡ŸžžžžžžžžŸŸ ˜“ˆ‚€|wrqstvwx}†”™›œ›šš—••™œžžž¢§¬³ºÀÀÀ¾¹µ®¦ž £¥©¬­ª¨¨¨¨°¹¿¹³¯¯®¯°°¯®®®®®®®®®®®®­ª¦£¡ž›šœžžžžžž›š˜–“Œ‰‡„}xtpkjifb^YUPMJG>4...4>HQZcipw‚˜£®®¬«¾Òãïúÿÿÿÿÿÿöîçäá×ų¡~tkb\UQONValv€Š”œ©¶ÀÈÐÐÐÎÇÀ·®¥˜Š}rh_ZVM>/#.Da}•¬ÂÏÜçìòôôôøüþúöòîéâÚÑÒÓÕÙÞàààæî÷ûýÿÿÿÿÿÿùïåääãâáÜÐŽº¶·¸·´²±´·¼ÁÇÏØßÞÝÚÖÒÕÞçèèçàÙд¤’€o_O:%  *:J[n‚Šˆ†’£´²±±±²´¸»·°ª›Œ€€€€€€{ung`YWUV[_VI;BKUeu{vqlf`m{…ƒ„†}pcehlw‚„|sgYKFA@IR^m||riebagmnid`^\[Z[agmu}€€€ˆ’›¥®ºËÝæéìèäáìøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýüþÿýøòïíìçáÜâèéÝÒǽ²§šŽ‚vmga]YVSQM?1$  #(,,'#  =dx‰}n`P@5427>F@;4)!>[hjlnqstvx{„Š„vlz‰•›¢¦©¬­®­¦Ÿ¦¯½Ïá×È»ÁÈÆ³ “‹ƒzqgdbdr€š¨­°³´µ±¢“‰ƒ}ulc[TORUVVVY]`^]_lx†‹’𢫴¾ËÙâåèî÷ÿÿÿÿÿÿÿÿÿòßÍ»ªž£©²½ÉÎÑÔËÁ¼ÂÉÔçùÿÿÿû÷óíçßÕËÎ×àëöþúööúþüøô÷úû÷òåÊ®šŠzjZKIGEDB8(  (/6=93-$  '6FQQRYfr{ƒ‰zjaab^YSW]cmw}|z}…Š““’““”œ¬¼Ê×äääá×ÍÎÚåìðôäÔË×âìõýÿÿÿÿÿüñæßÝÜÔÊÀÂÃÆÑÛàààààà×ÏÆ½µ¬¤œzg\RKPU[cjjgdVG;<>DTcbZRVY]ciq}Г𢕆yqjhlqng`ju€‚‚‚‚~ƒ‰¤·ÅÆÈËÏÔÚâéíñòìæÔ¹ˆucRA3*!,E]dfinsuroeVGLU_`a^QD8.$.=MU]^N>/"'04.)! )3=FLSe{’¤¶À¯š¦³¹½À»¶¯¤˜”˜›¦µÃÇÊÊ¿´¯±²³µ¶¸¹¼ÅÏÛêúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýùõ÷ûÿÿÿÿÿÿÿÿÿþýüêÖ¯œ•¤³¾ÉÓÌ»½¿¿¾¼´¦˜…r_O@9?FA7,-037;?@BFNUVVUUTYj{tZ?74358:::9761+'9KZbjbK3...,+***-1589:`†¡—…}€…Š…|ume[QKIFl”±¦š”””›¦°§Ÿ™ž¢¢ž››žœš‘‰Œ®¶¸ºÂÊÏËÆ½«š§ÄáØË¾²¥¤±¿·£Ž’™Ÿ£¨§Ÿ—¢·Í¾ªš¥±ºÀÆÄ½·²®©Ÿ””§¹ÊÚêÞο¶®¤™Ž…|suy}~†—©§—‡‹”žœ˜”˜¢¬®®¯·¿ÊàõúòêãÝ×Ðɺ³¯®®©¢œ“Šypmopu|‚‚‚€~}{ztldy›‡s_M;31.>O\\\_ekuŽ™£«¨¥ –…}vnf_ZUNE=CP]hs{wtstty†‚~‰”£ª¨£ž“†zoc`is~Š—Ÿ¦®ÀÑÜÜÜäñýþýûøõöúþÿÿÿöíãÙÎÉÌÏÓ×ÜÖÎÈÈÈÇÆÄÄÄÄËÔÛ뢻ÔÝÙÔ¼Ÿƒ“£®®®¬¨¤¤¤£›“Œ‡‚wgVOKHUakklqz„‹‘– «±±°¦“~‚†•¤®¦ž’‚rf[P[gmaTORTZbjgda\XY`foy„‹’•ˆztwy}‚†vdSB0$!'4A9.%$"*ITZ]`]YULC>>>CKSY^a`_`ejs€Œƒuga\[fpmaTV\_ZTQQRWajvƒ‘™¢­¼ÌÓÑÐÆ¹¬«ª¬´¼ÀÀÀ»´®³¹¿ÉÓÚÝàÚÓÌÊÉÊÑÙÖË¿¸´°¯®®®®­¬¬¨£žµÍáäçàͺ²°®«¨¥¡ž¡­¸ÅÒßààÞÒǺ¬Ÿ¢¦Ÿ˜ƒvoopruxvusoje_XTRPMJIPV[[\VNEINSVY\`edb`_^_ekoprtvxuqmhc__^YQIFDCGKOOPNJF?6/37AZrƒ‹“žª·¹»½¾À¾»¸³¬¦ž–ŽŠ†‚€~„Œ”Ÿª´¼ÄÆÃÀ¼·²µ·¶¯§§®µ¶¶¶¹»¿ÊÖßåëéäàÞÝÙʼ³²²·½ÄÆÇÇÄÁ¾»¹¹ºº¸·µ¯©£œ–’Ž’—œ¤¬±±²±¯®©¤ŸŸž ¥ª°µº¶±­¦žœŸ£§«°°°±¸ÀÇÎÕÒÊÁº´­©¤Ÿ—Šˆ†|wwvx}‚…††|wpi`TGEINOPPPPQSUSNILQUSQQQRTWZWSPKGCA?<9630.37JU[\\`di~’¥·ÈÖàêììíôúÿÿÿÿÿÿÿÿÿÿÿüôìëïóö÷øûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýùõ÷ûÿÿÿÿÿÿûòêÜË»¶²®¦ž™˜˜’‰€p^OONI=2#$8Phv‡vlbXSSTY_fxœš–ƒ}zvx{}†‚tedjponkP4-Mm{}~}|{ocZTNQX_abaVKHUchhhr}‰Š‹Š„~xsm`PA@?=:7=JWYXYYZYUQWco^D*%!#4FKGCCDDEFHPXajtvvv„“¤ÁÝëéèæåäçêîõüÿÿÿÿÿÿÿÿÿÿÿÿÿÿøîäêðõùýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøñíôûÿÿÿÿÿÿÿÿþýüøðçÙǶ¦–†xkZF28Pge_XJ;0*$!!$'.66,"  &-48<;5/6@ID>>LZbdfhijpuvogca`kx†Œ’·ÒãéïëæàÛ×ÒÌÇÇÍÓÙÞäáÞÝâæéëìäØÌ¾¯¥§©²ÂÓÛàäÖÆ¹¸¶¶¶¶¾ÉÓÄ´¡…iZ^ahqy€‡Š‚zusrw‡Œ“”–˜œ¡¦¬²°¯¯²µºÅÐÐÊĽ¶¯«¦©¸ÆÍÏÐÌÈÆÖæòøýÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷íãâáÞÚÖʸ¦“€ooptƒ‘–”’’’“˜ŸŸž—‹m[HOV]jvvk`P=*%! &6EOZZNADLT`lr`NCBBA?>N_jaYM<++3:DOUF73@LXdo†ž³¸½ÂÅÇÊÍÐØáèèèìôüÿÿÿÿÿýïáØØØáïýÿÿþ÷ðíîðñóôòñîàÑÊÎÓØÞãÓ¿««ª¯¾Îʺ©•me]\gqy~ƒ†ˆ‹’™¡¬·»ºº¯¡“ƒredbYJ:432EXedb[NA81*38,!"&*8GSUWYZZZZZ`fh^UH5#$-6?GORUSLFEFFR`lry~‚…«¤›“Š‰ŠŠ†€z}€„—¡¬¶ÁÌ×ÒÍÇÄÁ¼²§ š”™ž££¤§¯·ÁÌ×ÛÞßÔÊÁº³±³´²°¬œ‹‚„ˆŽ“˜œ¡¦«¬©¥¡˜¢¥£¡¥·ÈÖàêàÒú°©¥¡¡¢¢ ŸŸ¤ª³ÃÔßãç×Á¬¾ÏÞäêéåáØÎÄÎÙßÞÜÑ»¦š“ŒŽŒ‡‚}|xsnu}~{vnf^ULE?9869?EJPVdt‚zurpn\J93-(# #&$#!-=A?><;;<>@CGRappol]MB=866630/028IYiyˆrguƒ‰ƒ|ˆ‘‹ƒ}~ƒ–ž¥« ‘…™¥³Â·¬œŠ{ƒŒ–¤²´¯©ª«­´»ÂÆÊÉýº¸¶ÍãôôôéÔ¿®žŽ„ysw{zwtž¾ßùúüùóíìììììíîðîéåæéìììëæâÛÏý¸´®¨ŸƒhY[\q¯¶¹»¶±¨šŒŽ— “„tW;$ ,../38IVabdfikuƒ‘˜Ÿ¥¨«ª¥Ÿš•™¢«¯²¶º¿½¹´²¯¯°²°­©§¦¦©¬­ª§§¨ª®µ»ÅÏÙÜÞààààààÚÒËž¹·µ·»À»µ¯­«¨ ™”‘Ž‹ˆ…ƒ€}}|‚Žš¤®¸½ÁÃÀ½»ºº·´²°¯¬¦¡™‘ˆ~tjaXSTVUTTX\`bcgt‡††vlifcb`^[XVTRMHC>83-'%#"%(+17>HQVXZ]`doz„™›™˜‘‰}zwurqppnmn|Š”˜Ÿ  ¦­³ºÀÅÆÈĽ·´³±±°­§ œš˜…{upkjhlsy€†‘”›¡¤¤¤¢ Ÿ¡¤§«¯³·»ÄÎ×ÖÕÏ¿¯ ’ƒvj^RF?CGNZenv~ƒ‡Œ“›¡§­µ¿ÈÜðÿÿÿÿÿÿÿÿÿÿÿÿÿÿûòêÜͽµ­¦œ“ŠˆŒ’˜ ¨°¶½ÃËÒÙáèèèçáÛÖÑÍ´¥zeP;'Az‰O-E[q…𡤧«±¶º½¿µ¬¢—Œ„~y„’Ÿ£§¨£žžž¤ª¯¯®°·½¼µ¯½ÏàààáâääääâáàààÞØÒÊÀ¶ºÁÈÓÝåæèéëìðôøóïçÓ¾­ “Œ‡‚p^M?1(# /Kp–¸ËÞêïó÷ûÿÿÿþýüýþÿýúøèÖŶ§›”Ž„wkigeb````\YTG:6>GSaobSHYjrnijlng`XG5% $*0-&  !*29=AER_p‹¦¹ÅÒÜæñöûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúóìòøýþÿü÷ñïíìñõõèÛͼ«š‡usrph`XNEHQZVSL4 !@[_baZRB++8BLWdqz‡ˆˆ†xi__^gt‚‚qdXOFGNU]ek_TQaq~ˆ’“’‘ŽŠƒufacdjqwiZWp‰“’’‹‡zl]J7*#%*,-/25532709HWft†Š‹ˆ†‚|v}„ˆ{od\TZgspkgda]WRQSTct€wmrŠ£ºÐåðøÿÿÿþûùúýÿÿÿÿÿÿÿÿÿ÷êÞÓÉÁÄÇÍÚçð÷þÿÿýéÕËÔÝçòýþýûòêãâàÜÔͺ£€slsyuh[URQYair|†š”Š€ˆ™ª¼½°£“‚reYOLIJLNOPPSUWXZ[]^_``[WUZ^enx|~€’¤³¹¾¿½¼¯‹sihfhkn^G0:744Ldqh_dr€„……yngghe`[]ac[SOPRf‹°¶µ³¨—š˜Ž„šº×¿§™¡ª·ÈØÎ¼ª­¯¯¬©¦£ ­¿ÐÊÄÅÖçðððåÖÈÎÔÖÐËÉËÌŽ´½ÆÌÌÌŸªª®²±°«”}sx}gF$:Sk}Ž‹mP9&#,9ESev{yx‰œ«ª¨¢’ƒxog[NDDD=-->KFA:2),4=>>=:7Q_flpsvromrv|„Œ‡}r‹¦¿ÌÙÝÕÎËÉÈÆÅÆÎ×àëõçͳ¿ÏÚÊ»®¦•ˆ‹Ž“©¾ÐØáߨÑÌÇø®¦¢”‡zphakv{zxyzzƒŽš±ÈÕÌýº¶Å×éíñõøûýþÿÿÿÿÿÿùçÔ¿¦|l_kw„œ™ˆxpkgzŽ¡´ÇÓÙßÛÕÐÅ»°ŸŽ‰•£³Ä¼µ±³µ°£—¨´¬¤–pJ666432454/)  +6@IGA:8750,&  #8GTabdfim{Ž¢–‘˜ž’†€~|ƒŠ‘”—–‘Œ˜¡¬¶ÁÄÇÆÂ½ÁÊÓÞêóðîêæáÛÒÉÎÖÝáååÜÓÖàêòùþîßÐöÀÜùÿÿþöîêîòôôôëßÓÌŽµ¬§¥¤”Œ‚ysvy~†Ž‰vpjir{ƒ‰Šƒ|ywy„š¢ª¢•ˆuaSX\bktuttqnnv~‡“Ÿ¡Ÿž¬¼ËÛëòíéâÙÐàñþýüøíãÌ®|iYURNKGRdvz}‚………„|pcmy‚uh_\Y`mz‡‹xkWB5,#&*, .AOOPZj{‹š§Œrcmv~†ˆ}}~„Ž˜’‰paWZ]_abirz‡”¤¾×éóýÿÿÿÿÿÿÿÿÿÿÿÿÿÿôèàààäíöìÜÌÜìùüþýùõîåÜÖÐÏÞìòíéÝͽÄÍÒËÄ·¢{k[PF@JTTE75:>IT_bejr{а§œ”Ÿª¤„dXXX\aejotw{th\XVU]ef]TMIDA=9636ALOMLd›Žumegowqh__^\XTW`i{‘¥›‘ °»ÁÇÄ¿»ÁÈʺ´±®¨¡š•‘”ªÁËÉÈÁ¸°©£œ¥¸ËÁ­˜œ ¡ ž¡¨¯¸ÂÌÎÏÎż¼ÃÊĸ¬·ÃÌÌÌÌÌÌö©ª«¯½ÌÒÍɺ²°­­­®ªŸ•™¤¯¿ÏÝáæà͹³µ¶¯§£·ËÓǺÀÏÞÝÚÖË¿µ­¥¥¨¬­®­ª¦¡™‘ŒŠˆ‚zskc_`bdgjr|ƒtf_gok`TI?5! (5BOJ@51--6@JU`]VP@1$  ,7COZRJGPYbhowŠ”™ž¢–y\G5#)1;Vp„‘ž¢¢¢®ºÆÍÔÚßãèîôøüÿÿÿÿÿÿÿÿÿúôñ÷üüõîñøÿ÷ïçäáÙɸ³´´ÁÐØ¾£‰‚‚…ˆ—©·µ³³µ¸±¦›‘‡|fP>4**05CRajsyz|„‘ž™‘‰…€‚†Š–¤³¹À¾«˜„mWYagVF=FPYbjpuzzz}‰•œŸ¢¡  ¦«­ª§¡˜Ž†xcN?DHMQUTRPPPRYafkokf`hpz¥§”‚€†Œup„—¦­´±«¤š‹®¶±­¥›‘‰‚{ywslfcbbhosqor{…“¤´®¥ ¬¹ÅÐÜÝÙÔÙßãàÝÕ¯§¦¦²ÀËÈÅÃÀ½¼¼¼´¬£›“ŽŽŽ‘–œ›š› ¥¤˜†‚~~~~~~|uopv}‚†‰„~yvs}‘¦¥ž—†~ytrrr•¨­±²«£žœšŠu`O?5?IQW]acf_YYl€“§»»´®©¥¡›–•˜š”‹‚xneedfkolgbhouz…Š…ueZOHR\fowtkcfkp{†Ž’—‹xd\UQUX\`eZG4@P_fnw„‘‘Šƒ‹• ±ÁËÊȽ¬››ž¡¤¨§ž•Š„—¡¦«¯°²®©£¬¹ÅÕåìáÕɾ²·ÀÉÙéòêãâåèï÷þöîçäáÝ×ÑÙåðêäâèíóùþÿÿÿïàÒÉÀÁÉÒÐÌȹªœ¢­¹´ª ›–Šƒ‰œ¯ª›Š‰†~vpmjfa\ZWWWXZ]_^[XTQMKIJMOJB:4/,5?@7-  (6DG;.***C_wvtx‚Œ‰~s“¡Ÿ˜†vaMA7/QckpsldadgbYOWai_VK=04FW`hmaTNQU^m{€‚ƒtf]^`fq|q`Q`oxtpv„“Ž„ydNBNZj}—›ž›™šŸ¤ª±¹ÁËÔàëõöøïÜɾ¶®§Ÿ˜†€|yŒ˜‘‰…‰Œ‹†‚„†—œ’‡‹ž²¬š‰’“ƒsmtz„ˆ˜˜“–¥³º½ÀÀÀÁÉÐÖÚßàààÕÊÁÉÐÐÆ»¸¸¸¹º¸­¡œŸ£¨®´¶¹¹·µ¸ÂÌì•›¥­§ Ÿ¥¬¨Ÿ•’•œ¡¤§¦£ ›•Š…„ˆŒ“–Œ€u{‚„€|tj`gr{skjx†ˆ‚{|~€ƒ†‡†„‚€~{xvngchlptwrkd^XSSRLA58?F[q€~~~~{wtokkwƒ†}tuy|wrr…™Œ{y~‚zqjjjknpqrrpmkighlqz‡“—šž¨²³§š—˜˜–••˜›ž £¨®´¼ÅËľ¿Ë×ÙÕÐÓÖ×ÖÔ×ÞåãÜÕØÜáâãåæèäÜÕÏÉÃÂÁÁÂÄÁ½¸»¾ÁÂÃÁ¹±¨’•›Ÿ“‡™š”ŽŽˆƒ~ztm_O>FNUUVN>.***5@JOTTOKIHHHHKZhj^QOQRQPTj€‚jSYk}}|{vrmf`cipqrpibbjrrpnvˆ™Ÿ ¢¢¢¢°¿ÍÕÜÜÒǼ±¥©®³»ÃÉÊÌÌÌ̹¢–ž¡ž›¢°¾ÀÀ¿¹²­«¨¥¢ž£©¯´¹½Àý°¤˜•¥®¼ÊÏÍÌÓÜäääáØÐÉý¸´¯¯®®®®«¥Ÿ—ކ}vh[Yajrz‚…‡‡…ƒ„†ˆˆˆˆˆˆ‡†„‚|yuryˆ“—˜˜šœžŒyihfd_[XVTNHB5)(4@>6.;ISRPRW[WPHLOSTV]o€…ƒ‚{smoqv‰†}uttu|„‡…‚ƒ…†}skrxyrkt‰˜‡znir{yqiow‚†Š”—˜˜¤³ÁËÕÛÚØÓÊÁÆÍÓÏËÊÒÙÕɼ¼¾ÁÃÆÄµ§žœšž£¨ ˜‘Ž”¡­µ»ÀÅÉËÆÂÂÅÈÏ×àÝÚÖÍĽ·±®­¬¢˜Žˆ‚‰Š†Œ’—œ ¤¨«¡’ƒŒ–š‡sq…™š’Š…€{zxvsqlf`ZUOLIIKLQYaa`ahnv~‡‡‚~wpihfipxvpjmpsuwyz|yupkeakv}~€Šœ­µ»ÁÊÒÔÊÀ»ººÁÉÏÌÊÆÀº¶²®§ž•”“ŒˆŒ– —‘‹Šˆ›§¬®°©¢¡®º¸©š›¡¦•„z‚ŠŒŠˆŠ‹Œvoopppponnopqw||xusqpeYRZbghhlqvwx{‰–œ˜• ±ÃÀ»¹º¼·ªž•ކ††‡–›œœžžŸ ¡£¥¥¥¤¨¯¶¸»¼¼¼¹²ª©ªª¦£ŸŸžœ™•œ©¶°¦Ÿ¤©¨ž”‹„}~„ˆ‡wtttmd\\\[[Z\^`bccbabfjkjjnswgWLLLE7),3:BISew~~‚‡ŒŒŒ‰urvywurw{ƒ†Š“˜ž ¡£¤¦¨«®«¦¢ Ÿ ¥«±¸¾ÂÅÈÌÑÕÛáãáàãèìèãàààâåçäÞØË¼¯­«§¡œŸ¦®¯°±´·º¾ÃÁ¼¸¿ÆÌÌÌÊÆÁÀÀÀ»¶³¸½ÁÂÄÀ¹³©ž•˜œœ–• ª¤š‘ŽŠ†‚}sdUMGCFJJE@@DHHHIJKJC=:::5/+,-048?IRY`fs‰…‡“Ÿ—Š|vpkfbdltncX\`ccdfkotx|…‡…ƒ€}zƒ‘ž ¡£¤¦¨­±¶»À°ž‘‘’“•–œ¤¬™…v‰‡vfm’’‘’ž©¯­¬´¿ËÉÆÃÂÀ»°¤Ÿžž¡¤¥¥¤¦©­±´¸°¦Ÿ£¨¦œ’’™Ÿ£§©¥  £§¤—”“‘‘“œ¥¤œ•›£©£žœŸ£ ™“•˜™—”“—›Ÿ¤©¥ž——–•”’“””„|unlrx|€„‡ŠŒ€uox‚pbm–‹€wrnjgdjqx|€€{urrrtvx{}~~~|xusrruxytonqtmdZ^ac`]g›£¢¢ž™˜¡«°°°°°°¼ÉÒĶ«¥žš—”›£«µ¾ÃÂÀ½¹´²¯­§¡ ¦¬¦˜Š‰Š‰|pm{ˆŒŠˆ…‚„ˆŽœ©®®®°±±±°®§¡¤®¸¶°­´»ÂÈÎɽ°¦“Žˆ„„„…††ˆŠŒ‡ƒƒ…‡‰Š” ¬›Š}{yreYY]`ejpv{}||xsnqsuz~zoc_]\aegb^]_`fnvy|}|z}‚‡ŠƒukptqdX_o„‰ŽŠ€w„µ¶³±±°®©£¢¢¢ ¡¦«±¸¶¯©¡™‘ދޗ¡¢ ž•‹wnkqx€Š•“ˆƒ‚‡Œ“–Šƒƒ‚…š˜Ž„‰’›£¬¯¦ž˜–”Œ‡‚}{~~…ޖЉ”Ÿ¥¦¦©¬®©£¢§¬«¥Ÿ§´Àº´¯¬©£š’–š ¦­»ÉËÀµ³´´ºÀÅÆÈž¸½ÆÐÍÊÇÆÄ¿µ«³ÃÓÀª™ §¤–ˆŒ˜£¢ŸŸ¤©ª¥¡¢¥¨Ÿ”‹†}{x€Œ™“‹‚q`USPRUX\ac\TLA659>IU_[VUWZVPKLMOOPS\ekpumbWPIFKPTX\_cgilmjghjls|…‡ŠŠ†‚~~}||yvw„«¹¹µ²µ··³¯·ÉÛÒÀ®±´··¸»ÁÇÄ¿º¾Â½·µ¸º¼¾ÀË×áâäà×ÎÎÑÔÛâçæäà×ÎËÉÈÏÖÝÞàÝ×Ò­˜“ˆƒ‡—§¡€}|{uomorj^QRSU^gmmnmkjjjid_[ZXVTRVY]gruohfffoy|wrmhimrqpoonoru{ƒ‹†€{~‚„„„|w}†ŒŽŽŠ†„‚€‹–œ˜”–œ£©¯´¬¥ŸŸžŸ¡¢ž™”ž¨±²´µ¶¶»ÂÈ·¦–ˆ‰”Ÿ£¥¦Ÿ™“’“˜œœ£©®®®®®®°³¶º½¿¸±¬©§¢˜Ÿ¦ª¡—–¡«¬©¦ž•ªµ½Å¸¯«¨¥¡žž œ—’‰wz~‚†‹–›¡§«¡–ŽŒ‘˜Ÿ¥ª¯µ¼½³ª¨¬°¥˜‹‡ƒƒŠ‘rjd^^^\WRRUX^dks{„‡…}ƒ†‡ˆ…}tnjfdb`RDFile created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/empty.wav0000644000175000017500000000153313263212010021000 0ustar aeglosaeglosRIFFSWAVEfmt "V"Vdata/‚‚‚€€€€€€€€€€~||{{||}}}~~€ƒ…‡†„ƒ€~}|{zzzz{}€‚}||}~€€€€~|z|€€€€€€€€€‚ƒ„………„ƒ‚‚ƒƒƒƒ‚€€‚ƒƒƒ}}||~€€€€~|{{{{{{yxwwxy~„†‰‰ˆ‡†…ƒƒƒ‚‚‚‚‚€€€€€€€~|{{{{||{yyz{}€‚ƒ„„„„„…†††…„‚‚„…„ƒ|zzzyxxxxy|~~}~€€€€~}}~€ƒƒƒ}}€€‚ƒ†ˆŠˆ†„ƒ‚‚ƒ„„ƒ‚€}|}~}{zzz|€€€€‚„‡‰‰‰†~{xwxyyyyxxx{€~}|||~€€€}{}„‡‰†ƒ€€„‡‡ˆˆ…‚ƒ…†‡‡‡„€€€‚‚‚‚€~|ywuuux}ƒ†ˆˆˆ†ƒ€}{xxwwyz{||~€}}~€€€€‚‚ƒƒ€€€~}|zxxyz}€ƒ…††ƒ€„†‡…ƒ€||}~„†…ƒ„‡‹‹Š‰…€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€mirrormagic-3.0.0/sounds/snd_classic/klopf.wav0000644000175000017500000000360013263212010020752 0ustar aeglosaeglosRIFFxWAVEfmt "V"Vdata~~~~~~~~€‚‚‚‚‚ƒ‡‹ŒŠˆŠ‹‹ŠŠ‹Œ•› ¥©®³···¶´³ªž’}iVI<1'0@Sfy‘¨······¬Ÿ‘|gYTOVal^OFLQc‚¡¬¯±°°±´¶······················¡€^M=.$"+/01Po„€|ti^VOG6%  /=KXakmllZG6/)+4>L\lwž¯···················²¥™‘‰˜©µ«¡qSC90?O`tˆ’’’‰~sX>( !1CUjŒŠˆ†ƒzrke^^djlllptx…ˆˆˆ|jYH8,.0;Qgœ···¶µ³ªšŠukaVRUXh™¥¯···²¥™Žƒyzzyxwy}Œ™¥¬³¶³°§šŒvllllllnqtx}~}zw|‚‰ˆ†…ƒ†‘¦¯···µ®¨¢žššš™—•’މƒ|uqnke_WL@;;;BIMKJKNQUY\ckonlieabcdlsz€‡ˆˆˆ‹“”•—£¨¬°¯®®®®¯°°®¬ª¨¦£œ•‰ƒ„†ˆ„€~~~€„ˆŠŒŒˆ„~wqkf`][YYY\cjr|…ƒ€~~~‚Š’™ ¦¥¥£œ•Œˆˆˆ‰‰‰†~vrqpty|wsnida_^_`aabdjovˆ‘™Ÿœž¢§¬²··············¶²¯¨“ŠywuuuvtsqomjaYW\aeillljaXRNJMPQNKHFDCCCJRZfr{~‚‚€}|wronnprtx{}}}{ywy{}…‰‘“•–› ¦«°´µ······¶´±®«©§¦¦¤¡Ÿš”“”•˜œ ¢¤¤ œ”Šxrkd]XUSPLIFCAFKQX`ehlmmnpsuwyuqlhdcgknpsx~ƒ…‡ˆˆˆŠŽ’˜Ÿ¦©¬¯²µ´±®©¤Ÿ—Š…~~€‚„†‡ˆˆˆ…~{xvuttttsstvyywtrpmnpppponlmmmortuwy{~}}}zxvusrqpppqsvz„Ž•šŸ¤¨«ª¨§¦¥¦§¨ª­­­¬«¨¥¡›•‘‰„~xsnllle^WQKGECGKOSWYYY[^`dinu|„—ž£¨¬°´µ·¶´³±¯®°²²°®¬©¦¡›”‰ƒ}xvvvtrpppooopppqqrrstuutssuvwy{|}~€€ƒ†‰‘‘‘‘‘‘‘‘‘‘‘Œ‰…‚~zwtrpomlnoqrstuvutsqppppqsux{~€ƒ‡‹’“”“’‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘Ž‹ˆ…ƒ‚‚‚‚‚‚ƒ„…ƒ‚€€€|xtqnjgdeilllmoprtvx{}€‚ƒ…†ˆ‰ŒŽ‘‘‘‹ˆ…ƒ~€‚‚„†‰‰ŠŠŠŠ‹Œ‹‰‡†…„ƒ‚„†ˆŒ‘‘‘‘‘‘’“”—›ž¢¥§¨¨§¦¤•Žˆ‚|vpkgb`^\ZY[^`bcdgkmnoppprtvwyz|}{ywvuuuuvwx|€„Š–œ£¨«®®®­«ª¨¦¥¡›–‰„€|ywutsssssssrqqrstuvwz|~~~}}|xuromoqsx}ƒˆŽ”›¡¦ª®®®­­¬ª¨¥¢žš—“‰„{vrokgb_\YZZZ\]_djllllllllkgdcccfimnoqw|‚‡Œ‘•𠣤¥¤£¢ ›™–”’‘Ž‹ˆ†…†‡ˆ‡†…†‡ˆŠ‹ŒŽ‘‘‘‘‘Іƒ|zxwuvxz|}~‚„‡‰‹ŒŒ‹Š‡„‚€~}|{yxvutrommmmpsvy|€ƒ‡‰‰‰‡†„‚€}{xvtsqppppqsux{„………†‡ˆ‹Ž‘‘‘Šˆˆˆ…ƒ€~|yvtrqprsttuvy{}€‚„†‡ˆ‰‹‘‘‘’“•–˜™˜–••”“’‘’““’‘‘‘‘Іƒ€~|zxxxyz{{{{{{{{{{{{|}}}}~~~}}}}}}}}}}}}}}~~}}}~~~€‚‚ƒ…‡ˆˆˆ‡†………†‡ˆ‡†…„‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ‚‚‚‚‚‚„…†‡ˆˆˆˆˆˆˆˆˆ‡…‚~{xutrpppoooppqstvy{}€‚„…†‡ˆˆˆˆ‡†…ƒ‚€~~~~~~~~~~~~~€‚‚‚ƒ„…†‡ˆˆˆ‡†…„‚€~~}}~~~‚„†‰ŠŒŽ‘’““’‘‘‘‘‘‘‘Ž‹ˆ‡…„ƒ‚€~~~}|{yxwLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/quirk.wav0000644000175000017500000001215013263212010020772 0ustar aeglosaeglosRIFF`WAVEfmt "V"Vdataꀀ}}€ƒ‚€~€‚ƒ|{ƒ‚€}|}€ƒ‚~{~‚~{{‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~}ˆ§Åɾ´±®ª˜‡nK((8IUap‹¥»ÊÙÍ·¡˜Ž…zo[=+@U]fq‚“¬ÊèÚŲ¢“‡{a=&6FUcpz…£ÉïßÏ¿¯Ÿ“Šc>(4@P`mxƒ¡ÄáÖÌÀ³¥˜Œ\6'5CTdpz„§ËäÖÉ»®¡”‡zT.(7HYjt|†«ÑãÔĵ§™Œ€pM+1DQ\gr~޳Øâо®Ÿr`D'%:OYaiw†š¼ÝàϽ«˜†xiW?&,BW^dk}Ž¥ÃàÜɶ¤’€n]L9'4I_chp’ªÇäÚǵ¢}iVF7(9M_ejtƒ’«ÈæØÈ¸¤y_E93.CXimq|¢¶ËÝÑÅ·¢qO-,17LapuyŠ¡¸ÂËÏź­šˆiE!)1S_di~–­¿ÐÖÊ¿®š†kO8419Nblrw–¶ÌÊÈù°¡~Z7"-8GZlu{„¦ÈÙÍÁ¶« mM.#3CQ_mxƒ’³ÓÜÍ¿°¡’|fQ?-0BU`jtƒ’¤¼ÔÕʾ¬™…gI62.;Pelq{•°ÁÆÌƽ´¢yV3'/7H\psw„¦ÉÒÊ÷«Ÿ’„oK(&4BSeu|ƒ“±ÏÑǽ®žƒwbC$+Sivx{”´ÑËž¶®¡~^<-:J\nx}‚ž¾×Ë¿³¦š‹{jO4"5HXdo}Œš²ÉÖËÀ±ž‹ygTC1-CYehl™°½ÊÎÄ»¬™‡lP952;Skokh‰©ÃÆÉ޵¥“€_=(/6F_wxvxš½ÐÉ»´­œ‰sQ/#1@Rfy|~‡¨ÉÔɾ´©ž‰s\B()>S`kv€‰˜³ÎÑǼ­žtZE6(5Oimnsˆ¯½ËÉÁº§•aB20-C_xtou‘­½ÂÈÁ¹±ŸuU4-4AEQ_lw‚–ºÞÞȲ¡}ytojpyƒwk_REBKSapœ¸ÏÓØÊ¬Ž€votxxrlr~‹tYCDFKXeq}ˆ°Ú÷àÉ«†`_kwxy{„Œ‰{n^M>CIRexªÅÑÚݲ‡je`k}‹…‚‹•nNC@=M]lwƒš¾âÙªŽqcxŒ‘‰‚‡“~hUH<=EM^pƒœ¶ÊÖáÅ–flu}€‚|€…‰mQ>@BL\l|ž¿à龓}wqz„Œ†‡ƒkTI?:BKWi{ÆïЮ”’’–š’‡}†ƒnZJ?4:DOas‹®ÒѺ£¡£¢œ–Žƒxy„nWC=6=Pdr‹¥¿Í»¨¢¥©¡˜ˆzsm`M9:@QcqqqsvyŽ¬ÉÆÃ½­ŒxeSA1G\lqusle€¡ÀÃÆÁ´¦•„rX=*C\nvwhZw•¯ºÅÆ¿·§”[5 6LbxŽ…vjtªÅÌÈıœ…cA/37Li…‚~zwtƒ¦ÈÎÊdzŸ‰lO>70E`{|~|si{ ÄÈÈÆµ¤v]H6$Ac‚…~lZp•»ÀÄĸ¬›ƒjP4?b~†Ž„nYo­µ½¿¸±¡ŒvV4=]uŽƒmXs‘«µ¿À¹±¡zV3"A`uŽ~iWt¨´Áý¸¥ŽvQ,#Eg|ˆ”~dUp‹¡²ÃÅÁ¾¦tN(%Cav‡—~e\uŽ£´ÆÆÃ¾¥ŒnJ%)Fcv‡‘zday¤¶ÈÈÇÁ¦‹kE,Igv…Švcex‹ µÊËÌèlE3Qlx…„q^bq€™³ÈÌÏĨŒh@9[w‚Œ…nW^n}—±ÅÈ̽£ˆb:<^y‡•‰mRbu‰ŸµÂÃñ™€Z4Ad|‰–†nXj|¤ºÃ®•|V0#Df{‡”jZm€”ª¿ÇÈÈ®“uP*&Jm~‰”}fZn‚—®ÅÊËɬoJ$*Nrˆxb]q„™¯ÅÊÌȪ‹jE!0V{ƒ‰ˆr[[rˆ³ÆÅļ …d@6^ƒ‡Œ…mU[s‹¡¶ÆÃ¿³˜|]=AjŒ‚iO\v¥¹ÆÀºª‘wX9FnŠ‚iPd}—¨ºÃ¾º¦ŠnR5%LtŠ}eLh…Ÿ°ÀÅ¿º €aI1,T{ŒŒŒybQn‹£´Åǽ `F-/WŠŠŠt]Rn‰¡´ÇÊÇĤ„eH,3Y~‡‰ˆq[Tk™°ÈÊÈĦˆiH'7_‡‹‹†mTQfz“®ÉÈÇÀ¥‹kF!8`‡Œ‘ŒqWUcrªÅÈË©mE8Yw…“‘yb^bf†§ÃÉÏÆ®–rK%8Laz’’€mc\X{ž¹ÂËĵ¦‚\<>?MnŽ„whXSt•­»ÉÈþ|^I5;[z‚ƒƒrb]m}”®ÈÉÆÁ­˜\96BOas€{wrmh{˜´ºÀÀ·­žˆr]G4DUclutojt¦¼ÇÁ»®v^IEAETbkszxw|‘¦µ¼Ã½³ªšŠx]B9>CRcty}„†“§»»¹¶­¥˜„p\H4=GSexƒ…†‰‘¡±»µ¯¨ ˜ƒjRF;8HXiyЋЋ’˜ «µµ®¨ž’…iN<:7F\r~‰‘Œ‡‹—£ª®±«¥„pW>;=AYq„‹’ˆ‚Ÿ­­®«¦ ”„t^G7?GUk€‰‘‹†‡—¨¯®®©£œ‡q]L:CUv˜”†weSOlŠ¢¶ÉÇÁ¸‘jLA6Jq˜”ŠiROg€˜°ÇÆÄ¼›{]E,Bk“ŒƒlVUh{”®ÆÅÄ»ŸƒeF'Bh‰‰‰kVYiz”°ÇÇÇ»ž‚dF(Hk………{gS[k|™µËË̺šz_E1Rs‡„s_KZm ¾ÏÏ϶‘kWC;]„{kWD[s‹§ÃÎËȧ}TMFLk‰ƒvfVJc|•¯ÉÎÇÁšnJJJWsŽqaQLh„ž´ËÉ¿¶Š_CJRc{“‰yj^SWt’©»Í³¡xP?Par„–…raZS_€¡´Âл¥ŒhC?WoŒ–k\[Ym°¿Êд™{Z9A_}‡yaW\a{žÁÈÍɦ„fN5Jl†oYWcpŒ«ÈÈÉ»”mVG9Vx“‡{gRZn›¶ÉÅÁ¬WIEBcƒ–‹q`Oaz“¨¾É¿¶™oDCIRmˆ“ˆ|n^Ngƒ°ÄÈ»­Œb9DO]w“‚qdXNnŽ©ºÊǵ¤~T1DWk“Ž|kaXWx™²ÀÎî™tN6Lat„“‰wd_Y_€¢¸Äо¥ŒjH;Tl}ˆ“ƒo^]\j‹­¾ÆÏµš~`C@\x„Š|h[^as“²¿ÆË¬pW=Ed‚ŠŽxcY^dzš¹ÂÈÇ¥‚eO9JkŒˆs^Ybjƒ¢ÀÄÈÀœx]I5NqŽŒ„oYYgt«ÄÄÄ´ŽhSF9Xx‘‰}hS\oœ¶ÈÄÀ©€WKGEc‚“‹„vbOawަ¾ÊüžtJHIOk‡‘ˆ~o^Ld}–­Å˹–lDHMXrŒ‘†{kYLf€˜¯Åǽ´gFKP]w‘ƒvfVPi‚š±ÇÅ»²ŠbGNTe}–‚tdTRkƒš°ÆÂº¯‡`JOTf€šƒveUUi}”­ÆÂ¾±ŠcOMLc€š„weSUdt©ÁÁÁ´‘o[PE]zŠo][_b¶½Å¼£ŠpV>Tj}‡‘‹zi`ZVqŒ£±À¾²§ŠjOUZexŒ‹wmb]iv†œ²··· ŠueUVdry‚zqkhfq…™¥°¸°¨›…pd]Waktuvtrosw{Šš§ª¬©¢›Œ{iaYU\cjqx|ƒƒ„ˆ‘› £¥¢ž™ˆwfWHIR[j{ˆ‘ˆ†Ž•œ£¦¦¥š†r^K:FQ`w—™š…}‚‡˜£§¨¨—…s^IAHPcz‘•™™‡~z†”£¥¨¥š}dLGGI^t…š˜ˆup’ž¥«¨¢œ„kVLCH\p€Žœ•ކzmq€›¥­ª§ž‰tbQ@IUcuˆ’އ}rzƒŒ™¥«ª©Ÿ‘„lTCGKWl‚Š’‰|~Š™¨¬­¬¡–…iNCCCXnƒŠ’’‰€}|{Œ«­¯ªŸ”~dIGDI^t‚Š“…}}}ƒ“£«®°¦œw_OLJUgx‰†|}~‰™¨«®­¡–„lTOOP_o|ƒ‰‡~vx|€‘¡¬¯²¨™Št]KQW`mz€ztr|…‘ ®¯®¬™…rcTS]gox~zvsrq|ž§®²ª¡“~ia`_fmsssqomu€‹š¨±®¬¢sh_elqqqokhlqw‹ ®³·® ‘~j\dlsx}wofb_bwŒž®¿»³ªo\]^gw‡ƒ|uj_\gq…ž·¼½ºŸ…o_PXlƒ†…wia_]q¨³½¿¬šƒhMSao|ˆ‹rg]Tg}”¦¹À·¯–tSTY`tˆŽ…{n^O`qƒœ´¾¼¹ž{XUQWrŒ’‹ƒr`Q[ev•³ÁÄǧƒcVIOl‰‘‘‘}iZ[\lŒ¬»ÄÌ­Žq[FKeŠ‘•‚o`\XjŠ©·ÂÇ­“z`FMcy„‘€oc^XmЍµÃÆ®•|`EOdx‚Œ}lb\VnŒ¨¶Äí—|_BQewŒŠzj`XPm‹¦¶Åîš~`DVhxƒ‹{k_UOkˆ¡´Ç¯œ`HYix…‘Šyi^SQm‰¡µÉ¿¬˜z]L]o~‰•‰wf[QSpŒ¤·Ê»§‘uXM_q€Ž›‹yi]RXt¥¸Ì·¢‹nQMauƒ‘œ‰vf\S`}š¬»Ç¯—fMQez…•ƒpc]Wh„¡®»À¨‘zcMVi|†‘mb]Xmˆ¢¯½½¦ŽxaKYl~‡Ž{i`\Yr¦±½¸Ÿ‡r_L_q‰‘Švc][Zw”«µ¿³˜}k[Ocw†Œ‘‡s`]\a~›¯·À®seXSi~Œ”…q^_`h…¡²¹À¨ŠmaUVl‚’€l\aftª¶º½Ÿ~b[T[qˆŒŒyeZbk}˜³ºº¸–t[WS`wŽŽ‹‡s_Wbmœ¸ºº´’p[WSbyŒˆo\Ydo…Ÿ¸¸·­l[YWi~‹…|jYZfs‹¥º¸µ§‡f[[[o„’Œ†{jX^jw©º¶³¢ƒd]]^s‡“‡{iX_iu¨·µ³Ÿc^\_t‰’ŽŠ|jX`htާµ¶·Ÿb]X\rˆŽŒ}j[`eq‹¥²¶º ƒi^TWn„“n_][hƒ¬·Á§ŽwdQTh{‡‘™‡vh_Wbz’£´À¯ž‰nSS`m}—‹reW_o•¬»³¬š|_Z[]q„‘Š€o_`ci„Ÿ²·¼¬’xhYPcv„‹’Š{le^^r‡™©¹´¨œLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/njam.wav0000644000175000017500000000714213263212010020571 0ustar aeglosaeglosRIFFZWAVEfmt "V"Vdataã ƒƒƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚€‚‚‚‚‚‚ƒƒ‚‚‚ƒƒƒƒ‚‚{wvvvtrpommmmmmmptw|€…‹’•˜šŸ£§©«ªªª©¨¦¤¢Ÿš•‰†‚~ytponmmmmmnty}ƒ†‰‘”•––––•””““’ŽŠ‡„€}{yxxxz|~‚‚ƒ…‰Œ‘“““‘‰‚whYbs„kS>94:HWPC8ES`lw…”¤¦¦§®´¸¸¸¸¸¸¸¸·³¯§›„ynmmke^XRMUammmotz‰’˜ ŸžœžŸ¡™ˆ…‚€~ysmmmnoqrtvy|~†Ž”—ššššœŸ ž›˜‘‹†‚~{yvrommmpsvwyz~†Œ’”•–••“Œ†xdOTal[I9.$(7GIIJXesƒ”¡¬·¸¸¸¸¸¸¸¸´¯ª¢™‘‰‚ypfa]Z[[^hrwxx€‹•Ÿ©¯­ªªªª¨§¥ž—rjgdgkkd]^goz‡“—šž¥­²µ¸¶µ³ª¡š—”Œsg[QRTUUUX]ahpxƒ—œ £¥¦ª®¯«§ž€fH+7BH@9+.GVdr€Ž›©¶¸¸¸¸¸¸¸¸¸¸¸²¬ xQ952/-,6?IQZh|ž«¸¸¸¸¸¸¸¸¸®£˜ƒn\OB?@B>979:Ii‰›¦±´¶¸¸¸¸¸¸¸¸·¦•†}ukaWH8*,.3=FR_lt{ƒ”¤¯³·¶´²°®«¥ž–‹wmdSC2 .6CSh|‹›¨¯µ¸¸¸¸¸¸¸¸²¡ƒxnbTHC?@HPSSSh€• ª°°°³µ¸±«¤ž™‚ule_juyphglqx€ˆŒ‘”•–‡‚†Š‹‰yy|~†””•”“““““…wc= 2PlaUSao‚™°µ·¸¸¸³§œŽ€qg]SMGCA@ELRi—¤²¸¸¸¸¸¸¸¸·´²¦”‚rcTPKJLNRW\dmw†•¢¬µ·····µ¬¢–‡xsrqonnruy~‚…†ˆŒ‘’Ž‹‡ƒ€~{yxx{~€‚ƒ„„…‹”””“““““t\A$ (F]dkpty‡—§®´¸¸¸¸¸¸™wXPHFJNNMLKJLV_qФ®³¸¸¸¸¸¸¸¸¸±¨ ’…u_J>819BLYfpx€‹˜¥¬²¸¸¸¸¸¸® “ˆ~uutvy|}~~}|{zx|‚ˆ‰‰ˆ„€‚ƒ‰’Ž‹‡ƒ€ƒ„ˆŒ‹‰‚tgH$#>PYco}‹šªµ¶¸¸¸¸¸¸³“rXI:8;>IU]WRQSUl‹ª°µ¸¸¸¸¸¸³­§Ÿ˜‚veP;3-+9GVgy‰—¥¨©«°¶¸¸¸···¦–‡wuwy}‚†xspnqw}‚†‰‰‰ˆ†ƒ„„„…‡ˆŒ‘“““†~€‚…Ž–w`B!(G[gr’¢¤¦©°¶¸¸¸¸¸³kN<++4=Qgxsojc\k€–¢¯¸¸¸¸¸¸©–ƒ~yw{~vgWI;0018L_w’­³¶·´±²µ¸¸¸¸¸¸´£’„yonopsvyz|zxvvvw|€…‹‘“““Žˆ‚~zy|~…‰†„‚€{unT1 !-5=Qi€•©¸¸¸¸¸¸¸¸¸¸¸®’w\A&,4?Rfpnmnpq~Œ™¦²¸¸¸¸¸·¤‘€uiddd^XQIB<<;CP]u§®´¸¸¸¸¸¸¸¸·±¬¥š„{qonlheglp{ˆ“““’‹Š‰‹‹Š†€ytqmrw{~‚xaI1 $5Lb~›·¶µµ¶¸¸¸¸¸¸·µ²¤€]G;/7BKRX`lx‚‹“–˜¨³¸¸¸¸¸¸ªŽ}l_ULHGEB??BEP_o€’¢«³¸¸¸¸¸¸··µªŸ•‹{yvrokd]\^ajt†Ž””•’މ†ƒ‚„†…ƒ€}{yz|{upcM6(!$'0AQf}“–™ž©³¸¸¸¸¸¸¸¸¶±¬ž‹xx{{upkhegjmmmoy‚Š——––˜šš—•‘‹…‚€~{yurnmmmt|„ˆŒ•šž ŸžŸ¢¦¥¡–‡…„ƒƒƒ„„„ƒ‚€|wtttw{{vqqpqrtsrqv{€‚ƒ€xobRBDFF>6357FYmgbbmw‚Ž™œŸ¨²¸¸¸···¸¸·µ²°°°ª¡˜ˆƒ…ˆ‡„}xtrqpomjfb`_]]\]`cir{‚ˆŽ— ©¯¶¸¸¸¸¸¸¸¸¶³°ª£›”އxsrrpnmf_[[[\]^chnqtwxy|ƒzuj_Z_c]RGC??JTXTPZjz‡”Ÿ¢¥ª°·¸¸¸¸¸¸¸¸¸¸¸´°¬¥Ÿ—‚ztmprsqnmmmpuytpliefimortwz~‚‡ŠŠŠ‘•¥«­°°°°²³³¯ª§¦¦£Ÿ›‘†|vpkhdcbafjlheb`^`cfjnqtvvutj]TVY[]_WJ>DLQPNPRUcv‰”š §­²·¸¸¸¸¸¸¸¸¸¸¸¸¸·¯¦œƒztmmmle^[]_acda_`ejnpqsuvˆ”˜›››Ÿ¡£¥¨«¯°°°¬©¥Ÿ™–––—™š”Žˆvng`^^^dimmmjd_^^_djmmmib[XVV_hhYKINRW[^XRVhz†‘›£ª±´·¸¸¸¸¸¸¸¸¸¸¸¸¸¸µ²¯Ÿyqmmme\VXYZZZXWU]fnquy†Œ’˜š›¢¨­²·¶µ³²±®«§¤¢ žœš—”“““‰ƒ~xsojc]ZZZ\]^^^]\[]_afjlhe`YSZdlhc_ZUZeoia[bis‚—™›¤­µ¶¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸²¬¥–ˆ|wspnme\UUUTRPOOOV^ekqvz~„Œ“–™œ ¤ª°·¸¸¸¸¸¶²®©¢›—•“““’‰„zupkfb^[XVUUUVXYYXXZ]_ejlheb^Z`glga_`aelsqonv~‡˜ž£§­³¸¸¸¸¸¸¸¸¸¸¸·¶´°©¢™†ysrqmf`][YXVTROT\cjouy}‚Š‘•˜šŸ£¨®´¸¸¸¸¸¸¶µ²«¤ž™”‘‰…‚}xsmhb^^^][ZXWUUUUUUW\`fkqqqokfglqqponmou||yvz„–¡¦«±·¸¸¸¸¸¸¸¸¸¸¸²¬¦ ™’Š‚}yvvvuqnjd_\[YXVWZ]cjpv|„‡‹’–šž£¨¬±¶¸¸¸¶´²®ª¥–‘‰‡…‚~yuqnjfa^\ZZZZZZZZZ[[\]^aflpsvz}~ytqomorsqnnoqty~|zy…Œ•ž£§ª¯³¸¸¸······²­¨ ™’‹„{wspmmmkhda][\]_adglqw~„†‰Œ’–šž¡¤§¬²µ¶·µ²°¬¨¤–‘‰†ƒ€{upomib[YXYYZYYXYZZ\]_ejoqtx~ƒ‰’ŽŠ…}vw{~€‚‚}}~}{z{|ˆ•˜›Ÿ£§¨ªªªª©§¦¥¤£ž˜“Š…€|xtqqponmjgehknqsw{ƒ‡‹Ž‘”–˜œ¡¦¨ª¬®¯°°°­©¦ š•”“‰ƒ~zvrokfa^\Z[[\]^]\Z[[[_bfjosy~‚†‰“““”•–’ŽŠˆ‡ˆŠŒ‰ƒ}xtrsuuqnqw}ƒˆŽ’”—šššš˜——™šš˜–•”“ŽŠ†‚~ytoprttttttuwx{}€ƒ‡‹Ž’•˜› ¢¤¥¦¦¦¤¢¡žœš—”Š„~|vqmmmjfb_\[\]___abdddehkosw{ƒ†ˆ‹Ž’”•–˜š›››š—”ˆ€}{xvspomnopppqrtvz~„‡‹””””””•––—˜—•“‘Ї…„‚€€ƒƒƒƒƒƒ„†ˆ‹Ž’”•–˜šššš™–”“““““’Ž‹ˆ…ƒ€|xurpommmmmmmmmmmmmmmnoqsuwy|~ƒ…ˆŠŽ‘”””•––—˜—•“‘‰†‚~{xvvvusqrrsstuuvx|ƒ…‡ˆ‹’“““““““““““‘‹Š‰‰‰‰‰‰Œ““““““”•••••••””“‰‡„‚~|zywvtrpommmmmmmLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/base.wav0000644000175000017500000000015713263212010020555 0ustar aeglosaeglosRIFFgWAVEfmt "V"VdataC³³³³³³Žb@@@`ºŠZ@@@]}‰jJ`Š«€U[Š»¬š•§¹˜hJzª¯—€—°©yH@@M}­¾¾¾¾¾¾¾¾¾¾€€mirrormagic-3.0.0/sounds/snd_classic/quiek.wav0000644000175000017500000000730213263212010020760 0ustar aeglosaeglosRIFFºWAVEfmt "V"VdataD†ƒ„‡‰ŠŠ‰ˆ‡‡‡†„‚ƒ„„†‡ˆŠ‹Š‰‡ˆ‰‰‡„‚ƒƒ„ˆ‹Œ‹‹‰‡†ˆ‰ˆ‚}{}~„Œ•’‹Š‡ƒ|yv~†Ž’•”Љ‰‰‚zuz~„Œ”•’“—™Œuplu‡šžŸ¡¢£œ…meiny†“§¨’}z†’‡vep{†‘›œ––ž¦xhns|†‘’‘Š„ynuƒ—œž“‰…ŠŽ†yllnqƒ•›…§¿¡|^fnx†”œ ¤•„w„‘•‰}wtq|ˆ’Ž’••””ˆ{oprxˆ—š”Ž”œ£’‚usqx„š¤®š‡|†Švbepz‹¨¡™•“’†yts‹“–™’‰ˆ‘–ƒ{upw„‘•——ˆz|”¬¢…hgim„œ«¬®šyXk‡¡ª³­lgs€†ŠŒ†~~‡•¤ ˜‘…zswz~ƒ‡Œ‘—™›˜‹}uqmvƒŒspv|—¹Ü¥kAN[pª´¶¸–rXer€Žœ˜Œ~~~~‚Œ•› ¤—‰}xsw‡˜¡¤¨“zgq|…Œ“‘‹…ƒ|yz}€ªÅ§~Xbly¡§¢Ž|mt{†‹‹‰‡†…ƒ~xy‹¤ œ€qstyŒž¦¤¢ŽrVi~Œ‰‡…‚{wy‘©°¡“†ymrx€”§¬Ÿ’„tdo{‡‰‹Šˆ…€{uŠ•Ÿ¨¦‘{ojdx§ª®¦‡hbnz„ޕކ€€€}xs† ·­£•hdp|¥º¦’pbdvˆˆƒ~wpy“­­£š†qcksƒ¶»¶²‹`Dc”•–‘‹…xtwzˆ§Æ»šyohfz «¶ªuomm}Œ•’Š‚zslh…¡°¦œŒxdfkq©º¶²šrJSi€‰“˜ˆ€xpt{‚œ¶Àœxecar‰ ª³´™}nlkv…•’Œ€tpru‹«Ë°‘uhZ]t‹¤½×¼œ~m[[u—–•ˆ€wnq‡œ¦¨ªrYeq™°±¢“€lZjz†””ƒxn{ˆ• «¥{of^u‹ ¯¾±‰a[`exŒ™–“ƒxutt•·Ì´œ…p[cwŠ¡·Ã¥‡pdXdz‘‘†}si^x¤Ñ¹š|l\[o„¹Ö¼›{dMJk‹™™™‘‡~umn}–šžˆmVgw‰Ÿµ³¡Ž|jZj{ˆ’‘‰xq‚“¢§¬¥“‚xqj|¨³ªpfcat†”“‘Œƒyxxx¤³¦˜‰weiv„™¯½¨“m[as„Œ“—‰p`w¥ÓÄ«’rREWj‰°×ÓǸƒN5Wx™¤š‹|sij•¤­¶™qL[kŸ¾Åµ¥‹nQct„——ˆzj[zš´»Â±†[RVY¬ÌËɱzCBXo‚•¢š’ˆ|prz‚—®½£‰ti_kƒ›­¾È¤€hb]j™œœš…{unv‡˜ ¨¬œŒ}rfm€”Ÿ©°—~kigo‘Žƒxry€¨À³›ƒra\u§½Ó¼”lc[[v’™”‡veffp¢ÕØ¡iL>/ZжÊÞ×­‚iYHf‡£¢ —‚mjqw“²É­‘xeR]{˜¯ÅÕª€b\We™œ›š‹}obVn¢×̲—yZJXg§ÍÊ»­€S;[{™¢šŒuki~’£°¾§ƒ`abiˆ§º½À¥}U[cn„š¡˜rcgmx ÉÒ¯‹tdTg}’¤¶¹¤zgSdy•ƒysl{ž§°­”zmiez“«¯³¬Œk`dhz£›“‰}qieaŠÀôÈœu]ENuœ²ÂÑ­‰k_S[x•œ›šˆvjqx‡¢½·¤‘x^Nj†¡»ÕÀ–k]RNo ›qcUQÎçß~`BWt‘®ËÓµ˜{]?Uu“›£¡yle^v•³µ·­‰e\grŽ®Ì½­™xWRf{‹›ªœŽ€p``n|˜»Ý¬{VWYiŠ«¶¸º›{cfis‡š›•ƒwoqt~”©©Ÿ•‚n`n} ³° l_p€Ž–ŸšŽ‚wlep|Œ¥¿³k`[Zw”ª°¶©Žskhfz™–“‹rppqŒ§·¯§•wZ`q‚ž¹Ç±›ƒjQ^y“§ª™‰xiYk‰§µÃÄ•gPV\y¢ÊÆ¿³ŒdSap•¨ž‘„uff|’¥¶Ç¬Œn`RW{ ¹ÊÛ±~PSVb‚£ª¡—ˆwgebošÆÍ·¡‡kR_m€¡ÂĬ”x[?[wŽ˜¢}pf[y–­­®Ÿc]^_‚¥ÂÅȰyBBXnˆ¡³§›‹wcbjq‘´Ì±—€n]ct†µÅ«‘ygT]uŽ— €smftª²µµ›me^m­¸¿Â“dGTbt‹¢¡š”ƒsimq„¥Æ·›~m\Voˆ¯Á°•zl]Xo…”›¢–ƒpkfj޲À¶­’oMU^m”»ËÀ´‘d6Iay¥­¢—ƒjQf—ª½¼™wd[Rn¯¶½´j[[[p‰¡¡¢šicinŠªÈ´ ‰lPNat™Âèœz`FG`x ²£”…tcf|’£²Á¡f`Zf‡§³µ¸—tZ]am…¥¦¦ygijx˜·¹­¡„fO\i~¡Åì–gUan}’¦ª¤Šudozˆ›®®¡”‚p`lx‡œ±±¢“€m\iuƒ‘ žuj`}›°°°Ÿ~]WY[~ »¼¾¬ˆdYXWsŽ¥¥¦š‚iiqz’ªº¨–ƒo[arƒ·É²›ƒiPUj~”ª¸¡‰ufXk¶¶³¬‰gSUXr›ÃËÌÉœoPPOc…¦¬¬ªpakv‰¢¼±‰s^Uh{¨Àµ ‹qXKbx¥¼®•|k[X| ´·º¤†i_VVv—­¸Â°‘sfYTl…–Ÿ¨œ‡roln€’ž£§™ƒlhgj„ž¬ª§—jfdgyŒ™›“„tmhg„¡²¯«œ„lkmq…š§¥¢˜‡voifu„”˜’‡{zz{ˆ•ŸŸ —…tonm€”£¥§ŸŒzpjdq}‰‘˜™’Œ‚xm}Žœ ¤ž‹yrqq}Š–¤¢•ˆ|pdkt}‡“†ƒ€†‘Ž‹‡€xusr›Ÿ¤ rh^gt€‹•š—“Œ‚x}†’•”‰yxx˜›ž’†}umrz‚Š’–‘‹‡„€…Œ’‡|xt|ˆ”š ¡”†|tmpx‡•”’ކ~~‚†‹’ŽŠ†ƒ€ƒ†‹‘•“Œ„|zzz€†ŒŽŒ†€‚‰‘—’Œ‡‚}|~†Ž—˜™–„~{wz}€ƒ†‡‡‡‰‹”—“Š„~}€„‰–•”’ˆ‚}wwxy…‰‡†ˆŽ“–––ކ~|yz}€†Ž–——–ކ{wwyz}€ƒˆŽ“—›™”Žˆzyxy€†Œ“š—“ŽŠ…€{wtsrx‡’œ£¢ š…~xrtvzƒ”˜œ™”ˆzuport|†™£¨£”ˆ|vspv}„Œ”˜˜˜“Œ…~wpmjlt|‡”¡¦©ªƒzposv}…’—˜•‘Œ…ytppptŠ”¦¥¢Ÿ”ˆ~yssw{ƒŒ––—•‰ƒ}xtqosw|‰–Ÿ¥«¥›’ˆ~vvux~„Š–“Œ†zwtsss{ƒ‹“›Ÿ›–‡{wxy|ƒŠŽ’Œ‰„~zwttuvˆ’—ž›—’‹„~yuwz}„ŠŽŠ†|xvtw}‚‰–™››—“…}ywuz„ˆ‘’މ„~xuvw{‚‰“˜šœœ—’†|{{~‚…‰ŽŽŽ‹†}zxy{~…“˜ž›š”Žˆ„€~}|€…Š‘‹†|xvwx|ƒ‹‘—œ›™—’‡‚|{|}‚ˆ““‘‹…|zx}‚‡Œ‘–šŸš—‘‹…}|~ƒ‰Ž‘“”Іƒ€}|z|~‰‘—›Ÿ˜“‡}zz}€…ŠŽ‹ˆ…|yxv{‡Œ‘•˜›š˜–‡~}||~€ƒˆ’“Œˆ„{ywy{}„‹‘”——•“І|z|~€…‰ŒŽŒŠ‡‚|xwwy|~„Š•™š™˜“†‚}yyy|‡‹ŒŽ‹‰†ƒ€}{yz{{ƒˆ“——˜•І}}}‚†‰‹‹‰‡†…„|xtx|€†’–𙖓މ„‚ƒ†‰‹Œ‹Š‰†‚{xxyz‡‘”———”Ї„}}€ƒ†‹Ž‹ˆ„yyyy|€ƒˆŽ“–™™˜˜“‡ƒ~€„ŠŽ‹‰†ƒ}{zyz~ƒˆ–™™™”މƒ~||}€…‰‹Œ‹Š‰‰ˆ†‚~zxuxz~…Œ’•˜–’І‚€‚„‡ŠŒŽŽ‹‰†ƒ|yzz{„ˆŽ“–––“Œ‡ƒ€€€‚„†‰ŒŽ‹ˆ…‚}{{|~…‰Œ”•––‘Œ‡„‚ƒ†‰‹ŽŽŒŠ‰ˆ‡„€|ywwz~‚ˆ“—š—•’ˆ…ƒ‚‚‚…ˆ‹ŽŽ‹‰†ƒ€}{xxwy~‚‡Œ’”••“‡‚‚„ˆŠ†„‚}{{{{„ŠŽ‘”–˜—”Œ‡ƒ‚‚ƒ…ˆŠŒŽŽŠ‡…‚|{z{|}‡Œ‘“”–“މ…‚‚ƒ…‡ŠŒŽŒ‹‰†„~|||~€‚†‰‘“““‘Ž‹ˆ„ƒƒ„…‡‰Š‹ŒŠ‰‡…ƒ€~~}}~‚†‹”•••‘ˆ†ƒƒƒ„…‡ˆŠŒŒŒ‹Šˆ†„‚€€€€‚ƒ†ˆ‹‘‘‘ŽŒ‰†ƒƒƒƒ…‡‰ŒŽŽŒ‹‰†„ƒ€€€€€€‚…‡ŠŒŽ‹‰†ƒ„„„†‰‹ŒŒ‹‰ˆ†…„ƒ‚‚‚ƒƒƒ„„„„„…†ˆŠ‹Œ‹Š‡„‚…‡‰ŠŠˆ‡†LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/hui.wav0000644000175000017500000000532213263212010020427 0ustar aeglosaeglosRIFFÊ WAVEfmt "V"VdataS †††††‡‡‡ˆˆ‡‡†…ƒ‚‚‚‚‚‚€~}}}}}}}~€ƒ„……†††‡ˆˆ‰Š‹ŒŽ‘‘’“““””“““’’’‘ŽŒŠˆˆ‡†††…„‚€~~}|{zyxvvuttsrrrrrrsstuvwyz{|}€‚ƒ„…‡ˆ‰Š‹Ž‘’’’“”•••”””“’’‘‘‘ŽŒŠ‰‡…ƒ}{yxvuutsrrqqppppppqrsuvxy{}‚„†ˆ‹‘“•–˜™šš›œžŸ    Ÿ›™–”‘‹‰‡…ƒ~{ywusrqqpoonmnopqrstvwy{}ƒ†ˆŠŒŽ‘“”–––––––—˜˜˜˜—–•“’Ž‹‰†ƒ€}zxusqnmkihghhhijlmoqsuvxz}…ˆŒ“—š ¢£¤¥¦§§¨§¥¤£¢¢Ÿœ™–“Œˆ„~{yvspmjgedcbabbbcddfiloruy|€…ŠŽ“˜›ž¡¤§©ª¬­®®­¬«ª¨§¤¡˜“Žˆ‚~zvsolheb_\[ZZZ[\^_cgkpuz…Š”˜œ ¤¨«¬®®®®¬«ª§¤¡š–’‹‡ƒ~ytpmifca_]\[\^acfilorv{„ˆ‘•™œ ¢¥§¨ª©¨¦¤¢ š–“‹†‚}yurolkigecdeegikmptx|†‹“–šž         ž›˜”‘‰„€|ywusrpoonmlkklmnpsux{}€ƒ†‰Œ“•˜™›Ÿ   Ÿ›™•’‹ˆ…‚}zxvtssssstuvwxyz{|~€‚…ˆŠŒŽ‘“”•–—˜™››š™•‘Ž‹ˆ…‚}{zwuspnlkkmnorux{„†ˆŠŒ’•—™›œœœœš˜–“Їƒ{wtpomlllmoprsuvx{ƒ‡‹’”—˜šœœœ›š–’Ž‹‡„€}{ywutrrqqqqsuwz}€…‰‘“•––––•”“‘ŒŠ‡…‚}{yxwvutsrqsvxz}€„‡Š’•—˜š›œžœ›™–“Ž‹ˆ…|vpmjggghjlnqty~„‰Ž“—›Ÿ£¦¤£¡Ÿœ˜”Œ‡‚}xspnljhgffhijoty}‚†ŠŽ“˜£¨«¨¥¢Ÿœ–Š„~xrmhfcb`_cfjnrx€ˆ–¢¦««¬«©¦¢œ•ˆztmga^\[]^`flsy€†Œ’˜£§«­¬ª¨¥¢œ•†xqkfdbdefkpu{€†Œ’—œ ¡¢¡Ÿš•‘‹…xrljhfeeimrx~„‹‘—›Ÿ¡¢¢ ›™–“ˆƒ~xuronmnoqtw{€…Š’•————–•”Œˆ…~{xvtrqpqsux{ƒˆŽ‘•–––•“‘ŒŠ†‚~zvtttuvwz|‚„‡‹Ž‘“”•–•“‘ŽŠ‡ƒ|yvuvxy{|~„†‰Œ‘‘‘Šˆ†ƒ€}zxwvwxz}…ŠŽ‘“”•–•”“‘ŽŒ‡‚|wsolihlpu{‚ˆ“˜   ž›—‘‰{vqommopsvy„‰Ž’–˜››››˜•’‡‚{urqpqqrw{„‰Ž“˜š››˜•‘‹„|tlmnpsvz„‰’•˜ššš˜•’މ„ysrqpppt{‚‡’”––”’‹‡ƒ|xutx|‚†‰ŒŽ‹Š‰‰ˆˆˆ„~{xxyy{}„‰Ž‘‘‹ˆ…}{|}~€‚‚„†ˆ‹ŽŽ‹ˆ„€|yutuwy{}€ƒ†‰ŒŽ“’‹‡ƒ}|z{}~€ƒ„…†ˆŠŒŽ‘‹†‚~}{zyy|„†‰‹Œ‹‹ˆ…‚}zxwwyz|‚‰‘˜š›˜†yspmlqv{ƒŠ“—™šš”ˆ‚}xtoqsu{†‹•™ž™“ˆ‚}xtrrrw}ƒ†ˆ‹ŽŒ‹‰‡„~{ywxyy|‡Œ’”–—˜“Œ†€zvvvx{~…Œ“–˜™™˜”Œƒzpejot{ˆ—›œž˜’Œ…~wphjot{‚‰”˜™š”‹‚|wsssv|‚Š“œš–’ˆƒ}xuttz‚ŠŒŽŽŒŠˆ„€}yw{‚†ŠŽ“‘ƒyqqpsw{‚В𢤕†yoffkov~…‘œ¡Ÿž™“Œ„|tnhjwƒŒ“›—’Žˆ‚|unoty‚‹”•–•”“ކ~zwv{€…ˆŒ‘”ˆ‚zqnt{ˆŽ•œ¡ž›”…vooov‡ŠŒŽŽŽ‹…€|yw{‚…‰ŒŽ‘‰…~vrvy~‚‡Ž•š‹{qmjmrw~†Ž–žž–އwvuvy|€‡Ž†~xz}€„‰‰‡†……†ˆ‹‹Š‰…z{}€†‹ŽŒŠˆ…‚|zzz}†’’’Šxz|„Šˆ{yw{‚ˆ‹ŒŒˆ„~|{{…Љƒ}{~‚†‡ˆ‡‡†‡‰‹ŒŽˆ€xurv’“”‹wvuwz}‚‰•š‚wrnt“•–ˆƒƒ‡ŒŽŽ†}yyyƒœ˜”Ž€qnv~‰–¢—ƒ{tqstx}‚‹”™“„vimy„‘ž¥—ˆ|umqzƒ‰Ž”—š—Œr`O_s†–¦¨“}qkevЛ𙓂qmrxŒ•‘‰…~zwy{~‡”†ziXct…™­¶¢Ž~shq€Ž‘”“Š|||€„ˆ†…ƒ‚€„†‡ˆ‰†„ƒƒƒ„‡‰ˆ‡†„†Š“ˆ‚{zz{}‚†‰‹‰‡„€‚„………‚{{{}€ƒƒƒƒ€}||}~€‚†‰‹Œ‹‰‡…ƒ~~~‰–›Ÿ”„uqmn~–––Œrx~…œœƒyqiu‹Š~qoqs}ˆˆyoem𣧔sokr~‹‰†ƒypmu}…Ž–’ˆ…‚‚‚‚ƒ„ƒ~|xuyŠ–š’Š„‚€…Ž—•‘qiqyƒ›”…~wnfdhl{Ž¡žš•…upty€‡Ž‹‰„€ƒŠ’—“‰uv{€…‹ŽŒŠ†ƒ†Š•Ž€nYDYu‘£µ·˜ye\Re~–¥¨¥¡—‡veTDbœ¬½¶š~oe[fpz„˜£­¥—ˆzldrŠ—”‡‚}yvsw€Š—¥³¦–‡zmiqx~‚‡††…„‚|ytojecmw‰’˜œ ›–€pfhjq}‰‘˜Ÿ¥ªª –ƒzslffgjs|…•¥«›‹|l\ZdmwŠ–¢«­¯­¨£•„r]G;Qg|¢©«¬¥”€lbbblzˆ“ž¨±¹»´®¦•‡ylhcemuŽœ«»È¼´©Ÿ”‰}vojkmoruy~ƒ„„ƒ‚‚ˆŽ“˜›˜”’ŽŒ‹‰‡…‚€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/pong.wav0000644000175000017500000001030013263212010020575 0ustar aeglosaeglosRIFF¸WAVEfmt "V"VdataB{{{{|~}|||}~}}}~€~~~~€€€€€~‰¥Â¼Ÿtibo{|iWc}˜‘‡ƒ‘ŸŸ’„„ŠybUcqreYi———›§²¬™†~ytldadgbYQj‡Ÿ™“–£°­£™‘ˆ~n^WWWVUUl‚”›¡©±º³ª¡•‰zgTNOORV[p…•ž§±»Å·©›„ucQKJJRZey›¥¯·¿Å¸«œŠxhYJFDDNXf{¡°¿Âöªš…p_P@><>LZk~‘¤·ÈÇÆÁµ¨•{bRE9404G[o„™¬¿ÎÍÌŵ¥ŽrWH:.+(1EZp‡ž´ÊØÔÏŶ§‹lM>.#!-GawŒ¢¹ÑÜ×ÑŶ§‡fG9+!*Gc{“«ÂÚâÛÔÈ»­…^?4*",E`|˜´ÏëîãÙɹ¥€[?1"3Sq‹¤¼Ôëìåß̺£|U;- 5Qn°ÉÝñîçÞɳ™vT<+&>Up‘±ËâúñéÝÅ­lI4#$B`~›¹ÏâóíçÙ¿¤„a>+)Fc ¿ÔèöíäÒµ˜yZ;-!2Mh…¢¿ÐâéàÖÄ«’sT6&3Ok‰¨ÃÔåêáÙÄ©ŽnM1#4RpެÇÚíïäÙ§ŒkJ/!Yu’°ÎÚçëàÕÀ¢…iM2$ -B\w•µÑÜæçÜкeI0!!/F`z™¸ÒÜçæÜÓ¹š|`C, #0Ie ¾ÕßéåÛÑ´–y]B-!)7Qk‡¦ÅÙâêäÚв”w]B/"-%!1Jg… ¼ÓÜäáÒĪŒnS8!&6Qn‹¦ÁÖÞåßÐÁ¥‡jP5!)8Us¬ÇÙâêàÏ¿¢„gL2! .=\{˜²ÌÜäìßνŸeJ/"$4Ed„ ¸ÑÞåíÜʶ›dI/$*:Nm‹¦½ÔÞæêØÆ±•y_F-&!!0?TrªÁØßåæÔÁ«tZ@&#!$4DZw”¬ÃÙÞãàͺ£‡lT<&$!'8Ia~š°ÆØÜàÙÆ³›€fN7$#"+;Ke‚ž³ÈØÛÝÓÁ®”y_I3$$$/@Qlˆ£·ËØÚÝϼ¨ŽsYE1&%%3DVs©¼ÐÙÙÙÊ·¤‰nUB/'''8K_z•­ÀÓØØØÆ³ž„iR@-)**,+.1CUj…Ÿ´ÄÕÕÔѽª”zaM<*-/5H[pŠ£µÅÔÓÑÊ·¤t\J:-/19L`v§·ÆÒÏÌðœ†nUG9/24>Re{“«¹ÇÐÌɽª–€iRE8159EXk‚™¯¼ÉÏÊÄ·¤’{ePC7269H\q†œ°½ÊÍdz¡Žw_LA659=NbwŒ¡³¿ÊÊľ®œ‰r[I?56;@Sgz£´ÀÌÉÁº¨—„nWH?68>CWk“§µÀÊž¶£‘~iTG>5;AJ]pƒ—ª·Á˺¯žŒyePF>8>DNbv‰›­¸ÀǾ¶ª™‡taME?;BHTi~Ÿ¯¹ÁÅ»±¤”„q]IE@@FLYnƒ”£²ºÂø­Ÿ€mZHEBCJP_tˆ–¥²ºÁÀ´©š‹{hVGECFMUf{œ¨³ºÁ¼°¥–‡weTHFDIQYk~ž«µº¿¸¬ ‘qaPGFELU^pƒ”¡®¶º¿´¨›‹|l]MFEEMVat‡—£®µ¹¼±¥™ˆxiZLGGGQ[gxŠ˜¤°´·¸¬Ÿ’ƒtfXKIIJU_l}œ§²µ·¶©œŽpcWJKLOZesƒ” ªµµµ±¦šŒ|maVMNOS_jxˆ˜£­´´³®¢–ˆxi^TMOQWcn}Œ›¦°¶´²«Ÿ“„ue\SNPRZfrž§±µ²¯¦š€pbZQOQT]jv…“ ©±³°¬¢–‰{l_WNMQT_lz‡•¡©±±¬¨„ug\TMNSWcp|Š˜£ª±®ª¦™ŒqcYRLOTYftŽ›¤ª±¬¨¢•ˆ{m`XRLQV]iuƒž¦«°«¥Ÿ’…xk^WQNSX_lz†“Ÿ¦¬°ª¤œ‚vi\WRPV\eq}Š–£¨¬­§¢˜Œsg[WRQX_iv‚Žš¦©­¬¦ –‰|pdYVST[aly…‘§ª­«¤’†ymbYURU]ep|‰”Ÿ§ª¬¨¡šŽuj_XURW_gs‹—¢©ª«¦Ÿ˜‹~qg]VTRYbkwƒš¤©ª«¥–ˆ{oe[VUS[dmz†’œ¦ª««£œ“†zne[WVU^gp}‰”ž¨ªª©¡š‘„wlcZXXYbjt€— ªªª¨ —ukcZYY[dmx„š£ªª©¦ž•‹~qh`ZZZ]foz†’›£©¨§£š‘†zme^YYZ_hq|ˆ”œ¤¨§¥ —‚vjb[WXY_ir}ˆ“›£¦¤¢œ“‰~rf_XVXY`js~Š”›£¤¢ ™†{od^WVXZbluŒ–¤¤¢ —ƒxlc\VVY\eoy„˜Ÿ¥¤¡Ÿ•‹‚vkc]XY[^hs}ˆ’𠧤¡”Š€ujc^Y\^bmwŒ–ž£©¥¡œ“Š€ujd^[^agq{…™Ÿ¥¨¥¢œ“‰tjd_\`cjs}‡‘› ¥¨¤ š‡}rgc_]aelv€Š”¢¦§£Ÿ˜Ž„yoea^^bfnx‚‹•¢¦¥¡œ”Švld`\^bgoyƒŒ–ž¡¥£˜‡~tjb_\^cgpz„–¡¤¡›–Œƒypf`]Z^chr{…Ž—œ £ž™”Š€vmd_\Z_djs}†˜œŸ¡œ—‘ˆ~ulc_][aflv€‰‘™Ÿ ›–†|skc`]]bgnx‚‹“›ŸŸš”„zria_^_djq{…•ž Ÿ™“‹‚yqia`_aglt~‡–Ÿ ž˜’Šxphaa`ciowŠ’™ŸŸ œ–ˆvngaaaekqzƒŒ“™žŸ ›•Ž…|slebbbglr|…Ž”šžžž˜’‹‚zrkdbbbhou~‡•›žžž—‰xqjdcddjpv€‰–œœœ›•އwpiccdelry‚‹’—œœ›”…}tnhcefhmszƒŒ“™žœ›™’Œ„{rmgdefipv}†Ž”šœš—‰yqlgefgjqw€ˆ‘–››™•އwokgefhlsz‚Š’–š›š˜“Œ„}unjfeginu|„‹’–š›™—‘Šƒ{smiefhjpv}…Œ“–š™—•ˆyqkhefhjqx€‡Ž“—š™–”†xpkhegjmt{ˆ”—›˜•’‹…~wokhfiknu|ƒŠ”—š—”Šƒ|unkhfilpw~…Œ’–˜™–“Žˆ{tmkhhknrz‡“–˜™•’‡€zsljiimpu|ƒ‰•–˜—”‹„}wqkjhjmpv}„Š•–˜–’Žˆ{uojihjnrx†‹•–—”Œ†€ytnjihkosy€†‹”••’Ž‹„}wqlihhkosz‡Œ‘”””Œ‡|vqliiimqu{‚‡Œ‘“““І€ztpkiiinrw}ƒ‰‘““’ŽŠ…ytpkkklpty…Š“’’‘‰„~xtplllmrv{‚ˆŒ”““‘ˆ‚}wsommmotx~ƒ‰‘““’‹‡‚|vrommnquz…ŠŽ’““’І€ztronnorw|†Œ’“’‘މ„ytqnnpqty}ƒˆ““’‘ˆ„~xspnnpquz„ŠŽ‘““‘‹‡‚}xtqnoqrw|€†‹‘”’І}xtroqsuy~ƒˆŒ’”’ŽŠ…|vsqoqsuz€„‰Ž‘“”’މ„zvsqqrtw|€…Š‘““‘Ž‹†}xsqpprtw|…ŠŽ‘‘ŽŒˆ„zuqonnqsw|€…‰ŽŠ†|xsnnmnpsw|…‰ŽŒŠ‡ƒ~zuqmmlnprv{…‰ŒŒ‹‰†‚}xtolllnqsx}‚†‰Œ‹ˆ…€|xtpmmmortzƒ‡‹ŽŽ‹ˆ„€|wtpnnnqux}‚‡Š‹ˆ„€|xtqqqqtw{€…‰Œ‘‘‰…|yursstwz~ƒˆ‹Ž‘‘‘‰†|yvssstx|€„‰’‘‘Œˆ„{wtsstvy}†‹Ž‘‘ŽŠ‡ƒ~zwtsstvz}‚†ŠŽŒˆ„€|wurrrsuy|†‹ŒŽŽŽŠ†‚~zvsppqruy}…‰‹Œ‹ˆ„{wsqooqrvz~‚†‰‹ŒŠ‰…‚~zvspnoqrvz~‚†‰‹‹Š‰…}yurpnprtx|€„ˆ‹ŒŽŒŠˆ„€|yurqoqtvz~‚†ŠŒŽŒŠˆ„€|xtrqqsux|€„ˆŒŽŽŒŠ‡„€|xtsrsuvy~‚†ŠŽŽŒŠˆ„€|xutstvx|€„‡‹Š‡ƒ{xttstwy|…ˆŒŽ‹‰†‚{wttsuwz~‚†‰Œ‹‰…}zwtttvxz~‚†‰ŒŽŠ‡ƒ{xusrruxz~ƒ†‰ŒŠˆ…}yvssssvx{ƒ†‰ŒŠ‡„€|xurrrruxz~‚†ˆ‹‹‹Š‡„€}yvspqqrux{ƒ†‰‹Š‰ˆ…‚{xuropqrux{ƒ†‰ŠŠ‰ˆ…‚{xurqqrsvy}…‡ŠŠŠ‰‡„‚~zwtrrrsux{~‚†‰‹‹‹‹‰…~{wussstwz~…ˆŠŒŒŒ‹ˆ…‚{xvttvwz|ƒ‡ŠŒŽŒŒ‰…|ywuuwx{~…‰ŒŽŒŒ‰†ƒ|ywuvxy|‚†ŠŒŽŽŒˆ„}zxvuwxz}€ƒ†‰‹ŽŒ‹‰†ƒ|ywutvwy|€ƒ†‰Š‹ŒŠ‰‡ƒ€}zwuttuwy|‚†‰Š‹‹Šˆ…ƒ€|yutstuwy|‚…ˆŠ‹Šˆ†„€|zwusrsuwy}€ƒ†‰‰Š‰ˆ†ƒ€|yvssrsuwz}€ƒ†‰‰‰ˆ†…‚|yvttstvx{~‚„‡‰‰Šˆ‡…~zxusssuwy|€ƒ…ˆŠ‹‹‰‡†‚~{ywuuuwy{LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/gong.wav0000644000175000017500000002015013263212010020570 0ustar aeglosaeglosRIFF` WAVEfmt "V"Vdataéywwutuvxz||||}}}~~{yxxxz|~}}|||}~~}|zyyz{||||||||||||||{zyxxyz{||}~~~}|||}}}~~~~}||||}}~}}}|||||||||||}~~~}|||}~~}}}||}}~~~~}||}}}~~{xvroruxxyxwurnjjjku~ƒƒ‚{wutrqomkifdacdfmswvusqopqqrrrrrsuvvvvtspkfcccirzqi_SG?;7DWjŠªÂ°Ÿ†|xvupjdZPA,$BaŠ´×ÌÁ²ˆnQ55:>BFIIJXpˆ›­»¨•…znf`[fu„ˆŒ‹„|}ƒ‰‰ˆ†ucRA/"%Cao}ˆ‹“›£«³»ÃÊÊ®’zfS]q…‚znb[[[UNF9+ /T‡¹ÆÎÔÓÑÑÑÑÍÆÀ¶«wP765NwŸ™Œ~jVB,+9FMTax®Ó÷øòëÒ¸˜e2 ,7ETbWMGKPW`iW=# Q‡²×ýýýúìßÏ»¨nP@0")W„•˜šl: /F]r‡›­ÀÐÝëãϼ’d>GQ\iv…”¤ŽrV;!*+&! 8e«ÉÞëùܵ{f`|˜¢™Ž‚wy{ymaQ<&  /PrŽ£¸ÇÒÝÓÉ¿³¦™Œ~pbTdt‰´ß鯣‚bB. !/@Qm‰¦ÆæìȤˆs^VPPp‘­ÁÔл§™Œ€thY@' L‚­ÂÖϳ—‰…ƒ€{ocer~”¬ÄÓáåϸU #@^s€Œ•œ¤±¿Ä«’pA"O|œ»×äò湌d?"& /`ª¿ÑÑÑÀ‘cH:,Muš¡§ªªª­³¸¬Žv]G4""/=e”À¸°§šxnhb][YYYZf|’´ÙþÒ¦}]>' (;Nbrvz€‹–Ÿ¨°‡\6&$Fv¥»Ðܾ¡‰xgYK>.%5Oi‡©Êż­s8%1BRbq’£³ÁÏÒÍǰ•yL !8Piš³Ê¹¨–‚ohjl_O?,TŒµÏèéäß°€V=$%?Y_^]ZX_£´²°ž„jQ9'1/ /Hm¨âà»–wX<1%$3ARdv|‡™ª½ÐäÌ“[: Fp§¿²œ†„~|kL,)-2QpŽªÆÎŽU"(4?DCCSiœºÒÓÕʱ˜n= 7Ph€•¥µ´«¢•‡yph\L<+1b‘­ÈÚÛÝÆ¡}bH4@LSPNLJIn™Â·–uYB*$"#A_w}„‰—Ÿ¦–†sX=,%.E\“ÉëѶ›fVJ>71,+).8CYu‘·Ýñ»„[C+/>Lcyž®²ª¡œ™–’…b@("&7Ij®·À·”pccchlnbVUfw¯ÎÑÐͶŸQ"&3AOYco~𥱧—ˆr\D) Er©Â¾º²›„nYC93-& 2j¢»ÇÓ¶™|cK:4.?Zu~†’–Ÿ­¼´¡iB$5ZŠº¸¯¦˜Šyrj`VNF@KVe}”²ÔöØ­ƒfI41.18?IS]jx„𡧬hA8//CXo‰¢°»Å°›‰€vme\I2$.<\}“ž©£—Ša7(9K]puts‚‘¡´ÆÈ´ ˆoV9$A\q†‘”˜’‹…{rjaYPG>710a“¹ÇÕ˱–}cJPvœ®­­¦ž–Šn[F/*7Pi…ªÏÓ°ŒpV&$0<`‰°¾ÍÓÌÆ¬…^SNKKKH@7>Oa{—±¥™‹wbI,:Wq‹ §­±³µ±¬¨ŒpVC/Em€’„yrje`\^_afkqy‚˜¶ÔÎŶˆ[;0&$&'8J[bhntyƒŽš‚sY>3BRdxŒ¤¾Ó»¢Št]OID<3*&"'B\sˆ®¾Ì¦€_O?@Qbkrx~„‹–¢£›”…sbJ2!$'6SqŒ—™š—ˆymf^YTPNLObv°ÑÑÀ¯š…oT9.8CN[ghhjuŠ•Ÿ”|dUH;62;\}–©»·°¨“ˆ{o`N<51.38Db€“–gLHCADGO]kx„›¥®²µ¬™…fC $(.8CQey€}zwqle]TMF?Vn…—©¹ÅÒÁ¢ƒmYIKNNNNPSVfx‰Œ†nU<88;Yw˜¡§«®ª¥ “‡zk[L<-2ELWajpw…•¥¶ÇͰ”zcM;+-@Q_msrrpnmie_THDGJS_k†¢ºÀž§re[RID??GOZhu‚™Ž‚oO/+9GWgxˆ˜¤§«ª©§ —ŽydN56Obt†›œˆtcUFGLPSVY^cqˆŸª°¶¯©}\E;0;Nbipvz}ypgZMA7-.;Id‡ª«ª§ ˜Žtkc[VROPRXhw‹ ¶ŸdR@2.*3BRap‡— ©®²µœ~`VKFLQ^r†Ž’”€l\VPLIFB>:GTcx °À¾¶¯pYYZ\aejotvxxxxtlcWH:( +Id{‘ ¬·°§ž’‡|ri`XPKFF]sƒ…ˆ€reTC3.*-ShzŒœ¢¨¨“…vfTB1,('+0@[u…‘œ˜”~obXNPTXdp|‰–ž¡¤šhO:2)'+/AYp{‡‘•š˜‰~qdWKDP]jy‰™«¼¬šˆvdUI=:;;BJTi~Ž™£¨«­•{bWLHPWcr€‹–ž›˜’†{m^OD:28>I]q€Œ˜šš™…rbZQMKIR]hu‚›§¦™|kZD- )3>LZiy‰ŒŒˆo_UNGFFKc{Ž›¨©¦£’€o]L>4+.7@Parƒ•žžž“pdYOOOUfw…‘ž¥¬±©¢–„q\D,,04BPa{”™–Ž…|ocYVSTVYetƒŽ˜£«³©‘ydR?7/,8CP_mx‚‹ˆ…€wmbUHFHIYk{ˆ•ž£§Ÿ”ˆvcQ@0(,0;KZp‡™–“ކ}o^NNQS[cm|Š”œ¤¨««•~jXF6(*AVhz‰–”Œƒync^XVY[aiq‚—¬®±®žzeOA5)2;FTbp}‹ŽŽŽ„zo_OGJLS^h|‘£§ª©£waQB4+#&8K\l|‰— “‡znaXPHOW`m{‰˜§¬«ª •‰oU@6+,5>ObtŽ•‘…zpeYNLILWbsˆžª²¹³­¢‡kWJ<62/?O^kxƒ—‘‡}qfZM@?KWfv†š¯½¶°¥”ƒp\H@959=GZmz…ŽŒ{k\OC@CFSbq„—¥ª¯ª¢™†p\OA864>N^jt~ƒˆˆ}si^TJ@8DP^n~‘¦»¹°¨˜‰xcM@>BEMW`m{†‰‹ˆvhWF@;;Pex‡–¢«µ«¡–‰{l[JA<7?GQk†—™›–އt_LHDDJO\mŒ™¥®¶µ£’o^N?2;CN\jv‹Š‡„ynbUHA?>HUbwŒžªµ³¤–‡xi\ODB@DLTap‚„„}viT?999BJUj~Ž˜¡¦¨©œrbR@.2AP`p‹˜šŽ‚saPG?9>BJYgxŒŸª³ºµ±¦ŽwcQ?@DIXhwˆ˜š“‹vk^PE?9:@F[u›§°²´ª–ƒseWMD@IR]iuƒ‘ ’…vfVF7(+5?Pbtƒ“¡¥£žšˆucUH>95BWmž•ƒugXJ;99:CKVfv‡š¬²¶· ˆscRF?7FYlu†‰Œ‰„~ti^M=39?IXg€œ¸µ²¬žsd[TMKJM]mz…”–—…r_N<479BO[l~Ž—Ÿ£¡ ˜Žƒp\KD=ATgv’––„rcXNFA<<<>KXkЍ³±®£–ˆoUEFHO[gntz~‚…‡‰‚tgYL>2&$;Sl† ¨ª«¢˜Žpd[RNLKQXau‰— ¨›†rbRD;34BP_n}ž¬®°¬¡–€dHC@AIQ^s‰’”•…}tkaUI<-/DZp†š«¼¸¦”~gQPNNQSW]bn|ŠŽ“”Žˆx^D2#&8K`vŠœ¯¬¢™…{qg\PEEGJc|‘–š™“|dME>:=@GTap¡³¿°¢’€n]L;CNYiz‡”•“’‹„|hUE<2147Ok‡›¯·©œŽth]SSSU[`hs}‰• ™ŽpQ=2''()Eay…‘™œ š’‹~reTC?GNZiwŒ¢°£—…nWJA9878=COe|œª¯²±š‚lXDBIQ]jw†”œœ›–ކwhXG6***N^m|‹“•—“‹wkZIA@@VrŽ•¡Ÿ‘}h[PFA<:;EYw•—“„ynaTQVZeq|||~„Š’©œˆtcSD<37HXiz‹‡ƒ{wtqnhaZ[[]enzŒŸ©¯µŸ‡qg]UQMNQSY^emv‡‡kR>FNXft‚‘  ›†~{wocWD02DWhy…Ž—‹zjXG?IT\aeghjy‰–œ¢ ™‘~fN@1,=N\eouz{wsokgc_XQJQWa}™§§§ —~m_ZUSUVWXYbkvˆšŸqbSLGDSbr„–›™—––———zdSG;:;=Rh|‰–‘~ld^[\]^^^afkt}‡”¡ª§¤“sSF@;?CIVdlnpmiekpsnjaQAGUcrœ¨©ž’„scbba\WQIAK]ny‚‰†ƒ{l\QH?Obsz‚‡‰Œ“˜”‘‚xl]NGFEZsŠŠŠ‡wog_\ZZ[\\[Z`lxªÄµ¦—„qaUIJPU`krmiilov~‡yl_ULFDCQeyŠ›¥šŽ„~xspme]VUSV\akx„‡ˆ†oWJJJOW_ejov|ƒ‹’–––Ž…{dNBIQZeouy|yuqkddfhd`[QGF\s…”¤§§§–…ugXV_ijihb[Zepx|€}xseXLIEOf~‰Ž“Ž‹ˆ„|wrmh^SKLNVj}|xph`[WUWZ^chlos{‚‹—£|obVTRT\dls{wpjjijmpj_SONNYeqš ¥–lgcaceda]`cfox†Œ‹†pYCGLS^is{„‡ˆˆ…ƒ‚‚ƒxpcRAKXdozƒ…ˆ‚wmaULQUY\^`abn{ˆ““Œ…{oc[SNXbjmooooruwtqlc[TOKNSYn„“’‘†zupkgc_[XVSYah{›Œ}n`RMKJS\fq}‚€ƒ†‰—š‹|oe\YYYeq~†Ž~nfc_acca__belt}‡‘™™˜zcZZZ`fmoqsuwxz{ywtldYH88ESbq„‰‹‡„ysrrrlg`VLO`q{ƒ‹‚zpcWLE>IZlrvxvtx„•—˜†|obYVT`s‡‡„xnfa\ZXWXZYYY]fo•¬§Ÿ–‰{picbdglrvsqpqsv|ufVNEAHNWbmw€‰†„„„„…‡‰qd`\[ckquxwusdTIKLQX_`__dinx‚‰‰„saT[ckv€‚€ztnf^Z\_]YVNE@QbrŒ‘‘‘Šyqifkpqpokfcny‚„~sh`XPONQ_mvz~€€€„ˆŠ†ƒ}shfffjns}†‡wne[[[[[[[[[_chpx‚œœ~qeY\_cinsw{wpijklrxvhZRNJS]gq{ƒ‡‹„xkhggkookggikqx€‚€{wm^ONQTZagkosw{ƒ‡…ƒ€|wqh`dmu|ƒ‡…ƒxrkd^`bba`^\Ycr€ˆ“Œ†€xpkgcktzzywrmpu{xtpdWMHCEHL\n}}}{vqprsrqpnkifceimx…‘†{odXSSSW[_ekpqsuy}ƒŠ†{rlgeginsy}‚}wsqonmme]XY[`lx…‹‹‹‰}qkmosx}xtqqrty~~{yrjbTE@KValxuqmlkkkknrvsqne]Zeov{yqi`WOICEOX]`b`_airx{~zupkgccchr|}|{uoiihfc`[UPRUX^dlxƒƒ~ysminsvvvtqorux{~ƒ†}n^TKEPZbhmqtwusrsux}}sjfddmw~{wl^PPPRV[[XTW[^is{|~|yvne[agmt|}zwusrpomiea]YUQMV`jpwyurpppqqppopppqqqw|€~}wj^XWVXZ\`effecb`hr{}~xrqstwz}……}ulcZ\afghgfeeeegjlsy{tmhd`fnwz}~~~|yvtqomlibZUSRYblnqqqpoljklmprsrpqrtw{{wsnid^XX[^bfhebcfiov}{wspmjgdgov{„|tnkihhhhhhfdb^Z^hrx}ztnmklmnrx}~~}zvvxywusle^^]^`bgmsrrqomnqsssspmlortwy|}ysmhb`bedcca__cgjmoqstpkffehpx{{{xurpmlmnpswqib`_aiqsssqnlhdbfjpw}}zxyz{~‚|yuqkeafjnswtnhgghknprstuuuuvz‚ƒ„~vnkjjjkkkkjhgeccfhiiifa\`flrx}~}zwsompturpjaY[`dimqrtrnjfc`gouwyxvuwz|~€€€|tlfb]cinoponnmllmopsvvspqrrxƒƒƒ|wrmmmnpsrniijjouyuqmifeeeimrvz|zxxxxz|}yuqmjhfehloqrqkecefjnrstuuuuuux|€}tlhiilorstsplid_bgmoppmjjnsw|€‚……€|wqklostutsrrrrqppnljheccchowz}~|{xurnjhhhlryxusokhhhjlnqtwutuwx|‡„~ysmhgfhjmpsvqlhhhjosromkjjlmpuz}„zutsttuuuutsrqopqrqqqnjhikmqtvxz{|~~}{ytojmoqsuutsqomkiilprstsrrvz}€‚‚€}yuronruvvvtqoprrrrqnkjiijlmsx|}~}|{ywvvvwwwuroooptxyvtqmjihilosx|}{zzz{|}}yvsqooooruwz|{wtrqqstssstttvy{}€€€}xssttwz|||{zyxvuuutrplgbcfinrwy|||{ywuwxxxxvspqsvxzzyxvrnkgcfjnoqrrrtwz|}}}|{xvtrqtx{zzywuuuutssqpoooprsvz~}|{zxyz{|}}~~}{yxxxz}{wspmlmnpsvy{|yvvvvx{~{xutrsstvxz{|{wrnmlmnoqrttuuuuvxz{{{wsrrstvxz|}{zyvsssssssqppswz|~}|zxvtstvyyyywvvxz|||yvspnkkkmsx{||zyyyz{{||||zxuuuw{€€~}zwssrssstttuuvwxy|~~}|zxwvuvwy{}}zxvuuuutqonmlnpruwy|~}||||{{{zwutttwy|||{yxurnooprtuuuvwwyz||}||{xtprtvx{|||{zywvvwxxxxvtrtwz|~~|zxwvy{}}}||||||{zyyxwuttttx{~~~}|||||{yxwuvvvwxy{}}|zywtsrrstuvxyyz{||}~}|zxwuvwwy{}~}zywvuutsrqqqsuwy{}}~}zxwwwy{|}~€€€€}|zvsrtuwz|~~~~}||||||||||}~~~|{ywuvwwxxxxxyz|}~~}{zxwwvxz|}~~~~}}|{zzyxwwvwwwy{~~~~LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/schlurf.wav0000644000175000017500000000333413263212010021311 0ustar aeglosaeglosRIFFÔWAVEfmt "V"Vdata^ÒÒÒÑÏÐÑÒÑÑÒÒÓÔÖØÙÙÙÚÚÙØÖרØÖÕÓÓÓÔÕÖÕÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÓÓÓÔÔÓÓÓÔÖØÖÔÓÒÑÐÐÏÏÏÏÎÎÏÏÏÐÓÕÕÔÓÒÑÐÏÎÏÏÏÑÔÖÕÓÒÒÑÐÏÎÎÎÎÏÏÐÑÓÓÓÓÑÏÏÐÒÔÖØÚÝàÚÔÏÏÐÑÒÓÓÓÓÐÌÉÉÈÊÌÏÐÒÓÓÓÔÖØÙÚÚÙØØÔÑÑÕÙÜÞàààßÙÒÍËÈËÏÓÓÓÔÖ×ÚÝßÞÜÚÖÑÍÌÊËÌÌÌÌÌÈÄÀÀÀÁÃÄÆÈÊÌÎÐÑÓÕÖØÖÔÑÐÏÏÏÏÐÒÓÕ×ØØØØØØØØØÛÞßÜÙØØØÖÔÓÒÑÐÏÎÏÐÑÒÓÔÕ×××ÖÖÖÖÔÒÒÒÒÓÓÓÒÑÑÒÒÑÐÏÐÑÒÔÕÖØÚÚÙØ×ÖÖÕÔÓÓÓÒÑÏÏÏÏÏÏÏÏÏÏÏÏÑÔÖÖÖ××ØØØØ×ÖÖÓÑÏÏÏÎÎÎÍÌÍÍÎÏÏÏÐÑÑÒÓÒÒÒÓÓÓÕÖØØØ×ÕÒÐÏÏÏÏÏÑÒÓÓÓÔÖØØØØØØ×ÖÔÒÐÎÌÊÈÈÇÈÊÌÎÏÑÔÖÙÙÚÚÚÚÙØØ×ÖÕÔÓÒÒÒÑÐÏÏÏÐÐÐÏÏÏÐÐÑÒÓÔÖØØØØÛÞàààßÜÚ×ÔÑÍÊÆÆÆÅÄÄÅÆÆÇÇÈËÎÑÔØØØØÛÞàààÞÛØÕÓÐÐÏÎÎÎÏÏÏÑÒÔÔÔÕרÖÕÓÕ×ÙÜßÞÚ×ÔÑÏÎÎÍÍÌÊÇÃÃÃÄÅÆÈÍÑÔÔÔØÜááâãããßÙÓÑÏÏÏÏÍÊÇÄÂÀÂÃÅÌÓ×ÙÛÚÙØÛÞááâàÜØÔÐÌÌÌËÊÈÇÇÇÄÂÁÃÆÊÏÕרØ×Ö××ØØØØØØØÔÑÐÐÐÒÕØÕÒÐÐÐÑÒÓÕÖØ×ÖÕÔÒÓÕØÙÙÙØÖÕÓÒÓÕØØØØÖÕÓÒÑÐÏÏÑÒÒÑÐÐÐÑÓÕØÕÒÐÒÕÕÔÓÔÕÖØÛÛÚÙ×ÓÐÍÊÈÌÐÔÖ×ØØØÖÕÔÒÐÐÓÕÚàæãßÛÒÉÂÁÀÂÄÆÌÓ××ÖØÜááááàààààßÝÜÖÏÇÅÄÂÂÂÃÅÆÉÌÍÌËÉÉÉËÏÓ×ÜàààÞØÒÎËÈÇÇÇÇÇÇÇÇÈÉÉËÌÌÌÌÍÎÏÒÕØÙÚÛÛÜÛÙØØØ×ÔÒÑÒÓÒÐÏÒÔÕÔÓÔÕÖÕÓÒÑÏÐÑÓÔÕÖ×ØÙØØ×ÔÑÏÎÎËÇÅÆÇÇÇÇÇÇÇÊÍÐÝéðððìæàÖÌÄÅÇÉÌÏÔÜãáàÞ×ÏǾµºÃÌÔÛáááàààÜ×ÒÏËËÎÒÔÕÖÓÑÎÌÊÈÅÃÃÃÃÆÊÍÏÐÒÓÔØÜàààßÜÙÕÏÊËÍÍÌËËÍÏÑÕØÕÒÏÏÏÎÍÌÌÌÌÐÕÙÜßàààÞÛÙÖÔÒÏÍËÉÇÈÉÊÎÓ×ÛßÞÜÙÖÒÐÐÐÓÚááÞÜ×ÒÍËÈÉÎÒÔÔÔÔÔÓÐÍÍÎÎÐÒÓÑÐÎÌÊÎÖßáâââáßÙÓÏÌÊÉÇÈÈÉÊËÌÌÌÌÎÑÕãðöñíêèæææäÛÓÌÆÁÀÀ¿»·³³³¶»ÀÅËÑÕÚÝÞààààÝÚ××ÖÔÑÎÌÉÆÃÁ¿¼¹º¾ÁÈÏÖÛßãæééééçåâáàßÜÙÖÕÓÑÏÏÏÏÏÏÏÐÒÓÓÓÓÓÓÔÔÔÕÖÖ×ØØØØØØØØØ×ÕÒÏÏÏÍÌÊÇÅÄÇÊÍÏÒÓÓÓÑÐÐÔØÙØØØØØÖÔÒÒÑÐÏÎÌËÊÈÇÈËÎÎÍÌÎÏÏÌÈÅÅÄÆÉÌÍÎÏÔÙáëöõïéæâÞ×ÐËÈÆÈÊÌÏÒÒÑÏÒÖÚ×ÒÏ×ßàÒÅÀÀÀÄÈÍÐÔÓËü¶°°°±·½ÃÊÑ×ÛàÝÚÖÑËÇÅÂÅÉÍÎÐÒÒÓÔÔÔÒÐÐÓÖ×ÕÓÖÛàáãâââáÞÜÛÚÙÖÔÓÓÓÒÑÑÓÖØ×Ö×רÕÑÍÍÎÏÒÖÙÜßáâãââááàÝ×ÐËÈÄÅÆÇÊÍÑØÞàààáâàÛÕÒÐÎÍÌÍÎÏÎÍÌËÊÉÇÅÄÅÇÈÊÌÏÔØÛÞßÚÕÑÏÌËÊÊÌÍÍÍÌÎÑÔ×ÚÜÚÙÙÙÙ×ÕÓÑÏÏÏÏÐÑÓÖÛàÜÙÕÔÓÒÐÎÌÉÇÇÇÈËÎÑÔ×ÙÙÙÕÒÑÔ××ÖÖÔÒÑÔרÖÓÕÖØ×ÖÕÓÐÐÑÓÓÓÓÓÓÔÕÖÖÖÖÕÓÒÓÓÒÑÏÐÑÑÒÒÒÑÐÏÎÌËÉÈÊËËÊÈÇÇÇÉÌÏÎÎÍËÈÈÊÌÎÐÑÐÏÎÍÌÎÒÕÖÖÖ·˜€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/miep.wav0000644000175000017500000000333413263212010020575 0ustar aeglosaeglosRIFFÔWAVEfmt "V"Vdata^‰ŒŽ‘”•••’Ž‹ˆ……‡‰Œ“•——“Œˆ„„„…‰’—›•Œƒ‡“™Ÿžœ•‰„‚‡Œ”¤¥¦¢™‘Šƒ}€ƒŽ˜Ÿ¡¤ž—…{vy|ƒ—ž¤¨¡š’‰€{xu‰“¨«§¤™‹}xrr{…ª­­¬›‹|sjkt} ±²´¯ ‘‚telv€’¥±¶»²¤–ƒpbgkw£®µ¼°¥—€i_``sŠ¡«µº¶±Ÿƒg_\\r‰œª·¼¼¼ ‚g]TXk~’§¼¼¼¶ŸˆtbPU`k‰§¼¼¼µªŸ„gMPSa¢²·¼¹·¯ŠeMKH]|œ¨³¼¼¼¬ŠiWK?Wo†œ²¼¼¼©’{dLBP_w˜¸¼¼º¯¤lIAGLq™º»¼»»»rHC?Fi¤¯º¼¼º–rTF7@YrŒ¥¼¼¼±”w^H1CYpŽ«¼¼¼­—‚cE1@Oi޳¼¼»­ŸŠd>3>Im–¼¼¼º´¯’d77=Hu¡¼¼¼¼¼¼^889O}¬º»¼¼¼°€P740U„±µ¹¼¼¼¡sD822_Œ«²º¼¼¼“f>5-;f‘¦±¼¼¼²ˆ^B6)Gr¨´¼¼¼¦XC3'Ms’¤¶¼¼¼œxVB.2Uy’§»¼¼µ–vYA)<]~•¬¼¼¼­sW;#Ef…œ³¼¼¼¤ˆlP40QrŒ£º¼¼·š}`D(7Ww©¼¼¼°™‚cA!=Yu’¯¼¼¼­œ‰a:(>Tr•¸¼¼º¯£Š^1.=Lsœ¼¼¼º¸µ\)2:Lz§¼¼¼¼¼¹…R15:W†µ¼¼¼¼¼©wF310Zˆ¯µº¼¼¼œnA927a‹¦°º¼¼ºfE;1ChŽ¡¯¼¼¼®ˆcK=.LnŽ ²¼¼¼¢|WH:8[~˜¨¸¼¼»’iIBFile created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/slurp.wav0000644000175000017500000003664613263212010021024 0ustar aeglosaeglosRIFFž=WAVEfmt "V"Vdata'=€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚ƒƒƒƒƒƒ„„„………††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡†††††††††††††††††††………………„„ƒƒƒ‚‚‚‚‚‚€€€€€€€€€€€€€€‚‚‚‚‚ƒƒƒƒƒƒ„„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒ„„„„„„„„„……………†††……………„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒ„„………††††††‡‡‡ˆˆˆˆˆ‡‡‡†††…„ƒƒƒ‚‚‚€€€€€€€€‚‚‚ƒƒƒ„„„„„„„„„„„ƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„„„„……………………„„„ƒƒƒ‚‚‚‚‚€€€€€€€€‚‚‚ƒƒƒ„„„„„………†††††‡‡‡‡‡‡ˆˆˆˆˆ‰‰‰‰‰‰‰‰‰ˆˆ‡‡‡†††………„„ƒƒƒ‚‚‚‚‚‚ƒƒƒƒƒ„„„……………†††††††††††††††††……………………„„„„„„ƒƒƒƒƒ‚‚‚€€€€€‚‚‚ƒ„………†††‡‡‡ˆ‰‰‰‰‰‰‰ˆˆˆˆˆ‡‡‡‡‡‡†††††……………………………„„„„„„„„„„„„„„………………††‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ‡‡‡††††††……„„„ƒƒƒƒƒƒƒƒ„„„………†††‡‡ˆˆˆ‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹‹‹‹‹‹‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‰ˆˆ‡‡†††………„„„ƒƒ‚‚‚‚‚‚ƒƒƒƒƒ„„„„„„……………†††‡‡‡‡‡‡ˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŒŒŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡ˆˆˆˆˆ‰‰‰‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰ˆ‡‡‡†††…„„ƒƒ‚‚‚€€€€€‚‚‚ƒƒƒƒƒ„„„……………………………………„„„„„„„„„„„„„„……†††‡‡ˆ‰‰‰ŠŠŠ‹‹ŒŒŒŒŒŒŒŒŒ‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ‰‰‰‰‰‰‰‰ˆˆˆ‡‡‡†…„„„ƒƒƒ‚‚‚€€€€‚ƒƒ„„……†‡‡‡ˆˆˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰ˆˆˆˆˆˆ‡‡‡†††††…………………………………………………………………„„„„„„„„„„„„„„„„„„„„„„„„„………††‡‡‡‡‡‡ˆˆˆ‰‰ŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š‰‰ˆˆˆ‡†………„„ƒ‚‚‚€€€€€€€€€‚‚‚‚‚‚ƒƒƒ„„„……†††‡‡‡ˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡†††††††††††‡‡‡‡‡‡ˆˆˆˆˆ‰‰‰ŠŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆ‡‡‡‡‡††††††††‡‡‡‡‡‡ˆˆˆˆˆ‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆ‡††…„ƒƒƒ‚€~}||{{{{|}}~€€‚‚ƒ„……†‡ˆˆ‰‰‰‰ˆˆˆ‡‡†††………„„„ƒƒ‚‚‚ƒƒƒ„„„…†‡‡‡ˆˆ‰ŠŠŠ‹ŒŽŽŽ‘‘‘‘‘ŽŒŒ‹‹‹ŠŠŠ‰ˆˆ‡‡†††………„„„ƒƒ‚‚‚€€€€€‚‚‚ƒ„„……†††‡‡‡ˆˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠŠŠ‹‹‹ŒŒŒŒŒŽŽŽŒŒŒŒŒ‹‹‹ŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆ‡‡‡‡‡‡††††††††††††††††††††††††††††††††††††‡‡‡‡‡‡‡‡‡‡‡ˆˆ‰‰Š‹‹‹ŒŽ‘‘‘’““““’’’‘‘ŽŽŒŒ‹ŠŠ‰ˆ‡‡††……„ƒƒƒ‚€€€~}}|{{{|||~€€‚ƒ„…††‡ˆ‰Š‹ŒŒŒŒ‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡†††……„„„„ƒƒƒƒƒ‚‚‚‚‚‚‚ƒƒ„…††‡ˆˆ‰Š‹‹ŒŽŽŽŒ‹ŠŠ‰ˆ‡†…„„ƒ‚‚€€€€‚‚ƒ„„…†‡ˆ‰Š‹‹ŒŽŽŽŽŒ‹‹Š‰ˆˆˆ‡††…„„ƒƒ„„…††‡ˆ‰Š‹ŽŽ‘’“”•–•”“’‘ŽŽŒŠ‰ˆ‡†…„ƒƒ‚‚ƒ„†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜˜——––•”””“’’‘‘ŽŽŽŽŽŽ‘‘‘’’’““”””•••”””“’‘‘ŽŽŽŒ‹‹Š‰‰‰ˆ‡‡††………„„„ƒƒƒ‚‚€~~~~~}}}}}}||||||||}~€ƒ„……†‡ˆˆ‰Š‹ŒŽŽŽŒŒ‹ŠŠ‰ˆ‡‡†…„„ƒ‚‚€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚ƒƒƒƒƒ„„„………††‡‡‡ˆˆˆ‰‰‰ŠŠŠŠŠ‹‹‹‹‹‹ŒŒŒŒŒŒŒ‹‹‹Š‰‰ˆˆˆ‡‡††…„„„………†‡ˆ‰Š‹ŒŽ‘’“”••––––•”“““’’‘ŽŽŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹Š‰‰ˆ‡‡†…„„ƒ‚€~}|||||||||}}}}}~~~~~~~~€‚ƒ„„…†ˆˆ‰ŠŠ‹ŒŽŽŽŽŒŒ‹‹Š‰‰‰ˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆ‰‰‰‰‰‰ŠŠŠŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹‹‹ŒŒŒŽŽŽŽŽŽŒŒŒ‹‹‹ŠŠŠ‰ˆ‡‡‡†††‡‡‡ˆ‰ŠŒŽŽ‘‘’“”•–—˜™˜—–•”“‘ŽŒ‹Š‰ˆ‡…„ƒ‚‚‚‚‚‚‚‚‚‚‚ƒ„„„…†‡‡ˆ‰‰‰Š‹‹ŒŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡††………„„ƒ‚‚‚€€~}}}|||}}~~€‚ƒ„„…†‡‡ˆ‰ŠŠ‹ŒŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyxwvvwyz{|}}~€‚ƒ…†‡ˆ‰Š‹ŒŒŒŒŽŽŽŽŽŽ‘‘‘’’“““”””•••–––——˜˜˜—–•“’‘ŽŒŠ‰‡†…ƒ‚€}|z{||}~€‚ƒ„…†‡ˆ‰Š‹ŽŽŽŽŒ‹‹Š‰ˆˆ‡††…„ƒ‚€€ƒ„…†‡ˆŠ‹ŒŽ‘’“•–˜˜˜—–”“’‘ŽŒ‹‰ˆ†…„ƒ€~~€‚‚‚ƒƒ„„…†††‡‡‡ˆ‰ŠŠ‹ŒŒŒŽŽ‘’““”••”’‘‘ŽŒ‹Š‰‡†…„ƒ‚€€‚‚‚ƒƒ„…††‡ˆ‰‰Š‹‹Œ‹Šˆ‡†…„ƒ‚€~}|zyxwvuttuvwxyzz{|}~€€‚ƒƒ„…††††††††††††††††††††††††………„ƒ‚‚‚€€€~~~€‚„…‡ˆŠ‹ŒŽ‘“”•–˜™šššš™™™™™˜˜˜———––––––•••••”””””””””””““““““’’‘‘ŽŽŒŒ‹‰ˆˆ‡†……„ƒ‚€€~~~}||{{zzzyyxwwwxxyyz{{|}~~€‚ƒƒƒ„……†††††††††††††††††††‡‡‡ˆ‰ŠŒŽ‘’“”•–˜™›œžžžœ›š™˜—–•”“’‘ŽŒ‹Š‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆ‡†……„ƒ€~}||{zxxwxxyz|}~‚ƒ…†‡ˆ‰ŠŒŽ‘ŽŒ‹ŠŠˆ‡††…„ƒ‚€€~€‚ƒ„…†‡ˆ‰Š‹ŒŽŽŒ‹ŠŠ‰ˆ‡†…„„ƒ‚‚ƒ…†‡ˆ‰‹ŒŽ‘“”•–—™š™™˜—–”“‘ŽŒ‹‰ˆ‡…„‚~€‚„…‡‰‹ŒŽ’“”–˜šœžŸ¢¤¡Ÿœ™—”‘ŒŠ‡…‚€}{xvsqonopqstvwyz{|}€‚ƒ…†ˆ‰Š‹‹‹‹‹‹ŒŒŒŒŒŒŽŽ‘’““”••–—˜˜™š››œœ›š™—–”“’Ž‹Šˆ‡†„ƒ‚€€€€€€€€€€€€€€€€€€€€€~~~}}}|||{{zzzyyxwwwxxyz{}~€ƒ„†‡‰Š‹Ž’“””“““’’‘ŽŒŒ‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆ‡‡‡†„ƒ‚~}{zyxvutsqponnnoppqqqrstttuvvwxxyz{{|}€‚ƒ…†ˆ‰Š‹Ž‘“”“““’ŽŒ‹‰ˆ‡†…ƒ‚€~|}ƒ†ˆ‹’”—™œž¡£¦©¬®°±¯­«ª¨¦¤¢ žœ›™—•“’Œ‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆˆˆˆˆˆ‰Š‹‹ŒŽŽ‘‘’’“”••–——˜š››œžžŸ¡¢£¤¥¥¦§¨¨§¦¦¤¡Ÿžœ›š˜–•“‘ދЉ‡†……„„ƒƒƒ‚‚‚€€~~~~ƒ…‡‰Š‹‘’”•—™šŸ¡¡¢¡Ÿœ›š˜—•”“’ŽŒŠ‰‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡†††……„ƒ‚‚€~}}|{zzyxyz{|}€‚ƒ…‡‰Š‹Ž‘“”–—˜˜˜———–––––••••••”””“““‘Ž‹Šˆ‡…ƒ‚€}|zywutttvwy{|~€‚„…‡‰‹ŒŽ‘’“””••–––——————˜˜™™™ššš™™™˜˜———––•”””““’’‘ŽŽŽŒŒŒ‹‹‹ŠŠŠŠŠ‹‹‹ŒŽŽ‘‘’’’“””””“‘ŒŠ‰‡†„ƒ€~|{yxvvuvvvwxxyyzz{|||}}}~~~}|{ywvtrqonlkigfdca_^`bdgilortwz|‚…ˆ‹“–˜–”’Ž‹‰‡…‚€}{yvtromkigijklmnopqrrsuvwxyz{|}~€€‚‚‚ƒ„„…†‡‡‡ˆˆ‰ˆ‡‡…‚€~|zxusqomkhfdb`]]]]_acdfhjlnpqsuxy{}‚ƒ„…†‡ˆ‰ŠŠ‹ŒŽ‘’““”“’‘Œ‹Š‰ˆ‡†…„ƒ‚€~‚„†ˆŠŒ‘“•—™œž ¢¤§©ª¬«ª¨§¥¤¢¡Ÿžœ›š™˜–•“’ŽŽŽŒŒ‹‹ŠŠŠ‰‰‰ˆ‡‡††……………………………………………………………„ƒ‚‚€~}}|{zzyxwwvvvwwxxyz{|}~~€‚ƒƒ„…††‡‡ˆˆ‰ŠŠŠ‹ŒŒŽŽ‘‘‘’’’’’““““““”””””•••”““‘ŽŒŠˆ†„‚€~|zywusqopqqsvx{}€ƒ†‰‹Ž’”—š ££¢¢¢¢¢¡ Ÿžœ››š™™˜—––•””“’‘‘ŽŽŽŒ‹ŠŠ‰ˆ‡‡†…„ƒ‚€~|{zyxwvutsrpppqrtuvwyz{}~€ƒ„†‡‰Š‹ŒŒŒŒŒ‹‹‹ŠŠŠŠŠ‰‰‰ˆˆˆˆˆˆ‡‡†††………„„„ƒƒ‚‚‚€€€~~~}}}|||{{zzzyyxxxxyz{|}~€‚‚ƒ„†‡ˆ‰‰Š‹ŒŽŽ‘‘‘’’“““”””””””””””•••••••••••”““’‘‘ŽŒ‹Š‰ˆ‡†…„‚€€€€‚‚‚ƒƒƒ„„„……………………„„„ƒƒƒƒƒ‚‚‚€€€€€‚„…‡‰‹ŒŽ’”–—™šœž ¡¢¡žœ™—•“‘ŒŠˆ†„‚}{ywutrrqpoonmmllkkjihhgffhiknqtwz}„‡Š“–™œŸ£¦§¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¦¥££¢¡¡ Ÿœ›š™—–••”“‘Ž‹‰†ƒ€}zwtqoljgda^ZXVUWY[^`cegilnprtvy{}‚ƒƒƒƒ‚‚‚‚‚€€€€€‚ƒƒ„…‡‡ˆ‰Š‹ŒŽ‘Ž‹‰‡…‚€~|zxvtrpnmjhhjlmoqsuvxz|~€„†ˆŠ‹Ž‘’“•–—˜™šœž ¡¢¢£¥¦¦¦¥¤¢¡žœš™—•“‘ŽŒŠˆ†…ƒ‚€€~~~}}}||{{{{{{zzz{||~€‚ƒ„…†‡ˆŠ‹ŒŽŽ‹‰†ƒ€}zwtqoljgda_\ZWUVXY[\^`acegijlnoqrtuvxyzz{{||}~~~€€‚‚ƒ„…†‡‰ŠŒ‘“”–—™šœŸ¡££¢ žœ™—•“ŽŒŠˆ…ƒ€~|zwutttuvvwxxyz{{|}~~€€ƒ„†‡‰‹’”—™›œž ¢¤¦¨ª««¨¥£ š—•“‘Ž‹ˆ†ƒ~|ywvvvvwwwwwwxxyyyzzz{{{|||}}~~~€€€€€‚‚‚ƒ„„…†‡ˆ‰Š‹‹ŒŽ‘’“”“’‘ŽŒ‹Š‰ˆ‡…„ƒ€~}|{|}~‚ƒ„…†‡ˆŠ‹Œ‘’’’‘ދЉˆ‡†…„ƒ‚~}{{{|}~€€‚ƒ„…†‡‡ˆ‰‰‹ŒŒŒŒ‹‹‹ŠŠŠ‰ˆ‡‡‡†††………„„………†‡‡ˆ‰‰Š‹ŒŒŽ‘‘’“””””””•••–––––——————˜˜˜˜˜˜˜˜˜˜˜———————————–•”’ŽŒŠ‡…ƒ}zxvsqomkjiilnprtuwy{}ƒ…‡‰‹‘‘’’’’’’’’“““““””””””“‘Ž‹‰ˆ†…ƒ€~|zxwusrpqrsuwyz{}~€ƒ„†ˆŠ‹ŒŽŽŒ‡‚}xsoje`[VQLGB>951.+-159=AEILQUY^bfjnrvz|~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~‚ƒ…†ˆ‰‹ŒŽ’“•–˜™›œœ›š˜—–•“’‘ŒŠ‰‡†…„‚€~}|{zyyxwvutssrqppoooppqrstuuvwwxyzz{|}}~~~}|{{zyyxwvvuuttsrrqrssuvxy{|}‚„†‡‰Š‹Ž’”–—™šœž ¢£¥¦¨ª¬®¯±²´²°®¬«ª§¥£¡Ÿ›™—•“‘‹Šˆ‡†…ƒ‚~}|{yxwvutrrrrtwy|‚…ˆ‹Ž‘”–™œŸ¢¥¨«­¯±²´µ·¸º»½¾ÀÂÃÅÆÈÉËÌÌÉÇþ¸³¯«¥ š–’ˆƒ~yupkgjlnqtw{~‚…ˆ‹Ž‘”˜›ž¡¥©¬«ª©©¨§¦¦¦¦¦¥¤££¢¡     ¢£¥¦¨©ª¬­¯°²³µ¶¸¹º¼»ºº¸¶³°­«¨¥¢ š—”’Šˆ‡‡‡‰Œ‘”–™›ž¡¤¦¨«­°³µ·¸¸¸·¶¶´³±±°¯®®¬«ª©¨§¦¤£¢¢¡  Ÿžœ››š™™˜—––•”“’‘ŽŒ‹Š‰ˆ‡‡†„………‡ŠŽ’–šž¡¥©®²µ¹½ÁÅÉÍÑÑÑÐÍÊÇÄÁ¾»·´°­ª§¤ œ™–”’‘’“”•––—˜™š›œžŸ  ¡¢¢ žœ™—”’Šˆ…‚}zwtqoljloqsuwz|~ƒ…ˆŠŒŽ’•—˜š—“Ї„~zwtqnkhda^\ZY[\^`cegilnprtvxz|~€‚‚€€~}||{zyxwvvtsrqpqrrtvwy{}€‚„…‡‰ŠŒŽ‘“”•••••–––––———˜˜˜˜˜™™™š›œŸ ¡¢££¤¥¦¨©ªª¬­®®®­¬ª¨¦¤¡Ÿœ›™—•“‘‹‰†…„………†††‡‡‡ˆˆ‰‰Š‹‹‹ŒŒŒ‹Š‰‡…„‚€~|{ywusrpnmkihgedddcccbbbaa``____^]]`dgknruy}…‰Œ“—›Ÿ£§ª®¬«©©¨§¦¤£¢¢ Ÿœ›š™˜—–•”“‘ŽŽŒ‹Š‰ˆ‡…„ƒ‚ƒ…‡ŠŒŽ‘“•—™› ¢¥¦¨¨¨¨§¥¤¢Ÿ›™—•“‘ŽŒŠˆ†„‚‚€€€€€€€€€€€€€€€€‚‚‚ƒƒƒ„„„………††‡‡‡ˆˆˆ‰ŠŠŠŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆ‡‡‡‡‡‡‡‡ˆˆˆ‰ŠŠ‹‹‹ŒŽŽŽ‘’““”••–—˜˜™š››œžŸ  Ÿžœ››š™˜˜—–••”“’‘ŽŽŽŒŒŒ‹‹‹Š‰ˆˆˆˆˆˆŠ’•˜› £¦©«®±´·¹»½¿ÁÂÄÅÅÅÅÅÅÅÅÅÆÈÉÉÉÉÉÉÈÆÅ½¸´¯«§¢ž™”Œ‡ƒ~yupmjhfedb`^^]\[YXVUSRPPOPPQRTUWXZ[\^`bcefhijlnppqrstuvvxyz{|}~~€ƒ„………†††‡‡‡ˆˆ‰‰‰Š‹‹ŒŒŒŽŽŽ‘‘‘’’’“““““”””•••–––——˜˜˜™™™ššš˜—•“Ž‹‰†„|ywtromjhegiknqsvz}€ƒ†ˆ‹Ž‘”—𠣡ž›—”‘ŽŠ‡„}zwtpmjfc`^^`acdfgijkmnoprsuvxyz|}€‚ƒ…†ˆ‰ŠŒŽ‘’”•–˜™š›››œžŸ    ¡¢¢£¤¤¥¦¥¤¢ ž›™—•’Ž‹‰†„‚€}{xvtttuvvwwwxxyyyzzz{{{||}~€‚ƒƒ„…††‡ˆˆ‰Š‹‹ŒŽŽ‘’“”•–—™š›œœžŸ ¡¢¢¢¢££¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££¢¢¢¢£¤¤¤¤¤¤¤¥¦¦¦¦¦§¨¨¨¨©ªªªªª©¨¨¨¨¨¨¨¨¨¨¨¨§§¦¦¦¦¦¦¦¥¤¤¤¤££¢¡    ŸŸžœ››š™˜˜—––•”““’‘ŽŽŒ‹Š‰ˆ‡…„‚€~}{zywvuutttttttttssssssssssstuwy{~€ƒ…‡ŠŒŽ’•˜š ¢¥¥¥¤¤¤¤£¢¢¡ Ÿžœœ›ššš™˜—–•“’Ž‹Šˆ‡†…„‚~}|zzyxxwvutsrrqpoonmllmnnqsuxz}‚„‡‰ŒŽ’•˜šœ››˜–“Ї…‚|yvsqnkiffghjmoqsuxz}„†‰‹Ž’•”””””““““““’’’‘‘‘‘‘ŽŽŽŒŒ‹‹ŠŠ‰ˆ‡‡†††…„ƒƒ‚€€~}|{zyxwvvutsrponmlkigfdb`^][ZXUTRQONMMMNOQRTUVWXYZ\\]^`bcdfjnsw{€…‰Ž’–œ¡¦ª®³·»ÀÅÉÇÆÅÅÅÅÅÅÅÅÅÃÂÁÁÁÁÁÁÀ¿¾»¸µ²¯¬©§¤¢ ™–”‘Ž‹‰‡†…†‡ˆˆ‰ŠŠŠ‹ŒŒŽ‘’’“”••–——˜™š›œžŸ ¡¡¢¡  Ÿžœœ›šš™˜——–••”“’’‘ŽŽŽŽŽŽŒŒŒ‹‹‹‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡††……………………………„„„„„„„„„„„ƒƒƒ‚‚‚€€~~~}}}|||||}}}~~~€€€‚‚‚„†ˆŠŒ’”•—™›œžŸ¢¤¥§¨¦¥£¡Ÿ›™—•“‘ŽŒ‹‰‡…„‚‚ƒ„„…††‡ˆ‰Š‹ŒŽ‘’’”•—˜š›œžŸ¡¢¤¥§¨©«¬®­«ª§£Ÿ›—”Œ‰…~zwsolhdb`_`aaaabbbbbbcccccdddegikmnpqsuvxz|~€‚„†ˆ‰‹‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡†††……†††‡‰ŒŽ‘“•˜™›Ÿ¢¤¦¨ª¬¯¯°¯¯®­¬¬«ªªªª©©¨§¦¦¥¤¤£¢¡¡    Ÿžžœœœ›››ššš˜—•“’ŽŒŠˆ‡…ƒ}{ywutrstuuvwxxyzz{}~~€€‚ƒƒ}|zywutrqonlkigecbbbehkmprux{~„‡ŠŒ’•˜ššš—”’ŒŠ‡…‚|zwuroligghhkmptwz}„‡Š“–™œŸ£¤¤¤£¡ Ÿœ›™˜—–•”“‘ŽŽŽ‘“–™œ £§ª­¯²µ¸»¾ÁÃÆÉËÌÉÆÂ¾º·´±®ª§¤¡™•’ŒŠˆˆˆ‰Š‹ŒŽŽ‘‘’“””•–—˜™ššš›œœŸ    ¡¢¢£¤¤¥¦§¨ª«¬¬­®®°±³³´µ¶¸¹ºº¸µ³°­«¨¥¢Ÿœ™–“‹ˆ†ƒ€}€‚…‡ŠŒ‘”–™›ž¡£¦©¬¯²´¶´³²±°¯¯®­¬¬ª©¨§¦¥¥¤£¢¢£¤¤¤¤¥¥¦¦¦¦§¨¨¨¨©©ª©¦¤¡ž›˜”‘Ž‹‡„}zwtpmjgfhknrw|€…‰Ž’—œ ¥ª¯´¹¾ÂÅÅÅÄÂÁÁÁÀ¿¾½¼º¹¸¸·¶µµ´³¯«¨¥¢Ÿ›˜•’‹ˆ…‚~{xvsqqqrstuwxy{|}~€‚ƒ„…‡‰‹Ž“•—™›ž £¥§©«¬®°²³´³±¯­¬ª©§¦¤¡Ÿžœ›™—•”’Œ‹‰‡…„‚€~}{zxvusrpoppqqrsstuvvwxxyz{{|}~~}||{zyyxwvvuttrqppponnoppqqrrstuuvwwxyzzz{|}~€ƒ„…†‡ˆŠ‹ŒŽ‘“’’’‘ŽŒ‹Š‰ˆ‡††…„‚€~~~~~~~~}}}}}}}}}}}}}}~~~~~~~~~yuqmjfa]YVRMIE@;8520//38=BGMRW\bglqv{€…‹’”•”’ŽŒŠ‰‡…ƒ€}{ywvtrrrstuwxz{}~€‚„…‡ˆŠ‹Ž‘‘‘’’’““”””•••“‘ŒŠˆ†„‚}{ywtromljhfhjloqtvxz}‚…‡‰ŒŽ’”–˜˜˜˜—————––––––––•••••••••••••••••••••••••”””“““’‘‘ŽŽŽŒŒ‹‹ŠŠŠ‰‰‰‰‰‰ˆˆ‡‡‡‡‡‡†††††………„„„ƒƒƒ‚‚‚‚‚€€€€€‚ƒƒ„…†‡ˆ‰ŠŠ‹ŒŽŽŒ‹Š‰‡†…„‚€~|{zyyyy{|~‚„…‡ˆ‰‹ŒŽ‘“”“““‘ŽŒ‹Š‰ˆ‡…„ƒ‚€~~~}}|||{{{zzzyyxxxwwwwwwvvuuutttsssrrqqqrrrtx{~…ˆ‹Ž‘”—šž¡¥©«®±²´²°®«¨¦£¡Ÿœš—•’ŽŒ‰‡…„‚€€~~}}|{{{zyyxxyz{|ƒ„†ˆ‹’”–˜šœž¡¡¡ Ÿ›š˜—•”’‘Ž‹Šˆ‡…„‚‚‚€~~}|{{zyyyxwwvuusrponmkjihgedba_^\[\]]`behjloqsvx{}€‚…ˆŠŽŒŠ‰ˆ‡…„ƒ‚~|{zyxvwwwxxyyz{{|}}}~€€‚‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„………†ˆ‰‹Ž‘“”–—™›Ÿ ¢£¥¥¦¥¤¤¢¡ žœ›š™˜—–•”“‘ŒŠˆ†…ƒ}{ywusqpnljjjjkmprtvx{}ƒ…‡‰‹‘’’’‘ŽŒ‹‰‰ˆ‡†…„ƒ‚€€€€‚ƒƒ„„„……†††‡‡‡‡‡‡„‚€~|zxvtrpnljhfda_^]]`begjloqsvx{}€‚…‡ŠŽ‘’”•–—˜™š›œžŸ¡¡¢£¤¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¤¡ž›˜”’Œ‰†ƒ€|yvspmjgccccdeeffgghiiijjjklmmnortvy{}€‚„‡‰Œ‘“•—šœžœš˜—•“‘ŽŒ‹‰‡…„‚€~|||}}~€‚ƒ„…†‡ˆ‰Š‹‹ŒŒŒ‹Š‰‰ˆ‡‡…„ƒƒ‚€€~~€‚ƒ„†‡ˆ‰ŠŒŽ‘’“”•–––•••””””””“““““’’’’’’‘‘‘‘‘ŽŽŽŒŒ‹Š‰ˆ‡†…„ƒ‚€}|{zyxwwwxxyyz{{{|||}~~€€€‚‚‚ƒƒƒƒƒ„„„………†††††‡ˆˆ‰‰‰ŠŠ‹‹‹ŒŒŒŽŽŽŒ‹‰ˆ‡…„ƒ‚€~}|{yxvvuvvwxyyz{||}~~~€€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œœœžžŸ    ¡¡¢£¤¤¥¦¦£¡Ÿœ™–”‘ŒŠ‡„|ywtromnpqsuwy{}~€‚…‡‰ŠŒŽ’“•””““““““’’’‘‘ŽŽŽŒŒŒŒŒ‹‹‹Š‰‰‡†…ƒ‚€~}|{yxwutsrppppqrsuvwxyz{{|}~‚ƒ„„„„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒ„…††‡ˆ‰‰Š‹‹ŒŽŽ‘‘’“”–—™šœŸ ¡£¤¦§©ª¬­®®®­«©¦¤¢Ÿœš—•“Ž‹‰‡…‚€~€‚ƒ„…†‡ˆ‰Š‹ŒŽŽŒ‹‹Š‰ˆˆ‡†††…„„‚€~}{ywtsqpnlihfdb_][Y[]`bdfhjlnprtvxz|~€‚„…„„„„„ƒƒƒ‚‚‚€€~~~}|{zyxwvuttsrrqponmnnnoqrtvxz{}‚„…‡‰‹ŽŽŽ‹‰‡…‚€~|zxusqomkhfdddefhijkmnoqrstuvxy{‚ŠŽŽŽŒŒ‹‹‹ŠŠ‰‰‰†‚~}}}|||||{{{{{{zzzzzzzz{|}€‚ƒ„…†‡ˆŠ‹ŒŽ‘’’“’‘‘ŽŒŒ‹‹‹‹‹‹ŒŒŒŒŒŽŽŽ‘‘‘‘‘‘’’“““””””””•••––––––––––––––––––––––––•“‘‹‰‡†„}|zwusrpomnprtvxz|~€ƒ…‡‰‹‘“•—˜™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜—–•”’ŒŠ‰‡…„‚}{zxwwwwxyzz{|}~€€‚ƒƒ„…††‡‡‡‡‡ˆˆˆˆˆˆˆˆˆ‰‰‰‰‰ŠŠŠ‹ŒŽ‘’““”•–—˜š›œžžž›š˜–”“‘ŒŠ‰‡…ƒ‚~€€€‚‚‚‚‚‚ƒƒ„…†‡‰‹’“•—™šœž ¢¤¦§¨¨¨§¦¦¥£¢¡ Ÿžœ›š™˜˜—•””“’’’‘ŽŒŒ‹Š‰‰ˆˆˆˆˆˆˆˆ‰‰‰‰‰‰‰‰ŠŠŠŠŠŠ‹ŒŽ’”–—™›Ÿ¡£¥§¨ª¬®°°°°­ª§¤¡ž›˜•“‹ˆ…‚|yyyy{|}~€‚ƒ„†‡‰ŠŒŽ‘Œ‹Š‰ˆ‡†…„ƒ€~}|{zyyxwuutssrqppoonnmlllmnoqrtuvxy{|~‚„…†ˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹ŒŒŽŽŽ‘’’“”””•–•”“‘Ž‹Šˆ‡…„ƒ€~}{zyxwxxyyyz{{|||}}~~~€€‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„……†ˆ‰Š‹ŒŽ‘“”•–—˜™ššš››››››››œœœœœœ››š™˜˜—––•”“’‘ŽŽŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠŠ‰‰‰ˆ†…ƒ‚~|{yxwvusrpooooqtvy|‚…ˆ‹Ž‘”–𠣦¨¨¨§¥¢ žœš—•“‘Šˆ†„‚€€ƒ„†‡ˆ‰‹Œ‘’”•—˜˜—–•”“’Ž‹Šˆ‡†…„ƒ‚€‚ƒ„…†‡ˆ‰Š‹Ž‘’“”””“‘ŽŒ‹Š‰‡†„ƒ‚€~~~‚‚ƒ„…†‡ˆˆ‰ŠŒŒŽŽŒŠ‰ˆ‡†…„‚€}|{zywxxxyz{{|}~€‚ƒƒ„…††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆ‰Š‹Ž‘’“”•—˜™š›œžŸŸ Ÿžœ›š™—–”“’‘ŽŒ‹Š‰‡‡††††††††††††††††††††………„„ƒ‚€€€~}}|{{{zyyyyzz{|||}}}~~€€€ƒ„……†‡ˆˆ‰ŠŠ‹ŒŽ‘’’’’“““““““““““”””””””””••–––——————˜˜™™™ššš™˜˜—–”“’ŽŒ‹‰ˆ‡…„‚€€€€‚‚‚ƒƒƒ„„„„„…………………………………………………………………„ƒ‚€€~}|{zzyxwwvtssstuwxyz|}€‚ƒ…†ˆ‰Š‹ŽŒ‹ŠŠ‰ˆ‡‡†……„ƒ‚‚€€€€‚ƒ„†‡ˆ‰ŠŒŽ‘’“”•–––•”“’‘‘ŽŒŒ‹Š‰‰ˆ‡‡††………„„„ƒƒƒ‚‚€€€€€€‚„…†‡ˆ‰Š‹ŒŽ‘’“•–––•”’‘ŽŒ‹Š‰ˆ†…„ƒ‚€€ƒ„……†‡ˆˆ‰ŠŠ‹ŒŽŽŽŽŒŒŠ‰ˆˆ‡†……„ƒ‚€~}~€‚ƒ„†‡ˆŠ‹ŒŽ’“•–˜———–––••”””““’‘‘‘ŽŽŽŽŽŽŽŽŽŽŽŽŒ‹Š‰ˆ‡†…„ƒ‚€~}|{zyyyzz{|}~€‚ƒ„…†‡ˆ‰Š‹‹‹‹ŠŠ‰ˆ‡‡†……„ƒ‚€~}||||}}~€€€‚ƒƒƒ„„„………††‡‡‡ˆˆˆ‰ŠŠ‹‹ŒŒŒŒŒŒ‹Š‰‰‰ˆ‡‡†††…„ƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ„…†‡‰Š‹ŒŽ‘’”•—˜™˜˜˜—–•”’‘ŽŽŒ‹Š‰ˆ†…„………†††‡ˆ‰‰Š‹‹‹ŒŽŽŽŽŒŒŒ‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‰‰ˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‰ŠŠŠ‹‹‹ŒŒŽŽŽŒ‹Š‰ˆˆ‡††…„ƒƒ‚€€~~~~~}}}}}}||||||||}~~€‚ƒ„…†‡‡ˆ‰ŠŠ‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŽ‘’’’“““”••––••”“’’‘ŽŽŒ‹Š‰‰ˆ‡‡†…†††‡‡‡ˆˆˆ‰‰ŠŠŠ‹‹‹ŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡††……„ƒƒƒ‚‚‚€€€€€€€€€€€€€€‚ƒƒ„…††‡ˆˆ‰‹ŒŒŽŽŽŒŒ‹Š‰ˆ‡††…„ƒ‚€~}||||||}}~~~~~~€€€‚‚‚ƒƒ„„„………†††‡‡‡ˆˆ‰‰‰Š‹‹ŒŒŒŽŽŽ‘’’’’’’’‘‘‘‘‘‘‘‘‘‘‘‘‘‘’’’“““””•••–––———˜˜—–•”“’‘ŽŒ‹Š‰ˆ‡†……„ƒ„…†‡‡ˆ‰ŠŠ‹ŒŽŽ‘’“””””“’‘ŽŽŽŒ‹Š‰ˆˆ‡†…„„„„…†‡‡‡ˆ‰‰ŠŠŠ‹‹ŒŒŽŽŽŒ‹ŠŠ‰ˆˆ‡†……„ƒ‚‚€€€‚ƒ„…†‡‡ˆ‰Š‹ŒŽŽ‘ŽŒ‹Š‰‰ˆ‡††…„ƒ‚€€€€€€‚‚‚‚‚ƒƒƒ„„„„„………†††‡‡‡ˆˆ‰‰Š‹‹‹ŒŒŒŒŒŒ‹ŠŠ‰ˆ‡†…„ƒ‚€~}|{|||}}}~€€‚ƒƒƒ„……††‡‡ˆ‰‰Š‹ŒŒŽ‘’’’“””“’‘‘‘ŽŽŽŒŒ‹ŠŠŠ‰ˆˆˆˆˆˆˆ‡‡‡‡‡‡††††††††††††††††††††††††††††††‡‡‡‡‡ˆˆˆˆˆˆˆˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‰‰‰ŠŠŠŠŠ‹‹‹ŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹ŠŠŠŠŠŠ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆ‡‡†………„„„ƒƒ‚‚‚€€€€€‚‚‚ƒƒƒ„„………†††‡‡‡ˆˆ‰‰Š‹‹‹ŒŒŒŽ‘‘‘ŽŽŽŽŽŽŒ‹ŠŠŠ‰‰ˆ‡‡‡†…„„ƒ‚‚‚‚‚‚ƒ„„……†††‡‡‡ˆˆˆ‰‰ŠŠŠ‰‰‰ˆ‡‡†…„„ƒ‚€~~}|{{{|||}~~€‚ƒ„„………†‡ˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡††††††……………………††††††‡‡‡‡‡ˆˆˆ‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡†††††………………„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€‚ƒ„„…†††‡ˆˆ‰Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠŠ‰‰‰ˆ‡†††………„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„…………………………………………………………………………†††‡‡‡‡‡ˆˆˆ‰‰‰‰‰‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‹‹‹‹‹‹‹‹ŒŒŒ‹Š‰‰ˆ‡‡‡†……„ƒ‚‚‚€€€‚‚ƒ„„„………††‡‡ˆˆˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆˆ‰‰‰‰‰‰ŠŠŠŠŠ‹‹‹‹‹‹ŒŒŒŒŒŒŒŒ‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡†……………………………………………………………………………„„„ƒƒƒ‚‚‚‚‚€€€€€‚‚‚ƒƒƒ„…†††‡‡‡ˆˆˆ‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰ŠŠŠ‰‰‰‰‰‰‰‰‰‰‰ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‰‰ŠŠŠ‹‹‹‹‹‹ŒŒŒŒŒ‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡†††………………„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒ„„……†‡‡‡ˆˆˆ‰‰ŠŠŠ‹‹‹‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ŠŠ‰‰‰ˆˆˆ‡‡‡††………„„„ƒƒƒƒƒ„„„„„„………††‡‡‡‡‡‡ˆˆˆˆˆ‡‡‡‡‡‡†††††………„„„„„„„„„„„………………………†††††‡‡‡‡‡‡ˆˆˆˆˆ‰‰‰‰‰‰ŠŠŠŠŠŠŠŠ‰‰‰ˆˆ‡‡†………„ƒƒ‚‚€€€€€€€‚‚‚‚‚‚ƒƒƒƒƒ„„„„„„„„………………†††††††††††………………„„„„„ƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒ„„„……†††‡‡‡ˆˆˆ‰Š‰‰‰ˆˆˆˆˆˆ‡‡††††††………„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒƒ„„„……………………………„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚€€€€€€€€‚‚ƒ„„„…††‡‡ˆˆˆ‰‰‰ˆˆˆˆˆ‡‡‡†††………„„ƒƒƒƒƒƒƒƒƒ„„„„„………………††††††††††††††……………„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒ„„„……………†††††††††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡†††………………„„ƒƒƒƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/amoebe.wav0000644000175000017500000000327413263212010021076 0ustar aeglosaeglosRIFF´WAVEfmt "V"Vdata>’—šš™•‹uh[WTVpŠ¥ÁÝèæåͰ“rQ5'2Vy•±ÊØçëèåË«ŠnR:+6`Š¥ÁØàééâÛÃ¥‡lR;/$"+4No¨¿ÓÚááØÏ» †nVA5)'1;RpŽ¢µÆÎÕÖÏǵ›iR<1%#2@Wt‘¤µÆÉÌǵ£sYH8+/3>Umƒ™®¹ÁÈÄ¿¶¢ŽzeOA5+29E]uŠœ®¸¾Å¾·¬•}hWF<5.9ERh’¡°¶¹¼°¤—„q`RE@?>LZi|ާ±²°®¢•ˆxh\TLLOS`n}œ¨®´±ª£•†wj\PHABIPm²ÉáðíêØ¹™xV5( 5ZžºÕÞçéÜϸ•sYA*$8X„°ÆÓáçíëѶ˜vS>.@c…¦ÆÕÛáÝØÐ´—{_D1$#2Ce‡£·ÊÔØÝÐÁ±“tYD.!-Mm‰¥»ÄÍÐÎÍ»¤rX@0!5Ro‹¨¿ÈÑÒÎʵ›‚fK3',;Vv–©»ÊÏÓ̺§pR@/"""0On‰¢ºÅÎÓÌŵ˜{bK4.)):Ka~›¯½ÌÊÇ«•~gPB:3;FRl…œ­¾ÇÊ;¬š„n[OC@BETgyˆ˜ ™›Ÿ£¸ÑèäàÔ²pQ1"(0"%-6]…ªÀÕåìóáæ…dF6'!"Bt¥»ÍÞâçáÌ·™tP<,'.?d‰¦¼ÒØÛÛdz›{ZB/#-8Yz˜¬ÀÌÐÕǵ£„fK9&!%)Fiœ«¸½ÃÀ·®šiVD542>BVj}¢¬²¸­¡•‚o_SGEHK^tˆ–¤­®°¦˜‰xhXRLLU^l}Ž—Ÿ¥¡œ–‰}rg]ZYZeoz†“šž¢›“‹€ukc\XWW[_bnzЧÃ×ãîæ×É›kB/2^ŠªÉáááÔ·šyW4(4Mk’¸ÏÞìÞλ™vXA*#%&N|§¿ÖæçéÔ²pQ4'?`ƒ§ËÙáç×ǰ‹gL9%-;Io”³ÁÏÑɪŽqZC48K`u–·ÊÁ¸£†h^XUq¤°¼¶¡xcP^k{‘¨¯©£xa[VYn„“š¡˜Š|pd^gp{†‘‰ƒwkbcekwƒˆŠŒ‚xnga`hoxƒ‹ƒ{urpty~„…‚{xuuwx{}~}{zzzyyz{|}‚‚‚€}|zyyyz|}~~~~~~~}}}||{{{}ƒ…‡…„‚€~|||}~~~~}{xuspw€‰³Ä½·¥ZG?6Y€¤±¾·•r]QDa‚¡¥¨ „h_bdz“©¢œ‘|gfq{ˆ–¡”‡}vpu€‹‘’Š‚}„‰—”‹‡ƒ‚…ˆ‡…ƒ~xrw{€…ŠŠ†‚}xsx|~~~{uooqrw|}zwurvz€tjefgny„}ytoou|†‹†€}}~ƒ~{ywwz}~~~}}}~~}}|{zxz~‚‚€~~~~}|LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/blurb.wav0000644000175000017500000000440013263212010020744 0ustar aeglosaeglosRIFFøWAVEfmt "V"Vdata„€}~€~{yxwxyz|„‡‡‡†‡ˆˆ‰‰ˆ‡†…~|{zyxvusrqprux{}€„‰ŒŽ’”•“‘ŽŒŠˆ„zuqmlkjihjlnqswz~ƒˆŽ“—œœœ›š˜•’Ž‹†xsnjfdaaabdfimqw}„Š‘–™œžŸ ŸŸž›—’Œ†xplhd`][[[_chlptzˆ—ž¥¬¬¬ª¤˜“Žˆ‚{tmgb][ZY\^adglt}ƒˆ“™ž¢¥§§§£˜’Œ†|umd_ZWWWX\_cinu}…•œ¢§ªªª¨¦¤ž™’‰wnfa\XVTUVW]dks{‚ˆŽ“—›¡©¯¯¯¬£›“Œ…{vnga\WVVVZ^ciou|ƒŠ‘˜ž£¦¦¥¤¤¤ š•…}umf_YWVWYZ]bgmt|„Œ”˜›ž ¢£¤¤ œ˜‘‹„|tnhb^YWY[^bfjns|„Œ“›Ÿ ¢¤¦¦¤¡œ•†€zvrnic^ZWY\^fmt{‡‹”˜œ ¤¦¦¥¡œ–‰‚|uplieb^][\afkotzˆ•›Ÿ£¦§¨¤Ÿš”‡|vqkigdb__`aejpw~„‰Ž’–š ¢ Ÿžœš–‡€ysnjgdabdfilptx|‚‡Œ‘–šŸžœ™–’މƒ}wtpnljhfehknrvzƒˆŒ‘”˜›››™˜–‘‹…„‚|xtojgedgjlnosw|ƒ‹‘•™›œœš—“Œ†ztpmifca^\]`bhov~…Œ”› ¤¨ª¬¬§¢—‘‰€wlbZVRRSSUWZ`goy„™¤©®²²²±®«¤š‘…ymd[SOJGEDKQYdp|ˆ•Ÿ§°³¶·µ²­¥œ’‡|pe\VPPSUWZ\dkt~ˆ‘˜ ¤¨ª¨¦¡›”†wpjgdb`^acfkpv~†Œ•••–––”Іƒ|zwusssssssuwyz|}ƒ…‡‡ˆ‰‹ŽŽŽŠ†‚~}|zwuqnjjjlpsx~ƒˆ’—œ £¦£ ž•Œƒzqh`WRMJKMQ[do|Š–£®´º¾ÁÄ¿·¯ €qbULC@?>BFMZguƒ’ž©´¸½¿¼¹³ª¡•ˆ{ocYWTRQPV]dnx‚˜Ÿ¥ªªª©¤Ÿš•‘‰€woga^[\`ciov}…‹•𡍧¦¥Ÿ™“‹ƒ}wrolid`_``elr{…”𠤍©ªª¤–ކ~wpkfb`__achpx~„‹‘˜œŸ¡£¥¦¢Ÿš†|tlheddefhjpx€Š”ž¡¤¥£¡˜“Œ†xqje``bcjrx}‚ˆŽ•š ¥£¢Ÿ™“ˆ„€}yvrniedfgjnqx‡˜ §®®®­§¡™‚vi]VPMRXamy…œ¢©­­­§œ‘„vid^]afmv~ˆ‘𡍍£ž•Šwnhhhjmpu{€‡’’“‹†€xsstw€ˆ˜Ÿ¡£¡˜Žƒvi_WNOPScrŸ«·Â½¸°žŒ{jYOHCLUat†—¥´¶¶µªŸ“‚rdXLNQU`jv„’¦°­«¦™Œ‚yqmkihfgmsz‚Š”—•’Љ‰‰…€|xtpmkkllqv|‚‰—ž¢¤¥œ”‹tlf`acekqx‚Œ”š Ÿœš‡}umhgehkntyƒˆŽ•œžŸž—ˆ‚{vqlifcb`eltŠ•¤¨§¦ —„ynbWPPP[k{Œž­´»º²«}jWG?67@I\tŠŸ³ÃÆÊŽ´ ‹vdRD>9>HRf{¢´ÁÅÊÀ°¡‰q[J:0-*7HYzš¸Íâèäàʰ–tS6" 5Vx ÉåðüñÞÊ¥~Y; 9U|¤ÆÝôøíãÆ¥„a>" -Ouš¸×ëîðßŪ†b?'.Oo’¶ÔâðëÕÀŸzV<")Jj‹­ÎÚææÒ½žwQ8 0Rs’¯ÍÒÖÔ¼¥ŠkM:, 3G^Ÿ·ÈØÏÀ°mP<($)/Hd€›¶ÉÑÙË´`D5''9Je„£¶ÉÔ˯”x_F.+',AVpެ½ËÕȼªt\E/028Rl„š°»ÀIJ¡ŽzfWMCIS^r†–›¡ž—…{qkecgkr|†’–“Š‚ysnimqv‡‘•‘Š„xmda^aiq{…–Ÿ›—‡}wqnpsw}‚†‡‰†‚~wpkjiow‡”””‘Œ‡€yqpoqw~„Š‹‚zrlffgis}ˆ—š˜–ˆ€yrlllnqu|„Œ””Žˆ‚|vttux{~…‡‡‡„‚{wtsrvzƒ†‰‰‰ˆ†„}yvssw{„„„ƒ‚€~|zyyy{}€ƒ……†„|yvvuw{‚…‡…„ƒ€}zxuwy{}€‚„††…„}yvsrux}ƒ‰‹‰…€{usrqux|‚ˆŒŽŠ…{upporx~„‰ŒŠƒ|wqlnqsy€…‰Œ‰‡‚}xsoosv|‡ŠŒ‰…€yrommrw|‚‰ŒŽŠ…€ztpnlpv|‚‡Ž‹†€zslnoqv|ƒ†…„„€|ywuuvwz~‚„††…„~zxuuwy|‚„…†„‚€|yvutvxzƒ‡‰‹‰…€|xtttvz‚„‡††…|ywtvwy|~ƒ††††ƒ~zwtsuwz~ƒ†‰‹‡‚~zvtttwz~„†††ƒ€|yvuuuw{‚„†…„ƒ|yvtvxz~‚„„„ƒ}{yyyz|‚„ƒƒ‚€}{zyz{|‚ƒƒƒ‚€}|||}~€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/oeffnen.wav0000644000175000017500000011534213263212010021266 0ustar aeglosaeglosRIFFÚšWAVEfmt "V"Vdatadš€~}ƒƒƒ}|z{„‡ˆŠ†€{|~€ƒ††}|~€ƒ…†…ƒ}|zy…Їƒ€~|zx}‚‡‰Šˆvv~†ˆˆˆ€xt{ƒ†††…„ƒ}wtx{€…Šƒxlx…Ž‹†‚~{wutu~‡‰„~~ƒƒƒ‚zst€ŒŒŠ†‚~~~€†‹‰ƒ}tkdt„†{xu}ˆŽ‹…znlqu~ˆ‚sks{€‚„†ˆ““†xuy}…–އvmnz†ŠŒ„zv‚’‰€xpit€ŠŽ‘Ž‚wokfp{†™—†upqq{…Œ‰yy|€Œš¥‘~u~ˆ‘˜ vaflrx‡—Žvwyyurvˆ€thuˆ„€zskd\Ulƒ––—ru~‡‹…{wxx|€…Š„wu“—šŒ}rvz€ˆŒˆyi^s‡ˆ€ysmy‡’‰~„‰‡‚|~|yvvvz„~vnjfhu‚–  šŒ}x‰š”‹ydOe|ƒnZi„ –ƒwjm’› ¤’€ndY`}™—‡wtrtŽ—›Ÿ“kot{‡“•ˆ{obUexˆ…‚ƒ‹’–—˜Ž‚y~„Š’™”†yqkhx‰Ž~mn{ˆ€tjv‚‰†„‚€teYeq~Œš˜‰yy|~yttŽˆ€~~~ƒ†‰Œ‡ƒ~zvpkl…Ÿ¢ˆnjnsŒ–––Œs[cz’•—”~he}•–Š}n_Uh{†††~pcpˆztmlllx‡“†‚‚‚Š˜¦—‚nx‡†…„„„‹“™‹|ph`h€—‘‚sssttt|Œœ’~jklo{ˆ‹Š…~wxx{‡“•‹€|{z…‘™‹~xxx™•Ž}kj€–™’‹€sintzƒ‹ˆ€wz‚|vu|ƒ‡ˆˆ‰‰ˆ|pjot~‹˜˜–“kbqŠˆ~t|„Œ•”Œ„zquy}ƒ‡Šƒynz†Žˆƒ}zungmsz‰„p\^jv|€‚ypmpsy€‡zk`eipyƒˆŒpcjrx{~‚…‰tklns€‘–™Š|v‹Šurqry€ˆ’œ˜‡v{†Œ‰…}upony‡•އ€xppyˆŽ”‘Œ‹Š™£œ‚’¤°¤™…{}ƒ‰ŠŠ‰‰‰Š‹Œ‰…znhikr~ŠŽ’“Š{{z€ˆ‘Š‚ywuw‡…}tniesŒŽ‹†ƒ†ˆ‚{y…vjmsywvtojpކsg`js|…Žˆ~tvw{‰—š†„…†ˆŠŠ‡„€ysu|‚Š’—Š}zƒŒ†€zsmgadu†‚q`foxy{•~ga__m{‚~z{ƒ‚‚ƒ…ˆ˜¤Ÿ‹xw{ˆ‘•‰}slemy„’Ÿ¡aU]fnv}yuqomeVGN^nnmlkjp|ˆ}fPe}‹†|vrmipv}…Š…}£³©ž–“‘Ž‹•šž£¨¯µª‘x…™« •Š~qwŠš’Šˆ†„€}„’ Ÿ›—‡…•¥¤–‡„„„{{‡“•†ˆŒ„xr~‹’”•Š{mjim€’—Š|€Œ—‹}poms€Ž‡wgkqwz}}|{}~zwne_^\drscVetzm`^chd^Zckponrz~zwwwz…—šž—Ž†”œ¥®¢‚bnЦ£¡›ˆvu‡šœ˜”ˆ|suw{‚‰n]ivƒŒ””‰}|~€Ÿ¨wlv€œ«¢–Œˆ…‡’œ¥­´–rTlƒ•˜›™”€n_v˜‹~z~zqhgegow{{{o`QMIJZjqqqtwyyy{ƒ†‡ˆ™¢Šqbt…Š‚zwww}ƒ‰‰Š‡{sj`gnt{€vmgb^foutrv€‹Œ‹“•”“””•™ž£–‡}½Æ¢~u‰Ž’”‹ƒ~„‡‰Œ’˜€|Ž¡ ~ƒŽ˜eVfv~€‚„…Œ“”†xrssz‚‹““Œ…‡šž¡¤•‰„€~ƒŠ‘„wnx‚…}vnfsŒŠˆƒyonqsuwwvtqnkloqz…Іƒ‚{qfozƒ{suŒ¢Ÿ‡pmps|†Š†‚†™•އ‚}|€„„‚p]IazІvcPNRUr¤šƒufa`_jt~„Їykb\Um‡šŠzrw{xrlnoqx~zt|Œœ–ކ|svާ£‹snmo„™¢“ƒƒ—”‰‡…€refq}ƒ‰Œ~pjw„‹ŒŒn^hr|…–£˜‰yƒŒ“““‹†‡‰‹“šœŠynmlpuz{|~…ŒŽ‚scglsƒ“˜Ž„~zv}„‰…€ynchv„„‚‚Œ• £¢ž›™—•ŠŠ’››™¢¬´¨’ˆ~|€„†ˆˆvd[jxƒ‹“Š|oqsw€‰Œ‹‹„{rtvvrnic]ertibmwƒ‘Ÿ—…th\U]enw~zuwz|~zunf^chnrwtg[[ckjiimqttuspmszxqntyƒ’ š„xlk‚˜Ÿ™“‹‰‘•šŸ Ÿž¥­µ¥–‰‡…ˆŒ‘Žˆƒ€ƒ˜œ››Ÿ ˜‹– ¤Ÿ›—’ŽŒ‰Š““ˆƒ€}¤³œ…y|‡‘›Œ{lmory‚‚‚|yrjd`[alwxwuohca_hz“–—’Œ…{ppv||{zl^SRQV`i`QCKSZ\^\UOJFBO]fdccccfjmquwtprw|}}}„…|su…• £ š˜—™ž¤¤¡Ÿ˜‹”Ÿ•ŒŠ‹– ¨£ŸŸ¥¬ª¤ŸœœŸ£§«¯« –Œ‰’œ œ—”““އˆŽ“–™›››€psvwtrsw{tj___bq‚vkea^gqy{~}zwwyzod^o‰…~}umhs~†ˆŠƒynqv{{|~ƒˆ‰ˆˆ„€|sjflqx‡‚{tttyˆ˜š‡zl`wš~†ŽŽ‹Š‰‰‰ˆˆˆ›¥“‚xˆ™žš•–—˜‰„Š„{{‚zrmpttqou~‡…‚~ƒ}tlnpqqqpppsw{‡‹ˆ……‹Š…—Ÿ”Š€wnigft…”oa]Z]elf]U[bedbdhlz‹“Šyqr}‡ˆ†„‚€~„‘ž™‹~ˆ‘–‹wsosy€‡Ž’ˆ€xxz|‘©¹ ‡tnhjot{ƒ‰‚zy€‡’¡° Šx~„‹•Ÿ£££“€ort{‹šžš–’މuoqsy…‘‰|odYUds|ƒ{rhiihgeb]W]gqlhc^YX[^\YVbnvlbakt|‚‰}pflqy…•–—‰‚‚}z™£®µ¢‡˜ž¤©¤Ÿ™‘Š„~ƒžª •ŠˆŽ›¨¦¢žœœœ—‚‚ƒ‰Ž”™ž‘rTYk|vphWGGZmmf`pŠyhgwˆ˜¦µ¥’†”¢¨£Ÿ–Œ‚€{qffjnwˆ{od^WWZ]afha[[gswwwy{}…Ž–¤ ”ˆ|x†” ¥ªž„jqІxwz}~€vmfffedclwƒ†ˆ‰„€{wrx€‰’š|{‹œ¢¤¥”ƒu{€‡‘š‘nhcadgo|‰Š„}ƒŠ‘’”–œ¡Ÿ˜’“”–› ¡œ˜©´°©¢˜“‡„ƒƒŠ“šŽ‚ywu|‰–ƒwursx~ƒˆŒ‹Š‰uaVgxƒ‡Š}jWZ]aipqmhnx‚{smifjwƒ†……~ws}‡ŒŒŒq`t‹œŒ{mbX_pvhZVQS^iptxpg``afv†Ž“‰~u‰¨¤ š•“––––––’‹ƒ|y}ypotyyxw|€„„…„‚€‡™‘‰‚€„Šˆzxuy„‘Ž“˜œš˜›Ÿ£žš——˜“‡z{ƒŠˆ…‚‚‚~|xrmu}„„ƒ…Œ’’Ž‹‚vmquy|~|xsj^Tbpywupf\UOJT^fikjhefghpw}}}€‡Ž‰€xŠˆ€ƒ†xoy„‹‹Š†|sruxz}†ŒŒ’•˜š£ª¨›’Ÿ¬ª¥ ™‘‹†‚‰˜§¦£ ™’‰{lqƒ–“Œ…~vpliq€‰}qkdabcgnvurp`PHYik`VMDDJNRV\bgjnmhdjt‚€p_Zbkh`Xblsollnqqqqstw€Š‘’”’‘”¥¶¹¤Ž‡ˆŠ˜©¸µ²¯®­°¶»´«£©¯·ÃÏÎĺª™‰—¦¯«¦—fkzˆ‰‰‡‚|~…ŒŒ‹’šžœ›—І„‚}ztmkmnqtwfTFMS^pƒ…|†—Œžž–Ž‘‘ދЋhPWbmy…ˆxhdfiov{hVKNRaz“{X6=ERl‡‡th]`cgkprrrpmk‚™§–…†Œ†~u}†‹†~~~‚†‹ µÃ°—¡¬ºÉÙÍÀ²Ÿ„‡‰‘š¤˜‰{pe`ejkkks{ƒƒƒ€zttwzƒŒ”Š€|‚‡ŠŠŠwnoqrrrlcYVUUboy{}{vrv|ˆ”•—‘„x|…‰††•–’”œ¤¨¬«¡–•Ÿ¨¥”‡xnnoqvzqcT^itvy}ƒ‰‡€z|~™œ“‰ª²¹¼ª˜‰ƒ|…˜«ž‹xsokhekv‚}un{‰Œˆ€uit„’~j^ciq}‰sS4:@Kh…†jMLSZixjUGB841241)"#*18>C8-)378:::9;=?FNTQNP\hmmmopqvz{vpmmmnnnid_[WTSRX_ga[Ziw…‰“’’‘Ž’¨¯´º´¯«­®±´¸·¶´«¡šŸ£¤Ÿš–“‘’’‘Š‚|wsmf_dlqlfdegksz…œ¤¬±±±´º¿¾½½½¾¿ÃÆ¿°¡ £¥«°±¤–“˜›—“›¢¦œ’Ž‘“”“’“—šŸ¥«¤˜Ž‰‰‰‰…~xod^itvkaVK@6,$$$"  $0;5.,28=?BIQYaiptx~„‹Šˆ†ƒ€‚ž¤¢ š’Šœ®½ÂÆÌÔÜÞÞÞáãæðùûóìíñôøüýõìèéêéééèèåͶ¦¦¥®½Ë½¬›”‡ƒztnquwsopx€„……}tmw†}xrmkjjklmmmnprmgbUG<61036788657;@@<82+$,5@Zt€}zxus{ƒŒ™§ª£›¢®ººº»ÀÅĺ±¯¯¯³·¹¸¶°¢“• «„ˆ‰†‚xiY[_cfjjd_YTNU^hr}zst|„}tlt}„†ˆ‹Ž‘Ž‹ˆ„€~~~xmb`abktyuqnmlnop}‹•Љ‹ŽŠ†ƒ…†††‰•–”“ŽŠ…‚zuoljifcbjrutsuwy~ƒ†…ƒƒ…‡ˆ‰‰Ž“™£­±ª¢œ—’•šš—”ŒŒˆ‚}„ŒŒˆƒ~y|€„–›’ŠˆŠŒŽ‘©°«¥¦¬³·¹ºÀÆÈÀ¸²­©ª­¯°²±«¦ž’†|xuso`RF?878899::;<<<@FLE>7534:?;1&+18DQ]bbb`][WSS^ih\PYhwŠ•›¢«³µ·¶±«­¸ÂËÒÚÝßàÜÙÚßåëóúêØÈ½±¬®¯±´·±«¤›’ŽŽ”›¡Ÿœœœš—”’’’“”“‹–  š”‹ˆŽ•˜•’Œ„|vqmrwwoga[Uarƒyoiloomllllzˆ‘ˆ„~‚‡‹ŠŠŒ—¡¡—ˆ†…Š’”˜”†ƒ€‚…‚xnotz|~o_URPRUYRJEJOPMJLQVL@52..274-&"!##"+28<8437;>AEUk€Œ˜žš–•–—¢°¾ÆÍÔÙÞßÞÞãéïíëëëëå×ÊÅÄÄÉÏÐÀ¯ ‘ƒ‚‡™¥¯«¦ž€|||‰˜¤ ›› ¥¤ žžœ„mdu†ˆypg^XQOTXVQKD>7537FVXOG<1(()(((1AQY^b^Z[jy‚„†Š“Ž›§©¢šœ¢§¦¦§§§£œ”•™œ“Šƒ‡‹‰uyƒŒ‡~ˆ’”Œ„|un’¢¢¢ž“ˆ………}{}|qfgpxodYWTQMIMV`^ZVSOOTYZXVcs‚€Œ–Ÿ¥¬³»ÃÇÊȸ¨¥®·¸··»¿¿·®¨¥¢¥ª®«©¥›‘Іƒ„‡Š…|€ƒ„ƒƒxhXSQRct{uoic\]]\VPOSWN>-5AMRVWQLIGFMV^_aaaak}—¢°½Äº°³ÂÑÐÌÈÌÐÕàìïìéâÙÑÍÊÉÊËȼ´ª¡¬·¿½¼¸²¬©§¦©¬­¨£ ›ššš›œ¤ª¨œ‘Œ‹Š†‚}rg_^\WPIC>8+  -CHNPRRPNMLKJIJT^b[URRR[fqrsuy}vhZdt„yniqy~€ƒ~†Ž“’‘–ž§¨§¦“›¨µÃÒÂ¦Š›¯ÀÄÈż²±´¶ÀÊÒÎÉÈËÎÎÎÎÉÄ¿·¯­±µ±©¡š”ŽŒ‰ƒ}wrlpty|‚…ˆ‡ƒ€€€yrpw~€~}xrmptw{|tlqx~€{vw{€}xtrqnjefkptwzsljwƒ‡€zz}€‚ƒ…„ƒ‚~ƒˆ‹ˆ…€xpljhiih`XQMIIIIFBAHOOD9;DNNNMMLJC789:K\eTC>FMNMMTZ^XSTY_\WRVY]adiouxxx{}~ytvˆ“œ¦­¦ ž©»ÍËÇÅÎ×ÚÖÑÆµ¥—’’’”˜”„sw~„„„…†ˆƒ{ruy|tkc\VW]c`[W`jng`YQJVh{tle^WW\bYL?ReqeXTY_chlmmnnnpru‚–ª³»¿±¤¢¯½ÆËÑËÄÀÂĺ³¨œ’•ž¦§ž”—¢­­«©¤Ÿ™‡‡‹‘““‡zstuy…„‚{ww|‚…‡‰vlorrrqngaiv‚xof^WW`hheciouz€…ŠŽŠ‡”˜•‘’˜œ™—“Œˆƒ|qfejosxygUIIHKPUPKGMSRC45@KRY_fmpnlsŒˆzzzxtoqx€€€†‹‘š£¢š’”šŸžžŸ ¤­µ¹¼¾ÉÔÜÛÚÞåíæÚÍÔÚÞØÒÍÉÆÁ»¶®¦œ‹zoooqsuwyyupoqtnd[ainf_]cjkjibZT`ksssoicTB22248BKT[cf\QKKKJJJRZ`]Y[`f`WN[iwz}}xrkc[^ce`ZY\`^XSX]``_aglsz‚…††…„yqv„‘›£©©©¬µ¾ÄÇËÉÇÅ»²ª¦£ ž› ¦« –‘¨³»ÄÈËÍÑÕ×××Ñö¶º¿µª š““š¡“ŠŠŠ‹’˜˜“Žˆ‚|‡‰€wrrrrrrssqeXMF?AGNQSTQMMSYWRMS\env}„€yqtz€~zvw}ƒˆŒ–›ŸŸŸ¤®¸¶²®©¥¡ Ÿš†Š”ž”Š„„…€vllptuusjbVF57AKKIG?76>>?@@><:874,#!%)-148<>83146=HSLC=CIPX`hpwvtrrrv€Š‘–› ¥©¤ŸŸ¨²°©¡¤¨¬­¯®©¤¦®µ²®¬¹ÅË﻽¿º´¯±²´¶¸¸¸¸²ª£ž™•”“‘ދޑ”Žˆƒƒ‚€~{wqlaWQ]joliaVKQX_fmswz~ƒ‡‹Ž“œ¥©©©¬°´´´µ¸»¼º¸´­§©­±»Äƹ­£œ•š¡¦œ’‰€wrpnljhhhggfc^YVTSZ`eef]L:=FNRUYblnjfa\X]beedfjng]RPNOU\^]\WQKWeoidepzƒyogmty„sgjmqv{‰‘‘‰•£¯­«¬°´µµµµµ´¨–—˜–”‘‹Š‰ˆ‡†‡‰‹ˆ…ƒƒƒ|vx€‡Œ’”•——˜™›œŸ¡¤®¸ÁÂÄÉÕáÝÔËÌÍÌÊÉø­¥Ÿ™‹|qtwupjjmpkfckrx|€ƒ†‰†„€}yurpmiebegcR@BScVB/.-+*)-4;;::=AEMTUROV_gc`_dhihgfeea^_itxwwrkeimqv|„—–Š–ª·ÀÀÀÃÆÊÌÍÏÖÝÚʺ¯§Ÿ£§ª¥¡›”–œ’…xwurlg`YRPONNMNNOPPPUZ`lx~‚‰‘›¦°©£ ¡£¤¥¥¡œ˜–”’ŽŠ„}voha^\YQJHKNOOORTXerwtqpnmpstpllptz€‡~uo~Œ“‘ŽŒ‹‹†€}€zu’¥£ž›››ž¦®¹ÆÔÏÇÁÉÒÓÆ¹³±¯¬©§§¨§£ ›•ŽŠ†‚Žšž‘ƒ{ywz}‚„†‡‰‡„„ˆ‹’™˜””˜œ—Ž…‚~znc\[ZO@0(! (1:<<=GQY^bipwyzzrjhou‘  ž›•“š›šš¡©±²³·¿ÇÉÇÄËÔÝÛÚÜâèëëëêééîòòãÕÑÕÚÒŸ½Âļ³±´·¨‘zyz|„ŒŒ„{uqlfa]cjorvzƒzphmrtqorw|pbTPKKQVWVUPKF@9678;?DKS\_bccbfkqtvy‡•œ”‹…}uj`ejkc[QD81,'*,.0147:CMXRLJVaku~ˆ“ž£©®±µ·¹º¾ÂǾ¼ÅÏÑÊü´­°µ·®¤ž›•Œƒ|z€†‹’•˜ ©°°¯®¬ª°»ÇÊÊÉü·µ³¯ª¦Ÿ˜‘Ž‹„~xrmhd`bcbYPIE@ADFKOT\dhhhjmov}‚|xrlheb]XTTTW]cfghjkmnouƒ’–”“•—™¢«µÁÎÔÕÖÒÍÊØåëãÛÔÍÇÇÈÇ¿·°ª¥œ‚ƒ‡‰~sjfc[NB>==:79AJKE?HTa`_`dhknpooonnmifeffeeeZOHQ[abbbbb^[Zgt}ˆ“ ¡£¤¦ªµÀÆÈÊÍÏÐÉÁ»¸´¯©££¤¤›’‹ˆ…‚~zwtqdWQX_^VNPSV]ekkljfbgnti_WWW[dlh`Yaipsuxz}‚‡‡}~ƒ†‹‘˜ˆƒ‹“˜˜˜™›œ¨´¾¼»¹·µ´´´¯©¤Ÿ›•…‡Ž•Š„~xssrlbXUSR[dkorqmjjjkmpog`[XUZ`fhkkd^XTPTZ`ceecabcdn|Šƒ|z…–™›Ÿ¡¦«­¤›˜œŸž›™””‘‰}zxphcfihc^`gnjgc[TS\eknrvz}wqotx|~‚‚‚‚‚€}{y}„}vohbdnwm^OQRU]fgc_jz‰‘˜Ÿ©²´²°µ¼ÃÀ½¼Àĸ¯«©¨«­­¬ª§ ™ž§±°¯®¬ªª¬­±¶¼·³®«¨¥¥¤£¡ ¦­²§œ•“‘Œ„}xtoh`XNC9.$! !%).4983/7BKGBDScf`Zet‚ƒ„‚}wyˆpacegikhaZ\bgdbbeiifdfikihfc`dny‚†”šž£¨®´¸»½ÀÃÄÃÂÄÊÏÍȺ²ª¨¥¡™‘ŽŽ”𛓋Œ‘—¢§§§¦¥¤§¬°¯¬©©©§ š•“ˆvoic_[RF9=ENE<8>DEB?;96;?A=952/4?82258;>?=:>JWTH=>??<879<=>>BEIMRW_glnpppquy{{{|||}~~~~‰‘’‰—ž ¡¢¢¢¥ª¯¬¨¤¡Ÿ §®´»Á¼´¬·ÂÌÏÓÔÔÔÓÒÑÐÐÏÉÄÃÈÍÍËÊû·ÀÊÍÊÇÁº²´¶µªŸ˜•“•šŸ›—“’ŽŒŠˆ‡…yl___]ZVQJC=627=>:631/*$+8@?>9/&+3;<=;4.,,,/36,"")0+&$/9<96AQb_ZWWWZagnu|~ˆŽ•œ£§©«´¾ÈÌÑÔÔÕÒÎÉÍÒÕÔÓÐÊÃÀ¿¿·­¦³ÀÈÅþ·±ª¢£ª¬¦ š•ŒŠ‡‡†‚sd_adjqxŠŽ‰„ytx†††‡ŠŽˆ{npw€‚‚ƒ„†‡ŠŽ‘ދД•’’•—’Œ‡…„‚‚…ˆƒ~{‡ŒŽ‘Ž‹‡‰‹Ž¢¶½¬›“‘ŽŒ‰…€|{yungkqw~†ˆyvvvphbdggggd^Y[^`ZUT]fkkke]VTSRQPOMLF?7545@JSZaa_^iu€†Œ‘•˜œ ¤¨«­­¬«¨¥¦§§¤¡ ¤©¬­¯ª¢›ž¢§¨©§¤¡¡¡¡™ˆ‹Ž‹ˆ„€~}}‚…‡‰‡ƒˆ“•Žˆ„€}{yxwvtssw{~€‚‚‚†ŠŽ’‘Ž‹•›˜•‘†{x}‚{vohba_`cfdb`^[[]^`be`XQ`s‚|{}€‡’œš’Šˆ•›ž¢™„ˆŒŽŒŠŽ“™ššššš˜’ŒŒ’މ„~yw{€€|xutsx}~yssvzvpkostqmkjje_XVUV_gjfcejnt{…‰Ž•œ £¥Ÿ˜’‘ŽŒ‹‡„}rhjs|€€~|zyx|ƒ‰ŒŽ‘’””“‘’““Š…|sntzztns{ƒ‡‹‹‚z†š­¨¤£©°´µ¶¹¼¿¼º»ÃÌÎÌÉü´³²±«¦§°¹´ªŸ¤ª®¨¢œ–‰ƒ}yus{‚‚xnmprmhccbceh`REN[f`ZSLEDHLKKJHFEEEC?;;;<<=<<;96210/37:;=>@ACEFFFGGHLU^aaagmsstuvw}…’’ˆ~¡£œ–™œŸ§®±¯­²¹À¿½¾¿ÁÃÅÇÆÆÆÄÃÂÂÂÁ¾»»¼¼½¾½»¹¹º»µª ›˜—œ¡¡™‘‹†‚~}||{ywvuu{‚‰‡†„zslov}€ƒ„ztmeehjd^ZZZXURW_gc^ZUPI@8:AIPV[[ZXTPRVZVQMKHJRYdr‚ƒ…†ˆ‰‰ŠŒ’𤬥ž—‰‡‰Š‰‰Š–¢§šŒŒ–¡ œ™¡¡›–•™œ™—ˆ„‰‘‘‘ˆ|psuy„“‡„ƒ‚€†‹”—–•“œ¥ª£›”ŽˆŠ”–™›œ˜Œ€ˆ“””†ƒ†ˆ…~wwxzˆ‰urrrstssrrrrnica`_^][YWXYYVROLJKOTZahhec`^]bflsz{zy€†Œ””‹ŒŽ“•˜¢¨²»¿¿¿·¯ª¶ÂËÎÒÑÏÍÉÆÄÊÏÏÇÀ¼»»ÀÆÊÁ¸µº¿¹­ œš—‘Œ„zohb]UMDA>=@BA?=6.((()-11-)/7?FLQQQQQQLGAGLQRTSRRPMJPVZUQSZbcbabcdimpsux{~|{|Š—¡¥ª±ºÃÅÅĺ°®¸ÁÀ·¯­¬«©§§ª­±´¸³¬¦¦¥¦§©§£ ª¶ÁÀ¿ÀÇÍÒÔ×ÛßâÞÚ×ÔÒÌÄ»¸¸¸¹º¸±© •Љ‹Œ‘–™“Ž•›”‰~zwslebdfjoth[RRSUXZ\]]ZWTNHCA>;863101249>???EMRPNKGCGOX\^adghhhgeca_^`bb_][ZYds€€ƒ†Œ•ž¥«°©£™•‰‚ƒ…ˆ‰‰‹–š››ž£§¨©§ž•’–š ¨°¨Ÿ—”‘Œ„}ywu}…Šus‹‰€w}„‰ˆ††‡ˆˆˆˆ„€{upjd^_diovzuop{‡–œ•‹‚ˆŽ’’’Œ€tonmprrrqnjflvƒ‡ŠŒŽŠˆ‹Ž‘ŽŒ‰„|zywusvyzzzwpip~‹ŒŒŒ‹‹ŠŽ”›“Š‚‚„Š‘‘‘”——˜–”‘ŽŒ‹•Ÿ ‘‚zxvx{|qf^\ZXVUROMORUY]]ZVMB7HYd^WTTTTTTX\`jtwtqvˆ‹ŽŒŠ‡…†ˆ‰Œ“ ­¯¤™™Ÿ¥§©©©¨¬¶ÁÂÁ¿¾½¼µ®¬±¶¶µ³°®«§¢¢¥¨ª««¦¡›„~ƒ‡„|spomf_YYYVRNRX]^^_acfiloruy}}wqqw}…‰ŠŠˆƒ}|‚~xrpoptxxsooqrjb^kx|vqjbZhx‡ˆ‰†~wyˆŽ’••”–šŸœ–‘𥮍¢œ”‹Œ‘–“މ€vt~‰Š‡ƒ}zx{‚Љ†„~}…„€|yuruwy}~shb^Z]_^SHHR[_``^[[^behjnrvvvusrtz€ysowyqprtrqqqrtwz„“¢«´º´®©¨¦©­±®«¨¦¤¡™˜šœš˜˜ž¤§¥£¤§«©§¥£¡¡¢£¡ž›œžœž¤©®±´³²±ª¢ž¤©¨ ˜“Œ‡‚~{wx}|sjfa_cffc``bcfjmu}€{vssslc]`cc_[ULDCCB@>>>>@CFIMQRSOD9;GSZahhhikmptx}ƒˆ†…ƒ‚€„‹’–™œ”‹„„ƒ„……ƒ€}„‹“•“˜£®´¸»µ°­­­¯°²³µ´³±²²²¯ª¦¡šŸ¤¥¡œŸ¤ª¡˜Ž‰…€}yyyy|€‚‚€}zyyy}‚…„ƒ}yy{}zvsmhb\VW^efffhikosw~„‡ŠŒˆ„ƒ„…‚}xodYblrpomjhmt{‚„ƒƒˆ“•‘ŒŠŒŒ‡‚|z}€{utz}zvrptx{~~wogd`_cfhiijkjfbacejpwyzz}€xrpqqnjfkpqh^[^bfkpuy}~€ƒ…‡Š‘–˜”‘ŽŒ‰†ƒ{y~ƒ…„„}y~‚…~yslow~}xtx‹‡‚~†”›¡¡™ž¤ª¯´¶µ´·»¿º´¯¯°®¦ŸŸ£§­³¹±ª¦¨ª¨¤¡›–—ž¢Ÿž¢¥¤¡Ÿ–ˆŽ•–’Ž‘“Œ…~xqlifa\VZ]aaa`_][ZXUSRY`fhkhc^\[[\^\YUW\b]WQNJJNRW\b_YVVVYcnojfcaafkmidfnvvsqsuwwwxyyvrnnnq|†Š…}yvwxy{~}zwwwwƒš Ÿœ™¤«­°°¬§¤¤£¢ Ÿ›™‘‰ˆ’›™–•”•–—™¢¡ ž ¢£ œŸž ¤¦¦¦¢—ŒŠ”“’‘ƒvnrvz|~ƒ‰Ž†~{„Œ‹Ž•š›š› š—Ÿ¨«Ÿ“‹ˆ†Š”ŽˆvkaYQT]ekpuvwxxxz}ƒƒ„yrmiedb`]YVTRUY[WSPPPONMIE@<7568=EMMKIMQU^fmqv{†……‡Œ’”””’…{v}„ˆˆˆŠœ¨±¬§¤¤¤®¾ÍÏÏͶ¯¬ª§£Ÿ£¦¨Ÿ—“”•—šœ˜”•¤¡—Œ”Ÿ¨¡š——˜šœŸ¥­´µ·¶°©¬´¼¼¼»±§¡¢¤Ÿ•‹†‚~‚††€zuspruwyzyphcbbdefhiiiibRC?@AIQWQLF?830,+*+,-+(%*35-(''/8ABDC=7444:BIPV]gq{„Ž’‘Œ‡‰’𠥩 ˜” ¬µ¼Â¿¹³´¶··¸¶´±³µ·ÁËÑǾº½À¿¼º¿ÅÆ´¢˜›˜Ž„‚€€€€‚|siaXRZbilpnhcir{ƒ‡‹Ž‘•˜“ŽŒŽ“•—–––‰|tx{{zyupkqwytnib\`hph_XTPOQSSSSRQRUXYYY[^ajs||}|{z€‰’މ„}wuwz}€‚ƒƒ‚€„†ˆ‰‰„zupsƒ”š™™›œœš—”“’—¡ª­­¬«©ª¯´²¬¥¡š˜—–’Ž‹‡„~wpsuurnpuzo^NSX[ZX[agd\UX\`gnu|ƒ„„„†‰ˆ€xrpmid^gqywuw}ƒ†‡‡›£Ÿ›šššŸ¦­«§¥¥¦ª´¿ÄÅÆÈÊËÊÈÊÑÙØÒËÇÃÀ¼¸µ±­©¤ ¢¥§¤¡—‘”—•‘‡~~|uos|…~wqpoquxxxxnd\\\YSNMMMA5+3:=<:=BGFED?940+,036:<;:=CJJIGJNPMKJKLHA:=CFDAABCFKPW_fkoqomoty„’Ÿ¤©«ª¨®»ÈÏÓ×ÚÜÜÜÜÙÓÍÉÆÄÎØáâäáÜÖÓÐÎÍËɼ¯¨¨¨£œ”އ{wx{~~xrpuyti^]]\[ZZZZXVSVX[bioru{„‰‚|}~€„ˆ‰ˆ‡ˆ‰Š‰‰†~upppuz€{vqnjgc`bfimqtuvurppppjc_cgiiid]V[afffc]W^lz‚Š’“•‘‡}€ˆ‘™ ¥¢ŸŸ ¡¢£¤¤¤¥¨ªª¦¡Ÿœž £¤¥¤Ÿ›–’Ž”›¡˜“Žˆ‡ˆ‰‚yptxzzzwpjlorstuwxp\IFJNRV[agf^UVY\ckppponnmkjmqtwz|}‚…‰’œ¥¨««©¦§©ª¨¦£££ ™’•ž§£œ˜˜˜›¡¨§ š—”‘Šƒ|xtqppnmlptutrz‰˜™—•…ƒ…‰Ž”™ž¢¦ª­­®¯±²­§¡›•‰ƒ~~}{zxvvvwtldcefjoqjdadfaXOQTUSPKA8:CMQTVNE?>=?ADHLQRSTTUVVVUTTTTUWY]aehjksz€‚„‡Š‘’•˜™˜–—˜˜–•”’’””’‘’”•‘‹ŒŽ‹‰†ƒ€€€~|{xutsrtuvvvtroligikmmnnnnmlloruy}€„‡‰‹ŒŽ‘“–›¡¤¤¤¥¦¨©«­±µ³­§¨«­©¥¢Ÿš—”•••“‘‘’”–›Ÿ¤ª¯°°±³´´³³µ·¸¶µ³°¬ª¨§¨©©ªª««¬ª¥Ÿ›–’ˆƒ~|{zxvtqnkhdbbb_[WZ]`cefffghhfdcccbba[RHHJJGCBCDEGHKNQUY]bffc`___^]\XTSSSRQPSVY\`bcdeffc`^^^_bdfhjoty…ŠŒ“˜¢¨«ª¨§§§¨©©«¬¬«©ª­°³´¶µ´µ¶·¹½ÀÀ¾¼»º¸´¯­­­§ž”–› £¥¨­³¹¿ÅËÑ×ÙÛÛÙ×ÕÕÕÌÀ´¯ª¥”ŽŽ‘’’“™ž ŸŸš˜”Œ…~wpieb_XRMOQQQPNMKMNPQRPMJF@;8535873/0479;<;9:@FGEDCBBCDEILQX_cgjpuzzzxurnidba_\XY\_behqyƒ…ˆ‘“””‰‡†‡‰ŒŠˆ†ˆ‰‹’˜Ÿ¦¬²¸¾ÁÄÇÈÉÈÈÇý¶±¬§ ˜‘‰‚|xtwz}ƒˆ–œ ¢¤§©¬²·¹¶²°®¬««ª§££§¬°²µºÀÆÆÆÅÅÄÀ¹²ª¢™“މ„ztmkjjoswz~€ƒ…†‡‡…„‚}ytoje`ZWTQKFB@=<<<=?@BCDDDCBBA@ACEEEEHMROLKMPRSUPIA?><843:AHNT_lwk^XblniepŽœ«¶·¸º½Á³ Œˆ„€|y~Žž¥¨«©¨¨©«­²¶«šˆŒ‘–¤¥ ››œ›šš¡¨«ª¨¥¢ž™•’œ¥­³¸´«¡žœ™“ƒq^QH@ELSTUZfsyzztmfb^VC1#$-=M\jwƒ—‘†{tmf\SVdrsolu…ƒ‚ƒ’§½ÂÅŹ­«·ÃÉËÍÏÐÒÙàà×ÏÎÐÒÍÈÅÉÎÍŽ³©Ÿš•ok~‘“†wgXVSSVY^ekx‡“ˆ}vvvtrolignvzwty„ˆ|pppooohYJB<7-$%+/01/-,038DPTPMS]g`YSOKGDA???IS\bgloqnicmy„”¤²¼ÆÃ»²´¶·¬¡™—”™ ¨¶ÅÔàìñéàÞßßààßßÞÙ˼¼ÅÏÍÈÄÏÚáÞÜÚÙÙÑÆ¼·²±ºÂÇÉËÇÿ¹²­«©«¯³¹ÀǺ­¢¡Ÿš‘‡Œ˜£Ÿ™’‚rf`ZM;*1:@:34=FVghebjqtmecden{ˆƒ}~~|z~„‰’œ¤ª¯±°¯µ¾ÇÁ¼µ­¥ž›™ž¨±¯­ª¦¢¤¬µ³¬¥©¯³¨“‹„|y…ŒŒŒŒ‹Šˆ†††‡‹‘ŽŠ‚{zzyqiejpsuvwxxsokigipv{ƒ~ysj`VLC<72:AIT_ju€{qfgijjjkllnprpmnxƒŒ”œœš˜–“‘ˆ€~„Š“—•”””•„ww~†Š‘–›Ÿ ¢ šž¢§§§¢’‚zyyuqnnnpx€}y|‚{tnkiaRCEMT[aglquwzyxwk_VWX\cjjhfimmcYUUUTSSTVW]bkzŠ– ªª©ª¬¯­¤›“Œ…‹“›¦±»ÄÍÔÛâåççâÝÛßâàÜØÌ¼¯·ÀÇËÏÒÕØÒËĸ¬¢—˜ž£«µ¾¹µ±±°²´¶³¯¬¹ÅÍȶ£‹‹‹…€}‚ˆ‰‡†|n`YRLKIJMPMJG>3,,,& #(,5@KLLMU^eimlielt{ywx|€„‰Ž’–™”Œ‰†‡‹‘’ŽŠ†„‚|x{~‰’™¡¨²¼ÁÃľ¸¶ÂÎØÝâßÛÖÕÔÓËÄÂÈÍÉÁº»½½·°ª¢›šœž ¡£¥§§¤¡›’Š…‚††|{|}xrmmmoswy{|zxuohefghjkigfhjib\WTPXcmrv{‚ŠŠ…xqis~…‚{wrkbYaiqtxwurvzzupibagmnnnv‡‘𢩰¶¼ÂÀ½¹®¤œš™¡ª³´¶¶²¯«¥ –‹€xphb\XVSVZ\[Z[agihgb\VY[[[Z^dkhb][ZWPIECA:1($ &,3:@Obupjfgie]UW_gv‡––—•’‹ˆ„‰’›¤§¢—‡‹‘••”˜£¯­¤›˜–•••˜ž¥µÍåèçåäâßÛ×ÒÍÈÊÎÑÓÔÓÎÈËÓÜÛØÖÚÞÝÑÆµŸ‰|tkhefq|€|xwwwy{{upkgc_ZVNE=968BKSY`gnrbRIJKF?8;>@?=:4/./0+&"&*-028AJJIJPUZ[\[ZZ[[\^````acdjryrllz‡Œˆ„€|z}€}z}‚†Š‹…†‹Š’›¡š˜˜˜—––›Ÿ¢ž›–‹ŠŠŠ”Ÿ«¯©£§°¹±¦œš—˜›žžœ›ž¡¢Ÿ›ž¬ºÃÉÎÒÖØÓÍǾ¶«Ÿ’•›¡¢£¥¬²¶··¶µµ·¹¶§˜Š~n^dinqsssstuuoiefhikmoqsmgceffffkqxusrx}~{xz}€‚„ƒug\TLD=643346:DOUWYairtwwtrnjf`YTTTV[`hq{~€…Š‹†~|zrg]`bejotz€Œœ«£›”’‘‡…Œ“›£ª¬®®¬ª«¬¬­¯°³··¶¶±«¤¬µ»¸µ·ÁËÇ»°¨¡š’‹‡ŠŒ•¡¬ª¥ Ÿžœ˜“Œˆƒ~ytnh^UWblpsvƒ——–‘‰~}|tlkzˆ‰…~{wtqmiea]_cgjlnopsx}zvqstr`OC?<83/8AKRY_ejnsxuqnkhfecglqommw‹•ž¥«°®¬©¨¦¤Ÿš—•”™Ÿ£££¥©­°´¸´®©¢›——˜”Žˆ…‚€‚ƒxnkmokgcfilmnpruvvvutux|{xuqlhov}‚‡‹Ž’—œ“‰‚…ˆ‡‚~zupmif_XW]dhjlt}„„ƒvmihhlqv{ƒ…ˆ„yyz{‡’™–“”–™ƒy‚Œ”—™ž¤«ª¨§¥¤¢žšœ¢©±ºÃÁÀÀÀÀ½·±³·º²ª£ž˜ƒwrqpty{{z|‚€|xrlfdabgmoqrtwyz|}~€|wrdUFA=9759@FD@<840*%  %*,.7BNOPQTVWWW^gpu{€„‰ŒŒŒŠˆ†ƒ€}|z~„‹Ž‘˜ ¤¢¡£¨­°³µ´³²®ª¬¶¿ÄÆÈÍÑÔÑÎÈÀ¸µµµ°ª¦­µ¶°©¡™‹‡…ˆ‹‘œ§©§¤œ“І‚„†‰‘™¢©£œšž¢¡Ÿœž¡£Ÿ›—“Šƒ|}€„ˆ‰†ƒ€}zqdWSPPW^dhlf]SX\]SIIR\cinf]WXYUMEHOW[`dege_Z\cju‹Š‰ˆˆˆ‰ŠŠƒzrqoptxvqlpuyupkgc`]Z`glaVOSV^jv†”›¡¥©«««¨¥£§ª«¨¦¬¹ÆÇŶªŸžŸ¢¥£ ž ¡ œ˜¥­§ œ£ªª —•—˜—–—¤¦¤¢›…yuy}€€€‚‚„………„†Œ’ˆƒ‡‰{mb`^cmwŠ”£²¾¾¿º²ª©©©©©«²¹»¹·²¬¦£ ›‘†{pdbcd[SMNORW]]\[RIA?<>CIHECEFHLPU[b\OBBB@5+'-331/6>FFFHKOKD=Marh^VVUY_ec`]VNKOS^n~“ªÀµ©ž•Œ–Ÿ¤§©£ž±ÃÈÀ·ÀÎÝÖÏÍØäèäàäëòèÝÒ²¯»Ç÷«¸ÆÐǽ·¶¶±ª¢œ–“ž©´¼Ä½¬œ£¬³ª¡˜Ž…‘ªÄþ¸©š•£°«™†Š‘—ƒysld[QZeqy‚„via_\epznbVK@>BFMU\I7(((/9)  +38=822=HQX_\UORTV[`ejoonmtz€…‹‰vqonmmnpqw‚’”•Š„‚„ƒƒƒˆŽ”¦·¼¬œ———Ÿ§®­«©£–‡{m`VLEDCHOWPE=DJRZbm{ˆ{fRZbfc`kƒ›”‚qg]TLE@??Rk…Œ’—™›™’Œ‰‡†€zw|©ÂÔâïÖ¹ŸŸžœ–‘•›¢¨­³·»²“tnv~€‚… »Çµ¤žŸŸ”‡{pde}–¢¤§ºÒééêåÕŹ±¨­´¼ÄÌÔØÜϵ›œ¥®—rx}‚†‰•›•ެ·¾ÅÄÀ½¨’~wof\QIA:AHJ9( '/?PN0 # (32036:BJQG<>VnuqmjfaM9-.0=Tkw‰~sh^TQQQSVWSOQ^k{ ¢Ÿª·ÂÄÆÅÄÄÈÎÓÕ×Ó¾©•ƒqbUGLQUZ_l„œœ…†ˆŽ©ÄÉ®’uiwˆ˜¡ª°°°ª —¤µÂ»©–™¨¸ÄÐÙ×ÕÏö­¨£œ•sYOh‚Ž‘‰wwx}Œ›Ÿ™“˜Ÿ¥¥¥¨³½»­Ÿ™•’€n_VMGECBBBVl}‚†Š“‰ƒ†ˆ‡xhcjpux{vpkigjt~€cD'   )5AD7**18886$ &.02DZp}‰”™š’‰™ •‰‚…ˆ€p`mƒ™¦²·«ž™›œ•…}vrvz}…Œ“›š™œ¨´¸µ²µ¹½ÂÇÍÔÚÙÍÁµªŸ˜“Ÿ®»ÆÑÞëùüþþþþüøóóõöóðïïïîîíâϼ½ÁÄ´¤™˜–‘Š‚€fM<<=BKTUTU`jlXC864*#0JdgS?>CHPWaq‚ƒvi_XQW]_RD7++AWUSPPPS[ba^Z_dgeb\RGCCCKS\ky~tjtŠ Ÿš•”’•›¢¨®´±¬©²¼À¼·µ³²»ÅÏÏÏÌú´±®¡‘‚Ÿ§£Ÿ ¤¨¢˜ˆ‚{qfZL>=AELSVPIJQYZYYkˆ‚„Œ•‡pYet~wph`XY]ao}‹‘–tYKF@HQZk|uin}˜¢ªž’ƒp\Zclnopu{Œ–”‰~si`ju€Œ˜œ››œ›™—–”®ÀÈÍÒßìð×½¶ÀËÖàêíïðìéâØÎÁ³¥ž˜’Š‚‚Š“‚fIKNOA30=IT^huƒŒshaYXXX`ipomq‡taXRNbwƒ‚wgWY_etƒˆyj_YSI?4,$$5GH;.-/1AQ[TNTew…“¡®º¿¨’‚zrz‡•šŸ¤­¶´¦˜‰‚wkbehr‡œ ›—šž   ¦µÃÌÒØÖÕÕÞçäι¹ÆÓÈ»±¼ÈÐÒÔÇ°š——–Ž…}{†}lew‰‡|wrokhd`YOD;2*2:DRamxƒ†‡ˆ€yoaRIGFCA>2&)472,/49755;AEFFNYdZMDFGPcw‹ µº¼¼«š“œ¤—}c^][M>7;?BFIKLN\kvz~~p`OONPUY\\\hw†›±¿¹³µ¾ÇÏÕÜäìñññçÓ¾ÁÌ×ÑË󣘒‹‰‡†€{rX>9Ndv…•œ¢£”†{wt{‡’‹ƒ~Žž¨©ª«¬­¶ÀÊÓÛÛ̾·´²¥–†vf[ZY`lx‚‹”Ÿª«–‚~†’””ˆ|w…’€qlkjpuzz{vmd`_^bfhc_[YW_islfcjqtttgVD]yŒ€sou{ulbq“–”Š€p[GVjyvsrsu}‰•‘Œ†xk^ULTfw~‚‡““Œ„~zu‚‘ž›™š£«²¶º¹¸·©›ˆ„œ£¨­µ½ÃÃù¥‘ŽŽyeVZ^_^^bgky†Žsq|†‡„‚zriXGEWinnnrw|ƒ‹’™Ÿ™Œ€Š• ¢¤‰us}‡|oekqpg^ZZZbjt¥µ±®¤•†‚‚ƒ“£­ª§¢—†„Š‹wmaU]lz…˜ž¤¢˜Œ„{ri`YSLD:0EZlllpw~†• ¬³£’—¡•€jb[UROIA8678GXhw‡ŒŠuia[V[_dinsx}xsoooppqmgaju{wrlf_VNIFEXl¢¤šŽ„yv‰ª®²¸¿Å¾¸µ¾ÆÒâòçÒ½µ®¨¢–„ˆ‘š¨¸ÆÒÝèòüþþþîÜË»«¥­µ²ª¢±ÄÕÙÝÛÑÈÇÊν©˜œ¡§³¿»¬˜–“€n`^\]_`VKAFLK=.+/3455EUchnqqqdRA3%$8MSG<888-!$(((.6?/!&+7GWblsqpqtxgJ.C`wj\^{—ž–…|rqpw‹Ÿ²ÅØÞâäÚП«ª°·ÄÒáãååäãß×ϳ¥£¡¡¡¢¬ÁÕÛÜÝÒȼ¬›™¤°»ÅÏ¿¯£§ª£|‡ ¸±§’ˆziWRTUanvhZRRRZfrnjgntungb^Y\`ccdgnuriaZTPV]`^\[ZYTOKU^^I4-15-$.APV\cmwiUAVk}†ŽŒwwz}yvx‡—žœ›¦´Ã±Ÿ‰‚ƒ‹”¦°°°²»ÃÀ¬˜Œ‰—¦³µ¶½ËÚØÏž¸±¡‘‰Œ˜¢­¥›‘Œ‡‚~zsh]]^_hqsfZQJD8*#(-5FOXWRLT]ddc_SHB@>HTaq‘¡±µ²®ª¦£¦¨­´»»·²ºÄÌÆ¿¾ÊÕÓÇ»¾ÄÉÆÄÆÓßÜ˺¿Ë×ÕÔÏÁ³³ÀÍÖÝäèìëÛË¿·®¥œ’މˆ” ª±¸¸¶´°«¦›ˆ„‚…ˆ‘›¥®··ªž–‘Œ”¥ª¯¯¦ž•‹scTH<3209HW^bgikje`ZRKMPSSTVZ^cjqokhXI??@BEHNW_dikjie]UME=KYfpy|yvspnbUJHFIRZeoz€…‡{ne`[YXXWWX\_bdfc`\^`cccehllkjw…”—›š“‹Ž˜¡«¶¾«™š¤¥Ÿ™Ž€ux|‚…›¨¤š‘”—•Œƒ€„ˆ‡†…‹’˜¢¬²²²³´µ°«¨®³³­§©¬¯©£¡¯¼¾²¦§¯·¼ÂÈÒÝÞÑĺ°§£¡œ‡rfilnpqpomljf^VMC8653* "',:GNE;=IU\bhb\[enw}„‚~zwtu‚•“‘¬¼´­¨¨©¡rfZ_dfdadluz~‚€}{wtncYY^bfjlifccbis~}zz„‰‘‹v|ƒ‰„€~~~‡•¤¡œ˜¡«²µ¸¶±¬žŽ„ˆŒ‘–›Ÿ›•Ž‹ƒz{ƒ‹Œ‹Šsnw‰’’‘ˆƒ~{xy{|…˜œ ¤©­¯°°«¦¤±¾ÄÂÀ¾¼º¶³¯¯®«¦ Ÿ  £¦§£žž¢¦£ž˜•‘˜ ¤–­¼±ŸŽˆ‚xfTTbp~™™˜™¡™‰ysqpw}~pbdu‡ˆ„yqfQ<48=>>>N^jjje[QC4% '///2583.('3;CLVajoutplga]bhlnple_UJ?<9:AIS`my†“˜¤¯»»²ª¨¨©ª«¬®°³¹¿ÄÈÌÔÛßÝÛàì÷øöõóñîåÜϾ­¬²¸··¸¹º¶­¤©²¼´«¢˜Ž…|tmidksz~‚‡Ž•™›˜’–œ”Œƒyof\UZ_cdeghjw‡”Žˆˆ’—†uld\OB71+,047:=@CEILNPQOLJS\`XQKGCAAABBG\q|||‡—§¥¢¡¢¤£¡ ”otz™£©®­©¥ œ˜˜˜–‹“š…zzzvkah{Ž‘’””””˜Ÿ¥¯ºÅÇÉËËËÉÆÂÅÈʾ±©­°®¨£›“‹‡ƒ~wqkgcdgi`XT\cgggjnrkd`dggdaWJ>;89@FOYdjmpuz„€uklszyxy…†‚~~ƒ…‹‘˜¡ª¥–†œ¦¥£¤§«©¥ š“Œ‹‰‰‰‰‡†„~~„ŠŽ’‘’“rnrv{†™”Š€vmhecUG;85.""+-//+(')+(#&-5EU^\Z_fnljkt}ˆ” ©°·®¢—”‘ˆ„‰”Ÿ£¤¤™Š“™ž¤Ÿ—‘’“‘‰‡‡‡Œ“˜””™–…‡Œ‘•™œž žš—”‘‘’”¦«««¬­®·¿ÇÉËÆ¹­¦£ —„‚„–šœ¢¦¨›Žˆ’”•–œ£¨¥¢˜ƒmc`^[XVVVX]beghkosssrrqu|ƒ€{vpjea^YSLMOPW^gx‰“•˜›ž¡’‚xz||{{zzz~yrmmmptwrnn|Š‘‡}tqmiaXUY\bipsvyz{zzzunhjlou{}|zvroooqtxupkov{{{zwtw}„„„…’ «¯³²­¨¬±¶±¬¨§¥£Ÿ›˜•“‘Œ‡‚ƒˆ†|qx€„„ƒ…‡ŠŒ’ˆ}uuuw{~†‘›£«²¶¹¾ÃÈÆ¿¹¹¹·«Ÿ•Šˆˆˆ‚{wxzvmd[SJQY`_^_be_REGKMJFEEELYfkmow€…~{xtplhgfedb]SIDB?BDD>79BLSY_][YVSWbmw€ŠŽ‘•—˜˜–”—œ ¨°¶¶µ³¯«©©©£œ˜¢«ª™ˆˆ’››š™•‘“§ªªª¥Ÿ›£«²·¼¿Áøªž£¨¬­®±¶ºÉÛëÝÎÃÿ¹´´´´¯ª¦¦¥£Ÿ›•‰ˆ‡ˆˆˆƒypt}‡…„„„…~paWOFLSZaipw~{unf^YZ\[[Z_fmorrmhis}‚ƒƒ~ysnjcYNNTY\^^\YTI>;=@M]mtz‚‰‘Šƒ~zw~…ˆ„‚…ƒ|y|‹š›Ž|ywutv}„ˆŠŒŽŒŠ‡‚|{~€|vpnliaYM=-%"*)!%3@ABCEGECALYfimqtw|ƒ‰Ž’—Ÿ§®±µ¹½ÁÃÆÉËÎÎÊÆÂ¾º½ÀÃÁÀÀÄǶª§§§«¯´ºÀÅÊÎÏÏÏÉý¸³²¶ºÄÑÞ×Îź°¨¥£Ÿš–”‘Ž’›¤¦¤£ŸœšŸ££›“Іޗ”‹„zuqlf^WTPOOOPRSI=369:::4(!$# #&.582-.4;DMWOHCFJIFCGMSOKJMPV_hcWLXenha^acfkoqtw„‘¥®¯®¬´½ÄÄÃÆÌÒÖØÚÙÙÚÝàãããäääÝÔÌÇÂÄÒáãÛÔÏÊÅ¿¹³¯«­±µ¯§ ©²·¶´°ª¤¦©«¡—‘”˜šœž›™–ˆxolptpjdinqqplbYTQNPRQJB<9630.8CKKKMORUVXbmx|„…†ƒ{xvtttw†‹’‰~toid_[[]_l|ŠyhZVROLHOXaeimqvwusx~ƒ{y|~|z~„‰‰‰Œ—¢¦¢Ÿ”†yk]SY^cehmu}voihfeeemx„zmdgjh^TOLJVcoopuŒ“•—–•–œ¢£Ÿ›¡¥›†Ž–ž¨±ºÁÉÇÄÀ¼¸·¼ÂÄÄÄÀ»·ÃÏÔǺ¶¸»ÃÎÙÕÑÍÊÈÊÑØÛÝßÝÜÚÑÈÂÁÀ¶¨››œ¡¤¤Ÿ››œœ—“ŽŒŠŒ“™’„u|…Œ‡‚~~~}{zuojaXND;888=<;<=>:,"##"""!)4;AIVdg`Y^eloqu|ƒˆŒ•™›ššž¡¤¥¦¨ª«¬­¬¥Ÿš—•—šž›š˜–•••“’’““Š‚|{zumfmw~~~ƒ€}y|€‚…‡‰Š†‚~jUFDBFLR\gpia[XVYahr|…}|}}zvz€…‡ˆ‰‘’‘‘”™£©¯°²¯ª¥¥¥¥§¨§ž”’“”””–™™•‘’˜Ÿ Ÿžœš†‚„ˆ‹Ž“–™šššœž £¦§¤¡˜“މ†„‚zussseXLGAACFKQVSPMIEHPWWUSMFCDEFHILPSOLKLMLLLOTX]beeddddgjnoopqstttvz}yuqqqnf_^achnt}†ŒŽ‘”™žš“‘”—ž¥ª®²¶»¾¹³±¶¼ÂÉÐÓÕÖàéñöü÷êÝÙÙÙÝáâßÜÚÙØÒʾ»¶« ž¥­«¥ ˜‹‘–˜–”–™œ–ˆzkgt‚~z|~}xk_RF9>EJJJKLNF8+'%###$$$',1.,)&"$1=A?:613468:940135423?ADHI@70*%%')07?FMRTWYZ\YWTTSV_gjihnv~€‚}xy}ƒ†ˆ” ¦¢žž¢¦¥¤£¨­²¸½½¹´³³³­¨¥§¨¦¡››››Ÿž˜‘“–†|~€€‚ƒ…ˆŠ‹‹ŒŽŽŒ’œ¥©­®­¬««ª¨¥¢¢¢£¦©©§¤¥¦¦¡œ–‹€zzz{|}€€|xskbZSKIHHUakmoqqqoljgdcgkpuz}„†‡†…‡Š“–›¡£˜ŽŒ–Ÿž˜’ŽŠˆŠŒŽ‘”™š‘ˆ}yyyy|€}~…„ƒ€}}|{ywz€………………‚xnkkkosupjhmsqjbdhkihfb_][ZQF;?BC@>AIPTVWTRSaowxyxvuoidcafq|}zvutuy}…’Ÿ©°¸»¾¿º¶°©¢¤©¯®­«¨¥¢˜—˜™›œžŸ ¡¡¢£¤¤¨­²·½À¾¼ÀÆÌĸ®®®°µº»»»·³¯¬ªª¬®³»ÂÂÁÀ¹±ª¥  ¥©«¬­¨¤ž|l]NKNQX_fhiga\TLDA=:::=DKHA:?CHMRRJC?>>BGLT\enxzwtme___`cec_[WSOIB??@GUblt|zxupjea]`eis~‡‹ŠŒŽ‹ˆƒ~zwutss{‚‰ŒŽŠ‡„‚€ƒ†‰‰‰Œ“š˜“‹‰‰ŠŒ‘žª¶ÀËÆÀº¸µ²­¨©¬®´»À¸±¬¬¬«««¦ š—•””•›¤­²µ¸»¾½µ­¢•‰‡‡‡{{‰˜˜Œxsosvz€†•™ˆyri`XSMKJJIHJVbkmponnic^][ZYYWVTRQOG@;:9:;<60,1783/18?BCCBADNW`hp}Œ›œš’‰yqlgcvŠ›¥¯³±¯¬©§¥¤¦¬²·¹»¸¶³®©£—“’’‘“–™ž¢£ žš–‘ˆ†‡‰‹”’Œ‡|{zyxvxy{„Ž˜¢«­§ š•‘“”‰{‡…€{tnijkkkjlpstuurolkjklmszyrnnnptx{ƒ‚‚€~~„Œ”š ¢˜–˜™¢§¡›•‘Žˆ€wsqoqsuwyyvstttuvwwwz…ƒ~xxxvla\afilnopqx…ŠŽ‘‘‘”˜š™—™£¬±²²­§¡•‰€~|}…ŠŽ•›™”ŠzjdcbYPKLNMLLGA;CLPIB><:?GNTZ`lwƒ‡‡‡‡€xqonsƒ’•“‘ކ~z{|}€€†ŒŒ…~}€†Ž•–˜œ£©²»ÄÄÃÂÂÂÃÃľº¸µ´ºÀÅÇÉÎÕÝÛ×ÓÉ¿¹¹º½ÃÉÀ³¦£¡Ÿ›—“Œ‘”Œ‹‹Œ†{omnoljga[Z_d]QE?97?GID?AFKGC@@@BDGLQW[^`WNJLNQV\YVSSRRRRPNLORUVWY^dhknnnoooprtwy{zzz}‚ˆ•ž¨¬®¯®®­ª§¢™š«»·²­£˜”••™Ÿ¤©®¯¦ž› ¥¢˜œŸ£¥§©¬¯®¬«®°³³´²®©¤ž˜—–———˜šœŸ¤©¡—’”•“Œ„}zxvqkhikpx€‚ƒƒƒƒ|cI@FKQW\cimjg_RDBCCEFINSY]ba_^^^`gmokghjknqt{ƒƒƒ‚€yrmoqu}…Ž˜¢›’Šˆ…reenv„’žœ™—”‘ˆ{migflsxz||||zwtsqoonke``abkt|€„‡ˆˆ„€|wqpu{€‡–¡¬¥Ÿ˜“‹Œ†}t}…‹‰ˆ…‚‚†Š‰‡ˆ‰‹‡~vux{}~€„‰‡„€€…Б𤬲¹²¨Ÿ•Œƒzqlkk|‘¦ª¯°ª£œ•ˆ„‰–› Ÿ›˜–“‡ƒ€…‹‘œ¨®¨¡š“Œ…~wxyxxxyz{ywvutsqnkifinrvy{zxti_UJ@ADGTakmptw{xtqf\UROQUY^cgd`__`abbehlpuxxxuojjkkjijlnprstuu{€‚~z{„wosw|‡’šŸ£¡ž›œœ›–‘ŽŽŽ“™ŸžžŸŸ ŸžžŸ¡¢££¤¤¤¢Ÿœž¡¤¦©ªªª©§¤£££¤¥¦¨ª­°³¯¨ œš’‹‰˜š˜—•“‘‰}ƒ‰Šˆ‡ysvy||}€„ˆ…}}yusppppqrqommmmkihebbipuwy}†whZUQMIEKU^cgklmlifghhhhgeceltusrnjec`^^]`dhmrvrmkklmnnqtx|€„…†ƒ{|}~„†††‡ˆˆ‹“œ¥ªª©¥ž˜‘‹…‰‘—œ ¤¨«­¯§ ™•’‹‘›¤ª°³±°­¨¤ž˜‘“•—ž¥­¸Ãþ¹´°«¥Ÿš—••••”““–™›œ›™—’ˆ‚}xvtuvvvvwxzytolkknruz~yskbYPH@CFGECGR]fmunhba____acdhkouzwk^_ekd]Y`hje``aamz„„ƒ†‹‘Œvoieeeit~„†ˆ…‚tjehlosw{€…˜ŸŸŸžžž›˜•’Ž‹‡ƒ„†ˆŠ˜¢§£ŸŸŸŸš“‡‚Š”—’Ž”˜“‰~snoorw{~‚ƒ€}xnehpx‡ŽŽŽŠyxxy…‡…‚~~~ƒ……†…„„yuz€|xwwwvuuuuvy{zxvy|€Š•ž¢¦¦¤¡˜Œ€‚‹”˜–•‹…„ƒ…”•‘Œ‰†„€|yyy|‡ˆˆˆ‰Š‰‡…{vvwyvtqpnnnnnnnoqpmjhec`\YUQMLJGC????DJPTXYXVUSRPOMKIJPV_isy}€{wx{}…•¥¨¦¥¤¤¤©­¯¬¨¨©ª¬®°±±°®­­­­±·¼¼¼»¸µ³°®¯¯¯°±°¬©¤ž—’ˆ„€~…†…ƒ…‡‰Œ”—𢦦¤¢§®²©Ÿ—‰‡‰Šƒ{u|ƒ‡ƒztng_W\`ekprqph]RNJGFDGKPSUVY[^acdddeeeddc^ZY[\agnw€‰Œ‡|pkfdltz{}{zxvssstuuvtqnrw|}~}yvsokmnpx…ƒ†—˜——˜šœ £¥§©¤ž™•‘’”–——¥­®¯¬žˆˆˆ…‚€€…‰Ž“˜—”‘Šƒ}{zŒ™Ÿ¢¤œ”‹xrrr{ˆ•——˜¡ —ŽŠˆ‡“𣫭§ ™‘‰‰Š‹“š¢ª³³¯ª¤•…}xrruy{}€‚„„ƒ~zvk_SUWY[]^^^bgljhiqyzuopsvy{|wrrw{ƒ‡€ysolhda[TLSY^\[[[[_did`]`cfffecbhntx|}|zywvy|~}|‡“””›£«­¯®¦Ÿ™”Ž‘’’’‹‡„~|Š”“‰…ƒƒ„‚~{|‚†‰‹‰ˆ‰‘”–˜ž¤§¥¤ ™“މ„ƒƒ„†‡…€zz{}~~wpmprqnlnoomkklmpuz}‚„†‡ˆ‰ŠŠ‹ŒŒ†zvrsvyxwvy|}zwxz}€~|ytpoppu|ƒ~zungis}‚…‡ŠŒˆƒ{oc\YV^goty{{{zzzxvvy|~~~}|{„‰ŠŒ‹‰†ƒ~xwvtqnov}ƒ„}{{{zwtrqplgcehmx‚„~ytojfcbfjmoquy}„Š•™™–“ŽŠ†‡ˆ‡„‚„‡‹”“’“•–™ž£¥¦§¥£££¤£¡Ÿ›™›™–•–˜”Žˆ‡†‡Œ‘“’‘’“Љˆ‡‡‡ˆ‰‰Ž“™š›ššš™—–’ŽŠƒ{x~„‡ˆ‰Š‹‹ƒ|vsplga^\Z^bfffeeedcba`___`bceghgghlppjeca`ejoooqtw|‚‰ˆ†…ƒ€~}|yuqponmllllotz{|~…‘‰‚|||}}~‚„‡‰ŒŽŽ‹‰‡…ƒ…‰“™ž£©ª¤Ÿš˜–———Ž…ƒ‡”œ £¦¢žš–“ŽŒŽŽ’—™•’‘”—˜˜˜•’‰‚}{xvvv|‚ˆˆ‰†~wpjeefgr}‡——’‡xtpou|„—…|}~‚„‰•‘Œ‡…„„…‡ƒ}vsqokhglpv~††„‚€{wvvvwxytnigffhimrwz|~{xurnpsuwz}€ƒ‚€~ƒ„~{zxvspnmmu|€~}{yz{}~„‡‡‡‡ƒzzzyxvsnijlmv~…†‡‰‹’”•–—˜™–‰Œ•—˜˜–“•œ£¨¬°ª¤”ІˆŠ‹ŒŒ’™Ÿ¡¤¡˜‹‰ˆ‹’•˜›››—Š…‚€ƒ‚~yz||yx{}†Š•›™–“Œ…~}||‚ƒzm`]aegggedbZRMLKPW]`bb]YUSPYfsw{{tnhfc\QFS`lrw|‚€|xsmjnrw~…ˆˆˆ„€ƒ†‰‹‹‹‡‚}rg^[W^kxƒ–––“Œ„}z|~…‰ŒŒŠ„~|||€„‰‘™žŸ š˜ž£¨©ª«­¯¨Ÿ–’ŽŒŽ’”—•“‘‹…~|}€}yunga^[XUS[iw|}zvqlpx€‰’›œžœ™–‘‹†‡ˆŠ—œŸ¡ž—‘‹…†‹‘““’‘‰€vmc_cgkosx}‚|wqf\XYY]bgkosw{}}}‚‡‹Š‰ˆ†‡‰‹Ž“—“Œ‡ƒ‚„†„~€‚‚‚‚}xqjhffmtxxxrja\WRQPRV[]^^bglptvustttvx{{{~†–ž¥¤¡ž›˜———˜™šœž š•‹†}xxyz|}„‰ŒŽŒŠˆ‹‘“––––‰…Š’’’”—™˜–—ž¥«¯´´²±°®­¨£¢¨­­©¦Ÿ–މƒ~zuw|‚…ˆŠxpje`[W]enpsvz~{uojebehlpuvutvxzwuuuuvwwvutrppqrv~†‚yqi`ZZZ[\\agmqvxsnjihjlnu|}zvspruy…‹“›œ‘‡€|x}‚ˆŽ”™¢”Šƒ}x‡Š†‚€€€ztorvy|„Š‘–š•ˆŠŒŽ’‘‘‘”——“Ž‘’“”’‘‘‘’‘ŽŽ‰†‚|xtqx€†††‡ˆ‰Š‹‹ˆ…‚|yuplhdmv†’”–‘Šƒ‚‚ƒ†‰ŠŠŠ’—Ž„|„‡‰‰‰‰Œ‹‡ƒ{yvtuuvxzyxxtoje`_djnsw{‚xqlhefhjiikt|ƒ‡ŠŠ‰ˆ‚}wrmlqvz~‚„……}uojeeeeffglqssspkfdccgkpsw|‡ˆˆ‰ŒŽ‹ŒŒŒ•™—”‘Ž‹ˆ†„…†‡‹Ž‘‘‘”˜–„…‰Œ’˜›š™˜–”‘‰†‚~ˆŽŒ„|wz}‡’–š˜–”†ƒ†ˆŠŠŠŠŠ‰†‚}tkjkmquwwwuplkllorux|}}|~€ƒxj[ZXZclomlnprnjhjloruvwxtqnmloty~‚‡‰ŠŒŽŠxttt{‚†‚~}}}{zx{~~|{ywslehjkkjmt|‡ŒŒŒ‹ƒzuuuy€‡„€~…ˆ‹Ž’•–“Œ‡‚}|€…‰Ž“•”’ŠŠŠŠ‹Œ‘ކ€ƒ†Œ“˜˜™š›œ˜”‘‘’‘Ž’“•˜šœŸŸœ™•ŽˆŠ‹‹‹Š”œ¢§¬¥—š›•Ž‰…‚|||}}}zxurpkcZY[^]\\^`ckstronmlhdcegjlomkigfglpsuvy}€{vpjd_\Y]cju€ˆ‡†ƒ}xqjb^[Y[^clu|ƒ‰ŠŠ‰ˆ†……„†‰‹’”‘ŽŽ‘’”•––•”’‘’—œœš˜–“‘“™ž¡¤¥¢Ÿœš˜–“‹‡ƒƒƒ‚€~€„ˆŒ”’ŽŽ‹‰†Š•—˜˜•’І„ƒ‚‡Œ‘އ{wrx}ƒ„…††‡„{|}|xspmkgc^\[[cjnmlid_][[\]_acdfhknrtwy{}}}}||}ƒƒ„ƒƒƒ‡‹‘““‘І„ƒ‚‚‚ƒ‡‹’›¥¡˜ˆ€ytpqv|€ƒ†‰ŽŒ‰Š”‘‹…|qhgehnt|†’““Œ„|ywvvtromkkklkjjpx}}|{zyvqmnqtx}ƒŠ’–——•“’“”“’‘Žˆ‚€~{yyz{~‚‡‡††ƒ€|wrpqrtvxz{}ƒŠ’•‘ˆ‡‡ˆŠŒ’”™ž£¢ Ÿžœš˜••–—”’Š„€~€„‡ˆ‰ˆ…}zwxy{~ƒ€|{|~€€‚…ˆŠŒŒ‰†‚|wtrpsvxxxvrnkhegiiihikllllhedgilqux{~}{zxusqpjaX]chlqv{€}umga\VONSXbp~~}zvsqnquy…‹“”””—œ¡ŸžžŸ ¡£¥©®±©¡š•‹‡ƒ~zv|†ŠŽˆƒƒ„„…†‡Š‘’”•–™œš–“‘Ž’“Œ„€‹–Ÿ¤ª§ š–‘Ї‡‡ˆ‰‹Œˆ…€~€„ˆ‡…ƒ~ysokhhhikliea`_^\ZZZZblvwyyxvrkda_^aejv‚Ž˜¢ œ˜‰yld\Z\^eox„˜“ˆvrolpty…ŠŽŠ‡ˆˆˆˆˆ‰Œ‘”–‰‚€ƒ†…„„„„ƒ‚€‚ƒ…†|vspopruy}€ƒ†‹‘“’‘Žˆƒ‚…ˆ‰‰ˆ‡…ƒˆ’Œ‡‚~~{wtyƒ‡‹Šˆ†ˆŠŒŽ‘’‘‹…€„‡ŠŽŒ‰‡‰‹‘”“ˆƒ~z|}}|{}……ƒ‚€‚…†„~|~€€€…‹‰„{wtsrqqpnklpuuspmjhiikosw{~|zwutttuuu{‚Šˆ‡…€{xvtw{€‚ƒ…ˆŠ†€zwspjedinrvz{|}„‡‹Š‡„ˆ‹‘‹†ƒ}{z}„ˆ‹ŒŒŒ’“‘ŒŽŽ‹ˆ„‚ƒ†ˆŠŠŠŠˆ‡…‚~~~|{z}‚„…‡ˆ†„ƒ}wrpmmoquy~…Œ“–š™”‘“’‘ЉЋ’’’’’’Š…~{ywvvvx{~|z{|{zyy{~€~{xqjgiknpsw{€‚}ysmlllt|‚†Š‹Š‰ƒzrpnnsw|‚ˆŒ”‡zmf_]bfp~‹Š‡„wk`XPPSW_iqsuvvvwxxz}‚…ˆ‰Šˆ†„€|z~‚…‡‰†‚~~|zz}ƒ‡‰‡„ƒ†ˆ‹Ž’”•–˜™—‘‹‰‹‰„‡— ¨­®¯¬©¦Ÿ™“މ‡‡‡‹•“’“•–™¡œ’‰†„|wvwx}…‘•—’މ„}{zwtsx|}xsomkhfehknoppppnljihiijkmnpqssstttuuuwyzxwwxzyxxyzzvrqtvzˆ…€|vpmpsvy|†”¢¥¦¥œ“Š€wuwx~…‹•—––—™š•‘Œ‰†ƒ{ywvvvw€ˆŒ‹‰ˆ‡‡‰ŠŠŠŠ‹Œ‹‰†‡ˆˆƒ~|~€„ˆŒŒŒ‹„}wtqruxyz{€…‰‰Š‡€z|~~}xtsuv{‚‰Ž“”†~zuptx|~„ˆ‹‡wrljrz€‚‡”—š›™—”‘‰„€‚‚‚ˆ“ ¡¡˜Ž…{qnoow‹ŒŒˆ…{vttu}…‹‹‹‡{|}~ƒƒ{vrmnqsuwz„…„„€zuqnmrvyzz||xsqomllnqtuuvwxwvtvwyzzyvrqrtuvw|‚†††„z{~‚‡Ž”””’‰„€|~„‡Š‹Š‰‡ƒ~~~‰”œœœš˜•ކ~‚†ŠŽ“”““–š”Œ„‚€‚‡Œ‘•š››š”‘“•–••”‹ˆ…‚ƒ„„€}{|~€ƒ†…‚€€€~}|}~~€{vrmhghhknrx~}xofcbcfioz†‰‡…|wqke`Z[`emv{wtplnsy|~€{vqpnmkikmnrvxtportvxz}„†‡‰‹Œ‹‰ˆ‹Ž‘“•”‘‰†‚ƒ…†‡ˆŠ••“Œˆ……†…ƒ€ƒ‡‹Œˆ†††…ƒ‚€€€€„†…ƒ€ƒ„…ˆŠ‘”—šœ–ŒŒŒ‹‰ˆŒ•™œ—’‹‚yuropqrx}‚‚zvsqpv{€ƒ‡†…ƒ|tnnnoqtvy|„…†…ƒ€~|zwutwz}€ƒ}yvrnmlmpruy}||{zxvvuy‰‹‹‹ƒ{uplkmopqqw}‚„……„„‚€~€}~„ˆ‹ŽŒ‰…ƒ€†‹ŽŠ†‡—”Œ„}wstvx~ƒ‡ˆŠŠŠ‰ˆ‡ˆ‰Š‰‡†‡ˆŠŠŠ‰ˆ‡Š•”‘ŽŒ‰zy{~ƒ‰Ž‹‰‡ƒztoprsw{~~~ƒ~†Ž•–˜”†€{vtsu~†Š‡…{vxyyvsw†”˜——…|tkgggmu~ƒ‡‰ˆ††††„‚€‚zrmkinu|„Љ{wsx~„‡Š‹ˆ…}yz{|„Œ“•——––Œ~pmjinrxŠ–›‚wusqpoooortwwwy|~€€€‚~{xusqpnw€‰•–“‰xxz{€…†ƒ}}}|{{†Œ“’ŽŠ‡…‚€ƒ‡†„€€‚ƒ………†‡ˆ…~€‚ƒ…‡ŠŽ’Œ‡‚ƒ‰–šž™”Š„ƒ…†‹“š™™˜•’Š…„„„‚€€€„‡ŠŽ’ŽŒ‡‚}zvuuuy}~|{zxwvvz~‚ƒ„ypkifghjqx}{wspmljhhhjnrsttttspllmmlllptxxxvrnkhehjmv~‚ƒ…†„‚ƒ…ˆ‹Š‡…|z|~‚Š’–™›šš™™˜–’Љ‡„‚…ˆŒ“•˜–•“Žˆ‚{ttx|€†‹‘ŽŒŒŠ‰ˆ…‚‚„†ˆˆˆ‹ŽŽŒ…~|~ƒˆ“”Œ…|sonmjgfimptwyzzwtqpoquxyyyxvwy|~€ƒ~{xtqqqt|ƒ…„„~zuporu{‚Š‘˜™•ˆ€zvrvz~ƒˆ‘•“‹…z|}€‚„†„‚€}zwrnkhfjos|„’—˜•’މ„ƒ‚‚‚‚ƒ„„‡‹‹‚xqmjnt{~€‚‚‚wokjjlnpw…ˆŒŒ‹Š…€zvrrx}€‚„……†‡ˆ‡†„€xquz€‚„‡‹ŽŽŒŠ‰yrpnqw|…šŸ£¥ ›–Ї…„…†‡Š‘“Žˆ}ywxy|†‹•“‘ˆ|zxz|~‚‡‹“”‘Š…}{z}€‚…‡‡††‚}xtpnoqrtvtrrsux}„…†{uspnnnqvz|}~{yyz||||ywtnidcbelrvy|}~}}|{yx{~‚„……†…ƒ€€€ƒ…ˆŠˆƒzxz|~€‚„†ˆŠ‹ŽŽ‘“””••–”‹†|{{{{{}„‹‘—›—”Œ„~{yy{|}~~ƒ…ˆ‹Š†ƒ€€„ˆ‹Ž’“““†~|{{‚„„„|xwuvy||||}~~|zxxxyyz|}€€~|{zx{ƒ†ˆ‹‹‹ˆ‚{vrnsx|{z|ƒ‚€~|{{|~€‚„ƒ{zyxxxyz{}€ƒ„…†ŠŽ‹ˆ…}yurportvvvrnifddlt{€†ŠŽ’‰„zwvvwxx|€„ˆ‹Ž‘“”””‘Љ‡„~xuttz€‡ˆŠ‹‹‹‰†ƒ„…†‰Œ‘Šˆ…‚€„ˆŒ’——––“‰„€€|xtqooty|~€|wuzƒ‡‹Œˆƒ|tnkijmpx‰’’†~vmd]ciowƒ„„‚€}|z{}€~}{yy}„„„‚~zyyxwvwz}€ƒ†…„…†‡…€zvtrpnmoqtzˆŽ•”’‘‹…€{vvx{~ƒ‡‰Š‹ŒŽŒˆ…~vnnnov}‚…ˆ‹ŒŽ‰…€zutvy|„†‡†„‚}}}}ƒ…‡‰ŠŒˆ{{|{zxuqmpu{~„–›š˜’ˆ}vpjmos‹“™ŸŸž—’ˆ„ƒƒƒ„„„‡‰ˆzusrtvx{~„ˆˆˆˆ„€{}~€‡Ž”—šš™™“Œ†ƒ€~~~}{z}‚ƒ„……†„‚€|wrqooqsuwy{}€~|~€‚…ˆŠ„~yuqsx|‚ˆ†xphfggjmpsvy|~{xyyyxxwspopquzƒ†ŠŠ†ƒ€}||}€ƒ†ˆ‰…yurnnns~‰”Ÿª¤–އyrsvz‚‹””””””“’‘ŽŒ‹ŒŽŽ‹‰„yyyz‚Š‘‘’Žˆ~}||~‡•™œš˜‘‰ƒ~zzƒˆŒŽ‰…wnjgeimqv{}||}~~ysnkhiovyz{…—”‘‹€vpnlpty‚‹Ž‰‚|wsqqqrux{~€}xroqsv|‚‚}yuuux|€†Œ‘Ž‹ˆ„|zywtry€†‡ˆ‡††„‚}zy{}€„‡Š‰‡†…ƒ„„„ƒ‚…ŠŒ‹ŠŠŠŠŒŠ…€}zyyy{|~€~€‚€|y{}€„ˆ‹Ž‘”–™–“‹†‚}~„‰–“Œ‡‚€€€‚ƒ…‡†{wurrrrw|€ƒ††„‚„‡‰‡†…~{yxyzzˆŽ’‘Ž‹†yz{zyxyz{yxvwwxxywrmjgdjpw|ƒƒ‚„ˆ‹‰‡…}zxvtqnqtw}ƒ…}xqimrwŠ’“•‘‰{wsttv{€ƒ†ˆŠŒŽŒ‹‰ˆ†…‚€}yvwxyz||||{zzyxwwwzˆŒŠ…€€~}|€…‹”—Ž…~ytuz€‡––•”’Œ…~{yxz}…‰‹ŒŽ‘•–”’‰„~„†††„€}{zyxwwwwxz||||||}}}~€}|zyyyy|‚ˆ‘•Š„~{xusssvx{}‚ƒ€~xrkhdfr~ˆ˜“†~uoonrx~…“’‘‹‡‚~z{{|~„„„ƒ‚€~zvsqoquy~ƒ‡††‡‡‡ˆˆˆ†„ƒ‚‚ƒƒ„ƒ‚}{{{zzz{{{|}~€‚„„„„ƒ€€€‚ƒ…†††‡‡ˆˆ‰‰‰‰‹Œˆ†‡‰‰ˆ†„~~~~~~€†ŒŒ‰†ƒ|~ƒ…†ˆŠŒŽ‹‰‡†„ƒ‚‚„†ˆ„€|{z{~€ƒƒ~zwutrpnrvz}€„ˆ‹‰†‚~{y{||||~‚„ƒ‚€~{yy{|~~|{xutttvwyz|~€‚…‰Ž‹ˆ„|tmieeghq|†‹“•—’†zph`ejpz„Œ•’ŽŠƒ}y{|€„‰“Œˆ…‚‡Œ‹‰‡††…~…‹Ž‹‡‚|ytoptw}„‹‹Œ‹‰‡…„‚‚…ˆ‹‹Œ‘’“““’‹…€{wuuvx{|||}~~€†ŠŒŒ‹‰†‚{xvuv{€~€‚~zwwwy}€€~}}|yuuvvx{~~~‚„…†„‚€|yutrty~ƒ‡Œ‹Šˆ„€|yuvwy|‚†Š‹Šˆ†‚~|zz{|}}~}||||{{zzzz}ƒ‰Œ‘Œˆ„~{xtuvvvvw{‚„…‚~{||}}}|{z{|}||}~€‚ƒ„„„ƒƒ‚€}}~€‚‚~}{xtosz…ˆŠ‰ˆ‡‡†…„„……„‚ƒƒƒƒ‡‹’••‹†€z{~€‡Ž”•–’Œ†{vy{}‚†‰‹Šˆ…‚|ywxz}‚…‡Š‹ŒŠ…}|}~}}|}}}|||{{|~‚ƒ„…€|wtqoooooov‡ŠŒˆ„}zwtstuwz}}||{{|}~~}|||||||~‚„†ˆŠ‹Œ‰‡…ƒ}xsqqquy|‚‡ŠŒŠ‡„…†…}zwuy~„‡‹Ž‘І|wvvw{„‹’—› š”Žˆ‚}wrsw|€…ˆˆˆ‰‰Š‡‚}~†‹‘“’މ„~{xwy{~‚†ˆˆˆ„€|{zyyyyyy|~~|z{{{|||{{||}ƒ‡‰‹ŒŠ‰‡|xxxz{}„‹’“”’‡vliffnv}‚‡‡‡‡ƒ{xutttuuuvvw{‚„†…ƒ‚ƒ„†††††††††„‚}{yxvuttvxz|}€‚€€ƒ…ˆ‹Š‡„€}yuqsuwz~…ˆ‡…„„„ƒƒ‚ƒ„„…†‡ƒ~zxwwz}€ƒ‡…„‚€}~…ˆ‹ŽŠˆ…ƒƒƒƒ†ˆ‰‰ˆ‡…ƒƒ…†ˆŠŒˆ„€{wxz{ƒ†‰‹‹‰ˆ…}yusvy|‚„…†‰‹Œ‰…ƒ€~{wtuvwz~€‚„‡‰…‚~|{{|}€„ˆ†…ƒzwtronlqw}}~}|zyxxxxyz|~~~}}}|{{}„†…‚~{wuvx{„ˆŒŽˆƒ~zvvz~‚†Šˆ‡‡‰‹Š‰ˆ…~ƒƒ€ƒ†ˆŠŒ…~wvuvy{|~‚„‡ˆŠ‰†ƒ€}yzzyyxy{~}||wrosx|€…‰’‘Œˆ……„‚€~|{zzz{{{}…‰Ž’މ„€|ywvy|‡Ž’Ž‹‡ƒ|yxxy{}„ˆˆˆˆŠ‹ŒŒŒ‰ƒ}yvtttuy|†Œ‹‰‡|vutvy}€‚„†‡‡„~}|{zz{|~‚‡ŠŠŠ‡ƒ~|zy~ƒ…„‚ƒ…†„‚xqnnnquy}€„…††‚~|{zyxxxxwvtvy}†‹ˆ†„zvroqvz~‚†‹Œ‰…|~ƒ„†‰Œ‹‹‹ˆ…‚€}}|~„‡ŠŠŠ‰‡…|vutuy~‚…‰‰‡†‡ˆˆ‡†……„…††††‡‹Š‡…‚€~}|}„‡Š‡ƒ€}{{|~€‚…„„„€|zzz|~ƒ†‰ˆˆ†€yurpsw{ˆŽ‘Žˆ‚|wqppqsuwy|zxvvvwy|‚…„‚€‚„„„…ˆŠ‘‹ƒ|xsqtvzƒ†‡‡„€|xtrqpsvxz{}}~~~~€ƒ………„…††………‚|{z{{{}ƒ†ˆ‰Š‰‰‰ˆ‡‡„~|{zzz{||„‡ŠŠˆ†„~~‚…‡‡ˆ‡††„ƒ€ƒ†‰‹ŽŒŠ‡…ƒ‚‚‚‚‚ƒ„…††††††ˆ‰Šˆ‡†††‡‰Š‹‹‹…€{ywy|‚„†„ƒ|xtplmopv|‚„‚}zwtuuvz~‚…‰‰ˆ‡ƒ~zvrooorv{~€|zxvxz|ƒ‡‹‘Ž‹‡‚}zywwvw{~€‚„„„ƒ‚€~|z{||{zz|}ƒ‡†„~|y{|~ƒˆ‹ŒŒ‹Šˆ‡††††††„‚‚„ƒ‚€}z{}~‚„†ˆ‰Šˆ…‚‚‚ƒ…‡‰ŠŒ‹Š‰ŠŠ‰‡…‚}xwxxz|~…ˆŠŒŠ†ƒ|yvsrqsvy{}€€}{zxvxz|…ˆˆˆ†„‚€~€‚…ˆˆ†…€ztrqqtw{€†ŠŽ’‰„€|xustwz„‡†„ƒ~~~ƒ„ƒ‚|zywxxy|€ƒ…ˆ†„~|yxwwz}€ƒ†‡ˆ‰Š‹‹‡„~{ywvxy{ƒ†‡ˆ…‚€~}{{z{||~€„‡ˆ‡††††…ƒ‚~{yyz{{{|}~€‚‚€}}}}~€…‰Œˆƒ~yxvwy{}‚ƒ„…ˆ‹ŽŽŽŒŠ‰‰‰‡†„ƒ‚‚‚‚€~|}~€‚„†‡ˆ‡†…ƒ€}zxxx{ƒ†‡ˆˆˆ‡†„‚|~€€€‚„ƒƒƒ€|xyyz|~€‚„…††‚{yvtsrtvx{€€€~}||zxuuttttwz~‚†ˆ‡…ƒ~{wsuvx~„‡‡‡†„ƒ€}zzz{~€ƒ…‡‰‹Œ‰†ƒƒ…ˆŠ‰ˆ‡†…„ƒ‚ƒƒƒ…†……„…‡ˆ‰‰‰ˆ†…ƒ€~~~€ƒ„…†ˆ‰‰‰ˆ‡††…ƒ„„„ƒƒƒ~|zyyyz{|}ƒ‚~}||||||}~€€€~~€€~|zyxz|~€‚„†ˆˆˆˆ†„‚€~|{zzzz{}~~~~€‚‚‚€€~}{yxxyz|‚„…‡ˆŠ‰ˆ†„‚€‚ƒ„…†ˆŠ‰ˆ‡†…„ƒƒ…‡…ƒ‚‚‚ƒƒ„ƒ‚€€€€€€€€‚„†‚}xwwx{~€‚„‡ŠŒ‰†ƒ€|ywtuvw{€€€~{xvvvxy{€…‰‹‹ˆ…}yvstwy}…‡‰‹ŒŽŒ‰…ƒ€‚…‡‡ˆˆˆˆ†„‚€€‚‚‚€€‚ƒƒƒƒ‚€~~}}~€‚„†ˆ‡††‚}ywvw{~‚†ŠŒŒŒˆ„€}yxxxz{|€„‡‰‹‹ŠŠˆ†„~{{z{||}€€€~|{{zyxxyyz{|{yvwxxz|~€ƒ………‚~zzz{|}~ƒ…††…„‚‚€|xvvvz…†‡†††„€||}}€ƒ…ˆ‹Šˆ…‚€}zxwz|‚……„„‚€~|yy|~~~~€‚ƒ„…„„„……†‡‰ŠŠŠ‹ŒŒŠ‰‡†…„}||€ƒ‡‹‹‡‚|yvtuwz}ƒ…†…„ƒ‚~€€‚‚„……„ƒ‚€~}||}}~€ƒ„…††„‚€~}{ywvvvz}€ƒ‡†ƒ€}|}}|{z{||~„…†…~{yvuttwz}€ƒ…†ˆ‡‡‡„~}{|~‚„…††…„ƒ}|{z{|}‚‚‚‚‚‚€~|{{{|~€‚‚‚‚‚‚ƒƒ„…††‡ˆˆ‡‡ˆŠ‹‹ˆ†„|yxxxz}‚‚ƒ…„€}zxvxy{€„‰ŒŽŠ†‚€€‚„…‡‰ŠŒŽ‡‚~zwvvwxz|‚„†‡††…„‚€~|zzz{||~~~~~}||}~~~~}|{zyxz{}~€‚ƒ‚‚‚ƒ„ƒƒ‚€€‚‚‚‚‚‚‚‚‚‚~|{yyxwwvx{}€‚„„„ƒ‚€~~~€‚€€~}}}~ƒ…†††††††……„ƒ‚‚‚‚‚€‚}}}}€ƒ†††…„„ƒ€~€ƒ„ƒƒƒ‚€~|}~~~~~€ƒƒ„„„„…††…ƒ‚€€€€}|||}ƒƒ„ƒ‚~zvvvwxy|†‰‹‹‰†„~{xuwxy~ƒ‡ˆŠ‹ŒŒŠ‰ˆ…ƒ}~€ƒ…ˆŠ‹Š†ƒ€~||||~€€€~~~~~}{|||}€€€€€€}{yyxyz{~€ƒ„…„„ƒ~|{{|~€‚‚‚‚‚‚€}}|}~€€€€€€~}}|{zz{|}~~€~{yzz{}€‚ƒ„……ƒ‚€‚‚ƒ…†‡‡†…„„„„„„„„„„„„„„„„„„„„ƒƒ‚ƒ…‡ˆˆˆ…ƒ€~{zzzzzz~‚†‡‰‹‹ŒŠ‡„‚€~~~€€€€€€‚ƒ…†…„„ƒ‚‚‚‚~|{zzz{{|}~~~~~€}{zzz{||}~}}}|{zzzz|}~~~€€€€~{ywuvy}‚ˆŽŒ‡ƒ}z|~ƒ…ˆˆˆ‡„}|~€ƒƒ„„„„‚€~|{{|~€„‡‰Š‹‰‡†„‚€~|{{{}†‹Œ‹‰…‚~{xvuuz~‚†‰‰ˆˆ†…ƒ}{zyxxz{}€ƒ†ˆ‹‹ŠŠˆ…ƒ}|{|}}~€}~€€€‚ƒƒ„ƒ€~}|||}~€‚‚„…†LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/buing.wav0000644000175000017500000002045213263212010020747 0ustar aeglosaeglosRIFF"!WAVEfmt "V"Vdata« €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€~~~~~~€€€€€~~~~~~~€€€€€€€€€€€~~}}}~~~€€€€€€€~~~€€€€€€~~~€€€€€~~~~~€€€€€€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~‚Š‘ž¬º¾ÁÅËÒ×ÛàâäæçéçÞÕʼ¯žŒ{l]OD91+% %8L_s‡˜¤°¸¿ÇËÐÕÚßâããßÜØÑÊÁ´¦—‡vj_TLD=6/(! &4DUi}›§¯µº¿ÄÉÎÔÙÜßàààÚÔÍÁ¶©œŽth^ULE>81*$$.=KZix…’Ÿ©³»ÀÆÉÌÏÑÔÔÔÓÐËǾµ¬¢—„zqh_ZUPPPRTW[`fjnlaWJ;-&!#0=Up‰š«¹ÃÌÓÙÞãçëîðòóóðíêÞÓÆµ¤’l^SGA:3+# .>Pdyˆ˜¦°¹ÀÅÉÍÑÕØÚÜßáàÜ×Ïź«›Œ~pbVI>4*%   '8J`u†”£ª°¶¹¼ÁÉÐÕØÚ×ÔÑÍÈÁ¹±¦šŽ~oaVKB;4-&#.;GXiyˆ—£¯ºÀÅÊÎÒÕØÜÝÞÞÚÖÐÆ¼°¤—Š~rg\RJB;61.*'&%%%%-7BSev…“Ÿ©²·»¿ÅËÑ×ÝÜÖÑËľ¯¡’‚qcWJKLPcwŠœ¯ºÁÈÊËËËËǾµ¦”‚tfYPF>6.(!'7GXhxˆ–¥°ºÃÇËÎÑÕÙßææåäÝÖÎĺ¯¢–ˆzlbWNG@93.)$!!"$*020/.,*+-0>QcyŽ¡¯¼ÆÏ×ÝâçêíðòôòñïéâÚ̽­šˆxj[SKC>82,%!#.9ETct…–¢®¹¿ÆÌÑ×ÚÜßáââàÞÖËÀ²£”ˆ|peZOD:4.)&# !.;IZl{‰–Ÿ¨°¶»ÀÅËÏÒÕÓÐÎÊÆÁº´©ž’„vi_ULF?93-)%!!!#&)2=GUco{‡“žª²¸¿ÁÄÇËÏÑÒÒÍȹ°§ž”Š€vlc[SLFB>:50/./25:AHT`mxƒŒ•¤«²¸¾ÃÄÅÃÁ¾º´¯¥œ‘„vj_SPOO_p•©¶¿ÇÊÌÎÐÒÐËŶ¢Ž~oaVKA90*$ +8K^p‚“¢¯¼ÁÄÇÈÉÌÓÚàãçàÙÑȾ´©ž’„wk^SJA:5/+)&$##&(/;GWi{‡’¤¬³ºÁÇÌÑÒÔÓÒÐÍÊÇ¿·®£˜€tjaXRKE@:62.--.38>FMV`iuŒ–Ÿ§¬±µ¹½ÀÃÆÆÆÄÀ½¸²­¦ ™‡~ukc[TPLIFC?;789;BIPZdmv~…Œ“š¡§«¯²³µ¶¶µ³²¯¬©¥¡–‰ƒ~yuqkf`]ZY\^ckryˆŽ”•‹m\N@4/*%# #&):M`uŠœ«ºÅÎÖÚÞâåçéëìéæâÜÕÍÀ³¤”ƒugZQIA92,'"#*6CRct„”£­·¿ÄÈÌÏÒÔ×ÚÝàÞÚÖͶ©›Ž‚vk_TJ@71+&# #(/>M]n~‹—£ª±¶·¹»¿ÃÊÓÙÓÍÇÁ»µ®¨›Žtg\TLE?94/*%! "#)2:FR^kx„Ž™¢«´¸½ÁÄÆÈÉÊÉÈÆÁ»´«¡—Ž„{riaYRKE@;754579<@DLV`m{ˆ‘𡧬²¸¾ÂÆÇÆÅÁ¼·°¨Ÿ“ˆ|obWMB@?AO^p†­»ÉÎÓ×ÙÛÙÖÓȹ«š‰zmaVKA:3,(#%-6FUfx‹š§µ¼ÃÉÌÐÔØÜßáâàÞÚÓËÁµ©›€sg[RIB<51,(&##%&-7BRbr€›¤®µ»ÁÇÌÑÓÕÕÕÕÒÏÌﳦšŽ‚ukaXQJC>83/+*)*05=FP[huŽ™ ¨®³·¼ÁÆÈËËÊÉÇÿ¹³­£š‡}tjaYSLGB=964327;AKV`kvˆ‘™ §¬²¶¸»¼½¼»º¸µ²­¦ ™“…~wohb^YUQMLKNU\dmv‚Ž™ ¨¦”ƒp]TKC@<72,049K\n€’¡®»ÃÊÑÕØÜàäçéêäßÙÑʾ¯ ocWMF?93.(" &,5@KZix‡•¢«´»ÁÇËÎÒÕØÚÛÜØÒÍÀ´§™‹sh]SH@70*%!!(0:IYhw†™£©°¶»ÀÄÉÍÎÏÎÊÆÂ¾º°¥šŒ~qf\TLE?82-)%$"$'*2:COZfs‹–¡©°·»¿ÃÅÈÊÌÍÊÈż´«¡—„zqg^VMFA;85210147940+*)*/5BFM^o‚˜­¼ÈÕÙÝàâäáÝÙ̽®›ˆwi[OD:4.)&"  #&0:EUdt…–£®º¿ÄÊÎÒÖÛàààßÜØÒÉ¿³¤•‡ykaXOHA;5/,)'''*17BP]lzˆ”Ÿ©±ºÀÅËÍÐÒÔÖÔÒÐÊü±¦›Žvlc[SLFA<853216;@FLUam{ˆ–¤«±¶»¿ÃÆÈÉÉÉÈŽ·±© —ƒzqh`YRLGB>:7658CIXhx†” ©²ºÂÉÍÑÕ×ÙÙØØÓÍȽ³¨š‹~pcYPGB<71,(%"%)-6?IWdqŒ—¡«±¸½ÀÄÆÉËÍÎÍÉž´ªƒyndZQH?61,''&'*-2;CP^ly‡’𢧫¯´¹½ÀÃÂÀ½¸²¬¥ž–„zod[RJEA<8410.035=ENXcmw‰‘™¡¨®²¶¸¹¹¹¹¸¶´°¨¡™‡€yqjd]VPKGCB@??>AFJQX_it~ˆ‘™ž¤¨¬°´¸ººº¶²­¨¢›“‹‚xne\SLD>:67:83-)'$'-2;DN]k{‹›¥¬³·¼ÀÆËÎÑÓÒÑÑÌÈú²¨ž“ˆ}qh^VOHC>840./03:BMZgs‹•Ÿ§®´¹½ÁÃÄÆÆÇÅÃÁ¼¶¯¦”Š€wof^WOJD@>;=>@FMUan{Š˜£­¶¸º¹²«¢—Œ‚ypf]TMGFHKQX`jt~‹—¡©±¶¹½¿ÁÁÁÁ¿½»´­¥˜Œypid^WQJE?<;:71,(%!!(/=Oau‰›§³»ÁÆËÐÕÙÞáâãàÝÙÎö¦•…vh\RHA;50,($!!!!+4@Sew‡˜¤°»ÀÆËÎÒÖÛàÞÝÛÖÑɾ³¥–‡znbXNF@:5/*&#"%(.9CSfy‰™§®¶¼ÁÆÊÏÔÖØØÖÔÐËÅ»±¦šŽtg\SIB<60+'%"&+/;GTdtƒž¦­´¸¼ÁÅÉËÌÍÌËÊĽ¶«¡–Š~sh^ULD=61.+,-/5;DR_o𥮴»¿ÂÅÂÀ½´«¡–Œ€ui`VNJFC@>@CFPZcmw€ˆ–›Ÿ£¦©¬¯°°°­ª¦¢žš”ˆ€xpib]XSNJGECDFGKOU]dlu}„Š•›Ÿ¢¦§¨§§§¦¥£Ÿš”އ€{upje`\XUSPPPQSUX\`fkqx€†Œ‘•˜š ¢£¤£¡Ÿœ™•‘‰„ytokgca^\ZYZZZ]_afjnrvz~‚‡Œ”˜šœžŸŸžžž™–’މ…€|yuqnkhfdcbcdefiknqtx|€…‰“•—™š›››š˜•’ŽŠ…€zuoic]VRNLNPWes…™®»ÈÓØÝàâäåææÛЭ˜…tbVJ?94.)% !)4GZo…›©µÀÄÈÌÐÔÙÞâäåãÝ×Í¿± }oaUMD>93/*%""%/=K_t‰˜¨µ¼ÄÊÎÓ×ÛßáãâßÛÓÉÀ°Ÿ‚sh^UMF?92,)&&'(09CUgy‹©²¼ÁÆÊÏÓ×ÙÜÛÚÚÔÏȽ²¦˜‹~rf]SKD>950-+*,/5AN]nŒ˜¤«²¸½ÂÆÉÌÎÏÎÌÊÇÁ¼³©Ÿ‘„xmcYQIC<63/.027?GS`ly†‘›¥­³¹½ÀÄÆÈÈÅü³ªœ‚xnd[SJB:6200037;989;>EKS[doz…Ž—ž£©­°³µ···¶³®¨ ˜†~vnf^XQLHDCBCDFIMQYbku~‡Ž–œ¡¦ª­±±±°®¬©¦£œ–‡€xqjd_[WTQPOPQQUY^djqx‡Ž•›¡¦¨«­®¯®¬«¦¡œ–Šƒ|vpje_ZVQMJFDCCEHNYdt†™©¸ÆÏ×ÞàãæéëèäßϾ¬–o`PG=50,'#!1BWp‰œ­½ÃÉÍÐÒÖÛàâääßÚÑÁ²¡Ž|n_RJA:4.*&""-?Qiƒœ©µÀÄÉÍÑÕÙÞâââߨÑŶ§–…uh[PH@:50+&!%,61-(&%&*.7CO`qŽ›¥¬´¸¼¿ÃÇÊÊËÈÄ¿µªžƒvk_UMD>820--/06>FTcr€›¤­³¸½ÀÃÆÈÊÉÅÁ¸®£–Š}qe\VPJD?<9889=DJUan{‰•Ÿ©°¶¼¿ÂÅÇÉÇÄÁº²©ž”‰~skc\VQKHEDDDGJNTY`kv€‰‘—›žŸŸž›—”‘Ž’–š§µÁÌ×ÞáäâàÝÕÍ®›‡t`SG<60+&!(4E^x¡¶¿ÇÎÒÖÚßãåææÜÑİŠzi]RHC?92+'$!$'+9GZsŒ ±ÂÉÏÔÖØÛàåçèéÜÏÁ®›‰yi]SHB;50,)'&)-1CUj‚›«¸ÄÉÎÒÖÙÜßáßÜÚÎõ¢Ž}n^TKB<60+&###,6AXo„–¨³ºÂÆÉÍÑÕØÙÙÕÏʽ¯ Ž}m`RH@82,'$!#'+8GWk©²·½ÁÄÈÊËËÊÉľ¸¬Ÿ’ƒug\PG?72,('%)/5BQ`p˜¡§«¯²´·¸ºººº·²­¤š…zof\TLE@;7657;?GQ[hvƒŽ™¡¦«¯²¶·¹¸¶´¯¨¡—Ž„{qh_WPJDA?>?@CIPZfq|‡‘˜Ÿ¥©­¯±²²±¯ª¥ž–Ž…|skc[VPLJHIIJOSYbku‰—¢¦©«­¬«©¥ ›”…}unf_[WTRPQRRVZ^fmu}†Œ’˜œ £¤¥¤¢¡žš–Š„~xrlgc_[ZYZ[\_bflsy†Œ‘–š ¡¢¡Ÿš–’‡‚|wrnjfc`^]]]]^^^`acegilot|ƒŽš¦²¿ËÒÚßáãáßÝÓÈ»¦‘}jXJ?4.)$'3Mh—­¼ÅÎÓÖÚÜßßÜÙÏÀ²ž‰ueVI@71+&"!$/CVnˆ¢±¿ËÐÕÚÝáââáÙÑÆµ¥“€n`SG@:4.(%" )2?Xq‰ž´ÀÉÒÖÚÝàâáÝÙÏ÷¤‘p`TJ@92,(#$*/?Sh~”©´¿ÇËÎÓØÝÜÜÚÒɽ­œ‹zi\OD=5/+&(+.?OawŒª·½ÂÇÊÍÏÐÐÌǵ§™‰zl_SIA851036>JUeu…’Ÿ©¯´¸»½½½¼¶±©Ÿ”Štld\UNIEBBCCKRZep{„Ž•œ¢¥§ª«­«ª¨¢›•…}tlf_YVTSTUX^elt|ƒ‰—¡£¥¥¥¤ œ˜‘Šƒzrkd]ZWTTTVZ]dks{„Œ’˜œŸ¢£¤£ ˜‘Šƒ|unhb^ZXWVXZ]cipx€ˆ–›Ÿ£¤¥¤¢ œ–‘Šƒ|voie`][YZZ\`djqx…Œ‘—›ž    š–‘Œ†€zupkhebbabdfinrx~„Š”—š›œœ›š—“‹†}yurolkijklnprux{~€‚ƒƒ€~{wtokgdbfio|‰˜ª»ÈÓÞáãäàÝÓÅ·¡ŠtbQB7,% (9Sm‡Ÿ¸ÄÐÙÛÝßàà×ÌÀ©’|iUG<2+&! !,7Lgƒ›²ÈÐØÞßàßÞÝÑŶ ‹wfTH>4.)'''/=Jc~˜«¾ÍÔÚÝÞßÚÔο¯ž‹xgXI@80-*,39J`vŒ£·ÁËÒÔÖÕÕÔÊÀ³¢~m\OC83/.26BSdz¤¯»ÃÆÉÉÉÉ»³¤•…tdWK?94135=JWh{š§±µ¹»¼½¹´¯¤™~obWLE?:::?ISap€Š“œ ¥¨©©¥¡œ“Šwngb]]]^^^_acglrx}ƒ†Š‹‹‹‰‡†‚|xtqollllnopsux|‚…‰ŠŒ‹Šˆ…ƒ€|yuroljhgghikmptw{‚…ˆŠŒ‹ŠŠˆ†„|xurqonmnoqsvy}€ƒ†ˆ‹‹Œ‹Š‰‡„‚|yvtrqpqrstvx{}€‚…‡‰‹‹‹Š‰‡…ƒ~|ywvuuuvwwy{}€‚„†‡ˆˆ‡‡†„‚}{yvvvwwwy{}€‚…‡ŠŒŽŽŽŽ‹Šˆ†„}{ywvvvvwxxyz||}~~~}}}{ywurpomoru~‰”£²¿ÊÕÚÜÞÕÌÁ¯œŠwdUG:3,'&$,:Ha›®ÁÐÔÙØÖÔÊ¿³žˆtbPC:0.-.:FXq‹¢¸ÎÔÙÜØÔͶ£ŽyiXJC<:;;HWhƒž´ÃÑרØÒÌÄ´£’l^RFB><@DNatŠ¡·ÁËÑÐÎɺ¬œ|l^TKGFFP[hy‹›¨µ¼¿Â¾ºµ«¡–ˆzncWSPPUZcp}Š—¤©®°¯­©£“‰tia\VWXZaiq|‡—   œ˜”†~vnhc__`bgls{„Š••–•’‹…xqje`]\\_cgnu|ƒŠ‘”’І{upkgda```bfkpw}ƒ‰Ž’’’‘ŒŠ…€|xurqqrssvxz}€‚„…††…„ƒ}|zxwvvvwxxyz|}~€€€€€~~}|{{z{{{{{{zzzzz{{{|}~€‚ƒ„„„„ƒ‚€~}|{yxxxyyyz{|}}~~€€€€€~~~}}}}}|||{{{||}~€‚„…†‡‡†††…„„ƒ‚€~}}}|||}}~~€€€~~}|{zxvtrqpopqsw~†’Ÿ­¹ÅÎÒÕÐÆ»§‘|hUE:0+)(7GYv“ªºÉÍÌÌÁ·«—„r_LC<7?GRh~‘¡±¶··¯§€sfYUSS[do|‰”ž¨ª«ª¢š…yqjcefipw‰’˜ž¡Ÿœ˜ˆ€xqmkjnrw}„Š‘—™šš–’†€{xuwy|€…Š”—š›š˜•‘ˆ„€~€‚„‡‰‹ŒŒŠˆ†‚{wtrqpsvy~‚†‰‹‰‡ƒ|yvutuwz|~‚‚‚€}{xvsponnpsux{}€€€~|zxvtsstuvx{}€ƒ†‡‰†„yrjc[Z\]dkqx„‡ŠŠ‰‰„ytnkigjnqw|…‰‹ŒŒ‹‰…}zwwxy}€„†‡‡…„‚}|zyxwwwwy{|~€‚‚‚~}|}}~~~}}}|{zyyyz{|~€‚ƒ„ƒƒƒ‚€€~~~~~€€€€€€~||{{{{|}~€€€€‚ƒ„……††………„ƒƒ‚€€~~}|||}}~~€‚ƒ„…†‡ˆˆ‰ˆˆˆ‡††„ƒ‚‚€€€‚‚‚‚‚‚‚‚‚‚€~}|{yxwvvvwyz~ƒˆ‘›¦°ºÂÂü­ŸŒwcXMGJMWfvˆ›­²¸·¬¡“pe[TY^gw‡’›¤–Ž‚wnhabegq|†˜œœœ•…}tmjhkpu‰“˜œ˜“†~zustvx}‚†ŠŽŽ‹‡…ƒ‚‚‚…ˆ‹Ž‘‘‘‘Ž‹ˆ…‚€~€‚„ˆŒ’““““‘ŽŒŠ‡‡‡‡ˆ‰‰‰‰‰‡†…„‚€€€‚ƒ…‡‰ŠŠŠˆ‡…ƒ~}}}}}}|||||||||}}~~~€€€€€~}|{zyxxwvvuvvvwwxyz{|}~€ƒ„………„ƒ‚~yuojgjlpv|{yvsporuzˆˆˆ‡}tmkhls{‚ŠŽŒ‰…€„‰‘Їƒ‚„††…„€|xvttuwy}€~}|{{{}€‚„†††…„‚€€€~|zxwuuuvvwxxxyyz{|}~~~~~~~}}}|||{{{zyxxwxxxxxyyyzzz{||}}~~~~~~~~~~~~~~}}}|||||}}}~~~€€€€‚‚‚€€€€€€€€€~}|{yxwvwwx{}‚‰˜¡ª­¯¯£˜‹}nfc`jt~ˆ’•Œ†~wyz}„‹‘’Œ…~wpjjilrw{~|yvspqtv{„…‡†„ƒ‚‚‚„…‡ˆ‰ˆ†…ƒ€€€€€€€~|||}~‚„…†‡‡ˆ‰Š‹ŒŒ‹Š‰ˆˆ‡‡‡††………„„„„„………††††††‡ˆ‰‰‰‰‰‰‰‰‰‰‰ŠŠŠŠŠŠ‰ˆ‡†…„ƒ‚€€~~}||||}}}~€‚ƒ„…†‡‡‡‡††…„ƒƒ‚€~|{zyxxxyyyzz{{|}}}}}~€ƒ…‡ˆŠŒŽŽŽŒˆ„}umieemv}€ƒ|qfa\\grŒš™•‘‚sijks‚˜¡—„}vx…Ž—š—‘ˆ€|zy~ƒ‡ˆ‰‡‚~{yx|‚„††…„ƒ‚‚ƒ„†‡ˆ‡…„‚€}}|}}~}}}|zyyyz{|}}}|||||}}}~LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/deng.wav0000644000175000017500000001221013263212010020551 0ustar aeglosaeglosRIFF€WAVEfmt "V"Vdata zxz|}}}~}zz|~}}~~|||}}}}}}}}}|{{|}}~~}}~~~}~~~}}}}}}}~~}}~~}~~~~}~~{xvy||{yvqmv†}zxwusqnlmsz{xuvwwwwxy{zxwrmjr{{n`XTPm©˜‡|zyuoiR:1g´©ž†jNTY^^_n‹¨ŸŒzsll{‰Šƒ|‚‰{jU; 0X…ˆ‹“›£ª²œ{Yl€Œ~piii^QC2!&b¶´²²²±¨Ÿ‰[-8i™zdD#6Q_fmŸÔúáÉ¥sAD\sh]ZfrfG'sÆùçÔò¡†hMF@Mz¦”`,.5>Tk€“§¼Òé´~Wbn{Šš€Z7BMK, #aŸÂàõº~b}™™Šz{~|gR;""Uˆ°¼²©‚ugZ’Éä±}W>$*6CTd}©ÕÍ shcd‰®¼¨”†}sN%3WÉ£„„…‚vjrŠ£´ÄЃ6'Qz‡•¡®¤r@Jw¥ºËЗ]?EK;# Eƒ³³²™e0Dqœ›š› ¤˜€hJ,O‰«ž„zplihhi}®ßË”\H80Kfw{~Š˜¦{P2Sm„ŠˆxoeilsŠ ¢‹saQAMYep{†›Œwccci~’•‹vj_VMN`q‘¡|jgdgpyƒ›…xaKFTbrƒ“މ}phc^p†šš™u[QST^hs…–›Žq`Oc{•›—ˆyhVDHLUo‰“‹~m_cgn|‹“–™„lULDH^uƒŒ”ކ}o`^jv…–¨”laUSW[l–˜›–|b[bjx‡”‘އxi]SIYm‹–•‚oe_Zdozˆ—˜‹~kU?LYfv†ŒŠ‰|m]]\d|”œ˜•„p]SJL\m~¡’qg]_p€—¢š“‡oVLPTg˜‘Šuhdeeq€Ž–™€gYQIVfu~ˆ‰vj]P`p€ššŽ‚p\HLPXo†Œ‰|k]bhp~Œ•š xcUGH`w„‹“‡{pjeels„™®{fPKT\jz‰‰‰„sc^`bsˆ›››“}hYMBQduƒ‘‚sibZfs€ž¡–‹v\CLT`tˆŽŠ…zna_]cyœ¤«•y`WMN^n{†‘‡}reYYguˆœ° ‘€lXPTXgyŠŠ‰ƒp^X[^oƒ–›Ÿš…paTHVfu~††|rg]R^jx¢¦šŽ{eQV[bo|‚„…yj]]^gœ¤¡žŽ|k`TS_kz‰˜‰xi_UXi{‰—¤›“‡oWNQTcv†„‚|n`XVTi˜ž£…m_YR[dn{ˆ‹‚ykZH\pƒ‘žŸ•‹|l[VQVpŠ“|hWZ^fw‰•¥•ƒqbSP_nz…„ynaTT`l€–¬rc[YXdsƒ†€kVQUZl”—š–‰{lZIXiz†’}i^VN[ix‹Ÿ¥¡ˆmUY]fy‰‚uh[UOUo‰˜ ¨—ƒqf\Zclyˆ—‡vfWHJ\o~œ˜“‹xeYUPe–ކ{kZTTTbr‚”§©’{i[M^q„ˆ†€zm\LU^k‡£¨šŒ~oa`_ct„ŒŽ|eQSU]o•ž”‰}hTQdwƒŒ•„rb]XVVVm‹§ ˜ŒsYUbov|‚„†‚teXL@[{˜š›–‡xmcZ`fo…›œ‡scWJXesƒ”œž ŠnUXZcyŽ’Š‚ypgXJJbzŽž¯—{cb`bglw…“‡|`C>O`uŒ¡˜†{qf[Pc|’’‘‰r[TVXdp~¢¤“p_O`rƒ‰ˆq^LOR]}¥—‰}pdddhr}ˆ”¡ˆjOIDKg‚Ž‘•ކ}l[Wbl~”ª‘xcZRQV[m„š ™}`X_fu…’’‘‹|m\K;Tr™¥£xlf`abh›¡’ƒlQ7J\my†–Ž{hZLNn—‘Š{j[WRT\dx’¬›†rfYYiy†‹Š‰ƒlTLRWn‰£˜ƒ|ulaVdxŠ• šyXQW^emv„’˜”|`DXoƒŽ™•„sjd]UMPpœ˜•iS]gpv}†›ŠvbQAB_|‰•Žˆ€qb\_bx–µœ‚k_ROTYet‚•§©ˆfY[\o†™“Œ†€yhR;I[n‰¥©‘xnjgffj{”’‘yX:GUcs„‘ˆ~scRQmˆ•—™‡sa\WUWXlЍ›Œ|jXVfw„‰ŒŒygXMC]¡—„zqkgdlt~“¨©ŠkZRIWgu|ƒˆŠ‹zcLWdr‰Ÿ¡rg[QHH`y‰”ŸˆlS^irx‡‘›’†y\?:Up‚œvspkbZp‘²¦›‹oRKWbipv…”˜‡vgZMd€˜–”Ž‚wi[MORZx—žŠulhdgjnw‹–¢‰eDIOYn„‰ƒ~~}l[Xm“¢±•tY]`a_^k|މoTQfz†—ˆ€vmbTG\w‡xheimnor‰ ¤ŒsaRDXn|z{€„yhXWV_£©•ulc_[[bjz¥rY[]dt„‹ŠpVLU_pƒ–‰{qqqmf_o†››š’w\T\cfhjx†Œ†q^K`y‘ŒslhdZOMk‰”ŠsgZgt}}}ƒš‹vaYPRi€†‚}zwtmffnv†™¬˜€lgbadflu}…u\Wer“ˆ|xlXDSh|…ŽŠs[Ydnpqtƒ“™’‹w]BQbqw~~zvrnkd]_z–ž—‚qcdeghit†˜Šwf`[avŒ‘Ž‹u`UVVhšˆuhikkkks|†“¡ bUWXcpzvqqv|sdUdu…œš†smmme^\n€‡„€saPcv„…‡ŠŽ“ŠteVVn‡Œ„|tlgijjihz”¯ˆth\\ivuqmvse][Zn†‘…|yvpiaekq~‹Šs\Zbkpu{‚‰ŽiS_kv{}vnoqri__vŽ˜˜˜‡sajsvohmy„€{ufWYp‡‹‰…~xslaWbv‰vmidekptx|‡“”‚ofdblwyrqsvodYcnzŠ™™„olnqmjjs|ƒ‰Ž~gS_kv~†‡„‚ƒq`\kz„‡yj_dilmmw…“Œ†~pcakuvuux{zrjc_Zk”†zupmifdex‹|ia_^kx‚ƒŠ‘ˆxhhhl|Œ‹|lkmnljlt}†›Štahotvyz|}{xtdTSex†‹„|wwwrh^j|„{qcVZk||yx„“Š€uh[k~ƒyqlgghihhl‚˜Žvoipvzwtv|‚udU[bjv‚…ƒƒ†…xjemuz}€rcX`ilkkr{…‰‹yger€€~vnikmh`Wfy‹‹‹‡|qqv{vqoz…†{phaZgt†Šƒyopqt}‡„xkiiiiikot}Š–ˆvgjmrw}ztmsyzm_]gpz„tlquuqmsz‚‚ƒ~o`_fnrvz~ƒ„‚€zrjs~†„|umlnoljkz‰Ž‡zrkt}{uw|‚xl_\X\n€ƒ|vwxxvtqnltŽ€qdddgmtwxy€†ˆ}roqsx„yuuupiaju€…Šˆ}qrx{vty~|yoaRaq|xtsssvz}tliu€€xpg^W`inmkqy‚~ytpkmx‚€zsrqpjedfir}‰vqv{{xux{~ƒn]\fpuxzxvw|‚|siqz{m``fkgdenx~€xogpz€}zxvurnjfbdp{|yuvwvvuvww{‡{nefhjnrpmku~ƒ}wwy{ƒ†znhmqrpooopv}|tknv€€|xvtsmf^gpwwwusqtwxwvw{~ysniejprolpw{xtqnq{„yqqqqqqolhp{…~wsssw|‚€|z{|zslkkkpvzwtuxzyvsvy|~|ummoqnllptvxyuplt|€}zwtqtxzrkiqyywuqnmt|~|y|€ƒ€}ysmnu|xrmpsvwyyyy~ƒ†~vrrssssqnnqtsnimu}€€zuuy|wnflqvwyvpkpw|{zz}ypintvvutssvyzwtv}ƒƒzuruxvrnrx|wrooosx~}{z|~}ytrposxztmlqvxyyyyzƒxoptwxywrmnsxvsrw|€‚…€yruxzywwwwvtspmmt|€€€|yvrnqw~{vqqqsvzzxw|‚†wrqorw{vqnrwwtqrtu{„~yxyyyyywvvwywsorvz{|~~€€€{urvyzxwusqtwxxwy~‚‚€{vtx|{xuwxxvtrrquz~|{yzz{yvswz|xurqquz}||}}yuuuuy}~zvvxyxwxz|~€ƒ€zux{}}}|zyyyytolrw{}€~{y{||yvwz}|{zuporvwwwz}~~}{yvx{}zyyyxvuuuuz~€~||}}~~|zz}}xstuvy}~{xy||yxxyz}€|xstuvwyyyy{}{wvxz|~|yxxyxwux|€}|zxxz}|zy|~|xvsqu{€~|||}}}}{yx|€~zxwwxyyyyz}€}{zyz|~|yyyyvttuwy|~}}}}|zxy{}}}|yutvyyyy{|~~}yvwz}}}|{yz|}{ywz}}{y{}~~}}}}|{{yxx{~~}}}}{zzz{|~€~{yxwxy{|}}~|zzz{}}zzyxwuwy{}}zz|}~€€€}yvxz}€~}}}}}}~€}{yz{{{{|~€~}{zz|~~}}|{zzy{}€~}LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/pling.wav0000644000175000017500000001104413263212010020751 0ustar aeglosaeglosRIFFWAVEfmt "V"Vdata¦€€€€€€€€€€„†‹“›µÒçáÛ·k H¢ü¶k9Xx|dK`‚¢ ž¥¬¤‘}›Ãã·‹t†—‘m}‘ŸŽ~vy|wqj‚›¬ •‘“•†r_cgg`Yc{’ˆuewˆƒwuzthauŠ•’‘’“„uk}’…w{ƒŒ~ok„–rMUj|xtv†–“ƒs|ˆ‘}ibrthr~†}st‚ކ„ˆ‰vsvz|}~€„‰“•—‡ƒŽ˜•Ї•ƒrkt|wlatˆ”mk{‹~hQr’¤†ij‡¤kLnž`g‹®˜w]¡ª‰hq’³–rZ|ž zT_¢…fVxššyWgˆ¦ˆi\|š{\m‰¡ŠtoŠ¥œ~`r‹ž‹xuˆœ‘y`s‰–ƒqp‚”~n}Œ’€mm|‹„yo~‘~kn€“ˆxm~Ž‘~kr†šŽ~u…”•…u{‹›ˆuk}ŽŽ}lu‡–ƒpi{Ž}myŠ˜ƒmh|‘{iwˆ”„tr‚‘‹{lz‰’…xwƒ‰}q|‡‹‚xx€‡ƒ|x|ƒ€~‚„ƒƒ‚}xx}ƒ€ys}‡uvƒ‘ˆwew‰’€mo„˜Œwcz’šhl† Žs^y•›~ai‡¥Žq]{™œ}]hˆ§‹m]{š›|]lЍ‹na›~aq¤ˆlb~š•z_s †mg€™’{dx†ol–ydyŽ˜ƒnn‚–‹wfzŽ–mq„˜Švg{”nt‰žŒwi|’~js‰Ÿ‰re{‘‘{er‹¡‰pf~•“|dtŒ ‰qj‚™“zbtŒ†olƒš‘yatŠ—„poƒ—ŽzgxŠ’‚st‚ˆ{p{†‰€vw‡ƒ~{~‚€~‚„…}~ƒˆƒzr}‡Œ€tuƒ†vgyŒ“€lp…šŠr_y“š€fmˆ¤p[y—›}^j‰©lZz›œ{Zj‹­Œl]~ŸœzYmŽ«Šj_Ÿ™xXn¥‡ic‚ —yZs¢†igƒŸ“x]v‘žƒgh‚v_x’›gk„žubz“š€gn‡ ue~—š€fo‰¢Špb}—˜}cp‹¦Šnb~š˜|`r§‰ka~›–y]s‘§ˆic€ž•wZs¢†igƒž“y^w‘ž…mm…œyey”oqƒ”Šzn{ˆ‹€ux‚Œ…}x~ƒ„€}~€‚€~|}…zu~‡Štw„†wk|Ž“ot‡šˆrbz‘•~gp‰¢Šo_z–˜}ao‹¨Šm_|™—yZmŒ§‰ka˜xYoަˆjb€ž”uWpŽ¢†jg„¡•x[u‘ „ii„ ‘v\vš€fj…Ÿu`z“š€fl† tc}–šdnˆ¢‹rd~˜™~bo‰¤‰nc›™|`q¦‰lc€ž˜{]r¥†g`ž–xZt’¤†hdž’v[v’¡…hhƒŸv]w’œƒjm…Žwdy•ns…—‰xl{Štx„†|v}„„€{}„‚€~}|~€ƒ€|z€††~vy‚‹…~y„…~~€€}‚†‚|w~…‡vxƒŽ†yn{‰~os„•ˆvh{Ž’~jq†œŠtf}“•}doˆ¡Špc|––|bpŠ¢ˆnd~™–|arŒ¢‡meš”z_sŸ…kf€š’x_už„jh‚œ‘y`y’ƒik„žu_y“œ‚gk† r]y•œ€em‰¥Œo\z˜œ~am‹©Œm\{š›{\n®Œj\}Ÿ›zXn‘­‹h^€¢šwTo‘ªˆga‚£—vUq‘¥†hf„¡“vYuƒik„žxcxŽ–‚mpƒ–Šzm|Š€rv‚ކ|v~†‡z|€„€‚‚|{„…y|ƒ‹ƒzr}ˆŠ~rw…“†vl}~lt‡™‡ti}‘‘|grˆ‡qh•’{dsЇpi€—‘yasŠœ„lh€˜x`tŒšƒki‚›‘x`x›ƒkl…žwaz’›hk„Œs`z”šel‡¢Œq_{—›cnЧŒo_}œœ}_nª‹k]~Ÿœ{Zo¬Šh]€¢›xUp“¬‰e^£˜vSq”©‡dbƒ¥–uTt”¤…fg…£’tZv“žej†£Žr[y—ž€aj‰¨ŽnZ{œ ^k®ŽkY|žŸ}Zl°iZ} œzXn‘­Šh]¡šyXp‘§ˆhb€Ÿ•wYs‘¢†ig‚ž’w]vŽšƒln„šxfz”ƒqt„”Š{q}‰‹€vy‚Œ…}x~ƒ„€|~€ƒ€€‚€}|€„„z|‚ˆ‚zt~‡‰uy„Ž„yq~‹Œrx…“…vn}ŒŒ}nv†–…tm~Ž{jvˆ˜…sm€’zgv‰–„qn•ŽyewŒ˜ƒon‚—ŽxcxŽ˜‚mn…œwbz‘™€hl…Ÿs_z•œ€dl‡£Œp]z˜œ~_k‰¨Œm\|œœ|\l¬Œk]¡zXm‘®‹g\€£œyVp“¬‰f_‚¤™wUs•©ˆfc‚¢”uVt“¢„fgƒ t[vš‚jn…œŒvez•ns…—‰xn|‹€ty„†|vˆˆy}‚†‚~}~€ƒ‚|}„€|z€……y|ƒŠ‚yu‰‰tz„Žƒxs‹‰}qy†‘„ws€Ž‹}ozˆ“„urŠzky‰“ƒsq’Šxgy‹”‚pqƒ–‹xfz•mp…›Œvd{‘—€io‡ž‹sc{”—~dn‰¤‹p`|˜™|_n‹¨Šl_~šzZn©‰h^¡šyXp‘ªˆf_‚¤™wUq“¨†daƒ¤–vUt”¥„dd…¥”uXw•¡ƒeh…¡s]x”œ‚hn†ŸŒuf{‘”€ks†™‰wm}Žpw…‘…ytЉ€v|„Šƒ|z„ƒ€|‚ƒ€€~ƒ‚{~‚…€|{‡…x}ƒˆ€xv~‡…}v}†‚xv€‹‡|r{†uu‡{n{‰‚uuƒˆzm{Š€qsƒ“ˆxk|Ž’€ns†™‰ug|“~iq‡‰re|”•|dqŠ£‰pd™—{_p¦‰lc€ž˜yZq§ˆha¡—vVq‘¦†fcƒ¤–uTs”¥„cd„¥”tVv–£ƒcg†¦’sZx–žcj‡¤Žr_{–›foˆ¡‹tf}“•is‡›ˆul~‘nw†“…vr~‹‰~rz„‹‚xw‡†y~ƒ†}}€„ž­m]}œœ{[mެŒl`ž™z[pާˆi`~•xZr£‡jf‚“y^uŽ„lkƒšycyŽ—ƒoq„˜Œzj{Œ‘qtƒ‘‡zq}ŠŒ€tw‚„|w††y{†|{„„€|~‚€‚€€‚€~€ƒ~~€ƒ‚|ƒ†}{€„ƒ}x|‚‡{y€‡…~v|„Šxw‹‡|qz†vuމ{nzˆrr‚“Šzi{•‚oq…™Œwe{—€jo†‹saz”™em‡¢‹p^z–™}`m‹¨Œn^|šš|^oª‹l_~šz[p©Šja€Ÿ˜yZr¥‡icŸ”w[t‘¡†jiƒ‘w]v›ƒjl„›vcy—‚lp…™‹wh{‘€pu…•ˆyp~ŒŽ€sx…‘†zu‰ˆ~ty‚‰‚{y†…y}‚†‚}}€„‚{~‚€~~€‚€€€€€‚ƒƒ|ƒ…}}…‚}x}ƒ‡zz‡„|u}…‰vvŒ†{o{‡€tuƒ‘ˆyl|‹‘€ps„–ˆvh|“jq†œŠtf}“–~fp‰¡Špc}——|aoŠ£ˆla~›˜{]p¦ˆja—y[q¥‡icŸ•wZt‘£…hfƒ “vYu’ …jk…Ÿu_x’›‚im…Œucz‘–€jp†›Šuh{‘~ks…˜‡wn~px†“†xsŒŠ~rz…Žƒyv‰†~v|„‰‚{z‡„~x}‚…€||€„‚~z~‚ƒ€}~€ƒ€€€€€€€€€‚€~ƒ}€ƒ„€}}‚†ƒ~y„†yz‰ƒ{u}†‰uxƒŽ…yp}Šqu„“†vl}Ž~lt‡šˆti}’’|gsŠ ‰rh—•|ds‹ ‡nf€›•z_r †kf”x\t „ge‚ž’vZu‘Ÿƒgh„ ‘u\w’‚gk† Žuaz“šhn‡ŸŒte|“–€jr‡œ‰ti}’’lu‡˜†um~}mw‡”…vqŠ}oy†ƒwu€Œ‡|q{†Œ‚yxІ~v~†‰z{ˆ„}y~„…€{|†‚~|€ƒƒ~ƒ€€~€€}ƒ~}€„„€|}‚‡‚}y€†‡x{ƒ‹ƒys~‰Š~rx„‘„vo~Œ}nv†–…tm~Ž{hu‰›†qj€•‘zduŒ†ni™‘x`uŽ„ljƒ‘w]vž„jj„žu]w‘›gk… Žt_x’™el†ŸŒsbz“—fo‡ŸŠsf}”•~hrˆˆsj”’~kv‰˜†tn€’Ž}kwˆ”„tq€Š{mzˆ‘ƒutŽˆ{o|ˆŽ‚vv†|s}ˆŒ‚yzƒ‹…|v~†ˆy|ƒŠ„}y„„z}†}{ƒ‚|~‚€€~~€‚|~ƒ€}|€„„z}ƒˆ{x€ˆˆv|…„yt€ŒŠ~qz‡“„up€‹{kxˆ•„ro€’ŒzgwŠ–‚nl–wbvŒ˜‚llƒšvax˜jm…œubz‘˜jo†Œue{‘•~hp‡‰sg}““}gq‡œ‡ri}‘|htˆ™†sl~‘|jw‡”ƒso€‹{kyˆ’ƒsrŠ{m{‰tt‚ˆzo{ˆŒ€tv‹„zr}‡‰€vy‚‹„{v~†‡w{‚Š‚{w~……~x|‚‡|z„„€|‚„~}€‚}€€€€€€~€‚€~{~€ƒ{{„ƒ~y}ƒ‡zy€‡…~v|„ŠxwŒˆ}r|‡Ž‚vuˆzm{ˆss‡xkzŠqs‚‘‡wjzŠŽ~nrƒ”‡vk|nt…–‡vl}Ž~mu†—†vn~}mv†“„to~Ž‹|mx‡’ƒur€ŽŠ{my‡‚tsŽˆ{n{‡Ž‚vv‚އ|r}ˆŒvwŒ…{t~‡‰€vy‚‹„{v~‡ˆvz‚Š‚{w††~w{‚‰‚{y…„~y}‚†|{€…„z~‚„€}}€ƒ‚|~~~€‚€€€€€€€€~~€‚€~|‚ƒ€||€„‚}y~‚…€{{‡ƒ}w~„‡€xyˆ„|u}…‡wy‚Œ…|t~‡‰uw‚Œ„yr|‡ˆ~sxƒŽ„xr~ŠŠsx„„xs~ˆ‡}ry„ŽƒxtŠˆ}r{†ƒxuІ|r{†ƒywІ{q{…Š€wx€‰„|u}…ˆ€xz‚Š„|v~…‡wy‰ƒ{v~†‡x{‚‰‚{x~……x|‚‡|z…„~y}‚†|{€„ƒ~y}‚„€||€„‚~z~ƒ||‚€~{~‚€~~€~~€€~€€€€€€€~~€}~€‚€~}€‚‚}~„~{‚ƒ{}…}z~ƒ„{|‚‡‚|y„„~y{‚ˆ‚|y……y}‚ˆ‚|z€†„~x|‚‡{y€‡…~x}ƒ‡€zy†„}v|ƒ‡{{€†ƒ}x~ƒ…€{|†ƒ~y„…€{|…|y~„…z|‡‚|y~ƒ„{}…}{ƒƒ{}…}{ƒƒ~z}ƒ€}}€„‚{‚„}}€ƒ‚|‚€}~€ƒ~|}~€‚€~}LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/pusch.wav0000644000175000017500000002110013263212010020754 0ustar aeglosaeglosRIFF8"WAVEfmt D¬D¬dataÂ!Ž•›¡¦¦§¨©© –Œwsy~„‰Œˆ…‚~€…Š”™’Œ…xx~ƒ‰Ž’ŽŒŠˆ„}ungbnz†’ž¡Ÿžœ›˜…|rimw‹”š“Œ…~wvvvvvwwxxyy{~€‚……„ƒ‚€~}|{y{~‚†‰‰…€|xtqmjfcks{ƒŠ‹…ztpw‡Ž–•އzskd\UMTbo}‹”Š€vlb`````bhov|ƒ€{wrmigdb_]`dgknqux{~zskd\YZ[\\]bhmsxzxvusrvz~‚†‚xndYQ[eoyƒ„{vrorvz}}vng`\dmv~‡vk`TOYcnxƒ‚~{wst|…•ž•‰|pd`is|†Œˆ„€|xsnie`ejoty~„Š–œ‘†{qfcfiloruy}…„€}yvtx}‚†‹‡€yrkfgiklnopqrsttttttrqonmow‡˜•‘‰„|zxvz}…ˆ‡‚}xrmz‡”¡®³°­ª§¤¡ž›™–˜œ¡¥©¬¨£Ÿš•–™›ž £¥¦¨ª¬§ š“ŒˆŒ’–™ž¤ª¯µº¾ÂÅÉÍ´¦˜‹ƒŠ‘—ž¤¬´½ÅÍÌ»ª™ˆw‚‘Ÿ®½À´¨‘…Ž–Ÿ¨±´²±¯®­¤›“Š‚…Š“˜¢§«°­¤œ“‹…†ˆŠ‹Ž‘Ž‹ˆ†ƒ‚‚‚‚‚„ˆ’—›–ˆzvz}„ˆ…ƒ€~{|ƒ†Š‰…€|xwxyz{{|}~€‚ƒ„……|tkcZ\enw€‡…ƒ|yuqlhdca_^\YTPLGGR^iu€ytnifhjlnpmjgda`acdfghijklkihfdcdefghfb]YUQSUWY[]aeimoh`YQJKQX^eiaYQJB>=<;9;EOYcmnkhec``_^]]\[[ZY\enw€‰ŠŠŠŠŠˆƒzupuz„‰‰‚{tmflqw}‚‚|vpkep{†’ ž›™–“Œˆ„€~~}}|}†˜¡ª£“ƒsbW^fnu}~}|zyxxxxxxvtrpnnoprstnhb[UU`kvŒŒŠ‰ˆ‡„~ysmgmsz€†ˆ‡‡†……‡‰‹Œˆ„€|yz|}„‡‹Ž’–—™š›™”‰„‡Œ’— ¢£¥§§¤¡Ÿœ™š›œžœ–Š„~‚ˆ“™›š˜—•”˜œ ¤¨©¦¤¢ žŸ¡¢£¤Ÿ•‹wm{‰—¥³´ªŸ”Š‚ƒ„…ˆ‹“—™”މƒ~~ƒ†ˆŒ“𡍝©ž“‡|sqonljnsx}‚†‰‹’ŽŠ†‚~zvrnjfq}Š–¢¥œ“Šxz{|}~€€€~}{zxvsqnkjlnqsuy}‚†‹ˆ„zuqmifbbo}Š˜¥¢š‘ˆzzz{{{…Š••†~vnmmmmmpx‡–Ž„{qgaaaaaairzƒ‹Œ…ysmkifdbflsz€…ƒ€}zxtojfa^elsy€…Š“˜™…{qgba_]\]emt|„ˆ‹’•’ƒufWHP\gs‚xndZPRTVY[[ZYXWWQLFA;<@EINRX^ciomga[TPPPPPPQQQRRSTUVWX_hqz„Іƒ|yz}‚…„ztojklnpqtw{‚†‡ˆ‰Š‹‡{peZO[hv„‘•އ€xqqqqqqpnljhhqzƒ–”‰tiaeimqux{‚……zncXLQ]iu‹Ž’”Ž…}umjt}‡‘š˜”‹‡ƒ‚€}|‚„‡ŠŠ‰‡†„ƒ„„………‚|uoicjqx†Œ”˜œŸ›™—•˜Ÿ§®µº³¬¥ž—œ§²¼ÇÏÌÈÅ¿¸°§Ÿ–“¨³¾ÈÄ»³ª¡¡¥ª®³´´´´´³°­ª¨¥©­°´¸·±¬¦ š¢ª²»ÃÅÁ½¹µ²®«§¤ ¡¥©¬°²²±±°°¬§¢œ—‘‘Ž‘—ž¤ª®­«©¨¦¤£¡ŸžžžŸ ¡¡¡¡¡¡¡¢¢££¤¤Ÿš”‰‡ˆ‰‹ŒŽ‘’‘‘‘“”–˜”އ€yrz‰˜•‹wmels{‚‰‰„{vqpnlkiknpsux{}€ƒ†‚}xsnhc^XSNMMMMMMMMMMMJHEB??@ABBCFIKNQSSSSSSVXZ]_^\YVSQUX[_b`[VQKHMSX^cdcba_^\ZXVTZdmv€…{pf\RU\dksz€‡Ž”›•„|toprsuvwxyyzxtplhdgknqux}‚‡Œ‘Œ†|vph_WOGXhy‰™šƒwlbfjosxuoic]Y_djotqjb[TPZeoyƒ„ƒ‚€}{zxwuuuuuuvx{}}xsnjimqvz~€€…™£­·°©¢›”“–™œŸ¡ž›™–”•—™›ž›™—•”’‘Žš¥°»ÆÄ¼´­¥ ¡¡¢£¤©°¶½ÃǾº¶²¬¦ š”’˜£©®®®®®®­«©§¦¤¥¥¥¥¥¤¡Ÿ›™ §®µ¼º±¨Ÿ–Ž’•—™›œžŸ ¢£¥§¨ª¨¥¡ž›š›Ÿ ¢›’ˆ~tov~…”–––––••••••‘Œ‡‚}|ƒŠ—œš˜—•’ŽŠ…}|{zzyz{{|}}{zxwuvvwwxwuromjjlmoppib[TMR]ht‡xpia]\ZXWX^djqwsmhb\Z^cglpoljheegikmomkjhgda^ZWTX]afjjhec`^]\[ZY[^`cfgfdb`^[XTPLJRZbjqqmid`^_`bcdfiloqrqomljmquy}~}|zyxuroljilnpsuvwxxyxwutsruxz}€~ysnhcfilnqqpnmllpty}‚ztojfhkmpsqomkhhnsx}ƒ…‡ˆ‰ŠŒŒŒŒŒŒ‹Š‰ˆ‡ˆˆˆˆˆˆ–ž¦­±±±±±±±±±±±²³´µ¶·º¼¾À¿¶®¦•œ¢¨®´¶¶µµ´³¯«¦¢ §®µ¼ÁÁÁÁÁÁ½¸³®©¦¦¦¦¦¦¨ª«­¯¯«§¤ œžŸ¡¢£¦ª®²¶»¶°ª¤žœžŸŸ ž›š˜–’ŽŠ†‚†‰Œ““’’‘’”–˜š–ˆzuy}…Ї{tnjpw}ƒ‰‰ˆ†…ƒ|xsnjgda^\\aglrwz{}~}zxvtuvxyzxrmgb\dmv~‡‰‚{ungdb_\Z\ciou{upke`]\[ZYZZ[\]^_``abciou{~xrke__^]\\`dhmqqfZOD8:@EJOSWZ]`cdeffgeb^ZWSPNKIFHNTZ`fb^ZVSOLJGDBLU^gpof]ULEMT\dkkgd`\XUROLJMSY`fkpty~‚zvqljklnopjd]WPOV]dkrqonlkiihhgglpuy~‚‚ƒ„„‚€~|z{{{||}…ŠŽ’‘‹†{vtqoljmsy„ˆ‡…„‚€€€€€~~}}|||{{}ƒ‰•›˜“І…ˆŒ“—˜˜˜˜˜™š›œž¡£¦¨««©§¥£¢ž›˜”‘’–šž¢¤¢Ÿš˜›¢¨¯µ¼¼½½¾¾»·´°¬¨¨¨§§§©«­¯±±°¯¯®­°´¸¼ÀÀ¹²«¤ž¡£¥¨¨¨§§¦¦£ š–—›Ÿ¤¨¬©§¤¢Ÿœ™–“’–šŸ££Ÿœ˜•‘‘Šˆ…‚„‡‹Ž‘”•—˜šš”Žˆ‚{†”›ž–ކ~wvwxz{|~ƒ„|yvttttttsrqqpnkhda^]\[[ZYWUSQPSVX[]_`abccba`^]^^^__^^^]]][ZXVTRQOMLJLNQSVVQMIEABEHJMPV[aglllkjjifda^\`dimqqmhd`\_acfhgc_[WSZ`gmsx{~…†wog`bkt}†ŒŒŒŒŒŒŠ†ƒ€}|~ƒ…woh`\dksz‚€}zwtqqponnu~†—™ˆ€xppqrrsuz„‰Žˆ‚|wqpsvy|~{ywusqomkiilnqtwtoic^XUROLJR^kx…ŒreXJMV_gpwz|„ysnhcccbbb^[WSOQ[fpz„„ƒ‚‚}vnf_WZ\_bdir{ƒŒ”Œ…~wposvz}ƒ…‡‰ŒŽ‘ŽŒ‹Š‰ˆ‡…„{wrnortwz|}€‚ƒ„†‡ˆŠˆƒzupswz~€ztngap€ °¶¯©¢›•—™›ŸŸžœ›™˜–•“‘“•—™›žŸ¡¢£¥¡›”Žˆ„‰’–››››šš™™™˜˜˜”Œ‡ƒ‚ˆŽ“™Ÿ£¦ª­°¯¥œ“‰€„Š•›œš™˜—ž¥­´»º°§“‰‹‘“–™œŸ¢£Ÿš•‹Š‹‹ŒŽ“™ž¤©£—Š~qir{„–—–”’‘‘’”•—˜™™™™™˜”Œˆ„Œ•ž§°´®¨¢›•‹…€{{‡”š–‘ˆ„…‹’˜ž¤ž˜’Œ†ƒ‚€~~„‹’™ŸŸœ˜”Œ†€zuopuy}‚„€}yurrrsttuuvwxxˆ‘›¤§Ÿ—‡€€€~}||yvsplnsy„Š„ysnlmmnooqsuwy{}~€}{ywxyz{|{wsokghlorux{}€ƒ†‚~yupnrvz~‚~xrmgb_][XV\dkrz|wrmhcefhikmprux{ywusqsw|€…‰Œ‘”–’Š‚zrlqv{€……‚{xuuttssrqqponkheb_gq{†•‹€vlaelsz€„|zwxyz{|}}~€€ƒ†ˆ‹ŽŽŽŽŽŽŽŒ‹Š‰‹”˜œ ¢£¤¦§¥£¡Ÿš—•’ŒŽ’•™¡£¦¨ª­¬««ª©ª¬­¯±³®¦Ÿ˜‘‹‰†„‡’§²·°©£œ–”“’’‘“˜¡¦«¨¤¡žš›Ÿ¢¦ª­¨¤ ›—••••••“’‘Ž“•˜›œ–Š„~~…ˆ‹ŒŠ‰‡…ƒ‚€}||‚ˆ“™–’މ…|zwuwz|~€{vqlghijjklmoprsqnljhhhiijjmoqsuutrqpnid_YTXaku~†xk^PCCKRZbgffedcdefhihb]WRLQYaiquoid^X^fnv~|vqlfilnqtttsrqqlhc^YX[]`bdccbbbceghjlnqsvxvpkf`]afjnsqlhc^\_adgjloqtvwsokgdfjnrvz€‡”š‘…ynb[[[[[[bjqy†‡ˆ‰‰Šˆ…ƒ€€€~|zxvvxy{|~…Œ”›¢ ˜‡y|ƒ†‰’–šŸ ˜‡vy€‡Ž•™–“‘Ž‹ŠŠŠŠŠŒ’™Ÿ¥«©¥¢ž›˜•’Œ‰Ž’—œ¡¢ Ÿ›š—”‘Ž‹ŠŠŠŠŠŠ‰ˆ‡‡†‡ˆ‰Š‹‹Š‰ˆ†…ˆ‘–š™•’ŽŠ’—¢¥ œ˜“Œ‹‰ˆ‰‘”˜œ–ކ~vrrrsssuvxy{}„ˆŒ‘“”•–”‹‡ƒƒ‡‹““Šˆ…‚|yvwz}€ƒ‡‰ŒŽ‘“Žƒyoe]hr|†‘‘Œˆ„{zxvustttttuvwyz{}~€‚‚€€~xqjc\Z_dhmromkhfdccbaadfilnmkheb`__^^^bjqy€†€ztnheca`^^chmrxwvtsqonmkjiknpruutssrqstvxy|ƒ†ŠŽŠ‡ƒ{zz{|}}yuplhgikmoprtuwy{}€‚…‡„~{xz€…‹””““’’Œ‰†‚ˆŽ”›¡ œ—“’•—š—“‹‡‡Ž”›¡¨¦£ š–“‹ˆ„‡‹’–˜˜˜˜˜˜”Œ‰……‡ŠŒ‘’“”•–••••••’Šˆ‰‹‘“““”””“‘ŽŒŠˆ…ƒ~†Š“•“’ŽŒ‰…}yx|ƒ†Šˆ‡…„ƒƒ„†‡‰Š‹‹ŒŒŒ‹ˆ†„ztoidcgjnrurpmjhjosx}€~|{ywusqooqtwz|‚„‡‰Šƒ|uohjoty}€}zwtqu{€†‹Ž‹‰†„}yuqmmquy~‚|yvssuwyz|xtpmiks|„•Œƒzqhglqv{~{xurooqstvxz}‚„ƒ€~{yxxyyzz|~ƒ††…„‚€|vqlfddddddiou{€‚|vpjdhmqv{|{{zyyvsqnkiiihhhpx‡Žˆ‚|vqtx{~‚‚€~„‰Ž“˜•‘Œ‡‚‚†‰ŽŒ‹‰‡†„…†‡‰Š‹ŒŽ‘’‘ŽŒŒ‹‹Š‰‰ˆˆˆˆˆˆˆˆŒ‘•šžŸŸžžš—•’‘•™œ ¢¡ ŸœŸ¡¢¤¤£¢¡ Ÿžœ›™šŸ¤¨­²®¨¡›•ŽŒŒŽ‘”–™™•‘ŽŠ†‰”—–‰ƒ|uwz|~€‚‚‚‚‚‚ˆ“˜œ–ˆ{xurpmou{‡‹‡‚~ytrrrqqrux{~ƒƒƒƒƒzskd]`flrx{{{zzzupjd_]`dgkoqtvy{{zyxwvrolheddeeffeddccfkpuz~€‚„†ˆ…€{upkkjihgiloqturpmjghjklmoprsuvtqomjjkllmnrw{€„…ysmhjloruwz}‚„|zwutsrqqonlkihgfedchlquy}ƒ……‚|yvvvwwxy}„ˆŒŠ…€|wu{€…ŠŒ‡‚}wuy}…‰‰‰‰‰‰ˆ…‚}z{}~€„†ˆ‹Š‡„€}}}}}}}€ƒ†‰ŒŒ‹Š‰ˆ‡ƒ~ytopv{€†‰†ƒ~{}„ˆŒŽŒ‹‰ˆˆˆˆˆˆ‡‡†…„„†‰‹Ž‘Šƒ}vpqrtuvx{~„‡‡‡‡‡‡†††………ƒ€~|zz}ƒ…„„„„„………††‡ˆ‰ŠŒ‰„~xsoprstvz‡Ž”˜’Œ‡{}€ƒ‡Š‹†|wrsvxz}ƒ‡ŠŽ’ˆƒ}xw|†Œ‘ŽŒ‰‡„‚}{ywy{}ƒ†ˆŠŒŽˆ‚|vppsux{~ƒ‰”š˜‘Šƒ}vusrqorvz}…†‡ˆ‰ŠŠŠŠŠŠ‹ŒŽ‘“Š…zy€ˆ–š—“‹ˆˆˆˆˆˆŠ‹ŽŽŽŒŒŠˆ‡…ƒ…ŠŽ’–š•‘Œ‡ƒƒ…ˆŠŽŽŽŽŽŽ‹‰ˆ†„„ƒ‚€‚†‰ŒŒ‰…~~€‚ƒ‚‚‚‚‚‚ƒ„…†‡ˆŠŒ‘“”•–˜•Œƒ{rjou|‚‰Ž‘‘“•–˜š–‡€xqw}‚ˆŽ‹‰‡…}yuqsx|…ˆ…‚}zzzzzzyyyyyy{}‚„„|zwxy{|}~€‚ƒ„†ˆŠŒŽ‰†‚~z{{{{{xsnid_beilooonnmmnnnnnoqstvvusqomljigffiknqssssrrqoljhejry€‡Š„~xrlkkkkklnoqstx}†‹‰~sh^SYaipx{zyxwvqmhd_]]]]]]cintz{ywvttuvwxyxwvutuwxz|~|zwurrux{~}wqlfdinty~~~}}}|{zxwvy|€ƒ††ƒ€|yvusrqpqrstuuwy{}~~}|}~€‚„†‡ˆŠ‹ŒŽ’”–™–“Œ‰‡‰ŒŽ‘”‘Ž‹ˆ…„†ˆŠŒŽŽŽŽŽŽ‘’’““”””’ˆƒ~y|‚…‰‹‘“•–––––”Œˆ„€„‡‹Ž’’ŽŒŠ‰‰‰‰‰‰Œ‘—œ¡¤œ•…~~…‰Œ•šŸ¤©£™…|v}…Œ”›žžžžžœ”…~vy~‚‡‹‰„zvtvxz{}~€‚ƒ‚‚‚‚‚‚€€€~~‚†Š‘Іƒ‚ƒ„…‡ˆ†„‚€}}}~~~|{yxvusrpopqrtuvxz|~€~|zywwyz|~}|{zxyyyzzz{|}}~}{ywutvwyz|{zzyxyyyyyyxwwvuvwxy{|}€‚‚~|{}‚„‡‡‚~zvrpppppqsuxz|zxusqrvz~ƒ‡‚}wrmkmnprsuvxy{|}}~|zwustvxz|}}}}}}~~~~~€€‚ƒ„„„……„ƒ~|zwtqoosx}‚†„€|xtqponmlqv{€…‡„~|yz{{||||||||~€‚„…„‚|yw}‚ˆ““‹ˆ„‚ƒ„…†‡‹‘—ž¤¨¢—‘Œ‰‰ˆˆ‡ˆ‹“–“Œˆ„€€€‚…ˆŠ‘’’““”••”“’‘‘“–˜›žžœ›™—–˜™š›œš—”‘ŽŒŒŒŒ‹‹ŒŒŒŒŒŒŽ’”——“Œˆ…†‡‰‹‰†‚~{}€„‡‹ŒŠˆ†„‚ƒƒ„……„}zxyz{|}|||{{{|}~~}|{zyxxxwwwyz{}~}|{zyxvsqnlmptwz{{{zzzxvsqnnoopqrqpomlkigfdbehknpqpomlklmmnnopqrstuwxyz{~€‚„†€ztnhgiknpsstuuvwwwxxwwwwwwurnkhghhijkosx}‚„€}yurnkhda`dhkosuvxz{zwtqmjmpsvz|||}}}ytpkghntz€†„‚€~||}}~|yuqmknqux{}€‚ƒƒ€~|z{{|}}~ƒˆŒ‘•“Œ‰…‚€~|zxz}„†ˆ‰‹ŽŒŒ‹‹Œ‘“•—”’‹‰ˆ‡†……‰‘•™˜–”‘Ž‘“•—”‘І„…‡‰‹“–™žš—“Œ‹‹‹‹‹ŒŽ’”–’‰„~ƒˆ’––•””“’‘ŽŒ‹ŠŠ‰‰Š’•—“ŽŠ†‚‚ƒ„…†„ƒ€~…Š“–“‹ˆ„‚€~}{{}‚„‡…~{xwy{}€‚€€€€€€€€}zvsppu{€…Їƒ~zutttuuuvwxyz{{{{{{yxvusuwy|~€~}|zywtrolkmortvvuutsrqponmnoopqrstuvwxyz{|{ywvtrsssssrpnmkiklmnpqtvy|~{xuqnotx|…„ƒ‚‚}{xvtwz}‚‚‚€€€€€€€~~}~€‚„†ˆ‰Š‹ŒŽ‹Šˆ†„ƒƒ‚‚…ˆ‹Ž‘ŽŒ‹‹‹ŠŠŠˆ†ƒ€ƒ‡‹Ž’‹ˆ†„ƒƒ‚„†‰ŒŽ‰…}zˆŽ•›œ™–“‹ˆ…‚€ƒ†ˆŠ‹‰ˆ†„‚€~|zwx~„‹‘˜–“Ї‡‡†††‡ˆ‰Š‹Š‡…ƒ€~ƒ†ˆ‹Š‡ƒ|x|€„‡‹‹‰†„€‚‚ƒ‚‚€}zwurtx|€…‡†„‚|xtpljnrvz~ƒ†ˆ‹‹‡ƒ{wwwxyyxwvutsuwy{}}}}|||zwurpqtwz}€~}{zxyyyyyyvrolikpty~ƒƒ„……†ƒ{wrpuy~ƒˆˆ†…„ƒ}{ywy|~ƒ„€}yvrux{‚ƒ}{yvtqnkkmprtvy{~€ƒ………………„ƒ‚€~~}}}}}}}|{zyxyz|~€‚€€~€‚ƒ}{xxxxyyyxxxwwvvvuuutttttv|ƒ‰•’‹‡ƒƒ†Š‘”‘Ї„ƒ…†ˆŠ‹ˆ…‚||}~€€€~}|}}~€€~|zxvxz}‚‚€~|{yxxz|ƒ„…††‡†ƒ€~{xvtrqopv{€…‹‰‡†„ƒ}{yxwwvvvwy{}€‚‚‚€~|zxxz|~€‚ƒƒƒ„„ƒƒ‚‚‚‚‚‚‚ƒƒƒ„„„„„„„„ƒ}{y|‚„‡ˆˆˆ‡‡‡„€}yvuvwxxy{}‚„„„„„„……†††…„‚€€‚‚ƒ…‡ŠŒŽŒŠˆ†…ƒ‚€€ƒ„†‡ˆŠ‹Œˆƒ~zux}‚‡Œ‹ˆ…‚‚…‰Œ’ŽŒ‹‰‰‰Š‹ŒŒŽ‘ŽŠˆ†„‚‚ƒ„…†‡…‚€~|{{zzyzz{||}~~~~~€‚ƒ„„„„„„ƒ‚€~€€‚€€}|zxwutsrqpuz€…‹Œ‡‚}xsuvxy{|||}}}~~~~~}{zxwuuttsstvxz||yurnkmptwz|{yxvuuuuuuvwy{|~|zywuuxz}‚€~|zxxz{}€~{ywuuwy{|~{xuqnoqtwz|zxwusuwy{}~}|{yxwusrppqsuvx{~‚…ˆŠ…€|wrrtuwxz|ƒ†‡‡ˆ‰‰ˆ‡…„‚€~}|z{{{{{{|}}~~€‚‚ƒ„…††‡†„‚€~}…‰‘‘Іƒ‚‚‚„ˆ‹Ž‘“‰†ƒ€€„‡ŠŽŒ‹‰‰‰ˆˆˆ‹Ž“–—”‘Ž‹ˆˆˆˆˆˆ‰‰Š‹ŒŒŽ’”––••”““‘‹‰‰Š‹Œ‘’“’ŒŠˆ…‚}ƒ‡‹“”•–—˜•’ŽŠ‡…ˆ‹Ž‘”‘‹†€{x}‚‡‹Ž‹ˆ…‚‚ƒ„…†…„ƒ‚€€~}}{zyxvwy{}€‚‚‚ƒ„…†‡‡…ƒ|{{zzyzz{|}~}}}}}|{ywvtuwxz{}~€‚€~}|{zxwvx{}‚‚€~{ywyz{|~}zxurpsvx{~~~~}}}{zyxwxyz{|}}}}}}|zxvtttuvvwwwwwwxz{}‚ƒƒ„…„€|xtppqrstuy}€„ˆ„{vrpqrstuwxz{}||{{zz{|}~~}|{zy{|}€‚‚ƒ„„‚€~|zxvttuvwyz{{{||{{{{{{{{{{{|€ƒ‡ŠŒ‰‡…‚€}|zyz{|}~€‚ƒ„ƒƒƒƒƒ‚‚‚‚„…†‡†…ƒ‚€~~}}~€‚ƒLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/knurk.wav0000644000175000017500000000333413263212010020775 0ustar aeglosaeglosRIFFÔWAVEfmt "V"Vdata^†ˆŠŠ‡„{xyz{|}~‚„„„ƒ‚€€€ƒˆˆ}rh`Zo„•¤›‡sg\Ual{¤³ÀÌ¢uOKGN`r|‚‡”¡«®°¤ŒtmkgL1'C_§ÌÙáåͶ”`- )KnšÅáèï׳ŽjF(!&C`¼ÅÏÑ´£ŽzjZKIGJT^jv‚™£¨­®ª§‘„wi]WPPTXbnz…˜Ÿ¥¦£ š“Œ„}vpkhhhlosw{~„†‰Œ‹‡„zvtssvx{}‚„†‰‰ˆ‡…~|zyz{|}€ƒ……„‚€}{z{|{{{{{{|}~~~‚…‡‡‡„}{yyyz|~€‚…‡‡‡†ƒ€~}{yyzz|~‚„†ˆ‡…„€|xvttuvx{~€ƒ……†…„ƒ‚€}zzz{}‚…ˆ‹‰ˆ‡…ƒ€~|{zz{|{zyz{|~€‚ƒ„ƒ~|{|}|||}€‚„†‡‡†…„ƒ}{yxwxyz|~„‡‰ˆ‡…~xtsq…°œˆqT6Ac„Ÿ¹Ë³œ†q\TRPTX`tˆ¢ÂáÖ¾¥xK-15@Se„§ÇÑÛÖ¸š|]?979Oex‰šŸŸŸš•‰†‚~ysnjggkou}…‰ŒŽ‹Šˆƒzwtqnkmprw|†ŒŽŒ‹…€{wsqporux|€„†ˆˆˆˆ‰Š‰ˆ†„€|yvsuvxz|ƒ‡‡‡‡„‚~}{zyxxyyz|~…ˆ‰‰ˆ†ƒ€}zxwwxz{}€‚…ˆ‰‰‰‡„‚}yvuuvwx|€„†ˆ‡…ƒ‚~}{zyyxwxz}€‚„…‡‡‡†…ƒ|{zyz{|~€ƒ„…†…„ƒ€}yuvvwy{}}~…‰ˆˆ‡…ƒ~|ywyz{|~€ƒ‡ˆ‰Š‡…‚}xutsvz~€‚„„…†‡ˆ†…ƒ€}{ywy|~~~~‚ƒ…‡‡‡‡…‚}{{{|{zz}€ƒ…‡‡†„ƒ‚}{zxxxxz}‚ƒ…‡†„‚€~|zyxxxy{}€‚ƒ„„„„ƒ‚‚€~|{yyyy{~ƒ„††‡†„ƒ~|{yyxz|€€€€€~~}}}}}|{yz|}€‚…ˆˆ‡†„~|zzzz{}‚„„ƒ‚€€~|yyxyyz|ƒ…‡‡ˆ‡†…ƒ|zxxxyyy{~€ƒ…………„‚€~|zyxxy{~‚†‡ˆˆ†„‚€~}||||{yxxyy|€ƒ…‡‡†…ƒ€|zyyyz}ˆ“Ž{iilp…š¦¡œŽye[RN`r…›±¶³±‹cA@>Qy¢¦•†ƒˆŽŒ„}xsnZF@Thž¼ËØàÆ«ˆT!;a†©ÌâåèЮ‹gD&;Xy›¾ÉÔØË¾ªvaN<<JUdw‰—£­¬ª¥šŽ„yojedoz€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/kling.wav0000644000175000017500000001023413263212010020744 0ustar aeglosaeglosRIFF”WAVEfmt "V"Vdata{|||{zzz{{zzzywtrpnljjmpvŒ‘“”ŽˆxoeZNNV^kzˆ†ƒwoowŠ• —Ž…|sqsvxyzvronlnsw|€…‰Ž‹‡}tnjgilljifa\aiq¡¤¥¤¢˜‡wcO?GNWblnljjjl…ž³ÃÓȪŒu_LQVZZ[WOHNW`ž·¾ÆÂ´§š€reYSMIFCIPWbmy‡–¥µÅ¾¯ ‘‚tlc[SKD=666<^€œ±ÆÅ¹­£š‘ˆ€rdP8 %,6WwŽ”š–Ž†–Ÿ¯¿Â­™€dGIOValssstuu~Š•¥¦œ‘‡~tle^\Z\eouy}zvrx}…”£¥›‘|aGKOUgx~xqfYK\m€—­³£“o\hw„Ž˜–‚o`SFTds|†ˆzwvv‰“”–“Š‚|wrqponlkifhiknrv|‚ˆ–’ˆ~rf\biotztfXNF?[w‘¢´² Žƒzr~Š‘Š|cJCCC\uŠ•“Š‚„ˆŒ—£©œŽ}gRMPSZahknqtv~ˆ’›£¨ž”Š€ukbXRMJRY_ejnru{‚‰”Ÿ¤ž™Œyga_^gosmh_SGTfx‘ª¸«žŽ}lpz…™š„o[K:F\qŽ–„~{x€Š”••’„ujd]\^_behkoruxz}€ƒ‡ŠƒymaTY^dkrsnida]m‘ž¬® ‘…|rv{~|udTNPQdz–œ“Їˆ‰—„u^HBHNZhuwy{{{…Œ’˜’‡|rh`[VSRQ[ent{‚„‡Š–™“‚o]VTS_lxxxuoioz…–©¶©zfciov~„yne\T[l}Š—¡—…~xx|}|zncZWTYblrw||}~€ƒ„ƒ‚~|ytnhaZ^elu}‚~zwsov€‹“š}pf\alw{€tibbbn€’–™™‹~uttzƒŒ‡€yiYQV[eq~~~}zww}‚ˆŽ”„{sjdb_^]]dksy~ƒ…‡‰‹‘‘ˆ€p`WUS[fptwxvtx‰•£°¤˜Šwc[_cjqytoid^bq€Œ˜£˜‹~uljpvz{}umec`bjrx{~{yxxxy{}|||zxusqoljlpu{†ƒ}zvx~ƒˆŒ…{rkdfpy„ˆ~tlifkwƒˆ‹‚xooot}†…ƒ€th`cejs|}}}zwvz}‚‡‰‚{tlgghijjmrvz}ƒ„†‡‰Š‹‹‡„ujc`^bjrvxyxvw}‚Š”Ÿ˜‡vf\_bgovtqmhbcq€š§ “‡|rlortuupica`bny‚ˆŽŠˆ…ƒ€}{xuqlhhhikmqv{‡Š‡„zxz{|~xpha[[fqz‚Š…~wtqt}‡‹Ž„xljgir{€€€yqkmpt~‡‰†ƒ|tnpsw}ƒƒ{wrmpsuxzywtrqpuy}€ƒ„„„‚€~xrlifgjmoqrqpqw|ƒ–•‹rhhhjotspmhcanzˆ–¥¢–‰tlosvxzumea^\jw‚‰‹†ƒ~zwrlfeefjnsw{~‚†„ƒ‚|zxvutsplhd`_hrzˆ‡ƒ|zz~‚„„„}shfcdoy€ƒ…€yqsux€‰Œ‰…}rhjlov}|ytoinsx~„…|xtprtvwxxwvuttttuuvwy{zzzwtstvy…†„{skmorx~{wpiblv€™›‘ˆ}shmrvz}{rid_[gt€‡Žˆ‚}zwy{{ywskcbccjqx{‚ƒ…„ƒ‚€~{zxvtqolifcbks|„ŒŒˆƒ€}{„ˆˆˆuic^Yeq|€„‚|vwyzƒŒ’‰€qcabcktyyxvrorx}„‹ˆ‚zskloruwxvusrrtuwy{}}}|{zxtqrsty€{uoqsv~…ˆ„€ypgkrx‚Œˆvj_fp{„ƒwmd[bmx†ˆ€xsqnsz€‚ƒyqljimrwz|~~~}|{zxwvtspnlignv~†Ž‰ƒ}xrv{ƒ€wnheakv€„‰‡~uqppx‚‰‡„qd`bdmw~}ztnouz‚Š‘‹„}umkmprtvvvwwwy{~€‚„†‡†„‚~wpljhou{|~|wstwy‰Ž‰„|pedgkt}ƒ~yrjbeoxƒ”ˆ|qg]`jt{‚‡€xrolpw~‚„…zusqswz{|{zxvvuvwwxy{|~~zwsokmqu{ƒ~ytplqy€…Š‹sib[amy…‡vqppwŒ‹‰†yldddkv€€€yrqtw}„‹‡ƒ~wpmnprtvwwxxxyyyz{{}}wqnljou|}~}xrqst|…ŽŠ†€thdfipy‚~zumfgpy„œ‘†{pebhotzzupnmqz„‹”…~zussssssrqrsuvy{~€‚„††|vohhkotz~ytoicgr|†—Œvnfhpx}ƒzpigekwƒ‰ŒŽ„zrqpt|„„‚xojmot|„„ƒ‚~zwwvvvvvvvutttttttwz}~€ysolimtz|}}wqoopv~‡†ƒujdgjr|‡„€|rhelt~‰•ˆtiemu|„Œ‡wrmksz€…‰†‚~{xuutsssrqqqqrsuwz}€„ˆƒ~yqhfilqw~zuqkegr}‰•¡•‡zod`hpw|zrjhfjx…‘–ƒyvssy~}|umghjnu|€‚ƒ‚~~~|yurokjhfecgow~…‹†}zwx{~}|ria`_er„†‡~vprtz„މ„xlchmu€‹Šƒ}tkdls{ƒŒ‹…ztqtx{}|xtqonopqsuwz}||{wsrrsv{}zwpheims|„‚~{sljrz„š”ˆ}qf`ir{ˆ‚xojffs‰•†|wsquyzyxsmfhilt|ƒ…„‚|zxvtrponmljihfjs}…”އztsy~‚ƒyma_\`p‰’ŠvvvyƒŽˆƒvgY]`ep|€~zuqw|‚ˆŽ†wnfhjlnoqstuwxy{|}€‚ƒ‚€yrlllouz{zyslhmqxƒŽ‹‡unsw}…Š€vj^Tanz„ކ}wqmv~†‰ˆ}smifkqvxzxtpqrrw{ƒ‚‚‚|ytpnnnoqsqomjghs~‰•¡›„zpiouz|xmc_[\m~‹‘—’‰{xw}ƒ…|sg[\_bmx€€|y|~…‰‰ƒ~xqkihffeglqvz~~}~~~‚……ƒ‚yoda^`isz|~zuqvz€‹•˜’‹€qbehlt}~xrkc[fr}‰•˜ƒzqimrwz}{unjgdjpvz~~}}}|{zzzzzzxurnjhlpv}…†‚ztou{‚‰‘Ž„yof]gpx†„zqkgco{†‹‘Ž…|wtqvz|zxri`_bdnw€‚„„‚€ƒ„„ztmgfffghipv}‚ˆˆ†„‚€€€€}{vnfca`jt|‚€|x{}€‰‘•Š€qb`acjqusqnjfmwŽ›¡—ƒxnnopqqpmkihhmsy~ƒ‡ˆ‰ˆ†„yrpnnpqqqqoljnsx€ˆ‹‡„~wosvz€††}ulbX`jt}…‡{vsou|ƒ†ˆ‡vqmjnrwxywtppqqv{€}{yyyzzzxwvusrqponmsy„ŠŠ†‚~{xz|||{wofa^[fq{€……€{{{{‡‹‡‚{oc`bckszzzxvsv{ˆ”†vmklmnooooppquz€…‰‹‹‹Š‡„wokhfhkmnppppuzˆ”‹ƒynjjjmpqnliebhr|…”‡€{uw{~xqkheipx|||||ƒ‡…„‚|vqpnoooqrtuwyyzzzz|~€‚{upkgjotwzzvrponsz€ƒ††{xwvz~‚€~{slijjou{|}|zyz}€…Љƒ}vnkkklmmortvy|‚…‡‰‡„‚|xrmigeilpqstttvz}‚ˆŒ‰†‚{sonnpqqpnlifjr{„•Š„~xwy{|}}vpkhehow|…„ƒ‚‚€}zxtpllkloqsuwz}~~~}{z{{{|}|xsojfinsx||yvusw}ƒ†ˆ‰zspmosxyzzwtsuw{€††…ƒzxxxz|~{xuqmknpsvzzzzzz{{|}}}|{{yxvrnljiloruwz{}~ƒ†‰Œ‰…yqlkknqtttsrpsy€‡–‘Š„|tqrstuuqmigegnuz………„ƒ‚}{wtplggfgjmquy}‚‡‡‡†…ƒ~zwspmjhecfmtz‡„‚€~}~€ƒƒƒƒ|vpmjkpuxz|zwwxy{‚‚€|wssrstvutsqooqsvy}~~~}}|{zyxvutsrqrrrstuwy|}~~|ywwwy|€~~zvuuuwz}|{{xvvy|€„‰‡ƒzurrstuvtqomllqw{‚~|zxvusqponmnoprtvy{~‚…„‚~{xxwwwwuspnklqv|‚‡†„‚€€€€~~xrkhddhmqtxyz{}~€‚€}zuoihghknprsuvwy{}€‚‚}{xutrqqpqrrsttuvwxyz}€~{xwuvvwvuusrrstvy||{{xuttuvy{zxvspoprtwyywusrrtwy{}}|{zyyyyxxwusponnqsuwy|~~|zwtropppqstvxz}~~}}|{zxvspnkknqtwyzzz{|}~~}{xuqonnopqrstuvxz}‚‚€~|yutsqpopqstvwy{}€€€~}|zwusrrsuvvvvvvxyz|}}||zxvvvwwwvuutrqstvxy{{{{{{{{{{{zxutrqsuxy{{{{|||}}|||{zyxxxyzyyyxwuuuuvvvLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/zisch.wav0000644000175000017500000004023413263212010020763 0ustar aeglosaeglosRIFF”@WAVEfmt "V"Vdata@€€€€{vx†”€orz€€€ƒŠ‹}o{‹—ˆxr|‡ˆ„€~|{}€€€‚†‰„{}}vowˆ˜Šwhsƒ|ux€ˆxqrsuzƒˆŒˆƒ€€€~ytv{€‡”…vr|‡ˆ„€€€…‰„tdl~‘ŽŠ|nn€“|jy‹—‰{qlgs†™‘‡~wqsŠ|o‚˜¥‡j_n|‡™Šzp{‡ˆvw{€‰“—‰zromw…“‹‡zuqnz‹„{}}ytuxz†‘—Š|utsw|€…Š‹„}xvszƒŒ‡ƒ€€€|unx†“Œ…ƒ…€uiu‡™‹~x‚ŒˆyiqŒˆƒ‚ˆŽ†ucq‡œ~uz~„‹’ˆzn‘˜†urz‚„……„ƒ}y{‡ƒ~{ƒ‹Œ~qs€Œ†~w~……|rw…”‹~ty}ƒŠ‘‡r]rŽ¥‘}qtv|„‹Šˆ…|ssƒ“Ž{h}—«tgr|†˜t{‚‚yow‰›Ž~qw}}xrw‚Œ„{rpnqzƒˆŠŒˆƒzurom{¥–ƒslfl‚™—‰{}vlp‰¡š…pt{€€€€€€€€€‡Žxbcƒ£›goy€€€{riz–³’oWqŠ”‹‚‚„†xtz€€€„‰†ytou…•”‰up{†‰…„‰ƒzrpnv‡™”ˆ}yusssx‚‹Œ‹‹€uov}ƒˆŒŠ‡„{sr‚’‘qx„„xqrs}¢—…tx}}sjr‰Ÿ˜ˆzzz{}€€€€€‚„‚{sv€Š‰†ƒ~yuts{‰—€tvy|€…ƒz€†Štq}‰‰‚{~‚…{rpyƒˆŠŒ„{sssvˆ„zozˆ’†zv{‚€{vt‹Œ|lo}Œˆ„}{{}€}xsx|xqsˆ€ysox‡ˆˆ†ƒ€yrnprwЉƒ}wqp}‹‰‚|xssssssy…’Žƒwz~~tkpˆ ˜ƒms{zuzˆ–‚sx}~ysv‹†€…‰‰{mr‹¥›…nt{€€€|uo{ “‡{ups€ŒŠƒ}ˆ’•‚okt~‹˜¦wj{‹Œ~qt|„…†ƒ{sw…“Š{m|‹’†{x|€€€‡Š€ux~ƒ‚…ˆ‡„€|wt}‡Š€wx‹ƒwn“™„omx„Œ“˜…sjw„Š‹Œ‚wn~Ž”„tw‡—‘†|zwx{ˆ”¡zhxˆŽ‚utz€£°ŒgYt”Š|xvz~‚€}~€zvtuw~ˆ’Š€x}‚~z{~€‡‘ƒuuˆœ“zbn‹‚xuz~~…†„}wrv‰†‚†‹ˆ~sonmƒš§‡ga”y^mŒ‡‚ƒ…€zsx}zu{‹›‹mOhƒ—‰…‚€€€€yrrˆžœ}^dxŒŒ‰~ss~ЋЉxf`|˜›„ljot|ƒ‡„€€€€€€yrr„——„rsz€€€{x|†Š€wutuy~€€€€€yrp|‡‰…€€{vuz~€€€ˆ‘˜ˆxq|‡‰…€€€€€€}sjq…™‘ƒutssssv{€ˆ—‡wou{ƒ˜‹{nu}‚„†€wn€–§†eXt”‹zso„™›}_eƒ¡r\s‹”…vsvz|Š’{ggsˆ‘—‡wqzƒƒ€}€„…~wv{‚€ysqФ¤Zbƒ¤‘zhq{„–‡kOgƒ—„qjt}€€€n[Sxž¥^_r…xty~ƒŠ‘‡wgq}ˆ–’‚ry‰™ˆuiw†”˜ˆqZgu‚Бހrsz€{vu|„ƒ|vx|€{vv‚ˆ„ˆŒwc[¢£[f€š‡tir|„‹’ˆzm}•…ux¡”}fuƒ‹‡‚€€€€€yrpz…Š‹Œƒxny„‹‡ƒ€€|wt|„ˆ…ƒ€€|wrqos…–’~jnw€€€}z|~€‚„…|sr€Ž†~~†Šˆ{nsƒ”‡€€€|pdpŒ¨œŠytppx†Œ“‰}uƒ‘{dh|‘Œˆ~usz‚€€€„‡†x|„Œˆ‚‚…„€{|~€Š•›Œ|v}„„‚€„ˆŠƒ}{}€€€†…yuz€€€€€‚‹”’‚rxˆ˜Š{q€ŽŽ}ks†˜Šzoz…‰…{tm–¡…h`n|€€€yrp~ŒŒ~qqvzˆŠ€vt{‚€}zƒ…ƒ}ytw|€€€~wptƒ’ˆwf~• †ki•Žpv|ƒŒ•‘qmmm{ˆ“““Œ~pptvtqvŠžšƒkhkn~Ž—‰ƒ}xz}xquާ£‡knw{vx†”‘€pszxquަ¢‡lkou‡š¡“†~zwsomy…Ž“˜Žzfp‹}om€“€ppru…–›Ž‚zwsw||x}Ž —}bjv€€€}vo}—±“mPq’¡’‚zws}‡Ž„yxƒŽŠ}qv{ˆrx‰š‰vhw…‰vw{€€€zuqlgw‘«˜‚onmx’¬¡…it‚‹xrom{¥’~ou{~~~‚ˆ†{}‚ƒ‚€ysq|†‰‚{Š“ˆ~wxz‰”‹}ny…‹‡‚}yt}‹™‰ypy‚„‚€€€€ƒ††ƒ€€€‡™‰yqŽ‚v{…އ~€}xtw|‰’”‡yv{„ˆ‹‚yuz~ƒ‡Œ…}w‡Š€wqom~“¥vjv‚{tx}€yqq‚’€p|ž…mbt†‹‰†€ytvy~‰•optx€‡Š†~|z~‚„ƒ‚wot€Œ…{ty}€€€€€€€€xqsƒ’…yz{}~€‚†‹…zox„‹vrvz€†€rhw…Š…~~~€zuuz…Œ“†xp€’‚rry€{vu‰‰€vw{€€€€€€„†€xpv|†Š‰„~~€ƒ……ƒ|unu„zty~…Ž—Žptx}ˆ“sYj‹¬”zir{}ytz„‚voqsz†“‹|m~Ž•‚ohjmš´ŽhV|¡¢€]l‰¦…eVyœŸ†lvŒŸŠuir|€€€‚„…|ss‡›˜kuˆ™j`x’„v{„Œ~pky‡Š…€xoh‚›£…fh‚›ygu„‹†‚|vqu{ƒ…ƒ|uy‚ŒŒŒŠ}oo‡ ›‚jr€Œwqqq|¢‘zh{“ƒsz£Žr[jz†‹‘‹~qw…|ss~‰‰„}{{}~{x|„Œ‚xqy…‚€…Œ“„thu‚‡ƒ€€€€xqtƒ‘Œqtw{}‚‡‹…|s|…ŠtsŠŠ†‚zsqƒ–šŒ~|~€ƒ††|sry†‰Œvov}€€€€€€vmj}•Œ‚€€€€€~wpu†–“‰€vmm‰¦¤ƒak‚šŠznnntŠvosw|„Œ‰„€yrq‘Ž|juˆ™‰yoqs{ˆ–Œ|n€“˜ef~•Ž€t{‚ƒzqz‘¨’pRt•£‚ac‚¡”|gilr‚’€p€˜«ˆfXs’ƒuy€…|{{|‚†‰‚ummmx‹”†yvst}††‚~„…|xuqu}…Œ“–h`s†ŒŒŒ…}w{~‚…ˆ‚xn|Œ˜Š{rpnvŒŠˆ…zxyz|}†„yu|ƒƒ‚€{wv…•“zafyŒˆƒ~|xtw{€yrp‘’lkqw‹…yv|ƒ~vn€“œ|][{›–‚n{ˆ‘‡}z}€|ws}†Œ‡‚~zwz~‚€‚†‹†xit‡š‹{s}ˆ‡{p}’§ˆiZ{œžakƒš‹}uy~~zv~‰“…xq}ˆˆ~uw|€€€|n_j‹¬–qNo¡Ž|qom}‘£Œvjy‡‡~uw|€€€€€€~|z~‚…‚}}}ˆ‡|tx}‚†‹…zp}ž†oev†Š…€€€€€€}wpv„‘‰}ty}…˜ePu›¦ƒ`b|—‰vgqz€€€{tm{‹–‡yu‚ˆxhv‡•…€€€}xsssuŒ‰‚{tlwƒˆ~stz€‰’–ƒqp†–‚msz‚Žš˜…sw…’„siw…”˜‡mRi‚”Œ„€€€ypfxŠ–ˆzv|‚„…†xty~ƒ‡Œƒtfpy‚‹•‘qy‰™‡€€€‚„†‚}y{|„‰ˆ{~‚†xuy~ƒ‰„ufu„ˆ‚€€€|wsy{uv{|wrqorƒvw|€€€~wpv†—‹xgpzƒŒ•€pv‚‹€utˆ™‚juˆ˜ˆxq}ˆŠ…€€€€€€‚‡‹…wiz’¥vjs|‡‘œŠsawŒ•…vqrsœŠxq{……x}‚†††‚ypryˆ‘—‡wsƒ“Œwar‡˜Š|uz†˜Œu~‡ˆv{‡“ˆ{r~‰‡‚€€€„‰Š‚zy„ƒ€}~€€€€€€€‚„†~upv}„Œ”Œ}nw‚І‚}|€†‹€up€”Œ„|um|Œ–‰{w~„‚~z}ƒ…†††vmu~†Œ“‘‡|vqm}—ކ€€{uptx~‹™—…rrvz„”Žˆ‚{s{‡“„vnv}…˜‰t_uŠ—Ž„|unzŠ™†sir|…Ž—…kSs“¢„giˆ§•vZr‰–‡yv{„ˆ‹€us†™˜‰{†Œ…~{}€€€€ˆ‘—…rn…™‚jv‰™Š|uz~…Œ”†uhv„‹†}xs}ˆ‘†|wy|‰‘†yoz…І€€€€€‹”“ƒsw‡—‹{nv~…Šˆ{nxƒŒ‡‚}wpvŒ†€{}„†zs}‡Ž†~{~€‚„†}tp€”Š~€~|yxvz‚Їzywx{„†„‚€yrp|‰Š}qvƒ†{rqpvƒƒzxww{~€€€‚„†xty~~zvšŽwsou„’ˆ€}{ytpw‰œ{fyŒ•‚opƒ–Œyfpy€€€|un€™±ŽkYsŽ•‹‚zsnz‡Œ€trx†’|e\u•‹‚|wt{‚ƒ|uy„‹‚ywuw€‰Š…€„‰Œ„{uts{Š˜}oz†‰tu}…„‚zvuz„ˆŒ‚wo|ŠŠ„}un|Žœ‰uo“‘ƒuqnpФ§„`c€œŠp\v™†sr|…{phv„‹†}xsz€…‚†‹‰ƒ}xrq€“„uy…’€k]tŒ–…zvvvx€ˆ‹‰†zswz‰“‘‚ssy€€€€€€„Œ”€stuw‚Žƒxvww}‚…ƒ}yt}‹™‰yox‰—‹yfy‹–‡xqtv{€†ˆ‰†|rsЉ„€{vu|ƒ„‚€€€€„‡‡wv{†Ž–‡xpx„ƒ‚{x{~€€€}xtux{ˆŠ‚z{ˆwny„‰€wxŠƒxoy‚‰‰‰ƒyov‚‹‚ywƒŒ~ou~‡ˆ‰†~vw~…wqw|‚ˆ‰€vy}}{}…Œ†ztox‰—ow‚‹‚yw€Š‘“l\s‹•†xv{€zspyƒŠ‹Š…€yrnw€‰—o{‹—‡wt„”n|Œ—ƒok““‰zvv†——‚mp€ˆ€|‚‰‡yjmv€‰’–ƒpq‰¢”tToŽ£‹shmr}‹˜ŠzpŽŽ}khkm– €`^~ž“vZp‡˜Ž…€€€{tm}–‡xu}„€xpsv|Œ–xZg„¡Œvl†  †mmw€“¦«…_]~Ÿ•}fpy…ˆ†€{xus}†‰yx|€|wrpns†š–}djy…ƒ‚„†wqx„„„{v|„‹…~|‚‰…zp{‹™†tn‚—’{cq†™…€ƒ‡Œ„{tz€‚{|~€€€xqt†™‘x`l‰ƒ~}{}~€|wrpnu‰ž“uViƒ˜{}€€€€}~€€€€€€€{usŒ€spqs–‡xu‚ˆxgt„…{x|~|z}€€„†zsx}†Š‡|qv€‹…{}€‚„†~rft‚ŒŒŒ‡{py‰™ƒl^v•Œ‚{tmu}…ŠŒvtuu€‹‚tu…–Œyfpy‚‡Šwz€†xtx|}}}‡Œ‚yu‹zjqƒzrpnu…•}m~Ž•…upuy‚‹“Š€xxwy|€|wt‚”„tqy€€€€€€€|un~“¦Žvis|…Ž—‰wg}’™„olu‚ƒ„†„}vv{€‚ƒƒ‚€}{|||‚ˆŒ‰†‚ypw‡˜Šwhv„‰~ttz€‚……ƒ~ytv{€€€†ŠŠ„}ywuŽ—‡wqy………‚~„Їyko~Œ‘––„qo…›”~h{‘¡}uz|vp‚–£‹tjt}†™Šzqˆ ž{Xeˆ«•{hr{‚…ˆ…z}†‹ˆ|qprs…—¢xs~Š…ynu{‚Š’€qry€‰’•‚pq‡žuZpˆ—Ž…}ytw}‚„……ƒ}{}‚†‹‡}ru{€‡Ž†|z}€€€€€‚†Š‰…€€€€€€€€~|z|~€€€‚†Š†|rxƒ‹€usˆ™‚ks„’…yrx~ƒ‰Žƒtgu„‹†‚|un{‹™‰zrx~†˜Œ}qx…ˆ‹…zow‚‹ƒzx~„„‚€‚‚|zzz~ƒ‰…€~€‚„~z…‡~tr}ˆ†}ty€…‚{xt{†’‡{qy„‚€€…‰‹‚xromw†•ކzuv|‚‚}ƒ‰‹‚zvxz~„‰‰‰‡wtvx}…Œˆƒ€€€}vpu‰‡†„|trw{‰‰‚|xusss}‹™‰yqƒ•‘tWgЬ—€pv}}wqy„Š„}{|~€‚„†‚~ƒ‡ƒynuƒzuy~~|z}€‚„…„€|zzz~‚†ƒ€€…‹‡|psz€€€€€€}xtw|…‰Š†‚|tmv‚Œˆ„€{v{†‘‰~t}‡Šƒ{z}€{uq‘•}fjƒœygpzƒŠ‹}oy‡’‡|x†‡ƒ€xnh–ž‰tqy€€€€€€ƒ†{t{„‹‚xv}„ƒz|}{}ƒŠ‡x}„ˆ‚}|€„ƒ‚€zur|‡‰y|„Œƒwov|ˆ›®›vPi‰¡}ux{€„‰€vov}ƒˆŽ†znx„Œƒzy‚‹†}swzˆ‘Ž}kmv€€€~wpt„”Ž~oqsx…’‘€pqx€‡ŽŽzeh†¤—yZpˆ–†uqx~€€€„‡‡wy…‰{m€“œ†qm{Їx}ƒ…ƒ}xtz„‚wrx~ƒ‡‹„yo}Šsw‰œŠnToŠ™‰zuwzƒ–ˆzry€‚€|xv}„‡‡†„‚€‚|vv|ƒ„‚€~|{‚‰Š€wv{€…‹„zu{…‰Œ„|u‚Ž‘‚suƒ‘‰}t~‡‰€vy‚Œ‰„Š““ƒsy¡‘zgqz‚†‹…zoxƒŒŠ‡„€{|~€„‰Šxv~††ƒ€}~„ŠŠƒ||‚„…‡ˆ…|txƒŽŠ†€€€€‚‚}wvƒ‘’‚ryŠœty~‚‡‹„ymy‡‰ƒ~zw}†ƒvmrx‰’Œ€svx{}‚ƒ~|xuu~‡ŒŒŒ„xmw‡‚|{~€€€€yrq€su{€…‰‰~sr{ƒ………yvz~~}~€ƒ…„}vuy}…‰ƒ~zzz|ƒ‚{vv~†„|ty€†~vsx~‚„†€ytŠŒ}ns‡œzgt€†~uzˆ—Œ|n~Ž”„tv†–Šwh~”œ‰us|…ƒ€~„ƒ{s{Ž¡r[s‹–‡yv{€‚„…yz‡“Žoszzvx†”‚uvx{‚ˆŠ†‚…ˆvp{†‹‰†ƒ~z}‚„†„‚€{wu…”—‡xw{€€€€€€|z{}~…Œ‹xz€‡~up|‡‰‚zz}€€€|x|ˆ“Œ}ow‡‡†ƒ|uzƒƒxrw}„Ž—}m{ˆƒwvƒ‰{m}•…uwŒ oPr•©†d_y“Ž~nprw…“’qx…“…wov}€€€€€€€€~wpv‡—Ž~nu|€€€€€€„‰Œyf`z”–„rtz{vrpnv†—}mmmr‚’‘ƒusstx}}wpyŽ£‘v]jw‚†‹†|rx‚‰weax|inxzvrpmv†–Ž‚vsopw~ƒ‡Œˆ„ulju€ƒ€ƒ‚yqow~€~}‚ˆŠu_]|›•y\n…˜Š|rpmz¤ŒoYq‰“‰~xus€–†vqy‚€{wuƒ‘’‚rs{ƒ‚€zuv}„‚}x}‚„}{zz}‚†„€€€„†zsz…zz‡†ƒ€€€‚‹”~kw¦yiw†‰‚||~€†Œvsy„ˆŒvr€€qw…’„wr„–™„|tm}–‹|~€€€€yst‰šel}ˆƒ~zuzˆ•Šxgw‡‰ƒ€€€€€ˆ…yw}‚…‡ˆ…‚‚ƒ}z„Š•“ƒtu‚Ž‹‡ƒ‚€€ˆ’™†€€€€€€„‰Œ‡ƒ‚ƒyt~Š”‹‚~€‚„†{w‚ŒŽ‚wyƒ„yr”„ts{‚†‰Š†~|y~…Œ†€|‚ƒ‚€…Œ“†yqФ¦\d„¤’zi|“ƒrt~ˆyu~ˆ‹†{tmzˆ’‘Š}qry€{vv†——‚mq‚’Œ…~}„}z~‚……†„~{yx€ˆ‹svˆ›ŽtZv•§Žtm{‰‰„€{vv„’‘qw…“Œ…€€€€€€€€€€€‚†‹‡|qw‚†{}ƒ‡‹ƒxm{‰su…•}m|‹|hj€•Žqrsw„‘‰€€Š“”‚qs…–‹xgpz…ˆ‡„}yvwy}†Œvy~ƒƒƒ‚€}~€~~ƒ‰ˆ}rv„‘‡yo“}hl—‘†~„ƒ|uyŠˆ†ƒ‚€~ytv{€€€xqt…—ybn~Ž‘”~lsˆž|nw€…ƒ€~|z~…ˆ‹‡|qv„’‰~vz~~}~€€€}{|…zr|‡Ž†~{}€€€‚……yx|ƒ†‰xs}ˆ‡xjs†™‹{pv}€€€~}€‚|vtuuŒ™‰yov}‚…‰†ƒ€~}~€~}|{z‚ŠŒ}nm{Љ„€€€€€€}wqu|‚†‰ˆ}rsЇxz|ƒ‡‚uit…–‰|ttuy…‚~{ˆ‰~rs}‡†ƒ€€€€€€}xtw|€€€{xy}€€~~€€€€€|xxЇ{ozŠ—‡wq}ˆ‡~tz‚ˆ€xv~††‚}zxw}ƒ„€{…Œsh{Ž”„srx€€€€€€€€|vpyƒŠxxƒ‰xh}—©ˆg^}œ˜€iox€€€~yt¢Œp]uŽ–…tsy€€€zuwІ}sqnp‘’~jm}Œˆƒ|xy|‚‡‹‚xr}ˆ†uds«r]pƒˆvsssƒ“›hdxŠ}px€…‚~|{z}€ƒ‡Š‰{mo‚•“‰€€€€€€|unyŠšŠyp|‡‰‚{|~€…‰‰~rqx‚„†€{y~„€thuˆš‡~wps‹…|tx}‚†‹…wio{‡‰‹‰~tsy€}yv~‡‹…ytnx†’†{v€‰†{pwŠƒ|{ƒ‹‡{oszƒ††††€wnvŠƒ|z„xotz‰‘‘‚ss~ˆ†ƒxqsƒ“€pt{ƒ…‚yoqx„‰Štr€Ž‰yiwŠ—„rkx…ˆ‡†~to€”„smmm|Œ—‰{v~…€wn{Š”‡zw€ˆ„yo|‹–„}{xz|}†“„uqzƒ„‚€{vuŒ{kmv€ˆ‘”‡yv~‡„}v|‚‡‰Š‡z{}€ƒ……y{†ˆyis|„…†…‚€|wsx}€€€ƒ‡Œ‚tfu…ŒŠ„yowƒ‚vq‚’‘ms€†|ƒ‰‰…€€€zuv†•“‚rsz€€€‚‰‹~pt~…ƒƒ…ƒz|~ztu…–“‚psz€€€€€€‚„†€yt{‚†††„‚€~~‚†‡„‚ƒ~xt~‡‹†‚}xs{„‹‚yw‹‹†€|wty„ˆŒ‡vvwx€‡‹Š‰‚xnv€‡„€€€†˜‰vi~“›Žzws|…ŒŒŒ‡|qw†•‰zpx…‚€{tm~‘Šxr~‰‡~u~ˆŽ†~xsnuŒŽtt„”Œzh~–¥‡jat‡‹ˆ†ƒ‚‰ˆoVi²’oWo†‰‚€€€€€„ˆ„zpy‰™Ž‚{}‚…‰‚xn~Ž–†vu‚Œƒz}~|€‰‘Š~sx}€€€‚…‰ƒ|u~†‰xz…‘Š~s”„ts‹‰„}{{|}„‘€qy„}vw†…‚€€€€€€…Ž—Žv‡Š€wv{€„‰Œ~ol}Ž‘Šƒ}|€„„zqw‡—’ˆyrs‚‘…z}‚…ƒ}vozŽ£’|iv„ˆ|przƒ‡Š‹ƒ{wxz†Œ…|v|ƒ…ƒ€€€€€€xqw‘«œvPjŒ¦Žun€“”Š€€€€€~{y|†„xqt„”‘„xz~zusss}Š˜Šzov|~ytzƒ‡|{z‹—zgoy„—ª£}Xa€žŒwj}{ek|ˆƒzuy„‹vxy|‚‰ˆ€yuts|…І‚„‹‘iRi€‰ƒ€€€€€€ztqrs}£oOk†˜“ކ{ozŠšeZy˜Šwqon•‡qo|Љ„yrrŽpu€ˆ…‚~zv{†ƒp`v‹˜“ŽhPgˆ¦‘|oqs{‰—Šwhz•‡yw}‚~xty}€€€€€€€€€€€€€€}xsqoo‡ž¤Špmy…„xqsƒ“{hwŠ˜‡vq}‰‰ƒ}~€€€€€€€…Œ“…uj”˜ƒmny…ˆ‹Š|nm}Ž‹ty~„ˆ‰zks†™‹zo{‡ŒŒŒ‚ugz‚xsow„‘‡|tz€‚€{tm‚™¥†f^s‡‰ƒ}„‡ŠŒ‡|pryŠ–›‰wpuy{|}ˆ’–†us€mYu‘¡Šrhjmy‰™‹}uy~…Ž—…jOr–ªthjm}’¦“uy~€€€}yuƒ–Š~vrnw‚‰~rqy€‚ƒ„‡ŠŠ†‚}xtw|…‰ˆ}rv†–Œ|n|Ї~yxwz}€€€~yuy‚Œƒwmy…‰~ru€‹ƒwnw€…ƒ€€€€~}}}€ˆŠ|oszzvuz‚„†„€€€€€€|unz‡’‰€zyw|„Œˆ„zvuz€€€~{{}ƒŠ‘Š|nx…ކ~zzz}‚†{x†…{ry‰˜„l]uŒ’lmv€‰’”x\Yx–“oy„‹spw~‡šˆuiu†ƒ€‚‚}yusqu€‹‰‚{xvuz~‚‡‹…|s~ˆ€sr€Œ†~|yyy}„‹ˆ‚}zxyˆ†{pu~†ƒƒ…„‚€zsm†Ÿ¨…b_y”’‡}{z|ƒŠ‡{osz‚†Š‹„}|~€|wrpnsˆ›†qu‰’‚st‹ƒxn{ˆ‰‚‚„†€zu~‡‹†‚‚„†|pgtЋЅ€ztoyƒ‹‘—owƒŒ€tt†™–†vssrqpw‹Ÿ—}cjv‡…}|~€€€ƒ……ƒ€„‰Ž~maw•Š~†€rhq{„Œ•|kpv}ƒŠ‹†€€€{wttu{ˆ–‚tx|€€€€€€ƒˆŒqi|–ˆ€wn{ˆ‘…ywЇ~vxy|ƒŠŠ„~{yw}‚‡‰‹‡{pv‚ŽŒ‰~tu‚‰{m|‹’ppƒ•Ž}lt{‚Œ•‘qv‚ˆ‚€„‡„|uw|€…‰Š‚z{ƒ‹„xlx„ŽŽŽˆ|psz€Š“”„ts}‡wn{‰‰ƒ|unv‹‡ƒ€€€}xt{†Ž‰ƒ~|}€„ˆ‹‚yuz~}xs{„Œˆƒ}wpw‡—Šwhz—„}xs{…Œ‡ƒ€€€€€€|wuƒ‘”„srx€€†‹‹„|zzzzz{ƒ‹Œ„{z}€{wsssz ˜€iffj†¢§ƒ_c}—…m\tŒ˜“„ynrv{‚‰Œ‰‡€wnxƒŠst„”“‹‚xniv„ŒŒŒ‰„€}|vqu…•“Š€p^Vu• wsp~•ƒpnŽ„zwuv~†‹ŒŒ„xm}”ji”Œyfq{„„„‚~{vrn~•…usЉ„€€€~}~€~|zƒ„}vuy}~€€€€€€|vov€‰‰‰…yln}ŒŠ…‚ƒ‚~{xvsz„‹‚yvˆ„viq~ŒŽ‘„xv{}zx€‰Šuu}…‚~{|}€„ˆ†|wrny…‹ˆ†ƒ‚€ztou|†–¦™wU^p‚ŸŠuz¤ŒlRmˆ™™™€pmmoƒ—Ž|~€{wty}…œŽqTg‚—Š}yƒ‰~t|…‹‚xuz€€€€€…Šˆ~tuz€‚……~wxƒŽŠtw{‚†Œ‘‰|npty…’’‚ss{‚|{~‚…‰Œ…{pv|„‡†ƒ€{tm|Œ–…uu…•Œygt‚Œ‰‡‚yqtz€…‰‰uu€Š…zpv|‚‹”v_h|Š„€€€}|xtp{…‹‡‚|unzŠš‡{xy|€~~€„ˆ‡…ƒ{x{~ƒ‹“Žpszyrr€ssw{}…ˆ„|t{„‹€usƒ“€orzŠ“”„tqx‚„…|ssƒ“‘pprt‚’}hl—~oont„”€pnnp}‹Žsry€€ulp©xRe˜‰ysx~}|~€€€€‚„†~to€”„svŒƒyqx‚€€€€{wu|„‰‹Œ†}tw{|zx{…‰|ptz€‡rt}†„~wquˆš“onnr…™š‡tt|„|sq„˜™†rw…“ƒsit€Š‘—}mv‡‰‹ˆ€xy}€€€€€€ƒ‡Œ…{qw|‚ƒ…ˆŒƒxm|‹“‹‚€€€€€}{|ƒŠˆ~ux~„…†„€||~€„‰Œvrކ~||}„‹Žˆ‚}xs{…އ{}€€€‚€€€€|un~“¥Žvl’‘qtz‚„‚|uv{€†’‹„ƒ†€wns{‚‹”–Š~wrm“¤zq|‡ƒuht„‘Žˆ{now„ˆŠ†‚}wpw†”‰zo}‹Žƒwv{€„‰‹„~{}€€€€ysp…šœ‚hgsŒ™Ÿ‰slzˆ†}suvx}‚€ƒˆŒqk†¡¡]d~˜~ty~~zv}ˆ“‚qg{’‚qs|†ƒ~xqu„”‹yhu„ˆƒ€€€€€€€€€€€{vpv|…‰…{pt|„}wv€‰ˆ|pu€‹~ql~‘‘posw‚Œspw‡™ˆxp|‡‡~u{…‡{uov†–Žuy}~vos‹‰„xqov}}xt}Š•ƒriovŠ”ƒ{}~wps{ƒ‡ŠŒ€uotx€‰’‰}ty}~ytv}ƒ†ˆˆ~srŒ‡|wuˆššzYa…¨—}gqz€€€ƒ‡Œ‚wp„™œ€dct„ˆ‹Štrzƒ„‚€ysp…šœffu…ˆ‹‹‡‚€€€~{x}‚…|zzz~ƒ‰ˆ†„|tt|„„‚€{vuŽ‚vx†„~wqr~‰‰…‚}xwˆ‡}tw€‰ƒ~|ƒŠˆ}sv~†‰‹Šxw‡†ƒ€€€‚„ƒ€~|zˆŒ‰‡xo|‘¦‹o`wŽ“…vojf€š¨“tssx~„‡ŠŠ†‚€€€}yv€‰Žˆ‚}wrx€ˆˆˆ†~vy…‘ˆzn~•…urx‡•‹yvt{‰—Œ|n~”nluˆ‘˜ˆxs„–v]p‹¤’€vz~|z€†‹ˆ„wpuƒ‘‡zp’–ƒpox‚†‰‹‚zx†ƒ{tw|ˆŽ€rv…”‡€€€~zv|†‰{††~vz†‘Œ…€€€~ytv{€Œ˜Ÿ€aZu‘“Š{wt{‚…‚€{tm„œ¬‘vjt}€€€}~…ƒ|uw{€…Š‹„~ywv|…ˆƒ€€€‚‡‹„ym}™–“ˆr[h„Ÿ~rz‚ƒ}w{€†††…ƒ}{}€„‡ˆ…€€€~|zƒ‡‰‹†{py‰™‰yp|ˆŠ…{tn}‹“‡|vuuŒ™ˆxqu~Œ™Ž‚yxvx|€…ŠŽ„ztwy|~€~|{…|hj}†€€€~}‡„yo}ŠŽtu€‹„yqw|ƒŠ‘Œ~pu|„…†…ƒ€~|y†‹…}‚‡„|uy~‚€€€€€€€€€}{~‡‰zkt€Š†‚‚„‡ƒ|u{…ƒ‚…ˆ‚xnxƒŽ’—“ƒrv„’Œ†‚ƒ‚€}zvŒ”‡zw‡„}v~†Œ‡‚~yt|Š—Œw~……}uy‰†‚€‚ƒ‚€|xx…“{en„™Œ~ty~€€€}zw‹…yux|„Ž™Žƒytotƒ’ˆ€€€€€€|un{ –ƒzqs~‰Šˆ†ƒ~|{zzƒš‡~wpt‚Žˆ‚€~zuw~…„‚€€€}tjsŠ¢–nx‚†~vx€ˆ‹ŒŒupw…Ї}tx}€€€}xs|†ƒvpw~ƒ‡Œ„{t{‚…ƒ€€€€€€zvttt|ˆ”‹~rqotƒ“‘„wy}xrqw~„‹‘ˆ}rpnsƒ““Šzso}‹‚vuz€„‰Š|no†–iw‰—‡wr}ˆ†}u{ƒˆ‚}xtqw‚Œ„{sssuz{tm„ž­‡bZ{œ—hoy‚‰ŠvbhzŒˆ‚}{xxxx|†‚~ƒ‡„yopv|‚ˆŠ„}{~€€€€yrr‡œ›fht€†Žtqx‚„†ƒ~xsu€‹‰„€yrp}‰Šwx|€ƒ…„|tv‚†ylv„}vuwzƒŽ™ˆxnqty€ˆ‡„zrr‚’|jy¦Šm]lzˆ–£“|gt‚ˆ}su€Š†wursy~€€€€€}{|ƒ~zˆŽur€Œ€uw|„‡…{qry…‡ˆ~sq}‰†znwƒŒwrx~€€€|wu~mp~Œ„xow€xqry€‚€~ytv{€€€zuxƒˆxgtƒ‹ˆ‚yprz‚|{‚‰‹†zqgv†’‡|pry€‚„†‰Œˆ|pnopyƒŒŽ‘ˆr\e{’މ„{ruˆ›ŒpSi€‘Šƒ|vox‡–ˆyq}ŠŒ„|xus}‡Œvsz‚‚‚„…„~xx}‚‚€€€~xsvƒˆzm}”‚pn|Љ„€vml‘’„vsssz„~xy‰‡ƒ~}~€‚€zt|‡‘qis|†‘›Œwdny‚‡‹‰‚{zz{ˆŠƒ}zzz}€‚€~}~€‚„…‚}}}~€ƒ…†wuz~ƒˆ…{sssvˆ†€y~„‡{on€“€pt{€€€~ytz†’…thy‰Žƒwx€ˆ„~ywtuz€†Ž•‰zo}‹†}|~€€€}{|†ƒz€†‰~rt‡š’}hox€€€€€€€€€ztqw}„–Ž~nxƒ‹†ƒŠ‘‰{n|Œ–†vv‹Ÿ—‚nt{‚‹”’‚ru}†}{~€€€€…Š„wq|‡ˆusss•†wtz‚‚‚€}{|ƒ…†‡xu}…†‚~}}}‚†‡wz†’‰zl{‰Ž~nn|Љ„€€€~zuw}ƒ‚€€€€€€€€€}zx‡Š…|xs~Œ˜ˆyq{…„|t{„Œ†~€}xs{…Œˆƒ~yuy‚‹„{t|„ˆ‡†€wnx„ŽŒŠ…{qvƒ‘‡zo{†‹†wi[m…™†€€€{tnw‚‹‰‡…ƒ€~}~€‡Ž‚wv{€„ˆ‰xwˆ‡€z€‡Šts~‰†~v{€…ˆ‹ˆvw~„‚†‹‡yjmv€‰’–†vs‚‘‰xgp{…‹‘}nox€€€ƒ†…ƒ€ypfq}‡’‰‚zsly†ŽŒ‡|qsz…‰‹†‚€€€{tn{‰’އ{pt}†ƒ€€€ƒ‡‹ƒxm”žŒyt|„Š“‡{v‚Žˆƒ†‰€xvŒŒ„|‰€qjx‡‘“ˆzn€’˜~ef~•“Šzrq~‹Œ‡~~„ƒzru€‹‰„ysr|…‡ƒ€€€€~zv{„‰„~}~~~}}„‹‘Š„~{xxyz‚‹’‰€yvty‚‹Š‡…€{z|~~|{{‚‰Š…}}}yvuƒ‘“„uruw}„‡~us{„„‚€|wvˆˆ~ssvz~ƒ…~wv}„„‚€ztr}‰‹„||~€„‰Šus{„„‚€€€zuw‡†ƒ€€{uxŠ…znu{‚‰Œqv…~y||z~„‰„zzzˆ‘‰{mwˆ…€€€‚…‡}tpyƒˆŠŒ‡€zwtuy~‚„†„‚yqry€…Š‚vpw}€€€‚‚€~zuw}ƒ‹“™‰xnprv{‰•žƒh[q†‹„~€ƒ…|sr‚’|jr€Œwrx~„‹’ˆzou|€€€‚„†€xs}†‰€vyƒ„xnz†‹…‚ˆƒth}’šˆwqrsƒ–£Œul|ŒŠ}oxƒ‹€uqw~…Œ“ˆ}t}†‡vsssz€…ƒ}wpu€‹ˆƒ~}{xvz‰†‚€€€~zwy|€€€€€€€€€{tm€”Ÿ„ic{“ov„€|{~€~}zxz…€qt}†‰‹Š|mly††ƒ€ƒ…ƒxlkt~„ˆŒwqx€}z|€€€€€}ytx†ƒ€€€€€€}yvŒ~lm€“Œ~px€…ƒ€€€€€~wqs|„„‚{vu|ƒ‚{tqoo“˜{_`z•Ž~qv|€€€~{x€Š’‹„~wqtŠˆƒ~}{{~~wqy„Œ…~{|~€€€€}{|‚‡…€zzz{‡ˆ€x}Š—Œ}qw}‚†‹‰…€€€€€€‚†‹…ynz‰”Š€|€…zsx}€€€‚…ˆ„}ux{~„Љ€vv{€‚……~xxЉ…€‚…„xml{‰Š…€{wu~‡ˆ€w}ˆ“…tj{Œ‘…yz€†„}{}„І}u|ƒ‡„ƒ‡Œ…{pv|ƒ…„{|~€~}„ŠŠ…€€€€€€€ƒˆƒufu„Ž‹‡xovŒƒzu|ƒ„~}|{zz~Žž–uTd„¤|q€Žqsz€€€€€€~~zvt~ˆˆ‚~|z€†‹€ur‚“•‹‚ztoz…Їƒ€€}ywz|€…Љ…€€€|y{†‘‘‰zsny…Їƒ€€|wty}€€€€€€~€€€€…‹’‡yo|Ї€‚„€}{‚ˆˆ|q{“ªmRn‰”†xqom{‹—ƒ~€‚…ˆ…‚‚ƒ}x|„Œ„zu‰‹€vw{€„‡ˆywz|‡‡~€€€€{un}Œ–†wqx~ƒˆŒƒzuˆ‹†ypfx‹—ˆxsyƒ‡‹†€€€€~|zˆ‹xrpnzŠšŒ~rpntƒ’‹|mv„}vvz„ˆŒup{‡‰ƒ~~€‚€|wz‚ŠŠˆ†}tpw}‚…‰„zƒ‚xnt†™‘‚rpnqŽ…||~€€€}{~…Œ‰„ztt‰‰‚{|~€€€~yuyƒ†|tx}‚ˆ‰ux~‚€}z|~€†‘|g_oŠ‘˜‹{nw€…ƒ€{uny‡“‹…{qwˆ˜}qw}€€€zpgz’¤˜‹€ujnz‡yty}€€€{unwŠ‹ˆ}qs|……ƒ‚~z|…‰~ty~‚€€€€~|z|‚Š’rx‰šŽw{~}wqtz€ˆ“„vrzƒ„„„€|{}€€€{tnƒ˜¤ymmm|’§‘zk{‹‹{jq€ˆ{‚‰‚nZg—‘Š„{rs|……ƒ‚€€€€}ytz„†zzz}ƒˆ†ƒ€€€€€€|un–­ŠhVr™™™Ž€rqps|…ˆ†„ƒƒ‚zrr‚’”‹‚~|zzz|€„‡‰Šwnu}ƒƒ„wou~†††ƒ{swƒŽ‹…yrsŠxftˆ˜‡umw‚„‚€‚„…|{}‚„…~wtuw‚”§ŒkPo™†sqy€{xy‚І|qw…ƒ~ytz……xov|~ytv{€€}~€ƒˆŒvp€’‚rv„’‡zqsv{…‹v|ƒ‡‚}{~€~|z~ƒ…‚~ztnuˆƒzuvzvhYx˜«‹k`o~ysx}†Š‡|qsz€€€€€€}ytsssŠ„yvz|wsx}ƒ…ƒ€}yuq‘˜‡uoqsw|€€€‚†‹„sbm€’‘Œ€sqx…ŠŽ‰„{rhsƒ’‹…€€€zncp‚’‹„‚ƒ~vms{„…†…ƒ|vp|‹˜ˆxrƒ“€ooquŠŸ¥‹qr‡Žygqzƒ‰‹€uqoo|Š„yy~„€}zzz~‡„{zz{}€€€„Šƒsh{Ž”†xv{€€€xqt‡™’}hwŠ—gc}—•ƒrv{€€€‚ƒ…ˆ‹qhtˆ‹‡~tssty~„Œ”€tx}zuy…‘Šƒ{sou|†‹‡zuqq€Žƒwy‰upŽ‘‡}~‚†}uq|‡‹ˆ„ysz…€{~‡‘‰{nu{‚ˆŽŒvx|€€€‚„…††vmw‚ˆ‡†„‚€€€€€€}{~…Œ‰„€yrr‚’’„v{„Œ‚wqtv€¡’|gx‰‚ss‹ˆƒ}|{|ƒ†Š„ypv|€€€|uo{‹˜ˆxpy‚…„„}{ƒƒ{rw„‘†€€€}vouƒ‘Žˆ‚zrr€ŽŽˆ€€zvsssx€ˆ†‚€€€„–€qw…~wxƒ‹€tx|yst}††ƒ€zuqy†††€vmu~…ƒ~~}{z|~~{xz‚Šˆ‚|zyy|ƒ„wpz„Š~st…•{hv†‘Š„}vozŸŒwiw…І{tm|Œ•‚po‚•sttv|ƒ…‚€|ws‹‘‚ts~Љ„€yrq‘‘‚rt|„}wuy~„‹’‡vfu…Žˆ‚€€€‚ƒ}wv‹ˆ„}umv~……†„‚€~|{}€€€ƒ‡‹…{tw{†ŒŒ†‚‚{sr~‹‹ƒz…Š}ol“‘p{‹™ˆwp|ˆ‰‚{yyz~ƒƒ{svˆ†ƒzvuz~~}€„†††ƒypw‡—Žwz~€€€€€€}~€}z‹•‡uhv„І~|z|€€€ƒ†‚|v|…}uv…•‘‚ty~‚|}…Œ‰‚zxuuy~‚‡Œ…zoy…utƒzywy€‡‰…|xsx}zux„އ€~||€„ƒ|uzƒ†€|~„†ˆŠŒzg^u”‹‚€€€€€ƒˆŒˆzwuu|ƒŠ‘˜}m}•…ut‚Š…|tq|†‰…€€€|y{‡“‘qzŠš‡tk~‘•‹‚€€€€€€€€ƒ‡‹ƒxn~Ž”…uv„‘ˆznw€„€|~…Œ…|sssx…“Ž|iy¤vl’‘qv~…„‚zuy‚Œ‡zzz{}€~}~~„Š‹†|vp{‡„xt~ˆ…zo|˜ƒmfyŒŽ‡zso“ƒss|…ˆ‹Š€vt|…„z~ƒzz|}xs~‹“‡zuzƒ‡‹vp‚ttz€†ŒŽƒyv{€|unv…‚~„ˆ‚xmx„Œ†€‚…€wnruz‰˜˜…rs{ƒynj“–„rry€}{{€„…‚€{tm~˜ƒnm•pnmr‡›˜|`ev†}ts†™˜…roqsx}‚Š’Ž‚vuxzwtu{ƒƒƒ}uny„І‚€€€|wrrqu„“}kr€Œupy‚ˆŠ„xotz~€ƒˆŒ„zooot…–v^l„™†€€€€€€|wt‚zcf|’‘‹…|spx„†‰†ƒ}{|€„{u|…‹‚yvz€€€€€„‡†~vv{€ˆ‘—‡wpwƒ„†wr‘’|gj{‹ˆ„}{yvsy‚‹‚wq‘yafx‹ˆ„xqqy€}z|ƒ†ƒzqt}†ƒ~|{}‚ˆ…zwst‚ttz€€€†Œˆ|pvƒŠ„€€€}ytw|€‡Ž‚twŒ ‘sUpŒžŽ}sqn{Ž }rx}€€€~|z„’ƒtr{„‚~z‰™€c`uЉz‡”—€jguƒ„‚€€€~}|{zƒŽ˜ˆxpz„„|t|ˆ’‡{tuv{„‰{ƒƒzru€‹ŒŒ‹€uq{…ˆ†„€|z~‚„‚€~}{ƒ…yx‚‹‰tsst{‚‡ŠŒ†zow‚‹…†ˆ{nyˆ“…vt†™“~iv‰˜ˆwr}‰Š…€‚……{rr€Ž‹†€yty}}vo}–¯“pVpŠ”†xsssš†rlzˆ‰…€~{{}€€€€€€ƒ‡‡~uruw~‡…yqw}„Œ”Šyhv†‘Š„}vory€€€‚Œ•‘~lmv€’¥®mbo|‡™‰yq‚”“~ip“Š|€„‚zrzˆ•†€}z}„‹ˆ„€…‹Œ…}xvs~‹™‰yqy‚„~„†††ƒzqs‹‰„€yrp|‡‰…€€€€€~wpu‚†ztt‚‚ux~„„„ƒ‚€~{x‚—‡xq}ˆ‡~tw|†Œ†|{z|~‚ƒƒ€‚ƒ‚}{}„‹†znrzˆ†}}†~uo~Ž“‡{xyz€‡‹xx‰™”ou~„‚‚ƒ}zyxz†’”‰~|~€€€†‹“˜zhwŠ˜ˆyv†•‚tsst{‚‰‘˜Œvao‹…~~†Ž‡{oxƒ‹†‚‚‡‹„zoy„Šyzˆ–‹v`s‰—‰{vzƒ†‰zv~‡ˆƒ}€†‹~pj}•Œ‚|vq|‡ˆ‚€€€€€€€€€€€‚„†zsw{~ƒ‡‡„€|wsz„}vv{‚„†|sq‘’„vvz~„ƒ{rrx‡˜}aVu“š‹}vqnu{‚ƒ‚€€€zttŽŠyir€Œvpw}ƒ‡Œ}j[{œ§„aa{•Šwhz•†vonm{‹™Š|tuw|ƒŠ…{}€€€~zwz}‚€{uny‡’‡|utsx€ˆ†‚xqpw~~{x|……†vjo}ŒŒŒŠtpw~}yuy}…‰†{puŒ„{sssx…’Œ}nt{€€€}vouŒˆƒ~ukp†œ•‚nx„Š|njt}‡™‡uhr{ƒˆŽ‹†zrnprx‹ŒŒŒ‡ƒ}o`e™š’ŠvaVj~Ž™£oPe|‰{mm{Š‘“|dXs”ˆ}|~€€€~wqu‚‹xxxy{}‚…ˆŒLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/door.wav0000644000175000017500000002673213263212010020615 0ustar aeglosaeglosRIFFÒ-WAVEfmt "V"VLIST,INFOISFT Lavf52.93.0 (libsndfile-1.0.25)dataz-~€€}~}~€€~z~€€|}~€‚{{}‚}}~}ƒ€}{€‚}~}~~|€€}~~}}~€€€}z}„~z}~€{~€€€}|~ƒ{}…ƒx{|‚€{€‚}x|„†€{|}€~€€~|{~†yv~„‚~€|y{‚…€€|u}Šˆxu}€‚ƒ€{z‚|{€…zz„€{|‚…||ƒ{|€‚€}xzƒ‡€z|€‚…{|€ƒ{w}Œ‡uw‚}ƒ‰}muˆŒ€|}||„|z€‡yw|~†sry}€‡ˆ„}w|~{„‚yw‚…€{y|€‚ƒ‡ƒuqz‡qt†ˆ}y‚{}|†ƒxr‰ˆ~u‡y}ƒ~z}‚‚{z…Œ„wqy…†‡|pp|Œ‚}wwt€Œƒ{roxˆx~‡ˆ|rzˆ‰‚ysv~†‡~wz€…}}„Š‚kb|š—ƒxwrv|‹‘„vrz…‰z{|y{„‡ˆ‡{ou‡‹„yv~‚~x|Œzjm€Œ…ux|z‡ƒ|||txˆƒ€yo{‰ujv oZmŒ‘}w†‹}r}‘Žnh“…nz‘‹nj‹‘}q}„„{„Šym~Šy|xtš‹li„ƒpy› yeyylx“š€isˆ‹…u^oœ¤…e^uŽ”‰€lu‰†||u|’ˆig‡Ÿ•me|‡†ƒƒ~lt”™}_^Œ¦”ry‡mOs´·sFj¡|spkœ›eg|…Œ“Šh^{š‹uš‰aSn€… ±€ES‘­‹fi~‹—ŠbNq Ÿ€r_aЍ¢tS]„ž‡o]n—švd˜}d‰¬”]Np•œ„~‚}ii|™©qLTœ½„K\”¤v`~“—ˆlhƒž¡xQb‰–އ†„pcq‚Œ‹‚†tnlz–¢…[^‚˜‰|wrw‹”ƒz{rs€‡}ly™—}w{{utw}ŠŸšxZc‰l_s”“€€|qpw‹˜”vS[Œ¨—{qjbv–¨™pOY‡²°~YRdˆ§©ˆldi…“—…YZ›°|Xm—“~‡ŠiLm𫤆XDs¸Ym¥…DY«¹€]ex‚‘£jSX€š’zsy†ƒˆls|whrž¶–bJW˜º’UQw›˜…|oeŸ’~fbp¨¨zHFu±³…po`_œ½‚Tw›†TT¾±\PZ|¤À£^0I•¼¯PY’¡ci„‘Œ{x‚obˆÀœ<5˜ÄŽkŠ“aHw œ{lkq˜rW‚³µ{Jd‡yw’vxr^­ŸgX~‘vz—ŸvXkˆ‘…ut“ iH}Á©hPj‹‰w‡•zdt•¦šk@L—½—ff€‰›Šd\xˆ”Ÿ™yX^„˜…}}t}š–]U ´}^p…‚c`„­¼ŒR;M–оpAb‰ƒtŽ©|Hq´¢jRdµš\H®…j‘•dYŠžlQ}µ§sLQŒÆ SD|­œ‚t^`‚§ {\Yqœªro|…zzvi~››‚nlv‡…zxŒ£€ZjŽ€g…¨Œqpkq˜™nVˆÄš<@Ž£Œ€|stƒ’Žmf…‹sp‹™yiƒ‰je“Ä›:3{øvZ_n’¤skpr{›¨iQdŒvz —vLb“†c³¥tlprz„ˆjv“Š}wuˆ„ohu|‚…–£_Dm¨±‚ajn}‡š …U`†q†Œ…‰„wkgyŸšjU€œ™{b]qŒŽznŠ¡~bwƒjj‘¢{^t†‹“ˆo^}˜†x||ƒ†‰ƒ]Xˆ¢’v|~udƒ¦™r_s‡y’švRRxÀÓ“?3v¥Šƒ¨šQC³‚Rj–hcŽnƒ°—M9}À±mNj{‰›™y`q“…nx„‰……€nk”|r‚|{ƒ‚xt™¡iPx¤žqVg†¬ªˆoaM\¬ÇŒWn|cj‹š‹‹lo•ž^A‰È”GLŠ«˜o[}•nNk®½ƒLZ˜re„¡‡JU¦ÇŒBF¸oIƒ¶˜dm‘}U}§Tg¥ÂNOp¡x\o £wTe’µœa?SÍ·cH{‰vŽžhGpº¶]@| ƒn†¡†ZTq—©—s`ht‹ŸžwP\””yPZ޲Ÿnfwxs‹Š†qq„€y”wegs‹§¨i<]ž» v]co~tž²‡I@‚±’w€”g^”q_‚¢—meƒŒsx­¢ZJˆ¡r`ŠžŠ~p^t–•zxm€ˆ„njŽ£ŽeYsŒ‘¡žg6` }Œ£ˆ[Xi’±ŒMN»¢nago£‘i^n{“Šmci…˜ž’pUaƒ¢œ‚kjz’“ul„irŽ•|m}ˆ‰€qx‹|jbŽÄšFKƒ”Œœ£g'_½¼mHc¡¯‰ge{“‹}tu`v£¦rVkˆ‡€‚˜¦’_Ji†ŒŸœ{Z[s‡›«¦mGX„•r…¡–ZN‘Å›N8j¦®ee…—z]y w}”•d9n»°rTm‹…•ƒqyic°”XPŒ¡m‚™†fp“‡pjsˆ™m‚™uXtŽ{¾:%tºÀŽjdfs‰žŽtx‚i^•·…MeŽ•aV‡³JG‰»¬y[d‡–mX{µ»€C`’…cyŸ†vjh…¨“g_ˆp{˜ŸxK^Ž—„zw~™«v9T¡ºŽfrnh„­ sW^sƒ—©™pZ]nˆ ˜„ƒy_Z}“Ž”‘h_‚“uhv„ ¹{/T¤žlr£™d_Ša_ˆ¥–~zrTež´ŽcXu‹ŒœŽZFqª±bx“{Zq¹Ãn.R™¨su{Š‹€€{e\Ž´›qrpauЉƒ€†‹Š{RT”ß_Xtx†ššxc…—nOƒµ›PKœÉƒ@XŒ•‚x˜fqŠŒxu”™xgi‡xdjŽ£—xkZ]š¾˜mikx‹iU„©Ž @X ¥|l†‰klŽŠmh€y‚‹‹•sPr¦‹Sm¯¢sZVg‘½¯oRv“xey ¡u_u—Šd\s—©Ž^m˜‰^sªœWN|žŠu‡›pB[Ÿ»—k[nzt†ª¡bAg§¸ƒTW†ª}—ˆGH‡©…i‰¢ar‘‰b_ˆœ‰vvx†œfaƒ€e¯šlm‹ˆjn–•tet|~„Š•€keƒ£™eHm¾Ð~;Q{•˜’wfl|otŽ–œ—pZLb®Í‰F_‹Xy«¢kaw€sq†£iE^–©‡c€—`{©BK£Æ‘hlnt~}}’™‘mKZ•½¯p>R ‘ŒŒsWjˆ—–{dg{‹Šzu|‚‚uk„|‰dw¨ŒXg–“sw‰xdn¢±†^Yc—¹”proXV‡Á¶weompŠ¥ŠYaŽd~²•ZQ|ª¦v]^ˆ´Nr¨He³Èy.HŽ·©|j}YV™º‚FWš°†s‡}abƒ¦¢rs`k˜”ŒqS]…š“Œqcisª¡SH†£ˆgcЦxljˆu~ž˜cV{˜•wfp€„†‚`[‘»‹Da­§n\Y`žÒ¦B9Àm4}ͧOK†¥–|QG†¾¢VS—©„flut•Ÿ¬M1g§±ƒj„ŒlWk¡”‰oWl’¤ˆj‡¢{OUz‹›’dOp›‘x}†€–kLrœ…ltšž_^™ ur›ŠPW¤—Œ{SJ‡¾˜[]ˆ¡wCg³ºŽeWYrš­¡xN`Ÿ°…tˆoGW Ë¡lXOz¨”qxŽ}b¥’ke~€}‘Ÿ{Yz—|Z¶”Xq¥’HFœ·ŠlWf™«€[SƒÁ¦gdvg[¾^b”‰TW˜¹Œ^_‡˜}sˆ„hr ¢j\~˜~g{¡ŽND‚Á¯g^™ŒX_—šrr‘ŒWN‘¾ŠY|¨]Uy„†¯Äx!?›³™ˆzbZ{‰r‰–mUw”ƒ|’—|alƒ}wƒ–œ€[Qz²µ~TRsššyhs˜£i9w½—F[·Àd@u‘†’›uRp¢¡}t~Wh¡bKz²ªqV\s˜³œb^ru|ˆŸ¬€Tgˆ‚xy˜¡lRu¡’jr¡ _Bq¸¾zF]…€ˆˆlz™oq‚…Ž™j3fɾo]€Žygy•–…]Z¤ogjqŠªšymba~–°°p/G”·’hdw—¤}Th”ž†sxuil˜¹”PBo” §}Kg’¤—~gLh²´kU…‘]X Ä•ijeJh¼Ö”HKyŒ~ƒ¡o\hvƒ’­ o]hrhr¬»{OrŽŒ‹€TKÕ©@9²…`m“œ‚kny‡›jaqˆ—}xy„|n˜ˆwsnt}‡¢ zaqrq•«„K[”¯‘fd‹nf~“‘‰^Ln–£Ž}}vy„†„}nWkžª’p`nƒŽ›”mYtƒy†™˜}ly„€ij°¢gAxQKq¤­i^s}ˆ—ž}RZ„ ˆ_Tw¢¢ƒxk]dƒ¢¬Xf„‹‡“a^‹xzƒˆŒ{lˆ”rVn¡uq†ƒdi•¢‘tbt…{}•fx›†NXªÃ‹ZnŒ~dkŒ•Š‡ŠŒwUU‹½£nenkdŠÉµ_-W£Á—YBvº«[K†˜ss®·\^Á°t¢ˆIM†™‰ŒŒxjt‰Žlf‡šŒŠ†ud€”lT{šœƒ_a» L8w¨¡’ŒpWeŸŒtjsŠ‘wˆ‘…jVo‘©Ÿe>a©Å™_K[y•£Ÿq?^®Æ‰9?‰ºfˆt_mƒ–ŸqD[ Û­LBr…ˆ•–z]m‹‡„ukx{|›©~avpUƒÅ¬dDq¨¢pStšlj•¦ˆYd•‹`o•ˆk¯LN€¢™}j`mŸ¨„un]l‰”—‰odr‡Œ„‰–yNo¥™l_t‘‘}ƒzdm¨^f‘htª”Pg°žTI“ªy¤ƒMT‰“€Šš‡wjcx‘žŠqwzv†Œ„}~q~—†^`’±‘gs‰d_œ©€n‰opƒ€yŒ”zkkt–—ˆywnruq|«ªp\‹žfHz²Ÿee“}qy‰Š{xxgsžªxXn£†`\m|Žžš’‚e^i~‘|mzœšgbz„wt“©iehlŠ~–kYx™–‡j[t™™jW‹ºž`Pkƒ™­™V-fÉÌsNl}{}{†—£ƒLNt—©š{npgx œmKi©¾˜dQ`nŠ¥§ŽzeYp¤žieކZj³³`>‹´xLo±Å„=5s¨Ÿ‚‚{nvwyz…ˆugy‰}sw‡†rvˆ…}‘›vL^Ž–•˜nYi…–© e4h¼¤XT¯Œnnp^ˆ±‡Tkœ§€dk…px•‰bp¤ `L‰Ÿyt“‰nx†n|™„Yf˜•j^…™ƒw€‰…{wsmz’„ogq• …wkgxšœn[ƒ¦šu`nˆŒ˜‘`>`§À¦t_bl‘ƒo‚“ƒv…šxYcp‰²¼r5c©›jo…yrŒš†p}‰rašlbƒ—‡–ORŒž‡|ž©i7`›¢†‰”TU ‹ƒ‘†^m°¬bAn “su€„™‡T[ަ‡q‹•we„•hKx´£n`~š™›k/K¥Ç”^nsz{oƒŒ€}svˆ‘}n†ox–‰TW“ª hL[‹¢Ž~™Q@…Å¢OE‰¨†oŒ“Šk\~¡†Kh°¡ju„dc§¾w5T£¾˜hZb}—’ƒy„zpnˆ§NT¥¼vHo ›okbo£Ç£L*r± nc†žycqxxЦ’R[¡²q˜˜nKa’£„|›–x^Tr˜§‹eg‘zwl[ Štrrqx–‚nv€Œ~hmsŠ«’^^†žƒ€–…SRžÊ–GMoc—­|Kjšš|o‚uWuš‚pŽœiDyǺcDrŸ¡‰jSl£­w_‡£‡f}¤ŽL?À“du~f‚–yr—]_•¡mMo•‰‚ngt~’¬Ÿa\zŽœkWV]fmjc\gypYb‚˜ŽvfmfRTjyfJ[}‰€„}`[kogfZ]} Ÿˆm]dx‘uRVu…—š€nv‰“”†}ƒ‡n\iЍ§‘~{„”„Šoj·³“ƒ{pœ¦Šh_lˆ§£Žž§˜™™iev„–~~–•|ƒ¤«š— ”{vvx||y|ƒŠˆ¡«£Šwt‹ˆvdbmtzw…–š’Šzvtqnjuyrqx‰« „iYVdqqorsv„Ÿ›t]r‰zd`i^FT…Ÿ•’|_Xf}‰‡dDQoƒ‹˜’{ck‡ŒiUcpjr‰‚†›yalˆ‹q[gxut«¬“xsgfzƒmVc|‰™¬¶Ÿ}qvxhk}}j]dx’ª»³’zpoy„‹c[m–®£”…lxІrwƒ€ilƒ|z¢ÂŸf[p~ujs†‰ˆ”—ƒov”²ÊÄXWu‚om‘¬‡`h€„ˆžµ¶ fmƒ†bVw†dPgst…ª°’–ž‹…]Pgqlx{wtwФ¦’–¢˜ˆŠˆgOi|ia‡œ‡e]q“’†”¨›{w}zlXZfkrvnkr{ƒ‚vƒ£± ‰qZXkymW[pvovŠŒ…ˆš©¡„uqhWIL\q„‹{k©´€{‚ˆvVFSk|‡‚k\‚³»ª ‘zjlre]pyt}‹ip“¡šœ¤Ÿ‚€‰xN9`ˆ•¤¡}bix€ŒŽˆž¼µŽ}s_XSL]‡Ÿ™Š‡Œˆx~‡z}¥ºŸŠŠwcSBa{cwÇÂhO‚Ÿ•tV_†›¤¬°¢‡{…tNJUc~¤¬–rc¹¸€NQ‰¾Ä¥|ƒuPLWi‡ª¥‡lo’¡ŠgYb•º°§¹¨jO]nnWG^š¸¯kD~ÔÍi%G~Œ¡É»…djsseegUS|£™z[i³Ü†$:‹¤©¸³ƒ^W_z“K5P†¶Â–RQˆ£uH]ŽœŸÊÇ}TgwpcZNMj’¬¨‘bc¶Èe+f‰qx ³´™kMVx”z0&b’¨¸>G¯Ën%@Ÿ©»¼’U<^ˆ`QX]u™¿µj2l»™CE…¢¬¾¹j`^iz{fIIs§±~NqÀ¿]1r¯©«·šeEV„€H=v ª¼¤]MÈŸVR¯µ»™[Hqž®‰X\wy“ÀŸV[ž§pGn¿æÁ…fai{•“X6\ž¹¢hFƒÕÓŽg_[p›µ¥}fs|sxˆsRi›¥‡†rWn’‘‚†¡±jjhTd|kRkŽ„sp”·“RSy’¦vC[nnœ¯lFm¡ŽLT«¢LY•Š|¤’C:{so‹qO`š¤rkž˜QJ—~|ˆeZ|’y‚µ©]Ix‡bj¦°eA}›pc¢ÆŽERŠm”½z)H•¢Š’£’e\„šˆ¬ŠF>z¢–‰œ•aP‹Á®˜•tFW‘™†–¦qA` ¨™§¨‚\bnwޱ°sOk†ni”®Œmp~‡–Ÿpp‹˜{o“ŸlLu˜„fw‹Œ˜’zz‡€x†hXk{}ƒ„}x~Œƒzsxzuojw•’xltŒ‰sl~‚yy€tny|kj~‰€rxˆŽydfƒ‚rmoutx{ykh…˜Š‰„spŠœWT‘oNe𼮆oz€|ƒ~rm|Œyr‚”ww“¡…l~‘…hn‘˜zr „bj„ˆsq‰”Ž„„Ž€„ud}œŠhu“œ‡|‡Œw}~{’—zl€‘„ll…—ƒpzŽgu”‡rxyj‚¯ª†rmxl^†¤Žvw–qƒ‘x\À›:T»•9yØ•7g­›mbš‚]|jl©’Ieº­ou–‚ay¨Pbar‹zv†ƒ˜…hvˆuo„zhs–^Z‹›‚mdl~ƒt¡œ~vwvxˆˆ}oio}ŒŽˆƒ‰cb‰¥™mL[Œ²¸¦s^i•¬~/)‚¸}?m±µ˜Šws…ŒŽŽ—µ°tYtqfŠšl_’¦{VWn”£‹x~„ާµšqgo„ކy}™´£q]nqZ\y‹‡€Œ¥¤†„—~ƒ‚ulmzqeaeeky”Ÿšœ¤Šht•œˆcUeyy€‘tLrÃËŽ‰¨ƒKg—R_}tX_’·¤‹•f[ypHWŠˆfQ^z‘†—ef}lSiysqxf[n†ƒg_‹´²š†dF_‚“ ‹RN…”{wƒ‘¤¡ˆkimhz}pf|“’wq‚™Š[b‰]cty‰Ž‰Š{r‚Ž’†_i‘™ŒŒxv†…†°¸”˜ˆ}~w”…Šuv†¥¼­‹’›†{wgw¦šmjxˆœ “’‡~˜ªŠvcJ^~”˜ydzoT…¸œŒ¡‚eym;Lo`ewm€žtY—£kŽÊKpŠg\^[w_hšƒ_±ˆÄ˜Qn¥‘`?@q‘sq˜s9AJVhz“¯Ê»¬œ~”§Ÿxpp~Œ‡uccehqy‰›¨µ¬¡–Š~vrog\RW\dx™¡ž›˜•“†|uqlmnopru{€„ˆ‹“•“‘‡‚|wrtwwtqrvzˆ‘Œ‰…}~„ˆˆzn\KNU^z•©¬¯­ª§¤¢œˆtgecgkpmklw‚‰ŒŽŒŒ‘–˜“މ…€}zwrmlorx€ˆˆˆ‰‹‰…€yrnquwyz|~…Š‹‰ˆ†„€|wtrrv{}}}~€‡ŽŽ‹ˆ†„€{yz{}€ƒ‚€„‡ˆ‡†…„ƒ‚€€€‚„…††„‚€€€‚{peccdgkov}¡¶µ´±¦š‰‚wk`cfjr{€‚ƒˆ‘‘ŽŠ…~zyyzz{}‚†‡‡‡‡‡†…ƒ…ˆ‹ˆ„€|xtrpsy~ƒˆ‹Š‰ˆˆˆ†ƒ€|wtuwxyz|}‡“Œ…ƒ…ˆ†ƒ€~~~€€|z{€…†„‚„…‡‰‹‹ˆ…€zsz‚‡€yw{~„‡‹’‰…ƒ€€€€ztqsuwyz|~€†’“”’‘‹†€|y}„І‚€ƒ†…€{€‡ŽŒ‹Š‡|zyy|‚ƒ„‚~{~„„„‚||~ƒƒ‚€|z|~€€€€}|}}}€€€€‚‚€€ƒ…†††…„„‚€€€€€€€€€€ƒ…‡‡‡‡‡‡…‚€‚~||~€€‚ƒ…‡†„ƒ„…„€|{}€|wrx~„†‰ˆ„ƒ†‡„€~|z|~€‚ƒ‚}zv|‚‰‰‰‡„‚ƒ„†…|{|~„‡††……„ƒ€~€‚‚ƒƒƒ‚€~}{{~€‚„…ƒ‚€€€‚ƒ‚€}zz€…‡…„€|w{€~zv{ˆ†…ƒƒƒ‚~{yyyz|~€‚ƒ…„„„…††‚}‚‚‚ƒ„…~}~„ˆ†ƒ‚…ˆ‡ƒ€~€‚ƒ…‡…‚€}~‚……ƒ€ƒ‡ˆ‚}{}~„‡„‚€}ƒ„…„ƒ‚ƒƒƒ‚€‚ƒƒ‚€~zwx{~ƒ†††‡‡‡ˆˆˆ…‚|zzzz{|~~€€ƒ†ˆ‰Šˆ„€‚}zwww{†…„ƒ‚ƒ‡‹‰‡…‚~}}}|||}~€€‚‚ƒ„…†„€€€„†ƒ|ywvz}€€€€„ˆ‰‰ˆ†‚~€‚‚€~|{y{~€‚„……ƒ€~ƒ„ƒ€~}‚€€€€~}}~€‚…‡‡‡‡†…„ƒ~{xvtsw|€…ŠŠˆ…†††…„‚|utx|‚€€€€~|zyyz~‚†‰‹Š‡…ƒ{vuuux{€…‹ŽŒ†~||||{yx|‚……„ƒ‚€€…‰ˆ†„ƒƒ„„„‚€}{xuwy{~‚„…†‡‡‡ˆˆ‡†„………‚{ywwz|~€‚‚‚ƒ„…†††……„‚€€€€€€ysortz‚ŠŽŽ‹‰ƒ|usstvxz|‚…ˆ‡‡††††††ƒ|~€ƒ~z{|}‚ƒƒƒ…‡‰†„€~~€‚€€€€€€‚‚ƒ„ƒ‚€‚ƒƒƒƒ‚‚‚‚‚€€~}|||}…‰ŒŽ‰„ƒ€}yvspsw{‡Š‰‡‡‡‡…‚~}|||{{{}~€ƒ†ˆ‰‰‡„‚€}}}~€€€|yy{}€ƒ…„„ƒ‚€ƒ…††…‚€}}|{zz|~€‚…‰‹‰‡{z|~~~€‚„†…„„‚~}}€‚„„„…†…„‚€€€|wruy|~€„ˆŒ‰†ƒ‚€€€~|zyxyz{|~€ƒƒƒ„…‡†……ƒ|yxz|}}}~€„ˆ‰‡†ƒ{€„†„‚~xqtx|€„†ƒƒ†Š‹Œ‡}zw{€}{~„……„„ƒ‚€€‚„………ƒ€€€~}€ƒ‡„‚|yx{}~€‚„†ŠŒ‡}zx{~{wxz}€„†…ƒƒ†‰‰ˆˆ„{{{||||||~€‚„†ˆŠŒˆ„€‚€~}}{zyyy{€…ˆˆˆ†……ˆ‹‹†|wrvz~€‚‚‚‚‚‚‚„…„ƒ‚ƒƒ‡Œ‹‡ƒ|yvxz|‚‡Š‡…ƒ‚‚ƒ…„zwusx‡†…„ƒ„ˆŠ…€}{yyxyyy|€„…‡‡„‚ƒ‚€~||}}|z}„‡Š‡€xwww~†Š†‚}z~‚†††…}|||€„‡‡‡†ƒ€€€€€|yvspu~‡Œ’”‰‡ˆ‰‡„‚zrmnosy€‚‚ƒŠ’–•”Ž„yurqtwy{}ƒ„†‡ˆ‰Š‹‹…~vy{~…„‚€~|{zzzz{}ƒ‡ŒŽŠ…}xuroooqvz}€ƒˆŒŽŒ‹ˆ„~}yuuy}„ˆ…‚€‚…ƒ‚€~||}…‰‡„€€ƒ†…ƒ€~|{~„†ˆ‰‰‰†ƒ}zyz{}€ƒ€‚„‡…‚€~}{}‚†‰Œ‡~wusu|‚€}z|~‡‹…~|}€„‚~z{}~„†‡ˆ†ƒ€ztqz‚ˆ‰‰ˆ‡‡Š…}vpjmqvz~‚†Š•›–ˆƒzxuqnkqx~‚…ˆ‹Œ‹‹‹‹Š‡ƒ€|xvtrvz}~€‚„‡‰‹Œ‡ƒ…ˆ‡†…„ƒ~{uohmsy‰Œ‹‹‹‰…~zvuttvy{}‚‡ŒŽ‘Œ‡‚|zyxuqpv|ƒŠ’‘Œˆ„~|zxwvy|€…ŠŒŠˆ‰‰‰†ƒ€{uty~€€€}zy€†‹ŽŠ…€|yxz{~‚…„ƒ‚€€‚„}y{}€ƒ…††…„‚}{{{|}~€ƒ…ˆˆˆˆ†ƒ€~~~}{|~‚†ˆ…‚‚„‚~z}€€~zv{…ŽŒŠ‡ƒ~|||{zyyyz„…„ƒ}~€ƒ‚€~}}~€€€ƒ‰‹ˆ„~yx|~{xz}}|z|€ƒ………††‡‰‹‰…€~|zzz{|}~€‚ƒ…ˆŠŠŠ‡„€~}}€}|~€…‰‰…‚‚‚„††ƒ}ytwz}ƒ‰‹Šˆ†ƒ€‚ƒ‡Š‰‚|xvux|~~~~~~„‡ŠŽŠ†{uuvx€‰Œ‡‚~}{„ˆˆˆ†ƒ|{y{~€€‚‚‚…ˆ‹ˆ†„}{z}†‡ˆ†€zz|‚„…||‚†Š‹†‚€}||}}}~‚‡Œ‹‰ˆƒ|||„ˆ„{}€€€„‡ˆˆ‡zz€‡ŠŠŠƒ{v{€€€|vqux|ƒŠŽŒ‡‚‚‚ƒƒ„€ysuwz|€€€‚†‰ˆ†‡‡‡…}zxwz}€ƒ„‡‰‡…„~yx|€€€‚„‡‡ˆ‡„}|ywvvwzˆ‹‹‹ˆ„‚‚‚zusss}‡ŒŠ‰ˆˆ…‚}zxwvsplu~ˆŽ”•ˆ‡‡‡„‚~vnkmot|ƒˆ‹†ƒ‚‚‚‚xokqw~‡‰…||€„‚~ytolt{ƒ‹“”’Š„|yvsponnu{‚˜›˜”‰|quy|~€|wqx€ˆ‹Žˆ‚}zwy{}€„†‡‡‰‹ŒŠ‰†€zxz{|||~€‚„†‡‡ˆ‰ˆ†ƒ|{{{yxx{~‚‰ŽŠ†‡‡ˆˆ‰„{rooow~‚€‚ƒ‡‹Ž‹‰†ƒ€€ƒ‡†~vromy…ŽŠ‡„…Œ”‡€{vsssy€†††…‚‚ˆŽŽ‹xtwz~‚†‡ˆ‡†„„„„ƒ‚}|||~€ƒ‡Œ‘Šƒ|{}€yqjmqw‹Œ‡…†‡††…ƒ‚€~{yxvwxy{~€†Œ‹†€Š“—„|zwlb`jtŒ™–“‘‘‘‡zlmmnnorx~ƒ‰Ž‹ˆˆˆ‰ˆ†„ysrqrx}„Œ“އƒ„†‡ˆ‰…~xuqqx„‡Š‰ˆ‡…ƒ}ywwwz}€‚…††…†††‚}zz{}…„‚€€ƒ‡…~wx{~€€€„‡ŠŽ‘Š„~ytnhbis|‰—œ•މ„ƒƒzwvvy|€€€€ƒ„‚‚„†…ƒ€~|{~‚€}|~ƒƒ„……†„‚€€‚…‚zrsw{ˆ‹†‚‚„‡‹“†€ztsuw{€ƒ‚€€ƒ†ˆ‰Š‰ˆ†~uqrsz„‰„~}‚—”†‚~ztnouz}~|~…ŒŒ‡„…†„}ytpqsu{‚‡‰Œ‰…‚‡ŒŽŒ‡~vvy|‚‚|vw{„‰ŒŒŒŠ†~{y{}}}|{zy}‚‡‰Š‰‰‰Š‹Œˆ„€}zy{}€‚…„ƒƒƒƒ…ˆ‹‰…€€†ŒŒ‡|xsw{‚…ŠŽŒ‹‡ƒ~xromlt~ˆˆˆ‡„‚†”’‹wrrrtwz}€€€…‹‘Œ‡ƒ{|‚‡ƒ}xwwy~ƒ„ƒƒ„„………ƒ~yxxxz{}~€„‡‰‹Œˆ„€}{}†…‚€|yy‰‰…}zx{€~{~…}{€†‡„~}{„††…„‚}wrpoqy†ˆŠ‡„ƒƒƒ‚‚‚‚‚}vruy}ƒˆ†x}†Œ’’Š‚|xsx|€€€}{|||‚„‰Š‚zz{|‚‚|wx~ƒ…††„‚€€€~{y}‚„‚‚‚„‡‰‡…ƒ‚€}yuuvx†Š‰‡†††„‚€}zxxw{‡†„ƒ{}„Œ‹†‚}yx}ƒ†‡ˆ‚{tx|…Šˆƒ}}~€„ˆ‰„€„‰Œ‰†{ux†„‚„††††…„‚{somks}†††‡‹Ž“™Ÿ–Šsgdoy{zx{}€†‹ŠˆŠŒŽ†~y{}~€{uox€‡‹Š‡ƒ‚„„‚€{tmry€ƒ†‡‡‡‡‡‡‰‹Šƒ|wvuy~‚‚‚€‚„‡Š‹ˆ†ƒ~€€€}z|}}{{€…ˆŠŒ‰…€~}|{zyxxy}…‰‹†‚ƒƒƒ‚€€€{urw|‚ˆŽŒ†€~}|{{{{~ƒ€…ˆˆ‡‡ƒ}~€€€~}|z{{|~………………„‚}|~€€€ƒ…ƒ‚€€€ƒ…„„„……„ƒ~zvx{|zwvuy‰’‰€z|~„ˆ€vljhkx…‘Ž‹‡ƒ}}~|xuvwx€ˆ‹‰ˆ…‚€€~|~€ƒ‚€~}~‚††„ƒ€}|ƒ„‚€‚…‡€zx}‚„„„‚ƒƒ€ƒ„……„{z|}€ƒ†……†ŠŽŒˆ„€|y{}}zwwxy{~€†‹‹Š‰ˆˆ‡†„ytroty€‚ƒ„…‡ˆ†„„ˆŽˆ‚{rjs~†…„‚~yz}„‰Œ‡‚~~‚„„„‚€~€ƒ„~}~ƒ‰Š‡ƒ~}}}|||}€ƒ…‰Š…€yspv|‚‡ŒŠ‡…†‡ˆ‰Šˆ„€yqjpw}‚‡ˆ‡†††…ƒ~€‚†Š‡€xtppv|€‚„‚€€„ˆŠ‰ˆ…€z{||{yy|~‚‡Œˆ„€€€ƒ…‚|~€…ŠŠ…}yu{€„ˆ‹Š‡„}ywtuz‚‚‚ƒƒ„…†…ƒ€~}}~ƒˆˆ„~}|…†ywww~†Œˆ„ƒƒƒ…‡‰xqsv{ƒŒŒ‡ƒ„„„„„‚}ywww{ƒ„†…ƒ‚|z‡‰…|wqtx|ƒ‹Ž‹‰†ƒ€}|wrooou}†ˆ‹‹Šˆ‡…ƒ„…†{vrmlnpqqry€ˆ’›¡¢¤›’ˆ…‚}umklmoru|ƒŠ–“‹„‚€€ƒ‚‚‚€€€}zxwvy|€…‰‹‰†„ƒ€€€€‚„…ƒƒ†„‚€}zy|~€‚„ƒƒ„ˆŒŽŒ‡~upkhnty~„ˆŒŒ‡…‡ˆŠŠŠ„|tuuvz~„‡ŠŽ„hL6$C„¾¼ºº¼¿ÀÀÀ°ŸwaRMILRWhy‰—˜•’™¡©¢œ•„„…ynfffhlotz‹•ššš˜•’Œ‚ypibdjosvy|~ƒ‰Ž‹‰‹ŽŽŽŽ‡}ronntz|zwzƒ‰––—”‰‚yqlgeimrw|ƒ‹“—𙑉‡ˆˆ…‚xqouz~‚…‰ŒŽŽŽŒˆ…wdQ53[šÚæßØÛÞÛʸž{X@-"*8UsŠž²´³±°®­«¨™‚jggis}€ztokgjmpuy†Ž˜£®¯°«›‹}rf[QIPW_is~ˆ’›¤ª©¨¢“…ypfikkhehqy‚‹“””’މ…ƒ}}~~{ywww}„ˆ†ƒƒ…‡•–ކ}ut|…ˆ‰Š€wg>?ÞÚÕÕÞçèäàà}Z73Li†¡°¿ÆÃÁÀÀÀª’~vojhfhjklljbZ_n|ˆ“žŸ¡£¤¥¦¦¦šŒ~oaVQKQ\fox€ƒ†Žž®¯«¨›Ž‚{spppkeaejq}Š‘’Œ„Š•œž ˜yrnquutsz…—ž£žš–“†{plihhhT.%S‚±ßõ×¹¼ÔìàÏ»”lM;*%&'Cb~‹˜ž£«³»ÃÁ§}{yvsh]UQNS\fsŽ‘•›¦±´´´¥•…wh^\YYYYaiqx€‡—›ž ›–‘‰„ysmgfdfkpv{€ƒ…а¸±ªœ‰wtspjcaceq‚“˜ŸŸžš“‹ƒ{sok\6 %Jh…šª»® •••—›Ÿx`fks‚‘Ž{hefhov|}…š¢ª°§Ÿ”…uh]QX`hov~…”š   œŠyomknqs{‚†„‚{x{}€‡Ž‘‘‘ŽŒˆƒ~uljqx{|}ƒŠ‘˜ŸŸ—ˆ€xS-;“ëíÖ¿¿¿ÁÈε‡XH?8;>G[pƒ–©¨¥¢¢¡   ”‚prsv€‹‡vd__`is|…Œ” ¢£¢ œ„xk^^_airz‡“™•’Œ‰…yz{|~~|zyyy{}€†‹’™ŸŸœ˜‡vmiijnu{„‰’𡤧€ztg> #:tºþÛ¹¥¶ÈÐÐÐ¥p?9317=QnŒ›©³«¤Ÿž›™˜…pbks|‡’‡velsxxxyz{‚‹”š¡£ –ƒwkacfiloruw…“ ¢¥ ”‡‚€~}}{uokkkqx‚…‰—›Ÿ¢›“‹‡‚|tkijkryˆ•˜›™”‡y|j; /{ÇõÓ°¦²½ÄË͘c???ADGYm’¢¨ž••˜›ž¢Ÿ‡ogr|†˜„oadfkrz}~€†‹“Ÿ«¬¦¡“…wnebglkhenw™žœš“Š€€€|sjijly†’“””“Œ„|qgglquy}…‹“›š–“‘އ€xofI%(Q|±æêÜ©ÅÞÓǯw@-4;;;>]|•¤³°¥š §¬ª©œ‚hhtƒ€o]Yaiosx}ƒŠ“›¤«³¯ª¥—‰zhWONMWbmz†’¨­¯°¥™‚wnhbcegnt{„“—›š™—‰‚|zyxyzyyy{†‡‡‡Œ‘”Œ‹‰ˆt_I,Ft¢ÐûÙ·¨ÇæåÍ´‡U)06;=?Ne}¡¯ª¥¦®µ±¨ Šrdu†Š€vmd[bipx€………ˆŒ °¶­£—ˆzrke_XX_eq€Ž‘“•–˜–‘Љˆ…‚~xrpppqrsz‚Š“œ   ˜‡~vpnljgenw‰‘•••‘‹†……†ŠŽ„mV:/]Š´Ýã˳¿Òâɰ“kD7;?CFL\m~¡  ¥ª®¯°¨–…‚‚xoe\SU_irzƒ‡Œ’›¤¥¢Ÿ™’‹‚ypg]]bgox€†Œ’™Ÿœ–Š„{wtrpqrtx|ƒ†Š‘Š„€~|zxvttwz}‚„†‡‰Š‰‰ˆ‰Š‹‰ˆ‡„~xrnkgaZUeu…™¬±­¨¥£Ÿ“‡{odbdfggitˆŽ•—˜˜–•“’Œ…}xtonmou{€…ŠŒŽŽŒ‰†„‚}xsrqsuxz|}ƒ‰Ž’‹‡„‚~ulmt|…‡„€€†‹ŒŒŒˆƒ{xurptz‚‚€‚†ŠŒŽ‰ƒ‚…‡„€ƒ‚€{vqpnmkhknq}Š— ¨¬ª¨¢™†|rkdcfjpw}‡‘———”Š…€{{{}€ƒƒƒƒ„…„„ƒ‚‚‚…ˆ‰†‚‚ƒƒ‚€~}||{|~€‚‚‚ƒ…ˆ…}||}~€~zvz€‡‰‹‹†‚€‚€€€€€€‚ƒ…‡‰ˆ{y{}‚€~‚…‡ˆˆ‡…„‚~{xz~„‡ˆ…‚ƒ‡ŒŒˆ„}wuwy{||xsrx~„‰‰ƒ}{~€|vx€‰Ž‘”…‚‡‹†yz{~†ŽŽ‰„€|z|~~~~}||…ˆ…‚|y|‚}}~€‚„‚€‚}yz|~}|{{z|†‡…„€{y{}‚…„ƒ‚€~~€‚„†ˆ„z}€€€€~|y{}€†ŒŽŠ††‡‡„‚~€}yu{‚ˆ‰‹‰†ƒ„†‡„‚~yssw{ƒ‡‰ŠŠ‰ˆ‰ŠŠ‡ƒ|xuuuy~ƒ…†ˆ‰‹‰†ƒ„†‡„‚‚‚‚€|yz}ƒ†‡ƒƒ‚‚€€‚„‚|}€‚…„€{|}ƒ‡‰‡„‚€„†‚~{zy{}„†††……„ƒ€€€}zz{}€…‰‡……†‡ˆˆˆ„z|~€‚ƒ‚}y{‚„††„‚ƒ…ˆ…‚‚ƒ„„…ƒ|{z{€„†„‚€„‰‹‡ƒ{x{€…„„„„„‚€}||}‚„„„ƒ‚…ˆˆˆ…xwww}„ˆ…}{…‹Š‰ˆƒ~~„‚€€€€}ytx|€„ˆˆ„€‚†‹‰‡…yx{~€€€|yx~„ˆ‹Š†ƒ„…ƒzz|€€~~~€„‡†…„ƒ‚ƒ„†‚{zy{‚‚€‚ƒ„‚~z}…ƒ‚€…‰†ƒ|yy|~{x{}€„ˆ‡€y}…‹‰†}tsx~€€€ysr~ŠŒˆ„‚~‚‡ˆzz|ƒƒ~yy…†……€|y~ƒ„„„ƒ€€‚„„„„‚€€‚ƒƒƒ‚€‚„††„|z}‚€‚‚‚ƒƒ„„„‚~z|€ƒ†ˆˆ†„‚€~€‚‚ƒ~{{}~€„‡‡†„‚|}€‚ƒ‚|~€‚„††„‚‚‚‚€€€€‚…†}yyy}ƒ‰‡††‡‰‡…‚€€ztty~„Š‹‰ˆ‡†„‚€}{yvsv|ƒ‡ŒŽ‰„‚…‡ˆˆˆzvz}€ƒ…€zty~‚‚‚ƒƒƒ…ˆ‰‡„}z{}€€}|||{zz~…ˆ‹Š‡„ƒ‚ƒ„‚}xx{ƒ„‚‚ƒ„…†„‚~~~~€€€ƒ††…„|xz|~ƒˆ‰‡…ƒ€€ƒ…ƒ~ywwx|€„„„…†‡‰‹‹Šˆ…€zwvvwyz|~ƒ††††‡‡†ƒ~|y|€„„„ƒ‚€}{|}}{xx{~„Œ“Š…}}€ƒ~ulpty‰‹ˆ„…††…„‚~yxyz|~~ƒ‚€}zy„†„€ƒ‡‰…‚€€€~}{{z{}‚†ˆˆˆ‡…ƒ„†‡ƒ~yxwy|€‚„…ƒ‚ƒ„„„ƒ€ƒ…‡…‚€~||‚|}}~‚†ˆ†„ƒ‚‚€~}}~€€€„ˆ‰‡…}y|~€‚ƒ…†‡‡‡…||}~ƒ„ƒ~|y{ƒ‡ŒŽŠ†ƒ‚€€€}zwusvz~„‹‘‹ˆ†„‚~zwwwy~ƒ†‡‡„€ƒˆ‰ˆˆ„z|~€ƒ‡†‚~ƒ‚‚€€‚„‚ƒ……ƒ€~}{„†„~{x|‚‰ˆˆ‡„~~€‚ƒ€~|}~„…„‚€}~€€~‚„ƒ‚€ƒ„„…ƒ~z|€ƒ€~}~‚ˆŽ‹…€€€€~|}~}}}~~~†‹Šˆ‡{z~‚‚€|yw|„†‡ˆ‰‰†„~{zzzyxy{}‚…‡‰‹ˆ…€~}|{zy~ƒ†††„€}{zzyyz{|}ƒ„…‰ˆƒ€~}|{xvuwz}‚‡ˆˆ‡†„ƒ‚‚€€{vsuv{„‹…€…Љ…~~~‚€}}}}~‚…ˆˆ‰‡„‚…‡„‚{wx{~}|€…††…„ƒƒ‚€}}~€‚ƒ„„…†‡‡…‚€}yx{~€‚„‚€‚„„„ƒ„……ƒ|zz~‚…‡‰…€}~€ƒ~|€„ˆ‰Šˆ…‚ƒ…‡„‚{wy}‚€|y{~‡Œ‡‚ƒƒ‚€~xrty‚„………‡ŠŒŠ‡„{y|~‚ƒ„…„„ƒ‚€€‚„„‚€€€~}‚†ˆ‰Š‡…‚€~{xwww~„ˆ…‚}z…‰‡…‚}yz…†‡‡„€ƒƒ€}}~„‡…„ƒ‚€ƒ„€|{{{~‚‡…‚~}{xz}‚…†††…‚€„„‚}{|}}‚†‡‚|{}…“Œ…{xz~‚€€‚€~|zyyz~‚†‰ŒŽ‹ˆ…ƒ}unifcnx…‰Šˆ†‹‘•‰ƒ{tqqqv{€„ˆˆ…ƒ€„„}{{{ˆ‹‡ƒzwwwy{}}}ƒˆˆˆˆ‡†…€|xwvy|€€‚ƒ…ŠŽ‹ˆƒ~yxwy}‚‚ƒ„ˆ‹Šˆ†|x}ƒ„zyz{€†‰…‚„†„‚‚„†ƒ€~|{zzz{{{‡ŒŒŒ‹ˆ†„„„‚|yvsory‚„‡‰Š’‹ˆ{wwwxyz{{|„ŒŠ†‚}€‚ƒ‚€~{wx|„„„ƒ„……ƒ€}~€‚ƒ…‡ˆˆˆ…‚~}{z|~€…ŠŒ‰‡†††ƒ€}yvvy{}€„ˆŒŽ‘‹‡ƒ~{yxxxy{|~€ƒ‡ŒŽŒ‰…€}ywxz||}~„ˆŒŒŒŠ…}yv|„„ƒ‚€ƒ…†‡†ƒ~zwz}~~}~€ƒ…†ˆ‡…„‚~}€…‰†‚~|{zz{{{ƒ„„ƒ…‡ŠŠŠ‰‡„‚‚‚zuuuvy}€ƒ…†ˆ‡‡††…„‚ƒ…‡|wwwy|}|{‡ŒŒŒŒŒ‡{yvtrprvy{~€…ŠŒ†€ƒ…†|xtqrtu|ƒˆˆˆ‡…ƒ‚‚€~|zvszˆˆˆ†ƒ„‡‚}xvsu|ƒ‡ŠŒ‹Š‰‰ˆ…ywwx|‚~zz|ƒ‡‰†‚€€€ƒ„ƒ‚ƒ…††ƒ€~}~~}zvvy{€‡‹‰‰ŠŒ‹‰ˆ‚|wy{||||||€…ˆˆˆ†‚~~€‚‚ƒ„……ƒ€~‚…†„‚€}y}ƒƒ‚~||~ƒƒ‚‚„‡…„‚€}}|}~ƒ„€}|…ˆŠŒˆ„€‚…‡…€{|~€€€|y|ƒ‰†ƒ…‰ŒŒŒˆ{‚ƒ}wuuuy~ƒ…†‡ŠŒ†€}{xvrotz€‚…‡ˆ‰Œ”†zuv{€~{x{}‰Šƒ€~}|{ywx|€ƒ„…‡‹‡€}yx}‚‚}yz}ƒ†ˆ…ƒ€€…‹ŽŠ†}yyz{~‚‚~yz|‡—Ž…~}€‚€zuuz~„‡ˆˆ‡†…†ˆ‰†ƒztsw{~€~||…Ž‘‰„z|~~|{{}€€€~|}„‹Œˆƒ€~}€ƒ‚|vw{~}{zyz€…‰Œ‡„…‡„zuqmptw}‚‡‰ŒŠ‰ˆ‰‰Š‹Œˆ€xtrrx‚€}|‚………†‡ˆ†…ƒ„…„‚}wqooou{€ƒ…ˆŠŒ’”‘ŽŠ†‚}wrsuutsty}„‹’‘‘“‰‚|wrrrqqqu}…‹•’‰„€|xvttvx{€…ˆŠ‹ˆ„€€€€€€~}‚„„„ƒ~}|zyzˆŽ’—‘‰‚ƒ‚~{wrmpsv|‚‡Œ‘–™—‰„zvsnjekqx†Œ‘–•’‹†„‡‰…|tsstw{|{z}‚‡‰‹‹‡ƒ‚…ˆ‡††€yux|~€}zw}‚‡Œ‘Š…}z|{xxyy}„„ƒ…‰‹ˆ„~{zyz}~}}€‚…‰‰‡…ƒ€~}||||~€ƒzw{€…ˆ‹Š‰‡††…„‚€}zwvtsqrw}‚†‹Šˆ‡ˆ‰Š‡}zyz{zvrswz„ˆ…‚‚…ˆ‹’ˆƒ~ywwwvvv|„„„………„„„~yx|€€€€}zy{~€‚€ƒ†ˆ„€~}|}€‚…„‚ƒ‡‹‡ƒ|z{}€~}{ywx~…‰ŠŒŠˆ‡‡ˆ†„|vptx|‚|}~…Š‹‰†ƒ€„‡‡…ƒ~wqrtv|ƒ…€{~„‹‘—š’‰ƒ€~{xuqlkryƒ†Œ‘—˜˜•„}wqqrqolnu|…Ž—“ˆ‡†…„‚~ytsstz€„†‡…‚€‚ƒ„‡‰ˆ…€€€€€|zz|~}||}†‹‹ˆ†††‡‡ˆ…zurotx|†‰‹Œ‹ŠŒŒˆ…€xqqrtwy}„Љ†‚„†ˆŽ““‹‚~{xyzyvru}…ŠŠ„ƒ…ƒ}{yyy{}‚…††…ƒ€}~ƒ„„ƒzz|ƒ‡Œ‡‚ƒ…†‡ˆ‚|yyz{}~„…ƒ‚ƒ‚‚‚€~}|~„‚}|~„‹‰‡„ƒƒ„„„„„„€|wurqtv{†ˆ‰‹Œ’•‘‰zsoooquy}…”˜ˆ}xz~}zwwwz€…„‚‚ƒ…†††ƒ}xwwx{~|y‡ŒŠ‡ƒ|||zxwz}€€€‚„†‡ˆ‡…‚€~|{yxz|‚†‡„‚ƒƒ~|zyz~‚†‰Œ‹‹ŠŠŠˆ„€|wqpoptxˆ’’‘‹‡ƒ‚€~}{|}„†ˆˆˆ„€}{yyyy|€„†‡ˆˆˆ‰ŠŠ‡ƒzupmiaUITcq†š¨¨©­²·¯§‹zmga][X[]dx–•”˜œžœ™”†xuzzurz‚‰ŒŠyxxwspooowƒ•›ž•Œ‰‰‰„~xtpoty|~‚…ˆ‰‹Š†‚…†††‡‰‹ˆ…‚{torvz€‡…ƒ€†‹‘‡€€€~}~€~|{|~€€}{ƒ“’Œƒzz}€€|z|€„ƒ€hQBGM_|™ ¡¢¬µº¹¸­œŠ{l_XRQW]gr}€ƒ†Ž•› ›–Šˆ„{wsrpptwuqlorwƒ••”—𙕇}vqljiijjkosy‰Ž‘”””“’‹‚yslhmquuuy€‡ŠŽŒ‰†„ƒ„„„~xuxz|~€…‹ˆ‚‚ƒ„……„ƒ‚‚‚€}zvrbRC7+<\|’¨º¿ÅÈÊ̵¨ŒnTE53K^tŠ•ž¨µÃÄ»²¥—ˆ‡…€uia\W]elmoooou~†˜¡©±²ª¢š’Š}oaVJFJNZiw€‰“¢°´®©Ÿ“ˆvme^alvwwx{~‚‡Œ‹Šˆ‚|zˆŒŽ‰†…„ƒ{xurx€ˆ‹ŽŽŒ‰„uj]:?mªÅÿ¾ÓèíÝÍ®ˆbL7(.4=ITf{™¢¬´¼º²©ƒ‚~xrmidefgmtxyy{}†• «¬ •†€€}rf`__elt~‡‘”‘Œ‰†{utuvy}€€‚‚‚€€ysq}‰“𢛑ˆ„€€€~zw}…Œ‘——‡€yrS/*o´¿¬˜¹Ýùòë׳ŽpT84009CRf{‰•¢­¸ÀÀÀ±–|~…Šƒ|vqkloqtvvpijqy€ˆ”˜¡¦¤•ˆvkc`^_bekqx‚”–˜–“‘‰{}~~}|{yx{}€ƒ‡ƒxmlnoƒ–£¢ ›’‰‡†„zpkpu~ˆ““’‘ˆ€seI&5o¡®º¾»¸Êäþèѵ†X:/$$&(;7:2:BFIL\l|ž©°¶¼Áê}wqv‹zeU\bhnttqo”¤§©¨¤ ™ˆvmd[Y[^ht€†’•—šŸœš–‰|qjccfinsy‚‹“™ Ÿš”Žˆ{uojmquwy|…‰ŠŒ‹Š‰‡…†ŠŒ†€†}jU=$&2?lš¿¿¿Ç×çáÔÇ¡{\M?=DJNQUk•¦·¶¬¡ŸŸ“ŠzsppponnnntŠ‘•™›œœ˜“…}wqkighmrx}ƒ‰–—˜•ˆ„‚€}{xsmlnov€‰‹ŒŽ‹…~}|xusqpsvz„ˆˆ‰ˆ‡†……„‚~}|zy…Š‹Œ‹‰ˆƒ}w{~}qf^YT`p€•©¶³±­©¥ž–Ž|k___dkrw|Š’–”“‘‹‡ƒ~}|yvuuuw|…‰Œ’””“Š„}umllmquzˆˆ†…ŠŽ‰ƒ~|y{~€~}|||~€‚€€ƒ„…‡…‚|zy~ƒ………„ƒ‚€}|}„‚|€„ˆ‰Šˆ„€€€€‚„…‡‰‹‹ˆ„~{ywuvwxz}ƒ…ˆ‹’˜œ—’†€}zx{~~~~~~~€„‰Š‰ˆŠŽ‘‰…ywyzyxxz{~„ŠŽŒ‡ƒƒƒ‚€~{wvuuwz}†…‚€ƒ…ˆ‹Žˆ}qv|ysrtw{‡‹‘‹‰‡…‚zustvx|„‰Œ‰††‰Œ‹‰‡‚|y{~~}|~€ƒ„†††‡ˆ‰ˆ‡†‡ˆ‡„€€€}zx†Š‡……‡ˆŠ‹‹‡‚~|y{~‚€}{}„‹‰„€ƒ…‡ŠŒ‰„|xurpsy~‚„…„ƒ†Œ“’ˆ„{zxwvvxz|}~ƒ‡ˆ‡†………ƒ~}|}~€ƒ‡Šƒ{ux{ƒ‡…}„ˆŠ‹Š…€€|z{~‚ƒƒ~}€ƒƒ‚€€ƒ††„~|{|~€€~„‡ŠŒˆ„†‡ˆƒ|ywwxx{}€ƒ†‰ŒŒ†€ƒ‚€}xruz‚„„„ƒ‚‚‚€€€}zz|~€‚‚‚‚|ƒ‡…ƒ~{|~zvy|„ˆŠŠŠ‰‰‰†ƒ€}yz||wuvwyˆŠˆ‡…„„‡Š‹Š‰†‚~{wvvvx{~‚…ˆ‹ŽŽŒ‰…‚|zzyxwwyz|€…‰‹‹Šˆ‡†…„ƒ‚|zxvwwx}ƒ‡‰ŒŠ‡…†‡‡‡‡…}zwvy}€‚…„ƒƒ…‡‡†…„‚€~~~~€‚„………††…„ƒ„„„ƒ‚~{yyxz|ƒ„ƒƒ…ˆŒ‰†„|z|}~~‚……‚€ƒ‡Š‰‰ˆ„‚ƒ„„ƒ~|||}~€ƒ†‰Šˆ††††„zvvz}€‚„‚‚„…†††††}yxwz~‚€„ˆˆ†…ƒ~}~„†„‚€€€‚‚€€€‚„ƒ‚ƒ„†††„€{zzz~‚„ƒ‚„„„„€{y}‚€~|{‡Šˆ†…ƒ‚€{wuuuy€†‰ŠŠ‰‡‡‡‡†„ƒ~zusrsx}„ˆŒŽŒˆ…~|yvuwy|‚‚‚ƒ„…………ƒ‚€ƒ‚€|y{~€€‚„†‰‡…„{xxxz|‚…†…ƒƒƒƒƒƒƒ„„ƒ‚€€‚ƒ~yvy|„ƒ‚„‡ˆ‡…………„„„~xuwy|€„„„…†‡†††…„ƒ„„ƒ~yx{~€‚{z|~€‚€ƒ‡ŠŠŠ‰ˆ‡…ƒ{tqrsvzƒ†‹‘Ž‹†‚€}{yvtquz€€„†‰‹Ž‹‡ƒ‚‚€~|zyy}‚€~}„†††………………„ƒ‚€}zxz|}…††…†††‡ˆ‡ƒ{{{|}~€ƒ„„„ƒƒ‚…ˆ‹ˆ„|xx{~€€€~}~‚††††„€ƒƒ‚€€€‚~zy|~€‚ƒ€€‚ƒ„„„„„„‚~|||||||€„†…„ƒƒƒƒƒ‚}}|~€‚€~}„‰‰ˆˆ‡…„ƒ}z|~~~„‡…ƒ}~‚††…„ƒ‚€€€|z|ƒ…‡‡„€€€€€€~}}}}~‚†‰†ƒ}~„~{zxzˆ‰†„~}}~}{z}€ƒ„…„ƒ‚„†„‚€~||}~}|{{|~„„„ƒƒƒ…‡‡†„‚€}|||{z{}~„‡†ƒƒ„ƒ€‚ƒ„{z~‚‚‚€~~€‚„„…„ƒƒ…‡ˆˆˆ…zyzzzzyxwz€†‡‡‡‡‡ˆ‰‹ˆ„€€‚……ƒ€}|~~||||‚†††…„‚ƒ…‡†……~|||{ywz}€‚„††‡ˆŠŒ‰…~{{{|{zy{}ƒ‡ŠŠŠ‰‰‰‡†„|yux|€ƒ…ˆ‡††††…ƒ€~~€ƒƒ„ƒ‚€‚ƒ…††…ƒ}|{zz|}~ƒ†ˆŠ‰ˆ‡…‚~}|{z{€„††…ƒ|ƒ„ƒ‚~|~€‚ƒ‚{|ƒ~€„‡…}€ƒ†‡ˆ‡„~{yz{{{{|‚„…‡‰ŒŒ‡‚~|y{~€~}}}~€‚„……††‡†„{xz{}~€‚„………„„„„„‚|{zz{{|€„„„„‚€‚…†ƒ~|y{}€€€‚„ƒƒ„„„ƒ€„‰Šƒ|vtquz‚€‚ˆŽ‹‰„~{{{ywuvwx{‚„‡‰ŠŒˆƒ}{{}€€€€ƒ‡†ƒ€|wsw|€„‡†‚„‰Œ‹‰†€{xwwy|~€‚ƒ…ˆ‹‰ˆ†ƒ~{xz|}…†„‚‚ƒƒ‚‚~|yyy|‚‡††…ƒƒ…‚|}€‚ƒƒƒ„…†|y{}~€~ƒ‡‹‹Œ‰…‚ƒ‚€|yz{}~€~|~‚†ˆˆˆ‡†……„ƒ‚‚€~}}|||~…ƒƒ†ˆ‰Šˆ…‚|{}~€‚„‚‚…†‚~}~€€€~}…‹Œˆ„ƒ‚zvsqptx|~€‚„‡Š‘ˆ„~|||zxvy{~€‚„„„ƒ‚‚€€€€‚‚ƒ„………„ƒ~|{yz|}€€ƒˆŠ‡ƒ€}z|}zz~ƒ†‡ˆ…‚…†ƒ~zwz|‚‡Œˆ„‚€€€€~|}~~€}{}…„‚‚„†ˆŠˆ„€€}zxxxz}‚…ˆŠŠˆ„~xxxwustx{ƒ†ˆŠŒŽ‹†~~€~xsty~‚†ˆ†…ƒƒƒ‚‚‚}|~€{wy|‚„…ƒ‚„‡…ƒ€}}€€€~}|||~ƒˆˆ‡†ƒ€„‡‡‚}{zy|~‚†‰‡†……„………}{|~~|zyxw|‚ˆˆˆˆˆˆ†…ƒ‚€~|yvx|}|}€‚…‰ŽŒŠ‡…ƒƒ…‡…ƒ€ztpw‚‚‚ƒƒƒƒ„…‡…€{xvuy}€…‰ŒŒŒˆ„€}zwsoqw|€„ˆ‹ŽŒˆƒ{wvvvxz|€„ˆŠ‹‹‰ˆ…ƒ€€€€€€€€€ƒ†…ƒ€~~„ŠŒŠ‡„€}{zzzyvtuvw€‰ŽŒŠ‰‰‰ˆ‡‡‚}zzzyyyxxy{~„ˆˆ‡‡‰‹‹ƒ|y{|}~}{{~‚…‰Œ‰„€}zyz|~€ƒ„……„ƒ„†‰‡ƒ€}zyz{}‚ˆ†|}€‡Œ…~}€}zz~ƒ„‚€~€‚„…‚€€‚ƒƒƒ„„„ƒ‚‚‚‚~zvtssx|€ƒ†ˆ‰Š‰‰ˆ†„ƒ€|xsssu{„…†…ƒ„…†„}{zzxww|„†ˆ†„‚ƒƒ‚}{yx{€‚„„„„„„ƒzy|~€‚€„‡ˆ†„‚€~{yxxxz|ƒˆ‰†ƒ‚€€€{uqtw|„‹Œ‰…~}€‚|xtpoy‚‰ŒŒ‡‚‚‚‚‚‚€{wz}€€€ƒ‡Š‡ƒ~|y{|~€‚ƒƒƒƒƒƒ‚‚‚€ƒ…ƒ‚ƒ„†ˆ…‚‚ƒ†‰†xy{|†…z{ƒ‚‚ƒ…†ˆ‰‰…}…†ƒ}wqtx|‚|†Œ‘‘Ž‹ˆ…}zvz}ysrw|ƒ‹“‹‡„€…‰‡…ƒ{spuz}~ƒ‡Š‰‡†…„xqsvvvvy…‰ŒŽ‹ˆ‡ˆ‰†yvsqvz}}}‚…ˆŒŽŒ‰‡„~|zyyzz{~ƒ‰‰†„‚€~}|}~~„‡ˆ‰ˆ†„ƒ€|wqpoortz‚ŠŽ’”“’‘އ|qnkkklnsxŒ—˜˜–І„‚}vponpv}€€€…ŠŽ‡€€€|xvwxy|€€€€‚…„}€‚…ƒ{x{ˆ†ƒƒ††ƒ~{x{}~}{{}„‡†…„ƒ‚€€‚ƒ†ˆˆ†„}y{|zvroooz‡”•–”‘Ž‹ˆ†|wtqnlkpx‡”‘Їƒ‡‹†~vrmpzƒƒ…Љˆ†ƒ€€€€€‚‚~{www{‚Љ…‚€~~ƒ‡ˆ‡†‚~{~„„„‚€~|zy~‚„ƒ‚~…ˆˆ‰†€zz|~ƒˆ‹†‚}|€„ˆˆˆ†|{|}€ƒ…ƒ‚†ŠŠ‰ˆ…ƒ€€€}xrrsuy}ƒ†ŠŽ“’މ„~}||xtrw|…‰‰ˆˆ…‚~}~~‚†Š‰ˆ‡ƒ~{xvwxx{}€€€ƒ…‡‰‹Š‰‡ƒ~€†Œ‰„xqoty{{{|}~‚…ˆŠŒŠ‰‡‡‡†„~{wz}€}zy|~ƒ…„„ƒ‚‚…‡†ƒ€€ƒ††„~{xz{{tnnv}…•“‘‹Š‰ˆxpmklpuz€…ˆŠŒŽˆ‚~}{}zuuz~„†ˆ‰‰†ƒ~|ywtuuw‡Š‰ˆŠŒŒŠ‡„zuqlosvwy|‚‡Š‹ŒŽ‹wvy{wsqqqu|„‡‰‹‹‹ŒŽ‹‡‚€~|{yyyy}„‹„|wz}€€€~}„ŠŽ‹‰‡††„‚€}{yyxyzz}€„Š‘Šƒ‚†‡~uqrsz„ŽŒŠ‰‹ŽŒ‡}yuvwwwwz€†Œ’–”‘ŽŠ†€zunhchlr{„ˆ‰ŠŽ‘“‹„~|yxwvy{}……ƒ€‚…‡‹‰ƒ~|y}ƒ†„}z~ƒ‰‡…ƒ€€ƒ†„~…ˆˆˆ…yz}€€{wx{…Œ‘‹„‚†‹‰…€ztpw‚€„ˆ‹‰ˆ†…„|xwwx|€}ƒ‰Ž‘‰„~xz~€}zwusw}ƒ…ˆ‡~uk^RVal{Š—˜™œ¡¦¥£¢—Œwmfdbdfhqy€ƒ†‰Œ“—™‡ƒ…‡†…„~xu{€‚‚‚}wqrstwy{}„Š“–—“Œˆ„~vqqqqqqomks|„‡ŠŽ‘””“’‹…{xsojmquz~‚†Š‘Ž‹‡|qlquvuu{‚ˆ‹ŽŽŠ††‡‡„‚‚€€}zwz}~}|}€‚„†‰ŒŒ‹‰‡†…„€|vk`RC4AQcz‘£¬µ»¿Ä¿»´£‘}eNJMOU[bjrz„•¢¡ –‰„ysqtwutrpootyzzz~ƒ‡™žœš˜•‘Ž‹‡}skifedcgkpz„‰‰‰Œ“””“މ†††‚}xuronmnoox„‹Ž“—’Šƒ}wux{yuqx€†„„‡–Ÿ—އ„€‚ˆŽˆvvvtoj\D-8L`y’¤¥§¯»ÈÆÃ¾¬›‰xfZQHILOZeq~‹•ž§«®®§Ÿ˜‡‚~ytnkkknsxwvwxz|}ƒˆ“””“”••‘ˆzkabceimpqr}‡‘™¢¡™‘Œˆƒ‚|rhfikqx~~†‹Šˆ†‹’Š…€~~~€~zuv|‚ƒƒ„‰‘ŽŠˆ†…ƒ€€€„†ˆˆˆrYA1 &Ms†˜£®»ÌÝßÑç†dXLC?;>FN]o€Ÿ¬µ½¹­¡˜Ž…xsokkkkpuwvuvww{ƒ†‰’—˜—–“Œ†€ynd___emtx}ƒ‹”˜˜˜“މ‡„~{xusttuuu{†‘‡€…‰ŽŒ†yqkotx{~ƒŠ“”–˜›˜ƒ|uosx|}‚ˆŽsV<-/`•މ±ÄÕåÞŬ’x^SG?<9@KVj~’¡°¼ÁÇ¿±¤—Šzvpibbcclu|~€}wrx€ˆ˜œ›™˜——’މ€xqkfa^[bhoy‚Š‘˜Ÿ¦­¨£œŒ{rnjhfcb`coz†‘œ £¤œ”ˆ‚€€€sdZagq’“”—™œž ›†~}}~}zwwwwk]N6#]˜«¦ ¥«³ÎèíÓ¹™wTNJE@;:73DUj‡£³»ÃÂÀ½¬›Œ‰}o`__`cfjnrtuw}ƒ‰Œ”™Ÿ  Ÿ™“ˆ‚xma^[[`ekt}ƒ‰˜¡¦Ÿ—‘Š„~|qg___gv„‹‘’•rooq•„€†ˆ€„Š’‹…tF #:d“¿¡ƒ´èøíáºc\UNHB:1(A_{•¯¿Áü²¨¡™’‹ƒwgVW]dkswtqrtw–•““–™˜—•Œ†~vojdehknquz€…ŠŽ”š —Ž‡„}wqqqpmjks|„Œ””’‘Іƒ€~|{€†‰…‚ƒ‡ŒŒŒ‘Š…s]G-Z µ¤“•š¢Åè÷àÉ£tFKV]H4*,/Mx¤­³º¿ÅÁ¶« –ŒwmaUVbmu}‚{trx}†›”‹…‡ˆŒ‘—”Žˆ€wqsuwxxuroxˆ‹ŽŽŒ‹Šˆ…‚~zusrqv{€ƒ†Š“›—Œyqmy…ˆvzƒŒ“›’‡„ˆŒŽ‰„|y`5 $sÃæ®wƒ½÷þþ÷½ƒ[OCBEH9)":Rp–¼ÅÂÀÀÀ»©—‹†teX[]cmw}~€ztq|ˆŽ‹ˆŠ‹”›Ÿš–…{tnhgfgggmxƒŒ”žŸ”Œ„|uqnkigjwƒˆ‰Š•˜…}wqwƒŠ„€ƒ…‡Š…y„ˆ‘Š„~vJ 5^„§Ë­„e ÚøçÖ­v>EQXH9///Luž«·ÁÁÁ»¯£–‰|{yti]]dlv‰vqrs|‰—•‘”—›ž¡›’ˆ}qgdbcgknpq{„“™œœœ•Œƒ€}yuqlf_lz‡‡‡ˆŠ‹ˆ„€‚…‡‡ˆ†ƒ€„ˆŒŠ‰‡ƒ‚ˆŽ’•—†~zvcD%&uÅ輑™Âêõúö¼‚[OBDJP?.&=Sq•ºÁÀ¿Á½«šŽ‡teWTQTbqwxx{}€ˆ”””“’’”––‹„}vqnkihhknrx~ˆ“ž¢§§Ÿ—ˆxohhhiknt|…Œ“—Ž……‘œš’‹ˆ†„‚€€€€zrlszˆ‘‹ˆˆˆwEFqŽ©»˜tv±ëùñè²wILNLGA6(?d‡¤ÂÍÈÃÁÀ¿­œŒ~qf[QOOQaq}‚‚‚‚‰‘–”‘‹Ž’•“’‚vmhcdfhijnwˆ‘𠥍¢œ•Œƒzpgedefglx„ˆˆˆ—ž¡¤ —އ€zvrng`dp}ˆ’›š˜˜›ž˜Žƒwk\9PŠ¢¥¨š‹‡¶åõÞÇšd.;IRKC???^‡°·¾¿¸±§šŽ‡‚|wsnhchs~‚††|rkkkt’—¢¦« €uja_]ZXUbq€‹•ž£¨§¤ –Šysnkiggglqx‡•Ÿ¡¢›•Œ}ofc_cint{ƒŽ™™•‘Œ‡‚|wvwxQ%A“äÚ¦sœËñ÷ü麌lQ8AJK9('2=e”ÀÁÃÅÅÆ½¯¡™’Š{l_THNZfov{xtx‚–Ÿ¨Ÿ—“˜ž›’Š€vlhda`_dkr}‰”•—™œŸš–Œvmebfjqx…Šš£¤ž™“Œ…}unjfiqx|~‚ƒ…‹‘’‘Œˆ‡‰Š‰ˆ‡„‚wH "9o±óͧ•ÀëÿÿÿÍOC72;E?0"4KdºÒÌÆÃÁÀ±¡’Š‚xj\QH?Shx|{qhmw€ž»Êµ¡›Ÿ¤šŽ‚o\OOOZk{~‰’˜›™•‡yz{zyxuqnu{…‰‘’’‘‹…€yspoorux}‚‡ŠŒŽŽŒ‡‚~}~ytmaUD09e¥ºÆ¿¹ÁÓåÒ¸œuM:HVVOHPXdž°²´±­©¤Ÿ˜Š{rnjhggjmqvz€‡Ž”™œœœ˜…|xwutqnmmms{ƒ…‡‰‹’•‡€{wssrqomu~‡Š’•”””†{vuuusqotx}ƒˆŒŒŒ‰…„†††…‚{uzƒ‰†‚€€€€€€…ŠŽ‰ƒ|pd]XS\gq€›¤­²¶¹¬ž’ˆ~ulccfhnsy‰–›™–“’‘Žˆ‚}wrommv€…„ƒ…‡‰ŒŽ‰‚|yyyz{zzy|€„†‡††…„ƒ‚€~}}~€€~{…Œˆƒ|yz„„„„~yw}„†„‚ƒ„„†‡†€zz||ywy{}‚…‰Ž‰…‚‡ŒŒ†‚‚{{}‚„‡…ƒ€~{x{~€€€ƒ†…„ƒ†ˆ‰†ƒ}z{}€…ŠŠˆ…ƒ€€€„‡†ƒ‚…ˆ„~~}~~~€‚‚‚‚ƒƒƒ‚€~|}~€€€{wv|ƒ…‚€‚„„…ƒ~€~{yz}‚…†ƒ€~~}|||}€ƒƒƒƒ…‡ˆ„€ƒ|{{|€…‡„‚ƒ„……‚„‰†xvtt|ƒˆˆˆ†ƒ„†‡„}|zyx{}‚…†††‡ˆˆ…‚~}}||}~€€€‚…‡††…„‚ƒ„„‚€‚„„‚€~zvz†„…‰‡……†‡ˆˆ‰„}uy|€€€}{„‰…‚…‰‡ƒ€€‚„„‚€~~€ƒƒ…ˆ†ƒ€„†„‚€€€ƒ…‰‹ˆ……„‚~yz{}€ƒ…ƒƒ†‡ˆ‰ƒ}y{|~€€ƒ‡Š‹Œ‹‰ˆ„€|ywwwwy}€„ˆŒŽ‰‚{}‚‚‚}ƒ€~|||}~~€‚†‰‰ˆˆ†„ƒ„…„~xxy{}~}‚††„ƒ„…†ˆ‰‡‚}}~‚~z{}~}~€‚…ŠŽˆƒ„††„~zuvwy|€€‚…ˆ‡…„ƒ‚€€€€~}~€}{}~€ƒ…†…„‚‚‚~zy|„†„~‚€~|{{|~€‚ƒ„…‡‡†„ƒ}{xxxy{}‚…‡ˆˆ‡…ƒ€}ƒ€~€„ˆ†ƒ€~€‚€~{ˆŠ†……†‡‰Šƒ|uutv{~{y~ƒ‡‰Œ‹ˆ†€zwy{zxvy|€…‹ŒŠˆ„~|{{|{{{„‰‰‰ˆ‡…ƒ~yvtsx|€ƒ…ˆŠ“–ˆ‚|utvxwvvy}€ƒ†‰‹ŒŒ‹‡ƒ€€€~|{{{|~€‚ƒƒ€€‚„††††…„…†‡‡‡‡ƒ~xy{|}|y{}„‰ŽŽŽŒ‡ƒ€€€€|yy{}…ˆ…‚ƒ…ƒ~}~€‚‚ƒ…†††…‚€}|{{zyxz|‚…‡‹Ž‹ˆˆˆˆƒ}wtqqx~~zw~…ŒŽ‘Š…„„„‚zttx|‚€~~‚…………„ƒƒ„……„ƒ‚€€€~}~~~~~~€‚……ƒƒ…‡ˆ‰ˆƒ~|||~€ƒ†‚~{|~€‚„ƒƒƒ„„ƒ€}|||}~‚‚€‚ƒ~|~€ƒ……€{y{~€‚„ƒ‚€}zy|€‚„†‡‡‡†„ƒ{yz{|~€~{y„ˆŒˆ‚€€€€~|{{{„†…„ƒ€‚‚€~|}€‚ƒ„…„„ƒ€~~„…€{y|~…ˆ…‚~€‚…„‚€€‚……ƒ‚€€ƒ……ƒ‚‚}}}~€€‚…‰Š‡…ƒ‚}}}}}}}~‚…†…„ƒ‚‚‚‚‚ƒ„ƒ‚ƒƒ„ƒ€~~€€ƒ„†ˆ‹‡‚|{{|ƒ‚~{|~„‰Œˆ„„…………„ƒ€€€}|}}~€~{}€ƒˆŽ‘ˆ………ƒ€ztqtvy|€ˆ”Іƒ‚‚|urtw{€†‚}…ˆ‰Š‡‚~ƒ„‚~{xz{|~€‚ƒ…††…ƒƒƒƒ‚€€‚|{zz}‚ƒ…„„„‚€ƒ‡ˆ…‚}{~ƒ‚‚€|xy{~€~||‚…ˆ‹Œ‰†‚|zyurpqsv}„‡ˆ‰‰‰Š‹Œ‰…~~€ƒ‚|wvwxz|ƒ†‰ŒŽ‹ˆ…‚}zxuqnsx|†‡‡‡‰Œ„|wvvy|}{yz~‚…†ˆ…‚€‚‚‚‚„††††…‚€~}|yvuwy|€„‡ˆˆˆˆ‰ŠŒˆ‚|yvux{~~~„†‡‰ˆ†…„ƒƒ‚‚‚‚€}z{|~€ƒƒ…‰ˆ‡†„}z|}€€ƒ†ˆŠŒ‰„€~|zz}‚…‡„‚‚ƒ…„„„‚€~~~€€‚‚‚‚‚‚~€‚„‡‹Š†‚ƒ…‡ˆˆ†€zwvuwy{ƒ………ˆŒ‘‹„~{}€€€}~~~€€‚„„€„ˆˆˆˆ…‚€€€€€€}ywxy{€……ƒƒ†ˆˆˆ†ƒ~|zywvvux}‚†ŠŽŒ‹‰ˆ†…ƒ}}}}~~~€€€€€€€€€‚„†‡‡†…„~~~€€~}}~€„‡†„‚€‚ƒ‚€~€€€€€€‚‚€€€€€}{ƒ‡…„ƒƒƒ‚‚‚€~}|{yx{‚ƒ„„„„†ˆŠ‡ƒ€}|ywyz{}~„ˆ†ƒ€€€‚‚€€‚„‚~{}~€€€‚ƒ„†‡ƒ€‚†…ƒ€|vqxƒ‚€‚ƒ†‰‹ˆ†ƒ€€€~{{}~€€€€€€€€‚‚‚ƒƒƒ…†…ƒ~~}|{{{|€ƒ‚€~ƒ‰Œ‰ƒ||}~|}}}„ˆ‡…„……„‚€~{xz}€€„†ˆˆˆ†…ƒ‚€€€€~}{{{}€‚ƒƒƒ‚‚ƒ„„„„‚}~~€ƒ…‡…‚‚ƒ„…‡„€|}~€‚€}y{~ƒ†ˆˆˆ‡‡‡…‚€€€€~zvxz|~€ƒˆ‹Š‰ˆ†ƒ„…†}xtppuz~„‚‚‡ŒŒŒˆ‚}zwvy{}€~}}~€ƒ†Šˆ„€~||€…†…„‚|€„†„}{zzz{{|‚}y}†ŠŽŽ†~€ƒ…‡‡„|ywwwyz|‚…‡Š‹Ž‹‰‡‚~~…{vxz|||}~€€‚ƒ…………ƒ‚ƒ„€ztwy|~ƒ…†…„ƒƒƒ|}}~€~}~~~€~}}}}ƒˆŒ‰ƒƒ…†††}smpruy|ƒ‡ŠŒŒŒ‹ŠŠ…yyy{~‚‚€~}}‚‚€~}~€†ŒŽŒˆƒ~€~xrrw{~ƒ~~ƒ‡‰‰‰…€}~€}z{}ƒˆŠ„~€ƒ„……zwz~…‰†‚~€ƒƒ„ƒ€‚‚‚€~~}}~~…ˆŠŠŠˆ‡†…„‚}yvsquy|€…‡ˆ‰ŠŠ‰‡…ƒ~|{y{|~~ƒ†ˆˆˆ…‚‚ƒ‚ƒ…‡‰Š‰…~{wz}~~}~€‚„†ˆ‡†…„‚‚‚‚€}zxwwxyz|~„‡ˆ‰ŠŽŠ‡‚}x{}}{ywvv{€†‡ˆ‡…‚ƒƒƒ‚€}||}~ƒˆŠ‰ˆ†‚€ƒ…}yvtvz~€€~ƒ†ˆˆˆ…‚‚€~{x|€‚‚‚€ƒ„‚€‚„ƒ‚‚ƒƒƒƒ}y|€}zwwwz~ƒ…††††………ztuwxz}}|{€‡‹‰‡„‚€€€~{xxwxy{~………„ƒ}{|~€€~}‚‰Š…|wy€ˆ…€|~€‚„„„„‚{vuxz„‰†ƒ‚„…‡‰‹†xwwx{„ˆŒŒŒ‰ƒ}}~€‚~{{}~€‚‚~~~†Š†ƒ‚„ƒ€~}~~€‚ƒ„„„„…†ˆ†ƒ€~|{yzz{€‡ŽŠ„€‚„|xwwy~„‰‹Ž‰ƒ~‚…††…{ux|€ƒƒ~‚ƒ„ƒ€‚…„‚€€†‹‰€vvy{€…‡‚~}~…Œ’Œ†}~€~{y{~€‚…†††…ƒ‚‚‚~}|{}~€ƒƒƒƒ‚„††ƒ~~€€€€€€€‚…‡ˆˆ‡€zx}‚‚€yrox„‚€ˆ‘–“‘Š€uvz|xtsvx|†……†‡‰‡„~}{}€€}€†Œ‹ˆ†ƒ€}{yxvuvwwz|†Œ‘•˜”‹‡‚|ytojmorzƒ†……‡ŠŒŒŒŠ…zvsv{‚~|~‚†ƒ{zyz~€‚„†††…„ƒ‚‚‚€}{zxy{}|||{{|†‡…„…†ˆˆˆ‡„}|zywxz}€‚€~~‚…‰Ž“Š„‚„‚~yurowƒ‚€‚…ˆ‰‹Š‡ƒ€€€‚ƒ{tuz€‚|~…Œ‡~yz{}€„~wqv|€„‡‡…ƒ†‰‹‹Š‰‰ˆ„~xusrw|~}|{{{„Œ‘Œ†…†‡†††€{wwvuuux|€‰‘•‘‰…ƒ……€{wvuy…†ˆ‡{z~‚‚€‡ŽŒ‰†ƒ‚~ytstuy}‚„†‰ŒŒ‡‚€€€€€€~{x{}€ƒ…„‚€‚…‡„|yz~‚‚ƒ„†ˆ†ƒ€‚„††ƒ€|zwvuw{~ƒ‡‹Š‰ˆ‡…„‚€}zwvuvy}€ƒ†ˆŠŒŒŒŠˆ…‚zuqqqu|„„‚€‚„†‹…~ƒ†„|z{‚{y{~€‚…ƒ€}‚†ŠŠŠˆƒ€€ztrw|€€€‡Ž‘‹…€€€ytrvz…‹ŒŒŽ‰…xpmkkqx}…‡ˆ‰ŒŽŽŠ†}ywwxy{{wtxŠˆ…€†‹‰†‚„‡‡ƒ€}}}zwtwy|~€„ŠŒ‰‡‡‡…ƒ€|vsw{~|y†Š‰ˆ†ƒ€‚‡‹‡ƒ|xy{~}|{}~€‚„‡Šˆ‡…ƒ€€€€~{x{}€ƒ†‡‡‡†…„‡‰Š†‚}xrtx|umgd`fu„‹”—™œ¡¦¥¡œ“‰tjcccdfgoxŠ”š›œ›™˜”‘‡‚}wqnmloruy|‚…ˆŒŽ‹ˆ…‚ƒ†ˆ‰†‚„†|wsopw}ƒ„…†ˆŽ“”Œ†xwvvwyzzz|~€…‰ŒŒŒ‰…€}{z|}|}~…Ї‚}||||‚„„…†‡ˆ…‚|zwvtsqpyƒŒ‘•—•’Š„}vnffnw{~€„ˆŒŽŒ‰„€}{zx{†‡‡†„~xshZKNRXl€œ¨®±´¶·µ¬¤”y_SMGLPV^gr— ª¬¯¬ ”Œ…~ytpmjikmrx€‚|xz‰ŒŠ‡†ˆŠŠ‰ˆ„ytonrvvutsst}†‘•‘‹„ˆ‹‰„~woorusrsx}‚ˆŽŒ‰‡ˆ‰ˆˆ‡„{yxx{~~|z{|}‚„‡Š‰†„„†‡‡‡†ƒƒˆŒ„}y|~€€‚ƒ…‹‘”••އ|xskcTA/C[r‡›¨«­´½ÇÄ»£ŒwfUOMMNOTfw…Ž˜ ¨®¬©¤™Ž‡„€|wsmgfils{„~}~…ˆ‹”—•‘„zpomkigilov}„Š•™žœ˜”’…|uoijlnrvz…Š•’‰ŠŒ‹†‚}|‚€|zzzz{{|}„‡ŠŽ‹Šˆ‡…„~wpsvy}‚‚‚ƒ„†Ž–˜‡………†ˆ†yl^M=:=?Yu“˜¡®»ÃÈÌ¿²¢‡m[QGGILPT\jyа¸½Àµª •Š€vmgb___dnx~‚…‚€€…‰‘ŒŽ‹xqlgfdeinsy†Ž–› Ÿ˜’Œ†€yrkjhilnsy†‘ŽŒŒˆ„}{yyy{|~ytqx‚‚‚ƒ„„‰Ž‹ˆ…‚}vprtvwxz~‚‰—›ž•‰‡†€zsokgdaS=(:Rjƒ›¨¤ ¯ÆÝÔÉ»¤vbMD?:@EM]n}œª¹ÅÀ»³¥–‹„}ungb\[`fmv€ƒ†‰‹Ž’“•——”‘ˆƒ}wqia^bfjotz„‘¤¢ œ–Š…~tjfkpppptw{ƒ‹‘“–‘Š„†‡†ƒ|unsy€†Œ…|}„Šˆ…‚~zwww|ƒ‹ˆ„ƒ†‰‹‹‹Š‰‰‰‰ˆ‡…ƒ‚†ˆvhN30?Miˆ£˜«ÅÐÐзœ‚tg\WQLHCP]k|Ž›£«°³¶®¥“ˆ€{ulc\bgmpsqnjvƒ’“’ˆŒ’™—•’†zsssrrrlfdhmu‰–››š˜“މ…€{uonmosx|€„‚ƒ„„„„‚|‚ƒ‚‡ŒŠ‡„}}|}€{uq~‹’‰„„ŠŽ‰„€~}„—’‡{naRD;5/W›—’œ³ÊÔÚßÁ¤‡jNA@@AACQ_q‹¦³¸¾º·±¢’‡{vpje`^cipz„ƒ€‚…‰‘Œˆ†„„‰Žˆ‚|wqtvwuttuux|‡•”’‘ŽŠ…€ztonlnpszƒŒŽŒŠ‰„~xvuvz~€€€ƒ…ˆˆˆ…y{ƒŠ”Їƒ…‡‡‚|y{}€…Š„~v[A28=Y„¯£…¥ÄØØØÂ¢‚lWHKOLD=ER_|˜¯·¿ÁÀÀ´¥—ކzhWRSU]foy‚‰Œ’•—•“‘Œ‡„‚€}{yvsuz~}{{|}†’“’’‘Œ‡‚{uohiklszƒ†‹‘—”’ŒŠŠŠŠƒzroliiimu|~€ž¨¨©¥Ÿ˜Ž‚xxxuojknqw}€€€mD)LoŒªº¢Š“¹ßÞÒÆ z\PEACDGIM`sˆžµÀÃÇ¿·­›Š|sjbYPRTYhwƒ‰Œ’™š“‹…€{~‚€~xrsw{zxyyy{†‰‹ŽŽŒŠ…{uplhgpx}‚‡Ž””•–—˜ƒvojgjmpqruzލ ˜’Œ‰‡„}uqsux~„ƒ‚€ztd; Z”  ŸŸŸ«ÎòëˬV2@MQJB???fޱºÂþ¹±¨ ˜‘‡wg\TLQY`lw€€†”™ž•‹‡‰‹Š‰ˆ‚|wrmlmnopptx}„Œ’—œœ—‘Œ‡‚zpea^]aelwƒŒ“› ¤¦•‡zqifddls|…Ž–Ÿ™’Œ‡~||||}}}xpiG!4c‰ ¸°˜ªÙüîßÂ^MJG@931/>[y–³ÎÎÍËÇø¦•„sbVJEINWbnz‡‘‘‘”›¡Ÿ™”މ††‡…ƒ€xogiloswwww‡“–—–•“Œ†xrkjmoqqqv{Œ—˜‘Љ‰‰‡…ypmnox„ˆ‚ƒ—™–”އ€€€€}xsvxwhXD' ;‹ÜÄ©˜¨·ËâúåŸrD)8GG<28BNv¹¾ÃÅÇÈ»¬ž’‡{oc[SLSZbmy‚†‹Ž–œž–Šˆ…„ƒ€}wppqsrpqrsw€ˆ”™˜˜—’Žˆztojfbbnzƒ…‰ŽŒ…ynryƒ†ŠŒ‡………„‚€~{x{}‡ŒdG2!c·è¾”“µØèòùÌžvW94>I=/&:668;Uyž³È×ÔÑʾ²Ÿ‰si_VPILU^n‘““‘“˜•‹ƒƒƒ„†‡…‚€zuponopprtu|ƒ‰‘˜œž –‹{wux{ui]gt€†‹‹ˆ‚{y|~|zxvuuy}„Œ””‘ŽŽŽ‹ˆƒzqsvz~ƒ„‚€c4)X„¨ËѬ‡œÌüùôã¢b>;7:=@;6;Vr’¶ÙÜØÓÆ¸©•€sle[QIKNVhy†›–‘Ž’•–”’†€‚ƒ‚‚‚}tlkklmorx}ƒŠ‘”–˜™š•‰|tnhhhiijo|ˆŽ“—™š™—•Šƒzqgdablu|€…‹‘˜™š˜“ŽŠ…€|yusrruw|„‹•Ÿ zT52x¾³¨‘„—ÆõñàÍ“X28=@@@910Z„¨ÀØÞÛØÊ¼­›Š{qgZM@FKTj€ŒŒŒŠˆ‡™   š…ƒƒ‚|woggkow‡ˆŠ‹‹‹ŒŽ‰„~wonqux|€‚ƒ…Œ’”’Œˆƒ}xsrpsx}~€ƒ†‰ŽŒ‰…‚€~~|yvwwy‰‹Š‰‰‰ˆ‡…vld^YG2#R¥¶ÆÆ½´½Éζž„fIDJOUZ`fly¢«°´ª¡˜“‰‡„ylacfjpw{~€ƒ…ˆŽ•˜˜˜“†|wtppppsw{~ƒƒƒ„†‡…„ƒƒƒ‚‚‚zuvwx{ƒ…‡‰‹‹ˆ…‚}yz}€€€‚€~}}|~„‚}{}…ŒŠˆ…‚‚„‚~{|~„‰Šxsqoruxurs{ƒŒ– Ÿœ™™˜•Œƒ|uoprtvx{€†Š‘ŽŠ‡…„‚€{vpv{€€€~{w~‡Ž‰ƒ~|~‚…ƒ|yxz|}~ƒ‡‰ˆ‡†„‚‚‚‚{tpuy|~€‚‚†ŠŒŒŒ‰„€€€|xwxz{|}„‡‡‡ˆˆ‰†ƒ€‚„„‚€€‚€€€€‚…ˆˆˆ‡„‚‚„…ƒ|xy…„€|}€ƒ††ƒ€…‹ˆ‚~zwx{}yvv}„ˆ‰Š‰ˆ‡‡†„~~~}|}~ƒ‡Œ‰…„„…‡‰Œ‰‡„‚}{{}~€‚ƒ~~‚†‰‹…€‚€~|||}„…‚€ƒ‡‰…€€€€€€~}{zxz|ƒ‡‹‹‹Š‰ˆ†ƒ€€€zutwy{~€‚ƒ…‡‡††…„„‚€}ƒ~}}}~‚‚ƒ„…†„ƒ||}~~~~}{z„ˆŠŒ‹‰ˆ…‚~|zwurv{€‚……ƒ„‡‹Šˆ‡„~~|zx{}~{yz|„ŠŒ‰‡…ƒƒ„„~{wssx}ƒ…ƒ€€€~~‚„††…„}yz{zyxwvuz€†‡ˆˆˆˆ‡††††…‚~|||{zzyxy{~€‚ƒ…ˆ‹‰‡…‚€€€€~}|~€‚„„‚€‚‚ƒ‚€}€‚„……„‚ƒ…‡…ƒ}zz|}{y|~€„ˆ‡„‚ƒƒ‚€~€ƒ…†„~}|||}€€€ƒ…ˆ‹Ž‰…€~€€~€‚ƒ‚~|}€„†ˆ‰†ƒ‚„††……{vz}€€€~€‚ƒ†ˆˆ†„‚€~€€€~}~€ƒ…‡‡‡†„‚‚‚€}}}ƒ††…„…†‡‡ˆ…€{{|~€„‡†…†‡ˆ‡„‚~|ywvw{~‚†‰†„„„…†‡‡ƒ~y|~€‚€€~€€€€€€ƒ„…‡ˆˆˆ†ƒ€}yx{~zwy|†ŒŒ‰‡††„‚{wvvwxz{~„‡Š‹Šˆˆˆˆ„{zyzzz|‚ƒ„ƒƒƒƒƒƒ‚€€€‚‚‚€€€€ƒƒƒƒ„†ˆ†ƒ€}yx{~€€ƒ‡ˆ…ƒ€}z{|{{{}€„„ƒ‚ƒ„„„„‚€}{yx{€€€‚ƒ‚‚‚€€€€‚ƒ‚€}|~€€€‚ƒ„……„„„‚}{{{}~€€‚„…‡ˆ‰…‚~|~€ƒ‚‚€€ƒ‚€~}}~~~~€ƒ†‰Š†ƒ‚ƒƒ‚~|zyxyyy{}€ƒ†‡‡‡†„ƒ†ˆ‰†‚}z|~zyyy{‚„†‡‰Š‰‰‰ˆ…ƒ}yvuy|~€‚ƒ„ƒƒƒ„…†…„„‚€€ƒƒƒƒ‚€}~~€‚€„‰ŽŽŽ‹†~}|||{ywz~‚„…‡ˆ‰ˆˆˆ†ƒ€€~}}}}‚„…†…ƒ‚ƒ‚€}z{ƒƒ€‚ƒ„ƒ€~~€€€€€‚ƒ‚€}~€€€€‚ƒ€ƒ…‡ƒ~{|~~|zxvsw{€„‰Š‡„†‰‹Šˆ†xuwyxxx{}€ƒ†ˆ‰‰‡„‚€~~}~‚„„„ƒƒƒ€|x{}€€€‚…ˆ…‚‚~}||~€‚ƒ„ƒ€€€~}}}~€||€…†ƒ€~}‚‚~{z|~†Š‡„}~€~{zzz|…ˆˆˆ†„{wwyz{|}„‰Ž‹‡‚‚‚ƒ}zz{{~ƒƒƒƒƒƒ„…………„~}}}~€€€„‡††…ƒ|z}…ƒ…‰†ƒ~}}~€‚„†††††††‚{yxy|~{xz|~ƒ‡ˆ‡‡…„ƒ…‡‡„}|||}}}~€ƒ‚€€‚ƒ…‡ˆ‰ˆ‡†…‚€~{yxwxy{}€„†‡ˆˆˆ‰‰Šˆ†„‚€}{yxxxz{}~€ƒ†ˆŠŒ‹‰ˆ…ƒƒ„†ƒ~ywvuz}}~„‹Œˆ……„ƒƒƒ{wvuwz}|zx}ƒ†††………‡‰‹‡ƒ~|}€|xuwy|…†…„†ˆŠ‹‹†}xtvxxxxy|~†Š‰ˆ‡†…„„„‚€}}|{zxyyy|‚…ˆ‹ŒŽ‰„€€€}|xsntz€‚ƒ„„„‡‹ŽŒ‹ˆƒ~{{{zyxvtuy~‚„†‡‰‰‰ˆ†„ƒ‚‚€}{yvvxy{}~‡ŒŽŒŠ†‚}}}|zxwvvy|€ƒ†‡‡‡†††„ƒ}{yxyz{~‚€‚ƒ…‡ˆ…‚‚ƒ„„~|||}}}~~~€‚„„…†ˆ‰ˆˆˆ…‚|ywutuvw{ƒ‡Š’ŽŠ…ƒ€}{yxvuwy{~‚……†………‡ˆˆ…|z|~|{}ƒ…„ƒ‚ƒƒ„„…………‚€~|zyyy}€‚‚‚ƒ„…‡ˆ…ƒ€€€€€~}|~€ƒ„……†‡†…„‚~yyyy|~‚ƒ†‰‹Œˆ…}|~~~~{yy|€€€„ˆŠŠ‰‡…ƒ„……|yxwy|~}}~„†††…„ƒƒƒ‚‚€~}}}}€€€€€€€€€€~€ƒ…††…‚~~€€€~}}‚„……„ƒ‚€~~~~}|}€ƒ†††…„„‚}{yvtuwy~ƒˆˆˆˆˆˆ‡††‚~}}}|{z{{{€„†…„‚|€…ˆ…‚~}ƒ†„€€€}|{zy{~€ƒ…ˆ‹ŠŠŠ†‚}{ywvvvwz}€‚„…‡ˆ‰‰†‚}ywxyz|}~ƒ‡ˆˆˆ†„‚‚‚‚}ywy{}€ƒ€~}…†††ƒ€|~€€„†„ƒ~{zzz|}~…‰ŒŒŒŠ‡„„„‚{wsosw|}„Œ”‰‡„„„„xrpoptxz|}€„‡Œ‘Ž‹‰ˆˆ†„‚}wuuuuuuy|€…ŠŠ†‚ƒ…‡‰Šˆƒ}{||~€‚€~~~€‚…ƒ‚€€€‚ƒ…†…ƒ‚€€€€}{z{}‚……„„„„………„„„|zz{}……ƒƒ…ˆ‰Š‡{xwvy|„†‰ŒŒ‹†‚~zwwwwxxy~‚„†ˆŠŽ‹ˆ…„‚~xrsuvwyz|ƒ‰ŒŠ‡…ƒ‚‚‚{xwwy~ƒ„ƒ‚‚ƒ„ƒ~zyz{}€~€„ˆˆˆˆ„€~}zxvu{‚‡‰‹Š‡„„„„~{xuuvw|‡ˆ‰‰‰ˆ†ƒ€~}||||~„‡ˆ…‚€}{}~|yy{}€…Љ‡„ƒ‚€~}|}}~~€‚„ƒ‚‚~{y{~€€€~}…ˆŠŒ‰…~~|zxvtuy}€„†††‡ˆŠˆ…‚|yyxxxx{ƒ…†‡‡‡ˆˆˆ†…„‚}{|~€€~}‚†…ƒ€~}}‚„†ˆ…€|~€}z|~ƒ………†ˆ‰†ƒ€€€~|xux|€€€€‚‡‹Š‰ˆ†ƒƒƒƒ‚€|xwxz|~€€€‚„†‰‹‹‰ˆ„~{|}~€‚|x{}€…Š‹†‚†‡„€~}}|}~‚†ˆˆˆˆˆˆ†„€€|xwy{}„„„…†‡ˆŠŒ‰„€~}{ywwxy}…‡‰‹‹‹‰†‚€~}{{{|}~~|yy|‚…‡…‚€ƒ„†‡‡…„‚€~€|zxwwy{}~€‚„‡†……††‡‰‹‰ywxy|€}yz|‚†Š†‚„††…„~|}}~~~}||||}‚„‡‰‰‰‰†‚~}|{zxvuxz|‚‡ŠŠŠˆ†„ƒ‚|xyz|‚ƒ|}€€€‚„ƒ‚ƒ„„‚~zwxz|{z{|}€…ŠŠ‰‡†…ƒƒƒ€|xvttx}~~~‚‚€„‡†„ƒ€€€€~|{zy{}„‡‡‡‡‡‡†„‚|xyz{}€‚ƒ„†‡‰ˆ†…€|{||{{{{{|‚„†‡‡‡†††…‚€€~{y{~€‚„ƒ‚ƒ„„„„‚}x{€…ƒ‚€}€…Š…x{~€„ˆ…y{}€‚…„}„‰‰‰ˆ„~ƒ~|zyy|€‚‚‚„…†ˆŠŠ†‚‚…‰„ywtu|ƒƒ‚€€…‹Œ‡‚€~}‚†‰…‚~{x{‡…ƒ}€…Љ†„~~€~|z}€ƒƒ„ƒ‚ƒ…‡…ƒ}zyz{}~zy~ƒ‡ŠŠ†‚~{z~‚}yzz{~‚€‚‚€ƒ…†††‚}xyyzzz{}‚‡‹‹‹Š‡ƒ€€~{xwvw|‚€~€‚„†‰ˆ…‚‚ƒƒƒƒ‚|utx|‚„€||†ŠŠŠ†‚~€€~~~~|zz|~€‚…†‡‡„‚‚ƒ„„…|vy{~‚††}~ƒ†ˆ‡{y{}~~€€‚ƒƒ„……€|z{|}~~|}}~†ŒŠ‡„‚€€ƒ‡…yyz{}€€€„‡ˆ‡†„€{|‚€~}‚„ƒ‚€€„‡‡„ƒƒ€‚„ƒ‚€~||{}‚ƒ„†‰‰‰ˆ†ƒ~zwurty~„‡ˆˆ‰Š‹‰†ƒ€|xvuvxz|~€‚„‡ŠŒŒŒ‡€yyyz~ƒƒƒ„†‡ˆˆ‡|ywvwxy|~€„ˆ‰‰‰Š‹‹ˆ†‚{ttx{}~€‚ƒƒƒ…ˆ‹ˆ„€€‚€…‰‡ƒ€‚„ƒ€~~€‚„„…ƒ‚…†„~yuwz}€‚……††††………ƒ{wwww{„…†………‡‰‹ˆ†ƒyplqwy{|…ŠŒŽŽŽŽŠ†‚|vrrrsuw{ƒƒƒ„‡ŠŠ‰ˆ„|}~|{yx{}€€€}|}~€€~|~ƒ‰‡„‚€‚„„ƒƒ‚‚„††ƒ}zvy{|zyy|ƒ‰ŒŠŠ‰‡…‚{xwvvvvx{€€ƒ…‡‡ˆ‡†…ƒ~~}|zxxxxz{}~€€€€‚„†‰‹ŒŠˆ†ƒ€|xtttssrv}„‡‰ŒŽŒŠ‰‡‚|wtqqtvz}€ƒ…ˆ‹ŒŒˆ„€}zxxxy{|}~€ƒ‡ˆ„}ytplikntŽ”””𠤡–‰|ri`_^`flt|…Ž— ¡£¢›•އ|xspmlllpu{~„†‡‰ŒŽŒŠˆ…ƒ~}{zyxvx{~€‚‚‚ƒ†‰‹ŒŒˆƒ€‚„ƒ€}zxvxz|~ƒ‡‹ŠŠ‰‡…ƒ€€€€~ƒ„„ƒ{z|„†‡‡ˆ‰‹Š‡…„ƒ‚}xsssuz~€‚‚ƒ…‡‰‹Ž‡y{~„ˆ…y{~€„ˆ‡€zwww‡Œ‡‚~}‚‡Š‡……„ƒƒ„„„zsomlcYQV\g{œ¢©­²´²±¨—…tcSOMMSXamx…’Ÿ¥«®«©¡–Š‚zsnifffinsx~„…†‡‰‹Š‰‰‡†††‡†…„|zyxvtsqotz€…ŠŒŒŒ‹‰ˆ‰Š‰ysqorvzxww~„ˆ‰‰ŠŒ‰†ƒ|zxwvwwwy}„ˆŒŠˆ‡‡‡†ƒ|wrstuwz}ƒˆ‰‰‰ŒŽŽŠ†|wx{}€€~|~„‰ˆ†„ƒ‚€ƒ…‚€‚„…‡†††…ƒ‚€{ocVI;Sl‚Œ—žŸ«¼ÊÁ·¨ue\SOLJMQYiy‰šª°³µ³±©—…zskhfca_clu|ƒŠŒ‘“‰„‚€€‚ytvwwsoosv}†‘’”•—•“‹†€xqlllnqux|€…‹”˜–‘Œ‰†„„„zsqqqux|||„ŠŽ’•Œˆ…ƒ€}zwspty|€ƒƒƒƒ†‰Šˆ†††‡…‚€€ƒ‚|ƒ‡…ƒ€„†„ƒ‚‚„†„‚€wk_M:5Me{¤©«¯¼ÊÍÁ´ž€cVKCCDGNUdwŠ›«¸»½»¶±£‘€wnfb^ZVS\fp|ˆŽŽŽ”—˜˜—‡‚€~€€{wsplmptuuuy}‚Š“˜šœ˜”‹‡‚|voha__alx…Š”™œ  •Š|wsolkklpty…ˆŠŒŽˆ‚‚ƒ‚ztsx}€€€€ƒ††„‚ƒƒƒ…††…„………ƒ€~ƒ„„„‚€€€€xaJ???b‹¯¥œœ«ºÁÂÄ­”|eOCEFJOSap€•«¸¾ÃÀ¼·£Ž|qe^ZWWWXfs‹—š™™–“Œˆ„~{xvxy{~€€€€~|zxwy…†…„‡‰ŒŽ‘‰‚{tmoqtttux{€†‘•—”‘ˆƒ~zvtrpppsy~‚„†ˆ‹”’‹„…‡‡„€}|zyxx{}~~}ˆ‘ŽŽˆƒ€€€~}||~‚††…„€|v\A28=[Šº°ž’¨¾ÌÎй–s_M@CGJLO\m•«¼¼¼¹µ±£“ƒxmedb_\X_hq“ŒŒŽ‘‰ƒ~~€ƒ…xuuuvwxvsrw|‚Š“•“’ŽŒˆƒ~wokigjmpv|‚ˆ‘”–”’‰ƒynnpqomnu|„Œ•”‘ŽŽŒ‰‡‚{uuvuroqw}‚‡‹”–’ŒŒŒ‡€zwusqot|„zsT6'>Ut›Á²—‚¥ÈÛÏ·dUI@@ADIN^tŠŸ³ÄÆÈû² ŠtnicYNMRVfyŒŽ–›—“‡€}~€€€ztooorw|~€ƒ†‰‘™›˜”Œƒywuspmkjipx€‡”–˜•’‹‡‚{tnkhmt|€„‡ŠŒŽŠ‡ƒ{wsuz‚†‰‰‰ˆˆ‡ˆˆˆ…‚‚ƒ„†ˆ‡††„}m\F' !P~—®¾¶®º×ôåÊ®…\?;8888CP^z–­½ÍÎÈÁ¶ªœˆsfa]YURZak}Ž–•”“’Žˆ‚~|z~ƒ†…„‚~zzzzxvvx{„ŠŽ‘”’‘І{ung`ejov|‚ˆŽ”™š–‘ˆ~„{qijknu}€†‹‘’Šˆ‡†}ywuuwy|ƒ„†‰—˜”‹…ysb9%!3m¡¯¼À¹±ÃàýéÒ·ˆY;1',5=JVe}”«ÁØØÔϽ¬˜~d\]_[WUVW_tˆ‘”–’ŽŒŽ“•˜“Žˆ„€}{ytlc`__eksГ𠢢¡žš”Œƒwj]YUU_irzŠ•Ÿ¥¬­¡–Š~spppjdadfp€—›ž›—”‘‰yurqrsuz~ƒˆŠ‡†‰ŒŽ‹†€iQ:# #i¯ÀÀ¿¹³¸ÕóíÍ­R'&%(08EVfŸºÉØÛÑǵŸ‰uaSTUSQOXdp‚•¡™–“Ž‹‡ƒ€~|}€}{xrmihgmv…‹“–™¡™Œ€thabcb`_l|Œ“šžœ™•ˆwnebhmu~‡‹”•—•“‹†€~}|zxxxxz|ƒƒƒ‰Ž‘ŽŒ‰qK% V¢Ê¿³´º¿ÕíøÕ²d;.,*.18HXoŒ©»Ê×ÖÕϾ®—y\Z\\XTSSSaw”™›—““–™—•”‡}ytomlkjhhknv€‹’—œŸ¢¡œ–Š„}voicabcju„‰‘”˜œš—”މ„€}xpijlnsx~…Œ‘•˜•’‰ƒ|zwsptx|……ƒ€„ŠŽŒŠƒynR0"3P‡¿Ì¹§¶ÌàààÓ°oU;>DGD@H\q†œ²µ·¹¹º²£”ƒsdhlle]]bgrŠŠŠ‰†ƒ„…‡‰ŒŽ‘”’Š‚|wromntz~€ƒ‡ŠŽ‘‘‹…~voqtxxxwww}ˆ’”–•Žˆ„„„|xwvwxz{}ƒ…ƒ„†ˆ‰‰„~xxxy|}xsw{€„‰‹‹‹ŒŽŽpe^XB$#Eh˜ÇÙÊ»ÄÕæØÊµ‰]FC?ADGPYh‚œ«²¹¶²®¨£š‰yqlhfcccchr|ƒˆŒŽ‘—œ•Žˆƒ}zvrmiikmsy€…‹‘”’ŽŠ†‚~zvqlnqtwz}…ŠŽ’’’’Šƒ|wsprtwxyz|„‹’‹‡…‚‚‚‚zvy}€‚ƒƒ€~€€€€€€‚„‡††…„ƒ‚€‚‚ƒ}ytojpv|…‰Ž’”•–˜™˜“Žˆ€xwwxz||zxz€…‰‹ŽŠˆ„{xusrrtvw~„ŠŠ‹’މƒ{vvwxwvv{€„„„…†‡„‚~|}~zvy}€…ŠŠ…~}€‚ƒ~zyyy|€„„„„„„…‡‰…~~€€€~}€ƒ„‚€€€‚ƒ€~}~€‚„‚}…†„‚€€‚€‚„‚€€‚„………ƒ€~…ˆˆˆ…€{{||zyyyy{ƒ…†ˆ‰ŠŠ‰ˆ†‚~}||}~}}|}€‚„„„ƒ‚‚ƒƒ€~|~€ƒ‚€~|}……ƒ}}€ƒ†††„ƒ€€~}{xvwz}~€‚„…††‡ˆ‰‡…‚|vvy}{zz|~‡Œ‹‡‚ƒƒ„„„‚~yy{|ƒ„‚€‚ƒ„ˆ‹ŒŒ‰…‚€~|ytotz€ƒ…ˆŠŽŠ‡„~{ywutvxz}€‚„†‡‡‡ˆˆ‡…ƒ€‚‚€}{zy|€…ƒ‚ƒ†ŠŠ‰ˆ†ƒ€€€€}yvz}€ƒ†ˆ‰Š‡ƒ‚ƒ……†„€|{z{~‚ƒ‚€‚…†††…‚€€€€~}|}~‚ƒƒƒ‚€ƒ„…†…ƒ€‚ƒ€~|||}~„††‡ˆŠŒˆ„€~}|||zxvxy{~„…‡†……††…ƒ€€€~}||}~€}|}~„ˆŠ‰‡…ƒ€€€}{{|}~‚…ˆˆ‡†„ƒ}zwusw|‚‚„†‡‡‡†…„}}||||}~€€€‚„…††ƒ}~€ƒ†„~‚ƒ…ƒ{ywvz}€‚„ƒƒƒ†‰Œˆ„€~|zxyz{}‚ƒƒƒ„…„‚}{~ƒ‡„‚ƒ†‚~z{|}ƒƒƒ„„…†ˆˆ†„~zzzyyyz|ƒ…‡ŠŠ‰ˆ‡„‚€}|zyxz|€€‚„†††…„ƒ‚‚€€€€~}~~}|z|‚…‡‰‡…………†‡ˆ„€|zyz|~}||‚†‰ŒŽŽŽŒ‰†‚{wssux{~€‚ƒ‡‹ŒŒŒ‰†ƒ‚€€€~|y{}€‚‚€‚‚‚ƒ„†‡‡‡‡‡‡…ƒ}xwwwy|‚ƒ‡‹ŽŒ‡‚€~|zxwusw{€‚…‡‡‡ˆ‰Šˆ…ƒ~~~}}~€€€~~‚ƒƒƒ„†ˆ†…ƒ~||||||||}~€‚ƒ…†‡ˆ†…ƒ‚€~|{yx{}€€€ƒ„†ˆŠ‡„€~~~~~~€‚‚‚€‚„…†††„~|}€€€€~|}…†„ƒƒƒƒƒƒ‚‚}z{|}}~„†……„„„ƒ‚‚€|zyz{|~€‚ƒ……„ƒƒƒƒ‚€}|||}~~}|}~€‚ƒ‚€ƒ‡ˆ‡…„ƒ‚ƒ„…‚|zxy{}||}€ƒ†ˆŠ‰ˆ‡††…‚}}|}~€€‚„†„‚€€‚„ƒ€‚„„ƒ‚€~~~~€€‚ƒƒ„„………ƒ€}}~€€}{~‚†‡‡‡…„„„„‚|||}~€€€‚ƒ„…„‚‚ƒ„„„ƒ‚ƒ„ƒ‚~{xwvw{~€‚ƒ†ŠŽŒ‰†„‚{wvttwz|}ƒˆŒŽŽŒ‰„€~}{zxwww|‚‡††…‚€‚†Š‡ƒ„ˆ‡ƒ€~||}}zxy|‚†‡‡‡ˆ‰Š‡…‚~{zz{|||}~ƒ‡ˆˆˆ‡‡‡„‚|yxxxyzz}„†‰ˆ…‚ƒ„…ƒ|yyyy|€ƒƒ‚€„‡…ƒ€~€‚€€€€€€€€€€€€€€€‚‚ƒƒƒ‚€}|||~€€€€‚ƒ„„‚}}|}‚ƒƒƒ‚‚ƒ„†…‚€~|z|}€‚ƒ‚‚€€€~~}~~€€€€‚ƒƒ€€€€€€€€€€€€ƒ……„„‚~€~|}~€‚„……„„ƒ€€ƒ‚}~‚„„‚€€€€ƒƒ„†„ƒ€€€€€€€‚‚‚€€~€‚ƒ‚€€€ƒ†ƒ€|}€‚…„€}}~‚†‡„€€€~}}~€‚ƒƒƒ„†‰‰…‚€ƒ„ƒ~|~€‚€~~~€ƒ†…„ƒ…††„‚ƒƒƒ‚~}~€‚‚‚ƒƒƒ„„„‚€‚ƒ‚‚‚‚„…„€}}~~€€€€‚ƒ‚€~}~€€€~€ƒ‚€~|~„ƒ€‚…‡†ƒ€~~€€~|}~ƒ„ƒ€~}|}€€€€‚ƒ…††ƒ}|}~~|zz|~„‡…‚‚ƒ‚‚€€€€€~~€€‚ƒ‚‚‚‚‚‚€~~}~~~€ƒƒƒƒƒƒƒ‚~}}}}~€€€„‡…‚€~||‚‚€~}||€ƒ„ƒ‚€~|}~€‚ƒƒƒ‚‚‚‚‚€|yyyy}‚„ƒ‚ƒ„„…†‡…ƒ€~~~~€€€€€€€„‡…ƒ€€€}|}~€‚‚‚ƒƒƒ‚~}|z{}~€‚…‰‰†‚€€€}{{{{~‚…‡ˆˆˆˆ‡…ƒ‚€}zwusvz~€€ƒ†ˆ‰Šˆ…‚€~||{zzz}…†ˆ‡‡†…ƒ€~}|}~ƒ…†††††…„‚€€}{z|~€ƒ„„„…‡†„}|}€€€‚…‡†……ƒ€€€~~}}~€€€€€€€‚ƒƒ‚€}yz|€€€€€‚ƒ„„„~}~€‚€~{}~€ƒ‡‡‚}}~€€~|}~„†ƒ‚„…„ƒ‚€€~}€€}}‚ƒ„‚~€€‚‚€~~~€€~}|~€ƒ†…ƒ€€€€€€€€~~}|}~€€€‚……ƒ€€€€€€~}|}€€€€€€~}~~~€‚‚‚‚€€€~}{{{|~€~|z|~€„‡ˆ†„‚}€€|wxz|~„…†‡‡‡†…„~~~~~~}||€„†‚~ƒ„……‚€€‚‚‚‚€}}|{zxz|~~€‚…‰ŽŠˆ…~~~}zxvtsx|€ƒ‡‡…„†ˆ‰‡…ƒ€}{yxyz{|~†Š‹ŠŠ†ƒ}zwvty„…†…„ƒ…‡ˆ…‚}{|€„ƒ€ƒ†…ƒ€~||}~€ƒ„†‡ˆˆˆ‡„‚€~|ywvz~„‡…ƒ‚…ˆ‰…~|y{}€€€ƒ†‡ˆˆ‡…„‚}{zyxwy{}…ˆ‰‰ˆ‡†„ƒ‚~zxxxz|€€€€‚ƒƒ‚€€‚ƒ‚‚€~€€}{z|~€‚…………„„ƒ‚{xyz|}€€€‚†‰‰‰ˆƒ~|||{zzxvvz}…‰ˆ‡†††……„‚€}{ywvuw}ƒ………„ƒ„‡Š‰ƒ|zzz{{{{{|~€‚ƒ…††††„‚€~€|yz|€€~~‚„…ƒ‚€}~~~}||~€ƒ…†††ƒ‚€€~|zzz|€„†‡ˆ„€‚|zwtx|€ƒ††„ƒ„……†‡†‚€€€€~zuuwy|€‚‚‚ƒ…‡ŠŽ’Ž‹‡xuwyxxxvuw}„‰ŽŠ†ƒ~|{yxvuu{‡Œ‘Š…ƒ€€‚€|yvuswz~ƒ‰Š‰ˆ…ƒ€ƒ††ƒ~zvxz|~‚€‚ƒ…ˆŠ‹‡ƒ‚ƒ„ƒ€~|yy{}€ƒ†……†ˆŠŠ‰ˆ„zxwxz|}}}„†‰ŠŠŠˆ‡…ƒ~||||}}}~€‚ƒ„„„ƒƒ„†ˆ‡†…}zzz{{{|||„ˆ‰…ƒ‚€€ysrw|ƒ†ˆŠŒŽŒ‰…|yyzywuvww|‚†…„ƒ‚ƒ†ˆ…‚~€€€€~}}~‚…‡…ƒƒƒƒ‚‚‚|yyxy|~€‚ƒ†‰Š‰ˆ†‚}{zzyxwwwy}€„†‰‹ŒŒŠˆ…€{yxwwwxz|~‚…†‡†‚~}~€‚‚ƒ‚€~{yyyz{}~€‚†‹ŒŠ‡ƒ|{zupmquy~‚†‰‹Ž‹ˆ„}xtvwyyz|…‡ˆˆ‡†…ƒ~|z|}€€ƒ…‡„‚~|~ƒ‰ˆ…‚€~~‚††ƒ€}yuz„†ˆ‡…‚ƒ„…ƒ~ytsuvy}‚ƒ„…‡‰ŒŒŠ‡{wustttwy|~‚„‡‰ŒŽŠ†‚€~€ƒ‡…‚|yx|}|{{|ƒ‡ŠŽŽŽŽŠ…}zvssssw{€†ŒŽ‹ˆ„zvtrv{€€‚„‡†††„~‚€ƒ‡ˆ†…‚|{zyz{|}‚†Š‰ˆ‡†…„‚€}wruy|‚ƒƒƒ†‹Š‡€yttttttwy|…‰‘Ї„€}ywvuvvwy{~„†ˆ‰ˆ†‡‡ˆ†ƒ€~{xz||{zyyy}‚‡†…„„„„„„‚~}}~€~{x{}€ƒ†‡„‚ƒƒ‚€~}}~~ƒ†ƒ€€€€€€~}~~~}~~€‚„……„ƒ‚}|zywvuw{ƒ‡‹ŒŒ‹‹‹ˆ„€{uqqrtw{~ƒ…‡‡‡ˆˆˆ†ƒ€€}|zxwvvz}€ƒ†‡‡‡‰‹‹Š‰ˆ„|wqsuwz}~~~‚ˆŽ’’ŽŠ†‚~{xvsqptx|…‰ŒŽŒŠˆ…‚~{yz|}€‚‚€€‚ƒƒ€ƒ…†††ƒ~yyz{}~~|z{}ƒˆ‹‰†„‚€}|}}~€‚ƒ…‡‰ˆˆ‡|xwvx{}||}…‰‘Œˆ…‚}{yxxyz|~ƒ…‡ˆˆˆ†„„„…„‚€~€‚€}z|~ƒƒ‚ƒ…ˆ†„„„…ƒ€}{zy{~€€€€€€‚ƒ„„ƒ‚€}|~€‚ƒƒ‚~zy{}‚€}}€‚„„„ƒ‚‚ƒ„ƒ‚€~{y|‚‚‚ƒ„…†‡‡ƒ{zxy{|}~~„†ŠŽ‰†‚~zywvvvwxy~‚‡‰ŒŒŠ‰‡…ƒ|xxxyyy{}~‚…†ƒƒ„ƒ‚‚‚‚ƒ„„‚|ywwwxyz~‚†‰ŽŽŽŠ…€|xutrsssx†ŠŽŠ‡…‚|xtoorvz~ƒ†‰ŒŽŒ‡ƒ€€|xvxy{}~€€{wspmpw~…•–—˜˜™”Œ…|skifgilrx‡–˜››˜–‰‚{sopqpoosw|‚‰ŽŽŽŒ‰†††…ƒ~{wx|€€{ww{~€ƒ„†‰‹Š†ƒ€~}||||||~‚‚€€€‚‚€‚ƒƒ‚€~€~{xz|}‚†ˆ†„…‡ˆ‡‡†…„‚|vuuuwy|‚„…‡ˆ‰‰ŠŒ‹‡„€€~{zzz{}€€€~}€‰‘”’Œˆ„„„‚|wspmptwz}‚‰Ž‹ˆ…{usrqvz|||}~ƒ‡‰‰‰ˆ†„ƒƒƒ‚‚~{xwux{€‚ƒ…‡‡‡‡…‚€rcWWWbxŽ•—™ž£©­±©š‹|oa\WUVW^itƒ’ ¢¥¥¤£Ÿ™”…uggghkmoqr{ƒŠŒˆ…€~‚„…ƒ|yvspu{€ƒ‡‡‡‡ŠŒŒŠ†€yusrpnnsx}‚‡ŠŒŽŽŒ‰…xutstuvvwz€†ŠŠ„‚ƒ„…†ztwz|€„ƒ€|}~€ƒ†‡„€€€€‚‚‚‚€~||||}~ƒƒƒƒ…‰‰„}zz|~~~~€…ŠŽŽŽŠ…€ƒ‚€}xsuy}€‚ƒƒƒ…ˆ‹‹‹‹‡„€|wodZPGAXo„“¢©ª«²º¾¬š‰wf\UOSV[ckvƒ‘›£«¬¬ª£›‘„wqnjihikmqw|‚‡Œ‘Їƒ€|yvtssqpqtv{‚‰ŒŽ’•–•”ˆ}{xuroljmt{„ˆ‹Ž“•“‘Š„zutuuvwwz|~„ˆŒ‹Šˆ†„„…†…ƒ‚}xsssuy}{vqv{‰’•’ŽŒ‹‡„~zxvtuuv{€„†ˆŠŠŠŠŠ‰‰ˆ†€{xxxxxyz{~†Šˆ‡‡…}tdI/7K_}𮍢¨¹ÊÇ¿¶œ‚jYGCGKRYalx†—©³ºÀ¸¯¥—ˆ{rhc_\^_bmx‚‹““‘ŠŠŠŠˆ„~{y{~~|zwtprsuz‚…‡‰ŒŠ…€zuromlkmrx~†Ž’•–––“‹„}wpnmmmmpw}ƒ‰‘ŽŒ‡ƒ{xusqporx~‚„–›˜•‰ƒ}xsssrqosy…Š’•”Šˆ†|z{|{ywyz{ƒ„„ƒ|obQ?2[„¢¨®¬¦Ÿ®¾É³‡oXKC;DLVesŽœ¨³¿¹´­¡•‡udabddefhjr~‹’—š•‹Šˆ‡‡‡ƒ€}}}~€‚€~|xutuwz~‚‡‹‘’“”ˆ{uomkknquz…Š–œœ—‘Œ†€~}{vromkqx‚„†‡ˆŠŒŠ‡„‚‚„}yzzyxwxxy|ƒ…‡‰‹Œ’•‘Š„~ytsrtvy|€„ˆŒŽŒŠ‡ƒ~jU?()a˜§±·´°¸ÍáÖ¼¡\?:57=DP]k~‘£°¾ÃÁÀ¶«ž‡p``_]ZX[]arƒ”˜•‘Œ‘’‰„}||zyvpjjosux{„Š’šžžž˜‰€vokgdcaejox‚Š‘˜›œ—‹†‚|umifchlqw}ƒ…Œ•žŸ –†~upkgedfmsy…Ž˜  ¡Ÿœ˜‘‰€vmghjnu|€„ˆŽ“–“‹†€^5#4Qƒµ»¨•§½ÐÐÐÀštZE18?HUan{ˆš­ÀÀÀ¼±¥–…skfbcegggmu~†Ž“‹‡„„ˆŒŒ‹‡ƒ‚„†‚}xqjfginv~„Š”˜œž ›’‰ukgdcfint{‡“šœš˜’Š‚}yusqnljnsx…’š™˜•‘‹‰‡~uomkotz|~Š“˜˜˜—•”‡}ywvuwy{ƒ……„…‡‰†ƒ~U,/Fn£ØÇª“ªÁÎËȬ€TB3)2;FTct…—ª½ÊÉÈÀ²£|g_WSX\`dgq}ˆ˜›˜•‹†ƒ€€€|z|~€€{wvvvzƒ‡‹ŽŽŽŒˆ„yrnnnopqv{€ˆ”””‘‰†‚ytqppqrsx|‰’Ž‹ˆ††‡…€{wspu{€‚……„ƒ…‡‰ˆˆ‡„‚ƒ„……ƒvk_< ;j¯Îı¡¾Úä˲‘kE7-'0:H^t‰²ÁÐÙÏŶ¢xbLORTUW]gq“¢¡ ž˜’‡‚ƒ„ƒzwvux|€}zwvtvz~„‹‘’’‘‘‘Œˆ€vkjhhknsy~„Š“–—•’Žˆ|vqonotx}†ˆ‰Š‹‹‡ƒ€~|zyz~€ƒ‰Œ‹‰‡…‚ƒ„„†ˆˆ‡…„ƒ‚€~|zyxxxoZF1S¢ÜÑż¶°¾Ò㾚vT3(.4@LYj|Ž¡´ÂÍ×͵£’iSOSW[_bfjt‡š¡£¤–Œ‰ˆˆˆ…‚zvtuvtsqstvz}‚ˆ“˜›™–„~zwph`__bmx‡Ž“™œ›š˜“އ€ytpnnopsvx{}ƒŠ’•’Š‚„Š‹ˆ‚|xvtx|€„‡ŠŒŒŠ…}~€~}xtkB1S‚·ìѰ›¹×ãÚÒ¬zI9*!)0PlˆŸ´ÈÒÚÞÒÇ´—zcP-' P–ÝÔÈ¿½»¾ÃÇ´™bD123Rg{¤°ºÂÁÀ¼±¦–„qaPFTcloquy}ˆ’™•‘ŽŠ††‡ˆ‰Š‰‡…€zuqnmnoprtw{‰”žŸ –‰…€wof`Z[bitŠ•šž¡ œ˜‘ˆvngggijlry€‰’˜˜˜•Œˆƒztqonquxwvx‰•™—“Œˆ…ƒ€|unptx}‚††‡ˆŠ‹ŠŠ‰…‚{ocH%&Ox¡ÊÔ¼£­Â×Ⱥ¦ƒ`H:,18AUj|‹™¦²¾ÀÀ¾¯¡{g]ZW]ciiimu}‡‘›˜•’‡‡‰‹Š‰‡€xttusrpqrtz€…Š’”–”’‰ƒ|tlkkknpsx}ƒ‹’••”“’‰ƒ}wrtvwursx}„Œ“‹‡‡‡†ƒ€~{yxxy|~€ƒ…‡Š‘Žˆƒ{wustx|‚„‡‰ŒŽŒŠ…xph\8.M~¶îÙ³ÁÎÑÉÁ¡xO;''2F`z‹š¨¶ÃÊÊÊ¿¬š†q^ULMYflorz‰’›œ—‘Šˆ‡‡ˆ‰‹‰…}yurnkkknrw~…Œ–Ÿ¤¢ š‘ˆzrkd___gq{ƒŠ‘˜  š•ˆ}ytnghkotz€†Œ‘’Ї„~{yyyxwvspq|‡ŽŽŽ‘Ž‹ˆƒ~zvsw{€ƒ†‡‡‡†„…†‡†††yeQ5 E§¹ËÁ¬—±ËÙ«gA4/,9FVn…–¢­·ÁÈŸ¤{fRRTW`hlkks‹“šž˜“ŽŠ††††††„}wsqoppqrsuy~ƒŠ‘•˜š—”ˆ‚zqhecchms{ƒ‹’™—–•‘ŽŠ…{uonlloqw†‹“’‘Š…€ztptwvohmvŠ–™•’ŽŠ†ƒxpmrw|€…ˆ‹ŒŠŠ‹Œ‡€yxxvgXD' .tºË×Ûì©¿ÔĦˆb<"'-8J\qˆž©´½ÄÊÆ»±¡}fNCHMWdpsvy…‘š § –Œˆ„‚‚ƒ~zvqmnoqsvxz}‚ˆŽ•›   š‘‰€xpic_][ajsœŸ¡ žœ˜”„xnjffggnw€‰‘˜™š—’ˆ„xqosvyz|yvv€Š’™ œ–Š…€~|zwtuvwz}„ˆ‡…ƒ‡‹ŽŒ‰†‚}}€kT<% l·ÐÐп­¤½ÕÓµ—qI &+4FWizŒ›ª¸¿ÆÆ»°¢’‚nZIPW^fnoooz†–›š•Œ‹‹‹Š‡…€yqnlklmosv{†Ž•œœœ™“Œ†€zslec`cktz€†‹”˜œš’Š…‚~zupkgjt}€‚„‡‹ŽŽŽŒŠˆƒ}z|}wroooz†’“’Œ‹‹„}wsprv{~„…†ˆŠŒ‹‹‹‡ƒ~|{{ztj`@6e’¿ë⣲Ã˺¨‰Z+ 4I_y”§µÃÊÏÓŸª˜†qZCEKQ\gotx‚Ž›¢©¬¢™’Œ‰†„~xrkecccgkpw~†”›¡§¦¤¢˜Žƒuha\XWWYeq}Š˜ §­©¦¡•‰€yrlga`^alw€ˆ“••”“’Œ‰†‚}xslfgpyŠ“‘ŽŒ†~vxy{~€€~|}~€ƒ‡ˆˆˆ‡‡‡‡‡†ƒ€€‚ƒ€|xP$3^¥ëî×À¿¿ÁÇÍ»’iJ/!,:Pf~™³¾ÅÊÈÅ¿²¤‘zbRB8L`ov~‚…‡’ž¥¡—ƒ~{y{~~zwtroruxy{|‚†Š”™œ˜”ˆ‚zqhd`_cgmu}†—œ¡£ –Œ‚xoedcfnv{}„Š’•”Іƒ€{vsssw~†‰ŠŠŠŠ‰ˆ†ƒ~yyz|}~}|{}…†‡‡†…„„ƒ‚€}yxyz{}~„‡‹ŽŽ‰ƒoL)e«ÜÔÌľ¸¿ÈÎ¥|V9 *Da~—°ÁÇÌËÊȺ¬›cNB6?O_ly„ˆ•Ÿª¨¤Ÿ’…{ywxz{zyyyyz{|}~~€ƒ…‰’”‘Œˆyrmhiotx|…‹“•˜šœ“‰wpllmoru{‡‹‘‹‰ˆ€ws{ƒ†„ƒzvz}€€‚ƒƒ‡Œ‡‚{xtquz€‚…‰ŽŽŒ‹‡ƒ{wwy|~ƒƒƒ„†ˆ‹Ž‹‰†ƒ‚€veS8>x«ÎñóÞÊÁº±ž‹tW:37;FR`y’§¹ÊÉÀ¸«ž”‹lXUVXgu€€„‡‹•˜•’І|xsqrtuwxz|}†––—•‘‡{yvrnjlpuz€†ŠŽŠˆ†„‚{xwwwz~‚‚ƒ„…†‡‡†…„‚}{{}€‚ƒ„„‚€‚ƒ…ƒ‚€}z{~€€~|}€„„‚ƒ…†††…ƒ~|y{}~}|||}€ƒ‡ˆ‰ˆ†„‚ƒƒƒ‚~xphkmq{„‹Ž‘“•—™š—Ž„|vpqsuvwx{~ƒ‰ŽŒŠ†ƒ|yvsrstvy|€…‰‘‰‡…„~{wsqtvy|„†‰ŽŒ‰‡†„‚|ywtrw}ƒ‚‚‚‚‚„ˆŒŠ‡ƒ€}|~€€~|{z{~„…‡†……‡ˆˆ…‚|y{}€‚ƒƒƒƒ„…†„ƒ€€€€~€‚ƒ‚€}‚†ˆˆˆ†ƒ€€€~|z{{|‚„†‡…„„„„„„„‚|~€‚ƒ…„ƒ‚‚‚€ƒ„ƒ€€€„†…ƒ€~}~€€‚„…‡ˆˆˆˆ‡†„}yxwx{~€„‡ŠŠŠˆ„€€|yz}‚„†…ƒ‚€€~|}~‚‚€€€€€ƒ„…††ƒ~|{zzyyz{}~€ƒ…ˆ‹Šˆ‡†„ƒ€~|zyxyyz|~ƒ†ˆˆˆˆˆˆ†ƒ€~}{zyz|€€€‚„„…………„„„ƒƒ‚€}{ywxyz|}‚†ˆŠŒŠˆ…„ƒ}zwusvy|}€‚…‡ŠŒŠ‰‡„€€€}yvxyz}‚‚‚ƒ„„„„ƒ€}{{{}~€€‚ƒ…………ƒ}|{{{}€ƒ„„………†††ƒ|{z{|~€€‚…ˆ‰Š‰‡…‚€~|zz{}~€‚ƒ„„………„‚€€€€€€€€€ƒ……„ƒ~}~|}€‚ƒƒ‚‚‚‚‚„……„‚~|{{{}~€€€€€€‚…ˆˆˆ‡„‚€€€€€~||||}€ƒ„„„…‡‰‡…„{yz{|||~€…ˆŠŠŠˆ†„~{{{|}€‚ƒ„…††‡†…„ƒ€}~~€€€„†††…ƒ~€‚€~€ƒ„…„~}}~€€€ƒ…………ƒ€~~{yy{}‚ƒƒƒƒƒƒ‚€~}}|}~€‚ƒ…††…„ƒ€}|}}~€‚‚‚„……ƒ€€€€}zyz|}€€€‚ƒ„…†„ƒ€~}|{zz|~‚‚€‚‚ƒ„„ƒ€€€}zyz|~€‚€€ƒ„…†…‚€}|~~|}~‚ƒ„„ƒƒƒ‚€~}||||||}~‚…†††…ƒ‚ƒ„~{zyz}€‚ƒ„‚~}}€€€‚‚‚€€€€€€€€€€‚‚‚‚‚‚‚‚€}z{{{}€‚‚‚ƒ…†‡‡‡†„ƒ|yxxz|~|{|}…‰‰‰ˆ‡†………‚}xwvvy|~~~€ƒ„…††‡†…„ƒ‚~}}|{zyzzz„ˆˆ‰ˆ‡†ˆŠŠˆ…‚|vuvwz}„†ˆ‰Š‹‹Š‡ƒ~~~~|{||}ƒ…††…„ƒ‚€ƒ„‚€€€€€€‚€€‚ƒ‚€~}}}~~€‚€€~~~€ƒƒ„ƒ€€€€~}|zxxz|ƒ†‰‹‹ˆ…………ƒ{wuvwy{}„ˆ‹ŽŽ‹ˆ†ƒ€}zwursvy}‚‡…„„ˆŒŒŒ†xxwvvvxz|‚……†………………„‚||}}~~}~~~€‚ƒ„……„ƒ‚€~~}}|{ywy|~€„‡ŠŠŠˆ†„‚{xuttwz}€‚„†ˆŠ‹Š‰‡ƒ|||{zyz{}~€ƒ†‰†„€€‚„ƒ€~||…†„‚|z{|}~€€€ƒ…ˆˆˆ‡„‚€~|{{}~€‚ƒƒ…‡‡†„‚~{xwvz}€€€‚ƒ†‰‹ˆ„€€€€~}|||~€ƒ„„„‚‚ƒ‚€‚‚‚‚€€€€‚…†††…„ƒ‚€}zy{~ƒ„……„„„…††„‚€~€‚‚ƒƒƒƒƒƒ‚€€€€€‚€€€€}}€‚„†‡…‚€€€~|z|~~~~ƒ„„„‚‚ƒ„„„‚|{{|}~|{|}~‚…††…„‚‚‚€~|{zz{}~€ƒƒ€‚ƒ…‡ˆˆ…~{xz}~~~~~‚ƒ„………„ƒ€€~||||}~~‚…‡…ƒ‚|{}~~~€ƒ…„„ƒ}}}{zz{|}€‚„†‡‡‡†…ƒ‚€~{xvuux{~€ƒ…†‡†…„‚€}|}}~~€‚‚‚‚ƒƒ‚‚‚€~~‚„†…ƒ€~|{|}||{|~ƒ†‡ˆˆ‡…„‚€€€|yyz|}~„†‡ˆ‡„‚ƒ‚€}|~€}{{}ƒ†„‚ƒ††…ƒ‚€~~}}|}~€€€‚„††ƒ€~€€}{yyy}‚ˆˆˆ†ƒ€}|||~ƒ…‡‡†…„€}|||}~ƒ…„„ƒ„‡††…ƒ‚ƒƒ€~{{z{~€‚ƒ…†ˆ‰Š‰‡†„‚€{wtttuwy{}€…‹Œ‹‹‡ƒ{vuuuvwwz}€…ЋЉˆ‡†„ƒ}ywvvwwwz}…Š‹ŠŠ‰ˆ†„}zyyyyyz}€€€€‚„…„ƒ‚‚‚ƒƒƒ~|~€€€~}€€€ƒ„†„ƒ}}~€~~€‚„…†„‚€€€~|zxyyz|ƒ…‡‡‡†…„ƒ‚~{yxwz|€‚„††††ƒ~}||zyxz{|‚„†‡…‚€€€}|}~€€€€‚ƒ‚‚€‚ƒ€}|{zy{}€‚…‰ŒŒŠ†‚{wvttuwz~‚„‡‰‹‹‰†‚~}|{zyxwvy|…‹ŽŒŠ†}~‚€|yz~‚„ƒƒƒ‚€‚‚€}}ƒ…†ƒ~}}}~€€€‚ƒ„†‡…„‚||}~€‚„…†††………ƒ|ywutw{ƒ†‰‰‰ŠŒŽ‹‡ƒ€|xtopsvz~‚„†‰”“‘Š„}{yxxxxxz|~‚†ˆˆˆ‰‰ˆ‡…ƒ‚€€€€~~~~~~~‚‚‚ƒ„…‡Šˆƒ{wwy{{{|||}…ŠŒŠ‡ƒ|||{{{|~€‚„†‡„‚~|}€€€€ƒ„„„~}~€‚„ƒ€€€‚ƒ‚€€€€}{z|}€‚…„ƒ‚€€€€‚~{z|~€€€‚ƒƒƒ€~}}~€€€‚‚ƒ„†…‚€~|{||{zy{ƒ„………„……†ƒ€|{yz{|}}}‚„ƒ‚ƒ„…„‚~}||}~„ˆ…‚€ƒ|||}€ƒ…†ˆ‡†…ƒ‚€€€~{xyyy{|}€„†‡ˆ‡‡‡ˆ‰‡‚|ywvy|€€€€€€‚„†‡ˆ‡†„ƒ€}|}~€‚€€~}€ƒ…†‡†„‚€€€€|ywutx|€ƒ†‰‰‰‹ŒŽŠ‡ƒ~yuuuuuuy}€ƒ†ˆŠ‹ŒŒŠ‡ƒ{{||{zz{}~~„‡†„……†…„„‚€‚„„€|xvsw{ƒ‡ŠŠŠ‰‰‰ŠŠ‰ƒ|wusuvx{}€‡Šˆ…ƒ‚€|ywwwxyz„ˆŠŒ‹‰‡††…€{wvuwy|‚„„„„„„ƒ‚€€~|}‚‚‚}{zyz|~€‚ƒ…†………†‡ˆ„~yxvvwyz{|~ƒ†‰ŒŒŒ‰†ƒ~|{z{||{zz|~€„ˆ‡„€‚„‡‡„~~€}zz|€‚ƒƒ„„„„„„ƒ€}zy{}~€€€€€€‚ƒ‚€}zy{~€‚„ƒ‚‚ƒ‚‚|ywutx|€‚ƒƒƒƒ„……ƒ‚€€€~{xz|~€‚‚ƒ†…„ƒ}}}}}}‚„„…„‚€}{{}€‚ƒ‚LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/bong.wav0000644000175000017500000000667613263212010020604 0ustar aeglosaeglosRIFF¶ WAVEfmt "V"Vdata@ [Z[]^__^]][ZXWUTQOMJGEB@>;9766666678:70*%%+17=CMV_hqw|€†Œ’Ÿ­»ÇÓÝæïòôõíäÚ̾­–€lYG7'   !-:GUcr€ž§¬²¶º½·²«¤’„vhZL?3& &5EVgxˆ™¨¶ÅÑÜçìò÷úýüúùöóíÜ˸¥’{cK4  +8ER`n{ˆ–¤³ÁÍÙãëôõõôîèÞ˸ „iT@-  '>Tk“¤´ÀÌÓÍÈÁ¹²§œ‰{{zxsog^UJ?3% $1?N_o}‰–¢¯¸¾ÃÇÊÍÊÇÄÁ¾·ª„xj\N@3'  &.6=DHLPU[bjs|„Œ“›¢¢¢¡š”‰tg[PF;1'"""$%&()***(%""""(.4=FQ_nz†‘˜Ÿ¥¦¨¥ ›•Š…zwtrrqnkgb\VMD:."!"&*/6," "%(,18AJT`ky‡–¦µ½¿ÁÁÁÀ³¦™Ž‚yrjd]W[_cgjlmnmmmga\YVVXY\_bgkortvwwtpmg`ZUPJE?=;:7410.-+*)'&# "%(*-4GPYbijlmnnkgcb`ahov|ƒˆ“•˜™—•‘Œˆ€xpic^YURPONMMNOPQSTVWXYYXWWWWX[]_acfjmorqnlifca^\ZXUQLGA:3,%!&.7@IS\fmrxz|}zxtojfb_][XWVTSQQQQPOOQRTTUWY[]_acdfffedca`_]\ZXVTQONLKJIJLNQVZ^cgkptvxz{{xsoid^VOH@966689;AGNU\cinswytoib\TKB;4.../25;BJPV\^adddca_][YWVVVWXZ[^beiloqstuvspmiea`____bfjloolheb`^]]]]]]][WTNF?83-)$#$&)-28>DKSY]adgjfb^XSNKHEA>>>>>>?@ABDEINTZ`fnu|ƒ‹‘–›Ÿ¢££¢ ™”‰zqh^UME>820//258<@EKQUZ^cggc`\YUME=5.)(&&&&,17=BGLQUX[WTPKF@81+'"%(+16=GQ[enwˆŒ‘•™œžŸ ¡¢¡ Ÿœš˜•’Œ‰yriaYQIB<66678:;=>@BCCCDEGIMPRTUSRPKGB=741.013468:=AEINSVVUTSQOMKGDBEIMPTY`gmsy|~…ˆ‹’”–––•“‘Žˆƒ}wqib[SKC;4-'""(/6>EMU]elsx{~ƒ„{wrmf^UOHB@?=;:;=>@BDGJMORTVWXYXXWWWWXZ[^`cfjmnoooomljihfecb`___``abcefhigec`]YTOJFB@?>@BDIMRW\bhnqtwwxvqme\SJA8.$")08AJRY`fmsw{‚……ƒ€|yuohaZSMJFCA>>>>>>?ACEHKPV\aglquy{~€~}{xuqmic^YSNIE@<964324578:=AFKOSVY\^acccdddefghjkmnopqqqpponlifa]WPJEA;60-+***+/48<@DIOSW\`dhlpsw{~…ˆ‹Ž’’‘І}tj`VK@4+"%-5>HR[biotyxvuplhc_[VRRSSUVWWWVUUSQOMJJJKLLMLJIGFFFGHJMPV[`ejnswz}€ƒ„…‡‡‡†„‚~zvpiaXOG@92+#$)/5=EMV^fmtz‡‰Š‹Š‰ˆ‚}xsnhb[VRNKHFDCCCCCCDEGHIIJKKLMNNOPPQRSSUVXY[[[[\]]]]]]]^^_`abegjloqrtuuusqolie`[WSOMKILNPTX\afkosttsssplga[UPKFA<9766669<;:::;>@DIOTY^cinsxyyyxwuojd^WSOKHD@?>>>>@BEIMQY`glqtvxyyyvtrpnkheb`]ZXVTRPOOOOOOOPRTVY[ZYYWVTRPMKHFDCA?>>>?@ACFIMQV[`ejnsw|‚……†…„ƒ}ytoibZSMGB<743222369=BFKOSX\`bdefgecb`^\YVSPMKIGEDCCCDEEGIKNQTWZ\_bcdeeeddcba_^\[YVTRPPQSUWY]`dgjmortuwtqmjfb\WRMHEC@>;;<>?ACHOU[agkortusqpmjhd`]YVQLGC@=<::::;=>BFJOSW\`dhkheb^[WRNJEA@>=<:;<>AEIOV\ciouz„‰Œ’’’‘Ž‹†|uohaZRKD?=:8779?@AFKQV[`dhlorqppnmkfa]YVROKIFDCABCEHKOSX\aejmpsvyxxwvtrolhea\WRMHDCA@?>@BDEFHJLNPQRSTTUUUUTSSQOMLKKKKLMMMMMPRTX[^acdeefffffedca_]\[ZYWXYYYYY[\^^_`acdefggfffedba`_][XXWVVUTSSSSSSSTTUVWWVUUUUUUUTSSRQQLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/autsch.wav0000644000175000017500000001441613263212010021135 0ustar aeglosaeglosRIFFWAVEfmt "V"Vdata^v‡wh^ZVj†¢¯¼ÄÀ¼°›†tdSH>8?FY{ž°ºÅ¹­ ŒyhZMQ\fƒ¢»»º°–}ƒ›²™|`SFJiˆ™¡©lRnŠ£¶Ê²KBAEw¨¾œybTE^Ÿ¤©¤‰ol}Ž›§±¤—“¤´³£“tO***,4;FUd|˜´ÀÌί‘ƒ‡‹ŸºÔµ”tU7(+.,)&=Un’µÌ񯁤‰iI3Njƒ–©¦–†~xo\J;60EiŽªÅÛ̽²¯«‡qY@.\‹­µ¾¬†`NB7>EObu¨ÃÏÖÜdzž‹xkd\doy„v\H;-DgŠ¡¸ÊÏÓÖØÙ²{D6+(B]|¡ÆÕÛáǪhC+#".9bŽ·Ç×ÜÐų‡ƒ~qebo|~zvfSHw¦ÈÏÖ±n*)6CScosvЬÎÚà㵈`C'"1@=5/MjНÓâÞÚç‹oS@DIJHGMU]it€Ž›¤©­ Ž{rkl±¿²¦—ˆyŒ¢®lO9"2VyzwqT7;q¨Ç×çÜͼ“iG30Nn˜ÁÛÕÏ­w@>GQo§µÃÉÉɨV>'8Scipƒ›³ÄÕÕ§zXD/FkªÅÚÛÝ×Ë¿™h8)W‘¹ÌßÇr`OHn”¨¥¢£¤¤¯»½Œ[7'7o¨¸ÄÎÒ×ÔÆ¹”`--4=Si}ž®¾Ïº †pZVy›µÇÚѲŽjJ35Kbz’•˜¡»ÕäèìÀ„IWdosve@'Da‹µÎ®ubNj™ÇÖãä·ŠlcZlЍ—ƒo\ILnššš„m_ƒ¦ÃÕçÓ«ƒ~|zjZH1";T~¬Ñ¬ˆwŒ ¸Òíºw8'-Hg‰¬¯«©»ÍÜçñß·h@  <ÁÔçñáѵ‹b`kvqmcE& 6Kx¯æëìàšU:Tn®ÏŸ¥r@ 4M^n‚«ÔïôøÚ©yQ+ *9K_s—¾âëôðÕ»˜nE. /Qoƒ—¤«±»Çл§c9#@r£²ÂÒâòöòî‰O6 !1G\s‰ »×îó÷ùùùצvM&%4CRap”ºÚàæÕ¥uU?(  ),)&_ŸÛåïìÔ»yV?) +@q©Þêõû÷òܶ‘d6 $8ZŠºÑßìáÕÎÏѳx=9HWÃèÖÃ°ŠˆŠjF' "EgœÑýýýôàË¢n:' 5T±äð÷úçÔ¼šy`L8Rs’©¨’|ƒ¶Íäô·zH- _ ÓäõòÝÉžm=/ -?P`q‡ ¸ÐèõæØ²r3%(*S|ž£¨©¨¨¹ÑèëìàŸ^2  (=f´Óóýýýݹ”g9 T™ÍáõñÞ˧]m~Žž®«œ‡‚¦ÌÙ´g< N{¡³ÅÕäòøûüÈ”d@4Qn^NR’ÑïìéÉŸtN( 1Jlލ¾ÔÞæëâÙÅ¢Z3 %Jo¡´ÃÏÜçñöà˦i, 7k•|c[p„¤ÌóÕ«T'0Ls¢ÑÞäêëìêáØµ{A) 7W|¦ÐâîøçÕÈÇÅÌÙæ²h(2;Cc·ÏçV5$Im‹©ÁÁÁÉÚìØ´a2 '?g ¤¨±ºÄ×êö÷ùÆv%;_x}‚~zÇëÒº™h7!XŸâéðå²€mt{{zx[>/=LZgtiWF`{˜½ãöøùß¼™pF'(*%(KnšÆêïóÚ e?#B‚¸ÄÏÆ¢pmj…¢¶¢ŽsM'( )Ev§Çß÷éØÂˆN1EXbfjV?/Y„¨ÀØË¥hSCTel`TZm¥ÎôñïÙ•Q)  +BoœÀÙóùùùËžsP,*4+0Sy¨ØñññÖ±Œc; 1Nz®áëñðѳ‹R5P‚³×æôùùùñèܵŽg> 2W{—³ÉÓÝçïøÏ›iF" .Hw«ÞèòóÞÊY /W~ °ÁÎ×ßçîõßÉ©h'"Q€­ËéùùùêÖ”d:' -CÂùùùóäÖ°~L2 !9W‚¬ÉÞó÷øøõòèѹµ½ÄÏÛæíõóáЬ{J/ (Q‘ÐåðùùùôâÑ®|I. #:Zƒ¬ÂÒáκ¥ˆlk‰¦ÀØðÝÈ´¤”˜ ‡_8% "=X|¥Îßí÷íãËŸsM+  2R†¹×ç÷æÏµy=#Fi²×Ú×Ó¿«›“‹~n^E+ ;czƒŒ¬ÓùùùòÙÀ™f2 !7^˜ÒèñùàǬ‰eUY\cksz€Š£¼ÏÜéË›jI(  *YšÛéòöáͬyE' ,Mt£Óêñøâȯ¥›‡a:2@Mh…¡¤¨°ÃÕâéð·o)&:l§âêóôäÔ¶Š^@'  =}¼ÙéùìßÊšiSZ`{À°Ÿ‘‰–¶×Ì®c4 !4Lgƒ©ÐòõøîÔ¹’c4'  (`˜¼ÜøíãΡt^YSaqsgewˆ¢ÃãÝξz6 %A^Áçïöò娬u>)-b—»ÞõãÒ´…WUfw›¿ØÂ¬—ƒny’ªyL  &Ed‹³×äñùùùÚ¨vQ-  ^¯ùùùòÞɵ¡•¡©€V4!Bi†¡¸–sU@+1Mi{Šš®ÂÕäòæÀšqE *9It©ßêóöéÜšqWC/01/"-Bs±ðóò鹉^:%Ba€£Çáëößµ‹a7 -JOE;Y}¡ÂãìÄœpA0^‹°ÔîñôçͳD %")?T|©ÕÒÏŨ‹{yxƒ’ ›—mNH]r˜ÃïÓ´\' >_‚ªÒëðôʈG0!1?ITt¢ÐÛà๒uj_WPIC<;h–µµ¶³¯ª¶ÄΫ‡c> =[u«ÇäòôõÛº™pG)&#$'*Ccƒ—«»»¼³¡Ž}l[iw‰ªËÛØÕ¾|tlfb_R:! /[ƒ•¦ºÒéòôõèÙĆH 8`‰±ÙàÑÇC 1X±áîâ׸•vwywofT9 4`ƒ’ ¶ÒïõõôßÉ«q7%-;K[OCFz®Ñáñ»l$c£ÍßðñíéÒ¹ …iO8! 'Gf–«ÂÚóïêß·hB&5.%(1LŠÈÙ˾]1Uyœ¾ßêæá¿–odZ[tŒ‚\6"(HgƒŸ¹ÐèðóôÞÇ©vC(%" ]¤ÆÂ½”\$Iq™½áõõõîãÙ®€W@* ,Sy˜«¿Ñâóõõðʤ{K  0PÏäÝÖ½¡‹°ÕîïñëáÖ¾¡…iM5' GƒµÏéõõõèØÉ˜g=) !*2Rr“·ÚãÏ»ž}\ŒÀêïóòìæÉ wS/ ?z°Ëåõõõðéá½”kF!)28>0 aªÝçñÔœdfs£Æßåëâн”f_’£´ÅÖäëóÔžgF)1JZbjƒŸ¼ÑçéÄvh„©Ì¿±ª®²°ª£›’ˆwfQ5"2DVh‡¦Ã×ëìÙÆ”V 5iœºÍàãäݳŠw‚ŸµË¶««ª“["%Hj€•¡€_B,5Ln’³¼ÄÎÛèÝÁ¦t= *>]ƒ©¹ÄÎÝëñä×µNA??Thsg[g‰ªÄÛñÞ˲‚R1 7Qiš¶Òäêð·f 1V–ÕãÚÑØßá͹šl=@fŒ²ÙëîñÊ›mH#)Ac޹¼µ±ÈÞÝ¥nOF^|—²ÅÔãéíñññèͳ–xZG6%0Ek•¿ÐáîïñêÝЬVH93CSXSN@/:Vo}Œš©¸ÉÛíïðêÈ¥ŠwdJ-"Hm“»âéîìѶ§¨¨£›“wXCd†’|eK. 5Lx¤ÅÑÝäèíïðí¼‹cM7'&;g’´ÎèïððÓ¶ž’†vaLR`n«ºžƒc?"*RzŸ¹Óäèìïðñ·zD/"3DZqˆ¥ÁÖâîçØÊ³š……„{fP=*;d‡…„sI =Y„±×Ë¿½ÊØâéðÄ[>!<\~¤Ëáéðìæà°€U:&3cžÙÖÓÔÞèÛ·’h<':Mc|–²ÏìèäÚ¹—y`F:4.(""5HPIC6'(XrŽªÀÒåèëìéæË’Y9&3Jf†¥ ˜‘Ž‹•²ÏÞåíÚĵÇÚÜÄ­‰\0" *K}®ÆØêëíéÝÒ´ˆ[B-+:Nk‰©¶¨”€`A'3tµÐßíííéÙɧr<&*Mp’±ÐÝáåлŸh1!+Z›Üŧˆc?/:Fa…©¿ÔäáÞÏ­‹gA )?l™¸ÏæééæÏ·|[G=3ARd~˜®¹Ä²ŠaE-6No—ÀÒÞèáÚÒÆ»˜^$#*h¦×ÞæéééÓ¶™qI(!,:Sq¯Ïà³…]?  &De†¦ÆÜâçßÑ¡}[D,>}½ÑÞéééäÙͳk]RHA:=Qe~œ¹¢€_D)!0G_x‘©ÁØåÚÎ÷¬‰_5*&c ÆÖåéééÝÑÀ›v^VMD;2AQdƒ£¥…eJ3,@QX`gnt‘¹âÚÎø®šxW?-0Hc’ÀßáäãàÝħŒ{j]XSE1;b‡Š‚\6#2OiWFK¸ÕÝäÞÕÌ®sU8'!7]ƒ¦ÈâãåáÚÒ´elroR51H_p~t[HHIKORE2RŠ»ÊÙàÞÝÓĵf@1#)Pv™¹ÙàããÙϼšxhd_I03I[ennhbjszjZKA6W˜Ùãâà×ÏÆ¾µ¥x‹¨Ä¯›Ž’–› ¥ƒT&# !+55-$.=Mi„˜’Œ”š­ÅÜÌ»²ÃÔÒ»£T):Pex‹¢½ØÏµš„n\dkfN6/12+$"*3JjŠŠ‹ž°ÁÎÜÙÍÀÄËΤz_chs„•¢­¹¼¿¹ ‡ƒœxcN9+.1/)# *6Fh‰˜–”©Åà×ÍÄÁ¿´ŸŠnO/Qu–ª¾ÍÖßÙÍžx\o…vgeimf_VD1$"!&*?Vly‡š¸ÕÝ×ÑÅ·§‡fNG@Swœ³ÇÚÝߨº‚jRVbkaVTev}{zgN5-$ $(-15a›ÔÚÞàßÝÔÁ¯d;DN\|µÅÕÛÞáʲš‡thgfYF3G]nnnfS@3)/ARRSe–ÇÛÞáÞÛ×Ƕ›j:.;Gf‰ª¼ÍÚÝà┈o^RF?@AOg€‡ˆˆq[F6%#,489:h–¼É×ÜÚÙο°‘qT@,+?Rs™ÀËÕÝÝÝÓ¾¨—‡wY;#(,<]}†„‚~ys`N>2&(19e–ÃÍ×ÝÝÝÙÓͦxPSW^l{~{yrjaP>0,'1CV­ÙÙÙÙÙÙÕÍÆª‰gO7)3=J\n…ž¶ÂÍϺ¤€oe]UJ>/.CXj{Œ’”œ¤ Œx_E*()+2:EWix„Š‚x_G8>CQfz™ºÙÙÙÙÙÙÒŸœzXI9048DXk€•ª¢š’‡{pdXOF>7/.BUfu„€vkhfc]XSNJj™ÉÑÖÙÙÙÙÙÙ̹¦„aDDEJWds…—ž¤¥’~hL1&&&&&'3>Md{|wiXK]p|||Š£¼ÇÎÕÕÕÕÕÕÐǾ¨seWOW_eimsy~}|xhWI=126:EOWWW\enkd]UMJVbs‹£µÄÔÕÕÕÕÕÐĸ¢ˆmd^[clu€Š“›£šƒq`PA3-+*3UmŠªÊÓÔÕÕÕÕÕÕÎÀ³ Œyrkiou~‰”›¢¨ ˜xdQ@/,-.6=FQ\elroicSC50,2EWj}‘nc{”¦°¹¿ÂÅÈË˸®¥œ”Œ……‡†ƒ€€€{unhb\SJC=7667?HOU[ahorttsrt{‚›©³¼ÅÇÈÉÉÉÉÉÉ¿±¤¤¤£Ÿ›”‹‚€€€€€~}xmbUH;8778:@M[bfjkmnnomhdju€ ¯¸ÀÆÇÉÉÉÉÇÆÄ½¶´º¿½¸²§šŽŒ‹Š‰ˆˆˆ…‚rd\\]YSLF@;=@AAAEMU`juroljhlu†“™ž¤ª¯µºÀ½·²©Ÿ—”‘’•˜ž¥¬ “‡‚}|}~|{ytolllh^TLE>>>?ABFLSY^dinsuwz„Š‘—œ ¥ª¯¯¨ žžž¤«³´µ´°¬©¨¨ –ŒŠ‡ˆ’–˜›˜”‘m\PD?ACJT]bgknpsx|zvsnigqz†‹–›ž¢¤¤¤§¯¶²ª¢œ—“—šž £¢ ž—‰†‚~}}~{vroke^VRNLOSSNIFEEIOTZ`gpx~€ƒ„……LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/holz.wav0000644000175000017500000000243213263212010020615 0ustar aeglosaeglosRIFFWAVEfmt "V"Vdata›~~ˆ‘—žœ™”…~wpeYTVW`mzŠ›«¯´³«£”nU<$ #8HT_fkr­ÈÜðúüý÷ïèϵŸ‚jK-$##-7?AC@;79<>GQVUSTUUez›§®¨£¨¸ÈÖáíÞÎÀ¾½¿Ãȸž…p\LQVXUSC,$Oz‡gF=@C]{–›Ÿ¥«²µ·¸ÁÌÖÝåæÝÔ©w^HQYg›­¸ÃÇÈȾ³¯ºÄºŸ„eE%!(6C]wŒ•ŠnRHFCViz……|…’ ¸Ñçðøúôîáп®Œ}oc^XM>/" &5@JT]fp|ˆ„dC;AH`|–›¡¦¬²µ·¸ÁÌÖÝäæÛÑ¿¦u\FP[iƒœ¯»ÇÉÉɽ²­·À·œcE&!)8G_x’‡lQHFEWk{€††|…”£»Ôëòùúôïáо­œ‹|mb\WL>0" (5DTds‚mL9@FYtšŸ¥«°µ¶¸¾ÉÓÛâèÞÔÆ­•|cKMXb|•«·ÃÉÉÉÀµª´¾¿¤ˆlM/"%4CXqŠ’tYHFERex„‡‚}³Ìæð÷üöðæÔñ €qc^XPB4& $1>KXdq~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/roehr.wav0000644000175000017500000002521613263212010020765 0ustar aeglosaeglosRIFF†*WAVEfmt "V"Vdata*†……ˆŒ“‘‰zslt}†Ž–š™—•”’Š‚zqib^YURNPRTVX[`ejmqlga^Z[biouzzyzzz|…‰ŒŽ‹ˆ†ƒ}{zz~ƒˆŒ‹ˆ†„‚€~|zwusssw|†‹–› ¥©­°³´´³­§¢ŸœœžŸžžš—”‘ŽŒ‹‰†„}zywxyzyyxwuuuvy}‚„†‡‡†††††††„ƒ|yxvwxxvsqkfcccfkoqqqmjgfddddba`^\ZXVTRPSWZbiprssrqtwz€†‹‹‹‰†ƒ…ˆ‹‘—¡¦ª­°³´¶¸¹¹¸¶´±®ª¤Ÿ™“ŒŽŒŒŠ‰‡{tmfdeehkopqrrrsttuvvtsrpnprux{}€‚ƒ„…‡‰‹Š†‚}xwxyz|}ytpkfeghiklrw}ƒˆŠˆ†„ƒ}yuqnmpruxz|~€‚„†‡‰Š‹ŒŠˆ…ƒ€~}{zyxz{}~~|zxwv{ˆŒ‡ysmqw}ƒˆ‹‹‹ŒŒŒŽ‘“””””“‘Œ‡‚~zy{}‚„…‡ˆˆˆ‡‚~zvspnlmmnt{€‚…ƒ~yxwx€ˆŽ’——–•”“’’‘’’“•™œŸ¢¦©­¯¯¯¬¦¡œ˜“‘Ž‹‡ƒ}wqnlkmppnlg`XTPMNNNNNNNNOPQTWZ^afjosvy{|~~€€€ƒ†‰Ž”™™™—”’ŽŽŒ‹ŠŠŠ‹‹ŒŒŒŽŒŒ‹ŠŠŠŠ‹ŒŽŒ‹‰‡††‡ˆ‰‹ŒŽŽ‹‰†ƒ€‚„†ŠŠ…ysonnooojfb\WWZ]bglllkkjihgfeekqv}ƒ†ƒ|yvspmjjotz…|xtollllllmnoprsuwyz|€„ˆŒ’’’’’’–šŸ£§§£ž™•‘”™¡¥¥ ›–‘Œ‰‡…‚€~~}|{{yxwusqlgc_\^bfilmljihghhhiklnqsvy{~ƒ……„ƒ„…‡Œ”› ¤¦Ÿ™“Œ‘”•––“Šˆ†…„‚€}zwtsqsvy{||{zyxwvtrqpprstvxz|ƒ„…†‡ˆŠŒŽ‘Œ‰†‚~zvrolifdbbbcegilnquxy{||}|||{yz|~†‹ŒŒŒ‰†ƒƒƒ„†ˆ‰ŠŠ‰ˆ‡‡‡‡‡‡ˆˆˆ‰Š‹”˜œ›—“†€€ƒ‡ŒŒŠˆ†…„„ƒƒƒ‚€€€~~}||ƒ†‰ˆ…‚~yurpmkjjkklmnkhea^]^`bdfhkmorrrqpooqsvx{}‚„…ˆ‹’”—™›Ÿ¡¡¡¡¡¡   ŸŸŸ›—”Œ‰‡…„‚‚‚‚‚‚€{upkecccccdgiloruy}„ˆ‰Š‹ŒŒŒŒŒŒŒŽˆ„}{{{{{{zyyxwxxxyyzzzzyyxwvuutsrrsstw{~„†‡‡ˆ‰Š‹ŒŽŽŽŽŒ‹‡„}|||}~~€ƒƒƒ‚€~}|zyxxwvuuvvvx{}ƒ†ˆˆˆˆ…ƒ€~|zxwxxx{}€€€}zyxwvvutrolihhhkmpsux|‚ƒƒƒ‚‚‚‚ƒƒ„…‡‰‹‘”–™›Ÿ¡¢¤¤¥£ ™”‹ˆ…ƒ€€€~}{ywtromjhfca_^^^^_abcccccehkoswwwvvuvx{}€‚‚‚€‚ƒ„†‡‰ŠŒŽŒ‹Š‰ˆ‰Š‹‹Œ‹ˆ†ƒ€|}}~~~€‚ƒ„‚€~{xy…Œ’™œžŸ¡¢¢žš–’‘‘‘’’’Ž‹‰‡|wrmmnnoppppqqqqqqqqrstuvwwwwwwxxyz{|}€‚‚}|{}€ƒ…‡‡„~|zz{|}~~|{||}€†Œ“–“‹‰‹‘’“‘‘‘’•𠢤¥Ÿš•Œ‰ˆ‡†…„‚~|{ywusqmjfffhlqsturolkiiiijlmquyyzywtuvvz~‚…ˆ‹Ž‘”—𠤤¥¤£¡¡¡¡£¤¥¢ ˜“‹‡„€‚…‰‰‰‰‡„‚€~|zywvvuuuttssrsvx{~‚„…‡ˆ‰Š‹ŒŽŒ‰†‚~ytng`Z[^`eikigd`\^`behhc_YSMNPSW[]]]\[[]^`bdeeeeeeinsz€ƒ€~{xty€‡–›˜”‘Œˆ‰Š‹‘•™¡¤¤££¢ ¡¤¨«¯²´¶·¸º¹¶³°®«¨¦¤¢Ÿ™–’Œ‰‡…ƒ~|zxvsqomkjjloqrsnd[TNIQYahoqponnoqsuwyzzz{{{|}}}}{ywvuty}ƒ„ƒ~zwusw{€|sjb\VWYZ\_bgloqsplifc_\YY[\fq|‚ˆ‹‰‡ˆˆˆŒ“•—————————˜™š›ŸŸŸŸœ™–•”“““““““““Ž‹‡ƒ{wusqstuy}…‰‘•—˜—•””—™¡¦£ œ”ŒˆˆˆŒ’—–”“މ…‚€}|zyyyyyyyyxxxvtrpmnqty„}yqjdb_```__^^]^`bdgjhgec``bdfilkjjhggjloswwwwvuvz~†Š’“”””•••–——˜™šœŸ¢¤§¤ œ—“‘‘‘“–™œžŸœ™•’ŽŽŽŽŽ‹ˆ†ƒ€€€€‚ƒ„†ˆŠŒˆztmikmortwz}‚‚‚‚‚‚ƒ…†‡ˆˆ‚}wsooqtvxyuqmjgghhhhhec`^]^adgjmnnooonmmnopw~„ˆ‹‹‡‚€~}„Œ”˜˜“‹‡‚~zwxy{{{zyxyyy{~‚„†‡ˆ‡…ƒ~ysrqsw{‚†ˆ‹‘‘‘‘‘’Ž‹†€zzz{†ˆ‡†zssst{†Š‘’Š…€|{z|}‚…ˆ‹Š„}vvwy…ˆ‡†‚}xwwx{}}wqi_VSRRTWY\^aceghiklnpruwz{||}}||{zyx{~†ŠŽŽŽŽŽŒŒŒ‹‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠˆ„~zy|€„ˆ“•—™š–’ŽŠ†‡‰Œ’“““’’’ŽŒŠˆ†„‚€~|yuqnkhjkmnpnjfb^[_begihd`\YV\bgmruwyz|}~€€‚…‡ˆŠ‹‰†„‚~~~€‚„…‡ˆ‰Š‹Ž‘“”•”””’‘Š…€~|}…ˆŒ’”—™›ž Ÿž—‡ƒ}~€‚ƒ…ˆŠ‹‹Š†‚}zyxwvutsrsttw{~€}zz}…–˜šš”ŽŠˆ‡Š‘‘‘Ї‡‡‰ŒŽŽ‰†„„„†ŠŒ‰†…†‡Š‘Ž‹ˆ€xtvy~ˆ‘”—˜—–“‡€xoic]YUQQQRTVY]aflnljfa[]`cjqwxzyxx{~†‹ŒŠˆ…ƒ€~|yy}€„ŠŽ‹ˆ†„ƒ€~|ywtrqtx|‚‡Œ’—œ¡§ª­±´¸¶±«¦ œœžŸ¡Ÿœ™–“ŽŒ‹Šˆ„€}yvwxyz{zxvtrqvz~‚†‡‡‡††††††††„~|yvwwwwwtojfa]bfkottpmjgdddcccb`][ZXVSQQQT\cjputssssu{†ŠŒ‰…„ƒ…Œ’˜ž£§ª®°³¶·¹¹¹¹¶³±­©¤ž™”ŒŒŒ‹Šˆ…{tlhdcfiknpqrrssttuuuusrpqqrux{~€‚ƒ…†ˆŠŒŒ‹‰†|zxxy{zywtojhgghilptx~ƒ†ˆˆ†„‚|xtpppqsvxz|~€‚„†‡‰ŠŠ‰ˆ†„‚€~}{zzzz{}~}||ywwz~‚ˆŽ‰†~vqsuy…ˆŠ‹‹‹Œ’”•••””“І|{{{}‚ƒ…‡‰‹‰…‚~zurpmkhkpu{‚†„}xtv|‚‰———–•”“’’‘‘‘”—™œŸ¢¦©­±µ°«¥ š•“Ž‹‰ƒ}vpjiknprtmf^XQNNNNNNNNNNNPRUX[]bglpuxy{|~€€‚„Š”˜š—”’Ž‹‹Š‹‹‹ŒŒŒŽŽŒŠ‰ˆˆŠ‹ŒŽ‹‰‡†…‡ˆ‰‹ŒŽŽŽŽŒ‰…ƒ‚„‡ŠŒŒ‰…~xtpnnonljfa[ZXY^cgjllkkjiggfgjlqx~ƒ„|xurolmnpuz|xtqnlllmmmnoprstvxz}„ˆŒ‘’’’“–˜› ¤¤¢¡œ—•–—™ž£¢¡Ÿš”Œ‰‡„€~}|{zyxwvsokfa^_acgkllljihhhiiikmortwy|~„„„„ƒ‚ƒ‰•¥¦¢ž˜‘‹‘”—–”’Šˆ†„ƒ‚€}zvrortvy||{{zyywusqppqrstuxz}‚„„…†‡‡ŠŒ‘“’Œˆ…}yuqmjhecb`bdfgikorux{||}}}|{zyyy}‚‡ŠŽ‹ˆ…ƒ€‚„†ˆ‰‰‰‰ˆ‡‡‡‡‡‡‡ˆˆ‰ŠŒ”˜š›š“Œ†}„ˆ‹Ž‹Šˆ†…ƒƒƒ‚‚‚€~~}~~~€ƒ†‡‡†}xuronlkjklmlkjhd`_^^`bdfhkmpqrrqpqqrtvy{}‚„‡‰Œ’”—™œž  ¡¡¡¡   ŸŸžœš—“Šˆ†„‚‚‚‚‚|ytnigecccdfgjlorvz~‚…†ˆŠ‹ŒŒŒŒŒŒŽŽ‹‡ƒ}|{{{zzzyxwxxxyyyzzzzzyxxwvutsrrqsvy|€ƒ…†‡‡ˆ‰Š‹ŒŽŽŽŽŽŒ‰‡ƒ€}|||||}€ƒ„ƒ€}|{zyxxwvuutuwy{}ƒ†ˆŠŠ‡…‚|zywvuvy{~€‚€~|zxvvvuuuroliffiknpsvy|ƒƒƒ‚‚‚‚ƒ…†ˆ‰‹’”—™› ¢£¤¤££¢˜“Ї…ƒ€€€€}{ywurpmkhfca_^]^_`abccccdegkosvxxwvwwxz}€ƒ‚ƒ„†‡‰Š‹Œ‹Š‰‰‰Š‹‹Š‰‰…‚~|}~~€€ƒ‚‚€}z|~€†“—›žŸ¡ ž™•‘Ž‘’‘ŽŒŠ‡„€{vponnnopppppqqqqqqrsstuvwwwwwxxxyz{}~€‚€€~|{}„‡‡…ƒ€}z{{|}~}||{zy~‚‡“•“‘Œ‰‹ŒŽ’’’‘Ž’—› ¦§£ž™“Ž‹Šˆ‡†…„‚~|zxwvsplifbfjnrvwtroliiiiiijnruy}{ywtrrvz~‚†ŠŒ’”—šž¡¤§¦¤£¡  ¡£¤¥¥¡œ—’މ†ƒ}€ƒ†ˆ‹‹‰†„‚}|zxwuuutttsssttux{~„†‡ˆ‰Š‹ŒŒŒŒ‰…}xsmf`]Z\aehjlhd`_]_bfeee_XSPNOSWZ\^]\]]]^`bcdeeefhkouz~~zy{|€ˆ”–˜”‹Š‰ŠŒŽ“–𡢤£¢¡¢¤¥¨¬°²´¶·¹¸·¶³°­«¨¦¤¢Ÿœ™–’ŽŒ‰‡…ƒ€~|zxvsqomkklmortojdZQNQTZclnoonmnpqsvxyzzzz{||}~~|zxvtuwz~‚†ƒ€}ytsvx|€…xqh_XXXYZ[_chlqsqolheb_[XTU_isЋЉ‡……‰Œ“—˜˜˜————————™›Ÿ¡¡ž›˜–““““““““““““‹†‚}ywusqorvz~‚†ŠŽ’•™˜—•”“”™¡¤§£›“Œ†‚‡’•™—’‰…€}{zyyyyyyxxxwwvtronmmtzƒ€xpjd_`````_^^___bdghigeba``cfijlkihiiimptvwwvvwxy}‚†‰Œ‘’“”••–––——˜š› ¢££¢ ›—“‘‘’“”–™œœ››˜”ŽŽŽŽŒ‹ˆ…‚€€€‚„…‡‰Š†ƒyrnmlnpruwz}€‚ƒƒ‚‚‚ƒ„…†ˆ†ƒ€{vpqqrtwwusplhgghhihfdb_\^`behklnooonnmmlnsx~…Œ‹ˆ…}|‡Ž–žš—“ŽŒŽ‘“І€{xxxyz{zyyxwxz|„…†‡ˆ‰ˆƒ}xsmosw{€„†‰‹Ž‘‘‘‘‘‘’’‘‹…€zuw|‚†‹Ž‡ysmou{‡Ž‘‘’Š…€|yz|~€‚…‰‘’Šƒ|xsu{…‰‡|xtux{{{{qg^WPORUWZ\_acefhjkmopsuxz{}}}}}}|z{{|~‚‡ŠŽŽŒŒ‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ˆ†„€}}}}…‰“•——––’ŽŠ‰‰Š’“”“’’ŽŒ‹‰†„‚€~{xuqnkjjlmomkiea```behfec_ZY\^chnquxy{|}~€€‚ƒ…‡‰‰‰ˆ†„‚€~~~€‚„…‡ˆŠ‹ŒŽ‘“•”””““‘‰„€{|…‰’•—šœž ¢¡›”†}}}~€ƒ†‰‹ŽŒ‰†‚{zyxwvutsrqrux|‚~|ywv‡—Ÿž˜“ˆ„‡Š‘”“Œ‰†…‡ŠŒ‘Œˆ…‚€€€€€€€€€€€€€€ƒ†ŠŒŽŠ‡…ƒ„ˆŒ‘’Š‚{vqs|…”›™˜–“Š‚zrkc^ZUSPPRTVY[`ejlnmgb^][ahotxzzyz{|€…ŠŒŽŽ‹‰†„}|||~ƒˆŒŽŽ‹‰‡…ƒ‚€~|zxustuw|†‹•› ¥©­°´´³²®¨¢Ÿž Ÿžš—”’Œ‹Š‡„~zywxyzyyxvusuwy}‚…†ˆ‡†††††††…ƒ{xwvwwxwsplfabdfjoqqpnkgfedddhw†„tc][ZWUSQORW\cjrstsrpsw|‡ŒŠ‰†‚ƒˆ“™Ÿ£¦ª­°³µ·¸º»¸¶³°­©£ž˜’ŒŒŒŽŒ‹Š‰ˆ‚zsleadfilopqrrrsstuvvtsqpoorux{€‚„…†ˆŠ‹‹†|xvwyz{|xtokgeghjlnrx~ƒˆŠˆ†„|xtqonpsux{}~€‚„†‡‰ŠŠ‹‰‡…ƒ~}{zyxz{}~~}|zyyy}‚ˆ‹†~xtpsy„ˆ‹‹‹ŒŒŒŽ’“”•””“‘‹†~{y|~€‚ƒ…‡‰ˆ‡‡‚}yvrpmklnou{‚„‚}xxyz‰“–—–•”““’‘’“•–™œŸ£¦ª®°¯­«¥Ÿš—“І‚}vplkkmpqnjf^WRPMNNNNNNNNOQRUXZ^bgkptvy{|}~€€€‚†Š•š™˜—”‘ŽŒŠŠŠŠ‹‹‹ŒŽŽŽŒ‹‰ˆ‰‹ŒŽŒŠˆ†„…†ˆ‰‹ŽŽŽŽ‹ˆ…‚~„‡ŠŽ‹…xqnnnoookfa\WUY^cgllkkjihhgfeejpw}ƒ‡„~{yuromjjpuzƒ|xtollllllmnoprstvxz}€„ˆ‹’’’““”—› £¥¦¢™–“•šž¡£¤Ÿš”Œˆ†„‚€~}|{zyxwurpkfb`^_cfikmkjhhghiijkloqtvy|ƒ…†…ƒ„†‰•¡¢¤ž—‘Ž‘”–––“ŒŠˆ†…ƒ}zvrrrsvy{||{zyxwusqppprsuvxz}€‚„…†‡‡‰ŠŒ‘‘Œˆ…}zuqmkhfdbccdfgjloruxz{}}}|{{zyx{‚‡ŒŒ‹‰…‚ƒ„…†ˆ‰‰‰ˆˆˆ‡‡‡‡‡ˆˆˆ‰ŠŠ”˜œ—’Œ„}~„ˆ‹Šˆ†„„„ƒƒƒ‚€€~}||~ƒ†‰Š†‚}ytqonljjjklmnkgda]\^`begikmorrrqppoqtvy{~‚„†ˆŒ’•˜šœžŸ¡¡¡¡  ŸŸŸžž›—“‰ˆ†„ƒ‚‚‚€€ztnjfcccdddgiloruy}„‡‰Š‹‹ŒŒŒŒŒŒŒŽŽŽŒ‡ƒ€}{{{{{{zyxwwwxyzzzzzzyyyxvuutssrstux|€‚„††‡ˆ‰Š‹ŒŽŽŽŽ‹‰†ƒ~}|||}~‚ƒ‚‚€~}|{zyywvuutuvwy{}€‚„†ˆˆ‡‡…‚}{yxvwxy{~€~|zxxwvvvtqolihhiknpsvz}€‚‚ƒƒƒƒ‚‚‚‚ƒ„†‡‰‹Ž’”—™œž ¡¢¤¤¥¤ œ—’Ž‹ˆ†ƒ€€€€~|{xvtqoljgecb_]]^_`abcccccdhkotxxwwvuvx{}€ƒ‚‚‚€‚„…†ˆ‰Š‹ŒŒ‹Š‰ˆ‰ŠŠ‹Œ‹ˆ…‚}}}}~€‚ƒƒ„‚€}{zy€‡“™œž ¡¢¢žš–“‘‘’’’‘ŽŒŠ‡…€{vrnmnnoppppqqqqqqqqqstvvwwwwwwwxz{|}~‚‚‚€~|||}€ƒ…††ƒ€}|{{|}}}}|{{|~‡‘“•’Œ‹Š‹‘’’‘‘“–›¡£££ž™“Œ‰ˆ‡†„ƒ‚€}|zywurplifghimrtttrolkiiiijlorvzyyxvttvx{ƒ†‰Œ‘”˜›ž¢¥¤¤£¢¡¡¡¡¢¤¥¢Ÿœ—’ŽŠ‡„~€‚†‰Š‰ˆ†„}|zxvvvuuutssrrsux{‚„†‡ˆ‰Š‹ŒŽŒ‰†‚~zsmf_XY]afjmjgc_[\_behjd^XRKLOSW[]]]\\[\^`bdeeeeeeiou{€„~{xvyˆ–˜”ŒˆˆŠŒŽ’–𠤤£¢¡¡¡¥©¬¯³µ·¸¹¹¹¶³°­ª¨¥£¡Ÿ™–’Œ‰‡„‚€~|ywusqomlkjmoppplcZSOKR[cinqpooooqsvwyzzz{{{|}}||{ywvvvy}ƒ„‚~yvutx|€~}zqha\XXYZ]_bgmpqqolifb_[XX\`it„‰‹‰‡‡ˆ‰Œ”–——————————™šœŸŸŸžœ™–•”“““““““““І‚~{xusprtvz~…‰Ž’–———•””—šž¢§¤Ÿ›“Š…‡‰’˜—”’ˆ„‚}{yyyyyyyyyxxxvtromlpuz…ƒ}wph``_```___^]^`bdgjigeb`_adfillkjhggjmptwwwwvuuz~ƒ‡‹Ž’“”••–––—˜˜™ššŸ¢¤¦¤ ›—“‘‘’”—™œŸ›˜”‘ŽŽŽŽŽŽŽ‹ˆ…ƒ€€€€‚‚„†‰‰‰†xsnikmpruwz}ƒ‚‚ƒƒƒ„…‡†……€{usportvwwtpmjggghgggdb_^^_bfhkmnoooonnmnqsx†ˆŠŠ…€†Ž–™›œ—’ŽŒŽ‘‹†€|zwxyzzzyyxyyz|~ƒ…‡‡ˆ‡„‚~xsrrsw{ƒ†‰‹Ž‘‘‘‘’‘‰…yz{|‚ˆ‹ˆ„yrrtu{‡Š‘’Œ‰„{{{|~‚…ˆŒ’‰ƒ|ttx{‡‹ˆ…{vuwx{~wpg^TQRRUWZ\_acegijklnpsuxz|||}}}|{zyxz~‚‡‹ŽŽŽŒŒŒ‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰‰‰‡„~{x|…‰“•—™š–’Ž‹‡‡Š’”““’’‘ŽŒ‹‰‡„‚}{xuqnkhjlnnnlhda_\_beghgc_\ZY]chmrvwyz|}~‚ƒ…‡‰ŠŠˆ†„‚~‚„†‡‰Š‹ŒŽ‘“”•””“’‰„~}}…‰Œ’”—™›žŸ  ›•ކ‚}~€‚„†ˆ‹ŠŠ‰†‚}{yxwvutsrstvx{|zy}€†—™™™“ˆˆˆŠŽ‘‘‰ˆˆˆŠŒˆ…ƒ„†ˆ‹ŽŽŒ‹ˆ…„…‡ŠŽ’‹†wqvz€‰“—˜˜–•“Œ…~vmgb]XTQQRSUWZ^bglqmie`Z[`elryzzyyxz~‚‡ŒŽŒŠ‡…‚€}{yw|…Š‘ŽŒŠˆ†„ƒ€~|ywtqoty~ƒˆ’—¢¨«¯²µ¸·±«¥ šœŸ ¡Ÿœ™–’ދЉ†ƒ|yvwxzz{zxvtsrvz~‚†‡‡‡††††††……„}{xvwwwvutnieb_cglorspligddddcba_][YWUSQRTU]ekottsrsuv|‚‡ŠŒ‹ˆ…††‡“™ž£§«®±³¶·¸¸¸¸¶³¯«§¢—’ŒŒ‹Š‡ƒyrkgecfilnpqrrsttuvuutsqopqruy|~‚ƒ…†ˆŠŒŒŠˆ…€{yxwy{{yvsnigffhjlpuy…ˆˆˆ†„~{wsoopqsvy{}ƒ„†ˆŠ‹‹Šˆ†„‚€~|zyxz{|}~|{ywuz„‰‰ƒ|umquz€†Š‹‹‹‹‹Ž’”•••”””Š…zxz|~€‚„†ˆ‰‹‰…}ytrpmkijqw}ƒˆ…|xtt{ƒŠ‘˜˜—•”“’’’‘‘‘”—™œŸ¢¦ª®±´¯©¤Ÿ™•’І{upkilnpqqld]WQNNNNNNNNNOOPSVY\^chmqtxz{}~€€€‚„†‹‘•˜›š–“‘ŽŒ‹Š‹‹‹ŒŒŒŽŽŒ‹Š‰‰‰ŠŒŠˆ††…†ˆŠ‹ŒŽŽŒ‹‡„‚‚‚„ˆ‹Œˆ„}wspmnonlie`[ZZZ_dijlkkjihhgfgjmrx‚ƒ„~{xurolmoqv{~}{wspnlllmmnopqrtuwyz~…‰‘’’’’–™œ¡¥¥£ œ—’•—šŸ¤¤¡ž™“Ž‹‰†„‚€~}||{yxwusoje`[^adhkllkjhghhiiijmortwz}€‚………„ƒ‚‚ˆ—ž¦©£œ–ŠŒ’”—˜•’Œˆ‡†…ƒ‚€}yvsoqtvy{||{zyxvtsqppqrsuvx{}€‚……†‡ˆˆŠ‘’’Ž‹‡„}xtpmigecbacdfhjloruxz|||}}|{z{{{~ƒ‡ŠŽ‹ˆ…ƒƒ…‡ˆ‰Š‰‰ˆˆ‡‡‡‡‡‡‡ˆ‰ŠŒŽ‘•™™™™’Š„~€„‰Œ‘ŽŒ‹‰‡†…„ƒƒ‚‚‚€€~}~~ƒ††……|xuromkjjjkllkigd`^^^`begiknprrrqppqrtwy{}ƒ„‡ŠŒ“–˜šœž ¡¡¡¡¡   ŸŸŸœ™–’Œ‰‡…ƒ‚‚‚‚€|xsnhfecccdfhjmosvz~‚…‡‰Š‹ŒŒŒŒŒŒŽ‘Ž‹‡ƒ{{{{{{zyxxwxxxyyyzzzzzyxwvuutssrqrvy|€ƒ…††‡ˆ‰Š‹ŒŽŽŽŽŒ‰…‚||||}}~‚ƒ„ƒ€~}{{zyxwvuuttuwy{}€‚„†ˆ‰‰‡„‚}{yxwvwy|~€~|zxvvvuutrokiggilnqtwz}ƒƒƒ‚‚‚‚‚‚„…†ˆ‰‹Ž’•—šœž ¡£¤¤£¢¡œ—’ŽŠ‡„‚€€€~}{xvtroligeca_^]]_`bbccccefhlpuvwwwvwxx{~‚€‚‚„…†ˆ‰Š‹ŒŒŒ‹Š‰‰‰Š‹Œ‹‰‡„‚}|}}~€€‚ƒ€}z{‚ˆŽ•˜œŸ ¢¡žœ™•‘Ž‘’’’‘Ž‹ˆƒ~ztonmnnoppppppqqqqqrrstvwwwwwwxxyz{{}~‚‚~|z|„‡ˆ…ƒ€}yz{{}~}}|{zy}ƒˆŽ”—”‘Ž‹‰ŠŒŽ’’‘ŽŽ’—œ¡¦©£˜’Љˆ‡…„ƒ€}|zywusplifdfjnqtvsqnljiiijjkosvy{zxvutsw{ƒ‡Š“•˜œŸ¢¤¦¥£¢¡  ¢££££ ›–’‰†ƒ€~€ƒ†ˆŠ‹ˆ†ƒ}{yxwvuutttssrstuy|€‚„†‡ˆ‰Š‹ŒŒ‹‰…}wrke^]\]bfijjfb^^^_cffdc^WQONOSWZ\]\[[]^_abdeeeeeilpv|€€€}zwz~‚Š’–––“‹ŠŠ‹Ž‘“–šž¢££¢¡ ¡£¦©¬°²´·¸¹¸·µ³°­ª¨¥£¡Ÿ›˜•‘ŽŒ‰†„‚€~|ywusqomkklnpruoibYPKPV\empppnmnpqtvyzzzzz{{|}~~|zyvtswz~ƒ‡…}xtquy}…€xof]WXYZ[\_dimqtqnkheb^[XUT_ju€Š‹‰‡……‰”—————————˜˜˜šœžŸ ¡ž›˜–”““““““““’’‘ŽŠ…}ywtrrqswz~‚†Š“•˜˜–••••šž£¤¥¢™‘‹‡ƒˆŽ“•—–‘ˆ„€~|zzyyyyyyyxxwvutqooppu{~vnhd``````__^_``beghhgdbaaadfijkjighijmqtuwvvuvy{~ƒ‡ŠŒ’““”•••–—˜˜™šœž £¥£¡Ÿš–’‘‘‘“•—šœœš˜”ŽŽŒŠ‡„€€‚„†‡‰‹‡ƒxqlllnpsuxz}€ƒƒƒ‚‚‚ƒ„…‡ˆˆƒzuooqruwxurokhggghihfda_\]`cfjmmnooonnnmlmsy€‡‰„€|y€ˆ—ŸŸ›–’Ž‹ŒŽ‘“Š…€{vxyzz{zyyxwwz}‚„†‡‡ˆˆˆ‚}xsootx|€„‡‰ŒŽ‘‘‘‘‘‘‰„~{xx~ƒ‡ŠŒ…~wtpqw}‚ˆŽ‰„€|y{|~€ƒ†‰‰‚zxuu{†ˆŠ…€{xuux{{ywof\WRORUXZ]_acegijlmoqsvxz{}}}|||{zy{|~‚‡ŠŽŽŽŒŒ‹ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠˆ†ƒ€}|}‚†Š”–˜˜–”‘‰‰ŠŠ“““’’’ŽŒŠˆ†„‚}zwtplkkklnomjhd`^_acfiheb^ZX\_diosuwy{}}~€‚ƒ…‡‰Š‰‡†„€~~€ƒ„†‡ˆ‰Š‹Ž’“•”””““’ˆƒzz~‚…‰“•˜šœžŸ¡¢£›”Œ…~|}~€„†‰‹Œˆ…~{zxwvutssrrruy|‚|zyx€ˆ–œž˜’‰„ˆ‹‘“’Œ‰‡…ˆ‹Ž‹ˆ…ƒ€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/roaaar.wav0000644000175000017500000003550213263212010021112 0ustar aeglosaeglosRIFF:;WAVEfmt "V"VdataÃ:&'-38>CIOU[afkqv|€ƒ~{xvsqnligd`][YVTQNKHHJKLMMNOPPQRTUVWWXYZ[]^`beilorux|‚…‰Œ“–™ ¤§ª©§¦¤¡Ÿœš˜–”“‘ŽŒŠ‰‡…ƒ‚‚‚ƒ…††‡ˆ‰Š‹ŒŽ‘’““”•–—•“ŽŒŠˆ†ƒ~|zwurpnljhefghmrw|†ŠŽ“˜¢§¬±¶»¿ÄÉÍÑÌÈÄÀ¼·²­©¤ ›–‘Œˆ„zvqmkiikmoqrtvxz|~€ƒ…‡‰ŠŒŽ’“”••–—˜™š›žŸ ¢£¤¤¦§§¦¥£ ž›˜•“‹ˆ†ƒ€}{xurpmjjnrvz~‚†ŠŽ’–šž¢§«°´¸¼¿ÂÃÅÃÁ¾¼º¸µ²¯¬©§¤¢ š—•’ŽŽ’”–˜šŸ¡£¥§ª¬®°²´·¹»»º¸´®©£—’Œ‡{vpke^XSNIC<=CHNTZ_ekpv{‡’—¢¨®³·¸¸³®¨¢—’ˆƒ}xrmga\WQLF@DLU\dls{‚Š’š¢ª²ºÂÊÑØßçéééáØÐǽ´ª¡—Ž…|tkaWNE=4*&.7?HPYbkt}…–Ÿ¨±¹ÁÊÓÛáåéçæäãáàÞÝÛÚÙÙÙØ×ÕÔÒÑÏÎÍż´«¢š’‰xpg^UME=5,$$.6>GPXajs|…Ž–Ÿ¨°¹ÂÊÒÓÕÔÓÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÐÍËÆ¿·°¨¡š’Šƒ|ung`XPIA:2+'*-0369<>ACFILORUWY[_bejnsy…‹‘—¤ª±·½ÃÉÏÕÛàæìòòêãÛÒÊÁ¸®¥œ“‹‚yqi`WNE<52/28=BFJOTY^chlqv{€„‰Ž’–™™™™™™™™™™™˜˜˜˜˜˜˜˜˜˜˜———–•”’‘ŽŒ‹Š‰‡†…„ƒ‚‚ƒ„†‡‰ŠŒŽ’“”–—˜š›œžŸ  Ÿžœœœ›››šš™™˜———–––“Іƒ|yuqnkgda^ZVSOKMNPX`gov}…Œ”œ¤¬³ºÂÉÑØßçîõïéãÜÕÎÈ»´¬¥ž—Šƒ|unha]ZXY[\^_`abdeghijkmnopqstw{‚†Š‘•˜œ ¤¨«¯³¶º¾ÂÅÅÅÄÀ½º¶²¯«§£Ÿœ˜”‘‰†‚{wvwxyz{|}~€‚ƒ…†‡ˆ‰Š‹ŽŽ‹‰‡…ƒ€~{yvtromjhfca_\\]_ciov|ƒ‰—¤ª±·½ÄÊÑØßåëéáÚÓÌÄ»²©¡˜‡wog^UME=73/1469@CEILPUZ`fkqv|‡Œ’—£¨®³¸¾ÄȽ·±ª¤ž—‘‹…yrlf`ZTMG@>;;<>?ACEGJLNPRTVXY[]`bdfilorux{~„‡Š“–™ £¦©©ª©¦¤¢¡ ›˜–”’ŽŒŠˆ†„‚€~~€ƒ„†‡‰ŠŒŽ‘“”–—™šœ››š—“‹‡ƒ{wsokgc_[VRNIFBBDEHKNPSVXZ]`cehkmpruwyzzxuspmkigdb_\ZWTRPMJHECFJMRW\bglqv{€…Š”šŸ¤©­°³¶µ´³³²±°®­¬¬«ª©©¨§¦¤£¢¢—‘‹…€ysmf`ZTNHB<60*% !"$%'(*+-.0127;?CGLPTY^bfjnsw{ƒ‡Œ’””’‘‹‰‡†„‚€~}{xvtsqonmmmnnnooopppppqqqrrrsstuvwy|~€ƒ…‡ŠŒŽ“•˜šœŸ¢¥§©©§¥¢ ›˜–“‘ŒŠ‡…‚€~|ywtrpmkhfdb_]ZXVSPMKIGEB@>;=BHNT[bipw}ƒŠ—ž¦¬³¹¿ÆÊËÍÉü¶¯©¢›”އztmg`ZSLE=<>ADGJMORUX[^behkmpsvy|‚„†ˆŠŒŽ’•—™›ž ¢£¥§©«®°®­¬©§¥£¡žœ™—•“‘ŽŒŠˆ†ƒ~|{zyyxwwvuttsrqqpoonmllmnppqrstuvwxy{|}~€‚ƒ…‡ŠŽ’–šž£§«¯³·»¿ÃÇËÐÔØÝáåÝÖÎż³«¢™‡~umcZQH@7,"%-6?HQZcks|…–Ÿ§°¸ÁÉÒØÕÒÏËÆÁ¼¶±¬§¢œ—’‰ƒ~ytomkknpsuwz|„†ˆŠ’”–™›ž   Ÿžžžžžœœœ›››ššššš™™™˜˜˜˜˜˜————————–––––•••“‘Ž‹‡„}zvsolieb_[XTPMIGDA@>;852/-,*(%" $,39?ELRY_fmsz€‡”𠤍¦¤¢ žœš˜—•“‘ŒŠˆ†„ƒƒ„‡‰‹‘”–˜šœž¡£¦©«®°°°°­ª§¤¡ž›™–“‹ˆ…‚}zwtqrtuvxz|~€‚„†ˆŠ‹‘“”–˜˜˜—”Œ‰…}yvrnjfb^ZVRNJFCA?=<:976432/,)(&%#"  !$+29@GNV]dltzˆ—ž¦®µ¼À¾»¸´¯«¦¢˜“І‚}yuplgb_\\]_abdfgijkmnpqstvwyz{}‚„†ˆ‰‹ŒŽ’”•—™›ž¡£££¢Ÿ›—“‹†‚~zvrmiea]XTPKGDCCDEEFGGGGHIIJKKLMMMMNPSV[_dinsw|†ŠŽ“˜£§¬°µº»ºº¸·µ´³±¯­«©¨¦¥£¢¡Ÿ›š˜–”’‘ŽŒŠˆ†„‚€~}{ywusrpnqsv{ƒˆŒ”˜¡¦«¯³¸¼ÀÄÈÊÌÍÇÁ»¶±«¥Ÿ™”Žˆƒ}wqlfa[UOPQRUX[^adgjmoruxz}‚…ˆŠŒŒŒ‹‹Š‰‰‰ˆˆˆ‡‡†††………„ƒƒƒƒ„„…†‡‡ˆ‰‰Š‹ŒŒŽ‘‘’“““““““”””””””””””•••••–––——˜™šš›œžŸŸ ¡¢¢£¤¥¦§§¦¤£¡ ž›š™—–”“‘ŽŒŠ‰‡‡‡ˆŠŒŽ’”–—™šœž ¢¤¦§©ª¬«ªª¨¦¤¢Ÿ›™—”’‹‰‡…ƒ‚‚‚…‰‘•™¢¦©­±µº¾ÂÆÊÏÓ×ÜÙÓÎÇÀ¹²«£œ•އ€yrkd\UNHB>:=@DGKNRVY]aeimqtw{‚†‰ŠŠŠˆ‡†…„ƒ€~}{zyxwvutsrqpnmmlkjihgfecba_^^]\[[]^`cgjmorvy|‚…ˆŠ“–™œž      ¡¢¢¢¢¢¢¢££¤¤¤¤¤¤¤¤¤¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦§¨¨¨¨©ª¬­®®¯°°²³µµ¶·¹º»¼¼½¾½»¹¶³±­ª¦£ š—“Ї„}zxvvvvwwwxxyyz{{{|||}}~~~‚„‡Š“–™œŸ¢¥¨«®±µ¸¼¿ÁÁÁ¾ºµ°«¦¡œ–’ˆƒ~ytpkfb\WTRQQQQQQPPOOOOOOOOONNMNPQU\bgmrx}‚ˆ“˜ž£©¯µ»ÀÆËËÈÅ¿¹³­¨¢›•Š„~xrlga[UQMILORTWZ^adgjloqtwz~„‡ŠŠŠŠ‰ˆ‡‡‡†……„ƒƒ‚€€€~~~~~„‡‰Œ‘”–™œŸ¢¥§©¬®±´·º¹¸··¶µ´²±¯®¬«©¨¦¥¤¢¡  žœ™—•“‘ŽŒŠ‡…‚}{yvtqomkifedcccbbbaaaaa``____^]]]]^acehjlnprtvxz|ƒ…†ˆ‹‹‹‹Š‰ˆ‡…„ƒ€~}|{zxwvtssstvxz{}ƒ…‡‰‹Ž‘“•˜™›œœœ›››š™˜˜˜———–––•””““’’‘ŽŒŠ‰ˆ‡†…„ƒ‚€~}|{zywvtrpnmkihfca_][YXVTRQQQTY]bfkosw|…‰Ž’—›Ÿ¤¨¬±´·º½¿ÂÅÈÊÍÐÓÖÙÛÜÞáãæéìíííçàØÑÊû³¬¤œ•އwph`YRJKLMQUX\`cgjnruy}€„ˆŒ’•˜š˜•“‘Šˆ†„‚€}{ywurpnmklnoqsuxz}€‚…‡ŠŒŽ“•˜šŸ¡¡ žœ›™˜–•“’ŽŒŠ‰‡†„ƒ|zwurpmkhfb_\ZXUROMKIFC@?>=;:7520/-,*)'&%#" !&*.37<@DHLPUY]bfjnsw|†‹•šŸ¤©®³¸½ÃÈÎÒÖÚÝàÜÓ˹°§ž–…}tld[SJA8/&$'*.4:AHOU\bhnu{‚ˆŽ•›¢¨®³µ¶¶·¸¹¹º»¼¾¿ÀÁÁÁÂÃÅÆÇÉÅ¿¹±©¡™‘‰yqh`XPH@7/(!%/9BLV`is|†™£­·ÂÌÖÞççæåàÜ×ÑÌÆÁ»¶±¬¦¡œ–‘Œ‡}xtttssssssrrrrrrrrqqqqqqstvx{}‚„‡‰‹Ž’•—™œž¡¤¥¦¥Ÿ™“މƒ~ysnhb]WRMGA;5/+-04882/02479>>>>>>DINTY^bglqv{€„‰Ž”™Ÿ£¨¬«ª©¤Ÿ›–’މ…|xtokgb^ZUQNLMOPQSTUUWXZ[\^_abcdfgiiijjjjjjkkkkkllllllmmmllkjihfedcb`^\\[ZXWUTSQPPSVZ^cglpty}‚†Š“˜¢¦«¯²µ³®¨¢œ•Š„~xrmgaZTNHB<63469=ADHLPTY]bfjnrvz~‚†ŠŽ’”–˜›Ÿ¡¢¤¦¨ª¬®°³µ·¸º¹·¶²®ª¦¢Ÿ›—“Œˆ„€|xtpmifcdfgijlmoprstvwyz|~‚„…‡ˆ‰‹ŒŽ‘’“”–—™š›œžŸ  ž›š˜–•“’‹‰ˆ†„ƒ€~|{zyxxwwvuttsrrqqpponnnmlllllllllllllllllllllllloqtx}…‰‘•šž£§¬°³·»ÀÅÈËÌÈÿºµ±­¨£ž™•Œ‡ƒ~zuqmiiijmoruxz}€‚…ˆ‹Ž‘“–˜› £¢žš–’Ž‹‡ƒ{wsolhd`\YTPLLKLNOPRSUVXY[\^_abdfgijlmprtwy{~€‚…‡ŠŒ‘“–˜›ŸŸžœ™•‘ŽŠ†‚~zvrnjfb^ZWSOLHGGGHIIIIJJKKKKLMMNOOOOPRSUVWZ\^`bcegiklnprtuwy{{{{||}}}}}}~~~€€€€€€‚ƒ„†‡ˆŠ‹ŒŽ‘’“•–˜™šœžžœš˜—•“‘ŽŒ‹‰‡…„‚€~|zxvtsqponmlkjigfecba_]\[[ZYY^cinsx}‚‡‹•šŸ¤ª¯´¹¾ÄÉÉÉÈÄÀ¼¸µ±®ª¦£Ÿ›˜”‘ŽŠ‡ƒ€}{{{{{{{{{{{|||||||||||}~ƒ…ˆŠŒŽ’”–˜šœž ¢¤¦¨ª««©§¤¢ ž›™–”’Ž‹‰‡…‚€}{yxvutsrqpnmlkjihhgfedba`_______`abbbccccccddeeeffghjkmnpqstuwxz{}~€‚„…‡ˆŠŒŽ‘’”–˜šœž ¢£¤¦§©«­­«ª§£ œ˜•’Ž‹‡„€|yurolhea^_bdfhjlmoqsuvxz}‚„†ˆ‰‹ŒŽŽ‘’’“”••–———˜™™—–”“’‘ŽŒ‹Š‰‡†…ƒ‚€~}|||||||||||}}}}}}}}}}}~~~€‚„…‡ˆŠŒŽ’”–˜™›ž ¢¤£¢¡ ž›š˜—•“’Œ‹‰‡†„ƒ‚‚ƒ„„…†‡‡ˆ‰‹‹ŒŽ‘’‘‘‘ŒŠ‰‡†„ƒ‚€~|{yxvusrqrrrsttuvvwxyyyz{{|}}~~~~}|{zyxvutsqpoonmlkihhgimptw{‚†Š‘”˜œ ¤¨«¯²¶·¶´±«¦¡œ—’ˆƒ~ytnid^YTOKGGKORVZ^bfjnqtx|€ƒ‡‹Ž’–˜™š™˜—•”““’‘ދЉ‰ˆ‡†††††††††††††‡‡‡‡‡‡‡‡‡‡‡†„ƒ€~{xuspnkhfc_\ZXVSPMJGJMPRTVX[]`cegjloqsuxz}|{ywtqmjgc_\YWTQNJFCA>;869ELRY`gov}„‹’™ §®¶½¿ÀÀ½º¶²®ª¦¢žš–’Ž‹‡ƒ€|xtpmpsuxz}ƒ†ˆ‹“•˜šŸ¢¤¤¤£¢ Ÿœš˜–•“‘ŽŒ‹‰‡…ƒ~~€ƒ…ˆŠ‹‘“•—™›Ÿ¢¤¦§©©ª©©¨§¦¦¥¤£¢¡ŸŸžœœ›š˜˜—–“‘ŽŒŠˆ…ƒ€}{xvsqomjhebbcdgkotx|…‰Ž’–›Ÿ£¨¬±µ¹¾ÃÃÀ½º¸¶³°­ª§¤¡Ÿœ™–“‘Ž‹ˆ†…„…††‡ˆ‰‰‰ŠŠ‹ŒŽŽ‘‘‘‘’’’’’’’’““““““““””””””•••••–––——————˜˜˜˜˜™™™˜˜˜—————–––•••””“““’’’‘Œ‰†ƒ€~{xvspmkheb_]ZWTQTWZ]`dgjmorux|„‡Š“•–—————————––––––––––––––’މ…|xtplhc^ZUQMIFB>:8778:<>ACEGILNPRTWY[]_adfhikmoprsuwy{|~ƒ„†ˆŠŒŒŒŒ‹Š‰‰ˆ‡†††……„ƒ‚‚€~}}}|||{{zzyxxxwwwvuuttuvxz}€ƒ…ˆ‹Ž‘”˜›ž¡¤§ª­°³¶¹·²­¨£ž™”Š…{vqmhc]XSNJHEFGGIJLLMNNOPQQRSTTUVVWXYYZ[[[[\\]^____`abcccdeefghjkllmnopqrrtuvwxyzz{{{{{||||||}}}}}~~~~~~~~~}|{{{zzzyxxwwvvutttsssuwy{}„†ˆŠŒŽ’”–˜›Ÿ¢ Ÿ™”І|xsnie`[VQLHD?:6:>CGKPTX\`dimquy}‚†ŠŽ’”–––•”““’‘‘ŽŽŽŒŒ‹ŠŠ‰ˆ‰‹ŒŽ‘“”–˜›Ÿ¡£¤¦¨ª¬®¯±²´³³²±°°°°¯¯®®®®­¬¬¬¬««ª¨¥¡™•’ŽŠ†‚~zvsokgc_[WTSQRSSUVWXYZZ[\^_`aacdefgffffffeedddccccccbbaaabcehkorvy|ƒ†Š“—šž¡¤¨«¯¯­¬«ª©¨§¥¤¢¡Ÿœ›™˜—•”’‘ŽŽŽŒ‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡‰ŒŽ‘“–™›ž¡¤¦©¬¯²µ·¹¼¾ÁÁÁÁ¼¸³®ª¦¡™”Œˆ„€{wsnjeaaa``_______________^]]_`bdgikmprtvy|~€‚…‡ŠŒ‘“•’Ї„~{xvspmjgda]ZXUUUVY\_behknqtwz}€ƒ†‰Œ’•–’‰„€|wrnie`\WRMHC>:52224:?DJOTY^chmrw|†Œ‘–›¡£ ž›˜•’ŒŠ‡„~{yvspnkhedbccccccddeeeeeefffffggghijkmnoqrsuvxyz{|~‚ƒ‚~{xuqnjgc`\XUQNKHD@=:79>CHMRX]cinsx}ƒˆŽ“™ž¤ª®°²°¯­­¬«ª¨§¥¤¢¡ žœ›š™—–•””’‘ŽŒ‹ŠŠˆ‡††…„ƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„……………………………„„ƒ‚€~|zywvtrponljhgedb``abcdfgijklmopqrtuwxyz{}~€€‚ƒ„…††ˆ‰Š‹ŒŽŽ‘“”•—˜šœŸ ¢¥§¨ª«¬®°²´¶·¸¸¸·´±®«¨¥¢Ÿœ™–“Ї„~{yxxyz|}~‚ƒ„…†‡ˆ‰‹ŒŽŽŽŒŒ‹Š‰‰ˆ‡†…„ƒƒ‚€€€€€€€‚‚‚ƒƒƒƒƒ‚‚‚~|{ywvtsqponlkihfdca`^][YVUSRQONLKIHFDB@?>=;:::;<=>>>>>>>>>>>?@AAAACDEGHJKMNPQSTUWXZ[]^`abcdefghijkklmmnpqqrsttuvvwyzz{||}~€‚ƒƒ„……†‡ˆˆ‰‰ˆˆ‡†††…„„ƒƒ‚‚€€€~~}}|{zxwutrqonmkjhgedba_^]^_afkpty~‚‡Œ”™ž£¨­±¶º¿ÅÈÇÅÄÂÁÁÁÁ¿½»»º¹¸¶µ´´²±¯¯®­¬ª©¨¨¦¥££¢¡ žœ›š™—–•–––———˜˜™™š›››œœœžžžžžž›š™˜—•”’‘ŽŒ‹Š‰‡†„ƒ‚~|zywvtsqpnmkihfeca``aadgknruy|€„ˆ‹’–™ ¤¨«¯±³´µ¶·¸º»»¼¾¿ÁÁÁÂÃÄÆÇÉÉÉÉÇÆÅÅÅÄÃÁÀ¿¾¼»º¹¸··¶µ³²²²²³´´´´´´´´´´´´´´´µ¶¶µ´´³²±°®­¬¬«ªª¨§¥¥¤£¡ Ÿžš˜•’ŒŠ‡„~{xuromjgd`]\[\]_`acdfgijlmnpqrsuvxy{}€ƒ†‰ŒŽ‘”—™ £¦©¬¯²µ¸ººº¸³®©¤ž™”‹†‚|wrnid^YUPNOQSVX[]_behknpsuwz}€‚……†…ƒ€~|zwurqomjheca_]ZXVTTSRQQQQPPOOOONMMMMLLKLLMNPQSTUWXZ[]^`acdeghjkmoruxz}„‡Š“–˜›ž¡¤§«®°°°­ª¦¢™•‘‰…}yuqmiea]XZ]aeimptx|€„ˆŒ“—›Ÿ¤§«®±´¶·¹º»½¿ÁÂÄÅÇÈÊËÌÎÏÑÒÔÕÓÒÑÎËÈÇÅÄÂÁÀ¿¾»¹·¶´³±°®¬ª§¤¡ž›˜•’‹ˆ…‚|yvtqnlmnopqrstuvwyz|}~€‚ƒ„„„ƒ}{ywusqoljhfdb`^[YWVWXZ\^`bdfhjlnprtvxz|~‚„„„…††‡‡‡ˆˆ‰‰‰Š‹‹ŒŒŒŒ‹Š‰‡…ƒ€~}{yxvtsqpnlkihfedcbaa_^\\[ZZYXWWUTRRQRTWY[]`begjlnpsuxz|„†ˆŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’”•—™šœŸ¡£¥§¨©«¬®¯±³µ¶¶¶´²°®«©§¥¢Ÿš˜–”‘‹‰†„}zxusqomjhfc`]ZXVTRONLKLMNNOPPQRSSTUVVWXXYZ[[^adhloswz~…‰‘•˜œ ¤¨«®¯°­ª§£ œ™–”‘Ž‹‡„~{xurolkkkkkjjjjjjjjjjjiiiiiijklmoqrtvwy{}ƒ…‡‰ŠŒŽ‘‘‘‘ŽŽŒ‹‹Š‰‰‰ˆ‡‡†……„„………†††‡‡‡ˆˆ‰‰‰‰‰‰ŠŠŠ‹‹Š‰‡†ƒ}{yvtrqoljhfda_\[YZZ[[[[[[\\]]]]]]]^____`cfilorux{}€ƒ†‰Œ’•˜›ž¡¢¤¤¤¤£¢¢¢¢¡¡       Ÿž›™–”‘Œ‰†ƒ|yvtqolifb_\ZYZ[[\]^^_`aabbbcdeefgghiklnoqrstvxy{|~‚„…‡‰ŠŒŽ‘’”•–—˜™›œžŸ ¡¢¤¥¦¦¥¤¤£¢¡ ž›š™˜—•”“’‘ŽŒŠ‰†„~|ywtromjhec`]ZXUROPQQQQRSSTUUVWXXYZZ[\]]^____^^]]]]]]]]]]]]]]]]]^^_`abcdefghijklmnoopqrssrqponnmlkjihgfeddcba_^^^_______`aaaabbbcccddefgilosvz~…ˆ‹’•™œ ¤§«®²³³²±°°®­«ª©§§¦¥£¢ Ÿœ›™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜™™™™™™™™™™™˜˜˜—–•”’‘ŽŒ‹Š‰ˆ†…„ƒ‚€~~}}}||||||{{zzzyyyzzz}‚„†ˆŠŒ‘“•—šœŸ¡£¥¨ª¬«ªª§¥£¢ Ÿ›™—–”’ŒŠˆ‡††ˆ‰‹ŒŽ‘’”•—˜š›ž ¢£¥¦¥¤£¢ Ÿ›š˜—•”’‘ŽŒ‹‰ˆ‡†‡ˆ‰Š‹Ž‘“”•–—˜™š›œœœ›š™˜—–•”“’’‘ŽŒ‹‹ŒŽ‘’““•–—˜™š›œžŸ ¡¢¢¢¢¡  Ÿžœœ››š™˜˜———–•””“’ŽŒ‹‰ˆ‡…„ƒ‚~}{zywwwwxxxyyzz{|||}}}~~~~~~~}}}|||{{{zzzyyyyyxxxwwwwwvvvvvvuuuttttttttuvwxz{{|}~€‚ƒ…††‡ˆ‰Š‰ˆ‡…„‚~}{zxwutrqonmkjiiklnopqrtuwxyz|}~€ƒ„†‡ˆˆ‰‰‰‰‰‰ŠŠŠ‹‹‹ŒŒŒŒŒŽŽŽŽŽ‘‘‘ŽŒŠ‰‡…„‚}{zxwusrponnoqtvy{~ƒ†ˆ‹’•—𠢤¥¤£ œ˜•’Œˆ„~{wtqnjgda^\\\]^`abcdfgijklmnopqstuuuvvvwwwxxyyyzzz{{{|||||{zyxwvusrqponmlkkjhgfeffghjkmnpqrstvwyz|}€ƒ„…………††‡‡‡ˆˆˆˆˆˆ‰‰‰ŠŠŠŠŠŠŠŠ‰‰‰ˆˆ‡‡‡†……„„„ƒƒ‚‚‚€€~|zxusqomjhfdb_]ZXVTQOPQQSVXZ\^`cefhjmoprtvxz{}~€‚ƒƒ„…††‡ˆ‰Š‹ŒŒŽ‹ˆ…‚{xuroligc_\YVSOLJIIMQTX\_cfjnquy|€ƒ‡‹Ž’–™šš™™™˜˜˜—————–––•••”””””•–—˜™š›œžŸ¡¡¢£¤¦§¨¨ª««¨¦¢žš—“‹‡ƒ€|xtpmiea]XVTTVX[]_acehjlnprtvxz{~€€€€~}|zywvutsrqponmkjhhghhhhhhiiiiiiiijjjjjkkkkkkjjjiiiiihhhhhhggfffggghijlmopqrstuwxz{|~€ƒ‚~}{zxwutrqponlkihfeddeghjkmnpqstuwxz{}~€ƒ„„„„ƒ€~}|{zyyxvutsrrqppprtvxz|~€‚ƒ…‡‰Œ‘“•—™›™–“‹‡ƒ{wsplid`[WSOKGECADGJNRUY\`cfjnqtwz~…ˆ‹ŠŠ‰‡…ƒ}{ywusqpnljhfdb`^^]\\[ZXWVUTTSRRQPOONMNNOPRUVXY[]`acegikmoqsuvwyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽŽŒŠˆ…‚~|yvspmjgda_\YURNMKMPRUX[^`cfiknqsvx{~ƒ†ˆˆ‰‰‰‰‰‰ˆˆˆˆˆˆ‡‡‡‡‡‡‡‡†††…ƒ~|{zxwutrqonlkjhgefffghhijkklmnnoppqrsstuvvwwwxyzzz{||}}}~€€‚‚‚€€~}}|{{{zyxxwvvvuuuwxz{}~€ƒ„†‡‰Š‹Œ‘’‘ŽŒŠˆ†…ƒ‚€~}{ywusrponmlnopqrstuwxy{|}~€‚ƒ„†‡‰‹’•—™›œž¡£¥§©¬®°²´¶··µ³±¯¬ª¨¦¤¡Ÿžœš˜•“‘‹‰ˆ‡††…„ƒƒ‚€€~~}|{{zyxxwvvvuuutttttsssrrrqqqpppppqqqrrrssssstttuuuvvwwwwwwxxxxxxxxyyyyyyzzzzz{|~€ƒ…†ˆ‰‹Ž’“•—™›œŸŸ žš—”‘Іƒ|yvrolhea^ZVVXY\`cgjmpsvz}„‡Š”˜› žœ›™˜—–”“‘Ž‹Šˆ‡…„ƒ‚‚‚ƒƒƒ„„„„„„……†††‡‡‡‡‡‡†…ƒ‚€~}|{zxwutsrqponmnopqrstvwxy{|~€‚ƒ…†‡ˆŠ‹ŒŽ‘’’“””–—˜˜™š››œŸ    ¡¢¢¢¢¢£¤¤¤¤¥¦¦¦¦¦¦¦¥£¡Ÿš˜–”’‹‰‡…‚€~|ywtsrqqpooonmllkjjihggffeeefiloqtvy{~„‡‰ŒŽ‘“–˜›žž˜“‘‘‘ŽŒ‹‰‡†„‚‰” žœœ›š™˜—–•”“’‘ŽŽŒŒŽŽ‘‘‘’’““”•••–——˜˜™™š››œžžŸ ¡¡¢££¤¥¦¦¦¦¥£¡Ÿ›˜–”’ŒŠˆ†„‚€~|zxxxyyyz{{|}}~~€‚‚ƒƒƒ„„„„„ƒƒƒ‚‚‚‚‚€€€€€€€€‚‚‚‚‚ƒƒƒƒƒƒ„„„„„………††††††‡‡‡‡‡ˆˆˆ‰‰‰Š‹‹ŒŒŽŽŽ‘‘’“•–˜™šœŸ ¢£¥¦§©ª¬¯±²´³²²±°°®­«ª¨§§¦¥£¢¡ Ÿžœ›š˜–”’Ž‹‰‡…ƒ€~|ywurpnljgfeefffffgggggghhhhhiiijjjlnprtvxz}ƒ…†‰‹’•—–––”’Ž‹‰‡…ƒ‚€~|zywusrqprsuvxyz|~ƒ„†‡‰ŠŒŽ‘’‘ŽŒ‹Šˆ‡…„‚€~}|zxvusrqpqsvx{~„‡Š’•—𠣦©¬®¬«©¥¡žš—“‰†ƒ|xtqmjgda`begikmoqsuwy{}€‚„†ˆŠ‘‘‘‘‘‘‘‘ŽŒ‹Š‰‡†…„ƒ‚€~}{{zyxvutsrqponmlkjihgfecba`_`cegijlnpqstwy{}~€‚„†‡‰ŠŠ‹‹‹ŒŽŽŽ‘‘’’’“““”••––———˜˜™ššš›œžŸ Ÿœš˜–•”’Ž‹Šˆ†„ƒ~|{ywwwwwwwwwwwwwwwwwwwwwwwvuutsrrqpoonmmlkjjihggfeeghjkmnopqstuwxy{|}€‚ƒ„†††‡‡ˆ‰ŠŠ‹ŒŽŽ‘‘ŽŒŠ‰‡†„ƒ€}|zywvtsrsstvxy{}€ƒ…‡ˆŠ‹’“•––•“’ŽŒŠ‰‡†…„‚€~}|zyyyzzz{{{||}}}~~~€€€€€~}|zyxwutsqponmlkjhgfffghjlnoprtvxz{}ƒ„†ˆŠ‹ŒŠˆ†…„‚€~}{zxvtrqonlkihhhijjklmmmnoopppqrsstuuvxz|~ƒ…‡‰‹‘“•—™›Ÿ¡¤£¢¢Ÿš˜•“‘ŒŠ‡…‚}zxusqomnoprstuvwyz{|}€‚ƒ„…††††…„ƒƒ‚€€~~}|{{zyxxwwwxz{{|}~€‚ƒ…†‡ˆ‰Š‹ŒŒŒ‹ŠŠ‰ˆ‡†…„ƒƒ‚€~}||}}~€‚‚ƒ„††‡ˆˆ‰Š‹‹ŒŽŒŒ‹Š‰ˆ‡††„ƒ‚‚€~}||{z{{{|||}~~€€€‚ƒƒ„„………†††‡‡‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹ŒŒŒŽŽŽ‘‘‘’’’““””•”“‘ŽŒŠˆ…ƒ}{ywusqoljhfdefghijlmnopqrrstuwxyyzyyyxvusqonmljhgedb`^][ZZY[^adgjmprux{~„‡Š’•˜š››š™˜˜—––•”““’‘ŽŽŒ‹‹Š‰‰‡†…„ƒ‚€~}|{zyxwwvvvvvwwwwwwxxxxxyyyyyyyyyzzzzzzzzzzzzzzzzzzzzzz{{||}~~€€€‚ƒƒ„………†‡‡ˆˆ‡‡‡‡‡‡†††……„„„ƒƒƒ‚‚‚€~}{zyxwvusrpponlkjihfefhikmnoqrtuwyz|~€‚ƒ…‡‰‰‰ˆ‡‡†††…„ƒƒƒ‚‚‚€€~~}}}}}}}}}}}}}}}}}}}}}}}|||{{{zyxxxwwwvvvuuuttssrrrrqqqpppppooonnnmmllllllkkkjjiiiiiihhhgggggfffhjlnprtvxz}ƒ…‡Š‹‘””””“’ŽŒŠ‰ˆ‡…„‚€~}|{z{{||}~~€€€‚‚ƒ„………†‡‡‡‡‡†…„„ƒ‚‚‚€€~}}}|{{zzz{|}}~€€‚‚ƒ„……†‡‡ˆ‰Š‹ŠŠ‰‰ˆ‡†…„ƒƒ‚€~}}|{zzyxyyz{{|}~~€‚ƒƒ„…††‡ˆ‰ŠŠ‹‹‹ŒŽŽŽ‘‘‘’’’““’’’‘ŽŽŒŒŒ‹ŠŠ‰‰ŠŠŠ‹ŒŒŽ‘’’“”•–—˜˜™›œœœ›š™˜˜—–””“’‘ŽŽŒŠŠ‰ˆˆ‡†……„„ƒƒ‚€~}}||{{zyyyyyyxxwwwvvvuuuttsssrrrrrrqqqqqppppppppoooooopqqrtuuvwxyz{{|}~€‚ƒƒƒ‚€€~~~}||{zyyyxxwvuuuutttssssssrrrqqqqqppppppqrssstttuvvwwxxyzzz{||}}~~~€€€‚‚‚ƒƒƒ„„„……††††††‡‡‡ˆˆˆˆˆ‰‰‰ŠŠŠŠŠ‰‰‰ˆˆ‡†††…„ƒƒƒ‚‚€€€~~~~~~~~~~~~~~~~~~~~~~~~€‚ƒ„…†‡‡‰Š‹ŒŽ‘’“”–•••”“’‘ŽŒ‹Š‰ˆ‡†…„‚~~~~€€‚‚‚‚‚‚ƒƒ„„„„„„ƒƒƒ‚‚€€€~~~}}||{{{{{{{{{{{{{{{{{{{{{{{|||}}}~~~~~€€€‚‚‚ƒƒƒ„„„…†‡‡ˆ‰‰Š‹‹‹ŒŽŽŽ‹Šˆ‡†„ƒ€~|{zxwutsrstuuvwwxyzz{||}~€‚ƒ„„„…†‡‡‡ˆˆˆ‰ŠŠ‹‹ŒŒŽŽŽŽŒŒ‹Š‰‰ˆ‡‡†…„„ƒ‚€€€‚‚‚ƒ„„……††‡ˆˆˆ‰ŠŠ‹‹ŠŠ‰ˆˆ‡†…„ƒ‚€~}|{{zyyyyz{}~€‚ƒ„†‡‰ŠŒŽ‘’”••••”””“’’‘‘ŽŽŽŒŒ‹Š‰‰ˆ‡†…„ƒ‚€€~}|{zyxwxxxxxxyyyyyyyyzzzzzzzz{{{{{{{{|||||||||}}}}}}}}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}|||{{{zzyyxwwwvuuttsssrrqrrrstvwyz{|}~‚„…†‡ˆ‰ŠŒŒŒŒ‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡†††………„„„ƒ‚€€€~~}}}|||{{{{{||||||}}}~~~~~€€€€€~~~}}}|{zzzyyyxwwvvvvvwwxyzz{||}~€‚‚ƒ„„…†††††††††††††††††††††††………„„„ƒ‚‚€€€~~}}}||{{z{{{{{{{{{{{|||||||||||}}}~~~€€€‚‚‚ƒƒ„„„………„ƒƒ‚‚‚€€~~~}}}|{zzzzzzzzz{{{{{||||||}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||}}}}}}}}}}}~~~~~~~~~~~€€€€€€‚‚‚‚‚‚ƒƒƒ‚‚‚‚‚€€€€€€€€‚‚‚‚‚‚ƒƒƒ„„ƒƒƒ‚‚‚€€~~~}}~€ƒ††‡‡‡‡†……LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/sirr.wav0000644000175000017500000000230613263212010020620 0ustar aeglosaeglosRIFF¾WAVEfmt "V"VdataH„t‰Ÿ¦ž—Šzkqxzslmsz}~~|{€—¯¯“vorusqonlpy€{v†—¥¥¤œ‡rotztmioty{~”«¾¤Šxwvutspmlt|zv|‹™¢¨­“yiovwuspmks{~|{zzŒ¤¼¨“‚yqpuzvpjmptyys~Ÿ«¶¸›~ptwvtsnjhpx}}}}}}•¯Â°Œ}mlrytolmosz€|wŒ—¥²°”wmnpsvxsnlnpt{‚€}{|}„µ»²¨”}flquuurnjmrv{‚}xy…—­Ä´¢qlqvusqnkkqw|‚~yt~ˆ”¥·· ˆzrjouxtpmljov||wv|‚’ªÁ»°¤uhknqtwtplkjlrx|‚~yvy}…œ³¼¸´ †lkjlqvvsoligmsx}}zxww‹ ²¸¾µ›tmflrvusqmjlpty~€~ˆŒ…}zwvy|‰‘‡zwux{€‰’‡~zwuwz‹—•‰}xusvy€Ÿ|wtsvz‘¢ ztsrw{ƒ”¥¤Žysrrx}…•¦¤zsrrx~†“¡Ÿzsqpuz”§ª–‚yvsvx{~†•„ywuvxz‹–‘ƒuttux{„ˆ‹Œ…|ssrty}‰š«ˆssrsvy}…–€tsrtwz…’ ‘ƒwvtvx{~„‰Ž„xqqquy~ƒˆŽ˜¡ž‹yrqquy}~„œ”ooprux{|~‹ µ£Œvustuwxyz‡–¢Ž{oqsrrrux|ž¦™Œƒ}wtssw{€Š”•‰xpnmoty}‚Œ™¦‘}nprsssvy|…•› ™†topqsuwy{‚žŸœ™‹|ppprvy{||Œª‘…}uv{€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/gate.wav0000644000175000017500000003430613263212010020566 0ustar aeglosaeglosRIFF¾8WAVEfmt "V"Vdataš8lnprtvxz|~€€}|zxvusqpqsuvxz{}€€}|zxwusqpqstvwy{|~€€€}|zxwutrqrtuwxz|}€€€~}{zxvusrstvwyz|~€€~}|{yxwvvxyz{|}€€€~}|{yxwvvxyz{}~€‚‚€€~|{zxwvvxyz{}~€‚‚€~}|{yxwwxz{|}~€‚‚€€€~}||{{||}~€€€€€€~~}||||}~~€€€€€€~~}||||}~~€€€€€€~~}}||}}~€€‚‚‚€€€€€€€€€€€€€€€€€~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚€€€~}||{{||}}~€€€€~|{yxvusrsuwy{}ƒ…‡‡†……„ƒ‚€€€€€€€€€€€~}}||{{{}~€‚„…†ˆˆ†…ƒ‚€€}|zyyyyyyxxxxxxxyzz{||}~~~|{yxwutrqooqrtvwy{|~€…ŠŽ’–šž£§«ª¢™‡€wnf]TQW]cjpv|‚ˆŽ‘ˆ„€|wsnjfcegikmoqsuwz}€„ˆŒ“—›Ÿ¡™•‘‰…~zwwwwwwwwwwwx|…ˆ‹’•™›•Š„€zuojd`cehjmpruxz}€‚„‡‰‹’“މ„€{vqlgb^chmqv{€„‰Ž’‘ŽŒ‹‰ˆ†…ƒ€~|zxvtrpnkoswz~…ˆŒ“‘Ž‹‰†ƒ|ywutsqponlkjilptw{‚†Š‘Ž‹ˆ„{xuqnpruxz}€„†‰‰ˆ‡††…„ƒ‚€}{ywtrpmkiknrux{„ˆ‹‹Š‰ˆˆ‡†…„„ƒ‚‚€€€€€~}}|{zzyxwwx{}ƒ…ˆŠŒŠ‡„~{xuroortvy{~€‚„‡ˆˆˆˆˆ‰‰‰‰‰‰ˆ†„‚€~|zxvssuvwyz{}~€€€€€~}}|{{zzzzzyyyyyyyyyyyyyyyyy{}€‚„‡‰‹Œ‰†„|yvsrtuwxz{}~€‚‚‚‚‚‚‚‚‚‚‚‚‚€€€~~}|{zyxwvutsrrtvx{}€‚„†‡†…„ƒ‚€€~~~~€€€€€‚ƒƒ„…†‡ˆ‰ŠŠ‰ˆ†…„ƒ€€~‚‡Œ‘–› ¥ª®²®ª¦£Ÿ›—“Œˆ…ƒ€|ywtqolfa[VQKF@;518?FLSZahnu{qh^UKB8/%,8DQ]iv™–’‹‡„€}zvrux{~€ƒ†‰Œ’‹ƒ|tld\TLDFOW_gpx€‡”–™œŸ¢¥§ª­°¬¦Ÿ™“†€{tnpuz~‚‡Œ‘•šŸŸžœš˜—•“’Ž‹ˆ…‚|yurolgc^YUPKFB=8=HT_ju€Š• «©‘†{odXMA54;AHNU[bhovz|~€‚„†‰‹‹ˆ†ƒ|zwuvzƒˆŒ‘–šŸ¤¥£¡žœ™—”’‰‚|ung`YRLEEQ\hs‰• ¬·»³ª¢š‘‰€yphbbbbbbbbbbbcdfghjklnoqsy„‰•›¡¦¬®£™Ž„zpf[QF@HPX`hpx€†Ž•–—˜™š›œŸ Ÿ™“‡€{uoic^diotz„‰Ž”˜˜˜———–––••”‹‡ƒ€{wsojfdb`^\ZXVTQP[fq|†‘œ§²½Ç»°¤™‚wl`UJMQUX\`dgkorvz~€„ˆŒ“—š™—–”“‘ދІ‚€|yuqnjfchnsy„Š•›¡ž›˜”‘ŽŠ‡„€~ysnhc]WRLGAJVbmyƒ›¦²½º³­¦Ÿ˜’‹„xusqomkjhfdbdfilnqtwy|ƒˆŽ“™ž¤©¯´º³¨œ‘…{odXLABIOV]cjpw~ƒ‡ˆŠŒ’”•—”Žˆƒ~xrmga\[^adgiloruw{~€„‡ŠŽ‘”˜›š•Š…€|wrmhedcba`_^]\[`kv€‹–¡¬·ÂÍÍù¯¥›‘‡~tjeffghhijkklnrvz}€„ˆŒ“•”“‘ŽŒŠ‰†|vqkf`ZUONU\bipw~ƒŠ‘”‘Їƒ€}zvsokgc_[WSOKGHT`lxƒ›§³¿Æ¿¸²«¤—‰ƒ~|ywtrpmkifeefgghhijjkloqtwy|~€ƒ…‡†„ƒ€}|zywsokhd`\XUQNV^emu|ƒŠ’š œ˜”Œˆ„€}yuutsrqqponmmnopqrstuvwy{~€‚…ˆ‹“–”“’ދЉˆ’—¢§­²¸½Â¸¬¡–Š€ui^SGJNRUY]aehlpqrsstuvvwxxz}€ƒ…‡‰ŒŽŽŒ‰‡„‚€~{xvy}…ŠŽ’—›Ÿ¤¢žš—“Œˆ…~zuqlgc^ZUPLS]hs~ˆ’¨³¾½¹´°¬§£žš•‘Šƒ|umf^WOG@AFKOTY^chmruvxy{|~€ƒ}xsojea\WRSVY]`dgknruvtsqonlkihfdb`^\ZXVTRPT]foyŠ“œ¥®°«¦¡œ—‘Œ‡‚~zwtqnkheb_\\_begjmpsvy}‚ˆŽ”š¡§­³¹¸®¤™…{qg\RNSY^diotz„‡„‚€}{xvsqnmprtwy{~€„…„‚€~}{zxy}…ŠŽ“—œ¡¥§ ™’‹„~wpib]]]]^^^^___akt~†™¢¬µ¿Å¿¹³¬¦ š“‡€}{yvtromkimrv{ƒ‡Œ•˜˜—––•”““’‘‰{tme^WPHBGLRW\aglqv{zyxwvutsrqokgc^ZVRMIEAJS\eox€‰“œ¥¤¢ Ÿ›š˜–”“І‚{wrnjfimptx{‚†‰“š¡§®´»ÂÈÏÖÌÁµ©’†{ocXXZ]_bdgilnqtx{~„‡‹Ž‘•‘Œ‡‚~ysnid__acegilnprtw{‚†ŠŽ’–™›–‹†|wrlgeeeddcccbbbgpy€‰’𣬵½½¹´¯ª¥ ›–‘Œ‰†ƒ€|yvsqnnpsuwz|~€‚„‡‹’–𡥍¬©Ÿ–„{ri`VMJNRVZ^bfjnrtsrqpponmlkjiihggfeddcdhlptx|‚†ŠŽ“˜œ¡¥ª¯³¸½½¸²¬¦ š•‰ƒ€~}|{zxwvuw}ƒŠ‘—ž¥«²¹»±¨ž•‹‚yof\W[_cgkosw{€€€€€€}|{yxwutsqponmlkjigfgmsy„‹‘—£¨¡›•‰ƒ}wqkfffggghhhiijqx…Œ“™ §®´±®¬©¦£ š—”Œˆ„€|xtplhjmoruwz}„‰•›¡§­³¹¾Äº®£˜wlaUJNRW[_dhmqvzywutrpomkihfdb`_][YWVTW[_cgkosw{‚…‰‘”˜œŸ£§¢œ•ˆ‚}vpicdhkorvz}€ƒ‡Ž–¥­µ½ÅÍÕÝÕɽ±¥™vj^[]^_`bcdfghlqv|€…Š”šŸž›˜”‘Їƒ€~yupkfa]XSNIKRX^djpw}‚ˆ‰†„}zxurpnlkjigfedbafoy‚‹•ž¨²»ÅÆÁ»µ¯©£—‘‹‡…‚€~{xvsqnmmnoopqqrssv{€…Š”šŸ¤©© —ކ~ulc[RNRVZ^beimquwvutsrqponmmmnoppqrssttttttttttttv}‚‰–œ£©¯¶¹´¯©¤Ÿ™”Š„€~{xuroljgdcjry€‡Ž–¤¬±®¬©§¤¢Ÿš˜•“’ŽŒŠˆ‡…ƒ}zxurpmjhfhknpsvx{~€€~}{zxwutsx}†‹•šŸ¤¨¢›•Žˆ‚|voiccddeeffgghhou|ˆŽ•›¡¨®­¬«ª©¨§¦¥¤£žš•‘ˆ„€|wsrrrrrrrrrrrx…Œ“𡍝¶½¶­¤œ“Š‚zqi`adgjmpsvy|~|ywusqnljhiknprtvx{}}yvrokhd`]Y^els{ˆ–¥¢›•Žˆ|uohabehknqtwz}€…Œ“š §®µ¼ÂÉÈý¸²­§¢œ—’І‚€|xuqnjlry„Š–£©ª§¤¢Ÿœš—”‘Š‚|ung`XQJCBGLQV[_dinsvwxyzz{|}~~zvsokgd`\YX\_cgjnruy|€‚„†‡‰‹‹ˆ…‚€}zwtsuwyz|~€ƒ„‡Œ‘–› ¥ª®³¸¸­£˜ƒyncYNHMRW\afkpuz}{zxwusrpnmlmoprsuvwyz{zyxwvutsqpqv{€…Е𠥍¢œ–‰ƒ~wqkeeddccbbaa``how…”œ£«±°¯®¬«ª¨§¦¥£–‰ƒ}wpjd^^_``abccdefjnrvz‚†ŠŽ“ŽŒŠˆ…ƒ€~||||}}}}~~~~|yvspmjgda^^_``abccdeekqw}‚ˆŽ”𠦤¡ž›˜•“Ї„|yuroliffffffggggggnv~„Œ”œ¤¬´¼·®¥œ“Šyph__cgkosw{‚†…‚€~{xurolilpuy~†Š“˜–‘Œ‡‚~ytnidflrx}‚ˆŽ”šŸ—Šƒ~wqjd][\]^`abcdefinsx|€…Š”˜››œœžžŸŸœ—‘‹…€{uoicaceghjlmoqsw~ƒŠ‘˜Ÿ¥¬³º¹°§ž•Œƒ{ri`\^adgiloqtwy{|~€ƒ„†ˆ†€{tnhb[UOIFJNRUY]aeimpruwy{}ƒ…†„‚€~|zxwusqomkigeca__fnu|‚‰˜Ÿ¦ª¦¡˜“Š…}yyyyyyxxxxxxy{}~€‚„…‡ˆ…‚€}zwtqnkimptw{…‰Œ‘“•–˜™›ž ¡žš–“‹ˆ„~zxwusqomkigfmu|‚Š‘™ ¨¯·´±¯¬ª§¥¢ ›”އ{tngaZTUVWXY[\]^_`bdfhikmoqsttsrqponmllkjjjjjjjjjjjklmopqstvwxwtromkhfda_cjpv|‡Ž”š ž™”‹†}xtoortwz|€ƒ…ˆ†ƒ€}yvrokhegmrx~‚ˆ“˜ž›•Žˆ|voib\]chnsy~ƒˆŽ““މ…€|xsojeegikmoqsuxzzxwvtsrpomlnty~ƒˆŽ“˜ž£¢œ–‰ƒ~wqkebbcddeffghhkoty}…Š“˜šš™™˜˜˜——––“Žˆƒ~xsmhb]ZZ[[[\\]]^^ahov}ƒ‰—ž¥§ š“Œ†€yrleacegikmnprtutrqonlkihgfiknqsvy{~€€}yuplhd_[WU]emu}„Œ”œ¤©£–‰ƒ~wqkeddcba`_^]\]dlt{‚Š’™¡©¯­ª¨¥£¡žœ™—”Œˆƒ€|xtpkhhijklmnopqruy}€ƒ‡‹Ž’–™—”‘Œ‰†„|{zxwutrqonmmnopqrstuvwvutsrqponmlsz‰˜ ¨¯·¿»·²®©¥ œ—“ŽŒŒ‹ŠŠ‰‰ˆ‡‡„€~{wtqmjfcgmrx~‚ˆŽ“™ž™–’Œˆ…{zxwvtsrqonmlllkkjjjiiihggfeddcbaadimrw|€…‰Ž“”“’‘ŽŒ‹Š‰ŠŒŽ‘“•—™›š“†€{tnha[\agmrx~‚ˆ“––––———˜˜˜˜™›Ÿ ¢¤¦§©«¨ ™’‹ƒ}vog`^`bdgiknprtw{~…ˆŒ“—›œœ››šš™˜˜——”Š„€{vpkfa]]]]\\\[[[[^fnv~…Ž–ž¦®²®ª¦¡™•‘Œˆ…ƒ€~|zxvtrpnlkigeca`^_ir{„— ª³¼Âº²ª¢š’Š‚|tnoqrtvwyz|}~{xvspmjgeb`flqw}‡Œ’˜›”†€yrkd]VPX`hpx€‡—ž¥ž˜‘‹„xrke_`abcdefghijnsx}€…ŠŽ“˜ž ¡£¥¦¨ª«­¯¨¡›”އ{unhijkmnoprstu|‡Ž”›¡¨®µ»·±¬¦¡œ–‘Œ†~{xtqnjgd`]^acehjlnqsuvvwwxxyyzzzzzyyxxwwvvvtromkigeb`^`cfhknqtwz}|zxvtrpnljhjnruy}€ƒ‡‹ŽŠ‡„|yvspqux|‚†‰‘”’Œ‡|wqkf`[Z[]_acefhjlosx|€„ˆ‘•š™•Œˆƒ€|wsnmmnnoooppqqqpomlkjigfehntz€†Œ’™Ÿ¥§¤¡š—”‘ŽŠ‡‡‰Œ’”—šœŸ¢ ™‘‰{skd\TQSVY\_adgjmqw}ƒ‰•œ¢¨®±­¨¤ œ—“‹†‚€}yvsolieb````aaaabbbenw€ˆ‘𣭶¿Ãº°§”‹yof_chlptx|€ƒ‡Š…}ytpkgc^\dmu}…•ž¦®´­¦Ÿ˜‘Šƒ}voiou{€†Œ’—£¨ ™‘Š‚|tme]W]ciou{€‡“˜”‹‡ƒ€{wsokpv{€…Š•› ¦Ÿ˜‘Šƒ~wpib\_behknqtwz}€ƒ…ˆŠŒ‘“•–—˜™š›œžŸŸš”‰ƒ~xsmgaabcddefghiiqyŠ’›¤¬µ½ÆÂ»´­§ ™’‹…|{zywvutrqponnmllkkjiinu|‚‰—ž¥¬³¯¨¡š“‹„~wpighhijkklmnnooppqqrrrssssssrrrqqqqqqqqrrrsssstttuuvvvwwwy}€‚†‰“—š˜“ˆ‚~xsmhb`abcdfghijkntz€…‹‘—£©¬ª¨¦¤¢ žœš™•Š…€{vqkfa^^^^___````cipv|ˆŽ”š¡¢š’Šƒ|tme]VRW]bglqv|€…‡„€}yvrnkgcaehkorux|„…†ˆ‰Š‹Ž‘’”–˜šœŸ¡£¥§§Ÿ—ˆ€zrjb[UVXY[\]_`bcfmt|‚‰˜Ÿ¦­²«¤œ•†xpicdefgijklmnonmlkihgfedcipv|‚ˆŽ•›¡§ ˜‘‰‚|tme^W^fnu}ƒ‹“š¢ª¢›”†€yrkd]aeimquz~…‰‰ˆ‡‡†…„„ƒ‚‚„ˆ‹Ž‘”—›ž¡¤ž–ކ€xpiaYQRTVXY[]_abdhmrv{€ƒˆŒ‘–•“‘‹‰‡…ƒ{xtqnjgc`\[[[[[[[[[[[ahov}ƒŠ‘˜Ÿ§¤–ˆ{tmf``cfjmpswz}€€}{xvsqnkifjqx~„‹’™Ÿ¦­«£œ”…wphaafkpuzƒˆ’’‰„€|xsojffjnrvz~…‰Œ†}xrmhc]XX]bglpuzƒˆ‰†‚€}zvspmihiklnoprstvvtrpnmkigedelsz€†”›¡¨«©¦£ š—”‘Ž‹ˆ„~{wspligjmpsux{~€ƒ†”š¡§®´»ÁÈÊ»³«£›“‹ƒ|vtrpnlkigecbbccddeefggiov|‚ˆŽ•›¢¨¬¢˜Ž…|rh^UKDKRY`gnu|‚‰Š…}xtojea]^`bdegijlnpsvy|„‡ŠŽ‘”—›ž¡¥¨¬¯²µ®¦Ÿ˜‰{sldeffghhijjkkt|ƒŒ”œ¥­µ¾Æ¾´«¢˜†}tkacfilorux{~€~zwsolhd`]Y\`dimquy~…‚€|xtqmifb^dlt|ƒŒ”œ¤¬´¯¨ ˜‰zskcbcefghijklmrw}‚ˆ“™Ÿ¤ªª§¥£ žœ™—•’މ„€{wrmhc^\\\\\[[[[[[`irz‚‹“œ¥®¶µ­¦Ÿ—ˆzskijkklmnoppqpnligec`^\Z]dkszˆ—Ÿ¦¦ž—ˆ€zskd\[agmsy„Š–—‘‹…€ztnic][_cgkosw{‚„„„„ƒƒƒ‚‚‚‚ƒˆ‘–šŸ¤¨­²±©¡™‘‰zrjb]^`acdfgijlnrw{ƒ‡‹”˜›››››››››››™”Š„€{vqlfcccccccccccdgjmqtwz}€‚„„„ƒƒ‚‚€€€~}|{zyxwvusrponlkihgknrvz}€„‡‹”™¢§¬±µº¿Ã»´¬¤•ކxponmlkihgfedfiknpsuxz}‚†ŠŽ’–šž¢¦ª –‹€wlaWLB7=DKRY`gnu|‚€~zwtqnkhebdfhjmoqsvxzzyyxxwwvvuuy„Š•› ¦¬²¬¤œ•…~vog_^_abcdefghiqz‚‹”¦¯¸ÁÊÆ¾¶®¦ž–ކwtssrqpponmmlllllkkkkkkou{‡Ž”š¡§­ª£›“Œ„}vnf^`gmt{ˆŽ•œ£¡š“‹„~wohaZXZ\^`bdfhjlouz€„Š•šŸ¥§§§¦¦¥¥¥¤¤¤ š”އ|voic``abbcddeffkt}…˜¡ª´½ÆÇ½´ª –Œ‚yoeacfhknpsvx{{yvsqnkhfc`aiqy€‡—Ÿ¦®±¨ ˜‡€wog^[bipw~„Š‘˜Ÿ£œ•އ€zsle^Z^bfjnrvz~„ƒ‚‚€€~}||€…Š”™ž£¨­°¨ —‡€wog_XYZ\]_`acdegow†•¥­´»·²®©¥ œ˜“Іƒ€|xtqmieaaaaaaaaaaabkt~†™¢«µ¾È¾´ª –Œ‚yoe[]`cfiloruwzxvspnkifda_djpv|‡“™Ÿš”މƒ~xrlf`djotzƒ‰Ž“™–‘ˆ„€{wrnilpuy}€…‰‘–•”“’ދЉˆˆ‡††……„„ƒƒ€~{ywuspnlnqsvy|„‡Š‰‡…ƒ‚€}{ywtqnjgc`]YVSU\bhntz€…‹‘‘‰…{wsokjjjjjkkkkkknsx}€…Š”™ ¡¢£¤¥¥¦§¨©¦Ÿ˜’‹„~wqjc`abcddefghimv~…•¦®¶¾¾´ª —ƒzpf\XZ]_bdgilnqrqpnmlkjigfgjnruy}€ƒ‡ŠŠ„~xqke^XQKIR[dmu~†˜ ¥Ÿ™’Œ†€{uoiefgijklnoprtx}†Š”˜¢¥¤¢ Ÿ›š˜–•’ˆƒztoje`\\]^^__`aabdlt|„Œ”¥­µ»±¦œ‘‡~si^TKPV[aflqw|€…‚€~{xuroliglpuzƒ‡Œ‘–𕋆}xsnicjqw~„Š‘—ž¥«¤•ކ€xpiaZ\^`begilnpruxz}€‚„‡Š‘’”•—˜š›œžŸš“Œ…yrkd]WVWXYZ[\]^^_gpx€‰’›£¬µ¾º³¬¥ž—‰‚|usrqqpoonmllkjihhgfeddchpx€ˆ˜ ¨°¸³¨ž“ˆ~ti^TIJRY`gnu|ƒŠ‘Œ‡ƒzvqlhcdinrw|€„ˆ’‹…€{uojd_Y[clt|ƒ‹“œ¤¬«¤œ”Œ…~vog_]_acehjlnprtuvwxy{|}~…Š”˜¢¦«°¯§Ÿ—‡€xph`\^_acdfhikmpuzƒˆ’—œ¡¤¡Ÿ›˜–”’Ї„~{xtqnkiijkllmnoopqsuwy|~€ƒ…†„ƒ€~}{yxvuvxyz|}~€€‚€~|zxusqolkkkllmmnnooqx~„‹’™ §®µº¶²®ª¦¢žš–’ŽŠ†ƒ€|xtqmiffgghiijkklmu}„Œ”¥­µ½Äº¯¥›†}rh^TWZ]`cgjmpsvusqpnljigedgjmqtx{~„‡ƒ{vqlhc^ZU\dls{‚Š’š¢ª¤ž—‰‚}vohaabccdeefghhnsy„Š–œ¢§©©ªª««¬¬­­­¨¡›”‡€zsmfeeffgghhhiipy‰’›¤­µ¾Çù°§”‹ypfeghjlnpqsuwvtromkigeb`bglpuy~†Šˆ‚~ysnic^Y[ckt|ƒ‹“›£«ª£œ•†€yqjc`abcdfghijknrw{€„ˆ‘–šž ¡¢£¥¦§©ª§ ™’‹„~wpib____```aaaaenv‡˜ ©²º½µ®§ ˜‘Šƒ|uppoonnmllkkjigfecb`_^\^gpx€‰’𣬴¸®¤š†}si`VPV\bhntz€…‹ŽŠ…€}xtojfa_chmqv{€ƒˆ‹‡‚zvqmidbjqy€‡—Ÿ¦®³«£›“‹ƒ|tld^_abdeghjlmosvz~€„ˆŒ“—˜šœžŸ¡£¤¦¨©¢š“Œ„~wohaZZ[[\\]]^^__hpy€ˆ‘™¡ª²º¶±¬¨£žš•‹‡ƒ€}yvrnkgc`___________gpz‚‹•ž§±ºÃ½³ª¡˜†~ulccdfgijkmnpqpomljihfecbgmsy€…‹‘˜ž¤Ÿ–Ž…}uld[RJMSZagnu|ˆŽŠ†‚{wsokghlosvz}€ƒ‡Š‰†ƒ€~{xurolnsx}†‹•šŸ˜’ˆ‚~ysnihkmpsuxz}€ƒ…†ˆŠ‹Ž‘“’Œ‰†ƒ€~{xusrrqpoonmmllnoprstvwxz{}~€€ƒ„†‡‰‡|vpjd_YSMLSY`fmsz€†Œ‰…‚€}yvspnnooppqrrsstvxz}€‚„†ˆ‹Ž‘”—𠣦©©£œ•ˆ|ungcdeefghijklow€ˆ‘™¢«³¼Åʺ²ª¢š’Š‚{ttsrqpoonmlkkkkkkkkkkklsz€†“š §®²¨’ˆ~si^TI@GMT[ahou|‡„|yvspmjhkmpsvy|„†ƒ€}yvrokhd`gnu{ˆŽ•œ£©£œ•އ€ztmf_`abcdefghijqx…‹’™ §®µ³°­ª§¤¡ž›˜•‹‡‚~ytpkfaabbcddeefggow€ˆ‘™¢«³¼Å¿µ«¡—ƒzpg]]_behknpsvyxvusqomkjhfjpw}‚ˆ•›¡¨¤œ”Œ„|tld\TV^elt{‚‰˜Ÿ—Š„~xqkd^]adgjmqtwz}~}|{zyyxwvux}‡Œ‘—œ¡§¬ª¢š’‹ƒ|tld\YZ[\]^_`abcgnv}ƒŠ’™ §¯±®«¨¥¢Ÿœ™–“‹‡‚{vrniecccccccccccgqz‚Œ•ž¨±ºÄƽ³ª —„{riceghjlmoqstusqpnlkigedemu}ƒ‹“›£«³¶¬¡—ƒzpe[QKRX_elry…‹‹†‚~zuqlhcafkpuz€„‰Ž“–‰‚|unhaZSOW`hqy€‰‘𢩢›”†€yrkd^`begjlnqsuwwvvuuttssrrx„‹‘—ž¤«±·¯§Ÿ—‡€xph`abcdefghijjpu{€…‹–›¡¦§§§§§§§§§§§¢›•ˆ‚}vpiccddeffghhiipw…”œ£«²¹¶±­¨£ž™”Š…‚€~|ywtromjjjjjjjjjjjjnsx}†‹•šŸ˜“ˆƒzupkknpsuxz|€ƒ‚€~{yvsqnlijlnprtvxz|~€ƒ„†‡‰ŠŒŽ‘’“”•–—˜–‘‰„€|xsojiijkklmmnoosz€‡Ž•œ£ª±¸¸°©¢š“Œ„~wollmmnnoppqqqqppoonmmllnrw{€„ˆ’–›š’Š‚zrjbZRIGOV]dlsz€ˆ’މ…~yuqmhfghiklmnoqrrrqpponnmmlmt{€‡Ž”›¡¨¯²ª£œ•އ€zslgghhhiijjkkmsx~ƒ‰”š ¦ª©§¥¤¢ Ÿ›š˜“ŽŠ…}xtojgggggghhhhhiqx€†Ž•œ¤«³¹°§ž•Œƒ{ri`X[_bfilpswz}{ywuspnljhfjnrvz~…‰’‹„~xqjd]VOIQZbkt}„–ž§¡›•Žˆ‚|vpicdeghjkmnoqrstuvwxyz{|}€…‰Ž’—› ¤¨­§ ™‘Šƒ|umf_^^__``aabbbhov}ƒŠ‘˜Ÿ¦­¬ª§¤¢Ÿœ™—”‘ˆ„€|wrnid`_____``````gox€‰’𣬵¾º±¨Ÿ•Œƒzqh_]`cfiknqtwyywtrpmkifdadjqw}‚ˆŽ•›¡Ÿ–ކ~vne]ULMU^fnw‡—  š”Žˆ|vpjdbehknpsvy|€}{ywusqomkmsz€‡Ž”›¢©°°¨ ˜ˆ€yph`\]_`abdefgikosw{~…‰‘”–˜šœž ¢£¥§¦Ÿ˜‘Šƒ}voh`\\]]]^^__``cks{‚Š’š¢ª²¸´°¬©¥¡žš–’І‚~zvrmiebbbbbbbbbbbdmw€‰’›¥®·ÁǾ¶­¤œ“Š‚zqjjjkkllmmnnnnmlkjjihgffnu}„Œ“›£ª²¹¯¤š…{qg\RHMSY^diouz€…‚€}zwtqnkhfjotx}…Š”˜‘‰zriaYQIAHQYbjr{‚‹“œ˜“މ„€zupkfgjlnqsuwz|~|yvspnkheb_djqw~„Š‘—ž¤¡›–Š„€ztniijkmnoqrsuvxz{}€ƒ…†ˆ‰‹ŒŽ’“”–—”Œ‡ƒ€{wsnjijklnopqrstwz}€‚…‰Œ’•”‘‰†‚|xuqppqqrrrssttuuuuuuuuuuuvwxyz|}~€€€~|ywtrpmkijnrw{ƒ‡Œ”•‘‰…‚{wspmmmmmmmmmmmosx}€…Š“˜Ÿžœ›š™˜—–•“‹ˆ„€}yvrnkkkkkkkkkkkmu}„Œ”›£«³»¾¶¯§Ÿ—ˆ€yqllmnoopqrrssrrqponnmlklrw}‚ˆŽ“™Ÿ¥¨¡™’Šƒ|unf_Y^dinsx}†‹‹‡ƒ€|xtplhegjmoruwz}€€~}|{zyxwv{ƒˆŒ‘–›Ÿ¤¨¢›•Žˆ{unhbbcdefghijkkrx„‹‘˜ž¤«±°®¬ª¨§¥£¡Ÿž˜“Žˆƒytoidddeeffgghhhqz‚‹”ž§°¹ÂËż³ª¢™‡wnmmnnooppqqqqonmlkihgfeksz‰‘™ ¨°¸²© —Ž…|sjaXY^bgkpuy~‚†…‚|xuqnjgdfjotx}€…ŠŽ“‘ˆ„€{wrmidflrx~ƒ‰•›¡Ÿ™’Œ…€yslf_^`bdgikmoqtvy|„‡Š“•—™›Ÿ ¢¤¦¨¥ž–ˆ{tle^[\\]^^_`aabgox€‰’𣬵¾À¹³­§ š”އˆ„€|wrn~|zxvtrpnljhggfedcbba`cmw€‰“§±ºÄǼ²§’ˆ~ti_Y\_bfilosvy{xvsqoljgebcks{‚‹“›£«³·¬¢—‚yndYOHOU\cjpw~ƒŠŠ†‚~zvqmhdagmrx~‚ˆ“™œ•…wog`XPKS\dmu~…Ž–Ÿ¦Ÿ™’Œ…€yslf`cfilorux{~€~{xvsqnkifdkrz€‡–¥¬´¬¤•†xphabcdefhijklmpsvy|„‡Š“–™›ž¡¤§©¬¦ ™’‹„xqjccccddddeeeekry…Œ’™ §­­¬ª©§¦¥£¢ Ÿš•‰„ztoidcccccddddddks{‚Š’›£«³»ºµ°«¦¡œ—’ˆ…‚€}zwurolihhhhhhhhhhhmt{‚‰—ž¥­´²«¤ž—‰‚|unlmnopqqrstuutrqponmkjikqv{€„‰”™žž˜’Œ‡|vqkedhlpsw{~…‰‰†ƒ€~{xtqnkknqux{„‡‹ŒŠˆ†„‚€}{yy|~€ƒ†‰Œ’••‘‰…}yuqmkmoqrtvxz{}„‡‰Œ‘”—š›˜•“Šˆ…‚€~}{yxvusrponnnnooooppprv{€„‰Ž“˜¢¤—‰ƒ}voib]adgknruy|€€}{ywvtrpoqtvx{}ƒ…‡„€~zwspmifchmrx}†‹–š–’‰…€}xtpllmnnopqqrssvy{~€‚„‡‰ŒŽ‘‘‘’’’‹ˆ„~zwsolkkkkkkkkkkkqw}‚ˆŽ”›¡§­©£—’Œ†|vpppqqqrrrssssrqponmlkkjou{‡”š §­§ž•Œƒ{qh_VMOTY_djouz€„ƒ€|yvspmjgimquy}€„ˆŒ†€yrkd]VOHKS[cks{‚В𙔉„€{upkfegikmoqsuxzywusqomkigehntz€†Œ’˜ž¥¤—Šƒ}wpic`abcdefghijlosvy|€‚…ˆŒŽ‘’“”–—˜š›™”‰„€{upkfccccccdddddgnu|‚‰–¤«®©¤Ÿš•Œ‡‚~zyxwvutsrqponmlkjihfedfmu}„Œ“›£«³¶­¤›’‰€xof]V[_cgkotx|€‚€}zwtrolifekqw~ƒ‰–œ¢¦•Œƒ{rjaXOHPX`gow~…•›•Š…€{upje`dgkoswz~…ˆ„€}ytplhd`\cks{‰‘˜ ¨°¨ ˜‘‰{skc\]_acegikmoqrstuvwxyz{|€…Š”™ž£¨­²«¤œ”Œ„}ume]]^_`abcdeefkqv|€†‹‘–œ¢£££££¤¤¤¤¤¤Ÿ™’Œ…€ysle_^^___```aaahpy€‰’𣫴¼»¶±¬§¢˜“މ…‚|xuqnkgdbbbbbbbbbbbhqzƒŒ•Ÿ¨±»Ä¹±¨ —ކ~vmjjjjjkkkkkkkjjihggfeedhqyŠ’›¤¬µ½¼²¨“‰€ukaWSW[_bfjmquyzwusqomkigegnu|‚‰—ž¥¬¬¢—ƒyoeZPFBJQX_fmu|‚‰Œˆ„~zvrokgfkpuzƒˆŒ‘–—ކvnf]UMDAJS\fox€‰’› š•Š„€zuojfiloqtwz}€‚~ytoje`[VQOX`iqzŠ’›£©£–Šƒ~xqkfgikmnprtuwxwvtsrpomlkjpv}‚ˆŽ”𡧬¥Ÿ˜’‹„xqkefghijklmnoqsuwy{}€‚„‡‰Œ’•˜›ž¡¤¦¡›•‰ƒ~xrlffgghiijkkllptx}€„ˆŒ”˜˜˜———–––•••‘‰„€}yuplhhhiijjkklllquzƒˆ’—œ¡Ÿœ™–“‰†ƒ€~|zywutrqonnnnnmmmmmmpty}…Š“˜œ›–’ŽŠ†‚~zvrqrstuvwwxyzzxwvusrqpnmnrux{~„‡ŠŠˆ…ƒ€|zwuuvxz|~€‚„†…ƒ€|zwuspnmoprsuvwyz|}~€€€‚ƒ„…†‡‡ˆ‰‰Š‹ŒŒŒ‰†ƒ€~{xtqnlllllllllllmrv{ƒˆŒ‘•šœ™–”‘ŽŒ‰†„€~}|{zxwvutsqpnmkjhgffmsy„Š‘—£¦ š”‰ƒ~xsmilorux{~€‚…‡ƒ€~zwtpmjfdimqvz~‚†‹’ŽŠ†ƒ€|xtqmjnrw{‚†‹“–‘Œˆƒ{vqlhdfiloqtwz|€€€€€€€€€€€€‚…ˆ‹Ž‘“–™œž™“މƒytnicefgijklnopqvz~‚†‹“˜œ  Ÿžžœ››š™™”Š…€|xsniddeefgghiijjqx…Œ”›¢©°·´¯«¦¡œ—’ˆƒ}zxvsqoljiiiiiiiiiiiow†Ž–ž¦®¶¾º²ª¢š’Š‚{skiklnoprstvwvutrqonlkihlszˆ–¤«²¯§ž–…}umd\[_dhlpuy}……‚|yvspmjginsx~‚‡Œ’—œ›•ˆ‚}wpjd]]chnsy~‚ˆ““І~ytpkgfjmqtx{…‰‰†ƒ€~{xuqnklqv{€…Š”™žŸ™“ˆ‚}wqkebdgikmortvxz{|}}~€€‚„‡Š“—𠣤—Šƒ~wqkd`abcdefghijlqv|€…Š•šŸ£¢¡ Ÿœ›š™—–‘Œ‡ƒzvqlgcccccccccccemu}„Œ”œ¤¬´»µ°ª¥Ÿš”‰ƒ~|zxwusrpnllkjihgfedcclu~†˜¡ª³¼Ä¼³«£š’‰yqhjkmnoqrsuvwvtrpnmkigedkt|ƒ‹”œ¤¬µ½µ«¢˜…}si`VY^bfkotx|€„‚|yvroliebgnu{ˆŽ•œ£©£š’‰€xog^ULPW^elsz€‡Ž•“މ„€{vqlgbdjoty~‚ˆ’—”†€zslf_XRU]emu~…•¥£œ–‰‚|vohbbehlorvy}€‚|yurolhebemt|‚Š‘™ ¨¯®¦Ÿ—ˆ€yqjb`bdfhjlnprtuuvvwxxyyzz}‚‡’—¢¨­³²ª¢™‘‰zrjb^_abdefhijlnrvz~…‰‘•˜›Ÿ¡£¥¨ª¬®­¥–އ€xqia]^^_`abbcdehov|‚‰—ž¥¬°¯­¬«©¨§¥¤¢ š”Žˆ|vpjd````aaaabbbdmv†˜ ©²»Á¼·²­¨£ž™”Іƒ€}zvsolheeeeeedddddenw€‰’œ¥®¸ÁÉÁ¹±©¡™‘Š‚{ssrqqponnmlkkjjihhgffeenw€ˆ’›¤­¶¿É¿¶­£š‘ˆvmdefgijklnopqponmlkjihgfmv~†Ž–Ÿ§°¸Á¹¯¥›’ˆukbXY\_bfiloruxwutrqomljhgmt|‚‰‘˜ §¯¶°¦œ’ˆukaXNOTY^chmrw|€€~{yvsqnkifjpw}ƒ‰–œ¢©¤›’ˆ€wnd[RIJQW^dkrx…‹‹ˆ„€~zvsokhjoty~‚‡Œ‘–›˜ˆ€zrjbZSKLS[bjqy€‡–—’‰„€|wrmiilptx|€ƒ‡‹Žˆ‚}wrlf`ZUU\ckry€‡Ž•ž™“Žˆƒ~ytnigjmpsvy|„„€~zwsolhdaagnu{‡Ž”›¡£ž˜’Œ†€{uoifhkmoqsuxz|}|zyxvutrqopv{€…‹–›¡¦©¢œ–‰‚}vpiefhjkmoprtuwwxyyzz{||}І~ytmirrormagic-3.0.0/sounds/snd_classic/fuel.wav0000644000175000017500000000527013263212010020577 0ustar aeglosaeglosRIFF° WAVEfmt "V"Vdata: ~yxtoje_YRMHDDEEEEDCAAAADGKMNOOOQSVZ^c_ZVMDAJR]jwz{{{{||}~€€€‚„‹’˜¡ž™”“’“—›žžž™“‰…‚~}|{zy{|}€‚‚‚‚€~ƒˆŽ“™žžžžžœ›™˜–•“‘ŽŒŠ‡…ƒ‚€€€‚ƒ‡ŠŽŽŽŒ‡‚€~}ƒˆŒ’˜žŸžž›˜–ž¥®¹ÄÊÌÍËÊÉÉÉÊËÍÑÖÜâèíííìëéãÙÏȼ¾ÀÀ½»µ­¤œ“‹‚ypje`\XWWWZ\\WQKD<@HQ[fpppooonlkjijrz‡Œ‰†„€€€‚ƒ†‰ŽŽŠ…‚}{zyzz{|}|xtoiccdfiloopqqqlga[USW[_cghijlmnopqrsuxz|~€ƒ‚€}yvuuvy|‚…‰ŽŒŠŒ‘—ž¦®¯°¯¯®«¥Ÿ™”Ž“™ž¢¦¦£Ÿ›—“‹‡ƒ|ywtrpnllllmoqsuvwxxxxwvusqomjhlosx}~}}|{zyyxxxz~…ˆ‹ŽŽŽŽŒˆ…‚€‚„†††…„ƒ‚‚‚ƒ„………†‡‡Š”𡧝¶½ÄËÓÛäíöüùöôñîíííííìëéèåâÝ×ÒÌÆÀ¹²¬¨¤¡Ÿ™•‘‹„~ysnjfdcbcdb]WQKDDEEHJJHFCA>:62/,,5>GOW\`dhmqw}ƒˆ“–š¡¥ª¬¬¬ª§¤¢¡ŸŸžœš˜–”އyqmmmnpqlga[UNF=6.'*.3454.(#!$(07<@DGIKNQUY]bglqvzzzywuw{~ƒ‡Œ‹‹Š‰ˆ†ƒ€}zx|…‰ŒŽŽŽ‘”˜™˜–“Žˆ„~~}}}}}}|{zxvv|ƒŠ’šœ››š™—•“‘’—›Ÿ¢£Ÿš–“’“•—™œŸ¡¢¤¤¤¤¦¨ª­°³·º¾ÁÄÅÅÅÃÂÂÅÈËÐÔÕÕÕÓÒÐÊľ·°¯°°°°¯©£ž™“‘Šˆƒzvrokhfda`_^\YWUSQPNMLKKKLMMQW\aglpsvy}|||||~‚‡‹Ž’ŽŒ‹ŒŒŒ‹Š‡…‚‚‚ƒ‡ŠŒŒŒ‰†ƒ„…†‰‰†‚~}}}~~}|{zxvsqonsx}‚†Š‹’”–™šœž ¡¢¢£¤£¢¡Ÿœ™—–•”“’’‘ŽŒŒ‹‹‹Ž’•—•‘‰…‚‚‚‚‚‚ƒƒƒƒƒƒ€~{wsnhbaaahpwy{{ywxz{‚†‡ˆˆˆˆ…€|wrouz€†Šˆ…~zuromqx…‹‘‘’“–™Ÿ§¯µ¼ÂÅÇÊÍÐÓÖÙÛÜÝÝÝÜÛÙØÖÕÓÒÑÏÎÌÉÆÃ¿»¹¸¸¸¸¶±¬§¢—’Œ‡‚~|{vpic]XTQNMMNPQPONJGEEEGJMORTVXYYYXVUZ`fmsxyz{|}{zxxwz‚Š–›š—””“•™˜‘Їƒ€€€~zvpjd_ZVRNJE?94.+(%$"$'*-26;@DIMNKIIIIOV\afiiijkkmnppponmnooqtuuutrprvy~ƒˆ‰‹‹‹‹‰‡…‚€„†‰Œ‹‰†„~~~~~~‚ƒ„…†‡ˆˆ‰ŠŒŽ’“–™›››™—•“‘ŒŠˆ‡†………„ƒ‚€„ˆ‹’—› ¤§©¥¢Ÿœšž£¨¬±µ¹¼¿ÂÄÄÂÁÀ¾½º¶µµ¶¹½ÁÀ¿½·°­®°³¸½»·³­¨¢›”‡€ƒ…‡‰ˆ‚|wqlgc_\YX[^`bda^[ZY[_dhkoqsuwxyyzyxxwvuvxy{|}}}}}}}}}}}‚…ˆ‹ŒŒ‹‹‹ŒŒŒ”—››œ™“ˆƒ}zvttuw|€€€|wtvx{ˆ‹Œ‰…}€‰’œ¦°ª¥ š•‰‡…„Š”—›š˜•”””˜œŸŸ ž›˜–”“““’‘Œ‹Š‰ˆˆ‡†„ƒ‚€~{yvtsvy|~„…‡ˆ‰‰‡„‚‚„…†…„ƒ€€€€‚‚ƒ‚‚‚€~}{{{|€„‰•”“’Œ’˜£©¬­®¯°¯®¬«ªª®³¸½ÂÆÇÉÊÌÍÍÍÍËÊÈÇÅÄÂÁ¾»¸µ²¯¬©¥ š”Žˆ„}zwsmgaZTW[`eikjihgfb^ZXVVY\_acfilmnmlkjihgggjlnrvxxxwvuz€…‹’–——–––’ŽŠ…€†‹“—’ˆƒ}xsmieabcba_\VQNLKNQTUWWWWVUUTSRQONNMNPQSUVUSRPMPTY^chijlmooooppqsuwz|ƒ„……ƒ}{zxwxyy}€€~|~€‚†ŠŒŒŒ‹‹‹‰†ƒ€}}„‹’™  ›˜–“މ†„‚†‹‘“••ŒˆˆˆŒ‘—šœžžžœ›š™˜—–––—šœŸ£¦¤£¡ŸœœŸ¡¤§ª¬®±³µµ´²²²²³´´µ¶··¸¶´²­¦ š•Œˆ…ƒ€€€}{xtqppprtvtsqonje`[VQZcmu}€~|{yurnlklptwz}}}~‚…ˆŠ‹Œ‹Šˆˆˆˆˆˆ‡††……†††‡‡‡†„‚€}zywutrtvy{~€ƒ…‡ˆ‰‡…‚…‰ŽŽŒ‰ˆ‡‡‰ŠŒŽŽŽŽŒ‹Š‰‡†„‚†Š•›Ÿœ™–““–™œ›™—”’Ž‹‡„~~~‚„…†††…„„„ƒ‚‚ƒƒ„…†………„ƒ‚‚‚‚‚‚€€€|xtplkry†ŒŒŒŒŠ‰ˆ…ƒ€€‚…ˆ‹‘’“““““’‘“•™ž¤¥¦¥¤¢¥ª°·¾ÄÅÅÄ¿¼¹µ²¯¬¯³·¹»º¶±­©¤ œ—•““•——•“‡€~{{|~~~~{xuqmjhfdcbcdegigb^YUQY`hntvutsrrsstuvxz}‚„‡ŠŽ‹Šˆ‡…ƒ‚‚ƒ„‚|xwwwxyzyxxwvtkcZRJLT\bimiea^ZVRNLKLRY^adc`]^__cfikmopponmjheeefggiklnppnligdglptwyyyxxxyz{}~€‚ƒ…‡‰‹ŒŽŒ‰†ƒ‚€ƒ„†ˆ‹ŒŒŒ‹‹‹ŒŒŽ‘”—›ž™’Œ†~†Ž•œ£¡ž›™–“ŽŒŒŒ‘–›Ÿ¢£¢ ¡¢¢¥©¬¯±³³´³²²°®¬«ª©©¨§¦¦¥¤¤ œ˜”Ž‹‰‡†††††††ƒ~}|}~~}}yvrqpqqqrrrstuvwxyzyyyxxy}…‰Š‡lI&LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/warnton.wav0000644000175000017500000000463213263212010021335 0ustar aeglosaeglosRIFF’ WAVEfmt "V"Vdata Žˆ˜Ÿ¤¨¤š†}tsqoonopprstwy|€…‹’™Ÿ¤¨«­­¨¤ž–މ…}zy}€„‰ŽŒˆ„{vtsqomnoosw}ž¬µ¾½¸²­¨£ ™•‘ˆƒ†‰Œ– ¤ž˜Žsnlklnpppqqqy‚Œ–¡ª®²¶¹¼²¦›†~~}~€‚Š“ £¡”ˆ~wpmllmmnopt{‚Œ˜¤¤¤¢œ–”–—šž¢œ–ˆ€{xusrpx‚Š’™š”Žˆƒ}{xvusrrrtwzˆ”™œœžžžŸ Ÿœ˜”‹‡„}}}}~~~}|zyxvusrqrtvxz|€„ˆŒ”™“‰|xxz}|||yurqpppppppqqrtvx{}~~~~~…Œ’˜žœ•‰ƒ}|zyxwyz|}~}|{yxvusrqqrrru}…Ÿ­®­« ”‹ˆ††‡‡†…„‚}{zxw{€…Їwqjjklnoqqrtwz‰‘𣬴¼¿½º° ‘Šƒ}}|…Œ”ž§¡™ƒuljhijjlmopru~‡˜¡ª²»¿ÃÀ²£–‹€|{yyyz|~~~~|yvutrrqppppppw}„–ž¤«±¶¼µ­¦”ŽŠ†‚~{|}}}}{yvtrpqrsstuuuuuuuuw‡“¤¶½¾¾´©Ÿš–’‘Œˆ„€{xy{~…ƒ{wsnmlkkjkmoqrtuwy{}~~~…ˆ˜ŸŸ ›†}y{}}{ywsommmnopppqqquz…Š‹ˆ…‚‚…ˆŠŠ‡„~~~~}|{xusqnmkjjjklnoprstuz…”œ¥®¸ÂÌ´§•ƒvussssx}ƒ‡‹‹‡ƒ~zvsqpnmmnpqstuvw{ƒŠ‘˜Ÿ¦­²¸³¯©œ†{xvtz€‡˜™”‰‚{xvsqppppqrs{„–Ÿ¨±»¿ÀÁ² „zttuvxy{}~~}{xtrqpqqrrrrrruy}…Š–¢®¼ÊÈ·¦–†vuuvwyŠ”œ¢¨›ƒzrmmmmmmopqrtuwy}ƒˆ™¢ª²ºÂËÆ¼³£“„€{xvs|‰–¤²¼ª˜‡xieiloqrrrstvz„ˆŒ‘’”˜›™—•‰„~~~|zwuronlkihjklnorx}ƒˆŽ‘’“”“‹‡„€€€‚„†Œ‘•––‘‹…|xvusrrqpptw{ˆŠ‰ˆ†ƒ€…‹—žŸ˜ˆ€wuttttx„™¡©¢˜Ž†~xvtsqpppqrstwz}€ƒ†‰Œ“–šžžš–‰ƒ€~|{z{||}~~{yvsqqqqrrrrrsuw|„•Ÿ¨±ºÀ¾½µ£‘…}uuvwxz{|~}{zwtqqppppqqqrrsvz~‚†˜¢«´»¯¢–Œ{ywvuuwz|}~}{zxwvutssrqpptzˆ‘˜™›š˜—𠥩ª¡˜…{wutssu~†Ž”š—‘Š„~xvusrqqqquy~ˆ’šž££¢¢Ÿœ™–“‘Ž‹ˆ…‚€~zwtplmmnopqqqrrrtwz|~€€€ƒ…Š”–˜—‘‹†„‚…ˆ‹ŠŠ‰†ƒ€|yuqnmmnnorx~„Œ“Ž‹†‚ˆ“˜ž˜“‡}|zyxx{‚ƒ…ƒ€|yvtsrqqqrrruz†—™œœœ›Ÿ¢¥¨©¢›“Š{ywvuuzƒ‡‹‰yrlfilnprsssvz}‡‘𡍮³·µ±®¢–Œ‡~~~ƒ‰˜¢¨¡™ƒwqomlklmnopqw€‰’›£¬µ¼À娗Š~tuvwy|„‰ŠŠ‰…€|yvtrpppppptŠ˜¨¹¸´°§ž—•“‘‹…€{vssstuv{‚‰ŒŽŽ†~wsnnpqstuuvy…›§«®¯«¦¡›–‹…ƒ‚€€€|yvtqppppppqqrrstuwy}€†”˜ŸŸž›—’Šxvtuy}}{yuplkklmopppqqqtvy{}}{zyxx€‰‘—œ”‹„}vvvwwxy{}}}}{xvtsqpppppqqs~ˆ•¦¶¹¶²¨’ŽŠ‡„€€€~}|{{{~„‰ˆ€ytnmnnopqrsu|ƒŽœ«´»Á¿¾¼·²«¢˜’‰…‰™¤¯ª •ˆ{rrrsssrrrtuy‡–£­·µ¯¨£˜—•”‘Ž‹†„†Š”ž¢žš‘ƒvpmklnppqrrr|ˆ”¢±¸²¬¦ž—”“‘Ž‹†‚~zvy|€}yusppppqqrstuuuuuu}†«±¯®§ž”‘Ž‹Šˆ‡…„ƒ€|zwutrrqqqqrtuy}‚‰‘–šžŸ Ÿš—“‹‡ƒ€|z|‚†Š‰ƒ~wpjjklnpqrsuwx…‹””’‹‰†„‚~}}€…‰Š‰‡„}wspnmlmnoprsv{„Š›¦±½ÉŹ­ ’†„}zyxxwwxy{}}~}{zxwuutssrrrry‚Š™¨³¶¹¸´°­©¥ ›•Š…y|†Œ’”Œ‡ƒ{wtqonnoprsw|„†‡…ƒ‚‚‚…ˆ‹ŒŒ‹ˆ……‡ˆ‹“‘ˆƒ|yvspoopppt~ˆ‘›¥¤¡Ÿœ™•Œ‡„€€€‚ƒ†‰ŠŠŠ†|yuromlllnoqqrsstz„Ž›ª¸µ³°©£–Š…|zwussuvxz|ƒ„…ƒ€}zwutrqqqrssvy|†Œ•Ÿ©µÁÁ»´¦–ˆƒ~zxvz‡—–‰ytrpnllmnoqtyƒŒ•ž§±ºÀ¿¾´£‘…|ssstvxz}€~}|xtqqqrrrrrrrrt|ƒ‹”œ¥®¸ÀÇʺ«œƒ~}|}~…ŠŽ’І‚~zvsponooopqrstx‚‹˜¦´´³±«¥ œ˜•’‹†}xvz}€ƒ†ƒ€|zwtqomkjlmnLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/klapper.wav0000644000175000017500000001132413263212010021277 0ustar aeglosaeglosRIFFÌWAVEfmt "V"VdataU„†ˆŠ‹‹‹‰†„‚}zxxyyzz{{|}}~€€‚ƒ„„„ƒƒ‚€€€€€€€€€€ƒ…ˆ‹Œ‡{tnhb]bjr~Š•šŸž™”Š}qjc]\[_fmxƒš¦±¹Á¾­†kQLJINRYepw|€…Š˜ ¦©¬¬ª©›Œ~wpkjh]L:645GXl‚™­ÀÒÚßâÙÑÅ´£ŠjI5$ $9Of~˜³ÏØáæåã×Àª“|eO9(#!'.DLUi~‘¡²¹ºº­Ÿƒui`WSQPRTVZ_frŽŸ°ÃÖæ×Ƕ¡ŒsW;3227H_u‡—§¢˜“‰†ƒ…ˆ‹Šˆ‡ƒ~zwtnhaUI?HP[iwˆš­¹ÄÏÕÛÙÈ·¢‰qR2!+=Tl‚™¯ÁÔáãåÞÒÆ³‡qZF6',:NauŠ ±¼ÇÎÔÙÑÉÀ³¦˜‡wi]PIA<<<@GNW`jtŠ’›¢©°³´´²¯­§¢›’Šxpg_WSOLKJNSX_gnw€‰—œ ¥§©©¥¡—’Œ…~ytolihijlnqtx|~€‚‚ƒ‚€~}||{z{{|}€‚„†‡‡†††…ƒ‚€€€€‚ƒ„……†††ƒ~|ywussssttuvxy|ƒ…†ˆ‡‡†…„ƒ‚€~}{zyzz{|}}||}}}~€ƒ…†‡††…„„ƒ‚€~|{zyxwvvvwxxz{|ƒ…†‡‡‡ˆˆ‡‡‡†„‚€}{ywvvvwwwxyy{~€‚ƒ…‡ˆ‡††„ƒ~|yvtsqsvxy{}~€‚ƒ„†‡ˆˆˆˆ‡‡‡†…ƒ‚€~|z{{{{{zzyzzz{{{|}~€‚ƒ„„„„ƒƒƒ€~|zyxxyzz{|}}}}}}~€‚ƒ„„„„„„„„„‚~}|zyxwwvvwwwxz|~ƒ…†ˆˆˆ‡‡†…„„ƒ‚€~~~}||{zzzz{|~‚ƒ„ƒƒƒ‚‚‚€€~}{zyyxvtqsuw}„‡…ƒ~|zxwwwx|‡•£¤ œŽ€q_NEGIXn„”£±¶»·§˜ƒzrkd]WTUV[bhx‰š¥±º½Áº®¡mWA1106AL^r…’ž©¯µµ³±­¨£š‘ˆ€xqjb\UOLIIIIP\iv„’¡°¼ÀÄÄÂÀ·ª€rdVKFABDELS[gs~ˆ’š¢ª««ª¨¥¡š’‹…~xrliffhkpv}€~}|zwxxxz|~€ƒ…‡‰Š‹ŒŠˆ†„|yxxxyz{{|}}}~‚ƒ„„ƒƒƒ‚€€€€€€€€‚‚…ˆ‹‡„€yslgacfiu‚Ž”šœœœ”‡{rjb]XY`hq{…‘žª²º¼µ®›~aWPKKLP\gpv|…‰‘š¡¦ª­¯°¥—‰tlkibTG<1'9J]rˆžµÌÖÛàÜØÑ³žaH0,=Siƒž¹ÉØåêîæÐº¤v_I4,$!"".ASfyŒž±¿ÄÊËÉÈÀ·®¢–Š~rh]SOLHHHKQX_fmu|„‹’˜ž£§ª®¬«©¦¢•…}ume]YUQQPRUX^elt{‚ˆ”™¡£¦¤¢ ™–‘ˆ„{vrokihhiiilnqsvx{}~~~‚ƒ…†ˆŠ‹ŒŒŠˆ†ƒ~{xvussrstvwyz|}€‚ƒ„…‡ˆˆˆ‡†…„‚€}{zyxyyz{|}~~€€‚ƒ…„„„ƒ‚€~~}|{z{{{{{{{{{{{{{{|}~~~~~~€ƒ„††††…ƒ~|zyxxxyyz{}~€ƒ„…†††………ƒ‚€€€~~}|zyxyyyz{{|}~€‚ƒ„…†‡†††„ƒ~|zxvutsttuvxy{}~€‚„………„„„ƒ‚‚€~|{zyzzz{|}~€‚„†‡‰Š‰ˆ‡†…„ƒ€~}|{zzyzzz{{{zyzzz{{|}~€‚ƒƒ‚€~}|{{||||||||}}}€‚„…†††††……„ƒ‚€~|{zxwwwxxxyzz|}‚„†‰ˆˆˆ†„‚~zwustvw„“ŸŸžšq_LGEEZoƒ”¥²ºÃ¸ª›€rfZTRQRSSVY]iuƒ’¡´ÈÜÔÍIJŸ‰lPA8/25:EP^n~’§½ÆÎÓÒÑɶ£}jYH987:AHSaoz„Ž•›ŸŸŸš—”‘ŽŒŠˆ†ƒ|yuqoljhegiknrvzƒ†‰‹ŽŽŽŒ‹Š‰‡…„~{ywtrpnmlmnoqsux{~„ˆ‹ŽŽŽŽŽŒ‹ˆ…‚{yvtsqpooprsuwz|‚ƒ…†‡ˆˆˆˆˆˆˆ‰‰ˆˆ‡†„‚€~{ywtttuuvwyz|}„††‡†††„ƒ€~~~}|{zyyxxxxxyyy{|}ƒ…‡ˆˆˆ‡‡‡…ƒ~|zxwwwxxyyz{}€‚ƒ…†ˆˆˆ‡‡‡†„ƒ€~{ywuuuvvvwxy{~€‚„…†‡†…„ƒ‚€~~}}|{{zyxxwwwxxy{}~€‚‚„…‡‡‡†††…„„‚~|{zzyyyzz{|}~€‚ƒ„„………„ƒƒ‚€€}zxwuuuuvxyz|}}}~€„†ˆˆˆ‡‡†…ƒ‚€~}|{zxxxxyz{{|}~€‚„†‡ˆˆˆˆ‡†„‚€}zwutstuvxz}~€‚ƒ„„„…††‡‡‡†„ƒ‚€}{zyxyyz{}~~~~~~~~~~~~€‚ƒ„…†‡‡‡‡†…ƒ€~}{zzz{{{zzz{||~€ƒ„…†††…„„ƒ‚‚€~}|{zyxxxxyyz{}~€€‚ƒ„…‡†……„‚~|{zyxxxxxyyz{|}~€‚ƒ„„„ƒƒƒ‚‚‚€~}|{zyyyyyz{|~‚ƒ„……†††……„ƒ‚€}|{zzyxxxyz{}~€€€€€€€~~~}}}}}}}}|{{zyyz{|}~€€‚ƒ…†ˆ‡‡†…ƒ€~}|zyyyzzz{|}~€‚ƒ„„ƒ‚€€~|{zyxxxyyyz{{}€‚ƒ„…†‡‡‡†††…„ƒ‚€}|zyxxxxxxxxxy{|~‚„………„„„ƒ€~}|{zyxwwxyz{}€‚„†‡ˆ‡‡†…„ƒ‚€~}||||||{{{zywwwxxy{}ƒ…†‡†††…„ƒ}{zyyxyyy}…Œ’”ˆ}toijlmx„˜¡£ •‹vj`ZUTWZcny‡•¢ª²µ³±¤{gS@?>DTdy‘©§¡›–‘Œˆƒ„†‰Š‹Š†‚}zvrni_RHJLQ]jyŒž­¼ÊÒÚÛϱ‰kK*!+BZqˆŸµËÝàãáÚÔí˜kUB/!%.?Rez¢±ÀÊÑÙÓÍÆ¼±¤”„uhZOE<<<>CHPYblw‹”¤«°²´³²±¬¦ ˜ˆvne\WQMKIKPTZahpy‰‘—£¦¨©¦¤¡œ—‘Šƒ}xrnjiiijlnqux{}€‚ƒƒ€}|{z{{{|~‚„…‡‡‡‡†…ƒ‚€€‚ƒ„…†††„‚}{ywtssssstuvxz|„…†‡‡‡†…„ƒ€~}{z{{{|}}|||}}~~€‚„…†‡††……„ƒ‚€~|{zywvvvwwwxz{}ƒ…†‡‡ˆˆˆˆˆ‡…ƒ}zxvvvvvvwxxz|€‚„…‡†††…„‚}{yvtqsuwxz|}€‚ƒ„†‡ˆˆˆ‡‡‡†……ƒ‚€}{{{{{{{zyyyyz{{|}}~€‚ƒ„„„ƒƒƒ‚€~|{yxyzz{{||}}}}~€‚ƒƒ„„„„„„„ƒ‚€~}|zyxwvvwwwxyz|~ƒ…‡‡ˆ‡‡†………„ƒƒ€~}}}|{zzz{|}~€‚ƒ„ƒƒ‚‚‚€~}{zzyxussssy„„„ƒ€}{zxwwxxx}‹™ £¦™‹|k[MDFile created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/kink.wav0000644000175000017500000000415013263212010020574 0ustar aeglosaeglosRIFF`WAVEfmt "V"Vdataé…Œƒzw}„„‚~~~}}|}€~}|}€|x~…Š€ur€ŽŒ{jv‹ …k^}›™vRg¹‘hOuœ ~[g‡§Žsbx’~jo†|u|‚„}{y€ˆŒ€ss„–w`w–¬ˆd\†°£p>fžËŒL8z½µw9[’‘`Ly¦¤{Se‡¥ŒshzŽƒwy}‚†Š‰}qw‹ŸŽrUy®ƒWZŽÂ¥i,k¯ÕŠ?;àÀnZ¢Ñ’RF~·©yIhŽ©Škc{“€ow‚‰„~~‚…‰‚zu‰‹tx†“‰{q~Œ‚uv‚Žˆ~v{ƒ||~ƒƒzy}}y}…~}~€€€€~}€ƒƒ|uwŒ…xk{‹”mn…uYv—«†`[¤˜uRn§‰kc}—‘zcr†”…wr}ˆ‡€y{}€ƒ†…}vz†’…rd}–œ}^fŒ±”hAu©»€ENÓªc b¥ÅˆKKƒ»£p>i”«ˆebœ”ivƒ‹†€}{y€‰’pgššyYk“»’bCz±¸{?V˜Ú X$k²Ä…ERŠÂŸoJq™¦†ei‚›Ž{ly‡‹‚yy~„ƒ‚€~‚†ƒ~x~†Œ„{x……z~ƒ‡„€€}|€„…yy…‚}x~…‡{z~|y|~€‚ƒ‚~{~ƒˆ€xsŠŠ{ls…–…pc}˜œbkŒ¬‘mQt– €`eƒ¢u_w—„pq‘ˆ{qy…~|zx~…‹~qn‚—’x_r’±‰aP€±­w@a¡à˜O(tÁÇ~6Q’Ó›^9n¤­‚Vc‰®“t_vŒ’ƒuv~‡ˆ‰‡wx†”‹vax”§„a[„­ rDkŸÇVG‚½²w;_”Á“fTz ž`pŠ Œwn|‹Šsw…}|}~€€‚……}}€„¿á£c@|¹¸s.R î¥V%n¸Ã?R‹Å™eBm™£^fƒ {lz‡Œ„|{}~ƒ‡‰€wv„’Œ{iz¡‡ngƒŸ˜yZoާ‰j_~š}`m„˜‡vn|ŠŠ~sw~„€{z~ƒƒ€}€€€€~}‚€~~ƒ‚{ƒ‡{yЉ~sxƒ‚um{ˆ‹swƒŽ„yr|†ˆ€xz€†|y{~€‚|x~…‰}rp’ydw¦‡h_„ª¡uJišÆYBy¯­yE`‘À”gQvœ}]iƒŠwmzˆ‹ƒ|{||ƒŠŒ~ps‡œŽrVxœ²†ZWн¦l3h¨Ñ‹D8‚˸s-^œÊ”_O|©¡{TkŠ£Šri{Œ€tz†…ƒ~{~…‹ƒyq‘quˆšwd{’›„mo†Žu^sˆ“ƒrq€Žˆ}r{„‰ƒ}|€ƒ}z}€~‚€€~‚„‚€~ƒ„z{ƒŠ†}u}‡€sq‰{mx…Ž‚ur~Ї|px‚Šxu|‚‚~}~‚†…}tx„‘…uf|’š}`f‰¬•mEt¢·€JM‹É«m/ež½‰UP}«œtLm¦‰mg|‘Œ}nv€†„ƒzt|ˆ”„qf€š|[h¶’eEy¬¸€HW”С`,j¨¾‡PU„²˜pNp“¡…ij€–Œ{lw‚ˆ‚{{~‚ƒƒ{{ƒŒŠs{ˆ”„tn}jt‡š†rh|’ou„“†yq{„†y{€…€{y}€~|~ƒ‚€€€€€€€‚ƒƒ‚|„Šƒ{v€‰‹sw…“‡viyŠoq€‡ymz‡Œ€tu~ˆ„}x{~€€€~zv}†Žto€‘Žw_p¯ŒhU­­yE^–ΕU/q³¾€BSŠÁ™jJt§ƒ_fƒŸvfv†Œƒzy|ƒ‡ˆuu…•w`v’©‡e\„«¢uIj›Æ[G€¸³|E`¼’iUyž€bn†‰ukzˆŠ€vy€†‚||{~‚†‚{u~‡ŠttŽˆzkzŠ”ƒrqƒ•Ž{hwˆ“…vs~‰†}t{ƒˆ‚|{€…„€}€~~~~}||~~||€}z„ˆzxЇ|p{Š˜„og}“‘zdp†›†rh{}ls‚„yr{„…€{{{{ƒ„|uw„‘ˆucy’ ca†¬šnBlžÀˆPG‡Æ´s2^™Æ‘\L{ª£zQi‹§‹oe{nt~…‚~{zx}…ƒuj}•~gmЍ“pPv›«‚Y]‹º o>n¶Œa]ƒ¨šyXqŒ›†pm~ŽŠ~q{…Š„}{~€‚ƒ|z€†…~v{††{s€Ž~ou†–‰xl~”ƒrtŽ…zr{„‡xy„}{~‚€}~€~}}~}{|~€~{z„…~xzƒŒ„wk|•€ln‡ ’w\už…ljƒ›‘zbtˆ”ƒro}Œˆ~syƒ|zw|ƒŠrk|ŽycmЧŒiPwŸ¨zLYÁ™a3m§»†QV†¶œrMq”¢„fg€˜Ž{jx†Œ‚wvz~€|vu€‹ˆzkv‡™ƒmc|•”w[k‹«ŠgSz¡¤}Wd‡ªs`y’–€jp‚”‡xny…‡~vw|‚€~}}}~€ƒ€{w}„ˆwv€‰…ynwƒ€tq}ЇzluƒŽ…|y€‡†y|€ƒ€|{}~}~~~LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/laser.wav0000644000175000017500000000722613263212010020755 0ustar aeglosaeglosRIFFŽWAVEfmt "V"Vdata¤ž¦®µºÀ¼µ®ª§¥ª®±´¶³°¬¨¥¡œ—‘ˆ~rcUPMLOSX^dksz‚‹“œ¥«¬®®®®®®®®®¬¨¤ œ˜ž¤«°µ·¶´³²²°¯®¬«©§¥ ˜‘…yld\VTRMD<1& &-9EPZclu}€€€€†“ ­»ÈÐ×ÞäêéÞÔÊ¿µ¬¤›‘†yhWNJER`nu|€€€ƒ‰Ž–ž§³¾Ê×ääÝÖʾ± n\TRQSTVt’¯Êäëá×Îż®¡”ˆ|peZSOKSZblwƒ“¢­µ¾ÁÃû²¨š}m\J8,8DSfy€‚€‚‘ ­¹Åº¢‹u_LC;42/6CP\ivƒœ§²ºÁÈÄ¿¹©š‹|l]M=74345=Vo‹«ÊØáêïõñÔ¶—wWPQQTW_u‹¬º°žŒ~pd_[Z]_ivƒ’¢²Ä×ááá×É»²ª£ž™—šœ ¥ª ”‰yj_\XUSQ`q‚’¢§›…{qoonmkic]ZYYair‹™«½ÈÌÑǺ­œŠxbMEHKWfv‹ ¶Îæà¾œsG+;LavŠŸ´ÇØéÔ¿ª˜†zvrolijklqv~Š–¡ª´¹½À¹³¨–„yslkklrx~†Žœ®¿ÒåòÖº›xUB:3/,-T{Ÿ¾ÜÚ¿¥ŽxbYQMQUiŠ«¾ÌØË½¯žŽ|hU[ht™¾ÖË¿§‚]TUUbo~“§¼ÒçÒ­‡^3@g‹­ÏÕÏɾ³¤…eM@2EhН»¬ž‘†|vrnv€ŠŸ´¿ºµ§‘|qh`]Y]o€•­Å¹¦“{cWcn{‡”™   ›ŠzmbW]fpu{~}|zxwz|†Œ’–› ¤¨ž•Šyher”¬Ä²ž‰mQKaw‘¬Ç®‘u\DEh‹¦½Ó³ŽkU?=Xs‡–¥ž•‹‚yqh`cmv§½²¨–sOL]o•¾ãɯc64Uv Î÷Φ}S).[‡¬ÏðͪŠrZXj|‡™Žƒzwtx‚Œ“•Š…‚€ƒ‡‹‘—š—”Š„‚€€€€†Ž–¤§•„ulbs‘°¿ËЦ}\N?U‚¯¼ÃŘkNNOi•ÁÉÉǦ…pqr|Ÿš‘‡ve[cjsŠŽ’“•”†€{v|†”šš‘‡~wpnnnopquxxvslaWbm{˜µ¾¯¡Y1BWpÊÚ¾¢{O#>a…³áîÅvQ+;Tk~‘›•Š„€„‰«¬¦¡†fJMO]†¯À¾¼¤‡igdeoz†ŠŽ‘“““’’’ƒzpg]l|Š–¢ tjarƒ’›¤¡“…|tmquy~„‰Ž”’ŽŠskt}‹¡¶´¤”xY@Qbw“¯°¢“kZclu~‡ŒŽ‘’’Š‚|zw’£©­®–~kfam†Ÿ¦¨©”€ponu‚Ž˜ ¨®³±‰pS6Ec‚«ÕìÆ wK,Pt”´Ê¿´©ž“ˆ}rpmp‡¬¯±`VOLbw‰—¤«°´¦–„hLBVjŒµßδ™l?(:Lc~™§³¿ÉÓÍ¥~^B'Eqœ¸Õâ̶¢|qg`flx—¶ÄÂÁ¥€[PFALXgzަ¿ÙÁ©f?5Lc„ªÏŸªš‰}void_pƒ” ¬¨xh\Pcyœª±°®¥˜‹oQ7@H\†°ÅËÑ󢓃scSWgwާ½·°¨œ‘„wj^RH_v‹ž°±£–‹‚z}„„…‚|wwxxƒŽ˜ž¥©«¬¥›’ocmwˆ¡º¹®¢Šq^adiqz„œ©¶¾¯Ÿ‚tpppsv{Œž«²º­–qdZclt|ƒŠ–šŸžš‘‰~qdhov‡—¡ž›•Œ‚‚ƒ„†ˆ‡€yrler„–¦¶½¯¢”ˆ|qf[[[b~›±¿Í˺ªšˆnUD@;CO[p…œ¹ÕßѪŒnd\TPMTi~•®ÆÁ·®¤™‹xdUH;K_r‚“Ÿ£§¦£ ‘ndYTTU_oœ»ÙÙÙѹ ‹ziZL?LZi~“ž ¢ žœ~o`PP\iu‚Ž«¸ÁÉŵ¤•†wl`XY[f}”£®º·´¯Ÿ{aG?@AQbtŠŸµÍåãÕÆ±š„nYC.!8Ph™«½ÍÙåÖ·—~gRSTX_fvŒ¢­¶½´ª¡˜†~urqqtw|‡‘ž¬»µ©‰ucZQJD?Ndz’«½½¼º·´£ŒtaOBGKR^j‚ ¿ÌØÝɵ¢{iXF@:7>EQf{•³ÑØÛÜÔͯœˆr\RKD?9?YrŒ¦ÁÉÍÒÓÔÍ´›…q]UQNOPUdrŒ™¥±½½¾»±§œ‘…znb`^^aeintz‡’ž©´¿ÃÀ½¸³®›‡sbQILOSY_r†™¨¸ÃÆÈž¸¥{k[LA66;ARew‰›¬½ÎÔÒÑȽ²œ†oU<2226:@ZuªÅÒÔÕÕÕÔ¹Ÿ†r^VXY\_bjrz‚Š“¦«®°ª¤ž–†}snkhgfhov~ˆ’𠦫°²¨“ˆ|xvutrqnkigeint{‰–¢¬±¶³¬¥œ“‹‚yrmhfedfgilos|…œ¨­°±±°­£™„yuromjhfdcccjs|…Ž—Ÿ¨®²¶°¨ –ƒzpiebeimsy‡Ž”˜›Ÿ ¢¥§ª­ª –Š~qf\QH??LYfsž¬¹ÅÌËÉÅ¿¸¦‘|kZK@6222>LZjzŠš«¹ÄÏÚäìãÛ‰xhWF<1'-?Rfz“¬Ã×ëñêãÙÏŲŸ}l_ULE?:::Pbt†š®ÂÔåôñîëåßѼ§”€lXD2(!&/;FWizŠ›«ºÊÑÕØÖÓÏÈÁ¹°¨šŠzhVHD@<96?KWbmw€ˆ˜ ¦«°³¶·µ³¯©£›…}tle^YVTSSSZaitŠ”Ÿ¨±¹¼½½¼º¶­£™Žƒ{tld\UQLIFCIQXajt€‹–¡¬´»ÂÄÇÇþ¸±© –ŒvlbXQNKMOQV\agmvƒ¬ºÀÅÊÏÓÒÌÆÁ»¶«¡–Š~qaRE:/../38@M[iw†–§¸ÃÎØßçèæåàÚÓÇ»¯¡’nZE1%0=IVl–«ÀÏÙãìõüûú÷ïèÛÈ´¡zeP=1$")3H^w”²ÄÓáêòúûýýýýóäÖȹª”~hR=1*"*;MauŠ¢ºÏÝìóöùûüýýýøéÛȱ›…oYC-(GPZclu}…•œ£«²¸¾ÃÆÉÉÉÉÅÁ½¸´¯¨¢š’‰€wndZQG=:::=?CKT]fov|ƒ‰– ª´½ÆÊÌÍÍÍÌËÉÈÅ»±§’ˆ|pe]TNIDBABCDFILOSW^fmw€‰‘𣫴ºÀÅÊÎÑÑÑÐÎÍÈÁº³­¥›…|ske_ZUPMJGDA?<:<=?FLS^hs€Œ”š¡¥ª®²·»ÀÅÇÈÉÉÉÈÅ¿»¸°¨Ÿ–…xrlgb]XUSPNLLMMPTX[_cgkosw{€…ŠŽ’–š ¦­µ½ÅÇÈÊËÍËÆÂ¾º¶°ª¤ž—‡~vmd[RIB:53222258;@EKS[cluˆ‘™ §¬²·¼ÁÄÇÊÍÐÓ×ÜÚÖÑÍÉľ¸²«¤ž—‰‚{sjbYQIB;62.../0247:@GMYdoy„Ž™¤­µ¾ÇÏ×ÝâçìðïîíëêçàÙÑÈ¿µ« –Œ‚uh[OB92*$"(-4=GQ\gs‹˜£¯»ÆÐÙâêñøùùùùùøõòîêåߨÐÉÁ¸¬ ”‰}rfZPE;3*"&0:EOZgs€š¦´ÁËÕßèð÷úýýýýýýýýýùðèßÖÎù®¢—‹~qeZND:1*""(/6=FPZep{†‘œ¥®¶¾ÆÎ×ßçîòôõõõõõõôóñíæÞØÒÍÄ»²¨Ÿ–Ž…}tlcZQIB;5/+&""(.5File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/kabumm.wav0000644000175000017500000001240413263212010021115 0ustar aeglosaeglosRIFFüWAVEfmt "V"Vdata…‚‚†Š‘«ÅÑÈ¿ŸqC- 1Y¥ÇèßϽ•mXdqŒ²×Ôʽ‰U/&2]ˆ«ÍìãÛÖ×Ù¾‹XIEBu¨Å¦ˆd<Dn“¬ÅÔØÜÕËÁ¼·±¥˜„{uojbYQIB?@AFLSZbjqx€Š”¡±ÀËÕÚdz›yWF>7Kby”®ÆÜñøöõæÔÇÚíùùùôíæÊª‰fB& &8UrŒ®»ÃÌÏÐÐÌÈÁ±¢{fK/ +@Yv“³Óó÷øøõòíäÛàêõîçÞο°¡“„vh]SJD=986666;?DLT\ckqw}†™ž£¨®´¹½ÁÅÉÍÍÍÍÍÍÉýº¸µ²®«¨¥¢ žžžžžžžžž›™•‹‡ƒ€}zvrnhc]XSNIEA>;72.+(%$"""""""""#$&')*.4:?CHNTZaipw~†Ž•œ¤«±¸¾ÃÉÎÔÚàæëïôöøùùùùùùùùùùùù÷öôòïìéæâÜÖÒÏÍÆÀº¶²­§¡žœš…{wrnjf\QE:/&&&&&&&&&$#!&-4<<96?IRY_fmtxxx{ƒŠ‘—šŸ¡¢¤¦©²»ÂÅÈËÎÑÓÔÖØÛÝÝÝÝÝÝ×ÐÉËÌÏÕÚÝÝÝÕËÁÆÊÏÕÚÚÔÎÅ»°µ¹¾ÆÍ̹°§ž £¥«±³²²« –Šwwxy{|xsnkihjkjd_YRLGB=71/25;DLD;10/6Oguz|zyz|{xtojda_\QF;3*+45-09Bg”¾¾¾¶ƒ€›¯Äؽ£Œ€tprtƒ—ª¾ÒãëòìÛÉ®quy}‚ˆ}cH3!"2MvŸ£—‹}odin…·èõïéÄœ~šµËÚèÙ»~^G`z“¬ÄÎÐÑŸ©‘yaI0(+.Fb~•«¶ªž”Œ„€}|•¯ÇØéíåÞÀ›y‰™«ÄÝÒ¥ybSEn–³³²ŸySQ\ftŽš¦ ‡nR5%1==1%'/6TuŒˆ{_C/$2Kdy‡”Ÿ¨±¿ÍÖ®«ÁØçïøöóîÔ» ‚el¯¾ÊÒ­ˆc=&:[€¡’‚r_LRnŠ‘’‘tV>4*-:FR^jmol_RSap³Øãíö÷ùä·‰jP7c’»ÈÖÔÁ®¨¨¨„^=:7EiŽ‘„wcOB[tŠ›¬¨˜ˆzmcjq}“ªµ¹¾²¤–Š~rh]UOJIIK^q‡¤Àǽ´®ª§¸ÉÙäðóðíÙÀ§‡gTfxŠ›¬ª¢›}`C+ 1BRb[TR]ilhcP5$.;Rjrg\G. (+-@[v—¸×ãîòëãί‘ ¶ËÕßÚ¼„oZnˆ¢»ÔçíóìÞÏ©~TG::SlxyzaA#8Lc›•qM>6.d™ÆÙìä¡vH)8GXihUC_ŒºÂÉÆ¦†~£µÆØ¸•ubNOj†—£¯¬§¥©¬¥zfS@Qfy}€uT3 -Cnš¼ÍÞÏ©ƒpaVw˜·ÐêðéâǦ‡ylmŒ¬ÆÛñåѽ–oTUWh‰ªÁÕéÕª„^OV^s¨«®®¨£ŽgA* 6[hYIC@>^¡·ÍÜäëèáÙÁ¦‹qWFCAKYhc^WLA8639CNYep|‡•©½ÍÚçëìîñóõõõôòñèÞÔÌú¯£“jU?) &4CLQWOGDR`ks{seW^fo„™§­³·»¾ÆÎ×ÞåëðôõõõõõõõõõõõíâÖÆµ¥Ÿš‘q]G1# #)-$4KjµÊÜìÛʺ®¡œœœ ¤§™‹€}|{zyxx{~|si]OAGR]u¤¸ËÛæòõõõïéàÆ¬–‡x•©«¬«ª¨®½ÌÔÙݺ’ne\b}˜¨±¹˜pLB8N]lx„“¬Ä×âîóôõãм¤ˆ˜©¾ÕìðóòâÒ¼ž€z~ƒ ¿Õ¼¤Ž~nr‚’¯ÎèàÙȧ…xxxŠž±¼ÇÄ«’}jX[agillif^RG=3)('# .6)!)Cd„¶Ä³¢™™™¬Çáéðôñîãκ§–„œµÌÛé䯩“€m†£»½À®€SCCC^|—¢®«•kXETfw{~rM( +=Wr…‰Ž~`C:64Oj‰’ŠuaPA1+&,Ll­Î˾±§µÍßéóïèáÒù½ÀÀ¾¼ÃÌÕ²tvxvtq‡¥ÄÁ¾¾ÉÓÜâèÖºžsG#&);c‹ ª³”pO@27Wx›© •‹‡ƒydOD?:Oh~}{r[DCRaku~…Œ‚w]7 2Tr†›£¢¢§­±°¯©–ƒlP5E`{…q\fzŽ©ÄÔ¼¥…\38Rm‘¶ÒĶ¥‘|‡¡ºÃËÍ· ‡iK6%*8GXh}–¯¼ÇÒÙáæçéåßÚé}kbluupkV=%6NXVUUUVVWVRNPUZfs€•©¼ÍÝåååèëíííìëéãÕȰ”wnecu‡“—›Œu^ULGPZ___WK?2%"*(')B[yžÃÔØÝħž®¾ÐâéééãÛÒ°si_g}’¡¯»¨•„vhjz‰–¢­Ÿ„~x}¤©® ’‚hN:,)=Qbr~zvjQ9)%Jo‹™¨¢“„—¬ÁÏÝßÑï™‚Š”¡¸ÏßáäÜÏ­–ƒ‡ŠŽjRICA[u«ÆÖÝäγ˜†tggfks{mZH5#&;Pn­ÃÙèçåÝ黎lhdf{—‘‹vZ?0!.>Xv”¢®¶«¡ž¤ªŸzbJ50,0=KXdqŒ¨ÃÒàçåâÔÀ¬¸ÇÔÐ˽›y]E-2;Fi‹¨»ÍȲ…lVhyŒ¤»Â¼· „hP7$#;T`irstv}ƒŽž®ˆP +3465327=C_}˜«¿ÎØâæèéãÝ×Ðɽ·ª—…r_L<,  &>Xq|‡‘–œ‘}ifdfv†–¨ºÄÈͺ£Œf@&&&7Trpg^UMM`s‰¢¼ÌÙäàÜØÕÒÓÖÙŬ“qO7:=Mj‡š¨¶œ‚jZILby¨Àµ©›€f]ky„Ž˜‡t`C'$=a„’ž£…gM9%+?Sn‹¥¬²¸¾ÃÁ»´¡Œxpij|œª¸¹¸··¶ºÅÐÙÞäÛÐÄ®—‰ŒŽ• ªŸZ5.DYsŸž”ƒrbSCVj{‚Š„p]L=.Je„¡»ÕàÕɱnT<)Gd|‡’…zhT@6,)3=QnŠ— §¡›™ §³ÂÒÚàä˱•uURjƒ—ª¼ždJ/1Qp”ºàØÏŸ|\?""&?ZsŠ ©¢›˜—– ª±«¥œ{zxl`RA0+9FWk~vl`L7-6>Tt”ª¿ÐÈ¿°’tbYPh†¤ºÑÙÁ¨ŠhEGQ\x”ª°¶²¦›~pib^^_ciortv…•¢«´®š…teU]dn‚•¤«²«ž„wkc[UROC14Me|’žš–ˆuaJ2%+8Snˆ¡»ÉÖà×ξ ‚spl›±©¡–†uu‚Ž¡¶ÊÓÛáááÖÁ¬qRKCGjŒ›™˜^>2&%>Xr‹¤š„nrv}“©»ÊÙÔǺ¥zaH83/@Zs­ÄÀ¼­q_SH\r‰£½ÍÍÍô¥†dE8*"""2Lf˜°¿Ï×ÑËÁ³¦—‡xi[OLHB;3:CL\m|ˆ•”Š€}|}¬»ÊÎÊÆÇÈÉÇÆÃ¼µ´¶¸´¯ª¤Ÿ™”’§¨¦¤zdH-!"'/62-)(&->Odz£µÆÊÏÑÑÑÎÉŸ©›Šzk_SI@7:?EVhz ª¬®‰x†”®É˺©ŠhHMR^~°¸À±œ‡gF1=IXj|~~rg^\ZUNGEEETdu¥¹ÇÕØÖÕÈ»¯ª¤¨·ÅÊÌ;­‹zt}…Š‹ydN<) "2KeyŒ¢§¨¢œŽ{hYK@P`r‡›¡˜‘Š„‘ž«»ÊÓÖÙÎÁ³ŸŠ{zy„š¯·º¼©—…tc`jsx|€xqnu|{skgedp{ƒ€|zzztkbWLA:2059I_t‡š©©¨ž…l_YSfzŠyhXH8CQ_r…‰„‚‚‚ެ½ÎÙÙÙÓÉ¿´©Ÿ«¶ÁËÕÕÐÊÁ·­¥™¡¡  ‘~lXD8>DKQXSLEB@?BFILOXcoh`WG7/12C\t‘­ÆÉÌÆ¸©¥§¨¡™”–—Ÿ±ÃËÎÑÁ¯‚hUQLVi{„Œ‘Œˆ‚{tuy~‚†‰‡„‚€}xsokhjlligjqx…”£¯¼ÄÃÁ½¶¯«§¤§ª­®°¨˜‰u_IC>?Sh{Œ—ˆyphew‰œ¯ÃÀµ©“}jjip‚“¦¹ËËÊÆ²ž„b?0-*4>Jby™¥§¤ ¢££—Ž{iVB-.28MbwŒ¡¥›’ˆ~u€‹•›¢›ŠyiZL]n‹—”„tcRA?>AN[l—«¾ÑÓÔÔÓÑÃ¥†uj_p‘𣦡–„‰Œˆp`VOGTbp€—”„tc\VSev‰ŸµÃÉÐǼ°œ‡ywuwz}yto^NCCCOdzŠš§¢œ–‡…††–ž ¡žŽ~mZHM[h|™•ˆs]M@2@N^r‡“•—…zˆŸ®±¦›Žq|‰• ª­¥”‹}|vokjiiiintxuqpppy‰˜¢¬µ¶¸·µ²­¥œ’†{k\ND::AH[r‰š¬´©wbZVSqލµÃ¾©”„vhr|‡”¡«±·²«¤¥¦©´¿ÆÈÉ¿²¥˜Œƒˆ’™ ›‘ˆyj^add_ZQD730/7?Mfƒzqh_ZtŸ›“…wnfax£±¿Áº³§›Ž‰„~vmkkku‚œª¶¼ÂÅÅžµ¬Ÿ’ˆ†„„„„‚€{wsnjcYPF<2224:BI]t‹—¢©¦£¡  š—‹~si`]`cirz}…‰ŒŠ†‚…‰–Ÿ¦«¯­ª¦¢™–“ކ~xsomkkt|ƒ‰ŽŒ‡}†‹”™•‰zkd]\emsuwrlgilq~Š“™Ÿ™‡„‚‰—Ÿ¨«¬¬€o^VWW\agow{vpkheiou}„‹Ž’—›¡§««ª¨¢˜“Ž”˜™—”ƒyj[NV]i}›ž¢˜Œtgagmw„‘¡²ÂÃÄÄÀ½²Ÿxpsv{†™¡©§£ š•‘Š‚uh\OC?<CHM^o~†Ž‘“—š¢ª¯­«§ š–“‘–šŸ¦­®©¥—…rfZS\fr‘𠦣 œ“Š€ujb\U[`gq{‚„‡„ztnhd__cgknrssrjb[VQPRS^kyŠš¨°·¶±«¥ œŸ¡¢¤¡›•Œ‚ysmjjkmptx|€‡• ª²¶¹²§›…zpgaaacfimquuux}ƒˆ•—™›œ›—’‹ƒ{wutwz}€ƒ………ƒ‚€}}~€ƒ‡ŒŽ’•™¡¥§©ª¡–‹sigeglponmLISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/sounds/snd_classic/infotron.wav0000644000175000017500000002275213263212010021506 0ustar aeglosaeglosRIFFâ%WAVEfmt "V"Vdata¾%¨’}ppp„ª‘ypppponnny…Š~r€™¬”|~–®–|jii~™°°°°°¯“xt«˜}hhhhghu‚ƒvh}•§«®Ÿ‡xŽ¥°°°°°°°°—ydxŠ’”–˜š‘{dkw}rfm|ˆxgn­ŸŒ†˜«°°°°°°°°°°°°°œƒvަšyY]`eintzzk[e{œ©{Wv˜°°°°°°°°°°°¢•Œ‰†“£§‚^]r‚p]Ziyl[Xw–˜…™¡¨¯©¢ §®°°°°°¢ŒwŒ¢¡€^SMM`rsld\UU]f€œ£{RdŒ°°°°°°°°°°°¦™‚w€˜¯ƒYJ^sfQFS`[MC[t€|y~“ª¡Ž€”§°°°°°§y†ªq]OAWmp[GJQTLCVuoPW¬°°«Ÿ“™¥°°°­©¦|y‘«ŒbDRa`UJJJIEAQetw{mXIsœ¥‘~Ž¢°°°°°­œ‹†‹ŽŒ€cFWsfJEKPJDKczhQMy£«¥ ¦­°°°°°©–„Ž ©ˆhWQKU`aTGCBFZnof`n}Œ®œ†”ª°°¯¨¢š‘ˆ–¤žtIZ{mMACEINWgvfPLw¢‚m‡¢°°°°°©•Šžª‡fau‡mQBFJGDEZoiUBj •‰•¤°°°°°® ’“¡¯–|id`cilZH@@@RdkaXan}’¨žƒl†¡°°°¯®«¡–›¦«†bdˆ­‡\BFJHDDWkgTAj“ž€`v–°°°°°¯¡“~aDN\jv€sZDCA@@@P`eTDWuŒœ¨°°°¬¨¦ª®¤“‚ufi~’wWDNXXTQW\[VQs–œsIc¯®¬¬®¯©£¢¨¯–xkˆ¦’hAGMMGAN]bSDVtˆvcmޝ°°°°°¬©¦ª®¡‹wy{zuo_MDO[]\YOELaw‚ŒŽ€rš®£˜š¥¯°°®ª¦‘ym‰¥“iBSefTCISXMCVuŒnOX‚­®¬¬®¯¯®®®¯¡‰sŠ¢žuKFIJJJOUZPFLczrff€˜¤ª¯«§¨«¯°°¨”€||||{mVAThm`RKEEUeq{‚q_hЬŸŒ†˜«°°°°°¢Šs‰¡ŸwMSfp\HDKPJDLd}kRLx¢¨•Ÿª°°°°°©•€‹Ÿª‰iZXWZ]\WQKEEYmog_n}‹œ­žŠ•ª°°®¢•Œ†€‡‰kLVm|cKACEOYco{iRKv¡ ‰vŒ£°°°°°©”€ˆ«†aYjzeOBFJGDE[rmWAk”¦š—¥°°°°°®ŸŸ®–zfb_`aaSF@@@RdkbXctƒ–¨£Ž{¤°°°¬¨¤ ››`^x‘wVACDJQXdpiUAj”£‡l~™°°°°°¯¡“’ ®—{ju€rXABDDBAQchWEXwŽˆ‚ˆ—¥©­°°°© ›¤¬¡‹vrmmrxgSFKOTZ^][_fn‚˜œ‚hz—¯¯®®¯¯§ž¦®–yj‡¥”kENVWQKWeiWEXx‘}hp®°°°°°«¤¡§­¡Šu{€~oaVLFJOU\aTGLcz‚|‰ž¯®¬¬®¯°°ªœŽuoƒ˜‹jKT]`\WRNO`qz€„„„Œ®°°­§¡¤ª¬”}€—¯†]IS]UIBKSTOLeƒp]x˜­¥œŸ¨°°°¤|ƒŒv`XTPKFJT^SGKf€oTKv §›©°°°¤˜„}zzxfSPYba_ZOCRhv`I[…¯§ž¦®°°°°°¡‹z¥yT^lsh]SICXmpf[rŠœ£ª­®°°°°°¯›‡„™­”vbmyq`PKGM^opprw{Ь¥ž¦­®¯¨“€Œ ¨…c_mzePGKPW^emvvss‹¤¦“‘£°°°¡ƒ•¨œ|[bjhXGJQUNGQfwcOW€§˜ƒ{’©°°® ’“¡¯–|jhg`WPNKHDAVjnYDcŒ¦z™°°°«£š §¥{oibbb_XQKDH\peQHm‘”‚q‰¢°°°°°®¨¢š“Š}njpviZPMKVep\IW~¤“•«°°°°°ª¢š¢©¡…js„lRLNR]ieTBa‚•ˆ|ˆ°°°°°°¥š˜£­˜}k|fKQW\_bWJIh†Š‚’¦°°°°°®ª¦¨¬¬•€vuux{t^HNZaZSWaiYIOlˆ„||Ž ¨¬¯®¬¬®¯¬¨§«¯š€oˆ¡–tPNLMSZ]``THQcvƒ’‹pSr–¯®®®¯¯«§¨¬¯œˆ{vqz†ŠmPN\j[MJUaWJG^u|{{‚Œ®¤˜” ¬«¥ §­¢‹u‰‰xfXKDTedZQUXZXWg{jReЬ¬­©¢š §¬®¯¦šv—¯‹gSZa_ZVVVQIBUhtx|rgg…£¡‘†—¨¯­¬­¯©˜‡„„ƒ€~q^K\mo^MQY\PDOdxndfw†•£¨”Šž¯®¬¬®¯›‡–«™}e_Y]hreXPPPTX^iujTCdƒ”””””—¢­°°¯¨¢˜Š}££„edkndZUSPJDHXhmppiarŒ¤“‚„™®°°°°°¥—Œ’—’†{jZWhykUFJONIEWil_RcyŒš©ŸŠ{¥¯®®®¯ª™ˆ¡«vifcipn^MPV[\^dms_KPp’‘‘•˜ ¨°°°­ª¦š¬™~hpwrdVTRQTV]eklnnnp…šœˆt‡Ÿ°°°°°®£˜—ž¥–†yoeo€‡qYSWZYW[dmcUPg}‰’˜Š}—®¬¨§«¯¦š‘žª¡‰qsuvsqgZRY`bbchnj[Laz‰€w‚˜¬­¯¯­¬¬¬«¨¦¤¡œŠx{ŸƒhWYZ\]_`b`[Wcnz†’‚pkˆ§®­¬­¯¬¦ ¥¬¨“yxx…~l[agid_adcTFPg|{y{‡•¥¬¡—›¦¯®¬¬®¯›…~œvb_\]bfc`^\[^cis}veY{›ª¨¦¨«®®®®¯­ ’ˆ{Œ  ‚ecjme]ZZZPFJ_tvvvvuƒ›® ’“¡®°°°°°£’…›•‚qh`^emg^WXZXTQapreXm‡œ£«¨ š£«°°°¬¨ €‹ŸªŒoejnhb^\[RHEXltuvrmw©Ÿ‘Œœ«°°°°°¦•„‰…{pd]grl[KRZ\WQ]mvlbkœ¨§š˜¦°°°°°­™…‡›¯”xfffhiic]ZXW`iquzoa^{–œ˜”Ÿª°°°°°©—„Œ¨ylgcgllf`\YYepsqow€‹›«¡’Œš©®¯® ’‹‰ˆƒ€ymafpwk_[]^chmsytll„šˆzޤ¯­¬¬¬§–…ŒžªŽtjpviZQTVY\`hoiZKjˆ—‰”¢®®¯°°L¯¡“’ ®™€nlkihe]TRTV_imhdlw‚Ž›—‰}¤¯®®«¨¤–‘ŽŠ~qow€rbWYZ\]_fljb[oƒ‹€u…°°°°°¯§ž¦®›ƒu}…{hVVVVVV\bbSDSl€~{€‰“ž©¯®®«¨¦ª®£|yvuwxnc[\^`ab]Y\grz‚…}uƒš­ª§¨¬¯®¬¬¬¬š„y‰šŽt[agg_W[_`VMXl{naj‡¤£¡¡§¬­¬¬­¯£Ž{‹œ›‚kedba_`abTGKavuqr~ˆ•¢­ª§§©«­¯ªœŽˆƒ€}uj_eklhc[QN\jquxtpyޤœ’ª®®­§¢—‰{¡¡ƒeenrh^[]^[X]kyl\Xu‘—“‘›¦¬­­®¯©—„ «’ynlkgdbbbXKEZope[m‹’™œž ¢¥¨¬®žŠ“‰ukadlqib]ZWakqstuv{Ÿ›‹~¢¬®¯¨Ÿ–Œ‚Š™¢†kdmvla[]^^^akvrdWq‹•‰~Œ¡¯¯®®¯®ŒŒ®˜€ortnf^][XTQ\imcYfyˆ‰‹”š¡©®¯¯¥™’𣙆vqmlptkaZXW\dklnopp~‹„{ˆœ¬¬­¬¨¥”‘•™‰xmu~vhZZZ[]^ell`SbyŠx—­­¬¬®¯§œ–¡¬ ‰ux{xpgda^^^bfi]PUh{~€„‡’ ¬­¯©ž”ž©¨—†yux{wnfecbbbbbcgjqy€yry‹Ÿš“”ž©¦Ÿ›£«¡Œy…’’qnnnkhhii]QTfyuoq‚•šš›¢ª¨ž”ž©¨”€‚|uohcdfgijbXTbpwz|yv~‘¤Ÿ˜— ©¬¬«©¦›‰y…’‘~jjnof^]bf^UXgwpfey””•Ÿ©«¥ ¥«©–„…‘ƒvnjffffdc[RN_ottu{€‹šª©§¦¦¦¨¬­œ‹‰”Ÿ{oppja[^adgkotvuu„—¤–𣬭¯§–…‰Žoheb_\[]^YTVesofd}–šˆ—¥®¯¯¦›’މ„€|rgcefed_SGRdqh^g~“‡Ššª«¨¦¨«¢’„Œ•‘mostme_[Xcorokwƒ“›¤¬¬¬¬®¯Š‡™ª˜lqwrh_`bdgjosvvv‘Ÿ—’ž«­¯«‘™œ‰voqrh]X[^`adltusr†›Ÿ’…“¤°°°¨”””Œqmid^XVVVTQYfri`e~–‘‡„—©°°¯®¬¦›ˆzslhea[TOMKU`c[Rd}Žˆ‚‹ž°°°°°°®­ª¦¡“stvo`RLHGNUSNM^oxz|Œœ§«¯°°°°°°°®š†€‰’ƒpcdfc_ZYW\fpsv|„”𠦫­¬¬­¯¨•ƒŒš ‹vmljigeb_djpuyzyz†“œ¡¥£¡¢¨®¡‡ˆ{nnnmjgffghjouzyw}Š˜œž £¥¨¬­šˆ‚‡‹€skmnlighjhc_ly}tl~•£›’—¢«©§§«¯žŒ„‡ƒ~wpjjotojgijheeoy{wu€Š”Ÿª¢—“žª«¨¦¦¦~†’”„tnjgkonjgffgijs}vkuŠŸ›œ ¥¦¦§«®¦˜‹…‚™†shlpnjfffeb_gpuwxwtv…”•Žˆ–¤ª¨¦¨«©œ‰†„„„ukotsj`bgiaZ^jvtrsw|…‘—†Œ™¦¦¦§ª­ŸŽ†—vqmnsxphcefda`iqpicp}†ŠŠ‹–¢¤¢ ¢¤žœžŠvppppoke_`bcefkpslel{ˆ‰‹Ž“™ž¢¦¨«§ ˜Ž„†’Ÿ{ortnf^^^^^_ekopppps€‹Š|Œ¤¢ ¢¤¢–‹Š‰‚|skqxyoedefc`ckrnijry€†‰y€™—•˜¡«žŽˆ˜§‰xurruxphcefeddjpnf_ly€€€‚…‹–¢¡š”›¢ –Œ•ŸŸ{vvvqmhc_befdcglplhmw€}z€Ž   ¢¥¢ž™•‘Œ‚ytwzsjba__abglnlknsx…„~yˆ—žœšœž“ŠŒ“˜‹wusuwvohilnmkmqtojjs{~€ƒˆŽ“’‘•™•“˜ƒyyzxuqmihknnnoopnjgq{~ys|‡’“‘މ{~…Štnnnkhhknlihmrvz|yvyƒŽŽŽ•œ˜”›¢ ”ˆƒ~{~€{toprpkgjnng`gqxxwxz}„‹Œ–™—”—›ž’…€‚ƒysokmprolkmnmkmrxvss|„ŠŽŒŽ“™—•”””„~†‚wvutrqppplhinsuwwsow€‡†„‰’šššœ ¥œ’‹‡„…††€xvxzunknpkd`iqsqorv{ƒ‡‘—› ¥©§ž”š¡ €zwuuvtokigfffjmohafq}€…ˆŠ‹”ž¦¨«¬¬ª •• «™…xxxtojjjf^W^fkmnlihqy~„𢦫­®­¥œ˜–“’Š€wwxumdbbb_\_gnmklqv~…І‹œ¬¬¬¬®¯¨Ÿ› ¤™ˆzxvtssnifffffgkopooty„‹Š‰Š“œ   ¢¤ ”‰’ž Ž}xwvusqnklnopprstrot|ƒ‚€ƒ‹’—œŸš—“‘“‘ˆ‚}z}€{tnmklnppoopprsvz~zw‚”””˜œž˜‘”šž•Œ„~w|€yqnnnmkkmnhbbluz~€|x~‰”””–šŸ›œ¤«¡€€€}{unknpolklnlgcluzyy~ƒ‰’•—šœžžœšœžœƒ€€€{wroklnnlkjjjjjov|yvyƒŽ—Ÿ¤–•—šœž›’ˆ‚}{€†xppoopppppmkotyz||zyƒŽ”””–˜™—”•—™ˆ‚{}~wppqrollnpnlmsyzz{}€†™”ŽŽ“™šš™—”ކ€ƒ†„~wrmlqusnklnopqsuvtszˆ‹ŽŒˆ„šžœš–’އ„ŠŽ‚xrqqpppooliglqtvxvtw€ŠŽ”˜› ¢¤¡–Œ‡ƒ€‚ƒ~voqsqlghjjjjnsvvuw|€‡‘‹„œ¥£   Ÿ•ŒˆŠ‹ƒ{tqopqrolkmnnnptxvsrz‡Ž“’‘•™œžž˜‘‹…€…‰†}srrrqqoljjjmqtuvvvv}…І†šœžžœš•‹‰ˆ„zvrruxsnjjjlmoprrrsx}‚ˆŽŒ‡†‘œžœššš–ˆŽ••‡zusqrtrlgffhlpqrrolq{„„„†Œ“›¥ª¦¡œ˜“’Œ„|wxxuojgddgjlnopprux…†‚€Œ™   ¢¤£›’‡€zuqsutnhedcfilorqoqv{‡‹Šˆ— ¢¤£Ÿš–’‘”˜ƒxvtrrrmfdgjlmoprrqqx€ƒ€ˆ’ššš›Ÿ™“Œ‰†‚}xvutrpmjghjlorstuvx|‡ƒ€‡Ž•›žš•‘ŽŒŒ†€|xuy|wpklnnlkmopmkpw}€‚„„„Š”””•˜˜•‘‘’“‰€|zyvtqnklmnnnoqrrqrw|||~ƒ‰‘”””“‘Œˆƒ~yz|zuqnlkmnpqrolntz{||{{€‰”˜˜–”–˜˜–”…€}{{||vqoppmihlpnjhovyz{}‚ˆŽŽ’˜˜–”–˜•‹~|ywtqooppoonnnnnrwzxuy€ˆŒ‘”””•˜šœŸš“‹†‚„‡€xrqqponnnmjgmswxxxwx€ˆŒŽ–œ   ¢¤¢—‹…‚€~|yuqppokghijigjpvvuw}‚‡Œ“š   ™”Žˆ„„„€yrqonnnmljjjloqtwxvu|ƒ‰Ž“•˜šœŸ  Ÿ—‰‚}~~wpnnnkhgijjjlquxy{{|Š“’’˜Ÿ  Ÿš”‹ƒ‚€{wrnkorojghjlnpswxww}…’——“–œ   š”Žˆ‚ƒ|tomklmnlkjjkosuwxxwzŠŽ‘“–›Ÿ›–‘Š„„„ƒ€}zvsstrokjjknpruvvuvy|€…‡…„‰”””“‘Œ‰‡…„€}zvstuvspoppppruxwtsy~„ˆˆˆ‰Ž“’‘‘“Œˆ‹Ž‹‚yxwvsqponnnoqrsttttwz|||€ˆ‘““‘ŽŒŒŒ‰†ƒ{y{|yurqqpooprrqqtwy{||{|€…‰ŒŽ†{zyyzyvsrqqrrrrrrqruxz||||‚ŠŒ‰Š““‹‚|||{yvusrqqpppppppqtwyz{~…ŠŽŒ’””“‰…€€€zvtsrrrrqqpoortvwxwux~„…‡‰Œ‘’”””Œ‡‚}€|xtssqpnnnnlkmqsuvvuv~…ˆˆˆŒ‘•—™šš˜‘І…ƒ€~{xutsrponnnmkmqtttv{€‚…ˆ‰‹‘”–˜˜”Ї†„€{vtrqrrqpnnnopqsvvuu{€…ŠŽ’˜˜–“Іƒ€‚{urrrolkmnopqtvxy{{|€…ŒŒŒŽ“™˜•“’Œˆƒ€~|zyvtrrrqpoopqrruwxxx|€„‰Žˆ„ˆŠ‡„‚ƒyvtstuvsqrsuuvwyzywy~‚„„„„„†‹Œ‰‡…„‚€ƒ€}xxxxvuttuvvvvwwxxvux{|{{ƒˆ‰‹ŒŒ‹Šˆˆˆˆ…‚€}yz{|xtrrrrrrrrrrsvy{|||{}ƒŠŽŽŒŽŒ„}|{zyyvsqqrrqqqrrrrux{}€€‚„Š“‘ŽŒŒŒ‹„~{||yurpopqrrqqrruwz}€~~…’“’ŒŠ‰†‚~{ywxzxtopqrrrrrstvxz|~€€€€ƒˆŒŒŒŒŽŒ‰ˆŠ‹…€zywxyzvrrtvvutttuvwy||||~€†‹‰†„…‡‡…„„„‚{{||yuttuuvvvvvvwxxz{||{~‚ˆˆˆˆˆˆ‰ŠŒŒŒ‰†ƒ€~}€}yvuuuvvussttvxyzzzyy~‚ƒ€„‰ŒŒŒŒŒŠ†~|||{xuuvvtsrrrrrtvxxxy{|€„‡†„†‹ŽŒŒŒŒ‰†ƒ€}{zxvtsuvtrqrrstuvxxxx}„†‡ˆˆ‰’’ŽŒŒŒ‰…€€€{vtsrrrrpopqsuvxyzzy}„‹ˆ……ŠŽŒ‰†ƒ€~|||yusttsrqqrrrruyzzz|€…ŠŠ‡„ˆŒŠ‰‡„~|{ywustuvtsstuuvxz||{|€ƒ…†‡„ƒ‰‹†„„„}~€~zvvvvuutttttvwyyzzyy}„„„…†ˆ‹ŽŽŠ‡†„ƒ€~|zwvvvvutssstuwxxxyz|~€ƒ€~„ŠŒŒ‹Šˆ‡…„„„‚{yxwwxwussttttuvvvvx{}††ƒ€†ŒŽ‹ˆˆˆ‡„‚ƒywxxwvtssstuuvvvvwxz}€~~ƒ‰ŒŒ‹Šˆˆˆˆ…‚€}{ywxzyvssttttvwxxwxz|~€€€€ƒˆ‹Šˆˆˆ‡„€‚ƒ€}zzyxxxwuuvvvuuvvvvwy||||€‚…ˆ‹Š‰ˆˆˆ‡…ƒ‚€}{zzzxutssstuvvvvwyz|€}€…‹ŒŒ‹‰ˆ†…„„„|{yyzzxusuvvuuuvvuuw{|||„‡Š‹‰ˆ‰‹‹‰ˆ†…ƒ€~|||zxvuuuvvuuuvwwxy{|||~‚‡‰Š‹ŠˆˆŠ‹Šˆ†ƒ€|{{|zvrrrrrrsttssux{{||||‚ˆŒŒŒŒŒŒŒŒ‹‰‡ƒ|zyxwvtqqrrrqqstttvy|~€ƒ†Š“ŒŽŠ‡„{xxxwusqpoprrrsstvxz~ƒ€„Š‘“’ŒŽ‰„|{yxxxurqrrrqqrrtvyyz|~€ƒ…ˆ‹Š‰ˆ‰‹‹‰‡„€~}{zxxwutssttttuvwxxz{}~€€‚ƒ†ŠŠ‡„…†‡†„ƒ€~|{||{xvvuuvvvuuvvwxy{||{{}€€‚ƒ„„„†‡†…ƒ‚€€~||||zyxxxwutttttuvvxyzzz|€€€„‡‰‹‹‰ˆ…‚€€€}zywwxxwvtttuvvvvwxxz|~€ƒ‚€…Š‹‰ˆˆˆ†ƒ€~|{yxwvvvvtstuvvvwxyyz|~€ƒ„„„†‰‹ˆ…„„ƒ€~|||{xwwxwvtttuvvwxxxxz{}~€€€€ƒ†ˆˆˆ†…„„„ƒ€}|zyxxxwuttuuvvvvwxy{|~€€€„‡ˆˆˆˆˆ†…ƒ‚€€~||{zyywvuuvvuuuvwxxz{|||„…‡ˆˆˆˆˆ‡…„‚€~{zyxxwvtsstuvvwxyyz|~€€€„‡ˆˆˆˆˆ‡…ƒ‚€€~}{zxxxwussttttuvwxxz{|||~€ƒ†Š‹‰ˆˆˆ‡„€~‰||{zyyxwvvuuvvvvwyzzz{||~€ƒ„†‡„€‚ƒ‚€}|{zzzzxwvvwwxxwwxzzzz{||||ƒ‚€€€€ƒƒ€~||{zzzzyxxxxwwxxxxyyz{||||}€€€€ƒ„„ƒ‚€€~}|||{yxwwwxxwwwxxxxyzzzz|~€ƒ„„„„„ƒ‚€€~||||||{zxxxxxxxwwxxyz{||||}~€€€€€€€‚ƒ‚€}||||{zxwxyzywwxxxxyzzzz{||~€}~€ƒ‚€€€€~||||{zzyyzzzyxxxxxyyzzzz{|}€~}~€€€€€€€~}||||{zyxxxxxxxxxxxyzzzz{||||}€‚ƒ‚€€€€}||||{zzzyxwwxxxxxxyzz{|}~€€€€ƒƒ€€€€€€€~||{zyyxxxxwwxxxxyzzzz{||~€}~€ƒ€~|||||||||{zzyxxxxxyyzzyyz||{{{||||||||||||||||||||||||||{zzzzzzyyyzzzyy{||{{||||}~€€€€€€€~}|||||{zyyzzxwwxxxxxxyz||||~€€€€‚„„„„„ƒ€~||||{zzyxwvvvwxxxwwyz{|}~€€‚ƒ„„„„„„„ƒ‚€}zzzzxwvvvvvvvwwxyzz{||||„„„„„„‚€€~}|{zzyxxxxwwxxxxyyzzz{{|}€€€€€€€€€}||||||{{zzzzzzyyyzzzzzz{||||||||||||||||||||||||{{|||{zzzzzzzzzzzzz{|||{{{|||||||||~€}||||||{{zzzzzzyxxxyzzzz{|||||||}€€€€€€~||||{zzzzzzzyxxxyzzzzzzz{||||~€€€€€€}|||||||{zzzzyxxxxxyzzzz{{||||||}€€€€€€€~||||{{zyyyzzyxxxyzzzzzzz{|}~€€€€€€€€€~|||||||{zzzzzzzyyzzzzzzz{||||||}~€€€€}|||||||||{zzzzyyxxyyzzzzzz{|||||||~€€€€~}||||||{zzzzzzzyxxxyzzzzzz{{||||||}€€€€}||||||{{zzzzyxxxxxxxxyz{|||||||}€€€€€€€€€}||||{zzzzyxxxxxxxxyzz{||||||}~€€‚ƒ‚€€~}||||{zzzzyxxxxxxxxyz{{||||~€€€€€€€€€€€}||||{zzyxxxxxxxxxxyyz{|||||||~€€€€€€}||||||{{zzzzyxxyyzzzzzz{{||||||}€€€€€€~|||||||{zzzzyyyzzzzzzzzz{||||||}~€€~}||||||||||||||{zzzzzzzzzzzzz{|||||||||}~€€~}|||||||||{zzzzzzyyyzzzzzz{{|||||||||~€€€€~}||||||{zzyyzzzyxxxyzzzz{||||}€€€€€€€€€}||||||{{zyxxxxxyyzzzz{||||||}~€€€€€€€~}||||||{zzzzzzzyyyzzzzzz{|||||||||}~€€€€}|||||||{zzzzzzyyyzzzzzz{{|||||||||~€}|||||||||{zzzzyxxxxxxyzzzz{|||||||~€€€€€€}||||||{{zzzzyxxyyzzzzzz{{||||||}€€€€~}||||||{zzzzzzzyxxxyzzzzzzz{||||~€€€€€€}|||||||{zzzzyxxxxxyyzzz{{||||||}€€€€€€€~}||||||{zzzzyyyzzzzzzzzz{|||||||||||||||mirrormagic-3.0.0/sounds/snd_classic/knack.wav0000644000175000017500000000343013263212010020727 0ustar aeglosaeglosRIFFWAVEfmt "V"Vdataš€€€€€€€€€~~~€€€‚„‡‰‰‰ˆ‡†‹”œˆmRA00SwqN*R‘…iJ9m¡¾¼»¬—ƒ˜®»«œœ¬»½¼º®¡œ«¹¿¿¿³¤–އР¶¿¿¿žx\‚¨¿¿¿¾¾¾¿¿¿¿¿¿¿¿¹±ª²º¹¡‰Š ¶’]-Ml…‹’\8HaudRC6)9XwR%/WfXJ=1%'(+4=BDE2)QeL2$2OgM4 .CYo{L!@i’a+ 7f€„ˆkC7UeUEMj‡…|sokmz†pCF†¼©•|Y6K~±›€l|Œ‡~…œ…xiZg޶´¥—‹y~‚ˆŽ“š ¤œ””¢°£ˆl‚ž²¢’Ž™¤­¶¿° “ˆw‰¤¿°¢’{eo“¸³¤–•”–› –ž°¼¢‰yxw‰£½³¦š“Œ‹Ž‘®¿° –šš’Š–ª¶¼²©Ÿ•Š‘“‹‘¤¸¨…bs‰ž«¸«}Oa½»·¯—œ¸©r}‡”—šœž—‡s`^~žªªª•}jkmy—µ¦\mƒ•–—‘ƒvsss‹“ŽŠ„|tƒ—¨ˆi\w“ŸŸŸ‡kVyœ¤€[h‘¹¡‚jnqzŠšxas†‚ssŒŒ‰…{pm{‰•Ÿ©pUdt„”¤–uUh•Š€zzz}‚†ƒ€}zxuqn–®ŠfPcuƒ‹“ˆymx‚…ymnv}†•„smv€~|}~~~wgWiˆ¦”qh`eu…ƒ{uz€~|ztnky†Š|njlmt|€yqnpqx‚Œ‚xpmjq‘Œ€tkccr‚†|||{tmlt{€‚„ucWj}‡ƒ€vi]gs~‡}mpy‚yokqw}ƒˆ€tj}“wZYlˆ’}idxŠzjpx}|z|‚ƒ„„q\SoŠ“ŠsdVpŠ˜†uje`qˆ›Œ}sssv{€zsnv~€zu{„އxndi}’’‹„zpm}…|„‘›Šxnru}ˆ“Œˆ‚{wvtwz~†Ž‘rp€ˆ|wsss}’¦˜€jou~’¥œ{Zg“Œ…‚„†Š”އ€}xs–«•|m|Œ†|‹”„tp‰¢¥“‚{vsƒ’˜…€~…“Œ…ƒ†ˆ‰‰‰„~}‰•–Š}‹”Œˆ„€…Š—œ‹zs‚’—•”‡xmЧ¯’utƒ“””’†zw‡†‚~Š—‰vr~Š’”Š{~†Ž•†ƒ‡‹”€sv{”¨ªupv|‡“™ˆww‹Ÿ—„rz‡ˆ‰‡…‚„‡ˆ€xxˆ˜š“‹€tl}ޖކ€zt{ƒ‰‰‰‰‰‰‚yo~–‰‚{s~Žœƒywuzƒ‹ˆ…‚~}ƒ†‰ƒ}y~ƒ‡‰Š‡ƒ}|~‡ˆ€€€ˆ’Š~~~…“‹‡‚~€†Œ‹‰ˆ‚}|€…ˆ‹Ž‰…€~€„ˆ‰‰‰‚|y‚ŠŽŽŽ†|t|„ˆ„‚‚…‡Š‹‹ƒ{www•†~|}~~ƒˆŠ…|||ƒŒ”ˆ|v~†‰‰‰„{ƒ†††zsw}ƒ‡Š‰‚|{||}~€ˆ‘Š„~xs}‡Œ…}}ƒˆˆ‡…ƒ€„}x~„ˆ†ƒ‚‚‚~xrw|†‹Š€vy‰…}|z{}~…‰…‚}{{}|yx€‰Œ†€{wrzƒ‰„}~~~~~}|}„ƒ~x}†Ž†{~€~|ƒ…}{|~†Œ„{tx|€„ˆ…€z~ƒ„~wx…‘Œ‚w{‚…ˆ…}uyˆƒ~{~€}z|~€ƒ‡…ynq}ˆ‰‰‡}tqy€~†rnw€„‡‰yv~‡ˆƒ€~}€ˆ‹}pv‡ŒŽ‚vuzƒ†ˆƒ}}}†‹†}|z}„Šˆ„€~„ˆ‰‰‰‚zt€Œˆ€~~~…‘‰}}}‚…ˆˆƒ}{~€ƒ†‰ƒ~|‡‡…ƒ€}{‚‰‹„}|‚‚‚€~€ƒ…ƒ~z…ˆ‡†„~€ƒ†††…„‚‚‚‚‚‚ƒ…ˆ‡ƒ~‚Š’…~~~ƒ‚„‡ˆ„€…І~w~„‰‰‰…~w|‚‰†ƒ€~€ƒ†ƒ€€‚€€€€‚…†††„{~„‰†„ƒ„†„~€‚€~ƒ‚‚€~~~~…‰„{~„…†ƒ~z…ˆ…‚€€€‚‚„……‚~~~…‰LISTJINFOISFT>File created by GoldWave. GoldWave copyright (C) Chris Craigmirrormagic-3.0.0/COPYING0000644000175000017500000004307613263212010014366 0ustar aeglosaeglos 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. mirrormagic-3.0.0/CREDITS0000644000175000017500000000415313263212010014344 0ustar aeglosaeglos Rocks'n'Diamonds contains a lot of inspiration, ideas, code and contributions by many people and projects, which are listed here in no particular order. If somebody should be added to this list of credits, please let me know! ------------------------------------------------------------------------------- Special thanks to Peter Liepa for creating "Boulder Dash" that started it all! Special thanks to Klaus Heinz and Volker Wertich for creating "Emerald Mine", which took this kind of game to a new level! Special thanks to Michael Stopp and Philip Jespersen for creating "Supaplex"! Special thanks to Hiroyuki Imabayashi for creating "Sokoban"! Special thanks to Alan Bond and Jürgen Bonhagen for the continuous creation of outstanding level sets! Thanks to Peter Elzner for ideas and inspiration by Diamond Caves. Thanks to Steffest for ideas and inspiration by DX-Boulderdash. Thanks to Guido Schulz for the initial MS-DOS port of the game. The native Emerald mine engine was derived from Emerald Mine for X11 which was developed by David Tritscher as a very compatible Emerald Mine clone. Thanks a lot for this contribution! The native Supaplex engine is based on MegaPlex by Frank Schindler, which is based on the Supaplex Speed Fix by Herman Perk, which is based on the original Supaplex game by Michael Stopp and Philip Jespersen. Thanks a lot for this contribution! Thanks to Karl Hörnell for some additional toon graphics taken from "Iceblox": The penguin, the mole, the pig and the dragon. Thanks to the composers of the included music modules: "mod.apoplexy" by bee hunter/jazz, "mod.chiptune" by 4-mat/anarchy and "mod.cream_of_the_earth" by romeoknight. Thanks to Christopher Clark for the hash functions. The random number generator was taken from the GNU C library. The networking code was derived from xtris. Thanks! Thanks to Francesco Carta for the comprehensive Rocks'n'Diamonds manual. Thanks to Niko Böhm for the Rocks'n'Diamonds documentation wiki. Thanks to Simon Forsberg for being the moderator of the R'n'D forum. And not to forget: Many thanks to all those who contributed levels to this game since 1995! mirrormagic-3.0.0/conf/0000755000175000017500000000000013263214150014255 5ustar aeglosaeglosmirrormagic-3.0.0/conf/gamecontrollerdb.txt0000644000175000017500000013473713263212010020351 0ustar aeglosaeglos# Windows - DINPUT 8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, 6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, 4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, 25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, 4c05c405000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows, 4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows, 4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows, 6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, 4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, 00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, 00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, 28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, 8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, 79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows, 4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows, d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows, 4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, 83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows, 10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, 49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows, 4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows, 0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, 79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, 79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, 2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, 300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows, 10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows, 63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, 02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11, 341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows, c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1, 100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows, 79000600000000000000504944564944,NGS Phantom,a:b2,b:b3,y:b1,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows, # OS X 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, 4c05000000000000c405000000000000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X, 4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X, 5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, 4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, 8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, 4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X, 83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X, bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X, 79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X, 5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4, 5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4, 5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, 050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X, 79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X, 2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, 351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X, b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X, 81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X, 10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X, d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7, 0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4, # Linux 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux, 030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, 030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux, 050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux, 050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux, 030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux, 030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, 03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, 030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, 030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, 030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, 030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, 030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, 030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, 030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, 030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, 0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, 0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, 030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, 030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, 030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, 030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, 03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, 030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, 030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, 03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, 060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, 050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, 03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a3,rightx:a1,righty:a4, 03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, 05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, 05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, 030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux, 03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1, 050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16, 030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, 030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1, 030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7 03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3, 03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, 030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, 03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux, 03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux, 03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux, 03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux, 03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, 03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux, 030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3, 030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4, 03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux, 030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7, 05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1, 03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1, 030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5, 03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5, 03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, 03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5, 05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, 030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux, 030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, 03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5, 05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1, 030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux, 03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5, 05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5, 03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1, # custom game controller mappings 756e7520636f6e74726f6c6c65720000,SnakeByte GamePad,platform:Android,x:b2,a:b0,b:b1,y:b3,back:b4,start:b6,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a6,rightshoulder:b10,righttrigger:a7,leftstick:b7,rightstick:b8,leftx:a0,lefty:a1,rightx:a2,righty:a5, 030000000b0400003365000000010000,Competition Pro Joystick,platform:Linux,x:b2,a:b0,b:b1,y:b3,leftx:a0,lefty:a1, 416d617a6f6e20466972652054562052,Amazon Fire TV Remote,platform:Android,a:b19,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14, mirrormagic-3.0.0/conf/setup.conf0000664000175000017500000000155513262507665016313 0ustar aeglosaeglos# ============================================================================= # setup.conf # ----------------------------------------------------------------------------- # configuration to load Rocks'n'Diamonds binary with "Mirror Magic" settings # ============================================================================= program_title: Mirror Magic program_copyright: 1989-2018 by Holger Schemel program_version: 3.0.0 default_level_series: classic_mindbender default_window_width: 640 default_window_height: 440 graphics_set: gfx_mirrormagic sounds_set: snd_mirrormagic music_set: mus_mirrormagic # hide some setup options not relevant for Mirror Magic team_mode.hide: true input_on_focus.hide: true quick_player_switch.hide: true prefer_aga_graphics.hide: true sp_show_border_elements.hide: true small_game_graphics.hide: true mirrormagic-3.0.0/graphics/0000755000175000017500000000000013263214225015133 5ustar aeglosaeglosmirrormagic-3.0.0/graphics/gfx_classic/0000775000175000017500000000000013263214225017422 5ustar aeglosaeglosmirrormagic-3.0.0/graphics/gfx_classic/RocksDC.png0000644000175000017500000010264413263214224021424 0ustar aeglosaeglos‰PNG  IHDRæ$ȨPLTE™™™wªÿówªÌÿÌfÿ]]]™DL"ª™™nLÌfL333ÿœ|fùÌ̪ªªÿÿÿfˆˆˆÌÌUf3nnn™™ÿÿÿÌLLLÿÿDDD»UÝ™ffLLÝÝÝfÿfL3ˆÿ»»»ÿy;|Ñï` IDATxœì} c¹Íí(™U#×(qý¨¿ÆÝåV‘oê­XÒÿÿgwð€9²¤ØÉ.[g%r4Ãs‚àC]’s½sÅËÝ0ø°† Ö0+X¾ü~îµ[.g³å²ø˜e¨Á^-î3ÔáYãúÅí=¬ªiÒÂÃe†úðÉ× yÙÆº®†¥z¶°!Õ0ÿa S)÷SÃxÙþfµº¹¹™LnûNMîvrëSoqÔßö³º‚ú[ëâ>ÝÞ<< ß^ Ó²Êz7#®&,ùû§©_U0Á» õuB^¶0x¤ –êÙÆú–a3¤Ê¾³†±çX‘ªTYº]Ý܆¤“x{³šA²0d¹1ÁÉ$K}fdàðàÞ,"ÿÜ üêÈ$𯛀žòï0‰îkâù>RÀÀÿ ª/€A|ðóaHPQ³ôùO…ŸáÁ}ëÒø÷ H&`²à@1«Åà ¹ `© ô+ο4cYoÞ$ /‰ °p@ë/ˆÌB‰ûÞ•5aYž¥޽´…ãm˜xxOO˜ð.€ÉÍ0(¼ Ñ î Õ Ààyõ)tÃ<õ ÞO,k¸Ñ#@<’\ z€•U¤XwgQ„ø½!öƒ/ßp@4l"¤ ¥®ó샅s hå¥ Ðñ@¿…Ÿ¥Î\ÅiWð3ò±Ô¤FÏÞ-Qi psK^±|ƒ>  ÿê}ÀMMÞÿ[i^`rȫЬ8ÿ,ò€€üG $@6ßD¨ M=¨Ÿq HüL$íú™þ3õûé-Øø™yÿô#>F«XMF `¸ä¾ÀøçS?7 €H?(à‘¼y“}­‚¸Í«_Å™$^&íúù *NnÀÄk÷¯áuÌ^JÔ ¬ €ó/æþndÆtö.ùj1J! Ä9ÜG, ËK)׿nßß¶øžp3N7{À-m;šúÛAO$½a ˜PÖ‡*&Xʼn ç}pÙðòeR\_tAå÷Ÿ5pÞ  )f0'€ÉHô£0¹50ø´¾ xʤûÉ Lÿõ'Š÷á\&Nœ8O—xéDÊòÒ -¯oŽcU'}€^\œÿàF à\@¢ŸÄÔa±¡ê0LÇó0ÎÂ?¨×/‡‘¢|1 -®/†±Ê÷³a `ÝmMÈñ.: œHèÃÀÉHôL·u0pþÓ0$CÁ‘~:PRhýuJ ÆÄ?h±Ú2$qy¢¼D)×g@ý~bàÖõ”ó•|ƒ´­ïôåøvœn-Ü0L¸ÒTÀ}‘ãTœzzÊ‘À§ Ìse(•ÕŸеñEf/8•ˆZÞŽcuJ(8a·¶‚‘ïoTPýì1€Js'—d€ ÀIQE,HÀù?›àYé£3<6ðׇ³GÐË'û–qfVâu `r3)À¢õ³Ø8üÇÀÄ®Zà?^Ì‚Ü*à“A·Bÿñs˜N•õ÷“àg×a:8óÏLÀMß$®úI$~‚qàr:8 `¹¬L›>:>Œà Bb€Ñ`u:ø– ò?f=À+_°qh¼ã& 'º d9¹)ÖÈ!CÐ^à–Ò ë&RÚ‚`c¿·D‰ÿ­ð:—lGZèT`âŸPåûîú’07d±&P.õH‰. ëÓ‚¯˜Ê%a³bIØm@æÄ’°í–Pþ|©‹ `X­Dgíp£- Œ€mÈ¢ÐeÓRO¦ƒó€ ÀùßZõ%Ô‡ÈÓ^–~Ø{ŠÄP À+A(àVÜhüwî¶¿÷¯Â¿ß;dí ZBãठ<0þÙ²ð[¬±[ÊðVËÂ[›(‘§µ1åÐ÷”˜™L’‘hCBÛ¿h,:/€¬³ÐÛ[Ã&û~=ØS‘="˜0~oýVª[Æp{cˆ¨"QM®olíJ€‘§µ%K~ß¶yZ[ÃjÏæzÒiÅYǤ“ˆ ˜Õ¶†¹Â½# ·†ÝÌŒ1dÜ6aw^n{Îÿ˜­a­Í™Í 0ò´7eòïÛ6OkshíÙüKZ÷ú‡4 07‡Î|ë¯né­;¤Û›‡›[‹ÿ¼9” Lx¯·œÿAiÛžü5êÛ³ùÛ2OkË5¾{ž­¶—ÿ€ÛÃüö-<_éÙûê]“ sx>@ë €ÚÅö{>Àßß_\¼ÿ»ñ­>½ñ¾øû*Þµà‹Æõ/äꉅV°ùÝj8– n˜gW3Ýá]¥ W°Ít!Ó„«÷ZÃøu/î ]]Ý_h5Ôu_î¯î}29º¸¿Rã‹{ëâ>Ýß-÷1à÷p‡W_è%ê@LØVú˲çl9h3ä%(F`9jR¦§`T-GóÂS“ÊÒýÝÝ}H:‰C† H¶†,w&x…ûB,‚ò§i·Š’`ñ(û  B´±N~Ó!—¼‚Ž•òà—äòP‡q®6 Ï×:èüª@ú=¿††ö í¿fƯî¦þv|Qpq‡ x'BˆA«Ùˆ‰lÆ*•}÷–tr —9x@†ãe°ÆU°\ÞU/âï@2 Áÿè¿ÿ* ¸[\ Ô{ Øø¿2 ÷ÿ øû2$ þ% #€š}¨ó_´}j·Ï ÁÔúöÖý5¯ügú£˜vÖS (à~±@þ/†NÚR€oå¶6âæÀ/_Š«{þc°ð ˆ9°_×@ELúdI®> §•«–w ¼qý~çëçü_‰Ä0°Kø¿÷Þ ä8€šîL\,¨¤ xOø\|yO ({r³­¬éRÇ«Oà}[â={._È»Ä5þC{u•Û!xç÷÷T¢‘PQ€çXG®2ÿŠ ¸ ü{\E‰DÏ^¦ÉŠ À´YP1iAEZG‘êÏÂ#žø9PùæõÙý§!‡ü/H £î3;`îˆ}&àð%¤í°àà @†© °†vB–}`ü³%UyÍŒ õ§ïÏÏõ«â„w ¼uý¢|\Ò–îßœ, Kø]0t(L@0WÄ&` Å ‡_.ŒÑþÂÀû$€;»À½7I ðú>ä-Ã>D”‹*óš)í§z>@ê?>”ñlŸ‡‡ å¢Ô€÷²|\Ôª–'‹B# @!€l¢ÀÀœÄ/Ø\”^\CÉh¸+pŒÄx询ÊeÕy͹,›éƒ5P†§lœÐk¸ÿ.y}ã|yýÔÆ™>#N–…Gü>ó}•»xf|ƒ ¤‡N¾pï¢|0ø½éxæ,`±@ŠË>à}$=º'¤Ø“Ô¡$B9 á×úùª xÙÀùùEy¼ ³|xOO˜¯ ÀÕ]á F0T7¸€t$8¼¡ÝAà‰¯z¦R@s 07ðbŒøÎÑò³ Ñ@Øþú„SPÜE¡ž °À4ò|Qþ,uæ*N›¸rý3òñ÷u¼G\i }@!½xžî4„> %¾–´ü¬‹òú!ûëƒHåë¸u>@ìA¬óœþ|>@$óO®ï$ÎÏèYùü€ç £øä} Š¤î®‚`` `¸ä.n ¡?í3.eÿ<€v>ÁÕóèƒ'>ÆàôçòNx­_ߺÿ¢¼À/¨¸˜œ"€äZˆNà³@HHNàxÐÈöY­cŸ œÀÂ$>‚*2N·Ï`-˜ P–Wï¿"Àÿ«@í|*í|ŽÎ}ó|€ðýÆù”@Ñ1@ð«ãÊùï3ÝyÀ»€8Pp…€1@EW5`ç¸P‡[ €Fÿ´Ïä(K'¥Q"U€‰çtÄÉÌ©,_:‘Ì0Ï ÷¯cÙó1'}Åõ˸gHÞŸ)€0x¦ˆPg‚¶@O’öYÇ!Ã(P‡a:.ÎÀ ê0—/‡‘"ÎT C‹8Æò8@Æï«ˆh ~Ú•€> ¼)€ &€û@“ö™Há±ô2câX¬µKÃa2œý|€lD ŠÏ”,õþˆ‹øE å!€]Ý…@P” ûÐàD€)€{KwLW\!‡!(4.Ð ¡ØJå±ô2kã>ÔË ¼4!zy*‘Œ÷ùþµ8ÖŒ™õ|€ûf(øâî® ö2 –Ë ry&oG˜<”Pð¾"±/(&Sx,½œŒ‹³É Ç›xny:™HA¿¿dßÈõ/Ú“AWw­É  ìZ“AW–ød\W¨LÝm;4Ñb‚©z{9*ëÿpx—Œ´…»ZùÖýsüìZ9 ˜€4 sd:øâ L@ø@1SïÍé`Óèp’7̦ƒ³—òŒéà _¨à…|d†M¼¾ c×%Ù¾`jÆïQÕ!Ã'í!²ç Ò ë®¤´!ŒhÞ¾YÇAåŠÀ(›Æ’*:fxÞµpr ÏÂ÷ßøþ{fÿóX€puÕXö¦ ›kï-Ð%aiÁWLå’° ¶$L¶oÚÆ[KÂØ¨pÿ©uý®q­[l=@ëñº¨&»;ÑYCøÿ‚ð_. ½!ÛÐqÀE¹*ø‚øyЙ훴ñæš@V]•eÙz½‚ɲp“ÌS@±9¥H­eáùãÚù÷WT¸I€3€@W!R¨, ÿrï7}©ò{‡ è}êþË x`¨ñ?jY¸¾jø6 €V¼gÕ$ëLæÑêo ±$‚yº ÃæftN`}cˆÓï›”GfH$àJÛ’½Ã{}cÈØæã\Ø[î¢PV…w¸1$L^Œ€½?” ÀÜ~U= ¯l sôZEžŽÝÃþÏèºú¹‚‰#hœ†*ƒ¨€êÖ°/…{GÒUè #·†]1Ánß±OŠÃ$UbWeÜ€_ÛÜéR>5ûsïÿ˜<Ï;C Ý…‘‡ÖplàF#½°7‡úÖ_ߪ·îîýÚ3‹ÿ¼9”}¥}ÃSÒ XCÆÖújžd<xuyðn¯µïÔÆCªm—WÃd{ªVx‹ ³ÜÎ(O2øùÎðéê~>¤ÿYïé§Ò)¦“îÿ®šÞ–Y®u‰²»—ª¶Ï¨›wnÎó|'€û¨€ÿÉ;T,WÁHÕÕ°€WœHWŒAèwæ¹ ãìÀm ÀxŽ„ÿ¨ç@ÁQ0?7†X¡nTŒPbch-,~‰á=˜X/-„qTAeˆHðÞ%w€9Ân WÂH¬Þ'°À› &Ê+—-„%ãZ(=ä|>Þ0[Nhð©'UVÕÔ Î*¸!IP-5OØí¨[Âÿz>F¦‘Ø{%5@'Fâd ­Ç5Üç¨ã}_ÅÝÎ×w­ëw?øùžÒHì\I[€N—j¸@‰s‚4œtˆò ñ‡>`w„µqâ²L<´Ðî Ø w;^_–O BˆâÞ Æï•v>@Z¢,ÁÝ¡ï BªçDvóˆ6‰ ØY´~è’ª¤€Œ³%Y¹+x0â6îv,Ÿó†Ý¼yý¼$,€¸”Xü;a‚o½4ŒóÞûá¶ŸÍyÎù8 ú€ò|€«÷á³=`w`ý”‹*sp±(“óS.êŒUñfy§àg¬’x\ÔÊù/…JP < p‡ÐÎxKˆ¿<ï|\  <€äú/èùÿR$ö¿J¢U àþ*®+—U³ö­ül«ågßRœ¯_à®ëTœ4ñËÒë§6®^Ÿ, Hî}Eç aå|€‹´.Ï:àýâKØúŒóî¾' <`èöÓÊðÜ )«¥{2,0<4Ö¶±" árc탱QòÿÀRj¢ ~FšxYoÃ,ž!™0ާ'Ì&.í ¼-Ÿøü|€ ¿O<»Êùïï¾<ÿ|S¸1Ä @[XÍ©‹±`:ïí»ßFDÁ&B|€Ôu’­YÔ†_+[»¨  †§­eâúŒ³DÛ\ÊËsþÃõ]§à±‰SFÛª €ŽÊÍ¡°ÿ'DƒÕÝÁïï¿„#bž±;øîKXóe Ü×V¨§ä#+Ä|h^ýIŽàb{·ðá‹T”ÛË©¡mOç×·náT©Æy( Ñ{û€ˆ÷š{æw_¢¨nOCÿÅ~|$Myœoúhƒ@RÞ@OÊëb׿.jß?ñaö*Ú¸ºú¡ûHÅ„’>À0Á¤ŽxaÂclu±¼Ö…ˆï—]í㿹 `÷§t) ˜Î‡¡à]@´ÀŠps(SÀUM°$ l³ÅÃHc¿ˆ}4¯¡³¢ç 0qîÄ)xº ÷4'’ú ŠÊúxʼn•åi†„—çÜhç\T«ž+\l P¿\l)€@Êi” ùú0JÃÐa˜ÇáÃ8-Σ]_Fò8N1 %}¼:Œ-ã@Ú0°8€   À8ðÌó‚ìó¶ à €Æ þ}#’cíz &ÏX¥¼0/I¤×Q®ãß/ €r¥Ë;É ªÅóÂD@Œ*çÀL@EÕó€à‹°9°< 躀¼9äJKd}ûp¡tÝÑ»ÐFôPjnãF(Ö•åiïS¬^ÇsÖp:q¦†¢yyi”ëóP07v(8žP ‡óÞCÐÀWÏÈsêù|. Fµ5t}]ÿW àý‰•j“)ù÷åÍÉœ*®ÇŠžm´†þG•g ß_²od²è¢=ÎH”“Aá|€÷Y´'ƒ®,àdP¨çȹ€<$bß®¯H~R6tºõ€¸«¿kߟÛ?»fÓÁ̤Q@\|Wœp‘m¬q>@ÞŠñ Fš]xE›0W@½|)¼\@\s³TTZGñsásü#x (PÆÿËèNYŽËKFp¥¼ÇI!–/6ñUÉP¢y?&nëå£p«F=æú 5U¨Ô‚¯ ]Ççñ_‚G›L{N‰ÝK= QˆYøW0´©…sþü‘¡èº;‘!·ízù˜IчËüujXIZó{Ê€ŠoH:(>V\Çá),<>"ÁŒÊd¿ŠŠò5Üç@ËÞM9CS èÒe㽚2Ч.QÛ(™¦ ÿ½Lüw¤}„Šâ6t@D”8‘‡^~3÷ßeâp#&žÚ¸ŠÏóÿA¡×·PæõWÊ×ð €À/g¨‹ Ãþo*)¤»]³P$þ³€ „›ZÁ@dJÜ÷®¬ Ëò,Õpì¥-oÃÄÃ3xz„W)®  eÚ8 ¯V”ÞHZü¹wG0ͼY´RJ_@4l"¤ ¥®s¾±p.­¼4:è·ðyêÌUœ6qŸ“ºÀRƒ¿†hãÓÄÊo°àmÍ1%¶Ê; +üÏdñM„ÚÐÔƒÚøœK@ârá¢výLÿ\ý~z 6>7ïŸ> é†ÑXì^§¤z¨r÷;M•Oúøjyó ¿Ì+Mô’vó+G8Tb—…‹Òb PV÷¡yõ«8“€Äˤ]?_AÅÉ ˜xíþ<¹Q©jr¹”ü"˜pÙ)Ÿñ©sTIAÁE/ê:å”àË1å݊Éÿ €à#)Ä|(…€çr±€,/¤\ÿ¾}[⤆bÝ™ g˜Ü*/ÔS^ŸL×w_0¶<‡³ïûHÅ„²>T1Á*NL8ïƒË.€—/»âú¢ *¿ÞÀyû³õ>ž€Ëq¼°cÍk¨è£'Lʼn§ãé2/HY^:¡åõÍq¬ê’>€Q# N ‹ ÔWÊ7LðKwAXGê0ŠØPu¦ãygáõúå0R”/†¡ÅõÅ0Vù~6 Lü;îbYN˜•¡Q^zp…¾^Ö ÕÇQsK-1&¾Ñbµe HâòEyˆR®Ï €úýÄÀuÑp’ }ƃiSdžaµòNªG†b=”¡TVJ(ÖÆ7Ef/8•ˆZÞŽcuJ(8aɾ“P« ÄàG+®€`b[å±VਓžïˆÊ~:ŸLaõÇc½ó׉³GÐË'û–q—ùcüÒP¬šá2wñÕò…ÃQu|ŸP4ñ“²y,ëï'Áç÷a:8}ì¦Ä×öádŠÉ@\¸zyÈ$áà;MF½ô‚Œ—ÆÓtª¦ÐóÄ™Ž%òzŸVùèGð;–øîÓÑJ½ª%[‡Æ»¼ âò)º¼D†Â8+/Èà²êå£L$œU4}É)/½(ó¥Pì—Ýú6z¹‚v |¯.S'ïÂ*ž!§zùlXiÒC¤©.)K”áÛ½,I»ÌáÕáo®UeûÍÓ^–~Ø{âÅ‘ž¾(“e(’U^…ÁBäH@eQ) !ö½(Õ…E©«Æùj5î7O-¢‡½'ÊÓùÍ˲ ò:<¼É«œÞðeéØoìsYºËËÒGlͪníJ€‘çÙçŒÌÓÚV{6ÇõòömÉ_Ú˜aeh”×af"B£ ùÈëX\”9x£Ê—…¨ÒÚœIi…3ö}†@²vžÚ³ù—ü+Þ©¤(@ÏÐ(¯Á¼‹p¡Mæ×öÖ4GãË»ÊÖ´gŸ¾æóØíéy¢ó—É224Ê+0w.]n“ôµv §( YÞÕ/ Yž»¯Þ5I±°p>Àv‡8t5ë÷ú×ùvB»¨šà†yv­. 3±+¢¼# IDATû`W5Ó…<*&\¹×ö—RJýeÙs¶´Æò£°5)ºWÞk ãÏa¹ïûÊÐ,¿«<÷&õTh€6æ/WÁ8Á%†xåH ;‹×¯ ãcëO‘âCõ—µÊ—aefh–Ç+|‹H»J.ãTcÊ[õ㜠Å@Nà –9S Ç]¡(WÁryC¼òx ‡Šón´Qy»fh–{·Ë—Øå«Ô ±US«xó0ØÖõ_Ðx<¿å3¹eÝÊàì Íò” ’Þî®f5¤O–äêÓpZ¹jy×À×ïw¾~ΡãooH‚¿34Ë[½}+àU®•®—w¤zÊéR^}/èÛ/èÙsùBÞþömÁ'h× Íò:ƒ‚BÉßvp#ƒ¯"¨˜´ "­£Hõgá‘Oü¨|óúìþÓ‚‚w)Lb´}5SSÀJijüm72DþÙ’*²f&ÔŸ¾??ׯŠ~TÜ5ðÖõ‹òqI[^óEp²$,?TAt,‚d†"¦&3lYž£º£á®7Ê;°ÆùXƒå¢L®rQ'çïÙxÈP.J x/ËÇE­jy²(”ñßa¬¼ª‘¡TÏP0\-O ‚l%+¦Å5¸UÞùbœÐE!—e3}°ÊðÔ€óz ÷ß%¯oœ ¯ŸÚ8ÓgÄɲpÎÍt\2£LqeVÇkåÝ*®©oµ^ÜZ£¼ëÕ±ÌB9 á÷úùª xÙÀùùEy¼ ³|xOOHï?Ѓ+/òþ¡€ŽÇ0<¯|>ÞA§¨Äåµ^ÜZ£¼l |ÿ|Ä©(î¢PÏ XàNy>€(?O¹ŠÓ&®\N^pwoøÚIû¨4þ\ZÔ1-­4à«g”G~VùEG ÁŽwîAšå@^?lÿ<€T¾Ž[çÄÄ: ÈéÏçD9ÿäúNâü|€ž•ÏÈû²{'ïÄ凅Æød§nÁbq»òŽðïÒšqRâ[„ÙÅÖœN ‚[åõ Êõãˆ@*¸z>cðÄÇœþ\ÞIïõë[÷_”WX¹y)^…öªñR#˜¶)jùì:Ë!Cùòw §gåÑ\–¸UÞ¬ÀÔG:€WΈS@Æéöù¬sÊòêýW@âyw_jGCE’©BÒ€£@¸ÀåDR-ï8ÿlãa£4™…»³›?•¤QÞ2¡ÌPL°ŠÎ}ó|€ðýÆù”@Ñ1@ð«ãúùiűÐ~¨¬¸Êõx©à©^:]@Zy7¥ü]¦‘B&p%•IõpjÈÞðvyÛ‰"6VuÂT¼8 #NfNeùÒ‰d>€y>½mËž9¹(à˜È8©€ ÜSÂ?4´Ëqå™…¾,° -<+SÅóŧ丙vy1Ì"Ã(P‡a:.ÎÀ ê0—/‡‘"ÎT C‹8Æò8»? èŽ)€[€<ˆ&‚ZD9ÿ¥€Œò+¦ ÏÏ$˜Ù¦i)€˜ò`  RÞ ¤ðXzˆ1ñ ‹µvi ‰Å;-Äç Ê@Ÿ (YêýGç¦SIÑ¥Ø[2¥ü‘: ü“ZåñkSÙt/¤4a÷2ê£À½xÉݸòE(6†Ry,½ ÅÚøfS//ðÒ„èå©D2Þçû×âX3f"Ôó¸G¼ ;†A%ú$,ÀB´°Ñå‰2È}¥W>aµüw´rñ_JPœÀ¡·b­ü£ÑùÏçÄ$‘Ió¤"3¶<«.g/ËÖóèœóØü`žºŠÍ)EB°¼ïòþô<¼"u¹–GZ‘¶á‡WQÍòL!—ýù•¡ð þ³+ÍGÜ=Ο¡R¾£UïY5É:“y´zçC,‰`yežòž®º1Äé÷MÊój"ç(d¬Âžk gÊhYäO¦ùX'd2Ükå…ô-¼ù@ðE®Ë[Ö·ñT1ÔÀ%á¸R>W¾¹ýªz>@(^ÙæèµŠ<üö†@×ÕÏP8(Mðjl)[šNúU§´\È“Žk®”/¾¼@ îÅl~$áÈ™òŽã…†[k—ïƒJUâFJöVæ ØÌþÀÞ”9"ÏóÎHwaä)jÚ©›¨c„-eË;ðWáÜ¡¨e7¢¼øvÅÀÑÂä—]±t¾`5¢<ÖˆZ•lÎØÞÞí’ç´ò¤ýïšôeû˜º”ÍPN1Ó¸ò4Ã%, Y•ÊwA‘™ªå•J Ûö-L¶§j…·È0Ëíá쀢£©Üëÿþó9ýûÿÉë¾þ°ª¦Éf¾ÙÍáߣÍ|~4?ÚùOü+ÿ£šd*L'“OÍô¶Ìr­{Š+Ý‹ ×7MxW7ï=rí9|õÿû÷!ýÿýýwNÑË᫪&ý@þ@ô €vPÁ‘u{êá弓TËU0Ru5,à'Òcú.]_wâðú¶ƒG`<‚ Õ?Tý¿þå øöíwÿæ÷?òC|'üÿ{GñdšnnÙÛ¾÷œÏ‘wøÛ øÿAóߌ€1ÄrŒà®àqÈåœÇ\ý˜:—Ë«CÔŽZ㨂Ê1>ä|õ ‚†‰¡ï…SDœ àfÕßrxcïÙž£ïÿǾ`PÀséo f00-°‰…7L”W9.[KƵ Qx¨°»Ä†^o `ãûèP^ð~ã%0oûVÕÔ Î*¸!IP-5OØí¨[x‚ÿAýÿñÇï$ýñ|ø¿—Ç™nV«ž) ïý2ª£ M߀`À"4@'Fâd © Ž9j¸ÏQÇû¾Š»¯ïZ×ÇøûÎýAÒ¤ÇO-<~::úgá-lÐ÷Ÿãôo‚ý?aŠêIU$ q)€çi8%èå¸ Ðó‡i6[.}½: üâ‹Õ6™pœb˜8^VüHœ `àU€@èòƒ Àÿûz…¶ÖEÌÄ.d˜xh¡5ܰîv¼¾,Ÿ„düî+º HþóÿdœÓ?ä¡xAÿ‡âZÍÛ—?5ÿÁ¿Þ ÌG8´~è’ª¤€Œ³%YÙ„Vð`ÄmÜíXÞ{  ]¿~^–n?F0/èçxIèD®Õû8œÀóï@à?7ÿàÂ`p”°~ÊE•¹¸X”Éù)uF‚ªx³¼Sð9ë…$µrþËE¡þ#N0ÿC¼¤Ÿá ý} ‡<}Giü¯%F p„Þþëƒ#º´‘å²jÖ¾•Ÿmcõ¯üì[êƒóõ Üñïg•xX–n\?µqõúdY¸ìf‚þÐ _ÒOq~yjxÀ’nn’†×t0Ž?:>"x´A'pŒ ~´A —3hŒ’oìø†¥ÔD|NšxYoÃ,ž!™0ާ'Lxvñ–F°ñèâeô.ÈíëxÌSÃ}<Ø>€y“º¨±h`Hx„2ðÿ ômD4l"NàTÙDœK 7Az}ÍH’&€<Î7H}´A )o 'åu±ëß—µïß5žO`æ–³™!€´zœå1Ly*Cžq¸íIºaï†7i¼œÀù@ލ&”ô† &}pÄ û`« ˆåµ.D|¿ì‚œ¼Þ…¹òù*pýd²äHðX¬.’'â“N¤§Jðgdp›I÷]@¦ÿ&ƒ€uœÄFï€DX'2Žÿ™îD±>œ+Àŧàé2ÜМHÇïO:¡®¸s«:iøì¥²+$q‚±< ‚—£À(tý8šÇ@$¦æG¸:dl@F©q: Óã8|§Åy´ë+ÃHÇ)†¡NÞ¿Éâ߯ãBDªÞë0-!x”‚â00ÒÈKÁ6¡óÇ`¾= Rr¬]ĸ²|Êb– âe Éñû+QNÜ¿0Êý•Ž I@@!ÓB¤< ±­¼&)x{›Aq¸‡£¿à„PÒ¦BÑC©¹¡XW–§ ¼O±zwÊ÷óJp*µ¼4Êõy(XPéÈt´d-\a!œ¨Yj!$¶µ¬Pð. ›ÇÈOpý›1 ˆåΩžbùh÷\®ÇŠî”ïϸ~vyöúý%û–ðB•³‰!Åz›ô……˜‰ª¥BbûNú…@hø¸Fþ?–ÿΜn= îêßïÚ÷ç¶Äç÷l:X@ )`!!Ïäœ Á ì0¦ƒ7ó¸WƒnÂ[ ŽÀ\4t4”¸öýí¾`ä'@ˆþÇo³ þß|œ0›U´¿%]õò®ñý-ܧ^_öƒ @]ƒh 6óù&¼2Úè«©¹è²±9—E¥ÍE©ýˆûk¦B°,Ä["P. ËP°½ ÷l ´ú9Nç[ |’¶]Ö-òT€7–lwå=ñ<ú}k÷§æ‘ ¬ ršÄª †kO"®Óÿ (ËÂç¸ ÿQˆmâPp; PÛ˜¡çÑ[`mcÏS‘€‹h=zß$‡ùlá㢅Oò’³…‡<Õ>Á%?þO§?Ø`ó‡58x”<À͘­aµ­Y¡‚Í­]. dïûú{–ÃÎcH)m 3Ÿ ó8ÑÂ'tUÑÂSžJ ŸÄe£‚'Û  Üv„Ëÿæ¡Ïë6s\>"PÙœ \ßûßÜúÜ}ýeàDÏÓÚj?äéX ŸðEaj W,„Nc2ˆXï‚&}5áj0 :Ü.!HÁº¶¨{ ¶«äÀëËãÚÛËÿýûïÿÑéwÎcþO§?ãâò)§<<Ý[ƒÿWàB€Øý%Z¢V\Ùfr>@Þ ^`À*¶Í½~ûú9§Óoßäu_ ÿúùÝçÓ!óôuH1׃gA0]£…wu3½Ëù¡ž+ÝL½ jšð*×õŒ¾ú¡~°–†8E/ˆ{ö (³Py´ñª£¶Ëù©žm¬¯a®:z,  úß ~Îÿõ/OÀ·oçPW„¡ï„øàñwï^4ß²ïh*£ìÊ8¾6<ûQ0Ÿ<úª‡ä_Ä ü^8@ÂmìªÁê«a5éüêì.1Á„¡—Åmìªùs$oO±]’ô-|ˆöùEñÁ;P¼@FñN€N– é9=ŸégıžsîI“? TâñÓñø@ô3qìäåWñ¢zÌ*ü9qh€ž? L¼$œ‡ƒ8^ƒ9Þi,¾k oZ€¸æâ QpQÒ:ŠŸ ?Ç?‚wç¾¢µ`°ÿük—ð"Hq-Lñ’ß–qx·û8¿çú 5U¨Ôßy4P¯ ]dzž°lD4ð+2ƒ¸ ¦¸ ¦¸FðH¼;°õ0ÔI¨H`%iýŸRTœöaÅσ×qx ˜ñoÉÁ` q5œq…þ¾†Cž¾ŽiØ€?Ò>BEq: ¢ JœÈC/ÿm<î¿ËÄáFL<µq?Ïÿ XêÊóÀ _ÒOq~yjxÀ×Hà}l ÜÐú "³Pâ§¿´ño,Õpì¥-oÃÄÃ3xz„g¯Ø 6]”B@‰s¹X @–—R®Ú¾¿-ñ,€ò|€,€Y¬K–Ç 0å© y^…ˆ}¤bBYšñd‚Uœ˜pÞ—]/_v!ÅõET~ÿyç]÷”ó’Œó"nP%xÈó*,@ê£y }´â„©8qât<]Fà¥)ËK'´¼¾9ŽU@î¤Áe wÅÎ`Þ­ó/_…À:R‡QĆªÃ0ÏÃ8 ÿ¦^ŸÒ¯~1 -®/†±Ê÷³a ÷ ¨H¸q>€i!Á/nôqÔ¹Œ¥Ò&Ž ÜÄ¿i±Za”òòEùS~Êõ™P¿Ÿ¸NøLŠ ˜"å©Xˆ­p`@ ¥²úSB±6þ­ˆÃì§QËÛq¬N wÒÈ4;2$-=@Z¹B•Zm ó«°ÄOç“)¬þx¬÷üuâìôòɾ%¼€Ëçpü|i!fOÔBHl[Ø?)›Ç²þ~üü4L§Ï¤"x±˜àêîàWa^zAÆKã?ŠhŠ*zUK¶ÿ(ØÁÔ—”½ô¢Ì—N…Èù…Äù Wv'Ü8à»X€Ö¢R^àË4Ò~ó´—¥öžd §çÈ.Ï -ÜZæÿ¬ó¾‹h-+çUäK´(ÙožÖÆ”CßSÑÂÉ’³…‡<Õ>Á%?þÏ:à»X€ÖÆ’[³ª[»`äim-“ß·mžÖÖ°Ú³9.€b‡°ÑÂÙ²Q£…§e£‚'¯Â47g66w&ÀÈóìóFæim­=›ÉZ¸X¦¶pÅBXçT &BÅ»ïdºÎ€_óùìöô†4Õû 8ÚÅgœйVЙ˜ÿ,\Á6Ó…<øýhA阮ù—«*C“þÐxº½Ç§7)==– OýeÙs¶´Æò‚Ž>ú£&å!8…~v?5Ì¿l´%þæiËòáö;*E-ü±È°® B´±N~Ó!—¼‚Ž•òà—äò(¿®K}> ,è©u Ûvø›_ŸjxY>óûË/6C‡Æ-–}µ7öÝ[ÒÉ-\æàŽ—ÁWÁry;T}¼þ•à© ‡3äñ72ƒÀw)_« *8"µŠ7ƒm]¿ñÇë[G±n…4<2´Ëƒ}Öø{ó&Yy—0Çw)ŸjH›,¡Õ§á´rÕò®7®ßï|ýœCÃ_ƒžTþr…þ»ÌAðÝʇ*Ò§KsýéxAß–xAÏžËòxë8ömð‡ATíòÃýMõúæM®U“T¤u©þ,<`à‰Ÿ•o^ŸÝZ’ðW €G•7ÉF?ªí—ã»”ÏüŸÒ%UiÍ Ö`%žëWÅ ?*îxëúEù¸¤-Ý¿#8YðÖO²l{þ½ˆÚåGxHª¨\T™ø‡,er}”‹:9ÏÆC†rQjÀ{Y>.jUË“E¡ÿKH!i¡¢ÿÁ@ÈeÙL¬2<5`ã|€^ÃýwÉëçÈë§6Îôq²,<à‰ ¡B"A“ðãìŒÀ››DàUóåéõkMæ>¾Jp ÷u¤n¬}(1Êù ?ÕÏP ÁËÎÏ(Êãm˜åÃ3xz„‚ü@ê—7¡^…g'{¡‡¬o<úòìú‚¢—Þ‹0¡HêX4¶¿>áTwÑ@¨çÈ,p× \ž ÊŸ§Î\ÅiW®N^èGôñ÷Ù¢@`üwÆÅ¼oJ‡òüú‚Óq~U -äõCö×Ê×që|€ØƒˆÄm¸}>@$óO®ï$ÎÏèYùü€ŠôƒúüûìE@`¤ìIæ7î#òâú‚º ïiáN¯ Äo€v>ÁÕóèƒ'>ÆàôçòNxª_ߺÿ¢¼ÀÑpgR3?ž"Oà û„ç.ð7Oòòúvç¡ÜâfÆ>> @9€ „H|UdœnŸÀZ0 ,¯ÞEÁxz$é)ÿ:{?Ó¼Z±Onxîo”ó$p»‰gþTœMæT¸¡PL(ó¬âÄ„s¡ìˆ ·Ï Š.ˆù‚_WÎLôS&õiÕg¾noÑ„ßæN2?ixµ¼ï"8nTÌæUøm–WÄ €îD«:a*^œÐ'3§²|éD2À<€Þ¿6ŽeÏÇœÀˆx'-Ñ“œ¸H!8qO‰~¯”G'‘áAb¾¾`¸…sÔÊ‹aF‘8€: Óqq>fP‡¼|9Œq¦bZÄyÄ0–DZ¸†i §0L‹ôaP†qO‘~7ËÇa"Å ‚¿E†bIOëlRx,½ Ęø7kíÒ0@€Œ'A? ›ˆâse K½?bàä\ÀÓøoØ8c¬Žr†Ï"þôôTÅò9PDpÀ‚‘¡…+¬òE(6†Ry,½ ÅÚø·oõò/Mˆ^žJ$ã}¾-Ž5c&B9`¡àg…Š5‚´%}4ƒŽ³EuœÂÑ#)&Sx,½œŒ‹³É Ç›xny:™HA¿¿dßþj ÖØ£,¼yõÆtª¬ÿÃá]2Òîjå[÷ÏñóSy>À>§ƒŸ3]\ð£7ošÁÄc#o(ÄZ xž‡èßqÁG¾¯.èØuAÉ+€ç§Bÿ˜ †B$ÜXREàç- káäž…7î¿o|ÿ^—„=cÉ¥âì_×gUzÇä¸þW%‡†RZ×oÝCë[Ðz¼×#€§†}“£•GEYuU–eëyô &ËÂM0O]Åæ”"µ–…çõ<û]¾ý²qÆMÝ~?A†¦F*yôï UïY5É:“y´zçC,‰`yežòžh°¶1Äé÷Ó+ÀÓãc½õê†}&[O%ëÄÜ~U= ¯l sôZE!€½Ÿ!Ðuõ3ö¼5lë­c„Þ.8i†›@-CuDxø¯Rù• ˜ì­Ì,°™‡}¹÷Lžç!îÂȳšôÕth<ÞÕÓSfI¥/d0q´ïüj.àÖújžd<xuyüô‡Æã=eJ5ö(gzŸ%›M.qQq5l‹³ºêå%ø‡ðßÎ(O2h‹ã{§Í|³9šÃ¿G›ùüh~´9òŸøWþÿ‡ÆÃm¦“îÿ®šÞx­ qùÏÂõí³êæ½gBÓ…|ÿ43104Ð, l€x9ß>|‘ŽÃM¨Vn*%Fª®†¼âDºb B¿Ó¥ëgn;xTÆs02NB²È:î9 Â߯§# ê(r¶¼ë œW M.¨Ã< à|8æêÇÔ¹\^¢vÔBGT†ˆ\'$ÕèÛ/î±gÜxÆà_ÿ¡7Ú›}áðU n°ˆ ÌE lbáMå•@ŽËÂ’q-HDp"R¾}âÀˆoŠH"é©„¼aßߥáÏ$8g¨à†$AµÔ<=`·£nmþ%ƒcñÇÇ-ËϽ‘ö¼!Ys`Ò÷ΩeïÇ/+ñŽNŒÄÉZ;6Ž9j¸ÏQÇû¾Š»¯ïZ×üL§SÏŸÁpÄi ÷³ý6W“RØ9‚žÚ‚qÆžýh<>Øø ŽßVâ]Q=©Š¤$.P✠§¢|w™ŸõÒÛxÄ­6žËë 8ÀI˜âÐ"¡%C'„n îémà`2_3h&~p! ÀÄC ­áž€p·ãõeù´ „ Àó³@‚T+ñ €‚aR^U@ G—FkàŸÏÃèÍÛið×Fãx1 Ob$£?­º¤*WOÂÙ’¬\<qw;–÷^‚ÀCCׯŸ—„`=}¬ `ÀO¢u8aøIÀ£†Ó-Cz…Ÿ#Ç IDATy)…Y챡­‹G¡«Cûޏoê ï´4#¬+—U³ö­ül«ågßRœ¯_à®ëTœ4ñËÒë§6®^Ÿ, g8‰ü8Iü³~¾,¯ùy©¼&€yðÊÀlCSöcõ£@ãцâ¾ùÚxjÔÑáã¸B¿ÇC©m¬H¸Ü˜Aû`l”|c‡À¿±”š¨‚Ÿ“&^–ÇÛ0ˇgH&Œãé ‰‰£¼J#®£/sHœæ¡ ƒÈÜ|¼<Ÿc¼~Ž ›à L\¡—àJóºðmD4l"ÄH]'ÙšEmø©²µ‹Ú`ajxÚZ&®Ïø7˳&îøýÓ$ϧñ÷4¤šxÊnáB±KñŒÎ³w· nÛ|ƒÃ5l»ïÐkëtœÓ+qÍ@W6RÛ\Iûms&íãµÍÔŸ*›Ci¢m.åå9ÿáú®SðØÄ©£m¥(éG÷…sL1>Çö;ë9ŽáÞç#xfNÅý%^˜%Š>²RȦæÕŸà.¶w ¾HEy±½œúÚöt~}‹à)ôÙGüÉ x(InáØ£ãÌ ôÞàèƒÇ)Šþ œ @â’ÿ€wÑGÒÇù©6$å ô¤¼. výÓR öýf ·~ñ¬gH@ÄA! Á^:0ꛎÂcd‰‚Á<Æö1f»¡x´í:ÎÙ•¸ä?â]ì#JúÓ>8â… }°ÕÄòZ"¾_vA´ü‚éýµ»€H¿%Ï{| i\ùMðè68w׫}´‰ë8N¹+pFnKþžûh^CçEÎ`â܉SðtîhN$õA'”õñŠ+ËÓ ÄIdÝsæG@Æ×ª/ \?à©ÅA>í!~ƒÆ§l#¼uÏ/qÖº \òß%\£ÐašŒÃÐa˜ÇáÃ8-Σ]_Fò8N1 %}¼:Œ-ã@ía`æß@àÏÀMÅõ#fí7£ø,ôrÞá8 ÓpNok@<ÆÊõ@J޵ë˜<`r”òÂD¼ $‘>\D¹Ž¿0Êý•Ž3„Ýs"°#8¤¡ãŽü)xäW-/ù8¶y\§3!\á…Ã7‰£ß(qοÀ úÃ@"¸ÐFôPjnãF(Ö•åiïS¬^ÇsÖp:q®†¢yyi”ëóP0À‰À´&g(p*€ŒEo}¢¸aÉFñ7£ðج»è'r\@q+Õ&SR,¿íï”ëÃÂõXq³ÖpÂÿ¨òìôûKöMþ@H[þ4<òk”güG|ƒ«tq"7ö8‡‡KøÆàað8Zà¸ÆñX?9Ýz@œð§át.¸¾Û??eÓÁ\'TÓŠ,œ `,[v˜¶ Ãö‚ö»NèE¼Ë8"Þ`Ä»ƒ.¸h,èh,( 8ì‚ÆPå/ã('ëås‘pŽ…•}ÐÍσ]ÿ¶xPUÄáKºŒ‡[Š8©À,骗oûÔÂëKÂØ„ '8øSÎ_ƽ`ãqg—ƒD‚ûµ|¸Øk3AÀyXÙµ‰Kø·Ä;tSÄ' ð]]66çﲨ´¹(µqÍT2â´]§1¸+žãÀ„l¿G8 €k;bç98Æ-<~ñF[,—Po»¬[ä© n-Ù.ï‰çÑï[»?5 Ä0}'Ò¡pœØ N>®ÞÚ„±cß;_ðÑ3ô\ )`6ðY†wËAà Ÿq þ_!]ãaƒèêŽÚ.ç¤z¶±¾†e¸êèU°,€1ÎèYHY‡ÀWÈ}9ø_ª(øàóÛUóçH?’Á±øÛ·[–Ÿðä dï:G>éÅë~Ù±s o=å·ìïêû’ÿA×ÐñÉ–5.[ZÏŒô3⑟¡B<çY4üí[]ˆ¿ ‰â}Ïø÷íº§ï–þв×ý’œLz{ N`8­8¼£ðÎ"Q€À:/]U«ðçÄ#?`ßRœ1þ·Úx.¯+ à\ˆË3rØùë~.“~R¼žˆÞ °wmÄ5P1ÇC‚ŠJë(~.|ü, ÕÊG< `˜”WPÃ5©î3ExêUÐú 5U¨Ô‚¯ ]Ç×ñ_‚‡ú¯ë·5 øYÀ[ûVkâ¤ü‹àº&€³ÄÿP'¡v •¤õ·~¤ ¨ø1IÅ×ÁŠë8<……ÇG$88h>>ö¶ÀYäð³,€·þö­¡€T^ Àã<úgÅmüÍþmüÚ JŸP/ê´PQ܆ˆhƒ'òÐËÇýw™8܈‰§6®âëüßÄ?xè‘?Cg‰ÖÏwEyÍÏKåuä蟬à$ú§ÅÛ€zÀÂM­¿` 2 %î{WÖ„ey–j8öÒŽ·aâá <=aÂãím‘"ƒ6šñ2‡Äiª° þ­hÀ‡Æ+ø-‰þyúù'“ëéÃÀ €Øˆ‚M„´¡Ôu®-œK@+/M€Žú-|:s§M\Á×äEÄ4þþ1¤šøšÜÂ…b—’PÖðýÓãm@=È⛵¡©µñ5—€Ä×"i×Ïô¯Õï§·`ãkóþéæ> äï®Mls„I9*€F<°†c{·â–®£¢\V÷¡yõ«8“€Äˤ]?_AÅÉ ˜xíþRè³ Žø? ‚‡’„à>‘Ñ¿IñIgѿ⓶‚¤Tó¡JœÈ}ÄR²¼rýÇöým‰n¯†äRqPˆB°—Î5ÖðüÅûHÅ„²>T1Á*NL8ïƒË.€—/»âú¢ *¿ÝÀy@|ÎïÕ•-Ï{öSUìC××ÒPœ(Þ‡s˜8qât<]Fà¥)ËK'´¼¾9ŽU@✕üèÈø¿T^ @¹þ¿¢h„?ðË>©ãñw}úAòÛôÉ8`©Ã(bCÕa˜Žçaœ…«×/‡‘¢|1 -®/†±Ê÷³a`ö2C™S?SWšŠëG¼ˆÿ«356?9§Ot\_ @ ¤Ðúë”@Œ‰k±Ú2$qy¢¼D)×g@ý~bàºèP†þAVÎ\Ç_iÍ ûá[äOÁ#¿jyÉÀ¿W(¸ä?†‚±ÊP*«?%kãÇEf/8•ˆZÞŽcuJ(8aÝYfètá\E:ÎPàT \3d?O¦°úã±ÞõëÄÙ#èå“}Ë8ehpÐK@ö +ù5Ê3þÓÊÌgÍHœÏÐwÝY!€k&â'eóXÖßO‚¯Ãt0埨€RN01þIe ‰óö®Xt}MÀLÐ:Ñ_Ñ‚C㌡,Ê_ÆQ&NÖËç"á$Ä_™hà7qô3ôàºd߯ þkIØLØ€ëà\sþ2î}ƒ<»|$œîË€ñx¹"Ø¿C(é,À^.ùçH%á~ºNcpW<Ç;U£gJ¼\ìßY8ÓP_B}ˆ<íe釽'ÅÊ_ǼÂàÞqN°ù®óˆ`zUf¤ÿ ¶†ÜÔÏP«q¿yZS}O%E>Iú‡F‹ÁJüÏÂyü¼C‹À¬S¸,W?·fU·v%ÀÈóìóFæim «=›cx™­aô&·‰ÿ•8Æw°1¤ïÏŠò5Îpõ¦õkž!ðÌóFæim­=›i‘õ½’å°î+࿈Óï?‰«‚Ÿ>|øšÏ`·§çÑ®ñ=Óá0Ø€ð]ÂeÒ³÷Õ»1{îkçl}ˆÃÏt>@Jö·~¿‘el—–a9[Άÿ/ý†p½ðÐ!@=ÚÅgœйVЙöA«šéB5þãÒG¸#ïÛ9ئåYöýªG°ÐÀ@nïÿïOˆDP¼DÇùFš²ïPôœ-­q€¼Ũ,GMÊ£æÄíz>@ë§–“"µðû ÀÓ¿ò»ßë¥ñÛùÜGÿßÿã³T‡Þù °²ˆù²ýÌ9Eú*4@ëôá7rÉ+ÈáX)~I.uçjÃÀð|#ÎhóÖæ’¤á÷$qÄó¸õ÷9ÑlÀ'f ô”Ç™5€¾k›ɽ'¡%AS(ÀªçL(r*V°ÌÁ2/ƒ5®‚åòv ¨úx}À‰H5ú5 œŠT£_JÀõ0»3!,mÀÇÁ†&8NÏ»\FþC©™· .˜Dò4ãRTÍ• ¨VP3ÄVM­âÍÃ`[×o|AãñÄQ±¦Êqt©É?UÀÇHPð5?`éÛð*lŽÏx\¶=´}ìåñ‘d×CçÒ£ƒ9Ã~B( \QŸ,ÉÕ§á´rÕò®7®ßï|ýœÃž ‚#\+ ç¨ 8=ýüùsE÷÷WWW–\tþBÜl`ϳI9ZzŒ||oÕÝÌgYÎ@>¨ßÅåáÝ‹IÔ l)ït©žbºÔñêxAß–xAÏžËòÖ¦ƒáç½+  çh ø÷®¢€ÿ»;Kþä·IdÖóêŸZi2ËèÄi‚†<˜t±èPr(ä<ðõg !ðúIºö`%@`\þrP1iAEZG‘êÏÂ#žø9PùæõÙý§!Gþ¥’ØùŠ<ÿ‹RIžÿE)€ûXù0ÁÀ•'Èsœ(öÔeúÑJx{x×û8€x’—Ø €¬ HÃÓϽ„È?[R•×̸Púþü\¿*NøQq×À[×/ÊÇ%méþÁÉ’0²& ÀºàŸ ``°¦à®à? Gƒ–ÏÁ£?AÞügÿÍÅ“Øý£Ï>.Ý*v 8œ¡LÀzºå Õ$:–4zËBì£q>Ö`¹(“ë£\ÔÉù{62”‹RÞËòqQ«Zž, ¥ü§sÆÄ~ùUžp–§tÏ"ÿÞ üþÞGþ½@øÇ…ÁAƒ}öŽÛÐôÐtÑ¥[æö¨ŸÍ`8?[Â\óH®thf“>/ó†‡=(ÊÁÅ=ìàÿÙÏt¾ç$!—e3}°ÊðÔ€óz ÷ß%¯oœ ¯ŸÚ8ÓgÄɲðü|ȹ Ÿêœ úɤ>r.è$Üþ㾃+À²Ÿ¹4¦ö!€%4ÞY2ÝÄh ¶ïáSèâqà0t$C©À-„Šü%>ó๤n¢¯#ucEì#³PÎHø£~>€j ^6p~>@QoÃ,žÁÀÓ’ûvßS÷ñ$òÆ›XÕ‹ vßSÿî]ð #ÿ÷¼ùßÝŸ]ä?P:ƒ€=®/£_¿ô „⥀v!N,z{8LÖ_b `@|çmă3bœl lÿ|©(î¢PÏ XàNy>€(¿N¹ŠÓ&®\M^Äû/Àù³@Z7nàÝ»¨]wwQ8À!Ü`æ}û 9„üÃLŽï%ðsßM€Ÿà¿.Žÿ|¦ÁŸ ¬—wh ‚éMÄÌ÷ÑKŒòú¡ûçQ¤òuÜ: ö Öù@N> Èù'×wççô¬|~À|ÿ†ÿ†ÿ†ÿA8.÷-Æø°ˆ6:ƒÚ¬‹î¼háQAèxõDÇÛ[ƒ>@ŸÁä@Gè$  pzåu󎤂«çÐ1O|ŒÁéÏå$ðQ¿¾uÿEùâþ_VqÈmBüCHZbKÜx‡| CÅå ÃýžXßÒ}$hhâƒçnýGB.]ìòáQ öbóå†kãÎÁd³Ó8Ù锸r>@˜"2N·Ï`-˜ P–Wï¿"Õøþ ?Œö€!x®úr‰qAœŒd.1x —+4÷³>Æf.¸ì}Ì ™0[<\v² e¤´ó¨´ó8NL8÷ÌóÂ÷çPEÄ|Á¯Ž«ç¼¬‚Ç®G†¼ž¹`¢—@§ïÉÑÕ‡ÑÀÇŽ Á‘w°÷&ËWœ(bcU'Lŋ󨓙SY¾t"™`ž@ï_DzçcN æLé¯G+¸f?»P ó¯ óŸ,ò…á‡Ãxo£aùDv!Ã$D‚f`fÁéLfa†ñ ò€cà×…îÞ/A°$ #(uEâê0LÇÅùt˜IRY¾FŠ8S1 -â™h†'.!vDÚþzcºvx—Œ´…»ZùÖýs|ý¨ð’XÆ0°z|¸éô÷¾…ƒ\˜Æ±Âuƒ3\‚M?ØÿñGŒøc¤6A7c‚aœmtÑ”ëq ¢Æ/Èhá#ld+­ãn—ë7ï*€ŽéïkcÀk¶ ¤~f BÊ1 òß-cw<‹}û¬O«÷¢ä„¡ƒYCÆ5aèêc il@šMŽ6f&ƒ–1Æð‘´/ZE[-ùjá] '·ð,¼qÿýˆïg¿þèç¿ÿ^L‰ýßÅDã?) OEþƒn&4O2äƒ,¨€ÁÄ•a¸Æ‡Îç.1„ØÇˆÒŒð{ Å/ÿvR‡H­ë·î¡u‹­h=^W( Ìw,¨ûÿ‰Â\0ljÂ\pD–Ñ¿[bÛ ´£«¶¼Ÿ\?èË‘üHò2Nù¢‰˜±Ëš…qÅ’•ÄíeÙz½‚s›ÌS@±9¥H­eáùc=O¬…&{Y¸µÿÿ”IÀ^N—~B_Æ1:4Q²*Ð-qœßãú¯þ’ãR? ø‰m#!l”ì [L«Þ³j’u&óhõÎ7†XÁ<òÊ<å= ]ucˆÓï›”ðIÒG%à“†Óx†ÓxGȰ~–ƒÌx#öëBq7/îçk»—Áh„9¾ê{™ Î;)K‚­êÆï«P’B‘FB®¹%kLž1[»ô­aøVZ¾F¿O5ú}ªÑï“Nôzëù/èÇ<(ŒÐÔ‹µý0m„#Æbo ®/˜ÁªðRήʸ_ÝLZ¸KùÔ<ì Ô<â&Ì<îYyÒ]yŠ;y™ôìûòc ¨›|?.g1Ì;ñþµ(Ž. ”¶/lÄöl3O²ÀF¼º<þ2É[yï½ëìc–a„§ÓüÑ.›®l^[T\ ÛjÏýKžPždP¿×8P/üù«úñóï ß}l¤e#Õ°m*L'Ýÿ]5½-³\ë€âJ÷âÂõí³êæ½gBnt!|°¨¡ÓwŸÏµšÛá÷¾àÝ«€ê`¹ Fª®†¼âDºb B¿Ó¥ëgn;xTÆsD8³oHàó»bl)Ö™o3Nó4ðÝ0™<i2ñwØÂ­!–c—pOg(8޹ú1u.—W‡¨µêsT‡ˆYœ~E§2º›ðüßûz0GØ Ä æ¢6±ð¦‚‰òJ Çe aɸ$JYð_(àó¢Œï¢øi®®~šg‰ï.O¤žüâ¿ZĪš:Á9C7 ª¥æé»ukó/fƒNß¡JÐ Çý€Ÿæ©á/.:1'KhíØ8æ¨á>G3Ýîv¾¾k]ŸòïÍ"5YŸA…øÙ0Üæ§y’w_ü €N—j¸@‰s‚4œtˆò Üñö/0€¨€S1$½Ù±B›§yº¡°¿Ž¿¼ÂÚ8ñƒ Y&Zh ÷¸îv¼¾,Ÿ„ðÔ› @Àé×o¼“¾Žã޲“™‘A,íGñô¶%vJèüEšóÏæâ(ÿßð:×]R•q¶$+W`FÜÆÝŽåýƒ <4týúyI˜4ºPßÞEœ~µpœ  ø¼ø¬(àå€õS.ªÌ}@ÀÅ¢LÎO¹¨3Tś傯Y/$ñ¸¨•ó_. U ½ÀhÎ?¿{ø—@Ïù׺ïà¯ð5ñýi÷ÿê¯Èë°6®\VÍÚ·ò³m¬þ•Ÿ}K½\¾~;þýŒâ  ËÒë§6®^Ÿ, ßBÝy8ä«&8Ôg¸ÊC€7<Þ7¤s?øšñ—Ô¶±" árc탱Qò?f)5Q_“&^–ÇÛ0ˇgH&Œãé ® ‰’N±ýI€7¹ä±Œ÷Nþ“"¾O ñ¸þW¾ÃX¸ðDÁ&B|€Ôu’­YÔ†?*[»¨  †§­eâúŒ³Û&Ç5|õÓü綦¼ä‰Œ÷A:=e@üå6RÛ\Iûms&íãµÍÔ?*›Ci¢m.åå9ÿáú®SðØÄ©£m­ €äMÀXLQ,Þ7´ÿoƒ ®ð ÜÁw ß·z”&€H}r£¬Tó¡yõ'8‚‹í݇/RQ^l/§>†¶=_ß"¸…1Ñ 8…õ¿–Èpðîóy2ïç yI@ç¤>Ú ”7Гòº€ØõKÚ÷O|˜]pþírHç…|pàÝéH|ƒA$ àó»Óà €º‚š¤S˜úHÅ„’>À0Á¤ŽxaÂclu±¼Ö…ˆï—]“÷Ï»0æÃl)rRÜçS/¯Rç>8ðù<;„ÿãB~6ñü«¿‚7ÿ¯G±æ5´.úp®çNœ‚§Ëp@s"¿?鄲>^qbeyš!áMø¶;H€xÁ¼{7ðæè–2æ_ô|È=4o†—^ý€Ý€-옠£Ô8 †éq>ŒÓâ<Úõ•a$ãÃPÒÇ«ÃØ24z˜ø?‰+οqœ{àüüŸqv2%Å| ˆGü'ðÜ®0”@ð—€:Ž"–rœÆ¸6Î#±^§ âe ‰ôáz ʉû@¹¿ÒÀYsÁÉ|Æ^Ÿ…ð‘¡ÓÕ8¬#çK«‘à¯^ÃNs4p¡àB7gµ@º¸L†Îè¡ÔÜÆP¬+ËÓÞ§X½Ž;åûy%8•ˆZ^åú<l `J€1@J ø– À×óLæñI(£óF`P ¼ÈXîšúè)–߉ö÷Èõaáz¬8áNùþŒþG•g ß_²o?Q–ƒÑ À“Gðø^§¿½;öŽ!ȯ¬ŽSßòdP‚>DZ>› èÌéÖâ®þýt.¸¾Û_?²é`4r=(5î÷†0p4ßÀ„™¡¸æ7œèÐO”Á5ü ¦u¢ïkÁEcAGcAIÀó¯?æþ½ `ÇBL™À¦M|fÓ’¤T_\Á÷#=í¸$LVð3–tÕË ‚·Æ}jáõ%aø'S-…M‚ç¸Ý¼¿ó(oB_ÀÇûåŠàþâè«©¹è²±9—E¥ÍE©ýˆûk¦ÎP@Ú$:xïç8†K&ÀoˆKCÁ•Á:þÊ —Po»¬[ä© n-Ù.ï‰çÑï[»?5~ɉ”Ý$üíkR@0çÐ`Dl¾3ñW%€ÚÆ =Þko‚öˆ IDATCxžŠ\DëyÔû&9ÌgcßÂN)6‰g N}"„ѾXÌùWñݰëÆ%®¾µËeì}_ÏrØy )¥­aæ³ažøùI‘è—£H&àœ¬ ¥b’ñ?¹ëEÃ_\µÍ™PÁõ½ÿÍÍ¡ÏÝ×_d1ò´6‡ÚÏæxa›~Ÿ¢‚ È Ãf;¦Ý°{ªžà*yðúò¸í¶—×N#ðõë9Ÿþ Ç©³Y³’×Úg{ÅwÝ_¿ë÷ÓºˆN€UWjáÝe›úoÜÈ6ߥ&2(™(¯µÏö‹ï¸¿~×ï'ìu9¤OîzÝ™¸Okü3%².?úÓ `×ýõ{€v9 •@4ò)°þAA¬»–‘é/ÐhÙüç?üQÛ_]Åwý~ÂG 7óòÓÇ×D¢Xs}$‹±»v íZ{Â!ýñŸß‡ôŸ?h)v‘ÀïAiˆ¯yA Oü2ÀÏÀöß@>^3û®à% z¢þøÏ¿ÿïßÿ& à±³¼Ÿ~¯X&r<K€Ðóñ™a~~€–Úø_˜àïÞ†ôÇïÿ·üaDÓÂo±hÚî˜ãß%/¸úÁ`¬YëW¿Ép øŸ^„‘ÿüî-€7fØÄÿÈÿ$^QŒü'R |2d¬Ç@¬{ôC°Õ°¿Hû]’_ë BÄVñPE®AàÁp.€?[â{) ç^põ£€ßµpðÓxÓT÷ ¾|øð·¿}ø`W×o¿ýö›ûöõë·o6Ž?Ïnà1º7ùã÷ßÿßÿPãð+7^"H¯ˆ?§c  Äã¢ÐÄi€ g$΂̆/„u|? ‹Bó¿ú¢Pñ©Ẇ¿ýsHûÀ½äè(÷ýoGó!ýfáa²ì›…‡Eó':£{+x'Ðiñ@ÿƒè(LtF…[pÎ/îáx@ã­‰¦Aë4†ËÁ$ „èÃhíZz øð·³ë³3¯ÕOø¿¿º¿÷ Ðño_O?ŸžzèøÉôñÉ/Æ,ÏNÉô—qØëñ@&‚G:ó”¯.ço$@ð¸0’—ÜÁ)øñaÍ0!—Žõaâˆð»tˉ%‰ïY˜òk{ky5´Ãÿ¼^€>ðïŽ õ·ùÕð›Ž;ÿ¼|Óñ“õÓp¢à‘`Of ÞˆzüýïIAÁ¦€3"€<î8Üfâ‰àÜDš§Q‰¿ŠLÁkÁ®Ä‹tò 0´Ã¿ýÓ[oŽŽ6¿ý=åŒîÖÑÜ[otüë94­Áèøtí-€7 >!ñ¾à£Íl)#€ÿûoQÏÆ· écçÊ߀Ÿ ðù”à4È“…ôEdúy8hÊ ¦J‰¿„ì!¡ÚùÆÀ `3ð£ à ã_qåì ŸâjÜA >!ñ>@ìã™Oøog@þÿŸ)€ð«>By’g{ùu‡åI*€uˆ*T@á&jøkÀ‡þøÿçÇR? ž}ÿ6ŸÿóßtüÛ9l™º?½Cýœ(¸ xó[]›£BaTï"ÿAyîBð9 ñiºu2Xc£Cñu ~1©Ó?Œ²td $À @w}KÁA€îzü[\9­8›¯4'°—-üïþ7.ëè¹VÁ¥sÿYè’ñÀÿ» ÄCƒ^g §FV†äð`—ÔVÔ| xXÅaà²XIƒ-%-<-<5|’×ÏöÁÉëùŠZ‚'‘â™`PÀÀÿÿ££€žâ™ÿŒÇ‰ („u6ðH£Àl¢‹yçAârÐ'ƒÈ,B>Y‡DÅ”>…ŠÀ@Ðli…p1dã²q ©8ø‡@³Öצa"Á¹ûÿ±«ÓOÀ:÷ÀpàŸ €ñ%Ä …*‚x?¯) >9)=‚þ“"ܤ_¤} àY #FOÖà/€4[h@ õö-œ,ö‰‚Ð=§íÁÓäûå Zÿ€sî©d˜ Œ½^¬¼µìm÷†'o"ü €ø—+‚ólá$ãœà‰ü®¾…{#ž×!Õañ/®?™vy‚‰›Nã ð„.û(Ú~'’øÞ,À“AA~[tÀ}áqÍ/âêE¾åþúIž-œd<Lã~É7 °ph™þàfÚ.‹ƒÿÇ¢ÜðOc&C 娶à}á©£|t`õ;¾¿>Ïö—‰ À‘‹Ê+ÿÉþ`\2œ‚7a|Hpî'Äñ!iþlDÈ7ìGzy>ÀËvä~#MDlEhž-$3{ÀIÜBþCù=É!ÐöÃ!ñ/Úv(¦Ä)õ'¯cI˜AÐ$L×Zî ç½~Ì-ö×§a Áñšq•‹3ï´ñÈp—6a¦[ÄžvEœè#ý·´)v…ðj |vœç5ßá'q¶à»~hŒÓ´/ pÂÛ/F„spbÀ ï’0^IÿKùeßÞ_;{¾xÉùð–qï°k˜v]§Oò‘Î}䮽`Ç!åzyé-'éYûëwýþÄÝ^vß'aï0r¯Oóž4¸W‘W €?wÊô0hüióOqSY'¢ìîØ1½4/$ÅÖùÀÞ\"Ó‹ zÄ/u>ÀKãÝP‡—/Í¿Vj0Ð$謑rÎÄžÄ9˜¬ß*uŽá}æhù©îÇ:K?+-Í¿ÿ³*Å Ø `4ü—‚ûs‚>º™ùWOgõ,ÜPÀ8ø˜ÇÍMt\‘hD–K¶ vBÏLž~<77z‡ñó×MÐVøÒv{gþÕ“_»Ð}º}ãÏõ- ý%þlTøµ‘DùÅ?^,¶Àðÿ“[óOI¿þÚe‚ý¶‡éÔú`wrò©›Ï€ç¬ïooã=ßÞzÒQ¹cÀÄÃgÄÖ#ýñr¯UpG·ø§ èg‘~”ÀèïXº1ÿÊôéø¤;>™®ý_?YMž×ÖŸŸ·^OOŽýßðƒá“õããÓ/ožð—•Òq•Ÿþ¦QXp„(`QI €í?…²¡e¯îýŸŸdÞ>Z~Ìñ8°ïWDz€õ(àÎþói¥Ç¿"Œô$À‘2šJЩ¯¿/Á ¼ë..†gRPrǰÚÈ X|5“€?²ßþ+Ø?éüGø[­Vëá¿ÖŸŸ¯||œžÿzr,ú/€O^S’þãO> ·suÕ±ù H–rŽ‚¢À‚é/°´ÿÿŸü§õðß_ÖO~ÅÊzýôdýùµ,Oë'¯¦ÈºpÀÆãâÓ|T±ÿá‹O^­Jú}Z­noÛ¼ôE~æ_yÒ€œÂ•¤÷ü{hNà–à@8FÓÿf ÿÍ›Ç7¿øaõðòëÏ㿼yüåÍzí÷FzŠe®úŠ|€ï)\nˆËÃm—‡Û8.·ð¡ð:‰ë¨òŸ uD«Õriÿ1úO†¾ß7ÿǧ7ÃßÓð¿dÉkÁúºˆ‡×áÿ‘Ü“¡  >€t’Ð÷77èþñiœÉäæ&´'fö¡2É'é‹–Ë< ¤¢É$ϔŠ"rÄã D,Àd’C»~ȇÛ*ñß øÿKgÈ'¥ׂ³ýù³0ñ$Ï ˆ 5âòœ‰Ës$.Ï `Óóÿ÷¾¸èî/Êß™(@À…î$. ä/’¼1ˆèûîæfæì?bÿ}-š*ôÇ›!ùÆkýyüÑç}ÂN` ÇÏ“±@ð4'àÓw€oˆÁ äsð}Ú¢ð|N€Žçst<Ÿ ðà¬ÜwapߕΠSÀð†b–Úýb± Ä/’†ï½¹qÎþËõiêõ›'oü=¹ÐdAÀªþçq t°Á¸ÿuI&€éZqÐÈÀn€~â’ÉpnµÊ]Àj•瓸θoà´!€ÇŠ<õ(€îJÀ5áÿøªX@oÿeøáÿÓ/øHpþé@°~‚O§RèH'àÓ÷À íJ>'`Æö÷G<Ÿ ãùœÏç0ææý`°üƒ…¹ /åÜ=›Û·€8P?Ñ}€Õ¤‹ž”þ«i蓇À·âG0îžÇᾊùýÖO|¤0„‚‡}üå ;`÷Sø… }€àé§SÀ~ %@R>'`>YenFÏ Ðñ|N€ŽçsBÀàþ Æÿ>ŽàþÉ1)€:€€WœÀ0Y/:ý8Ÿ`è7tÒ‘ª(dø¿wp¦¥¼ x\~ –膃¿ò. ð¤p0ä•2鸸´'ÏW`ÆÓqqžŽ‹3ðt\ÃQW\Wª®cÀP‚0¤ `¸íí¿PcŸ€ýu4aëØæƒ<ù§'C7¾†cEŽOp60ZŸžÞ¢!hᣦ¥0Ú1 Dúã XüEï8Âa!Z Ñù%ÂÅ@c ÈÆ1Tâ!äø÷€,Ÿ Ë7@l)€ÛÛ[gÿ¥.`Š@ný†L·Q>„»« £n  G+Lº€O°$y[øûÀ öñ³k}¼K!€‹,ìXyPÀu±`R ÀdfÿpðNp ÿºpþøÀ º>xôqîÄ_0ŽôGÀ™'‚©0$e™àKüðÏë¥ rðºˆanc’æ;ž°J€ïRp¥ àúzßèoofÖ_Äþ #ç?0íã Ó0°øÿå M< à$âÈí4ÀHpˆõƒŽU'}€—ÀêÛj›;÷ˆçVÿÅßÑÚ ðòÿ ·¦ƒ©ÊèWKû/¸~ëÉa]@"Øó}ü {4Dñޱˆ€.àñ‰ÍøBP:i=í¨G}Ah~÷?_-Gxêýëèß¼*ø8S4šf’ÿŒ B¼*i€ˆ¶þ¢ÀñI’À:ÙˆO"Xi Lô%aÍuÃ鿣ýnÄôˆ=@rã<Ó(€ÁCøä=€lá½ |äÂ@î£<æ Ñ à“pˆ€ë¹Ë aO¿7ðô3¹ÌÿKj3ž Ã'¹_Xhšó_”ü3Àq–À:dHXòCÁ?äߣœ@¼D ¿ìù/w—3ó/®œÑMü`¢q®mâÃþ]{Ñ'‰nÀÉwÀŸ; -+ìÿó“~ðtfØïËpþPÃåGŸc'<úYÙ ðɹJÇZŒà/ú®%óÿÒ©¡ïQɯ9u—°?\ÿóHüiîŽ'€JãÅŸ¾‹Zûçt|3ßlŽæðïÑf>?šmŽü'þ•ÿk?åoo ˆ@:‚´f„àâ"Éüî™2Á ?Ù·…·Ò÷r¶^ Ȉ0Ð*>ØûðrÞÚßO-øÞº’}Õ ]À_xî9€¿OG „#¯‰Öþ~ÿoX®ÃÂ@ÁÉ›ÍêN Ä /0ú¥@}€‹‹««»»ûJxêáÑ{*f[Â^ûÏdzÏ‹ÅÃÇç–Ï!~f ±ÏAoà_ø,¯€Öþ~ß@:ŒKü™ó²‡~rB‚ýÞ(œîü9ðè{¸´ËûP°QžÎ à÷MEBðR€†O[ûûƒZeŽäÆq¼ìÿ×ÇùŸLœD‚’ œê\\,tš _g ø_qÁxø9&"WþãÑ鳇܀ºK£ìÿ×&ƒ(î—!Üðˆ}¤ÿJ$*oþH}]ÁC(˜©,ƒäjåÍó6èöƒñ÷-Ú?8ËÖþþNñ`ºwçàþm:˜âë“5¹±|€àdàO!€Øþý¸Ùÿ·“ €2‘ܲ¼½=]þÄ<Òúï¶ö÷w…€äùÝp>À  B¦\ÓͦâÄ•²‹Å]Jþ½w ±ˆÃ?žb'@Ö~­xè `Q  +Ë_‡E¡EùÊî`ïèÁÿcóÜ{]T÷÷w¥à<Ø%žöÿj8áKÂü‚?=NsG_ø•ôBÀåá6¸<ÜÆqy¸ãòðŒ& wÂøò×iY¸@mw0Áù›‡Öa\Öþþ®£>@:Nxýäyã+ô ìÿ>9!‹Bý'Šÿòä;\Vú5\\x¢#át èepöÑ–ôc ‰ ³à_&€r¦,oº/ð¼ADÇóÏD"ƒ"á ­BÀéÇÀ¶À  ‡kˆ"àKx€Þ?Á@,½Â9  º¿¿>Ðÿ8ÀoõŒûÿ‚§'iYøôñd:„àoàI1Zॠçò9«P÷<åst<Ÿ ãùœ€•0iØIЇýÁ]‡[…üNÀëôÞƒ ò7ÇÿGG!20¼níïï„à©{úÅ@öÿOýŽ opcˆÇžÞPÜS?ˆƒ ¥P@Þ+…v–¼ð%"Ýþip}(@Ÿ÷ïÇ”Ï àûûcÊçèx>'@Çó9Á(HþãÍl^;/q:€? ®äð˜ç;(à§`rG‡Ãÿ[ûû;éø€O|ÿ$·†=&dóL=¾ÞÎ8¸|“Ìsÿm0ùœ€ÐdžÏ Ðñ|N€Žçs®Óϧ:¯¹Äöp°ûTÐxÌ÷U›äþátv!níïï:é¼ÁÙþ=…#ÀøÝŸþü GHxÈóæQŒu±ÀЯ%ß ð3á 'P40´Éç”z<Ÿ ãùœÏçH<ðãÙ…QÊe΀?ÌÒŽ°ØŒ÷ÖO'Óµ|òä_>”Áýä€oé|Ìx¹|NßßS>'@Çó9:žÏ çèôÃZ…8·øÈ'„ó œ"¿Áûß`@ø(Íl&õPp9 ìÿÇCð,È&¾“@À(€Zà©æ'DÒc²xÊç¬JnFÏ Ðñ|N€ŽçsÂöðêûçt™‡×¥®óð’u8 ˆÃÀ~+@B³G[£ÀMX'2JÔ8Á“T‚óçìäDåJš4 ûûãë4 4ð4 4ð4 ŒçPß?§ À‚ `!`Æú Æ¡?ÓÀØ@ûÿ[çüù>uý¸túýÂ)\Å, Dèò9z/Ÿ ãùœÏçäu`üÍÔä9* h 膹ÀMèüçÉþs{[›†íÁe@ìÿoñ< |Žð=0Iûøî¾ñþÜd¢r™ë,€hb',ˆì±ÍƒãÓ@ÑD#0FÚ\ßÿß:qïø¥ 1ð YäoѨ1úïz>š!€K&€…À‚  r>öü0üŸ'0)`¤q€rÿë|Äc(˜ï {­øn?>{]Àe.C ïÈê ó|¤GóÜðÁ1ôþÇþHÿëão ç}ÝÊþÿÖùßÖÈ‹AµP°çoøf7RŸß½{W#pßøw/I½‡ç0Ï€–?>:€G~˜ ê{O”õ×+k‹ýÿ­óà%Ÿï¼¤ª-xïø^Ò2£ÀÏÀáî ˆ­§ðsÇàµë°?¼XÈ÷ÿ·Î˜Æ†žø pœ€ BË!q*h¹ôDëôãñçýxô÷î@Qdˆ-)ù§å ÿ“>.ùÿí][oâ86U Ã *¢Ù™‡2B+•¼ŒT$Hÿÿ?[Ÿ›}|‹“¶îÅ«v¾$K|¾ØÇÇçÂS>Û€Á;Ü„G Íá§âÿkù÷.aSu€{à>ùšŒ@öúÌg^?Pønÿ¿±öÏÎ!h|C¯àõUú!£iè˜Äÿ×òDøT@œÂÅ,“;M% èÍ ‰x‡¾$Îë¿7¶ÐâŸýÁ`DX¯AP¥$@Äÿ×òdðI:ÀÿøÎîÿooìøDæÀ'v {‚øýã¡ôƒf“4.ÀMá£òäð :Q&½¤CºŽ6\ÖkÊÂOBG”ÿÚñûÅÿ`ŸBBqõo>³íßÃqtL€Jü-?@ˆOÕf'À¿»¡ þ‰CÃ8*&áìalç\Á¡uxÄÂ÷$up¿‡g¦²óÃ7víÞš»‘{ˆU2Ü=<|tùø™à3wƒi¶±_K> î…#Imuݯü«ë0—7bñNãubþ€¬€µgNQû~54MÐ $† •¨I K.®4Ð% H-Ø{\Ý7kL‰—Qö°«>×âu—™SÄT¿ßÜ`_a©=ÿs' ut7¼¹uЕ&Ý*Ó–qèÄ(ö/Ìâd&ÅÿOÄÇ ~:p½¾ª*%AGæúê/^ðèŽQ·Æ¯¯¯u¶œ|5p“ÿ÷ët"Hf™·ŽÌ°…D¡ù<Á3‘óƸêÎÄ!BÂín‰GŸŒ'@Ÿ´EÜä×ù^B&“'pE;|3˜€óŠ} †h<"€7eG ¿FHI%õQذ\¤MIþö˜=š—ëtlbÊUc8•Ê ù*‚{Aþö~†qÏ”ls܈R|4mdZ¹®$ž()À#ûò\&×ì PÕ6nïÉ¿›æ +ù4þ?Ͱ%7x,8ãGX M,çéàP ×½%ý,ŸRÉ©4“) ÞTy_çÆÙÇF¹n­Æ‹éxy9—pyy¹¤¨ë=sè{ÏÛÂûÆÿËÕ>ÀÊÒîA†¾}¢xñ{g—Û€_G~Tðæmn|á#ÏØ€®½‡Ëi¨ê”ÍýŒE {ŽóèÑ0ÿçØÚÑêJÅ1v t€Pþš><ü·jâ ¢»ñññ™ÛãcҹŠÝÁ.ýn×8#òvM1`ìïå‹¥ÈOu€ösñ W6îqÿiü?Ï*MK©6ao8Ä:ÀÏØéív { ¥cÿ;¡„Ø"ã»YðfAòæÃ?¦óöÀ‰è‡°\¾G`-¼þ©ö'Þ FŒLü?]¯ò`½9; @p «9á ˆçåïàÃÃeûšw ‘a½ë|ÿýüÙu¡9èùYw—ÿ¤i¸*Çšä³³¿ „vZ ¡ENìqk‘¾ÇE%[ÃO|Ñß `þòöÀO$€ZLÐP €1|ù@uãW8ªÛ  ‹ãøÿ8£aÏ+ݶ‡/F€ötjAJ(*+èµÈGሖq䇕ð©t=]œ¹~Ñ)m`¿Óª¡…hNTu®íŠõ±´ËûIJ ŽÿOó€úÀs‡¢—c2òw ðî`@€Ø-ì÷o8&ÊýžÎ€Ò?ö{ ¥j„ Ï<P*D²ò9…ó9œnaÁÿŸä Ñ…Wì¾£ûKìfà·[~ïŒ·È Þò닚B‡ÏO§Òõ2Çdð…–?‹+Õ-¿ ˆq«—#)A£tP¨<ÐäÁ™}Óøÿ>É€+ˆ¾—ñ-*‹îîðJ,$@¶Ü€:‡IDAT* »‘ø¿§:‘Ô½ÏMà„Aý»ÿ6Þb$8ïö¶„;@ (àNˆñFËŸþl„«Ó pÎÀ®ó¨ëæ@êû (› ˜CI9þ?ɰrôr«Ä­]¾‚VpV€Š 5þ-àÛ·o'`Ä>Þâ‚)ñQ:€¡½Êg)!¿rÑ¿dÌFÎüÁÛ`q€'ÀëµDø~!¤Å¶û¸ÿ¼¹§VZ†‰DS@A€ þÁ7ÜÐì04Bà P$À)C€ûüö(y_3°o/ 7ctC/-ÝXNŠ  _@Ö€ƒ]Öaìc¬67 @#JZk¼Ð·kçðâ»Þºù¿„ó ¤DjÜÕ@‘ïÿùà™†‚eH€1:¸‰Ó}ï Hn#$$|+ŸÒ½Whpƒ‹lMâ•A"ô8ƒÁÝ  2ü»ßû³¨d†—©ÁÚ@íd6Ô¨U@ uo¥×8Ѝ„ŸDƒ,]¿“a&ÆÿJ|s;§ñ6ìXp 0BÀ³pW'Ù#ÿŽ.\’¬8MÀöpü:`5‰ì7D€–ÖñAœÇi¡oŠ83$wÙ,¸\\ÇHûÌ) ?/_xÐS@U0X>,|zCo,|Z\nõäBÏT47>0Ì‚µ!Hz‰ÜÛA?Å×§ {7Lª¥?Q{ A«ÿ·¬è%òA mÅàSÄk×gqÞ û ŸNPÏVþ/<LÒ ,ÁÄ È›¦F ?çà 1à 'G€üfÐüM“·kÛ¯vü ²=~nœÎÁ83ºFüƒ?ÀÖq˜¦À`U7y;Æs˜¤†ó `ø9]³:ÂÛ<S ?Si;¸ñΠ9S°xEÃ`NưJÝï»N|-®×jaI0¸/[Êï'c0{ìΓ͟Àò_ˆðç ¿Ø×y!-`º`°²d¡„Oøz†ó `ô1pX€YáÁmå™ !ó€®Î9l(ÿÜyq¶X6¢ vø5Â' l)²¸«èK 6ˆû‡Ìáðr‹oÜñÑ’êw?S¼>S ÷{¦$RòµƒF³²Å¥¥s-°æÏ‰;a.ËN´¯“¦€÷`Œ€ÍŽß–˜ÿIú÷0TøùÞþ˜Tê™Rñߌ ž©ý¬ŒG~7nnÜ 3ÜÿCKÞ(äÚ(ܘ±:€ VÀ_V¢ ñp~ ?ß!Ü<~û#ˆchð|pÎPxx,Ríz:x€Ò™Å£»áã"~Jò­ãf‚ ‡‚£ÅߟŒ*ªÅðÞ½|IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksHeroes.png0000644000175000017500000006532313263214225022366 0ustar aeglosaeglos‰PNG  IHDRæ$ȇPLTE™™™wªÿówªÌÿÌfÿ]]]™DL"ª™™ÌfLNÿœ|fùÌÌÿfÌÌf3nnn3ÿÿÿÌLLLÿÿÝ™ÝÝÝfÿfL3ˆÿ»»»ÿy;•ƒHm IDATxœí} cÛ¶®¶6õ8©ï]â6žâto|åÚÇ>uûÿßK )G–µ“ Ýü¡‡ > ø ºi¢žŸ÷NQn„??æÁ?ºžmé‹) *úVþ8R>†¨yqÉ@¦ÅÛÞ'ÐÐ×n6yN6mHy‰~%WOoß;Šx:7€\‚M›gTÐGe{4ý ‚®­@Qåx|>0üm=¦vl6¡<º¡u·ëÚ¯é7Þlº.|7¦Ö¹:šñß¡È *ú)Œü§°_ÿúü˜W±žŸ×,ç)7I!BÕvXç¹ÄI!õô¶úo:ÌÃ6#©Eþ¸ÞúÜb…aE?…}fæÏb VëußAðºÊ3˜¦m´Dà„xëùÙ€ó46´¡à\u±E»é@6Z‹úåß©u «~íf“ç+(6ìMKD°M?äÂì#äê 5î5ÏÞµîõr<åÚ„xn? GolQáÎ6ßH;\Ö9X`Ë,Òø[ç]8¿¡£a‰Ûä ¢”õÃ3Dsãf´‚ê¹r¯yùMžqœ® ã¦Â-A¶oº6ŒôØæÝ6üPµíÿð¹KVõï|³à2ðxlcèk¨5/“ÃiÝ­è‡g º™óR¬L½vÌË/©'ÇÜ ñðë¶8ð‡ÝëMëîøi{à?t ;Ï=xYßµÞX³ií¿M×z °ûŽC¨¢›è£7ÖËR<@MßɆ¢˜÷¿Lå\1T.À©q"7Å¡lBûèÞ´àÖñ‹¥×m6¤" Ðgýïh?À‚«©ÎÃSz­Å5ÈiÛcŠŽµ?E}—ª €>,ï,þZ¹ašÌÏ ð"Óá¼òÐRÔ~Œlh‚!úŒÁ@ƒ÷ÎU[cèhí¼ µ1{j¶ñ·¯ê;:þ¾hÁùlÓäò»^âo2œî†|  axZôúM`oCQß\ä7m0‡ ³ÀïOó/êC#Æÿ̆—ëqÏ¦Ž®ÌÛ«T|?–E\ÐjþŽŸ[ã-!Ñ*¾Ia¬WjE?rÃyô¶ st­€7´-´¬o•¸í¸ö‡ÕÁ4ÐKó¶—†Q7½é,EYÿðåü ¾´bò¿).”/A w­RÅs†Eý”ò±Ã?±‰Vprƒ’~Û2Mµ#CÏÏ+S4¦˜Vf¸$0Hð}¾žSÖwÅüŸqrœOJ”à õW{‘½˜Ÿo£ñ?H?m@Èý3þPr†R@ÀYþf¥ ÊxM?Ç©ÌLÀÜÈö$ÀaÓ‰_žP¬ëƒ½L',è‹°ŒúKÉJxM?Ç)<¹ –µ£±«iö²¶Kq¡¾Òyþb É:<{ p` %ºNø/è¯%zËÿ3Ï>#8ap•àÌüêúð•ãd6:”—@¹9š¼–%àhúð±×µçï„6Y}ô³éÀ‡4Ù®É4RMß&ŽÚëu2àüI.`Eñ÷áuýoBLf”?lÆù1˜5qÂ0LL@‡aýd ÀaÞT‡¡›â0TÕ¶# C=½ž@ÿvHWL†ÿ=@Ó2´¢‰—ˆ/[cU8p0&@ `}¸Pÿ`TN!,½Mtõç7NÄd 6†ÅÍ0}œà°Ò¸ýD”Ã.-à•½Àä°n[¹‡éSÛvwñ¸~ÙVëufeý,DŠÏ›ypê”Þ)г·4AXë©ê; Ê'ãÂTì&iÂ,¬‡†Ö£:]ЯMEGD$.À8ýuCÛh{!Чh]Ÿ4`΃¡ÄÅ?›fÞ`µVXŒ¡ „ÅE?Dµ= cë8Ùbh‘ÂbTY¿¶…iœ÷rpWÎe¬>ÐõJGMn¿ž¾-ÃP×y†ÜV W`MXŽM ×÷©8L—c ÿ^œ/Gs‚Ûl9ZÕçòåè(¶§xV·ÍÅ-t7…ƒ¼.½ˆSùÓá~C…aÈvÔ=¿¿°!#I0TßIoèÎѾ¸¡Äç7¤tÒ†”²>ßÒåR‚8êTŸ*xM߀{}’õíàì™ Ñr|UÁuý꧈[ª6~¸Öò-Y-^à †ê7˜ ƒ7¤…˜{KZ(À2˧çÃÓxx:HI¯éÇËš ú²¹ë2ÿU}TÔñ¦ÝT ©’` |jÜÊQ“pyÈ‹SãZ쎭%FPç35Sã ‰Üñ ³,&Æ?¸xìdÎàÄ8Ür,Ýwâ'Ô)Àz4\LÓÂÝ-ÊØUýZùLŒ'’©Oƒà|}'7ÕãàJ‚°J i$í± ªú¼ˆ*Gx\g P=§Æ;cÚa˜PDã຾%ö0U,ëLPÕ_­ýŠ´·Æ#òë—=>)Þûº‰ %c¹qð€¦‚úõÇO›{ê± ªú«"÷CO)+Á‰ñÐ?„TmÎà´¸/‘_‘†î$ÛJhˆÇuÔô!n"÷E¹“œ÷gˆ­Ý)yÇ"!û)®H %Iù™ ¦¿25Ô ÖË,¾njü—»îÒ´ùž£iq,›¸·Bbøð€4´ó[ ¥ÉÜ ªú Æî.•Ëiqµ‡irí©ñfc×ËAÝUázÙž,ƒ± ªúÍÒà°Rl'ÆáêÊ !-L»zšì×¼\MàkhÇvj]3AU¿Yz©EXO‹ÃUßHˆüL7±™”üGµq»§l?›‘ ªúí¨ÛöQ‹°Ÿ7Ô'µ§ÄÛLºJ‚+ãÂTðšþ…¸—u¾—ò¦ø<C£>- .IPd°‚Wõ›6Ã9G^ѯ柕Ã+ô‘žÛ–Ò".lë®êÁ!ìßWØàÄÅG(뫸xºaH>~0XÁ«ú ÿ„¢·áÃówü ''ÈÑû€\9Y×§øAÃý ‡•vÖsÄáõ2}‹D\)Í`œ^¼E_MÑ^ˆãJÃÅú¾„}9¬c€¿;oOZÎÓõ»¸l?1¾PZ,tçû!þüœž”õý¦t3ÿ¡•VQ™Þˆ« †ês%†8Þ)¸ WõŒî³%”…C6ž“Äþ¦)*ú°SËã.Ð8猭£HSøVÏC׊úî ½ /@Ò)l-™(Q$q²ª4)â:Ï]@Mß|ˆ'xˆ.`EÃncM3\_;mMMa`l>2‚—1úÔßaUp¹¾€g<ÆäYˆoÉ$iG7oE¼+ãv7þåú˜"ÎÔÈvát2—éoÚ8ß4P¿ñ5œœß!T Ãjà”ðýƒ u®<力ÁPÒöom½ÌEú ¯®é²1®ü€œ!v‘Ÿß°6m†“bqU?5€N1€˜ ‚“g¦oÓ¾";›¥©ê·žk툦bZ¾™Öð–…v®ò™þŠ>ÈÒ泈HÌK2€Pƒ‘`Çp{þ;¦p]¿`üý,bM 9@j‚¾RÃuˆ$7MÚ×ômx¶íJD‘@±†·Ñþ,.<^Qß=þÁvìs0MÁ6›x~F û37¼óàNñÌq]ßÏÇ[còM’ž+ Ǧ¥óб³ kú±„° ‹óDµ*x‰¾äÚåÀì¨è/u}f›À¢J ¯À©€š ÚÂ0v>1€ÄÓeê4AËî`Wœ¶® K DÖRˆß¿>ãí™ °­åþ ÞM—Üù]G¤ Ä̺‰¢¾KÁÙ!-DË´µ›R Ïlô±é:l„éÓ"Rã÷9ü¬¬¦ŒÓ¯h7KýxÑú‰¸èÙHPJ +æœ`Fƒ!f~룽:b´‡wœ@ÆüFT:ÀÜÄä«úT`¤ü,þàJƒie ýg¯®d>©~VI›ŽþøžñbÐ™Ë Þ0 6]2Õ_Їwc ;‘ÿøt]:†°Òuél6—ècºÔjÄT¸·RÆãôuͲrƒ·êcÉuŽ£¦±al\ï [ËãU0ßpQзüø;[úÔý6ô“GvÛ{r ¸Hß‹JàÓò×”\À8ý2x¸ gP§ÉëòÒ#.b#ÐËf“ÜéiŠŠ¾MÑyEzü)!èä3å 7,‹²¾Àåò°÷“ÈäÕõ‹Æš ŸÄä‘ú±èdzBÉUtm¹ã0ð}+q¿Fn‘âNËÜ>÷†=ÉPý º ·ÁÝþúA §_"ðú±àèhPøg'~$‰Šú,™Ç Ï(­ÁÌlµA^Aß Døc”¿†Ëz÷(}8?`ùô¬‡}ÉþÆêû z-ô΀6ºzÓn“Ÿ\´zi¨@Š]ÒZBè?Þ£õGz˜Û„¿ô´‡OIß ”‘~8€ñ2¤PÊxŒ>! X± §Â #ô}h½¶a®Áðz Ägzé.G]ƒé4@DŠòÏ(m³|Šú(³„èÿ-'øG@f ÑÿNð€Ì¢?ûáFv»ûÝÞ»nwï>Š©5ð.MQÖßy£®äìó0ÉN§B ›– ¦¿«ä>cˆþ̇¸²±{¦üâWƒx4¥±¬ïœNÆÐ6ò&Io aRg{'DU?hï(œ?Àœ!úóNÐ@±8þL î,UÜ9vw= 'ûí4\ß&°Fq2`÷I½c(­áà7|&=çp˜>>…O ÎhÎýy'hz,KqÅJÇÐîËXôô&”ôÝe[ò`†ztÆ<k÷§]ÆàÎ[€¥ðþ^£XÕ§pÐþ˜#DæÃ B75HêlMòà=’åܼ%7±€¢¾ËâäͧædóáÎØÚκpO`tüÈ™¥p—›_YÓmû y;5_ˆþ̇@ÑŽOPO±ÛÆ»sàÞyqëE}ÞöÿœeÜ[öÀ .¥eÈu\{ƒ&ärwÝÌ{É*ú>Ñ}oµ;oÖ˜/DæÃ Ç–døÊÏ‘ë+5°%y˜>ˆ5‹ èú¯'¯»»Î_Ý}ç,…Kœ|Uߥò¸7€Ýé>oæ ÑŸõp×´Û æò -ÕÞÁØèˆõA,3Ð…?í°wB¢\ 7>Áéßãõàùÿ°>ºáyMßÊÉuCïÝãÇ6+ch¦ý9'p¬¹ê…>Òè½+0Wî=n-`˜¾Mø½Op N¡5Æ>¼‡O¤&ãbg+-øçÂãWõm»S Ô[€hs…èÏx8gÖ3ìÑÖ`w½¿G°ðNõ]×Ûa?Üöv®±£Œ“740ZEwÖu ~êB öy×ôÛv<üÂ`rÎý'8aó|­{Å.Öt>Á0}›±Ï€Kàûñ÷h_ÔÈv–ßûXÃ1…Ckúî¢{Äw"ÿF †’NrMuœ¦8@ M¦ÆA°t¿»8Js¥‡@¨ßX ~êÐ…Änûq²8«¡ÑÃìX ß ÑwS6, cƒ,!¨ŽÄϯ’Åñ ð6z8?ànžÙamgzNÁG»"2ßû`÷f%ý†,ûñm€‡O¸ÀpOjxba». ¢ïÛ0tÁ€ˆ§ýÂéº]O›ÿp‘XÜ4>5Žå‹ ðGZR²ôm% x "wè£>ŽYþÔÀ‚ ÓßùÄ'ˆ$·€•/)œ±3 ­§Æ×–¼bí‚u¦Æ=A±†wY ŒüZ U|¨~ìLJQœ£/ÞûŠôÔ…9å} Qß:ˆ`'Ý,ݯ2?–Œ¿^N/×~‚Ð;ˆdJãVN¤ŽŸ„ûx´‘? ÕçĘŽT`ÒG¼Ì<¸œÈ4CQ¿!=ˆè¢h/.ö’Érz|ɯd¡{SãHQÆ/ıN`4€Ý0}øÚð`¬Hj(qñ÷dºÄÄjúă±NDbË}ëx{]®nc§p£¹ÝLŒãH/ðëKg'tÂb :‘%ߊ>”9i‚OÈ?i¤IC,ÄÃ÷÷÷ÑÁt¤x¤ßìˆúŽwB~´àÝÉñù 6±”ß›G 5Ü­ëù¦ö4D†a'‘.$$ƺè!â<нèâOƒôÝ 4ë¤P´ 'VÑæ–ø’? LM†»q²7ßã( Çj˜ä䦸w¸4|¢15}Wø®'vß¹ñ]L‚ÉAÊ7·z 0‹²~´^fA'>SÑ$ñó2Aïwìéê …³c35öÊ=`§úOƒõíe7ÜíЄBéÇâÎßiçÔÃRÐ)‘àPƒËúÎAE9u>›«Ñún·Âioí†øÎ-ÐÃXÙ—uß»²Å*¼CbY‚áú '»d'oE»§ {‚Â<€döv"q¦ª¨ßìhÀ·`§]\ŒŠgh¤ò#ñ÷òIœVÿ°|³~õü×ç¸Ýÿé»=¼;CLß;‚€"_o!Á.K\ ß¸Lzg ¦ÀWpNaïPhN8v·Ã|¿ '’Êún?±Î㹨ÄßûÈ 52ÔÇý>Â3‹úÕøJâ¬LÄÃíµ"dý“Ûr·ëí†Í}wüí¢‹… 4Áî}+ ¼£0 }½u5Øo@ñ¨mqà*v@,û‘àŠ~0“[Öö8™Š¦âïW|Y,`Ýjú>j¸”ƒOåÅFg%UôÝ–ª{Ü´;¾²köÞUVš@Ø“§ë»4‰öîÄŠlûEq˜`ù?ðAD ®è; èNÎíß»”®#8€F·wÀ‚~>ªêç7õžP>`¢Ä¿ªõél^ÓÄM•p™'ਚ¾' :ŽïýžB:Ñc>7Í .ëû,üN5w[קჀÀŒB‘OP2 ]pà5ÔóJÇ ç“ÔõmÕÝÑý~¸ØægÕòÃô1óÂã’ü¶òÞ£Ñ8? eOPÔ÷¸3™ï±ì’,BüüÓR>ä¨G¡ªB@]< ÛUÏp­‹~<íúL´;èú¶Žl\Eá®– ¢O`‡»ÎÝÖ=ýÎyyØ[š´1Œÿø¦(ê7vBÆ´B!~þiùtŠÈhSR¦oÌçàã¶ÕóL N2¹\šéÖúÉØ5;L)²ývüó&"4 n;©èb\óíyÙ#Vôýl”K*=^ˆŸ×Bü}ý]uˆ>Ñ-œ?às¨>@Uß4Ó›ÜQ¦‚M -AE¿ã¨àžnÏ’Ä”‚”õï£YÜkª›Í7'³â›Íã<øG—Ç- Ól¸™¡©ñ.P>/ß„cRn—šßíjõ#TõYb\ý.$ åóMüݹâ’L…ãø<ÌÐf]À‘ ªúA¬‘ÜïÜœñ.K9®&€ êb' ¨ò§»>‡„ÝÔ] ˆëMPÕ'I‘ Hx=¸žàÛÚÅí˜W±žŸËÜç‡îäºR‚ª>M{rž#‡S_2 ®%X­!„~í^¥È‰ñ m£%§Ä½‡ÞípÃMª=6AUßþcÝ…3”kÂ8‚:C{}!ø+÷z9‰ò@mZ|%÷Òp¸r!3§R‚²>>@Ü;š”ÂÉiÄ’ö¦”@8ÍØEP¯VJl÷ôøãÇéÚ0n2<#(A¡4 øq=A]vÄ$ÙqÂ)l™WáÖ>Óú ¿|õR ›ÿõè‰ÚKO‚oÜqútÛ ®ù’Ô¸*Þi èƒÐ؂ݽ͔’˜ÁM£ÃÂqå}[@+Û†0ê•\€SãDn‰[WB'} Ý¥Nzl‚"|6~ú­;÷÷ ñá2\Ѿ$–£¡XOŽù›ǹ‘¸á6£o\‚ Wzj!þZð€±„Ü0M.¿[à%þ&ÂïQèÆ9ÚJ×hønè ÛBG}Ú•«ÀXùrwwgêèʼ}‘ŠàwE\ÐjþŽŸ[ã¾4=!lBN¢«O»ëá?³ *ª}Í ÄúÛK0à÷±~‹xQßÊã·Ç—Ç;ÓL›·oÒ0ÊãwæÍô¦³—Ðo›ôÇ—;+&ÿ[㾇tº;¶OÌÅûè*(¿"~_Áeý{¬¡·>š3ü^Ã}ô±ŠËú®|ÌðèÅ)¦3\$ø·|=§¬ï4Šùo âäQ`pR¼ïÝéZ§·]ïx#íÃ3¡}øµŠã2Ãõï±æ;‚,XuSøž_g@¬þ}{ /é»ò±ü¡ä ¥xš¢¬ÿh׋ù~$'ÅMq¸}T„?^E«xèãa—èïBm7~»=]„"Ì—¨ó»øýN4€š~`ÈRóè Î| ¸iÏ“e}‹š>@À³ü ÌJ|,ã5ý§ðήçHŠ¡W¤i'>¸ˆ†% "ÅÃõyîƒ'Ÿ¨}œ¼?%ú.—;ƒ«ú”`_@¢Ü!l:Qàˇꃽ<šNXÐ à.êßIPÂkú9NaÓ„Кã:Iõñ„¥{â"š<;*Þ»€Áú±Ž5“ˆÔÑà ¢ù°*ì@4¾¤†×ô=±†ƒ‹ä =n¼8p%º®¿>îÐXþ7<ûŒà„Á—gæWׇ¯‰à½?^Ó–­¢èÁ]-wÇÊŸ¸€Šþ}ÆO`)~"UœxïÚv|ü]JpM¿É*°è£7¦ ~­½®oGíõ:™ŽäüI.à…≯ê?ò&ÄdF@œíÜß៞°áìHpÉÓ .º€¡ú±Þ».¢ëÈñNÿžúpO¬7.oÄÅ×ô½ž@ÿö˜®˜<þ[ô`MÛ\ ‰ï¿kT à‘€1bëÇ õ ÁyÎÐt>¢â*á‰À÷q65”q†s®ßðO{Ëïs¼óÎáÄòÎbõÞí¼ ßÀYZ--à{Éãºmµ¢O lÛuÞÅãúexY¯3(ë?®× gâŠc·ÛEöw´‚8¼s±ý±“©'`¨>àöáŸt¾~Ç3w:L šø/è{‰H2<‘ñú놶ÑÍ:;c”á)Z×' ˜ó`TB7}ǘ`°bév´`0iå1D þ)»1ïÅÜ‘å$}–èX‚š>œèù¸ òè®pá8—±ú@×:ÊÈ™Mðëê÷î(^v ëŽwãÍ@ÁÅ\7Á}¼ŸIî"ÉCõI `û»¤zÒò?u<Á mÏçï'’ò@Ñb{úuÛüXÜBò¦p/w^Ä©üiqç¤íq~p¤õà½ç6?+ÖòßÇfç?Tõã¶Qw½Kè¡-Dg›îžOô„ê·f júAu*O¼¦o À½Ê‘Y;8Û°!ZŽ¿Tp]ÿõ%„¡þ$Zƒ»-Vb6Õâù?l§?êPÔ¿Ç»î°#’?€Yã@<ö3è»ß³ò]ýáú±Ë.Ÿ6Oã àéqó$Gw4€¥ücu}£¨âKÒ”Ž›Zcð½Ç\NñÝ}Pµr‰¾Cÿ‹R©^Ô´‡:Ü'« Mˆ<¹»ûé.ÐX1€å07Ö —1°\jPÑ÷Šªœ"‰ßECá{Jp†ßG§n˺®oo뤡ß÷ºÞ…©Å,EMŸ`¥ p8ÚÔŸ–ð'Í€jú`ÀOÎDd<|-‰Ñw%‡)è°ßÀë#ÿ ¶ §Üu ÜE‚wôîîϬbŠuóÑÓæUfÈGW+xMßà›%æ"àOËÇÀÍ«îñ§§'ùÇç+ú¨¸|yTÂñ©ôßhÆÖ>û6:àaIìÁïÁ¢O4ÝTQꎶËïµÛñ¥‡¸²0D?†Öë1ö®æ)xM?^ÖÕ׎€ë2ÿU}T”q2 @ßòU¶§{h+á`®·ÛE/_ÕßÅ™lÜ¢sZär=1v=¾#ž+yžš¾pÛwwÍî›N}øÔ¸•GDM»Ç|°85þ¡ÅîØºÃê|¦fj¼!‘;>a–ÅÄø—G;™381N#·K7Å»íù¼5Ÿ·îs§””A-Ìðª~%Ó 3árîûr‚о›¿"AËå7D¥= IDAT9žXH¦>-¾µìxÉgI,Ó]ÂoUÿ :5þÏÑŒ˜nïÙÒTô%øœ[+¢Ê×Ç(¸çiñ…ÏÏ–|vX±º´‹ ôs¥­ä ÌvÿÛB%×ôe8·€Õúׯ@›g0-‘_¿ÄèñIqKY·_ºð¥ñåÞ¾[tÜŠú× ÿæ[ÚJ‚ÁZìû6àŪ¾ Cn,Áª…ÈýÐSÊ2˜ýCH%ü²è¤8ð Y‚|e þú¼=[öüw„©õ-Þypß·gkD«‚±~C±‚FÊÎ5õñÏH´Ól n"÷E¹“œ÷gˆ­Ý)y÷„y~ì‡è°Ï ¡] ÒoBýFÔ9‡±X8ŽLïÌø³ "?[ÿ‰VaneýÆçÂáÜìoëBô6lá]fñuSã¿Üu—¦ÍóeJéH߯‡O]Ç.èN”X: "Î9C 3^H)D©è;1è9ƒy„±»K%ÀrZÜ^\bš\{B|A¥£_<Úuœdˆ¾å_ÀœŸh°†sþà2„]÷m’¥¦‰ûà-ÉÒà°Rl'ÆáêÊ !-L‡/dé‚pæHŠ!ú%R8ÏÞ,8C KQç]?\9/Å $¯ªo-8êß“qÈÒ;H-ÂzZ®úFB\,šWò­¾†²^A¿„{ðür†dÈ2 ÿ/R mîU}—„Z@à?íKÚfÚ´Z„ý´¸© >¬=®S\Dk Ž»aƒ­Áç3¥)r؇4‹ ·Ù×ô­ít ²Î÷RÞŸåt‚*pÅÔq›@ç××Эó4Å‚XÓߦ°Êÿ—;Øo/ì™m`)-â¶îªþÀþ}% þ@\|„²¾Š›Ñ6¯ R<Ôbó»…OÚø¢>à\9àÞC+U´£ÍüyK8 D×÷Ê™vÆÿãNN£÷!¸r³®OñG ÷' <¾hg=G^/Ó·ø£ˆo)´‚¸"ü:0X@7H?â‹í–Z@° ßEÏÊpÁ„*\Ößž9øO àø³¸À‚ûb€¿;oOZÎÓõ»¸l?1¾PZ,tçû!¾Ùd'e}¿)ÝãÜ` aÙ¤.+ g˜\ÓO¬'ÏŸ*†ü· žÜ`¨>‡cY€‹î³%”…7`뀿d§ÔõØ âphœóƒÆÖQ¤)ü /ÏC׊úî ½ /@cƒÔ”køpºaÌm€ŽàÇx‚‡è^hø¯-a:˜ªêC#âk§­©)ÌŒÍGFð2FŸú;¼@®ï`ƒÇ˜$°å6k$·r+J]pA¿ê‚go‚_ÃÉùBz|y‰Fð˜”ðýGê\yÞM ƒ¡¤5ì+ÞÚz™‹ôA¾¸¦ËƸòn¬ß¬Qí„i *úi.³¯¹;¡®ˆI _ ‘ ÎÍÒTõ[ϵvD §Ìl©ÕpŠY¯¤rg ,‚‹ ¼M ’‡a|2m±eð’þ6µžÔÌ< õBj¸n‘d~>À}žm»"ƒH XÃÛh¯¨ïÿÑvìs øw2ÕšNĸKgnÞÅÖô],Àh*=·™ˆ¢%„U8ímPÄëú’h—³W  ¢§èo#Œ_:+&èºaú6 ‡Ñ>Êp›©h"…øý[à3ÝÞØ,H_(r‹)©ÝP}›(…x€-F±"Rã÷9¼*ðxýŠvs§/0Jß/§Âl ]1 ‘åX’ ¬ïqØ-ÇJàöËÑT`¤¼p¥Á´2Œ¿†þÆ«+™O¦¿õ*ºÎQÔuŽ!?Ί2x‚¡ú>QG+ZÌ»!…¡+A­†AL…p+ebr‚оó&bëëdü¬‡¦mÉb¸þ¶še¤``¼ )”2£G(ÖE,è©pÂÀýÆR$|$KIPÑ`ÞEè¶±NÒÏR[ÁªúÛr¦(³„èÿ-'øG@f ÑÿNð€Ì¢?ûá j÷ýZ ªú×ÈeÔC΢?óánͶ+Þ°g5AU߉Ýá›Í4±\*p>O5XÎýy'pÝhm?2AUh.Û17©èÏ¢?çá-_ÉÍ‹fP‚­ž ªï%Í¥½&< ÁŒ!úsNÐöí6‘æª ªú^2‚ø¶ŠÔŠr¸¤]Õoæ ÑŸõp‚¶ÍøÙ^5AUßIÊ`ÂPÊßeð€s†èÏ}8AÆOJÐå Äy˜’œS‚Ò‰1ð€ͬ!ú3N`Ê»FZñ¤ ²9µ4Á…úŒ œÕ 7¸ªïd¾ý¹'ðsåE HäÀd õ)A6Y“Ág¦ê\Õ÷2_ˆþ܇€¸âÁ-3"Á†ae¼¤¿=Çë’õ/óG«é£Ì¢ßÌ}8ßüJh›Y@ wÇ0¼M?ï S”ãiÞ ž=ZYŸÔPÒI΢鯎ÓPC…©q/>zJ'ÄQ¥ ßJ¸çKâ°†ë;~ÎñŠwZ?ÞH8LIPÓrAu$~þ%)L€·mؤç<¦[†§Æè‰Û¥ fUtj¼qí™pÑÄAPàPÎn@Šþ™Yð³O f¾i‘Jìq(ês~´àÝÉñ9`±H)ê’Ø*o! Ê)Bo„r@CMßÝ6è†g!Ú„Ýí#ÃÁxÉÍP}/¡pb½)~Gâ»'ÅDÎy6 ³…’x€>©aƒõ‰eçÈ´Ï<ôôn®ùœÄ}ÖôCkлƩl9¾es¼Çý6õsäí$<ØðßÃÏtÃõ½ž’¾=1~GܧEˆ. ËñþLÝ4Ã{˜ `ü/†ê#9gÙzâÙ4–\ ÷Ïp‰>Pœ¡‘ÊÄßË'qZýÇ»7ëWÏø2àü·ûÿ ú¤ÊŒÉ`„„:ØŸ ÿ¢‰ú–¶þ|–ù'ÏFÉÏŽ& ú/M?–_1þÞGV|ÛÈã~7ZxfM¿ÿoCIœ•‰x¸½vBDQ?³v¥7¥àœäp‘¾£Fé¡sþò£=2H‚GkúNuzüý _ X7€š¾/%ÀàSùçÁ” ´¨ONÐèÎçtž„®ûÅ—LNàk±¤o`ç@dþã91ÁÈR÷$"3XŸO£[€;`A?ŸUõóŠúÏ(0Q⿪OM€]ï¸èGRÂðý'4ª>Í#9ºËK·yë93Et=Îÿ†‚¾—?¯Pä” ÀhËpMŸß_=? t<Ácá|’!úM(Âä:ü&S¬Õ v@K¯,â±NŽIœp/éY(7wŽKý¶M YÜâ©bÎìùFu}/!~þi)òƒ Ô#€PU! ®Ȇíªñû®uÑ'°Ý@Ÿ‰v‡¢¾ä=AÎ=N°…da9Å´«[¡æÚ4á¸æ‚~vóÜpr“ÁHbKÎ,HŸ32V×÷â矖ORbmJªÃôù<ú¸mõü“B‡“LÞ¢ï'T…:ˆ3l!YŒÀ?ûs«±¥¼ ŸÜ]ðØRå3³=ž ƒó}”?¯…øûúºê}¢[8Àç /P}€²>üøž§I?âÅ !Ù6ƒ¢`¢aú4Ag7†œsȽì WIõ£<ìv÷NDøVøn÷0þÑåagKgÅ4nEfhjü£ ”ÏÎËýn¼ÄÐÔø‡R>†¨yqÉ@¦Æ­ô öÞq¨ .vŠj|nè{{š¦ZDï¿_»¸ó*¶Ñãó@ß¡ôüÞñÕBè×îUŠÜ™ßÑ6Z"pbÊÇVxéçÁ‹ M¯\Øþʽ¾ ‡ü•{½ƒDy 65n Hÿ2 >¯¸êÕJ‰ížØá8]ÆMŠC½„ÿüûx‘¡©q¶·ô±Ûò;OÿzpƒÄíÇ¥'Å1ûý¾H`À³ý~@þ—(Ý¿¤ß0€„mCõJ.À©q"·Çmùì÷óo/•PЧ *ú®økùJqùƒaÕÜ! x ¼Èß´¸çÏÉ!/¡ç *úÈ9ÿC9.ÝàX¶?L á%þ&Åß`,EYß—ÿu @ºÃ`T2€ÿœN'SGWæí?RñüááTÄ}Щæïø™g iü&8MQÖå_Ëÿ"Å; Fs x¸øúp2Í´y»—†Q?™7Ó›ÎRP\Bïw%:é_OVLþ7Æ)Cß)Êú¤üûJþ1(Þa0šZÀƒ}5EcŠé«. ü>_Ï)ë;bþ»ƒ8yœ%Ô;QK0Á1AEŸ¤¯ä!ƒù .‚™8þPr†R#8aðk‚3ó«ëÃW޽ܼ×í#Óïe|¨-|§úµ^FRE½3øP€ðkíä°š¾Mµ×ëd:þó'¹€¯à>¼®ÿÀ›“Yİ€úž3T«á½ŸŽ­éÃ4¬bE‚j÷}4 ’~Ów}ÕvH {HWL ÿ-z0€¦ehEŸ?µÆªðÀ À˜1€õÃ…úF…àê;\¦Mì‹ÐÕV¢€HPvÿŒ»žÝ_Ó·éjm€a—ðW{Éúmå¦O lÛuÞÅãúeøº^gPÖX¯N¥ï})2†z`Ùõ]ÊïPý3ax ðúÁìþw5ý&fBá܈H2<‘ñú놶ÑÍ:;c”á)Z×' ˜ó`\òÚS¨KNgQJú!A’A—ÝD&¸|‰ü×ô•üþp¢çÃ.ȃ»Â…ã\Æê]ÿ¡£ŒüÙ¿®~J+¿>3€¬x‹úJ‚¤ë\2)û ä©lOÿa§nš‹[èAÞòŸ“q*jœÄKÆ~eü—è{9¸äwQøÃÔ>d ëÛ›ïi‚ü)u*O¼¦o À½ÊÁ[;;8ÛÑ!š€­àºþWÔWö{Žô6¥)˜€®buX‚”€^åÏߟó_´€ôþîîI‚lSI…ÀåÓîái¼<=ìžäèì°”Œ ®oK ’èø€ð^(ÿ²þá@,Àk'‚zéþ}š¦¤ïž¸|ƒº,Ÿ€¹±¹Œ1€åR³€Š¾WÔ À2ä>IÜÂ=pŸö‡&+ã¢þ¡Ù{«ñÝ`´hAÎs(ê{Ò šzà p´¨?/ ,áOšÕôÁ€ŸœäøÁ.Ô#y ?XØã‡&/áŠ~cm¦¿wÀŽTÁ­Ž‡¥?®¦ï…&H1S¬»ˆž6¯2C>ºZÁkúØ-1Z>|ܼŠÑázz’|¾¢ŠË¯9~°»õ\©<Ù—¤¦¯¥ ×¼QÐ?÷÷°œgE? IÀZ¯ÇØ»š§à5ýxYsT_;®ËüWõQQÄûfðUÔ|&Õ5à‡Crí}–ö à„‘Ÿ}‰ÔúrÒ à¶O§æ„û¦S>5nåQ“ðô§Æ?´Ø['Œ Îgj¦Æ¹ãfYLŒpy౓9ƒã4r˱tcü©•ÏÄxb!™úÔ8ˆ¤‹Èmð™Qåëã ªçÔ¸"iìà³?ÂjýëW  ½5‘_¿Äèñ‰q2“Ú èôøì°j!r?ô”n‡þ!¤~Ytj¼ïËÅ35Þ$»GoŽCÜDî;Šr'95îÏ[»Sò::5Þ†òÒ™o’­G7ÇÝúBô6lá]fñsSã¿Üu—¦]eMã ½JàÄxC R³˜ÇØÝ¥@9-n/.1M®=5¾§›.úÛãÌCwÝþöx³ô8¬”Ú‰q¸ºòHH‹“â°”CwÝô7ƶœßÛ(Òã LÒ»ú¡EXO‹ÃUßHˆ‹Eâv%ÏŸû 145ÂöëØäœ¢©q+¶™6í£a?-n*¨O kO†cؾFÐÔ¸•„ '7Ľ¬ó½”7Ågyµ EDšáöìŠ2#hjÜÊN°ß^Ü3ÛÀâ¶îªþÀþ}% þ@\|„²~»-†Þ€÷—äŸnÙµÛÎÔú+àé–ЋõAvpr‚½Á•Ó˜u}Š?h¸?aàá«vÖsÄáõ2}‹?¨xOÇé9ASã)é@}jÜ–ðgq ÷ÅwÞž´œ§ë7v9qÙ~b|¡´XèÎ÷C|·ËOÊú~SºÇ3ÿáwsª ŵŽ~E_à‡1TÃyÿ úÝgK( nÀÖÿšPׇ3‚<îS8[G‘¦ð' | xºVÔwOè]x$6¨êo‡óë'Àà‡x‚‡è¾Òð_[ÂËKô¡ñµÓÖÔæÆæ##x£Oý¾@®ï`‡Ç˜¤Ð×ð¾‚_¤/Äô+øH}_ÃÉùBzøú5ÁCRÂCôlT¨såy7-P †’Öp°¯xkëe.ÒùkºlŒkÚ e¢0Hp2¡.è× @Ö—ùcú•ñÁ ë7¼†/…ÈΆGçfiªú-„çZ;¢„Sæ ¶Ôj8ŬWÒ9YÃË€àbsÀÒê%| ôo1€~„°¥¾7­áºD’ùùCômx¶íJ<ˆ "b o£ýY\x¼¢¾{üÛy°ÏÁ±X(žÕƒ½D0å_6Qßß.áŸê-Å ®J«pÚÛ$ ˆ×õ%Ð.f¯@EÿTÒçàÉèE<¥€Sþ/Ðï£ÑU*x© ¾åB}”Büþ-ð9oO«h(EÍDŸáŒÿ¢ àúì¶… ^pÄ.ÖE¤Æïsx'Tàñúíæ¤/0^?3i"Çã}F âÄ•‹¸ªŸÖÞÄüº ¤âäÎëG‘òNþAH+ÃøkèZ’ù´ú™hàJXÁ ý—è{p ¶}&ðý ¾µ1nÀ-«Ô¨øÐœ*7x»~¶`ñì¸x˜W?P}Xù¹@ŸÞU¢ÇᇎkM?4,ô¬¦D%ðé ùkJ.`œ~™@<\Ð3(ŽÕ·,wr)y}fÄý‡`Jpž¦l#胹cÆEÜņÈ¢ÿjúAt—ˇ{?jS(ú£ô‹.CÆÀ €ÃÍ1þs¸~Ý…ÛànýA §_"ðúMãOqPØñ1ÝRœxRâò}—¤U~ÚÂ#&YŠOXÒ÷þå/á²À=JÎX>íôàp¢/ñ7Vß’\<ôóJ&ZbŠš~¤F1|´½”†_ GU Ö·e¤``¼ )”2£G(ÖE,è©pÂÀýC”,–®ÃI·èï‹·¯=µÀ² ©7˜)Dÿoq8Á?2Sˆþßàp‚d¶ýÙ'øÛÈÖÈ|øŒ!ú3N¤8K2'Ûóù\¢è­8>2Çó?dÎýy'ðæÒ߈”­£Geø­8-ÇSž3DÞà œèË ~]KØž;GO'3üV½Väßâ‚3›1DæÃ ¬àJNß'™ƒãò¯À¿YÎ&o È¼‰¿G¦Ü\<'Ï?_ˆþ܇¸‚²óäþ…]w„§x¾"8JLý<Ÿ±’^žÁ.Ÿ0_ˆþ܇Ø‚rëå]ŸíöqDgøµ `kþµF†ßŠ;¢û·v‘¸€9Côç=œÄkc8sðÇëS¼—–Œß.®…n{à·ãÎRܶç$“Côg>œÀÒ좸îç{Џ†ŸãW7h·†Ÿ®“~3îøïSÜ@úø3†èÏ|8eyä@¹ [.žíû(P…ËÛ…í½‡nüb{¾ÍqLp¶ŽþÜs*ÿ9΢ßÌ}8åù]v¹døÛ Àu²MÓ[KY”ERÇ+8Tï ÷)z˵!›âæâ¹DZPCI'9‹¦¿:NS<@ M¦Æø<ŽÙe²e+XÇßÌ>г ô"ᯣjLÀðsÜ÷[×™¸ ©œ ¨ŽÄÏM6øO€·mؤç<¤[†§Æ­àN¾å·oÝ·oHpÏÑ ¿Ü΋ÅBãŸع]€·"î-'xüSœ{?#ðï}ŸuéÆi¿pºn×Sãæ?\$7OƒD†¿¤üÆ6 Á/6€ÅÙ’“\M4I{aŸâþÖÀ]Çðs´!ËýÙ¿º÷­l_}IáŒah=5¾¶üàk,ngj¼a›ªar–GϤxŸ•`Y,±¹xc^8þ¼«8ËøÙóëfwXø9æà¨·^Ph ¬C8§pr¿Ê¼ ,½œ_®ý¡w 9H«èÔx#Ee¨Àñ¾@¶$–8Cä‚_>{6 ޽ÎÃÞ(ÁÑB¶Vý •ûOÓ þÙþù§ýspÞ꾟 ôî s.ö’Érz|ɯd¡{SãRTŽl)ÞË4ë²°Ôv ÿ¾ èDœÿîl^LùµÆÐÿOÿ?çÿùÓ‰ýb'ýmg|jc'°€ýÔœbô­«"ÿ9}½ŽÂSŒ>fUtjü†`©M:ùO kx˜Oçÿ^삇Ç>Ÿ± 8=+ÅîMÏö!r®ç Ó¹~—þˆ²j›œ;ŒÏkxôÏkxä·q]@ó&ùì§…µPÄ‘r“­1•Pÿ“®H(œXEoŠŸèñB|÷dx\æMî¯n[àøå—¡oÕð.€1‰¼†/®›¢ßxÒmà¼õÍA:añó2Aï‡ù°>#¸ge"~±@[Þl³¢7tå5\ ØÔmÛ²ã÷w;ñé·ç0àF€öI!=%9|{büDÜï³6¾¿%oªá:žˆ]ÆÖßûó6Ÿ/ŸÄiõNoÖ¯ž?ðŸç¸ÝÿoÐï‚û ñQøó5¼ãü5ŒàPÅ5<㿱ÁþÑ-ùö-µ€Zü½¬¸ÏÙ‹€êN ϬéWãÿm(‰³2·×Nˆ(êS†%~kø(ñ”¹ÆßyûÅõðž@ï›Ñ ñó_1ø²XÀºÔô}üx)ŸÊ?î  d E}r~Šòƒe|”8Ò"‹îŠx`½hIü|.î€ý|TÕÏo(ê¿¿z~@éx‚‡Âù$Uý4i#h/ÆÇ‰¶-pü·È& Fá~1 f!~þi)òƒ Ô#€PU! ®Ȇíªñû®u)„÷ÛÃ@w XÔ?¸#ýíç½Þ_ÁÇŠ›ÄœÇã8l`_@¾,ÄÏ?-Ÿ¤"Ä2Ú”T‡éóyðqÛêù&…'™\¤°»ýþçßÙ 5|´¸™ -ÓÙÛ¸³Šî,nK ñóZˆ¿O  «Ñ'º…ó|âñÕ(èöàâO0œ°Ð$PÆÇʶ÷ ¼VìÇ)pû–„ÎblÉñÇßÈOy#üÇã<øG—ã[:? ˜fÃ­È Mtòùáå÷óà%†¦Æ|vò]ß=NÊÇ5/.ÈÔ8”XDï‡ êb' ¨fÁç4€ÏŸ]J+¢÷Žù}íâvÌ«ØFOŒÏkß?o?}ú‹(-¡÷Ž76|²‡jû*EîLŒÿ m´Dà”øg[>CÌ\¾ IDAT´ˆx ½wdåÂöWî5/À8„à¯Üëåx$ʵ)ñïŸ?¡Äúþqp'6nwµRb»§Ç?pœ® ã¦ÂmýøÍˆRBï÷òËGP/•ºÉñ_G7H‡J ðãX@+Û†0ê•\€SãDnŠÛöñ·sVªÈ{ÇCî©ün€ù›÷t®à»Åi ¹aš\~·ÀKüM…»òo¿ ä÷€ùc±X˜:º2oHÅGðã1n¨èƒN5ÇÏq˜"ù;IR¾kåøûñçqašióö»4ŒòøÂ¼™Þt–‚âúûôãO·µÑäCüññÑy·åc¿›ò1ï¶€^^l¾¼¼XؼÛ4ï®ïî¿»»³°y·lÞ¡€ïšæ ðåË ›w;7ï@À—/%¨ë: Ã;ÀæÝdwv}þL´-  ø§Oîmù5ï–`óÞØ?àeëŸÜò߇¿€1ôãÇOS4¦˜~šá’À ÁÏ×sÊúN£˜ÿ£Aœ'Ãûo°€GxþíwÃ?¼Cmñ—Þ¼C)ööûgûþý èÅP~×›7à ·_ÝwÿIp÷åóöKÿrÚw`Þ =dÐ}îú»/`öø‡wC°y‚™ö'¯m†w°@zoC°}7Ûwÿ}bÿäøÿðžò‡’3”âiвþÑ®ó'üH N‡Û€lá ÞÁÀ;Àã#¸€—Í£+>xïÖ^Lioï_ ðÞƒ|þòrç(„w0x7` 4p÷żƒÀ;À­á¢6À‹­âîžþÞàà ÞÍóÙ'Þ~òûK>û¿€3d©9z‚s7íy’¢¬oQÓø1ËßÀŒ ”Ác¯éçx€«·ë$¶ pïÖC’&pç@í»m!hðÙº]ë_]ð™7ŸÓ&œú÷Ø|†¨Nßl± øÎšÛJÑĵ Øl÷Ío¾Ó&pø ¶î/±-kÁ¾€DX l:QàËŠu}°—£é„}ÑQ!@ ¯éçx„¡4¶L>céûGÀ±†ƒ‹ä x p`%JN©é¯zËÿž}FpÂàÏgæWׇ¯ÿ°ïb}ôÞñ@àO"Býa:ð¡á×ÚÉ`5}›8j¯×Étü‘ó'¹€Ÿ?R>DÿÈ›“¿ó:ò9­ ïwôzýÛ1]19þ[ô`MËЊ>$^ ¾hT àÈ À˜1€õñBý£Q!8Ëø»+Z<¬‚¼wİK ø§½Àä¸n[¥éSÛvwñ¸~Ù~®×™”õë5Ùø"ÂËç½ãžÀ#‰@†'2^ÝÐ6ºYggŒ2"^o\Ž6õçÅ#%üI3 š>ð“3%~¸\<ï7ÅúãÑÓæUfÈGW+xMßàÇKÌEÀŸ–ÇŸ€›W1:ÜãOOOòÏWôQqù󨆗d ¡õzŒ½«y ^Ó—5@õµãàºÌUuü ¸m8Æ÷M§>|jÜÊQ8O÷˜§Æ?´Ø[ Œ Îgj¦Æ¹ãfYLŒp9òØÉœÁ‰q¹åXº1þÔÊgb<±L}j|ˆ¼y“âeÂg`ET9Âãú8…ê95>@^Wm»šÕÌÍí3L“ûjýëW  ½5‘_¿Äèñ‰ñº¼ÚÀ&kzš× k¨e߆V)ww÷U ‘û¡§tk<ô!•ðË¢Sãuyõ¿@¾V« e¨l!#äu@ÌäÝÁ¼!rßQ”;É©q†ØÚB×Ñ©q.R!¾úÐFdè-NºJ[°?ÅŒº»‘ê/a ï2‹¯›ÿå®ãß45Îäuµ- p Y@ô­b!M“žñ•—Ú"ÿ2ÁoË¢ö Æî.•Ëiq{q‰irí©q*¦®‹¥ìœ¬RƯ±šd²úë«Rü`[E ð¹«.ÞÞ2:=«Nï&,ý+%Àvb®Z~  >5NÄ:{±__ÑRˆŠ×$ÊèÔÌÂb­æØIG¾ÌÜÏÞ×[@!/g*"´ôR‹°ž‡«—‹¦Æ© r ðcTz}]v ®7 ºÁ‘çi =ün‰wcÒ,Ñ*›öQ‹°Ÿ7Ô'µ§Æ©0†…Á•à²ý,Aøžò_2)Á£$Êeü¡:r½6SP|”u¾—ò¦øüà…0l}~ê|È’ã-p¬u9ˆr›ÜüÕ?”œÝ€þ¤ø,,`¿½°ç¶¥´ˆ Ûº«úCpHû÷•6øqñÊúuœÎ¤Ã¶©ð{f´œ=!…Q8ä¢ñ² üÊ39ŒÑØ ‘ê1}Õ ´g9þ€“äè}@®œÆ¬ëSü¨áþ„ãOí¬çˆÃëeú?–p;#ú± s#ˆ¼à kàônšzW¤ßÞ>’ûPò…Þ>ô=ãXT÷ò³1€?‹ l ¸/ø»óö¤å<]¿±ËñˆËöã ¥ÅBw¾â?~d'e}¿)Ý㊠ó=(4cMj†àP¹^‘8:D7…ûK™¨ïi€Ëæ5Þ=}ªàÌÍ[Ý^­ÈP°Ô­žÅE÷ÙÊBƒ0€uÀf§Ôõጠ»@ãü0ÀØ:Š4…?aàgÀóе¢¾{BïÀ ,RØ–ËÒ9P4[ôIðJ(vÔ„ÂÖÅ–Úh_Ÿ‰%´‚ü[z_õ& {]ú!(šÀS‚íúOð]ÀOþkKxy‰>4"¾vÚšš= 06ÁË}êïð³àr}ÿ?ðé@\ù‚XOþêÚ€´ø püÊÚˆØQ“øWdb}7P/ 8ìM:h(è°Dèv®ÎeOck89¿C¨@ÇŸ?£“¢´Q¡Î•çݰ@1JZÃÁ¾â­­—¹Hä×tÙW­ŠÇ7ì&=à îû/:Ô4YŽ+Å-¼ÚÛ¬,ùb‚_Ê­Ó»ÐûÖæƒº×¬§BkøRˆìlxtn–¦ªßBx®µ JðÀ[j5œbV„Ç+éƒ,¬a‚e@p±ôFq~ÀuDZ«ûدq’–väÒÁ@ip }²¥>Ë;éÍù³ûò‡2͈ÔpÝ"Éü|€!ú6<Ûv%Ž"ƒH XÃÛh¯¨ïÿh;ö9„ ¢Xò ,mÇ‹+Úû2åçótXÖÈ¿¸$÷Ê&¹'0|¹´ iýÉ'ÿ’Ý<}âô¾ì©„[¿ ó’¤z硽MâŠx]_òír`öŠTô}"àÕ}mŠC}> E½J‹Ýé,AKqê¹ÜèQ¶µxWeü÷ã ¿ÕI'+ã­íS§7,ÄïߟùöDl7ÐPèX…Í®?¸Šk¾¯«ÄñBw°‹‹¼¬Ó1¸÷!Âø?>N»nñ®ø¼ÿ¿´7L, í¿ªV‰E¤Æïsø‡8ˆ«_ÑnúñWÑ'òšm¾‹‹ý~Ž€,îÅ™!Æ@GTCNù rØjXl¯ñ®ò’Çž1ÎeYÅ»‹.Àpüp¥Á´2Œ¿†þ¯®d>¹>—WV…p6€MÊ&ULîy±’šÞ×UiÚ–:÷M™Ö€' ’çâKP«aSáÜÊ Æéë›Eå#ô3y}]2—™uîÙš/ÚHF0©“ù,üë²Ä>]éÅ{®ôu¥×‚u x–OOÈ_SªBãôËâ႞A!@p¬¾ ÉâOîSi_•öþ£"~@e¶Nº§¾ÜçD¡;I]€NàryüÝO ÚJ„þ(ý"Ë10( Õ—„ÖðÚζ×&Îà íî%³Æž¤´ï¨Iû#y:Ý…Ûàný¨Ó/x ýÑRÛ”_Z¾ÍC”Ÿ"ü1Ê_Ãe=€{”>œ°|ú¡‡}‰¿±úÓKu¯Æ¬Oe¤``¼ )”2£G(ÖE,è©pÂÀýÈß!¶°„΢ÿ·8œà™)Dÿop8Á?2[ˆþì‡ü#Vf ÑŸùp‚É܆÷©‚Ï¢?ïá7’¹O%ú­‚Ï¢?ïáW’Z ÿ}¢û¢Ôjø¹‚Ï¢?óáW’ Á?þ5± ¨üÛ¿+.`¾ý¹'(½ã¿Ê ~ÿZÈ RÃ?ý»œàüo´%Ý|!úsN0PÊ5üø¯¾d?~7¸w>oôåþéß}É~;üì|€â æ ÑŸ÷p‚Arü½/.x4üö†a›B:ÿä_ÿ—õ?oê |:÷gàO†ßÞ0lSdÉ>ú-nLà“nI3†èÏ|8Á0줄ļµ30ØH ‰P;s†èÏ{8Á09f8Œü+ЈËäSöÃÈ¿Ò}€ØHeÎýy'¸Lþüe­3à+>í ¼Qþüe­3à+>í ä5”<|Muœ¦8B M¦Æß jgÀµÿ´3Àå÷¬3ð&Q;®ý§.ç¬3Ê‚êHüüÏdƒÿxÛ†Múp~À1Ý2<5þ&yãpÀ&ó^Ôá€è nœö §ëv=5nþÃEbqÓøÔø›äxõ­}€ oœÀ«jà§/)œ±3 ­§Æ×–¼bí‚ÅíLO"ÿ¥S‚ ÷«Ì?KÆ_/§Æ—k?AèDÒ*:5>‰ü—. ¸ØK&Ëéñ%¿’…îMßVœiÌ·,èLCu]ëªÈìGÖ'ñS¸ˆÑǬŠNßTõóm pÔ‹‚FÏJ45>ÿ\CþK?H(œXEoŠ/èñ‚“ž¿Žü—vÿ@Xü¼LлƇÉÕV„ß(W[„ô”Äò™_sàƒäj+Âo”«­ 2<þ^>iÓêoÖ¯ž?ðÇ€óÜîÿ·é×å‚aáé&œö¨: ÜT'›zü¼¬ø]9dã~há™5ýjü¾ %qV&âáöJùÖô‡È{öŽ:=~þ'_ X7€š¾/%ÀàS¹ç  d eý!òŽûIü¼œàØ”ÎWpªúù Eý甘(ñ_Õ¿†ü÷Žbü¼B‘OP<`ÃÕq®éóû«ç”Ž'8Î'¢ù¯ñóOKùL „ª u}ð@6lWßw­K!¼ßúCý­êO/ÛØ?ÿ´|:JEˆ d´)©Ó7æsôqÛêù&…'™¼Ir™o؉î!Bü¼âïèèªCô‰náüŸƒvÀOùêúQÌð0Èo¿}Ú~®áŸñ ÿ¦áÓ=ñ5òïû«<ÒŒÒZqEúÛ§´D3ü³»Â¿éøÕÿâëæß_ã‘æ”¾×p32ü7V¨ß$ÈðÏçÀ6ù¦â#þ6Y®›_Kàè.^)©N *^ò9ÿ;²'@‚>ÿ;|÷ßJøèLåºù÷µ{ZÒæ£¿TÏ}@¢7qh©·O¶¿\9Êžh)þ™\áßD|ô¦rÝüûZ‚½´,x¸’¦M*¥MZÍÿb ì_Ã~ã’÷Rü³úMÄG?`*×Í¿Ï/qϺ·]%^ç}ù'̵Ñ7S©=ÀPg’Þj¿wÏu¡f.Ÿ>1þ2ÈðÏñ ¤®àÀUóïÇ\¸€,"Á{WÒÖˆ ìûÔhµ Ej™Ÿ¨'§Zä›®KþXQ¶Ÿ˜dÃÀ ÿ¼e©+øpÕü{x!\:{¸àëýž˜ajï¾ÇNœ£ß{ ¡}ð¹S?îâòM{uI{´€‘¿‘Ï\jxšºKù]÷q¯bPŸÑmÇo¾¼‰ôÄPàÚž0‚̦ w.-š‰·´{£6énÂM’Ü™²Ê#ÿþaRbö:PÓšÌÀzW÷,›þR,v÷5µ§à¨Z’é3Àµ=©³ØHPÓé Ø'¨†|ÑÜFþý%Ÿï Pm>plþ ~Yþºô®ä`ßMlÚiOmÂUbÞ4÷=um`ü>ÞÊ>@Lܺ[@Ó$ücRïKFþý%Ÿï Ðo•ùÀ±ù+øeùëÒ‡Ât´ ¬gMÊ>0Kí¡iÓ³€–3šñßL±E -ýž>ËØ?ÇÈ¿ Äù¾s:XüÏ"æëÆæ¯à—å¯K¿µÒ{tÞЀP‹3é`Ĉ`+O;È?½CO“·òÛ'Ï@mð¶ Í"Ú|àØüü²üuéI£l‹¶ïyžÑ-¥ô{Úr·Ô¨Xá±ú3 yr ðž©¡£þÌú›€:_ø[e>plþ ~Yþºô‘°€~ßsÐþE!ÓB ÿÁWøÜ?m–{°€›3€0n`îÅ&ù÷”|¾/@¿UæÇæ¯à—寋/O?§ƒ/ýÈ€çÛðÐNc*R£ÑÒØ-ÒlCîÞ®œ u>I?òï(ïÜÐ'·Yý· $Ïø@MøÉYÚÓ~&ŸïSìËæ‚ùïÑÅdp»QÀ{6€}4€|¯§n—ðuº “r*ÿ¬uo’à,iò½‰D¹Ü®ø‰—?3;ÿŸâáÊØüü²üué{ê„ Ü¤OÇøO;i…{jÿMN)iéÁÈajûÛ€¾bÍÿ'+cóWðËòץôV ŸÔPl•é\ ¦Ivâ(ôJÉð…sÊšú}0r?Ö”y Ñ'`Ý·qSµ5½ñSͪ¤SoB‚È\(&j(/qQ(tØ|‘6%5´õ~±‡ðO\¦¼• ’ääh‰Úñ×2€Z5ÚKüGçêIë°éMq‘?5€Ø´´Á ´|ª9t&<ý+ söÒþb—gø‡í8†o#Ÿ¸—i‰²ü‡ÎxÛ¸X³Ç±zëVpŠ1¬i÷‰Óßq\ÃG>q_K°§õmØ–­–(øa¢®g‘8ÿY%«ÿßÍøŽÝAxBðE;ޝ±XMp¡¿¥ž›€bú}dŸ.æ7Åf†d¾¿Õ<ÀPá;váœ`õ›Š|â¾–àòÑVä²mí fô‹ –3Û\ðw3¾cxNÍv ó>ò‰ûZ‚}{!ÿAÚA%ΟÎüºÅ[žl:Iv ÁK;Šk;Ž·W˜ ¬%UƔӞeVÏ+êo{°É¤2E#Ìá ™ì™r"h¤þ?r‰HäÍkÿýáá7•¿¼hð^”ÿ»ðò¿o¼ÿ/üâEIp·ñr÷Æûlù#/ÙÀ_‹Åh ’ üïÏŸ 47ÙÀK$^²//h ’ Ü}û¶1IŒ<>þc—ËÉéž© Xú#øW’þ/K?1ÅBó#²¼¼ðï© Xú#ø%Ioé¹söqgm@ó#²ä=³ö¢ÎÚ[å6w©‹p²"#ðgn ôÂGCxb YÀc~‰¸É „^xùfê<5c—X@›MÍ´dZfx>—JK–f5ñl+B t8/±€?~ÿ™¶ Æ.°€t‘øM2h/ý·´MørwÄØ8·¿ÂÍâŠL±ÛÌiÊɪ@ùôõ`3þ/³^@àFL,Àøÿ¼OY€^À¡®Ç”~Z>lÌÀ èTíXAúÃrô52}“(‡{ X( ¼üešêáð¢žÀG%·€/ß6Ò¸ Z€›{Ký9™œÝïÉvá6ÝÁA/‡ÊšÞm¸kH2 ÛxVCrº–¨ü{ ÐøG ùw0äþ*ÿÞ4þÑdþà¦L\“kcñïÉnÎ×&á Iw‚å«ÄqÊ?[âÉ–˜Û&µ3ê}nÞ+¬À_%ø ÆZE70d4X1€/%ø €ÖØy1£A,ÎÖ„e_ç[\šw:éî?¼j+o­ýÞ6„¦ÜÙýêV2?Ó°ÝÔ ü[ Ðùw.@åßZ@ýþþ­èü;ðMó[„PB„ZÇ?rЦü“F‚ì 9¶Áˆ¼%}„$5Ð+ìŒ÷I3™ZŠí4@!5mbp ûê`…Öô_˜„¸"æxhÙ&LÊ Ò@k¶ÅÕî°ÇÇ9xwIàš£¶e&ý~ ¨À_:¿¶ ø_¥ààm@žh¿~1n^O ý¾ï¡ûèÉ[Î8%…óÒ§ a—ìò Ú¤sÙâþÃüV¢M”JæjRé¨ù·— ¤ê*ƒõ"ÿ–âǬï]êÜî_ ã U>†~aìå%¶ -møÔaÀ{—ÌÙ$w ÒÓ«ÿ€…ëPò‰´>6Ù}&99„ìR¶GÐ Pàž†ñOî%ßvfà¿ÞÊMŸc„¾ï[á=­óФü‡ äí>¯£vsx°Ú½D>¿%q ìžZ ÑõåC€ïþ»?¯èº ð{lÃs†Zl_öi§½Ëô²ÍíÃÎó©åc9" M:|¥¶€ÔÖà¤m½ÌïÇüû’£áÐuoÖ ø`Æîx ‰ Êj}J\´€^tÑmB~4§’]L[:ôøÇ®Ü ´B- òÏÃ?i¯O¡O^h¢g‰ÊiëÎèNû„¤q øï7€áÃ@/mœwcôÂÅ8¡ÃB>oêò!ý=Ötdc=:Í@VŸÚy:µ| ‰ .ùDMX0jš¼«`L©]4´$Ú `m;%;)¨Ïó70€¦l°V0íTpÙ`³ÀЩàTÚ$øJ²€àö¡÷Ïkª˜¯§›ƒ=iÚcgc§š1c›Žå3wð_ajP1m±&éû=¤ Lí+Ó4!ß8Ä5àhtV±%/6M,%‚›b/À-«0p9¸DpSì¸å`µ °ËÁeIülè{µœ9·zÜr©åKVžèr3a»eîž.JE ò\C*PpnCÝ/ÌÐB*PpnCˆq… !5!¥¾¶¸M¨5wOÖkô³ló 'ÑÄ|¨P¯4ïd ôîÞd ¾%L'ؽé5ܽÉpѶP"a ’¿Æe¼ h“Îvûè¢oâÞðà#D#?([¾Â¦PÉ.ÙªŒ”-_ØÃ-à­ü£ 1¨æëYíIm6°'H¸ø¶»Œ™àøQÜôw pÙ¶p™àøQÜôGx‚ŒåŸñ_ßJ íZ„ qûÛBðö»Œ‰`úE"˜~saA¼40D"˜~yI#…x`ÈÁ CD $§¤ &0Aæ×‘œ`þ='˜'_@`àˆÐ°œ`þýååK)4ìËG„†Ér½ )Ôíùª»,U‚C9Áypèb1.8ôK%8ô奺Ùü:Vþ ÿàrÔ ÀÅ^jbÄaI6š¸ñü¥íŠ«;l7§oˆ[œ³I×el¢š³nù o‚ìýÈ?Â-ŸöM2›£iøã¯cï)Km€ô|€”Ýü|€Ý0yù²é=e© žÎñäç„윆ҕ¼ÐA')òå¾Ú L'ôù="Äøü½hoµ ÄÄvêaÜŽì|p »âù—ðo;u„0nv>8Š„]ñ|€l;¡(¹¾Ï ›Žié8NTÏ …æK¶ ÉàŸãæü_r>€åþ¯c¸p¼ñù–û/q¡w3à|7” þ4oíï÷Äòé¸d(Ÿ Ÿ=nZp SÁYépñF¢€×ùùØ#ðßúãdçàu~>öü·~S? !Âp,ìÍæ[5’ç ãvÅÚ8w ÁÜò@¹ÄÙ¡›òÔÏ@?_>à8î|€~>úùòù›çø6^â?îIøÏ7|…™Úºä«Ì‰ô}r’}¤ÿÆü÷G=ú×ñ?éùP5Ì÷ôÆžÐø½X;SIzêr°½@+ã?O&X@ÞmµÝæS‹ÎÿmÎ(íÚºÂù^¨{N%íÿ«û½¨hÏä, ùyº¤‡z‹\u!n(ïû|/Ž:ù÷C¤ ¸á7l÷+[ôôòf† Cû´ ‹ÁIrrù ç°9IñfZè¶1¡ÒE 7Ê›qj¹`ûÄÈ o!“pœù|€ ßØÒŽ—Ð d;¾³a3HÉxê$þ±':ì}ø§½™T·…æsJÛÂMïò:Û ûºJÛÂMï’o oé/ž6qÐùHqŸ€Ò–øß‡›°ªNž^½TCŠ3º¥ÀãuC’9¿ V7o’À°_¿É6[²&ÚÍÔ¥´°70¸€üŽ–ätx‡P0Ou¶^@»áŽÓK=2¨4£{‹È ÒÎ΋BâdÛ­‰Øê-­/®MÖ¹.‚2Òܳ€<]ŒcÌNNvœ98t“®âp‹¶< Þ]pÐ1²OhÀÓ”r÷ Èº˜¨¯^]*‹v7ðÅÍû×õd=ˆ]m°ywköùzaÚ©ûgy æ‡ÿd²˜ŒDñ673€r--Àñ }€b'¯b›‹Îh±‘Nù'c|¹…¦kx…À§ÍF‘>{6Î ÷Å'£ÍL(c<¬#Œï¾ÝÀ:Â%À¦Áí9É*ŒKºâ$EhÒ-[ål—d˜—‚™µþɒɈÿ‚>z͆¦>`㇚ %G…ºazæØ_œ &µ—p£uäº-ñhû6¬J'Fv¹ÂùZ+r«ó´V$9ʹ–á÷± ù§ÛÉ7ªh«ÅÑÃ`BªâüL¸ÇßÀŽƒÃÃ0r*x3ø|Ťááí¾z×a–'¬Ñù‚sV¦ë…!F’Kn­ß‘Ô ¸á¢ Ê¯Ý :ãùv+èUÏhÅiš6T@Íø:ÖͲ–‰¢hS?D óÄ·t¦W‘›œ ‡ðl®~>€Ø>ãf?ݰa<@>›ä¤4B.`ϦzZ2HÜ3#»”§úáåMç‡n)OõÃË›ÎØÈçHk,8Ã'¬ÒÓDÌ\ –gƒ Ì `3FmÛòNÆíøÇz.ÊÛÏ€¥À›7SœKR|°HîóÑ@Ãüw˜V„´?‡÷òÉrä +–§ÜŒ9`0ÿ –§ÜŒ9@æ_3€8ÎWZB‘õ~BIè,ô{éYäéà0ÉÀ-mà/©)¸ÂùCCC¾HMÁΚáö‰¸k o¸ûÖ'kÛ^q >£l6(Çb'CÌi&s£P‚mÂAç û’{€À(ô|›pÐùBÿ¢+¨o‚IܬøDÄ”¹­`S É0/`¼pÛf ¯ÁÈc1l›÷ì|€£x>Àðà°ü|äαÏ€æ}èùÂA±²‡0t¿´ôÛ½7(fë•üÉdÒߨ@i81‰$çÄÚCƒ½Gá|“úÊçÄÚCƒ¿á|“zØù…IšØKzøølQÇ꺹>×ÐÆ½lšáÖÐ$çÂBx8¤¾îùB§°©‡œ ÏÒD°ç|4\¦§ãA!%û–8ÞÓlC¯’†ëSÊÊ¿ÏAÏÏþÏ‹×~û7&8øùùp ®ð3Jß' Óttœ§@dI¬U tˆ¶×_Ûο¡ž-¹ÏÀ3^ûôù}@Ó'ßõ&€úç}­ ðNû¢& ºy>ÝD oŠ&àüÛ''Àÿ³—ý³¿¸ý|>ûÁ=X@|{g˜Qúä»ÚI§ý3­¸çi¤¿j`Ø .€t£ã¡Äká—üÁ @¥åÃ3eÈê¯ä¡uî“N9·qlÁ6^©H àym˜Î `¿_‰ø{3qžFšŸ'‚özLª¹¼úúØlqŸbbWš ð}¿þõ Ø5¯ûïÔö’È´,sß±Ÿ&¤,ÖÛV²€Ö/ 0¸ÞT0À÷ÕzÝ÷À.¼®¾§ð}½þüÙÑïßߥ(3Á{²¤u½c.Èp‡€†)G²ˆËÑm4€k.zøn  3Ô»×ïßÿ1¼è«`ѨðM¸Ò˜” €.'в¿ª 0Ì»×ï¹´mlÚÖ'x_В߇aWã,])®Ãž!mÙp_ê»GÀ–“Û}Öɸ¢80|~7€%°k^~}G‚?˜h-@KßG(ûÈ ¤…¶óÆÅÜP‚m›f@ ¸ìU…€©üK#Ædð¯¶=Ÿa^¨mýz L­àåVwd˜犄dÖ.ŠàïÐÄ Ff±‰¹š ˆ`-À6–ÿgú&.fRÙÓ€ÂK™Ù „ÐãpâÚ_ˆ£žZÀ¥«,ľã0ð»d ZùO øÕÖOßf“AL5#Mbþ½›"”ž„l)Šm¿‡ücðð“«À«qÿƬÌÛë4뀕Q€vë4 „kEMƳL*óRäYœ òúäêîÔ‹%ÀaXL`iÞö‡Ôþüópø3|~wÐ(€Ó´”äÄèj¶gg”)œ¸ïwÛ€TŒ¯æpxØ??¯V‡ççÃjõül,àÓ3€F Ýn°OF¼|J¬÷æ@Ù'ØÄì÷a-±Ig›9ÿ{ÅX/oްj@ùós4XþóÏwg­^¬Ù¶ìÔp²®ÐOt;KÕ‰¤àÛ]Vòý÷ðo €·€en×6ƒÇøç<ú©"niûÖï-VóG"Y€oöx§ëÍD8Dp`àèçM€7we>¯ÜB[ Spˆ–îÊ -6ò Ѿ%MHj|» )Ö,ÿ‡èhÉ,É­8[¶„";¼ôôOÁ8\·€}Ëz‰àn³Ð=hµ¶äb‰°Zå.À@J4÷eû^¦‡8“[–Rj,nk[ÞÌ@§½–ððŒàßì…eÈ¿0JÃ)ÚØÅO[è`jfsDëp£P6™ÐòF¦M àºSÁëuû‰z{ ¦ÿÌ®¾#h s+ÔճɦëÓa‚K³Òº=·–ÿçø$Ñh‰p òá Àá*H`˜ÖD7‘Þ½ÆÌK<+°åZYê®E?@ÛºvÀËÁ]I6…‚|ÿîÞ?½³ !í>Ÿßi–€hMlâKü·{Ñ@Rþ…^@»ßï%ï3Rž@Ø íºy=„KÅì,°²#†ü%:¯ÄûðceÈúðqÉ,€§˜Æ¸ ÁÓö¤rf=¼>nË/X@‹SD EØÓ÷sF¡Ùï%¦[œÿ¹Z÷ÏÉ?ÒºyÑ‚_OÚ蔈¶LéííLŽ4Ê‹üïóŽBLàªð€>|VÀÄöq( ® ègcùpK‚PÓÚc]ϲhéfÁ«È?€úaâRÏ>ôõFºL?[ÏËÚ޺Ī.äÒj;—Þ(gC¢•§åòù°Ünáuùä/‚øO+úÿ·ÝþßÿÁ'Äß´-¡(Yꉤ}¿}šªØ;Kæù4(@+@ã õzðÛg'O°tùD>8yß@ÂÃiGœ0ÖEâB#MµËœ´Ô{d+ á¾lÛ ÍÕ» —ÿÚÆ‹E?IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksEMC.png0000644000175000017500000004522013263214224021536 0ustar aeglosaeglos‰PNG  IHDR€¼AKÈ“PLTE™™™wªÿówªÌÿfÿ]]]™DL"™™Ìf333NÿœùÌÌDÿÿÿfÌÌf3nnn™™3ÿÿÿÌLLLÿÿÝ™ffLLÝÝÝfÿf"""L3ˆÿ»»»y;°ÇR IDATxœí½ {·Î5J¹ò©ìÈšúmÜ6M¶«Èj¾-;’÷ÿÿugðr@’,kbOkf oX¼‚7·o·Osü÷i;Ÿ?ÍŸ¶Oð~ÁÇâîÄÒ ¿ŠÜ7ƒØ/}Æô¼÷¼ÿчÐ;ÃPú[t?çÇâ‡*Ö*­ð«¸à¾†=}ÖôGüôqÀÿ· OÐSóü`Í¥~Ý·B1§ÏœþˆCa¯1€-hÿ…—Pè¶Çâ‡*Ö*ð«¸è¾ˆ9}Öô']Aá?PðŽÄÖ¬Qjá7pɽŒ)}æô'|•¸{"eÎ1$¨bαã‡Y/â{ktO©Ä¯Kî áTÒŸ¥áAޱ{š^`X8¨f|2ãŽRBÜ:·Óut ‘ã×ÄE÷Z8µôµqþaÀ·Ôl{F0§`%Fú6Ö€‹¡ îê ‘k÷>,R‰_ÝëUÒ_~ÔÆÓ‡§&{“Ø~Ï}ïʶ'*š–s2øžð":Ûùñt-~U\t¯‡SKᛂGI85¤ÐJÍ©76Ç[R°‚cìúÙ¦aêÄ9’ÓŠ Yªñ«â’{C8•ôŸixò/àO¾ÇjtÌ+èË“¯ÊÚ¸qïž´€{£ÿƒøUqɽ% cü­é‹øÜ·Xl0«@_÷É{ó´Õp-ÞǺ?Ôÿ.º·…dŠ¿5}Ç‘Û|î[)ê¿’½cNGÁµhëþ@ÿë¸àÞ’1þ¶ô% Ul]¶¾Ùo©;Ey§‰« ÒÜÙ­ù_Å%÷–€¬é·é'ásâ+TöØz`¿9Œ³JÜå¸oÝÿ¦óÃü¯ã’{-Œð¥ÿÁgî%âTc‘e}ØÐc"V†C~?®EÛä¿s¢ {è—Üka„/¥ø¿ÓpŸ¶€‡‘3E;[d;¡15æ&Âó^¼w©7ªÿÆñÿë¸à^ Ëÿa„<~çñ­o1¶dÛ µÎÓ6ÌcPØâH·´,бÖüg8³L<…yý¯ã‚{- úPŽÿðC þyœFâÔÉE£Ž¨rxjwÁ±Å†Òô¿ÄCb á7üoá‚{-‡u¶M?VýÜ[õ·ÞÁSø‰%D7Ré Rüâ7cøÿ›øÐ½„mú±ëÏãÄ)Íã̃Ʉfàžì}äF0Šÿdž/»oâ’{5ÆøÙãpªÙ¼¦ÝhJ_¼Šÿdž_qßÀ%÷z:lñ³Ç?â[šå'+ÎÑà÷ÉOêQS"žüš‡º€ù¯á‡ùßÄE÷J0ÖøYãŸðÀ,}9ÇBôŒp¦¼Ñ–迟¿Üþ«øaþ7qÑ};”jüòï4Øñä§Í}#|!~íTTã7üªŽ'Ñð߯,8÷ƒÄ95‰” öÂZ Œî[á—ñk'¢¿ì; *øK ZП¼!Æç¾JÞ†I’}p·ûVøeüÚ©¨Ç¥áñ» ÷Ÿ”+Œ0ná×1ø©å°ø Ük²gú,é ¸}<·h òÎ1Z4<;?µÔïâ‚{MöJŸ1ýO¡™šûõïÎWJ[,²0ûûø©¥~Ý+aØÒgNÂçav|ûäêsKƱø©¥~ݷ°§Ïšþ„o\ÿ¯á{+tO©…ßÀ%÷z0¦ô™ÓÏq²±Ö׿ïŸa@%~ \r¯‡r²ýÎOu>‰ëß÷è ;ZÄø5qѽL-ýùGmœ˜p, òúÿ=p1úÛØð"Ư‹îõ`ªéÏ?jãéÄoÉ‚äÍÓåúvÞÜ€îÙ‹‰‘x%~U\t¯SMáYÂôçM¨Ô|<‘…Â7%Ø¥ÒpŒ]C?láÍ6Ô‰a€žnUªñ«â’{C8•ô¢áÉ¿„ShN–Ôbý»×dNËcvoò¿*.¹·cŒ¿5} §V£²~߀«1?Òýaþ×pѽ)[ü­écúõ¶Ql¥‚…Ë÷œ" ×äX÷‡ù_Ç÷¶€Œñ·¥ãóÔºy4K½MëÛ5\ø‘îó¿ŠKîmÁØâoK×/òL»ØzЬš¡—øžû þ7]æ—Ü«a„¥ø—¢á^ÒþZ„s[oöÆÂ±¥åJ9^îУmò¿º?à`ÿ«¸äÞŒsâþé; 'a8œ©éÀÎV˜ÿ‰ù¥¾?ÀqÍÿ€áÜ[BqNÚ |¥áñ;o}‹ViÁsÊ/¸Zɯ¯íÐc­ùÏpaÀ¡þ×qÁ½~(Ç(ü ø“_N7÷F‘-MuÏçj³5Õšÿk¿á Ü›‚1êǪ¿„Këë©É²f%êŠÿ%ží8Ðÿ&>t¯bÖ]ß’•Ã/|㏾]™!îŠÿdž/¹oâ’{C(¦øÙãŸð­/0[iý»1]4ÿ _tßÀ%÷–P,ñ³Ç?áØFy+Õ ö0ÿ¡¶}ø¯áùßÄE÷Z(ÆøYãŸðÀ,}9Ø ¦_“迟¿Üþ«øaþ7qÑ};”jürÑð$ GKáÉöÿ©wŒÕèÜ—QᅥæÝ+¡Xâg?Ç[ûôäëÒZÿoÁµÎn{€„‹îµdÔãEÃy ,ý­ýZ¬ B¶Y†>ùÉ‘´~Þ† žêþ7q)~ZB*ñã¢á)PŽŸzõ\ªjivpëg,¶±¬áÕý-÷ðÅøiɨÅÇKÁYü~ê• Oaý½oÃh8‰†uÌŠfœùit__Š_3õøqÑðä‚¿¨@¦~È“#³ŒÃFsévœyirß ¿fZñc_)8TÁ_RH!‹ÍÃj°XIì‡{ ”Å}+üAü4©Ç¯ðMÁ“w¯³r6Jìh^±võx3üŽ ðnÖuëþ»îf³õlÝ­á ü‚ÿŽÅIì>Ò ¿ŠÜ7ƒØ/}Æô¼÷¼ÿчÐ;ÃPúºÆŸ³cñCk•VøU\pßÞ>kú#~ú8àÿÈZ‡0ÁÖ¬Qêá7pÑ}+súÌé8øè@£ø/¼„B׋ªX«4¯â¢ûf æôYÓŸptTP …ÿ@Á;?X³F©…ßÀ%÷z0¦ô™ÓŸðT"ànMÊœaHP;ÅœcÇ!³^Ä÷ÖèžR‰_—Ü©¤?ÿJÃ0c·Æš^`X8¨f\›qG©!vÎãít]Bäø5qѽN-ýÅGmœðŽšmÏæ¬Ä(@߯p1Ä]½!ríÞ‡E*ñkà¢{= JúËÚxú0âÔdcoÛï™ï]B9ÂöDÅAÓrNß³^D§›ßH×âWÅE÷z8µô¾)x”„SC ­ÔŒzc3¬1±!+8Æ®¡Ÿ.Õ]¨gHN+‚f©Æ¯ŠKî áTÒ_|¦áÉ¿€¯})Ôè˜WЗµ¯ÊÚ¸qïž´€{£ÿƒøUqɽ% cü­é‹øÌ·Xl0«@_wí½Yw®ÅûX÷‡ú_ÃE÷¶Lñ·¦/â8r›Í|+EýW²wÌ(ã(¸ícÝèÜÛB2Æß–¾„C¡Š­Kç›ÝYGÝ)Ê;M\UæþÈŽhÍÿ*.¹·dM¿M? Ÿ_¡²ÇÖûÍaœUâ.ÇÕxëþ7æ—Üka„/¥ø>Óp/§‹,ChìÆË™°2ò+ø™p-Ú&ÿµÙã@ÿ«¸ä^ #|)Åø†û´<Œœ)¢ØÙ"Û ©17ž÷â½K½Výø0ŽGø_Ç÷Z^Äø#¤àñ;w¾Åèȶjuæ1(lq¤[ZÅXkþ3œY&Öaä@ÿë¸à^ ƒ>”ã?üPç‘8urÑ(‚ãªÖín"8¶ØPšþ—xH¬!ü†ÿ-\p¯â°Î¶éǪ¿€{«~ç¬ÃO,!º‘JWâÿ§¸ïøßćîµ@p lÓ]'NigL&4·¶÷‘Á(þ¾ì¾‰KîÕtãgÀ©fó<šv£)|ñ(þ~Å}—Üëé°ÅÏÿˆw4ËOV*œ!£ÁïÚOêQS"žü_ÏB]Àü×ðÃüoâ¢{%kü¬ñOx`–¾œa!Z#œ)o´%úïç/»Â?Ìÿ&.ºo‡R_þ†'‰8u—x_xæfT^¤ þSï«Ñ™/£¾jÖðÃüoâ¢{%œJüòœ{p˜ë”,2_ÐŽ–.ä?ÙQü rægîÈf¢âmkQÍ} Ýk ©Ä¢á<؈φÂbeüµŸÐ4 C×~r„Æ¿4 ³à‚¯ºÿM\ŠŸ–9~Ù'žBM¸u x¨aÊwBhv°ó3¡bÕñÒ&‡F,.w ÿá‹ñSR‰_/gñ¸Îüqâë‘®›ù6Œ†“hXï0çYqî©Í}=|)~ídÔâ—}¥áÉ;†Ÿ˜‡®}FfŒáÌç;žü´¹o„/įŠjü†_Õñ$þ‚â;Иg~8£&‘²Á^¸C ”Ñ}+ü2~íD4â—}§á1PIA úÚÒi|î«ä.L’샻}Ü·Â/ã×NE=~ü+ ße¸ÿ¤\a„q ¿ŽÁO-‡Åoà^“=ÓgI\ÀíãÙ¡È;ÇhÑðìXüÔR¿Š î5Ù+}Æô¯C35óë߯”:,²0ûûø©¥~Ý+aØÒgNÂgav¼[ûF„ú\Á’q,~j©‡_ÅE÷­0ì鳦?áÝ‘ëÿ5|o…î)µð¸ä^Æ”>sú9N6Öúú÷=ð3ì¨Ä¯KîõPN¶?Àù©Îµ¸þÝÙqq€ž°£EŒ_Ý«ÁÔÒŸÔÆù‡ Ç¢ ¯ÿßC¡¿ý/!bü¸è^¦šþü£6ž>LxG$ož.×·ðæþtÏ^äøKŒÄ+ñ«â¢{=˜jú ÏÚx¦?oB¥æcM ß”`—JÃ1v ý°…7]¨Ãþ=ݪTãWÅ%÷†p*é/DÓ §ÑŒ,©Åúw ®ÉŒ–ÇìÞäÿ ~U\ro ÆkúN­Feý¾Wc~¤ûÃü¯á¢{S8¶ø[ÓÇôëm£ØJ —ï9E®É±îó¿Ž îmãoKÇg©uòh–ºKëÛ5\ø‘îó¿ŠKîmÁØâoK×/òL»ØzЬš¡—øžû þ7]æ—Ü«a„¥ø—¢á^ÒþZ„s7{cáèh¹RŽ—ûôh›ü¯î8Øÿ*.¹7㜸?@úNÃIN#gj:°³æb~©ï°D\ó?àC‡Gø_Ç÷–Pœ“ö_ixüÎão1Â*M xFùW+ùõâµýz¬5ÿ.ì8Ôÿ:.¸WÁåøEÃ_ûåt3oéhª{6S«˜ÎTGhþxH¬!ü†ÿ-\po ƨ«þ.­¯§&Ëš9”¨+þ—x¶?à@ÿ›øÐ½ˆY?výE¼#+‡_øˆq}»3CÜÿ _rßÄ%÷†PLñ³Ç?á/0´þ]˜.šÿdž/ºoà’{K(–øÙãŸpl£¼•êû˜ÿPÛ®þkøAþ7qѽŠ1~Öø'<0K_ö¨é×$úïç/»Â?Ìÿ&.ºo‡R_.ž„áh)<Ùþ€à?õޱù2êý×ðÃüoâ¢{%Küìñçxk€ž|]Zëÿ-¸ÖÙmïpѽ–Œzü¢h8”¥¿µ?@‹•AÈ6‹ÃеŸIëçm¸à©î—â§%¤?.žåø©WOaÁ¥ª–f;?cÑÅn°†W÷´Ü7Âã§%£?/gñOø©W.¬Ãú{߆Ñp ë˜Í8óÓè¾¾¿f*êñã¢áÉ;QLýµ#³ŒÃFsi·μ4¹o…?Œ_3 ­ø±¯œªà/)¤ˆÅfa5X¬$öýÊâ¾þ ~šÔãWø¦àÉ»×Y9%v´‚ ¯X»z ¼þ Ç?І 8^ô:÷×½Îé¢_^ƒìâÅ™à=¬pSzgÞÜ;£†Ê÷—i푲~1_,îæøoïëÍÝÍ]ÿ£óÐÿró»›þbþ]+}‡ÈÍ]/777/íoSžüÝ«ópé.]jƒWkÑõfþæùp] =ø«˜zÿ€SöÜÝ,úD?,æw‹ÅMÏÂ]ÏÆx@e,ze,î(Èž‚ýv7•tw€ªÖ¡ÜÜÜ}ê9Øß߃ïY$žÂínpÿ|N[îüU:Ç;8:Z‚†0ºƒÞÏÎÔý ‡ÜÍ{2 P  ,}ø w€£ÄÅB—^ýS”Ï«Íf³éÿnž'’ë“”ºëïßóÓE|x"\øÄpG¸K¸SïÐöô ¢dÍ}†‡©Ï닇y¯ážšÅÂ1Ü ðýÒ ê¿Ç­Ùýt2eHÿøÜ—‹gø ß•®OTB¶átR2*oWÜú ¶¼;rÿ@_ï`¾¿t=,n昻ûWs¬‹4|¤®Qýkªg÷IÅèwÿϧO^Ãðx“Ó{²2÷w´bó;÷wÑÃý¢>çÓÍÃu|æm´‡î/xè³}¯Ì>Ö}+0‡}æÐ,?@ræPÏ´q³€þ×ëßPúïï}-tS# iò„%dë¯JòW^¢fñâEºˆÝ5q§Þ? í/€šýªÊ?}«ûpƒ•äòþkâûÈzÒëÿ·ßæ(¿ý6ÞS?ðyòõjµâ?c>©R!«Ÿ£1§ÓÅ‹¨ðxW Œ;§Þ? í/€6¸okûŠæ„>_Ï¡i¾sØÙiá(ŸÿŠòOùÄd2íõ?_ýúà)€çþuß û|Mœýìó9êÿeJH¥Š¢.O¸óxëÕNõ Þ÷ÙÆuyªû:mvy ×œþáë•yÿOŸÑúœßÆ! }òÏ×ò©,¿ýP|7é—kuü2%¤ZEmý¬Ô¼bÇ{ýe“Û&î\{ÿÎÎ5pˆ4´8€~ôvújæáô uþ¢‰SþúóÏ׿þáOÃÔ‹€JÀ‹”Fõä{”TãoŸüÍõt-ñ踅‡nèp}>-þ·ðÐ ]¸9æsÈáð •Žcb*¸U¼$à³BÀ¼$€2ø†eðôzz‰Ò¬¢æ¾UÓEÐXÏÐÇtë9^üYÇ ÷´÷ôµ;´ªý«ïÕôZ…á.du€ŽûçXE•çO:rø„eðôC…(!í* G¾ó¹oe©Oö Ìâ`háúýÊþøº›¾w¹}Bφrúúvm[º•›,NÁg”Ÿíû FVØ B\aŒµ Šæ®Ïà}ñà4üzõÿšàó$€3ÐÆ•¢VQT£“å ¡ØÑÁ:†Lt®…;ý~e@Ÿ©Á õ‰Ccèv8öóœká¨Ô úÿu> #1‡Z*œ1ÐÂ,!Á²@D`g“l?dsØR?©†;õ~mÖ}“ê°i]`e¶Ÿùï0·ð=`Eô_€#hã*[ߢâ„Ì–2øœò;ÍÓ´ñ½î××c ³‹Ðü&·^ïwXÕÃë6¾ë^ãS2E„&8€{ILÃÇàZE–êä£ÑÇ_˜ùAÝ[×Ä~ÿ€¶?²1± {ß¡±­@˜ãAç-|ŸUn¯'2ÆM@ÿiíÐ}TaPß,Ûj| Þ®¢YýA¹TÇŸXÃÀ|€kâ†ûÚûЪJ¥é0ÿ> Éá¡ïø, åmàDÀÿ£¤þ—àO\ÿ ÐÈ”ëÿ´(8åiš›“ÍPâk²Õpg¸ ½þº”ØÏìÿ`e7`À_`nnà˜„Ï^çÿýTž?ú_ÏîiFì>éqU—WÀ©f÷Nš–¤)1²mý¤e 7Ü?Ð^ÿû;ìí,æ8¼u05 dlN7ñ sÐøOAÿÏéiï“o„ÔÐÏÕ+à[ZA†æP×д0öù‚wG®ÿÇù]‡mëj™¾{§½@ëNÃ=ÿ|ÏŸ¸þ£(³]IÿkÈ+à!g{³§øq¶MüØû ƒ‡ŠeŽöç_Õϱ·§à^‰ÿ õù¿âé2­-ÀúÒWÀ©;ùä{÷XÍÏ}Ú€&NÝÉÃ×ÿCwòæWÝaŸßAW--UýNÃQò_ähùªú9g# s½4Ù¸ûAîÜÏ<¢Í‡¾¨áN½@[ÿ}™²óÌûÎå'p*¾ïl>ô0×ÂJeúß(ú?/d[Æa|¡/…¹&îÔû´õÿ°G\ØÃt8ù2Ç5}uÞÂ_Fÿ§ «8Ö|'‡f·~ÆëìUq§Þ ­ÿÇþd_±@3ó½x€e'8ãZø éÿœ„å?[?<§án˜’œ»6®Þ ­ÿƒö'Áê9_ຓŽ}qJòƵq­þ÷:Øz,NãÜ'ßÄ’ÙçÉÏÑ †qA¨Çá0IC¸ÛÒ8ׯŸ'3uyf~Ö]YÿÖ†õsîÈ̶ q~Ö½ÇÇ7 ÁqC%4µèß¹RA¯†û¾Ÿu§A.­ • ­}Âe¢½îü\><û¾Ÿu§A.­ •L{ý?tðIñØ»eºÐÊâ\<λ“És± ÷g°sj\j<‘,WÐëáháò†~²/ø*ŸÆZñ;G £ûÜVH#há_{C?Ù|•Oc­à¾¶¾–^¡M‡š8,d}†ê‰-,ð5þÂÿ˜°6·-©—rܹ° ©†_z©á /5‹÷xôï GF̦’ðo«Àÿ•và¦Pxù¼Âø¯¿Ê6˜CàË˲ &Âx±(Û`" ”gœ   ÃNgZÁ?a–h”yµšH@¥¸Q$ øíUŸ‡ú'.Èq1Ô?1pE–ˆ«¡þ‰IX—4.ý7Çf*í€<þM¿S˜_¿ÒÕ?Ðß÷¤!0ª ˜{¦!0ª ÿ¾ïÏEÝJÿM`ü8a+ {ý‡Å…Îà´õ¢ÚÈ5zÎ"òÇÀ’öIq ,iŸä Ž%í“ÜãxdÚwû°’ ÀÕÚÃv`/†°R¤Ê‡‹Tùp[åCÒ"¬?iyíd£bN€ÐìIÀ°û“˰û“˰û“ˈº?Lö!`Uð훋ÿ íÀO ¢pm¸AüúÒ’¡øI€AZ€ý“°zfà°¼ ÚŸÄN4 E;𓃘  n¨^X5D ¯‡‹¨ü$ |ÃWR—1¼% ÄÂÿE;` “ü$ |³7…]¨5œ„QÞâ$›!(¿­ãøÿ¬kþôœ< f Á T# ˜j3ÐȧÁØÿÖLk츯ÞT‹ê£·Õð/ÞTÃï½HWÊkÊÑ%&dÊÿY;°~9D£ "SP'SP'SP?‡ˆÓ`lŽŒk&€ÍïE€Sp N!ÀqŒÍ‘ño÷"À·{ÀIÂIÂIÂEÄi06GÆ¿—¥´J@_ íAÀgÔ€ Ô€+Ô€ êl€ ÙÛcaVߨ €è×F# =ÐÇF# =Ð/Fy?¾F䨥‰××õÿáD¦pi<\Dåý@NF@ßü ä”%@•Õ_MùguÙ”ÝjєەÜÏ 2–%¢2TÞ 7iuýâÛ·ÿýòí_Jnð©-wìœSIþù7ˆ²{lEã¦ÝÛ IDATâg¹Ÿ&6FT® õ¼úß5ý*Ôÿïê_¤ ÐÝlp×”êzVåë×˸+@’ÇÇEÜ É—/Ϲ£ç-9;ÿ»Z,¾}„<½¸úßÿ®®à‡ÅU|©¨ •€Ÿ´åºWúâ[¯rÈü×ÀBÿïÿâËëð]µ ‚ÚÒJw´'àÓ ýOÿ¤ŸŸnµv Pkµv PkÆ@@P*˜å6ÀA!€"Ðm‚Ã[(îZй¡±ÞD*í@,•v –€J;K@¥E HÕ d{¹ p5Àì í@½ ªTC_rý“ëŸD€\ÿŒ€¼ €ÚEn\‹€v ؇€¯_iuýðøH«ãè÷8'ý–”ô{ äm@ÿc!·®F˜‹íÀ]qemˆeà ìs„]Ô ÀAØUT÷dT$‘Û€Eêñ @,¥@šœ ò‰·lÌ ðƒàÏ5ü ø¢F€_ÕðÚžŒ“lú‚·}ßç[üY€XØ í€B¯y¢0¢â³L@4B\ÈD#Ä•L@TödDhã3†ð“AŠqÀÿ®‹q@?üê;þ$€ôüïǰ!;¶ XÞ¿w’ȶ Pr"€=ÜݹÁB­ †6à€¶ $€·ÿ®Èþ€6" >–Ìí@ƒ­ Ûôª°ß¦Wm„}Æ©6Â~2u¤0håÓÝÍù%¡ËÃbOÀ*=÷%€ ”•€÷Ý ­P+H;˜#¶|ÉzCð“€— JA…€Ÿã€¦Ô h6ÂåMe;ÄR½oì•”í@ŸãMä±oY¿?à@¬8 )¶?Ç‚XFÂ~z#„ã‹ |TDoØrˆÏl9Ä…D[q%Àt=ÚŒ˜jŒ“êãv¡ zô> Hr 5T" R4òɰ!ùdØ€|2lH@±ÍslÈ3bìȈ õev¡ ¦q@&Ò„ iB†‹4!Ãe=#V#ÀÏ’±%@|N˜¯ zß=#V;°ÕÏ[§$¿JÂx”„ ^ÐÁ¸—d $9pUD€PLÈúOÈúOÈúOÈúòŒX꺠ʭ¡0­ ªËÛ_˜uôʸ})0­ zÏh3bá»*­ƒ»ûv@¯‚*ÕOZõ¤Vý©U?A΢uQ\-ϾP PôÿUÑÿ£¢ÿ/ŠþGD€<#äK¾ê2:wã%mƒÆª­Ÿõ¹ñS«½AïîüÆíçõ:íâf¿Wëõ³?ÊiÓ/éš>ºÁ–ž(x³aè&í‹øëó¬!ëîò¢/®Úøó¤ß·à¿rð4RîÛ*«¯ÿI•¾yî8ñ¦x჆7áqÀ7eG1öðº.]OÀ®‰÷pÙ¢‚ßÏp¾ñ$òGV!üñGþ|ó©’ÈÈHgÈ…ÕÆ}ÅŸ zÃQfƒ^B@ƒ$ ÁÐ`àüô ÄÜ~óÇÿ—?ßüá6~iwP:R–çd¬×÷Iý3Šý}öÞp4aÉi†Ì2Dstæè ÍÑ<#@ÀÇCÀd"‘ásM”x^ o†¿ÿÄÃÑf";Oó2žædœ áã$` 8Jø„LLìL$`'âlBFÄÙ„Œˆ3D|ìd£ßêx¸Ž‹ËR*[ Øoü›ž´ý²? SötÊþ€®Vý99ìZ…tÀdz.æ„,rÈø7=}€¢ÿ×  )­òùÂãÒÅŠAŽë[Æd'ú„ŒsSîB%ÞäÇeOÊç,vÝà§ðË&¾ÓÜïZøR ÿRß!ø¯u ú[»É&®QÇKÇà™^àó&s?¹/ŸSôR”vÅsޝ܇¾ü ÏËè}Å}|h¸w£þkø…ßøü!<\–ø¯¿>Ô x^IÿЯ§!»O'Ï›>?—Ï4 r_>‡ø±è\ _±‡•×Ñ_Â/"`u)º_²Ý~Èð‡º%|¸ŒäWÝÿÒá½úª ¬Ÿ'õª'à9NŒM{•OÝsŸûù³‰€î¾»LAúœÔÝÇÂϺUPc;ÒïEH`‰_º¨Ü Ù=…°,ÁóøgÐ þÙ@À÷YŒ?IÔáO$ Ö9ޝSàðvɽ/Ýû÷¤¢Ë!jïýNðß±zh™ãÞû¿£÷èõ¿úµÎ€'@Ü>‚Ðʈ ^2½÷Ϙÿá(†õf’w»Ëç>ˆ,þ)z˜Bñ †}ð çxÊÝɧ ‡×rŸ <–¼¿ctrœ7¢¤è€_ò‚áXÜ_0oV)ü^ù¡zrC!p·N¾wgª MÈð0ÂíKÄ&VHð\èû¾|±Ì..¾„ë›ûø^BÜ ¿ààªÓ?}Ú5ÇEæ•ÇSÅô7×tæ>½%E¯J<êßW6¿\¥`/Xt¸{ÎLÿñªï(* Z¬&Ý,(žb ÈNÏT%õe¢«õÿÃsBQ¡2He—ß×gm4VB^çà”#õóé(wÏ‚Hy”ãKŽg,¹ÿ;®ÿД„ôeE èóüdÚ±á{ÿå à[Ü^áX"ˆ¸!´«õÿÃs=Kªdíñœ€ ‹]ÄcÂ0™—+ÒøeÀSů.£wÉ= !ÕA M¿§ö¢tŸé?–¡wô¿Ì¾6ÎpûJ¯æ^<Y ïáh€»_wµÆ7©Æ < BO]‚íz5a »Ä´\øRÍÍ•KÒÿ‡¿ÿ\.Ãߣþ^ýg#¨þ“¿WË ª^‡=þÁ ¯Q.¼'»ÂL/iÈ»ÌB —OŸ›Ï“þ›Àóp©9]@ ( l Âd3Éΰê¾Ûð¿?´ñЦìá?:±†8îDùu¦Ø àdz09°Ï|@Š „žÏÒ e‚a!û¼u\Ð?Ÿк¡SÌóa2&Ìì5Иs“j±7‡Ëú†!Ã@ÌÛ?a2†¦ÂÀjŸX5n}Ÿ¾¼F€g Ø‚úf6™"È6J¦ˆç°'cÂÜ€}> LŸ‰Ò—Ö·ŽKúçó€Õ„ãÀŒq¤tšŒ¡¹‰Ÿ¸·Ì4W®õ|ë¸DŸæh°&s41z¾ºn+ðÊcëAL7›¢RÈÏRОf`†”Žož½©ïË7ºv&$¼|ær néðÄ(9ãVÿ )XB½þÛ lü6öF% ®HŸ’QÚQ€úðíã oÀ½òÑ*Ÿ¹ô1»:/ƒ[0êOF¯’‚%ý.bÙP”j à>«ßuž“þqŒŽh…(úî3<# æ;Š~‹½$*Y|Þ¨åßXvÅ"ÀnEP”êyNÍëÄYX üLBP>è;P&v%NßB ½ {A¹¶ò^Pïß’['€¨¿‚.jÐ>ÚIÇeÙBò| {4«ƒPÉù™¸{ÀFÁiŒ#d6î¥_üwl–Hý»Õc" ÿQ¨?Гtã¾|°Ãl{äÇÛä8dYî¾×Ò²tŸð¯¡Š‰žÇËe†g y>…Ä@NÀfÅ­¤p®›ìïLÒ(8 ‚i„œÆ½ô‹ÿN£aÔÿãêR&À@Kd¦}²“T@‡;ú›ÊO~ØÊ’»ïC^–îcø—%Y Áíª€3vú‚0Å®63#©J£à4¦r÷â¯o‹ô; Æ|ýã³GLè’DKå26¸½@P0¶*»‹Õ¥@UuÁýåEIi1„/Àb¸Xôáçð²$ ` $àwXýpO ª>9í@Ó9{Ã/þ;€)ÜÕÀ×—- @0Ñ“ëoIŽwÉõ€€ä^ `™ÂonW%< ¤Á0›òA0Ó¸×ÿâ¿Ãh8Óp$ ì3ò±Žô¤TÂôú"¡2"Õ2s_!À‡?$€Çp±¸(à€&.9: àOØ…±/P‡0ã9{ý/Ðúm1Þ1G–Kü"¥^ÇÁƒÐ ‡Ë,Þ `¹Ì xÀœ€;/L€0Æ!r÷FýÇßi4œ%š"Ëâ_ ”øEÖóà ¦/v¥ë‘p÷91„,^ÔQé_ `Ø Íª ™µäWJ‹ƒ`"§qï•WøÍGÃm2#Ay ÷(S®Ï5œq(¢yøL‰N\•üd\Åc@À„€æì>ïC­”ƽ·¤ýø›†yæj`ñUì*B_?à<á¥/õ…|åÛ&!~ žÉø"+\KÐÿ€€¡rëXþM[Ò¸—ŽòL¿ùh8eò bI‰€J`Ë ÏÔk&¾]ð2@¯|Á0EP=84EH@ÍFÈ10þÊ”ÁT,êà±Ü®WNÈ”gŒj/î5C‡Æ¸C ¨™ èÜôͦ>¦_¹6²Ü!<x¡ÞeŽgŽŽ ®š£9Csô¡ÔL?KPÓ¯,–ÇOÈ7'|þ ™ý ¨™ ‚‰¢>¦_y4ž’¦_y,ÇMÀé&ååõŸöØŒ› &>I_Ó¯<–ïtYJmý-`БL³ç c´>¦_y$ßý¬¡XFÂ`ƒ`&¿GØPÓ¯<´w¿4q(úHØÛ ˜ â>ÌÒ÷`c Œ¿Šà~.Î-¥\×_J²A0Äz-­1ðí01?—§—¢èß`ŠØCŽÊAP´ow»Ux8L$<#4~áXhü"¸UôO ªº&­H ¨|_Ù…„F6¨å«ú7õÏñœ«Áw¸à©` ($)‘~2\,R /t|j°P‡ KÈuÀe#A;œ<–ó¸CËûÀh@O@]ÿkIÿž1ôO•H>œŒú÷p` $à .â¨Áðûr·ÃÅ]ËÂÝu­„”Ö1æ¾Ìä¡\V‹Àuе¸öïCÀª¡g €ë¿À˜) ûø¥cËÌä² ,×`ô_°{ü’0°gðœè¿àî‹| _°ð…"p›â_©ƒ¨Ž‚e¤÷Ù5…iÀjÕп€Lÿ% ¬Ì'íbØyœfüè ^T¼‚">£ò*ŠáÃîþª$àš‡/Ô2,þrtÖ$í’öôÔõïÖ‹o~ddßç¤ ¨ÀãÚÉ%SÛUYR¸Î“;VC¡`VLTæ gP2÷e#*¨PÊZ†Ç_¬ƒÂâ!?´?à?ÿÙ¬>ÿõ×çÕæ?ÿIû´q@¡ÏÛ}Ÿ£ž0ÅUT¸nà–iñ@Àm>=Ò·¡9W¹ýx@@1ƒ’¹/é<üA-“Å_ªƒv|D¾¹¡I€:Æ¿ögŸÖ«ÔÂê v»ˆ“Š®‰–ÆÇW° S\±‘æ®…e™û«œ€ë<üA.Îâ/ÖP|DÆ@« ÐÇÒø×þÕä»x‰—`IÈT8$ Sp$ †—Ër<'  _ €Å_\ –í€( ¨µÚ8 ÖôZŸ9LD¹Î@@¾T w@L&[šhü$ÀH¾¢$`Å H{Ä´qÀOö €í€ÈÖÎIËӭ〟ìA@BufÆqÀiX¶ ±?K€¥°D2# _<ÚÚ¢¤Ž^†€«!ÃnhI€Ð • °wC>ì†òðÅnh¡z0Ê8à°ñozöjZ ÄJ„XA@9ËñE"àvˆ/rnóðMhÎ@¹ü¸µMU6þMÏIOÙ(`)™"2؉¦ˆ‚€EaŠàô‰¦ˆŒ€ÒÁÃL,þ¢)"n­M ”ù€CÆ¿é9©‚sdc\A€`Œ+ã2cs/ãXøµ¡.IÅ—6@Ƹ⨂ÙÌ<pÈø7=/Jßrò"Àk Ü]°(ÍÑ NÀmé~QpËÃê˜Û©B?@1~XÇl¶Ï8à˜¦˜bpÅ‹@ØB2œ) À`B&'`8!à &d’{qB†iB&àNÈÌf3<®d²Ï8àxü”d¦aJ’ NIfS’ŒqJ2º—§$cøb¿ Þ1%9<1Ë2x®"QÿÒ¤|®ÿá¤|‘Óò —'å^›”oœðjÐãZ“òq13°ÎöXÆ/@@H2m¡ª.K‰T–¥9|°,%º¯,KIYX^–’`Y¿ØÎî¿,%-&ÏÀe‡Ú8॰-ÌzŒ=¤ÊÂ,V…×f‘Š* ³ðƒú¬:=¤ß£f nÕÆ/F€mi"ä°ÖÒD"@Xšx­è߯|óÈêÒÄeCÿ/±4Q$ 9Ç·ögÔK,Î x˜J¿ì°¦~òb×Ðÿ«,Ε€øÂ‚ù¯<¾µ?g¿<ý±ª`8n2pe'øõmmÕ[ ¢©à£—§ïVô_¹à0éBã#ß1Úµ@Ö®çu\ªrÔu³Y„ .ÿ=ÊõÒ%õu‚&ã»NÜ”Ð*ƒ}wØ+RÌ01;«Ðwס~¯é±‹ÿˆ²Æÿ—W" +T>|î*(ëô¦”|n”ýÞ j\ÇNÅ+]fƒ™|Ïþ ¥k±c×!`¨ÒRåÍÏóúa ä5÷i ã5ÓÝ÷!é:`ùòßuög(°“´†YäU褖½àù‹û"ûµÅ,ƒ¿9ž ròLüÉÜSö¨–€cå5èJ ’|ZðïŒõåù±¼¶½ÈÈ9<Ìåø3‰·ÜÈõÓ È+ð}˜í2@ÄÓË2KƒpÃ:§ñ4üš|š¦Ÿ…Lè¨Û—Ü­˜É+PÓ¿×­¤`îlX²"0¬Öseå6ð Üãn¹šŸMÃq§‘ÓPS0(YR0º[ó?…$Ge TV3žæÉ§t•à‹z¬rzj ùÞêE0T0:L øì†O“Íä~-~=Y‡Û˜Å àO.¯@@”s8b¨úÚÀ8þˆ…jºhhó rzÜvþ0ߺ7J@]Á ëïrG—­1h—åàZQ¯ÀÜÇâ°¤A}¸ÆÃáAäaô©åäÔ ò½«(–îSW„åržl_ÉLi¤›û8áWUŸ°1=TNO€k0UÇ<žÑ2܃›y2Y÷}øíüׇ‡ßÜóO†p^BxwÛ«>V1Ï}¿_—¾nž§¥dJîk Y¤æ'C8k2Y¹\ÞežœLy3›Ý—JÎoX>69/.¯Ý<çCÊ^ý‘€)åñh²$`#^ùz,“i?Xí¢ÀÉjãÓrCNß ÊŠôÇùsOOd¨ À;¬œø•<é;1ýxî·¾–ÿuÞWó? (%~žd7ÝØ:K„ª˜é¬¬e8¼’þIÀ@ØHi@äò•XÇÄZ¦' ï_v]^Ë$Š:~”õ|K^Á׸³{‚u¼XÉ%ßa´ÚW2¿m±–¹ÿ±´ÜÓPËá>—÷ Ô1X¬ì  IDATËDŠ:æù'{I=‡£Ž×`(êªe8FøG—“ÐÒ?# ¯c~£Jfîk™ äaÿÃÕó-99rk¨à'MÞ¸¼Ã*¦ë¦¾–YS™•­óO^J!‹û<¾ñ:^‡9¿¡¼ ý¿XÅÔ ¨Tòo¨šoÊ+€¹y:Þ·¼÷Ò à'î5bµåÝëÿ5L놜>ô±Ë«-Owêþ€÷)cÙðne$ûÞ¯ŒcÀ;–Qìð/Þe1†ýøÍ´¹GìíÊö€({ÄÞ°œˆ²Gì-Ëù÷8u½z£ Äù÷¨{Äð“ö>áXξ?@Ý#†Ÿµ÷ ÿÈröýê1§îþ¡åìû´=bNÝ'LÁ´Ï{¯œ}u´¶GLÝ'ŒŸ4ÏŠµœm˜ºOØigEŒ[ÎN€¶GLÛ'ì´³"F.gß nQRö kgEOãm!ξ?`ŸMz¢¯ÊYN=/è¼röýÚ1m›ªvV„z^Йåìû´=bê>aå¬í¼ sËÙ÷h{Ä´}ÂêYÊyAîÌ-ÄÙ÷h{Ä´}ÂÚYÚyAê™q'–³ïÐöˆiû„µ³"´ó‚´3ãN-gß íÓö kgEhçigÆZξ?@Û#¦íÖΊÐÎ ÒÎŒsÚ¹¡GÊööˆUÈAQΊÐÎ ÒÎŒÓÎ =Vξ?@ß#ÖÞ'¬¡¤§z¬œ}€¶GLÛ'¬¡¤§z¬œ}€¶GLÛ'¬¡¤§ž:ö³£µýÚ1mŸ°vV„v^vfœvnèøÏŽÖö({ÄôÃ:ÚgEhçigÆiç†vG¶Ð#ØP#Ç;o‚"žßœ~fœvnèqv´Ãþ}}¨a}nÛy‰/,ãCû0¦ý†õ¡†õAúü°a~À`2Œ,íÈöÖ‡ÖéóÆùƒ}È2>°´ãÙ`XjX¤Ïæ,ö!ËøÀÒ>Œf€a}¨a}>?l˜0؇^î^ÑìÐׇÖéóÆùƒ}Ƚܽ#Ù`XjX¤Ïæœny©{Ʊ?À°>Ô°>HŸvúü9sMûFMXeû ëC ëƒôùa|ãÿÖæÐ×W¼S` ûÔ;@ÔõANŸNoêóˆ¾â#ØÐZ-ÂnÊ?¨LÀWîQæ@^óNóïp­%ìÍ›2¯µùau~À½îçßàšÃEqýx@úº:? 2¶ûξ:Zù&­€SÖ¡hóÃn|÷ ŒƒíîQe}ˆ:?ìÆwŸÀ(PïQÖ¡Sí.e~àµåìûè£ð,¯Q×¹ó.³ïàjëCÑ¥25Ißüxw œ}‰²>Ôéëƒè›ï.³ï@ÑÖ‡:Ã= Úüðåüûœ~‡È[½Gàüû\mïý´\~òïÁþ€Ê^¶>”¾ÑáQο?ÀEÚGØ ‹ƒ~„:^“³ï oÞïgß@ß +ø÷r‡ÀÙ÷àGïø³ï ¯ä þ Tñªœ}À©Ã»œ}À©Ã»œÀ;—ìxß2²ýïOÆ´?à]ʈö¼OÏþ€w*£Ùà_¾»Fb,ûð»é;¼C`$û@ÞçãØòNïÇþgÚ#F¯ßX#1Žý¦=bøÙ›»G`ûL{Äðó·wÀ(ö˜öˆ¹·yÀ(öXöˆ9Û=äxOŠÊ(VG[öˆ™ö ãg?Ö]£ À²GÌ´OØýxw Œ‚Ë1Ë>a÷Þ%0Šý¦-J†}¦»Ð×ñ´£Ø°ï&½šï–³"œé¼ ×“Qì°ì³lSµœ1¶ûF±?À²GÌ´OØpVÄØîÅþË1Ë>aÓY†ó‚Ü+¶£Ø`Ù#fÙ'l9+Âr^ÐkÞ)0Šý–=b–}–³",ç½æ£Ø`Ù#fÙ'l9+Âr^ÐkÞ)0Šý–=b–}–³",çYÎŒs/t¯ÀHö÷ˆ5B1œa9/ÈrfÜKÝ+0Šý¶=bú>aËY–ó‚,gƽԽ£Ø`Ù#fÙ'l9+Âr^å̸—ºW`û,{Ä,û„-gEXÎ ²œg:7t gG[öXöˆYö [Ί°œd93Îrnè8ÎŽ¶ì0ì³Ö¡Ÿa9/ÈrfœåÜÐÎÐJd@ æúøÍ0:îlgÆYÎ ÍÙÑ&ùöÑòÅÇoŸÀ+Ë—™\_ùr…r}}ü5d³ò²À?5qúäÓ§ž¾sU>KyóDíJ*þºmàþ£OŸÂWm ú÷* š_~ù?/¿üruõåËk⯠›LkðÄѾvÝVqúyªãQˆ(5JŒ ·OÀ ÏË@®21CÕò­“ôlö|6Ë6'±’úòe±ø¿ÿûý÷  ßÿå—Å"©ˆðÍ&à›„sÙ2lñ«íu䛂³/ƒ‹oŸ€ÍP›< “BXµ½Qªùcq,o\PW0WQÀ9ACü÷ß“{ø]â›Mr¿_—‚LÿP?OžWy¡ø–ªd×Üïúæ+¡w@À†gÆO(Ï›Z-þjøÇOT ]]¥Š!)øêê5ðWž)ýŸîÄváUq¨„ Î{<§¬Ò× '(èUñO}t}MÝÃ_~™N¡ê€ÿ§SRÓbq}}jüµ"1ý7“ç©V¯Œr”þ›éd°Pô øÇ¾‰ êå$!}ùrjüe¬K¿ï‹œO”éï5p~œšH¨@þ@_Ô‘ÓÙiñÓ¨Z”aú¡/rnüý ¥ÿîü8WÐݽ •D©ÀSà§U:“»; >OÿÍùñ÷BÀ ¦ÿ†çų㤠_~¡&TD Úl‹¤ÀÓᯣ~‰ETõs.üpS×Ïñ4P¢a)†J  >: ~jÍG*ú9#þ>øD¥¿ÿ_ÖÏYñ0Yƒ%.‘¡ U§Æ_A0ŨÞ þö ðýŸ~ß&¿²@I*§ÄO.)Õ¬/2"ü­ÀRú"#©()i±(Õsjü´ÂR}ú"cÂÝÛ' ¦:äÃQá(°pjÁDZXuJü”ÂSMÕñ¸p”·L@–j)ýçÆƒ¼ÝŹ­T÷ò6 øÿ•0'îPÑ&LIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksDF.png0000644000175000017500000003715613263214224021434 0ustar aeglosaeglos‰PNG  IHDR@ý49PLTE™™™L"www»f"Ì™DfÿîÌ]]]UUUª;;;™™LÌÌÌ̪ªªÿ3ˆˆˆf3nnnfffÝ™]3ÿÿÿÌLLLÿÿDDDÝÝÝfÿfL3ˆÿ»»»ÿþD‰Ç IDATxœí}cÚ¼ÎÆÃeëB›–ÞP¸»­;ç<ìûÀ'–,[²%;¼t0Šÿh!¿ø%ÖÇvlÑl—Ű¾òËæÍr] í…ñ¶m ¼…PˆŸF?»ëÛ™ÿh˼5y{ww'Œ(¸£î#ÿ>bBOµ‘qŸ¾~ÿJ´Ñ o_‘uÞ¾¾¾ #J¼B0ଟPÆ8^sGžJÇ,ÿŸåç*€öÎæmo(ªMMܵðˆRmö àp­Gˆ3ÿ«ÒD®âÀUuäå?>?S8š¼}Ž&ÎyûüÌ’ àÙQëá¨;A/Ÿ‹—ÐÀѾ) å‘Óÿ.mYÔò½C@5›Ü[ÁxÆ?“´;| &60æ6N;yãñXQ ` Á@ÑQµ“ˆê›xÕ±ç–W lopŸZKØ?TœVðšLÀ.4iÂ)«‰÷¼$ÛÀòv›c)€'u© w¸.†S ¤ðg œ­p–Ò ÝxfÞAÃ@&€|$‰Ã(cÅL†9f/˜d£p˜mru”v ØÃÐ5‚L¯ý0֜烤þcž¤eè|îÛ)€b0æ’˜@¬™,÷wz±•™2‹»yXm&eðDÌz­Ôw™"û˜óëÊDÔ:ÌcYYpBq¦sN£¨±6ŒÆ‹lMÄyì €µ9¸(LE®ýT·jßÐB`/Ø+Ç~®ËàA!v ¡ØwWds©ûæ”öÍ Ô"›/»B ¯Î³ÀuV¦âýY`Ôc¼ ¬¾Œ`#Q«…0߆„âߦRx³^㫞²Ê/ƒÈ¾üŒÌÀÅ—QpˆÙW»ƒù»0ë§YÝ>µ—qüÔc¼®¼Ž„Õ2`?ý‚ ïCCß§š¡×±%Œàmžýˆ¨½^ƒ}å¹J¯£1¾`A»ƒýÛð»Vç.0pá÷¯êØï(¨,H g„ÑB¬ýëuE„o!^iE…U¾ò‚ ÿq™¿±—(.¯°ž`i `]\‚Gp=‹± ÅCû›X·¡…/5ñÅ9á´£,©-I‚;Ül!Ö¤S ȵ%wL(’Æã\"RÅ%aøu9¶Wù4ì%ixW´YKÚàŒ2÷g˜ñçT8žôG…ê+¦y|ó ÆK«jqQ¦¢!>ökúìò—…ÂW¿¦ÐìämìE©¾$qÙ²^m…Ç3¶Ï¹¬ nuÑñ×%ã£ìü[l$ôU½ì™H*¿ª¸$€Ò²t<Æ6.Xwx)¾Yþ}ø¹@ß7ù.΋3p×G&)€âÆŸM+NÑšøÂưÂ×±:Þç•­Y°ï+[~/PÞßagÑ]I¢$gT?:¿ Ô¸k¹³ýYÉ8?›óÊ{ ÿ"WP|зwW~Ù¼9õþô+?-Gü~õ ùß)€Ê3øê`8OÐu]1óà¶ÇKðžý8^òÐsC8 µËe>úã<ÀÓƒ<%MàOqÃ?ð‚äöD ð‚Œ¯—ÏM˜å÷Q3™&÷åýóõ/ÐëãéIžÒž†ëþ7ü®L¥F¾OùÚÖæh_“{ÿv|œ 8Eý3…ðÐi ìÊÓ—’·ÙûnÎ5ÿœkþ$Ï[€c_Ÿà­3¿Éá}h{yØñÛ¶”?^ì~åq<Ø ìȳב’çþWüHžûHùåß‘»Ößæík‘£ýmKnlŽU½gùƒ:‡ MÈnæÄûê”§þWü®øHxÖ <îõíÊÁ¾&÷ö·8ô/KüõµWùH‚ØIèd ‡!³ÊÝ’¤N.IJøós'ýpk¢:é€sXsS(,ÉR9vÒ`MˆÊ±¨òQ¥~ûñíOåK¹k ö¡öÁæØ>èÜ  óíB&t¾™hUÞ Î?‡‹gK–D|·(ªç\ Œãš7_Ï×DÚåCÿ:wÝ4\Ò§òv é·Æõ·‹…ã­U? àvý-[ƒ£ý[•û÷ÂU9ÙѶ íƒn_ñÂ6å8Y† ¸³ˆàé£>Ü;ãÂi3¿®Úâ´,[çq]°Áê`•³5ÁçËÒM>§ážÂÙ¢vÎû|åË®% é·yü >Í9n é§à„úŽ{KºDdZ·Ž\ÆÇ3Ð?€;ýtÌþs¯YAÁþÞ?@™·k•³}6Çç;O.¶ä\úȹôÀy ÓÒ?ãí+Ô†ôÐ%€ôi[¿~ØFd[Ã膒€ŠœÌ[[0Š¿@qƒãºöEò°õEçÑ?@™Ç[\–øè\lM˹ôs¹q*çÒ?çmh0Y>žm|&‚€Âæ±.¸m-NÛéHy¼Þ@àÎSáœû(Åg·¨Œ/,pt.6Žå\úÈx²÷5å©€Œ'þ¿{µí×€Âù3€ ú(Tà¶ÂMóÝ·ð7À¾\îOyê@ãÑm› ÝNö=Lm úP.Pø(TeÀZW t,(°Úõé¼5îðÀ¥€À}‡î`¤þ M^A‰E ¢ ÜzlÀÁ|[iát.ý®>‚SÿÃÐ3¤Z?³À;!¡b>£Rÿ¹@I/(@Ï‹¼öŒ®  ÖÇàþ |[å £ì“߀?ú€:—-DËý¸cÁ?5çù8p- F’T€–·l¤š·%¦þTˆn°"­þŸÀÖ60ó`rï («“½Žþàn³ô]HàNˆ)ûEß…y„—þ´aŒ´oÊåþq%þH›IaÃ,á@Æñº>Ì‹ÛÃía¦œ)ʆ±Þ?@‰/`¤ò°ûÛæÔ@ë|íýàL[«pTAà4˜ À_²kâÛ"¦<¾ôÀ9~“þ,¾m-.ýä\úPx"…³¹@Gÿþ,NþlÎZxe" ìñõÃüì0œó64§©ìŸÈÊÓçþ NP9ó qîÀ˜ þŒëþì©jôP˜J‡ýã…úm}ª}wÜàç×—¼ J¹O ÌÉÂw«ePÙ§ïwîêùGÿ: Ñyô`\_ð`^¿÷`×Ob_¥þàUX©~[Ÿoþ”¼·¿ò²×oÛ'yŒŸyqp· ¡ÈãëJ=}zÝaæßúס¨»|(¡ó¸ …ëÿÅúi+¼?‚\.hɯ_îþ͹\o¡píu{^¿é‚ŽÖ­å9½3¹W€™¾WÀÞ|½.§àõíÃÛ O×4îÊSÿyùÚ ÇòÉ%a´fŒ57Çà¸bº-|}ÃòïÁóE©’çûÿwã¹€=Ë/…>øÀÖ µˆ»§H‘÷ý„rü2wmÄËßV¸¶,]puÑ*K¿ÿÐòGž. ‡ÀµŠ·5)ò»bþíëë±Êoù nmL!nù`ù×øAåçüïܦò«€}ø  ÆÛöê çWÿïœ7×p ×ð¾Cé÷ĉã:¢þ¸N“À#ÿíùË—?îd\×w2>¸NUéãúnƇp w?~|ùòì¿ák¡yZÊõGôY>‹Ã«>Lû0éÂû䎬Vü´©GÓÕ‡4eŒ2a ®DÜ&°?XÿyúáÐ/%-å‡ÕÔ_âTD(€1œÐ“`~2Pã_bӉϠ‘÷ë=ëçv­ô¿q}÷;ýC`ÿg²¬_Z³—@•PV.Au7‰•jÜÇñ‡]¼Ä>‘Ù‡aø}2\áUøo¾¬I1á*‚ŠcÜAX¶hÿhþ`AÇW¹_¾4"@„Òÿ&˜–ˆÖnâIQX¦p}A,«I¸¾PÄxõ¿{:wÎ+nßt}$Fè,YÏî胓žnýï¥ÐÛöŽ>¼Š1 ³hz ±BáO3‡³Ç~MÆ’ŽTðap¨ôU4ó†U6šm*›X8­² ÄZ™°Báå…“§áò¦Ù£ÌwôkÁükïÒêpËíï½¥SLÿßýš}ðÔy_.ý÷p^³,ï/ÞC%ùþÇÂ=?¦ßdO+ <œ„ùƒ@„ý}ÕÒyø/Övþaˆ>ÐGùa*2i|)ý7.€D”S@ÒNY¡VìqÛlñçü·¾†A/âÃ+}hœ0‚õßåØgÿJÖâC/€!!èýùoñ±Tp-øB©@´àDØPˆ‰ÿ‚µVÙ‡fˆš½ø0]ñ\àëŠÆÇRhÁ§*+`ÚÒ×%5¡tÿ°· „žàÈýP%œÚXÓª}·Â¢ô¿ñ ÷aMÜOezÚ÷ÿBJ‹¤0þã=ÂHQMaµ4¡ìñÇ#¬Ã=A#Âÿé„â‡h2>Íúßø>Húa:™ŠlP™\2¾{„Ñþ«׉ 5µ¤e©±î’›.ŒÜX>@‹!>¬éÆÇ(ÖœýÖôa,>4lü'zÿM,J/!Z”$ð:±• :QÔ‹ŽÁFV¹ Âÿ ŠiöÁǯ @‰9 …0Ç,>‚÷UY'¶Ö dè%Àg’Ç.©!Žú”qð°¥Øvˆn™eé¿ ë…ÿ2¦îfÌÇÛ¤Cй¦Ë ðVë²ÅóM´Ô³ÿ ŒáC0Uþ¾”þCè‹ü ÇM2þk˜\1¨ð!ÑÌ?—)JÇ»¡Ñ û4&KÂÃŽÐ’EQtÒœ´ƒ&tŽˆñ_2$ÏS P= ™ŠæßLäaÿ_ Âñ`ÑMú–šè¤Í$ý0aôG¶``sü—3´`;O•î æh0´ù‡0Š(ý_…Üõæø//¦Ú‚ œª=CeÅóÑ`0Ý<ý°&9€ÝÆ7ÿ€eüÇ ÷avš*?CyÝÒ76¤Ã“ìÃjʹõ?Èó müÇnòZfHxÍzÑë¤-¾b4ȀĄØË¯ ÏÊåãšÌ!ÿ±®b‚Á—éDЀPïE§_6ìCKN…!­ÿx»æò™†ü”ñïÿUF1õÆÑÁüãt-»ßr4¸ÀΚÒ,† `a4‹0ÌKÆb0æ1B³¿Üm"ÈG³"ë~³³é™7“a˜M@Ôc>þãHs"hàLà€ , fÀšj‚s "àRPEÔ X@E@˜‡-À!.†zZn‚kMxMµG„Â#¨ò+„zZn‚kMxMµGfb?‚šÚ#¬:PéDÕ:aµN\]åN¤–­|%Ñ;±æʨJ'¬Ö‰« kHV0ã•Dsü‰ >Œª Ãjøj 2ŒT3Î_JšÃØC'‚ªÃ0÷§0Œ €â0RÍ8yj5G™2&Rj1µ‰œÚDPm"©6‚1‘uèDPm"¦6‘S@m"Ég&Ë6¼üC`N¥™Š-MåV§‚+Sɵ©èÚTö¡AC¦bKS¹5Ô§’ýÙùÏøêDРPx™2äeLéeNõePõeRùeTíeÖ Px†ySz™c½¦ÿ^&ùOÆË¨#L_§x[|[\~\{]{= {ÑC_ǦèunMõ×Éå×ÑGœÒTTdTtÔ„””Ô¤º"¨¶ ¢º £² £*€Ê‚’Ú‚”Ú‚–j¨U`mIVmIW}IXyIYuIÚÁ+‚¬‰ _ÁtX âçò’®ª*KÊ ã¿+¿=TëÖUúP –uÖ…–•ÖÆMeQë€a 0¿±¨²0,/ê¬. ¯,*­ÿj‹ZM•–Uc°—e×–uW—…7åeåC–¥—–µï4¤-«nüYi³Ìæ—–u×P^V>`YzyYûAêÆ …µÕ!MycÉ)MacËAúÆ JÄ ‰ATPÜX2`cJSÜØ2x"ÈØZ…uYØšUÙÚUÝæBakY3dkš ÆÖ¶ÁAÖÖ*Ÿ†5¬mí €âÖ²fÀÖ4w´°µí®á®á®áÞc¸ú¸úèºÎ £z^ôÐó¢ð±Vðàâ—ü8Þ$ÃH~ê¹é®¯à çº|Ýõ¼èÀå_òÐólÇ îâ«ð£G}bÎé¯Âs1 僉p}–çE¼+øî£iþ€ü/ø^ðàó7ýPù,ÿt}–àÿìúUÿÀ þ€'9|ê×Ç7ýøüW+6éÐÄ“¦T>Ë?¿¾PÄ(ò#Ûþ7ünø`ñUÿ1>?§’c|Ý?KŸÍÇ©lv}ª€À¥ÂT*K_õ¸á Oê ƒÇøBáä_÷ÀÒgóëU_Ä_^ÿ2…sÍ?€_ø\ñÆOýp®ùñãË(z™Å¹ö6к~z™Â9™BU­Äg&ž~œÕ?:€ï8×üÈø\XZÎ5ÿ ŽV ¾Wü(ñ…ÁÿYüÄ?€ä¹€4~|?€\yh^¿o Wü(ñ…ÁÿYüäÉÙ+ŸK?¾øç?ÍßxwâOOñ)G®øPâ ÿ’çþWü$égþòü¥€4~º,ܾ~zº2>Éd(ñÃC~’ÆWüÈôãq’P’~æ Ï_.HQâ tb''V,©âÝ9pX‚|Îã ÿÈ·ž¯ûøÒ?rø¹Ã–‚uÒ?ÏÒ??÷åçþòòɽ…ë‡NçЉŠ<د'<~èÍcï ë¹ëoHÿœc‚Ò?Ïa]äÃão|ùY|¥|òm p> ì:þ6°Ãve‰|¾u¿?Œ³ðéÏ!>6».>ó€ñ¡éŽôbü-ýVô9,íàkØ]âówÝ< <ú`ÜwHÜ׸n•—µ9ÎÞçÃÀî¡ão}úžo&SVþ`ÿ 'týÜ?Ƈô1Šˆï9æï_'¢üx}~¼ <¼dfÜ? ¸2>–ÏW:þ6Ðל‚q€é³eÕ”! ÖozÁè€â‡eÝ>>­õ%û‡ÕÀtÀ}_SúlY¹çä ljò³eí¼üÌþa"ÄN’·ß†ÕŠøÌþá±Ëão‚ýã²nŸVŒ‡üSA¸ï(}¶¬ÜsêäÅâø2’`‡”¿É]8þ6tHà¡“+àwï8— s FðÐQÇÛZƸï Èňùõù‚ñë#4\Ú1h ’Í•ðË„¯‘§›3c|Ö0ÂoIŽHăüMï¾àWÓ]•+`ó…ùÃtskz}µëÇùõ¸,¼€öxÃçÆø¬`&ÄF%å„é‡ÄàvMwFÊ×P~øãxèB‡ß/ ïvÀýð'ß^ψxnº=;Æ_ 1 ‚ц `ž¢ èó\ÄüÓíéLð„K··Ã3lØõ '_R™ @.Ïñ'hàÄ‚Ç}¯ `ž¢  ^A¨Ï><Ã|aWìyä\Š;fË0¬mÔ X@M@5°}ýõ , fÀª*ª °.àš5¡v\kÂk¨=Bj a0ûúëMh¹ ®5á5Ô!µGPõ†ïØÒõPAw‘ûˆao;6Æøþ[Ö _®Ñ˜Ò?ÀîQ†i:ÁòS›å[(±·1^Ýár=@¬ Ø‰nb'ŠWð”ßôn0òé )ýdM|²)4DH Aù¦ÌÀ²ŠIÀ:±Í.£(î ^ †?téŽÈ?†;’ðàØ°>µ&sîŽ}Œ“îqÇèm"ðÄ?<ÂvÛ]ËZˆ)¯lçÁ@ ÿawHÿpŒõAÒý!P&ΓÝ͉žêÃ@é€ #¾°yfwÈûðóŒÜ?òGhžm ÷#O÷}Lc6îyÿq€3Q_Dù¹€Ý‡r}q˜EÃ8ò€Ã4áÀ"ÀÉ\~ä æž„üÃD’?äýÄada˜j–èDÐÚšúòå9È=,Ä€#‹‹/ýÄ> Îæ3Ô þX Ø1¿tNM@ôÀË·XŸÇ¥iî@ôO÷}íúj×ÏŸ¡þ‹-Þ ²~aœòqÏýÚ œÉ‘+ƒð€×ŒO?úSÑÇ¥‰FùBfÐ3|G àó€Ü?€oñi1¦Ÿ§‹þ(AïíËüÀ耾ÿ>>ù@ý‘¶4×§âWæ@Ìzûóå •ë§—¢åþ0BðàçéâëXJÐûðÏœè€<„{L¸‹Œö ˆsÿ¦¾8±|\0²¿\P‡ü)]rýnAEÎ¥äè £©[æÀLJuÈ¥äèÀç/ü Gÿ>¾ðàÓû‡ò3ÿyù加Òõ “.ý GÿMݲ ›>>¬Ã øÜ?€ß}þqM`È–¹ø$<=ø7‰ÓP~¶»Y+¿\æ>ào 'kbpEPÊSÿ)Çg­Tç©€<é Ë?ñ –ŸùPâ‹Aöõ‡A‚Ç%U+5>ï“0â“:¦S-y†_øPË¿R~ZÚ=…ðàÖL¥þ$ÏýH.ºä°¨SòÜ?€äMæ@òÜ?@Ÿ·¨UòÜ?€ä¹ÉóE•’‹A™E£6D–?®-KÒ"ÏýØ×—„%ñ“ÝÁü÷å5ÿœkþWüp®ùàœG‘´¯’çþ8×ü$égþ8×ü¤" D~X<µ0çÚ=8‡Jú¢•—üéå)kwö%®•ŸøÐë{o¼qíƒsÎH$"¹bàȹ‰s.§/ ø,h0š¸Á‰+å|Èõ½C¾/—‹íË|D,%’òÔƒ9GZú‰…÷Î;|ÑÉðn<äïú\¹þ¯Õß¹q:ÙGJ$çªs^Š_L_ÉÿGN8XØæ]…ï~ý—Å¿À #xBßÞÞnxMÄ_¼š ø"òç6çÍóuÂC–çåȵü5>2Ò?CÞqS¾†oþÄ3¨É<„S*gÐx›ó®ÄÉ~çö݇cþ5^-ÿYñ‡‡\Kàî„IX9ÔÀÓ®ð0NöQ¸°ï< ì Ëÿ‡9¿Aq’p<Ž'lrïÎeRžðpÎ ´©xGNï/*å«ñ7¾þ¤þkìàÎø8†'Ä-žKGãâLƒS Èy{|ÞÙ<PåL{qÌ¿ÆßüúûÔx´¯?ÁÕàù$,îJ\f 9”ïŒ8PçÑÀûñ6<#ÎçúÁ5îìWãa¯Ø¨Ñt'L¼òDzümđʇ-|‘;×8ÍÕà x œðÅç/2`¼µøs%þó°ø&¯åÿF<@z}5ž ÀÊ(×ÀÊOö}è†ql$d€ü_¯<±ðCãøGI_³–lŒòñX/¿vƒ'×—s·ýS»þW. \ãÀµô¥Œüƒ¬òñØ(¿zƒ'×—ò¾‘§¼&ù_¹fþŒw8ê¦ÏŸvþ$»|Aá Ÿ–?·¿r} ‡3^åå%K†Þ9wËÊ<<"ŠÜYØÎ¹€Z>¯‡’ýjCºƒþÇk~\ù. \ãLÁ›éÓîBþ´Ã»d¿×òÇÍØ‘æ+ǯ¼Ì…ý (¤OD!ÿŽ^ÔÊWãZúÛâ߇Wø«á+¯ð®Æ!”Ò'‘”òÇ3*å«q5ý&ªÄÀW~ §V¢Ä-óRú5~Hù®á®á®á®á†?±?yÏÊÂFx×Óù[—ïó#î?WMˆÜ6ñ—/$=}dvþ›óÞîü˜ûÏ5{¾±îrljiéo"TówèXåü˜ûÏ5 ß Îlœ¦ãéù{v”ò¿G¾ûþriAÎ5 ß°s~“Ëü7XÎè­ls«ü›ÍyïÏ?5ßyybAÎ5 Χ/ òßàž.Î7ëå~ÆûóOÍwÝ_žZ˜síœC%}ÑÊKþóågÖîìK\+?ñsÝŸj¾ãþrÅÀ‘sç\ O_ @p·§%à”à N\)ägº?ÿÔ<ì§ ¶ö—o’°#çHK?±°àáþÏùfãw<¼þÛûÿ‡ñZýûÇY ‰ä\5pÎKñ‹é+ùßòÈ  Û|Sá»_ÿeñ°|ÃûÚâéþtα‚/"×ößo6‘§ûßC–çåÈÕýÿ5>2Ò?C¾á<ìßľth2á¯ak’ÂY4Þæ|Sâd?sûîÃ1ÿ¯–ÿ¬øím.€¥ï*Ýn&·´tsO ¸RÀÃ8ÙGá¾{ð(°7,ÿæü ûÇà ›ÜÀ»sY€”§<œ3m*Þ‘Óû‹Jùjü¯?©ÿû%þ¸ÿpæ-Øârÿ¹à¢9oÏ76T9À^ó¯ñ7¿þÄ>5íöoèÑ>ù A ç2É¡|gÄ™3¾‘Þ™·ìq.׿)óŸ\pF¸ÌŸ™. ñ¤€gÀ™šÞ‹»ôkœï×÷³Æå Z´oÜ?Þ³IÐG|ýFœÛn O¯¯Æƒ–O÷ÀíSãÎ~5NûÇ7ÐFüd¼òü Ä¯ñØF©|ØÂ¹3pÓ\}Ü?Ž'Øþ·®Äßäµü߈§H¯¯Æ3XùåšXùɾ·›aüôûïÏGûÖ8Ž”ô5ûgùÇÀ(¿õòk7xr}9?ùþûsçdß÷p-})#ÿ «|ü6ʯÞàÉõ¥üôûïÏkæÏø&гôùÂΟ`—/à6<áÓòçöW®/á§ßîÜ-_(óðˆ(rga;ä^jù¼BnKö«q ’Ÿ~ýßÎÑÀ5î,\HŸæê ùßR(دƵüO¿¿þoçÂþ Ò§F¢˜Î-•¯Æ¯þÞ„ojB)}I)<£R¾WÓoN¿þÒ9µ%n™—Ò¯ñCÊw ×p ×p ×p ï4ü‰ýé÷}°ø½%þÖå{ÇüˆûÏU"·Müå @O™ÿýyï¿?w~Ìý皉=¿·îrljiéßG¨æïбÊÿù1÷Ÿk&~o(8³qš~Œ§çïÙQÊÿùîûË¥9×,Lüž…œó›\æÿýûwR€R>âVùïïÏ{þ©ùÎûË r®Y8p.€<}!‘ÿý÷ÏŸIJùî×ËüŒ÷矚ﺿ<µ0çÚ=8‡Jú¢•—üóËç¬ ÜÙ—¸V~âçº?ÿÔ|ÇýåŠ#ç&ι@ž¾€àŸû;<à”à N\)ägº?ÿÔ<ì§ ¶ö—ß'aGΑ–~baÁÃýŸó{è|gx7ý ·÷ÿãµú;7ö³ɹjàœ—âÓWòÿÎ#',lóû ßýú/‹‡ýã=qk xMÄÓýéœc_D®í¿‡hž§ûßC–çåÈÕýÿ5>2Ò?C~ÏyØ?î8¬¾Mæ!ü5lMR8+€ÆÛœß—8ÙOãܾûp̿ƫå?+þý{.€%pØ?þƒ4ð®<-€àJãd… ûîÁ£ÀÞ°ü˜ó4ì'lrïÎeRžðpÎ ´©xGNï/*å«ñ7¾þ¤þkì—ø€'Ä-žàFMÎÂe.÷Ÿ . óöøüÞæÁ€*gØ‹cþ5þæ×ŸØ§Æ£}ý ®iÿøgR9—Hå;#ŽÔy4ð~¼ ψó¹~0O™æ€3Ü@øœ @á¢O x-¤ñ{fá}¸K¿Æ}q´ëû\ãò-Ú7îïϘ}Ä4ù§ûû#×ýDÞîÃ×oÄ™‡òôújœ0´|ºnŸwö«q@Ø?~÷Ϭ€Wž(@_ã±8Rù°…/rgà§¹ú¸O°ý o-þ\‰ÿ<,¾Ékù¿O^_g°òÊ5°ò“}¿ßã§ßî<Ú·Æqü£¤¯Ù?Ë?6Fùø ¬—_»Á“ëËùÉ÷ߟ;'ûÖø=Àµô¥Œüƒ¬òñØ(¿zƒ'×—òÓï¿?w®™?ã÷8ê¦ÏŸvþ$»|AßÃ>-nåú~úý÷çÎÝò…2ˆ"w¶óGî –Ï+ä{É~5ŽAòÓï¯ÿÛ9¸Æïa ÞL‚§ù§P°_kùŸ~ýßÎ…ý (¤OD!ÿ{z S*__ý¼ ¿¯q¥ôI$¥üñŒJùj\M¿9ýþùKçÔJ”¸e^J¿Æ)ß5\Ã5\Ã5\Ã5¼Óð'ö§Ïú`ñ™%þÖå{ÇüˆûÏU"·Müå @O™ÿì¼÷ߟ;?æþsÍĞϬ»ÜqbZú³Õü:Vùß#?æþsÍÂÄg†€3§éÇxzþž¥üï‘﾿\ZsÍÂÄg,äœßä2ÿÙìææ† ”¸UþÙì¼÷矚_<± çš…çÈÓùÏn~ÿ&(å›®—øïÏ?5ßuyjaε{2Ò?C>㜶‡Ý£³ØdÂ_ÃÖ¤œsh¼Íù¬ÄÉ~çö݇cþ5^-ÿYñ››\Kà°üƒ4ð®<-€àJãd… ûîÁ£ÀÞ°ü˜ó4ì'lrïÎeRžðpÎ ´©xGNï/*å«ñ7¾þ¤þkì—ø€'Ä-žàFMÎÂE>“ûÏ9—Èy{|>³y0 Ê™ö☿ùõ'ö©ñhß°|6£ýã¿!Hä\f 9”ïŒ8PçÑÀûñ6<#ÎçúÁ5îìWã$€°|÷߬€Wž(@_ã±8Rù°…/rgà§¹ú¸O°ý o-þ\‰ÿ<,¾Ékù¿O^_g°òÊ5°ò“}ofÃøé÷ߟ;®pÿjéköÏò €Q¾³Ÿ^~íO®/ç'ßî<5¿ÅgÒþ<})#ÿ «|RjùÕ<¹¾”Ÿ~ÿý¹sÍüŸá «š>BØù“ìòÜ„'|ZþÜþÊõÝH~úý÷çÎÝò…2G׸³°?r/µ|^!EûÕ8ÉO¿¿þoçhàŸÁ¼™>*O1ò¿¡P°_kùŸ~ýßÎ…ý Db¤OD!ÿ½†)•¯Æ¯þÞ„ÏjB)}ÒH)<£R¾WÓoN¿þÒ95%n™—Ò¯ñCÊw ×p ï.Ì·",7¦OÅððpòò'\Îr“\PryÓÏß‹áþÒy³¸\OD…MW%ówÝß.ñkbyøvé¼qûBX¶í„+`ºê`IÀ™_  ¶?½qiOW¶5»>ÉÇO6ì?}‡¶[[Ëåz=™Ø˜ö×wjœš÷¸X†°vèë…  IÍÏP۟އͭS€mà‡'§€¢@\p(€Tdþ(€ÊþóÍÄý]õÀ`²IL }ê€î’ÎÊâ«ÃÐ}rg å}àúðñXh’Và¥òšPÛ¾ éÿu§`ÿ0ûâ-npÞÛû @ÓÿgýáÔ# ­ª¡o—Î#€Êþóæ_@ãÚ0;˜ÿßX˜¯ Ƶ`ö.îýh\[‡Áü …#  OèE­¡o—Î!€¸¿~a¹ pXý;ÅÄWðE–¦—À§¯½:'ø"y/¯ÿ|rЙþ+™ÿˆÈBRÊ(€y*€d$ÐÛºãÓÌúzûCòÙ\½ýQÑúÍ‘ e‡5ôíÒùö÷§Ú}êCoÿŸ·øðW'ÝPàé!vïÒÐÛÿéþL W,€å:¨0_3.|"ÚîíŸ `‚ýÿþÿÏRXáìP‡ýÿþÿÓ )|±þ#öÿûÿ=ˆÝ¿~,ðx¤5ó¿>øúvé¼Ù.ÙzÑöµåöw , |&À `s ³@n.à'kVî¸ãî¾ÿäÖ|rÇw†¯8ðÄš€¯îø[àÿûoþgVàeñFØ¿·š°¯€apûÏù}´}˜¬ÜHÐy'ðSpxÔ¸OÖ=àñ&þ„Gw]Ãî n¢ð¾úêùÖWŒ«!µ/ŒW× î?;óGûG€`à;}ÝÿëÆ…Ø,ê;ÎÄ4È|„0ð°À?n\øøøŸ«ž{¬!­/X0LëÉüÔxLñ¡§g‡`nèúhqjpvç†ð¡§g‡>]®~`¡„QÇ­¨  ]‹Ð ¬|ŸÏ+`F|ò}>¯€Ç0 ðà«ïóy| £ÇÖÏçÏV^?Â0ðUÀëk6 d©6Jx| ·¸> ¤ðõí†ÿû/ÔT6Œº<~Œ‰ ² ˆ;’‰ U¨w}"(ÜáÆDÐW2ÿ›MÁ ?½êo¤/MrAˆØßîB?XýKC‹WÙ°~ðék¸Å?e Ãzu|ýç«ÿ|“…G îoWAßà ’L¥^ ?ÊË ÚþúÆ ú Ç·Âæ&…™>u~%È'lþaÀÇ$à† ‰¯Øüäð×7ë"©xYü8¨ì¯ŸlÂR0lýWS8D¼{KÁðΆIŸ‡°Üì± KÁ°õÿú O÷TA0Fúê'yz|G¸Nz.€Úþz\ ¦Ç‘ß¿0+…áZP\ó… `V(, õ `z”É?0+ÔQ±†úðßP?邊Ëã; ÆhR ) ´>¬§%a0/yX NKÂ`^0òð†–„Á¼`sL„ÂiÒû´/•ï 2¿”@ w 7<ôiA@‹BÿÆa.ôI‚aiQè×ÇG±:¼ï@@Bù' iùwPaê) >ø*‚÷$ñØ·KçƒÀÍÏ%@&’ÖÏvø?ö’ÝþÆ}dw€¿ñc_€ºˆGÝ%üÈ·Kçš?J ÚhÀþó7Ù²LÞgñμÞVÍO”‡o—έÐÌOàÆ¨î?“­aW¬°Ì°­õg‚m~”€m~”À© pj^]P2ÿcÒUûpÿ­þ{é|pE¶¿^~ý‚˜‹Ñr¼ÞÝT0¹ó ·|üÁà/ -þ©÷矚ïXN‹Åhûï"€¾?ºkêõ(x©|OÝŸšûj˜ÿ’A«À­;ÉßAO’˜s6^lå8ZìµFkf¡2DómÒ|Ú§æX ‹tgý\«Àxi4Û¥¿ˆl=¥éy¸°tkS öbXÏb¥Êøk¾HJjœšcÒ°ØjõGwÊY"ÁËñ²¿éf¿ÿïåÿþC?T0^ü²lév™©ù÷­LOuââÔš ï‰S¸Y;õDÌ©¹;°g!S~ewPrÿööÏSñM­ï3H4ã_[ýŽíÛ†>¨Žê±\œ²À 'xÚå H§J!èx‘¼ÿ6¹ûS>uÇË…0Á|*ÑמlÁÓ–Õ¥¶^ŽàXoøŸ ùµ©}Ièkè½_8A·Ãh7Bѽ³mÞ|ϫDž¼/”7îuvHŸºã«Ííb*Ñ+`ô‹óQbH­ïé¹Ï¿l°X!áÅÜ@(¡¦À|!Óbùë ø®ÖÏùìßkÞ¸§gCsG¥pço}÷J¸2ÝbmËV—0K =ÊG[!€˜°3ÿËKÜ̼ìO»C`aœˆèG¢nÚx݆Ó^ð™VR°ùcgÞ”¿ëõs6û÷ßš7Ôø÷gÂÀ ˜/ü-,Ná3œ?w#i65ŒBÌß/.á-˜/¸S¶.­—ß±¡Jм­K4g»ÿ­yóø¸ÝºšÁ¿‰¶Û_¬ ÷Kÿ vŸÒtS>1¾Lƒ€ðàow|þ ïåPÎÀvÃ5Ïd Geç¿zÛ0d!©À åM×ýúå‹¿~ÍR ¹îØ 7àoªBfÀêz‰è”¦{Yäãó;Ò'xÓ±@KÿbcÄ%Ž û/ R΂7d£- ‰«Whü»U?g²}û­yóððòò}xy‰uƒ1´Æ¿¢ ¹±ÝMj˜Òt¾„yüðn¢€¶L;Ûù ÍEÆ>æÒ Cfÿ-ÍC¾ÌYKæ&.èŒY踬 ‡‡¸U«À¿½eîïöàbv~î*w7Þ<=áCW´Î”®1†¦8@˜Kñp*™7³ØÆb €i>=Ñy{áÎA@sÔÆûå[z1Ó0¢‡@À˜OèÎqcG™ÎAÀ>èö„/è×зø-ü:÷þ×ìïÏÿç?‰…«¼×ô¯_înuw Æ€ —ô÷03 «ö&LƒÒŒ-€ÀM@û&dܧ6ÇÐÀ´_ ÈæÙù‘݉>ZF”©‹ÁNë„|&›WÐzA ¯ªÒ ¬qÿóì“}9nÚ /hvæ½}ÿÃ繆ð^óyü?óyx>û@†`m8 Àawïù4sÜüÎãßø3wÝÆy€ì¸nç4ŠHm§Q<ì~¢L“Å^DN#ñÞP1p¸Å ˜Üx³/÷¾ß—{ßìÂ{l·Î&}ÅÝDC¸€oˆjÄ÷>²}¸™Qš©r¹Ø44ïó\Àbªé42ÿbZš›§`Hد´*°Æooñ÷Ù÷åþ½-€ §Ÿ Ü… Ð/bpã¯\iŽ DfR¶²Gˆ‹}òè]b£¼öÑšðÆŸHñF£(³e|¥a>Bxu~¹‚U5¾AûšM|ã¶-»‰¯ñxsçý0p±p­vçqQÍØù}2À &áöï1¥™ ³N¤‹MÑ-HÉ}>A²et bô:tW¼Ð‰¤d¡sÖ‰ªñ „ýùýý}òu7ŽàxM£‘;Úß97¿™šPÆQƒÊìß €ÒT #A=á0†µ €ä>ŸÍJ ûB‹Årž á¦2Œ”äG¾*]FÕø„ÝßûðoìþÞ‡ÏØý=Œ7KhÀû¿7¬ Àj]ºÉÜòDΈšdñª…Ò”3ÚD¬Ï™Ýx4èo°É s"LJµ6ZÒk_—Éz¼¬M$É A©ÀËã½Æîž™¹¿ažœjwì*°<•Û×£?yÆ 4¥´©dl‰c¾¤€¤°æT.…`ÿPwt=®M%¿·jè>VàóþÃLÐÿ¥æ™Õíz\{™Ãçcb!MŠ/“ðš ÂVGo”ßF]øÛš^üû¦n}@UìÍ]Þ¶®kM5%Àß–_'óˆ>âz²¤´Ìþòu.ŒõQ¦å œïëÚ·æ ¬Øjò!qÑæ€Ùb,Hm<¢4k J¶ˆc=^*0t„òºEˆ¾9Ê»X(ú ­ NO¾—x±¼ÿ¸óÈe˜ýíæÐ†,éšÿ’p©qÑ_mIèv6;<›Éiˆ$@$u±+•Ï€£ Jjè>­ÀKåîKº) ]^7dQçVM„ñs²•²€ngóãAŠùAãê~eQi¨ ^EñØ·Kçð=Û õ[Ö]KÃ…Ò²r`•²´eÝØ*äBÈ—•³ ¢*âG¾]:ÇCÙÆ€ä²±£–FmcI íÚ€¶±ƒÂX¬1C¶±DTP¾]:÷Õn ȪwÀÖ.}S@ µ­e18—ƒÊaukçÝ œªNm€SóªêÀݽ»l.m[ŘúæÎb”áÔ85ß¡ªÀÁÛËí݇†SïÏ?5ÿ¥>ÄEvQ¾IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/joystick/0000755000175000017500000000000013263212010021245 5ustar aeglosaeglosmirrormagic-3.0.0/graphics/gfx_classic/joystick/controller.png0000644000175000017500000016313313263212010024145 0ustar aeglosaeglos‰PNG  IHDRà,þ`ZsRGB®ÎébKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá7)F¥ÿA IDATxÚìwXWÛÆïÙ]¶»ô…]–ÞÁ†5,±ˆÆ$*c‰±5&öþY°¡Ø¢Áèk‹½[Œc‹"bèm—ÞØ>ßyÙWc *ó»®¹D˜3ûÌœsŸòœç@ @ @ @ @ @ áµPÄÐè±àþ–mv€BbB"À„·xFb±x”@ øÚØØØˆ¢(úM>¬Ñh(¹\^¢T*ÎÈÈØ ˜”@hXŠD¢IÆÆÆ¹ººš´mÛÖˆÍf¿Q›MÓ4®^½Zž’’r!55õ+ĬBͰpvv¾²zõê2¹\N+Š·:ÊËËésçÎÑ!!!2—«mˆi „F‹¡D"Ù˜qâÄ MEEÅ[×ýêãÒ¥KšV­Z=a³Ù­ˆy „Íf»yzzþõàÁƒw®|Ï)))ô Aƒríìì6`K W—Ä'N¨k³Þ+ Z*•Ò]ºtÉ´°°x˜™@xÇ¥uëÖiYYYtmWÂêcëÖ­•vvv§@–!„Æ‚­‡‡GZzzzÕû’’ºGÙ†††ÄÜ “˜ ÑÁurrúíܹs®VVVuVˆŸŸŸƒÁ?zôˆ*//ÿ˜@hXÏ?~¼µ½½}•Áb±Â?zôèûßPË7d ²‘aee5æ»ï¾s …u^ÖW_}elnn>‡Xž@hP<:vìèîææVçñù||õÕWvL&³1;`Âó•£wÏž= ê£,Š¢f Xž@h8LMM{………YÕWyþþþ‰DÒXž0áÙÂ`Ø[[[×[y>>>|@àI,O 4ÀI$Õ›?†««+˜L¦/±<`Â3QUŸåÇã™Ë ‹Å2566®·òLLLÀb±¬ˆå‰þÏÔÔ”[Ï‚‡# ¦'cCCÃúîì³&üG777ƒú,Ëå‚Á`ð‰é „†ƒ¢(#W¯eš™™që&üW€½¼¼êU y<˜L¦11=ÐpÐ4mÈåÖëä<<<؉õ‰XZZzº¸¸Ôk7˜Ãဢ(±>РÌ«oöôôä&Lø/ÀÇѱ~ëÃ+=`¡aa³Ùìz-ÐÉɉ+ É"À„ÿâfggW¯r8Ð4M˜@hȆ˜Á¨÷¶ØÞÞ|>Ÿ$g L‹eVŸ[žs‰õ „–%Àÿíì»ë&ü-†õ>e³Ù išM¬O ´,666“É4#Ö'L˜FFFõ“™Åb¦ib~¡e pCuú D€#6‰„Õ’*?@hØ:Èãñ8Dˆ[GGdžÊJDr EQºéõÛØ0X’'@¸EÃd2m$I½ÄP*•Ðét•ä  ‡J¥R6D¹öööl"òˆ·h,--[¹¸¸ÔûZlQQ(ŠÊ#O€@h8t:¼ªªªÞËõòò0™Lòˆ·hø|¾¿«kýï(((MÓRò„C¨Õj颢¢z/ØÃÃ-‰È#hXĦìZßA8 °°jµ:ÔÞÞÞ,//ï˜B¡8 <¡N ´²¶¶Âápú % O§ÓYÀÖÖ¶^oÆÍÍ §-y,D€[*Næææƒy<ž'“ÉlðÔ©S…­[·þøæÍ›!¿üòKaFFF©J¥úE&“íð'š<&áD·½D"ùŠÃát à÷ë×Oضm[ðx<Ð4-[¶ °°þû½VVV (ÊŽ<""À- ž¥¥åxccã1^^^f½{÷þúë¯ ²'Ož 00Æ ã 6L¬ÕjÅ÷ïß÷:qâħ7oÞ,U*•'¥RéäÑ5ÆN,Oçp8»wïnfáááŠú{ÓÁ;w°iÓ&dee¡¤¤þþþõß3 (zŠÅâm999Kd‘ÇF¸¹Â …“Á´1cÆØ 0€m``€ÄÄD¤¥¥5È edd &&gΜF£Á?þ777 ÀJ§ÓYݾ}{Ú®]»>INNNÊÉÉ™©Ñhn‘GI ¼\Ó8Î{666K]]]FeÓ¾}{ªZtŸ%-- qqqÐh4€¬¬†Ñ>///V¯^½Æìܹs@FFÆo999‘GI¸9á ‘HŽ…‡‡»>ÜèÙéæ””øøø4ÈMI¥Rèt:äååÁÆÆ666Ï÷ tìØ‘êØ±£(77W´~ýúÓ7oÞ|=€Œãææ†˜˜‡Ó Qt-¡P8588xtdd¤•‰‰É}¶mÛÿ9 ççç7Èý{xx 55Uÿ6›U«VY~ôÑGcmll¶&Ü$177âííýãž={D¯K3X^^þÚ‘g]¢R©ü¥_¿~5þœ••6oÞì,‘H.0&O›ÐBëxXëÖ­¿3gÎ[e0`ŒŒŒ•• ÎÅÅ/úWNž<ÙdôèÑ‹D¢C˜äi×>d ¸îzÅc}}}—nÚ´ÉŠÅzµ™u:húßwù”––¢¨¨ŽŽŽxÖ¡###jµú¹s `ooÿFÌçóŸë×wwwjõêÕÞ3f̸˜““óÒ’Ðb}ÜÝÝ7oܸÑêms)@  ¢¢JeÍ£Q–””àÙÈYL&\.yyyÐjµ/´ ––/Ÿ¬b³ÙzG°ÎýÖ­[wF&“  "OžŒ€5"‘hvçΗEEE½V|¿ Äbñ¿^S.—¿ÔIÃÒÒÖÖÖ(//Gyy9¬­­_YÑ^'À–––000x›„¹jÕª¶b±ø7|òô -33³~žžž?lß¾Ýúßêøëàp8°°°x®.Ö„ÜÜ\dff‚Á`€Á` ¸¸wîÜB¡EQ`0ÈÊÊBnn. ^æ…ýO~Uù~ø¡áüùóߋŒ§O¸±B‰D¢U½zõšýÿ÷–5 ¬‘œœŒÖ­[¿u†††066‹Å‹Å‚±±1 kVG*++õ=å÷Þ{ï­ï¡C‡¬õë×ûK$’Ää5 4g¬­­?÷õõݽk×..—ûÎ×ëÞ½»^€k2VN§ƒJ¥‚R©„J¥‡Ã‹Å‚••¬­­a``‡kkk½È¿ ‡×n… æ¬\¹²“X,þ€€¼D€øÚØØìøè£ÆÎ;×ìßzœÕ¤¦¦¢M›6 rÃ………Ðét077GïÞ½ßéZ~~~ŒÝ»w{»¹¹]çp8ï‘×Ð a‰D¢-ï¿ÿþêmÛ¶ Ùlv­\´oß¾033ƒN§ƒ\.¯ñç˜L&ŒŒŒP^^…BOOO¼íh¼mÛ¶HNN~í9:ubmذÁÏÖÖö:ˆó%àFS$3fÌÐI“&½‘äÓ§OßÈúÁƒúãeŽoBAAÔj5 áææöÎFpppÀáÇz÷î}P,ÿ€¼„æÇëhoooÖ¬Y£-Zd^›acÝÝÝaddFóFá(Y,ÌÍÍѪU+<|øð¹] o‚··7RRRþõ¼6mÚ0¶mÛÖÊÎÎî: y3Þ±GGLðΰmllNM›6­kHHȯdeeA$ú÷tœ¶¶¶¯ Ôþ6< QUUWWW¼­É?144ÄÚµk…÷ïßÿxÍš5Ý¥RéS©TúF£¹A^BS«ÛŸóùü ;vMŸ>ÝÒÌÌ¬Ö a0H$xúô)òóóáèèø¯Ÿqtt„N§ðw8IwwwTTT<7~6ìeM:=ªé¹Ô?üàöÅ_üžššÚ @yUˆ7†b±ø—yóæµ zãù(š¦¡Õjk\Ij›üü|(•J|ðÁµ~m???ÆÞ½{msssm7oÞ|òÚµk©R©t cIh í¢¥¥åSSÓ©£F <˜[[Óͯ¢_¿~xøðaGÀç¹ÿS…nuäñx5.ŸÏ磸¸¸ÆçÛÙÙáÇt5jÔÅ´´´jµúOòÚ®OLlmm/®\¹²uÇŽßÊŽEEEo䱜ŸŸ;wî >>ÈÏÏGYY*++¡R© V«õNL&L&l6l6\.†††àóù055… îÝ».—ûÆÛÞkkk,^¼Ø2??ßrÍš5§nß¾Ÿ••5@"y… ÊÌÌl˜‰‰Éâ/¾øÂ6,,ŒW×Êär9RSSÁ`0 Ñh°uëVœ>}åååú­IJ¥jµ4Mƒ¢(°X,°Ùlðx<XXXÀÁÁžžžhÛ¶-¬­­ßüËSt:]gÄB!öíÛgñsJJÊ…Bq¼Bohsb‚·ÂÊÖÖöÒÆ½|}}ßzî6..?Æüùóõ¿«¬¬Ä… põêU$&&B&“A«Õ‚ËåÂÄÄÎÎÎpvv†½½=¬¬¬`ffÃá€Éd‚¦i¨Õj¨ÕjTUU¡¢¢r¹r¹eee())AAArss‘››‹üü|”——C­VC¥RÁ›6mBmxxþ“ŒŒ ,[¶L–˜˜x-''g)y ‡Ãéimm½1,,ÌþóÏ?üs„Y<|øûöíÃü p8ðx<ØØØÀÊÊ B¡–––055ŸÏ×ïh044‡Ã›ÍÖ×o•J…ÊÊJ”——ëësvv6RSS‘ššŠ’’ý–$kkk¸ºº¢K—. ‚©©éKïoäÈ‘>|8<=ß,¬\.ÇçŸ.KIIUVVKÞ&"Àu‰½½ý…­[·º¹ºº¾Ó…6mÚ¹\Ž’’¤¥¥A£Ñ@ ÀÇÇðòò‚»»;Þ4¼Ý»@Ó4Ö®]‹7n`ݺuuVΣGè¥K—æH¥ÒãR©ô[eäÕ"4¾vvvÛzôèá1eÊóºªkùùùX¸p!"##1gÎüôSýä9ËåHJJ“'Op÷î]}ú—£P(0vìØ¼ÄÄÄ)ÅÅÅÈkU3Èô›áæììüËÎ;%’7sÔét¸|ù2Î;§÷6 …èÞ½;:tè___Ô$€;hµZhµZ¨Õjèt:p¹Ü· ¢ñªi(CCCTTT --­F!oƒuàÀÛ«W¯Ž[µjÕ ÂÂÂòóóW¨"¯¡p¶µµÝìëëë?gÎaM!ß…7bÉ’%°··!JÕ» lNN˜L& †~ÙÉÌÌL?j¶µµ…úöí &“ ‡•J…øøxܾ}‹/Fzz: ***`kk‹Áƒ¿Ñ —ËÅ®]»„“&MÚo*“ɶ’WŒŒ€k ?''§“»wï¶³²²ªÑgŠŠŠ°k×.ÄÅŦi´oßýúõC§N^+¶ÅÅÅ(--}©øýñÇÐh4055‹Å‚J¥BQQ|||^9µô¦„‡‡cÒ¤IX½z5V¯^]/£î³gÏ*£¢¢d%%%› 7€„¼#Ô ¶b±x½““S—¹sçŠ\\\ê¼À§OŸâàÁƒˆŠŠ 6 ÇŽ«•k !!®®®022‚V«Eff&är9Ú·oÒÒR$$$@(‚ËåB£Ñ //æææ/l¬¬¬Ä;wð믿âÒ¥K¨¬¬„‡‡"""j<-­ÕjñÍ7߯ÅÅ­•J¥+ÈëFFÀï —Ëíæâârà‡~ÿÛUee%¶nÝŠk×®ÁØØü1¾ùæ›…›|V€³³³!‘H^ØX_íbmm µZÒÒR½“UmP}M___899áÆ ¬Û^ E¡ÿþœ¾}û:œ8qbñ¶mÛ&”••EFP’7P ˆÅbñ*‰DÒsΜ9booïz)T§ÓaãÆØ¸qãsÎjgªÚ¸>ð÷–ÂòòrP…B@&“©ÿ;ƒÁÐGË300ÀËœË Ñ­[7tëÖ ÀßIb~ýõWlݺ©©©ðôôÄ„ àààðÊûa2™Xµj•ÅÒ¥Kgž?ÞB*•Î@“×ð[Áçóû¹¹¹}¿k×.›×…x<þ<öìÙ…BO>ùsçÎ}#ççÊEW«Õ¾ À, UUU(//‹Å‚‘‘ ñ×_Á××÷¿ïéӧѳgOÀ7ß|ƒððp$&&" ­ZµB]z…2™L„††rìxüøñ¥;vì˜(—Ë¿ÏËË[@NÞFÂ[à,‘HVÙÚÚΜ9SÔºuëz™õ«¨¨À;w‹!C†<·×ßÌÌ ÅÅÅ5^rª‰ÛÚÚ‚¢(üõ×_àñxpwwƒÁÐÿ½Ú‘K£Ñ€ÅbA.—ë~MÛ‡ÐÐP„††¢ªª gϞŲeËPXXˆ^½zá‹/¾xéç)ŠÂ¼yóÌLMM¿8|ø°¹L&MDøƒb‚Wcaañ©——׺èèhá˼"U*6n܈+W® mÛ¶˜6mÚ;Åu®&''ÉÉÉhÛ¶­~o_õö¢'Ož ¸¸^^^P«ÕP*•ÈÎΆ©©é{/¾Œ°°0lß¾]_®R©Ä7ðûï¿ãÞ½{àp8èÙ³'\çö×jµˆUoݺUVVVvR*•.ñš&ÔŒvvvv+]]]½§OŸnSù¶ °ÿ~ÄÇÇÃÈÈ]»vE=àååõÜy+W®D¿~ýо}ûZi+RRRàïïCCC¨T*††† ZßjŠ¿¿?Ž;†ÔÔT,Y²Û¶mÃÇŒO>ùÌ622jÿÍ7ß\“J¥ï(%¯1™‚þ§øîúôÓOCÇ/€«W¯bÓ¦M …X´hüüüÍÍÒ4 ™L†¤¤$¤¤¤ 99éééÏ¥3ãóù°´´„‰‰‰¾2³X,P•J…òòr"##r¹OŸ>ŬY³ðé§Ÿ¾¶ì¡C‡bÓ¦MÆ•••¸víšöĉyIIIeæqAAÁÉÊÊÊ»ø;P<éq7mx¼AgSSÓ\.×¥mÛ¶‚Áƒ[µmÛu.²¦ÄÄÄ 00PïEü:|}}áíí SSSXXX€Çãé½–•J%***ôá(«˜¦iðx8^'´R©=£Gðøñc}ÐôêsŽŽŽptt„ƒƒÃ[¯Ó4Ó§OÃÊÊ :uúWÞ¸qc£ì™Ó4œœܽ{WóàÁƒâÄÄDUYY™B­V+T*U%€,µZTTTôX©T¦Èøï¨™¬M5 üÖΞÃá8XZZ¶b2™®lY,–›Íæòù|®··7§]»vþþþÔÛî.¨k¶nÝŠ¼tôŸdddÀÞÞþ­FÙ2™ 999ÈÉÉAvv6²²² “É Ñhô#lGGG}ØZ—Zñ¸~ŠŠŠ‰“'O¢gÏž˜2e îÞ½«™9sæoR©´7àŽÍº°°°CCCÓ3gΠcÇŽøöÛoaggW¯÷QQQÇãáÇxøð!222@Ó4lllЪU+x{{ÃËË u‘íM1b–/_ŽºÎSÛh4äççW7`tfffyZZZeff¦¶¢¢B©T*+Õju9€4•Jõ$???A«ÕfÈÆßÞ×ê7(΀-+æ&|>ß‚Íf›0™LƒÁàQÅÀe2™Z­Ö€¢(MÓ Š¢˜ø;W7ãuTûw_ƒÖ•——[³Ùì\.—[AÓ4€¢(êeŸ£išÖR¥ ¥iZGQ”€Z«Õª(t:B¥RÉU*U©\./Öétåø{ª°€ @!ÞÌñÍ€€-ƒÁ° …^l6Û‹¦i{‡#`³Ù\###®½½=ËÑÑÑÐÞÞÞX$QÖÖÖ°²²jT#ºš°~ýzŒ9ò¯çúî€æçç#==]:55Ußi711››ÜÜÜàîî77·Zqàü7är9¢££±wï^øúúÂÙÙY¾gÏžïe2ÙT"À-¡P¸R$MS©Tì?ü'N¬óÞ"MÓÈÌÌÄŸþ‰?ÿüñññ¨¬¬ǃ——|||àíí {{ûF9Ê7nf̘Q¯1ªë •J™L©T ™L¦MOO/ÏÌÌTäääh”J¥J©T*ÕjµR£Ñ()Š*PFQ”ò¿bɧiZÄápL---¹‰Ä@,sÌÍÍy€mdd.— 6›­÷bg±XúP‚Õá)ŠzîxöÝ©ÞÛ©ÓéPVV¦ÿlõ¹Õ?ÿóÓétzOXN§iªÑhôÉ;”J% *++!—ËU%%%м¼<¥L&SËd2uYYY™N§ËKÓtEQ Š¢Œ˜Ò4mÊd2Øl6‡Åbqy<[,3íììx|±X̋Š…M®óV–/_Ž3f¼Õȶ¾(--EJJ ’’’ôGõ4wu6%ooo´jÕªNÚA•J…ÿüç?ˆŠŠ‚R©Ôdgg/¨¬¬\N¸åa'‰~³´´tš4i>þøcÔE•J…„„yò³fÍÒ%$$¤gffvA ¶ÓÒ¸µ½½ýµÉ“'M˜0ª !ÌÏÏGll,Ο?¼¼<´k×ðóóC]gXi(BBB°eË–f=Ò#Þ”˜˜´k×ï¿ÿ~³þž*• ÷ïßÇo¿ý†7nÀßߟþ9œœœÞéºW®\Áĉ5999Särù"ÀÍ6›=ØÑÑñ§Ã‡³ÞÕ«911'OžÄµk×`bb‚àà`Á¢ÙÛ1//3gÎĪU«H‹K |¸/''g$àf‡ÃéëêêzúܹsÌ·]Ÿ©N)vóæM¸»»cÀ€5ŠzÓÜØ·oªªª0pà@Òâÿ£ñãÇãøñã-òû—••áСCˆE«V­0jÔ¨·ŠO¯ÓéðÅ_è.]º´W*•†nÚœœ².]ºdð¦NCr¹û÷ïÇ©S§ààà€°°0tìØ±É¯á¾ áááøöÛok-÷0МX¶l&Ož WW×m‡û÷ïcïÞ½HOOGÿþý1tèÐ7Ú>©Óé0hÐ ÝÕ«W?W(1D€›(vvvO7oÞìÖ»wï_RR‚_~ù§OŸFyy9>úè# 8°N<¤›jµC† Á¶mÛHKK ¼„+W® 77'N$Æ P(‹#GŽ@ `Ô¨Qèܹs_‹‹‹ÑµkWUrr² ই_—.]þ¸páÂk½…’““qæÌ\¾|ÁÁÁèÓ§¬¬¬Õ—Q©TÈÊÊBVV233‘––†œœäççC.—?·Ç³šg3 À‰puu…»»{¶N\½z.\¨³,.BSG©Tâ믿ơC‡þõ\­V‹ŒŒ $''#)) ÉÉÉÉd(..†V«}nO÷³û¼)ГɄ@ €™™„B!D"$ lmmagg÷\2†ÆBVVöîÝ‹¸¸8ôíÛŸ}öÙ¿î5Þ±c½xñâýùùùŸnbØÚÚ^ß¶m[`ppð Bvýúuœ={ñññprrBß¾}Ñ­[7p¹Ü½çêJ™˜˜ˆG!11Q¸ËåÂÁÁ‰"‘ÕƒÌÍÍaddT£^¥F£AQQ‘>åáÇ‘˜˜ˆ’’£k×®èÓ§üüü^ðrž;w.‚ƒƒ4ÒÐØ™€LVVªªª@Q,--áââ777¸ººÂÅÅ¥ÁÛ8Fƒ_~ù€@ À矎N:½´ýR*•hß¾½âéÓ§¼æø®4kvuu­¼wïÏÀÀ¹¹¹úíBr¹:uBïÞ½áååÕ Ñ¦t:ÒÓÓñøñcÄÅÅ!>>UUU`³Ùú ãââ'''X[[×Ë=* œ?ÇŽCZZ¼¼¼0vìX}å8p vìØÑ$²³ Åþýûáââ‚B.—ãСC8pà*++Ñ®]; :­[·®ózDÓ4ŠŠŠššŠääd$''#55*• \.®®®ðöö†··7ÜÜÜ$ˆJff&bbbpçÎ 4Ÿ|òÉ û¨  ;þ¼#€L"ÀM¦µµµzúôéÔåË—aff†Þ½{£gÏžõî@¤Óéð×_áÎ;øí·ß’’Š¢àää„víÚ¡U«Vpss«Ó\¿oÃåË—±aÃ( |ôÑGˆÇâÅ‹I K ¼†ììl¬Zµ ‰W®\AÇŽ1kÖ¬Kˆð2T*’““‘€„„$''C£Ñ@$ÁÏÏþþþðöö®7ßµZ³gÏâÀ°¶¶Æ˜1càááÒÒRÌš5 gΜÙYUU5†pA$måóùcW­ZEÖë´Kee%nݺ… . ..UUU°··G÷îÝÑ­[·FãùU¤¤¤àË/¿„¡¡!æÍ›wwwÒʯuž;w .ÄèÑ£1eÊ”&µk"77W£þñãÇP«ÕpuuE`` :wî ¡PXç÷””„íÛ·£°°¦¦¦HIIT*-ÏËËQXXx‚p#ÇÂÂ"¤{÷îß3 ó]»vÕKïíöíÛ8{ö,®_¿¥R www 8ï¿ÿ~³‰›––†¨¨(”––bܸqoµÇ@hÎ#ß•+W¢mÛ¶?~|³H8AÓ4’““‡Û·o#??ŽŽŽ B=ÀçóëüN:…ŒŒ 8p ûÏ?ÿ D3šŠnŽ,puuýsýúõ±±±X¶lY"—Ë‹ƒ"33666øàƒ0dÈf¿e)++ 7nDii)&L˜ÒúZô¨÷СCøí·ß°xñb8::6ëïšžžŽ+W®àêÕ«Ðh4èÞ½;>üðCˆÅâ:)3..çÎCçÎ1iÒ¤˜ìììˆæbÏfÆI,G/Z´HRTTT뱘išÆµk×°iÓ&ddd U«V˜>}:Z·nÝ¢‰D‚U«V!==k×®“ÉÄĉammMZcB‹¢  K–,A‡ðÃ?4û =EÁÑÑŽŽŽ9r$ ~ÿýw,\¸EEE EXXX­BD"òòòàãã[[Û^ÙÙÙÒɸ‘Áãñ:ôèÑãÔÆ…§N‚¹¹9BCCßùºyyyؽ{7Nž< gggL:•L¿>ÃãDZjÕ*¸»»c̘1r"PÛüþûïøá‡°hÑ"Ò¨¨¨À±cÇðóÏ?ÃËË #Gެ•-‹J¥áááØ°aÒÓÓ1jÔ¨›YYYÐMÝfÍ) G$ý²mÛ6.—‹«W¯ÂÇÇvvvou±j¯¼Y³fáĉèÙ³',X€Aƒ5É|Ÿu‰•• ¥R‰Å‹ÃÐÐÎÎÎd»¡Y¢V«‰ÔÔT¬_¿¾EçÅ~6›Ö­[#,, سg¶oߎòòòwÚÌb±pàÀôïߦ¦¦P*•‚§OŸVUVVÞlê6k.ó%”Íž¹sç:Uï!ËÏÏ«)èøøxLš4 }ûöEbb"¢¢¢pàÀ|ðÁ$ýÞëE¡W¯^Ø·oÒÓÓ1yòddeeÚIII7n±|ùòjÑXñööÆ’%K°sçNðù||ùå—;v,.]º­VûVíK5_|ñ…@,  É'$okÀB¡pôÇÜ·gÏžz·ÃÜÜÜ÷L °oß>œ>}žžž>|8|||H-zË^ð´iÓ––†… ¢mÛ¶ˆˆˆ B“õîÚµ ˆŠŠª—í8Í¥=0` ™L†#GŽ`Æ hÓ¦ FŒQã¤EA§ÓÁ`€Á``Íš5¶£GÞ“™™ÙƒŒ€¦©©éÌñãÇ žý¥J¥zíZ¤B¡À‘#Gðá‡b„ H$8|ø0V®\IÄ·pttÄîÝ»!‹1vìX<|ø…Ð$¹rå ÆŽ ìØ±ƒˆï[bccƒ¯¾ú {÷îEpp0¢¢¢Šèèh¾ö³æææ(--}®}éÚµ«'€&íÛäGÀfffúé§¶ÿa½ÌQ«Õâêիصk 0pà@DEE‘ÔzuEQ2d‚‚‚°lÙ2=zS¦L!ö&4 ÒÒÒ°nÝ:¸»»#&&†††MæÞu:Ôj54>±ƒX,Vƒç0§( þþþð÷÷‡Z­Æùóç1mÚ4(•J„……aÀ€/ØšÏ磲²ò¹”†&LÞ¼ysUjjj_"À 'À³ÂÂÂŒ^ö«GÂׯ_ÇÞ½{‘‘‘÷Þ{ß~û-$I“ø~jµùùùÉd(++CEE…þP*•/œÏáp`ddcccƒÏçC$A(6Ø sss¬]»wîÜÁ¬Y³Ð£G 6ŒLK%r¹ÑÑÑÈËË `ooß Bš››‹¿þú iiiÈÊÊBNN PTT¥R N÷B&4š¦ŸË T}-š¦Ÿk#«3-1 0™L˜ššÂÊÊ b±öööppp€‡‡Äbq´øàƒðÁ ´´gÏžÅðáÃÁb±0tèPôíÛÆÆÆP©T/lm²¶¶†³³³Ojjª€´IRšôðÅê0bĈ³sæÌ±øçßfÏžŒŒ h4tëÖ Ÿ}öך}ee%=z„'Ož 55éééÈÉÉAEEÅs•ŠËåÂÈÈGp¹\°X¬ç*Eu¯W¡P@©TB©T¢ªªJ/ÖÕ’ÅbÁÊÊ pvv†››üýýëejM§ÓáÀ8qâ¦L™ÒâöP/Z­GEll,&OžŒ.]ºÔ[ÙÙÙÙøã?ôíAVVT*4 x<ÌÌÌ`ii H$ØÙÙÁÎΠÖîA£Ñ 33ÈÈÈ@vv6òóóQXXˆÊÊJ°X,p¹\8;;Ã××þþþhß¾}*((ÀÙ³gqúôi( TTTàÈ‘#/ŒÞÿüóOzÊ”)ÑÙÙÙ_®gb÷îÝÛçÙ:kÖ¬—ËÅÔ©SÅ´Qee%ââ⇠33F?:‰D°³³ƒ‹‹ ¼¼¼`aaQ§÷£Ñh””„'Ož 99999J¥Ðh4`³ÙpttDÇŽÑ·oß;I¼)ÅÅÅX¾|9`êÔ©/d@!ê“[·naûöíèׯ†^§³3?Æ¥K—pëÖ-¤¦¦B­VƒÃá@,ÃÍÍ mÚ´AëÖ­e(Ëê¶ìÞ½{HIIA~~>(Š‚µµ5:v숞={"  V§¹u:Ž?ŽŸþ+V¬xÁó<444õÑ£G^”D€ëa×®]ïìÚµK?—LÓ4/^ŒöíÛcèС rSÕq¡/]º„›7o¢°°4MÃÚÚîîîèÔ©Ú´iÓàë0¯B©TâÎ;¸zõ*âããQYY [[[|òÉ' ©õFáöíÛX½z5ˆ²w˜P¯¤¥¥aÆ H$˜6mZ­Ž(«Q(8zô(Ž9‚¬¬,ðù|xzz¢k×®hß¾}£m Þ„'OžàâÅ‹xøð! allŒÀÀ@ 0:t¨•éë7n`çÎX½zõsíÐÑ£G«V­šXTTô=àzB$­^½zõô:èŸì† ààà€áÇ׫`]¼x±±±¸wï”J%„B!|}}Ñ»wo8995ùÊõàÁìÝ»)))puuÅ”)SX«#ò]»vá·ß~ÃôéÓáááA”P§””” ::EEE˜={vÄo¾rå ¢¢¢’’www 2þþþ-¾ÅÅÅ8qânݺ…‚‚ˆÅb <aaaïÔɹrå :„åË—ëE]©TbðàÁ¦¤¤´!\?°ÜÝÝO:å\=b:vì¤R)fÍšUç…ß»w‡Æõë×QUU‰D‚îÝ»£OŸ>Í> ã•+W°{÷nh4Œ;Æ «µ|nn.–.] >Ÿ‰'ÖÉh„вQ(Ø»w/âââ0eÊtìØ±V¯¯V«ñý÷ß#&&|>áááèÚµk‹·{||<>ŒÇC  $$Ç«¥§ƒ"%%“&MÒÿnÑ¢Eûöíë àà:ÆØØxÈäÉ“wEDDÀDZgÏlÞ¼¹N<õT*Nž<‰cǎ᯿þ‚‰‰ ºté‚ÐÐлv™™™‰õë×#33“&M§Ÿ~Zk¶¿qãÖ­[‡>ø¡¡¡Ä[šðÎhµZ?~§NBDDú÷ï_«Ëjµ7nÄþýûáááéÓ§“µ¯i;öìÙƒÀÊÊ #GŽDhhèuä—,YôêÕ ÀßNl'ÒÓÓCˆ×1·;ÖÎØØ¥¥¥˜1cvìØQ«¹)•J%Ž9‚C‡!;;ÎÎÎæÏŸ¾}kgKžF£ÁÞ½{qöìYŒ?:t Æ&¼14MãÂ… Ø·oŸÞÁª6ósët:ìÞ½ÑÑÑðññÁìÙ³›Ô~áÆ02Þ½{7RSSÑ­[7L™2¥FËcÆŒÁŒ3ôç1"óÖ­[¾J‰×® ø=22Ò†¦i̘1Ó¦M«•¬:gϞŮ]»™™ 777|òÉ'd«L ¨=)°qãÆZÛòUVV†ÈÈHdggcòäÉÍbMP?Â{íÚ5ÄÄÄ sçÎ=zt­ ãåË—ñí·ßB$aÞ¼yω ¼y‡{ÿþý8sæ ,--1sæLtïÞýµŸÉÏÏǤI“.—‹ .h.\8?77wà:B"‘ü°eË–pOOOûìBzzz0àZÆÁÁáÁ©S§ZïÛ·¶¶¶øè£jüÙ¼¼<|óÍ7xøð!ˆ#Fgªz@«ÕbñâÅHNNÆ÷ß_ëÓu×®]ÃŽ;`kk‹ˆˆˆ·ÊMhz( œ8q±±±ÆðáÃaddT'¿víZüç?ÿÁôéÓÿu]’Pw\¹rëׯÇ×_O>ù乿ÅÇÇcË–-ø¿ÿû?DDDd_¿~Ý@AcÿNMi‡OppðDOOO£S§NaöìÙ5šzÖh4X±b¾ûî;tïÞK–,ŸŸ‰¸TO0 ôìÙ666˜6m´Zm­z4ÛÛÛ#$$ؼy3~ýõWXYY½ñÌ¡i““ƒ;v`Ïž=ðóóÃwß}‡:ÔIØÆÔÔT 2ضmœÉhØú÷ïÅ‹#!!ÁÁÁúv\("!!¥¥¥h×®ñíÛ·Õr¹ü׉äà¶mÛ†®[·+W®„X,þ×ÏÜ¿'N„‹‹ æÍ›W«ÛoNee%f̘‡ƒÝ»w×É´qvv6vïÞGáý÷ßÇ€H@&ŽF£ÁåË—qòäIbäÈ‘hß¾}v¢·oߎ-[¶`òäÉ "¡¡Óé0gΰX,ÄÄÄèã¨T*Œ1‘‘‘øøã“RRR<舿;F¾¾¾‡n_UU…±cÇþëZºt)N:…ùóç“mDŒüGEdd$Þ{ï½:)C­Vãܹs8~ü8hšFpp0ºwïN’>4´Z-îÝ»‡Ÿþiii BXXX'*),,Ä知R‰µk×ÂØØ˜<ŒFÊÿýßÿA&“áàÁƒúÁÕíÛ·qèÐ!˜™™•îØ±cˆR©ü•ð;bjjúÕÔ©S×^¼x‘³wïÞ×:óH¥R„‡‡C(bÑ¢EÄ«¹‘’ššŠ™3g¢OŸ>X¼xq®Ç—”” 66—.]Byy9\]]áãã///ØÙÙ‘w¤¡iyyyHMMErr2îß¿ÒÒR`РApss«—û8~ü8-ZD<œ›‘‘‘ÈÌÌÄ¡C‡ôõxÖ¬YèÞ½;–.]ú[FFÆ{ùþ›„;88<êÖ­›÷!Cо}ûWžwáÂÌš5 ãÆCŸ>}ÈÛÙÈÑh4˜7oòòò°gÏž-+ÔÆÈ*99<À£Gô9£ÿÛуP(„µµ5,,,`ff¦?LLLÈÆ;ؼ°°¹¹¹ÉdJ¥ÈÎΆT*…V«EQ …puu…››|}}ë5ŒcEE¾úê+¤¤¤ 22’ì1ob¬\¹åå娳g JJJ0nÜ8h4šœ7nøÈ%üöøõêÕë²™™™Éúõë_yÒŠ+pâÄ ¬_¿žxÂ61ªƒwÌ›7¡¡¡ 6 +))L&ƒL&CAA QTT„¢¢"”””è…š¦iPŠ¢@Ó48x<¸\.¸\.8Žþ000›Í† Àb±ž; ˜L¦þ`0úk?{T—[ýoõEéË©¾î³e1™L}Y5™i i:F¨T*(•J( ( TUU¡²²r¹(//Gii)ÊÊÊPZZ •J¥·‹ÅÒ;ƉÅbØÚÚê†îÔ\¹r3fÌ@PP¾üòKR›(ß~û-„B!Ö­[Ø·o>|HÿòË/+e2Ù·D€ß‰DrÄÁÁ!4** ÖÖÖ/ü]¥R!""•••X»v-™Nl¢`êÔ©ðôôDTT8N“¸oš¦¡R©PYY©§jR©TP«ÕP*•úŸÕjõs¦Õj¡Õjõ‚W-~ÏþûOѯ]Š¢À`0 Õj¡ÑhôeUÿ¬R© Õjõeêt:èt:½0V_çŸß‡¢(}‡ ZÈÙl¶¾ƒÁãñ`hhCCCƒÏçÃÄĦ¦¦033k”ÉäŸE©TbæÌ™ˆ‹‹ÃŠ+Z”‡see%ÒÓÓ‘——‡òò2h4jp8\˜ššé;FM- MÓ;v, €É“'C§ÓáÓO?EZZZFFF†©3Vc`cGGǬ!C†˜L›6í…?æååaèÐ¡èØ±#&L˜@T¬‰›7o"::ºÅäN%Ô/W¯^ÅŒ3бcGL›6­ÙÇÐét¸wï~ÿí îß¿¶®N€­µ¦%Ø4TjŠJ¸È”²‘žÅ€¡‘9:wé àþ077oßS£Ñà³Ï> ðÁàÖ­[Xºt©îþýû}´Zíy"Àoˆ©©é±X¼¾zûÁ³ÄÇÇcÔ¨Q=zt­eà!4=z„ùóçcàÀ˜?> ˜B¨***0cÆ {ö,¾ÿþ{øùùaÉ’%dß72™ «W¯Æå˗ѳgO|ùå—-fKâÓ§‰ˆ\= ÛWÃô™H«:pü…£g™1ÄáCðkÞ~–•ë°íÇRü|¡ ãGháçý¿ÁãÃ`E´36Fýب;8 X¸p!¢££®.((hTûãc+ΰ´´ÔüþûïŸÏÇØ±cQZZŠ5kÖ4Š›S*•¸uënÞ¼‰?þø¦¦¦h×®Ú¶m ooo888Ôê YUU…¤¤$$$$àþýû¸ÿ> àç燀€6ê^h]¡Óép‡Ûi÷ IDATàÀ9r:tÀìÙ³áàà@”¨…qùòeDEE!33}úôÁ¨Q£Z”×|yy9¦O¨%¹ ÿ÷û¼`a$ïw`Æ—fà°ß¾©/)ÕáëEy0âUáË‘:ýhxÓnØ&£0dèˆFm£­[·B*•"%%IIIA.~•ú2ó:uê´øÐ¡CMÓX¶lYƒÞ“V«Å­[·pîÜ9<|ø;wFpp0:wîÜ Îåå刋‹ÃÕ«WqñâEðx<ôèÑÁÁÁMb«@m ñþýûqêÔ)XZZbÊ”) "ÓöÍøyÿñÇøÏþƒ7nÀÜÜèÔ©S‹´Çâ…ÓñaðMôèô¿ÑiüS r›¶®¶·Gí øvï/ÃÙ EXüµLæßSÛCÆ›aëö#àñxÚN°³³Ã;w²‹‹‹%D€_……EEtt´att4Øl6.\Ø`÷RTT„'Nà矆ŸŸÂÂÂйsçF5µEÓ4’’’‹“'OÂÀÀýû÷GŸ>}µ§b]p÷î]lß¾ÀÈ‘#Hĸ‰“ššŠŸþçÏŸGvv6ÌÌÌðþûï#,,¬EG¾»ÿ.Îÿkæ–þO|)lŽ1Àá¶0Púð©Ï p^»“@­Ñ4ýœDüÏÆ?*ÇñŸ 1oªlû‘®å øa£¶UQQF¥RI—––ò(‰¿ˆ£­­mŠ»»;Åáp°`Á‚¹ ©Tн{÷âîÝ»6l†Z'¹kë‚ÇãСCˆE§N0tèP¸¸¸´¨†I£ÑàÌ™38sæ Š‹‹accƒ   ôïß¿Ù_hêáæÍ›¸~ý:îÞ½‹¢¢"p¹\øøø _¿~d?ø3L<+f%ÁÖæ¿íV°p-ǰ…‰àïyâ¬ì\TUUé?Ãd2á`/“ùbÓ_UU…̬Pó™‘9ÌÍLñl$Ç¥ë Áb”!´Ÿ92`Îjw¬ÛÓèíuøðaDFF‚ÉdnÕjµb3x£`##£›*•ªcPPPƒˆoqq1vïÞ;wî`üøñ i²=l…B“'Ob÷îÝ077ÇÈ‘#áçç×"ª'OžàôéÓxøð!*++all¬_Co×®ÜÜÜH´­zD­V#)) Ožïùj_‘`—®_¿Îªå£øvª¸—p5fŠ‚ï¾ô¢šï} “¨ûé(”÷ž Pe}›ƒTEQ$âv$*›¼¾Èùe«!ë~'G³:½r‡éïpq‚ƒYúã–r±VvïÞäädÉd2•‰ _Ö,`©yóæ|ýõ×¥ú¥f³™uëÖ±aÆ Bß¾}Ÿ×–$IìÛ·  “É6lØÞŠHJJâï¿ÿæÜ¹sDEE‘––†B¡ÀÆÆ†Ê•+ãïïÞÞÞT©R…*Uª<µW¶Hƒ^¯Ï!ê IF£1‡`ÜiÈV?R*•y +d+$ÅË‘‘Azz:éé餦¦Z”²Õ£âããIHH !!äädŒF#f³I’°··§R¥JT­Z•ºuëŒF£¡ÃâïçЬÖo´kñ¯u·U†›‹3C8äúl†¡Öî“sü.+y9jX~ŽO U'â[÷'Êê˜L—!m6k8ªççµ±ŒffôG [\.òO’’’èÚµ+@K ìi_OYb™ ºuëj¿þúëRõõ†‡‡óùçŸÂæÍ›±··¦&ª ´mÛ–6mÚpàÀ¾üòK<<<5jÔÖºpvv¦wïÞ¹Dד’’¸pá—/_fÿþý$%%‘ššŠN§C’$‹T`¶µœMpË >¸ùÉ&œlÅ¢l¤ì¿?(+˜×ÏÙÏðAÙ¼$ üÎìãVUʾ–‡IûÁwåáŸþ܃?gßs¶ìb¶ZR¶BR¥J• ¤råÊøøø”y…¤ò„3§0öµÉÔ»Ãì\ëçg­U7HOÚ†sËïTý0§\BN™™z’µ)xøMÌI¾’Ò—‘—P«¦>™%Ç`4ãîzOï¹<°³³3}ûöwîÜÙ.))©‚€³áîî>fôèÑ¥F¾ÙÙ³ýõ_|ñÅ3¯¼#­[·¦eË–lܸ‘Ñ£GÓ¹sg P!4ÿÀälݺu»&‰¢h‘ÌÖÊ}˜°ÔæU«ÕX[[WHfV Èk—ÑnUøs¯À€Þ<*Š¢‘6bÌ F©öº·È4˜Õ¯!ÓÏ%îî]lšbïö¿œeþˆ ùž³s{Žœ4 R‰–æBå#GŽ”………õKJJšñ´¯¥¬¾d¦Si¹Fu:'N$::š 6ü§dïd2/½ôÛ·oÇl63hРΟ?_±ª=áXZ[[ãì쌧§'~~~–¦)Ùÿ|||ðôôÄÍÍ {{û ò­@‘‘˜˜ˆËm"÷„ÉéÝýÑr™ SÊ÷<؉Qe]­>“¨ÂÝïýœÏBÖÁGžó¹–6œ¾ '=CQ®Z+•JêÔ©ã Ô¬ `@.—·nÓ¦ci”‹DFF2bÄ:wîÌìÙ³sÉþW`ccÃÇÌìÙ³™3g‹/.W»Ø T࿊ŒŒ lþMI0A&“cmõøµÓJIzÒ†¿sp ¿I(Tn˜Øé¾‚ǵM® âV¤@T¬¼Ü…³zõêUÉÝÝ}LïuïÞÝ©¤¿çÊ•+Œ7Ž©S§Ò¯_¿Š™ Ô«W7"#FŒ 66¶bP*P2nÁeîýÿÆm¨Xpy@ Û1è#î€Ü [§V9?”ù HÚÇžËÚJ ËñI2œœœÊÕÖªU ++«ŽO›Ëklmmë{{{—è—üóÏ?L™2…… Ò¼yóŠYüÔj5ü1cÇŽe̘1=z´bP*P2 ââïY§1wÁÇ»à9rÁŒ9u1HbÞ0CÁçVøW,wÍnþ͉qR(-ÿÓ¬Ñh^ìÖ­›kI~ǵkט6mK–,©(äž{î9~ùå/^̺uëòÌ”­@*ðô7Ì“ƒñZi §‘m¥Œ%åîªÜR!óçŸ'#SB—!§CÇÞår»wïîèîî>î?MÀ...ïtìØ±Ä±qqqLž<™ùóçP1{ƒÊ•+³víZΜ9ÃüùóE±bP*P2†ºuêqâ,¨Õ–n.ôñ©w× š3rþ2s;ˆºŸãr¸ŒL‡”Ë1ôööÆÖÖ6P?­kxÚìâáááSRµ·YYYLœ8‘>úˆzõêUÌÚÂÆÆ†Å‹c6›™1c†¥nµ¨@ÙÀsÏ÷dã_öx»CøMC¡—$’dzè·…;Ïν™´lݳ\w‘ëÒ¥‹«F£éñŸ$`‡7^zé¥ÓÒûúë¯éС:t¨˜±…„\.ç‹/¾ÀËË‹iÓ¦Up*P†Ð°aCÂ#lÑhàÂå§£+°þ=o \®Ç±cÇŽÖ...ïü' ØÎÎî–-[–Hˆ={öËèÑ£+fëB>üðCªV­ÊŒ3*ÜѨ@š›o Çœ%vØX‰ÄÞ-Ý ò™ YTõoZî»›9::âæææ<µ§Ù jõêÕÝJâjµZ.\ÈêÕ«)½U‚Môl7þ¼yó3fL…¼ßS€ÑhäÖ­[DDDC\\Z­½^(Š( lmmqvvÆÝÝÊ•+ãç燻»{ÅózFѬy vüUJŽGøqu u.µïþp¦‘aïŒy&ÆñÅ_¬tëÖ­×´Zí‚ÿ »ººïÕ«—GIœ{éÒ¥ 0€*UªTÌÒb"áéÓ§3|øpÖ¯_O¯^½*¥€Ðét=z”àà`\\\ |œÙlæôéÓ„……qôèQ"##±³³C­V#“ÉÉd9zOg÷x6™Lˆ¢ˆÙl&##³ÙLPP-[¶$44´Ðýz9uê‚ P½zuªV­ZñPËÞŸ0±£rþr4£9ZdKk7gRÕÿy*UªôLŒaëÖ­•?üðÃà§AÀOkk,T©Råòš5kŠ;€ãÆ ¦L™Â¶mÛÊdcƒÁÀÕ«W¹zõ*—/_æöíÛÄÇÇ“––FVV¢("“ÉP«ÕÅ___‚‚‚ FO­aFFýû÷gðàÁ4iÒ¤bõ{ âââçÎ;´iÓ¦@Ý‚®\¹ÂúõëÙ³gÖÖÖ¨Õjlmm±±±y"KÖd2¡ÓéÈÈÈ -- {{{ºwïÎ /¼P ël-Ù+W®üg%-Ë2’’’;f ¡2Y>·`)5’$!8ΙíügÈÚóÈã®Ý02t¢ Ó?[òLµU}ÿý÷c<Dý¸þ‹/¾¸s„ nÅ}âÉ“'Ó£GºuëV&¬Édâøñãl۶Ç“––†\.Ç`0Xv²ÿ=¬j#Š¢Åš‘Ëå¨T*Ìf3ööö´jÕŠÿýï4hРTÝìQQQ¼þúëÌ;÷™Ù—4~ûí7BCCó%`I’ cÉ’%$$$`oo““S‰l 322HII!99™V­ZñÖ[oñ¨&8¢(rìØ1A $$¤B7¹ {ZƼӱC†¼ZÀª¹'9Ò€¤”G–!EƘè7\bÂG quu}¦ÆïСCÒÌ™3§ÇÇÇ—ªýS!`OOÏe3gÎ|³¸ëro߾ͤI“رcÇS]($IâÔ©S,[¶Œ“'O"ƒ•Je!Ù%ê–”{ð<Ù$ý »Q難Õj$I¢yóæ 4ˆ:uê”ÊýíÝ»—… 2oÞ¼Š¹ˆ|áÂfÍšEjj*NNN•ÃÌV`2 ˆ¢˜kÓ&—ËQ«Õ¨ÕêGZÌ¢(’˜˜HRR­[·fäÈ‘yZÄׯ_çÂ… 888àááAPPPÅ-£0™LŒû:£ÞÌäõ^¶Åzî®:AÆ{ãçPÒ] ŸÌf3ýúõ»|çÎRhx,óóó _µj•_q'‡|óÍ7Ô­[—W_}õ©|777ò]t:f³™L†~~~øúúâææ†µµ52™ “ÉDzz:111ܺu‹;wî Óé,›7[[Û< YEÐjµŒ3†Î;W$m•s"ùfÎÇT¯|Ï&ÚSÔe@’à‡ÕY¬ÞäÀû¾ÄÙ¹ä½L&±±±$%%‘™™iyß=<< .)*>ýôÓ»Û·oo\~f X.—·}õÕW7 >¼XGÔ`0лwovïÞ]ê Gf³™_ý•E‹YH6›HF#¢(bkkK`` ~~~Ej\®×뉊ŠâòåËÄÄÄd) …ÂR&¤V«7n/¼ðB‰-¦ôèу™3gR¹r劕¯¸té'NÄÊÊ 77·<ŸQZZF£GGG:uêDhh(nn…‹ØH’DDD{öìaÿþýdee¡Ñh°²²ÊõÙ¬¬,bbb dêÔ©åJ^®¹±k×öì\Éô÷¡EÈ“5zÚ$“©³¡^Ãÿѧï b÷ve'øë/Ξ:‰!#ƒJrN’$‚érwHE ªŸmºt¥uÛ¶y¾ÃEÅ… ˜2eÊ¢˜˜˜‘Ï,{yymœ7o^âvcìÛ·°°0æÎ[ª÷sêÔ)&L˜@ZZšÅ2Ív-+•J‚ƒƒ©Y³f‰ÔËI’DTT'Nœ >>¹\ŽR©´±‹‹ ³gϦfÍ’ñªìÛ·ï¿ÿžo¾ù¦Âj* ¶mÛÆ¼yóðòòÂÖ6·›0%%³ÙLûöíéÝ»w¾–qaß“S§O°jË÷DÅß@oÆAQ'ÇÜÁøøxŒF#sçÎ}&]ÿ%¤¦¦ò«yš~/šèÞI“ãI42ÆÄ†mÖnðñ ¦ß«Ã‹=Þ«ÕjùmÕ/ìܶ¢‰Æú4jËàQŠŠpG„c GÚtêÄ€!C‹ÕØ’$‰~ýú݈ˆˆ¨Îã´Ë)«®®X±Â·¸Oµ¸õÊ•+Y»v-UªTÉ•`•¬MFkºƒ•ƒœjÞ5y­ç0êÕ­WäÍÑã‡X¹q!.-c †Útq°{¼š¤¬ðrñ˕͚’’BBBß~û-5jÔ(õqÊÌÌäÊ•+¨T*jÖ¬iqÁÛÛÛWä<áxîß·“cGþ"#=wW ŸÊ`g#!J˜$póŽH|"8;{Ò´y'Zµ~®Ø=‰z½žK³wûv:féh-3?Qf3ð7JvjìûáG4mѢخqîܹIkÖ¬ùpì™#`•Jõâ°aÃ~îׯ_±fH’DÏž=Ù±cvvv%~·oßæ­·Þ"%%ÅBjF£¹\ÎóÏ?ÿT-‡ÌÌLöìÙCtt´%¦l6›qsscÙ²eÅž¹|óæM† ÆO?ýT&GI’G«ÕR«V-233¹ví‚ àîŸßS¹®+V°~ýzªT©’k#tçn8µttüÖˆµ ¤EÃ…¥ö¤œqá¥N¯Óá¹Î….ùgþOŸar‡ºÃRQ>à±pv©5ÇçËqsòD©TæZlu:±±±,X°€jÕª•êX}z‰ÞÀæÍ›ùüóÏ,™§Ý»wäÂ.I‰‰‰ÄÅÅ‘˜˜ˆV«%--ŒŒ ²²²,BÙµ¾VVVØÙÙáè舋‹ îîºÚÂ4™Lìܹ“èèhT*•¥låË/¿¤U«VÅ6.·nÝbĈ,[¶¬Ô7 F£‘ððpËåœ:u 777ªT©B||Ùl&%%…öíÛc6›¹zõªå(-OÓ· –sôl4qŠÎ`S½ðËiV4.YÛ©UE`¸¡OesX’E‘YS?!ëØaÞ4¥óà“1›îoW•ÀëjytpØ$ñM¦Dª$ÑK NdÓä¶¼7ë«bi³lÙ²´eË–õ2›Í;JzŒJÍbgg÷êk¯½Ö'00°Øgñ®]» ¤nݺ%vý7nä‹/¾°d8FlllèÓ§Ožn ._¾Ì‘#Gصk·nÝB\]]ñ÷÷§~ýú4mÚ”V­ZѺukZµjEÓ¦M©_¿>Õ«WÇÕÕA¸{÷.gΜaÿþýDFF’••…­­-jõã£'2™Œ5j “ɸ}û¶eݱcøúO(ÞÑёݻwãêꊇ‡G©Nr½^Ï‘#G¸sçîîîØÙÙqöìYlmm9vìAAAdddP­Z5œœœ,Ï­4••Åðá÷’X$}I’ÐjµLž<™úõëgÏÚ·ü¿|zµO2öUîç€8HôNGïz_ïäÐcøzÕÀÙÙ™k×®ñá£14ØG‹Zl=s瘲`Ç WÆ ø’ZAµrý½^½z˜ÍfÎ;‡F£±üÞÊÊŠ””âããK­û™³³3QQQ¨ÕjÉdDFFâïïÏ•+W¸~ý:r¹“É„¿¿?gÏž%55•«W¯âêêšãúK§Ïœã½çp2± :». ry2[FaG¦º!·S=ؽu1öÖ2jT/]wIZ¾³>ùõ±0^3gäPý9e†•xY%c­ŒJרPE&ÐG-PK.ð©^ÂNo™ Ì9tŒ{÷.r(ÌËËK½ÿ~·´´´UÏŒìíí}ô§Ÿ~j’WægQ1eÊXbî¨ðþûï[²œF#®®®¹Ê|DQäúõëœ?žØØX‚‚‚ ¢ZµjE¶º²²²ˆˆˆàòåË\¼xêÖ­K```,“7n°k×.Ëâ$I‹/¶@Q±oß>þïÿþiÓ¦•ÚI’ؾ};®®®DDDФI4 ñññøúú–JN@~X¸p!û÷ïÇÝÝ=—›xذayz!ôz=¦Ägè%ª¶Ïß–|ÎÍw"î„çššOOÄ&Ÿð¾d†o;óæóShÖäÑ +óæÍãäÉ“92´EQäÆÌŸ?ÿ§º°ÇÅÅáêêŠ^¯çàÁƒ4oÞœ?ÿü“jÕª¡R©$‰š5kæh\Sœøí÷?X¾þ$Iöo‚ì• ¢ŒÉ fþkêXƒÒ e¾ö}Úï<ß@Îø±CË}UÁÊ¥KˆXÿ+M’1¿ÀG.0ÛZ–+¦[Xè$x9M$X."‡eV4~ç]º¾ðB‘¯РA·/]ºèŸvkܸñéùóç—HvÒðáÃùúë¯K¤Qü­[·èׯŸ¥#•ÉdÂÙÙ™îÝ»[&‰Édâüùóœ8qš4iB5,î0I’ˆ'::š¸¸8’’’Ðjµ¤§§“••SËS¡P`ccƒ½½=ÎÎθ¹¹áåå…§§§…h%IâæÍ›?~œ7nLÆ [êtóæM ggnoذ¡X³Ìf3íڵ㧟~*Q S’$Nœ8Att4-[¶ÄÅÅ…mÛ¶€iiie•Ço¼AõêÕsAFFõë×gìØ±ùk0øð³±¸õ9Oõ­õjHÕc†ûàG´óF÷ÿ½\ ·áÈ‘#1™L9Þ'­V‹••‹/.3Vll,ׯ_'00S§NáééI`` Z­–K—.Z¬í–EõâÅ‹:tÚ¶mké“™™É¥K—¸rå ·o߯ÕÕ•ªU«âååE¥J•pvv¶¸’œhF£NgqûEGGsûömîܹƒ««+Ô®]Ûò=©©©åŽ|F#oõéÍ{©q¸÷Ir¡æÙÈh¢,Öðæ,‘6ï}€$š‘DÉ,"Šf$QB͘F :ÒÝ8œ®_Á5!.o#I„SÍ|¤‰ ;ýº®È\ Õj2dÈÈÈÈÖ%9^¥’Uagg÷Fhhh‰}WVVV‰X]Ó¦M³o¶0BÏž=‘Éd$''ó×_akkË AƒpqqA’$®^½Ê‰'ˆ¥~ýútèÐÿ'°(•JœœœprrÊaÑg7Ý8þ|xÞ¹\ÎôIsøìëÉ\ÈÒ‘¾W¨ã*UªDóæÍs¹¢X±b_}õU±X°wïÞ%""½^oy.J¥…BaɵP«Õøúúæ›óýüêׯZ­F§ÓqèÐ!Úµk‡J¥*–Ä1­VËœù«Ivúà>ùŠz„¸ (4.h}‡ v/ðù… ¯ž(¼z"fD ÿçÌ’€äört¶Yÿç"B›5¤Fê劀׭ú…f:­…|%`¹¾z€|³/Èd¸úüþ2.^ÀzÍO Ë)QUTÇL5”—/_¦iÓ¦Eº`ý"##í¹WUn-`ßÖ­[ž5kV‰u¥èÞ½;‡.֘υ xë­·,çÔëõtëÖ OOOÎ;ÇñãÇéÖ­AAAˆ¢ÈÙ³g9xð ÞÞÞ´iÓ†5j”¨ )66–ƒrúôiêׯOhh(†[·n±aÃiÖ¬Yž×`6›ùùçŸ- ½(Ь[·®ÈåF£‘¶mÛ²~ýú½w­VËþýû±¶¶¦E‹¹,ß„„V¬XAzz:/¼ðÍš5£råÊ( K—²l5ªl ݸ¸8>Ì®]»°²²¢wïÞOïÜ´i«V­Ê± ’$‰ŒŒ –/_^¨±‘$‰Ù fRm7 ÞI/¸ üœŒ Ó™ûùOdêt:†š£mª$I\¹r…ßÿ'ÍåHLLdÆ „‡‡ãççGPPeól4Ñëõ˜Ífˆ7%%…Ë—/c0hÖ¬Ï?ÿü#7H'OžÄ××·X»7Mš2‹½‘mî•dÅ ‹[‹UYÈœ O</U={mãÂ:ï °!í&f}ÒýX®Fã\ÓÝÝè/èùÚ½X±)•@i1ËUn\уA/÷dzfÙoÜNÔUÈ¥Éyz ¶K2z~»¨p·«—¾ÿ6×ï#Ex%ÍŒ¿B†×ØèÑ£G‘ïgëÖ­† ŒJIIYZn-`77·¡/½ôR‰¦ÆªTª\1«¢îÎ'MšdqoF|||¨T©Û·oÇl63räH¬¬¬¸ví;vì zõêŒ=ºD›•?zõêE·nÝØ¿?ß}÷Íš5£iÓ¦Œ5ŠÍ›7³~ýz^xá…\Öƒ\.§K—.lÚ´ ¹\ŽÙlæÃ?´ò“B©TâããÃíÛ·‹-Ã:¿ÝiëÖ­ól Æ–-[òu•f—z=|œ»»;õêÕãí·ß&""‚Y³fa2™6lX¡³jÿüóÏ\NG= ½˜ ‚ÀøQ“™·DÅ©yÒpôãI85 N|T™¹3<±ûÕÖÖ___,óJ8tè;v,ôœúý÷ß9{ö,|ðA¡kæõz=[·neêÔ©„„„ðÒK/å¹ánÔ¨Q±¾kqqq\O§É7ó6òÄ­X7û AåŒL€Ýñr½?Î7ï$±éD&‚<çFÁ¬O¤C0×¾_‡Ÿ–)ðó*µÇÚ.Œã=úƒÊèT?ŽŸ8I“Æå‚€÷íÙCì ù&J! |¯ÉCé „<Â^Û7Ãå@&ge‡ªs7œ|î¯%B@¸¸Ab|ŽÃ*Ëî•#©$‘¬ŒŒb¹Ÿçž{NµråÊ!%IÀ%ÞºH­V¿R¢[8kkkÒÓÓ‹í|aaa$$$XÜWf³™æÍ›³nÝ:ÜÝÝyíµ×, 'Oždøðáôïß¿ÔÈ÷Ah4:vìÈäÉ“Ñëõ,^¼˜øøx^~ùe‚ƒƒY³f ©©©yº=<<,ŠMááá\¾\t ðÏ?ÿ”ø};::æ"¹Ã‡sèÐ!~ûí·"Å)}}}Y´hýû÷gòäɤ¤¤øXQ¹víZ. Ñl6çë*/ ¿3ä}Ž.mÄã?îG !uÚ9¼{÷îdff><Ÿ +4ùΟ?GGGÖ­[G“&M ½Ñh4ôêÕ‹Í›7SµjU&OžLZZZ‰¿g«ÝD‚òßçfLFvw=ÖM×"¨îÍuQ‚¿Ï[!—ÉѨ•hÔJjVw§ŽG ¶–D>öwhÖÐÏò9µJÉ®3 Œÿ&»Ë¬*cÓd²è•`Î$ͺ+Wo¦¼`ׯ „šîç+üa„¯l„<ݬÙ.è\H¸ w" ⪋ç8µ:£ ïF\ YPSšµµ5žžžÞ@‰u¡)i®U¯^=§’nQèììLBBB±oöìÙAƒÁ@5ؼy3Í›7§}ûö\¿~åË—Ó¬Y3FŽYª]‚·@ 8-[¶pðàA7nL—.]X¿~=Z­6×1mÛ¶µ41™LÅÛ âÆ¥~ÿ)))üþûï|ÿý÷Åæ iÛ¶-_~ù%_|ñ…å}x"""°±±ÉE0J¥ò‰C$IböÂé´jÆ±Ž…ÐÉzΧle×Þ?‹tÿÁÁÁ¹î󮮠‹/ê<›7o& €wÞ)zf¯  0€iÓ¦ñé§Ÿæª"(n9~lkBÌJ¬-EPæ|ŽIi»N›sü®SK_ì„;÷=/™éÙ!§(ÊÑË·ãº?'Võf!Äþ(ˆŠ»§ŠUÖ‘éõïRŸ&ºù¤0K€L.ËëD÷6¬Ü0Ky%‡¦ëò<§— îªÔxcþ_|ÑÝÅÅårIÀîîî#{öìé^ÒßÍÍÍ"ÍWTܾ}›¸¸8KV°Ùl&22’víÚQ¿~}<È;v, 6,Òweee±}ûv¶nÝjéËZTT®\™>ø€ÌÌLÖ¬YƒŸŸ={ödÆ èJ^°³³ÃÙÙÙ¢ÜtñâÅ<‰º0ðóóãÎ;¥¾¬[·ŽI“&¨AIaP§N^xá¶mÛV Ïß¹s'×Àl6I‚réÏ H­¶šý – -Ƞݼd~;ü {ìzâïµ²²Ê•ĤV«ILLD’ &£Óé {dÙÕ“ ~ýúŒ=šåË——Ø;•™™I¦Qz¥Ksd¶y‹Sœ¿­äêûÞ¥BNV`JÁ”M·–•°±¾ÿnÆ%›9x1or’;7G¡q…ŒdÊ}¹~ýz™'ุ8\e÷­Ýf¨É³•ŸîåËñ z ¬ƒÔ4”oæü@l4DEære± ˆ„††Ê­­­_/©q+I4MÇÚµk—øÃ÷ññ)6«ë×_Å`0X¬BAhÑ¢µk×fëÖ­hµZÆŽ[,Ñ›7o¦Aƒ´lÙ’õë×Ûx( ^yå4hÀO?ý„‡‡]»veãÆ¹vÓ!!!9¬à-[¶黳[–&$IâÚµkO¬ÈtíÚ5Ëä…²ÿþ+111—•—]îõ$ømÓj®°‰ïè 7±Ð~Q2¿üŠ]{žÜÎË› T* ¼aܽ{7o¾ùæ#$õú'+³êÔ©±±±… QQQ÷ÒW„¤Ý¨Æ?â„¿N[¡Ë¼?¿¼ÝhæŸLÏ$jV¿Ÿc2Kl9&Çü§Š:h2BÒNtfOnß.ý maq÷î]\¤ûsè’:* OÀÕ;t"dèšEã×ÞÀÎýô¡;ðãw÷;¯ç%‚Q¥.Ö>*• ÿJ€Oy#àÆM›6u, ¾jÕªqéÒ¥b9ןþiYt uêÔ¡aÆlܸ{{{ Pl=q]]]9wîçÎ+‘øqhh(]»veåÊ•øøøÐ¨Q#vìÈÙÞ´J•*7£L&cÆ EúNgggKÿàÒBbb"UªT)´{óÈ‘# 0€Æä¢T*ñòò*Ð}åE&¢(>Q™Ü®½²çÖO´øäɪ dJhÿ]2Î|æí¿=Ù9òX$ E®Øp~8}úôcËÒjÔ¨ÁäÉ“‰/ôõ½üòË9r¤DÞ+N‡ 0¥"SÚ#(íÅÈÈ‚mÇs¾ƒ­C|éò\N×óžsø˜G*³ñC0ë0 V$iS)ëÈÊÊBñ@¸Â€€Ã#õ}óq/?©ú,$uþá¥kfhסC±ßÛ‹/¾èîææ6¤\°§§çè=z¸–ÆÃ¯]»6gÏž-òyRSSIOO·´›´±±¡sçÎüõ×_8::Ò³gÏb- hÛ¶-þþþxxxÐ¥K—›ºuëÒ­[7V¯^MHH2™,G’” ¸¸¸`2™ËåDGG?Ò|²ËšJ±±±–E‘-[¶XÜòï¿ÿ>;v|l#’5jýD„•í]( Žž8ÌÚßÒvŽö‘Å‚‘å\^«ÊW>\¦€vs“Ù»˜~YX`×ñã<mÜb0[²Ô¬Y3Z´hÁÈ‘#ùè£ EÄ 4àæÍ›%ã”É!ý ׂ‰—ÜŒSpòŠ>ÇüR*îÕõ3§¯l ‘;CV,Ч [XXh42„ûïþãîð^tsåü8´ñÈAÒO Kw?ÑξFÒ¨ñàš»s_’É29Ýûô-~K²qcA£Ñô*O,·²² --QGGGŒFc‘ã—çÏŸ·ô6 ¼öÚkœ9s†ôôt^~ùåb¯ÇJ´Ö¯^½z4oÞœ7Ò³gOŽ;–#kÜÏÏÏB2™Œððð"/Ð¥½û~\©^¯gÙ²etïÞþù‡Ù³góî»ï8.»Úã—¥«T* E*/ýÃâõÓiÿ}2Eþ+Ø™E6D/ Áþä‹üù†+)·óyÏd:=…;î¿1í« –KAWÁ`(°E_LI’hذ!óæÍ£E‹Œ1¢ÀDìèè˜+·¡¸àää„RÒ"“Ù\Gzï?*â“rWedèMüyBNA§‡Ì¶ S î•ʾJ’§§'±Ò}ñûÌóy7öï†ßþÙÚ_°ùåÎOLÚÝû°d+x.·Gåç, çê¹ú® ™ÉåÔ©SÇ(,—ËÛ´mÛÖ©4_€&MšpàÀ"ãÒ¥KèõzKÑ¿Á`àøñã 8°Ü7GoÕª¶¶¶üóÏ?´oß>ÇXUªTÉ2 ×®]+òÆ¢4áààïbœœÌ—_~IïÞ½1|ÿý÷ 8°Ð.áèèè… ÜÝÝsy²;ŽÌZ:ç—& È'ŸÌ˜»†;QCû*3§Ìå·Ç3eðbN«Åéù6ˆùì꽎CŸ0F4¨@ä&Šb.—zvm|A3Í »kÔ¨óçϧE‹ >œ?üð‘9iii%Ö‚ÔËË …ù.`¡àa'cÊUdyL Sft!æ‘ ñ”–!S¸ºº¢•$²sÒH·€ó²ì¥œÞ7!+“˜sy7«æÜ ™€ï “þ•Š- ôìÙ³’‡‡ÇÈrAÀ•*UÓ¥KÇÒ|²[1áááÈd2DQ¤eË–lÚ´‰[YËÓFß¾}9qâ>>>hµZKé–ƒƒƒ…4DQ,’l6›K€}}}ó,ÙµkU«VÅÞÞž%K–УG'Žß_½zoïÇk‰øùùå™ ”‘‘ñX×~bb"S¾Mû¥wQÛçýmlÅAí§3à•·,c]¥JæÏ\N3ùhþèåNìé¼§¶ÏsFB¾¾Ê³sþ¹G^Ï­[·r¹šõz}ÆáÁÍØ£’¬²Cyñ‚  eĈŒ1"O">þ<>>%’ƒ\.ÇÙA$h² ¶2ëißPƒ‹Sî ž•FI·¦*$SÁØD}4y:^^^e~m&MšpÒtŸ`3ÁÁb~uñþAĈš‡Ë÷šÃßdJÔ~®}‰X¿Ù¨S§jµº ÅÜ=²$Xekk[¿0“´8РAΞ=[¤ržøøxDQ¤mÛ¶œ8q‚Úµk—‹—¿ P*•ôéÓ‡íÛ·Ó¾}{Ž;Ü+8϶Td2±±±Oü)))Å.ŠQûÒh4DDäìRñüóϳk×.víÚÅÂ… ŸØUùÏ?ÿäð<ÎÈ&–M&ãÌ™3´6§ÌzÐ91Øä㿹CÅÑ1Õ™5q)!šä¹vëÜ“o§üLìw¡˜èˆ![vô…Ž?Ç2ýö‡íÉ÷švìØ‘kâÓéhРAÇ®~ýúìܹ3ß¿ëtºGz#Ôj5ööö„……qëÖ­\ß¼ys‘ûþ> Ý:·A!¥`J||¢—$ñ±¿CHýªxÀhºïñ÷u¥¾w,ðxÏ€9éÔ)7Þ·žý_åOµ ƒ]ÆüïQò¶€/ª¬9nmÇ!µ 율ҮU…äüPÜýõéº~RÚòÞ”OJ|ƒÑ¸qc' ~qž·Ø X.—wêÔ©S©-är9­Zµ*p½f^ÈÈÈ@EêÔ©ÃÉ“'éܹ3ÏjÔ¨J¥B¥R‘˜˜Hzz:r¹ÜBÀ‚ iýTäû÷ïÏG}”ËåºuëhÛ¶-ï½÷+V¬ÈÕ¼áQ œ(Š|òÉ'ôëׯÀ×Ò´iÓ\¥1†µkóW6[²r>^½oâ·Wîèçöè7µaÁÌŸòÚ°¬£#Ó'ÎáÕF3øë•Ê\ÿ#w;J• tø!‘Õf±ÿàîÜß)I„……å"GƒÁ@ëÖˆéܹ3‹/Î7~ž–––ë;Ìf3Û·ogĈüý÷ß|òÉ'œ={–&Mrn:.]º„Á`(ÑF8ݺtÀUöbÚ% È¼œ«ÙÆáK;Oå<®C‹ª8Èn?šÌMiÈ ‘¼=¸¹Y[‚‚‚pö¯ÎQQ ¹èAÀRÞeHµ†"dÆW´øb>ý‚ú½úäþ\Ø^R%xI/gú²å”t³'€=z¸x{{.ÓìááñN§NlŸÆ ðâ‹/©Ÿqjj*5kÖäÔ©S´jÕê™q=?ŒîÝ»³ÿ~6lÈÅ‹sÅ,‹RfuëÖ-*W®\ê÷TµjUjժŴiÓr‘° <ÿüólܸ‘êÕ«3bÄ6lØðX—°$ILœ8‘ÐÐÐÇ’ÞƒèÒ¥K®2•JEdddž±×K—/röîv‚úævÕf$Âö®´tÁäqŸê iÔ„%³×`Ö“¿Þt!í¡ð£L í&±rçWüséBÎ5.,,×8šL&ôz=õêÕ+ð5ØÚÚÒ¡C¦Nš/ggIkµZ–.]ʰaÃ0™LüüóÏ|ñÅyöOKKcüøñ :´Dß+µZM¯îí©0F®Ë÷s¦Œ(ºµrËÑl#&ÑÌ¡‹n«¸¡`~ÉèÙÆ Á”ý²áæ÷Us}âúñ§…÷?ù„5*;½R£=ùXÁù¶¢|L&Øð+\¾ˆN‚Î2FÌù¦Ô¼”Õ«WG­V·)NÞ,n¶vtt ,N%’ÂÀÇÇ;;;Nœ8ñDÇët:6lÈÙ³giÙ²%Ï*<==‘Ëåx{{síÚ5233-;HQ‹ÔCøÒ¥K. *‰ ˜  ><Ï>Á2™Œ—_~™7¢R©xûí·ùûï¿óLJIIaðàÁ¸¸¸Z^±Q£F˜Íæ\–¶F£aîܹ¹Híë¥Si93)×yîì—³{`&½1îÿ{鉯D¥R1ê­ñ|øúwÄ™ï­sä¹È”ðÜ¢D¾Zü‘eÌDQdéÒ¥¹ÞƒäädºuëVhk£C‡˜Íf&Mš”ËÖétDEE1uêT>ýôSš5kƦM›2dH¾®éèèh^}õU Di¬5ýú¾ˆ¿k:Yáß"™rg7‹æLêz%ä“f4Il=.Ç,ݳövœÑ–~?£ÜÝÕžÐÀ$1÷&PÊŠGºó#_ùI¹[[ÜÝÝyê4¾”ÛÒEcÓEâóH‰vZˆÌW.a¿‚ùú5Ì7Ã1GÜÀ|ûæÈÛˆQ‘H7¯Ãé°é7˜1ì!Z„vYJ|õ5õ‹Ø°0–-[:ÍË$k4šž]»v}ª‘_ýuæÍ›Wèã²ÅÒ þþþϬõ›–-[rýúuDQ$!!!E–ðôéÓOU°½wïÞ´mÛ–¾}ûòÝwßå÷U*• <˜uëÖÇÁƒsxAæÏŸÏ«¯¾J×®]yá… ?©d2^ýu’’’rð­[·rÄ‚×nü™jbÐ<²(‰püK;’iÅ¢™¿P½zÑ5a«V­Ê‚™+hlÅ}+ÿ@ßµ4žÇ·‹ïe‘f·w|hEQ$99™W^yå‰ç¥··7/½ôRŽÆ&“‰ÄÄDÞ{ï=V¯^M‡ò%xƒÁÀ?þÈ!C9r$5kÖ,•wJ&“1{æ$œ¬2É<=Œñ[IÂÆx‰ÿµÍÝl#é=`¦þ8‘ó¾Búàe}ë!ö5£?þ ã‰%Ÿ6š6kÆÈ§0OmOk¼fÎEÂr4q1ÈÏE¾èä ç Ÿ?ùÜ/‘;ùן#›3aþWðó°o¤jÙdè"wdÜÒe7.}•¨nݺ9zyy½[\ç+Öè¾··÷åË—·,ª KQ1fÌÆÿØGâÚµk¼ûî»ØÛÛÓ¼ys‚‚‚ži6Ìš5‹Ê•+c4 G£Ñ Š"3gΤmÛ¶…>§^¯§M›6lذ¡ÀJ ¢(²wï^víÚ…­­- 4ÀÖÖ¥R‰J¥B.—[DßM& ;v ƒÁ@‡hÞ¼y‘âJF£‘^½zQ©R¥úµ¢(’ššÊ¢E‹°··gÈ„—ùߺHËL4éa÷('ž z¾/•L Ú¤¤$f-øYË4›f©5þ£O%Æöÿœ™3gæê]}÷î]š5kVäžÎZ­–5kÖpçκvíÊsÏ=‡³³3*• …BR©Ì“ÏÊÊâôéÓlݺ•“'OÒ¾}{:wî\*1¿‡qãÆ †¿7 ½]4õ¾S¯¶Wà]éþ3¾mfý¡¼ë}ÛÕÉ¢IÍûnê´t#?îÈ2©î‘ï‰Wéû¼3#†(÷kÌ7˜>qžIñ$볘g#£•òÉ(çŠF84oÉð?z¤&tIcÀ€·®]»Vƒ{Pe†€4hp~Ñ¢EUžöƒ¿rå ß|ó ëׯ/ðDÝ´iÛ¶mãâÅ‹|øá‡ÅÖn²,cîܹøùùqòäI‹,!Àï¿ÿ^¨˜g68ÀÊ•+™1cF™ºÏ´´4ÂÃÃ1 ˜L&L&“%þ+I’$áèèHíÚµ‹ub‡……1kÖ,|}}s‘Š\.gÆŒLùñ ž_r¯,#v uexŸÉ4kÒ¢ÄÇåÏ][Y·o—Ý«9>2Í‘››ìqssË1oôz=111üúë¯ÅVs›••ÅÑ£G9sæ ˜L&ŒFc.µ Ô¨Qƒ¦M›øÔ3‚##£x{̧¤ÊëaÝp j•*¸ŒO}>½Nrð|¨œ\«ƒÔT-Y'^a`š¼ùFßgf1›Ílþýw~]¹Û´ü%3Y „(„Ç’Øa˜'©ýª3hâ¤2Q½bÅŠ´¥K—ö6›Íõ\ÅÆ2ööö¯tïÞ½RYxèøúúòÛo¿Ñ§OŸ[Àöööh4šÿùøûûc4ÉÌÌÌAÖu•––†R©|*5¬O ...–ÚçìÝê“&Ùlݺ•fÍšQ–Þ²²XÏ;—!C† P(rdöÚÛÛCj5~jsà†ž¥N¾’$±fÍ®œ½E@Õº¹âöqqqøøø0jÔþ^± IDAT¨Š™‚ë×cÓÚE\¾|…9óçsýà Ì w§æÈ#h¼v€„dJEʸƒ˜|I{k…޾]›ðÆ·sþ3·¡Ñh !$$¤\^çÎ]oݺÕ-33³H:²ÅPqppxw„ _¶k׮̽IÓ¦M£eË–ôïÿè‚ö¢P(ðööÎ×Afff™ˆE’’’øå—_ˆˆˆÀÆÆ™LÆþýû @%IݺucÒ¤IÅ*†ý,!<<œ1cÆàîîžkgŸ-$À¸qãr%@•nÞ¼ÉÌ™3ÑëõyZqqq8991oÞ¼g¾" 8þ}û8{þÑñ:ôz#2¹ G;kjTs£Y“F4mÚ´T“ QQQ–Æ;’$¡V«qvvÆÛÛ»Üf[?MhµZ† ²'22ò¹§nÛØØômÞ¼y™ÜÆ?žáÇS¯^½G–Ç(•JŒFc¾»Ñ#GŽÜvq±¨ •uèõzAÈåV´<ü~²åûõë÷D Ãßÿ««kù>Õ«WgþüùŒ3“É„££cŽwÏÍÍØØXFE£F4hPŽÏ"""øî»ï¸sç¶¶¶¹_I’ˆ‰‰¡råÊ|ùå—ä[HxzzòÊ+¯ð„ޤbÑhäÈ‘#ì>¸‹ÓgN“–š†U% G 4"È$“ 1M†!AD.)©]§6Ût&´Eèc•Å*p¯ÛœMuî•ò>±þjq°kY}h666L:•wß}—Õ«Wçëæstt$666ßîH‰‰‰Ô«WOOOV­ZUæ_'NpöìYDQ¤yóæyn>²…d2 …‚!C ¯9m6›™3g“&Mª˜•AµjÕX¶lcÇŽ%66ww÷žµZZ­æüùóŒ1zõêEHHˆ%CýI Ó騳g[·nE§Óaee•'¹geeEûöí3fÌS)õ©@Ѭb÷ÞÝhüA¨¥Ãêm°sÈ_C2@øƒ\ùû³çËiÛºƒ_ÂÓj¨T^¨¾råJ àÊÓ$`Oooï2ø«V­o¿ý6o¿ý6«V­Ê3NéååETTT¾ û;vìÈ®]»8uê½zõ*ó/Ç™3gx÷Ýw-:¸y°N§C¡P }ûö½“,$V­ZE`` 3²pssã§Ÿ~âÛo¿eïÞ½xxxäêødmmµµ5:ŽE‹!Š"LÕªUs• eÃ`0Ë78qâ/^D¯×#—˱µµÍ“x%I"11­VËĉË]fò©©©Ì_<‡÷¡i›ë‡"²B¤Ã *°‚2°íGŽmeß°=¼Ô­7_{ó?£.4hà²cÇŽ&z½þ‰ ¸8™]Ç·®W¯^e>ûfݺuœgªP6-MùÊK&0&€)Äa™Ž tË-w,@÷‡v1ž|3sn…5œ"""?~üÏ‘‘‘OÜ5¥È[ww÷çjÖ¬Y.R_{÷îMJJ cÇŽeÞ¼y9âuêÔ!###—ŠMy…——×c]ÊÙÿðáà M¾¢(òÁ0tèÐ ò}B³víZ~ÿýw–/_Ž NNNy’¦L&+¶dI’ÐjµhµZ\\\˜9s&uëÖ­x å’$ñÝ‹øãÀFì‡ëP8çþŒ!tg óê=ÒÕø‚Úä ÈÀœ™W@‚¬Á¦!(]îYÅv=3É8{“Á#ÞdÑ7ßÿ§J4 ‚*Uª B‘&N‘ X¡P4õ÷÷/7ƒ6xð`/^Ì;ï¼Ã¼yó,Ö‚¯¯/©©©˜ÍfDQüOÄ¿nܸAjjê•-Z´ggg:tèP1³QIII±´ÁÌcþЧOzôèÁ–-[Xµjf³‹û}éé餦¦’’’BPPãÆ#88¸@‹½$I1á2D¾ŸÏþŒ£Q{p•‘Óz• ã2hwƒÜ\{‚Ï$P>Æ€5§BÊ~ˆ_wOþÒ©#¨¼Àº¾D†:‘ïgÅÒŸK]ë»,C&“accãÈ=O²ôDç(êEh4·ò”5'o¿ý6ÞÞÞ <Ø¢}+ 4ÀÙÙ™7n<ó/Ovÿc__ßG ¢ç…Ý»w³mÛ6ÆW1 ƒãÇÅ–-[)¨V«éÕ«¿ÿþ;Ÿ}öuêÔáæÍ›\¿~èèh’’’Ðëõy*7å¹ šÍèt:îÞ½KTT/^$==®]»òË/¿0oÞ¼‘¯Ùlf×®]œ={¶âa–|·t!G£÷àðzNò5&BìÒÿgïÌâ,÷ÿÿš…aßWE!\qßw³RsKí”Y–i_³RÏÓÊ\ÊË¿ÿýo.]ºT/h3nܸ­­-cÆŒ©Õu111|øá‡¬[·ÎT®Pôèуøøø»øE"!!!„„„`4IJJâòåËDFFO~~>˜›› t÷ZÛåÒ¢pWé¬sçÎtéÒ…®]»âääTkK+<<ÜT'ÚˆpöÜYöŸÝ‡ãe2xW¡øø|6U¨®êKÀð}j±HªØ{[µ‡Àͳù.¡»O›¾:’¾Œåì¹³ôíÓ×ôEü‰Ž;:;v¬£^¯O{bÝToüøñ¸¹¹1eÊ>ûì3úõëÇûï¿Oaa!:®Ygÿ9s†âââZp||}ú4ËI“ŸŸOaa!ýû÷¯qL'&&†9sæðþûï׫à†V«%--´´4ÒÓÓÉËË£   ‚»öÞØcy<òÞ¿ÍÍÍquuÅÍÍ ///¼¼¼hÑ¢E£ˆY:99qåÊ|}}qs{ø^%b±WW×G"[éááÁ¨Q£ÈÏÏG©TšÈ÷1có›v-«pUº|hûõÝDªª ËƒŽ>]?°ruÇþ”m\SŸ¯~ÚbÈû Üÿy¥ù¤¤¤ÐºukÓÂÝW‰DÒ½®×?ÛØØôm®ZþóŸÿ°råJÄb1%%%=z”=z4K+ø·ß~C«ÕÖXã÷ܹs¼ûî»,_¾ü¡\óF£‘””¢££¹~ý:r¹™L†ŸŸmÚ´aðàÁ´hÑ77·Z{YY™ë¼}û6û÷ï'55ƒÁ€»»;!!!tèÐá±”R¸»»7yo©åñC«Õ²ï×}8ÿëÖª:õ®ë9pKõä  Ê„Ð=«<ÖÁ®'×òÎßÿû ÅÇ¡,dAÂÃÃMü'¬¬¬077¯óÎú¡ØE"‘´yÔò V¬XÁ¯¿þJtt4ŽŽŽ;vŒáÇ7« “’’BZZC† ÁÛÛû„ùÃ?ðã?²víÚ:µ+++ãÂ… „‡‡#—Ë…Þ®Ï=÷\½•/YYYáããƒO¯…Ñh$##ƒ‹/²uëVrrrðôô¤gÏžtêÔé‘êñšP7(•J²²²ÈÊÊ¢°°¢¢"JJJP(( ´Z-z½½^D"A*•"“ɰ¶¶„Gqqq¡eË–¸»»7ÉMuDDæ~FÄV¨õ¿Ú}s·d¨:Tàdt§µGÕ-.½}q.v§@›sß÷÷þÄÏ»¾Zn$Ä“L“óOØÚÚZSÇÎH3EVVV¶Í¡)ð@"£G¦S§NÌœ9“sçÎѹsgšË&C§Ó±mÛ6t: ,¸ï¹ …‚°°0 ëׯ¯U¦´F£áìÙ³Bc‡¡C‡²téÒZ'ÕÇ÷ÙªU+Zµj%hw'''sðàAöìÙ#”Q…„„МæqS„Ñh$--›7oOJJ :KKK¼¼¼ðôôÄÍÍÀÀ@°µµÅÚÚ™L†T*E,£×ëÑét¨T*¡äª¨¨ˆüü|’““9sæ ™™™hµZ,--ñóó# €   FoåŸ ? mÿ§ÒWN#ï– Ý÷·˜ }Ú÷ªðš\UŠ…­ð÷f=9©ÝwßûÈZ‚¹7èË °¸Ð4aïA@@€å•+W€èGIÀž^^^ÍR©ÝÛÛ›5kÖ°páB6nÜÈ;ï¼Ó,\ÑûöíC£Ñðá‡ÞWv2<<œÅ‹3vìXÆ_crJMMeïÞ½äææ2räH>ýôÓF—Aëãã#È’fdd°g϶nÝJçÎ5jTä8M¨ᦧ§Ε+WP(øúúÂäÉ“ñóó«µ8ŒT*ÅÜÜkkë¶U(ÄÅÅqíÚ5¾ùærssquu%44”îÝ»7:q™ø¤Ẋ–”^€öÛ4È Í–Ðu@Å–û~àùYÂß!.Ý9ö£þ¾·s¿€ØÌT~/‚‚‚,,,:«TªGJÀÁAAAÍV·®}ûöLš4‰ýû÷³cǦNÚ¤­¤¨¨(®_¿Nÿþý:th•çñÉ'ŸpóæMV¬XQã8ÏÕ«WÙ³g-Z´àÕW_¥©³xzz2gÎ gÏžå‹/¾ÀÚÚšçž{®NîvLº×¯_çäÉ“$$$àããÀ˜2eÊ#ßøX[[Ó¥Kºté"¼–ÍÙ³gùòË/)**¢sçÎ 8//¯Ç>vÅE%˜ýé„Rg‚…ïÝÚÝûA[îAØXþÏÚÍT¥*¹IZn ^nwß6¶øÉ‚HT_»ÿ˜=9›À=ØÃ4™ïA›6m$ÎÎÎ}322¾dìââÒ£mÛ¶VÍy`§NJll,III–H$ ² ‹Åôë×~ýú‘””Ä7ß|ƒV«å…^0•[Õ2339pà111tîÜ™ &о}ûF·¡õðð`üøñŒ?NGDD»ví"==Þ½{3bÄˆÇæÑKÄ”¨ªD°ë÷àk4™Ú¥bòÕõ;I!:ó¢@ÀOXö| KÀ ØÁ4©ï··7b±¸N’”u&` ‹n¾¾¾Íz`E"ï½÷sçÎ%22‰DÒ䤓’’زe ÖÖÖlÚ´©‚+]­V³{÷n6lØ@Ÿ>}øïÿ‹­­íï™––ÆÆñ÷÷çóÏ?¯Ñ5UA¯×“œœLbb"III¤¤¤““C~~>ƒA(9*o™ø×$‘H„££#x{{ãëë‹¿¿?mÛ¶­³„c›6mXµj·oßfݺuØØØðâ‹/ÖZ-ÌdíÞñøõ×_±··ç¹çžãŸÿüg“ñ"I¥Rz÷îMïÞ½Ñh4?~œ>ú;;;&L˜ðȽ<.Î.äg‚û]Å+‹,½˜Ëíl|Ïwbàféeâ4—yÒ8±èîF»k0Ör;º;÷¿¯FD÷îÝMü˜™™!“É골3‹Åbᅢ¿™™Ÿ~ú)o¿ý6ÈårÆŽ[/ ‰ÑhäâÅ‹ЧOŸzwÃEGG³k×.¬¬¬Ø±c‡pÿ¼¼<~üñG~þùgúöí˺uëj”„¢V«Ù¼y3¥¥¥|ðÁxxÔÎU\\,dD_½zµZ——>>>´jÕŠ‘#Gâêꊓ“S,ðrå¼¼<²²²HHHàÈ‘#$''c4 ¦{÷îôêÕ«Ö.e___Ö®]ËåË—Y±bƒ bèС¦d­|'GŽá?þ W¯^¬ZµªÉëËd2FŒÁˆ#HNNfãÆdgg3yòd:tx4Ö`Hûüžƒe€ƒªjÁ ^­lmÛM X€[ŠXªÒ»V´e) éqxµ¿»ž‹Ä™…rQw¬ú{怕¥e½Ô³77ØÚÚZQ‡L躮&¢ÀÀÀ¤7úþ]X­Vóî»ï’‘‘½½=Ó§O`«·!<<µZM‡رc3gά7ëãÀDDDàääÄ–-[°´´äĉìܹ“äädFÍÓO?]c—ÚÕ«WÙ¶m³gϦgÏž5þ 8p€S§N!•JéÒ¥ :t }ûö=~÷]€´Zâã㉎Ž&**Š¢¢"zöìɨQ£èÔ©S­D: [¶láܹsÌš5Ë´Uó]?~œ_ý•‘#G2a„Z'Q5%òí·ß’˜˜È´iÓ lÐ÷»ví W¿ƒÓ[ròvB‹WÀö>†¨<\Äܧáêø¿ʾS;¹š%üݱmWÆôû_oó¼Ò¾ËZ‰±š¾y?AÇ+ϰpþ"Ó„ÿ Ö¬Y“·sçÎÁ@Ì£ `×þýû_^µjÕߪ?•Á`૯¾âرcFžþyÚµk÷PêíÛ· âÌ™3LŸ>ý¡?cAA›6mB.—Ì Aƒ8uêÑÑÑtïÞ‘#GÒ¡C‡[rZ­–M›6!‹Y°`AôŸ³²²Ø³gÄÓÓ“þýûÓ³gÏ%Üš<ÇåË—9yò$7oÞ¤_¿~Lœ8±VÂ"™™™¼ÿþû 8Aƒ™V?qóæM6nÜHïÞ½yá…š5ñþùùù|ùå—”––òÚk¯5X9“ÑhdüÔg‘NÎA6]ÀubÕçêKÁ1Å—ÙãÞ®õûlN^C¦&¹Êc /HùooÁÇÇÇ4éÿ‚ß~ûM÷ÑG=o0~zÜ÷ÕW_ýõå—_þ[vï>{ö,ü12™ ___ž}öÙ:ÇA((( sçÎ%õ§Óé8vì'OžD¥Raee…££#Ý»w§GužÈËËã³Ï>cúôéôïßÿ ÄùóçÙ¸q# …‚'Ÿ|’~ýú5ʆ z½žˆˆ~ÿýwär9ÿøÇ?1bDÆÇ`0ðÿþßÿ#55•Ù³g×k»À¦†²²2¾ùæŒF#óçÏo°$¼¦€„„V¯^M×®]7n\ƒÈ ?~œoYåHÊ8h³¶šï%žn3…îA½jý‘Yç8\Z¹¾IeóZ³å«í˜P7nÜ`ñâÅk³²²Þip¶±±™µdÉ’õýû÷ÿÛÄŠŠŠX½z57oÞD§ÓѳgO† ‚•Õ£M 7 DDDpàÀŒF#2™Œ^xAƒÕySwµŸ·oßΊ+î?5 üñÇlذ6mÚ0qâÄFQ¶QÁÏ?ÿLxx8“'OfÒ¤I5"Õ .ðõ×_3oÞ¼G.0Òpùòe¶lÙœ9s 5­ÀnBwíÚÅÁƒ™;w.-[¶¬÷û¿õÏ7Iõ¸JQ„–à½Ut32€â¼Œ%ÿXÌìz•A‰Ñh¨L1fÿóL©µj¾Ly·Rƒ†Ìw¬Y0|=º÷0}ÑU@.—3}úôãéé郜€===7}úé§ÓLz Éš5kP«Õ¨T*:vìÈ€j T[”––rþüyN:…™™ƒ7ß|“>t¢ÐÑ£G¹rå +W®¼¯U~âÄ Ö­[G‡˜ÿ;¦¸¯ôœ‹Çÿʤ"ŠŽs,ïçjï×ß8ŽÞ…¿SŠ’Ø–÷ù]ËùÍ÷໵›Ê£öwÀË/¿œ|óæM?¨&‹­¾ØÏÏïæÖ­[MC^ׯ_gÏž=œ>};;;ôz=jµ___|||ðôôJmªÛÀèõzîܹC^^™™™¤¤¤””„N§Ã‚ââbBCC?~<¡¡¡õVóã?biiÉo¼Qåq­VËúõë9þøªI…•þõ¯e:uªß, JÞ°aƒé¹´Z-—.]âÌ™3B­¯fffh4”J%:©TŠ™™"‘N‡F£A$aii‰¹¹¹PëjkkKhh(}ûö¥GõîúÛ¹s'fffÌž=»Êã „……1dÈÆŒó@«Ò`0pòäI¶oß.ô“•J¥6 z½­V+¼¦Õj1XYYaccƒµµ5‚–^¯G¥RQVV†\.G.¿+N_žuk4133«DìåDniiIPPÓ§O¯q&ç¹sçøþûï »où•F£aΜ9Lš4‰öíÛ7«¹Ã?üРjgÍ7oÞä“O>!,,ìÕµÑh䫯׳ûô´ÛhDVQ¯’#TÿÏ5|§§§éK¬þûßÿ÷Ýw£€ó IÀ^Æ ÿðÃMb¹µÜ±ÆÆÆ’œœLJJ ÙÙÙsçÎxd2666ØÛÛ êN>>>B˜†ÂáÇÉÉÉáŸÿüg•ÇwìØÁ®]»X¸páŒJ¥’mÛ¶qðàAÊÊʉDÁ–[¦å„emmM»víð÷÷ºÝÔ6\«Õ’››Kff&IIIÄÅÅQRR‚¹¹¹0¦÷’¾N§C&“áììÌŒ3èÑ£Ç=wîÜaõêÕðöÛoWk¹+•JÞxã fΜÙl,†«W¯²k×.>ýôSS¼÷!––Æ’%K «÷R¥+W¯ðîª8Í•ã8’º×¶p7†\ð‰-Þš`>˜¿¬Ñ5SiÌ8räˆqùòå/«ÕêM IÀƒfÍšµïÅ_4𢣣9rä«W¯®DDZ­–Å‹#‹yã7îë¾Õh4lÞ¼Y Þ{ÏÕh4ÂÿÛ·oO·nÝh°¥rŽÈÈH®]»&|–{ëSË%.yã7èÖ­Û­]»vqéÒ%Ö­[W­ºSQQo¾ù&‹-jò P7nÜzA7Ær²¦†ŒŒ Þ}÷]–,YRïj¹\Κ¯?!*5û™w°ï Ô¢J™¥[m0FÛòæËïЧw_ÓVKÄÅűhÑ¢/333ç4ÛÙÙÍ^¼xñú~ýú™F¼‰#//µk×òÍ7ßTO(..æÿþïÿ2dO>ùä}‰éСC|÷ÝwÈårìŒF#½^——ƒ&((¨Aê#Dœ‰‰‰?~œøøx¡aû½V¹X,ÆÓÓ“°°0Zµjußû]¾|™o¾ù†Ï>û¬ÚnQ·nÝbåÊ•|ðÁüyëÓbûòË/Y·nÝ#/­kθuë+V¬àÃ?lMMFF›wGÄ• XtÒ! ½ƒeÈ<þ,Y^šlP%6Òš²p)ž®^Lý"}z÷i²söqãÏR¤£éééCŒ€[¶lùõªU«^«‚ z½ž%K–°råÊJõй¹¹¼þúë¼öÚktêÔ©Ú{äää°téR222*^9ñöìÙ“¡C‡6K°¬¬ŒãÇsòäI$‰{/™LÆÐ¡C™9sæ}³VÓÓÓž¬‘Î IDATY¶lüqµñÞßÿ¨¨¨zQ7{ Éûï¿Ï§Ÿ~Z¯1Kî"22’­[·²hÑ¢Ó×ëõܸqƒKW#¸~;šÜœ\ò2ŒF#–8;;ÓÖ;€.Á¡tîÜÙÔl¤ž0yòäk)))5ÎĬõ·ßªU«ãßÿý@Ó®¸icÓ¦M„††V*'ÉÎÎfæÌ™Ì›7ï¾2›¿üò ßÿ=jµZ +FƒN§£wïÞ<ùä“Üá ’’’ÈÎΦ´´…BB¡@­V£Ñh"//3*OX377µœœœððð ]»vµ’×òÞ½{5µÇ[·nqàÀŽ?NQQp7ÑÍh4 b,÷ÛH”׈‹D",,,‹Å¸ºº2lØ0FŽùX³{Ëå;'NœHÛ¶mM‹R3ÁìÙ³3._¾ìh„€Ûµk—øý÷ß› ›( ‹-bݺuA /½ô³gϮ֭ZXXÈ;ï¼C~~~«ॗ^ª’„î]pˆŠŠ"..sssæÍ›‡T*¥¸¸˜’’T*Z­VX8õz½` K$ÌÍͱ°°ÀÜܼÂ$$$pèÐ!ZµjEJJ J¥’€€ºvíJëÖ­ïk§¦¦òí·ß¢Õj+¥H$bÀ€¼õÖ[Õ^Ÿ——ÇâÅ‹ùÏþS¥dçéÓ§9q⯼òJ£Ÿ999|ñÅ|õÕW­íb^^[·nåàÁƒ¨T*”J¥*0 èt: ƒ`ÉVU+.‹‰DÂë囹òóu:VVVXYY1fÌ&MšôXÂ$%%%Ì;—O>ù¤^…:Lx|X±bEÎo¿ýÖHj6ïܹsâW_}ÕÊ4ÔMÀÆÆ†É“'W å™3g2bÄúö­:û1--ùóç£P(H$B¬·uëÖLŸ>½Zws^^§N"66–V­ZѾ}{är9æææ(•JbbbpqqÁÖÖVP²*Ù(·€¥R)F£µZV«H¹ÜÎÏÏç™gžáÌ™3ôéÓt:à²ÌÎΦcÇŽôíÛ·ÚìSNÇŽ;ˆŽŽF&“ ¼Ñh$00>ú¨ÚEòÖ­[¬Y³†Í›7W™°4wî\^|ñÅZ÷$~ÔøàƒX°`ÞÞÞü½oܸÁ§Ÿ~ÊíÛ·)++C&“ s¬œL­¬¬hÑ¢-Z´ÀÁÁ,,,*dÜ—«ª) îܹCnn.”””„lff†X,Æh4¢Óé°´´$88˜ùóçó¨åu÷ïßOJJ Ï=÷œiqjغu«üË/¿ mö}ê©§Î-^¼ØÃ4ÔMjµš÷Þ{M›6U “µk×¢ÕjyñÅ«%˜  Ñh‹Å‚;xĈ <¸Jk)))‰?þø½^O×®]ñ÷÷Híøñãܹs??¿ZµF¬Z­–Ÿþ___ÌÌÌ*©QéõznÞ¼ÉåË—±³³cäÈ‘Õf;_ºt‰Ÿ~ú ™LVÁjòõõeÍš5Õ–b>}šS§N±nݺJÏ“ššÊêÕ« k´s#**Š«W¯2þüGú¾·nÝâƒ> 55­V‹D"êâ% ´mÛ¶^jg ·nÝ"&&…BH$ª ‚cnnN`` ï½÷Þ#Û,FfΜÉÂ… ›|Ùš wõñ—-[öZYYÙkr~mý<­S§N榡nzøùçŸ2dH…˜Sxx8¿þú+óæÍ«’Ë-ßrò-w OŸ>îÝ»Wº&%%…ï¿ÿžŒŒ H÷îÝ+5H¸|ù2jµšaÆՋ«S"‘àççGxx8Z­¶RüZ,ãææFÇŽ±··çðáÃDEEáååUIh eË–.\+‰(,,$22’áÇWù™[·nMLL ¹¹¹•’®ìíí9{ö,nnnRIÊh4òÙgŸ±dÉ’G«V*•,]º”/¿ü’üü|u:ÞÞÞ 2„^½záååUoeP2™ wwwBBB B$‘^¯¼,YYYìÛ·‚‚ºwïÞàI["‘OOOöíÛ÷@Ýq?”J%çλUZZúGMίÕì233óiÕª•I€£ ¢\sèС,‚eË–±páÂ*I¥¨¨ˆùóç£V«òÕjµÌ™3§Rœ¸´´”7²ÿ~FŽɘ1cª-aQ©TõÞG×ÒÒ£ÑHAAÁ}ÏkÑ¢'N¤wïÞlÛ¶;v R©*œãååÅüùóe9É'&&²lÙ²J1Çr¼úê«ìܹ“”””JÇfÍšÅöí³—êÕ«W ydªG‘‘‘Œ3†cÇŽ¡×ëJPPÓ¦McذaµjðQXXXЭ[7¦OŸNß¾}…¥T*E¯×óóÏ?3vìX|<ºtéBrr2 …´P5q¸¹¹!‹kœ#U+vttlïîî.2 sÓéS§=zt…ýªU«˜2eJ•‹N§b¾÷Z¾sæÌ©Pžc4‰ˆˆ`ýúõ3qâÄöÇÕh4 ²À–Ç~ ÃÏõðð`êÔ©xxx°fÍ®_¿^ḋ‹ óæÍÂʭᨨ(¶nÝZÝ•·ß~›Å‹W"ér—waaa£›¿üò Ï?ÿü#±´×­[ǼyóP*•ˆÅbÔj5­ZµâÅ_¤W¯^<êk"‘ˆ€€^zé%ºté‚J¥B§Ó!‹)..æµ×^cÛ¶m þ9ÆÏ¡C‡L UÇŸëZãµ"`™Læïææfå&ˆcÇŽñÌ3Ï߸qƒäääjû•~üñÇäääTH¸š9sf…Ø©Z­æ»ï¾#..ŽiÓ¦áëë[£EX§Ó5·lÙKKKrssk¼øñ /pæÌvìØ!X¼ÎÎμõÖ[h4𠤾k×® eX÷Âßß~ûí·JǦNZåëwîÜÀÕÕµAßG£Ñ0{ölvíÚU!›yôèÑ >ü±—i‰D":wîÌóÏ?M…Ëþó/^\£]]1xð`Ο?oZ¨š8Äb1fff5M¯Æ–²nLh|ÈÊÊÂÃÃCÈT6|ôÑGÌž=»J×óÙ³g¹té’„¤V«?~|…Øj^^Ÿþ9Œ9²ÆmþÊÊÊ033«Q­pmáåå…X,&55µV×YXX0nÜ8Y·n@Jîîî̘1µZ-XµƒeË–¡T*«¼ßK/½Ä×_-´],G=¸víZµ.ìÇÓ§O3bĈ}¥RÉ /¼Àµk×2vqqá…^ ±mè­¬¬˜8q";v¾s£ÑÈÉ“'™5k–à ©oH¥RZµjUAU΄¦ ™LVcÑZ°D"±yÔ."êÇú3fŒðwxx8NNNU¶äS*•|þùçÂn_£ÑðÄOУGáœÛ·o³aÃF}ßÚߪPZZÚ`looV«%==½N×wîÜ™Áƒ³~ýzrrr„×ÛµkÇÀ…NN"‘…BÁ¿ÿýï*ïcmmͰaÃØ±cG%+ë‰'ž 11±Ñ̈ˆú÷ïß`÷W©T¼øâ‹¤¥¥ .ç   F]ãMÛã@hh(#FŒ@­Vc0‰D\¿~×_½ÁHxèСœ;wδ`5qXXXÈ€MîÚº MÙÏM111ºý|ñÅÕ–}öÙgB‰Fy¿â)S¦ÇãããÙ¹s'S¦L©“N°\.Ç`04——•h4š:[™žžžŒ?žï¾ûŽÌÌLáõ'Ÿ|R ø?7£DFFV›¤3f̘J.m€#F4šE¶<ù©¡’¯ôz=3gÎ$33©TŠZ­¦GôêÕ«Iün¼¼¼;v¬ #‹‰eáÂ… ò~]»v¼&4]¸ººJ€¹vjEÀR©ÔÔ“¬‰A.—ckk+¸“ccc±°°¨R†/;;›ˆˆÁ2ÑjµÌ˜1CøûÖ­[ìÝ»—)S¦Ô¹4D.—£×묽§§'VVV̆¾™4ißÿ½` ‹D"^}õU¡Fµœ`þ*çyÏ.˜^½zqðàÁ ¯wìØ‘ØØØF17233Txbùòåܺu ‰D‚Z­¦[·n„„4-[WWWÆŒ#lêD"ááálܸ±ÞßËÊÊJP–3¡éÂÍÍMÖlimm-5 oÓ³~CCC…¿·lÙ¸q㪵~ïíÝ(,й¹¹üôÓO<÷ÜsEžeeeH$’“:ôõõÅÂÂâ¡IÎÎÎŽqãÆ±aÃJKK»IYýû÷ÆH,“——ÇÕ«W«¼Çرc+eL—Kj–[ÒIII6Ƚ=ÊÑ£G‰DhµZÚ¶mKÇŽëíþjµšüü|ÒÒÒHLL$..ŽØØXHII!77·Ú}]Hxøðábú›6mª”9_ppp ¤¤Ä´p5m¶Ü뛀œœL"›nܸ!økµZ¢¢¢èܹs¥ó ˆ‹‹¬]NÇ„ „Åî»ï¾cìØ±%Š`4¹}ûvƒ–š¸»»£P(HOO'//ï¡îåääĈ#øöÛo…˜øˆ#„ĸëÆýꫯª¼ÞÅűX\Á• B\\ÜcŸÙÙÙì\”””°bÅ !ãÝÚÚú¡âÌ*•ŠÄÄDN:Å®]»Ø¾};¿ÿþ;×®]#++‹²²2¡#’J¥"//›7oräÈvìØÁO?ýÄÑ£G¹qãr¹¼NŸ¡uëÖ ›/½^Ïüùóë}#åååEvv¶iájÂpvv¶‹Å5²€¥µ[œLXM ÉÉÉB[Á³gÏÒµk×*Õ}~øáT*2™ µZM§N„8í?þHŸ>}º7ìÉ“' mÐ8Wyç›#F°k×.¦L™òP„ïíí¿¿?¿üò cÇŽE&“1xð`Ž?޹¹9b±˜ÜÜ\²²²ª”/4h`ÆŒÂkAAA$$$<ö6… ’…üþûï£R©H$èt:žyæ™Z{<ÊÊʈåöíÛH¥Rüüüèܹ3-Z´¾O£ÑHYYjµN'ÈW–·«,»èõzrssIIIáäÉ“( ¼½½ ¬•2Y¯^½¸}û¶ ™yçξøâ ÞyçzÝ@æçç×:¹Ñ„Æ‘ƒƒƒWMjþkCÀŽNNN¦$¬&†r[¸› Ý»wï*-Ó3gε˜ƒQ£F^¯hWå¹sçÉd(•J‚ƒƒô™ûõëÇÞ½{9r$û÷ïg̘1åòîÑ£[·n%99È‘#G*Xh?ýôsçέtmïÞ½Y¾|ynÓ¦ ÇŽ{ìsC©TRß}½¹rå R©FC=jõééé\¾|£ÑH§NèÛ·/æææ“œœÌõë×ÉÎΦ°°½^••–––H¥RD"z½^hÆ`0°··ÇÍÍ Z·nM÷îÝ1$&&ŽB¡ $$ÿΑHĨQ£Øµk—Ðñ—_~aÚ´i½9-‡µµµI«‰ÃÞÞssóõº¬­liÞ¦…{­ÝÈÈH^}õÕJçÄÆÆ ®5­V‹››ŽŽŽhµZ~ýõ×j3¦kƒÁÀ¡C‡pvvÆÇLJ .0zôè}f;;;zöìILL íÚµãСCÕj8×Ôª~ꩧرcÿüç?177'88˜ØØXÌÍÍ‘Édœ?¾JvttD.—£Ñh„ ާ§g…2§Ç¹9«ïR •+W "‰¤ÆIW\¸pwwwž~úiIOOçØ±cÄÅÅammMÛ¶m dÈ!¸ºº>ð³FŠŠŠÈÊÊ"55•'N••…——AAAL˜0µZMxx8;wî¤S§N‚·¨Z+ÄÑooo222033C¥RñùçŸóá‡ÖËø™™™5Šüê$Iº‡HkqS{{{SV‚R©ÄÒòîž©¸¸KKË*ݱÂ`00pà@Ž9B—.]êœt¥P(øå—_èÙ³'œ>}šgŸ}ö‘ôšõ÷÷'==±XŒŸŸÛ·o§}ûö899áì쌕•U­>‡££#­[·&<<œž={Ò¯_¿ q\µZMvv6•…µk׎ëׯ ±÷ƲÈÊd²zͺÍÈÈ ))I°~ûõë÷À1.--åäÉ“ØÙÙ1yòd¤R)—.]âòå˸¹¹Ñ½{wÆ/ÌãÚnœœœœprr¼.z½ž¤¤$¢¢¢8räþþþôìÙ“¾}ûræÌvïÞMÿþýï« Ö·o_AžR&“qêÔ)ÊÊÊêÅ› V«• M¶¶¶õKÀVVV®ÖÖÖ¦ÑmBËåB‹³7nTWŠŠŠ¬3½^OHH*•ŠÈÈÈ ®ÓA«Õ ýWÓÓÓ1 Œ7ŽØØXnܸÁ¸q㼻̽0`üñ-Z´à¥—^"..Žììl®]»Fii)F£sssœqvvÆÕÕggçj-«Þ½{³yófºwŸ:N7¥RÉ… ;vl¥ëˆŽŽ®üö¸Þß kkë:'%U…Í›7£V«…^¾÷vݪ ×®]#!!§žz NŸ>ÍÍ›7éÝ»7óçÏoúd‰DB»víh×®z½ž«W¯²oß>¬¬¬2d¡¡¡üöÛoØÛÛÓ³gÏ*竵µ5ÎÎÎ ›½{÷2uêÔ‡þ|%%%õæÎ6áñÀÊÊ ƒÁP£É+­ÅÄu¨Ë.Ô„ÇF#즫¬ù4 Â"¬×ë±³³ÃÜÜœãÇÓ©S§JMè wîÜ¡°°¢¢" (..¬OOOüüü2d999üñÇxxxðôÓO?rÒ‰DŒ9’+W®°yóf$ x{{ãî»;VVVäåå‘MBBgΜÄø]]]qwwÇÓÓ[[[,--iݺ5ÑÑÑtêÔ Á)•J9þ|•ìëëËñãÇ+}¶Ç gggrrrèv­ ŒF#G¬êvíÚUûŒZ­–#GŽ£ÈÈHvíÚÅ Aƒ˜0aÂ#SÈ’H$téÒ….]ºÏÞ½{quuåÙgŸ%..޽{÷2|øð*7ݺuã?þ@*•"‹ÙµkW½pNNNƒ•†™ðhðgø¥FâæÒZÜÔ¾¡ÄLhèõzaŸššJ§N*“••%”Ôèt:¡™}¹5wìØ1Š‹‹Q«ÕˆD"$ ŽŽŽ¸¹¹áééIçαµµ%//ÌÌLÒÓÓ9uê'OžÄÍÍð8õÃËEö;wîŒÑh¤´´”‚‚ÒÓÓ¹zõ*%%%FÌÌÌpww'44OOOœÉÍÍ%--ˆˆŠŠŠ033£M›6œ>}šN:Ljj*fffH$’ju|[¶lYk}êGV­Z‘œœL¿~ýú^)))‚ê—Ñh$((¨ÊóJKK9xð C† ÁÁÁM›6áççÇÂ… «ëµ]»v,X°€‹/²aÆ Ƙ1cسgýû÷ÇݽbY§§§§ð»‹ÅÖ‹:55µÊlzš$µ\–€E"‘­ÉnZÉdB¬177—Êa‰´´4¡*ÜfeeaeeÅÁƒyöÙgqttD¥RQXXHaa!yyy$'' 1P™L†‹‹ ®®®tî܇FaáUEÆvvvØÙÙUêܤ×ë)(( 77—³gÏ m­­­ñóóãÉ'ŸD&“±qãFŠ‹‹Q(´nݺ‚‹ò¯}…ËaooOQQQ£6mÚpæÌ™z¹×ùóçQ*•˜››c4«œkÅÅÅ>|˜ñãÇ“••Å¡C‡øÇ?þÑ j\µÝ»w'88˜-[¶`mmÍóÏ?ÏŽ; ­Ð†S$áàà€B¡Ê­¢¢¢èÛ·ïC}†²²2Lël³°‚ë—€“Ü´`aa!”4WéJËÍͲaE"nnnDGG£V«y饗ÈÉÉaß¾}¸ººbgg‡ƒƒmÛ¶¥{÷î½…\=ïXqss«T«R©HKKã—_~ÁÅÅ…É“'óßÿþ—ëׯóÄOTæ/o.ÿ׸¡X,®¤MÝ:"¹¸¸Ô[6ö¹sçH$ †*çYII ‡fòäÉ\ºt‰üü|æÍ›Gc\S¬­­™9s&ÇŽcçÎL˜0Ý»w#‹+H¸–‡#$ Z­– .<9&˜ø¯0oÌÝKL¨ ;;;!>{o<ø¯?úrkÕ`0àèèHTT” xöìY¦NÚ(-ÚGµ‰iÛ¶-mÛ¶eß¾}èt:<<<¸|ù2ݺu«Ô#V¡P”gAV²®ù–ÃÑÑ‘ÜÜ܇ä(×|Öjµ•tÆU*dÒ¤Iœ8q[[[^ýõzS'Nœ ..[[[&MšôÐqd‘HÄ!CpwwgûöíLœ8‘Ý»w3xð`¡—µ›››ð R©”7n<Ô{†‡‡W&2¡Ip²Mkœ’j4kêÖ6¡ñL Ê[ªýå±]¸¶²²B¥R1lØ0vîÜÉ“O>ù·%ß¿bÀ€8p€áÇ“™™‰H$ªdíþµpU(..®’¤úöíË¡C‡ú>*• ‘H„Á`¨Åk49xð £FâìÙ³¸¸¸0a„zS:Žøøx–,Y‚¿¿½6»xâ‰'˜0a;wîdôèÑ>|X(ݺ·£—D"!77÷¡ÞëÈ‘#U å˜Ðô ‰ê—€kAê&4" ¡Ü¦ªÚÓ{7U"‘¥R‰­­-QQQøúú6X«º¦a“RN.%’šlRoß¾··w£x¦=zpòäÉz!ÁrÜüt餤¤`aaÁÓO?]ïÏ •Jquuå£>âÊ•+´iÓ¦^ïß¶m[FÍÜ4€UXD‘‘‘‚¬æ_ÝÉUÅ4ÿzN|||…„žÇ ™L†‡‡ ¬Û­áÂ#xÊU¨üüüˆˆˆà7Þh0oʳÏ>Û Ê^å&''‡ÄÄD¬¬¬¸}û6-[¶¬ðÝþ5QìÛ·aÆ™~`3ˆè\ ÊE ÜÜܨJü¯år¹ƒÁ€D"©`dÂ]ØÚÚ¢V«‹Å(Š °X,®2ƒU.—WpW^¾|¹Ú2ÇqãÆÕ[[£Ñ(̛ӧO3lØ0>ÌË/¿Üà", £2hÐ  þþþDDD Ñh*l(꺹Ðëõ:tˆ>}ú˜~`Í5Íó¨Í/BkZ›¦ÅvñâEZµjU©-^9—'gI¥Rär¹ r_VVfÀ¿ ¼ä¤¼Ïí½?´êº.eeeUHLÊÊʪ²LçqÁÛÛ›²²²jë˜k:.åP(dddàääÄÅ‹=z4ÍAEO$1uêTNœ8A‡ˆ‰‰©@ºuÝüþûïôë×S’kóâàú&à²êêMh¼hݺ5ñññøûû“––Vé¸`™H$¡·ª­­­©+K5DS¾-o¹W¾ã­.±*%%EP›ÊËËk”q¾iÓ¦ñÙgŸÕùúò’4‰DBAA‘‘‘£P(q—æâéÛ·/jµš[·nUè ]ÁFÃÎ;$6nÂcµ€k¨1‹D¢²šdxšÐøvíŽŽŽ¸ºº_鸵µu…6„r¹±XŒ……wîÜ1 `50ÜUu*'`­V[-ÑÄÇÇ .çãÇÓ½{÷F÷\ÞÞÞX[[Q§ë[µj…^¯G*•’••…¹¹9UJs6uôëרØXüüü„͘N§«“¤ç† 3fÌCõ¬6¡ñA¯××/r7M 8 .PXXXe¢HË–-…׳²² ËÒÒRÓàýõ# ‹nvv¶ðo©TJ¯^½ª¼æÆB]õáÇ«=ïqã•W^aýúõÔÅÓÕ­[7Á5¯V«iÛ¶-:®Ñ$›Õ÷&¬wïÞº‹‰ÅbzôèQ«ûܺu‹7n0`ÀÓ«™Á`0èê•€ Ã¥RiÙ&ˆ®]»rêÔ)‚‚‚ª´‚‡ †N§ÃÌ̌۷o£V«1 &®fñÕëõˆD"®_¿.ÄíÌÌÌ’½åqtkkk J¥VjÐÊʊ矞U«VÕúÚ>}úà‰„âââzјn¬èÕ«‰‰‰‚D&“Zãë5 Ë—/çÍ7ß4ý¨š!t:]¦jLÀ*•*Óä’lšJ¥x{{[÷´ IDATÀ¹sç*ïׯˆÅbT*æææ¨T*߇€Åb1™™™H¥R -Z´¨Ò!ÑöíÛ5jT£ß¬Éd2öïß_«ë‚‚‚‰DFlllHLL$$$¤ÙÎKKKlllhÑ¢KKËZµüøã™0aÂcmTbBÃ@«Õ¢×ëk”ÁZc...N),,4š†·ibôèÑÄÅÅqþüùJÇlmmqwwtŒ]\\ˆ‰‰iMãŒF#ƒ¡B/`ƒÁÀĉ«<ÿرc<ýôÓèt:Ο?O—.]ý3Θ1ƒýû÷sýúõ_#‹éÚµ+J¥OOO¬­­›}\ó‰'žÀÒÒ½^_«ÕöíÛ±³³«µËÚ„¦’’D"QdÑjã‚ÎÈÊÊ2™DMžžž¨T*Z´hABBB¥ã/¼ð"‘©TJvv¶à†.×’6á.ÒÒÒ°±±A¯× °–––Uº[ yyyøûû³oß>Ø$d=Åb1ÿú׿X½zu•™óÕá•W^A*•"“Éðóókös¡M›6(•Jd2“'O®Ñ5ÇŽ#**Šüã¦S3E^^z½þV½0–žžn* m˜0Ó;??ŸäädÚ·oߤU²D"ÑcÝ?ÿü3§OŸæ½÷Þ3Õûþ ˜˜¨뛀Q©TwRðÜ„†‡»»;={öäðáÃLœ8±Bæ¦X,æwÞaÙ²e˜™™¡Ó鈉‰¡wïÞ„††rñâE.^¼XA~Q$!‘H«Y*• ¥6vvv8;;ãîîþØÛïiµZÎ;G||}šo¾ù†°°° ǺvíJPPÑÑѨT*NŸ>M`` 2™Œ>}úTŒ7 èõz ƒðoFƒZ­F¡PPPPÀÕ«W)(( ((ˆ^½z=òÅ611‘ƒ2pà@úöí[§ø[ii)ׯ_G¡Põ® ,¨Ò¢Ù³gcÇŽåêÕ«˜››×K—¡Ç kkk>üðC¾þúk®^½Ê;ï¼Så³;::"‰„ž¹UA¡PàääD`` ÇŽC¯×7:.--eÓ¦Møøø°ÿ~^ýõ*çÑh¬Ðh£………,Y²„þýû3tèPÓ¢ó7Ñh¤¬¬¬”Ђ¦  àD||¼©#C‡T*%,,Œk×®]éøâÅ‹…2…BÁÑ£G«Ÿ@b1fff˜›› µ‘NNN´hѺuëÆ³Ï>Ë+¯¼‚……ÿùÏÈÏÏdÏš””ÄüÁ«¯¾JûöíëD¾F£‘ýû÷£T*‘J¥èõzzôèA×®]+›——ÇÉ“'yúé§ùöÛo™>}z³™7b±˜Y³fѾ}{fΜÉíÛ·+ÓºukD"Ñ}eL[·nMÛ¶mÙµkO?ý´PÎÕ˜——G‹-9r$ƒªTË;?µjÕªÂë§OŸæí·ßfúôé&òý›¡  ½^Ÿ\ÓókµíÔétj{{ûçúöíkmê¦òæò›6mâ©§žªV033#((ˆ“'Ob4)((ÀÕÕõ¡kD"-Z´ 00~ø__ßGûÛ³gƒ~¨îCW®\áÖ­[èt:Äb1ÎÎάZµª’Õf4Y¾|9óçÏgõêÕ¼öÚkÍ2ÉÛÛ›.]º°fͲ³³éر£à^Õh4œrss…6%Y¸[ïň#¦¤¤„+V––Æ‚ UÇ+ .]ºd<|øðW&¼Þ-` >..ΤGÙL0iÒ$ÜÝÝ«ì‚ÌóÏ?L&C¯×³ÿþziÎ`kkËÔ©SÙ±cGƒ }”––¢ÑhîKBvv6çÏŸ§´´©TŠ……Ÿ~úi•î×½{÷ÂáÇ4hÞÞÞÍvî”Ç…­¬¬xå•W¸téíÛ·G£ÑœœÜ¤ŸO$1hÐ fÍšU¥Ä(@jj*R©”Ž;²{÷nÞ|óM†ÎìÙ³…Ÿ&ü½UPZZzºÆ^¥ZÞß P( þn%)Í+W®$::ºJ7ó„ 8p æææ(•J¶mÛF}4äprrÂËˋӧO7è³¥¦¦Ö(Kõ~¾gÏJKK‘ÉdH$V¬XQ¥eÇ™3gpssC,Ó¿ÿf?wD"ÇgéÒ¥üöÛo¼ùæ›dffbggW+¦ŠØØXÊÊÊøè£(,,dõêÕB×+þžˆŽŽ.®5£ÕjÏT%èoBÓ„T*eݺu|õÕW$&VΜŸ;w.¡¡¡XZZRRRÂ?þX/–k÷îÝIJJjÐgËÈÈÀÑѱN×–••±mÛ6îܹƒ……R©”%K–PéÜ¢¢"Ö®]˘1c¸víS§Ný[Í!æÌ™ÃŒ3øê«¯„ÆÙÙÙÍö™F#±±±8::²téRÆ×(3¹MxtÐét”––5¶PkMÀÙÙÙ{ÂÃÃKLÃÝ|àèèÈÇLXX¹¹¹•¬œÅ‹Ó«W/,,,ÈÍÍå‡~xhKØÍÍ µZÝ 999Ô%c_.—óÃ?PTT„……fff¼ûî»Uê8+•JÞ{ï=ÆŒùsç˜3gÎßVåÈÓÓ“°°0Þxã ”Je•ºãÍ·oßF*•òÖ[oacccZDL 66­V{¢6×Ô¥0íÂùóçMÜÌЦM˜;w.………•H8,,ŒQ£FammM^^›6mz¨nIb±‰DBVVVƒY(J¥’–-[Öêºüü|6oÞLQQ2™ +++V®\Ye«9FÃ’%KèÙ³'×®]cþüù¦ZOî6)hß¾=×®]»o9RSÆ‘#G033{ 0‰ œ;w®8''gOC°º¨¨(·>b&4.têÔ‰ùóçóÿ÷U’ð¬Y³˜={6666”””ðÝwß‘ššZç÷srrz¨ëï‡ÒÒRôz=5¾&..Žü¹\޹¹9ÎÎά_¿žöíÛWþ¨Õ,^¼˜Ö­[SXXÈ;ï¼c"ß{P^vvâĉf÷lÙÙÙdgg3}út“¦³ þô _hh¦¬¬lßåË—M­ ›!:wî,¸«²NGŒÁÚµkqssC£Ñ°sçNNž‚ƒƒøÈŸ744àäÉ“(((€ÅbÇCtt4¶mÛöÈ•Î-ßO?ý|>‰‰‰èׯy£ü.— @€ÜÜ\¸¹¹=2˜Ew¢Õj±ÿ~Œ5 'N$ L<œœ¬(++{ÀS=îyæ¬ v»ýbiii8¹õìN899Ÿþ9Ö¬Yƒ5kÖ€ÇãýÛÿ‰ŠŠÂþýûqèÐ!:t%%%(//ÇÀ1bĈß…òx6ØÁ³2›Í¼à766âÒ¥K¨¬¬|L= +W®|ä\/p?¨þ¾}ûpñâEÄÄÄ`Ñ¢EO¼å„¦é! û±³[þ­åõ8¿¾¹¥(ꑯ–2ZÊk™x¸ìß:ίËf0ÿö}k¯ÇÇÇãÊ•+ÈÊÊ‚L&{ì QWgµZ±k×.ôéÓË–-#âá¾UUUõžzEik†¯ƒ§M›–½bÅ !i‚ž///»víÂòåËñüóÏ?òÿX,ìÛ·0pwwGPPbbbàïïÿÈGv¨®®nÓG¹F£©©©˜?>X,hšFEE®^½ •J³Ù 6› ‰D‚Å‹cèС}œXUU…M›6Án·cÅŠÈÌÌl,..Ö;§Ëåzð¢iÚår¹\ô}-_iš¦]\\E=øMQÝüý“|6)š¦[zBFóÏ)š¦Íå<üz¸ü‡{^ú7ŽEÑ4M5—ÍxèxL ê¾–¯ƒÁ`4a0 &ƒÁ`2™L¦Ëåâ,[¶LøÒK/±¾@-[¶ Z­ O”¼¾+q8HNN†Á`ÀŽ;ž(ÿ/Ñ{\¾|ÙµiÓ¦ f}GvÀTpppÙÁƒû’ÇнCcc#¶mÛwww,_¾ü±)m6Nœ8C‡A§Ó¢(p8DEE¡ÿþðóó{Ðá }:^zé¥Û6***PRR‚«W¯¢®®V«|>·nÝB@@@›ä ¦iYYY¨¯¯Gqq1*++Ád2áé鉩S§âoûÞxãÇnO¢i999X³f l66oÞ ‡Ãa[»vmyeeå$ƒÁIÞ ¿Éf4SïÝ»Gçææ2dˆŸÏ‡››bccqþüyäææ"((虣”ýÚµk×ðóÏ?Ãår¡°°ð±S Ïò$åË/¿„Á`@RRR·ŸÃ&ÚžÕjÅÞ½{Ñét[žiÛÊãGÄÅÅ]Z¿~½˜4Eïb·ÛñÃ?àôéÓ˜1câããs®ÐåráÆ8räȃ\Ãv»<‡‰o¾ùf«ÂùÑ4ãÇ£¬¬ L&B¡ãÆC\\¤RéïþnAA’““Ááp°jÕ*p8lÙ²Ey÷îÝJ¥ò¯,¤åŸJ?©Tzhúôéa3fÌð`2™0›ÍHLLDMM FQ£FµzÄš••…~ýú!$$)))X´hQ«O¼²²ß|ó 8¶oß2È åôéÓö¤¤¤¿èŒþþþEiii»bNO¢ýF|ÿý÷ÈÍÍÅĉ1iÒ¤'Ê£×ëqãÆ œ;wEEEÐétpssà /¼€èèèG&9ÿu‡ét:aµZa6›¡T*¬¶]½z5"##Ÿ¨3w:¸té¾þúk¬X±¾¾¾Ø³gOCNNNYmmí|Ť¥ŸC(.õòòZ¹dÉÙ+¯¼Â¦iÉÉɸté¼¼¼ðÖ[oµj4l·Û‘ ƒÁ€¸¸¸V¥€t88uê~úé'„‡‡cÆ àr¹¤‰GúóŸÿ\}ýúõç4vJìííý—÷Þ{ok||<é{1‹Å‚“'O";;‘‘‘˜6mžºŒ””üóŸÿ„Íf“É|ìŠá– |>‰³fÍzì¢_S*•8vìÎ;‡àÝwßEQHMMm¸xñbmCCÃ&“)›´l›á‹D¢½¼¼æÌ›7O:fÌöõë×±yóf˜ÍfŒ9±±±Ïœ¹ªµhšÆ­[·ðÃ?€¦i,X°€l5"~“J¥BBBÂéÚÚÚ¸g-£-V+ P¼gÏ2AB€¦iâÔ©S¨®®Æˆ#0nܸ.±ýD£ÑàüùóÈÌ̃ÁÀ”)S‡²²2ìß¿_q÷îÝ µZ½Æjµ^YdÕn±¯¯ï{|>ÿ &ø½úê«‚C‡!''6› cÆŒÁˆ#:,ŸnKÇ›‘‘³ÙŒˆˆ$&&¶Ùü4Ñs%''7¤¥¥½át:/tf ™Lv,))éõÖ$>'zž–Œ8.\€\.Gxx8Fމ¨¨¨ÙÊa2™PTT„ÜÜ\\»v |>ãÇǘ1c@Ó4N:eÈÌÌÔÆ3 …b€_H«u&—Ë( Wùûû?^’ŸŸÏ¸}û6Ìf3¢££1|øp´KÄ)N‡+W® 77 b±Ë—/ÇþðÒ2Äïr:˜3gNYUUUdknÖÛê=qâÄÓ~ø¡iâq£Ï#GŽØu:K¥RQ ‹Åˆˆˆ@xx8!“Éð,k œN'êêêPSSƒ»wïâÖ­[¨©©‡ÃAtt4† ‚çž{‹.\°fdd¨êëëËU*Õv›Ív O¿•hs‘H´ÄÝÝ}Vß¾}}Ùl¶oQQ(Š‚Ãá@TT €°°°ÿ󤪪ªPZZŠëׯC¯×ƒÅb!** óçÏGhh(€ûóÉÇ·„‡‡s¢¢¢HŽ_â‘Ο?oÿì³ÏÖiµÚ¿·¦œ6»µ”Éd×÷íÛ÷ÉI´P©TÈÌÌÔŸ;w®Áh4–i4š#>>>£E"Ñи¸8ß¾N§CUUª««!—ËaµZár¹Àf³ÁçóÁårÁb±Àb±àt:a·Ûa±X`0ä$f³ÙÉd Bpp0ÂÃÊ¢P]]üü|ÓÙ³gµZ­¶J§Ó¥èõúð”!ãˆ)‹¹¹¹ýÑ××WÄ`0|jkkѲ‚šÁ` "‘B¡žžžàr¹`³Ù ( v»V«ƒ P©T¨­­…^¯ŸÏ‡Ãá@pp0&OžŒ#F€ËåÂl6ãÖ­[ôÙ³gÕ………Z•Jµ×ÓÓSìîî>!44Tøú믋‡  1ÑbÑ¢EÕEEEQZ•š·Í:`‡3cþüù{æÎKzà^Ìf³áìÙ³¶£GªJ Åv§ÓyúW£L.“É#‘H¦±Ùìç<<<¼|}}9aaaÜÀÀ@O___¶@ x°­‰ÉdÂét‚Éd‚ÍfÃÝÝnnn0›Í0¨¯¯‡V«EMM±¼¼\_YYiÓëõ:‡ÃqS¡Pr:gI u+a>>>oðx¼?2Œ6›íÅ`0xƒm·Û)Š¢Àf³¼Ohš~šÓáp€¦ip8"22àóùP*•ÆÊÊJ}UU•M¯×ëÍf³Úh4fkµÚcJuþ"‘h¡»»ûìÁƒ gΜéBZ¦»{÷.V®\yP¡PÌimYm9¹Â ºsàÀ°'IGô,µµµHKKÓ^½zUe0v666îð4©Ž¼„ôññéËårƒY,–Øårõ¡(ŠOQ³%bs¼cš¦i;EQõ‡£V¯×— †råª8IËô(™Lf¨——W$‡Ã s¹\.—ˇ¦i.EQL&“ Š¢,ËFÓ´€ €ž¦iµÓé¬mjjúÅd2U¸×üyšé‡d2Ù‡ÞÞÞCfÏž-=z4›\ëzŸÄÄĺK—.½Ò|é20„Bá _{í5²%©—(**¢wîÜY'—ËoÈåòu H­=œ@(&ðùü¯½öšdÆŒ²W¸wP*•HHH8/—ËcÛ¢¼¶^^È )=pà@ IPÞsÑ4k×®¹¾úê+¹F£9£P(Ö“š!z—Ë}£OŸ>;ÖÿOú“7YÓ³mܸQ}òäÉx×Ú¢¼¶^UàpssÉd²¡!!!¤îo~~¾cݺuµÙÙÙ+**f5'¡Ö“Ú!zãGÂápëõú¯ÊÊÊndeeEÕÕÕ¹õïߟÛÖù­‰Î§Õj±k×®›z½þ“¶*³=Ò ŠSSSH–¤žÓñæääØwïÞ­hll<¬V«?Æ3†^#ˆŒj^\¸uèСÁï¼óް5a1‰®eË–-šôôôɇãr[•Ùëêml6[$‘HbBCCɺýnÌåráìÙ³¶uëÖÕ^¸paGuuõ“É”’”€ w³Z¡×ëwUTT\>sæÌ€²²2Nÿþýy|>ŸTN7ýîØ±ãfSSÓGmzÇÖNçëZœššJæ‚»!‡ÃÌÌLKZZšÂ`0ìÑh4IL¤fâé°X¬—E"QÒ Aƒ"–,Y"’Éd¤Rº¡7ª³²²&:Ž6]dÚ^#T‹Åây{{ˆˆ ëô» ›Í†£G?ù䓚¼¼¼Muuuo›L¦ó ‘¢♸\.¹^¯ÿº¼¼<;'''¼°°áÑ¡X‰¶!—˱wïÞ‚¦¦¦Mm]v{NÒºÞNMM !© »6³ÙŒÃ‡ëÓÓÓz½~KSSÓ7¤f¢Í…K¥ÒÏ‚‚‚'$$È"""Htq+W®T俿ޯié²#`p2Œ‡Ã1îÅ_t'ÍØõèt:ìÝ»·ñ³Ï>«¸råÊr­V›`µZÿÀEj‡ ÚE½Á`8X[[{äÊ•+Ò‹/úxH$²bµ *))¡9’i0v´GùíÝè”T*ý9%%å9¡PHZ³‹Ðh4øæ›o´ùùùÕjµzµÍfËI¿GA,‘H>öññyuáÂ…ÒaÆ1Éî‘®¡9/tmIIÉ‹TíqŒv_¥l±XþU[[ûúرcÉ2ÀNV]]­[·ªöîÝ{½°°pASSÓ§Óy—Ô At£Á`H×h4_ÿüóϬŒŒŒ@>ŸÏ e‘¬+33Ó’““ó…Ñh<Õn#Թŋ¯_¿þèèhòŽê¥¥¥øê«¯êª««oÈåò‘Z!ˆ.‰+ ÿâáá±dÚ´iâÉ“'óÈšŽg00þü;555ƒÐŽ‹P;êY‡OPPÐÝ»wÒº€¦i¸RRRê4MŽB¡X…ûè ‚èúØ^^^sÁÇÅʼngÏžíEÂ\v —Ë…U«Vi þËb±\lÏcuØdÇ{ÞßßÿÛ·o$ÑaÚÓéĹsçlß~û­B§ÓW©TК!ˆn‰âr¹“|||6ÄÄÄø¿ýöÛ¾"‘ˆÔJ;^?×®]«¾qãÆZ­V»³Ý·ƒÿ¾ð“’’B¤R)ií6d6›qâÄ ãñãÇUƒa—V«ý_ü·Ñc°X¬a"‘èï‹-’„……‘JiC6› ‰‰‰ÊÒÒÒ¿644껫Nø;ÎnÚ´)<<<œ,÷k%­V‹ÔÔÔúœœ¥N§û»^¯OÙÃK=Y„T*ýÔÏÏ/fÁ‚Ò—_~™AVN·ŽÁ`Àûï¿/¯®®ž×ÔÔt¦£ŽÛY­ÖG*•ž]³fÍ Áƒ“HYÏ ¼¼)))Ê;wî”×××hµZ/€l%"ˆÞÄO,¯ñðð˜:kÖ,Q||<‡Íf“ZyJ*• Ë—/¯ª««›j2™ ;òØyÛÄ•H$é .6qâDyü>—Ë…üü|ç¾}ûêÔjõ•ºººÕîš!ˆ^ëíí½X ,?~¼hæÌ™^žžž¤Vž@YY½zõ겚ššx•}üÎ~nÁH$»Ç75!!Á›2™¬Kž¨Ëå­[·––VwçÎR¹\þnwètÇÈÞB¡p!Ç{Ëßßß/>>Þ/&&†íããÓ©'eµZ‘——çHOOWVWW+u:ÝnNw@#ùÑ1¼"“ÉÞóððˆŽí3aÂÏÎÞ.j±XpíÚ5úÇTë,K¶J¥ú@yw©ØîzÊÏÃÃc²··÷lww÷о}ûò‡*8p + í=g¬Ñh——gÉÎÎV«T*•^¯?ÐÔÔt€Š|f ‚èØL&s¬D"YÆår>Ü+66¶Oxxx‡\oKJJèŸ~úIsóæM£^¯W˜L¦ôúúú#è¦!y{RìG @0‡Ã) _e2™y<ž§T*åôë×Ï#,,L “É •JÁårŸºpš¦¡T*Q\\ìÌËËSß¾}ÛhµZïh4š‹å$€&òÙ$¢—Œc¤Ré›l6{”T*õ>|¸Ott4?,, ϲµÉn·C¥RA.—£²²ÒTZZÚtïÞ=›Á`Ð;Ž NwZ§Ó]ÄýÇËΞÐiõd?‘žžžƒÁ‹Eõe0>nnnînnnîl6ÛÇãQ‡ÃaPEÑ4M[­VÚd2¹t:ËjµZL&“™¦é;õõõ§M&ÓY¿€d"‚háÍd2GúùùųX¬—ÝÝݽ8—Çã1===‡b2™MÓ°Z­.“ÉDFÚf³9ìv»Õn·[ìv»‘¦é “Ét½¡¡áFóÈöWOí z; ¿ùÅm¾«£q¿˜€®§6>ADàðÀi¾¾ºp?þ² ÷W(;IAAAAAAAAAAAAA<ÒÿÃRÿîyò9JIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/joystick/button.png0000644000175000017500000000453513263212010023275 0ustar aeglosaeglos‰PNG  IHDR22)áxƒPLTE      "!#$&%')(*+-,/.01325477698;:=<>@?@BACCDEFGJIKNMPRQUWXY[Z]\_^`abedgfi h k j l m o n q p r u t s v y x w z { | ~ } € €  ‚  „ ƒ † … ˆ ‡ Š ‰ Œ ‹ Œ  Ž  ‘  ’ “ • ” — – ˜ ˜ ™ › š  œ ž Ÿ ¡   £ ¢ ¤¤ ¥¦¦§¨ª©¬«­®°°¯²±´³µ¶¸·º¹»¼¾½¿ÁÀÂÃÄÅÆÉÊÍÎÏÐÒÓÕÙØ Ù Þ Ý à â á ä å ê î ï ñ õ öQMeYye Žm¢y¶}(¾‚8ÇŽMÏ–aÛ¦u㲎ëæ÷ÓÃÿëßÿÿÿÿÿÿÿ¬||ÿÿÿÿWbz´´´ÿÿÿ>EºƒtEXtSoftwareGrafx2 ¢SjýIDATH‰Õ•û_SeÇý!{•æ%D#HA@˜lg¶Ñ$.J…†¦^’HD6ε³]ÛÙ…³3·1æ¸ ™cZÞ@,5Ìn¦Yv¿˜þ'=Gâ–¨ýXߟŸ÷ëó=Ÿóy>Ï¢Eÿ£¹}}|8`Ó6×o­ÿ›ó_}ra$2bmÚýÛªËËTÞ€/¯Æ‚^ˆxh Õº·®J!Ì“ 6<¸~í\øìä¨Ý½vëÎw·?=AÖWˆ!‰ ë‘ÄÇçãñ‹qgì‡{÷~ûúò¥Ï¿¿{ÿ§áÆMB‘€¿qaâòéщXøÊÝ;¡¦ ™DÂ{iujµnòÛxƒ âC 2×>89ÎŽýqs÷–Æî‘pÀI¶Öå¥$Uº?³‰ ~Î[œ`oÞ7 ©ñ1Ó¨aXÝ~´eßæÌÄ;õªâ?äÜ•S''‚·ÙY9z¾ûˆÇ´Z-†áˆºuoYRú®†RúóÅÙøûÍêCã¤Å ŠÔëIŠÀPT}¸ŽŸ\¶E˜ìyÈxlìØ­« ;Õœì4XÌV«ÙhÒéµܾO–¢Ræ æË\ˆ~ôç¶–qX c—vÒ4m³Y·¿#IÍæBó˜ˆ#ù©8OªQÊd¶;]n7øN{—Å@âHÇÛYY<‰h®=rý"oØÝS&«ÓÅô°‡íq;h›Ù@bHûÖuYÙÒ¹2úv?ósmóé#a°Ò®×ðû}^–qÑ6K'…ÇóÒS¤‚92šFztR#4Z½™v±_ ÈMÀça\v«IO êú iéÒY•úÆü6^5ÔŠF›‹ñø‚½}!0}AëvvY8 «²VÍ1 nÛAͯ…-„Ó[7|¼¿¿  z{6à€9R+Hä‰gšª¶kÕmèû¦nG׈ÁÈÈH¤?Üð¸i«AGᚆ¼äurÁtÒ*Jk‡|IÛÁ^vé;>8Å¢'B~1ê(LÓTž±F&šF ‹^¾—¶¿'-À._04‰ÆGGOŽ …ƒÇ§Õ¨'1õ¡×+äÂiD¡¨pÕ¦6€¤˜í.–C†c£§ÏÄ£‘pÐ÷¡´ðáíò•¹âi$WZÚ^Þ ÆH ·Ørf ñ0´Ù¤'µpëž‚eRÉ4"î*Kß TŒvãñ÷ÅNÆã±áþP€uqŽ—U-—I§‘a~ͦÔ:.-6§›ŽõÃF†‡Â½>ÆÑeÒqH›^š'ŸA²Ò´7ÚPÂ`¦œeáÁHdèx¯Ÿ†½\ÝaÎxQ)›EÄE¹™å­ˆVgérºX¯? ‡Ã¡^¿‡qÚŒ$×d*•Ó­‘A*~¶ä]5N@òÁÿ÷ùAÄü b.b¡…Q²yi®2¦ùü\QVÆŽ c´v9nÖãõz=,G€KF€(cöšÄü"ÉL’s ‘,-CÕ d8†v8\ øNîZ’œˆeRs”•³áçó!qVÆÆ75FéLk—ÍNÓv»­ËbâÅ×Á•/—¨2f¯%ÄAI|åÕ‚®0¹¶°š-&ƒŽ#pןZ“¥ªœ[‰×¦È«[aLK‘ºNƒÁd0t:=Ea`-»,MP”ËRÍcDâÄõªÚ6t(1œ')ÐdDä­g…%Åó{9â‹¡UÙ[êšaÅG¬EÑèÁå¼¢M²Œyá‹rVdï>Ð#SJ§ÂLN6,ãå—«*rð9"ÞÒu{;›Ž  J\ jÁ´s©ài^~•r炳JL¨±wëpAP¬„Yƒº”¢¢ò¼ì‡‰ŒP˜¹rõf@?@BACCDEFGJIKNMPRQUWXY[Z]\_^`abedgfi h k j l m o n q p r u t s v y x w z { | ~ } € €  ‚  „ ƒ † … ˆ ‡ Š ‰ Œ ‹ Œ  Ž  ‘  ’ “ • ” — – ˜ ˜ ™ › š  œ ž Ÿ ¡   £ ¢ ¤¤ ¥¦¦§¨ª©¬«­®°°¯²±´³µ¶¸·º¹»¼¾½¿ÁÀÂÃÄÅÆÉÊÍÎÏÐÒÓÕÙØ Ù Þ Ý à â á ä å ê î ï ñ õ öQMeYye Žm¢y¶}(¾‚8ÇŽMÏ–aÛ¦u㲎ëæ÷ÓÃÿëßÿÿÿÿÿÿÿ¬||ÿÿÿÿWbz´´´ÿÿÿ>EºƒtEXtSoftwareGrafx2 ¢Sj}IDATH‰•ÖùSwpêLk=©¥0  1{å¤!†0)‡Ò-µŠEÛJ-Šˆ$ì&»Ínrš›$˜@€(„Š€¶±*ÒV-޶ޭNÏé•ÿ¤û †$°¼_³Ÿyo_Þ÷}wݺ"‘Xé—#™\«H$“kIóèþÜd’¶ý‚ÿóü·_Þ¸ŸH’hªS)„¼§€oîNG?¹;O¦¢µQ†VHá«€û÷>][˜qy‹$A·Õ !Ì]Q|q}vöÖ¬wú§’éøe²cŠÁЮåÅí«3óÓ±;ý8šH‹„aá‡Ùv !Ëš{_ž Ýüóá‘}KI’E þ¯lJ øËT•Ÿ=LZQf.‘!‰½eù5.æžèÜ+—ç£~;Ô0sý\2+º© J·×bòóõµÙ›¡ï4œ"Ù$¡îj… Uû¬)Ï!sÓ7Ï÷s“éV¿ZCÒý&xÜl1õÞûޤH!¯€sÓܘ›úüï§çp5N™Ìv§§Óaîgtxï{Âb*BrLÜ3ÿƒ¨¿N«µŒÅêòúü€x¼.»ÍD“DßÛ\.Oˆew èq_º‹7éï#‹Ãë „ð{ÜN«‰Ö½û·sËÅÙiŒ½‘À¯-§®ž!(“Ãí† |n§­Ÿ!ñ®ŠÒ"1œ•FÓážY@§)ÞhuûBÁðP¡p0às9,FJ«nÛYR*Îdië8M>"'ºµ”Ùé ÃÑá@F¢áßk·t)¸[²Ðz Só{ÕiJ£3:¼þÁÈpl ØhtpÀãd; 'δÀù<Áin<è|°MÝ£ýÐrÎ30fÅ8 b#CA¿Ûa20¤¦½¢p»NOZ}mËD¸ ³—­Ëåc“ŒŒ§òGG#€˜ ŒNs¢Ž³U‚¥I•òµ©JÞí#iÛ®ptôb| K±èù€×a6Ò:õÉWáMR4Md²z_Kq;;)V—/Èä4 SñX4œ"ŒïzSºY$H‘¸¶·©´]­£m ° ¸­#­Ç»îÞ ¦ *¨:¬*=Äf1»<`däqa“F‡B>Ð1¶ËgÏ*6JÄiÂG+›÷·‚iqzý!¶cR+f"6xì =Fq^…t‰À’Úª’×{´”Éêö€–Å.26 ± cë¢HuŸ•ó’\’!¥¨¬®›Ðlv¯/4‰Ž2 ¼Ns?M±ƒ›·–Éåé­ÁGT.|_M2&vòÙÿ?„11†ÒãZúÔz‘¼ri Bãrö±iÌ»×ã Á2Še«9¿R)\šd>‚IJ8Šn6 0nÇ·xÄÀ±¤A½6PÌ—7d†‚—³ë ¡c ›Ãît¥²Ýf‚Ò’„¯sóË5 NæX"†@òã¸VÏî ‹ÙfÄf1€ Òxe+Wѽþl+’6uã:=CúM&@ #ÃèØ²(Ýmqž¬NR´.Ç`‚üŠ–‚¤†6¡†ÒQAQñ·žEkªs÷2È–ò}­§pmîê#µZíTçFžr„“CØ4ÆßT~äxNd\‡Ó íx•uŠ'9û:oýöcý'Îd¯q=øl÷3¼ÊFù2×h’Ÿ×ì:gÈÛи¡h¦¬«(R¤ Š–m~a/™¹’‚GáçwHjTŠ.YA`T°+ï¹Ó¤pCÞNéî†jé2ÒãÀ HÑâôõZ,T(TM2þjw2[›P(–U.’ªšêúf%T¸ H!Kd‹Ÿ µªj Rú°øN0ŒÂ^ªËöi…XãgO*ÖþqµÊ'Ü¿·®GCBªIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/joystick/axis_x.png0000644000175000017500000000426313263212010023253 0ustar aeglosaeglos‰PNG  IHDR22)áxƒPLTE      "!#$&%')(*+-,/.01325477698;:=<>@?@BACCDEFGJIKNMPRQUWXY[Z]\_^`abedgfi h k j l m o n q p r u t s v y x w z { | ~ } € €  ‚  „ ƒ † … ˆ ‡ Š ‰ Œ ‹ Œ  Ž  ‘  ’ “ • ” — – ˜ ˜ ™ › š  œ ž Ÿ ¡   £ ¢ ¤¤ ¥¦¦§¨ª©¬«­®°°¯²±´³µ¶¸·º¹»¼¾½¿ÁÀÂÃÄÅÆÉÊÍÎÏÐÒÓÕÙØ Ù Þ Ý à â á ä å ê î ï ñ õ öÿeYye Žm¢y¶}(¾‚8ÇŽMÏ–aÛ¦u㲎ëæ÷ÓÃÿëßÿÿÿÿÿÿÿ¬||ÿÿÿÿWbz´´´ÿÿÿåqaTtEXtSoftwareGrafx2 ¢SjSIDATH‰Õ•ÛwUÆy—‚–‚,ªZHC&“IÚ¤¦!¶–R{>VÔ"‚ÒÅÂBѦÉ̬d&“{“™$LLÒ4M[RRÒ‚†KKQÀ"ÞÁ*^—Š¿Ä“Þ+å"Oº_ÏüÖ·Ï7û|{Ñ¢ÿQ_é» M »jäóýןžOÄG—áíݵ•Z…øÀWW’‘®ŒÆý¬jÞ__£–«¤›î\»z6vflÐí¸zãæãŸ06TÉa…TtOâ“sCC†<ÉŸnßþýÛK¿øñÖ_ú·É)´yaâÒéÁÑdìò­›ÑCUJ…BüܪÜZzìû¡}J‚d®~xrDþóúÞí½‰XØcl®/ÎYSíûÜ^ŠÀd®R}£Âõ;652Ìã­:Õµ¼ôÀöÙånêe ÝåÜåS'G#㿽^=x®ýX+ '0]óþŠ5yoìÛŠ@ð?˜/Ï ß}SûîHkÓ$e4™Œ‰ëõº#õÐÚŠZÀÌCF’ÃÜø¹–¹`ÖµF3c·96‹•60´å€2G«)–Η9?Ð=ðñ_»Ž :”d,ëaYÖårZÌ޶¼£È-”Âó˜87ÿ«:gÔé)«Ííñú|<ïã8Ö KôuyÎa¥3À´c©r bl,—±,ÖÛïî À0«i Ii”³ˆ¼´p¢íW„"ÑX,í ùyËb6’ÀêÍtjH`X (D1`òÁÿ†Àˆ…Àˆq™£’26--Ԕ̤ "¢ü=m)mq:<œOð¿!À##©Š»ë²KJ3“,åú|m³Ž 2 Ëq^žç½œ'ó,APƒžÏ•hªg‡‚`¹(ó+­NÑV»Óár³¬ÛírØ­‚Ô˜÷ðŠʵù³Ï†x ¤9ˆê +¬–LZ8mv+Cg#L§V‹´Õsã†aùó9ªÚf7PFÚÌ0V†ahÚDQ8h‹Ä/e©+•9‹æ1ˆ<{ƒvç{È0b´ |o¤@’‘$F’ñמ”•—ÍÏe Éá•;ê›P=‚h 0„^¯8ü´¸t›2d D²¼`ïÁF›T¢2zGcû–‰K*µw9¸"^ºn¿ùÐ1=†‚×ÄpÆ_Üò¸¸¤F³ÀºÈXggÕ¹ÛiÃ0=ZÂíá>:g9RZY\p71ÁÈdW¬ÚNÄÏ&¬Kè;?êKúÔey…öKV ÃR™|sÖ’g¯bo=ôÒÚeY›T[ªËT ,¤©B`‘«d¹+—<¶xñâ'žÉUhµµjÉýv2èM¡(R—hÔªBµöÅò²ªºRhí}€ H*+Rª5[ÊÊÊ·n­(SÂy&ï$•" P`©.èÓµþôÆ'äµ-8KIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/graphicsinfo.conf0000644000175000017500000000014613263212010022732 0ustar aeglosaeglosname: Classic Graphics sort_priority: 100 mirrormagic-3.0.0/graphics/gfx_classic/RocksElements.png0000644000175000017500000010767513263214224022723 0ustar aeglosaeglos‰PNG  IHDRàä %ןPLTE™™™wªÿówªÌÿÌfÿ]]]™DL"ª™™nLÌfL333Nÿœ|fùÌÌÿÿÿfÌÌf3nnn™™3ÿÿÿÌLLLÿÿÝ™ffLLÝÝÝfÿf"""L3ˆÿ»»»ÿy;iˆ¡? IDATxœì} {Û¶Ò5iÓ‰%_9ŠGRâ/fZ-Ukë‘ÿÿßöa6` )ï¹}/ÚØ"AZ8ƒÁ`aõ0~xŽñçða<އC8Ÿàÿj\az¨L‚³t?Ü5C¸|8ü÷ÀOx ~|ùÒ‡(ÕƒÁí!óùÐÔþã¡®›v03tDžsÇë5TOHçç«Õ¨ FÓé´ãŠÃÉ]çËûÒ“¶i›ÆýkëÂ%k¸ É_°¬îÿõzRÊò•c ø ~ßèÂkJîo;Ô™Ïu}¸ÅD”Fgäþ޶æ‚>MçË%( (ó¥Q¥+˳N–Ëû¼&È­û ‚A^ë¦qõ¡Æ‹â+¹ üï—&‰ ÖM‹ò¸:c%€µ’4€ÿ ¨Š>€Ü§Šð pÈCxŽW®Ì«ûíi÷á}8ÜÞJ…Ì«°®ñŒFñsR‚J… æø_‚ (IpR@É 8~ÏNŠUq'€Ì@ÿ¡×m›ã¾å á"€ßÎØidË-|ÁudÖ„AÞfÐÚ¬ÌÅðVÂIh*…W„Wwù¿µòôŸÜ6ظ°ƒ9 v"(Ù¢'„ ÇhüÉ3V8zÁÏG-üùÐ÷ €£?‚o ÖpF£æ³( ½­}# ho[S¾Äï¹Q€–€ç_yVÂIÌ? À\Њó‡596µ^ƒF^È«Þà’õåCªi”¡cy€{Q‹nÜmP,ÁB<ÛÏ5šlóY|¬àØO(á À4ëBóƒ÷ùºñ>È–ï=´æh Ï$Ÿë–Jßy†rK§¹½Õ6€ù=°šZÜ+`JI)€øõH ü‹ÔÐs­…Yàu@ÍU0“µ8ñ.ÕdÈÙsHY]N— œ<ôõ(!ôšÚßÛY ˜W¹üã!w˜v²óàVÝ8Æȹ{wѸ|=xŸÏLðÍáp ¦" ®ôœÚàÄü‹¦»}¿Ànš€ù ˆ üŸÝ% h©uGj[¶Àq€§¨ ô“•Zø¶888@òšZt¼uAiýÁK G¼¼1õÇØâ£—‡‚.¼Â8´óbŒÃ7–ÚÞ¿‰ —uëT€$8 ܰ¿ÕïóHÓ @ñïÑn—(@óŸS€Âïîî"PÿÝ:'ˆç é í4˜ÿ࿵ä’L“u{„z€’ |wg @üµ8–\˜k£€!÷è¨Å ºŽ,S?ÐQÜc y{¾Ç/üBCß÷ ÀFÿJñÀ2^I'ùà­ð²>poÙÖïs«Ç? ÂA;+€P¿•”Tû жÏู?ºÁªK.80ÜÁ§Æ ºóÎóÁš ð®6dµ4ì6¨¨op‹ÿ“Ÿ9f¯Í:Vuèë™f@'^ 9Ä+¾Ðß“˜_7Þ/€ý+Ç˸ ®•ÇúÁÈó~üïvIû€ü‹v¶}·ð 8(ŒÀ¸#`ÐJ¿‚@h@ b&mMb2x Õow›x!ƒ®Û rKõÆÝb¢Ì ÿõ:¸‰ùÙË£þ=`‡p^%¨B½ª¥ÿ2ìÀ¢3½8F@‡%”&ý¨Ykmß5û£ÑnO8 €R@̬€ƒ†D$;rÄ5¥( ìUw}-~ý*> ¤@v J‡ƒîkµ Ãác@×´`#ÖØ° £î½»jõÑïÇ‘!× ¬ºñàÛI°W{zÃ^\œv4[™ÏBgw<°ŒSš€¼F«DÎÍë<ïÏ#Ó ؉BË’ >hú•PwØÁçîÍ<ÔOnÈÉFÿ8’­‡fý„–ùm¥ÿ9’Yw·oɰ &b,^â˜ê3Ul ù£¡¢ª<ôð|Ó.! ‡ ìÀûœ¸:ŽþÕÉ™N\ `ÉXŒV+Í?±Ô£ö«ó<ÿ,]à?#GðÁÐo¸£~9þ9«¢6@l4¬äÍ`”½¬á¢ r@=¾' ¶ž}òàT‹:"'Á)ŒZtùÁKa§ù®ºpp½Y· £ï§ƒ@yü8Ô6%ñÀ2ÎA`@ðµFdÄôï„TÀ~µ* °;Iù7 8;뀓€tù°NcˆßÕQGÒšjºsãÛ–Û°z= p? 5"A®Š×¬Üàð5( nòñ>úƉ ò¹{“§ ]a‰ì’°³G±2ïÔO(áQ¨Ðï0´üã>¼4@5éÏ€R@åùgLQ+Àh¤èeìFF†PÀîî¤['ݸk9BKÍ::{- «¾^S\F…Ì5]€^‚ãò@æ~ Cj ö@›!šáÑbwÛúÀyœ`'„<®džH7^Ah÷‹÷Ç c¨ïh^J¬@Ý ÿ"ÀÈ’»gTF‘œ*¯€œîþ¸;9éÀl Ñ±kˆ!°Ñƒ–Môé„–œ\}ì LBG¡¢¾5- $R_²ø):è6`(?E‚©“AŒÿ`庪N\ƾ@2ÿ&ðÛ÷ @Gøù¤9ÓÓ00 wÁDôÿ Àª(€ÀýIÌ¿Ýýñÿ?) à?*6Ø®i©6§ï`d/¨ý8ÆõÑJ¸Ø›…Å(ȃŽÌâæ¾,á” Š¯+õr©…—ÅÀ)x%=¼Ðº‡î–ð>$ñÿôL'4Š~Ö·®þW‡êp[ ÿàdOsü+h$üï÷•( ðûGøýIV7ìâÕÂ0èh°ÙÃcÛ ¸ÝÞïƒ: á Àä Ä;`íPèðÀÓ€h" Ð 1:0l£ZÆAq É0šÂ^ Ù8=¡ˆ?&jr3j Ðhc+ ¢îÜ{÷ØÌÙÆ‹Љ+ãóC¼ßþtãGZÁ #eœKùVµ%Ð7ºUÓ¦a†‡å_. ¬Î û‘î»øçK@B?ó_­¥9HÛ>hüì=¢È»"lqÔ†2'Œ\} $±F“ÅÆÔ<´–^0æ:Š£;ÔÃóÌ/ŒùWUN‘@™ôó¦~¾´þÃ>üˆ8€Æ“€>Üó:Ðï¼åZM ÿ^–_QÀt¿ÏòŸ11ÿ¢€û¦ÿ xp^lüÀtùðR€óifÍññã¹Í$ÿ‘e²Ö @¤')ó…×ò0Diš…ù†<ùƒfüP¨êÄ«JwýHïÃÐl'ðG àÈ€p$-IŠœiVê‚ÏÙåùO`¶ ˆù¯Öâß­©îrÝêy{àç± ¾É’×2äK&b`¬%:4à~ÅZç¥vòiö×Ïø@½€"N`6%Âÿ ¾¿?Ñ?NÅ£"îK¡ÌU©9>9þQÓ‚àé{øyÄüã„ÏÆ¯ÙYK}f¬ Z²\¤Ž¼=u|ÝÊT? øEËF8lä팚ì§÷ÙÇ£pŸL WÝxeÛúàêûN_~¼ÒÁ™ø_‚ë‚.Ðo$À,GðhUòr ÈòÏ Hø' H·~½–.Ÿ]Ý3YSüW&Aî!Ó]iŒÇ® [{@ãN:'Åù†ìâQئټ ñŠp˜$B¸;ñE‡zÄÝSƒA=xi@&="þŽlAè' ìD)½UÒCÈЫ#¼ÙtÇHòÚá?¡Ÿ®!apUø‡/×â€"Z÷(/Í/à¬ðXÜÁçYŸä“ËÇFž–ã2A—¯x.)~¥­W솾`ïˆá¼HÊS‘O<ÄŸa·ªxpp—·¼Jü£ Öa‚ö}=áÎ@v‘ïd=°q<Œë²Y©w¹â|ĉôæ‚K@Q]E ƒ]í—¨éûòÀ3 ¿Ã>üw›»”Dù+d®g‘¸¤¬°òà½çÙ§K&ÜÃËÓ<)çõw.Ý{ÑðýlŽö³ø’Ùçϳø¤¤ÑÊå—Ü«Õh—dÿ]ÓEWêÇ'77ã1Zï‰?{ói mÐK¦¸œJÊÕÕZóâß\§Ùêü|5Bó‰Ž,…70²saÎÉާÛÜéwJÀ¥Oäž Ý§OtøÇo<|Q¹ÓcгÖx NŒÉ q×ÃÍi±¸Ìü%L?>'ÆÆQ¼dšáXÇjEîèh´¯|…ŸÍ.\{p Ä…²$€ÙÅh•ävGÿ €úм~‡ô×W<õé†ê3,˜þ}yù 5p³æµÝNŸXFÈ?vk¼û% ý7îÿTÂÎ ]‚hd»ŸÀr s#ð <-ý9\aí<À= …cVD°9ƒ0ÎXލŒJ;àÎ`5”£ÇNwãáÅg—°öŸž^]¡À |¦4séóÅðjur«{ï@‰tI`³™Ï»$í’Àýý¯_y ÿžyœ@7XÝ//Iº¼´lð[47ìÞ¢`é>$á?Qò? íLP’JÔ† ÂÛÄ{ˆíÀùp˜WÀl„k¡yHÔ À‹!Ìétì»t:> ^¼ò¯8æ…{íUÀuw´aNJ¸,ç-áŽ~LèøOÙÇ„úSòY7kU"ìÜ`À–buþá+\ù[ n¬¸Ï•­Ü^cžŸ]*,¤åð<»Ò H“!Q¡Ÿ@8pîªÿ|à”[ÉSn°e¸­tnu¯ãpí 4o|¥,|5YÎ]ØßIøÿõ!Å.Êü;8 ˜­üAŸ†;W…E ®Ç5¶4^ïù‡¡jmÂ× xˆ0ƹ×XÅÕ_T1&m ûü»ÛÐÔ÷´”f®ÝžªñÐý>ŒŠì¿^Õ`ÿ¯˜t¦_™Ž|îè^å?I¥wß<<%@B»jÀBH‚FxW¶üÓD×ÿHAƈˆHPɨ}'M?NÊ•æ¡Ä> i¨ö@ŠŒÀž(÷œ…×~ÿɱŽ-?9¡þ_± ðÓ_*ˆÝ«ðW™t­Ê6‡oBÌ*Àó_P€ç?§€ €ð‘4Y\æТ üß`‡.¨?F!Ià1ýg‹Ý¯ <_ðÜ6ƒòÓóŸn´ßGQN¸ÓcUå…Bܯ»½Îmï•c$J×T˜Ý 7­,€Ñ¨[>'ì (\D@Пb'1XüÝ6ŸØ 8,®;@ß7Ë?ÎÇÄ„î=™ŸÈ*Pðaèë?le¿%«€ZãW•}Ĺ?ÂÌ3xB¿x„>}29¢{å97‰¢ë.lý¯4q»–iÞ(Ýó÷ÝØ€ØFÁ L š¸´ö¼? }ZÄ^à¢SÖ¨ZÎ'ýLJPÿ—f³S¹¶ÿÑ8SÏÞw¦1{%Q@  ”rŒØä‰/(À_P€'¾ O|V"€ÍÜ ôE€xá#ˆª-pò¤òü+7ÀÃqLjP@¨ÿÖÍ“óÃóT~@c¯œ>©ÀÓ0MÚ+à4Яù‡ÏjN½ÜAVZý÷â ¾ ˜kˆ„3Õ&> Ðç¶uøir‘ë*À÷—Àn :u¾UCQ€4 Ò[]úM awÏd¤°ý `Šaì»!{Ó7ªxFØf œÆÕÿêt…±ÿ‘ºÃNÎ5 b"ù ùÆÓ¾) `ÒéÞÓ~ŸÀ–èßøF@Œ[€K¢ÿúZl@° †áy¤FQ ƒvˆüº9Jyþ}?@Á”»r­`WŽÊ÷û¼t+¿£Ý>¤``•¬D5ËŸ®‚pgѧÞë7iäóÇ£xüHD!óDH”OóDv1÷*À¯{~$½¶C@Úp˜ð^ÀzËü1 €s6ŠXä,@"ÝèämÚ0ĹZ¾¸!W`p„Šüsà靨ÂïPãŠê?w*Eò×4ú¬–ñû0«a? lé‘9“0ž @ñ¯îÀÇ¿½>‘¦óÍj³1¦€ð)t®¯)€Š~A{øC3ÞòïO r.†‚'Ï€ÄøaâÖko"ür£qÌÛÛìikÈÃ*Ùƒ6¿ÀÞä~ØS±|¦_+µw¦Œ%„Å6€øØü3€øèü3/ö_ñÏD aXà àFBÁN¾‰Q¸Qü_KÅ€±œŸ‡,¡œXc àÓ K‹Ç@üÄÑ ÉÛI›à‚p ÐüÂÞ(ÙÃlBm`ø±üp¦OÓ‘æ? x‚Âïë¬ÂïMVá÷yVá÷½€8"€ `(ð¼i‡—˵sý˜ÀÍzx3†i%íK@£ŽÁ1°'Çø¥x¾5ìu³y‚w' 0–0ì¼Vqöv]ŒŠåÓ™>Ä×Û;ìŽ@Ô LuDÝÀDQ7ÐàSðùM°©®.®ã@Î`ÀF`°.Àó)mü¨FSw]kÁQ8^;OÃ&ÀJ ±; H¸Ž,Àΰbù|&˺êªüévO€ûtéæâü½)  :Çßç%¸Oä' `'lP—Z†ÂËËa ä¡a?tsQ €ãÀµÝçyàH°?†‡ü“ Pï€à b÷q,Ϥ~ÿPÏ0¾>ºÃÓBÁF™P°@&l kÜ `$àÚ 8¯jœ“H3Y< ÄÇÎ…ÈO9J´?Kå;z¬¯€(ÀGï†bwÀp @þí#÷ûLÏO€¡¡øz{‡ãƒ¸NÉ©Ë𓜮“Œo¶á'9ÿÜõdü|~’ó¯ƒî?ÈOå&  ÈOêB@IÀâ@Õef:˜nÊ @þ¼8TÖ`\… î³CË;*Á1~D=ò„%Ìß=Pµ0F8îˬT¿/+ÕïË ÀŽq¥°ÃÁy¬´ýpà`=@øéšˆ „yñ0¬„¿Áx j @QÁÖ¬. š¢‹á{Ùß•F ‡c§€‡i°§^„´Ù©è°V;œnÆBkt„rBêgnBÈ\ýÌMY©Ÿ¹ !¿äçÅÍW ýjú¥¨°0}@ú{]/€–¡©f'…¸ܫ٠àra•€’„‰ŽvñÄ p—îà’M!‘N 6â–+‚+kâØïJõþñùýš†`<>õ‘5 Çþ 0¶ Pöæë'#€„ÄËO(€:Lñ Aí&Pç§”þ}Ά«aø©q,¤Ùa®%`9øì˜?'€ÀHÏx¾ŸéŸ·¾p:eÖ¨±cлdF)áò·—p@‚áÜ0+Ð à/\pó-°€o7kšžŒè}„YÁ9(þ³ üó6]Šÿ*Âéåž2g€¯!P¦Œ8 µÆEV2ø§,€çÃçþQa,@„±'6AÜOH’ î·-Ì„D[}–qˆû}ÈÌ„uŸ†_ÿú+2Cýÿë+®ör^`aVø·ò>¿XŸh£§‰ÿz ýúë& ˆø}ÌÓoï LóÌpßAxð0nôç0ô‹ß÷á2 ã¿Ï?j,`ª"ÿv$áØ±€ŠË¨ï¢RýòôÓÊ OŸ¾þ•¬ ØþµÛóR¿›o7ßҙ߀× hü~݃0-œâ‚"€ÊÎ"¸Œù×½y¦/ðOƒ¾"ìõUÔC”¬t•±Q~Üßc:}‘6ý€š‡}ˆý‡Í²xjøq0k ôÈ‘¡à÷M¤€Oje 7üõ—çÖ¹3ˆDñ÷·?ºö/r³Ò`?æ2IÑߺó¡r*UÿÉ›“üUÈomÈÃŒ!ÀbŸ‡ Óe,@±ÆñüãÆ’5†ÿÿ \Ðô-]¿~º™ÿ„_|#Þ¾aƒìþü±ßãqp£Ò§¶iÕVdU'ýTR§é5Ý)΋Bx÷†|~0~P÷Ÿª Èбü8žÿ˜±ï1cïœÊK¿ÕOIŸ?ã?øÉY'´ã %})l÷­Öï`S†þcð‡NÎA´V,ʳIM,?ŽçïÊÞÁ~—É÷ˆ±€5o“;m]´ßi»æ=sþ‡¿*^E±ü8ž¿¿R @ûþ\¼ ¾WŸhiõ •—¡4ê8¸]þÿðWÅ«”4χyá2Tó懇ü:_~, ׯi [|ù ½çÒÉ»òÖÿÃ_ï ëõ€RûyYèG Ð},+Ú³ÅWàð óZö«×ÿÃ_Ç}$v/U˜ŽY¼ü9, 9å­‡¸`pªFFC Aq˜%€÷=_ëN6¿¹ ®sçp=0‡ëÉ€9\ï9ø¸îBäp)±>®èÆý§Píe_<«ß¯ þ;!˜Nåó”—ãE£*¬ ÆÒ@›ø¼KúÚ†Yèuz ¼õŠq›;ÅítзÓASÜl:Y¿=~cRН=û]¸WHî®z<]°Kbû™þœ8×£³ÈDZY¼QnËök ·óþökÁ9P¿‘p}Œ¯xI€|›w¤ã&~øÓÄxÍï¯åí³oŒË`"þt1®Ø/âžÿaü=¡`».Àî4¢M%[ù½€¦!ê?µ£&²¸+òÏ }¶­kc´þ-*„‡éš$€—%!"€gþ½b¼–WM0AoK QãÌ.üAEœ®ðxµ7³øÃ¬~=&à±QØ (Œ!MõÞ@ÿ$€Àxø) À>©*ΰðÉO¥wŸŽ34¼Rçy¤8à—@ŠAµ'èíq¬Ø^)ÎÌvàž]@‡ú¯q °£6¶a™¨ºžÀ„‚»€oºrjŒPãÖÏíZðX1 ÆcÄxLÐ[ã±b<@Š{ûp/Áy,ÀŽØØ~„å¢þéz-€yI z;BÓX,¼þDp+€ù<Æ­V«·øõ+Æ-AÔyzKÜ àæ&Æ­r¸·ÿxA =Þ±.€F)f‘ü(€ }àДÀ5ø´ÿ½àFð,np>€ÅîÀ°¸!耯â{SÜÛh‹dqqïè‚<Î×(¼¼. |Gýs£Ñ`"€9ö 10Nà5DÐyY nœÀ D,nœÀsˆXÜ8w °¸qÒÐS[Ü8CèÉ[œZ÷.Ü ûk<Þµ. |‡|“° 耼%½1ÙÐë# IDATÞ€&>€@ŒÇˆñX1ôÖx,€âVy<@p³¾æ—,’‘Àn4õz@>@X€‡Àw~ÀßN8\–o9Døjå÷ÀiŒÿ’@jÀ ÂEÀ6ÒoŠëݨ‘àç^`.}º ‡~¢àý ž™næÜ€n‹šñxl@o»lZ…dp#€ nÁ Aï€Ä8nÓ…C{C’Çé‹v~> Åcjfó(‚=§`ø¦c×FáÌÜm´Q µa ÈãAy< ‚ÞǸ#nËp$wÌŽd§NùVá)@íêF8ð«bý+3F¬%ØÒsÌsn0Èû` ÇÕv»ÕM€jÃ<®›€®›€®›€®Mô{ຠˆp˜¶Ývá(b7ò㸻`¶ÏÌæç cSµ3¿b”žÛ§í¾õðyÎ+Ûð`Õ@áÖHq뤸õRܶÑo[ ÂqÝÇMŽð"ÊãÜܼÂÍ¢“Ùüa¯ ä8ÞHåX%ç`³èPß0§8ŒK¥> c)<ò<ò<ò@Œ‡&€Úø®}ÂáLf6¼ÓOvŒ ^K0Rç8>¸¯ª¬ÂY~©á`1†å—Ê€(6Žf>ÃfŽÊˆðÕFª”á¿Æ®ðKù^—^‚Þ¿KÛøwÞûø&8ù=ü1_QÀ©ˆ>ã$€d61ÖŸÅ9Ì9/€y¥$ OÒ+Ñ!°¸Ö€6ªm¹ÛB`¾Ñˆñ•„• ñ_ T>€Æ}°^µÑo‰ßH(Pµñça^æpé†~~Š^aÌæ/Åú3GÓò9y]€g]»¢|Jè X°ŸêÜW= 7p‰ñUˆŸû8€Â…8ð(¼qڃ刺!~âÀCßÏWxJp"× ‹Ë5ÇSñÚ€B¬”GÕ¹è.òºˆy¢€p†F%y>€@Ë3™ã±b<@ŒÇ½5 Æc¤¸@OÍvÓ˜Ír¬?ù/³|Ïs‡ª€vBZ®Áz"x¾y¼^¤ $e1@øâZ·±r÷PÓnMúñóg³§>6{Êó!!­[”‘ÅS"G& ô{ܦÍO^‡û'W”ïûIʧ•„hâ6K¯ær‹`dqíoBÕµnâò¯Û˜äù(€'=6{Âó!m«­)ÿ˜Š«ªÂ³ÍCÀó•øº*êCîÙËþ“ÍÃAÊg ©i"¤ Ý¥‹EÃ%˜kã[4D€.á<öùN/üüŠù)VÀO©PxÖAôx–Å¥Ê_bñºêj 8ÛÓ,D¡l²mèbÕR~qžMš,·xÜóg.½ìó«*­àqŠñذxÆ=<òþe;óS¶¢ƒÑ“ºð” Õ¤m¨;¸¾v¥70ŧø1Ùñ’ÞŸ\7yP·?þùÈÿK>ŸÊ±À¥Ò·xÜalþÇáð¤îüøÂ‰N¼¬€>Z"eˆ „ò¯Å‰j5Ù=Dåò¶tDwzïçãñþå‹(ÅðÈüÂÝúó÷ã À øÁ—{}ÀúÖÔªØÜ§ÅŠm±h•fÿ /ôÙ=…–€@K*€cž?›A.çê½àó¡øãíÿ]g‹è½ñêùøÍÿåðƒøW¡"a7€Î3A08鮸¾†b»¾Æ*D–L 0æ:¡êÖ‡Ç @?»æùpæP@V¼Ê<ßÁ>àjüà ù9‚Þ_V×=ù«gáT,ÊU¢~ 8LT€Ðò»‡ŠíséØð@C/Pî (8”ǼHæùL·Ê-ü|ôÌóA~>2 r‘/ÂßßT×=ù]ø¡ÖåïCi htZ<0Q8aÀÐø@L,€ôù³Ç>öÄçc›ø´ß_>ûþUN^ríM'GÁ €7ÕO ønPûmïy¤’çÏÀ <æù³( xôó©¡z„·Ú$Eøžø¦7ÿ²÷þ‹ËELgˆ‚p‹Å¾ÐÌÅu¤{)€äù(€Ç<G}>•9P¥"üïÇoÊ8–Ë@J͇ÒÌG?\â‹( ÇÛ#Lxöù³Ç>öÄçsa)_„ÿjœœ¨ApŸ¨À'ú¨Aë‹;ô|¸íX'Ò<jÿSžzñó;œHo!™"Òôߊsçh L'v1…n”\×è^@+áÖc»‘æùØÁ{ÂóC/ ~~G7’Jh E‘/Á1.Å:øæ“ЇÜú €LE!ÎÙC<è$½Ýós$*!kÑÑ1Šu@èâsåÓJUí·ÏF[}¡Ü÷~~wUÿ~Ü ÆØÁÔÖÖv¦„öÛfgz“Þøù™Á¤Ž"ºü?€ë±3›¨|ŽNU\Ï-2ÃÉoûüìpr¾ˆ¾¥/8üwâ”^J“ò9bB…g ºEão!ÿÌ„’·}~vBI¶ˆ²Ã*ÿF\¢0vN`~ºEiJ3Í Œï‘ŸÒ•<6{êóãhàQÏ/Qþ7âÒå6s “¶K“*éÑœÀ®‰ßIÞhNà“žE|~©ˆþïàÌ€¥å¦\ÆÉ\ý1ËÞ#7­û½ŸŸ/¢âŽÿ…xâEe']w•ÿ±÷È/ìxïçg‹èÿâpùú‘2.ÐD·ÈÞ£°´ë½Ÿÿ¿äƒ(J‰ñFµÑmIîуÀÝ+,î|ïçÿ/Uúð#.ÉàÍs2¿öóŸì´ítuQþéëEñjHÚën½¶oÂtg.0ñÑÅdò¸aRùåÂþ–4¿r?N\º¿w6óô ¼‘jZ2~(íT—æÒ!ËÂ]Óççž«žŸëžÿ"iÛq„g¶æ ¹àë¶ ØVóo›µ_ѾvÆÌ2|1]qyÛà 'úQ X\_‹D ‹h¡ÁÆ1¥ïJ’+ éRO Ì ôJwMŸŸ{.ÿv¿®SŸTÚö0ì·~Úê‡sÛí<Éÿ×|»%Ôõøëv{cÐõz¼mh£“ ôuþªŒ› \§u p·XÈM¼) ܃¯¤lTvÉ£Äð;ºÄú  •¿ (‡Z·¸¶°8Uß”x¶> ÷ kÀg’çëä.¹äK/Õ×1)}~ÎÚ”“¡,­Áf󝼿|ÇŠÿåïÙÔN óÝ"8‚·Í–wµƒÙnÛ­%q2À!‚&ƒ^Ì;˜ÄO˜°}p:jPÈÂ-Êèw|Éf.UˆÊA…]iÂ{B†à''ggŽ»Dù\tÀø"÷|Â_-ß#ÃòüÈÚX#篌UÎ1Œíí“wwÙÎçqVÑËN`O£¶†mæÛO »óî°LÖD?˜wþd¦Õ¾^·¸?~Û:5@sàp/£õr;O .uJ2úÒFu¿PƒN˜8’Qmx S¨à°3”¿cà>£€Ê›cB‹@gîùéßo„ýý™çÃ49}q>VŸmBVÇác oææÊu¼óÛ²Þyû ¯DrG¯ƒ] ÷•Ú÷‰³úŽuç¬]ov ÀI]ã6ck|E.оv·À·¤4&þ.x™;g¡]¯#´ÂiSŒ%xâ›a)âËE4qaë ÕÊEurv{¦«à‚å‘ËCd#k€çãçÛDÈx òœøù¤/+“­nÆÓ´ÙÈŠÀ¹j· çü¦‚³]ÁмoÑø'Ç®:]Ä{Ûlñ:gÆë¯ëêÓ÷Ú^0 °Xj»­ëÚ™L®.ÃàÖðZøÄ/FŸ€>hP˜«ø pð_¥%àJøÄ$5›ˆK‰jÐÙ‰´¤¦´±æÚ;X³îîFù½@RõÝo›;r'œ“ç‡?­óÀ%`„Òç§n¢÷½ »„ˆˆ¿D-æÞ좀wC °qÂC°ñr ( Þà°Èÿܹõ¶º¹ø´¥ú¾và;Š'Ð/°®[ã_-ë£K5€;&«RÒm€« \@\L'Þ\rE¡$Uðþ.²±‹ëø ‹Rö@À/ Ø;éó£»/âç³iñþBúüÐ]ûìêù¹n"{g‰&‚ |L¦9k`Î ØxS€ù°JS×`¶}C¿<>v >h`NÔ³¨·@÷WèòmÁíwüÏD`—ex¯{ËhñÝ5TÀ %Ð ×ÜPà?'z îÓÄKà ïöÌà ðM ®º*ç¹–ò#±—ï O³BÀݯ`ñ»Ÿ/ ŠžMÎEÿóh2ÏÏ$h‡Sþ¥–39°k¯Ó9g°æÒPÈîQô®Ÿíf¹Æ1\pƒ˜ã[¼Ü¯zûÉñ_ ÀäSµvíC®&s¿f€ï0À‹Hmà 'ÑQßÿz›²ñÒ£¤Î7v–B 7JÊï (Üá>@`C+ çùæáù ê`ö>Ÿˆìó-ÇTI‘$$8yÉQ 8nët‚ú7û:‚y?gßH0«Ë "KÄÐ ìj;ÂÄüáp@ëès\¢×·mÑ*lñzt\;P¡{€og÷î,(€ì€+?8ÿüÑP K:9É–•*_ƒ¼­½kï«„›jÐÕ|åç““¾U€ Èølü_‚Ø… c·!zÿK¾,àl7ß,YGòpü  úçá' €ý~lý†´ôîpŒ 2ù5’ï'׸¼n±›0àa’–´@O¿?IÊNÊ*ô·C ¨`WóôÚWëÀïð|- èÃʘÂ[©ßð)ÔøÇY—„ã5F<(´t‘ØHµë’ ÀÊÀÿæ@4ûyMƒž¢ãû[òë-Õá¨ÛO}÷== ·Tù± F€úˆÜS3<U¡/©{ßýpÕ][­¤¤ ´(VxwR`à„X„N\$°àxUZú'÷*dã]¸ŒúŸOmxú|ê)óü¼l7`øGú ÝÀн‡¥Pl7‘ÃeŽÆŸëÿâ“mí8?ÌqFëùw ð#:ëõ|¤’ë;¢GBíÂèš̘ñC©ý ®iTôJ9G•áÉ‚;þ¤"û÷pщ){ꨩ¨ûuÁ@Ý>æùUþù‹ãž¹(X€(ŒM|‡4ž Àµ©âpA”ÛeH38Y³€µÿpض`êkqÓp%¹5u]g,µ`#Z6ÿ¤€A‹“­ÃxÁD€8` ¸»Ã´‰ŠÊ•áý X,.Ý ›_> Â8Y@ìþ¢C€Ç<q]ðÒH€o(f“$ƒ¡¯¤£@=Q¬àÞ?!Ϋq'u³×[ò@è  ð&Žq=Âù¼üÙm1.PŠ&€WM’°&þ[ŠS0íÆ„†ÈïmB ÈØÞŸ˜<9I ð¯Ò5O•¾K–À3Ó„ýÏW:9IÔÿük+€ð|pL0Ñ7Ïòð6ó[急ï¨p:ÒàŒ¼¸žs@?HÍ'$zyÌ? ÀQ;n0.Ìn`ã=î8·#„Tÿ±û‡äC#€ÿ+èä9À’‚ÙÊ„ª&XL(ÒtoÍ®J¿¬ p è¾jBÌó© 9æùe#°õ9êÂÏçVsnÇ¥Ÿ¸±ÍñõŸTÄ·@'p3'y°6\Ë)÷W H@=æ `„ˆÚæ—b¿ÂÀÜ„!¡ ãìÒï5¡I‘1 RRôä ÂÃãû“léß…zš!€œ¸cžoâ€êÎÇ=_;±VÊ  ÈìœAüj/¥ )œ;ò[oŒ6V ÐÏŸûNÂ’¯™oY“­¼ˆ[€-Y€9EШéUq"€-E‡|÷hèP€ ‚£€‘ Að0 $ãYî¸<¥¯æ½¬PÊÒ²·ÁhÏ¥€ Æ“‚Žyþ"÷üêÈçën¬~~2!dë£qð»Š[ ךœÛy ž[‹oC”€ñ¹×Ï·‰A ÀäÃ^ÇëC5…þ¤¥ßâkãjŒO`$0°ªC‘À l8ü3àOØð˜¥àî. j$0R6ó»Bõ‹ð[<ß*˜E‚íüÀv"õFxÖ+ uU#±D'1x[vI$ðõ›koCCÀÛ­¸y®iØâ{ã ð°¼@üã;sÁIœ@ü-€OQa,1p÷ ãì*”š%`3¿‚ ÛYþ!”l°Çzžß%°áÏ~¾aJF’¡ÂV†} îLJBCPÁñ<Àb©üi¤eáÛpc¥1^õµ£ü3UPszŸ²'χ?­ÿù<˜??Ë?ìææûT4è³­’ BØØmô–Ò(«-ºþ !ü‰²­½(ÜP/¿á@M £AØÀ ·ïŒþú1€†‚2d‚ßøhõʼláa ]ÍÕpjV¯/ß’‰šáÜþç£rϧáàÞç›áìðüt:ÑÏC¸}à€?O÷ÒS~ü§óõ¡»MÕ ÕŸs'OÒ,Ñ9N©a*è–…) À“9°qo±ÞÇìþ9¸®Ÿ8x°äqд5,Šô-@ヽØ`+@ŠÄoR\üŠ /”L¨ˆ-pT‚×ñÌFu:˜Œ,þ2:éóíŸw>ßL(qW$Ï' Lh±ÏÏLz”Y­Ç©^ss±\ÈsA)\hq±)[§œ fžq×Õs•½­qšE‘ÿOd£¡§W;kŽÔ×ãÙoB w=iqÜj=®ŠÅ±` ¸˜L(ú Å‚'vJص}¯h˜’¦T¢)Uî {‡…EeR¦é©—[ôå¾Î=ßN)[TöáÖzJ›z~Æló-¿çß:~™ è+ ¾;–ÔÔo}˜L[è…?û¼2ºzk¬yKUh.¶cì™`ˆ'òY5 Ÿ§HžÈT°µŸL¨‹¸8)3LªŒ\0;©²8)Óß׌ÑÄ-pyRj˜Tþ»ú&¥ú??5ù‰€>©À^® àß$€¸#é½~š €iýéëö¯9Eü)è?Tmô„ËÞan.x©ÇÌ÷ja5@=g`Ša ÓBÕ&k’G¨—ôMˆ$ã«^fZu÷´l‰ÞŸDá…*sy4-=L+Ož/—wNK)~~~•b „—^,‡?7A)ÙÕ€ÛŠ©^2x3†ë/\ß­Æ‘àj{ó)tÐPÍu}@ì ~T~©Ø„{úàÜC@¦ žúiÍӃ՜о…œîÓòx×ÂŒcvt-Lá[ežoðÎo’{þâºk…$å&‚§˜NDK °°7 ¾ ŽH4•ëâÝ|ÒpÓÂÈÿ„Fˆ„·ßºÚ=A§ê7Œ‚õ_çˆ`®¸ó ™¾¥Y’´‡ã]K³ŽYÚÕµ4MhJŸoñÈ€UÑò°âÒ¶—O=mIÞ‚ø“7Yæõâìþµ_"fÒæ~Opò7Б¹E9õ-Îää‹?íC{»»_ºtá£ZÜù+YÜyÄâÔîçÇGü9÷üŽoúÌÔ#€^dÏ®yòxƒéâNŠ÷ãô ‰“Çã‡÷.Ïö©XüÝ˳íòn߉&T±<½ûùñߟ팟äù[úîé»? ñÉ,H 2ú¿4>Å4~k¼“O9º×¸Ïä“YÐ_QFÿ¯'ÇÎ%GÑðMñ;Ã.¥?îí H­€<‰Ï@4ÈýèÔ—ÿðêµî?v ¾*þGªàßœêŸî`¸[\:Û¨ƒztêËÿ2xõ:÷·ü¤ ¾2ž( á_+ Äá³ÀST|*Ü¢˜úò¿^½Æý?··³™Ð3›ÝÞ†^áÿ• «ÇSЗÿÅðê5îõ3%h|óVx) ÇP@‘ág€«~ΕPæ½å—ê©nÃK ¿êÌ_þû;ŸÛg²Ñ®ŠÞ¼ ŽI) Ï¿z¼"ÊßB—+¿8K|ñ·¬ Ï•W@>V¿yüñÏÞ¹$"HŒt†¿Å™»@pÁÄãOvòʸ.ŸªJÆ)·Yè¼q çË¿€«›äñbþøñÇ>ì)inooÝ¿$ªè8ÃßÕ âž§€Ñh:-ñ ¼,À»Ç÷(jA•}åW1ÉS"8[þ%<¹ÿOìóO™×JCC" € UÑÔ@X‘«àÁC€ én·ËøJxOû\©öSö²b —Êÿ)xe½ÈýO=ÿŽ}úw{ ŽoÙBÜ6§9»µifª ™¡aq+ÛÆ€ø™Ï¯ ø ícþ^ ("5²À)] (P• ¬Â¿ôùáÆ!¿Êp¼|~rÊïSºÄ#€çâFô¯ùMsš/À*í,æðTú¿còãF}üßž¯䉮‹Á}øŒðYGÚ:ðŸ¶0 ÈDïc_ ’¶Ï@U€®ÎÇ=3ß–lÀѸåL‹¸‘O›šœ!˜Ú÷o!nb5døü½íŒ$‰“¶×ü½*þ¨& Gž{›'¶áOËŸiBŠ` ÖÇÃߊ `œÀ¨…ñœ¨úŠ  ¯‰?Æ ÌÐÁB€\T/þyNÜsȱTÑ@0ÆÜ¼QÀ&Âs[<é Q„%ô½&þˆn`¶€;ø»aþ2Ý|ánbžöb$:zÒÉ‹Aq'¯èyÒŠ ʰ÷šøÑ lù†TÂûI/(êÃ3¤ñiê‘0$U¸dÁÓ*þ8üÕ îà — ˜S/é¥ÇÝÿµCÉCŒíS,§ñ#co¡·ô½ NÜ@2‘:kÅ_ªŽã¿0鑃EÏÂsƒI4Y×Vñ±ª ‚k;ð’x%Ý4å¤e»q¯…ç ð±è% ª’ËßC¹áäá8ë¡û úÚ8vYL4ic_šôÝø&}IRŒ÷å)<;ad8§ô(~^w)!(îÇ¿.Þ=açð*I/{ÿcñ”2ÇÐ8¢ÇðóÚ8§Õhê~NKÃù¯‰÷xÏÆûÒk??U€Åo†ã(Y~^§´á¯i™À×Ã{¢AÏÆûÒk??V@Œß EØŸ×Æ!Q-WáWÆçÅ÷x_zíçÏÿ9ÜQ4vrô¼6þî(ÌôzA¼/½öó…ÿâ•Øyu|%ÉâVÓ IDATü C)E¯ÿ/½sr.z7¯Œÿ/9gÓÛâ{ì‘áϽOòñ)_#Ÿö{‰ÿØ›îG ˆ­ÎÏÏ™ «f3ºn¶ßÉ9¾`'‰qÌ?Ò äÚÝn:Õ8G¡v:ígpÁdêrï¦t¸¿÷d6£ìfŽ/ðeð)>oªò÷•çËý§ãü³˜à¢e8|%ÿÔÝžéIÿÌ#éÅ[áWÎeÙÓ½!,wЊœ ü9@9þr8þ™Y|4•áþ›í„©ð·gwBàd2Av&HÓG‡¿0O­ÀöSun?´ßÑßù½ˆÐQ)|5œÊÃW€”—WfX·,¢e—S ~c,¡UPc»‡‡AàwF‚Ùc Îv?ƒO‰ÁÙ(Âå‡î!„ËÕyÇ ^ˆ €éNtüºkPXE}ñ18›Fx0@ë$\¦@PŸP‰“„Ÿ± Ö£‘º×çáñš•LàÆ¿1Შ lG¢I/ÚM=/P…é*,‘"â:JíÐ^# N=Ž Ø+Χ#ó@8Ar^² ¨‘š¨îÒ„9Úc† 8Õ ‡ÂQ]ç§æ#üý„“ø&±ù“©”înêùa^èßi´j#྿Î$BÀÏ™‘Ý}q¬wOu`šiæÉx ˆßž ùõ7ßO©µp°òÐ8\°3ùCù³1b¤•ŹÙX¸ŸšýÝ^*äˆÐX.Ø›üÞ¼qß¹F?U‹?cá~j~' €p”ðG>\ ‹kĘNµR”Fû÷»â)òóÿ8Ä&°i–ÿù ®ëjíñÙ~Êuxó¿'¸Ž»oÞ›øe^»,ÿla\ ×ÕÚã³ÉŽëð.æ‚íŠÔqW(®âG˜M¦VÄ2Æ-œÔ …û݆yÜ·ë}øoƸ™>Œ«òtŸR$Cn¤ÔŠ$ð?ñI%SÍß>ˆ‰ü]ßïTƒ¿cž[yt¿g{oP.¢ªŸÓÕ¹ÈÃô „`lâ©ÁßgñÉ^5øû}hó¡QÀ–câmÊE€NàDX—kø 7ÄY`Pø;Uû{¥ø©5ù§I~‡»Á9§ueÿ±œÑ›Î ]Ú|©ù®PNÙ¡†|+åãþ¸ïÀ© :“Œ¨OHX’3ôv†`bx²›IQý-àØ²K¯$/š’ ¡ ¬ŸÓ{{OæPÈ+†‡úãX Áµ:Â~pÃèÒð 2`Äu´–I¨w£¼|Gx´*(€¿5÷6VT;+)j±àTA¡ÃOÍfA1'f³½´ùÒ1T`ÅH÷Ö]Åwãák¯Xp°ØÁ †ûO”,Ž~ål"m¾t •øóž0õwã1á ª&ïˆsõ¸1ÕØâ”:®q#Žq¸ÿ›S©ÿH_QÔZdÛ€ôÂèÚLX3öŸØ#•H¯\žJDˆë¨ë*4àòÙ£…‡¢{_IWB^BþÎÁ¢Ì¤W. {sÅ[yx þÐÂOÐà»§Ýð“šì3V^B!§·(3© ºv*¢†×àØWq®Ëê.êÄЈqüoP£Ðþ+Ä@`” »Å;‰#HÛë°cO&ü“HBkÍÍÏê<èÝ,úÈEhpïØÍö‘öâDâqhÜFìÛŠÍž©ÖÚëKó¿ŸpG/x÷ª“,ŽÝl `"ÝT<ö÷WÁÂà•ÐËù€%HŸ^ãZ'¾Šˆüe‚‹‰ñ/`?œgÔߤ ÐhL€nÑ‘IS©ÀXÕ‡ j? €ý…™Ü‰ €>”#²ò Õ­+qÄ™(¤4UÀ äžMôL Pü/݉ ‘•7"Ô`ìù[ГfRÚ)@f P~ªˆ>Åø…ÖTé½ yºØÛ›U*þ‡ÕM:{@ð!ă˜íý ÝŸ†€ü&¹9Û*e0ÎÔp…[‚µ…ç°ðü‰ŒB1ŽBeÜÅ ¼¿„Hø§n=äâ*­ƒ~^£À?´æçA~{ìTº>€¯ñ?j=ÝŸLÉÔÛÈÃUZý¼¦ãêaïÞÝÔõ|Ïøù“PëÙí@S"ŽçþQÈødTe î²¶Õ>^šb\3äŸN•0â€Îh¥Ý; Y”™uÖ¼9æúËÞ¼îì± ˜îÉ.)/råËŸ¢„»º?‰A|êºL¹Vg- é說þ›Î›€÷íµé«<9®< èCŽ$pXãø& `ÂnÔº Ñ@9ñ#¶õÊIÀ c¤ìY>;µó&`O`ãb£ð½5ßÜ)“I‡2°nž=Û“á±³¼À&Wç÷ÃáI8¬Ìö݇“iØê,Í•œo΀‚Ÿ\`FUþ}ÈÏ38’ a­cÀ¢w¤h/PN¤ Cá­bØN€ªái à))"`ªøÇÒª$tæaêÛwÏ¿0 U|êÛŽé!!4ˆÜ<Æw6?ÿx‹áùòí»ç_¦Y W.á2h¹y¥üø÷øû Fì–»qÇuËÝH%mÂÓ&@;‰ñˆZJ@$w+äÜÉ-µ¨n&¤÷ÂA¡w? ½ý}¨éjÌp$jü•º›F÷÷#;4ð¾÷ÂA¡w? ½ýI¨éßÉ0€@„Ûûû‘9„ùÇ‚TÓrŽ u’¸°½o¦JÔ•+`·™„ë9f$_JøG ìð´WíƒîÝ á¬0áÝÁ“Úœäç¡Iuÿà%@gpEqý4`O=àb!4îký^ænóÓûKìTÇ+zÇ nÈÍkÿB CAÈĺÄÈìq¼&žñ³ßó„?9ZYâ¿)ßo/™ŠUÖäxßNH&>¬pmôÃÃÎûÓiîþ¬fò}7ãÆyI«¾ŽZßO"Cr‰ž–»?«dÏíä‘B :Žžb @¸¿ ¥” €‡YeÅ&™ ·Wå«íŠF U" ¤)~lý<ÁåalóÕ)[ç}hFßAE ¦¾‘dë¼f_ã¾6£vê”­óSïô«;B4C=SÂòSº2xaJXh]4.N  å+þss«Ý4*ìÍOØ7üC'Ñ×›Ò\Ûª 3‚v•? e}á!¯„wõ°¹÷ÚMük»¯ù‰ê|’¦6¯„wC¥mþD» ÿb¨wRhvRg/äÏN*M'…*þ u=áŸÏï•fڎݎ׌H] õVUb•]j`Tý¦).êñóCL^çg‰„»‘Uñ|ìi /HuÊ1Fûù1îC½#?Tåg‰ð<±†¾˜ÞsZx¤Ï¿iÈ Ó9þ!‰î÷©Höþk •òÝ÷J ºSMë5öâ^h?ß✅¼OìµùÙM¤¸@ Üi²þ½ÂÀy{;ž & °8g óéZ“ŸÝDŠ ¹¨ùóï·0$V€x€#£Ð£Ò>´u‰6HW£©øèáš}ˆÅ¡”ÑÈ^šhoö2Ø;Y˜õ@Þ.HÀ@îÂYŸK,ÄJÍ#£øä~Æsv}ì~O¬L| ·šH4_Öq ¸ ë¿4.ý£éTÝÛõ¡ï·8Ôº_¾xz~’(B¤«½ød+nÁ©† “•úÄë…"<äüê\‰:q¾b² NÃØgg² ŸF2÷×à>à·ŠñQŠ'ëƒßeyø¾;•nõ´$m¬>‡ë§y¦ï¹¯Â3Y^ øÔŽq±ZXÆÊlD÷§^á3oWpÖï46á´¾£"|ç > ÁuÖ_kp5@øl’áÿ}Óv;Ÿo6å\_^Òë `?óË˧ù¾2£?ÅïîîïO0ÝG/&¯ö{šÝσ»4ëÇý¼=t¦ºW·š=÷Vtq‘;{“=‹×ß|¿tq|ñðå¡ûÛ½ez?ÀNÜMУûpÃâRTŸuWj}x¸ÓÅ0»uZÀ³T.f’g³‹ìÔ?N ¦rÇÑ<~‡¦JÿáTÂל² ÐOHq¡Ÿ$âB?I Å…~’€?=#kNÛ,¥Ë2ås¨›èë©íÀàT~§»¹(€<Íåä<ª/©€ÚO>w)>göÙèC¾ZIøç—%ð•røZ¥ ün ¥ ²¡JXF¡Iu‡lù(‚Ã×Ë ”ŸÂ?Cºøòàø¸qM€«”Ÿó 6òOÏbDå!ÊCµ·–3éâË—‹Ø84Ùš!o¢3üü'J1®iÏJ`³ Чïj®ªëë€__§øùyÀÏÏSüä$à''þôŒc‘2x¨×‚ òåÖÏ @—_À98:|ÀZ Ì óé˃K_’ÓT‰ÒØ¿ÆÃyÙÛl¬šâ¥­®¡‰ ˆùQžQÀ; €ëW>èx2ÓƒFSa¡|<ÁëuFJ¶ü<c®_Ä3˜%– êê!¼WýçsØšî®×ñ?ç¿_F$ߥK9ýŸÿ|øð¡Cëõ`0ˆ$=àêj0 zàwÂßká;?Y“pwvÐ ð(•ÌÄÿpI)  .?+€S(‰ØXÕfñ&Ë+ N‡jFWœ]wÉá -³ßêwÉ)±Žÿ_¿:àøoÛÁÀÜ1VÀ; @öƒîNΖF}å ðHËqõæçÊ$9!¬i@ëÂæÓûH§Wú]:û8Lôi¢ï ¼\†o`Lð¿Làü/cÄ Ðß!ç¼¾Îý=žðwïÀ  Î@_ùXü( -?#OÑUœ gêŸ?ÍðÏ`ÐT¸:•ú:ö Z'& À¯„#g¢*ÿÛ€§jO÷³»ûû³3RÀÔ…îò!‚S@ äÊ/ÀU–ÿ«Ó„]%€¹ '›SÚ½ WÛ»E¨²_’pdþ1–îîþóú'ŸXë¶mšÓ@UÑ?þdððpzz8ÜÞ§§™Õ+á~MÉhüŸ P+Y2ÒY>±ÖYäÊ/@>eê·R‹´ì9˜‡äêèâÛ™S}¸»ÿðŸ.´Í`ý ªûnïø8 oøHüxc(#„N{`Â4G €ÉV#RÀ©òéýLz_1¥…-‰Þ^^Æi4·ŒÀe!gí?¶¬œá¥›€|ùDPFà•03Ÿ{1ç•Ð=¶W÷  R¿ž%€îï»@ç~#ìˆÿ/€å Ž[TêWVºx¾N³uVSªÁØ(¯ÒÏâíkÖêkí¦€Rv^AQP<î§ÀׯÛíWŸà³¥îÛ·ËËo>Áç˜úQØÆ?ÇÔÓŸE >[@Àà7¤‘±€rùh8òäPvóìú*|šç_Zÿ€žÏhÀ^ÞM ¨‰¿àñÝ@ÝêÃ?(ÈXºöÃÑï'€Ùÿ»“prÇÓ¼ûÊGw × ìÕÿ‚NcHŸ¿ãêônÇ  # ààׯ“{ˆ d@.á i}kJôÏçA0 ¬%”/A0 ¬%€»7­‚hÅ…¥T) „YS¿‚ÿ?îND'÷ï`ø(¬×%A¹ ®^¸ÞÛÆ›8QÉ\¨«cÜ—Qc¿`>þ~²M”î/—NN´à·˜ˆ :4¿v<õè'Jç±a?T*Ÿ(¼6üÇ¡`U~‚ç*- `ÌÈ3êƒ{|0î6i$1€ÿ†yþ• ˆÁF`üOº1#¢ß6ZD¿m´ˆ~Ûh ý¶ ðØM}g¿R€CŒõ•O<ôCóŸ Ùú_SŠœýBª½º,€R IÙ„/X–/`‡‚bœt `ð{ B~Ú+Àñ/ëТáà´|âá`=‡ò x‡ÑýøíÕ£4“Ð@Ãì˜_ ™â€vö̸¸Ž á^èþ à‹ƒÀ ¤ûFô Ó$@xLá1ýAœ9ì6Àà)Ÿ0"ÐW>Ñ„ršœšP~ ï2ñ±“×%À#ùFÍ€’uÇ”0úñY½îcû?´¿Fò~§=*àm?¼,À [>Ñ”0€:M £ò3xg¼¶î.A|õSÐÔø{Ûÿ%Üþ¸’ý%ɵ‚{goó(þޝI |ú–$‹ï’dñIbœö¤ð¯â‚yW¶…„AÚüÂ~¼<'œÒº£úWï&€jæ7ËØÉîx~ŸðŸýþZDù͉«PŸÇé@Ïhc•|Ãþûð.ú!uÐÿ~¨xGu^±½ÛÉ6qÓÌêÒïon"þc€"<àU|¼Ç କüãǧ·Äe­¿ÿ—ßìéˆÕ釦íJƒ>\±òfM€~â±ô¼~z?TJS¿Q¬ß÷/ ¯Ý©·|¼8ÿ½‰-âû%pŒübùl¤œ±G¿+®ÅÃ<™%)'š{Eõ¦é½Pn1Q‘Ö«3:ÖG¿/®Šr³\‚ŠØ,ç\Õ߀ף Ý jõ´>.—ãçæ?ÜÞJ…¢_Úêè·ÅCInx¨·$ÀçÞÚ箸äTâªÏÉÞr*á…7'a0qædÍ3¢ôqé¼?7ÿá6”®°?æ£ß£oñˆT@V8`®Züý% ôu³·*uБ،N„•è¸t>ÀSóëÒçVåmŽÞÇŽ¼Å ¿²ü?#žpep¥.úsØF)¥Ÿ»±€$Fñ¢Kçåø¹ùk]üXÀú„9råÒ÷å.~v–à ÿ¬€H~Bè<˜µ½z¬€dÝe¤€˜ÿXëă‚pÇMX|\:/ÇÏÌß4¡ø]ç '‹…3úÈñ8»+ãMs½¸ìÈß4ßüìÄ7ó«N¾MŒk~7FZaJxð´`~Ë¢C}û/Àü™y‡Ž?{ xð®Ywfu\:/ÇÏÍãíùr 0¡r}Ô–®Õ(âíõr (âß—?@EÜyé €"޲=‹pÍï&RÀ\¬¼^4¿ kûÿ´ùYA}û/laÆi‡hžW€™³øÉ;I—ÎËñsó×ä|I[¼c&‡¥Àý] ¾^Òr%üûòû÷ï(|ÚÐ|í«~BfëÌžÍñ/ w(˜Uaó«°M‹â™ À+ oÿà™ À+eL&+UÀãzí/Ÿ|Iž/—´ÁWIÀ¿ëU”p½\Òb |_‚œ Øx'>/^2)@ñ»‰ ;¢Û5aWz£e®þºö_@°Iøhq òàð; €]kàÉ[¼­Vƒ8ÞFüƒNX1îø_òr‹Ewü£@?2¸ô⺠îWV€àŠßU€l‰áWj¯ž1ó@Ê¿(€ÙS?ð?Â?í?Xr±ÑªËCÖ¼¿À—üƒvû8ÞFü³Pîù|üœàžPÀßÿ$øf©œøñ0ÁOÀöP"^ೡyÚIûp¥7{ò¸ÌòðŸ,ÿAÛ,ÿV‡¼NtBJîÓ ]é<žÈŸùJç)0ð/8ßívq¼ÍóO<ÜÅ8ð/¸þøñcŒÿ"€ïÿýwŒë^ÜÆñãÀÿ]ø6gö]³u5¦½ÑMÿP @) ǼV@Žy­€óZäÈJ¿Åârg:Tgƒv™ó•Îû|¥óœ xå@óû÷Q¼m°ô8!X|ápùÒçÿáðóoHÿDøÜÓD -ÎþŸêØxüjžà ·u  7‘iŒ; MBIÒ$” M @÷@g:…P ڕ΃ ç•òç90!ÿÈ>¾5#Š· NüòùGö?FüçOäÙÿç€Á¯®¼ƒ†û1-~Æ›FpB0~uEë}–†}¾û9ßäùg Œs 9/‹¢dÚeI²#­€î–Bu6hW:OÈŸ÷gKç9Ÿ`µ<çÕ=87+Š· îN˜lîþ_„»B[^_ríÿ m€Åþü±üþ“kÿ?ÐXÜѸÜ0uÈœÅÑõ þýɽÇ!ª£ì‡'˜¶cu˜0Î `±è@˜w›€!´Ú^°qcbTЮtÞ×åÂyŸ¯tžó‰ÂÚ.\š `p²ôüã8 ÷‘ÓgP@"fðOF†ºXøK½èþ…çã0ªò+Œ¯Œ ÿüÚîÿÜŸÍ àϽ÷SosüSoF  £Á(í›…P ڕΣW8ïÏ–Îs>*à©À>ÀݽxaÿþÍ às,€?­þ‰pzÕÝøùgÞ£½Cþ­@W–\Þ‘y\DØ`Ê¿}-BÊ¿_{—À|¿vÐúƒÜë$_0Ú•Îã‰üùp¶tž>QD} Þƒ úÙ¾üQ%ê‡þ?'øÏŸþøÿ'ÁÃkd.}þYPï½~¾ŸÅ5Nù€æEŒcþóüçø×Dµ’Žù'Ѝ¦þE¹H‘W þcü¬dð?þdðS¿ÒŸy¾S4õ̿ǫÓÿJZ ÿ°Ys,€ëüêÀ&À:+€õï" ©Ê¢¼ñŸK,€<ˆ FIYüÏ?YÄ’dùí˜øÏ$çüaÄžœf0dÌsͺóüƒB (å?,¿Îó¿ñû8àz̨þ‡Õ™ïÌìû÷Ú—ø'ø >’ ü“ üþí·ÅÇS4:YUa’}Ê?2p_Q•°èÀ‡Ì­ì„µ<󹑼Òy“¯tÞ%?ãÖYZ\ !AËìŒ\9—ÁÝ §ŸKùÝ §¿ÿéÀñÍÉ8ôpš@%˜kþ5ª5ýû/t¯•ÔçFòžI”9·T¤mSgfä†3 žÊã}ù_?9Ip€ßÀ!˰(àʊÿ¬¡Ûôï¿Ðmøu)ÿ,€gFòJç$ú NEšŸ‘ðCÞ—ÿ™x“<¿BœZD“æþ«TšÿþýRÌÍNNk#»B﹑¼Òù»##‰¶¿ÎÈý½ð:ÁQ2¾j œFïm x°!íhJ˜é&ëï£Nà|í䵈è>7’W:wd$1" cÆîï‰Cžf ÊÿŠç‡Œ üpØÀ½û/Äaàx'·u’yn$¯t^çëŠ$F5¬tôÛâXˆæe\)ÿ¨€Ó‚`p)ÃÜ»ÿ‚ H§…—ø¯žÉ{n$Q•h“Ìȵåÿ[â\Œa’Ï8÷öô«yÉ?H%pyù: C û3×[½Ô˜ˆ[yFðïŠû‚Ë?Å÷¢”ôruѯ%P»è×0'ß[ŰËIÒeÉCüYeVüB IDATv‡488Î[ˆwLÿÀó’-M4evE¿ÿïž~§õý&ü–I×—¸cmÇeù¿ÿ„AÉ?YB¿K¢PrÏEì ¹zŸ¾˜q•}›Ïo´¾Väð€ÓÔÝ’`åS@Qß—?`bÊÏW“€™kü´„³Ûr@ëʯê“Àéér Áäô4lã´¢©þ0ís¯rXÙW»ÿ>ëûify¶æqž¼54óüGQ€“Jf Ï ìÜdk¬6œ+´1Üj•·ùbîS ý-~è’Ô|RÀé¯}^ý+)Àdzïõÿþ‘•ùn8áË0{?‘€¬<øQÎLgdÍ@_7°Ð£d÷‰ÏJ ø- ©w£Zœ"ÿ*e²ñ^§•XäÛ `s¾w4Oþް² ‰¹¦ Ájý†U@Xyð#+ï”?(à§UÀe”âÖ´§ˆß* ¸?@HK®ûðC+àtyon–ä•@˜ðíäÇMÀjÅ­@PAmÓ›GóøÏÐ+KrÁ¸k™îðíÛG…ë•'?2ø.ùð·Â忎Q&ï‰8PÞ ¤%züÃ’  óú`øÂ°¬B²Í@cÂm™hÛ+ãôW¿×FZžåh¿ß´<ÿÊ Ðhok³8¬½mhm{&|νwêt<¾ Wtì ø§ÿå·N‰Ú¼J ^,¬Ô­ß.š'%VËK7ù½Ž°+ø'ð+ ¼˜ßï‘~üiq¯€?)y€_Úh4··Úàë×£˜C`0÷ž4^]ûDØl68žbTq"£ïùŸøóÔ%<7 ÙÞ,bô½fŠLŽQÀ·Ÿþ>~‹ó/ øóïþþþ3Àes8Ü6õ‚ ðhÚ`€€ÿe,€ €ü~Ч!ÞÔ¹?€âèߺÿ6þX+@^úYö9»ø™û‚«]ðÞXë*ð« ø½Ž3 #þyù™U€ðû=RÌ@Œøçåi‘./SÀWÀ.n­vÑ´q÷MÌ¿YN›€Îý,ÿ”¶90û2ÝNb\UÿEÔȺÿ]ê¼M¼¯©‰YuS­ÃúþëeF×È? ÂqŠÀ÷eFß‘@„ã#ú!ÕÄ¿(À1Å,«€üþ²Êtïp¬Úº‚À< Á(à4I•Eßçž~ãÔoï«g‰€ø Û„6x}žÿëkZe´¼) Ïÿ÷ï´ !ixR$§€Z5Ò%ðD¯sá›G àÐ%f[ñ)€BH?Ç>´Šþ¥ïÿ¥  pÿoÇM@˜}'ݳB<ï‰x ß•Û%Àš#DÁ¾kö//?~&\G¬@û®ÙÿùóïHß#HV¨0Ù‡¥/ôe­£¥° #…w‹’  èÙÀr ôo“³žÿ6ðâÓ”}«Þ93€ À÷û¼n¼/ìNö½ò¨ËE"€K\gHø|™¿‘ðóG"Z‡Høç{düÅNèýr òé|[ô°êÝÀ0Í_%Q€©ÿ €ÉD™€Ó,ÿÚ €Åÿ Ø-A;q”^9Þç@Í;>˜p°¾šÿKYeŠ«Ì?~^\çùg |üùóÇÍ¿_…ú*àŸßóü³þVXr‘/I‹¢$|œ ¬ÄCïø‡c€û½ÎóŸ*€ª=´Õ¤° ü[7ÀªÚ-± 0& ~“xŸLÜ‘ê_Á84 àòRí/b׃E|$üü©ö±kA?Šø;@ð»ŽÀåòz Àß ÿþá÷±Ï?´g¸ È`ÿÔ€ F©` ^À› @þ*À7rÁ@——Š^ÀÇK£Ã?(à㟨€ µÝ àïŸF†P@@ƒ @êÁµ–Œ 3¼eP¨èŠ`ˆÛ5ø ï¥xé'?¤ü' HÐVÁÞ1U¨€E¸ñy%]€jÇMGƒÞV‹¼h—.ÃígV@e À)àO íBà×pû+ 2 ˆð7Œ ^j uËќ ÿ#€M@ p€î7f÷MÀ‘ØLª`”ÑLÊœ“@õ^ & 8ÿ¶pôD\¾PP¥@D?ñ ¨Ì‚½XEýÄ?(ð£(€¿•ZîаN^¾›óÏN`çþìwXþƒ?b,JÀ ÀU‘”Á¬  Àß»JñOxñˆO)«o9þ•´þ?®þÌñ¯ ðÿÏ?^ƒúbÕá–PÀ @öñb س?€Ž°LœL$€ÀÖ€ã@h*`èßcPUo æ?FÌsEß²øÌXäx%ø3+€X?rþá¿%Ôí-;!”1>“ : “O»÷LG]$``â`°°ˆ‚a2€z+¬™ö|9V¤Ù_$âV ¸Œ¯€[ýÉû9þ‘á €Ÿñ•`íø¿<ýU}ÝÜÖkµ<Ô@óOçSpš@qAû6œ˜'€éQ ¨| rC@*¼î@€ü¶â®›°¾_ð-'€J°ÐükÔ àÏœ*ÀÍ¿Fá°*œ3ôJ܃œšv¡ƒü‡ÔTÃÓÓÓ„~⟃:÷P ˆ @IKCqý@…Fpèp?3pI[ÁW;£@ìúÿ|„ÿEpVóïqÀ·oV†a¯€K+Fÿôü©è QÀO+Ὼ¬aøÿR-‡ÝPÒd`Cÿ©Y~й?@V™±ÀT h[4ÕäTÏ ÇF :ÇHĵàîZ)Âÿx#žàã¢_ßÿ-Ìð°ü{‚hzÀµa?à†–ÉOøñݰ¯pgn#€æ¶]˜ !‘ ÃñiœÆÚtï ›þáÃD09âÑ`~²#š`pè ÿ« †ó¶¿þêëûqDLã(ßÿfþxRÀ·ÏŸsüW ÿ^¿¬€?ÿù'Ï?L iY´?@[/¢)aBä:cÀ‡ãqJ¿â¿s€¶Û-ó_Z_¨$‚^`g3“ª%χЊÀÙˆÀwYßÿ-+ÍÏù˜ãß) +•ÿ'Ïù»ÀÿþLXaføp¬$0NùïÚÀ§íVáC^Ä¿mþ}’?`‘{··K;‡EQ -½Žššã“ãð-ëPRs|rü£þ,8ò#ò´ð<7aåi–ÿŽý8m7a$x Ÿ²øP6.-˜ÿ,H ÄV¸$.c¼ëúþ0ɇXŽþöËEÉ?à&ùËüóGÉ?PÏP)W~Õ÷fh$0ŒùïË¿ÅÙ€Äúv»))€C Y@8ú…dg„®È¼jüïÜÿueˆã{qJzÉË?Å÷¢”ôrÔE?¤"}nüôaŽþžüÛMõŸ°F Šp€éŠÄqu@ñŠJ* àçcÇð±—Núä!þ »UŃƒó‚ñgÙåÁÁ¿óâeÒ í=‘gÿwM¿“Ø äÙ…$*(^f Ì®¨àuø‰äºgï‰?>ÅÑÀ>ÜF »îX'ûdñºî¸ž[só¶É~7z'C¹´_BJæ÷á6Z˜Þ°¼@¯ù…û÷á¿—ø¥UÂP®þ?Çá¹ú}ΰüû& ÉÌïÕ!ü§àáLv0)“ö(Îÿ\¼Vî¿} åëwÀóõ;àÅúÝ›¿ò¤+þ»BÁšµ'áÙ+#˜ žêíÅ«ßA™:nøÉÔá§àåûc(Øò–@Q%nûÈ)§ôšì=š®'tãpÏßBi5ü¤u<÷åÏÛ€åß ¸¯y{mp;#÷(¼K´@|ÆÞ-¿#ÁQxEx^$¯tÞä+%®Ã1Çâùú݇PðY 6ëÿ3,uìpÞ%Ú? >cï–Û‘àHœðÌHÞs#‰–¡|ýx¾~<[¿ûóç&„Ü[ P—(3xfÆoÞ%Þ? :cïV—ï߇“žÉ+oŒ$F åëwÀóõûx<ÿ\/ã>Ä|ï)G™Á33~ûðnÄM@ºÿ@S¾Î E´OŒä•ηGFc†òõ;àùú}|þ¼}É à.%0ÃRDpˆ¹çàÉï`ÏØ»5åû÷áxËçFòJçÛ##‰ C÷þ^Ï“3gîj N¯îÃ;RØ?Àœ±wkÊ÷ïÃñ–Ïä•Îë|]‘Ä„¡“¯g“þzÝÈÏøíÃ;’Þ?@Î$û ”æã-ŸÉ+7ùJç›Æ†Â¥Ž–Jäµñ\2ñ³><3ã·ïHvÿÆÞ­¸#A?Ž·ìë§¿vÊ1T.’ׯ3©/pÓæéÃûžÝ÷´§Ï ¦;þ^¼s9Ækãiê#¬Þ§ÓO¹ûž×ñˆN\î÷î€íÃÚvÝÒ‹Eb¦ðȵTë;þ89þ KøǧÈY ËæßŽë²àº-•Õkãï’ð„ðWñ‡_3Ü®åm“ÿvÜDë=ô¼ƒøÚxåÛŠ¢Uz|=àåE|?m»ž¸’q?ñ<à¿ ¿Ó¸§§V)¥èµñJ» ù}À^ ç·Êm&“Éf£~NTBÿBü^ã9~R†^§—»aKU ðÕpz±t½‰Jp³Ûô_ˆßõà'~nog3¡g6»½5 ½6^U ŠêˆÁÓ?ðë_Dø"Â/=¾&ox³‘~È£®±€\ ,Á®Rܪ2Åíüü¤¿?»W8ó“!(¼fæµqwÅmÍ"•r{k_r3¾:5øøjlðËë…Á/¯/-ŽoŒSøÂãÜšl4ý cµ×)n Nq+ɝޯïºñ»³»,.«ÍOÎN^¥ö™ltã_×ýÚ8ídÕ†ƒæöVÛ€Ó+@#¸Ò6w˜×øåõµ¶°ý°Å^k X«@ýðN 5*± ¸¢ßh‚G'xõbøI'~w¶t Èà¼Ç%(÷¯üûøb‹QSO‘î˜áïEñjзpÐÁD_§‡6T¨Áøôôj\×¼xÛ:ƒ0+üòÿ·w5¼mãÊVŽ}ÓºHèQëÆ( ±QÀÁbãþÿßv9_œ’Õ¤nòÄÝ:–Ž(‰<‡Ãá²àu&‹¿×¦ï[x ¢Åá÷§á5¹øCÔ‡Ÿ£–Ÿ ïq’ ôƒpæðxŒ¸¥UÀ‹ Þ¼¾ùqó\Ÿ ýüåÍsŽÝÐb£´òˆp˜ôŸƒi>ŸÑkÔ&Úø[üAœ¦‚øòAç—Þ¾Ü;à› €år)H ðŸà@ùá€ÁomŠÊùmøMñ-ýÎÄiÛúûþ´Åç¡© né/á–þÐçŽáሠތá7eœcÌdr»þh". Øÿ5Š€­%6ÑÜ@xQj࿃óÓ‹¾;vñÒ¯ÍKúY.ôã¶Ú·o?ì Ýd8œ4¥?|¢î³¸¥ÇŒà$1Îñø‹1ÏE»~RÀs Ç®õ_"Î!ÿ}úw>§@ûÀâ»Ó?(€ÅÂ,ª_­3Êÿ~¿)àñµ­!µ¼µoÀ5ø‘†(ók§ÅMÖ'êVãx¨@ŽC=À"â‰yù†¨[úX0AÔDEÑDz€–ÑGWÀ»@ôÑœÞ%ƒ^¼Àö„˘å]3âeÇCðxÌŽGŒâ xé N]ÿ»~4)îº~v"ohÕ†aŸ5€¦nÝ(nA…(¾ˆþƒü[exI =Mb¬rL€ ð1>$h Aàä9lQ ‹UÄ”qÀ0Nà¿Å(áÆàp âNôÒ‚˜|ƒ;{¬¾™.äº÷9ðƒðc@{À~@KÀr@ÀÁ ï½üÕÚ €úÎ>âXwñ<3‚ã£8”áÏãø³å¿€G€,„àLr*/ìÁ Oàq'úçЯV/ÆÈÐ£Ô ,àãdèQ™€]@¿—cã2s }8Ì–P$q¬»xÈÁñˆQ¼/ÿ·ñ›qœG)n äw¶uC×ðo„+áH{Pþ³¦Y[l#ÿ†@£€mä?ÃQÛȆãÍm#ÿ‰¼âp§qò<8i¸ˆ1öÁa›jŽÉqS»aß(ލàÍ+ðç ~SÄ­‰o‰À–;ù¼ tE‚¥wâ&®’.€ ÇÿÐKp`€½ðcd€–øеe¼c´_““â•‘Àé„––23gÎðO Å›wÀÉ<'¸%ÐŒÁú”`8೸ΠLzø/ù€"ju<|Q ¾”(@oy xèpví:@¿â¹•Àö·¸BŠñ••@ŽûÔ9Þ¼7NÔÿ›à©ç0L€ž‡q‚¯ì 0ÁK{< ޝv†ï‹shÿÛ—íËy!üÐ@ñå.´ÿàå-wË"Þ…qÀr m¼+âÁ¾´Ûvœ¶#ÍD ˆ“†³i7ÈñˆQgx" oþ þ\Áo\A:ГA^JyƒžßÂùåÞ‹sOXô €ÈŸàË݆°dxwhI] Èð6ìG´T}à¤ÈJ€,C‹ ÷Áãh‹È˜á+ã-á)Á¯ÄoÆqq#®ÏæÄPO¤édq¡g¸çw:Žÿý п]¬WçÅ1!ðøßÁá¿uP@†þ™ànáõ¶ú·-NѯqÅLÓjmbù)δqó°Mwâä¸'xÇe08„Ë`ÐÌÀŠQÀ*Îôb¡÷ôýA­pà?jÄÁg=/ìlàqsAë5½x ³Án6ð¸מ†¡ÐÚ <¶Ôêéµ”d t6:I]BñXàCè_Ë‚n–p·1Ç á7£x •q E¼‘꾉÷Ú@#níÀŸÄ›ÐüÏäùq†@XàpØaðîÀžŸà°Ã  cÏOp\À³_ç8’HS<  €;dx"€OPÄc@¸ˆ›€pwáˆ7ùO8E~ìdÊq0góK2Á6¯ÎÆ€ Øm+‚,ÞZ‡ÃŠ ‡w ùÇ!PO‰¶'Z=}Lq¾ë"n(.àN9î0ˆßŒâÑ”qµ'†úœs¿×Æ dªâð¬_Xþ°pøf™àÁ¢[¼í*¸ê×Ì­ŒˆËB 4 ÀËÊãqUPwksGm@ëpgRéèëàÆÊÊ­¶Z¿;+èÓ@jèñÑÿ ØÎYmèÓØV˜aqf?~›vY6œÏîl€£ƒ!˜¡qf?~›V¾,ŠΊgw6 æÍ »$5IºnûÙ{÷ÇBüå>~ì­åüâ/šßu®% מr€ˆw~€í> ýR²rïSÊ7`èJΰݴER~R§â—ËoæwžÖSüh¨}%PÜ àPÊOM"åq'´ÞÄ›št.›4¦=¸j¬ð’ôµÍŒ@,Ô¤ò¹lÒü[¹¤áÙ /)ww···ÀßÂÛCJøåRVáNw¾¶¶Pv¦ ˆ&àÞnDzçùÑ&v*€ƒÍïÝklŒ™ð»÷ç­@lö(Þ8häŽGj°Eš^>ob³GðFà?*5'~.d¨ÜÆjãš¿¬Æ½î¸~¨îèÀ§(ð}QOjDüÈkšÿPÀ“'²Kÿ¸óÓî¯Ù,Mû§A¥lŠ\ét¹xT@ç 4±|MgКöOƒJÙ x`ÐåZåçT´ò‚³2†Mþ¢Æp¨à]¬ai¡Ò¾T;<‚ñ½@k(æçêQtxã‡LÐ/DÊþi÷‡<«–Öõ‡m¶j õ;÷Pè"eÿ´ò!ϪÖúš°Í6@-@‹KÄœ¸Ü^Æð;À¥Œ_.¥&nò—§‰I*RÜ ®ôð a_Ax”âGÀEt¦Ý™tÿq? @ZhCØù±fp6­||dÒýÇý,äŸì=ôí%ÀÃïT—~¹ ( æO8U#‡Pb +T°7F™ªC Qáb ¥*Y‚[k%ÒخޟQ’óþý^öx‚eA:ˆ;ÛÕò™¸ óþý^öx‚6Àð7 €»È¿ëçóü%?/æѰ‚c˜g¿Cd©Ø+U¿Œà VP óhe‹ŠbWœJÀµ^øQ…Úý¹]“¶þFJˆæžv( ¿#ò­÷1V+ŸØ5ië5„æþèG'éßÐòšr(xUÀýà)¬ZÍÏ]@B¼±cL¾u×ðDÒ¥4Ôš©6©‚€š¸Ë„èE€j½“Ú ‚Âã.b\<Ç>ÏŽTÿÅíj÷Ç<‘gówÑÀŽC# ÝRv)udž1!pýÇÇzùà¼þƒæ‡SD p¹Z# ®•]e‚é•-·ƒø}Ü à–÷±6—¢ê¥îJ€&Äl¨©IDAT¸@k£•>®Õ]©O`FÐüípÿ¤WžrO÷w‘QÃ6mõß @©<èõ§•ïéþÁ@dÔ°D@=äOP o˜àøRŸ‚CNKp ÷ÜQï¤Ù¤èX»|§ "2|gXG»uÔṌ Ÿvìx´V˜ÿäÇ=÷ð¿1áÓÊÇþWÁ£æHò—€Ü‹}€¡‚G…éÜR3Ÿ†W+ˆ°Û î¡jY]'xAIûMúðúýÅ1ž=S;M@ßSæ¾'}x½|qŒgÏô8M@ž`¡He\ \ ý´üu© ¼(€ag@xZwƒQêL0íþ¨ p2bkBòø˜Rgº€iå£.ÀɈ'þê]ˆëž•Ÿ²¿€x.€Âù/FU'IP´\NŽ@Á4‡ë”: »ñÊýÁ1è„%§ˆsÆSœÜGÖÀw¥®Ýx¥|p ^?9Eœ3®:ÉÎASþÀü àß’²ó_¼jÃ$6ÁjBªsDÎfÃåVïÁa`íþì00?ÅÔa.i@’\ÿû‚ñòÙa`~ŠiÃdÛA›€N ˆÎ¡ ÃðMø+àÂo1ÊÄ'J°ÍG¼(€Á@‡@ñ’0å Úýºñ@д@W¼bª•¯¢md“AÝ”É$C`Áä­¦ãZÁ#Ó¥Ô°_ÚÞA+hpº“ñ¶ËBæK³&ÄK`ÒýùeaFS§“­ê%0©|~Y˜‘À´édaH`ùSœ0ˆ‚Ëùµ‡püOX0A_#¾\š@PW]ð€+ã,Þ&ë¡ã\p² lòý¹aÖL\P"sÁùl´òi¾Î‰ J„`ön=Šƒ0ŒË o8?->iÉ”  K0iÉ“ à{Q~I˜ë&Ý_¶",f™¶¤Ì/ sÝÀ¤òœ°# '§Á%eŽaŽÓº úc¸Æ™²hàñD²1¸è‘¿EÜ À.S L¿¿œýhœ9ZTj„©¦—/g?ÚgNÍ6ÎÊÇ ­MWÃ',›†£–·]À”eÏ]ëq'G¿óýÔû3Yœ"Ɔ–•;úÓ9å å3Yœ"V¾~ênÞ™ÔÒ•ðúƒv)0íÁ‡.Å„þÔ ;õûK—ëÙšI–ý© vêåK—ëÙšI–h£ïZxýÑ):*ƒdIؤGŸ ¿¨€¥6ÙÌ L¹¿rë—ˆ€ò/ÖÃX[m²™˜R¾rëïØ]QþÇ{ÇT}x’Ž*d¤?Ó~,,”]äÌÅ»°*P½¿=Åy½ëÇãİY}¸”œ¹¸Çª`ø©–K]?'†ÍiϾcª=>=xï­ŸŽg>¨–T»?Óý–î–µÇË ‡·­qjå3Ýa9`×VŸ?¿)Á1ñew/ëµ|Óï«U ‡oµ4ž?ýñ¥ßKôC²à÷ßå‡ôì÷Ò>ù¾ÝþóOýãù¡Ž¤\ ü {x˜Ýz+þò2†Ï˜ðòê¿k ùéné¯ÿ.Ç•q¸Ú5ÆÎOH©šžŽG ~;ñÛ7ù uÿ½´O¾µkŒòkAoNe–R{œÊ>Œçùek(ÿ,€Ycj"à­ùÇpHSðßš ‡Td)—ŒålI-.eÂKùíÑ´š¥n͘0 à}`é“=í'O“ßã·jùW+qCe_tßBà,€Y³Þ ï2¯wjÇóú$!£OŸtï,€Y³ÞSTŠÃ†j@ ÝCo²Qœ\º—àŽæ§=ŠÒAÀçñ(9f̘ð¾ ÷‚3D ”öI‰—=×àŽæ× ý¶[š+„÷‡vÝv+¤Y³`råuIð–üµ4v~À·W&À[ò׎;? àà’ÿ±H¡(©ˆl+Û` ™i†#>}‚Ÿì'|À,u/ì”ki_Š‹Þ’ ‡4vþt2hê4®$À[òצ‘ÇÎOèFPTÉ`é,D¾û]­d-Ь?‘`Ð,€Y¿ï¼I²NàkóלDZó['ðwœ7IÖ |mþšó8v~*•:Œ£}4ŒS\Ëmq îÚa )µDïÍûô Ì?½ª‚É'êáƒhd+€ ë¥–Ö”âϵ§ßî¡á¿Ù¨ [ N€Î÷~ !tD> `³‘E‚ñòïtÊq ^þ}þœã@¼ü{~V\§ÎU¾KÒÒëg©6¨Î=B>ò¿ÙüÜŸö¨”Àª§QÀ,€"€|&ÍùÇÚF°Ö"€®ƒåêKq¸ÅÔ!ÜPþõ«tà‚ŽGýú7MD¿þMѯÓDôëßô>ÁƒA¶€)6’·ØïsÜ àé)Ç­.Áå>ˆ|JÐØ~_p.¢ß²±fÏo-ü‹Ž$LÜ3 àã  ‡höNk P$ðçÏ '}pȦ.§°#$ÝÓ4à‚€zŠÁ!x8Ê>®T>?TwúÍ&¨îô›M@|úMyİ…‡«Uâ+[Ü:%Ü:%Ü:‚Ó]ÝB¿ÝgÝ>/€\…. Çào.€ Ã,€$±®|híÁ x e8F Ðuð†B) 5œ. ŸD½„~‰ô¯_)$Îà¯_4áà¦J±8¹{½>»” à_—à>yrd!.€¬y\® ]@ —ëBPŸ9A@¸¥šj[¿Ó~¥Ü  i¦X ýCàÇ;ýjñz¡c? àÃjWù9ŒýŠ'ƒQ4 ìù©A8x@¯}W…%¹†×@€ÒNlQxø” À§\>åðI»€ÍÎ' .@9 á"€!\ ¸€¥HËî@Ô“ tïzñã…§~@H hÀljÀ’Xá¼o&€~çÀ¼ÁPìÉ5ÜKÀÓè{´0¹‚âB%x´ñ5Xºß € $í‘ýV÷÷ºGö[ÜÞêú”aÜ=D¡]€,ãð¸ve\»€2®]MÍ–€°ìM?ßøTpiíGŸ‚8@µžð‘@+ýý #]?Ê$Sliµ/¯k&áBµÀ"8,SÁÞl´ ÂI´m»!œà+À‚H´m»!œ@ÛÒЋ]ÈI @Àm¤€S0ŒS0ŒS@˜~¸dÂRRÛñ•Ú?ÑéÐy,š‚ Ä‘ÀYWGù)€<ˆ‚x 7î²ÕLÆ!Aý'U°Ni(H@uþô½gtf >SÁuˆ$•@[âüÝËKQ¢^ºqþˆ~’€|j¨öÅ$; ,ávXÂí0°„—‡–~»ß_Ú¦$ wã€Dè0àYÿ×PNGjê(€ŸEÙó’€”+Gòÿ›¿‡°†—@kÐÈüÃJà×/™zO‰¦P-$ú»XÈlÙµq[W©4•‡SøÂÕx5¯ ¡ð. £4 à# €ŸðL2ÿù,®!¹|Â1¼$€¯_É’é š ¦é`š ¢³ÆÞSmÁê=¦aœ^Z_Bä‡Ô€ó«¸@-ðOÂY] ¤;‘å¡´ (f’+o-/â<àtf HשÑc•àƒi[Yþ~ hô‡7Ñúøùuq¹; ßJrÿ]ò!×ü<?€]2}—f|$¬ˆzN±ûG³ð‡ +%Z a_ÐÞv»æ/‹Bß3Ñó2þÇ•‰œ•yˆóz8Ý…,»•0Ñ=ÖåMO4Mw® Aý_x8uÀ; `‹‡³X½1ÂÿL v‰7 =IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksMM.png0000644000175000017500000004751713263214225021457 0ustar aeglosaeglos‰PNG  IHDR õâ;c“PLTE™™™wªÿL"nLªÌÿwww»f"™DÌÿîÌ]]]DDUUUª;;;™™UÌÌÌ̪ªªÿ3ˆˆˆf3nnnfffÝ™]3ÿÿÿÌLLLÿÿDDDªÝÝÝfÿfLwf3ˆÿ»»»ÿæE8Î IDATxœí]‹bÚ¸¶5™a \“>èuë`s›äþÿëî~hK[/‹$¤í9E3MK–%­¥­­—]U—p —p &|ýúåã7¾ynWy¼€6m÷«óÿÞøpŒÿ|óœÇ)&4Ÿ>`•¿Ûý.å>ã÷ÁÓ 4v9|HŒæïOÈäï9”ÌÑïS ,Œðõã›!|óüÜæqâ?—¾ ;¤p-€· HâÏ¡|–ÿ'×ÿ—8—_Šož›*Ûoã_bdÒ·HâJ Ü@ˆ‡ðpÎp¾üÍóæeõsf¼úB1T„¯_¾¼7¾Àa§ê̦¿yÞíò÷'4›?+€$¾ÛY$p@»lù)ËÙúéZR@ß¼7?Š¿YÏÖÓÍcß á0ã^޾XÓîé3Ž@{8P¼Kç¯ZC#4—äÊ<Íà;Þ?‰ïžÑ,mrøð5‡??o6˜¿¾y;Û$ß?çñMu¾ñµ'#ÜdùŸíB8. a‡:›ÍÒùÛšÉ?&½ÚäÊ¢28¡å/Æw»š“ÿ°Éàm Påq¸ÒÔù0C8…õz6[¯§Ó$ø2|1¬qD¡½„®ºÁ‰ÿÙ,`Øâ˜rfœ(><Óù#ô!‰"ŽÈ”ïðð@H—nhÄw$€Ó8¨€týv]»C#«ÒǦz;çÓŸ#xJ†M¸rcÿ?›#– Á\“1L8IŽY«éCFC€N–Ÿï‡÷NÖÏá€t“¬?„ÙÈ ,œ©H;$U¾<~À^­ž.°‚‚ººR8wCÁOÀàHÿ, øàðMª »û‹ÿ糤q„$JúHÂá!!Æ‘BÌ >^±é«g},ÒWCÀ½¹þüêËÍH U¿ ³ÒõO9~Ž^Ç÷g¦¸|Y~¹~ñçñxsÇ`þ N 6×së÷@°àcVµ¨pâ-¸Ç‚Æ[Â’äþÈÁÍâSx 4å‹à£Ã“—{×'.‡ëñîÇ8}D¤€ î‹{$8\G˜Í •£R8 €­@‚?fʪ æw3L”ÙÎÔ…g -M ócŒÿ\boAÍçèáTâŽüS k¸ý1Ž—îstp8\ž`ø`õ±‚HÁpÇÝñÝî&6ø»>R€Ó3çpλà^鎔?§€CªK }ßÍ<\3ÌLiÌß7“ËŸ‚áš³£ž¹Ç邏?ABïÂ7Âü™ H¨ñ†¤o#piÍõ-5ñD!èxU ð¸ì’Ð×G&Âátÿ„ý"A 0¸W<Î+ñ*¬HŸÎâÇ+‘€Ìà]ÇBTÀ2Àï<…¤â› ’ݸf¿Â m¼!Hè¿ 2y¥Bæo¸‚|‚µ@Z+ ‰ùH[øaÌÈ…„’Í^.ˆ€µ`+€@“?Rá:‚à¦ÈâÖJø£‚HsÆ Ág…tAàïWÍžRÁN°ºzPNÜÿ°Æ=ª!x#ügpò€Ìõa'[i\!@äQ Ht`å†À•.(†$’ÿDézV@@°Å69üÁvà7ªôéÀWNÚÂWl®Ø’› t&B5{…{ÍéûS8ö8»ÊÐß%q$ØðŸÄ©Ê„&x‰Bœûa‹§ø­Þ"w=waUBb\ÿ¤€P žÌõG–€²ð~<*c 9¾*ë$°l"\ÑŸÁ¢4ÁèÅìxþ?s½ô¡mš`‡§Ó×N~Ç®˜d°§‡ R?f’hºAÌnÆHpg ¿™ë$!Pù…Õl„L¤p1þ×ãDXÞB‚ügp²!†ÿ<ÁƒÀ> ¿…gËÏHñ ·]¢ýºúE$øó[ø,‹cùlGÁ“å{½Ì¬ßÀõàGRóH3€‰ä,„QÈ0~<ÒbΛ°Û…“ §Ñ~’_+€çTó¬t  LF`ÐðÃÈãÉpûÝ„/Äͤo—Þ }âèþf2=Ÿ?Z«Ëã¤À`ù6a üDo’_)?ÇÈ]8̓fq¤€!\< Nù‡Hƒx:äç‹ð®€3ÿCéSÿ?|⇱în4´,_I6M†½Ê–“j¾Þ¶C8ü4û²xÅ ÈãÂ¥˜¿¯@ç…¡<ÎóÿƒéÓZÊàý‹¸…«áüP!½ÃåÇÃx¸ŸÉÇ™à„tý Âîÿ+PuœÖ h‡°) ª¾9‡ÚU¡ü¹=© / 0ˆÇíû X¯§×ðsŠ?6Þp³”6>-Šߟ0˜?^îÊ?Æ(”/'[¾Œ¼ò—ð¡ô_‡\q„*åãHïNµ^Hß`àþ$€Áüe%¢òŸT€GöûW×ï@H¶*ÒÍNÀpŒÁ“A§ÅÈZÐJ)\»„MSÉyp —p —p ÿ¡Ÿ4ÍdÒuõ¸mÇ]]w5ýUw=þìû÷ÆuùÿøüŒF“º['“ñªîžnU¯pOôÞøKó»œïúz5iGÍóóÒ„ççfÔNVuG8„¡ß°œm;¡ÏóùvëðÇv;ŸÓçIÛŽFM<ÍAáHÛ9s‹UusÄ…˜/ù¥"¼ij™[¤†3ÛÕ„?ôïûÙ»Å$ÞV{ø>‡ï Å·!T˜±~è7¸@ŸW+R€wäß,?ÿÑD6†#уüÞÜ$ˇKõ\Ð:fp—@ —m4ÉÛ;ফág´ÜA©îß3„Áz{ Wy ,ï«´Šð:á_á%Ô†~c kš}žLHþ½‰ÿ ⹌ò‡ä|!zƒËÙÚE8~A|±X'æÛ½º”mq½íïUèëí—TJ8ÆÆ¡ñXÜ}7†„ï&Èa0Z½EjG¬[9†Û1›ý-Û€H"$Äg[ ¡$Ù9’û]!ÿt}Æ2€8iû£"þ͘¹U‚ž#³ A¸[Óa–‰ìM×ñŠk>¼e~j` j'uoq&°„Kœ!b\[\¾SÂʧp»Çœ(d°ÀxOIwøõ-u·™‘ÓôV“¡ßÌ?(€>“'0aeˆ¯@ÿ#6FjÞmh³Â “SÑv³õl½°»°ù¯ã³ à5ÑSw@Ú5ú @“€’t½àןÅ9`Œ!ù¿¶¸ù (yîmèö{o®Éëo òb¼ºm¿÷Ý>œk¦ÆËaûCA6æ~{tj_ÐøÐÿÓŸÚûÓ’1ááÁ°ËÌhþèDÛBE˜â)·0Ÿ àÜ>»ÎðoÐÑ ²¯ŽxÅüá(ÎÎ1,Î_)Û^…í~¥¤–‹ÌÂ/à°ï5^Ý2Êü“¼ëÉ$æ%¥Û—H`4âv›û­ ºöÑÄßÖÿ×ÞŸî4LX6ÛûûíV:Ëbx¶žÞ,Ì÷4å $ÇiLÞmkjØVÓé¶£ÛÞ n˜À9p:÷YÛ¿Æé«Û¦!ÚÉzßRSÞOÜ·Ü»SÓE€a¢ð}ÕHóîo©“€Ë=»¢“Ø“Ópj7 gó¿­K§}Aë :ÿEÕôl¾}›N¿}“ÎR<¿ +4¹Åó‰ðG |(¼ßB#ŒF¡šI]ÁD  Æ)Ü‹2x%œ¾†[²îä¤Q^iÜ6ûöVD7ÐÃá*Ö‰ »%‘èëA„VÄü-þ3Î …’(r¿ÓÍšÇøIùÿ‘±P™Ä³­³õõuï‰~Àáljpõ€‚%`˜WɾA;ÂáXÛú¸¿G羿Ü@ 'rm‘Æ)%#8‡îßÞÐO¿W+Ïk\zï=[‰.ÀÅ>˜4zïú=Q~klÁžôP™ñâêØÕX@ûÿ¡»`2øþwü¢ðdæÆ àêáˆp;3½æ±ò7踣žx >GìðÏàž’8“+Ò¸‰£pÎÄžì÷2Lƒ.¼«Ô°pC±!ùvåãÆ¿ëö]‡‘ö|½Ìð…fô¿g§Â^]€0–û-®ýR‘«ÇžÿD²щsðì®{àgÌ_Î̉% (‰pu0)H —´R7À^úª›³p­°e罜{÷!Ü@·q,NüýèZìåÛñØÌÛßÎ+è„_Æ÷·âÇc5˜#¼¥Þa?cûfAWAäï…ò[Qv+•x‚o@Q«ÇUÊÿçhÊ0þxÞ,4Ó)ÐwWs ¡ó¿®P_A›v#®Ìl Ç3“@Ãx]':uƒ^ã=0!>€&ûhZÌ1x(€÷ÆGþšÍ¤]µ·{W‘æõzNiâ„ïWn·ŸË ÀáÝÝݸ½“1©ÄüS×ï&o¹8Í , €yÖÆ]˜éÀÿ—ŽÂJÈÜlFKš5¹ZÌÇýÇãgÁèÕÕ?ÿ€~HÀG™ìƒ!ášÔ°Ù,¯1 ïÊ´#h¤Ý¤½—‰¢úðѤÅ&*¸àD®ˆ$ƒ›8÷‡.•=št·ý[^¹›×sã­Î[Ó7Ø>@dàpóÕ®§¢q\˯™AFþ÷Æ xÁH°$ Ú½Óc|ÿ?âÜüf¹À¾Múb>?×j¨Ç84-RˆO+ѳ½0F|à˜àU½XDnÀŸMÏ5i¡ÚûEe éZê‹'ÓéÔ@7^­Æ˜œÁAi#ƒc˜ZC’Æ9ŽÆ!#(º®ùnr=§`Ðíß'~¾ù¤pÑZüÊðog™D ¤€ÊÌœ<xŠ —Â3´«îê@vØD~§kœ€¯‡Ãh¹l–‡«ç`XOoàŠ›åŃ.W<|¤SYKz°MÛj¼¦5úm=Å®díÆ>ºå>œp45&B'r§Æ‘Ìà(‹“ \èÇï[ Ò†Þ?·ÓÇ£½k÷¢T„Á÷·#ù~>¿«îªyÅùޘs÷½ùªâÿN '`ÐÄŸÐET_ô –Úý€~» P@`p”ÀhÈ8\u«EøÜà@nµ^á$fWûŽRñ|Àˆøo§?žQ%iþZ{%€Ê:‡Ø+ð࿨5®ûƒÊLØ?ßê–œ¼²“ˆÓ´Ö3ìߣ=ÀCƒM%0 €‡ãWÀ¢Y¢?€‰ÄG«Á~€BHÏíá£[Nnq@CõiåwP-Îâ ŽÐ]@Œ“¬ˆÒ8ÅaÀà,nÿm ÎÀõ}ߢG? .v@~î5ÎDv’€þ° P¼ì•L(K…a^q˜ˆ8’¾Ó5÷I<­dÐÀ `9cþÂ.¯¦ €Q{88tÐã²VìLVyqŒÇ>@ˆ¹Sç¤p#…c~@®nqðc9º¾î¡6k°çâ0îÌ€x|ûÚáf‚×·s·iŒõÿ,ˆÛêd”&‚J=¥‰" GTYé´=hÿ?zkúWL@Û½#7,€Å—År¹ž̳ì"\QËfA6Äî7Àýè8ÞOeÏôñÛÕª¦Õ<ÆÁ{ŸÞ;'?c¸Ÿšœâ°`pbp³i±ýCOЃ×H;Eœ“gð½ÌäÛ¶>×ø­Œ”— ü'€z}¾øVox³ S½¥©bVí@Wíó€{¿Ž7žŽ,€e‹´ î®ò8%c/ðê   Üh`Ýu8àÆðÒÇw÷ማe^3˜Â‰\_gp'Á1 ÝóæGÛ>Cûïûî–÷Š©L¸ôä"E ãÒðŸu0Ôó¦é&ηTZì)-±‡¯ T@;â[¢Uåû„¯Ð|`×Ûï1x$¹Àþì{j?(à—/Ú† @K‹²Z ¸–N€Æù`ˆ»º<œŠq&WÆ%ŽÃ…Aœ¥hp$8á5äùÞí!Bœie>CÿàÜ8ĹÝ#n%à¦hÞF8#dÆ'PÏ¡´\Zî--~¡¾y8\5ÍÍG¢y•€Ž5\PÀ‰a+…–ú©ð%8W(Ž3èhgV· €ãtt¤ãB. K‡u=Z>ã‚à|ÎSÁhΆ›ñ}×ÑšÿÞá2 |oW 4Ç{îöÉTÁ¨ JBŠ> F0 ß†Oo{¸ºi&Ü€¡Ðû¿ž'¿ÿ¼Ñ«i »M. x3[OÇ. -´ t» 7„à .îÞÜ®ôgqK.ÅHãç^áÌ  † îõ&BÜ€&]ð®ÛÞÞ*|?â~_ðÛúöÖß7F{EM±ça'o )m +oùÒrˆ·ŒaøÊ~ÜÍÃÕb!;ö7žD´«Gù¤ÀÀÍÕÃѦ ÚXt\Óþ2 C¯Kûµct¸·<@ˆc;’Ã)Žã’‹ù|Þ;úûm°‰”ùµxÝ{üqÃV×ïý]_f.±2^Ä-OIxë¦Ð6}jï/Ú4Êü"³ÇÃB)À àæ‰Ð½ÿÂX|´“ Ï¿¿2à£'C^ÑÖB°0X_XаwçZêˆàéºmzÁ}¤p«ü?‡W²!Dpa¸·ÆŸ§üÅŒ¾¿pÅð¾êç´ìðĶPÑA¸tŽmá¥mß…mãÔP @ü¹éœ‡«‡¯|"Àð¯Z8€¯"€Ãq‘°W_@Ð,¾à–ò©ë$&PV(j$0fè¾õ‚‡ˆqC/7ð,.ÜQŒvÃC´K,‹÷tyçã O=ìþã`HñàÇðÁÞ¯i¨…_øœVÀÍ‚bøiËÇ›/8+¼ˆñ+zÎëlýÀéƒùQ#´¶[Í{_0Ì#~À‰3¸ÚœÁM0Û†³¸ñW4ª“÷r<ÕÇ“å©N8vÂѯÁ£cºi‹b˜]½7q?$ !VG»-|ÒŽ ­' ‡ou-8ƽ·Hã8¥<Î;×ßÑ{¼8SôK’‡Ë`Ì›ùôÑùñG0àôõŽà:Ü"d¾…ŽðCtVºÔè€ÝaÌüô‚KZ%¼2}ÅN½€àïPÿqø§uPÚóo?ÙÇà/Žà†ñCòzºÎÔaÇ `µêºž¼øè\OõVc~Öš|Л"`˜÷\Q×X‡\TÑ7võ†+õó Ÿ>ãç®Ã_”‡ëkûqjÒÿë½Ëw‡¤Ùšnn»Ð9®ßÐéíp‹òŸ°:èh NO’®-ÿÔ’pÆÎ¬À˜#—OŸöô@Òǧ GóîNoÊÔ_›tíûûŸP>\€Ó ¬‘NÝŽèP÷åíjþÇТ1ÿì #e̯<ˆçg>öo¿ßBà‘„n6iøÈºÐqçlˆ²¤ˆù~ ú^áz{C‹p+²Ù@ÿ¾M^j¢ý‡ðÇ7¬„çUTøhB÷6›¼ 9¼TÉÀ«YÀ?îX…&ð}ƒ+ù¼ZÀé“{1˜æô Ÿ©‡0{m­p­KúcB|„_!ÄKõ— ÜþÜŠ—_Oug}M¸"€ €áÇhþÑì?`7p4ÀÁ( BáÓãã'4;Î(k`¦æM6ž[óPS„Q bq%ÝrÞ‰x=ihoáÄš©qΕn~ÁäôgzÍ>¡€µ¡Ÿ$°ÑÿP!ÿ¡BþClk¿þúÈü†ü}½BúGÏ?~<ƒèkiùb ¨‡¿úg³Ù€$ê>pGðiAë¸|¸ë@xÂ(è$Ò(á/šV‘žßN´ñ!{; è~4ØM¤v?:¯ÿ(OÒÐüÆïcÜ(€Ïïöµc7£özÆÉ¶œ Ù®ãæÏ/l‹_ññã—/_@ÓW  í° ¨ë•W±°ûü› „+Ç-Ðü£XK#šš 5Àp¥ð=ÁO P.Ðñ¦?À§„Ø3yî`†ýË €äGÁœ¸Ÿüø¡mÀý?ÿ¸|qÞþùGÙ€{çiºã`ò©WÜ"ÿ\sÆíA LŠŸ5ù÷(€Ú¿¼Ž3²À?¾Ñ=«€ÅâÆ>Û ¥€õšŽÑe°Å‡ÔéúÃÂz `îño€öÌ?:ÖÌ5»RvVœmŸ7nÔ¾o]€oEx¸A|7è'âæžM 5&ËmEnƒqjpÉ~Œ›fDÕ â Êѹ2÷÷Øÿ@n°ÿÞ‚Ÿz»^ïAì[|êÒæ¹æ:…šœ‘HcY¬!Ã]€ÿà@öÝ›á[…ÿM,«ä À*ùßİ €öF·Ã`Vœ}þ=ÿJ´6@ƒÀy-•'Æ]ÀÃÕ?,€Ç'nJ!T¼x¿¨È @ø€N€1ÎD» Óè³RÀ –Kª½åøï´„ïYWfIµ¿bþµ0³²àÞϯÝX 6 þiÌA 00S¸¦ëä?|´§ÏD&€ À׈Of±3+L1+°ÿ£gb‘š€««@È¿íøi64-íD|3x¿ ðáæFz š0áûþ‘óOÅ@ ã§Ï4Qôá;ͲYFÒu…ÍvÒË`À)o…~:àõÜi £A…‡ÏáÓ–ZüË øMoR;¼v5{~ðc-cNV@o7mVì¹) 1ðóà€À|$ æ_°p+dI¬×<¿s©þ:<›6WWˆ#€ž.þ»z‹õ@ÕOß_/h¥œ<^¯½y¢.Þðÿ]¦ƒù§*þôa³84“> °Ù–ŒFªþZO”‘Ãì\Ãe®µ0Ì5>¿Ïé÷èú¨iB Ððýð1É¿À"É¿À:É¿/€e(©¿ƒ ZF¸³½[™“Î8d}4¨W‹:ˆsóÀëµì䳸ç‘^µ°‘Ÿ`$ø‰P˜Ïîµ…?Í(ç¯HKBùGc Ð~Ñ$Õx†ޱ«±žÂÑ™ ðš¶nw±¨Ç£.À°5¤€ÖÔ•ZŽ=Y)æµRÌk¤˜× 0õ‡âè3 `ÈtðÞN›qàø€Áw²óT¯u÷Üþ]p½Î=*-}æ ÜQ2\Óñêv@x= Wî³ÀîŠíŠ?ƒâT°9š_ zz#f±(€Jýz“¤KÈ @º„œ¤K@ÜÔŸ8 D ðÐÛ)Dh½ž·á6dæ÷q¼§ƒöf¦G Qu:%O Ž{ªÝ+lŒ6(ê8:ˆôüE™°º÷ñ8Áà ë1Þê|'°“ÓŒº¾#˜œí¢à €©7µz²˜¦Ÿ€Ù>—€Ì8{0Ã@5à* €]îy9Ø*€»Q¡U÷ñhâCþ“A&”¬?|x¼–ÅÀ¿Ì\äd²T È¥0Ž^½uc‡ÿ`}xxOÇ÷è±½¬âàâÎO€6 08 ÌП€lŸÌ `6‹ÐM&\ðqZ´Ázþ6Ðÿù|ë}O!Ì8FÁn"ƉlŒF´—Àn7ø‹W#p^–PYþý.`Úu0–êèÉÜ0 "‚¯U0¥§j­ÇJ±xgoyŒ£,.:ÜÍå `f¼A™Ô?YA)þqTˆ Hà†·´ñº„$‡¤@mæµ'cÅ¿/_ž‚õ|ðò÷<’§éÜO¥õ~Æô€ï›N}ñµðÉ^›±w<)3^4²÷Y,^OøŠMù+ ÀNö N<™gs:¼nÑ9î"t¬³6#€Y(V€@z*Øñ¯®ŒùÿJ!-C¿jn1ÿ"O-žÙî¼½åÞÙ­-€p½ÿÃÞLò²ãýÐðjŸâZŒL,˪;è@âÑõL¦ìyû9e»áú[Žj_÷¨–~õ¿PyؽCÅýoß_OÝ(€q#Zßsx=i¬˜`"ˆßUGÏøçOœAB41$ Hó¯l@8œá?-ÇZÊ@)˜•ÀNñ  ŠL€@°žÿỞëß?&ÖûŸp'È'çSxÄëHéI>矗鮯wDÀN¦¨—¦I9ðáÀ\VÏ?FÆqÃ@œæ­ÿ÷ãÇ1pö‘ø·}‡ÃgÄ™Á±sÄÔ£Q€ñ{X»Š§ƒDUb^hâYøs¡¾p,` O   À^®÷‹õ߃)<†8¼ÅóA IDATOó|gz¸øíÍñp8>¸§¾<}ðºW§éi*X&ëè‘zÀ‡x®š@pIÜßÏ'šãáÂé­?ƒ8Ÿàf¹‘˜‰ Û¦*+€Ô¬@×±&™%D`mIó`<Í¿ëoÓüïì}¶¾ p}¸$ œôzÿÓ| ¾`ÿâ¸%T4"¸¡Ã¾|´Køÿ`^`ËûDOä>>ñZ€Y Älÿn í¿©FõøÇ¨÷@çu;hßün†Þ|un9ñL Í‚._æ…"Šqí¨XAf„ßæ À°n ˜ùð7„Ô}J•À•@°Þÿé»[ïŽ?3Ž½Æ•Yî}ÜK'!AhªÌbé`av ÿuÏ. fXƒ±âbœÇ𸠧³Ðþƒ&+·«E&È”×xÐó^ïùÄí€@ÛmÝ­ºyg§`yœ¹Ÿ:ð®™qv 9‡¥€¤P Hîü;@âMòWázÿ'µÞO€pèèðÖÑ,÷ØÅ^ZïÇÕÀ«‡¹W´,ħ—$ϼ'lO£„kÙý™Q€)A»êuö»‘ŸŽèà{íM-kœÒòð¾OFíxe÷ƒ™]a´…ªÍùséðjTN_ ý_‚-aÞ ð&œQ ÑÖã­›Ïíùg(þñÙ-d¨'è½U øP-ŽW8Î! ކ^µ¬‹Á¿1ÆÞ Ýf-=Éì©x!ÚŠS·n·Ç 8?…çÈ'´HdB7†ïGƒ›üãðzh˜y`§Ãµp8i”êO€û“ N ôy³§UÀ#€Úý‚MÝôÉDX þýlj,»¿\+@í–kýÜÇ;ÛÙjl·2Ä?ç™@ìíy«ˆÝ Æû ^r.à-н€ÖÁ_ Èo —e€/ÕŸ õMô=<<ÈùìOdÇoëB‰Ü˜ W²íþüùÓ‡HòbÈÇë8xgÜÕ[ =ýÌ ‘­¤¹ƒ! ¼¯i™´“ƒx.`5·¸jò²ƒ!xԸ™ N…Ïv¥ð> \Y»¢/AœKUö¾ïëÉXÏ’õ´¶„§^zz·tà{¢Ãý†èÇPª¿ôMÉïx4/ž>Ù¥ =ïêÓǸó™Ëw.H÷üâüŒÃ¡büå¡N´4¡×<_‡š# ÞrðçÏx¬þƒþÙ[ó¿Pg.üå™LÝoëþŒãáNFÖ¼¿„K¸„?'”ΟrbJNbï¿?/ž¤ñ<Åó¹ >cùû/Ηÿ?/ ž¢ØàÙ‘,â‚¥Ò_80y„Εÿ?/ žbXðÜ\áŠã0}w]úþ;KþÿD¼t~<Æ}5žbXðÜl㺑û÷×çãSù<—ÿÅâ¥åû³ðÒùñÔxŠa‹kÄé{ðî¯ÏÇ'òçÎϧóOøKÊ÷‡á¥óã!2¬ñT·¸é{VÞLJcd,Žü žÊ¿à§–ïOËçÇ}:ÀÁùù0ÿ%ÜŸg|U( /Õßï†Ûó㪆=‰Äx’àº~0ýÄý½óñ¾ÏÏûø¢€¿¼üÿ]¸œG}à^]SoÂÍÁƒ$ÎððÆá«:Æé2ƒwno™Âu~OÄS÷oJø(“þoˆ/4nÏ#N»‰þùó×ârƒ®Âë_ áÂ_ ×ü¾çû—ðbþ+üæ&@K8F˜úÇ_‰‡ððD߆ ? Üã÷¸Ø;æÿ'ãºÚóã6Â:&øå¸Ÿ3øv\´.üB\Ö/ ù+áï\þ þK8ñgÀçÇ©‡˜q}þ<‹/ä1îg Æëóã‹Nùûp&0;‚_‡×¶ø}ÊOô ãG-Š% pŒÀ½ DxÁßg†RøB1üÓ/áÆDœ­|Çî7ÐA~Ýùqˆ1µúpR8ÝßÜ@ð•Ãç¼~ Þ½®>ËWÂE§æ/Y?%ù+áv ïÖiÔl• ^ð@éëK¸³gÊ[øA .á2WïÎs„¹¹¿w…×9|U¸~uÚõY¼tÿwÂC„å+á‘r÷?O @å_ø½Yœ†—Ïÿé¸#¸€óø7•~ŠÿèþÎdò·Pü¥óŸ|~€_¾/žÿÓñþ¾ðù×éûÈÜß —?_Éü'xP¾/ŸÿÓñý¾àÖdúº‡Èß_ÏŸ~>@&ÿ1ÿ‰òEç‹KçÇÿt·/ ãLp G†ó÷—óÿùüåž ó_Â9„çËKçÇ/ø0ΗðMÁgÓ—Ãß÷Ï=@範§î_>?~Á‡qÿ nE’I_ŒÄÀý³ÏÐÙ+á™ç”Î_ða|QÂ) ¥/º?Ç(䯄'Ó¯Þÿýõ:.`ÏÑ+é—ð·äï.á.á^Öþ_ë—âÿû[66†¶U3}€ŽºÄ£ø!ÉÃOš ¥ëφWï“~h¤c\“–b˜^'@^îpHèßÅøÄIO)l0w³õß û†æÐ×w=Óæ¾ÿ†2@Ӈ;éñµ¸¸õÔ€ÝàVFý^]U5F%} ÇkPºþlxõ>éWÂùT}ö±:uCxò¾&`ï4BNVHñÞµü°W0Óþß}õ÷ßwÜ ?!f;ú×£Q怴eŒÑå£ÏÿÂ'|×3ü}‡ú ¢QawôvÔ;tèU¹•'W¿øjÆdýEµÄ`þ6•zdi"ý WH_ŸT€ðïÝþ÷7E+Ÿ1R æM²ö* ›Iìô»DÌÈàˢи—Fˆ ¨Eâ~Øo3[7ëê_ý½ž`{ŸôÐð©s@þ׳vÔ´wàè¡! ]Þ5ø:v2Á_“vÒ}Th)¨åÓ{0>Y ÝèúQ™öñ ²Â8úÚ°†ÓõŸÁU"i<{}xû“ïïÊ@F>šÄd<|]ÔÌh`f°³¦€®£&¨å¯×»™‰ÐÏéšòžŸÙµ?c! ÝÿÆåƒY€æßv³¦¦Ó.˜µôF÷–^|LâÔ¤z­ÊhÒâ«oMG€VÿŽå€ ¢ðéÎI r‚ºQöÕVITæÂ4ÉúÏáQúþ<ºýÉ÷we aFÜ…sÌ™<‹;€¡sf°“wM›F#÷ÚñɼÝfC¹™<ß“fÍh¦¿šõßÀU£ÉG¾›ú‡† Æz6¢Ç=ôÔ &à÷Õôrô@TpèÑ·¼Ða¿ßÉ;Ñ»Î÷Jý£ê,Ù‰hÙÎÕÿkðÊÿu–ôMî™´ÝΨ€Ú¾y½ÅØé„t/k¡7î”§·6¬nv„lø…ö¥>ÐÚùÄ1¿\.ÉÀ?›Ò\’×·îÖ#ÌôãƒÖÜ>!¿¨gî'#üƒ^¯V¡g·øGÛ?à?Ú*n’qùe×´TV*Þ9.â•Θ¾É½z;Ø.áÌìëãfšŽð&vfÌ,ñ¿1Ñnìã»Ñ‘Ü?hñDÿÌýœÍF¾„Œý~êýÛÄ$f[”¾×´§yAC> ͈¢…øÆÃ øxŸ¨{;›÷!ÿ΢“@•®á\üJ¼2ߟ-}Í·_jŒU û6í?¹öÿÌ¥Æ)Ž'YŽ$öCC@¶Ôø—ôß ‰æ—œvàë¡áÿ4> ÷` bà6Ü!µdû±ch‘ÿ»ød<=š(î¸ñS/À€Œ üû¸²î^*j†€´VÀ3×›{˜±Â˯ñ€bšg0òqï~%‡>,¸iü,oÒˆ¯]ÏäÕÑ€‹ñÍØ2ÿ,d¹a‚p £EtÿÁU@÷°­§èí“`h‡M›=ä¿Ð쀹ÁŸ²›Ñþ÷v®0¬ €ÔÀÇ ) O€7Ätÿâû»„Ýõê‚“ïïhX²üÇ/wå’9<ñÖЙ~?¼®©C™‘ñ7íŸßêæîÖ p¾D°0o]Ñéûé¤EÐØy;Nñõö#ä!¡Äÿˆ7BŸ 0ñÖ¥õ£#Г@Xòt*†ðTú¿S®§˜ùï÷7§.~@½ÀNš8F.­ÐBl\Øy÷¾ë@­¹\/×hêqÓÚzBãjý4@„Á Xzó"lt;vX0l»V/ ߉¨@-À·7 ªÀ  Ê  ÒÿNºÿnæ]tÒý“ùwowŽ'>< }%žö¡n=ôÂk5¾Ùé> mçköPäP–[ñÓÀ³çù?êÞA,Ð' Ñ¢|<ü‡Šð{ÔÒ(hF Ç=óßñ¬1O‘ݸKVð[à¹Ø…¼²Ýõ•âüÏd7Kòïð6ókÃ/9; PÓ äPHÀ^ÜÂÝÆl³ff:þÁhÿ&qrw¿fÄj§0.h&­qé1F  ¡)bºþŽÇ€D>vô^aÑOêCÓüGH$‰û¼7y }˜µÌñ~6ó%03ý¸Œw~7ÁߨöÏ*2I¸›±<Œv¦•óÕÿ–)#ÐLM„¦]ϸ@?Ÿ¼‚¡GŸ]@òÿÈhè7- ÝÐüŸqùw/èK†É à\o£éa䙇‰%¼2ß{ùgeÎÌDÐ̬Ûh‚y¬'¸ȯ-¼ó°ó‚ãü™$lLœÙÚHàξïÑôk¶fy †ù8À! Ø÷þB4;4iùµW£Æx4hy&l·qš ª@³@j=à䉠dý–ø/O$u¢¨„Wˆó¿¶³qø» ƒk™®õ >sÄ› ¨7K`ð™ÕO ë¥Ìa`ÈoÞ–¦¡Aã<ÓߢAÀ–NsÁw-ZÓü…hpȃv P`¦jó‰Æ¿FEâ¨?_•ÿ+T2K{ýA´ËL½'úÖ* U'±!'Qn±¢©`öýŒ#Hó@ÐÈj½--ãß#vGS\liã.¢˜ ï#VNwèÒbÐÎÿ“òyV¸Ï-ÅUsÒbÊ^ZLzábÑ›ð*;¦è;²ÿ‰-•\àv}Èu89!QØfÐjiüÞ á·wšæûƒ€j´ßÐ{Бº5ÍÀ °…}SÞC›ï5ÜL&(”Þz]g6˜@z¨Ôž²Tꂟ"€"q]¾ŠÀ7ãUŒ;"Mc¯¢À¾rÁMÛõ O#î Î71õ;»Àiým²n¼w?…<Ê‡ŽžÖ‚Ú@ü·¸$0ý;²=ÁÕß¶aW ©'¸|\Ëv;šø­Å ;PßyïŽz¼ZÄÙÓÊx‚§¦F|ˆÿʲb‹a6}¨‚¸»€¯.§w±»Yý™dЗ¼KtFB`p‡"hfvÀlæhѸwØî'ÓiC›Bp ýÄÁƒÀ~׹툧„Qn²÷ŽvÐ^ÀšgêpcpiÃÌ›ñ¸:Ï›þ©xž»(ÎÁi«×Ì‹,Í^Ð5©ÄÇ׿Ï5èc‘Ä̆zͤîÚæÁ3‚”Ù¿ÙF·Ý¤jÀšõÍtD죇g&zû;~åm€8cˆÞ?vÀ·»;žý§Ž€ç‚ï‚]/àÍx)¼÷ýcÄyX§{~fã—ˆÀ¿Œ¤Œc‰·æ1žùš§jê5/ôâˆÍƒÿÅp¨×Ó’`Cë|´'tò×z*‹=w4ÅÓÑD{ú .¡Ÿ§H¾“­`½ÝL˜©¡Lý¼/…÷¾¨€8…,«‰=ŠEœ$í-M6ü‰¦þï¯ÿo6™´ ÒÖ@#€ Gkw=:ØÀ[\À?þõÍõø†û½:< €“(ø1ÁY}@ #ñ {„‰£³ê;^ ï}ÿ™âÿå¹óf1’èçÎ)Åf®ZW†ú ÿšbüo0vkh%¸Zßÿmño¸\0á– c@|öûw]Ù£bwf¤Î: ½*ùâëÞlîÃs&“Ãô½/…÷¾¿ðÿª¼%>ÅèGrw9ÿAÓÂkÉ‚¿ñ‰ ’ @C¼ý­á¶Ã•ÿ;^ l' jBPhÝwäôcû§¡]ÕøUòX{ÅÁ'ÈôÞÖ8‰Û/ÿ•Äq_/íîïÇrDÌ w¸÷ûŽ6ã0Ù¾/á'…õÛð4Ü›Íè ¦wò“?°qƒ<.‡Ã/á.áåá7¿ý©x&< B0`3§¸?‚¿Aù_‹ÿæï·?OÏà°¢+ð‡&ûµŠ9ÎâÍoQþ×áæ¥vëð/Æ#¢||(ÿ©Â[\8NÞ_Àtþ,˜Ì¿A³åCì7ªßÿéﯯ‡ñáü…¨ÆÓ0¸€M2Šã·—&Ë'`®üÔ04Xõ;óóóß_?|ÿ¨v4žlÿ‚[ž’÷w,¦ò§y„ÛKÓåsh 7`¶~(úô]ùy‡÷Ó{$Ƹ_ºëÆÃm]'ñd·¸@÷â¡|<€Æ-š©?+[¿‚fñº~ïñ~z/ïžhÿöp×ÄS÷×M<ƵOà"SC½G&À»>anÑdýIAëLýJ*¹úgôõü½îýóŠäöñØÀ{xlÄ=ܺqÉü%›¸Å=ÄxV„çMâMן$®ßP9‘áÇ u–?Ü)2į¼_W”‰q¿…xÔƒ‡¸|ß$ÓW6<…+O='›¸Ã=GÎâsÁ­’¯_×m*á­Ãц÷Yœ Žð€à ÎàbãC<€;8‰'¢ñ”@n0NáÎáq?Èþÿ ŽÀàõ‰ÀG-ßÃùP²4{üÛ ¤pMp÷VxR*wƒx ‹ÇN€‡çà‘ nÄ•B¼ ¦®åIY‚Mã~‰rÜÛâ^¥˜~ÿýõžùo¢ ðGiqéqZªõå/ÆÇ~òéë‡p2žˆ§€oT7ⱊS„“0¼}„lÊ$¦_ß_ï5ÿ €„ôSqK`ŸÎ‚à³àJ)\OI ØÂKÄC#&¾Ž~~ ÇŒ'ÿ>ñùùùø¤> Ïåÿ͸U@W ˆñX®‹\Þ|m€dÕëÉCŒΠ6ÿÒÀü÷ÛG $ÀÇQMãU&ý">®OÃÅ€½·7ÈáZ \w1KÀâçÖ9Ô*!Z‡¨ÕäO#Ë®æÿ2xWŸ†»à]ØC¼«OÃc îEHáúI\)`¯’x,‡7y4!Û”?ÙÇ4ªuï¯÷øOàÿI<H„wQðˆ¿ïêÓpá/Âu„$®"¤q§€N1b<ŘÃs"÷ËK&k[ADóÐ,îè÷ð­gþ“x¶ÿÚw„í;Æãâ±ÂúñpŒ‡Çõëæ9Ó¸§€$îŒ@·!Àãîýò–~Ê¿G0“ŸÇ9Nß:þ3xDo„ûû1RxdàC<2óâ¿Ñõ¿ ÜÝ#‹+$q51œÁC‚#~#„oO7õc ¼˜ý.±†qÇ^ˆ÷u!Ä“ü{x‚¯Cáê&¾¾]ýH™ëƒéúuÒ¸S@¯£òJ ů'‚ðýò¦~¶§âT f÷bx†}?F*:F:ÿ.F®|![~I"_?*F¦þlŒ\ýZäê?"8âÇQæ/z¿ü ñýÿ}ËnþþË'’¿\”_]?'ÔŸ$ÿöx8<ËEÉa"€û®Ÿ š€ê××O±þ.á.áþ¬ÀïÔ¢së$Í;:GC¦»¿îﯧ&\_ÛÓküóþþ¯_ÿKxc þ»vLçŒp Ö¨“€ÿkâÞ*@ÿ¸¿ÿÕù?k(9Ag:ÿ>ƒËv5”þy¶oÙ8ñzhî+:CåóñæÃÀùw{®,ÑÊKç÷ÛXí¾yn’¸€‡7Ï›Lú5=c“ߤ$‹5:–À_÷¦EÝ›_ò‰ÿ4£€Åâææf@4ûH ¬£\( @?Ó“>KWa“•EP(Ÿ0åMö|åί§—SZbPôÜúû8ò?Y%p+ÿúIK H¥ÙUkd.&1dã?®7­ð<(*3òŒNV@Qÿl;è³ól:ÒM 8å||¨E‹eÎ÷sùóû1èŸÿø·8 qýŠLŸ ?ø=P8OÎo€2€a ;~Ä?ØN|£ÿÅCLùŽ`€ü?G®ñ© Î=ÿÛãß èßžÿ¯;ê¤óñ–¹ÔùOi#_ñùu½nïwA«AA þ' ¸~¹D¤Òç’‚€ö­ ø™Þ°ÜÍ{™ þ©fYf$` ë¨Ã=Ôç€u颱~HûÿìjðN;¯öÜ9Ü) q¾ßEô÷åE8Øgzï]®*gþG£ÎˆÒ‘ ˆÓ¯ÉóCèog;ÞLÝ÷l8±É¯ė °^!ü½xx8nn þ'ŸŒ ©ù|KÝ(ÿ3ŸŒJNà ðHÕc“~ÊÿwQO<Ÿ4ìwÌÚ©MþέW €ùFcä€ü¨ˆÓ‡ñ=E?@OoV1“>÷±lo‹”nC¨çÛþ=@ eÆ9ÿß^W»àØQ_„çßÃ0÷€PÙ4ÒGÜb¼adçògþ'8M÷@týr ja?€ÒÇ ¿B,ÀÖŒ)lgôŠÝù¼w>_f…à;"[ @þbÈ~D'ù‹P€0–ûrìôX ëÿ§çãžW®Ïÿ{°>ߟ8ªµÎ1øóD.èù6“ óŸ W+¦~¾ `£>Ÿ0ÆU€WF>äÿÏÇ$@-¿aÅù#ÈTpJZØ9_IDAT77‡Ãø»ó M­ž&Êùÿzs œzþ_ÁÁñïPþñìÍ@+žiˆiùç¥Óï€p·!4ž(¸@ůqÉÓããÓvÛŽÀÆt}wq™$¤(ÀÍ à&+€ž'ºEP¬ÜX€BÎÿ?]/;ÿŸ¿:¿þ<LtœÂù?]íˆã‹@ãñÄ\ŽÞ>N_X<>~øð¸ÝŽéEìóÎÔS€ºå`Ýëã¿Ã]B_ºõËlÓ¹@!rï|óûÿ§Y õ‰çÿÝRçßóç×Ã`ÿeåQH Èm=Tô>eg@«1‰„ò±Y6Лˆ€~Ûíd2»6&° Ð@øOàp<^p^ã`—p;¯OÝœuŠŠ2âY¿Ôùw¾¿²Ç3N;¿ÞuKóMø;މh*Ã?9 È¿Nk Q–YTxcgÀÉX9,éMËFÀÿ÷ïßAÝ5ÝR`èö`ýl¿ À¶„pu¥ÀåeÙ㜠`~F šøºˆášô Ö'%Bˆ''ˆù7’m|@pÙ äï ì.+á?é% ÜB#z^œiLŸ0§©!.àk¶0IvŸ?|¿½Ìp(¼êêî^üI rÑø_ ç´Þ: ,9yE'1zÀàó¿Éóý#ÄsË€»­BTzµg9j°£ýÏ B@†Ÿ[óÅÄM(ý•Y@à·è¼à”ߎ€€°“cÊÌu< ¸¶#­PWÃØž]…a^q˜X<¯+Q~gÏ÷ë8ÞùõüD’GP’`Ç7Kîÿs@0žÛ®ã§¦Lú¬€¥ ãÅ¿ž_÷hz€Gš ¦ "³ê“ʶ +šêQWW0äøV¼Š:Ÿ£p{Ìy&‚J=¥‰¢òùxW…½¹óý.Júü~ή ù‘ñÿ² 6Ý>³8”>*ç‘ØÂЈ ŠËx"ðñ ÀÛCi9 @VxBÐ à €Ýÿ­ >Ÿ†§zÓî¡›*®ÊçãÍצÑÛá¢gxU‡û« Câ¹`™ÿÏár=úC8P€›IîÍ _êìƒh- [uóî/òøcˆˆ_ØÕÿ%@`ËßÛ½Üc{òÒrpi±'ãÿëmC¥óñôeã·cûüÇçŸãóûI 4D]“ ùÏãöú’øúÕ£š¼ÙÕÀ™‘Âå`KðŒwkZ(ÞÉ8Ðî N ঠ€ÓOèœ"19(-c(×çÿå›óýñ†°øü~j‚8K0¯ÿžMÖ¬PøÆåÔ†1ͰH@…{;AH‰ÄÐü;X$6gà °ñR_Öÿ×O>Ÿ9ÿNßúûÄñ¸Òù}ÆòÓúÿù@ëü%=µ¢î®–µÖ{2°ûÁdW˜] Ààpcè¿ ¶„™_¼7ì%üŸ -³å+çÿë£'žO‘[©«N”ØtÊ/uš$Œ«å0n®G áöú•ø‰Ý˜ÞC0w89lí\×68³ÔªýŸÞöPd$¥À!½)TU‘…Þº-ü„MŸ9ÿ_oÞžv>>Ëmp¾8Vê€2ŽÝ˜ *Eá²€óõ$€<¾¾î–æPþ㽡4qÙòHdÈS€Ú!,é,< ä·…GüŸç\@aÛwìÿ'Ž4t>þ çß)åâùý·…ÒÉ 8ô¼W±“ƒx.`5·“çôÁk;=#àRÊï 7wJ5ÿê<(ü(1A­¬Aó~žóûo ¯€ÙËnBO'ƒÀöðT@Ýß„+ëO;…tZCôÓ½’õsÜ+J3G¿Bÿ?­€?0ÐQP2þ¸ œ]Xüeйá~p»D.µøŸî@VFÖ4ÇÃÝY0ÛöÅ-üÏ?n}» ÌÍQi7îq†P üsTazŸüÏÁ%–KðRùŸ ®„aÀ51Ÿ¢Ÿ‡/‚°Rñ0<=}úôáÒM ^@ª],”…|‚yof~R¸à"Û[úÇ&˜³Ò½¦ßÍ‚:wHÓƒkàL“$³bï‡s€Ÿñ;Þœ!WòÏRù‘|!öö6Àã#ÆùüùÓ'ƒ»¿øü™%ñù3v(ÿA]ÄEôÎø#õ¼é–ö]Ìål\Ž~W>Òƒ)ÂBàûâ|6ã°óDZ«X*¿þÛ[Ÿ~ük¿G8ó/qö{v]7€qXØ•¸®ã? \ð‡ @Œ?þcò›æ™öáLjø«_î3 âúšÍïáð„+þù‡7Gó°ì­øÁî t'€eàn€?ã¼3Ÿc”ʺ~H.ÒÍT£1ó/`ú¹#`Sqð*$¯e p÷!‡›—¹ü<=ýäîã"€‹¬ùgúyƒ5.±¼å` 耤9úð³3ÄçÀ…x÷É,ƒAüŒ¿¹‹x™¤@òÄ-Ä.à‘6 3*R-Î ¦“D¡Œ|p©¡Ttçᇧ'¼ÿÛY}A¸àÀj%äFÏÏ? à#t°@÷04ùa—à†hHŸéeÙˆ¿g0Æfüx”É>'»ïYš`™öÅŸ¯-;n€Çôêaá~›É qþ›ðøè;‰ô0'›µD>|H›yžŠþÉSÍ\°âÁ“ÏôË4 Ú£¦…}‚%0±†qv…~€LôÈg'”0ÈÎÌSƒd 8ú]@z˜(EĈ3óîC@ó‹çÝÃE¸ÄýcçO€]'DbúõdÛyïôrBÆÙȧpþNOù8‚ÅÅã¥'<Š­àÊäœÂÓƒ4}··ŽF^ôqpä»)aLà 8´›§qÝuè ‡›<õ“ÂEtÜÈCÚÜB.ë‰ß˜~xÄ¥ æ¡]ˆ#Òˆ± Èô®æùN^n˜‡ñËäc`Ã{!y´BÓÐKÅ‚j#®—šýð!j7QÒý)á"€?\èâ6h:uÛ ýôZ$‡âŠ Ý¸aÓpà&m”€Æ‘,c¸à"»%ÌÑÏß¡ÂM¡zXÈM[nŠÖÑË$!.&™—k5ÎS·!ÁZ ©pª‰/¤ÃÄ}·Aœ±x2Èm‘€´Ëpnc¨lÉmú¥?5\p€:¢†ñÑ=ñ£—ƒ¤SiZžœñ7d:‚ÉZOQYZÌ9ý²U#ÞÐáÕôÁvÕþ«†\ðÇ >*ßû“¿N⺥š£ô0-$ë”aœúxßÒófMtÜd³ÿc®M2›xÙØõ_CÿE¼Jaè}úç¹ÃkþÖéøx|ïN üA!W­ï)€RúñÝÒ÷ñ\ÉÒù.•¨TîRœ³ÎÞ- UÝ%ç¸çi!¾ÂO§T ?f:§ås/]zíüÄ+à)”œó¾å»¥îãî{#Œ›ÎÅ©yÌã¥ÞZkïN/Üy‹RJ?¾[êþ1î¾×1¸é\œšÇ<^Já­µvö/^®ðç*J)ýøn¥oâ¼çî4œ‡SrX¾z¸v›ÏâPñÏQRúñÝJßÄyÏÝi8§ä°|õpíþ&áåÅ;_AJé—rT¦?ýÍð÷ùû•ïî§Oá­5wÆðÚ⟣¥ôK9ºà áµÅ?G1Jé¿6G§}û6Š/8C1Jé¿6G§}{@õ–⟣¥ôã»’ŸÓ‘·Õ@ÙEJÿ­uw¦ðúž£¥ôã»’ŸÓ‘·ÕÀE?¡á݆ªXÿ§‘Ц—®TúrÝ”ð_† 8„þœB UxGÿ§‘Ц—®TúrÝ”ð_† 8„þœB U¸ÇŸJ#ަ—®TúrÝ”ð_† 8„þœB U¸ÇŸJ#ަ—®TúrÝ”ð_† 8„ž£¥ôã» çä´üž–âEëç¿@ÿA§§æÇ¾ª”fùêRýþáµÅ?G!J韚£ÓSóc_UJ³|u©~‹ðÚ⟣¥ôOËQ.­ü·Ú|ùýNÃO©ßß"¼¶øç(D)ýÓr”K+ÿíE^Ègo¨øç(D)ýøn§ç4÷ýpJ9,_=ã­uwÆÏÞPñÏQˆRúñÝNÏiþîûá<”rX¾z(Æ[ëî¬á¥™?W!JéÇwKç ÆSwñcâçá<”òxÊÕ¼è¾å»¥sã©»ø1/ÂPÕ½W!Jé—*<Îy:_ñõå<ü,ü· ©Œå2®B”Òï–ºŒ§ï“.e©lïÿÖ!—ùó"Lí¥§&vs÷‰c•ñüxúþ¿uÈî|…S{éß¼%ü?» ãQxÐIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksDoor.png0000644000175000017500000004517013263214224022041 0ustar aeglosaeglos‰PNG  IHDR |}/ÿ„PLTE™™™wfwwwUÿÿUUUÝ™D»fîÌ;;;™™Lwª]»nÌÌÌݪªªÿˆˆˆnnnfffîÿÿÿÌLLLÿÿDDDªÝ™ÝÝÝnfL»»».àë IDATxœí cœ8²¨!˘MìÉŽO†˜hr6ìñî]ÿÿÿwÑ»$•„žt7îšL›–@% ¾Ö»Ô‘Ö2®ÝÒ¡¤ëþJ‘Ñ+¾¥È—íFÚËp„ŽævdµÄÎ ó!ú•·ÎüA| ]¢õ²Ë’¬—^ð×ßãå_0/ñòå+½“ÖBÖ#t´¶+(6ýå$F…E›VëÌ HŠõ²Ë’¬·c*þ7Z~€|‰–Ï öoä­5@Y-"úÅÌ‹Šg1óœd•>¥ãX%ïGñAºDëe×%Yo—ªâš]á‘)â»â€7ˆ"¸ ÓTqKu¬ÁÈ怌Ëþ9æ+¡€Øõö• <2^|Wá:¡Hãb;˜§i.„âÑ÷kFÂ!$ C¨Qug„™™ÓöTh½¬Å0Ýk ØCLûAó]Ñ_ I„øJ‘ ÎÅv0mRÇc }ÅŒ„2"ªqñ/Ä+çä×ãÊ>Wz,þßì·Õ„ì^{^@$ü+C‚H@8ý2Óƒ¹‰!C9#|¨Ê+)f„½¨îH@þøãß9üA¿páßEÈׯ_?Ó¯”†¯ì[ #}Ä!ïEÿÊ ÁE¿LL²Ñx0)eÄ›³mGʱ‰³^ve’õv@Å4Ñ„~§é&lßé{˜…iþº}L_7 ì\C‡ ­ý†n2ò' Ù½ö@~'«EûÊ‘€.úÂäò±ð(fÄ— ‰K´˜þžºDëe—&Yog¨ØtüÎþLÕdúú™©ø*ÎýZˆzÑ€käñ0ù´ZD°¯ü¥@$Tc,ú.Ãx”1‚?m“bF@"¬—]šd½VÁ犼úƒ&?Se@æ¯\=šéQ~ üjB®¤Šõëñõy|€h"X¯.ÿ:›Ýl#é^<òA¶…G9#¢_´K´^vm’õvZ×Á50ÿ«Ê®ÿåõ9? “R!hÌĨ((B®OGÈ£Á{u%0c‘ô0™Œ ã8ëe×&YoT¬¾&äGóN#•KRÅ—]@V^3¢ÖíT±¬Š´$d÷ÚãIy¹òKˆ¤g5Ò1<0 Òq3áÅ£€9°Ö%Z/»8Éz;¨‚7q~—U:Ž!¯Å…éÓ<Å"ÍZf˜Ë‡"d÷Ú“ D6Ò³ºyQ<<$0bg"ŒG.# 1ÖË.N²ÞÎP¡Ë&­âw©#ØHŸæ@eňpÃ6Ã>$!»×¾@>ŒPŒnÞœBúÄ<ºÎGA$#.,•2FÔÌŒ.ÑzÙÕIÖÛùUÈšíIÞk¤³€@ìV C;*!»×ž“ˆ¶Qœ©&ÖôNŽ“FP@LkzHï’þ1CÅѪŽù‘?áÌ€("Àú©€Œ¼²òB$ëéŪj½OÅG˜½R~å‡h”8ŠDš>ˆshbœp^@2²?Éx\ õ¬·óªp>XÍa6Mx”¬Ù…·ÇÌ›}Ø¡xH@ ö ï†U,¾‹¯ìíÍ{¼—¤šõv‘*fÑÌ‘^Ш9ÜH×( …‰ M„_xZ@¬*– hÈXˆºèú)°Þ.JÅ [=ûßRGA@x«+á¡A@ÞAÄj¤ó€€ HîÎ„× H‘õv1*>ÉËyõŽþs£ôQ@Ö}@ÀÉçÄêæÍ¿ !× H™õv1*X'±jõ|ÚþC¢ÀQvsüÿsB©>ª`‹ËÉÛ ð6šBFÑNÏäZ«XeÖÛŨÍÆ¿…ó1¤9®CíRb¿ÿ>iºD’ݹޤÌz;¯ _GÙG; •»yñFz°ø¤€¹DB«Y§(AªYoçSáj±Tä²& ºkÕoÛ š®©È5• õ¬· ¨@ë-%SMŠÄ7ÕÄ¥ÁÙšiÍùù=ùz9E RÏz;\E`º×G“±'‰,ÂM7©“¯‘&Nɘg"®vóvm““­·CUÔ”0 Îï}XvÁ–WÝêšô ôbñ7HUëíÚ«’ôPHسâ¹Ö¤cûƒÌ%·„ €*€<ÝISaò×ß lÕ°#¥3öb™DˆíBæü[Bš• OOw@U€üüù×ß϶Uˆ™Ò> Ë4-êät“º šµŸÎÜ•äÊããdͪÿúëï†a§¼Wˆ•’¤a b†µéΫÅT»´m1ñBJ¡î§äõSK€üdf½Ù50ì”÷ª±S€Ø4Ð ~X H¦ádÉjq RòªXOO—¤­õÒ›ýb­D"¬šÙõÄ»ÈÄI ÂO9- íªXJuFv70<€Œm‘€œBø«ø©Ìú¯¿ÿ§7¥X@XÝ+þnʧü#Þ˜ùÍ‚ž‚]¡ÓÆ«X-éRÒK†ÄîæÛ0r>@~j³þý¿E€ )¡€pTª{ò‹OsYÁ?taý#ü&Cøÿ"ôÑ9źÞH› ôæÝ¼Y€ˆ’ƒB¿Ã¼ $ÃKõ£ÿi!g¿æêÀÓb7óûß¹UÿþŸÿüg3ëÿ—’’ˆ¦AIr ¶ ÿ(DQÖ¯¿ü \ÏÇ Ý¼À†¯§Š¥ªVOÊ©kmÂÈ Ú ®dy´~õ¥…¥F=²çéÀÓâ€lvý×ïÔ¨7³–EH nJ. ŠÙnŸêbÀÿü‚É*‡²°XM 2œDÉFÒUâ»Pè9  íñ„áÁ¤:#}¯v˜B,.£kK‚bƒ¤öéc®<-ˆ°ijÕ›]—â¤d÷bM ò¸ œfÑüU!L^®2–@¢~YWöëAb•wR£íáÃIMFèÞ>nÞO,0íü€ iÉÐäÓ¬ÿ›’’3PØ ó§8¬ª}"yÄyµ0·n¦›"äëAâápƒ‡mLé{/ƒÌ}w³€ˆ‰“í‡ÿ?´Y“|@”ŽdõÂ#‹ÉX3.?ØßÓoH> nðÞ¶&ñŒP z„‘…ïíÓ`½®¢µ8KòÇfÖ˜|d⦈¬|b¶%ØKU¬UÃO V±,@~A@x2öúÖƒì‹Á 6ŒTÅßâjpˆØúª1 Úz;\E@ÛFš›µzây…NJ. ІГ‰eËX#Än¤É8»Ú×HŃÉÊÝù¦hßc„ãÁªo#ƒÞù꜀ÿp»þ/xæ™SM씎™Í Š€G_7- B>Ân^ ÷z™ÌÕâÇ £A`Dâ!Û7Œ‘eÃc!ãx1@àÔR@X"tá¼J ¼ŠÍ²ÿ Ÿzþtw#¥cÖ¤ÃòÀ7Pˆ²z1¯7 ¯ ÔRb_pF8æØ ­W ãöψe½E€XÖÛÉàII9 NZSvc4,û ¦š®I·f• SM«:^sL N5¹.@ªãÁÄaDâñ4¾ª±E(ñbZ\ vZ—„”í¼æ‚HÅ5éñU.WH¡º€@F@ÛCr0~çä¨*V#9fMz뻀òNé#½n{l€¼¾9Ò¾ŠuL#½³&½õ]@y?€t’‘~Pm¾¾.?Œp@Àó8_/–[‡Î­ðZz”3-qÞ­ÒÓOZÎx¬M¾+@:ƈd#ᇕƒPä,€XÎÛ©¹H׉òÐÜyMœ¡c]Bhÿ.C[Â:°t¿è¢][1rE€<>HGŸ±Äuð4Š-°ôó¸q@©&Žy âüÆbÑ@ç/ÎË´ð¿w@Ò¡F{, X.øxýQU¬öSMÌ´ FIábbSñK#(ïFÙƒU±lhÐ"gžÌG² ‡=n>q$ x>RyL]Ë”1Y1GG4  .%>«‰Þ#DmEÔ€X40fdÏÝ¡%Èí"ëŽÄ—“d@R%ˆë"Áš– ‘X€ }žÜý€ðHõÀd bÒÀ˜™å·SŲÖ¸D }¼rÀp$C_¤¯&]—ã È—îÕ$Wž‘E QÛM=VĢ׺äeN¢¤ ö€׃°:Âé£X U¤tWœ 1&¸|þLÿ§ § bˆòĪbñ‰U,‹ÅL§ i€ð6Ó£òÓHý·d[´±”V åµÍ—•!€%ä‚wh-–U7 N#Ý¢A1SaÁT4  Q˜a×ÈåõõŸÖRZU·k˜5#C&‰€$¶žY ÚŸ/äì^MŒn^´ËîæEªXN7¯Mƒfæ8@Ôw¡0îÝ~}}|¥´L3Âgbi@žãA,.¿‘Ž¥…¥ÖÄ«‰1Pˆ¢†K±h¸D `°Z$× ˆvÄÀÀx…n|´´cÄÂÃäÙn†‰­çkðj'_è¯úÀ•áŠ¾Ê ½®Äɰ“Ýk–¶KŠé{_øà4Ð1@ž1@‹‹Ä3k9mœ6 :B€´”p BjùÅ:PÒ³˜ ÄÄ)%uÛ“\F„#4ܹÿ怵œ]@²¦»#:ð´ ¦ÒÄkNöTÔ/V¹Ó†%=‹ B x)áÇ#—èˆÁ wD"öŸ ’3ÝÂð â¤U°` Ñ‘¼¢0ð\‰Ù‚MhjNwÇ™ÍèÏÐòˆþJˆ¿”Ø{iŒ€¥´#< oÊ–Þ€d,˜ÚNQ€T\QˆèHdÿÙ‚§ˆŽ©¹&ݵ²)ÌèÏE/ö+±¥šžÅaOlSRèå0šµ”V´o$#^< Ëe© ˆ¼¤% –˜ÖÇ. ¯æ:±@Ì”Z“îf·g€ØU×h€ ©¦g1AØ‹(%ê0–Òª±V×¼x@6+z’ò6õ•ùÄ®c»¤»€ëípÑ€Ø:@Z]@˜Q[†ò^5 vJ”ÄÒdÜd]J²ÃˆíÆGÏ× vÝ|õ+ÉÇ:MýR~ÝÇW •±u𠱨׮b½’Wñ·'¥; IR #¨õÖv™ ,}_úó¾ý¸[€ÖÛu…€X:¤ ¾òÝäåõÅz ¹€Ø)ÝI’Ú€˜Œ72Ø[$Ä2O¦ôý\¹tÐXo×béi & l.ñ7Û°SÞ«ÄMéH’40ng»«í‘ˆÅÇÈTOé»]Å‚ÖÛu¥€˜:dZ\ƒ È˧——˰SÞ«ÄNéH’´D2b‚´=¢²òÖÔϵyåKkí6°Þ®+ÄÔêæ}Ùìúó‹mØ)ïUâ¦t$IšÂ±yí¶‡zûQ€¼ñ&ú4ÍõA í´Ž(|ùôi³hÛ°SÞ«ÄIéH’ ÈŠ/¥D t©hE@àêÁ@²¦š¸:‚SM^¸E3Ã~)ÄMéH’ÈëãëßVÏ$¡(@T$cª‰¹öuwª‰5E+Dž–(ü¬ »'¥; Ir$ ¯¯¯ƒ^,U€l€xz±,‹c³Sgü\W`Ø_?Ëßü©&FJw@’ä@@þo±|$‰y“!ôKülÞô)?¾´ºÃ¼š@ÃV¨d.ÖgXU»’ ` (r$}€¼a€œÇ« 0lY€”NVT)ÝI’+d¯yÈ/@Îì´}Dugó¶º; M 6›÷È^:w@êÈ­b®y¾ H{›¾ðuXRvGÆ'oZ@ênÁÖî!…IíÏ€=w@B€À…( È3¥ŠkY/M ÷D².Î^4a!ë“/­Àcª»[;“€¸<×X0…¥ÚîVºÛÄ^˜n‚õåX¯7-O×l`-‹ÏHŸ"ºyÉA€ìÑ’üõRTžj»[éNˆcq]–õzÓòõ’®b=? ÇI»[éÞ ÖëMKóÁõ|£†€D§zÔnl@÷!çX\–ÞÑ›–š”Ëæg}¬HBZ¶c^.Ö69z/¿î; BnÏ8 †Åeé½i©uOj c) )ii×î« ˆ±÷”÷ë¾’ äFù¬§(€˜—¥wô¦ÕºŒ*GkŸ5w‹6íÞ£ûH‚›DáÑ`½]^ѤbUi}¢µ¸O1iÉâAî4Åž1!°ZeítàÑ} í’?XÈõB]U[b¿oÿz@,ëíp¥€ÈuïÑ€¬Ða;÷hílÑvù6H»ärý€„¥) Ðz;\Åå[´Büºï€$¹â¤Ø Hq‹ÀýC¸\A¤]ò iˆëÕ¤‰^ź¶F:!øT~Ýw@„4sûÓDo¤_[7/±¹W±j ièËð|L[V”ÈñݼW6PHŒ*Öµ ¶Kþ`ÙžØÐ·Çc¹±[e9~ ðʦš½Ù<' ûH‚ÐGF7 h•µ#˜j¥Ò´ÒußIöÌø&ñ`RŸ‘½ÉŠe€˜i²£Rº ìH¬ÈÇV‡‘<˜TfäX@pO$év¼Fy5©Ó>´vc»’$àÉ3ƒ“šŒìx5ɱ^oZO$ØÆL{éÕ¤†¥õw@ Ä´¶F¢ñ`’ÃÈ.>@N!w@®L+dŒ´ÆƒI"#_ä¤E‘÷Èj=×´ïw@J3ÅqÖ4H2ð`’ÀœÓ ¹¯&OkRY8®Ñ^M˜¥±Gl>µ”ïw@Jy}›¡Iu­\<˜D2wÑ‘‹ -@<žH²$É«ÉSrsjŒõjräÒ‚á±µk‡øöHL"‘þy ÏøzÇâ²³”äÕ$cuPt7ïÊ+LÐâS¿ß)zƒÜ^#)ǃÉ#q€ ]³Y’4’Ñ7&Ò‰ù¬Ò¾ß)Ƈ|éaF*áÁ$Ĉ»¨øt¾8 é|Ðüª´úáÇe!éßއÑèô2R&^F.ˆ¶^#xYøŸ €,ýÏŸ?ÿ=ܹNqð  FªãÁgD8xgò67;ˆõÂà×åç•Ò/æàßÝ_h¯ŠÅÚéßˆƒõêâ2Ò&4õ pï Êz³ó€X¯¦‰ÿûç²P=…€ôÃÏ?ÿ=Móòc¿‘®Hû~¤D<Ð0Ò&öü©D@”õfg±^<ý{+S~Ó¿ûŸýV´²8ü{š7ý€ènÛ•ýKý~¤D؃xp^|3Ô·ss<܆° ĶÞì Ö+‚ßfæR|~[¦å­ À~ûÕÙ4,w@®RÄÌG>|@lëÍÎb½"˜~ýñc –¡/d+ –4A#ý>Õä’¢M >Bÿĸ¶Ç™£9b[ovëUÁT~ôLÑâ*ÖVÛŠ(VFù)|˜w@ Ä_‚P@Z㑈m½Ù@¬W3,ìG1 KÏ5 Á¤ðaÞ) Þ;ÚÅyqW9}1ºyñ¹X®õfg±^üÊgŠ»y‡…iøá(LÛw —; B’9"OÈ2ÀÏØ(!ÁQÖ›Äzu0”âÂAÖáð廉û®EìÆ¶ È?~ûí·d?¹wHÀ9wû[§ú±u²Ÿ%"†kÞ¶#éÐzApM@¬´.ï´áÏç—o/ÏŠol%_e¹ýzvï – ÜOn&®çjÒ;­“òíÛ·?éÇ·îOzÄäÏðíE|5Øç÷‡‡ïÝö9>Ðï¤BÍpO†#tøz±7Ûè"Dºñˆ7“ñ}¢gøà‡Áß „þû¦Ž¨üãù—g^˲¡Gúo¤Fú—~aÄ­SÓ…¢„\‰Çöb#—Êéù‡‚z"‰Êª%‘^Mä ±÷qÁ¾;îG}€pùíEòòûî2Žd4œ§’"Ç踢Dã!g³ìfÌÀ­7;3I^Mr}¤W!Ζk‘‡øtªXoRü€Œ¬NÅ«XZ¨˜U¬S²MZó˶;¿XxD0bÎ k¥‹HU;ç8L®bqI(AF»Š5ª[à&5¶e¶­u$— rZo]³Àð3bM°|€0q½€xž\q¤ó´A@vÛH¹BrO$ÀÇXŸ/L0Fl<.ëÕ$«w$Ϋ 41à¾9Àé»YÅŠ$¹ë·ÒykܸyWÖq€ôüùV-¤*#a<0F\<^M2¬×›–×IFïHœWùB!;€¬ € RgD‚>ßòPôùÖ-¤#xXŒ`x¼šdX¯7­‹ywÁnbX€ˆ˜ø*.UFÒ% m¬×ÄݹN¨`Û~)e$ÍŽÇi½» ‰l™ƒï«‘cæb)@šXo, ›q6$®áRÀH‚£9z¸¾]·9‚ë¾@ ¬dB.ë§iêPTEoæ¦V Â%‘t<˜`tc7Сã]Wk 6:{f/­¸Â뤶õ:€L¦qMß ÒO*”Îï­ìä‚K2#™xˆrÄÍ`‡ZoWº°ÞN”÷PcÏÏ_žÙ³´ôÍלjâÙYõ]?|—s°¾gRßzãªXŒ?¡}.Ë`* |·¾ˆFJðÀÁ­· Óz ?Çj€|ùùHE€È.*ö ðàA¼wTCäú@Ó¾Û¿ïæT“`«Èzm@ŒJ«Pœ¡*¸Ê”´„D3RŒÂn½…€Ö+ù(»;Ÿ¨Ž2@>~~~¡ >ùŒ¤U4lŠ¡[ÂgSÉ#Vxðƒ®ÓúïA}ønM5€4°^¼±ëÑPKƒÚËÀ@vdŸ‘:xØŒàÖ[ˆe½®a­“ç//( ‘¦Šbò!¹PSÚ Nðá)AªZoJ7ïÔc¡Ï ¸â&€F*âÁD2‚[o! †õZ€<­ÕÙ4x ýФHïDÁ„¢ªX"è¡ RÕzSÑ¥”Ú#¡ÏFÑU¿Š¥ÄÇHm<˜ôT#n½QÖkò´ŽUªX\Ã7¼ŠÕÒ¤ƒ%H ™Ö›4PÈUôFhïÀ$³Õ IDAT!³ ±Â9>1ÇDYo9 Úz% LǦa­Ó‹Å4¼ªw - „¹al‡ ˆe½E€XÖ ÙJ¨§JݼŸ·êË3Ú‹u cn/–zˆ¤¦õ¦— =T5\¶‘’â£. Àz‹Ö«9l °9 +ƒÔ·Þ4@d‡²‡°˜þ(@FxX€0PxØT“KRª, ,ë 2Ù—QüÀ¨£¥áši‚‡ ÈSM ´œ¬xB@*Y¯ ½lêá¨ã³©!‘äL8Áì@Êq€‹ënz6ïÉ©h½þdB.“CŒÕ±h@ijL}ñˆH9 ¸'’ô1ï5Æ«ÉÉ©h½ImìÐÓU±PO$ÖëMËã‰äCF¦c¼š¼‡Fz^è•2––!Çr ¹ÈHú%&+Öû¬ºÈhü¹r\Ó@!3| Èø] Ê&Q“ÛX//¿ËCwKqeH>#w@’嚦št²lؾ™Lb&+6|åªA:T¨b±.@ï€Ô’‹T±ü€tˆvŠ8`ˆ°3£&+brû^M/;FJHIr$Yn«‰˜‹ÕÄz¯¢‘N7ƒ^»Þi!·Õ)Ÿ¬X¡‘ž“Ø2Ïó‚›²¢ñ±ÞÛ ‡Š^½È‘+˜¬XÓzKYæáy:Ìý·X@FÆÇZV„ÜIãUTÙÍÞ…íêÇA"¬×d¢/{b$6Ó¿Ãì¨X¦ S‚¬ã½9TZÙ—¢á?ûr§¨ïV Qp & õ­×D“Uh½†Šyb©»*æ‰ÇìÂ]¿¯«tg˜ý.ôc»%äÁü¨q  Õ­· -!–’£b'Æ• #Ñ„d¿ ýØî€DIïp£bùˆh’X‡þ¨2@¢¬·™̈ŠMYJEŒ¤sƒ.áãéH²Áö8ØèC v\*"€ÐÑïNnÃé©bÇî¶w<ª8ë-d!³£‚Öád)ÝY[Bïàñt$ õ:|¼rÈ®ª9€DúEÑ}PzXü¢€DZoaäE¶ Z¹Q1%³è1·‘þøx0 ÈxR]9fWÕ½*–vÝ6;`ìò=ô{…$Îz›Â:d)S‚°‘Â1 ú+v4 ©yL#uèísÄ‘ëá=Œ‡UÅ¢p¯©‰´Þ €ÐÁ6ÜböÈR*bdä«È3ʧ§‹‚Ìú¬'Ò°ÐQÈ^+fäò€ìYoDGÊО»¢p3êäâcÃÈØ†H‹Ä…AV{Çò vs~S­Äl’¶ÙÙ‹DèCû»>¬Q‚ìXo•*Ö2«Ê”BðY–RQU,>—7 †ÄîæÛ0r ½¤ ¿› ÿ—QÅêø.µº†5>Œôn[+{}/SÅ [oƒ6ˆ†¥TÔ8IžÉ+J{‹à׆µø[0 Z`I,$»¿Èj4Òã6Hä{w-€„­·ÁT“YŽBnú—è*VºíñDñ t†¬M ­¬²c{%±ñ€Ôêæ¥4Œr„‹°-G¹Öà HR/Vuëu±d/Ô™îµl¸¾Q=åö­OpÚ°3ÓD#‚¶Ç†GFúž€ìFnìI²álT/Aê[o) þ ÃðÜ@vÊ9Tbµ=|xTg„V}Öw“À¬“Už±§äû5a½Å€D…ÆT±‚Ž7xØöá‘ÃÈÖ@ðá¡lêRAl@äZÁ:­V±FÚR»‡j½Xõ­×äB^MÀõk ¸Á{ÛeŒP z„±ô»y‰!ÙS´ÿŠrÅäÄ^MÂbc°Ê™ñQx€Kvá #j·ô÷ˆ÷¡²øÓ9Fb” xŸ9êI O!ü—Å`¥‡¾$ÀÇ€Uß F—d2ÄNDâ±³'a@’¬ô:IèQ÷±àéumØ>I_Ë-Ë«IHü¤á!.ñ2"ñíÉÀÃHuë­ Èä*9) m¬7·‘îS‘ÛHÇpb)±/8#sl…Öµ†q€Ù­f½Õq”\ #hˆÇ­IO°Þk¤:LF$plEd`´òS×zb)¹ cÐ7¯üv”oÞ €Lÿf†. *æR@Ú•ÍÐöPc+*Gb[o@ %$èK~ lâ¹ï›·õzÙžèÛÛà¨Ðƒ*û*"6ø¥eåU3ÒmÇWØWp ¦õ6(¹8 BÔ”úØz×7o#ëÅaÞèLK…–P‘°ä¶ÂkJÎH?¨ªÕ?__—FŽZo3@”’KV±â¢¢|ó¶±^¡A«à«J„,{*ø¬°)vÁT×”%,Ëu$ƒ™»ÑÎP;@´õžÒ$Þõh]ëÅ‘z¹#è2ËÙ[útrWHÅ2ƒ7=›×~´[µç@Ø3€ ŽÏÈõT±rÚ Ñ€T¶^~yäBD®aµ¸a©Ø²£äÙId×§£ÁÆ)¤yë*éÙ½X"(Â7omëEYf©A¨`&ÙT1ë’nÙIäÇí´§ƒÙË4»[l¤_¼›×#õÇAj[/Ȱéè…Íà<ÉÕZayÛf‘ýÉ€ Ëë§> ÈN–Œ÷}‹Ý¼W0P¨×¤WMŒ/Ϥ¶õbmMÅ$4¨Z­šñÂg§Ç\¤¿ºÔd$¯¯£„àÆ0©×  Í ¯bª‰µ¤Šg^¼ RÙzÑ^,º¡´±ŒÄmx{UÐ&Ñ2Ï×Ä6Èú·W5&1ŠR5ždðÇJ @šO5¹’ÉŠ *À³O+s=H]ëEy;®?ëždÍ õª@:Õ¢¡î{^ÕtQ 呦Œ\¸ÉмäÇ_Å‚õ,J+ «Z¯gK¨Åí¨`eÔ ÏÄ]J«:ÊI;FJ œ˜{R@ćê°m HEë„õDª`µ¸(@ô؃éÆG͵m̈1}OÞ øÊŸTkƒ”{5©o½ °Â`¨xžãU¨yaa@´#×–vŒ$áñŽIÝmG‘ HÓ*V}ëÅKÓ¼±ÐV ( °”°ÝøXRÄHßWÁã=RI Qr˜W“ë½ N)Ú˜ä2"1”ãq$YÌFú¾y’à£"Ö« ^JøñÈe:b(Ä〄܋”ÅJ-Å®bµöÍÛÆz! )žJp‰ôjâ/%ö€§ÁXJk0’…‡ H+ëÕ€„Ÿ|I¬ÖÑN´—zê¾y‰Q‚à>IÊC ô±•ÝM4#öRZÆÈÐuC Í” !©âÝý ö¾y1)5Û ñ~!ÒB5 ¥Ä¾Ä0–ÒŠÁGÂêZtÑGæf¡f ’[ñî~ŒQ‚4÷͛ǤÐÜFz®ëÑZ²ÃˆáÆgäUÌ×¥do¦kµAJl'{d#ý( ×á›w?´àý÷P@‚ŒXn|ÀRZuAŽ\¶ËÌvqì%¹:ß¼Ö ÝNdpBMÿñGb2ùmW¶”V­4å È RÑz=Æ;~ûf|-=6 H‰õ¢€¨©ú²e’ËØÄà$0²:Ò©ó3—Ò¶¤¦õÞ)¤®õb€LÓ¦KÚ ­‚~ÀÑuÒÃÝ€¤9 ’ÝöxµÖÍÞ, –C‰âØÓRÙz@8ã¦a1êk[àÀ>M&+ŸPoo“Þðª- ŒÇá€ø_kXU¬ŠÖ{ÎFúa€Ô¶^½´ÄTÁkrS?ô“ªÛñ6¦b0v„»  í^\Îvì†I\¦‘nÍ,޽@ÆÚkÒ«[¯ˆÜìpîmTÇÀ04ü -˜Š­„êß´w»‹âyq-©i½ãÌóŠcäA/G§½Xja:è«+øæ­o½ j9U¿0ÍŽ²YjP¡††«¤M RÏz½mã<¨bÓáõ]{| góv°ŠUÑ7o}ë – ÏV-î™ÕáSÓ¡ÜT3¡†÷HEëõU±zV‡¶ ©Å]„ÆÙ!p€¤·Aâ©k½ «TñìªX¨Û!{¨ePû7 áÊ!5ib½¾„Ðó¬¼,ó T±Õá»–é¿ ª+µKÕ®v©m½äÙU±ðn€ð`ýœ%5­×Èvž¥‚jàµ8;̘  =Ô©o½~@žb(òj&+f26¤šõbU¬­MK Þ.¤˜ã¹E$BD1¤T¯½\#ÝZ^â¤×H5ëuAÌ;zÁéî—¤‰õbÆ+*aeÆ.³Ã ¼ör%ˆÑQkõúæ‹H}ë-$.ô¤€p©l½˜ñN¬b·îÔâàµmƒDrôzˆP¿I¡WHõÉŠ•­©bÑq´býV¬ÝU\°KT§äêôN®’‚5¬Ã¼š$„B@R¼š¤„^ ù+n=U¬ÚÖë©b-ò4#/Vì¦1k\{%H& í%쟢’Ž«$«¦õzWVÇœD@ìâªð\{;€ì{5i-a/µt\ k(2(þ^¬šÖ‹T±fXR…”–É DbAö.׋E¿~W¾~`/V~«­£ã„€4±^¯ñºF^{0 Qräd€©g½¡*–w¾Jzìñ%óe"˜ðínÇÑ*,èÅj'êV[ë¸@ª·A˜Ô³Þc÷À6H"[U(®Ñõ(½XmuœìļØSò]ÒÝ =‰ïáÊöÍÛHÎ H{ïî‡èU,:ÁJM7U¬@Þ™oÞÓrïîGè%ï³RëAjW±ñÍûs—zK€ø† @š øuI%ÏëGÜä{»6H#ëd{¬EН=Ñ'zîO” !¹ïîGÜcC-æhÓ‹¤Ï·^ ¹Œöó÷N(ª¢7sSíµ4„âÑu+ʈÕid½Ç6 ¸®™ €Ô¶^ÉT".£é;¡@úI…²!3';±h±á`3@8LF.Û‹ÕÆ»û÷q õ­7®ŠÅøÚç²,¡lFà†ƒMÑx Œ9À»ûÿüñµ4öœ€ Y,²^£„"Fhï æ@(Sbœk’ÃØXÐeÄ$wÂ.ò*W¸B×HMë= $ÜT) Ö‹— vb=ji0B{h2ôëšËˆù6#¤óµ²Ãâù©Óz/ H#ïîí!†J¹`%HUë«b Å=J,pÅ"~ùsqr7 úòѲî5ƒ‘@n×»û€´•¨^,*™Ö›ˆ.¥ÌÐ %VÑ%ѵ£dFÜùÉa¤ÿCKŽõÒÈ»ûû$ÓzS¥”9Ÿ»÷é„FºdFRÙL;‘@n×»ûû$Óz=€Lòs/´ì€(SLc$^—Uî£C¤Ûõî~@Iˆ‰}rþ9 5­7½é¡ ¨!4FÒ1êsî­¹©år³Þݨ*ºB¬ ÎI,A’­7 Ù¡,C n ½>2"£ ûŒ¤ÂÏO`$xw?Ð3•IeŸ“H–õ†™ìË(~`ÔÑÒ H,#†*™Ð. $ž‘¢äV½»ŸJÖëdB/›zXm"¦†X@PCÜgþ bd%Š‘¢6È­zw?' ­×_‚LÈerˆ1¢:¦UDÈeÝð´@H #>@ìûêX7ëÝýœ€T´ÞP+!±ÝP HhnN#æ  XNö¡±¡÷(AnÖ»ûY e1)ôº‰fÄŽ‹„ì1Âcd`:A@nÔ»ûPæ¾y=÷™ÎˆÃŒ•làÕ%0æG‚GhW±*[/V‚´óî~"@Îà›×sŸŒXx$BbYzk–”§¹iïî礑%:¡¸B($~u@$#ò„>¨ì22krÓÞÝÏj{·æÕ$(FP<"—L…±{Ìô‚«ŠuÛÞÝOHë5‰} ÙôäåeAF8 u’󨀴×ÑB ëgñjââ‘ä‚= Q«cYw@¢¤Ï$¡7lÈÕ‘”X‚$ä-éîp@ô|Ù¡œ‘€9©B¾œV¿c@Ð÷»ï $Í c{È aBÞRîÎlƒÄç-íî@¬é䥌xÍɬ2ò|@°—jܪ6HëÍm¤§Þ¶Ú¢„Ÿ5I<ÀZD’Ï¿=e¼[bì“mFÂ:uÚ(>u$ø D¤ ÈÃÃÃ÷î;ýx Â>Ùi*¬S§±oßáú££xx ÑÒ1¾aVF#=AõEñ.FÊfDãÁ¤˜ú·ú¿ƒö7}¸”£¡²¡ÿ؇þ¿ƒö7}¸”þ{Ð 5İÞú€ˆÑ?9xa@¦‰3CåÒ鳑I¸ýw­•,FP>,<˜1"ˆÔRˆC ä»>¿> Žõ–ÆÂµŠi™—i‹"Ó¼Ìz˜¤¢õz¡Ãˆoƒ£Bªì«@œ6°¯A<˜¤3‚‚áÁ$ŸQÑêd• Dˆoº:eF‚o ÂkRìQ§R⛬IA@X˜ä;/CŠKHë-DX©b–þóÅ‘šÖ‹Â4¼ÍN¹2«aùÎ’[‚ãáw ½fo¿éŃI#òæ” ÝX³Š…— ¼’U^ÅŠ´Þú€,r‘ì´S‚Tµ^¡A«Xf Ëž >+l²LÑç:…F)H`Ä$Œ“ Fª‚·A@BÍÚ Ý÷–€8ÖÛ¢Ñÿ…©k½ RC/r?å‚A:¹+¤B?ªMÇb‚à!ùd3âðáâõ}'2¢^@oôbA@Ì^,«K׳"z± f/– ˆÕ‹¥ëY²ð¨Ñ‹i½å€èºœªÅ©ÿ€T¶^~y¤ys ³¨Å sHÅ–Í ÏŽ ˆƒ“µ€#[j´Þ’F\@ÚHÕã ÑÖ[EbJ RÛzQ@–Yj*˜†IöUH\y-ŽeLjåÝjÍdı$ââR±$–ñ; 1Ö[™ºDÓH]ëE6½Ð œU¿E˜AÞ¶Yd?@Ķ$ðí5CŒ„ÁFë-‰bäHšõûÉlU0HmëÅÚ ›ŠIhPµ¸™Wí6Ù©Å1é¯.P‚x À¨ƒÅ0‚ta€ N*ÈTƒ]F@2ÚxGØêP‡(ë,4Æäáöå><è«=QÖYhL qÖ[ˆJe0 HmëÅaJËH܆·WmÉ­bH¨ ’ˆ—‘$@X*xîÃŒ`€ˆ™$Öaç²ÎÂcz»K~‚ÃÎe…Ç”i½õ‰+Aj[/ ;®“Ö òPÿݹjµAÁƃ€Þ˜Ÿ˜Êë½X RÙz}€K¨Åí¨ D3¨S¨q© ÈêeäHªõVÄê(‹-AêZo4 dŽW!7)Ô„˜Œ ©”²¢Œ‰Ü!Ö[ˆmBæ—4@ò­×db¨ s¼ 5/Œ4„À)7‰B@V—‘; ÉÖ[!ÁnÞúÖ‹— ž¼Å«pR¨ ‘Œ I”²šŒ¬F¿@ÿ¾{±‚R§›7¨Â1,§Ù¿0Aõ B|Œ˜€ÄçÞ#÷$ÆB²Iör yKº»f€”d²p³¡—¿g@ò¼¤Hº7 Hë…:Rò–rwi€¤ñ±É#cIJzÚƒŒ°Ü¿c@ÄøåE!TÍ„ð:ïÙj‚¶ R ò¸ÉÓÓ0€NYâ  I¤C]®NÎúÎÊCͺ{¼?…C¼š\å}¸“§vä컵'OO'Ê#”‚Qn\›''¤Í[iÜ>;’J®â>j„¢ÓÝ-FvV⺲!M@ÐzT>’¬JZ?ezcö{±¤õ×éÅjd½)€|øðÁML>›çzI³ÈÈÐR@€÷ß@ˆÜ0³ë–T<â’ÚÖˆ &bÒTG ™Ö ÈvÁ‡~³¡þƒ™˜ ü CŹ0´ë„n'28¡¦ÿøL@Û0s’ñЀ°ºxÿ Õp$¤cëd~þ ö+ÿUèÀY‡ÊsAh %Ö‹Þ‡šú¨C—I.c7ƒ;äB#Òü`©ªÕ“Àò¦µ #Ã;¤Äz#y›ß¦·ÏÞ¸IÛ,·hÊÏ5B1@êZ/vÓ4‚©Á’6¨C« æŽèR†7ºI4 +nœ£m' &Õé{òÎ)±ÞX@&šØ3M®×‰õ*p‚*ø¹0¤²õ"÷Áù7 PÓ1°ÏE“ÉÊ'TÅÛÛ7¼*D{?1Ú><˜Ôd„v°é*¶©}-‘€ cëdfÕ¶~‚ÅÓGÿZ*f+Ô¤¶õº÷¡—–˜*xMnê‡^ΓmLÅ`íWXÅ‚ÞO¬¶Gø‡6‘ŸçoÖÁ6*@ðMík‰Pt„Ž]@²­7êañ6CE*عF¨HuëuîCnv8÷¶ ªc`ŠP¹;¢b+¡ú7èÝ®Çû‰·íQƈÏû‰è€´ïcª®cëÄ’ÔPû>ê[¯sj9U¿â¨öéàdßDòçóË·—ç?Å7¾-ˆÜ‹í{ŠŽ– µ­7P‚WÅ»€ 9X?¼Ï# r( `¤ìy]Rý. ÒúÙ§LXp§¿@ìUëjš»8B¦»ûöíOúñ­û“1ùó…|{_M@ "Ê<÷÷Ný¾C'.AjY¯‚¨C‘:´ÎdEr< d¤¬¶ÐoòáBÿêˆKX¸XWËE,@è¿oêˆÊ?ž¿qyæµ,€P‹AèîßÝí.Z‚´éŪi½1÷ -Ÿî.ÎÂ.¬ "´2Xm­Ÿ—!Î]ã€QU7õÕD³cã%"€pùíEòòûéWÓ‹åHj¨ j{þÐzÓÝ‹C“y|<f+VÛd|sóÁN„üû–" —IDATíbì-Ã; ¢Šù&ň±;´ ïÔZ«(@ʬ×0¬O%Gx5I=î>’¡F{, H–¶¬“¦%Hw@ ÒÁ¤Í[‡†•â $ÅGˆ È-ÜGŠW“ ¼=p$ h–X Ônƒ¤’ÓÙ¤‘¿¼è„â ¡ZG»©Ï‡é¢äÇ"ÌÇâÉ +Avs{±äÙ€d÷b‰ ‡P ‚É-yáOíä(1€l?د¯’º“y†ø34î⣘¸…qä}•‡׸ÝýÍ-–ctD2ŽÿüÛë£dLÜÉK>=¤²õ†™Õ'O„m­«‚ÅÙêÉã±)ݤ#šl)í¸á¹l˜„±Ð’ Hw ÝQ€”Yo ìp’//é¡@*Y/ ˆs²¡Â<¨ ÚH%ÙaÄvãÃçëÒótý{ ºN«X1€D÷b=è:¬bÅRÚ‹Uf½i€ð¾€9=¤®õâ€L*ø9z¿öyâõ7^’Í R[ # íñj,¥e§ïî´ 74DÞ©½›.AºFU,XŒtV±Ê¬÷‚%H]ë­×q &#Ùöƒz:;$H½Dß©Vmo=ë(@n®©j½x$B…<‡€G Ë¦‰¨ØZ€8®¥%" StSÇ÷-¤€ü ò@g†7Z€näÑwŠÒéþ¬Ú½X †ïº?ë˜^¬›-AêZ¯ˆ¨šéŽ·™CÜZœ®û©î2b25Òq÷ë. ×W³žD Ô°7òA@Úˆ H[/A*÷bµ°^ÕË5O»eŽ ØE&ULv7¯ø¹ÏÆs¿Îl䟯¯Ëëµ8StÍ—†º‘¯€´ïŪ ic½ ™7õ‰w¨Ežn ²°_? 9Œ€Ñ=—"7Ù!?œ‡êÃBL’&m¿§÷HY¨Hk¯&â6šX¯ ˆßv c9 C¿¢Þ££1T0Fßå]i>:}·0Ÿ>c2oól€Ü‚7¿I@@ ìÓ{( Düòç0â¨}ùh™Óê뉪Èiö(<7S¢kGÉŒ *ü€ñV±9Í…gðr ¡uée±"Iß6Í´QFªÒV¯ì®ÃÑá«)Ö°^ H¸öWk¢L1‘d@z]Vùu|«¥È—~ׯcß|²” ÁÚ^Q,H#é€õ¹º€4|!GîQx"A ¼™5é˜%®‘Œ¤ÂÏw¹v@¿XîïPnÈÆ{ð}œcMºÇר]𱔥x!#¾|¦â¼­Z!þ_,÷Mæ‡øyoõ>NÒ‹E<†¸Ï2ÄÄÈÑÃH" ­Þºÿ…T ñýòÞî}¯œF,놧íBbñbß&þBª½õ ÖYî#|iB¬qj‚Š˜X#¦¤n¬¸ LÓWƒ9Å6 ¡âFl¯(VªØ=ï1‚{?Ñ Ý¹îûhc½ð>æÉP!çomŸŽ gª˜Ù ±9hFì¸(@È#æýÄyE‡–µãÞ¤f‚b.n äËËËãªÙTz4 \¿•ëª÷ÑÈzá}H€¬¹óÛ?uúcÖ_¤ ¢.gZ€DL1Š`ÄaÆJ6Ph&0by?A©n½ ³ôN•¢â…‰y•TâÒÂzm@X\²Š„ûhd½Ù€ðL:*øj¬"@b±ðH„D1²¸ÎF úÖkÂ=Þ&ªøÂU|±®Y5i`½ Ê,ÝG#ëõ2‰¼€B ÆIÃ0T­|€ÄÏQdDžÀ•]F†ÑÁcí@X¯eXÜQ4ôl£âåE¯y•JǤ¾õº€ðºK³ûhd½1€ÌÄQ!u´$Š@È#v™^ «…õ"†å$ØêÖ{5€ZoDk¶äFƒ×âÂU¬äEAFF|x$BüŒèo&;½Xåo½J ’ÚH?¢Šu‚Fºè(Ó“ì(³ )££ $w•ˆ$>¨ ŒÀñ³¹^\‚¤6nsT¤uóÑH?ª›·¶õ÷1G«¾~ÞŠ€8ŒðH„øç4ºxÔ$­›×4ˆZ!& í»y¸6Öë¿pîc …ˬ!#~¹Kˆ ÜG8w)±5aŒ"Ë!šß6;â…´zëú…¸ë˜k…@Ã:ë}„sºpîâc9 -=UäC1âÛf‡ÞÍIÜþÜu\‘Ž[„1â‹¡†–" ý»Ž÷¥£»)>Ò^E¸V|×qN礭'›ýZñ]Ç)uÇ|ï±¹r×ñþtüBÜ[†‘GÓ4IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksSP.png0000644000175000017500000010412513263214225021455 0ustar aeglosaeglos‰PNG  IHDRàä %×¥PLTE™U3;twîwDDwwwUø˜@fPTØUUUDDÌøüøˆ;"ÿî¸`îîî|f™*L333ªÌÌÌ̸¸¸ªªªp˜èfw蘘˜L*|L ˆˆˆ;(*l""f|~|\0øÌ"nnnfffÿw3\\\8LtˆPLLLwÿU"ÝÝÝD("""²Ú¦- IDATxœì} câ¸Îv˜Òi)2mOÎ’n d‡w–rIÉG§ÿÿ§}–ä‹|KB¶³;šŠs{˲,;IÒ]&u…ROؽ;.;#ò Ûô&ËQ²›È¾=íz½»ÝOO1‡_B¦-2¾m”Áç÷O×7  ¿!±8`áß³Ð〣$‘s@ø‘OnoÃ/!e3þ›ÛF úÖÝÑ'èŸß)ôM×ÿÑúð ä¯PˆŠV­7¢ ƒ>¼8r%r‹þ»§o“É·Ï€&42`³ 7H¿oß}†Îù@ßxý­o“I­Ð×P °j½ÿ<¾:zì%‰À_ÂþS0ÀÖ5 ›Žà÷G!?¿ãõÍ×ÿÑú6øì EÉn&³¶ òø}G¼3ø¶3Õ^0À2eX®”®ÿN@üè¼ö(x†æüŽ×¶Î¹þSè›îrÿÛñ_h±@Í}ÿñÚ‡ðñý3xâþâΘhÂ#øo /ã Øt$€Áo¯…#x¼¾puÖõŸB_N^ÙM.^'¥[þí @üx¸Õ†’Tÿý&`ñP®‰Áã{g ñ^ÏÀªoÊwP¸ ÈÆ È€ #À8 Š?º½[!t›%‚Çë Ò)´êúO¢Ÿ.뙹·³z9µõÇ0@â_΄( (pŽ÷¯|€åúŽ>>'À7ñv¾ÝõøÄ@º6] ðÂñ÷~ßJáÇê%~ô»„P^ÿË©ôýñËÃÔÜÚéÃËXßßn÷?.“ ðŸN‘ŒÕ$‘þ ÄHnr<ñ ?¸8?8ÜPZ°o"€Ç€M+’ 0+€ßj…Š3„ó;V×øÁïeðúËÙ‰ô ÷WêƒÈ»˜€ZâO÷UÙm$bøï$Cyõ ÏÐP|ÀÉr®eO [à1`Ó™K…ßÃëï E"(ÎïX}&ñS¿ § ÁåiôMU¼Mß*d þ?<€ °M€!@°;( º¬9ꥤ¨>ÌúJzŽˆqø¶Àê§–ø—†È%€/÷XW«Û[¨kT…“ãõ ù]xÿò ªàiôñ*Þ®ohÈ<< Œ À6@ ŒÿNZ ×K}plï&?v—ü$T'D€tŠŒewÜH÷‚“T!B(«°°áÇë YÕïÛ­¨ { ÀIô ·ê[ `ZØ´@Y ·Ÿ*Ï€·Æ<_rsÐÉ(7†e„¡n vá_'/€Â†­×Üø2yÕŽü)ô kýý×<Ü{÷?&ÌTM€Õ´ N@¯ ¸ü¦ ÀüQ}ìîl4ÊC ,¸¸£äÂkSK6üh½qá” ßîqsºþSè›î¯Ô¦ŒâËØ½ÿ1ùóëõE fHžƒº:qméÅõ×?mô<_ 3’']í‡ó/>ô56 ÿÜ. CÙÑ6Ζð[õ w⸠}ÔÍÏ îÝ8ÁýÉ €À;CÂ] ð:y}}ýyyùåyþ8þÐçÀ°@ Dšd@ùvÈ^À!}ÖVÞôâe7ÎêÉ«‡íLè& ³…ëƒ''@°ˆhd¨8Ĥ|ÓŽñå5ö‹ ›í>€é´Tsà`Ë.!€]ýµ¼û1½Pÿ8¢Ïõyv ú<ݸ÷¸È75ÖDD|°Ó )‘X$24?nqq °ÀÛÀTw¹O7ë1ÒRÄõ¹ÔYÏoÑÀa}q&Ô ,Sm/Ò¥À¿“ÐJ€jÃFÜÑ隆ß4=MaÒ‰"†&ÿñË¢mÀëEz#L?x_ÿ¸¾(Ì 0ÀUƒ@A ¨È…À‰ä›f¶+}?¤O4ú=jÜ=« ®ZKß7öô}~"õÈ _`$ñ7-Xÿ.¨+=hàׂР챆¿Ç¹@Ý@²Q®(2Â?›üKy¬›TTùçÇù3}½›±& ÝPaÀC îxŸ ¹P]¢›€IœnDŸLê H@Ÿå–y?ƒ9Õ0¤—ǪqÏ=J%äÈz/@ã5„?ßÔ´w'•=ì`Âk»%ò·i£, ø¥…º) þòôæËp>ü[}í÷/ Z}> ¨9ФålÌUˆÕ¬Zc\UY½À_ˆ$€£¿1ªßó4×M°¯ïçx¨Íf]Iãâê~8^bôxú‚ ¨¢aï?J€ƒØ\ñ§Pp$  ’B•’«;¦ÊB%/ãs,aþÏú»ðºû|( ;h;ʼnC÷NÚÂWkºVÙP¶l]cÐÎÕ3A òŽš¥=2:4ÄW/î_]³Ü\mã‘B6š_2v˼[(X¶^Bˆl’lÜ¡Õ(E°§Y–**º¿_$:LÀpd¾ Й®²ëppšê3ò’.ÐBÖkÚŸØ$¨O^« ™¶Ñ+ì˜yØÄZ·†VÀÓDõ¦zM˜žŽ—2_,|¸£(;‰]ƒ&•аYðS¥˜$ºÐsñ—£ÚAÒ­ Z ‡{¸J•p“¦€¿úþ•R¶º4¾¶#nàžRº´£%,«Ø_Êz{¶wCöØýMl߀VD/nÜï%\¡¯ @‚ ?˜ÞØ Ü&8+:¶h6¡Û€B0ÿÏÁ~ëaB3R†¡…$àôªºÌx^dØêËï_‹®ž`3äh`’鎀{©‚T‚ùiÀˆêHúz‰‡óü\•D¨Ð0¨u­ ë‹ YbêD·ý È7¦ ÞHü;%„PJxÿ Í  ü¿PN ¤vÝ„ÎP§&Ϧp•”ðe4¥Ùµþž\›€°¾n 0)U`²ôÉíb;e,xý z4A}‘¡=F£Ùqÿä$BLN¢Ñwd€›®¦È”ÿg‹úMˆÒÇ_Ζ¯ò8€ÿ±ñµ>òEAN iÒ-Ñá/ ’BCf’BYR¿¹,é³Q!àŽÊ9åã×ÿ&=Œ2 ü/)/l@ý„å¦Rõÿ€´àJÚMͪtZøÎÿ3a™ØÛíØæìÌñ벬‰?q; .ò"…¿üuƟδجv†VZu£þú"ÍÚÊG¯ÿÍú,½¸>¬¼0)Ç*=°þKTÖ­7½Û ä!éÚw°P§§Žÿº$¼þxް¨ ð—Ý”æ‰!1ü‘]'†x'èLühÒ_w)¹þ#ô×——>˜§ïÆ>7ÐL ³»ÆìYsi^¢9;vüz¹XV“¿¿?¾}È_êø#áØM_Dužá|>$‘£ËPV8~SþâÇ÷æßÃä{æÈs^Ø‚–ùÿ8e.7^”7@ŽSììòo%€bÀxð<èB¸$þ*gHi2áâN—89ˆ½\´Æäñ½^€<þ3¸öÿ#ƒDÃËpü@/@?8ÿÞ w¦·ÏÿßçñòùÞ+ÿf–‡àÁ@ ¬K$‚qË%NŽb¯…ޤÅ„²8‰½–K3×°@æø~€Ê …e·j¿Àÿù‡:¾àÇoàüÿ}ÑTÛ«|àcÇ«›@°`@¹hŠøâ5‡€æ:š— %”»°K…K€¦&„æ/}ügønÕþg•_" `•ô Ð0?ÿÀùÿýæò}·|{wÅŒ€5hŠ$L€Ç0þ “³–à^ádSöZÊÁ”&¡¬S¬X¯—ˆŒi ?> Ì_êøM>”uŠÍùñ[çï·¬plùvø rH¬ÐáUd®w½€dØ"]Ðd» © éB€&  çï·¬plù6L²»"'fÏœ&€ú‡˜Þ‰t$ÀWrGÖW]¼Z»å*»2h!>¾{nêøM>”uËñã·ÎßoY?àØòm°My½;mÝA®t›D¦Ö)düµV  &ÊfNAàJ'd45!üø-éã7øPvääÇ7óï¡K'á3øâ"w†ò¶°Šæ÷Ûå³Ì+Z_ ¥K«x‚˜—ŽÌG£RþZwp:]4rº Éh#›_˜)â À‹kÈNçÂÔî˜ÿ¿/äh/̃½¹Á9Ñ´?ÿ¼S `ìþ›Aœv`¨}&#b€M€,å/@“ GˆjÀ_.šB¹6àœÌK¿É@Œì’ÖñÙüûB­ ð‡á¼ >š3û þ¡ùÿ}À¶ö9}º,gÈQ<°~@7”t(ø-àñCh7› ˆ;Â_• É›TâæüU×'@ã`?¾€ï™¿Ôñ›|8þ³¸þ²ŽoÍ¿/ø:6c7Öþ~pþ¿Àà‡:›fèa>¦øŠÐ 0å»1Àòüù`Qiîÿ»z§ØN€ ­€!ª5A^-žU“°ÙT0wŽ¿p…‹&@ãp.?>˜uþÒÇoòÄñŸÅ¥ð—u|gþ=¡,×±H¯aŽ[Ù"gðçÿÃlE 5æ`I½¸#`áR|°‹[¾J›l0PÅS›»ÿžþ ¨É€!`^}“°‰`#Ó²›:øñÀã7ù›(Ôñ½ÙÕz15¿ž-kÂ7 Íÿ/rÀ¿ëÏõДÀ¶¢«¨›ü7!¤¡ïß(n J6´˜_ð— É@ÔùK€å›Sºøñ¡fó—:~“€x¶KÚÇ̯ÏÙüúÐbkáùÿà Ò £ W™á ŠS¾ƒL-X)aÍé âĺ`"ÚõþR4ùPöææ"å¯  %©“_ ÷…¿Ôñ›|(ûE Î_Öñ;ͯo[?@kÒr±føk;—j¼yj€›ú&'P{‚¦ØNÑ-»¹þ#á/=µªÁÀzüÇõ ½²éæmiÝüøÏ_~$ü¥ßààN~|yæ/ëøÁÆùõ]çÿƒXÚø,¥pËF;)øíx8€xûý“™ˆÛ˜´LìØ/爠mbǹ¯j_ßmþ?»ÑýóõÐw.Ìvožb'…AŒ@åi!€7!ØH s/›§vU‘¹jŶ©]ç>>}ë6¿¾Ëü?Zg •ï.ÓR­ Dr  H$¢ †ÛŸm“;ãs{%m³{Ï||õídó÷3\°7¨Ïô"§›zX>€—ÃéÏM5Ýþ„–‘lœÞÝ4·íp+Î{|öõ—œ~`>€+eÒvíÃ]M®œ–ÄÎzi¦àÊ»=,%HÀ–ókšÿ/ÕÖ>”§kþab¯ãXÊ·Í„Z²pf¦› 0œú < …C¼ ¶_|þ?Hµ‘ø>þMø'gx(¨5œš(.$ÀÆú ¦G tÓÙ¢AÖl%î¾eý€Èü”Z†Šù>ÿ]HdÅyýy%ò4/m`›Æn—¢9…D€jí äxÏÊ¥$@Sù¶ó Ïÿ'õÔG¹œgŒ‹Ré­šîÏ{èÏ+ázš†¶j¤0Ù,6 @@hf‹µZÂ,Ì`‡ëª­@4Î ¬? ^`ô• IÄÈC>‚µº¡6‘´Ö1lÔ»óÍ8è€ÇêL¾þâ¬Þè\Ÿ$@Ópª‘ÍBÀb@G @Þ¨¾ä™ñ: i¸yX@½`ýí#¨f†1eóA>Â]àÁ×r­c<Û» €wKà±ú0îx¸ï(4]Ÿ²N|€#àÉé|€Ðúêñ%ð€+hE´p‘*AúÉÁfò®§ èÁÁ2z÷ »ë¦ þ";üêü‡Cëúv‡ø'&À‰|€Ðúê5¥‘³%®i”Ƹȴ Ƨ é“„ëÝ+ì®G˜‚úSˆý`O˜eáˆpbœÈ­? ×!:`y˜Í>ÀEf|M€`wIAÒ+÷Nìëºé¦ Þ…Ò>¯ ç/p~˜½+|@úÿ²?pBâ‰Ñ&`†KA”rbzž“p“3A „?'@@÷K€ð‡ð+û³ÀúêSÀÁGP”(úàÀˆ¬ñÞ“”0\½ ¥ÿ©]`i„qмC a]€ä”>@hýõ‚õÀGPkêýL¼˜ðï!ØÿñËcˆÄŸ-PÖP/\Bøz]#hнå#Øè9m½Ðׇ`“&@{qØzŸF–ÞÝÓŸ°0~pñ?Ä€ôÝE%Hð  lý;¥PÖP/¹_ÛHüÌÖ*ÂŒyîÞ9AFO"€ÒÇ@½‡8l½O£ËÝÛ{Ðàþ1L€ŽcÉÕU5©®ìŒ(д¾@ ©¹§¦ùù\„ ÝäÎÒv§èú‚¥Ÿ 6µ|€¦òtàæ(ÜõÔK>BàF‚n òí<Ñ@ç+ W@ÞëvÖ¸zJ®ïN¼>eœë“{jšŸ/îxRô |á›Ñ´òhJ˜íDËÃ1Z¦Ÿ{ë¨@\Íe¼1¡àš£ À[ô'Àîc¼ÀÐ8?Ÿ$§QDœ ¥–6ÐF&–´æ¶”‡c´,@á­? ^°~äá\Æ>tƒsáÁÊÁsCý==VFš¯×÷BnYw= ¨?…(àÆ€øƒ=çç£äØøö%ð³bÀ{ ÑL?W/X?òÿ`ãµ=| skqå‰Jœî9øÞ©ÑÀÞ] g gFózQŸ½›^}óõ§º°.þº£ÛÞŒ$¬? ðú ÎcãׇhžŸOÀÅl Àšäúsg ¿oÞìs7´M?w×P¯Šå¶‡SÂ`fʳÅäÂ{HÏ3~ŽÑƒ„õ§u-C;D_sÒ6?_оŸ;ý}ó&:·+ñ¹_lNà„ÖP¯Š‘8œZ#(?ΓØv9…þ¼b®%t}p-óóA ²$;œ¢¯]±7Ñù^ Äç"¯Nà„ÖP/X?@Íÿˆ¤…×x‹d~œéæËœ9mÂ#7÷$úó 6ÑëM@Ûü|؉iÒ$=¼ ÀŸy[°Ïð†ùÿ$rý€$iœÂ@2Nàyõçå_ m~>ìä‚9~Žض¾@›ØVþ­óÿQôì߯©a¬h\1Þ <¯þ¼ÂÁö/Πmz6îEvE' Ánë¶­/0]øÃŒˆý·”ûü9yø_<9”ÐÖ†ßô5T ¨(„ø#X ¨m}EÕ(uëúGÌÿO°ÿwOçË;Íà¡à&i_>ý•#^»™úÔàru¬þ0ø5åoù×Â?4¿üö69æÕF€²Á«Í±ú“ܬɤÿµEq” wMqde/Ú>{}¬üíþ0’[ç—Ÿ†BØîéÁ:H€&ECp¬¾ë jkBË ÕDסÄ^Ê„«E¯Gô=zü&ôuãò7ï*#÷‡¡üÛ:¿üx”¢ö½¢&V‚}e‚à«ïrst• ÕYTVÚ#™Ôj:µ•Y–RôXº ÎX{R;ÔŸßO†Î÷¿çÒ&Øp3‘óË›:yäJâxHˆÝªGk]"Ê«ˆlà£ôî¸V,àJø¡Ú,Å?Ü`]o¢Ÿ´É)V×jQJØbƒáɺQ›Š9¢¢×DÚˆ÷n4ÞJFÒ&HH|üåüò#ñß þèÜ/Ê2ö:@yzÚ½+êzZpðOó¼ØE I…hì'º ¬TµÙ,1 )««|³É64 )G€kµ05YÄ’Ö7W&ˆE–A_Ss66Éy¬ƒÆ›äïÑüe>BN´Í/W½Æ·ÉF`ÏDZΟd÷â e÷žØlàiÏ›Í\L̃ HFÖ€”o¦Fu^ˆ¯ƒ[HC0¡úÙt½0ýiÚlrøAÊø 5µœcò,&ÒúL<ÕÑÂðÆo8‡ òÄomóË'âÿ‚Ã%˜›nïF€ÿГ {Øf€@ÐZ–ù5 hÕ€aVÇ8Y¾ß®n}´'Ø@fš€W0Eh öûls•_mT³¯Ü`~ÊŒ©ð'~LàC„ok6l¼=F8óËméŠ%= M–du @”ˆLQ帞F‘ÂØh ‹<µ‚I¥ž ïjÅ€z¢¶åz˜‡8 àc Wh÷‹½Tö³|?m!†nÂr¹Ô¾BÑã(Opâ q…&7â-ÖÁ¶(Ìhš?u}§æ IDAT*H‘¸S«rßq'ÐX…0ÀC-a½Ià?¹©â0bÌPã#Ÿ¶«>òK=í%“øL2ýèÈ=Œ€yÓRÆK}u…¡†Çanh&µìŒ¾Å 8>€Õ hš?&¨%µy/@X!—ÀôPH‹–>Ï —†uªüCèåÌÔ‚ðÌï>9øÞ·¿&£çÁîñéÑ·{ñ_@¼Éi´J–)¡g‡oÅ{š¾ºUÝ@ªÿyÿêj¹Ž>£wyÅ ~èR™ÁÐÐú¹°MU-ÃÖ¡M$Þ̨~!Ÿ_~,çó'j'«°ë56!ÌÇš!}^Œ5˜ž®ò?áèÐóÜþcî+ ,„!@1ØÞ®ÀÁ£ª–"¶‚ «ö^¸Å->7¶ÀŽß• Ù‘ýŸ0c&++¡ ¤¿Z‚“ Øg@Ž-rd#*xõ«@kÑ:£oòofÔÇV\‘ë‹¢FE$ø ×eS/`§,@Oˆdx¨,Nrôõ¹²hZŒ^ 'ü!ú4˜F`Rg}ªãD¬ä°ÞH¥ €ø#dKX zp :íèÕ/ðyQÛÛÅôøüUW'ԼŽ=¹ª_,7êͲŸÏÄ&ËÙ¦=‰Æ“ 66ËÖ² Œ P”1h# Ë€Ýüü‰‚s°osÿS¬ ¿öÀíõ‚ øq‚[?¶ÁA`5— (2eÐ „Hœ!9-OñFãÓ࢜ Æ °¢Öx&@‘‚ èlÄFûíz•&˜qJDBp&ŠþÒ­œÅöª_ÌÛM¸– ¦B#ã¯ðÛI¨pÃAÜùóª9&p"îêeàv‰BØ!h8ÔL†j=¨ì}<‡s )Ï}½Ä_:hFï@ä:—Hú{|ðû-¼_0@`€¨¯6~xŽä@Àw°_lö’& ãhô’§Ý“‘À&b¿¯Äî)ŠÈsEýf _nBa"a%ÒlÛ4åH5R`„­(uÌ´@Û t†„]\]i¸ò×ÿýÕ@ þp¼rF¡ú'‡ª3#€Ä?JÝÓ [xeR¤f¾Ï}‡Šµ|°@ð¦Ê: ¼cí_‘€‘»ª·o¿Oq?˜-aá2Ž/ôß°iÙ”b#A.8àXö3Ñ.ìaÇË,°3z›å¾ÿV$Üg Þ ì5 $a ª———ØæÄÞlX/༨ÉßИ£˜ê6 ‚øù+iåÒ‡KÑ>l}Ñï_.`Ô,6¢¥Ià bÿ…`Ðf úv­Ž£ Ëj;Xn€H+Ñ˨œ0@UïÓÍl»%#¸   Hµ|3þÌ0΀ž_î‹G€«EKŸÀÓ,>Ý5@ã¿ @ã? À„z<¤¶ˆò-ö 0Ú ŽžjæW«ÅF¸xØÖ°Sß-Àt¥º «e)Å”špÛ€$‹%ùГÜllP ?Ûg °3ƒ­ðók«HñÁ=j…iÙl&`BÑÄcźâÏ-ÄçÏëÁ ëN^ €¹´WA|¦™Õ ´ €ð•m|½mˆ6”+éæï9h4§ÀGË£.s9Ò#â6ûÁ–L63Ñ­ÁYHäÁoòLè7ƒí@9‹ 3ÐT8œH¾Äíö>á€SÈÀÊì7ÛfŒ7P CÁÚTóË5ìÎüòþWæ÷vìXÄ  ‰`šÀ%@M3Ç úb¤¦_˜1!x.цž/|'OÔÑÜqA)X$fgM,0¢ƒ“³‹PàSØ€ñ¸“ð›ôæ.ÔÿÑ#Âyö{<Ó9P+ZbQ©1د¶4&$êýf)ì¼YæÐhð¤”ä¢l‘f0²°Ú‹Æq£ƒh/Ñh,ø€Ù«¥Ý  ‘/Ýð4ò÷p<ä6À±MóçOC3;?…}!ÿv¬žßˆÚLìù—‚i!¢-À@`NÏ"A×{)H±Ïû{á[,E-‡Pû…›P‘  ؤé^Xþ,a¿çH)ãpà­;Œõ¯®ÜŽžL ÀŸÓf„0 @bùw óçOC3{?Åš€@éSç + ĦS^/Œèás )'Dzp€Ý¦&‚–†±Ä½„‰dFEáˆ4z´Äû&„=Ñ,*™²Ü„zú™zú|A7Ìzº^:¢~;I°Ô³——ë»$@T&ÒúÖiŠ qµÑ+› ùÞö³|‹' §«‘g¹‰î† V°#B_a†˜éªÆ¨¼‰ì¿O¶è\ÒõÒõÛ‚µ¬o‘°(wúy˜¤<'íBÆ_D'.«°ßä´JÝRËè¤Ð« {ê›V­L¯øÎ¤–É>úíô‰‰ lš_~$þn7DíôSD¦åòœ]¥Ã´ð4ÍRØ+ä*#®k7Æh´_„I¥séÄóž6ÄÇZæ—=1$”lôô„cD€FŽ«Óí±À¡¹>2 —Šž¤ýÖëåcæ¸nÓÅ–“ÊKÞÂz¿“ž5ÆG[æ—Ÿ€a¡ã´à·9VŠ»%pfÊŸÌßfhò\n=ûãÓÌ kB»a~ùÑ'+³Ð‚ßæXýÉoX`òÆ$ øn^É; 7ÌV4@`0HŽyyÖ?âÄäXýGßß—¶ùóm}´À5˜™f 曺FÓUµó“Þó>C+#‡hL•ߌV´.H=(z0k"OC‡¨/wX/E% '…}{‚á”ÝOëǶùó p›Œ!ùBÏ4ä¸Ú@êéø €þp(Ò¶>y‚™ŽL½¤ǪԬƒ@?èVw=Ðû'Q÷.{»A¯·Úöv½~Úåh›?¯ïôp$?ä™ Û†G&`¦ÿ|.Np%'ýhy™5}’‚ó…çóíV/À  å(o<ØÃÓ‡àˆõäYZÀPæ|ænœo’æùRÂPad‡AYÑß,˜pл+ Ïxïnïz½§»[°—üwOß&“o;›eËüyu£çÃÑ™g:uKç F„qÈÿøxw9ó}‹Óò©á“ļ}|¤×[͸†Ô5j\…õmrÜú ÅyraÁ!¯3 7«¯ÎÅ¡„k”)§Fþëåb%³Ni­>KDõ¿ìîêêù®÷äÚq;%ì?ïîØÒ@ô-xä xoÍÇ!À£"@ŸÀÆ‚£LO¢˜N]à³. ò”ro Ês€Ûà†º€Ÿ½>@‚ƒ=¨ ü1[L¼Ïœ©_i¿¿ÛA¶fl¡ŠÛê?dbròà®ç˜€ú²w7 uçê0=× ø¶3Õ^0À˜"@ÿF¨õ|Æè)Ç;·›€\8ÿiQìWû½Ox.Á¤.a§×ìvßÄ;ØeøÆV)ÖðñO{TðÔ8¦ ˆuž,a ¸£ñO-å»Ü…g[€ZœŒ¿˜u¼ÇÌdC€IޏżCIËåq¾H €9¬n7`×ÀbË馤÷V>ðN»!@FÏp éûuzŒCìS›´™øŽMÀùÖ@à£ë·”2.»p!¯|‹y…ÔØv(ƒ6@œ˜"€ÛD@/º ‹eYáòÄn$€|ÀÉríyᯠÀ}€B5‘^À[ ðùô>8ãúÒM(öÁO4ö˜Rª;‰¸MÑ:<:ÌMÜ÷`aºÛƒ[!L€èMÂÜ%——¢]ÒJ \?õî@„ÿÒ³ÀþI“àõРι¼ àåÂÔÀÛ-öЊÀ Vošˆ[8ö–&¦8ŽHr¹ƒs+Rè_ˆÆ ïÆv—½Õ—˜\º o¬˜ü`q"$@ÿ&Àéü z`3›‘H^gDÊÛ30H€°þ¬ë`r‰w{ìÂÊV$u¦ð ßnw ­È '¦.’|·‘¬LçÖðúRPD,w·;ÿQ;VäùÒ|– þM>€Ó  Hó•±ä¾^,’ו±ò¶‰çÓOCM€¯g8Óú“ l£ ÀŽ\IœwdVPIEGš™[,›e^Èñr À÷ýH/ Év¿¬.w^ñ§Ýå7ùñÇüñ›þ] €ÿ-#@8Ì"}}é%3é“·ÞÉ{~Tì }j+jœa}Ñ„RS?lüerHšo‰@·BŸÛâ4…—²0ÅÈ­ÿ¸Í%ùöu=ôù! «ýðqnž 퇂ÍN€Âc§kfGúp¾ŒŒeKÙš#yíh.gÊÚø7÷êÛôg]@´°èôü -¢©å´0l.ÐÏ ñ½HÑK„õ! ” ê*E*åÂ{¤Ù«óÁÆ–M4ò¿ iÚ»ƒ¤Ä<Îs{Èùuòúúúóòò+Êóüq(þüÁ Äß&ÀNÛsýA6˜½'ÚÁ-ô…˜ìe½1’'“Ë.cŸÚÊ;¼v'ð|ë@Î0N<†î`³3À R‹PÓšqèGlûj(¨ONTŠó R€^ÜNœžŒ²—ñ ¤@}5-iÒ:LZ…ò´íÆLÊ—±l›pV""µ§‡ù¡`0(ÞÍã>@¼ ‰äu @cùÓuϳ>@UÃL à ’d°<ŒiD%ÍUÿL{ŸÅ’ù$µaö4)}?èçèr¨«‚F ¾Êg=¹§ Þ}_ÎNÁû¿H¼Pp`0¨"N Ã0 D{¹}Š|j+²@ЙÖ¨6ÂÄ‚â©h ºšlB\cL·[À3¯ ¥ï£ Aüá⎠£ùã £†+q»…‰ÈûÅöÿýw›£—P§ûbø(öŒ»ÌÓLü2¿,jѼ^¤7Âôƒðõë‹‚`‡‚íqÁÓ &] –Ó4ç[ ‚e !t»ê§ a§a…mdI"ä9‰+†ðn xƒ3²EG³H¯„ý_%nW¢Íxø‰M¡¿x[€ ¸¶gŸcâ)0 =ŸÓ$‡˜ø©¿¬áÉM*~œËœï | ” vÆ…-úáîxÿÛðAç[ ‚Q­ ÅÜZ"¶OvD¢€!v>A¶}Õ'"L ø‘Å{E SNÓÉp.èƒ&\ü.L€èa6&éTÏóùèÒÓ Ám–—yzóe8×3/àÙ<ìæèH hCýpw¼ß ½NÔœm}€ óÝÞTµØËðj Ý>6Ô¼Ý)uFVâ ‰»ÐǸ -ìoÙD4°ŒÜß=ôê>á_-À£¬Òáãp^ËD´ÛA^¼Œ_ Ë… ø›Ið8x öòB^Âýðï´o˜$„ˆ‡ CNàQ8ÓúðÄjŠ`DÙÊxþV 9¶8Ø ÎºÂD7^\)˜¢ýÓ gèv•?ç¢ñï§ô,\ dI½œ=ˆIxψoKá¡fp÷÷‹Dç€ ŽÌwaX(ØÏ R˜…ûá‹'ædþX@Æ @ë÷ôû ¹pÖO±O ÿ9Ç4H3¬€<˜?‹Â2ÜC¾¤¨É€üa¿A°èV ѲÒË…ø)ú¢É†ÑöÓ÷=$†ˆ½Š3_¯Ëõ$)êZøz½(×u‚§ûp—¢ònÒgýÉï_%"ø›& Öß`08Íà¹ì—”G]89OñOÝsíµIß’xúõrÊ!³¿fdÂ(÷–§Ž’Å è1·ÓJA.LÉ #@|U<ì;ÞŠí…ÙÉ’Éd-ðÏ£¡ g&¾A 1ƒÌ¡éœ¦Ìx^dØû—ß¿œþ&% ŽöãeH8MÓ‹‹”˺8GN Êû~[Ð(o^ —ÃÀ?Þ ü³‹1h øI‹KH® ëñ>=dˆ‹ÝLöBÜc*™ À@ý[4ï$éo‡£Z˜„"¡Ð2X’Ù å| Giv­¿'ל>þ<)tïÇ«1§ (ÅÐö†|7§Ê åýŸˆÉ[×À¸ ´÷ˆ?f†¬V·¹\N©b”M@!`Œ90æp;(Šr1¸%ÇTøû|;Ÿp¿G*û-åd[XÕ)~Ï °CÂx•g øÿ¸Éòk}IE ÒmÄD/Á_ ®å Iãð,9.Ôu™n‘àÐõ(r·P@Uo62yd)Fz}+†è/¬)LÂ"z˜Bf¿yEie¢ÈEMÿ½ðÿ’t¦<…¦8b]–51àà/@7 ¸ÈEÁ²eþt;ºJŒ Ð%'?œ“ Ö¨¡‘†®á-eVÊBÁ\@º',‡ú<…í©ACR“º¤Ø2Ä65ºvöÃ>M“´œí!žÐßö7£šlý a^ò×%1àõÇ3®úÆ ðÏ!Ô<ötˆËlñÔð©Ylo;§mšø_RÆÀ_ sOzÌ€õ 1ž±|Ì6ØcJ)¦™M08¼—Ñ~QC7‹r‹.ä‘Ö8‰¬?XIV"ÀÝ…®á™dñÇþc½\,«Éß_žG#Ìòôúë5à#Ð2ú,ˆ»òôÔô©Q:Å"×x*8l°ÖdÀö@¸ˆ›J=r³Ùn7)ŽåL`,ÂE¢þÓà^^èYâ'XkZH.œO±Æat· '’¤ÐÈl†CÑ aï3 £ŠO¥I^ëõ:ÏÏ:à&£ggþIÛüù3À}R j3ñ±k<9øaFÈgEË5ƒ&‰ž<(—‚çm„÷·‘+Ê4ˆ|Ü2z¹°( ?ä”m’à0†ð?àII2!(Åy*ØWÅ_^kq¤_X«uÞê ~ž’”U5ž>O+9Óõõõª |mpßkx¤!X9d9,hØáñ5ËRjZ–K±cõ }“=pµ¨ jÕüÛ±ðŒ†Ð³‹PyÕþljœ¼¬*=I˜.Õ„È×W57Òú î¸Á˜ ,¨a1´º’ºªõøÓ1 AǦ_Ô7õäe9ÿzøÓwúvìõ› à>TûŸ'ÇW±%à‹VDRKš¶`:« ¯Ž­Ùß*¾ªÌ±5NBñ?JTb ùgÐãx x € ¨I%o[OB6re:6è+èïKj=+Æ7 €þ~"ÜG„5¿ €_q¨êD$Pß&íO0ãèËcOù™pôå±+~&Ç^?˜ù(âaÌD ÕzšAñ«ÐãXÀÈsQ É :­&Ò2t<>;¶ý­¶|ëÛ±×߉11Ôûø÷Ñ'O@„ ?yí½€¥…¿8¶ù¾™õSq÷âØ|EÕw!@l qÐF ùc8=ñyèq<ÐÔË–"DûÌ®––ˆŽß•õíub t­oÇ^ÿIÚ‚سÿ  Ë_Õ² a§v`Òá9ÆU‹¼¶È±×ÿNp›Ë>€Œ†6?޽®Îr<èzBî­‰\IWð7ØQ´¸E àÒãŒr,äÒö²ÅŸ-@P?°ýø<úçÇíèŸ<öú? †¶Ú?Sc#NjŽ%@%½>4ûh PKt!€‰þ…â5‹þ…âÇ^ÿ¯Cc#NjŽo0î#½@êÿÓxš€.Ý@ýS!¬yôO…X<ðØëÿ…0lÒ‚ŒTÿãQ·¨sËÐgãpדÐg0úÚûÃဠ…€pd¨ RGÿÂñ@w,xÐÅäŸD¹Áa8Ö «¨¾Sŧ!lj!n;~éFÿJû—ÚþÕö/]l@þ]ùöáXP‹O#?¢!? S: ´…ýR»Ñ¿Úþ¥mÿmòï"Àüþ~îüËP¿ÅòÔo*òKDÀÎ PL¸«ø¡x ü¨ Üà‘ÀÛâÑ%Àc\K[h¶L9Å@úQFÍÈÑ š?QÃ6ê#¶ò¼ø¿3"àÅÿƒ.6 '#Àœß6ÄÐ%À<¦U[”€ „xHø6à¹ÕäxLd%âÊ«»t¬zÐÅD"9w/|>Y˜Õl€ÛHëG#ŸðkP«¶8–o’㛀‰4ø–)AøÃ/C÷ºNN€°šíãìxnmÞ$G;”LÁª- ´@Œ ´¿)#¾éîF #øµC7³M4F¿lý© 0j%À™ähÈšO^:„µŒ MÚ45P2‚ᛨÁðíØëÿ,ðÂÇ^Wg9ÐòSï_>%—Ú€N>ð2‚á›6Œ`øvìõ¿Fíø(9– "@&• V23 ÇÚŽÏåfOi4ßÊ®N4x~H Ó~¤MûÅ0`-“C(#hÒ)+Ø!€•,Gùñ­ŒàêD£Ç๟WŽ·“‰îPvØDf„LBÙsÅ&€ÿÍ&€ÿíØë?ö}û÷@¦ÿã\¬óT)a¤…ûÁK‹~Fðä]ðÜN€_YbyJ¢y*€z‚Ò¤aZæˆÔÆš2‚¯X>B(#øõ‘ÀçV( ïVñ Ž ÄÈ€Ì ¥ `¥rE;Ä>:¤+xáÄÍr4jJ­)|b\ŠûøÇß`WøçOg¢¦âǪmýŸBÞ\þCÄ~ö9[yB~9·þ£¯_ËD­[¡£nzx ÅÛÊ”Xøô,€üg£ŸAŸ$³Y¹8:œq¸T‹r6ÓßhÍkµ´Š\áŒÉk‹^•¿Ò¤gåO`¼O!‘ÅðYÅ=¯>)—‹ÅbVv¢=½È}d`7­-U9‡]ª…Äa{yûáæ¶èuù !Mz^þÏ.'zv ?ó”áÔ‡Íú¶òFŸ”ðp  @û¹¦jb@ãf­-ÿb©*ð¡5Ö ³ÆCðÏ?¿6êMyX!¶IÏÊý3Êu)ò©6¾ü÷þövõí×ûGKæ\(/>µgÃ…ø;ŸCz.õI)°˜µž;.% ‡k-Aø"á³Ðâ"(ðÿzÝ gåañª&½)ý5Ê€û¾^p> nð_zΛð8ç2@.þâwödT¥Øã‚Çó»!>ÔÌÕ;jÖëý'‹î Ø Œ×r1øÃRò„ü‘Fñ¿¸ˆêyy@­I¯Ë_\Döå2i 7 ÿØ=zØ9.#ªŸÜ<ÏÆCódT©´x||x¿ =¾ˆ-½ÝD¹¢z ’Ò'ë²3äcóš´L þô(q‰ð g3‘Bô€šÇõ¦<î&½*Ÿ§À€ðPàŸA[’ÁJy¾þ¿æáŒì[}x¾">ÜïIŸLpø£´‘øš†¹Ä¥I%>”˜¡ê¨©Â¨üûû¸^•‡Ep›ôTžžªªM„{™ö~€xú`+ïÿ¿P#€F€ùÜàúែù§fÀÖï,ü§‚+s¦å©ùvŒÇ÷RŸ èÄíæ¹GÉ;94 UP¨ŸPGí*®ô9>ß.®—åaÝó&=–Ç…Ós¥÷¤‘¬âÃGÛ þIЉ¢è`l=ÑôóùÚP|pô¦¼´÷S½‘$ÀbÖÿETÿµq΀uxªw”ËgÉ›“ÒƒŽð·mÝÀ5ÇóéÀBS}x@„LG®ôø|ÃA\Oå‘ z(K[÷Mq,à ° `!¾;ˆ?ô,€ñGÀg5æ´0ŸÞsüuðB°?ŠêÿT =œc@Y6 pS¨ÇšÑ¢5T#8f¡= Öú=><9®Çòàœ7éÅþñQ{ËM´¥‰÷VÃßB€ËÝP…0~AÈæs«öû©Ǯƒ€ê?5;M‹UÒÓ+$ÐÌØ›†~¶·ÊÃ?a.š2Ñ– 7z|,ò*®‡ò*wÿô[ÞF@ÇêÀÿ«wù& N@€Úܵÿ°…G[?´ôÐn ð ЃûgÔ g8ÉIcL¯`0KwÏ|•Okoª/¦ñOþ}^wÀô÷}Wî-Üßr±ý>8Õ{æ~ÝÛ@B8‘¿ÇûFôî$Ö6ÀhÀ!þËSž5Ü'¶ @ƒû±µ‡„3 ¬«YéÕURzÞá3ߊBld›U¾7±ûº´ðïHìÅOIoE*®ŸÎºèW+®ï¾pÈ ‡NÇß#€ù£è_²Ë& {Næ#S‡ªâ"ÀЕ¦n jXtGšp˜²ò"üC§¨ËãcѰ‡÷à–Wd(>?Ly}²Ä€…°”Ù¢\ˆú»ðb¼66´À ²pðïD‰`IÏÃ|Ŷõ_OOû·õE*7ª7˜Y€°Fž…ÿlìþRЋ~_   ™¸ýêèŸK€žä )ÌKk{ض Á»{„0«ßõ°{8…¾Ž#)ý:‘ˆÿÝPY­7g;Y '0`âþ%õwá6üÛlˆOpšá®y߫ڰH½íG-=ñ#ª¤¢å‰aÎþfVë}'ðÖÔü (mÀ_¾HßÑÐç#ºKUDaä¡Ðcƒ}0Eï]|x èU|眼'€€Ì>u'çLŸØpò þ ôÀ™[‡cesòÐÒ:¥'±VU”Ö˜ Z»zz¢]L¯Òc7råîÿ $vüW@ÔþÝ_^7°×=U±ú0dú=Þ4 ïz4dë%s÷ »yZO~%6û°—‡G6PàÀëæü±ÿÏü•;9Vš™nÞ2Slé&N €L4@Oøo÷ý»xÁòðüDRZúNÀÇ,Â/¡@к~>þº#MB‚ÿaŒàaW+õá{ âÎ׳ð.õ¬ž/Ð×!¶šzlü˦P!:Š.ÚEh£\1 íéÿ~ÖKÊøÍÀþ“>üÅ @µ_¶ýPðÝ_ý½”xÚ]"þêa¯€íÈO£Ú/Û!x|`ñŽZ…)†™^öò^(ØOëëyð+2E¸’FmáõÚñûÆlÊIh\¡%TL6ÚKØÐÚ×ÓÓÓƒz –ÇÁ¤mhÿ \g¿TûÒù3ƒA÷²]è™JO P#sÒb´yÞs ì)9þ-óá­q;Ë,6X4©T¾žUÐIPƒyiHÃÁ¡ò)'÷ŸÀØ/XF¾WT°â}Þpð¥!@ƒ/é¾ÃÀÐ7FºM€Ž¾XZ"‘IèÂVœÇ‡-=TkŒî›ñ‹p¥LÀôÑ(çdîzÂýլ;þ6fVœ5:\\WvÆ&çŽèÿ‹ë€,L ¼èi DögÅÌ’äiŸž¥ ¿ ¬€/BJH;&€ø#,Ї<*ˆ^üŒ†ø†_ÈÙS‰Ý3wÐÖËü¦§íuyüÊ´RùLÂ)å!øÛ °L@4adbKíéÿ믔ÚÍõÇsË¿Ö_¯±ýƒdŒE®"‚êé–¶4¦„ýÅ„~™[³{Ä·¢‚2?o(³5´PΞþÜ¬Ç /K Û[å}5•o… @wü-X& ž1Ä“ö5< ŸðW)}Lî¼WþÏ?ñý»’êˆ`æz¬$‡%…ÚÓ»¨ €@ù¶ðßÚõCàîåù¹CÀ‡ÕnÚöN2‘Ëñtl|Búk–ÒiôÉóËšöïÊ †ê?È¡·ñ¶´ðùÈ4Ñ*ÿ¯ÇÚ}øM™ð3êù¹ÊCñç àm@SÚ8›·œ½Òó”^­‡‰!òþÙ¼ÿ6ù{'ð|z~.<¦§ev0þŒ|LÀŽ:Bó6 :©]®þϧ†ÊÿÙ²ÿ,Ó¹·»çÓ['ÃbzZf”¿»z”o;Sí^<·žK›þÄr€^¾#¾+À··›È€(þwd~ŒnÿZªŸ0LH)Iìoýz’'îïü*xn½%múÓJzùzmò1#Ôn@Ç¿‡—áº\@õ“gý—BÙçÖË{¾csÉ¿Ù1ú÷Ð[Ò¦?©xþ¿Óø €v¿ü†ÿå·€ÿïôê&€êóë¥ì¸ÓšÜõÜÛtn½-múSJzù. ÀÞo°;ˆ¿‰+kÀÿé©Ù€ ¶ÎúïùõRìLÀóêmù\pÚþíÖ"@#þu$€éŸ;ϯ—²³º^½€çÕÛÒ¦?¡Ü4@ôm¿‰|ÿÙˆÿ_ß¾ C1ýþ¥Žhü[Ÿ[¯îÃo£“^À‰;¯Þ–6ý % ½|×m¿Ý ­VÍøÿõäöþÝ÷x ]ªþúYõê>ðnZòcwéÞ§së-iÓŸRÚ Û~2û[¢ÃV7 -ø?Ebú½±…~‡¿úFp7ý9°¼Ô¹õ\ÚôUÙ¾¨`Wé@îø1l·D€Fü/c1õ쟿ã_}#ž°Ï‚òcþèg[ϤM_ÏîMúƒ¤C L½°‘& ÿ]³85oø[ž[oîÄ“®vCá›øwêÜz#múåøåt«Kw&€; ‰Ð‚ï— À+<äçååW”çùãPüùùSBOõôÇYúÀþy¹nÔkiÓ×ÓñéZE€ö9ÔȘà^™~Ý(oô¡¡Äƒ¾!ÈÖïfCk}6=ü>Y>Üåú#8õq»‡…ÌÜ•ŠU>–°Î߃[ >\×Ëe£^I«¸9úQIFøè˜8 û°x€&Ã? õþA@-TÃ2ñþúùôð{]þ6ü˜>gSàg…ßEþÓé:¦WàåË¢Q/¥ÝÜ/›ôŠŠù778CÏŽÈ&€ÐŽP&d@¿ß/¥!.#†úÜzº§ë?s‘ÞÓðë×…Ç€ ÌS}]oÖ‹YÕ‡ïõúnǀƥä•V ÐÈ¡S?IfØï÷Þ?¤Ü¤ÐçÇù3}½pSèÔ{²‹f£AÒªŸžÿön  ûú!añ·ÁÿÃ_šbð^šL½†þúùôÖÍUøËp>ü[}í÷½*~ˆÞ•êe¼hÒƒtЯ›ôËæ´àßkŠøIâ ¢ ‹ûo* »,ó¡zW÷ÓF=áŒþp9  æÚ¸N°GH®^|LˆŒq’4wãΧ¯­“DæS E?JŸ€{ÁôÕ´œ7éÅm:R¸à† €hÂÏN€ÅŒ·¨7iÊïï×~ÿ(½[¿y2¬§>\l— =¼Ý®š€Fû/~‰ïÄ>l4`öÀjÐóð"ã­ú×¢”^ˆ£wñsô£Ãõã#§@7'¿·àßJrÏ¢ãõgÿ;›šxÎqÓìÚÜœkð1zÈÑ;ø¯¿?2*Ü-L¦ÜA÷{ þ5f åóš†kÏ­_Î–ê †xo²Ü xQGé…¸z÷þ«_¼,Ž{c+ÌàÀùÞ‚ÿ_ÍÙO€ZøtÐý½0^äEzŒ¾Z¬OïÈÑúéÃqÏàlïêñ™`oÁÿ¯¦¼t>Àë’îðëçá;XAož¡_Og‹€Þ–£õ‹)éßÚ8€2/ÀþÞ–Ô€÷ÔËŲšüýåy¤î¯@0½þz øÞ$oÔדº|y˜®Cz[ŽÖ/fB_¿yÎõM@`~àjÕ–Ôæ~øpðk½^®Åí{~Öø\¿º@|ߦ_Ì`å@\Õ3 ·äxý¢\,×ëð3øÚå'0øjÁÿóŸŒ]O~|a5èÖ©Ò+”®Oór|?U„öõ.„GëaQæãW]ø>ôûßá=¬ßß‚Ûw»ß߆õ=„>ô ƒzXo¢ö£ÿw‹„^¿»z^@ˆ«ßaå—Ðkôqk¾«·‡m^ÎÛ¹õï*‡<èý}ŽÆ¡Wï\)aî‹ë]øŸžì™0Ðé›Níw®§À lõ׆èÜú³Ê¬tVx:äAïÇKähõ’¥€5øø2ú^ˆlrË4DÆ€2Pù~ú“‹Ué–‹rf-GËA§iøoG+ Á£‰¾ƒpÕ7zù®ôdöý—Òáï™®÷ÈWz˜UZý}/ý¤ù®;•Vläèüœïö#u0'£!üÿôòôAð™3®ÿð éÐÓ»d@¨|ýn{Ë]w+>Ò,þdùyô‘:˜ëh(k€Ÿá'2À˜}߈Â/Bmꂞà1ÆÙüeóûϨËmgw½œÍʵÓ÷*­Þ¾ÔjÉG KÌœÔë’Cé`Iëϳ=ü&À¡·ÝuxÖ—Ë¿ÒÑêíäu¥³ŽÛÀ=V"чçƒY{ ŽaõgøG —ïÿùWÝAµ>@þîÓÃ=ãlŒô¹õoºíü®×K\™S c>ÀM~È‘ºnðÆÔùУ#¹øÿ&À[n»¥¯+²ð†!T5Ô£{Èìt¤ðα$ü‹¥ §æxyÿVM?ë 6Áñ `P¿Ó£î‚ÿž_ßvÛ¡¿,%Šp%ŸÒ$7°ª¸Ã€2)èøµ €¯:¨âNWð üÕ.RsĤôño&À Üö›Wcý…^¾Ç[hú{n=Ý´…ƒ±¹íTc¤(½‡p½\ ØUÜeÀJÁÃPèi6À ÝÅ:`ÀeÛ®EX«‚kø­ÕÅÓ,ƒ±+±ÁÒÿ•¾Ù1ÍA3üOO±. zo4ÐïðÒ6J†r C8 àõ„ÝòEB¸Z½]Å]ÌÊ‚¯Øn\•ìDfp(ßjÁèˆ'¶¶*¸Ñ¯ýD±¬(JÇÿÿMA€¥UÇáÎWÀuµæ(g!„ëµÚbFÏgSUÜa,þÏçWî™@Ç‘áËΰWÀXÁñisÊ8,Ý~)mWâse,â.M@Ó«þ]‡õŽúëÜs0ó!€ D3PXF\I…€Ç·±‡2$Kùô_ Ø2ïÄfÀ iþ9øF ‚ÓË@õGÖpæf‘ÿÛ °tÐÕźU@‚éƒQÔ—B¿Œò€Þ‰>ÈC‰ƒÂ£¿Ýó1D!ý,>m°ú2®½û£öö#dÐݽÄ ¦@{ûBB¡îî%MÓé;ÖÖ];‡~æÜÄ¢P-³nxX%é#פŸÅ  ª¨c‰,ÈãžÞ,%}éÇ¥d3ÒÇ3ƒu`q!>ú'éã }œ¤€ôqϧ—ÄLf‹P€î¹ÑGlTØÀ—³†&7°0k¨¼% ù=l¤~>KÎ/6S`‰jçGE€æ&¶ wUúG, ¬ÆþcAºN9};j¨Ï§Oj— Ï 4à“>ìæ×r“EÜ $€ÖQ'Ð;•Úuò•p'Pê#F ]Ï ø× ™ÔKîv-ín Úd éƒ}z¸[)ôÑn ÕÿEC7Ð>Hó³»2˜¤I£=œ!KRzžˆ0‹€ hïê°oðwÿè—¦. 50¾ÄgÚan¥ Ï,ÕýFH¤ÞõÉê/:à“h H>þ}Ýš°¡,O;zNѧ³2YK•et?b-/ÿ›6|aZÉŽ%€_½ ¥Ö 2ü«cCÁø°n8É'Tü@«ÉCÁ•Ç€Cš€Ð°°Êÿ‹„”ØÜ „éÛKøïùô­è _Kø5CBƒAúñŸg ü (ö`ÐÆeÀot¹«M°Hç_Öþjìñ¯ç+@F»Îh‘Ë€î¡àð«ÉüÃ/1à8@ùQÃwõ€4 ùd×MsBüï{$„l–:ìç&„8 øM€¨Um¸sAHRiõ{¤„á‰%†P_A1àP0¸ƒî÷føizxÓ0AñqáÈm=mR(âo"ôZ­~àMrPZø «ÿgJ G#@ hoìá_÷{[BHSð»ÇŠ…Ú j?Ÿºù &†LÀ ~àì²tþþ)¦†Mê5Æ nKis?z8ø= ð1ùD“Cà·|¡u7ØÂ ‡nЦŸÀB °–B|)…r9[D•*´V¹4c@x% TXû§÷µï$78\†°mƒ6= ¯†Y¢X. ¥'rе~¶ðJ—ÞjËC–ïãÍt É¶ò7pñë1ä&Íp´ Ï!t¼}ÃmzѹB!„(PÍ€>¼$K•NàÈÌY@ìê¦qÔ³<à´›ŸRB×ÞÀe„ó=D‡OF‘¿‚Ðð&³ôÞmúI­Ð×1V[}öˆ (e®}=+½Ú=[8 X˜9'ÁÁy[cºêYè¶35¾;Xüðê´uCr9`uá>5GÊ ×ŠûßÿbÖ$ãñ£% áß·ÅPàÛoÚ M/ðØ)ÍBQÀg‹6$ I€°ÿ&1®CHÊ›Ž ›0Èe€ÑÌ}Ê&2ê¿8XüðâÐCjš@~ôżg^~3Áÿ?!>þñø‰‰O €õ9`ŠœÞ1íú†ô/c¾|‚Þh}ˆ¨ŸTHÿtŠ`°"ô]PQú_¡¡ùX¨4Ý™ÝJÔ¸cgg%÷5LÒNfò…Ý@E{'ãáC þ9Ò¼3¼ ,*n¡jðªàÅg}£*Žúböbí¿’¾–øOQ” ™€v,Öè,z{%§Ro-?bQº ÀÓ`-NÛSîW(„ k20ŸÎ\wfDÜÂ2$¾±î˜þ‹ AH‡;Ào>sm¯ «o¸R¬÷l—nγT]™Òõ’¿ z[méÉ@ýx`› •v,Év6@€@=s)R»“r)?Àó5¡f¬¦újÔ{°¬Ï4cŸIiÑÄ¥ˆ+ïK€”åHêæ ÀH‚¯“¶~Ã6€ô⇲oéK©‡€ ÀÃ2À˜· èB€ºŽl M@Tx{‹µÍšp5ó– Ô m€•|9ó’:”p¿{wN}² Àáq pwg® »w—1ŽsàDzC¤ÞV3½i<¸m@ ÈÏ[Ǻ Ê,§v[ 3¨üp_ªxD—Œë}`Ïyˆ!Ôà%¬©ˆå} ¸È¢ Å,†´é™ ¨š€XÐBòóÐ ” ƒÄ–æáù¡¶T嬪ãSûÚõ0õ4¦'zÀÔÕÅšSd¼2@Î3 ïa]ÊýGªx=í=<¼,ÕìckÔé£. |Vº,SIa6}6eá·'Gø!¡Ip?ý#QFrOL€ÒÌòŒàc`|?‚ØåÅépŦÔ2ü]|Œ f}P·É€ß9(àÐÃ/vð‡œ@ øô6 ,ô—^)òËÞwƒ#y–+ ¹›Ð¦¯6l$À pâ„ù('ôc ôò {—ËIÔñ*ÞI_Wz(ÐÀo €}+?¶öQÝP¸‹4#¡@° øÿûuøxX‚(à /üÝíÆãÝÎþÂïm‘@…¿p 1 =îVð 9~$%Öè@ v`[ã Ä|T êc ø6ñÏ1­'¿A}‘¥¼ªÃiV¨P°ø=KS£/ò¿ªP°Ï€«` ðÑ¡Ø EÈ@¥-0»î⺃ð+¯ ¿¢ÀÿþGƒB= )5üîàÿö €'óÿŸ{ç‰{Êí8Ÿ©õT“„*³@PÍpe üXp= !pɤÈp’äÕÕ•—b·Ÿb0棣>˜79FtsÜͤ×ý…¬ÕLT  ôH~ß”ŸT*ЂŸ ÀÄ…ð#‡c?n8šH „‚©RBˆ=èK°ƒÂJˆÔüdú¿è§^èvP(#`R¦àï« Nz°„ØÕ;bÊוÊðWÕäs$d|\BÊÇ€r‚s½`¦©¿*åË®ãÆ>8z™`€þ9R²>.%Í•‹ #– Bþ°|±žyë窤~ G)øXj?Oúï¿AÏ'„§|ޤÌKJuå ä;ì©ÇêÕ2p}gjÈçHËþ¸´ô6¯+8»ëX=›œöI&f|ØÄ”õ@v…^`ê×QzšjÐw¦†È>tjÖ‡MMû ¢¦öÆ&ø«WSƒƒ„?ËäÌšœúIäØéßGLÿ,Ó³?`zúË´Q¿º^]§ñ¡äñ€ÿ‰äùÜ8•LÜGpYT¿º^]g Æëïý¨EßVþÝdê=¦†ËºúÕõt•°à èÆZ$8¯¶Ã}[ùKœoâVkODt:+—tƒi=]e+<¼œ;æáÕð¼EßVþÄ"Î7qáQ­f°ª,Þà_Zß\ø æîœ;æâõ÷ÜFÈÅëïÇfÝòžh!ÚøçÞ@¼Kà"?@PrSÕêãR…âè=ñÊË=Ë#÷¯w(ŸèóKbç9>|k'€—}Ç<¼F6B.^£‡fÝòžh!ZöæóMhÚØ_Z¯à·@õ]mïáåÜ1¯¿Gó—ùˆoáðe4¿·õ»z§¼+mæÇð‡õ½…/ßLùh 7mløs}¨†Ûz¿†[ú@ wË·ß³`Úh'€‹×ߣá|<ê_l¼@ûø2~yä[¼žAýp?¾€ žÝû.o1¢‡ IDAT‹{|ᅦã¡Å¯ÆÅç+ÿÑmô¹õ4,za`<Mžñâw4ˆ·Ç/Qò~?ˇÄFÔÅÛgÔ¸‘M>ß àÉçiÃõQÚ ñ¸wñà65€—Û&^f§M‘÷ÛüöØ!l›îZ¯M9Ðü‹|‚{:…1=.ð ;Óø>›ãã¹x¹w|èr½Ê¿ÙV¡òÞAÝã¶ö•Ÿó³·áÇú(Ýà÷‚5,ZC%^ìÇyèf³ƒˆ±ƒˆÇipp/@ËG·ÑçÖ‡:€6Pæþ>,qkx°†òÛ˜Ó,ؼ=8ptàÓ¶áÇú( 0l¹^ ZpfhCXñ†¦­|PÞ>|C$ð“´á§ñZ €7Èwµ´x5<°‰åjù£K!W3^>¸E‹…h;ÿ |ö6üX¥#/¿³eÝBÞÙòàméÜG:›Ë»ÇoÑxþ1ùè6ú“ø(¦E0Ð50Ø‚³*F 7u–ÏÞ†ë£Bƒ[¤Éz,1mx¸ü›ÔyÅ|€‘³]¬|H>º~O ×óËL`Ø/ ¹ÓŸyPmjh¸¼é´Y˜Èqcü98ù€§Sü ë;À DÐøE{±òsõ!æ‰9t¶‹î·¥¼v|qK?•jÊÛØ_Z¯ ÎÙ¥4ÍW{aÀ–þXÌ–ëš)kB¼~H ·s+t" )a¦ý¥õà æºƒg®>âÍýÝR^·ÕÁ@²ÙÎñææc[y~üè Dùøœ¾cõ'PÛ†Ÿ~…w÷~„úcì~¾©?§Ë?«-œÁCwðßêϵõÉåã4@N€à`îKh07~Ç=DËûŒsû÷¬?ú¦øB[ù“€„p7ÄÀ¿(ŽÍôú×öçüþyKÂYâðí@ Ð^ÞöÐ_6o öoð/­ïB€³§|z[·¤œº[¿Ñ'—·{è/›7á@ß®Äç~!½ì_Z×¢ƒÿ㓾ß>˜KúƒSí8@™${[,ÊÕ@|.òJv³~e=\c+Új¨''žöqdºÇQ|7;LæmÁ>ã þ¥õt•y@šîX"ï<ñëœ|üh'íüN È¡h“wžúyN>NþÄ*#Uõ«ëÍ•ž üO(ÇðqQ5Jý«ëÍ•þƒ pŒ|ôüýÏ´>ÀnG¾ÜíØýi9@ø®ÛZå€ÔåÕ-h~\$äLúž¿ÿIÖ@ù@Ô°˜9=܆þÖï¥ÿh'í}œÀÖéá À¿‘ +q #Ò´ÿup|*úðã"ß›…úË!<§~úÉç÷«ÿ ú™Õ¢ÎªçÔÝõšsî~ =|ë°>ƒÄdŸûŸÁ¯›"|8„Ep;77Ê0—%jõW"ø½Eÿ³Eÿ¥Q¯rê“•ÉÉ3)¾^eåÑŽ"9‰y çôÝ齄æ¨ý'ÁýóÓçå??nú9¬í» Íú‹}߯õ?/wú£i“þ£söέÁObJÑ n—È0ýNPM@ðCš€}?ÿngý—Îeµ šô—»^¯I ò6è£5Ü™ûçÕp?o߮ṃV ÷æ85<0ïÀªáÞù9ÌYàÓà0ˆ$ªèw À*®ÿ‰gˆë¿à’Ìq}¼ …!µ¦6ö×ЫîŸ?=Üî jŽi@èn‘[»uÖ…ØïWâÕÓã9zQ½\”;ªÿìmø±>ʯB€}i÷Óå_ Ààöv°_Åô„oÓ«eÙcún£Ï­'¸.×ø/¼àÁŸP`7¼ yKääF ïhü[¬àéàõ?%þ—Oaý—!< c>DôÉgoÃõQ>;šy Í@`uÔküŸþ êgóÑh:Å÷ ¾Áxœ7·±¿†>î†Ý@áÐöï4ªœ¿e›0|÷Zhñw¥š€Û——Þàÿ×_!ýÐ1¤÷>ùìmø±>ʯD€ÛO²’N à6 gø?=ôýH¾ôÿ  R½þ;wéìn Þ¿Ó€@wPQ ;,l=#]Š&`î„–`åÇJŽÿåÎ×ÛèñõÉgoÃõQ~-ìã㥅¯×B/Ð`LÖí/­Íã>mIñÁOWWÓ©zž¥kÐ=$¡¿QŸÝVZ6ßAŠHüñ}rôxZ¥.H>{~¬òkàÆ|vúë«Õv»Z!þI(ÀðO°GàèþI(ð÷Ô0~úõêjÀ¯G€Mtþ8V–žÚ¦ˆÓS @œñ#ÆÝx@Ãúƒmóüû_C¯–ŠåSCÍwXB–Ѧ¶ñ†%&Å®üýOCMÿø8ŽÇÓi·aÇ ¤¾@÷üŠˆÏ\oü?+"¤õ*‹üKÖøµ°çqCõðx@ˆi½ŽDâÿøœ@cþùŠyNijX@}'4ìM »$8ª €qÓ 4MÀJ¾DK`ô„?vTyDÈéš1!'𛟓¹p pk€õ`EZ0ú÷€O 5CÔ7èæ jx8¤bõ½|98ཛ8t&@øJïÛ²ãžð8À§žß¬þW%ÀÀŠØN ¾¤>‚ÿÝ‹`þ,Í©ÏÙŸ¿»”ªÙ¾züœgJÿôS|ýßá·õø9½QúŸßÄ×ÿûC¼Ýüzý¹[ù¶ã7?Üd:ïÔ¢h!³ÍSE¡‰ wo6ZÀ'p W+L9|OG`ËãdúÁ4ße ‚?F„„^eøï¬ØÛUrNývšù$Ue¿@=~ÎR¥ÿùM|ýþ?ñ–Þ ?ßü¡ôß^Å×?ÔÛ‚}îV¾íøMçÿë`ÏâŒæ;ê£øCD ³üwM€O=¿ÿX½2>=\Q`8$³o4*´ÙÔõrYUôIì_Ž »4 OqÿlMÀ¾ƒ>Ž?F„n Àü œÀ_—9Æ4à2/€}‡ÑÀ8þ*½€ø½>@f}³Qðó-áótÚuÿg ÀwX™¶ßú !qü!"u¥'ø{}€OM€A9ààû¯²ÿ§§ŒJ~.7]wv>×ßú3êm'õ,ÇoÞ”Ip“ßúóêÛpìþ }½…»ÐŠßéà¡-~ëÏ«ïä”û×üP›äYzc©•JïÃÚÃoýyõm8zÿœ r ¾(ïÝÚà3èÅw£…Ëygý9¯¬0©h$&IõØýþîfƒ@ykŸA/LצÙ;ëÏy}m8zÿ!ü‚åÙ>ƒ¾Èœ¼N†Ð{èûýñ W¿ŒOw}?¤¤ÚÉ«0h}ŠýGðÅÂåiŸEŸ{y½iÔkG'¢o+Ñ üØi’§¸¾6»ÿþb dÈMŽZá°ƒü¦›>FÁ“é3_ùzqÅ tÂ}[ù¨^\þ²æ¨—ãCîOƒ>Ï ~JJç·—åï·ø&õ‰ànáï‡L@&Ë{ —ê¤íü„zÞG¦ž,–±õе!! ¸zfúý Þ–œ_ÿÃä•_ÿëäá û×·@Vð—™u‹àk|ÿôôÚ™w— 0’@>ÑBõâPv?vB½Q¨J^ô½Á(€;µËSQ¶»Ðþ­cq½ÛÏêtâzÓP”ÎÄ,O_ãû§o¤Wnª¨ö !-H„áùMG}a¹ÑTO©W'Ì+¹¥/ü’vyUÔPÀß¿-‡èß|ÿÚ Ë—Vyúß?}#=÷ ÷bD j^€áhCºè!ðäv£²™ ô…ûT¸Ü9nt•àû÷ Dß=¾']ïO“>Ü4.¯MPëþÁÄ/A´q‚…:ê]7Zp*½ ?Öq¦w €1zÿ®ÒÙ¿o ºþ7ëÛpìþ£]€>U½Àw£mŽÕ€¸ `å½ÇBƒøþ}zÄb·ç'Q ¶Íù§Åéšz÷&½öñm}ßB5Q€] á×^b¨|¦{ Ü)yËý‰ëáï9 o„£}:X¿æª-”‡ Âzt2ÞFÇFM€ÖŠÛMLȃ°Î¯ÝËM8šäD± 8à>iC,/Ûr×ıÂÍc´6 °P7À>~ȃ°˜GœÈ_„žû¯¶4øˆEƒ é­û”‡Ê›-r§¼ããÛû¬,@ÑB€ˆ>oÜ¿}|×ŰzÜý‹ér%GîŸ|€ÜÉ ’°Æ”ï®×•Ÿãc—ç gvùH?^êƒ}˜Íú¬qÿ™u}~ù¼ð¯ŸI÷ûS*üÇÙB…&c×Ô,çÏ„^ ÆuÓqLÝ ¤¸uÜÒZa¦¶ñFwâú¬qÿв|Љt¯Ÿ‰vq¬ë/ì:úØÒj*ë±øP pCj«›Û‚Æîr““-õYj9?P×¹>|‹¸¾ïyÚ…­w!‚ë3ú`#ÎôÑNB\Ÿ7îùפ/úöùçåmú+~€¾Çâsƒ©`ý<ÄhÙxa"X&õò€AQNž¥bl½KÙI3z·•uô~~àüÐgû×-PøþèHµ9ßMtôÅB¢§ôþ”5}øéøH/À­ßøn˜<ÿB 7úF0˽w]½AV¸z"wÿHŸ¥ ¸>wŽïÞ?ÿœxïþX˜ Îïé<@€Vé[ p<>”¨BÝúb †`ÆH8VTHi½cÂ\½càåíÁ:OŸ7—÷œD[ï‡úœòmzjÌòÀõs//tØ¡ûçD £7 ÈàÛið‘ ¡j$5Ï©A #጖Z|ÃhcóÏÒ['Ôûø[z €Æý“-µõ…c¢½òmzSƒÃ××~Þ¨o#À ðQ)ÁE®¯C[:©ÐÉî¬|w½>°¾ÈØÝƒ^ï_6¥ŽÞȰ¾ß¦?úúߪwo¯#jÛ ŽŸ³¾)~,þúZ†,‹¾ ^NL¯Z¡·êUÓu¶ý{ýoÔ·àÇ—WͶp&èYCªøoý;êÛoŠã»xS‹Ì&ú­G} Nt|¾­7›HñÔ¿õgÖ·=ÞþüÇ7Û„µ¿õgÖ7àlÇßlªàÓæ¥T›««E9›><Áñ¿] àŸðõ:1@à/È¿æýâ€8§Öö€?~¸– x Ÿ¼BÕÈÚ&@4 õëŸNÖÓÉ€×õ¢”†¢ è`hyëŸåÕý 0›—dá¦L^¦³„¿*qï°Á³Y€:)WU2›¾ðפ»[ÐcIð Ó——{!/$P›…̼ã¿N& u>þdòÊ_Þñ'ry};"ïKOß%a!ÝfÓ“ ?2@šaä¯ÂHÿ`Û§ Å€£¡|‚ 0À¢ýëyRIýr?%ÔëåR7‚í&ð§O£¿íLµ 0LÇåï¡ÕY®«û—‡)AÅÑmhQ“Ùÿ/ïZ˜×up ò˜h'‡@–†RX  ”ÿÿÓ®$˶ì'9»íîÙ«™4…8¬ÏzYràÖù¾¯8@½Á­ê9Ô¼*Ì``é÷2PUû¶GòðûÏrªVaÿm7Ä,%Ã;žµföUà=EŽXøýÃËgyTíÿÙ»ÑïG5;9Ò“@cAãuZ¬H(»©£jÃsæP¢@¶ÙeÄQÖ“ÖD¿™L&R€jÀö» µOŠÿüúÀb©y×Ô¥ÃÓ}uPfôíW ”«ÑC8Ì/4¸¤Þé'pû†e´û;íð"-aWÀ ‹<–4€'§¨…çB‡Z% ï/‘¿òXáS\ðSáñÃW Ìýþ}Tí߀ß?NÓåäC€€Òpñ0¥¹xìßÍú{'ò)9·ðÍÕt‰pM4Hð›>F»å”&tœÆý£}©1ÐÖÁZ_º<\è½ìô7Ó„Êi4ÊK€Ãô x5Žð" nÿ!0¿ó±!0U&ör‰ü‘λˆ$* hŽÝ?_¸w¢Z’Ò&¢N6€ì8ô,ªý?Ã0É#×ÀPƼ‹Ö¯}`1°>ŽiQU!àóã±A›/›pul²ã€ßL]´Ëè~ 6çÒ }šzxãK§)`5¯0W€!ùyìæ–óËê¶ÂðÞ&¡ÏíÛ–ÑJèßYœ„8CåÎsD± š‚9+¿ úWOÞ4ýB6€ìÿrŠžåQµÿg˜ßòðûÙ,2•H¢×>ð?%¾'`ÙMbÿ#o¿ù—ÏÈP¥ÞdE©ó¦ RJ$ß÷{ÊGÐ"ýéI~­æ}¿É—J84ǵQ×-@yù`GL•%y=m·£v›Ì;n屮 gÃ`n(€OÓq`ÁÃOcD…m ÀD}”غžù‘•Õú×3?â³ßÈ~X£ ¨¿?·Rý¢3™ ˆÿÊŸ^__^öçfd¯§¬$ZXä ÆcÿµËýù´œgZ#Ô×[Œ”˜ïkó­·£Oäÿû§’€€Ój±³—·[ü kÿÝù™ kòS°…*@[ч]Ô¼Â6E*€>’ïÙ²àà³<ªözÿ$¿ÿ Ü& d>ã¤V“9IÁÑÿ£¸î¿îϯÇ7õªcíýÎÌÂfàxÂm|þ7{"L Ýºq/FêuîÉ@ˆHÙk{¿)Ý`p»ý®ýyüæ»%~S–(×îv+,W!70ZXo‡ŸƒFÞxάÆÀ"#p©æGlÙ?ü’gy,+0ï}F-/Ž\ÿdD…6€ œ%ÝýÌ@£ÎãÙÄñ™aï÷ ˆMÚ‹P®ooI:è¬Ap7YñØÀ¸ÑŠì$?¤Xñ@(FFæÇ z1@DøûåæÙÚq·kà¶$Îmû*á0Ò¥(pÿ‘ïpÿ!ŽýxNÿ! âÐ)þüö"ØXH—Y5éãW<þ£wÐÜß÷ûýN«¸MŒ÷qè¸3Nš¯/ý$I@`÷&´ üWÜÇd5°0Ñ¥µ8"ûƒîÖqMßï›ÕîÙ}ðáÝnW5¶N`óÝ. ¬__,Š–ŠV(^óqÅ€ñ^?°ÙpnY@¶ºÿñ^~ÿ!ÑØàÚÙç0Ùv÷ÉëkÿjŒ¥ÁlòøˆceŒD@‚ªü>NS'䛜Ïçþ+0¸t̲L#®ï÷{¬MM}P‹;ÀÿÁ@ñ,é “{qwëz{`ôñJÜÓ`‘?l|ìVNf£úN 핆Ø~7Ó l Éd<4JB¹+÷®§'Ÿ!R!7® ‚6Ò¼§v{‹“˜û¦ß¸ñH+ì> MŒyw³å!°Ì hå›Í·u3ËN'ÐÜb?.ô¬F#B×ô„b¿ê‰E~Öhœ6v@fÌ~Hì·…9xÍ`Ì>Ûí„è¨D¬ùÙ*4¯7òبŔ ñ^ï¶§ÝnC<àŘ €dÿ>tÿ!â½¹H ß@Ûm&@‚QÝFÛéŠbÍÆûµ½¹ÝÆ!‡‘‡ñôŒ”>x¹o ã Ó~…+ƒ#5þ{@KÏá <H â,k®ßšÍ# Ÿ×À {{¶¼<Ѓf¶øŒ‰.è9Àê¹Å1ê*‰ð*©*‰ð*(±Ô[£m7îá<ë°<ÐÂÞ­±‹ïn»J÷ûŸÆºjhB$ÊÆS*㺱O6G €ÿ}&X4¡¼%¯£dbžRTl+T7÷Žc²g°ÈÇ.þã=iè•Pÿ¬‚AöS¨36 ¸£àÊÅ£Ý]Þíüû¸wgP ӿ݈x¯¿ÿ2@ñ{ÚS¦˜²Ëqiÿ½!ýg cm™)þ³´Mp«GJe<ƒ‚Ö7_^5`äz ¹À3úþõeÏî`q˜vK46W'2ˆEÍdÜQÆ)'dÜLå±£„Š((ÂñÞ©w£bÀ'd„Uˆì?RÒÞ¦ÿ€‡÷^½ýþKm€(ƒB(Kz±ðÊÏ&EÁY_MFÀgÃÆU]¬JeF®Ì)°N¿ïŸ ‹‡:@¡øOa$€‡ý»¬{ÍÐí\wiòö†?#mµt¦Bv±kȃ8‚*R/㩪 „¥rª ÄÀ*õ¯>ë2±)uìßw8.3ÖÜÒ4·[}Gh>D\°íÒ·]¨ðÌÒ¨€ö‡µ>?lªÎd–&ƪ€ú¶S\! —ê5©·ãëyÿÚ7Ÿã&v`K“¥˜šÈ¤“C" )Œ R¹˜Nå¡á€©{§Ï€P(×Àõ*ÝH„®îuú'Z=Œ:ðÖÖ’޹r vd®¸zŸÊOÔ ¶Án±2ú‡€‰ŒËÄšcÚóÍiö1ì¤bM²yÞ¿À¦/è§va~Š@gÖâÿh3Z‰¯}+D0Nmƒì›ËãÀ² ÉaL—¸?’ÁÅÙ¿Ÿ¢ûÙØ¿ŸR§¢9Ilš¶MxÕL«/h+à]ÊÈ[ƒàU@Ç ÀÕc‚?ø4]Ø”/µüÂÆÛ§Õ˜L¦: ¸Ïý×ȶCcA­7±„H0Öð‡Ëe±Æ¢éD뀧'4.´ "€"üD3àÍ ëòÀ¼Z5@àÇÀô"`ÀáðÃ0 ¸œ+û'±.ÓÀÃþÁËäQ§¢Ë®¨‘â~Ó¶]ä—ñ‚¬2ò®ÍlÝ ¤'ï ZŒàþV—¹M팔‚¡ó„ЙÙåç3x¡kÑîý£=!À6ÂZ4‡ôxÀ\z7 5Mc½5}Bäh7l\ä¿~(p‚}!èaŠ!àÇMüPiÙ% ²ÿPÿ!àÇMTëŸpÑ\\@öªŒÀ·S¦BÅüšÂ­ˆ„§‡§©HYW`Fe~VÇ& $/q;“‰H(éë>O1e'¨¦ó©dû±Š_ê„–Y‹žš©€3[š!€0wï4  ûÃ)]²œÙòÐý‡l@æÞY§5JO–ã”–u›²‡‘©Ùá¤T€zÍþ]ÆZsY²À!e%ʽ(‰i·ªpÛ) Àª#Vé%·è¦F,è[(…fë€âN:¥Í@†c$Í€ €÷bÖ¶<2É€’¤NÙ?JvylïÖý­.¼úî$fø Ö¨ºv‡öã£MÂäõ™¤©ÉYTrs’y©Cx‘ФR4ÚÆ÷0aT™ÿMÌòôÆÚ!ÈÿuO•ñlfãB2’–VQÀ  r³sy4JÒºeÿÈSy˜þ6}ˆwcþ'çOþ7£¬Û$ܪ+¦lc€Ý€÷_Tléú4l˜làÿÇ{Ϧ•;)é4˜e…Xz19‚mRÎG-b CÚáÏbÕVü¶”%Ë‚²ÂŽßÝ¿j˜Î§;€hlÿ8ùL`åzZ®vWS~1 ò?‰%ŸÁ†Qï údSX›áÂ"27é¨d6ú–…€ëúÈÖA€*l!é{8‹½úæáÒªÃÚNÃXœYRÚõ»ûçæðV›Ý¦‰’8´ ¨\.q­üñUb…ùÏ©eY6 (Å ±H ýG•ŠÆ¥e‰ÝS 0«7é1rþ´YmÙ†‹uTEÇ”¶†ï>”WÞ®íe”U÷þæþuk”2(`x.;IDAT%ü§Å0‡àã–ªfì¶G ‚¤’K1½8È“…úÈK =³ÁO ÿÉœä- ¬ž¿žv› ññhŒ[½•6††?¢ ëpyu¨¶›äp)~oÿr î6»ÐÇ™]^ÿ¦dëF1vž(½¼ŒýªaƒRTøå û‘z1­b9¾Âõc¼nŠaî lµòPŸ$¸ecº«ûzQBrðJ6Xø;éî·×ç‡ifðâW Ê*%13_}~ Á=/~*l¢DnÑ à‹ÿ÷èw×ç—ÑF’Ï` 2lJˆ:)ßF-ÇRBÄüú|Ü@Ÿkí€)°|®³?@}Ê7RÄ-—ÝmØŠ÷¢Mbþ[ꃳòM}>î  Ïuö@÷YŸëìPFßg+U»ÙªD@϶ÐðÙÖèsý0OŸëìPF_±™² ‹€žÛ@AÀEÀ@4€Ëƒü/‰ðAÏ:üú|¬Òç:ûø\g€2úzó_!@}‡^îÙ\„é—“«~>›|ÛIE³Býñ»È¯ÏGésý°*WŸëÔç—Ñ— 7;-Ÿ-[f¸¢‡#Îfr;Ç.ýÐwç D_O£"c /ýfÓ¯ÏÇYªÏuöÀº|}®SŸ_F_ùtå³!žÇĨx2WÌD+þˤû™·pKü?J°AÆ©vA¾UIøõùÈx}®³?I>שÏ/£/ÀÄà,©¥ªÄ}òÀA[ãë/™"ö]¬¼Ð˜ÍÇÌ,#ä´€6"s· ú%Ä?U†­:©pˆ­Ï'ÀgmÅWÙëòõ¹V}~ }5z7ø¯¸ˆ“|¬ç®'¢îF‰øÉ/»¸^q‚ësÕú|Üëòõ¹v}~€¾‘«¬ Ѐث¦&áBhÃâTx’z­`â0±ç.8ÎfùA­HSü ôüâP°×ç_8!DîPVŸ{pBÈå_Õçè›`@ëpŒ›×•@{ÇÞr2.åƒdÂ@Q¾@ª’êJñŸ"Îð4åÙäÞñ¹j}>–„cY¶>×®ÏÐ7À]aªy:3Ž cå &ÞŸ-Û”¡â|‘qŒ×¾y9Ødw òþyü¨^Ÿ /@T ÐQbcÖÊ÷BlR‰Ê*Lá´Â?*!D”gS}>Zøú\g¬Ë×çÚõùúzô¤#`ÙŒü7)a9#¯ %L&Oñq:KÓ?-%L€ê³‘Oú\g¬ÊÖçÚõùúzX¸kþ2½·gíüV!ÿÉY0Yãÿ¥Ê¿>÷ÐçZûàM|®]Ÿ o€@€ÈúqÓ»{"i¼uCŠ{)ÑŸ$àËéϨϿMß…/-Ü/ X?û› Cþúü›´Û…ü󫪷4 W¢èï, [ãßWŸ‹vaÿ"¸ÕaÿWÅ¡L}þ úÙòðªˆþOËÃÿDX‡jPO¸IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksDoor2.png0000644000175000017500000000257213263214224022122 0ustar aeglosaeglos‰PNG  IHDRPÅ>ÿ$PLTE™™™wwwUUUªÌÌ̪ªªˆˆˆfffDDD»»»ÙøƒˆIDAThíÚOoÛ6ð|…ÀHºtß 7c0R!§=ùV¸ZìäÃÈ=Aˆ =5Úc`C»SvÜm(Önßn¢dÙ$ŷȪšŠpP‰â÷“ÿˆåÑdó'¥Ü&óÉæö˜P¦p†šS>~Ý{Fýw'Í3ŽB ë!?Ä—ä6Ùº"‘Iõ‡?ìC&Þ(öË B]6AHí…¤¶Ì›g $>,õc·™ ëYD(Ä$UŽwOÀ4ÈÅØ6²:ù5}ú‚yÞ1I%L²ë( DUÆ;»†À»Ð ¬„±mdurEƒ@j¥­©…!™†ÀU5­ ¼—Ä;‚¿Ê¹M­ú&¶¦VJK­¨Æ.t,&¯°Á–wÄD샘ƮTO=½€î÷Ÿ¶Æ®lcW‘!ºûÕí¥‚PºßO¯¼¼¦ˆ«IDw¿ð $Ðý"Dˆ;Ò€øÝrFœ¢Laèi…èqâ#JÄeqzI@YÀ؀ĔƒLÏùŒ3 YÈ+"dñºÈæI|‰™ÆŸ¿%BÜÝï!,„üáþO°]?ø!Ô°vŸÙ§áj§ú¢; Í~¬:žÙ“–jRçh$ä‘ó¨ó™ýC°êxfo­ö¶ŠÒlìó`ÕÑkÝÒõ*Ê—ƒÐWQêÀ©~uÓ +Y¿K y|Mƒ¬aÒ˜ ¢WQH\Eé’3=µ/Dyž5 XeL´BÖz%¡@NÏÔÍÒÁUÒF^ÍÂ몉|"+ÈöTy$DÇ¡ÅCÖŸÕ¿êM†ÌF^?€˜j憬†XIíŠ\d¿«â#òÛ2úû0DÖJR¹\¹ )%e•ÇAVgBݼ AŠVHÁ¶ VRV3¤` ˆ‘Ô7(’Ñ Zª-µdRJªä€ÈJl•G¦–¢¥VDc‡ëÛ€‰­fû}B¢%u¦¤±+\E Þ¹ AI•i‡¬q…: ®&BºH-…«( qŠ2…¡Ç!§V]OQÖ§—”5Œí~½±wÐýâ)ç<¡AàŒN»ßÄògDÈúu·âݧ(å~O„¨Ž§(wŸ4Vgu ¡LëÒëƒUpå >WQÜ¥/ÈQe„Œ!Aš«ñ-Õþ ÍÕøy°êZW{„PÊÿZï rðÕø¾ _ï Bnì#d„Œo‚O+õZÄ` :¤¼~„¿Ç‰»QqGé>$z ­ÙEÛ/¤üXÜ ´Ñë>å.Z )ÌnT?DÚ]´ýBÊõB »‹ÖBìVT½Ê )·ÐJÑ/¤üXÜöç‚”qsVA„jØ÷ ©¶ðz •³J-½„Zp½Õ aýC$®8K™A$>Û†Àƒ„øFª÷ú+µLîè½¾‘©eÙþ8¼Ænv‹F5vÓ÷b—ìê~q¿¬ÙiÞ{÷[BœÝ/³cßqs¬òA »Ó¼÷Qw¤Â±£xvÿ¦(÷ª~UÓø2BFȽ„Œ«ñ‡+ÿ¥¼± †0)IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksFontMedium.png0000644000175000017500000004705113263214224023205 0ustar aeglosaeglos‰PNG  IHDR@€ÚNQ±6PLTE»f"Ì™Dÿî̪™wÌÿfffÝ™ÿÿÿÿÿDDDªÿK­&Q IDATxœí‹–궆ӔBÞÿeÏ`[Ò¯‹Ét¯®‚°-Û_|•5Ù]÷ B§iü¯ëðG…ñ;Ð÷o6#~v%’tÓ×y²é%j3i°Äа[ر”{‡"íw6÷ïô™#ù£¤?Ÿ'“^$eª®œÚò<*~¿0ú§¸YÀ&6“|~É@9ɽ"IÒ}e¨cR¦êÊi -ÓDÇ\üÞ©~»è> ÀÄf’O°47u"•¾ôʬLw¸Ipu…Ì9€ðGÍÊ'5ݛƣ¬ÄqDïŸ÷!NC$-0£ép®:©-ÓDÓ(õçî9„3þ>e e©-q”$W$É€u²²„X€øð“æÄKÏ¡ÈðÁI¶hã‹:šÊyˆÑ…?sçÀ÷Ý…R§Áa©ª¨ïŸÔà!“ÎK?„‹ÖËsäøsÃH pʃx²ákc<–¬“þ…µ•Éç|·Š?våט†ìTš8RÚÑ4“@ýqTâóSI_iI9¹ç¾°3½IÇ¥Ñ&À¸{MÜäN÷:· ŒJó?’6y<á¥QñbX ð<ÁXHëVPÎ&„8V¹AözÿÙ— W6½ã8 ÀÔ;‚eÊž÷li+z ÷t+$A«ÿÀ2¥Ë˰©®ªß}C2žóÌU+ͤ}áˆõIíÛ㙕TÑîp`ê‚e3'#L± ”¹Æ;ÿ%€¼QODpß<Óž Ö„Ý;` µ7cÀ ö‘B0S Y}™2¤´¸ŽcÙ’Ö:¼­ßa@¨ÿ8éן[sVØ• ñÊg¾rv±õK‰+Ѷ~»„©9„Ër.C¸œÜà$¢ðôuß~´·m€ó+©¤ûµVum®p öí€÷õ´± 'rùc‚¤²®|Žhô…2yÖÅE¾>B–ÃîОöM\"7NeãÌ'„ ZGó§6.¤}T©¹B,·n÷(†ƒ8ªl¥Í¤Î³¶6+äå¹±†d€î(Ç“±Ðå^8ýÀF(34ïyRÿ: @g–ÉëHMc6æè2`&—Ò”øÖ³¦ÿ”_Gó9ía‘ÌMíZímL™ø‡oíü8"sVu^~¤¶Œµ|ž˜W™ã [®;܆Tæ9A߉ÜGÝ j—Ø%ã2ÆÿDlÚÛ À®l&ꀴ¸ÐmïÛª]ÐÌþó6õ5ñÓôÒ ¾²BæÖLG@0M‰´q¥žH:ÊqâK©°8u'’ŸÆ­lÖ×Ä7([…Fcy»"-¦öNDÃ-#­”îD¸;¯¯oÃr ÛóÒú³ºBiʪDNe {œÔéwÖ‘iŒÍ½‘Ù'/ðpÕ5·|ÍöL~Ï´Ch´•í~ØFl0^ÑºŽª—¨ïD»°míû9…,"ÿ妚À øý®È?á>ᄼխ‰•x1èCpIbd—Àè*°® «£žÑßæ‹Í+\'0"{|¨/p‰6iýÅ ×jQùknÕ|ë§9eÚórpîiYÓ'àxÅ  .#˜@I_‘UþÑ—ïäZ±* Ú³ AëžF®ÊôaâáD ªdv²Ï ä}ùN^ZÞ~ÚdÄölA0ó骼ÜPÈøëÊ)–Ç _8l†0_ŠMtñNú'1B`þ |”iE%N9‚Øö¼²¦³jXžV …ò¥èãÓ­—ËÑó«òµÌ•ÀJ;ZÍ©"aÞ rO#Û‰¾…)ÇOœ†‡ZùBí§leÊž–ïêÓysUè¤æVÇ’kJtø,@z å;j€“iPAÐÆ+‡ù¡ü >Î\åÌWŠwí0m{6Xš%9ù>‘is4†ÈI¼³ÀH¿/×>«-„J‰“!ïÚñÔžü×sªž °Â#<Ÿm|§ÌÞS 0ªgæ7úòC€£^1#\!ÊðåØäÇþrFÿ?[ñM[‘š¿ ÊßÉ— ¢“­¦I?uÎ1P^®"é1ÿ“þ‡ ·£øùAÏ`;ÞúÖüUúN¾Œ*’ÿCªöùu²ûY¥ç/Où6Žhl)â½òy ±}’½©ñÊøÙ Gù»N†$Ugòw$8dS‚ʇ¸Ò/åoÀ&£qä¿ÿêþzMy•`*½Ùa1žÔ`ý1Ùè?uF÷º¾×æùV°xzZæ[‘uzª)ylE'ý1B¶àdõÝ ÙÇ u‚éIm‘lÓ#@¶èGú}6žl²y)€g0G°…¹&O­xÝn/Wt_Q P½Pó1€Pß –ù8ä< êâåÉÆYË>?' {Ç(s&þõv _ø ÀòOÛS{êetë¤/he›?·v  Ü¹ä¿5ùƒ¦/ ¿Î`Ç‹‚K†%.’]~b]ã@Y¡×¤ô3s°ìB*vC\;å{Ùå'&M€“,{À@¹š€èŠõÝà¤ÒUŒ áêÙ ž<–ÊÂê›Ì6 ÐÏ<#@™ÄÖ<€º“Fо3ËG[>È糸Û1ÐÉ,‚{¤£–Âôgt`˜L…'P_ªEòԑͥȓó/\8šò¥>çiÔ5ÐéB 5€†T˜zˆ#6’ÅHÀ'0hn£–vùõýRŸ3»ßí0²'P=1 ÝÕÊ?: ¼«4ÈÊìuñ5€bÏ;›Œú @ùR€ž'%‹¾æEŠ+="®PÇö¸`Ô #O4  øÀéq€ÓnÇüÊϳTð =¢ðü@šÍC€<;€w LpÀì<³ À)áÊGWœ–ËζӲSÓUòWËSUZ“>ŽÇœaý?á>á>áù` ”ò“M°/&뿼*[ý¶|U³¨~ù—EÏ>¬s‘úŠÚ…´{”±ü + k°¥£-®ôË¦Ô <âÿÅ[¾ð}‚¯ÊTžDŒ¼/t/to@ìªÿ"Û&ôÿ«½oÌ[Öo<-È\¾DÈÆš _ðlŽÖ‰pË0>âÿÅÓ€™À¯“EO,3¿‰3N|Ë—½R°E£ãèÚ`*ëI@’ÇbŸ$™¯”YOEÖs Î ®E M³1@±1?.S}§³ˆÜ²iÜ(K­XZ‹ ¤ü;„'¼JžD¦úM =P´`;\„ùì ¥qù®M? 0)椕2ú°ºOÄ·2€LÆ™Ü1@‡Ë5kú9€“´$d.€8¢¸+NÓ²`Þ(ÓÒ¢J(ÁnúJ"3Æw#ø @ÚaO¨Ã´ù-@¹…S Ôür°ÎojW7p"€ûl¥AÖù¦ÐÏ9Óùu€õË¢ÛÕÚÓˆ©Ñ´/À²ÕÓ ¹„3¬ºælôd ô×%µj8€QdíÜ€½ŽeQUþ€Pøu¶#÷-€v2yÛê,?+íyžój¾/Às º„‘³ö‰­Nô]pÄ“J¹H¶Ù¶ 0‚åV ªø™;Š’¥Ðæ·ïñ÷¿T°CØ ªñëtd €4²Ð…xÓ`¦Àà¹ø¢è B«FéM1ÀIÒäøI,§[©“ºL^ЀbœØ `±YÏå 'v2­MU€&î‚ àDþ/”{š4@¼LÖã[-°€äÀfw¿ºM €à‚ë½­ †ð2khM€dÀ!\gùçGËü‹s„XÖo]× ¿Ý8d`R{h½¡¨ Š=oZ—ˆ/|3Ñ$—ùÁ$«ržØ˜Pˆ? À½ƒ­Ž{›ù¢”GÌk°:Ê€OÏ0û¿ê9Ãáþ¿Âßÿ ‘¬?—Ãv»Ö?5`ûþþþþwúoü»"«Ï{À£i1;¤M¸üðÖ©…Iø;m”þ.>“x38ù–}MÅrhß÷~A¿?ðï$þ]>*2|& àb–­‹c¶øMùÆGhawsÎÀÎ,᳓[¬/F:Þ#œÞßrã5fë||ç9®˜¦bF†wW½/@nW!˜W‹ïÎuÿ˜b™²±§ÿ;€£ø–[ÿÔÌ´Š’½ï{¿rNîï<½œß{eQ‘þ©Dñל`Î8*€“Hö¹ß0¹mw£Tó,Xð úÞàDËHãím±L@Àó¯˜þœàa€âÛrÿÿ2À÷´%€]nñ“Ó&zúµùý,Í­zkÜuüæ#Ò˜-ö°(ÀºhüÙÀ; °é/rÊ—Œä¢’þ‡÷È¿`Ë_䜯~Aó{~ÿ½§Ôž ÀÉ´w"Zÿ/xïWâ~& ^°©_Ö÷X¶1ÊOFþ‚,/ë€eÍàù\}aá  ãHïìxˆÆïü Ã}\VQ–öGòRÀ5ä]æ÷v¶‡i€­/¸°¾'@öÝe¼X{ rÏj„·HwrÞKŸ]okï\Dl‰Û½oîÏ ãÈ—hàH·j­÷.«§Ñ»´•Kþ€à õo̰·Ù’? •—´ŸþÆ ÀÇœëþ >|ð}Â'üÙáØ÷ÇÿºT8~úþÍæˆŸ]‰ƒ$]ÿuëmzI€ÚL,±"ìv,åÞ¡HûÍý;}æHþ(éo·Þ¤—I™ª+§¶|'Šß/ýSÜ,`›^>¿¿d œä^$é¾2ÔcR¦êÊi -}O¹ø½ RývÑ}€‰M/Ÿ`inêD*}é•Y™îp½àê 1˜s᎚”÷j»7GY‰ã$ˆÞ?ïCœ†HZ`ަÃõ¸ê¤¶ô=M£ÔŸw¸çÎ8ø{Ÿ”¥¶ÄQ’\‘D$ÖÉÊbâÃOšC,=?†"Ã'Ù¢/êh*ç!F[þÌ{ÜwJ‡¥¨¢¾Rƒ‡ô:/ý.Z/ϑǟFj€}Ľ_ã±díõ/¬­Lö8ç»Uüñ°+¿&À4dûÒÄ#¥=€f¨?ŽJ|~*é+-)0çã"÷\Ø·v¦7é¸4Úw¯ž›Üé^ç¶QiþGÒ&gÃ!¼4*^ kÞz iÀ ÊÙ„Ç*ò¢"È^ï?ûòÃäãʦ÷xì`jÁ² eÏ{¶´={:‹’ ÕÀÿ`™ÒˆåeØTWÕï¾!9ÞòÌU+ͤ}á7ê½Ú·Ç3+'¨¢Ý;à2ÀÔËfNF˜b=(;æ^ïü—òF=Á}{ ðF{‚Zvï€M€ÔÞhŒ3ØG ÁxL-dõeÊÒâ:Ë–´Öámýö«Bý½>|ù°5g…] ¯|V‘á+g[¿”¸më·Kè›C¸,!·2„ËÉ N"ê÷_÷íGëpÛØ1¿’Jº_kU׿ —`ßx_O«p"—?z8!ô ëÊçˆ6@_ØQF Ϻ¸È×GÈrؽÚÓ¾‰KäŽ}Ù8ó ¡ÇA‡ÖѼǩ̀‹ißUj®Ë­Û½Šá Ž*[i3©ó¬­Í yyn¬! ;Ê1Àd,4G¹—ö?°Ê Íû@žÔ¿nЙeò:RÓ˜9º ˜É¥4%¾5Å,‡þ?å×Ñ|Nû@X$s“C»V{Sæþá[;?ŽÈœU]ׄé€-c-Ÿ{æUæxÈ–ë·!U€yNÐw"÷ÇQ7¨Ú%vɸŒñ?Ñ›ö6°+[†ž: -.t›Çû¶jt³…ÿ¶M}M|ß¿´‚¯¬¹5Ó‘LS"m\©'’޲AìùR*,N݉ä§ñ@+›õ5ñÍ#ÊV¡ÑXÞ®H‹©½}Ñp‹ÇH«C'å‡;îÎëëÛ°èö¼´þ¬®Pš²*‘}Ù@ÃÞ'uúudÇæÞÈì“x¸êš[¾f{z¿gÚ!4ÚÊv?l#6/ƒè ]GÕKÔw"]ضöýœB‘ÿrS Mà?Pü~WäŸð Ÿð BÞêÖÄJ¼˜Fô‰!¸$1²K` tX׆ÕQÏèos‹Åæ.Ž‘=>Ô¸Dëµþb…kµ¨ü5·j>ë§9eÚórpîiYÓ'àxÅ  .G0’¾"«üG_¾“hŪ(hÏ6­{¹R(Ó‡‰‡;1¨’Ùɼ€ÿèËwòªÐòöÓŽ GlÏó1Ÿ®ÊË …Œ¿®œby ò…Éfó¥XO錄#æÊGù‘VTâ”#ˆmÏË!kº©€åiUÒP(_Š>>Ýz¹1¿*_Ë\ ¬´£Õ*fàí*÷4²Èá[˜r|Ïix¨•/Ô~ÁV¦ü·^€aù®>7W…Nê`n%@q,¹¦D—ϤRN±G °7 *Á8`å0?”ÔÇ™«œùJò® mÏK³Ä"'ß{2m!²ï,0Òï˵ÀêC ¡RâdEÈ»v`<µ'?Åõœª§¬ðÞn6¾Ó æ ï>Õ3ó;úòC€G½bF2¸B”áyÓùaÜÈ^¹d  ˜§Žö‘ ÀüÄ ˜ïYT••tõqÖ#«‡Vª¦\; à®{ØæX‹%¡óE€ùo=²L³ë? œû”ßG›€½ÞOº6ñÛd#- è›eRa@ õâÖ³®£nBþQF~/ûD¾¤êWÛÞ[R Z…¶ã·àñˆðV\¸Ç CÇDò=9¼ße"@’CzžkJñù/£Ö(_k”×ÉFð Æ2 Ò¾ñˆú{)¿ì³ùžTÉKaéNNê„96³¡óv¨ P㉖Q¬VMÚ¦”k_P58†ìÞCØÌ¯… T^¬)*‹4fØ`^f¡c¢þ›‚iÊï"¹òÃÑ¢^´tÜ 8#ËoðvëUñ!¼©sä)]ë1€7êÐ> +€‘“y¸†¬¡³",ä ž ö†Ÿ²¾Áú2'}àÒYXuÁÊID_›n7®X™`\ƒÃ¥x{àÂYX¬œDz­{»{PÞeH‰eW'7ÖÆÔéA‘ì²)>ÐïºòMzÖCãËŠ‡'ËoÓ@ `¼\ÛýÕ=ïI!mQ¾n1À(Þéïb€º|›þˆg_ŒÐ]¹²ï°§‡¨|οºïɺYÆ2ß™X* °Ä[ýœ´o”ß÷ÚAK¹£wåhîd<¿%ÂGBÛ°Ü€âWž!Ä÷x§Ñב#÷€ Ðèç¤}³|¯‹r÷w¢µNv§¯5mð÷ƪìB¬Œ #?ò¢±IÞv¬Go¬9Þèç¤}½|›~U#ª(\svYèàt#·4ÂW¬+ß›x­‡*}N¦¤ýŠòhE Ód¥ÐÎ=Ð2Ä57›!ÔŸ.÷®|Ÿ~U#ª¼½*³(½Lu ‰®ý±5²Ç¦âŽ£]DUüãøTé+¢¶Ü~Â'|Â'üú ŒgtšÐRÝ/2¾á/V6ùp§Ó{¯¾(½M‡S²­QHâ©`AÒºóÕãm4íj´ÜGkü"Gocƒç¥H†dR9áSþ‡M~ì/gDñÿ¹Ñ´©ù ªü|9¢A´·Õ4éûÎ9ÊËU$=æÒÿ°äò(~~ÐÀ›ØŽ·þ5A•¾“/G•É€ÿ!U»‡ü:ÙýÀ¬Òó—§ü›hl)â½òy ±}’½©ñÊøÙ Gù»N†$U§÷w$8dS‚ʇ¸Ò/åoÀ&£ã‘ÿþ·¯ûë5åUþA~¨÷f{„ÅxRƒõÇdGÿ©3º×õ½0Ï·€mÄýÓ2ØŠ¬ÓSE˜HÉc+Úë#d ö`Pß-’}LR'蟔Ñ6É6=d‹~d £Ï¦ÒS€M–"/åoðfæ¶0×侯Ûíå*@‚î+ªªj>ê»À2§‘œ§BD]¼³ÜÛx#KƒbÙçç„aï8Êœ‰½è~ðùûíS{êetë¤/he›?·v  Ü¹ä¿5ùƒ¦/ ¿n`Ç‹‚Kƒ%.’]~b]ã@Y¡×¤ô3s°ìB*vC\;å{Ùå'&M€½,{À@¹š€èŠõÝ`¯ÒUŒ áêÙ ž<–ÊÂêëÍ6 Ðϼ!@™ÄÖ¼€º“Fо3˶|o7q·c ½Y÷HG-=„éÏ*èÀЛ ÷ ¾T‹ä¾#›K‘{ç_¸ ðhÊ—úÜú£¨ö?z­4l¤ÂÔƒ@±‘,FÞ+€Aãpµ°Ë¯ï—úÜØýn€éÝ+€ê‰Y€ì®VþÑå]%À AVf¯Cˆ¯{ÞÍ<`ÔgÊ—ôÖ+Yôm0/R\Aèq…:¶Ç…£¹ï IˆÁßöìwx̯ü¼IoÐ#êo/¤Ù<ØÀ›xÂ×ÌÎ3»ìÓ®ÌóÇJô¢¢ ž kÀV¡mZt)o:­Ÿûo£<ÐÕ3€Çò'ŒM€Ößïxìâi»Rõð.nänEk®Ò_€í©ìú[\ß—?»ž½£T¬ÿ^oªø#ÈØCÕ 68ؽŽÞ<À¾k”göA}·H/øû^ƒc€Ædßþ„ ÉïÿDž.ôK]°Zž›³ƒún.-º|çÂ@ãßgdþ„òÄUy&½)/ϵ% u =”ªåù÷rÆÇý—ÂÓàzÈ‚¿ÆwZ.š Îï°$K IDATÊ;ò’F *éË®•‡=Ž ômC¸ùqe€tê‡H´þ„ÞqOgpå{£±–þæê×ú¤|‰ÐÞ¡hCéóèŠÓrÙÙvZvjºJþjyªJkÒÇñ˜3¬ÿ'|Â'|Â'<ŒR~² –âÅdÝá—We«ß–¯jÕ/ÿ²ÈáÙÀ‡u.òAÿ@Q@»¶sσ2–ßcd ¶t´Å•~Ù”„Güÿ¢xëϾOðU™Ê“ˆ#ï ݋ݻê¿È¶ Àýÿjï$ó–õÇ[#÷ 2—/²±f×¼€GëD¸e8>âÿÅÓ€éÁ¯“EO,3¿ž3ö|Ë—½R°EG5Æ;ѵÀTÖ“þ€$‹}’dV¼Rf=YÌ5¸tt-2mšŠùq™êÛßDä–õëä@YBh%ÀÒZ åß <áUr/2Õ¯é€ ¤Ûá"Ìg_(ËwmúY€ùK1'­”ÁЇÕ} ¾•d2Î䎩:\®YýÏì  %ùHæ"ˆ#Š»bß/Ë1À#ÌeZZT %ØM_IdÆønŸH;ìux€6¿(·pªš_ÖùMíêúNpŸ­ 4È:ß4ú9§¿½°Þ`Yt»@{15ê÷X¶zºÁ —pƒUל€þôþ:@ ¤V 0ꂬ°ÁcYT•? T~ÝìˆÃÃ}  ]„ @Þv€:ËÅ @{žC€·¼šï ðÖ¨.aäl€}bk€ý#}<âI¥\$ÛlÛÁr+UHüÌEÉRhó[€÷øû_*Ø!lÕøu:2…@YèB¼i0S`ðV|Qt¡UGéM1À^Òäø^,§[©“ºL^ЀbœØ `±YÏå 'v2­õU€&î‚ `Oþ/”»ï5@¼LÖã[-°€äÀfw¿ºM €à‚ë½­ †ð2khM€dÀ!\7ùçGËü‹s„XÖo]× ¿Ý8d`R{h½¡¨ Š=¯_—ˆ/|3Q/—ùÁ$«rîÙ˜Pˆ? À½ƒ­Ž{›ù¢”GÌk°:Ê€Oo0û¿ê9üi€ðJifÑP»]»ƒh¼—@iO QÚ—äü©€#耠 ê @s.xÄv÷à„ñ^b€÷G Nô§A€Þÿa9þ¦¼áJ‰ÖÕc¯§ÌœŽ» x† †KªM¬  ñ¾w±ôЭ¿ë©ÚøßÉ"Iü{ yUÅ!Üz]‚ª6o”ÅÃ0j/Þ‰m²ªø¯˜ZÏ»|é{iú×µÞHÛnZRóÔLÔ/oùëC€Ê¿ps±²íëÞkrIe5<\M:AÈ ˜0ð¯ëqåãiçW„ü—ªô)úÑÅ®Ç̢Øó,½;xäs×F³dmIÓ°óß üëzµË÷ñGá—¢‰C¯Ô"ñ›JoZõ¶!Ç0žêÂøV–Õ™à˜õ–,:W ªŽè ú´ZMüˆ™± ó/õ†Äñyd…?³LÂ'|ÂÿWø÷ßá#’õçrØn×ú§lß¿ßßÿMÿÿ­ÈêóðhZÌi.?¼5BjaþM¥ËGE†Ï¤Þ N¾e_}±Ú÷ã½_Ðïü7‰ÿ–Š ŸI¸˜eëâ1[üzŽ|c€GhawsËÀn,᳓[¬/Žt¼;áôþ–¯c¶þ0ÀLJpžóàŠ©/fdxwÕûäv‚yµøî\÷>–y!{ú¿x´ßr럚™VQ²÷}ïWn©Óý›‡ —3ð{¯,*Òÿá •(þ€ýãïÌ `¯’}îwLnÛÝѪy¬x}ï °§e¤ñö¶X& àí×LNð0@ñm¹ÿà{ÚÀ.·øI€iÝÿZ€üþÀN–æV½µ@î:~óiÌ{X”à]4þl`€Øô9åKFrQIÿÃ{äß°å/rÎW¿ ù=¿ÿÇÞSj÷`ïÚ;­ÿ—¼÷+q?“¯ØÔ/kÈû,Ûå¿'#A–—õ¿?À²fàíV}aá  Ç#½?°ã!¿?ð0 ÷]pYE XÚÉK×w˜ßØÙ¦¶þ½àVÀøžÙw—Mð `íýÊ=«Þ ÝÉy/}v½­½?p±%n÷¾¹?+ôŒ#_¢? ݪµÞ¸¬ž6Fï Ð:T.ùþ+Ô¿1?BÂÞfKþ€V^Ò~{ øÿe@+üs®{ø'øðÁ÷ Ÿðg‡Ó<Ÿþë:üQáôèû7›~v%’tó×a¶é%j3i°Äа[ر”{‡"íw6÷ïô™#ù£¤?f“^$eª®œÚò<*~¿pòOq³€ Llfùüþ’r’{E’¤ûÊPOI™ª+§¶Ì3<åâ÷&HõÛE÷A&6³|:€¥¹©©ô¥WfeºÃÍ‚«+Ä`΄w8jvP>« ìÞ4e%Ž“ xÿ¼q"i9™7㪓Ú2Ï4RÞàžC8ãàïsR–ÚGIrE‘ X'+Kˆˆ?iN ±ôüŠ œd‹6¾¨£©œ‡mQø3wìqß](u–  ŠúþI R0ë¼ôC¸h½J#–—aS]U¿û†ätÈ3W­4ö…'ܨÏjßϬœ :ˆvï€ËS,›9azˆÍ ì”{a¼ó_ÈõD÷í1Àí jMؽ6R{£1Ì`)ã1µÕ—)CJ‹ëx*[ÒZ‡·õÛ#¬õ?ÍúðågÀÖœv%H¼òYE†¯œ]lýRâJ´­ß.anᲄÊ.'78‰¨<Ý·­Ãm`ÇüJ*é~­U]›+\‚};à}=m¬Â‰\þ˜á„0k€¬+Ÿ#Ú}a'<ëâ"_!Ëa÷hOû&.‘;ÍeãÌ'„ZGó§6.¤}T©¹B,·n÷(†ƒ8ªl¥Í¤Î³¶6+äå¹±†d€î(Ç“±Ðå^8ÿÀF(34ïyRÿ:@g–ÉëHMc6æè2`&—Ò”øÖ³æÿ”_Gó9ía‘ÌMíZímL™ø‡oíü8"sVu^~¤¶Œµ|ž™W™ã [®;܆Tæ9A߉ÜGÝ j—Ø%ã2ÆÿDlÚÛ À®lfꀴ¸ÐmïÛª]ÐÌþÃ6õ5ñóüÒ ¾²BæÖLG@0M‰´q¥žH:ÊqæK©°8u'’ŸÆ­lÖ×Ä7([…Fcy»"-¦öÎ3DÃ-#­”îD¸;¯¯oÃr ÛóÒú³ºBiʪDÎe {œÔéwÖ‘iœš{#³O^àáªknùší™ýži‡Ðh+Ûý°Ø`¼ ¢/tU/Q߉ H9Åž4ÀÙ4¨ h〕ÃüP~Pg®ræ+EÈ»v€¶=,Í‹œ|ŸÉ´y2†ÈY¼³ÀH¿/×>«-„J‰“!ïÚñÔžü×sªž °Â'x8ØøN7˜/¼ç`TÏÌïäËžôŠÉà Q†çAä‡q {å6%€bž:ÙG*ó€`¾gQUVFPÐÕÇY{Œ¬Z©šrí0€»îa›c=,”„Îgæ¿õÈ2ÍB¬ÿt2sîSPþ\löz?éÚÄo“´4`n”I…i€dÔ?‰CÚ̺Nº ùGù³ìù’j^m{o]@HjÚŽßJ€§vÀCqMàs" YÈ÷ä ð~—‰I^ éy®(Å翌Z£|9¬S^'Á4È,HCúÀ #꟥ü²Ïæ{R%/…¥;9©æØÌ†ÎÛ¡*@'XF±Z5i›R®}@qÔàx²{a3C¾b€Py±¦¨,Ò@>šaƒy™…މú ¦)¿‹äzÈG‹zÑÒps€àŒ,¿ ÀÃaVÅw„ð z̉{¤t­Ç @¨Cû,¬FNæá²†Îа7x6Ø~ZTÈúvë Èœô€KgaÕ+'}mºÝ¸`e‚q 6—àái€ ga°r™µîíîAy—!%–]ÜpXÿI§E²Ë¦ø@¿èÊ7éýYXAŒ/+žD,¿M5€=òrmôW÷¼'!„´Eù:ÄK x§¿‹êòmúž}ý1BwA^ä:ȾÀ™P¢ò9Cþê~&ëfË|gb¨,ÀoõsÒ¹QþN>›HO6Yм”¿ Àƒ˜#ØÂ\“çV¼n·—« º¯¨¨^¨ù@¨ïË|œFrž uñÎòlã, ŠeŸŸ†½ã$s&þõv _ø À䟷xJí©”EЭ[¾ÄÝŽÎfÜ µô¦?« Ãl*<€úR-’çŽl.Ežá2À“)_ês˜O :ÿ@è´а‘ SrqÄF²iø¬ÃmÔÀ.¿¾_ês`÷»=¦Cö¬ª'f²»ZùG”w•ƒY™½!¾Pìyó€QŸ(_ ÐìdÑ·À¼Hq¡GÄêØŒdäy€&!C8?pÞ à)¿òó <@¨<¼fóà à\0;ÏìpNG¸2ÏŸ*ЋŠ2x‚¬ý[=„¶i!@Ò¥¼é´~î¿ò@Wÿ͞ʟ06Z¿Ói^ˆ§íJ`Ôû|d8»­¹Jr²¤°›q}_üìföŽR°þ{³¨âO cU,xØà|d`÷:xðç®Qž8õÝ ½àï{ Žÿ=}|øZ€&¿hüyºÐs,uÁjynÎê» @º´èò HŸ‘m<øÊWå™ô¦¼<×–4Ôu‚ôtRª–çßsÈ÷?\"Oƒ@ê! þ~ßi¹8hZ€:¿+ïÄK%¨¤/CºVö8*8з AxàæÇ5–Ò©"ÑúzÇ=Á•wšÆZúƒ«ßè“ò%BWx„¢ I¤Ï“+NËegÛiÙ©é*ù«å©*­IÇcΰþŸð Ÿð Ÿð|0JùÉ&XŠ“u‡_^•­~[¾ªYT¿üË"‡gÖ¹ÈýEíBÚÎ=ÊXþŒ5ØÒÑWúeSjñÿ‹â­?_ø>ÁWe*O"N¼/t/to@ìªÿ"Û&ôÿ«½oÌ[ÖoSYOú’|*öI’YñJ™õTd 0×àÒɵȴi6(6æÇeªï|‘[6¯“[e ¡•Kkd€”G€ð„WɳÈT¿¤G*l‡‹0Ÿ}¡4.ßµégæ/Åœ´RCV÷)€øVÉ8“;¦èp¹fÍ?p6€–䙋 Ž(îŠó¼,ÇO 0o”iiQ%”`7}%‘ã»| í°gÔáÚü Ü©j~9Xç7µ«›8À}¶‚Ò ë|Óèçœùð:ÀzƒeÑíjíiÄÔhÞ`Ùêéƒ\ÂV]s6ú2úë’Z5À¨ ²vnÀ^OeQUþ€Pøu°#÷-€v2yÛê,?+íyòj¾/ÀC º„‘³ö‰­Îô]ð„'•r‘l³m`Ë­T!ñ3w%K ÍoÞãï©`‡°ATã×éÈid¡ ñ¦ÁLÀCñEÑ„V¤7ÅgI“ãg °œn¥Nê2y@GPŠqb7€Å:d=”'€œØÉ´6Wšü¹ *€3ù¿PîyÖñ2YoµÀr’›mÜýê6‚ ®÷¶‚Â?Ȭ¡5’‡päŸ-ó/Î`Y¿u \d€þtãIí  õ†¢.(ö¼y@^"¾ðÍD³\擬È]xfcB þ(÷¶:îmjä‹R1¯Áê(gb<<Àìÿªç ð Â(¥™ECíRtív ñ^r¥=M€8Di_’ó§N _‚4T¨'@Íiºà gØÝƒÆ{‰Þ18ÑŸzÿ;4†åøƒ~@ ð„+%ZWO³ž2s:î‚âa6.©6±.x€ÆûJÜÅÒC·þz¬C¦jã'ˆ$ñ'ìäU„p˜u ªÚ¼Qè½x'¶Éªâÿ½bj=<ïòež¥Eè_×z m»i HÍ?Q3Q¿¼åo*ÿ:ÀÍÅÊt®{¯É%•Õðdp5é!{€bÂÀ¿nÆ=–§_ò_ªÒ§èG»3‹¾þbÏs °ôîà‰Ï]Í’µý%MÃÎ/ð¯›Õ.ßÇŸ„_Š&³R‹Ä*½QhÕÛ†œÂxª Oà[yXVg‚SnÖ[²è\¨~8¡g€èÓj5ñfÆ.Ì¿ÔÇSä‰þÌ2ý Ÿð ÿ_áŸþHÖŸËa»]런}ÿ|ÿ'ýwú§"«Ï{À£i1;¤M¸üðÖ©…Iø'm”þ)>“x38ù–}ÍÅrhß÷~A¿?ðŸ$þS>*2|& àb–­‹§lñ›9òž …ÝÌ!;°@†ÏNn²¾lt8Ññît‚Óû[n¼NÙúÃÂy΃+¦¹˜‘áÝUï ÛUæÕâ»sÝ?æXæE„lìéÿàÉ|Ë­jfZEÉÞ÷½_9¤N÷O‚^ÎÀï½²¨Hÿ‡ƒT¢økο?0g<)€³Hö¹ß0¹mw'¨æY° àô½7À™–‘ÆÛÛb™€8€‡_0ý9ÁÃÅ·åþÿe€ïi?J»Üâ'¦Môükòû;Xš[õÖ¹ëøÍG¤1[ìaQ"€?tÑø³v`Ó_ä”/ÉE%ýï‘À–¿ È9_ý‚æ÷üþ{O©!<€³hïD´þ_ðÞ¯ÄýL¼ `S¿¬!ï °lc”ÿžŒüY^ÖÿþËšq€‡Cõ……€&œNôþÀއhüþÀÀ0ÜwÁe5€`i$/\CÞ`~`g{˜Øú÷‚[;à{dß]6Á+€µ÷*÷¬Fx{€t'ç½ôÙõ¶öþÀU@Ä–¸Ýûæþ¬03Ž|‰þ€t«Özà²zÚ½+@ëP¹äø®PÿÆü {›-ùZyIûá1àÿ—i¬ð|̹îAàŸàÃß'|Ÿ.Ãpù¯ëðG…Ëw ïßl.øÙ•8HÒ _×Á¦—¨Í¤Á+ÂnaÇRßÙÜ¿ÓgŽä’þzLzI”©ºrhËwò¨øýÂÅ?ÅÍ60±äóûKÊIîH’î+C½$eª®œÚ2 Dð’‹ß› ÕoÝW˜Ø òé–æ¦N¤Ò—^™•é7®®C€9Þ!à¨ÙAù &°{Óx”•8NB€àýó>Äiˆ¤æb:Ü€«NjË0Ð4Jýyg€{ጃ¿HYjK%ÉID2`¬,! >ü¤91ÄÒóc(2|p’-Úø¢Ž¦rb´EáÏÜ9°Ç}w¡ÔipX*€*êû'5xHÁ óÒá¢õòyù9€a¤8äA.rÏ…};`gz“ŽK£M€q÷¸Éîun•æ$mòx6ÂK£âŰàu€±Ö¬ œMq¬r /*‚ìõþ³/?@>®lz/—A¦ÖØ,«Pð¼gK[ѹ§³XA Z üï–ù(X^†MuUýî’Ë5Ï\µÒ<@Ú^p£>¨}{<³r‚ê Ú½.L]°læd„é!6€²Kî…ñÎ oÔܷǯ´'¨5a÷ØHíÆ0ƒ}¤ŒÇÔ@V_¦ )-®ã¥lIkÞÖo° Ôÿ2èן[sVØ• ñÊg¾rv±õK‰+Ѷ~»„¡9„Ër-C¸œÜà$¢ððuß~´·m€ó+©¤ûµVum®p öí€÷õ´± 'rùc€ ²®|Žhô…]dò¬‹‹|}„,‡Ý; =훸Dî2”3ŸthÍ{œÚ ¸öMP¥æ ±ÜºÝ; ⨲•6“:ÏÚÚ¬—çÆ’º£LÆBs”{ àð¡ÌмäIýë*Y&¯#5Ù˜£Ë€™\JSâ[SÌrþS~Íç´„E279´kµ·1eNྵóãˆÌYÕxMø‘Ø2Öòx`^eŽg€l¹îpR˜ç}'ruƒª]b—ŒËÿ°io3»²e¨ÒâB·y¼o«vA0[ø¯ÛÔ×ÄÃK+øÊ ™[3Y À4%ÒÆ•z"é(Ä/¥ÂâÔH~´²Y_ß<¢lå튴˜Ú;  ·xŒ´:tR~¸áî¼¾¾ ËnÏKëÏê ¥)«9” 4ì=pR§ßYG¦qiîÌ>y‡«®¹åk¶gð{¦B£­l÷Ã6bƒñ2ˆ¾ÐuT½D}'òØ…mkßÏ)dù/÷0µÐþÅïwEþ Ÿð ¿ ä­nM¬Ä‹iDŸ‚K#»¶@WumXõŒþF0·Xl^áâ8ÙãC}K´Aë/Q¸V‹Ê_s«æÃ¥~š³Q¦=/çž–e0}pŽY ªà‚q(é+²Êñå;ùV¬Š‚ölCк§‘+…2}˜x¸ƒ*™,À«ù/¾|'¯ -o?írÁölA0ó骼ÜPÈøëÊ)–Ç _8l†0_Š tñNú1B`þ |”iE%N9‚Øö¼²¦«jXžV …ò¥èãÓ­—ËÑó«òµÌ•ÀJ;ZÍ©"aÞ rO#Û‰¾…)Çœ†‡ZùBí§leÊ–ïêÓysUè¤æVÇ’kJtø,@z å{ÑÓ ‚ ŒVóCùA}œ¹Ê™¯!ïÚaÚöl°4K,rò} ÓæÅ"ñÎr#ý¾\û¬>´*%NV„¼kÆS{òS\Ï©x*À _àõjã;Ý`¾ðb€Q=3¿‹/?xÑ+f$ƒ+DžW Æ•ì•ÛX@–Šyêb©ÌO\‚â‰0 –IDATùžEUYA@Wgí1²zh¥jʵÃmŽõ°P:ŸQ˜ÿÖ#Ë4 ±þËŠ̹/AùCp± Øëý¤kS¿M6ÒÒ€¡ P&¤’Qÿ"iëºè&äeä²OäKªaµí½u!ªUh;~+^.دÅ5{Ì…0tLd ß“3Àû]&$y1¤ç¹ Ÿÿ2jòå° Lyl/Ð`L ³ é+/Œ¨òË>›ïI•¼–îä¤N˜c3:o‡ª5ž`ÅjÕ¤mJ¹öUÅQƒãaÈî=„Í ùZˆBåÅš¢²Hùh† æe:&ê¿*˜¦ü.’ë!?-êEKwÀÍ‚3²ü&¯×Aß«ê1î‘Òµx5¡í³°9™‡kÈ:+Â@ÞàÙ`oøiQ!ëÛ¬/ sÒ.…U¬œDôµévSà €• Æ5Ø8\z€×§.œ…ÀÊIdк·»å]†”XvurÃamüÉ.›âý +ߤ÷ga=1¾¬xx±ü6 ÔöÈ˵½Ò_Ýóž„Òåë,âþ.¨Ë·é/xöõÇÝy‘ë ûnj@qˆÊç ù«û¬›e,ó‰u ²K¼ÕÏI‡Fùà´ô»xWŽæNÆó[ò'|$ ° Ë (ÞyåBü€wCm¹pÈ~N:4Ë÷ú±(wÿq'ZëdwúZÓo¬Ê.Äʺðó'/,j›ämÉzôÆšã~N:ÔË·éW5¢º1ñ‡Â5g—õNWrK#|ź‚ñƒ‰×z ÒçdJ:¬(ÿV4:MvQz1àíàœ1-C¼QsµBý©àrïÊ÷éW5¢ÊÛ«2‹ÒëÁT—‘èÚ[#ìa*Þá¸ØETÅ?ŽO•¾"jË}à'|Â'|¯ÊxF§ -Õý÷"ãþbe“ÿ÷w:½÷ê‹ÒÛtX1%Û…$ž Æ!Ð$­;_=ÞFÓ®FË]p´Æ/rô66Hp^ŠdH&™>åØäÇþrFÿ?[ñM[‘š¿ ÊßÉ— D[M“~èœc ¼\EÒcþ'ýAn!/âç ¼Z€íxëXóTé;ùrQ øRµȯ“ÝÌ*=yÊÿ° ð‚Æ–"Þ+ŸÇÛ'Ù›ªß¡Œ r”¿ëdHRuG‚C6%¨ ápˆ+ýRþüh2º\øï‡º¿^S^å䇊po¶GXŒ'5XLvñŸ:£{]ßkó|+ØF<<-óˆ­È:=U„‰”<¶¢ƒþ¸@¶à`õÝ ÙÇ u‚áIm‘lÓ#@¶èGú¸øl =Ød)òRþ6¯`Ž` sMZñºÝ^®$è¾¢ z¡æc¡¾,óqÉy*4@ÔÅ;˃7²4(–}~NöŽ‹Ì™ø×Û~á'/Øà%µ§PQ@·nAúòйV¶ùsk—ÊKþ[“?`ú²ðëªv¼(¸ôWXâ"Ùå'&Ð5N”z-@z@?0(Ë.¤Ra7ĵS¾—]~bÒ8À²¬”«iˆ Xßí ]ÅÈ®™MâÉc ,¡¾Ál“àýÀ+”Il=À«¨{0iýà;³ ðbËùzw;:˜Ep€tÔÒC˜þ¬‚ ƒ©ð`êKµH:²¹ypþ…Ë/¦|©Ïu¸h€èð¡GÐ@ÃF*L=ÈÄÉb¤àƒ4·QK»üú~©Ï•Ýïö˜Ùƒ¨ž˜ÈîjåPÞU deö:„ø@±ç]ÍF} |)@¯ƒ’EßFó"Å„W¨c{\0j‘‡š„ü àð8Àa7€—üÊÏ«Tð =¢ðú@šÍC€¼:€w LpÀì<³ À!áÊ<©T@/*Êà ²ölõÚ¦…I—ò¦Óú¹ÿ6Ês]ý7x)ÂØhýý.—a!ž¶+u€Qïò‘áJîV´æ*ýÈÅ>:Àn¸Æõ}9ð³Ø;JUÀúï  Š¿€Œ=T=°à`ƒó‘ÝëàÕºFyàÔw €ô‚¿ï58hü÷@öñ]àOhšü ñOäéBϱÔ«å¹9;¨ï6éÒ¢Ëw.\ 4þ}F¶ñàO(O\•gÒ›òò\[ÒP× ÒÓI©ZžÏ!g|Üÿp‰ < ^©‡,øûa|§åâ iêü®¼ /i” ’¾ éZyØã¨à@ß6áq€›×XH§~ˆDëOè÷tWÞe0k鯮~C OÊ—]ámŠ6$‘>/®8-—m§e§¦«ä¯–§ª´&}9ÃúÂ'|Â'|ÂóÁ(å'›`)^LÖ~yU¶úmùªfQýò/‹ž |Xç"ô´ i;÷<(cùV@Ö`KG[\é—M©AxÄÿ/Š·þ|áû_•©<‰¸ð¾Ð½8н±«þ‹l›|Ðÿ¯ö¾A2oY¼5ò° sù!k6| À«x±N„[†Ë#þQ< ˜üYñ:YôÄ2ó8ãÀ·|Ù+[tQc¼]ûLe=éHò¥Ø'IfÅ+eÖS‘5À\ƒ+H×"Ц٠ؘ—©¾ÃUDnÙ°Nn”%„V,­ERþÂ^%"Sý¨@Z°.Â|ö…Ò¸|צŸ˜¿sÒJ }Xݧâ[@&ãLî˜  Ãåš5üÀÁZ’/d.€8¢¸+ò¼0À¼Q¦¥E•P‚Ýô•DfŒïFð€´ÃP‡hó[€r §¨ùå`ßÔ®nàD÷Ù Jƒ¬óM Ÿs†ëëë –E·«´§S£a_€e«§ r WXuÍÙ8èÈè¯JjÕp£.ÈÚ¹{¼”EUùBà×ÕŽ8<Ü·ÚEÈäm¨³üP¬´ç9xÍ«ù¾¯ €êFÎØ'¶8<ÐwÁ žTÊE²Í¶M€,·bP…ÄÏÜQ”,€6¿x¿ÿ¥‚ÂQ_§#Sh¤‘….Ä›3F¯ÅEWZu‘Þ$MŽ4Àrº•:©ËäA(ƉÝëõLPžrb'ÓÚPhòç.¨äÿB¹‡AÄËd=¾ÕË!H~l¶q÷«Û.¸ÞÛ jÿ ³†ÖHÂu•~´Ì¿8Gx€eýÖ%@p]úkÐC&µ'€ÖŠº Øó†Uy‰øÂ7 r™L² wá €ø£Ü;Øê¸·©‘/Jyļ«£œˆñð*³ÿ«ž3 À«O ”f µKѵÛ98€Æ{É”ö4â¥}IΟ ¸€~:ÐP¡ž4§è‚œawn@ï%xÄ`àDèýïЖã¯ú1Àk®”h]½ zÊÌé¸ Š‡aØ`¸¤Úĺàï+qKÝúë±™ªÿü!’Ä_°’WU ÂuÐ%¨jóFY< £öâØ&«Šÿ÷Š©õð¼Ë—a¡]ë}€´í¦% 5ÿBÍDýò–¿!¨üë7+Сî½&—TVÓÁÕ¤„ìŠ ÿº÷X>žv~EÈ©JŸ¢]ìÌ,ú.ø‹=Ï1ÀÒ»c€>wm4KÖö—4 ;ÿ½À¿nP»|~)š8 J-¿ªôF¡Uor ã©."Y.‡ív­jÀöýõýý¯ôß寊¬>ï¦Åì6áòÃ[#¤&᯴Qú«|TdøL àÍàä[ö5Ë¡}?ÞûýþÀ¿’øWù¨Èð™4€‹Y¶.^²ÅoàÈ7xvw0× ìJÀ>;¹Èú²ÑáBÇ»ËNïo¹ñºdë||ç9®˜†bF†wW½/@nW!˜W‹ïÎuÿb™²±§ÿ;€ ð-·þ©™i%{ß÷~åš:Ý_yz9¿÷Ê¢"ýR‰â¯8<þþÀœñ¢ Ùç~Àä¶Ý]  šgÁ*€WÐ÷ÞZFoo‹eâ^Àôçß–ûÿ—¾§ý(ìr‹Ÿ˜6ÑïÈïì`inÕ[ ä®ã7‘Æl±‡E‰þÐEãÏØi€MAS¾d$•ô?¼Gþ}[þ‚ ç|õ šßðûì=¥†ð` ½Ñú À{¿÷3ið*€Mý²†¼/À²Qþ{0òdyYÿû,kÆE^¯Õ~šp¹Ðû;¢ñû?Ãpß—UÔ€¥ý‘¼p yW€ùýía`ëß nì€ï }wÙ¯ÖިܳáíÒœ÷Òg×ÛÚûW[âvï›û³ÂÀ8ò%øÒ­ZëýËêicô®­Cå’?`à¸Býó#$ìm¶ähå%í×Ç€ÿ_¤±Âð1纂|ŸP ÿáD“˜—E<¹IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/overlay/0000755000175000017500000000000013263214225021101 5ustar aeglosaeglosmirrormagic-3.0.0/graphics/gfx_classic/overlay/VirtualButtons.png0000644000175000017500000000126213263214225024615 0ustar aeglosaeglos‰PNG  IHDR„,æð• PLTEšššÿÿÿßßßùpTaIDATxœíݱQ†Ñ$P…m=”@´%P‚Óõ‚D@[ul¤^]?Ù3ï?œ/Ë÷ÈÒ¼]O“¤•û~ºÔ¯{µ^.O§—{¶ZÂ÷lµ>„¿ï=ØjÂã½[-Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#Ì0?Âüó#ÌoÿûÚö¿soÿ{÷¿ûRÒv}™ýB¹ü ú³ÙÄs{{( Ž‘çíFž×»Á±7>ØGW‡í†žÕè`_ÎF×¹—톞ÕûÁ¼Çá'ƒO€tnü;)ÁHO-ûDZéì»vR‚‘>ÙéÙÈZ"0ÆÖ˯l]-‚e,1_ð*ò†ÈÛŒtŠ2›?½ºXê0%‚gHxì‘4~ÂbZ$ƒˆèM‹xQÉÇð"†PÁÂp>¸ÈÈø‚EÀp"š³°.Ý9Ñ ¿Â¸x†Á{T•R¡ˆö¨‡¡Æ™hϰ"£Çý 69)*¢=®Ã+rýr *‚öˆ‰€=¸HމåM¬ˆñ¸Ö`gR\‡È!ò'E¾Md©Mp¤É(¡Ó m"/¿H‰A_Ëëkì>‚q-ŒG‘ºvÆ£æ7Dfò½5l‚ýœZ'™¢È_´>†ÁYø¡Ic§Þ•¢2'O;e“ÆÍAè½>?«ÓIÉÙ²5ÌÑÎ<€ée#`+¥ôT(›–"9ᣮ‚9({ÔÍÄø§/2AJЬ~òg½âE²2¬ˆ¬oÅÞaÒx/v€×«A/’—áD½Œ¥;ÄzÉÅ@$+ƒŠÈwàüõ8iMöò{"Ù Eäx‘÷i‘çðMûlI`¡€?Ù }Y {OÏH‹a·«€©…gÄD¬yO ‘ZXìì\.gD.¿n%2iÙ§¶O_~ñŒÈ ñUNBH¯øö©"ž!S¿²!§˜HJ0þ]Òh×ó”ÅŽÒÛ FùÒÛ ýŽ¥7ÿ…qÙ©ôvkÚ¶Á™h—}Jo·ŸöŽù¹íRzÓ"`.R¦¬ OìáLŠ‹àã9Dþ¤È«²O¤1ÁE •Þ`&£D«¯åMô>‚q˜)½!DšÆY!R¨ôv“¿h}´­³ðåKo6iÜ,„>Øž¥7\”Þ6—ÅŽÒÛ Æ/òêàýá·IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksToons.png0000644000175000017500000002262713263214225022243 0ustar aeglosaeglos‰PNG  IHDRš½%@tfPLTE™™™wªÿówªÌÿÌfÿ]]]™Dª™™ÌfLùÌÌÿf3nnnÿÿÿÌLLLÿÿÝ™LLfÿf3ˆÿÿO×DI IDATxœí cں΀³Þ3dmFÞ®üÿ?ùÚú°e[vB”uÑ=wcXQ=‘?SU‡CU”½üóä0Ë£²qŽ UüᑇES¡cÃàÑ ÿœ‡%ƒž !Í%öøh:мù ¢ù²ÉôØh,™®Ã›O…0¯îåÜ=äÑÑtM§¢ñß~­zh44'ªÑM{PE3)¯ë5Ð\»—‡ö”4§¦ $ ßt@…[#(’î¤UZÎeÒJ^îV~…¨Þh°EhN'L›ÐØ/N"OºÎ±Òr¾Vÿ)-weh#SÎj÷+¿ šô»=ÈYôh mˆÁ Å' ¤UÇŸãrüžÙ˜¿•r.‚¿ºL9«Ý±ü*ZüÅÞÉ”hBn¿¼œ¸’ óJ)¯ˆ Æ}ÐʽRUu¹rÒ)–WW.¿š} 6èÛpÔ‘9u½ý“óÀÃÓÊ+F382q¹Ðérå¤BçRË«‘ã//¿>ƒ£®ÿŒ £q‘7¡çÀ³x4/W—å>êúñ¡N®¼â–8IŠ®+ÿò«£±dí6ùžJ€& )rpݶøŠ¢r{¨$Ë5¸Ü“2å¡§×)¿ švšÁU4ƒ‡ÄcvZž8m2åUJ&,¯2I¹ c3K)'…!w<¸¨üÚhFP¡©l!ƒn-¾ã‰ÉÉ_S¡¼Š«ª¸¼ŠÐ(åx””û®½~¼ëäwÅò!,¿ šHÒ#p>,ËÆ£IØtq·3b£•K4Iy†L¤AdÄø6ŽÇW™z€ÊéTC-¿2š˜ æO|ÀÐN%6M{-2#厽3 KŽ £éôëqå†?Öàò!(¿-šº6ñXcODã{ŧldJå"i2Ç;2ùœ!sb4ê<Ÿ(Ç*/‚ã˱-£â›¢©kdéÃEÊÖ&¾–¯¨3ÏãåÃèñH&_Þ1™ìùÇF%s Ù 1.  HVn‰¦Î£‰D3ÈV]#YJ»Ky§;ê\lU2'‰.T Ê‘Í >ÜÅbºÑÍÆˆ× ©h—#Ñtœš)ÏÞfnDìٔʡnE¥Û¢i-š ëDd”»U Áþ$é¨-ìc”çÒJïë´Ly”U·CƒdÚԉɤU¸GCåi6a…l2àbc$0xðÃ;XåøSÕñõ|ÅòëwÖ‹…d£ôR4¢_Úxƒ©gÚÂàW.¿šõâp–lrd6.i!ì”òÄÁ£ÅîÆå×xP М/Fã[M߇lÍ,×@c`šacG›!lu*džûMØ…l°B{ðW>»|’‚>€CS×`cðh :ëwšY® ‡”Œ­Òê}HÆt£rÔI£+#¨Ð ›9k&”O’Íê6žÖd<Á&è4Ÿ]Ï?‚\Íblì ZDF ñß”LÓdzh_[šøÃÕÑ,šª„¦âɾš¬Ánþxõ ma»ÑÍkåÙ¤d¸/P…PúÞ¶;ÍþËË_XÞ¨åMˆÆîþT@S¡¡©¾L€}Οúï+ D¹½xú¾éoƒÈšve× d ›U%ÑX,¦íÐlŽUÿenÌ¿©<͉ {©ø5Üœ<ðþS9Dd°B[Õû2ÓÔ¬"4;‰†·ÿËÈ_SîSÅfG£”÷M=4Uš4Uõ eZÏÅ®¿Š¶Éh¬Û…+¿kyPEåMÒ»ŠŽh8'Âã=3'•«¢IÃhªd¸IbÉ ¯¢óŒd{Oñ´›&w.OØør™^Þ¸–¤ç´‘å½Cuz=4Uš4ÕŠJiŽ&nh@Dc#’†L- é¶Ñž1‚k»gy£°¡rù+÷9ÑK6¢œ¾m¸R¿b£Þœš]Œ=7¾ç^¯»oyÊÆ•sQ 匃;:i9¥¿?¯·”ôœí·¯ÞÃ|µñ‹¯§éc§l7Àøýò²\žN^Õ_­¼O㟄=(ïþ‡EM¨$Ê1ð"'’rÐhn€¦¢™GF ©òz ÜTÏGšS§ÄîŠå8Á:r|¬"Ê‘M¤”÷}ø´ÜjÂuÑ0&ã+4#¯¹¦”<Ùm‰íEå}©¼QÙDÇ'h‚rÛ]¤“”»À7…òÝuÇ5(ØàoE[³²]güüóÇöÇÖø¶ý!•x2@NìªS·qÏùw]ºKÊ%ô®¼kT6òxMX.Ød˃¤Ñ˽ÂÕtß:4›ãê¸A6?·vDÕÀXa=Q¯Ôñc„}zÛ_POÊ»Žî •çÑåÈ&@“–ˤɕ_uÍ}Z‹¶_Th¿ð¯Ÿ g´ÍdÃZÁeËE†b‡¡MJiú¡X^ „®Îz±žŠÆÈëkç2æÈ;$hHL ÌŠ¶©Â;ÃŽ’4Wg=¯§UhDïèY¨d¦mÕ ÍyPÁÜÎ`|¨Éƒà„³ž¦§vpº„Lœ4M€¦J48PÛak×µ±£³ž®§wžmG€÷Eæ-jÒê̱yÈ4üÍ~R²ææI\õR½Ì¸fxóàçÿÛ¥¥i¨ÿ¼©ëØhu:ùû‡vÃÈ–·R Ï5ë©zÙ!'´þ–LUBÃlªÄhu°o4jïB¨=ëéz#h ™*ÓÒ¨ÔžS£5îd{øÅµ^B‹Ï”êmg½ª€¦¢œ1¦ÜгŽgMCj‘ÑêÐúÝãOáéhR=ÝÕM¯ˆCn;ÛŒÆö»í´ v—Mß fl"2úƒµïÈ1¶b~¡ž>ëþ÷wòzEC!Ç­i-ŠîP×NrÂïA˜o›ÆwÒ£‰Õ†]ñ•ÞÍmÆõ@±‹Ñôó^¨7í¼ ù!{%4” ÉšF6ÓÑP$wýȵËÖ‹z´:Ø×” !ÜyGíMöO Õëi-F÷­l¯€†Úöþ]Éóúõ!Í£ÙÑkÓchèÅvgÏÜ,Ê¥ƒ½Kç½ ÍHzm ±©p ?kOK×Jšþýýý-ESï[`£m“¢±k<=]‘ýôý»~EF“\Î]ùÞlОý—u(¼|q^o/åø×—ýküÍ“×Ã<ã[«± ì™?¥½<îïÞ +ç3tÐÚÅÚ.ªÕ5¼¡Ö÷ ›š]Œ\Yeçô½M«I:šÈžr÷Nöo/"^BÓ4›4}Š:†“Æ¢y'4<M{1šýž¼lë··÷§§Ì¥S€`þÂ(Zw£ßÊAµý%y{{z²^à¤GtéxÖ=꡽61ˆþíÐ?k/‹º¦ñ¬žûõì½cƒÝ¦¢=¸_–GCbhz6°ýãyMlêíÖïj,e °É\ºCá„wÖÓë‡ñÐÄiÃh"{‰ÁMÎ?J`“Ñ«S6àZ M¨/Ds~G6€f±>›ÿ˜Ít4ÆOç¤eæÒ 9ýj;„R«¬šÓ{„¦ŽÑ Vd{ ˆ#8Ø‚½,´ãؼkZ-ŸŽÙpe«  ì½I{chìF&Û-æ î4üvÆŸQY`…† lxP 6ÖöÚ3—Nh‚P*—Dhu•?ãà‚^ÒA¥ä–ìµ.mƇ’¸=SÙ?îVO¿Pk2šÔÞš]ˆÆ!2{‰&>snmšÆ¡)E’ ¾ÝŠ‘dÍ sc͈J«ŽTb­2{“Ð4„fAhë=¡é§£ÁkOÖòb/ʇl$ñéQxuaŒ ]1 Ÿ®øÞUCÙª#•ŠŸnuÏÎnËhœ½Udo¬B£é¶ÆkÛÜn[ìZ4•ûùƒè( §DMÃé‰%?Øk/ƒÑäbînÇašjw—›X¨ÝašY[”•ÚVooµ ÁQ4 £±sgGKlðatœ‰Ê¢iÂ=‘â«âKÞnólü3פ—Vôò:Á?œßódôšjÏC0‹fÏj}¿2b?Éâ)h*Û瀇ÑíWĆʵ¤)£ÉOYR,LÆÍïêlö“P'þ•ÐØ®È¦ê_38›U²×{4Ro ÿnžACd*z Ëa:09*ƒ†üÈË¿‚ÀÊv¥LÑÚ‹û‹«45¿oo›1ÿqVÅ¿ZÜ­ e¬š_ŽŒjot6þl]ÍhLwt¿g6*™š^¿ƒè¢dNS0­½Lü<›ÔÞ´…Ó¼ºág¬š_XÔèö&¢éD¦´ö9PF£‘) Á ýTû=ŸÁ©+÷p¬åzwU8˜Tì­—܃I•È=MøLžîWvš ìßEh ò8™éì´lŒf?ªd®ƒFÞQy­Ê³©`·d¯wР™È¬µì@‰Ê7ÒŠÖäjµ©üíMþÕ©žÿ÷è̳¨Ï¼Õ¶v9¤’ÉkŠ×¾|ÍEr_«âýs±=a¦ïGü«› ™HË«Âop¯Dš‰½ih†w]‡ÿŽ%ÿ°“ lº«¬Ç¡ÌÄ(EaOÈLµç5ˆ ŽÉÓy6 î^|(n‚‘µ7MhõChhª;JJ bIOíàùÛœ–ÔMj:Í^›Ø‹¬°‡ª¢­Ø{Ã4QØìY{u`/44 hhP>ˆf/®<½ô –"”i6(hÒ+×ìáùµsK MÃ-W‹’lÈ Qì…¨éßøç$4 óÕÇЈ‹×D¯­ëz¥À²â`S°W)Yÿ8˜{)Y­qÿb{õD4šÕ¼>M­l2‡úK𮔤å²9a¯tî2=™±Y2JÞ\àŸÿÆDp|[»4iFЪy«º+ÈM‚X©i“å8ëeô®²·êN>Ë'É¥€fý{éߢšœå2‡¯P_†|–q±o–Ê iÃhãkz5‹%óœ¼ßH¾t%Ï3›Èïß&ôårÖå1¯1c3Ó™,@¦”„¦Ò h~;63š©Bd 9ñû÷X]4có!/ÿ=ùýÛ…¬¤t4Àæ¹þÍ‘èX?J“ 7ó3£É«LA§ª‡—Ã胑_OFûQš@;R̉g&«3-kêºÔ}X2òezt¿ͤªÜOv›hwjaz¼XMʰBl&8ù…FB ±lŽÅ|<ÓRM4ÍPãÆüÍz]:í× A£1±dÓf¹„›h™ë¯I´J5Ñ8še…9#Ѭ­äü:#!}L웚8—TØ|Ð/ÞòCÝa(×D²ÎVwâ«aXá|™‘Ðïña Çcíc®«˜ÜZ.½Zþ Ÿ14†qI*RoںȆ;_€Ìïç ªf;Žáç’Á ¡ˆŽEc“ôhkÑÖœët:NFZFSdó÷„j;^Ðl>=UX¿”ØØˆVÊ/¸G2V¡Q·Ö²;‚ÔL¦Èæï ™(b?`rÍlÐàÓ•ª´êhJ£ƒ‘ mͱZ,ð×ÍZˆzìå#¡‡“%ï¹1 “²q¶obö¼Aj©¦2`Öç¾EÚÆsPzœÔy^œÏýáàà@ÎØ-UòiséHèñ„ÑPokDÖç·'û–,£)½V êç~‡d`Õ›ˆPi šµ¹#ú~‡p@,ز#ÇæÒ‘Ð£I]ûÊøýe"ý~øn_17Qêì \finuÔtM·ÞRkûö´}ÏÂÃ!4 Íréû)SGB%µ%#zQ#l ™·÷†€—ج!¿¬¦cS+ýª ho‡§wsV`Cp‹›Œ„J e:ÂbìQbc+» Ùû»@sʪWç7ÔD6]Ôz{½q4ëó;œ•ÙÍ™ö‰RÂŒ„Dw»”‡ûT.®´ˆ±G ÅÛlÐtÆ€»DooÞÞž0Á€ †éCh ÞjïŽác8g`“^™ …ué_ÀÆÏ ó¦çå†îRڦцèÀ™pZíÉëõû“m—ðNç¦[t¬œâ$4¼ã¾siÈ,ÎŽMl¸çjütÉHèñ¤¦¡9Ÿ}4°·DlZ©„l»Äµc“t«ÆÑœqÛ! @ï}­ñFÑÑØ 1›Ñ‘ÉGÖ/‘©öϾ#\n8ª5WíZJ8j]§bÛr¿ÃÎt§#›µÖ傯‘YkSXCÃGáHˆîŸ #!­)Ž‹«£¦Ú_CCíÑZ ˆ)¶÷=/ýNA£ÖfÊ­>Íed¸B>À8hÍCæs®ã`Gª¸_zjÎËŸ±Ÿ<òöíÏ“N@aÅÎ-7•^»Æ&ˆ±à’kY•v†z1š*­ÎÞdð“i4UƒÜqÈ E|¦Àþ²[>t,Àæ‚q´_B/ë"9&ô}¨Ã‚é$@i³}þ8š8UÏç"™J4*Q—j¹%žZNŠÚ^rËêüxÈÄqb_ÙJx6šÀ©Œ¹:ºül„’Œd‚ûvÒzMŒFÎݤfƨchxQ‘B§-.…Ú—v¶ûêòž$ƒÕ±e³¾–ú™4Ôy4aÊüš0]ú F …I££15;nsðãË—¡uÅÖ-ïÙYáÜ8E€ñpä¨,­Ñ¢żZ*DµÙÛ›Ô¿h½&2&š¸üü™Öß.¡9ž#'GxÐŒwp ’v–GÊM;Öv´.Ûõ2š(Ô94î¡þ4Òšl&óÈQGBfü £ ûŒÉɉ?>ã7ëM¡í õaBúÙJy-pRDBhhª¤5w±Îi™‰h¢Æ®&A³éo¯íâí±ùÓãâ¶Cwçl'{‰Í¸ý” »ï+ƒøˆ$Ì¥ú¬ò‰VhhªÉh¢æ®¦*Œ„´¤YœaÕC·Û¹µ7<¶ÀÆ=Š5`›™†åa;£‡öO£ös`D ¥ÕQ³á~ÇIw^Tv 4Ìœ‘¥ÊuX»,v.ñ #wlÜêR1mê´mJ´ði—'ª2w2Ÿµ‰îlÝ¡èt–™f¯˜Í9ÈǸ ¾ÍtIî»,œ'}÷ó:b½Ü÷VÓ3@·º\A•¸bÑÐï*ñúpÙ¾À¢¶jëôи—”'äM®·{4•Šæœ¢Y‹ºüãï…]Rƒà%õŒo;"UŽ-]~j?a#ÑÄ=®s.‹›12\ .ܤPª{c4¢VîµhaébܺŸs: 8ôèÍ_\ڎБà¶$û=Ùww«ÂÆE-n=òUTÚyBe¬í¾ š`f ïÝ‹$rk‚³ã›0±?½„S˶#pCŽÂ¢uÅ ;Ü0Y2Ù¤¡« ¸Œ€Á3åÁÜ MÐÛAud™6«±19ók¨Ðvì´¶)¸ô ~öÅM‘°q~GdÎã©pE¹š¨³­Þž€²î'ªmÉÆ>ùmztµ™Î ‹ÖŠÁ¯e»²Ñ’Æ»òga¹@n†FT ™¤õm‘º¸tB‡ãÒ·}(Ä?“b縸íº·9ûë¼}ò,NÁðO£2]nˆF6tÅùŠð¦îØ(vâYžLÛ!Ø8ÊIeLO(l’>¦Ãp[¹)š²xá„[4HÑ^¯×Që-ÓLvÐIÛ?;1ɾpÍ·‘¢qW2ŸŽf„nE. ßò…,s]tRí/ÊößN܈ÝG>ÍZ‰²zS ¥”d4M˜ÌëgÔƒŒ¼[„ro0…FV"që;%ÐrZ!s€3NÈ(O}&˜OE“›ɸ§¶Ò9aÖG”hÕˆù2Ÿ.…}žoòrìÂÚLÓŽe«­¡WÅx )ìó<ËgËÅÐfý‡ÔŸå䝸’/ w¹|v=ûäfh´o—NÊGÏz7M›Üùq Ü‚³³ÈíšñØ2ŸŸ$ëì¬Gz÷Bž?ïë¬çôî–5âæ€-OÑ‹Œ¯³^À+Š^¡-ÁvBKñYôî‡æ°<¦N(¾Îz¤w74‡—Ã1ºAÔW[f=Ö»š¡3#¨n¹[“*¾Aƒf=¯w4ð’Ý¡ë–öIVã:ˆ>„ŽÎz^ïhÜ&¬]7ì÷èCå|ˆõœÞЀ \冮Îz¡Þдî#ìOÂõÞ9º:ë…z÷éµñÀÞ!{ÞEaí§0ë ½{užm×µöG8Ì-b¼P]õ„޽ИjUûÎ$;>DGÍzNïnYC ^[ ŒÒ)Ú<Öszw› ð.Ô‡ÓéÔÍzºÞýæÐì^J›ÍsUÙ:Õ9ßEÿªÞ&Õû4•ÈÝ¡KyåŸÔÛ¤z÷\¯ÁY¢‘íÇp!vŠÞµí=Úyï¸ÊÉ.}¥òq½©ö–Ç+ë-a²kŠ=Ø4o„Má¼wB³”.¨¾âö=´vqÌëMµÇzGÒ+Ç-åôüÖBþ¼Vs’½"›’“W†³àIDATwC#<Ð\µC¯ öS^òQE­ Ù»«pÌ¥«uH{.æE{Ø òÑÑ|ÿŽéÍhdÅ’ik·¤D‹JÏ6ß¿c|òö„3<ªzÔ*ãÂ|FϺf};ây7>è™ó²=J¯²›œwB#Ó{ #“M°·,Ù“ç=.Khl]…v|jh¬Ê4ð‹(¡=kð#þÝÝÝ¢ÆH¶V44-£±Zv*E5ýÝØ[íy½ºnÉì~ŸêÙÙ+Ðk÷Ô õpÅyB{pFŒfrÊÎÙƒ™—rvÙ—äßпcêßÝÐPÓY@•FDFGcì-Ëöüy‹hàçØlÐ Í>ƒ¦&4oV554f/æÝù÷YhÞŒwÍE©•Ÿµö–#öP€Œ½t0j#ÉÖ†’O·'ˆomMhˆ žr¿Tа½7¯µÌ£A{L&¾Ž» qdò¡´höD¦öÒªh&Ø#½/4Õ¬ ÑìS4•]J©8(âY4­b/Æû÷IhLã8Eëž?ˆ5X2bB>ÅÞ2è~hv0”ÎÔ¦+ýÄoåõ6vR2ÑTì)Z¡½œwAÓá#ÎÝüA1½±éÐÜ{nLžÿ˜†Šž`acÝ ýž²´'Ȥš­E}´@q½€Æ¸ìÞ?(F£kM·gŸðê\c_Ò£XvCÍÒǼ¤Éz@¦€ýëTÿîó„rB$c6¥ ìI4E=Œ%5>½£d˜×d{öÂiš¨ìNhL$WS"iÐ<“…@Œ ½çIö`­ ®|D céŸ|̉Í@=Í?ao86j.Ðéü4pjå¢äx¦d­ŽÖzbu¡„ÚÍu³{4G±XáÌø—:xO4ðyÓÅJ.ðë¿Ú”иÊhŽck5ŽŒ;iÆ¿˜ ¨jh¢e¤2šì ëŽhdaxAø+úà^›†9&zùÉš gtÆV½GükÝ ±±jÖ$±Ît¼{Ÿ…&x˜ vêÑÕ$‘ZÐSÅ6‹†¦L‹lÒà$h } T ú&aó°h6mp˜kÞï2±¦´·Ѳr<~„M…&Z[-„±æ4{© ›;vžK¡Üã³ØûÄÁVkkÆíÁ—-ÎL@C±tÿLBIlÒêîÚ³2 0Wž ¸Ó³œS"¹g ¿ŽÉ´0ßIæ¼=µ>ÃõÈÖMãkNâ¢Cù§¨S^Ç_Ç_Ñ"Ƹ=ôop* 7Fƒ“úm†]‹dM¨%WLèËÌŠXöÉ¢±ø U[÷/)®ËF¨3g¯Å½£iÜ †2¼¬L¥\º¢¹—R´'Ù(At„F&’ŠÊÍžÚ+ÝRù~hx˨$’ÙÞJê_)»Â›R÷aœ ê|Ô¿L=Ú9w–Ìí6Ýú¼ Þ¾ŽÜÍÃoŒøUôf™e–Yf™e–Yf™e–Yf™e–Yf™e–Yf™e–Yf™e–Yf™e–Yùð3’°D˜IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksMore.png0000644000175000017500000003177113263214225022043 0ustar aeglosaeglos‰PNG  IHDR  º¿8³`PLTE™™™wªÿªÌÿÿ]]]™D™™ÌfÿœùÌÌÿfnnn3ÿÿÿÌÿÿÝ™ÝÝÝfÿfL3ˆÿ»»»ÿy;<®W IDATxœí]‰vÛ¸•­T®8ò󴙸cYÿÿ—OÄB‚$¸x‹ÓD˜3mpÁr ‚‹¤¦Ù4@cã‘ùíjÅ?]ÿ7]&_T¿DgêW£ÿÇØçzÉŽ“ Füyú˜mµ¹ÿqò'ùJý¥_¥þcŸ«i5É9ý¿™”Ÿþ7#eús¿oÁ”ü¾Z¿ÐG~Õúœ}®¥Ífe´Œã¸§±2Â/G0òµüÇÉŸä«õs}ÔëW«ÿÇÙçZ2Mˆ7h0ĸ¢?¦ß^Ë”ü¾V¿ÜM•~Õú˜}n@ÓÄjôZ¡³7`‰Õf¤‘ußs/Áˆü¾V¿ÜKZ¯­Ÿ©ÄÿLd¬7°IV#0ØÀ?«3øÍF.¦y~ó1!T•/ËWë»IéïÊóeÁ,ÿS„:B4Œ´Íˆ™ä¯ãk sìù~ògøjýr7IýýBy¾+Xà"‚”{³æD0N68ãšáPÁ$¨ºŽ Ö¿ðù›¤ñ ù’|µ~¹›¤þAcy¾¥ÿó&š&‹3é ó#dYc ß4’€PŸæ9wà¹É*/)_’¯Õ¯è'¡@%¾k¯ÀÿD„+.ÐÞüm~-ÍokøUí#:.ª™üI¾V¿¦›Jùkõ»þw'̪ ,ÂP3ký©¹ªà_Ûþ}äOñÕúUýÔÉ_«ßíô¿7°¯CY®ßAG†x‰mû÷‘?ÍWê×uT)~·Óÿþ´qÙ—?ü<âr Bu‰mû÷‘?É×ê×uS'~7ÔÿÞ„xÇGHW¼ò›€}ûÙÚ—µŸækõ‹}pAMþJ|¢jû=špCˈ cƒÖú#a&÷ùf9 'Ù–“ö›FõRU†£·Ÿäkõ+ºi0»ˆå©ÄGªµß' ÜÆÔ sxvS.–@¾?Woš6/hŸùqÅ+ÚOó•ú5½4°ŽÑíãQ‰oËÕÚïÁ4RFeð #Ä$t8ÞVp2I¥”ª«hÛú’ö_ÄŒd{—·Ÿæ+õ‹@A]þ˜J|n¯N¿ÇfT°È‡C 3‡ÂŽP1ŽUs@©ý€-WõŸi?ÇWêWuSiŸZûÕê÷x‚‘1¢B0yÂo²×Wj?ä£íêû×ÚÏòãúåNªíSo¿[Ù÷î4â)*…GLÄ«†ÖÕí_Û¿V?Ë×êWôR%_½ü7³ïÝi¤€8Ò.1¬õé·9-É·mÿjý _«_ÓK|õòßξ÷&Èáèk1–ÂL‹kþ¶ofûUÔ~‰QûY¾Z¿ÔK¥|µòßξ÷&(é¦ÁmÚWºÁV°mŸî'ŽAûEþeígùiý“½$åó©Äwt+û~ÁI§V³u4nèÄ­ÚÇݘÆ7ƒ©ýÿ²ö³|µ~¡—ùêå¿¡}ïNæ¶e¼` n²LßÐe½qC›º™Gí—ø¥Å´^?ÇWë—ÔHËg©Ä—Þξ÷&å€iŒn€]Ú>ŽßžRàÝ_üÝXÇW-·Ÿåkò•IÈ'©ÄwøŸŠî-%fœêñößH7jhâ¯à‡gvf-2rhIÕÏô¯ÊWR#%Ÿ”«ÀògùŸŠî'áã㸡·#áb åj¾h³²~ºM¾¬iù$•ø®¹ÿ[‘‰¸ŽX5x,Ò@ £|<ƒ/š¬ªŸë?–/«CN>QªÀ—øß‰ÐQÓßòìö½iwg*u^’ªBÌ3õ«Ô¿Ò~_ž.u|-•ú. U#ç9úÕê_i¾¯O{¾’J=—„ª“´Z¿jýkí÷åéRÇ×R©ë’LU‚ÖëW«­ù¾>]ìùJ*õ[©RÌJýªõ?ÓŠ_…vøÿ®r`Þ‚R’Ôº¬VʤʅRçµö•iGI!› nl^  „09¾Zÿ²~¥øÅÖ¾0¥­ƒê*‰S’4-þ™UõVjíK’ÑVApÅœeÏä)-U‚¯Ö¿¾ŸT©3›û‚êì*þ±£òx.¤¬\.«•¢ÐM²ØÙr5ª4leˆ>ŸJr•:¬¢RþZý²FýJt©kë_Ú~­Ãê…¨“¿V¿’]¾ ]êÀÚú¶Ÿæ+õ¯é©Tì<±¿ ]è@WÿJˆ”ä* \¥D¦£R¹3ÅþT{ZYo‰lõËÚOóµú¥>êzÒ‹×Ú_O¸þ¨=âª6ÄNß©Ù'I¶˜àkõK}äz*•;Sî¿‘ìRÐ?äª\ žÓVõÂöÓ|¥~©\W¥Rç þ÷i“Rñ"«&»r©CíENj•¯Ô/õQÕQ¢à¹íýu”3Ù.Ï¿Èa¥ËÚÏñ•ú¥N2z” ÞÌ0Ÿ•Jv»Ô°¹Ïèÿ6‡u¥Nʶɂ·´Ì§¤²í.´ìú/Õ*5Y«f¥|õò_`‹OIEË]hØ[õ_ªVj±VË:ùêå¿À'<–~y]/Ô%ígùjýKÕ(•»“Y@(w}’UI·‘ëìö³|µþ…Z”ÊÝÍ.MBt/üS¤[JvNûY¾Zÿº~R…îf–¥x5b9WÒ=d«i?ÇWë_¨H©ÈÝÌò‘”Ð!±?vÝG¾ü"+•Z,Y¡¤I©Èý¬òqTtò5t 㩞n¥³ƒ’ÆÕfÈö’.s?£|çðsé.ržQ£Ô–Úþj”JÝÛ*w§ë<ÈÓ-E=³ÍLYE¾ µ(•º»UîMú½šn.mnVQTËñÿb%Jå>À(÷¥«¼_A·÷\Ýr<É¿T‹R©°É} >”±¡ÏelðEmô>Püö¯}±GðU¡ðM,?~üþýó#„NÒ°<<´ÿ/H+úvņ?ª‚/uƒW‡âëeéã¨ü:0ü} Èkêǯ_!„ÈðëiFÈiÄOx‹Ãùí¿æ |ô¯ ~ø ù ½JŽøÁ;”&|ü21äq~M9ι)á·þàýÑôá.|‘4¼oܼ0Rðä7Ž/B|Bƒ§!7¦‘¿±†  ŠÓôÚàŸÛ1ø€B™˜÷ƒÎ„H!ÃŒž3iC߸€ôtCßâ3ß? È_¾Éñ>!D I¹Wt1ø €¤2üšs”3i¤O±­è•÷ü’¹ýÚ}“ås+€!$‚Â{æ(Œ,B¦Bó t&¸l¡ˆ‘_l€°ïºÖùÜâÄòûYö$’”ÛCðᢣ’”!ç.Yø›;#ÁçøAžm„ø`„<ÿùÏuä') ˆ\š£ >@4`’2ç(çÑHŸ°ÀôB¼Gœ^6?fùØáCäâCD$)4)ÂüøuÙV›ÄG!”Äf2ç(­hÅJŸ–]Ñ—ûð³8ðÅÐß´Àøðòðá')^x±…pJ‹ûCã>|€„(°IJ6Gyz*Ì@ß?Ê:7ø¡$˜Gð;øU5ø0AšŸÂÇþP/J’ò'ȱ‘’V0Œ ¾§]’rUŽòý" ìœn6”…âþ}͇ù´E†ïðáäçÏ?ÿ €DIJ0ÿØBŒžç(ºA"!>T„ˆ$6‰Še*ðÝrÜqµqÙçˆY~Í,æ;ØYþÏß@~NðøCGGI ÁÇD&)ÊôcÈ.ƒdM‹ Η^’RÈQ2û(ßq´Áx@ßñÄãüªî°7þÏŸ¿Kï#: 4þ³a¹ðDàãg$až×áCûÒOR.ÎQ°@vôõˆ>ô 'søuzütãj¤/V79þäü‰~[ç2: >!¯ÄO )áþÓò“šøéÕ\Æøˆ$±*B*r”_ o…Þ9G ÀbÏ^pO}ÄuNŠß4Ï€ßÆw?<,@À•ÏXDàç¿ ÏE<=±¤Ï\`b»ß–e€p™-[?¸Ï•àÚ×Ûý¯¡‘2N¸04b€Ø`¼À{Dy>Äø_¢ƒòŸÈTD”@¦”ÊøÄ’>s‰-~m¢äð”9.ýZr”SÕk ïAp§79ðƒ«‘î‡8ŒM–ÏÎÿÀñÁ xŽJ Ód*ð,¸Š¨\ z_âÃ"àðÏÿ¨L C‚© ³ÿP½&(±Ò¹_•ðÖ‡qþHÇaˆfùš÷#€`™çˆí 2•y~vLEÔg,2a|pø‡1pœÊH>ð7›H)P‰o…cÞ#Ûð‘ Þ@¤oËçøȳ ÿ$@žC®/ÉT‹èð0Í@{0Þ÷ñ1! `]iÊHú'Ƈ)“ÇÇ„dŸaÞ¿Ÿ0³àOSõC¼R†§0#]JLñëýg ìÌg¿ˆ†p?$)íŸge‹ÄxÿiéÓñGÐÉ  ÉþM‰ï…8¬énÃs ^K…=¦Ä·‰§‚g,ñœÁGîW"D‘ÇÀýˆ¯ˆŠFÈ7‹%âÈ@Ƕ´-BûbŸdùBþ '*‘O2¢H ÿ ÊH®>‰ óìþ¿4áruE»flhá¤À·á!œB¤§Ÿ€ÜT‡8„(9ÆA&¡3ªÉÜ5ÅË„ã†6I7t³Î\°DŠM<3>žŸÿ¤ç?¸Ä­ñ¡„m9€Ü¸ÿ¯Lx ·IWt9oŒá.Y“åcÏ*@¢®"$e ò#*’Й"ƒ7Z¤àí‘nÁ«˜$Ÿ¡èPÌ1 ÜIF™!@ÔB‡9É8›øñ—‘î np»”¯nš<Ÿ›±¹GŽQC!sŽqCÂ}Ò¥ xì²¢;Dˆó@.ñä›KDÈÏtÿ‘IÆ9H€< ÿ¯J´ÁA·’q“ŸÊåI3QxLw¢ >MÇ»dQ’ñ|„Ìø¸%Á ]ôÀýsJ9p/Ì–kè)˜±á'üc„`y >hµ›8‰éR*½äZþCåOò£úÙ.ÎÓ¯Rÿ²ÏÕTz?ȵüGÊŸä+õó}ÔëW«ÿGÙçj*½äZþãäÏðÕú¹^ªõ«Öÿ£ìs5•Þr-ÿò'ùjýl'ÕúÕêÿaö¹š®}?HíûC>Zþ _«_î¦J¿jý?Ì>WSéý gñðÝváûC>Zþ _«_ÑOþý(D%>S‰ÿ‰¨ô~j~³¡—ÝQ» ñóÝ_=‚tù²|µ~©Ÿ”þA¡<_Ìò?•ÞRËWš&~“NÔšüêá ù3|µ~¹£äûSüBy¾+Xà*½¤Ì‡¦ª#al°¾ø…Ïß\Ÿ¤¥äKòÕúå~’ïOñ[+ð-•øŸ‡®z?Õô´7Wá<çn<71PR¾$_«_ÑOBÿ X‰ïÚ+ð? •ÞR~HUûˆŽ ê_*’¯Õ¯é¨RþZýn¥ÿÝ©ô~òûC®kÿ^ò§øjýºžªä¯ÕïVúß`ç/ó~ÿÚöï$š¯Ô¯ë©Rþ:ýn¦ÿÝ©ô~ÿÚö¯]è¦ÚOòµú5Õê_gŸjû=œJï‰øMðþëÛÏV¿¬ý4_«_êƒKjòGÅJ|¢Zû=œèA—Mòý ߌwøˆåߤý¦Q½´j.n?É×ê—úà’šüq¹Ÿt«´ßÉw†ÑñûAð%T°žõ ¹Ášå$µØ>ó£ª×´Ÿæ+õK}©òÇø¶\ýNÅ÷ƒP)¥ê*<½¨}Á;ï+¾§saûi¾R¿ÔÔå –øÜ^~'ÜiÆE>JŒÁûAÒ465û …öC>¶\Õ¦ý_©_ꤜ¡Î>µö«ÔïáD·:2ïÉRÙ…öc>Ú®²ÿDûY~\¿Ô l¤ÖÙ§Þ~uú=œpLà=¨ú~û¶mÿzý,_«_Ô£R¾zùodß»ά¹÷ƒÜ·ýkûOÔÏðµúe=êä«—ÿVö½;xKO±Æc)Œ*\óß°ýÕ†c½h¿Ä¿¬ý,_­_è¦V¾Zùofß» ”tÓàkQi_©jlU¶?^ôþ‘¢õ³ü´þÉ^’òùåJ|G·²ïÝ —cr/`c®ñŒ|ƒûVíãîLãŠÁ””ø—µŸå«õ ý$äó ø²¹Ù÷î„ï‰ODFºÆ}›öñc½_~YàçOkRõs|µ~I‘„|²H‰/»½•}ïN›ø€“hLìßþ*ù~¸ Wä+­–ÛÏò5ùJšèòyEJ|×kÿ‰¨v#ñŠöG»ˆÀÛ#ݨችÌÏìÌZÄ\u4W£“õ3ý«òIÈçËUà ù³üÏDå‘smû¸>n(ÇÃíH¸X1ÂÈ­åËFëê§û×äË«‘’Ï+Uâ»æ üÏDwîc®(ÅÃc°à†FQ=ßµYW?Ó¿"_^‹¤|q©4ßQ‰ÿˆ6`oh“qƒ)#£³ø œUÖÏõÊ—W"#ŸW®Ä·øß‰àÅŠ.Ràþ3¥#_â9‡ßœS?×(_^‹´|²T‰oËø3Í4ÓL3Í4ÓL3Í4SŽ~½gix4ÿÑöùöô>¨´¦ÿ þ¿ô_Šÿ“þKñô_ŠßÒ‹GÛçÛSÂAÃÚÐtà𡚨¾S–áÃ+M3üÖЀID™9º|½›jÆj„¾_CQù:^_ÿý7ɧ/¥&ùGó¹ã1ɟбX´A"ÍÑåãè}€‘¹hÂGDçOøxý7ßðñûg†o>2xÌð'|,8‚¼Ó?¦Ÿ=ü 3@>„R9$“ƒ@29$“ƒ@29ÄFÀC+¹mA~ÍÓÏ}èÝ%„!B8QùB8Qùð¥í Bç *1 ¦˜…Ç]„ä½µ LÐiçèr+Âe"‚¨|AT¾ˆ *_D•GYB‰ ïB!é×_.¡¿a—‰s÷ÖNA ƒ.MSBÊ)AÃ>HÍ*æ]rÕ)ÆNB3@ΡÔ&JŽðâgdL$âE%f€ÔÓ£p6@hM¼HdK䤦ӂyŽ g¾[ôƒæÀæG2WIR‰o2ØL1ùí zÒD;WæoÕÉWeDÒ²ˆy‘¦3@êéÑSÈSL)‚,5F˜íX¦±í— xó~PFøÇò##C¤ûgÜ!¾-LÆdÄ ’6Œ 3݉=…Üj™;ÓHÁÙ)àcùFÆpú˜§‘$%°A\Ÿ>–ÿhû|{zôR3ÅÌô@J…o¦GómŸ™fši¦™fši¦™fšé¬+;C™Bæ 5YÙ£3*‡õS=J5à7’Zý´©*¤OW–õÛœ€¤„^¤l‚¤+o.äïã–ü ΡÛO”DH‹}Ä2Ñr5–„*kÕ%Z.’ó‘k¡UUÀF”"ñÛØÏÉÊA­ÞwÃ.J5˜@·nþHü¨¶©Ú-àq´FJþŒj¦@ۦ✂ n ûÈa£i8 KlÕ!T¹eõQ$ÛÐTñ±ù  ­tåHÝ|¡aŒD£¤ôEˆ­‚€ÕQ:DJþ'õ¡@ʼ¤ ăˆ‚(*gu÷5B÷„Öñ¨C$hDq°+x9ê?j  *‡²}[Hÿ·Fs6ðjÃAÖu±ü>Ú/UPÍ—ö?Ë·Øë*zãÚg¶Ôÿ@¥DuB ©o1‹GÖ±•kß0†…FŠ©!Y5l@ƒº÷ŽÈ|®Áò†Øb˜@Ú@Z?’`š;ö^ÿÛ® 2à¸6¾íbýküŸ7oh_ŒC¶€ÅÇ–‚ÿžPD±• "¡á`ã.´â!$ú±y}S¿Yc)†˜ä SÝØÊ $!Âú“q[„KAdüõv+s kiý-¡ÇÍAæò{jwrC€1Àœz攣ÖÿŒ_,µßwA Eqæ³öÁè¹·vQ¦ò™(iA„aDȶgÂÞøqúí1À‡x B4x8ùøXìc„´ÊŠòú»šªx0Kì-ФQ†íÖºh ž,Àd¾…… 3ç=¹.RmQ}‡§¢ëÝbxÒÿ¶IÓÉ;¤§€ž C;ût`#¢W†Í³0æ±,VÑ6Ø1±bý¦2"F4HD!bøÚø.&ÚÁÃÛGªHÓ³hž Ü…ú;’ Hÿ.l]Š˜\èÃskõoy|YÛ&' #¤¥ÆÀkKsÌV Pð¿0¯™%¶,ˆ°BBhCZÏÇÇ4C`3® Í8Æ:¾ © •V–ˆ˜æcììí!Äáca'(ì½\€ôæßì¥ü8øŒ¾\ÀpC|X!Bù¦±èúG£® —Ñß„Ñ6_[š™ñ¥Œ…4 ßj‡nŽbhÊÿ.€ßy%ÿèrÀضEMÉÀ­Ä‡)ˆÙÈÞš2$¬dS0øcðõ)ZkÚo2@Þb$B:/|f—®º3ít{.€B·ü;,±pÉ kÃÎÓß-å=cÃÛm8<¼«/;hí°Aó €L­Ov1r:„´r€¿tfë`2­wþw|k‡½Wbp¡Ÿ¶¨©ˆÃǰñ¦"d`²û¾C ’ýÈ[ƒ\ È‡‘Á°ùühñÁu7ˆöÝ HËYîàBˆÓÚbÿÚwàTËì]éhöàùu! Øv¾aó¶9,@¨ÏÅ@i¦_z³±Á-e(0 áèÐÀÎ<äãÝjŸþ-3˜À|>Àm? DDEᥫD¸Å„ '0´Ä1Ãó«hÀ!ĉ µ@|±zY}±Vc±· J3˜¥7д+nsÙ”YzÕØ„X½¢ÿ)ü€¶€)ÁaÜ!Ë´E鬇5°Ÿ­í»E‹à©œu [' .X‰î2ùM ܸíƒ(váÍ0„AÌ1E€¸Æ!@Ì1Âft¹"“? ²:`(²3È^p¡sÁ1¦ÛC¸˜xTÀªÕ}lxŠu~'ÿ/ †,@Ø>9ÿÓ¬#}š¦Ô§1.ÂB 3”c $ “SÓ˜B(>¼ebâÀùƒó.‰Kõ©ÿÖ‘µ^!]&ê @ ºþœyˆ!Æ+[BÀØÇ‡H'CœTb¿o%@ @lÝ*”tÜw{,¹5ààG_ð)dhvHlâ%¨ì~;Y›23«_•ÿûEÏ@vˆíĤ‚ìt[ f·ð¶kN™Ø*ÃD{!mÇr¦uƒÈ¨KµÜ$0iÓ|Ó¬U ´p@ÜÛÜ– (H–Ÿ‡G;|o/Ä6*§)‡•­·‹Êaûí·°‰f·X]3lŸÉ  BìѲ»Îû’ÿ›3 ýµ4BAÄýÞÎÂEˆ·‚ù”UÐ ½¸›ºÅé6ÈÂŒ"“«s÷!@ö”¿xq3ˆPo{@¶¢@k‡ xŸwSýe§f`Y”Y€`b¶ vQÉ&Ig±$"¦h^ý·Ô:KèôCKúWÄ›£mœF)Gb!œ#š´ ãGç’H­b7u+34Û|ÇFâ,/ˆ)`,%‚¦À‡z(ê_cࢃ0Ààà`Á¸@G9F°‹ÊsPÇ–‚Å#ºˆZh À¯ˆ‚n{-Üúaå\–fb4ìm¢Líwl»•¸%¼8€ì‘ÛDCdÃ:DˆË’üÃü´Çø"s°Rˆ-„è\ˆçaÒ{·UhKì;BÄ6ØE¥ oŽÀfïgœÿ$5ÅÕL‘µQ“´ÀVxÅ爘F˜,tòØ@ |›«à*†~áúçC €ïÔqÙÒB+Œ€­˜!k’ôb’—K¹:†ˆÎvl ìí/Ü*Æ–˜úç¡cæmgCÊP(Ë$ÉmE’óq™§D,“švr à ­ FíèDhïw@xð [œ£ZÜðû0<ÉtûhŽæ!²o½…¾3pi™ßbH-¯/3[ÊBq†Øì7+ ›Ü*fOÑÎhÔ?»Ì®X¦–ù%€ø“|¬¡±î¸níín¿Qqa'×½8’9D[¢ÃàEÄÀ|gô«pûï°âÀ‘ýb€¸ôP³QÈYf«n4µùªÁ+U€€ð>kO·4º„ ¾L.bw²y£ÎBHDȪ¾Z€,l5WÀÕsûÈ.ECÿã¾/¥X´£ÎÑ–Búa‘ãËÓH[DÌÃÌ_ ¶‰-…—É|œ98„`‹‚V(ˆ1ùBx§ê¨AXnˆ·ªi¦ou£ƒÎÛÚ­³Û²ùWd } ã õ·µïœø5Gÿ—«„Qu€ÄrI–œ«¡HÂhŸÃˆ+ÂÖqü½;„0ýó½¸è´°…©vêØÀ¸€0«Ú…qïÀ'I âaUþ°‹™|Xæ…€ú-H HØ#){˜éò/_} ˜Ÿx‰ltXj!$ñQsØXåÿ8µþq9þ@øw¤‘*’!=|ˆ1`ù6Ai¼äÄ#TpAw7x­ÃKë_D{Þw´h) ÅÄf?lí '>nÏwëÇå ¸7ìãƒÒ’È<<tqh/CpÒ´ ^ ¾­P<œ/]dñ&©ë Åëbê…n ;Ãj ñá„®U¹óz››[‰¬  ÄDøL„» ^ˆÆñ–êmñº‚”¾ö2’/HIDATta†øú…1EŠüK,“¼8dUÜ«& >ÔߺËt“*ç., ‰ O"³ãtÿ{%<>a&'Ã^!!>$BÐ:î:‰߯“wR…‚·"„óG8ßâH5¹ ä ¦ˆÏN¤ÚV|jAŽ ˜<éº !®üA€ØFãCTówC|ó…»©rŒþÎAåÌ•G*´_ÑÿA‰˜o,¬Æ@!ƒ‡ 8x<óð–‡w'U(ÈMw|SˆÕ †ˆ»Ç†³Rgvµ ¹Ë"Ru'}|©KX¿ôˤ. Ëñ! Él£HÇ`7uï,ÄúïŠü!ºø‚ðB¬»îÿÈ:a']§M“ž ÑD*ñ!˜Þ ÎçÊ­DOA×{·µ;¬âß­'À„.j2bñíZV¬€%· ø4xº‡ø` R”ˆ[°6ðvS=üþž!“¶ÅÝ·÷û.ú_/áwÒua „¤ôíÉš5°/bIA¿÷@½”„iai·ßk-$jñRW·/µÒ¿¬CÖ®n§¶@ë\Æç—ý—ØGøaDq’0@Ì Ìˆ /VÐõ«—Ò ô€Û$è £ÓZH=zh2Q;· 7_Ô!`Qèªá¥˜Ï©¯8®Æÿ­Èx+&§`B±Õ£J¸gíÔá%:·­k<£cY+þ»i¡M=¼lÝ^uN,¾j=,˜4ó’-tžs•£:³Âÿ]@ ©“¤ ™Ê]—±¢ó&Ç‹Hô’ñ^›ï¿ÍT®ê¼¤Bô ëWôÝœc¾¨ÀëËôÇ>$7ýðöÚ4ë^iŠ¥H«Òz§Ut¿ä^•Þûݺ¢ƒJRµ;©åûš¾×ýº¢\¦”ü}ß'Y)ê×» LvŒKýÿ6•0Üãq²ù‡ôš,–îx½ÓjDÒ)…Ì/©;îUëÝhVa&Õ÷Msš|Ÿs6EÖ ÚPy"}ß× ¿ßU›Ü˜°”ô¯ç뺖';ìþÓFZÙÿÓ/—d à›Þb™^ ´|ðw"̬±Œ¦èô[øýš:]«82†­Â òKÀÇD擞N Æ!kk (qJô¬ÁN#ÏÛó¾ÅwÒTkù4TRÀcz€¨q¦ìÿ·WBèàI$+º›Þ^&3â0TÄCÅÕ0ÃÆÓƒ é? b™¿µ*†‘^ ðq˜zZ­n$ÐÄzšô:衱i1”€HUˆ†°«²–>1?{±¦_êa¼–¨Ñí•\«•ÊùÀ!tdûH]݈3­L#Qˆ—kìJ:TUè=Ã4j ±ƒhšB OÀ-9®Ìy2Yö½m¬'Õ >&„Ó™ú\º" „L-À†© C‰wÐ"Þø}AIA{-°7ÛSÃo¢Èý†±]õAÎÿÈ7ÚÛi(p i×E+ŸÖA^”Yˆ‚Ú…{{ñ˜ÁÏJ¬ì}„m€ñþ“ñ·BÄIˆÕ7&´È‚šx®ë©L6„ôhg¥@ïr£µóù€u‘^üE„Îß51ÇÍ )€Èب.Rþï1¦ÓzZòLhŠÆŠn½½y™Fê²çÓl/ê®÷S¶’WÝߣÐ&:@*Žö][3Ÿ8:LÄ2ëF¢ñAyâ2¶÷q>2,@ŒÓ¼”gçÑ‚=h1#¿ïi”õýT€¸á[`äÔ÷'SGM˜4^5ß¿¼€€ØGÔ-P¾ÉøM#GCèxˆqºÛÁ þ„ €ÈnL@`_Bw°!ÏBfåa›²0Ù¾_²ëHLOÏ“ðì²áÉfíÂÌ òO,ñÞïýuG!SC¤¾È 4’bE<ÿ¯m6À1BÐR«©‡#A`Ïü“÷Y® #n­bu4A`cW^"ûö ( [ã[éÚ ÿ©wvxð,࣌qF¬êº1Þ'‚ ÖÕY.)¾“—nÖû“o %†ññþd»‡˜¡™8Q*¼ÏY.N7€4¶®Èä=Œ¸ÇCˆ5ÌyýÚ@ ! ÎÒÚòú–·yÿàÖà#½? ¡ÔTÄD™ ÅŸ‚ë7ô®Ï,úß„ÞÖ_¢b­P~ò.¸_Ɔ顜¦9¬ê»Y(6– yHÄ+€ÁÜÎ$^ºͱ cí ®ŒŸÊ{жþ÷•þ÷ŒÌ(Š'¡£´Âòb’°­À#G'À­õ–±­ëNñL3õ rÐSã î‚ÿÙG~Qb-'i‘ÇØõ$­}Ýy9m$ á&$€¸À– |ŽQuƒç>·†aÙv°ª9„!6#z15(‘FŒJx‰˜Ht/Y‹Ãc8‹ˆ&„¨€T…;´!àLÎްh]w  †pîZ.£³þÇÞTJÝ bÇÆÕ]ƒÛ‚< ™——WÈ›v} JS– §u -˜šáþVd>1ºãø0Øo ¹žœ§Dî%BÎ7Xt þ*¯YËÎÅRx í= 9;žÌú4¶€ËÑÿ‡£s?Ëg¥yYmBH¸D¥5ÚRx_ÊŸ÷¿޲—ƒšäÛ †Oá rœu³ôt;ÅÜ÷ª`Xä2©ív@£œ'ë~é$ÚkZ=\ Ç^‹\/tp\F ˜¦b|P2È›¤¥Of~ˆX.]h(>ÈAÄðxg™¦HìZá¤û{‘„æýß{ó‡,Àv-ðïJØôCÚϦÁ˜ÆBîO/´Up8âVAõ´\ÒôCD „Ýï·%÷cO!¶º˜¢ú]6‚x@àb u4K3ž@ËKNJ!Ã8:ÄB _ß̶ӓº(Éðžðî;OLBÿ÷´È±D÷;5G{Sžâ´à>Qè‰2Ì%nÖcx>’ÀÇijž ¢ Ä+ÓËýz%„8€hÄw§GÑÆ ÃÇQÈ¥ÎâaúÁe–N±¥‡;Bs=Åqa‚¶…÷lç° Ø/Ã~'™£åüÇbj3u†Yœ>Gõ–ë&ë3_ÓŽYÄ’ë}";›©×F‡"f7å g›„Š"Þ‘©7Áì9oíëÄž.­'ŠÔƒ ±!><#a.&H€òòúr´ âZ¦uìÍõq“=·(ú¿ß‰9JØÑ¦Ëº‘“X ¾f <ý/Õ?2+&}!×Kˆ`O %gçiyÿºÃeŠ+âr9€wŽo«Ã܉»J€„dOz#€`j·Ê|S–ðæHŽsÈÅ|û$MuÝ"0€ˆ !Ž/˜|¶áå Nþ“›`³þ÷2Œ °û×N‚£7‚¨‹#ž„úø†ô°Yûî—Þ>˜üûõÅÁ¨9\g­i•óB«5g,B>ú8M]öëwKwê zjDŽ¡Í0 =“ >¬›W·PñàaZ9é–JŒ (ðòæ"IÍ#ýZ‰&Fô!À—ZŽUð¿lÀ+À;MbŽòÛ·‡Öv—ÎSÉú<ÒýÀü˜Ä®ÃÑN4»Y!<„Ä!d½‹V:ËN$@z%õfÆ ªƒÜ¡©MDã9¶¥n!kF?ùN–[0žÍú…€µ$D¸?çYÀÏrx'ÒÌRÎ'–½v9 xuzÔ´&Ê[~§ˆCW7 r7 Øãô뀘Æn-È]k ·Êé#€œhê¥0ª…x±²zðCZ“þá.XdÆåò]Hè9pÜÇ!Î r @<„¤ýÐÂWÃY°Ï,Ž®sUocØD˜ÂXªÀÔžS„¡¬c‰ƒÀI°ÑToÓ =¼[‡»i^Š¢D Kˆ·Qæ„°_“³;áfè øözH„éc;ÉÈX}²»}z±ò«!¢±w2þ§T=W ¡u`€/3ø ‘†œÛÆÞuõwt{L/`ÊÀ9…I£ ‚!Ù»SÐ{»!FØ)~yEÞ4”ó‰ç»Qf*‡9ÉË_)@ø3¼½õAg%Ñ"™D½@äN\+žì±õ.’ßÖ–ëéaØéËþwË|þYT&^ A ·t€ë¬ù2—Z‚v¡ßÌE“]:…¹*üåe"¥Lשhú±w†HY 8„a›æ »Ðd€˜Ý±J¡½¬ CqGt:áMçM>/rzXˆÈÛ°'\HI)Yƺ_;ûY(œÃ–üh™ˆ¸I¦qŸðjL”øÖÑ×JuYæåÕŽT"(‰¼÷h†«ØT;ðáŒZ*àí¥B ÞÞü#Ù‘»ö¯†Ú<[gíßêB;å̦{1i 4î’¡‘£t‚±¶²’õ|a€ê%ÿÃJ¯_>…ÆKbOÉ#Á üîîëøƒÿt:•AÃF®wwytw É‹£½ DѵG:Ö9šÛ Ë×·àF[h{ÜFXc¢õòv!4¾óGkrÆG]œ>½½ZáØkyyv*ç€ý*¾t&æ:qÞ¾sç¥Ëh’$ ­ü90ÈŸC¼ƒ†0 D>V°#F› N°xìûµ_}úåÉ#wÒj#‘³"¸?àÈ{mzr[fѵXØNãl`š½Ü¥Z{"`Ah}€êæF–§žÏÙ--ù|- \,ž"ʼnM@kcù• ÷- NŠxÇŸî]ÑQ–ô!ÍGHè$?}a?ýÏ—s—aŠÒó#èc‰íÖ8ù®O\æ•aÎÄvC×Eu{B’|ô¢‡vNÆ–xÑÆ‘9“1´Ù~‹ïÝ‹,Å$(”Ár¿n33|S²+ÒðÞœWb €pËã/dÄ>ÞÜŸ}fLl=¶ìÍ•VOÂ~-VÛ ^p–tgíøgÁÿôćŸÃö;1OxáC}€‹€3ÖrÖð«Û»ƒÞ³:½ÄÜ´ŽB½¨ÏV@/x\7âTwé3x°ŽM£ü@¡ù×'ñRS¥×Wù€Tõ¸Oî=þÂ@¼{ AU3Ѭ¸¼ ñÑD€w´^ô©àÿFË#qÛN·Ïr]Þþuõù|¬ƒõÈ  ¡aÌosä?¯á—Ú¿¼Wª¾>j̲ üúæ[ ” 3@f€:wŠ)9 ÆAyº|ŠbgžŸ£Ëï&'×ÿ  3@\bÇÆ(ùZ’ç×Ïó5€„ýkS€«_꟧óäÏO1¡Õf€Ì™‚tîSâóS Ò-“̰NçÔ—ÐHµÿ§Í=3@f€Ý 5ËÐ{.£„—.s,ó2hÈ ,ée—O5[Ù9€\»•_ȼÕ~&͉åÓêÏ)hækü 3ÈgvÀgçÏ™ùß FÑÏû`ÒgçÏ™ù€¼æžÝþ ™éúoÏt åžÝ6ôhùfº3í¯¤GË?ÓiÈ'OïÏÏÓ~?dÈ@ Ï¿‡Ç>˜í Góó4ä“oDÝŸŸ'€ÔôÁÉñïᱦG;èÑü<Íy¸ƒÍÏÓ ‡;èÑü<Íy¸ƒÍÏ“NLg€|"Îy0i¼ç•Àò¥g¤ËÛ?¯~žf€ÌÉÒ q)Wš8v óSœÇ/µyÿî_uõó4dH–f€¨Î¤ä€åh(žBjdH{ýÃuÑ7ÙåŸ:ÿÖÞzÍÉÑ Æ?´Ò"ù_íõyš2$K3@ΞbjB|~ŠAºU’©%ÙÚëæ$õBš’£ 7HÍ2ôžËh÷Ó ›Ð ÍQ¶Úñ÷÷Ú O¤¶þ­_ÿ§ 3@²4äáÇíæçi¾0ôp=šŸ§ wУùyšòp=šŸ§ l~æ›îÍÏÓüàÔÃôh~žf€Ì”¥ÔôQK–¦;ÓwÈÿlÊaŒéìIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksBusy.png0000644000175000017500000000407013263214224022052 0ustar aeglosaeglos‰PNG  IHDRà€à÷xˆPLTE™DL"ùÌÿÿÿÝ™y;}RßÞIDAThíZAâ: 6™¡çmGô\zèý©Ë;#­ö^ÔíœVÃÿÿ ÏNÒ&v P ¬´z90|b;‰ãøs N:Å–Ÿ 0íÙ ÊÛºÞéc€›5Ã@â`bú¼ƒnÔ¨1ð®ÆÍšáŸmˆ÷hP€İ±Ê¿×Ôtq;FF¦0Ȉ!ÙX‡þ~LLa2`À|˜ß×ÿôÏÃdÀ€_¢0ÄØåZ Ñs1Nj-œâ¹˜Ü˜pèÖÏÅ ¿èÁgþ* GiªWaè·hÂg–¼ C¯òv§‹äUzØþþÌ yÆjs(ÂÔÇ31=ȶ¯U¸í>_ŸÓxá*\"|’¯á·fF·í1â…n|¿5 0.Lú j„ßšbÐ=}&ù^7Óøm {ú“/À(ðv¬òwû¼¸“À[1$߬€U;&÷b|Bàu¼n8~›ïR(ñÃJ‹*ç>º¸Œ×ÍôÿßšiÜî§A·5-Ÿ…ÛG˜ÓàÆãÙd1öx “FŽYz9]ûüpö.ˆ¥³°ÊÑŸV ¯=^kCLü ¸ ùœ!6yl òØ ñ•Xñ7ÂD l °1ÈãÆ0â  V(ùœ4àŠA€‘KÜÅ÷8¥®¥F,¦ÈðP~È‹ µ(*Xü>(Ê,5+³¼‚¢ÿóÿ>•žã‡¯Vøê!]È÷îᇋøÞ=üð¡üï~8‹ß-ųùÝR<—ß݃Yª¿”ï&ؤúŒ=]c?\@„™@Ä]]w^ÓnÑL*œ'H`€;Ú»oìísšë „À5 h.âë5o+P¶.ckñe<ýš÷™Ã®§â¿Žb++ÿ^ÀA¥y¨ñÙ|LЩ×ÿhþñA€í*¯ñžZÛŒ&èbÉ8¬(}Má¡ÏJ;/P˜™>'Z×ër…IfÿnK«?·„Ѫ¿­ö6Ø]hg‚¦½"<ïè³›S{›Äp´ºÕà5Èß0†|Ž 1}¸;Ží9„ï:ñ·]ËùÝT°¹©`*"L;0¬ze¦UŸF">·k9nÖc‡o?XI Ó·ÕÞnàw]Çq³æ¦ŽŽ*Zù´ðÇæ“yø%ËƘ¶-tZý ‹é˜<ü¶b¸Ì ¥ýN€>“nGü»`Hçà¤<¥-PŒ/<ž†NWÒ®>”–Mó¿v—\,“T¨¯>dàwàø¿)lªø AJw6IìG…gø 1 1¥ú!&f¥¯ÊÜ÷ÙåÞg(?ÙÁ††”™{¼¦;TÍeÌîX È'n¸.¡‹‹Ôÿ]¤ú¿Dj/qx‡JY…õa¤&at ± +V '+3îL©Ê&úõÁûLò­å%–lèÃâÛ®$•Ú²µPáµ’ó,®R£q$k7(\ˆÆ]ZŒ Ÿ~Jé´;yøóù j 2ýçóAztê=x]C%ˆ¦äƒ9­ˆž ΀¾ÕG?º`Cü8þ-Â3Cl˜F$g{^a48 ÝŒœDÞ_µV¤©4³â<Ù?—îƒrÈû©î0S6 G^š`_=‰É L=ì¢\è2ÖÚ‡H"·L>Žq•S(ûc"K , eÑuOcd¿÷©¿íGVÈ>Û¶Ýt9›FZçÿޝÆÁúœÂdKu€ ‹˜øô†~é›2ò§ &tî2÷[ÚŽ¾ …²Ö†íhÒw±:BJ)iÑ 2¾až’¶?pûöóhÙ.2šxÃkm˜1Úຨ°Š*¸#ž(ã3s¹Í ÿQtå8ÇŽƒý¦CÙ˜²Ä)E[1³ í¤•$k‹“JTY·.y°ÝÏ­å–¶þm:”igµ±â}ÒÝ/Ŕحqš¸ÊL-îä`Ö¦ÑhÁûžoÛa‚ªcI>Û:…ƒ‚8-ŒÎcPIEEsVªÔÚ3>šY°rS†« —w^ª*µ”ï¢L|%ÿ¤œß)̡қîf¶\†^óaìÿ̰ƒ`¨°Üæ¥Æõá&(ƒ±‹Qj/ùæ±,K+u„9a7ĹUo×Ðnˆ´+e}üQüTèNnÊ4 q"ò"ÈME{Ç]6HP†Í“»N™·“Ì-ÚûñÊ-*g„Ò_t¨ýIRì FôŒÓ7ñçå£@§°Ú‘A{°n°UÀ hÏÔ9drHq´j3ävJûqJövJÌ ŠÍ)¸[§ã¤ §° Éi\§z·NÎélÑš%‹¬È€nýƒ¹µp{ç… {+¹l†Y…ve™„•QpáÖlኅ×ãÂw†Àà{ć-‘C!ˆŠôïš…&ã†>tE¡m }à«„<4š.í!¨òõá?ŸÁ—1ÎQð†!¸CP°äÁŸŠyVaá~ï‡#Ú^€ÜÐo?ñön_î-¾½ñr¥¬ó Tn°ñl5´“± ;( ²Q œ§q q¶‰„úâ÷oeº’s|'Š'AQ’tA#K²H¨ÏP¬ê¡¨—¤yš§çK#yšIëÞœ© 2u“>‘(óDšŒÄ5p‘ª_ŸÀAlðS~ôÕÀ¹™G±™ ~¸~¡[³ÓÎŽï]ûŷމ*’N¸IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksFontBig.png0000644000175000017500000006275713263214224022500 0ustar aeglosaeglos‰PNG  IHDR€Ý06PLTE»f"Ì™Dÿî̪™wÌÿfffÝ™ÿÿÿÿÿDDDªÿK­&Q IDATxœí]ÛbÛºŽõxâ[ÆÍqþÿg'‘—€¤”îîSá¡5%Þ©œNݾ蟶á ŽnÇã@ÀŸK·Bˆõ9/Ee—üxÿõ°Z¾žÆ Ï2•ÉJ‚†Œpþ•4Q‘#Ã{þ1¢… €wþ~¿×‘÷ì­¶2Z*ôóÈî 8Øf1n{ya?ð_ùî›{ô®-oe~íÂøïß…Ëx{ÆÈ ¥,¸t9Á­å…ù³ñ?-«7à @S]š|‘¶yÕKâ_ۀǭÎé‡Mœ€YÊ’Yl†Ñnt[ynýtü— ùÒŠ,&,;z­í7¡jŽYr Q›¸Ú•Àæ± ´ªŸÎ`—ë6–?…þë&°Èߥš–Øßi¡¥8Q/'F½Ü÷¿-l* CFn€iþjÁé!˜ËRóu[ˇþ‘âN’ºÕÀs¼‹õ6ø¹Œì§þñt:‰6`ÌÊ-8éæÙô?Ü®h=Ò#¶K5_~süWŒ–áX×Ú)AÍX ·„@SåoC°þQdµ³E']+Âà 2ýW›êð·L†Ç¬£w¯Òhüÿý8ÕÁÙ;[à=öƒÛÚe¿ÜÚª F­ì—f( PÙjúíøgãÏ_œ¶ÀGj„¿JòI¶C‹Ð­Eµ’v£Âz ”fh(éÑcj½bÿ Ñ-;S‡ ñ€7$SÌqJ¦ÖÓÒèQL¿š%7F_PºÍ!@ š…:Xl^1è”KÄ`Ê¿Yyè¿iùS2êÀ$N­`A,c@<ˆøSJ”]g3 ™Ê·r0‚ˆãOø)»N P°lXoŒ.ü7+?;š=üVq#œDy Z`mpv‰ÊˆSI3–úA¾¹œ½(<³Ø+ÂY‚úýË?SôÓ.þ³é–Lþú›ã Ï,tÐAý™Å4ÑyÏ{ËCöM—ÏÒtéßÂß•fEG—¢&Üײ¤U-¯åô¦™Åd‡ß­–¿+­;#å|“òú=ì¡æÅƒíÔè+oH9µ|–f%ùœ,á÷ëŸäïJeo|üØ 2µ?½Ÿÿë]:МɋË×et&U>K¯…8õðûõ;ÊøÂñ4.]G¡½ñ‰sWí`œÇòê×öã•›ŠÅF~{®m¶òkØêžÌ Ëgi½ið>ÀgäêwêŸð…«ÉnOÌ/­­È°«‘V¦Ÿ›iAåí쀲Èî€ö^´•ßÖ÷ªþ,ý.h€/žúúaý>o¼›ñO‘èøfoæ-pÐÀ"&ãó¨Ê%ðå2-=Tñ­;~êÍÔò»Ótµ¨‘¶òµþú6Xù°þ©š'’]—ŒoBÓ8éÍ Ÿ£[™óaœ/44ÂÀ±z=løo|Ë#`(¼)¿[¿SÿÜ?½NøB´b¥7ƒSiUþÑög0*@ÅÙ?qºº!Ñ×kOn$“}T¿¯/ÛÎË>QâF·çfgc¨úª€åŒÍ_8²ÐÛØšw8>NÙçÞ›"¼š©zx3èÆóˆÂ:HI’b]U°ÓÑ5þïNñHŸþ_”|ÈVÐÚ…ùØK¨þï[°a(übÙ|”í5#·¢0ëËhö¡UÁ‡ýä¡i6NÉac’µšìkmB(ûŒ,1 âC¡1„€¶O òÃ0ñ¡:î8%e ò`˜FÿÓœØÛ ¦} –êÅ´ƒK»¶ÄA€FÎ8ÈxA™ê‡~X¿_ .¦p€"þ.Ćù„òÊc-•@©màºíÁ¹[YƒxP¿V¯=õA€‡ø€È‰Ÿ~“jÄ"àïA Þ›d•?NmIª^^âÏAÅu`í$,'¶œZ©yðIÊ»Á© íÕËUº¢Š¥,Ê3¬} b ä 6ÿ°P?À‘Ù8ü§ºü¾„z„1cG½¿ù޾N£öÕ:ì €$r;IÍ?+5€ý5σ{WÊ‘oÒsÓ…„ö¾Çö—m½@‘—WMÀËßDâ Š3¬4#„b‹5¿è´P¶0Ã^ñfüÇäÀøW¾¬2€¶`b¼Ë «þ ÎÁlèžUN‚gÇÐÃ"N\®Ô2 ma"DöÔRÖs5ß8Bûkˆ_õhäÈ£€•%,¿kÕv¬#ù9})_}? ³7³?{>€t70¼üÙ⇕íÌÇ_T¨üÔ¬‚E>©Ù´Qî2•ïÚ³¦UíUùû¡Üþú«z¹ö§»}ñ^A“ •íÔq? ¿ @:k‚oúy)ÂÊË/s¾ñŸ–ØSŒ–ÛŒª|j¿#w´þ¹ýP=©¦)§SÇ^@[>@áAåê,hýÁTÜøsq¼F;P“(O¤äGö”ò­â |f¿'w¸þ©ýi€þ‰¶˜:ʼnã» ²÷®ÈOÔüz7õg  •×ò‘AùÌ~OîlýûãA`ÇåO_´ÒnŽý CH”Çæ}x Øùüľ”ïÉÝX×~nÙ,q5†yv€Ü¡^Þ°…j¹$CÂG 8/îÚÓi_Ê÷än­älDKg–ešM ý³²“ê¥õOøÐ…™¥ö¥|On_yŒ€ÈþM4+º£\¶RyÐAtÐAýÔVδ;¿CÿÈzôi(>¹ãÊG q©¼žô ‹³â<Ïðsýj¯j˜ßû}¯¸;êÎä×Ýå¹ñ#ß7Ùh§Wà§ø~1›àcý8Mâ'^¡¼ö@ÛçªòëG~¦ß©?“è`ãýùi>Ôoçâcü@?N×½^2Z H¿wp«§!ß•wsäuóqýkŽR)ãŸáûóu[Óáßúø7O?ÑÈ÷zôGié.ßÄ+•G[wÚ>ï|D;AÑr¾Ÿp‹õãøÖ5brG1Q@œãczh¾Èð°|Q>ãóOÔT¾³×ÐÍõ»éwY1.,’W4ß8ä WÞmý£(¿Z<?Ôâ·æXL ãóº´üGÂÏÊßx­_oÊòcýNº­=(^¾<áã彄ù]y­Üƒç—ÜX?ª?aR è™ - $Ûðo|Öd²:¼cüP¿Ú*Ðz`øpýúog÷Àt±‚BýZ€*<Ö±o\!'­ÏÍ…TÈ—9¨—ê÷åezrˆ&RýѼû5aøq[¸[i¾µ{:õ¿!:M ³P!û£1ŠïW0ý>@ç÷(Ñ pWŽC®¼ï'í ¨m¡ö€Q‘Öoù½nÀÒ#  Œ•Ë$Ô ð©uªÐ~Åí_ €˜Ÿë×ÿï 6^7Cîà>ü&‰«@õZ¾/ï¥ëبþ ÅÛ å_T<¬ºä7&@ÄïÑ¿üïÜþEr¢€ûo¢yî–Ë ë‘ëºâÇÐT>ËA)Yà<ôx ßhþµ$Õ² vL¼¿ýüý«˜Ÿ@ãõËmüõZüFxxXþWo7ðÁP:­OÉO¼Ôt¡ü™œ¬>‚ärÿªe–ïò~<·wQªྠæûiqlW¸ƒ¿Ž1ÚK¤ø ¼È^ž/ˆ¿g¿¤ ¿/O¬GÆò»ü™àÝýg¤&šû@¯òñ¿Ÿ‰Q² ¬xÃ|$g/û4€%*‘|9DÀm½zÒâoðX»x‡l¬ƒUP2¼#€Ù~€¿À%»oXO ¢€Þ0Í ’/°9Ô͆o¼ ØH4üÔ²ôâ×ÒH>ˆïÿDŸÉ»é>ñACS¿ÝméËÏôsvVWH€e=\…4Ü@ƒúèÛçÉ«¥´ l 9ÈðòO`}Pƒ4jj¿©^3áxe2ƒ|ÄÑÃrù;@5‰[Ðóý‚ÖÈì €öÚŽàQ@h 5`H›,8]Dk­ÿ!øÆiܾÔ 9•©F?¥ïƒõS£õ ÓY|,nìêÔƒà¡FéåWrÿFïä×›¸Õ>ÎWÛyÐ>M#öAy¤Îù>‚êÚù+L–\äfàßžúÅiB@|˜‰Íg,þæ^}”®¡‹ø_ÿàåÕPOÛÐiJ7À U ÆZx$¿xüÄ>ÖG­_’&IÝñ9±q1õvâì±&0H3Êøˆÿîè‡Rö ؇ҬUò`MòHàIEh¦~yZ ©AŸ•¾JpEDpÚ å»åÙJÎã”/v"{,úìsÒ|Ì"Iƒ$8\ÿš®uœªŸŸ¦üïCñ©yK;PDÄIkšæ“%J?’íèÑï¥éýÉô§õãˆî(ïÖ/KŸã£ab_%˜Ö´‰ô{y@h¦ßI£7êŒÖÏKë½õ7ùð'$²t$~˜ï™æäAÕÕ¤SÿÊïRÐoß©'dßAtÐAô—Ò Ðoä#vxþOLGõ7¹ Çæî.<((– «ðÃ|m2hyZÚ«¿Í%Çà(·¦HrËô ³ýC¤w3š™¿…+ ©A†ÂÕòöNßÓõ7¹Ô,Œ8iŒØqœIîKwÓ?vÿ¿Æ×Ü¿'GÉòZÞO§³ûöõ×¹ô4¼r²5AÜê¾t (,GK^2ÓüÇ_  äÃ÷çÝ´Ñ·5Ü··õSñW¯9÷[mgœ HÒGhçÆÚ˜Q´ûœïüE¬œã?øïœCkÒ¶|˜vîÛϧ+ ÿaê—€y¯¶k}„¤î1T‹Ex[€Øƒàg÷ï]y&=÷·…EÊ‘_žg$W[Ùó÷‡ÇJP}ô°ÐÊç ë¸'Ÿ¹AÆÿÆÃÿó¢p›Û¯¶›{ƒä@ÅßB‡Iô:ÀV{gô'6nV-¿õ®³ã¹ß aã\xjœÍxÖ°nô"åH(YAžØM¨JÛ6¼ÖO:0©^¿þÙ?ÿÎÝfl•¨¯ ÜÞ§1áÍ}I½Ú9J"å ç–v#`«ts‘²Œ|æ¢x'<& /W¹Vð¥1ŒœêuÏ*舔ׇðT7z8˜®_±þ[æÙáu‘™þ.û¤G¸ò¡‹×’ºùZeÝøT¯³v$@û'Š”D²±!'¸Gä<±4 `Çæ‡P~hŒsª·+儤Òcì»éJ>xã¢{kGÔƒG†ü‹qµCÒc,—X½–’ìØø Þt²¿øúÏ«£ç¢^ý €/ÓÐ@¬}zÍ~ü[–îÚUê@–¡ÿbuHþ)Y,vYh¸Ýø#Ù¤wßß§u3¹_f&K®™þ[A½††_|b¾o dú1dZ&âo¬¶$ 0–q{ÔK$H OI€ð3:Ò‹êðÐæNõà&[ €wzU´žZúÁñNÐúFÈvâߘǑQëÖ••TG‘+–šn},ºÔú˜øÖ±€€Yèö[µˆ,ºj!šà»e „·Ïý‚Iñﯧ Ž z_ùt¸Û#¿Û­]Zh}J”fïùB±•» VO[žé7=@€ŽÕs+{mk­½@yö)Ø<#ª$æ¿As4+œV0Bü[é)ï8 ÌÇMÁ£íwûuôª—áZ—Ø€÷÷A8 ¡Ü k½L_i.(D€/Ãfî¿ ° ÿÉ»]êÀ @Sh>Ží=ï€åòö]帵~Z°èé#÷3`Ìy¤´# ¼Á2F)KC¦ÚÄ¿ËA¦*/qË#µj·¯P~ê|Qüyù[ë¢tRºÍ»ËÙ €‡>"Ï ÀZ¸Ñhâ¡Ð ´{ˆHe€2¤jc¼ŠTžc¸¨W=ÿ¯:[”ý–c‡Ó‰|AüÑŸ·.l‚4õƒ­‚™Ÿ àlâÕ" …¯v¤üoÀßp×$>Ç«XÀå©$0·0ìX}ž¸RùDãþ°¬6¯}ðJH>_H±Ãh׾ܴ֬A-Üxq7µ ÿ À=±v«Ã2þ`‹¢«¥º<t±]Ž-jxvàHçãxËö±4â¸öIøö=ºrZÃ9€wõΤšÈñY¢-ßr•>ÀFÎS=;˜¼ <ç°ÏØÛÒp!%´ÔïZQÚ¯x$hôÓD{.$¯hFT©y³$ëç”g ‘i·‰íè,_m é5l/O{±ÏÂÐåi²ú©ùÀž E¿8ŠMÌê ÒûêèAú²çË»<û÷µ/¶ååOn¥µ0ú06zfèòÚÊžðEvìP>|€ìßß¾‘š,·ÂÖ=à3tÐAˆþ÷‹~2}ПMÿû5x¸ýïÏ¥·R°ÊqP?¹®ûßuðø¿Ä¦ô(ßKkäS>‹-éš]Ù}@`žß}Åë×2køßß’åã4YðG N'±ù(é…ñX·›ô^£áñò_Káëó¿·².QLéQ>Nä_.­ô¨O×Уl-/Ùºà€)Âïqÿ÷¡üPíæã4Ù þri#ÿzºtÂì6s袺ú®¨÷§¾Ñß‘]ûúšå£tѲlóÿۥœjÞàõ:iyùØ “@ ,íf·ô(¥™ÎõgêÞ_4D‡j´øóÁ|Y½\Øßïìcù§8~M?êŠ>¾“&#ä!Bea{´6ÿí“6Sq¥…KܾnÚ{WÒ- }|'ÝŒ¨¿uä,ö£ÅWz.Àý¹wºQ§xÈÿl¡âI> ”³Í?ð9<Ø)ïr¬þ`-®£ðå0×oÀ£! jæ&NÀˆ9 `9ötªG†´?÷N¥Õ€ò—K9=Å0úÿÀVj 'ëŠ<Õ[~ìõ—K¥‰vÄ–~Óÿö½?ñ_K A,ÿ«ûõ{ &7'qèwùÿÀVêÀ£Î½Þáõëé4Søx zö`„Éà¶þÑw €wÙì €±Ã©Âü[hñ–…#¼Óõ¬ŸÀ¼ù6…×®˜ÇŸß^wë6¤÷0ÿÀºq,ž{§?CÝø¥sæîý³°›‚ÿ~*£ð6ñâþDþ=ðo§GE@…³ÉØH@ËÏ!þF:°™Ê{ÍGá|6®ïÅGéå—º¿ßs¿ØNÔ²SZ®Æ˜ûÿAº´!b>ßu¿»ñ&þºé¡ÎT=Ômé:2xdiFÝü­Æ£Øï©ào ºÌ_Ü÷þΗcµ;½4ðû«í2î»#ì¯ å8黯G˜ÖÔÍßÑöŸ@Ø_B,ö&6äÔ,­©—¿Ùr„¯ýö×Pý¥£ðþ\øá;«8èϦ#üô_A×/ú§m8蟣ëù|>ðçÒµb}EÎKQY'Á%Ÿ?­–¯çF§±Â³Le²’ !#œ%MTäÊÈðÎgs™j…aBH>~ž–ë"Ïè"–t WÑfº^ûTü;h¦©eøú©åýúüJÕµ”H(ÉLe¹^­¸/ gŠ’NÂ$Iv3B#àze*þõ0þ)„pþzs¿<{F©Rø“€'´dNgÊ®ÄÕ–¢ðÙ€U’“¥¢ïŒÀ§@É¿€¬ÿF ¡&2ÀµÄülF2ÿšÅˆc =Y[´,8 ‡ßáÿ´8ÛÎIæ Çx¬ÿúJñ`ç+@K(ÉëËwZtØ8Fø£oÍq¥Î*—\¶m“ÈP{Õ ý#f9À£Å dŒì‹&ªD¹ß®×Zd“Œì/©s €Þà´^5è_§ºÞ½i2þ¢ÜY¿ 9”Z'…% Cç³–|æYZø¬RÄAZ—Ä€ j¹```2´^5è_gºÞ½ ûo¬¤‰< \»|€³|>u?Øwϵ¬žZÁNü5PÓ±#`ý.š €h!¨à“¿ßŸu¤Å={-OÐH<²¿JN«UÏ_)ˆ  PÍœã÷¤ ñç«uÑZ (WuŸ¬‰Ç »œ÷0°Ÿº6.œªÝ,T-ö¼÷7h›„¹Q4ä|¶1j£Ê¥Ý°fÁ*¿±­Œ– ý<²{¶FŒÛ^^Øü×_þŒûæ½k À›d™_»0þ„€óçwá2Þž1rh) .]ÎFpkyaþlüOËêÍpÐT—&_$€m^õ’ø×6à|­súa§`–²d›a´ÝVž[?ÿeB¾´âËÉËN€^k»ÆM¨„c–œCBÅ&®ve°yl­ê§3Ø¥ÆÄºåO¡ÿº ,òw©¦%öOZh)NÔˉQ/wöío ›J‘[`šÿ³Zp: æ²Ô'Køýú'ù»RÙ?vãƒLíOïçÿú”4gòâòuÝ„I•ÏÒk!N=ü~ýŽƒ2¾pE¬êŸæ‰d×%ã›Ð4Nz3ÈçèÃVæ|ç ̓0p¬^gþ+ßòÅ oÊïÖïÔ?÷Oo€¾­XéÍ ÁTZ•´ýYŒ PqvÄOœ®ƒnHôõÚ“ÛÉdÕïë˶ó²O”¸Ñí¹ÄÙª¾*`y#GóŽ,ô6¶æŽSFvŹ÷À¦A ¯fªžÞ ºò<¢ð™ŽR’¤X—Dìttÿ§S<Ò§ÿ%ϲ´va>öªÿçVl˜ ¿X6e{͈ð­(ÌúÄó2š€}èYUðì@?yhÚ€Srؘd­&ûZ›Ê>#ËC̈øÐGh ¡ íÓˆü0L|¨Ž;NIÙ‚<¦Ñÿ4'6Å6€i_G„‚¥z1íàÒ®-qP Q…3r^P¦ú¬Ö廓) ˆ¿ ±aþ¡¼òXK%Pj¸n{pîZVã ÎÔ¯ÕãëFO}à,¾A„ râ§ß¤Z ±Èø{ƒ÷&™AåO§S[E…ªW —øsPqX;Iˉíç™VjÎ|’òipªh{õr•®è™b)$‹òÅ k_#ÃßXùƒ¨Í?,Ôpd6ÿ©®ÆÁŸ…ïÏ¡!À@@ÌØQïo~¢¯“ðã¨}µ» ‰ÜNR@óÏJÍ ÅGÍsæÞ•rä†ô\õG!¡½Ÿ±ýe›E/PäåUpÆò7‘xƒâ +Í¡ÀbÍ/:­Ä#”-̰W¼ÿ190þ•/«Œ íGX‡Ÿ²調¨sE0›ºg•“àÙ1ô°ˆÅ—ëÀµ C[˜‘=µƒ”õ@Í7€Ð>ÆZâW=9òè`å_ ËãïZµëH~N_ÊWßÈìÍìÏžÏ Ý /¶ø!de{óñ*?u«`‘Oj6m”» då»ö¬iU{U¾Ã~(·¿þª^®ýén_¼WÐähe{5GÜÃï(P‡Îšà«~^аòòKÀœoü§åö£å6£*ŸÚïÈ­nÿFTOªiÊéÔ±ÐV'‚P`xP¹: Z°Wþ\¯ÑÔ$Ê)ù‘=¥|«8(ŸÙïÉ®jà„¢…0€-æ$¤NqâøÃ.¨¬Ä}ªò5¿>Mý¨E@åµ|ä…³@P>³ß“;[ÿÀþxØqùÓ­´›c?çÚ?ûÒ½ï;Rî–ó*ÏÔ±lŸgU^9Ñ9“§äc/0>ˆ¾(ŸØïÊ«h8 ì¹üIŽ^a¨­X*àЙÏÂPå±yÈvž?±/å{r7Öߵߣk6K\až wh€×7l¡Z.ÉðQ΋»ötÚ—ò=¹[ë9ÑÒ™e™æDÓBÿ¬ì¤ziý>tafé€})ß“ÛW# ²ÍŠî(—­TtÐAtÐA#µÕÆ€…3íÎïÐ?ò‚ýAŠOîø…ò‘‚@\*¯'=èâ¬8Ïó#ü\¿Ú«æ÷~ŸÀ+3ùuwÅãcyîGüÈ÷ B6Úéãø)~ _LÅ&øX?N“8¤Á‰W(¯=Ðö9€ªüúÀ‘ŸéwêÏ$:Øx~šõÛ¹ø?ÐÓu/€—ŒÖÒï\ëéDÈwå]yÝ|\ÿš£TÊøgøþ|ÝÖtø×>þÕÓO4ò}€ýQZz†Ë7ñJåÑÖ¶Ï;ÑÎCP´œï'\cý8~§u˜ÜQL”çø‚Κ/2œ-_”Ïøü5•ïì5tócýnúSVŒË‹äÍWyÀ•w]ÿ(ʯOÀõ£ø­9–ÓÂø¼€n-ÿœð³òWžAë×›r£üX¿“n+ÁFŠ—/Oøxy/a~W^+wæù%7ÖêO˜z¦HK€É6üëŸ5™¬„ï?Ô ´þ\¿þÛÙ½0]¬ P¿Ä ‡ çuìWÈIësóF!Õò¥…Cêå‡ú}y™ž¢‰T4¯Ã~M>@ÜîZ€¯@ížNýoˆNèìTÈþhŒâûL¿ÐùýJtÜ•ã+ïûI»j[¨}`T¤õ[~¯+°ôƒ(cå2 u|j*t€_Aqû æçúõÿ;€×Í»¸¿Jâ*ÆP½V€ïË{é:6ªBñzBùgë€.ù ñ{ô/ÿ;·‘œ(`Æþ«hž»åòÂz$‚Àz€®ø14•çórPJø$ÏHàwš-Iõ‡¬‚Ýïo?¿Gÿ*æçÐxýr=‡Ö#¿ÇŸÎ–ÿÕ <3”Î@ëSò“o5](&'« ¹Ü¿j™åÀ§¼Ïíã]”ª¸ï‚ù~ZÛÕîà¯cŒö)>/²—ç âïÙ/)ÈïË둱ü.føt@ÿÙ©‰æþЫ|cüïgb”¬+Þ0ÉÙ˾Í`‰J$_Gp]¯ž´ø[œ×.ÞEàù,ë`” Ÿ`¶…à¯pFÉîÖ¨( WLsˆä‹lu³áŸ¶’ €?µ,} øµ4’â;Ä?Ñgò®ºO<ÓÂÔ/”Œ(ö)i /?ö7—Ow[úò3}ņՕ`™AgW! ·†Ðã >úöyòj)­‡›@2¼ü“XÔ €š€Úï@ª×Lx^™Ì qôÅ0€\þNPMâô|¿ ÆŸ52û ½¶£8WH ÀÒ& NÑZkÀ?G¾rš·o5€BNeªÑO©†ÀçùÄ @ýÔhýÂtE@ €+»:uæ8+…Qzù•Ü߿һùõ&nµóÕv´OÓˆ}P©s¾ ºvGþ “å¹ø·§~qšÐfbó‹¿¹W¥kè">@ã×ÿxy5ÔÓö@tÚ‡Ò °Â@Õ‚±É/?±õ‘‡Gë—¤IRw|Nl`\L½ž8»D¬ ÒŒ2þ9â:ú¡ƒ”=ö¡4k•|XÓ„<xRš©_žVHê_À'G¥¯\œö#hùny¶’s>å‹È‹€>ûœ4³HGÒ É׿¦k§êç§)ÿçP|jÆÒqÒš¦ùd‰Ò$@{zô{iz2ýiý8¢;Ê»õËÒ§Áøh˜ØW D¦5mâý^PÚŸéwÒè ‡ú{åë£õóÒúAoýM>ü ‰,‰æ{¦9yPuFõéÔ£ò»ôÛwêÉÙwÐAtÐAý¥tôùˆÞŸÿÓQýM.ñ¹»  ŠeÃ*ü0ßc› ZÞŸ–öêosÉ18Ê­)’Ü2élÿéÝŒfæoá_ËBj¡pµ¼½Ó×ÁtgýM.5 #N#vg’ûÒÝôÝÿ¯ñ5÷ïÉQ²¼–÷Óéì¾}gýu.= ¯œ,FÍG׺/ ËÑ’— À4ÿ<Â(ùðýy7mômM'÷ímýTüÕkνÀVÛ'’ôZƹ²6fí>ç'kçøçþ'çК´-¦ûöóé È?›ú%`^à«íZŸá#©{ ÕbÞ öàøÙý{WžIÏýí_a‘rdÀ—çÉÕVöüóì±T-´ò9Ⱥ€îÉgnñ¿òðÿ<„(Âæö«íæ^!¹Pñ·Ãa=€°ÕÞý ‡M§›UËo½ëìxîw@CØ8žçC3ž5¬…½H9J–@'vcªÒ¶ ¯õ“Lª×¯öÏ¿s·[eê+(·÷iLxu_R¯vއ’Hy¹¥ÝØê@'Ý\¤,#Ÿ¹(Þ ç ÈËU®ƒ|i #§zÁ³ :"åõ!| Õ€^¦ëB¬ÿV§yvx]d¦¿ËþóéÑ®|èⵤn¾VYW>Õë¬ Ðþ‰"¥‘llÈÆ î9O,Mرùa”ÚãÜêí €s9!©ôû®:„’ƒÏ^¹èÞÚõ À‘!ÿb\íôË%V¯¥$;6>€Ï3ì/¾€þóê蹨W¿ÀàË4ôkŸF3†ÿ–¥»v•:€eè¿G’J‹]®W~ÅH6éÝ÷÷iÝLɒk@¦ÿZ@¯¡áŸ˜ï™~ ™–‰ø«-‰(Ìe\ÏõÆ ÇÂSÒ üÌ€Žô¢:œõ„¹ÓEý¸ÊÈà“^­§–>³A¼Ó´¾²øw@ æqdÔº5Ae%ÕQ䊥¦[‹îµ>&¾uì `ºýV-"‹®Zˆæøn!Äís¿`RüûkÇ)C€#ƒÞWþîöˆÇïzm—$ZŸ¥Ù;d>Pl宂ÕÓ–gú dРã_õ\Ë^ÛZk/Pž}Ê6ψj‰¹ÇïFÐÍJ§ŒÿZzÊó'óqSpnûÝ~½ê¥€C¸Ö%vàóóLŽC(7ÈZ/ÓWš à˰™»Ã¯lÂòn—º0Pçšã@{Ï{`¹¼}W9®­ß£ì zúÈý X's^ )íˆop§ŒQÊÄÒ©6ñŸr©ÊKgœÄòH­ÚÙíëc”Ÿ:_^þÚº(Ý…”nóÄîrö଄Èó°n4šx(4í"R™  ©Ú¯¢•ç.êUÏÿ«Îe¿åØá´@"_ôçíE„ › Mý`«`æ§³8…xµˆÇh!Ç«])ÿð7Ü5‰Ïñ*pyêÉÌ- ;VŸgnT>ѸŸ-«Íkϼ’ÏRì0Úµ¯5+WmEP 7^ÜM-ˆÂCpO¬]ë°Œ¿Ø¢èj©.Ï]l—cK§ž¸ÒùøÞr€},ø®}¾}ç.À…œÖpNàÓ@}…3©&r|–hË·\¥°Ñ‡óTÏ&/(Ïy€ì3ö¶4\H íõû„V”ö+ ý4QÁž ÉëšUjÞ,Éú9åHdÚmDb;:ËWÛCz ÛËÓ@Gì³0tyš¬~j>°çBBÑ/Žb³…zÄ…‚ô¾:zE¾ìùÆòîÏþ}í‹mGyù“ë@i-Ì„¾ŒÍEF„^º¼¶²'|‘;” û÷·o$‚&Ëu p‡uç3ø ÄAt¢ÿ|ÑO¦ú³é?_ƒ‡ë~.½•‚UŽƒúÉuÝÖÁãˆMéQ¾—Öȧ|[Ò5»²û€À<¾ûŠ×¯eÖðŸß’åã4YpG N'±y.é…q^·›ô^£áñò_KáëóŸkY—¨¦ô(§‹ ò/—V:×§ë è\¶–—ìg]ðÀáwˆ¸ÿ9«ŸU@»ù8M6ˆ¿\ÚHÆ¿ž.]€p»Íº¨î°®ëêý©oôwd×¾¾¦Gù(]´,Ûüß¿Àv©0§šw%x=À€NZ^>¶Â¤PK»Ù-=ÊGi¦sýÙ€º÷ Ñ¡šƒ-þ<3_V/ö÷;{^þ)Ž_Óçz ¢ï¤ÉyˆPYØ­ÍûdÇ€ÍT\)Fá×ï…›öÞ•t hßI7#êo9 €ó€ýhñ•…KpînFÔß)Îòÿ[¨x’ÂÏåló|gvÊ»\«ÿØD‹«Ä(|9Ìõ›pn¨š¹‰0b‚D¨XŽ=ê‘!íϽÓEi5 üåRNg€s1Œþ?°•èɺâOõ–û@ýåRiâ™±¥ßô€}ïOü×’ÀBËÿê~ý^h§É ÄIú]þ?°•:p®s¯Oxýz:ÍžÏÇž}a²¸®FôSàSö;`ìpª0ÿÀZ¼eGáŸt=ëg0oþ€ ÄÀGáµ+æñç·—Åݺ é=Ì?°®‹ç>?éÏP7~霹{ÿlì¦à¿Ÿ ä(¼M¼¸?‘üÛé\ÐFál26Ðòsˆ¿‘l¦ò^óQ8Ÿë{ñQzù¥îï÷Üïß@¶µì”–«1æþ.mˆ˜ÏwÝïßn¼‰ÿ€n:«3Ugu[ºŽ ÎYšQ7«ñ(ö{*ø¨.ó÷}~òåXíN/Í#ü9Àßj»Œûîû+H9Nú®Æë¦5uów´ý'ö—‹½‰ 95Kkêåo¶ák?„ý5DF?Dé(¼?~GøÎ*ú³éÿAýWÐý‹þiúçèþz½ü¹t/„X_‘óRTÖIpɯ·_/«åë¹Ñi¬ð,S™¬$hÈç_I¹32¼×‹Å\¦Za˜’_oo/£å¾È3ú„ˆ%ÆHÂU´™î÷>ÿšij™¾~jy¿Þ¾C‡Rµp-%J2ÓAYîw+îKˇ¢¤“ðI’݌иߙŠ=ŒÿF !¼¾ÞÜ/ϾPª~cà -™Ó‹²+qµ¥h¼u`•äd©è{aðÆ)Pò/ ë¿‘B¨‰Ìp/1™„‘Ìã¿f1âXCAOÖ- NÂáwøß,^¶s’9èq`Ä뿾R¼ÀëÎÐJòúò½„6Žþè[s\©W€ŠÃ%—m@Û$2Ô^5è_ÿˆYðßh1#û¢É€*Bî·ëµÙ$#ûKê ·xC#Å­W úש®wošŒ¿(÷Ò/E¥ÖIa ¨ÀÐë¥%¿x–>«qÖ%ñ_`'¨Z.˜ ­W ú×™®woÂþ+iâO×.à%ßE†7ÝöÇÝs-k§§V° Tà€ÆtìX¿‹æã Zjxãï÷[iqÏÞË4쯒Ó*dÕóW "èAT3çø=iCüùj]´–ÊÕAÝkâ1È.ç= ì§n† §j7 U‹„=ïýM Ú&¡Fn 9omŒÇ‡Ú¨ri7¬YE0Êoìc+£¥B?ìÞ€ƒm†ã¶—öÿõ—á¾¹GïÚðæYæ×.Œ?!àõö]¸Œ·gŒœZÊ‚K—³ÜZ^˜?ÿÓ²z3Ü4Õ¥É `›W½$þµ xÝëœ~ØÄi˜¥,™ÅfíF·•çÖOÇ™/­øpÁbrÀ² ×Úîqªá˜%çE±‰«]lÛ@«úé v©1±ncùSè¿n‹ü]ªi‰ýZŠõrbÔ˽|ûÛ¦’0dä˜æÿ¥œ^‚¹,5Y·µ|è¿)î$9 { <À›Xo£ŸÀÈ~êO§“hƬÜ€“nžMÿÃíŠÖ#=b»Tóå7ÇEÀh€u­ÔŒµpK4Uþ6ëEÆQ;[tÒµ"< "Ó_xµ©ËdxÌ:z÷*Æ?ðßSœ½±uÑc¿¸­]öË­­ª`ÔÊnàqpi†Â•­¦ß6þüÅië|4¡öHø«$Ÿd+0´ÝZ”Q+i7*¬@i†Ö‰’½¦fÑÛ)ößݳ3u¸oxs@2ŧdj=-Åô«Yrgô¥û$¢Y¨€ÅæƒÞH¹tàA ¦ü›•‡þ›–?%£ŽLâÔzÄ2Ö!ÔÁƒˆ?¥DÙu†1ƒš©|+#ˆ8þ„Ÿ²è´Á†õÆáòȳòÃ3u>ÕaŸIœäòJ<{茳Ä, Ì! ´:U—®ú½™‡Þï¶Óì9FÛ‘§ þ Ë#ÿÍ*˜[XœÛ^‘8ÕU"Mß5§Â˜%v Æì uùŠÐ&ì¶z÷ƒ°NaãÑE8>È“4¹t*½Ó©hÂð·üooZ¯È ƸkèhéiÔÆ"ž \½øÖ/»ÓV8ñþ›¤yÅ‹£ß¢â×êûö›å7§Œ›% Õ( úà( ég‰»CKê°K  ËÏ¿·†æ;QPK½ë°d~³nÜÕw—Íá§,eMfÝ}Ö^´µpã³£ÙÃo7ÂI”¢ÖgG¨Œ8•4c©ä»ËÙ‹Â3‹½"œ%¨ß¿ü3E?íâ?›îÉ$áo ¿9þ§ðÌâAtБYLm‘÷¼·hïEû÷Uùm} êÏÒo‚øâ©¯Ö?áóøÆÛ¹ÿ‰ŽoñfÞ÷ ,b2>¯ª\_.ÓÒCߺã§ÞL-¿;MW‹iû!_ë¯oƒ•ëŸú§y"ÙuÉø&4“Þ ò9ú°•9ÆùBCó «×ˆÿη|1ƀ›ò»õ;õÏýÓà„/D+Vz3H0•Våm£Tœñ§ë }½öävA2ÙGõûú²í¼ì%nt{nq6F€ª¯ X^ÁÈÑü…# ½­y‡ã㔑]qî½°i(«™ªç7ƒî<(ü¢#”$)Ö%Q;]ãÿæôéÿEÉ—l­]˜½„êÿ¶¦Â/–ÍGÙ^3"|+ ³>ñµŒ&`úR|9ÐÏAš6`ã”6&Y«É¾Ö&„²ÏÈòó">ôC(hû4"? ªãŽSR¶ †iô?͉M±Í`Úס`©^L;¸´kKhTጃ\€”©~é‡õûêb (âïBl˜¿A(¯<ÖR ”Ú®Ûœ»—Õ8€õkõøºÑSx‰o!ˆœøé7©H,rþÄà½IfPùÓéÔ–DQ¡êè%þT\ÖNRÀrb;Àù¢•šŸ¤¼œ*Ú^½\¥+ú¢X É¢|1ÃÚ×Èðw Ö@þ jó õ™Ãª«q0À/áûW¨G03vÔû›oèë$ü8j`_­Ã®H"·“Ðü³RóhqÁÑ_ó¼¸w¥ù†!=wýQHhï[lÙfÑ yyÕ¼°üM$Þ 8ÃJ3B(°Xó‹N+ñe 3ìïÆLŒåË*chûÖ!Æ›lºêoê\̦îYå$xv =,âD1ÀåzðB-ÃÐ&@dOí e=ÇPó ´±€øUFŽÖÓ$ipâÊk´} *¿>pägúú3‰N6ÞŸŸæCýv.>ÆôãtÝ à%£µ€ô{÷z:ò]ywG^7׿æ(•2þ¾?_·5þ½÷ô| G”–žáòM¼Ry´u§íóÎG´ó-çû ÷X?Žßi]#&w%Ä9>† —æ‹ /Ëå3>ÿDMå;{ ÝüX¿›~“ãòAÀ"yEó@°påÝ×?Šò«ÅðCý(~kŽ%Á´0>/ ÛAË%ü¬ügÐúõ¦Ü(?Öï¤ÛJ°ÑƒâåË>^ÞK˜ß•×ʽx~Éõ£ú&Å@€žiÒ @² ÿ>ÀgM&+¡Ã;Æõ{ ­­†?ׯÿvv/L+(Ô¯1È¡ÂkûÆrÒúܼQHõ‡|iáƒzù¡~_^¦'€h"ÕÍë°_€·…»—àk P»§Sÿ¢Ó:û²?£ø~Óït~?€wå8äÊû~Ò®€Újiý–ßë@àN,= ÊX¹LBŸZ§ àWPÜþňù¹~ýÿÎ`ãu3äîîÃï’¸Š1T¯Uàûò^ºŽêŸP¼ŸPþEÅË: K~cBDüýËÿÎí_$' ˜±ÿ.šçn¹¼°‰ °„úÊ‚ IDAT +~ Måëµ”’ÞÈC¯øæ_KR}À!«`7ÀÄûÛÏïÑ¿Šù94^¿ÜÆ_Ï¡õÈïñg€—€åõ†p_ ¥3Ðú”ü$ÀÛ@MÊŸÉÉê#h@.÷¯Zfù‡ð&ïÇsûx¥*î»`¾ŸÇvu€;øë£½DŠÏÀ‹ìåù‚ø{öK òûòÄzd,¿ËŸÞÐ6@j¢¹?ô*ßÿû™%«ÀŠ7Ì@rö²/@3X¢É—CÄÜ׫'-þ¯µ‹wøzÉÀ:X%À˜máø+œQ²û†õ* èÓ"ù¢›@ÝløÀ›€íd€@ ÀO-K(~-äƒøñOô™¼»î_4„0õË%#ŠýCJZÂË€ýÍåÓÝ–¾üL_1‡agu%€XfÐËUHíaô8¨Ï¾}ž¼ZJë¡À¦ƒ /ÿ$Ö5H & öð+ê5^€W&3ÈG}1  —¿T“¸=ß/¨ñg̾h¯í(^$R0€´É‚ÓE´Öð_‚ïœ&Àí@  S™jôSªaðö:1P?5Z¿0]ÅÇàήN½8^Ja”^~%÷÷ïô.@~½‰[íã|µíÓ4b”Gêœï#¨®Ý‘¿Âd¹ÁEnþí©_œ&ôLJ™Ø|ÆâoîÕGéºˆÐøõ?^^ õ´=ö¡t¬0Pµ`¬…Gò‹ÇOìc}äáÑú%i’ÔŸSï'Î.kƒ4£ŒÿŠøoŽ~è eÀ€}(ÍZ%Ö4!žT„fê—§’úðÉQé«WD§ýZ¾[ž­ä¼NAùb'²Ç" Ï>'ÍÇ,Ò‘4H²Ãõ¯éZÇ©úùiÊÿ6Ÿš‡±´EDœ´¦i>Y¢ô# Ѐý^šÞŸLZ?ŽèŽòný²ôi0>&öUiM›ø@¿—ögú4záþ^ùúÁhý¼´~Ð[“B"KGâ‡ùžiNTQýA:õߨü.ýözòGötÐAtÐA)ÝýF>b‡÷çÿÄtT“ËplîbÙ° ?Ì÷Ø&ƒ–÷§¥½úÛ\r ŽrkŠ$·L/:Û?Dz7£™ù[ø÷²d(\-oïô}0ÝY“K͈“ƈÇÁ™ä¾t7ýc÷ÿk|Íý{r”,¯åýt:»oßYKOÃ+'‹QóÀ½îK‚Âr´ä%0ÍðJ>|ÞM}[ÓÉ}{[?õšs/°ÕvÆ ‚$}„–qî¬@»ÏùÆ_ÄZÁ9þk€ÿÆ9´&mˇiç¾ý|ºò_¦~ ˜øj»Öç@ø@ê@µX„·ˆ=ø~vÿÞ•gÒsûWX¤ðåy@rµ•={y¬ÕG/ ­|². €{ò™düï<ü?a ‡°¹ýj»¹wH.Tü-äp˜D lµwFÂaÓéfÕò[ï:;žûÐ6Î…§ÆùÐŒg káFo RŽ„’%ä‰ÝØ„ª´mÃký¤“êõëŸýóïÜmÆVYú Êí}ÞÝ—Ô«ã¡$Ržpni7¶:ÐI7)ËÈg.ŠwÀkòr•ë`_ÃÈ©^g𬂎Hy}Hu# ×ƒéú…ë¿Õiž^™éï²ÿõBz´+ºx-©›¯UÖOõ:kG´¢HéA$²q‚{DÎK“vl~å‡6À8w z»àUNH*=ƾ»¡äàó‡w.º·vD=pdÈ¿W;$=Ær‰Õk)ÉŽàíE'û‹/ ÿ¼:z.êÕ¯ð‚ø2 }ÄÚ§‡ÑŒáÇ¿eé®]¥`ú/ÆQ‡äŸ’Åb—…†û_1’Mz÷ý}Z7“ûef²äÚé¿ÐkhøÅ'æûB¦C¦e"þÆjKb s`÷W½±D‚ıð”4?3 #½¨/=aîtQ?î²2x£WEë©¥_lï4­o„l'þ€yµnMPYIu¹b©éÖÇ¢»@­‰oû˜€n¿U‹È¢«¢9¾[BqûÜ/˜ÿþÚqÊàÈ ÷•?A‡»=âñ»ßÛ¥ €Ö§Diö™O [¹«`õ´å™~Ù4èøW=÷²×¶ÖÚ ”gŸ2Í3¢Z@bîñ»4A³’Ái`#Ä¿—žòõ†Â|ܼÚ~·_G¯z)à®u‰]x{{„cÀÊ ²ÖËô•æ‚Bø2læîð«›ðŸ¼Û¥. Ô9…æã8ÐÞóX.oßUŽ{ë÷¨{ž>r?ÖÉœHJ;¢ÀÜ)c”2±4dªMü›dªòÒ'±>·`K#>€kŸD€oß« p!§5œxsP_áLª‰Ÿ%Úò-Wélôá<Õ³ƒÉ ÊsàûŒ½- RBû@ýÞ ¥ýŠG‚F?MT°çBòz€fD•š7K²~Ny™v‘ØŽÎòÕ6À^Ãöò´Ðû, ]ž&«Ÿšì¹Pô‹£ØÄl¡q`¡ ½¯Ž^¤/{¾±¼ûÀ³_ûbÛQ^þä>PZ 3¡/cs‘¡w`†.¯­ì _dÇåÃÈþý퉠Ér(ÜaÝë>qÐA„èÿ¾è'ÓýÙô_ƒ‡ûÿý\z+«õ“ëºÿ[ÿGlJò½´6@>峨’®Ù•Ýæ)ðÝW¼~-³†ÿ«ñ-éQ>N“/p”àt ™¯’^¯u»Iï50/ÿµ¾>ÿw/ë5À”åãt1AþåÒJ¯út½ÊÖò’ý¥ ˜"ü÷ÿ^*À/Ðn>N“ â/—6’ñ¯§K ¼Àn3À€.ª;¬ëú€zêýÙµ¯¯éQ>J-Ë6ÿ÷/°]*Ì©æÝ ^p “–—­0)ÔÀÒnvKòQšé\v îýEC@t¨æ @‹?_Ì—ÕË…ýýξ–Šã×ô«¨èã;i2B"T¶Gkóß>Ùq`3WŠQ¸Àý{ᦽw%ÝÚÇwÒ͈ú[GÎàu`?Z|¥GáÜŸ{§›õw €—üÿÀ*žä£ðW9Ûü#ŸÀ‹ò.WÀêÿ6Ñâ*1 _sýf¼ªfn⌘ƒ j–cO§zdHûsïtQZ (¹”Ó‹àU £ÿl¥z²®¸ÁS½åÇþP¹TšøbGlé7ý`ßûÿµd°Àò¿º_¿Úirq‡~—ÿl¥N¼êÜë ^¿žN3…¯×ð¡gFÁA˜,îëŸ}Óx“=ÀÎ;œ*Ì?°…oÙQ8À]ÏúÌ›`1ðQxíŠyüùíeq·nCzól ;GÀâ¹·7ú3Ô_:gîÞ?»)øï§9 o/îOäßÿvzU´Q8›Œ´üâo¤›©¼×|Îgãú^|”^~©ûû=÷û7ЀíD-;¥åjŒ¹ÿ¤K"æó]÷û·oâ ›^êLÕKÝ–®#ƒW–fÔÍßj<Šýž þªËüÅ}oo|9V»ÓKó¿ ð·Ú.ã¾;Âþ RŽ“¾«ñz…iMÝümÿ „ý%ÄbobCNÍÒšzù›-GøÚa ‘ÑQ: ïÏ…ß¾³Šƒþl:ÂÐAÿôü¢Ú†ƒþ9z^.—.= !ÖW伕u\òåã×Åjùznt+<ËT&+ 2ÂùWÒDEžŒ ïra1—©V&„äËÇÇÅhy.òŒ>!bI§ñ’pm¦ç³OÅ¿ƒfšZ毟ZÞ¯ïСT-\K‰„’ÌtP–çÓŠûÒpá¡(é$<@’d7#4žO¦â_ã¿‘B—¯7÷˳”*…?xBKæt¡ìJ\m)š]X%9Y*ú.¼q ”ü Èúo¤j"3ÐH1@ëUƒþuªëÝ›&ã/Ê]ô B‘C©uRX*0t¹hÉž¥…Ï*E¤uIüWØ ª– FÆ&CëUƒþu¦ëÝ›°ÿÆJšøÇÓÀµË‡¸HÁO‘áC÷Ãýq÷\ËÚé©ìÄ_8 1;Öï¢ùøÇˆ‚>øûýQGZܳÏòÄ#û«ä´ Yõü•‚zÕÌ9~OÚ¾Z­¥€ruP÷Ášx ²Ëyû©›aã©ÚÍ@Õ"aÏ{ˆ¶I¨‘@CÎGãñ¡6ª\Ú kVL òûØÊh©ÐÏ#»7à`›aĸíå…ýÀýå/¸oîÑ»¶¼9@–ùµ ãO¸||.ãí#g€–²àÒål·–æÏÆÿ´¬Þ 7MuiòEØæU/‰m.Ï:§6qf)Kf±F»Ñmå¹õÓñ_&äK+>\°˜\°ìèµ¶gÜ„ªA8fÉ9$DQlâjW›Ç6Ъ~:ƒ]jL¬ÛXþú¯›À"—jZbÿ …–âD½œõrßþ¶°©$ ¹¦ù¿¨§‹`.KÍCÖm-úoDŠ;IèYÏð!ÖÛhàç0²ŸúÇÓé$Ú€1+·à¤›gÓÿp»¢õHØ.Õ|ùÍñ_0Z†`]k§5c-ÜM•¿ ÁúG‘qÔÎt­ƒÈô ^mªÃß2³ŽÞ½J£ñü÷ãTgl€@ôØnk—ýrk«*µ²x\š¡0@e«é·GàŸ?qÚ:M¨=þ*É'Ù -B·eÔJÚ ëPš¡u¢¤GD—©YôvŠý7DÏìL.Ä[ÞL1Ç)™ZOK£G1ýj–<}Aé9‡ €hê`±yÅ 7R.xƒ)ÿfå¡ÿ¦åOɨc“8µ€±Œuuð âO)QvaÌ €f*ßÊÁ"Ž?á§ì:-@ÁF°a½1F¸<ò߬üðLOuØg'¹¼R#Ï^#z ãß,1 s(­NÕ¥«þlæ¡÷»í4{ŽÑväiƒÃòȳ æÖç¶G$Nu•H“Àw Ä©0f‰]ƒ1;CF^"´† { í€>ý ¬SØxtŽòß$M.JïÇÆt*š0ü-ÿLJÖ+2ˆ1î:Zzµ±ˆ…gW/~´ÁËî´N|€ÿ&iÞ@ñâè·¨øµú¾ýfùÍ)ãf h5Jƒ>8 hºÁ™@âîÐ’úìÒèòóï­¡ùŽDÔRDïß:,™ß¬·GõÝesø)KY¤YOŸµmmÜøìhöð[ÅpåhµÁÙ$*#N%ÍXêùérö¢ðÌb¯g ê÷/ÿLÑO»øÏ¦g2IøèoŽÿ)<³xÐAôcdÓD[ä=ï-ÙO]>KoPÐ¥ Wš]Ššp_Ë’V}´¼–Ó›Vd“~·þYþ®´îŒL”óMÊëw±‡š6¶sP£¯¼ åÔòYš•äs²„߯’¿+•½ññc7þ1ÈÔþô~þ¯é@s&/._—ÑM˜Tù,½âÔÃï×ï8(ã WÄÓ¸t…öÆ'Î]µƒqË«_ÛWn*ùí¹¶Ùʯ`«{2ƒ,Ÿ¥õ¦ÁÇŸ‘«ß©Â®¾$»=1¿´VP´"îFZ™N|ž¦•·³Ê"»Ú{Ñþ½T~[ßG¨ú³ô‡ ¾xêë‡õOø<¾ñvnÆ?E¢ã›A¼™·À=@‹˜ŒÏ¥*—À—Ë´ôPÅ·îø©7SËïNÓÕ¢FÚ~È×úëÛ`åÃú§þižHv]2¾ Mã¤7ƒ|Ž>le·q¾ÐÐ<Çêu±áò-_Œ€q ð¦ünýNýsÿô8á ÑŠ•Þ L¥UùGÛŸÀ¨gGüÄé:è†D_¯=¹]LöQý¾¾l;/ûD‰Ýž›Aœ ê«–W0r4áÈBockÞáø8edWœ{olŠðj¦êyàÍ 'Ï# _èH %IŠuITÁNG×ø8Å#}úQò"[Akæc/¡úlÀ†i ð‹eóQ¶×Œߊ¬O¼,£ ؇^T/ôs‡¦ Ø8%‡IÖj²¯µ ¡ì3²<Ä<€ˆ}„Æ Ú> €ÈÃćê¸ã””-ȃaýOsbSl3˜öuD(XªÓ.íÚU8ã àeª/úaý~º˜ÂŠø»æoÊ+µT¥¶€ë¶çže5àBýZ=¾nôÔ.âD"'~úMª‹€¿1xo’Tþt:µ%QT¨zz‰?×µ“°œØp^h¥æÂ')§J€¶W/WéŠ^(–B²(_̰ö52üˆ5?€ÚüÃBýGfãðŸêj ðEøþê ÄŒõþæú: ?ŽØWë°+’Èí$4ÿ¬Ô<Z\pô×<î])G¾aHÏSÚûÛ_¶YôE^^5,‰7(ΰҌŠ,Öü¢ÓJ<@Ù {ŧñ“ã_ù²ÊÚ~€uˆñ!€®ú[€:W³i {V9 žC‹8Q p¹^\PË0´…‰ÙS;HYÏqÔ|ãíc¬ ~Õ£‘#Vþ•°<þ®UÛ°Žäçô¥|õý€ÌÞÌþìù<ÒÝÀðòg‹BV¶0Q¡òSW° ù¤fÓF¹Ë@V¾kÏšVµWå;ì‡rûë¯êåÚŸîöÅ{M>€V¶PsÄý0ü~€ruè¬ ~êç¥+/¿ÌùÆZ~`O1Zn3ªò©ýŽÜÑúçöo@õ¤š¦œN{mu"ø†•«³ õ;PñäÏÅñí@M¢<‘’ÙSÊ·Šƒò™ýžÜáú§ö§Nø'ZØb@Bê'Ž?ì‚ÊJ܇ ?QóëÃÔŸ€ZD€T^ËG^¸hå3û=¹³õì—?}ÑJ»9ös©ý³/Ýû¾)å`9ŸòLËöqQå•3yJ>öãƒè‹ò‰ý®Ü¹ú‡ö‡ÓÀžËŸäÈá†ÚŠ¥Â!>]ø, e Q›÷á|`çEðûR¾'wcý]û=zf³ÄÕæÙ"p‡xMxÃªå’ 5༸kO§})ß“»µþ‘³-Y–iN4-ôÏÊNª—Ö?áCf–Ø—ò=¹}å1"û7ѬèŽrÙJåAtÐAô7R[m X8Óîüý# èѤ¡øäŽ_()Ä¥òzÒƒ.Ίó–ç>pÄ|ß d£>^ŸâúÅTl‚õã4‰Cœx…òÚmŸ¨Ê¯ù™~§þL¢€÷ç§ùP¿‹ñý8]÷xÉh- ýÞÁ³žN„|WÞÓ‘×ÍÇõ¯9J¥Œ†ïÏ×mM‡ÿìã?=ýD#ßèÑ¥¥g¸|¯TmÝiû¼óí<EËù~Â3ÖãwZ׈ÉÅD qŽ!è¢ù"ÃÅòEùŒÏ?QSùÎ^C7?Öï¦?dŸ|°H^Ñüä,\yÏõ¢üjñüP?ŠßšcI0-ŒÏ èvÐò/ ?+ÿä´~½)7Êõ;é¶lô xùò„—÷æwåµrž_rcý¨þ„I1 gZ€´(lÃðY“ÉJèðŽñCýh«@ëáOÀõë¿Ý ÓÅ õkA r¨pYǾq…œ´>7oRý!_Z8ä ^~¨ß——éÉ šHõGó:ìׄàÄmឥøÔîéÔÿ†è4€Î>@…ìÆ(¾_Áôûß D'À]9¹ò¾Ÿ´+ ¶…ÚFEZ¿å÷:xRK0€2V.“P'À§Ö©Bø·1b~®_ÿ¿3ØxÝ ¹;€ûð§$®b Õkø¾¼—®c£ú'Ÿ'”Qq±è’ߘ¿Gÿò¿sûɉfìŠæ¹[./¬G"¬èŠ@Sy¹,¥dòÐå‚~g ù×’TpÈ*Ø 0ñþöó{ô¯b~×/·ñ×sh=ò{üàâ`ù_½!ÜÀ CéL´>%? ðvPÓ…ògr²úËý«–Yþ!|ÈûñÜ>ÞE© €û.˜ï§Å±]àþ:Æh/‘â3ð"{y¾ þžý’‚ü¾<±Ëïòg€ôŸ šhî½Ê7Æÿ~&FÉ*°â óœ½ì Ð –¨DòåqÏõêI‹¿Àeíâ]^.²°VAÉðf[øþ g”ì¾a=ŠúÄ4€H¾hÀæP7¾ð!`{  ÐðSËÒŠ_K#ù ¾Cü}&ï©ûÄ !Lýò@Ɉbÿ’–ðòc`sùt·¥/?ÓWÌaØY] –tqÒpk=ês oŸ'¯–Òz(°)ä ÃË? €õA Ò¨ ¨=ü ¤zÍ„à•É òG_ CÈåïÕ$n@Ï÷ jüY#³/Úk; €KEI Ô€ m²àt­µüK„à'§ pûP(äT¦ý”jX|\N ÔOÖ/LWdñ±x²«S€‹R¥—_Éýý'½ _oâVû8_mçAû4Øå‘:çûªkwä¯0Ynp‘›{ê§ ýña&6Ÿ±ø›{õQº†.â#4~ýO€—WC=m@§}(Ý+ T-ká‘üâñûXyx´~Iš$uÇçÄÆÅÔ牳KÄšÀ Í(ã_"þ‡£:HÙc0`J³VÉ€5MÈ#'¡™úåi€¤þ|rTú*ÁÁi?‚–ï–g+9—SP¾Ø‰ì±è³ÏIó1‹t$ ’làpýkºÖqª~~šò ŧæa,í@'­išO–(ýH´ G¿—¦÷'ÓŸÖ#º£¼[¿,}Œ†‰}•@D`ZÓ&>ÐïåE ý™~'Þp¨¿W¾~0Z?/­ôÖßäßÈÒ‘øa¾gš“UgTNý7*¿KA¿}§žü‘}tÐAtÐ_JO@¿‘Øáýù?1Õßä2›»»ð  X6¬Âó=¶É åýii¯þ6—ƒ£Üš"É-Ó…Îö‘ÞÍhfþþ³,¤ WËÛ;ýLwÖßäR³0â¤1bÇqp&¹/ÝMÿØýÿ_sÿž%Ëky?ÎîÛwÖ_çÒÓðÊÉbÔ|ð¬ûÒ °-yÉLó/#|€’ߟwÓFßÖtrßÞÖOÅ_½æÜ lµq‚ I¡eœ'kcFÐîs~ð±VpŽàp­IÛòaÚ¹o?Ÿ®€ü‹©_æ¾Ú®õ9>ºÇP-ámb~€ŸÝ¿wå™ôÜßþ)G|yž\meÏ?.+A@õÑÅ@+Ÿ€¬ àž|æÿ'ÿÏ@ˆÂ!ln¿Únî’  9&Ñè[íÑŸpØtºYµüֻΎç~'4„sá©q>4ãYÃZ¸Ñˆ”#¡d yb76¡*mÛðZ?éÀ¤zýúgÿü;w›±UV ¾‚r{ŸÆ„O÷%õjçx(‰”'œ[Ú€­tÒÍEÊ2ò™‹âp™€¼\å:XÁ—Æ0rª×<« #R^ÂRÝèuà`º~!Äúoušg‡×Efú»ì¿\màʇ.^Kêæk•õäS½ÎÚ‘íŸ(RzÉÆ†lœà‘óÄÒ$€›@ù¡ 0Ψޮ¸”’J±ï©C(9øüá“‹î­Qò/ÆÕI±\bõZJ²cãƒø¸ÐÉþâ è?¯Žž‹zõ+\ ¾LC_±öéa4cøñoYºkW©X†þ‹qÔ!ù§d±Øe¡áùäWŒd“Þ}ŸÖÍä~™™,¹v`dúŸô~ñ‰ù¾éÇi™ˆ¿±Ú’€ÂXÆóRo,‘ q,<% ÂÏ èH/ªÃEO˜;]Ô€§l >èUÑzjé Ä;M@ë!Û‰`GF­[TVRE®Xjºõ±ènPëcâ[Çþf ÛoÕ"²èª…h€ï–BÜ>÷ &Å¿¿vœ282è}åOÐánxüžÏviA õ)Qš½CæÅVî*X=my¦ß@ö :þUϳ쵭µöåÙ§L`󌨘{ünÍAЬdpXÀñŸ¥§¼|ÓÙ§$PIDATà€07—¶ßí×Ñ«^ 8„k]b>>.á0„rƒ¬õ2}¥¹ ¾ ›¹;ü*À&ü'ïv© ƒuN¡ù8´÷¼–ËÛw•ãÙú=jÁ. §ÜÏ€u2ç’ÒŽ(ðwÊ¥L, ™jÿ!™ª¼tÆI,Ôª]ܾ>@ù©óEñç埭‹Ò]Hé6Oì.g/.ú@ˆÔW8“j"Çg‰¶|ËUú}8Oõì`ò‚òœ8À>coKÃ…”Ð>P¿hEi¿â‘ ÑOì¹¼ Q¥æÍ’¬ŸSžD¦ÝF$¶£³|µ 0¤×°½<ítÄ> C—§Éê§æ{.$ýâ(61[¨GX(Hï«£WéËžo,ï>ðìß×¾Øv”—?y”ÖÂLè ÀØ\dD蘡Ëk+{ÂÙ±Cùð²ûF"h²< wXw¹€Ï@tÐA!úŸ/úÉôA6ýÏ×àáù??—ÞJÁ*ÇAýäºîÖÁãÿ›Ò£|/­ Où,¶¤kve÷y |÷¯_ˬáj|Kz”ÓdÁ%8ÄB楤ÆeÝnÒ{ Œ†ÇË-…¯Ïÿ<˺D 0¥Gù8]L¹´Ò¥>]g@—²µ¼d¿è‚¦¿CÄýŸ‹ ðE´›ÓdƒøË¥düëéÒ°ÛÌp  ‹êëº> ÞŸúFGvíëkz”ÒE˲Íÿý l— sªyO€×è¤ååc+L 5°´›ÝÒ£|”f:ן¨{Ѫ9ÐâÏ óeõra¿³—åŸâø5}©*úøNšŒ‡•…íÑÚü·OvØLÅ•b.ðü^¸iï]I·€öñt3¢þÖ‘³¸Ø_éQ¸÷çÞéfDýà"ÿ?°…Š'ù(üRÎ6ÿHÀçpa§¼Ë°úÿ€M´¸JŒÂ—Ã\¿—†€ª™›8#æ H€€åØÓ©ÒþÜ;]”VÊ_.åta¸Ãèÿ[©€ž¬+nðToù±?Ô_.•&^Ø[úMÿØ÷þÄ-Y,°ü¯î×ï€všÜ@œÄ¡ßåÿ[©—:÷ú€×¯§ÓLáå2|èÙ€Qp& €çúgD?4>d°3Ƨ ól¡Å[vŽðA׳~óæØ@ |^»b~{YÜ­ÛÞÃüèɰxîãƒþ uã—Ι»÷ÏÀn þû©@ŽÂÛÄ‹ûù÷À¿.mÎ&c#-?‡øéÀf*ï5…óÙ¸¾¥—_êþ~Ïýþ t`;QËNi¹cîÿéÒ†ˆù|×ýþíÆ›ø見:SuQ·¥ëÈà’¥uó·b¿§‚¿ê2qßÇ_ŽÕîôÒ<Âü­¶Ë¸ïް¿‚”ã¤ïj¼.aZS7GÛa ±Ø›ØS³´¦^þf˾öCØ_CAdôC”ŽÂûsáw„ï¬â ?›ŽðtÐý?Ûb·y:ó…IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksScreen.png0000644000175000017500000001011113263214225022341 0ustar aeglosaeglos‰PNG  IHDR 0«tĵPLTE]]]™DÌf333ùÌnnnLLLÿÿÝ™àb¿ÜæIDATxœíÜ?oãØ½‡q@hTí:/![¥sBtÉILyJð¥YCT 9‹M{ƒ-öÝÞó;‡”d™”lÍ·Ê}xhÒÛ| ñÏ¡VÉo4•k.,q5Mô¿—ƒþAýPm?ú ÷—ŸýóŸè¨ß4¡£ Ú÷!ж®=ÓiÐöõÐUË5 §; ê¯_ Iqp_èT'A]¾MËb@§: ê7¯‡½Û:ÕÔÕm½nŽri÷t[í‰jê9e›Ý/ÚÖaßꪢôTû·¼KžìéÏä2ü2ÐjÑzêuD®mÎn è| éÊ Û*)üµ‘ýòˆ.ÝÚ™=yº­#h’Þ¸*t¾CЭ?¹¤(_\c¿þ‘4Î}Kü™=]m“E¸®O‹ÞïZ:Ûè²®ÒÎ¥eŸ¹…ýúR¬\²¼+úëúþ1-Â_¤}ø @g;ýW’ž«Ïr—†_¥¿H*–÷]ž,ë»~c‡Õ»îº²]€Îuø })Ê®½ëò¶J·öë9ó®/.kŸŠÄu×v4­»Ö«ç¼Bg;<†º¾ÿÖ¸ov‡Ù¹oÍzá_ª½ÿ×ý¶úä™KWòïøŽ“Ò|‡ ?\ý¥y°SyÙù_Oñ²)}°Ë¥Â_‚ú£imïx@çÛƒ>¤ÝM²X57‰?•g­oü¶&)67‰ë«²Ë]½{Ç:ÙÁ½|Ñ=Åsã½7³õG¿­y*m»¿\ªÊÌ_‰Þùwü¯€ÎvúÜ5Wý&÷‹ÎÞÔaÝoküËõª÷—Ku™Û¥è}Ö>:Ûál“gÌŒ2‹ɸÞ4¹­gm}Ÿ·ëði‘ŠйÞÿ¤5ÊÄNPUú è\x¦´ôžéêÖÎø›ЙFÐ7S¡o{JìüÿlgüŽWè\èÿTïx‰¾øsý6ÿZñJЩ"h[W«ó/ÓG;×/š¾ï¸—Ÿmx…úk"Ïúpæ%ú˜Ùc»Çá*ЩÐ÷9o~—C§:|lèTãIéö.ožžÏ>¶tªêêg·iëõ&oí‘‘«{þ±n†çsqlƒøØn èl´­’_¯¿5®zlëdYy¸åƒk\ø°ˆ§ ã0X»t;>²tªê’â¦õŽÕÊ%é­?á»-n×þÇïIo\Ç6p.Ý=²tªš–ýÊ­Úê¶J‹mUzº—¶zj«Öû@ùÿ°§#ñ‘ “  }vå>¨¿t¯ÊÜ¥ÝV«mw×UÆ6øaÏFã#;@'@ý¥ºK¯½Yéý ´o«² ãÌŽ6ÿ§ñ‘ ÓÅ“Ò]ר“¹ªt¥÷3Ps½cÿ~/ã8 Òmxd—:ÝpÙžÌyÐëÚ_8ݨ1&6vöp.Œm§?††Gv¼ågŠ ñÉœ=—u½¼_¸ð‰ÿãÇURôqìëð(Ïã:Óp§ŸÌ%enstÉׇ´{Hû/ioã¢ì¾„± £<Ï1t¦4>™{*s›£{YmŠ®)ºÜp¾eŸ5qì«">²ã:Óx/ŸÌõy˜£ëŸ»&þØ8ËáQ^˜ÀtªÝ#0'gÏã³ÌÿÊšáÇmös?ò2Ž¡3ñ?~‰T â¨8@Å*Pqzá×=:•^ô…Vt²zÁ—ýþ@'  ÿùø×Õ€NA/øïPq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@ÅÐï¿}8@g  õ:]ýã‚Î@ÿùË%:™^ S*Pq€ŠT â7 Úú»¡u[Û  è$hÝÖkcºôýM–õÂyÓ*ôýMoëÔ^§I±ôÝ|ËWéÆùEÙúîNƒç}è»;} -=¨怾»ÓÇÐÏ™ÿ5ót²Ó—MiîAg^ €Nvî¤d Óèdó·ž¶·èšÐ5úT…¿`z*ýH'&GzŸ?õ€~¤cPçoÞ×vülÜ·,Ë®ýZf™×¶ô|o@+ÿ+Ž–q g{ ºò Ub‹• Úý¡­z¶7 áÕXÆXhqã!ýù)l[z®Ð2€æáíç·Ý÷aG è¹Þ¾åÃ{üÔŸU83%eè™Þ‚¯Aoâ14YS@Ïö´| Öü%¾«në¢ô\Ó »ë¤ÝÚ½í¸ï=×$è­/ƒe;‚ÆWí«‰<@§:}HÊ/Iéw¤7¶{e‹›¸ð;V€žëͽ|QæEùÕ_xö…ÍŽ„)’°vz®7 Ï}îú¾ï®lvÄÖú«¸°€žéílS–ûŸÇ,Ëÿ/®åa-ìôL¯AÃ4Sœk²Y§x¢÷›‡5&GÎ÷tw©´ÞÍ:UF;žè=Ûè0¹æšÆi&û4Î0áÄYþlÇ qrÉÃ-R1Î?Ù„gù³½}Ë›[_Œ·HÃ4S\«¸—?ÛÛ“’ÝdfW#cœfÖ=ßÑeS’ìfE’qšé{½›pôlGoù»aòn=Lã…i¦d·èÙÞCæB†i¦b\{ýœЩÞC“8×´ŸÆ{5¡Wzº7ÇÐ$æšÊ/ÓLÚoèÉŽ@mr©sM6¹´Ÿf*v³N€žìxrĦ™†¹¦üù`šéj7ë”zªcÐ0Íçšlri?Í”íf=ÿ'8@Å*Pqúñom²/nt²‹¿·éï€Nvé÷6ýÎ÷6M¿ûîãßÚÄ7‹ÍÄ— ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â¨8@Å*Pq€ŠT â@¿ÿöá)€Öètô t:ýç/—èdza€N¨8@Å*Pq€ŠTÜÚÖk@  m¸µýjìFt­ÝaºÝ¦ý:Óê’ôÆy®z÷‹EÐ>Ø´Ø9:Õº¬ïY¥þµº¬—Ã"IÒøòÝmþ`èL´­\â®ïšenëôÖÃ…E]ߣ7¥ã¤€Î´Mo–Õ¦5/ßr·°a˜ß‹”þ§ó£*Ý:Ý´¿­þÚF¯: ‹$¾Éÿê5hÑ:ÝÔ]W¥>xÆô‡-^Š[SMÂÁôvÝÚ1´t¦ñ¤t[ûÃhym^…0âߚª±†Åꡟ3@§A?ûUšÇдëûm}¸=¬¤9 Óí.쿺*œ>…sÎ~Ñ=f×õ¸}¹ûNJ3·žËºJŠÎoHü¢ø±[tv´Û¾[á:Óúä‘Êî©(ŠÿWvû…í,Æí/»?tºÝlÓKQöYÓ÷}÷ìÙ~a;ûÝöÝ  Óí@=RÞôÑ#“LÃLÓ뉧ýìÓwó½š`>šiZN €žîtœVZ$®J–GO¶-ôtG »i¥'W…;¤d˜xò÷JÅ‹ßfŸïí[>Þ m\UÚuþ]¸å´mþôî·õ '›õ7H/sáNsý”e¶-ôdSÇPÄ, 4ÃæîmÇÐÓMCÝ]i ×qÎ)€¦vôô|Ç Û(Øgt?ñ”úC( ïhôSnx»9'¿­óGO@Ï÷ú“#IÚùËM[4‰CÇ9'¿Íï¶m€žî5èSÑ=/¶Ø4…ÇÛÍ9½„i¼° Г}¶É(û.,šç>oösNñúÓ¶z²#ÐÇÌÿ„EÓØŒÒnÎé1^f€žÉ@íz¾]7nmKã¿v˜n²Íþ/üþ6î³A˜vtªtéå*;¡ÿêv¸dZûÍ^w¿? lÚ Ð©"¨={÷r7®²%ÿoY/Â4“_5G3üî1mŸ¤~G èd4õ·Dµ¿ÊtUa3J®ºµ…Ù¬SýïðÃ>?°góÅЩ†·|xön ¥«ïûðAœmüœS¦L÷õ S  Ÿ®÷ Uî&Aþø§ Щ†c¨ƒ»´JVî{ñcLá-ÿÝ@­†}”cèdã1ÔîáÐÂÿsweüSõ/Íáüöz¢ñ²)ØÅ·|}o'¥þú4NêUã>@çÛ_‡¦Û4~:-Ý€În=“$Î1•_ì'In’Ò®3mÖ釸á—4®&qÐ%€Î@í³K6ÇTæ…ÿ)в(¿›0õÔÙÀ¶¾„Õ"l “ÅÉûÄ’Í1åÏöÓ÷W}§œìƒLW6|îâj¶Щ"¨}bÉæ˜òf˜\ ÓKñǶ5®fq`;üû—ûË{?÷ÿzþ>ÿ%/ÿoû)PšPq—ƒþû¢oÓù¯ïrпý‰¦ºôÿþhCÔ켟IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksDC2.png0000644000175000017500000002155513263214224021507 0ustar aeglosaeglos‰PNG  IHDR õâ;c~PLTE™™™wªÿªÌÿÌÿ]]]™DL"ª™ÌfL333NùÌÌÿÿÿfÌÌUf3nnn™™ÿÿÿÌLLLÿÿffÝÝÝfÿf3ˆÿ»»»ÿy;ŠÄ¯( IDATxœí {Ú¸†²MS6'»{²KIã…öÿÿÁ£ÛÈÍHcc 4í°>ßð¼Öe$ËÕfålãì¸Ë{k‹åòsÏ|çÒé²*²FÒGŸÀÌõjóQ9ûpvÔåßÖšår¿`¾siƒôϬ‡›¥¤>™ë €I ˜€}ÎÃzMAŸú_º®˜’€é<Ülˆ—’n÷²d,<üUém¨&$àì?gË}ƒLÿLIwèÞ}÷·Âðšô]¨[~_;ûÝÙQ–õqNÀ>ç`I‡ ]ÁèÎHo½u—…Œµ•Îæ>yzç£×y}w· ô©Xu°¤ €êöŒö¯^FP-¡ªÌ }¡ògJ_@ÉøÉêU`Y½Íëí]Ëê­Óë»:Ы• Ûˆ”š™T]Ì €Êî³±õ2¾€v¹©ª}¸éþÉû”Þ€‹ö¬ŽÈèuVoï6w-§ïŒ¼«•^ï¼^­* @öòK¢jS úqhëMÍ:¸µêÝf£<ÜR]qÓ*÷]!ÐZEPMÀfN|DÐZ4€×;8=€Ñ9½æõ:̨®Šþ ør]WŸ€9ð@+QFð°z£#¨Ž :”á¦@u]ô;ZN×E¿åG׺J ­«OÀÇihrUQI÷è⨳º¹ñƒ"Ò}Ñ_™¬ `­.Dp_,jù5¨jø¨Öý¶?\Wöñ½% ÌënU€ZFG¯"x=¨0:ªP@tSô'õ®è¯|+!PâßU"A÷ßLs’=‡6¶pÆT‘1•@FG•@¢G•ÀXÇP½ÎêAÀéAPíB}j&‰0„v;´y½ üÏé¾`sÀÆðÉGíf^tLÛÍ=¸aZá1¹V££VÑ£V@¬#Ðë¼îZ±nǬ¡âv´ÊYÓ0MåÒÆ•6¶Øt:€Õi%0Ô¹J` c×[Ag+‘0 «ÀIt›´ Ð'Æx)0­t™V££VÑ£V@¬#N [×ï"½‚ºúôˆ1^ ‰PpÓéözE¡`¬ÓPp¨s¡à@ÇÔR:ÔºJ`PWg/°^=7ú;ãà.ƘÖÉþØåÌùÝ’>¸ÔÕ“ä<”sð‡@oòtÅ S°\[+@Ò…V‚¯DbÖЇOká’‡Rµx èýÈœŸ0Þ£fÏL%0'8…žš þüéè·r~ €*þ6þÏ9ŒwÔ¿ïÆCÔÖ{GÖSó4П?!½öOÎï‚0€l%0€öŒú£îSã!â@㿪Ê鯳’þé©ùèÏŸ€>û'çG`븧²ðœÄf`€çïߟµ—Œ«¾RjݨiÝð¡<ü=µ½ÝmŸœúóÇ€÷:|ÿôüp›vŸyþ?¶cëš?iû}fþM†ZåÍ:xa¾¾¾ÚíušÛE wû VèŽÙmOÎOÇ`Uí_ß.6ï[æü;ðö)‚U(¦<ÝØ”¾ý·p~:¹ÿû’–ÞRz_ÀiL* ýöú.Q[|4½=Êûuÿû…-³NÙ­tpZ íò~Ø¢äe÷Œ ó¾€Ó˜@tU_ãkœó?! €i‰Ù¯ºxlH3ÚÝÿè¨éù{€üóÿçîxÍÚBÔÑñ5üùm7ªòo¾«`£˜óÈö<d{ Ú¾Ët/„7ÍEz~_9‘`+_M@ŸÊtºöð[äß&OH||S dÏoû® ÓüRÞ÷•@´=@·çüO·¢íM%Ê€N2•Àäü~‡˜ƒ4ÚÿùØCì9Ð%6XïöèÁñÓØº¿j ,Pà,ºCÛF@r~¿ƒðsFû¿)`Ÿ)èñshÏïã&`O˜ísøžhPBrÏ߀ƒ4Úÿ%°àèöÉÀ?S,6K=ã‡ú@à¶OGwq ùíá£àæ ö,8Â}rpÇÏ âè»1sþ9¬ÿ‡°pqÀœÑ'€™ƒ4sÎÀ‚€÷I`Ÿ`¯ÛùóϰàüßWá³ötÜg@þÍ¡9ROþdßÎþ€3à¶Ï”὎Ÿ«èá |¾ç`GôÀvï¡!ÐõFvó¤L e3À][hß >¾¸½Ç6ú{ìþþ,üˆÀíŒݸy¡9¾¸½˜>=î0óûÿ¥C‚¨³ã>L‘}FG@~¦g.,:v|iû¸!ë÷íN€ ôûaXxBº ŒÎ–,³ýœhÀ‡_ÚžÉÝùpÜë ƒ4Û4³`ixøñ¥íÍpÐ$ï÷Kº`:˜7ÄN˜V—··ýù‡_ÚÞ<™5bÿSÍ03€ì-Ñ›Ûׯnr«VÂ39’çågzÎk¸9«~žÙž^´=¼üúõð𤗵™O•úðàVx×óëèIvÞ·[·ŽJ—•è›Å]­åpåxgÖÝ/úÓƒP˜ÖT«Ã¹bW[ÃË©tX»½r¢'Àù]}j,t¦ ­óíËŽ5úïriÓŸž¤ßwaèÒñćìîE@ísû€øë·oþÉ•›·{H]Où‚‚Pe&íç™ÍÜí/6ð­AwÿÛPÀ• ¯ÿ–¯<Úñ„€oÝá“k!ôÉ äñMÀ„q¿Jpž{·»èOÐì*ÚUV‚¿FÑ¡ù‚ÌUW @ÝôìA°¦ÏFØú¿vÿV;?6lêûADÀÕ® {ß­—›ÅRD ⧃ƒè Àú¿s…rÎÅ!»úd×cÖ×Kí׬‘Ÿ§ lR\ÂÓ“vÕ‹©@_ÝDòˆ¥½0?À^<ÜÖ«Ív­ïÖÿx €q¿+} Z`œ¨ƒs6<‡Cvæ|òëÑõñzéýÚõ|äçÉæ]}ðÅu ;?ÀPŽ1åíyÀê”hW¯» "ÖAre€àÜ Ù)OÁgb=²~¼^j¿î[òí*€¾"øòK‡~õíö.d?õ é¢_L ê`«ý¯›÷auÖ^‡w­ƒœ³a» dg’Zÿ™X¬­—ܯ[Ïe÷æB‚/ÀƒÊ®€µ™ bí¶ò@¾¸vy¿Ž?à‚A ÛiLª¾Q[ÿ™X¬­—ܯ[ïá×ÃÃC×#üb«ÿ]HH‡|ÀùàzÐû8ðbجºv˜* Ž @¦¸ÞÀý¿‰šúÃÔÅ: B4»Úûi‡‚xh=º>^/½_»ÞÃKç^ ЇŸ®€n3AÄ Ø2 w ¨ËPø!  ÎÅ!;ôɮǬOÖKì×| ªuê›­úC-@§é0TûžžlU@Ð[Jþbxw€ªŽ5‰Û|Ð;Ô>œÑlÀB/a·€)®×Ô÷?ߨr0YÀ€¾€€\5Ôvn‚a`Ýà°—'_-°Ø&`ç| œŠíyHú? CõÒ})¸˜ü F‡ÙLàZPþ_®Mü-3$ !€ñ¦70 ЏV@&Ò—I7ÛI‘>)Ryßåþ/PxÐ/ä†^Ð s«nm ³N€ˆÎÿU ÈGúÒév;)Ò'E aìÏ“»¿]'0øÿzØ+„ñ 9¬ÿsãp X Dú’én;)Ò'E ÃLß„þ^‚ì@¹|»Õ…„~ @Šô%ÓÝvR¤OŠþêšøÚû/®#ؼL8þ“mÿƒå¨Ü`n4˜=€8$ÌÆÌè@/H‘¾dºÛNŠôI‘Bòwyú‹'¡ëxÑ…Àr ÝA^ïßt!ˆC‚% I÷І‡I‘¾tºÝNŠôI‘ à¥kضz=ä‡÷@#Ùÿ€aáý"}™t<â/L¥k{îvhÿÃØ ;L@ÚUÚá~Âå¥þ¾ZõÖ`FHÛÓ„,àf9ðрà ùyfó¡_ÛpO†¡±ä>ìZhz4v&ègñxÐ`;7/.èÁ¢‡E¡Ù§]ÿþ¾ZY×kçÛŠ¡ôûÿŸ|HXúö| ì„§tvP Pûß=êbc&8Å5ž¹ÝîVu°ð½}õÔ{ $½KãÏ¥¿þÉîKÒÃk³s͹öŽ^¥kב…“)õÕS“1Iz—ÆŸK}ÏîKÒÁL¸.Y¸-Ù­pq<0{µü]ríz/Kúœ¨!`3½°ëî¯Ã,v)ê°)ý‹³”'4•¾ãub· €ö¼õ¯þV“ ¨ë_ýêZ±þÕߨ®•¿ŒéoTçÎi Þ zÍëÄn ×vUÚLn)ûÜo :¸ß"@up¿E€êÜ9 Ôë¼¾»Û±:±ÛÀ–îö‡ü§}âC—’öÓipƒ«E¬; npµˆu§éºu°N£·y½½k³z}„´Uú¸Õ­à €î7@&é €î7`ÝÐÝàA!à ë~m¬Ó_ÆèuVoï6wL!Ÿ»ZéÎã»*[Ü&8‹§à,ž€³x @çKÀ`ÚzS§Ü*ÿn”‡Í-Ñug´Öuo›%©à¬«`|Éék¬S°NÀ:ýeŒ^gõ ¨=ÈLe S ¸) <ú3ð¿òïOH‡ÏûÀÿÊ¿÷±þø_ù÷1Ö¿üžö__b=þaœîÝÕ²º¯è/ŒîëúK.,|S@t, Œš™2  Öcb= Öã–Õk^wþ5Y£»V€Ë Çœuý@|,Òá3 Öcb= Öã–ÑMe€Óí¨ P]‚*©2 œW¿¯žš—_Ò»4ÞÁýõ»/I×yéNÖ½Çè2`wg›QúUL%ë¨ `*XGUS À:ýe9½Îê¶2Àèî¯ÍRÇ­ð‹°Ré±.ô:÷0ÞÁÒ:Ò¾ä£êq `Ë€ÖÖ˜Í'Îlê8°e@¨ã À–¡NYNoóº© 0:¬e*©ãV·ÀÎd“›:ë¬S°NÙ½ÎëÐ `÷›1®_Ò¥qŽÉöãÓ¹ãß1ß è"€(Hˆ"€"½õVÐë* LûÒ%A_ÚÔÿ˜l=`˜Î¿f¾Ð‚˜"‚˜"‚˜"`` è(ºý"DSvì˜F@× ð ®A\‚¸"`h èzשíâí:€V-p+€¸@‹Ü Àç5®Ö[A¯‰>À®€9¶Òz׃áL+ e× À¼Zm^z„Y½ë>¬pÌ« Yx¨‡=Â\ (è.ENE@Ø#LuÔ#Lô¨G¸püyuVsFG9@)ÜñçjózP`õ PAîø×ªó:j”@ЂZA¯‰>À®€yµÆê;¢0®_Ò¥qCŽÉ;xˆÎN­€ñzKô&uâï–O—Ö¦ßJwð}€]%a_ñg¦ßøZõAd5îùü±ýú‡ê0hP§,\¡1 Ø®V?ʶçõá•Íä U÷©S¸@fïàjõ€½;Ì5³WËß%W£·Œ^°w‡¹z0?€^0iv¯ÃÃÃ)j)j)Ý_´‰ô£Á÷Yòè¿=¯Ož`O. ž€êZq-eT׊k!(£:þ½魠׌>ÔÑ)›36ïÄóØ4ØÂÞþA#ñžêøÙAªãg©ŽïAz×Ãù¼>ÜÕ¼Í[BÒù ä´Ÿt~¬?’ù°þ…Ì€uú‹½Íëx~ªãùœÞ×Á’Í_Dó@&é €h~¬?’ù°þ…Ì€uú‹½ÎêÑü±Ïàôþ.ÎÛüˆˆˆˆ @4?@¤“ùÎÌPpt5 €/%} €u Ö)X§¿˜Ñë¬ÍëñüNäåŒÍÆOC:|ÆOÇzütp¬ÇOÇzüƒ9=ìÒat4?££ùRÇ=Ôf €ûÚÄ@:|ÆÄz @¬ÇÄzüƒ³zÍëáüŒŽçH÷P›-?‹€tøŒˆõ€XˆõøgtSàt<4”êñü|Ùs˜þ|~~{^>î 9ÁòSg“ :?€MoœNçÀ:ët~¬Ó_œÓë¬n+ŒŽ‡ƒ>²;u¬ñÇ9ÝyT*7PÙdCÇØôÆét<Öéx¬ÓñX§¿8§·yÝT=ú™.||ÄsG¥sƒE\¸2@gN§`€u Öé/£×yZF?S?<¤Ñ#פßW-]$`Ó§S°NÀ:ëôÄÆè­ ×~¦Ê¤e|w“~_µt ¦ÐéÓ¹" Ô¹" Ô¹" Ôé‰M£»'Dýæp ®h\Ú$Š€@g‹€@g‹€@§'6ÞÍúÍ­ZàV-p+€¸€;®Ö[A¯‰~ó̱Öë¼ôûVÀ­0¯V@›×ƒaVž ô­€[`^EÍÂC=ìæAáÓÁ¥p+Ì©{„©Žçˆõx~€R¸æUÔY=Ìå¥p+Ì+Ôæõ ÀêA ‚Ü ×ªó:j,J ¨ºº@P+è5Ño€yµÆê;¢;B, Ü õî;—6ÅücMú}ójŒ×[¢Ÿ©6}Äãšx´™µޝß:¡å^¤¤Í½\ø>¥;HþHékg=λ؉Mû~/Xºcfà׎w=¶”íû?¾üaì¯GJÁšØ´¿§Ø@«Ã7lÕt5íûGÀ,`]ûþ/À,`½pÁf§L´oX7fið¹¼XÜW, >09¿ö¹¯ |.@_ ¸(³S&†oUЯ[ërÿØ(èzá¾Ë̯º^ø£Ëˆ¿ —eÜœ™5ë? XÿBÀzà‚Œ›33L³y?ÖÃ4›÷c=L+\´I“5·‰–¤?&Z~žruAàBLšŒ™+´A:WhƒôÀ…[àÆMš›«hƒt®  Ò —m©ð/¤§Â¿ž ÿBzªÅWZ‚býK¥Cô/Ö!¢±é€ 7ˆÿ¥Ò!þëñ¿X‡ôÀ¥›ô•´|3Ц«<à‘oÚôR¸p“^¸ðSwþ°­›þEwþ°­›^¸p“^¨ òúûD+àÞµþH´þ(­€X‰Þ¸•@Ð[ ݸ•VÀ[iܸ•VÀ[)nÜJpãVŠ€·ºq+ ·ºq+­€·Ò ¸q+­€Û¶p.ûÏà;7ïýÔ:ó}îësõæ&ÒW|á¦j̶©õôKŠMkî:ë+Þ€ƒÌvÐÔøýŒžIDATzà\¶€·ë.ºÙ¤¬·ü]:µ^8§-àå«ÊÖÎô¢»K½¾²–Ô·ÖV)ýÝÚ2Ò ç4ï jþWUóÕž8°Ú®€ªÚR}½Üëõ’ê+ðÿûrµjB½pNƒ»3À¦GŒŽ :€ê¤Îh®„ÖNX¯¡äö:`µÂºvzÀv‹uíô€÷wÐ ç5ÈÀ I{=ë¬Sp!P8—nÜ 'øRô¬S°NÀµ€À¹ ³1Þé€XˆõH/œÙ :Fí¬Žˆõ€X€ôÀ™ âsᄞú;¤w:$Ö×kÈJõÕêÝÏY­¿Ç3ç'ßo_lZ;Ò Öݾ"æ_ØpÞéÔoÞŽôB Ö)ì  '7÷B…®v†_¸`ÊvµöÖÖµ¯¶ëu—Í/±nºV« ã÷/làÇ@Ú¹¯ÏÕ›{­Z×üë²ð}ðÚ5 Ö»æÖ»æûÚ¶Ó¿TéæÍuÛPðk×(X§`À¾¶­prsn ~í[D:ëöµm€“[X‹Š€¸¡Î¡ÎÌË› '·°q->.B+B+˜—7Nn®–ÎA-¾W+!.-¥8¿•"àÆ­7n¥¸q+ ·ºq+ 7Ü èüµú´Vᘀ¨•àÇxó­~@p"+ÝÁ7n®–N\‹—t mE`ó­€@±bÅŠ+V¬X±bÅŠ+V¬X±bÅŠ+V¬X±bÅŠ+V¬X±bÅŠ+V¬X±bÅŠ+V¬X±bÅŠ+V¬X±bÅŠ+V¬XÎþ+– nØG†IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksCE.png0000644000175000017500000002501213263214225021417 0ustar aeglosaeglos‰PNG  IHDR@á» æ$PLTE™™™™333ùÌÌÿnnnÿÿÝ™»»»dd4< IDATxœí1’ì6’†Óc(dIÖFÈ1ÖXO°2Æ”Ó~YãŸ]‹?ÒõÝð_éGî?þ»ÈÿA;r×—ì]–saÖó{ü}OöˆÕüF{Oã÷Cü«énrÿøgwùõá Àÿ³ÈwÁö÷®[n_°7·ˆa~ ;3ÌïÁúÏŸÚ{üö¯Ï4]wûˆÁè ‰»e–í7± ØÄR°Ëšö†ÿ<XžÌq±,r¹¿bÀ‰õüÑ9Ob@îÍ­Q ðd¹˜Û/÷—âxЇëù¥ìsûTO€9@wY XÀæ†ÜÝB¸ýBŒ·pd=¿ÙÎýÕŸ7.ÄÃüt€(Â-x¶#‡[j®}Ïý»ÿ^lß©ñ„(j ¬ûväžÆãöÃü ™n™Á~+$@·˜œ 'Œê¿&j¯ç—N€.‘žÙˆÈ À ÂÿFG Ä Æ ±-øßè(8AøÁÏœ¥[øÖ%"?ßMèù -kx)ø^ paÇÏ/1«@–—„bð3€'ÀƇº kúšØú À µç% —¹×´˜ñµ-84gç×¼Àœ]÷üÙ±žOš±½ž_ÊÞMKÀç^Ûf¯l?𯟟'@öCMéÃÍäà•ŽdǦG€˜õ|RÌíõüRöéC¾Ú«ñGü1ã?]‹­`̓ާkü±äRlýs¬5ûÏÁÈæñ !•Ù:Öì °Óggß|°€ÔO€öX»t}Wp]¾ü€þø­½Ëã¯ì«ñ‡}7–?ñü×Õø¯®¿®Æòoüÿ{5¶€5‹µ>ßš­åÙÖìõ¯P™­_ìÙ`§ÏÎþ%ð`ñ/•Ù:ÖìKÀNž=v:ðììB¶EËbKØü]htÐ¥Ø:Öìõ–äÓy¹vOÛº{ÚöÝGÛ¼ Û¶;Úæòò´}y>«æ¶…gõóÞ¹íûåõVÏÏ`½Þ¾(Ì8R}µó{J³VÉ«•´Š¤]òl£YÈÎ'‹\îÿ‰ùiØG€¥¨·/èûT_`õü<6jéž,¤åÔþ‰Ø3Á ßT#ãÓxܾ0Ÿuó yøCÉ·%!§ÖòíNÝ‹r°–~ÍväžÆãö=÷WóKµGy9ÎOh~ú/$@ôÚöÞ¡ƒï:øÞ¡Ü{°ß°CÌãwhjßt ý›ŽX=<¹ÑK€'À-Q€BÉÁ;tðƒuÿÁ®õÿƒýFvOh¼ÈNã74~³1 @D¸+ê€GòlÅá&«Y÷7Y°sû—ÇÏ÷O-ðÿïù×¥ˆäÖ°¦ &À`²#Gý¡¾@Â^ÿží¿f €1žå`‡oM€¨=Ôˆí[ ô(ÉúÓkÑì ¼<Û@¾ýéùůüÙS™89¤~ÿÕóó˜õôêCI^OŸç×è÷?7¿5’¦ÐW{5öú—y@ àXzýÚlýs¬5ûÏÁÈæñ !•Ù:Öì °Óggß|°€ÔO€öX»t}Wp]¾ü€þ°—k×f¯°Ñaß½>@ —¹\ÛëTfëX³×¶—k{}€Êlk¾ü[€õk˜5{ìtàÙÙ¿, þ%°2[Àš} ØéÀ³³'ÀNž}CÈÁ¶hYl ›¿ º[Àš½>€‘|[úˆaÛ·Ð6ïëù mC—ç—´ã±q5õûƒ‘¶}'ìÌz~ 4ʵOÚ=lôû: KÁN,Û'ù]I§ Òª¯”o÷)鎗âx&€Ä·ðó-^0ißÜ[É™OÍoi ÐNÙ‹úû|‰˜U ²-À›Ç/<\)’upË,a’HŸo?<‚cážlϱ½<þ}ù5084gç×¼àà¼<[•| ¢ËÔ%Ûëù¥ì<¾žßd_x |¥~ÀNÖó[Õ^Ío¶{ä +6È_Z(RîǤs{˜_µ×óõ¨¯öjìõ.ó€$À±ôúµÙúçXköŸƒ‘ÍâB*³u¬Ù`§Ïξ+ø`©Ÿí±véú®àº|ù%ýa/×®Í^`£Ã¾{}€.s¹¶×¨ÌÖ°f¯l/×öú•Ù:Ö|ù·ë×0köØéÀ³³ I”ž~ç±m ìYyŒ\Éþ¥ÛÒ§úžiý|Rر±^À+ë |ÙüÞƒHŠÄš"1ƒ|[DÈÎ'‹\îÿ‚ùMÒ°z|ý~ŽÒ3˜_YÊæ @rí§ƒ Û¹¿Ö&N'ñ'Ê·~)á„Î愊¬Qê`}KËvp§¤_µ{´×;¾§ùõ4¿žú÷4?<;8¡¯_¡®e¹w$ßnˆy|–S{:žû”»Ž¯÷P @]%ÿ¦Š!P_`¼œí4~C㿦¾ÀÓ!Zl9ß  ßÎô—,ìnó`çö‚ °]ÿ/Ûü•õV¯ìÑ3ƒ'€*AÏŸppÔþ…õ¾n~ïiyõêã×ëÉË;²w4Ÿ4cû9b=ýW¼–½²¾À×ÍÏ ­§_Q’¹j}/›ß»ÀÕ^½>€Àeƒ8–^¿6[ÿkÍþs0²y@|CHe¶€5{ìtàÙÙw, õ =Ö.]ß\—/¿ ?ìåÚµÙëltØwc¯ÐÂe.×öú•Ù:Öìõ€íåÚ^ 2[Àš/ÿ`ýfÍž;xvö/ ˆ ¬ÌÖ°f_v:ðìì °Óggßr°-Z[ÂæïB£ƒ.ÅÖ°f¯ åÓz5Ê·Óö¼\ûøòòç¶rY¿ºd?g}O€ƒë÷_=¿w-—þ:ùvJÚÕ“ôk«tŒ¥h%iÚÒ|&i[Rmj%WúýÒñò)íaÌyí`ùøúÀž³^Ž[ : Öo¹€Ãš³{…íÜŸÏîˆélá-g Ç  ¤V{b<~=n¯åÛ¶€¬ûväžÆãö=÷×Ç×'Ú'åï³:˜ëD¸€CÃ@ \N€†Ú£¼<•ÝbBp4œ0ºÿ=ÔðHÊÓdzG"¸ ƒrð Ö½C<ì:@ƒýFvOh¼ÈNã74~³˜t n‘Úɯrëàðž–„ç]íÈÜ¿ÄåñóýSÏÛõ÷ùg„U ²-À›Ç¿gû'ž<–ê¶ê÷?“Qûæ¶hßšÙg€œ|š_›‚ƒóòlu\{/`b ƒO2¶ËÙy|=¿ôŸ¿ï5P6è÷ñßàϱ®/°ª½š_©=¼^>^¡ß×kð“áCR‚¹=ÔHØ£öz~¥öúC¾Ú«±×¸ÌbÇÒë×fëŸc­ÙF6ˆo©ÌÖ°fO€<;û®àƒ¤~´Çڥ뻂ëòå—ô‡½\»6{}€ûnìõZ¸ÌåÚ^ 2[Àš½>°½\ÛëTfëXóå߬_ìÙ`§ÏÎþ%ð`ñ/•Ù:ÖìKÀNž=v:ðììB¶EËbKØü]htÐ¥Ø:ÖìõòÛ¾yuÄjÛv꘶®/Ù—·¡—¶¥Éüä“Û¾ïêðçÔøŠcåÖÍÏààúýWÏï]I¥HúÅRª’t åä1—ûøóÓÒ0¥ß_wtëÆ£Z7ñKæç ÕþqÀ¢òÙÀÝmÑá²ñ,á’6ñkæ÷tˆ¾Å·àÙ^ïxø®ÇvªÄL`ìßÓüzš_ܾÒ°§\ĕÉrjo?ÖÔ†˜å×Ú…Ú7]¾ÿšãáù8ùèxø†˜ÇÏžéˆÈ À ¢Õ¸){”`œÐàÁÔÿFó»Ñünôçßh~ñ3€ôÛná[oÁñø òr² õ;·/ð0þÂÝ£5¹[¶ï©/ªFâšAQ¨(’ß`uDÛ¸¦—`{ÿ¯˜ßÂkÒªã×ì¥×8¶›_¿£LœÖïu}¯àuóóÈ~()}¸ýþ >ä”>$}ÍüÞ®öjìõ.ó€$À±ôúµÙúçXköŸƒ‘ÍâB*³u¬Ù`§Ïξ+ø`©Ÿí±véú®àº|ù%ýa/×®Í^`£Ã¾{}€.s¹¶×¨ÌÖ°f¯l/×öú•Ù:Ö|ù·ë×0köØéÀ³³ +8³ˆN€A^ òíXN­oÉÚáõ-vìÓ‘¹§ñ¸}ÏýŸó˵×ó•õü$,úøxÒÓóñðz ^“ µŸäÛÙè‚ á„ÑÏ+ ÑKÀÕ ¥¿'ý~ÐRDäàᣣâã„Ø–P BT³òlÙ–á>Ù¹}Ëãçû¯I€a~!$¥¿'}þÆ% º…—¼yüü³*t‰˜«'À&ýþ' j¿aM_“[Ÿ¦˜äÔý,ßN˳ŸKBO%^z*“el–³óøS‚fÿü™{½„=YÏgbõ(‡Ôï¿z~žÛõûžK±vpй½N€5ãë(µÇ‡ØB諽{}Ë<  p,½~m¶þ9Öšýç`dó€ø†ÊlköØéÀ³³ï >X@ê'@{¬]º¾+¸._~ @ØËµk³×Øè°ïÆ^ …Ë\®íõ*³u¬ÙëÛ˵½>@e¶€5_þ-Àú5Ìš=v:ðìì_ÿX™­`;ìtàÙÙ`§Ïξ!ä`[´,¶„Íß…F]Š­`Í^@f¡É©YX¡¥\2H«Jö¼\[o; Â’“'Y CH>Þ“¼(àÑ‚íÉ"Lš•ü!çÓêÞ»ÖÿöÙq<¡ñ";'€`ÀK\–_çû÷‚öp—F;2÷/qyüÂPJ€¢üúží?6GFù·À3ع?ÔHØ‹ãópñˆ¶eM_‘­ µ‡ú±}uÌri”S‡æì,¿Î˳?!ß~õüÊÄC¿ÿêùydõôìà’þž\j¿N¿ÿêù½ \íÕØë\æ1H€céõk³õϱÖì?#›Ä7„TfëX³'ÀNž}WðÁR?ÚcíÒõ]ÁuùòKúÃ^®]›½>ÀF‡}7öú-\ærm¯P™­`Í^Ø^®íõ*³u¬ùòoÖ¯aÖì °Óggÿx°€ø—ÀÊlkö%`§ÏΞ;xvö !Û¢e±%lþ.4:èRlköú2 %ríCÈ·s,©£i˜žX CVèñÅD¿ŸæA·BÌÂRûéàÈË'Àj=½…~?Ã7% ›X vâéèØ§nêòí ÷)Vóëi¼C¬Ñã›è÷s¬¤_¹(µ÷PK@B¯ ý~š"Æ%àÑç¾Èãüž·ÄŽnÉB·p¡%@è–,$ߺ¥§Ú÷Üäåq{\2z˜Ÿ–~Æ%¤‡ùÁѱ’Ð×7(ß~0Š?;{ööoˆyüíBí›.ßM4Ô¯÷€õòÛ ''Ù£ㄽ?Þ:,01>3ÜÈ~#{7'Àp—Õtph„vdî_âòø{û¯˜_H€›`€V,Ñ-œûë§ìÅñóK̪䨿'&ÞRyÍÅÁC]®=è÷c{yü|ûa¶Ä˜@;3µK@Z^Ý‘¼ƒO3¶ÏÙyüÀüŸ?ó£qG¬ç“fl?%À¡õûiº“=(´ž>¼<˜`n¯ eÚ«(¶nã·MçöS諽{}Ë<  p,½~m¶þ9Öšýç`dó€ø†ÊlköØéÀ³³ï >X@ê'@{¬]º¾+¸._~ @ØËµk³×Øè°ïÆ^ …Ë\®íõ*³u¬ÙëÛ˵½>@e¶€5_þ-Àú5Ìš=v:ðìì_ÿX™­`;ìtàÙÙ`§Ïξ!ä`[´,¶„Íß…F]Š­`Í^@žšŠyuàŽ8¶/ȵ“Ò,”nõ=Kµˆ•C#7_²ççÓécã‚0„NâŒôô{CR,fVî”Ú³²‡Ž‚Ûìézžëõô[øèõðàÈ ´By5ó,ôö%–˜{²3ÇãÉ"—û'X'è÷•TìÉB\Öß…~ÿUóSÇÇ_>‚\n騭”€ Ûôú+N¶sÿæ†L§‰ÓóKüùé³…n™|KÖòíô-v¾æxx`*I%éï)!8N˜òm–{GòífyäßMá™"y|½'@A>½å!åàEù7U úkäål§ñ?]_àépSlB¾ý¢ùMKÖRõ÷d?S}ý à ÖÏ—õ÷ùöG¯/@ÏG¢‚ü:88/Ï>¼|Z"žòð!€%=½–oÚ½¾½zˆÄúùHOO °ØþèõàCºÚ«±×¸ÌbÇÒë×fëŸc­ÙF6ˆo©ÌÖ°fO€<;û®àƒ¤~´Çڥ뻂ëòå—ô‡½\»6{}€ûnìõZ¸ÌåÚ^ 2[Àš½>°½\ÛëTfëXóå߬_ìÙ`§ÏÎþ%ð`ñ/•Ù:ÖìKÀNž=v:ðììB¶EËbKØü]htÐ¥Ø:ÖìõdØNÝ‘|»#iX’•Т#yvIÅRö„\;7jÉË糃Qø¡·Qg”=z›w®}ÁnS_ÀààúýWÏoJ<…S“°â©¦š„i~¥|;ˆ·€ÕüB%ŽÇ“˜§ú :XK©²Ìí—ûKq¼™AÛXÍ/i˜Û§ú{LzyÔÖ=ÚÜäÛæ’2Bãqû¤^½6QØÎýõqô‚r÷q|ùUÉÃQ¾­¥U³o©qûžûƒ¼X@ê'@{¬]º¾+¸._~ @ØËµk³×Øè°ïÆ^ …Ë\®íõ*³u¬ÙëÛ˵½>@e¶€5_þ-Àú5Ìš=v:ðìì_ÿX™­`;ìtàÙÙ`§Ïξ!ä`[´,¶„Íß…F]Š­`Í^@¦-ÖÛŽ_Oý*À|´kÄJ¨‘>*¶d_žÏªù)iXZ?Ÿæ”¾_T_`ýü<®ßõü¡„HÐKµŠ—äÚ}Š'ᇀÔ+Çñx²ÈåþŸ˜ß3àlÝúû¤¾ÿ@õÖÏÏ`–W³œzçÙÀ,Ä£¬-ìˆYœºQ‹¸n~Ï[â ¯Vò픜úLÇçJØàüúY–I€† *Ð ’\c;²ÓšÞ,¯ñw^ÛÂ3Eòxø™%’§wžS$Ô· éï9 ¥ˆÈ À BãEöâC&´¿ÑünÔÿ"Â[Å‘<[ñ:ù·¡¼œìBýC¥ˆäÖ;‡ú¿²¾€Ü\°ÿ\3È`ul×ÿÛÕX?¿á¡¨‡È˳—åßG’—¯>¾>ÈÃu¬c¦ž@ÍúëÙ ›‹zý„¾ÿPõVÏïqKTW{5öú—y@ àXzýÚlýs¬5ûÏÁÈæñ !•Ù:Öì °Óggß|°€ÔO€öX»t}Wp]¾ü€þ°—k×f¯°Ñaß½>@ —¹\ÛëTfëX³×¶—k{}€Êlk¾ü[€õk˜5{ìtàÙÙ¿, þ%°2[Àš} ØéÀ³³'ÀNž}CÈÁ¶hYl ›¿ º[Àš½>€L[ÀkɷÖmæyÛwGÛ¼3 ¼\ò¯Irýþ«çç ppýþ«ç7¼ÍW{5öú—y@ àXzýÚlýs¬5ûÏÁÈæñ !•Ù:Öì °Óggß|°€ÔO€öX»t}Wp]¾ü€þ°—k×f¯°Ñaß½>@ —¹\ÛëTfëX³×¶—k{}€Êlk¾ü[€õk˜5{ìtàÙÙ¿, þ%°2[Àš} ØéÀ³³'ÀNž}CÈÁ¶hYl ›¿ º[Àš½>€$åÚÒKÄó¶ê‘{²G@ —¹\ÛëTfëX³×¶—k{}€Êlk¾ü[€õk˜5{ìtàÙÙ¿D •IDAT, þ%°2[Àš} ØéÀ³³'ÀNž}CÈÁ¶hYl ›¿ º[Àš½>€(ùô,Ïå×ȱ}Y®ý%òíWÍOÔѱA/¯õù)=}Áþýþkæ7èVºIpñ¨$Äøœ~ÿEó¹)i˜‡µ „³}#F¾ý¢ùMrx¨°¬¯â²þþ+ôû¯š_ŠyÌzy­ßåð ¯oؾ¬×ÿýþkæ7PH€œœº'ÖòíT{”—£|[H¾-Ô_H¾-ê–žkßs—Çíáøú^%@Ð˳þ^ëóïJê5éïIoú%ß~2Ö訾€’o‡þ 1ß¡]¨}Óåû{èúyÒÛký~Jßþë  ~ ØAÿú}X°Óx‘Æoh|ª/p›OÞ$Ã-t½ü:!·~Ÿÿ¾'Öýõ-|²sû—Ç_Ñ’‡‹rðZù5Ùµœ[Hn®—€ÉŽõ×õRöâø÷lO€Dl×ß/µÇ iÐ Ù^ÕHÙËãçÛ³à%òíÔññ}ë_ÿh¼õ5ÐF¿ÿšù 0Uñørý¾P½øP“an¯ eÚ«ùÛ4ž>髽{}Ë<  p,½~m¶þ9Öšýç`dó€ø†ÊlköØéÀ³³ï >X@ê'@{¬]º¾+¸._~ @ØËµk³×Øè°ïÆ^ …Ë\®íõ*³u¬ÙëÛ˵½>@e¶€5_þ-Àú5Ìš=v:ðìì_ÿX™­`;ìtàÙÙ`§Ïξ!ä`[´,¶„Íß…F]Š­`Í^@&¹ô¼­zdk§xÚ¶ìÈ]_²'äÚû˜a~=Í'Åz~=ýùýs~Ïú üý|žµ~–[/´/Ø;ÐÞ`[zÆÎ óë@»¨Ú{(½¼Ú÷¯–cÙØ~ W«/0ÜŸáTòí^I©rË­e‘Ëý5KÌ0?¡ñbŽÇ“˜§ú:´~~‰¹ýr)ŽWà—ÌÏ`ÒËkýþÀ¤§gÖúý;b¡ñ¸}R¯ÿd}:ø“a~ZÍœa˜Ÿ>M|_~W·ØŽnÁ³YË·Sí{î¯äÛ©ö/9~¡}¤aO½¼Öï?Xë÷Gû Xë÷Ç ý}‡v¡öM·ÐRïÎ óÖðŽì7ìßóøáàò p§‡¬ ŸGýÿMë÷iMíX_ ¶ÓøT_`èCÏòî‘u¨2ÙodÇñ„ƛšÏÛgpð¡äÛ¯ž_‡C€‚~9Ò×+ý~ÒNÏö¯W_À`ÒË£ƒÕzzÕ^é÷Sö¨}4~¾}½úÃkÑó‘IɵӌòêÉ¡{Çí•|;e7‘—‡ããE­Á+äÛkÚkùv¡}½úž«ÈúzN€´þ>Ÿ‹í«Õ^‹æ«½{}Ë<  p,½~m¶þ9Öšýç`dó€ø†ÊlköØéÀ³³ï >X@ê'@{¬]º¾+¸._~ @ØËµk³×Øè°ïÆ^ …Ë\®íõ*³u¬ÙëÛ˵½>@e¶€5_þ-Àú5Ìš=v:ðìì_ÿX™­`;ìtàÙÙ`§Ïξ!ä`[´,¶„Íß…F]Š­`Í^àñ¿o?ßD~>þ®øçãŸ-ñÐAÛ‘ß~–ìoY~ ͬç÷øûŸdXÍo´ÿ¤ñÄ¡?Þ}ù;ˆ/~üeyt~{û{±ý²]óc*«ù%íÄz~#Ͼnï ðÛ¿ß|x(8x`å° O^Ù~5SaVóKÚcž`©ýûèÿ(ÿœ<žçŸË"—û+¦¬ç÷Sp¼ÇãIŠÇÌ 0ðÇ_–Yd™¡ý‡µ4ÞÌc‰u‚¦ì‹,óOH€°8€¿¼aÀßÞ–âñ¯ðêûAXÍo˜Ú™a~?Æã‘ED'€Pè[ðhGÖ·ÔTûŸÜÿíÿÛ¿Ñ-šoá¼ÄK/ |ËO.2ˆà‡ºEv `œ/$DjüLÿ¡©J ù'š`{5¿gÿ_ˆy|õ à (ÀÅ€Kt‡ˆh18 ¥PóË$'Ž=p”ná[—ˆxü|ÿ5  ç'´¬áçø ²´$”€–Ç€ëžV&€ˆ¬pÞNÏžË lÚ¾"8à[ nÏKÀB¤^ÓbÆ×6íД_ótSvX2~Òñ“–œ$c{|(Œíoz x¾†½mxmƒXÓ^'@¹ý[Šß vÍ4¿l{Oõ¡æéàunÔ¿ak>©(µH\J€¨?%@nüñ–8]íÕØë\æ1H€céõk³õϱÖì?#›Ä7„TfëX³'ÀNž}WðÁR?ÚcíÒõ]ÁuùòKúÃ^®]›½>ÀF‡}7öú-\ærm¯P™­`Í^Ø^®íõ*³u¬ùòoÖ¯aÖì °Óggÿx°€ø—ÀÊlkö%`§ÏΞ;xvö !Û¢e±%lþ.4:èRlköúÃ߬Rá6í·ˆAømóN0lÛ~£mÞ(/OÛ—ç³r~ãáÑ úùg¶‰¦¾À–ùy¬ÖÛ…G©/°i~O‡<£<9H(@$Õ"i×ÀZºÅR¯ÇãÉ"—ûj~OeÉ«Kúû¤´ë@õ6ÌÏ`Ò׳ž>«×b³Òî±Ø3Á ßF5r_piýôüV%ˆH˯óòê±92¾G²²ìWq…u¿NIÿOÝ×@åáoñ©šºv>>ö.wéº=ë÷3 O¾ÀºkŒî¿¥P‡R¨´¹óRÙ?ËIý’Î@\þv~€ è· $Ý-רèÈÔ ²l‡ñ1ŒÙ[—¶ß,ºF峞»Õˆ¶°‘yþf¿(ði!¾ XÀ&àtÝ’kìH‰–býÁ¨ßvÈëÑz‰ú}¦sõK`l\þf¿°$7c`òfHÀén ר%p%‰êÙ.ad©”X/¸6éägôõûLçê·€*¯ëð7û¶é«f $ßh€”ÎÌ5†ð\î«\ê ˆÏ(6Õ^]×¥Îdÿ,çë· €ÆÐç>¾­Z5ï!¹èÛ¤sçpPÀtà¸Úöÿ:#…*‚m"@¥Âeo¿®ƒº~Ÿç|ýÖ€õw>P>埒zGé&¥ñÀaÆq¯rì)Tî#x€~3uá½=ËTì¯@· Û`%®v¾mç·7úm4ÔÔÚ6Ý´ôtŒ*Áæõc@>îyŽøiϲ©ú}–Sõ[ 1°óm[D1ù-@ÎáQÂP)t –ʇmæ¾e›cæäœ`$NLcᬔ¦¯«ê·LW;¿®gL1ù-@ÎyÇó€Ä)n)ÀFÀqo¿ß̼@Mƒð†›>SÌa‘ERhHÄo«4.ñjPͺÔ'`.ƒ%`% @L#}€*{Så…4 2@h°4$â7a€U—"^ :úݼHs @oé@ú' Ûl76¯%€Æ%d ë0@"~X¥qá)¨_ ^¬—’âÞ^QÁkÓï¦-}€†¬–‚ù{ÉQ†rÊÎ: Q áÚ€Vi\Ú«AÏ"!À\KŠ¥Xν–>`ß-‡±ÆÀÃHPë¬Ó…®õ °Jã’X :D2B€¹ ‘«½¥,°“Ðà$Î ,˜x¾D!R®¨o‹žM`•$Ø^ ö#Ìeˆ¤Øo^.c2s)}€ SAhÕoµr#J¿ ¬’[«ÁpÔÉh"e8¹¬¾ZÆÝ’.¥¨}%It«Eû°~‘‚i =›0À*I°µ GÝ:€¹ ?YÊ=ÆÐë‚!JíhÑ>¬_¤`ZCÏ& °JŒWƒB„õu¿x±d5˜}Ó„„ %,º…jä°~‘‚i =›0À*I0^ D PgJPëxûΗf‰pñ!`'— ¾2ÎKÔ/R0­¡gx¸[ýþGv‘‚éIÜ“)˜¶nëæ~¯Ü·ôì~¿NÆ_Þ'¯Uya‚×aþû×atÿmº>¿¢kígÈ‚ú|ÂD?(GoaIŠ.H`cÂôGQþ8>YŸ_Óµö3t‚&y}‚‰Œ}øzH`Dñ&æ¤üàõ0Ê?ŒòÇñ'©ú´ôQ¸‹´è8ÕÀîaN šx?Ã+Ý$ŸŽ¾ÏP²2ö'QÇ›vX’2FÇ£üÃ(ÿ}¢>mýD6{$-CÆ­¦û䯇CLcÒψӫ¤mÒéΤٴ†ÃÍIËl†˜ÏIIÛÚÏà_hdH pyyä¸û/玠‚Ÿ¢°Kšµ2Püwkò·*Ìe†ëý0nöHZ†hÍúÞý ö3\º½Á|Òœ²ƒxÛà‡A˜ð“ÎpHñ‡:¬òÛ`/åé0W"\ïáh³GÒ2ÄÆ‚E 4÷©Ñw÷Àåk ÀðTÅ›O®ú&üd\’#Œ?ÕaŸÿÍ ÀiTžK6!*möPM¬–ŽZv …ø›KàÓq#€ñš.n2PˆAc¼jsŸÿ ”¬ã}yA}²¶~B‡‘õx‡ýÈ.ÀìàX eÇðˆ÷Q¸|ýJð‰R¼b€7 b¾É1^±€Ëÿ3}¼*ïT×'kë't aúA ÚdDhÙ1<âoŒðéP½Û6þüO‰w²žqþ÷{œ NaþS|›QùoîývÇ畧˜8^ï«01ÓCadp#‚2‘Œà,ÉþÝÐg¡iÿóͽ "óÜGUaÌ| Ã&"%Ùýž8gx¢â]y:Œ©cý„ ìùa?² øIÁM"+(`Þe>{°Ï~œ&¿Ï”¬§+ = ‡ €#Ø rï@$;¯ˆ‚x)O‡³5@  Õ°šè¡Ûµ”À’üÊ€}öˆè·HœdZÔQ¶ÍuŒÃ€¥Ì1€ä`^W‚Æ÷„ñöÑÇ(¼`¡?¥6Z.p¸]K),M¾ÐxôÈ‘àBÍuH’›ý¯×ÔÂßBãmy¥u`Ã˼—PË?+\¹©CTÕiŸý‡Ø€n*gÁ嘚ë˜$I?Ñ¿9b¨?Åñ‰­u€Ñe ;} ®üÔ¡f ‘‰—ÑŸIEpáæúx˜ErUR°ø—Žÿ‡HÐÂä+Vƒ·ðsÞžø‹X,¸Â¤iU3Uå»hÚ ˆéÏРõI𠦋aæàRh 6ü‚ù¥ãøúKWƒ´ž+‚ýJ,¸¢4 ª™‚ZàŸvp„Gf8Åa;Öà¨0M[Üâ¶¹NA¸¿ £ý4«›¸ã©ø¸|J®kð-í‰? ®Œb€€£ 2ì"AŽŽïS&Áå“o.”õÃh-™¥¨ø¸|N¬k0³ÀÜ·¨b ®Œf€h¿Àåá5íÐ$ÿgõ”ÇDM, ð‘RÅ{h 6 ³% Vƒ¡5XX@ºÇ²Õ`­v›ûü¼û û431@Kƒ£Ãjm@r2ÊþAtKÐI ããò9ù kpW["“«AÍG}Ôóö‘×ÈRƒ¯ÔØ|ren Qñý18 ŽO–¿Ú|[´-ÇѬ2@ÀQU tR`Ä›åa^&Q‘Ÿ€OAô_“éý3ŽO–¿ÚÜ-ږ ŽÒ‚‡åàïM¬Ái…E´õ‹Æ ÞFÇåGÉ×¼ŸÓ¯±ß¶-Ç!õšO†58‰ð¡,ndј…ñ'­ò£äkÞÏé×Xƒ»mËq@È!G½^˜]†ááš°É‹Æ,Êß.?J¾îýYÂýýÖà€ƒþ6€Òà$üh̲ìSý‡Tz—|ÍûO²„ûû­Á«ö?lÝoÑíâÖ×þh}ʯÓíò‘—ß*B¿ °ëWS£Øžþ6ˆ†UlÙß[öøÝ0èfU:½s*žÎ¦á)UÙIDöá*ñ~$øÊ‡÷³ˆÀEdOÏIåÜ ŠÓ÷›–=> ú…™I§wÎÇóÙ4¤-¡*`;°‹»pûý¶þĸ|!·9ðûÿÚÓûͨ4Q> ãÿÔ²¿Çá ¿¿n “%ZË~ïIsñr6 iŽÉìãÅ.\µÞg4®+>‹0î{“lW'Ø›/{z^OnBË$ˆÓÛ‚ã°Îß÷× d²DkÙï=iïΦM¸m8fõ¿‹÷váøýî\-•Ö0ŸËõ Ÿ7#mO‡„±}=ˆÒÇñq8w»ë©êU"½&ンimÃñ°óÂÇSxiù»ÆXØÿª¿7o7*ÁÞw½{{zÒJOñq8WÁÌï|§_-û½ ‘³ÊÞ&Ÿñäòß«øœíÂ’?¨?è×ökœʪ7¯¡û\ÃiÞ‡£§ý:$ ¯ãôèÖ„ÛÐmr*lîìWDPÅ÷‰\þ þÙ9khÜ+ûïöåœ<*Læä(¦ÿL°CºSaËpg¿ôr<Éââ{Ä:¿¯? uYÙªÏzùÍì ÁgA…Éœ¼8ýÀcx´ýœ \ À¸çÎ~%˜õ €~CégÄ1n€)á®öš›³ÃÑ×f qøqcˆÌj¦Eé&µ˜Âćñ”Ãó÷1²? j®ñôú쬹©š$Át?@iVÒJOš"ЇkˆF™J_:R¢Sa1c¼¼ÅMj • ×@ü§'9Ç$ë ÜX¦ÿ—ß½¬B¦ž`®XÀ´\žÊ Ëb]˜‚d*}áH‰©Š ãzr4© @Ï69ÄÏ8}Y ]_ ùï,û³€+,ä~Åâqµ‚ JzÐ.\;y/}ÿÀf`úRŽ&%êsm›Úq}¯‘^š°þF0‚“:€iH°»Àr+p ÀÏ{aSñ£‰.C¦ gG“õ¹‚ES^…à+´ Ï6Àµˆ ®ä’8À‰MJRcÅ9ß7 ËŸ&𫽰üYoo/×PJ [h-Ü׎`\íLW@]àšZ$=Í­ÀòÌZ¬ãTÀÀ±}6@­ƒò_V€½÷úý˜Ãt½Æ;—¾‡,P.`þ/¿³ÑW$[Ç¢k{šSóv2ÐéN‘(ý8Õp ×.Îã# (‚hµákl;_ßkd—©úò48Å>ÞkZ-’œöÔ¼ ¯Û¾%7ÌR³®áÚå_YY@·(­mØvz[aŸTù|–ª/ B}@d¿®çíIÉzÞ^ö}2 še¤‹aþʽ SAþ<.ÀIX hQ·8®UùÐ;æÓT}YÞãQµÝ")9@ÏÛ:,c„¾V&@4Ëp<ÒîUS—?~ †Y Í= À»ËE¢þ´êóï$+ß" 9 ˜·uXV‡ŠRƒf<Ëp¬vG­iË.Üò8 îJ˜eô(Ï´N]~—Þ¯6i9lY` ‡t‹:Xü ‚4Ÿ5íúƒB¤ßàþí …r@*4t|ä €Î?O@B✠õ¾F"¦Ÿ§89dL›¸‡ rF\Ô¨˜O] *Ó¹(BsëË(ÅbN¼Õ??x_Yz¯òJ¾¯»êO:ò¶ç/_ åÎ/nâpk¿@øýÉ ¿W€†Ôù| ˜õöÿ8>^}%”¨\òFa̯ìùɰ+ߘך4qÑ÷ Êþž@hÉÙ€¢{½û{†œ]a€‰4© Ûbðû|C§ Z´-5a…—ì(Ü͵€d§ÂWÀK¯¯… Òàq¸Åñeìm“Ð Z0hжԄ„ñ­ï lÀ„$; ㎅OˆÔ‚®Áãp‹bÚ,€Ø)Á ÀKiµxÎËü=M¨Q²saܳ2唥Ÿ¦° ©E—3@ë:þ è$xCçä¶ß,À[^ÒèøIëžuTU@ol´¬#özÙñçÛ[t´H°€Nò‚ ¯—s@$êÆö~?jÝÓ€®ß—y!*àé•ÅDìõ"ó \‘f€Ö÷b¿O°Îµ$;7ê·ìýc R1@¹5kÐP åø×@0ÛëEæ/à~“d€Ö÷b¿Oð@&jÔom`د QŠï[³ÊmáU¹”bªØëEæ—6Ä-eäAP¡¹ ¾G Y€*Ô÷ ÀHÏóUšË-îJ#””~Z³J—Y@Øâ‰`±×ž¦¨ ±EÝ܉¢>&óeÖþf Rß'x Á¬`+˜ËÏ ìY`Á¬‘1 àÊó2Ûë OSÔ†­òR¡ð{š€ðû`Úïs1—×" kв1 °ç³]¶–q â™`±×ë5@B²Tô‹F(üb†¨Ô÷ 6À‡µýü%md¤ø7-ºú¤hÛ߉dS£½>Z¤Õ èï(¨ý}‚µ,·ß—Uîí÷´ý>.¤m'‰L–µøÐ V‹àU^R#Äs±"PgOů`…ý Ð.~'m¿ ‰íùÜ:}™È8ÿDìõÁ o——Ô1Æš@•=/.´3äYëª>m?vööø´ýžjé IØß» C —[\)<á=ª¼”FH0ѪìÉx×àš~˜TVÙïíÝ_k¿÷Q­üòì–*7ñI'Î^ïe~u„*/ñ>ùþ@H ÏžŽˆj•ýd°µö{ÕÊïìïÀÂ']8{½’ù}³«òïÛ}öt<»oÝoÞ=æý±uw¹Çxg›žnÙ×FØchª(ý#![ww#÷¯LÐskŠV)JÜe§§µïSð“~‰iÚú8ÕŲüãs@|BÆ–fÅ.Á$ÞðPû>[þ˜ÉSJ7x[Ávw @S?>D÷!€»…Z(€c‡îÒèþ€‡Ú÷‰jÐÐð:†MÓ HBIäv­Rzlð €ô€Cû¸fZbs º?à¡ö}¢º©Ç/Õê —¿ƒ¹¹˜×1Îו\²:zÀÝÒÕ²žèÔ¢ûœz¢Ð²FR•À^ÓzŠ„ZN˜›¦iðèàéïå¤_)ùn]Ç…ºšÀß`3Ì›…WOhÙ?#©J`Wôü"¬©zƒ‹q€Ç梇ÜÔÒ“ñ‰B³@á(ªûúWÅ\´¾Ö²†œJ`WT9‡°šÅ—æ€wúÝöé9HÃtûxO³@gŠ82Cãf¿Wî׿Zײ†œJ`WX¨€¦P|i¸±/¾!zf¦a“”m¹f €¿?`oná‘xË tœ¤`,„¥T*üFzÕLŠ/Ív _ßPÕnL#–§Á ¿^_$ð÷äMÜàvˆøY¥©ë¤PâÂ¥·M|i0U@ MÎ ¥ð÷XäôÁI·C$Ü3”’v´ÝÉP›'à«&”fpU ±‚Ï €–fÙýí“Ì 9 ÓZ¥Õ|à+ƒ<‚ÖŒ§Ì¯%pEË#‡§ÿu¯ùs•¼? ÅÎø™§4 ϰj€¾æšzÞ#~-°WC4.ŒŸÏð}b?@Š#øUMä ÜäØ2ÚpöÖ0%~“Àß¿LØ/PG{†V@|i£ãÓp€ ó¼ÖéBX€—‰.¾? ¸3d¤œ…¿4f< À¡P ÃbCÆm ‹cºn^àûxôõ‚•½?¯¯Ð“̹ (4NZä–— ø¢}͸ûÂY@Ýï"Sá‡ðe8¥T€–:€þÜŽfEý’Íúþ€HŠîð³‚?€/´La²pñ“Y±¦gŠZÖ²úþ…€øþ€2~(Í( Ó2e ¶Ó²p_Q÷\•û+ï(Rá‡ðØ‹¡kZ_Ób(ào¶½êZŒ•êþ€^¿Y}Ÿßíÿà±9è­ ÛCУ²HŒ•þþÜsк?íý„Hòþ€‡ðØô‡æb› ðÛ®ÖÜÛûÛöÿ‡ðØôø/qõôofa€µ÷Äöþ„ýÿA<6 =îm Øñ·¹œ•·æþ€ØÞŸ°ÿ?€Gç€]êÞäXV„› º€(ÈVßв÷'ìÿ+ˆ òÎHOÄŸE´ âoŠ;ÖÝв÷'ìÿ«\¼ÃãÑ9 ¢'S¤¨$s]÷G½? Þáñø Ç¶÷·y0z=æýñÇç€=M €å’P딩_¹ëàíùðÿ›ÿ³NxÏ>Å?ÑÙô·¡ÂËÙ³Ÿ Ɉ+È?på­rPÞãÑó`ש#ú ÿ 3.à¿|œÒ>›\q€È€,¢’ñ¦*(c1À€¿qå­p](ﱩz€ë¾Y嬀ÿdÔöÙ‡ˆ3VÌ@ZÇ.!Ÿ½(cA–ƒºÄˆN•<¦æ–÷øtmì,ÃzÿeÁcÎiDéX0[WϡޤýµþyMÇDw]1@õÛUïëbyOׯި±+(ø_Ï,Õö¿°cÀR<‚Íø%àÔãÀN3;¯¡ç—gSG ½u¥~ð Gå}a"W9@ܸ0Ã>@ V/:ðãæz%g¾—@Uœ]0@ò,N7S(–çò¾}kå]ÀŽ…þ› ‚Ô`;È—Uþ®Ò_õ8¯Õº¿ÂŽ#ì»Ò£°”÷Œ\'è‘n!b<¨¥ÁàKÁùҧŒÄwåEáçÇØû}H¦Á ¨¶íÝ»Ü`æ|\V¦ ˜½…NN ê38ZcýY€:î n÷Ù1@$¸È4ˆ]×öîÛ`76k -VZHHÀ1`§)ìðhRApzÀrw€ÃÏŽ"ÁÅMƒø÷ä€úƦ0Ó¢¼ÐMg‡I–Îyú7x¤q‡ÕX ë¹1@$¸Ð4ØÔ|R½þÙ¦@@L£ÚŽg³«Hm†²b€ÆH ¢÷tžDƒ Lƒ¢#¶,<,p3`9€t I’$Håubq‡žï<;ˆA™åÃæßØƒ^ÌŒšo’xˆ  åËëô#q‡žóì`¹ûûÎUìäWö­{l÷oôão³ìÿþžÂÿËŸ?þöòþÓu(|wÊ>ÇÿÂáLüM自¸WHÉÝ Pnÿrøž?²~wbîéÛ¨~Æß%¿+ÇÉâ_‹zDClX=ÃÓP­}ëûh pd«O_¾¾ã¯À ÍôuÜŽáçFÇÿ2”ü®7ﳿk* >1E#ß%<ýø`~„ÏÛþ2Ìîï?€;üÞíð’¾²;4?;Ð7:æŸSzþCWŽ“'Ø¿1¬Ak"p‹*\c<,aÇ?³Ë»Wf[øNpi9»c†øÓ[ã-{`øûPŽ“'È· 0G"¯*”£êÅ€×OM¿ÀöÑVÜ"aÇ÷‡Cõ~Â>š£Ó{ËÀú6ý1òºÍú‡W8†?±> òù7´žnd-€¬,£Bù< ?—‡8<<9½¿;ü–F½;$Ð ï:—ÇH·ùé·)³SóÃÑ …m¸$¿U~5 ú:êˆT'ÅsàîÈ`Bƒo~wî¨ ÜÙ†=½?Âàáð„ú:~9 “1àÕùqù‹’î}¾njY ARÓβøý=¢ðo¯»KKIDATÒoü#0&¼:=bðøÇ~ÁÍ[Èd ÀOˆ¿Â1 ˜¯y–Lƒ8ø   ì4Ï€cì»–ƒ¡—ƒ€céþ :¿à`hÇ¿# ›N¤ÏCÖ†’ÿ‡!ÆãNƒ»Ì2 Ú|k±‰áä‹8ׇmõ½€s$óüïm»šáé!†?þâú|&½Çççç2 ò2øšÌzDXo8ù2Î\RŸ¦ùÿ(ò±¯w.mß04$œHzÈ !Ì?ôÓ ,ƒw5/ŽE%F °Þpòe ^G'$؈€ã:wÖ£ðÐ¥Ï@dÆùáy¼ þPóâ¸v fÔtž‡Yä/Dð >,àxýGð(ümözYï­4 á;ÿœÜÚeðÎó2‹lìbBÿÿ»ë¢8xê:<¥»†éÉ"ðÁJlƒ ¯Ó‹ŸeÞFoâÖïj¿Çp§@°¾Çð6 *÷è`ñÁþ±áÄKùOH9¹ÝâÀJfÅâ™'´LmFtøPÂ…ør>NŒp“€ñϱP 7Y÷¦jŒ·Ã½ èlßàé£ ¾M7UB n€€aP®ÏÈ>ñKŠÙµ-.pƒõ=„íóì㣠öŸC¸^Ø?%Ù Ÿ^¼9‡1à¶0œ9ü¦!ÿûV˜3yäÌù­cvrŸ9Ñ=¯»7¦™ˆåÐ";‡ÙÎ)ÿ³ÐÔæàfP1Á\±òÇLèx®˜á²v€V À¸° ½p\MÕX°@—üžg¡¸±¼yVR…°âD„ß5µ«(íx›yŽ7@XAËÚ¿¿€Ë)¡» çÅ`0†.`ùž? }€mm`L„_ÐzÝWÜúòÜ ïÎ?‡n?à ê`ƒ…áô`NwåÌŠæÔè×ʲþ„Î0ž_¼¤ [BÔ@ñ\Qbù)4 ËóÆ€Ó§ ö¡±c µ¼PÆÏ €ªn€Ö0.Jý…3ï_¸ôãs€áf0Ã.0¦iÑ–C}l‡[ŒŸÏ€Úìß½Ä`ý *}Þïò(`Þá€[*æÂ=—8By˜ŽGËç®Ë=5ývìõfƒ‰@Æôä[Y‰ºN‡˜ñ¬lp;…¦¦A$UW²ò¡ ªÏ€N1oÆ‹|a`³x?ÀDö´|žºå›Q¾Z?ÿë|î î^—.Ý“oEá)¨Yd¸ëÑþáz®ÉŸpx!ûxw$î paŸ¯æçÏŠÂuÒe`· §{bò­«ÇsÐРÞfúJ"ø–ü‘ÔSö ¸ÑXÁQGùêÛÆå³‹¡yä£tYwàÓ=1õà><‹vغ§r¼ |®ÿ?ðþÀ¯ó•—ót¯aÆ|¾× €Â ƒ¬\e1Ìð†Ñ·OIqäx;’õ¹ õ÷eÝúVTX|(íü?¨´^ ûxÇí{÷&¼àïçj0R’C'ë~YŸ‡z¿þwëþØÔøÐ=T¾ÑzŽÁ«…:F¾|aKÚáÕñé/=‘“uyÒ§é ×ùJ |:_l§7Å‚‚izûðd· ”Ï€l^Ñ`xPË9w ì@»[ ð.ÂOPˆFH!3å+Þ¢ð,Ö÷ êº$àÐ|Îûþeýn»6yá³ÂÊ sèç.åÃ48ç®Þ¥o ›³ù³XüE.\ß_à:N a;þµ¬‹?ÀhúƒÉ˜–·Vöé¼ tV‹ºãE@³¯W¿¼føãSÐ8YßÓúÜ4¶YÇ‹¿ËŠXñÀ`„ï6 žðJçòÙéNèö!æ,Xþ3NoŸ€ä­‹Ü‹íx6ÛÜ5÷ "–°>P×ýŒ/P¨@àYü4x6ÛÜ5×+àbù…¡»õ÷cv;ÍizkÌŸzáûpžºÚ¿šÛÁa»ÿÖŽÑVÒÛ¯•·àŸ^Àè~m‡ÈiYutήlÔgp¶ý£|¸€8In¥Ý¯€ò <çUmż4@ýÚ¿ØlêÌŒ¿BLSÕãó›”õÕa»€2¾(¢;â×ÀÅèwùŸ-WdÄt@Àpæ ­jû¯ú:°ln€+倗^ééjûoð5pö?;Ј0Ks¯ ­/ú­ô_ûU¯Ø/©å¡…]W ¿•þkàæâÚ’Ó'®pé äÇé¿::vA_÷ö'Òç˳?±\ò´§ÿêØ…;…írU$?\ÅZ'~œþ« û©Û3‘ü¾!ºGâÇɽ¢ä«q¤çØÔyEÉÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝÖmÝówÿ.÷ì"M<,IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksFontSmall.png0000644000175000017500000001477313263214225023043 0ustar aeglosaeglos‰PNG  IHDR@¤w› ]PLTEwªÿªÌÿ»f"™DÌÿÿÿî̪™wÌÌÌ̪ªªÿÿÿˆˆˆf3fff™™Ý™ÿÿÿÿÿDDDªfÿ3ˆÿÌ̈ÿˆÿa9íYIDATxœí {äºm†Ù$OÓ:u“tU·‰ÿÿÏÌZ7âò$u¡¤qžE_Ç£³B“åóó£—¹1½ÊV —ì*ZaVÅ$FׯkÙɲ?iÀIñã# Q‡䔼֯KÙÅprV 0cŒ>4ãá nUÐTÛ‘lœ5 Žá7‘1; dQ…©Šû¨¥ ~jƒ ×±pè:1êýˆ¢‘œ„<€›…÷aüJš‰t*;¨Íòªh!/-OäçÌmT‰½åUx$¿\€R[ÕŒ„£½IÊÏœÝ/"úh×ëçL_D>?=·“+8X¼c çHƒ–%Üò1ûÐT]Šs 3›Z¦yæW™ÓR§G‹Ï1 ÞW96öFµ<{·“Fæ5E¨DŒ²<ÇT¡¢PMô%ÄÀÙäýB›+Eb¡µÓ¬»Êk¯Bç·FSÜ=鬽 cE; ýdF²?ó ç|» q¨ˆ#M¯B—UáJÕ˜ŸÙús¬šŸ±Ò‘‘å„|“©Ikݱ&æË#±…ЂõÉì3„SyN£¯°Ÿ í™öæv°¢lI­ú…Éw4_£¿à \µß„+ü¬Ì;Í>dÔžÂr4[cLé5d J ‘(Ƴ ¨mo•ò_ôcóbtiHܦˆÔrz‡šüÚºÿ1¦²˜é?Ñân§4a^µ²%wN:k/#Kq{qª¢Xž—w¬Ò ”Д¾ig­Eäè5iò’òùLÒœ¾üÐGe‡Fplc•Så„\L-:ÂL ÛËPÓÅ`»Yl >%ÈѨU“àü³Ôû£¼Å—Ç[y¡9ñ6?ä›9þò\?6@ºÈ€hœîç6g~àÐ;﹃öüzzŸ‹vÙÎ?°Lg³\_lÌ:ºÅw ÏPÀ˜ÆR??¦_ˆ4€™‡(fÁ~(ÀÝsà’"â…ðô‡–›—."i€ZÓ+"Ò&/%Uö¯lR`>\ÞZ0Ì3lŽºµ:•ÙÊ[|±º¾ëÜ)öUŠçuÑ™F¹Â×dŸP“3ÍKEšd_¥þ\H+Mš¼¸ä‡©ÙWZn打Ùk*¬Œã޳æNˆ|YS(”ÈŒ<Ç©@ô–ÀYQ–._eŒÓ7Éio6¦‚ïA{° [ž/–UáxGN húcÖÈ ñp“ÁG·#ŸR:À "…*’Êe0ëɤþŒ¡[VØú̓„c1jÕPЧZ<š{ö#Ø' Â^…0Q[ J œØÞžàs¢n‚@^[^‘š¬˜¢˜úAê×å#íÀi± NÕ&@V[ù~ÔÛZTdÛ9yë¬?æ ’ŸË¼0õòc†Ûá3äQ`â*ìõ}Â/ÁÙEƹhöA+M.$©ãÕqÜkÄÜ]Œû¹úy°‡ú=t¬ô“Ö“ÞFø¼!@ölŒ(¬¥vàôer¼þ¼)À!åÚQ+àÇ ÆÇrŸ![ÇU‡r€ôÁLfòæ­ mÇ(:„À2)~6¦ä²ð_Ï⽪‡Ìã»w¨ñ Þ  ýQÎ;V{ænpci›¬ïï·^æÆô*[^²«h…Y“]¯e'Ëþ¤y'Å··@(DFSòZ/eÃÉY1ÀHŒ1zÓŒ‡7¸UASmG²qÖ08†ßDÆì0E¦*&ø­ .\Ç¡ëĨ÷#VˆFÞpònÞ‡ñ+h&:Щì 6Ë«¢…¼´<=’Ÿ3·UDP%ö–Wà‘ürJmU3vŒö&!|(?sv¿ˆè£]¯Ÿ3A~ùþöÜN®à`ñŽ1œ#= Z–pË?Æx`ìCSu)ÎtÌ plji˜æ<š_AdNK->Ç€x_娨ÕòìÝN™×u¢1ÊòS…ŠB5Ñ—<g“÷ m®‰…ÖN³î*¯½ ßMq÷¤³ö2Œí,ô“ÉþÌ+œóíJ€Æ¡"Ž4½ ]V…+Uc~fëϱjb|ÆJDFV”òM¦&­ ptÇš˜/Ä:8¾A Ö'°[ÌNå9¾À~2´dÚ›ÛÁˆ²%µê&ßÑ|jü€o4pÕ~®ð³2ï4ûQ{ ËÑl1¥×)(-€xD Ï6 ¶½uWÊь͈5Ò¥!p›"R`ÈèjòkëþǘÊb¦ÿD‹»Ò„yÕÊ–Ü9鬽Œ,ÅíÅ©Šby^Þ±Jƒ^PBSú¦µ‘£×¤ÉKÊ÷0qHsúòC•Á±=jŒUN•r1µè3-l/C9LƒíZd±I€ú” G£VM‚óÏRïò_oå\„æÄØ|“oæ ûÊopýüÙé"K¢qºŸÛœù!€Cï¼çØóëé}/Úe;|ÃZ0Iœ Ì^p |±1ëèß%ú®s§ØW +ž×UDgå __}@=NÎ4/i’}•øs!­4iòâ’¦f_i¹™'Nf¯©°2Ž;Κ;!òeM¡XP"3ò§Ñ[gEYºt|•1Nß$§½Ù˜ ¼íÁr€zlx¾XV…ã9l é!X ƒÆÃMÝŽ|Jé3ˆªH*—Á¬'Wø3 „>nYaë7ŽÅ¨UC @kœjñthî9Ø{Œ`Ÿ({ÀDm5(rb{{Z€c̉º FXymxEj²bŠbê©_—´§År€:U›YmåûQokQ‘mçä­³|›7H~.óÂÔËVl‡ÏD‰«°×÷ ¿g?æ¢Ù­4¹¤Ž#TÇ5r¯Msw@2îçêçÁ>ê÷8ÐY°ÒoZOzáû†Ù³1¢°–ÚÓ—Éñúû¦‡”kG­\€o7KÈ}6†l!WÊÒ3™É›´‚¶c ènˤøÙ˜ËÂG|=‹÷¨2ïÞ¡Æ3x3€öG9ïXí™»À¥l²BÞß¿z™Ó«lzÉ®¢fULbtm¼–,û“朿¾¡uANÉkm¼”] 'gÅ#1ÆèK3ÞàVMµÉÆYÃà~³Ã@U˜ª¸Zšà»6¸p ‡® ÞX!ùÂIȸYxƯ ™è@§²ƒÚ,¯ŠòÒòôH~ÎÜVA•Ø[^€GòË(µUÍHØ1Ú›„ð¡üÌÙý"¢v½~ÎùEäýÝs;¹‚ƒÅ;ÆpŽô0hYÂ-ÿã±MÕ¥8Ò13ÀA°©¥ašðh~99-uz´øâ}•ccoT˳w;id^SÔ‰JÄ(ËsL* ÕD_ò@ œMÞ/´¹R$Z;ͺ«¼ö*t~k4ÅÝ“ÎÚË0V´³ÐOf$û3¯pη+‡Š8Òô*tY®Tù™­?Ǫ‰ñ+ YPNÈ7™š´&ÀÑkb¾<ëàPø-XŸ\Àn1C8•ç4újûÉÐion Ê–Ôª_˜|Gó5ªñ~ÑÀUûM¸ÂÏʼÓìCFí),G³5Æ”^C¦ ´âi€b<Û€ÚöÖ!\)ÿEO06 ÖH—†ÀmŠHm€! w¨É¯­ûc*‹™þ-îvJæU+[r礳ö2²·§*ŠåyyÇ* zA Mé›vÖZDŽ^“&/)ï_8ÀÄ!ÍéË}TvhÇö¨1V9UNÈÅÔ¢#Ì´°½ å0] ¶k‘Å&êS‚Z5 Î?K½?Ê[|y¼•wpš?`óK¾™3ì+¿Áõóg¤‹,ˆÆé~ns懽óž;`ϯ§÷¾h—í ð kÁ$q€0{Á%ðÅÆ¬£[|—ð åŒi,ðýkú…H˜ pˆbì‡Ü=.)"^Oh¹yé"’¨5½""mòRR`ÿÊ&õæÃå­%ÃL0Ãæ¨[` óX™­¼Å«ûè»Îb_%¬x^Wi”+|}Aöyõ89Ó¼T¤IöU àÏ…´Ò¤É‹K~˜š}¥åfž8™½¦ÂÈ8î8kî„È—5…b!@‰ÌÈsœ Do œeéÒñUÆ8}“œöfc (ð´Ëê±eàùbYŽw䲦?†`€ 7|t;ò)¥Ì R¨"©\³ž\AàÏ(ú¸e…­ßBМËêTmdµ•ïG½­EE¶“·Î ðkÞ ù¹Ì S/?fX±>#@N&®Â^ß;üœ]dü˜‹f´ÒäB’:ŽP×Ƚ6AÌÝeɸŸ«Ÿûx¨ßà@gÁJßi=ém„÷dÏÆˆbÀZjN_&Çë÷›P®µBp~Ý`|,!÷Ù°…p\u(HÌd&oÐ ÚvŒ¢C¸,“âgc@. ñõ,Þ  zÈ<¾{‡ÏàÍÚå¼cµgîv7–°É éºg/scz•­@/ÙU´Â¬ŠIŒ®×²“eÒ<€“âó…¨ÃrJ^kã¥ìb89+‰1FOÍxxƒ[4Õv$g ƒcøMdÌYTaªâ>ji‚6¸p ‡® ÞX!yâ$äÜ,¼ãWÐLt SÙAm–WE yiyz$?gn«ˆ Jì-¯À#ùå”Úªf$ìíMBøP~æì~ÑG»^?g‚ü"ÒužÛÉ,Þ1†s¤‡AËnùÇŒ}hª.Å9Ž™‚M- Ó<€Gó+ÈÌi©Ó£Åçï«{£Zž½ÛI#óš¢NT"FYžcªPQ¨&ú’bàlò~¡Í•"±ÐÚiÖ]åµW¡ó[£)îžtÖ^†±¢…~2#ÙŸy…s¾] Ð8TÄ‘¦W¡Ëªp¥jÌÏlý9VMŒÏXi€ÈÈ €rB¾ÉÔ¤5ŽîXóå‘X‡Â'´`}r»Å áTžÓè«ì'C{@¦½¹l€([R«~aòÍרÆoø¤«ö›p…Ÿ•y§Ù‡ŒÚSXŽfkŒ)½†LAiÄ#ÒÅx¶µí­C¸Rþ‹ž`l@¬‘. )€Û‘ÚC@ïP“_[÷?ÆT3ý'ZÜí”&Ì«V¶äÎIgíed)n/NUËóòŽUô‚šÒ7í¬µˆ½&M^Rº'0qHsúòC•Á±=jŒUN•r1µè3-l/C9LƒíZd±I€ú” G£VM‚óÏRïò_oå\„æÄØ|Ê7s†}å7¸~þl€t‘%Ñ8ÝÏmÎüÀ¡wÞsìùõôºE»lg€O¬“ÄYÂì—À³Žnñ]Â3”0¦±Àî9ýB¤Ì8D1 öCîž—/„§?´Ü¼tIÔš^‘6y)© °e“zóáòÖ€a&˜asÔ­ 0Ðy¬ÌVÞâ‹Õ}ô]çN±¯V<¯«ˆÎ4ʾ¾ û<€zœœi^*Ò$û*ðçBZiÒäÅ%?L;Òr3OœÌ^Sa dwœ5wBäËšB± Dfä9N¢·Ί²téø*cœ¾IN{³1xÚƒåõØ2ð|±¬ Ç;rÙ@ÓC°@‡› >ºù”Òf)T‘T.ƒYO® ðg}ܲÂÖo$‹ P«†€Ö8ÕâéÐÜs°÷Á>Qö*<€‰ÚjPåÄöö´Ç˜uŒ°òÚ:ðŠÔdÅÅÔR¿.!hN‹åuª6²ÚÊ÷£ÞÖ¢"ÛÎÉ[gøœ7H~.óÂÔËVl‡ÏD‰«°××Á/ÁÙEƹhöA+M.$©ãÕqÜkÄÜ]Œû¹úy°‡ú=t¬´£õ¤·ºdÏÆˆbÀZjN_&Çë”kG­\€ÏŒ%ä>C¶Ž«å郙ÌäÍZAÛŽ1Pt7€eRülLÈeá#¾žÅ{T™ÇwïPã¼@û£œw¬öÌÝàÆÒzò`ïãë(°kzsýÜg–¹¢¬Æëߨ ÝøòØõ&k¿>À‡X¾ Œm²ö+ðCNþlºØkaÀ‡l¬òí|‚œ4wà#»=¸|°ë•®Oö¸8°¯0!±ˆˆ»ÙË#,cp÷2âïÀ@÷¿e ̽\âØe!@¼¾-sà…’*@Ž!àÂ*|~;, áÍüºŒd}Ùàuø%=}°÷ñÕ â‚Xõâ×x”\™>x‘»% ÉËM<…È’à]>ä¥ÔòtׯÿœOlò¤Æ¤:@cd¢Œ[*ÇËIv _…=£åɱœ•‹Vº€¬/²%UØî¤d3]¯,xâ]…/= ÞFÅæ­xR|g˜Î àÊ*Ü‚,é´Ôð´ÖʦŸ…K Ý\9¾Éieá‰o¿ß»\ì»:óæCp×»¥—͆2åC÷)µÉ¡ª—t8ŸHCÔŒ—¡,•Çø_8 èe!ü  î/Šø ï:l•Þ‚_ÁœHŽì°±1 €w µ=;—4€+å6¯ÂÙ§ÛŽ…Çb7À<ñ çî5láÌb¸þ‹k¶ ‡5y Ùé—-F>¨‰Ù,÷G9·$“ŽÊyÃd‘ fpf”½ó!æÜrÀ‡}¡îžŸànéþá[)à5¤>À‡{ÕÂÔ†½Àžl¹Úª·¾Md+ÁÄv Q&”i}3¹//!6ÀŒ“‡ ÿ?I/0<Œ¨Òíz‹UÎ/@ƒùY¸@ë÷G.@úîÄ%ÝÓ¹””üª„ï‚ÿLŽ¢Ú´Ýt}hòBO|¤5tɾsRß#J=ŸÏ$8ÔeR/  8Ð%áÀ¶ƒ>={— ü½°0hL `ÜVÁø»¤²Ãí¶¸RÊr ßTa4¾œ_À%Ò®ã3GêC S¼5À•Ò6ÙJºùï,·y7¿7ò7ŸÇüѪs±?«ÆWàüϯ°Þøw ÇÕvàÞBÖ ¯/`üËß»'í÷ۖѸ ÿN¶;-¬šè+Ôhâ´¹~ñ¶| €1„Ùr(µNÈ'Ë„3ùžŸDõ.b7‰q©ÁS ÿhÁ§eaåòÛà%ù¹I?­·uV„ð‹„EWhÄ/"š=ýŠ®ÈO :ÆDnã…IÐ?Æ€‘ñÞE¦sà¤$N‰ØŠOÁxQ~‰¨?ÊuϧÄåüøM\iŒš ÂNa1‚æ|G?“Χ̋êžq@sÍôسY:Má›0÷*Ð# 9¼ØŸÙØs‹¬©üÞܲÏĨ)^hÅ µdAvÖ¹F–dk¥.‹s[úCPl7mò:áñ•,ž§ðê ´BXæ„€noºÔ}dØw cs ø¤jj,Ó3æõ;.ÂoX¦Wºrö©Ãº²[ð*üø‡ ü¨Ơ„ð5`P™Ê(î,/"/Ð<Ðd\sŒ¹¨’ð|‚{³.û¬^¸Î9EnñKˆªšòwjËÈ2AûŒ^:›ÙbÍëlÒä`éž,}ÍOãÌrT|â$¨º„)=_N`øŸT¨ç Ì¢«@R˧.ôr‚ôç_ð2Žõ ˆBÐ9ŸÝüc€Yú烞.ÀQ/ PèÑY“ìã«ìù Y°{ÆÀ½4@žÑ‚ PôÆÐÙ ”çFi¹\›+\ÂyE…ð…nYDL€‘7¶» ÀùÅ£¸ÀñîË \Hþ¡yë¤yoî—«¤Ãø3ÇKuÂÂAŒÄåYA?$¶åø£LMš4qÅWuïéw`%™ 3xøw1Z/R8ˆŒ­ú.—˜{n¡‡—Qœ(p½y5‚¹g¾ÐbÙà|,b87~šß¯ÄÆyŒg¾Yu~Ûà%"Ry÷€ÙØ.^M/(C)€Q±›)Ú>U*ÊH6²]9ìÚ±Óòö°{r€¬’h€ónûyïÀçð‹AXNƒFSd#ruf“¿ÀH©ª¤üyëòÊíH?ÊQW.w$lRY¦mr÷âå1P0ú·î÷ųì…?Õcœ3ß8 k{‰é?C‘ü]8Èôp Õ•ì6²Àçþš%xO&´¶äWøç¯¿ýåÏŸ¿ÈîË-"Qn ðÿû?ÿú§?þÇW@%7øþ?Ïîßß¾ÿÏáГ_ÿÿoÿÇã¿~Ñ"ÒfË/r‘ûˆ/°¿ÀiU4€Ã…þ(‡N„@Àx±Hn p–òúË;¬´IEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksIcon32x32.png0000664000175000017500000000052313263214151022522 0ustar aeglosaeglos‰PNG  IHDR D¤ŠÆBPLTEwªÿ»f"™DÌÿî̪™™ÌÿˆˆˆfffÝ™ÿÿÿÌÿÿfÿ3ˆÿ»»»ÿjW¬ÌIDAT8ÅÑÛƒ €áÂ7ªt ¼ÿ«ŽrØÑ+“qAÌþOÖ ÀÍ Q¿®ûµ@<ج»>]ƒ(vµ†V e$«Ð©ZDŸh;LjŒRÆHCÞæù¤¼,û¸®Î ÃYrVÊÚ6;Á»Oo7à×ËáNYçëî(yZöÜA”< ÿRe¿“{TðHù¿}Íb³ë‚rxšµò­‰SùRÇw^Ïv„|çcLcÀ] |ÊGØ%ïý Àù×úNÁ,ˆøIEND®B`‚mirrormagic-3.0.0/graphics/gfx_classic/RocksFontDC.png0000644000175000017500000001756213263214224022257 0ustar aeglosaeglos‰PNG  IHDR¯ù“Ù-PLTE™™™wªÿªÌÿ]]]UÿÿÿªÝÝÝfÿ3ˆÿ»»»ˆÿˆ"%àƒIDATxœí]Í‹Iv¯!§¯@sÙ¢ å­Û°'§ÓPà>-*[Ëìe/ݣˀVÍ^|“‡¥Íú¢ÿ`ÕЭƒjÚ0yix`ÑuQ_ô78ÞWÄ‹¬RkÔ#­7Þ¡ª^¾øxñËW/âEFN^¿~}½üÎ~¾~?¾6ôSò<~RÅtym?‹÷〟ÿãñihPI<ývßmÛô]g¿ñ²£Ò¦›ÎÍwUè¥U Q¬áÏP\½$þ¥þ7Ö§qõ— ýÞÒ/ @ ²žxú­¾}Z¯ý&¤Ûa[-ZÅÓGŒÏŠ`ÌÖÖÏ9|ýÞÖo#,;Ûïz _×òÝz&`Hú…(Þ(!—ÿJß2>€ð…(Pv«üJè÷¾°~#´F&àoû]›&÷—`>ôÝj€œn§em,…ÊÿQ EºO™V Æ«mMÒÕ=üJè÷žˆ~c4eg€ßöÛÜú¦_ƒ‚ôÝj€œnѲÆÀ@¥`!…rƒÉ¤ß6³®ë.‡¯ß{ úÐ;*þÏã·Q­æØ\ü6IKØ)`:°\gþ-€V U 6‰âÕìaש¾~ï€Õï@ýí7´|Í7¾)©#J·Z´8Ìx9o,Z)T\!x€ª_[~g63&@Å~0¬~ï¤ëì·¹ÏW|¿ñ;@ÍÖ ÀãV •ïa^ @S^ÎE|63&к¿ÈÀé·2`ûmîeM-¦ïÏÐr¸—p,Z)tc‹=æMæÊ˜€Éqeý '.ãú£ÒN¿í`ºÎ~wÝ·˜¾# Ý+-ç,,  °Cœ=¬ú+çÔ<ÓHéëïJi”~ÛäÝå‚ZÌß­ŒŠrìå àZý¼!9Ê\}`€€ö[F 4€.€7*¥PúMv -§îŽWòîŠo9CÒµ‚Ò<²ÆTô€j;Y´$7œ®ïŸ€Sâ¿€KÈ·Ú•ì„ÇJ©œ@ÿ0}¢}Z¿É2E@R´\°Œ¿aTÐQø|In;VgZÕ”©BckÏG.µÚ•ì,?Ì™Oèî¥O6Áé7@5 €€Ó •6Èä†ä5vZF²ÆÏ÷@¹’å×ÂÇúùécòô›$çÊ$OÏ¥©áß½æ~B:4èfùw¯-À/LúVL€  KÔ÷#¶ö…ž«?–KX_Éã®)Røµåúyéãú<ý&É1Ó Óã$÷” |½N±vxbd§‰ú¨\é÷±\š²5 Õ ëç§êóõKà†é¨€p6¨ `Žÿ‰k=à*›³ÄZSN °ÆõäÁd®û“z€ }TŸ¯_ûS³Ae8.ê1–èaÌ4îør£˜¢Êó Àk€.*n1ó⋤ÐúXÀ¸ÎÕ¨K½¢Le00h–0÷`MëÄCa({Ñ”Œ4ñâ‹Hµ¾ž$䞌àl³AÛ~;.ÀT†0_3?@gL¶ “×4 Ç¡´>Z_ÏrÏFhF½(‚jùVŽ—u 2€ËÙ¬n ÚôDXóüŸySš€€”iÁðRr.xYŽù úFíñ `»`Ï ˆg„SSö-˜À¸ÌyþϼQø¡ð;¨1ذA@ôó¸·Aߨ=žŒ Ë/Q‰Ù E@<#˜Ê˜Š§ØÌÐR î¨õ ÂA|Ž6FÔèLJAþà (šÒ'Úòخ߻Ų¦ÑØôá~†ÉWú–Ü@…ƳjÍO ”·1o’jZ-? òùCùÓ„>ñŽ€„í“ú½Ì´<›VÛHÞMZ}KŽ1¹h~^‡íy˜ž’ŽN+žÜø;Bž6{HýêÛ5Ø 1 ¤ž'÷07ä àèèÀð—ÿ¶t ÞüÑAÀ_ù“-ùŸlâ©ÁÁŽŸçͶ~}ƒœ³¾D±?{¬FϱB0€ À³}&›¾ïñ¢xfØ'ù¾æU~Ãzr)OóÜ`GˆÏó*Ÿ Q7Ø€“ÒB&†H—s@4zòV8:Ö>SòöƪO<`Ì`“ ü™æ]þçÿÅ< ÊÓ<7¸ê}/ëü€JÝ` €˜@ǘ(ÄŸ 7_{0(×p¤8âÁ@#÷åêž»üÏ¡d-wåyúØE Ý( `¯»œq·ï/PÈ `M ŒcLâOÞGÇ_)nX ’+x£Á€s·åÊlþç˜ñÐÉUyÏ´>vC x4€žÛû½ù©ÄÂ8ÆÄ!þ¼nöß8Ì-C5~!rëëµVá?¼ÅÁàtÀ8Åï΃ÃçoÝî.¿F 8ÿó <ʼnE GàöC·ï/P¸AÁöâGÐ*öÄ"þä V¸» MÆŸ8g†ÿì¹úÏß¾!ù®Œso”˜ùkc»Ð0ið „ë¼@sô Ë9üFÉmyšÇô±s|Å0³Ý~°@¡¶   |OkxAYÀ!L å—iò×öâÿ³‡ËÿxNÃäï!¡˜€VþIÐ ˜bþb|ü{,Õ\ úŠ À“Kyšß6E@EbC€Ðè"]À4ù+þg¨ý Àº:Jas»ÀkÀåh0ÿÎÈÍ¥7¿ 0ija¤Õ~ÀîZ²˜¹±ü2í¤ƒ›;ÿ/·ÿøö(p\èví£ç¶tÒÿoÒslŽ©¦××b¯}¹)ïO£´mn7^ƽ.ÞкQ᤹,U+®¹»:äutî¨Ãú…´ÿ)ðv(gÇåkº]h‡K7Ѓx:643cxZDòÿ ­m3½yQ4·&ÈÝvü¡V‰‘¸D#@µyQQ¾]Oà.}¿j:6üKË8Z´ªKC¼mšâq«ý P®>F§ÅNðÇ©Z%V[¤ýõ£ÁÜ¿[¼Ù ELû98Y°oÇi¼£ >@´‚£ø7jn€·LÀÉhÇ&€çå3^ô×ï° p'éϧR€à,h¢ÇáüO³1D+8šWsò“Ñ÷÷ÄÓȱIà;B~ù À¦h0ßl €ž Z8:8 -jòFÛnEfŸnøÆ›7L½áM•ÄÓ7À!¡+$sÌHž,K4x§ƒ(һĦb¶°4ù6€ýýo<ƒðWpü¾'Ð4Oþt–Ïpò"’'Ë÷÷-êÇ Ô¸Î¤v‰MƒýÊ‚&Ëc¯Âé‘ÏnáÅ5¥I£ùåË$™^’Çò‘ò¯‹¢°XƒO¸ÆïÄ{%á¾ëßµ‚“ä¿‘xR¾Ž÷èÿ÷lãÕ~ÿë¥ Ì™¿œ£/ñâSˆ×Œý÷çì:¯~JÇòWÊO\ûûn6µ ãé/=1$h|6Š¿‡¼Ÿß7`Æêtz«°’ÓUлjüTtÌ5°y©ò‡úNÿ°ÆÓË¢ðø½@ÇߣóÖN̦m:½ÀÉé*Å„[?UaãÀNÎ|×oôŸ àôaŽ>gºþ_úñôª_ÝÓ|]®|ù/£ø{È{ùÕq௧Ò+¬œ®RLØñ €ÄœyJê?)Î~ár^ÏVÅ}`6øñô²[]ø+.+O¦7‡¼Î_¹ãp~J¯9]嘰ËÏHÐÊ™çü¡þ“b¡V ËAŽo y l´>]_÷äAúPò¥;nÀÎÙ£ó,§«vù€oŒY9ó#åOî·­ùšíOªÙÐ*ÁlÀ]ï.žÞ ‰Ò“<äKźïülI¿÷èåYevù,ÿ¥’#¯ò{úOvÚæ!´"Esj@Å®ËÞ{8z]u~ÊÎk`˜i €~º}*lyô'"¨äÈ«üžþ“‹öÛžú½EõÃCyμç)Lád€÷Ó¿'ø‡´O…`þK0‡*9ò/½üNÿ‰éºEcT¿š—{˜à¡4ø[Oa '¦¿øm?'XlàrnŸýJpUUOé‘"ìþÓS‚ÁÌú‹o74}í7ò·€‚{(!h7°®b© Ö0ð¡œÒ#?| ûšþ Ÿ^¿ú¶¿húdƒé|€E»(=9hªŽï¤#Z*ýÂ6eÁÏ$x®k땯M èÁ¯ù §'?§Mê \£ßÝ}Ðø¬]ƒY¿€õb”_K' › \-Oííªô®¦ø=?“àÍé[¯|9€®ú©ææ–ƒüŠÓÏÑÒúýùrùØÀ K9@™¸›N:¾ Óãaª–﬿Wž·úü)9¬d—OÏGI?3·µc}Ïд¾þí8k¿Áö|×ÉmÀ7x˜û<¦âKçºüw`Ípvê/Õ LšÊîR|‚ô«|÷úG €½#‚¸òK¤gÞÝ!ë6‘Ü@gÓÓ#à³Ò/-%S",M¥ŒË¿ªf³Y©ë§”Èh Üg¶Á8ÛYkly<«ÕŸÞIs:þ.|4Îb$Æ5°¾çÑ>ô#ð?+‹^ž>¯e¬_þƒÆ0{©ëÇ”ÈÏîlú9š€þ Ûò¸® #>!ß:t]ãaNÛIÞ æ/ÑBÇ Ý¿sc˸|xL@Ðàlø3¼wNß34)}y\ã?ürÖGw$9ì©q;Éoï}ä7\5)`—b¾Á¾×w”f‹†7z£°KKåp•Ò—¡ yØuC|Gܨà7ðî?Œ2òÃü­ SAþ2,ÀOLÀ»£vrœ©òáß1¬Sú²+<ã^5¾#jTh¾yé#ô±2)‚Q†åÜKÛªÖ6Xt-›@Úç€|Œ Ô ýi2Tqßu§áic?À·5/³Ce©N3eXÎÖpUd©Q©çƒ:ÀÊ”vÝ£Î3Ó<˜À<¡ÿäÝýÊÀŽ›¡`ùÊçerâ+” 1Êè^žÛº¶ùmz7Û¤£PŒ ŒXȲî¼QHË«>Öò%8͸¿{Ô°æù ACË{P@€Î?$@À“¢ ¢¾^ëi«2e‘h!+ØITŸ–71zXÛ;È{)H!§ýp냀ä§áŠŽ+Hç÷êóò¦·K^cõiýi'Q™(o²Ü‚?ÇëÓåáN¢2Uœà.ÙÐ9Ì­éW°ýÞ̺}Þ“ïîFç ¸òdn?&OÕ’T}.Ê?^Ÿ.Ïñay·•ý íøÛm>? ŸÐÔšV›ãÿõË­ñäÃxÿ>Ïw¼.¿°ïà÷4Ržm / úÿ“àvñÿrkü?ïßÂÄó]ü_—_¸÷Ðû$ƒÀ“ã2;pÃWþ–ø¿ÚÿOÅû·ðe:žïâÿºüB½€à €à}S3ს—inÿ/»Õ¶ø"Þ¿…‰ç»ø¿W~¡Þ?@p €–#”-FFhtù]ÄÏo#¯uü>Œçò/žò~ùEøþÉ ðßW€Ôa°&àfS]²Á¡<œ}%Q‹(œ=Îc~ÏOò¶|ÛÀ²Ó0¼ôhœœ¡,kâL^î‘‚v¾ìÂϞܟžñü[ÐÐc6žñ¾³_„ï# U¿ìû ÊÊ™À(nÕ”(\·åÔà žÿŽ|¶¾–Ð¥=ŠÔçg¿c— ßë>@¿ŸàB‰(mÀ® ÆÿÃel¤0žÿŽÌå¸UøÃ•Çó»p&l €dúýø(»ºÚ €Ž¡¤WmÂxþ»ðY=œºõZÚÐ@M yj¶Ý ëèøï'àL¥Õ&.~£ø¿“'Þ'¢kê“Þ€y=¬é?ó5H¼?ä±üWî…’a°ŽŽÿ~>¡PêG ƒ’ýëø ß' ãùôÓçÇ|]K¼~—ï Äû#Ê8E6x5ïyÉÁ?I^‘¥•òý ÁDÝQ½ŠºTáè±ý5‡ü½u*ÄŸHòˆî`Ëñþˆ_Òyø´²…ÇÿÈš€›äê$;ÔÏ—MÔ]Œ)ìË£÷ ¼çØ Ë㎅+NIw—®–1¿´pž`éz4ˆ:#¤"/^<Þ“»qYÞ'àÅóù¡~<Õßò¸geÍ)n˜`–N£Ö/pÖn{€×é÷¼²&z?Áw¯@ᯠ„ñÚà"/€k¨Ðr½ Ìï(‚hn¿ÁÅÈÕŽÞØhL§äx½œö^;±.©ËŸRÙw]Ñû¬ ÈŒ@¿Ÿàú3Pøº ¢µ”+ÆûµüTÀ¼€Žß—q!“VÀÕƒ‰Äëå´÷Úùs;üosGkGNîé÷¨€äµ~?AÐà¾gg{ý(Þ =½2€Å(jÔ ®ÊqÏ Á¯—~hŽ«æÍoÚê}ÚPÞè÷Ü€SÕ뇞ßÕÃnEë8µ(€5ÕvRUJùà¦J¼^|þZùs;„š|Ss*´Ôû´ @µz?Áû ¢­^¸Üà>Þ'@K6VNš6rj°Äë[¦èFåñ–@ _.ã÷tèåhÔû n €¿¯{?\þ-ðÎÆðF Zë;9Á:U—9^ßò0E÷0*O™úñû >I¤´øï'¸ Aü¾”py'®ðiô>/žÏqÙNNp97XâõzÐÇå©öW½0çù¾4H²3z?Á;à.,ÔzÀƒª?µò;,Z}Rèüè¼a\¶ê¹›ªc¼>˜¤Õ è÷Ⱥ/dgôû ¶0¿_4¥‹·ßKÇïYáJãï<®—<Ùs}ð¢s¬ì9ay‰ú‚÷Pƒ8ûtL>À†ø= U<>¿'…ñb”¿£s{Ðx “ý+‰×³ÏoÏËKÔgß? ÈÙ§criŸ×¥Ô¥`CüÌy[üžvŽJgOMÈþ¯wálº–—¨Ï¾Àk ïp•sû¼8CÕO'›â÷fŒ®¶Æï!§8®AþŽ0Ø!åVx0é¹×cûN)U™(/QŸ¼Ào eŸŽÊÅüò¦“Mñ{ðÁ¶Çïwƒóþµ”gÝÊÃòhÖïJ ËKÔ÷…´áÔ›ÛcÊÝqùnª¼|~@àõŸà÷ºuùâÅ‹Õù ûùâ.âÿ‰ö,*ö¶ÍÏs~@ݽoèË?»Ï]_º=;mý/*ýwY"€wìñýº!TßqH‡CSè˯V«Óó•ý\}xÂóhJ-ú!_ãLðϸm| ü2ÿ½ºãnïåNÛÝ5}w÷œ‡Pвz]ÿ«øžÎ¸m| Ä*PBÓ°„ž$øíjIéÎ-À¶§`“¯Á"-8Åf‚ónß'úîòFjžþî í‡.àÎ-଑CV×Ð<¢£eÿYOÝ1Áùvy¢Ö¾ÈÖK'ÌWËàdC‡¶ï#îÜ\{.g%$½à³uà6÷íù&à Gscƒ•ïò…õÒ#ªþ Ó5ó½?^ÆÜµP{ˆÖž‰ññڙРîü€ê¤º•[žÐ¾ÈÖ«hJ~a³®ŠŸÛvìÓïæ?=àüŸž;@:™¡~³š/v+7[×¾ÈC1î—À@Côs€âç¶€ SñµçªÅU34€õàLÀÀ0 3oõ]¼ˆ:ùÂ÷Záž÷ß@×k£ÅÏmf ß]jm/gMì]áÛëëîü€²_xçØ"nTé».é,°a…Z·MüÜФ€š9=ƒ”ÀÐyÏ»"Ö"hHø~;èÚ`ª&,Ú½“ƒ%¥h “”HŸ?ÙɆ@ñ~ùµœÚ™<\oàê¿2ôå}÷Æë*Oð‘A=m8€HE¹æÝ Άýòøüogýã&y~@d6ü]¦öØCúLpЇžÞ2 ÑóÊ s}7Ìi7Cÿj7%„Ç€%!ز®ªO€»p“cðe@w´ÝÏÞÖ´›BZ¾ÿréÎ0ôc“?`^õ›ÏØëbþS³h¬ VIŠ‹h1cªÎÀ=Ñ67Œ÷"Éó>5 €öˆ…–r¸ºš€D«·žÆûñÿOÊ =îÍc€J€& «Y[Ïãý‰øÿ'eØ[ÛJ°û €ÿ| $À–óÂx*þÿIYÀŸéïÝÙqð6Z¢ ¿õü€(ÞŸˆÿo Èß¹`{˜V€Ú¿üçh À–óâxÈož«‡;<ôZЇ\ à_^{âý ð Pú;?? Üáq×ë@Q{ʰy¿dëüŸîð¸ëõ¤°=}Ô¾A¸I¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™2eÊ”)S¦L™>)ú?þÐØãH®á“IEND®B`‚mirrormagic-3.0.0/graphics/gfx_mirrormagic/0000775000175000017500000000000013252264657020330 5ustar aeglosaeglosmirrormagic-3.0.0/graphics/gfx_mirrormagic/MirrorDoor.png0000664000175000017500000004061313177211034023123 0ustar aeglosaeglos‰PNG  IHDR„3«ÈlPLTE©©©‡‡‡oooÌeeeÝ™D»fîÌCCCª™™333wª»ÊÊÊÝÿ˜˜˜f3\\\îTTTÿÿÿÌLLLÿÿÝ™ÝÝݹ¹¹ÿUG]¤ IDATxœí‹bÛ¸®®e;ÉÈöé¤mܘn:±vúþïxD‚€iÉÖ…âö^­-‰‚Ðù?ƒwUBTÆDÒn^Q!3Ç꺪¸ãòL] æ«3pß·&Ï–Çy|ÛUX)qLb)ùß™kúH× •ëÊž¨­ï8H®(!Žónl{9Þ§”~VJ“ÈÂ~5?ÒÂü–WÖ«¹*%]s–“.œ¶×À-NªÑ ©—úÁêu–Çy÷4²}LáËÈ6M“XE*+Z$Ë@§1áV.G¤ý:<Œ>q!7øCåôN,%Ž‚ ü èéc±BèËWš/NªVNº.5Ü’®¹ÜˆWxu9†s-"XB-„Ç–"¬CÙé ¼¿ì …u·X‰—]‰òe2Íaò0 ¡NÒµ7ôµkSñˆŸR~ã\~½!üØå !s°g=2V‚½ýb-&_üÛÍE§I‹«³t‘v’üäN¥\z ÂëAs=ðþg¾/ÛðfÙÂìÌ—Œ9ndIÅ[yªÆòî+]]C),UFµö)Ó.;Žž^>ŽgLá áÍW¯=A;ÿ®“Þ»}x&õúc ÙƒË,eÄA 4šÿ^>>¿o0…Ê®fgŒx™ñ¶°Uï}ÒõïG}òóIG/%ƒÿb W—hÂþ2«UU…¿å¼€ÝÑû¥kJZ5!\œták)qô©Žƒ„µ:ºD£zÂVßÔ9ÏLÜñn>Ý›=ˆTyáÚ¯mõ­öÎY)—G ƒ˜ÂÂ%ЉWèÆ£>OäË)ú±'´#¿"½V®aNqgK‰#¨Žj‚È1ADa‡²+„ÙYmênF µ°ýUåÒ…§Ô!Õk2º!š`rCº¨U[D!Ä : W—h ]£^_èB_©HY?ª;­½ì!û}éºy'ŽÁåÇ¡!<ØJ¤_Á<@¥R3ø¬ÌQØ¡ì avfÄ[¹¾ôˆ|±xÅ Ò¥fë’/]ÓŠÚÄÑB`ðÙš¡p…p‰†Äéô7Wº‚+XÃ> ªµY‹I×c°8:L[kAR Jø¾)S* ;”]!ÌÎÜì’øÈ›9š:£H—(*Ý€Á2âè¡að›5Cá á É71þ]1Ó¼†¯À‘Ú éÖ¸3”b¸è8º,eÒ ~#fráM[!Ìΰ|S³PüѶ1¤ë‹I—éRô,#ŽƒŠ¼ÿ§ 0ìFá avæô[QõV¾f*Ò1Öó8û}í¤«s9q¤!Ô Æv pΞ†³¢ ÖvSè«dþhÅ4™zÁŸ9D~t˜vm¯åÇ‘„ð&ƒ](œq£§á¬¬žùz¿Í•ÎR¼b*ñJªgqï×-éÊŒSJ);0ØÂ{GsûÉ-%_- s^LÕœjîus*Ù £ŸOÀø_ q$ Tヷ”¦Ç W³´[òµÚSUã¤Ç=z†Ø³ÁÓ›Á†âˆCcô7l)LÚ¯fgBnóòX»õtÕ8å©×)ØŸ,jFßJ‰# ¡ž'ÓÂôÜ™ÂìÌ_íñO¶°Zõµ;x÷rª V¯5™^‚ÖA¬–G Âî Þ¢p…0;3½rD¾.»„ÚH¼jf Å õl˜'Æ}eÄP¯ìaœÂÂì kRÉ×þT ^»ŠWPõzÒÕ(œT ˆƒ‡Ð¬£ïa”ÂÂìL×|$ÔñP»S‰WÈ)Ÿžz±t+,eû÷âã`!4ûÉô‚0Fá av†z ľ2òµCàt§o¨^']—Íùâà ´{:ÉI£·Ê)¤ã®fg5©ÍÉ#:‹„ÊÑ©fЧRâUCðÌ3ÀCúê-$B´¯Zdê6¶ÿgŒP¸B˜ÕDpÌÈ—Ñîdâ5‹]}õš'Œ|/;ŽB²·áó ‚ÏörŽÂÂìÌS¯™ë¯V£º3ºµßO'ÞZ‹×S¯y¼ÓOG!Ý_4¡‡ Oá av¨WË7˜é!ÌKL¦x*ý®p[Kd`Ƨ½À¶ì¸i(KŽÃ‡ðòññtÞ<`…+„ÙîªHzþ¿ÑÒðOå¦ZJyÊù—rAö¦Â2âð ¼\žv=Ö¡³æQ¸B˜Q»ã°ÞZ3®ßqñÖÞJܵÑåÆA!lÓàvÛ­fm|.‘õ8X„í(W›N¼µo 59ÜÎKÚ’ã ~<õÚ "a+„9[4èŽ4縞¶‡_9h†µ .1Ž.ûŽ>f+„ÙY<Äë{¦ù£¶.%oœðx¼Ê ô[¯õGòùŸ³ò•ýX!ÌØôss¸^A¾VÄF@‚‘ÐØ/©À)ìZ™¡+–‡¡[ì3!ºf…0g»‚.꺕¯ûQÖ+²¯ð<£*\+²F-%ÂcôO°„øì a¦v8˜.üV½Zºvmzm”‰xM S¿Ñïj¤[ׇRâà!D°õ†Ðo®fgö'¸ÕBƒµëªq3‹{vÉi·V G´:Ê´õáÛÕѼM¦݈Rb¨Ã¶TFâ%«Mm¾)©G´cæÀw̤ DVs6™BjèÞ×â­Å5/ñ äÔª®Ñ Ä2XFÂß¿?>Ê(>‚«£ÊÈgZYýý{…0S;˜º›o±xå$´+Ô4A¼µ°8|ƒv †-d؆\!ÌÙ‡ëAËרAÿ4g#^êYè',kšÂ2â𪣟©¡ˆ.Ckut¦þ¨x+'^,ßÙÅkªoR¼úLc´V@>„þ`}qÙÂŒMå­Ýƒb»BWcžâµ‰‰Wj·)%€ÐTÿæ§}\ZëûþMw¿ ͪ~4¯F¼V@Уž‹x+Öü»õªa)qøö{‰´”±¬ êrWUqiÔ'õwCÄ[Í+^3Ø^ “à4kÍAS×ʸ8\uÔ€Ÿ.—Ï^öñ´cî²VG³4Ô¢jt¿#Þjö bÅ[AâÄ,k:•”GÂï}l§7Y[!\€é`Uk['ª^×þݸ Re$Þ&`L¬K‰CCøyÙ}ýß×y+?/aÏz¿Ñà>+„ü ˜DÜ4þPájÞb^ñVB³Œ©Gõ–‡Í„»óÿµ_Zv.’;! î³B˜¡vu/SqEÄ[Ï+^›»\[J(Õª]}åߪJWD®:ªáQéë÷ï{ „ (¾Ï a–¦~„AšÝW~UÚÅ]ûTBXbâ³n¶ê=èµuc°Œ8\&üØþÙ¨ÕñAHî³B˜¥ÙòÚˆW¦y&›™&ÞœK3K´Q+äë¶wfñqHÕ@‚dg»»ÈÙ£TGé}Ö!Š,Í-eÓâ•jB ñ¿ãã[|Îe%tµ³nìtQ¥ÞBâÐ~|<¾Zx䜙G:f¼û¬fi È :—HñVÙŠ·ª4nMc–B{ªŒ8tuôò´Ý¨W¹|èŠä÷Y!ÌФbµ: "„VI¾â…E±F¼µžðUFáåòôÕ²ÓÂsQû§Ý axŸ Ͷ¤à b‰sOµ3Ÿx=ÏVÃ]} :7ʈÃB¨Þ¦Ôf°G!ôî³B˜¡YÀ/2:c÷DÉK¼Ž/xã™:Ó4¥ÄÊ1=õ2¥ ,ë½Âð>+„šÖ®0¨¦‚÷«ÎG¼fã ùèn_Ëàâã??`dýòqyÂð>+„šù ¶ÚÕz€wÜFÇG¶Ä ý&Ù!šRâÐ~ªr ýc÷Y!ÌдtaHÍöç¯@žaï+_ÙÄÓA ˆC· å:»MÌýCá}V34÷{lÇÙjO¼3rÛGÒût t@a‡žmùq8Á‡Þg…0C3âÅÊ­ÉøÚœâ%Ká¼åŒ æME[~zœðãóÓ¬Šÿü|`wpŸ ͪ YáÆ¸f/V.}ìàÀRã0sGa\OšîZ¹sÚšŸ ˆI7ñ"×öÁ‚} ˆ#ö’ÐÂí¦™¥L­fg¼p¥™w8ÌÝ– fšTô­F)—GÂݹŸ­.ƈt‰0s¯pþQ©Ì¥DžPM}ée+„K1§]}À~"â³-åºò+”;Ìà ×ÏXBÑwÖïúÛ áBŒ$ÞÚ%Å+f/êg©P‡†¬”8¢f+„Ù‘.6uÖiv^ñÊÙgðúŽ8{¨€8Vs¸ýÄÆ+W§«^1xP¥våuŽO}¥Ä@xA–ú–°ÂÌ­¶ZðÓG««^,–)žŠŠ×h×È×Ó/\VH>„v˜†úô°;ìïûñyì`ŸŸ—¼ÍÊÀ“.,ÃÛ›V3‰W/6À“°ÉsÓïâð ¼x¯xAßä\4öõ/þ·ÂÜMæ“õ7­P/šV5½xíÚ'ðªsEÄ@ˆÐ"/]êþm…0w«Q*áXµì¡³>ñjíê•ó•] Kʈˎƒ…ФÀãß̼íÂ|Í%Ý‚‚Ž%%¥ÞÙÄ[ií o…ƇáâãˆBf¾ÁˆN®3Ù›Ó®ü¢QŸjô«-Ð&ŠWIT×áhõÁÈë| —Gª:ê Ô‹“BìÂ6áÑcp…0? ¥«¿ï]‡¾<‡WèoN¼¶%¬vk×ò£Ý%Ä‘ê˜qùí“æÅÂe[(]#ôµš\¼ÖîËÀyf´cËÂãð!ü¤Q” ×êèx·ŸØ8éjáõÎ$^O»ô I)$ŽÂµcf†ÛOl¼tkÕ™À©wBñ¦µ[ûY¤Œ8X»Jp•ÓÂ%Xt+$ªÞ‰ÅK´+È>k´BÖè·8Âêhl°>ø¶B¸\ãWžƒzÐW;çd’g µ[ù•8"_QJ]¦­ñ߸ƒkutF»1¨véÏ6Þ4zô§"ÚeçíWo)q$'pßikÇL憵àÿFËó¨M´Ý@»0´m‰¡Oè:dèS/;ÂÏìã)XµB˜Yø#%ùÊ#]àÏŸñJî¢-µ+àýJ•Y'$ïXqp~¿ßváV3+„Ù™›èåÿ:Ã1PoÓhíþùs½Ž-ßFl-:×oá'‘ª2 ‰ƒ…ðþg`6][!Ì΄@=Œd¬¼•t‡qåÛXÓ¿¦O?¡^ÔÌ[z+„9Ü~ ÷JrM•ŠHWÚxòÙ»Τ|ñœkÛºãÔ[J+„9Ü~ ´kû l›ÊIw<ùjå‚Yù:µò΢âX!Ìáös˜ }x>±²Çxòmìk®­_¾¶EUùººèâãX!ÌáöÓiž´!Ÿ­%…Ò^¾°ÞHª^©ß@¾¤"çž³ˆ8Vs¸ýĆrE Ý¤t‡•/Éž|Íø:‰À»’Ëc…0‡ÛOlh]Ñré'ߘt8ý™&¦Ž)ÈâX!Ìáö›MÈYNKwùÆ•›È"æñ%%ıB˜Ãí'6øN+V'oK÷qù²Ù£BF³o)q¬æpû‰MÀTÊ@UWé>&_F¹ðTäS—¯A¯”8Vs¸ýôæi7.ÝÙ òÕ;0 ÞÌãɇƒÇóÇÛxK‰c…0‡ÛOnT»1éJÁî‘î/ß´tÑ<Òk _4?´ˆ8V»ß¾ç[Sï±¾of½Ë‡š;ê´—®¬:umÔß àäÛpj‘u~H¬Áì»t¢Œ8V»ßþ|Ç;ûÙË$>¼ÙT*@VºêŒ0â… ¯œÖ(W¹`e,ÐÀC(_è{Éq¬v¿}ûÇÈ6’=”^bÒAýiϵê5êºS¾xj%k"•h­õ6Áü˜RâX!ì~ûr ¤µ¡„tU†±â•�S¾]¤k:;m!¬^'_”C ‰ƒƒp»¹ßJ‡ðc<³ŽíooQÉJš×“Ø4Vºu­jqJ¼•m)-_¿‹±•oêßÓnesRUù2ÆMÅÔKå[F „u”a°¯ÕPö²{™È‡÷.Š?œv­D„>/SˆÙà]0ê=ìSÿ~X»ùKx•7ÿ R4ˆ· ç—GáÓö1[!¼ÏÎB¾Ws€£B«ŸÚ¯Ön{ $ $^Ü ²o¼b]Åk0½˜É"T¼´Q»ü8ÂwÖ?ÜýV:„¬¾?J d{5‡8j:f@ER¡žxµva@M]eŋےUu µ¿Žâ­v+’ðå¼z•x¡¯S2mmáq„mRRSø˜Âq¡þ l˜£B%¥CO¼X»ªcOËRcõÒ6X7ñáUa~¸­ÞvPrò-%ŽÂNF!…ÂS¯›Éþ´->*Ó+ ¡S„/^¤]Ý¡GÄ+ˆÖˆzo‰×©ÑåÊo XïšV¼ŠŸ=òUBýqÝlý™ÂÇÔMHá‰: \œOäèv³û¹Ó>àè©5ìeB#Ý@¼º%̺¼ ‹·nê—UP2n ^#ÅŠS¦×°BŸñÒl¸ü8zÒb¡_z ¶Ù¾È>¦…pxBúVGϧ39º‘ï6çØ‰…÷-ñºüaªkè,ô+ÆÔÛA¼F‰œJ©¹ä'^o)qtDáñª­"= T>\a?YUGï ćdÚÐxpG7'u÷w­rÒBÓ—a^ðEÅ+M÷tr²ƒx­V+F¤Œ|Ý%œx¥|K‰£+ AÀð£#!Ý!Ô:½|L á„ð™Ð9¢.´{tÓ&Ö ãB99w„Ðõjù’$aÎJAYÿlZ¼Fª~“ŒW/n[ñ⥶ä8 ±wº(>^=caË{&} c¤G}Ì %¤Wu”€¥=(¡ ú8· ´chPUó›KÝÅ+\ñÅU¯7jLU"Fá’ã@€\ÜkÎ|D__/Þ`¤<0íƒ"ØÓG>ÕÑûéá™T1éƒs³†ÕÔœõ "O¼žò+Z8%^ó)Ðî-£âõ(,#ˆ”7nóù ¾½½y„ìv4Å?´áòBÿ…‡·ä|p峂ðNBz@è<¸£_§/ùWG€‰>9ýÝê8œ\¼f€›‚¸ì8, ­¾¥è¯ZüŸ8Ï(ßßC ·8Ç)¯CWA YÒ©u†!ú8"Ò©\ ¼—„§àfØu3ï·©~"2DÚp}÷B£³I˜ pÏJ¼|K )´2 ÏQñªëê`{¥Ça‘ þz{= ŸPžQ þ !|Ýâ÷ãŸßÿý8 my¡b“N|(Ò·4bÒ‰9 ’d&<¡b؃ǹì!Äæäw í@Œ¹`JñV ¾®*& ˆbðϯŸ¯K¡Õ¾I„[Ä×þüóД·ƒ„tìã!}K¦¤cóeÂaéZ%üd»…±HfØòvÌhE8ùî°nâ­mÏD¨O€@:À'$]<ÎĽä8 -ï-ƒ¯×ÆbÄÿÑžkÚ§{ƒ§TŸ__ÕÛkd]ôwËàY^¢Ï9ƒ”tçC'B†tçãŽ|dQ}€„häŸzHEÞ‚°¦M¸¬GŸà¶(3§:‹WÄÄ{¸:Á¶ÿeAú s¿´n••¨X5ß~ªš¢¥ð|_ƒíãé§ü˜BÕ üï_US´šòG{MHºõqŒ“~våÒ‘Ù ˆ„'z3ê!9)' !V¯íÚoÕ·ß3Õ;•±ò•+×]ñ”xÍf·LE­-ì¾4"^$øP»u)qhÛÞ’«dáªþÃiÀde´¥ÂÿŸþË”7½%-mù¥é4e!„d瓾³-Â(é®#¯êìhöF_mB¡.\òPÕOÛÌ*Ž‹hÏ8þ¼¾)Ûl#¾)å¿Â5Âÿ½þ§L—g!4¤ÇéÆGºó‘E›ð£BnŸ™!Žú3žx¥Lhiœ(½uwz—âqñ¾þyWÿíÛÏWF¼8°[ÌäÇ?¿•BûÅBزq}ûÕ‚°QÀY6 „í¡–ëÿ´–„ЇБÎAhHŸÂqÁîØ 0?šZʤç5{I¤Ùóâ…ô!:‹×ê1¯üóUuȽ½¹#xVte¿U„Áüâøñ[6—þý·_Â6UËütý¥ÌüÕRh!¼¾_¯j`BØ–—ùéúÏïÖþI@hI7פ3ZÒg€p$›p0oE:̨ô“/^“>P§äƒ* „ðŒ¨ôGÅ›_?‚ÂqÛG¾Ê:âõ×{kBZK|»Jßeù–Á®¿•E $¤#£¤{ÒçÈ„Ý÷ÉtR¢â­½$Šפº»xíQ%†ðMÎÔ°ªÕF_×Ò®)›SŠÁß¿ÿíGa«ú_×wá¡LPﯳaËào á !%ý A#ÝøàHÿš£M8 !v̸ßa´K™][@’#^—>º‹—ê°¾3VX¼5¯"¿8$„¿ÓqÐêh#ñøe!Ü1‡Ã{ ÂbÐBÈöŽRÒÍ5)ÒCé_s÷ŽŽÓ1ƒGANðõºZ·§Óõ®õ!tÒåÄK’HØ¡a[Q¢G5ÎסK#UuâªáÛthx³Sˆx!Ûå‡N„ÿö‹ ÖK“ ¶Õ=`pó¤~1Cx²&)k‰rVŽáC¢)”ÕÄÚ €]þèùÀ¤#QÒ=„täcžqÂá‰Mà>¾¾va1oÐq«—,r.Ì Ú;ªå°÷Å+`s²ªj´VZ»nË@ü;Þ]¼^¯¢>TU²;ÿ Z„o<ñjõš}Ù–ª}Ë+Õ"ü·ghÚšd°ÅCf€f£¨sî3‘9L´¼«æšI„6Jey€Î˜qBDº+']þ5! ‰¬¬—¾$Ãp”¼¢Ï'>ü\ê¦ê¸Íµü^EW•Ób=\Í2+^\—ê!ÞȼçƒänÔ§ëUÐ9—¶œ× ,";¹úÓà¡!l!Z`aìMÖ´¹D¨ÊûšòBðI§>xÒ}Ø ö1ÇÊú! a!Ô¬‹­I©òþr š”Ó^»Sº£_ÊŒsvî(™i¢7â#kÑý•&ÓèËz‰—]…×â¾ÄÄ £¶·X`n‰Â“†ðW£Ü>=¹TBøf[kº¼æãw£Ôå-„Ú"øˆ‘îû@ÓC8,!„ÆÃYO:ƒ9¨² «rínC&åÈZo[=>ŸìoÂÉšùMHlow!x-:] „7QÚãiÓ¤+¸Ò y–Ò9iË ]»Œío±ä8ЂۆP"ˆ|º|C>Þp"„òÂß„Aº¨w‡Iø ¤>éÔÇËÇ ßõ?ˆ1Láyû¥=˜´ ûEÚâ@;I«­BÝþ&8ÎÍo‚!Y ‹Ä¾_‰·ê-ÞÆJ4”´x-Ù¶6çM|v³MàRòM”Úzâé|@Z1’‹ããM#H„ò†B\Aˆ|´Æ|Ò»ûxya:þ‡³Â¡ a!ÜnŒÇyK¯¾'åò­ã|ã2öÆ^믬¯¨xE JV½fOOÑC¼Æ!ñM&w•[‘\½è8ðNhrš…lÍ´Òòv)¼ìvˆB0Áhy awšô>ƹ¦á°„0îZgíÁ²» Üš­ñ¢¤zr5^hknMß¡•€¿55駈‰Wè!îÎâµZ$²$S»xñ V¼Þ]–%a·cßn¦^ÕôJ0| Œ”§vòaAïãcj‡&„k¶.NÚC¢×2,ªúE8mw;\;ÞšMÞp&Äû³Ð=ŽÂ]ãYñºáðÎ$9‡=œ^ɥ芆–(%Ž®óJå¿"ûâø`͇°“`±Ü¸$hLÛ;*wöV@9ÎÝÑÝö,_ϺÛ)ÊQ?Ñv³1yÙk‚ˆk¼ç&R¥§]º:ÏÍIé±KYT¼HÞà[ʼn‹»”8:oQ¿“AŒ`G>úlƒÿÈÜê—Éf÷_öŽKHlœîŸø×xã²¾»M˜3´WÑ¥¯'×Ãbù²—Ý/£^|¾{ÝQ£ÝÆÏ7eÄÑãe-;×ë²yI IDATŽGÏÂ<à#2Dq¦„Ý ;N8 !1Ûmâ.¶ð*7@¹ÙÐkã+ëQ ¡µ85¿ ¯ b/{D¼«Ô?Š·ªH•tùqôzmÙÚcçxô~5ÚÝ>fp@BºCøÓË}ÛB×ÙW#¡‘pø"ïFF•d]^-D‹v/~£:XaQcñVþ±â(þ%¡SCx7!„¸;'¸ïBO ” ý ¢çrÑ~ sˆ¬ Ò‡/Æ¥¹$¯9]J‰¯DíÈ>¦…pxB&\Ê„´Ë¾\ÓÍár‹^éº rU_ñ²DTAz ´«ÅëΖˆ÷Ò£#³c±²c¼ÌM‡ö1C&” ÷˜Ù£V!÷ši7Ò.zUo{°I6SêõšéP½R9éÒÒ˜ïpª”88@.ù¶\$÷#·o¸œ†wŒ—¹áð>¦ƒ0¯=fxKî1oiºö]ÎP‡Lú@ó0MÑ‘‚}ÄËíAtŠŠzâuç꺔8@Z©Ës­Ü 5ô±q€„eÒ¶×k­¯9tó1„#É„ìôÕŽÚqÂ=ß‹¯†Ò@¼&}ì÷N½&‰H¥Ríö/S‰Ã:ÅEý ¢•«_‰VD! —OsUû1qE€4Çx™$„… Â°‡3‚Èû˜.r¶¨=f þfÔæÍ)¹^å²W´÷ƒNm¦–@iöžvûŠ7|Ï-Ñ)W‹sâ­kÃ`q€8žQè÷úÚ‚¾ÆË¤ l|þû÷™PxÛ‡zgOáÄmÂQ™°c¦&ò½_½¨å½ñÁ$‘@»7Å›To TæPâµïÀvãôKƒ…ðÏ”<~ø)ñ&Ëðþý£!ìîãU¾³IAÈú(ªc掛¡=¾oöŽRùî½Mã[õºV”¾Õåd ¿‡öQê®Þ°íDÏ2ÚÅïæ­ëRâðQIíɸ|òñaI— !”•QH„Ï­uõñúú®wˆ}{ã|d aB:Ž~!Ã7Ão»è2D‘’¯¬ÉU¦?+šSÕŸ`ë+a±|µPɸ6Q¯›úEÒ‘.yÅ¢ã`!Töýû÷j·¥gFËð>ƒ-‹]}Hü$ƒropÎGã„BèNbÎ/qßû乨}¾‚—„z•¹¨|q¯âÒÕòuRÅYÄ]Br :¢¤ëWCëRâˆBøýûç÷jÛB¶ á7Íàßç®>ôòŠ_¿Þ½q>&†ppBƒÞ}¨_ËM]|}Üo‚ÛèÉíØ™’oP׺[ºH¾ø¾ÞÁd¯**]ÃáòãˆCØòT±Øi§I·2)ƒŸ»ú° ¶r>2†°!A¨«»œ‹IÌv…É"0„“¯°6·WÙ]Ò•æÔ+<*´a‚ —ëRâˆõŽª¤Fµ®ç´4K¢ !PÈ1˜ôaüÅúÈÂn„<áV¯Å`\´™öüåöe «£ ãˆ|¯fŸ@½YàƒÒ•¦äKÅËšÑ.']”GÂ0©é9-oK²L ¿„  BÉ`ó†°#!¶ ²ÉVz8£åÁÜQ·{.ÛÃHæ1‘÷I·ªlC©ƒváC(ÝÊ-è-!ŽØ`ý÷'˜Órðæ±¤ËðB׌Dð¹!Ç`Þv$äaͲþ : ´;Ò&¬¼|—/k÷K׊²“vÙìQ¹A–"â`§”¿ òˆg³»•‰@h†ëƒ®Ñ´Y} ºFámBÏ„ãÁ%|+_¼Ýåû˜t|Óâ峇Ç`q°“«Qáø]¬Ó$Q&a{½d°¯É`ÌGÞÞ&d€êèæ„öÚ†ä‹!#L[Ûaþî„z£òVº __¿MjhžyàâHAØåËý&„a™„@aïšBÆÇËÈæA88!Nྭ^V¾ÃKWË× ¸ ¤ëe=¦â¹ü8’VŸXîÉN“H™ªiêe5-…Œi!žé—2Õ ^¤ ·,¡Öÿ5|Ç‘®•o£•ëI—¼AJpm¿âˆìÿâé:¹Çg³ÄËÄ!t>÷ñ¡^_úæc¨å5ž= a‡£Âq÷˜Á?ÉX½ ˆ^ìcä;žt|©tEð¿Ø[ÑGd'4´L×Ê=>›%^&¡£PnsÑÙ‡¦ðçOßǘ[O¼ì0„yí1Óç¨!Yn.Í_ýfå;¦t|­tÁ·7)-†àâãˆmGHËÃJöÄl–h™„(ÚÝf:ø0¹ðç+õ]Â0 cÉ„líGƒŸf<+¹vòë_ÖY Ý[ÚMYRQ@0QÐ癚Í+“†(|V~ëìCCØRøŠ}L!«ïåí11´Cm¿Nd{™ªÔ3è'¸õœ¥ÄÁ"+GŸŸG,i9MEý^Ç:M"e¢šëAEag¿~Á‹ÓZ ‘é ‡ a¬cèñ£rßѰÓ*Ó+ a•ÄÐÈU^ÒŠi2õªUïµìÑ šx¬ta2J qP@TªÁuʦO¼@‰äVB¸þ™š\ä{Óǵ–Á×ó|MHá‰: \œOäèv³{ÙipTŽab'ä_)!_ë>Ö“©·}¢½pê½)]Q—Dåt7EÓ'Y r» …P]ÏèŒøð ü‰œÂá é[=ŸÎäèFþ½Ûxœc'ö_ÉôRDÕ!´vÝ× ¬}¡7EK¨×I×´¹–‡D&t+C“ÄÉ-àóéRC(¯çlLú”¾RYUGï ćdÚÐxpG7'u÷w­r@¨õˆäKDZDEÎL£^)Þ©—>Q(]Ûû¸ø8, ‚Sei’8ÖÃN“Ûe(„ÁoÁ„&‚ÄǤŽ@Ÿ #êB{°GÕ Æ…rrf ôä+h?º§ÝéÄ[“Ì%èêy·ŽÝ]QBŠ“²JÒä¤ÌféP†@øñiúB=“>ÞMg(%0ð1C&”^ÕQ¬½Z‘sá?Ž¢åkD¡þòµ;‘xmK ?ÂJeÄ¡¹|Ú-´+Ø>´Ò49©û³Yº”Á^>ÿþ±S>ÞÿX |ª£÷Ò³WÅ´ëöY41Û¥Lœ|íÖb²jx Ôk¿¹,  ˆÃrt[h+;‡J÷g³t)C <þEcóàmïzÎö›iÆ|dá„ô€ÐypG¿N_ò¯nB·†Õ¯þí6Zñ´;±xõZé†K( ‰ÃAèìi«„lÊëÍféR†¦©uöñn(üùšö‘ „÷ðÜ { .ô¾né~"]%êÕòå´;±xý'f_5fC§Â…ÆÁ· «Jö‹\èz¡ Ó¤C™'¿Mh“akÝ|h u•4îc‡$$™ Oè(öàqnF#oBHä«¥ME¢]QWSö*‚x½š’.×Û_B¶çòãHX½—êt*ƒzG?Ž::»ø0yóeÂaéZ%üd»…±HfØòìAè~¡íÌ’}íç9?sBñîu烈C*~‚â’ãpcxoÀA™Ê;Q@:•Áã„òú¿>‡|¼¿[mBô}dQ}€„häŸzHE& ä:6¤ùí¨Z™N¼:MPõú[)øJˆÏfùët‚{¶iç#H—2tÆŒºÞãP-dºåÃãP®'¼ë ÇúwMB8!1OôfÔº6œ”“€ÐÈ× ÂÈÓî´âµÃ|*“ 9ãÓù¼‚KˆÃŸ×y9†¹­Í:Q@n—¡šë)‡ß¾uñá8„©£ÔÇ,HH<žøbþÑ`zjÂP¸J@5ÌÿWí(i“VãŒxM{JM»F¾y—G°ÂáCåOΰÖ/ºÌ(^†Ð]O(üÖ͇æpÖõ„ãÒk°þ£þÊz¨¯¨ç¯«_ =óRb*¢ž-:Ž>ë Sû¿ µž°‹Ù׎Bp¢=ft"Á 2u8¤¢)Åë¦Z 7¼žæoùqôXO˜xcÒ`ë oúÈa=aI{Ìhùâ°vl{zñ $^x y‚ïÍ`1\f=ÖFöI–a üH­'LúÈd=áHF2!¿CÌãG9I“J˜ñyÄK´)XíF9\n=Ö²û¿ ¼ž0î#£õ„œ-v$ PŠþ 'Õ© ;4ˆk¹A–Gõ„ê÷švš ¾ž0â#³õ„£2unjߥŸ÷F:9ˆ­Ý¢oÉqôXO¨ !Ãï'd}d¸žpìŽ< r‚oô¨×Õº=6è¬w­!©aŠ}]YÍN.^-R*^õX|‹°”8z¬' a=!ã#ãõ„ƒP¾[ækó·zÉ"çœH Ö›@ëP¼õ´â¸±ÄŽpû .?Žë }@ÆXOúÈz=á„ð*_{¦kóÁ‰?—â©:¶:êeèìâÕ¾ç˜È×^T@=Ö€Œ°ž0ô‘ózÂA a!Ô¬‹­I©òþr š”Ó^»Sº£ð~(ãœf‹Ôä~Ó¤ÙÄ[ûŽÕcÊá+,âÅÇÑy=áç‘všï'ä|d¼žpXB8‡³™t6ºÆ»ÛI9²ÖÛVÏ'û›à^ßæ~Ìö×ÃáPÛžrl™4x½æ”^x€­UnckseÄÑy=áçõŠg³Èù,ƒ¯'d}d»žp`BÏÛ/íÁ ûEÚâ@;I«­BÝþ&8ÎÝo‚혩%_Òœr&Í'ÞÚo%°~[éšó×Râ輞ðSsqÕË¡ô¡×F|乞phBX·ãÁqÞÒ«ïI9‡|ë8·A*×ÚkÛ¥«éh°zaƒˆ9Å[;ñ $ÞÊ ²ií*kURH×~Â4=›EÏgx=aÔGŽë ‡&„p×ú8k–Ý dàÖlvCIõäj¼ÐÖÜš¾áájD)Õ«0‚´¥æ¯°â%ã2Xí¶â-%ŽÎë ?5WóÄÏÛeo¬'LùÈn=áЄpmÂÖÅI{Hµóv™PÕ/Âi»ÛáÚñÖlò†3¡þ–b84 ”<Ä[óâuKH9”Gçõ„a§Éí2 „Éõ„7|d¶žp`BØÞQ¹;°·ÊqîŽî¶²Óx·Û)ÊQ?Ñv³1yµ U _ëôhùæ*ÞVµê¡:3à”z÷uqôXO(cR²Œ¡»žYOxÓGNë ‡%$6NH÷O|Á5Þz­\TÜÖw·î71QÅÖ‡¦Ñõ£:ñ «a4ß Ä[]MÆÓ–Gõ„q@’eÑõÞzÂN>²YO8(!1Ûmâ.¶ð*7@¹Ùø×ªê¨ý…vâõ3ˆÈD¼BWßÔ5Z¼j£¥Ä±¾Ÿ°‹E!î¾`ÛB× d!t]F¼ª~Te"^èÌÅ«´–Çú~Â.Ö» ÄÝ9ÁÍxz: ä!õ +ÞüD›Uᦖg¾õ‹ÍŠm ¨Å{Õ5Ï«­¶Ÿš¦”8ú¬' — ¿ž0ê#£õ„ãÂgÂèÍî>ª!<Øé&²¥êvo5‡x55¼éŠ÷ 1æ@SJ}Ö†û¿ ¿ž÷‘ÙzÂQ!Ž»ÇLƒ5 ’É5o•ƒxu6¹êªgû'<:h·.%Ž>ï' öáý„œÜÖæµÇ oé=f´là þnˆxíÜÇÉÅ[SñB èUþ Pí¦VH}ÞOèïÿ2Æû CÙ­'ÉH&äwˆyü¨†°ÖU99Ü}UŸµ:ìëÅtðSîRâV¼B͇1mÀ«Ö†©/#Ž>ï'ôߘ4Æû ®'älY{̘_:©-†¶ p@ïø³µ81C¯¢íN1Ж‚Ä×XøšRâèó~Bi¨Ód”÷>r\O8 !vÌÀo\]CßœìWT¢¨ð‹6mSjFñÚF›øìT5Po!qôx?¡‚„.êíRƇ0ù~ÂÐGÆë G옹ãfhïî%U+úï ‰·³‰×T­x[ŽÌ\Kýw[³ÓG÷ú€Œñ~BÆG¶ë &¤ã8á2|3ü¶‹Ûî=ÙÄŒWÁ8ï|ƒÜدÌdBxÕCE´Œ8Ö÷v±®ã„BèNbÎ/qßû乨}¾ÈKB¡ês.xõL“z^ñÚ •®ãÞaÅk *£%ı¾Ÿ°‹1NÈc»õk¹©‹¯¯þMP mV¼­:`»Î™Å[ãŰP3'jÈ$ZÞ*–G÷ú&]ÊxÞXO˜ò‘ÙzÂá yB]Ýå\ì¼ÄŒVQHñ!@@Šo qП…iG÷FÞ˜4èû “>rZO89µ‡³Yn—y¢½£0_T¯œèìÃQ˜òÑVé˜]#†2ן²|T¸£@*ˆ™x9¥xaX[ç½qmÀ>´ý£„8ðZ?„—s˜Ù,7ËPÕõÉ\ñq+òͬa­•“mí¤ ªë=äv†˜^¼š$Óâ7ûtw†}òÅÇAg³8¤"9‡™Ír«Œ?cÆLÚŽäˆt.TâeÚYÙ¤Ò.J•^†9„Ê{*ñ*_æyöî ÝUhJ]Jt^'BÊ®ÕKr»Œ?wÔbØæÂ>>Þu.ŒùxoKÐãñe÷RŽÊS®Ñ„гž÷á€øâµ sUa´[—‡¿ÂÁ"é8áÞ˜”.®¢PJ {úPF}ŒØ9ªºGGÄùH÷­Ñ9õ­N aRåœE¦zV<‹ D DöcÀO¶ŒZb3¯x÷úY„y;ÖÆ0¸ð8˜·š¨OcAõs.3J–‰@h(ìëCRó1„c‚!¼·ï¦ÃY!‘.toÅ«*N“‹ù²u8ȵkSù—¥´˜žÚ#û¿$ËD l¯‡I3ý|À¬µˆé ‰áé¤þóŸN°Ê- &'Ov‰†>»q×ë©‹„žtµ4ÌšpWyšI¼f›áÈÌ“‚ËŒƒÄÁ{¿øþ/ñ21?ÍÜÑ>>^µñ>&„pB8Û‹ô½ ¹p'íbE8»A×ózÒÅê5VÍ(^œ?¸œIE”G¸õ’2í‰ïÿ/ÃCØæÁ翟u.ìêãõíýýMçÂ, ˜„û'ãB}Ý Õæzòÿ¨:J×hƒªw.ñòÚõ³ˆ¥ÄÁBhGx€Ä÷‰–‰Bø÷aÂÇëûŸí4I”a!”•QH„rо«×WH„rQçc‡%„‡ð”r'O¾‹Í 꺆7ê÷àD 4bñŒªwoÔ;­xƒüaûUhÅÄÁB¨ m˜† aÇð’exŸÁ–Å®>$~’A¹÷/çc%d8ÁGB#•ÐxõN×µ_í¢9ØnE,J$¥Ä…ðû÷ÏïU¸Ô( ![†‡ð›fðïsWÐ)Ó2øþë󱣄ðm” s2p2­}!’®_Iª|õN÷†[/TxP«×µˈ#á'Þe­#„\™(„ŠÁ¿Ï]}X[9s´ %ăP×f]ƒ3lv¾ o¬Ùi»a„Xºþ\LmÔ‹Û.Ø^nÈiòGE¦–¸ÛЩX‹Râ`¦”©›¨¤ðR–(ÃN[K0õaüÅú˜Â1!ÚÞÓÍ)Þë\p°ÔʼnŽ:!`åšiz{vuÖãýÛ-TûZ˜ù%•y”á<õ–Glˆ‚$54ÁÑvšQ× W&á@ø—@xÛ‡‚P-jšÂq¡3f,žèåa†"ÍÉ—v(Òþ¼„Z¡2ÚUêÕâÕóÕuãýëV•õîÕÂA˜æœ—å´~ˈƒ›Í"ïåoùë f³€ãeR¶×„ÏÏ}|@¯ Ãàä3fF!„BX3À´µ¤tAµYg…5ª|].Û×Þ/u–n)oÕ[H̼ÎÝv+ãEL\Ñg7œ–IB(¯—Ã}}Èቘ’¦­¥Ö>v QxÚ5ÒêГŸ+$÷z,ù ô(õÞëχg ]®XqpoLÚmåœ~¼!La Íi ʤ!ÁÇdŽEˆóÁïÒd쑳蟉jWò²‰QÒïðÿ¶îAÌßÁüûløHP|±qp€<=y{šy>h÷ ¿Z Âá}Láh†2azMà#gÍ?“«7¹ßd[srm*{é˜YÄ=Šðäkˆvlïá–ˆgqát(ƒph“e”-c=¡mémT«CÒµŠöl ùÖé˜6ùì†ô[HyÈ:Bø°éÚ„#2qÇŒ–ªI ®‡kÕ5vÁ•9ý1|÷»yBü¹„8V;ÙÄ3;<Ȉ‡26f(ßÌÇÁÃv ÒÌäÁk¥ðj3Á‡Šf;½Øé×Wï ò¥ƒçN•u(_X°ÆÂ^z- ÝZ,Xó½š:B8!B<Ýæt²c‹íŸ wŽºØ¨ÑË ¡ªU1É•Õ*ªÎUøÈ ò5·Æð0¶_™3â­Ðù2â^¯eGõ ÿ‰Žùë¼"úsyŽD†Ð@úBqmÿß EÚ?6îK¸P]éUGm'Í5†³ê%âñ<ò/ênî|ÐY%`þmC˜°‰nùq !"¯hG"än¡:¸€Ùá<„¸o†dAe맪¾_¾PÚý‰nyK¾äAʈÃ@UG.t4 aXÚýý?awBbžÌÂ'—lñ¹~ 7q¡A÷žý3a©X5ßg}ÔT·8ñÞ+ßP®]äKMD[~B.wèƒæaê:óÝ/ é!žžjî¡}ô‚Ð×.ªÀUxl 7xDX¿»¿‡‘Þ%¼¯àå+ˆ|K‰gB>Ãá#®mò¥ÿ'!|ÕÑÏ9ʳ=ª£xˆKWxQ;û²§2ëùÉé–¹/Õ0#ßbâ@mBBt4 áÁ?ú?ငLÛ1ËD_žØ|á9uÿ—Œh3˜k«Ì‘Í! ‰ã~ùëþ‡!²cfcûW͈ïâäör£É–tÀ†òÙÃû!äV¡.Á\ÙÍ@µT»NÃìa8ãumð.1Žû«£‘ëþª£# ÖwqaJù.Є!•®y‰^öeTž˜¹,ž¸i ÐP¦ØYxFN†áv”Y~kÇL'ãë‡&dºik${X¥º¿bÚ¥ò£Öõ_ÒVk×2Â0Ñ»Û3ê°üÌŒ·->Žñ`ƒ¦¸=DQ6„ã‚ y=¡ÑƒiCá.|¿#Q##Ý1ÑÞnS¹Û¡9.6w¸k<ÎôqøJ0,"ŽBè}ŠB õ— áò×béíâLR…MKDÿ7úÕ,(@¾ÍèúJ8I[ù…ÐõH3ëÑÂIDAT¹D_Ò+…2H >*Ú“hÓµˆüÞC¢N^¸î`“¯;O»-Dm²˜À— bɰ涚/!;èJ›…ð¦=¹»NáKbÐãöRŽŠvæ{b zYé²Ê5â‹I·…éR'ÛÚte„g¥|K‰£ ¥L#[9>@ºHVì¨QhäÞj_¾VzñÁ³”Et­_K]@ÉVÊ0–n ­>&÷Qщ]q»S¼‚f‘ˆöz©7~¦„8Òíøalõ‘—ÿNÛiÕšúŽIEND®B`‚mirrormagic-3.0.0/graphics/gfx_mirrormagic/MirrorScreen.png0000664000175000017500000001045613201114267023437 0ustar aeglosaeglos‰PNG  IHDR€ -!HPLTE™™™www»f"™DÿîÌ]]]DDUUU;;;ÌÌ̪ªª3ˆˆˆnnnfffÝ™LLLÿÿDDDª»»»ºM‹¡IDATxœíÝëvÛ6FaËH*ŠB# ãû¿Ó!€G’Ž;Íøý1ûéªeY”òg/Aèé'Ð\ŸžÖBã–e¹\î›oßîwçÖ5.7,—Š‹-n‚÷ñsòRq¹ü×òñu[âç(~|}zº­S}}oß¾½Ý/n½ååÎLÞê§¹ ³k¢?¯?óå뚊™ºLú[î¯t•KæSƒk]ªfçÊëÛSO€mžô ¼Ô—°-gÑåÚÜ mhëÖ·lxË;òb±ÀààË—à¼óW¢Ê ÆuàÛ=è·ÛKÃRþ,ÓmŸ½ñ’_ö>øøqÝ8…•7Ã[qå•Wg‹sgõMa–×ÕÊMc>áÿÞÏàtôÑ-¶Ÿù·âñü¡î6ɵ¹V`ÞU|N‚{v1çm I€0%Àù°6ÿHÉÅ•×z,”%ò“œß°@ÝÏËòœVcv«´¶6‹uýõׯ_kyì~F[RÎwÏ^¶ue̯ü%-±Ø-ÿœt3膭»_k}L¯ ÏBèŸ-ñ·Áˆ"—ÐýÎ뿖ܰ,šžýÖ/ñì¶„ét}€­¿_õqØ?¤ÇG^>Ž–Ø¼ Š}€ådžõ·ý_<|ö+¸p¸Äs<©C€0'Öõßö£<ξóÌÅ+(îp D¯?ÙÿÆ­oyü†xõ$^¹; 0¾F€0‡:×mRçãßßo‚·ý¼té$-O€èõ'¢Û°‚Ýù—³,@w´<¢—Kȃüêx•}ûONägËA€å4ÌsÝ@€05@ßœú; °žzžùÓë‰èôo Ì>À]§ÆKq®f—ÝòAðe™Œ—â¢g摦Gýñ¶.—%ôÏ,Ç2òj™—cbÒHV„É%ÜViºÛÿ;:åæe‚m¶gu—S~<æåS€áX¨¦wǧþUFôÏ–þJÈòèNÍüU L÷Æ Œx‹º¥Œ®Úå;9 ^×ùY¾üx‰£§‡kÁ¥Àto&ÂX€OßS»þÎ<8Cøîh˜Z ¯7% Z ß}8?ÿ÷ñ+!ýI—ñº-q#@­„›ûþÞ ð`/qûå1ž÷[Ãë¼Ämøgñÿ­ °¿{ã¿ÒçÝs·ûTDÓ6Ákè§³~0Íð3ØMšùYú—&—ð2ÎÉvrS\h[Þý½r¡ÜN·0¿â˳í_"@˜£‡-i·EM{‰ºí3s6Mt·¶ŸÏõC#FD£×nLßïÿ­ãcÜ»þàd нôçœû5`É:nèÓˆ¢›¡ž€>\ÂîÏåÅá”óA€ñØ9N·ÊÜ0h¦©9n ®„Øæy?°Ž†>0®]žñ—aæw×?¦Kqaa?n‚ý¼ñíB–ç²H€hÆM°Ûß”4Øï‚;> “‚Ÿë‡pc:ªzl_k4÷×èë1ðÙyÀz²e8 vãy@D3øþMqq0ßtq·¿âNΦSåâßi?a†Ï&…žGáÇ ºe,B=ùû%%̈•Úøv]˜ÑX€~¼’;žÿÛ nI±ކ™BæfÚ;.š꿨æìüßPÕ/ûBçãb㸿ü†ÇôÊJ€uÓ³Í7?ÊÀæ`é/Ôûù¸öù`à©í4Î÷ÈÅÙÙñPõ³c­£ð|x›\šB!+fzþ2ßùÑ-êÇ»JžÓ…8DÓfÇòÁ¾jµ ŽŽëªî[Î×2ž>”/kMKå£ûjàñ;}jtœ}:_!@˜á¦¤ÝvYõ––h㦻»7û…»ïÒL÷múÕî嬃ùÓDQnËÌ_r¾gk¿ÛÓÓÍîçø‹ÑÞ;¿…›’ДŽòê6¾9ÀÕ4Á®¿¡lnËĨî®»çCˆu_àI–Yÿ¦1i„9 ÐÅ)6ŽlÛb¯Þ¿ŽíŽWÄG•~ž+¢ª^?ÍDÕüñ9®?Mà—Ïp%@ôú?éß#@4)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤R)„BŠ!E€"@H ¤º¯??¢×ü,ˆN·ü,ˆ¦xýòyU 0òÞ‡Æm–$þ–ÿ¶®uÉ~ÑÊûòzü™ßUþÿZž Ì Œõ].©Àíy×ÒïÜ~ña Ð vJ ·iXÖ—ûý î¾Äוõ=ÁÖt.%ºÄ·”ã¶â ža†w«¿ÔßýWÛ¯1§´ò›ÖK pq‹Ïý¥Ðâê:0¾eûÌü´M°ïë³½¿ÔßV`|I±íÜ‹ïͦϳ*ã_ï[Ç! L pèoY†ï)ø×aõ ¢cÇ'iÝ—V—ÛZ3m„Ó†ôñ.îN¦œ E.aX§µþâ!Ƚl„c[AKX¶³Ö[tñÙZãjΪ]B©Ú¹”fþÀ-Aç¦xØ_)0¸•‡¯9¼úÚZóâêne:$¶[âz”a†Yæã5®Â¶ÀÆuÞÚõ¸­]Šïí[ŠvÛ]LÇkYZ›w„)öýíL5¥Ø­¤9ÀZàº:KìíÍ6×)À¼‡I€8Kxy9[ÿµmp:øM9æ­Àõjaõ=!Lç`\Ù * Ðöýæúê°¸ÖÛAHKq;Îté@¸œ„éÏ, L`¼ê»ëÏNE·‡¾«]÷Mú¸¼´/!Ÿ2ÌWåGÎtýµ¸¸;7Ø­÷j€qðÒ¶Âåœ5✄¼Æ«5:ýb{m—tòÅ—ç}Àn ˜N5m{Owv;®# ¦ïúkÇ ®­Ëö†>ÀûÒ]?¶«Æ`^±.éX˜aºÓ0íØM'¥K]€m'°hÚËÅÎÚEc;Éiç@ Æ®Oã\]æÝ¹ÓƒZ`\eöoét¬ѳ_ʵ8 .„îÚ\R3ª«ÁnÂ0Jµ&ã;ÆYrŸ÷7„)£aZ:©¿’T7ÀyÿVŸ¯ƒÑ1{éJ^ðQänó ìËmíè×Z쮯Óþa÷¬ŒÔŠ# …x« Úð•ó-À<Öù4¹éY¹Ü¼… +áö=7X·«c€Gϼ ´:^r]»|ËiÛÇd8ªZÂ÷MIp7àà4Àp–ÜY€ù(‡aÆn¶žÏõ}d øÛ»{Ff`Û|?ÀT ïÿ6îõÇ'ùDu9¯C€0­„¸ .|düìÎô,ߦ °»5øCÚ‰˜„”/ˆ¢”ð=÷WùP€‘½ ­ïˆ¢x«§¢ÓŠí`*p!@Tv)îv+snØ‚߈þÈ©çƒÓý™oˆ¢ÍŒðn€»KqÇ=~$@G€hr G»<øgäÓúÏÝïß…ØCöÞþx€q4¢˜ç†ñÓþ^÷Ô~÷Ó¹¿ns[k;Ü—]@6Áhæ¹aæk û=¼wœŽ†O¼ ª~jŽt•ìC'`ÎN¹\‡‡ã}@¤¢3èºöൿ$·0n€/ ÉG“Kh÷ ýÛç rà–Ÿ»pc:zc€å"ܸ ø^dgg÷¯ÅÁ å®u„Ù¸?ìøx€y+| #@Œ6·ÿl\þ?|_º7“M06Àw_K“^˜½ã}À}HfTLä˜Ítð'¢ÇÈ>þZ}æ8 ƒj%¤?~ŽI×rˆ¥Fh«À&ØãY™”£ÛOœùÃo±fF@Ó†c…I¼ƒ<ÏŽo_6hcµB>°ŒÞª'±ë÷–/xµé;Ò\ùùååÂäDèØOΛ¾XË&Çïf/rc„ÃÛò[/e†ÞµÝꔦ券1Å>Àá‹ Ó·‡úMp]»§/éë s»¶„åw)3#üø ”Ù±º5`©hûo‰ƉÕò]#óZo®oü¢‘o—4=¯/á–ùÏCþºÖWàÚ¦gëjj“å§5×eñé®õÓKx-À¸º{»;?n€S£åû‚,N϶û¾ê27oþšéõéÉwïT8~¿ƒ[Û¤Xõ#וÑ)ú]M±¹°ÜÝúýéiõ¿ pú²¹ü‡>O\þ°|d¼Þ¶|Н·§a^„ª|ÑB<\¹7n¦èÚLÐéû¶‘Û¶ívKÿM#·íî_&΋U ÜÏ3¾¦ç[‡Lâ{óßÊÇñ/ÿg‰Æ? sm7IEND®B`‚mirrormagic-3.0.0/graphics/gfx_mirrormagic/graphicsinfo.conf0000664000175000017500000006426513262505715023662 0ustar aeglosaeglos# ============================================================================= # Mirror Magic / Mindbender # ============================================================================= name: Mirror Magic Graphics # set title and sub-title to match the classic "Mirror Magic" artwork program_title: Mirror Magic program_copyright: 1989-2018 by Holger Schemel # window size viewport.window.width: 640 viewport.window.height: 440 # window background global.border: MirrorScreen.png # door positions viewport.door_1.x: 534 viewport.door_1.y: 60 viewport.door_2.x: 0 viewport.door_2.y: 400 viewport.door_2.width: 640 viewport.door_2.height: 40 viewport.door_2.EDITOR.x: 534 viewport.door_2.EDITOR.y: 238 viewport.door_2.EDITOR.width: 100 viewport.door_2.EDITOR.height: 102 # door graphics and animations door_1.gfx.part_1: MirrorDoor.png door_1.gfx.part_1.x: 0 door_1.gfx.part_1.y: 0 door_1.gfx.part_1.width: 100 door_1.gfx.part_1.height: 40 door_1.gfx.part_2: MirrorDoor.png door_1.gfx.part_2.x: 0 door_1.gfx.part_2.y: 40 door_1.gfx.part_2.width: 100 door_1.gfx.part_2.height: 200 door_1.gfx.part_3: MirrorDoor.png door_1.gfx.part_3.x: 0 door_1.gfx.part_3.y: 240 door_1.gfx.part_3.width: 100 door_1.gfx.part_3.height: 40 door_1.gfx.part_4: MirrorDoor.png door_1.gfx.part_4.x: 100 door_1.gfx.part_4.y: 0 door_1.gfx.part_4.width: 100 door_1.gfx.part_4.height: 40 door_1.gfx.part_5: MirrorDoor.png door_1.gfx.part_5.x: 100 door_1.gfx.part_5.y: 40 door_1.gfx.part_5.width: 100 door_1.gfx.part_5.height: 200 door_1.gfx.part_5.frames: 2 door_1.gfx.part_5.delay: 1 door_1.gfx.part_5.offset: 200 door_1.gfx.part_5.anim_mode: linear door_1.gfx.part_6: MirrorDoor.png door_1.gfx.part_6.x: 100 door_1.gfx.part_6.y: 240 door_1.gfx.part_6.width: 100 door_1.gfx.part_6.height: 40 door_1.gfx.part_7: [NONE] door_1.gfx.part_8: [NONE] door_1.part_1.x: 0 door_1.part_1.y: 0 door_1.part_1.step_xoffset: 2 door_1.part_1.step_yoffset: 0 door_1.part_1.step_delay: 10 door_1.part_1.draw_order: 1 door_1.part_2.x: 0 door_1.part_2.y: 40 door_1.part_2.step_xoffset: 2 door_1.part_2.step_yoffset: 0 door_1.part_2.step_delay: 10 door_1.part_2.draw_order: 2 door_1.part_3.x: 0 door_1.part_3.y: 240 door_1.part_3.step_xoffset: 2 door_1.part_3.step_yoffset: 0 door_1.part_3.step_delay: 10 door_1.part_3.draw_order: 1 door_1.part_4.x: 0 door_1.part_4.y: 0 door_1.part_4.step_xoffset: -2 door_1.part_4.step_yoffset: 0 door_1.part_4.step_delay: 10 door_1.part_4.draw_order: 2 door_1.part_5.x: 0 door_1.part_5.y: 40 door_1.part_5.step_xoffset: -2 door_1.part_5.step_yoffset: 0 door_1.part_5.step_delay: 10 door_1.part_5.draw_order: 1 door_1.part_6.x: 0 door_1.part_6.y: 240 door_1.part_6.step_xoffset: -2 door_1.part_6.step_yoffset: 0 door_1.part_6.step_delay: 10 door_1.part_6.draw_order: 2 door_1.part_7.x: -1 door_1.part_7.y: -1 door_1.part_8.x: -1 door_1.part_8.y: -1 door_1.panel.start_step: 230 # do not use any multi-part door animations, as we use "naked" door panels door_2.gfx.part_1: [NONE] door_2.gfx.part_2: [NONE] door_2.gfx.part_3: [NONE] door_2.gfx.part_4: [NONE] door_2.gfx.part_5: [NONE] door_2.gfx.part_6: [NONE] door_2.gfx.part_7: [NONE] door_2.gfx.part_8: [NONE] # door panel animations for simple "slide up" and "slide down" effect door_2.panel.start_step: 0 door_2.panel.step_yoffset: -2 door_2.panel.step_delay: 10 # (no ugly border workaround needed) door_2.top_border_correction: [NONE] # main game panel background background.PANEL: MirrorDoor.png background.PANEL.x: 400 background.PANEL.y: 0 background.PANEL.width: 100 background.PANEL.height: 280 # game panel and tape recorder background background.TAPE: MirrorPanel.png background.TAPE.x: 0 background.TAPE.y: 0 background.TAPE.width: 640 background.TAPE.height: 40 # editor palette and toolbox background background.PALETTE: MirrorDoor.png background.PALETTE.x: 600 background.PALETTE.y: 0 background.PALETTE.width: 100 background.PALETTE.height: 280 background.TOOLBOX: MirrorDoor.png background.TOOLBOX.x: 800 background.TOOLBOX.y: 178 background.TOOLBOX.width: 100 background.TOOLBOX.height: 102 # game panel button and text positions game.button.gfx.save: MirrorPanel.png game.button.gfx.save.x: 195 game.button.gfx.save.y: 45 game.button.gfx.save.width: 45 game.button.gfx.save.height: 30 game.button.gfx.save.pressed_yoffset: -40 game.button.gfx.load: MirrorPanel.png game.button.gfx.load.x: 245 game.button.gfx.load.y: 45 game.button.gfx.load.width: 45 game.button.gfx.load.height: 30 game.button.gfx.load.pressed_yoffset: -40 game.button.gfx.panel_stop: MirrorDoor.png game.button.gfx.panel_stop.x: 434 game.button.gfx.panel_stop.y: 122 game.button.gfx.panel_stop.width: 32 game.button.gfx.panel_stop.height: 32 game.button.gfx.panel_stop.pressed_xoffset: 100 game.button.gfx.panel_sound_music: MirrorDoor.png game.button.gfx.panel_sound_music.x: 406 game.button.gfx.panel_sound_music.y: 126 game.button.gfx.panel_sound_music.width: 24 game.button.gfx.panel_sound_music.height: 24 game.button.gfx.panel_sound_music.pressed_xoffset: 100 game.button.gfx.panel_sound_music.active_xoffset: 64 game.button.gfx.panel_sound_simple: MirrorDoor.png game.button.gfx.panel_sound_simple.x: 406 game.button.gfx.panel_sound_simple.y: 126 game.button.gfx.panel_sound_simple.width: 24 game.button.gfx.panel_sound_simple.height: 24 game.button.gfx.panel_sound_simple.pressed_xoffset: 100 game.button.gfx.panel_sound_simple.active_xoffset: 64 game.button.stop.x: 5 game.button.stop.y: 5 game.button.pause.x: 35 game.button.pause.y: 5 game.button.play.x: 65 game.button.play.y: 5 game.button.undo.x: 5 game.button.undo.y: 5 game.button.pause2.x: 35 game.button.pause2.y: 5 game.button.redo.x: 65 game.button.redo.y: 5 game.button.sound_music.x: 100 game.button.sound_music.y: 5 game.button.sound_loops.x: 130 game.button.sound_loops.y: 5 game.button.sound_simple.x: 160 game.button.sound_simple.y: 5 game.button.save.x: 195 game.button.save.y: 5 game.button.load.x: 245 game.button.load.y: 5 game.button.panel_stop.x: 34 game.button.panel_stop.y: 122 game.button.panel_sound_music.x: 6 game.button.panel_sound_music.y: 126 game.button.panel_sound_simple.x: 70 game.button.panel_sound_simple.y: 126 game.panel.level_number.x: 50 game.panel.level_number.y: 23 game.panel.gems.x: 50 game.panel.gems.y: 63 game.panel.gems.digits: 3 game.panel.score.x: 50 game.panel.score.y: 101 game.panel.score.digits: 4 game.panel.time.x: -1 game.panel.time.y: -1 game.panel.inventory_count.x: -1 game.panel.inventory_count.y: -1 game.panel.time_anim.x: 0 game.panel.time_anim.y: 158 game.panel.time_anim.direction: up game.panel.time_anim.class: mm_engine_only game.panel.health_anim.x: 50 game.panel.health_anim.y: 158 game.panel.health_anim.direction: up game.panel.health_anim.class: mm_engine_only game.panel.health_anim.style: reverse gfx.game.panel.time_anim: MirrorDoor.png gfx.game.panel.time_anim.x: 400 gfx.game.panel.time_anim.y: 158 gfx.game.panel.time_anim.width: 50 gfx.game.panel.time_anim.height: 100 gfx.game.panel.time_anim.active: MirrorDoor.png gfx.game.panel.time_anim.active.x: 500 gfx.game.panel.time_anim.active.y: 158 gfx.game.panel.time_anim.active.width: 50 gfx.game.panel.time_anim.active.height: 100 gfx.game.panel.health_anim: MirrorDoor.png gfx.game.panel.health_anim.x: 450 gfx.game.panel.health_anim.y: 158 gfx.game.panel.health_anim.width: 50 gfx.game.panel.health_anim.height: 100 gfx.game.panel.health_anim.active: MirrorDoor.png gfx.game.panel.health_anim.active.x: 550 gfx.game.panel.health_anim.active.y: 158 gfx.game.panel.health_anim.active.width: 50 gfx.game.panel.health_anim.active.height: 100 # tape panel text and button positions tape.button.gfx.extra: MirrorPanel.png tape.button.gfx.extra.x: 30 tape.button.gfx.extra.y: 120 tape.button.gfx.extra.width: 30 tape.button.gfx.extra.height: 30 tape.button.gfx.extra.pressed_xoffset: -30 tape.button.gfx.eject: MirrorPanel.png tape.button.gfx.eject.x: 485 tape.button.gfx.eject.y: 45 tape.button.gfx.eject.width: 30 tape.button.gfx.eject.height: 30 tape.button.gfx.eject.pressed_yoffset: -40 tape.button.gfx.stop: MirrorPanel.png tape.button.gfx.stop.x: 515 tape.button.gfx.stop.y: 45 tape.button.gfx.stop.width: 30 tape.button.gfx.stop.height: 30 tape.button.gfx.stop.pressed_yoffset: -40 tape.button.gfx.pause: MirrorPanel.png tape.button.gfx.pause.x: 545 tape.button.gfx.pause.y: 45 tape.button.gfx.pause.width: 30 tape.button.gfx.pause.height: 30 tape.button.gfx.pause.pressed_yoffset: -40 tape.button.gfx.record: MirrorPanel.png tape.button.gfx.record.x: 575 tape.button.gfx.record.y: 45 tape.button.gfx.record.width: 30 tape.button.gfx.record.height: 30 tape.button.gfx.record.pressed_yoffset: -40 tape.button.gfx.play: MirrorPanel.png tape.button.gfx.play.x: 605 tape.button.gfx.play.y: 45 tape.button.gfx.play.width: 30 tape.button.gfx.play.height: 30 tape.button.gfx.play.pressed_yoffset: -40 tape.label.gfx.date: MirrorPanel.png tape.label.gfx.date.x: 295 tape.label.gfx.date.y: 45 tape.label.gfx.date.width: 90 tape.label.gfx.date.height: 30 tape.button.eject.x: 485 tape.button.eject.y: 5 tape.button.stop.x: 515 tape.button.stop.y: 5 tape.button.pause.x: 545 tape.button.pause.y: 5 tape.button.record.x: 575 tape.button.record.y: 5 tape.button.play.x: 605 tape.button.play.y: 5 tape.symbol.pause.x: 425 tape.symbol.pause.y: 5 tape.symbol.record.x: 410 tape.symbol.record.y: 5 tape.symbol.play.x: 442 tape.symbol.play.y: 5 tape.symbol.fast_forward.x: 424 tape.symbol.fast_forward.y: 6 tape.symbol.warp_forward.x: 424 tape.symbol.warp_forward.y: 6 tape.symbol.warp_forward_blind.x: 424 tape.symbol.warp_forward_blind.y: 6 tape.symbol.pause_before_end.x: 424 tape.symbol.pause_before_end.y: 6 tape.label.pause.x: 390 tape.label.pause.y: 25 tape.label.record.x: 390 tape.label.record.y: 5 tape.label.play.x: 455 tape.label.play.y: 5 tape.label.fast_forward.x: 390 tape.label.fast_forward.y: 6 tape.label.warp_forward.x: 390 tape.label.warp_forward.y: 6 tape.label.warp_forward_blind.x: 390 tape.label.warp_forward_blind.y: 6 tape.label.pause_before_end.x: 390 tape.label.pause_before_end.y: 6 tape.label.single_step.x: 442 tape.label.single_step.y: 6 tape.label.date.x: 295 tape.label.date.y: 5 tape.label.time.x: 430 tape.label.time.y: 19 tape.text.date.x: 297 tape.text.date.y: 19 tape.text.date.align: left tape.text.date.valign: top tape.text.date.digits: -1 tape.text.date.font: font.tape_recorder tape.text.time.x: 429 tape.text.time.y: 19 tape.text.time.align: left tape.text.time.valign: top tape.text.time.digits: -1 tape.text.time.font: font.tape_recorder # show game buttons inside tape panel tape.show_game_buttons: true #------------------------------------------------------------------------------ viewport.playfield.width: 516 viewport.playfield.height: 388 main.text.level_info_1.x: 512 main.text.level_info_1.y: 296 main.text.level_info_1.align: right main.text.level_info_2.x: 256 main.text.level_info_2.y: 352 main.text.title_1.x: 256 main.text.title_2.x: 256 main.text.title_3.x: 256 preview.x: 384 preview.y: 192 preview.xsize: 16 preview.ysize: 12 preview.tile_size: 8 preview.align: left global.num_toons: 6 font.text_1.INFO: RocksFontSmall.png font.text_1.INFO.x: 0 font.text_1.INFO.y: 140 font.text_1.INFO.width: 14 font.text_1.INFO.height: 14 font.text_4.INFO: RocksFontSmall.png font.text_4.INFO.x: 0 font.text_4.INFO.y: 70 font.text_4.INFO.width: 13 font.text_4.INFO.xoffset: 14 font.text_4.INFO.height: 14 main.button.prev_level.x: 352 main.button.prev_level.y: 96 main.button.next_level.x: 480 main.button.next_level.y: 96 main.text.level_number.x: 384 main.text.level_number.y: 96 main.text.first_level.x: 300 main.text.first_level.y: 98 main.text.last_level.x: 300 main.text.last_level.y: 112 font.menu_2.width: 15 font.menu_2.xoffset: 16 font.menu_2.active.width: 15 font.menu_2.active.xoffset: 16 font.option_on.width: 30 font.option_on.xoffset: 32 font.option_on.draw_xoffset: 6 font.option_off.width: 30 font.option_off.xoffset: 32 font.option_off.draw_xoffset: 6 font.option_on_narrow: RocksFontMedium.png font.option_on_narrow.x: 0 font.option_on_narrow.y: 480 font.option_on_narrow.width: 16 font.option_on_narrow.height: 32 font.option_on_narrow.draw_xoffset: 6 font.option_off_narrow: RocksFontMedium.png font.option_off_narrow.x: 0 font.option_off_narrow.y: 160 font.option_off_narrow.width: 16 font.option_off_narrow.height: 32 font.option_off_narrow.draw_xoffset: 6 menu.top_spacing.INFO: 84 menu.paragraph_spacing.INFO: -2 menu.headline1_spacing.INFO: -1 menu.headline2_spacing.INFO: 12 menu.extra_spacing.INFO: 0 menu.draw_xoffset.INFO[VERSION]: -20 menu.paragraph_spacing.INFO[VERSION]: -1 menu.headline2_spacing.INFO[VERSION]: 4 menu.top_spacing.INFO[ELEMENTS]: 76 menu.headline2_spacing.INFO[ELEMENTS]: 6 # editor settings editor.settings.headline.x: 256 editor.settings.headline.y: 4 editor.settings.element_graphic.x: 16 editor.settings.element_graphic.y: 44 editor.settings.tabs.x: 16 editor.settings.tabs.y: 40 editor.settings.tooltip.x: -8 editor.settings.tooltip.y: 392 editor.gadget.line_spacing: 1 editor.palette.x: 5 editor.palette.y: 26 editor.palette.rows: 6 editor.palette.element_left.x: -1000 editor.palette.element_left.y: -1000 editor.palette.element_middle.x: -1000 editor.palette.element_middle.y: -1000 editor.palette.element_right.x: -1000 editor.palette.element_right.y: -1000 editor.button.properties.x: -1000 editor.button.properties.y: -1000 gfx.editor.button.element_left: RocksDoor.png gfx.editor.button.element_left.x: 525 gfx.editor.button.element_left.y: 30 gfx.editor.button.element_left.width: 20 gfx.editor.button.element_left.height: 20 gfx.editor.button.element_left.pressed_xoffset: -20 gfx.editor.button.element_middle: RocksDoor.png gfx.editor.button.element_middle.x: 525 gfx.editor.button.element_middle.y: 30 gfx.editor.button.element_middle.width: 20 gfx.editor.button.element_middle.height: 20 gfx.editor.button.element_middle.pressed_xoffset:-20 gfx.editor.button.element_right: RocksDoor.png gfx.editor.button.element_right.x: 525 gfx.editor.button.element_right.y: 30 gfx.editor.button.element_right.width: 20 gfx.editor.button.element_right.height: 20 gfx.editor.button.element_right.pressed_xoffset:-20 editor.no_toolbox_button: RocksDoor.png editor.no_toolbox_button.x: 506 editor.no_toolbox_button.y: 286 editor.no_toolbox_button.width: 22 editor.no_toolbox_button.height: 20 gfx.editor.button.draw_single: MirrorDoor.png gfx.editor.button.draw_single.x: 806 gfx.editor.button.draw_single.y: 178 gfx.editor.button.draw_single.width: 22 gfx.editor.button.draw_single.height: 20 gfx.editor.button.draw_single.pressed_xoffset: -100 gfx.editor.button.draw_single.active_yoffset: -60 gfx.editor.button.draw_line: MirrorDoor.png gfx.editor.button.draw_line.x: 828 gfx.editor.button.draw_line.y: 178 gfx.editor.button.draw_line.width: 22 gfx.editor.button.draw_line.height: 20 gfx.editor.button.draw_line.pressed_xoffset: -100 gfx.editor.button.draw_line.active_yoffset: -60 gfx.editor.button.rotate_up: MirrorDoor.png gfx.editor.button.rotate_up.x: 850 gfx.editor.button.rotate_up.y: 178 gfx.editor.button.rotate_up.width: 22 gfx.editor.button.rotate_up.height: 20 gfx.editor.button.rotate_up.pressed_xoffset: -100 gfx.editor.button.rotate_up.active_yoffset: -60 gfx.editor.button.draw_arc: MirrorDoor.png gfx.editor.button.draw_arc.x: 872 gfx.editor.button.draw_arc.y: 178 gfx.editor.button.draw_arc.width: 22 gfx.editor.button.draw_arc.height: 20 gfx.editor.button.draw_arc.pressed_xoffset: -100 gfx.editor.button.draw_arc.active_yoffset: -60 gfx.editor.button.flood_fill: MirrorDoor.png gfx.editor.button.flood_fill.x: 806 gfx.editor.button.flood_fill.y: 198 gfx.editor.button.flood_fill.width: 22 gfx.editor.button.flood_fill.height: 20 gfx.editor.button.flood_fill.pressed_xoffset: -100 gfx.editor.button.flood_fill.active_yoffset: -60 gfx.editor.button.rotate_left: MirrorDoor.png gfx.editor.button.rotate_left.x: 828 gfx.editor.button.rotate_left.y: 198 gfx.editor.button.rotate_left.width: 22 gfx.editor.button.rotate_left.height: 20 gfx.editor.button.rotate_left.pressed_xoffset: -100 gfx.editor.button.rotate_left.active_yoffset: -60 gfx.editor.button.grab_brush: MirrorDoor.png gfx.editor.button.grab_brush.x: 850 gfx.editor.button.grab_brush.y: 198 gfx.editor.button.grab_brush.width: 22 gfx.editor.button.grab_brush.height: 20 gfx.editor.button.grab_brush.pressed_xoffset: -100 gfx.editor.button.grab_brush.active_yoffset: -60 gfx.editor.button.rotate_right: MirrorDoor.png gfx.editor.button.rotate_right.x: 872 gfx.editor.button.rotate_right.y: 198 gfx.editor.button.rotate_right.width: 22 gfx.editor.button.rotate_right.height: 20 gfx.editor.button.rotate_right.pressed_xoffset: -100 gfx.editor.button.rotate_right.active_yoffset: -60 gfx.editor.button.draw_rectangle: MirrorDoor.png gfx.editor.button.draw_rectangle.x: 806 gfx.editor.button.draw_rectangle.y: 218 gfx.editor.button.draw_rectangle.width: 22 gfx.editor.button.draw_rectangle.height: 20 gfx.editor.button.draw_rectangle.pressed_xoffset:-100 gfx.editor.button.draw_rectangle.active_yoffset:-60 gfx.editor.button.draw_filled_box: MirrorDoor.png gfx.editor.button.draw_filled_box.x: 828 gfx.editor.button.draw_filled_box.y: 218 gfx.editor.button.draw_filled_box.width: 22 gfx.editor.button.draw_filled_box.height: 20 gfx.editor.button.draw_filled_box.pressed_xoffset:-100 gfx.editor.button.draw_filled_box.active_yoffset:-60 gfx.editor.button.rotate_down: MirrorDoor.png gfx.editor.button.rotate_down.x: 850 gfx.editor.button.rotate_down.y: 218 gfx.editor.button.rotate_down.width: 22 gfx.editor.button.rotate_down.height: 20 gfx.editor.button.rotate_down.pressed_xoffset: -100 gfx.editor.button.rotate_down.active_yoffset: -60 gfx.editor.button.pick_element: MirrorDoor.png gfx.editor.button.pick_element.x: 872 gfx.editor.button.pick_element.y: 218 gfx.editor.button.pick_element.width: 22 gfx.editor.button.pick_element.height: 20 gfx.editor.button.pick_element.pressed_xoffset: -100 gfx.editor.button.pick_element.active_yoffset: -60 gfx.editor.button.undo: MirrorDoor.png gfx.editor.button.undo.x: 805 gfx.editor.button.undo.y: 243 gfx.editor.button.undo.width: 30 gfx.editor.button.undo.height: 16 gfx.editor.button.undo.pressed_xoffset: -100 gfx.editor.button.conf: MirrorDoor.png gfx.editor.button.conf.x: 835 gfx.editor.button.conf.y: 243 gfx.editor.button.conf.width: 30 gfx.editor.button.conf.height: 16 gfx.editor.button.conf.pressed_xoffset: -100 gfx.editor.button.save: MirrorDoor.png gfx.editor.button.save.x: 865 gfx.editor.button.save.y: 243 gfx.editor.button.save.width: 30 gfx.editor.button.save.height: 16 gfx.editor.button.save.pressed_xoffset: -100 gfx.editor.button.clear: MirrorDoor.png gfx.editor.button.clear.x: 805 gfx.editor.button.clear.y: 259 gfx.editor.button.clear.width: 30 gfx.editor.button.clear.height: 16 gfx.editor.button.clear.pressed_xoffset:-100 gfx.editor.button.test: MirrorDoor.png gfx.editor.button.test.x: 835 gfx.editor.button.test.y: 259 gfx.editor.button.test.width: 30 gfx.editor.button.test.height: 16 gfx.editor.button.test.pressed_xoffset: -100 gfx.editor.button.exit: MirrorDoor.png gfx.editor.button.exit.x: 865 gfx.editor.button.exit.y: 259 gfx.editor.button.exit.width: 30 gfx.editor.button.exit.height: 16 gfx.editor.button.exit.pressed_xoffset: -100 editor.button.element_left.x: 5 editor.button.element_left.y: 152 editor.button.element_middle.x: 40 editor.button.element_middle.y: 152 editor.button.element_right.x: 75 editor.button.element_right.y: 152 editor.button.draw_single.x: 6 editor.button.draw_single.y: 0 editor.button.draw_line.x: 28 editor.button.draw_line.y: 0 editor.button.rotate_up.x: 50 editor.button.rotate_up.y: 0 editor.button.draw_arc.x: 72 editor.button.draw_arc.y: 0 editor.button.flood_fill.x: 6 editor.button.flood_fill.y: 20 editor.button.rotate_left.x: 28 editor.button.rotate_left.y: 20 editor.button.grab_brush.x: 50 editor.button.grab_brush.y: 20 editor.button.rotate_right.x: 72 editor.button.rotate_right.y: 20 editor.button.draw_rectangle.x: 6 editor.button.draw_rectangle.y: 40 editor.button.draw_filled_box.x: 28 editor.button.draw_filled_box.y: 40 editor.button.rotate_down.x: 50 editor.button.rotate_down.y: 40 editor.button.pick_element.x: 72 editor.button.pick_element.y: 40 editor.button.undo.x: 5 editor.button.undo.y: 65 editor.button.conf.x: 35 editor.button.conf.y: 65 editor.button.save.x: 65 editor.button.save.y: 65 editor.button.clear.x: 5 editor.button.clear.y: 81 editor.button.test.x: 35 editor.button.test.y: 81 editor.button.exit.x: 65 editor.button.exit.y: 81 editor.button.draw_connected.x: -1000 editor.button.draw_connected.y: -1000 editor.button.draw_text.x: -1000 editor.button.draw_text.y: -1000 editor.button.zoom_level.x: -1000 editor.button.zoom_level.y: -1000 editor.button.draw_random.x: -1000 editor.button.draw_random.y: -1000 mirrormagic-3.0.0/graphics/gfx_mirrormagic/MirrorPanel.png0000664000175000017500000000546312306200307023255 0ustar aeglosaeglos‰PNG  IHDR€K7TG‹¥ßB/à+Ͻ¥ÏÑâ@é·Ð¬Z+`ø8qS4CúE¬lQ$#Gú}r2 'n‹¦O| íª‰ Iœ>¼½RQKÀÐqâÆhòôAI]gW¶HlH þ>V²Ÿw/\ÇZ Ó'íVG¥¬>Ç,Ž6ïø*¸k´²…VA9ðþçڻѽfYrm_/ziú‡kcZÜNo´ë’é·q¼š ¶!½6¡ÓÛ›x÷O}°Ù¼þ÷ßÙ]dK4£€õ±sµ%*àþ¦M[¿úDÅ }ч&4;G§u·Bxlš:= ÝÎôO÷´®€ÚMWß«‘ÍÏçÁ"[¢¹T±9v×’«4~ZÐn7W@kàï^G@#šc2¾ŒÛd=`q‚×ô€æþR,Ü,ý‹þh9²ÎjTÁ•\Ý·€þc@#QÄcÀ£ ø3TÐ'àO5\dK´ÿxËn º'Í:ÖÆö˜vÛàmÚoŽ3 6´gÁ¶€Î,XÃã³`§Ý  }§,­g÷×ü»½ùçÍìëâ 8PÐ+ mÑæh÷ñ–Ý ôOf èkÚo0 Sé#4>¶ÒÞO±lô³œèRè¼!à©l9½—©ú_¬M¨Ú,•›@ã‹jÞ [Ýžwæs«}MÕ+òÆHo}Š¥³›" Øû§ œèÒ8ܶ¡D¦EF´¬Bѱ¶–Ne¹N@o‹Ï°t÷R$oc™íÞ)•€Æûø-‹LߎGÇÚÎÕÉÜê XúwÒæÝÿÏðßhf³wJ'`ÿ>Þ!øT[tr†àj­<>«ö+Ÿ€¥£Sù~¥ì#hŸq¯„yBÎRÞÈB—®ƒ#`9ØG‘vÿí6ì'z§¼Õi#šhUžUØGϵcm;=“~ë¨×wB@µ¨W@ãØßøCÎRþÈ2¯ƒ-`9¶“ò ¨ßWj~Ö9–ge•=—>Û¨Ñ?Z§aô V¤þEÀÙ;ø÷ 蟄¨1÷tªÇד;7m*¥ØS ²½€Á¶ÎcÊóîþô ÁyºO~‡€7΂]>l; ÓRuœÍoz@3Z•ƒÐlëëÛ•8¤€Sé3¸“IÈÔ‰è>ƒ³ùÍ1 }ÏIÇ€f[ß1`§š!O¿¾ÎVVÀ;xåîßÅi˜Ð¥¸SwÚ;7³`'ê΂Mý³`çlr; ™%à¼ÑigÁWû¾Ëu:ÇTúÊŸˆžs3B¥Nã¹= ­ÔåÊm—â|ökl ¨^»xç\ŠKÜ6Ú :C9¦Òç0Ê¥8›£ƒEªŸ¿€F´ 8Òvp3‚! ’uJÀ‘Û7#ä°øUƸÁG$»Ñz¤\ ÖÛù´YOÔJ\wV¶È! sÍ!xŽ€7^2 Éë‡m‰~Ž€êAß*önàá¬W{—G?UÀ$Ç€Þ <œ€±ÓçÐ7ÍìöŒY°–ÍúûϘ³à•Ÿqš(.hQ$#Gúý ú¥mÑ ép*ýîü_ðKd¶Ds¤Kê°²EbC§OÙ¬jŸáïÙÄîÒçhq ô[è|¾Af;»KŸ£ÅÒo¡@†ZÀý~ƒ+|>¯"|–Bú@ uB@ê„€(Ô IÓâ@é·Ð ˜ðswU0¨²>¦NHp‘H-_+Kœ~b¥¢æÝ0¡ãÄ½× YRsam‹Ä†Œ‡ÿ|}}ýÙš~—U^s;Ö’[[Ö¶Ø ÀCF£ßo÷ÛßoõÛårQõ/Ùéwy3Œ˜€Ñë„äð½çÅ£~¸Ô4ÍNî_+úÅšßfýP«£‚¦€÷ûý»~¸ßõ³Ö¿[ýÂýöíðb*Ø&×kS¿1úöwü2 Ù¬šý_aÜßt£i£NdXÿÜûg5þÞ[þþñ h(è¼ëãò0üF@óµC 8°°ð¡—÷ ØòuSÞ¾Fìt,”8L½NH^Ûý)´ }À /K@5@ªŸGÛ:= ‚MïãZ÷ºþß?g¯láм¦4ßð— ¸åOãåê„´‹Ì«Ò`´Ð`¬Òâ°x¤8œ+àNª4DP¬NH³ÈÌ* >ÃUœY°) = ¶tfÁzî:¿á,¸põ,¸srRÀ½TiH  P¥Ó¬* >Ã_Ž¥LC8}ü󀻩ÒD@‘:!Z§é* ~½-v!`¬+!ý'°Ÿ* ‰¨2K§å-ö!`”ôúCÜQ•†df¯Ò ÁÝz¨o•†ƒ ¸§* Ì\'DOB¦«4L¨PŸu3ŸBÎRÞÈB—®ƒµwU¥!³€†D±ë„œúÓ0ÓU¶¨Žý§ÅxÈYÊY&àâuXº?BÀÌuBÌÆ”Ç÷%ù[†àß/ Ï‚³× ÑïQ ¼q&÷3 ¨ÒΫÒð™N¥O?ïå4ŒHn<§Jƒ_Ày'¢0 à.ND Õ Ñ³àé* –€êåp•†l³à‹}áNßåj]sÛ4 N(à.Å‰Õ Ñ³àé* >ÃU²õ€vÃæ˜JŸCÀ(7#øØ,»NHh f­ÐŒ"±Ý@©ègÔ ùõ˜kÁs ¼1ΑhKôsTúVÁèCðèJE?£NÈg ˜âpt¥¢Ü’?·E»G‡ÓÌnÿǘ÷²YÎs¼ò#NEÀ¹-ŠdäH¿u%ß2¼¶EbC§ße•SÀß]'dÑ· ¯l‘ØÄéÓí€Í;:!)Z(ý:u™ ê„§ßB' € Ô Y¨²P'$¡NHB…Y0ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(¢ ˆ‚€ ‚(Ô Y¨²áðD€­„ Uy&,2 ‡át,\òZzÝá—UG@H ‚(¢ ˆ‚€ Ê<JõÊO B4^AÇú`E@ˆË+蘪(B\^AÇŒ`E@ˆË+è˜l¢qy³‚u!.¯ cvðE@ˆË+èBb–È ÑY03 øÌŸ„p0û4 '¢!sODs)’0óR7#@æÝŒà!Ü¢ ˆ‚€ ‚(¢Lúî,„í¼‚Ž…¿;KzÝ Äÿ^CïwøeÞIEND®B`‚mirrormagic-3.0.0/src/0000755000175000017500000000000013263214225014122 5ustar aeglosaeglosmirrormagic-3.0.0/src/network.h0000644000175000017500000000175613263212010015763 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // network.h // ============================================================================ #ifndef NETWORK_H #define NETWORK_H #include "main.h" #define NETWORK_STOP_BY_PLAYER 0 #define NETWORK_STOP_BY_ERROR 1 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(int); void SendToServer_MovePlayer(byte); void HandleNetworking(void); #endif mirrormagic-3.0.0/src/files.h0000644000175000017500000000474413263212010015374 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // files.h // ============================================================================ #ifndef FILES_H #define FILES_H #include "main.h" #define LEVEL_PACKED_START 100 #define PACKED_LEVELS(x) (LEVEL_PACKED_START + x) #define LEVEL_FILE_TYPE_RND_PACKED PACKED_LEVELS(LEVEL_FILE_TYPE_RND) #define LEVEL_FILE_TYPE_EM_PACKED PACKED_LEVELS(LEVEL_FILE_TYPE_EM) #define IS_SINGLE_LEVEL_FILE(x) (x < LEVEL_PACKED_START) #define IS_PACKED_LEVEL_FILE(x) (x > LEVEL_PACKED_START) void setElementChangePages(struct ElementInfo *, int); void setElementChangeInfoToDefaults(struct ElementChangeInfo *); void copyElementInfo(struct ElementInfo *, struct ElementInfo *); char *getDefaultLevelFilename(int); char *getLocalLevelTemplateFilename(); char *getGlobalLevelTemplateFilename(); void LoadLevelFromFilename(struct LevelInfo *, char *); void LoadLevel(int); void LoadLevelTemplate(int); void LoadLevelInfoOnly(int); void SaveLevel(int); void SaveLevelTemplate(); void SaveNativeLevel(struct LevelInfo *); void DumpLevel(struct LevelInfo *); boolean SaveLevelChecked(int); void CopyNativeLevel_RND_to_Native(struct LevelInfo *); void CopyNativeLevel_Native_to_RND(struct LevelInfo *); void LoadTapeFromFilename(char *); void LoadTape(int); void LoadSolutionTape(int); void SaveTape(int); void DumpTape(struct TapeInfo *); boolean SaveTapeChecked(int); boolean SaveTapeChecked_LevelSolved(int); void LoadScore(int); void SaveScore(int); void LoadSetupFromFilename(char *); void LoadSetup(); void SaveSetup(); void LoadSetup_AutoSetup(); void SaveSetup_AutoSetup(); void LoadSetup_EditorCascade(); void SaveSetup_EditorCascade(); void SaveSetup_AddGameControllerMapping(char *); boolean hideSetupEntry(void *); void LoadCustomElementDescriptions(); void InitMenuDesignSettings_Static(); void LoadMenuDesignSettings(); void LoadMenuDesignSettings_AfterGraphics(); void LoadUserDefinedEditorElementList(int **, int *); void LoadMusicInfo(); void LoadHelpAnimInfo(); void LoadHelpTextInfo(); void ConvertLevels(); void CreateLevelSketchImages(); void CreateCustomElementImages(char *); #endif /* FILES_H */ mirrormagic-3.0.0/src/conf_g2m.c0000644000175000017500000000264313263214151015763 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_g2m.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_G2M_C #define CONF_G2M_C /* values for gamemode/music mapping configuration */ static struct { int gamemode; int music; } gamemode_to_music[] = { { -1, MUS_BACKGROUND }, { GFX_SPECIAL_ARG_TITLE_INITIAL, MUS_BACKGROUND_TITLE_INITIAL }, { GFX_SPECIAL_ARG_TITLE, MUS_BACKGROUND_TITLE }, { GFX_SPECIAL_ARG_MAIN, MUS_BACKGROUND_MAIN }, { GFX_SPECIAL_ARG_LEVELS, MUS_BACKGROUND_LEVELS }, { GFX_SPECIAL_ARG_LEVELNR, MUS_BACKGROUND_LEVELNR }, { GFX_SPECIAL_ARG_SCORES, MUS_BACKGROUND_SCORES }, { GFX_SPECIAL_ARG_EDITOR, MUS_BACKGROUND_EDITOR }, { GFX_SPECIAL_ARG_INFO, MUS_BACKGROUND_INFO }, { GFX_SPECIAL_ARG_SETUP, MUS_BACKGROUND_SETUP }, { -1, -1 }, }; #endif /* CONF_G2M_C */ mirrormagic-3.0.0/src/config.c0000644000175000017500000000731113263212010015523 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // config.c // ============================================================================ #include "libgame/libgame.h" #include "config.h" #include "conftime.h" char *getSourceDateString() { return SOURCE_DATE_STRING; } char *getProgramTitleString() { return program.program_title; } char *getProgramRealVersionString() { static char program_version_string[32]; sprintf(program_version_string, "%d.%d.%d.%d%s", PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH, PROGRAM_VERSION_BUILD, PROGRAM_VERSION_EXTRA); return program_version_string; } char *getProgramVersionString() { return program.version_string; } char *getProgramInitString() { static char *program_init_string = NULL; if (program_init_string == NULL) { program_init_string = checked_malloc(strlen(getProgramTitleString()) + 1 + strlen(getProgramVersionString()) + 1); sprintf(program_init_string, "%s %s", getProgramTitleString(), getProgramVersionString()); } return program_init_string; } char *getConfigProgramTitleString() { TreeInfo *graphics_current = getArtworkTreeInfoForUserLevelSet(ARTWORK_TYPE_GRAPHICS); return (leveldir_current->program_title ? leveldir_current->program_title : graphics_current->program_title ? graphics_current->program_title : setup.internal.program_title); } char *getConfigProgramCopyrightString() { TreeInfo *graphics_current = getArtworkTreeInfoForUserLevelSet(ARTWORK_TYPE_GRAPHICS); return (leveldir_current->program_copyright ? leveldir_current->program_copyright : graphics_current->program_copyright ? graphics_current->program_copyright : setup.internal.program_copyright); } char *getConfigProgramCompanyString() { TreeInfo *graphics_current = getArtworkTreeInfoForUserLevelSet(ARTWORK_TYPE_GRAPHICS); return (leveldir_current->program_company ? leveldir_current->program_company : graphics_current->program_company ? graphics_current->program_company : setup.internal.program_company); } char *getWindowTitleString() { static char *window_title_string = NULL; checked_free(window_title_string); #if defined(TARGET_SDL2) #ifdef DEBUG window_title_string = checked_malloc(strlen(getProgramInitString()) + 20 + strlen(getSourceDateString()) + 2 + 1); if (setup.internal.show_scaling_in_title) sprintf(window_title_string, "%s (%d %%) [%s]", getProgramInitString(), video.window_scaling_percent, getSourceDateString()); else sprintf(window_title_string, "%s [%s]", getProgramInitString(), getSourceDateString()); #else window_title_string = checked_malloc(strlen(getProgramInitString()) + 20); if (setup.internal.show_scaling_in_title) sprintf(window_title_string, "%s (%d %%)", getProgramInitString(), video.window_scaling_percent); else sprintf(window_title_string, "%s", getProgramInitString()); #endif #else #ifdef DEBUG window_title_string = checked_malloc(strlen(getProgramInitString()) + 1 + strlen(getSourceDateString()) + 2 + 1); sprintf(window_title_string, "%s [%s]", getProgramInitString(), getSourceDateString()); #else window_title_string = checked_malloc(strlen(getProgramInitString()) + 1); sprintf(window_title_string, "%s", getProgramInitString()); #endif #endif return window_title_string; } mirrormagic-3.0.0/src/game.c0000644000175000017500000150623613263212010015202 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // game.c // ============================================================================ #include "libgame/libgame.h" #include "game.h" #include "init.h" #include "tools.h" #include "screens.h" #include "events.h" #include "files.h" #include "tape.h" #include "network.h" #include "anim.h" /* DEBUG SETTINGS */ #define DEBUG_INIT_PLAYER 1 #define DEBUG_PLAYER_ACTIONS 0 /* EXPERIMENTAL STUFF */ #define USE_NEW_AMOEBA_CODE FALSE /* EXPERIMENTAL STUFF */ #define USE_QUICKSAND_BD_ROCK_BUGFIX 0 #define USE_QUICKSAND_IMPACT_BUGFIX 0 #define USE_DELAYED_GFX_REDRAW 0 #define USE_NEW_PLAYER_ASSIGNMENTS 1 #if USE_DELAYED_GFX_REDRAW #define TEST_DrawLevelField(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE #define TEST_DrawLevelFieldCrumbled(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED #define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS #define TEST_DrawTwinkleOnField(x, y) \ GfxRedraw[x][y] |= GFX_REDRAW_TILE_TWINKLED #else #define TEST_DrawLevelField(x, y) \ DrawLevelField(x, y) #define TEST_DrawLevelFieldCrumbled(x, y) \ DrawLevelFieldCrumbled(x, y) #define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \ DrawLevelFieldCrumbledNeighbours(x, y) #define TEST_DrawTwinkleOnField(x, y) \ DrawTwinkleOnField(x, y) #endif /* for DigField() */ #define DF_NO_PUSH 0 #define DF_DIG 1 #define DF_SNAP 2 /* for MovePlayer() */ #define MP_NO_ACTION 0 #define MP_MOVING 1 #define MP_ACTION 2 #define MP_DONT_RUN_INTO (MP_MOVING | MP_ACTION) /* for ScrollPlayer() */ #define SCROLL_INIT 0 #define SCROLL_GO_ON 1 /* for Bang()/Explode() */ #define EX_PHASE_START 0 #define EX_TYPE_NONE 0 #define EX_TYPE_NORMAL (1 << 0) #define EX_TYPE_CENTER (1 << 1) #define EX_TYPE_BORDER (1 << 2) #define EX_TYPE_CROSS (1 << 3) #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) #define PANEL_OFF() (local_player->LevelSolved_PanelOff) #define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF()) #define PANEL_XPOS(p) (DX + ALIGNED_TEXT_XPOS(p)) #define PANEL_YPOS(p) (DY + ALIGNED_TEXT_YPOS(p)) /* game panel display and control definitions */ #define GAME_PANEL_LEVEL_NUMBER 0 #define GAME_PANEL_GEMS 1 #define GAME_PANEL_INVENTORY_COUNT 2 #define GAME_PANEL_INVENTORY_FIRST_1 3 #define GAME_PANEL_INVENTORY_FIRST_2 4 #define GAME_PANEL_INVENTORY_FIRST_3 5 #define GAME_PANEL_INVENTORY_FIRST_4 6 #define GAME_PANEL_INVENTORY_FIRST_5 7 #define GAME_PANEL_INVENTORY_FIRST_6 8 #define GAME_PANEL_INVENTORY_FIRST_7 9 #define GAME_PANEL_INVENTORY_FIRST_8 10 #define GAME_PANEL_INVENTORY_LAST_1 11 #define GAME_PANEL_INVENTORY_LAST_2 12 #define GAME_PANEL_INVENTORY_LAST_3 13 #define GAME_PANEL_INVENTORY_LAST_4 14 #define GAME_PANEL_INVENTORY_LAST_5 15 #define GAME_PANEL_INVENTORY_LAST_6 16 #define GAME_PANEL_INVENTORY_LAST_7 17 #define GAME_PANEL_INVENTORY_LAST_8 18 #define GAME_PANEL_KEY_1 19 #define GAME_PANEL_KEY_2 20 #define GAME_PANEL_KEY_3 21 #define GAME_PANEL_KEY_4 22 #define GAME_PANEL_KEY_5 23 #define GAME_PANEL_KEY_6 24 #define GAME_PANEL_KEY_7 25 #define GAME_PANEL_KEY_8 26 #define GAME_PANEL_KEY_WHITE 27 #define GAME_PANEL_KEY_WHITE_COUNT 28 #define GAME_PANEL_SCORE 29 #define GAME_PANEL_HIGHSCORE 30 #define GAME_PANEL_TIME 31 #define GAME_PANEL_TIME_HH 32 #define GAME_PANEL_TIME_MM 33 #define GAME_PANEL_TIME_SS 34 #define GAME_PANEL_TIME_ANIM 35 #define GAME_PANEL_HEALTH 36 #define GAME_PANEL_HEALTH_ANIM 37 #define GAME_PANEL_FRAME 38 #define GAME_PANEL_SHIELD_NORMAL 39 #define GAME_PANEL_SHIELD_NORMAL_TIME 40 #define GAME_PANEL_SHIELD_DEADLY 41 #define GAME_PANEL_SHIELD_DEADLY_TIME 42 #define GAME_PANEL_EXIT 43 #define GAME_PANEL_EMC_MAGIC_BALL 44 #define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 45 #define GAME_PANEL_LIGHT_SWITCH 46 #define GAME_PANEL_LIGHT_SWITCH_TIME 47 #define GAME_PANEL_TIMEGATE_SWITCH 48 #define GAME_PANEL_TIMEGATE_SWITCH_TIME 49 #define GAME_PANEL_SWITCHGATE_SWITCH 50 #define GAME_PANEL_EMC_LENSES 51 #define GAME_PANEL_EMC_LENSES_TIME 52 #define GAME_PANEL_EMC_MAGNIFIER 53 #define GAME_PANEL_EMC_MAGNIFIER_TIME 54 #define GAME_PANEL_BALLOON_SWITCH 55 #define GAME_PANEL_DYNABOMB_NUMBER 56 #define GAME_PANEL_DYNABOMB_SIZE 57 #define GAME_PANEL_DYNABOMB_POWER 58 #define GAME_PANEL_PENGUINS 59 #define GAME_PANEL_SOKOBAN_OBJECTS 60 #define GAME_PANEL_SOKOBAN_FIELDS 61 #define GAME_PANEL_ROBOT_WHEEL 62 #define GAME_PANEL_CONVEYOR_BELT_1 63 #define GAME_PANEL_CONVEYOR_BELT_2 64 #define GAME_PANEL_CONVEYOR_BELT_3 65 #define GAME_PANEL_CONVEYOR_BELT_4 66 #define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 67 #define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 68 #define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 69 #define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 70 #define GAME_PANEL_MAGIC_WALL 71 #define GAME_PANEL_MAGIC_WALL_TIME 72 #define GAME_PANEL_GRAVITY_STATE 73 #define GAME_PANEL_GRAPHIC_1 74 #define GAME_PANEL_GRAPHIC_2 75 #define GAME_PANEL_GRAPHIC_3 76 #define GAME_PANEL_GRAPHIC_4 77 #define GAME_PANEL_GRAPHIC_5 78 #define GAME_PANEL_GRAPHIC_6 79 #define GAME_PANEL_GRAPHIC_7 80 #define GAME_PANEL_GRAPHIC_8 81 #define GAME_PANEL_ELEMENT_1 82 #define GAME_PANEL_ELEMENT_2 83 #define GAME_PANEL_ELEMENT_3 84 #define GAME_PANEL_ELEMENT_4 85 #define GAME_PANEL_ELEMENT_5 86 #define GAME_PANEL_ELEMENT_6 87 #define GAME_PANEL_ELEMENT_7 88 #define GAME_PANEL_ELEMENT_8 89 #define GAME_PANEL_ELEMENT_COUNT_1 90 #define GAME_PANEL_ELEMENT_COUNT_2 91 #define GAME_PANEL_ELEMENT_COUNT_3 92 #define GAME_PANEL_ELEMENT_COUNT_4 93 #define GAME_PANEL_ELEMENT_COUNT_5 94 #define GAME_PANEL_ELEMENT_COUNT_6 95 #define GAME_PANEL_ELEMENT_COUNT_7 96 #define GAME_PANEL_ELEMENT_COUNT_8 97 #define GAME_PANEL_CE_SCORE_1 98 #define GAME_PANEL_CE_SCORE_2 99 #define GAME_PANEL_CE_SCORE_3 100 #define GAME_PANEL_CE_SCORE_4 101 #define GAME_PANEL_CE_SCORE_5 102 #define GAME_PANEL_CE_SCORE_6 103 #define GAME_PANEL_CE_SCORE_7 104 #define GAME_PANEL_CE_SCORE_8 105 #define GAME_PANEL_CE_SCORE_1_ELEMENT 106 #define GAME_PANEL_CE_SCORE_2_ELEMENT 107 #define GAME_PANEL_CE_SCORE_3_ELEMENT 108 #define GAME_PANEL_CE_SCORE_4_ELEMENT 109 #define GAME_PANEL_CE_SCORE_5_ELEMENT 110 #define GAME_PANEL_CE_SCORE_6_ELEMENT 111 #define GAME_PANEL_CE_SCORE_7_ELEMENT 112 #define GAME_PANEL_CE_SCORE_8_ELEMENT 113 #define GAME_PANEL_PLAYER_NAME 114 #define GAME_PANEL_LEVEL_NAME 115 #define GAME_PANEL_LEVEL_AUTHOR 116 #define NUM_GAME_PANEL_CONTROLS 117 struct GamePanelOrderInfo { int nr; int sort_priority; }; static struct GamePanelOrderInfo game_panel_order[NUM_GAME_PANEL_CONTROLS]; struct GamePanelControlInfo { int nr; struct TextPosInfo *pos; int type; int graphic, graphic_active; int value, last_value; int frame, last_frame; int gfx_frame; int gfx_random; }; static struct GamePanelControlInfo game_panel_controls[] = { { GAME_PANEL_LEVEL_NUMBER, &game.panel.level_number, TYPE_INTEGER, }, { GAME_PANEL_GEMS, &game.panel.gems, TYPE_INTEGER, }, { GAME_PANEL_INVENTORY_COUNT, &game.panel.inventory_count, TYPE_INTEGER, }, { GAME_PANEL_INVENTORY_FIRST_1, &game.panel.inventory_first[0], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_2, &game.panel.inventory_first[1], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_3, &game.panel.inventory_first[2], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_4, &game.panel.inventory_first[3], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_5, &game.panel.inventory_first[4], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_6, &game.panel.inventory_first[5], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_7, &game.panel.inventory_first[6], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_FIRST_8, &game.panel.inventory_first[7], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_1, &game.panel.inventory_last[0], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_2, &game.panel.inventory_last[1], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_3, &game.panel.inventory_last[2], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_4, &game.panel.inventory_last[3], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_5, &game.panel.inventory_last[4], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_6, &game.panel.inventory_last[5], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_7, &game.panel.inventory_last[6], TYPE_ELEMENT, }, { GAME_PANEL_INVENTORY_LAST_8, &game.panel.inventory_last[7], TYPE_ELEMENT, }, { GAME_PANEL_KEY_1, &game.panel.key[0], TYPE_ELEMENT, }, { GAME_PANEL_KEY_2, &game.panel.key[1], TYPE_ELEMENT, }, { GAME_PANEL_KEY_3, &game.panel.key[2], TYPE_ELEMENT, }, { GAME_PANEL_KEY_4, &game.panel.key[3], TYPE_ELEMENT, }, { GAME_PANEL_KEY_5, &game.panel.key[4], TYPE_ELEMENT, }, { GAME_PANEL_KEY_6, &game.panel.key[5], TYPE_ELEMENT, }, { GAME_PANEL_KEY_7, &game.panel.key[6], TYPE_ELEMENT, }, { GAME_PANEL_KEY_8, &game.panel.key[7], TYPE_ELEMENT, }, { GAME_PANEL_KEY_WHITE, &game.panel.key_white, TYPE_ELEMENT, }, { GAME_PANEL_KEY_WHITE_COUNT, &game.panel.key_white_count, TYPE_INTEGER, }, { GAME_PANEL_SCORE, &game.panel.score, TYPE_INTEGER, }, { GAME_PANEL_HIGHSCORE, &game.panel.highscore, TYPE_INTEGER, }, { GAME_PANEL_TIME, &game.panel.time, TYPE_INTEGER, }, { GAME_PANEL_TIME_HH, &game.panel.time_hh, TYPE_INTEGER, }, { GAME_PANEL_TIME_MM, &game.panel.time_mm, TYPE_INTEGER, }, { GAME_PANEL_TIME_SS, &game.panel.time_ss, TYPE_INTEGER, }, { GAME_PANEL_TIME_ANIM, &game.panel.time_anim, TYPE_GRAPHIC, IMG_GFX_GAME_PANEL_TIME_ANIM, IMG_GFX_GAME_PANEL_TIME_ANIM_ACTIVE }, { GAME_PANEL_HEALTH, &game.panel.health, TYPE_INTEGER, }, { GAME_PANEL_HEALTH_ANIM, &game.panel.health_anim, TYPE_GRAPHIC, IMG_GFX_GAME_PANEL_HEALTH_ANIM, IMG_GFX_GAME_PANEL_HEALTH_ANIM_ACTIVE }, { GAME_PANEL_FRAME, &game.panel.frame, TYPE_INTEGER, }, { GAME_PANEL_SHIELD_NORMAL, &game.panel.shield_normal, TYPE_ELEMENT, }, { GAME_PANEL_SHIELD_NORMAL_TIME, &game.panel.shield_normal_time, TYPE_INTEGER, }, { GAME_PANEL_SHIELD_DEADLY, &game.panel.shield_deadly, TYPE_ELEMENT, }, { GAME_PANEL_SHIELD_DEADLY_TIME, &game.panel.shield_deadly_time, TYPE_INTEGER, }, { GAME_PANEL_EXIT, &game.panel.exit, TYPE_ELEMENT, }, { GAME_PANEL_EMC_MAGIC_BALL, &game.panel.emc_magic_ball, TYPE_ELEMENT, }, { GAME_PANEL_EMC_MAGIC_BALL_SWITCH, &game.panel.emc_magic_ball_switch, TYPE_ELEMENT, }, { GAME_PANEL_LIGHT_SWITCH, &game.panel.light_switch, TYPE_ELEMENT, }, { GAME_PANEL_LIGHT_SWITCH_TIME, &game.panel.light_switch_time, TYPE_INTEGER, }, { GAME_PANEL_TIMEGATE_SWITCH, &game.panel.timegate_switch, TYPE_ELEMENT, }, { GAME_PANEL_TIMEGATE_SWITCH_TIME, &game.panel.timegate_switch_time, TYPE_INTEGER, }, { GAME_PANEL_SWITCHGATE_SWITCH, &game.panel.switchgate_switch, TYPE_ELEMENT, }, { GAME_PANEL_EMC_LENSES, &game.panel.emc_lenses, TYPE_ELEMENT, }, { GAME_PANEL_EMC_LENSES_TIME, &game.panel.emc_lenses_time, TYPE_INTEGER, }, { GAME_PANEL_EMC_MAGNIFIER, &game.panel.emc_magnifier, TYPE_ELEMENT, }, { GAME_PANEL_EMC_MAGNIFIER_TIME, &game.panel.emc_magnifier_time, TYPE_INTEGER, }, { GAME_PANEL_BALLOON_SWITCH, &game.panel.balloon_switch, TYPE_ELEMENT, }, { GAME_PANEL_DYNABOMB_NUMBER, &game.panel.dynabomb_number, TYPE_INTEGER, }, { GAME_PANEL_DYNABOMB_SIZE, &game.panel.dynabomb_size, TYPE_INTEGER, }, { GAME_PANEL_DYNABOMB_POWER, &game.panel.dynabomb_power, TYPE_ELEMENT, }, { GAME_PANEL_PENGUINS, &game.panel.penguins, TYPE_INTEGER, }, { GAME_PANEL_SOKOBAN_OBJECTS, &game.panel.sokoban_objects, TYPE_INTEGER, }, { GAME_PANEL_SOKOBAN_FIELDS, &game.panel.sokoban_fields, TYPE_INTEGER, }, { GAME_PANEL_ROBOT_WHEEL, &game.panel.robot_wheel, TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_1, &game.panel.conveyor_belt[0], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_2, &game.panel.conveyor_belt[1], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_3, &game.panel.conveyor_belt[2], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_4, &game.panel.conveyor_belt[3], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_1_SWITCH, &game.panel.conveyor_belt_switch[0], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_2_SWITCH, &game.panel.conveyor_belt_switch[1], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_3_SWITCH, &game.panel.conveyor_belt_switch[2], TYPE_ELEMENT, }, { GAME_PANEL_CONVEYOR_BELT_4_SWITCH, &game.panel.conveyor_belt_switch[3], TYPE_ELEMENT, }, { GAME_PANEL_MAGIC_WALL, &game.panel.magic_wall, TYPE_ELEMENT, }, { GAME_PANEL_MAGIC_WALL_TIME, &game.panel.magic_wall_time, TYPE_INTEGER, }, { GAME_PANEL_GRAVITY_STATE, &game.panel.gravity_state, TYPE_STRING, }, { GAME_PANEL_GRAPHIC_1, &game.panel.graphic[0], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_2, &game.panel.graphic[1], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_3, &game.panel.graphic[2], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_4, &game.panel.graphic[3], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_5, &game.panel.graphic[4], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_6, &game.panel.graphic[5], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_7, &game.panel.graphic[6], TYPE_ELEMENT, }, { GAME_PANEL_GRAPHIC_8, &game.panel.graphic[7], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_1, &game.panel.element[0], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_2, &game.panel.element[1], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_3, &game.panel.element[2], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_4, &game.panel.element[3], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_5, &game.panel.element[4], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_6, &game.panel.element[5], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_7, &game.panel.element[6], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_8, &game.panel.element[7], TYPE_ELEMENT, }, { GAME_PANEL_ELEMENT_COUNT_1, &game.panel.element_count[0], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_2, &game.panel.element_count[1], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_3, &game.panel.element_count[2], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_4, &game.panel.element_count[3], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_5, &game.panel.element_count[4], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_6, &game.panel.element_count[5], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_7, &game.panel.element_count[6], TYPE_INTEGER, }, { GAME_PANEL_ELEMENT_COUNT_8, &game.panel.element_count[7], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_1, &game.panel.ce_score[0], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_2, &game.panel.ce_score[1], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_3, &game.panel.ce_score[2], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_4, &game.panel.ce_score[3], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_5, &game.panel.ce_score[4], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_6, &game.panel.ce_score[5], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_7, &game.panel.ce_score[6], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_8, &game.panel.ce_score[7], TYPE_INTEGER, }, { GAME_PANEL_CE_SCORE_1_ELEMENT, &game.panel.ce_score_element[0], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_2_ELEMENT, &game.panel.ce_score_element[1], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_3_ELEMENT, &game.panel.ce_score_element[2], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_4_ELEMENT, &game.panel.ce_score_element[3], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_5_ELEMENT, &game.panel.ce_score_element[4], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_6_ELEMENT, &game.panel.ce_score_element[5], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_7_ELEMENT, &game.panel.ce_score_element[6], TYPE_ELEMENT, }, { GAME_PANEL_CE_SCORE_8_ELEMENT, &game.panel.ce_score_element[7], TYPE_ELEMENT, }, { GAME_PANEL_PLAYER_NAME, &game.panel.player_name, TYPE_STRING, }, { GAME_PANEL_LEVEL_NAME, &game.panel.level_name, TYPE_STRING, }, { GAME_PANEL_LEVEL_AUTHOR, &game.panel.level_author, TYPE_STRING, }, { -1, NULL, -1, } }; /* values for delayed check of falling and moving elements and for collision */ #define CHECK_DELAY_MOVING 3 #define CHECK_DELAY_FALLING CHECK_DELAY_MOVING #define CHECK_DELAY_COLLISION 2 #define CHECK_DELAY_IMPACT CHECK_DELAY_COLLISION /* values for initial player move delay (initial delay counter value) */ #define INITIAL_MOVE_DELAY_OFF -1 #define INITIAL_MOVE_DELAY_ON 0 /* values for player movement speed (which is in fact a delay value) */ #define MOVE_DELAY_MIN_SPEED 32 #define MOVE_DELAY_NORMAL_SPEED 8 #define MOVE_DELAY_HIGH_SPEED 4 #define MOVE_DELAY_MAX_SPEED 1 #define DOUBLE_MOVE_DELAY(x) (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x)) #define HALVE_MOVE_DELAY(x) (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x)) #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY( (p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) /* values for scroll positions */ #define SCROLL_POSITION_X(x) ((x) < SBX_Left + MIDPOSX ? SBX_Left : \ (x) > SBX_Right + MIDPOSX ? SBX_Right :\ (x) - MIDPOSX) #define SCROLL_POSITION_Y(y) ((y) < SBY_Upper + MIDPOSY ? SBY_Upper :\ (y) > SBY_Lower + MIDPOSY ? SBY_Lower :\ (y) - MIDPOSY) /* values for other actions */ #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) #define MOVE_STEPSIZE_MIN (1) #define MOVE_STEPSIZE_MAX (TILEX) #define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0) #define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0) #define INIT_GFX_RANDOM() (GetSimpleRandom(1000000)) #define GET_NEW_PUSH_DELAY(e) ( (element_info[e].push_delay_fixed) + \ RND(element_info[e].push_delay_random)) #define GET_NEW_DROP_DELAY(e) ( (element_info[e].drop_delay_fixed) + \ RND(element_info[e].drop_delay_random)) #define GET_NEW_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ RND(element_info[e].move_delay_random)) #define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ (element_info[e].move_delay_random)) #define GET_NEW_CE_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\ RND(element_info[e].ce_value_random_initial)) #define GET_CE_SCORE(e) ( (element_info[e].collect_score)) #define GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \ RND((c)->delay_random * (c)->delay_frames)) #define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \ RND((c)->delay_random)) #define GET_VALID_RUNTIME_ELEMENT(e) \ ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e)) #define RESOLVED_REFERENCE_ELEMENT(be, e) \ ((be) + (e) - EL_SELF < EL_CUSTOM_START ? EL_CUSTOM_START : \ (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \ (be) + (e) - EL_SELF) #define GET_PLAYER_FROM_BITS(p) \ (EL_PLAYER_1 + ((p) != PLAYER_BITS_ANY ? log_2(p) : 0)) #define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : \ (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \ (e) == EL_CURRENT_CE_VALUE ? (cv) : \ (e) == EL_CURRENT_CE_SCORE ? (cs) : \ (e) >= EL_PREV_CE_8 && (e) <= EL_NEXT_CE_8 ? \ RESOLVED_REFERENCE_ELEMENT(be, e) : \ (e)) #define CAN_GROW_INTO(e) \ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) #define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition))) #define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (condition))) #define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (condition))) #define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (DONT_COLLIDE_WITH(e) && \ IS_PLAYER(x, y) && \ !PLAYER_ENEMY_PROTECTED(x, y)))) #define ELEMENT_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0) #define SATELLITE_CAN_ENTER_FIELD(x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0) #define ANDROID_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT) #define ANDROID_CAN_CLONE_FIELD(x, y) \ (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \ CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT))) #define ENEMY_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) #define YAMYAM_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND) #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y])) #define PACMAN_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y])) #define PIG_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y])) #define PENGUIN_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN || \ Feld[x][y] == EL_EM_EXIT_OPEN || \ Feld[x][y] == EL_STEEL_EXIT_OPEN || \ Feld[x][y] == EL_EM_STEEL_EXIT_OPEN || \ IS_FOOD_PENGUIN(Feld[x][y]))) #define DRAGON_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) #define MOLE_CAN_ENTER_FIELD(e, x, y, condition) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition)) #define SPRING_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) #define SPRING_CAN_BUMP_FROM_FIELD(x, y) \ (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \ Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE)) #define MOVE_ENTER_EL(e) (element_info[e].move_enter_element) #define CE_ENTER_FIELD_COND(e, x, y) \ (!IS_PLAYER(x, y) && \ IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e))) #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y)) #define IN_LEV_FIELD_AND_IS_FREE(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y)) #define ACCESS_FROM(e, d) (element_info[e].access_direction &(d)) #define IS_WALKABLE_FROM(e, d) (IS_WALKABLE(e) && ACCESS_FROM(e, d)) #define IS_PASSABLE_FROM(e, d) (IS_PASSABLE(e) && ACCESS_FROM(e, d)) #define IS_ACCESSIBLE_FROM(e, d) (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d)) #define MM_HEALTH(x) (MIN(MAX(0, MAX_HEALTH - (x)), MAX_HEALTH)) /* game button identifiers */ #define GAME_CTRL_ID_STOP 0 #define GAME_CTRL_ID_PAUSE 1 #define GAME_CTRL_ID_PLAY 2 #define GAME_CTRL_ID_UNDO 3 #define GAME_CTRL_ID_REDO 4 #define GAME_CTRL_ID_SAVE 5 #define GAME_CTRL_ID_PAUSE2 6 #define GAME_CTRL_ID_LOAD 7 #define GAME_CTRL_ID_PANEL_STOP 8 #define GAME_CTRL_ID_PANEL_PAUSE 9 #define GAME_CTRL_ID_PANEL_PLAY 10 #define SOUND_CTRL_ID_MUSIC 11 #define SOUND_CTRL_ID_LOOPS 12 #define SOUND_CTRL_ID_SIMPLE 13 #define SOUND_CTRL_ID_PANEL_MUSIC 14 #define SOUND_CTRL_ID_PANEL_LOOPS 15 #define SOUND_CTRL_ID_PANEL_SIMPLE 16 #define NUM_GAME_BUTTONS 17 /* forward declaration for internal use */ static void CreateField(int, int, int); static void ResetGfxAnimation(int, int); static void SetPlayerWaiting(struct PlayerInfo *, boolean); static void AdvanceFrameAndPlayerCounters(int); static boolean MovePlayerOneStep(struct PlayerInfo *, int, int, int, int); static boolean MovePlayer(struct PlayerInfo *, int, int); static void ScrollPlayer(struct PlayerInfo *, int); static void ScrollScreen(struct PlayerInfo *, int); static int DigField(struct PlayerInfo *, int, int, int, int, int, int, int); static boolean DigFieldByCE(int, int, int); static boolean SnapField(struct PlayerInfo *, int, int); static boolean DropElement(struct PlayerInfo *); static void InitBeltMovement(void); static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *); static void KillPlayerUnlessEnemyProtected(int, int); static void KillPlayerUnlessExplosionProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); static void TestIfElementHitsCustomElement(int, int, int); static void HandleElementChange(int, int, int); static void ExecuteCustomElementAction(int, int, int, int); static boolean ChangeElement(int, int, int, int); static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int); #define CheckTriggeredElementChange(x, y, e, ev) \ CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1) #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \ CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1) #define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \ CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1) #define CheckTriggeredElementChangeByPage(x, y, e, ev, p) \ CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, p) static boolean CheckElementChangeExt(int, int, int, int, int, int, int); #define CheckElementChange(x, y, e, te, ev) \ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY) #define CheckElementChangeByPlayer(x, y, e, ev, p, s) \ CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s) #define CheckElementChangeBySide(x, y, e, te, ev, s) \ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s) static void PlayLevelSound(int, int, int); static void PlayLevelSoundNearest(int, int, int); static void PlayLevelSoundAction(int, int, int); static void PlayLevelSoundElementAction(int, int, int, int); static void PlayLevelSoundElementActionIfLoop(int, int, int, int); static void PlayLevelSoundActionIfLoop(int, int, int); static void StopLevelSoundActionIfLoop(int, int, int); static void PlayLevelMusic(); static void FadeLevelSoundsAndMusic(); static void HandleGameButtons(struct GadgetInfo *); int AmoebeNachbarNr(int, int); void AmoebeUmwandeln(int, int); void ContinueMoving(int, int); void Bang(int, int); void InitMovDir(int, int); void InitAmoebaNr(int, int); int NewHiScore(void); void TestIfGoodThingHitsBadThing(int, int, int); void TestIfBadThingHitsGoodThing(int, int, int); void TestIfPlayerTouchesBadThing(int, int); void TestIfPlayerRunsIntoBadThing(int, int, int); void TestIfBadThingTouchesPlayer(int, int); void TestIfBadThingRunsIntoPlayer(int, int, int); void TestIfFriendTouchesBadThing(int, int); void TestIfBadThingTouchesFriend(int, int); void TestIfBadThingTouchesOtherBadThing(int, int); void TestIfGoodThingGetsHitByBadThing(int, int, int); void KillPlayer(struct PlayerInfo *); void BuryPlayer(struct PlayerInfo *); void RemovePlayer(struct PlayerInfo *); static int getInvisibleActiveFromInvisibleElement(int); static int getInvisibleFromInvisibleActiveElement(int); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; /* for detection of endless loops, caused by custom element programming */ /* (using maximal playfield width x 10 is just a rough approximation) */ #define MAX_ELEMENT_CHANGE_RECURSION_DEPTH (MAX_PLAYFIELD_WIDTH * 10) #define RECURSION_LOOP_DETECTION_START(e, rc) \ { \ if (recursion_loop_detected) \ return (rc); \ \ if (recursion_loop_depth > MAX_ELEMENT_CHANGE_RECURSION_DEPTH) \ { \ recursion_loop_detected = TRUE; \ recursion_loop_element = (e); \ } \ \ recursion_loop_depth++; \ } #define RECURSION_LOOP_DETECTION_END() \ { \ recursion_loop_depth--; \ } static int recursion_loop_depth; static boolean recursion_loop_detected; static boolean recursion_loop_element; static int map_player_action[MAX_PLAYERS]; /* ------------------------------------------------------------------------- */ /* definition of elements that automatically change to other elements after */ /* a specified time, eventually calling a function when changing */ /* ------------------------------------------------------------------------- */ /* forward declaration for changer functions */ static void InitBuggyBase(int, int); static void WarnBuggyBase(int, int); static void InitTrap(int, int); static void ActivateTrap(int, int); static void ChangeActiveTrap(int, int); static void InitRobotWheel(int, int); static void RunRobotWheel(int, int); static void StopRobotWheel(int, int); static void InitTimegateWheel(int, int); static void RunTimegateWheel(int, int); static void InitMagicBallDelay(int, int); static void ActivateMagicBall(int, int); struct ChangingElementInfo { int element; int target_element; int change_delay; void (*pre_change_function)(int x, int y); void (*change_function)(int x, int y); void (*post_change_function)(int x, int y); }; static struct ChangingElementInfo change_delay_list[] = { { EL_NUT_BREAKING, EL_EMERALD, 6, NULL, NULL, NULL }, { EL_PEARL_BREAKING, EL_EMPTY, 8, NULL, NULL, NULL }, { EL_EXIT_OPENING, EL_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_EXIT_CLOSING, EL_EXIT_CLOSED, 29, NULL, NULL, NULL }, { EL_STEEL_EXIT_OPENING, EL_STEEL_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_STEEL_EXIT_CLOSING, EL_STEEL_EXIT_CLOSED, 29, NULL, NULL, NULL }, { EL_EM_EXIT_OPENING, EL_EM_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_EM_EXIT_CLOSING, EL_EMPTY, 29, NULL, NULL, NULL }, { EL_EM_STEEL_EXIT_OPENING, EL_EM_STEEL_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_EM_STEEL_EXIT_CLOSING, EL_STEELWALL, 29, NULL, NULL, NULL }, { EL_SP_EXIT_OPENING, EL_SP_EXIT_OPEN, 29, NULL, NULL, NULL }, { EL_SP_EXIT_CLOSING, EL_SP_EXIT_CLOSED, 29, NULL, NULL, NULL }, { EL_SWITCHGATE_OPENING, EL_SWITCHGATE_OPEN, 29, NULL, NULL, NULL }, { EL_SWITCHGATE_CLOSING, EL_SWITCHGATE_CLOSED, 29, NULL, NULL, NULL }, { EL_TIMEGATE_OPENING, EL_TIMEGATE_OPEN, 29, NULL, NULL, NULL }, { EL_TIMEGATE_CLOSING, EL_TIMEGATE_CLOSED, 29, NULL, NULL, NULL }, { EL_ACID_SPLASH_LEFT, EL_EMPTY, 8, NULL, NULL, NULL }, { EL_ACID_SPLASH_RIGHT, EL_EMPTY, 8, NULL, NULL, NULL }, { EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVATING, 0, InitBuggyBase, NULL, NULL }, { EL_SP_BUGGY_BASE_ACTIVATING, EL_SP_BUGGY_BASE_ACTIVE, 0, InitBuggyBase, NULL, NULL }, { EL_SP_BUGGY_BASE_ACTIVE, EL_SP_BUGGY_BASE, 0, InitBuggyBase, WarnBuggyBase, NULL }, { EL_TRAP, EL_TRAP_ACTIVE, 0, InitTrap, NULL, ActivateTrap }, { EL_TRAP_ACTIVE, EL_TRAP, 31, NULL, ChangeActiveTrap, NULL }, { EL_ROBOT_WHEEL_ACTIVE, EL_ROBOT_WHEEL, 0, InitRobotWheel, RunRobotWheel, StopRobotWheel }, { EL_TIMEGATE_SWITCH_ACTIVE, EL_TIMEGATE_SWITCH, 0, InitTimegateWheel, RunTimegateWheel, NULL }, { EL_DC_TIMEGATE_SWITCH_ACTIVE, EL_DC_TIMEGATE_SWITCH, 0, InitTimegateWheel, RunTimegateWheel, NULL }, { EL_EMC_MAGIC_BALL_ACTIVE, EL_EMC_MAGIC_BALL_ACTIVE, 0, InitMagicBallDelay, NULL, ActivateMagicBall }, { EL_EMC_SPRING_BUMPER_ACTIVE, EL_EMC_SPRING_BUMPER, 8, NULL, NULL, NULL }, { EL_DIAGONAL_SHRINKING, EL_UNDEFINED, 0, NULL, NULL, NULL }, { EL_DIAGONAL_GROWING, EL_UNDEFINED, 0, NULL, NULL, NULL, }, { EL_UNDEFINED, EL_UNDEFINED, -1, NULL, NULL, NULL } }; struct { int element; int push_delay_fixed, push_delay_random; } push_delay_list[] = { { EL_SPRING, 0, 0 }, { EL_BALLOON, 0, 0 }, { EL_SOKOBAN_OBJECT, 2, 0 }, { EL_SOKOBAN_FIELD_FULL, 2, 0 }, { EL_SATELLITE, 2, 0 }, { EL_SP_DISK_YELLOW, 2, 0 }, { EL_UNDEFINED, 0, 0 }, }; struct { int element; int move_stepsize; } move_stepsize_list[] = { { EL_AMOEBA_DROP, 2 }, { EL_AMOEBA_DROPPING, 2 }, { EL_QUICKSAND_FILLING, 1 }, { EL_QUICKSAND_EMPTYING, 1 }, { EL_QUICKSAND_FAST_FILLING, 2 }, { EL_QUICKSAND_FAST_EMPTYING, 2 }, { EL_MAGIC_WALL_FILLING, 2 }, { EL_MAGIC_WALL_EMPTYING, 2 }, { EL_BD_MAGIC_WALL_FILLING, 2 }, { EL_BD_MAGIC_WALL_EMPTYING, 2 }, { EL_DC_MAGIC_WALL_FILLING, 2 }, { EL_DC_MAGIC_WALL_EMPTYING, 2 }, { EL_UNDEFINED, 0 }, }; struct { int element; int count; } collect_count_list[] = { { EL_EMERALD, 1 }, { EL_BD_DIAMOND, 1 }, { EL_EMERALD_YELLOW, 1 }, { EL_EMERALD_RED, 1 }, { EL_EMERALD_PURPLE, 1 }, { EL_DIAMOND, 3 }, { EL_SP_INFOTRON, 1 }, { EL_PEARL, 5 }, { EL_CRYSTAL, 8 }, { EL_UNDEFINED, 0 }, }; struct { int element; int direction; } access_direction_list[] = { { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN }, { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN }, { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP }, { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN }, { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP }, { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN }, { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP }, { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN }, { EL_SP_PORT_LEFT, MV_RIGHT }, { EL_SP_PORT_RIGHT, MV_LEFT }, { EL_SP_PORT_UP, MV_DOWN }, { EL_SP_PORT_DOWN, MV_UP }, { EL_SP_PORT_HORIZONTAL, MV_LEFT | MV_RIGHT }, { EL_SP_PORT_VERTICAL, MV_UP | MV_DOWN }, { EL_SP_PORT_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, { EL_SP_GRAVITY_PORT_LEFT, MV_RIGHT }, { EL_SP_GRAVITY_PORT_RIGHT, MV_LEFT }, { EL_SP_GRAVITY_PORT_UP, MV_DOWN }, { EL_SP_GRAVITY_PORT_DOWN, MV_UP }, { EL_SP_GRAVITY_ON_PORT_LEFT, MV_RIGHT }, { EL_SP_GRAVITY_ON_PORT_RIGHT, MV_LEFT }, { EL_SP_GRAVITY_ON_PORT_UP, MV_DOWN }, { EL_SP_GRAVITY_ON_PORT_DOWN, MV_UP }, { EL_SP_GRAVITY_OFF_PORT_LEFT, MV_RIGHT }, { EL_SP_GRAVITY_OFF_PORT_RIGHT, MV_LEFT }, { EL_SP_GRAVITY_OFF_PORT_UP, MV_DOWN }, { EL_SP_GRAVITY_OFF_PORT_DOWN, MV_UP }, { EL_UNDEFINED, MV_NONE } }; static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS]; #define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY]) #define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0) #define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \ IS_JUST_CHANGING(x, y)) #define CE_PAGE(e, ce) (element_info[e].event_page[ce]) /* static variables for playfield scan mode (scanning forward or backward) */ static int playfield_scan_start_x = 0; static int playfield_scan_start_y = 0; static int playfield_scan_delta_x = 1; static int playfield_scan_delta_y = 1; #define SCAN_PLAYFIELD(x, y) for ((y) = playfield_scan_start_y; \ (y) >= 0 && (y) <= lev_fieldy - 1; \ (y) += playfield_scan_delta_y) \ for ((x) = playfield_scan_start_x; \ (x) >= 0 && (x) <= lev_fieldx - 1; \ (x) += playfield_scan_delta_x) #ifdef DEBUG void DEBUG_SetMaximumDynamite() { int i; for (i = 0; i < MAX_INVENTORY_SIZE; i++) if (local_player->inventory_size < MAX_INVENTORY_SIZE) local_player->inventory_element[local_player->inventory_size++] = EL_DYNAMITE; } #endif static void InitPlayfieldScanModeVars() { if (game.use_reverse_scan_direction) { playfield_scan_start_x = lev_fieldx - 1; playfield_scan_start_y = lev_fieldy - 1; playfield_scan_delta_x = -1; playfield_scan_delta_y = -1; } else { playfield_scan_start_x = 0; playfield_scan_start_y = 0; playfield_scan_delta_x = 1; playfield_scan_delta_y = 1; } } static void InitPlayfieldScanMode(int mode) { game.use_reverse_scan_direction = (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE); InitPlayfieldScanModeVars(); } static int get_move_delay_from_stepsize(int move_stepsize) { move_stepsize = MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX); /* make sure that stepsize value is always a power of 2 */ move_stepsize = (1 << log_2(move_stepsize)); return TILEX / move_stepsize; } static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, boolean init_game) { int player_nr = player->index_nr; int move_delay = get_move_delay_from_stepsize(move_stepsize); boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE); /* do no immediately change move delay -- the player might just be moving */ player->move_delay_value_next = move_delay; /* information if player can move must be set separately */ player->cannot_move = cannot_move; if (init_game) { player->move_delay = game.initial_move_delay[player_nr]; player->move_delay_value = game.initial_move_delay_value[player_nr]; player->move_delay_value_next = -1; player->move_delay_reset_counter = 0; } } void GetPlayerConfig() { GameFrameDelay = setup.game_frame_delay; if (!audio.sound_available) setup.sound_simple = FALSE; if (!audio.loops_available) setup.sound_loops = FALSE; if (!audio.music_available) setup.sound_music = FALSE; if (!video.fullscreen_available) setup.fullscreen = FALSE; setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music); SetAudioMode(setup.sound); } int GetElementFromGroupElement(int element) { if (IS_GROUP_ELEMENT(element)) { struct ElementGroupInfo *group = element_info[element].group; int last_anim_random_frame = gfx.anim_random_frame; int element_pos; if (group->choice_mode == ANIM_RANDOM) gfx.anim_random_frame = RND(group->num_elements_resolved); element_pos = getAnimationFrame(group->num_elements_resolved, 1, group->choice_mode, 0, group->choice_pos); if (group->choice_mode == ANIM_RANDOM) gfx.anim_random_frame = last_anim_random_frame; group->choice_pos++; element = group->element_resolved[element_pos]; } return element; } static void InitPlayerField(int x, int y, int element, boolean init_game) { if (element == EL_SP_MURPHY) { if (init_game) { if (stored_player[0].present) { Feld[x][y] = EL_SP_MURPHY_CLONE; return; } else { stored_player[0].initial_element = element; stored_player[0].use_murphy = TRUE; if (!level.use_artwork_element[0]) stored_player[0].artwork_element = EL_SP_MURPHY; } Feld[x][y] = EL_PLAYER_1; } } if (init_game) { struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1]; int jx = player->jx, jy = player->jy; player->present = TRUE; player->block_last_field = (element == EL_SP_MURPHY ? level.sp_block_last_field : level.block_last_field); /* ---------- initialize player's last field block delay --------------- */ /* always start with reliable default value (no adjustment needed) */ player->block_delay_adjustment = 0; /* special case 1: in Supaplex, Murphy blocks last field one more frame */ if (player->block_last_field && element == EL_SP_MURPHY) player->block_delay_adjustment = 1; /* special case 2: in game engines before 3.1.1, blocking was different */ if (game.use_block_last_field_bug) player->block_delay_adjustment = (player->block_last_field ? -1 : 1); 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 DEBUG_INIT_PLAYER if (options.debug) { printf("- player element %d activated", player->element_nr); printf(" (local player is %d and currently %s)\n", local_player->element_nr, local_player->active ? "active" : "not active"); } } #endif Feld[x][y] = EL_EMPTY; player->jx = player->last_jx = x; player->jy = player->last_jy = y; } if (!init_game) { int player_nr = GET_PLAYER_NR(element); struct PlayerInfo *player = &stored_player[player_nr]; if (player->active && player->killed) player->reanimated = TRUE; /* if player was just killed, reanimate him */ } } static void InitField(int x, int y, boolean init_game) { int element = Feld[x][y]; switch (element) { case EL_SP_MURPHY: case EL_PLAYER_1: case EL_PLAYER_2: case EL_PLAYER_3: case EL_PLAYER_4: InitPlayerField(x, y, element, init_game); break; case EL_SOKOBAN_FIELD_PLAYER: element = Feld[x][y] = EL_PLAYER_1; InitField(x, y, init_game); element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY; InitField(x, y, init_game); break; case EL_SOKOBAN_FIELD_EMPTY: local_player->sokobanfields_still_needed++; break; case EL_STONEBLOCK: if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID) Feld[x][y] = EL_ACID_POOL_TOPLEFT; else if (x > 0 && Feld[x-1][y] == EL_ACID) Feld[x][y] = EL_ACID_POOL_TOPRIGHT; else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT) Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT; else if (y > 0 && Feld[x][y-1] == EL_ACID) Feld[x][y] = EL_ACID_POOL_BOTTOM; else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT) Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT; break; case EL_BUG: case EL_BUG_RIGHT: case EL_BUG_UP: case EL_BUG_LEFT: case EL_BUG_DOWN: case EL_SPACESHIP: case EL_SPACESHIP_RIGHT: case EL_SPACESHIP_UP: case EL_SPACESHIP_LEFT: case EL_SPACESHIP_DOWN: case EL_BD_BUTTERFLY: case EL_BD_BUTTERFLY_RIGHT: case EL_BD_BUTTERFLY_UP: case EL_BD_BUTTERFLY_LEFT: case EL_BD_BUTTERFLY_DOWN: case EL_BD_FIREFLY: case EL_BD_FIREFLY_RIGHT: case EL_BD_FIREFLY_UP: case EL_BD_FIREFLY_LEFT: case EL_BD_FIREFLY_DOWN: case EL_PACMAN_RIGHT: case EL_PACMAN_UP: case EL_PACMAN_LEFT: case EL_PACMAN_DOWN: case EL_YAMYAM: case EL_YAMYAM_LEFT: case EL_YAMYAM_RIGHT: case EL_YAMYAM_UP: case EL_YAMYAM_DOWN: case EL_DARK_YAMYAM: case EL_ROBOT: case EL_PACMAN: case EL_SP_SNIKSNAK: case EL_SP_ELECTRON: case EL_MOLE: case EL_MOLE_LEFT: case EL_MOLE_RIGHT: case EL_MOLE_UP: case EL_MOLE_DOWN: InitMovDir(x, y); break; case EL_AMOEBA_FULL: case EL_BD_AMOEBA: InitAmoebaNr(x, y); break; case EL_AMOEBA_DROP: if (y == lev_fieldy - 1) { Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; } break; case EL_DYNAMITE_ACTIVE: case EL_SP_DISK_RED_ACTIVE: case EL_DYNABOMB_PLAYER_1_ACTIVE: case EL_DYNABOMB_PLAYER_2_ACTIVE: case EL_DYNABOMB_PLAYER_3_ACTIVE: case EL_DYNABOMB_PLAYER_4_ACTIVE: MovDelay[x][y] = 96; break; case EL_EM_DYNAMITE_ACTIVE: MovDelay[x][y] = 32; break; case EL_LAMP: local_player->lights_still_needed++; break; case EL_PENGUIN: local_player->friends_still_needed++; break; case EL_PIG: case EL_DRAGON: GfxDir[x][y] = MovDir[x][y] = 1 << RND(4); break; case EL_CONVEYOR_BELT_1_SWITCH_LEFT: case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_1_SWITCH_RIGHT: case EL_CONVEYOR_BELT_2_SWITCH_LEFT: case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_2_SWITCH_RIGHT: case EL_CONVEYOR_BELT_3_SWITCH_LEFT: case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_3_SWITCH_RIGHT: case EL_CONVEYOR_BELT_4_SWITCH_LEFT: case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_4_SWITCH_RIGHT: if (init_game) { int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]); int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]); int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]); if (game.belt_dir_nr[belt_nr] == 3) /* initial value */ { game.belt_dir[belt_nr] = belt_dir; game.belt_dir_nr[belt_nr] = belt_dir_nr; } else /* more than one switch -- set it like the first switch */ { Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr]; } } break; case EL_LIGHT_SWITCH_ACTIVE: if (init_game) game.light_time_left = level.time_light * FRAMES_PER_SECOND; break; case EL_INVISIBLE_STEELWALL: case EL_INVISIBLE_WALL: case EL_INVISIBLE_SAND: if (game.light_time_left > 0 || game.lenses_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); break; case EL_EMC_MAGIC_BALL: if (game.ball_state) Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE; break; case EL_EMC_MAGIC_BALL_SWITCH: if (game.ball_state) Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE; break; case EL_TRIGGER_PLAYER: case EL_TRIGGER_ELEMENT: case EL_TRIGGER_CE_VALUE: case EL_TRIGGER_CE_SCORE: case EL_SELF: case EL_ANY_ELEMENT: case EL_CURRENT_CE_VALUE: case EL_CURRENT_CE_SCORE: case EL_PREV_CE_1: case EL_PREV_CE_2: case EL_PREV_CE_3: case EL_PREV_CE_4: case EL_PREV_CE_5: case EL_PREV_CE_6: case EL_PREV_CE_7: case EL_PREV_CE_8: case EL_NEXT_CE_1: case EL_NEXT_CE_2: case EL_NEXT_CE_3: case EL_NEXT_CE_4: case EL_NEXT_CE_5: case EL_NEXT_CE_6: case EL_NEXT_CE_7: case EL_NEXT_CE_8: /* reference elements should not be used on the playfield */ Feld[x][y] = EL_EMPTY; break; default: if (IS_CUSTOM_ELEMENT(element)) { if (CAN_MOVE(element)) InitMovDir(x, y); if (!element_info[element].use_last_ce_value || init_game) CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); } else if (IS_GROUP_ELEMENT(element)) { Feld[x][y] = GetElementFromGroupElement(element); InitField(x, y, init_game); } break; } if (!init_game) CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); } inline static void InitField_WithBug1(int x, int y, boolean init_game) { InitField(x, y, init_game); /* not needed to call InitMovDir() -- already done by InitField()! */ if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(Feld[x][y])) InitMovDir(x, y); } inline static void InitField_WithBug2(int x, int y, boolean init_game) { int old_element = Feld[x][y]; InitField(x, y, init_game); /* not needed to call InitMovDir() -- already done by InitField()! */ if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(old_element) && (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN)) InitMovDir(x, y); /* this case is in fact a combination of not less than three bugs: first, it calls InitMovDir() for elements that can move, although this is already done by InitField(); then, it checks the element that was at this field _before_ the call to InitField() (which can change it); lastly, it was not called for "mole with direction" elements, which were treated as "cannot move" due to (fixed) wrong element initialization in "src/init.c" */ } static int get_key_element_from_nr(int key_nr) { int key_base_element = (key_nr >= STD_NUM_KEYS ? EL_EMC_KEY_5 - STD_NUM_KEYS : level.game_engine_type == GAME_ENGINE_TYPE_EM ? EL_EM_KEY_1 : EL_KEY_1); return key_base_element + key_nr; } static int get_next_dropped_element(struct PlayerInfo *player) { return (player->inventory_size > 0 ? player->inventory_element[player->inventory_size - 1] : player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left > 0 ? EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : EL_UNDEFINED); } static int get_inventory_element_from_pos(struct PlayerInfo *player, int pos) { /* pos >= 0: get element from bottom of the stack; pos < 0: get element from top of the stack */ if (pos < 0) { int min_inventory_size = -pos; int inventory_pos = player->inventory_size - min_inventory_size; int min_dynabombs_left = min_inventory_size - player->inventory_size; return (player->inventory_size >= min_inventory_size ? player->inventory_element[inventory_pos] : player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left >= min_dynabombs_left ? EL_DYNABOMB_PLAYER_1 + player->index_nr : EL_UNDEFINED); } else { int min_dynabombs_left = pos + 1; int min_inventory_size = pos + 1 - player->dynabombs_left; int inventory_pos = pos - player->dynabombs_left; return (player->inventory_infinite_element != EL_UNDEFINED ? player->inventory_infinite_element : player->dynabombs_left >= min_dynabombs_left ? EL_DYNABOMB_PLAYER_1 + player->index_nr : player->inventory_size >= min_inventory_size ? player->inventory_element[inventory_pos] : EL_UNDEFINED); } } static int compareGamePanelOrderInfo(const void *object1, const void *object2) { const struct GamePanelOrderInfo *gpo1 = (struct GamePanelOrderInfo *)object1; const struct GamePanelOrderInfo *gpo2 = (struct GamePanelOrderInfo *)object2; int compare_result; if (gpo1->sort_priority != gpo2->sort_priority) compare_result = gpo1->sort_priority - gpo2->sort_priority; else compare_result = gpo1->nr - gpo2->nr; return compare_result; } int getPlayerInventorySize(int player_nr) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) return level.native_em_level->ply[player_nr]->dynamite; else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return level.native_sp_level->game_sp->red_disk_count; else return stored_player[player_nr].inventory_size; } void InitGameControlValues() { int i; for (i = 0; game_panel_controls[i].nr != -1; i++) { struct GamePanelControlInfo *gpc = &game_panel_controls[i]; struct GamePanelOrderInfo *gpo = &game_panel_order[i]; struct TextPosInfo *pos = gpc->pos; int nr = gpc->nr; int type = gpc->type; if (nr != i) { Error(ERR_INFO, "'game_panel_controls' structure corrupted at %d", i); Error(ERR_EXIT, "this should not happen -- please debug"); } /* force update of game controls after initialization */ gpc->value = gpc->last_value = -1; gpc->frame = gpc->last_frame = -1; gpc->gfx_frame = -1; /* determine panel value width for later calculation of alignment */ if (type == TYPE_INTEGER || type == TYPE_STRING) { pos->width = pos->size * getFontWidth(pos->font); pos->height = getFontHeight(pos->font); } else if (type == TYPE_ELEMENT) { pos->width = pos->size; pos->height = pos->size; } /* fill structure for game panel draw order */ gpo->nr = gpc->nr; gpo->sort_priority = pos->sort_priority; } /* sort game panel controls according to sort_priority and control number */ qsort(game_panel_order, NUM_GAME_PANEL_CONTROLS, sizeof(struct GamePanelOrderInfo), compareGamePanelOrderInfo); } void UpdatePlayfieldElementCount() { boolean use_element_count = FALSE; int i, j, x, y; /* first check if it is needed at all to calculate playfield element count */ for (i = GAME_PANEL_ELEMENT_COUNT_1; i <= GAME_PANEL_ELEMENT_COUNT_8; i++) if (!PANEL_DEACTIVATED(game_panel_controls[i].pos)) use_element_count = TRUE; if (!use_element_count) return; for (i = 0; i < MAX_NUM_ELEMENTS; i++) element_info[i].element_count = 0; SCAN_PLAYFIELD(x, y) { element_info[Feld[x][y]].element_count++; } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (IS_IN_GROUP(j, i)) element_info[EL_GROUP_START + i].element_count += element_info[j].element_count; } void UpdateGameControlValues() { int i, k; int time = (local_player->LevelSolved ? local_player->LevelSolved_CountingTime : level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->time : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->time_played : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.energy_left : game.no_time_limit ? TimePlayed : TimeLeft); int score = (local_player->LevelSolved ? local_player->LevelSolved_CountingScore : level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->score : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score : local_player->score); int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->required : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->infotrons_still_needed : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.kettles_still_needed : local_player->gems_still_needed); int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->required > 0 : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->infotrons_still_needed > 0 : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.kettles_still_needed > 0 || game_mm.lights_still_needed > 0 : local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0); int health = (local_player->LevelSolved ? local_player->LevelSolved_CountingHealth : level.game_engine_type == GAME_ENGINE_TYPE_MM ? MM_HEALTH(game_mm.laser_overload_value) : local_player->health); UpdatePlayfieldElementCount(); /* update game panel control values */ game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = level_nr; game_panel_controls[GAME_PANEL_GEMS].value = gems; game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0; for (i = 0; i < MAX_NUM_KEYS; i++) game_panel_controls[GAME_PANEL_KEY_1 + i].value = EL_EMPTY; game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_EMPTY; game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value = 0; if (game.centered_player_nr == -1) { for (i = 0; i < MAX_PLAYERS; i++) { /* only one player in Supaplex game engine */ if (level.game_engine_type == GAME_ENGINE_TYPE_SP && i > 0) break; for (k = 0; k < MAX_NUM_KEYS; k++) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->ply[i]->keys & (1 << k)) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } else if (stored_player[i].key[k]) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += getPlayerInventorySize(i); if (stored_player[i].num_white_keys > 0) game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += stored_player[i].num_white_keys; } } else { int player_nr = game.centered_player_nr; for (k = 0; k < MAX_NUM_KEYS; k++) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->ply[player_nr]->keys & (1 << k)) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } else if (stored_player[player_nr].key[k]) game_panel_controls[GAME_PANEL_KEY_1 + k].value = get_key_element_from_nr(k); } game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += getPlayerInventorySize(player_nr); if (stored_player[player_nr].num_white_keys > 0) game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += stored_player[player_nr].num_white_keys; } for (i = 0; i < NUM_PANEL_INVENTORY; i++) { game_panel_controls[GAME_PANEL_INVENTORY_FIRST_1 + i].value = get_inventory_element_from_pos(local_player, i); game_panel_controls[GAME_PANEL_INVENTORY_LAST_1 + i].value = get_inventory_element_from_pos(local_player, -i - 1); } game_panel_controls[GAME_PANEL_SCORE].value = score; game_panel_controls[GAME_PANEL_HIGHSCORE].value = highscore[0].Score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_TIME_HH].value = time / 3600; game_panel_controls[GAME_PANEL_TIME_MM].value = (time / 60) % 60; game_panel_controls[GAME_PANEL_TIME_SS].value = time % 60; if (level.time == 0) game_panel_controls[GAME_PANEL_TIME_ANIM].value = 100; else game_panel_controls[GAME_PANEL_TIME_ANIM].value = time * 100 / level.time; game_panel_controls[GAME_PANEL_HEALTH].value = health; game_panel_controls[GAME_PANEL_HEALTH_ANIM].value = health; game_panel_controls[GAME_PANEL_FRAME].value = FrameCounter; game_panel_controls[GAME_PANEL_SHIELD_NORMAL].value = (local_player->shield_normal_time_left > 0 ? EL_SHIELD_NORMAL_ACTIVE : EL_EMPTY); game_panel_controls[GAME_PANEL_SHIELD_NORMAL_TIME].value = local_player->shield_normal_time_left; game_panel_controls[GAME_PANEL_SHIELD_DEADLY].value = (local_player->shield_deadly_time_left > 0 ? EL_SHIELD_DEADLY_ACTIVE : EL_EMPTY); game_panel_controls[GAME_PANEL_SHIELD_DEADLY_TIME].value = local_player->shield_deadly_time_left; game_panel_controls[GAME_PANEL_EXIT].value = (exit_closed ? EL_EXIT_CLOSED : EL_EXIT_OPEN); game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL].value = (game.ball_state ? EL_EMC_MAGIC_BALL_ACTIVE : EL_EMC_MAGIC_BALL); game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL_SWITCH].value = (game.ball_state ? EL_EMC_MAGIC_BALL_SWITCH_ACTIVE : EL_EMC_MAGIC_BALL_SWITCH); game_panel_controls[GAME_PANEL_LIGHT_SWITCH].value = (game.light_time_left > 0 ? EL_LIGHT_SWITCH_ACTIVE : EL_LIGHT_SWITCH); game_panel_controls[GAME_PANEL_LIGHT_SWITCH_TIME].value = game.light_time_left; game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH].value = (game.timegate_time_left > 0 ? EL_TIMEGATE_OPEN : EL_TIMEGATE_CLOSED); game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH_TIME].value = game.timegate_time_left; game_panel_controls[GAME_PANEL_SWITCHGATE_SWITCH].value = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; game_panel_controls[GAME_PANEL_EMC_LENSES].value = (game.lenses_time_left > 0 ? EL_EMC_LENSES : EL_EMPTY); game_panel_controls[GAME_PANEL_EMC_LENSES_TIME].value = game.lenses_time_left; game_panel_controls[GAME_PANEL_EMC_MAGNIFIER].value = (game.magnify_time_left > 0 ? EL_EMC_MAGNIFIER : EL_EMPTY); game_panel_controls[GAME_PANEL_EMC_MAGNIFIER_TIME].value = game.magnify_time_left; game_panel_controls[GAME_PANEL_BALLOON_SWITCH].value = (game.wind_direction == MV_LEFT ? EL_BALLOON_SWITCH_LEFT : game.wind_direction == MV_RIGHT ? EL_BALLOON_SWITCH_RIGHT : game.wind_direction == MV_UP ? EL_BALLOON_SWITCH_UP : game.wind_direction == MV_DOWN ? EL_BALLOON_SWITCH_DOWN : EL_BALLOON_SWITCH_NONE); game_panel_controls[GAME_PANEL_DYNABOMB_NUMBER].value = local_player->dynabomb_count; game_panel_controls[GAME_PANEL_DYNABOMB_SIZE].value = local_player->dynabomb_size; game_panel_controls[GAME_PANEL_DYNABOMB_POWER].value = (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY); game_panel_controls[GAME_PANEL_PENGUINS].value = local_player->friends_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value = local_player->sokobanfields_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value = local_player->sokobanfields_still_needed; game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value = (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL); for (i = 0; i < NUM_BELTS; i++) { game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1 + i].value = (game.belt_dir[i] != MV_NONE ? EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE : EL_CONVEYOR_BELT_1_MIDDLE) + i; game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1_SWITCH + i].value = getBeltSwitchElementFromBeltNrAndBeltDir(i, game.belt_dir[i]); } game_panel_controls[GAME_PANEL_MAGIC_WALL].value = (game.magic_wall_active ? EL_MAGIC_WALL_ACTIVE : EL_MAGIC_WALL); game_panel_controls[GAME_PANEL_MAGIC_WALL_TIME].value = game.magic_wall_time_left; game_panel_controls[GAME_PANEL_GRAVITY_STATE].value = local_player->gravity; for (i = 0; i < NUM_PANEL_GRAPHICS; i++) game_panel_controls[GAME_PANEL_GRAPHIC_1 + i].value = EL_GRAPHIC_1 + i; for (i = 0; i < NUM_PANEL_ELEMENTS; i++) game_panel_controls[GAME_PANEL_ELEMENT_1 + i].value = (IS_DRAWABLE_ELEMENT(game.panel.element[i].id) ? game.panel.element[i].id : EL_UNDEFINED); for (i = 0; i < NUM_PANEL_ELEMENTS; i++) game_panel_controls[GAME_PANEL_ELEMENT_COUNT_1 + i].value = (IS_VALID_ELEMENT(game.panel.element_count[i].id) ? element_info[game.panel.element_count[i].id].element_count : 0); for (i = 0; i < NUM_PANEL_CE_SCORE; i++) game_panel_controls[GAME_PANEL_CE_SCORE_1 + i].value = (IS_CUSTOM_ELEMENT(game.panel.ce_score[i].id) ? element_info[game.panel.ce_score[i].id].collect_score : 0); for (i = 0; i < NUM_PANEL_CE_SCORE; i++) game_panel_controls[GAME_PANEL_CE_SCORE_1_ELEMENT + i].value = (IS_CUSTOM_ELEMENT(game.panel.ce_score_element[i].id) ? element_info[game.panel.ce_score_element[i].id].collect_score : EL_UNDEFINED); game_panel_controls[GAME_PANEL_PLAYER_NAME].value = 0; game_panel_controls[GAME_PANEL_LEVEL_NAME].value = 0; game_panel_controls[GAME_PANEL_LEVEL_AUTHOR].value = 0; /* update game panel control frames */ for (i = 0; game_panel_controls[i].nr != -1; i++) { struct GamePanelControlInfo *gpc = &game_panel_controls[i]; if (gpc->type == TYPE_ELEMENT) { if (gpc->value != EL_UNDEFINED && gpc->value != EL_EMPTY) { int last_anim_random_frame = gfx.anim_random_frame; int element = gpc->value; int graphic = el2panelimg(element); if (gpc->value != gpc->last_value) { gpc->gfx_frame = 0; gpc->gfx_random = INIT_GFX_RANDOM(); } else { gpc->gfx_frame++; if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(gpc->gfx_frame, graphic)) gpc->gfx_random = INIT_GFX_RANDOM(); } if (ANIM_MODE(graphic) == ANIM_RANDOM) gfx.anim_random_frame = gpc->gfx_random; if (ANIM_MODE(graphic) == ANIM_CE_SCORE) gpc->gfx_frame = element_info[element].collect_score; gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value), gpc->gfx_frame); if (ANIM_MODE(graphic) == ANIM_RANDOM) gfx.anim_random_frame = last_anim_random_frame; } } else if (gpc->type == TYPE_GRAPHIC) { if (gpc->graphic != IMG_UNDEFINED) { int last_anim_random_frame = gfx.anim_random_frame; int graphic = gpc->graphic; if (gpc->value != gpc->last_value) { gpc->gfx_frame = 0; gpc->gfx_random = INIT_GFX_RANDOM(); } else { gpc->gfx_frame++; if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(gpc->gfx_frame, graphic)) gpc->gfx_random = INIT_GFX_RANDOM(); } if (ANIM_MODE(graphic) == ANIM_RANDOM) gfx.anim_random_frame = gpc->gfx_random; gpc->frame = getGraphicAnimationFrame(graphic, gpc->gfx_frame); if (ANIM_MODE(graphic) == ANIM_RANDOM) gfx.anim_random_frame = last_anim_random_frame; } } } } void DisplayGameControlValues() { boolean redraw_panel = FALSE; int i; for (i = 0; game_panel_controls[i].nr != -1; i++) { struct GamePanelControlInfo *gpc = &game_panel_controls[i]; if (PANEL_DEACTIVATED(gpc->pos)) continue; if (gpc->value == gpc->last_value && gpc->frame == gpc->last_frame) continue; redraw_panel = TRUE; } if (!redraw_panel) return; /* copy default game door content to main double buffer */ /* !!! CHECK AGAIN !!! */ SetPanelBackground(); // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL); DrawBackground(DX, DY, DXSIZE, DYSIZE); /* redraw game control buttons */ RedrawGameButtons(); SetGameStatus(GAME_MODE_PSEUDO_PANEL); for (i = 0; i < NUM_GAME_PANEL_CONTROLS; i++) { int nr = game_panel_order[i].nr; struct GamePanelControlInfo *gpc = &game_panel_controls[nr]; struct TextPosInfo *pos = gpc->pos; int type = gpc->type; int value = gpc->value; int frame = gpc->frame; int size = pos->size; int font = pos->font; boolean draw_masked = pos->draw_masked; int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_OPAQUE); if (PANEL_DEACTIVATED(pos)) continue; gpc->last_value = value; gpc->last_frame = frame; if (type == TYPE_INTEGER) { if (nr == GAME_PANEL_LEVEL_NUMBER || nr == GAME_PANEL_TIME) { boolean use_dynamic_size = (size == -1 ? TRUE : FALSE); if (use_dynamic_size) /* use dynamic number of digits */ { int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000); int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3); int size2 = size1 + 1; int font1 = pos->font; int font2 = pos->font_alt; size = (value < value_change ? size1 : size2); font = (value < value_change ? font1 : font2); } } /* correct text size if "digits" is zero or less */ if (size <= 0) size = strlen(int2str(value, size)); /* dynamically correct text alignment */ pos->width = size * getFontWidth(font); DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, size), font, mask_mode); } else if (type == TYPE_ELEMENT) { int element, graphic; Bitmap *src_bitmap; int src_x, src_y; int width, height; int dst_x = PANEL_XPOS(pos); int dst_y = PANEL_YPOS(pos); if (value != EL_UNDEFINED && value != EL_EMPTY) { element = value; graphic = el2panelimg(value); // printf("::: %d, '%s' [%d]\n", element, EL_NAME(element), size); if (element >= EL_GRAPHIC_1 && element <= EL_GRAPHIC_8 && size == 0) size = TILESIZE; getSizedGraphicSource(graphic, frame, size, &src_bitmap, &src_x, &src_y); width = graphic_info[graphic].width * size / TILESIZE; height = graphic_info[graphic].height * size / TILESIZE; if (draw_masked) BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); } } else if (type == TYPE_GRAPHIC) { int graphic = gpc->graphic; int graphic_active = gpc->graphic_active; Bitmap *src_bitmap; int src_x, src_y; int width, height; int dst_x = PANEL_XPOS(pos); int dst_y = PANEL_YPOS(pos); boolean skip = (pos->class == get_hash_from_key("mm_engine_only") && level.game_engine_type != GAME_ENGINE_TYPE_MM); if (graphic != IMG_UNDEFINED && !skip) { if (pos->style == STYLE_REVERSE) value = 100 - value; getGraphicSource(graphic_active, frame, &src_bitmap, &src_x, &src_y); if (pos->direction & MV_HORIZONTAL) { width = graphic_info[graphic_active].width * value / 100; height = graphic_info[graphic_active].height; if (pos->direction == MV_LEFT) { src_x += graphic_info[graphic_active].width - width; dst_x += graphic_info[graphic_active].width - width; } } else { width = graphic_info[graphic_active].width; height = graphic_info[graphic_active].height * value / 100; if (pos->direction == MV_UP) { src_y += graphic_info[graphic_active].height - height; dst_y += graphic_info[graphic_active].height - height; } } if (draw_masked) BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); if (pos->direction & MV_HORIZONTAL) { if (pos->direction == MV_RIGHT) { src_x += width; dst_x += width; } else { dst_x = PANEL_XPOS(pos); } width = graphic_info[graphic].width - width; } else { if (pos->direction == MV_DOWN) { src_y += height; dst_y += height; } else { dst_y = PANEL_YPOS(pos); } height = graphic_info[graphic].height - height; } if (draw_masked) BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); } } else if (type == TYPE_STRING) { boolean active = (value != 0); char *state_normal = "off"; char *state_active = "on"; char *state = (active ? state_active : state_normal); char *s = (nr == GAME_PANEL_GRAVITY_STATE ? state : nr == GAME_PANEL_PLAYER_NAME ? setup.player_name : nr == GAME_PANEL_LEVEL_NAME ? level.name : nr == GAME_PANEL_LEVEL_AUTHOR ? level.author : NULL); if (nr == GAME_PANEL_GRAVITY_STATE) { int font1 = pos->font; /* (used for normal state) */ int font2 = pos->font_alt; /* (used for active state) */ font = (active ? font2 : font1); } if (s != NULL) { char *s_cut; if (size <= 0) { /* don't truncate output if "chars" is zero or less */ size = strlen(s); /* dynamically correct text alignment */ pos->width = size * getFontWidth(font); } s_cut = getStringCopyN(s, size); DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), s_cut, font, mask_mode); free(s_cut); } } redraw_mask |= REDRAW_DOOR_1; } SetGameStatus(GAME_MODE_PLAYING); } void UpdateAndDisplayGameControlValues() { if (tape.deactivate_display) return; UpdateGameControlValues(); DisplayGameControlValues(); } void UpdateGameDoorValues() { UpdateGameControlValues(); } void DrawGameDoorValues() { DisplayGameControlValues(); } /* ============================================================================= InitGameEngine() ----------------------------------------------------------------------------- initialize game engine due to level / tape version number ============================================================================= */ static void InitGameEngine() { int i, j, k, l, x, y; /* set game engine from tape file when re-playing, else from level file */ game.engine_version = (tape.playing ? tape.engine_version : level.game_version); /* set single or multi-player game mode (needed for re-playing tapes) */ game.team_mode = setup.team_mode; if (tape.playing) { int num_players = 0; for (i = 0; i < MAX_PLAYERS; i++) if (tape.player_participates[i]) num_players++; /* multi-player tapes contain input data for more than one player */ game.team_mode = (num_players > 1); } /* ---------------------------------------------------------------------- */ /* set flags for bugs and changes according to active game engine version */ /* ---------------------------------------------------------------------- */ /* Summary of bugfix/change: Fixed handling for custom elements that change when pushed by the player. Fixed/changed in version: 3.1.0 Description: Before 3.1.0, custom elements that "change when pushing" changed directly after the player started pushing them (until then handled in "DigField()"). Since 3.1.0, these custom elements are not changed until the "pushing" move of the element is finished (now handled in "ContinueMoving()"). Affected levels/tapes: The first condition is generally needed for all levels/tapes before version 3.1.0, which might use the old behaviour before it was changed; known tapes that are affected are some tapes from the level set "Walpurgis Gardens" by Jamie Cullen. The second condition is an exception from the above case and is needed for the special case of tapes recorded with game (not engine!) version 3.1.0 or above (including some development versions of 3.1.0), but before it was known that this change would break tapes like the above and was fixed in 3.1.1, so that the changed behaviour was active although the engine version while recording maybe was before 3.1.0. There is at least one tape that is affected by this exception, which is the tape for the one-level set "Bug Machine" by Juergen Bonhagen. */ game.use_change_when_pushing_bug = (game.engine_version < VERSION_IDENT(3,1,0,0) && !(tape.playing && tape.game_version >= VERSION_IDENT(3,1,0,0) && tape.game_version < VERSION_IDENT(3,1,1,0))); /* Summary of bugfix/change: Fixed handling for blocking the field the player leaves when moving. Fixed/changed in version: 3.1.1 Description: Before 3.1.1, when "block last field when moving" was enabled, the field the player is leaving when moving was blocked for the time of the move, and was directly unblocked afterwards. This resulted in the last field being blocked for exactly one less than the number of frames of one player move. Additionally, even when blocking was disabled, the last field was blocked for exactly one frame. Since 3.1.1, due to changes in player movement handling, the last field is not blocked at all when blocking is disabled. When blocking is enabled, the last field is blocked for exactly the number of frames of one player move. Additionally, if the player is Murphy, the hero of Supaplex, the last field is blocked for exactly one more than the number of frames of one player move. Affected levels/tapes: (!!! yet to be determined -- probably many !!!) */ game.use_block_last_field_bug = (game.engine_version < VERSION_IDENT(3,1,1,0)); game_em.use_single_button = (game.engine_version > VERSION_IDENT(4,0,0,2)); game_em.use_snap_key_bug = (game.engine_version < VERSION_IDENT(4,0,1,0)); /* ---------------------------------------------------------------------- */ /* set maximal allowed number of custom element changes per game frame */ game.max_num_changes_per_frame = 1; /* default scan direction: scan playfield from top/left to bottom/right */ InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL); /* dynamically adjust element properties according to game engine version */ InitElementPropertiesEngine(game.engine_version); #if 0 printf("level %d: level version == %06d\n", level_nr, level.game_version); printf(" tape version == %06d [%s] [file: %06d]\n", tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"), tape.file_version); printf(" => game.engine_version == %06d\n", game.engine_version); #endif /* ---------- initialize player's initial move delay --------------------- */ /* dynamically adjust player properties according to level information */ for (i = 0; i < MAX_PLAYERS; i++) game.initial_move_delay_value[i] = get_move_delay_from_stepsize(level.initial_player_stepsize[i]); /* dynamically adjust player properties according to game engine version */ for (i = 0; i < MAX_PLAYERS; i++) game.initial_move_delay[i] = (game.engine_version <= VERSION_IDENT(2,0,1,0) ? game.initial_move_delay_value[i] : 0); /* ---------- initialize player's initial push delay --------------------- */ /* dynamically adjust player properties according to game engine version */ game.initial_push_delay_value = (game.engine_version < VERSION_IDENT(3,0,7,1) ? 5 : -1); /* ---------- initialize changing elements ------------------------------- */ /* initialize changing elements information */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; /* this pointer might have been changed in the level editor */ ei->change = &ei->change_page[0]; if (!IS_CUSTOM_ELEMENT(i)) { ei->change->target_element = EL_EMPTY_SPACE; ei->change->delay_fixed = 0; ei->change->delay_random = 0; ei->change->delay_frames = 1; } for (j = 0; j < NUM_CHANGE_EVENTS; j++) { ei->has_change_event[j] = FALSE; ei->event_page_nr[j] = 0; ei->event_page[j] = &ei->change_page[0]; } } /* add changing elements from pre-defined list */ for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++) { struct ChangingElementInfo *ch_delay = &change_delay_list[i]; struct ElementInfo *ei = &element_info[ch_delay->element]; ei->change->target_element = ch_delay->target_element; ei->change->delay_fixed = ch_delay->change_delay; ei->change->pre_change_function = ch_delay->pre_change_function; ei->change->change_function = ch_delay->change_function; ei->change->post_change_function = ch_delay->post_change_function; ei->change->can_change = TRUE; ei->change->can_change_or_has_action = TRUE; ei->has_change_event[CE_DELAY] = TRUE; SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE); SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE); } /* ---------- initialize internal run-time variables --------------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; for (j = 0; j < ei->num_change_pages; j++) { ei->change_page[j].can_change_or_has_action = (ei->change_page[j].can_change | ei->change_page[j].has_action); } } /* add change events from custom element configuration */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change_or_has_action) continue; for (k = 0; k < NUM_CHANGE_EVENTS; k++) { /* only add event page for the first page found with this event */ if (ei->change_page[j].has_event[k] && !(ei->has_change_event[k])) { ei->has_change_event[k] = TRUE; ei->event_page_nr[k] = j; ei->event_page[k] = &ei->change_page[j]; } } } } /* ---------- initialize reference elements in change conditions --------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; for (j = 0; j < ei->num_change_pages; j++) { int trigger_element = ei->change_page[j].initial_trigger_element; if (trigger_element >= EL_PREV_CE_8 && trigger_element <= EL_NEXT_CE_8) trigger_element = RESOLVED_REFERENCE_ELEMENT(element, trigger_element); ei->change_page[j].trigger_element = trigger_element; } } /* ---------- initialize run-time trigger player and element ------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; for (j = 0; j < ei->num_change_pages; j++) { ei->change_page[j].actual_trigger_element = EL_EMPTY; ei->change_page[j].actual_trigger_player = EL_EMPTY; ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_NONE; ei->change_page[j].actual_trigger_side = CH_SIDE_NONE; ei->change_page[j].actual_trigger_ce_value = 0; ei->change_page[j].actual_trigger_ce_score = 0; } } /* ---------- initialize trigger events ---------------------------------- */ /* initialize trigger events information */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_CHANGE_EVENTS; j++) trigger_events[i][j] = FALSE; /* add trigger events from element change event properties */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change_or_has_action) continue; if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION]) { int trigger_element = ei->change_page[j].trigger_element; for (k = 0; k < NUM_CHANGE_EVENTS; k++) { if (ei->change_page[j].has_event[k]) { if (IS_GROUP_ELEMENT(trigger_element)) { struct ElementGroupInfo *group = element_info[trigger_element].group; for (l = 0; l < group->num_elements_resolved; l++) trigger_events[group->element_resolved[l]][k] = TRUE; } else if (trigger_element == EL_ANY_ELEMENT) for (l = 0; l < MAX_NUM_ELEMENTS; l++) trigger_events[l][k] = TRUE; else trigger_events[trigger_element][k] = TRUE; } } } } } /* ---------- initialize push delay -------------------------------------- */ /* initialize push delay values to default */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { /* set default push delay values (corrected since version 3.0.7-1) */ if (game.engine_version < VERSION_IDENT(3,0,7,1)) { element_info[i].push_delay_fixed = 2; element_info[i].push_delay_random = 8; } else { element_info[i].push_delay_fixed = 8; element_info[i].push_delay_random = 8; } } } /* set push delay value for certain elements from pre-defined list */ for (i = 0; push_delay_list[i].element != EL_UNDEFINED; i++) { int e = push_delay_list[i].element; element_info[e].push_delay_fixed = push_delay_list[i].push_delay_fixed; element_info[e].push_delay_random = push_delay_list[i].push_delay_random; } /* set push delay value for Supaplex elements for newer engine versions */ if (game.engine_version >= VERSION_IDENT(3,1,0,0)) { for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_SP_ELEMENT(i)) { /* set SP push delay to just enough to push under a falling zonk */ int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6); element_info[i].push_delay_fixed = delay; element_info[i].push_delay_random = 0; } } } /* ---------- initialize move stepsize ----------------------------------- */ /* initialize move stepsize values to default */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL; /* set move stepsize value for certain elements from pre-defined list */ for (i = 0; move_stepsize_list[i].element != EL_UNDEFINED; i++) { int e = move_stepsize_list[i].element; element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize; } /* ---------- initialize collect score ----------------------------------- */ /* initialize collect score values for custom elements from initial value */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (IS_CUSTOM_ELEMENT(i)) element_info[i].collect_score = element_info[i].collect_score_initial; /* ---------- initialize collect count ----------------------------------- */ /* initialize collect count values for non-custom elements */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].collect_count_initial = 0; /* add collect count values for all elements from pre-defined list */ for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++) element_info[collect_count_list[i].element].collect_count_initial = collect_count_list[i].count; /* ---------- initialize access direction -------------------------------- */ /* initialize access direction values to default (access from every side) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].access_direction = MV_ALL_DIRECTIONS; /* set access direction value for certain elements from pre-defined list */ for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++) element_info[access_direction_list[i].element].access_direction = access_direction_list[i].direction; /* ---------- initialize explosion content ------------------------------- */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_CUSTOM_ELEMENT(i)) continue; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { /* (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) */ element_info[i].content.e[x][y] = (i == EL_PLAYER_1 ? EL_EMERALD_YELLOW : i == EL_PLAYER_2 ? EL_EMERALD_RED : i == EL_PLAYER_3 ? EL_EMERALD : i == EL_PLAYER_4 ? EL_EMERALD_PURPLE : i == EL_MOLE ? EL_EMERALD_RED : i == EL_PENGUIN ? EL_EMERALD_PURPLE : i == EL_BUG ? (x == 1 && y == 1 ? EL_DIAMOND : EL_EMERALD) : i == EL_BD_BUTTERFLY ? EL_BD_DIAMOND : i == EL_SP_ELECTRON ? EL_SP_INFOTRON : i == EL_AMOEBA_TO_DIAMOND ? level.amoeba_content : i == EL_WALL_EMERALD ? EL_EMERALD : i == EL_WALL_DIAMOND ? EL_DIAMOND : i == EL_WALL_BD_DIAMOND ? EL_BD_DIAMOND : i == EL_WALL_EMERALD_YELLOW ? EL_EMERALD_YELLOW : i == EL_WALL_EMERALD_RED ? EL_EMERALD_RED : i == EL_WALL_EMERALD_PURPLE ? EL_EMERALD_PURPLE : i == EL_WALL_PEARL ? EL_PEARL : i == EL_WALL_CRYSTAL ? EL_CRYSTAL : EL_EMPTY); } } /* ---------- initialize recursion detection ------------------------------ */ recursion_loop_depth = 0; recursion_loop_detected = FALSE; recursion_loop_element = EL_UNDEFINED; /* ---------- initialize graphics engine ---------------------------------- */ game.scroll_delay_value = (game.forced_scroll_delay_value != -1 ? game.forced_scroll_delay_value : setup.scroll_delay ? setup.scroll_delay_value : 0); game.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY); /* ---------- initialize game engine snapshots ---------------------------- */ for (i = 0; i < MAX_PLAYERS; i++) game.snapshot.last_action[i] = 0; game.snapshot.changed_action = FALSE; game.snapshot.collected_item = FALSE; game.snapshot.mode = (strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_STEP) ? SNAPSHOT_MODE_EVERY_STEP : strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_MOVE) ? SNAPSHOT_MODE_EVERY_MOVE : strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_COLLECT) ? SNAPSHOT_MODE_EVERY_COLLECT : SNAPSHOT_MODE_OFF); game.snapshot.save_snapshot = FALSE; /* ---------- initialize level time for Supaplex engine ------------------- */ /* Supaplex levels with time limit currently unsupported -- should be added */ if (level.game_engine_type == GAME_ENGINE_TYPE_SP) level.time = 0; } int get_num_special_action(int element, int action_first, int action_last) { int num_special_action = 0; int i, j; for (i = action_first; i <= action_last; i++) { boolean found = FALSE; for (j = 0; j < NUM_DIRECTIONS; j++) if (el_act_dir2img(element, i, j) != el_act_dir2img(element, ACTION_DEFAULT, j)) found = TRUE; if (found) num_special_action++; else break; } return num_special_action; } /* ============================================================================= InitGame() ----------------------------------------------------------------------------- initialize and start new game ============================================================================= */ void InitGame() { int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); int fade_mask = REDRAW_FIELD; boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ int initial_move_dir = MV_DOWN; int i, j, x, y; // required here to update video display before fading (FIX THIS) DrawMaskedBorder(REDRAW_DOOR_2); if (!game.restart_level) CloseDoor(DOOR_CLOSE_1); SetGameStatus(GAME_MODE_PLAYING); if (level_editor_test_game) FadeSkipNextFadeIn(); else FadeSetEnterScreen(); if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; FadeLevelSoundsAndMusic(); ExpireSoundLoops(TRUE); if (!level_editor_test_game) FadeOut(fade_mask); /* needed if different viewport properties defined for playing */ ChangeViewportPropertiesIfNeeded(); ClearField(); DrawCompleteVideoDisplay(); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); InitGameEngine(); InitGameControlValues(); /* don't play tapes over network */ network_playing = (options.network && !tape.playing); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; player->index_nr = i; player->index_bit = (1 << i); player->element_nr = EL_PLAYER_1 + i; player->present = FALSE; player->active = FALSE; player->mapped = FALSE; player->killed = FALSE; player->reanimated = FALSE; player->action = 0; player->effective_action = 0; player->programmed_action = 0; player->mouse_action.lx = 0; player->mouse_action.ly = 0; player->mouse_action.button = 0; player->mouse_action.button_hint = 0; player->effective_mouse_action.lx = 0; player->effective_mouse_action.ly = 0; player->effective_mouse_action.button = 0; player->effective_mouse_action.button_hint = 0; player->score = 0; player->score_final = 0; player->health = MAX_HEALTH; player->health_final = MAX_HEALTH; player->gems_still_needed = level.gems_needed; player->sokobanfields_still_needed = 0; player->lights_still_needed = 0; player->friends_still_needed = 0; for (j = 0; j < MAX_NUM_KEYS; j++) player->key[j] = FALSE; player->num_white_keys = 0; player->dynabomb_count = 0; player->dynabomb_size = 1; player->dynabombs_left = 0; player->dynabomb_xl = FALSE; player->MovDir = initial_move_dir; player->MovPos = 0; player->GfxPos = 0; player->GfxDir = initial_move_dir; player->GfxAction = ACTION_DEFAULT; player->Frame = 0; player->StepFrame = 0; player->initial_element = player->element_nr; player->artwork_element = (level.use_artwork_element[i] ? level.artwork_element[i] : player->element_nr); player->use_murphy = FALSE; player->block_last_field = FALSE; /* initialized in InitPlayerField() */ player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */ player->gravity = level.initial_player_gravity[i]; player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr); player->actual_frame_counter = 0; player->step_counter = 0; player->last_move_dir = initial_move_dir; player->is_active = FALSE; player->is_waiting = FALSE; player->is_moving = FALSE; player->is_auto_moving = FALSE; player->is_digging = FALSE; player->is_snapping = FALSE; player->is_collecting = FALSE; player->is_pushing = FALSE; player->is_switching = FALSE; player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->is_bored = FALSE; player->is_sleeping = FALSE; player->was_waiting = TRUE; player->was_moving = FALSE; player->was_snapping = FALSE; player->was_dropping = FALSE; player->force_dropping = FALSE; player->frame_counter_bored = -1; player->frame_counter_sleeping = -1; player->anim_delay_counter = 0; player->post_delay_counter = 0; player->dir_waiting = initial_move_dir; player->action_waiting = ACTION_DEFAULT; player->last_action_waiting = ACTION_DEFAULT; player->special_action_bored = ACTION_DEFAULT; player->special_action_sleeping = ACTION_DEFAULT; player->switch_x = -1; player->switch_y = -1; player->drop_x = -1; player->drop_y = -1; player->show_envelope = 0; SetPlayerMoveSpeed(player, level.initial_player_stepsize[i], TRUE); player->push_delay = -1; /* initialized when pushing starts */ player->push_delay_value = game.initial_push_delay_value; player->drop_delay = 0; player->drop_pressed_delay = 0; player->last_jx = -1; player->last_jy = -1; player->jx = -1; player->jy = -1; player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; if (level.use_initial_inventory[i]) { for (j = 0; j < level.initial_inventory_size[i]; j++) { int element = level.initial_inventory_content[i][j]; int collect_count = element_info[element].collect_count_initial; int k; if (!IS_CUSTOM_ELEMENT(element)) collect_count = 1; if (collect_count == 0) player->inventory_infinite_element = element; else for (k = 0; k < collect_count; k++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; } } DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); player->LevelSolved = FALSE; player->GameOver = FALSE; player->LevelSolved_GameWon = FALSE; player->LevelSolved_GameEnd = FALSE; player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; player->LevelSolved_CountingTime = 0; player->LevelSolved_CountingScore = 0; player->LevelSolved_CountingHealth = 0; map_player_action[i] = i; } network_player_action_received = FALSE; #if defined(NETWORK_AVALIABLE) /* initial null action */ if (network_playing) SendToServer_MovePlayer(MV_NONE); #endif ZX = ZY = -1; ExitX = ExitY = -1; FrameCounter = 0; TimeFrames = 0; TimePlayed = 0; TimeLeft = level.time; TapeTime = 0; ScreenMovDir = MV_NONE; ScreenMovPos = 0; ScreenGfxPos = 0; ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */ AllPlayersGone = FALSE; game.no_time_limit = (level.time == 0); game.yamyam_content_nr = 0; game.robot_wheel_active = FALSE; game.magic_wall_active = FALSE; game.magic_wall_time_left = 0; game.light_time_left = 0; game.timegate_time_left = 0; game.switchgate_pos = 0; game.wind_direction = level.wind_direction_initial; game.lenses_time_left = 0; game.magnify_time_left = 0; game.ball_state = level.ball_state_initial; game.ball_content_nr = 0; game.envelope_active = FALSE; /* set focus to local player for network games, else to all players */ game.centered_player_nr = (network_playing ? local_player->index_nr : -1); game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; if (network_playing && tape.recording) { /* store client dependent player focus when recording network games */ tape.centered_player_nr_next = game.centered_player_nr_next; tape.set_centered_player = TRUE; } for (i = 0; i < NUM_BELTS; i++) { game.belt_dir[i] = MV_NONE; game.belt_dir_nr[i] = 3; /* not moving, next moving left */ } for (i = 0; i < MAX_NUM_AMOEBA; i++) AmoebaCnt[i] = AmoebaCnt2[i] = 0; #if DEBUG_INIT_PLAYER if (options.debug) { printf("Player status at level initialization:\n"); } #endif SCAN_PLAYFIELD(x, y) { Feld[x][y] = level.field[x][y]; MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; CustomValue[x][y] = 0; /* initialized in InitField() */ Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; AmoebaNr[x][y] = 0; WasJustMoving[x][y] = 0; WasJustFalling[x][y] = 0; CheckCollision[x][y] = 0; CheckImpact[x][y] = 0; Stop[x][y] = FALSE; Pushed[x][y] = FALSE; ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; ExplodePhase[x][y] = 0; ExplodeDelay[x][y] = 0; ExplodeField[x][y] = EX_TYPE_NONE; RunnerVisit[x][y] = 0; PlayerVisit[x][y] = 0; GfxFrame[x][y] = 0; GfxRandom[x][y] = INIT_GFX_RANDOM(); GfxElement[x][y] = EL_UNDEFINED; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MV_NONE; GfxRedraw[x][y] = GFX_REDRAW_NONE; } SCAN_PLAYFIELD(x, y) { if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y])) emulate_bd = FALSE; if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y])) emulate_sb = FALSE; if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y])) emulate_sp = FALSE; InitField(x, y, TRUE); ResetGfxAnimation(x, y); } InitBeltMovement(); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; /* set number of special actions for bored and sleeping animation */ player->num_special_action_bored = get_num_special_action(player->artwork_element, ACTION_BORING_1, ACTION_BORING_LAST); player->num_special_action_sleeping = get_num_special_action(player->artwork_element, ACTION_SLEEPING_1, ACTION_SLEEPING_LAST); } game.emulation = (emulate_bd ? EMU_BOULDERDASH : emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); /* initialize type of slippery elements */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { /* default: elements slip down either to the left or right randomly */ element_info[i].slippery_type = SLIPPERY_ANY_RANDOM; /* SP style elements prefer to slip down on the left side */ if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i)) element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; /* BD style elements prefer to slip down on the left side */ if (game.emulation == EMU_BOULDERDASH) element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; } } /* initialize explosion and ignition delay */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { int num_phase = 8; int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) && game.engine_version >= VERSION_IDENT(3,1,0,0)) || game.emulation == EMU_SUPAPLEX ? 3 : 2); int last_phase = (num_phase + 1) * delay; int half_phase = (num_phase / 2) * delay; element_info[i].explosion_delay = last_phase - 1; element_info[i].ignition_delay = half_phase; if (i == EL_BLACK_ORB) element_info[i].ignition_delay = 1; } } /* correct non-moving belts to start moving left */ for (i = 0; i < NUM_BELTS; i++) if (game.belt_dir[i] == MV_NONE) game.belt_dir_nr[i] = 3; /* not moving, next moving left */ #if USE_NEW_PLAYER_ASSIGNMENTS /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ /* choose default local player */ local_player = &stored_player[0]; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = FALSE; local_player->connected = TRUE; /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ if (tape.playing) { for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = tape.player_participates[i]; } else if (game.team_mode && !options.network) { /* try to guess locally connected team mode players (needed for correct assignment of player figures from level to locally playing players) */ for (i = 0; i < MAX_PLAYERS; i++) if (setup.input[i].use_joystick || setup.input[i].key.left != KSYM_UNDEFINED) stored_player[i].connected = TRUE; } #if DEBUG_INIT_PLAYER if (options.debug) { printf("Player status after level initialization:\n"); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; printf("- player %d: present == %d, connected == %d, active == %d", i + 1, player->present, player->connected, player->active); if (local_player == player) printf(" (local player)"); printf("\n"); } } #endif #if DEBUG_INIT_PLAYER if (options.debug) printf("Reassigning players ...\n"); #endif /* check if any connected player was not found in playfield */ for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->connected && !player->present) { struct PlayerInfo *field_player = NULL; #if DEBUG_INIT_PLAYER if (options.debug) printf("- looking for field player for player %d ...\n", i + 1); #endif /* assign first free player found that is present in the playfield */ /* first try: look for unmapped playfield player that is not connected */ for (j = 0; j < MAX_PLAYERS; j++) if (field_player == NULL && stored_player[j].present && !stored_player[j].mapped && !stored_player[j].connected) field_player = &stored_player[j]; /* second try: look for *any* unmapped playfield player */ for (j = 0; j < MAX_PLAYERS; j++) if (field_player == NULL && stored_player[j].present && !stored_player[j].mapped) field_player = &stored_player[j]; if (field_player != NULL) { int jx = field_player->jx, jy = field_player->jy; #if DEBUG_INIT_PLAYER if (options.debug) printf("- found player %d\n", field_player->index_nr + 1); #endif player->present = FALSE; player->active = FALSE; field_player->present = TRUE; field_player->active = TRUE; /* player->initial_element = field_player->initial_element; player->artwork_element = field_player->artwork_element; player->block_last_field = field_player->block_last_field; player->block_delay_adjustment = field_player->block_delay_adjustment; */ StorePlayer[jx][jy] = field_player->element_nr; field_player->jx = field_player->last_jx = jx; field_player->jy = field_player->last_jy = jy; if (local_player == player) local_player = field_player; map_player_action[field_player->index_nr] = i; field_player->mapped = TRUE; #if DEBUG_INIT_PLAYER if (options.debug) printf("- map_player_action[%d] == %d\n", field_player->index_nr + 1, i + 1); #endif } } if (player->connected && player->present) player->mapped = TRUE; } #if DEBUG_INIT_PLAYER if (options.debug) { printf("Player status after player assignment (first stage):\n"); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; printf("- player %d: present == %d, connected == %d, active == %d", i + 1, player->present, player->connected, player->active); if (local_player == player) printf(" (local player)"); printf("\n"); } } #endif #else /* check if any connected player was not found in playfield */ for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->connected && !player->present) { for (j = 0; j < MAX_PLAYERS; j++) { struct PlayerInfo *field_player = &stored_player[j]; int jx = field_player->jx, jy = field_player->jy; /* assign first free player found that is present in the playfield */ if (field_player->present && !field_player->connected) { player->present = TRUE; player->active = TRUE; field_player->present = FALSE; field_player->active = FALSE; player->initial_element = field_player->initial_element; player->artwork_element = field_player->artwork_element; player->block_last_field = field_player->block_last_field; player->block_delay_adjustment = field_player->block_delay_adjustment; StorePlayer[jx][jy] = player->element_nr; player->jx = player->last_jx = jx; player->jy = player->last_jy = jy; break; } } } } #endif #if 0 printf("::: local_player->present == %d\n", local_player->present); #endif if (tape.playing) { /* when playing a tape, eliminate all players who do not participate */ #if USE_NEW_PLAYER_ASSIGNMENTS if (!game.team_mode) { for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active && !tape.player_participates[map_player_action[i]]) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; #if DEBUG_INIT_PLAYER if (options.debug) printf("Removing player %d at (%d, %d)\n", i + 1, jx, jy); #endif player->active = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } } #else for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active && !tape.player_participates[i]) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; player->active = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } #endif } else if (!options.network && !game.team_mode) /* && !tape.playing */ { /* when in single player mode, eliminate all but the first active player */ for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active) { for (j = i + 1; j < MAX_PLAYERS; j++) { if (stored_player[j].active) { struct PlayerInfo *player = &stored_player[j]; int jx = player->jx, jy = player->jy; player->active = FALSE; player->present = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } } } } /* when recording the game, store which players take part in the game */ if (tape.recording) { #if USE_NEW_PLAYER_ASSIGNMENTS for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].connected) tape.player_participates[i] = TRUE; #else for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) tape.player_participates[i] = TRUE; #endif } #if DEBUG_INIT_PLAYER if (options.debug) { printf("Player status after player assignment (final stage):\n"); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; printf("- player %d: present == %d, connected == %d, active == %d", i + 1, player->present, player->connected, player->active); if (local_player == player) printf(" (local player)"); printf("\n"); } } #endif if (BorderElement == EL_EMPTY) { SBX_Left = 0; SBX_Right = lev_fieldx - SCR_FIELDX; SBY_Upper = 0; SBY_Lower = lev_fieldy - SCR_FIELDY; } else { SBX_Left = -1; SBX_Right = lev_fieldx - SCR_FIELDX + 1; SBY_Upper = -1; SBY_Lower = lev_fieldy - SCR_FIELDY + 1; } if (full_lev_fieldx <= SCR_FIELDX) SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; if (full_lev_fieldy <= SCR_FIELDY) SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; if (EVEN(SCR_FIELDX) && full_lev_fieldx > SCR_FIELDX) SBX_Left--; if (EVEN(SCR_FIELDY) && full_lev_fieldy > SCR_FIELDY) SBY_Upper--; /* if local player not found, look for custom element that might create the player (make some assumptions about the right custom element) */ if (!local_player->present) { int start_x = 0, start_y = 0; int found_rating = 0; int found_element = EL_UNDEFINED; int player_nr = local_player->index_nr; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; int content; int xx, yy; boolean is_player; if (level.use_start_element[player_nr] && level.start_element[player_nr] == element && found_rating < 4) { start_x = x; start_y = y; found_rating = 4; found_element = element; } if (!IS_CUSTOM_ELEMENT(element)) continue; if (CAN_CHANGE(element)) { for (i = 0; i < element_info[element].num_change_pages; i++) { /* check for player created from custom element as single target */ content = element_info[element].change_page[i].target_element; is_player = ELEM_IS_PLAYER(content); if (is_player && (found_rating < 3 || (found_rating == 3 && element < found_element))) { start_x = x; start_y = y; found_rating = 3; found_element = element; } } } for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++) { /* check for player created from custom element as explosion content */ content = element_info[element].content.e[xx][yy]; is_player = ELEM_IS_PLAYER(content); if (is_player && (found_rating < 2 || (found_rating == 2 && element < found_element))) { start_x = x + xx - 1; start_y = y + yy - 1; found_rating = 2; found_element = element; } if (!CAN_CHANGE(element)) continue; for (i = 0; i < element_info[element].num_change_pages; i++) { /* check for player created from custom element as extended target */ content = element_info[element].change_page[i].target_content.e[xx][yy]; is_player = ELEM_IS_PLAYER(content); if (is_player && (found_rating < 1 || (found_rating == 1 && element < found_element))) { start_x = x + xx - 1; start_y = y + yy - 1; found_rating = 1; found_element = element; } } } } scroll_x = SCROLL_POSITION_X(start_x); scroll_y = SCROLL_POSITION_Y(start_y); } else { scroll_x = SCROLL_POSITION_X(local_player->jx); scroll_y = SCROLL_POSITION_Y(local_player->jy); } /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { InitGameEngine_EM(); } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { InitGameEngine_SP(); } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { InitGameEngine_MM(); } else { DrawLevel(REDRAW_FIELD); DrawAllPlayers(); /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) CloseAllOpenTimegates(); } /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap(backbuffer); /* !!! FIX THIS (END) !!! */ DrawMaskedBorder(fade_mask); FadeIn(fade_mask); #if 1 // full screen redraw is required at this point in the following cases: // - special editor door undrawn when game was started from level editor // - drawing area (playfield) was changed and has to be removed completely redraw_mask = REDRAW_ALL; BackToFront(); #endif if (!game.restart_level) { /* copy default game door content to main double buffer */ /* !!! CHECK AGAIN !!! */ SetPanelBackground(); // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL); DrawBackground(DX, DY, DXSIZE, DYSIZE); } SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); UpdateAndDisplayGameControlValues(); if (!game.restart_level) { UnmapGameButtons(); UnmapTapeButtons(); FreeGameButtons(); CreateGameButtons(); MapGameButtons(); MapTapeButtons(); /* copy actual game door content to door double buffer for OpenDoor() */ BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); OpenDoor(DOOR_OPEN_ALL); PlaySound(SND_GAME_STARTING); if (setup.sound_music) PlayLevelMusic(); KeyboardAutoRepeatOffUnlessAutoplay(); #if DEBUG_INIT_PLAYER if (options.debug) { printf("Player status (final):\n"); for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; printf("- player %d: present == %d, connected == %d, active == %d", i + 1, player->present, player->connected, player->active); if (local_player == player) printf(" (local player)"); printf("\n"); } } #endif } UnmapAllGadgets(); MapGameButtons(); MapTapeButtons(); if (!game.restart_level && !tape.playing) { LevelStats_incPlayed(level_nr); SaveLevelSetup_SeriesInfo(); } game.restart_level = FALSE; game.restart_game_message = NULL; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) InitGameActions_MM(); SaveEngineSnapshotToListInitial(); } void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y, int actual_player_x, int actual_player_y) { /* this is used for non-R'n'D game engines to update certain engine values */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { actual_player_x = correctLevelPosX_EM(actual_player_x); actual_player_y = correctLevelPosY_EM(actual_player_y); } /* needed to determine if sounds are played within the visible screen area */ scroll_x = actual_scroll_x; scroll_y = actual_scroll_y; /* needed to get player position for "follow finger" playing input method */ local_player->jx = actual_player_x; local_player->jy = actual_player_y; } 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 } }; static int direction[3][4] = { { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN }, { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }, { MV_LEFT, MV_RIGHT, MV_UP, MV_DOWN } }; switch (element) { case EL_BUG_RIGHT: case EL_BUG_UP: case EL_BUG_LEFT: case EL_BUG_DOWN: Feld[x][y] = EL_BUG; MovDir[x][y] = direction[0][element - EL_BUG_RIGHT]; break; case EL_SPACESHIP_RIGHT: case EL_SPACESHIP_UP: case EL_SPACESHIP_LEFT: case EL_SPACESHIP_DOWN: Feld[x][y] = EL_SPACESHIP; MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT]; break; case EL_BD_BUTTERFLY_RIGHT: case EL_BD_BUTTERFLY_UP: case EL_BD_BUTTERFLY_LEFT: case EL_BD_BUTTERFLY_DOWN: Feld[x][y] = EL_BD_BUTTERFLY; MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT]; break; case EL_BD_FIREFLY_RIGHT: case EL_BD_FIREFLY_UP: case EL_BD_FIREFLY_LEFT: case EL_BD_FIREFLY_DOWN: Feld[x][y] = EL_BD_FIREFLY; MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT]; break; case EL_PACMAN_RIGHT: case EL_PACMAN_UP: case EL_PACMAN_LEFT: case EL_PACMAN_DOWN: Feld[x][y] = EL_PACMAN; MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT]; break; case EL_YAMYAM_LEFT: case EL_YAMYAM_RIGHT: case EL_YAMYAM_UP: case EL_YAMYAM_DOWN: Feld[x][y] = EL_YAMYAM; MovDir[x][y] = direction[2][element - EL_YAMYAM_LEFT]; break; case EL_SP_SNIKSNAK: MovDir[x][y] = MV_UP; break; case EL_SP_ELECTRON: MovDir[x][y] = MV_LEFT; break; case EL_MOLE_LEFT: case EL_MOLE_RIGHT: case EL_MOLE_UP: case EL_MOLE_DOWN: Feld[x][y] = EL_MOLE; MovDir[x][y] = direction[2][element - EL_MOLE_LEFT]; break; default: if (IS_CUSTOM_ELEMENT(element)) { struct ElementInfo *ei = &element_info[element]; int move_direction_initial = ei->move_direction_initial; int move_pattern = ei->move_pattern; if (move_direction_initial == MV_START_PREVIOUS) { if (MovDir[x][y] != MV_NONE) return; move_direction_initial = MV_START_AUTOMATIC; } if (move_direction_initial == MV_START_RANDOM) MovDir[x][y] = 1 << RND(4); else if (move_direction_initial & MV_ANY_DIRECTION) MovDir[x][y] = move_direction_initial; else if (move_pattern == MV_ALL_DIRECTIONS || move_pattern == MV_TURNING_LEFT || move_pattern == MV_TURNING_RIGHT || move_pattern == MV_TURNING_LEFT_RIGHT || move_pattern == MV_TURNING_RIGHT_LEFT || move_pattern == MV_TURNING_RANDOM) MovDir[x][y] = 1 << RND(4); else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); else if (move_pattern & MV_ANY_DIRECTION) MovDir[x][y] = element_info[element].move_pattern; else if (move_pattern == MV_ALONG_LEFT_SIDE || move_pattern == MV_ALONG_RIGHT_SIDE) { /* use random direction as default start direction */ if (game.engine_version >= VERSION_IDENT(3,1,0,0)) MovDir[x][y] = 1 << RND(4); for (i = 0; i < NUM_DIRECTIONS; i++) { int x1 = x + xy[i][0]; int y1 = y + xy[i][1]; if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1)) { if (move_pattern == MV_ALONG_RIGHT_SIDE) MovDir[x][y] = direction[0][i]; else MovDir[x][y] = direction[1][i]; break; } } } } else { MovDir[x][y] = 1 << RND(4); if (element != EL_BUG && element != EL_SPACESHIP && element != EL_BD_BUTTERFLY && element != EL_BD_FIREFLY) break; for (i = 0; i < NUM_DIRECTIONS; i++) { int x1 = x + xy[i][0]; int y1 = y + xy[i][1]; if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1)) { if (element == EL_BUG || element == EL_BD_BUTTERFLY) { MovDir[x][y] = direction[0][i]; break; } else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY || element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) { MovDir[x][y] = direction[1][i]; break; } } } } break; } GfxDir[x][y] = MovDir[x][y]; } void InitAmoebaNr(int x, int y) { int i; int group_nr = AmoebeNachbarNr(x, y); if (group_nr == 0) { for (i = 1; i < MAX_NUM_AMOEBA; i++) { if (AmoebaCnt[i] == 0) { group_nr = i; break; } } } AmoebaNr[x][y] = group_nr; AmoebaCnt[group_nr]++; AmoebaCnt2[group_nr]++; } static void PlayerWins(struct PlayerInfo *player) { player->LevelSolved = TRUE; player->GameOver = TRUE; player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score : player->score); player->health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? MM_HEALTH(game_mm.laser_overload_value) : player->health); player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : TimeLeft); player->LevelSolved_CountingScore = player->score_final; player->LevelSolved_CountingHealth = player->health_final; } void GameWon() { static int time_count_steps; static int time, time_final; static int score, score_final; static int health, health_final; static int game_over_delay_1 = 0; static int game_over_delay_2 = 0; static int game_over_delay_3 = 0; int game_over_delay_value_1 = 50; int game_over_delay_value_2 = 25; int game_over_delay_value_3 = 50; if (!local_player->LevelSolved_GameWon) { int i; /* do not start end game actions before the player stops moving (to exit) */ if (local_player->MovPos) return; local_player->LevelSolved_GameWon = TRUE; local_player->LevelSolved_SaveTape = tape.recording; local_player->LevelSolved_SaveScore = !tape.playing; if (!tape.playing) { LevelStats_incSolved(level_nr); SaveLevelSetup_SeriesInfo(); } if (tape.auto_play) /* tape might already be stopped here */ tape.auto_play_level_solved = TRUE; TapeStop(); game_over_delay_1 = 0; game_over_delay_2 = 0; game_over_delay_3 = game_over_delay_value_3; time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft); score = score_final = local_player->score_final; health = health_final = local_player->health_final; if (level.score[SC_TIME_BONUS] > 0) { if (TimeLeft > 0) { time_final = 0; score_final += TimeLeft * level.score[SC_TIME_BONUS]; } else if (game.no_time_limit && TimePlayed < 999) { time_final = 999; score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS]; } time_count_steps = MAX(1, ABS(time_final - time) / 100); game_over_delay_1 = game_over_delay_value_1; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { health_final = 0; score_final += health * level.score[SC_TIME_BONUS]; game_over_delay_2 = game_over_delay_value_2; } local_player->score_final = score_final; local_player->health_final = health_final; } if (level_editor_test_game) { time = time_final; score = score_final; local_player->LevelSolved_CountingTime = time; local_player->LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { if (ExitX >= 0 && ExitY >= 0) /* local player has left the level */ { /* close exit door after last player */ if ((AllPlayersGone && (Feld[ExitX][ExitY] == EL_EXIT_OPEN || Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN || Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) || Feld[ExitX][ExitY] == EL_EM_EXIT_OPEN || Feld[ExitX][ExitY] == EL_EM_STEEL_EXIT_OPEN) { int element = Feld[ExitX][ExitY]; Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING : element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING: EL_EM_STEEL_EXIT_CLOSING); PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); } /* player disappears */ DrawLevelField(ExitX, ExitY); } for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->present) { RemovePlayer(player); /* player disappears */ DrawLevelField(player->jx, player->jy); } } } PlaySound(SND_GAME_WINNING); } if (game_over_delay_1 > 0) { game_over_delay_1--; return; } if (time != time_final) { int time_to_go = ABS(time_final - time); int time_count_dir = (time < time_final ? +1 : -1); if (time_to_go < time_count_steps) time_count_steps = 1; time += time_count_steps * time_count_dir; score += time_count_steps * level.score[SC_TIME_BONUS]; local_player->LevelSolved_CountingTime = time; local_player->LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); if (time == time_final) StopSound(SND_GAME_LEVELTIME_BONUS); else if (setup.sound_loops) PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); else PlaySound(SND_GAME_LEVELTIME_BONUS); return; } if (game_over_delay_2 > 0) { game_over_delay_2--; return; } if (health != health_final) { int health_count_dir = (health < health_final ? +1 : -1); health += health_count_dir; score += level.score[SC_TIME_BONUS]; local_player->LevelSolved_CountingHealth = health; local_player->LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_HEALTH].value = health; game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); if (health == health_final) StopSound(SND_GAME_LEVELTIME_BONUS); else if (setup.sound_loops) PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); else PlaySound(SND_GAME_LEVELTIME_BONUS); return; } local_player->LevelSolved_PanelOff = TRUE; if (game_over_delay_3 > 0) { game_over_delay_3--; return; } GameEnd(); } void GameEnd() { int hi_pos; boolean raise_level = FALSE; local_player->LevelSolved_GameEnd = TRUE; if (local_player->LevelSolved_SaveTape) { /* make sure that request dialog to save tape does not open door again */ if (!global.use_envelope_request) CloseDoor(DOOR_CLOSE_1); SaveTapeChecked_LevelSolved(tape.level_nr); /* ask to save tape */ } /* if no tape is to be saved, close both doors simultaneously */ CloseDoor(DOOR_CLOSE_ALL); if (level_editor_test_game) { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); return; } if (!local_player->LevelSolved_SaveScore) { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); return; } if (level_nr == leveldir_current->handicap_level) { leveldir_current->handicap_level++; SaveLevelSetup_SeriesInfo(); } if (setup.increment_levels && level_nr < leveldir_current->last_level) raise_level = TRUE; /* advance to next level */ if ((hi_pos = NewHiScore()) >= 0) { SetGameStatus(GAME_MODE_SCORES); DrawHallOfFame(hi_pos); if (raise_level) { level_nr++; TapeErase(); } } else { SetGameStatus(GAME_MODE_MAIN); if (raise_level) { level_nr++; TapeErase(); } DrawMainMenu(); } } int NewHiScore() { int k, l; int position = -1; boolean one_score_entry_per_name = !program.many_scores_per_name; LoadScore(level_nr); if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) || local_player->score_final < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; for (k = 0; k < MAX_SCORE_ENTRIES; k++) { if (local_player->score_final > highscore[k].Score) { /* player has made it to the hall of fame */ if (k < MAX_SCORE_ENTRIES - 1) { int m = MAX_SCORE_ENTRIES - 1; if (one_score_entry_per_name) { for (l = k; l < MAX_SCORE_ENTRIES; l++) if (strEqual(setup.player_name, highscore[l].Name)) m = l; if (m == k) /* player's new highscore overwrites his old one */ goto put_into_list; } for (l = m; l > k; l--) { strcpy(highscore[l].Name, highscore[l - 1].Name); highscore[l].Score = highscore[l - 1].Score; } } put_into_list: strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN); highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0'; highscore[k].Score = local_player->score_final; position = k; break; } else if (one_score_entry_per_name && !strncmp(setup.player_name, highscore[k].Name, MAX_PLAYER_NAME_LEN)) break; /* player already there with a higher score */ } if (position >= 0) SaveScore(level_nr); return position; } inline static int getElementMoveStepsizeExt(int x, int y, int direction) { int element = Feld[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 horiz_move = (dx != 0); int sign = (horiz_move ? dx : dy); int step = sign * element_info[element].move_stepsize; /* special values for move stepsize for spring and things on conveyor belt */ if (horiz_move) { if (CAN_FALL(element) && y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1])) step = sign * MOVE_STEPSIZE_NORMAL / 2; else if (element == EL_SPRING) step = sign * MOVE_STEPSIZE_NORMAL * 2; } return step; } inline static int getElementMoveStepsize(int x, int y) { return getElementMoveStepsizeExt(x, y, MovDir[x][y]); } void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir) { if (player->GfxAction != action || player->GfxDir != dir) { player->GfxAction = action; player->GfxDir = dir; player->Frame = 0; player->StepFrame = 0; } } static void ResetGfxFrame(int x, int y) { // profiling showed that "autotest" spends 10~20% of its time in this function if (DrawingDeactivatedField()) return; int element = Feld[x][y]; int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) GfxFrame[x][y] = element_info[element].collect_score; else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) GfxFrame[x][y] = ChangeDelay[x][y]; } static void ResetGfxAnimation(int x, int y) { GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MovDir[x][y]; GfxFrame[x][y] = 0; ResetGfxFrame(x, y); } static void ResetRandomAnimationValue(int x, int y) { GfxRandom[x][y] = INIT_GFX_RANDOM(); } void InitMovingField(int x, int y, int direction) { int element = Feld[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 newx = x + dx; int newy = y + dy; boolean is_moving_before, is_moving_after; /* check if element was/is moving or being moved before/after mode change */ is_moving_before = (WasJustMoving[x][y] != 0); is_moving_after = (getElementMoveStepsizeExt(x, y, direction) != 0); /* reset animation only for moving elements which change direction of moving or which just started or stopped moving (else CEs with property "can move" / "not moving" are reset each frame) */ if (is_moving_before != is_moving_after || direction != MovDir[x][y]) ResetGfxAnimation(x, y); MovDir[x][y] = direction; GfxDir[x][y] = direction; GfxAction[x][y] = (!is_moving_after ? ACTION_WAITING : direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); /* this is needed for CEs with property "can move" / "not moving" */ if (is_moving_after) { if (Feld[newx][newy] == EL_EMPTY) Feld[newx][newy] = EL_BLOCKED; MovDir[newx][newy] = MovDir[x][y]; CustomValue[newx][newy] = CustomValue[x][y]; GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; GfxAction[newx][newy] = GfxAction[x][y]; GfxDir[newx][newy] = GfxDir[x][y]; } } 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); *goes_to_x = newx; *goes_to_y = newy; } 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) oldx++; else if (direction == MV_RIGHT) oldx--; else if (direction == MV_UP) oldy++; else if (direction == MV_DOWN) oldy--; *comes_from_x = oldx; *comes_from_y = oldy; } int MovingOrBlocked2Element(int x, int y) { int element = Feld[x][y]; if (element == EL_BLOCKED) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); return Feld[oldx][oldy]; } else return element; } static int MovingOrBlocked2ElementIfNotLeaving(int x, int y) { /* like MovingOrBlocked2Element(), but if element is moving and (x,y) is the field the moving element is just leaving, return EL_BLOCKED instead of the element value */ int element = Feld[x][y]; if (IS_MOVING(x, y)) { if (element == EL_BLOCKED) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); return Feld[oldx][oldy]; } else return EL_BLOCKED; } else return element; } static void RemoveField(int x, int y) { Feld[x][y] = EL_EMPTY; MovPos[x][y] = 0; MovDir[x][y] = 0; MovDelay[x][y] = 0; CustomValue[x][y] = 0; AmoebaNr[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; Pushed[x][y] = FALSE; GfxElement[x][y] = EL_UNDEFINED; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MV_NONE; } void RemoveMovingField(int x, int y) { int oldx = x, oldy = y, newx = x, newy = y; int element = Feld[x][y]; int next_element = EL_UNDEFINED; if (element != EL_BLOCKED && !IS_MOVING(x, y)) return; if (IS_MOVING(x, y)) { Moving2Blocked(x, y, &newx, &newy); if (Feld[newx][newy] != EL_BLOCKED) { /* element is moving, but target field is not free (blocked), but already occupied by something different (example: acid pool); in this case, only remove the moving field, but not the target */ RemoveField(oldx, oldy); Store[oldx][oldy] = Store2[oldx][oldy] = 0; TEST_DrawLevelField(oldx, oldy); return; } } else if (element == EL_BLOCKED) { Blocked2Moving(x, y, &oldx, &oldy); if (!IS_MOVING(oldx, oldy)) return; } if (element == EL_BLOCKED && (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING || Feld[oldx][oldy] == EL_QUICKSAND_FAST_EMPTYING || Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_DC_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_AMOEBA_DROPPING)) next_element = get_next_element(Feld[oldx][oldy]); RemoveField(oldx, oldy); RemoveField(newx, newy); Store[oldx][oldy] = Store2[oldx][oldy] = 0; if (next_element != EL_UNDEFINED) Feld[oldx][oldy] = next_element; TEST_DrawLevelField(oldx, oldy); TEST_DrawLevelField(newx, newy); } void DrawDynamite(int x, int y) { int sx = SCREENX(x), sy = SCREENY(y); int graphic = el2img(Feld[x][y]); int frame; if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y)) return; if (IS_WALKABLE_INSIDE(Back[x][y])) return; if (Back[x][y]) DrawGraphic(sx, sy, el2img(Back[x][y]), 0); else if (Store[x][y]) DrawGraphic(sx, sy, el2img(Store[x][y]), 0); frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); if (Back[x][y] || Store[x][y]) DrawGraphicThruMask(sx, sy, graphic, frame); else DrawGraphic(sx, sy, graphic, frame); } void CheckDynamite(int x, int y) { if (MovDelay[x][y] != 0) /* dynamite is still waiting to explode */ { MovDelay[x][y]--; if (MovDelay[x][y] != 0) { DrawDynamite(x, y); PlayLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); return; } } StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); Bang(x, y); } static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2) { boolean num_checked_players = 0; int i; for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active) { int sx = stored_player[i].jx; int sy = stored_player[i].jy; if (num_checked_players == 0) { *sx1 = *sx2 = sx; *sy1 = *sy2 = sy; } else { *sx1 = MIN(*sx1, sx); *sy1 = MIN(*sy1, sy); *sx2 = MAX(*sx2, sx); *sy2 = MAX(*sy2, sy); } num_checked_players++; } } } static boolean checkIfAllPlayersFitToScreen_RND() { int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); return (sx2 - sx1 < SCR_FIELDX && sy2 - sy1 < SCR_FIELDY); } static void setScreenCenteredToAllPlayers(int *sx, int *sy) { int sx1 = scroll_x, sy1 = scroll_y, sx2 = scroll_x, sy2 = scroll_y; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); *sx = (sx1 + sx2) / 2; *sy = (sy1 + sy2) / 2; } void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, boolean center_screen, boolean quick_relocation) { unsigned int frame_delay_value_old = GetVideoFrameDelay(); boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int wait_delay_value = (no_delay ? 0 : frame_delay_value); int new_scroll_x, new_scroll_y; if (level.lazy_relocation && IN_VIS_FIELD(SCREENX(x), SCREENY(y))) { /* case 1: quick relocation inside visible screen (without scrolling) */ RedrawPlayfield(); return; } if (!level.shifted_relocation || center_screen) { /* relocation _with_ centering of screen */ new_scroll_x = SCROLL_POSITION_X(x); new_scroll_y = SCROLL_POSITION_Y(y); } else { /* relocation _without_ centering of screen */ int center_scroll_x = SCROLL_POSITION_X(old_x); int center_scroll_y = SCROLL_POSITION_Y(old_y); int offset_x = x + (scroll_x - center_scroll_x); int offset_y = y + (scroll_y - center_scroll_y); /* for new screen position, apply previous offset to center position */ new_scroll_x = SCROLL_POSITION_X(offset_x); new_scroll_y = SCROLL_POSITION_Y(offset_y); } if (quick_relocation) { /* case 2: quick relocation (redraw without visible scrolling) */ scroll_x = new_scroll_x; scroll_y = new_scroll_y; RedrawPlayfield(); return; } /* case 3: visible relocation (with scrolling to new position) */ ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ SetVideoFrameDelay(wait_delay_value); while (scroll_x != new_scroll_x || scroll_y != new_scroll_y) { int dx = 0, dy = 0; int fx = FX, fy = FY; dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0); dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0); if (dx == 0 && dy == 0) /* no scrolling needed at all */ break; scroll_x -= dx; scroll_y -= dy; fx += dx * TILEX / 2; fy += dy * TILEY / 2; ScrollLevel(dx, dy); DrawAllPlayers(); /* scroll in two steps of half tile size to make things smoother */ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY); /* scroll second step to align at full tile size */ BlitScreenToBitmap(window); } DrawAllPlayers(); BackToFront(); SetVideoFrameDelay(frame_delay_value_old); } void RelocatePlayer(int jx, int jy, int el_player_raw) { int el_player = GET_PLAYER_ELEMENT(el_player_raw); int player_nr = GET_PLAYER_NR(el_player); struct PlayerInfo *player = &stored_player[player_nr]; boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int wait_delay_value = (no_delay ? 0 : frame_delay_value); int old_jx = player->jx; int old_jy = player->jy; int old_element = Feld[old_jx][old_jy]; int element = Feld[jx][jy]; boolean player_relocated = (old_jx != jx || old_jy != jy); int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0); int move_dir_vert = (jy < old_jy ? MV_UP : jy > old_jy ? MV_DOWN : 0); int enter_side_horiz = MV_DIR_OPPOSITE(move_dir_horiz); int enter_side_vert = MV_DIR_OPPOSITE(move_dir_vert); int leave_side_horiz = move_dir_horiz; int leave_side_vert = move_dir_vert; int enter_side = enter_side_horiz | enter_side_vert; int leave_side = leave_side_horiz | leave_side_vert; if (player->GameOver) /* do not reanimate dead player */ return; if (!player_relocated) /* no need to relocate the player */ return; if (IS_PLAYER(jx, jy)) /* player already placed at new position */ { RemoveField(jx, jy); /* temporarily remove newly placed player */ DrawLevelField(jx, jy); } if (player->present) { while (player->MovPos) { ScrollPlayer(player, SCROLL_GO_ON); ScrollScreen(NULL, SCROLL_GO_ON); AdvanceFrameAndPlayerCounters(player->index_nr); DrawPlayer(player); BackToFront_WithFrameDelay(wait_delay_value); } DrawPlayer(player); /* needed here only to cleanup last field */ DrawLevelField(player->jx, player->jy); /* remove player graphic */ player->is_moving = FALSE; } if (IS_CUSTOM_ELEMENT(old_element)) CheckElementChangeByPlayer(old_jx, old_jy, old_element, CE_LEFT_BY_PLAYER, player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, CE_PLAYER_LEAVES_X, player->index_bit, leave_side); Feld[jx][jy] = el_player; InitPlayerField(jx, jy, el_player, TRUE); /* "InitPlayerField()" above sets Feld[jx][jy] to EL_EMPTY, but it may be possible that the relocation target field did not contain a player element, but a walkable element, to which the new player was relocated -- in this case, restore that (already initialized!) element on the player field */ if (!ELEM_IS_PLAYER(element)) /* player may be set on walkable element */ { Feld[jx][jy] = element; /* restore previously existing element */ } /* only visually relocate centered player */ DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, player->MovDir, FALSE, level.instant_relocation); TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); if (IS_CUSTOM_ELEMENT(element)) CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER, player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); if (player->is_switching) { /* ensure that relocation while still switching an element does not cause a new element to be treated as also switched directly after relocation (this is important for teleporter switches that teleport the player to a place where another teleporter switch is in the same direction, which would then incorrectly be treated as immediately switched before the direction key that caused the switch was released) */ player->switch_x += jx - old_jx; player->switch_y += jy - old_jy; } } void Explode(int ex, int ey, int phase, int mode) { int x, y; int last_phase; int border_element; /* !!! eliminate this variable !!! */ int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); if (game.explosions_delayed) { ExplodeField[ex][ey] = mode; return; } if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */ { int center_element = Feld[ex][ey]; int artwork_element, explosion_element; /* set these values later */ /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) Back[ex][ey] = 0; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) { /* put moving element to center field (and let it explode there) */ center_element = MovingOrBlocked2Element(ex, ey); RemoveMovingField(ex, ey); Feld[ex][ey] = center_element; } /* now "center_element" is finally determined -- set related values now */ artwork_element = center_element; /* for custom player artwork */ explosion_element = center_element; /* for custom player artwork */ if (IS_PLAYER(ex, ey)) { int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]); artwork_element = stored_player[player_nr].artwork_element; if (level.use_explosion_element[player_nr]) { explosion_element = level.explosion_element[player_nr]; artwork_element = explosion_element; } } if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER || mode == EX_TYPE_CROSS) PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); last_phase = element_info[explosion_element].explosion_delay + 1; for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++) { int xx = x - ex + 1; int yy = y - ey + 1; int element; if (!IN_LEV_FIELD(x, y) || (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) || (mode == EX_TYPE_CROSS && (x != ex && y != ey))) continue; element = Feld[x][y]; if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) { element = MovingOrBlocked2Element(x, y); if (!IS_EXPLOSION_PROOF(element)) RemoveMovingField(x, y); } /* indestructible elements can only explode in center (but not flames) */ if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) || element == EL_FLAMES) continue; /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy behaviour, for example when touching a yamyam that explodes to rocks with active deadly shield, a rock is created under the player !!! */ /* (case 1 (surely buggy): >= 3.1.0, case 2 (maybe buggy): <= 3.0.8) */ #if 0 if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) && (game.engine_version < VERSION_IDENT(3,1,0,0) || (x == ex && y == ey && mode != EX_TYPE_BORDER))) #else if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y))) #endif { if (IS_ACTIVE_BOMB(element)) { /* re-activate things under the bomb like gate or penguin */ Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY); Back[x][y] = 0; } continue; } /* save walkable background elements while explosion on same tile */ if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) Back[x][y] = element; /* ignite explodable elements reached by other explosion */ if (element == EL_EXPLOSION) element = Store2[x][y]; if (AmoebaNr[x][y] && (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA || element == EL_AMOEBA_GROWING)) { AmoebaCnt[AmoebaNr[x][y]]--; AmoebaCnt2[AmoebaNr[x][y]]--; } RemoveField(x, y); if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey)) { int player_nr = StorePlayer[ex][ey] - EL_PLAYER_1; Store[x][y] = EL_PLAYER_IS_EXPLODING_1 + player_nr; if (PLAYERINFO(ex, ey)->use_murphy) Store[x][y] = EL_EMPTY; } /* !!! check this case -- currently needed for rnd_rado_negundo_v, !!! levels 015 018 019 020 021 022 023 026 027 028 !!! */ else if (ELEM_IS_PLAYER(center_element)) Store[x][y] = EL_EMPTY; else if (center_element == EL_YAMYAM) Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy]; else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY) Store[x][y] = element_info[center_element].content.e[xx][yy]; #if 1 /* needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE" (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond otherwise) -- FIX THIS !!! */ else if (!CAN_EXPLODE(element) && element != EL_BD_BUTTERFLY) Store[x][y] = element_info[element].content.e[1][1]; #else else if (!CAN_EXPLODE(element)) Store[x][y] = element_info[element].content.e[1][1]; #endif else Store[x][y] = EL_EMPTY; if (x != ex || y != ey || mode == EX_TYPE_BORDER || center_element == EL_AMOEBA_TO_DIAMOND) Store2[x][y] = element; Feld[x][y] = EL_EXPLOSION; GfxElement[x][y] = artwork_element; ExplodePhase[x][y] = 1; ExplodeDelay[x][y] = last_phase; Stop[x][y] = TRUE; } if (center_element == EL_YAMYAM) game.yamyam_content_nr = (game.yamyam_content_nr + 1) % level.num_yamyam_contents; return; } if (Stop[ex][ey]) return; x = ex; y = ey; if (phase == 1) GfxFrame[x][y] = 0; /* restart explosion animation */ last_phase = ExplodeDelay[x][y]; ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); /* this can happen if the player leaves an explosion just in time */ if (GfxElement[x][y] == EL_UNDEFINED) GfxElement[x][y] = EL_EMPTY; border_element = Store2[x][y]; if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) border_element = StorePlayer[x][y]; if (phase == element_info[border_element].ignition_delay || phase == last_phase) { boolean border_explosion = FALSE; if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present && !PLAYER_EXPLOSION_PROTECTED(x, y)) { KillPlayerUnlessExplosionProtected(x, y); border_explosion = TRUE; } else if (CAN_EXPLODE_BY_EXPLOSION(border_element)) { Feld[x][y] = Store2[x][y]; Store2[x][y] = 0; Bang(x, y); border_explosion = TRUE; } else if (border_element == EL_AMOEBA_TO_DIAMOND) { AmoebeUmwandeln(x, y); Store2[x][y] = 0; border_explosion = TRUE; } /* if an element just explodes due to another explosion (chain-reaction), do not immediately end the new explosion when it was the last frame of the explosion (as it would be done in the following "if"-statement!) */ if (border_explosion && phase == last_phase) return; } if (phase == last_phase) { int element; element = Feld[x][y] = Store[x][y]; Store[x][y] = Store2[x][y] = 0; GfxElement[x][y] = EL_UNDEFINED; /* player can escape from explosions and might therefore be still alive */ if (element >= EL_PLAYER_IS_EXPLODING_1 && element <= EL_PLAYER_IS_EXPLODING_4) { int player_nr = element - EL_PLAYER_IS_EXPLODING_1; int explosion_element = EL_PLAYER_1 + player_nr; int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2); int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2); if (level.use_explosion_element[player_nr]) explosion_element = level.explosion_element[player_nr]; Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY : element_info[explosion_element].content.e[xx][yy]); } /* restore probably existing indestructible background element */ if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y])) element = Feld[x][y] = Back[x][y]; Back[x][y] = 0; MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0; GfxDir[x][y] = MV_NONE; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; CustomValue[x][y] = 0; InitField_WithBug2(x, y, FALSE); TEST_DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); if (GFX_CRUMBLED(element)) TEST_DrawLevelFieldCrumbledNeighbours(x, y); if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present) StorePlayer[x][y] = 0; if (ELEM_IS_PLAYER(element)) RelocatePlayer(x, y, element); } else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING); int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); if (phase == delay) TEST_DrawLevelFieldCrumbled(x, y); if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY) { DrawLevelElement(x, y, Back[x][y]); DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame); } else if (IS_WALKABLE_UNDER(Back[x][y])) { DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); DrawLevelElementThruMask(x, y, Back[x][y]); } else if (!IS_WALKABLE_INSIDE(Back[x][y])) DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); } } void DynaExplode(int ex, int ey) { int i, j; int dynabomb_element = Feld[ex][ey]; int dynabomb_size = 1; boolean dynabomb_xl = FALSE; struct PlayerInfo *player; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (IS_ACTIVE_BOMB(dynabomb_element)) { player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE]; dynabomb_size = player->dynabomb_size; dynabomb_xl = player->dynabomb_xl; player->dynabombs_left++; } Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER); for (i = 0; i < NUM_DIRECTIONS; i++) { for (j = 1; j <= dynabomb_size; j++) { int x = ex + j * xy[i][0]; int y = ey + j * xy[i][1]; int element; if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y])) break; element = Feld[x][y]; /* do not restart explosions of fields with active bombs */ if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y])) continue; Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER); if (element != EL_EMPTY && element != EL_EXPLOSION && !IS_DIGGABLE(element) && !dynabomb_xl) break; } } } void Bang(int x, int y) { int element = MovingOrBlocked2Element(x, y); int explosion_type = EX_TYPE_NORMAL; if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) { struct PlayerInfo *player = PLAYERINFO(x, y); element = Feld[x][y] = player->initial_element; if (level.use_explosion_element[player->index_nr]) { int explosion_element = level.explosion_element[player->index_nr]; if (element_info[explosion_element].explosion_type == EXPLODES_CROSS) explosion_type = EX_TYPE_CROSS; else if (element_info[explosion_element].explosion_type == EXPLODES_1X1) explosion_type = EX_TYPE_CENTER; } } switch (element) { case EL_BUG: case EL_SPACESHIP: case EL_BD_BUTTERFLY: case EL_BD_FIREFLY: case EL_YAMYAM: case EL_DARK_YAMYAM: case EL_ROBOT: case EL_PACMAN: case EL_MOLE: RaiseScoreElement(element); break; case EL_DYNABOMB_PLAYER_1_ACTIVE: case EL_DYNABOMB_PLAYER_2_ACTIVE: case EL_DYNABOMB_PLAYER_3_ACTIVE: case EL_DYNABOMB_PLAYER_4_ACTIVE: case EL_DYNABOMB_INCREASE_NUMBER: case EL_DYNABOMB_INCREASE_SIZE: case EL_DYNABOMB_INCREASE_POWER: explosion_type = EX_TYPE_DYNA; break; case EL_DC_LANDMINE: explosion_type = EX_TYPE_CENTER; break; case EL_PENGUIN: case EL_LAMP: case EL_LAMP_ACTIVE: case EL_AMOEBA_TO_DIAMOND: if (!IS_PLAYER(x, y)) /* penguin and player may be at same field */ explosion_type = EX_TYPE_CENTER; break; default: if (element_info[element].explosion_type == EXPLODES_CROSS) explosion_type = EX_TYPE_CROSS; else if (element_info[element].explosion_type == EXPLODES_1X1) explosion_type = EX_TYPE_CENTER; break; } if (explosion_type == EX_TYPE_DYNA) DynaExplode(x, y); else Explode(x, y, EX_PHASE_START, explosion_type); CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X); } void SplashAcid(int x, int y) { if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) && (!IN_LEV_FIELD(x - 1, y - 2) || !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2)))) Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT; if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) && (!IN_LEV_FIELD(x + 1, y - 2) || !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2)))) Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT; PlayLevelSound(x, y, SND_ACID_SPLASHING); } static void InitBeltMovement() { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; static int belt_base_active_element[4] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }; int x, y, i, j; /* set frame order for belt animation graphic according to belt direction */ for (i = 0; i < NUM_BELTS; i++) { int belt_nr = i; for (j = 0; j < NUM_BELT_PARTS; j++) { int element = belt_base_active_element[belt_nr] + j; int graphic_1 = el2img(element); int graphic_2 = el2panelimg(element); if (game.belt_dir[i] == MV_LEFT) { graphic_info[graphic_1].anim_mode &= ~ANIM_REVERSE; graphic_info[graphic_2].anim_mode &= ~ANIM_REVERSE; } else { graphic_info[graphic_1].anim_mode |= ANIM_REVERSE; graphic_info[graphic_2].anim_mode |= ANIM_REVERSE; } } } SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; for (i = 0; i < NUM_BELTS; i++) { if (IS_BELT(element) && game.belt_dir[i] != MV_NONE) { int e_belt_nr = getBeltNrFromBeltElement(element); int belt_nr = i; if (e_belt_nr == belt_nr) { int belt_part = Feld[x][y] - belt_base_element[belt_nr]; Feld[x][y] = belt_base_active_element[belt_nr] + belt_part; } } } } } static void ToggleBeltSwitch(int x, int y) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; static int belt_base_active_element[4] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }; static int belt_base_switch_element[4] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT }; static int belt_move_dir[4] = { MV_LEFT, MV_NONE, MV_RIGHT, MV_NONE, }; int element = Feld[x][y]; int belt_nr = getBeltNrFromBeltSwitchElement(element); int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4; int belt_dir = belt_move_dir[belt_dir_nr]; int xx, yy, i; if (!IS_BELT_SWITCH(element)) return; game.belt_dir_nr[belt_nr] = belt_dir_nr; game.belt_dir[belt_nr] = belt_dir; if (belt_dir_nr == 3) belt_dir_nr = 1; /* set frame order for belt animation graphic according to belt direction */ for (i = 0; i < NUM_BELT_PARTS; i++) { int element = belt_base_active_element[belt_nr] + i; int graphic_1 = el2img(element); int graphic_2 = el2panelimg(element); if (belt_dir == MV_LEFT) { graphic_info[graphic_1].anim_mode &= ~ANIM_REVERSE; graphic_info[graphic_2].anim_mode &= ~ANIM_REVERSE; } else { graphic_info[graphic_1].anim_mode |= ANIM_REVERSE; graphic_info[graphic_2].anim_mode |= ANIM_REVERSE; } } SCAN_PLAYFIELD(xx, yy) { int element = Feld[xx][yy]; if (IS_BELT_SWITCH(element)) { int e_belt_nr = getBeltNrFromBeltSwitchElement(element); if (e_belt_nr == belt_nr) { Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr; TEST_DrawLevelField(xx, yy); } } else if (IS_BELT(element) && belt_dir != MV_NONE) { int e_belt_nr = getBeltNrFromBeltElement(element); if (e_belt_nr == belt_nr) { int belt_part = Feld[xx][yy] - belt_base_element[belt_nr]; Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part; TEST_DrawLevelField(xx, yy); } } else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE) { int e_belt_nr = getBeltNrFromBeltActiveElement(element); if (e_belt_nr == belt_nr) { int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr]; Feld[xx][yy] = belt_base_element[belt_nr] + belt_part; TEST_DrawLevelField(xx, yy); } } } } static void ToggleSwitchgateSwitch(int x, int y) { int xx, yy; game.switchgate_pos = !game.switchgate_pos; SCAN_PLAYFIELD(xx, yy) { int element = Feld[xx][yy]; if (element == EL_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN; TEST_DrawLevelField(xx, yy); } else if (element == EL_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP; TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_DOWN; TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP; TEST_DrawLevelField(xx, yy); } else if (element == EL_SWITCHGATE_OPEN || element == EL_SWITCHGATE_OPENING) { Feld[xx][yy] = EL_SWITCHGATE_CLOSING; PlayLevelSoundAction(xx, yy, ACTION_CLOSING); } else if (element == EL_SWITCHGATE_CLOSED || element == EL_SWITCHGATE_CLOSING) { Feld[xx][yy] = EL_SWITCHGATE_OPENING; PlayLevelSoundAction(xx, yy, ACTION_OPENING); } } } static int getInvisibleActiveFromInvisibleElement(int element) { return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE : element == EL_INVISIBLE_WALL ? EL_INVISIBLE_WALL_ACTIVE : element == EL_INVISIBLE_SAND ? EL_INVISIBLE_SAND_ACTIVE : element); } static int getInvisibleFromInvisibleActiveElement(int element) { return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL : element == EL_INVISIBLE_WALL_ACTIVE ? EL_INVISIBLE_WALL : element == EL_INVISIBLE_SAND_ACTIVE ? EL_INVISIBLE_SAND : element); } static void RedrawAllLightSwitchesAndInvisibleElements() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_LIGHT_SWITCH && game.light_time_left > 0) { Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_LIGHT_SWITCH_ACTIVE && game.light_time_left == 0) { Feld[x][y] = EL_LIGHT_SWITCH; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER && game.light_time_left > 0) { Feld[x][y] = EL_EMC_DRIPPER_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER_ACTIVE && game.light_time_left == 0) { Feld[x][y] = EL_EMC_DRIPPER; TEST_DrawLevelField(x, y); } else if (element == EL_INVISIBLE_STEELWALL || element == EL_INVISIBLE_WALL || element == EL_INVISIBLE_SAND) { if (game.light_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); TEST_DrawLevelField(x, y); /* uncrumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_INVISIBLE_STEELWALL_ACTIVE || element == EL_INVISIBLE_WALL_ACTIVE || element == EL_INVISIBLE_SAND_ACTIVE) { if (game.light_time_left == 0) Feld[x][y] = getInvisibleFromInvisibleActiveElement(element); TEST_DrawLevelField(x, y); /* re-crumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } static void RedrawAllInvisibleElementsForLenses() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_EMC_DRIPPER && game.lenses_time_left > 0) { Feld[x][y] = EL_EMC_DRIPPER_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER_ACTIVE && game.lenses_time_left == 0) { Feld[x][y] = EL_EMC_DRIPPER; TEST_DrawLevelField(x, y); } else if (element == EL_INVISIBLE_STEELWALL || element == EL_INVISIBLE_WALL || element == EL_INVISIBLE_SAND) { if (game.lenses_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); TEST_DrawLevelField(x, y); /* uncrumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_INVISIBLE_STEELWALL_ACTIVE || element == EL_INVISIBLE_WALL_ACTIVE || element == EL_INVISIBLE_SAND_ACTIVE) { if (game.lenses_time_left == 0) Feld[x][y] = getInvisibleFromInvisibleActiveElement(element); TEST_DrawLevelField(x, y); /* re-crumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } static void RedrawAllInvisibleElementsForMagnifier() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_EMC_FAKE_GRASS && game.magnify_time_left > 0) { Feld[x][y] = EL_EMC_FAKE_GRASS_ACTIVE; TEST_DrawLevelField(x, y); } else if (element == EL_EMC_FAKE_GRASS_ACTIVE && game.magnify_time_left == 0) { Feld[x][y] = EL_EMC_FAKE_GRASS; TEST_DrawLevelField(x, y); } else if (IS_GATE_GRAY(element) && game.magnify_time_left > 0) { Feld[x][y] = (IS_RND_GATE_GRAY(element) ? element - EL_GATE_1_GRAY + EL_GATE_1_GRAY_ACTIVE : IS_EM_GATE_GRAY(element) ? element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE : IS_EMC_GATE_GRAY(element) ? element - EL_EMC_GATE_5_GRAY + EL_EMC_GATE_5_GRAY_ACTIVE : IS_DC_GATE_GRAY(element) ? EL_DC_GATE_WHITE_GRAY_ACTIVE : element); TEST_DrawLevelField(x, y); } else if (IS_GATE_GRAY_ACTIVE(element) && game.magnify_time_left == 0) { Feld[x][y] = (IS_RND_GATE_GRAY_ACTIVE(element) ? element - EL_GATE_1_GRAY_ACTIVE + EL_GATE_1_GRAY : IS_EM_GATE_GRAY_ACTIVE(element) ? element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY : IS_EMC_GATE_GRAY_ACTIVE(element) ? element - EL_EMC_GATE_5_GRAY_ACTIVE + EL_EMC_GATE_5_GRAY : IS_DC_GATE_GRAY_ACTIVE(element) ? EL_DC_GATE_WHITE_GRAY : element); TEST_DrawLevelField(x, y); } } } static void ToggleLightSwitch(int x, int y) { int element = Feld[x][y]; game.light_time_left = (element == EL_LIGHT_SWITCH ? level.time_light * FRAMES_PER_SECOND : 0); RedrawAllLightSwitchesAndInvisibleElements(); } static void ActivateTimegateSwitch(int x, int y) { int xx, yy; game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND; SCAN_PLAYFIELD(xx, yy) { int element = Feld[xx][yy]; if (element == EL_TIMEGATE_CLOSED || element == EL_TIMEGATE_CLOSING) { Feld[xx][yy] = EL_TIMEGATE_OPENING; PlayLevelSound(xx, yy, SND_CLASS_TIMEGATE_OPENING); } /* else if (element == EL_TIMEGATE_SWITCH_ACTIVE) { Feld[xx][yy] = EL_TIMEGATE_SWITCH; TEST_DrawLevelField(xx, yy); } */ } Feld[x][y] = (Feld[x][y] == EL_TIMEGATE_SWITCH ? EL_TIMEGATE_SWITCH_ACTIVE : EL_DC_TIMEGATE_SWITCH_ACTIVE); } void Impact(int x, int y) { boolean last_line = (y == lev_fieldy - 1); boolean object_hit = FALSE; boolean impact = (last_line || object_hit); int element = Feld[x][y]; int smashed = EL_STEELWALL; if (!last_line) /* check if element below was hit */ { if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING) return; object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) || MovDir[x][y + 1] != MV_DOWN || MovPos[x][y + 1] <= TILEY / 2)); /* do not smash moving elements that left the smashed field in time */ if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) && ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) object_hit = FALSE; #if USE_QUICKSAND_IMPACT_BUGFIX if (Feld[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE) { RemoveMovingField(x, y + 1); Feld[x][y + 1] = EL_QUICKSAND_EMPTY; Feld[x][y + 2] = EL_ROCK; TEST_DrawLevelField(x, y + 2); object_hit = TRUE; } if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTYING && object_hit == FALSE) { RemoveMovingField(x, y + 1); Feld[x][y + 1] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 2] = EL_ROCK; TEST_DrawLevelField(x, y + 2); object_hit = TRUE; } #endif if (object_hit) smashed = MovingOrBlocked2Element(x, y + 1); impact = (last_line || object_hit); } if (!last_line && smashed == EL_ACID) /* element falls into acid */ { SplashAcid(x, y + 1); return; } /* !!! not sufficient for all cases -- see EL_PEARL below !!! */ /* only reset graphic animation if graphic really changes after impact */ if (impact && el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element)) { ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } if (impact && CAN_EXPLODE_IMPACT(element)) { Bang(x, y); return; } else if (impact && element == EL_PEARL && smashed != EL_DC_MAGIC_WALL && smashed != EL_DC_MAGIC_WALL_ACTIVE) { ResetGfxAnimation(x, y); Feld[x][y] = EL_PEARL_BREAKING; PlayLevelSound(x, y, SND_PEARL_BREAKING); return; } else if (impact && CheckElementChange(x, y, element, smashed, CE_IMPACT)) { PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); return; } if (impact && element == EL_AMOEBA_DROP) { if (object_hit && IS_PLAYER(x, y + 1)) KillPlayerUnlessEnemyProtected(x, y + 1); else if (object_hit && smashed == EL_PENGUIN) Bang(x, y + 1); else { Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; ResetRandomAnimationValue(x, y); } return; } if (object_hit) /* check which object was hit */ { if ((CAN_PASS_MAGIC_WALL(element) && (smashed == EL_MAGIC_WALL || smashed == EL_BD_MAGIC_WALL)) || (CAN_PASS_DC_MAGIC_WALL(element) && smashed == EL_DC_MAGIC_WALL)) { int xx, yy; int activated_magic_wall = (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE : smashed == EL_BD_MAGIC_WALL ? EL_BD_MAGIC_WALL_ACTIVE : EL_DC_MAGIC_WALL_ACTIVE); /* activate magic wall / mill */ SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == smashed) Feld[xx][yy] = activated_magic_wall; } game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND; game.magic_wall_active = TRUE; PlayLevelSound(x, y, (smashed == EL_MAGIC_WALL ? SND_MAGIC_WALL_ACTIVATING : smashed == EL_BD_MAGIC_WALL ? SND_BD_MAGIC_WALL_ACTIVATING : SND_DC_MAGIC_WALL_ACTIVATING)); } if (IS_PLAYER(x, y + 1)) { if (CAN_SMASH_PLAYER(element)) { KillPlayerUnlessEnemyProtected(x, y + 1); return; } } else if (smashed == EL_PENGUIN) { if (CAN_SMASH_PLAYER(element)) { Bang(x, y + 1); return; } } else if (element == EL_BD_DIAMOND) { if (IS_CLASSIC_ENEMY(smashed) && IS_BD_ELEMENT(smashed)) { Bang(x, y + 1); return; } } else if (((element == EL_SP_INFOTRON || element == EL_SP_ZONK) && (smashed == EL_SP_SNIKSNAK || smashed == EL_SP_ELECTRON || smashed == EL_SP_DISK_ORANGE)) || (element == EL_SP_INFOTRON && smashed == EL_SP_DISK_YELLOW)) { Bang(x, y + 1); return; } else if (CAN_SMASH_EVERYTHING(element)) { if (IS_CLASSIC_ENEMY(smashed) || CAN_EXPLODE_SMASHED(smashed)) { Bang(x, y + 1); return; } else if (!IS_MOVING(x, y + 1) && !IS_BLOCKED(x, y + 1)) { if (smashed == EL_LAMP || smashed == EL_LAMP_ACTIVE) { Bang(x, y + 1); return; } else if (smashed == EL_NUT) { Feld[x][y + 1] = EL_NUT_BREAKING; PlayLevelSound(x, y, SND_NUT_BREAKING); RaiseScoreElement(EL_NUT); return; } else if (smashed == EL_PEARL) { ResetGfxAnimation(x, y); Feld[x][y + 1] = EL_PEARL_BREAKING; PlayLevelSound(x, y, SND_PEARL_BREAKING); return; } else if (smashed == EL_DIAMOND) { Feld[x][y + 1] = EL_DIAMOND_BREAKING; PlayLevelSound(x, y, SND_DIAMOND_BREAKING); return; } else if (IS_BELT_SWITCH(smashed)) { ToggleBeltSwitch(x, y + 1); } else if (smashed == EL_SWITCHGATE_SWITCH_UP || smashed == EL_SWITCHGATE_SWITCH_DOWN || smashed == EL_DC_SWITCHGATE_SWITCH_UP || smashed == EL_DC_SWITCHGATE_SWITCH_DOWN) { ToggleSwitchgateSwitch(x, y + 1); } else if (smashed == EL_LIGHT_SWITCH || smashed == EL_LIGHT_SWITCH_ACTIVE) { ToggleLightSwitch(x, y + 1); } else { CheckElementChange(x, y + 1, smashed, element, CE_SMASHED); CheckElementChangeBySide(x, y + 1, smashed, element, CE_SWITCHED, CH_SIDE_TOP); CheckTriggeredElementChangeBySide(x, y + 1, smashed, CE_SWITCH_OF_X, CH_SIDE_TOP); } } else { CheckElementChange(x, y + 1, smashed, element, CE_SMASHED); } } } /* play sound of magic wall / mill */ if (!last_line && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)) { if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING); else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING); else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_DC_MAGIC_WALL_FILLING); return; } /* play sound of object that hits the ground */ if (last_line || object_hit) PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); } inline static void TurnRoundExt(int x, int y) { static struct { int dx, dy; } 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 move_pattern = element_info[element].move_pattern; 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; int left_dx = move_xy[left_dir].dx, left_dy = move_xy[left_dir].dy; int right_dx = move_xy[right_dir].dx, right_dy = move_xy[right_dir].dy; int move_dx = move_xy[old_move_dir].dx, move_dy = move_xy[old_move_dir].dy; int back_dx = move_xy[back_dir].dx, back_dy = move_xy[back_dir].dy; 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; int xx, yy; if (element == EL_BUG || element == EL_BD_BUTTERFLY) { TestIfBadThingTouchesOtherBadThing(x, y); if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = left_dir; if (element == EL_BUG && MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; else if (element == EL_BD_BUTTERFLY) /* && MovDir[x][y] == left_dir) */ MovDelay[x][y] = 1; } else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY) { TestIfBadThingTouchesOtherBadThing(x, y); if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = right_dir; if (element == EL_SPACESHIP && MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */ MovDelay[x][y] = 1; } else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) { TestIfBadThingTouchesOtherBadThing(x, y); if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0)) MovDir[x][y] = left_dir; else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0)) MovDir[x][y] = right_dir; if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; } else if (element == EL_YAMYAM) { boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y); 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; MovDelay[x][y] = 16 + 16 * RND(3); } else if (element == EL_DARK_YAMYAM) { boolean can_turn_left = DARK_YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y); 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; MovDelay[x][y] = 16 + 16 * RND(3); } else if (element == EL_PACMAN) { boolean can_turn_left = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y); 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; MovDelay[x][y] = 6 + RND(40); } else if (element == EL_PIG) { boolean can_turn_left = PIG_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y); boolean can_move_on = PIG_CAN_ENTER_FIELD(element, move_x, move_y); boolean should_turn_left, should_turn_right, should_move_on; int rnd_value = 24; int rnd = RND(rnd_value); should_turn_left = (can_turn_left && (!can_move_on || IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx, y + back_dy + left_dy))); should_turn_right = (can_turn_right && (!can_move_on || IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx, y + back_dy + right_dy))); should_move_on = (can_move_on && (!can_turn_left || !can_turn_right || IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx, y + move_dy + left_dy) || IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx, y + move_dy + right_dy))); if (should_turn_left || should_turn_right || should_move_on) { 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; xx = x + move_xy[MovDir[x][y]].dx; yy = y + move_xy[MovDir[x][y]].dy; if (!IN_LEV_FIELD(xx, yy) || (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))) MovDir[x][y] = old_move_dir; MovDelay[x][y] = 0; } else if (element == EL_DRAGON) { boolean can_turn_left = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y); boolean can_move_on = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y); int rnd_value = 24; int rnd = RND(rnd_value); 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; xx = x + move_xy[MovDir[x][y]].dx; yy = y + move_xy[MovDir[x][y]].dy; if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy)) MovDir[x][y] = old_move_dir; MovDelay[x][y] = 0; } else if (element == EL_MOLE) { boolean can_move_on = (MOLE_CAN_ENTER_FIELD(element, move_x, move_y, IS_AMOEBOID(Feld[move_x][move_y]) || Feld[move_x][move_y] == EL_AMOEBA_SHRINKING)); if (!can_move_on) { boolean can_turn_left = (MOLE_CAN_ENTER_FIELD(element, left_x, left_y, IS_AMOEBOID(Feld[left_x][left_y]))); boolean can_turn_right = (MOLE_CAN_ENTER_FIELD(element, right_x, right_y, IS_AMOEBOID(Feld[right_x][right_y]))); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(2) ? left_dir : right_dir); else if (can_turn_left) MovDir[x][y] = left_dir; else MovDir[x][y] = right_dir; } if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; } else if (element == EL_BALLOON) { MovDir[x][y] = game.wind_direction; MovDelay[x][y] = 0; } else if (element == EL_SPRING) { if (MovDir[x][y] & MV_HORIZONTAL) { if (SPRING_CAN_BUMP_FROM_FIELD(move_x, move_y) && !SPRING_CAN_ENTER_FIELD(element, x, y + 1)) { Feld[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE; ResetGfxAnimation(move_x, move_y); TEST_DrawLevelField(move_x, move_y); MovDir[x][y] = back_dir; } else if (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) || SPRING_CAN_ENTER_FIELD(element, x, y + 1)) MovDir[x][y] = MV_NONE; } MovDelay[x][y] = 0; } else if (element == EL_ROBOT || element == EL_SATELLITE || element == EL_PENGUIN || element == EL_EMC_ANDROID) { int attr_x = -1, attr_y = -1; if (AllPlayersGone) { attr_x = ExitX; attr_y = ExitY; } else { int i; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; if (!player->active) 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 (element == EL_ROBOT && ZX >= 0 && ZY >= 0 && (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE || game.engine_version < VERSION_IDENT(3,1,0,0))) { attr_x = ZX; attr_y = ZY; } if (element == EL_PENGUIN) { int i; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int ex = x + xy[i][0]; int ey = y + xy[i][1]; if (IN_LEV_FIELD(ex, ey) && (Feld[ex][ey] == EL_EXIT_OPEN || Feld[ex][ey] == EL_EM_EXIT_OPEN || Feld[ex][ey] == EL_STEEL_EXIT_OPEN || Feld[ex][ey] == EL_EM_STEEL_EXIT_OPEN)) { attr_x = ex; attr_y = ey; break; } } } MovDir[x][y] = MV_NONE; if (attr_x < x) MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT); else if (attr_x > x) MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT); if (attr_y < y) MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP); else if (attr_y > y) MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN); if (element == EL_ROBOT) { int newx, newy; if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) MovDir[x][y] &= (RND(2) ? MV_HORIZONTAL : MV_VERTICAL); 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 if (element == EL_PENGUIN) { int newx, newy; MovDelay[x][y] = 1; if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) { boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = old_move_dir; return; } } else if (element == EL_SATELLITE) { int newx, newy; MovDelay[x][y] = 1; if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) { boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (SATELLITE_CAN_ENTER_FIELD(newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (SATELLITE_CAN_ENTER_FIELD(newx, newy)) return; MovDir[x][y] = old_move_dir; return; } } else if (element == EL_EMC_ANDROID) { static int check_pos[16] = { -1, /* 0 => (invalid) */ 7, /* 1 => MV_LEFT */ 3, /* 2 => MV_RIGHT */ -1, /* 3 => (invalid) */ 1, /* 4 => MV_UP */ 0, /* 5 => MV_LEFT | MV_UP */ 2, /* 6 => MV_RIGHT | MV_UP */ -1, /* 7 => (invalid) */ 5, /* 8 => MV_DOWN */ 6, /* 9 => MV_LEFT | MV_DOWN */ 4, /* 10 => MV_RIGHT | MV_DOWN */ -1, /* 11 => (invalid) */ -1, /* 12 => (invalid) */ -1, /* 13 => (invalid) */ -1, /* 14 => (invalid) */ -1, /* 15 => (invalid) */ }; static struct { int dx, dy; int dir; } check_xy[8] = { { -1, -1, MV_LEFT | MV_UP }, { 0, -1, MV_UP }, { +1, -1, MV_RIGHT | MV_UP }, { +1, 0, MV_RIGHT }, { +1, +1, MV_RIGHT | MV_DOWN }, { 0, +1, MV_DOWN }, { -1, +1, MV_LEFT | MV_DOWN }, { -1, 0, MV_LEFT }, }; int start_pos, check_order; boolean can_clone = FALSE; int i; /* check if there is any free field around current position */ for (i = 0; i < 8; i++) { int newx = x + check_xy[i].dx; int newy = y + check_xy[i].dy; if (IN_LEV_FIELD_AND_IS_FREE(newx, newy)) { can_clone = TRUE; break; } } if (can_clone) /* randomly find an element to clone */ { can_clone = FALSE; start_pos = check_pos[RND(8)]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 8; i++) { int pos_raw = start_pos + i * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; if (ANDROID_CAN_CLONE_FIELD(newx, newy)) { element_info[element].move_leave_type = LEAVE_TYPE_LIMITED; element_info[element].move_leave_element = EL_TRIGGER_ELEMENT; Store[x][y] = Feld[newx][newy]; can_clone = TRUE; break; } } } if (can_clone) /* randomly find a direction to move */ { can_clone = FALSE; start_pos = check_pos[RND(8)]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 8; i++) { int pos_raw = start_pos + i * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; int new_move_dir = check_xy[pos].dir; if (IN_LEV_FIELD_AND_IS_FREE(newx, newy)) { MovDir[x][y] = new_move_dir; MovDelay[x][y] = level.android_clone_time * 8 + 1; can_clone = TRUE; break; } } } if (can_clone) /* cloning and moving successful */ return; /* cannot clone -- try to move towards player */ start_pos = check_pos[MovDir[x][y] & 0x0f]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 3; i++) { /* first check start_pos, then previous/next or (next/previous) pos */ int pos_raw = start_pos + (i < 2 ? i : -1) * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; int new_move_dir = check_xy[pos].dir; if (IS_PLAYER(newx, newy)) break; if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) { MovDir[x][y] = new_move_dir; MovDelay[x][y] = level.android_move_time * 8 + 1; break; } } } } else if (move_pattern == MV_TURNING_LEFT || move_pattern == MV_TURNING_RIGHT || move_pattern == MV_TURNING_LEFT_RIGHT || move_pattern == MV_TURNING_RIGHT_LEFT || move_pattern == MV_TURNING_RANDOM || move_pattern == MV_ALL_DIRECTIONS) { boolean can_turn_left = CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); if (element_info[element].move_stepsize == 0) /* "not moving" */ return; if (move_pattern == MV_TURNING_LEFT) MovDir[x][y] = left_dir; else if (move_pattern == MV_TURNING_RIGHT) MovDir[x][y] = right_dir; else if (move_pattern == MV_TURNING_LEFT_RIGHT) MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir); else if (move_pattern == MV_TURNING_RIGHT_LEFT) MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir); else if (move_pattern == MV_TURNING_RANDOM) MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir : can_turn_right && !can_turn_left ? right_dir : RND(2) ? left_dir : right_dir); else 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; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_HORIZONTAL || move_pattern == MV_VERTICAL) { if (move_pattern & old_move_dir) MovDir[x][y] = back_dir; else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern & MV_ANY_DIRECTION) { MovDir[x][y] = move_pattern; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern & MV_WIND_DIRECTION) { MovDir[x][y] = game.wind_direction; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_ALONG_LEFT_SIDE) { if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = right_dir; if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_ALONG_RIGHT_SIDE) { if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = left_dir; if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } else if (move_pattern == MV_TOWARDS_PLAYER || move_pattern == MV_AWAY_FROM_PLAYER) { int attr_x = -1, attr_y = -1; int newx, newy; boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER); if (AllPlayersGone) { attr_x = ExitX; attr_y = ExitY; } else { int i; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; if (!player->active) 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; } } } MovDir[x][y] = MV_NONE; if (attr_x < x) MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT); else if (attr_x > x) MovDir[x][y] |= (move_away ? MV_LEFT : MV_RIGHT); if (attr_y < y) MovDir[x][y] |= (move_away ? MV_DOWN : MV_UP); else if (attr_y > y) MovDir[x][y] |= (move_away ? MV_UP : MV_DOWN); MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL) { boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; if (element_info[element].move_stepsize == 0) /* "not moving" */ { first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y)); MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); return; } MovDir[x][y] = new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = old_move_dir; } } else if (move_pattern == MV_WHEN_PUSHED || move_pattern == MV_WHEN_DROPPED) { if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = MV_NONE; MovDelay[x][y] = 0; } else if (move_pattern & MV_MAZE_RUNNER_STYLE) { static int test_xy[7][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 }, { 0, -1 }, { -1, 0 }, { +1, 0 }, }; static int test_dir[7] = { MV_UP, MV_LEFT, MV_RIGHT, MV_DOWN, MV_UP, MV_LEFT, MV_RIGHT, }; boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER); int move_preference = -1000000; /* start with very low preference */ int new_move_dir = MV_NONE; int start_test = RND(4); int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int move_dir = test_dir[start_test + i]; int move_dir_preference; xx = x + test_xy[start_test + i][0]; yy = y + test_xy[start_test + i][1]; if (hunter_mode && IN_LEV_FIELD(xx, yy) && (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING)) { new_move_dir = move_dir; break; } if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy)) continue; move_dir_preference = -1 * RunnerVisit[xx][yy]; if (hunter_mode && PlayerVisit[xx][yy] > 0) move_dir_preference = PlayerVisit[xx][yy]; if (move_dir_preference > move_preference) { /* prefer field that has not been visited for the longest time */ move_preference = move_dir_preference; new_move_dir = move_dir; } else if (move_dir_preference == move_preference && move_dir == old_move_dir) { /* prefer last direction when all directions are preferred equally */ move_preference = move_dir_preference; new_move_dir = move_dir; } } MovDir[x][y] = new_move_dir; if (old_move_dir != new_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } } static void TurnRound(int x, int y) { int direction = MovDir[x][y]; TurnRoundExt(x, y); GfxDir[x][y] = MovDir[x][y]; if (direction != MovDir[x][y]) GfxFrame[x][y] = 0; if (MovDelay[x][y]) GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction); ResetGfxFrame(x, y); } static boolean JustBeingPushed(int x, int y) { int i; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (player->active && player->is_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) { boolean started_moving = FALSE; /* some elements can fall _and_ move */ int element = Feld[x][y]; if (Stop[x][y]) return; if (MovDelay[x][y] == 0) GfxAction[x][y] = ACTION_DEFAULT; if (CAN_FALL(element) && y < lev_fieldy - 1) { if ((x > 0 && IS_PLAYER(x - 1, y)) || (x < lev_fieldx - 1 && IS_PLAYER(x + 1, y))) if (JustBeingPushed(x, y)) return; if (element == EL_QUICKSAND_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_EMPTYING; #if USE_QUICKSAND_BD_ROCK_BUGFIX if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) Store[x][y] = EL_ROCK; #else Store[x][y] = EL_ROCK; #endif PlayLevelSoundAction(x, y, ACTION_EMPTYING); } else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FAST_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } } else if (element == EL_QUICKSAND_FAST_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_FAST_EMPTYING; #if USE_QUICKSAND_BD_ROCK_BUGFIX if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) Store[x][y] = EL_ROCK; #else Store[x][y] = EL_ROCK; #endif PlayLevelSoundAction(x, y, ACTION_EMPTYING); } else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_FAST_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FAST_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { if (!MovDelay[x][y]) { MovDelay[x][y] = TILEY + 1; ResetGfxAnimation(x, y); ResetGfxAnimation(x, y + 1); } if (MovDelay[x][y]) { DrawLevelElement(x, y, EL_QUICKSAND_FAST_EMPTYING); DrawLevelElement(x, y + 1, EL_QUICKSAND_FILLING); MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 1] = EL_QUICKSAND_FULL; Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; PlayLevelSoundAction(x, y, ACTION_FILLING); } } else if ((element == EL_ROCK || element == EL_BD_ROCK) && Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_FILLING; Store[x][y] = element; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if ((element == EL_ROCK || element == EL_BD_ROCK) && Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_QUICKSAND_FAST_FILLING; Store[x][y] = element; PlayLevelSoundAction(x, y, ACTION_FILLING); } else if (element == EL_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_MAGIC_WALL_EMPTYING; Store[x][y] = EL_CHANGED(Store[x][y]); } else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY / 4 + 1; if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_MAGIC_WALL_FULL; Store[x][y + 1] = EL_CHANGED(Store[x][y]); Store[x][y] = 0; } } else if (element == EL_BD_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING; Store[x][y] = EL_CHANGED_BD(Store[x][y]); } else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY / 4 + 1; if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL; Store[x][y + 1] = EL_CHANGED_BD(Store[x][y]); Store[x][y] = 0; } } else if (element == EL_DC_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = EL_DC_MAGIC_WALL_EMPTYING; Store[x][y] = EL_CHANGED_DC(Store[x][y]); } else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) MovDelay[x][y] = TILEY / 4 + 1; if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) return; } Feld[x][y] = EL_DC_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_DC_MAGIC_WALL_FULL; Store[x][y + 1] = EL_CHANGED_DC(Store[x][y]); Store[x][y] = 0; } } else if ((CAN_PASS_MAGIC_WALL(element) && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) || (CAN_PASS_DC_MAGIC_WALL(element) && (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE))) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING : Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ? EL_BD_MAGIC_WALL_FILLING : EL_DC_MAGIC_WALL_FILLING); Store[x][y] = element; } else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID) { SplashAcid(x, y + 1); InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Store[x][y] = EL_ACID; } else if ( (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckImpact[x][y] && !IS_FREE(x, y + 1)) || (game.engine_version >= VERSION_IDENT(3,0,7,0) && CAN_FALL(element) && WasJustFalling[x][y] && (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) || (game.engine_version < VERSION_IDENT(2,2,0,7) && CAN_FALL(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] && (Feld[x][y + 1] == EL_BLOCKED))) { /* this is needed for a special case not covered by calling "Impact()" from "ContinueMoving()": if an element moves to a tile directly below another element which was just falling on that tile (which was empty in the previous frame), the falling element above would just stop instead of smashing the element below (in previous version, the above element was just checked for "moving" instead of "falling", resulting in incorrect smashes caused by horizontal movement of the above element; also, the case of the player being the element to smash was simply not covered here... :-/ ) */ CheckCollision[x][y] = 0; CheckImpact[x][y] = 0; Impact(x, y); } else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug) { if (MovDir[x][y] == MV_NONE) { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; } } else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING) { if (WasJustFalling[x][y]) /* prevent animation from being restarted */ MovDir[x][y] = MV_DOWN; InitMovingField(x, y, MV_DOWN); started_moving = TRUE; } else if (element == EL_AMOEBA_DROP) { Feld[x][y] = EL_AMOEBA_GROWING; Store[x][y] = EL_AMOEBA_WET; } else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) || (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) && !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] && element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE) { boolean can_fall_left = (x > 0 && IS_FREE(x - 1, y) && (IS_FREE(x - 1, y + 1) || Feld[x - 1][y + 1] == EL_ACID)); boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) && (IS_FREE(x + 1, y + 1) || Feld[x + 1][y + 1] == EL_ACID)); boolean can_fall_any = (can_fall_left || can_fall_right); boolean can_fall_both = (can_fall_left && can_fall_right); int slippery_type = element_info[Feld[x][y + 1]].slippery_type; if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM) { if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both) can_fall_left = FALSE; else if (slippery_type == SLIPPERY_ONLY_LEFT) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ONLY_RIGHT) can_fall_left = FALSE; can_fall_any = (can_fall_left || can_fall_right); can_fall_both = FALSE; } if (can_fall_both) { if (element == EL_BD_ROCK || element == EL_BD_DIAMOND) can_fall_right = FALSE; /* slip down on left side */ else can_fall_left = !(can_fall_right = RND(2)); can_fall_both = FALSE; } if (can_fall_any) { /* if not determined otherwise, prefer left side for slipping down */ InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT); started_moving = TRUE; } } else if (IS_BELT_ACTIVE(Feld[x][y + 1])) { boolean left_is_free = (x > 0 && IS_FREE(x - 1, y)); boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y)); int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]); int belt_dir = game.belt_dir[belt_nr]; if ((belt_dir == MV_LEFT && left_is_free) || (belt_dir == MV_RIGHT && right_is_free)) { int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1); InitMovingField(x, y, belt_dir); started_moving = TRUE; Pushed[x][y] = TRUE; Pushed[nextx][y] = TRUE; GfxAction[x][y] = ACTION_DEFAULT; } else { MovDir[x][y] = 0; /* if element was moving, stop it */ } } } /* not "else if" because of elements that can fall and move (EL_SPRING) */ if (CAN_MOVE(element) && !started_moving) { int move_pattern = element_info[element].move_pattern; int newx, newy; Moving2Blocked(x, y, &newx, &newy); if (IS_PUSHABLE(element) && JustBeingPushed(x, y)) return; if (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy)) { WasJustMoving[x][y] = 0; CheckCollision[x][y] = 0; TestIfElementHitsCustomElement(x, y, MovDir[x][y]); if (Feld[x][y] != element) /* element has changed */ return; } if (!MovDelay[x][y]) /* start new movement phase */ { /* all objects that can change their move direction after each step (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */ if (element != EL_YAMYAM && element != EL_DARK_YAMYAM && element != EL_PACMAN && !(move_pattern & MV_ANY_DIRECTION) && move_pattern != MV_TURNING_LEFT && move_pattern != MV_TURNING_RIGHT && move_pattern != MV_TURNING_LEFT_RIGHT && move_pattern != MV_TURNING_RIGHT_LEFT && move_pattern != MV_TURNING_RANDOM) { TurnRound(x, y); if (MovDelay[x][y] && (element == EL_BUG || element == EL_SPACESHIP || element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON || element == EL_MOLE)) TEST_DrawLevelField(x, y); } } if (MovDelay[x][y]) /* wait some time before next movement */ { MovDelay[x][y]--; if (element == EL_ROBOT || element == EL_YAMYAM || element == EL_DARK_YAMYAM) { DrawLevelElementAnimationIfNeeded(x, y, element); PlayLevelSoundAction(x, y, ACTION_WAITING); } else if (element == EL_SP_ELECTRON) DrawLevelElementAnimationIfNeeded(x, y, element); else if (element == EL_DRAGON) { 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 ? IMG_FLAMES_1_LEFT : dir == MV_RIGHT ? IMG_FLAMES_1_RIGHT : dir == MV_UP ? IMG_FLAMES_1_UP : dir == MV_DOWN ? IMG_FLAMES_1_DOWN : IMG_EMPTY); int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); GfxAction[x][y] = ACTION_ATTACKING; if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); PlayLevelSoundActionIfLoop(x, y, ACTION_ATTACKING); for (i = 1; i <= 3; i++) { int xx = x + i * dx; int yy = y + i * dy; int sx = SCREENX(xx); int sy = SCREENY(yy); int flame_graphic = graphic + (i - 1); if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy])) break; if (MovDelay[x][y]) { int flamed = MovingOrBlocked2Element(xx, yy); if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed)) Bang(xx, yy); else RemoveMovingField(xx, yy); ChangeDelay[xx][yy] = 0; Feld[xx][yy] = EL_FLAMES; if (IN_SCR_FIELD(sx, sy)) { TEST_DrawLevelFieldCrumbled(xx, yy); DrawGraphic(sx, sy, flame_graphic, frame); } } else { if (Feld[xx][yy] == EL_FLAMES) Feld[xx][yy] = EL_EMPTY; TEST_DrawLevelField(xx, yy); } } } if (MovDelay[x][y]) /* element still has to wait some time */ { PlayLevelSoundAction(x, y, ACTION_WAITING); return; } } /* now make next step */ Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ if (DONT_COLLIDE_WITH(element) && IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) && !PLAYER_ENEMY_PROTECTED(newx, newy)) { TestIfBadThingRunsIntoPlayer(x, y, MovDir[x][y]); return; } else if (CAN_MOVE_INTO_ACID(element) && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID && !IS_MV_DIAGONAL(MovDir[x][y]) && (MovDir[x][y] == MV_DOWN || game.engine_version >= VERSION_IDENT(3,1,0,0))) { SplashAcid(newx, newy); Store[x][y] = EL_ACID; } else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy)) { if (Feld[newx][newy] == EL_EXIT_OPEN || Feld[newx][newy] == EL_EM_EXIT_OPEN || Feld[newx][newy] == EL_STEEL_EXIT_OPEN || Feld[newx][newy] == EL_EM_STEEL_EXIT_OPEN) { RemoveField(x, y); TEST_DrawLevelField(x, y); PlayLevelSound(newx, newy, SND_PENGUIN_PASSING); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0); local_player->friends_still_needed--; if (!local_player->friends_still_needed && !local_player->GameOver && AllPlayersGone) PlayerWins(local_player); return; } else if (IS_FOOD_PENGUIN(Feld[newx][newy])) { if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING) TEST_DrawLevelField(newx, newy); else GfxDir[x][y] = MovDir[x][y] = MV_NONE; } else if (!IS_FREE(newx, newy)) { GfxAction[x][y] = ACTION_WAITING; if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); return; } } else if (element == EL_PIG && IN_LEV_FIELD(newx, newy)) { if (IS_FOOD_PIG(Feld[newx][newy])) { if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_PIG_DIGGING); } else if (!IS_FREE(newx, newy)) { if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); return; } } else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy)) { if (Store[x][y] != EL_EMPTY) { boolean can_clone = FALSE; int xx, yy; /* check if element to clone is still there */ for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++) { if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y]) { can_clone = TRUE; break; } } /* cannot clone or target field not free anymore -- do not clone */ if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy)) Store[x][y] = EL_EMPTY; } if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) { if (IS_MV_DIAGONAL(MovDir[x][y])) { int diagonal_move_dir = MovDir[x][y]; int stored = Store[x][y]; int change_delay = 8; int graphic; /* android is moving diagonally */ CreateField(x, y, EL_DIAGONAL_SHRINKING); Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored); GfxElement[x][y] = EL_EMC_ANDROID; GfxAction[x][y] = ACTION_SHRINKING; GfxDir[x][y] = diagonal_move_dir; ChangeDelay[x][y] = change_delay; graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y], GfxDir[x][y]); DrawLevelGraphicAnimation(x, y, graphic); PlayLevelSoundAction(x, y, ACTION_SHRINKING); if (Feld[newx][newy] == EL_ACID) { SplashAcid(newx, newy); return; } CreateField(newx, newy, EL_DIAGONAL_GROWING); Store[newx][newy] = EL_EMC_ANDROID; GfxElement[newx][newy] = EL_EMC_ANDROID; GfxAction[newx][newy] = ACTION_GROWING; GfxDir[newx][newy] = diagonal_move_dir; ChangeDelay[newx][newy] = change_delay; graphic = el_act_dir2img(GfxElement[newx][newy], GfxAction[newx][newy], GfxDir[newx][newy]); DrawLevelGraphicAnimation(newx, newy, graphic); PlayLevelSoundAction(newx, newy, ACTION_GROWING); return; } else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); PlayLevelSoundAction(x, y, ACTION_DIGGING); } } else if (!IS_FREE(newx, newy)) { return; } } else if (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) { if (!DigFieldByCE(newx, newy, element)) return; if (move_pattern & MV_MAZE_RUNNER_STYLE) { RunnerVisit[x][y] = FrameCounter; PlayerVisit[x][y] /= 8; /* expire player visit path */ } } else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy)) { if (!IS_FREE(newx, newy)) { if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_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_STEELWALL); int element2 = (IN_LEV_FIELD(newx2, newy2) ? MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL); if ((wanna_flame || IS_CLASSIC_ENEMY(element1) || IS_CLASSIC_ENEMY(element2)) && element1 != EL_DRAGON && element2 != EL_DRAGON && element1 != EL_FLAMES && element2 != EL_FLAMES) { ResetGfxAnimation(x, y); GfxAction[x][y] = ACTION_ATTACKING; if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else TEST_DrawLevelField(x, y); PlayLevelSound(x, y, SND_DRAGON_ATTACKING); MovDelay[x][y] = 50; Feld[newx][newy] = EL_FLAMES; if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY) Feld[newx1][newy1] = EL_FLAMES; if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY) Feld[newx2][newy2] = EL_FLAMES; return; } } } else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_DIAMOND) { if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_YAMYAM_DIGGING); } else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) && IS_FOOD_DARK_YAMYAM(Feld[newx][newy])) { if (AmoebaNr[newx][newy]) { AmoebaCnt2[AmoebaNr[newx][newy]]--; if (Feld[newx][newy] == EL_AMOEBA_FULL || Feld[newx][newy] == EL_BD_AMOEBA) AmoebaCnt[AmoebaNr[newx][newy]]--; } if (IS_MOVING(newx, newy)) { RemoveMovingField(newx, newy); } else { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING); } else if ((element == EL_PACMAN || element == EL_MOLE) && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy])) { if (AmoebaNr[newx][newy]) { AmoebaCnt2[AmoebaNr[newx][newy]]--; if (Feld[newx][newy] == EL_AMOEBA_FULL || Feld[newx][newy] == EL_BD_AMOEBA) AmoebaCnt[AmoebaNr[newx][newy]]--; } if (element == EL_MOLE) { Feld[newx][newy] = EL_AMOEBA_SHRINKING; PlayLevelSound(x, y, SND_MOLE_DIGGING); ResetGfxAnimation(x, y); GfxAction[x][y] = ACTION_DIGGING; TEST_DrawLevelField(x, y); MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */ return; /* wait for shrinking amoeba */ } else /* element == EL_PACMAN */ { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); PlayLevelSound(x, y, SND_PACMAN_DIGGING); } } else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) && (Feld[newx][newy] == EL_AMOEBA_SHRINKING || (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy]))) { /* wait for shrinking amoeba to completely disappear */ return; } else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy)) { /* object was running against a wall */ TurnRound(x, y); if (GFX_ELEMENT(element) != EL_SAND) /* !!! FIX THIS (crumble) !!! */ DrawLevelElementAnimation(x, y, element); if (DONT_TOUCH(element)) TestIfBadThingTouchesPlayer(x, y); return; } InitMovingField(x, y, MovDir[x][y]); PlayLevelSoundAction(x, y, ACTION_MOVING); } if (MovDir[x][y]) ContinueMoving(x, y); } void ContinueMoving(int x, int y) { int element = Feld[x][y]; struct ElementInfo *ei = &element_info[element]; 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 newx = x + dx, newy = y + dy; int stored = Store[x][y]; int stored_new = Store[newx][newy]; boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y)); boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y)); boolean last_line = (newy == lev_fieldy - 1); MovPos[x][y] += getElementMoveStepsize(x, y); if (pushed_by_player) /* special case: moving object pushed by player */ MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); if (ABS(MovPos[x][y]) < TILEX) { TEST_DrawLevelField(x, y); return; /* element is still moving */ } /* element reached destination field */ Feld[x][y] = EL_EMPTY; Feld[newx][newy] = element; MovPos[x][y] = 0; /* force "not moving" for "crumbled sand" */ if (Store[x][y] == EL_ACID) /* element is moving into acid pool */ { element = Feld[newx][newy] = EL_ACID; } else if (element == EL_MOLE) { Feld[x][y] = EL_SAND; TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_QUICKSAND_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; } else if (element == EL_QUICKSAND_EMPTYING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } else if (element == EL_QUICKSAND_FAST_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; } else if (element == EL_QUICKSAND_FAST_EMPTYING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } else if (element == EL_MAGIC_WALL_FILLING) { element = Feld[newx][newy] = get_next_element(element); if (!game.magic_wall_active) element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD; Store[newx][newy] = Store[x][y]; } else if (element == EL_MAGIC_WALL_EMPTYING) { Feld[x][y] = get_next_element(element); if (!game.magic_wall_active) Feld[x][y] = EL_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; InitField(newx, newy, FALSE); } else if (element == EL_BD_MAGIC_WALL_FILLING) { element = Feld[newx][newy] = get_next_element(element); if (!game.magic_wall_active) element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD; Store[newx][newy] = Store[x][y]; } else if (element == EL_BD_MAGIC_WALL_EMPTYING) { Feld[x][y] = get_next_element(element); if (!game.magic_wall_active) Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; InitField(newx, newy, FALSE); } else if (element == EL_DC_MAGIC_WALL_FILLING) { element = Feld[newx][newy] = get_next_element(element); if (!game.magic_wall_active) element = Feld[newx][newy] = EL_DC_MAGIC_WALL_DEAD; Store[newx][newy] = Store[x][y]; } else if (element == EL_DC_MAGIC_WALL_EMPTYING) { Feld[x][y] = get_next_element(element); if (!game.magic_wall_active) Feld[x][y] = EL_DC_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; InitField(newx, newy, FALSE); } else if (element == EL_AMOEBA_DROPPING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; } else if (element == EL_SOKOBAN_OBJECT) { if (Back[x][y]) Feld[x][y] = Back[x][y]; if (Back[newx][newy]) Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL; Back[x][y] = Back[newx][newy] = 0; } Store[x][y] = EL_EMPTY; MovPos[x][y] = 0; MovDir[x][y] = 0; MovDelay[x][y] = 0; MovDelay[newx][newy] = 0; if (CAN_CHANGE_OR_HAS_ACTION(element)) { /* copy element change control values to new field */ ChangeDelay[newx][newy] = ChangeDelay[x][y]; ChangePage[newx][newy] = ChangePage[x][y]; ChangeCount[newx][newy] = ChangeCount[x][y]; ChangeEvent[newx][newy] = ChangeEvent[x][y]; } CustomValue[newx][newy] = CustomValue[x][y]; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; CustomValue[x][y] = 0; /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */ GfxAction[newx][newy] = GfxAction[x][y]; /* keep action one frame */ GfxDir[newx][newy] = GfxDir[x][y]; /* keep element direction */ Pushed[x][y] = Pushed[newx][newy] = FALSE; /* some elements can leave other elements behind after moving */ if (ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) { int move_leave_element = ei->move_leave_element; /* this makes it possible to leave the removed element again */ if (ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored); Feld[x][y] = move_leave_element; if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = direction; InitField(x, y, FALSE); if (GFX_CRUMBLED(Feld[x][y])) TEST_DrawLevelFieldCrumbledNeighbours(x, y); if (ELEM_IS_PLAYER(move_leave_element)) RelocatePlayer(x, y, move_leave_element); } /* do this after checking for left-behind element */ ResetGfxAnimation(x, y); /* reset animation values for old field */ if (!CAN_MOVE(element) || (CAN_FALL(element) && direction == MV_DOWN && (element == EL_SPRING || element_info[element].move_pattern == MV_WHEN_PUSHED || element_info[element].move_pattern == MV_WHEN_DROPPED))) GfxDir[x][y] = MovDir[newx][newy] = 0; TEST_DrawLevelField(x, y); TEST_DrawLevelField(newx, newy); Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ /* prevent pushed element from moving on in pushed direction */ if (pushed_by_player && CAN_MOVE(element) && element_info[element].move_pattern & MV_ANY_DIRECTION && !(element_info[element].move_pattern & direction)) TurnRound(newx, newy); /* prevent elements on conveyor belt from moving on in last direction */ if (pushed_by_conveyor && CAN_FALL(element) && direction & MV_HORIZONTAL) MovDir[newx][newy] = 0; if (!pushed_by_player) { int nextx = newx + dx, nexty = newy + dy; boolean check_collision_again = IN_LEV_FIELD_AND_IS_FREE(nextx, nexty); WasJustMoving[newx][newy] = CHECK_DELAY_MOVING; if (CAN_FALL(element) && direction == MV_DOWN) WasJustFalling[newx][newy] = CHECK_DELAY_FALLING; if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again) CheckCollision[newx][newy] = CHECK_DELAY_COLLISION; if (CAN_FALL(element) && direction == MV_DOWN && check_collision_again) CheckImpact[newx][newy] = CHECK_DELAY_IMPACT; } if (DONT_TOUCH(element)) /* object may be nasty to player or others */ { TestIfBadThingTouchesPlayer(newx, newy); TestIfBadThingTouchesFriend(newx, newy); if (!IS_CUSTOM_ELEMENT(element)) TestIfBadThingTouchesOtherBadThing(newx, newy); } else if (element == EL_PENGUIN) TestIfFriendTouchesBadThing(newx, newy); if (DONT_GET_HIT_BY(element)) { TestIfGoodThingGetsHitByBadThing(newx, newy, direction); } /* give the player one last chance (one more frame) to move away */ if (CAN_FALL(element) && direction == MV_DOWN && (last_line || (!IS_FREE(x, newy + 1) && (!IS_PLAYER(x, newy + 1) || game.engine_version < VERSION_IDENT(3,1,1,0))))) Impact(x, newy); if (pushed_by_player && !game.use_change_when_pushing_bug) { int push_side = MV_DIR_OPPOSITE(direction); struct PlayerInfo *player = PLAYERINFO(x, y); CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER, player->index_bit, push_side); CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X, player->index_bit, push_side); } if (element == EL_EMC_ANDROID && pushed_by_player) /* make another move */ MovDelay[newx][newy] = 1; CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction); TestIfElementTouchesCustomElement(x, y); /* empty or new element */ TestIfElementHitsCustomElement(newx, newy, direction); TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY && IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element)) CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X, MV_DIR_OPPOSITE(direction)); } int AmoebeNachbarNr(int ax, int ay) { int i; int element = Feld[ax][ay]; int group_nr = 0; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int x = ax + xy[i][0]; int y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; if (Feld[x][y] == element && AmoebaNr[x][y] > 0) group_nr = AmoebaNr[x][y]; } return group_nr; } void AmoebenVereinigen(int ax, int ay) { 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 } }; if (new_group_nr == 0) return; for (i = 0; i < NUM_DIRECTIONS; i++) { x = ax + xy[i][0]; y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; if ((Feld[x][y] == EL_AMOEBA_FULL || Feld[x][y] == EL_BD_AMOEBA || Feld[x][y] == EL_AMOEBA_DEAD) && AmoebaNr[x][y] != new_group_nr) { int old_group_nr = AmoebaNr[x][y]; if (old_group_nr == 0) return; 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; SCAN_PLAYFIELD(xx, yy) { if (AmoebaNr[xx][yy] == old_group_nr) AmoebaNr[xx][yy] = new_group_nr; } } } } void AmoebeUmwandeln(int ax, int ay) { int i, x, y; if (Feld[ax][ay] == EL_AMOEBA_DEAD) { int group_nr = AmoebaNr[ax][ay]; #ifdef DEBUG if (group_nr == 0) { printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay); printf("AmoebeUmwandeln(): This should never happen!\n"); return; } #endif SCAN_PLAYFIELD(x, y) { if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr) { AmoebaNr[x][y] = 0; Feld[x][y] = EL_AMOEBA_TO_DIAMOND; } } PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ? SND_AMOEBA_TURNING_TO_GEM : SND_AMOEBA_TURNING_TO_ROCK)); Bang(ax, ay); } else { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { x = ax + xy[i][0]; y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND) { PlayLevelSound(x, y, (IS_GEM(level.amoeba_content) ? SND_AMOEBA_TURNING_TO_GEM : SND_AMOEBA_TURNING_TO_ROCK)); Bang(x, y); } } } } void AmoebeUmwandelnBD(int ax, int ay, int new_element) { int x, y; int group_nr = AmoebaNr[ax][ay]; boolean done = FALSE; #ifdef DEBUG if (group_nr == 0) { printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay); printf("AmoebeUmwandelnBD(): This should never happen!\n"); return; } #endif SCAN_PLAYFIELD(x, y) { if (AmoebaNr[x][y] == group_nr && (Feld[x][y] == EL_AMOEBA_DEAD || Feld[x][y] == EL_BD_AMOEBA || Feld[x][y] == EL_AMOEBA_GROWING)) { AmoebaNr[x][y] = 0; Feld[x][y] = new_element; InitField(x, y, FALSE); TEST_DrawLevelField(x, y); done = TRUE; } } if (done) PlayLevelSound(ax, ay, (new_element == EL_BD_ROCK ? SND_BD_AMOEBA_TURNING_TO_ROCK : SND_BD_AMOEBA_TURNING_TO_GEM)); } void AmoebeWaechst(int x, int y) { static unsigned int sound_delay = 0; static unsigned int sound_delay_value = 0; if (!MovDelay[x][y]) /* start new growing cycle */ { MovDelay[x][y] = 7; if (DelayReached(&sound_delay, sound_delay_value)) { PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING); sound_delay_value = 30; } } if (MovDelay[x][y]) /* wait some time before growing bigger */ { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING, 6 - MovDelay[x][y]); DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame); } if (!MovDelay[x][y]) { Feld[x][y] = Store[x][y]; Store[x][y] = 0; TEST_DrawLevelField(x, y); } } } void AmoebaDisappearing(int x, int y) { static unsigned int sound_delay = 0; static unsigned int sound_delay_value = 0; if (!MovDelay[x][y]) /* start new shrinking cycle */ { MovDelay[x][y] = 7; if (DelayReached(&sound_delay, sound_delay_value)) sound_delay_value = 30; } if (MovDelay[x][y]) /* wait some time before shrinking */ { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING, 6 - MovDelay[x][y]); DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame); } if (!MovDelay[x][y]) { Feld[x][y] = EL_EMPTY; TEST_DrawLevelField(x, y); /* don't let mole enter this field in this cycle; (give priority to objects falling to this field from above) */ Stop[x][y] = TRUE; } } } void AmoebeAbleger(int ax, int ay) { int i; int element = Feld[ax][ay]; int graphic = el2img(element); int newax = ax, neway = ay; boolean can_drop = (element == EL_AMOEBA_WET || element == EL_EMC_DRIPPER); static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (!level.amoeba_speed && element != EL_EMC_DRIPPER) { Feld[ax][ay] = EL_AMOEBA_DEAD; TEST_DrawLevelField(ax, ay); return; } if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (!MovDelay[ax][ay]) /* start making new amoeba field */ MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed)); if (MovDelay[ax][ay]) /* wait some time before making new amoeba */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } if (can_drop) /* EL_AMOEBA_WET or EL_EMC_DRIPPER */ { int start = RND(4); int x = ax + xy[start][0]; int y = ay + xy[start][1]; if (!IN_LEV_FIELD(x, y)) return; if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || Feld[x][y] == EL_QUICKSAND_EMPTY || Feld[x][y] == EL_QUICKSAND_FAST_EMPTY) { newax = x; neway = y; } if (newax == ax && neway == ay) return; } else /* normal or "filled" (BD style) amoeba */ { int start = RND(4); boolean waiting_for_player = FALSE; for (i = 0; i < NUM_DIRECTIONS; i++) { int j = (start + i) % 4; int x = ax + xy[j][0]; int y = ay + xy[j][1]; if (!IN_LEV_FIELD(x, y)) continue; if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || Feld[x][y] == EL_QUICKSAND_EMPTY || Feld[x][y] == EL_QUICKSAND_FAST_EMPTY) { newax = x; neway = y; break; } else if (IS_PLAYER(x, y)) waiting_for_player = TRUE; } if (newax == ax && neway == ay) /* amoeba cannot grow */ { if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA)) { Feld[ax][ay] = EL_AMOEBA_DEAD; TEST_DrawLevelField(ax, ay); AmoebaCnt[AmoebaNr[ax][ay]]--; if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */ { if (element == EL_AMOEBA_FULL) AmoebeUmwandeln(ax, ay); else if (element == EL_BD_AMOEBA) AmoebeUmwandelnBD(ax, ay, level.amoeba_content); } } return; } else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA) { /* amoeba gets larger by growing in some direction */ int new_group_nr = AmoebaNr[ax][ay]; #ifdef DEBUG if (new_group_nr == 0) { printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway); printf("AmoebeAbleger(): This should never happen!\n"); return; } #endif AmoebaNr[newax][neway] = new_group_nr; AmoebaCnt[new_group_nr]++; AmoebaCnt2[new_group_nr]++; /* if amoeba touches other amoeba(s) after growing, unify them */ AmoebenVereinigen(newax, neway); if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200) { AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK); return; } } } if (!can_drop || neway < ay || !IS_FREE(newax, neway) || (neway == lev_fieldy - 1 && newax != ax)) { Feld[newax][neway] = EL_AMOEBA_GROWING; /* creation of new amoeba */ Store[newax][neway] = element; } else if (neway == ay || element == EL_EMC_DRIPPER) { Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */ PlayLevelSoundAction(newax, neway, ACTION_GROWING); } else { InitMovingField(ax, ay, MV_DOWN); /* drop dripping from amoeba */ Feld[ax][ay] = EL_AMOEBA_DROPPING; Store[ax][ay] = EL_AMOEBA_DROP; ContinueMoving(ax, ay); return; } TEST_DrawLevelField(newax, neway); } void Life(int ax, int ay) { int x1, y1, x2, y2; int life_time = 40; int element = Feld[ax][ay]; int graphic = el2img(element); int *life_parameter = (element == EL_GAME_OF_LIFE ? level.game_of_life : level.biomaze); boolean changed = FALSE; if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (Stop[ax][ay]) return; if (!MovDelay[ax][ay]) /* start new "game of life" cycle */ MovDelay[ax][ay] = life_time; if (MovDelay[ax][ay]) /* wait some time before next cycle */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++) { int xx = ax+x1, yy = ay+y1; int nachbarn = 0; if (!IN_LEV_FIELD(xx, yy)) continue; for (y2 = -1; y2 < 2; y2++) for (x2 = -1; x2 < 2; x2++) { int x = xx+x2, y = yy+y2; if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy)) continue; if (((Feld[x][y] == element || (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) && !Stop[x][y]) || (IS_FREE(x, y) && Stop[x][y])) nachbarn++; } if (xx == ax && yy == ay) /* field in the middle */ { if (nachbarn < life_parameter[0] || nachbarn > life_parameter[1]) { Feld[xx][yy] = EL_EMPTY; if (!Stop[xx][yy]) TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } } else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy])) { /* free border field */ if (nachbarn >= life_parameter[2] && nachbarn <= life_parameter[3]) { Feld[xx][yy] = element; MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1); if (!Stop[xx][yy]) TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } } } if (changed) PlayLevelSound(ax, ay, element == EL_BIOMAZE ? SND_BIOMAZE_GROWING : SND_GAME_OF_LIFE_GROWING); } static void InitRobotWheel(int x, int y) { ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND; } static void RunRobotWheel(int x, int y) { PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE); } static void StopRobotWheel(int x, int y) { if (ZX == x && ZY == y) { ZX = ZY = -1; game.robot_wheel_active = FALSE; } } static void InitTimegateWheel(int x, int y) { ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND; } static void RunTimegateWheel(int x, int y) { PlayLevelSound(x, y, SND_CLASS_TIMEGATE_SWITCH_ACTIVE); } static void InitMagicBallDelay(int x, int y) { ChangeDelay[x][y] = (level.ball_time + 1) * 8 + 1; } static void ActivateMagicBall(int bx, int by) { int x, y; if (level.ball_random) { int pos_border = RND(8); /* select one of the eight border elements */ int pos_content = (pos_border > 3 ? pos_border + 1 : pos_border); int xx = pos_content % 3; int yy = pos_content / 3; x = bx - 1 + xx; y = by - 1 + yy; if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY) CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]); } else { for (y = by - 1; y <= by + 1; y++) for (x = bx - 1; x <= bx + 1; x++) { int xx = x - bx + 1; int yy = y - by + 1; if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY) CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]); } } game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents; } void CheckExit(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING); } void CheckExitEM(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_EM_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_EM_EXIT_OPENING); } void CheckExitSteel(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_STEEL_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_STEEL_EXIT_OPENING); } void CheckExitSteelEM(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_EM_STEEL_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_EM_STEEL_EXIT_OPENING); } void CheckExitSP(int x, int y) { if (local_player->gems_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); return; } if (AllPlayersGone) /* do not re-open exit door closed after last player */ return; Feld[x][y] = EL_SP_EXIT_OPENING; PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING); } static void CloseAllOpenTimegates() { int x, y; SCAN_PLAYFIELD(x, y) { int element = Feld[x][y]; if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING) { Feld[x][y] = EL_TIMEGATE_CLOSING; PlayLevelSoundAction(x, y, ACTION_CLOSING); } } } void DrawTwinkleOnField(int x, int y) { if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y)) return; if (Feld[x][y] == EL_BD_DIAMOND) return; if (MovDelay[x][y] == 0) /* next animation frame */ MovDelay[x][y] = 11 * !GetSimpleRandom(500); if (MovDelay[x][y] != 0) /* wait some time before next frame */ { MovDelay[x][y]--; DrawLevelElementAnimation(x, y, Feld[x][y]); if (MovDelay[x][y] != 0) { int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE, 10 - MovDelay[x][y]); DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame); } } } void MauerWaechst(int x, int y) { int delay = 6; if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 3 * delay; if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int graphic = el_dir2img(Feld[x][y], GfxDir[x][y]); int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]); DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); } if (!MovDelay[x][y]) { if (MovDir[x][y] == MV_LEFT) { if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y])) TEST_DrawLevelField(x - 1, y); } else if (MovDir[x][y] == MV_RIGHT) { if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y])) TEST_DrawLevelField(x + 1, y); } else if (MovDir[x][y] == MV_UP) { if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1])) TEST_DrawLevelField(x, y - 1); } else { if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1])) TEST_DrawLevelField(x, y + 1); } Feld[x][y] = Store[x][y]; Store[x][y] = 0; GfxDir[x][y] = MovDir[x][y] = MV_NONE; TEST_DrawLevelField(x, y); } } } void MauerAbleger(int ax, int ay) { int element = Feld[ax][ay]; int graphic = el2img(element); boolean oben_frei = FALSE, unten_frei = FALSE; boolean links_frei = FALSE, rechts_frei = FALSE; boolean oben_massiv = FALSE, unten_massiv = FALSE; boolean links_massiv = FALSE, rechts_massiv = FALSE; boolean new_wall = FALSE; if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (!MovDelay[ax][ay]) /* start building new wall */ MovDelay[ax][ay] = 6; if (MovDelay[ax][ay]) /* wait some time before building new wall */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1)) oben_frei = TRUE; if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1)) unten_frei = TRUE; if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay)) links_frei = TRUE; if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay)) rechts_frei = TRUE; if (element == EL_EXPANDABLE_WALL_VERTICAL || element == EL_EXPANDABLE_WALL_ANY) { if (oben_frei) { Feld[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING; Store[ax][ay-1] = element; GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1))) DrawGraphic(SCREENX(ax), SCREENY(ay - 1), IMG_EXPANDABLE_WALL_GROWING_UP, 0); new_wall = TRUE; } if (unten_frei) { Feld[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING; Store[ax][ay+1] = element; GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1))) DrawGraphic(SCREENX(ax), SCREENY(ay + 1), IMG_EXPANDABLE_WALL_GROWING_DOWN, 0); new_wall = TRUE; } } if (element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_ANY || element == EL_EXPANDABLE_WALL || element == EL_BD_EXPANDABLE_WALL) { if (links_frei) { Feld[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING; Store[ax-1][ay] = element; GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT; if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay))) DrawGraphic(SCREENX(ax - 1), SCREENY(ay), IMG_EXPANDABLE_WALL_GROWING_LEFT, 0); new_wall = TRUE; } if (rechts_frei) { Feld[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING; Store[ax+1][ay] = element; GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT; if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay))) DrawGraphic(SCREENX(ax + 1), SCREENY(ay), IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0); new_wall = TRUE; } } if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei)) TEST_DrawLevelField(ax, ay); if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1])) oben_massiv = TRUE; if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1])) unten_massiv = TRUE; if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay])) links_massiv = TRUE; if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay])) rechts_massiv = TRUE; if (((oben_massiv && unten_massiv) || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL) && ((links_massiv && rechts_massiv) || element == EL_EXPANDABLE_WALL_VERTICAL)) Feld[ax][ay] = EL_WALL; if (new_wall) PlayLevelSoundAction(ax, ay, ACTION_GROWING); } void MauerAblegerStahl(int ax, int ay) { int element = Feld[ax][ay]; int graphic = el2img(element); boolean oben_frei = FALSE, unten_frei = FALSE; boolean links_frei = FALSE, rechts_frei = FALSE; boolean oben_massiv = FALSE, unten_massiv = FALSE; boolean links_massiv = FALSE, rechts_massiv = FALSE; boolean new_wall = FALSE; if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); if (!MovDelay[ax][ay]) /* start building new wall */ MovDelay[ax][ay] = 6; if (MovDelay[ax][ay]) /* wait some time before building new wall */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1)) oben_frei = TRUE; if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1)) unten_frei = TRUE; if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay)) links_frei = TRUE; if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay)) rechts_frei = TRUE; if (element == EL_EXPANDABLE_STEELWALL_VERTICAL || element == EL_EXPANDABLE_STEELWALL_ANY) { if (oben_frei) { Feld[ax][ay-1] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax][ay-1] = element; GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1))) DrawGraphic(SCREENX(ax), SCREENY(ay - 1), IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0); new_wall = TRUE; } if (unten_frei) { Feld[ax][ay+1] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax][ay+1] = element; GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN; if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1))) DrawGraphic(SCREENX(ax), SCREENY(ay + 1), IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0); new_wall = TRUE; } } if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || element == EL_EXPANDABLE_STEELWALL_ANY) { if (links_frei) { Feld[ax-1][ay] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax-1][ay] = element; GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT; if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay))) DrawGraphic(SCREENX(ax - 1), SCREENY(ay), IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0); new_wall = TRUE; } if (rechts_frei) { Feld[ax+1][ay] = EL_EXPANDABLE_STEELWALL_GROWING; Store[ax+1][ay] = element; GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT; if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay))) DrawGraphic(SCREENX(ax + 1), SCREENY(ay), IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0); new_wall = TRUE; } } if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1])) oben_massiv = TRUE; if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1])) unten_massiv = TRUE; if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay])) links_massiv = TRUE; if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay])) rechts_massiv = TRUE; if (((oben_massiv && unten_massiv) || element == EL_EXPANDABLE_STEELWALL_HORIZONTAL) && ((links_massiv && rechts_massiv) || element == EL_EXPANDABLE_STEELWALL_VERTICAL)) Feld[ax][ay] = EL_STEELWALL; if (new_wall) PlayLevelSoundAction(ax, ay, ACTION_GROWING); } void CheckForDragon(int x, int y) { int i, j; boolean dragon_found = FALSE; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { for (j = 0; j < 4; j++) { int xx = x + j * xy[i][0], yy = y + j * xy[i][1]; if (IN_LEV_FIELD(xx, yy) && (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON)) { if (Feld[xx][yy] == EL_DRAGON) dragon_found = TRUE; } else break; } } if (!dragon_found) { for (i = 0; i < NUM_DIRECTIONS; i++) { for (j = 0; j < 3; j++) { int xx = x + j * xy[i][0], yy = y + j * xy[i][1]; if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES) { Feld[xx][yy] = EL_EMPTY; TEST_DrawLevelField(xx, yy); } else break; } } } } static void InitBuggyBase(int x, int y) { int element = Feld[x][y]; int activating_delay = FRAMES_PER_SECOND / 4; ChangeDelay[x][y] = (element == EL_SP_BUGGY_BASE ? 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay : element == EL_SP_BUGGY_BASE_ACTIVATING ? activating_delay : element == EL_SP_BUGGY_BASE_ACTIVE ? 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1); } static void WarnBuggyBase(int x, int y) { int i; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy)) { PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE); break; } } } static void InitTrap(int x, int y) { ChangeDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); } static void ActivateTrap(int x, int y) { PlayLevelSound(x, y, SND_TRAP_ACTIVATING); } static void ChangeActiveTrap(int x, int y) { int graphic = IMG_TRAP_ACTIVE; /* if new animation frame was drawn, correct crumbled sand border */ if (IS_NEW_FRAME(GfxFrame[x][y], graphic)) TEST_DrawLevelFieldCrumbled(x, y); } static int getSpecialActionElement(int element, int number, int base_element) { return (element != EL_EMPTY ? element : number != -1 ? base_element + number - 1 : EL_EMPTY); } static int getModifiedActionNumber(int value_old, int operator, int operand, int value_min, int value_max) { int value_new = (operator == CA_MODE_SET ? operand : operator == CA_MODE_ADD ? value_old + operand : operator == CA_MODE_SUBTRACT ? value_old - operand : operator == CA_MODE_MULTIPLY ? value_old * operand : operator == CA_MODE_DIVIDE ? value_old / MAX(1, operand) : operator == CA_MODE_MODULO ? value_old % MAX(1, operand) : value_old); return (value_new < value_min ? value_min : value_new > value_max ? value_max : value_new); } static void ExecuteCustomElementAction(int x, int y, int element, int page) { struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; int target_element = change->target_element; int action_type = change->action_type; int action_mode = change->action_mode; int action_arg = change->action_arg; int action_element = change->action_element; int i; if (!change->has_action) return; /* ---------- determine action paramater values -------------------------- */ int level_time_value = (level.time > 0 ? TimeLeft : TimePlayed); int action_arg_element_raw = (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player : action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element : action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_ACTION ? change->action_element : action_arg == CA_ARG_INVENTORY_RM_TRIGGER ? change->actual_trigger_element: action_arg == CA_ARG_INVENTORY_RM_TARGET ? change->target_element : action_arg == CA_ARG_INVENTORY_RM_ACTION ? change->action_element : EL_EMPTY); int action_arg_element = GetElementFromGroupElement(action_arg_element_raw); int action_arg_direction = (action_arg >= CA_ARG_DIRECTION_LEFT && action_arg <= CA_ARG_DIRECTION_DOWN ? action_arg - CA_ARG_DIRECTION : action_arg == CA_ARG_DIRECTION_TRIGGER ? change->actual_trigger_side : action_arg == CA_ARG_DIRECTION_TRIGGER_BACK ? MV_DIR_OPPOSITE(change->actual_trigger_side) : MV_NONE); int action_arg_number_min = (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_NOT_MOVING : CA_ARG_MIN); int action_arg_number_max = (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_EVEN_FASTER : action_type == CA_SET_LEVEL_GEMS ? 999 : action_type == CA_SET_LEVEL_TIME ? 9999 : action_type == CA_SET_LEVEL_SCORE ? 99999 : action_type == CA_SET_CE_VALUE ? 9999 : action_type == CA_SET_CE_SCORE ? 9999 : CA_ARG_MAX); int action_arg_number_reset = (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize[0] : action_type == CA_SET_LEVEL_GEMS ? level.gems_needed : action_type == CA_SET_LEVEL_TIME ? level.time : action_type == CA_SET_LEVEL_SCORE ? 0 : action_type == CA_SET_CE_VALUE ? GET_NEW_CE_VALUE(element) : action_type == CA_SET_CE_SCORE ? 0 : 0); int action_arg_number = (action_arg <= CA_ARG_MAX ? action_arg : action_arg >= CA_ARG_SPEED_NOT_MOVING && action_arg <= CA_ARG_SPEED_EVEN_FASTER ? (action_arg - CA_ARG_SPEED) : action_arg == CA_ARG_SPEED_RESET ? action_arg_number_reset : action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min : action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max : action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset : action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] : action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) : action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value : action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed : action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CE_VALUE(target_element): action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value: action_arg == CA_ARG_ELEMENT_CV_ACTION ? GET_NEW_CE_VALUE(action_element): action_arg == CA_ARG_ELEMENT_CS_TARGET ? GET_CE_SCORE(target_element) : action_arg == CA_ARG_ELEMENT_CS_TRIGGER ? change->actual_trigger_ce_score: action_arg == CA_ARG_ELEMENT_CS_ACTION ? GET_CE_SCORE(action_element) : action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element : action_arg == CA_ARG_ELEMENT_NR_ACTION ? change->action_element : -1); int action_arg_number_old = (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed : action_type == CA_SET_LEVEL_TIME ? TimeLeft : action_type == CA_SET_LEVEL_SCORE ? local_player->score : action_type == CA_SET_CE_VALUE ? CustomValue[x][y] : action_type == CA_SET_CE_SCORE ? ei->collect_score : 0); int action_arg_number_new = getModifiedActionNumber(action_arg_number_old, action_mode, action_arg_number, action_arg_number_min, action_arg_number_max); int trigger_player_bits = (change->actual_trigger_player_bits != CH_PLAYER_NONE ? change->actual_trigger_player_bits : change->trigger_player); int action_arg_player_bits = (action_arg >= CA_ARG_PLAYER_1 && action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER : action_arg == CA_ARG_PLAYER_TRIGGER ? trigger_player_bits : action_arg == CA_ARG_PLAYER_ACTION ? 1 << GET_PLAYER_NR(action_element) : PLAYER_BITS_ANY); /* ---------- execute action -------------------------------------------- */ switch (action_type) { case CA_NO_ACTION: { return; } /* ---------- level actions ------------------------------------------- */ case CA_RESTART_LEVEL: { game.restart_level = TRUE; break; } case CA_SHOW_ENVELOPE: { int element = getSpecialActionElement(action_arg_element, action_arg_number, EL_ENVELOPE_1); if (IS_ENVELOPE(element)) local_player->show_envelope = element; break; } case CA_SET_LEVEL_TIME: { if (level.time > 0) /* only modify limited time value */ { TimeLeft = action_arg_number_new; game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } break; } case CA_SET_LEVEL_SCORE: { local_player->score = action_arg_number_new; game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); break; } case CA_SET_LEVEL_GEMS: { local_player->gems_still_needed = action_arg_number_new; game.snapshot.collected_item = TRUE; game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); break; } case CA_SET_LEVEL_WIND: { game.wind_direction = action_arg_direction; break; } case CA_SET_LEVEL_RANDOM_SEED: { /* ensure that setting a new random seed while playing is predictable */ InitRND(action_arg_number_new ? action_arg_number_new : RND(1000000) + 1); break; } /* ---------- player actions ------------------------------------------ */ case CA_MOVE_PLAYER: { /* automatically move to the next field in specified direction */ for (i = 0; i < MAX_PLAYERS; i++) if (trigger_player_bits & (1 << i)) stored_player[i].programmed_action = action_arg_direction; break; } case CA_EXIT_PLAYER: { for (i = 0; i < MAX_PLAYERS; i++) if (action_arg_player_bits & (1 << i)) PlayerWins(&stored_player[i]); break; } case CA_KILL_PLAYER: { for (i = 0; i < MAX_PLAYERS; i++) if (action_arg_player_bits & (1 << i)) KillPlayer(&stored_player[i]); break; } case CA_SET_PLAYER_KEYS: { int key_state = (action_mode == CA_MODE_ADD ? TRUE : FALSE); int element = getSpecialActionElement(action_arg_element, action_arg_number, EL_KEY_1); if (IS_KEY(element)) { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { stored_player[i].key[KEY_NR(element)] = key_state; DrawGameDoorValues(); } } } break; } case CA_SET_PLAYER_SPEED: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { int move_stepsize = TILEX / stored_player[i].move_delay_value; if (action_arg == CA_ARG_SPEED_FASTER && stored_player[i].cannot_move) { action_arg_number = STEPSIZE_VERY_SLOW; } else if (action_arg == CA_ARG_SPEED_SLOWER || action_arg == CA_ARG_SPEED_FASTER) { action_arg_number = 2; action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE : CA_MODE_MULTIPLY); } else if (action_arg == CA_ARG_NUMBER_RESET) { action_arg_number = level.initial_player_stepsize[i]; } move_stepsize = getModifiedActionNumber(move_stepsize, action_mode, action_arg_number, action_arg_number_min, action_arg_number_max); SetPlayerMoveSpeed(&stored_player[i], move_stepsize, FALSE); } } break; } case CA_SET_PLAYER_SHIELD: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { if (action_arg == CA_ARG_SHIELD_OFF) { stored_player[i].shield_normal_time_left = 0; stored_player[i].shield_deadly_time_left = 0; } else if (action_arg == CA_ARG_SHIELD_NORMAL) { stored_player[i].shield_normal_time_left = 999999; } else if (action_arg == CA_ARG_SHIELD_DEADLY) { stored_player[i].shield_normal_time_left = 999999; stored_player[i].shield_deadly_time_left = 999999; } } } break; } case CA_SET_PLAYER_GRAVITY: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { stored_player[i].gravity = (action_arg == CA_ARG_GRAVITY_OFF ? FALSE : action_arg == CA_ARG_GRAVITY_ON ? TRUE : action_arg == CA_ARG_GRAVITY_TOGGLE ? !stored_player[i].gravity : stored_player[i].gravity); } } break; } case CA_SET_PLAYER_ARTWORK: { for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) { int artwork_element = action_arg_element; if (action_arg == CA_ARG_ELEMENT_RESET) artwork_element = (level.use_artwork_element[i] ? level.artwork_element[i] : stored_player[i].element_nr); if (stored_player[i].artwork_element != artwork_element) stored_player[i].Frame = 0; stored_player[i].artwork_element = artwork_element; SetPlayerWaiting(&stored_player[i], FALSE); /* set number of special actions for bored and sleeping animation */ stored_player[i].num_special_action_bored = get_num_special_action(artwork_element, ACTION_BORING_1, ACTION_BORING_LAST); stored_player[i].num_special_action_sleeping = get_num_special_action(artwork_element, ACTION_SLEEPING_1, ACTION_SLEEPING_LAST); } } break; } case CA_SET_PLAYER_INVENTORY: { for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int j, k; if (trigger_player_bits & (1 << i)) { int inventory_element = action_arg_element; if (action_arg == CA_ARG_ELEMENT_TARGET || action_arg == CA_ARG_ELEMENT_TRIGGER || action_arg == CA_ARG_ELEMENT_ACTION) { int element = inventory_element; int collect_count = element_info[element].collect_count_initial; if (!IS_CUSTOM_ELEMENT(element)) collect_count = 1; if (collect_count == 0) player->inventory_infinite_element = element; else for (k = 0; k < collect_count; k++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; } else if (action_arg == CA_ARG_INVENTORY_RM_TARGET || action_arg == CA_ARG_INVENTORY_RM_TRIGGER || action_arg == CA_ARG_INVENTORY_RM_ACTION) { if (player->inventory_infinite_element != EL_UNDEFINED && IS_EQUAL_OR_IN_GROUP(player->inventory_infinite_element, action_arg_element_raw)) player->inventory_infinite_element = EL_UNDEFINED; for (k = 0, j = 0; j < player->inventory_size; j++) { if (!IS_EQUAL_OR_IN_GROUP(player->inventory_element[j], action_arg_element_raw)) player->inventory_element[k++] = player->inventory_element[j]; } player->inventory_size = k; } else if (action_arg == CA_ARG_INVENTORY_RM_FIRST) { if (player->inventory_size > 0) { for (j = 0; j < player->inventory_size - 1; j++) player->inventory_element[j] = player->inventory_element[j + 1]; player->inventory_size--; } } else if (action_arg == CA_ARG_INVENTORY_RM_LAST) { if (player->inventory_size > 0) player->inventory_size--; } else if (action_arg == CA_ARG_INVENTORY_RM_ALL) { player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; } else if (action_arg == CA_ARG_INVENTORY_RESET) { player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; if (level.use_initial_inventory[i]) { for (j = 0; j < level.initial_inventory_size[i]; j++) { int element = level.initial_inventory_content[i][j]; int collect_count = element_info[element].collect_count_initial; if (!IS_CUSTOM_ELEMENT(element)) collect_count = 1; if (collect_count == 0) player->inventory_infinite_element = element; else for (k = 0; k < collect_count; k++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; } } } } } break; } /* ---------- CE actions ---------------------------------------------- */ case CA_SET_CE_VALUE: { int last_ce_value = CustomValue[x][y]; CustomValue[x][y] = action_arg_number_new; if (CustomValue[x][y] != last_ce_value) { CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_CHANGES); CheckTriggeredElementChange(x, y, element, CE_VALUE_CHANGES_OF_X); if (CustomValue[x][y] == 0) { CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); } } break; } case CA_SET_CE_SCORE: { int last_ce_score = ei->collect_score; ei->collect_score = action_arg_number_new; if (ei->collect_score != last_ce_score) { CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_CHANGES); CheckTriggeredElementChange(x, y, element, CE_SCORE_CHANGES_OF_X); if (ei->collect_score == 0) { int xx, yy; CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_SCORE_GETS_ZERO_OF_X); /* This is a very special case that seems to be a mixture between CheckElementChange() and CheckTriggeredElementChange(): while the first one only affects single elements that are triggered directly, the second one affects multiple elements in the playfield that are triggered indirectly by another element. This is a third case: Changing the CE score always affects multiple identical CEs, so every affected CE must be checked, not only the single CE for which the CE score was changed in the first place (as every instance of that CE shares the same CE score, and therefore also can change)! */ SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == element) CheckElementChange(xx, yy, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO); } } } break; } case CA_SET_CE_ARTWORK: { int artwork_element = action_arg_element; boolean reset_frame = FALSE; int xx, yy; if (action_arg == CA_ARG_ELEMENT_RESET) artwork_element = (ei->use_gfx_element ? ei->gfx_element_initial : element); if (ei->gfx_element != artwork_element) reset_frame = TRUE; ei->gfx_element = artwork_element; SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == element) { if (reset_frame) { ResetGfxAnimation(xx, yy); ResetRandomAnimationValue(xx, yy); } TEST_DrawLevelField(xx, yy); } } break; } /* ---------- engine actions ------------------------------------------ */ case CA_SET_ENGINE_SCAN_MODE: { InitPlayfieldScanMode(action_arg); break; } default: break; } } static void CreateFieldExt(int x, int y, int element, boolean is_change) { int old_element = Feld[x][y]; int new_element = GetElementFromGroupElement(element); int previous_move_direction = MovDir[x][y]; int last_ce_value = CustomValue[x][y]; boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y); boolean new_element_is_player = ELEM_IS_PLAYER(new_element); boolean add_player_onto_element = (new_element_is_player && new_element != EL_SOKOBAN_FIELD_PLAYER && IS_WALKABLE(old_element)); if (!add_player_onto_element) { if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) RemoveMovingField(x, y); else RemoveField(x, y); Feld[x][y] = new_element; if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = previous_move_direction; if (element_info[new_element].use_last_ce_value) CustomValue[x][y] = last_ce_value; InitField_WithBug1(x, y, FALSE); new_element = Feld[x][y]; /* element may have changed */ ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); TEST_DrawLevelField(x, y); if (GFX_CRUMBLED(new_element)) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } /* check if element under the player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ /* (must be checked after creating new element for walkable group elements) */ if (IS_PLAYER(x, y) && !player_explosion_protected && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { Bang(x, y); return; } /* "ChangeCount" not set yet to allow "entered by player" change one time */ if (new_element_is_player) RelocatePlayer(x, y, new_element); if (is_change) ChangeCount[x][y]++; /* count number of changes in the same frame */ TestIfBadThingTouchesPlayer(x, y); TestIfPlayerTouchesCustomElement(x, y); TestIfElementTouchesCustomElement(x, y); } static void CreateField(int x, int y, int element) { CreateFieldExt(x, y, element, FALSE); } static void CreateElementFromChange(int x, int y, int element) { element = GET_VALID_RUNTIME_ELEMENT(element); if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { int old_element = Feld[x][y]; /* prevent changed element from moving in same engine frame unless both old and new element can either fall or move */ if ((!CAN_FALL(old_element) || !CAN_FALL(element)) && (!CAN_MOVE(old_element) || !CAN_MOVE(element))) Stop[x][y] = TRUE; } CreateFieldExt(x, y, element, TRUE); } static boolean ChangeElement(int x, int y, int element, int page) { struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; int ce_value = CustomValue[x][y]; int ce_score = ei->collect_score; int target_element; int old_element = Feld[x][y]; /* always use default change event to prevent running into a loop */ if (ChangeEvent[x][y] == -1) ChangeEvent[x][y] = CE_DELAY; if (ChangeEvent[x][y] == CE_DELAY) { /* reset actual trigger element, trigger player and action element */ change->actual_trigger_element = EL_EMPTY; change->actual_trigger_player = EL_EMPTY; change->actual_trigger_player_bits = CH_PLAYER_NONE; change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; } /* do not change elements more than a specified maximum number of changes */ if (ChangeCount[x][y] >= game.max_num_changes_per_frame) return FALSE; ChangeCount[x][y]++; /* count number of changes in the same frame */ if (change->explode) { Bang(x, y); return TRUE; } if (change->use_target_content) { boolean complete_replace = TRUE; boolean can_replace[3][3]; int xx, yy; for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++) { boolean is_empty; boolean is_walkable; boolean is_diggable; boolean is_collectible; boolean is_removable; boolean is_destructible; int ex = x + xx - 1; int ey = y + yy - 1; int content_element = change->target_content.e[xx][yy]; int e; can_replace[xx][yy] = TRUE; if (ex == x && ey == y) /* do not check changing element itself */ continue; if (content_element == EL_EMPTY_SPACE) { can_replace[xx][yy] = FALSE; /* do not replace border with space */ continue; } if (!IN_LEV_FIELD(ex, ey)) { can_replace[xx][yy] = FALSE; complete_replace = FALSE; continue; } e = Feld[ex][ey]; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) e = MovingOrBlocked2Element(ex, ey); is_empty = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element))); is_walkable = (is_empty || IS_WALKABLE(e)); is_diggable = (is_empty || IS_DIGGABLE(e)); is_collectible = (is_empty || IS_COLLECTIBLE(e)); is_destructible = (is_empty || !IS_INDESTRUCTIBLE(e)); is_removable = (is_diggable || is_collectible); can_replace[xx][yy] = (((change->replace_when == CP_WHEN_EMPTY && is_empty) || (change->replace_when == CP_WHEN_WALKABLE && is_walkable) || (change->replace_when == CP_WHEN_DIGGABLE && is_diggable) || (change->replace_when == CP_WHEN_COLLECTIBLE && is_collectible) || (change->replace_when == CP_WHEN_REMOVABLE && is_removable) || (change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) && !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element))); if (!can_replace[xx][yy]) complete_replace = FALSE; } if (!change->only_if_complete || complete_replace) { boolean something_has_changed = FALSE; if (change->only_if_complete && change->use_random_replace && RND(100) < change->random_percentage) return FALSE; for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++) { int ex = x + xx - 1; int ey = y + yy - 1; int content_element; if (can_replace[xx][yy] && (!change->use_random_replace || RND(100) < change->random_percentage)) { if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) RemoveMovingField(ex, ey); ChangeEvent[ex][ey] = ChangeEvent[x][y]; content_element = change->target_content.e[xx][yy]; target_element = GET_TARGET_ELEMENT(element, content_element, change, ce_value, ce_score); CreateElementFromChange(ex, ey, target_element); something_has_changed = TRUE; /* for symmetry reasons, freeze newly created border elements */ if (ex != x || ey != y) Stop[ex][ey] = TRUE; /* no more moving in this frame */ } } if (something_has_changed) { PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page); } } } else { target_element = GET_TARGET_ELEMENT(element, change->target_element, change, ce_value, ce_score); if (element == EL_DIAGONAL_GROWING || element == EL_DIAGONAL_SHRINKING) { target_element = Store[x][y]; Store[x][y] = EL_EMPTY; } CreateElementFromChange(x, y, target_element); PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page); } /* this uses direct change before indirect change */ CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page); return TRUE; } static void HandleElementChange(int x, int y, int page) { int element = MovingOrBlocked2Element(x, y); struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; boolean handle_action_before_change = FALSE; #ifdef DEBUG if (!CAN_CHANGE_OR_HAS_ACTION(element) && !CAN_CHANGE_OR_HAS_ACTION(Back[x][y])) { printf("\n\n"); printf("HandleElementChange(): %d,%d: element = %d ('%s')\n", x, y, element, element_info[element].token_name); printf("HandleElementChange(): This should never happen!\n"); printf("\n\n"); } #endif /* this can happen with classic bombs on walkable, changing elements */ if (!CAN_CHANGE_OR_HAS_ACTION(element)) { return; } if (ChangeDelay[x][y] == 0) /* initialize element change */ { ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; if (change->can_change) { /* !!! not clear why graphic animation should be reset at all here !!! */ /* !!! UPDATE: but is needed for correct Snake Bite tail animation !!! */ /* !!! SOLUTION: do not reset if graphics engine set to 4 or above !!! */ /* GRAPHICAL BUG ADDRESSED BY CHECKING GRAPHICS ENGINE VERSION: When using an animation frame delay of 1 (this only happens with "sp_zonk.moving.left/right" in the classic graphics), the default (non-moving) animation shows wrong animation frames (while the moving animation, like "sp_zonk.moving.left/right", is correct, so this graphical bug never shows up with the classic graphics). For an animation with 4 frames, this causes wrong frames 0,0,1,2 be drawn instead of the correct frames 0,1,2,3. This is caused by "GfxFrame[][]" being reset *twice* (in two successive frames) after an element change: First when the change delay ("ChangeDelay[][]") counter has reached zero after decrementing, then a second time in the next frame (after "GfxFrame[][]" was already incremented) when "ChangeDelay[][]" is reset to the initial delay value again. This causes frame 0 to be drawn twice, while the last frame won't be drawn anymore, resulting in the wrong frame sequence 0,0,1,2. As some animations may already be cleverly designed around this bug (at least the "Snake Bite" snake tail animation does this), it cannot simply be fixed here without breaking such existing animations. Unfortunately, it cannot easily be detected if a graphics set was designed "before" or "after" the bug was fixed. As a workaround, a new graphics set option "game.graphics_engine_version" was added to be able to specify the game's major release version for which the graphics set was designed, which can then be used to decide if the bugfix should be used (version 4 and above) or not (version 3 or below, or if no version was specified at all, as with old sets). (The wrong/fixed animation frames can be tested with the test level set "test_gfxframe" and level "000", which contains a specially prepared custom element at level position (x/y) == (11/9) which uses the zonk animation mentioned above. Using "game.graphics_engine_version: 4" fixes the wrong animation frames, showing the correct frames 0,1,2,3. This can also be seen from the debug output for this test element.) */ /* when a custom element is about to change (for example by change delay), do not reset graphic animation when the custom element is moving */ if (game.graphics_engine_version < 4 && !IS_MOVING(x, y)) { ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); } if (change->pre_change_function) change->pre_change_function(x, y); } } ChangeDelay[x][y]--; if (ChangeDelay[x][y] != 0) /* continue element change */ { if (change->can_change) { int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (change->change_function) change->change_function(x, y); } } else /* finish element change */ { if (ChangePage[x][y] != -1) /* remember page from delayed change */ { page = ChangePage[x][y]; ChangePage[x][y] = -1; change = &ei->change_page[page]; } if (IS_MOVING(x, y)) /* never change a running system ;-) */ { ChangeDelay[x][y] = 1; /* try change after next move step */ ChangePage[x][y] = page; /* remember page to use for change */ return; } /* special case: set new level random seed before changing element */ if (change->has_action && change->action_type == CA_SET_LEVEL_RANDOM_SEED) handle_action_before_change = TRUE; if (change->has_action && handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); if (change->can_change) { if (ChangeElement(x, y, element, page)) { if (change->post_change_function) change->post_change_function(x, y); } } if (change->has_action && !handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); } } static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, int trigger_element, int trigger_event, int trigger_player, int trigger_side, int trigger_page) { boolean change_done_any = FALSE; int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page); int i; if (!(trigger_events[trigger_element][trigger_event])) return FALSE; RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; boolean change_done = FALSE; int p; if (!CAN_CHANGE_OR_HAS_ACTION(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) continue; for (p = 0; p < element_info[element].num_change_pages; p++) { struct ElementChangeInfo *change = &element_info[element].change_page[p]; if (change->can_change_or_has_action && change->has_event[trigger_event] && change->trigger_side & trigger_side && change->trigger_player & trigger_player && change->trigger_page & trigger_page_bits && IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)) { change->actual_trigger_element = trigger_element; change->actual_trigger_player = GET_PLAYER_FROM_BITS(trigger_player); change->actual_trigger_player_bits = trigger_player; change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); if ((change->can_change && !change_done) || change->has_action) { int x, y; SCAN_PLAYFIELD(x, y) { if (Feld[x][y] == element) { if (change->can_change && !change_done) { /* if element already changed in this frame, not only prevent another element change (checked in ChangeElement()), but also prevent additional element actions for this element */ if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) continue; ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; HandleElementChange(x, y, p); } else if (change->has_action) { /* if element already changed in this frame, not only prevent another element change (checked in ChangeElement()), but also prevent additional element actions for this element */ if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) continue; ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } } } if (change->can_change) { change_done = TRUE; change_done_any = TRUE; } } } } } RECURSION_LOOP_DETECTION_END(); return change_done_any; } static boolean CheckElementChangeExt(int x, int y, int element, int trigger_element, int trigger_event, int trigger_player, int trigger_side) { boolean change_done = FALSE; int p; if (!CAN_CHANGE_OR_HAS_ACTION(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) return FALSE; if (Feld[x][y] == EL_BLOCKED) { Blocked2Moving(x, y, &x, &y); element = Feld[x][y]; } /* check if element has already changed or is about to change after moving */ if ((game.engine_version < VERSION_IDENT(3,2,0,7) && Feld[x][y] != element) || (game.engine_version >= VERSION_IDENT(3,2,0,7) && (ChangeCount[x][y] >= game.max_num_changes_per_frame || ChangePage[x][y] != -1))) return FALSE; RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); for (p = 0; p < element_info[element].num_change_pages; p++) { struct ElementChangeInfo *change = &element_info[element].change_page[p]; /* check trigger element for all events where the element that is checked for changing interacts with a directly adjacent element -- this is different to element changes that affect other elements to change on the whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */ boolean check_trigger_element = (trigger_event == CE_TOUCHING_X || trigger_event == CE_HITTING_X || trigger_event == CE_HIT_BY_X || trigger_event == CE_DIGGING_X); /* this one was forgotten until 3.2.3 */ if (change->can_change_or_has_action && change->has_event[trigger_event] && change->trigger_side & trigger_side && change->trigger_player & trigger_player && (!check_trigger_element || IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))) { change->actual_trigger_element = trigger_element; change->actual_trigger_player = GET_PLAYER_FROM_BITS(trigger_player); change->actual_trigger_player_bits = trigger_player; change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[x][y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); /* special case: trigger element not at (x,y) position for some events */ if (check_trigger_element) { static struct { int dx, dy; } move_xy[] = { { 0, 0 }, { -1, 0 }, { +1, 0 }, { 0, 0 }, { 0, -1 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, +1 } }; int xx = x + move_xy[MV_DIR_OPPOSITE(trigger_side)].dx; int yy = y + move_xy[MV_DIR_OPPOSITE(trigger_side)].dy; change->actual_trigger_ce_value = CustomValue[xx][yy]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); } if (change->can_change && !change_done) { ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; HandleElementChange(x, y, p); change_done = TRUE; } else if (change->has_action) { ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } } } RECURSION_LOOP_DETECTION_END(); return change_done; } static void PlayPlayerSound(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; int sound_element = player->artwork_element; int last_action = player->last_action_waiting; int action = player->action_waiting; if (player->is_waiting) { if (action != last_action) PlayLevelSoundElementAction(jx, jy, sound_element, action); else PlayLevelSoundElementActionIfLoop(jx, jy, sound_element, action); } else { if (action != last_action) StopSound(element_info[sound_element].sound[last_action]); if (last_action == ACTION_SLEEPING) PlayLevelSoundElementAction(jx, jy, sound_element, ACTION_AWAKENING); } } static void PlayAllPlayersSound() { int i; for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) PlayPlayerSound(&stored_player[i]); } static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) { boolean last_waiting = player->is_waiting; int move_dir = player->MovDir; player->dir_waiting = move_dir; player->last_action_waiting = player->action_waiting; if (is_waiting) { if (!last_waiting) /* not waiting -> waiting */ { player->is_waiting = TRUE; player->frame_counter_bored = FrameCounter + game.player_boring_delay_fixed + GetSimpleRandom(game.player_boring_delay_random); player->frame_counter_sleeping = FrameCounter + game.player_sleeping_delay_fixed + GetSimpleRandom(game.player_sleeping_delay_random); InitPlayerGfxAnimation(player, ACTION_WAITING, move_dir); } if (game.player_sleeping_delay_fixed + game.player_sleeping_delay_random > 0 && player->anim_delay_counter == 0 && player->post_delay_counter == 0 && FrameCounter >= player->frame_counter_sleeping) player->is_sleeping = TRUE; else if (game.player_boring_delay_fixed + game.player_boring_delay_random > 0 && FrameCounter >= player->frame_counter_bored) player->is_bored = TRUE; player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING : player->is_bored ? ACTION_BORING : ACTION_WAITING); if (player->is_sleeping && player->use_murphy) { /* special case for sleeping Murphy when leaning against non-free tile */ if (!IN_LEV_FIELD(player->jx - 1, player->jy) || (Feld[player->jx - 1][player->jy] != EL_EMPTY && !IS_MOVING(player->jx - 1, player->jy))) move_dir = MV_LEFT; else if (!IN_LEV_FIELD(player->jx + 1, player->jy) || (Feld[player->jx + 1][player->jy] != EL_EMPTY && !IS_MOVING(player->jx + 1, player->jy))) move_dir = MV_RIGHT; else player->is_sleeping = FALSE; player->dir_waiting = move_dir; } if (player->is_sleeping) { if (player->num_special_action_sleeping > 0) { if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) { int last_special_action = player->special_action_sleeping; int num_special_action = player->num_special_action_sleeping; int special_action = (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 : last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING : last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ? last_special_action + 1 : ACTION_SLEEPING); int special_graphic = el_act_dir2img(player->artwork_element, special_action, move_dir); player->anim_delay_counter = graphic_info[special_graphic].anim_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].anim_delay_random); player->post_delay_counter = graphic_info[special_graphic].post_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].post_delay_random); player->special_action_sleeping = special_action; } if (player->anim_delay_counter > 0) { player->action_waiting = player->special_action_sleeping; player->anim_delay_counter--; } else if (player->post_delay_counter > 0) { player->post_delay_counter--; } } } else if (player->is_bored) { if (player->num_special_action_bored > 0) { if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) { int special_action = ACTION_BORING_1 + GetSimpleRandom(player->num_special_action_bored); int special_graphic = el_act_dir2img(player->artwork_element, special_action, move_dir); player->anim_delay_counter = graphic_info[special_graphic].anim_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].anim_delay_random); player->post_delay_counter = graphic_info[special_graphic].post_delay_fixed + GetSimpleRandom(graphic_info[special_graphic].post_delay_random); player->special_action_bored = special_action; } if (player->anim_delay_counter > 0) { player->action_waiting = player->special_action_bored; player->anim_delay_counter--; } else if (player->post_delay_counter > 0) { player->post_delay_counter--; } } } } else if (last_waiting) /* waiting -> not waiting */ { player->is_waiting = FALSE; player->is_bored = FALSE; player->is_sleeping = FALSE; player->frame_counter_bored = -1; player->frame_counter_sleeping = -1; player->anim_delay_counter = 0; player->post_delay_counter = 0; player->dir_waiting = player->MovDir; player->action_waiting = ACTION_DEFAULT; player->special_action_bored = ACTION_DEFAULT; player->special_action_sleeping = ACTION_DEFAULT; } } static void CheckSaveEngineSnapshot(struct PlayerInfo *player) { if ((!player->is_moving && player->was_moving) || (player->MovPos == 0 && player->was_moving) || (player->is_snapping && !player->was_snapping) || (player->is_dropping && !player->was_dropping)) { if (!CheckSaveEngineSnapshotToList()) return; player->was_moving = FALSE; player->was_snapping = TRUE; player->was_dropping = TRUE; } else { if (player->is_moving) player->was_moving = TRUE; if (!player->is_snapping) player->was_snapping = FALSE; if (!player->is_dropping) player->was_dropping = FALSE; } } static void CheckSingleStepMode(struct PlayerInfo *player) { if (tape.single_step && tape.recording && !tape.pausing) { /* as it is called "single step mode", just return to pause mode when the player stopped moving after one tile (or never starts moving at all) */ if (!player->is_moving && !player->is_pushing && !player->is_dropping_pressed) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); SnapField(player, 0, 0); /* stop snapping */ } } CheckSaveEngineSnapshot(player); } static byte PlayerActions(struct PlayerInfo *player, byte player_action) { 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); if (!player->active || tape.pausing) return 0; if (player_action) { if (button1) SnapField(player, dx, dy); else { if (button2) DropElement(player); MovePlayer(player, dx, dy); } CheckSingleStepMode(player); SetPlayerWaiting(player, FALSE); return player_action; } else { /* no actions for this player (no input at player's configured device) */ DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); CheckGravityMovementWhenNotMoving(player); if (player->MovPos == 0) SetPlayerWaiting(player, TRUE); if (player->MovPos == 0) /* needed for tape.playing */ player->is_moving = FALSE; player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; CheckSingleStepMode(player); return 0; } } static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action, byte *tape_action) { if (!tape.use_mouse) return; mouse_action->lx = tape_action[TAPE_ACTION_LX]; mouse_action->ly = tape_action[TAPE_ACTION_LY]; mouse_action->button = tape_action[TAPE_ACTION_BUTTON]; } static void SetTapeActionFromMouseAction(byte *tape_action, struct MouseActionInfo *mouse_action) { if (!tape.use_mouse) return; tape_action[TAPE_ACTION_LX] = mouse_action->lx; tape_action[TAPE_ACTION_LY] = mouse_action->ly; tape_action[TAPE_ACTION_BUTTON] = mouse_action->button; } static void CheckLevelTime() { int i; /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ { PlayerWins(local_player); AllPlayersGone = TRUE; level.native_em_level->lev->home = -1; } if (level.native_em_level->ply[0]->alive == 0 && level.native_em_level->ply[1]->alive == 0 && level.native_em_level->ply[2]->alive == 0 && level.native_em_level->ply[3]->alive == 0) /* all dead */ AllPlayersGone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { if (game_sp.LevelSolved && !game_sp.GameOver) /* game won */ { PlayerWins(local_player); game_sp.GameOver = TRUE; AllPlayersGone = TRUE; } if (game_sp.GameOver) /* game lost */ AllPlayersGone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { if (game_mm.level_solved && !game_mm.game_over) /* game won */ { PlayerWins(local_player); game_mm.game_over = TRUE; AllPlayersGone = TRUE; } if (game_mm.game_over) /* game lost */ AllPlayersGone = TRUE; } if (TimeFrames >= FRAMES_PER_SECOND) { TimeFrames = 0; TapeTime++; for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (SHIELD_ON(player)) { player->shield_normal_time_left--; if (player->shield_deadly_time_left > 0) player->shield_deadly_time_left--; } } if (!local_player->LevelSolved && !level.use_step_counter) { TimePlayed++; if (TimeLeft > 0) { TimeLeft--; if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); /* this does not make sense: game_panel_controls[GAME_PANEL_TIME].value is reset from other values in UpdateGameDoorValues() -- FIX THIS */ game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; if (!TimeLeft && setup.time_limit) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) level.native_em_level->lev->killed_out_of_time = TRUE; else for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } } else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; } level.native_em_level->lev->time = (game.no_time_limit ? TimePlayed : TimeLeft); } if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); } if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter); UpdateAndDisplayGameControlValues(); } void AdvanceFrameAndPlayerCounters(int player_nr) { int i; /* advance frame counters (global frame counter and time frame counter) */ FrameCounter++; TimeFrames++; /* advance player counters (counters for move delay, move animation etc.) */ for (i = 0; i < MAX_PLAYERS; i++) { boolean advance_player_counters = (player_nr == -1 || player_nr == i); int move_delay_value = stored_player[i].move_delay_value; int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value; if (!advance_player_counters) /* not all players may be affected */ continue; if (move_frames == 0) /* less than one move per game frame */ { int stepsize = TILEX / move_delay_value; int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED; int count = (stored_player[i].is_moving ? ABS(stored_player[i].MovPos) / stepsize : FrameCounter); if (count % delay == 0) move_frames = 1; } stored_player[i].Frame += move_frames; if (stored_player[i].MovPos != 0) stored_player[i].StepFrame += move_frames; if (stored_player[i].move_delay > 0) stored_player[i].move_delay--; /* due to bugs in previous versions, counter must count up, not down */ if (stored_player[i].push_delay != -1) stored_player[i].push_delay++; if (stored_player[i].drop_delay > 0) stored_player[i].drop_delay--; if (stored_player[i].is_dropping_pressed) stored_player[i].drop_pressed_delay++; } } void StartGameActions(boolean init_network_game, boolean record_tape, int random_seed) { unsigned int new_random_seed = InitRND(random_seed); if (record_tape) TapeStartRecording(new_random_seed); #if defined(NETWORK_AVALIABLE) if (init_network_game) { SendToServer_StartPlaying(); return; } #endif InitGame(); } void GameActionsExt() { #if 0 static unsigned int game_frame_delay = 0; #endif unsigned int game_frame_delay_value; byte *recorded_player_action; byte summarized_player_action = 0; byte tape_action[MAX_PLAYERS]; int i; /* detect endless loops, caused by custom element programming */ if (recursion_loop_detected && recursion_loop_depth == 0) { char *message = getStringCat3("Internal Error! Element ", EL_NAME(recursion_loop_element), " caused endless loop! Quit the game?"); Error(ERR_WARN, "element '%s' caused endless loop in game engine", EL_NAME(recursion_loop_element)); RequestQuitGameExt(FALSE, level_editor_test_game, message); recursion_loop_detected = FALSE; /* if game should be continued */ free(message); return; } if (game.restart_level) StartGameActions(options.network, setup.autorecord, level.random_seed); /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ { PlayerWins(local_player); AllPlayersGone = TRUE; level.native_em_level->lev->home = -1; } if (level.native_em_level->ply[0]->alive == 0 && level.native_em_level->ply[1]->alive == 0 && level.native_em_level->ply[2]->alive == 0 && level.native_em_level->ply[3]->alive == 0) /* all dead */ AllPlayersGone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { if (game_sp.LevelSolved && !game_sp.GameOver) /* game won */ { PlayerWins(local_player); game_sp.GameOver = TRUE; AllPlayersGone = TRUE; } if (game_sp.GameOver) /* game lost */ AllPlayersGone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { if (game_mm.level_solved && !game_mm.game_over) /* game won */ { PlayerWins(local_player); game_mm.game_over = TRUE; AllPlayersGone = TRUE; } if (game_mm.game_over) /* game lost */ AllPlayersGone = TRUE; } if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) TapeStop(); if (game_status != GAME_MODE_PLAYING) /* status might have changed */ return; game_frame_delay_value = (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay); if (tape.playing && tape.warp_forward && !tape.pausing) game_frame_delay_value = 0; SetVideoFrameDelay(game_frame_delay_value); #if 0 #if 0 /* ---------- main game synchronization point ---------- */ int skip = WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); printf("::: skip == %d\n", skip); #else /* ---------- main game synchronization point ---------- */ WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); #endif #endif if (network_playing && !network_player_action_received) { /* try to get network player actions in time */ #if defined(NETWORK_AVALIABLE) /* last chance to get network player actions without main loop delay */ HandleNetworking(); #endif /* game was quit by network peer */ if (game_status != GAME_MODE_PLAYING) return; if (!network_player_action_received) return; /* failed to get network player actions in time */ /* do not yet reset "network_player_action_received" (for tape.pausing) */ } if (tape.pausing) return; /* at this point we know that we really continue executing the game */ network_player_action_received = FALSE; /* when playing tape, read previously recorded player input from tape data */ recorded_player_action = (tape.playing ? TapePlayAction() : NULL); local_player->effective_mouse_action = local_player->mouse_action; if (recorded_player_action != NULL) SetMouseActionFromTapeAction(&local_player->effective_mouse_action, recorded_player_action); /* TapePlayAction() may return NULL when toggling to "pause before death" */ if (tape.pausing) return; if (tape.set_centered_player) { game.centered_player_nr_next = tape.centered_player_nr_next; game.set_centered_player = TRUE; } for (i = 0; i < MAX_PLAYERS; i++) { summarized_player_action |= stored_player[i].action; if (!network_playing && (game.team_mode || tape.playing)) stored_player[i].effective_action = stored_player[i].action; } #if defined(NETWORK_AVALIABLE) if (network_playing) SendToServer_MovePlayer(summarized_player_action); #endif // summarize all actions at local players mapped input device position // (this allows using different input devices in single player mode) if (!options.network && !game.team_mode) stored_player[map_player_action[local_player->index_nr]].effective_action = summarized_player_action; if (tape.recording && setup.team_mode && setup.input_on_focus && game.centered_player_nr != -1) { for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = (i == game.centered_player_nr ? summarized_player_action : 0); } if (recorded_player_action != NULL) for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = recorded_player_action[i]; for (i = 0; i < MAX_PLAYERS; i++) { tape_action[i] = stored_player[i].effective_action; /* (this may happen in the RND game engine if a player was not present on the playfield on level start, but appeared later from a custom element */ if (setup.team_mode && tape.recording && tape_action[i] && !tape.player_participates[i]) tape.player_participates[i] = TRUE; } SetTapeActionFromMouseAction(tape_action, &local_player->effective_mouse_action); /* only record actions from input devices, but not programmed actions */ if (tape.recording) TapeRecordAction(tape_action); #if USE_NEW_PLAYER_ASSIGNMENTS // !!! also map player actions in single player mode !!! // if (game.team_mode) if (1) { byte mapped_action[MAX_PLAYERS]; #if DEBUG_PLAYER_ACTIONS printf(":::"); for (i = 0; i < MAX_PLAYERS; i++) printf(" %d, ", stored_player[i].effective_action); #endif for (i = 0; i < MAX_PLAYERS; i++) mapped_action[i] = stored_player[map_player_action[i]].effective_action; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = mapped_action[i]; #if DEBUG_PLAYER_ACTIONS printf(" =>"); for (i = 0; i < MAX_PLAYERS; i++) printf(" %d, ", stored_player[i].effective_action); printf("\n"); #endif } #if DEBUG_PLAYER_ACTIONS else { printf(":::"); for (i = 0; i < MAX_PLAYERS; i++) printf(" %d, ", stored_player[i].effective_action); printf("\n"); } #endif #endif for (i = 0; i < MAX_PLAYERS; i++) { // allow engine snapshot in case of changed movement attempt if ((game.snapshot.last_action[i] & KEY_MOTION) != (stored_player[i].effective_action & KEY_MOTION)) game.snapshot.changed_action = TRUE; // allow engine snapshot in case of snapping/dropping attempt if ((game.snapshot.last_action[i] & KEY_BUTTON) == 0 && (stored_player[i].effective_action & KEY_BUTTON) != 0) game.snapshot.changed_action = TRUE; game.snapshot.last_action[i] = stored_player[i].effective_action; } if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { GameActions_EM_Main(); } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { GameActions_SP_Main(); } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { GameActions_MM_Main(); } else { GameActions_RND_Main(); } BlitScreenToBitmap(backbuffer); CheckLevelTime(); AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ if (global.show_frames_per_second) { static unsigned int fps_counter = 0; static int fps_frames = 0; unsigned int fps_delay_ms = Counter() - fps_counter; fps_frames++; if (fps_delay_ms >= 500) /* calculate FPS every 0.5 seconds */ { global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms; fps_frames = 0; fps_counter = Counter(); /* always draw FPS to screen after FPS value was updated */ redraw_mask |= REDRAW_FPS; } /* only draw FPS if no screen areas are deactivated (invisible warp mode) */ if (GetDrawDeactivationMask() == REDRAW_NONE) redraw_mask |= REDRAW_FPS; } } static void GameActions_CheckSaveEngineSnapshot() { if (!game.snapshot.save_snapshot) return; // clear flag for saving snapshot _before_ saving snapshot game.snapshot.save_snapshot = FALSE; SaveEngineSnapshotToList(); } void GameActions() { GameActionsExt(); GameActions_CheckSaveEngineSnapshot(); } void GameActions_EM_Main() { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); int i; for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; GameActions_EM(effective_action, warp_mode); } void GameActions_SP_Main() { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); int i; for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; GameActions_SP(effective_action, warp_mode); for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].force_dropping) stored_player[i].action |= KEY_BUTTON_DROP; stored_player[i].force_dropping = FALSE; } } void GameActions_MM_Main() { boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); GameActions_MM(local_player->effective_mouse_action, warp_mode); } void GameActions_RND_Main() { GameActions_RND(); } void GameActions_RND() { int magic_wall_x = 0, magic_wall_y = 0; int i, x, y, element, graphic, last_gfx_frame; InitPlayfieldScanModeVars(); if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; } } if (game.set_centered_player) { boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND(); /* switching to "all players" only possible if all players fit to screen */ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } /* do not switch focus to non-existing (or non-active) player */ if (game.centered_player_nr_next >= 0 && !stored_player[game.centered_player_nr_next].active) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } } if (game.set_centered_player && ScreenMovPos == 0) /* screen currently aligned at tile position */ { int sx, sy; if (game.centered_player_nr_next == -1) { setScreenCenteredToAllPlayers(&sx, &sy); } else { sx = stored_player[game.centered_player_nr_next].jx; sy = stored_player[game.centered_player_nr_next].jy; } game.centered_player_nr = game.centered_player_nr_next; game.set_centered_player = FALSE; DrawRelocateScreen(0, 0, sx, sy, MV_NONE, TRUE, setup.quick_switch); DrawGameDoorValues(); } for (i = 0; i < MAX_PLAYERS; i++) { int actual_player_action = stored_player[i].effective_action; #if 1 /* !!! THIS BREAKS THE FOLLOWING TAPES: !!! - rnd_equinox_tetrachloride 048 - rnd_equinox_tetrachloride_ii 096 - rnd_emanuel_schmieg 002 - doctor_sloan_ww 001, 020 */ if (stored_player[i].MovPos == 0) CheckGravityMovement(&stored_player[i]); #endif /* overwrite programmed action with tape action */ if (stored_player[i].programmed_action) actual_player_action = stored_player[i].programmed_action; PlayerActions(&stored_player[i], actual_player_action); ScrollPlayer(&stored_player[i], SCROLL_GO_ON); } ScrollScreen(NULL, SCROLL_GO_ON); /* for backwards compatibility, the following code emulates a fixed bug that occured when pushing elements (causing elements that just made their last pushing step to already (if possible) make their first falling step in the same game frame, which is bad); this code is also needed to use the famous "spring push bug" which is used in older levels and might be wanted to be used also in newer levels, but in this case the buggy pushing code is only affecting the "spring" element and no other elements */ if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug) { for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; int x = player->jx; int y = player->jy; if (player->active && player->is_pushing && player->is_moving && IS_MOVING(x, y) && (game.engine_version < VERSION_IDENT(2,2,0,7) || Feld[x][y] == EL_SPRING)) { ContinueMoving(x, y); /* continue moving after pushing (this is actually a bug) */ if (!IS_MOVING(x, y)) Stop[x][y] = FALSE; } } } SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; /* this must be handled before main playfield loop */ if (Feld[x][y] == EL_PLAYER_IS_LEAVING) { MovDelay[x][y]--; if (MovDelay[x][y] <= 0) RemoveField(x, y); } if (Feld[x][y] == EL_ELEMENT_SNAPPING) { MovDelay[x][y]--; if (MovDelay[x][y] <= 0) { RemoveField(x, y); TEST_DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); /* for empty space */ } } #if DEBUG if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1) { printf("GameActions(): x = %d, y = %d: ChangePage != -1\n", x, y); printf("GameActions(): This should never happen!\n"); ChangePage[x][y] = -1; } #endif Stop[x][y] = FALSE; if (WasJustMoving[x][y] > 0) WasJustMoving[x][y]--; if (WasJustFalling[x][y] > 0) WasJustFalling[x][y]--; if (CheckCollision[x][y] > 0) CheckCollision[x][y]--; if (CheckImpact[x][y] > 0) CheckImpact[x][y]--; GfxFrame[x][y]++; /* reset finished pushing action (not done in ContinueMoving() to allow continuous pushing animation for elements with zero push delay) */ if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y)) { ResetGfxAnimation(x, y); TEST_DrawLevelField(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 } SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); last_gfx_frame = GfxFrame[x][y]; ResetGfxFrame(x, y); if (GfxFrame[x][y] != last_gfx_frame && !Stop[x][y]) DrawLevelGraphicAnimation(x, y, graphic); if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(GfxFrame[x][y], graphic)) ResetRandomAnimationValue(x, y); SetRandomAnimationValue(x, y); PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]); if (IS_INACTIVE(element)) { if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); continue; } /* this may take place after moving, so 'element' may have changed */ if (IS_CHANGING(x, y) && (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y])) { int page = element_info[element].event_page_nr[CE_DELAY]; HandleElementChange(x, y, page); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); } if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (IS_ANIMATED(graphic) && !IS_MOVING(x, y) && !Stop[x][y]) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_GEM(element) || element == EL_SP_INFOTRON) TEST_DrawTwinkleOnField(x, y); } else if (element == EL_ACID) { if (!Stop[x][y]) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); } else if ((element == EL_EXIT_OPEN || element == EL_EM_EXIT_OPEN || element == EL_SP_EXIT_OPEN || element == EL_STEEL_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPEN || element == EL_SP_TERMINAL || element == EL_SP_TERMINAL_ACTIVE || element == EL_EXTRA_TIME || element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) && IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); else if (IS_MOVING(x, y)) ContinueMoving(x, y); else if (IS_ACTIVE_BOMB(element)) CheckDynamite(x, y); else if (element == EL_AMOEBA_GROWING) AmoebeWaechst(x, y); else if (element == EL_AMOEBA_SHRINKING) AmoebaDisappearing(x, y); #if !USE_NEW_AMOEBA_CODE else if (IS_AMOEBALIVE(element)) AmoebeAbleger(x, y); #endif else if (element == EL_GAME_OF_LIFE || element == EL_BIOMAZE) Life(x, y); else if (element == EL_EXIT_CLOSED) CheckExit(x, y); else if (element == EL_EM_EXIT_CLOSED) CheckExitEM(x, y); else if (element == EL_STEEL_EXIT_CLOSED) CheckExitSteel(x, y); else if (element == EL_EM_STEEL_EXIT_CLOSED) CheckExitSteelEM(x, y); else if (element == EL_SP_EXIT_CLOSED) CheckExitSP(x, y); else if (element == EL_EXPANDABLE_WALL_GROWING || element == EL_EXPANDABLE_STEELWALL_GROWING) MauerWaechst(x, y); else if (element == EL_EXPANDABLE_WALL || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_VERTICAL || element == EL_EXPANDABLE_WALL_ANY || element == EL_BD_EXPANDABLE_WALL) MauerAbleger(x, y); else if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || element == EL_EXPANDABLE_STEELWALL_VERTICAL || element == EL_EXPANDABLE_STEELWALL_ANY) MauerAblegerStahl(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); else if (element == EL_EXPLOSION) ; /* drawing of correct explosion animation is handled separately */ else if (element == EL_ELEMENT_SNAPPING || element == EL_DIAGONAL_SHRINKING || element == EL_DIAGONAL_GROWING) { graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); DrawLevelGraphicAnimationIfNeeded(x, y, graphic); } else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_BELT_ACTIVE(element)) PlayLevelSoundAction(x, y, ACTION_ACTIVE); if (game.magic_wall_active) { int jx = local_player->jx, jy = local_player->jy; /* play the element sound at the position nearest to the player */ if ((element == EL_MAGIC_WALL_FULL || element == EL_MAGIC_WALL_ACTIVE || element == EL_MAGIC_WALL_EMPTYING || element == EL_BD_MAGIC_WALL_FULL || element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_EMPTYING || element == EL_DC_MAGIC_WALL_FULL || element == EL_DC_MAGIC_WALL_ACTIVE || element == EL_DC_MAGIC_WALL_EMPTYING) && ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy)) { magic_wall_x = x; magic_wall_y = y; } } } #if USE_NEW_AMOEBA_CODE /* new experimental amoeba growth stuff */ if (!(FrameCounter % 8)) { static unsigned int random = 1684108901; for (i = 0; i < level.amoeba_speed * 28 / 8; i++) { x = RND(lev_fieldx); y = RND(lev_fieldy); element = Feld[x][y]; if (!IS_PLAYER(x,y) && (element == EL_EMPTY || CAN_GROW_INTO(element) || element == EL_QUICKSAND_EMPTY || element == EL_QUICKSAND_FAST_EMPTY || element == EL_ACID_SPLASH_LEFT || element == EL_ACID_SPLASH_RIGHT)) { if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) || (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) || (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) || (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET)) Feld[x][y] = EL_AMOEBA_DROP; } random = random * 129 + 1; } } #endif game.explosions_delayed = FALSE; SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; if (ExplodeField[x][y]) Explode(x, y, EX_PHASE_START, ExplodeField[x][y]); else if (element == EL_EXPLOSION) Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL); ExplodeField[x][y] = EX_TYPE_NONE; } game.explosions_delayed = TRUE; if (game.magic_wall_active) { if (!(game.magic_wall_time_left % 4)) { int element = Feld[magic_wall_x][magic_wall_y]; if (element == EL_BD_MAGIC_WALL_FULL || element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_EMPTYING) PlayLevelSound(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE); else if (element == EL_DC_MAGIC_WALL_FULL || element == EL_DC_MAGIC_WALL_ACTIVE || element == EL_DC_MAGIC_WALL_EMPTYING) PlayLevelSound(magic_wall_x, magic_wall_y, SND_DC_MAGIC_WALL_ACTIVE); else PlayLevelSound(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE); } if (game.magic_wall_time_left > 0) { game.magic_wall_time_left--; if (!game.magic_wall_time_left) { SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; if (element == EL_MAGIC_WALL_ACTIVE || element == EL_MAGIC_WALL_FULL) { Feld[x][y] = EL_MAGIC_WALL_DEAD; TEST_DrawLevelField(x, y); } else if (element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_FULL) { Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; TEST_DrawLevelField(x, y); } else if (element == EL_DC_MAGIC_WALL_ACTIVE || element == EL_DC_MAGIC_WALL_FULL) { Feld[x][y] = EL_DC_MAGIC_WALL_DEAD; TEST_DrawLevelField(x, y); } } game.magic_wall_active = FALSE; } } } if (game.light_time_left > 0) { game.light_time_left--; if (game.light_time_left == 0) RedrawAllLightSwitchesAndInvisibleElements(); } if (game.timegate_time_left > 0) { game.timegate_time_left--; if (game.timegate_time_left == 0) CloseAllOpenTimegates(); } if (game.lenses_time_left > 0) { game.lenses_time_left--; if (game.lenses_time_left == 0) RedrawAllInvisibleElementsForLenses(); } if (game.magnify_time_left > 0) { game.magnify_time_left--; if (game.magnify_time_left == 0) RedrawAllInvisibleElementsForMagnifier(); } for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; if (SHIELD_ON(player)) { if (player->shield_deadly_time_left) PlayLevelSound(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE); else if (player->shield_normal_time_left) PlayLevelSound(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE); } } #if USE_DELAYED_GFX_REDRAW SCAN_PLAYFIELD(x, y) { if (GfxRedraw[x][y] != GFX_REDRAW_NONE) { /* !!! PROBLEM: THIS REDRAWS THE PLAYFIELD _AFTER_ THE SCAN, BUT TILES !!! MAY HAVE CHANGED AFTER BEING DRAWN DURING PLAYFIELD SCAN !!! */ if (GfxRedraw[x][y] & GFX_REDRAW_TILE) DrawLevelField(x, y); if (GfxRedraw[x][y] & GFX_REDRAW_TILE_CRUMBLED) DrawLevelFieldCrumbled(x, y); if (GfxRedraw[x][y] & GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS) DrawLevelFieldCrumbledNeighbours(x, y); if (GfxRedraw[x][y] & GFX_REDRAW_TILE_TWINKLED) DrawTwinkleOnField(x, y); } GfxRedraw[x][y] = GFX_REDRAW_NONE; } #endif DrawAllPlayers(); PlayAllPlayersSound(); if (local_player->show_envelope != 0 && local_player->MovPos == 0) { ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); local_player->show_envelope = 0; } /* use random number generator in every frame to make it less predictable */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) { int min_x = x, min_y = y, max_x = x, max_y = y; int i; for (i = 0; i < MAX_PLAYERS; i++) { int jx = stored_player[i].jx, jy = stored_player[i].jy; if (!stored_player[i].active || &stored_player[i] == player) continue; min_x = MIN(min_x, jx); min_y = MIN(min_y, jy); max_x = MAX(max_x, jx); max_y = MAX(max_y, jy); } return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY); } static boolean AllPlayersInVisibleScreen() { int i; for (i = 0; i < MAX_PLAYERS; i++) { int jx = stored_player[i].jx, jy = stored_player[i].jy; if (!stored_player[i].active) continue; if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) return FALSE; } return TRUE; } void ScrollLevel(int dx, int dy) { int scroll_offset = 2 * TILEX_VAR; int x, y; BlitBitmap(drawto_field, drawto_field, FX + TILEX_VAR * (dx == -1) - scroll_offset, FY + TILEY_VAR * (dy == -1) - scroll_offset, SXSIZE - TILEX_VAR * (dx != 0) + 2 * scroll_offset, SYSIZE - TILEY_VAR * (dy != 0) + 2 * scroll_offset, FX + TILEX_VAR * (dx == 1) - scroll_offset, FY + TILEY_VAR * (dy == 1) - scroll_offset); if (dx != 0) { x = (dx == 1 ? BX1 : BX2); for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); } if (dy != 0) { y = (dy == 1 ? BY1 : BY2); for (x = BX1; x <= BX2; x++) DrawScreenField(x, y); } redraw_mask |= REDRAW_FIELD; } static boolean canFallDown(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; return (IN_LEV_FIELD(jx, jy + 1) && (IS_FREE(jx, jy + 1) || (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) && IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) && !IS_WALKABLE_INSIDE(Feld[jx][jy])); } static boolean canPassField(int x, int y, int move_dir) { int opposite_dir = MV_DIR_OPPOSITE(move_dir); int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); int nextx = x + dx; int nexty = y + dy; int element = Feld[x][y]; return (IS_PASSABLE_FROM(element, opposite_dir) && !CAN_MOVE(element) && IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) && IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) && (level.can_pass_to_walkable || IS_FREE(nextx, nexty))); } static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) { int opposite_dir = MV_DIR_OPPOSITE(move_dir); int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); int newx = x + dx; int newy = y + dy; return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && IS_GRAVITY_REACHABLE(Feld[newx][newy]) && (IS_DIGGABLE(Feld[newx][newy]) || IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || canPassField(newx, newy, move_dir))); } static void CheckGravityMovement(struct PlayerInfo *player) { if (player->gravity && !player->programmed_action) { int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; boolean player_is_snapping = (player->effective_action & JOY_BUTTON_1); int jx = player->jx, jy = player->jy; boolean player_is_moving_to_valid_field = (!player_is_snapping && (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) || canMoveToValidFieldWithGravity(jx, jy, move_dir_vertical))); boolean player_can_fall_down = canFallDown(player); if (player_can_fall_down && !player_is_moving_to_valid_field) player->programmed_action = MV_DOWN; } } static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player) { return CheckGravityMovement(player); if (player->gravity && !player->programmed_action) { int jx = player->jx, jy = player->jy; boolean field_under_player_is_free = (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1)); boolean player_is_standing_on_valid_field = (IS_WALKABLE_INSIDE(Feld[jx][jy]) || (IS_WALKABLE(Feld[jx][jy]) && !(element_info[Feld[jx][jy]].access_direction & MV_DOWN))); if (field_under_player_is_free && !player_is_standing_on_valid_field) player->programmed_action = MV_DOWN; } } /* MovePlayerOneStep() ----------------------------------------------------------------------------- dx, dy: direction (non-diagonal) to try to move the player to real_dx, real_dy: direction as read from input device (can be diagonal) */ boolean MovePlayerOneStep(struct PlayerInfo *player, int dx, int dy, int real_dx, int real_dy) { int jx = player->jx, jy = player->jy; int new_jx = jx + dx, new_jy = jy + dy; int can_move; boolean player_can_move = !player->cannot_move; if (!player->active || (!dx && !dy)) return MP_NO_ACTION; player->MovDir = (dx < 0 ? MV_LEFT : dx > 0 ? MV_RIGHT : dy < 0 ? MV_UP : dy > 0 ? MV_DOWN : MV_NONE); if (!IN_LEV_FIELD(new_jx, new_jy)) return MP_NO_ACTION; if (!player_can_move) { if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; player->is_snapping = FALSE; player->is_pushing = FALSE; } } if (!options.network && game.centered_player_nr == -1 && !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG); if (can_move != MP_MOVING) return can_move; /* check if DigField() has caused relocation of the player */ if (player->jx != jx || player->jy != jy) return MP_NO_ACTION; /* <-- !!! CHECK THIS [-> MP_ACTION ?] !!! */ StorePlayer[jx][jy] = 0; player->last_jx = jx; player->last_jy = jy; player->jx = new_jx; player->jy = new_jy; StorePlayer[new_jx][new_jy] = player->element_nr; if (player->move_delay_value_next != -1) { player->move_delay_value = player->move_delay_value_next; player->move_delay_value_next = -1; } player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value); player->step_counter++; PlayerVisit[jx][jy] = FrameCounter; player->is_moving = TRUE; #if 1 /* should better be called in MovePlayer(), but this breaks some tapes */ ScrollPlayer(player, SCROLL_INIT); #endif return MP_MOVING; } boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) { int jx = player->jx, jy = player->jy; int old_jx = jx, old_jy = jy; int moved = MP_NO_ACTION; if (!player->active) return FALSE; if (!dx && !dy) { if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; player->is_snapping = FALSE; player->is_pushing = FALSE; } return FALSE; } if (player->move_delay > 0) return FALSE; player->move_delay = -1; /* set to "uninitialized" value */ /* store if player is automatically moved to next field */ player->is_auto_moving = (player->programmed_action != MV_NONE); /* remove the last programmed player action */ player->programmed_action = 0; if (player->MovPos) { /* should only happen if pre-1.2 tape recordings are played */ /* this is only for backward compatibility */ int original_move_delay_value = player->move_delay_value; #if DEBUG printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%d]\n", tape.counter); #endif /* scroll remaining steps with finest movement resolution */ player->move_delay_value = MOVE_DELAY_NORMAL_SPEED; while (player->MovPos) { ScrollPlayer(player, SCROLL_GO_ON); ScrollScreen(NULL, SCROLL_GO_ON); AdvanceFrameAndPlayerCounters(player->index_nr); DrawAllPlayers(); BackToFront_WithFrameDelay(0); } player->move_delay_value = original_move_delay_value; } player->is_active = FALSE; if (player->last_move_dir & MV_HORIZONTAL) { if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy))) moved |= MovePlayerOneStep(player, dx, 0, dx, dy); } else { if (!(moved |= MovePlayerOneStep(player, dx, 0, dx, dy))) moved |= MovePlayerOneStep(player, 0, dy, dx, dy); } if (!moved && !player->is_active) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; player->is_snapping = FALSE; player->is_pushing = FALSE; } jx = player->jx; jy = player->jy; if (moved & MP_MOVING && !ScreenMovPos && (player->index_nr == game.centered_player_nr || game.centered_player_nr == -1)) { int old_scroll_x = scroll_x, old_scroll_y = scroll_y; int offset = game.scroll_delay_value; 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 { 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 < SBX_Left || scroll_x > SBX_Right) scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); /* 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 < SBY_Upper || scroll_y > SBY_Lower) scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); /* 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 && game.centered_player_nr == -1 && !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); } } } player->StepFrame = 0; if (moved & MP_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); TEST_DrawLevelField(jx, jy); /* for "crumbled sand" */ player->last_move_dir = player->MovDir; player->is_moving = TRUE; player->is_snapping = FALSE; player->is_switching = FALSE; player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; #if 0 /* should better be called here than above, but this breaks some tapes */ ScrollPlayer(player, SCROLL_INIT); #endif } else { CheckGravityMovementWhenNotMoving(player); player->is_moving = FALSE; /* at this point, the player is allowed to move, but cannot move right now (e.g. because of something blocking the way) -- ensure that the player is also allowed to move in the next frame (in old versions before 3.1.1, the player was forced to wait again for eight frames before next try) */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) player->move_delay = 0; /* allow direct movement in the next frame */ } if (player->move_delay == -1) /* not yet initialized by DigField() */ player->move_delay = player->move_delay_value; if (game.engine_version < VERSION_IDENT(3,0,7,0)) { TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); } if (!player->active) RemovePlayer(player); return moved; } void ScrollPlayer(struct PlayerInfo *player, int mode) { int jx = player->jx, jy = player->jy; int last_jx = player->last_jx, last_jy = player->last_jy; int move_stepsize = TILEX / player->move_delay_value; if (!player->active) return; if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */ return; if (mode == SCROLL_INIT) { player->actual_frame_counter = FrameCounter; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); if ((player->block_last_field || player->block_delay_adjustment > 0) && Feld[last_jx][last_jy] == EL_EMPTY) { int last_field_block_delay = 0; /* start with no blocking at all */ int block_delay_adjustment = player->block_delay_adjustment; /* if player blocks last field, add delay for exactly one move */ if (player->block_last_field) { last_field_block_delay += player->move_delay_value; /* when blocking enabled, prevent moving up despite gravity */ if (player->gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; } /* add block delay adjustment (also possible when not blocking) */ last_field_block_delay += block_delay_adjustment; Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; MovDelay[last_jx][last_jy] = last_field_block_delay + 1; } if (player->MovPos != 0) /* player has not yet reached destination */ return; } else if (!FrameReached(&player->actual_frame_counter, 1)) return; if (player->MovPos != 0) { player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); /* before DrawPlayer() to draw correct player graphic for this case */ if (player->MovPos == 0) CheckGravityMovement(player); } if (player->MovPos == 0) /* player reached destination field */ { if (player->move_delay_reset_counter > 0) { player->move_delay_reset_counter--; if (player->move_delay_reset_counter == 0) { /* continue with normal speed after quickly moving through gate */ HALVE_PLAYER_SPEED(player); /* be able to make the next move without delay */ player->move_delay = 0; } } player->last_jx = jx; player->last_jy = jy; if (Feld[jx][jy] == EL_EXIT_OPEN || Feld[jx][jy] == EL_EM_EXIT_OPEN || Feld[jx][jy] == EL_EM_EXIT_OPENING || Feld[jx][jy] == EL_STEEL_EXIT_OPEN || Feld[jx][jy] == EL_EM_STEEL_EXIT_OPEN || Feld[jx][jy] == EL_EM_STEEL_EXIT_OPENING || Feld[jx][jy] == EL_SP_EXIT_OPEN || Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */ { DrawPlayer(player); /* needed here only to cleanup last field */ RemovePlayer(player); if (local_player->friends_still_needed == 0 || IS_SP_ELEMENT(Feld[jx][jy])) PlayerWins(player); } /* this breaks one level: "machine", level 000 */ { int move_direction = player->MovDir; int enter_side = MV_DIR_OPPOSITE(move_direction); int leave_side = move_direction; int old_jx = last_jx; int old_jy = last_jy; int old_element = Feld[old_jx][old_jy]; int new_element = Feld[jx][jy]; if (IS_CUSTOM_ELEMENT(old_element)) CheckElementChangeByPlayer(old_jx, old_jy, old_element, CE_LEFT_BY_PLAYER, player->index_bit, leave_side); CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element, CE_PLAYER_LEAVES_X, player->index_bit, leave_side); if (IS_CUSTOM_ELEMENT(new_element)) CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER, player->index_bit, enter_side); CheckTriggeredElementChangeByPlayer(jx, jy, new_element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); CheckTriggeredElementChangeBySide(jx, jy, player->initial_element, CE_MOVE_OF_X, move_direction); } if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); /* needed because pushed element has not yet reached its destination, so it would trigger a change event at its previous field location */ if (!player->is_pushing) TestIfElementTouchesCustomElement(jx, jy); /* for empty space */ if (!player->active) RemovePlayer(player); } if (!local_player->LevelSolved && level.use_step_counter) { int i; TimePlayed++; if (TimeLeft > 0) { TimeLeft--; if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } } if (tape.single_step && tape.recording && !tape.pausing && !player->programmed_action) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); if (!player->programmed_action) CheckSaveEngineSnapshot(player); } } void ScrollScreen(struct PlayerInfo *player, int mode) { static unsigned int screen_frame_counter = 0; if (mode == SCROLL_INIT) { /* set scrolling step size according to actual player's moving speed */ ScrollStepSize = TILEX / player->move_delay_value; screen_frame_counter = FrameCounter; ScreenMovDir = player->MovDir; ScreenMovPos = player->MovPos; ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); return; } else if (!FrameReached(&screen_frame_counter, 1)) return; if (ScreenMovPos) { ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize; ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); redraw_mask |= REDRAW_FIELD; } else ScreenMovDir = MV_NONE; } void TestIfPlayerTouchesCustomElement(int x, int y) { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int trigger_sides[4][2] = { /* center side border side */ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; int center_element = Feld[x][y]; /* should always be non-moving! */ int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int center_side = trigger_sides[i][0]; int border_side = trigger_sides[i][1]; int border_element; if (!IN_LEV_FIELD(xx, yy)) continue; if (IS_PLAYER(x, y)) /* player found at center element */ { struct PlayerInfo *player = PLAYERINFO(x, y); if (game.engine_version < VERSION_IDENT(3,0,7,0)) border_element = Feld[xx][yy]; /* may be moving! */ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ border_element = MovingOrBlocked2Element(xx, yy); else continue; /* center and border element do not touch */ CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, player->index_bit, border_side); CheckTriggeredElementChangeByPlayer(xx, yy, border_element, CE_PLAYER_TOUCHES_X, player->index_bit, border_side); { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(x, y)->initial_element; CheckElementChangeBySide(xx, yy, border_element, player_element, CE_TOUCHING_X, border_side); } } else if (IS_PLAYER(xx, yy)) /* player found at border element */ { struct PlayerInfo *player = PLAYERINFO(xx, yy); if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { if (player->MovPos != 0 && !(player->MovDir & touch_dir[i])) continue; /* center and border element do not touch */ } CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, player->index_bit, center_side); CheckTriggeredElementChangeByPlayer(x, y, center_element, CE_PLAYER_TOUCHES_X, player->index_bit, center_side); { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(xx, yy)->initial_element; CheckElementChangeBySide(x, y, center_element, player_element, CE_TOUCHING_X, center_side); } break; } } } void TestIfElementTouchesCustomElement(int x, int y) { static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int trigger_sides[4][2] = { /* center side border side */ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; boolean change_center_element = FALSE; int center_element = Feld[x][y]; /* should always be non-moving! */ int border_element_old[NUM_DIRECTIONS]; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int border_element; border_element_old[i] = -1; if (!IN_LEV_FIELD(xx, yy)) continue; if (game.engine_version < VERSION_IDENT(3,0,7,0)) border_element = Feld[xx][yy]; /* may be moving! */ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ border_element = MovingOrBlocked2Element(xx, yy); else continue; /* center and border element do not touch */ border_element_old[i] = border_element; } for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int center_side = trigger_sides[i][0]; int border_element = border_element_old[i]; if (border_element == -1) continue; /* check for change of border element */ CheckElementChangeBySide(xx, yy, border_element, center_element, CE_TOUCHING_X, center_side); /* (center element cannot be player, so we dont have to check this here) */ } for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int border_side = trigger_sides[i][1]; int border_element = border_element_old[i]; if (border_element == -1) continue; /* check for change of center element (but change it only once) */ if (!change_center_element) change_center_element = CheckElementChangeBySide(x, y, center_element, border_element, CE_TOUCHING_X, border_side); if (IS_PLAYER(xx, yy)) { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(xx, yy)->initial_element; CheckElementChangeBySide(x, y, center_element, player_element, CE_TOUCHING_X, border_side); } } } void TestIfElementHitsCustomElement(int x, int y, int direction) { int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int hitx = x + dx, hity = y + dy; int hitting_element = Feld[x][y]; int touched_element; if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity)) return; touched_element = (IN_LEV_FIELD(hitx, hity) ? MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL); if (IN_LEV_FIELD(hitx, hity)) { int opposite_direction = MV_DIR_OPPOSITE(direction); int hitting_side = direction; int touched_side = opposite_direction; boolean object_hit = (!IS_MOVING(hitx, hity) || MovDir[hitx][hity] != direction || ABS(MovPos[hitx][hity]) <= TILEY / 2); object_hit = TRUE; if (object_hit) { CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_X, touched_side); CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_X, hitting_side); CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_SOMETHING, opposite_direction); if (IS_PLAYER(hitx, hity)) { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number (example: a level that contains EL_PLAYER_3 as the only player would incorrectly give EL_PLAYER_1 for "player->element_nr") */ int player_element = PLAYERINFO(hitx, hity)->initial_element; CheckElementChangeBySide(x, y, hitting_element, player_element, CE_HITTING_X, touched_side); } } } /* "hitting something" is also true when hitting the playfield border */ CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_SOMETHING, direction); } void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) { int i, kill_x = -1, kill_y = -1; int bad_element = -1; static int test_xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int test_dir[4] = { MV_UP, MV_LEFT, MV_RIGHT, MV_DOWN }; for (i = 0; i < NUM_DIRECTIONS; i++) { int test_x, test_y, test_move_dir, test_element; test_x = good_x + test_xy[i][0]; test_y = good_y + test_xy[i][1]; if (!IN_LEV_FIELD(test_x, test_y)) continue; test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y); /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing; 2nd case: DONT_TOUCH style bad thing does not move away from good thing */ if ((DONT_RUN_INTO(test_element) && good_move_dir == test_dir[i]) || (DONT_TOUCH(test_element) && test_move_dir != test_dir[i])) { kill_x = test_x; kill_y = test_y; bad_element = test_element; break; } } if (kill_x != -1 || kill_y != -1) { if (IS_PLAYER(good_x, good_y)) { struct PlayerInfo *player = PLAYERINFO(good_x, good_y); if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(kill_x, kill_y); else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y)) KillPlayer(player); } else Bang(good_x, good_y); } } void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) { int i, kill_x = -1, kill_y = -1; int bad_element = Feld[bad_x][bad_y]; static int test_xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; static int touch_dir[4] = { MV_LEFT | MV_RIGHT, MV_UP | MV_DOWN, MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; static int test_dir[4] = { MV_UP, MV_LEFT, MV_RIGHT, MV_DOWN }; if (bad_element == EL_EXPLOSION) /* skip just exploding bad things */ return; for (i = 0; i < NUM_DIRECTIONS; i++) { int test_x, test_y, test_move_dir, test_element; test_x = bad_x + test_xy[i][0]; test_y = bad_y + test_xy[i][1]; if (!IN_LEV_FIELD(test_x, test_y)) continue; test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); test_element = Feld[test_x][test_y]; /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing; 2nd case: DONT_TOUCH style bad thing does not move away from good thing */ if ((DONT_RUN_INTO(bad_element) && bad_move_dir == test_dir[i]) || (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i])) { /* good thing is player or penguin that does not move away */ if (IS_PLAYER(test_x, test_y)) { struct PlayerInfo *player = PLAYERINFO(test_x, test_y); if (bad_element == EL_ROBOT && player->is_moving) continue; /* robot does not kill player if he is moving */ if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { if (player->MovPos != 0 && !(player->MovDir & touch_dir[i])) continue; /* center and border element do not touch */ } kill_x = test_x; kill_y = test_y; break; } else if (test_element == EL_PENGUIN) { kill_x = test_x; kill_y = test_y; break; } } } if (kill_x != -1 || kill_y != -1) { if (IS_PLAYER(kill_x, kill_y)) { struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y); if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(bad_x, bad_y); else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) KillPlayer(player); } else Bang(kill_x, kill_y); } } void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir) { int bad_element = Feld[bad_x][bad_y]; int dx = (bad_move_dir == MV_LEFT ? -1 : bad_move_dir == MV_RIGHT ? +1 : 0); int dy = (bad_move_dir == MV_UP ? -1 : bad_move_dir == MV_DOWN ? +1 : 0); int test_x = bad_x + dx, test_y = bad_y + dy; int test_move_dir, test_element; int kill_x = -1, kill_y = -1; if (!IN_LEV_FIELD(test_x, test_y)) return; test_move_dir = (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); test_element = Feld[test_x][test_y]; if (test_move_dir != bad_move_dir) { /* good thing can be player or penguin that does not move away */ if (IS_PLAYER(test_x, test_y)) { struct PlayerInfo *player = PLAYERINFO(test_x, test_y); /* (note: in comparison to DONT_RUN_TO and DONT_TOUCH, also handle the player as being hit when he is moving towards the bad thing, because the "get hit by" condition would be lost after the player stops) */ if (player->MovPos != 0 && player->MovDir == bad_move_dir) return; /* player moves away from bad thing */ kill_x = test_x; kill_y = test_y; } else if (test_element == EL_PENGUIN) { kill_x = test_x; kill_y = test_y; } } if (kill_x != -1 || kill_y != -1) { if (IS_PLAYER(kill_x, kill_y)) { struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y); if (player->shield_deadly_time_left > 0 && !IS_INDESTRUCTIBLE(bad_element)) Bang(bad_x, bad_y); else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) KillPlayer(player); } else Bang(kill_x, kill_y); } } void TestIfPlayerTouchesBadThing(int x, int y) { TestIfGoodThingHitsBadThing(x, y, MV_NONE); } void TestIfPlayerRunsIntoBadThing(int x, int y, int move_dir) { TestIfGoodThingHitsBadThing(x, y, move_dir); } void TestIfBadThingTouchesPlayer(int x, int y) { TestIfBadThingHitsGoodThing(x, y, MV_NONE); } void TestIfBadThingRunsIntoPlayer(int x, int y, int move_dir) { TestIfBadThingHitsGoodThing(x, y, move_dir); } void TestIfFriendTouchesBadThing(int x, int y) { TestIfGoodThingHitsBadThing(x, y, MV_NONE); } void TestIfBadThingTouchesFriend(int x, int y) { TestIfBadThingHitsGoodThing(x, y, MV_NONE); } void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y) { int i, kill_x = bad_x, kill_y = bad_y; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; for (i = 0; i < NUM_DIRECTIONS; i++) { int x, y, element; x = bad_x + xy[i][0]; y = bad_y + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; element = Feld[x][y]; if (IS_AMOEBOID(element) || element == EL_GAME_OF_LIFE || element == EL_AMOEBA_GROWING || element == EL_AMOEBA_DROP) { kill_x = x; kill_y = y; break; } } if (kill_x != bad_x || kill_y != bad_y) Bang(bad_x, bad_y); } void KillPlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; if (!player->active) return; #if 0 printf("::: 0: killed == %d, active == %d, reanimated == %d\n", player->killed, player->active, player->reanimated); #endif /* the following code was introduced to prevent an infinite loop when calling -> Bang() -> CheckTriggeredElementChangeExt() -> ExecuteCustomElementAction() -> KillPlayer() -> (infinitely repeating the above sequence of function calls) which occurs when killing the player while having a CE with the setting "kill player X when explosion of "; the solution using a new field "player->killed" was chosen for backwards compatibility, although clever use of the fields "player->active" etc. would probably also work */ #if 1 if (player->killed) return; #endif player->killed = TRUE; /* remove accessible field at the player's position */ Feld[jx][jy] = EL_EMPTY; /* deactivate shield (else Bang()/Explode() would not work right) */ player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; #if 0 printf("::: 1: killed == %d, active == %d, reanimated == %d\n", player->killed, player->active, player->reanimated); #endif Bang(jx, jy); #if 0 printf("::: 2: killed == %d, active == %d, reanimated == %d\n", player->killed, player->active, player->reanimated); #endif if (player->reanimated) /* killed player may have been reanimated */ player->killed = player->reanimated = FALSE; else BuryPlayer(player); } static void KillPlayerUnlessEnemyProtected(int x, int y) { if (!PLAYER_ENEMY_PROTECTED(x, y)) KillPlayer(PLAYERINFO(x, y)); } static void KillPlayerUnlessExplosionProtected(int x, int y) { if (!PLAYER_EXPLOSION_PROTECTED(x, y)) KillPlayer(PLAYERINFO(x, y)); } void BuryPlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; if (!player->active) return; PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING); PlayLevelSound(jx, jy, SND_GAME_LOSING); player->GameOver = TRUE; RemovePlayer(player); } void RemovePlayer(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; int i, found = FALSE; player->present = FALSE; player->active = FALSE; if (!ExplodeField[jx][jy]) StorePlayer[jx][jy] = 0; if (player->is_moving) TEST_DrawLevelField(player->last_jx, player->last_jy); for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) found = TRUE; if (!found) AllPlayersGone = TRUE; ExitX = ZX = jx; ExitY = ZY = jy; } static void setFieldForSnapping(int x, int y, int element, int direction) { struct ElementInfo *ei = &element_info[element]; int direction_bit = MV_DIR_TO_BIT(direction); int graphic_snapping = ei->direction_graphic[ACTION_SNAPPING][direction_bit]; int action = (graphic_snapping != IMG_EMPTY_SPACE ? ACTION_SNAPPING : IS_DIGGABLE(element) ? ACTION_DIGGING : ACTION_COLLECTING); Feld[x][y] = EL_ELEMENT_SNAPPING; MovDelay[x][y] = MOVE_DELAY_NORMAL_SPEED + 1 - 1; ResetGfxAnimation(x, y); GfxElement[x][y] = element; GfxAction[x][y] = action; GfxDir[x][y] = direction; GfxFrame[x][y] = -1; } /* ============================================================================= checkDiagonalPushing() ----------------------------------------------------------------------------- check if diagonal input device direction results in pushing of object (by checking if the alternative direction is walkable, diggable, ...) ============================================================================= */ static boolean checkDiagonalPushing(struct PlayerInfo *player, int x, int y, int real_dx, int real_dy) { int jx, jy, dx, dy, xx, yy; if (real_dx == 0 || real_dy == 0) /* no diagonal direction => push */ return TRUE; /* diagonal direction: check alternative direction */ jx = player->jx; jy = player->jy; dx = x - jx; dy = y - jy; xx = jx + (dx == 0 ? real_dx : 0); yy = jy + (dy == 0 ? real_dy : 0); return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy])); } /* ============================================================================= DigField() ----------------------------------------------------------------------------- x, y: field next to player (non-diagonal) to try to dig to real_dx, real_dy: direction as read from input device (can be diagonal) ============================================================================= */ static int DigField(struct PlayerInfo *player, int oldx, int oldy, int x, int y, int real_dx, int real_dy, int mode) { boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG); boolean player_was_pushing = player->is_pushing; boolean player_can_move = (!player->cannot_move && mode != DF_SNAP); boolean player_can_move_or_snap = (!player->cannot_move || mode == DF_SNAP); int jx = oldx, jy = oldy; int dx = x - jx, dy = y - jy; int nextx = x + dx, nexty = y + dy; int move_direction = (dx == -1 ? MV_LEFT : dx == +1 ? MV_RIGHT : dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NONE); int opposite_direction = MV_DIR_OPPOSITE(move_direction); int dig_side = MV_DIR_OPPOSITE(move_direction); int old_element = Feld[jx][jy]; int element = MovingOrBlocked2ElementIfNotLeaving(x, y); int collect_count; if (is_player) /* function can also be called by EL_PENGUIN */ { if (player->MovPos == 0) { player->is_digging = FALSE; player->is_collecting = FALSE; } if (player->MovPos == 0) /* last pushing move finished */ player->is_pushing = FALSE; if (mode == DF_NO_PUSH) /* player just stopped pushing */ { player->is_switching = FALSE; player->push_delay = -1; return MP_NO_ACTION; } } if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; /* in case of element dropped at player position, check background */ else if (Back[jx][jy] != EL_EMPTY && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) { SplashAcid(x, y); Feld[jx][jy] = player->artwork_element; InitMovingField(jx, jy, MV_DOWN); Store[jx][jy] = EL_ACID; ContinueMoving(jx, jy); BuryPlayer(player); return MP_DONT_RUN_INTO; } if (player_can_move && DONT_RUN_INTO(element)) { TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); return MP_DONT_RUN_INTO; } if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MP_NO_ACTION; collect_count = element_info[element].collect_count_initial; if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */ return MP_NO_ACTION; if (game.engine_version < VERSION_IDENT(2,2,0,0)) player_can_move = player_can_move_or_snap; if (mode == DF_SNAP && !IS_SNAPPABLE(element) && game.engine_version >= VERSION_IDENT(2,2,0,0)) { CheckElementChangeByPlayer(x, y, element, CE_SNAPPED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); if (element == EL_DC_LANDMINE) Bang(x, y); if (Feld[x][y] != element) /* field changed by snapping */ return MP_ACTION; return MP_NO_ACTION; } if (player->gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MP_NO_ACTION; /* player cannot walk here due to gravity */ if (player_can_move && IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) { int sound_element = SND_ELEMENT(element); int sound_action = ACTION_WALKING; if (IS_RND_GATE(element)) { if (!player->key[RND_GATE_NR(element)]) return MP_NO_ACTION; } else if (IS_RND_GATE_GRAY(element)) { if (!player->key[RND_GATE_GRAY_NR(element)]) return MP_NO_ACTION; } else if (IS_RND_GATE_GRAY_ACTIVE(element)) { if (!player->key[RND_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } else if (element == EL_EXIT_OPEN || element == EL_EM_EXIT_OPEN || element == EL_EM_EXIT_OPENING || element == EL_STEEL_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPENING || element == EL_SP_EXIT_OPEN || element == EL_SP_EXIT_OPENING) { sound_action = ACTION_PASSING; /* player is passing exit */ } else if (element == EL_EMPTY) { sound_action = ACTION_MOVING; /* nothing to walk on */ } /* play sound from background or player, whatever is available */ if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED) PlayLevelSoundElementAction(x, y, sound_element, sound_action); else PlayLevelSoundElementAction(x, y, player->artwork_element, sound_action); } else if (player_can_move && IS_PASSABLE(element) && canPassField(x, y, move_direction)) { if (!ACCESS_FROM(element, opposite_direction)) return MP_NO_ACTION; /* field not accessible from this direction */ if (CAN_MOVE(element)) /* only fixed elements can be passed! */ return MP_NO_ACTION; if (IS_EM_GATE(element)) { if (!player->key[EM_GATE_NR(element)]) return MP_NO_ACTION; } else if (IS_EM_GATE_GRAY(element)) { if (!player->key[EM_GATE_GRAY_NR(element)]) return MP_NO_ACTION; } else if (IS_EM_GATE_GRAY_ACTIVE(element)) { if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } else if (IS_EMC_GATE(element)) { if (!player->key[EMC_GATE_NR(element)]) return MP_NO_ACTION; } else if (IS_EMC_GATE_GRAY(element)) { if (!player->key[EMC_GATE_GRAY_NR(element)]) return MP_NO_ACTION; } else if (IS_EMC_GATE_GRAY_ACTIVE(element)) { if (!player->key[EMC_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } else if (element == EL_DC_GATE_WHITE || element == EL_DC_GATE_WHITE_GRAY || element == EL_DC_GATE_WHITE_GRAY_ACTIVE) { if (player->num_white_keys == 0) return MP_NO_ACTION; player->num_white_keys--; } else if (IS_SP_PORT(element)) { if (element == EL_SP_GRAVITY_PORT_LEFT || element == EL_SP_GRAVITY_PORT_RIGHT || element == EL_SP_GRAVITY_PORT_UP || element == EL_SP_GRAVITY_PORT_DOWN) player->gravity = !player->gravity; else if (element == EL_SP_GRAVITY_ON_PORT_LEFT || element == EL_SP_GRAVITY_ON_PORT_RIGHT || element == EL_SP_GRAVITY_ON_PORT_UP || element == EL_SP_GRAVITY_ON_PORT_DOWN) player->gravity = TRUE; else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT || element == EL_SP_GRAVITY_OFF_PORT_RIGHT || element == EL_SP_GRAVITY_OFF_PORT_UP || element == EL_SP_GRAVITY_OFF_PORT_DOWN) player->gravity = FALSE; } /* automatically move to the next field with double speed */ player->programmed_action = move_direction; if (player->move_delay_reset_counter == 0) { player->move_delay_reset_counter = 2; /* two double speed steps */ DOUBLE_PLAYER_SPEED(player); } PlayLevelSoundAction(x, y, ACTION_PASSING); } else if (player_can_move_or_snap && IS_DIGGABLE(element)) { RemoveField(x, y); if (mode != DF_SNAP) { GfxElement[x][y] = GFX_ELEMENT(element); player->is_digging = TRUE; } PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X, player->index_bit, dig_side); if (mode == DF_SNAP) { if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else TestIfElementTouchesCustomElement(x, y); /* for empty space */ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); } } else if (player_can_move_or_snap && IS_COLLECTIBLE(element)) { RemoveField(x, y); if (is_player && mode != DF_SNAP) { GfxElement[x][y] = element; player->is_collecting = TRUE; } if (element == EL_SPEED_PILL) { player->move_delay_value = MOVE_DELAY_HIGH_SPEED; } else if (element == EL_EXTRA_TIME && level.time > 0) { TimeLeft += level.extra_time; game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); } else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) { player->shield_normal_time_left += level.shield_normal_time; if (element == EL_SHIELD_DEADLY) player->shield_deadly_time_left += level.shield_deadly_time; } else if (element == EL_DYNAMITE || element == EL_EM_DYNAMITE || element == EL_SP_DISK_RED) { if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; DrawGameDoorValues(); } else if (element == EL_DYNABOMB_INCREASE_NUMBER) { player->dynabomb_count++; player->dynabombs_left++; } else if (element == EL_DYNABOMB_INCREASE_SIZE) { player->dynabomb_size++; } else if (element == EL_DYNABOMB_INCREASE_POWER) { player->dynabomb_xl = TRUE; } else if (IS_KEY(element)) { player->key[KEY_NR(element)] = TRUE; DrawGameDoorValues(); } else if (element == EL_DC_KEY_WHITE) { player->num_white_keys++; /* display white keys? */ /* DrawGameDoorValues(); */ } else if (IS_ENVELOPE(element)) { player->show_envelope = element; } else if (element == EL_EMC_LENSES) { game.lenses_time_left = level.lenses_time * FRAMES_PER_SECOND; RedrawAllInvisibleElementsForLenses(); } else if (element == EL_EMC_MAGNIFIER) { game.magnify_time_left = level.magnify_time * FRAMES_PER_SECOND; RedrawAllInvisibleElementsForMagnifier(); } else if (IS_DROPPABLE(element) || IS_THROWABLE(element)) /* can be collected and dropped */ { int i; if (collect_count == 0) player->inventory_infinite_element = element; else for (i = 0; i < collect_count; i++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; DrawGameDoorValues(); } else if (collect_count > 0) { local_player->gems_still_needed -= collect_count; if (local_player->gems_still_needed < 0) local_player->gems_still_needed = 0; game.snapshot.collected_item = TRUE; game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); } RaiseScoreElement(element); PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); if (is_player) CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_COLLECTS_X, player->index_bit, dig_side); if (mode == DF_SNAP) { if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else TestIfElementTouchesCustomElement(x, y); /* for empty space */ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); } } else if (player_can_move_or_snap && IS_PUSHABLE(element)) { if (mode == DF_SNAP && element != EL_BD_ROCK) return MP_NO_ACTION; if (CAN_FALL(element) && dy) return MP_NO_ACTION; if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) && !(element == EL_SPRING && level.use_spring_bug)) return MP_NO_ACTION; if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 && ((move_direction & MV_VERTICAL && ((element_info[element].move_pattern & MV_LEFT && IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) || (element_info[element].move_pattern & MV_RIGHT && IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) || (move_direction & MV_HORIZONTAL && ((element_info[element].move_pattern & MV_UP && IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) || (element_info[element].move_pattern & MV_DOWN && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1)))))) return MP_NO_ACTION; /* do not push elements already moving away faster than player */ if (CAN_MOVE(element) && MovDir[x][y] == move_direction && ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL) return MP_NO_ACTION; if (game.engine_version >= VERSION_IDENT(3,1,0,0)) { if (player->push_delay_value == -1 || !player_was_pushing) player->push_delay_value = GET_NEW_PUSH_DELAY(element); } else if (game.engine_version >= VERSION_IDENT(3,0,7,1)) { if (player->push_delay_value == -1) player->push_delay_value = GET_NEW_PUSH_DELAY(element); } else if (game.engine_version >= VERSION_IDENT(2,2,0,7)) { if (!player->is_pushing) player->push_delay_value = GET_NEW_PUSH_DELAY(element); } player->is_pushing = TRUE; player->is_active = TRUE; if (!(IN_LEV_FIELD(nextx, nexty) && (IS_FREE(nextx, nexty) || (IS_SB_ELEMENT(element) && Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) || (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty))))) return MP_NO_ACTION; if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) return MP_NO_ACTION; if (player->push_delay == -1) /* new pushing; restart delay */ player->push_delay = 0; if (player->push_delay < player->push_delay_value && !(tape.playing && tape.file_version < FILE_VERSION_2_0) && element != EL_SPRING && element != EL_BALLOON) { /* make sure that there is no move delay before next try to push */ if (game.engine_version >= VERSION_IDENT(3,0,7,1)) player->move_delay = 0; return MP_NO_ACTION; } if (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty)) { if (!DigFieldByCE(nextx, nexty, element)) return MP_NO_ACTION; } if (IS_SB_ELEMENT(element)) { if (element == EL_SOKOBAN_FIELD_FULL) { Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; local_player->sokobanfields_still_needed++; } if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) { Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY; local_player->sokobanfields_still_needed--; } Feld[x][y] = EL_SOKOBAN_OBJECT; if (Back[x][y] == Back[nextx][nexty]) PlayLevelSoundAction(x, y, ACTION_PUSHING); else if (Back[x][y] != 0) PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL, ACTION_EMPTYING); else PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, ACTION_FILLING); if (local_player->sokobanfields_still_needed == 0 && (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban)) { PlayerWins(player); PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); } } else PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); InitMovingField(x, y, move_direction); GfxAction[x][y] = ACTION_PUSHING; if (mode == DF_SNAP) ContinueMoving(x, y); else MovPos[x][y] = (dx != 0 ? dx : dy); Pushed[x][y] = TRUE; Pushed[nextx][nexty] = TRUE; if (game.engine_version < VERSION_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); else player->push_delay_value = -1; /* get new value later */ /* check for element change _after_ element has been pushed */ if (game.use_change_when_pushing_bug) { CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X, player->index_bit, dig_side); } } else if (IS_SWITCHABLE(element)) { if (PLAYER_SWITCHING(player, x, y)) { CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MP_ACTION; } player->is_switching = TRUE; player->switch_x = x; player->switch_y = y; PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); if (element == EL_ROBOT_WHEEL) { Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; ZX = x; ZY = y; game.robot_wheel_active = TRUE; TEST_DrawLevelField(x, y); } else if (element == EL_SP_TERMINAL) { int xx, yy; SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == EL_SP_DISK_YELLOW) { Bang(xx, yy); } else if (Feld[xx][yy] == EL_SP_TERMINAL) { Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE; ResetGfxAnimation(xx, yy); TEST_DrawLevelField(xx, yy); } } } else if (IS_BELT_SWITCH(element)) { ToggleBeltSwitch(x, y); } else if (element == EL_SWITCHGATE_SWITCH_UP || element == EL_SWITCHGATE_SWITCH_DOWN || element == EL_DC_SWITCHGATE_SWITCH_UP || element == EL_DC_SWITCHGATE_SWITCH_DOWN) { ToggleSwitchgateSwitch(x, y); } else if (element == EL_LIGHT_SWITCH || element == EL_LIGHT_SWITCH_ACTIVE) { ToggleLightSwitch(x, y); } else if (element == EL_TIMEGATE_SWITCH || element == EL_DC_TIMEGATE_SWITCH) { ActivateTimegateSwitch(x, y); } else if (element == EL_BALLOON_SWITCH_LEFT || element == EL_BALLOON_SWITCH_RIGHT || element == EL_BALLOON_SWITCH_UP || element == EL_BALLOON_SWITCH_DOWN || element == EL_BALLOON_SWITCH_NONE || element == EL_BALLOON_SWITCH_ANY) { game.wind_direction = (element == EL_BALLOON_SWITCH_LEFT ? MV_LEFT : element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT : element == EL_BALLOON_SWITCH_UP ? MV_UP : element == EL_BALLOON_SWITCH_DOWN ? MV_DOWN : element == EL_BALLOON_SWITCH_NONE ? MV_NONE : move_direction); } else if (element == EL_LAMP) { Feld[x][y] = EL_LAMP_ACTIVE; local_player->lights_still_needed--; ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } else if (element == EL_TIME_ORB_FULL) { Feld[x][y] = EL_TIME_ORB_EMPTY; if (level.time > 0 || level.use_time_orb_bug) { TimeLeft += level.time_orb_time; game.no_time_limit = FALSE; game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); } ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); } else if (element == EL_EMC_MAGIC_BALL_SWITCH || element == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) { int xx, yy; game.ball_state = !game.ball_state; SCAN_PLAYFIELD(xx, yy) { int e = Feld[xx][yy]; if (game.ball_state) { if (e == EL_EMC_MAGIC_BALL) CreateField(xx, yy, EL_EMC_MAGIC_BALL_ACTIVE); else if (e == EL_EMC_MAGIC_BALL_SWITCH) CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE); } else { if (e == EL_EMC_MAGIC_BALL_ACTIVE) CreateField(xx, yy, EL_EMC_MAGIC_BALL); else if (e == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH); } } } CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SWITCHES_X, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MP_ACTION; } else { if (!PLAYER_SWITCHING(player, x, y)) { player->is_switching = TRUE; player->switch_x = x; player->switch_y = y; CheckElementChangeByPlayer(x, y, element, CE_SWITCHED, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X, player->index_bit, dig_side); CheckElementChangeByPlayer(x, y, element, CE_SWITCHED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SWITCHES_X, player->index_bit, dig_side); } CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER, player->index_bit, dig_side); CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X, player->index_bit, dig_side); return MP_NO_ACTION; } player->push_delay = -1; if (is_player) /* function can also be called by EL_PENGUIN */ { if (Feld[x][y] != element) /* really digged/collected something */ { player->is_collecting = !player->is_digging; player->is_active = TRUE; } } return MP_MOVING; } static boolean DigFieldByCE(int x, int y, int digging_element) { int element = Feld[x][y]; if (!IS_FREE(x, y)) { int action = (IS_DIGGABLE(element) ? ACTION_DIGGING : IS_COLLECTIBLE(element) ? ACTION_COLLECTING : ACTION_BREAKING); /* no element can dig solid indestructible elements */ if (IS_INDESTRUCTIBLE(element) && !IS_DIGGABLE(element) && !IS_COLLECTIBLE(element)) return FALSE; if (AmoebaNr[x][y] && (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA || element == EL_AMOEBA_GROWING)) { AmoebaCnt[AmoebaNr[x][y]]--; AmoebaCnt2[AmoebaNr[x][y]]--; } if (IS_MOVING(x, y)) RemoveMovingField(x, y); else { RemoveField(x, y); TEST_DrawLevelField(x, y); } /* if digged element was about to explode, prevent the explosion */ ExplodeField[x][y] = EX_TYPE_NONE; PlayLevelSoundAction(x, y, action); } Store[x][y] = EL_EMPTY; /* this makes it possible to leave the removed element again */ if (IS_EQUAL_OR_IN_GROUP(element, MOVE_ENTER_EL(digging_element))) Store[x][y] = element; return TRUE; } static boolean SnapField(struct PlayerInfo *player, int dx, int dy) { int jx = player->jx, jy = player->jy; int x = jx + dx, y = jy + dy; int snap_direction = (dx == -1 ? MV_LEFT : dx == +1 ? MV_RIGHT : dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NONE); boolean can_continue_snapping = (level.continuous_snapping && WasJustFalling[x][y] < CHECK_DELAY_FALLING); if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0)) return FALSE; if (!player->active || !IN_LEV_FIELD(x, y)) return FALSE; if (dx && dy) return FALSE; if (!dx && !dy) { if (player->MovPos == 0) player->is_pushing = FALSE; player->is_snapping = FALSE; if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } return FALSE; } /* prevent snapping with already pressed snap key when not allowed */ if (player->is_snapping && !can_continue_snapping) return FALSE; player->MovDir = snap_direction; if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MP_NO_ACTION) return FALSE; player->is_snapping = TRUE; player->is_active = TRUE; if (player->MovPos == 0) { player->is_moving = FALSE; player->is_digging = FALSE; player->is_collecting = FALSE; } if (player->MovPos != 0) /* prevent graphic bugs in versions < 2.2.0 */ TEST_DrawLevelField(player->last_jx, player->last_jy); TEST_DrawLevelField(x, y); return TRUE; } static boolean DropElement(struct PlayerInfo *player) { int old_element, new_element; int dropx = player->jx, dropy = player->jy; int drop_direction = player->MovDir; int drop_side = drop_direction; int drop_element = get_next_dropped_element(player); /* do not drop an element on top of another element; when holding drop key pressed without moving, dropped element must move away before the next element can be dropped (this is especially important if the next element is dynamite, which can be placed on background for historical reasons) */ if (PLAYER_DROPPING(player, dropx, dropy) && Feld[dropx][dropy] != EL_EMPTY) return MP_ACTION; if (IS_THROWABLE(drop_element)) { dropx += GET_DX_FROM_DIR(drop_direction); dropy += GET_DY_FROM_DIR(drop_direction); if (!IN_LEV_FIELD(dropx, dropy)) return FALSE; } old_element = Feld[dropx][dropy]; /* old element at dropping position */ new_element = drop_element; /* default: no change when dropping */ /* check if player is active, not moving and ready to drop */ if (!player->active || player->MovPos || player->drop_delay > 0) return FALSE; /* check if player has anything that can be dropped */ if (new_element == EL_UNDEFINED) return FALSE; /* only set if player has anything that can be dropped */ player->is_dropping_pressed = TRUE; /* check if drop key was pressed long enough for EM style dynamite */ if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40) return FALSE; /* check if anything can be dropped at the current position */ if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION) return FALSE; /* collected custom elements can only be dropped on empty fields */ if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY) return FALSE; if (old_element != EL_EMPTY) Back[dropx][dropy] = old_element; /* store old element on this field */ ResetGfxAnimation(dropx, dropy); ResetRandomAnimationValue(dropx, dropy); if (player->inventory_size > 0 || player->inventory_infinite_element != EL_UNDEFINED) { if (player->inventory_size > 0) { player->inventory_size--; DrawGameDoorValues(); if (new_element == EL_DYNAMITE) new_element = EL_DYNAMITE_ACTIVE; else if (new_element == EL_EM_DYNAMITE) new_element = EL_EM_DYNAMITE_ACTIVE; else if (new_element == EL_SP_DISK_RED) new_element = EL_SP_DISK_RED_ACTIVE; } Feld[dropx][dropy] = new_element; if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy))) DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy), el2img(Feld[dropx][dropy]), 0); PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); /* needed if previous element just changed to "empty" in the last frame */ ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element, CE_PLAYER_DROPS_X, player->index_bit, drop_side); TestIfElementTouchesCustomElement(dropx, dropy); } else /* player is dropping a dyna bomb */ { player->dynabombs_left--; Feld[dropx][dropy] = new_element; if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy))) DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy), el2img(Feld[dropx][dropy]), 0); PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); } if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */ InitField_WithBug1(dropx, dropy, FALSE); new_element = Feld[dropx][dropy]; /* element might have changed */ if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && element_info[new_element].move_pattern == MV_WHEN_DROPPED) { if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC) MovDir[dropx][dropy] = drop_direction; ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ /* do not cause impact style collision by dropping elements that can fall */ CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; } player->drop_delay = GET_NEW_DROP_DELAY(drop_element); player->is_dropping = TRUE; player->drop_pressed_delay = 0; player->is_dropping_pressed = FALSE; player->drop_x = dropx; player->drop_y = dropy; return TRUE; } /* ------------------------------------------------------------------------- */ /* game sound playing functions */ /* ------------------------------------------------------------------------- */ static int *loop_sound_frame = NULL; static int *loop_sound_volume = NULL; void InitPlayLevelSound() { int num_sounds = getSoundListSize(); checked_free(loop_sound_frame); checked_free(loop_sound_volume); loop_sound_frame = checked_calloc(num_sounds * sizeof(int)); loop_sound_volume = checked_calloc(num_sounds * sizeof(int)); } static void PlayLevelSound(int x, int y, int nr) { int sx = SCREENX(x), sy = SCREENY(y); int volume, stereo_position; int max_distance = 8; int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND); if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) || (!setup.sound_loops && IS_LOOP_SOUND(nr))) return; if (!IN_LEV_FIELD(x, y) || sx < -max_distance || sx >= SCR_FIELDX + max_distance || sy < -max_distance || sy >= SCR_FIELDY + max_distance) return; volume = SOUND_MAX_VOLUME; if (!IN_SCR_FIELD(sx, sy)) { int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2; int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2; volume -= volume * (dx > dy ? dx : dy) / max_distance; } stereo_position = (SOUND_MAX_LEFT + (sx + max_distance) * SOUND_MAX_LEFT2RIGHT / (SCR_FIELDX + 2 * max_distance)); if (IS_LOOP_SOUND(nr)) { /* This assures that quieter loop sounds do not overwrite louder ones, while restarting sound volume comparison with each new game frame. */ if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter) return; loop_sound_volume[nr] = volume; loop_sound_frame[nr] = FrameCounter; } PlaySoundExt(nr, volume, stereo_position, type); } static void PlayLevelSoundNearest(int x, int y, int sound_action) { PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) : x > LEVELX(BX2) ? LEVELX(BX2) : x, y < LEVELY(BY1) ? LEVELY(BY1) : y > LEVELY(BY2) ? LEVELY(BY2) : y, sound_action); } static void PlayLevelSoundAction(int x, int y, int action) { PlayLevelSoundElementAction(x, y, Feld[x][y], action); } static void PlayLevelSoundElementAction(int x, int y, int element, int action) { int sound_effect = element_info[SND_ELEMENT(element)].sound[action]; if (sound_effect != SND_UNDEFINED) PlayLevelSound(x, y, sound_effect); } static void PlayLevelSoundElementActionIfLoop(int x, int y, int element, int action) { int sound_effect = element_info[SND_ELEMENT(element)].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) PlayLevelSound(x, y, sound_effect); } static void PlayLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) PlayLevelSound(x, y, sound_effect); } static void StopLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) StopSound(sound_effect); } static int getLevelMusicNr() { if (levelset.music[level_nr] != MUS_UNDEFINED) return levelset.music[level_nr]; /* from config file */ else return MAP_NOCONF_MUSIC(level_nr); /* from music dir */ } static void FadeLevelSounds() { FadeSounds(); } static void FadeLevelMusic() { int music_nr = getLevelMusicNr(); char *curr_music = getCurrentlyPlayingMusicFilename(); char *next_music = getMusicInfoEntryFilename(music_nr); if (!strEqual(curr_music, next_music)) FadeMusic(); } void FadeLevelSoundsAndMusic() { FadeLevelSounds(); FadeLevelMusic(); } static void PlayLevelMusic() { int music_nr = getLevelMusicNr(); char *curr_music = getCurrentlyPlayingMusicFilename(); char *next_music = getMusicInfoEntryFilename(music_nr); if (!strEqual(curr_music, next_music)) PlayMusic(music_nr); } void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) { int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0); int offset = (BorderElement == EL_STEELWALL ? 1 : 0); int x = xx - 1 - offset; int y = yy - 1 - offset; switch (sample) { case SAMPLE_blank: PlayLevelSoundElementAction(x, y, element, ACTION_WALKING); break; case SAMPLE_roll: PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); break; case SAMPLE_stone: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_nut: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_crack: PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING); break; case SAMPLE_bug: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_tank: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_android_clone: PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING); break; case SAMPLE_android_move: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_spring: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_slurp: PlayLevelSoundElementAction(x, y, element, ACTION_EATING); break; case SAMPLE_eater: PlayLevelSoundElementAction(x, y, element, ACTION_WAITING); break; case SAMPLE_eater_eat: PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); break; case SAMPLE_alien: PlayLevelSoundElementAction(x, y, element, ACTION_MOVING); break; case SAMPLE_collect: PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); break; case SAMPLE_diamond: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_squash: /* !!! CHECK THIS !!! */ #if 1 PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING); #else PlayLevelSoundElementAction(x, y, element, ACTION_SMASHED_BY_ROCK); #endif break; case SAMPLE_wonderfall: PlayLevelSoundElementAction(x, y, element, ACTION_FILLING); break; case SAMPLE_drip: PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); break; case SAMPLE_push: PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); break; case SAMPLE_dirt: PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); break; case SAMPLE_acid: PlayLevelSoundElementAction(x, y, element, ACTION_SPLASHING); break; case SAMPLE_ball: PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING); break; case SAMPLE_grow: PlayLevelSoundElementAction(x, y, element, ACTION_GROWING); break; case SAMPLE_wonder: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE); break; case SAMPLE_door: PlayLevelSoundElementAction(x, y, element, ACTION_PASSING); break; case SAMPLE_exit_open: PlayLevelSoundElementAction(x, y, element, ACTION_OPENING); break; case SAMPLE_exit_leave: PlayLevelSoundElementAction(x, y, element, ACTION_PASSING); break; case SAMPLE_dynamite: PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING); break; case SAMPLE_tick: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE); break; case SAMPLE_press: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); break; case SAMPLE_wheel: PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE); break; case SAMPLE_boom: PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING); break; case SAMPLE_die: PlayLevelSoundElementAction(x, y, element, ACTION_DYING); break; case SAMPLE_time: PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); break; default: PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT); break; } } void PlayLevelSound_SP(int xx, int yy, int element_sp, int action_sp) { int element = map_element_SP_to_RND(element_sp); int action = map_action_SP_to_RND(action_sp); int offset = (setup.sp_show_border_elements ? 0 : 1); int x = xx - offset; int y = yy - offset; PlayLevelSoundElementAction(x, y, element, action); } void PlayLevelSound_MM(int xx, int yy, int element_mm, int action_mm) { int element = map_element_MM_to_RND(element_mm); int action = map_action_MM_to_RND(action_mm); int offset = 0; int x = xx - offset; int y = yy - offset; if (!IS_MM_ELEMENT(element)) element = EL_MM_DEFAULT; PlayLevelSoundElementAction(x, y, element, action); } void PlaySound_MM(int sound_mm) { int sound = map_sound_MM_to_RND(sound_mm); if (sound == SND_UNDEFINED) return; PlaySound(sound); } void PlaySoundLoop_MM(int sound_mm) { int sound = map_sound_MM_to_RND(sound_mm); if (sound == SND_UNDEFINED) return; PlaySoundLoop(sound); } void StopSound_MM(int sound_mm) { int sound = map_sound_MM_to_RND(sound_mm); if (sound == SND_UNDEFINED) return; StopSound(sound); } void RaiseScore(int value) { local_player->score += value; game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); } void RaiseScoreElement(int element) { switch (element) { case EL_EMERALD: case EL_BD_DIAMOND: case EL_EMERALD_YELLOW: case EL_EMERALD_RED: case EL_EMERALD_PURPLE: case EL_SP_INFOTRON: RaiseScore(level.score[SC_EMERALD]); break; case EL_DIAMOND: RaiseScore(level.score[SC_DIAMOND]); break; case EL_CRYSTAL: RaiseScore(level.score[SC_CRYSTAL]); break; case EL_PEARL: RaiseScore(level.score[SC_PEARL]); break; case EL_BUG: case EL_BD_BUTTERFLY: case EL_SP_ELECTRON: RaiseScore(level.score[SC_BUG]); break; case EL_SPACESHIP: case EL_BD_FIREFLY: case EL_SP_SNIKSNAK: RaiseScore(level.score[SC_SPACESHIP]); break; case EL_YAMYAM: case EL_DARK_YAMYAM: RaiseScore(level.score[SC_YAMYAM]); break; case EL_ROBOT: RaiseScore(level.score[SC_ROBOT]); break; case EL_PACMAN: RaiseScore(level.score[SC_PACMAN]); break; case EL_NUT: RaiseScore(level.score[SC_NUT]); break; case EL_DYNAMITE: case EL_EM_DYNAMITE: case EL_SP_DISK_RED: case EL_DYNABOMB_INCREASE_NUMBER: case EL_DYNABOMB_INCREASE_SIZE: case EL_DYNABOMB_INCREASE_POWER: RaiseScore(level.score[SC_DYNAMITE]); break; case EL_SHIELD_NORMAL: case EL_SHIELD_DEADLY: RaiseScore(level.score[SC_SHIELD]); break; case EL_EXTRA_TIME: RaiseScore(level.extra_time_score); break; case EL_KEY_1: case EL_KEY_2: case EL_KEY_3: case EL_KEY_4: case EL_EM_KEY_1: case EL_EM_KEY_2: case EL_EM_KEY_3: case EL_EM_KEY_4: case EL_EMC_KEY_5: case EL_EMC_KEY_6: case EL_EMC_KEY_7: case EL_EMC_KEY_8: case EL_DC_KEY_WHITE: RaiseScore(level.score[SC_KEY]); break; default: RaiseScore(element_info[element].collect_score); break; } } void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) { if (skip_request || Request(message, REQ_ASK | REQ_STAY_CLOSED)) { /* closing door required in case of envelope style request dialogs */ if (!skip_request) CloseDoor(DOOR_CLOSE_1); #if defined(NETWORK_AVALIABLE) if (options.network) SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); else #endif { if (quick_quit) FadeSkipNextFadeIn(); SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } } else /* continue playing the game */ { if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOn(); } } void RequestQuitGame(boolean ask_if_really_quit) { boolean quick_quit = (!ask_if_really_quit || level_editor_test_game); boolean skip_request = AllPlayersGone || quick_quit; RequestQuitGameExt(skip_request, quick_quit, "Do you really want to quit the game?"); } void RequestRestartGame(char *message) { game.restart_game_message = NULL; if (Request(message, REQ_ASK | REQ_STAY_CLOSED)) { StartGameActions(options.network, setup.autorecord, level.random_seed); } else { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } } /* ------------------------------------------------------------------------- */ /* random generator functions */ /* ------------------------------------------------------------------------- */ unsigned int InitEngineRandom_RND(int seed) { game.num_random_calls = 0; return InitEngineRandom(seed); } unsigned int RND(int max) { if (max > 0) { game.num_random_calls++; return GetEngineRandom(max); } return 0; } /* ------------------------------------------------------------------------- */ /* game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ struct EngineSnapshotInfo { /* runtime values for custom element collect score */ int collect_score[NUM_CUSTOM_ELEMENTS]; /* runtime values for group element choice position */ int choice_pos[NUM_GROUP_ELEMENTS]; /* runtime values for belt position animations */ int belt_graphic[4][NUM_BELT_PARTS]; int belt_anim_mode[4][NUM_BELT_PARTS]; }; static struct EngineSnapshotInfo engine_snapshot_rnd; static char *snapshot_level_identifier = NULL; static int snapshot_level_nr = -1; static void SaveEngineSnapshotValues_RND() { static int belt_base_active_element[4] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }; int i, j; for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; engine_snapshot_rnd.collect_score[i] = element_info[element].collect_score; } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int element = EL_GROUP_START + i; engine_snapshot_rnd.choice_pos[i] = element_info[element].group->choice_pos; } for (i = 0; i < 4; i++) { for (j = 0; j < NUM_BELT_PARTS; j++) { int element = belt_base_active_element[i] + j; int graphic = el2img(element); int anim_mode = graphic_info[graphic].anim_mode; engine_snapshot_rnd.belt_graphic[i][j] = graphic; engine_snapshot_rnd.belt_anim_mode[i][j] = anim_mode; } } } static void LoadEngineSnapshotValues_RND() { unsigned int num_random_calls = game.num_random_calls; int i, j; for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; element_info[element].collect_score = engine_snapshot_rnd.collect_score[i]; } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int element = EL_GROUP_START + i; element_info[element].group->choice_pos = engine_snapshot_rnd.choice_pos[i]; } for (i = 0; i < 4; i++) { for (j = 0; j < NUM_BELT_PARTS; j++) { int graphic = engine_snapshot_rnd.belt_graphic[i][j]; int anim_mode = engine_snapshot_rnd.belt_anim_mode[i][j]; graphic_info[graphic].anim_mode = anim_mode; } } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { InitRND(tape.random_seed); for (i = 0; i < num_random_calls; i++) RND(1); } if (game.num_random_calls != num_random_calls) { Error(ERR_INFO, "number of random calls out of sync"); Error(ERR_INFO, "number of random calls should be %d", num_random_calls); Error(ERR_INFO, "number of random calls is %d", game.num_random_calls); Error(ERR_EXIT, "this should not happen -- please debug"); } } void FreeEngineSnapshotSingle() { FreeSnapshotSingle(); setString(&snapshot_level_identifier, NULL); snapshot_level_nr = -1; } void FreeEngineSnapshotList() { FreeSnapshotList(); } ListNode *SaveEngineSnapshotBuffers() { ListNode *buffers = NULL; /* copy some special values to a structure better suited for the snapshot */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) SaveEngineSnapshotValues_RND(); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) SaveEngineSnapshotValues_EM(); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) SaveEngineSnapshotValues_SP(&buffers); if (level.game_engine_type == GAME_ENGINE_TYPE_MM) SaveEngineSnapshotValues_MM(&buffers); /* save values stored in special snapshot structure */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); if (level.game_engine_type == GAME_ENGINE_TYPE_MM) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_mm)); /* save further RND engine values */ SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(stored_player)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(game)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(tape)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZX)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZY)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitX)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitY)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTime)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Feld)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovPos)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDir)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDelay)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeDelay)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangePage)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CustomValue)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Store)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Store2)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(StorePlayer)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Back)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaNr)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CheckImpact)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Stop)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Pushed)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeCount)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeEvent)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodePhase)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodeField)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(RunnerVisit)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(PlayerVisit)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandom)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElement)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxAction)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxDir)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(scroll_x)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(scroll_y)); #if 0 ListNode *node = engine_snapshot_list_rnd; int num_bytes = 0; while (node != NULL) { num_bytes += ((struct EngineSnapshotNodeInfo *)node->content)->size; node = node->next; } printf("::: size of engine snapshot: %d bytes\n", num_bytes); #endif return buffers; } void SaveEngineSnapshotSingle() { ListNode *buffers = SaveEngineSnapshotBuffers(); /* finally save all snapshot buffers to single snapshot */ SaveSnapshotSingle(buffers); /* save level identification information */ setString(&snapshot_level_identifier, leveldir_current->identifier); snapshot_level_nr = level_nr; } boolean CheckSaveEngineSnapshotToList() { boolean save_snapshot = ((game.snapshot.mode == SNAPSHOT_MODE_EVERY_STEP) || (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE && game.snapshot.changed_action) || (game.snapshot.mode == SNAPSHOT_MODE_EVERY_COLLECT && game.snapshot.collected_item)); game.snapshot.changed_action = FALSE; game.snapshot.collected_item = FALSE; game.snapshot.save_snapshot = save_snapshot; return save_snapshot; } void SaveEngineSnapshotToList() { if (game.snapshot.mode == SNAPSHOT_MODE_OFF || tape.quick_resume) return; ListNode *buffers = SaveEngineSnapshotBuffers(); /* finally save all snapshot buffers to snapshot list */ SaveSnapshotToList(buffers); } void SaveEngineSnapshotToListInitial() { FreeEngineSnapshotList(); SaveEngineSnapshotToList(); } void LoadEngineSnapshotValues() { /* restore special values from snapshot structure */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) LoadEngineSnapshotValues_RND(); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) LoadEngineSnapshotValues_EM(); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) LoadEngineSnapshotValues_SP(); if (level.game_engine_type == GAME_ENGINE_TYPE_MM) LoadEngineSnapshotValues_MM(); } void LoadEngineSnapshotSingle() { LoadSnapshotSingle(); LoadEngineSnapshotValues(); } void LoadEngineSnapshot_Undo(int steps) { LoadSnapshotFromList_Older(steps); LoadEngineSnapshotValues(); } void LoadEngineSnapshot_Redo(int steps) { LoadSnapshotFromList_Newer(steps); LoadEngineSnapshotValues(); } boolean CheckEngineSnapshotSingle() { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && snapshot_level_nr == level_nr); } boolean CheckEngineSnapshotList() { return CheckSnapshotList(); } /* ---------- new game button stuff ---------------------------------------- */ static struct { int graphic; struct XY *pos; int gadget_id; boolean *setup_value; boolean allowed_on_tape; char *infotext; } gamebutton_info[NUM_GAME_BUTTONS] = { { IMG_GFX_GAME_BUTTON_STOP, &game.button.stop, GAME_CTRL_ID_STOP, NULL, TRUE, "stop game" }, { IMG_GFX_GAME_BUTTON_PAUSE, &game.button.pause, GAME_CTRL_ID_PAUSE, NULL, TRUE, "pause game" }, { IMG_GFX_GAME_BUTTON_PLAY, &game.button.play, GAME_CTRL_ID_PLAY, NULL, TRUE, "play game" }, { IMG_GFX_GAME_BUTTON_UNDO, &game.button.undo, GAME_CTRL_ID_UNDO, NULL, TRUE, "undo step" }, { IMG_GFX_GAME_BUTTON_REDO, &game.button.redo, GAME_CTRL_ID_REDO, NULL, TRUE, "redo step" }, { IMG_GFX_GAME_BUTTON_SAVE, &game.button.save, GAME_CTRL_ID_SAVE, NULL, TRUE, "save game" }, { IMG_GFX_GAME_BUTTON_PAUSE2, &game.button.pause2, GAME_CTRL_ID_PAUSE2, NULL, TRUE, "pause game" }, { IMG_GFX_GAME_BUTTON_LOAD, &game.button.load, GAME_CTRL_ID_LOAD, NULL, TRUE, "load game" }, { IMG_GFX_GAME_BUTTON_PANEL_STOP, &game.button.panel_stop, GAME_CTRL_ID_PANEL_STOP, NULL, FALSE, "stop game" }, { IMG_GFX_GAME_BUTTON_PANEL_PAUSE, &game.button.panel_pause, GAME_CTRL_ID_PANEL_PAUSE, NULL, FALSE, "pause game" }, { IMG_GFX_GAME_BUTTON_PANEL_PLAY, &game.button.panel_play, GAME_CTRL_ID_PANEL_PLAY, NULL, FALSE, "play game" }, { IMG_GFX_GAME_BUTTON_SOUND_MUSIC, &game.button.sound_music, SOUND_CTRL_ID_MUSIC, &setup.sound_music, TRUE, "background music on/off" }, { IMG_GFX_GAME_BUTTON_SOUND_LOOPS, &game.button.sound_loops, SOUND_CTRL_ID_LOOPS, &setup.sound_loops, TRUE, "sound loops on/off" }, { IMG_GFX_GAME_BUTTON_SOUND_SIMPLE, &game.button.sound_simple, SOUND_CTRL_ID_SIMPLE, &setup.sound_simple, TRUE, "normal sounds on/off" }, { IMG_GFX_GAME_BUTTON_PANEL_SOUND_MUSIC, &game.button.panel_sound_music, SOUND_CTRL_ID_PANEL_MUSIC, &setup.sound_music, FALSE, "background music on/off" }, { IMG_GFX_GAME_BUTTON_PANEL_SOUND_LOOPS, &game.button.panel_sound_loops, SOUND_CTRL_ID_PANEL_LOOPS, &setup.sound_loops, FALSE, "sound loops on/off" }, { IMG_GFX_GAME_BUTTON_PANEL_SOUND_SIMPLE, &game.button.panel_sound_simple, SOUND_CTRL_ID_PANEL_SIMPLE, &setup.sound_simple, FALSE, "normal sounds on/off" } }; void CreateGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) { struct GraphicInfo *gfx = &graphic_info[gamebutton_info[i].graphic]; struct XY *pos = gamebutton_info[i].pos; struct GadgetInfo *gi; int button_type; boolean checked; unsigned int event_mask; boolean allowed_on_tape = gamebutton_info[i].allowed_on_tape; boolean on_tape = (tape.show_game_buttons && allowed_on_tape); int base_x = (on_tape ? VX : DX); int base_y = (on_tape ? VY : DY); int gd_x = gfx->src_x; int gd_y = gfx->src_y; int gd_xp = gfx->src_x + gfx->pressed_xoffset; int gd_yp = gfx->src_y + gfx->pressed_yoffset; int gd_xa = gfx->src_x + gfx->active_xoffset; int gd_ya = gfx->src_y + gfx->active_yoffset; int gd_xap = gfx->src_x + gfx->active_xoffset + gfx->pressed_xoffset; int gd_yap = gfx->src_y + gfx->active_yoffset + gfx->pressed_yoffset; int id = i; if (gfx->bitmap == NULL) { game_gadget[id] = NULL; continue; } if (id == GAME_CTRL_ID_STOP || id == GAME_CTRL_ID_PANEL_STOP || id == GAME_CTRL_ID_PLAY || id == GAME_CTRL_ID_PANEL_PLAY || id == GAME_CTRL_ID_SAVE || id == GAME_CTRL_ID_LOAD) { button_type = GD_TYPE_NORMAL_BUTTON; checked = FALSE; event_mask = GD_EVENT_RELEASED; } else if (id == GAME_CTRL_ID_UNDO || id == GAME_CTRL_ID_REDO) { button_type = GD_TYPE_NORMAL_BUTTON; checked = FALSE; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; } else { button_type = GD_TYPE_CHECK_BUTTON; checked = (gamebutton_info[i].setup_value != NULL ? *gamebutton_info[i].setup_value : FALSE); event_mask = GD_EVENT_PRESSED; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, gamebutton_info[i].infotext, GDI_X, base_x + GDI_ACTIVE_POS(pos->x), GDI_Y, base_y + GDI_ACTIVE_POS(pos->y), GDI_WIDTH, gfx->width, GDI_HEIGHT, gfx->height, GDI_TYPE, button_type, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_CHECKED, checked, GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp, GDI_ALT_DESIGN_UNPRESSED, gfx->bitmap, gd_xa, gd_ya, GDI_ALT_DESIGN_PRESSED, gfx->bitmap, gd_xap, gd_yap, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleGameButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); game_gadget[id] = gi; } } void FreeGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) FreeGadget(game_gadget[i]); } static void UnmapGameButtonsAtSamePosition(int id) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) if (i != id && gamebutton_info[i].pos->x == gamebutton_info[id].pos->x && gamebutton_info[i].pos->y == gamebutton_info[id].pos->y) UnmapGadget(game_gadget[i]); } static void UnmapGameButtonsAtSamePosition_All() { if (setup.show_snapshot_buttons) { UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD); } else { UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_STOP); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PLAY); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PANEL_STOP); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PANEL_PAUSE); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PANEL_PLAY); } } static void MapGameButtonsAtSamePosition(int id) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) if (i != id && gamebutton_info[i].pos->x == gamebutton_info[id].pos->x && gamebutton_info[i].pos->y == gamebutton_info[id].pos->y) MapGadget(game_gadget[i]); UnmapGameButtonsAtSamePosition_All(); } void MapUndoRedoButtons() { UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); MapGadget(game_gadget[GAME_CTRL_ID_UNDO]); MapGadget(game_gadget[GAME_CTRL_ID_REDO]); ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, TRUE, GDI_END); } void UnmapUndoRedoButtons() { UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]); UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]); MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); MapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END); } void MapGameButtonsExt(boolean on_tape) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) if ((!on_tape || gamebutton_info[i].allowed_on_tape) && i != GAME_CTRL_ID_UNDO && i != GAME_CTRL_ID_REDO) MapGadget(game_gadget[i]); UnmapGameButtonsAtSamePosition_All(); RedrawGameButtons(); } void UnmapGameButtonsExt(boolean on_tape) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) if (!on_tape || gamebutton_info[i].allowed_on_tape) UnmapGadget(game_gadget[i]); } void RedrawGameButtonsExt(boolean on_tape) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) if (!on_tape || gamebutton_info[i].allowed_on_tape) RedrawGadget(game_gadget[i]); // RedrawGadget() may have set REDRAW_ALL if buttons are defined off-area redraw_mask &= ~REDRAW_ALL; } void SetGadgetState(struct GadgetInfo *gi, boolean state) { if (gi == NULL) return; gi->checked = state; } void RedrawSoundButtonGadget(int id) { int id2 = (id == SOUND_CTRL_ID_MUSIC ? SOUND_CTRL_ID_PANEL_MUSIC : id == SOUND_CTRL_ID_LOOPS ? SOUND_CTRL_ID_PANEL_LOOPS : id == SOUND_CTRL_ID_SIMPLE ? SOUND_CTRL_ID_PANEL_SIMPLE : id == SOUND_CTRL_ID_PANEL_MUSIC ? SOUND_CTRL_ID_MUSIC : id == SOUND_CTRL_ID_PANEL_LOOPS ? SOUND_CTRL_ID_LOOPS : id == SOUND_CTRL_ID_PANEL_SIMPLE ? SOUND_CTRL_ID_SIMPLE : id); SetGadgetState(game_gadget[id2], *gamebutton_info[id2].setup_value); RedrawGadget(game_gadget[id2]); } void MapGameButtons() { MapGameButtonsExt(FALSE); } void UnmapGameButtons() { UnmapGameButtonsExt(FALSE); } void RedrawGameButtons() { RedrawGameButtonsExt(FALSE); } void MapGameButtonsOnTape() { MapGameButtonsExt(TRUE); } void UnmapGameButtonsOnTape() { UnmapGameButtonsExt(TRUE); } void RedrawGameButtonsOnTape() { RedrawGameButtonsExt(TRUE); } void GameUndoRedoExt() { ClearPlayerAction(); tape.pausing = TRUE; RedrawPlayfield(); UpdateAndDisplayGameControlValues(); DrawCompleteVideoDisplay(); DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter); DrawVideoDisplay(VIDEO_STATE_1STEP(tape.single_step), 0); BackToFront(); } void GameUndo(int steps) { if (!CheckEngineSnapshotList()) return; LoadEngineSnapshot_Undo(steps); GameUndoRedoExt(); } void GameRedo(int steps) { if (!CheckEngineSnapshotList()) return; LoadEngineSnapshot_Redo(steps); GameUndoRedoExt(); } static void HandleGameButtonsExt(int id, int button) { static boolean game_undo_executed = FALSE; int steps = BUTTON_STEPSIZE(button); boolean handle_game_buttons = (game_status == GAME_MODE_PLAYING || (game_status == GAME_MODE_MAIN && tape.show_game_buttons)); if (!handle_game_buttons) return; switch (id) { case GAME_CTRL_ID_STOP: case GAME_CTRL_ID_PANEL_STOP: if (game_status == GAME_MODE_MAIN) break; if (tape.playing) TapeStop(); else RequestQuitGame(TRUE); break; case GAME_CTRL_ID_PAUSE: case GAME_CTRL_ID_PAUSE2: case GAME_CTRL_ID_PANEL_PAUSE: if (options.network && game_status == GAME_MODE_PLAYING) { #if defined(NETWORK_AVALIABLE) if (tape.pausing) SendToServer_ContinuePlaying(); else SendToServer_PausePlaying(); #endif } else TapeTogglePause(TAPE_TOGGLE_MANUAL); game_undo_executed = FALSE; break; case GAME_CTRL_ID_PLAY: case GAME_CTRL_ID_PANEL_PLAY: if (game_status == GAME_MODE_MAIN) { StartGameActions(options.network, setup.autorecord, level.random_seed); } else if (tape.pausing) { #if defined(NETWORK_AVALIABLE) if (options.network) SendToServer_ContinuePlaying(); else #endif TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE); } break; case GAME_CTRL_ID_UNDO: // Important: When using "save snapshot when collecting an item" mode, // load last (current) snapshot for first "undo" after pressing "pause" // (else the last-but-one snapshot would be loaded, because the snapshot // pointer already points to the last snapshot when pressing "pause", // which is fine for "every step/move" mode, but not for "every collect") if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_COLLECT && !game_undo_executed) steps--; game_undo_executed = TRUE; GameUndo(steps); break; case GAME_CTRL_ID_REDO: GameRedo(steps); break; case GAME_CTRL_ID_SAVE: TapeQuickSave(); break; case GAME_CTRL_ID_LOAD: TapeQuickLoad(); break; case SOUND_CTRL_ID_MUSIC: case SOUND_CTRL_ID_PANEL_MUSIC: if (setup.sound_music) { setup.sound_music = FALSE; FadeMusic(); } else if (audio.music_available) { setup.sound = setup.sound_music = TRUE; SetAudioMode(setup.sound); if (game_status == GAME_MODE_PLAYING) PlayLevelMusic(); } RedrawSoundButtonGadget(id); break; case SOUND_CTRL_ID_LOOPS: case SOUND_CTRL_ID_PANEL_LOOPS: if (setup.sound_loops) setup.sound_loops = FALSE; else if (audio.loops_available) { setup.sound = setup.sound_loops = TRUE; SetAudioMode(setup.sound); } RedrawSoundButtonGadget(id); break; case SOUND_CTRL_ID_SIMPLE: case SOUND_CTRL_ID_PANEL_SIMPLE: if (setup.sound_simple) setup.sound_simple = FALSE; else if (audio.sound_available) { setup.sound = setup.sound_simple = TRUE; SetAudioMode(setup.sound); } RedrawSoundButtonGadget(id); break; default: break; } } static void HandleGameButtons(struct GadgetInfo *gi) { HandleGameButtonsExt(gi->custom_id, gi->event.button); } void HandleSoundButtonKeys(Key key) { if (key == setup.shortcut.sound_simple) ClickOnGadget(game_gadget[SOUND_CTRL_ID_SIMPLE], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_loops) ClickOnGadget(game_gadget[SOUND_CTRL_ID_LOOPS], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_music) ClickOnGadget(game_gadget[SOUND_CTRL_ID_MUSIC], MB_LEFTBUTTON); } mirrormagic-3.0.0/src/netserv.h0000644000175000017500000000221613263212010015750 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // 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_PLAYER 12 #define OP_BROADCAST_MESSAGE 13 #define MAX_BUFFER_SIZE 4096 int NetworkServerThread(void *); void NetworkServer(int, int); #endif mirrormagic-3.0.0/src/conf_e2g.c0000644000175000017500000036577513263214151015775 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_e2g.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_E2G_C #define CONF_E2G_C /* values for element/graphics mapping configuration (normal) */ static struct { int element; int action; int direction; boolean crumbled; int graphic; } element_to_graphic[] = { { EL_BD_WALL, -1, -1, FALSE, IMG_BD_WALL }, { EL_BD_ROCK, -1, -1, FALSE, IMG_BD_ROCK }, { EL_BD_ROCK, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_BD_ROCK_MOVING_LEFT }, { EL_BD_ROCK, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_BD_ROCK_MOVING_RIGHT }, { EL_BD_ROCK, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_BD_ROCK_PUSHING_LEFT }, { EL_BD_ROCK, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_BD_ROCK_PUSHING_RIGHT }, { EL_BD_DIAMOND, -1, -1, FALSE, IMG_BD_DIAMOND }, { EL_BD_DIAMOND, ACTION_MOVING, -1, FALSE, IMG_BD_DIAMOND_MOVING }, { EL_BD_DIAMOND, ACTION_FALLING, -1, FALSE, IMG_BD_DIAMOND_FALLING }, { EL_BD_MAGIC_WALL, -1, -1, FALSE, IMG_BD_MAGIC_WALL }, { EL_BD_MAGIC_WALL_ACTIVE, -1, -1, FALSE, IMG_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL, ACTION_ACTIVE, -1, FALSE, IMG_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL_FILLING, -1, -1, FALSE, IMG_BD_MAGIC_WALL_FILLING }, { EL_BD_MAGIC_WALL, ACTION_FILLING, -1, FALSE, IMG_BD_MAGIC_WALL_FILLING }, { EL_BD_MAGIC_WALL_FULL, -1, -1, FALSE, IMG_BD_MAGIC_WALL_FULL }, { EL_BD_MAGIC_WALL_EMPTYING, -1, -1, FALSE, IMG_BD_MAGIC_WALL_EMPTYING }, { EL_BD_MAGIC_WALL, ACTION_EMPTYING, -1, FALSE, IMG_BD_MAGIC_WALL_EMPTYING }, { EL_BD_MAGIC_WALL_DEAD, -1, -1, FALSE, IMG_BD_MAGIC_WALL_DEAD }, { EL_BD_AMOEBA, -1, -1, FALSE, IMG_BD_AMOEBA }, { EL_BD_BUTTERFLY, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_RIGHT, -1, -1, FALSE, IMG_BD_BUTTERFLY_RIGHT }, { EL_BD_BUTTERFLY, -1, MV_BIT_RIGHT, FALSE, IMG_BD_BUTTERFLY_RIGHT }, { EL_BD_BUTTERFLY_UP, -1, -1, FALSE, IMG_BD_BUTTERFLY_UP }, { EL_BD_BUTTERFLY, -1, MV_BIT_UP, FALSE, IMG_BD_BUTTERFLY_UP }, { EL_BD_BUTTERFLY_LEFT, -1, -1, FALSE, IMG_BD_BUTTERFLY_LEFT }, { EL_BD_BUTTERFLY, -1, MV_BIT_LEFT, FALSE, IMG_BD_BUTTERFLY_LEFT }, { EL_BD_BUTTERFLY_DOWN, -1, -1, FALSE, IMG_BD_BUTTERFLY_DOWN }, { EL_BD_BUTTERFLY, -1, MV_BIT_DOWN, FALSE, IMG_BD_BUTTERFLY_DOWN }, { EL_BD_FIREFLY, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_RIGHT, -1, -1, FALSE, IMG_BD_FIREFLY_RIGHT }, { EL_BD_FIREFLY, -1, MV_BIT_RIGHT, FALSE, IMG_BD_FIREFLY_RIGHT }, { EL_BD_FIREFLY_UP, -1, -1, FALSE, IMG_BD_FIREFLY_UP }, { EL_BD_FIREFLY, -1, MV_BIT_UP, FALSE, IMG_BD_FIREFLY_UP }, { EL_BD_FIREFLY_LEFT, -1, -1, FALSE, IMG_BD_FIREFLY_LEFT }, { EL_BD_FIREFLY, -1, MV_BIT_LEFT, FALSE, IMG_BD_FIREFLY_LEFT }, { EL_BD_FIREFLY_DOWN, -1, -1, FALSE, IMG_BD_FIREFLY_DOWN }, { EL_BD_FIREFLY, -1, MV_BIT_DOWN, FALSE, IMG_BD_FIREFLY_DOWN }, { EL_SP_DEFAULT, ACTION_EXPLODING, -1, FALSE, IMG_SP_DEFAULT_EXPLODING }, { EL_SP_ZONK, -1, -1, FALSE, IMG_SP_ZONK }, { EL_SP_ZONK, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SP_ZONK_MOVING_LEFT }, { EL_SP_ZONK, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SP_ZONK_MOVING_RIGHT }, { EL_SP_ZONK, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_SP_ZONK_PUSHING_LEFT }, { EL_SP_ZONK, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_SP_ZONK_PUSHING_RIGHT }, { EL_SP_BASE, -1, -1, FALSE, IMG_SP_BASE }, { EL_SP_BASE, ACTION_DIGGING, -1, FALSE, IMG_SP_BASE_DIGGING }, { EL_SP_BASE, ACTION_SNAPPING, -1, FALSE, IMG_SP_BASE_SNAPPING }, { EL_SP_MURPHY, -1, -1, FALSE, IMG_SP_MURPHY }, { EL_SP_MURPHY, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_MOVING_LEFT }, { EL_SP_MURPHY, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_MOVING_RIGHT }, { EL_SP_MURPHY, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_DIGGING_LEFT }, { EL_SP_MURPHY, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_DIGGING_RIGHT }, { EL_SP_MURPHY, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_COLLECTING_LEFT }, { EL_SP_MURPHY, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_COLLECTING_RIGHT }, { EL_SP_MURPHY, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_PUSHING_LEFT }, { EL_SP_MURPHY, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_PUSHING_RIGHT }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_SNAPPING_LEFT }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_SNAPPING_RIGHT }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_SP_MURPHY_SNAPPING_UP }, { EL_SP_MURPHY, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_SP_MURPHY_SNAPPING_DOWN }, { EL_SP_MURPHY, ACTION_BORING, -1, FALSE, IMG_SP_MURPHY_BORING }, { EL_SP_MURPHY, ACTION_BORING_1, -1, FALSE, IMG_SP_MURPHY_BORING_1 }, { EL_SP_MURPHY, ACTION_SLEEPING, MV_BIT_LEFT, FALSE, IMG_SP_MURPHY_SLEEPING_LEFT }, { EL_SP_MURPHY, ACTION_SLEEPING, MV_BIT_RIGHT, FALSE, IMG_SP_MURPHY_SLEEPING_RIGHT }, { EL_SP_MURPHY, ACTION_DROPPING, -1, FALSE, IMG_SP_MURPHY_DROPPING }, { EL_SP_MURPHY, ACTION_SHRINKING, -1, FALSE, IMG_SP_MURPHY_SHRINKING }, { EL_SP_MURPHY_CLONE, -1, -1, FALSE, IMG_SP_MURPHY_CLONE }, { EL_SP_INFOTRON, -1, -1, FALSE, IMG_SP_INFOTRON }, { EL_SP_INFOTRON, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SP_INFOTRON_MOVING_LEFT }, { EL_SP_INFOTRON, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SP_INFOTRON_MOVING_RIGHT }, { EL_SP_INFOTRON, ACTION_COLLECTING, -1, FALSE, IMG_SP_INFOTRON_COLLECTING }, { EL_SP_CHIP_SINGLE, -1, -1, FALSE, IMG_SP_CHIP_SINGLE }, { EL_SP_CHIP_LEFT, -1, -1, FALSE, IMG_SP_CHIP_LEFT }, { EL_SP_CHIP_RIGHT, -1, -1, FALSE, IMG_SP_CHIP_RIGHT }, { EL_SP_CHIP_TOP, -1, -1, FALSE, IMG_SP_CHIP_TOP }, { EL_SP_CHIP_BOTTOM, -1, -1, FALSE, IMG_SP_CHIP_BOTTOM }, { EL_SP_HARDWARE_GRAY, -1, -1, FALSE, IMG_SP_HARDWARE_GRAY }, { EL_SP_HARDWARE_GREEN, -1, -1, FALSE, IMG_SP_HARDWARE_GREEN }, { EL_SP_HARDWARE_BLUE, -1, -1, FALSE, IMG_SP_HARDWARE_BLUE }, { EL_SP_HARDWARE_RED, -1, -1, FALSE, IMG_SP_HARDWARE_RED }, { EL_SP_HARDWARE_YELLOW, -1, -1, FALSE, IMG_SP_HARDWARE_YELLOW }, { EL_SP_EXIT_CLOSED, -1, -1, FALSE, IMG_SP_EXIT_CLOSED }, { EL_SP_EXIT_OPENING, -1, -1, FALSE, IMG_SP_EXIT_OPENING }, { EL_SP_EXIT_OPEN, -1, -1, FALSE, IMG_SP_EXIT_OPEN }, { EL_SP_EXIT_CLOSING, -1, -1, FALSE, IMG_SP_EXIT_CLOSING }, { EL_SP_DISK_ORANGE, -1, -1, FALSE, IMG_SP_DISK_ORANGE }, { EL_SP_DISK_YELLOW, -1, -1, FALSE, IMG_SP_DISK_YELLOW }, { EL_SP_DISK_RED, -1, -1, FALSE, IMG_SP_DISK_RED }, { EL_SP_DISK_RED, ACTION_COLLECTING, -1, FALSE, IMG_SP_DISK_RED_COLLECTING }, { EL_SP_DISK_RED_ACTIVE, -1, -1, FALSE, IMG_SP_DISK_RED_ACTIVE }, { EL_SP_DISK_RED, ACTION_ACTIVE, -1, FALSE, IMG_SP_DISK_RED_ACTIVE }, { EL_SP_PORT_RIGHT, -1, -1, FALSE, IMG_SP_PORT_RIGHT }, { EL_SP_PORT_DOWN, -1, -1, FALSE, IMG_SP_PORT_DOWN }, { EL_SP_PORT_LEFT, -1, -1, FALSE, IMG_SP_PORT_LEFT }, { EL_SP_PORT_UP, -1, -1, FALSE, IMG_SP_PORT_UP }, { EL_SP_PORT_HORIZONTAL, -1, -1, FALSE, IMG_SP_PORT_HORIZONTAL }, { EL_SP_PORT_VERTICAL, -1, -1, FALSE, IMG_SP_PORT_VERTICAL }, { EL_SP_PORT_ANY, -1, -1, FALSE, IMG_SP_PORT_ANY }, { EL_SP_GRAVITY_PORT_RIGHT, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_RIGHT }, { EL_SP_GRAVITY_PORT_DOWN, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_DOWN }, { EL_SP_GRAVITY_PORT_LEFT, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_LEFT }, { EL_SP_GRAVITY_PORT_UP, -1, -1, FALSE, IMG_SP_GRAVITY_PORT_UP }, { EL_SP_GRAVITY_ON_PORT_RIGHT, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_RIGHT }, { EL_SP_GRAVITY_ON_PORT_DOWN, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_DOWN }, { EL_SP_GRAVITY_ON_PORT_LEFT, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_LEFT }, { EL_SP_GRAVITY_ON_PORT_UP, -1, -1, FALSE, IMG_SP_GRAVITY_ON_PORT_UP }, { EL_SP_GRAVITY_OFF_PORT_RIGHT, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_RIGHT }, { EL_SP_GRAVITY_OFF_PORT_DOWN, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_DOWN }, { EL_SP_GRAVITY_OFF_PORT_LEFT, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_LEFT }, { EL_SP_GRAVITY_OFF_PORT_UP, -1, -1, FALSE, IMG_SP_GRAVITY_OFF_PORT_UP }, { EL_SP_SNIKSNAK, -1, -1, FALSE, IMG_SP_SNIKSNAK }, { EL_SP_SNIKSNAK, -1, MV_BIT_LEFT, FALSE, IMG_SP_SNIKSNAK_LEFT }, { EL_SP_SNIKSNAK, -1, MV_BIT_RIGHT, FALSE, IMG_SP_SNIKSNAK_RIGHT }, { EL_SP_SNIKSNAK, -1, MV_BIT_UP, FALSE, IMG_SP_SNIKSNAK_UP }, { EL_SP_SNIKSNAK, -1, MV_BIT_DOWN, FALSE, IMG_SP_SNIKSNAK_DOWN }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_LEFT, MV_BIT_UP, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_UP, MV_BIT_LEFT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT }, { EL_SP_SNIKSNAK, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT, FALSE, IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT }, { EL_SP_ELECTRON, -1, -1, FALSE, IMG_SP_ELECTRON }, { EL_SP_ELECTRON, ACTION_EXPLODING, -1, FALSE, IMG_SP_ELECTRON_EXPLODING }, { EL_SP_TERMINAL, -1, -1, FALSE, IMG_SP_TERMINAL }, { EL_SP_TERMINAL_ACTIVE, -1, -1, FALSE, IMG_SP_TERMINAL_ACTIVE }, { EL_SP_TERMINAL, ACTION_ACTIVE, -1, FALSE, IMG_SP_TERMINAL_ACTIVE }, { EL_SP_BUGGY_BASE, -1, -1, FALSE, IMG_SP_BUGGY_BASE }, { EL_SP_BUGGY_BASE_ACTIVATING, -1, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVATING }, { EL_SP_BUGGY_BASE, ACTION_ACTIVATING, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVATING }, { EL_SP_BUGGY_BASE_ACTIVE, -1, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVE }, { EL_SP_BUGGY_BASE, ACTION_ACTIVE, -1, FALSE, IMG_SP_BUGGY_BASE_ACTIVE }, { EL_SP_HARDWARE_BASE_1, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_1 }, { EL_SP_HARDWARE_BASE_2, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_2 }, { EL_SP_HARDWARE_BASE_3, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_3 }, { EL_SP_HARDWARE_BASE_4, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_4 }, { EL_SP_HARDWARE_BASE_5, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_5 }, { EL_SP_HARDWARE_BASE_6, -1, -1, FALSE, IMG_SP_HARDWARE_BASE_6 }, { EL_SOKOBAN_OBJECT, -1, -1, FALSE, IMG_SOKOBAN_OBJECT }, { EL_SOKOBAN_FIELD_EMPTY, -1, -1, FALSE, IMG_SOKOBAN_FIELD_EMPTY }, { EL_SOKOBAN_FIELD_FULL, -1, -1, FALSE, IMG_SOKOBAN_FIELD_FULL }, { EL_SOKOBAN_FIELD_PLAYER, -1, -1, FALSE, IMG_SOKOBAN_FIELD_PLAYER }, { EL_EMPTY_SPACE, -1, -1, FALSE, IMG_EMPTY_SPACE }, { EL_SAND, -1, -1, FALSE, IMG_SAND }, { EL_SAND, -1, -1, TRUE, IMG_SAND_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_SAND_DIGGING_LEFT }, { EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_SAND_DIGGING_RIGHT }, { EL_SAND, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_SAND_DIGGING_UP }, { EL_SAND, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_SAND_DIGGING_DOWN }, { EL_SAND, ACTION_DIGGING, MV_BIT_LEFT, TRUE, IMG_SAND_DIGGING_LEFT_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT, TRUE, IMG_SAND_DIGGING_RIGHT_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_UP, TRUE, IMG_SAND_DIGGING_UP_CRUMBLED }, { EL_SAND, ACTION_DIGGING, MV_BIT_DOWN, TRUE, IMG_SAND_DIGGING_DOWN_CRUMBLED }, { EL_WALL, -1, -1, FALSE, IMG_WALL }, { EL_WALL_SLIPPERY, -1, -1, FALSE, IMG_WALL_SLIPPERY }, { EL_STEELWALL, -1, -1, FALSE, IMG_STEELWALL }, { EL_ROCK, -1, -1, FALSE, IMG_ROCK }, { EL_ROCK, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_ROCK_MOVING_LEFT }, { EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_ROCK_MOVING_RIGHT }, { EL_ROCK, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_ROCK_PUSHING_LEFT }, { EL_ROCK, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_ROCK_PUSHING_RIGHT }, { EL_EMERALD, -1, -1, FALSE, IMG_EMERALD }, { EL_EMERALD, ACTION_MOVING, -1, FALSE, IMG_EMERALD_MOVING }, { EL_EMERALD, ACTION_FALLING, -1, FALSE, IMG_EMERALD_FALLING }, { EL_EMERALD, ACTION_COLLECTING, -1, FALSE, IMG_EMERALD_COLLECTING }, { EL_DIAMOND, -1, -1, FALSE, IMG_DIAMOND }, { EL_DIAMOND, ACTION_MOVING, -1, FALSE, IMG_DIAMOND_MOVING }, { EL_DIAMOND, ACTION_FALLING, -1, FALSE, IMG_DIAMOND_FALLING }, { EL_DIAMOND, ACTION_COLLECTING, -1, FALSE, IMG_DIAMOND_COLLECTING }, { EL_BOMB, -1, -1, FALSE, IMG_BOMB }, { EL_NUT, -1, -1, FALSE, IMG_NUT }, { EL_NUT_BREAKING, -1, -1, FALSE, IMG_NUT_BREAKING }, { EL_NUT, ACTION_BREAKING, -1, FALSE, IMG_NUT_BREAKING }, { EL_DYNAMITE, -1, -1, FALSE, IMG_DYNAMITE }, { EL_DYNAMITE_ACTIVE, -1, -1, FALSE, IMG_DYNAMITE_ACTIVE }, { EL_DYNAMITE, ACTION_ACTIVE, -1, FALSE, IMG_DYNAMITE_ACTIVE }, { EL_EM_DYNAMITE, -1, -1, FALSE, IMG_EM_DYNAMITE }, { EL_EM_DYNAMITE_ACTIVE, -1, -1, FALSE, IMG_EM_DYNAMITE_ACTIVE }, { EL_EM_DYNAMITE, ACTION_ACTIVE, -1, FALSE, IMG_EM_DYNAMITE_ACTIVE }, { EL_WALL_EMERALD, -1, -1, FALSE, IMG_WALL_EMERALD }, { EL_WALL_DIAMOND, -1, -1, FALSE, IMG_WALL_DIAMOND }, { EL_BUG, -1, -1, FALSE, IMG_BUG }, { EL_BUG_RIGHT, -1, -1, FALSE, IMG_BUG_RIGHT }, { EL_BUG, -1, MV_BIT_RIGHT, FALSE, IMG_BUG_RIGHT }, { EL_BUG_UP, -1, -1, FALSE, IMG_BUG_UP }, { EL_BUG, -1, MV_BIT_UP, FALSE, IMG_BUG_UP }, { EL_BUG_LEFT, -1, -1, FALSE, IMG_BUG_LEFT }, { EL_BUG, -1, MV_BIT_LEFT, FALSE, IMG_BUG_LEFT }, { EL_BUG_DOWN, -1, -1, FALSE, IMG_BUG_DOWN }, { EL_BUG, -1, MV_BIT_DOWN, FALSE, IMG_BUG_DOWN }, { EL_BUG, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_BUG_MOVING_RIGHT }, { EL_BUG, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_BUG_MOVING_UP }, { EL_BUG, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_BUG_MOVING_LEFT }, { EL_BUG, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_BUG_MOVING_DOWN }, { EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP, FALSE, IMG_BUG_TURNING_FROM_RIGHT_UP }, { EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT, FALSE, IMG_BUG_TURNING_FROM_UP_LEFT }, { EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN, FALSE, IMG_BUG_TURNING_FROM_LEFT_DOWN }, { EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT, FALSE, IMG_BUG_TURNING_FROM_DOWN_RIGHT }, { EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN, FALSE, IMG_BUG_TURNING_FROM_RIGHT_DOWN }, { EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT, FALSE, IMG_BUG_TURNING_FROM_UP_RIGHT }, { EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP, FALSE, IMG_BUG_TURNING_FROM_LEFT_UP }, { EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT, FALSE, IMG_BUG_TURNING_FROM_DOWN_LEFT }, { EL_SPACESHIP, -1, -1, FALSE, IMG_SPACESHIP }, { EL_SPACESHIP_RIGHT, -1, -1, FALSE, IMG_SPACESHIP_RIGHT }, { EL_SPACESHIP, -1, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_RIGHT }, { EL_SPACESHIP_UP, -1, -1, FALSE, IMG_SPACESHIP_UP }, { EL_SPACESHIP, -1, MV_BIT_UP, FALSE, IMG_SPACESHIP_UP }, { EL_SPACESHIP_LEFT, -1, -1, FALSE, IMG_SPACESHIP_LEFT }, { EL_SPACESHIP, -1, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_LEFT }, { EL_SPACESHIP_DOWN, -1, -1, FALSE, IMG_SPACESHIP_DOWN }, { EL_SPACESHIP, -1, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_DOWN }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_MOVING_RIGHT }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_SPACESHIP_MOVING_UP }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_MOVING_LEFT }, { EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_MOVING_DOWN }, { EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP, FALSE, IMG_SPACESHIP_TURNING_FROM_RIGHT_UP }, { EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_TURNING_FROM_UP_LEFT }, { EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN }, { EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT }, { EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN, FALSE, IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN }, { EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT, FALSE, IMG_SPACESHIP_TURNING_FROM_UP_RIGHT }, { EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP, FALSE, IMG_SPACESHIP_TURNING_FROM_LEFT_UP }, { EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT, FALSE, IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT }, { EL_YAMYAM, -1, -1, FALSE, IMG_YAMYAM }, { EL_YAMYAM_LEFT, -1, -1, FALSE, IMG_YAMYAM_LEFT }, { EL_YAMYAM, -1, MV_BIT_LEFT, FALSE, IMG_YAMYAM_LEFT }, { EL_YAMYAM_RIGHT, -1, -1, FALSE, IMG_YAMYAM_RIGHT }, { EL_YAMYAM, -1, MV_BIT_RIGHT, FALSE, IMG_YAMYAM_RIGHT }, { EL_YAMYAM_UP, -1, -1, FALSE, IMG_YAMYAM_UP }, { EL_YAMYAM, -1, MV_BIT_UP, FALSE, IMG_YAMYAM_UP }, { EL_YAMYAM_DOWN, -1, -1, FALSE, IMG_YAMYAM_DOWN }, { EL_YAMYAM, -1, MV_BIT_DOWN, FALSE, IMG_YAMYAM_DOWN }, { EL_YAMYAM, ACTION_MOVING, -1, FALSE, IMG_YAMYAM_MOVING }, { EL_ROBOT, -1, -1, FALSE, IMG_ROBOT }, { EL_ROBOT, ACTION_MOVING, -1, FALSE, IMG_ROBOT_MOVING }, { EL_ROBOT_WHEEL, -1, -1, FALSE, IMG_ROBOT_WHEEL }, { EL_ROBOT_WHEEL_ACTIVE, -1, -1, FALSE, IMG_ROBOT_WHEEL_ACTIVE }, { EL_ROBOT_WHEEL, ACTION_ACTIVE, -1, FALSE, IMG_ROBOT_WHEEL_ACTIVE }, { EL_MAGIC_WALL, -1, -1, FALSE, IMG_MAGIC_WALL }, { EL_MAGIC_WALL_ACTIVE, -1, -1, FALSE, IMG_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL, ACTION_ACTIVE, -1, FALSE, IMG_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL_FILLING, -1, -1, FALSE, IMG_MAGIC_WALL_FILLING }, { EL_MAGIC_WALL, ACTION_FILLING, -1, FALSE, IMG_MAGIC_WALL_FILLING }, { EL_MAGIC_WALL_FULL, -1, -1, FALSE, IMG_MAGIC_WALL_FULL }, { EL_MAGIC_WALL_EMPTYING, -1, -1, FALSE, IMG_MAGIC_WALL_EMPTYING }, { EL_MAGIC_WALL, ACTION_EMPTYING, -1, FALSE, IMG_MAGIC_WALL_EMPTYING }, { EL_MAGIC_WALL_DEAD, -1, -1, FALSE, IMG_MAGIC_WALL_DEAD }, { EL_DC_MAGIC_WALL, -1, -1, FALSE, IMG_DC_MAGIC_WALL }, { EL_DC_MAGIC_WALL_ACTIVE, -1, -1, FALSE, IMG_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL, ACTION_ACTIVE, -1, FALSE, IMG_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL_FILLING, -1, -1, FALSE, IMG_DC_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL, ACTION_FILLING, -1, FALSE, IMG_DC_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL_FULL, -1, -1, FALSE, IMG_DC_MAGIC_WALL_FULL }, { EL_DC_MAGIC_WALL_EMPTYING, -1, -1, FALSE, IMG_DC_MAGIC_WALL_EMPTYING }, { EL_DC_MAGIC_WALL, ACTION_EMPTYING, -1, FALSE, IMG_DC_MAGIC_WALL_EMPTYING }, { EL_DC_MAGIC_WALL_DEAD, -1, -1, FALSE, IMG_DC_MAGIC_WALL_DEAD }, { EL_QUICKSAND_EMPTY, -1, -1, FALSE, IMG_QUICKSAND_EMPTY }, { EL_QUICKSAND_FILLING, -1, -1, FALSE, IMG_QUICKSAND_FILLING }, { EL_QUICKSAND_FULL, -1, -1, FALSE, IMG_QUICKSAND_FULL }, { EL_QUICKSAND_EMPTYING, -1, -1, FALSE, IMG_QUICKSAND_EMPTYING }, { EL_QUICKSAND_FAST_EMPTY, -1, -1, FALSE, IMG_QUICKSAND_FAST_EMPTY }, { EL_QUICKSAND_FAST_FILLING, -1, -1, FALSE, IMG_QUICKSAND_FAST_FILLING }, { EL_QUICKSAND_FAST_FULL, -1, -1, FALSE, IMG_QUICKSAND_FAST_FULL }, { EL_QUICKSAND_FAST_EMPTYING, -1, -1, FALSE, IMG_QUICKSAND_FAST_EMPTYING }, { EL_ACID_POOL_TOPLEFT, -1, -1, FALSE, IMG_ACID_POOL_TOPLEFT }, { EL_ACID_POOL_TOPRIGHT, -1, -1, FALSE, IMG_ACID_POOL_TOPRIGHT }, { EL_ACID_POOL_BOTTOMLEFT, -1, -1, FALSE, IMG_ACID_POOL_BOTTOMLEFT }, { EL_ACID_POOL_BOTTOM, -1, -1, FALSE, IMG_ACID_POOL_BOTTOM }, { EL_ACID_POOL_BOTTOMRIGHT, -1, -1, FALSE, IMG_ACID_POOL_BOTTOMRIGHT }, { EL_ACID, -1, -1, FALSE, IMG_ACID }, { EL_ACID_SPLASH_LEFT, -1, -1, FALSE, IMG_ACID_SPLASH_LEFT }, { EL_ACID_SPLASH_RIGHT, -1, -1, FALSE, IMG_ACID_SPLASH_RIGHT }, { EL_AMOEBA_DROP, -1, -1, FALSE, IMG_AMOEBA_DROP }, { EL_AMOEBA_GROWING, -1, -1, FALSE, IMG_AMOEBA_GROWING }, { EL_AMOEBA, ACTION_GROWING, -1, FALSE, IMG_AMOEBA_GROWING }, { EL_AMOEBA_SHRINKING, -1, -1, FALSE, IMG_AMOEBA_SHRINKING }, { EL_AMOEBA, ACTION_SHRINKING, -1, FALSE, IMG_AMOEBA_SHRINKING }, { EL_AMOEBA_WET, -1, -1, FALSE, IMG_AMOEBA_WET }, { EL_AMOEBA_DROPPING, -1, -1, FALSE, IMG_AMOEBA_DROPPING }, { EL_AMOEBA, ACTION_DROPPING, -1, FALSE, IMG_AMOEBA_DROPPING }, { EL_AMOEBA_DRY, -1, -1, FALSE, IMG_AMOEBA_DRY }, { EL_AMOEBA_FULL, -1, -1, FALSE, IMG_AMOEBA_FULL }, { EL_AMOEBA_DEAD, -1, -1, FALSE, IMG_AMOEBA_DEAD }, { EL_EM_KEY_1, -1, -1, FALSE, IMG_EM_KEY_1 }, { EL_EM_KEY_2, -1, -1, FALSE, IMG_EM_KEY_2 }, { EL_EM_KEY_3, -1, -1, FALSE, IMG_EM_KEY_3 }, { EL_EM_KEY_4, -1, -1, FALSE, IMG_EM_KEY_4 }, { EL_DC_KEY_WHITE, -1, -1, FALSE, IMG_DC_KEY_WHITE }, { EL_EM_GATE_1, -1, -1, FALSE, IMG_EM_GATE_1 }, { EL_EM_GATE_2, -1, -1, FALSE, IMG_EM_GATE_2 }, { EL_EM_GATE_3, -1, -1, FALSE, IMG_EM_GATE_3 }, { EL_EM_GATE_4, -1, -1, FALSE, IMG_EM_GATE_4 }, { EL_DC_GATE_WHITE, -1, -1, FALSE, IMG_DC_GATE_WHITE }, { EL_EM_GATE_1_GRAY, -1, -1, FALSE, IMG_EM_GATE_1_GRAY }, { EL_EM_GATE_1_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_1_GRAY_ACTIVE }, { EL_EM_GATE_1_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_1_GRAY_ACTIVE }, { EL_EM_GATE_2_GRAY, -1, -1, FALSE, IMG_EM_GATE_2_GRAY }, { EL_EM_GATE_2_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_2_GRAY_ACTIVE }, { EL_EM_GATE_2_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_2_GRAY_ACTIVE }, { EL_EM_GATE_3_GRAY, -1, -1, FALSE, IMG_EM_GATE_3_GRAY }, { EL_EM_GATE_3_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_3_GRAY_ACTIVE }, { EL_EM_GATE_3_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_3_GRAY_ACTIVE }, { EL_EM_GATE_4_GRAY, -1, -1, FALSE, IMG_EM_GATE_4_GRAY }, { EL_EM_GATE_4_GRAY_ACTIVE, -1, -1, FALSE, IMG_EM_GATE_4_GRAY_ACTIVE }, { EL_EM_GATE_4_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EM_GATE_4_GRAY_ACTIVE }, { EL_DC_GATE_WHITE_GRAY, -1, -1, FALSE, IMG_DC_GATE_WHITE_GRAY }, { EL_DC_GATE_WHITE_GRAY_ACTIVE, -1, -1, FALSE, IMG_DC_GATE_WHITE_GRAY_ACTIVE }, { EL_DC_GATE_WHITE_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_DC_GATE_WHITE_GRAY_ACTIVE }, { EL_DC_GATE_FAKE_GRAY, -1, -1, FALSE, IMG_DC_GATE_FAKE_GRAY }, { EL_EXIT_CLOSED, -1, -1, FALSE, IMG_EXIT_CLOSED }, { EL_EXIT_OPENING, -1, -1, FALSE, IMG_EXIT_OPENING }, { EL_EXIT_OPEN, -1, -1, FALSE, IMG_EXIT_OPEN }, { EL_EXIT_CLOSING, -1, -1, FALSE, IMG_EXIT_CLOSING }, { EL_STEEL_EXIT_CLOSED, -1, -1, FALSE, IMG_STEEL_EXIT_CLOSED }, { EL_STEEL_EXIT_OPENING, -1, -1, FALSE, IMG_STEEL_EXIT_OPENING }, { EL_STEEL_EXIT_OPEN, -1, -1, FALSE, IMG_STEEL_EXIT_OPEN }, { EL_STEEL_EXIT_CLOSING, -1, -1, FALSE, IMG_STEEL_EXIT_CLOSING }, { EL_EM_EXIT_CLOSED, -1, -1, FALSE, IMG_EM_EXIT_CLOSED }, { EL_EM_EXIT_OPENING, -1, -1, FALSE, IMG_EM_EXIT_OPENING }, { EL_EM_EXIT_OPEN, -1, -1, FALSE, IMG_EM_EXIT_OPEN }, { EL_EM_EXIT_CLOSING, -1, -1, FALSE, IMG_EM_EXIT_CLOSING }, { EL_EM_STEEL_EXIT_CLOSED, -1, -1, FALSE, IMG_EM_STEEL_EXIT_CLOSED }, { EL_EM_STEEL_EXIT_OPENING, -1, -1, FALSE, IMG_EM_STEEL_EXIT_OPENING }, { EL_EM_STEEL_EXIT_OPEN, -1, -1, FALSE, IMG_EM_STEEL_EXIT_OPEN }, { EL_EM_STEEL_EXIT_CLOSING, -1, -1, FALSE, IMG_EM_STEEL_EXIT_CLOSING }, { EL_BALLOON, -1, -1, FALSE, IMG_BALLOON }, { EL_BALLOON, ACTION_MOVING, -1, FALSE, IMG_BALLOON_MOVING }, { EL_BALLOON, ACTION_PUSHING, -1, FALSE, IMG_BALLOON_PUSHING }, { EL_BALLOON_SWITCH_LEFT, -1, -1, FALSE, IMG_BALLOON_SWITCH_LEFT }, { EL_BALLOON_SWITCH_RIGHT, -1, -1, FALSE, IMG_BALLOON_SWITCH_RIGHT }, { EL_BALLOON_SWITCH_UP, -1, -1, FALSE, IMG_BALLOON_SWITCH_UP }, { EL_BALLOON_SWITCH_DOWN, -1, -1, FALSE, IMG_BALLOON_SWITCH_DOWN }, { EL_BALLOON_SWITCH_ANY, -1, -1, FALSE, IMG_BALLOON_SWITCH_ANY }, { EL_BALLOON_SWITCH_NONE, -1, -1, FALSE, IMG_BALLOON_SWITCH_NONE }, { EL_SPRING, -1, -1, FALSE, IMG_SPRING }, { EL_EMC_STEELWALL_1, -1, -1, FALSE, IMG_EMC_STEELWALL_1 }, { EL_EMC_STEELWALL_2, -1, -1, FALSE, IMG_EMC_STEELWALL_2 }, { EL_EMC_STEELWALL_3, -1, -1, FALSE, IMG_EMC_STEELWALL_3 }, { EL_EMC_STEELWALL_4, -1, -1, FALSE, IMG_EMC_STEELWALL_4 }, { EL_EMC_WALL_1, -1, -1, FALSE, IMG_EMC_WALL_1 }, { EL_EMC_WALL_2, -1, -1, FALSE, IMG_EMC_WALL_2 }, { EL_EMC_WALL_3, -1, -1, FALSE, IMG_EMC_WALL_3 }, { EL_EMC_WALL_4, -1, -1, FALSE, IMG_EMC_WALL_4 }, { EL_EMC_WALL_5, -1, -1, FALSE, IMG_EMC_WALL_5 }, { EL_EMC_WALL_6, -1, -1, FALSE, IMG_EMC_WALL_6 }, { EL_EMC_WALL_7, -1, -1, FALSE, IMG_EMC_WALL_7 }, { EL_EMC_WALL_8, -1, -1, FALSE, IMG_EMC_WALL_8 }, { EL_INVISIBLE_STEELWALL, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL }, { EL_INVISIBLE_STEELWALL_ACTIVE, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_ACTIVE }, { EL_INVISIBLE_STEELWALL, ACTION_ACTIVE, -1, FALSE, IMG_INVISIBLE_STEELWALL_ACTIVE }, { EL_INVISIBLE_WALL, -1, -1, FALSE, IMG_INVISIBLE_WALL }, { EL_INVISIBLE_WALL_ACTIVE, -1, -1, FALSE, IMG_INVISIBLE_WALL_ACTIVE }, { EL_INVISIBLE_WALL, ACTION_ACTIVE, -1, FALSE, IMG_INVISIBLE_WALL_ACTIVE }, { EL_INVISIBLE_SAND, -1, -1, FALSE, IMG_INVISIBLE_SAND }, { EL_INVISIBLE_SAND_ACTIVE, -1, -1, FALSE, IMG_INVISIBLE_SAND_ACTIVE }, { EL_INVISIBLE_SAND, ACTION_ACTIVE, -1, FALSE, IMG_INVISIBLE_SAND_ACTIVE }, { EL_INVISIBLE_SAND, ACTION_ACTIVE, -1, TRUE, IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, -1, -1, TRUE, IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_LEFT, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_RIGHT, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_UP, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP_CRUMBLED }, { EL_INVISIBLE_SAND_ACTIVE, ACTION_DIGGING, MV_BIT_DOWN, TRUE, IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN_CRUMBLED }, { EL_CONVEYOR_BELT_1_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_MIDDLE }, { EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_1_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_1_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_LEFT }, { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_1_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_1_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_1_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_RIGHT }, { EL_CONVEYOR_BELT_1_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_1_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_1_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_SWITCH_LEFT }, { EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_1_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_1_SWITCH_RIGHT }, { EL_CONVEYOR_BELT_2_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_MIDDLE }, { EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_2_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_2_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_LEFT }, { EL_CONVEYOR_BELT_2_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_2_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_2_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_2_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_RIGHT }, { EL_CONVEYOR_BELT_2_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_2_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_2_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_SWITCH_LEFT }, { EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_2_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_2_SWITCH_RIGHT }, { EL_CONVEYOR_BELT_3_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_MIDDLE }, { EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_3_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_3_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_LEFT }, { EL_CONVEYOR_BELT_3_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_3_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_3_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_3_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_RIGHT }, { EL_CONVEYOR_BELT_3_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_3_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_3_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_SWITCH_LEFT }, { EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_3_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_3_SWITCH_RIGHT }, { EL_CONVEYOR_BELT_4_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_MIDDLE }, { EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_4_MIDDLE, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_4_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_LEFT }, { EL_CONVEYOR_BELT_4_LEFT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_4_LEFT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_4_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_4_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_RIGHT }, { EL_CONVEYOR_BELT_4_RIGHT_ACTIVE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_4_RIGHT, ACTION_ACTIVE, -1, FALSE, IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_4_SWITCH_LEFT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_SWITCH_LEFT }, { EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE }, { EL_CONVEYOR_BELT_4_SWITCH_RIGHT, -1, -1, FALSE, IMG_CONVEYOR_BELT_4_SWITCH_RIGHT }, { EL_SWITCHGATE_SWITCH_UP, -1, -1, FALSE, IMG_SWITCHGATE_SWITCH_UP }, { EL_SWITCHGATE_SWITCH_DOWN, -1, -1, FALSE, IMG_SWITCHGATE_SWITCH_DOWN }, { EL_DC_SWITCHGATE_SWITCH_UP, -1, -1, FALSE, IMG_DC_SWITCHGATE_SWITCH_UP }, { EL_DC_SWITCHGATE_SWITCH_DOWN, -1, -1, FALSE, IMG_DC_SWITCHGATE_SWITCH_DOWN }, { EL_LIGHT_SWITCH, -1, -1, FALSE, IMG_LIGHT_SWITCH }, { EL_LIGHT_SWITCH_ACTIVE, -1, -1, FALSE, IMG_LIGHT_SWITCH_ACTIVE }, { EL_LIGHT_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_LIGHT_SWITCH_ACTIVE }, { EL_TIMEGATE_SWITCH, -1, -1, FALSE, IMG_TIMEGATE_SWITCH }, { EL_TIMEGATE_SWITCH_ACTIVE, -1, -1, FALSE, IMG_TIMEGATE_SWITCH_ACTIVE }, { EL_TIMEGATE_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_TIMEGATE_SWITCH_ACTIVE }, { EL_DC_TIMEGATE_SWITCH, -1, -1, FALSE, IMG_DC_TIMEGATE_SWITCH }, { EL_DC_TIMEGATE_SWITCH_ACTIVE, -1, -1, FALSE, IMG_DC_TIMEGATE_SWITCH_ACTIVE }, { EL_DC_TIMEGATE_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_DC_TIMEGATE_SWITCH_ACTIVE }, { EL_ENVELOPE_1, -1, -1, FALSE, IMG_ENVELOPE_1 }, { EL_ENVELOPE_1, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_1_COLLECTING }, { EL_ENVELOPE_2, -1, -1, FALSE, IMG_ENVELOPE_2 }, { EL_ENVELOPE_2, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_2_COLLECTING }, { EL_ENVELOPE_3, -1, -1, FALSE, IMG_ENVELOPE_3 }, { EL_ENVELOPE_3, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_3_COLLECTING }, { EL_ENVELOPE_4, -1, -1, FALSE, IMG_ENVELOPE_4 }, { EL_ENVELOPE_4, ACTION_COLLECTING, -1, FALSE, IMG_ENVELOPE_4_COLLECTING }, { EL_SIGN_RADIOACTIVITY, -1, -1, FALSE, IMG_SIGN_RADIOACTIVITY }, { EL_SIGN_GIVE_WAY, -1, -1, FALSE, IMG_SIGN_GIVE_WAY }, { EL_SIGN_NO_ENTRY, -1, -1, FALSE, IMG_SIGN_NO_ENTRY }, { EL_SIGN_EMERGENCY_EXIT, -1, -1, FALSE, IMG_SIGN_EMERGENCY_EXIT }, { EL_SIGN_YIN_YANG, -1, -1, FALSE, IMG_SIGN_YIN_YANG }, { EL_SIGN_EXCLAMATION, -1, -1, FALSE, IMG_SIGN_EXCLAMATION }, { EL_SIGN_STOP, -1, -1, FALSE, IMG_SIGN_STOP }, { EL_SIGN_PARKING, -1, -1, FALSE, IMG_SIGN_PARKING }, { EL_SIGN_WHEELCHAIR, -1, -1, FALSE, IMG_SIGN_WHEELCHAIR }, { EL_SIGN_ENTRY_FORBIDDEN, -1, -1, FALSE, IMG_SIGN_ENTRY_FORBIDDEN }, { EL_SPERMS, -1, -1, FALSE, IMG_SPERMS }, { EL_BULLET, -1, -1, FALSE, IMG_BULLET }, { EL_HEART, -1, -1, FALSE, IMG_HEART }, { EL_CROSS, -1, -1, FALSE, IMG_CROSS }, { EL_FRANKIE, -1, -1, FALSE, IMG_FRANKIE }, { EL_SIGN_SPERMS, -1, -1, FALSE, IMG_SIGN_SPERMS }, { EL_SIGN_BULLET, -1, -1, FALSE, IMG_SIGN_BULLET }, { EL_SIGN_HEART, -1, -1, FALSE, IMG_SIGN_HEART }, { EL_SIGN_CROSS, -1, -1, FALSE, IMG_SIGN_CROSS }, { EL_SIGN_FRANKIE, -1, -1, FALSE, IMG_SIGN_FRANKIE }, { EL_LANDMINE, -1, -1, FALSE, IMG_LANDMINE }, { EL_DC_LANDMINE, -1, -1, FALSE, IMG_DC_LANDMINE }, { EL_STEELWALL_SLIPPERY, -1, -1, FALSE, IMG_STEELWALL_SLIPPERY }, { EL_EXTRA_TIME, -1, -1, FALSE, IMG_EXTRA_TIME }, { EL_SHIELD_NORMAL, -1, -1, FALSE, IMG_SHIELD_NORMAL }, { EL_SHIELD_NORMAL_ACTIVE, -1, -1, FALSE, IMG_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_NORMAL, ACTION_ACTIVE, -1, FALSE, IMG_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_DEADLY, -1, -1, FALSE, IMG_SHIELD_DEADLY }, { EL_SHIELD_DEADLY_ACTIVE, -1, -1, FALSE, IMG_SHIELD_DEADLY_ACTIVE }, { EL_SHIELD_DEADLY, ACTION_ACTIVE, -1, FALSE, IMG_SHIELD_DEADLY_ACTIVE }, { EL_SWITCHGATE_CLOSED, -1, -1, FALSE, IMG_SWITCHGATE_CLOSED }, { EL_SWITCHGATE_OPENING, -1, -1, FALSE, IMG_SWITCHGATE_OPENING }, { EL_SWITCHGATE_OPEN, -1, -1, FALSE, IMG_SWITCHGATE_OPEN }, { EL_SWITCHGATE_CLOSING, -1, -1, FALSE, IMG_SWITCHGATE_CLOSING }, { EL_TIMEGATE_CLOSED, -1, -1, FALSE, IMG_TIMEGATE_CLOSED }, { EL_TIMEGATE_OPENING, -1, -1, FALSE, IMG_TIMEGATE_OPENING }, { EL_TIMEGATE_OPEN, -1, -1, FALSE, IMG_TIMEGATE_OPEN }, { EL_TIMEGATE_CLOSING, -1, -1, FALSE, IMG_TIMEGATE_CLOSING }, { EL_PEARL, -1, -1, FALSE, IMG_PEARL }, { EL_PEARL_BREAKING, -1, -1, FALSE, IMG_PEARL_BREAKING }, { EL_PEARL, ACTION_BREAKING, -1, FALSE, IMG_PEARL_BREAKING }, { EL_CRYSTAL, -1, -1, FALSE, IMG_CRYSTAL }, { EL_WALL_PEARL, -1, -1, FALSE, IMG_WALL_PEARL }, { EL_WALL_CRYSTAL, -1, -1, FALSE, IMG_WALL_CRYSTAL }, { EL_DC_STEELWALL_1_LEFT, -1, -1, FALSE, IMG_DC_STEELWALL_1_LEFT }, { EL_DC_STEELWALL_1_RIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_1_RIGHT }, { EL_DC_STEELWALL_1_TOP, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOP }, { EL_DC_STEELWALL_1_BOTTOM, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOM }, { EL_DC_STEELWALL_1_HORIZONTAL, -1, -1, FALSE, IMG_DC_STEELWALL_1_HORIZONTAL }, { EL_DC_STEELWALL_1_VERTICAL, -1, -1, FALSE, IMG_DC_STEELWALL_1_VERTICAL }, { EL_DC_STEELWALL_1_TOPLEFT, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPLEFT }, { EL_DC_STEELWALL_1_TOPRIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPRIGHT }, { EL_DC_STEELWALL_1_BOTTOMLEFT, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMLEFT }, { EL_DC_STEELWALL_1_BOTTOMRIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMRIGHT }, { EL_DC_STEELWALL_1_TOPLEFT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPLEFT_2 }, { EL_DC_STEELWALL_1_TOPRIGHT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_TOPRIGHT_2 }, { EL_DC_STEELWALL_1_BOTTOMLEFT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMLEFT_2 }, { EL_DC_STEELWALL_1_BOTTOMRIGHT_2, -1, -1, FALSE, IMG_DC_STEELWALL_1_BOTTOMRIGHT_2 }, { EL_DC_STEELWALL_2_LEFT, -1, -1, FALSE, IMG_DC_STEELWALL_2_LEFT }, { EL_DC_STEELWALL_2_RIGHT, -1, -1, FALSE, IMG_DC_STEELWALL_2_RIGHT }, { EL_DC_STEELWALL_2_TOP, -1, -1, FALSE, IMG_DC_STEELWALL_2_TOP }, { EL_DC_STEELWALL_2_BOTTOM, -1, -1, FALSE, IMG_DC_STEELWALL_2_BOTTOM }, { EL_DC_STEELWALL_2_HORIZONTAL, -1, -1, FALSE, IMG_DC_STEELWALL_2_HORIZONTAL }, { EL_DC_STEELWALL_2_VERTICAL, -1, -1, FALSE, IMG_DC_STEELWALL_2_VERTICAL }, { EL_DC_STEELWALL_2_MIDDLE, -1, -1, FALSE, IMG_DC_STEELWALL_2_MIDDLE }, { EL_DC_STEELWALL_2_SINGLE, -1, -1, FALSE, IMG_DC_STEELWALL_2_SINGLE }, { EL_TUBE_RIGHT_DOWN, -1, -1, FALSE, IMG_TUBE_RIGHT_DOWN }, { EL_TUBE_HORIZONTAL_DOWN, -1, -1, FALSE, IMG_TUBE_HORIZONTAL_DOWN }, { EL_TUBE_LEFT_DOWN, -1, -1, FALSE, IMG_TUBE_LEFT_DOWN }, { EL_TUBE_HORIZONTAL, -1, -1, FALSE, IMG_TUBE_HORIZONTAL }, { EL_TUBE_VERTICAL_RIGHT, -1, -1, FALSE, IMG_TUBE_VERTICAL_RIGHT }, { EL_TUBE_ANY, -1, -1, FALSE, IMG_TUBE_ANY }, { EL_TUBE_VERTICAL_LEFT, -1, -1, FALSE, IMG_TUBE_VERTICAL_LEFT }, { EL_TUBE_VERTICAL, -1, -1, FALSE, IMG_TUBE_VERTICAL }, { EL_TUBE_RIGHT_UP, -1, -1, FALSE, IMG_TUBE_RIGHT_UP }, { EL_TUBE_HORIZONTAL_UP, -1, -1, FALSE, IMG_TUBE_HORIZONTAL_UP }, { EL_TUBE_LEFT_UP, -1, -1, FALSE, IMG_TUBE_LEFT_UP }, { EL_TRAP, -1, -1, FALSE, IMG_TRAP }, { EL_TRAP_ACTIVE, -1, -1, FALSE, IMG_TRAP_ACTIVE }, { EL_TRAP, ACTION_ACTIVE, -1, FALSE, IMG_TRAP_ACTIVE }, { EL_DX_SUPABOMB, -1, -1, FALSE, IMG_DX_SUPABOMB }, { EL_KEY_1, -1, -1, FALSE, IMG_KEY_1 }, { EL_KEY_2, -1, -1, FALSE, IMG_KEY_2 }, { EL_KEY_3, -1, -1, FALSE, IMG_KEY_3 }, { EL_KEY_4, -1, -1, FALSE, IMG_KEY_4 }, { EL_GATE_1, -1, -1, FALSE, IMG_GATE_1 }, { EL_GATE_2, -1, -1, FALSE, IMG_GATE_2 }, { EL_GATE_3, -1, -1, FALSE, IMG_GATE_3 }, { EL_GATE_4, -1, -1, FALSE, IMG_GATE_4 }, { EL_GATE_1_GRAY, -1, -1, FALSE, IMG_GATE_1_GRAY }, { EL_GATE_1_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_1_GRAY_ACTIVE }, { EL_GATE_1_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_1_GRAY_ACTIVE }, { EL_GATE_2_GRAY, -1, -1, FALSE, IMG_GATE_2_GRAY }, { EL_GATE_2_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_2_GRAY_ACTIVE }, { EL_GATE_2_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_2_GRAY_ACTIVE }, { EL_GATE_3_GRAY, -1, -1, FALSE, IMG_GATE_3_GRAY }, { EL_GATE_3_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_3_GRAY_ACTIVE }, { EL_GATE_3_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_3_GRAY_ACTIVE }, { EL_GATE_4_GRAY, -1, -1, FALSE, IMG_GATE_4_GRAY }, { EL_GATE_4_GRAY_ACTIVE, -1, -1, FALSE, IMG_GATE_4_GRAY_ACTIVE }, { EL_GATE_4_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_GATE_4_GRAY_ACTIVE }, { EL_GAME_OF_LIFE, -1, -1, FALSE, IMG_GAME_OF_LIFE }, { EL_BIOMAZE, -1, -1, FALSE, IMG_BIOMAZE }, { EL_PACMAN, -1, -1, FALSE, IMG_PACMAN }, { EL_PACMAN_RIGHT, -1, -1, FALSE, IMG_PACMAN_RIGHT }, { EL_PACMAN, -1, MV_BIT_RIGHT, FALSE, IMG_PACMAN_RIGHT }, { EL_PACMAN_UP, -1, -1, FALSE, IMG_PACMAN_UP }, { EL_PACMAN, -1, MV_BIT_UP, FALSE, IMG_PACMAN_UP }, { EL_PACMAN_LEFT, -1, -1, FALSE, IMG_PACMAN_LEFT }, { EL_PACMAN, -1, MV_BIT_LEFT, FALSE, IMG_PACMAN_LEFT }, { EL_PACMAN_DOWN, -1, -1, FALSE, IMG_PACMAN_DOWN }, { EL_PACMAN, -1, MV_BIT_DOWN, FALSE, IMG_PACMAN_DOWN }, { EL_PACMAN, ACTION_TURNING_FROM_RIGHT, -1, FALSE, IMG_PACMAN_TURNING_FROM_RIGHT }, { EL_PACMAN, ACTION_TURNING_FROM_UP, -1, FALSE, IMG_PACMAN_TURNING_FROM_UP }, { EL_PACMAN, ACTION_TURNING_FROM_LEFT, -1, FALSE, IMG_PACMAN_TURNING_FROM_LEFT }, { EL_PACMAN, ACTION_TURNING_FROM_DOWN, -1, FALSE, IMG_PACMAN_TURNING_FROM_DOWN }, { EL_LAMP, -1, -1, FALSE, IMG_LAMP }, { EL_LAMP_ACTIVE, -1, -1, FALSE, IMG_LAMP_ACTIVE }, { EL_LAMP, ACTION_ACTIVE, -1, FALSE, IMG_LAMP_ACTIVE }, { EL_TIME_ORB_FULL, -1, -1, FALSE, IMG_TIME_ORB_FULL }, { EL_TIME_ORB_EMPTY, -1, -1, FALSE, IMG_TIME_ORB_EMPTY }, { EL_EMERALD_YELLOW, -1, -1, FALSE, IMG_EMERALD_YELLOW }, { EL_EMERALD_YELLOW, ACTION_MOVING, -1, FALSE, IMG_EMERALD_YELLOW_MOVING }, { EL_EMERALD_YELLOW, ACTION_FALLING, -1, FALSE, IMG_EMERALD_YELLOW_FALLING }, { EL_EMERALD_RED, -1, -1, FALSE, IMG_EMERALD_RED }, { EL_EMERALD_RED, ACTION_MOVING, -1, FALSE, IMG_EMERALD_RED_MOVING }, { EL_EMERALD_RED, ACTION_FALLING, -1, FALSE, IMG_EMERALD_RED_FALLING }, { EL_EMERALD_PURPLE, -1, -1, FALSE, IMG_EMERALD_PURPLE }, { EL_EMERALD_PURPLE, ACTION_MOVING, -1, FALSE, IMG_EMERALD_PURPLE_MOVING }, { EL_EMERALD_PURPLE, ACTION_FALLING, -1, FALSE, IMG_EMERALD_PURPLE_FALLING }, { EL_WALL_EMERALD_YELLOW, -1, -1, FALSE, IMG_WALL_EMERALD_YELLOW }, { EL_WALL_EMERALD_RED, -1, -1, FALSE, IMG_WALL_EMERALD_RED }, { EL_WALL_EMERALD_PURPLE, -1, -1, FALSE, IMG_WALL_EMERALD_PURPLE }, { EL_WALL_BD_DIAMOND, -1, -1, FALSE, IMG_WALL_BD_DIAMOND }, { EL_EXPANDABLE_WALL, -1, -1, FALSE, IMG_EXPANDABLE_WALL }, { EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1, FALSE, IMG_EXPANDABLE_WALL_HORIZONTAL }, { EL_EXPANDABLE_WALL_VERTICAL, -1, -1, FALSE, IMG_EXPANDABLE_WALL_VERTICAL }, { EL_EXPANDABLE_WALL_ANY, -1, -1, FALSE, IMG_EXPANDABLE_WALL_ANY }, { EL_EXPANDABLE_STEELWALL_HORIZONTAL, -1, -1, FALSE, IMG_EXPANDABLE_STEELWALL_HORIZONTAL }, { EL_EXPANDABLE_STEELWALL_VERTICAL, -1, -1, FALSE, IMG_EXPANDABLE_STEELWALL_VERTICAL }, { EL_EXPANDABLE_STEELWALL_ANY, -1, -1, FALSE, IMG_EXPANDABLE_STEELWALL_ANY }, { EL_BD_EXPANDABLE_WALL, -1, -1, FALSE, IMG_BD_EXPANDABLE_WALL }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_WALL_GROWING_LEFT }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_WALL_GROWING_LEFT }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_WALL_GROWING_RIGHT }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_WALL_GROWING_RIGHT }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_UP, FALSE, IMG_EXPANDABLE_WALL_GROWING_UP }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_UP, FALSE, IMG_EXPANDABLE_WALL_GROWING_UP }, { EL_EXPANDABLE_WALL, ACTION_GROWING, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_WALL_GROWING_DOWN }, { EL_EXPANDABLE_WALL_GROWING, -1, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_WALL_GROWING_DOWN }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_LEFT }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_LEFT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_LEFT }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_RIGHT, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_UP, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_UP }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_UP, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_UP }, { EL_EXPANDABLE_STEELWALL, ACTION_GROWING, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_DOWN }, { EL_EXPANDABLE_STEELWALL_GROWING, -1, MV_BIT_DOWN, FALSE, IMG_EXPANDABLE_STEELWALL_GROWING_DOWN }, { EL_BLACK_ORB, -1, -1, FALSE, IMG_BLACK_ORB }, { EL_SPEED_PILL, -1, -1, FALSE, IMG_SPEED_PILL }, { EL_DARK_YAMYAM, -1, -1, FALSE, IMG_DARK_YAMYAM }, { EL_DYNABOMB, -1, -1, FALSE, IMG_DYNABOMB }, { EL_DYNABOMB_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_ACTIVE }, { EL_DYNABOMB, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_ACTIVE }, { EL_DYNABOMB_PLAYER_1, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_1 }, { EL_DYNABOMB_PLAYER_1_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_1_ACTIVE }, { EL_DYNABOMB_PLAYER_1, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_1_ACTIVE }, { EL_DYNABOMB_PLAYER_2, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_2 }, { EL_DYNABOMB_PLAYER_2_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_2_ACTIVE }, { EL_DYNABOMB_PLAYER_2, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_2_ACTIVE }, { EL_DYNABOMB_PLAYER_3, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_3 }, { EL_DYNABOMB_PLAYER_3_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_3_ACTIVE }, { EL_DYNABOMB_PLAYER_3, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_3_ACTIVE }, { EL_DYNABOMB_PLAYER_4, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_4 }, { EL_DYNABOMB_PLAYER_4_ACTIVE, -1, -1, FALSE, IMG_DYNABOMB_PLAYER_4_ACTIVE }, { EL_DYNABOMB_PLAYER_4, ACTION_ACTIVE, -1, FALSE, IMG_DYNABOMB_PLAYER_4_ACTIVE }, { EL_DYNABOMB_INCREASE_NUMBER, -1, -1, FALSE, IMG_DYNABOMB_INCREASE_NUMBER }, { EL_DYNABOMB_INCREASE_SIZE, -1, -1, FALSE, IMG_DYNABOMB_INCREASE_SIZE }, { EL_DYNABOMB_INCREASE_POWER, -1, -1, FALSE, IMG_DYNABOMB_INCREASE_POWER }, { EL_PIG, -1, -1, FALSE, IMG_PIG }, { EL_PIG, -1, MV_BIT_DOWN, FALSE, IMG_PIG_DOWN }, { EL_PIG, -1, MV_BIT_UP, FALSE, IMG_PIG_UP }, { EL_PIG, -1, MV_BIT_LEFT, FALSE, IMG_PIG_LEFT }, { EL_PIG, -1, MV_BIT_RIGHT, FALSE, IMG_PIG_RIGHT }, { EL_PIG, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PIG_MOVING_DOWN }, { EL_PIG, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PIG_MOVING_UP }, { EL_PIG, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PIG_MOVING_LEFT }, { EL_PIG, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PIG_MOVING_RIGHT }, { EL_PIG, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PIG_DIGGING_DOWN }, { EL_PIG, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PIG_DIGGING_UP }, { EL_PIG, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PIG_DIGGING_LEFT }, { EL_PIG, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PIG_DIGGING_RIGHT }, { EL_DRAGON, -1, -1, FALSE, IMG_DRAGON }, { EL_DRAGON, -1, MV_BIT_DOWN, FALSE, IMG_DRAGON_DOWN }, { EL_DRAGON, -1, MV_BIT_UP, FALSE, IMG_DRAGON_UP }, { EL_DRAGON, -1, MV_BIT_LEFT, FALSE, IMG_DRAGON_LEFT }, { EL_DRAGON, -1, MV_BIT_RIGHT, FALSE, IMG_DRAGON_RIGHT }, { EL_DRAGON, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_DRAGON_MOVING_DOWN }, { EL_DRAGON, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_DRAGON_MOVING_UP }, { EL_DRAGON, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_DRAGON_MOVING_LEFT }, { EL_DRAGON, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_DRAGON_MOVING_RIGHT }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_DOWN, FALSE, IMG_DRAGON_ATTACKING_DOWN }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_UP, FALSE, IMG_DRAGON_ATTACKING_UP }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_LEFT, FALSE, IMG_DRAGON_ATTACKING_LEFT }, { EL_DRAGON, ACTION_ATTACKING, MV_BIT_RIGHT, FALSE, IMG_DRAGON_ATTACKING_RIGHT }, { EL_MOLE, -1, -1, FALSE, IMG_MOLE }, { EL_MOLE_DOWN, -1, -1, FALSE, IMG_MOLE_DOWN }, { EL_MOLE, -1, MV_BIT_DOWN, FALSE, IMG_MOLE_DOWN }, { EL_MOLE_UP, -1, -1, FALSE, IMG_MOLE_UP }, { EL_MOLE, -1, MV_BIT_UP, FALSE, IMG_MOLE_UP }, { EL_MOLE_LEFT, -1, -1, FALSE, IMG_MOLE_LEFT }, { EL_MOLE, -1, MV_BIT_LEFT, FALSE, IMG_MOLE_LEFT }, { EL_MOLE_RIGHT, -1, -1, FALSE, IMG_MOLE_RIGHT }, { EL_MOLE, -1, MV_BIT_RIGHT, FALSE, IMG_MOLE_RIGHT }, { EL_MOLE, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_MOLE_MOVING_DOWN }, { EL_MOLE, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_MOLE_MOVING_UP }, { EL_MOLE, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_MOLE_MOVING_LEFT }, { EL_MOLE, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_MOLE_MOVING_RIGHT }, { EL_MOLE, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_MOLE_DIGGING_DOWN }, { EL_MOLE, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_MOLE_DIGGING_UP }, { EL_MOLE, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_MOLE_DIGGING_LEFT }, { EL_MOLE, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_MOLE_DIGGING_RIGHT }, { EL_PENGUIN, -1, -1, FALSE, IMG_PENGUIN }, { EL_PENGUIN, -1, MV_BIT_DOWN, FALSE, IMG_PENGUIN_DOWN }, { EL_PENGUIN, -1, MV_BIT_UP, FALSE, IMG_PENGUIN_UP }, { EL_PENGUIN, -1, MV_BIT_LEFT, FALSE, IMG_PENGUIN_LEFT }, { EL_PENGUIN, -1, MV_BIT_RIGHT, FALSE, IMG_PENGUIN_RIGHT }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PENGUIN_MOVING_DOWN }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PENGUIN_MOVING_UP }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PENGUIN_MOVING_LEFT }, { EL_PENGUIN, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PENGUIN_MOVING_RIGHT }, { EL_SATELLITE, -1, -1, FALSE, IMG_SATELLITE }, { EL_STONEBLOCK, -1, -1, FALSE, IMG_STONEBLOCK }, { EL_PLAYER_1, -1, -1, FALSE, IMG_PLAYER_1 }, { EL_PLAYER_1, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_DOWN }, { EL_PLAYER_1, -1, MV_BIT_UP, FALSE, IMG_PLAYER_1_UP }, { EL_PLAYER_1, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_LEFT }, { EL_PLAYER_1, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_RIGHT }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_MOVING_DOWN }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_1_MOVING_UP }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_MOVING_LEFT }, { EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_MOVING_RIGHT }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_DIGGING_DOWN }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_1_DIGGING_UP }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_DIGGING_LEFT }, { EL_PLAYER_1, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_DIGGING_RIGHT }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_COLLECTING_DOWN }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_1_COLLECTING_UP }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_COLLECTING_LEFT }, { EL_PLAYER_1, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_COLLECTING_RIGHT }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_PUSHING_DOWN }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_1_PUSHING_UP }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_PUSHING_LEFT }, { EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_PUSHING_RIGHT }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_1_SNAPPING_DOWN }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_1_SNAPPING_UP }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_1_SNAPPING_LEFT }, { EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_1_SNAPPING_RIGHT }, { EL_PLAYER_2, -1, -1, FALSE, IMG_PLAYER_2 }, { EL_PLAYER_2, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_DOWN }, { EL_PLAYER_2, -1, MV_BIT_UP, FALSE, IMG_PLAYER_2_UP }, { EL_PLAYER_2, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_LEFT }, { EL_PLAYER_2, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_RIGHT }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_MOVING_DOWN }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_2_MOVING_UP }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_MOVING_LEFT }, { EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_MOVING_RIGHT }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_DIGGING_DOWN }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_2_DIGGING_UP }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_DIGGING_LEFT }, { EL_PLAYER_2, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_DIGGING_RIGHT }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_COLLECTING_DOWN }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_2_COLLECTING_UP }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_COLLECTING_LEFT }, { EL_PLAYER_2, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_COLLECTING_RIGHT }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_PUSHING_DOWN }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_2_PUSHING_UP }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_PUSHING_LEFT }, { EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_PUSHING_RIGHT }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_2_SNAPPING_DOWN }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_2_SNAPPING_UP }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_2_SNAPPING_LEFT }, { EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_2_SNAPPING_RIGHT }, { EL_PLAYER_3, -1, -1, FALSE, IMG_PLAYER_3 }, { EL_PLAYER_3, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_DOWN }, { EL_PLAYER_3, -1, MV_BIT_UP, FALSE, IMG_PLAYER_3_UP }, { EL_PLAYER_3, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_LEFT }, { EL_PLAYER_3, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_RIGHT }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_MOVING_DOWN }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_3_MOVING_UP }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_MOVING_LEFT }, { EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_MOVING_RIGHT }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_DIGGING_DOWN }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_3_DIGGING_UP }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_DIGGING_LEFT }, { EL_PLAYER_3, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_DIGGING_RIGHT }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_COLLECTING_DOWN }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_3_COLLECTING_UP }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_COLLECTING_LEFT }, { EL_PLAYER_3, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_COLLECTING_RIGHT }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_PUSHING_DOWN }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_3_PUSHING_UP }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_PUSHING_LEFT }, { EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_PUSHING_RIGHT }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_3_SNAPPING_DOWN }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_3_SNAPPING_UP }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_3_SNAPPING_LEFT }, { EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_3_SNAPPING_RIGHT }, { EL_PLAYER_4, -1, -1, FALSE, IMG_PLAYER_4 }, { EL_PLAYER_4, -1, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_DOWN }, { EL_PLAYER_4, -1, MV_BIT_UP, FALSE, IMG_PLAYER_4_UP }, { EL_PLAYER_4, -1, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_LEFT }, { EL_PLAYER_4, -1, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_RIGHT }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_MOVING_DOWN }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP, FALSE, IMG_PLAYER_4_MOVING_UP }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_MOVING_LEFT }, { EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_MOVING_RIGHT }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_DIGGING_DOWN }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_PLAYER_4_DIGGING_UP }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_DIGGING_LEFT }, { EL_PLAYER_4, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_DIGGING_RIGHT }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_COLLECTING_DOWN }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_UP, FALSE, IMG_PLAYER_4_COLLECTING_UP }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_COLLECTING_LEFT }, { EL_PLAYER_4, ACTION_COLLECTING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_COLLECTING_RIGHT }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_PUSHING_DOWN }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP, FALSE, IMG_PLAYER_4_PUSHING_UP }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_PUSHING_LEFT }, { EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_PUSHING_RIGHT }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN, FALSE, IMG_PLAYER_4_SNAPPING_DOWN }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP, FALSE, IMG_PLAYER_4_SNAPPING_UP }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT, FALSE, IMG_PLAYER_4_SNAPPING_LEFT }, { EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT, FALSE, IMG_PLAYER_4_SNAPPING_RIGHT }, { EL_DEFAULT, ACTION_EXPLODING, -1, FALSE, IMG_DEFAULT_EXPLODING }, { EL_STEELWALL_TOPLEFT, -1, -1, FALSE, IMG_STEELWALL_TOPLEFT }, { EL_STEELWALL_TOPRIGHT, -1, -1, FALSE, IMG_STEELWALL_TOPRIGHT }, { EL_STEELWALL_BOTTOMLEFT, -1, -1, FALSE, IMG_STEELWALL_BOTTOMLEFT }, { EL_STEELWALL_BOTTOMRIGHT, -1, -1, FALSE, IMG_STEELWALL_BOTTOMRIGHT }, { EL_STEELWALL_HORIZONTAL, -1, -1, FALSE, IMG_STEELWALL_HORIZONTAL }, { EL_STEELWALL_VERTICAL, -1, -1, FALSE, IMG_STEELWALL_VERTICAL }, { EL_INVISIBLE_STEELWALL_TOPLEFT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_TOPLEFT }, { EL_INVISIBLE_STEELWALL_TOPRIGHT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_TOPRIGHT }, { EL_INVISIBLE_STEELWALL_BOTTOMLEFT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT }, { EL_INVISIBLE_STEELWALL_BOTTOMRIGHT, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT }, { EL_INVISIBLE_STEELWALL_HORIZONTAL, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_HORIZONTAL }, { EL_INVISIBLE_STEELWALL_VERTICAL, -1, -1, FALSE, IMG_INVISIBLE_STEELWALL_VERTICAL }, { EL_ARROW_LEFT, -1, -1, FALSE, IMG_ARROW_LEFT }, { EL_ARROW_RIGHT, -1, -1, FALSE, IMG_ARROW_RIGHT }, { EL_ARROW_UP, -1, -1, FALSE, IMG_ARROW_UP }, { EL_ARROW_DOWN, -1, -1, FALSE, IMG_ARROW_DOWN }, { EL_UNKNOWN, -1, -1, FALSE, IMG_UNKNOWN }, { EL_TRIGGER_ELEMENT, -1, -1, FALSE, IMG_TRIGGER_ELEMENT }, { EL_TRIGGER_PLAYER, -1, -1, FALSE, IMG_TRIGGER_PLAYER }, { EL_TRIGGER_CE_VALUE, -1, -1, FALSE, IMG_TRIGGER_CE_VALUE }, { EL_TRIGGER_CE_SCORE, -1, -1, FALSE, IMG_TRIGGER_CE_SCORE }, { EL_CURRENT_CE_VALUE, -1, -1, FALSE, IMG_CURRENT_CE_VALUE }, { EL_CURRENT_CE_SCORE, -1, -1, FALSE, IMG_CURRENT_CE_SCORE }, { EL_PREV_CE_1, -1, -1, FALSE, IMG_PREV_CE_1 }, { EL_PREV_CE_2, -1, -1, FALSE, IMG_PREV_CE_2 }, { EL_PREV_CE_3, -1, -1, FALSE, IMG_PREV_CE_3 }, { EL_PREV_CE_4, -1, -1, FALSE, IMG_PREV_CE_4 }, { EL_PREV_CE_5, -1, -1, FALSE, IMG_PREV_CE_5 }, { EL_PREV_CE_6, -1, -1, FALSE, IMG_PREV_CE_6 }, { EL_PREV_CE_7, -1, -1, FALSE, IMG_PREV_CE_7 }, { EL_PREV_CE_8, -1, -1, FALSE, IMG_PREV_CE_8 }, { EL_NEXT_CE_1, -1, -1, FALSE, IMG_NEXT_CE_1 }, { EL_NEXT_CE_2, -1, -1, FALSE, IMG_NEXT_CE_2 }, { EL_NEXT_CE_3, -1, -1, FALSE, IMG_NEXT_CE_3 }, { EL_NEXT_CE_4, -1, -1, FALSE, IMG_NEXT_CE_4 }, { EL_NEXT_CE_5, -1, -1, FALSE, IMG_NEXT_CE_5 }, { EL_NEXT_CE_6, -1, -1, FALSE, IMG_NEXT_CE_6 }, { EL_NEXT_CE_7, -1, -1, FALSE, IMG_NEXT_CE_7 }, { EL_NEXT_CE_8, -1, -1, FALSE, IMG_NEXT_CE_8 }, { EL_SELF, -1, -1, FALSE, IMG_SELF }, { EL_ANY_ELEMENT, -1, -1, FALSE, IMG_ANY_ELEMENT }, { EL_EMC_KEY_5, -1, -1, FALSE, IMG_EMC_KEY_5 }, { EL_EMC_KEY_6, -1, -1, FALSE, IMG_EMC_KEY_6 }, { EL_EMC_KEY_7, -1, -1, FALSE, IMG_EMC_KEY_7 }, { EL_EMC_KEY_8, -1, -1, FALSE, IMG_EMC_KEY_8 }, { EL_EMC_GATE_5, -1, -1, FALSE, IMG_EMC_GATE_5 }, { EL_EMC_GATE_6, -1, -1, FALSE, IMG_EMC_GATE_6 }, { EL_EMC_GATE_7, -1, -1, FALSE, IMG_EMC_GATE_7 }, { EL_EMC_GATE_8, -1, -1, FALSE, IMG_EMC_GATE_8 }, { EL_EMC_GATE_5_GRAY, -1, -1, FALSE, IMG_EMC_GATE_5_GRAY }, { EL_EMC_GATE_5_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_5_GRAY_ACTIVE }, { EL_EMC_GATE_5_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_5_GRAY_ACTIVE }, { EL_EMC_GATE_6_GRAY, -1, -1, FALSE, IMG_EMC_GATE_6_GRAY }, { EL_EMC_GATE_6_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_6_GRAY_ACTIVE }, { EL_EMC_GATE_6_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_6_GRAY_ACTIVE }, { EL_EMC_GATE_7_GRAY, -1, -1, FALSE, IMG_EMC_GATE_7_GRAY }, { EL_EMC_GATE_7_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_7_GRAY_ACTIVE }, { EL_EMC_GATE_7_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_7_GRAY_ACTIVE }, { EL_EMC_GATE_8_GRAY, -1, -1, FALSE, IMG_EMC_GATE_8_GRAY }, { EL_EMC_GATE_8_GRAY_ACTIVE, -1, -1, FALSE, IMG_EMC_GATE_8_GRAY_ACTIVE }, { EL_EMC_GATE_8_GRAY, ACTION_ACTIVE, -1, FALSE, IMG_EMC_GATE_8_GRAY_ACTIVE }, { EL_EMC_ANDROID, -1, -1, FALSE, IMG_EMC_ANDROID }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT, FALSE, IMG_EMC_ANDROID_SHRINKING_UPLEFT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT, FALSE, IMG_EMC_ANDROID_GROWING_DOWNRIGHT }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT, FALSE, IMG_EMC_ANDROID_SHRINKING_DOWNLEFT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT, FALSE, IMG_EMC_ANDROID_GROWING_UPRIGHT }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT, FALSE, IMG_EMC_ANDROID_SHRINKING_UPRIGHT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT, FALSE, IMG_EMC_ANDROID_GROWING_DOWNLEFT }, { EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT, FALSE, IMG_EMC_ANDROID_SHRINKING_DOWNRIGHT }, { EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT, FALSE, IMG_EMC_ANDROID_GROWING_UPLEFT }, { EL_EMC_GRASS, -1, -1, FALSE, IMG_EMC_GRASS }, { EL_EMC_GRASS, -1, -1, TRUE, IMG_EMC_GRASS_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT, FALSE, IMG_EMC_GRASS_DIGGING_LEFT }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT, FALSE, IMG_EMC_GRASS_DIGGING_RIGHT }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP, FALSE, IMG_EMC_GRASS_DIGGING_UP }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN, FALSE, IMG_EMC_GRASS_DIGGING_DOWN }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT, TRUE, IMG_EMC_GRASS_DIGGING_LEFT_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT, TRUE, IMG_EMC_GRASS_DIGGING_RIGHT_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP, TRUE, IMG_EMC_GRASS_DIGGING_UP_CRUMBLED }, { EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN, TRUE, IMG_EMC_GRASS_DIGGING_DOWN_CRUMBLED }, { EL_EMC_MAGIC_BALL, -1, -1, FALSE, IMG_EMC_MAGIC_BALL }, { EL_EMC_MAGIC_BALL_ACTIVE, -1, -1, FALSE, IMG_EMC_MAGIC_BALL_ACTIVE }, { EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1, FALSE, IMG_EMC_MAGIC_BALL_ACTIVE }, { EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1, FALSE, IMG_EMC_MAGIC_BALL_DROPPING }, { EL_EMC_MAGIC_BALL_SWITCH, -1, -1, FALSE, IMG_EMC_MAGIC_BALL_SWITCH }, { EL_EMC_MAGIC_BALL_SWITCH_ACTIVE, -1, -1, FALSE, IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE }, { EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1, FALSE, IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE }, { EL_EMC_SPRING_BUMPER, -1, -1, FALSE, IMG_EMC_SPRING_BUMPER }, { EL_EMC_SPRING_BUMPER_ACTIVE, -1, -1, FALSE, IMG_EMC_SPRING_BUMPER_ACTIVE }, { EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1, FALSE, IMG_EMC_SPRING_BUMPER_ACTIVE }, { EL_EMC_PLANT, -1, -1, FALSE, IMG_EMC_PLANT }, { EL_EMC_PLANT, -1, -1, TRUE, IMG_EMC_PLANT_CRUMBLED }, { EL_EMC_LENSES, -1, -1, FALSE, IMG_EMC_LENSES }, { EL_EMC_MAGNIFIER, -1, -1, FALSE, IMG_EMC_MAGNIFIER }, { EL_EMC_WALL_9, -1, -1, FALSE, IMG_EMC_WALL_9 }, { EL_EMC_WALL_10, -1, -1, FALSE, IMG_EMC_WALL_10 }, { EL_EMC_WALL_11, -1, -1, FALSE, IMG_EMC_WALL_11 }, { EL_EMC_WALL_12, -1, -1, FALSE, IMG_EMC_WALL_12 }, { EL_EMC_WALL_13, -1, -1, FALSE, IMG_EMC_WALL_13 }, { EL_EMC_WALL_14, -1, -1, FALSE, IMG_EMC_WALL_14 }, { EL_EMC_WALL_15, -1, -1, FALSE, IMG_EMC_WALL_15 }, { EL_EMC_WALL_16, -1, -1, FALSE, IMG_EMC_WALL_16 }, { EL_EMC_WALL_SLIPPERY_1, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_1 }, { EL_EMC_WALL_SLIPPERY_2, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_2 }, { EL_EMC_WALL_SLIPPERY_3, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_3 }, { EL_EMC_WALL_SLIPPERY_4, -1, -1, FALSE, IMG_EMC_WALL_SLIPPERY_4 }, { EL_EMC_FAKE_GRASS, -1, -1, FALSE, IMG_EMC_FAKE_GRASS }, { EL_EMC_FAKE_GRASS, -1, -1, TRUE, IMG_EMC_FAKE_GRASS_CRUMBLED }, { EL_EMC_FAKE_GRASS_ACTIVE, -1, -1, FALSE, IMG_EMC_FAKE_GRASS_ACTIVE }, { EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1, FALSE, IMG_EMC_FAKE_GRASS_ACTIVE }, { EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1, TRUE, IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED }, { EL_EMC_FAKE_GRASS_ACTIVE, -1, -1, TRUE, IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED }, { EL_EMC_FAKE_ACID, -1, -1, FALSE, IMG_EMC_FAKE_ACID }, { EL_EMC_DRIPPER, -1, -1, FALSE, IMG_EMC_DRIPPER }, { EL_EMC_DRIPPER_ACTIVE, -1, -1, FALSE, IMG_EMC_DRIPPER_ACTIVE }, { EL_EMC_DRIPPER, ACTION_ACTIVE, -1, FALSE, IMG_EMC_DRIPPER_ACTIVE }, { EL_MM_MCDUFFIN, -1, -1, FALSE, IMG_MM_MCDUFFIN }, { EL_MM_MCDUFFIN_RIGHT, -1, -1, FALSE, IMG_MM_MCDUFFIN_RIGHT }, { EL_MM_MCDUFFIN, -1, MV_BIT_RIGHT, FALSE, IMG_MM_MCDUFFIN_RIGHT }, { EL_MM_MCDUFFIN_UP, -1, -1, FALSE, IMG_MM_MCDUFFIN_UP }, { EL_MM_MCDUFFIN, -1, MV_BIT_UP, FALSE, IMG_MM_MCDUFFIN_UP }, { EL_MM_MCDUFFIN_LEFT, -1, -1, FALSE, IMG_MM_MCDUFFIN_LEFT }, { EL_MM_MCDUFFIN, -1, MV_BIT_LEFT, FALSE, IMG_MM_MCDUFFIN_LEFT }, { EL_MM_MCDUFFIN_DOWN, -1, -1, FALSE, IMG_MM_MCDUFFIN_DOWN }, { EL_MM_MCDUFFIN, -1, MV_BIT_DOWN, FALSE, IMG_MM_MCDUFFIN_DOWN }, { EL_MM_EXIT_CLOSED, -1, -1, FALSE, IMG_MM_EXIT_CLOSED }, { EL_MM_EXIT_OPENING, -1, -1, FALSE, IMG_MM_EXIT_OPENING }, { EL_MM_EXIT_OPEN, -1, -1, FALSE, IMG_MM_EXIT_OPEN }, { EL_MM_EXIT_CLOSING, -1, -1, FALSE, IMG_MM_EXIT_CLOSING }, { EL_MM_MIRROR_1, -1, -1, FALSE, IMG_MM_MIRROR_1 }, { EL_MM_MIRROR_2, -1, -1, FALSE, IMG_MM_MIRROR_2 }, { EL_MM_MIRROR_3, -1, -1, FALSE, IMG_MM_MIRROR_3 }, { EL_MM_MIRROR_4, -1, -1, FALSE, IMG_MM_MIRROR_4 }, { EL_MM_MIRROR_5, -1, -1, FALSE, IMG_MM_MIRROR_5 }, { EL_MM_MIRROR_6, -1, -1, FALSE, IMG_MM_MIRROR_6 }, { EL_MM_MIRROR_7, -1, -1, FALSE, IMG_MM_MIRROR_7 }, { EL_MM_MIRROR_8, -1, -1, FALSE, IMG_MM_MIRROR_8 }, { EL_MM_MIRROR_9, -1, -1, FALSE, IMG_MM_MIRROR_9 }, { EL_MM_MIRROR_10, -1, -1, FALSE, IMG_MM_MIRROR_10 }, { EL_MM_MIRROR_11, -1, -1, FALSE, IMG_MM_MIRROR_11 }, { EL_MM_MIRROR_12, -1, -1, FALSE, IMG_MM_MIRROR_12 }, { EL_MM_MIRROR_13, -1, -1, FALSE, IMG_MM_MIRROR_13 }, { EL_MM_MIRROR_14, -1, -1, FALSE, IMG_MM_MIRROR_14 }, { EL_MM_MIRROR_15, -1, -1, FALSE, IMG_MM_MIRROR_15 }, { EL_MM_MIRROR_16, -1, -1, FALSE, IMG_MM_MIRROR_16 }, { EL_MM_MIRROR_FIXED_1, -1, -1, FALSE, IMG_MM_MIRROR_FIXED_1 }, { EL_MM_MIRROR_FIXED_2, -1, -1, FALSE, IMG_MM_MIRROR_FIXED_2 }, { EL_MM_MIRROR_FIXED_3, -1, -1, FALSE, IMG_MM_MIRROR_FIXED_3 }, { EL_MM_MIRROR_FIXED_4, -1, -1, FALSE, IMG_MM_MIRROR_FIXED_4 }, { EL_MM_STEEL_GRID_FIXED_1, -1, -1, FALSE, IMG_MM_STEEL_GRID_FIXED_1 }, { EL_MM_STEEL_GRID_FIXED_2, -1, -1, FALSE, IMG_MM_STEEL_GRID_FIXED_2 }, { EL_MM_STEEL_GRID_FIXED_3, -1, -1, FALSE, IMG_MM_STEEL_GRID_FIXED_3 }, { EL_MM_STEEL_GRID_FIXED_4, -1, -1, FALSE, IMG_MM_STEEL_GRID_FIXED_4 }, { EL_MM_WOODEN_GRID_FIXED_1, -1, -1, FALSE, IMG_MM_WOODEN_GRID_FIXED_1 }, { EL_MM_WOODEN_GRID_FIXED_2, -1, -1, FALSE, IMG_MM_WOODEN_GRID_FIXED_2 }, { EL_MM_WOODEN_GRID_FIXED_3, -1, -1, FALSE, IMG_MM_WOODEN_GRID_FIXED_3 }, { EL_MM_WOODEN_GRID_FIXED_4, -1, -1, FALSE, IMG_MM_WOODEN_GRID_FIXED_4 }, { EL_MM_POLARIZER_1, -1, -1, FALSE, IMG_MM_POLARIZER_1 }, { EL_MM_POLARIZER_2, -1, -1, FALSE, IMG_MM_POLARIZER_2 }, { EL_MM_POLARIZER_3, -1, -1, FALSE, IMG_MM_POLARIZER_3 }, { EL_MM_POLARIZER_4, -1, -1, FALSE, IMG_MM_POLARIZER_4 }, { EL_MM_POLARIZER_5, -1, -1, FALSE, IMG_MM_POLARIZER_5 }, { EL_MM_POLARIZER_6, -1, -1, FALSE, IMG_MM_POLARIZER_6 }, { EL_MM_POLARIZER_7, -1, -1, FALSE, IMG_MM_POLARIZER_7 }, { EL_MM_POLARIZER_8, -1, -1, FALSE, IMG_MM_POLARIZER_8 }, { EL_MM_POLARIZER_9, -1, -1, FALSE, IMG_MM_POLARIZER_9 }, { EL_MM_POLARIZER_10, -1, -1, FALSE, IMG_MM_POLARIZER_10 }, { EL_MM_POLARIZER_11, -1, -1, FALSE, IMG_MM_POLARIZER_11 }, { EL_MM_POLARIZER_12, -1, -1, FALSE, IMG_MM_POLARIZER_12 }, { EL_MM_POLARIZER_13, -1, -1, FALSE, IMG_MM_POLARIZER_13 }, { EL_MM_POLARIZER_14, -1, -1, FALSE, IMG_MM_POLARIZER_14 }, { EL_MM_POLARIZER_15, -1, -1, FALSE, IMG_MM_POLARIZER_15 }, { EL_MM_POLARIZER_16, -1, -1, FALSE, IMG_MM_POLARIZER_16 }, { EL_MM_POLARIZER_CROSS_1, -1, -1, FALSE, IMG_MM_POLARIZER_CROSS_1 }, { EL_MM_POLARIZER_CROSS_2, -1, -1, FALSE, IMG_MM_POLARIZER_CROSS_2 }, { EL_MM_POLARIZER_CROSS_3, -1, -1, FALSE, IMG_MM_POLARIZER_CROSS_3 }, { EL_MM_POLARIZER_CROSS_4, -1, -1, FALSE, IMG_MM_POLARIZER_CROSS_4 }, { EL_MM_TELEPORTER_1, -1, -1, FALSE, IMG_MM_TELEPORTER_1 }, { EL_MM_TELEPORTER_2, -1, -1, FALSE, IMG_MM_TELEPORTER_2 }, { EL_MM_TELEPORTER_3, -1, -1, FALSE, IMG_MM_TELEPORTER_3 }, { EL_MM_TELEPORTER_4, -1, -1, FALSE, IMG_MM_TELEPORTER_4 }, { EL_MM_TELEPORTER_5, -1, -1, FALSE, IMG_MM_TELEPORTER_5 }, { EL_MM_TELEPORTER_6, -1, -1, FALSE, IMG_MM_TELEPORTER_6 }, { EL_MM_TELEPORTER_7, -1, -1, FALSE, IMG_MM_TELEPORTER_7 }, { EL_MM_TELEPORTER_8, -1, -1, FALSE, IMG_MM_TELEPORTER_8 }, { EL_MM_TELEPORTER_9, -1, -1, FALSE, IMG_MM_TELEPORTER_9 }, { EL_MM_TELEPORTER_10, -1, -1, FALSE, IMG_MM_TELEPORTER_10 }, { EL_MM_TELEPORTER_11, -1, -1, FALSE, IMG_MM_TELEPORTER_11 }, { EL_MM_TELEPORTER_12, -1, -1, FALSE, IMG_MM_TELEPORTER_12 }, { EL_MM_TELEPORTER_13, -1, -1, FALSE, IMG_MM_TELEPORTER_13 }, { EL_MM_TELEPORTER_14, -1, -1, FALSE, IMG_MM_TELEPORTER_14 }, { EL_MM_TELEPORTER_15, -1, -1, FALSE, IMG_MM_TELEPORTER_15 }, { EL_MM_TELEPORTER_16, -1, -1, FALSE, IMG_MM_TELEPORTER_16 }, { EL_MM_TELEPORTER_RED_1, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_1 }, { EL_MM_TELEPORTER_RED_2, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_2 }, { EL_MM_TELEPORTER_RED_3, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_3 }, { EL_MM_TELEPORTER_RED_4, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_4 }, { EL_MM_TELEPORTER_RED_5, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_5 }, { EL_MM_TELEPORTER_RED_6, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_6 }, { EL_MM_TELEPORTER_RED_7, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_7 }, { EL_MM_TELEPORTER_RED_8, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_8 }, { EL_MM_TELEPORTER_RED_9, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_9 }, { EL_MM_TELEPORTER_RED_10, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_10 }, { EL_MM_TELEPORTER_RED_11, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_11 }, { EL_MM_TELEPORTER_RED_12, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_12 }, { EL_MM_TELEPORTER_RED_13, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_13 }, { EL_MM_TELEPORTER_RED_14, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_14 }, { EL_MM_TELEPORTER_RED_15, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_15 }, { EL_MM_TELEPORTER_RED_16, -1, -1, FALSE, IMG_MM_TELEPORTER_RED_16 }, { EL_MM_TELEPORTER_YELLOW_1, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_1 }, { EL_MM_TELEPORTER_YELLOW_2, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_2 }, { EL_MM_TELEPORTER_YELLOW_3, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_3 }, { EL_MM_TELEPORTER_YELLOW_4, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_4 }, { EL_MM_TELEPORTER_YELLOW_5, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_5 }, { EL_MM_TELEPORTER_YELLOW_6, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_6 }, { EL_MM_TELEPORTER_YELLOW_7, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_7 }, { EL_MM_TELEPORTER_YELLOW_8, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_8 }, { EL_MM_TELEPORTER_YELLOW_9, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_9 }, { EL_MM_TELEPORTER_YELLOW_10, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_10 }, { EL_MM_TELEPORTER_YELLOW_11, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_11 }, { EL_MM_TELEPORTER_YELLOW_12, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_12 }, { EL_MM_TELEPORTER_YELLOW_13, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_13 }, { EL_MM_TELEPORTER_YELLOW_14, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_14 }, { EL_MM_TELEPORTER_YELLOW_15, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_15 }, { EL_MM_TELEPORTER_YELLOW_16, -1, -1, FALSE, IMG_MM_TELEPORTER_YELLOW_16 }, { EL_MM_TELEPORTER_GREEN_1, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_1 }, { EL_MM_TELEPORTER_GREEN_2, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_2 }, { EL_MM_TELEPORTER_GREEN_3, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_3 }, { EL_MM_TELEPORTER_GREEN_4, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_4 }, { EL_MM_TELEPORTER_GREEN_5, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_5 }, { EL_MM_TELEPORTER_GREEN_6, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_6 }, { EL_MM_TELEPORTER_GREEN_7, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_7 }, { EL_MM_TELEPORTER_GREEN_8, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_8 }, { EL_MM_TELEPORTER_GREEN_9, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_9 }, { EL_MM_TELEPORTER_GREEN_10, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_10 }, { EL_MM_TELEPORTER_GREEN_11, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_11 }, { EL_MM_TELEPORTER_GREEN_12, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_12 }, { EL_MM_TELEPORTER_GREEN_13, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_13 }, { EL_MM_TELEPORTER_GREEN_14, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_14 }, { EL_MM_TELEPORTER_GREEN_15, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_15 }, { EL_MM_TELEPORTER_GREEN_16, -1, -1, FALSE, IMG_MM_TELEPORTER_GREEN_16 }, { EL_MM_TELEPORTER_BLUE_1, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_1 }, { EL_MM_TELEPORTER_BLUE_2, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_2 }, { EL_MM_TELEPORTER_BLUE_3, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_3 }, { EL_MM_TELEPORTER_BLUE_4, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_4 }, { EL_MM_TELEPORTER_BLUE_5, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_5 }, { EL_MM_TELEPORTER_BLUE_6, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_6 }, { EL_MM_TELEPORTER_BLUE_7, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_7 }, { EL_MM_TELEPORTER_BLUE_8, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_8 }, { EL_MM_TELEPORTER_BLUE_9, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_9 }, { EL_MM_TELEPORTER_BLUE_10, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_10 }, { EL_MM_TELEPORTER_BLUE_11, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_11 }, { EL_MM_TELEPORTER_BLUE_12, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_12 }, { EL_MM_TELEPORTER_BLUE_13, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_13 }, { EL_MM_TELEPORTER_BLUE_14, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_14 }, { EL_MM_TELEPORTER_BLUE_15, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_15 }, { EL_MM_TELEPORTER_BLUE_16, -1, -1, FALSE, IMG_MM_TELEPORTER_BLUE_16 }, { EL_MM_KETTLE, -1, -1, FALSE, IMG_MM_KETTLE }, { EL_MM_KETTLE, ACTION_EXPLODING, -1, FALSE, IMG_MM_KETTLE_EXPLODING }, { EL_MM_BOMB, -1, -1, FALSE, IMG_MM_BOMB }, { EL_MM_PRISM, -1, -1, FALSE, IMG_MM_PRISM }, { EL_MM_FUSE, -1, -1, FALSE, IMG_MM_FUSE }, { EL_MM_FUSE_ACTIVE, -1, -1, FALSE, IMG_MM_FUSE_ACTIVE }, { EL_MM_FUSE, ACTION_ACTIVE, -1, FALSE, IMG_MM_FUSE_ACTIVE }, { EL_MM_STEEL_LOCK, -1, -1, FALSE, IMG_MM_STEEL_LOCK }, { EL_MM_WOODEN_LOCK, -1, -1, FALSE, IMG_MM_WOODEN_LOCK }, { EL_MM_STEEL_BLOCK, -1, -1, FALSE, IMG_MM_STEEL_BLOCK }, { EL_MM_WOODEN_BLOCK, -1, -1, FALSE, IMG_MM_WOODEN_BLOCK }, { EL_MM_KEY, -1, -1, FALSE, IMG_MM_KEY }, { EL_MM_LIGHTBULB, -1, -1, FALSE, IMG_MM_LIGHTBULB }, { EL_MM_LIGHTBULB_ACTIVE, -1, -1, FALSE, IMG_MM_LIGHTBULB_ACTIVE }, { EL_MM_LIGHTBULB, ACTION_ACTIVE, -1, FALSE, IMG_MM_LIGHTBULB_ACTIVE }, { EL_MM_LIGHTBALL, -1, -1, FALSE, IMG_MM_LIGHTBALL }, { EL_MM_LIGHTBALL_RED, -1, -1, FALSE, IMG_MM_LIGHTBALL_RED }, { EL_MM_LIGHTBALL_BLUE, -1, -1, FALSE, IMG_MM_LIGHTBALL_BLUE }, { EL_MM_LIGHTBALL_YELLOW, -1, -1, FALSE, IMG_MM_LIGHTBALL_YELLOW }, { EL_MM_GRAY_BALL, -1, -1, FALSE, IMG_MM_GRAY_BALL }, { EL_MM_FUEL_FULL, -1, -1, FALSE, IMG_MM_FUEL_FULL }, { EL_MM_FUEL_EMPTY, -1, -1, FALSE, IMG_MM_FUEL_EMPTY }, { EL_MM_STEEL_WALL, -1, -1, FALSE, IMG_MM_STEEL_WALL }, { EL_MM_WOODEN_WALL, -1, -1, FALSE, IMG_MM_WOODEN_WALL }, { EL_MM_ICE_WALL, -1, -1, FALSE, IMG_MM_ICE_WALL }, { EL_MM_ICE_WALL_SHRINKING, -1, -1, FALSE, IMG_MM_ICE_WALL_SHRINKING }, { EL_MM_ICE_WALL, ACTION_SHRINKING, -1, FALSE, IMG_MM_ICE_WALL_SHRINKING }, { EL_MM_AMOEBA_WALL, -1, -1, FALSE, IMG_MM_AMOEBA_WALL }, { EL_MM_AMOEBA_WALL_GROWING, -1, -1, FALSE, IMG_MM_AMOEBA_WALL_GROWING }, { EL_MM_AMOEBA_WALL, ACTION_GROWING, -1, FALSE, IMG_MM_AMOEBA_WALL_GROWING }, { EL_MM_PACMAN, -1, -1, FALSE, IMG_MM_PACMAN }, { EL_MM_PACMAN_RIGHT, -1, -1, FALSE, IMG_MM_PACMAN_RIGHT }, { EL_MM_PACMAN, -1, MV_BIT_RIGHT, FALSE, IMG_MM_PACMAN_RIGHT }, { EL_MM_PACMAN_UP, -1, -1, FALSE, IMG_MM_PACMAN_UP }, { EL_MM_PACMAN, -1, MV_BIT_UP, FALSE, IMG_MM_PACMAN_UP }, { EL_MM_PACMAN_LEFT, -1, -1, FALSE, IMG_MM_PACMAN_LEFT }, { EL_MM_PACMAN, -1, MV_BIT_LEFT, FALSE, IMG_MM_PACMAN_LEFT }, { EL_MM_PACMAN_DOWN, -1, -1, FALSE, IMG_MM_PACMAN_DOWN }, { EL_MM_PACMAN, -1, MV_BIT_DOWN, FALSE, IMG_MM_PACMAN_DOWN }, { EL_MM_PACMAN_EATING_RIGHT, -1, -1, FALSE, IMG_MM_PACMAN_EATING_RIGHT }, { EL_MM_PACMAN, ACTION_EATING, MV_BIT_RIGHT, FALSE, IMG_MM_PACMAN_EATING_RIGHT }, { EL_MM_PACMAN_EATING_UP, -1, -1, FALSE, IMG_MM_PACMAN_EATING_UP }, { EL_MM_PACMAN, ACTION_EATING, MV_BIT_UP, FALSE, IMG_MM_PACMAN_EATING_UP }, { EL_MM_PACMAN_EATING_LEFT, -1, -1, FALSE, IMG_MM_PACMAN_EATING_LEFT }, { EL_MM_PACMAN, ACTION_EATING, MV_BIT_LEFT, FALSE, IMG_MM_PACMAN_EATING_LEFT }, { EL_MM_PACMAN_EATING_DOWN, -1, -1, FALSE, IMG_MM_PACMAN_EATING_DOWN }, { EL_MM_PACMAN, ACTION_EATING, MV_BIT_DOWN, FALSE, IMG_MM_PACMAN_EATING_DOWN }, { EL_MM_MASK_MCDUFFIN_RIGHT, -1, -1, FALSE, IMG_MM_MASK_MCDUFFIN_RIGHT }, { EL_MM_MASK_MCDUFFIN_UP, -1, -1, FALSE, IMG_MM_MASK_MCDUFFIN_UP }, { EL_MM_MASK_MCDUFFIN_LEFT, -1, -1, FALSE, IMG_MM_MASK_MCDUFFIN_LEFT }, { EL_MM_MASK_MCDUFFIN_DOWN, -1, -1, FALSE, IMG_MM_MASK_MCDUFFIN_DOWN }, { EL_MM_MASK_GRID_1, -1, -1, FALSE, IMG_MM_MASK_GRID_1 }, { EL_MM_MASK_GRID_2, -1, -1, FALSE, IMG_MM_MASK_GRID_2 }, { EL_MM_MASK_GRID_3, -1, -1, FALSE, IMG_MM_MASK_GRID_3 }, { EL_MM_MASK_GRID_4, -1, -1, FALSE, IMG_MM_MASK_GRID_4 }, { EL_MM_MASK_RECTANGLE, -1, -1, FALSE, IMG_MM_MASK_RECTANGLE }, { EL_MM_MASK_CIRCLE, -1, -1, FALSE, IMG_MM_MASK_CIRCLE }, { EL_MM_DEFAULT, ACTION_EXPLODING, -1, FALSE, IMG_MM_DEFAULT_EXPLODING }, { EL_DF_LASER, -1, -1, FALSE, IMG_DF_LASER }, { EL_DF_LASER_RIGHT, -1, -1, FALSE, IMG_DF_LASER_RIGHT }, { EL_DF_LASER, -1, MV_BIT_RIGHT, FALSE, IMG_DF_LASER_RIGHT }, { EL_DF_LASER_UP, -1, -1, FALSE, IMG_DF_LASER_UP }, { EL_DF_LASER, -1, MV_BIT_UP, FALSE, IMG_DF_LASER_UP }, { EL_DF_LASER_LEFT, -1, -1, FALSE, IMG_DF_LASER_LEFT }, { EL_DF_LASER, -1, MV_BIT_LEFT, FALSE, IMG_DF_LASER_LEFT }, { EL_DF_LASER_DOWN, -1, -1, FALSE, IMG_DF_LASER_DOWN }, { EL_DF_LASER, -1, MV_BIT_DOWN, FALSE, IMG_DF_LASER_DOWN }, { EL_DF_RECEIVER, -1, -1, FALSE, IMG_DF_RECEIVER }, { EL_DF_RECEIVER_RIGHT, -1, -1, FALSE, IMG_DF_RECEIVER_RIGHT }, { EL_DF_RECEIVER, -1, MV_BIT_RIGHT, FALSE, IMG_DF_RECEIVER_RIGHT }, { EL_DF_RECEIVER_UP, -1, -1, FALSE, IMG_DF_RECEIVER_UP }, { EL_DF_RECEIVER, -1, MV_BIT_UP, FALSE, IMG_DF_RECEIVER_UP }, { EL_DF_RECEIVER_LEFT, -1, -1, FALSE, IMG_DF_RECEIVER_LEFT }, { EL_DF_RECEIVER, -1, MV_BIT_LEFT, FALSE, IMG_DF_RECEIVER_LEFT }, { EL_DF_RECEIVER_DOWN, -1, -1, FALSE, IMG_DF_RECEIVER_DOWN }, { EL_DF_RECEIVER, -1, MV_BIT_DOWN, FALSE, IMG_DF_RECEIVER_DOWN }, { EL_DF_MIRROR_1, -1, -1, FALSE, IMG_DF_MIRROR_1 }, { EL_DF_MIRROR_2, -1, -1, FALSE, IMG_DF_MIRROR_2 }, { EL_DF_MIRROR_3, -1, -1, FALSE, IMG_DF_MIRROR_3 }, { EL_DF_MIRROR_4, -1, -1, FALSE, IMG_DF_MIRROR_4 }, { EL_DF_MIRROR_5, -1, -1, FALSE, IMG_DF_MIRROR_5 }, { EL_DF_MIRROR_6, -1, -1, FALSE, IMG_DF_MIRROR_6 }, { EL_DF_MIRROR_7, -1, -1, FALSE, IMG_DF_MIRROR_7 }, { EL_DF_MIRROR_8, -1, -1, FALSE, IMG_DF_MIRROR_8 }, { EL_DF_MIRROR_9, -1, -1, FALSE, IMG_DF_MIRROR_9 }, { EL_DF_MIRROR_10, -1, -1, FALSE, IMG_DF_MIRROR_10 }, { EL_DF_MIRROR_11, -1, -1, FALSE, IMG_DF_MIRROR_11 }, { EL_DF_MIRROR_12, -1, -1, FALSE, IMG_DF_MIRROR_12 }, { EL_DF_MIRROR_13, -1, -1, FALSE, IMG_DF_MIRROR_13 }, { EL_DF_MIRROR_14, -1, -1, FALSE, IMG_DF_MIRROR_14 }, { EL_DF_MIRROR_15, -1, -1, FALSE, IMG_DF_MIRROR_15 }, { EL_DF_MIRROR_16, -1, -1, FALSE, IMG_DF_MIRROR_16 }, { EL_DF_MIRROR_ROTATING_1, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_1 }, { EL_DF_MIRROR_ROTATING_2, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_2 }, { EL_DF_MIRROR_ROTATING_3, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_3 }, { EL_DF_MIRROR_ROTATING_4, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_4 }, { EL_DF_MIRROR_ROTATING_5, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_5 }, { EL_DF_MIRROR_ROTATING_6, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_6 }, { EL_DF_MIRROR_ROTATING_7, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_7 }, { EL_DF_MIRROR_ROTATING_8, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_8 }, { EL_DF_MIRROR_ROTATING_9, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_9 }, { EL_DF_MIRROR_ROTATING_10, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_10 }, { EL_DF_MIRROR_ROTATING_11, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_11 }, { EL_DF_MIRROR_ROTATING_12, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_12 }, { EL_DF_MIRROR_ROTATING_13, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_13 }, { EL_DF_MIRROR_ROTATING_14, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_14 }, { EL_DF_MIRROR_ROTATING_15, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_15 }, { EL_DF_MIRROR_ROTATING_16, -1, -1, FALSE, IMG_DF_MIRROR_ROTATING_16 }, { EL_DF_STEEL_GRID_FIXED_1, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_1 }, { EL_DF_STEEL_GRID_FIXED_2, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_2 }, { EL_DF_STEEL_GRID_FIXED_3, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_3 }, { EL_DF_STEEL_GRID_FIXED_4, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_4 }, { EL_DF_STEEL_GRID_FIXED_5, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_5 }, { EL_DF_STEEL_GRID_FIXED_6, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_6 }, { EL_DF_STEEL_GRID_FIXED_7, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_7 }, { EL_DF_STEEL_GRID_FIXED_8, -1, -1, FALSE, IMG_DF_STEEL_GRID_FIXED_8 }, { EL_DF_WOODEN_GRID_FIXED_1, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_1 }, { EL_DF_WOODEN_GRID_FIXED_2, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_2 }, { EL_DF_WOODEN_GRID_FIXED_3, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_3 }, { EL_DF_WOODEN_GRID_FIXED_4, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_4 }, { EL_DF_WOODEN_GRID_FIXED_5, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_5 }, { EL_DF_WOODEN_GRID_FIXED_6, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_6 }, { EL_DF_WOODEN_GRID_FIXED_7, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_7 }, { EL_DF_WOODEN_GRID_FIXED_8, -1, -1, FALSE, IMG_DF_WOODEN_GRID_FIXED_8 }, { EL_DF_STEEL_GRID_ROTATING_1, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_1 }, { EL_DF_STEEL_GRID_ROTATING_2, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_2 }, { EL_DF_STEEL_GRID_ROTATING_3, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_3 }, { EL_DF_STEEL_GRID_ROTATING_4, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_4 }, { EL_DF_STEEL_GRID_ROTATING_5, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_5 }, { EL_DF_STEEL_GRID_ROTATING_6, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_6 }, { EL_DF_STEEL_GRID_ROTATING_7, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_7 }, { EL_DF_STEEL_GRID_ROTATING_8, -1, -1, FALSE, IMG_DF_STEEL_GRID_ROTATING_8 }, { EL_DF_WOODEN_GRID_ROTATING_1, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_1 }, { EL_DF_WOODEN_GRID_ROTATING_2, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_2 }, { EL_DF_WOODEN_GRID_ROTATING_3, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_3 }, { EL_DF_WOODEN_GRID_ROTATING_4, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_4 }, { EL_DF_WOODEN_GRID_ROTATING_5, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_5 }, { EL_DF_WOODEN_GRID_ROTATING_6, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_6 }, { EL_DF_WOODEN_GRID_ROTATING_7, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_7 }, { EL_DF_WOODEN_GRID_ROTATING_8, -1, -1, FALSE, IMG_DF_WOODEN_GRID_ROTATING_8 }, { EL_DF_FIBRE_OPTIC_RED_1, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_RED_1 }, { EL_DF_FIBRE_OPTIC_RED_2, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_RED_2 }, { EL_DF_FIBRE_OPTIC_YELLOW_1, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_YELLOW_1 }, { EL_DF_FIBRE_OPTIC_YELLOW_2, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_YELLOW_2 }, { EL_DF_FIBRE_OPTIC_GREEN_1, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_GREEN_1 }, { EL_DF_FIBRE_OPTIC_GREEN_2, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_GREEN_2 }, { EL_DF_FIBRE_OPTIC_BLUE_1, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_BLUE_1 }, { EL_DF_FIBRE_OPTIC_BLUE_2, -1, -1, FALSE, IMG_DF_FIBRE_OPTIC_BLUE_2 }, { EL_DF_STEEL_WALL, -1, -1, FALSE, IMG_DF_STEEL_WALL }, { EL_DF_WOODEN_WALL, -1, -1, FALSE, IMG_DF_WOODEN_WALL }, { EL_DF_REFRACTOR, -1, -1, FALSE, IMG_DF_REFRACTOR }, { EL_DF_CELL, -1, -1, FALSE, IMG_DF_CELL }, { EL_DF_MINE, -1, -1, FALSE, IMG_DF_MINE }, { EL_GRAPHIC_1, -1, -1, FALSE, IMG_GRAPHIC_1 }, { EL_GRAPHIC_2, -1, -1, FALSE, IMG_GRAPHIC_2 }, { EL_GRAPHIC_3, -1, -1, FALSE, IMG_GRAPHIC_3 }, { EL_GRAPHIC_4, -1, -1, FALSE, IMG_GRAPHIC_4 }, { EL_GRAPHIC_5, -1, -1, FALSE, IMG_GRAPHIC_5 }, { EL_GRAPHIC_6, -1, -1, FALSE, IMG_GRAPHIC_6 }, { EL_GRAPHIC_7, -1, -1, FALSE, IMG_GRAPHIC_7 }, { EL_GRAPHIC_8, -1, -1, FALSE, IMG_GRAPHIC_8 }, { EL_BD_BUTTERFLY_DOWN, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_LEFT, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_RIGHT, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_BUTTERFLY_UP, -1, -1, FALSE, IMG_BD_BUTTERFLY }, { EL_BD_FIREFLY_DOWN, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_LEFT, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_RIGHT, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_BD_FIREFLY_UP, -1, -1, FALSE, IMG_BD_FIREFLY }, { EL_DX_UNKNOWN_15, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_DX_UNKNOWN_42, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_SIGN_UNUSED_1, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_SIGN_UNUSED_2, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_CHAR_SPACE, -1, -1, FALSE, IMG_CHAR_SPACE }, { EL_CHAR_EXCLAM, -1, -1, FALSE, IMG_CHAR_EXCLAM }, { EL_CHAR_QUOTEDBL, -1, -1, FALSE, IMG_CHAR_QUOTEDBL }, { EL_CHAR_NUMBERSIGN, -1, -1, FALSE, IMG_CHAR_NUMBERSIGN }, { EL_CHAR_DOLLAR, -1, -1, FALSE, IMG_CHAR_DOLLAR }, { EL_CHAR_PERCENT, -1, -1, FALSE, IMG_CHAR_PERCENT }, { EL_CHAR_AMPERSAND, -1, -1, FALSE, IMG_CHAR_AMPERSAND }, { EL_CHAR_APOSTROPHE, -1, -1, FALSE, IMG_CHAR_APOSTROPHE }, { EL_CHAR_PARENLEFT, -1, -1, FALSE, IMG_CHAR_PARENLEFT }, { EL_CHAR_PARENRIGHT, -1, -1, FALSE, IMG_CHAR_PARENRIGHT }, { EL_CHAR_ASTERISK, -1, -1, FALSE, IMG_CHAR_ASTERISK }, { EL_CHAR_PLUS, -1, -1, FALSE, IMG_CHAR_PLUS }, { EL_CHAR_COMMA, -1, -1, FALSE, IMG_CHAR_COMMA }, { EL_CHAR_MINUS, -1, -1, FALSE, IMG_CHAR_MINUS }, { EL_CHAR_PERIOD, -1, -1, FALSE, IMG_CHAR_PERIOD }, { EL_CHAR_SLASH, -1, -1, FALSE, IMG_CHAR_SLASH }, { EL_CHAR_0, -1, -1, FALSE, IMG_CHAR_0 }, { EL_CHAR_1, -1, -1, FALSE, IMG_CHAR_1 }, { EL_CHAR_2, -1, -1, FALSE, IMG_CHAR_2 }, { EL_CHAR_3, -1, -1, FALSE, IMG_CHAR_3 }, { EL_CHAR_4, -1, -1, FALSE, IMG_CHAR_4 }, { EL_CHAR_5, -1, -1, FALSE, IMG_CHAR_5 }, { EL_CHAR_6, -1, -1, FALSE, IMG_CHAR_6 }, { EL_CHAR_7, -1, -1, FALSE, IMG_CHAR_7 }, { EL_CHAR_8, -1, -1, FALSE, IMG_CHAR_8 }, { EL_CHAR_9, -1, -1, FALSE, IMG_CHAR_9 }, { EL_CHAR_COLON, -1, -1, FALSE, IMG_CHAR_COLON }, { EL_CHAR_SEMICOLON, -1, -1, FALSE, IMG_CHAR_SEMICOLON }, { EL_CHAR_LESS, -1, -1, FALSE, IMG_CHAR_LESS }, { EL_CHAR_EQUAL, -1, -1, FALSE, IMG_CHAR_EQUAL }, { EL_CHAR_GREATER, -1, -1, FALSE, IMG_CHAR_GREATER }, { EL_CHAR_QUESTION, -1, -1, FALSE, IMG_CHAR_QUESTION }, { EL_CHAR_AT, -1, -1, FALSE, IMG_CHAR_AT }, { EL_CHAR_A, -1, -1, FALSE, IMG_CHAR_A }, { EL_CHAR_B, -1, -1, FALSE, IMG_CHAR_B }, { EL_CHAR_C, -1, -1, FALSE, IMG_CHAR_C }, { EL_CHAR_D, -1, -1, FALSE, IMG_CHAR_D }, { EL_CHAR_E, -1, -1, FALSE, IMG_CHAR_E }, { EL_CHAR_F, -1, -1, FALSE, IMG_CHAR_F }, { EL_CHAR_G, -1, -1, FALSE, IMG_CHAR_G }, { EL_CHAR_H, -1, -1, FALSE, IMG_CHAR_H }, { EL_CHAR_I, -1, -1, FALSE, IMG_CHAR_I }, { EL_CHAR_J, -1, -1, FALSE, IMG_CHAR_J }, { EL_CHAR_K, -1, -1, FALSE, IMG_CHAR_K }, { EL_CHAR_L, -1, -1, FALSE, IMG_CHAR_L }, { EL_CHAR_M, -1, -1, FALSE, IMG_CHAR_M }, { EL_CHAR_N, -1, -1, FALSE, IMG_CHAR_N }, { EL_CHAR_O, -1, -1, FALSE, IMG_CHAR_O }, { EL_CHAR_P, -1, -1, FALSE, IMG_CHAR_P }, { EL_CHAR_Q, -1, -1, FALSE, IMG_CHAR_Q }, { EL_CHAR_R, -1, -1, FALSE, IMG_CHAR_R }, { EL_CHAR_S, -1, -1, FALSE, IMG_CHAR_S }, { EL_CHAR_T, -1, -1, FALSE, IMG_CHAR_T }, { EL_CHAR_U, -1, -1, FALSE, IMG_CHAR_U }, { EL_CHAR_V, -1, -1, FALSE, IMG_CHAR_V }, { EL_CHAR_W, -1, -1, FALSE, IMG_CHAR_W }, { EL_CHAR_X, -1, -1, FALSE, IMG_CHAR_X }, { EL_CHAR_Y, -1, -1, FALSE, IMG_CHAR_Y }, { EL_CHAR_Z, -1, -1, FALSE, IMG_CHAR_Z }, { EL_CHAR_BRACKETLEFT, -1, -1, FALSE, IMG_CHAR_BRACKETLEFT }, { EL_CHAR_BACKSLASH, -1, -1, FALSE, IMG_CHAR_BACKSLASH }, { EL_CHAR_BRACKETRIGHT, -1, -1, FALSE, IMG_CHAR_BRACKETRIGHT }, { EL_CHAR_ASCIICIRCUM, -1, -1, FALSE, IMG_CHAR_ASCIICIRCUM }, { EL_CHAR_UNDERSCORE, -1, -1, FALSE, IMG_CHAR_UNDERSCORE }, { EL_CHAR_COPYRIGHT, -1, -1, FALSE, IMG_CHAR_COPYRIGHT }, { EL_CHAR_AUMLAUT, -1, -1, FALSE, IMG_CHAR_AUMLAUT }, { EL_CHAR_OUMLAUT, -1, -1, FALSE, IMG_CHAR_OUMLAUT }, { EL_CHAR_UUMLAUT, -1, -1, FALSE, IMG_CHAR_UUMLAUT }, { EL_CHAR_DEGREE, -1, -1, FALSE, IMG_CHAR_DEGREE }, { EL_CHAR_TRADEMARK, -1, -1, FALSE, IMG_CHAR_TRADEMARK }, { EL_CHAR_CURSOR, -1, -1, FALSE, IMG_CHAR_CURSOR }, { EL_CHAR_BUTTON, -1, -1, FALSE, IMG_CHAR_BUTTON }, { EL_CHAR_UP, -1, -1, FALSE, IMG_CHAR_UP }, { EL_CHAR_DOWN, -1, -1, FALSE, IMG_CHAR_DOWN }, { EL_STEEL_CHAR_SPACE, -1, -1, FALSE, IMG_STEEL_CHAR_SPACE }, { EL_STEEL_CHAR_EXCLAM, -1, -1, FALSE, IMG_STEEL_CHAR_EXCLAM }, { EL_STEEL_CHAR_QUOTEDBL, -1, -1, FALSE, IMG_STEEL_CHAR_QUOTEDBL }, { EL_STEEL_CHAR_NUMBERSIGN, -1, -1, FALSE, IMG_STEEL_CHAR_NUMBERSIGN }, { EL_STEEL_CHAR_DOLLAR, -1, -1, FALSE, IMG_STEEL_CHAR_DOLLAR }, { EL_STEEL_CHAR_PERCENT, -1, -1, FALSE, IMG_STEEL_CHAR_PERCENT }, { EL_STEEL_CHAR_AMPERSAND, -1, -1, FALSE, IMG_STEEL_CHAR_AMPERSAND }, { EL_STEEL_CHAR_APOSTROPHE, -1, -1, FALSE, IMG_STEEL_CHAR_APOSTROPHE }, { EL_STEEL_CHAR_PARENLEFT, -1, -1, FALSE, IMG_STEEL_CHAR_PARENLEFT }, { EL_STEEL_CHAR_PARENRIGHT, -1, -1, FALSE, IMG_STEEL_CHAR_PARENRIGHT }, { EL_STEEL_CHAR_ASTERISK, -1, -1, FALSE, IMG_STEEL_CHAR_ASTERISK }, { EL_STEEL_CHAR_PLUS, -1, -1, FALSE, IMG_STEEL_CHAR_PLUS }, { EL_STEEL_CHAR_COMMA, -1, -1, FALSE, IMG_STEEL_CHAR_COMMA }, { EL_STEEL_CHAR_MINUS, -1, -1, FALSE, IMG_STEEL_CHAR_MINUS }, { EL_STEEL_CHAR_PERIOD, -1, -1, FALSE, IMG_STEEL_CHAR_PERIOD }, { EL_STEEL_CHAR_SLASH, -1, -1, FALSE, IMG_STEEL_CHAR_SLASH }, { EL_STEEL_CHAR_0, -1, -1, FALSE, IMG_STEEL_CHAR_0 }, { EL_STEEL_CHAR_1, -1, -1, FALSE, IMG_STEEL_CHAR_1 }, { EL_STEEL_CHAR_2, -1, -1, FALSE, IMG_STEEL_CHAR_2 }, { EL_STEEL_CHAR_3, -1, -1, FALSE, IMG_STEEL_CHAR_3 }, { EL_STEEL_CHAR_4, -1, -1, FALSE, IMG_STEEL_CHAR_4 }, { EL_STEEL_CHAR_5, -1, -1, FALSE, IMG_STEEL_CHAR_5 }, { EL_STEEL_CHAR_6, -1, -1, FALSE, IMG_STEEL_CHAR_6 }, { EL_STEEL_CHAR_7, -1, -1, FALSE, IMG_STEEL_CHAR_7 }, { EL_STEEL_CHAR_8, -1, -1, FALSE, IMG_STEEL_CHAR_8 }, { EL_STEEL_CHAR_9, -1, -1, FALSE, IMG_STEEL_CHAR_9 }, { EL_STEEL_CHAR_COLON, -1, -1, FALSE, IMG_STEEL_CHAR_COLON }, { EL_STEEL_CHAR_SEMICOLON, -1, -1, FALSE, IMG_STEEL_CHAR_SEMICOLON }, { EL_STEEL_CHAR_LESS, -1, -1, FALSE, IMG_STEEL_CHAR_LESS }, { EL_STEEL_CHAR_EQUAL, -1, -1, FALSE, IMG_STEEL_CHAR_EQUAL }, { EL_STEEL_CHAR_GREATER, -1, -1, FALSE, IMG_STEEL_CHAR_GREATER }, { EL_STEEL_CHAR_QUESTION, -1, -1, FALSE, IMG_STEEL_CHAR_QUESTION }, { EL_STEEL_CHAR_AT, -1, -1, FALSE, IMG_STEEL_CHAR_AT }, { EL_STEEL_CHAR_A, -1, -1, FALSE, IMG_STEEL_CHAR_A }, { EL_STEEL_CHAR_B, -1, -1, FALSE, IMG_STEEL_CHAR_B }, { EL_STEEL_CHAR_C, -1, -1, FALSE, IMG_STEEL_CHAR_C }, { EL_STEEL_CHAR_D, -1, -1, FALSE, IMG_STEEL_CHAR_D }, { EL_STEEL_CHAR_E, -1, -1, FALSE, IMG_STEEL_CHAR_E }, { EL_STEEL_CHAR_F, -1, -1, FALSE, IMG_STEEL_CHAR_F }, { EL_STEEL_CHAR_G, -1, -1, FALSE, IMG_STEEL_CHAR_G }, { EL_STEEL_CHAR_H, -1, -1, FALSE, IMG_STEEL_CHAR_H }, { EL_STEEL_CHAR_I, -1, -1, FALSE, IMG_STEEL_CHAR_I }, { EL_STEEL_CHAR_J, -1, -1, FALSE, IMG_STEEL_CHAR_J }, { EL_STEEL_CHAR_K, -1, -1, FALSE, IMG_STEEL_CHAR_K }, { EL_STEEL_CHAR_L, -1, -1, FALSE, IMG_STEEL_CHAR_L }, { EL_STEEL_CHAR_M, -1, -1, FALSE, IMG_STEEL_CHAR_M }, { EL_STEEL_CHAR_N, -1, -1, FALSE, IMG_STEEL_CHAR_N }, { EL_STEEL_CHAR_O, -1, -1, FALSE, IMG_STEEL_CHAR_O }, { EL_STEEL_CHAR_P, -1, -1, FALSE, IMG_STEEL_CHAR_P }, { EL_STEEL_CHAR_Q, -1, -1, FALSE, IMG_STEEL_CHAR_Q }, { EL_STEEL_CHAR_R, -1, -1, FALSE, IMG_STEEL_CHAR_R }, { EL_STEEL_CHAR_S, -1, -1, FALSE, IMG_STEEL_CHAR_S }, { EL_STEEL_CHAR_T, -1, -1, FALSE, IMG_STEEL_CHAR_T }, { EL_STEEL_CHAR_U, -1, -1, FALSE, IMG_STEEL_CHAR_U }, { EL_STEEL_CHAR_V, -1, -1, FALSE, IMG_STEEL_CHAR_V }, { EL_STEEL_CHAR_W, -1, -1, FALSE, IMG_STEEL_CHAR_W }, { EL_STEEL_CHAR_X, -1, -1, FALSE, IMG_STEEL_CHAR_X }, { EL_STEEL_CHAR_Y, -1, -1, FALSE, IMG_STEEL_CHAR_Y }, { EL_STEEL_CHAR_Z, -1, -1, FALSE, IMG_STEEL_CHAR_Z }, { EL_STEEL_CHAR_BRACKETLEFT, -1, -1, FALSE, IMG_STEEL_CHAR_BRACKETLEFT }, { EL_STEEL_CHAR_BACKSLASH, -1, -1, FALSE, IMG_STEEL_CHAR_BACKSLASH }, { EL_STEEL_CHAR_BRACKETRIGHT, -1, -1, FALSE, IMG_STEEL_CHAR_BRACKETRIGHT }, { EL_STEEL_CHAR_ASCIICIRCUM, -1, -1, FALSE, IMG_STEEL_CHAR_ASCIICIRCUM }, { EL_STEEL_CHAR_UNDERSCORE, -1, -1, FALSE, IMG_STEEL_CHAR_UNDERSCORE }, { EL_STEEL_CHAR_COPYRIGHT, -1, -1, FALSE, IMG_STEEL_CHAR_COPYRIGHT }, { EL_STEEL_CHAR_AUMLAUT, -1, -1, FALSE, IMG_STEEL_CHAR_AUMLAUT }, { EL_STEEL_CHAR_OUMLAUT, -1, -1, FALSE, IMG_STEEL_CHAR_OUMLAUT }, { EL_STEEL_CHAR_UUMLAUT, -1, -1, FALSE, IMG_STEEL_CHAR_UUMLAUT }, { EL_STEEL_CHAR_DEGREE, -1, -1, FALSE, IMG_STEEL_CHAR_DEGREE }, { EL_STEEL_CHAR_TRADEMARK, -1, -1, FALSE, IMG_STEEL_CHAR_TRADEMARK }, { EL_STEEL_CHAR_CURSOR, -1, -1, FALSE, IMG_STEEL_CHAR_CURSOR }, { EL_STEEL_CHAR_BUTTON, -1, -1, FALSE, IMG_STEEL_CHAR_BUTTON }, { EL_STEEL_CHAR_UP, -1, -1, FALSE, IMG_STEEL_CHAR_UP }, { EL_STEEL_CHAR_DOWN, -1, -1, FALSE, IMG_STEEL_CHAR_DOWN }, { EL_CUSTOM_1, -1, -1, FALSE, IMG_CUSTOM_1 }, { EL_CUSTOM_2, -1, -1, FALSE, IMG_CUSTOM_2 }, { EL_CUSTOM_3, -1, -1, FALSE, IMG_CUSTOM_3 }, { EL_CUSTOM_4, -1, -1, FALSE, IMG_CUSTOM_4 }, { EL_CUSTOM_5, -1, -1, FALSE, IMG_CUSTOM_5 }, { EL_CUSTOM_6, -1, -1, FALSE, IMG_CUSTOM_6 }, { EL_CUSTOM_7, -1, -1, FALSE, IMG_CUSTOM_7 }, { EL_CUSTOM_8, -1, -1, FALSE, IMG_CUSTOM_8 }, { EL_CUSTOM_9, -1, -1, FALSE, IMG_CUSTOM_9 }, { EL_CUSTOM_10, -1, -1, FALSE, IMG_CUSTOM_10 }, { EL_CUSTOM_11, -1, -1, FALSE, IMG_CUSTOM_11 }, { EL_CUSTOM_12, -1, -1, FALSE, IMG_CUSTOM_12 }, { EL_CUSTOM_13, -1, -1, FALSE, IMG_CUSTOM_13 }, { EL_CUSTOM_14, -1, -1, FALSE, IMG_CUSTOM_14 }, { EL_CUSTOM_15, -1, -1, FALSE, IMG_CUSTOM_15 }, { EL_CUSTOM_16, -1, -1, FALSE, IMG_CUSTOM_16 }, { EL_CUSTOM_17, -1, -1, FALSE, IMG_CUSTOM_17 }, { EL_CUSTOM_18, -1, -1, FALSE, IMG_CUSTOM_18 }, { EL_CUSTOM_19, -1, -1, FALSE, IMG_CUSTOM_19 }, { EL_CUSTOM_20, -1, -1, FALSE, IMG_CUSTOM_20 }, { EL_CUSTOM_21, -1, -1, FALSE, IMG_CUSTOM_21 }, { EL_CUSTOM_22, -1, -1, FALSE, IMG_CUSTOM_22 }, { EL_CUSTOM_23, -1, -1, FALSE, IMG_CUSTOM_23 }, { EL_CUSTOM_24, -1, -1, FALSE, IMG_CUSTOM_24 }, { EL_CUSTOM_25, -1, -1, FALSE, IMG_CUSTOM_25 }, { EL_CUSTOM_26, -1, -1, FALSE, IMG_CUSTOM_26 }, { EL_CUSTOM_27, -1, -1, FALSE, IMG_CUSTOM_27 }, { EL_CUSTOM_28, -1, -1, FALSE, IMG_CUSTOM_28 }, { EL_CUSTOM_29, -1, -1, FALSE, IMG_CUSTOM_29 }, { EL_CUSTOM_30, -1, -1, FALSE, IMG_CUSTOM_30 }, { EL_CUSTOM_31, -1, -1, FALSE, IMG_CUSTOM_31 }, { EL_CUSTOM_32, -1, -1, FALSE, IMG_CUSTOM_32 }, { EL_CUSTOM_33, -1, -1, FALSE, IMG_CUSTOM_33 }, { EL_CUSTOM_34, -1, -1, FALSE, IMG_CUSTOM_34 }, { EL_CUSTOM_35, -1, -1, FALSE, IMG_CUSTOM_35 }, { EL_CUSTOM_36, -1, -1, FALSE, IMG_CUSTOM_36 }, { EL_CUSTOM_37, -1, -1, FALSE, IMG_CUSTOM_37 }, { EL_CUSTOM_38, -1, -1, FALSE, IMG_CUSTOM_38 }, { EL_CUSTOM_39, -1, -1, FALSE, IMG_CUSTOM_39 }, { EL_CUSTOM_40, -1, -1, FALSE, IMG_CUSTOM_40 }, { EL_CUSTOM_41, -1, -1, FALSE, IMG_CUSTOM_41 }, { EL_CUSTOM_42, -1, -1, FALSE, IMG_CUSTOM_42 }, { EL_CUSTOM_43, -1, -1, FALSE, IMG_CUSTOM_43 }, { EL_CUSTOM_44, -1, -1, FALSE, IMG_CUSTOM_44 }, { EL_CUSTOM_45, -1, -1, FALSE, IMG_CUSTOM_45 }, { EL_CUSTOM_46, -1, -1, FALSE, IMG_CUSTOM_46 }, { EL_CUSTOM_47, -1, -1, FALSE, IMG_CUSTOM_47 }, { EL_CUSTOM_48, -1, -1, FALSE, IMG_CUSTOM_48 }, { EL_CUSTOM_49, -1, -1, FALSE, IMG_CUSTOM_49 }, { EL_CUSTOM_50, -1, -1, FALSE, IMG_CUSTOM_50 }, { EL_CUSTOM_51, -1, -1, FALSE, IMG_CUSTOM_51 }, { EL_CUSTOM_52, -1, -1, FALSE, IMG_CUSTOM_52 }, { EL_CUSTOM_53, -1, -1, FALSE, IMG_CUSTOM_53 }, { EL_CUSTOM_54, -1, -1, FALSE, IMG_CUSTOM_54 }, { EL_CUSTOM_55, -1, -1, FALSE, IMG_CUSTOM_55 }, { EL_CUSTOM_56, -1, -1, FALSE, IMG_CUSTOM_56 }, { EL_CUSTOM_57, -1, -1, FALSE, IMG_CUSTOM_57 }, { EL_CUSTOM_58, -1, -1, FALSE, IMG_CUSTOM_58 }, { EL_CUSTOM_59, -1, -1, FALSE, IMG_CUSTOM_59 }, { EL_CUSTOM_60, -1, -1, FALSE, IMG_CUSTOM_60 }, { EL_CUSTOM_61, -1, -1, FALSE, IMG_CUSTOM_61 }, { EL_CUSTOM_62, -1, -1, FALSE, IMG_CUSTOM_62 }, { EL_CUSTOM_63, -1, -1, FALSE, IMG_CUSTOM_63 }, { EL_CUSTOM_64, -1, -1, FALSE, IMG_CUSTOM_64 }, { EL_CUSTOM_65, -1, -1, FALSE, IMG_CUSTOM_65 }, { EL_CUSTOM_66, -1, -1, FALSE, IMG_CUSTOM_66 }, { EL_CUSTOM_67, -1, -1, FALSE, IMG_CUSTOM_67 }, { EL_CUSTOM_68, -1, -1, FALSE, IMG_CUSTOM_68 }, { EL_CUSTOM_69, -1, -1, FALSE, IMG_CUSTOM_69 }, { EL_CUSTOM_70, -1, -1, FALSE, IMG_CUSTOM_70 }, { EL_CUSTOM_71, -1, -1, FALSE, IMG_CUSTOM_71 }, { EL_CUSTOM_72, -1, -1, FALSE, IMG_CUSTOM_72 }, { EL_CUSTOM_73, -1, -1, FALSE, IMG_CUSTOM_73 }, { EL_CUSTOM_74, -1, -1, FALSE, IMG_CUSTOM_74 }, { EL_CUSTOM_75, -1, -1, FALSE, IMG_CUSTOM_75 }, { EL_CUSTOM_76, -1, -1, FALSE, IMG_CUSTOM_76 }, { EL_CUSTOM_77, -1, -1, FALSE, IMG_CUSTOM_77 }, { EL_CUSTOM_78, -1, -1, FALSE, IMG_CUSTOM_78 }, { EL_CUSTOM_79, -1, -1, FALSE, IMG_CUSTOM_79 }, { EL_CUSTOM_80, -1, -1, FALSE, IMG_CUSTOM_80 }, { EL_CUSTOM_81, -1, -1, FALSE, IMG_CUSTOM_81 }, { EL_CUSTOM_82, -1, -1, FALSE, IMG_CUSTOM_82 }, { EL_CUSTOM_83, -1, -1, FALSE, IMG_CUSTOM_83 }, { EL_CUSTOM_84, -1, -1, FALSE, IMG_CUSTOM_84 }, { EL_CUSTOM_85, -1, -1, FALSE, IMG_CUSTOM_85 }, { EL_CUSTOM_86, -1, -1, FALSE, IMG_CUSTOM_86 }, { EL_CUSTOM_87, -1, -1, FALSE, IMG_CUSTOM_87 }, { EL_CUSTOM_88, -1, -1, FALSE, IMG_CUSTOM_88 }, { EL_CUSTOM_89, -1, -1, FALSE, IMG_CUSTOM_89 }, { EL_CUSTOM_90, -1, -1, FALSE, IMG_CUSTOM_90 }, { EL_CUSTOM_91, -1, -1, FALSE, IMG_CUSTOM_91 }, { EL_CUSTOM_92, -1, -1, FALSE, IMG_CUSTOM_92 }, { EL_CUSTOM_93, -1, -1, FALSE, IMG_CUSTOM_93 }, { EL_CUSTOM_94, -1, -1, FALSE, IMG_CUSTOM_94 }, { EL_CUSTOM_95, -1, -1, FALSE, IMG_CUSTOM_95 }, { EL_CUSTOM_96, -1, -1, FALSE, IMG_CUSTOM_96 }, { EL_CUSTOM_97, -1, -1, FALSE, IMG_CUSTOM_97 }, { EL_CUSTOM_98, -1, -1, FALSE, IMG_CUSTOM_98 }, { EL_CUSTOM_99, -1, -1, FALSE, IMG_CUSTOM_99 }, { EL_CUSTOM_100, -1, -1, FALSE, IMG_CUSTOM_100 }, { EL_CUSTOM_101, -1, -1, FALSE, IMG_CUSTOM_101 }, { EL_CUSTOM_102, -1, -1, FALSE, IMG_CUSTOM_102 }, { EL_CUSTOM_103, -1, -1, FALSE, IMG_CUSTOM_103 }, { EL_CUSTOM_104, -1, -1, FALSE, IMG_CUSTOM_104 }, { EL_CUSTOM_105, -1, -1, FALSE, IMG_CUSTOM_105 }, { EL_CUSTOM_106, -1, -1, FALSE, IMG_CUSTOM_106 }, { EL_CUSTOM_107, -1, -1, FALSE, IMG_CUSTOM_107 }, { EL_CUSTOM_108, -1, -1, FALSE, IMG_CUSTOM_108 }, { EL_CUSTOM_109, -1, -1, FALSE, IMG_CUSTOM_109 }, { EL_CUSTOM_110, -1, -1, FALSE, IMG_CUSTOM_110 }, { EL_CUSTOM_111, -1, -1, FALSE, IMG_CUSTOM_111 }, { EL_CUSTOM_112, -1, -1, FALSE, IMG_CUSTOM_112 }, { EL_CUSTOM_113, -1, -1, FALSE, IMG_CUSTOM_113 }, { EL_CUSTOM_114, -1, -1, FALSE, IMG_CUSTOM_114 }, { EL_CUSTOM_115, -1, -1, FALSE, IMG_CUSTOM_115 }, { EL_CUSTOM_116, -1, -1, FALSE, IMG_CUSTOM_116 }, { EL_CUSTOM_117, -1, -1, FALSE, IMG_CUSTOM_117 }, { EL_CUSTOM_118, -1, -1, FALSE, IMG_CUSTOM_118 }, { EL_CUSTOM_119, -1, -1, FALSE, IMG_CUSTOM_119 }, { EL_CUSTOM_120, -1, -1, FALSE, IMG_CUSTOM_120 }, { EL_CUSTOM_121, -1, -1, FALSE, IMG_CUSTOM_121 }, { EL_CUSTOM_122, -1, -1, FALSE, IMG_CUSTOM_122 }, { EL_CUSTOM_123, -1, -1, FALSE, IMG_CUSTOM_123 }, { EL_CUSTOM_124, -1, -1, FALSE, IMG_CUSTOM_124 }, { EL_CUSTOM_125, -1, -1, FALSE, IMG_CUSTOM_125 }, { EL_CUSTOM_126, -1, -1, FALSE, IMG_CUSTOM_126 }, { EL_CUSTOM_127, -1, -1, FALSE, IMG_CUSTOM_127 }, { EL_CUSTOM_128, -1, -1, FALSE, IMG_CUSTOM_128 }, { EL_CUSTOM_129, -1, -1, FALSE, IMG_CUSTOM_129 }, { EL_CUSTOM_130, -1, -1, FALSE, IMG_CUSTOM_130 }, { EL_CUSTOM_131, -1, -1, FALSE, IMG_CUSTOM_131 }, { EL_CUSTOM_132, -1, -1, FALSE, IMG_CUSTOM_132 }, { EL_CUSTOM_133, -1, -1, FALSE, IMG_CUSTOM_133 }, { EL_CUSTOM_134, -1, -1, FALSE, IMG_CUSTOM_134 }, { EL_CUSTOM_135, -1, -1, FALSE, IMG_CUSTOM_135 }, { EL_CUSTOM_136, -1, -1, FALSE, IMG_CUSTOM_136 }, { EL_CUSTOM_137, -1, -1, FALSE, IMG_CUSTOM_137 }, { EL_CUSTOM_138, -1, -1, FALSE, IMG_CUSTOM_138 }, { EL_CUSTOM_139, -1, -1, FALSE, IMG_CUSTOM_139 }, { EL_CUSTOM_140, -1, -1, FALSE, IMG_CUSTOM_140 }, { EL_CUSTOM_141, -1, -1, FALSE, IMG_CUSTOM_141 }, { EL_CUSTOM_142, -1, -1, FALSE, IMG_CUSTOM_142 }, { EL_CUSTOM_143, -1, -1, FALSE, IMG_CUSTOM_143 }, { EL_CUSTOM_144, -1, -1, FALSE, IMG_CUSTOM_144 }, { EL_CUSTOM_145, -1, -1, FALSE, IMG_CUSTOM_145 }, { EL_CUSTOM_146, -1, -1, FALSE, IMG_CUSTOM_146 }, { EL_CUSTOM_147, -1, -1, FALSE, IMG_CUSTOM_147 }, { EL_CUSTOM_148, -1, -1, FALSE, IMG_CUSTOM_148 }, { EL_CUSTOM_149, -1, -1, FALSE, IMG_CUSTOM_149 }, { EL_CUSTOM_150, -1, -1, FALSE, IMG_CUSTOM_150 }, { EL_CUSTOM_151, -1, -1, FALSE, IMG_CUSTOM_151 }, { EL_CUSTOM_152, -1, -1, FALSE, IMG_CUSTOM_152 }, { EL_CUSTOM_153, -1, -1, FALSE, IMG_CUSTOM_153 }, { EL_CUSTOM_154, -1, -1, FALSE, IMG_CUSTOM_154 }, { EL_CUSTOM_155, -1, -1, FALSE, IMG_CUSTOM_155 }, { EL_CUSTOM_156, -1, -1, FALSE, IMG_CUSTOM_156 }, { EL_CUSTOM_157, -1, -1, FALSE, IMG_CUSTOM_157 }, { EL_CUSTOM_158, -1, -1, FALSE, IMG_CUSTOM_158 }, { EL_CUSTOM_159, -1, -1, FALSE, IMG_CUSTOM_159 }, { EL_CUSTOM_160, -1, -1, FALSE, IMG_CUSTOM_160 }, { EL_CUSTOM_161, -1, -1, FALSE, IMG_CUSTOM_161 }, { EL_CUSTOM_162, -1, -1, FALSE, IMG_CUSTOM_162 }, { EL_CUSTOM_163, -1, -1, FALSE, IMG_CUSTOM_163 }, { EL_CUSTOM_164, -1, -1, FALSE, IMG_CUSTOM_164 }, { EL_CUSTOM_165, -1, -1, FALSE, IMG_CUSTOM_165 }, { EL_CUSTOM_166, -1, -1, FALSE, IMG_CUSTOM_166 }, { EL_CUSTOM_167, -1, -1, FALSE, IMG_CUSTOM_167 }, { EL_CUSTOM_168, -1, -1, FALSE, IMG_CUSTOM_168 }, { EL_CUSTOM_169, -1, -1, FALSE, IMG_CUSTOM_169 }, { EL_CUSTOM_170, -1, -1, FALSE, IMG_CUSTOM_170 }, { EL_CUSTOM_171, -1, -1, FALSE, IMG_CUSTOM_171 }, { EL_CUSTOM_172, -1, -1, FALSE, IMG_CUSTOM_172 }, { EL_CUSTOM_173, -1, -1, FALSE, IMG_CUSTOM_173 }, { EL_CUSTOM_174, -1, -1, FALSE, IMG_CUSTOM_174 }, { EL_CUSTOM_175, -1, -1, FALSE, IMG_CUSTOM_175 }, { EL_CUSTOM_176, -1, -1, FALSE, IMG_CUSTOM_176 }, { EL_CUSTOM_177, -1, -1, FALSE, IMG_CUSTOM_177 }, { EL_CUSTOM_178, -1, -1, FALSE, IMG_CUSTOM_178 }, { EL_CUSTOM_179, -1, -1, FALSE, IMG_CUSTOM_179 }, { EL_CUSTOM_180, -1, -1, FALSE, IMG_CUSTOM_180 }, { EL_CUSTOM_181, -1, -1, FALSE, IMG_CUSTOM_181 }, { EL_CUSTOM_182, -1, -1, FALSE, IMG_CUSTOM_182 }, { EL_CUSTOM_183, -1, -1, FALSE, IMG_CUSTOM_183 }, { EL_CUSTOM_184, -1, -1, FALSE, IMG_CUSTOM_184 }, { EL_CUSTOM_185, -1, -1, FALSE, IMG_CUSTOM_185 }, { EL_CUSTOM_186, -1, -1, FALSE, IMG_CUSTOM_186 }, { EL_CUSTOM_187, -1, -1, FALSE, IMG_CUSTOM_187 }, { EL_CUSTOM_188, -1, -1, FALSE, IMG_CUSTOM_188 }, { EL_CUSTOM_189, -1, -1, FALSE, IMG_CUSTOM_189 }, { EL_CUSTOM_190, -1, -1, FALSE, IMG_CUSTOM_190 }, { EL_CUSTOM_191, -1, -1, FALSE, IMG_CUSTOM_191 }, { EL_CUSTOM_192, -1, -1, FALSE, IMG_CUSTOM_192 }, { EL_CUSTOM_193, -1, -1, FALSE, IMG_CUSTOM_193 }, { EL_CUSTOM_194, -1, -1, FALSE, IMG_CUSTOM_194 }, { EL_CUSTOM_195, -1, -1, FALSE, IMG_CUSTOM_195 }, { EL_CUSTOM_196, -1, -1, FALSE, IMG_CUSTOM_196 }, { EL_CUSTOM_197, -1, -1, FALSE, IMG_CUSTOM_197 }, { EL_CUSTOM_198, -1, -1, FALSE, IMG_CUSTOM_198 }, { EL_CUSTOM_199, -1, -1, FALSE, IMG_CUSTOM_199 }, { EL_CUSTOM_200, -1, -1, FALSE, IMG_CUSTOM_200 }, { EL_CUSTOM_201, -1, -1, FALSE, IMG_CUSTOM_201 }, { EL_CUSTOM_202, -1, -1, FALSE, IMG_CUSTOM_202 }, { EL_CUSTOM_203, -1, -1, FALSE, IMG_CUSTOM_203 }, { EL_CUSTOM_204, -1, -1, FALSE, IMG_CUSTOM_204 }, { EL_CUSTOM_205, -1, -1, FALSE, IMG_CUSTOM_205 }, { EL_CUSTOM_206, -1, -1, FALSE, IMG_CUSTOM_206 }, { EL_CUSTOM_207, -1, -1, FALSE, IMG_CUSTOM_207 }, { EL_CUSTOM_208, -1, -1, FALSE, IMG_CUSTOM_208 }, { EL_CUSTOM_209, -1, -1, FALSE, IMG_CUSTOM_209 }, { EL_CUSTOM_210, -1, -1, FALSE, IMG_CUSTOM_210 }, { EL_CUSTOM_211, -1, -1, FALSE, IMG_CUSTOM_211 }, { EL_CUSTOM_212, -1, -1, FALSE, IMG_CUSTOM_212 }, { EL_CUSTOM_213, -1, -1, FALSE, IMG_CUSTOM_213 }, { EL_CUSTOM_214, -1, -1, FALSE, IMG_CUSTOM_214 }, { EL_CUSTOM_215, -1, -1, FALSE, IMG_CUSTOM_215 }, { EL_CUSTOM_216, -1, -1, FALSE, IMG_CUSTOM_216 }, { EL_CUSTOM_217, -1, -1, FALSE, IMG_CUSTOM_217 }, { EL_CUSTOM_218, -1, -1, FALSE, IMG_CUSTOM_218 }, { EL_CUSTOM_219, -1, -1, FALSE, IMG_CUSTOM_219 }, { EL_CUSTOM_220, -1, -1, FALSE, IMG_CUSTOM_220 }, { EL_CUSTOM_221, -1, -1, FALSE, IMG_CUSTOM_221 }, { EL_CUSTOM_222, -1, -1, FALSE, IMG_CUSTOM_222 }, { EL_CUSTOM_223, -1, -1, FALSE, IMG_CUSTOM_223 }, { EL_CUSTOM_224, -1, -1, FALSE, IMG_CUSTOM_224 }, { EL_CUSTOM_225, -1, -1, FALSE, IMG_CUSTOM_225 }, { EL_CUSTOM_226, -1, -1, FALSE, IMG_CUSTOM_226 }, { EL_CUSTOM_227, -1, -1, FALSE, IMG_CUSTOM_227 }, { EL_CUSTOM_228, -1, -1, FALSE, IMG_CUSTOM_228 }, { EL_CUSTOM_229, -1, -1, FALSE, IMG_CUSTOM_229 }, { EL_CUSTOM_230, -1, -1, FALSE, IMG_CUSTOM_230 }, { EL_CUSTOM_231, -1, -1, FALSE, IMG_CUSTOM_231 }, { EL_CUSTOM_232, -1, -1, FALSE, IMG_CUSTOM_232 }, { EL_CUSTOM_233, -1, -1, FALSE, IMG_CUSTOM_233 }, { EL_CUSTOM_234, -1, -1, FALSE, IMG_CUSTOM_234 }, { EL_CUSTOM_235, -1, -1, FALSE, IMG_CUSTOM_235 }, { EL_CUSTOM_236, -1, -1, FALSE, IMG_CUSTOM_236 }, { EL_CUSTOM_237, -1, -1, FALSE, IMG_CUSTOM_237 }, { EL_CUSTOM_238, -1, -1, FALSE, IMG_CUSTOM_238 }, { EL_CUSTOM_239, -1, -1, FALSE, IMG_CUSTOM_239 }, { EL_CUSTOM_240, -1, -1, FALSE, IMG_CUSTOM_240 }, { EL_CUSTOM_241, -1, -1, FALSE, IMG_CUSTOM_241 }, { EL_CUSTOM_242, -1, -1, FALSE, IMG_CUSTOM_242 }, { EL_CUSTOM_243, -1, -1, FALSE, IMG_CUSTOM_243 }, { EL_CUSTOM_244, -1, -1, FALSE, IMG_CUSTOM_244 }, { EL_CUSTOM_245, -1, -1, FALSE, IMG_CUSTOM_245 }, { EL_CUSTOM_246, -1, -1, FALSE, IMG_CUSTOM_246 }, { EL_CUSTOM_247, -1, -1, FALSE, IMG_CUSTOM_247 }, { EL_CUSTOM_248, -1, -1, FALSE, IMG_CUSTOM_248 }, { EL_CUSTOM_249, -1, -1, FALSE, IMG_CUSTOM_249 }, { EL_CUSTOM_250, -1, -1, FALSE, IMG_CUSTOM_250 }, { EL_CUSTOM_251, -1, -1, FALSE, IMG_CUSTOM_251 }, { EL_CUSTOM_252, -1, -1, FALSE, IMG_CUSTOM_252 }, { EL_CUSTOM_253, -1, -1, FALSE, IMG_CUSTOM_253 }, { EL_CUSTOM_254, -1, -1, FALSE, IMG_CUSTOM_254 }, { EL_CUSTOM_255, -1, -1, FALSE, IMG_CUSTOM_255 }, { EL_CUSTOM_256, -1, -1, FALSE, IMG_CUSTOM_256 }, { EL_GROUP_1, -1, -1, FALSE, IMG_GROUP_1 }, { EL_GROUP_2, -1, -1, FALSE, IMG_GROUP_2 }, { EL_GROUP_3, -1, -1, FALSE, IMG_GROUP_3 }, { EL_GROUP_4, -1, -1, FALSE, IMG_GROUP_4 }, { EL_GROUP_5, -1, -1, FALSE, IMG_GROUP_5 }, { EL_GROUP_6, -1, -1, FALSE, IMG_GROUP_6 }, { EL_GROUP_7, -1, -1, FALSE, IMG_GROUP_7 }, { EL_GROUP_8, -1, -1, FALSE, IMG_GROUP_8 }, { EL_GROUP_9, -1, -1, FALSE, IMG_GROUP_9 }, { EL_GROUP_10, -1, -1, FALSE, IMG_GROUP_10 }, { EL_GROUP_11, -1, -1, FALSE, IMG_GROUP_11 }, { EL_GROUP_12, -1, -1, FALSE, IMG_GROUP_12 }, { EL_GROUP_13, -1, -1, FALSE, IMG_GROUP_13 }, { EL_GROUP_14, -1, -1, FALSE, IMG_GROUP_14 }, { EL_GROUP_15, -1, -1, FALSE, IMG_GROUP_15 }, { EL_GROUP_16, -1, -1, FALSE, IMG_GROUP_16 }, { EL_GROUP_17, -1, -1, FALSE, IMG_GROUP_17 }, { EL_GROUP_18, -1, -1, FALSE, IMG_GROUP_18 }, { EL_GROUP_19, -1, -1, FALSE, IMG_GROUP_19 }, { EL_GROUP_20, -1, -1, FALSE, IMG_GROUP_20 }, { EL_GROUP_21, -1, -1, FALSE, IMG_GROUP_21 }, { EL_GROUP_22, -1, -1, FALSE, IMG_GROUP_22 }, { EL_GROUP_23, -1, -1, FALSE, IMG_GROUP_23 }, { EL_GROUP_24, -1, -1, FALSE, IMG_GROUP_24 }, { EL_GROUP_25, -1, -1, FALSE, IMG_GROUP_25 }, { EL_GROUP_26, -1, -1, FALSE, IMG_GROUP_26 }, { EL_GROUP_27, -1, -1, FALSE, IMG_GROUP_27 }, { EL_GROUP_28, -1, -1, FALSE, IMG_GROUP_28 }, { EL_GROUP_29, -1, -1, FALSE, IMG_GROUP_29 }, { EL_GROUP_30, -1, -1, FALSE, IMG_GROUP_30 }, { EL_GROUP_31, -1, -1, FALSE, IMG_GROUP_31 }, { EL_GROUP_32, -1, -1, FALSE, IMG_GROUP_32 }, { -1, -1, -1, FALSE, -1 }, }; #endif /* CONF_E2G_C */ mirrormagic-3.0.0/src/engines.h0000644000175000017500000000464613263212010015723 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // engines.h // ============================================================================ #ifndef ENGINES_H #define ENGINES_H #include "libgame/libgame.h" #include "game_em/export.h" #include "game_sp/export.h" #include "game_mm/export.h" #include "game.h" /* ========================================================================= */ /* functions and definitions exported from main program to game_em */ /* ========================================================================= */ extern void SetBitmaps_EM(Bitmap **); extern void UpdateEngineValues(int, int, int, int); extern boolean getTeamMode_EM(); extern int getGameFrameDelay_EM(int); extern void PlayLevelSound_EM(int, int, int, int); extern void InitGraphicInfo_EM(void); extern void CheckSingleStepMode_EM(byte action[], int, boolean, boolean, boolean); void SetGfxAnimation_EM(struct GraphicInfo_EM *, int, int, int, int); void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *, int, int, int, int); void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *, int, int, int); /* ========================================================================= */ /* functions and definitions exported from main program to game_sp */ /* ========================================================================= */ void CheckSingleStepMode_SP(boolean, boolean); void getGraphicSource_SP(struct GraphicInfo_SP *, int, int, int, int); int getGraphicInfo_Delay(int); boolean isNextAnimationFrame_SP(int, int); /* ========================================================================= */ /* functions and definitions exported from main program to game_mm */ /* ========================================================================= */ void SetDrawtoField(int); int el2img_mm(int); void CheckSingleStepMode_MM(boolean, boolean); void getGraphicSource(int, int, Bitmap **, int *, int *); void getMiniGraphicSource(int, Bitmap **, int *, int *); void getSizedGraphicSource(int, int, int, Bitmap **, int *, int *); #endif /* ENGINES_H */ mirrormagic-3.0.0/src/tape.h0000644000175000017500000001654113263212010015221 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // tape.h // ============================================================================ #ifndef TAPE_H #define TAPE_H /* values for TapeTogglePause() */ #define TAPE_TOGGLE_AUTOMATIC 0 #define TAPE_TOGGLE_MANUAL (1 << 0) #define TAPE_TOGGLE_PLAY_PAUSE (1 << 1) /* values for tape properties */ #define MAX_TAPE_LEN (1000 * FRAMES_PER_SECOND) /* max.time x fps */ /* values for tape mouse actions */ #define TAPE_ACTION_LX 0 #define TAPE_ACTION_LY 1 #define TAPE_ACTION_BUTTON 2 #define TAPE_ACTION_UNUSED 3 /* some positions in the video tape control window */ #define VIDEO_DISPLAY1_XPOS 5 #define VIDEO_DISPLAY1_YPOS 5 #define VIDEO_DISPLAY2_XPOS 5 #define VIDEO_DISPLAY2_YPOS 41 #define VIDEO_DISPLAY_XSIZE 90 #define VIDEO_DISPLAY_YSIZE 31 #define VIDEO_BUTTON_XSIZE 18 #define VIDEO_BUTTON_YSIZE 18 #define VIDEO_CONTROL_XPOS 5 #define VIDEO_CONTROL_YPOS 77 #define VIDEO_CONTROL_XSIZE VIDEO_DISPLAY_XSIZE #define VIDEO_CONTROL_YSIZE VIDEO_BUTTON_YSIZE /* values for video tape control */ #define VIDEO_STATE_PLAY_OFF (1 << 0) #define VIDEO_STATE_PLAY_ON (1 << 1) #define VIDEO_STATE_REC_OFF (1 << 2) #define VIDEO_STATE_REC_ON (1 << 3) #define VIDEO_STATE_PAUSE_OFF (1 << 4) #define VIDEO_STATE_PAUSE_ON (1 << 5) #define VIDEO_STATE_DATE_OFF (1 << 6) #define VIDEO_STATE_DATE_ON (1 << 7) #define VIDEO_STATE_TIME_OFF (1 << 8) #define VIDEO_STATE_TIME_ON (1 << 9) #define VIDEO_STATE_FRAME_OFF (1 << 10) #define VIDEO_STATE_FRAME_ON (1 << 11) #define VIDEO_STATE_FFWD_OFF (1 << 12) #define VIDEO_STATE_FFWD_ON (1 << 13) #define VIDEO_STATE_WARP_OFF (1 << 14) #define VIDEO_STATE_WARP_ON (1 << 15) #define VIDEO_STATE_WARP2_OFF (1 << 16) #define VIDEO_STATE_WARP2_ON (1 << 17) #define VIDEO_STATE_PBEND_OFF (1 << 18) #define VIDEO_STATE_PBEND_ON (1 << 19) #define VIDEO_STATE_1STEP_OFF (1 << 20) #define VIDEO_STATE_1STEP_ON (1 << 21) #define VIDEO_PRESS_PLAY_ON (1 << 22) #define VIDEO_PRESS_PLAY_OFF (1 << 23) #define VIDEO_PRESS_REC_ON (1 << 24) #define VIDEO_PRESS_REC_OFF (1 << 25) #define VIDEO_PRESS_PAUSE_ON (1 << 26) #define VIDEO_PRESS_PAUSE_OFF (1 << 27) #define VIDEO_PRESS_STOP_ON (1 << 28) #define VIDEO_PRESS_STOP_OFF (1 << 29) #define VIDEO_PRESS_EJECT_ON (1 << 30) #define VIDEO_PRESS_EJECT_OFF (1 << 31) #define VIDEO_STATE_PLAY(x) ((x) ? VIDEO_STATE_PLAY_ON : VIDEO_STATE_PLAY_OFF) #define VIDEO_STATE_REC(x) ((x) ? VIDEO_STATE_REC_ON : VIDEO_STATE_REC_OFF) #define VIDEO_STATE_PAUSE(x) ((x) ? VIDEO_STATE_PAUSE_ON: VIDEO_STATE_PAUSE_OFF) #define VIDEO_STATE_DATE(x) ((x) ? VIDEO_STATE_DATE_ON : VIDEO_STATE_DATE_OFF) #define VIDEO_STATE_TIME(x) ((x) ? VIDEO_STATE_TIME_ON : VIDEO_STATE_TIME_OFF) #define VIDEO_STATE_FRAME(x) ((x) ? VIDEO_STATE_FRAME_ON: VIDEO_STATE_FRAME_OFF) #define VIDEO_STATE_FFWD(x) ((x) ? VIDEO_STATE_FFWD_ON : VIDEO_STATE_FFWD_OFF) #define VIDEO_STATE_WARP(x) ((x) ? VIDEO_STATE_WARP_ON : VIDEO_STATE_WARP_OFF) #define VIDEO_STATE_WARP2(x) ((x) ? VIDEO_STATE_WARP2_ON: VIDEO_STATE_WARP2_OFF) #define VIDEO_STATE_PBEND(x) ((x) ? VIDEO_STATE_PBEND_ON: VIDEO_STATE_PBEND_OFF) #define VIDEO_STATE_1STEP(x) ((x) ? VIDEO_STATE_1STEP_ON: VIDEO_STATE_1STEP_OFF) #define VIDEO_PRESS_PLAY(x) ((x) ? VIDEO_PRESS_PLAY_ON : VIDEO_PRESS_PLAY_OFF) #define VIDEO_PRESS_REC(x) ((x) ? VIDEO_PRESS_REC_ON : VIDEO_PRESS_REC_OFF) #define VIDEO_PRESS_PAUSE(x) ((x) ? VIDEO_PRESS_PAUSE_ON: VIDEO_PRESS_PAUSE_OFF) #define VIDEO_PRESS_STOP(x) ((x) ? VIDEO_PRESS_STOP_ON : VIDEO_PRESS_STOP_OFF) #define VIDEO_PRESS_EJECT(x) ((x) ? VIDEO_PRESS_EJECT_ON: VIDEO_PRESS_EJECT_OFF) /* tags to draw video display labels or symbols only */ /* (negative values to prevent misinterpretation in DrawVideoDisplay(), where the variable "value" is also used for tape length -- better fix this) */ #define VIDEO_DISPLAY_DEFAULT 0 #define VIDEO_DISPLAY_LABEL_ONLY -1 #define VIDEO_DISPLAY_SYMBOL_ONLY -2 struct TapeButtonInfo { struct XY eject; struct XY stop; struct XY pause; struct XY record; struct XY play; }; struct TapeSymbolInfo { struct XY eject; struct XY stop; struct XY pause; struct XY record; struct XY play; struct XY fast_forward; struct XY warp_forward; struct XY warp_forward_blind; struct XY pause_before_end; struct XY single_step; }; struct TapeLabelInfo { struct XY eject; struct XY stop; struct XY pause; struct XY record; struct XY play; struct XY fast_forward; struct XY warp_forward; struct XY warp_forward_blind; struct XY pause_before_end; struct XY single_step; struct XY date; struct XY time; }; struct TapeTextInfo { struct TextPosInfo date; struct TextPosInfo date_yyyy; struct TextPosInfo date_yy; struct TextPosInfo date_mon; struct TextPosInfo date_mm; struct TextPosInfo date_dd; struct TextPosInfo time; struct TextPosInfo time_hh; struct TextPosInfo time_mm; struct TextPosInfo time_ss; struct TextPosInfo frame; }; struct TapeInfo { int file_version; /* file format version the tape is stored with */ int game_version; /* game release version the tape was created with */ int engine_version; /* game engine version the tape was recorded with */ char *level_identifier; int level_nr; unsigned int random_seed; unsigned int date; unsigned int counter; unsigned int length; unsigned int length_frames; unsigned int length_seconds; unsigned int delay_played; boolean pause_before_end; boolean recording, playing, pausing; boolean fast_forward; boolean warp_forward; boolean deactivate_display; boolean auto_play; boolean auto_play_level_solved; boolean quick_resume; boolean single_step; boolean changed; boolean player_participates[MAX_PLAYERS]; int num_participating_players; int centered_player_nr_next; boolean set_centered_player; boolean use_mouse; struct { byte action[MAX_PLAYERS]; byte delay; } pos[MAX_TAPE_LEN]; struct TapeButtonInfo button; struct TapeSymbolInfo symbol; struct TapeLabelInfo label; struct TapeTextInfo text; boolean show_game_buttons; /* show game buttons in tape viewport */ boolean no_valid_file; /* set when tape file missing or invalid */ }; void DrawVideoDisplay(unsigned int, unsigned int); void DrawCompleteVideoDisplay(void); void TapeDeactivateDisplayOn(); void TapeDeactivateDisplayOff(boolean); void TapeSetDateFromEpochSeconds(time_t); void TapeSetDateFromNow(); void TapeStartRecording(int); void TapeHaltRecording(void); void TapeStopRecording(void); boolean TapeAddAction(byte *); void TapeRecordAction(byte *); void TapeTogglePause(boolean); void TapeStartPlaying(void); void TapeStopPlaying(void); byte *TapePlayAction(void); void TapeStop(void); void TapeErase(void); unsigned int GetTapeLengthFrames(void); unsigned int GetTapeLengthSeconds(void); void TapeQuickSave(void); void TapeQuickLoad(void); void InsertSolutionTape(void); void AutoPlayTape(void); void CreateTapeButtons(); void FreeTapeButtons(); void MapTapeEjectButton(); void MapTapeWarpButton(); void MapTapeButtons(); void UnmapTapeButtons(); void RedrawTapeButtons(); void RedrawOrRemapTapeButtons(); void HandleTapeButtonKeys(Key); #endif mirrormagic-3.0.0/src/conf_gfx.c0000644000175000017500000144156613263212010016066 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_gfx.c // ============================================================================ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is GFX_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigTypeInfo image_config_suffix[] = { { ".x", ARG_UNDEFINED, TYPE_INTEGER }, { ".y", ARG_UNDEFINED, TYPE_INTEGER }, { ".xpos", ARG_UNDEFINED, TYPE_INTEGER }, { ".ypos", ARG_UNDEFINED, TYPE_INTEGER }, { ".width", ARG_UNDEFINED, TYPE_INTEGER }, { ".height", ARG_UNDEFINED, TYPE_INTEGER }, { ".vertical", "false", TYPE_BOOLEAN }, { ".offset", ARG_UNDEFINED, TYPE_INTEGER }, { ".xoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".yoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_movement_tile", "false", TYPE_BOOLEAN }, { ".2nd_vertical", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".2nd_offset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_xoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_yoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".2nd_swap_tiles", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".frames", ARG_UNDEFINED, TYPE_INTEGER }, { ".frames_per_line", ARG_UNDEFINED, TYPE_INTEGER }, { ".start_frame", ARG_UNDEFINED, TYPE_INTEGER }, { ".delay", "1", TYPE_INTEGER }, { ".anim_mode", ARG_UNDEFINED, TYPE_STRING }, { ".global_sync", "false", TYPE_BOOLEAN }, { ".crumbled_like", ARG_UNDEFINED, TYPE_ELEMENT }, { ".diggable_like", ARG_UNDEFINED, TYPE_ELEMENT }, { ".border_size", ARG_UNDEFINED, TYPE_INTEGER }, { ".step_offset", "4", TYPE_INTEGER }, { ".step_xoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".step_yoffset", ARG_UNDEFINED, TYPE_INTEGER }, { ".step_delay", "1", TYPE_INTEGER }, { ".direction", ARG_UNDEFINED, TYPE_STRING }, { ".position", ARG_UNDEFINED, TYPE_STRING }, { ".draw_xoffset", "0", TYPE_INTEGER }, { ".draw_yoffset", "0", TYPE_INTEGER }, { ".draw_masked", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".draw_order", ARG_UNDEFINED, TYPE_INTEGER }, { ".init_delay_fixed", ARG_UNDEFINED, TYPE_INTEGER }, { ".init_delay_random", ARG_UNDEFINED, TYPE_INTEGER }, { ".anim_delay_fixed", ARG_UNDEFINED, TYPE_INTEGER }, { ".anim_delay_random", ARG_UNDEFINED, TYPE_INTEGER }, { ".post_delay_fixed", ARG_UNDEFINED, TYPE_INTEGER }, { ".post_delay_random", ARG_UNDEFINED, TYPE_INTEGER }, { ".init_event", ARG_UNDEFINED, TYPE_STRING }, { ".anim_event", ARG_UNDEFINED, TYPE_STRING }, { ".name", ARG_UNDEFINED, TYPE_STRING }, { ".scale_up_factor", ARG_UNDEFINED, TYPE_INTEGER }, { ".tile_size", ARG_UNDEFINED, TYPE_INTEGER }, { ".clone_from", ARG_UNDEFINED, TYPE_GRAPHIC }, { ".fade_mode", ARG_UNDEFINED, TYPE_INTEGER }, { ".fade_delay", ARG_UNDEFINED, TYPE_INTEGER }, { ".post_delay", ARG_UNDEFINED, TYPE_INTEGER }, { ".auto_delay", ARG_UNDEFINED, TYPE_INTEGER }, { ".align", ARG_UNDEFINED, TYPE_INTEGER }, { ".valign", ARG_UNDEFINED, TYPE_INTEGER }, { ".sort_priority", ARG_UNDEFINED, TYPE_INTEGER }, { ".class", ARG_UNDEFINED, TYPE_STRING }, { ".style", ARG_UNDEFINED, TYPE_STRING }, { ".active_xoffset", "0", TYPE_INTEGER }, { ".active_yoffset", "0", TYPE_INTEGER }, { ".pressed_xoffset", "0", TYPE_INTEGER }, { ".pressed_yoffset", "0", TYPE_INTEGER }, { NULL, NULL, 0 } }; struct ConfigInfo image_config[] = { // ========================================================================== // image definitions for game elements (for in-game and editor graphics) // ========================================================================== /* images for Boulder Dash style elements and actions */ { "bd_wall", "RocksDC.png" }, { "bd_wall.xpos", "12" }, { "bd_wall.ypos", "9" }, { "bd_wall.frames", "1" }, { "bd_wall.EDITOR", "RocksDC.png" }, { "bd_wall.EDITOR.xpos", "14" }, { "bd_wall.EDITOR.ypos", "13" }, { "bd_rock", "RocksDC.png" }, { "bd_rock.xpos", "12" }, { "bd_rock.ypos", "10" }, { "bd_rock.frames", "1" }, { "bd_rock.EDITOR", "RocksDC.png" }, { "bd_rock.EDITOR.xpos", "14" }, { "bd_rock.EDITOR.ypos", "14" }, { "bd_rock.moving.left", "RocksDC.png" }, { "bd_rock.moving.left.xpos", "12" }, { "bd_rock.moving.left.ypos", "10" }, { "bd_rock.moving.left.frames", "4" }, { "bd_rock.moving.left.delay", "2" }, { "bd_rock.moving.left.anim_mode", "reverse" }, { "bd_rock.moving.right", "RocksDC.png" }, { "bd_rock.moving.right.xpos", "12" }, { "bd_rock.moving.right.ypos", "10" }, { "bd_rock.moving.right.frames", "4" }, { "bd_rock.moving.right.start_frame", "1" }, { "bd_rock.moving.right.delay", "2" }, { "bd_rock.pushing.left", "RocksDC.png" }, { "bd_rock.pushing.left.xpos", "12" }, { "bd_rock.pushing.left.ypos", "10" }, { "bd_rock.pushing.left.frames", "4" }, { "bd_rock.pushing.left.delay", "2" }, { "bd_rock.pushing.left.anim_mode", "reverse" }, { "bd_rock.pushing.right", "RocksDC.png" }, { "bd_rock.pushing.right.xpos", "12" }, { "bd_rock.pushing.right.ypos", "10" }, { "bd_rock.pushing.right.frames", "4" }, { "bd_rock.pushing.right.start_frame", "1" }, { "bd_rock.pushing.right.delay", "2" }, { "bd_diamond", "RocksElements.png" }, { "bd_diamond.xpos", "0" }, { "bd_diamond.ypos", "10" }, { "bd_diamond.frames", "4" }, { "bd_diamond.delay", "4" }, { "bd_diamond.anim_mode", "reverse" }, { "bd_diamond.moving", "RocksElements.png" }, { "bd_diamond.moving.xpos", "3" }, { "bd_diamond.moving.ypos", "10" }, { "bd_diamond.moving.frames", "2" }, { "bd_diamond.moving.delay", "4" }, { "bd_diamond.falling", "RocksElements.png" }, { "bd_diamond.falling.xpos", "3" }, { "bd_diamond.falling.ypos", "10" }, { "bd_diamond.falling.frames", "2" }, { "bd_diamond.falling.delay", "4" }, { "bd_magic_wall", "RocksElements.png" }, { "bd_magic_wall.xpos", "12" }, { "bd_magic_wall.ypos", "10" }, { "bd_magic_wall.frames", "1" }, { "bd_magic_wall.active", "RocksElements.png" }, { "bd_magic_wall.active.xpos", "12" }, { "bd_magic_wall.active.ypos", "10" }, { "bd_magic_wall.active.frames", "4" }, { "bd_magic_wall.active.anim_mode", "reverse" }, { "bd_magic_wall.active.delay", "4" }, { "bd_magic_wall.active.global_sync", "true" }, { "bd_magic_wall.filling", "RocksElements.png" }, { "bd_magic_wall.filling.xpos", "12" }, { "bd_magic_wall.filling.ypos", "10" }, { "bd_magic_wall.filling.frames", "4" }, { "bd_magic_wall.filling.anim_mode", "reverse" }, { "bd_magic_wall.filling.delay", "4" }, { "bd_magic_wall.filling.global_sync", "true" }, { "bd_magic_wall_full", "RocksElements.png" }, { "bd_magic_wall_full.xpos", "12" }, { "bd_magic_wall_full.ypos", "10" }, { "bd_magic_wall_full.frames", "4" }, { "bd_magic_wall_full.anim_mode", "reverse" }, { "bd_magic_wall_full.delay", "4" }, { "bd_magic_wall_full.global_sync", "true" }, { "bd_magic_wall.emptying", "RocksElements.png" }, { "bd_magic_wall.emptying.xpos", "12" }, { "bd_magic_wall.emptying.ypos", "10" }, { "bd_magic_wall.emptying.frames", "4" }, { "bd_magic_wall.emptying.anim_mode", "reverse" }, { "bd_magic_wall.emptying.delay", "4" }, { "bd_magic_wall.emptying.global_sync", "true" }, { "bd_magic_wall_dead", "RocksElements.png" }, { "bd_magic_wall_dead.xpos", "12" }, { "bd_magic_wall_dead.ypos", "10" }, { "bd_magic_wall_dead.frames", "1" }, { "bd_amoeba", "RocksElements.png" }, { "bd_amoeba.xpos", "8" }, { "bd_amoeba.ypos", "6" }, { "bd_amoeba.frames", "4" }, { "bd_amoeba.delay", "1000000" }, { "bd_amoeba.anim_mode", "random" }, { "bd_amoeba.EDITOR", "RocksElements.png" }, { "bd_amoeba.EDITOR.xpos", "8" }, { "bd_amoeba.EDITOR.ypos", "7" }, { "bd_butterfly", "RocksElements.png" }, { "bd_butterfly.xpos", "4" }, { "bd_butterfly.ypos", "12" }, { "bd_butterfly.frames", "2" }, { "bd_butterfly.anim_mode", "pingpong" }, { "bd_butterfly.delay", "4" }, { "bd_butterfly.global_sync", "true" }, { "bd_butterfly.right", "RocksElements.png" }, { "bd_butterfly.right.xpos", "4" }, { "bd_butterfly.right.ypos", "12" }, { "bd_butterfly.right.frames", "2" }, { "bd_butterfly.right.anim_mode", "pingpong" }, { "bd_butterfly.right.delay", "4" }, { "bd_butterfly.right.global_sync", "true" }, { "bd_butterfly.right.EDITOR", "RocksElements.png" }, { "bd_butterfly.right.EDITOR.xpos", "8" }, { "bd_butterfly.right.EDITOR.ypos", "12" }, { "bd_butterfly.up", "RocksElements.png" }, { "bd_butterfly.up.xpos", "4" }, { "bd_butterfly.up.ypos", "12" }, { "bd_butterfly.up.frames", "2" }, { "bd_butterfly.up.anim_mode", "pingpong" }, { "bd_butterfly.up.delay", "4" }, { "bd_butterfly.up.global_sync", "true" }, { "bd_butterfly.up.EDITOR", "RocksElements.png" }, { "bd_butterfly.up.EDITOR.xpos", "9" }, { "bd_butterfly.up.EDITOR.ypos", "12" }, { "bd_butterfly.left", "RocksElements.png" }, { "bd_butterfly.left.xpos", "4" }, { "bd_butterfly.left.ypos", "12" }, { "bd_butterfly.left.frames", "2" }, { "bd_butterfly.left.anim_mode", "pingpong" }, { "bd_butterfly.left.delay", "4" }, { "bd_butterfly.left.global_sync", "true" }, { "bd_butterfly.left.EDITOR", "RocksElements.png" }, { "bd_butterfly.left.EDITOR.xpos", "10" }, { "bd_butterfly.left.EDITOR.ypos", "12" }, { "bd_butterfly.down", "RocksElements.png" }, { "bd_butterfly.down.xpos", "4" }, { "bd_butterfly.down.ypos", "12" }, { "bd_butterfly.down.frames", "2" }, { "bd_butterfly.down.anim_mode", "pingpong" }, { "bd_butterfly.down.delay", "4" }, { "bd_butterfly.down.global_sync", "true" }, { "bd_butterfly.down.EDITOR", "RocksElements.png" }, { "bd_butterfly.down.EDITOR.xpos", "11" }, { "bd_butterfly.down.EDITOR.ypos", "12" }, { "bd_firefly", "RocksElements.png" }, { "bd_firefly.xpos", "6" }, { "bd_firefly.ypos", "12" }, { "bd_firefly.frames", "2" }, { "bd_firefly.anim_mode", "pingpong" }, { "bd_firefly.delay", "4" }, { "bd_firefly.global_sync", "true" }, { "bd_firefly.right", "RocksElements.png" }, { "bd_firefly.right.xpos", "6" }, { "bd_firefly.right.ypos", "12" }, { "bd_firefly.right.frames", "2" }, { "bd_firefly.right.anim_mode", "pingpong" }, { "bd_firefly.right.delay", "4" }, { "bd_firefly.right.global_sync", "true" }, { "bd_firefly.right.EDITOR", "RocksElements.png" }, { "bd_firefly.right.EDITOR.xpos", "12" }, { "bd_firefly.right.EDITOR.ypos", "12" }, { "bd_firefly.up", "RocksElements.png" }, { "bd_firefly.up.xpos", "6" }, { "bd_firefly.up.ypos", "12" }, { "bd_firefly.up.frames", "2" }, { "bd_firefly.up.anim_mode", "pingpong" }, { "bd_firefly.up.delay", "4" }, { "bd_firefly.up.global_sync", "true" }, { "bd_firefly.up.EDITOR", "RocksElements.png" }, { "bd_firefly.up.EDITOR.xpos", "13" }, { "bd_firefly.up.EDITOR.ypos", "12" }, { "bd_firefly.left", "RocksElements.png" }, { "bd_firefly.left.xpos", "6" }, { "bd_firefly.left.ypos", "12" }, { "bd_firefly.left.frames", "2" }, { "bd_firefly.left.anim_mode", "pingpong" }, { "bd_firefly.left.delay", "4" }, { "bd_firefly.left.global_sync", "true" }, { "bd_firefly.left.EDITOR", "RocksElements.png" }, { "bd_firefly.left.EDITOR.xpos", "14" }, { "bd_firefly.left.EDITOR.ypos", "12" }, { "bd_firefly.down", "RocksElements.png" }, { "bd_firefly.down.xpos", "6" }, { "bd_firefly.down.ypos", "12" }, { "bd_firefly.down.frames", "2" }, { "bd_firefly.down.anim_mode", "pingpong" }, { "bd_firefly.down.delay", "4" }, { "bd_firefly.down.global_sync", "true" }, { "bd_firefly.down.EDITOR", "RocksElements.png" }, { "bd_firefly.down.EDITOR.xpos", "15" }, { "bd_firefly.down.EDITOR.ypos", "12" }, /* images for Supaplex style elements and actions */ { "[sp_default].exploding", "RocksSP.png" }, { "[sp_default].exploding.xpos", "8" }, { "[sp_default].exploding.ypos", "3" }, { "[sp_default].exploding.frames", "8" }, { "[sp_default].exploding.delay", "4" }, { "[sp_default].exploding.anim_mode", "linear" }, { "sp_zonk", "RocksSP.png" }, { "sp_zonk.xpos", "1" }, { "sp_zonk.ypos", "0" }, { "sp_zonk.frames", "1" }, { "sp_zonk.moving.left", "RocksSP.png" }, { "sp_zonk.moving.left.xpos", "0" }, { "sp_zonk.moving.left.ypos", "6" }, { "sp_zonk.moving.left.frames", "4" }, { "sp_zonk.moving.left.delay", "1" }, { "sp_zonk.moving.left.anim_mode", "reverse" }, { "sp_zonk.moving.right", "RocksSP.png" }, { "sp_zonk.moving.right.xpos", "0" }, { "sp_zonk.moving.right.ypos", "6" }, { "sp_zonk.moving.right.frames", "4" }, { "sp_zonk.moving.right.start_frame", "1" }, { "sp_zonk.moving.right.delay", "1" }, { "sp_zonk.pushing.left", "RocksSP.png" }, { "sp_zonk.pushing.left.xpos", "0" }, { "sp_zonk.pushing.left.ypos", "6" }, { "sp_zonk.pushing.left.frames", "4" }, { "sp_zonk.pushing.left.delay", "1" }, { "sp_zonk.pushing.left.anim_mode", "reverse" }, { "sp_zonk.pushing.right", "RocksSP.png" }, { "sp_zonk.pushing.right.xpos", "0" }, { "sp_zonk.pushing.right.ypos", "6" }, { "sp_zonk.pushing.right.frames", "4" }, { "sp_zonk.pushing.right.start_frame", "1" }, { "sp_zonk.pushing.right.delay", "1" }, { "sp_base", "RocksSP.png" }, { "sp_base.xpos", "2" }, { "sp_base.ypos", "0" }, { "sp_base.frames", "1" }, { "sp_base.digging", "RocksSP.png" }, { "sp_base.digging.xpos", "2" }, { "sp_base.digging.ypos", "0" }, { "sp_base.digging.frames", "1" }, { "sp_base.digging.anim_mode", "opaque_player" }, { "sp_base.snapping", "RocksSP.png" }, { "sp_base.snapping.xpos", "8" }, { "sp_base.snapping.ypos", "2" }, { "sp_base.snapping.frames", "7" }, { "sp_base.snapping.anim_mode", "linear" }, { "sp_murphy", "RocksSP.png" }, { "sp_murphy.xpos", "3" }, { "sp_murphy.ypos", "0" }, { "sp_murphy.frames", "1" }, { "sp_murphy.moving.left", "RocksSP.png" }, { "sp_murphy.moving.left.xpos", "8" }, { "sp_murphy.moving.left.ypos", "0" }, { "sp_murphy.moving.left.frames", "3" }, { "sp_murphy.moving.left.anim_mode", "pingpong" }, { "sp_murphy.moving.left.delay", "2" }, { "sp_murphy.moving.left.start_frame", "1" }, { "sp_murphy.moving.right", "RocksSP.png" }, { "sp_murphy.moving.right.xpos", "11" }, { "sp_murphy.moving.right.ypos", "0" }, { "sp_murphy.moving.right.frames", "3" }, { "sp_murphy.moving.right.anim_mode", "pingpong" }, { "sp_murphy.moving.right.delay", "2" }, { "sp_murphy.moving.right.start_frame", "1" }, { "sp_murphy.digging.left", "RocksSP.png" }, { "sp_murphy.digging.left.xpos", "8" }, { "sp_murphy.digging.left.ypos", "0" }, { "sp_murphy.digging.left.frames", "3" }, { "sp_murphy.digging.left.anim_mode", "pingpong" }, { "sp_murphy.digging.left.delay", "2" }, { "sp_murphy.digging.left.start_frame", "1" }, { "sp_murphy.digging.right", "RocksSP.png" }, { "sp_murphy.digging.right.xpos", "11" }, { "sp_murphy.digging.right.ypos", "0" }, { "sp_murphy.digging.right.frames", "3" }, { "sp_murphy.digging.right.anim_mode", "pingpong" }, { "sp_murphy.digging.right.delay", "2" }, { "sp_murphy.digging.right.start_frame", "1" }, { "sp_murphy.collecting.left", "RocksSP.png" }, { "sp_murphy.collecting.left.xpos", "8" }, { "sp_murphy.collecting.left.ypos", "0" }, { "sp_murphy.collecting.left.frames", "3" }, { "sp_murphy.collecting.left.anim_mode", "pingpong" }, { "sp_murphy.collecting.left.delay", "2" }, { "sp_murphy.collecting.left.start_frame", "1" }, { "sp_murphy.collecting.right", "RocksSP.png" }, { "sp_murphy.collecting.right.xpos", "11" }, { "sp_murphy.collecting.right.ypos", "0" }, { "sp_murphy.collecting.right.frames", "3" }, { "sp_murphy.collecting.right.anim_mode", "pingpong" }, { "sp_murphy.collecting.right.delay", "2" }, { "sp_murphy.collecting.right.start_frame", "1" }, { "sp_murphy.pushing.left", "RocksSP.png" }, { "sp_murphy.pushing.left.xpos", "11" }, { "sp_murphy.pushing.left.ypos", "1" }, { "sp_murphy.pushing.left.frames", "1" }, { "sp_murphy.pushing.right", "RocksSP.png" }, { "sp_murphy.pushing.right.xpos", "10" }, { "sp_murphy.pushing.right.ypos", "1" }, { "sp_murphy.pushing.right.frames", "1" }, { "sp_murphy.snapping.left", "RocksSP.png" }, { "sp_murphy.snapping.left.xpos", "9" }, { "sp_murphy.snapping.left.ypos", "1" }, { "sp_murphy.snapping.left.frames", "1" }, { "sp_murphy.snapping.right", "RocksSP.png" }, { "sp_murphy.snapping.right.xpos", "8" }, { "sp_murphy.snapping.right.ypos", "1" }, { "sp_murphy.snapping.right.frames", "1" }, { "sp_murphy.snapping.up", "RocksSP.png" }, { "sp_murphy.snapping.up.xpos", "14" }, { "sp_murphy.snapping.up.ypos", "0" }, { "sp_murphy.snapping.up.frames", "1" }, { "sp_murphy.snapping.down", "RocksSP.png" }, { "sp_murphy.snapping.down.xpos", "15" }, { "sp_murphy.snapping.down.ypos", "0" }, { "sp_murphy.snapping.down.frames", "1" }, { "sp_murphy.boring", "RocksSP.png" }, { "sp_murphy.boring.xpos", "11" }, { "sp_murphy.boring.ypos", "12" }, { "sp_murphy.boring.frames", "1" }, { "sp_murphy.boring[1]", "RocksSP.png" }, { "sp_murphy.boring[1].xpos", "0" }, { "sp_murphy.boring[1].ypos", "12" }, { "sp_murphy.boring[1].frames", "12" }, { "sp_murphy.boring[1].delay", "10" }, { "sp_murphy.boring[1].anim_mode", "linear" }, { "sp_murphy.boring[1].anim_delay_fixed", "120" }, { "sp_murphy.boring[1].anim_delay_random", "0" }, { "sp_murphy.boring[1].post_delay_fixed", "500" }, { "sp_murphy.boring[1].post_delay_random", "500" }, { "sp_murphy.sleeping.left", "RocksSP.png" }, { "sp_murphy.sleeping.left.xpos", "4" }, { "sp_murphy.sleeping.left.ypos", "9" }, { "sp_murphy.sleeping.left.frames", "3" }, { "sp_murphy.sleeping.left.delay", "100" }, { "sp_murphy.sleeping.left.anim_mode", "linear,reverse" }, { "sp_murphy.sleeping.right", "RocksSP.png" }, { "sp_murphy.sleeping.right.xpos", "13" }, { "sp_murphy.sleeping.right.ypos", "12" }, { "sp_murphy.sleeping.right.frames", "3" }, { "sp_murphy.sleeping.right.delay", "100" }, { "sp_murphy.sleeping.right.anim_mode", "linear" }, { "sp_murphy.dropping", "RocksSP.png" }, { "sp_murphy.dropping.xpos", "11" }, { "sp_murphy.dropping.ypos", "12" }, { "sp_murphy.dropping.frames", "1" }, { "sp_murphy.shrinking", "RocksSP.png" }, { "sp_murphy.shrinking.xpos", "8" }, { "sp_murphy.shrinking.ypos", "14" }, { "sp_murphy.shrinking.frames", "8" }, { "sp_murphy.shrinking.delay", "4" }, { "sp_murphy.shrinking.anim_mode", "linear" }, { "sp_murphy_clone", "RocksSP.png" }, { "sp_murphy_clone.xpos", "3" }, { "sp_murphy_clone.ypos", "0" }, { "sp_murphy_clone.frames", "1" }, { "sp_infotron", "RocksSP.png" }, { "sp_infotron.xpos", "4" }, { "sp_infotron.ypos", "0" }, { "sp_infotron.frames", "1" }, { "sp_infotron.EDITOR", "RocksSP.png" }, { "sp_infotron.EDITOR.xpos", "8" }, { "sp_infotron.EDITOR.ypos", "11" }, { "sp_infotron.moving.left", "RocksSP.png" }, { "sp_infotron.moving.left.xpos", "8" }, { "sp_infotron.moving.left.ypos", "13" }, { "sp_infotron.moving.left.frames", "8" }, { "sp_infotron.moving.right", "RocksSP.png" }, { "sp_infotron.moving.right.xpos", "8" }, { "sp_infotron.moving.right.ypos", "13" }, { "sp_infotron.moving.right.frames", "8" }, { "sp_infotron.moving.right.start_frame", "6" }, { "sp_infotron.moving.right.anim_mode", "reverse" }, { "sp_infotron.collecting", "RocksSP.png" }, { "sp_infotron.collecting.xpos", "8" }, { "sp_infotron.collecting.ypos", "7" }, { "sp_infotron.collecting.frames", "8" }, { "sp_infotron.collecting.anim_mode", "linear" }, { "sp_chip_single", "RocksSP.png" }, { "sp_chip_single.xpos", "5" }, { "sp_chip_single.ypos", "0" }, { "sp_chip_single.frames", "1" }, { "sp_chip_left", "RocksSP.png" }, { "sp_chip_left.xpos", "2" }, { "sp_chip_left.ypos", "3" }, { "sp_chip_left.frames", "1" }, { "sp_chip_right", "RocksSP.png" }, { "sp_chip_right.xpos", "3" }, { "sp_chip_right.ypos", "3" }, { "sp_chip_right.frames", "1" }, { "sp_chip_top", "RocksSP.png" }, { "sp_chip_top.xpos", "6" }, { "sp_chip_top.ypos", "4" }, { "sp_chip_top.frames", "1" }, { "sp_chip_bottom", "RocksSP.png" }, { "sp_chip_bottom.xpos", "7" }, { "sp_chip_bottom.ypos", "4" }, { "sp_chip_bottom.frames", "1" }, { "sp_hardware_gray", "RocksSP.png" }, { "sp_hardware_gray.xpos", "6" }, { "sp_hardware_gray.ypos", "0" }, { "sp_hardware_gray.frames", "1" }, { "sp_hardware_green", "RocksSP.png" }, { "sp_hardware_green.xpos", "5" }, { "sp_hardware_green.ypos", "3" }, { "sp_hardware_green.frames", "1" }, { "sp_hardware_blue", "RocksSP.png" }, { "sp_hardware_blue.xpos", "6" }, { "sp_hardware_blue.ypos", "3" }, { "sp_hardware_blue.frames", "1" }, { "sp_hardware_red", "RocksSP.png" }, { "sp_hardware_red.xpos", "7" }, { "sp_hardware_red.ypos", "3" }, { "sp_hardware_red.frames", "1" }, { "sp_hardware_yellow", "RocksSP.png" }, { "sp_hardware_yellow.xpos", "0" }, { "sp_hardware_yellow.ypos", "4" }, { "sp_hardware_yellow.frames", "1" }, { "sp_exit_closed", "RocksSP.png" }, { "sp_exit_closed.xpos", "7" }, { "sp_exit_closed.ypos", "0" }, { "sp_exit_closed.frames", "1" }, { "sp_exit.opening", "RocksSP.png" }, { "sp_exit.opening.xpos", "7" }, { "sp_exit.opening.ypos", "0" }, { "sp_exit.opening.frames", "1" }, { "sp_exit_open", "RocksSP.png" }, { "sp_exit_open.xpos", "7" }, { "sp_exit_open.ypos", "0" }, { "sp_exit_open.frames", "1" }, { "sp_exit.closing", "RocksSP.png" }, { "sp_exit.closing.xpos", "7" }, { "sp_exit.closing.ypos", "0" }, { "sp_exit.closing.frames", "1" }, { "sp_disk_orange", "RocksSP.png" }, { "sp_disk_orange.xpos", "0" }, { "sp_disk_orange.ypos", "1" }, { "sp_disk_orange.frames", "1" }, { "sp_disk_yellow", "RocksSP.png" }, { "sp_disk_yellow.xpos", "2" }, { "sp_disk_yellow.ypos", "2" }, { "sp_disk_yellow.frames", "1" }, { "sp_disk_red", "RocksSP.png" }, { "sp_disk_red.xpos", "4" }, { "sp_disk_red.ypos", "2" }, { "sp_disk_red.frames", "1" }, { "sp_disk_red.collecting", "RocksSP.png" }, { "sp_disk_red.collecting.xpos", "9" }, { "sp_disk_red.collecting.ypos", "5" }, { "sp_disk_red.collecting.frames", "7" }, { "sp_disk_red.collecting.anim_mode", "linear" }, { "sp_disk_red.active", "RocksSP.png" }, { "sp_disk_red.active.xpos", "4" }, { "sp_disk_red.active.ypos", "2" }, { "sp_disk_red.active.frames", "1" }, { "sp_port_right", "RocksSP.png" }, { "sp_port_right.xpos", "1" }, { "sp_port_right.ypos", "1" }, { "sp_port_right.frames", "1" }, { "sp_port_down", "RocksSP.png" }, { "sp_port_down.xpos", "2" }, { "sp_port_down.ypos", "1" }, { "sp_port_down.frames", "1" }, { "sp_port_left", "RocksSP.png" }, { "sp_port_left.xpos", "3" }, { "sp_port_left.ypos", "1" }, { "sp_port_left.frames", "1" }, { "sp_port_up", "RocksSP.png" }, { "sp_port_up.xpos", "4" }, { "sp_port_up.ypos", "1" }, { "sp_port_up.frames", "1" }, { "sp_port_horizontal", "RocksSP.png" }, { "sp_port_horizontal.xpos", "6" }, { "sp_port_horizontal.ypos", "2" }, { "sp_port_horizontal.frames", "1" }, { "sp_port_vertical", "RocksSP.png" }, { "sp_port_vertical.xpos", "5" }, { "sp_port_vertical.ypos", "2" }, { "sp_port_vertical.frames", "1" }, { "sp_port_any", "RocksSP.png" }, { "sp_port_any.xpos", "7" }, { "sp_port_any.ypos", "2" }, { "sp_port_any.frames", "1" }, { "sp_gravity_port_right", "RocksSP.png" }, { "sp_gravity_port_right.xpos", "1" }, { "sp_gravity_port_right.ypos", "1" }, { "sp_gravity_port_right.frames", "1" }, { "sp_gravity_port_right.EDITOR", "RocksSP.png" }, { "sp_gravity_port_right.EDITOR.xpos", "0" }, { "sp_gravity_port_right.EDITOR.ypos", "14" }, { "sp_gravity_port_down", "RocksSP.png" }, { "sp_gravity_port_down.xpos", "2" }, { "sp_gravity_port_down.ypos", "1" }, { "sp_gravity_port_down.frames", "1" }, { "sp_gravity_port_down.EDITOR", "RocksSP.png" }, { "sp_gravity_port_down.EDITOR.xpos", "1" }, { "sp_gravity_port_down.EDITOR.ypos", "14" }, { "sp_gravity_port_left", "RocksSP.png" }, { "sp_gravity_port_left.xpos", "3" }, { "sp_gravity_port_left.ypos", "1" }, { "sp_gravity_port_left.frames", "1" }, { "sp_gravity_port_left.EDITOR", "RocksSP.png" }, { "sp_gravity_port_left.EDITOR.xpos", "2" }, { "sp_gravity_port_left.EDITOR.ypos", "14" }, { "sp_gravity_port_up", "RocksSP.png" }, { "sp_gravity_port_up.xpos", "4" }, { "sp_gravity_port_up.ypos", "1" }, { "sp_gravity_port_up.frames", "1" }, { "sp_gravity_port_up.EDITOR", "RocksSP.png" }, { "sp_gravity_port_up.EDITOR.xpos", "3" }, { "sp_gravity_port_up.EDITOR.ypos", "14" }, { "sp_gravity_on_port_right", "RocksSP.png" }, { "sp_gravity_on_port_right.xpos", "1" }, { "sp_gravity_on_port_right.ypos", "1" }, { "sp_gravity_on_port_right.frames", "1" }, { "sp_gravity_on_port_right.EDITOR", "RocksSP.png" }, { "sp_gravity_on_port_right.EDITOR.xpos", "0" }, { "sp_gravity_on_port_right.EDITOR.ypos", "13" }, { "sp_gravity_on_port_down", "RocksSP.png" }, { "sp_gravity_on_port_down.xpos", "2" }, { "sp_gravity_on_port_down.ypos", "1" }, { "sp_gravity_on_port_down.frames", "1" }, { "sp_gravity_on_port_down.EDITOR", "RocksSP.png" }, { "sp_gravity_on_port_down.EDITOR.xpos", "1" }, { "sp_gravity_on_port_down.EDITOR.ypos", "13" }, { "sp_gravity_on_port_left", "RocksSP.png" }, { "sp_gravity_on_port_left.xpos", "3" }, { "sp_gravity_on_port_left.ypos", "1" }, { "sp_gravity_on_port_left.frames", "1" }, { "sp_gravity_on_port_left.EDITOR", "RocksSP.png" }, { "sp_gravity_on_port_left.EDITOR.xpos", "2" }, { "sp_gravity_on_port_left.EDITOR.ypos", "13" }, { "sp_gravity_on_port_up", "RocksSP.png" }, { "sp_gravity_on_port_up.xpos", "4" }, { "sp_gravity_on_port_up.ypos", "1" }, { "sp_gravity_on_port_up.frames", "1" }, { "sp_gravity_on_port_up.EDITOR", "RocksSP.png" }, { "sp_gravity_on_port_up.EDITOR.xpos", "3" }, { "sp_gravity_on_port_up.EDITOR.ypos", "13" }, { "sp_gravity_off_port_right", "RocksSP.png" }, { "sp_gravity_off_port_right.xpos", "1" }, { "sp_gravity_off_port_right.ypos", "1" }, { "sp_gravity_off_port_right.frames", "1" }, { "sp_gravity_off_port_right.EDITOR", "RocksSP.png" }, { "sp_gravity_off_port_right.EDITOR.xpos", "4" }, { "sp_gravity_off_port_right.EDITOR.ypos", "13" }, { "sp_gravity_off_port_down", "RocksSP.png" }, { "sp_gravity_off_port_down.xpos", "2" }, { "sp_gravity_off_port_down.ypos", "1" }, { "sp_gravity_off_port_down.frames", "1" }, { "sp_gravity_off_port_down.EDITOR", "RocksSP.png" }, { "sp_gravity_off_port_down.EDITOR.xpos", "5" }, { "sp_gravity_off_port_down.EDITOR.ypos", "13" }, { "sp_gravity_off_port_left", "RocksSP.png" }, { "sp_gravity_off_port_left.xpos", "3" }, { "sp_gravity_off_port_left.ypos", "1" }, { "sp_gravity_off_port_left.frames", "1" }, { "sp_gravity_off_port_left.EDITOR", "RocksSP.png" }, { "sp_gravity_off_port_left.EDITOR.xpos", "6" }, { "sp_gravity_off_port_left.EDITOR.ypos", "13" }, { "sp_gravity_off_port_up", "RocksSP.png" }, { "sp_gravity_off_port_up.xpos", "4" }, { "sp_gravity_off_port_up.ypos", "1" }, { "sp_gravity_off_port_up.frames", "1" }, { "sp_gravity_off_port_up.EDITOR", "RocksSP.png" }, { "sp_gravity_off_port_up.EDITOR.xpos", "7" }, { "sp_gravity_off_port_up.EDITOR.ypos", "13" }, { "sp_sniksnak", "RocksSP.png" }, { "sp_sniksnak.xpos", "1" }, { "sp_sniksnak.ypos", "2" }, { "sp_sniksnak.frames", "1" }, { "sp_sniksnak.left", "RocksSP.png" }, { "sp_sniksnak.left.xpos", "8" }, { "sp_sniksnak.left.ypos", "8" }, { "sp_sniksnak.left.frames", "4" }, { "sp_sniksnak.left.anim_mode", "pingpong2" }, { "sp_sniksnak.right", "RocksSP.png" }, { "sp_sniksnak.right.xpos", "12" }, { "sp_sniksnak.right.ypos", "8" }, { "sp_sniksnak.right.frames", "4" }, { "sp_sniksnak.right.anim_mode", "pingpong2" }, { "sp_sniksnak.up", "RocksSP.png" }, { "sp_sniksnak.up.xpos", "8" }, { "sp_sniksnak.up.ypos", "9" }, { "sp_sniksnak.up.frames", "4" }, { "sp_sniksnak.up.anim_mode", "pingpong2" }, { "sp_sniksnak.down", "RocksSP.png" }, { "sp_sniksnak.down.xpos", "12" }, { "sp_sniksnak.down.ypos", "9" }, { "sp_sniksnak.down.frames", "4" }, { "sp_sniksnak.down.anim_mode", "pingpong2" }, { "sp_sniksnak.turning_from_left.up", "RocksSP.png" }, { "sp_sniksnak.turning_from_left.up.xpos", "12" }, { "sp_sniksnak.turning_from_left.up.ypos", "6" }, { "sp_sniksnak.turning_from_left.up.frames", "2" }, { "sp_sniksnak.turning_from_left.up.delay", "4" }, { "sp_sniksnak.turning_from_left.up.offset", "1408" }, { "sp_sniksnak.turning_from_left.up.anim_mode","linear" }, { "sp_sniksnak.turning_from_left.down", "RocksSP.png" }, { "sp_sniksnak.turning_from_left.down.xpos", "13" }, { "sp_sniksnak.turning_from_left.down.ypos", "6" }, { "sp_sniksnak.turning_from_left.down.frames","2" }, { "sp_sniksnak.turning_from_left.down.delay", "4" }, { "sp_sniksnak.turning_from_left.down.offset","1504" }, { "sp_sniksnak.turning_from_left.down.anim_mode","linear" }, { "sp_sniksnak.turning_from_right.up", "RocksSP.png" }, { "sp_sniksnak.turning_from_right.up.xpos", "15" }, { "sp_sniksnak.turning_from_right.up.ypos", "6" }, { "sp_sniksnak.turning_from_right.up.frames", "2" }, { "sp_sniksnak.turning_from_right.up.delay", "4" }, { "sp_sniksnak.turning_from_right.up.offset", "1312" }, { "sp_sniksnak.turning_from_right.up.anim_mode","linear" }, { "sp_sniksnak.turning_from_right.down", "RocksSP.png" }, { "sp_sniksnak.turning_from_right.down.xpos", "14" }, { "sp_sniksnak.turning_from_right.down.ypos", "6" }, { "sp_sniksnak.turning_from_right.down.frames","2" }, { "sp_sniksnak.turning_from_right.down.delay","4" }, { "sp_sniksnak.turning_from_right.down.offset","1472" }, { "sp_sniksnak.turning_from_right.down.anim_mode","linear" }, { "sp_sniksnak.turning_from_up.left", "RocksSP.png" }, { "sp_sniksnak.turning_from_up.left.xpos", "12" }, { "sp_sniksnak.turning_from_up.left.ypos", "6" }, { "sp_sniksnak.turning_from_up.left.frames", "2" }, { "sp_sniksnak.turning_from_up.left.delay", "4" }, { "sp_sniksnak.turning_from_up.left.offset", "896" }, { "sp_sniksnak.turning_from_up.left.anim_mode","linear" }, { "sp_sniksnak.turning_from_up.right", "RocksSP.png" }, { "sp_sniksnak.turning_from_up.right.xpos", "15" }, { "sp_sniksnak.turning_from_up.right.ypos", "6" }, { "sp_sniksnak.turning_from_up.right.frames", "2" }, { "sp_sniksnak.turning_from_up.right.delay", "4" }, { "sp_sniksnak.turning_from_up.right.offset", "928" }, { "sp_sniksnak.turning_from_up.right.anim_mode","linear" }, { "sp_sniksnak.turning_from_down.left", "RocksSP.png" }, { "sp_sniksnak.turning_from_down.left.xpos", "13" }, { "sp_sniksnak.turning_from_down.left.ypos", "6" }, { "sp_sniksnak.turning_from_down.left.frames","2" }, { "sp_sniksnak.turning_from_down.left.delay", "4" }, { "sp_sniksnak.turning_from_down.left.offset","864" }, { "sp_sniksnak.turning_from_down.left.anim_mode","linear" }, { "sp_sniksnak.turning_from_down.right", "RocksSP.png" }, { "sp_sniksnak.turning_from_down.right.xpos", "14" }, { "sp_sniksnak.turning_from_down.right.ypos", "6" }, { "sp_sniksnak.turning_from_down.right.frames","2" }, { "sp_sniksnak.turning_from_down.right.delay","4" }, { "sp_sniksnak.turning_from_down.right.offset","960" }, { "sp_sniksnak.turning_from_down.right.anim_mode","linear" }, { "sp_electron", "RocksSP.png" }, { "sp_electron.xpos", "8" }, { "sp_electron.ypos", "10" }, { "sp_electron.frames", "8" }, { "sp_electron.delay", "4" }, { "sp_electron.global_sync", "true" }, { "sp_electron.EDITOR", "RocksSP.png" }, { "sp_electron.EDITOR.xpos", "10" }, { "sp_electron.EDITOR.ypos", "11" }, { "sp_electron.exploding", "RocksSP.png" }, { "sp_electron.exploding.xpos", "8" }, { "sp_electron.exploding.ypos", "4" }, { "sp_electron.exploding.frames", "8" }, { "sp_electron.exploding.delay", "4" }, { "sp_electron.exploding.anim_mode", "linear" }, { "sp_terminal", "RocksSP.png" }, { "sp_terminal.xpos", "0" }, { "sp_terminal.ypos", "10" }, { "sp_terminal.frames", "7" }, { "sp_terminal.delay", "12" }, { "sp_terminal.EDITOR", "RocksSP.png" }, { "sp_terminal.EDITOR.xpos", "9" }, { "sp_terminal.EDITOR.ypos", "11" }, { "sp_terminal.active", "RocksSP.png" }, { "sp_terminal.active.xpos", "0" }, { "sp_terminal.active.ypos", "11" }, { "sp_terminal.active.frames", "7" }, { "sp_terminal.active.delay", "4" }, { "sp_buggy_base", "RocksSP.png" }, { "sp_buggy_base.xpos", "1" }, { "sp_buggy_base.ypos", "3" }, { "sp_buggy_base.frames", "1" }, { "sp_buggy_base.EDITOR", "RocksSP.png" }, { "sp_buggy_base.EDITOR.xpos", "9" }, { "sp_buggy_base.EDITOR.ypos", "6" }, { "sp_buggy_base.activating", "RocksSP.png" }, { "sp_buggy_base.activating.xpos", "15" }, { "sp_buggy_base.activating.ypos", "2" }, { "sp_buggy_base.activating.frames", "1" }, { "sp_buggy_base.active", "RocksSP.png" }, { "sp_buggy_base.active.xpos", "8" }, { "sp_buggy_base.active.ypos", "6" }, { "sp_buggy_base.active.frames", "4" }, { "sp_buggy_base.active.delay", "4" }, { "sp_buggy_base.active.anim_mode", "pingpong" }, { "sp_hardware_base_1", "RocksSP.png" }, { "sp_hardware_base_1.xpos", "4" }, { "sp_hardware_base_1.ypos", "3" }, { "sp_hardware_base_1.frames", "1" }, { "sp_hardware_base_2", "RocksSP.png" }, { "sp_hardware_base_2.xpos", "1" }, { "sp_hardware_base_2.ypos", "4" }, { "sp_hardware_base_2.frames", "1" }, { "sp_hardware_base_3", "RocksSP.png" }, { "sp_hardware_base_3.xpos", "2" }, { "sp_hardware_base_3.ypos", "4" }, { "sp_hardware_base_3.frames", "1" }, { "sp_hardware_base_4", "RocksSP.png" }, { "sp_hardware_base_4.xpos", "3" }, { "sp_hardware_base_4.ypos", "4" }, { "sp_hardware_base_4.frames", "1" }, { "sp_hardware_base_5", "RocksSP.png" }, { "sp_hardware_base_5.xpos", "4" }, { "sp_hardware_base_5.ypos", "4" }, { "sp_hardware_base_5.frames", "1" }, { "sp_hardware_base_6", "RocksSP.png" }, { "sp_hardware_base_6.xpos", "5" }, { "sp_hardware_base_6.ypos", "4" }, { "sp_hardware_base_6.frames", "1" }, /* images for Sokoban style elements and actions */ { "sokoban_object", "RocksElements.png" }, { "sokoban_object.xpos", "9" }, { "sokoban_object.ypos", "7" }, { "sokoban_object.frames", "1" }, { "sokoban_object.EDITOR", "RocksElements.png" }, { "sokoban_object.EDITOR.xpos", "2" }, { "sokoban_object.EDITOR.ypos", "14" }, { "sokoban_field_empty", "RocksElements.png" }, { "sokoban_field_empty.xpos", "10" }, { "sokoban_field_empty.ypos", "7" }, { "sokoban_field_empty.frames", "1" }, { "sokoban_field_full", "RocksElements.png" }, { "sokoban_field_full.xpos", "11" }, { "sokoban_field_full.ypos", "7" }, { "sokoban_field_full.frames", "1" }, { "sokoban_field_player", "RocksHeroes.png" }, { "sokoban_field_player.xpos", "0" }, { "sokoban_field_player.ypos", "15" }, { "sokoban_field_player.frames", "1" }, { "sokoban_field_player.EDITOR", "RocksHeroes.png" }, { "sokoban_field_player.EDITOR.xpos", "1" }, { "sokoban_field_player.EDITOR.ypos", "15" }, /* images for Emerald Mine style elements and actions */ { "empty_space", "RocksSP.png" }, { "empty_space.xpos", "0" }, { "empty_space.ypos", "0" }, { "empty_space.frames", "1" }, { "sand", "RocksElements.png" }, { "sand.xpos", "0" }, { "sand.ypos", "0" }, { "sand.frames", "1" }, { "sand.CRUMBLED", "RocksElements.png" }, { "sand.CRUMBLED.xpos", "1" }, { "sand.CRUMBLED.ypos", "0" }, { "sand.CRUMBLED.frames", "1" }, { "sand.digging.left", "RocksMore.png" }, { "sand.digging.left.xpos", "6" }, { "sand.digging.left.ypos", "3" }, { "sand.digging.left.frames", "3" }, { "sand.digging.left.delay", "2" }, { "sand.digging.left.anim_mode", "linear" }, { "sand.digging.right", "RocksMore.png" }, { "sand.digging.right.xpos", "9" }, { "sand.digging.right.ypos", "3" }, { "sand.digging.right.frames", "3" }, { "sand.digging.right.delay", "2" }, { "sand.digging.right.anim_mode", "linear" }, { "sand.digging.up", "RocksMore.png" }, { "sand.digging.up.xpos", "0" }, { "sand.digging.up.ypos", "3" }, { "sand.digging.up.frames", "3" }, { "sand.digging.up.delay", "2" }, { "sand.digging.up.anim_mode", "linear" }, { "sand.digging.down", "RocksMore.png" }, { "sand.digging.down.xpos", "3" }, { "sand.digging.down.ypos", "3" }, { "sand.digging.down.frames", "3" }, { "sand.digging.down.delay", "2" }, { "sand.digging.down.anim_mode", "linear" }, { "sand.digging.left.CRUMBLED", "RocksMore.png" }, { "sand.digging.left.CRUMBLED.xpos", "6" }, { "sand.digging.left.CRUMBLED.ypos", "0" }, { "sand.digging.left.CRUMBLED.frames", "3" }, { "sand.digging.left.CRUMBLED.delay", "2" }, { "sand.digging.left.CRUMBLED.anim_mode", "linear" }, { "sand.digging.right.CRUMBLED", "RocksMore.png" }, { "sand.digging.right.CRUMBLED.xpos", "9" }, { "sand.digging.right.CRUMBLED.ypos", "0" }, { "sand.digging.right.CRUMBLED.frames", "3" }, { "sand.digging.right.CRUMBLED.delay", "2" }, { "sand.digging.right.CRUMBLED.anim_mode", "linear" }, { "sand.digging.up.CRUMBLED", "RocksMore.png" }, { "sand.digging.up.CRUMBLED.xpos", "0" }, { "sand.digging.up.CRUMBLED.ypos", "0" }, { "sand.digging.up.CRUMBLED.frames", "3" }, { "sand.digging.up.CRUMBLED.delay", "2" }, { "sand.digging.up.CRUMBLED.anim_mode", "linear" }, { "sand.digging.down.CRUMBLED", "RocksMore.png" }, { "sand.digging.down.CRUMBLED.xpos", "3" }, { "sand.digging.down.CRUMBLED.ypos", "0" }, { "sand.digging.down.CRUMBLED.frames", "3" }, { "sand.digging.down.CRUMBLED.delay", "2" }, { "sand.digging.down.CRUMBLED.anim_mode", "linear" }, { "wall", "RocksElements.png" }, { "wall.xpos", "5" }, { "wall.ypos", "0" }, { "wall.frames", "1" }, { "wall_slippery", "RocksElements.png" }, { "wall_slippery.xpos", "6" }, { "wall_slippery.ypos", "0" }, { "wall_slippery.frames", "1" }, { "steelwall", "RocksElements.png" }, { "steelwall.xpos", "4" }, { "steelwall.ypos", "0" }, { "steelwall.frames", "1" }, { "rock", "RocksElements.png" }, { "rock.xpos", "12" }, { "rock.ypos", "0" }, { "rock.frames", "1" }, { "rock.moving.left", "RocksElements.png" }, { "rock.moving.left.xpos", "12" }, { "rock.moving.left.ypos", "0" }, { "rock.moving.left.frames", "4" }, { "rock.moving.left.delay", "2" }, { "rock.moving.left.anim_mode", "reverse" }, { "rock.moving.right", "RocksElements.png" }, { "rock.moving.right.xpos", "12" }, { "rock.moving.right.ypos", "0" }, { "rock.moving.right.frames", "4" }, { "rock.moving.right.start_frame", "1" }, { "rock.moving.right.delay", "2" }, { "rock.pushing.left", "RocksElements.png" }, { "rock.pushing.left.xpos", "12" }, { "rock.pushing.left.ypos", "0" }, { "rock.pushing.left.frames", "4" }, { "rock.pushing.left.delay", "2" }, { "rock.pushing.left.anim_mode", "reverse" }, { "rock.pushing.right", "RocksElements.png" }, { "rock.pushing.right.xpos", "12" }, { "rock.pushing.right.ypos", "0" }, { "rock.pushing.right.frames", "4" }, { "rock.pushing.right.start_frame", "1" }, { "rock.pushing.right.delay", "2" }, { "emerald", "RocksElements.png" }, { "emerald.xpos", "8" }, { "emerald.ypos", "0" }, { "emerald.frames", "1" }, { "emerald.moving", "RocksElements.png" }, { "emerald.moving.xpos", "8" }, { "emerald.moving.ypos", "0" }, { "emerald.moving.frames", "2" }, { "emerald.moving.delay", "4" }, { "emerald.falling", "RocksElements.png" }, { "emerald.falling.xpos", "8" }, { "emerald.falling.ypos", "0" }, { "emerald.falling.frames", "2" }, { "emerald.falling.delay", "4" }, { "emerald.collecting", "RocksMore.png" }, { "emerald.collecting.xpos", "3" }, { "emerald.collecting.ypos", "2" }, { "emerald.collecting.frames", "3" }, { "emerald.collecting.delay", "2" }, { "emerald.collecting.anim_mode", "linear" }, { "diamond", "RocksElements.png" }, { "diamond.xpos", "10" }, { "diamond.ypos", "0" }, { "diamond.frames", "1" }, { "diamond.moving", "RocksElements.png" }, { "diamond.moving.xpos", "10" }, { "diamond.moving.ypos", "0" }, { "diamond.moving.frames", "2" }, { "diamond.moving.delay", "4" }, { "diamond.falling", "RocksElements.png" }, { "diamond.falling.xpos", "10" }, { "diamond.falling.ypos", "0" }, { "diamond.falling.frames", "2" }, { "diamond.falling.delay", "4" }, { "diamond.collecting", "RocksMore.png" }, { "diamond.collecting.xpos", "7" }, { "diamond.collecting.ypos", "2" }, { "diamond.collecting.frames", "3" }, { "diamond.collecting.delay", "2" }, { "diamond.collecting.anim_mode", "linear" }, { "bomb", "RocksElements.png" }, { "bomb.xpos", "11" }, { "bomb.ypos", "1" }, { "bomb.frames", "1" }, { "nut", "RocksElements.png" }, { "nut.xpos", "12" }, { "nut.ypos", "1" }, { "nut.frames", "1" }, { "nut.breaking", "RocksElements.png" }, { "nut.breaking.xpos", "13" }, { "nut.breaking.ypos", "1" }, { "nut.breaking.frames", "3" }, { "nut.breaking.delay", "2" }, { "nut.breaking.anim_mode", "linear" }, { "dynamite", "RocksElements.png" }, { "dynamite.xpos", "0" }, { "dynamite.ypos", "3" }, { "dynamite.frames", "1" }, { "dynamite.EDITOR", "RocksElements.png" }, { "dynamite.EDITOR.xpos", "0" }, { "dynamite.EDITOR.ypos", "14" }, { "dynamite.active", "RocksElements.png" }, { "dynamite.active.xpos", "1" }, { "dynamite.active.ypos", "3" }, { "dynamite.active.frames", "7" }, { "dynamite.active.delay", "12" }, { "dynamite.active.anim_mode", "linear" }, { "dynamite.active.EDITOR", "RocksElements.png" }, { "dynamite.active.EDITOR.xpos", "1" }, { "dynamite.active.EDITOR.ypos", "14" }, { "em_dynamite", "RocksEMC.png" }, { "em_dynamite.xpos", "0" }, { "em_dynamite.ypos", "15" }, { "em_dynamite.frames", "1" }, { "em_dynamite.active", "RocksEMC.png" }, { "em_dynamite.active.xpos", "1" }, { "em_dynamite.active.ypos", "15" }, { "em_dynamite.active.frames", "4" }, { "em_dynamite.active.delay", "8" }, { "em_dynamite.active.anim_mode", "linear" }, { "em_dynamite.active.EDITOR", "RocksEMC.png" }, { "em_dynamite.active.EDITOR.xpos", "2" }, { "em_dynamite.active.EDITOR.ypos", "15" }, { "wall_emerald", "RocksElements.png" }, { "wall_emerald.xpos", "4" }, { "wall_emerald.ypos", "8" }, { "wall_emerald.frames", "1" }, { "wall_diamond", "RocksElements.png" }, { "wall_diamond.xpos", "5" }, { "wall_diamond.ypos", "8" }, { "wall_diamond.frames", "1" }, { "bug", "RocksElements.png" }, { "bug.xpos", "8" }, { "bug.ypos", "4" }, { "bug.frames", "4" }, { "bug.delay", "8" }, { "bug.right", "RocksElements.png" }, { "bug.right.xpos", "8" }, { "bug.right.ypos", "4" }, { "bug.right.frames", "1" }, { "bug.up", "RocksElements.png" }, { "bug.up.xpos", "9" }, { "bug.up.ypos", "4" }, { "bug.up.frames", "1" }, { "bug.left", "RocksElements.png" }, { "bug.left.xpos", "10" }, { "bug.left.ypos", "4" }, { "bug.left.frames", "1" }, { "bug.down", "RocksElements.png" }, { "bug.down.xpos", "11" }, { "bug.down.ypos", "4" }, { "bug.down.frames", "1" }, { "bug.moving.right", "RocksElements.png" }, { "bug.moving.right.xpos", "8" }, { "bug.moving.right.ypos", "4" }, { "bug.moving.right.frames", "2" }, { "bug.moving.right.delay", "4" }, { "bug.moving.right.offset", "128" }, { "bug.moving.up", "RocksElements.png" }, { "bug.moving.up.xpos", "9" }, { "bug.moving.up.ypos", "4" }, { "bug.moving.up.frames", "2" }, { "bug.moving.up.delay", "4" }, { "bug.moving.up.offset", "128" }, { "bug.moving.left", "RocksElements.png" }, { "bug.moving.left.xpos", "10" }, { "bug.moving.left.ypos", "4" }, { "bug.moving.left.frames", "2" }, { "bug.moving.left.delay", "4" }, { "bug.moving.left.offset", "128" }, { "bug.moving.down", "RocksElements.png" }, { "bug.moving.down.xpos", "11" }, { "bug.moving.down.ypos", "4" }, { "bug.moving.down.frames", "2" }, { "bug.moving.down.delay", "4" }, { "bug.moving.down.offset", "128" }, { "bug.turning_from_right.up", "RocksMore.png" }, { "bug.turning_from_right.up.xpos", "0" }, { "bug.turning_from_right.up.ypos", "6" }, { "bug.turning_from_right.up.frames", "4" }, { "bug.turning_from_right.up.delay", "2" }, { "bug.turning_from_right.up.anim_mode", "linear,reverse" }, { "bug.turning_from_up.left", "RocksMore.png" }, { "bug.turning_from_up.left.xpos", "12" }, { "bug.turning_from_up.left.ypos", "6" }, { "bug.turning_from_up.left.frames", "4" }, { "bug.turning_from_up.left.delay", "2" }, { "bug.turning_from_up.left.anim_mode", "linear,reverse" }, { "bug.turning_from_left.down", "RocksMore.png" }, { "bug.turning_from_left.down.xpos", "8" }, { "bug.turning_from_left.down.ypos", "6" }, { "bug.turning_from_left.down.frames", "4" }, { "bug.turning_from_left.down.delay", "2" }, { "bug.turning_from_left.down.anim_mode", "linear,reverse" }, { "bug.turning_from_down.right", "RocksMore.png" }, { "bug.turning_from_down.right.xpos", "4" }, { "bug.turning_from_down.right.ypos", "6" }, { "bug.turning_from_down.right.frames", "4" }, { "bug.turning_from_down.right.delay", "2" }, { "bug.turning_from_down.right.anim_mode", "linear,reverse" }, { "bug.turning_from_right.down", "RocksMore.png" }, { "bug.turning_from_right.down.xpos", "5" }, { "bug.turning_from_right.down.ypos", "6" }, { "bug.turning_from_right.down.frames", "4" }, { "bug.turning_from_right.down.delay", "2" }, { "bug.turning_from_right.down.anim_mode", "linear" }, { "bug.turning_from_up.right", "RocksMore.png" }, { "bug.turning_from_up.right.xpos", "1" }, { "bug.turning_from_up.right.ypos", "6" }, { "bug.turning_from_up.right.frames", "4" }, { "bug.turning_from_up.right.delay", "2" }, { "bug.turning_from_up.right.anim_mode", "linear" }, { "bug.turning_from_left.up", "RocksMore.png" }, { "bug.turning_from_left.up.xpos", "13" }, { "bug.turning_from_left.up.ypos", "6" }, { "bug.turning_from_left.up.frames", "4" }, { "bug.turning_from_left.up.delay", "2" }, { "bug.turning_from_left.up.anim_mode", "linear" }, { "bug.turning_from_down.left", "RocksMore.png" }, { "bug.turning_from_down.left.xpos", "9" }, { "bug.turning_from_down.left.ypos", "6" }, { "bug.turning_from_down.left.frames", "4" }, { "bug.turning_from_down.left.delay", "2" }, { "bug.turning_from_down.left.anim_mode", "linear" }, { "spaceship", "RocksElements.png" }, { "spaceship.xpos", "8" }, { "spaceship.ypos", "3" }, { "spaceship.frames", "4" }, { "spaceship.delay", "8" }, { "spaceship.right", "RocksElements.png" }, { "spaceship.right.xpos", "8" }, { "spaceship.right.ypos", "3" }, { "spaceship.right.frames", "1" }, { "spaceship.up", "RocksElements.png" }, { "spaceship.up.xpos", "9" }, { "spaceship.up.ypos", "3" }, { "spaceship.up.frames", "1" }, { "spaceship.left", "RocksElements.png" }, { "spaceship.left.xpos", "10" }, { "spaceship.left.ypos", "3" }, { "spaceship.left.frames", "1" }, { "spaceship.down", "RocksElements.png" }, { "spaceship.down.xpos", "11" }, { "spaceship.down.ypos", "3" }, { "spaceship.down.frames", "1" }, { "spaceship.moving.right", "RocksElements.png" }, { "spaceship.moving.right.xpos", "8" }, { "spaceship.moving.right.ypos", "3" }, { "spaceship.moving.right.frames", "2" }, { "spaceship.moving.right.delay", "4" }, { "spaceship.moving.right.offset", "128" }, { "spaceship.moving.up", "RocksElements.png" }, { "spaceship.moving.up.xpos", "9" }, { "spaceship.moving.up.ypos", "3" }, { "spaceship.moving.up.frames", "2" }, { "spaceship.moving.up.delay", "4" }, { "spaceship.moving.up.offset", "128" }, { "spaceship.moving.left", "RocksElements.png" }, { "spaceship.moving.left.xpos", "10" }, { "spaceship.moving.left.ypos", "3" }, { "spaceship.moving.left.frames", "2" }, { "spaceship.moving.left.delay", "4" }, { "spaceship.moving.left.offset", "128" }, { "spaceship.moving.down", "RocksElements.png" }, { "spaceship.moving.down.xpos", "11" }, { "spaceship.moving.down.ypos", "3" }, { "spaceship.moving.down.frames", "2" }, { "spaceship.moving.down.delay", "4" }, { "spaceship.moving.down.offset", "128" }, { "spaceship.turning_from_right.up", "RocksMore.png" }, { "spaceship.turning_from_right.up.xpos", "0" }, { "spaceship.turning_from_right.up.ypos", "5" }, { "spaceship.turning_from_right.up.frames", "4" }, { "spaceship.turning_from_right.up.delay", "2" }, { "spaceship.turning_from_right.up.anim_mode","linear,reverse" }, { "spaceship.turning_from_up.left", "RocksMore.png" }, { "spaceship.turning_from_up.left.xpos", "12" }, { "spaceship.turning_from_up.left.ypos", "5" }, { "spaceship.turning_from_up.left.frames", "4" }, { "spaceship.turning_from_up.left.delay", "2" }, { "spaceship.turning_from_up.left.anim_mode", "linear,reverse" }, { "spaceship.turning_from_left.down", "RocksMore.png" }, { "spaceship.turning_from_left.down.xpos", "8" }, { "spaceship.turning_from_left.down.ypos", "5" }, { "spaceship.turning_from_left.down.frames", "4" }, { "spaceship.turning_from_left.down.delay", "2" }, { "spaceship.turning_from_left.down.anim_mode","linear,reverse" }, { "spaceship.turning_from_down.right", "RocksMore.png" }, { "spaceship.turning_from_down.right.xpos", "4" }, { "spaceship.turning_from_down.right.ypos", "5" }, { "spaceship.turning_from_down.right.frames", "4" }, { "spaceship.turning_from_down.right.delay", "2" }, { "spaceship.turning_from_down.right.anim_mode","linear,reverse" }, { "spaceship.turning_from_right.down", "RocksMore.png" }, { "spaceship.turning_from_right.down.xpos", "5" }, { "spaceship.turning_from_right.down.ypos", "5" }, { "spaceship.turning_from_right.down.frames", "4" }, { "spaceship.turning_from_right.down.delay", "2" }, { "spaceship.turning_from_right.down.anim_mode","linear" }, { "spaceship.turning_from_up.right", "RocksMore.png" }, { "spaceship.turning_from_up.right.xpos", "1" }, { "spaceship.turning_from_up.right.ypos", "5" }, { "spaceship.turning_from_up.right.frames", "4" }, { "spaceship.turning_from_up.right.delay", "2" }, { "spaceship.turning_from_up.right.anim_mode","linear" }, { "spaceship.turning_from_left.up", "RocksMore.png" }, { "spaceship.turning_from_left.up.xpos", "13" }, { "spaceship.turning_from_left.up.ypos", "5" }, { "spaceship.turning_from_left.up.frames", "4" }, { "spaceship.turning_from_left.up.delay", "2" }, { "spaceship.turning_from_left.up.anim_mode", "linear" }, { "spaceship.turning_from_down.left", "RocksMore.png" }, { "spaceship.turning_from_down.left.xpos", "9" }, { "spaceship.turning_from_down.left.ypos", "5" }, { "spaceship.turning_from_down.left.frames", "4" }, { "spaceship.turning_from_down.left.delay", "2" }, { "spaceship.turning_from_down.left.anim_mode","linear" }, { "yamyam", "RocksElements.png" }, { "yamyam.xpos", "0" }, { "yamyam.ypos", "5" }, { "yamyam.frames", "4" }, { "yamyam.anim_mode", "pingpong2" }, { "yamyam.left", "RocksElements.png" }, { "yamyam.left.xpos", "0" }, { "yamyam.left.ypos", "5" }, { "yamyam.left.frames", "4" }, { "yamyam.left.anim_mode", "pingpong2" }, { "yamyam.left.EDITOR", "RocksEMC.png" }, { "yamyam.left.EDITOR.xpos", "7" }, { "yamyam.left.EDITOR.ypos", "15" }, { "yamyam.right", "RocksElements.png" }, { "yamyam.right.xpos", "0" }, { "yamyam.right.ypos", "5" }, { "yamyam.right.frames", "4" }, { "yamyam.right.anim_mode", "pingpong2" }, { "yamyam.right.EDITOR", "RocksEMC.png" }, { "yamyam.right.EDITOR.xpos", "8" }, { "yamyam.right.EDITOR.ypos", "15" }, { "yamyam.up", "RocksElements.png" }, { "yamyam.up.xpos", "0" }, { "yamyam.up.ypos", "5" }, { "yamyam.up.frames", "4" }, { "yamyam.up.anim_mode", "pingpong2" }, { "yamyam.up.EDITOR", "RocksEMC.png" }, { "yamyam.up.EDITOR.xpos", "5" }, { "yamyam.up.EDITOR.ypos", "15" }, { "yamyam.down", "RocksElements.png" }, { "yamyam.down.xpos", "0" }, { "yamyam.down.ypos", "5" }, { "yamyam.down.frames", "4" }, { "yamyam.down.anim_mode", "pingpong2" }, { "yamyam.down.EDITOR", "RocksEMC.png" }, { "yamyam.down.EDITOR.xpos", "6" }, { "yamyam.down.EDITOR.ypos", "15" }, { "yamyam.moving", "RocksElements.png" }, { "yamyam.moving.xpos", "0" }, { "yamyam.moving.ypos", "5" }, { "yamyam.moving.frames", "1" }, { "robot", "RocksElements.png" }, { "robot.xpos", "4" }, { "robot.ypos", "5" }, { "robot.frames", "4" }, { "robot.anim_mode", "pingpong2" }, { "robot.moving", "RocksElements.png" }, { "robot.moving.xpos", "4" }, { "robot.moving.ypos", "5" }, { "robot.moving.frames", "1" }, { "robot_wheel", "RocksElements.png" }, { "robot_wheel.xpos", "0" }, { "robot_wheel.ypos", "6" }, { "robot_wheel.frames", "1" }, { "robot_wheel.active", "RocksElements.png" }, { "robot_wheel.active.xpos", "0" }, { "robot_wheel.active.ypos", "6" }, { "robot_wheel.active.frames", "4" }, { "magic_wall", "RocksElements.png" }, { "magic_wall.xpos", "0" }, { "magic_wall.ypos", "8" }, { "magic_wall.frames", "1" }, { "magic_wall.active", "RocksElements.png" }, { "magic_wall.active.xpos", "0" }, { "magic_wall.active.ypos", "8" }, { "magic_wall.active.frames", "4" }, { "magic_wall.active.anim_mode", "reverse" }, { "magic_wall.active.delay", "4" }, { "magic_wall.active.global_sync", "true" }, { "magic_wall.filling", "RocksElements.png" }, { "magic_wall.filling.xpos", "0" }, { "magic_wall.filling.ypos", "8" }, { "magic_wall.filling.frames", "4" }, { "magic_wall.filling.anim_mode", "reverse" }, { "magic_wall.filling.delay", "4" }, { "magic_wall.filling.global_sync", "true" }, { "magic_wall_full", "RocksElements.png" }, { "magic_wall_full.xpos", "0" }, { "magic_wall_full.ypos", "8" }, { "magic_wall_full.frames", "4" }, { "magic_wall_full.anim_mode", "reverse" }, { "magic_wall_full.delay", "4" }, { "magic_wall_full.global_sync", "true" }, { "magic_wall.emptying", "RocksElements.png" }, { "magic_wall.emptying.xpos", "0" }, { "magic_wall.emptying.ypos", "8" }, { "magic_wall.emptying.frames", "4" }, { "magic_wall.emptying.anim_mode", "reverse" }, { "magic_wall.emptying.delay", "4" }, { "magic_wall.emptying.global_sync", "true" }, { "magic_wall_dead", "RocksElements.png" }, { "magic_wall_dead.xpos", "0" }, { "magic_wall_dead.ypos", "8" }, { "magic_wall_dead.frames", "1" }, { "dc_magic_wall", "RocksDC2.png" }, { "dc_magic_wall.xpos", "0" }, { "dc_magic_wall.ypos", "3" }, { "dc_magic_wall.frames", "1" }, { "dc_magic_wall.active", "RocksDC2.png" }, { "dc_magic_wall.active.xpos", "0" }, { "dc_magic_wall.active.ypos", "3" }, { "dc_magic_wall.active.frames", "4" }, { "dc_magic_wall.active.anim_mode", "reverse" }, { "dc_magic_wall.active.delay", "4" }, { "dc_magic_wall.active.global_sync", "true" }, { "dc_magic_wall.filling", "RocksDC2.png" }, { "dc_magic_wall.filling.xpos", "0" }, { "dc_magic_wall.filling.ypos", "3" }, { "dc_magic_wall.filling.frames", "4" }, { "dc_magic_wall.filling.anim_mode", "reverse" }, { "dc_magic_wall.filling.delay", "4" }, { "dc_magic_wall.filling.global_sync", "true" }, { "dc_magic_wall_full", "RocksDC2.png" }, { "dc_magic_wall_full.xpos", "0" }, { "dc_magic_wall_full.ypos", "3" }, { "dc_magic_wall_full.frames", "4" }, { "dc_magic_wall_full.anim_mode", "reverse" }, { "dc_magic_wall_full.delay", "4" }, { "dc_magic_wall_full.global_sync", "true" }, { "dc_magic_wall.emptying", "RocksDC2.png" }, { "dc_magic_wall.emptying.xpos", "0" }, { "dc_magic_wall.emptying.ypos", "3" }, { "dc_magic_wall.emptying.frames", "4" }, { "dc_magic_wall.emptying.anim_mode", "reverse" }, { "dc_magic_wall.emptying.delay", "4" }, { "dc_magic_wall.emptying.global_sync", "true" }, { "dc_magic_wall_dead", "RocksDC2.png" }, { "dc_magic_wall_dead.xpos", "0" }, { "dc_magic_wall_dead.ypos", "3" }, { "dc_magic_wall_dead.frames", "1" }, { "quicksand_empty", "RocksElements.png" }, { "quicksand_empty.xpos", "2" }, { "quicksand_empty.ypos", "0" }, { "quicksand_empty.frames", "1" }, { "quicksand.filling", "RocksElements.png" }, { "quicksand.filling.xpos", "3" }, { "quicksand.filling.ypos", "0" }, { "quicksand.filling.frames", "1" }, { "quicksand_full", "RocksElements.png" }, { "quicksand_full.xpos", "3" }, { "quicksand_full.ypos", "0" }, { "quicksand_full.frames", "1" }, { "quicksand_full.EDITOR", "RocksElements.png" }, { "quicksand_full.EDITOR.xpos", "3" }, { "quicksand_full.EDITOR.ypos", "14" }, { "quicksand.emptying", "RocksElements.png" }, { "quicksand.emptying.xpos", "3" }, { "quicksand.emptying.ypos", "0" }, { "quicksand.emptying.frames", "1" }, { "quicksand_fast_empty", "RocksDC2.png" }, { "quicksand_fast_empty.xpos", "4" }, { "quicksand_fast_empty.ypos", "3" }, { "quicksand_fast_empty.frames", "1" }, { "quicksand_fast.filling", "RocksDC2.png" }, { "quicksand_fast.filling.xpos", "4" }, { "quicksand_fast.filling.ypos", "3" }, { "quicksand_fast.filling.frames", "1" }, { "quicksand_fast_full", "RocksDC2.png" }, { "quicksand_fast_full.xpos", "4" }, { "quicksand_fast_full.ypos", "3" }, { "quicksand_fast_full.frames", "1" }, { "quicksand_fast_full.EDITOR", "RocksDC2.png" }, { "quicksand_fast_full.EDITOR.xpos", "5" }, { "quicksand_fast_full.EDITOR.ypos", "3" }, { "quicksand_fast.emptying", "RocksDC2.png" }, { "quicksand_fast.emptying.xpos", "4" }, { "quicksand_fast.emptying.ypos", "3" }, { "quicksand_fast.emptying.frames", "1" }, { "acid_pool_topleft", "RocksElements.png" }, { "acid_pool_topleft.xpos", "0" }, { "acid_pool_topleft.ypos", "1" }, { "acid_pool_topleft.frames", "1" }, { "acid_pool_topright", "RocksElements.png" }, { "acid_pool_topright.xpos", "2" }, { "acid_pool_topright.ypos", "1" }, { "acid_pool_topright.frames", "1" }, { "acid_pool_bottomleft", "RocksElements.png" }, { "acid_pool_bottomleft.xpos", "0" }, { "acid_pool_bottomleft.ypos", "2" }, { "acid_pool_bottomleft.frames", "1" }, { "acid_pool_bottom", "RocksElements.png" }, { "acid_pool_bottom.xpos", "1" }, { "acid_pool_bottom.ypos", "2" }, { "acid_pool_bottom.frames", "1" }, { "acid_pool_bottomright", "RocksElements.png" }, { "acid_pool_bottomright.xpos", "2" }, { "acid_pool_bottomright.ypos", "2" }, { "acid_pool_bottomright.frames", "1" }, { "acid", "RocksElements.png" }, { "acid.xpos", "12" }, { "acid.ypos", "7" }, { "acid.frames", "4" }, { "acid.delay", "10" }, { "acid.global_sync", "true" }, { "acid_splash_left", "RocksHeroes.png" }, { "acid_splash_left.xpos", "8" }, { "acid_splash_left.ypos", "10" }, { "acid_splash_left.frames", "4" }, { "acid_splash_left.delay", "2" }, { "acid_splash_left.anim_mode", "linear" }, { "acid_splash_right", "RocksHeroes.png" }, { "acid_splash_right.xpos", "12" }, { "acid_splash_right.ypos", "10" }, { "acid_splash_right.frames", "4" }, { "acid_splash_right.delay", "2" }, { "acid_splash_right.anim_mode", "linear" }, { "amoeba_drop", "RocksElements.png" }, { "amoeba_drop.xpos", "5" }, { "amoeba_drop.ypos", "6" }, { "amoeba_drop.frames", "1" }, { "amoeba.growing", "RocksElements.png" }, { "amoeba.growing.xpos", "5" }, { "amoeba.growing.ypos", "6" }, { "amoeba.growing.frames", "3" }, { "amoeba.growing.delay", "2" }, { "amoeba.growing.anim_mode", "linear" }, { "amoeba.shrinking", "RocksElements.png" }, { "amoeba.shrinking.xpos", "5" }, { "amoeba.shrinking.ypos", "6" }, { "amoeba.shrinking.frames", "3" }, { "amoeba.shrinking.delay", "2" }, { "amoeba.shrinking.anim_mode", "linear,reverse" }, { "amoeba_wet", "RocksElements.png" }, { "amoeba_wet.xpos", "8" }, { "amoeba_wet.ypos", "6" }, { "amoeba_wet.frames", "4" }, { "amoeba_wet.delay", "1000000" }, { "amoeba_wet.anim_mode", "random" }, { "amoeba_wet.EDITOR", "RocksElements.png" }, { "amoeba_wet.EDITOR.xpos", "4" }, { "amoeba_wet.EDITOR.ypos", "6" }, { "amoeba.dropping", "RocksElements.png" }, { "amoeba.dropping.xpos", "8" }, { "amoeba.dropping.ypos", "6" }, { "amoeba.dropping.frames", "4" }, { "amoeba.dropping.delay", "1000000" }, { "amoeba.dropping.anim_mode", "random" }, { "amoeba_dry", "RocksElements.png" }, { "amoeba_dry.xpos", "8" }, { "amoeba_dry.ypos", "6" }, { "amoeba_dry.frames", "4" }, { "amoeba_dry.delay", "1000000" }, { "amoeba_dry.anim_mode", "random" }, { "amoeba_full", "RocksElements.png" }, { "amoeba_full.xpos", "8" }, { "amoeba_full.ypos", "6" }, { "amoeba_full.frames", "4" }, { "amoeba_full.delay", "1000000" }, { "amoeba_full.anim_mode", "random" }, { "amoeba_full.EDITOR", "RocksElements.png" }, { "amoeba_full.EDITOR.xpos", "8" }, { "amoeba_full.EDITOR.ypos", "7" }, { "amoeba_dead", "RocksElements.png" }, { "amoeba_dead.xpos", "12" }, { "amoeba_dead.ypos", "6" }, { "amoeba_dead.frames", "4" }, { "amoeba_dead.delay", "1000000" }, { "amoeba_dead.anim_mode", "random" }, { "amoeba_dead.EDITOR", "RocksElements.png" }, { "amoeba_dead.EDITOR.xpos", "12" }, { "amoeba_dead.EDITOR.ypos", "6" }, { "em_key_1", "RocksSP.png" }, { "em_key_1.xpos", "4" }, { "em_key_1.ypos", "6" }, { "em_key_1.frames", "1" }, { "em_key_2", "RocksSP.png" }, { "em_key_2.xpos", "5" }, { "em_key_2.ypos", "6" }, { "em_key_2.frames", "1" }, { "em_key_3", "RocksSP.png" }, { "em_key_3.xpos", "6" }, { "em_key_3.ypos", "6" }, { "em_key_3.frames", "1" }, { "em_key_4", "RocksSP.png" }, { "em_key_4.xpos", "7" }, { "em_key_4.ypos", "6" }, { "em_key_4.frames", "1" }, { "dc_key_white", "RocksSP.png" }, { "dc_key_white.xpos", "13" }, { "dc_key_white.ypos", "1" }, { "dc_key_white.frames", "1" }, { "em_gate_1", "RocksSP.png" }, { "em_gate_1.xpos", "0" }, { "em_gate_1.ypos", "7" }, { "em_gate_1.frames", "1" }, { "em_gate_2", "RocksSP.png" }, { "em_gate_2.xpos", "1" }, { "em_gate_2.ypos", "7" }, { "em_gate_2.frames", "1" }, { "em_gate_3", "RocksSP.png" }, { "em_gate_3.xpos", "2" }, { "em_gate_3.ypos", "7" }, { "em_gate_3.frames", "1" }, { "em_gate_4", "RocksSP.png" }, { "em_gate_4.xpos", "3" }, { "em_gate_4.ypos", "7" }, { "em_gate_4.frames", "1" }, { "dc_gate_white", "RocksSP.png" }, { "dc_gate_white.xpos", "14" }, { "dc_gate_white.ypos", "1" }, { "dc_gate_white.frames", "1" }, { "em_gate_1_gray", "RocksSP.png" }, { "em_gate_1_gray.xpos", "4" }, { "em_gate_1_gray.ypos", "7" }, { "em_gate_1_gray.frames", "1" }, { "em_gate_1_gray.EDITOR", "RocksSP.png" }, { "em_gate_1_gray.EDITOR.xpos", "12" }, { "em_gate_1_gray.EDITOR.ypos", "11" }, { "em_gate_1_gray.active", "RocksSP.png" }, { "em_gate_1_gray.active.xpos", "0" }, { "em_gate_1_gray.active.ypos", "7" }, { "em_gate_1_gray.active.frames", "1" }, { "em_gate_2_gray", "RocksSP.png" }, { "em_gate_2_gray.xpos", "5" }, { "em_gate_2_gray.ypos", "7" }, { "em_gate_2_gray.frames", "1" }, { "em_gate_2_gray.EDITOR", "RocksSP.png" }, { "em_gate_2_gray.EDITOR.xpos", "13" }, { "em_gate_2_gray.EDITOR.ypos", "11" }, { "em_gate_2_gray.active", "RocksSP.png" }, { "em_gate_2_gray.active.xpos", "1" }, { "em_gate_2_gray.active.ypos", "7" }, { "em_gate_2_gray.active.frames", "1" }, { "em_gate_3_gray", "RocksSP.png" }, { "em_gate_3_gray.xpos", "6" }, { "em_gate_3_gray.ypos", "7" }, { "em_gate_3_gray.frames", "1" }, { "em_gate_3_gray.EDITOR", "RocksSP.png" }, { "em_gate_3_gray.EDITOR.xpos", "14" }, { "em_gate_3_gray.EDITOR.ypos", "11" }, { "em_gate_3_gray.active", "RocksSP.png" }, { "em_gate_3_gray.active.xpos", "2" }, { "em_gate_3_gray.active.ypos", "7" }, { "em_gate_3_gray.active.frames", "1" }, { "em_gate_4_gray", "RocksSP.png" }, { "em_gate_4_gray.xpos", "7" }, { "em_gate_4_gray.ypos", "7" }, { "em_gate_4_gray.frames", "1" }, { "em_gate_4_gray.EDITOR", "RocksSP.png" }, { "em_gate_4_gray.EDITOR.xpos", "15" }, { "em_gate_4_gray.EDITOR.ypos", "11" }, { "em_gate_4_gray.active", "RocksSP.png" }, { "em_gate_4_gray.active.xpos", "3" }, { "em_gate_4_gray.active.ypos", "7" }, { "em_gate_4_gray.active.frames", "1" }, { "dc_gate_white_gray", "RocksSP.png" }, { "dc_gate_white_gray.xpos", "7" }, { "dc_gate_white_gray.ypos", "7" }, { "dc_gate_white_gray.frames", "1" }, { "dc_gate_white_gray.EDITOR", "RocksSP.png" }, { "dc_gate_white_gray.EDITOR.xpos", "15" }, { "dc_gate_white_gray.EDITOR.ypos", "1" }, { "dc_gate_white_gray.active", "RocksSP.png" }, { "dc_gate_white_gray.active.xpos", "14" }, { "dc_gate_white_gray.active.ypos", "1" }, { "dc_gate_white_gray.active.frames", "1" }, { "dc_gate_fake_gray", "RocksSP.png" }, { "dc_gate_fake_gray.xpos", "7" }, { "dc_gate_fake_gray.ypos", "7" }, { "dc_gate_fake_gray.frames", "1" }, { "exit_closed", "RocksElements.png" }, { "exit_closed.xpos", "0" }, { "exit_closed.ypos", "11" }, { "exit_closed.frames", "1" }, { "exit.opening", "RocksElements.png" }, { "exit.opening.xpos", "0" }, { "exit.opening.ypos", "11" }, { "exit.opening.frames", "5" }, { "exit.opening.delay", "6" }, { "exit.opening.anim_mode", "linear" }, { "exit_open", "RocksElements.png" }, { "exit_open.xpos", "4" }, { "exit_open.ypos", "11" }, { "exit_open.frames", "4" }, { "exit_open.delay", "4" }, { "exit_open.anim_mode", "pingpong" }, { "exit.closing", "RocksElements.png" }, { "exit.closing.xpos", "0" }, { "exit.closing.ypos", "11" }, { "exit.closing.frames", "5" }, { "exit.closing.delay", "6" }, { "exit.closing.anim_mode", "linear,reverse" }, { "steel_exit_closed", "RocksDC2.png" }, { "steel_exit_closed.xpos", "8" }, { "steel_exit_closed.ypos", "0" }, { "steel_exit_closed.frames", "1" }, { "steel_exit.opening", "RocksDC2.png" }, { "steel_exit.opening.xpos", "8" }, { "steel_exit.opening.ypos", "0" }, { "steel_exit.opening.frames", "5" }, { "steel_exit.opening.delay", "6" }, { "steel_exit.opening.anim_mode", "linear" }, { "steel_exit_open", "RocksDC2.png" }, { "steel_exit_open.xpos", "12" }, { "steel_exit_open.ypos", "0" }, { "steel_exit_open.frames", "4" }, { "steel_exit_open.delay", "4" }, { "steel_exit_open.anim_mode", "pingpong" }, { "steel_exit.closing", "RocksDC2.png" }, { "steel_exit.closing.xpos", "8" }, { "steel_exit.closing.ypos", "0" }, { "steel_exit.closing.frames", "5" }, { "steel_exit.closing.delay", "6" }, { "steel_exit.closing.anim_mode", "linear,reverse" }, { "em_exit_closed", "RocksDC2.png" }, { "em_exit_closed.xpos", "0" }, { "em_exit_closed.ypos", "4" }, { "em_exit_closed.frames", "1" }, { "em_exit.opening", "RocksDC2.png" }, { "em_exit.opening.xpos", "0" }, { "em_exit.opening.ypos", "4" }, { "em_exit.opening.frames", "5" }, { "em_exit.opening.delay", "6" }, { "em_exit.opening.anim_mode", "linear" }, { "em_exit_open", "RocksDC2.png" }, { "em_exit_open.xpos", "4" }, { "em_exit_open.ypos", "4" }, { "em_exit_open.frames", "4" }, { "em_exit_open.delay", "4" }, { "em_exit_open.anim_mode", "pingpong" }, { "em_exit.closing", "RocksDC2.png" }, { "em_exit.closing.xpos", "0" }, { "em_exit.closing.ypos", "6" }, { "em_exit.closing.frames", "5" }, { "em_exit.closing.delay", "6" }, { "em_exit.closing.anim_mode", "linear" }, { "em_steel_exit_closed", "RocksDC2.png" }, { "em_steel_exit_closed.xpos", "0" }, { "em_steel_exit_closed.ypos", "5" }, { "em_steel_exit_closed.frames", "1" }, { "em_steel_exit.opening", "RocksDC2.png" }, { "em_steel_exit.opening.xpos", "0" }, { "em_steel_exit.opening.ypos", "5" }, { "em_steel_exit.opening.frames", "5" }, { "em_steel_exit.opening.delay", "6" }, { "em_steel_exit.opening.anim_mode", "linear" }, { "em_steel_exit_open", "RocksDC2.png" }, { "em_steel_exit_open.xpos", "4" }, { "em_steel_exit_open.ypos", "5" }, { "em_steel_exit_open.frames", "4" }, { "em_steel_exit_open.delay", "4" }, { "em_steel_exit_open.anim_mode", "pingpong" }, { "em_steel_exit.closing", "RocksDC2.png" }, { "em_steel_exit.closing.xpos", "0" }, { "em_steel_exit.closing.ypos", "7" }, { "em_steel_exit.closing.frames", "5" }, { "em_steel_exit.closing.delay", "6" }, { "em_steel_exit.closing.anim_mode", "linear" }, /* images for Emerald Mine Club style elements and actions */ { "balloon", "RocksDC.png" }, { "balloon.xpos", "12" }, { "balloon.ypos", "7" }, { "balloon.frames", "1" }, { "balloon.moving", "RocksDC.png" }, { "balloon.moving.xpos", "12" }, { "balloon.moving.ypos", "7" }, { "balloon.moving.frames", "4" }, { "balloon.moving.anim_mode", "pingpong" }, { "balloon.moving.delay", "2" }, { "balloon.pushing", "RocksDC.png" }, { "balloon.pushing.xpos", "12" }, { "balloon.pushing.ypos", "7" }, { "balloon.pushing.frames", "4" }, { "balloon.pushing.anim_mode", "pingpong" }, { "balloon.pushing.delay", "2" }, { "balloon_switch_left", "RocksDC.png" }, { "balloon_switch_left.xpos", "8" }, { "balloon_switch_left.ypos", "7" }, { "balloon_switch_left.frames", "1" }, { "balloon_switch_right", "RocksDC.png" }, { "balloon_switch_right.xpos", "9" }, { "balloon_switch_right.ypos", "7" }, { "balloon_switch_right.frames", "1" }, { "balloon_switch_up", "RocksDC.png" }, { "balloon_switch_up.xpos", "10" }, { "balloon_switch_up.ypos", "7" }, { "balloon_switch_up.frames", "1" }, { "balloon_switch_down", "RocksDC.png" }, { "balloon_switch_down.xpos", "11" }, { "balloon_switch_down.ypos", "7" }, { "balloon_switch_down.frames", "1" }, { "balloon_switch_any", "RocksDC.png" }, { "balloon_switch_any.xpos", "15" }, { "balloon_switch_any.ypos", "0" }, { "balloon_switch_any.frames", "1" }, { "balloon_switch_none", "RocksDC.png" }, { "balloon_switch_none.xpos", "13" }, { "balloon_switch_none.ypos", "5" }, { "balloon_switch_none.frames", "1" }, { "spring", "RocksDC.png" }, { "spring.xpos", "8" }, { "spring.ypos", "13" }, { "spring.frames", "1" }, { "emc_steelwall_1", "RocksDC.png" }, { "emc_steelwall_1.xpos", "14" }, { "emc_steelwall_1.ypos", "0" }, { "emc_steelwall_1.frames", "1" }, { "emc_steelwall_2", "RocksEMC.png" }, { "emc_steelwall_2.xpos", "9" }, { "emc_steelwall_2.ypos", "8" }, { "emc_steelwall_2.frames", "1" }, { "emc_steelwall_3", "RocksEMC.png" }, { "emc_steelwall_3.xpos", "9" }, { "emc_steelwall_3.ypos", "9" }, { "emc_steelwall_3.frames", "1" }, { "emc_steelwall_4", "RocksEMC.png" }, { "emc_steelwall_4.xpos", "9" }, { "emc_steelwall_4.ypos", "10" }, { "emc_steelwall_4.frames", "1" }, { "emc_wall_1", "RocksDC.png" }, { "emc_wall_1.xpos", "13" }, { "emc_wall_1.ypos", "6" }, { "emc_wall_1.frames", "1" }, { "emc_wall_2", "RocksDC.png" }, { "emc_wall_2.xpos", "14" }, { "emc_wall_2.ypos", "6" }, { "emc_wall_2.frames", "1" }, { "emc_wall_3", "RocksDC.png" }, { "emc_wall_3.xpos", "15" }, { "emc_wall_3.ypos", "6" }, { "emc_wall_3.frames", "1" }, { "emc_wall_4", "RocksDC.png" }, { "emc_wall_4.xpos", "14" }, { "emc_wall_4.ypos", "1" }, { "emc_wall_4.frames", "1" }, { "emc_wall_5", "RocksDC.png" }, { "emc_wall_5.xpos", "15" }, { "emc_wall_5.ypos", "1" }, { "emc_wall_5.frames", "1" }, { "emc_wall_6", "RocksDC.png" }, { "emc_wall_6.xpos", "14" }, { "emc_wall_6.ypos", "2" }, { "emc_wall_6.frames", "1" }, { "emc_wall_7", "RocksDC.png" }, { "emc_wall_7.xpos", "15" }, { "emc_wall_7.ypos", "2" }, { "emc_wall_7.frames", "1" }, { "emc_wall_8", "RocksEMC.png" }, { "emc_wall_8.xpos", "8" }, { "emc_wall_8.ypos", "7" }, { "emc_wall_8.frames", "1" }, /* images for Diamond Caves style elements and actions */ { "invisible_steelwall", "RocksSP.png" }, { "invisible_steelwall.xpos", "3" }, { "invisible_steelwall.ypos", "5" }, { "invisible_steelwall.frames", "1" }, { "invisible_steelwall.EDITOR", "RocksSP.png" }, { "invisible_steelwall.EDITOR.xpos", "1" }, { "invisible_steelwall.EDITOR.ypos", "5" }, { "invisible_steelwall.active", "RocksSP.png" }, { "invisible_steelwall.active.xpos", "1" }, { "invisible_steelwall.active.ypos", "5" }, { "invisible_steelwall.active.frames", "1" }, { "invisible_wall", "RocksSP.png" }, { "invisible_wall.xpos", "7" }, { "invisible_wall.ypos", "5" }, { "invisible_wall.frames", "1" }, { "invisible_wall.EDITOR", "RocksSP.png" }, { "invisible_wall.EDITOR.xpos", "5" }, { "invisible_wall.EDITOR.ypos", "5" }, { "invisible_wall.active", "RocksSP.png" }, { "invisible_wall.active.xpos", "5" }, { "invisible_wall.active.ypos", "5" }, { "invisible_wall.active.frames", "1" }, { "invisible_sand", "RocksSP.png" }, { "invisible_sand.xpos", "0" }, { "invisible_sand.ypos", "0" }, { "invisible_sand.frames", "1" }, { "invisible_sand.EDITOR", "RocksEMC.png" }, { "invisible_sand.EDITOR.xpos", "2" }, { "invisible_sand.EDITOR.ypos", "4" }, { "invisible_sand.active", "RocksEMC.png" }, { "invisible_sand.active.xpos", "2" }, { "invisible_sand.active.ypos", "4" }, { "invisible_sand.active.frames", "1" }, { "invisible_sand.active.CRUMBLED", "RocksEMC.png" }, { "invisible_sand.active.CRUMBLED.xpos", "3" }, { "invisible_sand.active.CRUMBLED.ypos", "4" }, { "invisible_sand.active.CRUMBLED.frames", "1" }, { "invisible_sand.active.digging.left", "RocksEMC.png" }, { "invisible_sand.active.digging.left.xpos", "6" }, { "invisible_sand.active.digging.left.ypos", "2" }, { "invisible_sand.active.digging.left.frames","3" }, { "invisible_sand.active.digging.left.delay", "2" }, { "invisible_sand.active.digging.left.anim_mode","linear" }, { "invisible_sand.active.digging.right", "RocksEMC.png" }, { "invisible_sand.active.digging.right.xpos", "9" }, { "invisible_sand.active.digging.right.ypos", "2" }, { "invisible_sand.active.digging.right.frames","3" }, { "invisible_sand.active.digging.right.delay","2" }, { "invisible_sand.active.digging.right.anim_mode","linear" }, { "invisible_sand.active.digging.up", "RocksEMC.png" }, { "invisible_sand.active.digging.up.xpos", "0" }, { "invisible_sand.active.digging.up.ypos", "2" }, { "invisible_sand.active.digging.up.frames", "3" }, { "invisible_sand.active.digging.up.delay", "2" }, { "invisible_sand.active.digging.up.anim_mode","linear" }, { "invisible_sand.active.digging.down", "RocksEMC.png" }, { "invisible_sand.active.digging.down.xpos", "3" }, { "invisible_sand.active.digging.down.ypos", "2" }, { "invisible_sand.active.digging.down.frames","3" }, { "invisible_sand.active.digging.down.delay", "2" }, { "invisible_sand.active.digging.down.anim_mode","linear" }, { "invisible_sand.active.digging.left.CRUMBLED", "RocksEMC.png" }, { "invisible_sand.active.digging.left.CRUMBLED.xpos", "6" }, { "invisible_sand.active.digging.left.CRUMBLED.ypos", "3" }, { "invisible_sand.active.digging.left.CRUMBLED.frames","3" }, { "invisible_sand.active.digging.left.CRUMBLED.delay","2" }, { "invisible_sand.active.digging.left.CRUMBLED.anim_mode","linear" }, { "invisible_sand.active.digging.right.CRUMBLED", "RocksEMC.png" }, { "invisible_sand.active.digging.right.CRUMBLED.xpos","9" }, { "invisible_sand.active.digging.right.CRUMBLED.ypos","3" }, { "invisible_sand.active.digging.right.CRUMBLED.frames","3" }, { "invisible_sand.active.digging.right.CRUMBLED.delay","2" }, { "invisible_sand.active.digging.right.CRUMBLED.anim_mode","linear" }, { "invisible_sand.active.digging.up.CRUMBLED", "RocksEMC.png" }, { "invisible_sand.active.digging.up.CRUMBLED.xpos", "0" }, { "invisible_sand.active.digging.up.CRUMBLED.ypos", "3" }, { "invisible_sand.active.digging.up.CRUMBLED.frames", "3" }, { "invisible_sand.active.digging.up.CRUMBLED.delay", "2" }, { "invisible_sand.active.digging.up.CRUMBLED.anim_mode","linear" }, { "invisible_sand.active.digging.down.CRUMBLED", "RocksEMC.png" }, { "invisible_sand.active.digging.down.CRUMBLED.xpos", "3" }, { "invisible_sand.active.digging.down.CRUMBLED.ypos", "3" }, { "invisible_sand.active.digging.down.CRUMBLED.frames","3" }, { "invisible_sand.active.digging.down.CRUMBLED.delay","2" }, { "invisible_sand.active.digging.down.CRUMBLED.anim_mode","linear" }, { "conveyor_belt_1_middle", "RocksDC.png" }, { "conveyor_belt_1_middle.xpos", "0" }, { "conveyor_belt_1_middle.ypos", "0" }, { "conveyor_belt_1_middle.frames", "1" }, { "conveyor_belt_1_middle.active", "RocksDC.png" }, { "conveyor_belt_1_middle.active.xpos", "0" }, { "conveyor_belt_1_middle.active.ypos", "0" }, { "conveyor_belt_1_middle.active.frames", "8" }, { "conveyor_belt_1_middle.active.delay", "2" }, { "conveyor_belt_1_left", "RocksDC.png" }, { "conveyor_belt_1_left.xpos", "0" }, { "conveyor_belt_1_left.ypos", "1" }, { "conveyor_belt_1_left.frames", "1" }, { "conveyor_belt_1_left.active", "RocksDC.png" }, { "conveyor_belt_1_left.active.xpos", "0" }, { "conveyor_belt_1_left.active.ypos", "1" }, { "conveyor_belt_1_left.active.frames", "8" }, { "conveyor_belt_1_left.active.delay", "2" }, { "conveyor_belt_1_right", "RocksDC.png" }, { "conveyor_belt_1_right.xpos", "0" }, { "conveyor_belt_1_right.ypos", "2" }, { "conveyor_belt_1_right.frames", "1" }, { "conveyor_belt_1_right.active", "RocksDC.png" }, { "conveyor_belt_1_right.active.xpos", "0" }, { "conveyor_belt_1_right.active.ypos", "2" }, { "conveyor_belt_1_right.active.frames", "8" }, { "conveyor_belt_1_right.active.delay", "2" }, { "conveyor_belt_1_switch_left", "RocksDC.png" }, { "conveyor_belt_1_switch_left.xpos", "0" }, { "conveyor_belt_1_switch_left.ypos", "12" }, { "conveyor_belt_1_switch_left.frames", "1" }, { "conveyor_belt_1_switch_middle", "RocksDC.png" }, { "conveyor_belt_1_switch_middle.xpos", "0" }, { "conveyor_belt_1_switch_middle.ypos", "13" }, { "conveyor_belt_1_switch_middle.frames", "1" }, { "conveyor_belt_1_switch_right", "RocksDC.png" }, { "conveyor_belt_1_switch_right.xpos", "0" }, { "conveyor_belt_1_switch_right.ypos", "14" }, { "conveyor_belt_1_switch_right.frames", "1" }, { "conveyor_belt_2_middle", "RocksDC.png" }, { "conveyor_belt_2_middle.xpos", "0" }, { "conveyor_belt_2_middle.ypos", "3" }, { "conveyor_belt_2_middle.frames", "1" }, { "conveyor_belt_2_middle.active", "RocksDC.png" }, { "conveyor_belt_2_middle.active.xpos", "0" }, { "conveyor_belt_2_middle.active.ypos", "3" }, { "conveyor_belt_2_middle.active.frames", "8" }, { "conveyor_belt_2_middle.active.delay", "2" }, { "conveyor_belt_2_left", "RocksDC.png" }, { "conveyor_belt_2_left.xpos", "0" }, { "conveyor_belt_2_left.ypos", "4" }, { "conveyor_belt_2_left.frames", "1" }, { "conveyor_belt_2_left.active", "RocksDC.png" }, { "conveyor_belt_2_left.active.xpos", "0" }, { "conveyor_belt_2_left.active.ypos", "4" }, { "conveyor_belt_2_left.active.frames", "8" }, { "conveyor_belt_2_left.active.delay", "2" }, { "conveyor_belt_2_right", "RocksDC.png" }, { "conveyor_belt_2_right.xpos", "0" }, { "conveyor_belt_2_right.ypos", "5" }, { "conveyor_belt_2_right.frames", "1" }, { "conveyor_belt_2_right.active", "RocksDC.png" }, { "conveyor_belt_2_right.active.xpos", "0" }, { "conveyor_belt_2_right.active.ypos", "5" }, { "conveyor_belt_2_right.active.frames", "8" }, { "conveyor_belt_2_right.active.delay", "2" }, { "conveyor_belt_2_switch_left", "RocksDC.png" }, { "conveyor_belt_2_switch_left.xpos", "1" }, { "conveyor_belt_2_switch_left.ypos", "12" }, { "conveyor_belt_2_switch_left.frames", "1" }, { "conveyor_belt_2_switch_middle", "RocksDC.png" }, { "conveyor_belt_2_switch_middle.xpos", "1" }, { "conveyor_belt_2_switch_middle.ypos", "13" }, { "conveyor_belt_2_switch_middle.frames", "1" }, { "conveyor_belt_2_switch_right", "RocksDC.png" }, { "conveyor_belt_2_switch_right.xpos", "1" }, { "conveyor_belt_2_switch_right.ypos", "14" }, { "conveyor_belt_2_switch_right.frames", "1" }, { "conveyor_belt_3_middle", "RocksDC.png" }, { "conveyor_belt_3_middle.xpos", "0" }, { "conveyor_belt_3_middle.ypos", "6" }, { "conveyor_belt_3_middle.frames", "1" }, { "conveyor_belt_3_middle.active", "RocksDC.png" }, { "conveyor_belt_3_middle.active.xpos", "0" }, { "conveyor_belt_3_middle.active.ypos", "6" }, { "conveyor_belt_3_middle.active.frames", "8" }, { "conveyor_belt_3_middle.active.delay", "2" }, { "conveyor_belt_3_left", "RocksDC.png" }, { "conveyor_belt_3_left.xpos", "0" }, { "conveyor_belt_3_left.ypos", "7" }, { "conveyor_belt_3_left.frames", "1" }, { "conveyor_belt_3_left.active", "RocksDC.png" }, { "conveyor_belt_3_left.active.xpos", "0" }, { "conveyor_belt_3_left.active.ypos", "7" }, { "conveyor_belt_3_left.active.frames", "8" }, { "conveyor_belt_3_left.active.delay", "2" }, { "conveyor_belt_3_right", "RocksDC.png" }, { "conveyor_belt_3_right.xpos", "0" }, { "conveyor_belt_3_right.ypos", "8" }, { "conveyor_belt_3_right.frames", "1" }, { "conveyor_belt_3_right.active", "RocksDC.png" }, { "conveyor_belt_3_right.active.xpos", "0" }, { "conveyor_belt_3_right.active.ypos", "8" }, { "conveyor_belt_3_right.active.frames", "8" }, { "conveyor_belt_3_right.active.delay", "2" }, { "conveyor_belt_3_switch_left", "RocksDC.png" }, { "conveyor_belt_3_switch_left.xpos", "2" }, { "conveyor_belt_3_switch_left.ypos", "12" }, { "conveyor_belt_3_switch_left.frames", "1" }, { "conveyor_belt_3_switch_middle", "RocksDC.png" }, { "conveyor_belt_3_switch_middle.xpos", "2" }, { "conveyor_belt_3_switch_middle.ypos", "13" }, { "conveyor_belt_3_switch_middle.frames", "1" }, { "conveyor_belt_3_switch_right", "RocksDC.png" }, { "conveyor_belt_3_switch_right.xpos", "2" }, { "conveyor_belt_3_switch_right.ypos", "14" }, { "conveyor_belt_3_switch_right.frames", "1" }, { "conveyor_belt_4_middle", "RocksDC.png" }, { "conveyor_belt_4_middle.xpos", "0" }, { "conveyor_belt_4_middle.ypos", "9" }, { "conveyor_belt_4_middle.frames", "1" }, { "conveyor_belt_4_middle.active", "RocksDC.png" }, { "conveyor_belt_4_middle.active.xpos", "0" }, { "conveyor_belt_4_middle.active.ypos", "9" }, { "conveyor_belt_4_middle.active.frames", "8" }, { "conveyor_belt_4_middle.active.delay", "2" }, { "conveyor_belt_4_left", "RocksDC.png" }, { "conveyor_belt_4_left.xpos", "0" }, { "conveyor_belt_4_left.ypos", "10" }, { "conveyor_belt_4_left.frames", "1" }, { "conveyor_belt_4_left.active", "RocksDC.png" }, { "conveyor_belt_4_left.active.xpos", "0" }, { "conveyor_belt_4_left.active.ypos", "10" }, { "conveyor_belt_4_left.active.frames", "8" }, { "conveyor_belt_4_left.active.delay", "2" }, { "conveyor_belt_4_right", "RocksDC.png" }, { "conveyor_belt_4_right.xpos", "0" }, { "conveyor_belt_4_right.ypos", "11" }, { "conveyor_belt_4_right.frames", "1" }, { "conveyor_belt_4_right.active", "RocksDC.png" }, { "conveyor_belt_4_right.active.xpos", "0" }, { "conveyor_belt_4_right.active.ypos", "11" }, { "conveyor_belt_4_right.active.frames", "8" }, { "conveyor_belt_4_right.active.delay", "2" }, { "conveyor_belt_4_switch_left", "RocksDC.png" }, { "conveyor_belt_4_switch_left.xpos", "3" }, { "conveyor_belt_4_switch_left.ypos", "12" }, { "conveyor_belt_4_switch_left.frames", "1" }, { "conveyor_belt_4_switch_middle", "RocksDC.png" }, { "conveyor_belt_4_switch_middle.xpos", "3" }, { "conveyor_belt_4_switch_middle.ypos", "13" }, { "conveyor_belt_4_switch_middle.frames", "1" }, { "conveyor_belt_4_switch_right", "RocksDC.png" }, { "conveyor_belt_4_switch_right.xpos", "3" }, { "conveyor_belt_4_switch_right.ypos", "14" }, { "conveyor_belt_4_switch_right.frames", "1" }, { "switchgate_switch_up", "RocksDC.png" }, { "switchgate_switch_up.xpos", "4" }, { "switchgate_switch_up.ypos", "12" }, { "switchgate_switch_up.frames", "1" }, { "switchgate_switch_down", "RocksDC.png" }, { "switchgate_switch_down.xpos", "5" }, { "switchgate_switch_down.ypos", "12" }, { "switchgate_switch_down.frames", "1" }, { "dc_switchgate_switch_up", "RocksDC2.png" }, { "dc_switchgate_switch_up.xpos", "10" }, { "dc_switchgate_switch_up.ypos", "1" }, { "dc_switchgate_switch_up.frames", "1" }, { "dc_switchgate_switch_down", "RocksDC2.png" }, { "dc_switchgate_switch_down.xpos", "11" }, { "dc_switchgate_switch_down.ypos", "1" }, { "dc_switchgate_switch_down.frames", "1" }, { "light_switch", "RocksDC.png" }, { "light_switch.xpos", "6" }, { "light_switch.ypos", "12" }, { "light_switch.frames", "1" }, { "light_switch.active", "RocksDC.png" }, { "light_switch.active.xpos", "7" }, { "light_switch.active.ypos", "12" }, { "light_switch.active.frames", "1" }, { "timegate_switch", "RocksDC.png" }, { "timegate_switch.xpos", "0" }, { "timegate_switch.ypos", "15" }, { "timegate_switch.frames", "1" }, { "timegate_switch.active", "RocksDC.png" }, { "timegate_switch.active.xpos", "0" }, { "timegate_switch.active.ypos", "15" }, { "timegate_switch.active.frames", "4" }, { "dc_timegate_switch", "RocksDC2.png" }, { "dc_timegate_switch.xpos", "12" }, { "dc_timegate_switch.ypos", "1" }, { "dc_timegate_switch.frames", "1" }, { "dc_timegate_switch.active", "RocksDC2.png" }, { "dc_timegate_switch.active.xpos", "12" }, { "dc_timegate_switch.active.ypos", "1" }, { "dc_timegate_switch.active.frames", "4" }, { "envelope_1", "RocksMore.png" }, { "envelope_1.xpos", "0" }, { "envelope_1.ypos", "4" }, { "envelope_1.frames", "1" }, { "envelope_1.collecting", "RocksMore.png" }, { "envelope_1.collecting.xpos", "5" }, { "envelope_1.collecting.ypos", "4" }, { "envelope_1.collecting.frames", "3" }, { "envelope_1.collecting.delay", "2" }, { "envelope_1.collecting.anim_mode", "linear" }, { "envelope_2", "RocksMore.png" }, { "envelope_2.xpos", "1" }, { "envelope_2.ypos", "4" }, { "envelope_2.frames", "1" }, { "envelope_2.collecting", "RocksMore.png" }, { "envelope_2.collecting.xpos", "5" }, { "envelope_2.collecting.ypos", "4" }, { "envelope_2.collecting.frames", "3" }, { "envelope_2.collecting.delay", "2" }, { "envelope_2.collecting.anim_mode", "linear" }, { "envelope_3", "RocksMore.png" }, { "envelope_3.xpos", "2" }, { "envelope_3.ypos", "4" }, { "envelope_3.frames", "1" }, { "envelope_3.collecting", "RocksMore.png" }, { "envelope_3.collecting.xpos", "5" }, { "envelope_3.collecting.ypos", "4" }, { "envelope_3.collecting.frames", "3" }, { "envelope_3.collecting.delay", "2" }, { "envelope_3.collecting.anim_mode", "linear" }, { "envelope_4", "RocksMore.png" }, { "envelope_4.xpos", "3" }, { "envelope_4.ypos", "4" }, { "envelope_4.frames", "1" }, { "envelope_4.collecting", "RocksMore.png" }, { "envelope_4.collecting.xpos", "5" }, { "envelope_4.collecting.ypos", "4" }, { "envelope_4.collecting.frames", "3" }, { "envelope_4.collecting.delay", "2" }, { "envelope_4.collecting.anim_mode", "linear" }, { "sign_radioactivity", "RocksDC.png" }, { "sign_radioactivity.xpos", "4" }, { "sign_radioactivity.ypos", "13" }, { "sign_radioactivity.frames", "1" }, { "sign_give_way", "RocksDC.png" }, { "sign_give_way.xpos", "5" }, { "sign_give_way.ypos", "13" }, { "sign_give_way.frames", "1" }, { "sign_no_entry", "RocksDC.png" }, { "sign_no_entry.xpos", "6" }, { "sign_no_entry.ypos", "13" }, { "sign_no_entry.frames", "1" }, { "sign_emergency_exit", "RocksDC.png" }, { "sign_emergency_exit.xpos", "7" }, { "sign_emergency_exit.ypos", "13" }, { "sign_emergency_exit.frames", "1" }, { "sign_yin_yang", "RocksDC.png" }, { "sign_yin_yang.xpos", "4" }, { "sign_yin_yang.ypos", "14" }, { "sign_yin_yang.frames", "1" }, { "sign_exclamation", "RocksDC.png" }, { "sign_exclamation.xpos", "5" }, { "sign_exclamation.ypos", "14" }, { "sign_exclamation.frames", "1" }, { "sign_stop", "RocksDC.png" }, { "sign_stop.xpos", "6" }, { "sign_stop.ypos", "14" }, { "sign_stop.frames", "1" }, { "sign_parking", "RocksDC.png" }, { "sign_parking.xpos", "6" }, { "sign_parking.ypos", "15" }, { "sign_parking.frames", "1" }, { "sign_wheelchair", "RocksDC.png" }, { "sign_wheelchair.xpos", "7" }, { "sign_wheelchair.ypos", "15" }, { "sign_wheelchair.frames", "1" }, { "sign_entry_forbidden", "RocksDC.png" }, { "sign_entry_forbidden.xpos", "12" }, { "sign_entry_forbidden.ypos", "15" }, { "sign_entry_forbidden.frames", "1" }, { "sperms", "RocksDC2.png" }, { "sperms.xpos", "11" }, { "sperms.ypos", "3" }, { "sperms.frames", "1" }, { "bullet", "RocksDC2.png" }, { "bullet.xpos", "12" }, { "bullet.ypos", "3" }, { "bullet.frames", "1" }, { "heart", "RocksDC2.png" }, { "heart.xpos", "13" }, { "heart.ypos", "3" }, { "heart.frames", "1" }, { "cross", "RocksDC2.png" }, { "cross.xpos", "14" }, { "cross.ypos", "3" }, { "cross.frames", "1" }, { "frankie", "RocksDC2.png" }, { "frankie.xpos", "15" }, { "frankie.ypos", "3" }, { "frankie.frames", "1" }, { "sign_sperms", "RocksDC2.png" }, { "sign_sperms.xpos", "11" }, { "sign_sperms.ypos", "2" }, { "sign_sperms.frames", "1" }, { "sign_bullet", "RocksDC2.png" }, { "sign_bullet.xpos", "12" }, { "sign_bullet.ypos", "2" }, { "sign_bullet.frames", "1" }, { "sign_heart", "RocksDC2.png" }, { "sign_heart.xpos", "13" }, { "sign_heart.ypos", "2" }, { "sign_heart.frames", "1" }, { "sign_cross", "RocksDC2.png" }, { "sign_cross.xpos", "14" }, { "sign_cross.ypos", "2" }, { "sign_cross.frames", "1" }, { "sign_frankie", "RocksDC2.png" }, { "sign_frankie.xpos", "15" }, { "sign_frankie.ypos", "2" }, { "sign_frankie.frames", "1" }, { "landmine", "RocksDC.png" }, { "landmine.xpos", "7" }, { "landmine.ypos", "14" }, { "landmine.frames", "1" }, { "landmine.crumbled_like", "sand" }, { "dc_landmine", "RocksDC.png" }, { "dc_landmine.xpos", "14" }, { "dc_landmine.ypos", "5" }, { "dc_landmine.frames", "1" }, { "dc_landmine.crumbled_like", "sand" }, { "steelwall_slippery", "RocksDC.png" }, { "steelwall_slippery.xpos", "5" }, { "steelwall_slippery.ypos", "15" }, { "steelwall_slippery.frames", "1" }, { "extra_time", "RocksDC.png" }, { "extra_time.xpos", "8" }, { "extra_time.ypos", "0" }, { "extra_time.frames", "6" }, { "extra_time.delay", "4" }, { "shield_normal", "RocksDC.png" }, { "shield_normal.xpos", "8" }, { "shield_normal.ypos", "2" }, { "shield_normal.frames", "6" }, { "shield_normal.delay", "4" }, { "shield_normal.active", "RocksHeroes.png" }, { "shield_normal.active.xpos", "1" }, { "shield_normal.active.ypos", "13" }, { "shield_normal.active.frames", "3" }, { "shield_normal.active.delay", "8" }, { "shield_normal.active.anim_mode", "pingpong" }, { "shield_deadly", "RocksDC.png" }, { "shield_deadly.xpos", "8" }, { "shield_deadly.ypos", "1" }, { "shield_deadly.frames", "6" }, { "shield_deadly.delay", "4" }, { "shield_deadly.active", "RocksHeroes.png" }, { "shield_deadly.active.xpos", "5" }, { "shield_deadly.active.ypos", "13" }, { "shield_deadly.active.frames", "3" }, { "shield_deadly.active.delay", "8" }, { "shield_deadly.active.anim_mode", "pingpong" }, { "switchgate_closed", "RocksDC.png" }, { "switchgate_closed.xpos", "8" }, { "switchgate_closed.ypos", "5" }, { "switchgate_closed.frames", "1" }, { "switchgate.opening", "RocksDC.png" }, { "switchgate.opening.xpos", "8" }, { "switchgate.opening.ypos", "5" }, { "switchgate.opening.frames", "5" }, { "switchgate.opening.delay", "6" }, { "switchgate_open", "RocksDC.png" }, { "switchgate_open.xpos", "12" }, { "switchgate_open.ypos", "5" }, { "switchgate_open.frames", "1" }, { "switchgate.closing", "RocksDC.png" }, { "switchgate.closing.xpos", "8" }, { "switchgate.closing.ypos", "5" }, { "switchgate.closing.frames", "5" }, { "switchgate.closing.delay", "6" }, { "switchgate.closing.anim_mode", "reverse" }, { "timegate_closed", "RocksDC.png" }, { "timegate_closed.xpos", "8" }, { "timegate_closed.ypos", "6" }, { "timegate_closed.frames", "1" }, { "timegate.opening", "RocksDC.png" }, { "timegate.opening.xpos", "8" }, { "timegate.opening.ypos", "6" }, { "timegate.opening.frames", "5" }, { "timegate.opening.delay", "6" }, { "timegate_open", "RocksDC.png" }, { "timegate_open.xpos", "12" }, { "timegate_open.ypos", "6" }, { "timegate_open.frames", "1" }, { "timegate.closing", "RocksDC.png" }, { "timegate.closing.xpos", "8" }, { "timegate.closing.ypos", "6" }, { "timegate.closing.frames", "5" }, { "timegate.closing.delay", "6" }, { "timegate.closing.anim_mode", "reverse" }, { "pearl", "RocksDC.png" }, { "pearl.xpos", "8" }, { "pearl.ypos", "11" }, { "pearl.frames", "1" }, { "pearl.breaking", "RocksDC.png" }, { "pearl.breaking.xpos", "8" }, { "pearl.breaking.ypos", "12" }, { "pearl.breaking.frames", "4" }, { "pearl.breaking.delay", "2" }, { "pearl.breaking.anim_mode", "linear" }, { "crystal", "RocksDC.png" }, { "crystal.xpos", "9" }, { "crystal.ypos", "11" }, { "crystal.frames", "1" }, { "wall_pearl", "RocksDC.png" }, { "wall_pearl.xpos", "10" }, { "wall_pearl.ypos", "11" }, { "wall_pearl.frames", "1" }, { "wall_crystal", "RocksDC.png" }, { "wall_crystal.xpos", "11" }, { "wall_crystal.ypos", "11" }, { "wall_crystal.frames", "1" }, { "dc_steelwall_1_left", "RocksDC2.png" }, { "dc_steelwall_1_left.xpos", "5" }, { "dc_steelwall_1_left.ypos", "1" }, { "dc_steelwall_1_left.frames", "1" }, { "dc_steelwall_1_right", "RocksDC2.png" }, { "dc_steelwall_1_right.xpos", "3" }, { "dc_steelwall_1_right.ypos", "1" }, { "dc_steelwall_1_right.frames", "1" }, { "dc_steelwall_1_top", "RocksDC2.png" }, { "dc_steelwall_1_top.xpos", "4" }, { "dc_steelwall_1_top.ypos", "2" }, { "dc_steelwall_1_top.frames", "1" }, { "dc_steelwall_1_bottom", "RocksDC2.png" }, { "dc_steelwall_1_bottom.xpos", "4" }, { "dc_steelwall_1_bottom.ypos", "0" }, { "dc_steelwall_1_bottom.frames", "1" }, { "dc_steelwall_1_horizontal", "RocksDC2.png" }, { "dc_steelwall_1_horizontal.xpos", "1" }, { "dc_steelwall_1_horizontal.ypos", "0" }, { "dc_steelwall_1_horizontal.frames", "1" }, { "dc_steelwall_1_vertical", "RocksDC2.png" }, { "dc_steelwall_1_vertical.xpos", "0" }, { "dc_steelwall_1_vertical.ypos", "1" }, { "dc_steelwall_1_vertical.frames", "1" }, { "dc_steelwall_1_topleft", "RocksDC2.png" }, { "dc_steelwall_1_topleft.xpos", "0" }, { "dc_steelwall_1_topleft.ypos", "0" }, { "dc_steelwall_1_topleft.frames", "1" }, { "dc_steelwall_1_topright", "RocksDC2.png" }, { "dc_steelwall_1_topright.xpos", "2" }, { "dc_steelwall_1_topright.ypos", "0" }, { "dc_steelwall_1_topright.frames", "1" }, { "dc_steelwall_1_bottomleft", "RocksDC2.png" }, { "dc_steelwall_1_bottomleft.xpos", "0" }, { "dc_steelwall_1_bottomleft.ypos", "2" }, { "dc_steelwall_1_bottomleft.frames", "1" }, { "dc_steelwall_1_bottomright", "RocksDC2.png" }, { "dc_steelwall_1_bottomright.xpos", "2" }, { "dc_steelwall_1_bottomright.ypos", "2" }, { "dc_steelwall_1_bottomright.frames", "1" }, { "dc_steelwall_1_topleft_2", "RocksDC2.png" }, { "dc_steelwall_1_topleft_2.xpos", "5" }, { "dc_steelwall_1_topleft_2.ypos", "2" }, { "dc_steelwall_1_topleft_2.frames", "1" }, { "dc_steelwall_1_topright_2", "RocksDC2.png" }, { "dc_steelwall_1_topright_2.xpos", "3" }, { "dc_steelwall_1_topright_2.ypos", "2" }, { "dc_steelwall_1_topright_2.frames", "1" }, { "dc_steelwall_1_bottomleft_2", "RocksDC2.png" }, { "dc_steelwall_1_bottomleft_2.xpos", "5" }, { "dc_steelwall_1_bottomleft_2.ypos", "0" }, { "dc_steelwall_1_bottomleft_2.frames", "1" }, { "dc_steelwall_1_bottomright_2", "RocksDC2.png" }, { "dc_steelwall_1_bottomright_2.xpos", "3" }, { "dc_steelwall_1_bottomright_2.ypos", "0" }, { "dc_steelwall_1_bottomright_2.frames", "1" }, { "dc_steelwall_2_left", "RocksDC2.png" }, { "dc_steelwall_2_left.xpos", "6" }, { "dc_steelwall_2_left.ypos", "1" }, { "dc_steelwall_2_left.frames", "1" }, { "dc_steelwall_2_right", "RocksDC2.png" }, { "dc_steelwall_2_right.xpos", "9" }, { "dc_steelwall_2_right.ypos", "1" }, { "dc_steelwall_2_right.frames", "1" }, { "dc_steelwall_2_top", "RocksDC2.png" }, { "dc_steelwall_2_top.xpos", "7" }, { "dc_steelwall_2_top.ypos", "0" }, { "dc_steelwall_2_top.frames", "1" }, { "dc_steelwall_2_bottom", "RocksDC2.png" }, { "dc_steelwall_2_bottom.xpos", "7" }, { "dc_steelwall_2_bottom.ypos", "3" }, { "dc_steelwall_2_bottom.frames", "1" }, { "dc_steelwall_2_horizontal", "RocksDC2.png" }, { "dc_steelwall_2_horizontal.xpos", "8" }, { "dc_steelwall_2_horizontal.ypos", "1" }, { "dc_steelwall_2_horizontal.frames", "1" }, { "dc_steelwall_2_vertical", "RocksDC2.png" }, { "dc_steelwall_2_vertical.xpos", "7" }, { "dc_steelwall_2_vertical.ypos", "2" }, { "dc_steelwall_2_vertical.frames", "1" }, { "dc_steelwall_2_middle", "RocksDC2.png" }, { "dc_steelwall_2_middle.xpos", "7" }, { "dc_steelwall_2_middle.ypos", "1" }, { "dc_steelwall_2_middle.frames", "1" }, { "dc_steelwall_2_single", "RocksDC2.png" }, { "dc_steelwall_2_single.xpos", "6" }, { "dc_steelwall_2_single.ypos", "0" }, { "dc_steelwall_2_single.frames", "1" }, /* images for DX Boulderdash style elements and actions */ { "tube_right_down", "RocksDC.png" }, { "tube_right_down.xpos", "9" }, { "tube_right_down.ypos", "13" }, { "tube_right_down.frames", "1" }, { "tube_horizontal_down", "RocksDC.png" }, { "tube_horizontal_down.xpos", "10" }, { "tube_horizontal_down.ypos", "13" }, { "tube_horizontal_down.frames", "1" }, { "tube_left_down", "RocksDC.png" }, { "tube_left_down.xpos", "11" }, { "tube_left_down.ypos", "13" }, { "tube_left_down.frames", "1" }, { "tube_horizontal", "RocksDC.png" }, { "tube_horizontal.xpos", "8" }, { "tube_horizontal.ypos", "14" }, { "tube_horizontal.frames", "1" }, { "tube_vertical_right", "RocksDC.png" }, { "tube_vertical_right.xpos", "9" }, { "tube_vertical_right.ypos", "14" }, { "tube_vertical_right.frames", "1" }, { "tube_any", "RocksDC.png" }, { "tube_any.xpos", "10" }, { "tube_any.ypos", "14" }, { "tube_any.frames", "1" }, { "tube_vertical_left", "RocksDC.png" }, { "tube_vertical_left.xpos", "11" }, { "tube_vertical_left.ypos", "14" }, { "tube_vertical_left.frames", "1" }, { "tube_vertical", "RocksDC.png" }, { "tube_vertical.xpos", "8" }, { "tube_vertical.ypos", "15" }, { "tube_vertical.frames", "1" }, { "tube_right_up", "RocksDC.png" }, { "tube_right_up.xpos", "9" }, { "tube_right_up.ypos", "15" }, { "tube_right_up.frames", "1" }, { "tube_horizontal_up", "RocksDC.png" }, { "tube_horizontal_up.xpos", "10" }, { "tube_horizontal_up.ypos", "15" }, { "tube_horizontal_up.frames", "1" }, { "tube_left_up", "RocksDC.png" }, { "tube_left_up.xpos", "11" }, { "tube_left_up.ypos", "15" }, { "tube_left_up.frames", "1" }, { "trap", "RocksDC.png" }, { "trap.xpos", "12" }, { "trap.ypos", "8" }, { "trap.frames", "1" }, { "trap.crumbled_like", "sand" }, { "trap.diggable_like", "sand" }, { "trap.active", "RocksDC.png" }, { "trap.active.xpos", "12" }, { "trap.active.ypos", "8" }, { "trap.active.frames", "4" }, { "trap.active.delay", "4" }, { "trap.active.anim_mode", "pingpong2" }, { "trap.active.crumbled_like", "sand" }, { "dx_supabomb", "RocksDC.png" }, { "dx_supabomb.xpos", "15" }, { "dx_supabomb.ypos", "9" }, { "dx_supabomb.frames", "1" }, /* images for Rocks'n'Diamonds style elements and actions */ { "key_1", "RocksElements.png" }, { "key_1.xpos", "4" }, { "key_1.ypos", "1" }, { "key_1.frames", "1" }, { "key_1.EDITOR", "RocksElements.png" }, { "key_1.EDITOR.xpos", "4" }, { "key_1.EDITOR.ypos", "14" }, { "key_2", "RocksElements.png" }, { "key_2.xpos", "5" }, { "key_2.ypos", "1" }, { "key_2.frames", "1" }, { "key_2.EDITOR", "RocksElements.png" }, { "key_2.EDITOR.xpos", "5" }, { "key_2.EDITOR.ypos", "14" }, { "key_3", "RocksElements.png" }, { "key_3.xpos", "6" }, { "key_3.ypos", "1" }, { "key_3.frames", "1" }, { "key_3.EDITOR", "RocksElements.png" }, { "key_3.EDITOR.xpos", "6" }, { "key_3.EDITOR.ypos", "14" }, { "key_4", "RocksElements.png" }, { "key_4.xpos", "7" }, { "key_4.ypos", "1" }, { "key_4.frames", "1" }, { "key_4.EDITOR", "RocksElements.png" }, { "key_4.EDITOR.xpos", "7" }, { "key_4.EDITOR.ypos", "14" }, { "gate_1", "RocksElements.png" }, { "gate_1.xpos", "4" }, { "gate_1.ypos", "2" }, { "gate_1.frames", "1" }, { "gate_2", "RocksElements.png" }, { "gate_2.xpos", "5" }, { "gate_2.ypos", "2" }, { "gate_2.frames", "1" }, { "gate_3", "RocksElements.png" }, { "gate_3.xpos", "6" }, { "gate_3.ypos", "2" }, { "gate_3.frames", "1" }, { "gate_4", "RocksElements.png" }, { "gate_4.xpos", "7" }, { "gate_4.ypos", "2" }, { "gate_4.frames", "1" }, { "gate_1_gray", "RocksElements.png" }, { "gate_1_gray.xpos", "8" }, { "gate_1_gray.ypos", "2" }, { "gate_1_gray.frames", "1" }, { "gate_1_gray.EDITOR", "RocksElements.png" }, { "gate_1_gray.EDITOR.xpos", "8" }, { "gate_1_gray.EDITOR.ypos", "14" }, { "gate_1_gray.active", "RocksElements.png" }, { "gate_1_gray.active.xpos", "4" }, { "gate_1_gray.active.ypos", "2" }, { "gate_1_gray.active.frames", "1" }, { "gate_2_gray", "RocksElements.png" }, { "gate_2_gray.xpos", "9" }, { "gate_2_gray.ypos", "2" }, { "gate_2_gray.frames", "1" }, { "gate_2_gray.EDITOR", "RocksElements.png" }, { "gate_2_gray.EDITOR.xpos", "9" }, { "gate_2_gray.EDITOR.ypos", "14" }, { "gate_2_gray.active", "RocksElements.png" }, { "gate_2_gray.active.xpos", "5" }, { "gate_2_gray.active.ypos", "2" }, { "gate_2_gray.active.frames", "1" }, { "gate_3_gray", "RocksElements.png" }, { "gate_3_gray.xpos", "10" }, { "gate_3_gray.ypos", "2" }, { "gate_3_gray.frames", "1" }, { "gate_3_gray.EDITOR", "RocksElements.png" }, { "gate_3_gray.EDITOR.xpos", "10" }, { "gate_3_gray.EDITOR.ypos", "14" }, { "gate_3_gray.active", "RocksElements.png" }, { "gate_3_gray.active.xpos", "6" }, { "gate_3_gray.active.ypos", "2" }, { "gate_3_gray.active.frames", "1" }, { "gate_4_gray", "RocksElements.png" }, { "gate_4_gray.xpos", "11" }, { "gate_4_gray.ypos", "2" }, { "gate_4_gray.frames", "1" }, { "gate_4_gray.EDITOR", "RocksElements.png" }, { "gate_4_gray.EDITOR.xpos", "11" }, { "gate_4_gray.EDITOR.ypos", "14" }, { "gate_4_gray.active", "RocksElements.png" }, { "gate_4_gray.active.xpos", "7" }, { "gate_4_gray.active.ypos", "2" }, { "gate_4_gray.active.frames", "1" }, { "game_of_life", "RocksElements.png" }, { "game_of_life.xpos", "8" }, { "game_of_life.ypos", "1" }, { "game_of_life.frames", "1" }, { "biomaze", "RocksElements.png" }, { "biomaze.xpos", "9" }, { "biomaze.ypos", "1" }, { "biomaze.frames", "1" }, { "pacman", "RocksElements.png" }, { "pacman.xpos", "8" }, { "pacman.ypos", "5" }, { "pacman.frames", "1" }, { "pacman.right", "RocksElements.png" }, { "pacman.right.xpos", "8" }, { "pacman.right.ypos", "5" }, { "pacman.right.frames", "2" }, { "pacman.right.delay", "4" }, { "pacman.right.offset", "128" }, { "pacman.up", "RocksElements.png" }, { "pacman.up.xpos", "9" }, { "pacman.up.ypos", "5" }, { "pacman.up.frames", "2" }, { "pacman.up.delay", "4" }, { "pacman.up.offset", "128" }, { "pacman.left", "RocksElements.png" }, { "pacman.left.xpos", "10" }, { "pacman.left.ypos", "5" }, { "pacman.left.frames", "2" }, { "pacman.left.delay", "4" }, { "pacman.left.offset", "128" }, { "pacman.down", "RocksElements.png" }, { "pacman.down.xpos", "11" }, { "pacman.down.ypos", "5" }, { "pacman.down.frames", "2" }, { "pacman.down.delay", "4" }, { "pacman.down.offset", "128" }, { "pacman.turning_from_right", "RocksElements.png" }, { "pacman.turning_from_right.xpos", "12" }, { "pacman.turning_from_right.ypos", "5" }, { "pacman.turning_from_right.frames", "1" }, { "pacman.turning_from_up", "RocksElements.png" }, { "pacman.turning_from_up.xpos", "13" }, { "pacman.turning_from_up.ypos", "5" }, { "pacman.turning_from_up.frames", "1" }, { "pacman.turning_from_left", "RocksElements.png" }, { "pacman.turning_from_left.xpos", "14" }, { "pacman.turning_from_left.ypos", "5" }, { "pacman.turning_from_left.frames", "1" }, { "pacman.turning_from_down", "RocksElements.png" }, { "pacman.turning_from_down.xpos", "15" }, { "pacman.turning_from_down.ypos", "5" }, { "pacman.turning_from_down.frames", "1" }, { "lamp", "RocksElements.png" }, { "lamp.xpos", "0" }, { "lamp.ypos", "7" }, { "lamp.frames", "1" }, { "lamp.EDITOR", "RocksElements.png" }, { "lamp.EDITOR.xpos", "2" }, { "lamp.EDITOR.ypos", "14" }, { "lamp.active", "RocksElements.png" }, { "lamp.active.xpos", "1" }, { "lamp.active.ypos", "7" }, { "lamp.active.frames", "1" }, { "time_orb_full", "RocksElements.png" }, { "time_orb_full.xpos", "2" }, { "time_orb_full.ypos", "7" }, { "time_orb_full.frames", "1" }, { "time_orb_empty", "RocksElements.png" }, { "time_orb_empty.xpos", "3" }, { "time_orb_empty.ypos", "7" }, { "time_orb_empty.frames", "1" }, { "emerald_yellow", "RocksElements.png" }, { "emerald_yellow.xpos", "10" }, { "emerald_yellow.ypos", "8" }, { "emerald_yellow.frames", "1" }, { "emerald_yellow.moving", "RocksElements.png" }, { "emerald_yellow.moving.xpos", "10" }, { "emerald_yellow.moving.ypos", "8" }, { "emerald_yellow.moving.frames", "2" }, { "emerald_yellow.moving.delay", "4" }, { "emerald_yellow.falling", "RocksElements.png" }, { "emerald_yellow.falling.xpos", "10" }, { "emerald_yellow.falling.ypos", "8" }, { "emerald_yellow.falling.frames", "2" }, { "emerald_yellow.falling.delay", "4" }, { "emerald_red", "RocksElements.png" }, { "emerald_red.xpos", "8" }, { "emerald_red.ypos", "9" }, { "emerald_red.frames", "1" }, { "emerald_red.moving", "RocksElements.png" }, { "emerald_red.moving.xpos", "8" }, { "emerald_red.moving.ypos", "9" }, { "emerald_red.moving.frames", "2" }, { "emerald_red.moving.delay", "4" }, { "emerald_red.falling", "RocksElements.png" }, { "emerald_red.falling.xpos", "8" }, { "emerald_red.falling.ypos", "9" }, { "emerald_red.falling.frames", "2" }, { "emerald_red.falling.delay", "4" }, { "emerald_purple", "RocksElements.png" }, { "emerald_purple.xpos", "10" }, { "emerald_purple.ypos", "9" }, { "emerald_purple.frames", "1" }, { "emerald_purple.moving", "RocksElements.png" }, { "emerald_purple.moving.xpos", "10" }, { "emerald_purple.moving.ypos", "9" }, { "emerald_purple.moving.frames", "2" }, { "emerald_purple.moving.delay", "4" }, { "emerald_purple.falling", "RocksElements.png" }, { "emerald_purple.falling.xpos", "10" }, { "emerald_purple.falling.ypos", "9" }, { "emerald_purple.falling.frames", "2" }, { "emerald_purple.falling.delay", "4" }, { "wall_emerald_yellow", "RocksElements.png" }, { "wall_emerald_yellow.xpos", "8" }, { "wall_emerald_yellow.ypos", "8" }, { "wall_emerald_yellow.frames", "1" }, { "wall_emerald_red", "RocksElements.png" }, { "wall_emerald_red.xpos", "6" }, { "wall_emerald_red.ypos", "8" }, { "wall_emerald_red.frames", "1" }, { "wall_emerald_purple", "RocksElements.png" }, { "wall_emerald_purple.xpos", "7" }, { "wall_emerald_purple.ypos", "8" }, { "wall_emerald_purple.frames", "1" }, { "wall_bd_diamond", "RocksElements.png" }, { "wall_bd_diamond.xpos", "9" }, { "wall_bd_diamond.ypos", "8" }, { "wall_bd_diamond.frames", "1" }, { "expandable_wall", "RocksElements.png" }, { "expandable_wall.xpos", "11" }, { "expandable_wall.ypos", "10" }, { "expandable_wall.frames", "1" }, { "expandable_wall_horizontal", "RocksElements.png" }, { "expandable_wall_horizontal.xpos", "5" }, { "expandable_wall_horizontal.ypos", "9" }, { "expandable_wall_horizontal.frames", "1" }, { "expandable_wall_horizontal.EDITOR", "RocksElements.png" }, { "expandable_wall_horizontal.EDITOR.xpos", "13" }, { "expandable_wall_horizontal.EDITOR.ypos", "13" }, { "expandable_wall_vertical", "RocksElements.png" }, { "expandable_wall_vertical.xpos", "6" }, { "expandable_wall_vertical.ypos", "9" }, { "expandable_wall_vertical.frames", "1" }, { "expandable_wall_vertical.EDITOR", "RocksElements.png" }, { "expandable_wall_vertical.EDITOR.xpos", "14" }, { "expandable_wall_vertical.EDITOR.ypos", "13" }, { "expandable_wall_any", "RocksElements.png" }, { "expandable_wall_any.xpos", "4" }, { "expandable_wall_any.ypos", "9" }, { "expandable_wall_any.frames", "1" }, { "expandable_wall_any.EDITOR", "RocksElements.png" }, { "expandable_wall_any.EDITOR.xpos", "12" }, { "expandable_wall_any.EDITOR.ypos", "13" }, { "expandable_steelwall_horizontal", "RocksDC2.png" }, { "expandable_steelwall_horizontal.xpos", "6" }, { "expandable_steelwall_horizontal.ypos", "2" }, { "expandable_steelwall_horizontal.frames", "1" }, { "expandable_steelwall_horizontal.EDITOR", "RocksDC2.png" }, { "expandable_steelwall_horizontal.EDITOR.xpos","9" }, { "expandable_steelwall_horizontal.EDITOR.ypos","2" }, { "expandable_steelwall_vertical", "RocksDC2.png" }, { "expandable_steelwall_vertical.xpos", "6" }, { "expandable_steelwall_vertical.ypos", "2" }, { "expandable_steelwall_vertical.frames", "1" }, { "expandable_steelwall_vertical.EDITOR", "RocksDC2.png" }, { "expandable_steelwall_vertical.EDITOR.xpos","10" }, { "expandable_steelwall_vertical.EDITOR.ypos","2" }, { "expandable_steelwall_any", "RocksDC2.png" }, { "expandable_steelwall_any.xpos", "6" }, { "expandable_steelwall_any.ypos", "2" }, { "expandable_steelwall_any.frames", "1" }, { "expandable_steelwall_any.EDITOR", "RocksDC2.png" }, { "expandable_steelwall_any.EDITOR.xpos", "8" }, { "expandable_steelwall_any.EDITOR.ypos", "2" }, { "bd_expandable_wall", "RocksElements.png" }, { "bd_expandable_wall.xpos", "5" }, { "bd_expandable_wall.ypos", "9" }, { "bd_expandable_wall.frames", "1" }, { "bd_expandable_wall.EDITOR", "RocksDC.png" }, { "bd_expandable_wall.EDITOR.xpos", "15" }, { "bd_expandable_wall.EDITOR.ypos", "15" }, { "expandable_wall.growing.left", "RocksElements.png" }, { "expandable_wall.growing.left.xpos", "8" }, { "expandable_wall.growing.left.ypos", "10" }, { "expandable_wall.growing.left.frames", "3" }, { "expandable_wall.growing.left.delay", "6" }, { "expandable_wall.growing.left.anim_mode", "linear" }, { "expandable_wall.growing.right", "RocksElements.png" }, { "expandable_wall.growing.right.xpos", "5" }, { "expandable_wall.growing.right.ypos", "10" }, { "expandable_wall.growing.right.frames", "3" }, { "expandable_wall.growing.right.delay", "6" }, { "expandable_wall.growing.right.anim_mode", "linear" }, { "expandable_wall.growing.up", "RocksHeroes.png" }, { "expandable_wall.growing.up.xpos", "3" }, { "expandable_wall.growing.up.ypos", "12" }, { "expandable_wall.growing.up.frames", "3" }, { "expandable_wall.growing.up.delay", "6" }, { "expandable_wall.growing.up.anim_mode", "linear" }, { "expandable_wall.growing.down", "RocksHeroes.png" }, { "expandable_wall.growing.down.xpos", "0" }, { "expandable_wall.growing.down.ypos", "12" }, { "expandable_wall.growing.down.frames", "3" }, { "expandable_wall.growing.down.delay", "6" }, { "expandable_wall.growing.down.anim_mode", "linear" }, { "expandable_steelwall.growing.left", "RocksDC2.png" }, { "expandable_steelwall.growing.left.xpos", "8" }, { "expandable_steelwall.growing.left.ypos", "4" }, { "expandable_steelwall.growing.left.frames", "4" }, { "expandable_steelwall.growing.left.delay", "4" }, { "expandable_steelwall.growing.left.anim_mode","linear" }, { "expandable_steelwall.growing.right", "RocksDC2.png" }, { "expandable_steelwall.growing.right.xpos", "12" }, { "expandable_steelwall.growing.right.ypos", "4" }, { "expandable_steelwall.growing.right.frames","4" }, { "expandable_steelwall.growing.right.delay", "4" }, { "expandable_steelwall.growing.right.anim_mode","linear" }, { "expandable_steelwall.growing.up", "RocksDC2.png" }, { "expandable_steelwall.growing.up.xpos", "8" }, { "expandable_steelwall.growing.up.ypos", "5" }, { "expandable_steelwall.growing.up.frames", "4" }, { "expandable_steelwall.growing.up.delay", "4" }, { "expandable_steelwall.growing.up.anim_mode","linear" }, { "expandable_steelwall.growing.down", "RocksDC2.png" }, { "expandable_steelwall.growing.down.xpos", "12" }, { "expandable_steelwall.growing.down.ypos", "5" }, { "expandable_steelwall.growing.down.frames", "4" }, { "expandable_steelwall.growing.down.delay", "4" }, { "expandable_steelwall.growing.down.anim_mode","linear" }, { "black_orb", "RocksElements.png" }, { "black_orb.xpos", "13" }, { "black_orb.ypos", "9" }, { "black_orb.frames", "1" }, { "speed_pill", "RocksElements.png" }, { "speed_pill.xpos", "14" }, { "speed_pill.ypos", "9" }, { "speed_pill.frames", "1" }, { "dark_yamyam", "RocksElements.png" }, { "dark_yamyam.xpos", "8" }, { "dark_yamyam.ypos", "11" }, { "dark_yamyam.frames", "4" }, { "dark_yamyam.anim_mode", "pingpong2" }, { "dynabomb", "RocksElements.png" }, { "dynabomb.xpos", "12" }, { "dynabomb.ypos", "11" }, { "dynabomb.frames", "1" }, { "dynabomb.active", "RocksElements.png" }, { "dynabomb.active.xpos", "12" }, { "dynabomb.active.ypos", "11" }, { "dynabomb.active.frames", "4" }, { "dynabomb.active.delay", "6" }, { "dynabomb.active.anim_mode", "pingpong" }, { "dynabomb_player_1", "RocksElements.png" }, { "dynabomb_player_1.xpos", "12" }, { "dynabomb_player_1.ypos", "11" }, { "dynabomb_player_1.frames", "1" }, { "dynabomb_player_1.active", "RocksElements.png" }, { "dynabomb_player_1.active.xpos", "12" }, { "dynabomb_player_1.active.ypos", "11" }, { "dynabomb_player_1.active.frames", "4" }, { "dynabomb_player_1.active.delay", "6" }, { "dynabomb_player_1.active.anim_mode", "pingpong" }, { "dynabomb_player_2", "RocksElements.png" }, { "dynabomb_player_2.xpos", "12" }, { "dynabomb_player_2.ypos", "11" }, { "dynabomb_player_2.frames", "1" }, { "dynabomb_player_2.active", "RocksElements.png" }, { "dynabomb_player_2.active.xpos", "12" }, { "dynabomb_player_2.active.ypos", "11" }, { "dynabomb_player_2.active.frames", "4" }, { "dynabomb_player_2.active.delay", "6" }, { "dynabomb_player_2.active.anim_mode", "pingpong" }, { "dynabomb_player_3", "RocksElements.png" }, { "dynabomb_player_3.xpos", "12" }, { "dynabomb_player_3.ypos", "11" }, { "dynabomb_player_3.frames", "1" }, { "dynabomb_player_3.active", "RocksElements.png" }, { "dynabomb_player_3.active.xpos", "12" }, { "dynabomb_player_3.active.ypos", "11" }, { "dynabomb_player_3.active.frames", "4" }, { "dynabomb_player_3.active.delay", "6" }, { "dynabomb_player_3.active.anim_mode", "pingpong" }, { "dynabomb_player_4", "RocksElements.png" }, { "dynabomb_player_4.xpos", "12" }, { "dynabomb_player_4.ypos", "11" }, { "dynabomb_player_4.frames", "1" }, { "dynabomb_player_4.active", "RocksElements.png" }, { "dynabomb_player_4.active.xpos", "12" }, { "dynabomb_player_4.active.ypos", "11" }, { "dynabomb_player_4.active.frames", "4" }, { "dynabomb_player_4.active.delay", "6" }, { "dynabomb_player_4.active.anim_mode", "pingpong" }, { "dynabomb_increase_number", "RocksElements.png" }, { "dynabomb_increase_number.xpos", "12" }, { "dynabomb_increase_number.ypos", "11" }, { "dynabomb_increase_number.frames", "1" }, { "dynabomb_increase_size", "RocksElements.png" }, { "dynabomb_increase_size.xpos", "15" }, { "dynabomb_increase_size.ypos", "11" }, { "dynabomb_increase_size.frames", "1" }, { "dynabomb_increase_power", "RocksElements.png" }, { "dynabomb_increase_power.xpos", "12" }, { "dynabomb_increase_power.ypos", "9" }, { "dynabomb_increase_power.frames", "1" }, { "pig", "RocksHeroes.png" }, { "pig.xpos", "8" }, { "pig.ypos", "0" }, { "pig.frames", "1" }, { "pig.down", "RocksHeroes.png" }, { "pig.down.xpos", "8" }, { "pig.down.ypos", "0" }, { "pig.down.frames", "1" }, { "pig.up", "RocksHeroes.png" }, { "pig.up.xpos", "12" }, { "pig.up.ypos", "0" }, { "pig.up.frames", "1" }, { "pig.left", "RocksHeroes.png" }, { "pig.left.xpos", "8" }, { "pig.left.ypos", "1" }, { "pig.left.frames", "1" }, { "pig.right", "RocksHeroes.png" }, { "pig.right.xpos", "12" }, { "pig.right.ypos", "1" }, { "pig.right.frames", "1" }, { "pig.moving.down", "RocksHeroes.png" }, { "pig.moving.down.xpos", "8" }, { "pig.moving.down.ypos", "0" }, { "pig.moving.down.frames", "4" }, { "pig.moving.down.delay", "2" }, { "pig.moving.up", "RocksHeroes.png" }, { "pig.moving.up.xpos", "12" }, { "pig.moving.up.ypos", "0" }, { "pig.moving.up.frames", "4" }, { "pig.moving.up.delay", "2" }, { "pig.moving.left", "RocksHeroes.png" }, { "pig.moving.left.xpos", "8" }, { "pig.moving.left.ypos", "1" }, { "pig.moving.left.frames", "4" }, { "pig.moving.left.delay", "2" }, { "pig.moving.right", "RocksHeroes.png" }, { "pig.moving.right.xpos", "12" }, { "pig.moving.right.ypos", "1" }, { "pig.moving.right.frames", "4" }, { "pig.moving.right.delay", "2" }, { "pig.digging.down", "RocksHeroes.png" }, { "pig.digging.down.xpos", "8" }, { "pig.digging.down.ypos", "0" }, { "pig.digging.down.frames", "4" }, { "pig.digging.down.delay", "2" }, { "pig.digging.up", "RocksHeroes.png" }, { "pig.digging.up.xpos", "12" }, { "pig.digging.up.ypos", "0" }, { "pig.digging.up.frames", "4" }, { "pig.digging.up.delay", "2" }, { "pig.digging.left", "RocksHeroes.png" }, { "pig.digging.left.xpos", "8" }, { "pig.digging.left.ypos", "1" }, { "pig.digging.left.frames", "4" }, { "pig.digging.left.delay", "2" }, { "pig.digging.right", "RocksHeroes.png" }, { "pig.digging.right.xpos", "12" }, { "pig.digging.right.ypos", "1" }, { "pig.digging.right.frames", "4" }, { "pig.digging.right.delay", "2" }, { "dragon", "RocksHeroes.png" }, { "dragon.xpos", "8" }, { "dragon.ypos", "2" }, { "dragon.frames", "1" }, { "dragon.down", "RocksHeroes.png" }, { "dragon.down.xpos", "8" }, { "dragon.down.ypos", "2" }, { "dragon.down.frames", "1" }, { "dragon.up", "RocksHeroes.png" }, { "dragon.up.xpos", "12" }, { "dragon.up.ypos", "2" }, { "dragon.up.frames", "1" }, { "dragon.left", "RocksHeroes.png" }, { "dragon.left.xpos", "8" }, { "dragon.left.ypos", "3" }, { "dragon.left.frames", "1" }, { "dragon.right", "RocksHeroes.png" }, { "dragon.right.xpos", "12" }, { "dragon.right.ypos", "3" }, { "dragon.right.frames", "1" }, { "dragon.moving.down", "RocksHeroes.png" }, { "dragon.moving.down.xpos", "8" }, { "dragon.moving.down.ypos", "2" }, { "dragon.moving.down.frames", "4" }, { "dragon.moving.down.delay", "2" }, { "dragon.moving.up", "RocksHeroes.png" }, { "dragon.moving.up.xpos", "12" }, { "dragon.moving.up.ypos", "2" }, { "dragon.moving.up.frames", "4" }, { "dragon.moving.up.delay", "2" }, { "dragon.moving.left", "RocksHeroes.png" }, { "dragon.moving.left.xpos", "8" }, { "dragon.moving.left.ypos", "3" }, { "dragon.moving.left.frames", "4" }, { "dragon.moving.left.delay", "2" }, { "dragon.moving.right", "RocksHeroes.png" }, { "dragon.moving.right.xpos", "12" }, { "dragon.moving.right.ypos", "3" }, { "dragon.moving.right.frames", "4" }, { "dragon.moving.right.delay", "2" }, { "dragon.attacking.down", "RocksHeroes.png" }, { "dragon.attacking.down.xpos", "8" }, { "dragon.attacking.down.ypos", "2" }, { "dragon.attacking.down.frames", "1" }, { "dragon.attacking.up", "RocksHeroes.png" }, { "dragon.attacking.up.xpos", "12" }, { "dragon.attacking.up.ypos", "2" }, { "dragon.attacking.up.frames", "1" }, { "dragon.attacking.left", "RocksHeroes.png" }, { "dragon.attacking.left.xpos", "8" }, { "dragon.attacking.left.ypos", "3" }, { "dragon.attacking.left.frames", "1" }, { "dragon.attacking.right", "RocksHeroes.png" }, { "dragon.attacking.right.xpos", "12" }, { "dragon.attacking.right.ypos", "3" }, { "dragon.attacking.right.frames", "1" }, { "mole", "RocksHeroes.png" }, { "mole.xpos", "8" }, { "mole.ypos", "4" }, { "mole.frames", "1" }, { "mole.down", "RocksHeroes.png" }, { "mole.down.xpos", "8" }, { "mole.down.ypos", "4" }, { "mole.down.frames", "1" }, { "mole.up", "RocksHeroes.png" }, { "mole.up.xpos", "12" }, { "mole.up.ypos", "4" }, { "mole.up.frames", "1" }, { "mole.left", "RocksHeroes.png" }, { "mole.left.xpos", "8" }, { "mole.left.ypos", "5" }, { "mole.left.frames", "1" }, { "mole.right", "RocksHeroes.png" }, { "mole.right.xpos", "12" }, { "mole.right.ypos", "5" }, { "mole.right.frames", "1" }, { "mole.moving.down", "RocksHeroes.png" }, { "mole.moving.down.xpos", "8" }, { "mole.moving.down.ypos", "4" }, { "mole.moving.down.frames", "4" }, { "mole.moving.down.delay", "2" }, { "mole.moving.up", "RocksHeroes.png" }, { "mole.moving.up.xpos", "12" }, { "mole.moving.up.ypos", "4" }, { "mole.moving.up.frames", "4" }, { "mole.moving.up.delay", "2" }, { "mole.moving.left", "RocksHeroes.png" }, { "mole.moving.left.xpos", "8" }, { "mole.moving.left.ypos", "5" }, { "mole.moving.left.frames", "4" }, { "mole.moving.left.delay", "2" }, { "mole.moving.right", "RocksHeroes.png" }, { "mole.moving.right.xpos", "12" }, { "mole.moving.right.ypos", "5" }, { "mole.moving.right.frames", "4" }, { "mole.moving.right.delay", "2" }, { "mole.digging.down", "RocksHeroes.png" }, { "mole.digging.down.xpos", "8" }, { "mole.digging.down.ypos", "4" }, { "mole.digging.down.frames", "4" }, { "mole.digging.down.delay", "2" }, { "mole.digging.up", "RocksHeroes.png" }, { "mole.digging.up.xpos", "12" }, { "mole.digging.up.ypos", "4" }, { "mole.digging.up.frames", "4" }, { "mole.digging.up.delay", "2" }, { "mole.digging.left", "RocksHeroes.png" }, { "mole.digging.left.xpos", "8" }, { "mole.digging.left.ypos", "5" }, { "mole.digging.left.frames", "4" }, { "mole.digging.left.delay", "2" }, { "mole.digging.right", "RocksHeroes.png" }, { "mole.digging.right.xpos", "12" }, { "mole.digging.right.ypos", "5" }, { "mole.digging.right.frames", "4" }, { "mole.digging.right.delay", "2" }, { "penguin", "RocksHeroes.png" }, { "penguin.xpos", "8" }, { "penguin.ypos", "6" }, { "penguin.frames", "1" }, { "penguin.EDITOR", "RocksElements.png" }, { "penguin.EDITOR.xpos", "12" }, { "penguin.EDITOR.ypos", "14" }, { "penguin.down", "RocksHeroes.png" }, { "penguin.down.xpos", "8" }, { "penguin.down.ypos", "6" }, { "penguin.down.frames", "1" }, { "penguin.up", "RocksHeroes.png" }, { "penguin.up.xpos", "12" }, { "penguin.up.ypos", "6" }, { "penguin.up.frames", "1" }, { "penguin.left", "RocksHeroes.png" }, { "penguin.left.xpos", "8" }, { "penguin.left.ypos", "7" }, { "penguin.left.frames", "1" }, { "penguin.right", "RocksHeroes.png" }, { "penguin.right.xpos", "12" }, { "penguin.right.ypos", "7" }, { "penguin.right.frames", "1" }, { "penguin.moving.down", "RocksHeroes.png" }, { "penguin.moving.down.xpos", "8" }, { "penguin.moving.down.ypos", "6" }, { "penguin.moving.down.frames", "4" }, { "penguin.moving.down.delay", "2" }, { "penguin.moving.up", "RocksHeroes.png" }, { "penguin.moving.up.xpos", "12" }, { "penguin.moving.up.ypos", "6" }, { "penguin.moving.up.frames", "4" }, { "penguin.moving.up.delay", "2" }, { "penguin.moving.left", "RocksHeroes.png" }, { "penguin.moving.left.xpos", "8" }, { "penguin.moving.left.ypos", "7" }, { "penguin.moving.left.frames", "4" }, { "penguin.moving.left.delay", "2" }, { "penguin.moving.right", "RocksHeroes.png" }, { "penguin.moving.right.xpos", "12" }, { "penguin.moving.right.ypos", "7" }, { "penguin.moving.right.frames", "4" }, { "penguin.moving.right.delay", "2" }, { "satellite", "RocksHeroes.png" }, { "satellite.xpos", "8" }, { "satellite.ypos", "9" }, { "satellite.frames", "8" }, { "satellite.delay", "2" }, { "satellite.global_sync", "true" }, { "flames_1_left", "RocksHeroes.png" }, { "flames_1_left.xpos", "8" }, { "flames_1_left.ypos", "12" }, { "flames_1_left.frames", "2" }, { "flames_1_left.offset", "96" }, { "flames_2_left", "RocksHeroes.png" }, { "flames_2_left.xpos", "9" }, { "flames_2_left.ypos", "12" }, { "flames_2_left.frames", "2" }, { "flames_2_left.offset", "96" }, { "flames_3_left", "RocksHeroes.png" }, { "flames_3_left.xpos", "10" }, { "flames_3_left.ypos", "12" }, { "flames_3_left.frames", "2" }, { "flames_3_left.offset", "96" }, { "flames_1_right", "RocksHeroes.png" }, { "flames_1_right.xpos", "8" }, { "flames_1_right.ypos", "13" }, { "flames_1_right.frames", "2" }, { "flames_1_right.offset", "96" }, { "flames_2_right", "RocksHeroes.png" }, { "flames_2_right.xpos", "9" }, { "flames_2_right.ypos", "13" }, { "flames_2_right.frames", "2" }, { "flames_2_right.offset", "96" }, { "flames_3_right", "RocksHeroes.png" }, { "flames_3_right.xpos", "10" }, { "flames_3_right.ypos", "13" }, { "flames_3_right.frames", "2" }, { "flames_3_right.offset", "96" }, { "flames_1_up", "RocksHeroes.png" }, { "flames_1_up.xpos", "8" }, { "flames_1_up.ypos", "14" }, { "flames_1_up.frames", "2" }, { "flames_1_up.offset", "96" }, { "flames_2_up", "RocksHeroes.png" }, { "flames_2_up.xpos", "9" }, { "flames_2_up.ypos", "14" }, { "flames_2_up.frames", "2" }, { "flames_2_up.offset", "96" }, { "flames_3_up", "RocksHeroes.png" }, { "flames_3_up.xpos", "10" }, { "flames_3_up.ypos", "14" }, { "flames_3_up.frames", "2" }, { "flames_3_up.offset", "96" }, { "flames_1_down", "RocksHeroes.png" }, { "flames_1_down.xpos", "8" }, { "flames_1_down.ypos", "15" }, { "flames_1_down.frames", "2" }, { "flames_1_down.offset", "96" }, { "flames_2_down", "RocksHeroes.png" }, { "flames_2_down.xpos", "9" }, { "flames_2_down.ypos", "15" }, { "flames_2_down.frames", "2" }, { "flames_2_down.offset", "96" }, { "flames_3_down", "RocksHeroes.png" }, { "flames_3_down.xpos", "10" }, { "flames_3_down.ypos", "15" }, { "flames_3_down.frames", "2" }, { "flames_3_down.offset", "96" }, { "stoneblock", "RocksElements.png" }, { "stoneblock.xpos", "10" }, { "stoneblock.ypos", "1" }, { "stoneblock.frames", "1" }, /* images for other elements and actions */ { "player_1", "RocksHeroes.png" }, { "player_1.xpos", "0" }, { "player_1.ypos", "0" }, { "player_1.frames", "1" }, { "player_1.EDITOR", "RocksElements.png" }, { "player_1.EDITOR.xpos", "4" }, { "player_1.EDITOR.ypos", "7" }, { "player_1.down", "RocksHeroes.png" }, { "player_1.down.xpos", "0" }, { "player_1.down.ypos", "0" }, { "player_1.down.frames", "1" }, { "player_1.up", "RocksHeroes.png" }, { "player_1.up.xpos", "4" }, { "player_1.up.ypos", "0" }, { "player_1.up.frames", "1" }, { "player_1.left", "RocksHeroes.png" }, { "player_1.left.xpos", "0" }, { "player_1.left.ypos", "1" }, { "player_1.left.frames", "1" }, { "player_1.right", "RocksHeroes.png" }, { "player_1.right.xpos", "4" }, { "player_1.right.ypos", "1" }, { "player_1.right.frames", "1" }, { "player_1.moving.down", "RocksHeroes.png" }, { "player_1.moving.down.xpos", "0" }, { "player_1.moving.down.ypos", "0" }, { "player_1.moving.down.frames", "4" }, { "player_1.moving.down.start_frame", "1" }, { "player_1.moving.down.delay", "4" }, { "player_1.moving.up", "RocksHeroes.png" }, { "player_1.moving.up.xpos", "4" }, { "player_1.moving.up.ypos", "0" }, { "player_1.moving.up.frames", "4" }, { "player_1.moving.up.start_frame", "1" }, { "player_1.moving.up.delay", "4" }, { "player_1.moving.left", "RocksHeroes.png" }, { "player_1.moving.left.xpos", "0" }, { "player_1.moving.left.ypos", "1" }, { "player_1.moving.left.frames", "4" }, { "player_1.moving.left.start_frame", "1" }, { "player_1.moving.left.delay", "4" }, { "player_1.moving.right", "RocksHeroes.png" }, { "player_1.moving.right.xpos", "4" }, { "player_1.moving.right.ypos", "1" }, { "player_1.moving.right.frames", "4" }, { "player_1.moving.right.start_frame", "1" }, { "player_1.moving.right.delay", "4" }, { "player_1.digging.down", "RocksHeroes.png" }, { "player_1.digging.down.xpos", "0" }, { "player_1.digging.down.ypos", "0" }, { "player_1.digging.down.frames", "4" }, { "player_1.digging.down.start_frame", "1" }, { "player_1.digging.down.delay", "4" }, { "player_1.digging.up", "RocksHeroes.png" }, { "player_1.digging.up.xpos", "4" }, { "player_1.digging.up.ypos", "0" }, { "player_1.digging.up.frames", "4" }, { "player_1.digging.up.start_frame", "1" }, { "player_1.digging.up.delay", "4" }, { "player_1.digging.left", "RocksHeroes.png" }, { "player_1.digging.left.xpos", "0" }, { "player_1.digging.left.ypos", "1" }, { "player_1.digging.left.frames", "4" }, { "player_1.digging.left.start_frame", "1" }, { "player_1.digging.left.delay", "4" }, { "player_1.digging.right", "RocksHeroes.png" }, { "player_1.digging.right.xpos", "4" }, { "player_1.digging.right.ypos", "1" }, { "player_1.digging.right.frames", "4" }, { "player_1.digging.right.start_frame", "1" }, { "player_1.digging.right.delay", "4" }, { "player_1.collecting.down", "RocksHeroes.png" }, { "player_1.collecting.down.xpos", "0" }, { "player_1.collecting.down.ypos", "0" }, { "player_1.collecting.down.frames", "4" }, { "player_1.collecting.down.start_frame", "1" }, { "player_1.collecting.down.delay", "4" }, { "player_1.collecting.up", "RocksHeroes.png" }, { "player_1.collecting.up.xpos", "4" }, { "player_1.collecting.up.ypos", "0" }, { "player_1.collecting.up.frames", "4" }, { "player_1.collecting.up.start_frame", "1" }, { "player_1.collecting.up.delay", "4" }, { "player_1.collecting.left", "RocksHeroes.png" }, { "player_1.collecting.left.xpos", "0" }, { "player_1.collecting.left.ypos", "1" }, { "player_1.collecting.left.frames", "4" }, { "player_1.collecting.left.start_frame", "1" }, { "player_1.collecting.left.delay", "4" }, { "player_1.collecting.right", "RocksHeroes.png" }, { "player_1.collecting.right.xpos", "4" }, { "player_1.collecting.right.ypos", "1" }, { "player_1.collecting.right.frames", "4" }, { "player_1.collecting.right.start_frame", "1" }, { "player_1.collecting.right.delay", "4" }, { "player_1.pushing.down", "RocksHeroes.png" }, { "player_1.pushing.down.xpos", "0" }, { "player_1.pushing.down.ypos", "0" }, { "player_1.pushing.down.frames", "4" }, { "player_1.pushing.down.delay", "4" }, { "player_1.pushing.up", "RocksHeroes.png" }, { "player_1.pushing.up.xpos", "4" }, { "player_1.pushing.up.ypos", "0" }, { "player_1.pushing.up.frames", "4" }, { "player_1.pushing.up.delay", "4" }, { "player_1.pushing.left", "RocksHeroes.png" }, { "player_1.pushing.left.xpos", "4" }, { "player_1.pushing.left.ypos", "2" }, { "player_1.pushing.left.frames", "4" }, { "player_1.pushing.left.delay", "4" }, { "player_1.pushing.right", "RocksHeroes.png" }, { "player_1.pushing.right.xpos", "0" }, { "player_1.pushing.right.ypos", "2" }, { "player_1.pushing.right.frames", "4" }, { "player_1.pushing.right.delay", "4" }, { "player_1.snapping.down", "RocksHeroes.png" }, { "player_1.snapping.down.xpos", "0" }, { "player_1.snapping.down.ypos", "0" }, { "player_1.snapping.down.frames", "1" }, { "player_1.snapping.up", "RocksHeroes.png" }, { "player_1.snapping.up.xpos", "4" }, { "player_1.snapping.up.ypos", "0" }, { "player_1.snapping.up.frames", "1" }, { "player_1.snapping.left", "RocksHeroes.png" }, { "player_1.snapping.left.xpos", "0" }, { "player_1.snapping.left.ypos", "1" }, { "player_1.snapping.left.frames", "1" }, { "player_1.snapping.right", "RocksHeroes.png" }, { "player_1.snapping.right.xpos", "4" }, { "player_1.snapping.right.ypos", "1" }, { "player_1.snapping.right.frames", "1" }, { "player_2", "RocksHeroes.png" }, { "player_2.xpos", "0" }, { "player_2.ypos", "3" }, { "player_2.frames", "1" }, { "player_2.EDITOR", "RocksElements.png" }, { "player_2.EDITOR.xpos", "5" }, { "player_2.EDITOR.ypos", "7" }, { "player_2.down", "RocksHeroes.png" }, { "player_2.down.xpos", "0" }, { "player_2.down.ypos", "3" }, { "player_2.down.frames", "1" }, { "player_2.up", "RocksHeroes.png" }, { "player_2.up.xpos", "4" }, { "player_2.up.ypos", "3" }, { "player_2.up.frames", "1" }, { "player_2.left", "RocksHeroes.png" }, { "player_2.left.xpos", "0" }, { "player_2.left.ypos", "4" }, { "player_2.left.frames", "1" }, { "player_2.right", "RocksHeroes.png" }, { "player_2.right.xpos", "4" }, { "player_2.right.ypos", "4" }, { "player_2.right.frames", "1" }, { "player_2.moving.down", "RocksHeroes.png" }, { "player_2.moving.down.xpos", "0" }, { "player_2.moving.down.ypos", "3" }, { "player_2.moving.down.frames", "4" }, { "player_2.moving.down.start_frame", "1" }, { "player_2.moving.down.delay", "4" }, { "player_2.moving.up", "RocksHeroes.png" }, { "player_2.moving.up.xpos", "4" }, { "player_2.moving.up.ypos", "3" }, { "player_2.moving.up.frames", "4" }, { "player_2.moving.up.start_frame", "1" }, { "player_2.moving.up.delay", "4" }, { "player_2.moving.left", "RocksHeroes.png" }, { "player_2.moving.left.xpos", "0" }, { "player_2.moving.left.ypos", "4" }, { "player_2.moving.left.frames", "4" }, { "player_2.moving.left.start_frame", "1" }, { "player_2.moving.left.delay", "4" }, { "player_2.moving.right", "RocksHeroes.png" }, { "player_2.moving.right.xpos", "4" }, { "player_2.moving.right.ypos", "4" }, { "player_2.moving.right.frames", "4" }, { "player_2.moving.right.start_frame", "1" }, { "player_2.moving.right.delay", "4" }, { "player_2.digging.down", "RocksHeroes.png" }, { "player_2.digging.down.xpos", "0" }, { "player_2.digging.down.ypos", "3" }, { "player_2.digging.down.frames", "4" }, { "player_2.digging.down.start_frame", "1" }, { "player_2.digging.down.delay", "4" }, { "player_2.digging.up", "RocksHeroes.png" }, { "player_2.digging.up.xpos", "4" }, { "player_2.digging.up.ypos", "3" }, { "player_2.digging.up.frames", "4" }, { "player_2.digging.up.start_frame", "1" }, { "player_2.digging.up.delay", "4" }, { "player_2.digging.left", "RocksHeroes.png" }, { "player_2.digging.left.xpos", "0" }, { "player_2.digging.left.ypos", "4" }, { "player_2.digging.left.frames", "4" }, { "player_2.digging.left.start_frame", "1" }, { "player_2.digging.left.delay", "4" }, { "player_2.digging.right", "RocksHeroes.png" }, { "player_2.digging.right.xpos", "4" }, { "player_2.digging.right.ypos", "4" }, { "player_2.digging.right.frames", "4" }, { "player_2.digging.right.start_frame", "1" }, { "player_2.digging.right.delay", "4" }, { "player_2.collecting.down", "RocksHeroes.png" }, { "player_2.collecting.down.xpos", "0" }, { "player_2.collecting.down.ypos", "3" }, { "player_2.collecting.down.frames", "4" }, { "player_2.collecting.down.start_frame", "1" }, { "player_2.collecting.down.delay", "4" }, { "player_2.collecting.up", "RocksHeroes.png" }, { "player_2.collecting.up.xpos", "4" }, { "player_2.collecting.up.ypos", "3" }, { "player_2.collecting.up.frames", "4" }, { "player_2.collecting.up.start_frame", "1" }, { "player_2.collecting.up.delay", "4" }, { "player_2.collecting.left", "RocksHeroes.png" }, { "player_2.collecting.left.xpos", "0" }, { "player_2.collecting.left.ypos", "4" }, { "player_2.collecting.left.frames", "4" }, { "player_2.collecting.left.start_frame", "1" }, { "player_2.collecting.left.delay", "4" }, { "player_2.collecting.right", "RocksHeroes.png" }, { "player_2.collecting.right.xpos", "4" }, { "player_2.collecting.right.ypos", "4" }, { "player_2.collecting.right.frames", "4" }, { "player_2.collecting.right.start_frame", "1" }, { "player_2.collecting.right.delay", "4" }, { "player_2.pushing.down", "RocksHeroes.png" }, { "player_2.pushing.down.xpos", "0" }, { "player_2.pushing.down.ypos", "3" }, { "player_2.pushing.down.frames", "4" }, { "player_2.pushing.down.delay", "4" }, { "player_2.pushing.up", "RocksHeroes.png" }, { "player_2.pushing.up.xpos", "4" }, { "player_2.pushing.up.ypos", "3" }, { "player_2.pushing.up.frames", "4" }, { "player_2.pushing.up.delay", "4" }, { "player_2.pushing.left", "RocksHeroes.png" }, { "player_2.pushing.left.xpos", "4" }, { "player_2.pushing.left.ypos", "5" }, { "player_2.pushing.left.frames", "4" }, { "player_2.pushing.left.delay", "4" }, { "player_2.pushing.right", "RocksHeroes.png" }, { "player_2.pushing.right.xpos", "0" }, { "player_2.pushing.right.ypos", "5" }, { "player_2.pushing.right.frames", "4" }, { "player_2.pushing.right.delay", "4" }, { "player_2.snapping.down", "RocksHeroes.png" }, { "player_2.snapping.down.xpos", "0" }, { "player_2.snapping.down.ypos", "3" }, { "player_2.snapping.down.frames", "1" }, { "player_2.snapping.up", "RocksHeroes.png" }, { "player_2.snapping.up.xpos", "4" }, { "player_2.snapping.up.ypos", "3" }, { "player_2.snapping.up.frames", "1" }, { "player_2.snapping.left", "RocksHeroes.png" }, { "player_2.snapping.left.xpos", "0" }, { "player_2.snapping.left.ypos", "4" }, { "player_2.snapping.left.frames", "1" }, { "player_2.snapping.right", "RocksHeroes.png" }, { "player_2.snapping.right.xpos", "4" }, { "player_2.snapping.right.ypos", "4" }, { "player_2.snapping.right.frames", "1" }, { "player_3", "RocksHeroes.png" }, { "player_3.xpos", "0" }, { "player_3.ypos", "6" }, { "player_3.frames", "1" }, { "player_3.EDITOR", "RocksElements.png" }, { "player_3.EDITOR.xpos", "6" }, { "player_3.EDITOR.ypos", "7" }, { "player_3.down", "RocksHeroes.png" }, { "player_3.down.xpos", "0" }, { "player_3.down.ypos", "6" }, { "player_3.down.frames", "1" }, { "player_3.up", "RocksHeroes.png" }, { "player_3.up.xpos", "4" }, { "player_3.up.ypos", "6" }, { "player_3.up.frames", "1" }, { "player_3.left", "RocksHeroes.png" }, { "player_3.left.xpos", "0" }, { "player_3.left.ypos", "7" }, { "player_3.left.frames", "1" }, { "player_3.right", "RocksHeroes.png" }, { "player_3.right.xpos", "4" }, { "player_3.right.ypos", "7" }, { "player_3.right.frames", "1" }, { "player_3.moving.down", "RocksHeroes.png" }, { "player_3.moving.down.xpos", "0" }, { "player_3.moving.down.ypos", "6" }, { "player_3.moving.down.frames", "4" }, { "player_3.moving.down.start_frame", "1" }, { "player_3.moving.down.delay", "4" }, { "player_3.moving.up", "RocksHeroes.png" }, { "player_3.moving.up.xpos", "4" }, { "player_3.moving.up.ypos", "6" }, { "player_3.moving.up.frames", "4" }, { "player_3.moving.up.start_frame", "1" }, { "player_3.moving.up.delay", "4" }, { "player_3.moving.left", "RocksHeroes.png" }, { "player_3.moving.left.xpos", "0" }, { "player_3.moving.left.ypos", "7" }, { "player_3.moving.left.frames", "4" }, { "player_3.moving.left.start_frame", "1" }, { "player_3.moving.left.delay", "4" }, { "player_3.moving.right", "RocksHeroes.png" }, { "player_3.moving.right.xpos", "4" }, { "player_3.moving.right.ypos", "7" }, { "player_3.moving.right.frames", "4" }, { "player_3.moving.right.start_frame", "1" }, { "player_3.moving.right.delay", "4" }, { "player_3.digging.down", "RocksHeroes.png" }, { "player_3.digging.down.xpos", "0" }, { "player_3.digging.down.ypos", "6" }, { "player_3.digging.down.frames", "4" }, { "player_3.digging.down.start_frame", "1" }, { "player_3.digging.down.delay", "4" }, { "player_3.digging.up", "RocksHeroes.png" }, { "player_3.digging.up.xpos", "4" }, { "player_3.digging.up.ypos", "6" }, { "player_3.digging.up.frames", "4" }, { "player_3.digging.up.start_frame", "1" }, { "player_3.digging.up.delay", "4" }, { "player_3.digging.left", "RocksHeroes.png" }, { "player_3.digging.left.xpos", "0" }, { "player_3.digging.left.ypos", "7" }, { "player_3.digging.left.frames", "4" }, { "player_3.digging.left.start_frame", "1" }, { "player_3.digging.left.delay", "4" }, { "player_3.digging.right", "RocksHeroes.png" }, { "player_3.digging.right.xpos", "4" }, { "player_3.digging.right.ypos", "7" }, { "player_3.digging.right.frames", "4" }, { "player_3.digging.right.start_frame", "1" }, { "player_3.digging.right.delay", "4" }, { "player_3.collecting.down", "RocksHeroes.png" }, { "player_3.collecting.down.xpos", "0" }, { "player_3.collecting.down.ypos", "6" }, { "player_3.collecting.down.frames", "4" }, { "player_3.collecting.down.start_frame", "1" }, { "player_3.collecting.down.delay", "4" }, { "player_3.collecting.up", "RocksHeroes.png" }, { "player_3.collecting.up.xpos", "4" }, { "player_3.collecting.up.ypos", "6" }, { "player_3.collecting.up.frames", "4" }, { "player_3.collecting.up.start_frame", "1" }, { "player_3.collecting.up.delay", "4" }, { "player_3.collecting.left", "RocksHeroes.png" }, { "player_3.collecting.left.xpos", "0" }, { "player_3.collecting.left.ypos", "7" }, { "player_3.collecting.left.frames", "4" }, { "player_3.collecting.left.start_frame", "1" }, { "player_3.collecting.left.delay", "4" }, { "player_3.collecting.right", "RocksHeroes.png" }, { "player_3.collecting.right.xpos", "4" }, { "player_3.collecting.right.ypos", "7" }, { "player_3.collecting.right.frames", "4" }, { "player_3.collecting.right.start_frame", "1" }, { "player_3.collecting.right.delay", "4" }, { "player_3.pushing.down", "RocksHeroes.png" }, { "player_3.pushing.down.xpos", "0" }, { "player_3.pushing.down.ypos", "6" }, { "player_3.pushing.down.frames", "4" }, { "player_3.pushing.down.delay", "4" }, { "player_3.pushing.up", "RocksHeroes.png" }, { "player_3.pushing.up.xpos", "4" }, { "player_3.pushing.up.ypos", "6" }, { "player_3.pushing.up.frames", "4" }, { "player_3.pushing.up.delay", "4" }, { "player_3.pushing.left", "RocksHeroes.png" }, { "player_3.pushing.left.xpos", "4" }, { "player_3.pushing.left.ypos", "8" }, { "player_3.pushing.left.frames", "4" }, { "player_3.pushing.left.delay", "4" }, { "player_3.pushing.right", "RocksHeroes.png" }, { "player_3.pushing.right.xpos", "0" }, { "player_3.pushing.right.ypos", "8" }, { "player_3.pushing.right.frames", "4" }, { "player_3.pushing.right.delay", "4" }, { "player_3.snapping.down", "RocksHeroes.png" }, { "player_3.snapping.down.xpos", "0" }, { "player_3.snapping.down.ypos", "6" }, { "player_3.snapping.down.frames", "1" }, { "player_3.snapping.up", "RocksHeroes.png" }, { "player_3.snapping.up.xpos", "4" }, { "player_3.snapping.up.ypos", "6" }, { "player_3.snapping.up.frames", "1" }, { "player_3.snapping.left", "RocksHeroes.png" }, { "player_3.snapping.left.xpos", "0" }, { "player_3.snapping.left.ypos", "7" }, { "player_3.snapping.left.frames", "1" }, { "player_3.snapping.right", "RocksHeroes.png" }, { "player_3.snapping.right.xpos", "4" }, { "player_3.snapping.right.ypos", "7" }, { "player_3.snapping.right.frames", "1" }, { "player_4", "RocksHeroes.png" }, { "player_4.xpos", "0" }, { "player_4.ypos", "9" }, { "player_4.frames", "1" }, { "player_4.EDITOR", "RocksElements.png" }, { "player_4.EDITOR.xpos", "7" }, { "player_4.EDITOR.ypos", "7" }, { "player_4.down", "RocksHeroes.png" }, { "player_4.down.xpos", "0" }, { "player_4.down.ypos", "9" }, { "player_4.down.frames", "1" }, { "player_4.up", "RocksHeroes.png" }, { "player_4.up.xpos", "4" }, { "player_4.up.ypos", "9" }, { "player_4.up.frames", "1" }, { "player_4.left", "RocksHeroes.png" }, { "player_4.left.xpos", "0" }, { "player_4.left.ypos", "10" }, { "player_4.left.frames", "1" }, { "player_4.right", "RocksHeroes.png" }, { "player_4.right.xpos", "4" }, { "player_4.right.ypos", "10" }, { "player_4.right.frames", "1" }, { "player_4.moving.down", "RocksHeroes.png" }, { "player_4.moving.down.xpos", "0" }, { "player_4.moving.down.ypos", "9" }, { "player_4.moving.down.frames", "4" }, { "player_4.moving.down.start_frame", "1" }, { "player_4.moving.down.delay", "4" }, { "player_4.moving.up", "RocksHeroes.png" }, { "player_4.moving.up.xpos", "4" }, { "player_4.moving.up.ypos", "9" }, { "player_4.moving.up.frames", "4" }, { "player_4.moving.up.start_frame", "1" }, { "player_4.moving.up.delay", "4" }, { "player_4.moving.left", "RocksHeroes.png" }, { "player_4.moving.left.xpos", "0" }, { "player_4.moving.left.ypos", "10" }, { "player_4.moving.left.frames", "4" }, { "player_4.moving.left.start_frame", "1" }, { "player_4.moving.left.delay", "4" }, { "player_4.moving.right", "RocksHeroes.png" }, { "player_4.moving.right.xpos", "4" }, { "player_4.moving.right.ypos", "10" }, { "player_4.moving.right.frames", "4" }, { "player_4.moving.right.start_frame", "1" }, { "player_4.moving.right.delay", "4" }, { "player_4.digging.down", "RocksHeroes.png" }, { "player_4.digging.down.xpos", "0" }, { "player_4.digging.down.ypos", "9" }, { "player_4.digging.down.frames", "4" }, { "player_4.digging.down.start_frame", "1" }, { "player_4.digging.down.delay", "4" }, { "player_4.digging.up", "RocksHeroes.png" }, { "player_4.digging.up.xpos", "4" }, { "player_4.digging.up.ypos", "9" }, { "player_4.digging.up.frames", "4" }, { "player_4.digging.up.start_frame", "1" }, { "player_4.digging.up.delay", "4" }, { "player_4.digging.left", "RocksHeroes.png" }, { "player_4.digging.left.xpos", "0" }, { "player_4.digging.left.ypos", "10" }, { "player_4.digging.left.frames", "4" }, { "player_4.digging.left.start_frame", "1" }, { "player_4.digging.left.delay", "4" }, { "player_4.digging.right", "RocksHeroes.png" }, { "player_4.digging.right.xpos", "4" }, { "player_4.digging.right.ypos", "10" }, { "player_4.digging.right.frames", "4" }, { "player_4.digging.right.start_frame", "1" }, { "player_4.digging.right.delay", "4" }, { "player_4.collecting.down", "RocksHeroes.png" }, { "player_4.collecting.down.xpos", "0" }, { "player_4.collecting.down.ypos", "9" }, { "player_4.collecting.down.frames", "4" }, { "player_4.collecting.down.start_frame", "1" }, { "player_4.collecting.down.delay", "4" }, { "player_4.collecting.up", "RocksHeroes.png" }, { "player_4.collecting.up.xpos", "4" }, { "player_4.collecting.up.ypos", "9" }, { "player_4.collecting.up.frames", "4" }, { "player_4.collecting.up.start_frame", "1" }, { "player_4.collecting.up.delay", "4" }, { "player_4.collecting.left", "RocksHeroes.png" }, { "player_4.collecting.left.xpos", "0" }, { "player_4.collecting.left.ypos", "10" }, { "player_4.collecting.left.frames", "4" }, { "player_4.collecting.left.start_frame", "1" }, { "player_4.collecting.left.delay", "4" }, { "player_4.collecting.right", "RocksHeroes.png" }, { "player_4.collecting.right.xpos", "4" }, { "player_4.collecting.right.ypos", "10" }, { "player_4.collecting.right.frames", "4" }, { "player_4.collecting.right.start_frame", "1" }, { "player_4.collecting.right.delay", "4" }, { "player_4.pushing.down", "RocksHeroes.png" }, { "player_4.pushing.down.xpos", "0" }, { "player_4.pushing.down.ypos", "9" }, { "player_4.pushing.down.frames", "4" }, { "player_4.pushing.down.delay", "4" }, { "player_4.pushing.up", "RocksHeroes.png" }, { "player_4.pushing.up.xpos", "4" }, { "player_4.pushing.up.ypos", "9" }, { "player_4.pushing.up.frames", "4" }, { "player_4.pushing.up.delay", "4" }, { "player_4.pushing.left", "RocksHeroes.png" }, { "player_4.pushing.left.xpos", "4" }, { "player_4.pushing.left.ypos", "11" }, { "player_4.pushing.left.frames", "4" }, { "player_4.pushing.left.delay", "4" }, { "player_4.pushing.right", "RocksHeroes.png" }, { "player_4.pushing.right.xpos", "0" }, { "player_4.pushing.right.ypos", "11" }, { "player_4.pushing.right.frames", "4" }, { "player_4.pushing.right.delay", "4" }, { "player_4.snapping.down", "RocksHeroes.png" }, { "player_4.snapping.down.xpos", "0" }, { "player_4.snapping.down.ypos", "9" }, { "player_4.snapping.down.frames", "1" }, { "player_4.snapping.up", "RocksHeroes.png" }, { "player_4.snapping.up.xpos", "4" }, { "player_4.snapping.up.ypos", "9" }, { "player_4.snapping.up.frames", "1" }, { "player_4.snapping.left", "RocksHeroes.png" }, { "player_4.snapping.left.xpos", "0" }, { "player_4.snapping.left.ypos", "10" }, { "player_4.snapping.left.frames", "1" }, { "player_4.snapping.right", "RocksHeroes.png" }, { "player_4.snapping.right.xpos", "4" }, { "player_4.snapping.right.ypos", "10" }, { "player_4.snapping.right.frames", "1" }, { "[default].exploding", "RocksElements.png" }, { "[default].exploding.xpos", "0" }, { "[default].exploding.ypos", "4" }, { "[default].exploding.frames", "8" }, { "[default].exploding.delay", "2" }, { "[default].exploding.anim_mode", "linear" }, { "twinkle_blue", "RocksHeroes.png" }, { "twinkle_blue.xpos", "9" }, { "twinkle_blue.ypos", "11" }, { "twinkle_blue.frames", "3" }, { "twinkle_blue.delay", "2" }, { "twinkle_blue.anim_mode", "pingpong" }, { "twinkle_blue.global_sync", "false" }, { "twinkle_white", "RocksHeroes.png" }, { "twinkle_white.xpos", "13" }, { "twinkle_white.ypos", "11" }, { "twinkle_white.frames", "3" }, { "twinkle_white.delay", "2" }, { "twinkle_white.anim_mode", "pingpong" }, { "twinkle_white.global_sync", "false" }, { "steelwall_topleft", "RocksElements.png" }, { "steelwall_topleft.xpos", "4" }, { "steelwall_topleft.ypos", "0" }, { "steelwall_topleft.frames", "1" }, { "steelwall_topright", "RocksElements.png" }, { "steelwall_topright.xpos", "4" }, { "steelwall_topright.ypos", "0" }, { "steelwall_topright.frames", "1" }, { "steelwall_bottomleft", "RocksElements.png" }, { "steelwall_bottomleft.xpos", "4" }, { "steelwall_bottomleft.ypos", "0" }, { "steelwall_bottomleft.frames", "1" }, { "steelwall_bottomright", "RocksElements.png" }, { "steelwall_bottomright.xpos", "4" }, { "steelwall_bottomright.ypos", "0" }, { "steelwall_bottomright.frames", "1" }, { "steelwall_horizontal", "RocksElements.png" }, { "steelwall_horizontal.xpos", "4" }, { "steelwall_horizontal.ypos", "0" }, { "steelwall_horizontal.frames", "1" }, { "steelwall_vertical", "RocksElements.png" }, { "steelwall_vertical.xpos", "4" }, { "steelwall_vertical.ypos", "0" }, { "steelwall_vertical.frames", "1" }, { "steelwall_topleft.EDITOR", "RocksElements.png" }, { "steelwall_topleft.EDITOR.xpos", "0" }, { "steelwall_topleft.EDITOR.ypos", "13" }, { "steelwall_topright.EDITOR", "RocksElements.png" }, { "steelwall_topright.EDITOR.xpos", "1" }, { "steelwall_topright.EDITOR.ypos", "13" }, { "steelwall_bottomleft.EDITOR", "RocksElements.png" }, { "steelwall_bottomleft.EDITOR.xpos", "2" }, { "steelwall_bottomleft.EDITOR.ypos", "13" }, { "steelwall_bottomright.EDITOR", "RocksElements.png" }, { "steelwall_bottomright.EDITOR.xpos", "3" }, { "steelwall_bottomright.EDITOR.ypos", "13" }, { "steelwall_horizontal.EDITOR", "RocksElements.png" }, { "steelwall_horizontal.EDITOR.xpos", "4" }, { "steelwall_horizontal.EDITOR.ypos", "13" }, { "steelwall_vertical.EDITOR", "RocksElements.png" }, { "steelwall_vertical.EDITOR.xpos", "5" }, { "steelwall_vertical.EDITOR.ypos", "13" }, { "invisible_steelwall_topleft", "RocksSP.png" }, { "invisible_steelwall_topleft.xpos", "0" }, { "invisible_steelwall_topleft.ypos", "0" }, { "invisible_steelwall_topleft.frames", "1" }, { "invisible_steelwall_topright", "RocksSP.png" }, { "invisible_steelwall_topright.xpos", "0" }, { "invisible_steelwall_topright.ypos", "0" }, { "invisible_steelwall_topright.frames", "1" }, { "invisible_steelwall_bottomleft", "RocksSP.png" }, { "invisible_steelwall_bottomleft.xpos", "0" }, { "invisible_steelwall_bottomleft.ypos", "0" }, { "invisible_steelwall_bottomleft.frames", "1" }, { "invisible_steelwall_bottomright", "RocksSP.png" }, { "invisible_steelwall_bottomright.xpos", "0" }, { "invisible_steelwall_bottomright.ypos", "0" }, { "invisible_steelwall_bottomright.frames", "1" }, { "invisible_steelwall_horizontal", "RocksSP.png" }, { "invisible_steelwall_horizontal.xpos", "0" }, { "invisible_steelwall_horizontal.ypos", "0" }, { "invisible_steelwall_horizontal.frames", "1" }, { "invisible_steelwall_vertical", "RocksSP.png" }, { "invisible_steelwall_vertical.xpos", "0" }, { "invisible_steelwall_vertical.ypos", "0" }, { "invisible_steelwall_vertical.frames", "1" }, { "invisible_steelwall_topleft.EDITOR", "RocksElements.png" }, { "invisible_steelwall_topleft.EDITOR.xpos", "6" }, { "invisible_steelwall_topleft.EDITOR.ypos", "13" }, { "invisible_steelwall_topright.EDITOR", "RocksElements.png" }, { "invisible_steelwall_topright.EDITOR.xpos", "7" }, { "invisible_steelwall_topright.EDITOR.ypos", "13" }, { "invisible_steelwall_bottomleft.EDITOR", "RocksElements.png" }, { "invisible_steelwall_bottomleft.EDITOR.xpos","8" }, { "invisible_steelwall_bottomleft.EDITOR.ypos","13" }, { "invisible_steelwall_bottomright.EDITOR", "RocksElements.png" }, { "invisible_steelwall_bottomright.EDITOR.xpos","9" }, { "invisible_steelwall_bottomright.EDITOR.ypos","13" }, { "invisible_steelwall_horizontal.EDITOR", "RocksElements.png" }, { "invisible_steelwall_horizontal.EDITOR.xpos","10" }, { "invisible_steelwall_horizontal.EDITOR.ypos","13" }, { "invisible_steelwall_vertical.EDITOR", "RocksElements.png" }, { "invisible_steelwall_vertical.EDITOR.xpos", "11" }, { "invisible_steelwall_vertical.EDITOR.ypos", "13" }, { "arrow_left", "RocksDC.png" }, { "arrow_left.xpos", "8" }, { "arrow_left.ypos", "8" }, { "arrow_left.frames", "1" }, { "arrow_right", "RocksDC.png" }, { "arrow_right.xpos", "9" }, { "arrow_right.ypos", "8" }, { "arrow_right.frames", "1" }, { "arrow_up", "RocksDC.png" }, { "arrow_up.xpos", "10" }, { "arrow_up.ypos", "8" }, { "arrow_up.frames", "1" }, { "arrow_down", "RocksDC.png" }, { "arrow_down.xpos", "11" }, { "arrow_down.ypos", "8" }, { "arrow_down.frames", "1" }, { "unknown", "RocksFontEM.png" }, { "unknown.xpos", "15" }, { "unknown.ypos", "1" }, { "unknown.frames", "1" }, { "trigger_element", "RocksDC.png" }, { "trigger_element.xpos", "15" }, { "trigger_element.ypos", "14" }, { "trigger_element.frames", "1" }, { "trigger_player", "RocksDC.png" }, { "trigger_player.xpos", "15" }, { "trigger_player.ypos", "13" }, { "trigger_player.frames", "1" }, { "trigger_ce_value", "RocksDC.png" }, { "trigger_ce_value.xpos", "15" }, { "trigger_ce_value.ypos", "11" }, { "trigger_ce_value.frames", "1" }, { "trigger_ce_score", "RocksDC.png" }, { "trigger_ce_score.xpos", "15" }, { "trigger_ce_score.ypos", "12" }, { "trigger_ce_score.frames", "1" }, { "current_ce_value", "RocksDC.png" }, { "current_ce_value.xpos", "14" }, { "current_ce_value.ypos", "11" }, { "current_ce_value.frames", "1" }, { "current_ce_score", "RocksDC.png" }, { "current_ce_score.xpos", "14" }, { "current_ce_score.ypos", "12" }, { "current_ce_score.frames", "1" }, { "prev_ce_1", "RocksMore.png" }, { "prev_ce_1.xpos", "0" }, { "prev_ce_1.ypos", "7" }, { "prev_ce_1.frames", "1" }, { "prev_ce_2", "RocksMore.png" }, { "prev_ce_2.xpos", "1" }, { "prev_ce_2.ypos", "7" }, { "prev_ce_2.frames", "1" }, { "prev_ce_3", "RocksMore.png" }, { "prev_ce_3.xpos", "2" }, { "prev_ce_3.ypos", "7" }, { "prev_ce_3.frames", "1" }, { "prev_ce_4", "RocksMore.png" }, { "prev_ce_4.xpos", "3" }, { "prev_ce_4.ypos", "7" }, { "prev_ce_4.frames", "1" }, { "prev_ce_5", "RocksMore.png" }, { "prev_ce_5.xpos", "4" }, { "prev_ce_5.ypos", "7" }, { "prev_ce_5.frames", "1" }, { "prev_ce_6", "RocksMore.png" }, { "prev_ce_6.xpos", "5" }, { "prev_ce_6.ypos", "7" }, { "prev_ce_6.frames", "1" }, { "prev_ce_7", "RocksMore.png" }, { "prev_ce_7.xpos", "6" }, { "prev_ce_7.ypos", "7" }, { "prev_ce_7.frames", "1" }, { "prev_ce_8", "RocksMore.png" }, { "prev_ce_8.xpos", "7" }, { "prev_ce_8.ypos", "7" }, { "prev_ce_8.frames", "1" }, { "next_ce_1", "RocksMore.png" }, { "next_ce_1.xpos", "0" }, { "next_ce_1.ypos", "8" }, { "next_ce_1.frames", "1" }, { "next_ce_2", "RocksMore.png" }, { "next_ce_2.xpos", "1" }, { "next_ce_2.ypos", "8" }, { "next_ce_2.frames", "1" }, { "next_ce_3", "RocksMore.png" }, { "next_ce_3.xpos", "2" }, { "next_ce_3.ypos", "8" }, { "next_ce_3.frames", "1" }, { "next_ce_4", "RocksMore.png" }, { "next_ce_4.xpos", "3" }, { "next_ce_4.ypos", "8" }, { "next_ce_4.frames", "1" }, { "next_ce_5", "RocksMore.png" }, { "next_ce_5.xpos", "4" }, { "next_ce_5.ypos", "8" }, { "next_ce_5.frames", "1" }, { "next_ce_6", "RocksMore.png" }, { "next_ce_6.xpos", "5" }, { "next_ce_6.ypos", "8" }, { "next_ce_6.frames", "1" }, { "next_ce_7", "RocksMore.png" }, { "next_ce_7.xpos", "6" }, { "next_ce_7.ypos", "8" }, { "next_ce_7.frames", "1" }, { "next_ce_8", "RocksMore.png" }, { "next_ce_8.xpos", "7" }, { "next_ce_8.ypos", "8" }, { "next_ce_8.frames", "1" }, { "self", "RocksMore.png" }, { "self.xpos", "8" }, { "self.ypos", "7" }, { "self.frames", "1" }, { "any_element", "RocksMore.png" }, { "any_element.xpos", "9" }, { "any_element.ypos", "7" }, { "any_element.frames", "1" }, { "emc_key_5", "RocksEMC.png" }, { "emc_key_5.xpos", "0" }, { "emc_key_5.ypos", "5" }, { "emc_key_5.frames", "1" }, { "emc_key_6", "RocksEMC.png" }, { "emc_key_6.xpos", "1" }, { "emc_key_6.ypos", "5" }, { "emc_key_6.frames", "1" }, { "emc_key_7", "RocksEMC.png" }, { "emc_key_7.xpos", "2" }, { "emc_key_7.ypos", "5" }, { "emc_key_7.frames", "1" }, { "emc_key_8", "RocksEMC.png" }, { "emc_key_8.xpos", "3" }, { "emc_key_8.ypos", "5" }, { "emc_key_8.frames", "1" }, { "emc_gate_5", "RocksEMC.png" }, { "emc_gate_5.xpos", "0" }, { "emc_gate_5.ypos", "6" }, { "emc_gate_5.frames", "1" }, { "emc_gate_6", "RocksEMC.png" }, { "emc_gate_6.xpos", "1" }, { "emc_gate_6.ypos", "6" }, { "emc_gate_6.frames", "1" }, { "emc_gate_7", "RocksEMC.png" }, { "emc_gate_7.xpos", "2" }, { "emc_gate_7.ypos", "6" }, { "emc_gate_7.frames", "1" }, { "emc_gate_8", "RocksEMC.png" }, { "emc_gate_8.xpos", "3" }, { "emc_gate_8.ypos", "6" }, { "emc_gate_8.frames", "1" }, { "emc_gate_5_gray", "RocksEMC.png" }, { "emc_gate_5_gray.xpos", "4" }, { "emc_gate_5_gray.ypos", "7" }, { "emc_gate_5_gray.frames", "1" }, { "emc_gate_5_gray.EDITOR", "RocksEMC.png" }, { "emc_gate_5_gray.EDITOR.xpos", "0" }, { "emc_gate_5_gray.EDITOR.ypos", "7" }, { "emc_gate_5_gray.active", "RocksEMC.png" }, { "emc_gate_5_gray.active.xpos", "0" }, { "emc_gate_5_gray.active.ypos", "6" }, { "emc_gate_5_gray.active.frames", "1" }, { "emc_gate_6_gray", "RocksEMC.png" }, { "emc_gate_6_gray.xpos", "4" }, { "emc_gate_6_gray.ypos", "7" }, { "emc_gate_6_gray.frames", "1" }, { "emc_gate_6_gray.EDITOR", "RocksEMC.png" }, { "emc_gate_6_gray.EDITOR.xpos", "1" }, { "emc_gate_6_gray.EDITOR.ypos", "7" }, { "emc_gate_6_gray.active", "RocksEMC.png" }, { "emc_gate_6_gray.active.xpos", "1" }, { "emc_gate_6_gray.active.ypos", "6" }, { "emc_gate_6_gray.active.frames", "1" }, { "emc_gate_7_gray", "RocksEMC.png" }, { "emc_gate_7_gray.xpos", "4" }, { "emc_gate_7_gray.ypos", "7" }, { "emc_gate_7_gray.frames", "1" }, { "emc_gate_7_gray.EDITOR", "RocksEMC.png" }, { "emc_gate_7_gray.EDITOR.xpos", "2" }, { "emc_gate_7_gray.EDITOR.ypos", "7" }, { "emc_gate_7_gray.active", "RocksEMC.png" }, { "emc_gate_7_gray.active.xpos", "2" }, { "emc_gate_7_gray.active.ypos", "6" }, { "emc_gate_7_gray.active.frames", "1" }, { "emc_gate_8_gray", "RocksEMC.png" }, { "emc_gate_8_gray.xpos", "4" }, { "emc_gate_8_gray.ypos", "7" }, { "emc_gate_8_gray.frames", "1" }, { "emc_gate_8_gray.EDITOR", "RocksEMC.png" }, { "emc_gate_8_gray.EDITOR.xpos", "3" }, { "emc_gate_8_gray.EDITOR.ypos", "7" }, { "emc_gate_8_gray.active", "RocksEMC.png" }, { "emc_gate_8_gray.active.xpos", "3" }, { "emc_gate_8_gray.active.ypos", "6" }, { "emc_gate_8_gray.active.frames", "1" }, { "emc_android", "RocksEMC.png" }, { "emc_android.xpos", "0" }, { "emc_android.ypos", "8" }, { "emc_android.frames", "8" }, { "emc_android.delay", "2" }, { "emc_android.shrinking.upleft", "RocksEMC.png" }, { "emc_android.shrinking.upleft.xpos", "1" }, { "emc_android.shrinking.upleft.ypos", "11" }, { "emc_android.shrinking.upleft.frames", "8" }, { "emc_android.shrinking.upleft.anim_mode", "linear" }, { "emc_android.growing.downright", "RocksEMC.png" }, { "emc_android.growing.downright.xpos", "0" }, { "emc_android.growing.downright.ypos", "11" }, { "emc_android.growing.downright.frames", "8" }, { "emc_android.growing.downright.anim_mode", "linear,reverse" }, { "emc_android.shrinking.downleft", "RocksEMC.png" }, { "emc_android.shrinking.downleft.xpos", "1" }, { "emc_android.shrinking.downleft.ypos", "12" }, { "emc_android.shrinking.downleft.frames", "8" }, { "emc_android.shrinking.downleft.anim_mode", "linear" }, { "emc_android.growing.upright", "RocksEMC.png" }, { "emc_android.growing.upright.xpos", "0" }, { "emc_android.growing.upright.ypos", "12" }, { "emc_android.growing.upright.frames", "8" }, { "emc_android.growing.upright.anim_mode", "linear,reverse" }, { "emc_android.shrinking.upright", "RocksEMC.png" }, { "emc_android.shrinking.upright.xpos", "1" }, { "emc_android.shrinking.upright.ypos", "13" }, { "emc_android.shrinking.upright.frames", "8" }, { "emc_android.shrinking.upright.anim_mode", "linear" }, { "emc_android.growing.downleft", "RocksEMC.png" }, { "emc_android.growing.downleft.xpos", "0" }, { "emc_android.growing.downleft.ypos", "13" }, { "emc_android.growing.downleft.frames", "8" }, { "emc_android.growing.downleft.anim_mode", "linear,reverse" }, { "emc_android.shrinking.downright", "RocksEMC.png" }, { "emc_android.shrinking.downright.xpos", "1" }, { "emc_android.shrinking.downright.ypos", "14" }, { "emc_android.shrinking.downright.frames", "8" }, { "emc_android.shrinking.downright.anim_mode","linear" }, { "emc_android.growing.upleft", "RocksEMC.png" }, { "emc_android.growing.upleft.xpos", "0" }, { "emc_android.growing.upleft.ypos", "14" }, { "emc_android.growing.upleft.frames", "8" }, { "emc_android.growing.upleft.anim_mode", "linear,reverse" }, { "emc_grass", "RocksEMC.png" }, { "emc_grass.xpos", "0" }, { "emc_grass.ypos", "4" }, { "emc_grass.frames", "1" }, { "emc_grass.CRUMBLED", "RocksEMC.png" }, { "emc_grass.CRUMBLED.xpos", "1" }, { "emc_grass.CRUMBLED.ypos", "4" }, { "emc_grass.CRUMBLED.frames", "1" }, { "emc_grass.digging.left", "RocksEMC.png" }, { "emc_grass.digging.left.xpos", "6" }, { "emc_grass.digging.left.ypos", "0" }, { "emc_grass.digging.left.frames", "3" }, { "emc_grass.digging.left.delay", "2" }, { "emc_grass.digging.left.anim_mode", "linear" }, { "emc_grass.digging.right", "RocksEMC.png" }, { "emc_grass.digging.right.xpos", "9" }, { "emc_grass.digging.right.ypos", "0" }, { "emc_grass.digging.right.frames", "3" }, { "emc_grass.digging.right.delay", "2" }, { "emc_grass.digging.right.anim_mode", "linear" }, { "emc_grass.digging.up", "RocksEMC.png" }, { "emc_grass.digging.up.xpos", "0" }, { "emc_grass.digging.up.ypos", "0" }, { "emc_grass.digging.up.frames", "3" }, { "emc_grass.digging.up.delay", "2" }, { "emc_grass.digging.up.anim_mode", "linear" }, { "emc_grass.digging.down", "RocksEMC.png" }, { "emc_grass.digging.down.xpos", "3" }, { "emc_grass.digging.down.ypos", "0" }, { "emc_grass.digging.down.frames", "3" }, { "emc_grass.digging.down.delay", "2" }, { "emc_grass.digging.down.anim_mode", "linear" }, { "emc_grass.digging.left.CRUMBLED", "RocksEMC.png" }, { "emc_grass.digging.left.CRUMBLED.xpos", "6" }, { "emc_grass.digging.left.CRUMBLED.ypos", "1" }, { "emc_grass.digging.left.CRUMBLED.frames", "3" }, { "emc_grass.digging.left.CRUMBLED.delay", "2" }, { "emc_grass.digging.left.CRUMBLED.anim_mode","linear" }, { "emc_grass.digging.right.CRUMBLED", "RocksEMC.png" }, { "emc_grass.digging.right.CRUMBLED.xpos", "9" }, { "emc_grass.digging.right.CRUMBLED.ypos", "1" }, { "emc_grass.digging.right.CRUMBLED.frames", "3" }, { "emc_grass.digging.right.CRUMBLED.delay", "2" }, { "emc_grass.digging.right.CRUMBLED.anim_mode","linear" }, { "emc_grass.digging.up.CRUMBLED", "RocksEMC.png" }, { "emc_grass.digging.up.CRUMBLED.xpos", "0" }, { "emc_grass.digging.up.CRUMBLED.ypos", "1" }, { "emc_grass.digging.up.CRUMBLED.frames", "3" }, { "emc_grass.digging.up.CRUMBLED.delay", "2" }, { "emc_grass.digging.up.CRUMBLED.anim_mode", "linear" }, { "emc_grass.digging.down.CRUMBLED", "RocksEMC.png" }, { "emc_grass.digging.down.CRUMBLED.xpos", "3" }, { "emc_grass.digging.down.CRUMBLED.ypos", "1" }, { "emc_grass.digging.down.CRUMBLED.frames", "3" }, { "emc_grass.digging.down.CRUMBLED.delay", "2" }, { "emc_grass.digging.down.CRUMBLED.anim_mode","linear" }, { "emc_magic_ball", "RocksEMC.png" }, { "emc_magic_ball.xpos", "0" }, { "emc_magic_ball.ypos", "9" }, { "emc_magic_ball.frames", "1" }, { "emc_magic_ball.active", "RocksEMC.png" }, { "emc_magic_ball.active.xpos", "0" }, { "emc_magic_ball.active.ypos", "9" }, { "emc_magic_ball.active.frames", "16" }, { "emc_magic_ball.active.frames_per_line", "8" }, { "emc_magic_ball.dropping", "RocksElements.png" }, { "emc_magic_ball.dropping.xpos", "0" }, { "emc_magic_ball.dropping.ypos", "4" }, { "emc_magic_ball.dropping.frames", "8" }, { "emc_magic_ball.dropping.anim_mode", "linear" }, { "emc_magic_ball_switch", "RocksEMC.png" }, { "emc_magic_ball_switch.xpos", "8" }, { "emc_magic_ball_switch.ypos", "10" }, { "emc_magic_ball_switch.frames", "1" }, { "emc_magic_ball_switch.active", "RocksEMC.png" }, { "emc_magic_ball_switch.active.xpos", "8" }, { "emc_magic_ball_switch.active.ypos", "9" }, { "emc_magic_ball_switch.active.frames", "1" }, { "emc_spring_bumper", "RocksEMC.png" }, { "emc_spring_bumper.xpos", "8" }, { "emc_spring_bumper.ypos", "4" }, { "emc_spring_bumper.frames", "1" }, { "emc_spring_bumper.active", "RocksEMC.png" }, { "emc_spring_bumper.active.xpos", "8" }, { "emc_spring_bumper.active.ypos", "4" }, { "emc_spring_bumper.active.frames", "4" }, { "emc_spring_bumper.active.anim_mode", "pingpong2" }, { "emc_plant", "RocksEMC.png" }, { "emc_plant.xpos", "4" }, { "emc_plant.ypos", "4" }, { "emc_plant.frames", "1" }, { "emc_plant.CRUMBLED", "RocksEMC.png" }, { "emc_plant.CRUMBLED.xpos", "5" }, { "emc_plant.CRUMBLED.ypos", "4" }, { "emc_plant.CRUMBLED.frames", "1" }, { "emc_lenses", "RocksEMC.png" }, { "emc_lenses.xpos", "6" }, { "emc_lenses.ypos", "4" }, { "emc_lenses.frames", "1" }, { "emc_magnifier", "RocksEMC.png" }, { "emc_magnifier.xpos", "7" }, { "emc_magnifier.ypos", "4" }, { "emc_magnifier.frames", "1" }, { "emc_wall_9", "RocksEMC.png" }, { "emc_wall_9.xpos", "10" }, { "emc_wall_9.ypos", "5" }, { "emc_wall_9.frames", "1" }, { "emc_wall_10", "RocksEMC.png" }, { "emc_wall_10.xpos", "10" }, { "emc_wall_10.ypos", "6" }, { "emc_wall_10.frames", "1" }, { "emc_wall_11", "RocksEMC.png" }, { "emc_wall_11.xpos", "11" }, { "emc_wall_11.ypos", "5" }, { "emc_wall_11.frames", "1" }, { "emc_wall_12", "RocksEMC.png" }, { "emc_wall_12.xpos", "11" }, { "emc_wall_12.ypos", "6" }, { "emc_wall_12.frames", "1" }, { "emc_wall_13", "RocksEMC.png" }, { "emc_wall_13.xpos", "10" }, { "emc_wall_13.ypos", "7" }, { "emc_wall_13.frames", "1" }, { "emc_wall_14", "RocksEMC.png" }, { "emc_wall_14.xpos", "10" }, { "emc_wall_14.ypos", "8" }, { "emc_wall_14.frames", "1" }, { "emc_wall_15", "RocksEMC.png" }, { "emc_wall_15.xpos", "10" }, { "emc_wall_15.ypos", "9" }, { "emc_wall_15.frames", "1" }, { "emc_wall_16", "RocksEMC.png" }, { "emc_wall_16.xpos", "10" }, { "emc_wall_16.ypos", "10" }, { "emc_wall_16.frames", "1" }, { "emc_wall_slippery_1", "RocksEMC.png" }, { "emc_wall_slippery_1.xpos", "11" }, { "emc_wall_slippery_1.ypos", "7" }, { "emc_wall_slippery_1.frames", "1" }, { "emc_wall_slippery_2", "RocksEMC.png" }, { "emc_wall_slippery_2.xpos", "11" }, { "emc_wall_slippery_2.ypos", "8" }, { "emc_wall_slippery_2.frames", "1" }, { "emc_wall_slippery_3", "RocksEMC.png" }, { "emc_wall_slippery_3.xpos", "11" }, { "emc_wall_slippery_3.ypos", "9" }, { "emc_wall_slippery_3.frames", "1" }, { "emc_wall_slippery_4", "RocksEMC.png" }, { "emc_wall_slippery_4.xpos", "11" }, { "emc_wall_slippery_4.ypos", "10" }, { "emc_wall_slippery_4.frames", "1" }, { "emc_fake_grass", "RocksEMC.png" }, { "emc_fake_grass.xpos", "0" }, { "emc_fake_grass.ypos", "4" }, { "emc_fake_grass.frames", "1" }, { "emc_fake_grass.CRUMBLED", "RocksEMC.png" }, { "emc_fake_grass.CRUMBLED.xpos", "1" }, { "emc_fake_grass.CRUMBLED.ypos", "4" }, { "emc_fake_grass.CRUMBLED.frames", "1" }, { "emc_fake_grass.active", "RocksEMC.png" }, { "emc_fake_grass.active.xpos", "2" }, { "emc_fake_grass.active.ypos", "4" }, { "emc_fake_grass.active.frames", "1" }, { "emc_fake_grass.active.CRUMBLED", "RocksEMC.png" }, { "emc_fake_grass.active.CRUMBLED.xpos", "3" }, { "emc_fake_grass.active.CRUMBLED.ypos", "4" }, { "emc_fake_grass.active.CRUMBLED.frames", "1" }, { "emc_fake_grass.EDITOR", "RocksEMC.png" }, { "emc_fake_grass.EDITOR.xpos", "2" }, { "emc_fake_grass.EDITOR.ypos", "4" }, { "emc_fake_grass.EDITOR.frames", "1" }, { "emc_fake_acid", "RocksElements.png" }, { "emc_fake_acid.xpos", "12" }, { "emc_fake_acid.ypos", "7" }, { "emc_fake_acid.frames", "4" }, { "emc_fake_acid.delay", "10" }, { "emc_fake_acid.global_sync", "true" }, { "emc_dripper", "RocksSP.png" }, { "emc_dripper.xpos", "0" }, { "emc_dripper.ypos", "0" }, { "emc_dripper.frames", "1" }, { "emc_dripper.EDITOR", "RocksEMC.png" }, { "emc_dripper.EDITOR.xpos", "8" }, { "emc_dripper.EDITOR.ypos", "8" }, { "emc_dripper.active", "RocksEMC.png" }, { "emc_dripper.active.xpos", "8" }, { "emc_dripper.active.ypos", "8" }, { "emc_dripper.active.frames", "1" }, { "mm_mcduffin", "RocksMM.png" }, { "mm_mcduffin.xpos", "4" }, { "mm_mcduffin.ypos", "1" }, { "mm_mcduffin.frames", "4" }, { "mm_mcduffin.delay", "8" }, { "mm_mcduffin.right", "RocksMM.png" }, { "mm_mcduffin.right.xpos", "4" }, { "mm_mcduffin.right.ypos", "1" }, { "mm_mcduffin.right.frames", "1" }, { "mm_mcduffin.up", "RocksMM.png" }, { "mm_mcduffin.up.xpos", "5" }, { "mm_mcduffin.up.ypos", "1" }, { "mm_mcduffin.up.frames", "1" }, { "mm_mcduffin.left", "RocksMM.png" }, { "mm_mcduffin.left.xpos", "6" }, { "mm_mcduffin.left.ypos", "1" }, { "mm_mcduffin.left.frames", "1" }, { "mm_mcduffin.down", "RocksMM.png" }, { "mm_mcduffin.down.xpos", "7" }, { "mm_mcduffin.down.ypos", "1" }, { "mm_mcduffin.down.frames", "1" }, { "mm_exit_closed", "RocksMM.png" }, { "mm_exit_closed.xpos", "8" }, { "mm_exit_closed.ypos", "1" }, { "mm_exit_closed.frames", "1" }, { "mm_exit.opening", "RocksMM.png" }, { "mm_exit.opening.xpos", "8" }, { "mm_exit.opening.ypos", "1" }, { "mm_exit.opening.frames", "4" }, { "mm_exit.opening.delay", "6" }, { "mm_exit.opening.anim_mode", "linear" }, { "mm_exit_open", "RocksMM.png" }, { "mm_exit_open.xpos", "11" }, { "mm_exit_open.ypos", "1" }, { "mm_exit_open.frames", "1" }, { "mm_exit.closing", "RocksMM.png" }, { "mm_exit.closing.xpos", "8" }, { "mm_exit.closing.ypos", "1" }, { "mm_exit.closing.frames", "4" }, { "mm_exit.closing.delay", "6" }, { "mm_exit.closing.anim_mode", "linear,reverse" }, { "mm_mirror_1", "RocksMM.png" }, { "mm_mirror_1.xpos", "0" }, { "mm_mirror_1.ypos", "0" }, { "mm_mirror_1.frames", "1" }, { "mm_mirror_2", "RocksMM.png" }, { "mm_mirror_2.xpos", "1" }, { "mm_mirror_2.ypos", "0" }, { "mm_mirror_2.frames", "1" }, { "mm_mirror_3", "RocksMM.png" }, { "mm_mirror_3.xpos", "2" }, { "mm_mirror_3.ypos", "0" }, { "mm_mirror_3.frames", "1" }, { "mm_mirror_4", "RocksMM.png" }, { "mm_mirror_4.xpos", "3" }, { "mm_mirror_4.ypos", "0" }, { "mm_mirror_4.frames", "1" }, { "mm_mirror_5", "RocksMM.png" }, { "mm_mirror_5.xpos", "4" }, { "mm_mirror_5.ypos", "0" }, { "mm_mirror_5.frames", "1" }, { "mm_mirror_6", "RocksMM.png" }, { "mm_mirror_6.xpos", "5" }, { "mm_mirror_6.ypos", "0" }, { "mm_mirror_6.frames", "1" }, { "mm_mirror_7", "RocksMM.png" }, { "mm_mirror_7.xpos", "6" }, { "mm_mirror_7.ypos", "0" }, { "mm_mirror_7.frames", "1" }, { "mm_mirror_8", "RocksMM.png" }, { "mm_mirror_8.xpos", "7" }, { "mm_mirror_8.ypos", "0" }, { "mm_mirror_8.frames", "1" }, { "mm_mirror_9", "RocksMM.png" }, { "mm_mirror_9.xpos", "8" }, { "mm_mirror_9.ypos", "0" }, { "mm_mirror_9.frames", "1" }, { "mm_mirror_10", "RocksMM.png" }, { "mm_mirror_10.xpos", "9" }, { "mm_mirror_10.ypos", "0" }, { "mm_mirror_10.frames", "1" }, { "mm_mirror_11", "RocksMM.png" }, { "mm_mirror_11.xpos", "10" }, { "mm_mirror_11.ypos", "0" }, { "mm_mirror_11.frames", "1" }, { "mm_mirror_12", "RocksMM.png" }, { "mm_mirror_12.xpos", "11" }, { "mm_mirror_12.ypos", "0" }, { "mm_mirror_12.frames", "1" }, { "mm_mirror_13", "RocksMM.png" }, { "mm_mirror_13.xpos", "12" }, { "mm_mirror_13.ypos", "0" }, { "mm_mirror_13.frames", "1" }, { "mm_mirror_14", "RocksMM.png" }, { "mm_mirror_14.xpos", "13" }, { "mm_mirror_14.ypos", "0" }, { "mm_mirror_14.frames", "1" }, { "mm_mirror_15", "RocksMM.png" }, { "mm_mirror_15.xpos", "14" }, { "mm_mirror_15.ypos", "0" }, { "mm_mirror_15.frames", "1" }, { "mm_mirror_16", "RocksMM.png" }, { "mm_mirror_16.xpos", "15" }, { "mm_mirror_16.ypos", "0" }, { "mm_mirror_16.frames", "1" }, { "mm_mirror_fixed_1", "RocksMM.png" }, { "mm_mirror_fixed_1.xpos", "4" }, { "mm_mirror_fixed_1.ypos", "6" }, { "mm_mirror_fixed_1.frames", "1" }, { "mm_mirror_fixed_2", "RocksMM.png" }, { "mm_mirror_fixed_2.xpos", "5" }, { "mm_mirror_fixed_2.ypos", "6" }, { "mm_mirror_fixed_2.frames", "1" }, { "mm_mirror_fixed_3", "RocksMM.png" }, { "mm_mirror_fixed_3.xpos", "6" }, { "mm_mirror_fixed_3.ypos", "6" }, { "mm_mirror_fixed_3.frames", "1" }, { "mm_mirror_fixed_4", "RocksMM.png" }, { "mm_mirror_fixed_4.xpos", "7" }, { "mm_mirror_fixed_4.ypos", "6" }, { "mm_mirror_fixed_4.frames", "1" }, { "mm_steel_grid_fixed_1", "RocksMM.png" }, { "mm_steel_grid_fixed_1.xpos", "0" }, { "mm_steel_grid_fixed_1.ypos", "1" }, { "mm_steel_grid_fixed_1.frames", "1" }, { "mm_steel_grid_fixed_2", "RocksMM.png" }, { "mm_steel_grid_fixed_2.xpos", "1" }, { "mm_steel_grid_fixed_2.ypos", "1" }, { "mm_steel_grid_fixed_2.frames", "1" }, { "mm_steel_grid_fixed_3", "RocksMM.png" }, { "mm_steel_grid_fixed_3.xpos", "2" }, { "mm_steel_grid_fixed_3.ypos", "1" }, { "mm_steel_grid_fixed_3.frames", "1" }, { "mm_steel_grid_fixed_4", "RocksMM.png" }, { "mm_steel_grid_fixed_4.xpos", "3" }, { "mm_steel_grid_fixed_4.ypos", "1" }, { "mm_steel_grid_fixed_4.frames", "1" }, { "mm_wooden_grid_fixed_1", "RocksMM.png" }, { "mm_wooden_grid_fixed_1.xpos", "12" }, { "mm_wooden_grid_fixed_1.ypos", "6" }, { "mm_wooden_grid_fixed_1.frames", "1" }, { "mm_wooden_grid_fixed_2", "RocksMM.png" }, { "mm_wooden_grid_fixed_2.xpos", "13" }, { "mm_wooden_grid_fixed_2.ypos", "6" }, { "mm_wooden_grid_fixed_2.frames", "1" }, { "mm_wooden_grid_fixed_3", "RocksMM.png" }, { "mm_wooden_grid_fixed_3.xpos", "14" }, { "mm_wooden_grid_fixed_3.ypos", "6" }, { "mm_wooden_grid_fixed_3.frames", "1" }, { "mm_wooden_grid_fixed_4", "RocksMM.png" }, { "mm_wooden_grid_fixed_4.xpos", "15" }, { "mm_wooden_grid_fixed_4.ypos", "6" }, { "mm_wooden_grid_fixed_4.frames", "1" }, { "mm_polarizer_1", "RocksMM.png" }, { "mm_polarizer_1.xpos", "0" }, { "mm_polarizer_1.ypos", "5" }, { "mm_polarizer_1.frames", "1" }, { "mm_polarizer_2", "RocksMM.png" }, { "mm_polarizer_2.xpos", "1" }, { "mm_polarizer_2.ypos", "5" }, { "mm_polarizer_2.frames", "1" }, { "mm_polarizer_3", "RocksMM.png" }, { "mm_polarizer_3.xpos", "2" }, { "mm_polarizer_3.ypos", "5" }, { "mm_polarizer_3.frames", "1" }, { "mm_polarizer_4", "RocksMM.png" }, { "mm_polarizer_4.xpos", "3" }, { "mm_polarizer_4.ypos", "5" }, { "mm_polarizer_4.frames", "1" }, { "mm_polarizer_5", "RocksMM.png" }, { "mm_polarizer_5.xpos", "4" }, { "mm_polarizer_5.ypos", "5" }, { "mm_polarizer_5.frames", "1" }, { "mm_polarizer_6", "RocksMM.png" }, { "mm_polarizer_6.xpos", "5" }, { "mm_polarizer_6.ypos", "5" }, { "mm_polarizer_6.frames", "1" }, { "mm_polarizer_7", "RocksMM.png" }, { "mm_polarizer_7.xpos", "6" }, { "mm_polarizer_7.ypos", "5" }, { "mm_polarizer_7.frames", "1" }, { "mm_polarizer_8", "RocksMM.png" }, { "mm_polarizer_8.xpos", "7" }, { "mm_polarizer_8.ypos", "5" }, { "mm_polarizer_8.frames", "1" }, { "mm_polarizer_9", "RocksMM.png" }, { "mm_polarizer_9.xpos", "8" }, { "mm_polarizer_9.ypos", "5" }, { "mm_polarizer_9.frames", "1" }, { "mm_polarizer_10", "RocksMM.png" }, { "mm_polarizer_10.xpos", "9" }, { "mm_polarizer_10.ypos", "5" }, { "mm_polarizer_10.frames", "1" }, { "mm_polarizer_11", "RocksMM.png" }, { "mm_polarizer_11.xpos", "10" }, { "mm_polarizer_11.ypos", "5" }, { "mm_polarizer_11.frames", "1" }, { "mm_polarizer_12", "RocksMM.png" }, { "mm_polarizer_12.xpos", "11" }, { "mm_polarizer_12.ypos", "5" }, { "mm_polarizer_12.frames", "1" }, { "mm_polarizer_13", "RocksMM.png" }, { "mm_polarizer_13.xpos", "12" }, { "mm_polarizer_13.ypos", "5" }, { "mm_polarizer_13.frames", "1" }, { "mm_polarizer_14", "RocksMM.png" }, { "mm_polarizer_14.xpos", "13" }, { "mm_polarizer_14.ypos", "5" }, { "mm_polarizer_14.frames", "1" }, { "mm_polarizer_15", "RocksMM.png" }, { "mm_polarizer_15.xpos", "14" }, { "mm_polarizer_15.ypos", "5" }, { "mm_polarizer_15.frames", "1" }, { "mm_polarizer_16", "RocksMM.png" }, { "mm_polarizer_16.xpos", "15" }, { "mm_polarizer_16.ypos", "5" }, { "mm_polarizer_16.frames", "1" }, { "mm_polarizer_cross_1", "RocksMM.png" }, { "mm_polarizer_cross_1.xpos", "0" }, { "mm_polarizer_cross_1.ypos", "6" }, { "mm_polarizer_cross_1.frames", "1" }, { "mm_polarizer_cross_2", "RocksMM.png" }, { "mm_polarizer_cross_2.xpos", "1" }, { "mm_polarizer_cross_2.ypos", "6" }, { "mm_polarizer_cross_2.frames", "1" }, { "mm_polarizer_cross_3", "RocksMM.png" }, { "mm_polarizer_cross_3.xpos", "2" }, { "mm_polarizer_cross_3.ypos", "6" }, { "mm_polarizer_cross_3.frames", "1" }, { "mm_polarizer_cross_4", "RocksMM.png" }, { "mm_polarizer_cross_4.xpos", "3" }, { "mm_polarizer_cross_4.ypos", "6" }, { "mm_polarizer_cross_4.frames", "1" }, { "mm_teleporter_1", "RocksMM.png" }, { "mm_teleporter_1.xpos", "0" }, { "mm_teleporter_1.ypos", "3" }, { "mm_teleporter_1.frames", "1" }, { "mm_teleporter_2", "RocksMM.png" }, { "mm_teleporter_2.xpos", "1" }, { "mm_teleporter_2.ypos", "3" }, { "mm_teleporter_2.frames", "1" }, { "mm_teleporter_3", "RocksMM.png" }, { "mm_teleporter_3.xpos", "2" }, { "mm_teleporter_3.ypos", "3" }, { "mm_teleporter_3.frames", "1" }, { "mm_teleporter_4", "RocksMM.png" }, { "mm_teleporter_4.xpos", "3" }, { "mm_teleporter_4.ypos", "3" }, { "mm_teleporter_4.frames", "1" }, { "mm_teleporter_5", "RocksMM.png" }, { "mm_teleporter_5.xpos", "4" }, { "mm_teleporter_5.ypos", "3" }, { "mm_teleporter_5.frames", "1" }, { "mm_teleporter_6", "RocksMM.png" }, { "mm_teleporter_6.xpos", "5" }, { "mm_teleporter_6.ypos", "3" }, { "mm_teleporter_6.frames", "1" }, { "mm_teleporter_7", "RocksMM.png" }, { "mm_teleporter_7.xpos", "6" }, { "mm_teleporter_7.ypos", "3" }, { "mm_teleporter_7.frames", "1" }, { "mm_teleporter_8", "RocksMM.png" }, { "mm_teleporter_8.xpos", "7" }, { "mm_teleporter_8.ypos", "3" }, { "mm_teleporter_8.frames", "1" }, { "mm_teleporter_9", "RocksMM.png" }, { "mm_teleporter_9.xpos", "8" }, { "mm_teleporter_9.ypos", "3" }, { "mm_teleporter_9.frames", "1" }, { "mm_teleporter_10", "RocksMM.png" }, { "mm_teleporter_10.xpos", "9" }, { "mm_teleporter_10.ypos", "3" }, { "mm_teleporter_10.frames", "1" }, { "mm_teleporter_11", "RocksMM.png" }, { "mm_teleporter_11.xpos", "10" }, { "mm_teleporter_11.ypos", "3" }, { "mm_teleporter_11.frames", "1" }, { "mm_teleporter_12", "RocksMM.png" }, { "mm_teleporter_12.xpos", "11" }, { "mm_teleporter_12.ypos", "3" }, { "mm_teleporter_12.frames", "1" }, { "mm_teleporter_13", "RocksMM.png" }, { "mm_teleporter_13.xpos", "12" }, { "mm_teleporter_13.ypos", "3" }, { "mm_teleporter_13.frames", "1" }, { "mm_teleporter_14", "RocksMM.png" }, { "mm_teleporter_14.xpos", "13" }, { "mm_teleporter_14.ypos", "3" }, { "mm_teleporter_14.frames", "1" }, { "mm_teleporter_15", "RocksMM.png" }, { "mm_teleporter_15.xpos", "14" }, { "mm_teleporter_15.ypos", "3" }, { "mm_teleporter_15.frames", "1" }, { "mm_teleporter_16", "RocksMM.png" }, { "mm_teleporter_16.xpos", "15" }, { "mm_teleporter_16.ypos", "3" }, { "mm_teleporter_16.frames", "1" }, { "mm_teleporter_red_1", "RocksDF.png" }, { "mm_teleporter_red_1.xpos", "0" }, { "mm_teleporter_red_1.ypos", "4" }, { "mm_teleporter_red_1.frames", "1" }, { "mm_teleporter_red_2", "RocksDF.png" }, { "mm_teleporter_red_2.xpos", "1" }, { "mm_teleporter_red_2.ypos", "4" }, { "mm_teleporter_red_2.frames", "1" }, { "mm_teleporter_red_3", "RocksDF.png" }, { "mm_teleporter_red_3.xpos", "2" }, { "mm_teleporter_red_3.ypos", "4" }, { "mm_teleporter_red_3.frames", "1" }, { "mm_teleporter_red_4", "RocksDF.png" }, { "mm_teleporter_red_4.xpos", "3" }, { "mm_teleporter_red_4.ypos", "4" }, { "mm_teleporter_red_4.frames", "1" }, { "mm_teleporter_red_5", "RocksDF.png" }, { "mm_teleporter_red_5.xpos", "4" }, { "mm_teleporter_red_5.ypos", "4" }, { "mm_teleporter_red_5.frames", "1" }, { "mm_teleporter_red_6", "RocksDF.png" }, { "mm_teleporter_red_6.xpos", "5" }, { "mm_teleporter_red_6.ypos", "4" }, { "mm_teleporter_red_6.frames", "1" }, { "mm_teleporter_red_7", "RocksDF.png" }, { "mm_teleporter_red_7.xpos", "6" }, { "mm_teleporter_red_7.ypos", "4" }, { "mm_teleporter_red_7.frames", "1" }, { "mm_teleporter_red_8", "RocksDF.png" }, { "mm_teleporter_red_8.xpos", "7" }, { "mm_teleporter_red_8.ypos", "4" }, { "mm_teleporter_red_8.frames", "1" }, { "mm_teleporter_red_9", "RocksDF.png" }, { "mm_teleporter_red_9.xpos", "8" }, { "mm_teleporter_red_9.ypos", "4" }, { "mm_teleporter_red_9.frames", "1" }, { "mm_teleporter_red_10", "RocksDF.png" }, { "mm_teleporter_red_10.xpos", "9" }, { "mm_teleporter_red_10.ypos", "4" }, { "mm_teleporter_red_10.frames", "1" }, { "mm_teleporter_red_11", "RocksDF.png" }, { "mm_teleporter_red_11.xpos", "10" }, { "mm_teleporter_red_11.ypos", "4" }, { "mm_teleporter_red_11.frames", "1" }, { "mm_teleporter_red_12", "RocksDF.png" }, { "mm_teleporter_red_12.xpos", "11" }, { "mm_teleporter_red_12.ypos", "4" }, { "mm_teleporter_red_12.frames", "1" }, { "mm_teleporter_red_13", "RocksDF.png" }, { "mm_teleporter_red_13.xpos", "12" }, { "mm_teleporter_red_13.ypos", "4" }, { "mm_teleporter_red_13.frames", "1" }, { "mm_teleporter_red_14", "RocksDF.png" }, { "mm_teleporter_red_14.xpos", "13" }, { "mm_teleporter_red_14.ypos", "4" }, { "mm_teleporter_red_14.frames", "1" }, { "mm_teleporter_red_15", "RocksDF.png" }, { "mm_teleporter_red_15.xpos", "14" }, { "mm_teleporter_red_15.ypos", "4" }, { "mm_teleporter_red_15.frames", "1" }, { "mm_teleporter_red_16", "RocksDF.png" }, { "mm_teleporter_red_16.xpos", "15" }, { "mm_teleporter_red_16.ypos", "4" }, { "mm_teleporter_red_16.frames", "1" }, { "mm_teleporter_yellow_1", "RocksDF.png" }, { "mm_teleporter_yellow_1.xpos", "0" }, { "mm_teleporter_yellow_1.ypos", "5" }, { "mm_teleporter_yellow_1.frames", "1" }, { "mm_teleporter_yellow_2", "RocksDF.png" }, { "mm_teleporter_yellow_2.xpos", "1" }, { "mm_teleporter_yellow_2.ypos", "5" }, { "mm_teleporter_yellow_2.frames", "1" }, { "mm_teleporter_yellow_3", "RocksDF.png" }, { "mm_teleporter_yellow_3.xpos", "2" }, { "mm_teleporter_yellow_3.ypos", "5" }, { "mm_teleporter_yellow_3.frames", "1" }, { "mm_teleporter_yellow_4", "RocksDF.png" }, { "mm_teleporter_yellow_4.xpos", "3" }, { "mm_teleporter_yellow_4.ypos", "5" }, { "mm_teleporter_yellow_4.frames", "1" }, { "mm_teleporter_yellow_5", "RocksDF.png" }, { "mm_teleporter_yellow_5.xpos", "4" }, { "mm_teleporter_yellow_5.ypos", "5" }, { "mm_teleporter_yellow_5.frames", "1" }, { "mm_teleporter_yellow_6", "RocksDF.png" }, { "mm_teleporter_yellow_6.xpos", "5" }, { "mm_teleporter_yellow_6.ypos", "5" }, { "mm_teleporter_yellow_6.frames", "1" }, { "mm_teleporter_yellow_7", "RocksDF.png" }, { "mm_teleporter_yellow_7.xpos", "6" }, { "mm_teleporter_yellow_7.ypos", "5" }, { "mm_teleporter_yellow_7.frames", "1" }, { "mm_teleporter_yellow_8", "RocksDF.png" }, { "mm_teleporter_yellow_8.xpos", "7" }, { "mm_teleporter_yellow_8.ypos", "5" }, { "mm_teleporter_yellow_8.frames", "1" }, { "mm_teleporter_yellow_9", "RocksDF.png" }, { "mm_teleporter_yellow_9.xpos", "8" }, { "mm_teleporter_yellow_9.ypos", "5" }, { "mm_teleporter_yellow_9.frames", "1" }, { "mm_teleporter_yellow_10", "RocksDF.png" }, { "mm_teleporter_yellow_10.xpos", "9" }, { "mm_teleporter_yellow_10.ypos", "5" }, { "mm_teleporter_yellow_10.frames", "1" }, { "mm_teleporter_yellow_11", "RocksDF.png" }, { "mm_teleporter_yellow_11.xpos", "10" }, { "mm_teleporter_yellow_11.ypos", "5" }, { "mm_teleporter_yellow_11.frames", "1" }, { "mm_teleporter_yellow_12", "RocksDF.png" }, { "mm_teleporter_yellow_12.xpos", "11" }, { "mm_teleporter_yellow_12.ypos", "5" }, { "mm_teleporter_yellow_12.frames", "1" }, { "mm_teleporter_yellow_13", "RocksDF.png" }, { "mm_teleporter_yellow_13.xpos", "12" }, { "mm_teleporter_yellow_13.ypos", "5" }, { "mm_teleporter_yellow_13.frames", "1" }, { "mm_teleporter_yellow_14", "RocksDF.png" }, { "mm_teleporter_yellow_14.xpos", "13" }, { "mm_teleporter_yellow_14.ypos", "5" }, { "mm_teleporter_yellow_14.frames", "1" }, { "mm_teleporter_yellow_15", "RocksDF.png" }, { "mm_teleporter_yellow_15.xpos", "14" }, { "mm_teleporter_yellow_15.ypos", "5" }, { "mm_teleporter_yellow_15.frames", "1" }, { "mm_teleporter_yellow_16", "RocksDF.png" }, { "mm_teleporter_yellow_16.xpos", "15" }, { "mm_teleporter_yellow_16.ypos", "5" }, { "mm_teleporter_yellow_16.frames", "1" }, { "mm_teleporter_green_1", "RocksDF.png" }, { "mm_teleporter_green_1.xpos", "0" }, { "mm_teleporter_green_1.ypos", "6" }, { "mm_teleporter_green_1.frames", "1" }, { "mm_teleporter_green_2", "RocksDF.png" }, { "mm_teleporter_green_2.xpos", "1" }, { "mm_teleporter_green_2.ypos", "6" }, { "mm_teleporter_green_2.frames", "1" }, { "mm_teleporter_green_3", "RocksDF.png" }, { "mm_teleporter_green_3.xpos", "2" }, { "mm_teleporter_green_3.ypos", "6" }, { "mm_teleporter_green_3.frames", "1" }, { "mm_teleporter_green_4", "RocksDF.png" }, { "mm_teleporter_green_4.xpos", "3" }, { "mm_teleporter_green_4.ypos", "6" }, { "mm_teleporter_green_4.frames", "1" }, { "mm_teleporter_green_5", "RocksDF.png" }, { "mm_teleporter_green_5.xpos", "4" }, { "mm_teleporter_green_5.ypos", "6" }, { "mm_teleporter_green_5.frames", "1" }, { "mm_teleporter_green_6", "RocksDF.png" }, { "mm_teleporter_green_6.xpos", "5" }, { "mm_teleporter_green_6.ypos", "6" }, { "mm_teleporter_green_6.frames", "1" }, { "mm_teleporter_green_7", "RocksDF.png" }, { "mm_teleporter_green_7.xpos", "6" }, { "mm_teleporter_green_7.ypos", "6" }, { "mm_teleporter_green_7.frames", "1" }, { "mm_teleporter_green_8", "RocksDF.png" }, { "mm_teleporter_green_8.xpos", "7" }, { "mm_teleporter_green_8.ypos", "6" }, { "mm_teleporter_green_8.frames", "1" }, { "mm_teleporter_green_9", "RocksDF.png" }, { "mm_teleporter_green_9.xpos", "8" }, { "mm_teleporter_green_9.ypos", "6" }, { "mm_teleporter_green_9.frames", "1" }, { "mm_teleporter_green_10", "RocksDF.png" }, { "mm_teleporter_green_10.xpos", "9" }, { "mm_teleporter_green_10.ypos", "6" }, { "mm_teleporter_green_10.frames", "1" }, { "mm_teleporter_green_11", "RocksDF.png" }, { "mm_teleporter_green_11.xpos", "10" }, { "mm_teleporter_green_11.ypos", "6" }, { "mm_teleporter_green_11.frames", "1" }, { "mm_teleporter_green_12", "RocksDF.png" }, { "mm_teleporter_green_12.xpos", "11" }, { "mm_teleporter_green_12.ypos", "6" }, { "mm_teleporter_green_12.frames", "1" }, { "mm_teleporter_green_13", "RocksDF.png" }, { "mm_teleporter_green_13.xpos", "12" }, { "mm_teleporter_green_13.ypos", "6" }, { "mm_teleporter_green_13.frames", "1" }, { "mm_teleporter_green_14", "RocksDF.png" }, { "mm_teleporter_green_14.xpos", "13" }, { "mm_teleporter_green_14.ypos", "6" }, { "mm_teleporter_green_14.frames", "1" }, { "mm_teleporter_green_15", "RocksDF.png" }, { "mm_teleporter_green_15.xpos", "14" }, { "mm_teleporter_green_15.ypos", "6" }, { "mm_teleporter_green_15.frames", "1" }, { "mm_teleporter_green_16", "RocksDF.png" }, { "mm_teleporter_green_16.xpos", "15" }, { "mm_teleporter_green_16.ypos", "6" }, { "mm_teleporter_green_16.frames", "1" }, { "mm_teleporter_blue_1", "RocksDF.png" }, { "mm_teleporter_blue_1.xpos", "0" }, { "mm_teleporter_blue_1.ypos", "7" }, { "mm_teleporter_blue_1.frames", "1" }, { "mm_teleporter_blue_2", "RocksDF.png" }, { "mm_teleporter_blue_2.xpos", "1" }, { "mm_teleporter_blue_2.ypos", "7" }, { "mm_teleporter_blue_2.frames", "1" }, { "mm_teleporter_blue_3", "RocksDF.png" }, { "mm_teleporter_blue_3.xpos", "2" }, { "mm_teleporter_blue_3.ypos", "7" }, { "mm_teleporter_blue_3.frames", "1" }, { "mm_teleporter_blue_4", "RocksDF.png" }, { "mm_teleporter_blue_4.xpos", "3" }, { "mm_teleporter_blue_4.ypos", "7" }, { "mm_teleporter_blue_4.frames", "1" }, { "mm_teleporter_blue_5", "RocksDF.png" }, { "mm_teleporter_blue_5.xpos", "4" }, { "mm_teleporter_blue_5.ypos", "7" }, { "mm_teleporter_blue_5.frames", "1" }, { "mm_teleporter_blue_6", "RocksDF.png" }, { "mm_teleporter_blue_6.xpos", "5" }, { "mm_teleporter_blue_6.ypos", "7" }, { "mm_teleporter_blue_6.frames", "1" }, { "mm_teleporter_blue_7", "RocksDF.png" }, { "mm_teleporter_blue_7.xpos", "6" }, { "mm_teleporter_blue_7.ypos", "7" }, { "mm_teleporter_blue_7.frames", "1" }, { "mm_teleporter_blue_8", "RocksDF.png" }, { "mm_teleporter_blue_8.xpos", "7" }, { "mm_teleporter_blue_8.ypos", "7" }, { "mm_teleporter_blue_8.frames", "1" }, { "mm_teleporter_blue_9", "RocksDF.png" }, { "mm_teleporter_blue_9.xpos", "8" }, { "mm_teleporter_blue_9.ypos", "7" }, { "mm_teleporter_blue_9.frames", "1" }, { "mm_teleporter_blue_10", "RocksDF.png" }, { "mm_teleporter_blue_10.xpos", "9" }, { "mm_teleporter_blue_10.ypos", "7" }, { "mm_teleporter_blue_10.frames", "1" }, { "mm_teleporter_blue_11", "RocksDF.png" }, { "mm_teleporter_blue_11.xpos", "10" }, { "mm_teleporter_blue_11.ypos", "7" }, { "mm_teleporter_blue_11.frames", "1" }, { "mm_teleporter_blue_12", "RocksDF.png" }, { "mm_teleporter_blue_12.xpos", "11" }, { "mm_teleporter_blue_12.ypos", "7" }, { "mm_teleporter_blue_12.frames", "1" }, { "mm_teleporter_blue_13", "RocksDF.png" }, { "mm_teleporter_blue_13.xpos", "12" }, { "mm_teleporter_blue_13.ypos", "7" }, { "mm_teleporter_blue_13.frames", "1" }, { "mm_teleporter_blue_14", "RocksDF.png" }, { "mm_teleporter_blue_14.xpos", "13" }, { "mm_teleporter_blue_14.ypos", "7" }, { "mm_teleporter_blue_14.frames", "1" }, { "mm_teleporter_blue_15", "RocksDF.png" }, { "mm_teleporter_blue_15.xpos", "14" }, { "mm_teleporter_blue_15.ypos", "7" }, { "mm_teleporter_blue_15.frames", "1" }, { "mm_teleporter_blue_16", "RocksDF.png" }, { "mm_teleporter_blue_16.xpos", "15" }, { "mm_teleporter_blue_16.ypos", "7" }, { "mm_teleporter_blue_16.frames", "1" }, { "mm_kettle", "RocksMM.png" }, { "mm_kettle.xpos", "12" }, { "mm_kettle.ypos", "1" }, { "mm_kettle.frames", "1" }, { "mm_kettle.exploding", "RocksMM.png" }, { "mm_kettle.exploding.xpos", "13" }, { "mm_kettle.exploding.ypos", "1" }, { "mm_kettle.exploding.frames", "3" }, { "mm_kettle.exploding.delay", "4" }, { "mm_kettle.exploding.anim_mode", "linear" }, { "mm_bomb", "RocksMM.png" }, { "mm_bomb.xpos", "5" }, { "mm_bomb.ypos", "2" }, { "mm_bomb.frames", "1" }, { "mm_prism", "RocksMM.png" }, { "mm_prism.xpos", "0" }, { "mm_prism.ypos", "2" }, { "mm_prism.frames", "1" }, { "mm_fuse", "RocksMM.png" }, { "mm_fuse.xpos", "7" }, { "mm_fuse.ypos", "2" }, { "mm_fuse.frames", "1" }, { "mm_fuse.active", "RocksMM.png" }, { "mm_fuse.active.xpos", "6" }, { "mm_fuse.active.ypos", "2" }, { "mm_fuse.active.frames", "1" }, { "mm_steel_lock", "RocksMM.png" }, { "mm_steel_lock.xpos", "8" }, { "mm_steel_lock.ypos", "2" }, { "mm_steel_lock.frames", "1" }, { "mm_wooden_lock", "RocksMM.png" }, { "mm_wooden_lock.xpos", "9" }, { "mm_wooden_lock.ypos", "6" }, { "mm_wooden_lock.frames", "1" }, { "mm_steel_block", "RocksMM.png" }, { "mm_steel_block.xpos", "8" }, { "mm_steel_block.ypos", "6" }, { "mm_steel_block.frames", "1" }, { "mm_wooden_block", "RocksMM.png" }, { "mm_wooden_block.xpos", "4" }, { "mm_wooden_block.ypos", "2" }, { "mm_wooden_block.frames", "1" }, { "mm_key", "RocksMM.png" }, { "mm_key.xpos", "9" }, { "mm_key.ypos", "2" }, { "mm_key.frames", "1" }, { "mm_lightbulb", "RocksMM.png" }, { "mm_lightbulb.xpos", "10" }, { "mm_lightbulb.ypos", "2" }, { "mm_lightbulb.frames", "1" }, { "mm_lightbulb.active", "RocksMM.png" }, { "mm_lightbulb.active.xpos", "11" }, { "mm_lightbulb.active.ypos", "2" }, { "mm_lightbulb.active.frames", "1" }, { "mm_lightball", "RocksMM.png" }, { "mm_lightball.xpos", "12" }, { "mm_lightball.ypos", "2" }, { "mm_lightball.frames", "3" }, { "mm_lightball.delay", "1000000" }, { "mm_lightball.anim_mode", "random" }, { "mm_lightball_red", "RocksMM.png" }, { "mm_lightball_red.xpos", "12" }, { "mm_lightball_red.ypos", "2" }, { "mm_lightball_red.frames", "1" }, { "mm_lightball_blue", "RocksMM.png" }, { "mm_lightball_blue.xpos", "13" }, { "mm_lightball_blue.ypos", "2" }, { "mm_lightball_blue.frames", "1" }, { "mm_lightball_yellow", "RocksMM.png" }, { "mm_lightball_yellow.xpos", "14" }, { "mm_lightball_yellow.ypos", "2" }, { "mm_lightball_yellow.frames", "1" }, { "mm_gray_ball", "RocksMM.png" }, { "mm_gray_ball.xpos", "15" }, { "mm_gray_ball.ypos", "2" }, { "mm_gray_ball.frames", "1" }, { "mm_fuel_full", "RocksMM.png" }, { "mm_fuel_full.xpos", "10" }, { "mm_fuel_full.ypos", "6" }, { "mm_fuel_full.frames", "1" }, { "mm_fuel_empty", "RocksMM.png" }, { "mm_fuel_empty.xpos", "11" }, { "mm_fuel_empty.ypos", "6" }, { "mm_fuel_empty.frames", "1" }, { "mm_steel_wall", "RocksMM.png" }, { "mm_steel_wall.xpos", "0" }, { "mm_steel_wall.ypos", "7" }, { "mm_steel_wall.frames", "1" }, { "mm_wooden_wall", "RocksMM.png" }, { "mm_wooden_wall.xpos", "1" }, { "mm_wooden_wall.ypos", "7" }, { "mm_wooden_wall.frames", "1" }, { "mm_ice_wall", "RocksMM.png" }, { "mm_ice_wall.xpos", "2" }, { "mm_ice_wall.ypos", "7" }, { "mm_ice_wall.frames", "1" }, { "mm_ice_wall.shrinking", "RocksMM.png" }, { "mm_ice_wall.shrinking.xpos", "2" }, { "mm_ice_wall.shrinking.ypos", "7" }, { "mm_ice_wall.shrinking.frames", "5" }, { "mm_ice_wall.shrinking.delay", "8" }, { "mm_ice_wall.shrinking.anim_mode", "linear" }, { "mm_amoeba_wall", "RocksMM.png" }, { "mm_amoeba_wall.xpos", "8" }, { "mm_amoeba_wall.ypos", "7" }, { "mm_amoeba_wall.frames", "1" }, { "mm_amoeba_wall.growing", "RocksMM.png" }, { "mm_amoeba_wall.growing.xpos", "8" }, { "mm_amoeba_wall.growing.ypos", "7" }, { "mm_amoeba_wall.growing.frames", "5" }, { "mm_amoeba_wall.growing.delay", "8" }, { "mm_amoeba_wall.growing.anim_mode", "linear,reverse" }, { "mm_pacman", "RocksMM.png" }, { "mm_pacman.xpos", "0" }, { "mm_pacman.ypos", "4" }, { "mm_pacman.frames", "1" }, { "mm_pacman.right", "RocksMM.png" }, { "mm_pacman.right.xpos", "0" }, { "mm_pacman.right.ypos", "4" }, { "mm_pacman.right.frames", "1" }, { "mm_pacman.up", "RocksMM.png" }, { "mm_pacman.up.xpos", "1" }, { "mm_pacman.up.ypos", "4" }, { "mm_pacman.up.frames", "1" }, { "mm_pacman.left", "RocksMM.png" }, { "mm_pacman.left.xpos", "2" }, { "mm_pacman.left.ypos", "4" }, { "mm_pacman.left.frames", "1" }, { "mm_pacman.down", "RocksMM.png" }, { "mm_pacman.down.xpos", "3" }, { "mm_pacman.down.ypos", "4" }, { "mm_pacman.down.frames", "1" }, { "mm_pacman.eating.right", "RocksMM.png" }, { "mm_pacman.eating.right.xpos", "4" }, { "mm_pacman.eating.right.ypos", "4" }, { "mm_pacman.eating.right.frames", "1" }, { "mm_pacman.eating.up", "RocksMM.png" }, { "mm_pacman.eating.up.xpos", "5" }, { "mm_pacman.eating.up.ypos", "4" }, { "mm_pacman.eating.up.frames", "1" }, { "mm_pacman.eating.left", "RocksMM.png" }, { "mm_pacman.eating.left.xpos", "6" }, { "mm_pacman.eating.left.ypos", "4" }, { "mm_pacman.eating.left.frames", "1" }, { "mm_pacman.eating.down", "RocksMM.png" }, { "mm_pacman.eating.down.xpos", "7" }, { "mm_pacman.eating.down.ypos", "4" }, { "mm_pacman.eating.down.frames", "1" }, { "mm_mask_mcduffin.right", "RocksMM.png" }, { "mm_mask_mcduffin.right.xpos", "8" }, { "mm_mask_mcduffin.right.ypos", "8" }, { "mm_mask_mcduffin.right.frames", "1" }, { "mm_mask_mcduffin.up", "RocksMM.png" }, { "mm_mask_mcduffin.up.xpos", "9" }, { "mm_mask_mcduffin.up.ypos", "8" }, { "mm_mask_mcduffin.up.frames", "1" }, { "mm_mask_mcduffin.left", "RocksMM.png" }, { "mm_mask_mcduffin.left.xpos", "10" }, { "mm_mask_mcduffin.left.ypos", "8" }, { "mm_mask_mcduffin.left.frames", "1" }, { "mm_mask_mcduffin.down", "RocksMM.png" }, { "mm_mask_mcduffin.down.xpos", "11" }, { "mm_mask_mcduffin.down.ypos", "8" }, { "mm_mask_mcduffin.down.frames", "1" }, { "mm_mask_grid_1", "RocksMM.png" }, { "mm_mask_grid_1.xpos", "4" }, { "mm_mask_grid_1.ypos", "8" }, { "mm_mask_grid_1.frames", "1" }, { "mm_mask_grid_2", "RocksMM.png" }, { "mm_mask_grid_2.xpos", "5" }, { "mm_mask_grid_2.ypos", "8" }, { "mm_mask_grid_2.frames", "1" }, { "mm_mask_grid_3", "RocksMM.png" }, { "mm_mask_grid_3.xpos", "6" }, { "mm_mask_grid_3.ypos", "8" }, { "mm_mask_grid_3.frames", "1" }, { "mm_mask_grid_4", "RocksMM.png" }, { "mm_mask_grid_4.xpos", "7" }, { "mm_mask_grid_4.ypos", "8" }, { "mm_mask_grid_4.frames", "1" }, { "mm_mask_rectangle", "RocksMM.png" }, { "mm_mask_rectangle.xpos", "1" }, { "mm_mask_rectangle.ypos", "8" }, { "mm_mask_rectangle.frames", "1" }, { "mm_mask_circle", "RocksMM.png" }, { "mm_mask_circle.xpos", "0" }, { "mm_mask_circle.ypos", "8" }, { "mm_mask_circle.frames", "1" }, { "[mm_default].exploding", "RocksMM.png" }, { "[mm_default].exploding.xpos", "8" }, { "[mm_default].exploding.ypos", "4" }, { "[mm_default].exploding.frames", "8" }, { "[mm_default].exploding.delay", "2" }, { "[mm_default].exploding.anim_mode", "linear" }, { "df_laser", "RocksDF.png" }, { "df_laser.xpos", "0" }, { "df_laser.ypos", "9" }, { "df_laser.frames", "4" }, { "df_laser.delay", "8" }, { "df_laser.right", "RocksDF.png" }, { "df_laser.right.xpos", "0" }, { "df_laser.right.ypos", "9" }, { "df_laser.right.frames", "1" }, { "df_laser.up", "RocksDF.png" }, { "df_laser.up.xpos", "1" }, { "df_laser.up.ypos", "9" }, { "df_laser.up.frames", "1" }, { "df_laser.left", "RocksDF.png" }, { "df_laser.left.xpos", "2" }, { "df_laser.left.ypos", "9" }, { "df_laser.left.frames", "1" }, { "df_laser.down", "RocksDF.png" }, { "df_laser.down.xpos", "3" }, { "df_laser.down.ypos", "9" }, { "df_laser.down.frames", "1" }, { "df_receiver", "RocksDF.png" }, { "df_receiver.xpos", "4" }, { "df_receiver.ypos", "9" }, { "df_receiver.frames", "4" }, { "df_receiver.delay", "8" }, { "df_receiver.right", "RocksDF.png" }, { "df_receiver.right.xpos", "4" }, { "df_receiver.right.ypos", "9" }, { "df_receiver.right.frames", "1" }, { "df_receiver.up", "RocksDF.png" }, { "df_receiver.up.xpos", "5" }, { "df_receiver.up.ypos", "9" }, { "df_receiver.up.frames", "1" }, { "df_receiver.left", "RocksDF.png" }, { "df_receiver.left.xpos", "6" }, { "df_receiver.left.ypos", "9" }, { "df_receiver.left.frames", "1" }, { "df_receiver.down", "RocksDF.png" }, { "df_receiver.down.xpos", "7" }, { "df_receiver.down.ypos", "9" }, { "df_receiver.down.frames", "1" }, { "df_mirror_1", "RocksDF.png" }, { "df_mirror_1.xpos", "0" }, { "df_mirror_1.ypos", "0" }, { "df_mirror_1.frames", "1" }, { "df_mirror_2", "RocksDF.png" }, { "df_mirror_2.xpos", "1" }, { "df_mirror_2.ypos", "0" }, { "df_mirror_2.frames", "1" }, { "df_mirror_3", "RocksDF.png" }, { "df_mirror_3.xpos", "2" }, { "df_mirror_3.ypos", "0" }, { "df_mirror_3.frames", "1" }, { "df_mirror_4", "RocksDF.png" }, { "df_mirror_4.xpos", "3" }, { "df_mirror_4.ypos", "0" }, { "df_mirror_4.frames", "1" }, { "df_mirror_5", "RocksDF.png" }, { "df_mirror_5.xpos", "4" }, { "df_mirror_5.ypos", "0" }, { "df_mirror_5.frames", "1" }, { "df_mirror_6", "RocksDF.png" }, { "df_mirror_6.xpos", "5" }, { "df_mirror_6.ypos", "0" }, { "df_mirror_6.frames", "1" }, { "df_mirror_7", "RocksDF.png" }, { "df_mirror_7.xpos", "6" }, { "df_mirror_7.ypos", "0" }, { "df_mirror_7.frames", "1" }, { "df_mirror_8", "RocksDF.png" }, { "df_mirror_8.xpos", "7" }, { "df_mirror_8.ypos", "0" }, { "df_mirror_8.frames", "1" }, { "df_mirror_9", "RocksDF.png" }, { "df_mirror_9.xpos", "8" }, { "df_mirror_9.ypos", "0" }, { "df_mirror_9.frames", "1" }, { "df_mirror_10", "RocksDF.png" }, { "df_mirror_10.xpos", "9" }, { "df_mirror_10.ypos", "0" }, { "df_mirror_10.frames", "1" }, { "df_mirror_11", "RocksDF.png" }, { "df_mirror_11.xpos", "10" }, { "df_mirror_11.ypos", "0" }, { "df_mirror_11.frames", "1" }, { "df_mirror_12", "RocksDF.png" }, { "df_mirror_12.xpos", "11" }, { "df_mirror_12.ypos", "0" }, { "df_mirror_12.frames", "1" }, { "df_mirror_13", "RocksDF.png" }, { "df_mirror_13.xpos", "12" }, { "df_mirror_13.ypos", "0" }, { "df_mirror_13.frames", "1" }, { "df_mirror_14", "RocksDF.png" }, { "df_mirror_14.xpos", "13" }, { "df_mirror_14.ypos", "0" }, { "df_mirror_14.frames", "1" }, { "df_mirror_15", "RocksDF.png" }, { "df_mirror_15.xpos", "14" }, { "df_mirror_15.ypos", "0" }, { "df_mirror_15.frames", "1" }, { "df_mirror_16", "RocksDF.png" }, { "df_mirror_16.xpos", "15" }, { "df_mirror_16.ypos", "0" }, { "df_mirror_16.frames", "1" }, { "df_mirror_rotating_1", "RocksDF.png" }, { "df_mirror_rotating_1.xpos", "0" }, { "df_mirror_rotating_1.ypos", "0" }, { "df_mirror_rotating_1.frames", "1" }, { "df_mirror_rotating_1.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_1.EDITOR.xpos", "0" }, { "df_mirror_rotating_1.EDITOR.ypos", "1" }, { "df_mirror_rotating_1.EDITOR.frames", "1" }, { "df_mirror_rotating_2", "RocksDF.png" }, { "df_mirror_rotating_2.xpos", "1" }, { "df_mirror_rotating_2.ypos", "0" }, { "df_mirror_rotating_2.frames", "1" }, { "df_mirror_rotating_2.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_2.EDITOR.xpos", "1" }, { "df_mirror_rotating_2.EDITOR.ypos", "1" }, { "df_mirror_rotating_2.EDITOR.frames", "1" }, { "df_mirror_rotating_3", "RocksDF.png" }, { "df_mirror_rotating_3.xpos", "2" }, { "df_mirror_rotating_3.ypos", "0" }, { "df_mirror_rotating_3.frames", "1" }, { "df_mirror_rotating_3.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_3.EDITOR.xpos", "2" }, { "df_mirror_rotating_3.EDITOR.ypos", "1" }, { "df_mirror_rotating_3.EDITOR.frames", "1" }, { "df_mirror_rotating_4", "RocksDF.png" }, { "df_mirror_rotating_4.xpos", "3" }, { "df_mirror_rotating_4.ypos", "0" }, { "df_mirror_rotating_4.frames", "1" }, { "df_mirror_rotating_4.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_4.EDITOR.xpos", "3" }, { "df_mirror_rotating_4.EDITOR.ypos", "1" }, { "df_mirror_rotating_4.EDITOR.frames", "1" }, { "df_mirror_rotating_5", "RocksDF.png" }, { "df_mirror_rotating_5.xpos", "4" }, { "df_mirror_rotating_5.ypos", "0" }, { "df_mirror_rotating_5.frames", "1" }, { "df_mirror_rotating_5.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_5.EDITOR.xpos", "4" }, { "df_mirror_rotating_5.EDITOR.ypos", "1" }, { "df_mirror_rotating_5.EDITOR.frames", "1" }, { "df_mirror_rotating_6", "RocksDF.png" }, { "df_mirror_rotating_6.xpos", "5" }, { "df_mirror_rotating_6.ypos", "0" }, { "df_mirror_rotating_6.frames", "1" }, { "df_mirror_rotating_6.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_6.EDITOR.xpos", "5" }, { "df_mirror_rotating_6.EDITOR.ypos", "1" }, { "df_mirror_rotating_6.EDITOR.frames", "1" }, { "df_mirror_rotating_7", "RocksDF.png" }, { "df_mirror_rotating_7.xpos", "6" }, { "df_mirror_rotating_7.ypos", "0" }, { "df_mirror_rotating_7.frames", "1" }, { "df_mirror_rotating_7.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_7.EDITOR.xpos", "6" }, { "df_mirror_rotating_7.EDITOR.ypos", "1" }, { "df_mirror_rotating_7.EDITOR.frames", "1" }, { "df_mirror_rotating_8", "RocksDF.png" }, { "df_mirror_rotating_8.xpos", "7" }, { "df_mirror_rotating_8.ypos", "0" }, { "df_mirror_rotating_8.frames", "1" }, { "df_mirror_rotating_8.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_8.EDITOR.xpos", "7" }, { "df_mirror_rotating_8.EDITOR.ypos", "1" }, { "df_mirror_rotating_8.EDITOR.frames", "1" }, { "df_mirror_rotating_9", "RocksDF.png" }, { "df_mirror_rotating_9.xpos", "8" }, { "df_mirror_rotating_9.ypos", "0" }, { "df_mirror_rotating_9.frames", "1" }, { "df_mirror_rotating_9.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_9.EDITOR.xpos", "8" }, { "df_mirror_rotating_9.EDITOR.ypos", "1" }, { "df_mirror_rotating_9.EDITOR.frames", "1" }, { "df_mirror_rotating_10", "RocksDF.png" }, { "df_mirror_rotating_10.xpos", "9" }, { "df_mirror_rotating_10.ypos", "0" }, { "df_mirror_rotating_10.frames", "1" }, { "df_mirror_rotating_10.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_10.EDITOR.xpos", "9" }, { "df_mirror_rotating_10.EDITOR.ypos", "1" }, { "df_mirror_rotating_10.EDITOR.frames", "1" }, { "df_mirror_rotating_11", "RocksDF.png" }, { "df_mirror_rotating_11.xpos", "10" }, { "df_mirror_rotating_11.ypos", "0" }, { "df_mirror_rotating_11.frames", "1" }, { "df_mirror_rotating_11.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_11.EDITOR.xpos", "10" }, { "df_mirror_rotating_11.EDITOR.ypos", "1" }, { "df_mirror_rotating_11.EDITOR.frames", "1" }, { "df_mirror_rotating_12", "RocksDF.png" }, { "df_mirror_rotating_12.xpos", "11" }, { "df_mirror_rotating_12.ypos", "0" }, { "df_mirror_rotating_12.frames", "1" }, { "df_mirror_rotating_12.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_12.EDITOR.xpos", "11" }, { "df_mirror_rotating_12.EDITOR.ypos", "1" }, { "df_mirror_rotating_12.EDITOR.frames", "1" }, { "df_mirror_rotating_13", "RocksDF.png" }, { "df_mirror_rotating_13.xpos", "12" }, { "df_mirror_rotating_13.ypos", "0" }, { "df_mirror_rotating_13.frames", "1" }, { "df_mirror_rotating_13.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_13.EDITOR.xpos", "12" }, { "df_mirror_rotating_13.EDITOR.ypos", "1" }, { "df_mirror_rotating_13.EDITOR.frames", "1" }, { "df_mirror_rotating_14", "RocksDF.png" }, { "df_mirror_rotating_14.xpos", "13" }, { "df_mirror_rotating_14.ypos", "0" }, { "df_mirror_rotating_14.frames", "1" }, { "df_mirror_rotating_14.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_14.EDITOR.xpos", "13" }, { "df_mirror_rotating_14.EDITOR.ypos", "1" }, { "df_mirror_rotating_14.EDITOR.frames", "1" }, { "df_mirror_rotating_15", "RocksDF.png" }, { "df_mirror_rotating_15.xpos", "14" }, { "df_mirror_rotating_15.ypos", "0" }, { "df_mirror_rotating_15.frames", "1" }, { "df_mirror_rotating_15.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_15.EDITOR.xpos", "14" }, { "df_mirror_rotating_15.EDITOR.ypos", "1" }, { "df_mirror_rotating_15.EDITOR.frames", "1" }, { "df_mirror_rotating_16", "RocksDF.png" }, { "df_mirror_rotating_16.xpos", "15" }, { "df_mirror_rotating_16.ypos", "0" }, { "df_mirror_rotating_16.frames", "1" }, { "df_mirror_rotating_16.EDITOR", "RocksDF.png" }, { "df_mirror_rotating_16.EDITOR.xpos", "15" }, { "df_mirror_rotating_16.EDITOR.ypos", "1" }, { "df_mirror_rotating_16.EDITOR.frames", "1" }, { "df_steel_grid_fixed_1", "RocksDF.png" }, { "df_steel_grid_fixed_1.xpos", "0" }, { "df_steel_grid_fixed_1.ypos", "2" }, { "df_steel_grid_fixed_1.frames", "1" }, { "df_steel_grid_fixed_2", "RocksDF.png" }, { "df_steel_grid_fixed_2.xpos", "1" }, { "df_steel_grid_fixed_2.ypos", "2" }, { "df_steel_grid_fixed_2.frames", "1" }, { "df_steel_grid_fixed_3", "RocksDF.png" }, { "df_steel_grid_fixed_3.xpos", "2" }, { "df_steel_grid_fixed_3.ypos", "2" }, { "df_steel_grid_fixed_3.frames", "1" }, { "df_steel_grid_fixed_4", "RocksDF.png" }, { "df_steel_grid_fixed_4.xpos", "3" }, { "df_steel_grid_fixed_4.ypos", "2" }, { "df_steel_grid_fixed_4.frames", "1" }, { "df_steel_grid_fixed_5", "RocksDF.png" }, { "df_steel_grid_fixed_5.xpos", "4" }, { "df_steel_grid_fixed_5.ypos", "2" }, { "df_steel_grid_fixed_5.frames", "1" }, { "df_steel_grid_fixed_6", "RocksDF.png" }, { "df_steel_grid_fixed_6.xpos", "5" }, { "df_steel_grid_fixed_6.ypos", "2" }, { "df_steel_grid_fixed_6.frames", "1" }, { "df_steel_grid_fixed_7", "RocksDF.png" }, { "df_steel_grid_fixed_7.xpos", "6" }, { "df_steel_grid_fixed_7.ypos", "2" }, { "df_steel_grid_fixed_7.frames", "1" }, { "df_steel_grid_fixed_8", "RocksDF.png" }, { "df_steel_grid_fixed_8.xpos", "7" }, { "df_steel_grid_fixed_8.ypos", "2" }, { "df_steel_grid_fixed_8.frames", "1" }, { "df_wooden_grid_fixed_1", "RocksDF.png" }, { "df_wooden_grid_fixed_1.xpos", "8" }, { "df_wooden_grid_fixed_1.ypos", "2" }, { "df_wooden_grid_fixed_1.frames", "1" }, { "df_wooden_grid_fixed_2", "RocksDF.png" }, { "df_wooden_grid_fixed_2.xpos", "9" }, { "df_wooden_grid_fixed_2.ypos", "2" }, { "df_wooden_grid_fixed_2.frames", "1" }, { "df_wooden_grid_fixed_3", "RocksDF.png" }, { "df_wooden_grid_fixed_3.xpos", "10" }, { "df_wooden_grid_fixed_3.ypos", "2" }, { "df_wooden_grid_fixed_3.frames", "1" }, { "df_wooden_grid_fixed_4", "RocksDF.png" }, { "df_wooden_grid_fixed_4.xpos", "11" }, { "df_wooden_grid_fixed_4.ypos", "2" }, { "df_wooden_grid_fixed_4.frames", "1" }, { "df_wooden_grid_fixed_5", "RocksDF.png" }, { "df_wooden_grid_fixed_5.xpos", "12" }, { "df_wooden_grid_fixed_5.ypos", "2" }, { "df_wooden_grid_fixed_5.frames", "1" }, { "df_wooden_grid_fixed_6", "RocksDF.png" }, { "df_wooden_grid_fixed_6.xpos", "13" }, { "df_wooden_grid_fixed_6.ypos", "2" }, { "df_wooden_grid_fixed_6.frames", "1" }, { "df_wooden_grid_fixed_7", "RocksDF.png" }, { "df_wooden_grid_fixed_7.xpos", "14" }, { "df_wooden_grid_fixed_7.ypos", "2" }, { "df_wooden_grid_fixed_7.frames", "1" }, { "df_wooden_grid_fixed_8", "RocksDF.png" }, { "df_wooden_grid_fixed_8.xpos", "15" }, { "df_wooden_grid_fixed_8.ypos", "2" }, { "df_wooden_grid_fixed_8.frames", "1" }, { "df_steel_grid_rotating_1", "RocksDF.png" }, { "df_steel_grid_rotating_1.xpos", "0" }, { "df_steel_grid_rotating_1.ypos", "2" }, { "df_steel_grid_rotating_1.frames", "1" }, { "df_steel_grid_rotating_1.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_1.EDITOR.xpos", "0" }, { "df_steel_grid_rotating_1.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_1.EDITOR.frames", "1" }, { "df_steel_grid_rotating_2", "RocksDF.png" }, { "df_steel_grid_rotating_2.xpos", "1" }, { "df_steel_grid_rotating_2.ypos", "2" }, { "df_steel_grid_rotating_2.frames", "1" }, { "df_steel_grid_rotating_2.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_2.EDITOR.xpos", "1" }, { "df_steel_grid_rotating_2.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_2.EDITOR.frames", "1" }, { "df_steel_grid_rotating_3", "RocksDF.png" }, { "df_steel_grid_rotating_3.xpos", "2" }, { "df_steel_grid_rotating_3.ypos", "2" }, { "df_steel_grid_rotating_3.frames", "1" }, { "df_steel_grid_rotating_3.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_3.EDITOR.xpos", "2" }, { "df_steel_grid_rotating_3.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_3.EDITOR.frames", "1" }, { "df_steel_grid_rotating_4", "RocksDF.png" }, { "df_steel_grid_rotating_4.xpos", "3" }, { "df_steel_grid_rotating_4.ypos", "2" }, { "df_steel_grid_rotating_4.frames", "1" }, { "df_steel_grid_rotating_4.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_4.EDITOR.xpos", "3" }, { "df_steel_grid_rotating_4.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_4.EDITOR.frames", "1" }, { "df_steel_grid_rotating_5", "RocksDF.png" }, { "df_steel_grid_rotating_5.xpos", "4" }, { "df_steel_grid_rotating_5.ypos", "2" }, { "df_steel_grid_rotating_5.frames", "1" }, { "df_steel_grid_rotating_5.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_5.EDITOR.xpos", "4" }, { "df_steel_grid_rotating_5.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_5.EDITOR.frames", "1" }, { "df_steel_grid_rotating_6", "RocksDF.png" }, { "df_steel_grid_rotating_6.xpos", "5" }, { "df_steel_grid_rotating_6.ypos", "2" }, { "df_steel_grid_rotating_6.frames", "1" }, { "df_steel_grid_rotating_6.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_6.EDITOR.xpos", "5" }, { "df_steel_grid_rotating_6.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_6.EDITOR.frames", "1" }, { "df_steel_grid_rotating_7", "RocksDF.png" }, { "df_steel_grid_rotating_7.xpos", "6" }, { "df_steel_grid_rotating_7.ypos", "2" }, { "df_steel_grid_rotating_7.frames", "1" }, { "df_steel_grid_rotating_7.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_7.EDITOR.xpos", "6" }, { "df_steel_grid_rotating_7.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_7.EDITOR.frames", "1" }, { "df_steel_grid_rotating_8", "RocksDF.png" }, { "df_steel_grid_rotating_8.xpos", "7" }, { "df_steel_grid_rotating_8.ypos", "2" }, { "df_steel_grid_rotating_8.frames", "1" }, { "df_steel_grid_rotating_8.EDITOR", "RocksDF.png" }, { "df_steel_grid_rotating_8.EDITOR.xpos", "7" }, { "df_steel_grid_rotating_8.EDITOR.ypos", "3" }, { "df_steel_grid_rotating_8.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_1", "RocksDF.png" }, { "df_wooden_grid_rotating_1.xpos", "8" }, { "df_wooden_grid_rotating_1.ypos", "2" }, { "df_wooden_grid_rotating_1.frames", "1" }, { "df_wooden_grid_rotating_1.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_1.EDITOR.xpos", "8" }, { "df_wooden_grid_rotating_1.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_1.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_2", "RocksDF.png" }, { "df_wooden_grid_rotating_2.xpos", "9" }, { "df_wooden_grid_rotating_2.ypos", "2" }, { "df_wooden_grid_rotating_2.frames", "1" }, { "df_wooden_grid_rotating_2.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_2.EDITOR.xpos", "9" }, { "df_wooden_grid_rotating_2.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_2.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_3", "RocksDF.png" }, { "df_wooden_grid_rotating_3.xpos", "10" }, { "df_wooden_grid_rotating_3.ypos", "2" }, { "df_wooden_grid_rotating_3.frames", "1" }, { "df_wooden_grid_rotating_3.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_3.EDITOR.xpos", "10" }, { "df_wooden_grid_rotating_3.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_3.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_4", "RocksDF.png" }, { "df_wooden_grid_rotating_4.xpos", "11" }, { "df_wooden_grid_rotating_4.ypos", "2" }, { "df_wooden_grid_rotating_4.frames", "1" }, { "df_wooden_grid_rotating_4.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_4.EDITOR.xpos", "11" }, { "df_wooden_grid_rotating_4.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_4.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_5", "RocksDF.png" }, { "df_wooden_grid_rotating_5.xpos", "12" }, { "df_wooden_grid_rotating_5.ypos", "2" }, { "df_wooden_grid_rotating_5.frames", "1" }, { "df_wooden_grid_rotating_5.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_5.EDITOR.xpos", "12" }, { "df_wooden_grid_rotating_5.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_5.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_6", "RocksDF.png" }, { "df_wooden_grid_rotating_6.xpos", "13" }, { "df_wooden_grid_rotating_6.ypos", "2" }, { "df_wooden_grid_rotating_6.frames", "1" }, { "df_wooden_grid_rotating_6.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_6.EDITOR.xpos", "13" }, { "df_wooden_grid_rotating_6.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_6.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_7", "RocksDF.png" }, { "df_wooden_grid_rotating_7.xpos", "14" }, { "df_wooden_grid_rotating_7.ypos", "2" }, { "df_wooden_grid_rotating_7.frames", "1" }, { "df_wooden_grid_rotating_7.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_7.EDITOR.xpos", "14" }, { "df_wooden_grid_rotating_7.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_7.EDITOR.frames", "1" }, { "df_wooden_grid_rotating_8", "RocksDF.png" }, { "df_wooden_grid_rotating_8.xpos", "15" }, { "df_wooden_grid_rotating_8.ypos", "2" }, { "df_wooden_grid_rotating_8.frames", "1" }, { "df_wooden_grid_rotating_8.EDITOR", "RocksDF.png" }, { "df_wooden_grid_rotating_8.EDITOR.xpos", "15" }, { "df_wooden_grid_rotating_8.EDITOR.ypos", "3" }, { "df_wooden_grid_rotating_8.EDITOR.frames", "1" }, { "df_fibre_optic_red_1", "RocksDF.png" }, { "df_fibre_optic_red_1.xpos", "8" }, { "df_fibre_optic_red_1.ypos", "8" }, { "df_fibre_optic_red_1.frames", "1" }, { "df_fibre_optic_red_1.EDITOR", "RocksDF.png" }, { "df_fibre_optic_red_1.EDITOR.xpos", "8" }, { "df_fibre_optic_red_1.EDITOR.ypos", "9" }, { "df_fibre_optic_red_1.EDITOR.frames", "1" }, { "df_fibre_optic_red_2", "RocksDF.png" }, { "df_fibre_optic_red_2.xpos", "9" }, { "df_fibre_optic_red_2.ypos", "8" }, { "df_fibre_optic_red_2.frames", "1" }, { "df_fibre_optic_red_2.EDITOR", "RocksDF.png" }, { "df_fibre_optic_red_2.EDITOR.xpos", "9" }, { "df_fibre_optic_red_2.EDITOR.ypos", "9" }, { "df_fibre_optic_red_2.EDITOR.frames", "1" }, { "df_fibre_optic_yellow_1", "RocksDF.png" }, { "df_fibre_optic_yellow_1.xpos", "10" }, { "df_fibre_optic_yellow_1.ypos", "8" }, { "df_fibre_optic_yellow_1.frames", "1" }, { "df_fibre_optic_yellow_1.EDITOR", "RocksDF.png" }, { "df_fibre_optic_yellow_1.EDITOR.xpos", "10" }, { "df_fibre_optic_yellow_1.EDITOR.ypos", "9" }, { "df_fibre_optic_yellow_1.EDITOR.frames", "1" }, { "df_fibre_optic_yellow_2", "RocksDF.png" }, { "df_fibre_optic_yellow_2.xpos", "11" }, { "df_fibre_optic_yellow_2.ypos", "8" }, { "df_fibre_optic_yellow_2.frames", "1" }, { "df_fibre_optic_yellow_2.EDITOR", "RocksDF.png" }, { "df_fibre_optic_yellow_2.EDITOR.xpos", "11" }, { "df_fibre_optic_yellow_2.EDITOR.ypos", "9" }, { "df_fibre_optic_yellow_2.EDITOR.frames", "1" }, { "df_fibre_optic_green_1", "RocksDF.png" }, { "df_fibre_optic_green_1.xpos", "12" }, { "df_fibre_optic_green_1.ypos", "8" }, { "df_fibre_optic_green_1.frames", "1" }, { "df_fibre_optic_green_1.EDITOR", "RocksDF.png" }, { "df_fibre_optic_green_1.EDITOR.xpos", "12" }, { "df_fibre_optic_green_1.EDITOR.ypos", "9" }, { "df_fibre_optic_green_1.EDITOR.frames", "1" }, { "df_fibre_optic_green_2", "RocksDF.png" }, { "df_fibre_optic_green_2.xpos", "13" }, { "df_fibre_optic_green_2.ypos", "8" }, { "df_fibre_optic_green_2.frames", "1" }, { "df_fibre_optic_green_2.EDITOR", "RocksDF.png" }, { "df_fibre_optic_green_2.EDITOR.xpos", "13" }, { "df_fibre_optic_green_2.EDITOR.ypos", "9" }, { "df_fibre_optic_green_2.EDITOR.frames", "1" }, { "df_fibre_optic_blue_1", "RocksDF.png" }, { "df_fibre_optic_blue_1.xpos", "14" }, { "df_fibre_optic_blue_1.ypos", "8" }, { "df_fibre_optic_blue_1.frames", "1" }, { "df_fibre_optic_blue_1.EDITOR", "RocksDF.png" }, { "df_fibre_optic_blue_1.EDITOR.xpos", "14" }, { "df_fibre_optic_blue_1.EDITOR.ypos", "9" }, { "df_fibre_optic_blue_1.EDITOR.frames", "1" }, { "df_fibre_optic_blue_2", "RocksDF.png" }, { "df_fibre_optic_blue_2.xpos", "15" }, { "df_fibre_optic_blue_2.ypos", "8" }, { "df_fibre_optic_blue_2.frames", "1" }, { "df_fibre_optic_blue_2.EDITOR", "RocksDF.png" }, { "df_fibre_optic_blue_2.EDITOR.xpos", "15" }, { "df_fibre_optic_blue_2.EDITOR.ypos", "9" }, { "df_fibre_optic_blue_2.EDITOR.frames", "1" }, { "df_steel_wall", "RocksDF.png" }, { "df_steel_wall.xpos", "6" }, { "df_steel_wall.ypos", "8" }, { "df_steel_wall.frames", "1" }, { "df_wooden_wall", "RocksDF.png" }, { "df_wooden_wall.xpos", "7" }, { "df_wooden_wall.ypos", "8" }, { "df_wooden_wall.frames", "1" }, { "df_refractor", "RocksDF.png" }, { "df_refractor.xpos", "1" }, { "df_refractor.ypos", "8" }, { "df_refractor.frames", "1" }, { "df_cell", "RocksDF.png" }, { "df_cell.xpos", "2" }, { "df_cell.ypos", "8" }, { "df_cell.frames", "1" }, { "df_mine", "RocksDF.png" }, { "df_mine.xpos", "4" }, { "df_mine.ypos", "8" }, { "df_mine.frames", "1" }, /* (these are only defined as elements to support ".PANEL" definitions) */ { "graphic_1", UNDEFINED_FILENAME }, { "graphic_2", UNDEFINED_FILENAME }, { "graphic_3", UNDEFINED_FILENAME }, { "graphic_4", UNDEFINED_FILENAME }, { "graphic_5", UNDEFINED_FILENAME }, { "graphic_6", UNDEFINED_FILENAME }, { "graphic_7", UNDEFINED_FILENAME }, { "graphic_8", UNDEFINED_FILENAME }, #include "conf_chr.c" /* include auto-generated data structure definitions */ #include "conf_cus.c" /* include auto-generated data structure definitions */ #include "conf_grp.c" /* include auto-generated data structure definitions */ // ========================================================================== // image definitions not associated with game elements (menu screens etc.) // ========================================================================== /* keyword to stop parser: "NO_MORE_ELEMENT_IMAGES" <-- do not change! */ #if 1 /* !!! TEMPORARILY STORED HERE -- PROBABLY TO BE CHANGED !!! */ /* (for testing, change filename back to "emc_objects dot png") */ { "emc_object", "RocksEMC.png" }, #if 0 { "emc_object.scale_up_factor", "2" }, #endif /* (for testing, change filename back to "emc_players dot png") */ { "emc_sprite", "RocksEMC.png" }, #if 0 { "emc_sprite.scale_up_factor", "2" }, #endif #endif { "sp_frame_horizontal", "RocksSP.png" }, { "sp_frame_horizontal.xpos", "7" }, { "sp_frame_horizontal.ypos", "14" }, { "sp_frame_vertical", "RocksSP.png" }, { "sp_frame_vertical.xpos", "6" }, { "sp_frame_vertical.ypos", "14" }, { "sp_frame_corner", "RocksSP.png" }, { "sp_frame_corner.xpos", "5" }, { "sp_frame_corner.ypos", "14" }, { "toon_1", "RocksToons.png" }, { "toon_1.x", "2" }, { "toon_1.y", "72" }, { "toon_1.width", "40" }, { "toon_1.height", "48" }, { "toon_1.frames", "8" }, { "toon_1.delay", "1" }, { "toon_1.step_offset", "4" }, { "toon_1.step_delay", "5" }, { "toon_1.direction", "right" }, { "toon_1.position", "bottom" }, { "toon_2", "RocksToons.png" }, { "toon_2.x", "2" }, { "toon_2.y", "186" }, { "toon_2.width", "40" }, { "toon_2.height", "48" }, { "toon_2.frames", "8" }, { "toon_2.delay", "1" }, { "toon_2.step_offset", "4" }, { "toon_2.step_delay", "5" }, { "toon_2.direction", "left" }, { "toon_2.position", "bottom" }, { "toon_3", "RocksToons.png" }, { "toon_3.x", "2" }, { "toon_3.y", "125" }, { "toon_3.width", "48" }, { "toon_3.height", "56" }, { "toon_3.frames", "8" }, { "toon_3.delay", "1" }, { "toon_3.step_offset", "4" }, { "toon_3.step_delay", "5" }, { "toon_3.direction", "right" }, { "toon_3.position", "bottom" }, { "toon_4", "RocksToons.png" }, { "toon_4.x", "327" }, { "toon_4.y", "10" }, { "toon_4.width", "80" }, { "toon_4.height", "110" }, { "toon_4.frames", "1" }, { "toon_4.delay", "1" }, { "toon_4.step_offset", "1" }, { "toon_4.step_delay", "1" }, { "toon_4.direction", "up" }, { "toon_4.position", "any" }, { "toon_5", "RocksToons.png" }, { "toon_5.x", "2" }, { "toon_5.y", "2" }, { "toon_5.width", "32" }, { "toon_5.height", "30" }, { "toon_5.frames", "8" }, { "toon_5.delay", "2" }, { "toon_5.anim_mode", "pingpong2" }, { "toon_5.step_offset", "2" }, { "toon_5.step_delay", "1" }, { "toon_5.direction", "right" }, { "toon_5.position", "upper" }, { "toon_6", "RocksToons.png" }, { "toon_6.x", "2" }, { "toon_6.y", "37" }, { "toon_6.width", "32" }, { "toon_6.height", "30" }, { "toon_6.frames", "8" }, { "toon_6.delay", "2" }, { "toon_6.anim_mode", "pingpong2" }, { "toon_6.step_offset", "2" }, { "toon_6.step_delay", "1" }, { "toon_6.direction", "left" }, { "toon_6.position", "upper" }, { "toon_7", "RocksMore.png" }, { "toon_7.xpos", "0" }, { "toon_7.ypos", "6" }, { "toon_7.frames", "16" }, { "toon_7.delay", "2" }, { "toon_7.direction", "down" }, { "toon_7.position", "any" }, { "toon_8", "RocksHeroes.png" }, { "toon_8.xpos", "4" }, { "toon_8.ypos", "1" }, { "toon_8.frames", "4" }, { "toon_8.delay", "4" }, { "toon_8.direction", "right" }, { "toon_8.position", "bottom" }, { "toon_9", "RocksHeroes.png" }, { "toon_9.xpos", "8" }, { "toon_9.ypos", "7" }, { "toon_9.frames", "4" }, { "toon_9.delay", "2" }, { "toon_9.direction", "left" }, { "toon_9.position", "bottom" }, { "toon_10", "RocksHeroes.png" }, { "toon_10.xpos", "12" }, { "toon_10.ypos", "7" }, { "toon_10.frames", "4" }, { "toon_10.delay", "2" }, { "toon_10.direction", "right" }, { "toon_10.position", "bottom" }, { "toon_11", "RocksHeroes.png" }, { "toon_11.xpos", "8" }, { "toon_11.ypos", "5" }, { "toon_11.frames", "4" }, { "toon_11.delay", "2" }, { "toon_11.direction", "left" }, { "toon_11.position", "bottom" }, { "toon_12", "RocksHeroes.png" }, { "toon_12.xpos", "12" }, { "toon_12.ypos", "5" }, { "toon_12.frames", "4" }, { "toon_12.delay", "2" }, { "toon_12.direction", "right" }, { "toon_12.position", "bottom" }, { "toon_13", "RocksHeroes.png" }, { "toon_13.xpos", "8" }, { "toon_13.ypos", "1" }, { "toon_13.frames", "4" }, { "toon_13.delay", "2" }, { "toon_13.direction", "left" }, { "toon_13.position", "bottom" }, { "toon_14", "RocksHeroes.png" }, { "toon_14.xpos", "12" }, { "toon_14.ypos", "1" }, { "toon_14.frames", "4" }, { "toon_14.delay", "2" }, { "toon_14.direction", "right" }, { "toon_14.position", "bottom" }, { "toon_15", "RocksHeroes.png" }, { "toon_15.xpos", "8" }, { "toon_15.ypos", "3" }, { "toon_15.frames", "4" }, { "toon_15.delay", "2" }, { "toon_15.direction", "left" }, { "toon_15.position", "bottom" }, { "toon_16", "RocksHeroes.png" }, { "toon_16.xpos", "12" }, { "toon_16.ypos", "3" }, { "toon_16.frames", "4" }, { "toon_16.delay", "2" }, { "toon_16.direction", "right" }, { "toon_16.position", "bottom" }, { "toon_17", "RocksHeroes.png" }, { "toon_17.xpos", "8" }, { "toon_17.ypos", "9" }, { "toon_17.frames", "8" }, { "toon_17.delay", "2" }, { "toon_17.direction", "left" }, { "toon_17.position", "any" }, { "toon_18", "RocksHeroes.png" }, { "toon_18.xpos", "8" }, { "toon_18.ypos", "9" }, { "toon_18.frames", "8" }, { "toon_18.delay", "2" }, { "toon_18.direction", "right" }, { "toon_18.position", "any" }, { "toon_19", "RocksElements.png" }, { "toon_19.xpos", "8" }, { "toon_19.ypos", "0" }, { "toon_19.frames", "2" }, { "toon_19.delay", "4" }, { "toon_19.direction", "down" }, { "toon_19.position", "any" }, { "toon_20", "RocksElements.png" }, { "toon_20.xpos", "10" }, { "toon_20.ypos", "0" }, { "toon_20.frames", "2" }, { "toon_20.delay", "4" }, { "toon_20.direction", "down" }, { "toon_20.position", "any" }, { "gfx.global.anim_1", UNDEFINED_FILENAME }, { "gfx.global.anim_2", UNDEFINED_FILENAME }, { "gfx.global.anim_3", UNDEFINED_FILENAME }, { "gfx.global.anim_4", UNDEFINED_FILENAME }, { "gfx.global.anim_5", UNDEFINED_FILENAME }, { "gfx.global.anim_6", UNDEFINED_FILENAME }, { "gfx.global.anim_7", UNDEFINED_FILENAME }, { "gfx.global.anim_8", UNDEFINED_FILENAME }, { "gfx.global.anim_9", UNDEFINED_FILENAME }, { "gfx.global.anim_10", UNDEFINED_FILENAME }, { "gfx.global.anim_11", UNDEFINED_FILENAME }, { "gfx.global.anim_12", UNDEFINED_FILENAME }, { "gfx.global.anim_13", UNDEFINED_FILENAME }, { "gfx.global.anim_14", UNDEFINED_FILENAME }, { "gfx.global.anim_15", UNDEFINED_FILENAME }, { "gfx.global.anim_16", UNDEFINED_FILENAME }, { "gfx.global.anim_17", UNDEFINED_FILENAME }, { "gfx.global.anim_18", UNDEFINED_FILENAME }, { "gfx.global.anim_19", UNDEFINED_FILENAME }, { "gfx.global.anim_20", UNDEFINED_FILENAME }, { "gfx.global.anim_21", UNDEFINED_FILENAME }, { "gfx.global.anim_22", UNDEFINED_FILENAME }, { "gfx.global.anim_23", UNDEFINED_FILENAME }, { "gfx.global.anim_24", UNDEFINED_FILENAME }, { "gfx.global.anim_25", UNDEFINED_FILENAME }, { "gfx.global.anim_26", UNDEFINED_FILENAME }, { "gfx.global.anim_27", UNDEFINED_FILENAME }, { "gfx.global.anim_28", UNDEFINED_FILENAME }, { "gfx.global.anim_29", UNDEFINED_FILENAME }, { "gfx.global.anim_30", UNDEFINED_FILENAME }, { "gfx.global.anim_31", UNDEFINED_FILENAME }, { "gfx.global.anim_32", UNDEFINED_FILENAME }, { "global.anim_1", UNDEFINED_FILENAME }, { "global.anim_2", UNDEFINED_FILENAME }, { "global.anim_3", UNDEFINED_FILENAME }, { "global.anim_4", UNDEFINED_FILENAME }, { "global.anim_5", UNDEFINED_FILENAME }, { "global.anim_6", UNDEFINED_FILENAME }, { "global.anim_7", UNDEFINED_FILENAME }, { "global.anim_8", UNDEFINED_FILENAME }, { "global.anim_9", UNDEFINED_FILENAME }, { "global.anim_10", UNDEFINED_FILENAME }, { "global.anim_11", UNDEFINED_FILENAME }, { "global.anim_12", UNDEFINED_FILENAME }, { "global.anim_13", UNDEFINED_FILENAME }, { "global.anim_14", UNDEFINED_FILENAME }, { "global.anim_15", UNDEFINED_FILENAME }, { "global.anim_16", UNDEFINED_FILENAME }, { "global.anim_17", UNDEFINED_FILENAME }, { "global.anim_18", UNDEFINED_FILENAME }, { "global.anim_19", UNDEFINED_FILENAME }, { "global.anim_20", UNDEFINED_FILENAME }, { "global.anim_21", UNDEFINED_FILENAME }, { "global.anim_22", UNDEFINED_FILENAME }, { "global.anim_23", UNDEFINED_FILENAME }, { "global.anim_24", UNDEFINED_FILENAME }, { "global.anim_25", UNDEFINED_FILENAME }, { "global.anim_26", UNDEFINED_FILENAME }, { "global.anim_27", UNDEFINED_FILENAME }, { "global.anim_28", UNDEFINED_FILENAME }, { "global.anim_29", UNDEFINED_FILENAME }, { "global.anim_30", UNDEFINED_FILENAME }, { "global.anim_31", UNDEFINED_FILENAME }, { "global.anim_32", UNDEFINED_FILENAME }, { "internal.global.toon_default", UNDEFINED_FILENAME }, { "internal.global.toon_default.anim_mode", "random" }, { "internal.global.anim_default", UNDEFINED_FILENAME }, { "menu.calibrate_red", "RocksElements.png" }, { "menu.calibrate_red.xpos", "12" }, { "menu.calibrate_red.ypos", "8" }, { "menu.calibrate_red.frames", "1" }, { "menu.calibrate_blue", "RocksElements.png" }, { "menu.calibrate_blue.xpos", "13" }, { "menu.calibrate_blue.ypos", "8" }, { "menu.calibrate_blue.frames", "1" }, { "menu.calibrate_yellow", "RocksElements.png" }, { "menu.calibrate_yellow.xpos", "14" }, { "menu.calibrate_yellow.ypos", "8" }, { "menu.calibrate_yellow.frames", "1" }, { "menu.button", "RocksElements.png" }, { "menu.button.xpos", "13" }, { "menu.button.ypos", "8" }, { "menu.button.frames", "1" }, { "menu.button.active", "RocksElements.png" }, { "menu.button.active.xpos", "12" }, { "menu.button.active.ypos", "8" }, { "menu.button.active.frames", "1" }, { "menu.button_left", "RocksDC.png" }, { "menu.button_left.xpos", "8" }, { "menu.button_left.ypos", "8" }, { "menu.button_left.frames", "1" }, { "menu.button_left.active", "RocksDC.png" }, { "menu.button_left.active.xpos", "8" }, { "menu.button_left.active.ypos", "9" }, { "menu.button_left.active.frames", "1" }, { "menu.button_right", "RocksDC.png" }, { "menu.button_right.xpos", "9" }, { "menu.button_right.ypos", "8" }, { "menu.button_right.frames", "1" }, { "menu.button_right.active", "RocksDC.png" }, { "menu.button_right.active.xpos", "9" }, { "menu.button_right.active.ypos", "9" }, { "menu.button_right.active.frames", "1" }, { "menu.button_up", "RocksDC.png" }, { "menu.button_up.xpos", "10" }, { "menu.button_up.ypos", "8" }, { "menu.button_up.frames", "1" }, { "menu.button_up.active", "RocksDC.png" }, { "menu.button_up.active.xpos", "10" }, { "menu.button_up.active.ypos", "9" }, { "menu.button_up.active.frames", "1" }, { "menu.button_down", "RocksDC.png" }, { "menu.button_down.xpos", "11" }, { "menu.button_down.ypos", "8" }, { "menu.button_down.frames", "1" }, { "menu.button_down.active", "RocksDC.png" }, { "menu.button_down.active.xpos", "11" }, { "menu.button_down.active.ypos", "9" }, { "menu.button_down.active.frames", "1" }, { "menu.button_enter_menu", UNDEFINED_FILENAME }, { "menu.button_enter_menu.clone_from", "menu.button_right" }, { "menu.button_enter_menu.active", UNDEFINED_FILENAME }, { "menu.button_enter_menu.active.clone_from", "menu.button_right.active" }, { "menu.button_leave_menu", UNDEFINED_FILENAME }, { "menu.button_leave_menu.clone_from", "menu.button_left" }, { "menu.button_leave_menu.active", UNDEFINED_FILENAME }, { "menu.button_leave_menu.active.clone_from", "menu.button_left.active" }, { "menu.button_next_level", UNDEFINED_FILENAME }, { "menu.button_next_level.clone_from", "menu.button_right" }, { "menu.button_next_level.active", UNDEFINED_FILENAME }, { "menu.button_next_level.active.clone_from", "menu.button_right.active" }, { "menu.button_prev_level", UNDEFINED_FILENAME }, { "menu.button_prev_level.clone_from", "menu.button_left" }, { "menu.button_prev_level.active", UNDEFINED_FILENAME }, { "menu.button_prev_level.active.clone_from", "menu.button_left.active" }, { "menu.button_name", UNDEFINED_FILENAME }, { "menu.button_name.clone_from", "menu.button" }, { "menu.button_name.active", UNDEFINED_FILENAME }, { "menu.button_name.active.clone_from", "menu.button.active" }, { "menu.button_levels", UNDEFINED_FILENAME }, { "menu.button_levels.clone_from", "menu.button_right" }, { "menu.button_levels.active", UNDEFINED_FILENAME }, { "menu.button_levels.active.clone_from", "menu.button_right.active" }, { "menu.button_scores", UNDEFINED_FILENAME }, { "menu.button_scores.clone_from", "menu.button" }, { "menu.button_scores.active", UNDEFINED_FILENAME }, { "menu.button_scores.active.clone_from", "menu.button.active" }, { "menu.button_editor", UNDEFINED_FILENAME }, { "menu.button_editor.clone_from", "menu.button" }, { "menu.button_editor.active", UNDEFINED_FILENAME }, { "menu.button_editor.active.clone_from", "menu.button.active" }, { "menu.button_info", UNDEFINED_FILENAME }, { "menu.button_info.clone_from", "menu.button_right" }, { "menu.button_info.active", UNDEFINED_FILENAME }, { "menu.button_info.active.clone_from", "menu.button_right.active" }, { "menu.button_game", UNDEFINED_FILENAME }, { "menu.button_game.clone_from", "menu.button" }, { "menu.button_game.active", UNDEFINED_FILENAME }, { "menu.button_game.active.clone_from", "menu.button.active" }, { "menu.button_setup", UNDEFINED_FILENAME }, { "menu.button_setup.clone_from", "menu.button_right" }, { "menu.button_setup.active", UNDEFINED_FILENAME }, { "menu.button_setup.active.clone_from", "menu.button_right.active" }, { "menu.button_quit", UNDEFINED_FILENAME }, { "menu.button_quit.clone_from", "menu.button" }, { "menu.button_quit.active", UNDEFINED_FILENAME }, { "menu.button_quit.active.clone_from", "menu.button.active" }, { "menu.scrollbar", "RocksDC.png" }, { "menu.scrollbar.xpos", "8" }, { "menu.scrollbar.ypos", "10" }, { "menu.scrollbar.frames", "1" }, { "menu.scrollbar.active", "RocksDC.png" }, { "menu.scrollbar.active.xpos", "9" }, { "menu.scrollbar.active.ypos", "10" }, { "menu.scrollbar.active.frames", "1" }, { "gfx.game.panel.time_anim", "RocksDoorMM.png" }, { "gfx.game.panel.time_anim.x", "5" }, { "gfx.game.panel.time_anim.y", "0" }, { "gfx.game.panel.time_anim.width", "90" }, { "gfx.game.panel.time_anim.height", "35" }, { "gfx.game.panel.time_anim.frames", "1" }, { "gfx.game.panel.time_anim.active", "RocksDoorMM.png" }, { "gfx.game.panel.time_anim.active.x", "105" }, { "gfx.game.panel.time_anim.active.y", "0" }, { "gfx.game.panel.time_anim.active.width", "90" }, { "gfx.game.panel.time_anim.active.height", "35" }, { "gfx.game.panel.time_anim.active.frames", "1" }, { "gfx.game.panel.health_anim", "RocksDoorMM.png" }, { "gfx.game.panel.health_anim.x", "5" }, { "gfx.game.panel.health_anim.y", "35" }, { "gfx.game.panel.health_anim.width", "90" }, { "gfx.game.panel.health_anim.height", "35" }, { "gfx.game.panel.health_anim.frames", "1" }, { "gfx.game.panel.health_anim.active", "RocksDoorMM.png" }, { "gfx.game.panel.health_anim.active.x", "105" }, { "gfx.game.panel.health_anim.active.y", "35" }, { "gfx.game.panel.health_anim.active.width", "90" }, { "gfx.game.panel.health_anim.active.height", "35" }, { "gfx.game.panel.health_anim.active.frames", "1" }, { "gfx.game.button.stop", "RocksDoor.png" }, { "gfx.game.button.stop.x", "305" }, { "gfx.game.button.stop.y", "185" }, { "gfx.game.button.stop.width", "30" }, { "gfx.game.button.stop.height", "30" }, { "gfx.game.button.stop.pressed_xoffset", "-100" }, { "gfx.game.button.pause", "RocksDoor.png" }, { "gfx.game.button.pause.x", "335" }, { "gfx.game.button.pause.y", "185" }, { "gfx.game.button.pause.width", "30" }, { "gfx.game.button.pause.height", "30" }, { "gfx.game.button.pause.pressed_xoffset", "-100" }, { "gfx.game.button.play", "RocksDoor.png" }, { "gfx.game.button.play.x", "365" }, { "gfx.game.button.play.y", "185" }, { "gfx.game.button.play.width", "30" }, { "gfx.game.button.play.height", "30" }, { "gfx.game.button.play.pressed_xoffset", "-100" }, { "gfx.game.button.undo", "RocksDoor2.png" }, { "gfx.game.button.undo.x", "105" }, { "gfx.game.button.undo.y", "20" }, { "gfx.game.button.undo.width", "30" }, { "gfx.game.button.undo.height", "30" }, { "gfx.game.button.undo.pressed_xoffset", "-100" }, { "gfx.game.button.redo", "RocksDoor2.png" }, { "gfx.game.button.redo.x", "165" }, { "gfx.game.button.redo.y", "20" }, { "gfx.game.button.redo.width", "30" }, { "gfx.game.button.redo.height", "30" }, { "gfx.game.button.redo.pressed_xoffset", "-100" }, { "gfx.game.button.save", "RocksDoor2.png" }, { "gfx.game.button.save.x", "105" }, { "gfx.game.button.save.y", "50" }, { "gfx.game.button.save.width", "30" }, { "gfx.game.button.save.height", "30" }, { "gfx.game.button.save.pressed_xoffset", "-100" }, { "gfx.game.button.pause2", "RocksDoor2.png" }, { "gfx.game.button.pause2.x", "135" }, { "gfx.game.button.pause2.y", "50" }, { "gfx.game.button.pause2.width", "30" }, { "gfx.game.button.pause2.height", "30" }, { "gfx.game.button.pause2.pressed_xoffset", "-100" }, { "gfx.game.button.pause2.active_yoffset", "-30" }, { "gfx.game.button.load", "RocksDoor2.png" }, { "gfx.game.button.load.x", "165" }, { "gfx.game.button.load.y", "50" }, { "gfx.game.button.load.width", "30" }, { "gfx.game.button.load.height", "30" }, { "gfx.game.button.load.pressed_xoffset", "-100" }, { "gfx.game.button.sound_music", "RocksDoor.png" }, { "gfx.game.button.sound_music.x", "305" }, { "gfx.game.button.sound_music.y", "245" }, { "gfx.game.button.sound_music.width", "30" }, { "gfx.game.button.sound_music.height", "30" }, { "gfx.game.button.sound_music.pressed_xoffset", "-100" }, { "gfx.game.button.sound_music.active_yoffset", "-30" }, { "gfx.game.button.sound_loops", "RocksDoor.png" }, { "gfx.game.button.sound_loops.x", "335" }, { "gfx.game.button.sound_loops.y", "245" }, { "gfx.game.button.sound_loops.width", "30" }, { "gfx.game.button.sound_loops.height", "30" }, { "gfx.game.button.sound_loops.pressed_xoffset", "-100" }, { "gfx.game.button.sound_loops.active_yoffset", "-30" }, { "gfx.game.button.sound_simple", "RocksDoor.png" }, { "gfx.game.button.sound_simple.x", "365" }, { "gfx.game.button.sound_simple.y", "245" }, { "gfx.game.button.sound_simple.width", "30" }, { "gfx.game.button.sound_simple.height", "30" }, { "gfx.game.button.sound_simple.pressed_xoffset", "-100" }, { "gfx.game.button.sound_simple.active_yoffset", "-30" }, { "gfx.game.button.panel_stop", UNDEFINED_FILENAME }, { "gfx.game.button.panel_pause", UNDEFINED_FILENAME }, { "gfx.game.button.panel_play", UNDEFINED_FILENAME }, { "gfx.game.button.panel_sound_music", UNDEFINED_FILENAME }, { "gfx.game.button.panel_sound_loops", UNDEFINED_FILENAME }, { "gfx.game.button.panel_sound_simple", UNDEFINED_FILENAME }, { "gfx.tape.button.eject", "RocksDoor.png" }, { "gfx.tape.button.eject.x", "305" }, { "gfx.tape.button.eject.y", "357" }, { "gfx.tape.button.eject.width", "18" }, { "gfx.tape.button.eject.height", "18" }, { "gfx.tape.button.eject.pressed_xoffset", "-100" }, { "gfx.tape.button.extra", "RocksDoor.png" }, { "gfx.tape.button.extra.x", "505" }, { "gfx.tape.button.extra.y", "357" }, { "gfx.tape.button.extra.width", "18" }, { "gfx.tape.button.extra.height", "18" }, { "gfx.tape.button.extra.pressed_xoffset", "-100" }, { "gfx.tape.button.stop", "RocksDoor.png" }, { "gfx.tape.button.stop.x", "323" }, { "gfx.tape.button.stop.y", "357" }, { "gfx.tape.button.stop.width", "18" }, { "gfx.tape.button.stop.height", "18" }, { "gfx.tape.button.stop.pressed_xoffset", "-100" }, { "gfx.tape.button.pause", "RocksDoor.png" }, { "gfx.tape.button.pause.x", "341" }, { "gfx.tape.button.pause.y", "357" }, { "gfx.tape.button.pause.width", "18" }, { "gfx.tape.button.pause.height", "18" }, { "gfx.tape.button.pause.pressed_xoffset", "-100" }, { "gfx.tape.button.record", "RocksDoor.png" }, { "gfx.tape.button.record.x", "359" }, { "gfx.tape.button.record.y", "357" }, { "gfx.tape.button.record.width", "18" }, { "gfx.tape.button.record.height", "18" }, { "gfx.tape.button.record.pressed_xoffset", "-100" }, { "gfx.tape.button.play", "RocksDoor.png" }, { "gfx.tape.button.play.x", "377" }, { "gfx.tape.button.play.y", "357" }, { "gfx.tape.button.play.width", "18" }, { "gfx.tape.button.play.height", "18" }, { "gfx.tape.button.play.pressed_xoffset", "-100" }, { "gfx.tape.symbol.eject", UNDEFINED_FILENAME }, { "gfx.tape.symbol.stop", UNDEFINED_FILENAME }, { "gfx.tape.symbol.pause", "RocksDoor.png" }, { "gfx.tape.symbol.pause.x", "340" }, { "gfx.tape.symbol.pause.y", "321" }, { "gfx.tape.symbol.pause.width", "17" }, { "gfx.tape.symbol.pause.height", "13" }, { "gfx.tape.symbol.record", "RocksDoor.png" }, { "gfx.tape.symbol.record.x", "325" }, { "gfx.tape.symbol.record.y", "321" }, { "gfx.tape.symbol.record.width", "16" }, { "gfx.tape.symbol.record.height", "16" }, { "gfx.tape.symbol.play", "RocksDoor.png" }, { "gfx.tape.symbol.play.x", "357" }, { "gfx.tape.symbol.play.y", "321" }, { "gfx.tape.symbol.play.width", "11" }, { "gfx.tape.symbol.play.height", "13" }, { "gfx.tape.symbol.fast_forward", "RocksDoor.png" }, { "gfx.tape.symbol.fast_forward.x", "539" }, { "gfx.tape.symbol.fast_forward.y", "193" }, { "gfx.tape.symbol.fast_forward.width", "27" }, { "gfx.tape.symbol.fast_forward.height", "13" }, { "gfx.tape.symbol.warp_forward", "RocksDoor.png" }, { "gfx.tape.symbol.warp_forward.x", "539" }, { "gfx.tape.symbol.warp_forward.y", "152" }, { "gfx.tape.symbol.warp_forward.width", "27" }, { "gfx.tape.symbol.warp_forward.height", "13" }, { "gfx.tape.symbol.warp_forward_blind", "RocksDoor.png" }, { "gfx.tape.symbol.warp_forward_blind.x", "539" }, { "gfx.tape.symbol.warp_forward_blind.y", "165" }, { "gfx.tape.symbol.warp_forward_blind.width", "27" }, { "gfx.tape.symbol.warp_forward_blind.height","13" }, { "gfx.tape.symbol.pause_before_end", "RocksDoor.png" }, { "gfx.tape.symbol.pause_before_end.x", "539" }, { "gfx.tape.symbol.pause_before_end.y", "221" }, { "gfx.tape.symbol.pause_before_end.width", "27" }, { "gfx.tape.symbol.pause_before_end.height", "13" }, { "gfx.tape.symbol.single_step", UNDEFINED_FILENAME }, { "gfx.tape.label.eject", UNDEFINED_FILENAME }, { "gfx.tape.label.stop", UNDEFINED_FILENAME }, { "gfx.tape.label.pause", "RocksDoor.png" }, { "gfx.tape.label.pause.x", "305" }, { "gfx.tape.label.pause.y", "341" }, { "gfx.tape.label.pause.width", "35" }, { "gfx.tape.label.pause.height", "8" }, { "gfx.tape.label.record", "RocksDoor.png" }, { "gfx.tape.label.record.x", "305" }, { "gfx.tape.label.record.y", "321" }, { "gfx.tape.label.record.width", "20" }, { "gfx.tape.label.record.height", "12" }, { "gfx.tape.label.play", "RocksDoor.png" }, { "gfx.tape.label.play.x", "370" }, { "gfx.tape.label.play.y", "321" }, { "gfx.tape.label.play.width", "22" }, { "gfx.tape.label.play.height", "12" }, { "gfx.tape.label.fast_forward", "RocksDoor.png" }, { "gfx.tape.label.fast_forward.x", "505" }, { "gfx.tape.label.fast_forward.y", "193" }, { "gfx.tape.label.fast_forward.width", "40" }, { "gfx.tape.label.fast_forward.height", "28" }, { "gfx.tape.label.warp_forward", "RocksDoor.png" }, { "gfx.tape.label.warp_forward.x", "505" }, { "gfx.tape.label.warp_forward.y", "165" }, { "gfx.tape.label.warp_forward.width", "40" }, { "gfx.tape.label.warp_forward.height", "28" }, { "gfx.tape.label.warp_forward_blind", "RocksDoor.png" }, { "gfx.tape.label.warp_forward_blind.x", "505" }, { "gfx.tape.label.warp_forward_blind.y", "165" }, { "gfx.tape.label.warp_forward_blind.width", "40" }, { "gfx.tape.label.warp_forward_blind.height", "28" }, { "gfx.tape.label.pause_before_end", "RocksDoor.png" }, { "gfx.tape.label.pause_before_end.x", "505" }, { "gfx.tape.label.pause_before_end.y", "221" }, { "gfx.tape.label.pause_before_end.width", "40" }, { "gfx.tape.label.pause_before_end.height", "28" }, { "gfx.tape.label.single_step", "RocksDoor.png" }, { "gfx.tape.label.single_step.x", "557" }, { "gfx.tape.label.single_step.y", "139" }, { "gfx.tape.label.single_step.width", "38" }, { "gfx.tape.label.single_step.height", "13" }, { "gfx.tape.label.date", "RocksDoor.png" }, { "gfx.tape.label.date.x", "305" }, { "gfx.tape.label.date.y", "285" }, { "gfx.tape.label.date.width", "90" }, { "gfx.tape.label.date.height", "31" }, { "gfx.tape.label.time", "RocksDoor.png" }, { "gfx.tape.label.time.x", "346" }, { "gfx.tape.label.time.y", "335" }, { "gfx.tape.label.time.width", "45" }, { "gfx.tape.label.time.height", "13" }, { "gfx.request.button.yes", "RocksDoor.png" }, { "gfx.request.button.yes.x", "302" }, { "gfx.request.button.yes.y", "0" }, { "gfx.request.button.yes.width", "46" }, { "gfx.request.button.yes.height", "28" }, { "gfx.request.button.yes.pressed_xoffset", "-100" }, { "gfx.request.button.no", "RocksDoor.png" }, { "gfx.request.button.no.x", "352" }, { "gfx.request.button.no.y", "0" }, { "gfx.request.button.no.width", "46" }, { "gfx.request.button.no.height", "28" }, { "gfx.request.button.no.pressed_xoffset", "-100" }, { "gfx.request.button.confirm", "RocksDoor.png" }, { "gfx.request.button.confirm.x", "302" }, { "gfx.request.button.confirm.y", "30" }, { "gfx.request.button.confirm.width", "96" }, { "gfx.request.button.confirm.height", "28" }, { "gfx.request.button.confirm.pressed_xoffset", "-100" }, { "gfx.request.button.player_1", "RocksDoor.png" }, { "gfx.request.button.player_1.x", "305" }, { "gfx.request.button.player_1.y", "185" }, { "gfx.request.button.player_1.width", "30" }, { "gfx.request.button.player_1.height", "30" }, { "gfx.request.button.player_1.pressed_xoffset", "-100" }, { "gfx.request.button.player_2", UNDEFINED_FILENAME }, { "gfx.request.button.player_2.clone_from", "gfx.request.button.player_1" }, { "gfx.request.button.player_3", UNDEFINED_FILENAME }, { "gfx.request.button.player_3.clone_from", "gfx.request.button.player_1" }, { "gfx.request.button.player_4", UNDEFINED_FILENAME }, { "gfx.request.button.player_4.clone_from", "gfx.request.button.player_1" }, { "font.initial_1", "RocksFontSmall.png" }, { "font.initial_1.x", "0" }, { "font.initial_1.y", "0" }, { "font.initial_1.width", "14" }, { "font.initial_1.height", "14" }, { "font.initial_2", "RocksFontSmall.png" }, { "font.initial_2.x", "0" }, { "font.initial_2.y", "70" }, { "font.initial_2.width", "14" }, { "font.initial_2.height", "14" }, { "font.initial_3", "RocksFontSmall.png" }, { "font.initial_3.x", "0" }, { "font.initial_3.y", "140" }, { "font.initial_3.width", "14" }, { "font.initial_3.height", "14" }, { "font.initial_4", "RocksFontSmall.png" }, { "font.initial_4.x", "0" }, { "font.initial_4.y", "210" }, { "font.initial_4.width", "14" }, { "font.initial_4.height", "14" }, { "font.title_1", "RocksFontBig.png" }, { "font.title_1.x", "0" }, { "font.title_1.y", "480" }, { "font.title_1.width", "32" }, { "font.title_1.height", "32" }, { "font.title_2", "RocksFontSmall.png" }, { "font.title_2.x", "0" }, { "font.title_2.y", "0" }, { "font.title_2.width", "14" }, { "font.title_2.height", "14" }, { "font.title_2.SETUP", UNDEFINED_FILENAME }, { "font.title_2.SETUP.clone_from", "font.text_2" }, { "font.menu_1", "RocksFontBig.png" }, { "font.menu_1.x", "0" }, { "font.menu_1.y", "320" }, { "font.menu_1.width", "32" }, { "font.menu_1.height", "32" }, { "font.menu_1.active", "RocksFontBig.png" }, { "font.menu_1.active.x", "0" }, { "font.menu_1.active.y", "480" }, { "font.menu_1.active.width", "32" }, { "font.menu_1.active.height", "32" }, { "font.menu_2", "RocksFontMedium.png" }, { "font.menu_2.x", "0" }, { "font.menu_2.y", "320" }, { "font.menu_2.width", "16" }, { "font.menu_2.height", "32" }, { "font.menu_2.active", "RocksFontMedium.png" }, { "font.menu_2.active.x", "0" }, { "font.menu_2.active.y", "480" }, { "font.menu_2.active.width", "16" }, { "font.menu_2.active.height", "32" }, { "font.text_1", "RocksFontSmall.png" }, { "font.text_1.x", "0" }, { "font.text_1.y", "140" }, { "font.text_1.width", "14" }, { "font.text_1.height", "14" }, { "font.text_1.MAIN", UNDEFINED_FILENAME }, { "font.text_1.MAIN.clone_from", "font.text_1.PREVIEW" }, { "font.text_1.LEVELS", "RocksFontMedium.png" }, { "font.text_1.LEVELS.x", "0" }, { "font.text_1.LEVELS.y", "0" }, { "font.text_1.LEVELS.width", "16" }, { "font.text_1.LEVELS.height", "32" }, { "font.text_1.LEVELNR", UNDEFINED_FILENAME }, { "font.text_1.LEVELNR.clone_from", "font.text_1.LEVELS" }, { "font.text_1.SETUP", UNDEFINED_FILENAME }, { "font.text_1.SETUP.clone_from", "font.text_1.LEVELS" }, { "font.text_1.PREVIEW", "RocksFontEM.png" }, { "font.text_1.PREVIEW.x", "0" }, { "font.text_1.PREVIEW.y", "160" }, { "font.text_1.PREVIEW.width", "16" }, { "font.text_1.PREVIEW.height", "16" }, { "font.text_1.SCORES", "RocksFontMedium.png" }, { "font.text_1.SCORES.x", "0" }, { "font.text_1.SCORES.y", "480" }, { "font.text_1.SCORES.width", "16" }, { "font.text_1.SCORES.height", "32" }, { "font.text_1.active.SCORES", "RocksFontMedium.png" }, { "font.text_1.active.SCORES.x", "0" }, { "font.text_1.active.SCORES.y", "0" }, { "font.text_1.active.SCORES.width", "16" }, { "font.text_1.active.SCORES.height", "32" }, { "font.text_1.PANEL", UNDEFINED_FILENAME }, { "font.text_1.PANEL.clone_from", "font.level_number" }, { "font.text_1.DOOR", UNDEFINED_FILENAME }, { "font.text_1.DOOR.clone_from", "font.level_number" }, { "font.text_2", "RocksFontSmall.png" }, { "font.text_2.x", "0" }, { "font.text_2.y", "210" }, { "font.text_2.width", "14" }, { "font.text_2.height", "14" }, { "font.text_2.MAIN", UNDEFINED_FILENAME }, { "font.text_2.MAIN.clone_from", "font.text_2.PREVIEW" }, { "font.text_2.LEVELS", "RocksFontMedium.png" }, { "font.text_2.LEVELS.x", "0" }, { "font.text_2.LEVELS.y", "160" }, { "font.text_2.LEVELS.width", "16" }, { "font.text_2.LEVELS.height", "32" }, { "font.text_2.LEVELNR", UNDEFINED_FILENAME }, { "font.text_2.LEVELNR.clone_from", "font.text_2.LEVELS" }, { "font.text_2.SETUP", UNDEFINED_FILENAME }, { "font.text_2.SETUP.clone_from", "font.text_2.LEVELS" }, { "font.text_2.PREVIEW", "RocksFontEM.png" }, { "font.text_2.PREVIEW.x", "0" }, { "font.text_2.PREVIEW.y", "160" }, { "font.text_2.PREVIEW.width", "16" }, { "font.text_2.PREVIEW.height", "16" }, { "font.text_2.SCORES", "RocksFontBig.png" }, { "font.text_2.SCORES.x", "0" }, { "font.text_2.SCORES.y", "320" }, { "font.text_2.SCORES.width", "32" }, { "font.text_2.SCORES.height", "32" }, { "font.text_2.active.SCORES", "RocksFontBig.png" }, { "font.text_2.active.SCORES.x", "0" }, { "font.text_2.active.SCORES.y", "0" }, { "font.text_2.active.SCORES.width", "32" }, { "font.text_2.active.SCORES.height", "32" }, { "font.text_3", "RocksFontSmall.png" }, { "font.text_3.x", "0" }, { "font.text_3.y", "0" }, { "font.text_3.width", "14" }, { "font.text_3.height", "14" }, { "font.text_3.LEVELS", "RocksFontMedium.png" }, { "font.text_3.LEVELS.x", "0" }, { "font.text_3.LEVELS.y", "320" }, { "font.text_3.LEVELS.width", "16" }, { "font.text_3.LEVELS.height", "32" }, { "font.text_3.LEVELNR", UNDEFINED_FILENAME }, { "font.text_3.LEVELNR.clone_from", "font.text_3.LEVELS" }, { "font.text_3.SETUP", UNDEFINED_FILENAME }, { "font.text_3.SETUP.clone_from", "font.text_3.LEVELS" }, { "font.text_3.PREVIEW", "RocksFontEM.png" }, { "font.text_3.PREVIEW.x", "0" }, { "font.text_3.PREVIEW.y", "160" }, { "font.text_3.PREVIEW.width", "16" }, { "font.text_3.PREVIEW.height", "16" }, { "font.text_3.SCORES", "RocksFontMedium.png" }, { "font.text_3.SCORES.x", "0" }, { "font.text_3.SCORES.y", "480" }, { "font.text_3.SCORES.width", "16" }, { "font.text_3.SCORES.height", "32" }, { "font.text_3.active.SCORES", "RocksFontMedium.png" }, { "font.text_3.active.SCORES.x", "0" }, { "font.text_3.active.SCORES.y", "0" }, { "font.text_3.active.SCORES.width", "16" }, { "font.text_3.active.SCORES.height", "32" }, { "font.text_4", "RocksFontSmall.png" }, { "font.text_4.x", "0" }, { "font.text_4.y", "70" }, { "font.text_4.width", "14" }, { "font.text_4.height", "14" }, { "font.text_4.MAIN", UNDEFINED_FILENAME }, { "font.text_4.MAIN.clone_from", "font.text_3.PREVIEW" }, { "font.text_4.LEVELS", "RocksFontMedium.png" }, { "font.text_4.LEVELS.x", "0" }, { "font.text_4.LEVELS.y", "480" }, { "font.text_4.LEVELS.width", "16" }, { "font.text_4.LEVELS.height", "32" }, { "font.text_4.LEVELNR", UNDEFINED_FILENAME }, { "font.text_4.LEVELNR.clone_from", "font.text_4.LEVELS" }, { "font.text_4.SETUP", UNDEFINED_FILENAME }, { "font.text_4.SETUP.clone_from", "font.text_4.LEVELS" }, { "font.text_4.SCORES", "RocksFontMedium.png" }, { "font.text_4.SCORES.x", "0" }, { "font.text_4.SCORES.y", "480" }, { "font.text_4.SCORES.width", "16" }, { "font.text_4.SCORES.height", "32" }, { "font.text_4.active.SCORES", "RocksFontMedium.png" }, { "font.text_4.active.SCORES.x", "0" }, { "font.text_4.active.SCORES.y", "0" }, { "font.text_4.active.SCORES.width", "16" }, { "font.text_4.active.SCORES.height", "32" }, { "font.envelope_1", "RocksFontEM.png" }, { "font.envelope_1.x", "0" }, { "font.envelope_1.y", "160" }, { "font.envelope_1.width", "16" }, { "font.envelope_1.height", "16" }, { "font.envelope_2", "RocksFontEM.png" }, { "font.envelope_2.x", "0" }, { "font.envelope_2.y", "160" }, { "font.envelope_2.width", "16" }, { "font.envelope_2.height", "16" }, { "font.envelope_3", "RocksFontEM.png" }, { "font.envelope_3.x", "0" }, { "font.envelope_3.y", "160" }, { "font.envelope_3.width", "16" }, { "font.envelope_3.height", "16" }, { "font.envelope_4", "RocksFontEM.png" }, { "font.envelope_4.x", "0" }, { "font.envelope_4.y", "160" }, { "font.envelope_4.width", "16" }, { "font.envelope_4.height", "16" }, { "font.request", "RocksFontSmall.png" }, { "font.request.x", "0" }, { "font.request.y", "210" }, { "font.request.width", "14" }, { "font.request.height", "14" }, { "font.input_1", "RocksFontSmall.png" }, { "font.input_1.x", "0" }, { "font.input_1.y", "210" }, { "font.input_1.width", "14" }, { "font.input_1.height", "14" }, { "font.input_1.MAIN", "RocksFontBig.png" }, { "font.input_1.MAIN.x", "0" }, { "font.input_1.MAIN.y", "0" }, { "font.input_1.MAIN.width", "32" }, { "font.input_1.MAIN.height", "32" }, { "font.input_1.active", "RocksFontSmall.png" }, { "font.input_1.active.x", "0" }, { "font.input_1.active.y", "210" }, { "font.input_1.active.width", "14" }, { "font.input_1.active.height", "14" }, { "font.input_1.active.MAIN", "RocksFontBig.png" }, { "font.input_1.active.MAIN.x", "0" }, { "font.input_1.active.MAIN.y", "480" }, { "font.input_1.active.MAIN.width", "32" }, { "font.input_1.active.MAIN.height", "32" }, { "font.input_1.active.SETUP", "RocksFontBig.png" }, { "font.input_1.active.SETUP.x", "0" }, { "font.input_1.active.SETUP.y", "0" }, { "font.input_1.active.SETUP.width", "32" }, { "font.input_1.active.SETUP.height", "32" }, { "font.input_2", "RocksFontSmall.png" }, { "font.input_2.x", "0" }, { "font.input_2.y", "210" }, { "font.input_2.width", "14" }, { "font.input_2.height", "14" }, { "font.input_2.active", "RocksFontSmall.png" }, { "font.input_2.active.x", "0" }, { "font.input_2.active.y", "210" }, { "font.input_2.active.width", "14" }, { "font.input_2.active.height", "14" }, { "font.option_off", "RocksFontBig.png" }, { "font.option_off.x", "0" }, { "font.option_off.y", "160" }, { "font.option_off.width", "32" }, { "font.option_off.height", "32" }, { "font.option_off_narrow", UNDEFINED_FILENAME }, { "font.option_off_narrow.clone_from", "font.text_2.LEVELS" }, { "font.option_on", "RocksFontBig.png" }, { "font.option_on.x", "0" }, { "font.option_on.y", "480" }, { "font.option_on.width", "32" }, { "font.option_on.height", "32" }, { "font.option_on_narrow", UNDEFINED_FILENAME }, { "font.option_on_narrow.clone_from", "font.text_4.LEVELS" }, { "font.value_1", "RocksFontBig.png" }, { "font.value_1.x", "0" }, { "font.value_1.y", "480" }, { "font.value_1.width", "32" }, { "font.value_1.height", "32" }, { "font.value_2", "RocksFontMedium.png" }, { "font.value_2.x", "0" }, { "font.value_2.y", "480" }, { "font.value_2.width", "16" }, { "font.value_2.height", "32" }, { "font.value_old", "RocksFontBig.png" }, { "font.value_old.x", "0" }, { "font.value_old.y", "160" }, { "font.value_old.width", "32" }, { "font.value_old.height", "32" }, { "font.value_narrow", UNDEFINED_FILENAME }, { "font.value_narrow.clone_from", "font.text_4.LEVELS" }, { "font.level_number", "RocksFontSmall.png" }, { "font.level_number.x", "0" }, { "font.level_number.y", "350" }, { "font.level_number.width", "10" }, { "font.level_number.height", "14" }, { "font.level_number.active", UNDEFINED_FILENAME }, { "font.level_number.active.clone_from", "font.level_number" }, { "font.tape_recorder", "RocksFontSmall.png" }, { "font.tape_recorder.x", "0" }, { "font.tape_recorder.y", "280" }, { "font.tape_recorder.width", "11" }, { "font.tape_recorder.height", "14" }, { "font.game_info", "RocksFontEM.png" }, { "font.game_info.xpos", "0" }, { "font.game_info.ypos", "0" }, { "font.game_info.delay", "10" }, { "font.info.elements", UNDEFINED_FILENAME }, { "font.info.elements.clone_from", "font.level_number" }, { "font.info.levelset", UNDEFINED_FILENAME }, { "font.info.levelset.clone_from", "font.level_number" }, { "editor.element_border", "RocksMore.png" }, { "editor.element_border.xpos", "0" }, { "editor.element_border.ypos", "2" }, { "editor.element_border.border_size", "8" }, { "editor.element_border_input", "RocksMore.png" }, { "editor.element_border_input.xpos", "10" }, { "editor.element_border_input.ypos", "7" }, { "editor.element_border_input.border_size", "4" }, { "editor.counter.down", "RocksDoor.png" }, { "editor.counter.down.x", "302" }, { "editor.counter.down.y", "60" }, { "editor.counter.down.width", "20" }, { "editor.counter.down.height", "20" }, { "editor.counter.down.pressed_xoffset", "-100" }, { "editor.counter.up", "RocksDoor.png" }, { "editor.counter.up.x", "378" }, { "editor.counter.up.y", "60" }, { "editor.counter.up.width", "20" }, { "editor.counter.up.height", "20" }, { "editor.counter.up.pressed_xoffset", "-100" }, { "editor.counter.input", "RocksDoor.png" }, { "editor.counter.input.x", "324" }, { "editor.counter.input.y", "60" }, { "editor.counter.input.width", "52" }, { "editor.counter.input.height", "20" }, { "editor.counter.input.active_xoffset", "-100" }, { "editor.counter.input.border_size", "3" }, { "editor.selectbox.input", "RocksDoor.png" }, { "editor.selectbox.input.x", "324" }, { "editor.selectbox.input.y", "82" }, { "editor.selectbox.input.width", "52" }, { "editor.selectbox.input.height", "20" }, { "editor.selectbox.input.active_xoffset", "-100" }, { "editor.selectbox.input.border_size", "3" }, { "editor.selectbox.button", UNDEFINED_FILENAME }, { "editor.selectbox.button.width", "14" }, { "editor.checkbox", "RocksDoor.png" }, { "editor.checkbox.x", "302" }, { "editor.checkbox.y", "82" }, { "editor.checkbox.width", "20" }, { "editor.checkbox.height", "20" }, { "editor.checkbox.pressed_xoffset", "-100" }, { "editor.checkbox.active_xoffset", "76" }, { "editor.radiobutton", "RocksDoor.png" }, { "editor.radiobutton.x", "302" }, { "editor.radiobutton.y", "104" }, { "editor.radiobutton.width", "20" }, { "editor.radiobutton.height", "20" }, { "editor.radiobutton.pressed_xoffset", "-100" }, { "editor.radiobutton.active_xoffset", "76" }, { "editor.stickybutton", "RocksDoor.png" }, { "editor.stickybutton.x", "302" }, { "editor.stickybutton.y", "126" }, { "editor.stickybutton.width", "20" }, { "editor.stickybutton.height", "20" }, { "editor.stickybutton.pressed_xoffset", "-100" }, { "editor.stickybutton.active_xoffset", "76" }, { "editor.tabbutton", "RocksDoor.png" }, { "editor.tabbutton.x", "324" }, { "editor.tabbutton.y", "104" }, { "editor.tabbutton.width", "52" }, { "editor.tabbutton.height", "20" }, { "editor.tabbutton.pressed_xoffset", "-100" }, { "editor.tabbutton.active_yoffset", "22" }, { "editor.tabbutton.border_size", "3" }, { "editor.tabbutton.draw_xoffset", "2" }, { "editor.textbutton", "RocksDoor.png" }, { "editor.textbutton.x", "324" }, { "editor.textbutton.y", "148" }, { "editor.textbutton.width", "52" }, { "editor.textbutton.height", "20" }, { "editor.textbutton.pressed_xoffset", "-100" }, { "editor.textbutton.border_size", "3" }, { "editor.textbutton.draw_xoffset", "2" }, { "editor.input.text", "RocksDoor.png" }, { "editor.input.text.x", "324" }, { "editor.input.text.y", "60" }, { "editor.input.text.width", "52" }, { "editor.input.text.height", "20" }, { "editor.input.text.active_xoffset", "-100" }, { "editor.input.text.border_size", "3" }, { "editor.input.textarea", "RocksDoor.png" }, { "editor.input.textarea.x", "324" }, { "editor.input.textarea.y", "60" }, { "editor.input.textarea.width", "52" }, { "editor.input.textarea.height", "20" }, { "editor.input.textarea.active_xoffset", "-100" }, { "editor.input.textarea.border_size", "3" }, { "editor.cascade_list", "RocksMore.png" }, { "editor.cascade_list.xpos", "9" }, { "editor.cascade_list.ypos", "8" }, { "editor.cascade_list.frames", "1" }, { "editor.cascade_list.active", "RocksMore.png" }, { "editor.cascade_list.active.xpos", "10" }, { "editor.cascade_list.active.ypos", "8" }, { "editor.cascade_list.active.frames", "1" }, { "editor.palette.button", "RocksDoor.png" }, { "editor.palette.button.x", "525" }, { "editor.palette.button.y", "30" }, { "editor.palette.button.width", "20" }, { "editor.palette.button.height", "20" }, { "editor.palette.button.pressed_xoffset", "-20" }, { "editor.palette.scroll_up", "RocksDoor.png" }, { "editor.palette.scroll_up.x", "750" }, { "editor.palette.scroll_up.y", "0" }, { "editor.palette.scroll_up.width", "10" }, { "editor.palette.scroll_up.height", "10" }, { "editor.palette.scroll_up.pressed_xoffset", "-10" }, { "editor.palette.scroll_down", "RocksDoor.png" }, { "editor.palette.scroll_down.x", "750" }, { "editor.palette.scroll_down.y", "10" }, { "editor.palette.scroll_down.width", "10" }, { "editor.palette.scroll_down.height", "10" }, { "editor.palette.scroll_down.pressed_xoffset", "-10" }, { "editor.palette.scrollbar", "RocksDoor.png" }, { "editor.palette.scrollbar.x", "750" }, { "editor.palette.scrollbar.y", "20" }, { "editor.palette.scrollbar.width", "10" }, { "editor.palette.scrollbar.height", "10" }, { "editor.palette.scrollbar.pressed_xoffset", "-10" }, { "editor.palette.scrollbar.border_size", "3" }, { "editor.playfield.scroll_up", "RocksDoor.png" }, { "editor.playfield.scroll_up.x", "724" }, { "editor.playfield.scroll_up.y", "0" }, { "editor.playfield.scroll_up.width", "16" }, { "editor.playfield.scroll_up.height", "16" }, { "editor.playfield.scroll_up.pressed_xoffset", "-16" }, { "editor.playfield.scroll_down", "RocksDoor.png" }, { "editor.playfield.scroll_down.x", "724" }, { "editor.playfield.scroll_down.y", "16" }, { "editor.playfield.scroll_down.width", "16" }, { "editor.playfield.scroll_down.height", "16" }, { "editor.playfield.scroll_down.pressed_xoffset", "-16" }, { "editor.playfield.scroll_left", "RocksDoor.png" }, { "editor.playfield.scroll_left.x", "724" }, { "editor.playfield.scroll_left.y", "32" }, { "editor.playfield.scroll_left.width", "16" }, { "editor.playfield.scroll_left.height", "16" }, { "editor.playfield.scroll_left.pressed_xoffset", "-16" }, { "editor.playfield.scroll_right", "RocksDoor.png" }, { "editor.playfield.scroll_right.x", "724" }, { "editor.playfield.scroll_right.y", "48" }, { "editor.playfield.scroll_right.width", "16" }, { "editor.playfield.scroll_right.height", "16" }, { "editor.playfield.scroll_right.pressed_xoffset", "-16" }, { "editor.playfield.scrollbar", "RocksDoor.png" }, { "editor.playfield.scrollbar.x", "724" }, { "editor.playfield.scrollbar.y", "64" }, { "editor.playfield.scrollbar.width", "16" }, { "editor.playfield.scrollbar.height", "16" }, { "editor.playfield.scrollbar.pressed_xoffset", "-16" }, { "editor.playfield.scrollbar.border_size", "3" }, { "gfx.editor.button.prev_level", "RocksDoor.png" }, { "gfx.editor.button.prev_level.x", "724" }, { "gfx.editor.button.prev_level.y", "32" }, { "gfx.editor.button.prev_level.width", "16" }, { "gfx.editor.button.prev_level.height", "16" }, { "gfx.editor.button.prev_level.pressed_xoffset", "-16" }, { "gfx.editor.button.next_level", "RocksDoor.png" }, { "gfx.editor.button.next_level.x", "724" }, { "gfx.editor.button.next_level.y", "48" }, { "gfx.editor.button.next_level.width", "16" }, { "gfx.editor.button.next_level.height", "16" }, { "gfx.editor.button.next_level.pressed_xoffset", "-16" }, { "gfx.editor.button.properties", "RocksDoor2.png" }, { "gfx.editor.button.properties.x", "105" }, { "gfx.editor.button.properties.y", "0" }, { "gfx.editor.button.properties.width", "90" }, { "gfx.editor.button.properties.height", "20" }, { "gfx.editor.button.properties.pressed_xoffset", "-100" }, { "gfx.editor.button.element_left", "RocksDoor2.png" }, { "gfx.editor.button.element_left.x", "368" }, { "gfx.editor.button.element_left.y", "48" }, { "gfx.editor.button.element_left.width", "16" }, { "gfx.editor.button.element_left.height", "16" }, { "gfx.editor.button.element_left.pressed_xoffset", "0" }, { "gfx.editor.button.element_middle", "RocksDoor2.png" }, { "gfx.editor.button.element_middle.x", "368" }, { "gfx.editor.button.element_middle.y", "48" }, { "gfx.editor.button.element_middle.width", "16" }, { "gfx.editor.button.element_middle.height", "16" }, { "gfx.editor.button.element_middle.pressed_xoffset", "0" }, { "gfx.editor.button.element_right", "RocksDoor2.png" }, { "gfx.editor.button.element_right.x", "368" }, { "gfx.editor.button.element_right.y", "48" }, { "gfx.editor.button.element_right.width", "16" }, { "gfx.editor.button.element_right.height", "16" }, { "gfx.editor.button.element_right.pressed_xoffset", "0" }, { "gfx.editor.button.palette", UNDEFINED_FILENAME }, { "editor.no_toolbox_button", "RocksDoor.png" }, { "editor.no_toolbox_button.x", "506" }, { "editor.no_toolbox_button.y", "286" }, { "editor.no_toolbox_button.width", "22" }, { "editor.no_toolbox_button.height", "22" }, { "gfx.editor.button.draw_single", "RocksDoor.png" }, { "gfx.editor.button.draw_single.x", "706" }, { "gfx.editor.button.draw_single.y", "242" }, { "gfx.editor.button.draw_single.width", "22" }, { "gfx.editor.button.draw_single.height", "22" }, { "gfx.editor.button.draw_single.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_single.active_yoffset", "-94" }, { "gfx.editor.button.draw_connected", "RocksDoor.png" }, { "gfx.editor.button.draw_connected.x", "728" }, { "gfx.editor.button.draw_connected.y", "242" }, { "gfx.editor.button.draw_connected.width", "22" }, { "gfx.editor.button.draw_connected.height", "22" }, { "gfx.editor.button.draw_connected.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_connected.active_yoffset", "-94" }, { "gfx.editor.button.draw_line", "RocksDoor.png" }, { "gfx.editor.button.draw_line.x", "750" }, { "gfx.editor.button.draw_line.y", "242" }, { "gfx.editor.button.draw_line.width", "22" }, { "gfx.editor.button.draw_line.height", "22" }, { "gfx.editor.button.draw_line.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_line.active_yoffset", "-94" }, { "gfx.editor.button.draw_arc", "RocksDoor.png" }, { "gfx.editor.button.draw_arc.x", "772" }, { "gfx.editor.button.draw_arc.y", "242" }, { "gfx.editor.button.draw_arc.width", "22" }, { "gfx.editor.button.draw_arc.height", "22" }, { "gfx.editor.button.draw_arc.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_arc.active_yoffset", "-94" }, { "gfx.editor.button.draw_rectangle", "RocksDoor.png" }, { "gfx.editor.button.draw_rectangle.x", "706" }, { "gfx.editor.button.draw_rectangle.y", "264" }, { "gfx.editor.button.draw_rectangle.width", "22" }, { "gfx.editor.button.draw_rectangle.height", "22" }, { "gfx.editor.button.draw_rectangle.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_rectangle.active_yoffset", "-94" }, { "gfx.editor.button.draw_filled_box", "RocksDoor.png" }, { "gfx.editor.button.draw_filled_box.x", "728" }, { "gfx.editor.button.draw_filled_box.y", "264" }, { "gfx.editor.button.draw_filled_box.width", "22" }, { "gfx.editor.button.draw_filled_box.height", "22" }, { "gfx.editor.button.draw_filled_box.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_filled_box.active_yoffset", "-94" }, { "gfx.editor.button.rotate_up", "RocksDoor.png" }, { "gfx.editor.button.rotate_up.x", "750" }, { "gfx.editor.button.rotate_up.y", "264" }, { "gfx.editor.button.rotate_up.width", "22" }, { "gfx.editor.button.rotate_up.height", "22" }, { "gfx.editor.button.rotate_up.pressed_xoffset", "-100" }, { "gfx.editor.button.rotate_up.active_yoffset", "-94" }, { "gfx.editor.button.draw_text", "RocksDoor.png" }, { "gfx.editor.button.draw_text.x", "772" }, { "gfx.editor.button.draw_text.y", "264" }, { "gfx.editor.button.draw_text.width", "22" }, { "gfx.editor.button.draw_text.height", "22" }, { "gfx.editor.button.draw_text.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_text.active_yoffset", "-94" }, { "gfx.editor.button.flood_fill", "RocksDoor.png" }, { "gfx.editor.button.flood_fill.x", "706" }, { "gfx.editor.button.flood_fill.y", "286" }, { "gfx.editor.button.flood_fill.width", "22" }, { "gfx.editor.button.flood_fill.height", "22" }, { "gfx.editor.button.flood_fill.pressed_xoffset", "-100" }, { "gfx.editor.button.flood_fill.active_yoffset", "-94" }, { "gfx.editor.button.rotate_left", "RocksDoor.png" }, { "gfx.editor.button.rotate_left.x", "728" }, { "gfx.editor.button.rotate_left.y", "286" }, { "gfx.editor.button.rotate_left.width", "22" }, { "gfx.editor.button.rotate_left.height", "22" }, { "gfx.editor.button.rotate_left.pressed_xoffset", "-100" }, { "gfx.editor.button.rotate_left.active_yoffset", "-94" }, { "gfx.editor.button.zoom_level", "RocksDoor2.png" }, { "gfx.editor.button.zoom_level.x", "350" }, { "gfx.editor.button.zoom_level.y", "22" }, { "gfx.editor.button.zoom_level.width", "22" }, { "gfx.editor.button.zoom_level.height", "22" }, { "gfx.editor.button.zoom_level.pressed_xoffset", "-100" }, { "gfx.editor.button.zoom_level.active_yoffset", "-22" }, { "gfx.editor.button.rotate_right", "RocksDoor.png" }, { "gfx.editor.button.rotate_right.x", "772" }, { "gfx.editor.button.rotate_right.y", "286" }, { "gfx.editor.button.rotate_right.width", "22" }, { "gfx.editor.button.rotate_right.height", "22" }, { "gfx.editor.button.rotate_right.pressed_xoffset", "-100" }, { "gfx.editor.button.rotate_right.active_yoffset", "-94" }, { "gfx.editor.button.draw_random", "RocksDoor.png" }, { "gfx.editor.button.draw_random.x", "706" }, { "gfx.editor.button.draw_random.y", "308" }, { "gfx.editor.button.draw_random.width", "22" }, { "gfx.editor.button.draw_random.height", "22" }, { "gfx.editor.button.draw_random.pressed_xoffset", "-100" }, { "gfx.editor.button.draw_random.active_yoffset", "-94" }, { "gfx.editor.button.grab_brush", "RocksDoor.png" }, { "gfx.editor.button.grab_brush.x", "728" }, { "gfx.editor.button.grab_brush.y", "308" }, { "gfx.editor.button.grab_brush.width", "22" }, { "gfx.editor.button.grab_brush.height", "22" }, { "gfx.editor.button.grab_brush.pressed_xoffset", "-100" }, { "gfx.editor.button.grab_brush.active_yoffset", "-94" }, { "gfx.editor.button.rotate_down", "RocksDoor.png" }, { "gfx.editor.button.rotate_down.x", "750" }, { "gfx.editor.button.rotate_down.y", "308" }, { "gfx.editor.button.rotate_down.width", "22" }, { "gfx.editor.button.rotate_down.height", "22" }, { "gfx.editor.button.rotate_down.pressed_xoffset", "-100" }, { "gfx.editor.button.rotate_down.active_yoffset", "-94" }, { "gfx.editor.button.pick_element", "RocksDoor.png" }, { "gfx.editor.button.pick_element.x", "772" }, { "gfx.editor.button.pick_element.y", "308" }, { "gfx.editor.button.pick_element.width", "22" }, { "gfx.editor.button.pick_element.height", "22" }, { "gfx.editor.button.pick_element.pressed_xoffset", "-100" }, { "gfx.editor.button.pick_element.active_yoffset", "-94" }, { "gfx.editor.button.ce_copy_from", "RocksDoor.png" }, { "gfx.editor.button.ce_copy_from.x", "528" }, { "gfx.editor.button.ce_copy_from.y", "330" }, { "gfx.editor.button.ce_copy_from.width", "22" }, { "gfx.editor.button.ce_copy_from.height", "22" }, { "gfx.editor.button.ce_copy_from.pressed_xoffset", "-100" }, { "gfx.editor.button.ce_copy_from.active_yoffset", "-22" }, { "gfx.editor.button.ce_copy_to", "RocksDoor.png" }, { "gfx.editor.button.ce_copy_to.x", "550" }, { "gfx.editor.button.ce_copy_to.y", "330" }, { "gfx.editor.button.ce_copy_to.width", "22" }, { "gfx.editor.button.ce_copy_to.height", "22" }, { "gfx.editor.button.ce_copy_to.pressed_xoffset", "-100" }, { "gfx.editor.button.ce_copy_to.active_yoffset", "-22" }, { "gfx.editor.button.ce_swap", "RocksDoor.png" }, { "gfx.editor.button.ce_swap.x", "572" }, { "gfx.editor.button.ce_swap.y", "330" }, { "gfx.editor.button.ce_swap.width", "22" }, { "gfx.editor.button.ce_swap.height", "22" }, { "gfx.editor.button.ce_swap.pressed_xoffset", "-100" }, { "gfx.editor.button.ce_swap.active_yoffset", "-22" }, { "gfx.editor.button.ce_copy", "RocksDoor.png" }, { "gfx.editor.button.ce_copy.x", "550" }, { "gfx.editor.button.ce_copy.y", "286" }, { "gfx.editor.button.ce_copy.width", "22" }, { "gfx.editor.button.ce_copy.height", "22" }, { "gfx.editor.button.ce_copy.pressed_xoffset", "-100" }, { "gfx.editor.button.ce_paste", "RocksDoor.png" }, { "gfx.editor.button.ce_paste.x", "572" }, { "gfx.editor.button.ce_paste.y", "286" }, { "gfx.editor.button.ce_paste.width", "22" }, { "gfx.editor.button.ce_paste.height", "22" }, { "gfx.editor.button.ce_paste.pressed_xoffset", "-100" }, { "gfx.editor.button.cp_copy", "RocksDoor.png" }, { "gfx.editor.button.cp_copy.x", "525" }, { "gfx.editor.button.cp_copy.y", "50" }, { "gfx.editor.button.cp_copy.width", "20" }, { "gfx.editor.button.cp_copy.height", "20" }, { "gfx.editor.button.cp_copy.pressed_xoffset", "-20" }, { "gfx.editor.button.cp_paste", "RocksDoor.png" }, { "gfx.editor.button.cp_paste.x", "525" }, { "gfx.editor.button.cp_paste.y", "70" }, { "gfx.editor.button.cp_paste.width", "20" }, { "gfx.editor.button.cp_paste.height", "20" }, { "gfx.editor.button.cp_paste.pressed_xoffset", "-20" }, { "gfx.editor.button.undo", "RocksDoor.png" }, { "gfx.editor.button.undo.x", "705" }, { "gfx.editor.button.undo.y", "335" }, { "gfx.editor.button.undo.width", "30" }, { "gfx.editor.button.undo.height", "20" }, { "gfx.editor.button.undo.pressed_xoffset", "-100" }, { "gfx.editor.button.conf", "RocksDoor.png" }, { "gfx.editor.button.conf.x", "735" }, { "gfx.editor.button.conf.y", "335" }, { "gfx.editor.button.conf.width", "30" }, { "gfx.editor.button.conf.height", "20" }, { "gfx.editor.button.conf.pressed_xoffset", "-100" }, { "gfx.editor.button.save", "RocksDoor.png" }, { "gfx.editor.button.save.x", "765" }, { "gfx.editor.button.save.y", "335" }, { "gfx.editor.button.save.width", "30" }, { "gfx.editor.button.save.height", "20" }, { "gfx.editor.button.save.pressed_xoffset", "-100" }, { "gfx.editor.button.clear", "RocksDoor.png" }, { "gfx.editor.button.clear.x", "705" }, { "gfx.editor.button.clear.y", "355" }, { "gfx.editor.button.clear.width", "30" }, { "gfx.editor.button.clear.height", "20" }, { "gfx.editor.button.clear.pressed_xoffset", "-100" }, { "gfx.editor.button.test", "RocksDoor.png" }, { "gfx.editor.button.test.x", "735" }, { "gfx.editor.button.test.y", "355" }, { "gfx.editor.button.test.width", "30" }, { "gfx.editor.button.test.height", "20" }, { "gfx.editor.button.test.pressed_xoffset", "-100" }, { "gfx.editor.button.exit", "RocksDoor.png" }, { "gfx.editor.button.exit.x", "765" }, { "gfx.editor.button.exit.y", "355" }, { "gfx.editor.button.exit.width", "30" }, { "gfx.editor.button.exit.height", "20" }, { "gfx.editor.button.exit.pressed_xoffset", "-100" }, { "gfx.editor.input.level_number", "RocksDoor.png" }, { "gfx.editor.input.level_number.x", "529" }, { "gfx.editor.input.level_number.y", "5" }, { "gfx.editor.input.level_number.width", "42" }, { "gfx.editor.input.level_number.height", "16" }, { "gfx.editor.input.level_number.border_size","1" }, { "global.border", "RocksScreen.png" }, { "global.border.MAIN", UNDEFINED_FILENAME }, { "global.border.SCORES", UNDEFINED_FILENAME }, { "global.border.EDITOR", UNDEFINED_FILENAME }, { "global.border.PLAYING", UNDEFINED_FILENAME }, { "global.door", "RocksDoor.png" }, { "global.busy", "RocksBusy.png" }, { "global.busy.x", "0" }, { "global.busy.y", "0" }, { "global.busy.width", "32" }, { "global.busy.height", "32" }, { "global.busy.frames", "28" }, { "global.busy.frames_per_line", "7" }, { "global.busy.delay", "2" }, { "global.tile_cursor", "RocksMore.png" }, { "global.tile_cursor.xpos", "10" }, { "global.tile_cursor.ypos", "7" }, { "global.tile_cursor.frames", "1" }, { "background", UNDEFINED_FILENAME }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, { "background.MAIN", UNDEFINED_FILENAME }, { "background.LEVELS", UNDEFINED_FILENAME }, { "background.LEVELNR", UNDEFINED_FILENAME }, { "background.SCORES", UNDEFINED_FILENAME }, { "background.EDITOR", UNDEFINED_FILENAME }, { "background.INFO", UNDEFINED_FILENAME }, { "background.INFO[ELEMENTS]", UNDEFINED_FILENAME }, { "background.INFO[MUSIC]", UNDEFINED_FILENAME }, { "background.INFO[CREDITS]", UNDEFINED_FILENAME }, { "background.INFO[PROGRAM]", UNDEFINED_FILENAME }, { "background.INFO[VERSION]", UNDEFINED_FILENAME }, { "background.INFO[LEVELSET]", UNDEFINED_FILENAME }, { "background.SETUP", UNDEFINED_FILENAME }, { "background.PLAYING", UNDEFINED_FILENAME }, { "background.DOOR", UNDEFINED_FILENAME }, { "background.TAPE", "RocksDoor.png" }, { "background.TAPE.x", "200" }, { "background.TAPE.y", "280" }, { "background.TAPE.width", "100" }, { "background.TAPE.height", "100" }, { "background.PANEL", "RocksDoor.png" }, { "background.PANEL.x", "400" }, { "background.PANEL.y", "0" }, { "background.PANEL.width", "100" }, { "background.PANEL.height", "280" }, { "background.PALETTE", "RocksDoor.png" }, { "background.PALETTE.x", "500" }, { "background.PALETTE.y", "0" }, { "background.PALETTE.width", "100" }, { "background.PALETTE.height", "280" }, { "background.TOOLBOX", "RocksDoor.png" }, { "background.TOOLBOX.x", "700" }, { "background.TOOLBOX.y", "236" }, { "background.TOOLBOX.width", "100" }, { "background.TOOLBOX.height", "144" }, { "background.titlescreen_initial_1", UNDEFINED_FILENAME }, { "background.titlescreen_initial_2", UNDEFINED_FILENAME }, { "background.titlescreen_initial_3", UNDEFINED_FILENAME }, { "background.titlescreen_initial_4", UNDEFINED_FILENAME }, { "background.titlescreen_initial_5", UNDEFINED_FILENAME }, { "background.titlescreen_1", UNDEFINED_FILENAME }, { "background.titlescreen_2", UNDEFINED_FILENAME }, { "background.titlescreen_3", UNDEFINED_FILENAME }, { "background.titlescreen_4", UNDEFINED_FILENAME }, { "background.titlescreen_5", UNDEFINED_FILENAME }, { "background.titlemessage_initial_1", UNDEFINED_FILENAME }, { "background.titlemessage_initial_2", UNDEFINED_FILENAME }, { "background.titlemessage_initial_3", UNDEFINED_FILENAME }, { "background.titlemessage_initial_4", UNDEFINED_FILENAME }, { "background.titlemessage_initial_5", UNDEFINED_FILENAME }, { "background.titlemessage_1", UNDEFINED_FILENAME }, { "background.titlemessage_2", UNDEFINED_FILENAME }, { "background.titlemessage_3", UNDEFINED_FILENAME }, { "background.titlemessage_4", UNDEFINED_FILENAME }, { "background.titlemessage_5", UNDEFINED_FILENAME }, { "background.envelope_1", "RocksScreen.png" }, { "background.envelope_1.x", "0" }, { "background.envelope_1.y", "0" }, { "background.envelope_1.width", "560" }, { "background.envelope_1.height", "560" }, { "background.envelope_1.anim_mode", "default" }, { "background.envelope_1.draw_masked", "false" }, { "background.envelope_2", "RocksScreen.png" }, { "background.envelope_2.x", "0" }, { "background.envelope_2.y", "0" }, { "background.envelope_2.width", "560" }, { "background.envelope_2.height", "560" }, { "background.envelope_2.anim_mode", "default" }, { "background.envelope_2.draw_masked", "false" }, { "background.envelope_3", "RocksScreen.png" }, { "background.envelope_3.x", "0" }, { "background.envelope_3.y", "0" }, { "background.envelope_3.width", "560" }, { "background.envelope_3.height", "560" }, { "background.envelope_3.anim_mode", "default" }, { "background.envelope_3.draw_masked", "false" }, { "background.envelope_4", "RocksScreen.png" }, { "background.envelope_4.x", "0" }, { "background.envelope_4.y", "0" }, { "background.envelope_4.width", "560" }, { "background.envelope_4.height", "560" }, { "background.envelope_4.anim_mode", "default" }, { "background.envelope_4.draw_masked", "false" }, { "background.request", "RocksScreen.png" }, { "background.request.x", "562" }, { "background.request.y", "56" }, { "background.request.width", "108" }, { "background.request.height", "288" }, { "background.request.anim_mode", "default" }, { "background.request.draw_masked", "false" }, { "titlescreen_initial_1", UNDEFINED_FILENAME }, { "titlescreen_initial_2", UNDEFINED_FILENAME }, { "titlescreen_initial_3", UNDEFINED_FILENAME }, { "titlescreen_initial_4", UNDEFINED_FILENAME }, { "titlescreen_initial_5", UNDEFINED_FILENAME }, { "titlescreen_1", UNDEFINED_FILENAME }, { "titlescreen_2", UNDEFINED_FILENAME }, { "titlescreen_3", UNDEFINED_FILENAME }, { "titlescreen_4", UNDEFINED_FILENAME }, { "titlescreen_5", UNDEFINED_FILENAME }, { "gfx.door_1.part_1", "RocksDoor.png" }, { "gfx.door_1.part_1.x", "0" }, { "gfx.door_1.part_1.y", "0" }, { "gfx.door_1.part_1.width", "100" }, { "gfx.door_1.part_1.height", "77" }, { "gfx.door_1.part_1.frames", "1" }, { "gfx.door_1.part_2", "RocksDoor.png" }, { "gfx.door_1.part_2.x", "0" }, { "gfx.door_1.part_2.y", "77" }, { "gfx.door_1.part_2.width", "100" }, { "gfx.door_1.part_2.height", "63" }, { "gfx.door_1.part_2.frames", "1" }, { "gfx.door_1.part_3", "RocksDoor.png" }, { "gfx.door_1.part_3.x", "0" }, { "gfx.door_1.part_3.y", "140" }, { "gfx.door_1.part_3.width", "100" }, { "gfx.door_1.part_3.height", "63" }, { "gfx.door_1.part_3.frames", "1" }, { "gfx.door_1.part_4", "RocksDoor.png" }, { "gfx.door_1.part_4.x", "0" }, { "gfx.door_1.part_4.y", "203" }, { "gfx.door_1.part_4.width", "100" }, { "gfx.door_1.part_4.height", "77" }, { "gfx.door_1.part_4.frames", "1" }, { "gfx.door_1.part_5", "RocksDoor.png" }, { "gfx.door_1.part_5.x", "100" }, { "gfx.door_1.part_5.y", "0" }, { "gfx.door_1.part_5.width", "100" }, { "gfx.door_1.part_5.height", "77" }, { "gfx.door_1.part_5.frames", "1" }, { "gfx.door_1.part_6", "RocksDoor.png" }, { "gfx.door_1.part_6.x", "100" }, { "gfx.door_1.part_6.y", "77" }, { "gfx.door_1.part_6.width", "100" }, { "gfx.door_1.part_6.height", "63" }, { "gfx.door_1.part_6.frames", "1" }, { "gfx.door_1.part_7", "RocksDoor.png" }, { "gfx.door_1.part_7.x", "100" }, { "gfx.door_1.part_7.y", "140" }, { "gfx.door_1.part_7.width", "100" }, { "gfx.door_1.part_7.height", "63" }, { "gfx.door_1.part_7.frames", "1" }, { "gfx.door_1.part_8", "RocksDoor.png" }, { "gfx.door_1.part_8.x", "100" }, { "gfx.door_1.part_8.y", "203" }, { "gfx.door_1.part_8.width", "100" }, { "gfx.door_1.part_8.height", "77" }, { "gfx.door_1.part_8.frames", "1" }, { "gfx.door_2.part_1", "RocksDoor.png" }, { "gfx.door_2.part_1.x", "0" }, { "gfx.door_2.part_1.y", "280" }, { "gfx.door_2.part_1.width", "100" }, { "gfx.door_2.part_1.height", "50" }, { "gfx.door_2.part_1.frames", "1" }, { "gfx.door_2.part_2", "RocksDoor.png" }, { "gfx.door_2.part_2.x", "0" }, { "gfx.door_2.part_2.y", "330" }, { "gfx.door_2.part_2.width", "100" }, { "gfx.door_2.part_2.height", "50" }, { "gfx.door_2.part_2.frames", "1" }, { "gfx.door_2.part_3", "RocksDoor.png" }, { "gfx.door_2.part_3.x", "100" }, { "gfx.door_2.part_3.y", "280" }, { "gfx.door_2.part_3.width", "100" }, { "gfx.door_2.part_3.height", "50" }, { "gfx.door_2.part_3.frames", "1" }, { "gfx.door_2.part_4", "RocksDoor.png" }, { "gfx.door_2.part_4.x", "100" }, { "gfx.door_2.part_4.y", "330" }, { "gfx.door_2.part_4.width", "100" }, { "gfx.door_2.part_4.height", "50" }, { "gfx.door_2.part_4.frames", "1" }, { "gfx.door_2.part_5", UNDEFINED_FILENAME }, { "gfx.door_2.part_6", UNDEFINED_FILENAME }, { "gfx.door_2.part_7", UNDEFINED_FILENAME }, { "gfx.door_2.part_8", UNDEFINED_FILENAME }, { "door_2.top_border_correction", "RocksDoor.png" }, { "door_2.top_border_correction.x", "600" }, { "door_2.top_border_correction.y", "0" }, { "door_2.top_border_correction.width", "108" }, { "door_2.top_border_correction.height", "8" }, /* the last image entry apparently gets overwritten by very last entry of "image_config[]"; so far this bug could not be found and fixed */ { "last_image_entry_bug", UNDEFINED_FILENAME }, // ========================================================================== // non-image definitions // ========================================================================== /* the following directives are not associated with an image, but probably make sense to be defined in "graphicsinfo.conf", too */ /* keyword to start parser: "CONFIG_VARS_START" <-- do not change! */ { "[title_initial].fade_mode", "fade" }, { "[title_initial].fade_delay", "500" }, { "[title_initial].post_delay", "250" }, { "[title_initial].auto_delay", "-1" }, { "[title].fade_mode", "fade" }, { "[title].fade_delay", "500" }, { "[title].post_delay", "250" }, { "[title].auto_delay", "-1" }, { "[titlescreen_initial].sort_priority", "0" }, { "[titlescreen_initial].fade_mode", ARG_DEFAULT }, { "[titlescreen_initial].fade_delay", ARG_DEFAULT }, { "[titlescreen_initial].post_delay", ARG_DEFAULT }, { "[titlescreen_initial].auto_delay", ARG_DEFAULT }, { "[titlescreen].sort_priority", "0" }, { "[titlescreen].fade_mode", ARG_DEFAULT }, { "[titlescreen].fade_delay", ARG_DEFAULT }, { "[titlescreen].post_delay", ARG_DEFAULT }, { "[titlescreen].auto_delay", ARG_DEFAULT }, { "titlescreen_initial_1.sort_priority", ARG_DEFAULT }, { "titlescreen_initial_1.fade_mode", ARG_DEFAULT }, { "titlescreen_initial_1.fade_delay", ARG_DEFAULT }, { "titlescreen_initial_1.post_delay", ARG_DEFAULT }, { "titlescreen_initial_1.auto_delay", ARG_DEFAULT }, { "titlescreen_initial_2.sort_priority", ARG_DEFAULT }, { "titlescreen_initial_2.fade_mode", ARG_DEFAULT }, { "titlescreen_initial_2.fade_delay", ARG_DEFAULT }, { "titlescreen_initial_2.post_delay", ARG_DEFAULT }, { "titlescreen_initial_2.auto_delay", ARG_DEFAULT }, { "titlescreen_initial_3.sort_priority", ARG_DEFAULT }, { "titlescreen_initial_3.fade_mode", ARG_DEFAULT }, { "titlescreen_initial_3.fade_delay", ARG_DEFAULT }, { "titlescreen_initial_3.post_delay", ARG_DEFAULT }, { "titlescreen_initial_3.auto_delay", ARG_DEFAULT }, { "titlescreen_initial_4.sort_priority", ARG_DEFAULT }, { "titlescreen_initial_4.fade_mode", ARG_DEFAULT }, { "titlescreen_initial_4.fade_delay", ARG_DEFAULT }, { "titlescreen_initial_4.post_delay", ARG_DEFAULT }, { "titlescreen_initial_4.auto_delay", ARG_DEFAULT }, { "titlescreen_initial_5.sort_priority", ARG_DEFAULT }, { "titlescreen_initial_5.fade_mode", ARG_DEFAULT }, { "titlescreen_initial_5.fade_delay", ARG_DEFAULT }, { "titlescreen_initial_5.post_delay", ARG_DEFAULT }, { "titlescreen_initial_5.auto_delay", ARG_DEFAULT }, { "titlescreen_1.sort_priority", ARG_DEFAULT }, { "titlescreen_1.fade_mode", ARG_DEFAULT }, { "titlescreen_1.fade_delay", ARG_DEFAULT }, { "titlescreen_1.post_delay", ARG_DEFAULT }, { "titlescreen_1.auto_delay", ARG_DEFAULT }, { "titlescreen_2.sort_priority", ARG_DEFAULT }, { "titlescreen_2.fade_mode", ARG_DEFAULT }, { "titlescreen_2.fade_delay", ARG_DEFAULT }, { "titlescreen_2.post_delay", ARG_DEFAULT }, { "titlescreen_2.auto_delay", ARG_DEFAULT }, { "titlescreen_3.sort_priority", ARG_DEFAULT }, { "titlescreen_3.fade_mode", ARG_DEFAULT }, { "titlescreen_3.fade_delay", ARG_DEFAULT }, { "titlescreen_3.post_delay", ARG_DEFAULT }, { "titlescreen_3.auto_delay", ARG_DEFAULT }, { "titlescreen_4.sort_priority", ARG_DEFAULT }, { "titlescreen_4.fade_mode", ARG_DEFAULT }, { "titlescreen_4.fade_delay", ARG_DEFAULT }, { "titlescreen_4.post_delay", ARG_DEFAULT }, { "titlescreen_4.auto_delay", ARG_DEFAULT }, { "titlescreen_5.sort_priority", ARG_DEFAULT }, { "titlescreen_5.fade_mode", ARG_DEFAULT }, { "titlescreen_5.fade_delay", ARG_DEFAULT }, { "titlescreen_5.post_delay", ARG_DEFAULT }, { "titlescreen_5.auto_delay", ARG_DEFAULT }, { "[titlemessage_initial].x", "-1" }, { "[titlemessage_initial].y", "-1" }, { "[titlemessage_initial].width", "-1" }, { "[titlemessage_initial].height", "-1" }, { "[titlemessage_initial].chars", "-1" }, { "[titlemessage_initial].lines", "-1" }, { "[titlemessage_initial].align", "center" }, { "[titlemessage_initial].valign", "middle" }, { "[titlemessage_initial].font", "font.text_1" }, { "[titlemessage_initial].autowrap", "false" }, { "[titlemessage_initial].centered", "false" }, { "[titlemessage_initial].parse_comments", "false" }, { "[titlemessage_initial].sort_priority", "0" }, { "[titlemessage_initial].fade_mode", ARG_DEFAULT }, { "[titlemessage_initial].fade_delay", ARG_DEFAULT }, { "[titlemessage_initial].post_delay", ARG_DEFAULT }, { "[titlemessage_initial].auto_delay", ARG_DEFAULT }, { "[titlemessage].x", "-1" }, { "[titlemessage].y", "-1" }, { "[titlemessage].width", "-1" }, { "[titlemessage].height", "-1" }, { "[titlemessage].chars", "-1" }, { "[titlemessage].lines", "-1" }, { "[titlemessage].align", "center" }, { "[titlemessage].valign", "middle" }, { "[titlemessage].font", "font.text_1" }, { "[titlemessage].autowrap", "false" }, { "[titlemessage].centered", "false" }, { "[titlemessage].parse_comments", "false" }, { "[titlemessage].sort_priority", "0" }, { "[titlemessage].fade_mode", ARG_DEFAULT }, { "[titlemessage].fade_delay", ARG_DEFAULT }, { "[titlemessage].post_delay", ARG_DEFAULT }, { "[titlemessage].auto_delay", ARG_DEFAULT }, { "titlemessage_initial_1.x", ARG_DEFAULT }, { "titlemessage_initial_1.y", ARG_DEFAULT }, { "titlemessage_initial_1.width", ARG_DEFAULT }, { "titlemessage_initial_1.height", ARG_DEFAULT }, { "titlemessage_initial_1.chars", ARG_DEFAULT }, { "titlemessage_initial_1.lines", ARG_DEFAULT }, { "titlemessage_initial_1.align", ARG_DEFAULT }, { "titlemessage_initial_1.valign", ARG_DEFAULT }, { "titlemessage_initial_1.font", ARG_DEFAULT }, { "titlemessage_initial_1.autowrap", ARG_DEFAULT }, { "titlemessage_initial_1.centered", ARG_DEFAULT }, { "titlemessage_initial_1.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_1.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_1.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_1.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_1.post_delay", ARG_DEFAULT }, { "titlemessage_initial_1.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_2.x", ARG_DEFAULT }, { "titlemessage_initial_2.y", ARG_DEFAULT }, { "titlemessage_initial_2.width", ARG_DEFAULT }, { "titlemessage_initial_2.height", ARG_DEFAULT }, { "titlemessage_initial_2.chars", ARG_DEFAULT }, { "titlemessage_initial_2.lines", ARG_DEFAULT }, { "titlemessage_initial_2.align", ARG_DEFAULT }, { "titlemessage_initial_2.valign", ARG_DEFAULT }, { "titlemessage_initial_2.font", ARG_DEFAULT }, { "titlemessage_initial_2.autowrap", ARG_DEFAULT }, { "titlemessage_initial_2.centered", ARG_DEFAULT }, { "titlemessage_initial_2.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_2.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_2.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_2.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_2.post_delay", ARG_DEFAULT }, { "titlemessage_initial_2.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_3.x", ARG_DEFAULT }, { "titlemessage_initial_3.y", ARG_DEFAULT }, { "titlemessage_initial_3.width", ARG_DEFAULT }, { "titlemessage_initial_3.height", ARG_DEFAULT }, { "titlemessage_initial_3.chars", ARG_DEFAULT }, { "titlemessage_initial_3.lines", ARG_DEFAULT }, { "titlemessage_initial_3.align", ARG_DEFAULT }, { "titlemessage_initial_3.valign", ARG_DEFAULT }, { "titlemessage_initial_3.font", ARG_DEFAULT }, { "titlemessage_initial_3.autowrap", ARG_DEFAULT }, { "titlemessage_initial_3.centered", ARG_DEFAULT }, { "titlemessage_initial_3.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_3.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_3.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_3.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_3.post_delay", ARG_DEFAULT }, { "titlemessage_initial_3.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_4.x", ARG_DEFAULT }, { "titlemessage_initial_4.y", ARG_DEFAULT }, { "titlemessage_initial_4.width", ARG_DEFAULT }, { "titlemessage_initial_4.height", ARG_DEFAULT }, { "titlemessage_initial_4.chars", ARG_DEFAULT }, { "titlemessage_initial_4.lines", ARG_DEFAULT }, { "titlemessage_initial_4.align", ARG_DEFAULT }, { "titlemessage_initial_4.valign", ARG_DEFAULT }, { "titlemessage_initial_4.font", ARG_DEFAULT }, { "titlemessage_initial_4.autowrap", ARG_DEFAULT }, { "titlemessage_initial_4.centered", ARG_DEFAULT }, { "titlemessage_initial_4.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_4.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_4.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_4.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_4.post_delay", ARG_DEFAULT }, { "titlemessage_initial_4.auto_delay", ARG_DEFAULT }, { "titlemessage_initial_5.x", ARG_DEFAULT }, { "titlemessage_initial_5.y", ARG_DEFAULT }, { "titlemessage_initial_5.width", ARG_DEFAULT }, { "titlemessage_initial_5.height", ARG_DEFAULT }, { "titlemessage_initial_5.chars", ARG_DEFAULT }, { "titlemessage_initial_5.lines", ARG_DEFAULT }, { "titlemessage_initial_5.align", ARG_DEFAULT }, { "titlemessage_initial_5.valign", ARG_DEFAULT }, { "titlemessage_initial_5.font", ARG_DEFAULT }, { "titlemessage_initial_5.autowrap", ARG_DEFAULT }, { "titlemessage_initial_5.centered", ARG_DEFAULT }, { "titlemessage_initial_5.parse_comments", ARG_DEFAULT }, { "titlemessage_initial_5.sort_priority", ARG_DEFAULT }, { "titlemessage_initial_5.fade_mode", ARG_DEFAULT }, { "titlemessage_initial_5.fade_delay", ARG_DEFAULT }, { "titlemessage_initial_5.post_delay", ARG_DEFAULT }, { "titlemessage_initial_5.auto_delay", ARG_DEFAULT }, { "titlemessage_1.x", ARG_DEFAULT }, { "titlemessage_1.y", ARG_DEFAULT }, { "titlemessage_1.width", ARG_DEFAULT }, { "titlemessage_1.height", ARG_DEFAULT }, { "titlemessage_1.chars", ARG_DEFAULT }, { "titlemessage_1.lines", ARG_DEFAULT }, { "titlemessage_1.align", ARG_DEFAULT }, { "titlemessage_1.valign", ARG_DEFAULT }, { "titlemessage_1.font", ARG_DEFAULT }, { "titlemessage_1.autowrap", ARG_DEFAULT }, { "titlemessage_1.centered", ARG_DEFAULT }, { "titlemessage_1.parse_comments", ARG_DEFAULT }, { "titlemessage_1.sort_priority", ARG_DEFAULT }, { "titlemessage_1.fade_mode", ARG_DEFAULT }, { "titlemessage_1.fade_delay", ARG_DEFAULT }, { "titlemessage_1.post_delay", ARG_DEFAULT }, { "titlemessage_1.auto_delay", ARG_DEFAULT }, { "titlemessage_2.x", ARG_DEFAULT }, { "titlemessage_2.y", ARG_DEFAULT }, { "titlemessage_2.width", ARG_DEFAULT }, { "titlemessage_2.height", ARG_DEFAULT }, { "titlemessage_2.chars", ARG_DEFAULT }, { "titlemessage_2.lines", ARG_DEFAULT }, { "titlemessage_2.align", ARG_DEFAULT }, { "titlemessage_2.valign", ARG_DEFAULT }, { "titlemessage_2.font", ARG_DEFAULT }, { "titlemessage_2.autowrap", ARG_DEFAULT }, { "titlemessage_2.centered", ARG_DEFAULT }, { "titlemessage_2.parse_comments", ARG_DEFAULT }, { "titlemessage_2.sort_priority", ARG_DEFAULT }, { "titlemessage_2.fade_mode", ARG_DEFAULT }, { "titlemessage_2.fade_delay", ARG_DEFAULT }, { "titlemessage_2.post_delay", ARG_DEFAULT }, { "titlemessage_2.auto_delay", ARG_DEFAULT }, { "titlemessage_3.x", ARG_DEFAULT }, { "titlemessage_3.y", ARG_DEFAULT }, { "titlemessage_3.width", ARG_DEFAULT }, { "titlemessage_3.height", ARG_DEFAULT }, { "titlemessage_3.chars", ARG_DEFAULT }, { "titlemessage_3.lines", ARG_DEFAULT }, { "titlemessage_3.align", ARG_DEFAULT }, { "titlemessage_3.valign", ARG_DEFAULT }, { "titlemessage_3.font", ARG_DEFAULT }, { "titlemessage_3.autowrap", ARG_DEFAULT }, { "titlemessage_3.centered", ARG_DEFAULT }, { "titlemessage_3.parse_comments", ARG_DEFAULT }, { "titlemessage_3.sort_priority", ARG_DEFAULT }, { "titlemessage_3.fade_mode", ARG_DEFAULT }, { "titlemessage_3.fade_delay", ARG_DEFAULT }, { "titlemessage_3.post_delay", ARG_DEFAULT }, { "titlemessage_3.auto_delay", ARG_DEFAULT }, { "titlemessage_4.x", ARG_DEFAULT }, { "titlemessage_4.y", ARG_DEFAULT }, { "titlemessage_4.width", ARG_DEFAULT }, { "titlemessage_4.height", ARG_DEFAULT }, { "titlemessage_4.chars", ARG_DEFAULT }, { "titlemessage_4.lines", ARG_DEFAULT }, { "titlemessage_4.align", ARG_DEFAULT }, { "titlemessage_4.valign", ARG_DEFAULT }, { "titlemessage_4.font", ARG_DEFAULT }, { "titlemessage_4.autowrap", ARG_DEFAULT }, { "titlemessage_4.centered", ARG_DEFAULT }, { "titlemessage_4.parse_comments", ARG_DEFAULT }, { "titlemessage_4.sort_priority", ARG_DEFAULT }, { "titlemessage_4.fade_mode", ARG_DEFAULT }, { "titlemessage_4.fade_delay", ARG_DEFAULT }, { "titlemessage_4.post_delay", ARG_DEFAULT }, { "titlemessage_4.auto_delay", ARG_DEFAULT }, { "titlemessage_5.x", ARG_DEFAULT }, { "titlemessage_5.y", ARG_DEFAULT }, { "titlemessage_5.width", ARG_DEFAULT }, { "titlemessage_5.height", ARG_DEFAULT }, { "titlemessage_5.chars", ARG_DEFAULT }, { "titlemessage_5.lines", ARG_DEFAULT }, { "titlemessage_5.align", ARG_DEFAULT }, { "titlemessage_5.valign", ARG_DEFAULT }, { "titlemessage_5.font", ARG_DEFAULT }, { "titlemessage_5.autowrap", ARG_DEFAULT }, { "titlemessage_5.centered", ARG_DEFAULT }, { "titlemessage_5.parse_comments", ARG_DEFAULT }, { "titlemessage_5.sort_priority", ARG_DEFAULT }, { "titlemessage_5.fade_mode", ARG_DEFAULT }, { "titlemessage_5.fade_delay", ARG_DEFAULT }, { "titlemessage_5.post_delay", ARG_DEFAULT }, { "titlemessage_5.auto_delay", ARG_DEFAULT }, { "readme.x", "-1" }, { "readme.y", "-1" }, { "readme.width", "-1" }, { "readme.height", "-1" }, { "readme.chars", "-1" }, { "readme.lines", "-1" }, { "readme.align", "center" }, { "readme.valign", "top" }, { "readme.font", "font.info.levelset" }, { "readme.autowrap", "true" }, { "readme.centered", "false" }, { "readme.parse_comments", "true" }, { "readme.sort_priority", "0" }, { "global.num_toons", "20" }, { "border.draw_masked.TITLE", "false" }, { "border.draw_masked.MAIN", "false" }, { "border.draw_masked.LEVELS", "false" }, { "border.draw_masked.LEVELNR", "false" }, { "border.draw_masked.SCORES", "false" }, { "border.draw_masked.EDITOR", "false" }, { "border.draw_masked.INFO", "false" }, { "border.draw_masked.SETUP", "false" }, { "border.draw_masked.PLAYING", "false" }, { "border.draw_masked.DOOR", "false" }, { "border.draw_masked_when_fading", "true" }, { "init.busy.x", "-1" }, { "init.busy.y", "-1" }, { "init.busy.align", "center" }, { "init.busy.valign", "middle" }, { "menu.enter_menu.fade_mode", "none" }, { "menu.enter_menu.fade_delay", "250" }, { "menu.enter_menu.post_delay", "125" }, { "menu.leave_menu.fade_mode", "none" }, { "menu.leave_menu.fade_delay", "250" }, { "menu.leave_menu.post_delay", "125" }, { "menu.enter_screen.fade_mode", "fade" }, { "menu.enter_screen.fade_delay", "250" }, { "menu.enter_screen.post_delay", "125" }, { "menu.leave_screen.fade_mode", "fade" }, { "menu.leave_screen.fade_delay", "250" }, { "menu.leave_screen.post_delay", "125" }, { "menu.next_screen.fade_mode", "crossfade" }, { "menu.next_screen.fade_delay", "250" }, { "menu.next_screen.post_delay", "125" }, { "menu.enter_screen.TITLE.fade_mode", "fade" }, { "menu.enter_screen.TITLE.fade_delay", "500" }, { "menu.enter_screen.TITLE.post_delay", "250" }, { "menu.enter_screen.TITLE.auto_delay", "-1" }, { "menu.enter_screen.SCORES.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.SCORES.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.SCORES.post_delay", ARG_DEFAULT }, { "menu.enter_screen.EDITOR.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.EDITOR.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.EDITOR.post_delay", ARG_DEFAULT }, { "menu.enter_screen.INFO.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.INFO.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.INFO.post_delay", ARG_DEFAULT }, { "menu.enter_screen.PLAYING.fade_mode", ARG_DEFAULT }, { "menu.enter_screen.PLAYING.fade_delay", ARG_DEFAULT }, { "menu.enter_screen.PLAYING.post_delay", ARG_DEFAULT }, { "menu.leave_screen.TITLE.fade_mode", "fade" }, { "menu.leave_screen.TITLE.fade_delay", "500" }, { "menu.leave_screen.TITLE.post_delay", "250" }, { "menu.leave_screen.TITLE.auto_delay", "-1" }, { "menu.leave_screen.SCORES.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.SCORES.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.SCORES.post_delay", ARG_DEFAULT }, { "menu.leave_screen.EDITOR.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.EDITOR.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.EDITOR.post_delay", ARG_DEFAULT }, { "menu.leave_screen.INFO.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.INFO.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.INFO.post_delay", ARG_DEFAULT }, { "menu.leave_screen.PLAYING.fade_mode", ARG_DEFAULT }, { "menu.leave_screen.PLAYING.fade_delay", ARG_DEFAULT }, { "menu.leave_screen.PLAYING.post_delay", ARG_DEFAULT }, { "menu.next_screen.TITLE.fade_mode", "fade" }, { "menu.next_screen.TITLE.fade_delay", "500" }, { "menu.next_screen.TITLE.post_delay", "250" }, { "menu.next_screen.TITLE.auto_delay", "-1" }, { "menu.next_screen.INFO.fade_mode", ARG_DEFAULT }, { "menu.next_screen.INFO.fade_delay", ARG_DEFAULT }, { "menu.next_screen.INFO.post_delay", ARG_DEFAULT }, { "menu.draw_xoffset", "0" }, { "menu.draw_yoffset", "0" }, { "menu.draw_xoffset.MAIN", "0" }, { "menu.draw_yoffset.MAIN", "0" }, { "menu.draw_xoffset.LEVELS", "0" }, { "menu.draw_yoffset.LEVELS", "0" }, { "menu.draw_xoffset.LEVELNR", "0" }, { "menu.draw_yoffset.LEVELNR", "0" }, { "menu.draw_xoffset.SCORES", "0" }, { "menu.draw_yoffset.SCORES", "0" }, { "menu.draw_xoffset.EDITOR", "0" }, { "menu.draw_yoffset.EDITOR", "0" }, { "menu.draw_xoffset.INFO", "0" }, { "menu.draw_yoffset.INFO", "0" }, { "menu.draw_xoffset.INFO[TITLE]", "0" }, { "menu.draw_yoffset.INFO[TITLE]", "0" }, { "menu.draw_xoffset.INFO[ELEMENTS]", "0" }, { "menu.draw_yoffset.INFO[ELEMENTS]", "0" }, { "menu.draw_xoffset.INFO[MUSIC]", "0" }, { "menu.draw_yoffset.INFO[MUSIC]", "0" }, { "menu.draw_xoffset.INFO[CREDITS]", "0" }, { "menu.draw_yoffset.INFO[CREDITS]", "0" }, { "menu.draw_xoffset.INFO[PROGRAM]", "0" }, { "menu.draw_yoffset.INFO[PROGRAM]", "0" }, { "menu.draw_xoffset.INFO[VERSION]", "0" }, { "menu.draw_yoffset.INFO[VERSION]", "0" }, { "menu.draw_xoffset.INFO[LEVELSET]", "0" }, { "menu.draw_yoffset.INFO[LEVELSET]", "0" }, { "menu.draw_xoffset.SETUP", "0" }, { "menu.draw_yoffset.SETUP", "0" }, { "menu.draw_xoffset.SETUP[GAME]", "0" }, { "menu.draw_yoffset.SETUP[GAME]", "0" }, { "menu.draw_xoffset.SETUP[EDITOR]", "0" }, { "menu.draw_yoffset.SETUP[EDITOR]", "0" }, { "menu.draw_xoffset.SETUP[GRAPHICS]", "0" }, { "menu.draw_yoffset.SETUP[GRAPHICS]", "0" }, { "menu.draw_xoffset.SETUP[SOUND]", "0" }, { "menu.draw_yoffset.SETUP[SOUND]", "0" }, { "menu.draw_xoffset.SETUP[ARTWORK]", "0" }, { "menu.draw_yoffset.SETUP[ARTWORK]", "0" }, { "menu.draw_xoffset.SETUP[INPUT]", "0" }, { "menu.draw_yoffset.SETUP[INPUT]", "0" }, { "menu.draw_xoffset.SETUP[TOUCH]", "0" }, { "menu.draw_yoffset.SETUP[TOUCH]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_1]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_1]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_2]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_2]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_3]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_3]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_4]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_4]", "0" }, { "menu.draw_xoffset.SETUP[SHORTCUTS_5]", "0" }, { "menu.draw_yoffset.SETUP[SHORTCUTS_5]", "0" }, { "menu.draw_xoffset.SETUP[CHOOSE_ARTWORK]", "0" }, { "menu.draw_yoffset.SETUP[CHOOSE_ARTWORK]", "0" }, { "menu.draw_xoffset.SETUP[CHOOSE_OTHER]", "0" }, { "menu.draw_yoffset.SETUP[CHOOSE_OTHER]", "0" }, { "menu.scrollbar_xoffset", "0" }, { "menu.list_size", "-1" }, { "menu.list_size.LEVELS", "-1" }, { "menu.list_size.LEVELNR", "-1" }, { "menu.list_size.SCORES", "-1" }, { "menu.list_size.INFO", "-1" }, { "menu.list_size.INFO[ELEMENTS]", "-1" }, { "menu.list_size.SETUP", "-1" }, { "menu.left_spacing.INFO", "16" }, { "menu.left_spacing.INFO[TITLE]", "16" }, { "menu.left_spacing.INFO[ELEMENTS]", "16" }, { "menu.left_spacing.INFO[MUSIC]", "16" }, { "menu.left_spacing.INFO[CREDITS]", "16" }, { "menu.left_spacing.INFO[PROGRAM]", "16" }, { "menu.left_spacing.INFO[VERSION]", "16" }, { "menu.left_spacing.INFO[LEVELSET]", "16" }, { "menu.left_spacing.SETUP[INPUT]", "16" }, { "menu.right_spacing.INFO", "16" }, { "menu.right_spacing.INFO[TITLE]", "16" }, { "menu.right_spacing.INFO[ELEMENTS]", "16" }, { "menu.right_spacing.INFO[MUSIC]", "16" }, { "menu.right_spacing.INFO[CREDITS]", "16" }, { "menu.right_spacing.INFO[PROGRAM]", "16" }, { "menu.right_spacing.INFO[VERSION]", "16" }, { "menu.right_spacing.INFO[LEVELSET]", "16" }, { "menu.right_spacing.SETUP[INPUT]", "16" }, { "menu.top_spacing.INFO", "100" }, { "menu.top_spacing.INFO[TITLE]", "100" }, { "menu.top_spacing.INFO[ELEMENTS]", "100" }, { "menu.top_spacing.INFO[MUSIC]", "100" }, { "menu.top_spacing.INFO[CREDITS]", "100" }, { "menu.top_spacing.INFO[PROGRAM]", "100" }, { "menu.top_spacing.INFO[VERSION]", "100" }, { "menu.top_spacing.INFO[LEVELSET]", "100" }, { "menu.top_spacing.SETUP[INPUT]", "100" }, { "menu.bottom_spacing.INFO", "20" }, { "menu.bottom_spacing.INFO[TITLE]", "20" }, { "menu.bottom_spacing.INFO[ELEMENTS]", "20" }, { "menu.bottom_spacing.INFO[MUSIC]", "20" }, { "menu.bottom_spacing.INFO[CREDITS]", "20" }, { "menu.bottom_spacing.INFO[PROGRAM]", "20" }, { "menu.bottom_spacing.INFO[VERSION]", "20" }, { "menu.bottom_spacing.INFO[LEVELSET]", "20" }, { "menu.bottom_spacing.SETUP[INPUT]", "20" }, { "menu.paragraph_spacing.INFO", "-3" }, { "menu.paragraph_spacing.INFO[TITLE]", "-3" }, { "menu.paragraph_spacing.INFO[ELEMENTS]", "-3" }, { "menu.paragraph_spacing.INFO[MUSIC]", "-3" }, { "menu.paragraph_spacing.INFO[CREDITS]", "-3" }, { "menu.paragraph_spacing.INFO[PROGRAM]", "-3" }, { "menu.paragraph_spacing.INFO[VERSION]", "-3" }, { "menu.paragraph_spacing.INFO[LEVELSET]", "-3" }, { "menu.paragraph_spacing.SETUP[INPUT]", "-1" }, { "menu.headline1_spacing.INFO", "-2" }, { "menu.headline1_spacing.INFO[TITLE]", "-2" }, { "menu.headline1_spacing.INFO[ELEMENTS]", "-2" }, { "menu.headline1_spacing.INFO[MUSIC]", "-2" }, { "menu.headline1_spacing.INFO[CREDITS]", "-2" }, { "menu.headline1_spacing.INFO[PROGRAM]", "-2" }, { "menu.headline1_spacing.INFO[VERSION]", "-2" }, { "menu.headline1_spacing.INFO[LEVELSET]", "-2" }, { "menu.headline1_spacing.SETUP[INPUT]", "-2" }, { "menu.headline2_spacing.INFO", "-1" }, { "menu.headline2_spacing.INFO[TITLE]", "-1" }, { "menu.headline2_spacing.INFO[ELEMENTS]", "-1" }, { "menu.headline2_spacing.INFO[MUSIC]", "-1" }, { "menu.headline2_spacing.INFO[CREDITS]", "-1" }, { "menu.headline2_spacing.INFO[PROGRAM]", "-1" }, { "menu.headline2_spacing.INFO[VERSION]", "-1" }, { "menu.headline2_spacing.INFO[LEVELSET]", "-1" }, { "menu.headline2_spacing.SETUP[INPUT]", "-1" }, { "menu.line_spacing.INFO", "0" }, { "menu.line_spacing.INFO[TITLE]", "0" }, { "menu.line_spacing.INFO[ELEMENTS]", "0" }, { "menu.line_spacing.INFO[MUSIC]", "0" }, { "menu.line_spacing.INFO[CREDITS]", "0" }, { "menu.line_spacing.INFO[PROGRAM]", "0" }, { "menu.line_spacing.INFO[VERSION]", "0" }, { "menu.line_spacing.INFO[LEVELSET]", "0" }, { "menu.line_spacing.SETUP[INPUT]", "0" }, { "menu.extra_spacing.INFO", "2" }, { "menu.extra_spacing.INFO[TITLE]", "2" }, { "menu.extra_spacing.INFO[ELEMENTS]", "2" }, { "menu.extra_spacing.INFO[MUSIC]", "2" }, { "menu.extra_spacing.INFO[CREDITS]", "2" }, { "menu.extra_spacing.INFO[PROGRAM]", "2" }, { "menu.extra_spacing.INFO[VERSION]", "2" }, { "menu.extra_spacing.INFO[LEVELSET]", "2" }, { "menu.extra_spacing.SETUP[INPUT]", "2" }, { "main.button.name.x", "0" }, { "main.button.name.y", "64" }, { "main.button.levels.x", "0" }, { "main.button.levels.y", "96" }, { "main.button.scores.x", "0" }, { "main.button.scores.y", "128" }, { "main.button.editor.x", "0" }, { "main.button.editor.y", "160" }, { "main.button.info.x", "0" }, { "main.button.info.y", "192" }, { "main.button.game.x", "0" }, { "main.button.game.y", "224" }, { "main.button.setup.x", "0" }, { "main.button.setup.y", "256" }, { "main.button.quit.x", "0" }, { "main.button.quit.y", "288" }, { "main.button.prev_level.x", "320" }, { "main.button.prev_level.y", "96" }, { "main.button.next_level.x", "448" }, { "main.button.next_level.y", "96" }, { "main.text.name.x", "-1" }, { "main.text.name.y", "-1" }, { "main.text.name.width", "-1" }, { "main.text.name.height", "-1" }, { "main.text.name.align", "left" }, { "main.text.name.valign", "top" }, { "main.text.name.font", "font.menu_1" }, { "main.text.levels.x", "-1" }, { "main.text.levels.y", "-1" }, { "main.text.levels.width", "-1" }, { "main.text.levels.height", "-1" }, { "main.text.levels.align", "left" }, { "main.text.levels.valign", "top" }, { "main.text.levels.font", "font.menu_1" }, { "main.text.scores.x", "-1" }, { "main.text.scores.y", "-1" }, { "main.text.scores.width", "-1" }, { "main.text.scores.height", "-1" }, { "main.text.scores.align", "left" }, { "main.text.scores.valign", "top" }, { "main.text.scores.font", "font.menu_1" }, { "main.text.editor.x", "-1" }, { "main.text.editor.y", "-1" }, { "main.text.editor.width", "-1" }, { "main.text.editor.height", "-1" }, { "main.text.editor.align", "left" }, { "main.text.editor.valign", "top" }, { "main.text.editor.font", "font.menu_1" }, { "main.text.info.x", "-1" }, { "main.text.info.y", "-1" }, { "main.text.info.width", "-1" }, { "main.text.info.height", "-1" }, { "main.text.info.align", "left" }, { "main.text.info.valign", "top" }, { "main.text.info.font", "font.menu_1" }, { "main.text.game.x", "-1" }, { "main.text.game.y", "-1" }, { "main.text.game.width", "-1" }, { "main.text.game.height", "-1" }, { "main.text.game.align", "left" }, { "main.text.game.valign", "top" }, { "main.text.game.font", "font.menu_1" }, { "main.text.setup.x", "-1" }, { "main.text.setup.y", "-1" }, { "main.text.setup.width", "-1" }, { "main.text.setup.height", "-1" }, { "main.text.setup.align", "left" }, { "main.text.setup.valign", "top" }, { "main.text.setup.font", "font.menu_1" }, { "main.text.quit.x", "-1" }, { "main.text.quit.y", "-1" }, { "main.text.quit.width", "-1" }, { "main.text.quit.height", "-1" }, { "main.text.quit.align", "left" }, { "main.text.quit.valign", "top" }, { "main.text.quit.font", "font.menu_1" }, { "main.text.first_level.x", "488" }, { "main.text.first_level.y", "98" }, { "main.text.first_level.align", "left" }, { "main.text.first_level.valign", "top" }, { "main.text.first_level.digits", "3" }, { "main.text.first_level.font", "font.text_3" }, { "main.text.last_level.x", "488" }, { "main.text.last_level.y", "112" }, { "main.text.last_level.align", "left" }, { "main.text.last_level.valign", "top" }, { "main.text.last_level.digits", "3" }, { "main.text.last_level.font", "font.text_3" }, { "main.text.level_number.x", "352" }, { "main.text.level_number.y", "96" }, { "main.text.level_number.align", "left" }, { "main.text.level_number.valign", "top" }, { "main.text.level_number.digits", "3" }, { "main.text.level_number.font", "font.value_1" }, { "main.text.level_info_1.x", "272" }, { "main.text.level_info_1.y", "352" }, { "main.text.level_info_1.align", "center" }, { "main.text.level_info_1.valign", "top" }, { "main.text.level_info_1.chars", "-1" }, { "main.text.level_info_1.font", "font.text_1" }, { "main.text.level_info_2.x", "272" }, { "main.text.level_info_2.y", "523" }, { "main.text.level_info_2.align", "center" }, { "main.text.level_info_2.valign", "top" }, { "main.text.level_info_2.chars", "-1" }, { "main.text.level_info_2.font", "font.text_2" }, { "main.text.level_info_2.font_header", "font.text_4" }, { "main.text.level_name.x", "-1" }, { "main.text.level_name.y", "-1" }, { "main.text.level_name.align", "left" }, { "main.text.level_name.valign", "top" }, { "main.text.level_name.chars", "-1" }, { "main.text.level_name.font", "font.text_2" }, { "main.text.level_author.x", "-1" }, { "main.text.level_author.y", "-1" }, { "main.text.level_author.align", "left" }, { "main.text.level_author.valign", "top" }, { "main.text.level_author.chars", "-1" }, { "main.text.level_author.font", "font.text_2" }, { "main.text.level_year.x", "-1" }, { "main.text.level_year.y", "-1" }, { "main.text.level_year.align", "left" }, { "main.text.level_year.valign", "top" }, { "main.text.level_year.digits", "-1" }, { "main.text.level_year.font", "font.text_2" }, { "main.text.level_imported_from.x", "-1" }, { "main.text.level_imported_from.y", "-1" }, { "main.text.level_imported_from.align", "left" }, { "main.text.level_imported_from.valign", "top" }, { "main.text.level_imported_from.chars", "-1" }, { "main.text.level_imported_from.font", "font.text_2" }, { "main.text.level_imported_by.x", "-1" }, { "main.text.level_imported_by.y", "-1" }, { "main.text.level_imported_by.align", "left" }, { "main.text.level_imported_by.valign", "top" }, { "main.text.level_imported_by.chars", "-1" }, { "main.text.level_imported_by.font", "font.text_2" }, { "main.text.level_tested_by.x", "-1" }, { "main.text.level_tested_by.y", "-1" }, { "main.text.level_tested_by.align", "left" }, { "main.text.level_tested_by.valign", "top" }, { "main.text.level_tested_by.chars", "-1" }, { "main.text.level_tested_by.font", "font.text_2" }, { "main.text.title_1.x", "272" }, { "main.text.title_1.y", "8" }, { "main.text.title_1.align", "center" }, { "main.text.title_1.valign", "top" }, { "main.text.title_1.font", "font.title_1" }, { "main.text.title_2.x", "272" }, { "main.text.title_2.y", "46" }, { "main.text.title_2.align", "center" }, { "main.text.title_2.valign", "top" }, { "main.text.title_2.font", "font.title_2" }, { "main.text.title_3.x", "272" }, { "main.text.title_3.y", "326" }, { "main.text.title_3.align", "center" }, { "main.text.title_3.valign", "top" }, { "main.text.title_3.font", "font.title_2" }, { "main.input.name.x", "-1" }, { "main.input.name.y", "-1" }, { "main.input.name.align", "left" }, { "main.input.name.valign", "top" }, { "main.input.name.font", "font.input_1" }, { "preview.x", "272" }, { "preview.y", "380" }, { "preview.align", "center" }, { "preview.valign", "top" }, { "preview.xsize", "66" }, { "preview.ysize", "34" }, { "preview.xoffset", "0" }, { "preview.yoffset", "0" }, { "preview.tile_size", "4" }, { "preview.step_offset", "1" }, { "preview.step_delay", "50" }, { "preview.anim_mode", "default" }, { "door_1.part_1.x", "0" }, { "door_1.part_1.y", "0" }, { "door_1.part_1.step_xoffset", "3" }, { "door_1.part_1.step_yoffset", "1" }, { "door_1.part_1.step_delay", "10" }, { "door_1.part_1.start_step", "0" }, { "door_1.part_1.start_step_opening", "0" }, { "door_1.part_1.start_step_closing", "0" }, { "door_1.part_1.draw_masked", "true" }, { "door_1.part_1.draw_order", "3" }, { "door_1.part_2.x", "0" }, { "door_1.part_2.y", "77" }, { "door_1.part_2.step_xoffset", "3" }, { "door_1.part_2.step_yoffset", "1" }, { "door_1.part_2.step_delay", "10" }, { "door_1.part_2.start_step", "0" }, { "door_1.part_2.start_step_opening", "0" }, { "door_1.part_2.start_step_closing", "0" }, { "door_1.part_2.draw_masked", "true" }, { "door_1.part_2.draw_order", "5" }, { "door_1.part_3.x", "0" }, { "door_1.part_3.y", "140" }, { "door_1.part_3.step_xoffset", "3" }, { "door_1.part_3.step_yoffset", "1" }, { "door_1.part_3.step_delay", "10" }, { "door_1.part_3.start_step", "0" }, { "door_1.part_3.start_step_opening", "0" }, { "door_1.part_3.start_step_closing", "0" }, { "door_1.part_3.draw_masked", "true" }, { "door_1.part_3.draw_order", "4" }, { "door_1.part_4.x", "0" }, { "door_1.part_4.y", "203" }, { "door_1.part_4.step_xoffset", "3" }, { "door_1.part_4.step_yoffset", "1" }, { "door_1.part_4.step_delay", "10" }, { "door_1.part_4.start_step", "0" }, { "door_1.part_4.start_step_opening", "0" }, { "door_1.part_4.start_step_closing", "0" }, { "door_1.part_4.draw_masked", "true" }, { "door_1.part_4.draw_order", "6" }, { "door_1.part_5.x", "0" }, { "door_1.part_5.y", "0" }, { "door_1.part_5.step_xoffset", "-3" }, { "door_1.part_5.step_yoffset", "-1" }, { "door_1.part_5.step_delay", "10" }, { "door_1.part_5.start_step", "0" }, { "door_1.part_5.start_step_opening", "0" }, { "door_1.part_5.start_step_closing", "0" }, { "door_1.part_5.draw_masked", "true" }, { "door_1.part_5.draw_order", "1" }, { "door_1.part_6.x", "0" }, { "door_1.part_6.y", "77" }, { "door_1.part_6.step_xoffset", "-3" }, { "door_1.part_6.step_yoffset", "-1" }, { "door_1.part_6.step_delay", "10" }, { "door_1.part_6.start_step", "0" }, { "door_1.part_6.start_step_opening", "0" }, { "door_1.part_6.start_step_closing", "0" }, { "door_1.part_6.draw_masked", "true" }, { "door_1.part_6.draw_order", "7" }, { "door_1.part_7.x", "0" }, { "door_1.part_7.y", "140" }, { "door_1.part_7.step_xoffset", "-3" }, { "door_1.part_7.step_yoffset", "-1" }, { "door_1.part_7.step_delay", "10" }, { "door_1.part_7.start_step", "0" }, { "door_1.part_7.start_step_opening", "0" }, { "door_1.part_7.start_step_closing", "0" }, { "door_1.part_7.draw_masked", "true" }, { "door_1.part_7.draw_order", "2" }, { "door_1.part_8.x", "0" }, { "door_1.part_8.y", "203" }, { "door_1.part_8.step_xoffset", "-3" }, { "door_1.part_8.step_yoffset", "-1" }, { "door_1.part_8.step_delay", "10" }, { "door_1.part_8.start_step", "0" }, { "door_1.part_8.start_step_opening", "0" }, { "door_1.part_8.start_step_closing", "0" }, { "door_1.part_8.draw_masked", "true" }, { "door_1.part_8.draw_order", "8" }, { "door_2.part_1.x", "0" }, { "door_2.part_1.y", "0" }, { "door_2.part_1.step_xoffset", "3" }, { "door_2.part_1.step_yoffset", "1" }, { "door_2.part_1.step_delay", "10" }, { "door_2.part_1.start_step", "0" }, { "door_2.part_1.start_step_opening", "0" }, { "door_2.part_1.start_step_closing", "0" }, { "door_2.part_1.draw_masked", "true" }, { "door_2.part_1.draw_order", "2" }, { "door_2.part_2.x", "0" }, { "door_2.part_2.y", "50" }, { "door_2.part_2.step_xoffset", "3" }, { "door_2.part_2.step_yoffset", "1" }, { "door_2.part_2.step_delay", "10" }, { "door_2.part_2.start_step", "0" }, { "door_2.part_2.start_step_opening", "0" }, { "door_2.part_2.start_step_closing", "0" }, { "door_2.part_2.draw_masked", "true" }, { "door_2.part_2.draw_order", "3" }, { "door_2.part_3.x", "0" }, { "door_2.part_3.y", "0" }, { "door_2.part_3.step_xoffset", "-3" }, { "door_2.part_3.step_yoffset", "-1" }, { "door_2.part_3.step_delay", "10" }, { "door_2.part_3.start_step", "0" }, { "door_2.part_3.start_step_opening", "0" }, { "door_2.part_3.start_step_closing", "0" }, { "door_2.part_3.draw_masked", "true" }, { "door_2.part_3.draw_order", "1" }, { "door_2.part_4.x", "0" }, { "door_2.part_4.y", "50" }, { "door_2.part_4.step_xoffset", "-3" }, { "door_2.part_4.step_yoffset", "-1" }, { "door_2.part_4.step_delay", "10" }, { "door_2.part_4.start_step", "0" }, { "door_2.part_4.start_step_opening", "0" }, { "door_2.part_4.start_step_closing", "0" }, { "door_2.part_4.draw_masked", "true" }, { "door_2.part_4.draw_order", "4" }, { "door_2.part_5.x", "-1" }, { "door_2.part_5.y", "-1" }, { "door_2.part_5.step_xoffset", "0" }, { "door_2.part_5.step_yoffset", "0" }, { "door_2.part_5.step_delay", "0" }, { "door_2.part_5.start_step", "0" }, { "door_2.part_5.start_step_opening", "0" }, { "door_2.part_5.start_step_closing", "0" }, { "door_2.part_5.draw_masked", "true" }, { "door_2.part_5.draw_order", "0" }, { "door_2.part_6.x", "-1" }, { "door_2.part_6.y", "-1" }, { "door_2.part_6.step_xoffset", "0" }, { "door_2.part_6.step_yoffset", "0" }, { "door_2.part_6.step_delay", "0" }, { "door_2.part_6.start_step", "0" }, { "door_2.part_6.start_step_opening", "0" }, { "door_2.part_6.start_step_closing", "0" }, { "door_2.part_6.draw_masked", "true" }, { "door_2.part_6.draw_order", "0" }, { "door_2.part_7.x", "-1" }, { "door_2.part_7.y", "-1" }, { "door_2.part_7.step_xoffset", "0" }, { "door_2.part_7.step_yoffset", "0" }, { "door_2.part_7.step_delay", "0" }, { "door_2.part_7.start_step", "0" }, { "door_2.part_7.start_step_opening", "0" }, { "door_2.part_7.start_step_closing", "0" }, { "door_2.part_7.draw_masked", "true" }, { "door_2.part_7.draw_order", "0" }, { "door_2.part_8.x", "-1" }, { "door_2.part_8.y", "-1" }, { "door_2.part_8.step_xoffset", "0" }, { "door_2.part_8.step_yoffset", "0" }, { "door_2.part_8.step_delay", "0" }, { "door_2.part_8.start_step", "0" }, { "door_2.part_8.start_step_opening", "0" }, { "door_2.part_8.start_step_closing", "0" }, { "door_2.part_8.draw_masked", "true" }, { "door_2.part_8.draw_order", "0" }, { "door_1.panel.x", "0" }, { "door_1.panel.y", "0" }, { "door_1.panel.step_xoffset", "0" }, { "door_1.panel.step_yoffset", "1" }, { "door_1.panel.step_delay", "10" }, { "door_1.panel.start_step", "246" }, { "door_1.panel.start_step_opening", "0" }, { "door_1.panel.start_step_closing", "0" }, { "door_1.panel.draw_masked", "false" }, { "door_1.panel.draw_order", "0" }, { "door_2.panel.x", "0" }, { "door_2.panel.y", "0" }, { "door_2.panel.step_xoffset", "0" }, { "door_2.panel.step_yoffset", "1" }, { "door_2.panel.step_delay", "10" }, { "door_2.panel.start_step", "66" }, { "door_2.panel.start_step_opening", "0" }, { "door_2.panel.start_step_closing", "0" }, { "door_2.panel.draw_masked", "false" }, { "door_2.panel.draw_order", "0" }, { "door_1.width", "-1" }, { "door_1.height", "-1" }, { "door_1.step_offset", "2" }, { "door_1.step_delay", "10" }, { "door_1.post_delay", "100" }, { "door_1.anim_mode", "default" }, { "door_2.width", "-1" }, { "door_2.height", "-1" }, { "door_2.step_offset", "2" }, { "door_2.step_delay", "10" }, { "door_2.post_delay", "100" }, { "door_2.anim_mode", "default" }, { "game.panel.level_number.x", "51" }, { "game.panel.level_number.y", "20" }, { "game.panel.level_number.align", "center" }, { "game.panel.level_number.valign", "top" }, { "game.panel.level_number.digits", "-1" }, { "game.panel.level_number.font", "font.text_2" }, { "game.panel.level_number.font_narrow", "font.text_1" }, { "game.panel.level_number.draw_masked", "true" }, { "game.panel.level_number.draw_order", "0" }, { "game.panel.gems.x", "50" }, { "game.panel.gems.y", "54" }, { "game.panel.gems.align", "center" }, { "game.panel.gems.valign", "top" }, { "game.panel.gems.digits", "3" }, { "game.panel.gems.font", "font.text_2" }, { "game.panel.gems.draw_masked", "true" }, { "game.panel.gems.draw_order", "0" }, { "game.panel.inventory_count.x", "50" }, { "game.panel.inventory_count.y", "89" }, { "game.panel.inventory_count.align", "center" }, { "game.panel.inventory_count.valign", "top" }, { "game.panel.inventory_count.digits", "3" }, { "game.panel.inventory_count.font", "font.text_2" }, { "game.panel.inventory_count.draw_masked", "true" }, { "game.panel.inventory_count.draw_order", "0" }, { "game.panel.inventory_first_1.x", "-1" }, { "game.panel.inventory_first_1.y", "-1" }, { "game.panel.inventory_first_1.tile_size", "16" }, { "game.panel.inventory_first_1.draw_masked", "false" }, { "game.panel.inventory_first_1.draw_order", "0" }, { "game.panel.inventory_first_2.x", "-1" }, { "game.panel.inventory_first_2.y", "-1" }, { "game.panel.inventory_first_2.tile_size", "16" }, { "game.panel.inventory_first_2.draw_masked", "false" }, { "game.panel.inventory_first_2.draw_order", "0" }, { "game.panel.inventory_first_3.x", "-1" }, { "game.panel.inventory_first_3.y", "-1" }, { "game.panel.inventory_first_3.tile_size", "16" }, { "game.panel.inventory_first_3.draw_masked", "false" }, { "game.panel.inventory_first_3.draw_order", "0" }, { "game.panel.inventory_first_4.x", "-1" }, { "game.panel.inventory_first_4.y", "-1" }, { "game.panel.inventory_first_4.tile_size", "16" }, { "game.panel.inventory_first_4.draw_masked", "false" }, { "game.panel.inventory_first_4.draw_order", "0" }, { "game.panel.inventory_first_5.x", "-1" }, { "game.panel.inventory_first_5.y", "-1" }, { "game.panel.inventory_first_5.tile_size", "16" }, { "game.panel.inventory_first_5.draw_masked", "false" }, { "game.panel.inventory_first_5.draw_order", "0" }, { "game.panel.inventory_first_6.x", "-1" }, { "game.panel.inventory_first_6.y", "-1" }, { "game.panel.inventory_first_6.tile_size", "16" }, { "game.panel.inventory_first_6.draw_masked", "false" }, { "game.panel.inventory_first_6.draw_order", "0" }, { "game.panel.inventory_first_7.x", "-1" }, { "game.panel.inventory_first_7.y", "-1" }, { "game.panel.inventory_first_7.tile_size", "16" }, { "game.panel.inventory_first_7.draw_masked", "false" }, { "game.panel.inventory_first_7.draw_order", "0" }, { "game.panel.inventory_first_8.x", "-1" }, { "game.panel.inventory_first_8.y", "-1" }, { "game.panel.inventory_first_8.tile_size", "16" }, { "game.panel.inventory_first_8.draw_masked", "false" }, { "game.panel.inventory_first_8.draw_order", "0" }, { "game.panel.inventory_last_1.x", "-1" }, { "game.panel.inventory_last_1.y", "-1" }, { "game.panel.inventory_last_1.tile_size", "16" }, { "game.panel.inventory_last_1.draw_masked", "false" }, { "game.panel.inventory_last_1.draw_order", "0" }, { "game.panel.inventory_last_2.x", "-1" }, { "game.panel.inventory_last_2.y", "-1" }, { "game.panel.inventory_last_2.tile_size", "16" }, { "game.panel.inventory_last_2.draw_masked", "false" }, { "game.panel.inventory_last_2.draw_order", "0" }, { "game.panel.inventory_last_3.x", "-1" }, { "game.panel.inventory_last_3.y", "-1" }, { "game.panel.inventory_last_3.tile_size", "16" }, { "game.panel.inventory_last_3.draw_masked", "false" }, { "game.panel.inventory_last_3.draw_order", "0" }, { "game.panel.inventory_last_4.x", "-1" }, { "game.panel.inventory_last_4.y", "-1" }, { "game.panel.inventory_last_4.tile_size", "16" }, { "game.panel.inventory_last_4.draw_masked", "false" }, { "game.panel.inventory_last_4.draw_order", "0" }, { "game.panel.inventory_last_5.x", "-1" }, { "game.panel.inventory_last_5.y", "-1" }, { "game.panel.inventory_last_5.tile_size", "16" }, { "game.panel.inventory_last_5.draw_masked", "false" }, { "game.panel.inventory_last_5.draw_order", "0" }, { "game.panel.inventory_last_6.x", "-1" }, { "game.panel.inventory_last_6.y", "-1" }, { "game.panel.inventory_last_6.tile_size", "16" }, { "game.panel.inventory_last_6.draw_masked", "false" }, { "game.panel.inventory_last_6.draw_order", "0" }, { "game.panel.inventory_last_7.x", "-1" }, { "game.panel.inventory_last_7.y", "-1" }, { "game.panel.inventory_last_7.tile_size", "16" }, { "game.panel.inventory_last_7.draw_masked", "false" }, { "game.panel.inventory_last_7.draw_order", "0" }, { "game.panel.inventory_last_8.x", "-1" }, { "game.panel.inventory_last_8.y", "-1" }, { "game.panel.inventory_last_8.tile_size", "16" }, { "game.panel.inventory_last_8.draw_masked", "false" }, { "game.panel.inventory_last_8.draw_order", "0" }, { "game.panel.key_1.x", "18" }, { "game.panel.key_1.y", "123" }, { "game.panel.key_1.tile_size", "16" }, { "game.panel.key_1.draw_masked", "false" }, { "game.panel.key_1.draw_order", "0" }, { "game.panel.key_2.x", "34" }, { "game.panel.key_2.y", "123" }, { "game.panel.key_2.tile_size", "16" }, { "game.panel.key_2.draw_masked", "false" }, { "game.panel.key_2.draw_order", "0" }, { "game.panel.key_3.x", "50" }, { "game.panel.key_3.y", "123" }, { "game.panel.key_3.tile_size", "16" }, { "game.panel.key_3.draw_masked", "false" }, { "game.panel.key_3.draw_order", "0" }, { "game.panel.key_4.x", "66" }, { "game.panel.key_4.y", "123" }, { "game.panel.key_4.tile_size", "16" }, { "game.panel.key_4.draw_masked", "false" }, { "game.panel.key_4.draw_order", "0" }, { "game.panel.key_5.x", "-1" }, { "game.panel.key_5.y", "-1" }, { "game.panel.key_5.tile_size", "16" }, { "game.panel.key_5.draw_masked", "false" }, { "game.panel.key_5.draw_order", "0" }, { "game.panel.key_6.x", "-1" }, { "game.panel.key_6.y", "-1" }, { "game.panel.key_6.tile_size", "16" }, { "game.panel.key_6.draw_masked", "false" }, { "game.panel.key_6.draw_order", "0" }, { "game.panel.key_7.x", "-1" }, { "game.panel.key_7.y", "-1" }, { "game.panel.key_7.tile_size", "16" }, { "game.panel.key_7.draw_masked", "false" }, { "game.panel.key_7.draw_order", "0" }, { "game.panel.key_8.x", "-1" }, { "game.panel.key_8.y", "-1" }, { "game.panel.key_8.tile_size", "16" }, { "game.panel.key_8.draw_masked", "false" }, { "game.panel.key_8.draw_order", "0" }, { "game.panel.key_white.x", "-1" }, { "game.panel.key_white.y", "-1" }, { "game.panel.key_white.tile_size", "16" }, { "game.panel.key_white.draw_masked", "false" }, { "game.panel.key_white.draw_order", "0" }, { "game.panel.key_white_count.x", "-1" }, { "game.panel.key_white_count.y", "-1" }, { "game.panel.key_white_count.align", "left" }, { "game.panel.key_white_count.valign", "top" }, { "game.panel.key_white_count.digits", "-1" }, { "game.panel.key_white_count.font", "font.text_2" }, { "game.panel.key_white_count.draw_masked", "true" }, { "game.panel.key_white_count.draw_order", "0" }, { "game.panel.score.x", "50" }, { "game.panel.score.y", "159" }, { "game.panel.score.align", "center" }, { "game.panel.score.valign", "top" }, { "game.panel.score.digits", "5" }, { "game.panel.score.font", "font.text_2" }, { "game.panel.score.draw_masked", "true" }, { "game.panel.score.draw_order", "0" }, { "game.panel.highscore.x", "-1" }, { "game.panel.highscore.y", "-1" }, { "game.panel.highscore.align", "left" }, { "game.panel.highscore.valign", "top" }, { "game.panel.highscore.digits", "5" }, { "game.panel.highscore.font", "font.text_2" }, { "game.panel.highscore.draw_masked", "true" }, { "game.panel.highscore.draw_order", "0" }, { "game.panel.time.x", "50" }, { "game.panel.time.y", "194" }, { "game.panel.time.align", "center" }, { "game.panel.time.valign", "top" }, { "game.panel.time.digits", "-1" }, { "game.panel.time.font", "font.text_2" }, { "game.panel.time.font_narrow", "font.text_1" }, { "game.panel.time.draw_masked", "true" }, { "game.panel.time.draw_order", "0" }, { "game.panel.time_hh.x", "-1" }, { "game.panel.time_hh.y", "-1" }, { "game.panel.time_hh.align", "left" }, { "game.panel.time_hh.valign", "top" }, { "game.panel.time_hh.digits", "2" }, { "game.panel.time_hh.font", "font.text_2" }, { "game.panel.time_hh.draw_masked", "true" }, { "game.panel.time_hh.draw_order", "0" }, { "game.panel.time_mm.x", "-1" }, { "game.panel.time_mm.y", "-1" }, { "game.panel.time_mm.align", "left" }, { "game.panel.time_mm.valign", "top" }, { "game.panel.time_mm.digits", "2" }, { "game.panel.time_mm.font", "font.text_2" }, { "game.panel.time_mm.draw_masked", "true" }, { "game.panel.time_mm.draw_order", "0" }, { "game.panel.time_ss.x", "-1" }, { "game.panel.time_ss.y", "-1" }, { "game.panel.time_ss.align", "left" }, { "game.panel.time_ss.valign", "top" }, { "game.panel.time_ss.digits", "2" }, { "game.panel.time_ss.font", "font.text_2" }, { "game.panel.time_ss.draw_masked", "true" }, { "game.panel.time_ss.draw_order", "0" }, { "game.panel.time_anim.x", "5" }, { "game.panel.time_anim.y", "72" }, { "game.panel.time_anim.direction", "right" }, { "game.panel.time_anim.class", "mm_engine_only" }, { "game.panel.health.x", "-1" }, { "game.panel.health.y", "-1" }, { "game.panel.health.align", "center" }, { "game.panel.health.valign", "top" }, { "game.panel.health.digits", "-1" }, { "game.panel.health.font", "font.text_2" }, { "game.panel.health.font_narrow", "font.text_1" }, { "game.panel.health.draw_masked", "true" }, { "game.panel.health.draw_order", "0" }, { "game.panel.health_anim.x", "5" }, { "game.panel.health_anim.y", "107" }, { "game.panel.health_anim.direction", "right" }, { "game.panel.health_anim.class", "mm_engine_only" }, { "game.panel.health_anim.style", "reverse" }, { "game.panel.frame.x", "-1" }, { "game.panel.frame.y", "-1" }, { "game.panel.frame.align", "left" }, { "game.panel.frame.valign", "top" }, { "game.panel.frame.digits", "-1" }, { "game.panel.frame.font", "font.text_2" }, { "game.panel.frame.draw_masked", "true" }, { "game.panel.frame.draw_order", "0" }, { "game.panel.shield_normal.x", "-1" }, { "game.panel.shield_normal.y", "-1" }, { "game.panel.shield_normal.tile_size", "16" }, { "game.panel.shield_normal.draw_masked", "false" }, { "game.panel.shield_normal.draw_order", "0" }, { "game.panel.shield_normal_time.x", "-1" }, { "game.panel.shield_normal_time.y", "-1" }, { "game.panel.shield_normal_time.align", "left" }, { "game.panel.shield_normal_time.valign", "top" }, { "game.panel.shield_normal_time.digits", "-1" }, { "game.panel.shield_normal_time.font", "font.text_2" }, { "game.panel.shield_normal_time.draw_masked", "true" }, { "game.panel.shield_normal_time.draw_order", "0" }, { "game.panel.shield_deadly.x", "-1" }, { "game.panel.shield_deadly.y", "-1" }, { "game.panel.shield_deadly.tile_size", "16" }, { "game.panel.shield_deadly.draw_masked", "false" }, { "game.panel.shield_deadly.draw_order", "0" }, { "game.panel.shield_deadly_time.x", "-1" }, { "game.panel.shield_deadly_time.y", "-1" }, { "game.panel.shield_deadly_time.align", "left" }, { "game.panel.shield_deadly_time.valign", "top" }, { "game.panel.shield_deadly_time.digits", "-1" }, { "game.panel.shield_deadly_time.font", "font.text_2" }, { "game.panel.shield_deadly_time.draw_masked","true" }, { "game.panel.shield_deadly_time.draw_order", "0" }, { "game.panel.exit.x", "-1" }, { "game.panel.exit.y", "-1" }, { "game.panel.exit.tile_size", "16" }, { "game.panel.exit.draw_masked", "false" }, { "game.panel.exit.draw_order", "0" }, { "game.panel.emc_magic_ball.x", "-1" }, { "game.panel.emc_magic_ball.y", "-1" }, { "game.panel.emc_magic_ball.tile_size", "16" }, { "game.panel.emc_magic_ball.draw_masked", "false" }, { "game.panel.emc_magic_ball.draw_order", "0" }, { "game.panel.emc_magic_ball_switch.x", "-1" }, { "game.panel.emc_magic_ball_switch.y", "-1" }, { "game.panel.emc_magic_ball_switch.tile_size", "16" }, { "game.panel.emc_magic_ball_switch.draw_masked", "true" }, { "game.panel.emc_magic_ball_switch.draw_order", "0" }, { "game.panel.light_switch.x", "-1" }, { "game.panel.light_switch.y", "-1" }, { "game.panel.light_switch.tile_size", "16" }, { "game.panel.light_switch.draw_masked", "false" }, { "game.panel.light_switch.draw_order", "0" }, { "game.panel.light_switch_time.x", "-1" }, { "game.panel.light_switch_time.y", "-1" }, { "game.panel.light_switch_time.align", "left" }, { "game.panel.light_switch_time.valign", "top" }, { "game.panel.light_switch_time.digits", "-1" }, { "game.panel.light_switch_time.font", "font.text_2" }, { "game.panel.light_switch_time.draw_masked", "true" }, { "game.panel.light_switch_time.draw_order", "0" }, { "game.panel.timegate_switch.x", "-1" }, { "game.panel.timegate_switch.y", "-1" }, { "game.panel.timegate_switch.tile_size", "16" }, { "game.panel.timegate_switch.draw_masked", "false" }, { "game.panel.timegate_switch.draw_order", "0" }, { "game.panel.timegate_switch_time.x", "-1" }, { "game.panel.timegate_switch_time.y", "-1" }, { "game.panel.timegate_switch_time.align", "left" }, { "game.panel.timegate_switch_time.valign", "top" }, { "game.panel.timegate_switch_time.digits", "-1" }, { "game.panel.timegate_switch_time.font", "font.text_2" }, { "game.panel.timegate_switch_time.draw_masked", "true" }, { "game.panel.timegate_switch_time.draw_order", "0" }, { "game.panel.switchgate_switch.x", "-1" }, { "game.panel.switchgate_switch.y", "-1" }, { "game.panel.switchgate_switch.tile_size", "16" }, { "game.panel.switchgate_switch.draw_masked", "false" }, { "game.panel.switchgate_switch.draw_order", "0" }, { "game.panel.emc_lenses.x", "-1" }, { "game.panel.emc_lenses.y", "-1" }, { "game.panel.emc_lenses.tile_size", "16" }, { "game.panel.emc_lenses.draw_masked", "false" }, { "game.panel.emc_lenses.draw_order", "0" }, { "game.panel.emc_lenses_time.x", "-1" }, { "game.panel.emc_lenses_time.y", "-1" }, { "game.panel.emc_lenses_time.align", "left" }, { "game.panel.emc_lenses_time.valign", "top" }, { "game.panel.emc_lenses_time.digits", "-1" }, { "game.panel.emc_lenses_time.font", "font.text_2" }, { "game.panel.emc_lenses_time.draw_masked", "true" }, { "game.panel.emc_lenses_time.draw_order", "0" }, { "game.panel.emc_magnifier.x", "-1" }, { "game.panel.emc_magnifier.y", "-1" }, { "game.panel.emc_magnifier.tile_size", "16" }, { "game.panel.emc_magnifier.draw_masked", "false" }, { "game.panel.emc_magnifier.draw_order", "0" }, { "game.panel.emc_magnifier_time.x", "-1" }, { "game.panel.emc_magnifier_time.y", "-1" }, { "game.panel.emc_magnifier_time.align", "left" }, { "game.panel.emc_magnifier_time.valign", "top" }, { "game.panel.emc_magnifier_time.digits", "-1" }, { "game.panel.emc_magnifier_time.font", "font.text_2" }, { "game.panel.emc_magnifier_time.draw_masked","true" }, { "game.panel.emc_magnifier_time.draw_order", "0" }, { "game.panel.balloon_switch.x", "-1" }, { "game.panel.balloon_switch.y", "-1" }, { "game.panel.balloon_switch.tile_size", "16" }, { "game.panel.balloon_switch.draw_masked", "false" }, { "game.panel.balloon_switch.draw_order", "0" }, { "game.panel.dynabomb_number.x", "-1" }, { "game.panel.dynabomb_number.y", "-1" }, { "game.panel.dynabomb_number.align", "left" }, { "game.panel.dynabomb_number.valign", "top" }, { "game.panel.dynabomb_number.digits", "-1" }, { "game.panel.dynabomb_number.font", "font.text_2" }, { "game.panel.dynabomb_number.draw_masked", "true" }, { "game.panel.dynabomb_number.draw_order", "0" }, { "game.panel.dynabomb_size.x", "-1" }, { "game.panel.dynabomb_size.y", "-1" }, { "game.panel.dynabomb_size.align", "left" }, { "game.panel.dynabomb_size.valign", "top" }, { "game.panel.dynabomb_size.digits", "-1" }, { "game.panel.dynabomb_size.font", "font.text_2" }, { "game.panel.dynabomb_size.draw_masked", "true" }, { "game.panel.dynabomb_size.draw_order", "0" }, { "game.panel.dynabomb_power.x", "-1" }, { "game.panel.dynabomb_power.y", "-1" }, { "game.panel.dynabomb_power.tile_size", "16" }, { "game.panel.dynabomb_power.draw_masked", "false" }, { "game.panel.dynabomb_power.draw_order", "0" }, { "game.panel.penguins.x", "-1" }, { "game.panel.penguins.y", "-1" }, { "game.panel.penguins.align", "left" }, { "game.panel.penguins.valign", "top" }, { "game.panel.penguins.digits", "-1" }, { "game.panel.penguins.font", "font.text_2" }, { "game.panel.penguins.draw_masked", "true" }, { "game.panel.penguins.draw_order", "0" }, { "game.panel.sokoban_objects.x", "-1" }, { "game.panel.sokoban_objects.y", "-1" }, { "game.panel.sokoban_objects.align", "left" }, { "game.panel.sokoban_objects.valign", "top" }, { "game.panel.sokoban_objects.digits", "-1" }, { "game.panel.sokoban_objects.font", "font.text_2" }, { "game.panel.sokoban_objects.draw_masked", "true" }, { "game.panel.sokoban_objects.draw_order", "0" }, { "game.panel.sokoban_fields.x", "-1" }, { "game.panel.sokoban_fields.y", "-1" }, { "game.panel.sokoban_fields.align", "left" }, { "game.panel.sokoban_fields.valign", "top" }, { "game.panel.sokoban_fields.digits", "-1" }, { "game.panel.sokoban_fields.font", "font.text_2" }, { "game.panel.sokoban_fields.draw_masked", "true" }, { "game.panel.sokoban_fields.draw_order", "0" }, { "game.panel.robot_wheel.x", "-1" }, { "game.panel.robot_wheel.y", "-1" }, { "game.panel.robot_wheel.tile_size", "16" }, { "game.panel.robot_wheel.draw_masked", "false" }, { "game.panel.robot_wheel.draw_order", "0" }, { "game.panel.conveyor_belt_1.x", "-1" }, { "game.panel.conveyor_belt_1.y", "-1" }, { "game.panel.conveyor_belt_1.tile_size", "16" }, { "game.panel.conveyor_belt_1.draw_masked", "false" }, { "game.panel.conveyor_belt_1.draw_order", "0" }, { "game.panel.conveyor_belt_1_switch.x", "-1" }, { "game.panel.conveyor_belt_1_switch.y", "-1" }, { "game.panel.conveyor_belt_1_switch.tile_size", "16" }, { "game.panel.conveyor_belt_1_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_1_switch.draw_order", "0" }, { "game.panel.conveyor_belt_2.x", "-1" }, { "game.panel.conveyor_belt_2.y", "-1" }, { "game.panel.conveyor_belt_2.tile_size", "16" }, { "game.panel.conveyor_belt_2.draw_masked", "false" }, { "game.panel.conveyor_belt_2.draw_order", "0" }, { "game.panel.conveyor_belt_2_switch.x", "-1" }, { "game.panel.conveyor_belt_2_switch.y", "-1" }, { "game.panel.conveyor_belt_2_switch.tile_size", "16" }, { "game.panel.conveyor_belt_2_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_2_switch.draw_order", "0" }, { "game.panel.conveyor_belt_3.x", "-1" }, { "game.panel.conveyor_belt_3.y", "-1" }, { "game.panel.conveyor_belt_3.tile_size", "16" }, { "game.panel.conveyor_belt_3.draw_masked", "false" }, { "game.panel.conveyor_belt_3.draw_order", "0" }, { "game.panel.conveyor_belt_3_switch.x", "-1" }, { "game.panel.conveyor_belt_3_switch.y", "-1" }, { "game.panel.conveyor_belt_3_switch.tile_size", "16" }, { "game.panel.conveyor_belt_3_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_3_switch.draw_order", "0" }, { "game.panel.conveyor_belt_4.x", "-1" }, { "game.panel.conveyor_belt_4.y", "-1" }, { "game.panel.conveyor_belt_4.tile_size", "16" }, { "game.panel.conveyor_belt_4.draw_masked", "false" }, { "game.panel.conveyor_belt_4.draw_order", "0" }, { "game.panel.conveyor_belt_4_switch.x", "-1" }, { "game.panel.conveyor_belt_4_switch.y", "-1" }, { "game.panel.conveyor_belt_4_switch.tile_size", "16" }, { "game.panel.conveyor_belt_4_switch.draw_masked", "false" }, { "game.panel.conveyor_belt_4_switch.draw_order", "0" }, { "game.panel.magic_wall.x", "-1" }, { "game.panel.magic_wall.y", "-1" }, { "game.panel.magic_wall.tile_size", "16" }, { "game.panel.magic_wall.draw_masked", "false" }, { "game.panel.magic_wall.draw_order", "0" }, { "game.panel.magic_wall_time.x", "-1" }, { "game.panel.magic_wall_time.y", "-1" }, { "game.panel.magic_wall_time.align", "left" }, { "game.panel.magic_wall_time.valign", "top" }, { "game.panel.magic_wall_time.digits", "-1" }, { "game.panel.magic_wall_time.font", "font.text_2" }, { "game.panel.magic_wall_time.draw_masked", "true" }, { "game.panel.magic_wall_time.draw_order", "0" }, { "game.panel.gravity_state.x", "-1" }, { "game.panel.gravity_state.y", "-1" }, { "game.panel.gravity_state.align", "left" }, { "game.panel.gravity_state.valign", "top" }, { "game.panel.gravity_state.chars", "-1" }, { "game.panel.gravity_state.font", "font.text_1" }, { "game.panel.gravity_state.font_active", "font.text_2" }, { "game.panel.gravity_state.draw_masked", "true" }, { "game.panel.gravity_state.draw_order", "0" }, { "game.panel.graphic_1.x", "-1" }, { "game.panel.graphic_1.y", "-1" }, { "game.panel.graphic_1.draw_masked", "true" }, { "game.panel.graphic_1.draw_order", "0" }, { "game.panel.graphic_2.x", "-1" }, { "game.panel.graphic_2.y", "-1" }, { "game.panel.graphic_2.draw_masked", "true" }, { "game.panel.graphic_2.draw_order", "0" }, { "game.panel.graphic_3.x", "-1" }, { "game.panel.graphic_3.y", "-1" }, { "game.panel.graphic_3.draw_masked", "true" }, { "game.panel.graphic_3.draw_order", "0" }, { "game.panel.graphic_4.x", "-1" }, { "game.panel.graphic_4.y", "-1" }, { "game.panel.graphic_4.draw_masked", "true" }, { "game.panel.graphic_4.draw_order", "0" }, { "game.panel.graphic_5.x", "-1" }, { "game.panel.graphic_5.y", "-1" }, { "game.panel.graphic_5.draw_masked", "true" }, { "game.panel.graphic_5.draw_order", "0" }, { "game.panel.graphic_6.x", "-1" }, { "game.panel.graphic_6.y", "-1" }, { "game.panel.graphic_6.draw_masked", "true" }, { "game.panel.graphic_6.draw_order", "0" }, { "game.panel.graphic_7.x", "-1" }, { "game.panel.graphic_7.y", "-1" }, { "game.panel.graphic_7.draw_masked", "true" }, { "game.panel.graphic_7.draw_order", "0" }, { "game.panel.graphic_8.x", "-1" }, { "game.panel.graphic_8.y", "-1" }, { "game.panel.graphic_8.draw_masked", "true" }, { "game.panel.graphic_8.draw_order", "0" }, { "game.panel.element_1.x", "-1" }, { "game.panel.element_1.y", "-1" }, { "game.panel.element_1.tile_size", "16" }, { "game.panel.element_1.element", "empty_space" }, { "game.panel.element_1.draw_masked", "false" }, { "game.panel.element_1.draw_order", "0" }, { "game.panel.element_1_count.x", "-1" }, { "game.panel.element_1_count.y", "-1" }, { "game.panel.element_1_count.align", "left" }, { "game.panel.element_1_count.valign", "top" }, { "game.panel.element_1_count.digits", "-1" }, { "game.panel.element_1_count.font", "font.text_2" }, { "game.panel.element_1_count.element", "empty_space" }, { "game.panel.element_1_count.draw_masked", "true" }, { "game.panel.element_1_count.draw_order", "0" }, { "game.panel.element_2.x", "-1" }, { "game.panel.element_2.y", "-1" }, { "game.panel.element_2.tile_size", "16" }, { "game.panel.element_2.element", "empty_space" }, { "game.panel.element_2.draw_masked", "false" }, { "game.panel.element_2.draw_order", "0" }, { "game.panel.element_2_count.x", "-1" }, { "game.panel.element_2_count.y", "-1" }, { "game.panel.element_2_count.align", "left" }, { "game.panel.element_2_count.valign", "top" }, { "game.panel.element_2_count.digits", "-1" }, { "game.panel.element_2_count.font", "font.text_2" }, { "game.panel.element_2_count.element", "empty_space" }, { "game.panel.element_2_count.draw_masked", "true" }, { "game.panel.element_2_count.draw_order", "0" }, { "game.panel.element_3.x", "-1" }, { "game.panel.element_3.y", "-1" }, { "game.panel.element_3.tile_size", "16" }, { "game.panel.element_3.element", "empty_space" }, { "game.panel.element_3.draw_masked", "false" }, { "game.panel.element_3.draw_order", "0" }, { "game.panel.element_3_count.x", "-1" }, { "game.panel.element_3_count.y", "-1" }, { "game.panel.element_3_count.align", "left" }, { "game.panel.element_3_count.valign", "top" }, { "game.panel.element_3_count.digits", "-1" }, { "game.panel.element_3_count.font", "font.text_2" }, { "game.panel.element_3_count.element", "empty_space" }, { "game.panel.element_3_count.draw_masked", "true" }, { "game.panel.element_3_count.draw_order", "0" }, { "game.panel.element_4.x", "-1" }, { "game.panel.element_4.y", "-1" }, { "game.panel.element_4.tile_size", "16" }, { "game.panel.element_4.element", "empty_space" }, { "game.panel.element_4.draw_masked", "false" }, { "game.panel.element_4.draw_order", "0" }, { "game.panel.element_4_count.x", "-1" }, { "game.panel.element_4_count.y", "-1" }, { "game.panel.element_4_count.align", "left" }, { "game.panel.element_4_count.valign", "top" }, { "game.panel.element_4_count.digits", "-1" }, { "game.panel.element_4_count.font", "font.text_2" }, { "game.panel.element_4_count.element", "empty_space" }, { "game.panel.element_4_count.draw_masked", "true" }, { "game.panel.element_4_count.draw_order", "0" }, { "game.panel.element_5.x", "-1" }, { "game.panel.element_5.y", "-1" }, { "game.panel.element_5.tile_size", "16" }, { "game.panel.element_5.element", "empty_space" }, { "game.panel.element_5.draw_masked", "false" }, { "game.panel.element_5.draw_order", "0" }, { "game.panel.element_5_count.x", "-1" }, { "game.panel.element_5_count.y", "-1" }, { "game.panel.element_5_count.align", "left" }, { "game.panel.element_5_count.valign", "top" }, { "game.panel.element_5_count.digits", "-1" }, { "game.panel.element_5_count.font", "font.text_2" }, { "game.panel.element_5_count.element", "empty_space" }, { "game.panel.element_5_count.draw_masked", "true" }, { "game.panel.element_5_count.draw_order", "0" }, { "game.panel.element_6.x", "-1" }, { "game.panel.element_6.y", "-1" }, { "game.panel.element_6.tile_size", "16" }, { "game.panel.element_6.element", "empty_space" }, { "game.panel.element_6.draw_masked", "false" }, { "game.panel.element_6.draw_order", "0" }, { "game.panel.element_6_count.x", "-1" }, { "game.panel.element_6_count.y", "-1" }, { "game.panel.element_6_count.align", "left" }, { "game.panel.element_6_count.valign", "top" }, { "game.panel.element_6_count.digits", "-1" }, { "game.panel.element_6_count.font", "font.text_2" }, { "game.panel.element_6_count.element", "empty_space" }, { "game.panel.element_6_count.draw_masked", "true" }, { "game.panel.element_6_count.draw_order", "0" }, { "game.panel.element_7.x", "-1" }, { "game.panel.element_7.y", "-1" }, { "game.panel.element_7.tile_size", "16" }, { "game.panel.element_7.element", "empty_space" }, { "game.panel.element_7.draw_masked", "false" }, { "game.panel.element_7.draw_order", "0" }, { "game.panel.element_7_count.x", "-1" }, { "game.panel.element_7_count.y", "-1" }, { "game.panel.element_7_count.align", "left" }, { "game.panel.element_7_count.valign", "top" }, { "game.panel.element_7_count.digits", "-1" }, { "game.panel.element_7_count.font", "font.text_2" }, { "game.panel.element_7_count.element", "empty_space" }, { "game.panel.element_7_count.draw_masked", "true" }, { "game.panel.element_7_count.draw_order", "0" }, { "game.panel.element_8.x", "-1" }, { "game.panel.element_8.y", "-1" }, { "game.panel.element_8.tile_size", "16" }, { "game.panel.element_8.element", "empty_space" }, { "game.panel.element_8.draw_masked", "false" }, { "game.panel.element_8.draw_order", "0" }, { "game.panel.element_8_count.x", "-1" }, { "game.panel.element_8_count.y", "-1" }, { "game.panel.element_8_count.align", "left" }, { "game.panel.element_8_count.valign", "top" }, { "game.panel.element_8_count.digits", "-1" }, { "game.panel.element_8_count.font", "font.text_2" }, { "game.panel.element_8_count.element", "empty_space" }, { "game.panel.element_8_count.draw_masked", "true" }, { "game.panel.element_8_count.draw_order", "0" }, { "game.panel.ce_score_1.x", "-1" }, { "game.panel.ce_score_1.y", "-1" }, { "game.panel.ce_score_1.align", "left" }, { "game.panel.ce_score_1.valign", "top" }, { "game.panel.ce_score_1.digits", "-1" }, { "game.panel.ce_score_1.font", "font.text_2" }, { "game.panel.ce_score_1.element", "empty_space" }, { "game.panel.ce_score_1.draw_masked", "true" }, { "game.panel.ce_score_1.draw_order", "0" }, { "game.panel.ce_score_1_element.x", "-1" }, { "game.panel.ce_score_1_element.y", "-1" }, { "game.panel.ce_score_1_element.tile_size", "16" }, { "game.panel.ce_score_1_element.element", "empty_space" }, { "game.panel.ce_score_1_element.draw_masked","false" }, { "game.panel.ce_score_1_element.draw_order", "0" }, { "game.panel.ce_score_2.x", "-1" }, { "game.panel.ce_score_2.y", "-1" }, { "game.panel.ce_score_2.align", "left" }, { "game.panel.ce_score_2.valign", "top" }, { "game.panel.ce_score_2.digits", "-1" }, { "game.panel.ce_score_2.font", "font.text_2" }, { "game.panel.ce_score_2.element", "empty_space" }, { "game.panel.ce_score_2.draw_masked", "true" }, { "game.panel.ce_score_2.draw_order", "0" }, { "game.panel.ce_score_2_element.x", "-1" }, { "game.panel.ce_score_2_element.y", "-1" }, { "game.panel.ce_score_2_element.tile_size", "16" }, { "game.panel.ce_score_2_element.element", "empty_space" }, { "game.panel.ce_score_2_element.draw_masked","false" }, { "game.panel.ce_score_2_element.draw_order", "0" }, { "game.panel.ce_score_3.x", "-1" }, { "game.panel.ce_score_3.y", "-1" }, { "game.panel.ce_score_3.align", "left" }, { "game.panel.ce_score_3.valign", "top" }, { "game.panel.ce_score_3.digits", "-1" }, { "game.panel.ce_score_3.font", "font.text_2" }, { "game.panel.ce_score_3.element", "empty_space" }, { "game.panel.ce_score_3.draw_masked", "true" }, { "game.panel.ce_score_3.draw_order", "0" }, { "game.panel.ce_score_3_element.x", "-1" }, { "game.panel.ce_score_3_element.y", "-1" }, { "game.panel.ce_score_3_element.tile_size", "16" }, { "game.panel.ce_score_3_element.element", "empty_space" }, { "game.panel.ce_score_3_element.draw_masked","false" }, { "game.panel.ce_score_3_element.draw_order", "0" }, { "game.panel.ce_score_4.x", "-1" }, { "game.panel.ce_score_4.y", "-1" }, { "game.panel.ce_score_4.align", "left" }, { "game.panel.ce_score_4.valign", "top" }, { "game.panel.ce_score_4.digits", "-1" }, { "game.panel.ce_score_4.font", "font.text_2" }, { "game.panel.ce_score_4.element", "empty_space" }, { "game.panel.ce_score_4.draw_masked", "true" }, { "game.panel.ce_score_4.draw_order", "0" }, { "game.panel.ce_score_4_element.x", "-1" }, { "game.panel.ce_score_4_element.y", "-1" }, { "game.panel.ce_score_4_element.tile_size", "16" }, { "game.panel.ce_score_4_element.element", "empty_space" }, { "game.panel.ce_score_4_element.draw_masked","false" }, { "game.panel.ce_score_4_element.draw_order", "0" }, { "game.panel.ce_score_5.x", "-1" }, { "game.panel.ce_score_5.y", "-1" }, { "game.panel.ce_score_5.align", "left" }, { "game.panel.ce_score_5.valign", "top" }, { "game.panel.ce_score_5.digits", "-1" }, { "game.panel.ce_score_5.font", "font.text_2" }, { "game.panel.ce_score_5.element", "empty_space" }, { "game.panel.ce_score_5.draw_masked", "true" }, { "game.panel.ce_score_5.draw_order", "0" }, { "game.panel.ce_score_5_element.x", "-1" }, { "game.panel.ce_score_5_element.y", "-1" }, { "game.panel.ce_score_5_element.tile_size", "16" }, { "game.panel.ce_score_5_element.element", "empty_space" }, { "game.panel.ce_score_5_element.draw_masked","false" }, { "game.panel.ce_score_5_element.draw_order", "0" }, { "game.panel.ce_score_6.x", "-1" }, { "game.panel.ce_score_6.y", "-1" }, { "game.panel.ce_score_6.align", "left" }, { "game.panel.ce_score_6.valign", "top" }, { "game.panel.ce_score_6.digits", "-1" }, { "game.panel.ce_score_6.font", "font.text_2" }, { "game.panel.ce_score_6.element", "empty_space" }, { "game.panel.ce_score_6.draw_masked", "true" }, { "game.panel.ce_score_6.draw_order", "0" }, { "game.panel.ce_score_6_element.x", "-1" }, { "game.panel.ce_score_6_element.y", "-1" }, { "game.panel.ce_score_6_element.tile_size", "16" }, { "game.panel.ce_score_6_element.element", "empty_space" }, { "game.panel.ce_score_6_element.draw_masked","false" }, { "game.panel.ce_score_6_element.draw_order", "0" }, { "game.panel.ce_score_7.x", "-1" }, { "game.panel.ce_score_7.y", "-1" }, { "game.panel.ce_score_7.align", "left" }, { "game.panel.ce_score_7.valign", "top" }, { "game.panel.ce_score_7.digits", "-1" }, { "game.panel.ce_score_7.font", "font.text_2" }, { "game.panel.ce_score_7.element", "empty_space" }, { "game.panel.ce_score_7.draw_masked", "true" }, { "game.panel.ce_score_7.draw_order", "0" }, { "game.panel.ce_score_7_element.x", "-1" }, { "game.panel.ce_score_7_element.y", "-1" }, { "game.panel.ce_score_7_element.tile_size", "16" }, { "game.panel.ce_score_7_element.element", "empty_space" }, { "game.panel.ce_score_7_element.draw_masked","false" }, { "game.panel.ce_score_7_element.draw_order", "0" }, { "game.panel.ce_score_8.x", "-1" }, { "game.panel.ce_score_8.y", "-1" }, { "game.panel.ce_score_8.align", "left" }, { "game.panel.ce_score_8.valign", "top" }, { "game.panel.ce_score_8.digits", "-1" }, { "game.panel.ce_score_8.font", "font.text_2" }, { "game.panel.ce_score_8.element", "empty_space" }, { "game.panel.ce_score_8.draw_masked", "true" }, { "game.panel.ce_score_8.draw_order", "0" }, { "game.panel.ce_score_8_element.x", "-1" }, { "game.panel.ce_score_8_element.y", "-1" }, { "game.panel.ce_score_8_element.tile_size", "16" }, { "game.panel.ce_score_8_element.element", "empty_space" }, { "game.panel.ce_score_8_element.draw_masked","false" }, { "game.panel.ce_score_8_element.draw_order", "0" }, { "game.panel.player_name.x", "-1" }, { "game.panel.player_name.y", "-1" }, { "game.panel.player_name.align", "left" }, { "game.panel.player_name.valign", "top" }, { "game.panel.player_name.chars", "-1" }, { "game.panel.player_name.font", "font.text_2" }, { "game.panel.player_name.draw_masked", "true" }, { "game.panel.player_name.draw_order", "0" }, { "game.panel.level_name.x", "-1" }, { "game.panel.level_name.y", "-1" }, { "game.panel.level_name.align", "left" }, { "game.panel.level_name.valign", "top" }, { "game.panel.level_name.chars", "-1" }, { "game.panel.level_name.font", "font.text_2" }, { "game.panel.level_name.draw_masked", "true" }, { "game.panel.level_name.draw_order", "0" }, { "game.panel.level_author.x", "-1" }, { "game.panel.level_author.y", "-1" }, { "game.panel.level_author.align", "left" }, { "game.panel.level_author.valign", "top" }, { "game.panel.level_author.chars", "-1" }, { "game.panel.level_author.font", "font.text_2" }, { "game.panel.level_author.draw_masked", "true" }, { "game.panel.level_author.draw_order", "0" }, { "game.button.stop.x", "5" }, { "game.button.stop.y", "215" }, { "game.button.pause.x", "35" }, { "game.button.pause.y", "215" }, { "game.button.play.x", "65" }, { "game.button.play.y", "215" }, { "game.button.undo.x", "-1" }, { "game.button.undo.y", "-1" }, { "game.button.redo.x", "-1" }, { "game.button.redo.y", "-1" }, { "game.button.save.x", "-1" }, { "game.button.save.y", "-1" }, { "game.button.pause2.x", "-1" }, { "game.button.pause2.y", "-1" }, { "game.button.load.x", "-1" }, { "game.button.load.y", "-1" }, { "game.button.sound_music.x", "5" }, { "game.button.sound_music.y", "245" }, { "game.button.sound_loops.x", "35" }, { "game.button.sound_loops.y", "245" }, { "game.button.sound_simple.x", "65" }, { "game.button.sound_simple.y", "245" }, { "game.button.panel_stop.x", "-1" }, { "game.button.panel_stop.y", "-1" }, { "game.button.panel_pause.x", "-1" }, { "game.button.panel_pause.y", "-1" }, { "game.button.panel_play.x", "-1" }, { "game.button.panel_play.y", "-1" }, { "game.button.panel_sound_music.x", "-1" }, { "game.button.panel_sound_music.y", "-1" }, { "game.button.panel_sound_loops.x", "-1" }, { "game.button.panel_sound_loops.y", "-1" }, { "game.button.panel_sound_simple.x", "-1" }, { "game.button.panel_sound_simple.y", "-1" }, { "tape.button.eject.x", "5" }, { "tape.button.eject.y", "77" }, { "tape.button.stop.x", "23" }, { "tape.button.stop.y", "77" }, { "tape.button.pause.x", "41" }, { "tape.button.pause.y", "77" }, { "tape.button.record.x", "59" }, { "tape.button.record.y", "77" }, { "tape.button.play.x", "77" }, { "tape.button.play.y", "77" }, { "tape.symbol.eject.x", "-1" }, { "tape.symbol.eject.y", "-1" }, { "tape.symbol.stop.x", "-1" }, { "tape.symbol.stop.y", "-1" }, { "tape.symbol.pause.x", "40" }, { "tape.symbol.pause.y", "41" }, { "tape.symbol.record.x", "25" }, { "tape.symbol.record.y", "41" }, { "tape.symbol.play.x", "57" }, { "tape.symbol.play.y", "41" }, { "tape.symbol.fast_forward.x", "39" }, { "tape.symbol.fast_forward.y", "42" }, { "tape.symbol.warp_forward.x", "39" }, { "tape.symbol.warp_forward.y", "42" }, { "tape.symbol.warp_forward_blind.x", "39" }, { "tape.symbol.warp_forward_blind.y", "42" }, { "tape.symbol.pause_before_end.x", "-1" }, { "tape.symbol.pause_before_end.y", "-1" }, { "tape.symbol.single_step.x", "-1" }, { "tape.symbol.single_step.y", "-1" }, { "tape.label.eject.x", "-1" }, { "tape.label.eject.y", "-1" }, { "tape.label.stop.x", "-1" }, { "tape.label.stop.y", "-1" }, { "tape.label.pause.x", "5" }, { "tape.label.pause.y", "61" }, { "tape.label.record.x", "5" }, { "tape.label.record.y", "41" }, { "tape.label.play.x", "70" }, { "tape.label.play.y", "41" }, { "tape.label.fast_forward.x", "5" }, { "tape.label.fast_forward.y", "42" }, { "tape.label.warp_forward.x", "5" }, { "tape.label.warp_forward.y", "42" }, { "tape.label.warp_forward_blind.x", "5" }, { "tape.label.warp_forward_blind.y", "42" }, { "tape.label.pause_before_end.x", "5" }, { "tape.label.pause_before_end.y", "42" }, { "tape.label.single_step.x", "57" }, { "tape.label.single_step.y", "42" }, { "tape.label.date.x", "5" }, { "tape.label.date.y", "5" }, { "tape.label.time.x", "46" }, { "tape.label.time.y", "55" }, { "tape.text.date.x", "7" }, { "tape.text.date.y", "19" }, { "tape.text.date.align", "left" }, { "tape.text.date.valign", "top" }, { "tape.text.date.digits", "-1" }, { "tape.text.date.xoffset", "27" }, { "tape.text.date.2nd_xoffset", "64" }, { "tape.text.date.font", "font.tape_recorder" }, { "tape.text.date.draw_masked", "false" }, { "tape.text.date_yyyy.x", "-1" }, { "tape.text.date_yyyy.y", "-1" }, { "tape.text.date_yyyy.align", "left" }, { "tape.text.date_yyyy.valign", "top" }, { "tape.text.date_yyyy.digits", "4" }, { "tape.text.date_yyyy.font", "font.tape_recorder" }, { "tape.text.date_yyyy.draw_masked", "false" }, { "tape.text.date_yy.x", "-1" }, { "tape.text.date_yy.y", "-1" }, { "tape.text.date_yy.align", "left" }, { "tape.text.date_yy.valign", "top" }, { "tape.text.date_yy.digits", "2" }, { "tape.text.date_yy.font", "font.tape_recorder" }, { "tape.text.date_yy.draw_masked", "false" }, { "tape.text.date_mon.x", "-1" }, { "tape.text.date_mon.y", "-1" }, { "tape.text.date_mon.align", "left" }, { "tape.text.date_mon.valign", "top" }, { "tape.text.date_mon.chars", "3" }, { "tape.text.date_mon.font", "font.tape_recorder" }, { "tape.text.date_mon.draw_masked", "false" }, { "tape.text.date_mm.x", "-1" }, { "tape.text.date_mm.y", "-1" }, { "tape.text.date_mm.align", "left" }, { "tape.text.date_mm.valign", "top" }, { "tape.text.date_mm.digits", "2" }, { "tape.text.date_mm.font", "font.tape_recorder" }, { "tape.text.date_mm.draw_masked", "false" }, { "tape.text.date_dd.x", "-1" }, { "tape.text.date_dd.y", "-1" }, { "tape.text.date_dd.align", "left" }, { "tape.text.date_dd.valign", "top" }, { "tape.text.date_dd.digits", "2" }, { "tape.text.date_dd.font", "font.tape_recorder" }, { "tape.text.date_dd.draw_masked", "false" }, { "tape.text.time.x", "44" }, { "tape.text.time.y", "55" }, { "tape.text.time.align", "left" }, { "tape.text.time.valign", "top" }, { "tape.text.time.digits", "-1" }, { "tape.text.time.xoffset", "27" }, { "tape.text.time.font", "font.tape_recorder" }, { "tape.text.time.draw_masked", "false" }, { "tape.text.time_hh.x", "-1" }, { "tape.text.time_hh.y", "-1" }, { "tape.text.time_hh.align", "left" }, { "tape.text.time_hh.valign", "top" }, { "tape.text.time_hh.digits", "2" }, { "tape.text.time_hh.font", "font.tape_recorder" }, { "tape.text.time_hh.draw_masked", "false" }, { "tape.text.time_mm.x", "-1" }, { "tape.text.time_mm.y", "-1" }, { "tape.text.time_mm.align", "left" }, { "tape.text.time_mm.valign", "top" }, { "tape.text.time_mm.digits", "2" }, { "tape.text.time_mm.font", "font.tape_recorder" }, { "tape.text.time_mm.draw_masked", "false" }, { "tape.text.time_ss.x", "-1" }, { "tape.text.time_ss.y", "-1" }, { "tape.text.time_ss.align", "left" }, { "tape.text.time_ss.valign", "top" }, { "tape.text.time_ss.digits", "2" }, { "tape.text.time_ss.font", "font.tape_recorder" }, { "tape.text.time_ss.draw_masked", "false" }, { "tape.text.frame.x", "-1" }, { "tape.text.frame.y", "-1" }, { "tape.text.frame.align", "left" }, { "tape.text.frame.valign", "top" }, { "tape.text.frame.digits", "-1" }, { "tape.text.frame.font", "font.tape_recorder" }, { "tape.text.frame.draw_masked", "false" }, { "tape.show_game_buttons", "false" }, { "editor.button.prev_level.x", "5" }, { "editor.button.prev_level.y", "5" }, { "editor.button.next_level.x", "79" }, { "editor.button.next_level.y", "5" }, { "editor.button.properties.x", "5" }, { "editor.button.properties.y", "230" }, { "editor.button.element_left.x", "-1" }, { "editor.button.element_left.y", "-1" }, { "editor.button.element_left.tile_size", "-1" }, { "editor.button.element_middle.x", "-1" }, { "editor.button.element_middle.y", "-1" }, { "editor.button.element_middle.tile_size", "-1" }, { "editor.button.element_right.x", "-1" }, { "editor.button.element_right.y", "-1" }, { "editor.button.element_right.tile_size", "-1" }, { "editor.button.palette.x", "-1" }, { "editor.button.palette.y", "-1" }, { "editor.button.draw_single.x", "6" }, { "editor.button.draw_single.y", "6" }, { "editor.button.draw_connected.x", "28" }, { "editor.button.draw_connected.y", "6" }, { "editor.button.draw_line.x", "50" }, { "editor.button.draw_line.y", "6" }, { "editor.button.draw_arc.x", "72" }, { "editor.button.draw_arc.y", "6" }, { "editor.button.draw_rectangle.x", "6" }, { "editor.button.draw_rectangle.y", "28" }, { "editor.button.draw_filled_box.x", "28" }, { "editor.button.draw_filled_box.y", "28" }, { "editor.button.rotate_up.x", "50" }, { "editor.button.rotate_up.y", "28" }, { "editor.button.draw_text.x", "72" }, { "editor.button.draw_text.y", "28" }, { "editor.button.flood_fill.x", "6" }, { "editor.button.flood_fill.y", "50" }, { "editor.button.rotate_left.x", "28" }, { "editor.button.rotate_left.y", "50" }, { "editor.button.zoom_level.x", "50" }, { "editor.button.zoom_level.y", "50" }, { "editor.button.rotate_right.x", "72" }, { "editor.button.rotate_right.y", "50" }, { "editor.button.draw_random.x", "6" }, { "editor.button.draw_random.y", "72" }, { "editor.button.grab_brush.x", "28" }, { "editor.button.grab_brush.y", "72" }, { "editor.button.rotate_down.x", "50" }, { "editor.button.rotate_down.y", "72" }, { "editor.button.pick_element.x", "72" }, { "editor.button.pick_element.y", "72" }, { "editor.button.ce_copy_from.x", "28" }, { "editor.button.ce_copy_from.y", "6" }, { "editor.button.ce_copy_to.x", "50" }, { "editor.button.ce_copy_to.y", "6" }, { "editor.button.ce_swap.x", "72" }, { "editor.button.ce_swap.y", "6" }, { "editor.button.ce_copy.x", "6" }, { "editor.button.ce_copy.y", "72" }, { "editor.button.ce_paste.x", "28" }, { "editor.button.ce_paste.y", "72" }, { "editor.button.undo.x", "5" }, { "editor.button.undo.y", "99" }, { "editor.button.conf.x", "35" }, { "editor.button.conf.y", "99" }, { "editor.button.save.x", "65" }, { "editor.button.save.y", "99" }, { "editor.button.clear.x", "5" }, { "editor.button.clear.y", "119" }, { "editor.button.test.x", "35" }, { "editor.button.test.y", "119" }, { "editor.button.exit.x", "65" }, { "editor.button.exit.y", "119" }, { "editor.input.level_number.x", "29" }, { "editor.input.level_number.y", "5" }, { "editor.palette.x", "5" }, { "editor.palette.y", "30" }, { "editor.palette.cols", "4" }, { "editor.palette.rows", "10" }, { "editor.palette.tile_size", "16" }, { "editor.palette.show_as_separate_screen", "false" }, { "editor.palette.show_on_element_buttons", "false" }, { "editor.palette.element_left.x", "6" }, { "editor.palette.element_left.y", "258" }, { "editor.palette.element_left.tile_size", "16" }, { "editor.palette.element_middle.x", "42" }, { "editor.palette.element_middle.y", "258" }, { "editor.palette.element_middle.tile_size", "16" }, { "editor.palette.element_right.x", "78" }, { "editor.palette.element_right.y", "258" }, { "editor.palette.element_right.tile_size", "16" }, { "editor.drawingarea.tile_size", "16" }, { "editor.settings.headline.x", "272" }, { "editor.settings.headline.y", "16" }, { "editor.settings.headline.align", "center" }, { "editor.settings.element_graphic.x", "24" }, { "editor.settings.element_graphic.y", "64" }, { "editor.settings.element_name.x", "-1" }, { "editor.settings.element_name.y", "-1" }, { "editor.settings.tabs.x", "24" }, { "editor.settings.tabs.y", "64" }, { "editor.settings.tabs.2nd_yoffset", "64" }, { "editor.settings.tabs.draw_xoffset", "0" }, { "editor.settings.tabs.draw_yoffset", "8" }, { "editor.settings.tooltip.x", "-1" }, { "editor.settings.tooltip.y", "-1" }, { "editor.gadget.normal_spacing", "4" }, { "editor.gadget.small_spacing", "2" }, { "editor.gadget.tiny_spacing", "1" }, { "editor.gadget.line_spacing", "4" }, { "editor.gadget.text_spacing", "4" }, { "editor.gadget.separator_line.height", "2" }, { "request.button.yes.x", "2" }, { "request.button.yes.y", "250" }, { "request.button.no.x", "52" }, { "request.button.no.y", "250" }, { "request.button.confirm.x", "2" }, { "request.button.confirm.y", "250" }, { "request.button.player_1.x", "20" }, { "request.button.player_1.y", "200" }, { "request.button.player_1.draw_player", "true" }, { "request.button.player_1.tile_size", "16" }, { "request.button.player_2.x", "50" }, { "request.button.player_2.y", "200" }, { "request.button.player_2.draw_player", "true" }, { "request.button.player_2.tile_size", "16" }, { "request.button.player_3.x", "20" }, { "request.button.player_3.y", "230" }, { "request.button.player_3.draw_player", "true" }, { "request.button.player_3.tile_size", "16" }, { "request.button.player_4.x", "50" }, { "request.button.player_4.y", "230" }, { "request.button.player_4.draw_player", "true" }, { "request.button.player_4.tile_size", "16" }, { "request.x", "-1" }, { "request.y", "-1" }, { "request.width", "120" }, { "request.height", "300" }, { "request.border_size", "10" }, { "request.line_spacing", "2" }, { "request.step_offset", "10" }, { "request.step_delay", "20" }, { "request.anim_mode", "default" }, { "request.align", "center" }, { "request.valign", "middle" }, { "request.autowrap", "false" }, { "request.centered", "true" }, { "request.wrap_single_words", "true" }, { "global.use_envelope_request", "false" }, { "game.graphics_engine_version", "-1" }, { "game.forced_scroll_delay_value", "-1" }, { "game.use_native_emc_graphics_engine", "false" }, { "game.use_native_sp_graphics_engine", "true" }, { "game.use_masked_pushing", "false" }, { "game.tile_size", "32" }, { "[player].boring_delay_fixed", "1000" }, { "[player].boring_delay_random", "1000" }, { "[player].sleeping_delay_fixed", "2000" }, { "[player].sleeping_delay_random", "2000" }, { "viewport.window.width", "672" }, { "viewport.window.height", "560" }, { "viewport.window.TITLE.width", ARG_DEFAULT }, { "viewport.window.TITLE.height", ARG_DEFAULT }, { "viewport.playfield.x", "6" }, { "viewport.playfield.y", "6" }, { "viewport.playfield.width", "548" }, { "viewport.playfield.height", "548" }, { "viewport.playfield.border_size", "2" }, { "viewport.playfield.MAIN.x", ARG_DEFAULT }, { "viewport.playfield.MAIN.y", ARG_DEFAULT }, { "viewport.playfield.MAIN.width", ARG_DEFAULT }, { "viewport.playfield.MAIN.height", ARG_DEFAULT }, { "viewport.playfield.MAIN.border_size", ARG_DEFAULT }, { "viewport.playfield.SCORES.x", ARG_DEFAULT }, { "viewport.playfield.SCORES.y", ARG_DEFAULT }, { "viewport.playfield.SCORES.width", ARG_DEFAULT }, { "viewport.playfield.SCORES.height", ARG_DEFAULT }, { "viewport.playfield.SCORES.border_size", ARG_DEFAULT }, { "viewport.playfield.EDITOR.x", ARG_DEFAULT }, { "viewport.playfield.EDITOR.y", ARG_DEFAULT }, { "viewport.playfield.EDITOR.width", ARG_DEFAULT }, { "viewport.playfield.EDITOR.height", ARG_DEFAULT }, { "viewport.playfield.EDITOR.border_size", ARG_DEFAULT }, { "viewport.playfield.PLAYING.x", ARG_DEFAULT }, { "viewport.playfield.PLAYING.y", ARG_DEFAULT }, { "viewport.playfield.PLAYING.width", ARG_DEFAULT }, { "viewport.playfield.PLAYING.height", ARG_DEFAULT }, { "viewport.playfield.PLAYING.border_size", ARG_DEFAULT }, { "viewport.door_1.x", "566" }, { "viewport.door_1.y", "60" }, { "viewport.door_1.width", "100" }, { "viewport.door_1.height", "280" }, { "viewport.door_1.border_size", "4" }, { "viewport.door_1.MAIN.x", ARG_DEFAULT }, { "viewport.door_1.MAIN.y", ARG_DEFAULT }, { "viewport.door_1.MAIN.width", ARG_DEFAULT }, { "viewport.door_1.MAIN.height", ARG_DEFAULT }, { "viewport.door_1.MAIN.border_size", ARG_DEFAULT }, { "viewport.door_1.SCORES.x", ARG_DEFAULT }, { "viewport.door_1.SCORES.y", ARG_DEFAULT }, { "viewport.door_1.SCORES.width", ARG_DEFAULT }, { "viewport.door_1.SCORES.height", ARG_DEFAULT }, { "viewport.door_1.SCORES.border_size", ARG_DEFAULT }, { "viewport.door_1.EDITOR.x", ARG_DEFAULT }, { "viewport.door_1.EDITOR.y", ARG_DEFAULT }, { "viewport.door_1.EDITOR.width", ARG_DEFAULT }, { "viewport.door_1.EDITOR.height", ARG_DEFAULT }, { "viewport.door_1.EDITOR.border_size", ARG_DEFAULT }, { "viewport.door_1.PLAYING.x", ARG_DEFAULT }, { "viewport.door_1.PLAYING.y", ARG_DEFAULT }, { "viewport.door_1.PLAYING.width", ARG_DEFAULT }, { "viewport.door_1.PLAYING.height", ARG_DEFAULT }, { "viewport.door_1.PLAYING.border_size", ARG_DEFAULT }, { "viewport.door_2.x", "566" }, { "viewport.door_2.y", "400" }, { "viewport.door_2.width", "100" }, { "viewport.door_2.height", "100" }, { "viewport.door_2.border_size", "4" }, { "viewport.door_2.MAIN.x", ARG_DEFAULT }, { "viewport.door_2.MAIN.y", ARG_DEFAULT }, { "viewport.door_2.MAIN.width", ARG_DEFAULT }, { "viewport.door_2.MAIN.height", ARG_DEFAULT }, { "viewport.door_2.MAIN.border_size", ARG_DEFAULT }, { "viewport.door_2.SCORES.x", ARG_DEFAULT }, { "viewport.door_2.SCORES.y", ARG_DEFAULT }, { "viewport.door_2.SCORES.width", ARG_DEFAULT }, { "viewport.door_2.SCORES.height", ARG_DEFAULT }, { "viewport.door_2.SCORES.border_size", ARG_DEFAULT }, { "viewport.door_2.EDITOR.x", "566" }, { "viewport.door_2.EDITOR.y", "356" }, { "viewport.door_2.EDITOR.width", "100" }, { "viewport.door_2.EDITOR.height", "144" }, { "viewport.door_2.EDITOR.border_size", "4" }, { "viewport.door_2.PLAYING.x", ARG_DEFAULT }, { "viewport.door_2.PLAYING.y", ARG_DEFAULT }, { "viewport.door_2.PLAYING.width", ARG_DEFAULT }, { "viewport.door_2.PLAYING.height", ARG_DEFAULT }, { "viewport.door_2.PLAYING.border_size", ARG_DEFAULT }, { NULL, NULL } }; mirrormagic-3.0.0/src/files.c0000644000175000017500000112230013263212010015355 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // files.c // ============================================================================ #include #include #include #include #include "libgame/libgame.h" #include "files.h" #include "init.h" #include "tools.h" #include "tape.h" #include "config.h" #define ENABLE_UNUSED_CODE 0 /* currently unused functions */ #define ENABLE_HISTORIC_CHUNKS 0 /* only for historic reference */ #define ENABLE_RESERVED_CODE 0 /* reserved for later use */ #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */ #define CHUNK_SIZE_NONE -1 /* do not write chunk size */ #define LEVEL_CHUNK_NAME_SIZE MAX_LEVEL_NAME_LEN #define LEVEL_CHUNK_AUTH_SIZE MAX_LEVEL_AUTHOR_LEN #define LEVEL_CHUNK_VERS_SIZE 8 /* size of file version chunk */ #define LEVEL_CHUNK_DATE_SIZE 4 /* size of file date chunk */ #define LEVEL_CHUNK_HEAD_SIZE 80 /* size of level file header */ #define LEVEL_CHUNK_HEAD_UNUSED 0 /* unused level header bytes */ #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */ #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */ #define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */ #define LEVEL_CHUNK_CNT3_UNUSED 10 /* unused CNT3 chunk bytes */ #define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */ #define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */ #define LEVEL_CHUNK_GRP1_SIZE 74 /* size of level GRP1 chunk */ /* (element number, number of change pages, change page number) */ #define LEVEL_CHUNK_CUSX_UNCHANGED (2 + (1 + 1) + (1 + 1)) /* (element number only) */ #define LEVEL_CHUNK_GRPX_UNCHANGED 2 #define LEVEL_CHUNK_NOTE_UNCHANGED 2 /* (nothing at all if unchanged) */ #define LEVEL_CHUNK_ELEM_UNCHANGED 0 #define TAPE_CHUNK_VERS_SIZE 8 /* size of file version chunk */ #define TAPE_CHUNK_HEAD_SIZE 20 /* size of tape file header */ #define TAPE_CHUNK_HEAD_UNUSED 2 /* unused tape header bytes */ #define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x)) #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE) #define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48) /* file identifier strings */ #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x" #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x" #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" /* values for deciding when (not) to save configuration data */ #define SAVE_CONF_NEVER 0 #define SAVE_CONF_ALWAYS 1 #define SAVE_CONF_WHEN_CHANGED -1 /* values for chunks using micro chunks */ #define CONF_MASK_1_BYTE 0x00 #define CONF_MASK_2_BYTE 0x40 #define CONF_MASK_4_BYTE 0x80 #define CONF_MASK_MULTI_BYTES 0xc0 #define CONF_MASK_BYTES 0xc0 #define CONF_MASK_TOKEN 0x3f #define CONF_VALUE_1_BYTE(x) (CONF_MASK_1_BYTE | (x)) #define CONF_VALUE_2_BYTE(x) (CONF_MASK_2_BYTE | (x)) #define CONF_VALUE_4_BYTE(x) (CONF_MASK_4_BYTE | (x)) #define CONF_VALUE_MULTI_BYTES(x) (CONF_MASK_MULTI_BYTES | (x)) /* these definitions are just for convenience of use and readability */ #define CONF_VALUE_8_BIT(x) CONF_VALUE_1_BYTE(x) #define CONF_VALUE_16_BIT(x) CONF_VALUE_2_BYTE(x) #define CONF_VALUE_32_BIT(x) CONF_VALUE_4_BYTE(x) #define CONF_VALUE_BYTES(x) CONF_VALUE_MULTI_BYTES(x) #define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \ (x) == CONF_MASK_2_BYTE ? 2 : \ (x) == CONF_MASK_4_BYTE ? 4 : 0) #define CONF_CONTENT_NUM_ELEMENTS (3 * 3) #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2) #define CONF_ELEMENT_NUM_BYTES (2) #define CONF_ENTITY_NUM_BYTES(t) ((t) == TYPE_ELEMENT || \ (t) == TYPE_ELEMENT_LIST ? \ CONF_ELEMENT_NUM_BYTES : \ (t) == TYPE_CONTENT || \ (t) == TYPE_CONTENT_LIST ? \ CONF_CONTENT_NUM_BYTES : 1) #define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES) #define CONF_ELEMENTS_ELEMENT(b,i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \ (b[CONF_ELEMENT_BYTE_POS(i) + 1])) #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS + \ (y) * 3 + (x)) #define CONF_CONTENT_BYTE_POS(c,x,y) (CONF_CONTENT_ELEMENT_POS(c,x,y) * \ CONF_ELEMENT_NUM_BYTES) #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\ (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1])) /* temporary variables used to store pointers to structure members */ static struct LevelInfo li; static struct ElementInfo xx_ei, yy_ei; static struct ElementChangeInfo xx_change; static struct ElementGroupInfo xx_group; static struct EnvelopeInfo xx_envelope; static unsigned int xx_event_bits[NUM_CE_BITFIELDS]; static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1]; static int xx_num_contents; static int xx_current_change_page; static char xx_default_string_empty[1] = ""; static int xx_string_length_unused; struct LevelFileConfigInfo { int element; /* element for which data is to be stored */ int save_type; /* save data always, never or when changed */ int data_type; /* data type (used internally, not stored) */ int conf_type; /* micro chunk identifier (stored in file) */ /* (mandatory) */ void *value; /* variable that holds the data to be stored */ int default_value; /* initial default value for this variable */ /* (optional) */ void *value_copy; /* variable that holds the data to be copied */ void *num_entities; /* number of entities for multi-byte data */ int default_num_entities; /* default number of entities for this data */ int max_num_entities; /* maximal number of entities for this data */ char *default_string; /* optional default string for string data */ }; static struct LevelFileConfigInfo chunk_config_INFO[] = { /* ---------- values not related to single elements ----------------------- */ { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.game_engine_type, GAME_ENGINE_TYPE_RND }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.fieldx, STD_LEV_FIELDX }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.fieldy, STD_LEV_FIELDY }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(3), &li.time, 100 }, { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_16_BIT(4), &li.gems_needed, 0 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_32_BIT(2), &li.random_seed, 0 }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.use_step_counter, FALSE }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(4), &li.wind_direction_initial, MV_NONE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(5), &li.em_slippery_gems, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(6), &li.use_custom_template, FALSE }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(1), &li.can_move_into_acid_bits, ~0 /* default: everything can */ }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(7), &li.dont_collide_with_bits, ~0 /* default: always deadly */ }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.em_explodes_by_fire, FALSE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(5), &li.score[SC_TIME_BONUS], 1 }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.auto_exit_sokoban, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.auto_count_gems, FALSE }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_ELEM[] = { /* (these values are the same for each player) */ { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.block_last_field, FALSE /* default case for EM levels */ }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.sp_block_last_field, TRUE /* default case for SP levels */ }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &li.instant_relocation, FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(4), &li.can_pass_to_walkable, FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(5), &li.block_snap_field, TRUE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(6), &li.continuous_snapping, TRUE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(12), &li.shifted_relocation, FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(15), &li.lazy_relocation, FALSE }, /* (these values are different for each player) */ { EL_PLAYER_1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[0], STEPSIZE_NORMAL }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[0], FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[0], FALSE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[0], 1 }, { EL_PLAYER_1, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[0][0],EL_EMPTY, NULL, &li.initial_inventory_size[0], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_PLAYER_2, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[1], STEPSIZE_NORMAL }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[1], FALSE }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[1], FALSE }, { EL_PLAYER_2, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[1], EL_PLAYER_2 }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[1], FALSE }, { EL_PLAYER_2, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[1], EL_PLAYER_2 }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[1], FALSE }, { EL_PLAYER_2, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[1], EL_PLAYER_2 }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[1], FALSE }, { EL_PLAYER_2, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[1], 1 }, { EL_PLAYER_2, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[1][0],EL_EMPTY, NULL, &li.initial_inventory_size[1], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_PLAYER_3, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[2], STEPSIZE_NORMAL }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[2], FALSE }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[2], FALSE }, { EL_PLAYER_3, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[2], EL_PLAYER_3 }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[2], FALSE }, { EL_PLAYER_3, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[2], EL_PLAYER_3 }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[2], FALSE }, { EL_PLAYER_3, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[2], EL_PLAYER_3 }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[2], FALSE }, { EL_PLAYER_3, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[2], 1 }, { EL_PLAYER_3, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[2][0],EL_EMPTY, NULL, &li.initial_inventory_size[2], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_PLAYER_4, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &li.initial_player_stepsize[3], STEPSIZE_NORMAL }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &li.initial_player_gravity[3], FALSE }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.use_start_element[3], FALSE }, { EL_PLAYER_4, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[3], EL_PLAYER_4 }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_artwork_element[3], FALSE }, { EL_PLAYER_4, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[3], EL_PLAYER_4 }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_explosion_element[3], FALSE }, { EL_PLAYER_4, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[3], EL_PLAYER_4 }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.use_initial_inventory[3], FALSE }, { EL_PLAYER_4, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(14), &li.initial_inventory_size[3], 1 }, { EL_PLAYER_4, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.initial_inventory_content[3][0],EL_EMPTY, NULL, &li.initial_inventory_size[3], 1, MAX_INITIAL_INVENTORY_SIZE }, { EL_EMERALD, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_EMERALD], 10 }, { EL_DIAMOND, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_DIAMOND], 10 }, { EL_BUG, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_BUG], 10 }, { EL_SPACESHIP, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_SPACESHIP], 10 }, { EL_PACMAN, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_PACMAN], 10 }, { EL_NUT, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_NUT], 10 }, { EL_DYNAMITE, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_DYNAMITE], 10 }, { EL_KEY_1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_KEY], 10 }, { EL_PEARL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_PEARL], 10 }, { EL_CRYSTAL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_CRYSTAL], 10 }, { EL_BD_AMOEBA, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.amoeba_content, EL_DIAMOND }, { EL_BD_AMOEBA, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.amoeba_speed, 10 }, { EL_BD_AMOEBA, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.grow_into_diggable, TRUE }, { EL_YAMYAM, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1), &li.yamyam_content, EL_ROCK, NULL, &li.num_yamyam_contents, 4, MAX_ELEMENT_CONTENTS }, { EL_YAMYAM, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_YAMYAM], 10 }, { EL_ROBOT, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_ROBOT], 10 }, { EL_ROBOT, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.slurp_score, 10 }, { EL_ROBOT_WHEEL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_wheel, 10 }, { EL_MAGIC_WALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_magic_wall, 10 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.game_of_life[0], 2 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &li.game_of_life[1], 3 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(3), &li.game_of_life[2], 3 }, { EL_GAME_OF_LIFE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(4), &li.game_of_life[3], 3 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.biomaze[0], 2 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &li.biomaze[1], 3 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(3), &li.biomaze[2], 3 }, { EL_BIOMAZE, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(4), &li.biomaze[3], 3 }, { EL_TIMEGATE_SWITCH, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_timegate, 10 }, { EL_LIGHT_SWITCH_ACTIVE, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_light, 10 }, { EL_SHIELD_NORMAL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.shield_normal_time, 10 }, { EL_SHIELD_NORMAL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.score[SC_SHIELD], 10 }, { EL_SHIELD_DEADLY, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.shield_deadly_time, 10 }, { EL_SHIELD_DEADLY, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.score[SC_SHIELD], 10 }, { EL_EXTRA_TIME, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.extra_time, 10 }, { EL_EXTRA_TIME, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.extra_time_score, 10 }, { EL_TIME_ORB_FULL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.time_orb_time, 10 }, { EL_TIME_ORB_FULL, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.use_time_orb_bug, FALSE }, { EL_SPRING, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.use_spring_bug, FALSE }, { EL_EMC_ANDROID, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.android_move_time, 10 }, { EL_EMC_ANDROID, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.android_clone_time, 10 }, { EL_EMC_ANDROID, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), &li.android_clone_element[0], EL_EMPTY, NULL, &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS }, { EL_EMC_LENSES, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.lenses_score, 10 }, { EL_EMC_LENSES, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.lenses_time, 10 }, { EL_EMC_MAGNIFIER, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.magnify_score, 10 }, { EL_EMC_MAGNIFIER, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &li.magnify_time, 10 }, { EL_EMC_MAGIC_BALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.ball_time, 10 }, { EL_EMC_MAGIC_BALL, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.ball_random, FALSE }, { EL_EMC_MAGIC_BALL, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.ball_state_initial, FALSE }, { EL_EMC_MAGIC_BALL, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1), &li.ball_content, EL_EMPTY, NULL, &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS }, { EL_MM_MCDUFFIN, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.mm_laser_red, FALSE }, { EL_MM_MCDUFFIN, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.mm_laser_green, FALSE }, { EL_MM_MCDUFFIN, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &li.mm_laser_blue, TRUE }, { EL_DF_LASER, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &li.df_laser_red, TRUE }, { EL_DF_LASER, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &li.df_laser_green, TRUE }, { EL_DF_LASER, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &li.df_laser_blue, FALSE }, { EL_MM_FUSE_ACTIVE, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.mm_time_fuse, 25 }, { EL_MM_BOMB, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.mm_time_bomb, 75 }, { EL_MM_GRAY_BALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.mm_time_ball, 75 }, { EL_MM_STEEL_BLOCK, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.mm_time_block, 75 }, { EL_MM_LIGHTBALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_ELEM_BONUS], 10 }, /* ---------- unused values ----------------------------------------------- */ { EL_UNKNOWN, SAVE_CONF_NEVER, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.score[SC_UNKNOWN_15], 10 }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_NOTE[] = { { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &xx_envelope.xsize, MAX_ENVELOPE_XSIZE, }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &xx_envelope.ysize, MAX_ENVELOPE_YSIZE, }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &xx_envelope.autowrap, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(4), &xx_envelope.centered, FALSE }, { -1, -1, TYPE_STRING, CONF_VALUE_BYTES(1), &xx_envelope.text, -1, NULL, &xx_string_length_unused, -1, MAX_ENVELOPE_TEXT_LEN, &xx_default_string_empty[0] }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_CUSX_base[] = { { -1, -1, TYPE_STRING, CONF_VALUE_BYTES(1), &xx_ei.description[0], -1, &yy_ei.description[0], &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN, &xx_default_description[0] }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(1), &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT, &yy_ei.properties[EP_BITFIELD_BASE_NR] }, #if ENABLE_RESERVED_CODE /* (reserved for later use) */ { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(2), &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT, &yy_ei.properties[EP_BITFIELD_BASE_NR + 1] }, #endif { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &xx_ei.use_gfx_element, FALSE, &yy_ei.use_gfx_element }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &xx_ei.gfx_element_initial, EL_EMPTY_SPACE, &yy_ei.gfx_element_initial }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(2), &xx_ei.access_direction, MV_ALL_DIRECTIONS, &yy_ei.access_direction }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &xx_ei.collect_score_initial, 10, &yy_ei.collect_score_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(3), &xx_ei.collect_count_initial, 1, &yy_ei.collect_count_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(4), &xx_ei.ce_value_fixed_initial, 0, &yy_ei.ce_value_fixed_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(5), &xx_ei.ce_value_random_initial, 0, &yy_ei.ce_value_random_initial }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(3), &xx_ei.use_last_ce_value, FALSE, &yy_ei.use_last_ce_value }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(6), &xx_ei.push_delay_fixed, 8, &yy_ei.push_delay_fixed }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(7), &xx_ei.push_delay_random, 8, &yy_ei.push_delay_random }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(8), &xx_ei.drop_delay_fixed, 0, &yy_ei.drop_delay_fixed }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(9), &xx_ei.drop_delay_random, 0, &yy_ei.drop_delay_random }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(10), &xx_ei.move_delay_fixed, 0, &yy_ei.move_delay_fixed }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(11), &xx_ei.move_delay_random, 0, &yy_ei.move_delay_random }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(3), &xx_ei.move_pattern, MV_ALL_DIRECTIONS, &yy_ei.move_pattern }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(4), &xx_ei.move_direction_initial, MV_START_AUTOMATIC, &yy_ei.move_direction_initial }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(5), &xx_ei.move_stepsize, TILEX / 8, &yy_ei.move_stepsize }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(12), &xx_ei.move_enter_element, EL_EMPTY_SPACE, &yy_ei.move_enter_element }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(13), &xx_ei.move_leave_element, EL_EMPTY_SPACE, &yy_ei.move_leave_element }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(6), &xx_ei.move_leave_type, LEAVE_TYPE_UNLIMITED, &yy_ei.move_leave_type }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(7), &xx_ei.slippery_type, SLIPPERY_ANY_RANDOM, &yy_ei.slippery_type }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(8), &xx_ei.explosion_type, EXPLODES_3X3, &yy_ei.explosion_type }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(14), &xx_ei.explosion_delay, 16, &yy_ei.explosion_delay }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(15), &xx_ei.ignition_delay, 8, &yy_ei.ignition_delay }, { -1, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2), &xx_ei.content, EL_EMPTY_SPACE, &yy_ei.content, &xx_num_contents, 1, 1 }, /* ---------- "num_change_pages" must be the last entry ------------------- */ { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_8_BIT(9), &xx_ei.num_change_pages, 1, &yy_ei.num_change_pages }, { -1, -1, -1, -1, NULL, -1, NULL } }; static struct LevelFileConfigInfo chunk_config_CUSX_change[] = { /* ---------- "current_change_page" must be the first entry --------------- */ { -1, SAVE_CONF_ALWAYS, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &xx_current_change_page, -1 }, /* ---------- (the remaining entries can be in any order) ----------------- */ { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), &xx_change.can_change, FALSE }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(1), &xx_event_bits[0], 0 }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(2), &xx_event_bits[1], 0 }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(3), &xx_change.trigger_player, CH_PLAYER_ANY }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_8_BIT(4), &xx_change.trigger_side, CH_SIDE_ANY }, { -1, -1, TYPE_BITFIELD, CONF_VALUE_32_BIT(3), &xx_change.trigger_page, CH_PAGE_ANY }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &xx_change.target_element, EL_EMPTY_SPACE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(2), &xx_change.delay_fixed, 0 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(3), &xx_change.delay_random, 0 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(4), &xx_change.delay_frames, FRAMES_PER_SECOND }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(5), &xx_change.initial_trigger_element, EL_EMPTY_SPACE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(6), &xx_change.explode, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(7), &xx_change.use_target_content, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(8), &xx_change.only_if_complete, FALSE }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &xx_change.use_random_replace, FALSE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(10), &xx_change.random_percentage, 100 }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(11), &xx_change.replace_when, CP_WHEN_EMPTY }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(12), &xx_change.has_action, FALSE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(13), &xx_change.action_type, CA_NO_ACTION }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(14), &xx_change.action_mode, CA_MODE_UNDEFINED }, { -1, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(6), &xx_change.action_arg, CA_ARG_UNDEFINED }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(7), &xx_change.action_element, EL_EMPTY_SPACE }, { -1, -1, TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1), &xx_change.target_content, EL_EMPTY_SPACE, NULL, &xx_num_contents, 1, 1 }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_GRPX[] = { { -1, -1, TYPE_STRING, CONF_VALUE_BYTES(1), &xx_ei.description[0], -1, NULL, &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN, &xx_default_description[0] }, { -1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), &xx_ei.use_gfx_element, FALSE }, { -1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &xx_ei.gfx_element_initial, EL_EMPTY_SPACE }, { -1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(2), &xx_group.choice_mode, ANIM_RANDOM }, { -1, -1, TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2), &xx_group.element[0], EL_EMPTY_SPACE, NULL, &xx_group.num_elements, 1, MAX_ELEMENTS_IN_GROUP }, { -1, -1, -1, -1, NULL, -1 } }; static struct LevelFileConfigInfo chunk_config_CONF[] = /* (OBSOLETE) */ { { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(9), &li.block_snap_field, TRUE }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(13), &li.continuous_snapping, TRUE }, { EL_PLAYER_1, -1, TYPE_INTEGER, CONF_VALUE_8_BIT(1), &li.initial_player_stepsize[0], STEPSIZE_NORMAL }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(10), &li.use_start_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(1), &li.start_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(11), &li.use_artwork_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(2), &li.artwork_element[0], EL_PLAYER_1 }, { EL_PLAYER_1, -1, TYPE_BOOLEAN, CONF_VALUE_8_BIT(12), &li.use_explosion_element[0], FALSE }, { EL_PLAYER_1, -1, TYPE_ELEMENT, CONF_VALUE_16_BIT(3), &li.explosion_element[0], EL_PLAYER_1 }, { -1, -1, -1, -1, NULL, -1 } }; static struct { int filetype; char *id; } filetype_id_list[] = { { LEVEL_FILE_TYPE_RND, "RND" }, { LEVEL_FILE_TYPE_BD, "BD" }, { LEVEL_FILE_TYPE_EM, "EM" }, { LEVEL_FILE_TYPE_SP, "SP" }, { LEVEL_FILE_TYPE_DX, "DX" }, { LEVEL_FILE_TYPE_SB, "SB" }, { LEVEL_FILE_TYPE_DC, "DC" }, { LEVEL_FILE_TYPE_MM, "MM" }, { LEVEL_FILE_TYPE_MM, "DF" }, { -1, NULL }, }; /* ========================================================================= */ /* level file functions */ /* ========================================================================= */ static boolean check_special_flags(char *flag) { if (strEqual(options.special_flags, flag) || strEqual(leveldir_current->special_flags, flag)) return TRUE; return FALSE; } static struct DateInfo getCurrentDate() { time_t epoch_seconds = time(NULL); struct tm *now = localtime(&epoch_seconds); struct DateInfo date; date.year = now->tm_year + 1900; date.month = now->tm_mon + 1; date.day = now->tm_mday; date.src = DATE_SRC_CLOCK; return date; } static void resetEventFlags(struct ElementChangeInfo *change) { int i; for (i = 0; i < NUM_CHANGE_EVENTS; i++) change->has_event[i] = FALSE; } static void resetEventBits() { int i; for (i = 0; i < NUM_CE_BITFIELDS; i++) xx_event_bits[i] = 0; } static void setEventFlagsFromEventBits(struct ElementChangeInfo *change) { int i; /* important: only change event flag if corresponding event bit is set (this is because all xx_event_bits[] values are loaded separately, and all xx_event_bits[] values are set back to zero before loading another value xx_event_bits[x] (each value representing 32 flags)) */ for (i = 0; i < NUM_CHANGE_EVENTS; i++) if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i)) change->has_event[i] = TRUE; } static void setEventBitsFromEventFlags(struct ElementChangeInfo *change) { int i; /* in contrast to the above function setEventFlagsFromEventBits(), it would also be possible to set all bits in xx_event_bits[] to 0 or 1 depending on the corresponding change->has_event[i] values here, as all xx_event_bits[] values are reset in resetEventBits() before */ for (i = 0; i < NUM_CHANGE_EVENTS; i++) if (change->has_event[i]) xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i); } static char *getDefaultElementDescription(struct ElementInfo *ei) { static char description[MAX_ELEMENT_NAME_LEN + 1]; char *default_description = (ei->custom_description != NULL ? ei->custom_description : ei->editor_description); int i; /* always start with reliable default values */ for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++) description[i] = '\0'; /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */ strncpy(description, default_description, MAX_ELEMENT_NAME_LEN); return &description[0]; } static void setElementDescriptionToDefault(struct ElementInfo *ei) { char *default_description = getDefaultElementDescription(ei); int i; for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++) ei->description[i] = default_description[i]; } static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf) { int i; for (i = 0; conf[i].data_type != -1; i++) { int default_value = conf[i].default_value; int data_type = conf[i].data_type; int conf_type = conf[i].conf_type; int byte_mask = conf_type & CONF_MASK_BYTES; if (byte_mask == CONF_MASK_MULTI_BYTES) { int default_num_entities = conf[i].default_num_entities; int max_num_entities = conf[i].max_num_entities; *(int *)(conf[i].num_entities) = default_num_entities; if (data_type == TYPE_STRING) { char *default_string = conf[i].default_string; char *string = (char *)(conf[i].value); strncpy(string, default_string, max_num_entities); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(conf[i].value); int j; for (j = 0; j < max_num_entities; j++) element_array[j] = default_value; } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content = (struct Content *)(conf[i].value); int c, x, y; for (c = 0; c < max_num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content[c].e[x][y] = default_value; } } else /* constant size configuration data (1, 2 or 4 bytes) */ { if (data_type == TYPE_BOOLEAN) *(boolean *)(conf[i].value) = default_value; else *(int *) (conf[i].value) = default_value; } } } static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf) { int i; for (i = 0; conf[i].data_type != -1; i++) { int data_type = conf[i].data_type; int conf_type = conf[i].conf_type; int byte_mask = conf_type & CONF_MASK_BYTES; if (byte_mask == CONF_MASK_MULTI_BYTES) { int max_num_entities = conf[i].max_num_entities; if (data_type == TYPE_STRING) { char *string = (char *)(conf[i].value); char *string_copy = (char *)(conf[i].value_copy); strncpy(string_copy, string, max_num_entities); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(conf[i].value); int *element_array_copy = (int *)(conf[i].value_copy); int j; for (j = 0; j < max_num_entities; j++) element_array_copy[j] = element_array[j]; } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content = (struct Content *)(conf[i].value); struct Content *content_copy = (struct Content *)(conf[i].value_copy); int c, x, y; for (c = 0; c < max_num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_copy[c].e[x][y] = content[c].e[x][y]; } } else /* constant size configuration data (1, 2 or 4 bytes) */ { if (data_type == TYPE_BOOLEAN) *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value); else *(int *) (conf[i].value_copy) = *(int *) (conf[i].value); } } } void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to) { int i; xx_ei = *ei_from; /* copy element data into temporary buffer */ yy_ei = *ei_to; /* copy element data into temporary buffer */ copyConfigFromConfigList(chunk_config_CUSX_base); *ei_from = xx_ei; *ei_to = yy_ei; /* ---------- reinitialize and copy change pages ---------- */ ei_to->num_change_pages = ei_from->num_change_pages; ei_to->current_change_page = ei_from->current_change_page; setElementChangePages(ei_to, ei_to->num_change_pages); for (i = 0; i < ei_to->num_change_pages; i++) ei_to->change_page[i] = ei_from->change_page[i]; /* ---------- copy group element info ---------- */ if (ei_from->group != NULL && ei_to->group != NULL) /* group or internal */ *ei_to->group = *ei_from->group; /* mark this custom element as modified */ ei_to->modified_settings = TRUE; } void setElementChangePages(struct ElementInfo *ei, int change_pages) { int change_page_size = sizeof(struct ElementChangeInfo); ei->num_change_pages = MAX(1, change_pages); ei->change_page = checked_realloc(ei->change_page, ei->num_change_pages * change_page_size); if (ei->current_change_page >= ei->num_change_pages) ei->current_change_page = ei->num_change_pages - 1; ei->change = &ei->change_page[ei->current_change_page]; } void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) { xx_change = *change; /* copy change data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_CUSX_change); *change = xx_change; resetEventFlags(change); change->direct_action = 0; change->other_action = 0; change->pre_change_function = NULL; change->change_function = NULL; change->post_change_function = NULL; } static void setLevelInfoToDefaults_Level(struct LevelInfo *level) { int i, x, y; li = *level; /* copy level data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_INFO); *level = li; /* copy temporary buffer back to level data */ setLevelInfoToDefaults_EM(); setLevelInfoToDefaults_SP(); setLevelInfoToDefaults_MM(); level->native_em_level = &native_em_level; level->native_sp_level = &native_sp_level; level->native_mm_level = &native_mm_level; level->file_version = FILE_VERSION_ACTUAL; level->game_version = GAME_VERSION_ACTUAL; level->creation_date = getCurrentDate(); level->encoding_16bit_field = TRUE; level->encoding_16bit_yamyam = TRUE; level->encoding_16bit_amoeba = TRUE; /* clear level name and level author string buffers */ for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = '\0'; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) level->author[i] = '\0'; /* set level name and level author to default values */ strcpy(level->name, NAMELESS_LEVEL_NAME); strcpy(level->author, ANONYMOUS_NAME); /* set level playfield to playable default level with player and exit */ for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) level->field[x][y] = EL_SAND; level->field[0][0] = EL_PLAYER_1; level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED; BorderElement = EL_STEELWALL; /* detect custom elements when loading them */ level->file_has_custom_elements = FALSE; /* set all bug compatibility flags to "false" => do not emulate this bug */ level->use_action_after_change_bug = FALSE; if (leveldir_current) { /* try to determine better author name than 'anonymous' */ if (!strEqual(leveldir_current->author, ANONYMOUS_NAME)) { strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN); level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; } else { switch (LEVELCLASS(leveldir_current)) { case LEVELCLASS_TUTORIAL: strcpy(level->author, PROGRAM_AUTHOR_STRING); break; case LEVELCLASS_CONTRIB: strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN); level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; break; case LEVELCLASS_PRIVATE: strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN); level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; break; default: /* keep default value */ break; } } } } static void setLevelInfoToDefaults_Elements(struct LevelInfo *level) { static boolean clipboard_elements_initialized = FALSE; int i; InitElementPropertiesStatic(); li = *level; /* copy level data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_ELEM); *level = li; /* copy temporary buffer back to level data */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { int element = i; struct ElementInfo *ei = &element_info[element]; /* never initialize clipboard elements after the very first time */ /* (to be able to use clipboard elements between several levels) */ if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized) continue; if (IS_ENVELOPE(element)) { int envelope_nr = element - EL_ENVELOPE_1; setConfigToDefaultsFromConfigList(chunk_config_NOTE); level->envelope[envelope_nr] = xx_envelope; } if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { xx_ei = *ei; /* copy element data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_CUSX_base); *ei = xx_ei; } setElementChangePages(ei, 1); setElementChangeInfoToDefaults(ei->change); if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { setElementDescriptionToDefault(ei); ei->modified_settings = FALSE; } if (IS_CUSTOM_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { /* internal values used in level editor */ ei->access_type = 0; ei->access_layer = 0; ei->access_protected = 0; ei->walk_to_action = 0; ei->smash_targets = 0; ei->deadliness = 0; ei->can_explode_by_fire = FALSE; ei->can_explode_smashed = FALSE; ei->can_explode_impact = FALSE; ei->current_change_page = 0; } if (IS_GROUP_ELEMENT(element) || IS_INTERNAL_ELEMENT(element)) { struct ElementGroupInfo *group; /* initialize memory for list of elements in group */ if (ei->group == NULL) ei->group = checked_malloc(sizeof(struct ElementGroupInfo)); group = ei->group; xx_group = *group; /* copy group data into temporary buffer */ setConfigToDefaultsFromConfigList(chunk_config_GRPX); *group = xx_group; } } clipboard_elements_initialized = TRUE; } static void setLevelInfoToDefaults(struct LevelInfo *level, boolean level_info_only, boolean reset_file_status) { setLevelInfoToDefaults_Level(level); if (!level_info_only) setLevelInfoToDefaults_Elements(level); if (reset_file_status) { level->no_valid_file = FALSE; level->no_level_file = FALSE; } level->changed = FALSE; } static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info) { level_file_info->nr = 0; level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN; level_file_info->packed = FALSE; level_file_info->basename = NULL; level_file_info->filename = NULL; } int getMappedElement_SB(int, boolean); static void ActivateLevelTemplate() { int x, y; if (check_special_flags("load_xsb_to_ces")) { /* fill smaller playfields with padding "beyond border wall" elements */ if (level.fieldx < level_template.fieldx || level.fieldy < level_template.fieldy) { short field[level.fieldx][level.fieldy]; int new_fieldx = MAX(level.fieldx, level_template.fieldx); int new_fieldy = MAX(level.fieldy, level_template.fieldy); int pos_fieldx = (new_fieldx - level.fieldx) / 2; int pos_fieldy = (new_fieldy - level.fieldy) / 2; /* copy old playfield (which is smaller than the visible area) */ for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++) field[x][y] = level.field[x][y]; /* fill new, larger playfield with "beyond border wall" elements */ for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++) level.field[x][y] = getMappedElement_SB('_', TRUE); /* copy the old playfield to the middle of the new playfield */ for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++) level.field[pos_fieldx + x][pos_fieldy + y] = field[x][y]; level.fieldx = new_fieldx; level.fieldy = new_fieldy; } } /* Currently there is no special action needed to activate the template data, because 'element_info' property settings overwrite the original level data, while all other variables do not change. */ /* Exception: 'from_level_template' elements in the original level playfield are overwritten with the corresponding elements at the same position in playfield from the level template. */ for (x = 0; x < level.fieldx; x++) for (y = 0; y < level.fieldy; y++) if (level.field[x][y] == EL_FROM_LEVEL_TEMPLATE) level.field[x][y] = level_template.field[x][y]; if (check_special_flags("load_xsb_to_ces")) { struct LevelInfo level_backup = level; /* overwrite all individual level settings from template level settings */ level = level_template; /* restore playfield size */ level.fieldx = level_backup.fieldx; level.fieldy = level_backup.fieldy; /* restore playfield content */ for (x = 0; x < level.fieldx; x++) for (y = 0; y < level.fieldy; y++) level.field[x][y] = level_backup.field[x][y]; /* restore name and author from individual level */ strcpy(level.name, level_backup.name); strcpy(level.author, level_backup.author); /* restore flag "use_custom_template" */ level.use_custom_template = level_backup.use_custom_template; } } static char *getLevelFilenameFromBasename(char *basename) { static char *filename[2] = { NULL, NULL }; int pos = (strEqual(basename, LEVELTEMPLATE_FILENAME) ? 0 : 1); checked_free(filename[pos]); filename[pos] = getPath2(getCurrentLevelDir(), basename); return filename[pos]; } static int getFileTypeFromBasename(char *basename) { /* !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!! */ static char *filename = NULL; struct stat file_status; /* ---------- try to determine file type from filename ---------- */ /* check for typical filename of a Supaplex level package file */ if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d")) return LEVEL_FILE_TYPE_SP; /* check for typical filename of a Diamond Caves II level package file */ if (strSuffixLower(basename, ".dc") || strSuffixLower(basename, ".dc2")) return LEVEL_FILE_TYPE_DC; /* check for typical filename of a Sokoban level package file */ if (strSuffixLower(basename, ".xsb") && strchr(basename, '%') == NULL) return LEVEL_FILE_TYPE_SB; /* ---------- try to determine file type from filesize ---------- */ checked_free(filename); filename = getPath2(getCurrentLevelDir(), basename); if (stat(filename, &file_status) == 0) { /* check for typical filesize of a Supaplex level package file */ if (file_status.st_size == 170496) return LEVEL_FILE_TYPE_SP; } return LEVEL_FILE_TYPE_UNKNOWN; } static int getFileTypeFromMagicBytes(char *filename, int type) { File *file; if ((file = openFile(filename, MODE_READ))) { char chunk_name[CHUNK_ID_LEN + 1]; getFileChunkBE(file, chunk_name, NULL); if (strEqual(chunk_name, "MMII") || strEqual(chunk_name, "MIRR")) type = LEVEL_FILE_TYPE_MM; closeFile(file); } return type; } static boolean checkForPackageFromBasename(char *basename) { /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!! !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES !!! */ return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN); } static char *getSingleLevelBasenameExt(int nr, char *extension) { static char basename[MAX_FILENAME_LEN]; if (nr < 0) sprintf(basename, "%s", LEVELTEMPLATE_FILENAME); else sprintf(basename, "%03d.%s", nr, extension); return basename; } static char *getSingleLevelBasename(int nr) { return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION); } static char *getPackedLevelBasename(int type) { static char basename[MAX_FILENAME_LEN]; char *directory = getCurrentLevelDir(); Directory *dir; DirectoryEntry *dir_entry; strcpy(basename, UNDEFINED_FILENAME); /* default: undefined file */ if ((dir = openDirectory(directory)) == NULL) { Error(ERR_WARN, "cannot read current level directory '%s'", directory); return basename; } while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ { char *entry_basename = dir_entry->basename; int entry_type = getFileTypeFromBasename(entry_basename); if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) /* found valid level package */ { if (type == LEVEL_FILE_TYPE_UNKNOWN || type == entry_type) { strcpy(basename, entry_basename); break; } } } closeDirectory(dir); return basename; } static char *getSingleLevelFilename(int nr) { return getLevelFilenameFromBasename(getSingleLevelBasename(nr)); } #if ENABLE_UNUSED_CODE static char *getPackedLevelFilename(int type) { return getLevelFilenameFromBasename(getPackedLevelBasename(type)); } #endif char *getDefaultLevelFilename(int nr) { return getSingleLevelFilename(nr); } #if ENABLE_UNUSED_CODE static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi, int type) { lfi->type = type; lfi->packed = FALSE; lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type); lfi->filename = getLevelFilenameFromBasename(lfi->basename); } #endif static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi, int type, char *format, ...) { static char basename[MAX_FILENAME_LEN]; va_list ap; va_start(ap, format); vsprintf(basename, format, ap); va_end(ap); lfi->type = type; lfi->packed = FALSE; lfi->basename = basename; lfi->filename = getLevelFilenameFromBasename(lfi->basename); } static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi, int type) { lfi->type = type; lfi->packed = TRUE; lfi->basename = getPackedLevelBasename(lfi->type); lfi->filename = getLevelFilenameFromBasename(lfi->basename); } static int getFiletypeFromID(char *filetype_id) { char *filetype_id_lower; int filetype = LEVEL_FILE_TYPE_UNKNOWN; int i; if (filetype_id == NULL) return LEVEL_FILE_TYPE_UNKNOWN; filetype_id_lower = getStringToLower(filetype_id); for (i = 0; filetype_id_list[i].id != NULL; i++) { char *id_lower = getStringToLower(filetype_id_list[i].id); if (strEqual(filetype_id_lower, id_lower)) filetype = filetype_id_list[i].filetype; free(id_lower); if (filetype != LEVEL_FILE_TYPE_UNKNOWN) break; } free(filetype_id_lower); return filetype; } char *getLocalLevelTemplateFilename() { return getDefaultLevelFilename(-1); } char *getGlobalLevelTemplateFilename() { /* global variable "leveldir_current" must be modified in the loop below */ LevelDirTree *leveldir_current_last = leveldir_current; char *filename = NULL; /* check for template level in path from current to topmost tree node */ while (leveldir_current != NULL) { filename = getDefaultLevelFilename(-1); if (fileExists(filename)) break; leveldir_current = leveldir_current->node_parent; } /* restore global variable "leveldir_current" modified in above loop */ leveldir_current = leveldir_current_last; return filename; } static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi) { int nr = lfi->nr; /* special case: level number is negative => check for level template file */ if (nr < 0) { setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, getSingleLevelBasename(-1)); /* replace local level template filename with global template filename */ lfi->filename = getGlobalLevelTemplateFilename(); /* no fallback if template file not existing */ return; } /* special case: check for file name/pattern specified in "levelinfo.conf" */ if (leveldir_current->level_filename != NULL) { int filetype = getFiletypeFromID(leveldir_current->level_filetype); setLevelFileInfo_FormatLevelFilename(lfi, filetype, leveldir_current->level_filename, nr); lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename); if (fileExists(lfi->filename)) return; } else if (leveldir_current->level_filetype != NULL) { int filetype = getFiletypeFromID(leveldir_current->level_filetype); /* check for specified native level file with standard file name */ setLevelFileInfo_FormatLevelFilename(lfi, filetype, "%03d.%s", nr, LEVELFILE_EXTENSION); if (fileExists(lfi->filename)) return; } /* check for native Rocks'n'Diamonds level file */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, "%03d.%s", nr, LEVELFILE_EXTENSION); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V1) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c", 'a' + (nr / 10) % 26, '0' + nr % 10); if (fileExists(lfi->filename)) return; setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c", 'A' + (nr / 10) % 26, '0' + nr % 10); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V2 to V5) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V6 / single mode) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr); if (fileExists(lfi->filename)) return; setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr); if (fileExists(lfi->filename)) return; /* check for Emerald Mine level file (V6 / teamwork mode) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr); if (fileExists(lfi->filename)) return; setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr); if (fileExists(lfi->filename)) return; /* check for various packed level file formats */ setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN); if (fileExists(lfi->filename)) return; /* no known level file found -- use default values (and fail later) */ setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND, "%03d.%s", nr, LEVELFILE_EXTENSION); } static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi) { if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN) lfi->type = getFileTypeFromBasename(lfi->basename); if (lfi->type == LEVEL_FILE_TYPE_RND) lfi->type = getFileTypeFromMagicBytes(lfi->filename, lfi->type); } static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr) { /* always start with reliable default values */ setFileInfoToDefaults(level_file_info); level_file_info->nr = nr; /* set requested level number */ determineLevelFileInfo_Filename(level_file_info); determineLevelFileInfo_Filetype(level_file_info); } /* ------------------------------------------------------------------------- */ /* functions for loading R'n'D level */ /* ------------------------------------------------------------------------- */ int getMappedElement(int element) { /* remap some (historic, now obsolete) elements */ switch (element) { case EL_PLAYER_OBSOLETE: element = EL_PLAYER_1; break; case EL_KEY_OBSOLETE: element = EL_KEY_1; break; case EL_EM_KEY_1_FILE_OBSOLETE: element = EL_EM_KEY_1; break; case EL_EM_KEY_2_FILE_OBSOLETE: element = EL_EM_KEY_2; break; case EL_EM_KEY_3_FILE_OBSOLETE: element = EL_EM_KEY_3; break; case EL_EM_KEY_4_FILE_OBSOLETE: element = EL_EM_KEY_4; break; case EL_ENVELOPE_OBSOLETE: element = EL_ENVELOPE_1; break; case EL_SP_EMPTY: element = EL_EMPTY; break; default: if (element >= NUM_FILE_ELEMENTS) { Error(ERR_WARN, "invalid level element %d", element); element = EL_UNKNOWN; } break; } return element; } int getMappedElementByVersion(int element, int game_version) { /* remap some elements due to certain game version */ if (game_version <= VERSION_IDENT(2,2,0,0)) { /* map game font elements */ element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT : element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT : element == EL_CHAR(']') ? EL_CHAR_UUMLAUT : element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element); } if (game_version < VERSION_IDENT(3,0,0,0)) { /* map Supaplex gravity tube elements */ element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT : element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT : element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP : element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN : element); } return element; } static int LoadLevel_VERS(File *file, int chunk_size, struct LevelInfo *level) { level->file_version = getFileVersion(file); level->game_version = getFileVersion(file); return chunk_size; } static int LoadLevel_DATE(File *file, int chunk_size, struct LevelInfo *level) { level->creation_date.year = getFile16BitBE(file); level->creation_date.month = getFile8Bit(file); level->creation_date.day = getFile8Bit(file); level->creation_date.src = DATE_SRC_LEVELFILE; return chunk_size; } static int LoadLevel_HEAD(File *file, int chunk_size, struct LevelInfo *level) { int initial_player_stepsize; int initial_player_gravity; int i, x, y; level->fieldx = getFile8Bit(file); level->fieldy = getFile8Bit(file); level->time = getFile16BitBE(file); level->gems_needed = getFile16BitBE(file); for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = getFile8Bit(file); level->name[MAX_LEVEL_NAME_LEN] = 0; for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) level->score[i] = getFile8Bit(file); level->num_yamyam_contents = STD_ELEMENT_CONTENTS; for (i = 0; i < STD_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file)); level->amoeba_speed = getFile8Bit(file); level->time_magic_wall = getFile8Bit(file); level->time_wheel = getFile8Bit(file); level->amoeba_content = getMappedElement(getFile8Bit(file)); initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST : STEPSIZE_NORMAL); for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_stepsize[i] = initial_player_stepsize; initial_player_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE); for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_gravity[i] = initial_player_gravity; level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->can_move_into_acid_bits = getFile32BitBE(file); level->dont_collide_with_bits = getFile8Bit(file); level->use_spring_bug = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->instant_relocation = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->can_pass_to_walkable = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->grow_into_diggable = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->game_engine_type = getFile8Bit(file); ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED); return chunk_size; } static int LoadLevel_NAME(File *file, int chunk_size, struct LevelInfo *level) { int i; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = getFile8Bit(file); level->name[MAX_LEVEL_NAME_LEN] = 0; return chunk_size; } static int LoadLevel_AUTH(File *file, int chunk_size, struct LevelInfo *level) { int i; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) level->author[i] = getFile8Bit(file); level->author[MAX_LEVEL_AUTHOR_LEN] = 0; return chunk_size; } static int LoadLevel_BODY(File *file, int chunk_size, struct LevelInfo *level) { int x, y; int chunk_size_expected = level->fieldx * level->fieldy; /* Note: "chunk_size" was wrong before version 2.0 when elements are stored with 16-bit encoding (and should be twice as big then). Even worse, playfield data was stored 16-bit when only yamyam content contained 16-bit elements and vice versa. */ if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0) chunk_size_expected *= 2; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) level->field[x][y] = getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) : getFile8Bit(file)); return chunk_size; } static int LoadLevel_CONT(File *file, int chunk_size, struct LevelInfo *level) { int i, x, y; int header_size = 4; int content_size = MAX_ELEMENT_CONTENTS * 3 * 3; int chunk_size_expected = header_size + content_size; /* Note: "chunk_size" was wrong before version 2.0 when elements are stored with 16-bit encoding (and should be twice as big then). Even worse, playfield data was stored 16-bit when only yamyam content contained 16-bit elements and vice versa. */ if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0) chunk_size_expected += content_size; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } getFile8Bit(file); level->num_yamyam_contents = getFile8Bit(file); getFile8Bit(file); getFile8Bit(file); /* correct invalid number of content fields -- should never happen */ if (level->num_yamyam_contents < 1 || level->num_yamyam_contents > MAX_ELEMENT_CONTENTS) level->num_yamyam_contents = STD_ELEMENT_CONTENTS; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) : getFile8Bit(file)); return chunk_size; } static int LoadLevel_CNT2(File *file, int chunk_size, struct LevelInfo *level) { int i, x, y; int element; int num_contents; int content_array[MAX_ELEMENT_CONTENTS][3][3]; element = getMappedElement(getFile16BitBE(file)); num_contents = getFile8Bit(file); getFile8Bit(file); /* content x size (unused) */ getFile8Bit(file); /* content y size (unused) */ ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_array[i][x][y] = getMappedElement(getFile16BitBE(file)); /* correct invalid number of content fields -- should never happen */ if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS) num_contents = STD_ELEMENT_CONTENTS; if (element == EL_YAMYAM) { level->num_yamyam_contents = num_contents; for (i = 0; i < num_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = content_array[i][x][y]; } else if (element == EL_BD_AMOEBA) { level->amoeba_content = content_array[0][0][0]; } else { Error(ERR_WARN, "cannot load content for element '%d'", element); } return chunk_size; } static int LoadLevel_CNT3(File *file, int chunk_size, struct LevelInfo *level) { int i; int element; int envelope_nr; int envelope_len; int chunk_size_expected; element = getMappedElement(getFile16BitBE(file)); if (!IS_ENVELOPE(element)) element = EL_ENVELOPE_1; envelope_nr = element - EL_ENVELOPE_1; envelope_len = getFile16BitBE(file); level->envelope[envelope_nr].xsize = getFile8Bit(file); level->envelope[envelope_nr].ysize = getFile8Bit(file); ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED); chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len); if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER); return chunk_size_expected; } for (i = 0; i < envelope_len; i++) level->envelope[envelope_nr].text[i] = getFile8Bit(file); return chunk_size; } static int LoadLevel_CUS1(File *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); int chunk_size_expected = 2 + num_changed_custom_elements * 6; int i; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size_expected; } for (i = 0; i < num_changed_custom_elements; i++) { int element = getMappedElement(getFile16BitBE(file)); int properties = getFile32BitBE(file); if (IS_CUSTOM_ELEMENT(element)) element_info[element].properties[EP_BITFIELD_BASE_NR] = properties; else Error(ERR_WARN, "invalid custom element number %d", element); /* older game versions that wrote level files with CUS1 chunks used different default push delay values (not yet stored in level file) */ element_info[element].push_delay_fixed = 2; element_info[element].push_delay_random = 8; } level->file_has_custom_elements = TRUE; return chunk_size; } static int LoadLevel_CUS2(File *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); int chunk_size_expected = 2 + num_changed_custom_elements * 4; int i; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size_expected; } for (i = 0; i < num_changed_custom_elements; i++) { int element = getMappedElement(getFile16BitBE(file)); int custom_target_element = getMappedElement(getFile16BitBE(file)); if (IS_CUSTOM_ELEMENT(element)) element_info[element].change->target_element = custom_target_element; else Error(ERR_WARN, "invalid custom element number %d", element); } level->file_has_custom_elements = TRUE; return chunk_size; } static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements); int i, j, x, y; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size_expected; } for (i = 0; i < num_changed_custom_elements; i++) { int element = getMappedElement(getFile16BitBE(file)); struct ElementInfo *ei = &element_info[element]; unsigned int event_bits; if (!IS_CUSTOM_ELEMENT(element)) { Error(ERR_WARN, "invalid custom element number %d", element); element = EL_INTERNAL_DUMMY; } for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++) ei->description[j] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file); /* some free bytes for future properties and padding */ ReadUnusedBytesFromFile(file, 7); ei->use_gfx_element = getFile8Bit(file); ei->gfx_element_initial = getMappedElement(getFile16BitBE(file)); ei->collect_score_initial = getFile8Bit(file); ei->collect_count_initial = getFile8Bit(file); ei->push_delay_fixed = getFile16BitBE(file); ei->push_delay_random = getFile16BitBE(file); ei->move_delay_fixed = getFile16BitBE(file); ei->move_delay_random = getFile16BitBE(file); ei->move_pattern = getFile16BitBE(file); ei->move_direction_initial = getFile8Bit(file); ei->move_stepsize = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) ei->content.e[x][y] = getMappedElement(getFile16BitBE(file)); event_bits = getFile32BitBE(file); for (j = 0; j < NUM_CHANGE_EVENTS; j++) if (event_bits & (1 << j)) ei->change->has_event[j] = TRUE; ei->change->target_element = getMappedElement(getFile16BitBE(file)); ei->change->delay_fixed = getFile16BitBE(file); ei->change->delay_random = getFile16BitBE(file); ei->change->delay_frames = getFile16BitBE(file); ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file)); ei->change->explode = getFile8Bit(file); ei->change->use_target_content = getFile8Bit(file); ei->change->only_if_complete = getFile8Bit(file); ei->change->use_random_replace = getFile8Bit(file); ei->change->random_percentage = getFile8Bit(file); ei->change->replace_when = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) ei->change->target_content.e[x][y] = getMappedElement(getFile16BitBE(file)); ei->slippery_type = getFile8Bit(file); /* some free bytes for future properties and padding */ ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED); /* mark that this custom element has been modified */ ei->modified_settings = TRUE; } level->file_has_custom_elements = TRUE; return chunk_size; } static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level) { struct ElementInfo *ei; int chunk_size_expected; int element; int i, j, x, y; /* ---------- custom element base property values (96 bytes) ------------- */ element = getMappedElement(getFile16BitBE(file)); if (!IS_CUSTOM_ELEMENT(element)) { Error(ERR_WARN, "invalid custom element number %d", element); ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size; } ei = &element_info[element]; for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) ei->description[i] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file); ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */ ei->num_change_pages = getFile8Bit(file); chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages); if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size - 43); return chunk_size_expected; } ei->ce_value_fixed_initial = getFile16BitBE(file); ei->ce_value_random_initial = getFile16BitBE(file); ei->use_last_ce_value = getFile8Bit(file); ei->use_gfx_element = getFile8Bit(file); ei->gfx_element_initial = getMappedElement(getFile16BitBE(file)); ei->collect_score_initial = getFile8Bit(file); ei->collect_count_initial = getFile8Bit(file); ei->drop_delay_fixed = getFile8Bit(file); ei->push_delay_fixed = getFile8Bit(file); ei->drop_delay_random = getFile8Bit(file); ei->push_delay_random = getFile8Bit(file); ei->move_delay_fixed = getFile16BitBE(file); ei->move_delay_random = getFile16BitBE(file); /* bits 0 - 15 of "move_pattern" ... */ ei->move_pattern = getFile16BitBE(file); ei->move_direction_initial = getFile8Bit(file); ei->move_stepsize = getFile8Bit(file); ei->slippery_type = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) ei->content.e[x][y] = getMappedElement(getFile16BitBE(file)); ei->move_enter_element = getMappedElement(getFile16BitBE(file)); ei->move_leave_element = getMappedElement(getFile16BitBE(file)); ei->move_leave_type = getFile8Bit(file); /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */ ei->move_pattern |= (getFile16BitBE(file) << 16); ei->access_direction = getFile8Bit(file); ei->explosion_delay = getFile8Bit(file); ei->ignition_delay = getFile8Bit(file); ei->explosion_type = getFile8Bit(file); /* some free bytes for future custom property values and padding */ ReadUnusedBytesFromFile(file, 1); /* ---------- change page property values (48 bytes) --------------------- */ setElementChangePages(ei, ei->num_change_pages); for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; unsigned int event_bits; /* always start with reliable default values */ setElementChangeInfoToDefaults(change); /* bits 0 - 31 of "has_event[]" ... */ event_bits = getFile32BitBE(file); for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (event_bits & (1 << j)) change->has_event[j] = TRUE; change->target_element = getMappedElement(getFile16BitBE(file)); change->delay_fixed = getFile16BitBE(file); change->delay_random = getFile16BitBE(file); change->delay_frames = getFile16BitBE(file); change->initial_trigger_element = getMappedElement(getFile16BitBE(file)); change->explode = getFile8Bit(file); change->use_target_content = getFile8Bit(file); change->only_if_complete = getFile8Bit(file); change->use_random_replace = getFile8Bit(file); change->random_percentage = getFile8Bit(file); change->replace_when = getFile8Bit(file); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file)); change->can_change = getFile8Bit(file); change->trigger_side = getFile8Bit(file); change->trigger_player = getFile8Bit(file); change->trigger_page = getFile8Bit(file); change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ? CH_PAGE_ANY : (1 << change->trigger_page)); change->has_action = getFile8Bit(file); change->action_type = getFile8Bit(file); change->action_mode = getFile8Bit(file); change->action_arg = getFile16BitBE(file); /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */ event_bits = getFile8Bit(file); for (j = 32; j < NUM_CHANGE_EVENTS; j++) if (event_bits & (1 << (j - 32))) change->has_event[j] = TRUE; } /* mark this custom element as modified */ ei->modified_settings = TRUE; level->file_has_custom_elements = TRUE; return chunk_size; } static int LoadLevel_GRP1(File *file, int chunk_size, struct LevelInfo *level) { struct ElementInfo *ei; struct ElementGroupInfo *group; int element; int i; element = getMappedElement(getFile16BitBE(file)); if (!IS_GROUP_ELEMENT(element)) { Error(ERR_WARN, "invalid group element number %d", element); ReadUnusedBytesFromFile(file, chunk_size - 2); return chunk_size; } ei = &element_info[element]; for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) ei->description[i] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; group = element_info[element].group; group->num_elements = getFile8Bit(file); ei->use_gfx_element = getFile8Bit(file); ei->gfx_element_initial = getMappedElement(getFile16BitBE(file)); group->choice_mode = getFile8Bit(file); /* some free bytes for future values and padding */ ReadUnusedBytesFromFile(file, 3); for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++) group->element[i] = getMappedElement(getFile16BitBE(file)); /* mark this group element as modified */ element_info[element].modified_settings = TRUE; level->file_has_custom_elements = TRUE; return chunk_size; } static int LoadLevel_MicroChunk(File *file, struct LevelFileConfigInfo *conf, int element, int real_element) { int micro_chunk_size = 0; int conf_type = getFile8Bit(file); int byte_mask = conf_type & CONF_MASK_BYTES; boolean element_found = FALSE; int i; micro_chunk_size += 1; if (byte_mask == CONF_MASK_MULTI_BYTES) { int num_bytes = getFile16BitBE(file); byte *buffer = checked_malloc(num_bytes); ReadBytesFromFile(file, buffer, num_bytes); for (i = 0; conf[i].data_type != -1; i++) { if (conf[i].element == element && conf[i].conf_type == conf_type) { int data_type = conf[i].data_type; int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type); int max_num_entities = conf[i].max_num_entities; if (num_entities > max_num_entities) { Error(ERR_WARN, "truncating number of entities for element %d from %d to %d", element, num_entities, max_num_entities); num_entities = max_num_entities; } if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST || data_type == TYPE_CONTENT_LIST)) { /* for element and content lists, zero entities are not allowed */ Error(ERR_WARN, "found empty list of entities for element %d", element); /* do not set "num_entities" here to prevent reading behind buffer */ *(int *)(conf[i].num_entities) = 1; /* at least one is required */ } else { *(int *)(conf[i].num_entities) = num_entities; } element_found = TRUE; if (data_type == TYPE_STRING) { char *string = (char *)(conf[i].value); int j; for (j = 0; j < max_num_entities; j++) string[j] = (j < num_entities ? buffer[j] : '\0'); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(conf[i].value); int j; for (j = 0; j < num_entities; j++) element_array[j] = getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j)); } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content= (struct Content *)(conf[i].value); int c, x, y; for (c = 0; c < num_entities; c++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content[c].e[x][y] = getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y)); } else element_found = FALSE; break; } } checked_free(buffer); micro_chunk_size += 2 + num_bytes; } else /* constant size configuration data (1, 2 or 4 bytes) */ { int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) : byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) : byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0); for (i = 0; conf[i].data_type != -1; i++) { if (conf[i].element == element && conf[i].conf_type == conf_type) { int data_type = conf[i].data_type; if (data_type == TYPE_ELEMENT) value = getMappedElement(value); if (data_type == TYPE_BOOLEAN) *(boolean *)(conf[i].value) = value; else *(int *) (conf[i].value) = value; element_found = TRUE; break; } } micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask); } if (!element_found) { char *error_conf_chunk_bytes = (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" : byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" : byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES"); int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN; int error_element = real_element; Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']", error_conf_chunk_bytes, error_conf_chunk_token, error_element, EL_NAME(error_element)); } return micro_chunk_size; } static int LoadLevel_INFO(File *file, int chunk_size, struct LevelInfo *level) { int real_chunk_size = 0; li = *level; /* copy level data into temporary buffer */ while (!checkEndOfFile(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1); if (real_chunk_size >= chunk_size) break; } *level = li; /* copy temporary buffer back to level data */ return real_chunk_size; } static int LoadLevel_CONF(File *file, int chunk_size, struct LevelInfo *level) { int real_chunk_size = 0; li = *level; /* copy level data into temporary buffer */ while (!checkEndOfFile(file)) { int element = getMappedElement(getFile16BitBE(file)); real_chunk_size += 2; real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF, element, element); if (real_chunk_size >= chunk_size) break; } *level = li; /* copy temporary buffer back to level data */ return real_chunk_size; } static int LoadLevel_ELEM(File *file, int chunk_size, struct LevelInfo *level) { int real_chunk_size = 0; li = *level; /* copy level data into temporary buffer */ while (!checkEndOfFile(file)) { int element = getMappedElement(getFile16BitBE(file)); real_chunk_size += 2; real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM, element, element); if (real_chunk_size >= chunk_size) break; } *level = li; /* copy temporary buffer back to level data */ return real_chunk_size; } static int LoadLevel_NOTE(File *file, int chunk_size, struct LevelInfo *level) { int element = getMappedElement(getFile16BitBE(file)); int envelope_nr = element - EL_ENVELOPE_1; int real_chunk_size = 2; xx_envelope = level->envelope[envelope_nr]; /* copy into temporary buffer */ while (!checkEndOfFile(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE, -1, element); if (real_chunk_size >= chunk_size) break; } level->envelope[envelope_nr] = xx_envelope; /* copy from temporary buffer */ return real_chunk_size; } static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level) { int element = getMappedElement(getFile16BitBE(file)); int real_chunk_size = 2; struct ElementInfo *ei = &element_info[element]; int i; xx_ei = *ei; /* copy element data into temporary buffer */ xx_ei.num_change_pages = -1; while (!checkEndOfFile(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base, -1, element); if (xx_ei.num_change_pages != -1) break; if (real_chunk_size >= chunk_size) break; } *ei = xx_ei; if (ei->num_change_pages == -1) { Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'", EL_NAME(element)); ei->num_change_pages = 1; setElementChangePages(ei, 1); setElementChangeInfoToDefaults(ei->change); return real_chunk_size; } /* initialize number of change pages stored for this custom element */ setElementChangePages(ei, ei->num_change_pages); for (i = 0; i < ei->num_change_pages; i++) setElementChangeInfoToDefaults(&ei->change_page[i]); /* start with reading properties for the first change page */ xx_current_change_page = 0; while (!checkEndOfFile(file)) { struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page]; xx_change = *change; /* copy change data into temporary buffer */ resetEventBits(); /* reset bits; change page might have changed */ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change, -1, element); *change = xx_change; setEventFlagsFromEventBits(change); if (real_chunk_size >= chunk_size) break; } level->file_has_custom_elements = TRUE; return real_chunk_size; } static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level) { int element = getMappedElement(getFile16BitBE(file)); int real_chunk_size = 2; struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; xx_ei = *ei; /* copy element data into temporary buffer */ xx_group = *group; /* copy group data into temporary buffer */ while (!checkEndOfFile(file)) { real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX, -1, element); if (real_chunk_size >= chunk_size) break; } *ei = xx_ei; *group = xx_group; level->file_has_custom_elements = TRUE; return real_chunk_size; } static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { char *filename = level_file_info->filename; char cookie[MAX_LINE_LEN]; char chunk_name[CHUNK_ID_LEN + 1]; int chunk_size; File *file; if (!(file = openFile(filename, MODE_READ))) { level->no_valid_file = TRUE; level->no_level_file = TRUE; if (level_info_only) return; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); if (!setup.editor.use_template_for_new_levels) return; /* if level file not found, try to initialize level data from template */ filename = getGlobalLevelTemplateFilename(); if (!(file = openFile(filename, MODE_READ))) return; /* default: for empty levels, use level template for custom elements */ level->use_custom_template = TRUE; level->no_valid_file = FALSE; } getFileChunkBE(file, chunk_name, NULL); if (strEqual(chunk_name, "RND1")) { getFile32BitBE(file); /* not used */ getFileChunkBE(file, chunk_name, NULL); if (!strEqual(chunk_name, "CAVE")) { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown format of level file '%s'", filename); closeFile(file); return; } } else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); if (getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4) == NULL) cookie[4] = '\0'; if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL)) { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown format of level file '%s'", filename); closeFile(file); return; } if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1) { level->no_valid_file = TRUE; Error(ERR_WARN, "unsupported version of level file '%s'", filename); closeFile(file); return; } /* pre-2.0 level files have no game version, so use file version here */ level->game_version = level->file_version; } if (level->file_version < FILE_VERSION_1_2) { /* level files from versions before 1.2.0 without chunk structure */ LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE, level); LoadLevel_BODY(file, level->fieldx * level->fieldy, level); } else { static struct { char *name; int size; int (*loader)(File *, int, struct LevelInfo *); } chunk_info[] = { { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS }, { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE }, { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD }, { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME }, { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH }, { "INFO", -1, LoadLevel_INFO }, { "BODY", -1, LoadLevel_BODY }, { "CONT", -1, LoadLevel_CONT }, { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 }, { "CNT3", -1, LoadLevel_CNT3 }, { "CUS1", -1, LoadLevel_CUS1 }, { "CUS2", -1, LoadLevel_CUS2 }, { "CUS3", -1, LoadLevel_CUS3 }, { "CUS4", -1, LoadLevel_CUS4 }, { "GRP1", -1, LoadLevel_GRP1 }, { "CONF", -1, LoadLevel_CONF }, { "ELEM", -1, LoadLevel_ELEM }, { "NOTE", -1, LoadLevel_NOTE }, { "CUSX", -1, LoadLevel_CUSX }, { "GRPX", -1, LoadLevel_GRPX }, { NULL, 0, NULL } }; while (getFileChunkBE(file, chunk_name, &chunk_size)) { int i = 0; while (chunk_info[i].name != NULL && !strEqual(chunk_name, chunk_info[i].name)) i++; if (chunk_info[i].name == NULL) { Error(ERR_WARN, "unknown chunk '%s' in level file '%s'", chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else if (chunk_info[i].size != -1 && chunk_info[i].size != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else { /* call function to load this level chunk */ int chunk_size_expected = (chunk_info[i].loader)(file, chunk_size, level); /* the size of some chunks cannot be checked before reading other chunks first (like "HEAD" and "BODY") that contain some header information, so check them here */ if (chunk_size_expected != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); } } } } closeFile(file); } /* ------------------------------------------------------------------------- */ /* functions for loading EM level */ /* ------------------------------------------------------------------------- */ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) { static int ball_xy[8][2] = { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, }; struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; struct PLAYER **ply = level_em->ply; int i, j, x, y; lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH); lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT); lev->time_seconds = level->time; lev->required_initial = level->gems_needed; lev->emerald_score = level->score[SC_EMERALD]; lev->diamond_score = level->score[SC_DIAMOND]; lev->alien_score = level->score[SC_ROBOT]; lev->tank_score = level->score[SC_SPACESHIP]; lev->bug_score = level->score[SC_BUG]; lev->eater_score = level->score[SC_YAMYAM]; lev->nut_score = level->score[SC_NUT]; lev->dynamite_score = level->score[SC_DYNAMITE]; lev->key_score = level->score[SC_KEY]; lev->exit_score = level->score[SC_TIME_BONUS]; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) lev->eater_array[i][y * 3 + x] = map_element_RND_to_EM(level->yamyam_content[i].e[x][y]); lev->amoeba_time = level->amoeba_speed; lev->wonderwall_time_initial = level->time_magic_wall; lev->wheel_time = level->time_wheel; lev->android_move_time = level->android_move_time; lev->android_clone_time = level->android_clone_time; lev->ball_random = level->ball_random; lev->ball_state_initial = level->ball_state_initial; lev->ball_time = level->ball_time; lev->num_ball_arrays = level->num_ball_contents; lev->lenses_score = level->lenses_score; lev->magnify_score = level->magnify_score; lev->slurp_score = level->slurp_score; lev->lenses_time = level->lenses_time; lev->magnify_time = level->magnify_time; lev->wind_direction_initial = map_direction_RND_to_EM(level->wind_direction_initial); lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ? lev->wind_time : 0); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) lev->ball_array[i][j] = map_element_RND_to_EM(level-> ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]); map_android_clone_elements_RND_to_EM(level); /* first fill the complete playfield with the default border element */ for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++) for (x = 0; x < EM_MAX_CAVE_WIDTH; x++) level_em->cave[x][y] = ZBORDER; if (BorderElement == EL_STEELWALL) { for (y = 0; y < lev->height + 2; y++) for (x = 0; x < lev->width + 2; x++) level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL); } /* then copy the real level contents from level file into the playfield */ for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) { int new_element = map_element_RND_to_EM(level->field[x][y]); int offset = (BorderElement == EL_STEELWALL ? 1 : 0); int xx = x + 1 + offset; int yy = y + 1 + offset; if (level->field[x][y] == EL_AMOEBA_DEAD) new_element = map_element_RND_to_EM(EL_AMOEBA_WET); level_em->cave[xx][yy] = new_element; } for (i = 0; i < MAX_PLAYERS; i++) { ply[i]->x_initial = 0; ply[i]->y_initial = 0; } /* initialize player positions and delete players from the playfield */ for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++) { if (ELEM_IS_PLAYER(level->field[x][y])) { int player_nr = GET_PLAYER_NR(level->field[x][y]); int offset = (BorderElement == EL_STEELWALL ? 1 : 0); int xx = x + 1 + offset; int yy = y + 1 + offset; ply[player_nr]->x_initial = xx; ply[player_nr]->y_initial = yy; level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY); } } if (BorderElement == EL_STEELWALL) { lev->width += 2; lev->height += 2; } } void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) { static int ball_xy[8][2] = { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, }; struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; struct PLAYER **ply = level_em->ply; int i, j, x, y; level->fieldx = MIN(lev->width, MAX_LEV_FIELDX); level->fieldy = MIN(lev->height, MAX_LEV_FIELDY); level->time = lev->time_seconds; level->gems_needed = lev->required_initial; sprintf(level->name, "Level %d", level->file_info.nr); level->score[SC_EMERALD] = lev->emerald_score; level->score[SC_DIAMOND] = lev->diamond_score; level->score[SC_ROBOT] = lev->alien_score; level->score[SC_SPACESHIP] = lev->tank_score; level->score[SC_BUG] = lev->bug_score; level->score[SC_YAMYAM] = lev->eater_score; level->score[SC_NUT] = lev->nut_score; level->score[SC_DYNAMITE] = lev->dynamite_score; level->score[SC_KEY] = lev->key_score; level->score[SC_TIME_BONUS] = lev->exit_score; level->num_yamyam_contents = MAX_ELEMENT_CONTENTS; for (i = 0; i < level->num_yamyam_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) level->yamyam_content[i].e[x][y] = map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]); level->amoeba_speed = lev->amoeba_time; level->time_magic_wall = lev->wonderwall_time_initial; level->time_wheel = lev->wheel_time; level->android_move_time = lev->android_move_time; level->android_clone_time = lev->android_clone_time; level->ball_random = lev->ball_random; level->ball_state_initial = lev->ball_state_initial; level->ball_time = lev->ball_time; level->num_ball_contents = lev->num_ball_arrays; level->lenses_score = lev->lenses_score; level->magnify_score = lev->magnify_score; level->slurp_score = lev->slurp_score; level->lenses_time = lev->lenses_time; level->magnify_time = lev->magnify_time; level->wind_direction_initial = map_direction_EM_to_RND(lev->wind_direction_initial); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] = map_element_EM_to_RND(lev->ball_array[i][j]); map_android_clone_elements_EM_to_RND(level); /* convert the playfield (some elements need special treatment) */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]); if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0) new_element = EL_AMOEBA_DEAD; level->field[x][y] = new_element; } for (i = 0; i < MAX_PLAYERS; i++) { /* in case of all players set to the same field, use the first player */ int nr = MAX_PLAYERS - i - 1; int jx = ply[nr]->x_initial - 1; int jy = ply[nr]->y_initial - 1; if (jx != -1 && jy != -1) level->field[jx][jy] = EL_PLAYER_1 + nr; } } /* ------------------------------------------------------------------------- */ /* functions for loading SP level */ /* ------------------------------------------------------------------------- */ void CopyNativeLevel_RND_to_SP(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; LevelInfoType *header = &level_sp->header; int i, x, y; level_sp->width = level->fieldx; level_sp->height = level->fieldy; for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) level_sp->playfield[x][y] = map_element_RND_to_SP(level->field[x][y]); header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0); for (i = 0; i < SP_LEVEL_NAME_LEN; i++) header->LevelTitle[i] = level->name[i]; /* !!! NO STRING TERMINATION IN SUPAPLEX VB CODE YET -- FIX THIS !!! */ header->InfotronsNeeded = level->gems_needed; header->SpecialPortCount = 0; for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) { boolean gravity_port_found = FALSE; boolean gravity_port_valid = FALSE; int gravity_port_flag; int gravity_port_base_element; int element = level->field[x][y]; if (element >= EL_SP_GRAVITY_ON_PORT_RIGHT && element <= EL_SP_GRAVITY_ON_PORT_UP) { gravity_port_found = TRUE; gravity_port_valid = TRUE; gravity_port_flag = 1; gravity_port_base_element = EL_SP_GRAVITY_ON_PORT_RIGHT; } else if (element >= EL_SP_GRAVITY_OFF_PORT_RIGHT && element <= EL_SP_GRAVITY_OFF_PORT_UP) { gravity_port_found = TRUE; gravity_port_valid = TRUE; gravity_port_flag = 0; gravity_port_base_element = EL_SP_GRAVITY_OFF_PORT_RIGHT; } else if (element >= EL_SP_GRAVITY_PORT_RIGHT && element <= EL_SP_GRAVITY_PORT_UP) { /* change R'n'D style gravity inverting special port to normal port (there are no gravity inverting ports in native Supaplex engine) */ gravity_port_found = TRUE; gravity_port_valid = FALSE; gravity_port_base_element = EL_SP_GRAVITY_PORT_RIGHT; } if (gravity_port_found) { if (gravity_port_valid && header->SpecialPortCount < SP_MAX_SPECIAL_PORTS) { SpecialPortType *port = &header->SpecialPort[header->SpecialPortCount]; port->PortLocation = (y * level->fieldx + x) * 2; port->Gravity = gravity_port_flag; element += EL_SP_GRAVITY_PORT_RIGHT - gravity_port_base_element; header->SpecialPortCount++; } else { /* change special gravity port to normal port */ element += EL_SP_PORT_RIGHT - gravity_port_base_element; } level_sp->playfield[x][y] = element - EL_SP_START; } } } void CopyNativeLevel_SP_to_RND(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; LevelInfoType *header = &level_sp->header; boolean num_invalid_elements = 0; int i, j, x, y; level->fieldx = level_sp->width; level->fieldy = level_sp->height; for (x = 0; x < level->fieldx; x++) { for (y = 0; y < level->fieldy; y++) { int element_old = level_sp->playfield[x][y]; int element_new = getMappedElement(map_element_SP_to_RND(element_old)); if (element_new == EL_UNKNOWN) { num_invalid_elements++; Error(ERR_DEBUG, "invalid element %d at position %d, %d", element_old, x, y); } level->field[x][y] = element_new; } } if (num_invalid_elements > 0) Error(ERR_WARN, "found %d invalid elements%s", num_invalid_elements, (!options.debug ? " (use '--debug' for more details)" : "")); for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_gravity[i] = (header->InitialGravity == 1 ? TRUE : FALSE); /* skip leading spaces */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) if (header->LevelTitle[i] != ' ') break; /* copy level title */ for (j = 0; i < SP_LEVEL_NAME_LEN; i++, j++) level->name[j] = header->LevelTitle[i]; level->name[j] = '\0'; /* cut trailing spaces */ for (; j > 0; j--) if (level->name[j - 1] == ' ' && level->name[j] == '\0') level->name[j - 1] = '\0'; level->gems_needed = header->InfotronsNeeded; for (i = 0; i < header->SpecialPortCount; i++) { SpecialPortType *port = &header->SpecialPort[i]; int port_location = port->PortLocation; int gravity = port->Gravity; int port_x, port_y, port_element; port_x = (port_location / 2) % level->fieldx; port_y = (port_location / 2) / level->fieldx; if (port_x < 0 || port_x >= level->fieldx || port_y < 0 || port_y >= level->fieldy) { Error(ERR_WARN, "special port position (%d, %d) out of bounds", port_x, port_y); continue; } port_element = level->field[port_x][port_y]; if (port_element < EL_SP_GRAVITY_PORT_RIGHT || port_element > EL_SP_GRAVITY_PORT_UP) { Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y); continue; } /* change previous (wrong) gravity inverting special port to either gravity enabling special port or gravity disabling special port */ level->field[port_x][port_y] += (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT : EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT; } /* change special gravity ports without database entries to normal ports */ for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT && level->field[x][y] <= EL_SP_GRAVITY_PORT_UP) level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT; level->time = 0; /* no time limit */ level->amoeba_speed = 0; level->time_magic_wall = 0; level->time_wheel = 0; level->amoeba_content = EL_EMPTY; #if 1 /* original Supaplex does not use score values -- use default values */ #else for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) level->score[i] = 0; #endif /* there are no yamyams in supaplex levels */ for (i = 0; i < level->num_yamyam_contents; i++) for (x = 0; x < 3; x++) for (y = 0; y < 3; y++) level->yamyam_content[i].e[x][y] = EL_EMPTY; } static void CopyNativeTape_RND_to_SP(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; struct DemoInfo_SP *demo = &level_sp->demo; int i, j; /* always start with reliable default values */ demo->is_available = FALSE; demo->length = 0; if (TAPE_IS_EMPTY(tape)) return; demo->level_nr = tape.level_nr; /* (currently not used) */ level_sp->header.DemoRandomSeed = tape.random_seed; demo->length = 0; for (i = 0; i < tape.length; i++) { int demo_action = map_key_RND_to_SP(tape.pos[i].action[0]); int demo_repeat = tape.pos[i].delay; int demo_entries = (demo_repeat + 15) / 16; if (demo->length + demo_entries >= SP_MAX_TAPE_LEN) { Error(ERR_WARN, "tape truncated: size exceeds maximum SP demo size %d", SP_MAX_TAPE_LEN); break; } for (j = 0; j < demo_repeat / 16; j++) demo->data[demo->length++] = 0xf0 | demo_action; if (demo_repeat % 16) demo->data[demo->length++] = ((demo_repeat % 16 - 1) << 4) | demo_action; } demo->is_available = TRUE; } static void setTapeInfoToDefaults(); static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) { struct LevelInfo_SP *level_sp = level->native_sp_level; struct DemoInfo_SP *demo = &level_sp->demo; char *filename = level->file_info.filename; int i; /* always start with reliable default values */ setTapeInfoToDefaults(); if (!demo->is_available) return; tape.level_nr = demo->level_nr; /* (currently not used) */ tape.random_seed = level_sp->header.DemoRandomSeed; TapeSetDateFromEpochSeconds(getFileTimestampEpochSeconds(filename)); tape.counter = 0; tape.pos[tape.counter].delay = 0; for (i = 0; i < demo->length; i++) { int demo_action = demo->data[i] & 0x0f; int demo_repeat = (demo->data[i] & 0xf0) >> 4; int tape_action = map_key_SP_to_RND(demo_action); int tape_repeat = demo_repeat + 1; byte action[MAX_PLAYERS] = { tape_action, 0, 0, 0 }; boolean success = 0; int j; for (j = 0; j < tape_repeat; j++) success = TapeAddAction(action); if (!success) { Error(ERR_WARN, "SP demo truncated: size exceeds maximum tape size %d", MAX_TAPE_LEN); break; } } TapeHaltRecording(); } /* ------------------------------------------------------------------------- */ /* functions for loading MM level */ /* ------------------------------------------------------------------------- */ void CopyNativeLevel_RND_to_MM(struct LevelInfo *level) { struct LevelInfo_MM *level_mm = level->native_mm_level; int x, y; level_mm->fieldx = MIN(level->fieldx, MM_MAX_PLAYFIELD_WIDTH); level_mm->fieldy = MIN(level->fieldy, MM_MAX_PLAYFIELD_HEIGHT); level_mm->time = level->time; level_mm->kettles_needed = level->gems_needed; level_mm->auto_count_kettles = level->auto_count_gems; level_mm->laser_red = level->mm_laser_red; level_mm->laser_green = level->mm_laser_green; level_mm->laser_blue = level->mm_laser_blue; strcpy(level_mm->name, level->name); strcpy(level_mm->author, level->author); level_mm->score[SC_EMERALD] = level->score[SC_EMERALD]; level_mm->score[SC_PACMAN] = level->score[SC_PACMAN]; level_mm->score[SC_KEY] = level->score[SC_KEY]; level_mm->score[SC_TIME_BONUS] = level->score[SC_TIME_BONUS]; level_mm->score[SC_ELEM_BONUS] = level->score[SC_ELEM_BONUS]; level_mm->amoeba_speed = level->amoeba_speed; level_mm->time_fuse = level->mm_time_fuse; level_mm->time_bomb = level->mm_time_bomb; level_mm->time_ball = level->mm_time_ball; level_mm->time_block = level->mm_time_block; for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) Ur[x][y] = level_mm->field[x][y] = map_element_RND_to_MM(level->field[x][y]); } void CopyNativeLevel_MM_to_RND(struct LevelInfo *level) { struct LevelInfo_MM *level_mm = level->native_mm_level; int x, y; level->fieldx = MIN(level_mm->fieldx, MAX_LEV_FIELDX); level->fieldy = MIN(level_mm->fieldy, MAX_LEV_FIELDY); level->time = level_mm->time; level->gems_needed = level_mm->kettles_needed; level->auto_count_gems = level_mm->auto_count_kettles; level->mm_laser_red = level_mm->laser_red; level->mm_laser_green = level_mm->laser_green; level->mm_laser_blue = level_mm->laser_blue; strcpy(level->name, level_mm->name); /* only overwrite author from 'levelinfo.conf' if author defined in level */ if (!strEqual(level_mm->author, ANONYMOUS_NAME)) strcpy(level->author, level_mm->author); level->score[SC_EMERALD] = level_mm->score[SC_EMERALD]; level->score[SC_PACMAN] = level_mm->score[SC_PACMAN]; level->score[SC_KEY] = level_mm->score[SC_KEY]; level->score[SC_TIME_BONUS] = level_mm->score[SC_TIME_BONUS]; level->score[SC_ELEM_BONUS] = level_mm->score[SC_ELEM_BONUS]; level->amoeba_speed = level_mm->amoeba_speed; level->mm_time_fuse = level_mm->time_fuse; level->mm_time_bomb = level_mm->time_bomb; level->mm_time_ball = level_mm->time_ball; level->mm_time_block = level_mm->time_block; for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) level->field[x][y] = map_element_MM_to_RND(level_mm->field[x][y]); } /* ------------------------------------------------------------------------- */ /* functions for loading DC level */ /* ------------------------------------------------------------------------- */ #define DC_LEVEL_HEADER_SIZE 344 unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init) { static int last_data_encoded; static int offset1; static int offset2; int diff; int diff_hi, diff_lo; int data_hi, data_lo; unsigned short data_decoded; if (init) { last_data_encoded = 0; offset1 = -1; offset2 = 0; return 0; } diff = data_encoded - last_data_encoded; diff_hi = diff & ~0xff; diff_lo = diff & 0xff; offset2 += diff_lo; data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00); data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff; data_hi = data_hi & 0xff00; data_decoded = data_hi | data_lo; last_data_encoded = data_encoded; offset1 = (offset1 + 1) % 31; offset2 = offset2 & 0xff; return data_decoded; } int getMappedElement_DC(int element) { switch (element) { case 0x0000: element = EL_ROCK; break; /* 0x0117 - 0x036e: (?) */ /* EL_DIAMOND */ /* 0x042d - 0x0684: (?) */ /* EL_EMERALD */ case 0x06f1: element = EL_NUT; break; case 0x074c: element = EL_BOMB; break; case 0x07a4: element = EL_PEARL; break; case 0x0823: element = EL_CRYSTAL; break; case 0x0e77: /* quicksand (boulder) */ element = EL_QUICKSAND_FAST_FULL; break; case 0x0e99: /* slow quicksand (boulder) */ element = EL_QUICKSAND_FULL; break; case 0x0ed2: element = EL_EM_EXIT_OPEN; break; case 0x0ee3: element = EL_EM_EXIT_CLOSED; break; case 0x0eeb: element = EL_EM_STEEL_EXIT_OPEN; break; case 0x0efc: element = EL_EM_STEEL_EXIT_CLOSED; break; case 0x0f4f: /* dynamite (lit 1) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f57: /* dynamite (lit 2) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f5f: /* dynamite (lit 3) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f67: /* dynamite (lit 4) */ element = EL_EM_DYNAMITE_ACTIVE; break; case 0x0f81: case 0x0f82: case 0x0f83: case 0x0f84: element = EL_AMOEBA_WET; break; case 0x0f85: element = EL_AMOEBA_DROP; break; case 0x0fb9: element = EL_DC_MAGIC_WALL; break; case 0x0fd0: element = EL_SPACESHIP_UP; break; case 0x0fd9: element = EL_SPACESHIP_DOWN; break; case 0x0ff1: element = EL_SPACESHIP_LEFT; break; case 0x0ff9: element = EL_SPACESHIP_RIGHT; break; case 0x1057: element = EL_BUG_UP; break; case 0x1060: element = EL_BUG_DOWN; break; case 0x1078: element = EL_BUG_LEFT; break; case 0x1080: element = EL_BUG_RIGHT; break; case 0x10de: element = EL_MOLE_UP; break; case 0x10e7: element = EL_MOLE_DOWN; break; case 0x10ff: element = EL_MOLE_LEFT; break; case 0x1107: element = EL_MOLE_RIGHT; break; case 0x11c0: element = EL_ROBOT; break; case 0x13f5: element = EL_YAMYAM; break; case 0x1425: element = EL_SWITCHGATE_OPEN; break; case 0x1426: element = EL_SWITCHGATE_CLOSED; break; case 0x1437: element = EL_DC_SWITCHGATE_SWITCH_UP; break; case 0x143a: element = EL_TIMEGATE_CLOSED; break; case 0x144c: /* conveyor belt switch (green) */ element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE; break; case 0x144f: /* conveyor belt switch (red) */ element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE; break; case 0x1452: /* conveyor belt switch (blue) */ element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE; break; case 0x145b: element = EL_CONVEYOR_BELT_3_MIDDLE; break; case 0x1463: element = EL_CONVEYOR_BELT_3_LEFT; break; case 0x146b: element = EL_CONVEYOR_BELT_3_RIGHT; break; case 0x1473: element = EL_CONVEYOR_BELT_1_MIDDLE; break; case 0x147b: element = EL_CONVEYOR_BELT_1_LEFT; break; case 0x1483: element = EL_CONVEYOR_BELT_1_RIGHT; break; case 0x148b: element = EL_CONVEYOR_BELT_4_MIDDLE; break; case 0x1493: element = EL_CONVEYOR_BELT_4_LEFT; break; case 0x149b: element = EL_CONVEYOR_BELT_4_RIGHT; break; case 0x14ac: element = EL_EXPANDABLE_WALL_HORIZONTAL; break; case 0x14bd: element = EL_EXPANDABLE_WALL_VERTICAL; break; case 0x14c6: element = EL_EXPANDABLE_WALL_ANY; break; case 0x14ce: /* growing steel wall (left/right) */ element = EL_EXPANDABLE_STEELWALL_HORIZONTAL; break; case 0x14df: /* growing steel wall (up/down) */ element = EL_EXPANDABLE_STEELWALL_VERTICAL; break; case 0x14e8: /* growing steel wall (up/down/left/right) */ element = EL_EXPANDABLE_STEELWALL_ANY; break; case 0x14e9: element = EL_SHIELD_DEADLY; break; case 0x1501: element = EL_EXTRA_TIME; break; case 0x154f: element = EL_ACID; break; case 0x1577: element = EL_EMPTY_SPACE; break; case 0x1578: /* quicksand (empty) */ element = EL_QUICKSAND_FAST_EMPTY; break; case 0x1579: /* slow quicksand (empty) */ element = EL_QUICKSAND_EMPTY; break; /* 0x157c - 0x158b: */ /* EL_SAND */ /* 0x1590 - 0x159f: */ /* EL_DC_LANDMINE */ case 0x15a0: element = EL_EM_DYNAMITE; break; case 0x15a1: /* key (red) */ element = EL_EM_KEY_1; break; case 0x15a2: /* key (yellow) */ element = EL_EM_KEY_2; break; case 0x15a3: /* key (blue) */ element = EL_EM_KEY_4; break; case 0x15a4: /* key (green) */ element = EL_EM_KEY_3; break; case 0x15a5: /* key (white) */ element = EL_DC_KEY_WHITE; break; case 0x15a6: element = EL_WALL_SLIPPERY; break; case 0x15a7: element = EL_WALL; break; case 0x15a8: /* wall (not round) */ element = EL_WALL; break; case 0x15a9: /* (blue) */ element = EL_CHAR_A; break; case 0x15aa: /* (blue) */ element = EL_CHAR_B; break; case 0x15ab: /* (blue) */ element = EL_CHAR_C; break; case 0x15ac: /* (blue) */ element = EL_CHAR_D; break; case 0x15ad: /* (blue) */ element = EL_CHAR_E; break; case 0x15ae: /* (blue) */ element = EL_CHAR_F; break; case 0x15af: /* (blue) */ element = EL_CHAR_G; break; case 0x15b0: /* (blue) */ element = EL_CHAR_H; break; case 0x15b1: /* (blue) */ element = EL_CHAR_I; break; case 0x15b2: /* (blue) */ element = EL_CHAR_J; break; case 0x15b3: /* (blue) */ element = EL_CHAR_K; break; case 0x15b4: /* (blue) */ element = EL_CHAR_L; break; case 0x15b5: /* (blue) */ element = EL_CHAR_M; break; case 0x15b6: /* (blue) */ element = EL_CHAR_N; break; case 0x15b7: /* (blue) */ element = EL_CHAR_O; break; case 0x15b8: /* (blue) */ element = EL_CHAR_P; break; case 0x15b9: /* (blue) */ element = EL_CHAR_Q; break; case 0x15ba: /* (blue) */ element = EL_CHAR_R; break; case 0x15bb: /* (blue) */ element = EL_CHAR_S; break; case 0x15bc: /* (blue) */ element = EL_CHAR_T; break; case 0x15bd: /* (blue) */ element = EL_CHAR_U; break; case 0x15be: /* (blue) */ element = EL_CHAR_V; break; case 0x15bf: /* (blue) */ element = EL_CHAR_W; break; case 0x15c0: /* (blue) */ element = EL_CHAR_X; break; case 0x15c1: /* (blue) */ element = EL_CHAR_Y; break; case 0x15c2: /* (blue) */ element = EL_CHAR_Z; break; case 0x15c3: /* (blue) */ element = EL_CHAR_AUMLAUT; break; case 0x15c4: /* (blue) */ element = EL_CHAR_OUMLAUT; break; case 0x15c5: /* (blue) */ element = EL_CHAR_UUMLAUT; break; case 0x15c6: /* (blue) */ element = EL_CHAR_0; break; case 0x15c7: /* (blue) */ element = EL_CHAR_1; break; case 0x15c8: /* (blue) */ element = EL_CHAR_2; break; case 0x15c9: /* (blue) */ element = EL_CHAR_3; break; case 0x15ca: /* (blue) */ element = EL_CHAR_4; break; case 0x15cb: /* (blue) */ element = EL_CHAR_5; break; case 0x15cc: /* (blue) */ element = EL_CHAR_6; break; case 0x15cd: /* (blue) */ element = EL_CHAR_7; break; case 0x15ce: /* (blue) */ element = EL_CHAR_8; break; case 0x15cf: /* (blue) */ element = EL_CHAR_9; break; case 0x15d0: /* (blue) */ element = EL_CHAR_PERIOD; break; case 0x15d1: /* (blue) */ element = EL_CHAR_EXCLAM; break; case 0x15d2: /* (blue) */ element = EL_CHAR_COLON; break; case 0x15d3: /* (blue) */ element = EL_CHAR_LESS; break; case 0x15d4: /* (blue) */ element = EL_CHAR_GREATER; break; case 0x15d5: /* (blue) */ element = EL_CHAR_QUESTION; break; case 0x15d6: /* (blue) */ element = EL_CHAR_COPYRIGHT; break; case 0x15d7: /* (blue) */ element = EL_CHAR_UP; break; case 0x15d8: /* (blue) */ element = EL_CHAR_DOWN; break; case 0x15d9: /* (blue) */ element = EL_CHAR_BUTTON; break; case 0x15da: /* (blue) */ element = EL_CHAR_PLUS; break; case 0x15db: /* (blue) */ element = EL_CHAR_MINUS; break; case 0x15dc: /* (blue) */ element = EL_CHAR_APOSTROPHE; break; case 0x15dd: /* (blue) */ element = EL_CHAR_PARENLEFT; break; case 0x15de: /* (blue) */ element = EL_CHAR_PARENRIGHT; break; case 0x15df: /* (green) */ element = EL_CHAR_A; break; case 0x15e0: /* (green) */ element = EL_CHAR_B; break; case 0x15e1: /* (green) */ element = EL_CHAR_C; break; case 0x15e2: /* (green) */ element = EL_CHAR_D; break; case 0x15e3: /* (green) */ element = EL_CHAR_E; break; case 0x15e4: /* (green) */ element = EL_CHAR_F; break; case 0x15e5: /* (green) */ element = EL_CHAR_G; break; case 0x15e6: /* (green) */ element = EL_CHAR_H; break; case 0x15e7: /* (green) */ element = EL_CHAR_I; break; case 0x15e8: /* (green) */ element = EL_CHAR_J; break; case 0x15e9: /* (green) */ element = EL_CHAR_K; break; case 0x15ea: /* (green) */ element = EL_CHAR_L; break; case 0x15eb: /* (green) */ element = EL_CHAR_M; break; case 0x15ec: /* (green) */ element = EL_CHAR_N; break; case 0x15ed: /* (green) */ element = EL_CHAR_O; break; case 0x15ee: /* (green) */ element = EL_CHAR_P; break; case 0x15ef: /* (green) */ element = EL_CHAR_Q; break; case 0x15f0: /* (green) */ element = EL_CHAR_R; break; case 0x15f1: /* (green) */ element = EL_CHAR_S; break; case 0x15f2: /* (green) */ element = EL_CHAR_T; break; case 0x15f3: /* (green) */ element = EL_CHAR_U; break; case 0x15f4: /* (green) */ element = EL_CHAR_V; break; case 0x15f5: /* (green) */ element = EL_CHAR_W; break; case 0x15f6: /* (green) */ element = EL_CHAR_X; break; case 0x15f7: /* (green) */ element = EL_CHAR_Y; break; case 0x15f8: /* (green) */ element = EL_CHAR_Z; break; case 0x15f9: /* (green) */ element = EL_CHAR_AUMLAUT; break; case 0x15fa: /* (green) */ element = EL_CHAR_OUMLAUT; break; case 0x15fb: /* (green) */ element = EL_CHAR_UUMLAUT; break; case 0x15fc: /* (green) */ element = EL_CHAR_0; break; case 0x15fd: /* (green) */ element = EL_CHAR_1; break; case 0x15fe: /* (green) */ element = EL_CHAR_2; break; case 0x15ff: /* (green) */ element = EL_CHAR_3; break; case 0x1600: /* (green) */ element = EL_CHAR_4; break; case 0x1601: /* (green) */ element = EL_CHAR_5; break; case 0x1602: /* (green) */ element = EL_CHAR_6; break; case 0x1603: /* (green) */ element = EL_CHAR_7; break; case 0x1604: /* (green) */ element = EL_CHAR_8; break; case 0x1605: /* (green) */ element = EL_CHAR_9; break; case 0x1606: /* (green) */ element = EL_CHAR_PERIOD; break; case 0x1607: /* (green) */ element = EL_CHAR_EXCLAM; break; case 0x1608: /* (green) */ element = EL_CHAR_COLON; break; case 0x1609: /* (green) */ element = EL_CHAR_LESS; break; case 0x160a: /* (green) */ element = EL_CHAR_GREATER; break; case 0x160b: /* (green) */ element = EL_CHAR_QUESTION; break; case 0x160c: /* (green) */ element = EL_CHAR_COPYRIGHT; break; case 0x160d: /* (green) */ element = EL_CHAR_UP; break; case 0x160e: /* (green) */ element = EL_CHAR_DOWN; break; case 0x160f: /* (green) */ element = EL_CHAR_BUTTON; break; case 0x1610: /* (green) */ element = EL_CHAR_PLUS; break; case 0x1611: /* (green) */ element = EL_CHAR_MINUS; break; case 0x1612: /* (green) */ element = EL_CHAR_APOSTROPHE; break; case 0x1613: /* (green) */ element = EL_CHAR_PARENLEFT; break; case 0x1614: /* (green) */ element = EL_CHAR_PARENRIGHT; break; case 0x1615: /* (blue steel) */ element = EL_STEEL_CHAR_A; break; case 0x1616: /* (blue steel) */ element = EL_STEEL_CHAR_B; break; case 0x1617: /* (blue steel) */ element = EL_STEEL_CHAR_C; break; case 0x1618: /* (blue steel) */ element = EL_STEEL_CHAR_D; break; case 0x1619: /* (blue steel) */ element = EL_STEEL_CHAR_E; break; case 0x161a: /* (blue steel) */ element = EL_STEEL_CHAR_F; break; case 0x161b: /* (blue steel) */ element = EL_STEEL_CHAR_G; break; case 0x161c: /* (blue steel) */ element = EL_STEEL_CHAR_H; break; case 0x161d: /* (blue steel) */ element = EL_STEEL_CHAR_I; break; case 0x161e: /* (blue steel) */ element = EL_STEEL_CHAR_J; break; case 0x161f: /* (blue steel) */ element = EL_STEEL_CHAR_K; break; case 0x1620: /* (blue steel) */ element = EL_STEEL_CHAR_L; break; case 0x1621: /* (blue steel) */ element = EL_STEEL_CHAR_M; break; case 0x1622: /* (blue steel) */ element = EL_STEEL_CHAR_N; break; case 0x1623: /* (blue steel) */ element = EL_STEEL_CHAR_O; break; case 0x1624: /* (blue steel) */ element = EL_STEEL_CHAR_P; break; case 0x1625: /* (blue steel) */ element = EL_STEEL_CHAR_Q; break; case 0x1626: /* (blue steel) */ element = EL_STEEL_CHAR_R; break; case 0x1627: /* (blue steel) */ element = EL_STEEL_CHAR_S; break; case 0x1628: /* (blue steel) */ element = EL_STEEL_CHAR_T; break; case 0x1629: /* (blue steel) */ element = EL_STEEL_CHAR_U; break; case 0x162a: /* (blue steel) */ element = EL_STEEL_CHAR_V; break; case 0x162b: /* (blue steel) */ element = EL_STEEL_CHAR_W; break; case 0x162c: /* (blue steel) */ element = EL_STEEL_CHAR_X; break; case 0x162d: /* (blue steel) */ element = EL_STEEL_CHAR_Y; break; case 0x162e: /* (blue steel) */ element = EL_STEEL_CHAR_Z; break; case 0x162f: /* (blue steel) */ element = EL_STEEL_CHAR_AUMLAUT; break; case 0x1630: /* (blue steel) */ element = EL_STEEL_CHAR_OUMLAUT; break; case 0x1631: /* (blue steel) */ element = EL_STEEL_CHAR_UUMLAUT; break; case 0x1632: /* (blue steel) */ element = EL_STEEL_CHAR_0; break; case 0x1633: /* (blue steel) */ element = EL_STEEL_CHAR_1; break; case 0x1634: /* (blue steel) */ element = EL_STEEL_CHAR_2; break; case 0x1635: /* (blue steel) */ element = EL_STEEL_CHAR_3; break; case 0x1636: /* (blue steel) */ element = EL_STEEL_CHAR_4; break; case 0x1637: /* (blue steel) */ element = EL_STEEL_CHAR_5; break; case 0x1638: /* (blue steel) */ element = EL_STEEL_CHAR_6; break; case 0x1639: /* (blue steel) */ element = EL_STEEL_CHAR_7; break; case 0x163a: /* (blue steel) */ element = EL_STEEL_CHAR_8; break; case 0x163b: /* (blue steel) */ element = EL_STEEL_CHAR_9; break; case 0x163c: /* (blue steel) */ element = EL_STEEL_CHAR_PERIOD; break; case 0x163d: /* (blue steel) */ element = EL_STEEL_CHAR_EXCLAM; break; case 0x163e: /* (blue steel) */ element = EL_STEEL_CHAR_COLON; break; case 0x163f: /* (blue steel) */ element = EL_STEEL_CHAR_LESS; break; case 0x1640: /* (blue steel) */ element = EL_STEEL_CHAR_GREATER; break; case 0x1641: /* (blue steel) */ element = EL_STEEL_CHAR_QUESTION; break; case 0x1642: /* (blue steel) */ element = EL_STEEL_CHAR_COPYRIGHT; break; case 0x1643: /* (blue steel) */ element = EL_STEEL_CHAR_UP; break; case 0x1644: /* (blue steel) */ element = EL_STEEL_CHAR_DOWN; break; case 0x1645: /* (blue steel) */ element = EL_STEEL_CHAR_BUTTON; break; case 0x1646: /* (blue steel) */ element = EL_STEEL_CHAR_PLUS; break; case 0x1647: /* (blue steel) */ element = EL_STEEL_CHAR_MINUS; break; case 0x1648: /* (blue steel) */ element = EL_STEEL_CHAR_APOSTROPHE; break; case 0x1649: /* (blue steel) */ element = EL_STEEL_CHAR_PARENLEFT; break; case 0x164a: /* (blue steel) */ element = EL_STEEL_CHAR_PARENRIGHT; break; case 0x164b: /* (green steel) */ element = EL_STEEL_CHAR_A; break; case 0x164c: /* (green steel) */ element = EL_STEEL_CHAR_B; break; case 0x164d: /* (green steel) */ element = EL_STEEL_CHAR_C; break; case 0x164e: /* (green steel) */ element = EL_STEEL_CHAR_D; break; case 0x164f: /* (green steel) */ element = EL_STEEL_CHAR_E; break; case 0x1650: /* (green steel) */ element = EL_STEEL_CHAR_F; break; case 0x1651: /* (green steel) */ element = EL_STEEL_CHAR_G; break; case 0x1652: /* (green steel) */ element = EL_STEEL_CHAR_H; break; case 0x1653: /* (green steel) */ element = EL_STEEL_CHAR_I; break; case 0x1654: /* (green steel) */ element = EL_STEEL_CHAR_J; break; case 0x1655: /* (green steel) */ element = EL_STEEL_CHAR_K; break; case 0x1656: /* (green steel) */ element = EL_STEEL_CHAR_L; break; case 0x1657: /* (green steel) */ element = EL_STEEL_CHAR_M; break; case 0x1658: /* (green steel) */ element = EL_STEEL_CHAR_N; break; case 0x1659: /* (green steel) */ element = EL_STEEL_CHAR_O; break; case 0x165a: /* (green steel) */ element = EL_STEEL_CHAR_P; break; case 0x165b: /* (green steel) */ element = EL_STEEL_CHAR_Q; break; case 0x165c: /* (green steel) */ element = EL_STEEL_CHAR_R; break; case 0x165d: /* (green steel) */ element = EL_STEEL_CHAR_S; break; case 0x165e: /* (green steel) */ element = EL_STEEL_CHAR_T; break; case 0x165f: /* (green steel) */ element = EL_STEEL_CHAR_U; break; case 0x1660: /* (green steel) */ element = EL_STEEL_CHAR_V; break; case 0x1661: /* (green steel) */ element = EL_STEEL_CHAR_W; break; case 0x1662: /* (green steel) */ element = EL_STEEL_CHAR_X; break; case 0x1663: /* (green steel) */ element = EL_STEEL_CHAR_Y; break; case 0x1664: /* (green steel) */ element = EL_STEEL_CHAR_Z; break; case 0x1665: /* (green steel) */ element = EL_STEEL_CHAR_AUMLAUT; break; case 0x1666: /* (green steel) */ element = EL_STEEL_CHAR_OUMLAUT; break; case 0x1667: /* (green steel) */ element = EL_STEEL_CHAR_UUMLAUT; break; case 0x1668: /* (green steel) */ element = EL_STEEL_CHAR_0; break; case 0x1669: /* (green steel) */ element = EL_STEEL_CHAR_1; break; case 0x166a: /* (green steel) */ element = EL_STEEL_CHAR_2; break; case 0x166b: /* (green steel) */ element = EL_STEEL_CHAR_3; break; case 0x166c: /* (green steel) */ element = EL_STEEL_CHAR_4; break; case 0x166d: /* (green steel) */ element = EL_STEEL_CHAR_5; break; case 0x166e: /* (green steel) */ element = EL_STEEL_CHAR_6; break; case 0x166f: /* (green steel) */ element = EL_STEEL_CHAR_7; break; case 0x1670: /* (green steel) */ element = EL_STEEL_CHAR_8; break; case 0x1671: /* (green steel) */ element = EL_STEEL_CHAR_9; break; case 0x1672: /* (green steel) */ element = EL_STEEL_CHAR_PERIOD; break; case 0x1673: /* (green steel) */ element = EL_STEEL_CHAR_EXCLAM; break; case 0x1674: /* (green steel) */ element = EL_STEEL_CHAR_COLON; break; case 0x1675: /* (green steel) */ element = EL_STEEL_CHAR_LESS; break; case 0x1676: /* (green steel) */ element = EL_STEEL_CHAR_GREATER; break; case 0x1677: /* (green steel) */ element = EL_STEEL_CHAR_QUESTION; break; case 0x1678: /* (green steel) */ element = EL_STEEL_CHAR_COPYRIGHT; break; case 0x1679: /* (green steel) */ element = EL_STEEL_CHAR_UP; break; case 0x167a: /* (green steel) */ element = EL_STEEL_CHAR_DOWN; break; case 0x167b: /* (green steel) */ element = EL_STEEL_CHAR_BUTTON; break; case 0x167c: /* (green steel) */ element = EL_STEEL_CHAR_PLUS; break; case 0x167d: /* (green steel) */ element = EL_STEEL_CHAR_MINUS; break; case 0x167e: /* (green steel) */ element = EL_STEEL_CHAR_APOSTROPHE; break; case 0x167f: /* (green steel) */ element = EL_STEEL_CHAR_PARENLEFT; break; case 0x1680: /* (green steel) */ element = EL_STEEL_CHAR_PARENRIGHT; break; case 0x1681: /* gate (red) */ element = EL_EM_GATE_1; break; case 0x1682: /* secret gate (red) */ element = EL_GATE_1_GRAY; break; case 0x1683: /* gate (yellow) */ element = EL_EM_GATE_2; break; case 0x1684: /* secret gate (yellow) */ element = EL_GATE_2_GRAY; break; case 0x1685: /* gate (blue) */ element = EL_EM_GATE_4; break; case 0x1686: /* secret gate (blue) */ element = EL_GATE_4_GRAY; break; case 0x1687: /* gate (green) */ element = EL_EM_GATE_3; break; case 0x1688: /* secret gate (green) */ element = EL_GATE_3_GRAY; break; case 0x1689: /* gate (white) */ element = EL_DC_GATE_WHITE; break; case 0x168a: /* secret gate (white) */ element = EL_DC_GATE_WHITE_GRAY; break; case 0x168b: /* secret gate (no key) */ element = EL_DC_GATE_FAKE_GRAY; break; case 0x168c: element = EL_ROBOT_WHEEL; break; case 0x168d: element = EL_DC_TIMEGATE_SWITCH; break; case 0x168e: element = EL_ACID_POOL_BOTTOM; break; case 0x168f: element = EL_ACID_POOL_TOPLEFT; break; case 0x1690: element = EL_ACID_POOL_TOPRIGHT; break; case 0x1691: element = EL_ACID_POOL_BOTTOMLEFT; break; case 0x1692: element = EL_ACID_POOL_BOTTOMRIGHT; break; case 0x1693: element = EL_STEELWALL; break; case 0x1694: element = EL_STEELWALL_SLIPPERY; break; case 0x1695: /* steel wall (not round) */ element = EL_STEELWALL; break; case 0x1696: /* steel wall (left) */ element = EL_DC_STEELWALL_1_LEFT; break; case 0x1697: /* steel wall (bottom) */ element = EL_DC_STEELWALL_1_BOTTOM; break; case 0x1698: /* steel wall (right) */ element = EL_DC_STEELWALL_1_RIGHT; break; case 0x1699: /* steel wall (top) */ element = EL_DC_STEELWALL_1_TOP; break; case 0x169a: /* steel wall (left/bottom) */ element = EL_DC_STEELWALL_1_BOTTOMLEFT; break; case 0x169b: /* steel wall (right/bottom) */ element = EL_DC_STEELWALL_1_BOTTOMRIGHT; break; case 0x169c: /* steel wall (right/top) */ element = EL_DC_STEELWALL_1_TOPRIGHT; break; case 0x169d: /* steel wall (left/top) */ element = EL_DC_STEELWALL_1_TOPLEFT; break; case 0x169e: /* steel wall (right/bottom small) */ element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2; break; case 0x169f: /* steel wall (left/bottom small) */ element = EL_DC_STEELWALL_1_BOTTOMLEFT_2; break; case 0x16a0: /* steel wall (right/top small) */ element = EL_DC_STEELWALL_1_TOPRIGHT_2; break; case 0x16a1: /* steel wall (left/top small) */ element = EL_DC_STEELWALL_1_TOPLEFT_2; break; case 0x16a2: /* steel wall (left/right) */ element = EL_DC_STEELWALL_1_VERTICAL; break; case 0x16a3: /* steel wall (top/bottom) */ element = EL_DC_STEELWALL_1_HORIZONTAL; break; case 0x16a4: /* steel wall 2 (left end) */ element = EL_DC_STEELWALL_2_LEFT; break; case 0x16a5: /* steel wall 2 (right end) */ element = EL_DC_STEELWALL_2_RIGHT; break; case 0x16a6: /* steel wall 2 (top end) */ element = EL_DC_STEELWALL_2_TOP; break; case 0x16a7: /* steel wall 2 (bottom end) */ element = EL_DC_STEELWALL_2_BOTTOM; break; case 0x16a8: /* steel wall 2 (left/right) */ element = EL_DC_STEELWALL_2_HORIZONTAL; break; case 0x16a9: /* steel wall 2 (up/down) */ element = EL_DC_STEELWALL_2_VERTICAL; break; case 0x16aa: /* steel wall 2 (mid) */ element = EL_DC_STEELWALL_2_MIDDLE; break; case 0x16ab: element = EL_SIGN_EXCLAMATION; break; case 0x16ac: element = EL_SIGN_RADIOACTIVITY; break; case 0x16ad: element = EL_SIGN_STOP; break; case 0x16ae: element = EL_SIGN_WHEELCHAIR; break; case 0x16af: element = EL_SIGN_PARKING; break; case 0x16b0: element = EL_SIGN_NO_ENTRY; break; case 0x16b1: element = EL_SIGN_HEART; break; case 0x16b2: element = EL_SIGN_GIVE_WAY; break; case 0x16b3: element = EL_SIGN_ENTRY_FORBIDDEN; break; case 0x16b4: element = EL_SIGN_EMERGENCY_EXIT; break; case 0x16b5: element = EL_SIGN_YIN_YANG; break; case 0x16b6: element = EL_WALL_EMERALD; break; case 0x16b7: element = EL_WALL_DIAMOND; break; case 0x16b8: element = EL_WALL_PEARL; break; case 0x16b9: element = EL_WALL_CRYSTAL; break; case 0x16ba: element = EL_INVISIBLE_WALL; break; case 0x16bb: element = EL_INVISIBLE_STEELWALL; break; /* 0x16bc - 0x16cb: */ /* EL_INVISIBLE_SAND */ case 0x16cc: element = EL_LIGHT_SWITCH; break; case 0x16cd: element = EL_ENVELOPE_1; break; default: if (element >= 0x0117 && element <= 0x036e) /* (?) */ element = EL_DIAMOND; else if (element >= 0x042d && element <= 0x0684) /* (?) */ element = EL_EMERALD; else if (element >= 0x157c && element <= 0x158b) element = EL_SAND; else if (element >= 0x1590 && element <= 0x159f) element = EL_DC_LANDMINE; else if (element >= 0x16bc && element <= 0x16cb) element = EL_INVISIBLE_SAND; else { Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element); element = EL_UNKNOWN; } break; } return getMappedElement(element); } static void LoadLevelFromFileStream_DC(File *file, struct LevelInfo *level, int nr) { byte header[DC_LEVEL_HEADER_SIZE]; int envelope_size; int envelope_header_pos = 62; int envelope_content_pos = 94; int level_name_pos = 251; int level_author_pos = 292; int envelope_header_len; int envelope_content_len; int level_name_len; int level_author_len; int fieldx, fieldy; int num_yamyam_contents; int i, x, y; getDecodedWord_DC(0, TRUE); /* initialize DC2 decoding engine */ for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++) { unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE); header[i * 2 + 0] = header_word >> 8; header[i * 2 + 1] = header_word & 0xff; } /* read some values from level header to check level decoding integrity */ fieldx = header[6] | (header[7] << 8); fieldy = header[8] | (header[9] << 8); num_yamyam_contents = header[60] | (header[61] << 8); /* do some simple sanity checks to ensure that level was correctly decoded */ if (fieldx < 1 || fieldx > 256 || fieldy < 1 || fieldy > 256 || num_yamyam_contents < 1 || num_yamyam_contents > 8) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot decode level from stream -- using empty level"); return; } /* maximum envelope header size is 31 bytes */ envelope_header_len = header[envelope_header_pos]; /* maximum envelope content size is 110 (156?) bytes */ envelope_content_len = header[envelope_content_pos]; /* maximum level title size is 40 bytes */ level_name_len = MIN(header[level_name_pos], MAX_LEVEL_NAME_LEN); /* maximum level author size is 30 (51?) bytes */ level_author_len = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN); envelope_size = 0; for (i = 0; i < envelope_header_len; i++) if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = header[envelope_header_pos + 1 + i]; if (envelope_header_len > 0 && envelope_content_len > 0) { if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = '\n'; if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = '\n'; } for (i = 0; i < envelope_content_len; i++) if (envelope_size < MAX_ENVELOPE_TEXT_LEN) level->envelope[0].text[envelope_size++] = header[envelope_content_pos + 1 + i]; level->envelope[0].text[envelope_size] = '\0'; level->envelope[0].xsize = MAX_ENVELOPE_XSIZE; level->envelope[0].ysize = 10; level->envelope[0].autowrap = TRUE; level->envelope[0].centered = TRUE; for (i = 0; i < level_name_len; i++) level->name[i] = header[level_name_pos + 1 + i]; level->name[level_name_len] = '\0'; for (i = 0; i < level_author_len; i++) level->author[i] = header[level_author_pos + 1 + i]; level->author[level_author_len] = '\0'; num_yamyam_contents = header[60] | (header[61] << 8); level->num_yamyam_contents = MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS); for (i = 0; i < num_yamyam_contents; i++) { for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE); int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff); if (i < MAX_ELEMENT_CONTENTS) level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc); } } fieldx = header[6] | (header[7] << 8); fieldy = header[8] | (header[9] << 8); level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX); level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY); for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++) { unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE); int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff); if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY) level->field[x][y] = getMappedElement_DC(element_dc); } x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1); y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1); level->field[x][y] = EL_PLAYER_1; x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1); y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1); level->field[x][y] = EL_PLAYER_2; level->gems_needed = header[18] | (header[19] << 8); level->score[SC_EMERALD] = header[20] | (header[21] << 8); level->score[SC_DIAMOND] = header[22] | (header[23] << 8); level->score[SC_PEARL] = header[24] | (header[25] << 8); level->score[SC_CRYSTAL] = header[26] | (header[27] << 8); level->score[SC_NUT] = header[28] | (header[29] << 8); level->score[SC_ROBOT] = header[30] | (header[31] << 8); level->score[SC_SPACESHIP] = header[32] | (header[33] << 8); level->score[SC_BUG] = header[34] | (header[35] << 8); level->score[SC_YAMYAM] = header[36] | (header[37] << 8); level->score[SC_DYNAMITE] = header[38] | (header[39] << 8); level->score[SC_KEY] = header[40] | (header[41] << 8); level->score[SC_TIME_BONUS] = header[42] | (header[43] << 8); level->time = header[44] | (header[45] << 8); level->amoeba_speed = header[46] | (header[47] << 8); level->time_light = header[48] | (header[49] << 8); level->time_timegate = header[50] | (header[51] << 8); level->time_wheel = header[52] | (header[53] << 8); level->time_magic_wall = header[54] | (header[55] << 8); level->extra_time = header[56] | (header[57] << 8); level->shield_normal_time = header[58] | (header[59] << 8); /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems can slip down from flat walls, like normal walls and steel walls */ level->em_slippery_gems = TRUE; } static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { char *filename = level_file_info->filename; File *file; int num_magic_bytes = 8; char magic_bytes[num_magic_bytes + 1]; int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level; if (!(file = openFile(filename, MODE_READ))) { level->no_valid_file = TRUE; if (!level_info_only) Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } // fseek(file, 0x0000, SEEK_SET); if (level_file_info->packed) { /* read "magic bytes" from start of file */ if (getStringFromFile(file, magic_bytes, num_magic_bytes + 1) == NULL) magic_bytes[0] = '\0'; /* check "magic bytes" for correct file format */ if (!strPrefix(magic_bytes, "DC2")) { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown DC level file '%s' -- using empty level", filename); return; } if (strPrefix(magic_bytes, "DC2Win95") || strPrefix(magic_bytes, "DC2Win98")) { int position_first_level = 0x00fa; int extra_bytes = 4; int skip_bytes; /* advance file stream to first level inside the level package */ skip_bytes = position_first_level - num_magic_bytes - extra_bytes; /* each block of level data is followed by block of non-level data */ num_levels_to_skip *= 2; /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */ while (num_levels_to_skip >= 0) { /* advance file stream to next level inside the level package */ if (seekFile(file, skip_bytes, SEEK_CUR) != 0) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); return; } /* skip apparently unused extra bytes following each level */ ReadUnusedBytesFromFile(file, extra_bytes); /* read size of next level in level package */ skip_bytes = getFile32BitLE(file); num_levels_to_skip--; } } else { level->no_valid_file = TRUE; Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level", filename); return; } } LoadLevelFromFileStream_DC(file, level, level_file_info->nr); closeFile(file); } /* ------------------------------------------------------------------------- */ /* functions for loading SB level */ /* ------------------------------------------------------------------------- */ int getMappedElement_SB(int element_ascii, boolean use_ces) { static struct { int ascii; int sb; int ce; } sb_element_mapping[] = { { ' ', EL_EMPTY, EL_CUSTOM_1 }, /* floor (space) */ { '#', EL_STEELWALL, EL_CUSTOM_2 }, /* wall */ { '@', EL_PLAYER_1, EL_CUSTOM_3 }, /* player */ { '$', EL_SOKOBAN_OBJECT, EL_CUSTOM_4 }, /* box */ { '.', EL_SOKOBAN_FIELD_EMPTY, EL_CUSTOM_5 }, /* goal square */ { '*', EL_SOKOBAN_FIELD_FULL, EL_CUSTOM_6 }, /* box on goal square */ { '+', EL_SOKOBAN_FIELD_PLAYER, EL_CUSTOM_7 }, /* player on goal square */ { '_', EL_INVISIBLE_STEELWALL, EL_FROM_LEVEL_TEMPLATE }, /* floor beyond border */ { 0, -1, -1 }, }; int i; for (i = 0; sb_element_mapping[i].ascii != 0; i++) if (element_ascii == sb_element_mapping[i].ascii) return (use_ces ? sb_element_mapping[i].ce : sb_element_mapping[i].sb); return EL_UNDEFINED; } static void LoadLevelFromFileInfo_SB(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { char *filename = level_file_info->filename; char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; char last_comment[MAX_LINE_LEN]; char level_name[MAX_LINE_LEN]; char *line_ptr; File *file; int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level; boolean read_continued_line = FALSE; boolean reading_playfield = FALSE; boolean got_valid_playfield_line = FALSE; boolean invalid_playfield_char = FALSE; boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces"); int file_level_nr = 0; int line_nr = 0; int x = 0, y = 0; /* initialized to make compilers happy */ last_comment[0] = '\0'; level_name[0] = '\0'; if (!(file = openFile(filename, MODE_READ))) { level->no_valid_file = TRUE; if (!level_info_only) Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } while (!checkEndOfFile(file)) { /* level successfully read, but next level may follow here */ if (!got_valid_playfield_line && reading_playfield) { /* read playfield from single level file -- skip remaining file */ if (!level_file_info->packed) break; if (file_level_nr >= num_levels_to_skip) break; file_level_nr++; last_comment[0] = '\0'; level_name[0] = '\0'; reading_playfield = FALSE; } got_valid_playfield_line = FALSE; /* read next line of input file */ if (!getStringFromFile(file, line, MAX_LINE_LEN)) break; /* check if line was completely read and is terminated by line break */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line_nr++; /* cut trailing line break (this can be newline and/or carriage return) */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* copy raw input line for later use (mainly debugging output) */ strcpy(line_raw, line); if (read_continued_line) { /* append new line to existing line, if there is enough space */ if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN) strcat(previous_line, line_ptr); strcpy(line, previous_line); /* copy storage buffer to line */ read_continued_line = FALSE; } /* if the last character is '\', continue at next line */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') { line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */ strcpy(previous_line, line); /* copy line to storage buffer */ read_continued_line = TRUE; continue; } /* skip empty lines */ if (line[0] == '\0') continue; /* extract comment text from comment line */ if (line[0] == ';') { for (line_ptr = line; *line_ptr; line_ptr++) if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != ';') break; strcpy(last_comment, line_ptr); continue; } /* extract level title text from line containing level title */ if (line[0] == '\'') { strcpy(level_name, &line[1]); if (strlen(level_name) > 0 && level_name[strlen(level_name) - 1] == '\'') level_name[strlen(level_name) - 1] = '\0'; continue; } /* skip lines containing only spaces (or empty lines) */ for (line_ptr = line; *line_ptr; line_ptr++) if (*line_ptr != ' ') break; if (*line_ptr == '\0') continue; /* at this point, we have found a line containing part of a playfield */ got_valid_playfield_line = TRUE; if (!reading_playfield) { reading_playfield = TRUE; invalid_playfield_char = FALSE; for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) level->field[x][y] = getMappedElement_SB(' ', load_xsb_to_ces); level->fieldx = 0; level->fieldy = 0; /* start with topmost tile row */ y = 0; } /* skip playfield line if larger row than allowed */ if (y >= MAX_LEV_FIELDY) continue; /* start with leftmost tile column */ x = 0; /* read playfield elements from line */ for (line_ptr = line; *line_ptr; line_ptr++) { int mapped_sb_element = getMappedElement_SB(*line_ptr, load_xsb_to_ces); /* stop parsing playfield line if larger column than allowed */ if (x >= MAX_LEV_FIELDX) break; if (mapped_sb_element == EL_UNDEFINED) { invalid_playfield_char = TRUE; break; } level->field[x][y] = mapped_sb_element; /* continue with next tile column */ x++; level->fieldx = MAX(x, level->fieldx); } if (invalid_playfield_char) { /* if first playfield line, treat invalid lines as comment lines */ if (y == 0) reading_playfield = FALSE; continue; } /* continue with next tile row */ y++; } closeFile(file); level->fieldy = y; level->fieldx = MIN(MAX(MIN_LEV_FIELDX, level->fieldx), MAX_LEV_FIELDX); level->fieldy = MIN(MAX(MIN_LEV_FIELDY, level->fieldy), MAX_LEV_FIELDY); if (!reading_playfield) { level->no_valid_file = TRUE; Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } if (*level_name != '\0') { strncpy(level->name, level_name, MAX_LEVEL_NAME_LEN); level->name[MAX_LEVEL_NAME_LEN] = '\0'; } else if (*last_comment != '\0') { strncpy(level->name, last_comment, MAX_LEVEL_NAME_LEN); level->name[MAX_LEVEL_NAME_LEN] = '\0'; } else { sprintf(level->name, "--> Level %d <--", level_file_info->nr); } /* set all empty fields beyond the border walls to invisible steel wall */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) { if ((x == 0 || x == level->fieldx - 1 || y == 0 || y == level->fieldy - 1) && level->field[x][y] == getMappedElement_SB(' ', load_xsb_to_ces)) FloodFillLevel(x, y, getMappedElement_SB('_', load_xsb_to_ces), level->field, level->fieldx, level->fieldy); } /* set special level settings for Sokoban levels */ level->time = 0; level->use_step_counter = TRUE; if (load_xsb_to_ces) { /* special global settings can now be set in level template */ level->use_custom_template = TRUE; } } /* ------------------------------------------------------------------------- */ /* functions for handling native levels */ /* ------------------------------------------------------------------------- */ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { if (!LoadNativeLevel_EM(level_file_info->filename, level_info_only)) level->no_valid_file = TRUE; } static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { int pos = 0; /* determine position of requested level inside level package */ if (level_file_info->packed) pos = level_file_info->nr - leveldir_current->first_level; if (!LoadNativeLevel_SP(level_file_info->filename, pos, level_info_only)) level->no_valid_file = TRUE; } static void LoadLevelFromFileInfo_MM(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { if (!LoadNativeLevel_MM(level_file_info->filename, level_info_only)) level->no_valid_file = TRUE; } void CopyNativeLevel_RND_to_Native(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_EM) CopyNativeLevel_RND_to_EM(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_SP) CopyNativeLevel_RND_to_SP(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_MM) CopyNativeLevel_RND_to_MM(level); } void CopyNativeLevel_Native_to_RND(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_EM) CopyNativeLevel_EM_to_RND(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_SP) CopyNativeLevel_SP_to_RND(level); else if (level->game_engine_type == GAME_ENGINE_TYPE_MM) CopyNativeLevel_MM_to_RND(level); } void SaveNativeLevel(struct LevelInfo *level) { if (level->game_engine_type == GAME_ENGINE_TYPE_SP) { char *basename = getSingleLevelBasenameExt(level->file_info.nr, "sp"); char *filename = getLevelFilenameFromBasename(basename); CopyNativeLevel_RND_to_SP(level); CopyNativeTape_RND_to_SP(level); SaveNativeLevel_SP(filename); } } /* ------------------------------------------------------------------------- */ /* functions for loading generic level */ /* ------------------------------------------------------------------------- */ static void LoadLevelFromFileInfo(struct LevelInfo *level, struct LevelFileInfo *level_file_info, boolean level_info_only) { /* always start with reliable default values */ setLevelInfoToDefaults(level, level_info_only, TRUE); switch (level_file_info->type) { case LEVEL_FILE_TYPE_RND: LoadLevelFromFileInfo_RND(level, level_file_info, level_info_only); break; case LEVEL_FILE_TYPE_EM: LoadLevelFromFileInfo_EM(level, level_file_info, level_info_only); level->game_engine_type = GAME_ENGINE_TYPE_EM; break; case LEVEL_FILE_TYPE_SP: LoadLevelFromFileInfo_SP(level, level_file_info, level_info_only); level->game_engine_type = GAME_ENGINE_TYPE_SP; break; case LEVEL_FILE_TYPE_MM: LoadLevelFromFileInfo_MM(level, level_file_info, level_info_only); level->game_engine_type = GAME_ENGINE_TYPE_MM; break; case LEVEL_FILE_TYPE_DC: LoadLevelFromFileInfo_DC(level, level_file_info, level_info_only); break; case LEVEL_FILE_TYPE_SB: LoadLevelFromFileInfo_SB(level, level_file_info, level_info_only); break; default: LoadLevelFromFileInfo_RND(level, level_file_info, level_info_only); break; } /* if level file is invalid, restore level structure to default values */ if (level->no_valid_file) setLevelInfoToDefaults(level, level_info_only, FALSE); if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN) level->game_engine_type = GAME_ENGINE_TYPE_RND; if (level_file_info->type != LEVEL_FILE_TYPE_RND) CopyNativeLevel_Native_to_RND(level); } void LoadLevelFromFilename(struct LevelInfo *level, char *filename) { static struct LevelFileInfo level_file_info; /* always start with reliable default values */ setFileInfoToDefaults(&level_file_info); level_file_info.nr = 0; /* unknown level number */ level_file_info.type = LEVEL_FILE_TYPE_RND; /* no others supported yet */ level_file_info.filename = filename; LoadLevelFromFileInfo(level, &level_file_info, FALSE); } static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) { int i, j; if (leveldir_current == NULL) /* only when dumping level */ return; /* all engine modifications also valid for levels which use latest engine */ if (level->game_version < VERSION_IDENT(3,2,0,5)) { /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */ level->score[SC_TIME_BONUS] /= 10; } if (leveldir_current->latest_engine) { /* ---------- use latest game engine ----------------------------------- */ /* For all levels which are forced to use the latest game engine version (normally all but user contributed, private and undefined levels), set the game engine version to the actual version; this allows for actual corrections in the game engine to take effect for existing, converted levels (from "classic" or other existing games) to make the emulation of the corresponding game more accurate, while (hopefully) not breaking existing levels created from other players. */ level->game_version = GAME_VERSION_ACTUAL; /* Set special EM style gems behaviour: EM style gems slip down from normal, steel and growing wall. As this is a more fundamental change, it seems better to set the default behaviour to "off" (as it is more natural) and make it configurable in the level editor (as a property of gem style elements). Already existing converted levels (neither private nor contributed levels) are changed to the new behaviour. */ if (level->file_version < FILE_VERSION_2_0) level->em_slippery_gems = TRUE; return; } /* ---------- use game engine the level was created with ----------------- */ /* For all levels which are not forced to use the latest game engine version (normally user contributed, private and undefined levels), use the version of the game engine the levels were created for. Since 2.0.1, the game engine version is now directly stored in the level file (chunk "VERS"), so there is no need anymore to set the game version from the file version (except for old, pre-2.0 levels, where the game version is still taken from the file format version used to store the level -- see above). */ /* player was faster than enemies in 1.0.0 and before */ if (level->file_version == FILE_VERSION_1_0) for (i = 0; i < MAX_PLAYERS; i++) level->initial_player_stepsize[i] = STEPSIZE_FAST; /* default behaviour for EM style gems was "slippery" only in 2.0.1 */ if (level->game_version == VERSION_IDENT(2,0,1,0)) level->em_slippery_gems = TRUE; /* springs could be pushed over pits before (pre-release version) 2.2.0 */ if (level->game_version < VERSION_IDENT(2,2,0,0)) level->use_spring_bug = TRUE; if (level->game_version < VERSION_IDENT(3,2,0,5)) { /* time orb caused limited time in endless time levels before 3.2.0-5 */ level->use_time_orb_bug = TRUE; /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */ level->block_snap_field = FALSE; /* extra time score was same value as time left score before 3.2.0-5 */ level->extra_time_score = level->score[SC_TIME_BONUS]; } if (level->game_version < VERSION_IDENT(3,2,0,7)) { /* default behaviour for snapping was "not continuous" before 3.2.0-7 */ level->continuous_snapping = FALSE; } /* only few elements were able to actively move into acid before 3.1.0 */ /* trigger settings did not exist before 3.1.0; set to default "any" */ if (level->game_version < VERSION_IDENT(3,1,0,0)) { /* correct "can move into acid" settings (all zero in old levels) */ level->can_move_into_acid_bits = 0; /* nothing can move into acid */ level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */ setMoveIntoAcidProperty(level, EL_ROBOT, TRUE); setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE); setMoveIntoAcidProperty(level, EL_PENGUIN, TRUE); setMoveIntoAcidProperty(level, EL_BALLOON, TRUE); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE); /* correct trigger settings (stored as zero == "none" in old levels) */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; for (j = 0; j < ei->num_change_pages; j++) { struct ElementChangeInfo *change = &ei->change_page[j]; change->trigger_player = CH_PLAYER_ANY; change->trigger_page = CH_PAGE_ANY; } } } /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */ { int element = EL_CUSTOM_256; struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[0]; /* This is needed to fix a problem that was caused by a bugfix in function game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did not replace walkable elements, but instead just placed the player on it, without placing the Sokoban field under the player). Unfortunately, this breaks "Snake Bite" style levels when the snake is halfway through a door that just closes (the snake head is still alive and can be moved in this case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the player (without Sokoban element) which then gets killed as designed). */ if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 || strncmp(ei->description, "pause b4 death", 14) == 0) && change->target_element == EL_SOKOBAN_FIELD_PLAYER) change->target_element = EL_PLAYER_1; } /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */ if (level->game_version < VERSION_IDENT(3,2,5,0)) { /* This is needed to fix a problem that was caused by a bugfix in function game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that corrects the behaviour when a custom element changes to another custom element with a higher element number that has change actions defined. Normally, only one change per frame is allowed for custom elements. Therefore, it is checked if a custom element already changed in the current frame; if it did, subsequent changes are suppressed. Unfortunately, this is only checked for element changes, but not for change actions, which are still executed. As the function above loops through all custom elements from lower to higher, an element change resulting in a lower CE number won't be checked again, while a target element with a higher number will also be checked, and potential change actions will get executed for this CE, too (which is wrong), while further changes are ignored (which is correct). As this bugfix breaks Zelda II (and introduces graphical bugs to Zelda I, and also breaks a few other levels like Alan Bond's "FMV"), allow the previous, incorrect behaviour for existing levels and tapes that make use of this bug */ level->use_action_after_change_bug = TRUE; } /* not centering level after relocating player was default only in 3.2.3 */ if (level->game_version == VERSION_IDENT(3,2,3,0)) /* (no pre-releases) */ level->shifted_relocation = TRUE; /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */ if (level->game_version < VERSION_IDENT(3,2,6,0)) level->em_explodes_by_fire = TRUE; } static void LoadLevel_InitStandardElements(struct LevelInfo *level) { int i, x, y; /* map elements that have changed in newer versions */ level->amoeba_content = getMappedElementByVersion(level->amoeba_content, level->game_version); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (x = 0; x < 3; x++) for (y = 0; y < 3; y++) level->yamyam_content[i].e[x][y] = getMappedElementByVersion(level->yamyam_content[i].e[x][y], level->game_version); } static void LoadLevel_InitCustomElements(struct LevelInfo *level) { int i, j; /* map custom element change events that have changed in newer versions (these following values were accidentally changed in version 3.0.1) (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */ if (level->game_version <= VERSION_IDENT(3,0,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; /* order of checking and copying events to be mapped is important */ /* (do not change the start and end value -- they are constant) */ for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--) { if (HAS_CHANGE_EVENT(element, j - 2)) { SET_CHANGE_EVENT(element, j - 2, FALSE); SET_CHANGE_EVENT(element, j, TRUE); } } /* order of checking and copying events to be mapped is important */ /* (do not change the start and end value -- they are constant) */ for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--) { if (HAS_CHANGE_EVENT(element, j - 1)) { SET_CHANGE_EVENT(element, j - 1, FALSE); SET_CHANGE_EVENT(element, j, TRUE); } } } } /* initialize "can_change" field for old levels with only one change page */ if (level->game_version <= VERSION_IDENT(3,0,2,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (CAN_CHANGE(element)) element_info[element].change->can_change = TRUE; } } /* correct custom element values (for old levels without these options) */ if (level->game_version < VERSION_IDENT(3,1,1,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; if (ei->access_direction == MV_NO_DIRECTION) ei->access_direction = MV_ALL_DIRECTIONS; } } /* correct custom element values (fix invalid values for all versions) */ if (1) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; for (j = 0; j < ei->num_change_pages; j++) { struct ElementChangeInfo *change = &ei->change_page[j]; if (change->trigger_player == CH_PLAYER_NONE) change->trigger_player = CH_PLAYER_ANY; if (change->trigger_side == CH_SIDE_NONE) change->trigger_side = CH_SIDE_ANY; } } } /* initialize "can_explode" field for old levels which did not store this */ /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */ if (level->game_version <= VERSION_IDENT(3,1,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (EXPLODES_1X1_OLD(element)) element_info[element].explosion_type = EXPLODES_1X1; SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) || EXPLODES_SMASHED(element) || EXPLODES_IMPACT(element))); } } /* correct previously hard-coded move delay values for maze runner style */ if (level->game_version < VERSION_IDENT(3,1,1,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE) { /* previously hard-coded and therefore ignored */ element_info[element].move_delay_fixed = 9; element_info[element].move_delay_random = 0; } } } /* set some other uninitialized values of custom elements in older levels */ if (level->game_version < VERSION_IDENT(3,1,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; element_info[element].access_direction = MV_ALL_DIRECTIONS; element_info[element].explosion_delay = 17; element_info[element].ignition_delay = 8; } } } static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) { LoadLevel_InitStandardElements(level); if (level->file_has_custom_elements) LoadLevel_InitCustomElements(level); /* initialize element properties for level editor etc. */ InitElementPropertiesEngine(level->game_version); InitElementPropertiesGfxElement(); } static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) { int x, y; /* map elements that have changed in newer versions */ for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) level->field[x][y] = getMappedElementByVersion(level->field[x][y], level->game_version); /* clear unused playfield data (nicer if level gets resized in editor) */ for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) if (x >= level->fieldx || y >= level->fieldy) level->field[x][y] = EL_EMPTY; /* copy elements to runtime playfield array */ for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) Feld[x][y] = level->field[x][y]; /* initialize level size variables for faster access */ lev_fieldx = level->fieldx; lev_fieldy = level->fieldy; /* determine border element for this level */ if (level->file_info.type == LEVEL_FILE_TYPE_DC) BorderElement = EL_EMPTY; /* (in editor, SetBorderElement() is used) */ else SetBorderElement(); } static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename) { struct LevelFileInfo *level_file_info = &level->file_info; if (level_file_info->type == LEVEL_FILE_TYPE_RND) CopyNativeLevel_RND_to_Native(level); } void LoadLevelTemplate(int nr) { char *filename; setLevelFileInfo(&level_template.file_info, nr); filename = level_template.file_info.filename; LoadLevelFromFileInfo(&level_template, &level_template.file_info, FALSE); LoadLevel_InitVersion(&level_template, filename); LoadLevel_InitElements(&level_template, filename); ActivateLevelTemplate(); } void LoadLevel(int nr) { char *filename; setLevelFileInfo(&level.file_info, nr); filename = level.file_info.filename; LoadLevelFromFileInfo(&level, &level.file_info, FALSE); if (level.use_custom_template) LoadLevelTemplate(-1); LoadLevel_InitVersion(&level, filename); LoadLevel_InitElements(&level, filename); LoadLevel_InitPlayfield(&level, filename); LoadLevel_InitNativeEngines(&level, filename); } void LoadLevelInfoOnly(int nr) { setLevelFileInfo(&level.file_info, nr); LoadLevelFromFileInfo(&level, &level.file_info, TRUE); } static int SaveLevel_VERS(FILE *file, struct LevelInfo *level) { int chunk_size = 0; chunk_size += putFileVersion(file, level->file_version); chunk_size += putFileVersion(file, level->game_version); return chunk_size; } static int SaveLevel_DATE(FILE *file, struct LevelInfo *level) { int chunk_size = 0; chunk_size += putFile16BitBE(file, level->creation_date.year); chunk_size += putFile8Bit(file, level->creation_date.month); chunk_size += putFile8Bit(file, level->creation_date.day); return chunk_size; } #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level) { int i, x, y; putFile8Bit(file, level->fieldx); putFile8Bit(file, level->fieldy); putFile16BitBE(file, level->time); putFile16BitBE(file, level->gems_needed); for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) putFile8Bit(file, level->name[i]); for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) putFile8Bit(file, level->score[i]); for (i = 0; i < STD_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY : level->yamyam_content[i].e[x][y])); putFile8Bit(file, level->amoeba_speed); putFile8Bit(file, level->time_magic_wall); putFile8Bit(file, level->time_wheel); putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content)); putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0)); putFile8Bit(file, (level->initial_gravity ? 1 : 0)); putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0)); putFile8Bit(file, (level->em_slippery_gems ? 1 : 0)); putFile8Bit(file, (level->use_custom_template ? 1 : 0)); putFile8Bit(file, (level->block_last_field ? 1 : 0)); putFile8Bit(file, (level->sp_block_last_field ? 1 : 0)); putFile32BitBE(file, level->can_move_into_acid_bits); putFile8Bit(file, level->dont_collide_with_bits); putFile8Bit(file, (level->use_spring_bug ? 1 : 0)); putFile8Bit(file, (level->use_step_counter ? 1 : 0)); putFile8Bit(file, (level->instant_relocation ? 1 : 0)); putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0)); putFile8Bit(file, (level->grow_into_diggable ? 1 : 0)); putFile8Bit(file, level->game_engine_type); WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED); } #endif static int SaveLevel_NAME(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) chunk_size += putFile8Bit(file, level->name[i]); return chunk_size; } static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) chunk_size += putFile8Bit(file, level->author[i]); return chunk_size; } #if ENABLE_HISTORIC_CHUNKS static int SaveLevel_BODY(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int x, y; for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) if (level->encoding_16bit_field) chunk_size += putFile16BitBE(file, level->field[x][y]); else chunk_size += putFile8Bit(file, level->field[x][y]); return chunk_size; } #endif static int SaveLevel_BODY(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int x, y; for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) chunk_size += putFile16BitBE(file, level->field[x][y]); return chunk_size; } #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_CONT(FILE *file, struct LevelInfo *level) { int i, x, y; putFile8Bit(file, EL_YAMYAM); putFile8Bit(file, level->num_yamyam_contents); putFile8Bit(file, 0); putFile8Bit(file, 0); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (level->encoding_16bit_field) putFile16BitBE(file, level->yamyam_content[i].e[x][y]); else putFile8Bit(file, level->yamyam_content[i].e[x][y]); } #endif #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) { int i, x, y; int num_contents, content_xsize, content_ysize; int content_array[MAX_ELEMENT_CONTENTS][3][3]; if (element == EL_YAMYAM) { num_contents = level->num_yamyam_contents; content_xsize = 3; content_ysize = 3; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_array[i][x][y] = level->yamyam_content[i].e[x][y]; } else if (element == EL_BD_AMOEBA) { num_contents = 1; content_xsize = 1; content_ysize = 1; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) content_array[i][x][y] = EL_EMPTY; content_array[0][0][0] = level->amoeba_content; } else { /* chunk header already written -- write empty chunk data */ WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE); Error(ERR_WARN, "cannot save content for element '%d'", element); return; } putFile16BitBE(file, element); putFile8Bit(file, num_contents); putFile8Bit(file, content_xsize); putFile8Bit(file, content_ysize); WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, content_array[i][x][y]); } #endif #if ENABLE_HISTORIC_CHUNKS static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element) { int envelope_nr = element - EL_ENVELOPE_1; int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1; int chunk_size = 0; int i; chunk_size += putFile16BitBE(file, element); chunk_size += putFile16BitBE(file, envelope_len); chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]); chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]); WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED); chunk_size += LEVEL_CHUNK_CNT3_UNUSED; for (i = 0; i < envelope_len; i++) chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]); return chunk_size; } #endif #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { int i, check = 0; putFile16BitBE(file, num_changed_custom_elements); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]); } check++; } } if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom element properties"); } #endif #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { int i, check = 0; putFile16BitBE(file, num_changed_custom_elements); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; if (element_info[element].change->target_element != EL_EMPTY_SPACE) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); putFile16BitBE(file, element_info[element].change->target_element); } check++; } } if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom target elements"); } #endif #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { int i, j, x, y, check = 0; putFile16BitBE(file, num_changed_custom_elements); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; struct ElementInfo *ei = &element_info[element]; if (ei->modified_settings) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++) putFile8Bit(file, ei->description[j]); putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]); /* some free bytes for future properties and padding */ WriteUnusedBytesToFile(file, 7); putFile8Bit(file, ei->use_gfx_element); putFile16BitBE(file, ei->gfx_element_initial); putFile8Bit(file, ei->collect_score_initial); putFile8Bit(file, ei->collect_count_initial); putFile16BitBE(file, ei->push_delay_fixed); putFile16BitBE(file, ei->push_delay_random); putFile16BitBE(file, ei->move_delay_fixed); putFile16BitBE(file, ei->move_delay_random); putFile16BitBE(file, ei->move_pattern); putFile8Bit(file, ei->move_direction_initial); putFile8Bit(file, ei->move_stepsize); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, ei->content.e[x][y]); putFile32BitBE(file, ei->change->events); putFile16BitBE(file, ei->change->target_element); putFile16BitBE(file, ei->change->delay_fixed); putFile16BitBE(file, ei->change->delay_random); putFile16BitBE(file, ei->change->delay_frames); putFile16BitBE(file, ei->change->initial_trigger_element); putFile8Bit(file, ei->change->explode); putFile8Bit(file, ei->change->use_target_content); putFile8Bit(file, ei->change->only_if_complete); putFile8Bit(file, ei->change->use_random_replace); putFile8Bit(file, ei->change->random_percentage); putFile8Bit(file, ei->change->replace_when); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, ei->change->content.e[x][y]); putFile8Bit(file, ei->slippery_type); /* some free bytes for future properties and padding */ WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED); } check++; } } if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom element properties"); } #endif #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; int i, j, x, y; /* ---------- custom element base property values (96 bytes) ------------- */ putFile16BitBE(file, element); for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) putFile8Bit(file, ei->description[i]); putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]); WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */ putFile8Bit(file, ei->num_change_pages); putFile16BitBE(file, ei->ce_value_fixed_initial); putFile16BitBE(file, ei->ce_value_random_initial); putFile8Bit(file, ei->use_last_ce_value); putFile8Bit(file, ei->use_gfx_element); putFile16BitBE(file, ei->gfx_element_initial); putFile8Bit(file, ei->collect_score_initial); putFile8Bit(file, ei->collect_count_initial); putFile8Bit(file, ei->drop_delay_fixed); putFile8Bit(file, ei->push_delay_fixed); putFile8Bit(file, ei->drop_delay_random); putFile8Bit(file, ei->push_delay_random); putFile16BitBE(file, ei->move_delay_fixed); putFile16BitBE(file, ei->move_delay_random); /* bits 0 - 15 of "move_pattern" ... */ putFile16BitBE(file, ei->move_pattern & 0xffff); putFile8Bit(file, ei->move_direction_initial); putFile8Bit(file, ei->move_stepsize); putFile8Bit(file, ei->slippery_type); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, ei->content.e[x][y]); putFile16BitBE(file, ei->move_enter_element); putFile16BitBE(file, ei->move_leave_element); putFile8Bit(file, ei->move_leave_type); /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */ putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff); putFile8Bit(file, ei->access_direction); putFile8Bit(file, ei->explosion_delay); putFile8Bit(file, ei->ignition_delay); putFile8Bit(file, ei->explosion_type); /* some free bytes for future custom property values and padding */ WriteUnusedBytesToFile(file, 1); /* ---------- change page property values (48 bytes) --------------------- */ for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; unsigned int event_bits; /* bits 0 - 31 of "has_event[]" ... */ event_bits = 0; for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (change->has_event[j]) event_bits |= (1 << j); putFile32BitBE(file, event_bits); putFile16BitBE(file, change->target_element); putFile16BitBE(file, change->delay_fixed); putFile16BitBE(file, change->delay_random); putFile16BitBE(file, change->delay_frames); putFile16BitBE(file, change->initial_trigger_element); putFile8Bit(file, change->explode); putFile8Bit(file, change->use_target_content); putFile8Bit(file, change->only_if_complete); putFile8Bit(file, change->use_random_replace); putFile8Bit(file, change->random_percentage); putFile8Bit(file, change->replace_when); for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) putFile16BitBE(file, change->target_content.e[x][y]); putFile8Bit(file, change->can_change); putFile8Bit(file, change->trigger_side); putFile8Bit(file, change->trigger_player); putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE : log_2(change->trigger_page))); putFile8Bit(file, change->has_action); putFile8Bit(file, change->action_type); putFile8Bit(file, change->action_mode); putFile16BitBE(file, change->action_arg); /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */ event_bits = 0; for (j = 32; j < NUM_CHANGE_EVENTS; j++) if (change->has_event[j]) event_bits |= (1 << (j - 32)); putFile8Bit(file, event_bits); } } #endif #if ENABLE_HISTORIC_CHUNKS static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; int i; putFile16BitBE(file, element); for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) putFile8Bit(file, ei->description[i]); putFile8Bit(file, group->num_elements); putFile8Bit(file, ei->use_gfx_element); putFile16BitBE(file, ei->gfx_element_initial); putFile8Bit(file, group->choice_mode); /* some free bytes for future values and padding */ WriteUnusedBytesToFile(file, 3); for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++) putFile16BitBE(file, group->element[i]); } #endif static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry, boolean write_element) { int save_type = entry->save_type; int data_type = entry->data_type; int conf_type = entry->conf_type; int byte_mask = conf_type & CONF_MASK_BYTES; int element = entry->element; int default_value = entry->default_value; int num_bytes = 0; boolean modified = FALSE; if (byte_mask != CONF_MASK_MULTI_BYTES) { void *value_ptr = entry->value; int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr : *(int *)value_ptr); /* check if any settings have been modified before saving them */ if (value != default_value) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit (file, value) : byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) : byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) : 0); } else if (data_type == TYPE_STRING) { char *default_string = entry->default_string; char *string = (char *)(entry->value); int string_length = strlen(string); int i; /* check if any settings have been modified before saving them */ if (!strEqual(string, default_string)) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += putFile16BitBE(file, string_length); for (i = 0; i < string_length; i++) num_bytes += putFile8Bit(file, string[i]); } else if (data_type == TYPE_ELEMENT_LIST) { int *element_array = (int *)(entry->value); int num_elements = *(int *)(entry->num_entities); int i; /* check if any settings have been modified before saving them */ for (i = 0; i < num_elements; i++) if (element_array[i] != default_value) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES); for (i = 0; i < num_elements; i++) num_bytes += putFile16BitBE(file, element_array[i]); } else if (data_type == TYPE_CONTENT_LIST) { struct Content *content = (struct Content *)(entry->value); int num_contents = *(int *)(entry->num_entities); int i, x, y; /* check if any settings have been modified before saving them */ for (i = 0; i < num_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (content[i].e[x][y] != default_value) modified = TRUE; /* do not save if explicitly told or if unmodified default settings */ if ((save_type == SAVE_CONF_NEVER) || (save_type == SAVE_CONF_WHEN_CHANGED && !modified)) return 0; if (write_element) num_bytes += putFile16BitBE(file, element); num_bytes += putFile8Bit(file, conf_type); num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES); for (i = 0; i < num_contents; i++) for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) num_bytes += putFile16BitBE(file, content[i].e[x][y]); } return num_bytes; } static int SaveLevel_INFO(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; li = *level; /* copy level data into temporary buffer */ for (i = 0; chunk_config_INFO[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE); return chunk_size; } static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level) { int chunk_size = 0; int i; li = *level; /* copy level data into temporary buffer */ for (i = 0; chunk_config_ELEM[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE); return chunk_size; } static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element) { int envelope_nr = element - EL_ENVELOPE_1; int chunk_size = 0; int i; chunk_size += putFile16BitBE(file, element); /* copy envelope data into temporary buffer */ xx_envelope = level->envelope[envelope_nr]; for (i = 0; chunk_config_NOTE[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE); return chunk_size; } static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; int chunk_size = 0; int i, j; chunk_size += putFile16BitBE(file, element); xx_ei = *ei; /* copy element data into temporary buffer */ /* set default description string for this specific element */ strcpy(xx_default_description, getDefaultElementDescription(ei)); for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE); for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; xx_current_change_page = i; xx_change = *change; /* copy change data into temporary buffer */ resetEventBits(); setEventBitsFromEventFlags(change); for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j], FALSE); } return chunk_size; } static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element) { struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; int chunk_size = 0; int i; chunk_size += putFile16BitBE(file, element); xx_ei = *ei; /* copy element data into temporary buffer */ xx_group = *group; /* copy group data into temporary buffer */ /* set default description string for this specific element */ strcpy(xx_default_description, getDefaultElementDescription(ei)); for (i = 0; chunk_config_GRPX[i].data_type != -1; i++) chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE); return chunk_size; } static void SaveLevelFromFilename(struct LevelInfo *level, char *filename, boolean save_as_template) { int chunk_size; int i; FILE *file; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save level file '%s'", filename); return; } level->file_version = FILE_VERSION_ACTUAL; level->game_version = GAME_VERSION_ACTUAL; level->creation_date = getCurrentDate(); putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED); putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE); chunk_size = SaveLevel_VERS(NULL, level); putFileChunkBE(file, "VERS", chunk_size); SaveLevel_VERS(file, level); chunk_size = SaveLevel_DATE(NULL, level); putFileChunkBE(file, "DATE", chunk_size); SaveLevel_DATE(file, level); chunk_size = SaveLevel_NAME(NULL, level); putFileChunkBE(file, "NAME", chunk_size); SaveLevel_NAME(file, level); chunk_size = SaveLevel_AUTH(NULL, level); putFileChunkBE(file, "AUTH", chunk_size); SaveLevel_AUTH(file, level); chunk_size = SaveLevel_INFO(NULL, level); putFileChunkBE(file, "INFO", chunk_size); SaveLevel_INFO(file, level); chunk_size = SaveLevel_BODY(NULL, level); putFileChunkBE(file, "BODY", chunk_size); SaveLevel_BODY(file, level); chunk_size = SaveLevel_ELEM(NULL, level); if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "ELEM", chunk_size); SaveLevel_ELEM(file, level); } for (i = 0; i < NUM_ENVELOPES; i++) { int element = EL_ENVELOPE_1 + i; chunk_size = SaveLevel_NOTE(NULL, level, element); if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "NOTE", chunk_size); SaveLevel_NOTE(file, level, element); } } /* if not using template level, check for non-default custom/group elements */ if (!level->use_custom_template || save_as_template) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; chunk_size = SaveLevel_CUSX(NULL, level, element); if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "CUSX", chunk_size); SaveLevel_CUSX(file, level, element); } } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int element = EL_GROUP_START + i; chunk_size = SaveLevel_GRPX(NULL, level, element); if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED) /* save if changed */ { putFileChunkBE(file, "GRPX", chunk_size); SaveLevel_GRPX(file, level, element); } } } fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); } void SaveLevel(int nr) { char *filename = getDefaultLevelFilename(nr); SaveLevelFromFilename(&level, filename, FALSE); } void SaveLevelTemplate() { char *filename = getLocalLevelTemplateFilename(); SaveLevelFromFilename(&level, filename, TRUE); } boolean SaveLevelChecked(int nr) { char *filename = getDefaultLevelFilename(nr); boolean new_level = !fileExists(filename); boolean level_saved = FALSE; if (new_level || Request("Save this level and kill the old?", REQ_ASK)) { SaveLevel(nr); if (new_level) Request("Level saved!", REQ_CONFIRM); level_saved = TRUE; } return level_saved; } void DumpLevel(struct LevelInfo *level) { if (level->no_level_file || level->no_valid_file) { Error(ERR_WARN, "cannot dump -- no valid level file found"); return; } PrintLine("-", 79); Print("Level xxx (file version %08d, game version %08d)\n", level->file_version, level->game_version); PrintLine("-", 79); Print("Level author: '%s'\n", level->author); Print("Level title: '%s'\n", level->name); Print("\n"); Print("Playfield size: %d x %d\n", level->fieldx, level->fieldy); Print("\n"); Print("Level time: %d seconds\n", level->time); Print("Gems needed: %d\n", level->gems_needed); Print("\n"); Print("Time for magic wall: %d seconds\n", level->time_magic_wall); Print("Time for wheel: %d seconds\n", level->time_wheel); Print("Time for light: %d seconds\n", level->time_light); Print("Time for timegate: %d seconds\n", level->time_timegate); Print("\n"); Print("Amoeba speed: %d\n", level->amoeba_speed); Print("\n"); Print("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no")); Print("Player blocks last field: %s\n", (level->block_last_field ? "yes" : "no")); Print("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no")); Print("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no")); Print("use step counter: %s\n", (level->use_step_counter ? "yes" : "no")); PrintLine("-", 79); } /* ========================================================================= */ /* tape file functions */ /* ========================================================================= */ static void setTapeInfoToDefaults() { int i; /* always start with reliable default values (empty tape) */ TapeErase(); /* default values (also for pre-1.2 tapes) with only the first player */ tape.player_participates[0] = TRUE; for (i = 1; i < MAX_PLAYERS; i++) tape.player_participates[i] = FALSE; /* at least one (default: the first) player participates in every tape */ tape.num_participating_players = 1; tape.level_nr = level_nr; tape.counter = 0; tape.changed = FALSE; tape.recording = FALSE; tape.playing = FALSE; tape.pausing = FALSE; tape.no_valid_file = FALSE; } static int LoadTape_VERS(File *file, int chunk_size, struct TapeInfo *tape) { tape->file_version = getFileVersion(file); tape->game_version = getFileVersion(file); return chunk_size; } static int LoadTape_HEAD(File *file, int chunk_size, struct TapeInfo *tape) { int i; tape->random_seed = getFile32BitBE(file); tape->date = getFile32BitBE(file); tape->length = getFile32BitBE(file); /* read header fields that are new since version 1.2 */ if (tape->file_version >= FILE_VERSION_1_2) { byte store_participating_players = getFile8Bit(file); int engine_version; /* since version 1.2, tapes store which players participate in the tape */ tape->num_participating_players = 0; for (i = 0; i < MAX_PLAYERS; i++) { tape->player_participates[i] = FALSE; if (store_participating_players & (1 << i)) { tape->player_participates[i] = TRUE; tape->num_participating_players++; } } tape->use_mouse = (getFile8Bit(file) == 1 ? TRUE : FALSE); ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED); engine_version = getFileVersion(file); if (engine_version > 0) tape->engine_version = engine_version; else tape->engine_version = tape->game_version; } return chunk_size; } static int LoadTape_INFO(File *file, int chunk_size, struct TapeInfo *tape) { int level_identifier_size; int i; level_identifier_size = getFile16BitBE(file); tape->level_identifier = checked_realloc(tape->level_identifier, level_identifier_size); for (i = 0; i < level_identifier_size; i++) tape->level_identifier[i] = getFile8Bit(file); tape->level_nr = getFile16BitBE(file); chunk_size = 2 + level_identifier_size + 2; return chunk_size; } static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape) { int i, j; int tape_pos_size = (tape->use_mouse ? 3 : tape->num_participating_players) + 1; int chunk_size_expected = tape_pos_size * tape->length; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPE_LEN) { Error(ERR_WARN, "tape truncated -- size exceeds maximum tape size %d", MAX_TAPE_LEN); // tape too large; read and ignore remaining tape data from this chunk for (;i < tape->length; i++) ReadUnusedBytesFromFile(file, tape->num_participating_players + 1); break; } if (tape->use_mouse) { tape->pos[i].action[TAPE_ACTION_LX] = getFile8Bit(file); tape->pos[i].action[TAPE_ACTION_LY] = getFile8Bit(file); tape->pos[i].action[TAPE_ACTION_BUTTON] = getFile8Bit(file); tape->pos[i].action[TAPE_ACTION_UNUSED] = 0; } else { for (j = 0; j < MAX_PLAYERS; j++) { tape->pos[i].action[j] = MV_NONE; if (tape->player_participates[j]) tape->pos[i].action[j] = getFile8Bit(file); } } tape->pos[i].delay = getFile8Bit(file); if (tape->file_version == FILE_VERSION_1_0) { /* eliminate possible diagonal moves in old tapes */ /* this is only for backward compatibility */ byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN }; byte action = tape->pos[i].action[0]; int k, num_moves = 0; for (k = 0; k<4; k++) { if (action & joy_dir[k]) { tape->pos[i + num_moves].action[0] = joy_dir[k]; if (num_moves > 0) tape->pos[i + num_moves].delay = 0; num_moves++; } } if (num_moves > 1) { num_moves--; i += num_moves; tape->length += num_moves; } } else if (tape->file_version < FILE_VERSION_2_0) { /* convert pre-2.0 tapes to new tape format */ if (tape->pos[i].delay > 1) { /* action part */ tape->pos[i + 1] = tape->pos[i]; tape->pos[i + 1].delay = 1; /* delay part */ for (j = 0; j < MAX_PLAYERS; j++) tape->pos[i].action[j] = MV_NONE; tape->pos[i].delay--; i++; tape->length++; } } if (checkEndOfFile(file)) break; } if (i != tape->length) chunk_size = tape_pos_size * i; return chunk_size; } void LoadTape_SokobanSolution(char *filename) { File *file; int move_delay = TILESIZE / level.initial_player_stepsize[0]; if (!(file = openFile(filename, MODE_READ))) { tape.no_valid_file = TRUE; return; } while (!checkEndOfFile(file)) { unsigned char c = getByteFromFile(file); if (checkEndOfFile(file)) break; switch (c) { case 'u': case 'U': tape.pos[tape.length].action[0] = MV_UP; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case 'd': case 'D': tape.pos[tape.length].action[0] = MV_DOWN; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case 'l': case 'L': tape.pos[tape.length].action[0] = MV_LEFT; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case 'r': case 'R': tape.pos[tape.length].action[0] = MV_RIGHT; tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); tape.length++; break; case '\n': case '\r': case '\t': case ' ': /* ignore white-space characters */ break; default: tape.no_valid_file = TRUE; Error(ERR_WARN, "unsupported Sokoban solution file '%s' ['%d']", filename, c); break; } } closeFile(file); if (tape.no_valid_file) return; tape.length_frames = GetTapeLengthFrames(); tape.length_seconds = GetTapeLengthSeconds(); } void LoadTapeFromFilename(char *filename) { char cookie[MAX_LINE_LEN]; char chunk_name[CHUNK_ID_LEN + 1]; File *file; int chunk_size; /* always start with reliable default values */ setTapeInfoToDefaults(); if (strSuffix(filename, ".sln")) { LoadTape_SokobanSolution(filename); return; } if (!(file = openFile(filename, MODE_READ))) { tape.no_valid_file = TRUE; return; } getFileChunkBE(file, chunk_name, NULL); if (strEqual(chunk_name, "RND1")) { getFile32BitBE(file); /* not used */ getFileChunkBE(file, chunk_name, NULL); if (!strEqual(chunk_name, "TAPE")) { tape.no_valid_file = TRUE; Error(ERR_WARN, "unknown format of tape file '%s'", filename); closeFile(file); return; } } else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); if (getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4) == NULL) cookie[4] = '\0'; if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, TAPE_COOKIE_TMPL)) { tape.no_valid_file = TRUE; Error(ERR_WARN, "unknown format of tape file '%s'", filename); closeFile(file); return; } if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1) { tape.no_valid_file = TRUE; Error(ERR_WARN, "unsupported version of tape file '%s'", filename); closeFile(file); return; } /* pre-2.0 tape files have no game version, so use file version here */ tape.game_version = tape.file_version; } if (tape.file_version < FILE_VERSION_1_2) { /* tape files from versions before 1.2.0 without chunk structure */ LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape); LoadTape_BODY(file, 2 * tape.length, &tape); } else { static struct { char *name; int size; int (*loader)(File *, int, struct TapeInfo *); } chunk_info[] = { { "VERS", TAPE_CHUNK_VERS_SIZE, LoadTape_VERS }, { "HEAD", TAPE_CHUNK_HEAD_SIZE, LoadTape_HEAD }, { "INFO", -1, LoadTape_INFO }, { "BODY", -1, LoadTape_BODY }, { NULL, 0, NULL } }; while (getFileChunkBE(file, chunk_name, &chunk_size)) { int i = 0; while (chunk_info[i].name != NULL && !strEqual(chunk_name, chunk_info[i].name)) i++; if (chunk_info[i].name == NULL) { Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'", chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else if (chunk_info[i].size != -1 && chunk_info[i].size != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'", chunk_size, chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else { /* call function to load this tape chunk */ int chunk_size_expected = (chunk_info[i].loader)(file, chunk_size, &tape); /* the size of some chunks cannot be checked before reading other chunks first (like "HEAD" and "BODY") that contain some header information, so check them here */ if (chunk_size_expected != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'", chunk_size, chunk_name, filename); } } } } closeFile(file); tape.length_frames = GetTapeLengthFrames(); tape.length_seconds = GetTapeLengthSeconds(); #if 0 printf("::: tape file version: %d\n", tape.file_version); printf("::: tape game version: %d\n", tape.game_version); printf("::: tape engine version: %d\n", tape.engine_version); #endif } void LoadTape(int nr) { char *filename = getTapeFilename(nr); LoadTapeFromFilename(filename); } void LoadSolutionTape(int nr) { char *filename = getSolutionTapeFilename(nr); LoadTapeFromFilename(filename); if (TAPE_IS_EMPTY(tape) && level.game_engine_type == GAME_ENGINE_TYPE_SP && level.native_sp_level->demo.is_available) CopyNativeTape_SP_to_RND(&level); } static void SaveTape_VERS(FILE *file, struct TapeInfo *tape) { putFileVersion(file, tape->file_version); putFileVersion(file, tape->game_version); } static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape) { int i; byte store_participating_players = 0; /* set bits for participating players for compact storage */ for (i = 0; i < MAX_PLAYERS; i++) if (tape->player_participates[i]) store_participating_players |= (1 << i); putFile32BitBE(file, tape->random_seed); putFile32BitBE(file, tape->date); putFile32BitBE(file, tape->length); putFile8Bit(file, store_participating_players); putFile8Bit(file, (tape->use_mouse ? 1 : 0)); /* unused bytes not at the end here for 4-byte alignment of engine_version */ WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED); putFileVersion(file, tape->engine_version); } static void SaveTape_INFO(FILE *file, struct TapeInfo *tape) { int level_identifier_size = strlen(tape->level_identifier) + 1; int i; putFile16BitBE(file, level_identifier_size); for (i = 0; i < level_identifier_size; i++) putFile8Bit(file, tape->level_identifier[i]); putFile16BitBE(file, tape->level_nr); } static void SaveTape_BODY(FILE *file, struct TapeInfo *tape) { int i, j; for (i = 0; i < tape->length; i++) { if (tape->use_mouse) { putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LX]); putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LY]); putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_BUTTON]); } else { for (j = 0; j < MAX_PLAYERS; j++) if (tape->player_participates[j]) putFile8Bit(file, tape->pos[i].action[j]); } putFile8Bit(file, tape->pos[i].delay); } } void SaveTape(int nr) { char *filename = getTapeFilename(nr); FILE *file; int num_participating_players = 0; int tape_pos_size; int info_chunk_size; int body_chunk_size; int i; InitTapeDirectory(leveldir_current->subdir); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save level recording file '%s'", filename); return; } tape.file_version = FILE_VERSION_ACTUAL; tape.game_version = GAME_VERSION_ACTUAL; /* count number of participating players */ for (i = 0; i < MAX_PLAYERS; i++) if (tape.player_participates[i]) num_participating_players++; tape_pos_size = (tape.use_mouse ? 3 : num_participating_players) + 1; info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2; body_chunk_size = tape_pos_size * tape.length; putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED); putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE); putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE); SaveTape_VERS(file, &tape); putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE); SaveTape_HEAD(file, &tape); putFileChunkBE(file, "INFO", info_chunk_size); SaveTape_INFO(file, &tape); putFileChunkBE(file, "BODY", body_chunk_size); SaveTape_BODY(file, &tape); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); tape.changed = FALSE; } static boolean SaveTapeCheckedExt(int nr, char *msg_replace, char *msg_saved) { char *filename = getTapeFilename(nr); boolean new_tape = !fileExists(filename); boolean tape_saved = FALSE; if (new_tape || Request(msg_replace, REQ_ASK)) { SaveTape(nr); if (new_tape) Request(msg_saved, REQ_CONFIRM); tape_saved = TRUE; } return tape_saved; } boolean SaveTapeChecked(int nr) { return SaveTapeCheckedExt(nr, "Replace old tape?", "Tape saved!"); } boolean SaveTapeChecked_LevelSolved(int nr) { return SaveTapeCheckedExt(nr, "Level solved! Replace old tape?", "Level solved! Tape saved!"); } void DumpTape(struct TapeInfo *tape) { int tape_frame_counter; int i, j; if (tape->no_valid_file) { Error(ERR_WARN, "cannot dump -- no valid tape file found"); return; } PrintLine("-", 79); Print("Tape of Level %03d (file version %08d, game version %08d)\n", tape->level_nr, tape->file_version, tape->game_version); Print(" (effective engine version %08d)\n", tape->engine_version); Print("Level series identifier: '%s'\n", tape->level_identifier); PrintLine("-", 79); tape_frame_counter = 0; for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPE_LEN) break; Print("%04d: ", i); for (j = 0; j < MAX_PLAYERS; j++) { if (tape->player_participates[j]) { int action = tape->pos[i].action[j]; Print("%d:%02x ", j, action); Print("[%c%c%c%c|%c%c] - ", (action & JOY_LEFT ? '<' : ' '), (action & JOY_RIGHT ? '>' : ' '), (action & JOY_UP ? '^' : ' '), (action & JOY_DOWN ? 'v' : ' '), (action & JOY_BUTTON_1 ? '1' : ' '), (action & JOY_BUTTON_2 ? '2' : ' ')); } } Print("(%03d) ", tape->pos[i].delay); Print("[%05d]\n", tape_frame_counter); tape_frame_counter += tape->pos[i].delay; } PrintLine("-", 79); } /* ========================================================================= */ /* score file functions */ /* ========================================================================= */ void LoadScore(int nr) { int i; char *filename = getScoreFilename(nr); char cookie[MAX_LINE_LEN]; char line[MAX_LINE_LEN]; char *line_ptr; FILE *file; /* always start with reliable default values */ for (i = 0; i < MAX_SCORE_ENTRIES; i++) { strcpy(highscore[i].Name, EMPTY_PLAYER_NAME); highscore[i].Score = 0; } if (!(file = fopen(filename, MODE_READ))) return; /* check file identifier */ if (fgets(cookie, MAX_LINE_LEN, file) == NULL) cookie[0] = '\0'; if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, SCORE_COOKIE)) { Error(ERR_WARN, "unknown format of score file '%s'", filename); fclose(file); return; } for (i = 0; i < MAX_SCORE_ENTRIES; i++) { if (fscanf(file, "%d", &highscore[i].Score) == EOF) Error(ERR_WARN, "fscanf() failed; %s", strerror(errno)); if (fgets(line, MAX_LINE_LEN, file) == NULL) line[0] = '\0'; if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0') { strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN); highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0'; break; } } } fclose(file); } void SaveScore(int nr) { int i; int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE); char *filename = getScoreFilename(nr); FILE *file; InitScoreDirectory(leveldir_current->subdir); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save score for level %d", nr); return; } fprintf(file, "%s\n\n", SCORE_COOKIE); for (i = 0; i < MAX_SCORE_ENTRIES; i++) fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name); fclose(file); SetFilePermissions(filename, permissions); } /* ========================================================================= */ /* setup file functions */ /* ========================================================================= */ #define TOKEN_STR_PLAYER_PREFIX "player_" /* global setup */ #define SETUP_TOKEN_PLAYER_NAME 0 #define SETUP_TOKEN_SOUND 1 #define SETUP_TOKEN_SOUND_LOOPS 2 #define SETUP_TOKEN_SOUND_MUSIC 3 #define SETUP_TOKEN_SOUND_SIMPLE 4 #define SETUP_TOKEN_TOONS 5 #define SETUP_TOKEN_SCROLL_DELAY 6 #define SETUP_TOKEN_SCROLL_DELAY_VALUE 7 #define SETUP_TOKEN_ENGINE_SNAPSHOT_MODE 8 #define SETUP_TOKEN_ENGINE_SNAPSHOT_MEMORY 9 #define SETUP_TOKEN_FADE_SCREENS 10 #define SETUP_TOKEN_AUTORECORD 11 #define SETUP_TOKEN_SHOW_TITLESCREEN 12 #define SETUP_TOKEN_QUICK_DOORS 13 #define SETUP_TOKEN_TEAM_MODE 14 #define SETUP_TOKEN_HANDICAP 15 #define SETUP_TOKEN_SKIP_LEVELS 16 #define SETUP_TOKEN_INCREMENT_LEVELS 17 #define SETUP_TOKEN_TIME_LIMIT 18 #define SETUP_TOKEN_FULLSCREEN 19 #define SETUP_TOKEN_WINDOW_SCALING_PERCENT 20 #define SETUP_TOKEN_WINDOW_SCALING_QUALITY 21 #define SETUP_TOKEN_SCREEN_RENDERING_MODE 22 #define SETUP_TOKEN_ASK_ON_ESCAPE 23 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 24 #define SETUP_TOKEN_QUICK_SWITCH 25 #define SETUP_TOKEN_INPUT_ON_FOCUS 26 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS 27 #define SETUP_TOKEN_GAME_FRAME_DELAY 28 #define SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS 29 #define SETUP_TOKEN_SMALL_GAME_GRAPHICS 30 #define SETUP_TOKEN_SHOW_SNAPSHOT_BUTTONS 31 #define SETUP_TOKEN_GRAPHICS_SET 32 #define SETUP_TOKEN_SOUNDS_SET 33 #define SETUP_TOKEN_MUSIC_SET 34 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 35 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 36 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 37 #define SETUP_TOKEN_VOLUME_SIMPLE 38 #define SETUP_TOKEN_VOLUME_LOOPS 39 #define SETUP_TOKEN_VOLUME_MUSIC 40 #define SETUP_TOKEN_TOUCH_CONTROL_TYPE 41 #define SETUP_TOKEN_TOUCH_MOVE_DISTANCE 42 #define SETUP_TOKEN_TOUCH_DROP_DISTANCE 43 #define NUM_GLOBAL_SETUP_TOKENS 44 /* auto setup */ #define SETUP_TOKEN_AUTO_EDITOR_ZOOM_TILESIZE 0 #define NUM_AUTO_SETUP_TOKENS 1 /* editor setup */ #define SETUP_TOKEN_EDITOR_EL_CLASSIC 0 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 1 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 2 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC 3 #define SETUP_TOKEN_EDITOR_EL_HEADLINES 4 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN 5 #define NUM_EDITOR_SETUP_TOKENS 6 /* editor cascade setup */ #define SETUP_TOKEN_EDITOR_CASCADE_BD 0 #define SETUP_TOKEN_EDITOR_CASCADE_EM 1 #define SETUP_TOKEN_EDITOR_CASCADE_EMC 2 #define SETUP_TOKEN_EDITOR_CASCADE_RND 3 #define SETUP_TOKEN_EDITOR_CASCADE_SB 4 #define SETUP_TOKEN_EDITOR_CASCADE_SP 5 #define SETUP_TOKEN_EDITOR_CASCADE_DC 6 #define SETUP_TOKEN_EDITOR_CASCADE_DX 7 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT 8 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT 9 #define SETUP_TOKEN_EDITOR_CASCADE_CE 10 #define SETUP_TOKEN_EDITOR_CASCADE_GE 11 #define SETUP_TOKEN_EDITOR_CASCADE_REF 12 #define SETUP_TOKEN_EDITOR_CASCADE_USER 13 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC 14 #define NUM_EDITOR_CASCADE_SETUP_TOKENS 15 /* shortcut setup */ #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1 3 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2 4 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3 5 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4 6 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL 7 #define SETUP_TOKEN_SHORTCUT_TAPE_EJECT 8 #define SETUP_TOKEN_SHORTCUT_TAPE_EXTRA 9 #define SETUP_TOKEN_SHORTCUT_TAPE_STOP 10 #define SETUP_TOKEN_SHORTCUT_TAPE_PAUSE 11 #define SETUP_TOKEN_SHORTCUT_TAPE_RECORD 12 #define SETUP_TOKEN_SHORTCUT_TAPE_PLAY 13 #define SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE 14 #define SETUP_TOKEN_SHORTCUT_SOUND_LOOPS 15 #define SETUP_TOKEN_SHORTCUT_SOUND_MUSIC 16 #define SETUP_TOKEN_SHORTCUT_SNAP_LEFT 17 #define SETUP_TOKEN_SHORTCUT_SNAP_RIGHT 18 #define SETUP_TOKEN_SHORTCUT_SNAP_UP 19 #define SETUP_TOKEN_SHORTCUT_SNAP_DOWN 20 #define NUM_SHORTCUT_SETUP_TOKENS 21 /* player setup */ #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8 #define SETUP_TOKEN_PLAYER_JOY_DROP 9 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11 #define SETUP_TOKEN_PLAYER_KEY_UP 12 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14 #define SETUP_TOKEN_PLAYER_KEY_DROP 15 #define NUM_PLAYER_SETUP_TOKENS 16 /* system setup */ #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER 0 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 1 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 2 #define NUM_SYSTEM_SETUP_TOKENS 3 /* internal setup */ #define SETUP_TOKEN_INT_PROGRAM_TITLE 0 #define SETUP_TOKEN_INT_PROGRAM_VERSION 1 #define SETUP_TOKEN_INT_PROGRAM_AUTHOR 2 #define SETUP_TOKEN_INT_PROGRAM_EMAIL 3 #define SETUP_TOKEN_INT_PROGRAM_WEBSITE 4 #define SETUP_TOKEN_INT_PROGRAM_COPYRIGHT 5 #define SETUP_TOKEN_INT_PROGRAM_COMPANY 6 #define SETUP_TOKEN_INT_PROGRAM_ICON_FILE 7 #define SETUP_TOKEN_INT_DEFAULT_GRAPHICS_SET 8 #define SETUP_TOKEN_INT_DEFAULT_SOUNDS_SET 9 #define SETUP_TOKEN_INT_DEFAULT_MUSIC_SET 10 #define SETUP_TOKEN_INT_FALLBACK_GRAPHICS_FILE 11 #define SETUP_TOKEN_INT_FALLBACK_SOUNDS_FILE 12 #define SETUP_TOKEN_INT_FALLBACK_MUSIC_FILE 13 #define SETUP_TOKEN_INT_DEFAULT_LEVEL_SERIES 14 #define SETUP_TOKEN_INT_CHOOSE_FROM_TOP_LEVELDIR 15 #define SETUP_TOKEN_INT_SHOW_SCALING_IN_TITLE 16 #define SETUP_TOKEN_INT_DEFAULT_WINDOW_WIDTH 17 #define SETUP_TOKEN_INT_DEFAULT_WINDOW_HEIGHT 18 #define NUM_INTERNAL_SETUP_TOKENS 19 /* debug setup */ #define SETUP_TOKEN_DEBUG_FRAME_DELAY_0 0 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_1 1 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_2 2 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_3 3 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_4 4 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_5 5 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_6 6 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_7 7 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_8 8 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_9 9 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_0 10 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_1 11 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_2 12 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_3 13 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_4 14 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_5 15 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_6 16 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_7 17 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_8 18 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_9 19 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_USE_MOD_KEY 20 #define SETUP_TOKEN_DEBUG_FRAME_DELAY_GAME_ONLY 21 #define SETUP_TOKEN_DEBUG_SHOW_FRAMES_PER_SECOND 22 #define NUM_DEBUG_SETUP_TOKENS 23 /* options setup */ #define SETUP_TOKEN_OPTIONS_VERBOSE 0 #define NUM_OPTIONS_SETUP_TOKENS 1 static struct SetupInfo si; static struct SetupAutoSetupInfo sasi; static struct SetupEditorInfo sei; static struct SetupEditorCascadeInfo seci; static struct SetupShortcutInfo ssi; static struct SetupInputInfo sii; static struct SetupSystemInfo syi; static struct SetupInternalInfo sxi; static struct SetupDebugInfo sdi; static struct OptionInfo soi; static struct TokenInfo global_setup_tokens[] = { { TYPE_STRING, &si.player_name, "player_name" }, { TYPE_SWITCH, &si.sound, "sound" }, { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" }, { TYPE_SWITCH, &si.sound_music, "background_music" }, { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" }, { TYPE_SWITCH, &si.toons, "toons" }, { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" }, { TYPE_INTEGER,&si.scroll_delay_value, "scroll_delay_value" }, { TYPE_STRING, &si.engine_snapshot_mode, "engine_snapshot_mode" }, { TYPE_INTEGER,&si.engine_snapshot_memory, "engine_snapshot_memory" }, { TYPE_SWITCH, &si.fade_screens, "fade_screens" }, { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording"}, { TYPE_SWITCH, &si.show_titlescreen, "show_titlescreen" }, { TYPE_SWITCH, &si.quick_doors, "quick_doors" }, { TYPE_SWITCH, &si.team_mode, "team_mode" }, { TYPE_SWITCH, &si.handicap, "handicap" }, { TYPE_SWITCH, &si.skip_levels, "skip_levels" }, { TYPE_SWITCH, &si.increment_levels, "increment_levels" }, { TYPE_SWITCH, &si.time_limit, "time_limit" }, { TYPE_SWITCH, &si.fullscreen, "fullscreen" }, { TYPE_INTEGER,&si.window_scaling_percent, "window_scaling_percent" }, { TYPE_STRING, &si.window_scaling_quality, "window_scaling_quality" }, { TYPE_STRING, &si.screen_rendering_mode, "screen_rendering_mode" }, { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" }, { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor" }, { TYPE_SWITCH, &si.quick_switch, "quick_player_switch" }, { TYPE_SWITCH, &si.input_on_focus, "input_on_focus" }, { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics" }, { TYPE_INTEGER,&si.game_frame_delay, "game_frame_delay" }, { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements" }, { TYPE_SWITCH, &si.small_game_graphics, "small_game_graphics" }, { TYPE_SWITCH, &si.show_snapshot_buttons, "show_snapshot_buttons" }, { TYPE_STRING, &si.graphics_set, "graphics_set" }, { TYPE_STRING, &si.sounds_set, "sounds_set" }, { TYPE_STRING, &si.music_set, "music_set" }, { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" }, { TYPE_SWITCH3,&si.override_level_sounds, "override_level_sounds" }, { TYPE_SWITCH3,&si.override_level_music, "override_level_music" }, { TYPE_INTEGER,&si.volume_simple, "volume_simple" }, { TYPE_INTEGER,&si.volume_loops, "volume_loops" }, { TYPE_INTEGER,&si.volume_music, "volume_music" }, { TYPE_STRING, &si.touch.control_type, "touch.control_type" }, { TYPE_INTEGER,&si.touch.move_distance, "touch.move_distance" }, { TYPE_INTEGER,&si.touch.drop_distance, "touch.drop_distance" }, }; static struct TokenInfo auto_setup_tokens[] = { { TYPE_INTEGER,&sasi.editor_zoom_tilesize, "editor.zoom_tilesize" }, }; static struct TokenInfo editor_setup_tokens[] = { { TYPE_SWITCH, &sei.el_classic, "editor.el_classic" }, { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" }, { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" }, { TYPE_SWITCH, &sei.el_dynamic, "editor.el_dynamic" }, { TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" }, { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token" }, }; static struct TokenInfo editor_cascade_setup_tokens[] = { { TYPE_SWITCH, &seci.el_bd, "editor.cascade.el_bd" }, { TYPE_SWITCH, &seci.el_em, "editor.cascade.el_em" }, { TYPE_SWITCH, &seci.el_emc, "editor.cascade.el_emc" }, { TYPE_SWITCH, &seci.el_rnd, "editor.cascade.el_rnd" }, { TYPE_SWITCH, &seci.el_sb, "editor.cascade.el_sb" }, { TYPE_SWITCH, &seci.el_sp, "editor.cascade.el_sp" }, { TYPE_SWITCH, &seci.el_dc, "editor.cascade.el_dc" }, { TYPE_SWITCH, &seci.el_dx, "editor.cascade.el_dx" }, { TYPE_SWITCH, &seci.el_mm, "editor.cascade.el_mm" }, { TYPE_SWITCH, &seci.el_df, "editor.cascade.el_df" }, { TYPE_SWITCH, &seci.el_chars, "editor.cascade.el_chars" }, { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" }, { TYPE_SWITCH, &seci.el_ce, "editor.cascade.el_ce" }, { TYPE_SWITCH, &seci.el_ge, "editor.cascade.el_ge" }, { TYPE_SWITCH, &seci.el_ref, "editor.cascade.el_ref" }, { TYPE_SWITCH, &seci.el_user, "editor.cascade.el_user" }, { TYPE_SWITCH, &seci.el_dynamic, "editor.cascade.el_dynamic" }, }; static struct TokenInfo shortcut_setup_tokens[] = { { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" }, { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" }, { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }, { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1" }, { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2" }, { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3" }, { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4" }, { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all" }, { TYPE_KEY_X11, &ssi.tape_eject, "shortcut.tape_eject" }, { TYPE_KEY_X11, &ssi.tape_extra, "shortcut.tape_extra" }, { TYPE_KEY_X11, &ssi.tape_stop, "shortcut.tape_stop" }, { TYPE_KEY_X11, &ssi.tape_pause, "shortcut.tape_pause" }, { TYPE_KEY_X11, &ssi.tape_record, "shortcut.tape_record" }, { TYPE_KEY_X11, &ssi.tape_play, "shortcut.tape_play" }, { TYPE_KEY_X11, &ssi.sound_simple, "shortcut.sound_simple" }, { TYPE_KEY_X11, &ssi.sound_loops, "shortcut.sound_loops" }, { TYPE_KEY_X11, &ssi.sound_music, "shortcut.sound_music" }, { TYPE_KEY_X11, &ssi.snap_left, "shortcut.snap_left" }, { TYPE_KEY_X11, &ssi.snap_right, "shortcut.snap_right" }, { TYPE_KEY_X11, &ssi.snap_up, "shortcut.snap_up" }, { TYPE_KEY_X11, &ssi.snap_down, "shortcut.snap_down" }, }; static struct TokenInfo player_setup_tokens[] = { { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" }, { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" }, { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" }, { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" }, { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" }, { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" }, { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" }, { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" }, { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" }, { TYPE_INTEGER, &sii.joy.drop, ".joy.place_bomb" }, { TYPE_KEY_X11, &sii.key.left, ".key.move_left" }, { TYPE_KEY_X11, &sii.key.right, ".key.move_right" }, { TYPE_KEY_X11, &sii.key.up, ".key.move_up" }, { TYPE_KEY_X11, &sii.key.down, ".key.move_down" }, { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" }, { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" }, }; static struct TokenInfo system_setup_tokens[] = { { TYPE_STRING, &syi.sdl_videodriver, "system.sdl_videodriver" }, { TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" }, { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }, }; static struct TokenInfo internal_setup_tokens[] = { { TYPE_STRING, &sxi.program_title, "program_title" }, { TYPE_STRING, &sxi.program_version, "program_version" }, { TYPE_STRING, &sxi.program_author, "program_author" }, { TYPE_STRING, &sxi.program_email, "program_email" }, { TYPE_STRING, &sxi.program_website, "program_website" }, { TYPE_STRING, &sxi.program_copyright, "program_copyright" }, { TYPE_STRING, &sxi.program_company, "program_company" }, { TYPE_STRING, &sxi.program_icon_file, "program_icon_file" }, { TYPE_STRING, &sxi.default_graphics_set, "default_graphics_set" }, { TYPE_STRING, &sxi.default_sounds_set, "default_sounds_set" }, { TYPE_STRING, &sxi.default_music_set, "default_music_set" }, { TYPE_STRING, &sxi.fallback_graphics_file, "fallback_graphics_file"}, { TYPE_STRING, &sxi.fallback_sounds_file, "fallback_sounds_file" }, { TYPE_STRING, &sxi.fallback_music_file, "fallback_music_file" }, { TYPE_STRING, &sxi.default_level_series, "default_level_series" }, { TYPE_BOOLEAN,&sxi.choose_from_top_leveldir, "choose_from_top_leveldir" }, { TYPE_BOOLEAN,&sxi.show_scaling_in_title, "show_scaling_in_title" }, { TYPE_INTEGER,&sxi.default_window_width, "default_window_width" }, { TYPE_INTEGER,&sxi.default_window_height, "default_window_height" }, }; static struct TokenInfo debug_setup_tokens[] = { { TYPE_INTEGER, &sdi.frame_delay[0], "debug.frame_delay_0" }, { TYPE_INTEGER, &sdi.frame_delay[1], "debug.frame_delay_1" }, { TYPE_INTEGER, &sdi.frame_delay[2], "debug.frame_delay_2" }, { TYPE_INTEGER, &sdi.frame_delay[3], "debug.frame_delay_3" }, { TYPE_INTEGER, &sdi.frame_delay[4], "debug.frame_delay_4" }, { TYPE_INTEGER, &sdi.frame_delay[5], "debug.frame_delay_5" }, { TYPE_INTEGER, &sdi.frame_delay[6], "debug.frame_delay_6" }, { TYPE_INTEGER, &sdi.frame_delay[7], "debug.frame_delay_7" }, { TYPE_INTEGER, &sdi.frame_delay[8], "debug.frame_delay_8" }, { TYPE_INTEGER, &sdi.frame_delay[9], "debug.frame_delay_9" }, { TYPE_KEY_X11, &sdi.frame_delay_key[0], "debug.key.frame_delay_0" }, { TYPE_KEY_X11, &sdi.frame_delay_key[1], "debug.key.frame_delay_1" }, { TYPE_KEY_X11, &sdi.frame_delay_key[2], "debug.key.frame_delay_2" }, { TYPE_KEY_X11, &sdi.frame_delay_key[3], "debug.key.frame_delay_3" }, { TYPE_KEY_X11, &sdi.frame_delay_key[4], "debug.key.frame_delay_4" }, { TYPE_KEY_X11, &sdi.frame_delay_key[5], "debug.key.frame_delay_5" }, { TYPE_KEY_X11, &sdi.frame_delay_key[6], "debug.key.frame_delay_6" }, { TYPE_KEY_X11, &sdi.frame_delay_key[7], "debug.key.frame_delay_7" }, { TYPE_KEY_X11, &sdi.frame_delay_key[8], "debug.key.frame_delay_8" }, { TYPE_KEY_X11, &sdi.frame_delay_key[9], "debug.key.frame_delay_9" }, { TYPE_BOOLEAN, &sdi.frame_delay_use_mod_key,"debug.frame_delay.use_mod_key"}, { TYPE_BOOLEAN, &sdi.frame_delay_game_only, "debug.frame_delay.game_only" }, { TYPE_BOOLEAN, &sdi.show_frames_per_second, "debug.show_frames_per_second" }, }; static struct TokenInfo options_setup_tokens[] = { { TYPE_BOOLEAN, &soi.verbose, "options.verbose" }, }; static char *get_corrected_login_name(char *login_name) { /* needed because player name must be a fixed length string */ char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1); strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN); login_name_new[MAX_PLAYER_NAME_LEN] = '\0'; if (strlen(login_name) > MAX_PLAYER_NAME_LEN) /* name has been cut */ if (strchr(login_name_new, ' ')) *strchr(login_name_new, ' ') = '\0'; return login_name_new; } static void setSetupInfoToDefaults(struct SetupInfo *si) { int i; si->player_name = get_corrected_login_name(getLoginName()); si->sound = TRUE; si->sound_loops = TRUE; si->sound_music = TRUE; si->sound_simple = TRUE; si->toons = TRUE; si->scroll_delay = TRUE; si->scroll_delay_value = STD_SCROLL_DELAY; si->engine_snapshot_mode = getStringCopy(STR_SNAPSHOT_MODE_DEFAULT); si->engine_snapshot_memory = SNAPSHOT_MEMORY_DEFAULT; si->fade_screens = TRUE; si->autorecord = TRUE; si->show_titlescreen = TRUE; si->quick_doors = FALSE; si->team_mode = FALSE; si->handicap = TRUE; si->skip_levels = TRUE; si->increment_levels = TRUE; si->time_limit = TRUE; si->fullscreen = FALSE; si->window_scaling_percent = STD_WINDOW_SCALING_PERCENT; si->window_scaling_quality = getStringCopy(SCALING_QUALITY_DEFAULT); si->screen_rendering_mode = getStringCopy(STR_SPECIAL_RENDERING_DEFAULT); si->ask_on_escape = TRUE; si->ask_on_escape_editor = TRUE; si->quick_switch = FALSE; si->input_on_focus = FALSE; si->prefer_aga_graphics = TRUE; si->game_frame_delay = GAME_FRAME_DELAY; si->sp_show_border_elements = FALSE; si->small_game_graphics = FALSE; si->show_snapshot_buttons = FALSE; si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR); si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR); si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR); si->override_level_graphics = FALSE; si->override_level_sounds = FALSE; si->override_level_music = FALSE; si->volume_simple = 100; /* percent */ si->volume_loops = 100; /* percent */ si->volume_music = 100; /* percent */ si->touch.control_type = getStringCopy(TOUCH_CONTROL_DEFAULT); si->touch.move_distance = TOUCH_MOVE_DISTANCE_DEFAULT; /* percent */ si->touch.drop_distance = TOUCH_DROP_DISTANCE_DEFAULT; /* percent */ si->editor.el_boulderdash = TRUE; si->editor.el_emerald_mine = TRUE; si->editor.el_emerald_mine_club = TRUE; si->editor.el_more = TRUE; si->editor.el_sokoban = TRUE; si->editor.el_supaplex = TRUE; si->editor.el_diamond_caves = TRUE; si->editor.el_dx_boulderdash = TRUE; si->editor.el_mirror_magic = TRUE; si->editor.el_deflektor = TRUE; si->editor.el_chars = TRUE; si->editor.el_steel_chars = TRUE; si->editor.el_classic = TRUE; si->editor.el_custom = TRUE; si->editor.el_user_defined = FALSE; si->editor.el_dynamic = TRUE; si->editor.el_headlines = TRUE; si->editor.show_element_token = FALSE; si->editor.use_template_for_new_levels = TRUE; si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME; si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME; si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE; si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1; si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2; si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3; si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4; si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL; si->shortcut.tape_eject = DEFAULT_KEY_TAPE_EJECT; si->shortcut.tape_extra = DEFAULT_KEY_TAPE_EXTRA; si->shortcut.tape_stop = DEFAULT_KEY_TAPE_STOP; si->shortcut.tape_pause = DEFAULT_KEY_TAPE_PAUSE; si->shortcut.tape_record = DEFAULT_KEY_TAPE_RECORD; si->shortcut.tape_play = DEFAULT_KEY_TAPE_PLAY; si->shortcut.sound_simple = DEFAULT_KEY_SOUND_SIMPLE; si->shortcut.sound_loops = DEFAULT_KEY_SOUND_LOOPS; si->shortcut.sound_music = DEFAULT_KEY_SOUND_MUSIC; si->shortcut.snap_left = DEFAULT_KEY_SNAP_LEFT; si->shortcut.snap_right = DEFAULT_KEY_SNAP_RIGHT; si->shortcut.snap_up = DEFAULT_KEY_SNAP_UP; si->shortcut.snap_down = DEFAULT_KEY_SNAP_DOWN; for (i = 0; i < MAX_PLAYERS; i++) { si->input[i].use_joystick = FALSE; si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(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.drop = (i == 0 ? JOY_BUTTON_2 : 0); si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED); si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED); si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED); si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED); si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED); si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED); } si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT); si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT); si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE; si->internal.program_title = getStringCopy(PROGRAM_TITLE_STRING); si->internal.program_version = getStringCopy(getProgramRealVersionString()); si->internal.program_author = getStringCopy(PROGRAM_AUTHOR_STRING); si->internal.program_email = getStringCopy(PROGRAM_EMAIL_STRING); si->internal.program_website = getStringCopy(PROGRAM_WEBSITE_STRING); si->internal.program_copyright = getStringCopy(PROGRAM_COPYRIGHT_STRING); si->internal.program_company = getStringCopy(PROGRAM_COMPANY_STRING); si->internal.program_icon_file = getStringCopy(PROGRAM_ICON_FILENAME); si->internal.default_graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR); si->internal.default_sounds_set = getStringCopy(SND_CLASSIC_SUBDIR); si->internal.default_music_set = getStringCopy(MUS_CLASSIC_SUBDIR); si->internal.fallback_graphics_file = getStringCopy(UNDEFINED_FILENAME); si->internal.fallback_sounds_file = getStringCopy(UNDEFINED_FILENAME); si->internal.fallback_music_file = getStringCopy(UNDEFINED_FILENAME); si->internal.default_level_series = getStringCopy(UNDEFINED_LEVELSET); si->internal.choose_from_top_leveldir = FALSE; si->internal.show_scaling_in_title = TRUE; si->internal.default_window_width = WIN_XSIZE_DEFAULT; si->internal.default_window_height = WIN_YSIZE_DEFAULT; si->debug.frame_delay[0] = DEFAULT_FRAME_DELAY_0; si->debug.frame_delay[1] = DEFAULT_FRAME_DELAY_1; si->debug.frame_delay[2] = DEFAULT_FRAME_DELAY_2; si->debug.frame_delay[3] = DEFAULT_FRAME_DELAY_3; si->debug.frame_delay[4] = DEFAULT_FRAME_DELAY_4; si->debug.frame_delay[5] = DEFAULT_FRAME_DELAY_5; si->debug.frame_delay[6] = DEFAULT_FRAME_DELAY_6; si->debug.frame_delay[7] = DEFAULT_FRAME_DELAY_7; si->debug.frame_delay[8] = DEFAULT_FRAME_DELAY_8; si->debug.frame_delay[9] = DEFAULT_FRAME_DELAY_9; si->debug.frame_delay_key[0] = DEFAULT_KEY_FRAME_DELAY_0; si->debug.frame_delay_key[1] = DEFAULT_KEY_FRAME_DELAY_1; si->debug.frame_delay_key[2] = DEFAULT_KEY_FRAME_DELAY_2; si->debug.frame_delay_key[3] = DEFAULT_KEY_FRAME_DELAY_3; si->debug.frame_delay_key[4] = DEFAULT_KEY_FRAME_DELAY_4; si->debug.frame_delay_key[5] = DEFAULT_KEY_FRAME_DELAY_5; si->debug.frame_delay_key[6] = DEFAULT_KEY_FRAME_DELAY_6; si->debug.frame_delay_key[7] = DEFAULT_KEY_FRAME_DELAY_7; si->debug.frame_delay_key[8] = DEFAULT_KEY_FRAME_DELAY_8; si->debug.frame_delay_key[9] = DEFAULT_KEY_FRAME_DELAY_9; si->debug.frame_delay_use_mod_key = DEFAULT_FRAME_DELAY_USE_MOD_KEY; si->debug.frame_delay_game_only = DEFAULT_FRAME_DELAY_GAME_ONLY; si->debug.show_frames_per_second = FALSE; si->options.verbose = FALSE; #if defined(PLATFORM_ANDROID) si->fullscreen = TRUE; #endif } static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si) { si->auto_setup.editor_zoom_tilesize = MINI_TILESIZE; } static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si) { si->editor_cascade.el_bd = TRUE; si->editor_cascade.el_em = TRUE; si->editor_cascade.el_emc = TRUE; si->editor_cascade.el_rnd = TRUE; si->editor_cascade.el_sb = TRUE; si->editor_cascade.el_sp = TRUE; si->editor_cascade.el_dc = TRUE; si->editor_cascade.el_dx = TRUE; si->editor_cascade.el_mm = TRUE; si->editor_cascade.el_df = TRUE; si->editor_cascade.el_chars = FALSE; si->editor_cascade.el_steel_chars = FALSE; si->editor_cascade.el_ce = FALSE; si->editor_cascade.el_ge = FALSE; si->editor_cascade.el_ref = FALSE; si->editor_cascade.el_user = FALSE; si->editor_cascade.el_dynamic = FALSE; } #define MAX_HIDE_SETUP_TOKEN_SIZE 20 static char *getHideSetupToken(void *setup_value) { static char hide_setup_token[MAX_HIDE_SETUP_TOKEN_SIZE]; if (setup_value != NULL) snprintf(hide_setup_token, MAX_HIDE_SETUP_TOKEN_SIZE, "%p", setup_value); return hide_setup_token; } static void setHideSetupEntry(void *setup_value_raw) { /* !!! DIRTY WORKAROUND; TO BE FIXED AFTER THE MM ENGINE RELEASE !!! */ void *setup_value = setup_value_raw - (void *)&si + (void *)&setup; char *hide_setup_token = getHideSetupToken(setup_value); if (setup_value != NULL) setHashEntry(hide_setup_hash, hide_setup_token, ""); } boolean hideSetupEntry(void *setup_value) { char *hide_setup_token = getHideSetupToken(setup_value); return (setup_value != NULL && getHashEntry(hide_setup_hash, hide_setup_token) != NULL); } static void setSetupInfoFromTokenText(SetupFileHash *setup_file_hash, struct TokenInfo *token_info, int token_nr, char *token_text) { char *token_hide_text = getStringCat2(token_text, ".hide"); char *token_hide_value = getHashEntry(setup_file_hash, token_hide_text); /* set the value of this setup option in the setup option structure */ setSetupInfo(token_info, token_nr, getHashEntry(setup_file_hash, token_text)); /* check if this setup option should be hidden in the setup menu */ if (token_hide_value != NULL && get_boolean_from_string(token_hide_value)) setHideSetupEntry(token_info[token_nr].value); } static void setSetupInfoFromTokenInfo(SetupFileHash *setup_file_hash, struct TokenInfo *token_info, int token_nr) { setSetupInfoFromTokenText(setup_file_hash, token_info, token_nr, token_info[token_nr].text); } static void decodeSetupFileHash(SetupFileHash *setup_file_hash) { int i, pnr; if (!setup_file_hash) return; if (hide_setup_hash == NULL) hide_setup_hash = newSetupFileHash(); /* global setup */ si = setup; for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, global_setup_tokens, i); setup = si; /* editor setup */ sei = setup.editor; for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, editor_setup_tokens, i); setup.editor = sei; /* shortcut setup */ ssi = setup.shortcut; for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, shortcut_setup_tokens, i); setup.shortcut = ssi; /* player setup */ for (pnr = 0; pnr < MAX_PLAYERS; pnr++) { char prefix[30]; sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1); sii = setup.input[pnr]; for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++) { char full_token[100]; sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text); setSetupInfoFromTokenText(setup_file_hash, player_setup_tokens, i, full_token); } setup.input[pnr] = sii; } /* system setup */ syi = setup.system; for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, system_setup_tokens, i); setup.system = syi; /* internal setup */ sxi = setup.internal; for (i = 0; i < NUM_INTERNAL_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, internal_setup_tokens, i); setup.internal = sxi; /* debug setup */ sdi = setup.debug; for (i = 0; i < NUM_DEBUG_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, debug_setup_tokens, i); setup.debug = sdi; /* options setup */ soi = setup.options; for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++) setSetupInfoFromTokenInfo(setup_file_hash, options_setup_tokens, i); setup.options = soi; } static void decodeSetupFileHash_AutoSetup(SetupFileHash *setup_file_hash) { int i; if (!setup_file_hash) return; /* auto setup */ sasi = setup.auto_setup; for (i = 0; i < NUM_AUTO_SETUP_TOKENS; i++) setSetupInfo(auto_setup_tokens, i, getHashEntry(setup_file_hash, auto_setup_tokens[i].text)); setup.auto_setup = sasi; } static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash) { int i; if (!setup_file_hash) return; /* editor cascade setup */ seci = setup.editor_cascade; for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++) setSetupInfo(editor_cascade_setup_tokens, i, getHashEntry(setup_file_hash, editor_cascade_setup_tokens[i].text)); setup.editor_cascade = seci; } void LoadSetupFromFilename(char *filename) { SetupFileHash *setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash) { decodeSetupFileHash(setup_file_hash); freeSetupFileHash(setup_file_hash); } else { Error(ERR_DEBUG, "using default setup values"); } } static void LoadSetup_SpecialPostProcessing() { char *player_name_new; /* needed to work around problems with fixed length strings */ player_name_new = get_corrected_login_name(setup.player_name); free(setup.player_name); setup.player_name = player_name_new; /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */ if (setup.scroll_delay == FALSE) { setup.scroll_delay_value = MIN_SCROLL_DELAY; setup.scroll_delay = TRUE; /* now always "on" */ } /* make sure that scroll delay value stays inside valid range */ setup.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY); } void LoadSetup() { char *filename; /* always start with reliable default values */ setSetupInfoToDefaults(&setup); /* try to load setup values from default setup file */ filename = getDefaultSetupFilename(); if (fileExists(filename)) LoadSetupFromFilename(filename); /* try to load setup values from user setup file */ filename = getSetupFilename(); LoadSetupFromFilename(filename); LoadSetup_SpecialPostProcessing(); } void LoadSetup_AutoSetup() { char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME); SetupFileHash *setup_file_hash = NULL; /* always start with reliable default values */ setSetupInfoToDefaults_AutoSetup(&setup); setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash) { decodeSetupFileHash_AutoSetup(setup_file_hash); freeSetupFileHash(setup_file_hash); } free(filename); } void LoadSetup_EditorCascade() { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); SetupFileHash *setup_file_hash = NULL; /* always start with reliable default values */ setSetupInfoToDefaults_EditorCascade(&setup); setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash) { decodeSetupFileHash_EditorCascade(setup_file_hash); freeSetupFileHash(setup_file_hash); } free(filename); } static void addGameControllerMappingToHash(SetupFileHash *mappings_hash, char *mapping_line) { char mapping_guid[MAX_LINE_LEN]; char *mapping_start, *mapping_end; // get GUID from game controller mapping line: copy complete line strncpy(mapping_guid, mapping_line, MAX_LINE_LEN - 1); mapping_guid[MAX_LINE_LEN - 1] = '\0'; // get GUID from game controller mapping line: cut after GUID part mapping_start = strchr(mapping_guid, ','); if (mapping_start != NULL) *mapping_start = '\0'; // cut newline from game controller mapping line mapping_end = strchr(mapping_line, '\n'); if (mapping_end != NULL) *mapping_end = '\0'; // add mapping entry to game controller mappings hash setHashEntry(mappings_hash, mapping_guid, mapping_line); } static void LoadSetup_ReadGameControllerMappings(SetupFileHash *mappings_hash, char *filename) { FILE *file; if (!(file = fopen(filename, MODE_READ))) { Error(ERR_WARN, "cannot read game controller mappings file '%s'", filename); return; } while (!feof(file)) { char line[MAX_LINE_LEN]; if (!fgets(line, MAX_LINE_LEN, file)) break; addGameControllerMappingToHash(mappings_hash, line); } fclose(file); } void SaveSetup() { char *filename = getSetupFilename(); FILE *file; int i, pnr; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); return; } fprintFileHeader(file, SETUP_FILENAME); /* global setup */ si = setup; for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++) { /* just to make things nicer :) */ if (i == SETUP_TOKEN_PLAYER_NAME + 1 || i == SETUP_TOKEN_GRAPHICS_SET || i == SETUP_TOKEN_VOLUME_SIMPLE || i == SETUP_TOKEN_TOUCH_CONTROL_TYPE) fprintf(file, "\n"); fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i)); } /* editor setup */ sei = setup.editor; fprintf(file, "\n"); for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i)); /* shortcut setup */ ssi = setup.shortcut; fprintf(file, "\n"); for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i)); /* player setup */ for (pnr = 0; pnr < MAX_PLAYERS; pnr++) { char prefix[30]; sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1); fprintf(file, "\n"); sii = setup.input[pnr]; for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i)); } /* system setup */ syi = setup.system; fprintf(file, "\n"); for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i)); /* internal setup */ /* (internal setup values not saved to user setup file) */ /* debug setup */ sdi = setup.debug; fprintf(file, "\n"); for (i = 0; i < NUM_DEBUG_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i)); /* options setup */ soi = setup.options; fprintf(file, "\n"); for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); } void SaveSetup_AutoSetup() { char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME); FILE *file; int i; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write auto setup file '%s'", filename); free(filename); return; } fprintFileHeader(file, AUTOSETUP_FILENAME); sasi = setup.auto_setup; for (i = 0; i < NUM_AUTO_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(auto_setup_tokens, "", i)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } void SaveSetup_EditorCascade() { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); FILE *file; int i; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename); free(filename); return; } fprintFileHeader(file, EDITORCASCADE_FILENAME); seci = setup.editor_cascade; for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++) fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } static void SaveSetup_WriteGameControllerMappings(SetupFileHash *mappings_hash, char *filename) { FILE *file; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write game controller mappings file '%s'",filename); return; } BEGIN_HASH_ITERATION(mappings_hash, itr) { fprintf(file, "%s\n", HASH_ITERATION_VALUE(itr)); } END_HASH_ITERATION(mappings_hash, itr) fclose(file); } void SaveSetup_AddGameControllerMapping(char *mapping) { char *filename = getPath2(getSetupDir(), GAMECONTROLLER_BASENAME); SetupFileHash *mappings_hash = newSetupFileHash(); InitUserDataDirectory(); // load existing personal game controller mappings LoadSetup_ReadGameControllerMappings(mappings_hash, filename); // add new mapping to personal game controller mappings addGameControllerMappingToHash(mappings_hash, mapping); // save updated personal game controller mappings SaveSetup_WriteGameControllerMappings(mappings_hash, filename); freeSetupFileHash(mappings_hash); free(filename); } void LoadCustomElementDescriptions() { char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS); SetupFileHash *setup_file_hash; int i; for (i = 0; i < NUM_FILE_ELEMENTS; i++) { if (element_info[i].custom_description != NULL) { free(element_info[i].custom_description); element_info[i].custom_description = NULL; } } if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; for (i = 0; i < NUM_FILE_ELEMENTS; i++) { char *token = getStringCat2(element_info[i].token_name, ".name"); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) element_info[i].custom_description = getStringCopy(value); free(token); } freeSetupFileHash(setup_file_hash); } static int getElementFromToken(char *token) { char *value = getHashEntry(element_token_hash, token); if (value != NULL) return atoi(value); Error(ERR_WARN, "unknown element token '%s'", token); return EL_UNDEFINED; } static int get_token_parameter_value(char *token, char *value_raw) { char *suffix; if (token == NULL || value_raw == NULL) return ARG_UNDEFINED_VALUE; suffix = strrchr(token, '.'); if (suffix == NULL) suffix = token; if (strEqual(suffix, ".element")) return getElementFromToken(value_raw); /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */ return get_parameter_value(value_raw, suffix, TYPE_INTEGER); } void InitMenuDesignSettings_Static() { int i; /* always start with reliable default values from static default config */ for (i = 0; image_config_vars[i].token != NULL; i++) { char *value = getHashEntry(image_config_hash, image_config_vars[i].token); if (value != NULL) *image_config_vars[i].value = get_token_parameter_value(image_config_vars[i].token, value); } } static void InitMenuDesignSettings_SpecialPreProcessing() { int i; /* the following initializes hierarchical values from static configuration */ /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */ titlescreen_initial_first_default.fade_mode = title_initial_first_default.fade_mode; titlescreen_initial_first_default.fade_delay = title_initial_first_default.fade_delay; titlescreen_initial_first_default.post_delay = title_initial_first_default.post_delay; titlescreen_initial_first_default.auto_delay = title_initial_first_default.auto_delay; titlescreen_first_default.fade_mode = title_first_default.fade_mode; titlescreen_first_default.fade_delay = title_first_default.fade_delay; titlescreen_first_default.post_delay = title_first_default.post_delay; titlescreen_first_default.auto_delay = title_first_default.auto_delay; titlemessage_initial_first_default.fade_mode = title_initial_first_default.fade_mode; titlemessage_initial_first_default.fade_delay = title_initial_first_default.fade_delay; titlemessage_initial_first_default.post_delay = title_initial_first_default.post_delay; titlemessage_initial_first_default.auto_delay = title_initial_first_default.auto_delay; titlemessage_first_default.fade_mode = title_first_default.fade_mode; titlemessage_first_default.fade_delay = title_first_default.fade_delay; titlemessage_first_default.post_delay = title_first_default.post_delay; titlemessage_first_default.auto_delay = title_first_default.auto_delay; titlescreen_initial_default.fade_mode = title_initial_default.fade_mode; titlescreen_initial_default.fade_delay = title_initial_default.fade_delay; titlescreen_initial_default.post_delay = title_initial_default.post_delay; titlescreen_initial_default.auto_delay = title_initial_default.auto_delay; titlescreen_default.fade_mode = title_default.fade_mode; titlescreen_default.fade_delay = title_default.fade_delay; titlescreen_default.post_delay = title_default.post_delay; titlescreen_default.auto_delay = title_default.auto_delay; titlemessage_initial_default.fade_mode = title_initial_default.fade_mode; titlemessage_initial_default.fade_delay = title_initial_default.fade_delay; titlemessage_initial_default.post_delay = title_initial_default.post_delay; titlemessage_initial_default.auto_delay = title_initial_default.auto_delay; titlemessage_default.fade_mode = title_default.fade_mode; titlemessage_default.fade_delay = title_default.fade_delay; titlemessage_default.post_delay = title_default.post_delay; titlemessage_default.auto_delay = title_default.auto_delay; /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */ for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++) { titlescreen_initial_first[i] = titlescreen_initial_first_default; titlescreen_first[i] = titlescreen_first_default; titlemessage_initial_first[i] = titlemessage_initial_first_default; titlemessage_first[i] = titlemessage_first_default; titlescreen_initial[i] = titlescreen_initial_default; titlescreen[i] = titlescreen_default; titlemessage_initial[i] = titlemessage_initial_default; titlemessage[i] = titlemessage_default; } /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { if (i == GFX_SPECIAL_ARG_TITLE) /* title values already initialized */ continue; menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT]; menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT]; menu.next_screen[i] = menu.next_screen[GFX_SPECIAL_ARG_DEFAULT]; } /* special case: initialize "ARG_DEFAULT" values in static default config */ /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { viewport.window[i] = viewport.window[GFX_SPECIAL_ARG_DEFAULT]; viewport.playfield[i] = viewport.playfield[GFX_SPECIAL_ARG_DEFAULT]; viewport.door_1[i] = viewport.door_1[GFX_SPECIAL_ARG_DEFAULT]; if (i == GFX_SPECIAL_ARG_EDITOR) /* editor values already initialized */ continue; viewport.door_2[i] = viewport.door_2[GFX_SPECIAL_ARG_DEFAULT]; } } static void InitMenuDesignSettings_SpecialPostProcessing() { static struct { struct XY *dst, *src; } game_buttons_xy[] = { { &game.button.save, &game.button.stop }, { &game.button.pause2, &game.button.pause }, { &game.button.load, &game.button.play }, { &game.button.undo, &game.button.stop }, { &game.button.redo, &game.button.play }, { NULL, NULL } }; int i; /* special case: initialize later added SETUP list size from LEVELS value */ if (menu.list_size[GAME_MODE_SETUP] == -1) menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS]; /* set default position for snapshot buttons to stop/pause/play buttons */ for (i = 0; game_buttons_xy[i].dst != NULL; i++) if ((*game_buttons_xy[i].dst).x == -1 && (*game_buttons_xy[i].dst).y == -1) *game_buttons_xy[i].dst = *game_buttons_xy[i].src; } static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics() { static struct { struct XYTileSize *dst, *src; int graphic; } editor_buttons_xy[] = { { &editor.button.element_left, &editor.palette.element_left, IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT }, { &editor.button.element_middle, &editor.palette.element_middle, IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE }, { &editor.button.element_right, &editor.palette.element_right, IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT }, { NULL, NULL } }; int i; /* set default position for element buttons to element graphics */ for (i = 0; editor_buttons_xy[i].dst != NULL; i++) { if ((*editor_buttons_xy[i].dst).x == -1 && (*editor_buttons_xy[i].dst).y == -1) { struct GraphicInfo *gd = &graphic_info[editor_buttons_xy[i].graphic]; gd->width = gd->height = editor_buttons_xy[i].src->tile_size; *editor_buttons_xy[i].dst = *editor_buttons_xy[i].src; } } } static void LoadMenuDesignSettingsFromFilename(char *filename) { static struct TitleFadingInfo tfi; static struct TitleMessageInfo tmi; static struct TokenInfo title_tokens[] = { { TYPE_INTEGER, &tfi.fade_mode, ".fade_mode" }, { TYPE_INTEGER, &tfi.fade_delay, ".fade_delay" }, { TYPE_INTEGER, &tfi.post_delay, ".post_delay" }, { TYPE_INTEGER, &tfi.auto_delay, ".auto_delay" }, { -1, NULL, NULL } }; static struct TokenInfo titlemessage_tokens[] = { { TYPE_INTEGER, &tmi.x, ".x" }, { TYPE_INTEGER, &tmi.y, ".y" }, { TYPE_INTEGER, &tmi.width, ".width" }, { TYPE_INTEGER, &tmi.height, ".height" }, { TYPE_INTEGER, &tmi.chars, ".chars" }, { TYPE_INTEGER, &tmi.lines, ".lines" }, { TYPE_INTEGER, &tmi.align, ".align" }, { TYPE_INTEGER, &tmi.valign, ".valign" }, { TYPE_INTEGER, &tmi.font, ".font" }, { TYPE_BOOLEAN, &tmi.autowrap, ".autowrap" }, { TYPE_BOOLEAN, &tmi.centered, ".centered" }, { TYPE_BOOLEAN, &tmi.parse_comments, ".parse_comments" }, { TYPE_INTEGER, &tmi.sort_priority, ".sort_priority" }, { TYPE_INTEGER, &tmi.fade_mode, ".fade_mode" }, { TYPE_INTEGER, &tmi.fade_delay, ".fade_delay" }, { TYPE_INTEGER, &tmi.post_delay, ".post_delay" }, { TYPE_INTEGER, &tmi.auto_delay, ".auto_delay" }, { -1, NULL, NULL } }; static struct { struct TitleFadingInfo *info; char *text; } title_info[] = { /* initialize first titles from "enter screen" definitions, if defined */ { &title_initial_first_default, "menu.enter_screen.TITLE" }, { &title_first_default, "menu.enter_screen.TITLE" }, /* initialize title screens from "next screen" definitions, if defined */ { &title_initial_default, "menu.next_screen.TITLE" }, { &title_default, "menu.next_screen.TITLE" }, { NULL, NULL } }; static struct { struct TitleMessageInfo *array; char *text; } titlemessage_arrays[] = { /* initialize first titles from "enter screen" definitions, if defined */ { titlescreen_initial_first, "menu.enter_screen.TITLE" }, { titlescreen_first, "menu.enter_screen.TITLE" }, { titlemessage_initial_first, "menu.enter_screen.TITLE" }, { titlemessage_first, "menu.enter_screen.TITLE" }, /* initialize titles from "next screen" definitions, if defined */ { titlescreen_initial, "menu.next_screen.TITLE" }, { titlescreen, "menu.next_screen.TITLE" }, { titlemessage_initial, "menu.next_screen.TITLE" }, { titlemessage, "menu.next_screen.TITLE" }, /* overwrite titles with title definitions, if defined */ { titlescreen_initial_first, "[title_initial]" }, { titlescreen_first, "[title]" }, { titlemessage_initial_first, "[title_initial]" }, { titlemessage_first, "[title]" }, { titlescreen_initial, "[title_initial]" }, { titlescreen, "[title]" }, { titlemessage_initial, "[title_initial]" }, { titlemessage, "[title]" }, /* overwrite titles with title screen/message definitions, if defined */ { titlescreen_initial_first, "[titlescreen_initial]" }, { titlescreen_first, "[titlescreen]" }, { titlemessage_initial_first, "[titlemessage_initial]" }, { titlemessage_first, "[titlemessage]" }, { titlescreen_initial, "[titlescreen_initial]" }, { titlescreen, "[titlescreen]" }, { titlemessage_initial, "[titlemessage_initial]" }, { titlemessage, "[titlemessage]" }, { NULL, NULL } }; SetupFileHash *setup_file_hash; int i, j, k; if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; /* the following initializes hierarchical values from dynamic configuration */ /* special case: initialize with default values that may be overwritten */ /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset"); char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset"); char *value_3 = getHashEntry(setup_file_hash, "menu.list_size"); if (value_1 != NULL) menu.draw_xoffset[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.draw_yoffset[i] = get_integer_from_string(value_2); if (value_3 != NULL) menu.list_size[i] = get_integer_from_string(value_3); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */ for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO"); char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO"); if (value_1 != NULL) menu.draw_xoffset_info[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.draw_yoffset_info[i] = get_integer_from_string(value_2); if (i == GFX_SPECIAL_ARG_INFO_ELEMENTS) { char *value_1 = getHashEntry(setup_file_hash, "menu.list_size.INFO"); if (value_1 != NULL) menu.list_size_info[i] = get_integer_from_string(value_1); } } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */ for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP"); char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP"); if (value_1 != NULL) menu.draw_xoffset_setup[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.draw_yoffset_setup[i] = get_integer_from_string(value_2); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.line_spacing.INFO[XXX]" from "menu.line_spacing.INFO") */ for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++) { char *value_1 = getHashEntry(setup_file_hash,"menu.left_spacing.INFO"); char *value_2 = getHashEntry(setup_file_hash,"menu.right_spacing.INFO"); char *value_3 = getHashEntry(setup_file_hash,"menu.top_spacing.INFO"); char *value_4 = getHashEntry(setup_file_hash,"menu.bottom_spacing.INFO"); char *value_5 = getHashEntry(setup_file_hash,"menu.paragraph_spacing.INFO"); char *value_6 = getHashEntry(setup_file_hash,"menu.headline1_spacing.INFO"); char *value_7 = getHashEntry(setup_file_hash,"menu.headline2_spacing.INFO"); char *value_8 = getHashEntry(setup_file_hash,"menu.line_spacing.INFO"); char *value_9 = getHashEntry(setup_file_hash,"menu.extra_spacing.INFO"); if (value_1 != NULL) menu.left_spacing_info[i] = get_integer_from_string(value_1); if (value_2 != NULL) menu.right_spacing_info[i] = get_integer_from_string(value_2); if (value_3 != NULL) menu.top_spacing_info[i] = get_integer_from_string(value_3); if (value_4 != NULL) menu.bottom_spacing_info[i] = get_integer_from_string(value_4); if (value_5 != NULL) menu.paragraph_spacing_info[i] = get_integer_from_string(value_5); if (value_6 != NULL) menu.headline1_spacing_info[i] = get_integer_from_string(value_6); if (value_7 != NULL) menu.headline2_spacing_info[i] = get_integer_from_string(value_7); if (value_8 != NULL) menu.line_spacing_info[i] = get_integer_from_string(value_8); if (value_9 != NULL) menu.extra_spacing_info[i] = get_integer_from_string(value_9); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { char *token_1 = "menu.enter_screen.fade_mode"; char *token_2 = "menu.enter_screen.fade_delay"; char *token_3 = "menu.enter_screen.post_delay"; char *token_4 = "menu.leave_screen.fade_mode"; char *token_5 = "menu.leave_screen.fade_delay"; char *token_6 = "menu.leave_screen.post_delay"; char *token_7 = "menu.next_screen.fade_mode"; char *token_8 = "menu.next_screen.fade_delay"; char *token_9 = "menu.next_screen.post_delay"; char *value_1 = getHashEntry(setup_file_hash, token_1); char *value_2 = getHashEntry(setup_file_hash, token_2); char *value_3 = getHashEntry(setup_file_hash, token_3); char *value_4 = getHashEntry(setup_file_hash, token_4); char *value_5 = getHashEntry(setup_file_hash, token_5); char *value_6 = getHashEntry(setup_file_hash, token_6); char *value_7 = getHashEntry(setup_file_hash, token_7); char *value_8 = getHashEntry(setup_file_hash, token_8); char *value_9 = getHashEntry(setup_file_hash, token_9); if (value_1 != NULL) menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1, value_1); if (value_2 != NULL) menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2, value_2); if (value_3 != NULL) menu.enter_screen[i].post_delay = get_token_parameter_value(token_3, value_3); if (value_4 != NULL) menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4, value_4); if (value_5 != NULL) menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5, value_5); if (value_6 != NULL) menu.leave_screen[i].post_delay = get_token_parameter_value(token_6, value_6); if (value_7 != NULL) menu.next_screen[i].fade_mode = get_token_parameter_value(token_7, value_7); if (value_8 != NULL) menu.next_screen[i].fade_delay = get_token_parameter_value(token_8, value_8); if (value_9 != NULL) menu.next_screen[i].post_delay = get_token_parameter_value(token_9, value_9); } /* special case: initialize with default values that may be overwritten */ /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) { char *token_w1 = "viewport.window.width"; char *token_w2 = "viewport.window.height"; char *token_01 = "viewport.playfield.x"; char *token_02 = "viewport.playfield.y"; char *token_03 = "viewport.playfield.width"; char *token_04 = "viewport.playfield.height"; char *token_05 = "viewport.playfield.border_size"; char *token_06 = "viewport.door_1.x"; char *token_07 = "viewport.door_1.y"; char *token_08 = "viewport.door_1.width"; char *token_09 = "viewport.door_1.height"; char *token_10 = "viewport.door_1.border_size"; char *token_11 = "viewport.door_2.x"; char *token_12 = "viewport.door_2.y"; char *token_13 = "viewport.door_2.width"; char *token_14 = "viewport.door_2.height"; char *token_15 = "viewport.door_2.border_size"; char *value_w1 = getHashEntry(setup_file_hash, token_w1); char *value_w2 = getHashEntry(setup_file_hash, token_w2); char *value_01 = getHashEntry(setup_file_hash, token_01); char *value_02 = getHashEntry(setup_file_hash, token_02); char *value_03 = getHashEntry(setup_file_hash, token_03); char *value_04 = getHashEntry(setup_file_hash, token_04); char *value_05 = getHashEntry(setup_file_hash, token_05); char *value_06 = getHashEntry(setup_file_hash, token_06); char *value_07 = getHashEntry(setup_file_hash, token_07); char *value_08 = getHashEntry(setup_file_hash, token_08); char *value_09 = getHashEntry(setup_file_hash, token_09); char *value_10 = getHashEntry(setup_file_hash, token_10); char *value_11 = getHashEntry(setup_file_hash, token_11); char *value_12 = getHashEntry(setup_file_hash, token_12); char *value_13 = getHashEntry(setup_file_hash, token_13); char *value_14 = getHashEntry(setup_file_hash, token_14); char *value_15 = getHashEntry(setup_file_hash, token_15); if (value_w1 != NULL) viewport.window[i].width = get_token_parameter_value(token_w1, value_w1); if (value_w2 != NULL) viewport.window[i].height = get_token_parameter_value(token_w2, value_w2); if (value_01 != NULL) viewport.playfield[i].x = get_token_parameter_value(token_01, value_01); if (value_02 != NULL) viewport.playfield[i].y = get_token_parameter_value(token_02, value_02); if (value_03 != NULL) viewport.playfield[i].width = get_token_parameter_value(token_03, value_03); if (value_04 != NULL) viewport.playfield[i].height = get_token_parameter_value(token_04, value_04); if (value_05 != NULL) viewport.playfield[i].border_size = get_token_parameter_value(token_05, value_05); if (value_06 != NULL) viewport.door_1[i].x = get_token_parameter_value(token_06, value_06); if (value_07 != NULL) viewport.door_1[i].y = get_token_parameter_value(token_07, value_07); if (value_08 != NULL) viewport.door_1[i].width = get_token_parameter_value(token_08, value_08); if (value_09 != NULL) viewport.door_1[i].height = get_token_parameter_value(token_09, value_09); if (value_10 != NULL) viewport.door_1[i].border_size = get_token_parameter_value(token_10, value_10); if (value_11 != NULL) viewport.door_2[i].x = get_token_parameter_value(token_11, value_11); if (value_12 != NULL) viewport.door_2[i].y = get_token_parameter_value(token_12, value_12); if (value_13 != NULL) viewport.door_2[i].width = get_token_parameter_value(token_13, value_13); if (value_14 != NULL) viewport.door_2[i].height = get_token_parameter_value(token_14, value_14); if (value_15 != NULL) viewport.door_1[i].border_size = get_token_parameter_value(token_15, value_15); } /* special case: initialize with default values that may be overwritten */ /* (e.g., init "[title].fade_mode" from "menu.next_screen.TITLE.fade_mode") */ for (i = 0; title_info[i].info != NULL; i++) { struct TitleFadingInfo *info = title_info[i].info; char *base_token = title_info[i].text; for (j = 0; title_tokens[j].type != -1; j++) { char *token = getStringCat2(base_token, title_tokens[j].text); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) { int parameter_value = get_token_parameter_value(token, value); tfi = *info; *(int *)title_tokens[j].value = (int)parameter_value; *info = tfi; } free(token); } } /* special case: initialize with default values that may be overwritten */ /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */ for (i = 0; titlemessage_arrays[i].array != NULL; i++) { struct TitleMessageInfo *array = titlemessage_arrays[i].array; char *base_token = titlemessage_arrays[i].text; for (j = 0; titlemessage_tokens[j].type != -1; j++) { char *token = getStringCat2(base_token, titlemessage_tokens[j].text); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) { int parameter_value = get_token_parameter_value(token, value); for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++) { tmi = array[k]; if (titlemessage_tokens[j].type == TYPE_INTEGER) *(int *)titlemessage_tokens[j].value = (int)parameter_value; else *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value; array[k] = tmi; } } free(token); } } /* read (and overwrite with) values that may be specified in config file */ for (i = 0; image_config_vars[i].token != NULL; i++) { char *value = getHashEntry(setup_file_hash, image_config_vars[i].token); /* (ignore definitions set to "[DEFAULT]" which are already initialized) */ if (value != NULL && !strEqual(value, ARG_DEFAULT)) *image_config_vars[i].value = get_token_parameter_value(image_config_vars[i].token, value); } freeSetupFileHash(setup_file_hash); } void LoadMenuDesignSettings() { char *filename_base = UNDEFINED_FILENAME, *filename_local; InitMenuDesignSettings_Static(); InitMenuDesignSettings_SpecialPreProcessing(); if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS)) { /* first look for special settings configured in level series config */ filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS); if (fileExists(filename_base)) LoadMenuDesignSettingsFromFilename(filename_base); } filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS); if (filename_local != NULL && !strEqual(filename_base, filename_local)) LoadMenuDesignSettingsFromFilename(filename_local); InitMenuDesignSettings_SpecialPostProcessing(); } void LoadMenuDesignSettings_AfterGraphics() { InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(); } void LoadUserDefinedEditorElementList(int **elements, int *num_elements) { char *filename = getEditorSetupFilename(); SetupFileList *setup_file_list, *list; SetupFileHash *element_hash; int num_unknown_tokens = 0; int i; if ((setup_file_list = loadSetupFileList(filename)) == NULL) return; element_hash = newSetupFileHash(); for (i = 0; i < NUM_FILE_ELEMENTS; i++) setHashEntry(element_hash, element_info[i].token_name, i_to_a(i)); /* determined size may be larger than needed (due to unknown elements) */ *num_elements = 0; for (list = setup_file_list; list != NULL; list = list->next) (*num_elements)++; /* add space for up to 3 more elements for padding that may be needed */ *num_elements += 3; /* free memory for old list of elements, if needed */ checked_free(*elements); /* allocate memory for new list of elements */ *elements = checked_malloc(*num_elements * sizeof(int)); *num_elements = 0; for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(element_hash, list->token); if (value == NULL) /* try to find obsolete token mapping */ { char *mapped_token = get_mapped_token(list->token); if (mapped_token != NULL) { value = getHashEntry(element_hash, mapped_token); free(mapped_token); } } if (value != NULL) { (*elements)[(*num_elements)++] = atoi(value); } else { if (num_unknown_tokens == 0) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: unknown token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); num_unknown_tokens++; } Error(ERR_INFO, "- token: '%s'", list->token); } } if (num_unknown_tokens > 0) Error(ERR_INFO_LINE, "-"); while (*num_elements % 4) /* pad with empty elements, if needed */ (*elements)[(*num_elements)++] = EL_EMPTY; freeSetupFileList(setup_file_list); freeSetupFileHash(element_hash); #if 0 for (i = 0; i < *num_elements; i++) printf("editor: element '%s' [%d]\n", element_info[(*elements)[i]].token_name, (*elements)[i]); #endif } static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music, boolean is_sound) { SetupFileHash *setup_file_hash = NULL; struct MusicFileInfo tmp_music_file_info, *new_music_file_info; char *filename_music, *filename_prefix, *filename_info; struct { char *token; char **value_ptr; } token_to_value_ptr[] = { { "title_header", &tmp_music_file_info.title_header }, { "artist_header", &tmp_music_file_info.artist_header }, { "album_header", &tmp_music_file_info.album_header }, { "year_header", &tmp_music_file_info.year_header }, { "title", &tmp_music_file_info.title }, { "artist", &tmp_music_file_info.artist }, { "album", &tmp_music_file_info.album }, { "year", &tmp_music_file_info.year }, { NULL, NULL }, }; int i; filename_music = (is_sound ? getCustomSoundFilename(basename) : getCustomMusicFilename(basename)); if (filename_music == NULL) return NULL; /* ---------- try to replace file extension ---------- */ filename_prefix = getStringCopy(filename_music); if (strrchr(filename_prefix, '.') != NULL) *strrchr(filename_prefix, '.') = '\0'; filename_info = getStringCat2(filename_prefix, ".txt"); if (fileExists(filename_info)) setup_file_hash = loadSetupFileHash(filename_info); free(filename_prefix); free(filename_info); if (setup_file_hash == NULL) { /* ---------- try to add file extension ---------- */ filename_prefix = getStringCopy(filename_music); filename_info = getStringCat2(filename_prefix, ".txt"); if (fileExists(filename_info)) setup_file_hash = loadSetupFileHash(filename_info); free(filename_prefix); free(filename_info); } if (setup_file_hash == NULL) return NULL; /* ---------- music file info found ---------- */ clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo)); for (i = 0; token_to_value_ptr[i].token != NULL; i++) { char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token); *token_to_value_ptr[i].value_ptr = getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME); } tmp_music_file_info.basename = getStringCopy(basename); tmp_music_file_info.music = music; tmp_music_file_info.is_sound = is_sound; new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo)); *new_music_file_info = tmp_music_file_info; return new_music_file_info; } static struct MusicFileInfo *get_music_file_info(char *basename, int music) { return get_music_file_info_ext(basename, music, FALSE); } static struct MusicFileInfo *get_sound_file_info(char *basename, int sound) { return get_music_file_info_ext(basename, sound, TRUE); } static boolean music_info_listed_ext(struct MusicFileInfo *list, char *basename, boolean is_sound) { for (; list != NULL; list = list->next) if (list->is_sound == is_sound && strEqual(list->basename, basename)) return TRUE; return FALSE; } static boolean music_info_listed(struct MusicFileInfo *list, char *basename) { return music_info_listed_ext(list, basename, FALSE); } static boolean sound_info_listed(struct MusicFileInfo *list, char *basename) { return music_info_listed_ext(list, basename, TRUE); } void LoadMusicInfo() { char *music_directory = getCustomMusicDirectory(); int num_music = getMusicListSize(); int num_music_noconf = 0; int num_sounds = getSoundListSize(); Directory *dir; DirectoryEntry *dir_entry; struct FileInfo *music, *sound; struct MusicFileInfo *next, **new; int i; while (music_file_info != NULL) { next = music_file_info->next; checked_free(music_file_info->basename); checked_free(music_file_info->title_header); checked_free(music_file_info->artist_header); checked_free(music_file_info->album_header); checked_free(music_file_info->year_header); checked_free(music_file_info->title); checked_free(music_file_info->artist); checked_free(music_file_info->album); checked_free(music_file_info->year); free(music_file_info); music_file_info = next; } new = &music_file_info; for (i = 0; i < num_music; i++) { music = getMusicListEntry(i); if (music->filename == NULL) continue; if (strEqual(music->filename, UNDEFINED_FILENAME)) continue; /* a configured file may be not recognized as music */ if (!FileIsMusic(music->filename)) continue; if (!music_info_listed(music_file_info, music->filename)) { *new = get_music_file_info(music->filename, i); if (*new != NULL) new = &(*new)->next; } } if ((dir = openDirectory(music_directory)) == NULL) { Error(ERR_WARN, "cannot read music directory '%s'", music_directory); return; } while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ { char *basename = dir_entry->basename; boolean music_already_used = FALSE; int i; /* skip all music files that are configured in music config file */ for (i = 0; i < num_music; i++) { music = getMusicListEntry(i); if (music->filename == NULL) continue; if (strEqual(basename, music->filename)) { music_already_used = TRUE; break; } } if (music_already_used) continue; if (!FileIsMusic(dir_entry->filename)) continue; if (!music_info_listed(music_file_info, basename)) { *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf)); if (*new != NULL) new = &(*new)->next; } num_music_noconf++; } closeDirectory(dir); for (i = 0; i < num_sounds; i++) { sound = getSoundListEntry(i); if (sound->filename == NULL) continue; if (strEqual(sound->filename, UNDEFINED_FILENAME)) continue; /* a configured file may be not recognized as sound */ if (!FileIsSound(sound->filename)) continue; if (!sound_info_listed(music_file_info, sound->filename)) { *new = get_sound_file_info(sound->filename, i); if (*new != NULL) new = &(*new)->next; } } } void add_helpanim_entry(int element, int action, int direction, int delay, int *num_list_entries) { struct HelpAnimInfo *new_list_entry; (*num_list_entries)++; helpanim_info = checked_realloc(helpanim_info, *num_list_entries * sizeof(struct HelpAnimInfo)); new_list_entry = &helpanim_info[*num_list_entries - 1]; new_list_entry->element = element; new_list_entry->action = action; new_list_entry->direction = direction; new_list_entry->delay = delay; } void print_unknown_token(char *filename, char *token, int token_nr) { if (token_nr == 0) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: unknown token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); } Error(ERR_INFO, "- token: '%s'", token); } void print_unknown_token_end(int token_nr) { if (token_nr > 0) Error(ERR_INFO_LINE, "-"); } void LoadHelpAnimInfo() { char *filename = getHelpAnimFilename(); SetupFileList *setup_file_list = NULL, *list; SetupFileHash *element_hash, *action_hash, *direction_hash; int num_list_entries = 0; int num_unknown_tokens = 0; int i; if (fileExists(filename)) setup_file_list = loadSetupFileList(filename); if (setup_file_list == NULL) { /* use reliable default values from static configuration */ SetupFileList *insert_ptr; insert_ptr = setup_file_list = newSetupFileList(helpanim_config[0].token, helpanim_config[0].value); for (i = 1; helpanim_config[i].token; i++) insert_ptr = addListEntry(insert_ptr, helpanim_config[i].token, helpanim_config[i].value); } element_hash = newSetupFileHash(); action_hash = newSetupFileHash(); direction_hash = newSetupFileHash(); for (i = 0; i < MAX_NUM_ELEMENTS; i++) setHashEntry(element_hash, element_info[i].token_name, i_to_a(i)); for (i = 0; i < NUM_ACTIONS; i++) setHashEntry(action_hash, element_action_info[i].suffix, i_to_a(element_action_info[i].value)); /* do not store direction index (bit) here, but direction value! */ for (i = 0; i < NUM_DIRECTIONS_FULL; i++) setHashEntry(direction_hash, element_direction_info[i].suffix, i_to_a(1 << element_direction_info[i].value)); for (list = setup_file_list; list != NULL; list = list->next) { char *element_token, *action_token, *direction_token; char *element_value, *action_value, *direction_value; int delay = atoi(list->value); if (strEqual(list->token, "end")) { add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries); continue; } /* first try to break element into element/action/direction parts; if this does not work, also accept combined "element[.act][.dir]" elements (like "dynamite.active"), which are unique elements */ if (strchr(list->token, '.') == NULL) /* token contains no '.' */ { element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else { /* no further suffixes found -- this is not an element */ print_unknown_token(filename, list->token, num_unknown_tokens++); } continue; } /* token has format "." */ action_token = strchr(list->token, '.'); /* suffix may be action ... */ direction_token = action_token; /* ... or direction */ element_token = getStringCopy(list->token); *strchr(element_token, '.') = '\0'; element_value = getHashEntry(element_hash, element_token); if (element_value == NULL) /* this is no element */ { element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); continue; } action_value = getHashEntry(action_hash, action_token); if (action_value != NULL) /* action found */ { add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay, &num_list_entries); free(element_token); continue; } direction_value = getHashEntry(direction_hash, direction_token); if (direction_value != NULL) /* direction found */ { add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay, &num_list_entries); free(element_token); continue; } if (strchr(action_token + 1, '.') == NULL) { /* no further suffixes found -- this is not an action nor direction */ element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); continue; } /* token has format ".." */ direction_token = strchr(action_token + 1, '.'); action_token = getStringCopy(action_token); *strchr(action_token + 1, '.') = '\0'; action_value = getHashEntry(action_hash, action_token); if (action_value == NULL) /* this is no action */ { element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); free(action_token); continue; } direction_value = getHashEntry(direction_hash, direction_token); if (direction_value != NULL) /* direction found */ { add_helpanim_entry(atoi(element_value), atoi(action_value), atoi(direction_value), delay, &num_list_entries); free(element_token); free(action_token); continue; } /* this is no direction */ element_value = getHashEntry(element_hash, list->token); if (element_value != NULL) /* combined element found */ add_helpanim_entry(atoi(element_value), -1, -1, delay, &num_list_entries); else print_unknown_token(filename, list->token, num_unknown_tokens++); free(element_token); free(action_token); } print_unknown_token_end(num_unknown_tokens); add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries); add_helpanim_entry(HELPANIM_LIST_END, -1, -1, -1, &num_list_entries); freeSetupFileList(setup_file_list); freeSetupFileHash(element_hash); freeSetupFileHash(action_hash); freeSetupFileHash(direction_hash); #if 0 for (i = 0; i < num_list_entries; i++) printf("::: '%s': %d, %d, %d => %d\n", EL_NAME(helpanim_info[i].element), helpanim_info[i].element, helpanim_info[i].action, helpanim_info[i].direction, helpanim_info[i].delay); #endif } void LoadHelpTextInfo() { char *filename = getHelpTextFilename(); int i; if (helptext_info != NULL) { freeSetupFileHash(helptext_info); helptext_info = NULL; } if (fileExists(filename)) helptext_info = loadSetupFileHash(filename); if (helptext_info == NULL) { /* use reliable default values from static configuration */ helptext_info = newSetupFileHash(); for (i = 0; helptext_config[i].token; i++) setHashEntry(helptext_info, helptext_config[i].token, helptext_config[i].value); } #if 0 BEGIN_HASH_ITERATION(helptext_info, itr) { printf("::: '%s' => '%s'\n", HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr)); } END_HASH_ITERATION(hash, itr) #endif } /* ------------------------------------------------------------------------- */ /* convert levels */ /* ------------------------------------------------------------------------- */ #define MAX_NUM_CONVERT_LEVELS 1000 void ConvertLevels() { static LevelDirTree *convert_leveldir = NULL; static int convert_level_nr = -1; static int num_levels_handled = 0; static int num_levels_converted = 0; static boolean levels_failed[MAX_NUM_CONVERT_LEVELS]; int i; convert_leveldir = getTreeInfoFromIdentifier(leveldir_first, global.convert_leveldir); if (convert_leveldir == NULL) Error(ERR_EXIT, "no such level identifier: '%s'", global.convert_leveldir); leveldir_current = convert_leveldir; if (global.convert_level_nr != -1) { convert_leveldir->first_level = global.convert_level_nr; convert_leveldir->last_level = global.convert_level_nr; } convert_level_nr = convert_leveldir->first_level; PrintLine("=", 79); Print("Converting levels\n"); PrintLine("-", 79); Print("Level series identifier: '%s'\n", convert_leveldir->identifier); Print("Level series name: '%s'\n", convert_leveldir->name); Print("Level series author: '%s'\n", convert_leveldir->author); Print("Number of levels: %d\n", convert_leveldir->levels); PrintLine("=", 79); Print("\n"); for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++) levels_failed[i] = FALSE; while (convert_level_nr <= convert_leveldir->last_level) { char *level_filename; boolean new_level; level_nr = convert_level_nr++; Print("Level %03d: ", level_nr); LoadLevel(level_nr); if (level.no_level_file || level.no_valid_file) { Print("(no level)\n"); continue; } Print("converting level ... "); level_filename = getDefaultLevelFilename(level_nr); new_level = !fileExists(level_filename); if (new_level) { SaveLevel(level_nr); num_levels_converted++; Print("converted.\n"); } else { if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS) levels_failed[level_nr] = TRUE; Print("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n"); } num_levels_handled++; } Print("\n"); PrintLine("=", 79); Print("Number of levels handled: %d\n", num_levels_handled); Print("Number of levels converted: %d (%d%%)\n", num_levels_converted, (num_levels_handled ? num_levels_converted * 100 / num_levels_handled : 0)); PrintLine("-", 79); Print("Summary (for automatic parsing by scripts):\n"); Print("LEVELDIR '%s', CONVERTED %d/%d (%d%%)", convert_leveldir->identifier, num_levels_converted, num_levels_handled, (num_levels_handled ? num_levels_converted * 100 / num_levels_handled : 0)); if (num_levels_handled != num_levels_converted) { Print(", FAILED:"); for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++) if (levels_failed[i]) Print(" %03d", i); } Print("\n"); PrintLine("=", 79); CloseAllAndExit(0); } /* ------------------------------------------------------------------------- */ /* create and save images for use in level sketches (raw BMP format) */ /* ------------------------------------------------------------------------- */ void CreateLevelSketchImages() { #if defined(TARGET_SDL) Bitmap *bitmap1; Bitmap *bitmap2; int i; InitElementPropertiesGfxElement(); bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH); bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH); for (i = 0; i < NUM_FILE_ELEMENTS; i++) { Bitmap *src_bitmap; int src_x, src_y; int element = getMappedElement(i); int graphic = el2edimg(element); char basename1[16]; char basename2[16]; char *filename1; char *filename2; sprintf(basename1, "%03d.bmp", i); sprintf(basename2, "%03ds.bmp", i); filename1 = getPath2(global.create_images_dir, basename1); filename2 = getPath2(global.create_images_dir, basename2); getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0); if (SDL_SaveBMP(bitmap1->surface, filename1) != 0) Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1); getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0); if (SDL_SaveBMP(bitmap2->surface, filename2) != 0) Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2); free(filename1); free(filename2); if (options.debug) printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n')); } FreeBitmap(bitmap1); FreeBitmap(bitmap2); if (options.debug) printf("\n"); Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS); CloseAllAndExit(0); #endif } /* ------------------------------------------------------------------------- */ /* create and save images for custom and group elements (raw BMP format) */ /* ------------------------------------------------------------------------- */ void CreateCustomElementImages(char *directory) { #if defined(TARGET_SDL) char *src_basename = "RocksCE-template.ilbm"; char *dst_basename = "RocksCE.bmp"; char *src_filename = getPath2(directory, src_basename); char *dst_filename = getPath2(directory, dst_basename); Bitmap *src_bitmap; Bitmap *bitmap; int yoffset_ce = 0; int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16); int i; SDLInitVideoDisplay(); ReCreateBitmap(&backbuffer, video.width, video.height); src_bitmap = LoadImage(src_filename); bitmap = CreateBitmap(TILEX * 16 * 2, TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16, DEFAULT_DEPTH); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int x = i % 16; int y = i / 16; int ii = i + 1; int j; BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY, TILEX * x, TILEY * y + yoffset_ce); BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY, TILEX * x + TILEX * 16, TILEY * y + yoffset_ce); for (j = 2; j >= 0; j--) { int c = ii % 10; BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10, TILEX * x + 6 + j * 7, TILEY * y + 11 + yoffset_ce); BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10, TILEX * 16 + TILEX * x + 6 + j * 8, TILEY * y + 10 + yoffset_ce); ii /= 10; } } for (i = 0; i < NUM_GROUP_ELEMENTS; i++) { int x = i % 16; int y = i / 16; int ii = i + 1; int j; BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY, TILEX * x, TILEY * y + yoffset_ge); BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY, TILEX * x + TILEX * 16, TILEY * y + yoffset_ge); for (j = 1; j >= 0; j--) { int c = ii % 10; BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10, TILEX * x + 6 + j * 10, TILEY * y + 11 + yoffset_ge); BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10, TILEX * 16 + TILEX * x + 10 + j * 8, TILEY * y + 10 + yoffset_ge); ii /= 10; } } if (SDL_SaveBMP(bitmap->surface, dst_filename) != 0) Error(ERR_EXIT, "cannot save CE graphics file '%s'", dst_filename); FreeBitmap(bitmap); CloseAllAndExit(0); #endif } mirrormagic-3.0.0/src/conf_mus.h0000644000175000017500000000374113263214151016107 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_mus.h // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_MUS_H #define CONF_MUS_H /* values for music configuration */ #define MUS_BACKGROUND 0 #define MUS_BACKGROUND_TITLE_INITIAL 1 #define MUS_BACKGROUND_TITLE 2 #define MUS_BACKGROUND_MAIN 3 #define MUS_BACKGROUND_LEVELS 4 #define MUS_BACKGROUND_LEVELNR 5 #define MUS_BACKGROUND_SCORES 6 #define MUS_BACKGROUND_EDITOR 7 #define MUS_BACKGROUND_INFO 8 #define MUS_BACKGROUND_SETUP 9 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_1 10 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_2 11 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_3 12 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_4 13 #define MUS_BACKGROUND_TITLESCREEN_INITIAL_5 14 #define MUS_BACKGROUND_TITLESCREEN_1 15 #define MUS_BACKGROUND_TITLESCREEN_2 16 #define MUS_BACKGROUND_TITLESCREEN_3 17 #define MUS_BACKGROUND_TITLESCREEN_4 18 #define MUS_BACKGROUND_TITLESCREEN_5 19 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 20 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_2 21 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_3 22 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_4 23 #define MUS_BACKGROUND_TITLEMESSAGE_INITIAL_5 24 #define MUS_BACKGROUND_TITLEMESSAGE_1 25 #define MUS_BACKGROUND_TITLEMESSAGE_2 26 #define MUS_BACKGROUND_TITLEMESSAGE_3 27 #define MUS_BACKGROUND_TITLEMESSAGE_4 28 #define MUS_BACKGROUND_TITLEMESSAGE_5 29 #define NUM_MUSIC_FILES 30 #endif /* CONF_MUS_H */ mirrormagic-3.0.0/src/editor.c0000644000175000017500000152355013263212010015555 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // editor.c // ============================================================================ #include #include "libgame/libgame.h" #include "editor.h" #include "screens.h" #include "tools.h" #include "files.h" #include "game.h" #include "init.h" #include "tape.h" #define INFOTEXT_UNKNOWN_ELEMENT "unknown" /* ----------------------------------------------------------------------------- screen and artwork graphic pixel position definitions ----------------------------------------------------------------------------- */ /* values for the control window */ #define ED_CTRL1_BUTTONS_HORIZ 4 /* toolbox */ #define ED_CTRL1_BUTTONS_VERT 4 #define ED_CTRL2_BUTTONS_HORIZ 3 /* level */ #define ED_CTRL2_BUTTONS_VERT 2 #define ED_CTRL3_BUTTONS_HORIZ 3 /* CE and GE */ #define ED_CTRL3_BUTTONS_VERT 1 #define ED_CTRL4_BUTTONS_HORIZ 2 /* CE and GE */ #define ED_CTRL4_BUTTONS_VERT 1 #define ED_CTRL5_BUTTONS_HORIZ 1 /* properties */ #define ED_CTRL5_BUTTONS_VERT 1 #define ED_CTRL6_BUTTONS_HORIZ 3 /* properties */ #define ED_CTRL6_BUTTONS_VERT 1 #define ED_CTRL7_BUTTONS_HORIZ 1 /* palette */ #define ED_CTRL7_BUTTONS_VERT 1 #define ED_NUM_CTRL1_BUTTONS (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT) #define ED_NUM_CTRL2_BUTTONS (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT) #define ED_NUM_CTRL3_BUTTONS (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT) #define ED_NUM_CTRL4_BUTTONS (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT) #define ED_NUM_CTRL5_BUTTONS (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT) #define ED_NUM_CTRL6_BUTTONS (ED_CTRL6_BUTTONS_HORIZ * ED_CTRL6_BUTTONS_VERT) #define ED_NUM_CTRL7_BUTTONS (ED_CTRL7_BUTTONS_HORIZ * ED_CTRL7_BUTTONS_VERT) #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS) #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS) #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS) #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS) #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS) #define ED_NUM_CTRL1_7_BUTTONS (ED_NUM_CTRL1_6_BUTTONS + ED_NUM_CTRL7_BUTTONS) #define ED_NUM_CTRL_BUTTONS ED_NUM_CTRL1_7_BUTTONS /* values for the element list */ #define ED_ELEMENTLIST_XPOS (editor.palette.x) #define ED_ELEMENTLIST_YPOS (editor.palette.y) #define ED_ELEMENTLIST_XSIZE (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width) #define ED_ELEMENTLIST_YSIZE (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height) #define ED_ELEMENTLIST_BUTTONS_HORIZ (editor.palette.cols) #define ED_ELEMENTLIST_BUTTONS_VERT (editor.palette.rows) #define ED_NUM_ELEMENTLIST_BUTTONS (ED_ELEMENTLIST_BUTTONS_HORIZ * \ ED_ELEMENTLIST_BUTTONS_VERT) /* standard distances */ #define ED_GADGET_NORMAL_DISTANCE (editor.gadget.normal_spacing) #define ED_GADGET_SMALL_DISTANCE (editor.gadget.small_spacing) #define ED_GADGET_TINY_DISTANCE (editor.gadget.tiny_spacing) #define ED_GADGET_LINE_DISTANCE (editor.gadget.line_spacing) #define ED_GADGET_TEXT_DISTANCE (editor.gadget.text_spacing) #define ED_TAB_BAR_HEIGHT (editor.gadget.separator_line.height) #define ED_DRAWINGAREA_TEXT_DISTANCE (ED_GADGET_TEXT_DISTANCE + \ ED_DRAWINGAREA_BORDER_SIZE) #define ED_GADGET_SPACE_DISTANCE (getFontWidth(FONT_TEXT_1)) /* values for drawingarea gadgets */ #define IMG_BORDER_1 IMG_EDITOR_ELEMENT_BORDER #define IMG_BORDER_2 IMG_EDITOR_ELEMENT_BORDER_INPUT #define ED_ELEMENT_BORDER (graphic_info[IMG_BORDER_1].border_size) #define ED_DRAWINGAREA_BORDER_SIZE (graphic_info[IMG_BORDER_2].border_size) #define ED_DRAWINGAREA_TILE_SIZE (editor.drawingarea.tile_size) /* values for checkbutton gadgets */ #define ED_CHECKBUTTON_XSIZE (graphic_info[IMG_EDITOR_CHECKBOX].width) #define ED_CHECKBUTTON_YSIZE (graphic_info[IMG_EDITOR_CHECKBOX].height) #define ED_TABBUTTON_XSIZE (graphic_info[IMG_EDITOR_TABBUTTON].width) #define ED_TABBUTTON_YSIZE (graphic_info[IMG_EDITOR_TABBUTTON].height) #define ED_SETTINGS_LEVEL_TABS_X (editor.settings.tabs.x) #define ED_SETTINGS_LEVEL_TABS_Y (editor.settings.tabs.y) #define ED_SETTINGS_ELEMENT_TABS_X (editor.settings.tabs.x) #define ED_SETTINGS_ELEMENT_TABS_Y (editor.settings.tabs.y + \ editor.settings.tabs.yoffset2) #define ED_SETTINGS_TABS_XOFFSET (editor.settings.tabs.draw_xoffset) #define ED_SETTINGS_TABS_YOFFSET (editor.settings.tabs.draw_yoffset) #define ED_LEVEL_TABS_XSTART (ED_SETTINGS_LEVEL_TABS_X) #define ED_LEVEL_TABS_YSTART (ED_SETTINGS_LEVEL_TABS_Y) #define ED_LEVEL_SETTINGS_XSTART (ED_SETTINGS_LEVEL_TABS_X + \ ED_SETTINGS_TABS_XOFFSET) #define ED_LEVEL_SETTINGS_YSTART (ED_SETTINGS_LEVEL_TABS_Y + \ ED_TABBUTTON_YSIZE + \ ED_GADGET_TINY_DISTANCE + \ ED_TAB_BAR_HEIGHT + \ ED_SETTINGS_TABS_YOFFSET + \ getFontHeight(FONT_TEXT_1) + \ ED_GADGET_TEXT_DISTANCE) #define ED_ELEMENT_TABS_XSTART (ED_SETTINGS_ELEMENT_TABS_X) #define ED_ELEMENT_TABS_YSTART (ED_SETTINGS_ELEMENT_TABS_Y) #define ED_ELEMENT_SETTINGS_XSTART (ED_SETTINGS_ELEMENT_TABS_X + \ ED_SETTINGS_TABS_XOFFSET) #define ED_ELEMENT_SETTINGS_YSTART (ED_SETTINGS_ELEMENT_TABS_Y + \ ED_TABBUTTON_YSIZE + \ ED_GADGET_TINY_DISTANCE + \ ED_TAB_BAR_HEIGHT + \ ED_SETTINGS_TABS_YOFFSET) #define ED_SETTINGS_XOFFSET (ED_CHECKBUTTON_XSIZE + \ ED_GADGET_TEXT_DISTANCE) #define ED_SETTINGS_YOFFSET (ED_CHECKBUTTON_YSIZE + \ ED_GADGET_LINE_DISTANCE) #define ED_POS_RANGE (10000) #define ED_POS_LEVEL_TABS_FIRST (1 * ED_POS_RANGE) #define ED_POS_LEVEL_TABS_LAST (2 * ED_POS_RANGE - 1) #define ED_POS_LEVEL_SETTINGS_FIRST (2 * ED_POS_RANGE) #define ED_POS_LEVEL_SETTINGS_LAST (3 * ED_POS_RANGE - 1) #define ED_POS_ELEMENT_TABS_FIRST (3 * ED_POS_RANGE) #define ED_POS_ELEMENT_TABS_LAST (4 * ED_POS_RANGE - 1) #define ED_POS_ELEMENT_SETTINGS_FIRST (4 * ED_POS_RANGE) #define ED_POS_ELEMENT_SETTINGS_LAST (5 * ED_POS_RANGE - 1) #define ED_LEVEL_TABS_XPOS(n) (ED_POS_LEVEL_TABS_FIRST + (n)) #define ED_LEVEL_TABS_YPOS(n) (ED_POS_LEVEL_TABS_FIRST + (n)) #define ED_LEVEL_SETTINGS_XPOS(n) (ED_POS_LEVEL_SETTINGS_FIRST + (n)) #define ED_LEVEL_SETTINGS_YPOS(n) (ED_POS_LEVEL_SETTINGS_FIRST + (n)) #define ED_ELEMENT_TABS_XPOS(n) (ED_POS_ELEMENT_TABS_FIRST + (n)) #define ED_ELEMENT_TABS_YPOS(n) (ED_POS_ELEMENT_TABS_FIRST + (n)) #define ED_ELEMENT_SETTINGS_XPOS(n) (ED_POS_ELEMENT_SETTINGS_FIRST + (n)) #define ED_ELEMENT_SETTINGS_YPOS(n) (ED_POS_ELEMENT_SETTINGS_FIRST + (n)) #define IS_POS_LEVEL_TABS(n) ((n) >= ED_POS_LEVEL_TABS_FIRST && \ (n) <= ED_POS_LEVEL_TABS_LAST) #define IS_POS_LEVEL_SETTINGS(n) ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \ (n) <= ED_POS_LEVEL_SETTINGS_LAST) #define IS_POS_ELEMENT_TABS(n) ((n) >= ED_POS_ELEMENT_TABS_FIRST && \ (n) <= ED_POS_ELEMENT_TABS_LAST) #define IS_POS_ELEMENT_SETTINGS(n) ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \ (n) <= ED_POS_ELEMENT_SETTINGS_LAST) #define ED_LEVEL_TABS_LINE(n) ((n) - ED_POS_LEVEL_TABS_FIRST) #define ED_LEVEL_SETTINGS_LINE(n) ((n) - ED_POS_LEVEL_SETTINGS_FIRST) #define ED_ELEMENT_TABS_LINE(n) ((n) - ED_POS_ELEMENT_TABS_FIRST) #define ED_ELEMENT_SETTINGS_LINE(n) ((n) - ED_POS_ELEMENT_SETTINGS_FIRST) #define ED_LEVEL_TABS_X(n) (ED_LEVEL_TABS_XSTART + \ (n) * ED_SETTINGS_TABS_XOFFSET) #define ED_LEVEL_TABS_Y(n) (ED_LEVEL_TABS_YSTART + \ (n) * ED_SETTINGS_TABS_YOFFSET) #define ED_LEVEL_SETTINGS_X(n) (ED_LEVEL_SETTINGS_XSTART + \ (n) * ED_SETTINGS_XOFFSET) #define ED_LEVEL_SETTINGS_Y(n) (ED_LEVEL_SETTINGS_YSTART + \ (n) * ED_SETTINGS_YOFFSET) #define ED_ELEMENT_TABS_X(n) (ED_ELEMENT_TABS_XSTART + \ (n) * ED_SETTINGS_TABS_XOFFSET) #define ED_ELEMENT_TABS_Y(n) (ED_ELEMENT_TABS_YSTART + \ (n) * ED_SETTINGS_TABS_YOFFSET) #define ED_ELEMENT_SETTINGS_X(n) (ED_ELEMENT_SETTINGS_XSTART + \ (n) * ED_SETTINGS_XOFFSET) #define ED_ELEMENT_SETTINGS_Y(n) (ED_ELEMENT_SETTINGS_YSTART + \ (n) * ED_SETTINGS_YOFFSET) #define ED_POS_TO_LEVEL_TABS_X(n) \ (ED_LEVEL_TABS_X(ED_LEVEL_TABS_LINE(n))) #define ED_POS_TO_LEVEL_TABS_Y(n) \ (ED_LEVEL_TABS_Y(ED_LEVEL_TABS_LINE(n))) #define ED_POS_TO_LEVEL_SETTINGS_X(n) \ (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n))) #define ED_POS_TO_LEVEL_SETTINGS_Y(n) \ (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n))) #define ED_POS_TO_ELEMENT_TABS_X(n) \ (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n))) #define ED_POS_TO_ELEMENT_TABS_Y(n) \ (ED_ELEMENT_TABS_Y(ED_ELEMENT_TABS_LINE(n))) #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \ (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n))) #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \ (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n))) #define ED_SETTINGS_X(n) (IS_POS_LEVEL_TABS(n) ? \ ED_POS_TO_LEVEL_TABS_X(n) : \ IS_POS_LEVEL_SETTINGS(n) ? \ ED_POS_TO_LEVEL_SETTINGS_X(n) : \ IS_POS_ELEMENT_TABS(n) ? \ ED_POS_TO_ELEMENT_TABS_X(n) : \ IS_POS_ELEMENT_SETTINGS(n) ? \ ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n)) #define ED_SETTINGS_Y(n) (IS_POS_LEVEL_TABS(n) ? \ ED_POS_TO_LEVEL_TABS_Y(n) : \ IS_POS_LEVEL_SETTINGS(n) ? \ ED_POS_TO_LEVEL_SETTINGS_Y(n) : \ IS_POS_ELEMENT_TABS(n) ? \ ED_POS_TO_ELEMENT_TABS_Y(n) : \ IS_POS_ELEMENT_SETTINGS(n) ? \ ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n)) #define ED_SETTINGS_XOFF(n) (5 * ((n) % 4) * \ ED_DRAWINGAREA_TILE_SIZE) #define ED_SETTINGS_YOFF(n) (5 * ((n) / 4) * \ ED_DRAWINGAREA_TILE_SIZE) #define ED_AREA_XOFFSET_1(n) ((n) != 0 ? \ ED_DRAWINGAREA_BORDER_SIZE : 0) #define ED_AREA_YOFFSET_1(n) ((n) != 0 ? \ (ED_CHECKBUTTON_YSIZE - \ ED_DRAWINGAREA_TILE_SIZE) / 2 : 0) #define ED_AREA_XOFFSET_2(n) (0) #define ED_AREA_YOFFSET_2(n) ((n) == 3 ? \ ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0) #define ED_AREA_SETTINGS_X(i) (ED_SETTINGS_X((i).x) + \ ED_SETTINGS_XOFF((i).xoffset) + \ ED_AREA_XOFFSET_1((i).x) - \ ED_AREA_XOFFSET_2((i).area_xsize)) #define ED_AREA_SETTINGS_Y(i) (ED_SETTINGS_Y((i).y) + \ ED_SETTINGS_YOFF((i).yoffset) + \ ED_AREA_YOFFSET_1((i).y) - \ ED_AREA_YOFFSET_2((i).area_ysize)) /* values for element content drawing areas */ #define ED_AREA_1X1_LSETTINGS_XPOS(n) ED_LEVEL_SETTINGS_XPOS(n) #define ED_AREA_1X1_LSETTINGS_YPOS(n) ED_LEVEL_SETTINGS_YPOS(n) #define ED_AREA_1X1_LSETTINGS_XOFF (0) #define ED_AREA_1X1_LSETTINGS_YOFF (0) #define ED_AREA_1X1_SETTINGS_XPOS(n) ED_ELEMENT_SETTINGS_XPOS(n) #define ED_AREA_1X1_SETTINGS_YPOS(n) ED_ELEMENT_SETTINGS_YPOS(n) #define ED_AREA_1X1_SETTINGS_XOFF (0) #define ED_AREA_1X1_SETTINGS_YOFF (0) #define ED_AREA_3X3_SETTINGS_XPOS(n) ED_ELEMENT_SETTINGS_XPOS(n) #define ED_AREA_3X3_SETTINGS_YPOS(n) ED_ELEMENT_SETTINGS_YPOS(n) #define ED_AREA_3X3_SETTINGS_XOFF (0) #define ED_AREA_3X3_SETTINGS_YOFF (0) /* element content */ #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n) #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n) /* yamyam content */ #define ED_XPOS_YAM 0 #define ED_YPOS_YAM 5 #define ED_AREA_YAMYAM_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM) #define ED_AREA_YAMYAM_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM) #define ED_AREA_YAMYAM_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n) #define ED_AREA_YAMYAM_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n) #define ED_AREA_YAMYAM_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \ ED_SETTINGS_XOFF(n)) #define ED_AREA_YAMYAM_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \ ED_SETTINGS_YOFF(n) + \ ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \ ED_AREA_YOFFSET_2(3)) /* magic ball content */ #define ED_XPOS_BALL 0 #define ED_YPOS_BALL 6 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL) #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL) #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n) #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n) #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \ ED_SETTINGS_XOFF(n)) #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \ ED_SETTINGS_YOFF(n) + \ ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \ ED_AREA_YOFFSET_2(3)) /* values for scrolling gadgets for drawing area */ #define ED_SCROLLBUTTON_XSIZE (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width) #define ED_SCROLLBUTTON_YSIZE (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height) #define ED_SCROLL_UP_XPOS (SXSIZE - ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_UP_YPOS (0) #define ED_SCROLL_DOWN_XPOS ED_SCROLL_UP_XPOS #define ED_SCROLL_DOWN_YPOS (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE) #define ED_SCROLL_LEFT_XPOS (0) #define ED_SCROLL_LEFT_YPOS (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE) #define ED_SCROLL_RIGHT_XPOS (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_RIGHT_YPOS ED_SCROLL_LEFT_YPOS #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + \ ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_HORIZONTAL_YPOS ED_SCROLL_LEFT_YPOS #define ED_SCROLL_HORIZONTAL_XSIZE (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE) #define ED_SCROLL_HORIZONTAL_YSIZE ED_SCROLLBUTTON_YSIZE #define ED_SCROLL_VERTICAL_XPOS ED_SCROLL_UP_XPOS #define ED_SCROLL_VERTICAL_YPOS (ED_SCROLL_UP_YPOS + \ ED_SCROLLBUTTON_YSIZE) #define ED_SCROLL_VERTICAL_XSIZE ED_SCROLLBUTTON_XSIZE #define ED_SCROLL_VERTICAL_YSIZE (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE) /* values for scrolling gadgets for element list */ #define ED_SCROLLBUTTON2_XSIZE (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width) #define ED_SCROLLBUTTON2_YSIZE (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height) #define ED_SCROLL2_UP_XPOS (ED_ELEMENTLIST_XPOS + \ ED_ELEMENTLIST_BUTTONS_HORIZ * \ ED_ELEMENTLIST_XSIZE) #define ED_SCROLL2_UP_YPOS ED_ELEMENTLIST_YPOS #define ED_SCROLL2_DOWN_XPOS ED_SCROLL2_UP_XPOS #define ED_SCROLL2_DOWN_YPOS (ED_SCROLL2_UP_YPOS + \ ED_ELEMENTLIST_BUTTONS_VERT * \ ED_ELEMENTLIST_YSIZE - \ ED_SCROLLBUTTON2_YSIZE) #define ED_SCROLL2_VERTICAL_XPOS ED_SCROLL2_UP_XPOS #define ED_SCROLL2_VERTICAL_YPOS (ED_SCROLL2_UP_YPOS + \ ED_SCROLLBUTTON2_YSIZE) #define ED_SCROLL2_VERTICAL_XSIZE ED_SCROLLBUTTON2_XSIZE #define ED_SCROLL2_VERTICAL_YSIZE (ED_ELEMENTLIST_BUTTONS_VERT * \ ED_ELEMENTLIST_YSIZE - \ 2 * ED_SCROLLBUTTON2_YSIZE) /* values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() */ #define INFOTEXT_FONT FONT_TEXT_2 #define INFOTEXT_XSIZE SXSIZE #define INFOTEXT_YSIZE getFontHeight(INFOTEXT_FONT) #define INFOTEXT_YSIZE_FULL (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE) #define INFOTEXT_X (editor.settings.tooltip.x) #define INFOTEXT_Y (editor.settings.tooltip.y) #define INFOTEXT_XY_REDEFINED (INFOTEXT_X != -1 || INFOTEXT_Y != -1) #define INFOTEXT_XPOS SX + (INFOTEXT_XY_REDEFINED ? INFOTEXT_X : 0) #define INFOTEXT_YPOS SY + (INFOTEXT_XY_REDEFINED ? INFOTEXT_Y : \ SYSIZE - INFOTEXT_YSIZE) /* ----------------------------------------------------------------------------- editor gadget definitions ----------------------------------------------------------------------------- */ /* drawing toolbox buttons */ #define GADGET_ID_NONE -1 #define GADGET_ID_TOOLBOX_FIRST 0 #define GADGET_ID_SINGLE_ITEMS (GADGET_ID_TOOLBOX_FIRST + 0) #define GADGET_ID_CONNECTED_ITEMS (GADGET_ID_TOOLBOX_FIRST + 1) #define GADGET_ID_LINE (GADGET_ID_TOOLBOX_FIRST + 2) #define GADGET_ID_ARC (GADGET_ID_TOOLBOX_FIRST + 3) #define GADGET_ID_RECTANGLE (GADGET_ID_TOOLBOX_FIRST + 4) #define GADGET_ID_FILLED_BOX (GADGET_ID_TOOLBOX_FIRST + 5) #define GADGET_ID_WRAP_UP (GADGET_ID_TOOLBOX_FIRST + 6) #define GADGET_ID_TEXT (GADGET_ID_TOOLBOX_FIRST + 7) #define GADGET_ID_FLOOD_FILL (GADGET_ID_TOOLBOX_FIRST + 8) #define GADGET_ID_WRAP_LEFT (GADGET_ID_TOOLBOX_FIRST + 9) #define GADGET_ID_ZOOM (GADGET_ID_TOOLBOX_FIRST + 10) #define GADGET_ID_WRAP_RIGHT (GADGET_ID_TOOLBOX_FIRST + 11) #define GADGET_ID_RANDOM_PLACEMENT (GADGET_ID_TOOLBOX_FIRST + 12) #define GADGET_ID_GRAB_BRUSH (GADGET_ID_TOOLBOX_FIRST + 13) #define GADGET_ID_WRAP_DOWN (GADGET_ID_TOOLBOX_FIRST + 14) #define GADGET_ID_PICK_ELEMENT (GADGET_ID_TOOLBOX_FIRST + 15) #define GADGET_ID_UNDO (GADGET_ID_TOOLBOX_FIRST + 16) #define GADGET_ID_INFO (GADGET_ID_TOOLBOX_FIRST + 17) #define GADGET_ID_SAVE (GADGET_ID_TOOLBOX_FIRST + 18) #define GADGET_ID_CLEAR (GADGET_ID_TOOLBOX_FIRST + 19) #define GADGET_ID_TEST (GADGET_ID_TOOLBOX_FIRST + 20) #define GADGET_ID_EXIT (GADGET_ID_TOOLBOX_FIRST + 21) #define GADGET_ID_CUSTOM_COPY_FROM (GADGET_ID_TOOLBOX_FIRST + 22) #define GADGET_ID_CUSTOM_COPY_TO (GADGET_ID_TOOLBOX_FIRST + 23) #define GADGET_ID_CUSTOM_EXCHANGE (GADGET_ID_TOOLBOX_FIRST + 24) #define GADGET_ID_CUSTOM_COPY (GADGET_ID_TOOLBOX_FIRST + 25) #define GADGET_ID_CUSTOM_PASTE (GADGET_ID_TOOLBOX_FIRST + 26) #define GADGET_ID_PROPERTIES (GADGET_ID_TOOLBOX_FIRST + 27) #define GADGET_ID_ELEMENT_LEFT (GADGET_ID_TOOLBOX_FIRST + 28) #define GADGET_ID_ELEMENT_MIDDLE (GADGET_ID_TOOLBOX_FIRST + 29) #define GADGET_ID_ELEMENT_RIGHT (GADGET_ID_TOOLBOX_FIRST + 30) #define GADGET_ID_PALETTE (GADGET_ID_TOOLBOX_FIRST + 31) /* counter gadget identifiers */ #define GADGET_ID_COUNTER_FIRST (GADGET_ID_TOOLBOX_FIRST + 32) #define GADGET_ID_SELECT_LEVEL_DOWN (GADGET_ID_COUNTER_FIRST + 0) #define GADGET_ID_SELECT_LEVEL_TEXT (GADGET_ID_COUNTER_FIRST + 1) #define GADGET_ID_SELECT_LEVEL_UP (GADGET_ID_COUNTER_FIRST + 2) #define GADGET_ID_LEVEL_XSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 3) #define GADGET_ID_LEVEL_XSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 4) #define GADGET_ID_LEVEL_XSIZE_UP (GADGET_ID_COUNTER_FIRST + 5) #define GADGET_ID_LEVEL_YSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 6) #define GADGET_ID_LEVEL_YSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 7) #define GADGET_ID_LEVEL_YSIZE_UP (GADGET_ID_COUNTER_FIRST + 8) #define GADGET_ID_LEVEL_RANDOM_DOWN (GADGET_ID_COUNTER_FIRST + 9) #define GADGET_ID_LEVEL_RANDOM_TEXT (GADGET_ID_COUNTER_FIRST + 10) #define GADGET_ID_LEVEL_RANDOM_UP (GADGET_ID_COUNTER_FIRST + 11) #define GADGET_ID_LEVEL_GEMSLIMIT_DOWN (GADGET_ID_COUNTER_FIRST + 12) #define GADGET_ID_LEVEL_GEMSLIMIT_TEXT (GADGET_ID_COUNTER_FIRST + 13) #define GADGET_ID_LEVEL_GEMSLIMIT_UP (GADGET_ID_COUNTER_FIRST + 14) #define GADGET_ID_LEVEL_TIMELIMIT_DOWN (GADGET_ID_COUNTER_FIRST + 15) #define GADGET_ID_LEVEL_TIMELIMIT_TEXT (GADGET_ID_COUNTER_FIRST + 16) #define GADGET_ID_LEVEL_TIMELIMIT_UP (GADGET_ID_COUNTER_FIRST + 17) #define GADGET_ID_LEVEL_TIMESCORE_DOWN (GADGET_ID_COUNTER_FIRST + 18) #define GADGET_ID_LEVEL_TIMESCORE_TEXT (GADGET_ID_COUNTER_FIRST + 19) #define GADGET_ID_LEVEL_TIMESCORE_UP (GADGET_ID_COUNTER_FIRST + 20) #define GADGET_ID_LEVEL_RANDOM_SEED_DOWN (GADGET_ID_COUNTER_FIRST + 21) #define GADGET_ID_LEVEL_RANDOM_SEED_TEXT (GADGET_ID_COUNTER_FIRST + 22) #define GADGET_ID_LEVEL_RANDOM_SEED_UP (GADGET_ID_COUNTER_FIRST + 23) #define GADGET_ID_LEVELSET_NUM_LEVELS_DOWN (GADGET_ID_COUNTER_FIRST + 24) #define GADGET_ID_LEVELSET_NUM_LEVELS_TEXT (GADGET_ID_COUNTER_FIRST + 25) #define GADGET_ID_LEVELSET_NUM_LEVELS_UP (GADGET_ID_COUNTER_FIRST + 26) #define GADGET_ID_ELEMENT_VALUE1_DOWN (GADGET_ID_COUNTER_FIRST + 27) #define GADGET_ID_ELEMENT_VALUE1_TEXT (GADGET_ID_COUNTER_FIRST + 28) #define GADGET_ID_ELEMENT_VALUE1_UP (GADGET_ID_COUNTER_FIRST + 29) #define GADGET_ID_ELEMENT_VALUE2_DOWN (GADGET_ID_COUNTER_FIRST + 30) #define GADGET_ID_ELEMENT_VALUE2_TEXT (GADGET_ID_COUNTER_FIRST + 31) #define GADGET_ID_ELEMENT_VALUE2_UP (GADGET_ID_COUNTER_FIRST + 32) #define GADGET_ID_ELEMENT_VALUE3_DOWN (GADGET_ID_COUNTER_FIRST + 33) #define GADGET_ID_ELEMENT_VALUE3_TEXT (GADGET_ID_COUNTER_FIRST + 34) #define GADGET_ID_ELEMENT_VALUE3_UP (GADGET_ID_COUNTER_FIRST + 35) #define GADGET_ID_ELEMENT_VALUE4_DOWN (GADGET_ID_COUNTER_FIRST + 36) #define GADGET_ID_ELEMENT_VALUE4_TEXT (GADGET_ID_COUNTER_FIRST + 37) #define GADGET_ID_ELEMENT_VALUE4_UP (GADGET_ID_COUNTER_FIRST + 38) #define GADGET_ID_YAMYAM_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 39) #define GADGET_ID_YAMYAM_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 40) #define GADGET_ID_YAMYAM_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 41) #define GADGET_ID_BALL_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 42) #define GADGET_ID_BALL_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 43) #define GADGET_ID_BALL_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 44) #define GADGET_ID_ANDROID_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 45) #define GADGET_ID_ANDROID_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 46) #define GADGET_ID_ANDROID_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 47) #define GADGET_ID_ENVELOPE_XSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 48) #define GADGET_ID_ENVELOPE_XSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 49) #define GADGET_ID_ENVELOPE_XSIZE_UP (GADGET_ID_COUNTER_FIRST + 50) #define GADGET_ID_ENVELOPE_YSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 51) #define GADGET_ID_ENVELOPE_YSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 52) #define GADGET_ID_ENVELOPE_YSIZE_UP (GADGET_ID_COUNTER_FIRST + 53) #define GADGET_ID_INVENTORY_SIZE_DOWN (GADGET_ID_COUNTER_FIRST + 54) #define GADGET_ID_INVENTORY_SIZE_TEXT (GADGET_ID_COUNTER_FIRST + 55) #define GADGET_ID_INVENTORY_SIZE_UP (GADGET_ID_COUNTER_FIRST + 56) #define GADGET_ID_CUSTOM_SCORE_DOWN (GADGET_ID_COUNTER_FIRST + 57) #define GADGET_ID_CUSTOM_SCORE_TEXT (GADGET_ID_COUNTER_FIRST + 58) #define GADGET_ID_CUSTOM_SCORE_UP (GADGET_ID_COUNTER_FIRST + 59) #define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 60) #define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 61) #define GADGET_ID_CUSTOM_GEMCOUNT_UP (GADGET_ID_COUNTER_FIRST + 62) #define GADGET_ID_CUSTOM_VALUE_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 63) #define GADGET_ID_CUSTOM_VALUE_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 64) #define GADGET_ID_CUSTOM_VALUE_FIX_UP (GADGET_ID_COUNTER_FIRST + 65) #define GADGET_ID_CUSTOM_VALUE_RND_DOWN (GADGET_ID_COUNTER_FIRST + 66) #define GADGET_ID_CUSTOM_VALUE_RND_TEXT (GADGET_ID_COUNTER_FIRST + 67) #define GADGET_ID_CUSTOM_VALUE_RND_UP (GADGET_ID_COUNTER_FIRST + 68) #define GADGET_ID_PUSH_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 69) #define GADGET_ID_PUSH_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 70) #define GADGET_ID_PUSH_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 71) #define GADGET_ID_PUSH_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 72) #define GADGET_ID_PUSH_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 73) #define GADGET_ID_PUSH_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 74) #define GADGET_ID_DROP_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 75) #define GADGET_ID_DROP_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 76) #define GADGET_ID_DROP_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 77) #define GADGET_ID_DROP_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 78) #define GADGET_ID_DROP_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 79) #define GADGET_ID_DROP_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 80) #define GADGET_ID_MOVE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 81) #define GADGET_ID_MOVE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 82) #define GADGET_ID_MOVE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 83) #define GADGET_ID_MOVE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 84) #define GADGET_ID_MOVE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 85) #define GADGET_ID_MOVE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 86) #define GADGET_ID_EXPLOSION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 87) #define GADGET_ID_EXPLOSION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 88) #define GADGET_ID_EXPLOSION_DELAY_UP (GADGET_ID_COUNTER_FIRST + 89) #define GADGET_ID_IGNITION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 90) #define GADGET_ID_IGNITION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 91) #define GADGET_ID_IGNITION_DELAY_UP (GADGET_ID_COUNTER_FIRST + 92) #define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 93) #define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 94) #define GADGET_ID_CHANGE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 95) #define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 96) #define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 97) #define GADGET_ID_CHANGE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 98) #define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 99) #define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 100) #define GADGET_ID_CHANGE_CONT_RND_UP (GADGET_ID_COUNTER_FIRST + 101) #define GADGET_ID_GROUP_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 102) #define GADGET_ID_GROUP_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 103) #define GADGET_ID_GROUP_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 104) /* drawing area identifiers */ #define GADGET_ID_DRAWING_AREA_FIRST (GADGET_ID_COUNTER_FIRST + 105) #define GADGET_ID_DRAWING_LEVEL (GADGET_ID_DRAWING_AREA_FIRST + 0) #define GADGET_ID_YAMYAM_CONTENT_0 (GADGET_ID_DRAWING_AREA_FIRST + 1) #define GADGET_ID_YAMYAM_CONTENT_1 (GADGET_ID_DRAWING_AREA_FIRST + 2) #define GADGET_ID_YAMYAM_CONTENT_2 (GADGET_ID_DRAWING_AREA_FIRST + 3) #define GADGET_ID_YAMYAM_CONTENT_3 (GADGET_ID_DRAWING_AREA_FIRST + 4) #define GADGET_ID_YAMYAM_CONTENT_4 (GADGET_ID_DRAWING_AREA_FIRST + 5) #define GADGET_ID_YAMYAM_CONTENT_5 (GADGET_ID_DRAWING_AREA_FIRST + 6) #define GADGET_ID_YAMYAM_CONTENT_6 (GADGET_ID_DRAWING_AREA_FIRST + 7) #define GADGET_ID_YAMYAM_CONTENT_7 (GADGET_ID_DRAWING_AREA_FIRST + 8) #define GADGET_ID_MAGIC_BALL_CONTENT_0 (GADGET_ID_DRAWING_AREA_FIRST + 9) #define GADGET_ID_MAGIC_BALL_CONTENT_1 (GADGET_ID_DRAWING_AREA_FIRST + 10) #define GADGET_ID_MAGIC_BALL_CONTENT_2 (GADGET_ID_DRAWING_AREA_FIRST + 11) #define GADGET_ID_MAGIC_BALL_CONTENT_3 (GADGET_ID_DRAWING_AREA_FIRST + 12) #define GADGET_ID_MAGIC_BALL_CONTENT_4 (GADGET_ID_DRAWING_AREA_FIRST + 13) #define GADGET_ID_MAGIC_BALL_CONTENT_5 (GADGET_ID_DRAWING_AREA_FIRST + 14) #define GADGET_ID_MAGIC_BALL_CONTENT_6 (GADGET_ID_DRAWING_AREA_FIRST + 15) #define GADGET_ID_MAGIC_BALL_CONTENT_7 (GADGET_ID_DRAWING_AREA_FIRST + 16) #define GADGET_ID_ANDROID_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 17) #define GADGET_ID_AMOEBA_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 18) #define GADGET_ID_START_ELEMENT (GADGET_ID_DRAWING_AREA_FIRST + 19) #define GADGET_ID_ARTWORK_ELEMENT (GADGET_ID_DRAWING_AREA_FIRST + 20) #define GADGET_ID_EXPLOSION_ELEMENT (GADGET_ID_DRAWING_AREA_FIRST + 21) #define GADGET_ID_INVENTORY_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 22) #define GADGET_ID_CUSTOM_GRAPHIC (GADGET_ID_DRAWING_AREA_FIRST + 23) #define GADGET_ID_CUSTOM_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 24) #define GADGET_ID_CUSTOM_MOVE_ENTER (GADGET_ID_DRAWING_AREA_FIRST + 25) #define GADGET_ID_CUSTOM_MOVE_LEAVE (GADGET_ID_DRAWING_AREA_FIRST + 26) #define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 27) #define GADGET_ID_CUSTOM_CHANGE_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 28) #define GADGET_ID_CUSTOM_CHANGE_TRIGGER (GADGET_ID_DRAWING_AREA_FIRST + 29) #define GADGET_ID_CUSTOM_CHANGE_ACTION (GADGET_ID_DRAWING_AREA_FIRST + 30) #define GADGET_ID_GROUP_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 31) #define GADGET_ID_RANDOM_BACKGROUND (GADGET_ID_DRAWING_AREA_FIRST + 32) /* text input identifiers */ #define GADGET_ID_TEXT_INPUT_FIRST (GADGET_ID_DRAWING_AREA_FIRST + 33) #define GADGET_ID_LEVEL_NAME (GADGET_ID_TEXT_INPUT_FIRST + 0) #define GADGET_ID_LEVEL_AUTHOR (GADGET_ID_TEXT_INPUT_FIRST + 1) #define GADGET_ID_LEVELSET_NAME (GADGET_ID_TEXT_INPUT_FIRST + 2) #define GADGET_ID_LEVELSET_AUTHOR (GADGET_ID_TEXT_INPUT_FIRST + 3) #define GADGET_ID_ELEMENT_NAME (GADGET_ID_TEXT_INPUT_FIRST + 4) /* text area identifiers */ #define GADGET_ID_TEXT_AREA_FIRST (GADGET_ID_TEXT_INPUT_FIRST + 5) #define GADGET_ID_ENVELOPE_INFO (GADGET_ID_TEXT_AREA_FIRST + 0) /* selectbox identifiers */ #define GADGET_ID_SELECTBOX_FIRST (GADGET_ID_TEXT_AREA_FIRST + 1) #define GADGET_ID_TIME_OR_STEPS (GADGET_ID_SELECTBOX_FIRST + 0) #define GADGET_ID_GAME_ENGINE_TYPE (GADGET_ID_SELECTBOX_FIRST + 1) #define GADGET_ID_LEVELSET_SAVE_MODE (GADGET_ID_SELECTBOX_FIRST + 2) #define GADGET_ID_WIND_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 3) #define GADGET_ID_PLAYER_SPEED (GADGET_ID_SELECTBOX_FIRST + 4) #define GADGET_ID_CUSTOM_WALK_TO_ACTION (GADGET_ID_SELECTBOX_FIRST + 5) #define GADGET_ID_CUSTOM_EXPLOSION_TYPE (GADGET_ID_SELECTBOX_FIRST + 6) #define GADGET_ID_CUSTOM_DEADLINESS (GADGET_ID_SELECTBOX_FIRST + 7) #define GADGET_ID_CUSTOM_MOVE_PATTERN (GADGET_ID_SELECTBOX_FIRST + 8) #define GADGET_ID_CUSTOM_MOVE_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 9) #define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 10) #define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 11) #define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 12) #define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 13) #define GADGET_ID_CUSTOM_ACCESS_TYPE (GADGET_ID_SELECTBOX_FIRST + 14) #define GADGET_ID_CUSTOM_ACCESS_LAYER (GADGET_ID_SELECTBOX_FIRST + 15) #define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 16) #define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 17) #define GADGET_ID_CHANGE_TIME_UNITS (GADGET_ID_SELECTBOX_FIRST + 18) #define GADGET_ID_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 19) #define GADGET_ID_CHANGE_OTHER_ACTION (GADGET_ID_SELECTBOX_FIRST + 20) #define GADGET_ID_CHANGE_SIDE (GADGET_ID_SELECTBOX_FIRST + 21) #define GADGET_ID_CHANGE_PLAYER (GADGET_ID_SELECTBOX_FIRST + 22) #define GADGET_ID_CHANGE_PAGE (GADGET_ID_SELECTBOX_FIRST + 23) #define GADGET_ID_CHANGE_REPLACE_WHEN (GADGET_ID_SELECTBOX_FIRST + 24) #define GADGET_ID_ACTION_TYPE (GADGET_ID_SELECTBOX_FIRST + 25) #define GADGET_ID_ACTION_MODE (GADGET_ID_SELECTBOX_FIRST + 26) #define GADGET_ID_ACTION_ARG (GADGET_ID_SELECTBOX_FIRST + 27) #define GADGET_ID_SELECT_CHANGE_PAGE (GADGET_ID_SELECTBOX_FIRST + 28) #define GADGET_ID_GROUP_CHOICE_MODE (GADGET_ID_SELECTBOX_FIRST + 29) /* textbutton identifiers */ #define GADGET_ID_TEXTBUTTON_FIRST (GADGET_ID_SELECTBOX_FIRST + 30) #define GADGET_ID_LEVELINFO_LEVEL (GADGET_ID_TEXTBUTTON_FIRST + 0) #define GADGET_ID_LEVELINFO_LEVELSET (GADGET_ID_TEXTBUTTON_FIRST + 1) #define GADGET_ID_LEVELINFO_EDITOR (GADGET_ID_TEXTBUTTON_FIRST + 2) #define GADGET_ID_PROPERTIES_INFO (GADGET_ID_TEXTBUTTON_FIRST + 3) #define GADGET_ID_PROPERTIES_CONFIG (GADGET_ID_TEXTBUTTON_FIRST + 4) #define GADGET_ID_PROPERTIES_CONFIG_1 (GADGET_ID_TEXTBUTTON_FIRST + 5) #define GADGET_ID_PROPERTIES_CONFIG_2 (GADGET_ID_TEXTBUTTON_FIRST + 6) #define GADGET_ID_PROPERTIES_CHANGE (GADGET_ID_TEXTBUTTON_FIRST + 7) #define GADGET_ID_SAVE_AS_TEMPLATE_1 (GADGET_ID_TEXTBUTTON_FIRST + 8) #define GADGET_ID_SAVE_AS_TEMPLATE_2 (GADGET_ID_TEXTBUTTON_FIRST + 9) #define GADGET_ID_SAVE_LEVELSET (GADGET_ID_TEXTBUTTON_FIRST + 10) #define GADGET_ID_ADD_CHANGE_PAGE (GADGET_ID_TEXTBUTTON_FIRST + 11) #define GADGET_ID_DEL_CHANGE_PAGE (GADGET_ID_TEXTBUTTON_FIRST + 12) /* graphicbutton identifiers */ #define GADGET_ID_GRAPHICBUTTON_FIRST (GADGET_ID_TEXTBUTTON_FIRST + 13) #define GADGET_ID_PREV_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 0) #define GADGET_ID_NEXT_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 1) #define GADGET_ID_COPY_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 2) #define GADGET_ID_PASTE_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 3) /* gadgets for scrolling of drawing area */ #define GADGET_ID_SCROLLING_FIRST (GADGET_ID_GRAPHICBUTTON_FIRST + 4) #define GADGET_ID_SCROLL_UP (GADGET_ID_SCROLLING_FIRST + 0) #define GADGET_ID_SCROLL_DOWN (GADGET_ID_SCROLLING_FIRST + 1) #define GADGET_ID_SCROLL_LEFT (GADGET_ID_SCROLLING_FIRST + 2) #define GADGET_ID_SCROLL_RIGHT (GADGET_ID_SCROLLING_FIRST + 3) #define GADGET_ID_SCROLL_HORIZONTAL (GADGET_ID_SCROLLING_FIRST + 4) #define GADGET_ID_SCROLL_VERTICAL (GADGET_ID_SCROLLING_FIRST + 5) /* gadgets for scrolling element list */ #define GADGET_ID_SCROLLING_LIST_FIRST (GADGET_ID_SCROLLING_FIRST + 6) #define GADGET_ID_SCROLL_LIST_UP (GADGET_ID_SCROLLING_LIST_FIRST + 0) #define GADGET_ID_SCROLL_LIST_DOWN (GADGET_ID_SCROLLING_LIST_FIRST + 1) #define GADGET_ID_SCROLL_LIST_VERTICAL (GADGET_ID_SCROLLING_LIST_FIRST + 2) /* checkbuttons/radiobuttons for level/element properties */ #define GADGET_ID_CHECKBUTTON_FIRST (GADGET_ID_SCROLLING_LIST_FIRST + 3) #define GADGET_ID_AUTO_COUNT_GEMS (GADGET_ID_CHECKBUTTON_FIRST + 0) #define GADGET_ID_USE_LEVELSET_ARTWORK (GADGET_ID_CHECKBUTTON_FIRST + 1) #define GADGET_ID_COPY_LEVEL_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 2) #define GADGET_ID_RANDOM_PERCENTAGE (GADGET_ID_CHECKBUTTON_FIRST + 3) #define GADGET_ID_RANDOM_QUANTITY (GADGET_ID_CHECKBUTTON_FIRST + 4) #define GADGET_ID_RANDOM_RESTRICTED (GADGET_ID_CHECKBUTTON_FIRST + 5) #define GADGET_ID_STICK_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 6) #define GADGET_ID_EM_SLIPPERY_GEMS (GADGET_ID_CHECKBUTTON_FIRST + 7) #define GADGET_ID_EM_EXPLODES_BY_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 8) #define GADGET_ID_USE_SPRING_BUG (GADGET_ID_CHECKBUTTON_FIRST + 9) #define GADGET_ID_USE_TIME_ORB_BUG (GADGET_ID_CHECKBUTTON_FIRST + 10) #define GADGET_ID_RANDOM_BALL_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 11) #define GADGET_ID_INITIAL_BALL_STATE (GADGET_ID_CHECKBUTTON_FIRST + 12) #define GADGET_ID_GROW_INTO_DIGGABLE (GADGET_ID_CHECKBUTTON_FIRST + 13) #define GADGET_ID_AUTO_EXIT_SOKOBAN (GADGET_ID_CHECKBUTTON_FIRST + 14) #define GADGET_ID_CONTINUOUS_SNAPPING (GADGET_ID_CHECKBUTTON_FIRST + 15) #define GADGET_ID_BLOCK_SNAP_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 16) #define GADGET_ID_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 17) #define GADGET_ID_SP_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 18) #define GADGET_ID_INSTANT_RELOCATION (GADGET_ID_CHECKBUTTON_FIRST + 19) #define GADGET_ID_SHIFTED_RELOCATION (GADGET_ID_CHECKBUTTON_FIRST + 20) #define GADGET_ID_LAZY_RELOCATION (GADGET_ID_CHECKBUTTON_FIRST + 21) #define GADGET_ID_USE_START_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 22) #define GADGET_ID_USE_ARTWORK_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 23) #define GADGET_ID_USE_EXPLOSION_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 24) #define GADGET_ID_INITIAL_GRAVITY (GADGET_ID_CHECKBUTTON_FIRST + 25) #define GADGET_ID_USE_INITIAL_INVENTORY (GADGET_ID_CHECKBUTTON_FIRST + 26) #define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 27) #define GADGET_ID_CAN_FALL_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 28) #define GADGET_ID_CAN_MOVE_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 29) #define GADGET_ID_DONT_COLLIDE_WITH (GADGET_ID_CHECKBUTTON_FIRST + 30) #define GADGET_ID_ENVELOPE_AUTOWRAP (GADGET_ID_CHECKBUTTON_FIRST + 31) #define GADGET_ID_ENVELOPE_CENTERED (GADGET_ID_CHECKBUTTON_FIRST + 32) #define GADGET_ID_MM_LASER_RED (GADGET_ID_CHECKBUTTON_FIRST + 33) #define GADGET_ID_MM_LASER_GREEN (GADGET_ID_CHECKBUTTON_FIRST + 34) #define GADGET_ID_MM_LASER_BLUE (GADGET_ID_CHECKBUTTON_FIRST + 35) #define GADGET_ID_DF_LASER_RED (GADGET_ID_CHECKBUTTON_FIRST + 36) #define GADGET_ID_DF_LASER_GREEN (GADGET_ID_CHECKBUTTON_FIRST + 37) #define GADGET_ID_DF_LASER_BLUE (GADGET_ID_CHECKBUTTON_FIRST + 38) #define GADGET_ID_CUSTOM_INDESTRUCTIBLE (GADGET_ID_CHECKBUTTON_FIRST + 39) #define GADGET_ID_CUSTOM_CAN_EXPLODE (GADGET_ID_CHECKBUTTON_FIRST + 40) #define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 41) #define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 42) #define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 43) #define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 44) #define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 45) #define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 46) #define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 47) #define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 48) #define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 49) #define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 50) #define GADGET_ID_CUSTOM_GRAV_REACHABLE (GADGET_ID_CHECKBUTTON_FIRST + 51) #define GADGET_ID_CUSTOM_USE_LAST_VALUE (GADGET_ID_CHECKBUTTON_FIRST + 52) #define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 53) #define GADGET_ID_CUSTOM_USE_TEMPLATE_1 (GADGET_ID_CHECKBUTTON_FIRST + 54) #define GADGET_ID_CUSTOM_USE_TEMPLATE_2 (GADGET_ID_CHECKBUTTON_FIRST + 55) #define GADGET_ID_CUSTOM_USE_TEMPLATE_3 (GADGET_ID_CHECKBUTTON_FIRST + 56) #define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 57) #define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 58) #define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 59) #define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 60) #define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 61) #define GADGET_ID_CHANGE_HAS_ACTION (GADGET_ID_CHECKBUTTON_FIRST + 62) #define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 63) #define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 64) #define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 65) /* gadgets for buttons in element list */ #define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 66) #define GADGET_ID_ELEMENTLIST_LAST (GADGET_ID_ELEMENTLIST_FIRST + \ ED_NUM_ELEMENTLIST_BUTTONS - 1) #define NUM_EDITOR_GADGETS (GADGET_ID_ELEMENTLIST_LAST + 1) /* radio button numbers */ #define RADIO_NR_NONE 0 #define RADIO_NR_DRAWING_TOOLBOX 1 #define RADIO_NR_RANDOM_ELEMENTS 2 /* values for counter gadgets */ #define ED_COUNTER_ID_SELECT_LEVEL 0 #define ED_COUNTER_ID_LEVEL_XSIZE 1 #define ED_COUNTER_ID_LEVEL_YSIZE 2 #define ED_COUNTER_ID_LEVEL_GEMSLIMIT 3 #define ED_COUNTER_ID_LEVEL_TIMELIMIT 4 #define ED_COUNTER_ID_LEVEL_TIMESCORE 5 #define ED_COUNTER_ID_LEVEL_RANDOM_SEED 6 #define ED_COUNTER_ID_LEVELSET_NUM_LEVELS 7 #define ED_COUNTER_ID_LEVEL_RANDOM 8 #define ED_COUNTER_ID_ELEMENT_VALUE1 9 #define ED_COUNTER_ID_ELEMENT_VALUE2 10 #define ED_COUNTER_ID_ELEMENT_VALUE3 11 #define ED_COUNTER_ID_ELEMENT_VALUE4 12 #define ED_COUNTER_ID_YAMYAM_CONTENT 13 #define ED_COUNTER_ID_BALL_CONTENT 14 #define ED_COUNTER_ID_ANDROID_CONTENT 15 #define ED_COUNTER_ID_ENVELOPE_XSIZE 16 #define ED_COUNTER_ID_ENVELOPE_YSIZE 17 #define ED_COUNTER_ID_INVENTORY_SIZE 18 #define ED_COUNTER_ID_CUSTOM_SCORE 19 #define ED_COUNTER_ID_CUSTOM_GEMCOUNT 20 #define ED_COUNTER_ID_CUSTOM_VALUE_FIX 21 #define ED_COUNTER_ID_CUSTOM_VALUE_RND 22 #define ED_COUNTER_ID_PUSH_DELAY_FIX 23 #define ED_COUNTER_ID_PUSH_DELAY_RND 24 #define ED_COUNTER_ID_DROP_DELAY_FIX 25 #define ED_COUNTER_ID_DROP_DELAY_RND 26 #define ED_COUNTER_ID_MOVE_DELAY_FIX 27 #define ED_COUNTER_ID_MOVE_DELAY_RND 28 #define ED_COUNTER_ID_EXPLOSION_DELAY 29 #define ED_COUNTER_ID_IGNITION_DELAY 30 #define ED_COUNTER_ID_GROUP_CONTENT 31 #define ED_COUNTER_ID_CHANGE_DELAY_FIX 32 #define ED_COUNTER_ID_CHANGE_DELAY_RND 33 #define ED_COUNTER_ID_CHANGE_CONT_RND 34 #define ED_NUM_COUNTERBUTTONS 35 #define ED_COUNTER_ID_LEVEL_FIRST ED_COUNTER_ID_LEVEL_XSIZE #define ED_COUNTER_ID_LEVEL_LAST ED_COUNTER_ID_LEVEL_RANDOM_SEED #define ED_COUNTER_ID_LEVELSET_FIRST ED_COUNTER_ID_LEVELSET_NUM_LEVELS #define ED_COUNTER_ID_LEVELSET_LAST ED_COUNTER_ID_LEVELSET_NUM_LEVELS #define ED_COUNTER_ID_EDITOR_FIRST ED_COUNTER_ID_LEVEL_RANDOM #define ED_COUNTER_ID_EDITOR_LAST ED_COUNTER_ID_LEVEL_RANDOM #define ED_COUNTER_ID_CUSTOM1_FIRST ED_COUNTER_ID_CUSTOM_SCORE #define ED_COUNTER_ID_CUSTOM1_LAST ED_COUNTER_ID_DROP_DELAY_RND #define ED_COUNTER_ID_CUSTOM2_FIRST ED_COUNTER_ID_MOVE_DELAY_FIX #define ED_COUNTER_ID_CUSTOM2_LAST ED_COUNTER_ID_IGNITION_DELAY #define ED_COUNTER_ID_CUSTOM_FIRST ED_COUNTER_ID_CUSTOM1_FIRST #define ED_COUNTER_ID_CUSTOM_LAST ED_COUNTER_ID_CUSTOM2_LAST #define ED_COUNTER_ID_CHANGE_FIRST ED_COUNTER_ID_CHANGE_DELAY_FIX #define ED_COUNTER_ID_CHANGE_LAST ED_COUNTER_ID_CHANGE_CONT_RND /* values for scrollbutton gadgets */ #define ED_SCROLLBUTTON_ID_AREA_UP 0 #define ED_SCROLLBUTTON_ID_AREA_DOWN 1 #define ED_SCROLLBUTTON_ID_AREA_LEFT 2 #define ED_SCROLLBUTTON_ID_AREA_RIGHT 3 #define ED_SCROLLBUTTON_ID_LIST_UP 4 #define ED_SCROLLBUTTON_ID_LIST_DOWN 5 #define ED_NUM_SCROLLBUTTONS 6 #define ED_SCROLLBUTTON_ID_AREA_FIRST ED_SCROLLBUTTON_ID_AREA_UP #define ED_SCROLLBUTTON_ID_AREA_LAST ED_SCROLLBUTTON_ID_AREA_RIGHT /* values for scrollbar gadgets */ #define ED_SCROLLBAR_ID_AREA_HORIZONTAL 0 #define ED_SCROLLBAR_ID_AREA_VERTICAL 1 #define ED_SCROLLBAR_ID_LIST_VERTICAL 2 #define ED_NUM_SCROLLBARS 3 #define ED_SCROLLBAR_ID_AREA_FIRST ED_SCROLLBAR_ID_AREA_HORIZONTAL #define ED_SCROLLBAR_ID_AREA_LAST ED_SCROLLBAR_ID_AREA_VERTICAL /* values for text input gadgets */ #define ED_TEXTINPUT_ID_LEVEL_NAME 0 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR 1 #define ED_TEXTINPUT_ID_LEVELSET_NAME 2 #define ED_TEXTINPUT_ID_LEVELSET_AUTHOR 3 #define ED_TEXTINPUT_ID_ELEMENT_NAME 4 #define ED_NUM_TEXTINPUT 5 #define ED_TEXTINPUT_ID_LEVEL_FIRST ED_TEXTINPUT_ID_LEVEL_NAME #define ED_TEXTINPUT_ID_LEVEL_LAST ED_TEXTINPUT_ID_LEVEL_AUTHOR #define ED_TEXTINPUT_ID_LEVELSET_FIRST ED_TEXTINPUT_ID_LEVELSET_NAME #define ED_TEXTINPUT_ID_LEVELSET_LAST ED_TEXTINPUT_ID_LEVELSET_AUTHOR /* values for text area gadgets */ #define ED_TEXTAREA_ID_ENVELOPE_INFO 0 #define ED_NUM_TEXTAREAS 1 #define ED_TEXTAREA_ID_LEVEL_FIRST ED_TEXTAREA_ID_ENVELOPE #define ED_TEXTAREA_ID_LEVEL_LAST ED_TEXTAREA_ID_ENVELOPE /* values for selectbox gadgets */ #define ED_SELECTBOX_ID_TIME_OR_STEPS 0 #define ED_SELECTBOX_ID_GAME_ENGINE_TYPE 1 #define ED_SELECTBOX_ID_LEVELSET_SAVE_MODE 2 #define ED_SELECTBOX_ID_WIND_DIRECTION 3 #define ED_SELECTBOX_ID_PLAYER_SPEED 4 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE 5 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER 6 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED 7 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION 8 #define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION 9 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN 10 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION 11 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE 12 #define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE 13 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS 14 #define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE 15 #define ED_SELECTBOX_ID_CUSTOM_DEADLINESS 16 #define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE 17 #define ED_SELECTBOX_ID_CHANGE_TIME_UNITS 18 #define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION 19 #define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION 20 #define ED_SELECTBOX_ID_CHANGE_SIDE 21 #define ED_SELECTBOX_ID_CHANGE_PLAYER 22 #define ED_SELECTBOX_ID_CHANGE_PAGE 23 #define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN 24 #define ED_SELECTBOX_ID_ACTION_TYPE 25 #define ED_SELECTBOX_ID_ACTION_MODE 26 #define ED_SELECTBOX_ID_ACTION_ARG 27 #define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE 28 #define ED_SELECTBOX_ID_GROUP_CHOICE_MODE 29 #define ED_NUM_SELECTBOX 30 #define ED_SELECTBOX_ID_LEVEL_FIRST ED_SELECTBOX_ID_TIME_OR_STEPS #define ED_SELECTBOX_ID_LEVEL_LAST ED_SELECTBOX_ID_GAME_ENGINE_TYPE #define ED_SELECTBOX_ID_LEVELSET_FIRST ED_SELECTBOX_ID_LEVELSET_SAVE_MODE #define ED_SELECTBOX_ID_LEVELSET_LAST ED_SELECTBOX_ID_LEVELSET_SAVE_MODE #define ED_SELECTBOX_ID_CUSTOM1_FIRST ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE #define ED_SELECTBOX_ID_CUSTOM1_LAST ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION #define ED_SELECTBOX_ID_CUSTOM2_FIRST ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN #define ED_SELECTBOX_ID_CUSTOM2_LAST ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE #define ED_SELECTBOX_ID_CUSTOM_FIRST ED_SELECTBOX_ID_CUSTOM1_FIRST #define ED_SELECTBOX_ID_CUSTOM_LAST ED_SELECTBOX_ID_CUSTOM2_LAST #define ED_SELECTBOX_ID_CHANGE_FIRST ED_SELECTBOX_ID_CHANGE_TIME_UNITS #define ED_SELECTBOX_ID_CHANGE_LAST ED_SELECTBOX_ID_SELECT_CHANGE_PAGE /* values for textbutton gadgets */ #define ED_TEXTBUTTON_ID_LEVELINFO_LEVEL 0 #define ED_TEXTBUTTON_ID_LEVELINFO_LEVELSET 1 #define ED_TEXTBUTTON_ID_LEVELINFO_EDITOR 2 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO 3 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG 4 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1 5 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2 6 #define ED_TEXTBUTTON_ID_PROPERTIES_CHANGE 7 #define ED_TEXTBUTTON_ID_SAVE_LEVELSET 8 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2 9 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 10 #define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE 11 #define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE 12 #define ED_NUM_TEXTBUTTONS 13 #define ED_TAB_BUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL #define ED_TAB_BUTTON_ID_LEVELINFO_LAST ED_TEXTBUTTON_ID_LEVELINFO_EDITOR #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO #define ED_TAB_BUTTON_ID_PROPERTIES_LAST ED_TEXTBUTTON_ID_PROPERTIES_CHANGE #define ED_TEXTBUTTON_ID_CHANGE_FIRST ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE #define ED_TEXTBUTTON_ID_CHANGE_LAST ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE /* values for graphicbutton gadgets */ #define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE 0 #define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE 1 #define ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE 2 #define ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE 3 #define ED_NUM_GRAPHICBUTTONS 4 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE #define ED_GRAPHICBUTTON_ID_CHANGE_LAST ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE /* values for checkbutton gadgets */ #define ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS 0 #define ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK 1 #define ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE 2 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED 3 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3 4 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2 5 #define ED_CHECKBUTTON_ID_STICK_ELEMENT 6 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS 7 #define ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE 8 #define ED_CHECKBUTTON_ID_USE_SPRING_BUG 9 #define ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG 10 #define ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT 11 #define ED_CHECKBUTTON_ID_INITIAL_BALL_STATE 12 #define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE 13 #define ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN 14 #define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING 15 #define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD 16 #define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD 17 #define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD 18 #define ED_CHECKBUTTON_ID_INSTANT_RELOCATION 19 #define ED_CHECKBUTTON_ID_SHIFTED_RELOCATION 20 #define ED_CHECKBUTTON_ID_LAZY_RELOCATION 21 #define ED_CHECKBUTTON_ID_USE_START_ELEMENT 22 #define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT 23 #define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT 24 #define ED_CHECKBUTTON_ID_INITIAL_GRAVITY 25 #define ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY 26 #define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 27 #define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID 28 #define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID 29 #define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH 30 #define ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP 31 #define ED_CHECKBUTTON_ID_ENVELOPE_CENTERED 32 #define ED_CHECKBUTTON_ID_MM_LASER_RED 33 #define ED_CHECKBUTTON_ID_MM_LASER_GREEN 34 #define ED_CHECKBUTTON_ID_MM_LASER_BLUE 35 #define ED_CHECKBUTTON_ID_DF_LASER_RED 36 #define ED_CHECKBUTTON_ID_DF_LASER_GREEN 37 #define ED_CHECKBUTTON_ID_DF_LASER_BLUE 38 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 39 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 40 #define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 41 #define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE 42 #define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE 43 #define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 44 #define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE 45 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 46 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 47 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 48 #define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 49 #define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 50 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE 51 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 52 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 53 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 54 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 55 #define ED_CHECKBUTTON_ID_CHANGE_DELAY 56 #define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 57 #define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 58 #define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 59 #define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 60 #define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 61 #define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 62 #define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION 63 #define ED_NUM_CHECKBUTTONS 64 #define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS #define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK #define ED_CHECKBUTTON_ID_LEVELSET_LAST ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE #define ED_CHECKBUTTON_ID_EDITOR_FIRST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED #define ED_CHECKBUTTON_ID_EDITOR_LAST ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC #define ED_CHECKBUTTON_ID_CUSTOM1_LAST ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE #define ED_CHECKBUTTON_ID_CUSTOM2_LAST ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT #define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM1_FIRST #define ED_CHECKBUTTON_ID_CUSTOM_LAST ED_CHECKBUTTON_ID_CUSTOM2_LAST #define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE #define ED_CHECKBUTTON_ID_CHANGE_LAST ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION /* values for radiobutton gadgets */ #define ED_RADIOBUTTON_ID_PERCENTAGE 0 #define ED_RADIOBUTTON_ID_QUANTITY 1 #define ED_NUM_RADIOBUTTONS 2 #define ED_RADIOBUTTON_ID_EDITOR_FIRST ED_RADIOBUTTON_ID_PERCENTAGE #define ED_RADIOBUTTON_ID_EDITOR_LAST ED_RADIOBUTTON_ID_QUANTITY /* values for drawing area gadgets */ #define ED_DRAWING_ID_DRAWING_LEVEL 0 #define ED_DRAWING_ID_YAMYAM_CONTENT_0 1 #define ED_DRAWING_ID_YAMYAM_CONTENT_1 2 #define ED_DRAWING_ID_YAMYAM_CONTENT_2 3 #define ED_DRAWING_ID_YAMYAM_CONTENT_3 4 #define ED_DRAWING_ID_YAMYAM_CONTENT_4 5 #define ED_DRAWING_ID_YAMYAM_CONTENT_5 6 #define ED_DRAWING_ID_YAMYAM_CONTENT_6 7 #define ED_DRAWING_ID_YAMYAM_CONTENT_7 8 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 9 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_1 10 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_2 11 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_3 12 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_4 13 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_5 14 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_6 15 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_7 16 #define ED_DRAWING_ID_ANDROID_CONTENT 17 #define ED_DRAWING_ID_AMOEBA_CONTENT 18 #define ED_DRAWING_ID_START_ELEMENT 19 #define ED_DRAWING_ID_ARTWORK_ELEMENT 20 #define ED_DRAWING_ID_EXPLOSION_ELEMENT 21 #define ED_DRAWING_ID_INVENTORY_CONTENT 22 #define ED_DRAWING_ID_CUSTOM_GRAPHIC 23 #define ED_DRAWING_ID_CUSTOM_CONTENT 24 #define ED_DRAWING_ID_CUSTOM_MOVE_ENTER 25 #define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE 26 #define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET 27 #define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT 28 #define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER 29 #define ED_DRAWING_ID_CUSTOM_CHANGE_ACTION 30 #define ED_DRAWING_ID_GROUP_CONTENT 31 #define ED_DRAWING_ID_RANDOM_BACKGROUND 32 #define ED_NUM_DRAWING_AREAS 33 #define ED_DRAWING_ID_EDITOR_FIRST ED_DRAWING_ID_RANDOM_BACKGROUND #define ED_DRAWING_ID_EDITOR_LAST ED_DRAWING_ID_RANDOM_BACKGROUND /* ----------------------------------------------------------------------------- some internally used definitions ----------------------------------------------------------------------------- */ /* values for CopyLevelToUndoBuffer() */ #define UNDO_IMMEDIATE 0 #define UNDO_ACCUMULATE 1 /* values for scrollbars */ #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 /* screens in the level editor */ #define ED_MODE_DRAWING 0 #define ED_MODE_INFO 1 #define ED_MODE_PROPERTIES 2 #define ED_MODE_PALETTE 3 /* sub-screens in the global settings section */ #define ED_MODE_LEVELINFO_LEVEL ED_TEXTBUTTON_ID_LEVELINFO_LEVEL #define ED_MODE_LEVELINFO_LEVELSET ED_TEXTBUTTON_ID_LEVELINFO_LEVELSET #define ED_MODE_LEVELINFO_EDITOR ED_TEXTBUTTON_ID_LEVELINFO_EDITOR /* sub-screens in the element properties section */ #define ED_MODE_PROPERTIES_INFO ED_TEXTBUTTON_ID_PROPERTIES_INFO #define ED_MODE_PROPERTIES_CONFIG ED_TEXTBUTTON_ID_PROPERTIES_CONFIG #define ED_MODE_PROPERTIES_CONFIG_1 ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1 #define ED_MODE_PROPERTIES_CONFIG_2 ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2 #define ED_MODE_PROPERTIES_CHANGE ED_TEXTBUTTON_ID_PROPERTIES_CHANGE /* how many steps can be cancelled */ #define NUM_UNDO_STEPS (64 + 1) /* values for elements with score for certain actions */ #define MIN_SCORE 0 #define MAX_SCORE 999 /* values for elements with count for collecting */ #define MIN_COLLECT_COUNT 0 #define MAX_COLLECT_COUNT 999 /* values for random placement */ #define RANDOM_USE_PERCENTAGE 0 #define RANDOM_USE_QUANTITY 1 /* values for level set save mode */ #define LEVELSET_SAVE_MODE_UPDATE 0 #define LEVELSET_SAVE_MODE_CREATE 1 /* default value for element tile size in drawing area */ #define DEFAULT_EDITOR_TILESIZE MINI_TILESIZE #define DEFAULT_EDITOR_TILESIZE_MM TILESIZE /* ----------------------------------------------------------------------------- some internally used data structure definitions ----------------------------------------------------------------------------- */ static struct { int graphic; int gadget_id; struct XYTileSize *pos; int gadget_type; char *infotext; char shortcut; } controlbutton_info[ED_NUM_CTRL_BUTTONS] = { /* note: some additional characters are already reserved for "cheat mode" shortcuts (":XYZ" style) -- for details, see "events.c" */ /* ---------- toolbox control buttons ------------------------------------ */ { IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE, GADGET_ID_SINGLE_ITEMS, &editor.button.draw_single, GD_TYPE_RADIO_BUTTON, "draw single items", 's' }, { IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED, GADGET_ID_CONNECTED_ITEMS, &editor.button.draw_connected, GD_TYPE_RADIO_BUTTON, "draw connected items", 'd' }, { IMG_GFX_EDITOR_BUTTON_DRAW_LINE, GADGET_ID_LINE, &editor.button.draw_line, GD_TYPE_RADIO_BUTTON, "draw lines", 'l' }, { IMG_GFX_EDITOR_BUTTON_DRAW_ARC, GADGET_ID_ARC, &editor.button.draw_arc, GD_TYPE_RADIO_BUTTON, "draw arcs", 'a' }, { IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE, GADGET_ID_RECTANGLE, &editor.button.draw_rectangle, GD_TYPE_RADIO_BUTTON, "draw outline rectangles", 'r' }, { IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX, GADGET_ID_FILLED_BOX, &editor.button.draw_filled_box, GD_TYPE_RADIO_BUTTON, "draw filled rectangles", 'R' }, { IMG_GFX_EDITOR_BUTTON_ROTATE_UP, GADGET_ID_WRAP_UP, &editor.button.rotate_up, GD_TYPE_NORMAL_BUTTON, "wrap (rotate) level up", 0 }, { IMG_GFX_EDITOR_BUTTON_DRAW_TEXT, GADGET_ID_TEXT, &editor.button.draw_text, GD_TYPE_RADIO_BUTTON, "enter text elements", 't' }, { IMG_GFX_EDITOR_BUTTON_FLOOD_FILL, GADGET_ID_FLOOD_FILL, &editor.button.flood_fill, GD_TYPE_RADIO_BUTTON, "flood fill", 'f' }, { IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT, GADGET_ID_WRAP_LEFT, &editor.button.rotate_left, GD_TYPE_NORMAL_BUTTON, "wrap (rotate) level left", 0 }, { IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL, GADGET_ID_ZOOM, &editor.button.zoom_level, GD_TYPE_NORMAL_BUTTON, "zoom level tile size", '+' }, { IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT, GADGET_ID_WRAP_RIGHT, &editor.button.rotate_right, GD_TYPE_NORMAL_BUTTON, "wrap (rotate) level right", 0 }, { IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM, GADGET_ID_RANDOM_PLACEMENT, &editor.button.draw_random, GD_TYPE_NORMAL_BUTTON, "random element placement", 0 }, { IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH, GADGET_ID_GRAB_BRUSH, &editor.button.grab_brush, GD_TYPE_RADIO_BUTTON, "grab brush", 'b' }, { IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN, GADGET_ID_WRAP_DOWN, &editor.button.rotate_down, GD_TYPE_NORMAL_BUTTON, "wrap (rotate) level down", 0 }, { IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT, GADGET_ID_PICK_ELEMENT, &editor.button.pick_element, GD_TYPE_RADIO_BUTTON, "pick drawing element", ',' }, /* ---------- level control buttons -------------------------------------- */ { IMG_GFX_EDITOR_BUTTON_UNDO, GADGET_ID_UNDO, &editor.button.undo, GD_TYPE_NORMAL_BUTTON, "undo/redo last operation", 'u' }, { IMG_GFX_EDITOR_BUTTON_CONF, GADGET_ID_INFO, &editor.button.conf, GD_TYPE_NORMAL_BUTTON, "properties of level", 'I' }, { IMG_GFX_EDITOR_BUTTON_SAVE, GADGET_ID_SAVE, &editor.button.save, GD_TYPE_NORMAL_BUTTON, "save level", 'S' }, { IMG_GFX_EDITOR_BUTTON_CLEAR, GADGET_ID_CLEAR, &editor.button.clear, GD_TYPE_NORMAL_BUTTON, "clear level", 'C' }, { IMG_GFX_EDITOR_BUTTON_TEST, GADGET_ID_TEST, &editor.button.test, GD_TYPE_NORMAL_BUTTON, "test level", 'T' }, { IMG_GFX_EDITOR_BUTTON_EXIT, GADGET_ID_EXIT, &editor.button.exit, GD_TYPE_NORMAL_BUTTON, "exit level editor", 'E' }, /* ---------- CE and GE control buttons ---------------------------------- */ { IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM, GADGET_ID_CUSTOM_COPY_FROM, &editor.button.ce_copy_from, GD_TYPE_RADIO_BUTTON, "copy settings from other element", 0 }, { IMG_GFX_EDITOR_BUTTON_CE_COPY_TO, GADGET_ID_CUSTOM_COPY_TO, &editor.button.ce_copy_to, GD_TYPE_RADIO_BUTTON, "copy settings to other element", 0 }, { IMG_GFX_EDITOR_BUTTON_CE_SWAP, GADGET_ID_CUSTOM_EXCHANGE, &editor.button.ce_swap, GD_TYPE_RADIO_BUTTON, "exchange element with other element", 0 }, { IMG_GFX_EDITOR_BUTTON_CE_COPY, GADGET_ID_CUSTOM_COPY, &editor.button.ce_copy, GD_TYPE_NORMAL_BUTTON, "copy settings from this element", 0 }, { IMG_GFX_EDITOR_BUTTON_CE_PASTE, GADGET_ID_CUSTOM_PASTE, &editor.button.ce_paste, GD_TYPE_NORMAL_BUTTON, "paste settings to this element", 0 }, /* ---------- palette control buttons ------------------------------------ */ { IMG_GFX_EDITOR_BUTTON_PROPERTIES, GADGET_ID_PROPERTIES, &editor.button.properties, GD_TYPE_NORMAL_BUTTON, "properties of drawing element", 'p' }, { IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT, GADGET_ID_ELEMENT_LEFT, &editor.button.element_left, GD_TYPE_NORMAL_BUTTON, "properties of drawing element 1", '1' }, { IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE, GADGET_ID_ELEMENT_MIDDLE, &editor.button.element_middle, GD_TYPE_NORMAL_BUTTON, "properties of drawing element 2", '2' }, { IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT, GADGET_ID_ELEMENT_RIGHT, &editor.button.element_right, GD_TYPE_NORMAL_BUTTON, "properties of drawing element 3", '3' }, { IMG_GFX_EDITOR_BUTTON_PALETTE, GADGET_ID_PALETTE, &editor.button.palette, GD_TYPE_NORMAL_BUTTON, "show list of elements", 'e' } }; static int random_placement_value = 10; static int random_placement_method = RANDOM_USE_QUANTITY; static int random_placement_background_element = EL_SAND; static boolean random_placement_background_restricted = FALSE; static boolean stick_element_properties_window = FALSE; static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES]; static boolean custom_element_change_events[NUM_CHANGE_EVENTS]; static struct ElementChangeInfo custom_element_change; static struct ElementGroupInfo group_element_info; static struct ElementInfo custom_element; static char levelset_name[MAX_LEVEL_NAME_LEN + 1]; static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1]; static int levelset_num_levels = 100; static boolean levelset_use_levelset_artwork = FALSE; static boolean levelset_copy_level_template = FALSE; static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE; static struct { int x, y; int min_value, max_value; int gadget_id_down, gadget_id_up; int gadget_id_text; int gadget_id_align; int *value; char *text_above, *text_left, *text_right; } counterbutton_info[ED_NUM_COUNTERBUTTONS] = { /* ---------- current level number --------------------------------------- */ { -1, -1, /* these values are not constant, but can change at runtime */ 1, 100, GADGET_ID_SELECT_LEVEL_DOWN, GADGET_ID_SELECT_LEVEL_UP, GADGET_ID_SELECT_LEVEL_TEXT, GADGET_ID_NONE, &level_nr, NULL, NULL, NULL }, /* ---------- level and editor settings ---------------------------------- */ { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(4), MIN_LEV_FIELDX, MAX_LEV_FIELDX, GADGET_ID_LEVEL_XSIZE_DOWN, GADGET_ID_LEVEL_XSIZE_UP, GADGET_ID_LEVEL_XSIZE_TEXT, GADGET_ID_NONE, &level.fieldx, "playfield size:", NULL, "width", }, { -1, ED_LEVEL_SETTINGS_YPOS(4), MIN_LEV_FIELDY, MAX_LEV_FIELDY, GADGET_ID_LEVEL_YSIZE_DOWN, GADGET_ID_LEVEL_YSIZE_UP, GADGET_ID_LEVEL_YSIZE_TEXT, GADGET_ID_LEVEL_XSIZE_UP, &level.fieldy, NULL, " ", "height", }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(5), 0, 999, GADGET_ID_LEVEL_GEMSLIMIT_DOWN, GADGET_ID_LEVEL_GEMSLIMIT_UP, GADGET_ID_LEVEL_GEMSLIMIT_TEXT, GADGET_ID_NONE, &level.gems_needed, NULL, "number of gems to collect:", NULL }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(8), 0, 9999, GADGET_ID_LEVEL_TIMELIMIT_DOWN, GADGET_ID_LEVEL_TIMELIMIT_UP, GADGET_ID_LEVEL_TIMELIMIT_TEXT, GADGET_ID_NONE, &level.time, "time or step limit to solve level:", NULL, NULL }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(10), 0, 999, GADGET_ID_LEVEL_TIMESCORE_DOWN, GADGET_ID_LEVEL_TIMESCORE_UP, GADGET_ID_LEVEL_TIMESCORE_TEXT, GADGET_ID_NONE, &level.score[SC_TIME_BONUS], "score for each second/step left:", NULL, NULL }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(12), 0, 9999, GADGET_ID_LEVEL_RANDOM_SEED_DOWN, GADGET_ID_LEVEL_RANDOM_SEED_UP, GADGET_ID_LEVEL_RANDOM_SEED_TEXT, GADGET_ID_NONE, &level.random_seed, NULL, "random seed:", "(0 => random)" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(4), 1, MAX_LEVELS, GADGET_ID_LEVELSET_NUM_LEVELS_DOWN, GADGET_ID_LEVELSET_NUM_LEVELS_UP, GADGET_ID_LEVELSET_NUM_LEVELS_TEXT, GADGET_ID_NONE, &levelset_num_levels, "number of levels:", NULL, NULL, }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(0), 1, 100, GADGET_ID_LEVEL_RANDOM_DOWN, GADGET_ID_LEVEL_RANDOM_UP, GADGET_ID_LEVEL_RANDOM_TEXT, GADGET_ID_NONE, &random_placement_value, "random element placement:", NULL, "in" }, /* ---------- element settings: configure (various elements) ------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE1_DOWN, GADGET_ID_ELEMENT_VALUE1_UP, GADGET_ID_ELEMENT_VALUE1_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE2_DOWN, GADGET_ID_ELEMENT_VALUE2_UP, GADGET_ID_ELEMENT_VALUE2_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE3_DOWN, GADGET_ID_ELEMENT_VALUE3_UP, GADGET_ID_ELEMENT_VALUE3_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), MIN_SCORE, MAX_SCORE, GADGET_ID_ELEMENT_VALUE4_DOWN, GADGET_ID_ELEMENT_VALUE4_UP, GADGET_ID_ELEMENT_VALUE4_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), MIN_ELEMENT_CONTENTS, MAX_ELEMENT_CONTENTS, GADGET_ID_YAMYAM_CONTENT_DOWN, GADGET_ID_YAMYAM_CONTENT_UP, GADGET_ID_YAMYAM_CONTENT_TEXT, GADGET_ID_NONE, &level.num_yamyam_contents, NULL, NULL, "number of content areas" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), MIN_ELEMENT_CONTENTS, MAX_ELEMENT_CONTENTS, GADGET_ID_BALL_CONTENT_DOWN, GADGET_ID_BALL_CONTENT_UP, GADGET_ID_BALL_CONTENT_TEXT, GADGET_ID_NONE, &level.num_ball_contents, NULL, NULL, "number of content areas" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), MIN_ANDROID_ELEMENTS, MAX_ANDROID_ELEMENTS, GADGET_ID_ANDROID_CONTENT_DOWN, GADGET_ID_ANDROID_CONTENT_UP, GADGET_ID_ANDROID_CONTENT_TEXT, GADGET_ID_NONE, &level.num_android_clone_elements, NULL, NULL, "number of clonable elements" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), MIN_ENVELOPE_XSIZE, MAX_ENVELOPE_XSIZE, GADGET_ID_ENVELOPE_XSIZE_DOWN, GADGET_ID_ENVELOPE_XSIZE_UP, GADGET_ID_ENVELOPE_XSIZE_TEXT, GADGET_ID_NONE, NULL, /* will be set when used */ NULL, NULL, "width", }, { -1, ED_ELEMENT_SETTINGS_YPOS(0), MIN_ENVELOPE_YSIZE, MAX_ENVELOPE_YSIZE, GADGET_ID_ENVELOPE_YSIZE_DOWN, GADGET_ID_ENVELOPE_YSIZE_UP, GADGET_ID_ENVELOPE_YSIZE_TEXT, GADGET_ID_ENVELOPE_XSIZE_UP, NULL, /* will be set when used */ NULL, " ", "height", }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), MIN_INITIAL_INVENTORY_SIZE, MAX_INITIAL_INVENTORY_SIZE, GADGET_ID_INVENTORY_SIZE_DOWN, GADGET_ID_INVENTORY_SIZE_UP, GADGET_ID_INVENTORY_SIZE_TEXT, GADGET_ID_NONE, &level.initial_inventory_size[0], NULL, NULL, "number of inventory elements" }, /* ---------- element settings: configure 1 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(5), MIN_SCORE, MAX_SCORE, GADGET_ID_CUSTOM_SCORE_DOWN, GADGET_ID_CUSTOM_SCORE_UP, GADGET_ID_CUSTOM_SCORE_TEXT, GADGET_ID_NONE, &custom_element.collect_score_initial, NULL, "CE score", " " }, { -1, ED_ELEMENT_SETTINGS_YPOS(5), MIN_COLLECT_COUNT, MAX_COLLECT_COUNT, GADGET_ID_CUSTOM_GEMCOUNT_DOWN, GADGET_ID_CUSTOM_GEMCOUNT_UP, GADGET_ID_CUSTOM_GEMCOUNT_TEXT, GADGET_ID_CUSTOM_SCORE_UP, &custom_element.collect_count_initial, NULL, "CE count", NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), 0, 9999, GADGET_ID_CUSTOM_VALUE_FIX_DOWN, GADGET_ID_CUSTOM_VALUE_FIX_UP, GADGET_ID_CUSTOM_VALUE_FIX_TEXT, GADGET_ID_NONE, &custom_element.ce_value_fixed_initial, NULL, "CE value", NULL }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), 0, 9999, GADGET_ID_CUSTOM_VALUE_RND_DOWN, GADGET_ID_CUSTOM_VALUE_RND_UP, GADGET_ID_CUSTOM_VALUE_RND_TEXT, GADGET_ID_CUSTOM_VALUE_FIX_UP, &custom_element.ce_value_random_initial, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(6), 0, 999, GADGET_ID_PUSH_DELAY_FIX_DOWN, GADGET_ID_PUSH_DELAY_FIX_UP, GADGET_ID_PUSH_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element.push_delay_fixed, NULL, "push delay", NULL }, { -1, ED_ELEMENT_SETTINGS_YPOS(6), 0, 999, GADGET_ID_PUSH_DELAY_RND_DOWN, GADGET_ID_PUSH_DELAY_RND_UP, GADGET_ID_PUSH_DELAY_RND_TEXT, GADGET_ID_PUSH_DELAY_FIX_UP, &custom_element.push_delay_random, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(7), 0, 999, GADGET_ID_DROP_DELAY_FIX_DOWN, GADGET_ID_DROP_DELAY_FIX_UP, GADGET_ID_DROP_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element.drop_delay_fixed, NULL, "drop delay", NULL }, { -1, ED_ELEMENT_SETTINGS_YPOS(7), 0, 999, GADGET_ID_DROP_DELAY_RND_DOWN, GADGET_ID_DROP_DELAY_RND_UP, GADGET_ID_DROP_DELAY_RND_TEXT, GADGET_ID_DROP_DELAY_FIX_UP, &custom_element.drop_delay_random, NULL, "+random", NULL }, /* ---------- element settings: configure 2 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(5), 0, 999, GADGET_ID_MOVE_DELAY_FIX_DOWN, GADGET_ID_MOVE_DELAY_FIX_UP, GADGET_ID_MOVE_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element.move_delay_fixed, NULL, "move delay", NULL }, { -1, ED_ELEMENT_SETTINGS_YPOS(5), 0, 999, GADGET_ID_MOVE_DELAY_RND_DOWN, GADGET_ID_MOVE_DELAY_RND_UP, GADGET_ID_MOVE_DELAY_RND_TEXT, GADGET_ID_MOVE_DELAY_FIX_UP, &custom_element.move_delay_random, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(12), 0, 999, GADGET_ID_EXPLOSION_DELAY_DOWN, GADGET_ID_EXPLOSION_DELAY_UP, GADGET_ID_EXPLOSION_DELAY_TEXT, GADGET_ID_NONE, &custom_element.explosion_delay, NULL, "explosion delay", NULL }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(13), 0, 999, GADGET_ID_IGNITION_DELAY_DOWN, GADGET_ID_IGNITION_DELAY_UP, GADGET_ID_IGNITION_DELAY_TEXT, GADGET_ID_NONE, &custom_element.ignition_delay, NULL, "ignition delay", "(by fire)" }, /* ---------- element settings: configure (group elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), MIN_ELEMENTS_IN_GROUP, MAX_ELEMENTS_IN_GROUP, GADGET_ID_GROUP_CONTENT_DOWN, GADGET_ID_GROUP_CONTENT_UP, GADGET_ID_GROUP_CONTENT_TEXT, GADGET_ID_NONE, &group_element_info.num_elements, NULL, NULL, "number of elements in group" }, /* ---------- element settings: advanced (custom elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(2), 0, 999, GADGET_ID_CHANGE_DELAY_FIX_DOWN, GADGET_ID_CHANGE_DELAY_FIX_UP, GADGET_ID_CHANGE_DELAY_FIX_TEXT, GADGET_ID_NONE, &custom_element_change.delay_fixed, NULL, "CE delay", NULL, }, { -1, ED_ELEMENT_SETTINGS_YPOS(2), 0, 999, GADGET_ID_CHANGE_DELAY_RND_DOWN, GADGET_ID_CHANGE_DELAY_RND_UP, GADGET_ID_CHANGE_DELAY_RND_TEXT, GADGET_ID_CHANGE_DELAY_FIX_UP, &custom_element_change.delay_random, NULL, "+random", NULL }, { ED_ELEMENT_SETTINGS_XPOS(3), ED_ELEMENT_SETTINGS_YPOS(12), 0, 100, GADGET_ID_CHANGE_CONT_RND_DOWN, GADGET_ID_CHANGE_CONT_RND_UP, GADGET_ID_CHANGE_CONT_RND_TEXT, GADGET_ID_NONE, &custom_element_change.random_percentage, NULL, "use random replace:", "%" }, }; static struct { int x, y; int gadget_id; int size; char *value; char *text_above, *infotext; } textinput_info[ED_NUM_TEXTINPUT] = { { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_LEVEL_NAME, MAX_LEVEL_NAME_LEN, level.name, "Title:", "Title for this level" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(2), GADGET_ID_LEVEL_AUTHOR, MAX_LEVEL_AUTHOR_LEN, level.author, "Author:", "Author for this level" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_LEVELSET_NAME, MAX_LEVEL_NAME_LEN, levelset_name, "Title:", "Title for this or new level set" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(2), GADGET_ID_LEVELSET_AUTHOR, MAX_LEVEL_AUTHOR_LEN, levelset_author, "Author:", "Author for this or new level set" }, { -1, -1, /* these values are not constant, but can change at runtime */ GADGET_ID_ELEMENT_NAME, MAX_ELEMENT_NAME_LEN - 2, /* currently 2 chars less editable */ custom_element.description, NULL, "Element name" } }; static struct { int x, y; int gadget_id; int xsize, ysize; char *value; char *text_above, *infotext; } textarea_info[ED_NUM_TEXTAREAS] = { { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_ENVELOPE_INFO, MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE, NULL, "Envelope Content:", "Envelope Content" } }; static struct ValueTextInfo options_time_or_steps[] = { { 0, "seconds" }, { 1, "steps" }, { -1, NULL } }; static struct ValueTextInfo options_game_engine_type[] = { { GAME_ENGINE_TYPE_RND, "Rocks'n'Diamonds" }, { GAME_ENGINE_TYPE_EM, "Emerald Mine" }, { GAME_ENGINE_TYPE_SP, "Supaplex" }, { GAME_ENGINE_TYPE_MM, "Mirror Magic" }, { -1, NULL } }; static struct ValueTextInfo options_levelset_save_mode[] = { { LEVELSET_SAVE_MODE_UPDATE, "Update this level set" }, { LEVELSET_SAVE_MODE_CREATE, "Create new level set" }, { -1, NULL } }; static struct ValueTextInfo options_wind_direction[] = { { MV_START_NONE, "none" }, { MV_START_LEFT, "left" }, { MV_START_RIGHT, "right" }, { MV_START_UP, "up" }, { MV_START_DOWN, "down" }, { -1, NULL } }; static struct ValueTextInfo options_player_speed[] = { { 0, "frozen" }, { 1, "very slow" }, { 2, "slow" }, { 4, "normal" }, { 8, "fast" }, { 16, "very fast" }, { 32, "ultrafast" }, { -1, NULL } }; static struct ValueTextInfo options_access_type[] = { { EP_WALKABLE, "walkable" }, { EP_PASSABLE, "passable" }, { -1, NULL } }; static struct ValueTextInfo options_access_layer[] = { { EP_ACCESSIBLE_OVER, "over" }, { EP_ACCESSIBLE_INSIDE, "inside" }, { EP_ACCESSIBLE_UNDER, "under" }, { -1, NULL } }; static struct ValueTextInfo options_access_protected[] = { { 0, "unprotected" }, { 1, "protected" }, { -1, NULL } }; static struct ValueTextInfo options_access_direction[] = { { MV_NO_DIRECTION, "no direction" }, { MV_LEFT, "left" }, { MV_RIGHT, "right" }, { MV_UP, "up" }, { MV_DOWN, "down" }, { MV_LEFT | MV_UP, "left + up" }, { MV_LEFT | MV_DOWN, "left + down" }, { MV_RIGHT | MV_UP, "right + up" }, { MV_RIGHT | MV_DOWN, "right + down" }, { MV_HORIZONTAL, "horizontal" }, { MV_VERTICAL, "vertical" }, { MV_HORIZONTAL | MV_UP, "horizontal + up" }, { MV_HORIZONTAL | MV_DOWN, "horizontal + down" }, { MV_VERTICAL | MV_LEFT, "vertical + left" }, { MV_VERTICAL | MV_RIGHT, "vertical + right" }, { MV_ALL_DIRECTIONS, "all directions" }, { -1, NULL } }; static struct ValueTextInfo options_walk_to_action[] = { { EP_DIGGABLE, "diggable" }, { EP_COLLECTIBLE_ONLY, "collectible" }, { EP_DROPPABLE, "collectible & droppable" }, { EP_THROWABLE, "collectible & throwable" }, { EP_PUSHABLE, "pushable" }, { -1, NULL } }; static struct ValueTextInfo options_move_pattern[] = { { MV_LEFT, "left" }, { MV_RIGHT, "right" }, { MV_UP, "up" }, { MV_DOWN, "down" }, { MV_HORIZONTAL, "horizontal" }, { MV_VERTICAL, "vertical" }, { MV_ALL_DIRECTIONS, "all directions" }, { MV_WIND_DIRECTION, "wind direction" }, { MV_TOWARDS_PLAYER, "towards player" }, { MV_AWAY_FROM_PLAYER, "away from player" }, { MV_ALONG_LEFT_SIDE, "along left side" }, { MV_ALONG_RIGHT_SIDE, "along right side" }, { MV_TURNING_LEFT, "turning left" }, { MV_TURNING_RIGHT, "turning right" }, { MV_TURNING_LEFT_RIGHT, "turning left, right" }, { MV_TURNING_RIGHT_LEFT, "turning right, left" }, { MV_TURNING_RANDOM, "turning random" }, { MV_MAZE_RUNNER, "maze runner style" }, { MV_MAZE_HUNTER, "maze hunter style" }, { MV_WHEN_PUSHED, "when pushed" }, { MV_WHEN_DROPPED, "when dropped/thrown" }, { -1, NULL } }; static struct ValueTextInfo options_move_direction[] = { { MV_START_AUTOMATIC, "automatic" }, { MV_START_LEFT, "left" }, { MV_START_RIGHT, "right" }, { MV_START_UP, "up" }, { MV_START_DOWN, "down" }, { MV_START_RANDOM, "random" }, { MV_START_PREVIOUS, "previous" }, { -1, NULL } }; static struct ValueTextInfo options_move_stepsize[] = { { 0, "not moving" }, { 1, "very slow" }, { 2, "slow" }, { 4, "normal" }, { 8, "fast" }, { 16, "very fast" }, { 32, "even faster" }, { -1, NULL } }; static struct ValueTextInfo options_move_leave_type[] = { { LEAVE_TYPE_UNLIMITED, "leave behind" }, { LEAVE_TYPE_LIMITED, "change it to" }, { -1, NULL } }; static struct ValueTextInfo options_smash_targets[] = { { EP_CAN_SMASH_PLAYER, "player" }, #if 0 { EP_CAN_SMASH_ENEMIES, "enemies" }, #endif { EP_CAN_SMASH_EVERYTHING, "everything" }, { -1, NULL } }; static struct ValueTextInfo options_slippery_type[] = { { SLIPPERY_ANY_RANDOM, "random" }, { SLIPPERY_ANY_LEFT_RIGHT, "left, right" }, { SLIPPERY_ANY_RIGHT_LEFT, "right, left" }, { SLIPPERY_ONLY_LEFT, "only left" }, { SLIPPERY_ONLY_RIGHT, "only right" }, { -1, NULL } }; static struct ValueTextInfo options_deadliness[] = { { EP_DONT_RUN_INTO, "running into" }, { EP_DONT_COLLIDE_WITH, "colliding with" }, { EP_DONT_GET_HIT_BY, "getting hit by" }, { EP_DONT_TOUCH, "touching" }, { -1, NULL } }; static struct ValueTextInfo options_explosion_type[] = { { EXPLODES_3X3, "3x3" }, { EXPLODES_CROSS, "3+3" }, { EXPLODES_1X1, "1x1" }, { -1, NULL } }; static struct ValueTextInfo options_time_units[] = { { 1, "frames" }, { FRAMES_PER_SECOND, "seconds" }, { -1, NULL } }; static struct ValueTextInfo options_change_direct_action[] = { { CE_TOUCHED_BY_PLAYER, "touched by player" }, { CE_PRESSED_BY_PLAYER, "pressed by player" }, { CE_SWITCHED_BY_PLAYER, "switched by player" }, { CE_SNAPPED_BY_PLAYER, "snapped by player" }, { CE_PUSHED_BY_PLAYER, "pushed by player" }, { CE_ENTERED_BY_PLAYER, "entered by player" }, { CE_LEFT_BY_PLAYER, "left by player" }, { CE_DROPPED_BY_PLAYER, "dropped/thrown by player" }, { CE_SWITCHED, "switched" }, { CE_HITTING_SOMETHING, "hitting something" }, { CE_HIT_BY_SOMETHING, "hit by something" }, #if 0 { CE_BLOCKED, "blocked" }, #endif { CE_IMPACT, "impact (on something)" }, { CE_SMASHED, "smashed (from above)" }, #if 0 { CE_VALUE_CHANGES, "CE value changes" }, { CE_SCORE_CHANGES, "CE score changes" }, #endif { CE_VALUE_GETS_ZERO, "CE value gets 0" }, { CE_SCORE_GETS_ZERO, "CE score gets 0" }, { -1, NULL } }; static struct ValueTextInfo options_change_other_action[] = { { CE_PLAYER_TOUCHES_X, "player touches" }, { CE_PLAYER_PRESSES_X, "player presses" }, { CE_PLAYER_SWITCHES_X, "player switches" }, { CE_PLAYER_SNAPS_X, "player snaps" }, { CE_PLAYER_PUSHES_X, "player pushes" }, { CE_PLAYER_ENTERS_X, "player enters" }, { CE_PLAYER_LEAVES_X, "player leaves" }, { CE_PLAYER_DIGS_X, "player digs" }, { CE_PLAYER_COLLECTS_X, "player collects" }, { CE_PLAYER_DROPS_X, "player drops/throws" }, { CE_TOUCHING_X, "touching" }, { CE_HITTING_X, "hitting" }, { CE_DIGGING_X, "digging" }, { CE_HIT_BY_X, "hit by" }, { CE_SWITCH_OF_X, "switch of" }, { CE_CHANGE_OF_X, "change by page of" }, { CE_EXPLOSION_OF_X, "explosion of" }, { CE_MOVE_OF_X, "move of" }, { CE_CREATION_OF_X, "creation of" }, { CE_VALUE_CHANGES_OF_X, "CE value changes of" }, { CE_SCORE_CHANGES_OF_X, "CE score changes of" }, { CE_VALUE_GETS_ZERO_OF_X, "CE value gets 0 of" }, { CE_SCORE_GETS_ZERO_OF_X, "CE score gets 0 of" }, { -1, NULL } }; static struct ValueTextInfo options_change_trigger_side[] = { { CH_SIDE_LEFT, "left" }, { CH_SIDE_RIGHT, "right" }, { CH_SIDE_TOP, "top" }, { CH_SIDE_BOTTOM, "bottom" }, { CH_SIDE_LEFT_RIGHT, "left/right" }, { CH_SIDE_TOP_BOTTOM, "top/bottom" }, { CH_SIDE_ANY, "any" }, { -1, NULL } }; static struct ValueTextInfo options_change_trigger_player[] = { { CH_PLAYER_1, "1" }, { CH_PLAYER_2, "2" }, { CH_PLAYER_3, "3" }, { CH_PLAYER_4, "4" }, { CH_PLAYER_ANY, "any" }, { -1, NULL } }; static struct ValueTextInfo options_change_trigger_page[] = { { (1 << 0), "1" }, { (1 << 1), "2" }, { (1 << 2), "3" }, { (1 << 3), "4" }, { (1 << 4), "5" }, { (1 << 5), "6" }, { (1 << 6), "7" }, { (1 << 7), "8" }, { (1 << 8), "9" }, { (1 << 9), "10" }, { (1 << 10), "11" }, { (1 << 11), "12" }, { (1 << 12), "13" }, { (1 << 13), "14" }, { (1 << 14), "15" }, { (1 << 15), "16" }, { (1 << 16), "17" }, { (1 << 17), "18" }, { (1 << 18), "19" }, { (1 << 19), "20" }, { (1 << 20), "21" }, { (1 << 21), "22" }, { (1 << 22), "23" }, { (1 << 23), "24" }, { (1 << 24), "25" }, { (1 << 25), "26" }, { (1 << 26), "27" }, { (1 << 27), "28" }, { (1 << 28), "29" }, { (1 << 29), "30" }, { (1 << 30), "31" }, { (1 << 31), "32" }, { CH_PAGE_ANY, "any" }, { -1, NULL } }; static struct ValueTextInfo options_change_replace_when[] = { { CP_WHEN_EMPTY, "empty" }, { CP_WHEN_WALKABLE, "walkable" }, { CP_WHEN_DIGGABLE, "diggable" }, { CP_WHEN_COLLECTIBLE, "collectible" }, { CP_WHEN_REMOVABLE, "removable" }, { CP_WHEN_DESTRUCTIBLE, "destructible" }, { -1, NULL } }; static struct ValueTextInfo options_action_type[] = { { CA_NO_ACTION, "no action" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_LEVEL_ACTIONS, "[level]" }, { CA_RESTART_LEVEL, "restart level" }, { CA_SHOW_ENVELOPE, "show envelope" }, { CA_SET_LEVEL_TIME, "set time" }, { CA_SET_LEVEL_SCORE, "set score" }, { CA_SET_LEVEL_GEMS, "set gems" }, { CA_SET_LEVEL_WIND, "set wind dir." }, { CA_SET_LEVEL_RANDOM_SEED, "set rand. seed" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_PLAYER_ACTIONS, "[player]" }, { CA_MOVE_PLAYER, "move player" }, { CA_EXIT_PLAYER, "exit player" }, { CA_KILL_PLAYER, "kill player" }, { CA_SET_PLAYER_KEYS, "set keys" }, { CA_SET_PLAYER_SPEED, "set speed" }, { CA_SET_PLAYER_SHIELD, "set shield" }, { CA_SET_PLAYER_GRAVITY, "set gravity" }, { CA_SET_PLAYER_ARTWORK, "set artwork" }, { CA_SET_PLAYER_INVENTORY, "set inventory" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_CE_ACTIONS, "[CE]" }, { CA_SET_CE_VALUE, "set CE value" }, { CA_SET_CE_SCORE, "set CE score" }, { CA_SET_CE_ARTWORK, "set CE artwork" }, { CA_UNDEFINED, " " }, { CA_HEADLINE_ENGINE_ACTIONS, "[engine]" }, { CA_SET_ENGINE_SCAN_MODE, "set scan mode" }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_none[] = { { CA_MODE_UNDEFINED, " " }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_assign[] = { { CA_MODE_SET, "=" }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_add_remove[] = { { CA_MODE_ADD, "+" }, { CA_MODE_SUBTRACT, "-" }, { -1, NULL } }; static struct ValueTextInfo options_action_mode_calculate[] = { { CA_MODE_SET, "=" }, { CA_MODE_ADD, "+" }, { CA_MODE_SUBTRACT, "-" }, { CA_MODE_MULTIPLY, "*" }, { CA_MODE_DIVIDE, "/" }, { CA_MODE_MODULO, "%" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_none[] = { { CA_ARG_UNDEFINED, " " }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_player[] = { { CA_ARG_PLAYER_HEADLINE, "[player]" }, { CA_ARG_PLAYER_1, "1" }, { CA_ARG_PLAYER_2, "2" }, { CA_ARG_PLAYER_3, "3" }, { CA_ARG_PLAYER_4, "4" }, { CA_ARG_PLAYER_ANY, "any" }, { CA_ARG_PLAYER_TRIGGER, "trigger" }, { CA_ARG_PLAYER_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_number[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_0, "0" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_5, "5" }, { CA_ARG_10, "10" }, { CA_ARG_100, "100" }, { CA_ARG_1000, "1000" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_MIN, "min" }, { CA_ARG_NUMBER_MAX, "max" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_RESET, "reset" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_CE_VALUE, "CE value" }, { CA_ARG_NUMBER_CE_SCORE, "CE score" }, { CA_ARG_NUMBER_CE_DELAY, "CE delay" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_LEVEL_TIME, "time" }, { CA_ARG_NUMBER_LEVEL_GEMS, "gems" }, { CA_ARG_NUMBER_LEVEL_SCORE, "score" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]" }, { CA_ARG_ELEMENT_CV_TARGET, "target" }, { CA_ARG_ELEMENT_CV_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CV_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]" }, { CA_ARG_ELEMENT_CS_TARGET, "target" }, { CA_ARG_ELEMENT_CS_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CS_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_value[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_0, "0" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_5, "5" }, { CA_ARG_10, "10" }, { CA_ARG_100, "100" }, { CA_ARG_1000, "1000" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_MIN, "min" }, { CA_ARG_NUMBER_MAX, "max" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_RESET, "reset" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_CE_VALUE, "CE value" }, { CA_ARG_NUMBER_CE_SCORE, "CE score" }, { CA_ARG_NUMBER_CE_DELAY, "CE delay" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_NUMBER_LEVEL_TIME, "time" }, { CA_ARG_NUMBER_LEVEL_GEMS, "gems" }, { CA_ARG_NUMBER_LEVEL_SCORE, "score" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]" }, { CA_ARG_ELEMENT_CV_TARGET, "target" }, { CA_ARG_ELEMENT_CV_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CV_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]" }, { CA_ARG_ELEMENT_CS_TARGET, "target" }, { CA_ARG_ELEMENT_CS_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_CS_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_NR_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_NR_TARGET, "target" }, { CA_ARG_ELEMENT_NR_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_NR_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_envelope[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_TARGET, "target" }, { CA_ARG_ELEMENT_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_key[] = { { CA_ARG_NUMBER_HEADLINE, "[number]" }, { CA_ARG_1, "1" }, { CA_ARG_2, "2" }, { CA_ARG_3, "3" }, { CA_ARG_4, "4" }, { CA_ARG_5, "5" }, { CA_ARG_6, "6" }, { CA_ARG_7, "7" }, { CA_ARG_8, "8" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_TARGET, "target" }, { CA_ARG_ELEMENT_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_ACTION, "action ->" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_speed[] = { { CA_ARG_SPEED_HEADLINE, "[speed]" }, { CA_ARG_SPEED_NOT_MOVING, "frozen" }, { CA_ARG_SPEED_VERY_SLOW, "very slow" }, { CA_ARG_SPEED_SLOW, "slow" }, { CA_ARG_SPEED_NORMAL, "normal" }, { CA_ARG_SPEED_FAST, "fast" }, { CA_ARG_SPEED_VERY_FAST, "very fast" }, { CA_ARG_SPEED_EVEN_FASTER, "ultrafast" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_SPEED_SLOWER, "slower" }, { CA_ARG_SPEED_FASTER, "faster" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_SPEED_RESET, "reset" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_shield[] = { { CA_ARG_SHIELD_HEADLINE, "[shield]" }, { CA_ARG_SHIELD_OFF, "off" }, { CA_ARG_SHIELD_NORMAL, "normal" }, { CA_ARG_SHIELD_DEADLY, "deadly" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_artwork[] = { { CA_ARG_ELEMENT_HEADLINE, "[element]" }, { CA_ARG_ELEMENT_TARGET, "target" }, { CA_ARG_ELEMENT_TRIGGER, "trigger" }, { CA_ARG_ELEMENT_ACTION, "action ->" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_ELEMENT_RESET, "reset" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_gravity[] = { { CA_ARG_GRAVITY_HEADLINE, "[gravity]" }, { CA_ARG_GRAVITY_ON, "on" }, { CA_ARG_GRAVITY_OFF, "off" }, { CA_ARG_GRAVITY_TOGGLE, "toggle" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_direction[] = { { CA_ARG_DIRECTION_HEADLINE, "[dir.]" }, { CA_ARG_DIRECTION_NONE, "none" }, { CA_ARG_DIRECTION_LEFT, "left" }, { CA_ARG_DIRECTION_RIGHT, "right" }, { CA_ARG_DIRECTION_UP, "up" }, { CA_ARG_DIRECTION_DOWN, "down" }, { CA_ARG_DIRECTION_TRIGGER, "trigger" }, { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_scan_mode[] = { { CA_ARG_SCAN_MODE_HEADLINE, "[mode]" }, { CA_ARG_SCAN_MODE_NORMAL, "normal" }, { CA_ARG_SCAN_MODE_REVERSE, "reverse" }, { -1, NULL } }; static struct ValueTextInfo options_action_arg_inventory[] = { { CA_ARG_INVENTORY_HEADLINE, "[add]" }, { CA_ARG_ELEMENT_TARGET, "+ target" }, { CA_ARG_ELEMENT_TRIGGER, "+ trigger" }, { CA_ARG_ELEMENT_ACTION, "+ action" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]" }, { CA_ARG_INVENTORY_RM_TARGET, "- target" }, { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger" }, { CA_ARG_INVENTORY_RM_ACTION, "- action" }, { CA_ARG_INVENTORY_RM_FIRST, "- first" }, { CA_ARG_INVENTORY_RM_LAST, "- last" }, { CA_ARG_INVENTORY_RM_ALL, "- all" }, { CA_ARG_UNDEFINED, " " }, { CA_ARG_INVENTORY_RESET, "reset" }, { -1, NULL } }; static char options_change_page_strings[MAX_CHANGE_PAGES][10]; static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] = { { -1, NULL } }; static struct ValueTextInfo options_group_choice_mode[] = { { ANIM_RANDOM, "random" }, { ANIM_LOOP, "loop" }, { ANIM_LINEAR, "linear" }, { ANIM_PINGPONG, "pingpong" }, { ANIM_PINGPONG2, "pingpong 2" }, { -1, NULL } }; static struct ValueTextInfo *action_arg_modes[] = { options_action_mode_none, options_action_mode_assign, options_action_mode_add_remove, options_action_mode_calculate, }; static struct { int value; int mode; struct ValueTextInfo *options; } action_arg_options[] = { { CA_NO_ACTION, 0, options_action_arg_none, }, { CA_EXIT_PLAYER, 0, options_action_arg_player, }, { CA_KILL_PLAYER, 0, options_action_arg_player, }, { CA_MOVE_PLAYER, 0, options_action_arg_direction, }, { CA_RESTART_LEVEL, 0, options_action_arg_none, }, { CA_SHOW_ENVELOPE, 0, options_action_arg_envelope, }, { CA_SET_LEVEL_TIME, 3, options_action_arg_number, }, { CA_SET_LEVEL_GEMS, 3, options_action_arg_number, }, { CA_SET_LEVEL_SCORE, 3, options_action_arg_number, }, { CA_SET_LEVEL_WIND, 1, options_action_arg_direction, }, { CA_SET_LEVEL_RANDOM_SEED, 1, options_action_arg_number, }, { CA_SET_PLAYER_KEYS, 2, options_action_arg_key, }, { CA_SET_PLAYER_SPEED, 1, options_action_arg_speed, }, { CA_SET_PLAYER_SHIELD, 1, options_action_arg_shield, }, { CA_SET_PLAYER_GRAVITY, 1, options_action_arg_gravity, }, { CA_SET_PLAYER_ARTWORK, 1, options_action_arg_artwork, }, { CA_SET_PLAYER_INVENTORY, 0, options_action_arg_inventory, }, { CA_SET_CE_VALUE, 3, options_action_arg_value, }, { CA_SET_CE_SCORE, 3, options_action_arg_value, }, { CA_SET_CE_ARTWORK, 1, options_action_arg_artwork, }, { CA_SET_ENGINE_SCAN_MODE, 1, options_action_arg_scan_mode, }, { -1, FALSE, NULL } }; static struct { int x, y; int gadget_id; int gadget_id_align; int size; /* char size of selectbox or '-1' (dynamically determined) */ struct ValueTextInfo *options; int *value; char *text_above, *text_left, *text_right, *infotext; } selectbox_info[ED_NUM_SELECTBOX] = { /* ---------- level and editor settings ---------------------------------- */ { -1, ED_LEVEL_SETTINGS_YPOS(8), GADGET_ID_TIME_OR_STEPS, GADGET_ID_LEVEL_TIMELIMIT_UP, -1, options_time_or_steps, &level.use_step_counter, NULL, NULL, "(0 => no limit)", "time or step limit" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(11), GADGET_ID_GAME_ENGINE_TYPE, GADGET_ID_NONE, -1, options_game_engine_type, &level.game_engine_type, NULL, "game engine:", NULL, "game engine" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(10), GADGET_ID_LEVELSET_SAVE_MODE, GADGET_ID_NONE, -1, options_levelset_save_mode, &levelset_save_mode, "Action:", NULL, NULL, "action when saving level set" }, /* ---------- element settings: configure (several elements) ------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_WIND_DIRECTION, GADGET_ID_NONE, -1, options_wind_direction, &level.wind_direction_initial, NULL, "initial wind direction:", NULL, "initial wind direction" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_PLAYER_SPEED, GADGET_ID_NONE, -1, options_player_speed, &level.initial_player_stepsize[0], NULL, "initial player speed:", NULL, "initial player speed" }, /* ---------- element settings: configure 1 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_ACCESS_TYPE, GADGET_ID_NONE, -1, options_access_type, &custom_element.access_type, NULL, NULL, NULL, "type of access to this field" }, { -1, ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_ACCESS_LAYER, GADGET_ID_CUSTOM_ACCESS_TYPE, -1, options_access_layer, &custom_element.access_layer, NULL, NULL, NULL, "layer of access for this field" }, { -1, ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_ACCESS_PROTECTED, GADGET_ID_CUSTOM_ACCESS_LAYER, -1, options_access_protected, &custom_element.access_protected, NULL, NULL, NULL, "protected access for this field" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_ACCESS_DIRECTION, GADGET_ID_NONE, -1, options_access_direction, &custom_element.access_direction, NULL, "from", NULL, "access direction for this field" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CUSTOM_WALK_TO_ACTION, GADGET_ID_NONE, -1, options_walk_to_action, &custom_element.walk_to_action, NULL, NULL, NULL, "diggable/collectible/pushable" }, /* ---------- element settings: configure 2 (custom elements) ------------ */ { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_MOVE_PATTERN, GADGET_ID_NONE, -1, options_move_pattern, &custom_element.move_pattern, NULL, "can move", NULL, "element move pattern" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_MOVE_DIRECTION, GADGET_ID_NONE, -1, options_move_direction, &custom_element.move_direction_initial, NULL, "starts moving", NULL, "initial element move direction" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CUSTOM_MOVE_STEPSIZE, GADGET_ID_NONE, -1, options_move_stepsize, &custom_element.move_stepsize, NULL, "move/fall speed", NULL, "speed of element movement" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE, GADGET_ID_NONE, -1, options_move_leave_type, &custom_element.move_leave_type, // left text with leading spaces to place gadget next to "can dig" gadget // (needed because drawing area gadgets created after selectbox gadgets) // NULL, "can dig: can", ":", "leave behind or change element" NULL, " can", ":", "leave behind or change element" }, { -1, ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CUSTOM_SMASH_TARGETS, GADGET_ID_CUSTOM_CAN_SMASH, -1, options_smash_targets, &custom_element.smash_targets, NULL, "can smash", NULL, "elements that can be smashed" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CUSTOM_SLIPPERY_TYPE, GADGET_ID_NONE, -1, options_slippery_type, &custom_element.slippery_type, NULL, "slippery", NULL, "where other elements fall down" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_DEADLINESS, GADGET_ID_NONE, -1, options_deadliness, &custom_element.deadliness, NULL, "deadly when", NULL, "deadliness of element" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CUSTOM_EXPLOSION_TYPE, GADGET_ID_NONE, -1, options_explosion_type, &custom_element.explosion_type, NULL, "can explode", NULL, "explosion type" }, /* ---------- element settings: advanced (custom elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_CHANGE_TIME_UNITS, GADGET_ID_NONE, -1, options_time_units, &custom_element_change.delay_frames, NULL, "delay time given in", NULL, "delay time units for change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CHANGE_DIRECT_ACTION, GADGET_ID_NONE, -1, options_change_direct_action, &custom_element_change.direct_action, NULL, NULL, NULL, "type of direct action" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CHANGE_OTHER_ACTION, GADGET_ID_NONE, -1, options_change_other_action, &custom_element_change.other_action, NULL, NULL, "element:", "type of other element action" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(6), GADGET_ID_CHANGE_SIDE, GADGET_ID_NONE, -1, options_change_trigger_side, &custom_element_change.trigger_side, NULL, "at", "side", "element side triggering change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CHANGE_PLAYER, GADGET_ID_NONE, -1, options_change_trigger_player, &custom_element_change.trigger_player, NULL, "player:", " ", "player that causes change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CHANGE_PAGE, GADGET_ID_CHANGE_PLAYER, -1, options_change_trigger_page, &custom_element_change.trigger_page, NULL, "page:", NULL, "change page that causes change" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CHANGE_REPLACE_WHEN, GADGET_ID_NONE, -1, options_change_replace_when, &custom_element_change.replace_when, NULL, "replace when", NULL, "which elements can be replaced" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_ACTION_TYPE, GADGET_ID_NONE, -1, options_action_type, &custom_element_change.action_type, NULL, NULL, NULL, "action on specified condition" }, { -1, ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_ACTION_MODE, GADGET_ID_ACTION_TYPE, -1, options_action_mode_none, &custom_element_change.action_mode, NULL, NULL, NULL, "action operator" }, { -1, ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_ACTION_ARG, GADGET_ID_ACTION_MODE, -1, options_action_arg_none, &custom_element_change.action_arg, NULL, NULL, NULL, "action parameter" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_SELECT_CHANGE_PAGE, GADGET_ID_NONE, 3, options_change_page, &custom_element.current_change_page, NULL, NULL, NULL, "element change page" }, /* ---------- element settings: configure (group elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_GROUP_CHOICE_MODE, GADGET_ID_NONE, -1, options_group_choice_mode, &group_element_info.choice_mode, NULL, "choice type:", NULL, "type of group element choice" }, }; static struct { int x, y; int gadget_id; int gadget_id_align; int size; char *text; char *text_above, *text_left, *text_right, *infotext; } textbutton_info[ED_NUM_TEXTBUTTONS] = { /* ---------- level and editor settings (tabs) --------------------------- */ { ED_LEVEL_TABS_XPOS(0), ED_LEVEL_TABS_YPOS(0), GADGET_ID_LEVELINFO_LEVEL, GADGET_ID_NONE, 8, "Level", NULL, NULL, NULL, "Configure level properties" }, { -1, -1, GADGET_ID_LEVELINFO_LEVELSET, GADGET_ID_LEVELINFO_LEVEL, 8, "Levelset", NULL, NULL, NULL, "Update this or create new level set" }, { -1, -1, GADGET_ID_LEVELINFO_EDITOR, GADGET_ID_LEVELINFO_LEVELSET, 8, "Editor", NULL, NULL, NULL, "Configure editor properties" }, /* ---------- element settings (tabs) ------------------------------------ */ { ED_ELEMENT_TABS_XPOS(0), ED_ELEMENT_TABS_YPOS(0), GADGET_ID_PROPERTIES_INFO, GADGET_ID_NONE, 8, "Info", NULL, NULL, NULL, "Show information about element" }, { -1, -1, GADGET_ID_PROPERTIES_CONFIG, GADGET_ID_PROPERTIES_INFO, 8, "Config", NULL, NULL, NULL, "Configure element properties" }, { -1, -1, GADGET_ID_PROPERTIES_CONFIG_1, GADGET_ID_PROPERTIES_INFO, 8, "Config 1", NULL, NULL, NULL, "Configure element properties, part 1" }, { -1, -1, GADGET_ID_PROPERTIES_CONFIG_2, GADGET_ID_PROPERTIES_CONFIG_1, 8, "Config 2", NULL, NULL, NULL, "Configure element properties, part 2" }, { -1, -1, GADGET_ID_PROPERTIES_CHANGE, GADGET_ID_PROPERTIES_CONFIG_2, 8, "Change", NULL, NULL, NULL, "Configure custom element change pages" }, /* ---------- level and editor settings (buttons) ------------------------ */ { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(10), GADGET_ID_SAVE_LEVELSET, GADGET_ID_LEVELSET_SAVE_MODE, -1, "Save", NULL, NULL, NULL, "Update or create level set" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(6), GADGET_ID_SAVE_AS_TEMPLATE_2, GADGET_ID_NONE, -1, "Save", NULL, NULL, "this level as level template", "Save current settings as new template" }, /* ---------- element settings (buttons) --------------------------------- */ { -1, -1, GADGET_ID_SAVE_AS_TEMPLATE_1, GADGET_ID_CUSTOM_USE_TEMPLATE_1, -1, "Save", NULL, " ", "As Template", "Save current settings as new template" }, { -1, -1, GADGET_ID_ADD_CHANGE_PAGE, GADGET_ID_PASTE_CHANGE_PAGE, -1, "New", NULL, NULL, NULL, "Add new change page" }, { -1, -1, GADGET_ID_DEL_CHANGE_PAGE, GADGET_ID_ADD_CHANGE_PAGE, -1, "Delete", NULL, NULL, NULL, "Delete current change page" }, }; static struct { int graphic; int x, y; int gadget_id; int gadget_id_align; char *text_left, *text_right, *infotext; } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] = { { IMG_EDITOR_COUNTER_DOWN, ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_PREV_CHANGE_PAGE, GADGET_ID_NONE, NULL, NULL, "select previous change page" }, { IMG_EDITOR_COUNTER_UP, -1, ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_NEXT_CHANGE_PAGE, GADGET_ID_SELECT_CHANGE_PAGE, NULL, "change page", "select next change page" }, { IMG_GFX_EDITOR_BUTTON_CP_COPY, -1, ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_COPY_CHANGE_PAGE, GADGET_ID_NEXT_CHANGE_PAGE, " ", NULL, "copy settings from this change page" }, { IMG_GFX_EDITOR_BUTTON_CP_PASTE, -1, ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_PASTE_CHANGE_PAGE, GADGET_ID_COPY_CHANGE_PAGE, NULL, NULL, "paste settings to this change page" }, }; static struct { int x, y; } scrollbutton_pos[ED_NUM_SCROLLBUTTONS]; static struct { int graphic; int gadget_id; char *infotext; } scrollbutton_info[ED_NUM_SCROLLBUTTONS] = { { IMG_EDITOR_PLAYFIELD_SCROLL_UP, GADGET_ID_SCROLL_UP, "scroll level editing area up" }, { IMG_EDITOR_PLAYFIELD_SCROLL_DOWN, GADGET_ID_SCROLL_DOWN, "scroll level editing area down" }, { IMG_EDITOR_PLAYFIELD_SCROLL_LEFT, GADGET_ID_SCROLL_LEFT, "scroll level editing area left" }, { IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT, GADGET_ID_SCROLL_RIGHT, "scroll level editing area right" }, { IMG_EDITOR_PALETTE_SCROLL_UP, GADGET_ID_SCROLL_LIST_UP, "scroll element list up ('Page Up')" }, { IMG_EDITOR_PALETTE_SCROLL_DOWN, GADGET_ID_SCROLL_LIST_DOWN, "scroll element list down ('Page Down')" }, }; static struct { int x, y; int width, height; int wheel_x, wheel_y; int wheel_width, wheel_height; } scrollbar_pos[ED_NUM_SCROLLBARS]; static struct { int graphic; int type; int gadget_id; char *infotext; } scrollbar_info[ED_NUM_SCROLLBARS] = { { IMG_EDITOR_PLAYFIELD_SCROLLBAR, GD_TYPE_SCROLLBAR_HORIZONTAL, GADGET_ID_SCROLL_HORIZONTAL, "scroll level editing area horizontally" }, { IMG_EDITOR_PLAYFIELD_SCROLLBAR, GD_TYPE_SCROLLBAR_VERTICAL, GADGET_ID_SCROLL_VERTICAL, "scroll level editing area vertically" }, { IMG_EDITOR_PALETTE_SCROLLBAR, GD_TYPE_SCROLLBAR_VERTICAL, GADGET_ID_SCROLL_LIST_VERTICAL, "scroll element list vertically" } }; static struct { int x, y; int gadget_id; int gadget_id_align; int radio_button_nr; int *value; int checked_value; char *text_left, *text_right, *infotext; } radiobutton_info[ED_NUM_RADIOBUTTONS] = { { -1, ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_RANDOM_PERCENTAGE, GADGET_ID_LEVEL_RANDOM_UP, RADIO_NR_RANDOM_ELEMENTS, &random_placement_method, RANDOM_USE_PERCENTAGE, " ", "percentage", "use percentage for random elements" }, { -1, ED_LEVEL_SETTINGS_YPOS(0), GADGET_ID_RANDOM_QUANTITY, GADGET_ID_RANDOM_PERCENTAGE, RADIO_NR_RANDOM_ELEMENTS, &random_placement_method, RANDOM_USE_QUANTITY, " ", "quantity", "use quantity for random elements" } }; static struct { int x, y; int gadget_id; int gadget_id_align; boolean *value; char *text_above, *text_left, *text_right, *infotext; } checkbutton_info[ED_NUM_CHECKBUTTONS] = { /* ---------- level and editor settings ---------------------------------- */ { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(6), GADGET_ID_AUTO_COUNT_GEMS, GADGET_ID_NONE, &level.auto_count_gems, NULL, NULL, "automatically count gems needed", "set counter to number of gems" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(7), GADGET_ID_USE_LEVELSET_ARTWORK, GADGET_ID_NONE, &levelset_use_levelset_artwork, NULL, NULL, "use current custom artwork", "use custom artwork of this level set" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(8), GADGET_ID_COPY_LEVEL_TEMPLATE, GADGET_ID_NONE, &levelset_copy_level_template, NULL, NULL, "copy current level template", "copy level template of this level set" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(1), GADGET_ID_RANDOM_RESTRICTED, GADGET_ID_NONE, &random_placement_background_restricted, NULL, NULL, "restrict random placement to:", "set random placement restriction" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(4), GADGET_ID_CUSTOM_USE_TEMPLATE_3, GADGET_ID_NONE, &setup.editor.use_template_for_new_levels, "Template for new levels and CE/GE:", NULL, "use template for new levels", "use template for level properties" }, { ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(5), GADGET_ID_CUSTOM_USE_TEMPLATE_2, GADGET_ID_NONE, &level.use_custom_template, NULL, NULL, "use template for custom elements", "use template for custom properties" }, /* ---------- element settings: configure (various elements) ------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_STICK_ELEMENT, GADGET_ID_NONE, &stick_element_properties_window, NULL, NULL, "stick this screen to edit content","stick this screen to edit content" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_EM_SLIPPERY_GEMS, GADGET_ID_NONE, &level.em_slippery_gems, NULL, NULL, "slip down from certain flat walls","use EM/DC style slipping behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_EM_EXPLODES_BY_FIRE, GADGET_ID_NONE, &level.em_explodes_by_fire, NULL, NULL, "explodes with chain reaction", "use R'n'D style explosion behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_USE_SPRING_BUG, GADGET_ID_NONE, &level.use_spring_bug, NULL, NULL, "use spring pushing bug", "use odd spring pushing behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_USE_TIME_ORB_BUG, GADGET_ID_NONE, &level.use_time_orb_bug, NULL, NULL, "use time orb bug", "use odd time orb behaviour" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_RANDOM_BALL_CONTENT, GADGET_ID_NONE, &level.ball_random, NULL, NULL, "create single random element", "only create one element from content" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_INITIAL_BALL_STATE, GADGET_ID_NONE, &level.ball_state_initial, NULL, NULL, "magic ball initially activated", "activate magic ball after level start" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_GROW_INTO_DIGGABLE, GADGET_ID_NONE, &level.grow_into_diggable, NULL, NULL, "can grow into anything diggable", "grow into more than just sand" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_AUTO_EXIT_SOKOBAN, GADGET_ID_NONE, &level.auto_exit_sokoban, NULL, NULL, "exit level if all fields solved", "automatically finish Sokoban levels" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CONTINUOUS_SNAPPING, GADGET_ID_NONE, &level.continuous_snapping, NULL, NULL, "continuous snapping", "use snapping without releasing key" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_BLOCK_SNAP_FIELD, GADGET_ID_NONE, &level.block_snap_field, NULL, NULL, "block snapped field when snapping", "use snapping delay to show animation" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_BLOCK_LAST_FIELD, GADGET_ID_NONE, &level.block_last_field, NULL, NULL, "block last field when moving", "player blocks last field when moving" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_SP_BLOCK_LAST_FIELD, GADGET_ID_NONE, &level.sp_block_last_field, NULL, NULL, "block last field when moving", "player blocks last field when moving" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_INSTANT_RELOCATION, GADGET_ID_NONE, &level.instant_relocation, NULL, NULL, "no scrolling when relocating", "player gets relocated without delay" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_SHIFTED_RELOCATION, GADGET_ID_NONE, &level.shifted_relocation, NULL, NULL, "no centering when relocating", "level not centered after relocation" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_LAZY_RELOCATION, GADGET_ID_NONE, &level.lazy_relocation, NULL, NULL, "only redraw off-screen relocation","no redraw if relocation target visible" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_USE_START_ELEMENT, GADGET_ID_NONE, &level.use_start_element[0], NULL, NULL, "use level start element:", "start level at this element's position" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_USE_ARTWORK_ELEMENT, GADGET_ID_NONE, &level.use_artwork_element[0], NULL, NULL, "use artwork from element:", "use player artwork from other element" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(12), GADGET_ID_USE_EXPLOSION_ELEMENT, GADGET_ID_NONE, &level.use_explosion_element[0], NULL, NULL, "use explosion from element:", "use explosion properties from element" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_INITIAL_GRAVITY, GADGET_ID_NONE, &level.initial_player_gravity[0], NULL, NULL, "use initial gravity", "set initial player gravity" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_USE_INITIAL_INVENTORY, GADGET_ID_NONE, &level.use_initial_inventory[0], NULL, NULL, "use initial inventory:", "use collected elements on level start" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(6), GADGET_ID_CAN_PASS_TO_WALKABLE, GADGET_ID_NONE, &level.can_pass_to_walkable, NULL, NULL, "can pass to walkable element", "player can pass to empty or walkable" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CAN_FALL_INTO_ACID, GADGET_ID_NONE, &custom_element_properties[EP_CAN_MOVE_INTO_ACID], NULL, NULL, "can fall into acid (with gravity)","player can fall into acid pool" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(0), GADGET_ID_CAN_MOVE_INTO_ACID, GADGET_ID_NONE, &custom_element_properties[EP_CAN_MOVE_INTO_ACID], NULL, NULL, "can move into acid", "element can move into acid pool" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_DONT_COLLIDE_WITH, GADGET_ID_NONE, &custom_element_properties[EP_DONT_COLLIDE_WITH], NULL, NULL, "deadly when colliding with", "element is deadly when hitting player" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_ENVELOPE_AUTOWRAP, GADGET_ID_NONE, &level.envelope[0].autowrap, NULL, NULL, "auto-wrap", "automatically wrap envelope text" }, { -1, ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_ENVELOPE_CENTERED, GADGET_ID_ENVELOPE_AUTOWRAP, &level.envelope[0].centered, NULL, " ", "centered", "automatically center envelope text" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_MM_LASER_RED, GADGET_ID_NONE, &level.mm_laser_red, "choose color components for laser:", NULL, "red", "use red color components in laser" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_MM_LASER_GREEN, GADGET_ID_NONE, &level.mm_laser_green, NULL, NULL, "green", "use green color components in laser" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_MM_LASER_BLUE, GADGET_ID_NONE, &level.mm_laser_blue, NULL, NULL, "blue", "use blue color components in laser" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_DF_LASER_RED, GADGET_ID_NONE, &level.df_laser_red, "choose color components for laser:", NULL, "red", "use red color components in laser" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_DF_LASER_GREEN, GADGET_ID_NONE, &level.df_laser_green, NULL, NULL, "green", "use green color components in laser" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3), GADGET_ID_DF_LASER_BLUE, GADGET_ID_NONE, &level.df_laser_blue, NULL, NULL, "blue", "use blue color components in laser" }, /* ---------- element settings: configure 1 (custom elements) ----------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_USE_GRAPHIC, GADGET_ID_NONE, &custom_element.use_gfx_element, NULL, NULL, "use graphic of element:", "use existing element graphic" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(14), GADGET_ID_CUSTOM_USE_TEMPLATE_1, GADGET_ID_NONE, &level.use_custom_template, NULL, NULL, "use template", "use template for custom properties" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_ACCESSIBLE, GADGET_ID_NONE, &custom_element_properties[EP_ACCESSIBLE], NULL, NULL, NULL, "player can walk to or pass this field" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_GRAV_REACHABLE, GADGET_ID_NONE, &custom_element_properties[EP_GRAVITY_REACHABLE], NULL, NULL, "reachable despite gravity", "player can walk/dig despite gravity" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_USE_LAST_VALUE, GADGET_ID_NONE, &custom_element.use_last_ce_value, NULL, NULL, "use last CE value after change", "use last CE value after change" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CUSTOM_WALK_TO_OBJECT, GADGET_ID_NONE, &custom_element_properties[EP_WALK_TO_OBJECT], NULL, NULL, NULL, "player can dig/collect/push element" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CUSTOM_INDESTRUCTIBLE, GADGET_ID_NONE, &custom_element_properties[EP_INDESTRUCTIBLE], NULL, NULL, "indestructible", "element is indestructible" }, /* ---------- element settings: configure 2 (custom elements) ----------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_CAN_MOVE, GADGET_ID_NONE, &custom_element_properties[EP_CAN_MOVE], NULL, NULL, NULL, "element can move with some pattern" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CUSTOM_CAN_FALL, GADGET_ID_NONE, &custom_element_properties[EP_CAN_FALL], NULL, NULL, "can fall", "element can fall down" }, { -1, ED_ELEMENT_SETTINGS_YPOS(7), GADGET_ID_CUSTOM_CAN_SMASH, GADGET_ID_CUSTOM_CAN_FALL, &custom_element_properties[EP_CAN_SMASH], NULL, " ", NULL, "element can smash other elements" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CUSTOM_SLIPPERY, GADGET_ID_NONE, &custom_element_properties[EP_SLIPPERY], NULL, NULL, NULL, "other elements can fall down from it" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_DEADLY, GADGET_ID_NONE, &custom_element_properties[EP_DEADLY], NULL, NULL, NULL, "element can kill the player" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10), GADGET_ID_CUSTOM_CAN_EXPLODE, GADGET_ID_NONE, &custom_element_properties[EP_CAN_EXPLODE], NULL, NULL, NULL, "element can explode" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_EXPLODE_FIRE, GADGET_ID_NONE, &custom_element_properties[EP_EXPLODES_BY_FIRE], NULL, NULL, "by fire", "element can explode by fire/explosion" }, { -1, ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_EXPLODE_SMASH, GADGET_ID_CUSTOM_EXPLODE_FIRE, &custom_element_properties[EP_EXPLODES_SMASHED], NULL, " ", "smashed", "element can explode when smashed" }, { -1, ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CUSTOM_EXPLODE_IMPACT, GADGET_ID_CUSTOM_EXPLODE_SMASH, &custom_element_properties[EP_EXPLODES_IMPACT], NULL, " ", "impact", "element can explode on impact" }, /* ---------- element settings: advanced (custom elements) --------------- */ { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_CAN_CHANGE, GADGET_ID_NONE, &custom_element_change.can_change, NULL, NULL, "element changes to:", "change element on specified condition" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(2), GADGET_ID_CHANGE_DELAY, GADGET_ID_NONE, &custom_element_change_events[CE_DELAY], NULL, NULL, NULL, "element changes after delay" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(4), GADGET_ID_CHANGE_BY_DIRECT_ACT, GADGET_ID_NONE, &custom_element_change_events[CE_BY_DIRECT_ACTION], NULL, NULL, NULL, "element changes by direct action" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(5), GADGET_ID_CHANGE_BY_OTHER_ACT, GADGET_ID_NONE, &custom_element_change_events[CE_BY_OTHER_ACTION], NULL, NULL, NULL, "element changes by other element" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(8), GADGET_ID_CHANGE_USE_EXPLOSION, GADGET_ID_NONE, &custom_element_change.explode, NULL, NULL, "explode instead of change", "element explodes instead of change" }, { ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(9), GADGET_ID_CHANGE_USE_CONTENT, GADGET_ID_NONE, &custom_element_change.use_target_content, NULL, NULL, "use extended change target:", "element changes to more elements" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(11), GADGET_ID_CHANGE_ONLY_COMPLETE, GADGET_ID_NONE, &custom_element_change.only_if_complete, NULL, NULL, "replace all or nothing", "only replace when all can be changed" }, { ED_ELEMENT_SETTINGS_XPOS(2), ED_ELEMENT_SETTINGS_YPOS(12), GADGET_ID_CHANGE_USE_RANDOM, GADGET_ID_NONE, &custom_element_change.use_random_replace, NULL, NULL, NULL, "use percentage for random replace" }, { ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(13), GADGET_ID_CHANGE_HAS_ACTION, GADGET_ID_NONE, &custom_element_change.has_action, NULL, NULL, NULL, "execute action on specified condition" }, }; static struct { int x, y; int xoffset, yoffset; int gadget_id; int gadget_id_align; int *value; int area_xsize, area_ysize; char *text_left, *text_right, *text_below, *infotext; } drawingarea_info[ED_NUM_DRAWING_AREAS] = { /* ---------- level playfield content ------------------------------------ */ { 0, 0, 0, 0, GADGET_ID_DRAWING_LEVEL, GADGET_ID_NONE, NULL, -1, -1, /* these values are not constant, but can change at runtime */ NULL, NULL, NULL, NULL }, /* ---------- yam yam content -------------------------------------------- */ { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(0), ED_AREA_YAMYAM_CONTENT_YOFF(0), GADGET_ID_YAMYAM_CONTENT_0, GADGET_ID_NONE, &level.yamyam_content[0].e[0][0], 3, 3, NULL, NULL, "1", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(1), ED_AREA_YAMYAM_CONTENT_YOFF(1), GADGET_ID_YAMYAM_CONTENT_1, GADGET_ID_NONE, &level.yamyam_content[1].e[0][0], 3, 3, NULL, NULL, "2", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(2), ED_AREA_YAMYAM_CONTENT_YOFF(2), GADGET_ID_YAMYAM_CONTENT_2, GADGET_ID_NONE, &level.yamyam_content[2].e[0][0], 3, 3, NULL, NULL, "3", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(3), ED_AREA_YAMYAM_CONTENT_YOFF(3), GADGET_ID_YAMYAM_CONTENT_3, GADGET_ID_NONE, &level.yamyam_content[3].e[0][0], 3, 3, NULL, NULL, "4", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(4), ED_AREA_YAMYAM_CONTENT_YOFF(4), GADGET_ID_YAMYAM_CONTENT_4, GADGET_ID_NONE, &level.yamyam_content[4].e[0][0], 3, 3, NULL, NULL, "5", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(5), ED_AREA_YAMYAM_CONTENT_YOFF(5), GADGET_ID_YAMYAM_CONTENT_5, GADGET_ID_NONE, &level.yamyam_content[5].e[0][0], 3, 3, NULL, NULL, "6", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(6), ED_AREA_YAMYAM_CONTENT_YOFF(6), GADGET_ID_YAMYAM_CONTENT_6, GADGET_ID_NONE, &level.yamyam_content[6].e[0][0], 3, 3, NULL, NULL, "7", NULL }, { ED_AREA_YAMYAM_CONTENT_XPOS, ED_AREA_YAMYAM_CONTENT_YPOS, ED_AREA_YAMYAM_CONTENT_XOFF(7), ED_AREA_YAMYAM_CONTENT_YOFF(7), GADGET_ID_YAMYAM_CONTENT_7, GADGET_ID_NONE, &level.yamyam_content[7].e[0][0], 3, 3, NULL, NULL, "8", NULL }, /* ---------- magic ball content ----------------------------------------- */ { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(0), ED_AREA_MAGIC_BALL_CONTENT_YOFF(0), GADGET_ID_MAGIC_BALL_CONTENT_0, GADGET_ID_NONE, &level.ball_content[0].e[0][0], 3, 3, NULL, NULL, "1", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(1), ED_AREA_MAGIC_BALL_CONTENT_YOFF(1), GADGET_ID_MAGIC_BALL_CONTENT_1, GADGET_ID_NONE, &level.ball_content[1].e[0][0], 3, 3, NULL, NULL, "2", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(2), ED_AREA_MAGIC_BALL_CONTENT_YOFF(2), GADGET_ID_MAGIC_BALL_CONTENT_2, GADGET_ID_NONE, &level.ball_content[2].e[0][0], 3, 3, NULL, NULL, "3", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(3), ED_AREA_MAGIC_BALL_CONTENT_YOFF(3), GADGET_ID_MAGIC_BALL_CONTENT_3, GADGET_ID_NONE, &level.ball_content[3].e[0][0], 3, 3, NULL, NULL, "4", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(4), ED_AREA_MAGIC_BALL_CONTENT_YOFF(4), GADGET_ID_MAGIC_BALL_CONTENT_4, GADGET_ID_NONE, &level.ball_content[4].e[0][0], 3, 3, NULL, NULL, "5", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(5), ED_AREA_MAGIC_BALL_CONTENT_YOFF(5), GADGET_ID_MAGIC_BALL_CONTENT_5, GADGET_ID_NONE, &level.ball_content[5].e[0][0], 3, 3, NULL, NULL, "6", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(6), ED_AREA_MAGIC_BALL_CONTENT_YOFF(6), GADGET_ID_MAGIC_BALL_CONTENT_6, GADGET_ID_NONE, &level.ball_content[6].e[0][0], 3, 3, NULL, NULL, "7", NULL }, { ED_AREA_MAGIC_BALL_CONTENT_XPOS, ED_AREA_MAGIC_BALL_CONTENT_YPOS, ED_AREA_MAGIC_BALL_CONTENT_XOFF(7), ED_AREA_MAGIC_BALL_CONTENT_YOFF(7), GADGET_ID_MAGIC_BALL_CONTENT_7, GADGET_ID_NONE, &level.ball_content[7].e[0][0], 3, 3, NULL, NULL, "8", NULL }, /* ---------- android content -------------------------------------------- */ { ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(5), ED_AREA_1X1_SETTINGS_XOFF, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_ANDROID_CONTENT, GADGET_ID_NONE, &level.android_clone_element[0], MAX_ANDROID_ELEMENTS, 1, "elements:", NULL, NULL, "elements android can clone" }, /* ---------- amoeba content --------------------------------------------- */ { ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(3), ED_AREA_1X1_SETTINGS_XOFF, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_AMOEBA_CONTENT, GADGET_ID_NONE, &level.amoeba_content, 1, 1, "content:", NULL, NULL, "amoeba content" }, /* ---------- level start element ---------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(10), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_START_ELEMENT, GADGET_ID_USE_START_ELEMENT, &level.start_element[0], 1, 1, NULL, NULL, NULL, "level start element" }, /* ---------- player artwork element ------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(11), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_ARTWORK_ELEMENT, GADGET_ID_USE_ARTWORK_ELEMENT, &level.artwork_element[0], 1, 1, NULL, NULL, NULL, "element for player artwork" }, /* ---------- player explosion element ----------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(12), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_EXPLOSION_ELEMENT, GADGET_ID_USE_EXPLOSION_ELEMENT, &level.explosion_element[0], 1, 1, NULL, NULL, NULL, "element for player explosion" }, /* ---------- player initial inventory ----------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(1), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_INVENTORY_CONTENT, GADGET_ID_USE_INITIAL_INVENTORY, &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1, NULL, NULL, NULL, "content for initial inventory" }, /* ---------- element settings: configure 1 (custom elements) ----------- */ /* ---------- custom graphic --------------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(1), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_CUSTOM_GRAPHIC, GADGET_ID_CUSTOM_USE_GRAPHIC, &custom_element.gfx_element_initial,1, 1, NULL, NULL, NULL, "custom graphic element" }, /* ---------- element settings: configure 2 (custom elements) ----------- */ /* ---------- custom content (when exploding) ---------------------------- */ { -1, ED_AREA_3X3_SETTINGS_YPOS(10), 0, ED_AREA_3X3_SETTINGS_YOFF, GADGET_ID_CUSTOM_CONTENT, GADGET_ID_NONE, /* align three rows */ &custom_element.content.e[0][0], 3, 3, "content:", NULL, NULL, NULL }, /* ---------- custom enter and leave element (when moving) --------------- */ { ED_AREA_1X1_SETTINGS_XPOS(1), ED_AREA_1X1_SETTINGS_YPOS(3), ED_AREA_1X1_SETTINGS_XOFF, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_CUSTOM_MOVE_ENTER, GADGET_ID_NONE, &custom_element.move_enter_element, 1, 1, "can dig:", " ", NULL, "element that can be digged/collected" }, { -1, ED_AREA_1X1_SETTINGS_YPOS(3), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_CUSTOM_MOVE_LEAVE, GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE, &custom_element.move_leave_element, 1, 1, NULL, NULL, NULL, "element that will be left behind" }, /* ---------- element settings: advanced (custom elements) --------------- */ /* ---------- custom change target --------------------------------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(1), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_CUSTOM_CHANGE_TARGET, GADGET_ID_CUSTOM_CAN_CHANGE, &custom_element_change.target_element, 1, 1, NULL, "after/when:", NULL, "new target element after change" }, /* ---------- custom change content (extended change target) ------------- */ { -1, ED_AREA_3X3_SETTINGS_YPOS(9), 0, ED_AREA_3X3_SETTINGS_YOFF, GADGET_ID_CUSTOM_CHANGE_CONTENT, GADGET_ID_NONE, /* align three rows */ &custom_element_change.target_content.e[0][0], 3, 3, NULL, NULL, NULL, "new extended elements after change" }, /* ---------- custom change trigger (element causing change) ------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(5), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_CUSTOM_CHANGE_TRIGGER, GADGET_ID_CHANGE_OTHER_ACTION, &custom_element_change.initial_trigger_element, 1, 1, NULL, NULL, NULL, "other element triggering change" }, /* ---------- custom change action (element used for action) ------------- */ { -1, ED_AREA_1X1_SETTINGS_YPOS(13), 0, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_CUSTOM_CHANGE_ACTION, GADGET_ID_ACTION_ARG, &custom_element_change.action_element, 1, 1, NULL, NULL, NULL, "element used as action parameter" }, /* ---------- group element content -------------------------------------- */ { ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(2), ED_AREA_1X1_SETTINGS_XOFF, ED_AREA_1X1_SETTINGS_YOFF, GADGET_ID_GROUP_CONTENT, GADGET_ID_NONE, &group_element_info.element[0], MAX_ELEMENTS_IN_GROUP, 1, "content:", NULL, NULL, NULL }, /* ---------- random background (for random painting) -------------------- */ { -1, ED_AREA_1X1_LSETTINGS_YPOS(1), 0, ED_AREA_1X1_LSETTINGS_YOFF, GADGET_ID_RANDOM_BACKGROUND, GADGET_ID_RANDOM_RESTRICTED, &random_placement_background_element, 1, 1, NULL, NULL, NULL, "random placement background" }, }; /* ----------------------------------------------------------------------------- some internally used variables ----------------------------------------------------------------------------- */ /* maximal size of level editor drawing area */ static int MAX_ED_FIELDX, MAX_ED_FIELDY; /* actual size of level editor drawing area */ static int ed_fieldx, ed_fieldy; /* actual position of level editor drawing area in level playfield */ static int level_xpos = -1, level_ypos = -1; /* actual tile size used to display playfield drawing area */ static int ed_tilesize = DEFAULT_EDITOR_TILESIZE; static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE; #define IN_ED_FIELD(x,y) IN_FIELD(x, y, ed_fieldx, ed_fieldy) /* drawing elements on the three mouse buttons */ static int new_element1 = EL_WALL; static int new_element2 = EL_EMPTY; static int new_element3 = EL_SAND; #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3) #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \ (button) == 2 ? new_element2 : \ (button) == 3 ? new_element3 : EL_EMPTY) #define BUTTON_TILE_SIZE(x) ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE) static int use_permanent_palette = TRUE; #define PX (use_permanent_palette ? DX : SX) #define PY (use_permanent_palette ? DY : SY) #define PXSIZE (use_permanent_palette ? DXSIZE : SXSIZE) #define PYSIZE (use_permanent_palette ? DYSIZE : SYSIZE) /* forward declaration for internal use */ static void ModifyEditorCounterValue(int, int); static void ModifyEditorCounterLimits(int, int, int); static void ModifyEditorSelectboxValue(int, int); static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *); static void ModifyEditorDrawingArea(int, int, int); static void ModifyEditorElementList(); static void AdjustElementListScrollbar(); static void RedrawDrawingElements(); static void DrawDrawingWindowExt(boolean); static void DrawDrawingWindow(); static void DrawLevelInfoWindow(); static void DrawPropertiesWindow(); static void DrawPaletteWindow(); static void UpdateCustomElementGraphicGadgets(); static boolean checkPropertiesConfig(int); static void SetAutomaticNumberOfGemsNeeded(); static void ClearEditorGadgetInfoText(); static void CopyLevelToUndoBuffer(int); static void HandleDrawingAreas(struct GadgetInfo *); static void HandleCounterButtons(struct GadgetInfo *); static void HandleTextInputGadgets(struct GadgetInfo *); static void HandleTextAreaGadgets(struct GadgetInfo *); static void HandleSelectboxGadgets(struct GadgetInfo *); static void HandleTextbuttonGadgets(struct GadgetInfo *); static void HandleGraphicbuttonGadgets(struct GadgetInfo *); static void HandleRadiobuttons(struct GadgetInfo *); static void HandleCheckbuttons(struct GadgetInfo *); static void HandleControlButtons(struct GadgetInfo *); static void HandleDrawingAreaInfo(struct GadgetInfo *); static void PrintEditorGadgetInfoText(struct GadgetInfo *); static boolean AskToCopyAndModifyLevelTemplate(); static boolean getDrawModeHiRes(); static int getTabulatorBarWidth(); static int getTabulatorBarHeight(); static Pixel getTabulatorBarColor(); static int num_editor_gadgets = 0; /* dynamically determined */ static struct GadgetInfo **level_editor_gadget = NULL; static int *right_gadget_border = NULL; static int drawing_function = GADGET_ID_SINGLE_ITEMS; static int last_drawing_function = GADGET_ID_SINGLE_ITEMS; static boolean draw_with_brush = FALSE; static int properties_element = 0; static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static int undo_buffer_position = 0; static int undo_buffer_steps = 0; static int redo_buffer_steps = 0; static int edit_mode; static int edit_mode_levelinfo; static int edit_mode_properties; static int element_shift = 0; static int editor_el_players[] = { EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4 }; static int *editor_el_players_ptr = editor_el_players; static int num_editor_el_players = SIZEOF_ARRAY_INT(editor_el_players); static int editor_hl_boulderdash[] = { EL_INTERNAL_CASCADE_BD_ACTIVE, EL_CHAR('B'), EL_CHAR('D'), EL_EMPTY, }; static int editor_el_boulderdash[] = { EL_EMPTY, EL_SAND, EL_BD_ROCK, EL_BD_DIAMOND, EL_STEELWALL, EL_BD_WALL, EL_BD_EXPANDABLE_WALL, EL_BD_MAGIC_WALL, EL_BD_AMOEBA, EL_BD_BUTTERFLY_UP, EL_BD_FIREFLY_UP, EL_EXIT_CLOSED, EL_BD_BUTTERFLY_LEFT, EL_BD_FIREFLY_LEFT, EL_BD_BUTTERFLY_RIGHT, EL_BD_FIREFLY_RIGHT, EL_EMPTY, EL_BD_BUTTERFLY_DOWN, EL_BD_FIREFLY_DOWN, EL_EXIT_OPEN, }; static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash; static int *editor_el_boulderdash_ptr = editor_el_boulderdash; static int num_editor_hl_boulderdash = SIZEOF_ARRAY_INT(editor_hl_boulderdash); static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash); static int editor_hl_emerald_mine[] = { EL_INTERNAL_CASCADE_EM_ACTIVE, EL_CHAR('E'), EL_CHAR('M'), EL_EMPTY, }; static int editor_el_emerald_mine[] = { EL_SAND, EL_ROCK, EL_QUICKSAND_EMPTY, EL_QUICKSAND_FULL, EL_STEELWALL, EL_WALL, EL_WALL_SLIPPERY, EL_MAGIC_WALL, EL_EMERALD, EL_DIAMOND, EL_NUT, EL_BOMB, EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_EM_EXIT_CLOSED, EL_EM_EXIT_OPEN, EL_YAMYAM_UP, EL_BUG_UP, EL_SPACESHIP_UP, EL_ROBOT, EL_BUG_LEFT, EL_SPACESHIP_LEFT, EL_BUG_RIGHT, EL_SPACESHIP_RIGHT, EL_ROBOT_WHEEL, EL_BUG_DOWN, EL_SPACESHIP_DOWN, EL_INVISIBLE_WALL, EL_ACID_POOL_TOPLEFT, EL_ACID, EL_ACID_POOL_TOPRIGHT, EL_AMOEBA_DROP, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_AMOEBA_WET, EL_EM_KEY_1, EL_EM_KEY_2, EL_EM_KEY_3, EL_EM_KEY_4, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, }; static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine; static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine; static int num_editor_hl_emerald_mine=SIZEOF_ARRAY_INT(editor_hl_emerald_mine); static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine); static int editor_hl_emerald_mine_club[] = { EL_INTERNAL_CASCADE_EMC_ACTIVE, EL_CHAR('E'), EL_CHAR('M'), EL_CHAR('C'), }; static int editor_el_emerald_mine_club[] = { EL_EMC_KEY_5, EL_EMC_KEY_6, EL_EMC_KEY_7, EL_EMC_KEY_8, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_EMC_WALL_13, EL_EMC_WALL_14, EL_EMC_WALL_15, EL_EMC_WALL_16, EL_EMC_WALL_SLIPPERY_1, EL_EMC_WALL_SLIPPERY_2, EL_EMC_WALL_SLIPPERY_3, EL_EMC_WALL_SLIPPERY_4, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, EL_EMC_WALL_9, EL_EMC_WALL_10, EL_EMC_WALL_11, EL_EMC_WALL_12, EL_EMC_GRASS, EL_EMC_FAKE_GRASS, EL_EMC_PLANT, EL_EMC_DRIPPER, EL_EMC_MAGIC_BALL, EL_EMC_MAGIC_BALL_SWITCH, EL_SPRING, EL_EMC_SPRING_BUMPER, EL_EMC_LENSES, EL_EMC_MAGNIFIER, EL_EMPTY, EL_EMPTY, EL_BALLOON, EL_YAMYAM_UP, EL_BALLOON_SWITCH_UP, EL_BALLOON_SWITCH_ANY, EL_YAMYAM_LEFT, EL_BALLOON_SWITCH_LEFT, EL_YAMYAM_RIGHT, EL_BALLOON_SWITCH_RIGHT, EL_EMC_ANDROID, EL_YAMYAM_DOWN, EL_BALLOON_SWITCH_DOWN, EL_BALLOON_SWITCH_NONE, }; static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club; static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club; static int num_editor_hl_emerald_mine_club=SIZEOF_ARRAY_INT(editor_hl_emerald_mine_club); static int num_editor_el_emerald_mine_club=SIZEOF_ARRAY_INT(editor_el_emerald_mine_club); static int editor_hl_rnd[] = { EL_INTERNAL_CASCADE_RND_ACTIVE, EL_CHAR('R'), EL_CHAR('N'), EL_CHAR('D'), }; static int editor_el_rnd[] = { EL_DYNAMITE, /* RND */ EL_DYNAMITE_ACTIVE, /* RND */ EL_EMPTY, EL_EMPTY, EL_KEY_1, EL_KEY_2, EL_KEY_3, EL_KEY_4, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_ARROW_LEFT, EL_ARROW_RIGHT, EL_ARROW_UP, EL_ARROW_DOWN, EL_AMOEBA_DEAD, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_GAME_OF_LIFE, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_BIOMAZE, EL_WALL_EMERALD_YELLOW, EL_WALL_EMERALD_RED, EL_WALL_EMERALD_PURPLE, EL_WALL_BD_DIAMOND, EL_SPEED_PILL, EL_PACMAN_UP, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_PACMAN_LEFT, EL_DARK_YAMYAM, EL_PACMAN_RIGHT, EL_YAMYAM, /* RND */ EL_BLACK_ORB, EL_PACMAN_DOWN, EL_LAMP, EL_LAMP_ACTIVE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_STONEBLOCK, EL_MOLE, EL_PENGUIN, EL_PIG, EL_DRAGON, EL_BUG, EL_MOLE_UP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_MOLE_LEFT, EL_SATELLITE, EL_MOLE_RIGHT, EL_PACMAN, EL_SPACESHIP, EL_MOLE_DOWN, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_WALL, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, }; static int *editor_hl_rnd_ptr = editor_hl_rnd; static int *editor_el_rnd_ptr = editor_el_rnd; static int num_editor_hl_rnd = SIZEOF_ARRAY_INT(editor_hl_rnd); static int num_editor_el_rnd = SIZEOF_ARRAY_INT(editor_el_rnd); static int editor_hl_sokoban[] = { EL_INTERNAL_CASCADE_SB_ACTIVE, EL_CHAR('S'), EL_CHAR('B'), EL_EMPTY, }; static int editor_el_sokoban[] = { EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_SOKOBAN_FIELD_PLAYER, }; static int *editor_hl_sokoban_ptr = editor_hl_sokoban; static int *editor_el_sokoban_ptr = editor_el_sokoban; static int num_editor_hl_sokoban = SIZEOF_ARRAY_INT(editor_hl_sokoban); static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban); static int editor_hl_supaplex[] = { EL_INTERNAL_CASCADE_SP_ACTIVE, EL_CHAR('S'), EL_CHAR('P'), EL_EMPTY, }; static int editor_el_supaplex[] = { EL_SP_MURPHY, EL_EMPTY, EL_SP_BASE, EL_SP_BUGGY_BASE, EL_SP_INFOTRON, EL_SP_ZONK, EL_SP_SNIKSNAK, EL_SP_ELECTRON, EL_SP_DISK_RED, EL_SP_DISK_ORANGE, EL_SP_DISK_YELLOW, EL_SP_TERMINAL, EL_SP_EXIT_CLOSED, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_HARDWARE_YELLOW, EL_SP_CHIP_TOP, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_BOTTOM, }; static int *editor_hl_supaplex_ptr = editor_hl_supaplex; static int *editor_el_supaplex_ptr = editor_el_supaplex; static int num_editor_hl_supaplex = SIZEOF_ARRAY_INT(editor_hl_supaplex); static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex); static int editor_hl_diamond_caves[] = { EL_INTERNAL_CASCADE_DC_ACTIVE, EL_CHAR('D'), EL_CHAR('C'), EL_CHAR('2'), }; static int editor_el_diamond_caves[] = { EL_EM_STEEL_EXIT_CLOSED, /* DC2 */ EL_EM_STEEL_EXIT_OPEN, /* DC2 */ EL_WALL_EMERALD, /* DC2 */ EL_WALL_DIAMOND, /* DC2 */ EL_PEARL, EL_CRYSTAL, EL_WALL_PEARL, EL_WALL_CRYSTAL, EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_1_MIDDLE, EL_CONVEYOR_BELT_1_RIGHT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_2_MIDDLE, EL_CONVEYOR_BELT_2_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_3_MIDDLE, EL_CONVEYOR_BELT_3_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_LEFT, EL_CONVEYOR_BELT_4_MIDDLE, EL_CONVEYOR_BELT_4_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_TIMEGATE_CLOSED, EL_TIMEGATE_OPEN, EL_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH, EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_OPEN, EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN, EL_STEELWALL_SLIPPERY, EL_INVISIBLE_SAND, EL_QUICKSAND_FAST_EMPTY, EL_QUICKSAND_FAST_FULL, EL_LANDMINE, EL_DC_LANDMINE, EL_SHIELD_NORMAL, EL_SHIELD_DEADLY, EL_EXTRA_TIME, EL_DC_MAGIC_WALL, EL_ENVELOPE_1, EL_ENVELOPE_2, EL_ENVELOPE_3, EL_ENVELOPE_4, EL_SIGN_RADIOACTIVITY, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, #if 0 EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_EMPTY, EL_EMPTY, EL_EMPTY, EL_SPERMS, EL_BULLET, EL_HEART, EL_CROSS, EL_FRANKIE, EL_EMPTY, EL_EMPTY, EL_EMPTY, #endif EL_DC_STEELWALL_2_SINGLE, EL_DC_STEELWALL_2_TOP, EL_SIGN_EXCLAMATION, EL_SIGN_STOP, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_GATE_WHITE, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_2_BOTTOM, EL_DC_KEY_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_GATE_FAKE_GRAY, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_DC_STEELWALL_1_RIGHT, EL_EMPTY, EL_DC_STEELWALL_1_LEFT, EL_EXPANDABLE_STEELWALL_VERTICAL, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_TOPLEFT_2, EL_EXPANDABLE_STEELWALL_ANY, }; static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves; static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves; static int num_editor_hl_diamond_caves = SIZEOF_ARRAY_INT(editor_hl_diamond_caves); static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves); static int editor_hl_dx_boulderdash[] = { EL_INTERNAL_CASCADE_DX_ACTIVE, EL_CHAR('D'), EL_CHAR('X'), EL_EMPTY, }; static int editor_el_dx_boulderdash[] = { EL_EMPTY, EL_TUBE_RIGHT_DOWN, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_DOWN, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_ANY, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL, EL_TUBE_RIGHT_UP, EL_TUBE_HORIZONTAL_UP, EL_TUBE_LEFT_UP, EL_TRAP, EL_DX_SUPABOMB, EL_EMPTY, EL_EMPTY }; static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash; static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash; static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash); static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash); static int editor_hl_mirror_magic[] = { EL_INTERNAL_CASCADE_MM_ACTIVE, EL_CHAR('M'), EL_CHAR('M'), EL_EMPTY, }; static int editor_el_mirror_magic[] = { EL_MM_MCDUFFIN_RIGHT, EL_MM_MCDUFFIN_UP, EL_MM_MCDUFFIN_LEFT, EL_MM_MCDUFFIN_DOWN, EL_MM_MIRROR_START, EL_MM_MIRROR_FIXED_START, EL_MM_POLARIZER_START, EL_MM_POLARIZER_CROSS_START, EL_MM_TELEPORTER_RED_START, EL_MM_TELEPORTER_YELLOW_START, EL_MM_TELEPORTER_GREEN_START, EL_MM_TELEPORTER_BLUE_START, EL_MM_PRISM, EL_MM_FUSE_ACTIVE, EL_MM_PACMAN_RIGHT, EL_MM_EXIT_CLOSED, EL_MM_KETTLE, EL_MM_BOMB, EL_MM_KEY, EL_MM_FUEL_FULL, EL_MM_LIGHTBULB, EL_MM_LIGHTBULB_ACTIVE, EL_MM_GRAY_BALL, EL_MM_LIGHTBALL, EL_MM_STEEL_WALL, EL_MM_WOODEN_WALL, EL_MM_ICE_WALL, EL_MM_AMOEBA_WALL, EL_MM_STEEL_LOCK, EL_MM_WOODEN_LOCK, EL_MM_STEEL_BLOCK, EL_MM_WOODEN_BLOCK, EL_MM_STEEL_GRID_FIXED_1, EL_MM_STEEL_GRID_FIXED_2, EL_MM_STEEL_GRID_FIXED_3, EL_MM_STEEL_GRID_FIXED_4, EL_MM_WOODEN_GRID_FIXED_1, EL_MM_WOODEN_GRID_FIXED_2, EL_MM_WOODEN_GRID_FIXED_3, EL_MM_WOODEN_GRID_FIXED_4 }; static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic; static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic; static int num_editor_hl_mirror_magic = SIZEOF_ARRAY_INT(editor_hl_mirror_magic); static int num_editor_el_mirror_magic = SIZEOF_ARRAY_INT(editor_el_mirror_magic); static int editor_hl_deflektor[] = { EL_INTERNAL_CASCADE_DF_ACTIVE, EL_CHAR('D'), EL_CHAR('F'), EL_EMPTY, }; static int editor_el_deflektor[] = { EL_DF_LASER_RIGHT, EL_DF_LASER_UP, EL_DF_LASER_LEFT, EL_DF_LASER_DOWN, EL_DF_RECEIVER_RIGHT, EL_DF_RECEIVER_UP, EL_DF_RECEIVER_LEFT, EL_DF_RECEIVER_DOWN, EL_DF_MIRROR_START, EL_DF_MIRROR_ROTATING_START, EL_DF_CELL, EL_DF_MINE, EL_DF_FIBRE_OPTIC_RED_1, EL_DF_FIBRE_OPTIC_YELLOW_1, EL_DF_FIBRE_OPTIC_GREEN_1, EL_DF_FIBRE_OPTIC_BLUE_1, EL_DF_STEEL_GRID_FIXED_START, EL_DF_STEEL_GRID_ROTATING_START, EL_DF_WOODEN_GRID_FIXED_START, EL_DF_WOODEN_GRID_ROTATING_START, EL_DF_STEEL_WALL, EL_DF_WOODEN_WALL, EL_DF_REFRACTOR, EL_EMPTY }; static int *editor_hl_deflektor_ptr = editor_hl_deflektor; static int *editor_el_deflektor_ptr = editor_el_deflektor; static int num_editor_hl_deflektor = SIZEOF_ARRAY_INT(editor_hl_deflektor); static int num_editor_el_deflektor = SIZEOF_ARRAY_INT(editor_el_deflektor); static int editor_hl_chars[] = { EL_INTERNAL_CASCADE_CHARS_ACTIVE, EL_CHAR('T'), EL_CHAR('X'), EL_CHAR('T'), }; static int editor_el_chars[] = { EL_CHAR(' '), EL_CHAR('!'), EL_CHAR('"'), EL_CHAR('#'), EL_CHAR('$'), EL_CHAR('%'), EL_CHAR('&'), EL_CHAR('\''), EL_CHAR('('), EL_CHAR(')'), EL_CHAR('*'), EL_CHAR('+'), EL_CHAR(','), EL_CHAR('-'), EL_CHAR('.'), EL_CHAR('/'), EL_CHAR('0'), EL_CHAR('1'), EL_CHAR('2'), EL_CHAR('3'), EL_CHAR('4'), EL_CHAR('5'), EL_CHAR('6'), EL_CHAR('7'), EL_CHAR('8'), EL_CHAR('9'), EL_CHAR(':'), EL_CHAR(';'), EL_CHAR('<'), EL_CHAR('='), EL_CHAR('>'), EL_CHAR('?'), EL_CHAR('@'), EL_CHAR('A'), EL_CHAR('B'), EL_CHAR('C'), EL_CHAR('D'), EL_CHAR('E'), EL_CHAR('F'), EL_CHAR('G'), EL_CHAR('H'), EL_CHAR('I'), EL_CHAR('J'), EL_CHAR('K'), EL_CHAR('L'), EL_CHAR('M'), EL_CHAR('N'), EL_CHAR('O'), EL_CHAR('P'), EL_CHAR('Q'), EL_CHAR('R'), EL_CHAR('S'), EL_CHAR('T'), EL_CHAR('U'), EL_CHAR('V'), EL_CHAR('W'), EL_CHAR('X'), EL_CHAR('Y'), EL_CHAR('Z'), EL_CHAR('['), EL_CHAR('\\'), EL_CHAR(']'), EL_CHAR('^'), EL_CHAR('_'), EL_CHAR(CHAR_BYTE_COPYRIGHT), EL_CHAR(CHAR_BYTE_UMLAUT_A), EL_CHAR(CHAR_BYTE_UMLAUT_O), EL_CHAR(CHAR_BYTE_UMLAUT_U), EL_CHAR(CHAR_BYTE_DEGREE), EL_CHAR(CHAR_BYTE_REGISTERED), EL_CHAR(FONT_ASCII_CURSOR), EL_CHAR(FONT_ASCII_BUTTON), EL_CHAR(FONT_ASCII_UP), EL_CHAR(FONT_ASCII_DOWN), EL_CHAR(' '), EL_CHAR(' ') }; static int *editor_hl_chars_ptr = editor_hl_chars; static int *editor_el_chars_ptr = editor_el_chars; static int num_editor_hl_chars = SIZEOF_ARRAY_INT(editor_hl_chars); static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars); static int editor_hl_steel_chars[] = { EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE, EL_STEEL_CHAR('T'), EL_STEEL_CHAR('X'), EL_STEEL_CHAR('T'), }; static int editor_el_steel_chars[] = { EL_STEEL_CHAR(' '), EL_STEEL_CHAR('!'), EL_STEEL_CHAR('"'), EL_STEEL_CHAR('#'), EL_STEEL_CHAR('$'), EL_STEEL_CHAR('%'), EL_STEEL_CHAR('&'), EL_STEEL_CHAR('\''), EL_STEEL_CHAR('('), EL_STEEL_CHAR(')'), EL_STEEL_CHAR('*'), EL_STEEL_CHAR('+'), EL_STEEL_CHAR(','), EL_STEEL_CHAR('-'), EL_STEEL_CHAR('.'), EL_STEEL_CHAR('/'), EL_STEEL_CHAR('0'), EL_STEEL_CHAR('1'), EL_STEEL_CHAR('2'), EL_STEEL_CHAR('3'), EL_STEEL_CHAR('4'), EL_STEEL_CHAR('5'), EL_STEEL_CHAR('6'), EL_STEEL_CHAR('7'), EL_STEEL_CHAR('8'), EL_STEEL_CHAR('9'), EL_STEEL_CHAR(':'), EL_STEEL_CHAR(';'), EL_STEEL_CHAR('<'), EL_STEEL_CHAR('='), EL_STEEL_CHAR('>'), EL_STEEL_CHAR('?'), EL_STEEL_CHAR('@'), EL_STEEL_CHAR('A'), EL_STEEL_CHAR('B'), EL_STEEL_CHAR('C'), EL_STEEL_CHAR('D'), EL_STEEL_CHAR('E'), EL_STEEL_CHAR('F'), EL_STEEL_CHAR('G'), EL_STEEL_CHAR('H'), EL_STEEL_CHAR('I'), EL_STEEL_CHAR('J'), EL_STEEL_CHAR('K'), EL_STEEL_CHAR('L'), EL_STEEL_CHAR('M'), EL_STEEL_CHAR('N'), EL_STEEL_CHAR('O'), EL_STEEL_CHAR('P'), EL_STEEL_CHAR('Q'), EL_STEEL_CHAR('R'), EL_STEEL_CHAR('S'), EL_STEEL_CHAR('T'), EL_STEEL_CHAR('U'), EL_STEEL_CHAR('V'), EL_STEEL_CHAR('W'), EL_STEEL_CHAR('X'), EL_STEEL_CHAR('Y'), EL_STEEL_CHAR('Z'), EL_STEEL_CHAR('['), EL_STEEL_CHAR('\\'), EL_STEEL_CHAR(']'), EL_STEEL_CHAR('^'), EL_STEEL_CHAR('_'), EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT), EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A), EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O), EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U), EL_STEEL_CHAR(CHAR_BYTE_DEGREE), EL_STEEL_CHAR(CHAR_BYTE_REGISTERED), EL_STEEL_CHAR(FONT_ASCII_CURSOR), EL_STEEL_CHAR(FONT_ASCII_BUTTON), EL_STEEL_CHAR(FONT_ASCII_UP), EL_STEEL_CHAR(FONT_ASCII_DOWN), EL_STEEL_CHAR(' '), EL_STEEL_CHAR(' ') }; static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars; static int *editor_el_steel_chars_ptr = editor_el_steel_chars; static int num_editor_hl_steel_chars = SIZEOF_ARRAY_INT(editor_hl_steel_chars); static int num_editor_el_steel_chars = SIZEOF_ARRAY_INT(editor_el_steel_chars); static int editor_hl_custom[] = { EL_INTERNAL_CASCADE_CE_ACTIVE, EL_CHAR('C'), EL_CHAR('E'), EL_EMPTY, }; static int editor_el_custom[] = { EL_CUSTOM_START + 0, EL_CUSTOM_START + 1, EL_CUSTOM_START + 2, EL_CUSTOM_START + 3, EL_CUSTOM_START + 4, EL_CUSTOM_START + 5, EL_CUSTOM_START + 6, EL_CUSTOM_START + 7, EL_CUSTOM_START + 8, EL_CUSTOM_START + 9, EL_CUSTOM_START + 10, EL_CUSTOM_START + 11, EL_CUSTOM_START + 12, EL_CUSTOM_START + 13, EL_CUSTOM_START + 14, EL_CUSTOM_START + 15, EL_CUSTOM_START + 16, EL_CUSTOM_START + 17, EL_CUSTOM_START + 18, EL_CUSTOM_START + 19, EL_CUSTOM_START + 20, EL_CUSTOM_START + 21, EL_CUSTOM_START + 22, EL_CUSTOM_START + 23, EL_CUSTOM_START + 24, EL_CUSTOM_START + 25, EL_CUSTOM_START + 26, EL_CUSTOM_START + 27, EL_CUSTOM_START + 28, EL_CUSTOM_START + 29, EL_CUSTOM_START + 30, EL_CUSTOM_START + 31, EL_CUSTOM_START + 32, EL_CUSTOM_START + 33, EL_CUSTOM_START + 34, EL_CUSTOM_START + 35, EL_CUSTOM_START + 36, EL_CUSTOM_START + 37, EL_CUSTOM_START + 38, EL_CUSTOM_START + 39, EL_CUSTOM_START + 40, EL_CUSTOM_START + 41, EL_CUSTOM_START + 42, EL_CUSTOM_START + 43, EL_CUSTOM_START + 44, EL_CUSTOM_START + 45, EL_CUSTOM_START + 46, EL_CUSTOM_START + 47, EL_CUSTOM_START + 48, EL_CUSTOM_START + 49, EL_CUSTOM_START + 50, EL_CUSTOM_START + 51, EL_CUSTOM_START + 52, EL_CUSTOM_START + 53, EL_CUSTOM_START + 54, EL_CUSTOM_START + 55, EL_CUSTOM_START + 56, EL_CUSTOM_START + 57, EL_CUSTOM_START + 58, EL_CUSTOM_START + 59, EL_CUSTOM_START + 60, EL_CUSTOM_START + 61, EL_CUSTOM_START + 62, EL_CUSTOM_START + 63, EL_CUSTOM_START + 64, EL_CUSTOM_START + 65, EL_CUSTOM_START + 66, EL_CUSTOM_START + 67, EL_CUSTOM_START + 68, EL_CUSTOM_START + 69, EL_CUSTOM_START + 70, EL_CUSTOM_START + 71, EL_CUSTOM_START + 72, EL_CUSTOM_START + 73, EL_CUSTOM_START + 74, EL_CUSTOM_START + 75, EL_CUSTOM_START + 76, EL_CUSTOM_START + 77, EL_CUSTOM_START + 78, EL_CUSTOM_START + 79, EL_CUSTOM_START + 80, EL_CUSTOM_START + 81, EL_CUSTOM_START + 82, EL_CUSTOM_START + 83, EL_CUSTOM_START + 84, EL_CUSTOM_START + 85, EL_CUSTOM_START + 86, EL_CUSTOM_START + 87, EL_CUSTOM_START + 88, EL_CUSTOM_START + 89, EL_CUSTOM_START + 90, EL_CUSTOM_START + 91, EL_CUSTOM_START + 92, EL_CUSTOM_START + 93, EL_CUSTOM_START + 94, EL_CUSTOM_START + 95, EL_CUSTOM_START + 96, EL_CUSTOM_START + 97, EL_CUSTOM_START + 98, EL_CUSTOM_START + 99, EL_CUSTOM_START + 100, EL_CUSTOM_START + 101, EL_CUSTOM_START + 102, EL_CUSTOM_START + 103, EL_CUSTOM_START + 104, EL_CUSTOM_START + 105, EL_CUSTOM_START + 106, EL_CUSTOM_START + 107, EL_CUSTOM_START + 108, EL_CUSTOM_START + 109, EL_CUSTOM_START + 110, EL_CUSTOM_START + 111, EL_CUSTOM_START + 112, EL_CUSTOM_START + 113, EL_CUSTOM_START + 114, EL_CUSTOM_START + 115, EL_CUSTOM_START + 116, EL_CUSTOM_START + 117, EL_CUSTOM_START + 118, EL_CUSTOM_START + 119, EL_CUSTOM_START + 120, EL_CUSTOM_START + 121, EL_CUSTOM_START + 122, EL_CUSTOM_START + 123, EL_CUSTOM_START + 124, EL_CUSTOM_START + 125, EL_CUSTOM_START + 126, EL_CUSTOM_START + 127, EL_CUSTOM_START + 128, EL_CUSTOM_START + 129, EL_CUSTOM_START + 130, EL_CUSTOM_START + 131, EL_CUSTOM_START + 132, EL_CUSTOM_START + 133, EL_CUSTOM_START + 134, EL_CUSTOM_START + 135, EL_CUSTOM_START + 136, EL_CUSTOM_START + 137, EL_CUSTOM_START + 138, EL_CUSTOM_START + 139, EL_CUSTOM_START + 140, EL_CUSTOM_START + 141, EL_CUSTOM_START + 142, EL_CUSTOM_START + 143, EL_CUSTOM_START + 144, EL_CUSTOM_START + 145, EL_CUSTOM_START + 146, EL_CUSTOM_START + 147, EL_CUSTOM_START + 148, EL_CUSTOM_START + 149, EL_CUSTOM_START + 150, EL_CUSTOM_START + 151, EL_CUSTOM_START + 152, EL_CUSTOM_START + 153, EL_CUSTOM_START + 154, EL_CUSTOM_START + 155, EL_CUSTOM_START + 156, EL_CUSTOM_START + 157, EL_CUSTOM_START + 158, EL_CUSTOM_START + 159, EL_CUSTOM_START + 160, EL_CUSTOM_START + 161, EL_CUSTOM_START + 162, EL_CUSTOM_START + 163, EL_CUSTOM_START + 164, EL_CUSTOM_START + 165, EL_CUSTOM_START + 166, EL_CUSTOM_START + 167, EL_CUSTOM_START + 168, EL_CUSTOM_START + 169, EL_CUSTOM_START + 170, EL_CUSTOM_START + 171, EL_CUSTOM_START + 172, EL_CUSTOM_START + 173, EL_CUSTOM_START + 174, EL_CUSTOM_START + 175, EL_CUSTOM_START + 176, EL_CUSTOM_START + 177, EL_CUSTOM_START + 178, EL_CUSTOM_START + 179, EL_CUSTOM_START + 180, EL_CUSTOM_START + 181, EL_CUSTOM_START + 182, EL_CUSTOM_START + 183, EL_CUSTOM_START + 184, EL_CUSTOM_START + 185, EL_CUSTOM_START + 186, EL_CUSTOM_START + 187, EL_CUSTOM_START + 188, EL_CUSTOM_START + 189, EL_CUSTOM_START + 190, EL_CUSTOM_START + 191, EL_CUSTOM_START + 192, EL_CUSTOM_START + 193, EL_CUSTOM_START + 194, EL_CUSTOM_START + 195, EL_CUSTOM_START + 196, EL_CUSTOM_START + 197, EL_CUSTOM_START + 198, EL_CUSTOM_START + 199, EL_CUSTOM_START + 200, EL_CUSTOM_START + 201, EL_CUSTOM_START + 202, EL_CUSTOM_START + 203, EL_CUSTOM_START + 204, EL_CUSTOM_START + 205, EL_CUSTOM_START + 206, EL_CUSTOM_START + 207, EL_CUSTOM_START + 208, EL_CUSTOM_START + 209, EL_CUSTOM_START + 210, EL_CUSTOM_START + 211, EL_CUSTOM_START + 212, EL_CUSTOM_START + 213, EL_CUSTOM_START + 214, EL_CUSTOM_START + 215, EL_CUSTOM_START + 216, EL_CUSTOM_START + 217, EL_CUSTOM_START + 218, EL_CUSTOM_START + 219, EL_CUSTOM_START + 220, EL_CUSTOM_START + 221, EL_CUSTOM_START + 222, EL_CUSTOM_START + 223, EL_CUSTOM_START + 224, EL_CUSTOM_START + 225, EL_CUSTOM_START + 226, EL_CUSTOM_START + 227, EL_CUSTOM_START + 228, EL_CUSTOM_START + 229, EL_CUSTOM_START + 230, EL_CUSTOM_START + 231, EL_CUSTOM_START + 232, EL_CUSTOM_START + 233, EL_CUSTOM_START + 234, EL_CUSTOM_START + 235, EL_CUSTOM_START + 236, EL_CUSTOM_START + 237, EL_CUSTOM_START + 238, EL_CUSTOM_START + 239, EL_CUSTOM_START + 240, EL_CUSTOM_START + 241, EL_CUSTOM_START + 242, EL_CUSTOM_START + 243, EL_CUSTOM_START + 244, EL_CUSTOM_START + 245, EL_CUSTOM_START + 246, EL_CUSTOM_START + 247, EL_CUSTOM_START + 248, EL_CUSTOM_START + 249, EL_CUSTOM_START + 250, EL_CUSTOM_START + 251, EL_CUSTOM_START + 252, EL_CUSTOM_START + 253, EL_CUSTOM_START + 254, EL_CUSTOM_START + 255 }; static int *editor_hl_custom_ptr = editor_hl_custom; static int *editor_el_custom_ptr = editor_el_custom; static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom); static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom); static int editor_hl_group[] = { EL_INTERNAL_CASCADE_GE_ACTIVE, EL_CHAR('G'), EL_CHAR('E'), EL_EMPTY, }; static int editor_el_group[] = { EL_GROUP_START + 0, EL_GROUP_START + 1, EL_GROUP_START + 2, EL_GROUP_START + 3, EL_GROUP_START + 4, EL_GROUP_START + 5, EL_GROUP_START + 6, EL_GROUP_START + 7, EL_GROUP_START + 8, EL_GROUP_START + 9, EL_GROUP_START + 10, EL_GROUP_START + 11, EL_GROUP_START + 12, EL_GROUP_START + 13, EL_GROUP_START + 14, EL_GROUP_START + 15, EL_GROUP_START + 16, EL_GROUP_START + 17, EL_GROUP_START + 18, EL_GROUP_START + 19, EL_GROUP_START + 20, EL_GROUP_START + 21, EL_GROUP_START + 22, EL_GROUP_START + 23, EL_GROUP_START + 24, EL_GROUP_START + 25, EL_GROUP_START + 26, EL_GROUP_START + 27, EL_GROUP_START + 28, EL_GROUP_START + 29, EL_GROUP_START + 30, EL_GROUP_START + 31 }; static int *editor_hl_group_ptr = editor_hl_group; static int *editor_el_group_ptr = editor_el_group; static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group); static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group); static int editor_hl_reference[] = { EL_INTERNAL_CASCADE_REF_ACTIVE, EL_CHAR('R'), EL_CHAR('E'), EL_CHAR('F') }; static int editor_el_reference[] = { EL_TRIGGER_PLAYER, EL_TRIGGER_ELEMENT, EL_TRIGGER_CE_VALUE, EL_TRIGGER_CE_SCORE, EL_SELF, EL_ANY_ELEMENT, EL_CURRENT_CE_VALUE, EL_CURRENT_CE_SCORE, EL_PREV_CE_8, EL_PREV_CE_7, EL_PREV_CE_6, EL_PREV_CE_5, EL_PREV_CE_4, EL_PREV_CE_3, EL_PREV_CE_2, EL_PREV_CE_1, EL_NEXT_CE_1, EL_NEXT_CE_2, EL_NEXT_CE_3, EL_NEXT_CE_4, EL_NEXT_CE_5, EL_NEXT_CE_6, EL_NEXT_CE_7, EL_NEXT_CE_8, }; static int *editor_hl_reference_ptr = editor_hl_reference; static int *editor_el_reference_ptr = editor_el_reference; static int num_editor_hl_reference = SIZEOF_ARRAY_INT(editor_hl_reference); static int num_editor_el_reference = SIZEOF_ARRAY_INT(editor_el_reference); static int editor_hl_user_defined[] = { EL_INTERNAL_CASCADE_USER_ACTIVE, EL_CHAR('M'), EL_CHAR('Y'), EL_EMPTY, }; static int *editor_hl_user_defined_ptr = editor_hl_user_defined; static int *editor_el_user_defined_ptr = NULL; static int num_editor_hl_user_defined=SIZEOF_ARRAY_INT(editor_hl_user_defined); static int num_editor_el_user_defined = 0; static int editor_hl_dynamic[] = { EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE, EL_CHAR('U'), EL_CHAR('S'), EL_CHAR('E'), }; static int *editor_hl_dynamic_ptr = editor_hl_dynamic; static int *editor_el_dynamic_ptr = NULL; static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic); static int num_editor_el_dynamic = 0; static int editor_hl_empty[] = { EL_EMPTY }; static int *editor_el_empty = NULL; /* dynamically allocated */ static int *editor_hl_empty_ptr = editor_hl_empty; static int *editor_el_empty_ptr = NULL; static int num_editor_hl_empty = 0; static int num_editor_el_empty = 0; /* dynamically determined, if needed */ static boolean use_el_empty = FALSE; static int *editor_elements = NULL; /* dynamically allocated */ static int num_editor_elements = 0; /* dynamically determined */ static boolean setup_editor_cascade_never = FALSE; static boolean setup_editor_el_players = TRUE; static boolean setup_editor_el_boulderdash = TRUE; static boolean setup_editor_el_emerald_mine = TRUE; static boolean setup_editor_el_emerald_mine_club = TRUE; static boolean setup_editor_el_more = TRUE; static boolean setup_editor_el_sokoban = TRUE; static boolean setup_editor_el_supaplex = TRUE; static boolean setup_editor_el_diamond_caves = TRUE; static boolean setup_editor_el_dx_boulderdash = TRUE; static boolean setup_editor_el_mirror_magic = TRUE; static boolean setup_editor_el_deflektor = TRUE; static boolean setup_editor_el_chars = TRUE; static boolean setup_editor_el_steel_chars = TRUE; static boolean setup_editor_el_custom = TRUE; static boolean setup_editor_el_user_defined = TRUE; static boolean setup_editor_el_dynamic = TRUE; static int editor_hl_unused[] = { EL_EMPTY }; static int *editor_hl_unused_ptr = editor_hl_unused; static int num_editor_hl_unused = 0; static struct { boolean *setup_value; boolean *setup_cascade_value; int **headline_list; int *headline_list_size; int **element_list; int *element_list_size; boolean last_setup_value; } editor_elements_info[] = { { &setup_editor_el_players, &setup_editor_cascade_never, &editor_hl_unused_ptr, &num_editor_hl_unused, &editor_el_players_ptr, &num_editor_el_players }, { &setup_editor_el_boulderdash, &setup.editor_cascade.el_bd, &editor_hl_boulderdash_ptr, &num_editor_hl_boulderdash, &editor_el_boulderdash_ptr, &num_editor_el_boulderdash }, { &setup_editor_el_emerald_mine, &setup.editor_cascade.el_em, &editor_hl_emerald_mine_ptr, &num_editor_hl_emerald_mine, &editor_el_emerald_mine_ptr, &num_editor_el_emerald_mine }, { &setup_editor_el_emerald_mine_club, &setup.editor_cascade.el_emc, &editor_hl_emerald_mine_club_ptr, &num_editor_hl_emerald_mine_club, &editor_el_emerald_mine_club_ptr, &num_editor_el_emerald_mine_club }, { &setup_editor_el_more, &setup.editor_cascade.el_rnd, &editor_hl_rnd_ptr, &num_editor_hl_rnd, &editor_el_rnd_ptr, &num_editor_el_rnd }, { &setup_editor_el_sokoban, &setup.editor_cascade.el_sb, &editor_hl_sokoban_ptr, &num_editor_hl_sokoban, &editor_el_sokoban_ptr, &num_editor_el_sokoban }, { &setup_editor_el_supaplex, &setup.editor_cascade.el_sp, &editor_hl_supaplex_ptr, &num_editor_hl_supaplex, &editor_el_supaplex_ptr, &num_editor_el_supaplex }, { &setup_editor_el_diamond_caves, &setup.editor_cascade.el_dc, &editor_hl_diamond_caves_ptr, &num_editor_hl_diamond_caves, &editor_el_diamond_caves_ptr, &num_editor_el_diamond_caves }, { &setup_editor_el_dx_boulderdash, &setup.editor_cascade.el_dx, &editor_hl_dx_boulderdash_ptr, &num_editor_hl_dx_boulderdash, &editor_el_dx_boulderdash_ptr, &num_editor_el_dx_boulderdash }, { &setup_editor_el_mirror_magic, &setup.editor_cascade.el_mm, &editor_hl_mirror_magic_ptr, &num_editor_hl_mirror_magic, &editor_el_mirror_magic_ptr, &num_editor_el_mirror_magic }, { &setup_editor_el_deflektor, &setup.editor_cascade.el_df, &editor_hl_deflektor_ptr, &num_editor_hl_deflektor, &editor_el_deflektor_ptr, &num_editor_el_deflektor }, { &setup_editor_el_chars, &setup.editor_cascade.el_chars, &editor_hl_chars_ptr, &num_editor_hl_chars, &editor_el_chars_ptr, &num_editor_el_chars }, { &setup_editor_el_steel_chars, &setup.editor_cascade.el_steel_chars, &editor_hl_steel_chars_ptr, &num_editor_hl_steel_chars, &editor_el_steel_chars_ptr, &num_editor_el_steel_chars }, { &setup_editor_el_custom, &setup.editor_cascade.el_ce, &editor_hl_custom_ptr, &num_editor_hl_custom, &editor_el_custom_ptr, &num_editor_el_custom }, { &setup_editor_el_custom, &setup.editor_cascade.el_ge, &editor_hl_group_ptr, &num_editor_hl_group, &editor_el_group_ptr, &num_editor_el_group }, { &setup_editor_el_custom, &setup.editor_cascade.el_ref, &editor_hl_reference_ptr, &num_editor_hl_reference, &editor_el_reference_ptr, &num_editor_el_reference }, { &setup_editor_el_user_defined, &setup.editor_cascade.el_user, &editor_hl_user_defined_ptr, &num_editor_hl_user_defined, &editor_el_user_defined_ptr, &num_editor_el_user_defined }, { &setup_editor_el_dynamic, &setup.editor_cascade.el_dynamic, &editor_hl_dynamic_ptr, &num_editor_hl_dynamic, &editor_el_dynamic_ptr, &num_editor_el_dynamic, }, { &use_el_empty, &use_el_empty, &editor_hl_empty_ptr, &num_editor_hl_empty, &editor_el_empty_ptr, &num_editor_el_empty, }, { NULL, NULL, NULL, NULL, NULL, NULL } }; /* ----------------------------------------------------------------------------- functions ----------------------------------------------------------------------------- */ static int getMaxInfoTextLength() { return (SXSIZE / getFontWidth(INFOTEXT_FONT)); } static int getTextWidthForGadget(char *text) { if (text == NULL) return 0; return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE); } static int getTextWidthForDrawingArea(char *text) { if (text == NULL) return 0; return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE); } static int getRightGadgetBorder(struct GadgetInfo *gi, char *text) { return (gi->x + gi->width + getTextWidthForGadget(text)); } static char *getElementInfoText(int element) { char *info_text = NULL; if (element < MAX_NUM_ELEMENTS) { if (strlen(element_info[element].description) > 0) info_text = element_info[element].description; else if (element_info[element].custom_description != NULL) info_text = element_info[element].custom_description; else if (element_info[element].editor_description != NULL) info_text = element_info[element].editor_description; } if (info_text == NULL) info_text = INFOTEXT_UNKNOWN_ELEMENT; return info_text; } static char *getElementDescriptionFilenameExt(char *basename) { char *elements_subdir = "elements"; static char *elements_subdir2 = NULL; static char *filename = NULL; if (elements_subdir2 == NULL) elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir); checked_free(filename); /* 1st try: look for element description in current level set directory */ filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename); if (fileExists(filename)) return filename; free(filename); /* 2nd try: look for element description in the game's base directory */ filename = getPath3(options.docs_directory, elements_subdir, basename); if (fileExists(filename)) return filename; return NULL; } char *getElementDescriptionFilename(int element) { char basename[MAX_FILENAME_LEN]; char *filename; /* 1st try: look for element description file for exactly this element */ sprintf(basename, "%s.txt", element_info[element].token_name); filename = getElementDescriptionFilenameExt(basename); if (filename != NULL) return filename; /* 2nd try: look for element description file for this element's class */ sprintf(basename, "%s.txt", element_info[element].class_name); filename = getElementDescriptionFilenameExt(basename); if (filename != NULL) return filename; return NULL; } static boolean suppressBorderElement() { return (level.game_engine_type == GAME_ENGINE_TYPE_MM && lev_fieldx <= MAX_ED_FIELDX && lev_fieldy <= MAX_ED_FIELDY); } static void InitDynamicEditorElementList(int **elements, int *num_elements) { boolean element_found[NUM_FILE_ELEMENTS]; int i, x, y; /* initialize list of used elements to "not used" */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) element_found[i] = FALSE; /* find all elements used in current level */ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] < NUM_FILE_ELEMENTS) /* should always be true */ element_found[Feld[x][y]] = TRUE; *num_elements = 0; /* count number of elements used in current level */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (element_found[i]) (*num_elements)++; /* add space for up to 3 more elements for padding that may be needed */ *num_elements += 3; /* free memory for old list of elements, if needed */ checked_free(*elements); /* allocate memory for new list of elements */ *elements = checked_malloc(*num_elements * sizeof(int)); *num_elements = 0; /* add all elements used in current level (non-custom/group elements) */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i))) (*elements)[(*num_elements)++] = i; /* add all elements used in current level (custom/group elements) */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i))) (*elements)[(*num_elements)++] = i; while (*num_elements % 4) /* pad with empty elements, if needed */ (*elements)[(*num_elements)++] = EL_EMPTY; } static void ReinitializeElementList_EnableSections() { /* default: enable all element sections */ setup_editor_el_players = TRUE; setup_editor_el_boulderdash = TRUE; setup_editor_el_emerald_mine = TRUE; setup_editor_el_emerald_mine_club = TRUE; setup_editor_el_more = TRUE; setup_editor_el_sokoban = TRUE; setup_editor_el_supaplex = TRUE; setup_editor_el_diamond_caves = TRUE; setup_editor_el_dx_boulderdash = TRUE; setup_editor_el_mirror_magic = TRUE; setup_editor_el_deflektor = TRUE; setup_editor_el_chars = TRUE; setup_editor_el_steel_chars = TRUE; setup_editor_el_custom = TRUE; setup_editor_el_user_defined = TRUE; setup_editor_el_dynamic = TRUE; /* now disable all element sections not to be displayed */ if (!setup.editor.el_classic) { setup_editor_el_players = FALSE; setup_editor_el_boulderdash = FALSE; setup_editor_el_emerald_mine = FALSE; setup_editor_el_emerald_mine_club = FALSE; setup_editor_el_more = FALSE; setup_editor_el_sokoban = FALSE; setup_editor_el_supaplex = FALSE; setup_editor_el_diamond_caves = FALSE; setup_editor_el_dx_boulderdash = FALSE; setup_editor_el_mirror_magic = FALSE; setup_editor_el_deflektor = FALSE; setup_editor_el_chars = FALSE; setup_editor_el_steel_chars = FALSE; } if (!setup.editor.el_custom) { setup_editor_el_custom = FALSE; } if (!setup.editor.el_user_defined) { setup_editor_el_user_defined = FALSE; } if (!setup.editor.el_dynamic) { setup_editor_el_dynamic = FALSE; } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { setup_editor_el_mirror_magic = FALSE; setup_editor_el_deflektor = FALSE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { setup_editor_el_boulderdash = FALSE; setup_editor_el_more = FALSE; setup_editor_el_sokoban = FALSE; setup_editor_el_supaplex = FALSE; setup_editor_el_diamond_caves = FALSE; setup_editor_el_dx_boulderdash = FALSE; setup_editor_el_mirror_magic = FALSE; setup_editor_el_deflektor = FALSE; setup_editor_el_steel_chars = FALSE; setup_editor_el_custom = FALSE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { setup_editor_el_players = FALSE; setup_editor_el_boulderdash = FALSE; setup_editor_el_emerald_mine = FALSE; setup_editor_el_emerald_mine_club = FALSE; setup_editor_el_more = FALSE; setup_editor_el_sokoban = FALSE; setup_editor_el_diamond_caves = FALSE; setup_editor_el_dx_boulderdash = FALSE; setup_editor_el_mirror_magic = FALSE; setup_editor_el_deflektor = FALSE; setup_editor_el_chars = FALSE; setup_editor_el_steel_chars = FALSE; setup_editor_el_custom = FALSE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { setup_editor_el_players = FALSE; setup_editor_el_boulderdash = FALSE; setup_editor_el_emerald_mine = FALSE; setup_editor_el_emerald_mine_club = FALSE; setup_editor_el_more = FALSE; setup_editor_el_sokoban = FALSE; setup_editor_el_supaplex = FALSE; setup_editor_el_diamond_caves = FALSE; setup_editor_el_dx_boulderdash = FALSE; setup_editor_el_steel_chars = FALSE; setup_editor_el_custom = FALSE; } } static void ReinitializeElementList() { static boolean initialization_needed = TRUE; int pos = 0; int i, j; ReinitializeElementList_EnableSections(); if (initialization_needed) { LoadSetup_EditorCascade(); /* load last editor cascade state */ /* initialize editor cascade element from saved cascade state */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { int *cascade_element = &(*editor_elements_info[i].headline_list)[0]; boolean cascade_value = *editor_elements_info[i].setup_cascade_value; if (IS_EDITOR_CASCADE(*cascade_element)) *cascade_element = (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) : EL_CASCADE_INACTIVE(*cascade_element)); } initialization_needed = FALSE; } checked_free(editor_elements); /* reload optional user defined element list for each invocation of editor */ LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr, &num_editor_el_user_defined); /* initialize dynamic level element list for each invocation of editor */ InitDynamicEditorElementList(&editor_el_dynamic_ptr, &num_editor_el_dynamic); /* initialize list of empty elements (used for padding, if needed) */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) editor_el_empty[i] = EL_EMPTY; /* do some sanity checks for each element from element list */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { for (j = 0; j < *editor_elements_info[i].element_list_size; j++) { int element = (*editor_elements_info[i].element_list)[j]; if (element >= NUM_FILE_ELEMENTS) Error(ERR_WARN, "editor element %d is runtime element", element); if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT)) Error(ERR_WARN, "no element description text for element %d", element); } } num_editor_elements = 0; use_el_empty = FALSE; /* determine size of element list */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { boolean found_inactive_cascade = FALSE; if (*editor_elements_info[i].setup_value) { if (setup.editor.el_headlines) { // required for correct padding of palette headline buttons if (*editor_elements_info[i].headline_list_size > 0) num_editor_elements += editor.palette.cols; for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) { int element = (*editor_elements_info[i].headline_list)[j]; if (IS_EDITOR_CASCADE_INACTIVE(element)) found_inactive_cascade = TRUE; } } if (found_inactive_cascade) continue; // required for correct padding of palette element buttons int element_list_size = *editor_elements_info[i].element_list_size; int element_rows = (element_list_size + editor.palette.cols - 1) / editor.palette.cols; int element_buttons = editor.palette.cols * element_rows; num_editor_elements += element_buttons; } } if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS) { /* offer at least as many elements as element buttons exist */ use_el_empty = TRUE; num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements; num_editor_elements += num_editor_el_empty; } else { num_editor_el_empty = 0; } editor_elements = checked_malloc(num_editor_elements * sizeof(int)); /* fill element list */ for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { boolean found_inactive_cascade = FALSE; if (*editor_elements_info[i].setup_value) { if (setup.editor.el_headlines) { // required for correct padding of palette headline buttons int headline_size = (*editor_elements_info[i].headline_list_size > 0 ? editor.palette.cols : 0); for (j = 0; j < headline_size; j++) { // use empty elements for padding of palette headline buttons int element = (j < *editor_elements_info[i].headline_list_size ? (*editor_elements_info[i].headline_list)[j] : editor_el_empty[0]); editor_elements[pos++] = element; if (IS_EDITOR_CASCADE_INACTIVE(element)) found_inactive_cascade = TRUE; } } if (found_inactive_cascade) continue; // required for correct padding of palette element buttons int element_list_size = *editor_elements_info[i].element_list_size; int element_rows = (element_list_size + editor.palette.cols - 1) / editor.palette.cols; int element_buttons = editor.palette.cols * element_rows; // copy all elements from element list for (j = 0; j < element_list_size; j++) editor_elements[pos++] = (*editor_elements_info[i].element_list)[j]; // use empty elements for padding of palette element buttons for (j = 0; j < element_buttons - element_list_size; j++) editor_elements[pos++] = editor_el_empty[0]; } } /* (this function is also called before editor gadgets are initialized!) */ AdjustElementListScrollbar(); } void PrintEditorElementList() { boolean *stop = &setup_editor_el_user_defined; int i, j; for (i = 0; editor_elements_info[i].setup_value != stop; i++) { int cascade_element = (*editor_elements_info[i].headline_list)[0]; if (IS_EDITOR_CASCADE(cascade_element)) { int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element); char *headline = element_info[cascade_element_show].editor_description; PrintLineWithPrefix("# ", "-", 77); Print("# %s\n", headline); PrintLineWithPrefix("# ", "-", 77); } for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) { int element = (*editor_elements_info[i].headline_list)[j]; if (IS_EDITOR_CASCADE(element)) element = EL_CHAR_MINUS; Print("# %s\n", element_info[element].token_name); } if (j > 0) Print("#\n"); for (j = 0; j < *editor_elements_info[i].element_list_size; j++) { int element = (*editor_elements_info[i].element_list)[j]; Print("# %s\n", element_info[element].token_name); } if (j > 0) Print("#\n"); } } static void ReinitializeElementListButtons() { static boolean last_setup_value_headlines = FALSE; static boolean initialization_needed = TRUE; int i; if (!initialization_needed) /* check if editor element setup has changed */ { if (last_setup_value_headlines != setup.editor.el_headlines) initialization_needed = TRUE; for (i = 0; editor_elements_info[i].setup_value != NULL; i++) if (editor_elements_info[i].last_setup_value != *editor_elements_info[i].setup_value) initialization_needed = TRUE; } if (!initialization_needed) return; FreeLevelEditorGadgets(); CreateLevelEditorGadgets(); /* store current setup values for next invocation of this function */ last_setup_value_headlines = setup.editor.el_headlines; for (i = 0; editor_elements_info[i].setup_value != NULL; i++) editor_elements_info[i].last_setup_value = *editor_elements_info[i].setup_value; initialization_needed = FALSE; } static void DrawElementBorder(int dest_x, int dest_y, int width, int height, boolean input) { int border_graphic = (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER); struct GraphicInfo *g = &graphic_info[border_graphic]; Bitmap *src_bitmap = g->bitmap; int src_x = g->src_x; int src_y = g->src_y; int border_size = g->border_size; int border_xpos = g->width - border_size; int border_ypos = g->height - border_size; int tilesize = ED_DRAWINGAREA_TILE_SIZE; int i; BlitBitmap(src_bitmap, drawto, src_x, src_y, border_size, border_size, dest_x - border_size, dest_y - border_size); BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y, border_size, border_size, dest_x + width, dest_y - border_size); BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos, border_size, border_size, dest_x - border_size, dest_y + height); BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos, border_size, border_size, dest_x + width, dest_y + height); for (i = 0; i < width / tilesize; i++) { BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y, tilesize, border_size, dest_x + i * tilesize, dest_y - border_size); BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos, tilesize, border_size, dest_x + i * tilesize, dest_y + height); } for (i = 0; i < height / tilesize; i++) { BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size, border_size, tilesize, dest_x - border_size, dest_y + i * tilesize); BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size, border_size, tilesize, dest_x + width, dest_y + i * tilesize); } ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2); } static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize) { int xsize_tile = MAX(ed_tilesize, xsize); int ysize_tile = MAX(ed_tilesize, ysize); int xsize_full = xsize + 1; int ysize_full = ysize + 1; int xsize_thin = (xsize < ed_tilesize ? 1 : xsize); int ysize_thin = (ysize < ed_tilesize ? 1 : ysize); Pixel line_color = getTabulatorBarColor(); if (line_color == BLACK_PIXEL) /* black => transparent */ return; FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL); FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color); FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL); } static void DrawEditorLevelBorderLinesIfNeeded() { int xsize = lev_fieldx * ed_tilesize; int ysize = lev_fieldy * ed_tilesize; int line_size = getTabulatorBarHeight(); if (!suppressBorderElement()) return; /* draw little border line around editable level playfield */ if (xsize < SXSIZE) DrawEditorLevelBorderLine(xsize, 0, line_size, ysize); if (ysize < SYSIZE) DrawEditorLevelBorderLine(0, ysize, xsize, line_size); if (xsize < SXSIZE && ysize < SYSIZE) DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size); } static void DrawEditorElement(int x, int y, int element) { DrawSizedElement(x, y, element, ed_tilesize); } static void DrawEditorElementThruMask(int x, int y, int element) { DrawSizedElementThruMask(x, y, element, ed_tilesize); } static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y) { DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize); } static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y) { DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize); DrawEditorLevelBorderLinesIfNeeded(); } static void DrawDrawingArea(int id) { struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int x, y; int *value = drawingarea_info[id].value; int area_xsize = drawingarea_info[id].area_xsize; int area_ysize = drawingarea_info[id].area_ysize; int tilesize = ED_DRAWINGAREA_TILE_SIZE; for (x = 0; x < area_xsize; x++) for (y = 0; y < area_ysize; y++) DrawSizedGraphicExt(drawto, gi->x + x * tilesize, gi->y + y * tilesize, el2edimg(value[x * area_ysize + y]), 0, tilesize); } static void ScrollEditorLevel(int from_x, int from_y, int scroll) { int x, y; int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0); int dy = (scroll == ED_SCROLL_UP ? -1 : scroll == ED_SCROLL_DOWN ? 1 : 0); BlitBitmap(drawto, drawto, SX + (dx == -1 ? ed_tilesize : 0), SY + (dy == -1 ? ed_tilesize : 0), (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0), (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0), SX + (dx == +1 ? ed_tilesize : 0), SY + (dy == +1 ? ed_tilesize : 0)); if (dx) { x = (dx == 1 ? 0 : ed_fieldx - 1); for (y = 0; y < ed_fieldy; y++) DrawEditorElementOrWall(x, y, from_x, from_y); } else if (dy) { y = (dy == 1 ? 0 : ed_fieldy - 1); for (x = 0; x < ed_fieldx; x++) DrawEditorElementOrWall(x, y, from_x, from_y); } redraw_mask |= REDRAW_FIELD; BackToFront(); } void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap, int *x, int *y) { getSizedGraphicSource(el2edimg(element), 0, tile_size, bitmap, x, y); } static void CreateControlButtons() { struct GadgetInfo *gi; int i; /* create toolbox buttons */ for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++) { int id = controlbutton_info[i].gadget_id; int type = controlbutton_info[i].gadget_type; int graphic = controlbutton_info[i].graphic; struct XYTileSize *pos = controlbutton_info[i].pos; struct GraphicInfo *gd = &graphic_info[graphic]; Bitmap *deco_bitmap = NULL; int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0; int tile_size = 0, deco_shift = 0; boolean deco_masked = FALSE; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; int gd_x1a = gd->src_x + gd->active_xoffset; int gd_y1a = gd->src_y + gd->active_yoffset; int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset; int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset; int x = pos->x; int y = pos->y; unsigned int event_mask; int radio_button_nr = RADIO_NR_NONE; boolean checked = FALSE; if (type == GD_TYPE_RADIO_BUTTON) { event_mask = GD_EVENT_PRESSED; radio_button_nr = RADIO_NR_DRAWING_TOOLBOX; if (id == drawing_function) checked = TRUE; } else { if (id == GADGET_ID_WRAP_LEFT || id == GADGET_ID_WRAP_RIGHT || id == GADGET_ID_WRAP_UP || id == GADGET_ID_WRAP_DOWN) event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; else event_mask = GD_EVENT_RELEASED; } if (id == GADGET_ID_PROPERTIES || id == GADGET_ID_PALETTE) { x += DX; y += DY; } else if (id == GADGET_ID_ELEMENT_LEFT || id == GADGET_ID_ELEMENT_MIDDLE || id == GADGET_ID_ELEMENT_RIGHT) { x += DX; y += DY; int element = (id == GADGET_ID_ELEMENT_LEFT ? new_element1 : id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 : id == GADGET_ID_ELEMENT_RIGHT ? new_element3 : EL_EMPTY); tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ? editor.button.element_left.tile_size : id == GADGET_ID_ELEMENT_MIDDLE ? editor.button.element_middle.tile_size : id == GADGET_ID_ELEMENT_RIGHT ? editor.button.element_right.tile_size : 0); // make sure that decoration does not overlap gadget border tile_size = MIN(tile_size, MIN(gd->width, gd->height)); getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y); deco_xpos = (gd->width - tile_size) / 2; deco_ypos = (gd->height - tile_size) / 2; deco_shift = 1; deco_masked = gd->draw_masked; } else { x += EX; y += EY; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, controlbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, gd->width, GDI_HEIGHT, gd->height, GDI_TYPE, type, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_RADIO_NR, radio_button_nr, GDI_CHECKED, checked, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a, GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_DECORATION_POSITION, deco_xpos, deco_ypos, GDI_DECORATION_SIZE, tile_size, tile_size, GDI_DECORATION_SHIFTING, deco_shift, deco_shift, GDI_DECORATION_MASKED, deco_masked, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } /* these values are not constant, but can change at runtime */ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x = ED_SCROLL_UP_XPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y = ED_SCROLL_UP_YPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x = ED_SCROLL_DOWN_XPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y = ED_SCROLL_DOWN_YPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x = ED_SCROLL_LEFT_XPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y = ED_SCROLL_LEFT_YPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x = ED_SCROLL2_UP_XPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y = ED_SCROLL2_UP_YPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x = ED_SCROLL2_DOWN_XPOS; scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y = ED_SCROLL2_DOWN_YPOS; /* create buttons for scrolling of drawing area and element list */ for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++) { int id = scrollbutton_info[i].gadget_id; int graphic = scrollbutton_info[i].graphic; struct GraphicInfo *gd = &graphic_info[graphic]; Bitmap *gd_bitmap = gd->bitmap; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; int width = gd->width; int height = gd->height; int x = scrollbutton_pos[i].x; int y = scrollbutton_pos[i].y; unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; if (id == GADGET_ID_SCROLL_LIST_UP || id == GADGET_ID_SCROLL_LIST_DOWN) { x += PX; y += PY; } else { x += SX; y += SY; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } /* create buttons for element list */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) { int id = GADGET_ID_ELEMENTLIST_FIRST + i; int graphic = IMG_EDITOR_PALETTE_BUTTON; struct GraphicInfo *gd = &graphic_info[graphic]; Bitmap *gd_bitmap = gd->bitmap; Bitmap *deco_bitmap; int deco_x, deco_y, deco_xpos, deco_ypos; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ; int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ; int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width; int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height; int element = editor_elements[i]; int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size); unsigned int event_mask = GD_EVENT_RELEASED; getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y); deco_xpos = (gd->width - tile_size) / 2; deco_ypos = (gd->height - tile_size) / 2; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, getElementInfoText(element), GDI_X, x, GDI_Y, y, GDI_WIDTH, gd->width, GDI_HEIGHT, gd->height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_DECORATION_POSITION, deco_xpos, deco_ypos, GDI_DECORATION_SIZE, tile_size, tile_size, GDI_DECORATION_SHIFTING, 1, 1, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateCounterButtons() { int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++) { int j; int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); /* down count button */ int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y); /* determine horizontal position to the right of specified gadget */ if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[counterbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (counterbutton_info[i].text_left != NULL) x += getTextWidthForGadget(counterbutton_info[i].text_left); for (j = 0; j < 2; j++) { struct GadgetInfo *gi; int id = (j == 0 ? counterbutton_info[i].gadget_id_down : counterbutton_info[i].gadget_id_up); int graphic; struct GraphicInfo *gd; int gd_x1, gd_x2, gd_y1, gd_y2; unsigned int event_mask; char infotext[max_infotext_len + 1]; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; if (i == ED_COUNTER_ID_SELECT_LEVEL) { graphic = (j == 0 ? IMG_GFX_EDITOR_BUTTON_PREV_LEVEL : IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL); event_mask |= GD_EVENT_RELEASED; if (j == 0) { x = DX + editor.button.prev_level.x; y = DY + editor.button.prev_level.y; } else { x = DX + editor.button.next_level.x; y = DY + editor.button.next_level.y; } } else { graphic = (j == 0 ? IMG_EDITOR_COUNTER_DOWN : IMG_EDITOR_COUNTER_UP); } gd = &graphic_info[graphic]; gd_x1 = gd->src_x; gd_y1 = gd->src_y; gd_x2 = gd->src_x + gd->pressed_xoffset; gd_y2 = gd->src_y + gd->pressed_yoffset; sprintf(infotext, "%s counter value by 1, 5 or 10", (j == 0 ? "decrease" : "increase")); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, gd->width, GDI_HEIGHT, gd->height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleCounterButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, counterbutton_info[i].text_right); x += gi->width + ED_GADGET_SMALL_DISTANCE; /* text count button */ if (j == 0) { int font_type = FONT_INPUT_1; int font_type_active = FONT_INPUT_1_ACTIVE; id = counterbutton_info[i].gadget_id_text; event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; if (i == ED_COUNTER_ID_SELECT_LEVEL) { graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER; font_type = FONT_LEVEL_NUMBER; font_type_active = FONT_LEVEL_NUMBER_ACTIVE; x = DX + editor.input.level_number.x; y = DY + editor.input.level_number.y; } else { graphic = IMG_EDITOR_COUNTER_INPUT; } gd = &graphic_info[graphic]; gd_x1 = gd->src_x; gd_y1 = gd->src_y; gd_x2 = gd->src_x + gd->active_xoffset; gd_y2 = gd->src_y + gd->active_yoffset; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, "enter counter value", GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC, GDI_NUMBER_VALUE, 0, GDI_NUMBER_MIN, counterbutton_info[i].min_value, GDI_NUMBER_MAX, counterbutton_info[i].max_value, GDI_TEXT_SIZE, 3, /* minimal counter text size */ GDI_TEXT_FONT, font_type, GDI_TEXT_FONT_ACTIVE, font_type_active, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_BORDER_SIZE, gd->border_size, gd->border_size, GDI_DESIGN_WIDTH, gd->width, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleCounterButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, counterbutton_info[i].text_right); x += gi->width + ED_GADGET_SMALL_DISTANCE; /* up count button */ } } } } static void CreateDrawingAreas() { int i; /* these values are not constant, but can change at runtime */ drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX; drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY; for (i = 0; i < ED_NUM_DRAWING_AREAS; i++) { struct GadgetInfo *gi; unsigned int event_mask; int id = drawingarea_info[i].gadget_id; int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]); int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]); int area_xsize = drawingarea_info[i].area_xsize; int area_ysize = drawingarea_info[i].area_ysize; int item_size = (id == GADGET_ID_DRAWING_LEVEL ? ed_tilesize : ED_DRAWINGAREA_TILE_SIZE); event_mask = GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE; /* determine horizontal position to the right of specified gadget */ if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[drawingarea_info[i].gadget_id_align] + ED_DRAWINGAREA_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (drawingarea_info[i].text_left != NULL) x += getTextWidthForDrawingArea(drawingarea_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_DRAWING_AREA, GDI_AREA_SIZE, area_xsize, area_ysize, GDI_ITEM_SIZE, item_size, item_size, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleDrawingAreaInfo, GDI_CALLBACK_ACTION, HandleDrawingAreas, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, drawingarea_info[i].text_right); } } static void CreateTextInputGadgets() { struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT]; int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_TEXTINPUT; i++) { int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->active_xoffset; int gd_y2 = gd->src_y + gd->active_yoffset; struct GadgetInfo *gi; unsigned int event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = textinput_info[i].gadget_id; int x, y; if (i == ED_TEXTINPUT_ID_ELEMENT_NAME) { int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size; int border_size = gd->border_size; int font_nr = FONT_INPUT_1; int font_height = getFontHeight(font_nr); int xoffset = element_border + TILEX + element_border + 3 * border_size; int yoffset = element_border + (TILEY - font_height) / 2; x = (editor.settings.element_name.x != -1 ? editor.settings.element_name.x : editor.settings.element_graphic.x + xoffset) - border_size; y = (editor.settings.element_name.y != -1 ? editor.settings.element_name.y : editor.settings.element_graphic.y + yoffset) - border_size; } else { x = ED_SETTINGS_X(textinput_info[i].x); y = ED_SETTINGS_Y(textinput_info[i].y); } event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; sprintf(infotext, "Enter %s", textinput_info[i].infotext); infotext[max_infotext_len] = '\0'; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, SX + x, GDI_Y, SY + y, GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC, GDI_TEXT_VALUE, textinput_info[i].value, GDI_TEXT_SIZE, textinput_info[i].size, GDI_TEXT_FONT, FONT_INPUT_1, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_BORDER_SIZE, gd->border_size, gd->border_size, GDI_DESIGN_WIDTH, gd->width, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleTextInputGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateTextAreaGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_TEXTAREAS; i++) { struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->active_xoffset; int gd_y2 = gd->src_y + gd->active_yoffset; struct GadgetInfo *gi; unsigned int event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = textarea_info[i].gadget_id; int area_xsize = textarea_info[i].xsize; int area_ysize = textarea_info[i].ysize; event_mask = GD_EVENT_TEXT_LEAVING; sprintf(infotext, "Enter %s", textarea_info[i].infotext); infotext[max_infotext_len] = '\0'; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x), GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y), GDI_TYPE, GD_TYPE_TEXT_AREA, GDI_AREA_SIZE, area_xsize, area_ysize, GDI_TEXT_FONT, FONT_INPUT_1, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_BORDER_SIZE, gd->border_size, gd->border_size, GDI_DESIGN_WIDTH, gd->width, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleTextAreaGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateSelectboxGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i, j; for (i = 0; i < ED_NUM_SELECTBOX; i++) { struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT]; struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->active_xoffset; int gd_y2 = gd->src_y + gd->active_yoffset; int selectbox_button_xsize = gd2->width; struct GadgetInfo *gi; unsigned int event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int id = selectbox_info[i].gadget_id; int x = SX + ED_SETTINGS_X(selectbox_info[i].x); int y = SY + ED_SETTINGS_Y(selectbox_info[i].y); if (selectbox_info[i].size == -1) /* dynamically determine size */ { /* (we cannot use -1 for uninitialized values if we directly compare with results from strlen(), because the '<' and '>' operation will implicitely cast -1 to an unsigned integer value!) */ selectbox_info[i].size = 0; for (j = 0; selectbox_info[i].options[j].text != NULL; j++) if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size) selectbox_info[i].size = strlen(selectbox_info[i].options[j].text); selectbox_info[i].size++; /* add one character empty space */ } event_mask = GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING; /* determine horizontal position to the right of specified gadget */ if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[selectbox_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (selectbox_info[i].text_left != NULL) x += getTextWidthForGadget(selectbox_info[i].text_left); sprintf(infotext, "Select %s", selectbox_info[i].infotext); infotext[max_infotext_len] = '\0'; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_SELECTBOX, GDI_SELECTBOX_OPTIONS, selectbox_info[i].options, GDI_SELECTBOX_CHAR_UNSELECTABLE, '[', GDI_TEXT_SIZE, selectbox_info[i].size, GDI_TEXT_FONT, FONT_INPUT_1, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE, GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_BORDER_SIZE, gd->border_size, gd->border_size, GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize, GDI_DESIGN_WIDTH, gd->width, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleSelectboxGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, selectbox_info[i].text_right); } } static void CreateTextbuttonGadgets() { int max_infotext_len = getMaxInfoTextLength(); int i; for (i = 0; i < ED_NUM_TEXTBUTTONS; i++) { int id = textbutton_info[i].gadget_id; int is_tab_button = ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) || (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE)); int graphic = (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON); int gadget_distance = (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE); struct GraphicInfo *gd = &graphic_info[graphic]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; int gd_x1a = gd->src_x + gd->active_xoffset; int gd_y1a = gd->src_y + gd->active_yoffset; int border_xsize = gd->border_size + gd->draw_xoffset; int border_ysize = gd->border_size; struct GadgetInfo *gi; unsigned int event_mask; char infotext[MAX_OUTPUT_LINESIZE + 1]; int x = SX + ED_SETTINGS_X(textbutton_info[i].x); int y = SY + ED_SETTINGS_Y(textbutton_info[i].y); if (textbutton_info[i].size == -1) /* dynamically determine size */ textbutton_info[i].size = strlen(textbutton_info[i].text); event_mask = GD_EVENT_RELEASED; sprintf(infotext, "%s", textbutton_info[i].infotext); infotext[max_infotext_len] = '\0'; /* determine horizontal position to the right of specified gadget */ if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE) { int gadget_id_align = textbutton_info[i].gadget_id_align; x = right_gadget_border[gadget_id_align] + gadget_distance; if (textbutton_info[i].y == -1) y = level_editor_gadget[gadget_id_align]->y; } /* determine horizontal offset for leading text */ if (textbutton_info[i].text_left != NULL) x += getTextWidthForGadget(textbutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, infotext, GDI_X, x, GDI_Y, y, GDI_TYPE, GD_TYPE_TEXT_BUTTON, GDI_TEXT_VALUE, textbutton_info[i].text, GDI_TEXT_SIZE, textbutton_info[i].size, GDI_TEXT_FONT, FONT_INPUT_2, GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a, GDI_BORDER_SIZE, border_xsize, border_ysize, GDI_DESIGN_WIDTH, gd->width, GDI_DECORATION_SHIFTING, 1, 1, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleTextbuttonGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, textbutton_info[i].text_right); } } static void CreateGraphicbuttonGadgets() { struct GadgetInfo *gi; unsigned int event_mask; int i; /* create buttons for scrolling of drawing area and element list */ for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++) { int id = graphicbutton_info[i].gadget_id; int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x); int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y); struct GraphicInfo *gd = &graphic_info[graphicbutton_info[i].graphic]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; /* determine horizontal position to the right of specified gadget */ if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (graphicbutton_info[i].text_left != NULL) x += getTextWidthForGadget(graphicbutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, graphicbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, gd->width, GDI_HEIGHT, gd->height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, graphicbutton_info[i].text_right); } } static void CreateScrollbarGadgets() { int i; /* these values are not constant, but can change at runtime */ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x = SX + ED_SCROLL_HORIZONTAL_XPOS; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y = SY + ED_SCROLL_HORIZONTAL_YPOS; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width = ED_SCROLL_HORIZONTAL_XSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height = ED_SCROLL_HORIZONTAL_YSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x = SX; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y = SY; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width = SXSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x = SX + ED_SCROLL_VERTICAL_XPOS; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y = SY + ED_SCROLL_VERTICAL_YPOS; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width = ED_SCROLL_VERTICAL_XSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height = ED_SCROLL_VERTICAL_YSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x = SX; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y = SY; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width = SXSIZE; scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x = PX + ED_SCROLL2_VERTICAL_XPOS; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y = PY + ED_SCROLL2_VERTICAL_YPOS; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width = ED_SCROLL2_VERTICAL_XSIZE; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height = ED_SCROLL2_VERTICAL_YSIZE; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width = PXSIZE; scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE; for (i = 0; i < ED_NUM_SCROLLBARS; i++) { int id = scrollbar_info[i].gadget_id; int graphic = scrollbar_info[i].graphic; struct GraphicInfo *gd = &graphic_info[graphic]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; struct GadgetInfo *gi; int items_max, items_visible, item_position; unsigned int event_mask; if (i == ED_SCROLLBAR_ID_LIST_VERTICAL) { items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ; items_visible = ED_ELEMENTLIST_BUTTONS_VERT; item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ; } else /* drawing area scrollbars */ { if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL) { items_max = MAX(lev_fieldx + 2, ed_fieldx); items_visible = ed_fieldx; item_position = 0; } else { items_max = MAX(lev_fieldy + 2, ed_fieldy); items_visible = ed_fieldy; item_position = 0; } } event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbar_info[i].infotext, GDI_X, scrollbar_pos[i].x, GDI_Y, scrollbar_pos[i].y, GDI_WIDTH, scrollbar_pos[i].width, GDI_HEIGHT, scrollbar_pos[i].height, GDI_TYPE, scrollbar_info[i].type, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x, GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y, GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width, GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_BORDER_SIZE, gd->border_size, gd->border_size, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleControlButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; } } static void CreateCheckbuttonGadgets() { struct GadgetInfo *gi; unsigned int event_mask; int i; event_mask = GD_EVENT_PRESSED; for (i = 0; i < ED_NUM_CHECKBUTTONS; i++) { int id = checkbutton_info[i].gadget_id; int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON : IMG_EDITOR_CHECKBOX); struct GraphicInfo *gd = &graphic_info[graphic]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; int gd_x1a = gd->src_x + gd->active_xoffset; int gd_y1a = gd->src_y + gd->active_yoffset; int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset; int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset; int x = SX + ED_SETTINGS_X(checkbutton_info[i].x); int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y); /* determine horizontal position to the right of specified gadget */ if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[checkbutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (checkbutton_info[i].text_left != NULL) x += getTextWidthForGadget(checkbutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, checkbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, gd->width, GDI_HEIGHT, gd->height, GDI_TYPE, GD_TYPE_CHECK_BUTTON, GDI_CHECKED, *checkbutton_info[i].value, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a, GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleCheckbuttons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, checkbutton_info[i].text_right); } } static void CreateRadiobuttonGadgets() { struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_RADIOBUTTON]; int gd_x1 = gd->src_x; int gd_y1 = gd->src_y; int gd_x2 = gd->src_x + gd->pressed_xoffset; int gd_y2 = gd->src_y + gd->pressed_yoffset; int gd_x1a = gd->src_x + gd->active_xoffset; int gd_y1a = gd->src_y + gd->active_yoffset; int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset; int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset; struct GadgetInfo *gi; unsigned int event_mask; int i; event_mask = GD_EVENT_PRESSED; for (i = 0; i < ED_NUM_RADIOBUTTONS; i++) { int id = radiobutton_info[i].gadget_id; int x = SX + ED_SETTINGS_X(radiobutton_info[i].x); int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y); int checked = (*radiobutton_info[i].value == radiobutton_info[i].checked_value); /* determine horizontal position to the right of specified gadget */ if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE) x = (right_gadget_border[radiobutton_info[i].gadget_id_align] + ED_GADGET_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (radiobutton_info[i].text_left != NULL) x += getTextWidthForGadget(radiobutton_info[i].text_left); gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, radiobutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, gd->width, GDI_HEIGHT, gd->height, GDI_TYPE, GD_TYPE_RADIO_BUTTON, GDI_RADIO_NR, radiobutton_info[i].radio_button_nr, GDI_CHECKED, checked, GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2, GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a, GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_INFO, HandleEditorGadgetInfoText, GDI_CALLBACK_ACTION, HandleRadiobuttons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); level_editor_gadget[id] = gi; right_gadget_border[id] = getRightGadgetBorder(gi, radiobutton_info[i].text_right); } } void CreateLevelEditorGadgets() { /* force EDITOR font inside level editor */ SetFontStatus(GAME_MODE_EDITOR); /* these values are not constant, but can change at runtime */ ed_fieldx = MAX_ED_FIELDX - 1; ed_fieldy = MAX_ED_FIELDY - 1; num_editor_gadgets = NUM_EDITOR_GADGETS; // printf("::: allocating %d gadgets ...\n", num_editor_gadgets); level_editor_gadget = checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *)); right_gadget_border = checked_calloc(num_editor_gadgets * sizeof(int)); editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int)); editor_el_empty_ptr = editor_el_empty; use_permanent_palette = !editor.palette.show_as_separate_screen; ReinitializeElementList(); CreateControlButtons(); CreateScrollbarGadgets(); /* order of function calls is important because of cross-references */ CreateCheckbuttonGadgets(); CreateCounterButtons(); CreateRadiobuttonGadgets(); CreateTextInputGadgets(); CreateTextAreaGadgets(); CreateSelectboxGadgets(); CreateGraphicbuttonGadgets(); CreateTextbuttonGadgets(); CreateDrawingAreas(); ResetFontStatus(); } void FreeLevelEditorGadgets() { int i; // printf("::: freeing %d gadgets ...\n", num_editor_gadgets); for (i = 0; i < num_editor_gadgets; i++) { FreeGadget(level_editor_gadget[i]); level_editor_gadget[i] = NULL; } checked_free(level_editor_gadget); checked_free(right_gadget_border); checked_free(editor_el_empty); } static void MapCounterButtons(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); int gadget_id_down = counterbutton_info[id].gadget_id_down; int gadget_id_text = counterbutton_info[id].gadget_id_text; int gadget_id_up = counterbutton_info[id].gadget_id_up; struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down]; struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text]; struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up]; int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE; int yoffset = (gi_down->height - font_height) / 2; int x_left = gi_down->x - xoffset_left; int x_right; /* set after gadget position was modified */ int y_above = gi_down->y - yoffset_above; int x = gi_down->x; int y; /* set after gadget position was modified */ /* counter limits must be changed first to prevent value truncation */ ModifyEditorCounterLimits(id, counterbutton_info[id].min_value, counterbutton_info[id].max_value); /* right text position might have changed after setting position above */ x_right = gi_up->x + gi_up->width + xoffset_right; ModifyEditorCounterValue(id, *counterbutton_info[id].value); /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */ if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 && id <= ED_COUNTER_ID_ELEMENT_VALUE4) { ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END); ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END); ModifyGadget(gi_up, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END); } /* vertical position might have changed after setting position above */ y = gi_up->y + yoffset; if (counterbutton_info[id].text_above) DrawText(x, y_above, counterbutton_info[id].text_above, font_nr); if (counterbutton_info[id].text_left) DrawText(x_left, y, counterbutton_info[id].text_left, font_nr); if (counterbutton_info[id].text_right) DrawText(x_right, y, counterbutton_info[id].text_right, font_nr); MapGadget(gi_down); MapGadget(gi_text); MapGadget(gi_up); } static void MapControlButtons() { int counter_id; int i; /* map toolbox buttons (excluding special CE toolbox buttons) */ for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++) MapGadget(level_editor_gadget[i]); /* map toolbox buttons (element properties buttons) */ for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++) MapGadget(level_editor_gadget[i]); if (use_permanent_palette) { /* map buttons to select elements */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]); } /* map buttons to select level */ counter_id = ED_COUNTER_ID_SELECT_LEVEL; counterbutton_info[counter_id].min_value = leveldir_current->first_level; counterbutton_info[counter_id].max_value = leveldir_current->last_level; MapCounterButtons(counter_id); } static void MapDrawingArea(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int area_xsize = gi->drawing.area_xsize; int area_ysize = gi->drawing.area_ysize; int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left); int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr); int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE; int x_below = gi->x + (gi->width - xoffset_below) / 2; int y_side = gi->y + (gi->height - font_height) / 2; int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE; if (drawingarea_info[id].text_left) DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr); if (drawingarea_info[id].text_right) DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr); if (drawingarea_info[id].text_below) DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr); if (id != ED_DRAWING_ID_DRAWING_LEVEL) { DrawElementBorder(gi->x, gi->y, area_xsize * ED_DRAWINGAREA_TILE_SIZE, area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE); DrawDrawingArea(id); } MapGadget(gi); } static void MapTextInputGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id]; int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE; int x_above = ED_SETTINGS_X(textinput_info[id].x); int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above; if (textinput_info[id].text_above) DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above); ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END); MapGadget(gi); } static void MapTextAreaGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id]; int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE; int x_above = ED_SETTINGS_X(textarea_info[id].x); int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above; if (textarea_info[id].text_above) DrawTextS(x_above, y_above, font_nr, textarea_info[id].text_above); ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END); MapGadget(gi); } static void MapSelectboxGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE; int yoffset = (gi->height - font_height) / 2; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y_above = gi->y - yoffset_above; int x = gi->x; int y = gi->y + yoffset; if (selectbox_info[id].text_above) DrawText(x, y_above, selectbox_info[id].text_above, font_nr); if (selectbox_info[id].text_left) DrawText(x_left, y, selectbox_info[id].text_left, font_nr); if (selectbox_info[id].text_right) DrawText(x_right, y, selectbox_info[id].text_right, font_nr); ModifyEditorSelectboxValue(id, *selectbox_info[id].value); MapGadget(gi); } static void MapTextbuttonGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE; int yoffset = (gi->height - font_height) / 2; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y_above = gi->y - yoffset_above; int x = gi->x; int y = gi->y + yoffset; /* only show button to delete change pages when more than minimum pages */ if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE && custom_element.num_change_pages == MIN_CHANGE_PAGES) return; if (textbutton_info[id].text_above) DrawText(x, y_above, textbutton_info[id].text_above, font_nr); if (textbutton_info[id].text_left) DrawText(x_left, y, textbutton_info[id].text_left, font_nr); if (textbutton_info[id].text_right) DrawText(x_right, y, textbutton_info[id].text_right, font_nr); MapGadget(gi); } static void MapGraphicbuttonGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = (gi->height - font_height) / 2; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; if (graphicbutton_info[id].text_left) DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr); if (graphicbutton_info[id].text_right) DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr); MapGadget(gi); } static void MapRadiobuttonGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = (gi->height - font_height) / 2; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; boolean checked = (*radiobutton_info[id].value == radiobutton_info[id].checked_value); if (radiobutton_info[id].text_left) DrawText(x_left, y, radiobutton_info[id].text_left, font_nr); if (radiobutton_info[id].text_right) DrawText(x_right, y, radiobutton_info[id].text_right, font_nr); ModifyGadget(gi, GDI_CHECKED, checked, GDI_END); MapGadget(gi); } static void MapCheckbuttonGadget(int id) { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id]; int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE; int yoffset = (gi->height - font_height) / 2; int y_above = gi->y - yoffset_above; int x = gi->x; int x_left, x_right, y; /* set after gadget position was modified */ /* set position for gadgets with dynamically determined position */ if (checkbutton_info[id].x != -1) /* do not change dynamic positions */ ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x),GDI_END); ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END); x_left = gi->x - xoffset_left; x_right = gi->x + gi->width + xoffset_right; y = gi->y + yoffset; if (checkbutton_info[id].text_above) DrawText(x, y_above, checkbutton_info[id].text_above, font_nr); if (checkbutton_info[id].text_left) DrawText(x_left, y, checkbutton_info[id].text_left, font_nr); if (checkbutton_info[id].text_right) DrawText(x_right, y, checkbutton_info[id].text_right, font_nr); ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END); MapGadget(gi); } static void MapMainDrawingArea() { boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx); boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy); int i; if (suppressBorderElement()) { no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx); no_vertical_scrollbar = (lev_fieldy <= ed_fieldy); } for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++) { if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT || i == ED_SCROLLBUTTON_ID_AREA_RIGHT) && no_horizontal_scrollbar) || ((i == ED_SCROLLBUTTON_ID_AREA_UP || i == ED_SCROLLBUTTON_ID_AREA_DOWN) && no_vertical_scrollbar)) continue; MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]); } for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++) { if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) || (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar)) continue; MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]); } MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL); } static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map) { int i; for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++) { if (i == GADGET_ID_CUSTOM_COPY_FROM || i == GADGET_ID_CUSTOM_COPY_TO || i == GADGET_ID_CUSTOM_EXCHANGE || i == GADGET_ID_CUSTOM_COPY || i == GADGET_ID_CUSTOM_PASTE) { if (map) MapGadget(level_editor_gadget[i]); else UnmapGadget(level_editor_gadget[i]); } } } static void MapLevelEditorToolboxCustomGadgets() { MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE); } static void UnmapLevelEditorToolboxCustomGadgets() { MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE); } static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map) { int i; for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++) { if (i != GADGET_ID_SINGLE_ITEMS && i != GADGET_ID_PICK_ELEMENT) { struct GadgetInfo *gi = level_editor_gadget[i]; if (map) { MapGadget(gi); } else { int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON; struct GraphicInfo *gd = &graphic_info[graphic]; UnmapGadget(gi); BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y, gi->width, gi->height, gi->x, gi->y); redraw_mask |= REDRAW_DOOR_3; } } } } static void MapLevelEditorToolboxDrawingGadgets() { MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE); } static void UnmapLevelEditorToolboxDrawingGadgets() { MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE); } static void UnmapDrawingArea(int id) { UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]); } static void UnmapLevelEditorFieldGadgets() { int i; for (i = 0; i < num_editor_gadgets; i++) if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x, level_editor_gadget[i]->y)) UnmapGadget(level_editor_gadget[i]); } void UnmapLevelEditorGadgets() { int i; for (i = 0; i < num_editor_gadgets; i++) UnmapGadget(level_editor_gadget[i]); } static void ResetUndoBuffer() { undo_buffer_position = -1; undo_buffer_steps = -1; redo_buffer_steps = 0; CopyLevelToUndoBuffer(UNDO_IMMEDIATE); level.changed = FALSE; } static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets) { if (remap_toolbox_gadgets) { ModifyEditorElementList(); RedrawDrawingElements(); } if (edit_mode == ED_MODE_INFO) DrawLevelInfoWindow(); else if (edit_mode == ED_MODE_PROPERTIES) DrawPropertiesWindow(); else if (edit_mode == ED_MODE_PALETTE) DrawPaletteWindow(); else /* edit_mode == ED_MODE_DRAWING */ DrawDrawingWindowExt(remap_toolbox_gadgets); } static void DrawEditModeWindow() { DrawEditModeWindowExt(TRUE); } static void DrawEditModeWindow_PlayfieldOnly() { DrawEditModeWindowExt(FALSE); } static void ChangeEditModeWindow(int new_edit_mode) { edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING); DrawEditModeWindow(); } static boolean LevelChanged() { boolean field_changed = FALSE; int x, y; for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] != level.field[x][y]) field_changed = TRUE; return (level.changed || field_changed); } static boolean PrepareSavingIntoPersonalLevelSet() { static LevelDirTree *last_copied_leveldir = NULL; static LevelDirTree *last_written_leveldir = NULL; static int last_copied_level_nr = -1; static int last_written_level_nr = -1; LevelDirTree *leveldir_former = leveldir_current; int level_nr_former = level_nr; int new_level_nr; // remember last mod/save so that for current session, we write // back to the same personal copy, asking only about overwrite. if (leveldir_current == last_copied_leveldir && level_nr == last_copied_level_nr) { // "cd" to personal level set dir (as used when writing last copy) leveldir_current = last_written_leveldir; level_nr = last_written_level_nr; return TRUE; } if (!Request("This level is read only! " "Save into personal level set?", REQ_ASK)) return FALSE; // "cd" to personal level set dir (for writing copy the first time) leveldir_current = getTreeInfoFromIdentifier(leveldir_first, getLoginName()); // find unused level number for (new_level_nr = leveldir_current->first_level; ; new_level_nr++) { static char *level_filename = NULL; setString(&level_filename, getDefaultLevelFilename(new_level_nr)); if (!fileExists(level_filename)) break; } last_copied_leveldir = leveldir_former; last_copied_level_nr = level_nr_former; last_written_leveldir = leveldir_current; last_written_level_nr = level_nr = new_level_nr; return TRUE; } static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name) { static char *filename_levelinfo = NULL, *mod_name = NULL; FILE *file; // annotate this copy-and-mod in personal levelinfo.conf setString(&filename_levelinfo, getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME)); if ((file = fopen(filename_levelinfo, MODE_APPEND))) { fprintf(file, "\n"); fprintf(file, "# level %d was modified from:\n", level_nr); fprintf(file, "# - previous level set name: %s\n", former_name); fprintf(file, "# - level within previous set: %d \"%s\"\n", level.file_info.nr, level.name); fprintf(file, "# - previous author: %s\n", level.author); fprintf(file, "# - previous save date: "); if (level.creation_date.src == DATE_SRC_LEVELFILE) { fprintf(file, "%04d-%02d-%02d\n", level.creation_date.year, level.creation_date.month, level.creation_date.day); } else { fprintf(file, "not recorded\n"); } fclose(file); } if (level_nr > leveldir_current->last_level) UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9); // else: allow the save even if annotation failed // now... spray graffiti on the old level vital statistics // user can change these; just trying to set a good baseline // don't truncate names for fear of making offensive or silly: // long-named original author only recorded in levelinfo.conf. // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe" if (!strEqual(level.author, leveldir_current->author)) { setString(&mod_name, getStringCat3(leveldir_current->author, " after ", level.author)); if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN) setString(&mod_name, getStringCat2(leveldir_current->author, " (ed.)")); if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN) setString(&mod_name, leveldir_current->author); strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN); // less worried about truncation here setString(&mod_name, getStringCat2("Mod: ", level.name)); strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN); } } static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY], short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY]) { int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) dst[x][y] = src[x][y]; } static int setSelectboxValue(int selectbox_id, int new_value) { int new_index_value = 0; int i; for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++) if (selectbox_info[selectbox_id].options[i].value == new_value) new_index_value = i; *selectbox_info[selectbox_id].value = selectbox_info[selectbox_id].options[new_index_value].value; return new_index_value; } static void setSelectboxSpecialActionVariablesIfNeeded() { int i; /* change action mode and arg variables according to action type variable */ for (i = 0; action_arg_options[i].value != -1; i++) { if (action_arg_options[i].value == custom_element_change.action_type) { int mode = action_arg_options[i].mode; /* only change if corresponding selectbox has changed */ if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options != action_arg_modes[mode]) custom_element_change.action_mode = -1; /* only change if corresponding selectbox has changed */ if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options != action_arg_options[i].options) custom_element_change.action_arg = -1; break; } } } static void setSelectboxSpecialActionOptions() { int i; /* change action mode and arg selectbox according to action type selectbox */ for (i = 0; action_arg_options[i].value != -1; i++) { if (action_arg_options[i].value == custom_element_change.action_type) { int mode = action_arg_options[i].mode; ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE, action_arg_modes[mode]); ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE, custom_element_change.action_mode); ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG, action_arg_options[i].options); ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG, custom_element_change.action_arg); break; } } } static void copy_custom_element_settings(int element_from, int element_to) { struct ElementInfo *ei_from = &element_info[element_from]; struct ElementInfo *ei_to = &element_info[element_to]; copyElementInfo(ei_from, ei_to); } static void replace_custom_element_in_settings(int element_from, int element_to) { int i, j, x, y; for (i = 0; i < NUM_FILE_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (ei->content.e[x][y] == element_from) ei->content.e[x][y] = element_to; for (j = 0; j < ei->num_change_pages; j++) { struct ElementChangeInfo *change = &ei->change_page[j]; if (change->target_element == element_from) change->target_element = element_to; if (change->initial_trigger_element == element_from) change->initial_trigger_element = element_to; if (change->action_element == element_from) change->action_element = element_to; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) if (change->target_content.e[x][y] == element_from) change->target_content.e[x][y] = element_to; } if (ei->group != NULL) /* group or internal */ for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++) if (ei->group->element[j] == element_from) ei->group->element[j] = element_to; } } static void replace_custom_element_in_playfield(int element_from, int element_to) { int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) if (Feld[x][y] == element_from) Feld[x][y] = element_to; } static boolean CopyCustomElement(int element_old, int element_new, int copy_mode) { int copy_mode_orig = copy_mode; if (copy_mode == GADGET_ID_CUSTOM_COPY) { element_new = (IS_CUSTOM_ELEMENT(element_old) ? EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP); copy_mode = GADGET_ID_CUSTOM_COPY_TO; } else if (copy_mode == GADGET_ID_CUSTOM_PASTE) { element_old = (IS_CUSTOM_ELEMENT(element_new) ? EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP); copy_mode = GADGET_ID_CUSTOM_COPY_TO; level.changed = TRUE; } else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new)) { Request("Please choose custom element!", REQ_CONFIRM); return FALSE; } else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new)) { Request("Please choose group element!", REQ_CONFIRM); return FALSE; } else { level.changed = TRUE; } /* when modifying custom/group element, ask for copying level template */ if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template) { if (!AskToCopyAndModifyLevelTemplate()) return FALSE; } if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM) { copy_custom_element_settings(element_new, element_old); } else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO) { copy_custom_element_settings(element_old, element_new); } else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE) { copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY); copy_custom_element_settings(element_new, element_old); copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new); replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY); replace_custom_element_in_settings(element_new, element_old); replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new); replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY); replace_custom_element_in_playfield(element_new, element_old); replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new); } UpdateCustomElementGraphicGadgets(); DrawPropertiesWindow(); return TRUE; } static void CopyCustomElementPropertiesToEditor(int element) { int i; int current_change_page = element_info[element].current_change_page; /* dynamically (re)build selectbox for selecting change page */ for (i = 0; i < element_info[element].num_change_pages; i++) { sprintf(options_change_page_strings[i], "%d", i + 1); options_change_page[i].value = i; options_change_page[i].text = options_change_page_strings[i]; } options_change_page[i].value = -1; options_change_page[i].text = NULL; /* needed here to initialize combined element properties */ InitElementPropertiesEngine(level.game_version); element_info[element].change = &element_info[element].change_page[current_change_page]; custom_element = element_info[element]; custom_element_change = *element_info[element].change; /* needed to initially set selectbox options for special action options */ setSelectboxSpecialActionOptions(); /* needed to initially set selectbox value variables to reliable defaults */ for (i = 0; i < ED_NUM_SELECTBOX; i++) setSelectboxValue(i, *selectbox_info[i].value); for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) custom_element_properties[i] = HAS_PROPERTY(element, i); for (i = 0; i < NUM_CHANGE_EVENTS; i++) custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i); /* ---------- element settings: configure (custom elements) ------------- */ /* set accessible layer selectbox help value */ custom_element.access_type = (IS_WALKABLE(element) ? EP_WALKABLE : IS_PASSABLE(element) ? EP_PASSABLE : custom_element.access_type); custom_element.access_layer = (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER : IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE : IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER : custom_element.access_layer); custom_element.access_protected = (IS_PROTECTED(element) ? 1 : 0); custom_element_properties[EP_ACCESSIBLE] = (IS_ACCESSIBLE_OVER(element) || IS_ACCESSIBLE_INSIDE(element) || IS_ACCESSIBLE_UNDER(element)); /* set walk-to-object action selectbox help value */ custom_element.walk_to_action = (IS_DIGGABLE(element) ? EP_DIGGABLE : IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY : IS_DROPPABLE(element) ? EP_DROPPABLE : IS_THROWABLE(element) ? EP_THROWABLE : IS_PUSHABLE(element) ? EP_PUSHABLE : custom_element.walk_to_action); custom_element_properties[EP_WALK_TO_OBJECT] = (IS_DIGGABLE(element) || IS_COLLECTIBLE_ONLY(element) || IS_DROPPABLE(element) || IS_THROWABLE(element) || IS_PUSHABLE(element)); /* set smash targets selectbox help value */ custom_element.smash_targets = (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING : CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES : CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER : custom_element.smash_targets); custom_element_properties[EP_CAN_SMASH] = (CAN_SMASH_EVERYTHING(element) || CAN_SMASH_ENEMIES(element) || CAN_SMASH_PLAYER(element)); /* set deadliness selectbox help value */ custom_element.deadliness = (DONT_TOUCH(element) ? EP_DONT_TOUCH : DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY : DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH : DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO : custom_element.deadliness); custom_element_properties[EP_DEADLY] = (DONT_TOUCH(element) || DONT_GET_HIT_BY(element) || DONT_COLLIDE_WITH(element) || DONT_RUN_INTO(element)); /* ---------- element settings: advanced (custom elements) --------------- */ /* set "change by direct action" selectbox help value */ custom_element_change.direct_action = (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED : HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING : HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING : HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED : HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT : HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED : HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES : HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES : HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO : HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO : custom_element_change.direct_action); /* set "change by other element action" selectbox help value */ custom_element_change.other_action = (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X : HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X : HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X : HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X : HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X : HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X : HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X : HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X : HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X : HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X : HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X : HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X : HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X : HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X : HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X : HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X : custom_element_change.other_action); } static void CopyGroupElementPropertiesToEditor(int element) { group_element_info = *element_info[element].group; custom_element = element_info[element]; /* needed for description */ } static void CopyClassicElementPropertiesToEditor(int element) { if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element)) custom_element_properties[EP_CAN_MOVE_INTO_ACID] = getMoveIntoAcidProperty(&level, element); if (MAYBE_DONT_COLLIDE_WITH(element)) custom_element_properties[EP_DONT_COLLIDE_WITH] = getDontCollideWithProperty(&level, element); } static void CopyElementPropertiesToEditor(int element) { if (IS_CUSTOM_ELEMENT(element)) CopyCustomElementPropertiesToEditor(element); else if (IS_GROUP_ELEMENT(element)) CopyGroupElementPropertiesToEditor(element); else CopyClassicElementPropertiesToEditor(element); } static boolean AskToCopyAndModifyLevelTemplate() { if (Request("Copy and modify settings from level template?", REQ_ASK)) { level.use_custom_template = FALSE; ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1], GDI_CHECKED, FALSE, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2], GDI_CHECKED, FALSE, GDI_END); return TRUE; } else { LoadLevelTemplate(-1); /* this resets all element modifications ... */ DrawEditModeWindow(); /* ... and copies them to 'custom_element' */ return FALSE; } } static void CopyCustomElementPropertiesToGame(int element) { int i; int access_type_and_layer; /* mark that this custom element has been modified */ custom_element.modified_settings = TRUE; level.changed = TRUE; if (level.use_custom_template) AskToCopyAndModifyLevelTemplate(); element_info[element] = custom_element; *element_info[element].change = custom_element_change; /* ---------- element settings: configure (custom elements) ------------- */ /* set accessible property from checkbox and selectbox */ custom_element_properties[EP_WALKABLE_OVER] = FALSE; custom_element_properties[EP_WALKABLE_INSIDE] = FALSE; custom_element_properties[EP_WALKABLE_UNDER] = FALSE; custom_element_properties[EP_PASSABLE_OVER] = FALSE; custom_element_properties[EP_PASSABLE_INSIDE] = FALSE; custom_element_properties[EP_PASSABLE_UNDER] = FALSE; access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ? EP_WALKABLE_OVER : EP_PASSABLE_OVER) + (custom_element.access_layer - EP_ACCESSIBLE_OVER)); custom_element_properties[access_type_and_layer] = custom_element_properties[EP_ACCESSIBLE]; custom_element_properties[EP_PROTECTED] = (custom_element.access_protected != 0 && custom_element_properties[EP_ACCESSIBLE]); /* set walk-to-object property from checkbox and selectbox */ custom_element_properties[EP_DIGGABLE] = FALSE; custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE; custom_element_properties[EP_DROPPABLE] = FALSE; custom_element_properties[EP_THROWABLE] = FALSE; custom_element_properties[EP_PUSHABLE] = FALSE; custom_element_properties[custom_element.walk_to_action] = custom_element_properties[EP_WALK_TO_OBJECT]; /* set smash property from checkbox and selectbox */ custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE; custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE; custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE; custom_element_properties[custom_element.smash_targets] = custom_element_properties[EP_CAN_SMASH]; /* set deadliness property from checkbox and selectbox */ custom_element_properties[EP_DONT_RUN_INTO] = FALSE; custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE; custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE; custom_element_properties[EP_DONT_TOUCH] = FALSE; custom_element_properties[custom_element.deadliness] = custom_element_properties[EP_DEADLY]; /* ---------- element settings: advanced (custom elements) --------------- */ /* set player change event from checkbox and selectbox */ custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE; custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE; custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE; custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SWITCHED] = FALSE; custom_element_change_events[CE_HITTING_SOMETHING] = FALSE; custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE; custom_element_change_events[CE_BLOCKED] = FALSE; custom_element_change_events[CE_IMPACT] = FALSE; custom_element_change_events[CE_SMASHED] = FALSE; custom_element_change_events[CE_VALUE_CHANGES] = FALSE; custom_element_change_events[CE_SCORE_CHANGES] = FALSE; custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE; custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE; custom_element_change_events[custom_element_change.direct_action] = custom_element_change_events[CE_BY_DIRECT_ACTION]; /* set other element action change event from checkbox and selectbox */ custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE; custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE; custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE; custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE; custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE; custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE; custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE; custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE; custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE; custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE; custom_element_change_events[CE_TOUCHING_X] = FALSE; custom_element_change_events[CE_HITTING_X] = FALSE; custom_element_change_events[CE_DIGGING_X] = FALSE; custom_element_change_events[CE_HIT_BY_X] = FALSE; custom_element_change_events[CE_SWITCH_OF_X] = FALSE; custom_element_change_events[CE_CHANGE_OF_X] = FALSE; custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE; custom_element_change_events[CE_MOVE_OF_X] = FALSE; custom_element_change_events[CE_CREATION_OF_X] = FALSE; custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE; custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE; custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE; custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE; custom_element_change_events[custom_element_change.other_action] = custom_element_change_events[CE_BY_OTHER_ACTION]; for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) SET_PROPERTY(element, i, custom_element_properties[i]); for (i = 0; i < NUM_CHANGE_EVENTS; i++) SET_CHANGE_EVENT(element, i, custom_element_change_events[i]); /* copy change events also to special level editor variable */ custom_element = element_info[element]; custom_element_change = *element_info[element].change; } static void CopyGroupElementPropertiesToGame(int element) { /* mark that this group element has been modified */ custom_element.modified_settings = TRUE; level.changed = TRUE; if (level.use_custom_template) AskToCopyAndModifyLevelTemplate(); element_info[element] = custom_element; *element_info[element].group = group_element_info; } static void CopyClassicElementPropertiesToGame(int element) { if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element)) setMoveIntoAcidProperty(&level, element, custom_element_properties[EP_CAN_MOVE_INTO_ACID]); if (MAYBE_DONT_COLLIDE_WITH(element)) setDontCollideWithProperty(&level, element, custom_element_properties[EP_DONT_COLLIDE_WITH]); } static void CopyElementPropertiesToGame(int element) { if (IS_CUSTOM_ELEMENT(element)) CopyCustomElementPropertiesToGame(element); else if (IS_GROUP_ELEMENT(element)) CopyGroupElementPropertiesToGame(element); else CopyClassicElementPropertiesToGame(element); } void CheckElementDescriptions() { int i; for (i = 0; i < NUM_FILE_ELEMENTS; i++) if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i)) Error(ERR_WARN, "no element description file for element '%s'", EL_NAME(i)); } static int getMaxEdFieldX(boolean has_scrollbar) { int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0); int sxsize = SXSIZE - scrollbar_width; int max_ed_fieldx = sxsize / ed_tilesize; return max_ed_fieldx; } static int getMaxEdFieldY(boolean has_scrollbar) { int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ? INFOTEXT_YSIZE_FULL : 0); int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0); int sysize = SYSIZE - scrollbar_height - infotext_height; int max_ed_fieldy = sysize / ed_tilesize; return max_ed_fieldy; } void InitZoomLevelSettings(int zoom_tilesize) { static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN; if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type) { ed_tilesize = setup.auto_setup.editor_zoom_tilesize; ed_tilesize_default = DEFAULT_EDITOR_TILESIZE; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM; ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM; } } last_game_engine_type = level.game_engine_type; // limit zoom tilesize by upper and lower bound ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE); // store zoom tilesize in auto setup file only if it was manually changed if (zoom_tilesize != -1) setup.auto_setup.editor_zoom_tilesize = ed_tilesize; MAX_ED_FIELDX = getMaxEdFieldX(FALSE); MAX_ED_FIELDY = getMaxEdFieldY(FALSE); } static void InitDrawingElements() { static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN; if (level.game_engine_type == game_engine_type_last) return; if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { new_element1 = EL_SP_CHIP_SINGLE; new_element2 = EL_EMPTY; new_element3 = EL_SP_BASE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { new_element1 = EL_MM_MIRROR_START; new_element2 = EL_EMPTY; new_element3 = EL_MM_WOODEN_WALL; } else { new_element1 = EL_WALL; new_element2 = EL_EMPTY; new_element3 = EL_SAND; } game_engine_type_last = level.game_engine_type; } static void InitLevelSetInfo() { snprintf(levelset_name, MAX_LEVEL_NAME_LEN + 1, "%s", leveldir_current->name); snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1, "%s", leveldir_current->author); levelset_num_levels = leveldir_current->levels; levelset_use_levelset_artwork = FALSE; levelset_copy_level_template = FALSE; levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE; } static void ChangeEditorToLevelSet(char *levelset_subdir) { leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir); // the previous level set might have used custom artwork ReloadCustomArtwork(0); LoadLevelSetup_SeriesInfo(); SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); TapeErase(); LoadLevel(level_nr); LoadScore(level_nr); DrawLevelEd(); } static boolean useEditorDoorAnimation() { struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN]; boolean door_1_viewport_unchanged = (vp_door_1->x == DX && vp_door_1->y == DY && vp_door_1->width == DXSIZE && vp_door_1->height == DYSIZE); boolean door_1_contains_toolbox = (EX >= DX && EY >= DY && EX + EXSIZE <= DX + DXSIZE && EY + EYSIZE <= DY + DYSIZE); return (door_1_viewport_unchanged && door_1_contains_toolbox); } void DrawEditorDoorContent() { /* needed for gadgets drawn on background (like palette scrollbar) */ SetDoorBackgroundImage(IMG_UNDEFINED); /* copy default editor door content to main double buffer */ BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto, graphic_info[IMG_BACKGROUND_PALETTE].src_x, graphic_info[IMG_BACKGROUND_PALETTE].src_y, MIN(DXSIZE, graphic_info[IMG_BACKGROUND_PALETTE].width), MIN(DYSIZE, graphic_info[IMG_BACKGROUND_PALETTE].height), DX, DY); /* draw bigger door */ DrawSpecialEditorDoor(); /* draw new control window */ BlitBitmap(graphic_info[IMG_BACKGROUND_TOOLBOX].bitmap, drawto, graphic_info[IMG_BACKGROUND_TOOLBOX].src_x, graphic_info[IMG_BACKGROUND_TOOLBOX].src_y, MIN(EXSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].width), MIN(EYSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].height), EX, EY); /* draw all toolbox gadgets to editor doors */ MapControlButtons(); /* draw all palette gadgets to editor doors */ ModifyEditorElementList(); RedrawDrawingElements(); /* copy actual editor door content to door double buffer for OpenDoor() */ BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); } void DrawLevelEd() { int fade_mask = REDRAW_FIELD; FadeSoundsAndMusic(); if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; FadeOut(fade_mask); /* needed if different viewport properties defined for editor */ ChangeViewportPropertiesIfNeeded(); ClearField(); InitZoomLevelSettings(-1); InitDrawingElements(); InitLevelSetInfo(); #if DEBUG CheckElementDescriptions(); #endif if (level_editor_test_game) { CopyPlayfield(level.field, Feld); CopyPlayfield(FieldBackup, level.field); level_editor_test_game = FALSE; } else { edit_mode = ED_MODE_DRAWING; edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL; edit_mode_properties = ED_MODE_PROPERTIES_INFO; ResetUndoBuffer(); level_xpos = -1; level_ypos = -1; } // redraw_mask |= REDRAW_ALL; FreeLevelEditorGadgets(); CreateLevelEditorGadgets(); ReinitializeElementList(); /* update dynamic level element list */ ReinitializeElementListButtons(); /* custom element may look different */ InitElementPropertiesGfxElement(); UnmapAllGadgets(); DrawEditModeWindow_PlayfieldOnly(); DrawMaskedBorder(fade_mask); // use door animation if door 1 viewport is unchanged and contains toolbox if (useEditorDoorAnimation()) { FadeIn(fade_mask); DrawEditorDoorContent(); OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM); } else { DrawEditorDoorContent(); FadeIn(fade_mask); } SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2); } static void AdjustDrawingAreaGadgets() { int ed_xsize = lev_fieldx + 2; int ed_ysize = lev_fieldy + 2; int max_ed_fieldx = MAX_ED_FIELDX; int max_ed_fieldy = MAX_ED_FIELDY; boolean horizontal_scrollbar_needed; boolean vertical_scrollbar_needed; int x, y, width, height; if (suppressBorderElement()) { ed_xsize = max_ed_fieldx; ed_ysize = max_ed_fieldy; } /* check if we need any scrollbars */ horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx); vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy); /* check if we have a smaller editor field because of scrollbars */ max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed); max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed); /* check again if we now need more scrollbars because of less space */ horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx); vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy); /* check if editor field gets even smaller after adding new scrollbars */ max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed); max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed); ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize); ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize); x = SX + ed_fieldx * ed_tilesize; y = SY + ed_fieldy * ed_tilesize; width = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE; height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE; /* adjust drawing area gadget */ ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL], GDI_AREA_SIZE, ed_fieldx, ed_fieldy, GDI_ITEM_SIZE, ed_tilesize, ed_tilesize, GDI_END); /* adjust horizontal scrollbar gadgets */ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT], GDI_Y, y, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x - ED_SCROLLBUTTON_XSIZE, GDI_Y, y, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL], GDI_Y, y, GDI_WIDTH, width, GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx, GDI_END); /* adjust vertical scrollbar gadgets */ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP], GDI_X, x, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_X, x, GDI_Y, y - ED_SCROLLBUTTON_YSIZE, GDI_END); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL], GDI_X, x, GDI_HEIGHT, height, GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy, GDI_END); } static void AdjustLevelScrollPosition() { if (level_xpos < -1) level_xpos = -1; if (level_xpos > lev_fieldx - ed_fieldx + 1) level_xpos = lev_fieldx - ed_fieldx + 1; if (lev_fieldx < ed_fieldx - 2) level_xpos = -1; if (level_ypos < -1) level_ypos = -1; if (level_ypos > lev_fieldy - ed_fieldy + 1) level_ypos = lev_fieldy - ed_fieldy + 1; if (lev_fieldy < ed_fieldy - 2) level_ypos = -1; if (suppressBorderElement()) { level_xpos = 0; level_ypos = 0; } } static void AdjustEditorScrollbar(int id) { struct GadgetInfo *gi = level_editor_gadget[id]; int items_max, items_visible, item_position; if (id == GADGET_ID_SCROLL_HORIZONTAL) { items_max = MAX(lev_fieldx + 2, ed_fieldx); items_visible = ed_fieldx; item_position = level_xpos + 1; } else { items_max = MAX(lev_fieldy + 2, ed_fieldy); items_visible = ed_fieldy; item_position = level_ypos + 1; } if (item_position > items_max - items_visible) item_position = items_max - items_visible; ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); } static void AdjustElementListScrollbar() { struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]; int items_max, items_visible, item_position; /* correct position of element list scrollbar */ if (element_shift < 0) element_shift = 0; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ; items_visible = ED_ELEMENTLIST_BUTTONS_VERT; item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ; ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); } static void ModifyEditorCounterValue(int counter_id, int new_value) { int *counter_value = counterbutton_info[counter_id].value; int gadget_id = counterbutton_info[counter_id].gadget_id_text; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END); if (counter_value != NULL) *counter_value = gi->textinput.number_value; } static void ModifyEditorCounterLimits(int counter_id, int min, int max) { int gadget_id = counterbutton_info[counter_id].gadget_id_text; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END); if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 && counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4) { int gadget_id_up = counterbutton_info[counter_id].gadget_id_up; struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up]; ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END); ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE, GDI_END); } } static void ModifyEditorSelectboxValue(int selectbox_id, int new_value) { int gadget_id = selectbox_info[selectbox_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; int new_index_value = setSelectboxValue(selectbox_id, new_value); ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END); } static void ModifyEditorSelectboxOptions(int selectbox_id, struct ValueTextInfo *options) { int gadget_id = selectbox_info[selectbox_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; selectbox_info[selectbox_id].options = options; /* set index to zero -- list may be shorter now (correct later, if needed) */ ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0, GDI_SELECTBOX_OPTIONS, options, GDI_END); } static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize) { int gadget_id = drawingarea_info[drawingarea_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; drawingarea_info[drawingarea_id].area_xsize = xsize; drawingarea_info[drawingarea_id].area_ysize = ysize; ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END); } static void ModifyEditorElementList() { int i; if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE) return; for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) { int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; struct GadgetDesign *gd = &gi->deco.design; int element = editor_elements[element_shift + i]; int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size); UnmapGadget(gi); getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y); ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END); MapGadget(gi); } } static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos) { int graphic = el2edimg(element); int tile_size = BUTTON_TILE_SIZE(pos->tile_size); if (pos->x == -1 && pos->y == -1) return; DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size); } static void ModifyDrawingElementButton(int element, int id) { struct GadgetInfo *gi = level_editor_gadget[id]; Bitmap *deco_bitmap; int deco_x, deco_y; int tile_size = gi->deco.width; getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y); ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END); } static void PickDrawingElement(int button, int element) { struct { int *new_element; struct XYTileSize *pos; int id; } de, drawing_elements[] = { { &new_element1, &editor.palette.element_left, GADGET_ID_ELEMENT_LEFT }, { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE }, { &new_element3, &editor.palette.element_right, GADGET_ID_ELEMENT_RIGHT }, }; if (button < 1 || button > 3) return; if (IS_MM_WALL(element)) element = map_mm_wall_element(element); de = drawing_elements[button - 1]; *de.new_element = element; // update global drawing element variable DrawDrawingElementGraphic(element, de.pos); ModifyDrawingElementButton(element, de.id); redraw_mask |= REDRAW_DOOR_1; } static void RedrawDrawingElements() { PickDrawingElement(1, new_element1); PickDrawingElement(2, new_element2); PickDrawingElement(3, new_element3); } static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets) { stick_element_properties_window = FALSE; SetMainBackgroundImage(IMG_UNDEFINED); ClearField(); UnmapLevelEditorFieldGadgets(); AdjustDrawingAreaGadgets(); AdjustLevelScrollPosition(); AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL); AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL); DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); MapMainDrawingArea(); if (remap_toolbox_gadgets) { UnmapLevelEditorToolboxCustomGadgets(); MapLevelEditorToolboxDrawingGadgets(); } } static void DrawDrawingWindow() { DrawDrawingWindowExt(TRUE); } static int getTabulatorBarWidth() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO]; struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE]; return gd_gi4->x - gd_gi1->x + gd_gi4->width; } static int getTabulatorBarHeight() { return ED_TAB_BAR_HEIGHT; } static Pixel getTabulatorBarColor() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL]; struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED]; int gd_x = gd->x + gd_gi1->border.width / 2; int gd_y = gd->y + gd_gi1->height - 1; return GetPixel(gd->bitmap, gd_x, gd_y); } static void DrawLevelInfoTabulatorGadgets() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL]; Pixel tab_color = getTabulatorBarColor(); int id_first = ED_TAB_BUTTON_ID_LEVELINFO_FIRST; int id_last = ED_TAB_BUTTON_ID_LEVELINFO_LAST; int i; for (i = id_first; i <= id_last; i++) { int gadget_id = textbutton_info[i].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; boolean active = (i != edit_mode_levelinfo); /* draw background line below tabulator button */ ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1); /* draw solid line below inactive tabulator buttons */ if (!active && tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width, ED_GADGET_TINY_DISTANCE, tab_color); ModifyGadget(gi, GDI_ACTIVE, active, GDI_END); MapTextbuttonGadget(i); } /* draw little border line below tabulator buttons */ if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + ED_GADGET_TINY_DISTANCE, getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color); } static void DrawPropertiesTabulatorGadgets() { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO]; struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED]; int gd_x = gd->x + gd_gi1->border.width / 2; int gd_y = gd->y + gd_gi1->height - 1; Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y); int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO; int id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG; int i; /* draw two config tabulators for player elements */ if (ELEM_IS_PLAYER(properties_element)) id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2; /* draw two config and one "change" tabulator for custom elements */ if (IS_CUSTOM_ELEMENT(properties_element)) id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE; for (i = id_first; i <= id_last; i++) { int gadget_id = textbutton_info[i].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; boolean active = (i != edit_mode_properties); /* use "config 1" and "config 2" instead of "config" for players and CEs */ if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG && (ELEM_IS_PLAYER(properties_element) || IS_CUSTOM_ELEMENT(properties_element))) continue; /* draw background line below tabulator button */ ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1); /* draw solid line below inactive tabulator buttons */ if (!active && tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width, ED_GADGET_TINY_DISTANCE, tab_color); ModifyGadget(gi, GDI_ACTIVE, active, GDI_END); MapTextbuttonGadget(i); } /* draw little border line below tabulator buttons */ if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + ED_GADGET_TINY_DISTANCE, getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color); } static void PrintInfoText(char *text, int font_nr, int xpos, int ypos) { DrawText(SX + xpos, SY + ypos, text, font_nr); } static int PrintElementDescriptionFromFile(char *filename, int font_nr, int xpos, int ypos) { int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width; int max_lines_drawable = (SYSIZE - ypos) / font_height - 1; return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr, max_chars_per_line, -1, max_lines_drawable, 0, -1, TRUE, FALSE, FALSE); } static void DrawLevelInfoLevel() { int i; /* draw counter gadgets */ for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++) MapCounterButtons(i); /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++) MapCheckbuttonGadget(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++) MapSelectboxGadget(i); /* draw text input gadgets */ for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++) MapTextInputGadget(i); } static char *getLevelSubdirFromSaveMode(int save_mode) { if (save_mode == LEVELSET_SAVE_MODE_CREATE) return getNewUserLevelSubdir(); return leveldir_current->subdir; } static void DrawLevelInfoLevelSet_DirectoryInfo() { char *directory_text = "Level set directory:"; char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode); int font1_nr = FONT_TEXT_1; int font2_nr = FONT_TEXT_2; int font1_height = getFontHeight(font1_nr); int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE; int x = ED_LEVEL_SETTINGS_X(0); int y = ED_LEVEL_SETTINGS_Y(6); PrintInfoText(directory_text, font1_nr, x, y - yoffset_above); PrintInfoText(directory_name, font2_nr, x, y); } static void DrawLevelInfoLevelSet() { boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet(); boolean template_exists = fileExists(getLocalLevelTemplateFilename()); int i; /* draw counter gadgets */ for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++) MapCounterButtons(i); /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++) { if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE || (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) || (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE && !template_exists)) continue; MapCheckbuttonGadget(i); } /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++) MapSelectboxGadget(i); /* draw text input gadgets */ for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++) MapTextInputGadget(i); /* draw textbutton gadgets */ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET); /* draw info text */ DrawLevelInfoLevelSet_DirectoryInfo(); } static void DrawLevelInfoEditor() { int i; /* draw counter gadgets */ for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++) MapCounterButtons(i); /* draw checkbutton gadgets */ for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++) MapCheckbuttonGadget(i); /* draw radiobutton gadgets */ for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++) MapRadiobuttonGadget(i); /* draw drawing area */ MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND); /* draw textbutton gadgets */ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2); } static void DrawLevelInfoWindow() { char *text = "Global Settings"; int font_nr = FONT_TITLE_1; struct MenuPosInfo *pos = &editor.settings.headline; int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align); int sy = SY + pos->y; stick_element_properties_window = FALSE; SetAutomaticNumberOfGemsNeeded(); UnmapLevelEditorFieldGadgets(); SetMainBackgroundImage(IMG_BACKGROUND_EDITOR); ClearField(); DrawText(sx, sy, text, font_nr); DrawLevelInfoTabulatorGadgets(); if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL) DrawLevelInfoLevel(); else if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVELSET) DrawLevelInfoLevelSet(); else if (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR) DrawLevelInfoEditor(); } static void DrawCustomContentArea() { int id = ED_DRAWING_ID_CUSTOM_CONTENT; struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS]; int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE]; int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT]; int xoffset = ED_GADGET_SPACE_DISTANCE; /* add distance for potential left text (without drawing area border) */ x2 += getTextWidthForGadget(drawingarea_info[id].text_left); ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END); MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT); } static void DrawCustomChangeContentArea() { int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT; struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id]; int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT]; int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN]; int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE]; int xoffset = ED_GADGET_SPACE_DISTANCE; ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END); MapDrawingArea(id); } static void RemoveElementContentArea(int id, int font_height) { int border_size = ED_DRAWINGAREA_BORDER_SIZE; DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size, SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size, 3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size, 3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size + ED_GADGET_TEXT_DISTANCE + font_height); } static void DrawYamYamContentAreas() { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); int tilesize = ED_DRAWINGAREA_TILE_SIZE; int yoffset = (tilesize - font_height) / 2; int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize; int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset; int i; /* display counter to choose number of element content areas */ MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) { int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i; if (i < level.num_yamyam_contents) { MapDrawingArea(id); } else { UnmapDrawingArea(id); /* delete content areas in case of reducing number of them */ RemoveElementContentArea(id, font_height); } } DrawText(x, y + 0 * tilesize, "content", font_nr); DrawText(x, y + 1 * tilesize, "when", font_nr); DrawText(x, y + 2 * tilesize, "smashed", font_nr); } static void DrawMagicBallContentAreas() { int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); int tilesize = ED_DRAWINGAREA_TILE_SIZE; int yoffset = (tilesize - font_height) / 2; int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize; int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset; int i; /* display counter to choose number of element content areas */ MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) { int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i; if (i < level.num_ball_contents) { MapDrawingArea(id); } else { UnmapDrawingArea(id); /* delete content areas in case of reducing number of them */ RemoveElementContentArea(id, font_height); } } DrawText(x, y + 0 * tilesize, "generated", font_nr); DrawText(x, y + 1 * tilesize, "when", font_nr); DrawText(x, y + 2 * tilesize, "active", font_nr); } static void DrawAndroidElementArea(int element) { int id = ED_DRAWING_ID_ANDROID_CONTENT; int num_elements = level.num_android_clone_elements; int border_size = ED_DRAWINGAREA_BORDER_SIZE; int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size; int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size; int xsize = MAX_ANDROID_ELEMENTS; int ysize = 1; /* display counter to choose number of element areas */ MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT); if (drawingarea_info[id].text_left != NULL) sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left); UnmapDrawingArea(id); ModifyEditorDrawingArea(id, num_elements, 1); /* delete content areas in case of reducing number of them */ DrawBackground(sx, sy, xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size, ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size); MapDrawingArea(id); } static void DrawGroupElementArea(int element) { int id = ED_DRAWING_ID_GROUP_CONTENT; int num_elements = group_element_info.num_elements; int border_size = ED_DRAWINGAREA_BORDER_SIZE; int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size; int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size; int xsize = MAX_ELEMENTS_IN_GROUP; int ysize = 1; if (drawingarea_info[id].text_left != NULL) sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left); UnmapDrawingArea(id); ModifyEditorDrawingArea(id, num_elements, 1); /* delete content areas in case of reducing number of them */ DrawBackground(sx, sy, xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size, ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size); MapDrawingArea(id); } static void DrawPlayerInitialInventoryArea(int element) { int id = ED_DRAWING_ID_INVENTORY_CONTENT; int player_nr = GET_PLAYER_NR(element); int num_elements = level.initial_inventory_size[player_nr]; int border_size = ED_DRAWINGAREA_BORDER_SIZE; int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size; int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size; int xsize = MAX_INITIAL_INVENTORY_SIZE; int ysize = 1; /* determine horizontal position to the right of specified gadget */ if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE) sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] + ED_DRAWINGAREA_TEXT_DISTANCE); /* determine horizontal offset for leading text */ if (drawingarea_info[id].text_left != NULL) sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left); UnmapDrawingArea(id); ModifyEditorDrawingArea(id, num_elements, 1); /* delete content areas in case of reducing number of them */ DrawBackground(sx, sy, xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size, ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size); MapDrawingArea(id); } static void DrawEnvelopeTextArea(int envelope_nr) { int id = ED_TEXTAREA_ID_ENVELOPE_INFO; struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id]; UnmapGadget(gi); DrawBackground(gi->x, gi->y, gi->width, gi->height); if (envelope_nr != -1) textarea_info[id].value = level.envelope[envelope_nr].text; ModifyGadget(gi, GDI_AREA_SIZE, *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value, *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value, GDI_END); MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO); } static void DrawPropertiesInfo() { static struct { int value; char *text; } properties[] = { /* configurable properties */ { EP_WALKABLE_OVER, "- player can walk over it" }, { EP_WALKABLE_INSIDE, "- player can walk inside it" }, { EP_WALKABLE_UNDER, "- player can walk under it" }, { EP_PASSABLE_OVER, "- player can pass over it" }, { EP_PASSABLE_INSIDE, "- player can pass through it" }, { EP_PASSABLE_UNDER, "- player can pass under it" }, { EP_PROTECTED, "- player is protected by it" }, { EP_DIGGABLE, "- can be digged away" }, { EP_COLLECTIBLE, "- can be collected" }, { EP_DROPPABLE, "- can be dropped after collecting" }, { EP_THROWABLE, "- can be thrown after collecting" }, { EP_PUSHABLE, "- can be pushed" }, { EP_CAN_FALL, "- can fall" }, { EP_CAN_MOVE, "- can move" }, { EP_CAN_SMASH_PLAYER, "- can smash player" }, #if 0 { EP_CAN_SMASH_ENEMIES, "- can smash good and bad guys" }, #endif { EP_CAN_SMASH_EVERYTHING, "- can smash everything smashable" }, { EP_SLIPPERY, "- slippery for falling elements" }, { EP_EM_SLIPPERY_WALL, "- slippery for some gems (EM style)" }, { EP_DONT_RUN_INTO, "- deadly when running into" }, { EP_DONT_COLLIDE_WITH, "- deadly when colliding with" }, { EP_DONT_GET_HIT_BY, "- deadly when getting hit by" }, { EP_DONT_TOUCH, "- deadly when touching" }, { EP_INDESTRUCTIBLE, "- indestructible" }, { EP_CAN_EXPLODE_BY_FIRE, "- can explode by fire or explosions" }, { EP_CAN_EXPLODE_SMASHED, "- can explode when smashed" }, { EP_CAN_EXPLODE_IMPACT, "- can explode on impact" }, { EP_CAN_CHANGE, "- can change to other element" }, /* pre-defined properties */ { EP_CAN_PASS_MAGIC_WALL, "- can pass magic walls" }, { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)" }, { EP_SWITCHABLE, "- can be switched" }, #if 0 { EP_HAS_EDITOR_CONTENT, "- can contain other elements" }, #endif { -1, NULL } }; char *filename = getElementDescriptionFilename(properties_element); char *percentage_text = "In this level: "; char *properties_text = "Standard properties: "; char *description_text = "Description:"; char *no_description_text = "No description available."; char *none_text = "None"; float percentage; int num_elements_in_level; int num_standard_properties = 0; int font1_nr = FONT_TEXT_1; int font2_nr = FONT_TEXT_2; int font1_width = getFontWidth(font1_nr); int font1_height = getFontHeight(font1_nr); int font2_height = getFontHeight(font2_nr); int line1_height = font1_height + ED_GADGET_LINE_DISTANCE; int font2_yoffset = (font1_height - font2_height) / 2; int percentage_text_len = strlen(percentage_text) * font1_width; int properties_text_len = strlen(properties_text) * font1_width; int xpos = ED_ELEMENT_SETTINGS_X(0); int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE; int i, x, y; if (setup.editor.show_element_token) { int font3_nr = FONT_TEXT_3; int font3_height = getFontHeight(font3_nr); DrawTextF(xpos, ypos, font3_nr, "[%s]", element_info[properties_element].token_name); ypos += 2 * font3_height; } /* ----- print number of elements / percentage of this element in level */ num_elements_in_level = 0; for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] == properties_element) num_elements_in_level++; percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy); DrawTextS(xpos, ypos, font1_nr, percentage_text); if (num_elements_in_level > 0) DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr, "%d (%.2f %%)", num_elements_in_level, percentage); else DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr, none_text); ypos += 2 * MAX(font1_height, font2_height); /* ----- print standard properties of this element */ DrawTextS(xpos, ypos, font1_nr, properties_text); ypos += line1_height; for (i = 0; properties[i].value != -1; i++) { if (!HAS_PROPERTY(properties_element, properties[i].value)) continue; DrawTextS(xpos, ypos, font2_nr, properties[i].text); ypos += font2_height; num_standard_properties++; } if (num_standard_properties == 0) { DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset, font2_nr, none_text); ypos -= (line1_height - font1_height); } ypos += MAX(font1_height, font2_height); /* ----- print special description of this element */ PrintInfoText(description_text, font1_nr, xpos, ypos); ypos += line1_height; if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0) PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height); } #define TEXT_COLLECTING "Score for collecting" #define TEXT_SMASHING "Score for smashing" #define TEXT_SLURPING "Score for slurping robot" #define TEXT_CRACKING "Score for cracking" #define TEXT_AMOEBA_SPEED "Speed of amoeba growth" #define TEXT_DURATION "Duration when activated" #define TEXT_DELAY_ON "Delay before activating" #define TEXT_DELAY_OFF "Delay before deactivating" #define TEXT_DELAY_EXPLODING "Delay before exploding" #define TEXT_DELAY_MOVING "Delay before moving" #define TEXT_BALL_DELAY "Element generation delay" #define TEXT_MOVE_SPEED "Speed of android moving" #define TEXT_CLONE_SPEED "Speed of android cloning" #define TEXT_GAME_OF_LIFE_1 "Min neighbours to survive" #define TEXT_GAME_OF_LIFE_2 "Max neighbours to survive" #define TEXT_GAME_OF_LIFE_3 "Min neighbours to create" #define TEXT_GAME_OF_LIFE_4 "Max neighbours to create" #define TEXT_TIME_BONUS "Extra time to solve level" static struct { int element; int *value; char *text; } elements_with_counter[] = { { EL_EMERALD, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_BD_DIAMOND, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_EMERALD_YELLOW, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_EMERALD_RED, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_EMERALD_PURPLE, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_SP_INFOTRON, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_DIAMOND, &level.score[SC_DIAMOND], TEXT_COLLECTING }, { EL_CRYSTAL, &level.score[SC_CRYSTAL], TEXT_COLLECTING }, { EL_PEARL, &level.score[SC_PEARL], TEXT_COLLECTING }, { EL_BUG, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_RIGHT, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_UP, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_LEFT, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BUG_DOWN, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_UP, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG], TEXT_SMASHING }, { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG], TEXT_SMASHING }, { EL_SP_ELECTRON, &level.score[SC_BUG], TEXT_SMASHING }, { EL_SPACESHIP, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_UP, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_LEFT, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SPACESHIP_DOWN, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_UP, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_SP_SNIKSNAK, &level.score[SC_SPACESHIP], TEXT_SMASHING }, { EL_YAMYAM, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_LEFT, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_RIGHT, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_UP, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_YAMYAM_DOWN, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_DARK_YAMYAM, &level.score[SC_YAMYAM], TEXT_SMASHING }, { EL_ROBOT, &level.score[SC_ROBOT], TEXT_SMASHING }, { EL_PACMAN, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_RIGHT, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_UP, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_LEFT, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_PACMAN_DOWN, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_NUT, &level.score[SC_NUT], TEXT_CRACKING }, { EL_DYNAMITE, &level.score[SC_DYNAMITE], TEXT_COLLECTING }, { EL_EM_DYNAMITE, &level.score[SC_DYNAMITE], TEXT_COLLECTING }, { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING }, { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],TEXT_COLLECTING }, { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],TEXT_COLLECTING }, { EL_SHIELD_NORMAL, &level.score[SC_SHIELD], TEXT_COLLECTING }, { EL_SHIELD_DEADLY, &level.score[SC_SHIELD], TEXT_COLLECTING }, { EL_EXTRA_TIME, &level.extra_time_score, TEXT_COLLECTING }, { EL_KEY_1, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_KEY_2, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_KEY_3, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_KEY_4, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_1, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_2, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_3, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EM_KEY_4, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_5, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_6, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_7, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_EMC_KEY_8, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_DC_KEY_WHITE, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_MM_KETTLE, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_DF_CELL, &level.score[SC_EMERALD], TEXT_COLLECTING }, { EL_MM_KEY, &level.score[SC_KEY], TEXT_COLLECTING }, { EL_MM_LIGHTBALL, &level.score[SC_ELEM_BONUS], TEXT_COLLECTING }, { EL_MM_PACMAN, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_MM_PACMAN_RIGHT, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_MM_PACMAN_UP, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_MM_PACMAN_LEFT, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_MM_PACMAN_DOWN, &level.score[SC_PACMAN], TEXT_SMASHING }, { EL_AMOEBA_WET, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_AMOEBA_DRY, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_AMOEBA_FULL, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_BD_AMOEBA, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_EMC_DRIPPER, &level.amoeba_speed, TEXT_AMOEBA_SPEED }, { EL_MAGIC_WALL, &level.time_magic_wall, TEXT_DURATION }, { EL_BD_MAGIC_WALL, &level.time_magic_wall, TEXT_DURATION }, { EL_DC_MAGIC_WALL, &level.time_magic_wall, TEXT_DURATION }, { EL_ROBOT_WHEEL, &level.time_wheel, TEXT_DURATION }, { EL_TIMEGATE_SWITCH, &level.time_timegate, TEXT_DURATION }, { EL_DC_TIMEGATE_SWITCH,&level.time_timegate, TEXT_DURATION }, { EL_LIGHT_SWITCH, &level.time_light, TEXT_DURATION }, { EL_LIGHT_SWITCH_ACTIVE, &level.time_light, TEXT_DURATION }, { EL_SHIELD_NORMAL, &level.shield_normal_time, TEXT_DURATION }, { EL_SHIELD_DEADLY, &level.shield_deadly_time, TEXT_DURATION }, { EL_EXTRA_TIME, &level.extra_time, TEXT_TIME_BONUS }, { EL_TIME_ORB_FULL, &level.time_orb_time, TEXT_TIME_BONUS }, { EL_GAME_OF_LIFE, &level.game_of_life[0], TEXT_GAME_OF_LIFE_1 }, { EL_GAME_OF_LIFE, &level.game_of_life[1], TEXT_GAME_OF_LIFE_2 }, { EL_GAME_OF_LIFE, &level.game_of_life[2], TEXT_GAME_OF_LIFE_3 }, { EL_GAME_OF_LIFE, &level.game_of_life[3], TEXT_GAME_OF_LIFE_4 }, { EL_BIOMAZE, &level.biomaze[0], TEXT_GAME_OF_LIFE_1 }, { EL_BIOMAZE, &level.biomaze[1], TEXT_GAME_OF_LIFE_2 }, { EL_BIOMAZE, &level.biomaze[2], TEXT_GAME_OF_LIFE_3 }, { EL_BIOMAZE, &level.biomaze[3], TEXT_GAME_OF_LIFE_4 }, { EL_EMC_ANDROID, &level.android_move_time, TEXT_MOVE_SPEED }, { EL_EMC_ANDROID, &level.android_clone_time, TEXT_CLONE_SPEED }, { EL_EMC_MAGIC_BALL, &level.ball_time, TEXT_BALL_DELAY }, { EL_EMC_LENSES, &level.lenses_score, TEXT_COLLECTING }, { EL_EMC_MAGNIFIER, &level.magnify_score, TEXT_COLLECTING }, { EL_SPRING, &level.slurp_score, TEXT_SLURPING }, { EL_EMC_LENSES, &level.lenses_time, TEXT_DURATION }, { EL_EMC_MAGNIFIER, &level.magnify_time, TEXT_DURATION }, { EL_MM_FUSE_ACTIVE, &level.mm_time_fuse, TEXT_DELAY_OFF }, { EL_MM_BOMB, &level.mm_time_bomb, TEXT_DELAY_EXPLODING }, { EL_MM_GRAY_BALL, &level.mm_time_ball, TEXT_DELAY_ON }, { EL_MM_STEEL_BLOCK, &level.mm_time_block, TEXT_DELAY_MOVING }, { EL_MM_WOODEN_BLOCK, &level.mm_time_block, TEXT_DELAY_MOVING }, { -1, NULL, NULL } }; static boolean checkPropertiesConfig(int element) { int i; if (IS_GEM(element) || IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element) || IS_BALLOON_ELEMENT(element) || IS_ENVELOPE(element) || IS_MM_MCDUFFIN(element) || IS_DF_LASER(element) || ELEM_IS_PLAYER(element) || HAS_EDITOR_CONTENT(element) || CAN_GROW(element) || COULD_MOVE_INTO_ACID(element) || MAYBE_DONT_COLLIDE_WITH(element) || element == EL_SOKOBAN_OBJECT || element == EL_SOKOBAN_FIELD_EMPTY || element == EL_SOKOBAN_FIELD_FULL) return TRUE; else for (i = 0; elements_with_counter[i].element != -1; i++) if (elements_with_counter[i].element == element) return TRUE; return FALSE; } static void SetAutomaticNumberOfGemsNeeded() { int x, y; if (!level.auto_count_gems) return; level.gems_needed = 0; for (x = 0; x < lev_fieldx; x++) { for (y = 0; y < lev_fieldy; y++) { int element = Feld[x][y]; if (IS_GEM(element) || element == EL_MM_KETTLE || element == EL_DF_CELL) level.gems_needed++; } } ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed); } static void DrawPropertiesConfig() { boolean draw_footer_line = FALSE; int max_num_element_counters = 4; int num_element_counters = 0; int i; if (!checkPropertiesConfig(properties_element)) { int xpos = ED_ELEMENT_SETTINGS_X(0); int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE; PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos); return; } /* check if there are elements where a value can be chosen for */ for (i = 0; elements_with_counter[i].element != -1; i++) { if (elements_with_counter[i].element == properties_element) { int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters; counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS( (HAS_EDITOR_CONTENT(properties_element) ? 1 : 0) + (CAN_GROW(properties_element) ? 1 : 0) + (COULD_MOVE_INTO_ACID(properties_element) ? 1 : 0) + (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) + (properties_element == EL_EMC_MAGIC_BALL ? 2 : 0) + num_element_counters); counterbutton_info[counter_id].value = elements_with_counter[i].value; counterbutton_info[counter_id].text_right= elements_with_counter[i].text; if (properties_element == EL_GAME_OF_LIFE || properties_element == EL_BIOMAZE) { counterbutton_info[counter_id].min_value = 0; /* min neighbours */ counterbutton_info[counter_id].max_value = 8; /* max neighbours */ } else { /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */ counterbutton_info[counter_id].min_value = MIN_SCORE; counterbutton_info[counter_id].max_value = MAX_SCORE; } MapCounterButtons(counter_id); num_element_counters++; if (num_element_counters >= max_num_element_counters) break; } } if (HAS_EDITOR_CONTENT(properties_element)) { /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); if (IS_AMOEBOID(properties_element)) MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT); else if (properties_element == EL_YAMYAM || properties_element == EL_YAMYAM_LEFT || properties_element == EL_YAMYAM_RIGHT || properties_element == EL_YAMYAM_UP || properties_element == EL_YAMYAM_DOWN) DrawYamYamContentAreas(); else if (properties_element == EL_EMC_MAGIC_BALL) { DrawMagicBallContentAreas(); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE); } else if (properties_element == EL_EMC_ANDROID) DrawAndroidElementArea(properties_element); } if (ELEM_IS_PLAYER(properties_element)) { int player_nr = GET_PLAYER_NR(properties_element); /* these properties can be set for every player individually */ if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1) { drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value = &level.start_element[player_nr]; drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value = &level.artwork_element[player_nr]; drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value = &level.explosion_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value = &level.use_start_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value = &level.use_artwork_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value = &level.use_explosion_element[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value = &level.initial_player_gravity[player_nr]; selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value = &level.initial_player_stepsize[player_nr]; MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID); MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ? ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD : ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE); MapDrawingArea(ED_DRAWING_ID_START_ELEMENT); MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT); MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT); MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED); } else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2) { drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value = &level.initial_inventory_content[player_nr][0]; counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value = &level.initial_inventory_size[player_nr]; checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value = &level.use_initial_inventory[player_nr]; /* draw checkbutton gadgets */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY); /* draw counter gadgets */ MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE); /* draw drawing area gadgets */ DrawPlayerInitialInventoryArea(properties_element); } } if (IS_GEM(properties_element)) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS); if (properties_element == EL_EM_DYNAMITE) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE); if (COULD_MOVE_INTO_ACID(properties_element) && !ELEM_IS_PLAYER(properties_element) && (!IS_CUSTOM_ELEMENT(properties_element) || edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)) { /* set position for checkbutton for "can move into acid" */ checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x = ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0); checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y = ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 : IS_BALLOON_ELEMENT(properties_element) || HAS_EDITOR_CONTENT(properties_element) ? 1 : 0); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID); } if (MAYBE_DONT_COLLIDE_WITH(properties_element)) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH); if (properties_element == EL_SPRING) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG); if (properties_element == EL_TIME_ORB_FULL) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG); if (CAN_GROW(properties_element)) { checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y = ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE); } if (properties_element == EL_SOKOBAN_OBJECT || properties_element == EL_SOKOBAN_FIELD_EMPTY || properties_element == EL_SOKOBAN_FIELD_FULL) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN); if (IS_BALLOON_ELEMENT(properties_element)) MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION); if (IS_ENVELOPE(properties_element)) { int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE; int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE; int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP; int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED; int envelope_nr = properties_element - EL_ENVELOPE_1; counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize; counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize; checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap; checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered; /* display counter to choose size of envelope text area */ MapCounterButtons(counter1_id); MapCounterButtons(counter2_id); /* display checkbuttons to choose auto-wrap and alignment properties */ MapCheckbuttonGadget(button1_id); MapCheckbuttonGadget(button2_id); DrawEnvelopeTextArea(envelope_nr); } if (IS_MM_MCDUFFIN(properties_element)) { MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE); } if (IS_DF_LASER(properties_element)) { MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE); } if (IS_CUSTOM_ELEMENT(properties_element)) { /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1) { /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_CUSTOM1_FIRST; i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++) MapCheckbuttonGadget(i); /* draw counter gadgets */ for (i = ED_COUNTER_ID_CUSTOM1_FIRST; i <= ED_COUNTER_ID_CUSTOM1_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_CUSTOM1_FIRST; i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++) MapSelectboxGadget(i); /* draw textbutton gadgets */ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1); /* draw text input gadgets */ MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME); /* draw drawing area gadgets */ MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC); draw_footer_line = TRUE; } else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2) { /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_CUSTOM2_FIRST; i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++) MapCheckbuttonGadget(i); /* draw counter gadgets */ for (i = ED_COUNTER_ID_CUSTOM2_FIRST; i <= ED_COUNTER_ID_CUSTOM2_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_CUSTOM2_FIRST; i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++) MapSelectboxGadget(i); /* draw drawing area gadgets */ MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER); MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE); DrawCustomContentArea(); } } else if (IS_GROUP_ELEMENT(properties_element)) { /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); /* draw checkbutton gadgets */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC); MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1); /* draw counter gadgets */ MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT); /* draw selectbox gadgets */ MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE); /* draw textbutton gadgets */ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1); /* draw drawing area gadgets */ DrawGroupElementArea(properties_element); /* draw text input gadgets */ MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME); /* draw drawing area gadgets */ MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC); draw_footer_line = TRUE; } /* draw little footer border line above CE/GE use/save template gadgets */ if (draw_footer_line) { struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO]; struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED]; int gd_x = gd->x + gd_gi1->border.width / 2; int gd_y = gd->y + gd_gi1->height - 1; Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y); if (tab_color != BLACK_PIXEL) /* black => transparent */ FillRectangle(drawto, SX + ED_ELEMENT_SETTINGS_X(0), SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET - ED_TAB_BAR_HEIGHT, getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color); } } static void DrawPropertiesChangeDrawingAreas() { if (IS_CUSTOM_ELEMENT(properties_element)) { MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET); MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER); MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION); DrawCustomChangeContentArea(); } redraw_mask |= REDRAW_FIELD; } static void DrawPropertiesChange() { int i; /* needed to initially set selectbox options for special action options */ setSelectboxSpecialActionOptions(); /* draw stickybutton gadget */ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT); /* draw checkbutton gadgets */ for (i = ED_CHECKBUTTON_ID_CHANGE_FIRST; i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++) MapCheckbuttonGadget(i); /* draw counter gadgets */ for (i = ED_COUNTER_ID_CHANGE_FIRST; i <= ED_COUNTER_ID_CHANGE_LAST; i++) MapCounterButtons(i); /* draw selectbox gadgets */ for (i = ED_SELECTBOX_ID_CHANGE_FIRST; i <= ED_SELECTBOX_ID_CHANGE_LAST; i++) MapSelectboxGadget(i); /* draw textbutton gadgets */ for (i = ED_TEXTBUTTON_ID_CHANGE_FIRST; i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++) MapTextbuttonGadget(i); /* draw graphicbutton gadgets */ for (i = ED_GRAPHICBUTTON_ID_CHANGE_FIRST; i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++) MapGraphicbuttonGadget(i); /* draw drawing area gadgets */ DrawPropertiesChangeDrawingAreas(); } static void DrawEditorElementAnimation(int x, int y) { int graphic = el2img(properties_element); int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ? custom_element.ce_value_fixed_initial : ANIM_MODE(graphic) == ANIM_CE_SCORE ? custom_element.collect_score_initial : FrameCounter); DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING); } static void DrawEditorElementName(int x, int y, int font_nr) { char *element_name = getElementInfoText(properties_element); int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0); int max_chars_per_line = max_text_width / font_width; char buffer[max_chars_per_line + 1]; if (strlen(element_name) <= max_chars_per_line) DrawTextS(x, y, font_nr, element_name); else { int next_pos = max_chars_per_line; strncpy(buffer, element_name, max_chars_per_line); buffer[max_chars_per_line] = '\0'; if (element_name[max_chars_per_line] == ' ') next_pos++; else { int i; for (i = max_chars_per_line - 1; i >= 0; i--) if (buffer[i] == ' ') break; if (strlen(&element_name[i + 1]) <= max_chars_per_line) { buffer[i] = '\0'; next_pos = i + 1; } } DrawTextS(x, y - font_height / 2, font_nr, buffer); strncpy(buffer, &element_name[next_pos], max_chars_per_line); buffer[max_chars_per_line] = '\0'; DrawTextS(x, y + font_height / 2, font_nr, buffer); } } static void DrawPropertiesWindow() { struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT]; int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size; int border_size = gd->border_size; int font_nr = FONT_TEXT_1; int font_height = getFontHeight(font_nr); int xoffset = TILEX + element_border + 3 * border_size; int yoffset = (TILEY - font_height) / 2; int x1 = editor.settings.element_graphic.x + element_border; int y1 = editor.settings.element_graphic.y + element_border; int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset : editor.settings.element_name.x); int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset : editor.settings.element_name.y); char *text = "Element Settings"; int font2_nr = FONT_TITLE_1; struct MenuPosInfo *pos = &editor.settings.headline; int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align); int sy = SY + pos->y; stick_element_properties_window = FALSE; /* make sure that previous properties edit mode exists for this element */ if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 && !IS_CUSTOM_ELEMENT(properties_element)) edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2; if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG && !ELEM_IS_PLAYER(properties_element) && !IS_CUSTOM_ELEMENT(properties_element)) edit_mode_properties = ED_MODE_PROPERTIES_CONFIG; if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG && (ELEM_IS_PLAYER(properties_element) || IS_CUSTOM_ELEMENT(properties_element))) edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1; CopyElementPropertiesToEditor(properties_element); UnmapLevelEditorFieldGadgets(); UnmapLevelEditorToolboxDrawingGadgets(); UnmapLevelEditorToolboxCustomGadgets(); if (IS_CUSTOM_ELEMENT(properties_element) || IS_GROUP_ELEMENT(properties_element)) MapLevelEditorToolboxCustomGadgets(); SetMainBackgroundImage(IMG_BACKGROUND_EDITOR); ClearField(); DrawText(sx, sy, text, font2_nr); FrameCounter = 0; /* restart animation frame counter */ DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE); DrawEditorElementAnimation(SX + x1, SY + y1); DrawEditorElementName(x2, y2, font_nr); DrawPropertiesTabulatorGadgets(); if (edit_mode_properties == ED_MODE_PROPERTIES_INFO) DrawPropertiesInfo(); else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE) DrawPropertiesChange(); else /* (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2]) */ DrawPropertiesConfig(); } static void DrawPaletteWindow() { int i; UnmapLevelEditorFieldGadgets(); SetMainBackgroundImage(IMG_BACKGROUND_EDITOR); ClearField(); /* map buttons to select elements */ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++) MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]); MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]); } static void UpdateCustomElementGraphicGadgets() { int i; InitElementPropertiesGfxElement(); ModifyEditorElementList(); RedrawDrawingElements(); /* force redraw of all mapped drawing area gadgets */ for (i = 0; i < ED_NUM_DRAWING_AREAS; i++) { struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id]; if (gi->mapped) MapDrawingArea(i); } } static int getOpenDirectionFromTube(int element) { switch (element) { case EL_TUBE_LEFT_UP: return (MV_LEFT | MV_UP); case EL_TUBE_LEFT_DOWN: return (MV_LEFT | MV_DOWN); case EL_TUBE_RIGHT_UP: return (MV_RIGHT | MV_UP); case EL_TUBE_RIGHT_DOWN: return (MV_RIGHT | MV_DOWN); case EL_TUBE_HORIZONTAL: return (MV_HORIZONTAL); case EL_TUBE_HORIZONTAL_UP: return (MV_HORIZONTAL | MV_UP); case EL_TUBE_HORIZONTAL_DOWN: return (MV_HORIZONTAL | MV_DOWN); case EL_TUBE_VERTICAL: return (MV_VERTICAL); case EL_TUBE_VERTICAL_LEFT: return (MV_VERTICAL | MV_LEFT); case EL_TUBE_VERTICAL_RIGHT: return (MV_VERTICAL | MV_RIGHT); case EL_TUBE_ANY: return (MV_ANY_DIRECTION); } return MV_NONE; } static int getTubeFromOpenDirection(int direction) { switch (direction) { case (MV_LEFT | MV_UP): return EL_TUBE_LEFT_UP; case (MV_LEFT | MV_DOWN): return EL_TUBE_LEFT_DOWN; case (MV_RIGHT | MV_UP): return EL_TUBE_RIGHT_UP; case (MV_RIGHT | MV_DOWN): return EL_TUBE_RIGHT_DOWN; case (MV_HORIZONTAL): return EL_TUBE_HORIZONTAL; case (MV_HORIZONTAL | MV_UP): return EL_TUBE_HORIZONTAL_UP; case (MV_HORIZONTAL | MV_DOWN): return EL_TUBE_HORIZONTAL_DOWN; case (MV_VERTICAL): return EL_TUBE_VERTICAL; case (MV_VERTICAL | MV_LEFT): return EL_TUBE_VERTICAL_LEFT; case (MV_VERTICAL | MV_RIGHT): return EL_TUBE_VERTICAL_RIGHT; case (MV_ANY_DIRECTION): return EL_TUBE_ANY; /* if only one direction, fall back to simple tube with that direction */ case (MV_LEFT): return EL_TUBE_HORIZONTAL; case (MV_RIGHT): return EL_TUBE_HORIZONTAL; case (MV_UP): return EL_TUBE_VERTICAL; case (MV_DOWN): return EL_TUBE_VERTICAL; } return EL_EMPTY; } static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getTubeFromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromBelt(int element) { int belt_dir = getBeltDirFromBeltElement(element); return (belt_dir == MV_LEFT ? MV_RIGHT : belt_dir == MV_RIGHT ? MV_LEFT : belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir); } static int getBeltFromNrAndOpenDirection(int nr, int direction) { int belt_dir = (direction == MV_LEFT ? MV_RIGHT : direction == MV_RIGHT ? MV_LEFT : direction == MV_HORIZONTAL ? MV_NONE : direction); if (direction == MV_NONE) return EL_EMPTY; return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir); } static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction, int element_old) { int element_new = getBeltFromNrAndOpenDirection(nr, direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromPool(int element) { switch (element) { case EL_ACID_POOL_TOPLEFT: return (MV_DOWN | MV_RIGHT); case EL_ACID_POOL_TOPRIGHT: return (MV_DOWN | MV_LEFT); case EL_ACID_POOL_BOTTOMLEFT: return (MV_UP | MV_RIGHT); case EL_ACID_POOL_BOTTOMRIGHT: return (MV_UP | MV_LEFT); case EL_ACID_POOL_BOTTOM: return (MV_HORIZONTAL | MV_UP); case EL_ACID: return (MV_HORIZONTAL | MV_DOWN); } return MV_NONE; } static int getPoolFromOpenDirection(int direction) { switch (direction) { case (MV_DOWN | MV_RIGHT): return EL_ACID_POOL_TOPLEFT; case (MV_DOWN | MV_LEFT): return EL_ACID_POOL_TOPRIGHT; case (MV_UP | MV_RIGHT): return EL_ACID_POOL_BOTTOMLEFT; case (MV_UP | MV_LEFT): return EL_ACID_POOL_BOTTOMRIGHT; case (MV_HORIZONTAL | MV_UP): return EL_ACID_POOL_BOTTOM; case (MV_HORIZONTAL | MV_DOWN): return EL_ACID; } return EL_EMPTY; } static int getPoolFromOpenDirectionExt(int direction, int help_element) { int element = getPoolFromOpenDirection(direction); int help_direction = getOpenDirectionFromPool(help_element); if (element == EL_EMPTY) { int help_direction_vertical = help_direction & MV_VERTICAL; element = getPoolFromOpenDirection(direction | help_direction_vertical); } if (element == EL_EMPTY) { int help_direction_horizontal = help_direction & MV_HORIZONTAL; element = getPoolFromOpenDirection(direction | help_direction_horizontal); } return element; } static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getPoolFromOpenDirectionExt(direction, element_old); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromPillar(int element) { switch (element) { case EL_EMC_WALL_1: return (MV_DOWN); case EL_EMC_WALL_2: return (MV_VERTICAL); case EL_EMC_WALL_3: return (MV_UP); } return MV_NONE; } static int getPillarFromOpenDirection(int direction) { switch (direction) { case (MV_DOWN): return EL_EMC_WALL_1; case (MV_VERTICAL): return EL_EMC_WALL_2; case (MV_UP): return EL_EMC_WALL_3; } return EL_EMPTY; } static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getPillarFromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromSteel2(int element) { switch (element) { case EL_DC_STEELWALL_2_LEFT: return (MV_RIGHT); case EL_DC_STEELWALL_2_RIGHT: return (MV_LEFT); case EL_DC_STEELWALL_2_TOP: return (MV_DOWN); case EL_DC_STEELWALL_2_BOTTOM: return (MV_UP); case EL_DC_STEELWALL_2_HORIZONTAL: return (MV_HORIZONTAL); case EL_DC_STEELWALL_2_VERTICAL: return (MV_VERTICAL); case EL_DC_STEELWALL_2_MIDDLE: return (MV_ANY_DIRECTION); case EL_DC_STEELWALL_2_SINGLE: return (MV_NONE); } return MV_NONE; } static int getSteel2FromOpenDirection(int direction) { switch (direction) { case (MV_RIGHT): return EL_DC_STEELWALL_2_LEFT; case (MV_LEFT): return EL_DC_STEELWALL_2_RIGHT; case (MV_DOWN): return EL_DC_STEELWALL_2_TOP; case (MV_UP): return EL_DC_STEELWALL_2_BOTTOM; case (MV_HORIZONTAL): return EL_DC_STEELWALL_2_HORIZONTAL; case (MV_VERTICAL): return EL_DC_STEELWALL_2_VERTICAL; case (MV_ANY_DIRECTION): return EL_DC_STEELWALL_2_MIDDLE; case (MV_NONE): return EL_DC_STEELWALL_2_SINGLE; } return EL_EMPTY; } static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getSteel2FromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getOpenDirectionFromChip(int element) { switch (element) { case EL_SP_CHIP_SINGLE: return (MV_NONE); case EL_SP_CHIP_LEFT: return (MV_RIGHT); case EL_SP_CHIP_RIGHT: return (MV_LEFT); case EL_SP_CHIP_TOP: return (MV_DOWN); case EL_SP_CHIP_BOTTOM: return (MV_UP); } return MV_NONE; } static int getChipFromOpenDirection(int direction) { switch (direction) { case (MV_NONE): return EL_SP_CHIP_SINGLE; case (MV_LEFT): return EL_SP_CHIP_RIGHT; case (MV_RIGHT): return EL_SP_CHIP_LEFT; case (MV_UP): return EL_SP_CHIP_BOTTOM; case (MV_DOWN): return EL_SP_CHIP_TOP; } return EL_EMPTY; } static int getChipFromOpenDirectionNotEmpty(int direction, int element_old) { int element_new = getChipFromOpenDirection(direction); return (element_new != EL_EMPTY ? element_new : element_old); } static int getClosedTube(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromTube(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getTubeFromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedBelt(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int nr = getBeltNrFromBeltElement(element_old); int direction_old = getOpenDirectionFromBelt(element_old); int direction_new = MV_NONE; int i; for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getBeltFromNrAndOpenDirection(nr, direction_new); } static int getClosedPool(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromPool(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getPoolFromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedPillar(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromPillar(element_old); int direction_new = MV_NONE; int i; for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getPillarFromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedSteel2(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromSteel2(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old); } static int getClosedChip(int x, int y) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; int element_old = IntelliDrawBuffer[x][y]; int direction_old = getOpenDirectionFromChip(element_old); int direction_new = MV_NONE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) && (direction_old & dir) && (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite)) direction_new |= dir; } return getChipFromOpenDirectionNotEmpty(direction_new, element_old); } static void SetElementSimpleExt(int x, int y, int dx, int dy, int element, boolean change_level) { int sx = x - level_xpos; int sy = y - level_ypos; int old_element = Feld[x][y]; int new_element = element; unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f); boolean draw_masked = FALSE; if (IS_MM_WALL_EDITOR(element)) { element = map_mm_wall_element_editor(element) | new_bitmask; if (IS_MM_WALL(old_element)) element |= MM_WALL_BITS(old_element); if (!change_level) draw_masked = TRUE; } else if (IS_MM_WALL(old_element) && element == EL_EMPTY) { int element_changed = old_element & ~new_bitmask; if (MM_WALL_BITS(element_changed) != 0) element = element_changed; } IntelliDrawBuffer[x][y] = element; if (change_level) Feld[x][y] = element; if (IN_ED_FIELD(sx, sy)) { if (IS_MM_WALL(old_element) && new_element == EL_EMPTY) DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask); else if (draw_masked) DrawEditorElementThruMask(sx, sy, element); else DrawEditorElement(sx, sy, element); } } static void SetElementSimple(int x, int y, int element, boolean change_level) { SetElementSimpleExt(x, y, 0, 0, element, change_level); } static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1, int x2, int y2, int *element2, int (*close_function)(int, int), boolean change_level) { /* set neighbour elements to newly determined connections */ SetElementSimple(x1, y1, *element1, change_level); SetElementSimple(x2, y2, *element2, change_level); /* remove all open connections of neighbour elements */ *element1 = close_function(x1, y1); *element2 = close_function(x2, y2); /* set neighbour elements to new, minimized connections */ SetElementSimple(x1, y1, *element1, change_level); SetElementSimple(x2, y2, *element2, change_level); } static void SetElementIntelliDraw(int x, int y, int new_element, boolean change_level, int button) { static int xy[4][2] = { { -1, 0 }, { +1, 0 }, { 0, -1 }, { 0, +1 } }; static int last_x = -1; static int last_y = -1; int old_element = IntelliDrawBuffer[x][y]; if (new_element == EL_UNDEFINED) { last_x = -1; last_y = -1; return; } if (IS_TUBE(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_TUBE(old_element)) direction |= getOpenDirectionFromTube(old_element); for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_TUBE(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromTube(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getTubeFromOpenDirection(last_direction_new); direction |= dir; } } new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedTube, change_level); } else if (IS_BELT(new_element)) { int belt_nr = getBeltNrFromBeltElement(new_element); int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_BELT(old_element)) direction |= getOpenDirectionFromBelt(old_element); for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_BELT(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_belt_nr = getBeltNrFromBeltElement(last_element_old); int last_direction_old = getOpenDirectionFromBelt(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr, last_direction_new); direction |= dir; } } new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedBelt, change_level); } else if (IS_ACID_POOL_OR_ACID(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_ACID_POOL_OR_ACID(old_element)) direction |= getOpenDirectionFromPool(old_element); for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromPool(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getPoolFromOpenDirection(last_direction_new); direction |= dir; } } /* special corrections needed for intuitively correct acid pool drawing */ if (last_element_new == EL_EMPTY) last_element_new = new_element; else if (last_element_new != EL_UNDEFINED) new_element = last_element_new; new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedPool, change_level); } else if (IS_EMC_PILLAR(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_EMC_PILLAR(old_element)) direction |= getOpenDirectionFromPillar(old_element); for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromPillar(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getPillarFromOpenDirection(last_direction_new); direction |= dir; } } new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedPillar, change_level); } else if (IS_DC_STEELWALL_2(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* if old element is of same kind, keep all existing directions */ if (IS_DC_STEELWALL_2(old_element)) direction |= getOpenDirectionFromSteel2(old_element); for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromSteel2(last_element_old); int last_direction_new = last_direction_old | dir_opposite; last_element_new = getSteel2FromOpenDirection(last_direction_new); direction |= dir; } } new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedSteel2, change_level); } else if (IS_SP_CHIP(new_element)) { int last_element_new = EL_UNDEFINED; int direction = MV_NONE; int i; /* (do not keep existing directions, regardless of kind of old element) */ for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y])) { int dir = MV_DIR_FROM_BIT(i); int dir_opposite = MV_DIR_OPPOSITE(dir); int last_element_old = IntelliDrawBuffer[last_x][last_y]; int last_direction_old = getOpenDirectionFromChip(last_element_old); int last_direction_new = last_direction_old | dir_opposite; if (last_direction_old == MV_NONE) { last_element_new = getChipFromOpenDirection(last_direction_new); direction |= dir; } else if (last_direction_old & (dir | dir_opposite)) { direction |= MV_DIR_OPPOSITE(last_direction_old); } else { direction |= MV_DIR_OPPOSITE(dir); } } } new_element = getChipFromOpenDirectionNotEmpty(direction, new_element); if (last_element_new != EL_UNDEFINED) MergeAndCloseNeighbourElements(x, y, &new_element, last_x, last_y, &last_element_new, getClosedChip, change_level); } else if (IS_SP_HARDWARE_BASE(new_element)) { int nr = GetSimpleRandom(6); new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 : nr == 1 ? EL_SP_HARDWARE_BASE_2 : nr == 2 ? EL_SP_HARDWARE_BASE_3 : nr == 3 ? EL_SP_HARDWARE_BASE_4 : nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6); } else if (new_element == EL_SP_HARDWARE_GREEN || new_element == EL_SP_HARDWARE_BLUE || new_element == EL_SP_HARDWARE_RED) { int nr = GetSimpleRandom(3); new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN : nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED); } else if (IS_GROUP_ELEMENT(new_element)) { boolean connected_drawing = FALSE; int i; for (i = 0; i < NUM_DIRECTIONS; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) && IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element)) connected_drawing = TRUE; } if (!connected_drawing) ResolveGroupElement(new_element); new_element = GetElementFromGroupElement(new_element); } else if (IS_BELT_SWITCH(old_element)) { int belt_nr = getBeltNrFromBeltSwitchElement(old_element); int belt_dir = getBeltDirFromBeltSwitchElement(old_element); belt_dir = (belt_dir == MV_LEFT ? MV_NONE : belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT); new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir); } else { static int swappable_elements[][2] = { { EL_EXIT_CLOSED, EL_EXIT_OPEN }, { EL_DYNAMITE, EL_DYNAMITE_ACTIVE }, { EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE }, { EL_QUICKSAND_EMPTY, EL_QUICKSAND_FULL }, { EL_EMERALD, EL_WALL_EMERALD }, { EL_EMERALD_YELLOW, EL_WALL_EMERALD_YELLOW }, { EL_EMERALD_RED, EL_WALL_EMERALD_RED }, { EL_EMERALD_PURPLE, EL_WALL_EMERALD_PURPLE }, { EL_DIAMOND, EL_WALL_DIAMOND }, { EL_BD_DIAMOND, EL_WALL_BD_DIAMOND }, { EL_GATE_1, EL_GATE_1_GRAY }, { EL_GATE_2, EL_GATE_2_GRAY }, { EL_GATE_3, EL_GATE_3_GRAY }, { EL_GATE_4, EL_GATE_4_GRAY }, { EL_EM_GATE_1, EL_EM_GATE_1_GRAY }, { EL_EM_GATE_2, EL_EM_GATE_2_GRAY }, { EL_EM_GATE_3, EL_EM_GATE_3_GRAY }, { EL_EM_GATE_4, EL_EM_GATE_4_GRAY }, { EL_EMC_GATE_5, EL_EMC_GATE_5_GRAY }, { EL_EMC_GATE_6, EL_EMC_GATE_6_GRAY }, { EL_EMC_GATE_7, EL_EMC_GATE_7_GRAY }, { EL_EMC_GATE_8, EL_EMC_GATE_8_GRAY }, { EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY }, { EL_TIME_ORB_EMPTY, EL_TIME_ORB_FULL }, { EL_LAMP, EL_LAMP_ACTIVE }, { EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL }, { EL_SP_BASE, EL_SP_BUGGY_BASE }, { EL_PEARL, EL_WALL_PEARL }, { EL_CRYSTAL, EL_WALL_CRYSTAL }, { EL_TIMEGATE_CLOSED, EL_TIMEGATE_OPEN }, { EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_OPEN }, { EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN }, { EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN }, { EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE }, { EL_LANDMINE, EL_DC_LANDMINE }, { EL_SHIELD_NORMAL, EL_SHIELD_DEADLY }, { EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN }, { EL_EM_EXIT_CLOSED, EL_EM_EXIT_OPEN }, { EL_EM_STEEL_EXIT_CLOSED, EL_EM_STEEL_EXIT_OPEN }, { EL_QUICKSAND_FAST_EMPTY, EL_QUICKSAND_FAST_FULL }, { EL_MM_EXIT_CLOSED, EL_MM_EXIT_OPEN }, { EL_MM_FUSE, EL_MM_FUSE_ACTIVE }, { EL_MM_LIGHTBULB, EL_MM_LIGHTBULB_ACTIVE }, { EL_MM_FUEL_EMPTY, EL_MM_FUEL_FULL }, { -1, -1 }, }; static int rotatable_elements_4[][4] = { { EL_BUG_UP, EL_BUG_RIGHT, EL_BUG_DOWN, EL_BUG_LEFT }, { EL_SPACESHIP_UP, EL_SPACESHIP_RIGHT, EL_SPACESHIP_DOWN, EL_SPACESHIP_LEFT }, { EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_RIGHT, EL_BD_BUTTERFLY_DOWN, EL_BD_BUTTERFLY_LEFT }, { EL_BD_FIREFLY_UP, EL_BD_FIREFLY_RIGHT, EL_BD_FIREFLY_DOWN, EL_BD_FIREFLY_LEFT }, { EL_PACMAN_UP, EL_PACMAN_RIGHT, EL_PACMAN_DOWN, EL_PACMAN_LEFT }, { EL_YAMYAM_UP, EL_YAMYAM_RIGHT, EL_YAMYAM_DOWN, EL_YAMYAM_LEFT }, { EL_ARROW_UP, EL_ARROW_RIGHT, EL_ARROW_DOWN, EL_ARROW_LEFT }, { EL_SP_PORT_UP, EL_SP_PORT_RIGHT, EL_SP_PORT_DOWN, EL_SP_PORT_LEFT }, { EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT }, { EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT }, { EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT }, { EL_MOLE_UP, EL_MOLE_RIGHT, EL_MOLE_DOWN, EL_MOLE_LEFT }, { EL_BALLOON_SWITCH_UP, EL_BALLOON_SWITCH_RIGHT, EL_BALLOON_SWITCH_DOWN, EL_BALLOON_SWITCH_LEFT }, { EL_MM_MCDUFFIN_UP, EL_MM_MCDUFFIN_RIGHT, EL_MM_MCDUFFIN_DOWN, EL_MM_MCDUFFIN_LEFT }, { EL_MM_MIRROR_FIXED_1, EL_MM_MIRROR_FIXED_4, EL_MM_MIRROR_FIXED_3, EL_MM_MIRROR_FIXED_2 }, { EL_MM_STEEL_GRID_FIXED_1, EL_MM_STEEL_GRID_FIXED_4, EL_MM_STEEL_GRID_FIXED_2, EL_MM_STEEL_GRID_FIXED_3 }, { EL_MM_WOODEN_GRID_FIXED_1, EL_MM_WOODEN_GRID_FIXED_4, EL_MM_WOODEN_GRID_FIXED_2, EL_MM_WOODEN_GRID_FIXED_3 }, { EL_MM_POLARIZER_CROSS_1, EL_MM_POLARIZER_CROSS_4, EL_MM_POLARIZER_CROSS_3, EL_MM_POLARIZER_CROSS_2 }, { EL_MM_PACMAN_UP, EL_MM_PACMAN_RIGHT, EL_MM_PACMAN_DOWN, EL_MM_PACMAN_LEFT }, { EL_DF_LASER_UP, EL_DF_LASER_RIGHT, EL_DF_LASER_DOWN, EL_DF_LASER_LEFT }, { EL_DF_RECEIVER_UP, EL_DF_RECEIVER_RIGHT, EL_DF_RECEIVER_DOWN, EL_DF_RECEIVER_LEFT }, { -1, }, }; static int rotatable_elements_8[][8] = { { EL_DF_STEEL_GRID_FIXED_1, EL_DF_STEEL_GRID_FIXED_8, EL_DF_STEEL_GRID_FIXED_7, EL_DF_STEEL_GRID_FIXED_6, EL_DF_STEEL_GRID_FIXED_5, EL_DF_STEEL_GRID_FIXED_4, EL_DF_STEEL_GRID_FIXED_3, EL_DF_STEEL_GRID_FIXED_2 }, { EL_DF_WOODEN_GRID_FIXED_1, EL_DF_WOODEN_GRID_FIXED_8, EL_DF_WOODEN_GRID_FIXED_7, EL_DF_WOODEN_GRID_FIXED_6, EL_DF_WOODEN_GRID_FIXED_5, EL_DF_WOODEN_GRID_FIXED_4, EL_DF_WOODEN_GRID_FIXED_3, EL_DF_WOODEN_GRID_FIXED_2 }, { EL_DF_STEEL_GRID_ROTATING_1, EL_DF_STEEL_GRID_ROTATING_8, EL_DF_STEEL_GRID_ROTATING_7, EL_DF_STEEL_GRID_ROTATING_6, EL_DF_STEEL_GRID_ROTATING_5, EL_DF_STEEL_GRID_ROTATING_4, EL_DF_STEEL_GRID_ROTATING_3, EL_DF_STEEL_GRID_ROTATING_2 }, { EL_DF_WOODEN_GRID_ROTATING_1, EL_DF_WOODEN_GRID_ROTATING_8, EL_DF_WOODEN_GRID_ROTATING_7, EL_DF_WOODEN_GRID_ROTATING_6, EL_DF_WOODEN_GRID_ROTATING_5, EL_DF_WOODEN_GRID_ROTATING_4, EL_DF_WOODEN_GRID_ROTATING_3, EL_DF_WOODEN_GRID_ROTATING_2 }, { -1, }, }; static int rotatable_elements_16[][16] = { { EL_MM_MIRROR_1, EL_MM_MIRROR_16, EL_MM_MIRROR_15, EL_MM_MIRROR_14, EL_MM_MIRROR_13, EL_MM_MIRROR_12, EL_MM_MIRROR_11, EL_MM_MIRROR_10, EL_MM_MIRROR_9, EL_MM_MIRROR_8, EL_MM_MIRROR_7, EL_MM_MIRROR_6, EL_MM_MIRROR_5, EL_MM_MIRROR_4, EL_MM_MIRROR_3, EL_MM_MIRROR_2 }, { EL_MM_TELEPORTER_5, EL_MM_TELEPORTER_4, EL_MM_TELEPORTER_3, EL_MM_TELEPORTER_2, EL_MM_TELEPORTER_1, EL_MM_TELEPORTER_16, EL_MM_TELEPORTER_15, EL_MM_TELEPORTER_14, EL_MM_TELEPORTER_13, EL_MM_TELEPORTER_12, EL_MM_TELEPORTER_11, EL_MM_TELEPORTER_10, EL_MM_TELEPORTER_9, EL_MM_TELEPORTER_8, EL_MM_TELEPORTER_7, EL_MM_TELEPORTER_6 }, { EL_MM_TELEPORTER_RED_5, EL_MM_TELEPORTER_RED_4, EL_MM_TELEPORTER_RED_3, EL_MM_TELEPORTER_RED_2, EL_MM_TELEPORTER_RED_1, EL_MM_TELEPORTER_RED_16, EL_MM_TELEPORTER_RED_15, EL_MM_TELEPORTER_RED_14, EL_MM_TELEPORTER_RED_13, EL_MM_TELEPORTER_RED_12, EL_MM_TELEPORTER_RED_11, EL_MM_TELEPORTER_RED_10, EL_MM_TELEPORTER_RED_9, EL_MM_TELEPORTER_RED_8, EL_MM_TELEPORTER_RED_7, EL_MM_TELEPORTER_RED_6 }, { EL_MM_TELEPORTER_YELLOW_5, EL_MM_TELEPORTER_YELLOW_4, EL_MM_TELEPORTER_YELLOW_3, EL_MM_TELEPORTER_YELLOW_2, EL_MM_TELEPORTER_YELLOW_1, EL_MM_TELEPORTER_YELLOW_16, EL_MM_TELEPORTER_YELLOW_15, EL_MM_TELEPORTER_YELLOW_14, EL_MM_TELEPORTER_YELLOW_13, EL_MM_TELEPORTER_YELLOW_12, EL_MM_TELEPORTER_YELLOW_11, EL_MM_TELEPORTER_YELLOW_10, EL_MM_TELEPORTER_YELLOW_9, EL_MM_TELEPORTER_YELLOW_8, EL_MM_TELEPORTER_YELLOW_7, EL_MM_TELEPORTER_YELLOW_6 }, { EL_MM_TELEPORTER_GREEN_5, EL_MM_TELEPORTER_GREEN_4, EL_MM_TELEPORTER_GREEN_3, EL_MM_TELEPORTER_GREEN_2, EL_MM_TELEPORTER_GREEN_1, EL_MM_TELEPORTER_GREEN_16, EL_MM_TELEPORTER_GREEN_15, EL_MM_TELEPORTER_GREEN_14, EL_MM_TELEPORTER_GREEN_13, EL_MM_TELEPORTER_GREEN_12, EL_MM_TELEPORTER_GREEN_11, EL_MM_TELEPORTER_GREEN_10, EL_MM_TELEPORTER_GREEN_9, EL_MM_TELEPORTER_GREEN_8, EL_MM_TELEPORTER_GREEN_7, EL_MM_TELEPORTER_GREEN_6 }, { EL_MM_TELEPORTER_BLUE_5, EL_MM_TELEPORTER_BLUE_4, EL_MM_TELEPORTER_BLUE_3, EL_MM_TELEPORTER_BLUE_2, EL_MM_TELEPORTER_BLUE_1, EL_MM_TELEPORTER_BLUE_16, EL_MM_TELEPORTER_BLUE_15, EL_MM_TELEPORTER_BLUE_14, EL_MM_TELEPORTER_BLUE_13, EL_MM_TELEPORTER_BLUE_12, EL_MM_TELEPORTER_BLUE_11, EL_MM_TELEPORTER_BLUE_10, EL_MM_TELEPORTER_BLUE_9, EL_MM_TELEPORTER_BLUE_8, EL_MM_TELEPORTER_BLUE_7, EL_MM_TELEPORTER_BLUE_6 }, { EL_MM_POLARIZER_1, EL_MM_POLARIZER_16, EL_MM_POLARIZER_15, EL_MM_POLARIZER_14, EL_MM_POLARIZER_13, EL_MM_POLARIZER_12, EL_MM_POLARIZER_11, EL_MM_POLARIZER_10, EL_MM_POLARIZER_9, EL_MM_POLARIZER_8, EL_MM_POLARIZER_7, EL_MM_POLARIZER_6, EL_MM_POLARIZER_5, EL_MM_POLARIZER_4, EL_MM_POLARIZER_3, EL_MM_POLARIZER_2 }, { EL_DF_MIRROR_1, EL_DF_MIRROR_16, EL_DF_MIRROR_15, EL_DF_MIRROR_14, EL_DF_MIRROR_13, EL_DF_MIRROR_12, EL_DF_MIRROR_11, EL_DF_MIRROR_10, EL_DF_MIRROR_9, EL_DF_MIRROR_8, EL_DF_MIRROR_7, EL_DF_MIRROR_6, EL_DF_MIRROR_5, EL_DF_MIRROR_4, EL_DF_MIRROR_3, EL_DF_MIRROR_2 }, { EL_DF_MIRROR_ROTATING_1, EL_DF_MIRROR_ROTATING_16, EL_DF_MIRROR_ROTATING_15, EL_DF_MIRROR_ROTATING_14, EL_DF_MIRROR_ROTATING_13, EL_DF_MIRROR_ROTATING_12, EL_DF_MIRROR_ROTATING_11, EL_DF_MIRROR_ROTATING_10, EL_DF_MIRROR_ROTATING_9, EL_DF_MIRROR_ROTATING_8, EL_DF_MIRROR_ROTATING_7, EL_DF_MIRROR_ROTATING_6, EL_DF_MIRROR_ROTATING_5, EL_DF_MIRROR_ROTATING_4, EL_DF_MIRROR_ROTATING_3, EL_DF_MIRROR_ROTATING_2 }, { -1, }, }; int i, j; for (i = 0; swappable_elements[i][0] != -1; i++) { int element1 = swappable_elements[i][0]; int element2 = swappable_elements[i][1]; if (old_element == element1 || old_element == element2) new_element = (old_element == element1 ? element2 : element1); } for (i = 0; rotatable_elements_4[i][0] != -1; i++) { for (j = 0; j < 4; j++) { int element = rotatable_elements_4[i][j]; if (old_element == element) new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] : button == 2 ? rotatable_elements_4[i][0] : button == 3 ? rotatable_elements_4[i][(j + 1) % 4] : old_element); } } for (i = 0; rotatable_elements_8[i][0] != -1; i++) { for (j = 0; j < 8; j++) { int element = rotatable_elements_8[i][j]; if (old_element == element) new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] : button == 2 ? rotatable_elements_8[i][0] : button == 3 ? rotatable_elements_8[i][(j + 1) % 8] : old_element); } } for (i = 0; rotatable_elements_16[i][0] != -1; i++) { for (j = 0; j < 16; j++) { int element = rotatable_elements_16[i][j]; if (old_element == element) new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] : button == 2 ? rotatable_elements_16[i][0] : button == 3 ? rotatable_elements_16[i][(j + 1) % 16] : old_element); } } if (old_element != new_element) { int max_infotext_len = getMaxInfoTextLength(); char infotext[MAX_OUTPUT_LINESIZE + 1]; strncpy(infotext, getElementInfoText(new_element), max_infotext_len); infotext[max_infotext_len] = '\0'; ClearEditorGadgetInfoText(); DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext); } } SetElementSimple(x, y, new_element, change_level); last_x = x; last_y = y; } static void ResetIntelliDraw() { int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) IntelliDrawBuffer[x][y] = Feld[x][y]; SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1); } static boolean draw_mode_hires = FALSE; static void SetDrawModeHiRes(int element) { draw_mode_hires = (level.game_engine_type == GAME_ENGINE_TYPE_MM && (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY)); } static boolean getDrawModeHiRes() { return draw_mode_hires; } static int getLoResScreenPos(int pos) { return (getDrawModeHiRes() ? pos / 2 : pos); } static int getLoResScreenMod(int pos) { return (getDrawModeHiRes() ? pos % 2 : 0); } static void SetElementExt(int x, int y, int dx, int dy, int element, boolean change_level, int button) { if (element < 0) SetElementSimple(x, y, Feld[x][y], change_level); else if (GetKeyModState() & KMOD_Shift && !IS_MM_WALL_EDITOR(element)) SetElementIntelliDraw(x, y, element, change_level, button); else SetElementSimpleExt(x, y, dx, dy, element, change_level); } static void SetElement(int x, int y, int element) { SetElementExt(x, y, 0, 0, element, TRUE, -1); } static void SetElementButton(int x, int y, int dx, int dy, int element, int button) { SetElementExt(x, y, dx, dy, element, TRUE, button); } static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level) { int lx = getLoResScreenPos(sx2) + level_xpos; int ly = getLoResScreenPos(sy2) + level_ypos; int dx = getLoResScreenMod(sx2); int dy = getLoResScreenMod(sy2); SetElementExt(lx, ly, dx, dy, element, change_level, -1); } static void SetLevelElementHiRes(int lx2, int ly2, int element) { int lx = lx2 / 2; int ly = ly2 / 2; int dx = lx2 % 2; int dy = ly2 % 2; SetElementExt(lx, ly, dx, dy, element, TRUE, -1); } static int getLevelElementHiRes(int lx2, int ly2) { int lx = lx2 / 2; int ly = ly2 / 2; int dx = lx2 % 2; int dy = ly2 % 2; int element = Feld[lx][ly]; unsigned int bitmask = (dx + 1) << (dy * 2); if (IS_MM_WALL(element)) { if (element & bitmask) return map_mm_wall_element(element); else return EL_EMPTY; } return element; } static void DrawLineElement(int x, int y, int element, boolean change_level) { SetElementHiRes(x, y, element, change_level); } static void DrawLine(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int xsize = ABS(to_x - from_x); int ysize = ABS(to_y - from_y); int dx = (to_x < from_x ? -1 : +1); int dy = (to_y < from_y ? -1 : +1); int i; if (from_y == to_y) /* horizontal line */ { for (i = 0; i <= xsize; i++) DrawLineElement(from_x + i * dx, from_y, element, change_level); } else if (from_x == to_x) /* vertical line */ { for (i = 0; i <= ysize; i++) DrawLineElement(from_x, from_y + i * dy, element, change_level); } else /* diagonal line */ { if (ysize < xsize) /* a < 1 */ { float a = (float)ysize / (float)xsize; for (i = 0; i <= xsize; i++) { int x = dx * i; int y = dy * (int)(a * i + 0.5); DrawLineElement(from_x + x, from_y + y, element, change_level); } } else /* a >= 1 */ { float a = (float)xsize / (float)ysize; for (i = 0; i <= ysize; i++) { int x = dx * (int)(a * i + 0.5); int y = dy * i; DrawLineElement(from_x + x, from_y + y, element, change_level); } } } } static void DrawBox(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { DrawLine(from_x, from_y, from_x, to_y, element, change_level); DrawLine(from_x, to_y, to_x, to_y, element, change_level); DrawLine(to_x, to_y, to_x, from_y, element, change_level); DrawLine(to_x, from_y, from_x, from_y, element, change_level); } static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int y; if (from_y > to_y) swap_number_pairs(&from_x, &from_y, &to_x, &to_y); for (y = from_y; y <= to_y; y++) DrawLine(from_x, y, to_x, y, element, change_level); } static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2, int element, boolean change_level) { int to_x = to_x2 - (to_x2 > from_x ? +1 : -1); int to_y = to_y2 - (to_y2 > from_y ? +1 : -1); int len_x = ABS(to_x - from_x); int len_y = ABS(to_y - from_y); int radius, x, y; radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5); /* not optimal (some points get drawn twice) but simple, and fast enough for the few points we are drawing */ for (x = 0; x <= radius; x++) { int sx, sy, sx2, sy2, lx, ly; y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5); sx2 = from_x + x * (from_x < to_x2 ? +1 : -1); sy2 = from_y + y * (from_y < to_y2 ? +1 : -1); sx = getLoResScreenPos(sx2); sy = getLoResScreenPos(sy2); lx = sx + level_xpos; ly = sy + level_ypos; if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) DrawLineElement(sx2, sy2, element, change_level); } for (y = 0; y <= radius; y++) { int sx, sy, sx2, sy2, lx, ly; x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5); sx2 = from_x + x * (from_x < to_x2 ? +1 : -1); sy2 = from_y + y * (from_y < to_y2 ? +1 : -1); sx = getLoResScreenPos(sx2); sy = getLoResScreenPos(sy2); lx = sx + level_xpos; ly = sy + level_ypos; if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) DrawLineElement(sx2, sy2, element, change_level); } } static void DrawArc(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int to_x2 = to_x + (to_x < from_x ? -1 : +1); int to_y2 = to_y + (to_y > from_y ? +1 : -1); DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level); } #define DRAW_CIRCLES_BUTTON_AVAILABLE 0 #if DRAW_CIRCLES_BUTTON_AVAILABLE static void DrawCircle(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { int to_x2 = to_x + (to_x < from_x ? -1 : +1); int to_y2 = to_y + (to_y > from_y ? +1 : -1); int mirror_to_x2 = from_x - (to_x2 - from_x); int mirror_to_y2 = from_y - (to_y2 - from_y); DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level); DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level); DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level); DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level); } #endif static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y) { int from_sx, from_sy; int to_sx, to_sy; if (from_x > to_x) swap_numbers(&from_x, &to_x); if (from_y > to_y) swap_numbers(&from_y, &to_y); from_sx = SX + from_x * ed_tilesize; from_sy = SY + from_y * ed_tilesize; to_sx = SX + (to_x + 1) * ed_tilesize - 1; to_sy = SY + (to_y + 1) * ed_tilesize - 1; DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy); DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy); DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy); DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy); if (from_x == to_x && from_y == to_y) MarkTileDirty(from_x/2, from_y/2); else redraw_mask |= REDRAW_FIELD; } static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { DrawBox(from_x, from_y, to_x, to_y, element, change_level); } static void SelectArea(int from_x, int from_y, int to_x, int to_y, int element, boolean change_level) { if (element == -1 || change_level) DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE); else DrawAreaBorder(from_x, from_y, to_x, to_y); } /* values for CopyBrushExt() */ #define CB_AREA_TO_BRUSH 0 #define CB_BRUSH_TO_CURSOR 1 #define CB_BRUSH_TO_LEVEL 2 #define CB_DELETE_OLD_CURSOR 3 #define CB_DUMP_BRUSH 4 #define CB_DUMP_BRUSH_SMALL 5 static void DrawBrushElement(int sx, int sy, int element, boolean change_level) { DrawLineElement(sx, sy, element, change_level); } static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, int button, int mode) { static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; static int brush_width, brush_height; static int last_cursor_x = -1, last_cursor_y = -1; static boolean delete_old_brush; int new_element = BUTTON_ELEMENT(button); int x, y; if (mode == CB_DUMP_BRUSH || mode == CB_DUMP_BRUSH_SMALL) { if (!draw_with_brush) { Error(ERR_WARN, "no brush selected"); return; } for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width; x++) { int element = brush_buffer[x][y]; int element_mapped = element; if (IS_CUSTOM_ELEMENT(element)) element_mapped = EL_CUSTOM_START; else if (IS_GROUP_ELEMENT(element)) element_mapped = EL_GROUP_START; else if (element >= NUM_FILE_ELEMENTS) element_mapped = EL_UNKNOWN; // dump brush as level sketch text for the R'n'D forum: // - large tiles: `xxx (0x60 ASCII) // - small tiles: ¸xxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8) printf("%s%03d", (mode == CB_DUMP_BRUSH ? "`" : "¸"), element_mapped); } printf("\n"); } return; } if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush) return; if (mode == CB_AREA_TO_BRUSH) { int from_lx, from_ly; if (from_x > to_x) swap_numbers(&from_x, &to_x); if (from_y > to_y) swap_numbers(&from_y, &to_y); brush_width = to_x - from_x + 1; brush_height = to_y - from_y + 1; from_lx = from_x + level_xpos; from_ly = from_y + level_ypos; for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width; x++) { brush_buffer[x][y] = Feld[from_lx + x][from_ly + y]; if (button != 1) DrawBrushElement(from_x + x, from_y + y, new_element, TRUE); } } if (button != 1) CopyLevelToUndoBuffer(UNDO_IMMEDIATE); delete_old_brush = FALSE; } else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR || mode == CB_BRUSH_TO_LEVEL) { int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x); int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y); int cursor_from_x = cursor_x - brush_width / 2; int cursor_from_y = cursor_y - brush_height / 2; int border_from_x = cursor_x, border_from_y = cursor_y; int border_to_x = cursor_x, border_to_y = cursor_y; if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush) CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR); if (!IN_ED_FIELD(cursor_x, cursor_y) || !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos)) { delete_old_brush = FALSE; return; } for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width; x++) { int sx = cursor_from_x + x; int sy = cursor_from_y + y; int lx = sx + level_xpos; int ly = sy + level_ypos; boolean change_level = (mode == CB_BRUSH_TO_LEVEL); int element = (mode == CB_DELETE_OLD_CURSOR ? -1 : mode == CB_BRUSH_TO_CURSOR || button == 1 ? brush_buffer[x][y] : new_element); if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) { if (sx < border_from_x) border_from_x = sx; else if (sx > border_to_x) border_to_x = sx; if (sy < border_from_y) border_from_y = sy; else if (sy > border_to_y) border_to_y = sy; DrawBrushElement(sx, sy, element, change_level); } } } if (mode != CB_DELETE_OLD_CURSOR) DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y); last_cursor_x = cursor_x; last_cursor_y = cursor_y; delete_old_brush = TRUE; } } static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y, int button) { CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH); } static void CopyBrushToLevel(int x, int y, int button) { CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL); } static void CopyBrushToCursor(int x, int y) { CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR); } static void DeleteBrushFromCursor() { CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR); } void DumpBrush() { CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH); } void DumpBrush_Small() { CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL); } static void FloodFill(int from_x, int from_y, int fill_element) { FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy); } static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element) { int from_x = from_sx2 + 2 * level_xpos; int from_y = from_sy2 + 2 * level_ypos; int max_fillx = lev_fieldx * 2; int max_filly = lev_fieldy * 2; short FillFeld[max_fillx][max_filly]; int x, y; for (x = 0; x < max_fillx; x++) for (y = 0; y < max_filly; y++) FillFeld[x][y] = getLevelElementHiRes(x, y); FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly, FillFeld, max_fillx, max_filly); for (x = 0; x < max_fillx; x++) for (y = 0; y < max_filly; y++) if (FillFeld[x][y] == fill_element) SetLevelElementHiRes(x, y, FillFeld[x][y]); } /* values for DrawLevelText() modes */ #define TEXT_INIT 0 #define TEXT_SETCURSOR 1 #define TEXT_WRITECHAR 2 #define TEXT_BACKSPACE 3 #define TEXT_NEWLINE 4 #define TEXT_END 5 #define TEXT_QUERY_TYPING 6 static int DrawLevelText(int sx, int sy, char letter, int mode) { static short delete_buffer[MAX_LEV_FIELDX]; static int start_sx; static int last_sx, last_sy; static boolean typing = FALSE; int letter_element = EL_CHAR_ASCII0 + letter; int lx = 0, ly = 0; /* map lower case letters to upper case and convert special characters */ if (letter >= 'a' && letter <= 'z') letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a'); else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A) letter_element = EL_CHAR_AUMLAUT; else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O) letter_element = EL_CHAR_OUMLAUT; else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U) letter_element = EL_CHAR_UUMLAUT; else if (letter == '^') letter_element = EL_CHAR_COPYRIGHT; else letter_element = EL_CHAR_ASCII0 + letter; if (mode != TEXT_INIT) { if (!typing) return FALSE; if (mode != TEXT_SETCURSOR) { sx = last_sx; sy = last_sy; } lx = last_sx + level_xpos; ly = last_sy + level_ypos; } switch (mode) { case TEXT_INIT: if (typing) DrawLevelText(0, 0, 0, TEXT_END); typing = TRUE; start_sx = sx; last_sx = sx; last_sy = sy; DrawLevelText(sx, sy, 0, TEXT_SETCURSOR); break; case TEXT_SETCURSOR: DrawEditorElement(last_sx, last_sy, Feld[lx][ly]); DrawAreaBorder(sx, sy, sx, sy); last_sx = sx; last_sy = sy; break; case TEXT_WRITECHAR: if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END) { if (new_element1 >= EL_STEEL_CHAR_START && new_element1 <= EL_STEEL_CHAR_END) letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START; delete_buffer[sx - start_sx] = Feld[lx][ly]; Feld[lx][ly] = letter_element; if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx) DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR); else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy) DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR); else DrawLevelText(0, 0, 0, TEXT_END); level.changed = TRUE; } break; case TEXT_BACKSPACE: if (sx > start_sx) { Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1]; DrawEditorElement(sx - 1, sy, Feld[lx - 1][ly]); DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR); } break; case TEXT_NEWLINE: if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1) DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR); else DrawLevelText(0, 0, 0, TEXT_END); break; case TEXT_END: CopyLevelToUndoBuffer(UNDO_IMMEDIATE); DrawEditorElement(sx, sy, Feld[lx][ly]); typing = FALSE; break; case TEXT_QUERY_TYPING: break; default: break; } return typing; } static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy, int element, boolean change_level) { int lx = sx + level_xpos; int ly = sy + level_ypos; if (element == -1) DrawEditorElement(sx, sy, Feld[lx][ly]); else DrawAreaBorder(sx, sy, sx, sy); } static void CheckLevelBorderElement(boolean redraw_playfield) { int last_border_element = BorderElement; SetBorderElement(); if (redraw_playfield && BorderElement != last_border_element) DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); } static void CopyLevelToUndoBuffer(int mode) { static boolean accumulated_undo = FALSE; boolean new_undo_buffer_position = TRUE; int x, y; if (undo_buffer_steps == 0) accumulated_undo = FALSE; switch (mode) { case UNDO_IMMEDIATE: accumulated_undo = FALSE; break; case UNDO_ACCUMULATE: if (accumulated_undo) new_undo_buffer_position = FALSE; accumulated_undo = TRUE; break; default: break; } if (new_undo_buffer_position) { /* advance position in undo buffer ring */ undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS; if (undo_buffer_steps < NUM_UNDO_STEPS - 1) undo_buffer_steps++; } /* always reset redo buffer when storing level change into undo buffer */ redo_buffer_steps = 0; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) UndoBuffer[undo_buffer_position][x][y] = Feld[x][y]; /* check if drawing operation forces change of border style */ CheckLevelBorderElement(TRUE); level.changed = TRUE; } static void RandomPlacement(int new_element) { static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int num_free_positions = 0; int num_percentage, num_elements; int x, y; ResetIntelliDraw(); /* determine number of free positions for randomly placing the new element */ for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) { free_position[x][y] = (random_placement_background_restricted ? Feld[x][y] == random_placement_background_element : Feld[x][y] != new_element); if (free_position[x][y]) num_free_positions++; } /* determine number of new elements to place there */ num_percentage = num_free_positions * random_placement_value / 100; num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ? num_percentage : random_placement_value); /* if less free positions than elements to place, fill all these positions */ if (num_free_positions < num_elements) { for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) if (free_position[x][y]) SetElement(x, y, new_element); } else { while (num_elements > 0) { x = GetSimpleRandom(lev_fieldx); y = GetSimpleRandom(lev_fieldy); /* don't place element at the same position twice */ if (free_position[x][y]) { free_position[x][y] = FALSE; SetElement(x, y, new_element); num_elements--; } } } DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } void WrapLevel(int dx, int dy) { int wrap_dx = lev_fieldx - dx; int wrap_dy = lev_fieldy - dy; int x, y; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) FieldBackup[x][y] = Feld[x][y]; for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) Feld[x][y] = FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy]; DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); CopyLevelToUndoBuffer(UNDO_ACCUMULATE); } static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir) { char *template_filename_old = getLocalLevelTemplateFilename(); char *template_filename_new = getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME); if (copyFile(template_filename_old, template_filename_new) != 0) Request("Cannot copy level template!", REQ_CONFIRM); free(template_filename_new); } static void HandleDrawingAreas(struct GadgetInfo *gi) { static boolean started_inside_drawing_area = FALSE; static int last_sx = -1, last_sy = -1; static int last_sx2 = -1, last_sy2 = -1; int id = gi->custom_id; int type_id = gi->custom_type_id; boolean button_press_event; boolean button_release_event; boolean inside_drawing_area = !gi->event.off_borders; boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL); int actual_drawing_function; int button = gi->event.button; int new_element = BUTTON_ELEMENT(button); int sx = gi->event.x, sy = gi->event.y; int min_sx = 0, min_sy = 0; int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1; int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize; int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2; int sx2 = gi->event.mx / mini_item_xsize; int sy2 = gi->event.my / mini_item_ysize; int dx = sx2 % 2; int dy = sy2 % 2; int lx = 0, ly = 0; int min_lx = 0, min_ly = 0; int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1; int x, y; button_press_event = (gi->event.type == GD_EVENT_PRESSED); button_release_event = (gi->event.type == GD_EVENT_RELEASED); /* make sure to stay inside drawing area boundaries */ sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx); sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy); if (draw_level) { /* get positions inside level field */ lx = sx + level_xpos; ly = sy + level_ypos; if (!IN_LEV_FIELD(lx, ly)) inside_drawing_area = FALSE; /* make sure to stay inside level field boundaries */ lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx); ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly); /* correct drawing area positions accordingly */ sx = lx - level_xpos; sy = ly - level_ypos; } /* also correct MM wall-sized (double) drawing area positions accordingly */ if (sx2 / 2 < sx || sx2 / 2 > sx) { dx = (sx2 / 2 < sx ? 0 : 1); sx2 = sx * 2 + dx; } if (sy2 / 2 < sy || sy2 / 2 > sy) { dy = (sy2 / 2 < sy ? 0 : 1); sy2 = sy * 2 + dy; } if (button_release_event) { last_sx = -1; last_sy = -1; last_sx2 = -1; last_sy2 = -1; } else if (!button_press_event) { /* prevent handling events for every pixel position when moving mouse */ if ((sx == last_sx && sy == last_sy && !IS_MM_WALL_EDITOR(new_element) && new_element != EL_EMPTY) || (sx2 == last_sx2 && sy2 == last_sy2)) return; } last_sx = sx; last_sy = sy; last_sx2 = sx2; last_sy2 = sy2; if (button_press_event) started_inside_drawing_area = inside_drawing_area; if (!started_inside_drawing_area) return; if (!IS_VALID_BUTTON(button)) return; if (!button && !button_release_event) return; /* handle info callback for each invocation of action callback */ gi->callback_info(gi); /* automatically switch to 'single item' drawing mode, if needed */ actual_drawing_function = (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ? drawing_function : GADGET_ID_SINGLE_ITEMS); /* clicking into drawing area with pressed Control key picks element */ if (GetKeyModState() & KMOD_Control) { last_drawing_function = drawing_function; actual_drawing_function = GADGET_ID_PICK_ELEMENT; } if (GetKeyModState() & KMOD_Shift) { if (button_press_event || button_release_event) ResetIntelliDraw(); } SetDrawModeHiRes(-1); /* reset to normal draw mode */ switch (actual_drawing_function) { case GADGET_ID_SINGLE_ITEMS: if (draw_level) { if (button_release_event) { CopyLevelToUndoBuffer(UNDO_IMMEDIATE); if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !inside_drawing_area) DeleteBrushFromCursor(); } if (!button || button_release_event) break; if (draw_with_brush) { CopyBrushToLevel(sx, sy, button); } else { SetDrawModeHiRes(new_element); if (new_element == EL_PLAYER_1) { /* remove player at old position */ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) if (Feld[x][y] == EL_PLAYER_1) SetElement(x, y, EL_EMPTY); } SetElementButton(lx, ly, dx, dy, new_element, button); } } else if (!button_release_event) { int pos = sx * drawingarea_info[type_id].area_ysize + sy; if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY) DrawMiniGraphicExt(drawto, gi->x + sx * MINI_TILEX, gi->y + sy * MINI_TILEY, el2edimg(new_element)); else DrawFixedGraphicExt(drawto, gi->x + sx * TILEX, gi->y + sy * TILEY, el2edimg(new_element), 0); if (id == GADGET_ID_CUSTOM_GRAPHIC) new_element = GFX_ELEMENT(new_element); drawingarea_info[type_id].value[pos] = new_element; CopyElementPropertiesToGame(properties_element); if (id == GADGET_ID_CUSTOM_GRAPHIC) { UpdateCustomElementGraphicGadgets(); FrameCounter = 0; /* restart animation frame counter */ } } break; case GADGET_ID_CONNECTED_ITEMS: { static int last_sx = -1; static int last_sy = -1; if (button_release_event) CopyLevelToUndoBuffer(UNDO_IMMEDIATE); if (button) { SetDrawModeHiRes(new_element); if (getDrawModeHiRes()) { sx = sx2; sy = sy2; } if (!button_press_event) DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE); last_sx = sx; last_sy = sy; } } break; case GADGET_ID_LINE: case GADGET_ID_ARC: case GADGET_ID_RECTANGLE: case GADGET_ID_FILLED_BOX: SetDrawModeHiRes(new_element); if (getDrawModeHiRes()) { sx = sx2; sy = sy2; } /* FALLTHROUGH */ case GADGET_ID_GRAB_BRUSH: case GADGET_ID_TEXT: { static int last_sx = -1; static int last_sy = -1; static int start_sx = -1; static int start_sy = -1; void (*draw_func)(int, int, int, int, int, boolean); if (drawing_function == GADGET_ID_LINE) draw_func = DrawLine; else if (drawing_function == GADGET_ID_ARC) draw_func = DrawArc; else if (drawing_function == GADGET_ID_RECTANGLE) draw_func = DrawBox; else if (drawing_function == GADGET_ID_FILLED_BOX) draw_func = DrawFilledBox; else if (drawing_function == GADGET_ID_GRAB_BRUSH) draw_func = SelectArea; else /* (drawing_function == GADGET_ID_TEXT) */ draw_func = SetTextCursor; if (button_press_event) { draw_func(sx, sy, sx, sy, new_element, FALSE); start_sx = last_sx = sx; start_sy = last_sy = sy; if (drawing_function == GADGET_ID_TEXT) DrawLevelText(0, 0, 0, TEXT_END); } else if (button_release_event) { draw_func(start_sx, start_sy, sx, sy, new_element, TRUE); if (drawing_function == GADGET_ID_GRAB_BRUSH) { CopyAreaToBrush(start_sx, start_sy, sx, sy, button); CopyBrushToCursor(sx, sy); ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON); draw_with_brush = TRUE; } else if (drawing_function == GADGET_ID_TEXT) DrawLevelText(sx, sy, 0, TEXT_INIT); else CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } else if (last_sx != sx || last_sy != sy) { draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE); if (IS_MM_WALL_EDITOR(new_element)) /* clear wall background */ draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE); draw_func(start_sx, start_sy, sx, sy, new_element, FALSE); last_sx = sx; last_sy = sy; } } break; case GADGET_ID_FLOOD_FILL: if (button_press_event && Feld[lx][ly] != new_element) { if (IS_MM_WALL_EDITOR(new_element)) FloodFillWall_MM(sx2, sy2, new_element); else FloodFill(lx, ly, new_element); DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); CopyLevelToUndoBuffer(UNDO_IMMEDIATE); } break; case GADGET_ID_PICK_ELEMENT: if (button_release_event) ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFTBUTTON); else if (draw_level) PickDrawingElement(button, Feld[lx][ly]); else { int pos = sx * drawingarea_info[type_id].area_ysize + sy; PickDrawingElement(button, drawingarea_info[type_id].value[pos]); } default: break; } /* do not mark level as modified for certain non-level-changing gadgets */ if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST && type_id <= ED_DRAWING_ID_EDITOR_LAST) || actual_drawing_function == GADGET_ID_GRAB_BRUSH || actual_drawing_function == GADGET_ID_PICK_ELEMENT) return; level.changed = TRUE; } static void HandleCounterButtons(struct GadgetInfo *gi) { int gadget_id = gi->custom_id; int counter_id = gi->custom_type_id; int button = gi->event.button; int *counter_value = counterbutton_info[counter_id].value; int step = BUTTON_STEPSIZE(button) * (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1); if (counter_id == ED_COUNTER_ID_SELECT_LEVEL) { boolean pressed = (gi->event.type == GD_EVENT_PRESSED); boolean released = (gi->event.type == GD_EVENT_RELEASED); boolean level_changed = LevelChanged(); if ((level_changed && pressed) || (!level_changed && released)) return; if (level_changed && !Request("Level has changed! Discard changes?", REQ_ASK)) { if (gadget_id == counterbutton_info[counter_id].gadget_id_text) ModifyEditorCounterValue(counter_id, *counter_value); return; } } if (gadget_id == counterbutton_info[counter_id].gadget_id_text) *counter_value = gi->textinput.number_value; else ModifyEditorCounterValue(counter_id, *counter_value + step); if (counter_id == ED_COUNTER_ID_SELECT_LEVEL) { int last_game_engine_type = level.game_engine_type; LoadLevel(level_nr); LoadScore(level_nr); SaveLevelSetup_SeriesInfo(); TapeErase(); ResetUndoBuffer(); DrawEditModeWindow(); if (level.game_engine_type != last_game_engine_type) { /* update element selection list */ ReinitializeElementList(); ModifyEditorElementList(); } return; } switch (counter_id) { case ED_COUNTER_ID_YAMYAM_CONTENT: DrawYamYamContentAreas(); break; case ED_COUNTER_ID_BALL_CONTENT: DrawMagicBallContentAreas(); break; case ED_COUNTER_ID_ANDROID_CONTENT: DrawAndroidElementArea(properties_element); break; case ED_COUNTER_ID_GROUP_CONTENT: DrawGroupElementArea(properties_element); CopyGroupElementPropertiesToGame(properties_element); break; case ED_COUNTER_ID_INVENTORY_SIZE: DrawPlayerInitialInventoryArea(properties_element); break; case ED_COUNTER_ID_ENVELOPE_XSIZE: case ED_COUNTER_ID_ENVELOPE_YSIZE: DrawEnvelopeTextArea(-1); break; case ED_COUNTER_ID_LEVEL_XSIZE: case ED_COUNTER_ID_LEVEL_YSIZE: lev_fieldx = level.fieldx; lev_fieldy = level.fieldy; /* check if resizing of level results in change of border border */ SetBorderElement(); break; default: break; } if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST && counter_id <= ED_COUNTER_ID_CUSTOM_LAST) || (counter_id >= ED_COUNTER_ID_CHANGE_FIRST && counter_id <= ED_COUNTER_ID_CHANGE_LAST)) CopyElementPropertiesToGame(properties_element); /* do not mark level as modified for certain non-level-changing gadgets */ if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST && counter_id <= ED_COUNTER_ID_LEVELSET_LAST) || (counter_id >= ED_COUNTER_ID_EDITOR_FIRST && counter_id <= ED_COUNTER_ID_EDITOR_LAST)) return; level.changed = TRUE; } static void HandleTextInputGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; strcpy(textinput_info[type_id].value, gi->textinput.value); if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME) { CopyElementPropertiesToGame(properties_element); ModifyEditorElementList(); /* update changed button info text */ } /* do not mark level as modified for certain non-level-changing gadgets */ if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST && type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST) return; level.changed = TRUE; } static void HandleTextAreaGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; strncpy(textarea_info[type_id].value, gi->textarea.value, MAX_ENVELOPE_TEXT_LEN); textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0'; level.changed = TRUE; } static void HandleSelectboxGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; int value_old = *selectbox_info[type_id].value; int value_new = selectbox_info[type_id].options[gi->selectbox.index].value; *selectbox_info[type_id].value = value_new; if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE) { DrawLevelInfoWindow(); } else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE) { element_info[properties_element].current_change_page = gi->selectbox.index; DrawPropertiesWindow(); } else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST && type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) || (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST && type_id <= ED_SELECTBOX_ID_CHANGE_LAST) || (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE)) { if (type_id == ED_SELECTBOX_ID_ACTION_TYPE) { /* when changing action type, also check action mode and action arg */ if (value_old != value_new) setSelectboxSpecialActionVariablesIfNeeded(); DrawPropertiesChange(); } CopyElementPropertiesToGame(properties_element); } else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE) { /* update element selection list */ ReinitializeElementList(); ModifyEditorElementList(); } /* do not mark level as modified for certain non-level-changing gadgets */ if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE || type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE) return; level.changed = TRUE; } static void HandleTextbuttonGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; int i; if (type_id >= ED_TAB_BUTTON_ID_LEVELINFO_FIRST && type_id <= ED_TAB_BUTTON_ID_LEVELINFO_LAST) { edit_mode_levelinfo = gi->custom_type_id; DrawLevelInfoWindow(); } else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST && type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST) { edit_mode_properties = gi->custom_type_id; DrawPropertiesWindow(); } else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 || type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2) { boolean new_template = !fileExists(getLocalLevelTemplateFilename()); /* backup original "level.field" (needed to track playfield changes) */ CopyPlayfield(level.field, FieldBackup); /* "SaveLevelTemplate()" uses "level.field", so copy editor playfield */ CopyPlayfield(Feld, level.field); if (new_template || Request("Save this template and kill the old?", REQ_ASK)) SaveLevelTemplate(); if (new_template) Request("Template saved!", REQ_CONFIRM); /* restore original "level.field" (needed to track playfield changes) */ CopyPlayfield(FieldBackup, level.field); } else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET) { char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode); if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE && leveldir_current->readonly) { Request("This level set is read only!", REQ_CONFIRM); return; } if (strEqual(levelset_name, "")) { Request("Please enter level set title!", REQ_CONFIRM); return; } if (strEqual(levelset_author, "")) { Request("Please enter level set author!", REQ_CONFIRM); return; } if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE) { if (UpdateUserLevelSet(levelset_subdir, levelset_name, levelset_author, levelset_num_levels)) { Request("Level set updated!", REQ_CONFIRM); } else { Request("Updating level set failed!", REQ_CONFIRM); } } else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE) { if (level.changed && !Request("Level has changed! Discard changes?", REQ_ASK)) return; if (CreateUserLevelSet(levelset_subdir, levelset_name, levelset_author, levelset_num_levels, levelset_use_levelset_artwork)) { if (levelset_copy_level_template) CopyLevelTemplateToUserLevelSet(levelset_subdir); Request("New level set created!", REQ_CONFIRM); AddUserLevelSetToLevelInfo(levelset_subdir); ChangeEditorToLevelSet(levelset_subdir); } else { Request("Creating new level set failed!", REQ_CONFIRM); } } } else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE && custom_element.num_change_pages < MAX_CHANGE_PAGES) { struct ElementInfo *ei = &element_info[properties_element]; /* when modifying custom element, ask for copying level template */ if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate()) return; setElementChangePages(ei, ei->num_change_pages + 1); /* set new change page to be new current change page */ ei->current_change_page = ei->num_change_pages - 1; ei->change = &ei->change_page[ei->current_change_page]; setElementChangeInfoToDefaults(ei->change); DrawPropertiesWindow(); level.changed = TRUE; } else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE && custom_element.num_change_pages > MIN_CHANGE_PAGES) { struct ElementInfo *ei = &element_info[properties_element]; /* when modifying custom element, ask for copying level template */ if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate()) return; /* copy all change pages after change page to be deleted */ for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++) ei->change_page[i] = ei->change_page[i + 1]; setElementChangePages(ei, ei->num_change_pages - 1); DrawPropertiesWindow(); level.changed = TRUE; } } static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE || type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE) { struct ElementInfo *ei = &element_info[properties_element]; int step = BUTTON_STEPSIZE(gi->event.button); step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1); ei->current_change_page += step; if (ei->current_change_page < 0) ei->current_change_page = 0; else if (ei->current_change_page >= ei->num_change_pages) ei->current_change_page = ei->num_change_pages - 1; DrawPropertiesWindow(); } else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE || type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) { struct ElementInfo *ei = &element_info[properties_element]; int current_change_page = ei->current_change_page; if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE) { element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] = ei->change_page[current_change_page]; } else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) { /* when modifying custom element, ask for copying level template */ if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate()) return; ei->change_page[current_change_page] = element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0]; level.changed = TRUE; } DrawPropertiesWindow(); } } static void HandleRadiobuttons(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; *radiobutton_info[type_id].value = radiobutton_info[type_id].checked_value; /* do not mark level as modified for certain non-level-changing gadgets */ if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST && type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST) return; level.changed = TRUE; } static void HandleCheckbuttons(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; *checkbutton_info[type_id].value ^= TRUE; if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID || type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID || type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH || (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST && type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) || (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST && type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) && type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1)) { CopyElementPropertiesToGame(properties_element); } if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC) { UpdateCustomElementGraphicGadgets(); } else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 || type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) { boolean template_related_changes_found = FALSE; int i; /* check if any custom or group elements have been changed */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) if ((IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)) && element_info[i].modified_settings) template_related_changes_found = TRUE; if (level.use_custom_template && !fileExists(getGlobalLevelTemplateFilename())) { Request("No level template found!", REQ_CONFIRM); level.use_custom_template = FALSE; ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END); return; } if (level.use_custom_template && template_related_changes_found && !Request("Discard changes and use level template?", REQ_ASK)) { level.use_custom_template = FALSE; ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END); return; } if (!level.use_custom_template && Request("Copy settings from level template?", REQ_ASK)) { return; } LoadLevelTemplate(level.use_custom_template ? -1 : level_nr); DrawEditModeWindow(); } else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3) { if (setup.editor.use_template_for_new_levels && !fileExists(getGlobalLevelTemplateFilename())) { Request("No level template found!", REQ_CONFIRM); return; } if (setup.editor.use_template_for_new_levels && level.changed && !Request("Discard level and load template?", REQ_ASK)) { return; } if (!setup.editor.use_template_for_new_levels && level.changed && !Request("Discard level and use empty level?", REQ_ASK)) { return; } LoadLevel(level_nr); LoadScore(level_nr); TapeErase(); ResetUndoBuffer(); DrawEditModeWindow(); } else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS) { SetAutomaticNumberOfGemsNeeded(); } /* do not mark level as modified for certain non-level-changing gadgets */ if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST && type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) || (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST && type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST) || type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT) return; level.changed = TRUE; } static void HandleControlButtons(struct GadgetInfo *gi) { static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS; static int last_edit_mode = ED_MODE_DRAWING; static int last_custom_copy_mode = -1; static int last_button = 0; int id = gi->custom_id; int button = gi->event.button; int step = BUTTON_STEPSIZE(button); int new_element = BUTTON_ELEMENT(button); int last_properties_element = properties_element; int x, y; if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT) DrawLevelText(0, 0, 0, TEXT_END); if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_SINGLE_ITEMS && id != GADGET_ID_PICK_ELEMENT && edit_mode != ED_MODE_DRAWING && drawing_function != GADGET_ID_PICK_ELEMENT && !(GetKeyModState() & KMOD_Control)) ChangeEditModeWindow(ED_MODE_DRAWING); /* element copy mode active, but no element button pressed => deactivate */ if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS) last_custom_copy_mode = -1; /* when showing palette on element buttons, change element of button used */ if (editor.palette.show_on_element_buttons && id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT) { last_button = id - GADGET_ID_ELEMENT_LEFT + 1; id = GADGET_ID_PALETTE; } switch (id) { case GADGET_ID_SCROLL_LEFT: if (level_xpos >= 0) { if (lev_fieldx < ed_fieldx - 2) break; level_xpos -= step; if (level_xpos < -1) level_xpos = -1; if (button == 1) ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT); else DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL], GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END); } break; case GADGET_ID_SCROLL_RIGHT: if (level_xpos <= lev_fieldx - ed_fieldx) { if (lev_fieldx < ed_fieldx - 2) break; level_xpos += step; if (level_xpos > lev_fieldx - ed_fieldx + 1) level_xpos = lev_fieldx - ed_fieldx + 1; if (button == 1) ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT); else DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL], GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END); } break; case GADGET_ID_SCROLL_UP: if (level_ypos >= 0) { if (lev_fieldy < ed_fieldy - 2) break; level_ypos -= step; if (level_ypos < -1) level_ypos = -1; if (button == 1) ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN); else DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END); } break; case GADGET_ID_SCROLL_DOWN: if (level_ypos <= lev_fieldy - ed_fieldy) { if (lev_fieldy < ed_fieldy - 2) break; level_ypos += step; if (level_ypos > lev_fieldy - ed_fieldy + 1) level_ypos = lev_fieldy - ed_fieldy + 1; if (button == 1) ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP); else DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END); } break; case GADGET_ID_SCROLL_HORIZONTAL: level_xpos = gi->event.item_position - 1; DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); BackToFront(); break; case GADGET_ID_SCROLL_VERTICAL: level_ypos = gi->event.item_position - 1; DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); BackToFront(); break; case GADGET_ID_SCROLL_LIST_UP: case GADGET_ID_SCROLL_LIST_DOWN: case GADGET_ID_SCROLL_LIST_VERTICAL: if (id == GADGET_ID_SCROLL_LIST_VERTICAL) element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ; else { step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1); element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ; if (element_shift < 0) element_shift = 0; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); } ModifyEditorElementList(); break; case GADGET_ID_PROPERTIES: // always switch off element properties when they are already displayed last_properties_element = new_element; case GADGET_ID_ELEMENT_LEFT: case GADGET_ID_ELEMENT_MIDDLE: case GADGET_ID_ELEMENT_RIGHT: properties_element = (id == GADGET_ID_ELEMENT_LEFT ? new_element1 : id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 : id == GADGET_ID_ELEMENT_RIGHT ? new_element3 : new_element); if (edit_mode != ED_MODE_PROPERTIES) { last_edit_mode = edit_mode; ChangeEditModeWindow(ED_MODE_PROPERTIES); last_level_drawing_function = drawing_function; ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON); } else if (properties_element != last_properties_element) { DrawEditModeWindow(); } else { ChangeEditModeWindow(last_edit_mode); ClickOnGadget(level_editor_gadget[last_level_drawing_function], MB_LEFTBUTTON); } break; case GADGET_ID_PALETTE: if (edit_mode != ED_MODE_PALETTE) { last_edit_mode = edit_mode; ChangeEditModeWindow(ED_MODE_PALETTE); } else { ChangeEditModeWindow(last_edit_mode); } break; case GADGET_ID_WRAP_LEFT: WrapLevel(-step, 0); break; case GADGET_ID_WRAP_RIGHT: WrapLevel(step, 0); break; case GADGET_ID_WRAP_UP: WrapLevel(0, -step); break; case GADGET_ID_WRAP_DOWN: WrapLevel(0, step); break; case GADGET_ID_SINGLE_ITEMS: case GADGET_ID_CONNECTED_ITEMS: case GADGET_ID_LINE: case GADGET_ID_ARC: case GADGET_ID_TEXT: case GADGET_ID_RECTANGLE: case GADGET_ID_FILLED_BOX: case GADGET_ID_FLOOD_FILL: case GADGET_ID_GRAB_BRUSH: case GADGET_ID_PICK_ELEMENT: if (drawing_function != GADGET_ID_PICK_ELEMENT) last_drawing_function = drawing_function; drawing_function = id; draw_with_brush = FALSE; break; case GADGET_ID_RANDOM_PLACEMENT: RandomPlacement(new_element); break; case GADGET_ID_ZOOM: // zoom level editor tile size in or out (or reset to default size) ed_tilesize = (button == 1 ? ed_tilesize * 2 : button == 2 ? ed_tilesize_default : button == 3 ? ed_tilesize / 2 : ed_tilesize); // limit zoom level by upper and lower bound ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE); InitZoomLevelSettings(ed_tilesize); if (edit_mode == ED_MODE_DRAWING) { DrawDrawingWindow(); /* redraw zoom gadget info text */ PrintEditorGadgetInfoText(level_editor_gadget[id]); } /* save current editor zoom tilesize */ SaveSetup_AutoSetup(); break; case GADGET_ID_CUSTOM_COPY_FROM: case GADGET_ID_CUSTOM_COPY_TO: case GADGET_ID_CUSTOM_EXCHANGE: last_custom_copy_mode = id; last_drawing_function = drawing_function; break; case GADGET_ID_CUSTOM_COPY: CopyCustomElement(properties_element, -1, id); break; case GADGET_ID_CUSTOM_PASTE: CopyCustomElement(-1, properties_element, id); break; case GADGET_ID_UNDO: if (button == 1 && GetKeyModState() & (KMOD_Shift|KMOD_Control)) button = 3; if (button == 1 && undo_buffer_steps == 0) { Request("Undo buffer empty!", REQ_CONFIRM); break; } else if (button == 2) { break; } else if (button == 3 && redo_buffer_steps == 0) { Request("Redo buffer empty!", REQ_CONFIRM); break; } if (edit_mode != ED_MODE_DRAWING) ChangeEditModeWindow(ED_MODE_DRAWING); if (button == 1) { /* undo */ undo_buffer_position = (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS; undo_buffer_steps--; redo_buffer_steps++; } else { /* redo */ undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS; undo_buffer_steps++; redo_buffer_steps--; } for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) Feld[x][y] = UndoBuffer[undo_buffer_position][x][y]; /* check if undo operation forces change of border style */ CheckLevelBorderElement(FALSE); DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); break; case GADGET_ID_INFO: if (edit_mode != ED_MODE_INFO) { last_edit_mode = edit_mode; ChangeEditModeWindow(ED_MODE_INFO); } else { ChangeEditModeWindow(last_edit_mode); } break; case GADGET_ID_CLEAR: if (edit_mode != ED_MODE_DRAWING) ChangeEditModeWindow(ED_MODE_DRAWING); for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) Feld[x][y] = (button == 1 ? EL_EMPTY : new_element); CopyLevelToUndoBuffer(GADGET_ID_CLEAR); DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos); break; case GADGET_ID_SAVE: { /* saving read-only levels into personal level set modifies global vars "leveldir_current" and "level_nr"; restore them after saving level */ LevelDirTree *leveldir_former = leveldir_current; int level_nr_former = level_nr; char *level_filename; boolean new_level; if (leveldir_current->readonly && !PrepareSavingIntoPersonalLevelSet()) break; level_filename = getDefaultLevelFilename(level_nr); new_level = !fileExists(level_filename); if (new_level || Request("Save this level and kill the old?", REQ_ASK)) { if (leveldir_former->readonly) ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name); SetAutomaticNumberOfGemsNeeded(); CopyPlayfield(Feld, level.field); SaveLevel(level_nr); level.changed = FALSE; if (new_level) { char level_saved_msg[64]; if (leveldir_former->readonly) sprintf(level_saved_msg, "Level saved as level %d into personal level set!", level_nr); else strcpy(level_saved_msg, "Level saved!"); Request(level_saved_msg, REQ_CONFIRM); } } /* "cd" back to copied-from levelset (in case of saved read-only level) */ leveldir_current = leveldir_former; level_nr = level_nr_former; break; } case GADGET_ID_TEST: if (LevelChanged()) level.game_version = GAME_VERSION_ACTUAL; CopyPlayfield(level.field, FieldBackup); CopyPlayfield(Feld, level.field); CopyNativeLevel_RND_to_Native(&level); UnmapLevelEditorGadgets(); UndrawSpecialEditorDoor(); CloseDoor(DOOR_CLOSE_ALL); /* needed before playing if editor playfield area has different size */ ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); // redraw_mask = REDRAW_ALL; level_editor_test_game = TRUE; StartGameActions(FALSE, setup.autorecord, level.random_seed); break; case GADGET_ID_EXIT: RequestExitLevelEditor(TRUE, FALSE); /* if level has changed, ask user */ break; default: if (id >= GADGET_ID_ELEMENTLIST_FIRST && id <= GADGET_ID_ELEMENTLIST_LAST) { int element_position = id - GADGET_ID_ELEMENTLIST_FIRST; int new_element = editor_elements[element_position + element_shift]; if (IS_EDITOR_CASCADE(new_element)) { int i; for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { int *cascade_element= &(*editor_elements_info[i].headline_list)[0]; boolean *cascade_value=editor_elements_info[i].setup_cascade_value; if (*cascade_element == new_element) { *cascade_element = EL_CASCADE_TOGGLE(*cascade_element); *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element); /* update element selection list */ ReinitializeElementList(); ModifyEditorElementList(); /* update cascading gadget info text */ PrintEditorGadgetInfoText(level_editor_gadget[id]); /* save current editor cascading state */ SaveSetup_EditorCascade(); break; } } break; } if (last_custom_copy_mode != -1) { if (CopyCustomElement(properties_element, new_element, last_custom_copy_mode)) { ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFTBUTTON); last_custom_copy_mode = -1; } break; } /* change element of button used to show palette */ if (editor.palette.show_on_element_buttons) button = last_button; PickDrawingElement(button, new_element); if (!stick_element_properties_window && drawing_function != GADGET_ID_PICK_ELEMENT && !(GetKeyModState() & KMOD_Control)) { properties_element = new_element; if (edit_mode == ED_MODE_PROPERTIES) DrawPropertiesWindow(); } if (drawing_function == GADGET_ID_PICK_ELEMENT) ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFTBUTTON); if (!use_permanent_palette) ChangeEditModeWindow(last_edit_mode); } #ifdef DEBUG else if (gi->event.type == GD_EVENT_PRESSED) printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id); else if (gi->event.type == GD_EVENT_RELEASED) printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id); else if (gi->event.type == GD_EVENT_MOVING) printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id); else printf("default: HandleControlButtons: ? (id == %d)\n", id); #endif break; } } void HandleLevelEditorKeyInput(Key key) { char letter = getCharFromKey(key); int button = MB_LEFTBUTTON; if (drawing_function == GADGET_ID_TEXT && DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE) { if (letter) DrawLevelText(0, 0, letter, TEXT_WRITECHAR); else if (key == KSYM_Delete || key == KSYM_BackSpace) DrawLevelText(0, 0, 0, TEXT_BACKSPACE); else if (key == KSYM_Return) DrawLevelText(0, 0, 0, TEXT_NEWLINE); else if (key == KSYM_Escape) DrawLevelText(0, 0, 0, TEXT_END); } else if (button_status == MB_RELEASED) { int id = GADGET_ID_NONE; int new_element_shift = element_shift; int step = ED_ELEMENTLIST_BUTTONS_VERT - 1; int i; switch (key) { case KSYM_Left: id = GADGET_ID_SCROLL_LEFT; break; case KSYM_Right: id = GADGET_ID_SCROLL_RIGHT; break; case KSYM_Up: id = GADGET_ID_SCROLL_UP; break; case KSYM_Down: id = GADGET_ID_SCROLL_DOWN; break; case KSYM_Page_Up: case KSYM_Page_Down: step *= (key == KSYM_Page_Up ? -1 : +1); element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ; if (element_shift < 0) element_shift = 0; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); ModifyEditorElementList(); break; case KSYM_Home: case KSYM_End: element_shift = (key == KSYM_Home ? 0 : num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS); ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); ModifyEditorElementList(); break; case KSYM_Insert: case KSYM_Delete: /* this is needed to prevent interference with running "True X-Mouse" */ if (GetKeyModStateFromEvents() & KMOD_Control) break; /* check for last or next editor cascade block in element list */ for (i = 0; i < num_editor_elements; i++) { if ((key == KSYM_Insert && i == element_shift) || (key == KSYM_Delete && new_element_shift > element_shift)) break; /* jump to next cascade block (or to start of element list) */ if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i])) new_element_shift = i; } if (i < num_editor_elements) element_shift = new_element_shift; if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS) element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL], GDI_SCROLLBAR_ITEM_POSITION, element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END); ModifyEditorElementList(); break; case KSYM_Escape: if (edit_mode == ED_MODE_DRAWING) { RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE); } else if (edit_mode == ED_MODE_INFO) { HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]); } else if (edit_mode == ED_MODE_PROPERTIES) { HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]); } else if (edit_mode == ED_MODE_PALETTE) { HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]); } else /* should never happen */ { ChangeEditModeWindow(ED_MODE_DRAWING); } break; default: break; } if (id != GADGET_ID_NONE) ClickOnGadget(level_editor_gadget[id], button); else if (letter == '1' || letter == '?') ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button); else if (letter == '2') ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button); else if (letter == '3') ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button); else if (letter == '.') ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button); else if (letter == 'U') ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3); else if (letter == '-' || key == KSYM_KP_Subtract) ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3); else if (letter == '0' || key == KSYM_KP_0) ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2); else if (letter == '+' || key == KSYM_KP_Add || letter == '=') // ("Shift-=" is "+" on US keyboards) ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1); else if (key == KSYM_Return || key == KSYM_space || key == setup.shortcut.toggle_pause) ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button); else for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++) if (letter && letter == controlbutton_info[i].shortcut) if (!anyTextGadgetActive()) ClickOnGadget(level_editor_gadget[i], button); } } void HandleLevelEditorIdle() { int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size; int x = editor.settings.element_graphic.x + element_border; int y = editor.settings.element_graphic.y + element_border; static unsigned int action_delay = 0; unsigned int action_delay_value = GameFrameDelay; int i; if (edit_mode != ED_MODE_PROPERTIES) return; if (!DelayReached(&action_delay, action_delay_value)) return; for (i = 0; i < ED_NUM_SELECTBOX; i++) { struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id]; if (gi->mapped && gi->active && gi->selectbox.open) return; } DrawEditorElementAnimation(SX + x, SY + y); redraw_mask |= REDRAW_FIELD; FrameCounter++; /* increase animation frame counter */ } static void ClearEditorGadgetInfoText() { DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE); } void PrintEditorGadgetInfoText(struct GadgetInfo *gi) { char infotext[MAX_OUTPUT_LINESIZE + 1]; char shortcut[MAX_OUTPUT_LINESIZE + 1]; int max_infotext_len = getMaxInfoTextLength(); if (gi == NULL || strlen(gi->info_text) == 0) return; strncpy(infotext, gi->info_text, max_infotext_len); infotext[max_infotext_len] = '\0'; if (gi->custom_id < ED_NUM_CTRL_BUTTONS) { int key = controlbutton_info[gi->custom_id].shortcut; if (key) { if (gi->custom_id == GADGET_ID_SINGLE_ITEMS) sprintf(shortcut, " ('.' or '%c')", key); else if (gi->custom_id == GADGET_ID_PICK_ELEMENT) sprintf(shortcut, " ('%c' or 'Ctrl')", key); else if (gi->custom_id == GADGET_ID_TEST) sprintf(shortcut, " ('Enter' or 'Shift-%c')", key); else if (gi->custom_id == GADGET_ID_UNDO) sprintf(shortcut, " ('%c/Shift-U')", key); else if (gi->custom_id == GADGET_ID_ZOOM) sprintf(shortcut, " ('%c', '0', '-')", key); else sprintf(shortcut, " ('%s%c')", (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key); if (strlen(infotext) + strlen(shortcut) <= max_infotext_len) strcat(infotext, shortcut); } } DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT); } void HandleEditorGadgetInfoText(void *ptr) { struct GadgetInfo *gi = (struct GadgetInfo *)ptr; if (game_status != GAME_MODE_EDITOR) return; ClearEditorGadgetInfoText(); if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING) return; /* misuse this function to delete brush cursor, if needed */ if (edit_mode == ED_MODE_DRAWING && draw_with_brush) DeleteBrushFromCursor(); PrintEditorGadgetInfoText(gi); } static void HandleDrawingAreaInfo(struct GadgetInfo *gi) { static int start_lx, start_ly; int id = gi->custom_id; int type_id = gi->custom_type_id; int sx = gi->event.x; int sy = gi->event.y; int lx = sx + level_xpos; int ly = sy + level_ypos; int min_sx = 0, min_sy = 0; int max_sx = gi->drawing.area_xsize - 1; int max_sy = gi->drawing.area_ysize - 1; int actual_drawing_function = drawing_function; int max_infotext_len = getMaxInfoTextLength(); char infotext[MAX_OUTPUT_LINESIZE + 1]; char *text; infotext[0] = '\0'; /* start with empty info text */ /* pressed Control key: simulate picking element */ if (GetKeyModState() & KMOD_Control) actual_drawing_function = GADGET_ID_PICK_ELEMENT; ClearEditorGadgetInfoText(); if (gi->event.type == GD_EVENT_INFO_LEAVING) return; /* make sure to stay inside drawing area boundaries */ sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx); sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy); if (id == GADGET_ID_DRAWING_LEVEL) { if (button_status) { int min_lx = 0, min_ly = 0; int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1; /* get positions inside level field */ lx = sx + level_xpos; ly = sy + level_ypos; /* make sure to stay inside level field boundaries */ lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx); ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly); /* correct drawing area positions accordingly */ sx = lx - level_xpos; sy = ly - level_ypos; } if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly)) { if (button_status) /* if (gi->state == GD_BUTTON_PRESSED) */ { if (gi->event.type == GD_EVENT_PRESSED) { start_lx = lx; start_ly = ly; } switch (actual_drawing_function) { case GADGET_ID_SINGLE_ITEMS: text = "Drawing single items"; break; case GADGET_ID_CONNECTED_ITEMS: text = "Drawing connected items"; break; case GADGET_ID_LINE: text = "Drawing line"; break; case GADGET_ID_ARC: text = "Drawing arc"; break; case GADGET_ID_TEXT: text = "Setting text cursor"; break; case GADGET_ID_RECTANGLE: text = "Drawing rectangle"; break; case GADGET_ID_FILLED_BOX: text = "Drawing filled box"; break; case GADGET_ID_FLOOD_FILL: text = "Flood fill"; break; case GADGET_ID_GRAB_BRUSH: text = "Grabbing brush"; break; case GADGET_ID_PICK_ELEMENT: text = "Picking element"; break; default: text = "Drawing position"; break; } if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) sprintf(infotext, "%s: %d, %d", text, lx, ly); else sprintf(infotext, "%s: %d, %d", text, ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1); } else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len); else sprintf(infotext, "Level position: %d, %d", lx, ly); } /* misuse this function to draw brush cursor, if needed */ if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status) { if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly)) CopyBrushToCursor(sx, sy); else DeleteBrushFromCursor(); } } else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT) { int pos = sx * drawingarea_info[type_id].area_ysize + sy; int element = drawingarea_info[type_id].value[pos]; strncpy(infotext, getElementInfoText(element), max_infotext_len); } else { if (id == GADGET_ID_CUSTOM_CONTENT) sprintf(infotext, "custom element content position: %d, %d", sx, sy); else if (id == GADGET_ID_GROUP_CONTENT) sprintf(infotext, "group element position: %d", sx + 1); else if (id >= GADGET_ID_YAMYAM_CONTENT_0 && id <= GADGET_ID_YAMYAM_CONTENT_7) sprintf(infotext, "content area %d position: %d, %d", id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy); else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 && id <= GADGET_ID_MAGIC_BALL_CONTENT_7) sprintf(infotext, "content area %d position: %d, %d", id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy); else if (id == GADGET_ID_ANDROID_CONTENT) sprintf(infotext, "android element position: %d", sx + 1); else if (drawingarea_info[type_id].infotext != NULL) strcpy(infotext, drawingarea_info[type_id].infotext); } infotext[max_infotext_len] = '\0'; if (strlen(infotext) > 0) DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext); } void RequestExitLevelEditor(boolean ask_if_level_has_changed, boolean quick_quit) { if (!ask_if_level_has_changed || !LevelChanged() || Request("Level has changed! Exit without saving?", REQ_ASK | REQ_STAY_OPEN)) { struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN]; struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN]; /* draw normal door */ UndrawSpecialEditorDoor(); // use door animation if door 1 viewport is unchanged and contains toolbox if (useEditorDoorAnimation()) CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM); // close editor doors if viewport definition is the same as in main menu if (vp_door_1->x == DX && vp_door_1->y == DY && vp_door_1->width == DXSIZE && vp_door_1->height == DYSIZE && vp_door_2->x == VX && vp_door_2->y == VY && vp_door_2->width == VXSIZE && vp_door_2->height == VYSIZE) CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY); else SetDoorState(DOOR_CLOSE_2); BackToFront(); if (quick_quit) FadeSkipNextFadeIn(); SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } else { if (!global.use_envelope_request) { CloseDoor(DOOR_CLOSE_1); OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); } } } mirrormagic-3.0.0/src/Makefile0000644000175000017500000002047613263212010015561 0ustar aeglosaeglos# ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1995-2015 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # src/Makefile # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- .EXPORT_ALL_VARIABLES: ifndef PLATFORM # unknown platform -- default to Unix PLATFORM = unix endif AR = ar RANLIB = ranlib ETAGS = etags RM = rm -f CONVERT = convert WINDRES = windres CONVERT_ICON_ARGS = -transparent black -background transparent PROGBASE = rocksndiamonds PROGNAME = ../$(PROGBASE) EDITION ?= default # ----------------------------------------------------------------------------- # configuring platform # ----------------------------------------------------------------------------- ifeq ($(PLATFORM),macosx) # compiling on Mac OS X EXTRA_LDFLAGS = -lstdc++ override PLATFORM = unix endif ifeq ($(PLATFORM),unix) # compiling on Unix/Linux (generic) PROFILING_FLAGS = -pg endif ifeq ($(PLATFORM),cross-win32) # cross-compiling to Windows PROGNAME = ../$(PROGBASE).exe EXTRA_LDFLAGS = -lshfolder -lwsock32 endif # ----------------------------------------------------------------------------- # configuring target # ----------------------------------------------------------------------------- ifndef TARGET # auto-detect compiling for SDL or SDL2 SDL_VERSION := $(shell sdl2-config --version 2> /dev/null) ifdef SDL_VERSION TARGET = sdl2 else SDL_VERSION := $(shell sdl-config --version 2> /dev/null) ifdef SDL_VERSION TARGET = sdl else $(error SDL/SDL2 library not found) endif endif endif # $(info Using SDL version $(SDL_VERSION) [TARGET == $(TARGET)]) ifeq ($(TARGET),sdl) # compiling for SDL target SYS_CFLAGS = -DTARGET_SDL $(shell sdl-config --cflags) SDL_LIBS = -lSDL_image -lSDL_mixer -lSDL_net SYS_LDFLAGS = $(SDL_LIBS) $(shell sdl-config --libs) endif ifeq ($(TARGET),sdl2) # compiling for SDL2 target SYS_CFLAGS = -DTARGET_SDL2 $(shell sdl2-config --cflags) SDL_LIBS = -lSDL2_image -lSDL2_mixer -lSDL2_net SYS_LDFLAGS = $(SDL_LIBS) $(shell sdl2-config --libs) endif # ----------------------------------------------------------------------------- # configuring compile-time definitions # ----------------------------------------------------------------------------- ifdef RO_GAME_DIR # path to read-only game data specified CONFIG_RO_GAME_DIR = -DRO_GAME_DIR="\"$(RO_GAME_DIR)\"" endif ifdef RW_GAME_DIR # path to writable game data specified CONFIG_RW_GAME_DIR = -DRW_GAME_DIR="\"$(RW_GAME_DIR)\"" endif CONFIG = $(CONFIG_RO_GAME_DIR) $(CONFIG_RW_GAME_DIR) $(JOYSTICK) DEBUG = -DDEBUG -g # PROFILING = $(PROFILING_FLAGS) # OPTIONS = $(DEBUG) -Wall # only for debugging purposes # OPTIONS = $(DEBUG) -O3 -Wall # only for debugging purposes OPTIONS = $(DEBUG) -Wall # only for debugging purposes # OPTIONS = $(DEBUG) -Wall -ansi -pedantic # only for debugging purposes # OPTIONS = -O3 -Wall -ansi -pedantic # OPTIONS = -O3 -Wall # OPTIONS = -O3 ifdef BUILD_DIST # distribution build SYS_LDFLAGS := $(shell echo $(SYS_LDFLAGS) | \ sed -e "s%-rpath,[^ ]*%-rpath,'\$$ORIGIN/lib'%") OPTIONS = -O3 -Wall endif CFLAGS = $(OPTIONS) $(SYS_CFLAGS) $(EXTRA_CFLAGS) $(CONFIG) LDFLAGS = $(SYS_LDFLAGS) $(EXTRA_LDFLAGS) -lm SRCS = main.c \ conf_gfx.c \ conf_snd.c \ conf_mus.c \ conf_hlp.c \ init.c \ config.c \ events.c \ tools.c \ screens.c \ game.c \ editor.c \ files.c \ tape.c \ anim.c \ network.c \ netserv.c OBJS = main.o \ conf_gfx.o \ conf_snd.o \ conf_mus.o \ conf_hlp.o \ init.o \ config.o \ events.o \ tools.o \ screens.o \ game.o \ editor.o \ files.o \ tape.o \ anim.o \ network.o \ netserv.o CNFS = conf_gfx.h \ conf_snd.h \ conf_mus.h \ conf_chr.c \ conf_chr.h \ conf_cus.c \ conf_cus.h \ conf_grp.c \ conf_grp.h \ conf_e2g.c \ conf_esg.c \ conf_e2s.c \ conf_fnt.c \ conf_g2s.c \ conf_g2m.c \ conf_var.c \ conf_act.c CNFS_CMD = ../build-scripts/create_element_defs.pl TIMESTAMP_FILE = conftime.h TIMESTAMP_FORMAT = %Y-%m-%d %H:%M # use SOURCE_DATE_EPOCH, or else last Git commit date, or else current date SOURCE_DATE_EPOCH ?= $(shell test -d ../.git && test `git ls-files -m | wc -l` -eq 0 && git show -s --format=%ct || date +%s) # get source date string from either GNU / Linux or BSD / Mac OS X style "date" SOURCE_DATE_STRING := $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+$(TIMESTAMP_FORMAT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+$(TIMESTAMP_FORMAT)" 2>/dev/null || date -u "+$(TIMESTAMP_FORMAT)") LIBGAME_DIR = libgame LIBGAME = $(LIBGAME_DIR)/libgame.a GAME_EM_DIR = game_em GAME_EM = $(GAME_EM_DIR)/game_em.a GAME_SP_DIR = game_sp GAME_SP = $(GAME_SP_DIR)/game_sp.a GAME_MM_DIR = game_mm GAME_MM = $(GAME_MM_DIR)/game_mm.a RNDLIBS = $(LIBGAME) $(GAME_EM) $(GAME_SP) $(GAME_MM) AUTOCONF = conf_gfx.h conf_snd.h conf_mus.h ICONBASE = windows_icon ICON_BASEPATH = ../Special/Icons/windows_icons ifeq ($(PLATFORM),cross-win32) ICON_PATH = $(ICON_BASEPATH)/$(EDITION) ICON = $(ICONBASE).o endif GRAPHICS_DIR = ../graphics # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(AUTOCONF) libgame_dir game_em_dir game_sp_dir game_mm_dir $(PROGNAME) graphics_dir $(PROGNAME): $(RNDLIBS) $(TIMESTAMP_FILE) $(OBJS) $(ICON) $(CC) $(PROFILING) $(OBJS) $(ICON) $(RNDLIBS) $(LDFLAGS) -o $(PROGNAME) ifdef BUILD_DIST strip $(PROGNAME) endif libgame_dir: @$(MAKE) -C $(LIBGAME_DIR) $(LIBGAME): @$(MAKE) -C $(LIBGAME_DIR) game_em_dir: @$(MAKE) -C $(GAME_EM_DIR) $(GAME_EM): @$(MAKE) -C $(GAME_EM_DIR) game_sp_dir: @$(MAKE) -C $(GAME_SP_DIR) $(GAME_SP): @$(MAKE) -C $(GAME_SP_DIR) game_mm_dir: @$(MAKE) -C $(GAME_MM_DIR) $(GAME_MM): @$(MAKE) -C $(GAME_MM_DIR) auto-conf: @for i in $(CNFS); do \ echo "$(CNFS_CMD) $$i > $$i"; \ $(CNFS_CMD) $$i > $$i; \ done auto-conf-clean: @for i in $(CNFS); do \ echo "$(RM) $$i"; \ $(RM) $$i; \ done conf_gfx.h: conf_gfx.c $(CNFS_CMD) @$(MAKE) auto-conf conf_snd.h: conf_snd.c $(CNFS_CMD) @$(MAKE) auto-conf conf_mus.h: conf_mus.c $(CNFS_CMD) @$(MAKE) auto-conf $(TIMESTAMP_FILE): $(SRCS) $(RNDLIBS) @echo '#define SOURCE_DATE_STRING "$(SOURCE_DATE_STRING)"' \ > $(TIMESTAMP_FILE) $(ICON): # $(CONVERT) $(ICON32X32) $(CONVERT_ICON_ARGS) $(ICONBASE).ico $(CONVERT) $(ICON_PATH)/*.png $(CONVERT_ICON_ARGS) $(ICONBASE).ico echo "$(ICONBASE) ICON $(ICONBASE).ico" | $(WINDRES) -o $(ICON) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c graphics_dir: @test -f $(GRAPHICS_DIR)/Makefile && $(MAKE) -C $(GRAPHICS_DIR) || true clean-obj: $(MAKE) -C $(LIBGAME_DIR) clean $(MAKE) -C $(GAME_EM_DIR) clean $(MAKE) -C $(GAME_SP_DIR) clean $(MAKE) -C $(GAME_MM_DIR) clean $(RM) $(OBJS) $(RM) $(RNDLIBS) clean-ico: $(RM) $(ICONBASE).ico $(RM) $(ICONBASE).o clean-bin: $(RM) $(PROGNAME) $(RM) ../*.exe clean: clean-obj clean-ico clean-bin clean-git: clean auto-conf-clean @$(MAKE) -C $(GRAPHICS_DIR) clean dist-clean: clean-obj clean-ico # ----------------------------------------------------------------------------- # run and test targets # ----------------------------------------------------------------------------- run: cd .. && ./$(PROGBASE) --verbose gdb: cd .. && gdb -batch -x GDB_COMMANDS ./$(PROGBASE) valgrind: cd .. && valgrind -v --leak-check=yes ./$(PROGBASE) 2> valgrind.out # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- tags: $(ETAGS) *.[ch] $(LIBGAME_DIR)/*.[ch] $(GAME_EM_DIR)/*.[ch] $(GAME_SP_DIR)/*.[ch] $(GAME_MM_DIR)/*.[ch] depend: $(MAKE) -C $(LIBGAME_DIR) depend $(MAKE) -C $(GAME_EM_DIR) depend $(MAKE) -C $(GAME_SP_DIR) depend $(MAKE) -C $(GAME_MM_DIR) depend for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif mirrormagic-3.0.0/src/conf_grp.h0000644000175000017500000000412113263214151016064 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_grp.h // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_GRP_H #define CONF_GRP_H /* values for elements configuration (group elements) */ #define EL_GROUP_1 (EL_GROUP_START + 0) #define EL_GROUP_2 (EL_GROUP_START + 1) #define EL_GROUP_3 (EL_GROUP_START + 2) #define EL_GROUP_4 (EL_GROUP_START + 3) #define EL_GROUP_5 (EL_GROUP_START + 4) #define EL_GROUP_6 (EL_GROUP_START + 5) #define EL_GROUP_7 (EL_GROUP_START + 6) #define EL_GROUP_8 (EL_GROUP_START + 7) #define EL_GROUP_9 (EL_GROUP_START + 8) #define EL_GROUP_10 (EL_GROUP_START + 9) #define EL_GROUP_11 (EL_GROUP_START + 10) #define EL_GROUP_12 (EL_GROUP_START + 11) #define EL_GROUP_13 (EL_GROUP_START + 12) #define EL_GROUP_14 (EL_GROUP_START + 13) #define EL_GROUP_15 (EL_GROUP_START + 14) #define EL_GROUP_16 (EL_GROUP_START + 15) #define EL_GROUP_17 (EL_GROUP_START + 16) #define EL_GROUP_18 (EL_GROUP_START + 17) #define EL_GROUP_19 (EL_GROUP_START + 18) #define EL_GROUP_20 (EL_GROUP_START + 19) #define EL_GROUP_21 (EL_GROUP_START + 20) #define EL_GROUP_22 (EL_GROUP_START + 21) #define EL_GROUP_23 (EL_GROUP_START + 22) #define EL_GROUP_24 (EL_GROUP_START + 23) #define EL_GROUP_25 (EL_GROUP_START + 24) #define EL_GROUP_26 (EL_GROUP_START + 25) #define EL_GROUP_27 (EL_GROUP_START + 26) #define EL_GROUP_28 (EL_GROUP_START + 27) #define EL_GROUP_29 (EL_GROUP_START + 28) #define EL_GROUP_30 (EL_GROUP_START + 29) #define EL_GROUP_31 (EL_GROUP_START + 30) #define EL_GROUP_32 (EL_GROUP_START + 31) #endif /* CONF_GRP_C */ mirrormagic-3.0.0/src/conf_snd.c0000644000175000017500000003573413263212010016061 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_snd.c // ============================================================================ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is SND_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigTypeInfo sound_config_suffix[] = { { ".mode_loop", ARG_UNDEFINED, TYPE_BOOLEAN }, { ".volume", "100", TYPE_INTEGER }, { ".priority", "0", TYPE_INTEGER }, { NULL, NULL, 0 } }; struct ConfigInfo sound_config[] = { /* some default sounds */ { "[default].digging", "schlurf.wav" }, { "[default].collecting", "pong.wav" }, { "[default].snapping", "pong.wav" }, { "[default].pushing", "pusch.wav" }, { "[default].impact", "klopf.wav" }, { "[default].walking", "empty.wav" }, { "[default].passing", "gate.wav" }, { "[default].dying", "autsch.wav" }, { "[default].exploding", "roaaar.wav" }, { "[default].hitting", "kink.wav" }, { "[sp_default].exploding", "booom.wav" }, { "[mm_default].exploding", "kabumm.wav" }, /* sounds for Boulder Dash style elements and actions */ { "bd_diamond.collecting", "pong.wav" }, { "bd_diamond.impact", "pling.wav" }, { "bd_rock.pushing", "pusch.wav" }, { "bd_rock.impact", "klopf.wav" }, { "bd_magic_wall.activating", "quirk.wav" }, { "bd_magic_wall.active", "miep.wav" }, { "bd_magic_wall.filling", "quirk.wav" }, { "bd_amoeba.waiting", UNDEFINED_FILENAME }, { "bd_amoeba.growing", "amoebe.wav" }, { "bd_amoeba.turning_to_gem", "pling.wav" }, { "bd_amoeba.turning_to_rock", "klopf.wav" }, { "bd_butterfly.moving", "klapper.wav" }, { "bd_butterfly.waiting", "klapper.wav" }, { "bd_firefly.moving", "roehr.wav" }, { "bd_firefly.waiting", "roehr.wav" }, /* sounds for Supaplex style elements and actions */ { "sp_base.digging", "base.wav" }, { "sp_buggy_base.digging", "base.wav" }, { "sp_buggy_base.active", "bug.wav" }, { "sp_infotron.collecting", "infotron.wav" }, { "sp_infotron.impact", "pling.wav" }, { "sp_zonk.pushing", "zonkpush.wav" }, { "sp_zonk.impact", "zonkdown.wav" }, { "sp_disk_red.collecting", "infotron.wav" }, { "sp_disk_orange.pushing", "zonkpush.wav" }, { "sp_disk_yellow.pushing", "pusch.wav" }, { "[sp_port].passing", "gate.wav" }, { "[sp_exit].passing", "exit.wav" }, { "[sp_exit].opening", UNDEFINED_FILENAME }, { "[sp_exit].closing", UNDEFINED_FILENAME }, { "sp_sniksnak.moving", UNDEFINED_FILENAME }, { "sp_sniksnak.waiting", UNDEFINED_FILENAME }, { "sp_electron.moving", UNDEFINED_FILENAME }, { "sp_electron.waiting", UNDEFINED_FILENAME }, { "sp_terminal.activating", UNDEFINED_FILENAME }, { "sp_terminal.active", UNDEFINED_FILENAME }, /* sounds for Sokoban style elements and actions */ { "[sokoban].pushing", "pusch.wav" }, { "[sokoban].filling", "deng.wav" }, { "[sokoban].emptying", UNDEFINED_FILENAME }, /* sounds for Emerald Mine style elements and actions */ { "[player].moving", "empty.wav" }, { "[player].moving.mode_loop", "false" }, { "sand.digging", "schlurf.wav" }, { "[emerald].collecting", "pong.wav" }, { "[emerald].impact", "pling.wav" }, { "diamond.collecting", "pong.wav" }, { "diamond.impact", "pling.wav" }, { "diamond.breaking", "quirk.wav" }, { "rock.pushing", "pusch.wav" }, { "rock.impact", "klopf.wav" }, { "bomb.pushing", "pusch.wav" }, { "nut.pushing", "knurk.wav" }, { "nut.breaking", "knack.wav" }, { "nut.impact", "klumpf.wav" }, { "[dynamite].collecting", "pong.wav" }, { "[dynamite].dropping", "deng.wav" }, { "[dynamite].active", "zisch.wav" }, { "[key].collecting", "pong.wav" }, { "[gate].passing", "gate.wav" }, { "bug.moving", "klapper.wav" }, { "bug.waiting", "klapper.wav" }, { "spaceship.moving", "roehr.wav" }, { "spaceship.waiting", "roehr.wav" }, { "yamyam.moving", UNDEFINED_FILENAME }, { "yamyam.waiting", "njam.wav" }, { "yamyam.digging", "njam.wav" }, { "robot.moving", "schlurf.wav" }, { "robot.moving.mode_loop", "false" }, { "robot.waiting", UNDEFINED_FILENAME }, { "robot_wheel.activating", "deng.wav" }, { "robot_wheel.active", "miep.wav" }, { "magic_wall.activating", "quirk.wav" }, { "magic_wall.active", "miep.wav" }, { "magic_wall.filling", "quirk.wav" }, { "dc_magic_wall.activating", "quirk.wav" }, { "dc_magic_wall.active", "miep.wav" }, { "dc_magic_wall.filling", "quirk.wav" }, { "[amoeba].waiting", UNDEFINED_FILENAME }, { "[amoeba].growing", "amoebe.wav" }, { "[amoeba].dropping", UNDEFINED_FILENAME }, { "acid.splashing", "blurb.wav" }, { "[quicksand].filling", UNDEFINED_FILENAME }, { "[quicksand].emptying", UNDEFINED_FILENAME }, { "[exit].opening", "oeffnen.wav" }, { "[exit].closing", "oeffnen.wav" }, { "[exit].passing", "buing.wav" }, { "[steel_exit].opening", "oeffnen.wav" }, { "[steel_exit].closing", "oeffnen.wav" }, { "[steel_exit].passing", "buing.wav" }, { "[em_exit].opening", "gong.wav" }, { "[em_exit].closing", UNDEFINED_FILENAME }, { "[em_exit].passing", "buing.wav" }, { "[em_steel_exit].opening", "gong.wav" }, { "[em_steel_exit].closing", UNDEFINED_FILENAME }, { "[em_steel_exit].passing", "buing.wav" }, { "penguin.passing", "buing.wav" }, /* sounds for Emerald Mine Club style elements and actions */ { "balloon.moving", UNDEFINED_FILENAME }, { "balloon.waiting", UNDEFINED_FILENAME }, { "balloon.pushing", "schlurf.wav" }, { "[balloon_switch].activating", UNDEFINED_FILENAME }, { "spring.moving", UNDEFINED_FILENAME }, { "spring.pushing", "pusch.wav" }, { "spring.impact", "klopf.wav" }, { "[wall].growing", UNDEFINED_FILENAME }, { "emc_android.pushing", "pusch.wav" }, { "emc_android.moving", "roehr.wav" }, { "emc_android.moving.mode_loop", "false" }, { "emc_android.dropping", "deng.wav" }, { "emc_magic_ball.dropping", "deng.wav" }, /* sounds for Diamond Caves style elements and actions */ { "pearl.collecting", "pong.wav" }, { "pearl.breaking", "knack.wav" }, { "pearl.impact", "pling.wav" }, { "crystal.collecting", "pong.wav" }, { "crystal.impact", "pling.wav" }, { "[envelope].collecting", "pong.wav" }, { "[envelope].opening", UNDEFINED_FILENAME }, { "[envelope].closing", UNDEFINED_FILENAME }, { "invisible_sand.digging", "schlurf.wav" }, { "invisible_sand.active.digging", "schlurf.wav" }, { "shield_normal.collecting", "pong.wav" }, { "shield_normal.active", UNDEFINED_FILENAME }, { "shield_deadly.collecting", "pong.wav" }, { "shield_deadly.active", UNDEFINED_FILENAME }, { "extra_time.collecting", "gong.wav" }, { "mole.moving", UNDEFINED_FILENAME }, { "mole.waiting", UNDEFINED_FILENAME }, { "mole.digging", "blurb.wav" }, { "[switchgate_switch].activating", UNDEFINED_FILENAME }, { "[switchgate].opening", "oeffnen.wav" }, { "[switchgate].closing", "oeffnen.wav" }, { "[switchgate].passing", "gate.wav" }, { "[timegate_switch].activating", "deng.wav" }, { "[timegate_switch].active", "miep.wav" }, { "[timegate_switch].deactivating", UNDEFINED_FILENAME }, { "[timegate].opening", "oeffnen.wav" }, { "[timegate].closing", "oeffnen.wav" }, { "[timegate].passing", "gate.wav" }, { "[conveyor_belt_switch].activating",UNDEFINED_FILENAME }, { "[conveyor_belt].active", UNDEFINED_FILENAME }, { "[conveyor_belt_switch].deactivating",UNDEFINED_FILENAME }, { "light_switch.activating", UNDEFINED_FILENAME }, { "light_switch.deactivating", UNDEFINED_FILENAME }, /* sounds for DX Boulderdash style elements and actions */ { "dx_supabomb.pushing", "pusch.wav" }, { "trap.digging", "schlurf.wav" }, { "trap.activating", UNDEFINED_FILENAME }, { "[tube].walking", UNDEFINED_FILENAME }, /* sounds for Rocks'n'Diamonds style elements and actions */ { "amoeba.turning_to_gem", "pling.wav" }, { "amoeba.turning_to_rock", "klopf.wav" }, { "speed_pill.collecting", "pong.wav" }, { "dynabomb_increase_number.collecting","pong.wav" }, { "dynabomb_increase_size.collecting","pong.wav" }, { "dynabomb_increase_power.collecting","pong.wav" }, { "[dynabomb].dropping", "deng.wav" }, { "[dynabomb].active", "zisch.wav" }, { "satellite.moving", UNDEFINED_FILENAME }, { "satellite.waiting", UNDEFINED_FILENAME }, { "satellite.pushing", "pusch.wav" }, { "lamp.activating", "deng.wav" }, { "lamp.deactivating", "deng.wav" }, { "time_orb_full.collecting", "gong.wav" }, { "time_orb_full.impact", "deng.wav" }, { "time_orb_empty.pushing", "pusch.wav" }, { "time_orb_empty.impact", "deng.wav" }, { "game_of_life.waiting", UNDEFINED_FILENAME }, { "game_of_life.growing", "amoebe.wav" }, { "biomaze.waiting", UNDEFINED_FILENAME }, { "biomaze.growing", "amoebe.wav" }, { "pacman.moving", UNDEFINED_FILENAME }, { "pacman.waiting", UNDEFINED_FILENAME }, { "pacman.digging", UNDEFINED_FILENAME }, { "dark_yamyam.moving", UNDEFINED_FILENAME }, { "dark_yamyam.waiting", "njam.wav" }, { "dark_yamyam.digging", UNDEFINED_FILENAME }, { "penguin.moving", UNDEFINED_FILENAME }, { "penguin.waiting", UNDEFINED_FILENAME }, { "pig.moving", UNDEFINED_FILENAME }, { "pig.waiting", UNDEFINED_FILENAME }, { "pig.digging", UNDEFINED_FILENAME }, { "dragon.moving", UNDEFINED_FILENAME }, { "dragon.waiting", UNDEFINED_FILENAME }, { "dragon.attacking", UNDEFINED_FILENAME }, /* sounds for Mirror Magic style elements and actions */ { "[mm_mcduffin].hitting", "autsch.wav" }, { "[mm_mirror].hitting", "laser.wav" }, { "[mm_mirror_fixed].hitting", "laser.wav" }, { "[mm_prism].hitting", "laser.wav" }, { "[mm_exit].hitting", "holz.wav" }, { "[mm_exit].opening", "kling.wav" }, { "mm_exit_open.hitting", UNDEFINED_FILENAME }, { "[df_mirror].hitting", "laser.wav" }, { "[df_mirror_rotating].hitting", "laser.wav" }, { "[df_refractor].hitting", "laser.wav" }, { "[df_receiver].hitting", "holz.wav" }, { "[df_receiver].opening", "kling.wav" }, { "[mm_wooden_wall].hitting", "holz.wav" }, { "[mm_wooden_block].hitting", "holz.wav" }, { "[mm_wooden_block].pushing", "bong.wav" }, { "[mm_wooden_lock].hitting", "holz.wav" }, { "[mm_wooden_grid_fixed].hitting", "holz.wav" }, { "[mm_fuse].hitting", "holz.wav" }, { "[mm_ice_wall].hitting", "holz.wav" }, { "[mm_ice_wall].shrinking", "slurp.wav" }, { "[mm_amoeba_wall].hitting", "holz.wav" }, { "[mm_amoeba_wall].growing", "amoebe.wav" }, { "[mm_amoeba_wall].growing.mode_loop","false" }, { "[df_wooden_wall].hitting", "holz.wav" }, { "[df_wooden_grid_fixed].hitting", "holz.wav" }, { "[df_wooden_grid_rotating].hitting","holz.wav" }, { "[mm_steel_wall].hitting", "hui.wav" }, { "[mm_steel_grid_fixed].hitting", "hui.wav" }, { "[mm_steel_block].hitting", "hui.wav" }, { "[mm_steel_block].pushing", "bong.wav" }, { "[mm_steel_lock].hitting", "hui.wav" }, { "[df_steel_wall].hitting", "hui.wav" }, { "[df_steel_grid_fixed].hitting", "hui.wav" }, { "[df_steel_grid_rotating].hitting", "hui.wav" }, { "[mm_pacman].exploding", "quiek.wav" }, { "[mm_mcduffin].exploding", "roaaar.wav" }, { "[mm_bomb].exploding", "roaaar.wav" }, { "[mm_key].exploding", "kling.wav" }, { "[mm_steel_lock].exploding", "whoosh.wav" }, { "[mm_wooden_lock].exploding", "whoosh.wav" }, /* sounds not associated to game elements (used for menu screens etc.) */ /* keyword to stop parser: "NO_MORE_ELEMENT_SOUNDS" <-- do not change! */ /* sounds for other game actions */ { "game.starting", UNDEFINED_FILENAME }, { "game.leveltime_charging", "fuel.wav" }, { "game.health_charging", "warnton.wav" }, { "game.running_out_of_time", "gong.wav" }, { "game.leveltime_bonus", "sirr.wav" }, { "game.health_bonus", "sirr.wav" }, { "game.losing", "lachen.wav" }, { "game.winning", UNDEFINED_FILENAME }, { "game.sokoban_solving", "buing.wav" }, /* sounds for other non-game actions */ { "door.opening", "door.wav" }, { "door.closing", "door.wav" }, { "door_1.opening", UNDEFINED_FILENAME }, { "door_1.closing", UNDEFINED_FILENAME }, { "door_2.opening", UNDEFINED_FILENAME }, { "door_2.closing", UNDEFINED_FILENAME }, { "request.opening", UNDEFINED_FILENAME }, { "request.closing", UNDEFINED_FILENAME }, /* sounds for menu actions */ { "menu.item.activating", "empty.wav" }, { "menu.item.selecting", "base.wav" }, { "menu.button.pressing", UNDEFINED_FILENAME }, { "menu.button.releasing", UNDEFINED_FILENAME }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, { "background.MAIN", UNDEFINED_FILENAME }, { "background.LEVELS", UNDEFINED_FILENAME }, { "background.LEVELNR", UNDEFINED_FILENAME }, { "background.SCORES", "halloffame.wav" }, { "background.SCORES.mode_loop", "false" }, { "background.EDITOR", UNDEFINED_FILENAME }, { "background.INFO", UNDEFINED_FILENAME }, { "background.SETUP", UNDEFINED_FILENAME }, { "background.titlescreen_initial_1", UNDEFINED_FILENAME }, { "background.titlescreen_initial_2", UNDEFINED_FILENAME }, { "background.titlescreen_initial_3", UNDEFINED_FILENAME }, { "background.titlescreen_initial_4", UNDEFINED_FILENAME }, { "background.titlescreen_initial_5", UNDEFINED_FILENAME }, { "background.titlescreen_1", UNDEFINED_FILENAME }, { "background.titlescreen_2", UNDEFINED_FILENAME }, { "background.titlescreen_3", UNDEFINED_FILENAME }, { "background.titlescreen_4", UNDEFINED_FILENAME }, { "background.titlescreen_5", UNDEFINED_FILENAME }, { "background.titlemessage_initial_1",UNDEFINED_FILENAME }, { "background.titlemessage_initial_2",UNDEFINED_FILENAME }, { "background.titlemessage_initial_3",UNDEFINED_FILENAME }, { "background.titlemessage_initial_4",UNDEFINED_FILENAME }, { "background.titlemessage_initial_5",UNDEFINED_FILENAME }, { "background.titlemessage_1", UNDEFINED_FILENAME }, { "background.titlemessage_2", UNDEFINED_FILENAME }, { "background.titlemessage_3", UNDEFINED_FILENAME }, { "background.titlemessage_4", UNDEFINED_FILENAME }, { "background.titlemessage_5", UNDEFINED_FILENAME }, { NULL, NULL } }; mirrormagic-3.0.0/src/conf_cus.h0000644000175000017500000003101313263214151016066 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_cus.h // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CUS_H #define CONF_CUS_H /* values for elements configuration (custom elements) */ #define EL_CUSTOM_1 (EL_CUSTOM_START + 0) #define EL_CUSTOM_2 (EL_CUSTOM_START + 1) #define EL_CUSTOM_3 (EL_CUSTOM_START + 2) #define EL_CUSTOM_4 (EL_CUSTOM_START + 3) #define EL_CUSTOM_5 (EL_CUSTOM_START + 4) #define EL_CUSTOM_6 (EL_CUSTOM_START + 5) #define EL_CUSTOM_7 (EL_CUSTOM_START + 6) #define EL_CUSTOM_8 (EL_CUSTOM_START + 7) #define EL_CUSTOM_9 (EL_CUSTOM_START + 8) #define EL_CUSTOM_10 (EL_CUSTOM_START + 9) #define EL_CUSTOM_11 (EL_CUSTOM_START + 10) #define EL_CUSTOM_12 (EL_CUSTOM_START + 11) #define EL_CUSTOM_13 (EL_CUSTOM_START + 12) #define EL_CUSTOM_14 (EL_CUSTOM_START + 13) #define EL_CUSTOM_15 (EL_CUSTOM_START + 14) #define EL_CUSTOM_16 (EL_CUSTOM_START + 15) #define EL_CUSTOM_17 (EL_CUSTOM_START + 16) #define EL_CUSTOM_18 (EL_CUSTOM_START + 17) #define EL_CUSTOM_19 (EL_CUSTOM_START + 18) #define EL_CUSTOM_20 (EL_CUSTOM_START + 19) #define EL_CUSTOM_21 (EL_CUSTOM_START + 20) #define EL_CUSTOM_22 (EL_CUSTOM_START + 21) #define EL_CUSTOM_23 (EL_CUSTOM_START + 22) #define EL_CUSTOM_24 (EL_CUSTOM_START + 23) #define EL_CUSTOM_25 (EL_CUSTOM_START + 24) #define EL_CUSTOM_26 (EL_CUSTOM_START + 25) #define EL_CUSTOM_27 (EL_CUSTOM_START + 26) #define EL_CUSTOM_28 (EL_CUSTOM_START + 27) #define EL_CUSTOM_29 (EL_CUSTOM_START + 28) #define EL_CUSTOM_30 (EL_CUSTOM_START + 29) #define EL_CUSTOM_31 (EL_CUSTOM_START + 30) #define EL_CUSTOM_32 (EL_CUSTOM_START + 31) #define EL_CUSTOM_33 (EL_CUSTOM_START + 32) #define EL_CUSTOM_34 (EL_CUSTOM_START + 33) #define EL_CUSTOM_35 (EL_CUSTOM_START + 34) #define EL_CUSTOM_36 (EL_CUSTOM_START + 35) #define EL_CUSTOM_37 (EL_CUSTOM_START + 36) #define EL_CUSTOM_38 (EL_CUSTOM_START + 37) #define EL_CUSTOM_39 (EL_CUSTOM_START + 38) #define EL_CUSTOM_40 (EL_CUSTOM_START + 39) #define EL_CUSTOM_41 (EL_CUSTOM_START + 40) #define EL_CUSTOM_42 (EL_CUSTOM_START + 41) #define EL_CUSTOM_43 (EL_CUSTOM_START + 42) #define EL_CUSTOM_44 (EL_CUSTOM_START + 43) #define EL_CUSTOM_45 (EL_CUSTOM_START + 44) #define EL_CUSTOM_46 (EL_CUSTOM_START + 45) #define EL_CUSTOM_47 (EL_CUSTOM_START + 46) #define EL_CUSTOM_48 (EL_CUSTOM_START + 47) #define EL_CUSTOM_49 (EL_CUSTOM_START + 48) #define EL_CUSTOM_50 (EL_CUSTOM_START + 49) #define EL_CUSTOM_51 (EL_CUSTOM_START + 50) #define EL_CUSTOM_52 (EL_CUSTOM_START + 51) #define EL_CUSTOM_53 (EL_CUSTOM_START + 52) #define EL_CUSTOM_54 (EL_CUSTOM_START + 53) #define EL_CUSTOM_55 (EL_CUSTOM_START + 54) #define EL_CUSTOM_56 (EL_CUSTOM_START + 55) #define EL_CUSTOM_57 (EL_CUSTOM_START + 56) #define EL_CUSTOM_58 (EL_CUSTOM_START + 57) #define EL_CUSTOM_59 (EL_CUSTOM_START + 58) #define EL_CUSTOM_60 (EL_CUSTOM_START + 59) #define EL_CUSTOM_61 (EL_CUSTOM_START + 60) #define EL_CUSTOM_62 (EL_CUSTOM_START + 61) #define EL_CUSTOM_63 (EL_CUSTOM_START + 62) #define EL_CUSTOM_64 (EL_CUSTOM_START + 63) #define EL_CUSTOM_65 (EL_CUSTOM_START + 64) #define EL_CUSTOM_66 (EL_CUSTOM_START + 65) #define EL_CUSTOM_67 (EL_CUSTOM_START + 66) #define EL_CUSTOM_68 (EL_CUSTOM_START + 67) #define EL_CUSTOM_69 (EL_CUSTOM_START + 68) #define EL_CUSTOM_70 (EL_CUSTOM_START + 69) #define EL_CUSTOM_71 (EL_CUSTOM_START + 70) #define EL_CUSTOM_72 (EL_CUSTOM_START + 71) #define EL_CUSTOM_73 (EL_CUSTOM_START + 72) #define EL_CUSTOM_74 (EL_CUSTOM_START + 73) #define EL_CUSTOM_75 (EL_CUSTOM_START + 74) #define EL_CUSTOM_76 (EL_CUSTOM_START + 75) #define EL_CUSTOM_77 (EL_CUSTOM_START + 76) #define EL_CUSTOM_78 (EL_CUSTOM_START + 77) #define EL_CUSTOM_79 (EL_CUSTOM_START + 78) #define EL_CUSTOM_80 (EL_CUSTOM_START + 79) #define EL_CUSTOM_81 (EL_CUSTOM_START + 80) #define EL_CUSTOM_82 (EL_CUSTOM_START + 81) #define EL_CUSTOM_83 (EL_CUSTOM_START + 82) #define EL_CUSTOM_84 (EL_CUSTOM_START + 83) #define EL_CUSTOM_85 (EL_CUSTOM_START + 84) #define EL_CUSTOM_86 (EL_CUSTOM_START + 85) #define EL_CUSTOM_87 (EL_CUSTOM_START + 86) #define EL_CUSTOM_88 (EL_CUSTOM_START + 87) #define EL_CUSTOM_89 (EL_CUSTOM_START + 88) #define EL_CUSTOM_90 (EL_CUSTOM_START + 89) #define EL_CUSTOM_91 (EL_CUSTOM_START + 90) #define EL_CUSTOM_92 (EL_CUSTOM_START + 91) #define EL_CUSTOM_93 (EL_CUSTOM_START + 92) #define EL_CUSTOM_94 (EL_CUSTOM_START + 93) #define EL_CUSTOM_95 (EL_CUSTOM_START + 94) #define EL_CUSTOM_96 (EL_CUSTOM_START + 95) #define EL_CUSTOM_97 (EL_CUSTOM_START + 96) #define EL_CUSTOM_98 (EL_CUSTOM_START + 97) #define EL_CUSTOM_99 (EL_CUSTOM_START + 98) #define EL_CUSTOM_100 (EL_CUSTOM_START + 99) #define EL_CUSTOM_101 (EL_CUSTOM_START + 100) #define EL_CUSTOM_102 (EL_CUSTOM_START + 101) #define EL_CUSTOM_103 (EL_CUSTOM_START + 102) #define EL_CUSTOM_104 (EL_CUSTOM_START + 103) #define EL_CUSTOM_105 (EL_CUSTOM_START + 104) #define EL_CUSTOM_106 (EL_CUSTOM_START + 105) #define EL_CUSTOM_107 (EL_CUSTOM_START + 106) #define EL_CUSTOM_108 (EL_CUSTOM_START + 107) #define EL_CUSTOM_109 (EL_CUSTOM_START + 108) #define EL_CUSTOM_110 (EL_CUSTOM_START + 109) #define EL_CUSTOM_111 (EL_CUSTOM_START + 110) #define EL_CUSTOM_112 (EL_CUSTOM_START + 111) #define EL_CUSTOM_113 (EL_CUSTOM_START + 112) #define EL_CUSTOM_114 (EL_CUSTOM_START + 113) #define EL_CUSTOM_115 (EL_CUSTOM_START + 114) #define EL_CUSTOM_116 (EL_CUSTOM_START + 115) #define EL_CUSTOM_117 (EL_CUSTOM_START + 116) #define EL_CUSTOM_118 (EL_CUSTOM_START + 117) #define EL_CUSTOM_119 (EL_CUSTOM_START + 118) #define EL_CUSTOM_120 (EL_CUSTOM_START + 119) #define EL_CUSTOM_121 (EL_CUSTOM_START + 120) #define EL_CUSTOM_122 (EL_CUSTOM_START + 121) #define EL_CUSTOM_123 (EL_CUSTOM_START + 122) #define EL_CUSTOM_124 (EL_CUSTOM_START + 123) #define EL_CUSTOM_125 (EL_CUSTOM_START + 124) #define EL_CUSTOM_126 (EL_CUSTOM_START + 125) #define EL_CUSTOM_127 (EL_CUSTOM_START + 126) #define EL_CUSTOM_128 (EL_CUSTOM_START + 127) #define EL_CUSTOM_129 (EL_CUSTOM_START + 128) #define EL_CUSTOM_130 (EL_CUSTOM_START + 129) #define EL_CUSTOM_131 (EL_CUSTOM_START + 130) #define EL_CUSTOM_132 (EL_CUSTOM_START + 131) #define EL_CUSTOM_133 (EL_CUSTOM_START + 132) #define EL_CUSTOM_134 (EL_CUSTOM_START + 133) #define EL_CUSTOM_135 (EL_CUSTOM_START + 134) #define EL_CUSTOM_136 (EL_CUSTOM_START + 135) #define EL_CUSTOM_137 (EL_CUSTOM_START + 136) #define EL_CUSTOM_138 (EL_CUSTOM_START + 137) #define EL_CUSTOM_139 (EL_CUSTOM_START + 138) #define EL_CUSTOM_140 (EL_CUSTOM_START + 139) #define EL_CUSTOM_141 (EL_CUSTOM_START + 140) #define EL_CUSTOM_142 (EL_CUSTOM_START + 141) #define EL_CUSTOM_143 (EL_CUSTOM_START + 142) #define EL_CUSTOM_144 (EL_CUSTOM_START + 143) #define EL_CUSTOM_145 (EL_CUSTOM_START + 144) #define EL_CUSTOM_146 (EL_CUSTOM_START + 145) #define EL_CUSTOM_147 (EL_CUSTOM_START + 146) #define EL_CUSTOM_148 (EL_CUSTOM_START + 147) #define EL_CUSTOM_149 (EL_CUSTOM_START + 148) #define EL_CUSTOM_150 (EL_CUSTOM_START + 149) #define EL_CUSTOM_151 (EL_CUSTOM_START + 150) #define EL_CUSTOM_152 (EL_CUSTOM_START + 151) #define EL_CUSTOM_153 (EL_CUSTOM_START + 152) #define EL_CUSTOM_154 (EL_CUSTOM_START + 153) #define EL_CUSTOM_155 (EL_CUSTOM_START + 154) #define EL_CUSTOM_156 (EL_CUSTOM_START + 155) #define EL_CUSTOM_157 (EL_CUSTOM_START + 156) #define EL_CUSTOM_158 (EL_CUSTOM_START + 157) #define EL_CUSTOM_159 (EL_CUSTOM_START + 158) #define EL_CUSTOM_160 (EL_CUSTOM_START + 159) #define EL_CUSTOM_161 (EL_CUSTOM_START + 160) #define EL_CUSTOM_162 (EL_CUSTOM_START + 161) #define EL_CUSTOM_163 (EL_CUSTOM_START + 162) #define EL_CUSTOM_164 (EL_CUSTOM_START + 163) #define EL_CUSTOM_165 (EL_CUSTOM_START + 164) #define EL_CUSTOM_166 (EL_CUSTOM_START + 165) #define EL_CUSTOM_167 (EL_CUSTOM_START + 166) #define EL_CUSTOM_168 (EL_CUSTOM_START + 167) #define EL_CUSTOM_169 (EL_CUSTOM_START + 168) #define EL_CUSTOM_170 (EL_CUSTOM_START + 169) #define EL_CUSTOM_171 (EL_CUSTOM_START + 170) #define EL_CUSTOM_172 (EL_CUSTOM_START + 171) #define EL_CUSTOM_173 (EL_CUSTOM_START + 172) #define EL_CUSTOM_174 (EL_CUSTOM_START + 173) #define EL_CUSTOM_175 (EL_CUSTOM_START + 174) #define EL_CUSTOM_176 (EL_CUSTOM_START + 175) #define EL_CUSTOM_177 (EL_CUSTOM_START + 176) #define EL_CUSTOM_178 (EL_CUSTOM_START + 177) #define EL_CUSTOM_179 (EL_CUSTOM_START + 178) #define EL_CUSTOM_180 (EL_CUSTOM_START + 179) #define EL_CUSTOM_181 (EL_CUSTOM_START + 180) #define EL_CUSTOM_182 (EL_CUSTOM_START + 181) #define EL_CUSTOM_183 (EL_CUSTOM_START + 182) #define EL_CUSTOM_184 (EL_CUSTOM_START + 183) #define EL_CUSTOM_185 (EL_CUSTOM_START + 184) #define EL_CUSTOM_186 (EL_CUSTOM_START + 185) #define EL_CUSTOM_187 (EL_CUSTOM_START + 186) #define EL_CUSTOM_188 (EL_CUSTOM_START + 187) #define EL_CUSTOM_189 (EL_CUSTOM_START + 188) #define EL_CUSTOM_190 (EL_CUSTOM_START + 189) #define EL_CUSTOM_191 (EL_CUSTOM_START + 190) #define EL_CUSTOM_192 (EL_CUSTOM_START + 191) #define EL_CUSTOM_193 (EL_CUSTOM_START + 192) #define EL_CUSTOM_194 (EL_CUSTOM_START + 193) #define EL_CUSTOM_195 (EL_CUSTOM_START + 194) #define EL_CUSTOM_196 (EL_CUSTOM_START + 195) #define EL_CUSTOM_197 (EL_CUSTOM_START + 196) #define EL_CUSTOM_198 (EL_CUSTOM_START + 197) #define EL_CUSTOM_199 (EL_CUSTOM_START + 198) #define EL_CUSTOM_200 (EL_CUSTOM_START + 199) #define EL_CUSTOM_201 (EL_CUSTOM_START + 200) #define EL_CUSTOM_202 (EL_CUSTOM_START + 201) #define EL_CUSTOM_203 (EL_CUSTOM_START + 202) #define EL_CUSTOM_204 (EL_CUSTOM_START + 203) #define EL_CUSTOM_205 (EL_CUSTOM_START + 204) #define EL_CUSTOM_206 (EL_CUSTOM_START + 205) #define EL_CUSTOM_207 (EL_CUSTOM_START + 206) #define EL_CUSTOM_208 (EL_CUSTOM_START + 207) #define EL_CUSTOM_209 (EL_CUSTOM_START + 208) #define EL_CUSTOM_210 (EL_CUSTOM_START + 209) #define EL_CUSTOM_211 (EL_CUSTOM_START + 210) #define EL_CUSTOM_212 (EL_CUSTOM_START + 211) #define EL_CUSTOM_213 (EL_CUSTOM_START + 212) #define EL_CUSTOM_214 (EL_CUSTOM_START + 213) #define EL_CUSTOM_215 (EL_CUSTOM_START + 214) #define EL_CUSTOM_216 (EL_CUSTOM_START + 215) #define EL_CUSTOM_217 (EL_CUSTOM_START + 216) #define EL_CUSTOM_218 (EL_CUSTOM_START + 217) #define EL_CUSTOM_219 (EL_CUSTOM_START + 218) #define EL_CUSTOM_220 (EL_CUSTOM_START + 219) #define EL_CUSTOM_221 (EL_CUSTOM_START + 220) #define EL_CUSTOM_222 (EL_CUSTOM_START + 221) #define EL_CUSTOM_223 (EL_CUSTOM_START + 222) #define EL_CUSTOM_224 (EL_CUSTOM_START + 223) #define EL_CUSTOM_225 (EL_CUSTOM_START + 224) #define EL_CUSTOM_226 (EL_CUSTOM_START + 225) #define EL_CUSTOM_227 (EL_CUSTOM_START + 226) #define EL_CUSTOM_228 (EL_CUSTOM_START + 227) #define EL_CUSTOM_229 (EL_CUSTOM_START + 228) #define EL_CUSTOM_230 (EL_CUSTOM_START + 229) #define EL_CUSTOM_231 (EL_CUSTOM_START + 230) #define EL_CUSTOM_232 (EL_CUSTOM_START + 231) #define EL_CUSTOM_233 (EL_CUSTOM_START + 232) #define EL_CUSTOM_234 (EL_CUSTOM_START + 233) #define EL_CUSTOM_235 (EL_CUSTOM_START + 234) #define EL_CUSTOM_236 (EL_CUSTOM_START + 235) #define EL_CUSTOM_237 (EL_CUSTOM_START + 236) #define EL_CUSTOM_238 (EL_CUSTOM_START + 237) #define EL_CUSTOM_239 (EL_CUSTOM_START + 238) #define EL_CUSTOM_240 (EL_CUSTOM_START + 239) #define EL_CUSTOM_241 (EL_CUSTOM_START + 240) #define EL_CUSTOM_242 (EL_CUSTOM_START + 241) #define EL_CUSTOM_243 (EL_CUSTOM_START + 242) #define EL_CUSTOM_244 (EL_CUSTOM_START + 243) #define EL_CUSTOM_245 (EL_CUSTOM_START + 244) #define EL_CUSTOM_246 (EL_CUSTOM_START + 245) #define EL_CUSTOM_247 (EL_CUSTOM_START + 246) #define EL_CUSTOM_248 (EL_CUSTOM_START + 247) #define EL_CUSTOM_249 (EL_CUSTOM_START + 248) #define EL_CUSTOM_250 (EL_CUSTOM_START + 249) #define EL_CUSTOM_251 (EL_CUSTOM_START + 250) #define EL_CUSTOM_252 (EL_CUSTOM_START + 251) #define EL_CUSTOM_253 (EL_CUSTOM_START + 252) #define EL_CUSTOM_254 (EL_CUSTOM_START + 253) #define EL_CUSTOM_255 (EL_CUSTOM_START + 254) #define EL_CUSTOM_256 (EL_CUSTOM_START + 255) #endif /* CONF_CUS_C */ mirrormagic-3.0.0/src/init.c0000644000175000017500000053477313263212010015242 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // init.c // ============================================================================ #include "libgame/libgame.h" #include "init.h" #include "events.h" #include "screens.h" #include "editor.h" #include "game.h" #include "tape.h" #include "tools.h" #include "files.h" #include "network.h" #include "netserv.h" #include "anim.h" #include "config.h" #include "conf_e2g.c" /* include auto-generated data structure definitions */ #include "conf_esg.c" /* include auto-generated data structure definitions */ #include "conf_e2s.c" /* include auto-generated data structure definitions */ #include "conf_fnt.c" /* include auto-generated data structure definitions */ #include "conf_g2s.c" /* include auto-generated data structure definitions */ #include "conf_g2m.c" /* include auto-generated data structure definitions */ #include "conf_act.c" /* include auto-generated data structure definitions */ #define CONFIG_TOKEN_FONT_INITIAL "font.initial" #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy" static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS]; static struct GraphicInfo anim_initial; static int copy_properties[][5] = { { EL_BUG, EL_BUG_LEFT, EL_BUG_RIGHT, EL_BUG_UP, EL_BUG_DOWN }, { EL_SPACESHIP, EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT, EL_SPACESHIP_UP, EL_SPACESHIP_DOWN }, { EL_BD_BUTTERFLY, EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT, EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN }, { EL_BD_FIREFLY, EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT, EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN }, { EL_PACMAN, EL_PACMAN_LEFT, EL_PACMAN_RIGHT, EL_PACMAN_UP, EL_PACMAN_DOWN }, { EL_YAMYAM, EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT, EL_YAMYAM_UP, EL_YAMYAM_DOWN }, { EL_MOLE, EL_MOLE_LEFT, EL_MOLE_RIGHT, EL_MOLE_UP, EL_MOLE_DOWN }, { -1, -1, -1, -1, -1 } }; /* forward declaration for internal use */ static int get_graphic_parameter_value(char *, char *, int); void DrawInitAnim() { struct GraphicInfo *graphic_info_last = graphic_info; int graphic = 0; static unsigned int action_delay = 0; unsigned int action_delay_value = GameFrameDelay; int sync_frame = FrameCounter; int x, y; /* prevent OS (Windows) from complaining about program not responding */ CheckQuitEvent(); if (game_status != GAME_MODE_LOADING) return; if (anim_initial.bitmap == NULL || window == NULL) return; if (!DelayReached(&action_delay, action_delay_value)) return; if (init_last.busy.x == -1) init_last.busy.x = WIN_XSIZE / 2; if (init_last.busy.y == -1) init_last.busy.y = WIN_YSIZE / 2; x = ALIGNED_TEXT_XPOS(&init_last.busy); y = ALIGNED_TEXT_YPOS(&init_last.busy); graphic_info = &anim_initial; /* graphic == 0 => anim_initial */ if (sync_frame % anim_initial.anim_delay == 0) { Bitmap *src_bitmap; int src_x, src_y; int width = graphic_info[graphic].width; int height = graphic_info[graphic].height; int frame = getGraphicAnimationFrame(graphic, sync_frame); getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y); } graphic_info = graphic_info_last; FrameCounter++; } void FreeGadgets() { FreeLevelEditorGadgets(); FreeGameButtons(); FreeTapeButtons(); FreeToolButtons(); FreeScreenGadgets(); } void InitGadgets() { static boolean gadgets_initialized = FALSE; if (gadgets_initialized) FreeGadgets(); CreateLevelEditorGadgets(); CreateGameButtons(); CreateTapeButtons(); CreateToolButtons(); CreateScreenGadgets(); InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting); gadgets_initialized = TRUE; } inline static void InitElementSmallImagesScaledUp(int graphic) { struct GraphicInfo *g = &graphic_info[graphic]; // create small and game tile sized bitmaps (and scale up, if needed) CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size); } void InitElementSmallImages() { print_timestamp_init("InitElementSmallImages"); static int special_graphics[] = { IMG_FLAMES_1_LEFT, IMG_FLAMES_2_LEFT, IMG_FLAMES_3_LEFT, IMG_FLAMES_1_RIGHT, IMG_FLAMES_2_RIGHT, IMG_FLAMES_3_RIGHT, IMG_FLAMES_1_UP, IMG_FLAMES_2_UP, IMG_FLAMES_3_UP, IMG_FLAMES_1_DOWN, IMG_FLAMES_2_DOWN, IMG_FLAMES_3_DOWN, IMG_EDITOR_ELEMENT_BORDER, IMG_EDITOR_ELEMENT_BORDER_INPUT, IMG_EDITOR_CASCADE_LIST, IMG_EDITOR_CASCADE_LIST_ACTIVE, -1 }; struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i; print_timestamp_time("getImageListPropertyMapping/Size"); print_timestamp_init("InitElementSmallImagesScaledUp (1)"); /* initialize normal element images from static configuration */ for (i = 0; element_to_graphic[i].element > -1; i++) InitElementSmallImagesScaledUp(element_to_graphic[i].graphic); print_timestamp_done("InitElementSmallImagesScaledUp (1)"); /* initialize special element images from static configuration */ for (i = 0; element_to_special_graphic[i].element > -1; i++) InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic); print_timestamp_time("InitElementSmallImagesScaledUp (2)"); /* initialize element images from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) if (property_mapping[i].base_index < MAX_NUM_ELEMENTS) InitElementSmallImagesScaledUp(property_mapping[i].artwork_index); print_timestamp_time("InitElementSmallImagesScaledUp (3)"); /* initialize special non-element images from above list */ for (i = 0; special_graphics[i] > -1; i++) InitElementSmallImagesScaledUp(special_graphics[i]); print_timestamp_time("InitElementSmallImagesScaledUp (4)"); print_timestamp_done("InitElementSmallImages"); } inline static void InitScaledImagesScaledUp(int graphic) { struct GraphicInfo *g = &graphic_info[graphic]; ScaleImage(graphic, g->scale_up_factor); } void InitScaledImages() { struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i; /* scale normal images from static configuration, if not already scaled */ for (i = 0; i < NUM_IMAGE_FILES; i++) InitScaledImagesScaledUp(i); /* scale images from dynamic configuration, if not already scaled */ for (i = 0; i < num_property_mappings; i++) InitScaledImagesScaledUp(property_mapping[i].artwork_index); } void InitBitmapPointers() { int num_images = getImageListSize(); int i; // standard size bitmap may have changed -- update default bitmap pointer for (i = 0; i < num_images; i++) if (graphic_info[i].bitmaps) graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD]; } void InitImageTextures() { int i, j, k; FreeAllImageTextures(); for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++) CreateImageTextures(i); for (i = 0; i < MAX_NUM_TOONS; i++) CreateImageTextures(IMG_TOON_1 + i); for (i = 0; i < NUM_GLOBAL_ANIMS; i++) { for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) { for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) { int graphic = global_anim_info[i].graphic[j][k]; if (graphic == IMG_UNDEFINED) continue; CreateImageTextures(graphic); } } } } #if 1 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */ void SetBitmaps_EM(Bitmap **em_bitmap) { em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap; em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap; } #endif #if 0 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */ void SetBitmaps_SP(Bitmap **sp_bitmap) { *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap; } #endif static int getFontBitmapID(int font_nr) { int special = -1; /* (special case: do not use special font for GAME_MODE_LOADING) */ if (game_status >= GAME_MODE_TITLE_INITIAL && game_status <= GAME_MODE_PSEUDO_PREVIEW) special = game_status; else if (game_status == GAME_MODE_PSEUDO_TYPENAME) special = GFX_SPECIAL_ARG_MAIN; if (special != -1) return font_info[font_nr].special_bitmap_id[special]; else return font_nr; } static int getFontFromToken(char *token) { char *value = getHashEntry(font_token_hash, token); if (value != NULL) return atoi(value); /* if font not found, use reliable default value */ return FONT_INITIAL_1; } void InitFontGraphicInfo() { static struct FontBitmapInfo *font_bitmap_info = NULL; struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int num_font_bitmaps = NUM_FONTS; int i, j; if (graphic_info == NULL) /* still at startup phase */ { InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID, getFontFromToken); return; } /* ---------- initialize font graphic definitions ---------- */ /* always start with reliable default values (normal font graphics) */ for (i = 0; i < NUM_FONTS; i++) font_info[i].graphic = IMG_FONT_INITIAL_1; /* initialize normal font/graphic mapping from static configuration */ for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; int graphic = font_to_graphic[i].graphic; if (special != -1) continue; font_info[font_nr].graphic = graphic; } /* always start with reliable default values (special font graphics) */ for (i = 0; i < NUM_FONTS; i++) { for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { font_info[i].special_graphic[j] = font_info[i].graphic; font_info[i].special_bitmap_id[j] = i; } } /* initialize special font/graphic mapping from static configuration */ for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; int graphic = font_to_graphic[i].graphic; int base_graphic = font2baseimg(font_nr); if (IS_SPECIAL_GFX_ARG(special)) { boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean special_redefined = getImageListEntryFromImageID(graphic)->redefined; boolean special_cloned = (graphic_info[graphic].clone_from != -1); /* if the base font ("font.title_1", for example) has been redefined, but not the special font ("font.title_1.LEVELS", for example), do not use an existing (in this case considered obsolete) special font anymore, but use the automatically determined default font */ /* special case: cloned special fonts must be explicitly redefined, but are not automatically redefined by redefining base font */ if (base_redefined && !special_redefined && !special_cloned) continue; font_info[font_nr].special_graphic[special] = graphic; font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps; num_font_bitmaps++; } } /* initialize special font/graphic mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; if (font_nr < 0 || font_nr >= NUM_FONTS) continue; if (IS_SPECIAL_GFX_ARG(special)) { font_info[font_nr].special_graphic[special] = graphic; font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps; num_font_bitmaps++; } } /* correct special font/graphic mapping for cloned fonts for downwards compatibility of PREVIEW fonts -- this is only needed for implicit redefinition of special font by redefined base font, and only if other fonts are cloned from this special font (like in the "Zelda" level set) */ for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; int graphic = font_to_graphic[i].graphic; if (IS_SPECIAL_GFX_ARG(special)) { boolean special_redefined = getImageListEntryFromImageID(graphic)->redefined; boolean special_cloned = (graphic_info[graphic].clone_from != -1); if (special_cloned && !special_redefined) { int j; for (j = 0; font_to_graphic[j].font_nr > -1; j++) { int font_nr2 = font_to_graphic[j].font_nr; int special2 = font_to_graphic[j].special; int graphic2 = font_to_graphic[j].graphic; if (IS_SPECIAL_GFX_ARG(special2) && graphic2 == graphic_info[graphic].clone_from) { font_info[font_nr].special_graphic[special] = font_info[font_nr2].special_graphic[special2]; font_info[font_nr].special_bitmap_id[special] = font_info[font_nr2].special_bitmap_id[special2]; } } } } } /* reset non-redefined ".active" font graphics if normal font is redefined */ /* (this different treatment is needed because normal and active fonts are independently defined ("active" is not a property of font definitions!) */ for (i = 0; i < NUM_FONTS; i++) { int font_nr_base = i; int font_nr_active = FONT_ACTIVE(font_nr_base); /* check only those fonts with exist as normal and ".active" variant */ if (font_nr_base != font_nr_active) { int base_graphic = font_info[font_nr_base].graphic; int active_graphic = font_info[font_nr_active].graphic; boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean active_redefined = getImageListEntryFromImageID(active_graphic)->redefined; /* if the base font ("font.menu_1", for example) has been redefined, but not the active font ("font.menu_1.active", for example), do not use an existing (in this case considered obsolete) active font anymore, but use the automatically determined default font */ if (base_redefined && !active_redefined) font_info[font_nr_active].graphic = base_graphic; /* now also check each "special" font (which may be the same as above) */ for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { int base_graphic = font_info[font_nr_base].special_graphic[j]; int active_graphic = font_info[font_nr_active].special_graphic[j]; boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean active_redefined = getImageListEntryFromImageID(active_graphic)->redefined; /* same as above, but check special graphic definitions, for example: redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */ if (base_redefined && !active_redefined) { font_info[font_nr_active].special_graphic[j] = font_info[font_nr_base].special_graphic[j]; font_info[font_nr_active].special_bitmap_id[j] = font_info[font_nr_base].special_bitmap_id[j]; } } } } /* ---------- initialize font bitmap array ---------- */ if (font_bitmap_info != NULL) FreeFontInfo(font_bitmap_info); font_bitmap_info = checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo)); /* ---------- initialize font bitmap definitions ---------- */ for (i = 0; i < NUM_FONTS; i++) { if (i < NUM_INITIAL_FONTS) { font_bitmap_info[i] = font_initial[i]; continue; } for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { int font_bitmap_id = font_info[i].special_bitmap_id[j]; int graphic = font_info[i].special_graphic[j]; /* set 'graphic_info' for font entries, if uninitialized (guessed) */ if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT) { graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT; graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE; } /* copy font relevant information from graphics information */ font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap; font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x; font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y; font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width; font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height; font_bitmap_info[font_bitmap_id].offset_x = graphic_info[graphic].offset_x; font_bitmap_info[font_bitmap_id].offset_y = graphic_info[graphic].offset_y; font_bitmap_info[font_bitmap_id].draw_xoffset = graphic_info[graphic].draw_xoffset; font_bitmap_info[font_bitmap_id].draw_yoffset = graphic_info[graphic].draw_yoffset; font_bitmap_info[font_bitmap_id].num_chars = graphic_info[graphic].anim_frames; font_bitmap_info[font_bitmap_id].num_chars_per_line = graphic_info[graphic].anim_frames_per_line; } } InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID, getFontFromToken); } void InitGlobalAnimGraphicInfo() { struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i, j, k; if (graphic_info == NULL) /* still at startup phase */ return; /* always start with reliable default values (no global animations) */ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) global_anim_info[i].graphic[j][k] = IMG_UNDEFINED; /* initialize global animation definitions from static configuration */ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) { int j = GLOBAL_ANIM_ID_PART_BASE; int k = GFX_SPECIAL_ARG_DEFAULT; global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i; } /* initialize global animation definitions from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS; int part_nr = property_mapping[i].ext1_index - ACTION_PART_1; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS) continue; /* set animation part to base part, if not specified */ if (!IS_GLOBAL_ANIM_PART(part_nr)) part_nr = GLOBAL_ANIM_ID_PART_BASE; /* set animation screen to default, if not specified */ if (!IS_SPECIAL_GFX_ARG(special)) special = GFX_SPECIAL_ARG_DEFAULT; global_anim_info[anim_nr].graphic[part_nr][special] = graphic; /* fix default value for ".draw_masked" (for backward compatibility) */ struct GraphicInfo *g = &graphic_info[graphic]; struct FileInfo *image = getImageListEntryFromImageID(graphic); char **parameter_raw = image->parameter; int p = GFX_ARG_DRAW_MASKED; int draw_masked = get_graphic_parameter_value(parameter_raw[p], image_config_suffix[p].token, image_config_suffix[p].type); /* if ".draw_masked" parameter is undefined, use default value "TRUE" */ if (draw_masked == ARG_UNDEFINED_VALUE) g->draw_masked = TRUE; } #if 0 printf("::: InitGlobalAnimGraphicInfo\n"); for (i = 0; i < NUM_GLOBAL_ANIMS; i++) for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED && graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL) printf("::: - anim %d, part %d, mode %d => %d\n", i, j, k, global_anim_info[i].graphic[j][k]); #endif } void InitGlobalAnimSoundInfo() { struct PropertyMapping *property_mapping = getSoundListPropertyMapping(); int num_property_mappings = getSoundListPropertyMappingSize(); int i, j, k; /* always start with reliable default values (no global animation sounds) */ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) global_anim_info[i].sound[j][k] = SND_UNDEFINED; /* initialize global animation sound definitions from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS; int part_nr = property_mapping[i].ext1_index - ACTION_PART_1; int special = property_mapping[i].ext3_index; int sound = property_mapping[i].artwork_index; // sound uses control definition; map it to position of graphic (artwork) anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST; if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS) continue; /* set animation part to base part, if not specified */ if (!IS_GLOBAL_ANIM_PART(part_nr)) part_nr = GLOBAL_ANIM_ID_PART_BASE; /* set animation screen to default, if not specified */ if (!IS_SPECIAL_GFX_ARG(special)) special = GFX_SPECIAL_ARG_DEFAULT; global_anim_info[anim_nr].sound[part_nr][special] = sound; } #if 0 printf("::: InitGlobalAnimSoundInfo\n"); for (i = 0; i < NUM_GLOBAL_ANIMS; i++) for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) if (global_anim_info[i].sound[j][k] != SND_UNDEFINED) printf("::: - anim %d, part %d, mode %d => %d\n", i, j, k, global_anim_info[i].sound[j][k]); #endif } void InitGlobalAnimMusicInfo() { struct PropertyMapping *property_mapping = getMusicListPropertyMapping(); int num_property_mappings = getMusicListPropertyMappingSize(); int i, j, k; /* always start with reliable default values (no global animation music) */ for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) global_anim_info[i].music[j][k] = MUS_UNDEFINED; /* initialize global animation music definitions from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES; int part_nr = property_mapping[i].ext1_index - ACTION_PART_1; int special = property_mapping[i].ext2_index; int music = property_mapping[i].artwork_index; // music uses control definition; map it to position of graphic (artwork) anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST; if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS) continue; /* set animation part to base part, if not specified */ if (!IS_GLOBAL_ANIM_PART(part_nr)) part_nr = GLOBAL_ANIM_ID_PART_BASE; /* set animation screen to default, if not specified */ if (!IS_SPECIAL_GFX_ARG(special)) special = GFX_SPECIAL_ARG_DEFAULT; global_anim_info[anim_nr].music[part_nr][special] = music; } #if 0 printf("::: InitGlobalAnimMusicInfo\n"); for (i = 0; i < NUM_GLOBAL_ANIMS; i++) for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++) for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++) if (global_anim_info[i].music[j][k] != MUS_UNDEFINED) printf("::: - anim %d, part %d, mode %d => %d\n", i, j, k, global_anim_info[i].music[j][k]); #endif } void InitElementGraphicInfo() { struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i, act, dir; if (graphic_info == NULL) /* still at startup phase */ return; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { element_info[i].graphic[act] = -1; element_info[i].crumbled[act] = -1; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { element_info[i].direction_graphic[act][dir] = -1; element_info[i].direction_crumbled[act][dir] = -1; } } } UPDATE_BUSY_STATE(); /* initialize normal element/graphic mapping from static configuration */ for (i = 0; element_to_graphic[i].element > -1; i++) { int element = element_to_graphic[i].element; int action = element_to_graphic[i].action; int direction = element_to_graphic[i].direction; boolean crumbled = element_to_graphic[i].crumbled; int graphic = element_to_graphic[i].graphic; int base_graphic = el2baseimg(element); if (graphic_info[graphic].bitmap == NULL) continue; if ((action > -1 || direction > -1 || crumbled == TRUE) && base_graphic != -1) { boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean act_dir_redefined = getImageListEntryFromImageID(graphic)->redefined; /* if the base graphic ("emerald", for example) has been redefined, but not the action graphic ("emerald.falling", for example), do not use an existing (in this case considered obsolete) action graphic anymore, but use the automatically determined default graphic */ if (base_redefined && !act_dir_redefined) continue; } if (action < 0) action = ACTION_DEFAULT; if (crumbled) { if (direction > -1) element_info[element].direction_crumbled[action][direction] = graphic; else element_info[element].crumbled[action] = graphic; } else { if (direction > -1) element_info[element].direction_graphic[action][direction] = graphic; else element_info[element].graphic[action] = graphic; } } /* initialize normal element/graphic mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; int direction = property_mapping[i].ext2_index; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; boolean crumbled = FALSE; if (special == GFX_SPECIAL_ARG_CRUMBLED) { special = -1; crumbled = TRUE; } if (graphic_info[graphic].bitmap == NULL) continue; if (element >= MAX_NUM_ELEMENTS || special != -1) continue; if (action < 0) action = ACTION_DEFAULT; if (crumbled) { if (direction < 0) for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[element].direction_crumbled[action][dir] = -1; if (direction > -1) element_info[element].direction_crumbled[action][direction] = graphic; else element_info[element].crumbled[action] = graphic; } else { if (direction < 0) for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[element].direction_graphic[action][dir] = -1; if (direction > -1) element_info[element].direction_graphic[action][direction] = graphic; else element_info[element].graphic[action] = graphic; } } /* now copy all graphics that are defined to be cloned from other graphics */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { int graphic = element_info[i].graphic[ACTION_DEFAULT]; int crumbled_like, diggable_like; if (graphic == -1) continue; crumbled_like = graphic_info[graphic].crumbled_like; diggable_like = graphic_info[graphic].diggable_like; if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1) { for (act = 0; act < NUM_ACTIONS; act++) element_info[i].crumbled[act] = element_info[crumbled_like].crumbled[act]; for (act = 0; act < NUM_ACTIONS; act++) for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[i].direction_crumbled[act][dir] = element_info[crumbled_like].direction_crumbled[act][dir]; } if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1) { element_info[i].graphic[ACTION_DIGGING] = element_info[diggable_like].graphic[ACTION_DIGGING]; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) element_info[i].direction_graphic[ACTION_DIGGING][dir] = element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir]; } } /* set hardcoded definitions for some runtime elements without graphic */ element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD; /* set hardcoded definitions for some internal elements without graphic */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_EDITOR_CASCADE_INACTIVE(i)) element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST; else if (IS_EDITOR_CASCADE_ACTIVE(i)) element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE; } /* now set all undefined/invalid graphics to -1 to set to default after it */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { int graphic; graphic = element_info[i].graphic[act]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].graphic[act] = -1; graphic = element_info[i].crumbled[act]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].crumbled[act] = -1; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { graphic = element_info[i].direction_graphic[act][dir]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].direction_graphic[act][dir] = -1; graphic = element_info[i].direction_crumbled[act][dir]; if (graphic > 0 && graphic_info[graphic].bitmap == NULL) element_info[i].direction_crumbled[act][dir] = -1; } } } UPDATE_BUSY_STATE(); /* adjust graphics with 2nd tile for movement according to direction (do this before correcting '-1' values to minimize calculations) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { int graphic = element_info[i].direction_graphic[act][dir]; int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir); if (act == ACTION_FALLING) /* special case */ graphic = element_info[i].graphic[act]; if (graphic != -1 && graphic_info[graphic].double_movement && graphic_info[graphic].swap_double_tiles != 0) { struct GraphicInfo *g = &graphic_info[graphic]; int src_x_front = g->src_x; int src_y_front = g->src_y; int src_x_back = g->src_x + g->offset2_x; int src_y_back = g->src_y + g->offset2_y; boolean frames_are_ordered_diagonally = (g->offset_x != 0 && g->offset_y != 0); boolean front_is_left_or_upper = (src_x_front < src_x_back || src_y_front < src_y_back); boolean swap_movement_tiles_always = (g->swap_double_tiles == 1); boolean swap_movement_tiles_autodetected = (!frames_are_ordered_diagonally && ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) || (move_dir == MV_BIT_UP && !front_is_left_or_upper) || (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) || (move_dir == MV_BIT_DOWN && front_is_left_or_upper))); /* swap frontside and backside graphic tile coordinates, if needed */ if (swap_movement_tiles_always || swap_movement_tiles_autodetected) { /* get current (wrong) backside tile coordinates */ getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE); /* set frontside tile coordinates to backside tile coordinates */ g->src_x = src_x_back; g->src_y = src_y_back; /* invert tile offset to point to new backside tile coordinates */ g->offset2_x *= -1; g->offset2_y *= -1; /* do not swap front and backside tiles again after correction */ g->swap_double_tiles = 0; } } } } } UPDATE_BUSY_STATE(); /* now set all '-1' values to element specific default values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { int default_graphic = element_info[i].graphic[ACTION_DEFAULT]; int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT]; int default_direction_graphic[NUM_DIRECTIONS_FULL]; int default_direction_crumbled[NUM_DIRECTIONS_FULL]; if (default_graphic == -1) default_graphic = IMG_UNKNOWN; if (default_crumbled == -1) default_crumbled = default_graphic; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { default_direction_graphic[dir] = element_info[i].direction_graphic[ACTION_DEFAULT][dir]; default_direction_crumbled[dir] = element_info[i].direction_crumbled[ACTION_DEFAULT][dir]; if (default_direction_graphic[dir] == -1) default_direction_graphic[dir] = default_graphic; if (default_direction_crumbled[dir] == -1) default_direction_crumbled[dir] = default_direction_graphic[dir]; } for (act = 0; act < NUM_ACTIONS; act++) { boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) || (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) || (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING)); boolean act_turning = (act == ACTION_TURNING_FROM_LEFT || act == ACTION_TURNING_FROM_RIGHT || act == ACTION_TURNING_FROM_UP || act == ACTION_TURNING_FROM_DOWN); /* generic default action graphic (defined by "[default]" directive) */ int default_action_graphic = element_info[EL_DEFAULT].graphic[act]; int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act]; int default_remove_graphic = IMG_EMPTY; if (act_remove && default_action_graphic != -1) default_remove_graphic = default_action_graphic; /* look for special default action graphic (classic game specific) */ if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act]; if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act]; if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act]; if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1) default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act]; if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act]; if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act]; if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act]; if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1) default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act]; /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */ /* !!! make this better !!! */ if (i == EL_EMPTY_SPACE) { default_action_graphic = element_info[EL_DEFAULT].graphic[act]; default_action_crumbled = element_info[EL_DEFAULT].crumbled[act]; } if (default_action_graphic == -1) default_action_graphic = default_graphic; if (default_action_crumbled == -1) default_action_crumbled = default_action_graphic; for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++) { /* use action graphic as the default direction graphic, if undefined */ int default_action_direction_graphic = element_info[i].graphic[act]; int default_action_direction_crumbled = element_info[i].crumbled[act]; /* no graphic for current action -- use default direction graphic */ if (default_action_direction_graphic == -1) default_action_direction_graphic = (act_remove ? default_remove_graphic : act_turning ? element_info[i].direction_graphic[ACTION_TURNING][dir] : default_action_graphic != default_graphic ? default_action_graphic : default_direction_graphic[dir]); if (element_info[i].direction_graphic[act][dir] == -1) element_info[i].direction_graphic[act][dir] = default_action_direction_graphic; if (default_action_direction_crumbled == -1) default_action_direction_crumbled = element_info[i].direction_graphic[act][dir]; if (element_info[i].direction_crumbled[act][dir] == -1) element_info[i].direction_crumbled[act][dir] = default_action_direction_crumbled; } /* no graphic for this specific action -- use default action graphic */ if (element_info[i].graphic[act] == -1) element_info[i].graphic[act] = (act_remove ? default_remove_graphic : act_turning ? element_info[i].graphic[ACTION_TURNING] : default_action_graphic); if (element_info[i].crumbled[act] == -1) element_info[i].crumbled[act] = element_info[i].graphic[act]; } } UPDATE_BUSY_STATE(); } void InitElementSpecialGraphicInfo() { struct PropertyMapping *property_mapping = getImageListPropertyMapping(); int num_property_mappings = getImageListPropertyMappingSize(); int i, j; /* always start with reliable default values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) element_info[i].special_graphic[j] = element_info[i].graphic[ACTION_DEFAULT]; /* initialize special element/graphic mapping from static configuration */ for (i = 0; element_to_special_graphic[i].element > -1; i++) { int element = element_to_special_graphic[i].element; int special = element_to_special_graphic[i].special; int graphic = element_to_special_graphic[i].graphic; int base_graphic = el2baseimg(element); boolean base_redefined = getImageListEntryFromImageID(base_graphic)->redefined; boolean special_redefined = getImageListEntryFromImageID(graphic)->redefined; /* if the base graphic ("emerald", for example) has been redefined, but not the special graphic ("emerald.EDITOR", for example), do not use an existing (in this case considered obsolete) special graphic anymore, but use the automatically created (down-scaled) graphic */ if (base_redefined && !special_redefined) continue; element_info[element].special_graphic[special] = graphic; } /* initialize special element/graphic mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; int direction = property_mapping[i].ext2_index; int special = property_mapping[i].ext3_index; int graphic = property_mapping[i].artwork_index; /* for action ".active", replace element with active element, if exists */ if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element)) { element = ELEMENT_ACTIVE(element); action = -1; } if (element >= MAX_NUM_ELEMENTS) continue; /* do not change special graphic if action or direction was specified */ if (action != -1 || direction != -1) continue; if (IS_SPECIAL_GFX_ARG(special)) element_info[element].special_graphic[special] = graphic; } /* now set all undefined/invalid graphics to default */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL) element_info[i].special_graphic[j] = element_info[i].graphic[ACTION_DEFAULT]; } static int get_graphic_parameter_value(char *value_raw, char *suffix, int type) { if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC) return get_parameter_value(value_raw, suffix, type); if (strEqual(value_raw, ARG_UNDEFINED)) return ARG_UNDEFINED_VALUE; if (type == TYPE_ELEMENT) { char *value = getHashEntry(element_token_hash, value_raw); if (value == NULL) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "error: invalid element token '%s'", value_raw); Error(ERR_INFO, "custom graphic rejected for this element/action"); Error(ERR_INFO, "fallback done to undefined element for this graphic"); Error(ERR_INFO_LINE, "-"); } return (value != NULL ? atoi(value) : EL_UNDEFINED); } else if (type == TYPE_GRAPHIC) { char *value = getHashEntry(graphic_token_hash, value_raw); int fallback_graphic = IMG_CHAR_EXCLAM; if (value == NULL) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw); Error(ERR_INFO, "custom graphic rejected for this element/action"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); } return (value != NULL ? atoi(value) : fallback_graphic); } return -1; } static int get_scaled_graphic_width(int graphic) { int original_width = getOriginalImageWidthFromImageID(graphic); int scale_up_factor = graphic_info[graphic].scale_up_factor; return original_width * scale_up_factor; } static int get_scaled_graphic_height(int graphic) { int original_height = getOriginalImageHeightFromImageID(graphic); int scale_up_factor = graphic_info[graphic].scale_up_factor; return original_height * scale_up_factor; } static void set_graphic_parameters_ext(int graphic, int *parameter, Bitmap **src_bitmaps) { struct GraphicInfo *g = &graphic_info[graphic]; Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL); int anim_frames_per_row = 1, anim_frames_per_col = 1; int anim_frames_per_line = 1; /* always start with reliable default values */ g->src_image_width = 0; g->src_image_height = 0; g->src_x = 0; g->src_y = 0; g->width = TILEX; /* default for element graphics */ g->height = TILEY; /* default for element graphics */ g->offset_x = 0; /* one or both of these values ... */ g->offset_y = 0; /* ... will be corrected later */ g->offset2_x = 0; /* one or both of these values ... */ g->offset2_y = 0; /* ... will be corrected later */ g->swap_double_tiles = -1; /* auto-detect tile swapping */ g->crumbled_like = -1; /* do not use clone element */ g->diggable_like = -1; /* do not use clone element */ g->border_size = TILEX / 8; /* "CRUMBLED" border size */ g->scale_up_factor = 1; /* default: no scaling up */ g->tile_size = TILESIZE; /* default: standard tile size */ g->clone_from = -1; /* do not use clone graphic */ g->init_delay_fixed = 0; g->init_delay_random = 0; g->anim_delay_fixed = 0; g->anim_delay_random = 0; g->post_delay_fixed = 0; g->post_delay_random = 0; g->init_event = ANIM_EVENT_DEFAULT; g->anim_event = ANIM_EVENT_DEFAULT; g->draw_masked = FALSE; g->draw_order = 0; g->fade_mode = FADE_MODE_DEFAULT; g->fade_delay = -1; g->post_delay = -1; g->auto_delay = -1; g->align = ALIGN_CENTER; /* default for title screens */ g->valign = VALIGN_MIDDLE; /* default for title screens */ g->sort_priority = 0; /* default for title screens */ g->class = 0; g->style = STYLE_DEFAULT; g->bitmaps = src_bitmaps; g->bitmap = src_bitmap; /* optional zoom factor for scaling up the image to a larger size */ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE) g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR]; if (g->scale_up_factor < 1) g->scale_up_factor = 1; /* no scaling */ /* optional tile size for using non-standard image size */ if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE) { g->tile_size = parameter[GFX_ARG_TILE_SIZE]; #if 0 // CHECK: should tile sizes less than standard tile size be allowed? if (g->tile_size < TILESIZE) g->tile_size = TILESIZE; /* standard tile size */ #endif // when setting tile size, also set width and height accordingly g->width = g->tile_size; g->height = g->tile_size; } if (g->use_image_size) { /* set new default bitmap size (with scaling, but without small images) */ g->width = get_scaled_graphic_width(graphic); g->height = get_scaled_graphic_height(graphic); } /* optional width and height of each animation frame */ if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE) g->width = parameter[GFX_ARG_WIDTH]; if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE) g->height = parameter[GFX_ARG_HEIGHT]; /* optional x and y tile position of animation frame sequence */ if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE) g->src_x = parameter[GFX_ARG_XPOS] * g->width; if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE) g->src_y = parameter[GFX_ARG_YPOS] * g->height; /* optional x and y pixel position of animation frame sequence */ if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE) g->src_x = parameter[GFX_ARG_X]; if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE) g->src_y = parameter[GFX_ARG_Y]; if (src_bitmap) { if (g->width <= 0) { Error(ERR_INFO_LINE, "-"); Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)", g->width, getTokenFromImageID(graphic), TILEX); Error(ERR_INFO_LINE, "-"); g->width = TILEX; /* will be checked to be inside bitmap later */ } if (g->height <= 0) { Error(ERR_INFO_LINE, "-"); Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)", g->height, getTokenFromImageID(graphic), TILEY); Error(ERR_INFO_LINE, "-"); g->height = TILEY; /* will be checked to be inside bitmap later */ } } if (src_bitmap) { /* get final bitmap size (with scaling, but without small images) */ int src_image_width = get_scaled_graphic_width(graphic); int src_image_height = get_scaled_graphic_height(graphic); if (src_image_width == 0 || src_image_height == 0) { /* only happens when loaded outside artwork system (like "global.busy") */ src_image_width = src_bitmap->width; src_image_height = src_bitmap->height; } if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE) { anim_frames_per_row = MAX(1, src_image_width / g->tile_size); anim_frames_per_col = MAX(1, src_image_height / g->tile_size); } else { anim_frames_per_row = MAX(1, src_image_width / g->width); anim_frames_per_col = MAX(1, src_image_height / g->height); } g->src_image_width = src_image_width; g->src_image_height = src_image_height; } /* correct x or y offset dependent of vertical or horizontal frame order */ if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */ { g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_OFFSET] : g->height); anim_frames_per_line = anim_frames_per_col; } else /* frames are ordered horizontally */ { g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_OFFSET] : g->width); anim_frames_per_line = anim_frames_per_row; } /* optionally, the x and y offset of frames can be specified directly */ if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE) g->offset_x = parameter[GFX_ARG_XOFFSET]; if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE) g->offset_y = parameter[GFX_ARG_YOFFSET]; /* optionally, moving animations may have separate start and end graphics */ g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE]; if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE) parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL]; /* correct x or y offset2 dependent of vertical or horizontal frame order */ if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */ g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_2ND_OFFSET] : g->height); else /* frames are ordered horizontally */ g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_2ND_OFFSET] : g->width); /* optionally, the x and y offset of 2nd graphic can be specified directly */ if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE) g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET]; if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE) g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET]; /* optionally, the second movement tile can be specified as start tile */ if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE) g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES]; /* automatically determine correct number of frames, if not defined */ if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE) g->anim_frames = parameter[GFX_ARG_FRAMES]; else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL]) g->anim_frames = anim_frames_per_row; else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL]) g->anim_frames = anim_frames_per_col; else g->anim_frames = 1; if (g->anim_frames == 0) /* frames must be at least 1 */ g->anim_frames = 1; g->anim_frames_per_line = (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ? parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line); g->anim_delay = parameter[GFX_ARG_DELAY]; if (g->anim_delay == 0) /* delay must be at least 1 */ g->anim_delay = 1; g->anim_mode = parameter[GFX_ARG_ANIM_MODE]; /* automatically determine correct start frame, if not defined */ if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE) g->anim_start_frame = 0; else if (g->anim_mode & ANIM_REVERSE) g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1; else g->anim_start_frame = parameter[GFX_ARG_START_FRAME]; /* animation synchronized with global frame counter, not move position */ g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC]; /* optional element for cloning crumble graphics */ if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE) g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE]; /* optional element for cloning digging graphics */ if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE) g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE]; /* optional border size for "crumbling" diggable graphics */ if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE) g->border_size = parameter[GFX_ARG_BORDER_SIZE]; /* used for global animations and player "boring" and "sleeping" actions */ if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE) g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED]; if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM]; if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE) g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED]; if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM]; if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE) g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED]; if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM]; /* used for global animations */ if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE) g->init_event = parameter[GFX_ARG_INIT_EVENT]; if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE) g->anim_event = parameter[GFX_ARG_ANIM_EVENT]; /* used for toon animations and global animations */ g->step_offset = parameter[GFX_ARG_STEP_OFFSET]; g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET]; g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET]; g->step_delay = parameter[GFX_ARG_STEP_DELAY]; g->direction = parameter[GFX_ARG_DIRECTION]; g->position = parameter[GFX_ARG_POSITION]; g->x = parameter[GFX_ARG_X]; // (may be uninitialized, g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y) /* this is only used for drawing font characters */ g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET]; g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET]; /* use a different default value for global animations and toons */ if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) || (graphic >= IMG_TOON_1 && graphic <= IMG_TOON_20)) g->draw_masked = TRUE; /* this is used for drawing envelopes, global animations and toons */ if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE) g->draw_masked = parameter[GFX_ARG_DRAW_MASKED]; /* used for toon animations and global animations */ if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE) g->draw_order = parameter[GFX_ARG_DRAW_ORDER]; /* optional graphic for cloning all graphics settings */ if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE) g->clone_from = parameter[GFX_ARG_CLONE_FROM]; /* optional settings for drawing title screens and title messages */ if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE) g->fade_mode = parameter[GFX_ARG_FADE_MODE]; if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE) g->fade_delay = parameter[GFX_ARG_FADE_DELAY]; if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE) g->post_delay = parameter[GFX_ARG_POST_DELAY]; if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE) g->auto_delay = parameter[GFX_ARG_AUTO_DELAY]; if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE) g->align = parameter[GFX_ARG_ALIGN]; if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE) g->valign = parameter[GFX_ARG_VALIGN]; if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE) g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY]; if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE) g->class = parameter[GFX_ARG_CLASS]; if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE) g->style = parameter[GFX_ARG_STYLE]; /* this is only used for drawing menu buttons and text */ g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET]; g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET]; g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET]; g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET]; } static void set_graphic_parameters(int graphic) { struct FileInfo *image = getImageListEntryFromImageID(graphic); char **parameter_raw = image->parameter; Bitmap **src_bitmaps = getBitmapsFromImageID(graphic); int parameter[NUM_GFX_ARGS]; int i; /* if fallback to default artwork is done, also use the default parameters */ if (image->fallback_to_default) parameter_raw = image->default_parameter; /* get integer values from string parameters */ for (i = 0; i < NUM_GFX_ARGS; i++) parameter[i] = get_graphic_parameter_value(parameter_raw[i], image_config_suffix[i].token, image_config_suffix[i].type); set_graphic_parameters_ext(graphic, parameter, src_bitmaps); UPDATE_BUSY_STATE(); } static void set_cloned_graphic_parameters(int graphic) { int fallback_graphic = IMG_CHAR_EXCLAM; int max_num_images = getImageListSize(); int clone_graphic = graphic_info[graphic].clone_from; int num_references_followed = 1; while (graphic_info[clone_graphic].clone_from != -1 && num_references_followed < max_num_images) { clone_graphic = graphic_info[clone_graphic].clone_from; num_references_followed++; } if (num_references_followed >= max_num_images) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic)); Error(ERR_INFO, "error: loop discovered when resolving cloned graphics"); Error(ERR_INFO, "custom graphic rejected for this element/action"); if (graphic == fallback_graphic) Error(ERR_EXIT, "no fallback graphic available"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); graphic_info[graphic] = graphic_info[fallback_graphic]; } else { graphic_info[graphic] = graphic_info[clone_graphic]; graphic_info[graphic].clone_from = clone_graphic; } } static void InitGraphicInfo() { int fallback_graphic = IMG_CHAR_EXCLAM; int num_images = getImageListSize(); int i; /* use image size as default values for width and height for these images */ static int full_size_graphics[] = { IMG_GLOBAL_BORDER, IMG_GLOBAL_BORDER_MAIN, IMG_GLOBAL_BORDER_SCORES, IMG_GLOBAL_BORDER_EDITOR, IMG_GLOBAL_BORDER_PLAYING, IMG_GLOBAL_DOOR, IMG_BACKGROUND_ENVELOPE_1, IMG_BACKGROUND_ENVELOPE_2, IMG_BACKGROUND_ENVELOPE_3, IMG_BACKGROUND_ENVELOPE_4, IMG_BACKGROUND_REQUEST, IMG_BACKGROUND, IMG_BACKGROUND_TITLE_INITIAL, IMG_BACKGROUND_TITLE, IMG_BACKGROUND_MAIN, IMG_BACKGROUND_LEVELS, IMG_BACKGROUND_LEVELNR, IMG_BACKGROUND_SCORES, IMG_BACKGROUND_EDITOR, IMG_BACKGROUND_INFO, IMG_BACKGROUND_INFO_ELEMENTS, IMG_BACKGROUND_INFO_MUSIC, IMG_BACKGROUND_INFO_CREDITS, IMG_BACKGROUND_INFO_PROGRAM, IMG_BACKGROUND_INFO_VERSION, IMG_BACKGROUND_INFO_LEVELSET, IMG_BACKGROUND_SETUP, IMG_BACKGROUND_PLAYING, IMG_BACKGROUND_DOOR, IMG_BACKGROUND_TAPE, IMG_BACKGROUND_PANEL, IMG_BACKGROUND_PALETTE, IMG_BACKGROUND_TOOLBOX, IMG_TITLESCREEN_INITIAL_1, IMG_TITLESCREEN_INITIAL_2, IMG_TITLESCREEN_INITIAL_3, IMG_TITLESCREEN_INITIAL_4, IMG_TITLESCREEN_INITIAL_5, IMG_TITLESCREEN_1, IMG_TITLESCREEN_2, IMG_TITLESCREEN_3, IMG_TITLESCREEN_4, IMG_TITLESCREEN_5, IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1, IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2, IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3, IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4, IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5, IMG_BACKGROUND_TITLEMESSAGE_1, IMG_BACKGROUND_TITLEMESSAGE_2, IMG_BACKGROUND_TITLEMESSAGE_3, IMG_BACKGROUND_TITLEMESSAGE_4, IMG_BACKGROUND_TITLEMESSAGE_5, -1 }; checked_free(graphic_info); graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo)); /* initialize "use_image_size" flag with default value */ for (i = 0; i < num_images; i++) graphic_info[i].use_image_size = FALSE; /* initialize "use_image_size" flag from static configuration above */ for (i = 0; full_size_graphics[i] != -1; i++) graphic_info[full_size_graphics[i]].use_image_size = TRUE; /* first set all graphic paramaters ... */ for (i = 0; i < num_images; i++) set_graphic_parameters(i); /* ... then copy these parameters for cloned graphics */ for (i = 0; i < num_images; i++) if (graphic_info[i].clone_from != -1) set_cloned_graphic_parameters(i); for (i = 0; i < num_images; i++) { Bitmap *src_bitmap = graphic_info[i].bitmap; int src_x, src_y; int width, height; int last_frame; int src_bitmap_width, src_bitmap_height; /* now check if no animation frames are outside of the loaded image */ if (graphic_info[i].bitmap == NULL) continue; /* skip check for optional images that are undefined */ /* get image size (this can differ from the standard element tile size!) */ width = graphic_info[i].width; height = graphic_info[i].height; /* get final bitmap size (with scaling, but without small images) */ src_bitmap_width = graphic_info[i].src_image_width; src_bitmap_height = graphic_info[i].src_image_height; /* check if first animation frame is inside specified bitmap */ /* do not use getGraphicSourceXY() here to get position of first frame; */ /* this avoids calculating wrong start position for out-of-bounds frame */ src_x = graphic_info[i].src_x; src_y = graphic_info[i].src_y; if (program.headless) continue; if (src_x < 0 || src_y < 0 || src_x + width > src_bitmap_width || src_y + height > src_bitmap_height) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i)); Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename); Error(ERR_INFO, "- frame size: %d, %d", width, height); Error(ERR_INFO, "error: first animation frame out of bounds (%d, %d) [%d, %d]", src_x, src_y, src_bitmap_width, src_bitmap_height); Error(ERR_INFO, "custom graphic rejected for this element/action"); if (i == fallback_graphic) Error(ERR_EXIT, "no fallback graphic available"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); graphic_info[i] = graphic_info[fallback_graphic]; /* if first frame out of bounds, do not check last frame anymore */ continue; } /* check if last animation frame is inside specified bitmap */ last_frame = graphic_info[i].anim_frames - 1; getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE); if (src_x < 0 || src_y < 0 || src_x + width > src_bitmap_width || src_y + height > src_bitmap_height) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: error found in config file:"); Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename()); Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i)); Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename); Error(ERR_INFO, "- frame size: %d, %d", width, height); Error(ERR_INFO, "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]", last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height); Error(ERR_INFO, "custom graphic rejected for this element/action"); if (i == fallback_graphic) Error(ERR_EXIT, "no fallback graphic available"); Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic"); Error(ERR_INFO_LINE, "-"); graphic_info[i] = graphic_info[fallback_graphic]; } } } static void InitGraphicCompatibilityInfo() { struct FileInfo *fi_global_door = getImageListEntryFromImageID(IMG_GLOBAL_DOOR); int num_images = getImageListSize(); int i; /* the following compatibility handling is needed for the following case: versions up to 3.3.0.0 used one large bitmap "global.door" for various graphics mainly used for door and panel graphics, like editor, tape and in-game buttons with hard-coded bitmap positions and button sizes; as these graphics now have individual definitions, redefining "global.door" to change all these graphics at once like before does not work anymore (because all those individual definitions still have their default values); to solve this, remap all those individual definitions that are not redefined to the new bitmap of "global.door" if it was redefined */ /* special compatibility handling if image "global.door" was redefined */ if (fi_global_door->redefined) { for (i = 0; i < num_images; i++) { struct FileInfo *fi = getImageListEntryFromImageID(i); /* process only those images that still use the default settings */ if (!fi->redefined) { /* process all images which default to same image as "global.door" */ if (strEqual(fi->default_filename, fi_global_door->default_filename)) { // printf("::: special treatment needed for token '%s'\n", fi->token); graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps; graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; } } } } InitGraphicCompatibilityInfo_Doors(); } static void InitElementSoundInfo() { struct PropertyMapping *property_mapping = getSoundListPropertyMapping(); int num_property_mappings = getSoundListPropertyMappingSize(); int i, j, act; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (act = 0; act < NUM_ACTIONS; act++) element_info[i].sound[act] = -1; /* initialize element/sound mapping from static configuration */ for (i = 0; element_to_sound[i].element > -1; i++) { int element = element_to_sound[i].element; int action = element_to_sound[i].action; int sound = element_to_sound[i].sound; boolean is_class = element_to_sound[i].is_class; if (action < 0) action = ACTION_DEFAULT; if (!is_class) element_info[element].sound[action] = sound; else for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (strEqual(element_info[j].class_name, element_info[element].class_name)) element_info[j].sound[action] = sound; } /* initialize element class/sound mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS; int action = property_mapping[i].ext1_index; int sound = property_mapping[i].artwork_index; if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS) continue; if (action < 0) action = ACTION_DEFAULT; for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (strEqual(element_info[j].class_name, element_info[element_class].class_name)) element_info[j].sound[action] = sound; } /* initialize element/sound mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; int sound = property_mapping[i].artwork_index; if (element >= MAX_NUM_ELEMENTS) continue; if (action < 0) action = ACTION_DEFAULT; element_info[element].sound[action] = sound; } /* now set all '-1' values to element specific default values */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { for (act = 0; act < NUM_ACTIONS; act++) { /* generic default action sound (defined by "[default]" directive) */ int default_action_sound = element_info[EL_DEFAULT].sound[act]; /* look for special default action sound (classic game specific) */ if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_BD_DEFAULT].sound[act]; if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_SP_DEFAULT].sound[act]; if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_SB_DEFAULT].sound[act]; if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1) default_action_sound = element_info[EL_MM_DEFAULT].sound[act]; /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */ /* !!! make this better !!! */ if (i == EL_EMPTY_SPACE) default_action_sound = element_info[EL_DEFAULT].sound[act]; /* no sound for this specific action -- use default action sound */ if (element_info[i].sound[act] == -1) element_info[i].sound[act] = default_action_sound; } } /* copy sound settings to some elements that are only stored in level file in native R'n'D levels, but are used by game engine in native EM levels */ for (i = 0; copy_properties[i][0] != -1; i++) for (j = 1; j <= 4; j++) for (act = 0; act < NUM_ACTIONS; act++) element_info[copy_properties[i][j]].sound[act] = element_info[copy_properties[i][0]].sound[act]; } static void InitGameModeSoundInfo() { int i; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) menu.sound[i] = -1; /* initialize gamemode/sound mapping from static configuration */ for (i = 0; gamemode_to_sound[i].sound > -1; i++) { int gamemode = gamemode_to_sound[i].gamemode; int sound = gamemode_to_sound[i].sound; if (gamemode < 0) gamemode = GAME_MODE_DEFAULT; menu.sound[gamemode] = sound; } /* now set all '-1' values to levelset specific default values */ for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) if (menu.sound[i] == -1) menu.sound[i] = menu.sound[GAME_MODE_DEFAULT]; } static void set_sound_parameters(int sound, char **parameter_raw) { int parameter[NUM_SND_ARGS]; int i; /* get integer values from string parameters */ for (i = 0; i < NUM_SND_ARGS; i++) parameter[i] = get_parameter_value(parameter_raw[i], sound_config_suffix[i].token, sound_config_suffix[i].type); /* explicit loop mode setting in configuration overrides default value */ if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE) sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP]; /* sound volume to change the original volume when loading the sound file */ sound_info[sound].volume = parameter[SND_ARG_VOLUME]; /* sound priority to give certain sounds a higher or lower priority */ sound_info[sound].priority = parameter[SND_ARG_PRIORITY]; } static void InitSoundInfo() { int *sound_effect_properties; int num_sounds = getSoundListSize(); int i, j; checked_free(sound_info); sound_effect_properties = checked_calloc(num_sounds * sizeof(int)); sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo)); /* initialize sound effect for all elements to "no sound" */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_ACTIONS; j++) element_info[i].sound[j] = SND_UNDEFINED; for (i = 0; i < num_sounds; i++) { struct FileInfo *sound = getSoundListEntry(i); int len_effect_text = strlen(sound->token); sound_effect_properties[i] = ACTION_OTHER; sound_info[i].loop = FALSE; /* default: play sound only once */ /* determine all loop sounds and identify certain sound classes */ for (j = 0; element_action_info[j].suffix; j++) { int len_action_text = strlen(element_action_info[j].suffix); if (len_action_text < len_effect_text && strEqual(&sound->token[len_effect_text - len_action_text], element_action_info[j].suffix)) { sound_effect_properties[i] = element_action_info[j].value; sound_info[i].loop = element_action_info[j].is_loop_sound; break; } } /* associate elements and some selected sound actions */ for (j = 0; j < MAX_NUM_ELEMENTS; j++) { if (element_info[j].class_name) { int len_class_text = strlen(element_info[j].class_name); if (len_class_text + 1 < len_effect_text && strncmp(sound->token, element_info[j].class_name, len_class_text) == 0 && sound->token[len_class_text] == '.') { int sound_action_value = sound_effect_properties[i]; element_info[j].sound[sound_action_value] = i; } } } set_sound_parameters(i, sound->parameter); } free(sound_effect_properties); } static void InitGameModeMusicInfo() { struct PropertyMapping *property_mapping = getMusicListPropertyMapping(); int num_property_mappings = getMusicListPropertyMappingSize(); int default_levelset_music = -1; int i; /* set values to -1 to identify later as "uninitialized" values */ for (i = 0; i < MAX_LEVELS; i++) levelset.music[i] = -1; for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) menu.music[i] = -1; /* initialize gamemode/music mapping from static configuration */ for (i = 0; gamemode_to_music[i].music > -1; i++) { int gamemode = gamemode_to_music[i].gamemode; int music = gamemode_to_music[i].music; if (gamemode < 0) gamemode = GAME_MODE_DEFAULT; menu.music[gamemode] = music; } /* initialize gamemode/music mapping from dynamic configuration */ for (i = 0; i < num_property_mappings; i++) { int prefix = property_mapping[i].base_index; int gamemode = property_mapping[i].ext2_index; int level = property_mapping[i].ext3_index; int music = property_mapping[i].artwork_index; if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES) continue; if (gamemode < 0) gamemode = GAME_MODE_DEFAULT; /* level specific music only allowed for in-game music */ if (level != -1 && gamemode == GAME_MODE_DEFAULT) gamemode = GAME_MODE_PLAYING; if (level == -1) { level = 0; default_levelset_music = music; } if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT) levelset.music[level] = music; if (gamemode != GAME_MODE_PLAYING) menu.music[gamemode] = music; } /* now set all '-1' values to menu specific default values */ /* (undefined values of "levelset.music[]" might stay at "-1" to allow dynamic selection of music files from music directory!) */ for (i = 0; i < MAX_LEVELS; i++) if (levelset.music[i] == -1) levelset.music[i] = default_levelset_music; for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) if (menu.music[i] == -1) menu.music[i] = menu.music[GAME_MODE_DEFAULT]; } static void set_music_parameters(int music, char **parameter_raw) { int parameter[NUM_MUS_ARGS]; int i; /* get integer values from string parameters */ for (i = 0; i < NUM_MUS_ARGS; i++) parameter[i] = get_parameter_value(parameter_raw[i], music_config_suffix[i].token, music_config_suffix[i].type); /* explicit loop mode setting in configuration overrides default value */ if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE) music_info[music].loop = parameter[MUS_ARG_MODE_LOOP]; } static void InitMusicInfo() { int num_music = getMusicListSize(); int i, j; checked_free(music_info); music_info = checked_calloc(num_music * sizeof(struct MusicInfo)); for (i = 0; i < num_music; i++) { struct FileInfo *music = getMusicListEntry(i); int len_music_text = strlen(music->token); music_info[i].loop = TRUE; /* default: play music in loop mode */ /* determine all loop music */ for (j = 0; music_prefix_info[j].prefix; j++) { int len_prefix_text = strlen(music_prefix_info[j].prefix); if (len_prefix_text < len_music_text && strncmp(music->token, music_prefix_info[j].prefix, len_prefix_text) == 0) { music_info[i].loop = music_prefix_info[j].is_loop_music; break; } } set_music_parameters(i, music->parameter); } } static void ReinitializeGraphics() { print_timestamp_init("ReinitializeGraphics"); InitGfxTileSizeInfo(game.tile_size, TILESIZE); InitGraphicInfo(); /* graphic properties mapping */ print_timestamp_time("InitGraphicInfo"); InitElementGraphicInfo(); /* element game graphic mapping */ print_timestamp_time("InitElementGraphicInfo"); InitElementSpecialGraphicInfo(); /* element special graphic mapping */ print_timestamp_time("InitElementSpecialGraphicInfo"); InitElementSmallImages(); /* scale elements to all needed sizes */ print_timestamp_time("InitElementSmallImages"); InitScaledImages(); /* scale all other images, if needed */ print_timestamp_time("InitScaledImages"); InitBitmapPointers(); /* set standard size bitmap pointers */ print_timestamp_time("InitBitmapPointers"); InitFontGraphicInfo(); /* initialize text drawing functions */ print_timestamp_time("InitFontGraphicInfo"); InitGlobalAnimGraphicInfo(); /* initialize global animation config */ print_timestamp_time("InitGlobalAnimGraphicInfo"); InitImageTextures(); /* create textures for certain images */ print_timestamp_time("InitImageTextures"); InitGraphicInfo_EM(); /* graphic mapping for EM engine */ print_timestamp_time("InitGraphicInfo_EM"); InitGraphicCompatibilityInfo(); print_timestamp_time("InitGraphicCompatibilityInfo"); SetMainBackgroundImage(IMG_BACKGROUND); print_timestamp_time("SetMainBackgroundImage"); SetDoorBackgroundImage(IMG_BACKGROUND_DOOR); print_timestamp_time("SetDoorBackgroundImage"); InitGadgets(); print_timestamp_time("InitGadgets"); InitDoors(); print_timestamp_time("InitDoors"); print_timestamp_done("ReinitializeGraphics"); } static void ReinitializeSounds() { InitSoundInfo(); /* sound properties mapping */ InitElementSoundInfo(); /* element game sound mapping */ InitGameModeSoundInfo(); /* game mode sound mapping */ InitGlobalAnimSoundInfo(); /* global animation sound settings */ InitPlayLevelSound(); /* internal game sound settings */ } static void ReinitializeMusic() { InitMusicInfo(); /* music properties mapping */ InitGameModeMusicInfo(); /* game mode music mapping */ InitGlobalAnimMusicInfo(); /* global animation music settings */ } static int get_special_property_bit(int element, int property_bit_nr) { struct PropertyBitInfo { int element; int bit_nr; }; static struct PropertyBitInfo pb_can_move_into_acid[] = { /* the player may be able fall into acid when gravity is activated */ { EL_PLAYER_1, 0 }, { EL_PLAYER_2, 0 }, { EL_PLAYER_3, 0 }, { EL_PLAYER_4, 0 }, { EL_SP_MURPHY, 0 }, { EL_SOKOBAN_FIELD_PLAYER, 0 }, /* all elements that can move may be able to also move into acid */ { EL_BUG, 1 }, { EL_BUG_LEFT, 1 }, { EL_BUG_RIGHT, 1 }, { EL_BUG_UP, 1 }, { EL_BUG_DOWN, 1 }, { EL_SPACESHIP, 2 }, { EL_SPACESHIP_LEFT, 2 }, { EL_SPACESHIP_RIGHT, 2 }, { EL_SPACESHIP_UP, 2 }, { EL_SPACESHIP_DOWN, 2 }, { EL_BD_BUTTERFLY, 3 }, { EL_BD_BUTTERFLY_LEFT, 3 }, { EL_BD_BUTTERFLY_RIGHT, 3 }, { EL_BD_BUTTERFLY_UP, 3 }, { EL_BD_BUTTERFLY_DOWN, 3 }, { EL_BD_FIREFLY, 4 }, { EL_BD_FIREFLY_LEFT, 4 }, { EL_BD_FIREFLY_RIGHT, 4 }, { EL_BD_FIREFLY_UP, 4 }, { EL_BD_FIREFLY_DOWN, 4 }, { EL_YAMYAM, 5 }, { EL_YAMYAM_LEFT, 5 }, { EL_YAMYAM_RIGHT, 5 }, { EL_YAMYAM_UP, 5 }, { EL_YAMYAM_DOWN, 5 }, { EL_DARK_YAMYAM, 6 }, { EL_ROBOT, 7 }, { EL_PACMAN, 8 }, { EL_PACMAN_LEFT, 8 }, { EL_PACMAN_RIGHT, 8 }, { EL_PACMAN_UP, 8 }, { EL_PACMAN_DOWN, 8 }, { EL_MOLE, 9 }, { EL_MOLE_LEFT, 9 }, { EL_MOLE_RIGHT, 9 }, { EL_MOLE_UP, 9 }, { EL_MOLE_DOWN, 9 }, { EL_PENGUIN, 10 }, { EL_PIG, 11 }, { EL_DRAGON, 12 }, { EL_SATELLITE, 13 }, { EL_SP_SNIKSNAK, 14 }, { EL_SP_ELECTRON, 15 }, { EL_BALLOON, 16 }, { EL_SPRING, 17 }, { EL_EMC_ANDROID, 18 }, { -1, -1 }, }; static struct PropertyBitInfo pb_dont_collide_with[] = { { EL_SP_SNIKSNAK, 0 }, { EL_SP_ELECTRON, 1 }, { -1, -1 }, }; static struct { int bit_nr; struct PropertyBitInfo *pb_info; } pb_definition[] = { { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid }, { EP_DONT_COLLIDE_WITH, pb_dont_collide_with }, { -1, NULL }, }; struct PropertyBitInfo *pb_info = NULL; int i; for (i = 0; pb_definition[i].bit_nr != -1; i++) if (pb_definition[i].bit_nr == property_bit_nr) pb_info = pb_definition[i].pb_info; if (pb_info == NULL) return -1; for (i = 0; pb_info[i].element != -1; i++) if (pb_info[i].element == element) return pb_info[i].bit_nr; return -1; } void setBitfieldProperty(int *bitfield, int property_bit_nr, int element, boolean property_value) { int bit_nr = get_special_property_bit(element, property_bit_nr); if (bit_nr > -1) { if (property_value) *bitfield |= (1 << bit_nr); else *bitfield &= ~(1 << bit_nr); } } boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element) { int bit_nr = get_special_property_bit(element, property_bit_nr); if (bit_nr > -1) return ((*bitfield & (1 << bit_nr)) != 0); return FALSE; } static void ResolveGroupElementExt(int group_element, int recursion_depth) { static int group_nr; static struct ElementGroupInfo *group; struct ElementGroupInfo *actual_group = element_info[group_element].group; int i; if (actual_group == NULL) /* not yet initialized */ return; if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */ { Error(ERR_WARN, "recursion too deep when resolving group element %d", group_element - EL_GROUP_START + 1); /* replace element which caused too deep recursion by question mark */ group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN; return; } if (recursion_depth == 0) /* initialization */ { group = actual_group; group_nr = GROUP_NR(group_element); group->num_elements_resolved = 0; group->choice_pos = 0; for (i = 0; i < MAX_NUM_ELEMENTS; i++) element_info[i].in_group[group_nr] = FALSE; } for (i = 0; i < actual_group->num_elements; i++) { int element = actual_group->element[i]; if (group->num_elements_resolved == NUM_FILE_ELEMENTS) break; if (IS_GROUP_ELEMENT(element)) ResolveGroupElementExt(element, recursion_depth + 1); else { group->element_resolved[group->num_elements_resolved++] = element; element_info[element].in_group[group_nr] = TRUE; } } } void ResolveGroupElement(int group_element) { ResolveGroupElementExt(group_element, 0); } void InitElementPropertiesStatic() { static boolean clipboard_elements_initialized = FALSE; static int ep_diggable[] = { EL_SAND, EL_SP_BASE, EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVATING, EL_TRAP, EL_INVISIBLE_SAND, EL_INVISIBLE_SAND_ACTIVE, EL_EMC_GRASS, /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */ /* (if amoeba can grow into anything diggable, maybe keep these out) */ #if 0 EL_LANDMINE, EL_DC_LANDMINE, EL_TRAP_ACTIVE, EL_SP_BUGGY_BASE_ACTIVE, EL_EMC_PLANT, #endif -1 }; static int ep_collectible_only[] = { EL_BD_DIAMOND, EL_EMERALD, EL_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_KEY_1, EL_KEY_2, EL_KEY_3, EL_KEY_4, EL_EM_KEY_1, EL_EM_KEY_2, EL_EM_KEY_3, EL_EM_KEY_4, EL_EMC_KEY_5, EL_EMC_KEY_6, EL_EMC_KEY_7, EL_EMC_KEY_8, EL_DYNAMITE, EL_EM_DYNAMITE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_SP_INFOTRON, EL_SP_DISK_RED, EL_PEARL, EL_CRYSTAL, EL_DC_KEY_WHITE, EL_SHIELD_NORMAL, EL_SHIELD_DEADLY, EL_EXTRA_TIME, EL_ENVELOPE_1, EL_ENVELOPE_2, EL_ENVELOPE_3, EL_ENVELOPE_4, EL_SPEED_PILL, EL_EMC_LENSES, EL_EMC_MAGNIFIER, #if 0 /* !!! handle separately !!! */ EL_DC_LANDMINE, /* deadly when running into, but can be snapped */ #endif -1 }; static int ep_dont_run_into[] = { /* same elements as in 'ep_dont_touch' */ EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, /* same elements as in 'ep_dont_collide_with' */ EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_SP_SNIKSNAK, EL_SP_ELECTRON, /* new elements */ EL_AMOEBA_DROP, EL_ACID, /* !!! maybe this should better be handled by 'ep_diggable' !!! */ #if 1 EL_LANDMINE, EL_DC_LANDMINE, EL_TRAP_ACTIVE, EL_SP_BUGGY_BASE_ACTIVE, EL_EMC_PLANT, #endif -1 }; static int ep_dont_collide_with[] = { /* same elements as in 'ep_dont_touch' */ EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, /* new elements */ EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_SP_SNIKSNAK, EL_SP_ELECTRON, -1 }; static int ep_dont_touch[] = { EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, -1 }; static int ep_indestructible[] = { EL_STEELWALL, EL_ACID, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_SIGN_EXCLAMATION, EL_SIGN_RADIOACTIVITY, EL_SIGN_STOP, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_UNUSED_1, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, EL_SIGN_UNUSED_2, EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN, EL_STEEL_EXIT_OPENING, EL_STEEL_EXIT_CLOSING, EL_EM_STEEL_EXIT_CLOSED, EL_EM_STEEL_EXIT_OPEN, EL_EM_STEEL_EXIT_OPENING, EL_EM_STEEL_EXIT_CLOSING, EL_DC_STEELWALL_1_LEFT, EL_DC_STEELWALL_1_RIGHT, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_STEELWALL_1_TOPLEFT_2, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_2_TOP, EL_DC_STEELWALL_2_BOTTOM, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_SINGLE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_CRYSTAL, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_DC_GATE_FAKE_GRAY, EL_SWITCHGATE_OPEN, EL_SWITCHGATE_OPENING, EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_CLOSING, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_TIMEGATE_OPEN, EL_TIMEGATE_OPENING, EL_TIMEGATE_CLOSED, EL_TIMEGATE_CLOSING, EL_DC_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH_ACTIVE, EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL, EL_EXPANDABLE_STEELWALL_ANY, -1 }; static int ep_slippery[] = { EL_WALL_SLIPPERY, EL_BD_WALL, EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_BOMB, EL_NUT, EL_ROBOT_WHEEL_ACTIVE, EL_ROBOT_WHEEL, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_LAMP_ACTIVE, EL_LAMP, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_SATELLITE, EL_SP_ZONK, EL_SP_INFOTRON, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SPEED_PILL, EL_STEELWALL_SLIPPERY, EL_PEARL, EL_CRYSTAL, EL_EMC_WALL_SLIPPERY_1, EL_EMC_WALL_SLIPPERY_2, EL_EMC_WALL_SLIPPERY_3, EL_EMC_WALL_SLIPPERY_4, EL_EMC_MAGIC_BALL, EL_EMC_MAGIC_BALL_ACTIVE, -1 }; static int ep_can_change[] = { -1 }; static int ep_can_move[] = { /* same elements as in 'pb_can_move_into_acid' */ EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_MOLE, EL_PENGUIN, EL_PIG, EL_DRAGON, EL_SATELLITE, EL_SP_SNIKSNAK, EL_SP_ELECTRON, EL_BALLOON, EL_SPRING, EL_EMC_ANDROID, -1 }; static int ep_can_fall[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_BOMB, EL_NUT, EL_AMOEBA_DROP, EL_QUICKSAND_FULL, EL_QUICKSAND_FAST_FULL, EL_MAGIC_WALL_FULL, EL_BD_MAGIC_WALL_FULL, EL_DC_MAGIC_WALL_FULL, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_SP_ZONK, EL_SP_INFOTRON, EL_SP_DISK_ORANGE, EL_PEARL, EL_CRYSTAL, EL_SPRING, EL_DX_SUPABOMB, -1 }; static int ep_can_smash_player[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_BOMB, EL_NUT, EL_AMOEBA_DROP, EL_TIME_ORB_FULL, EL_TIME_ORB_EMPTY, EL_SP_ZONK, EL_SP_INFOTRON, EL_SP_DISK_ORANGE, EL_PEARL, EL_CRYSTAL, EL_SPRING, EL_DX_SUPABOMB, -1 }; static int ep_can_smash_enemies[] = { EL_ROCK, EL_BD_ROCK, EL_SP_ZONK, -1 }; static int ep_can_smash_everything[] = { EL_ROCK, EL_BD_ROCK, EL_SP_ZONK, -1 }; static int ep_explodes_by_fire[] = { /* same elements as in 'ep_explodes_impact' */ EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, /* same elements as in 'ep_explodes_smashed' */ EL_SATELLITE, EL_PIG, EL_DRAGON, EL_MOLE, /* new elements */ EL_DYNAMITE, EL_DYNAMITE_ACTIVE, EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_DYNABOMB_PLAYER_1_ACTIVE, EL_DYNABOMB_PLAYER_2_ACTIVE, EL_DYNABOMB_PLAYER_3_ACTIVE, EL_DYNABOMB_PLAYER_4_ACTIVE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_SP_DISK_RED_ACTIVE, EL_BUG, EL_PENGUIN, EL_SP_DISK_RED, EL_SP_DISK_YELLOW, EL_SP_SNIKSNAK, EL_SP_ELECTRON, #if 0 EL_BLACK_ORB, #endif -1 }; static int ep_explodes_smashed[] = { /* same elements as in 'ep_explodes_impact' */ EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, /* new elements */ EL_SATELLITE, EL_PIG, EL_DRAGON, EL_MOLE, -1 }; static int ep_explodes_impact[] = { EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, -1 }; static int ep_walkable_over[] = { EL_EMPTY_SPACE, EL_SP_EMPTY_SPACE, EL_SOKOBAN_FIELD_EMPTY, EL_EXIT_OPEN, EL_EM_EXIT_OPEN, EL_EM_EXIT_OPENING, EL_SP_EXIT_OPEN, EL_SP_EXIT_OPENING, EL_STEEL_EXIT_OPEN, EL_EM_STEEL_EXIT_OPEN, EL_EM_STEEL_EXIT_OPENING, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_PENGUIN, EL_PIG, EL_DRAGON, -1 }; static int ep_walkable_inside[] = { EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, -1 }; static int ep_walkable_under[] = { -1 }; static int ep_passable_over[] = { EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_SWITCHGATE_OPEN, EL_TIMEGATE_OPEN, -1 }; static int ep_passable_inside[] = { EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, -1 }; static int ep_passable_under[] = { -1 }; static int ep_droppable[] = { -1 }; static int ep_explodes_1x1_old[] = { -1 }; static int ep_pushable[] = { EL_ROCK, EL_BOMB, EL_DX_SUPABOMB, EL_NUT, EL_TIME_ORB_EMPTY, EL_SP_ZONK, EL_SP_DISK_ORANGE, EL_SPRING, EL_BD_ROCK, EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_FULL, EL_SATELLITE, EL_SP_DISK_YELLOW, EL_BALLOON, EL_EMC_ANDROID, -1 }; static int ep_explodes_cross_old[] = { -1 }; static int ep_protected[] = { /* same elements as in 'ep_walkable_inside' */ EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, /* same elements as in 'ep_passable_over' */ EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_SWITCHGATE_OPEN, EL_TIMEGATE_OPEN, /* same elements as in 'ep_passable_inside' */ EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, -1 }; static int ep_throwable[] = { -1 }; static int ep_can_explode[] = { /* same elements as in 'ep_explodes_impact' */ EL_BOMB, EL_SP_DISK_ORANGE, EL_DX_SUPABOMB, /* same elements as in 'ep_explodes_smashed' */ EL_SATELLITE, EL_PIG, EL_DRAGON, EL_MOLE, /* elements that can explode by explosion or by dragonfire */ EL_DYNAMITE, EL_DYNAMITE_ACTIVE, EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_DYNABOMB_PLAYER_1_ACTIVE, EL_DYNABOMB_PLAYER_2_ACTIVE, EL_DYNABOMB_PLAYER_3_ACTIVE, EL_DYNABOMB_PLAYER_4_ACTIVE, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, EL_SP_DISK_RED_ACTIVE, EL_BUG, EL_PENGUIN, EL_SP_DISK_RED, EL_SP_DISK_YELLOW, EL_SP_SNIKSNAK, EL_SP_ELECTRON, /* elements that can explode only by explosion */ EL_BLACK_ORB, -1 }; static int ep_gravity_reachable[] = { EL_SAND, EL_SP_BASE, EL_TRAP, EL_INVISIBLE_SAND, EL_INVISIBLE_SAND_ACTIVE, EL_SP_PORT_LEFT, EL_SP_PORT_RIGHT, EL_SP_PORT_UP, EL_SP_PORT_DOWN, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_UP, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_EMC_GRASS, -1 }; static int ep_player[] = { EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_SP_MURPHY, EL_SOKOBAN_FIELD_PLAYER, EL_TRIGGER_PLAYER, -1 }; static int ep_can_pass_magic_wall[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, -1 }; static int ep_can_pass_dc_magic_wall[] = { EL_ROCK, EL_BD_ROCK, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_PEARL, EL_CRYSTAL, -1 }; static int ep_switchable[] = { EL_ROBOT_WHEEL, EL_SP_TERMINAL, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH, EL_BALLOON_SWITCH_LEFT, EL_BALLOON_SWITCH_RIGHT, EL_BALLOON_SWITCH_UP, EL_BALLOON_SWITCH_DOWN, EL_BALLOON_SWITCH_ANY, EL_BALLOON_SWITCH_NONE, EL_LAMP, EL_TIME_ORB_FULL, EL_EMC_MAGIC_BALL_SWITCH, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE, -1 }; static int ep_bd_element[] = { EL_EMPTY, EL_SAND, EL_WALL_SLIPPERY, EL_BD_WALL, EL_ROCK, EL_BD_ROCK, EL_BD_DIAMOND, EL_BD_MAGIC_WALL, EL_EXIT_CLOSED, EL_EXIT_OPEN, EL_STEELWALL, EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_BD_FIREFLY, EL_BD_FIREFLY_1, EL_BD_FIREFLY_2, EL_BD_FIREFLY_3, EL_BD_FIREFLY_4, EL_BD_BUTTERFLY, EL_BD_BUTTERFLY_1, EL_BD_BUTTERFLY_2, EL_BD_BUTTERFLY_3, EL_BD_BUTTERFLY_4, EL_BD_AMOEBA, EL_CHAR_QUESTION, EL_UNKNOWN, -1 }; static int ep_sp_element[] = { /* should always be valid */ EL_EMPTY, /* standard classic Supaplex elements */ EL_SP_EMPTY, EL_SP_ZONK, EL_SP_BASE, EL_SP_MURPHY, EL_SP_INFOTRON, EL_SP_CHIP_SINGLE, EL_SP_HARDWARE_GRAY, EL_SP_EXIT_CLOSED, EL_SP_EXIT_OPEN, EL_SP_DISK_ORANGE, EL_SP_PORT_RIGHT, EL_SP_PORT_DOWN, EL_SP_PORT_LEFT, EL_SP_PORT_UP, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_UP, EL_SP_SNIKSNAK, EL_SP_DISK_YELLOW, EL_SP_TERMINAL, EL_SP_DISK_RED, EL_SP_PORT_VERTICAL, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_ANY, EL_SP_ELECTRON, EL_SP_BUGGY_BASE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, /* additional elements that appeared in newer Supaplex levels */ EL_INVISIBLE_WALL, /* additional gravity port elements (not switching, but setting gravity) */ EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, /* more than one Murphy in a level results in an inactive clone */ EL_SP_MURPHY_CLONE, /* runtime Supaplex elements */ EL_SP_DISK_RED_ACTIVE, EL_SP_TERMINAL_ACTIVE, EL_SP_BUGGY_BASE_ACTIVATING, EL_SP_BUGGY_BASE_ACTIVE, EL_SP_EXIT_OPENING, EL_SP_EXIT_CLOSING, -1 }; static int ep_sb_element[] = { EL_EMPTY, EL_STEELWALL, EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_SOKOBAN_FIELD_PLAYER, EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_INVISIBLE_STEELWALL, -1 }; static int ep_gem[] = { EL_BD_DIAMOND, EL_EMERALD, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, -1 }; static int ep_food_dark_yamyam[] = { EL_SAND, EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_YAMYAM, EL_ROBOT, EL_PACMAN, EL_AMOEBA_DROP, EL_AMOEBA_DEAD, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_PEARL, EL_CRYSTAL, -1 }; static int ep_food_penguin[] = { EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, EL_PEARL, EL_CRYSTAL, -1 }; static int ep_food_pig[] = { EL_EMERALD, EL_BD_DIAMOND, EL_EMERALD_YELLOW, EL_EMERALD_RED, EL_EMERALD_PURPLE, EL_DIAMOND, -1 }; static int ep_historic_wall[] = { EL_STEELWALL, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EXIT_CLOSED, EL_EXIT_OPENING, EL_EXIT_OPEN, EL_WALL, EL_WALL_SLIPPERY, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, EL_EXPANDABLE_WALL_GROWING, EL_BD_EXPANDABLE_WALL, EL_BD_WALL, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_TERMINAL, EL_SP_TERMINAL_ACTIVE, EL_SP_EXIT_CLOSED, EL_SP_EXIT_OPEN, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE, EL_INVISIBLE_WALL, EL_INVISIBLE_WALL_ACTIVE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, -1 }; static int ep_historic_solid[] = { EL_WALL, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, EL_BD_EXPANDABLE_WALL, EL_BD_WALL, EL_WALL_SLIPPERY, EL_EXIT_CLOSED, EL_EXIT_OPENING, EL_EXIT_OPEN, EL_AMOEBA_DEAD, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_QUICKSAND_EMPTY, EL_QUICKSAND_FULL, EL_QUICKSAND_FILLING, EL_QUICKSAND_EMPTYING, EL_MAGIC_WALL, EL_MAGIC_WALL_ACTIVE, EL_MAGIC_WALL_EMPTYING, EL_MAGIC_WALL_FILLING, EL_MAGIC_WALL_FULL, EL_MAGIC_WALL_DEAD, EL_BD_MAGIC_WALL, EL_BD_MAGIC_WALL_ACTIVE, EL_BD_MAGIC_WALL_EMPTYING, EL_BD_MAGIC_WALL_FULL, EL_BD_MAGIC_WALL_FILLING, EL_BD_MAGIC_WALL_DEAD, EL_GAME_OF_LIFE, EL_BIOMAZE, EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SP_TERMINAL, EL_SP_TERMINAL_ACTIVE, EL_SP_EXIT_CLOSED, EL_SP_EXIT_OPEN, EL_INVISIBLE_WALL, EL_INVISIBLE_WALL_ACTIVE, EL_SWITCHGATE_SWITCH_UP, EL_SWITCHGATE_SWITCH_DOWN, EL_DC_SWITCHGATE_SWITCH_UP, EL_DC_SWITCHGATE_SWITCH_DOWN, EL_TIMEGATE_SWITCH, EL_TIMEGATE_SWITCH_ACTIVE, EL_DC_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH_ACTIVE, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, EL_WALL_PEARL, EL_WALL_CRYSTAL, /* the following elements are a direct copy of "indestructible" elements, except "EL_ACID", which is "indestructible", but not "solid"! */ #if 0 EL_ACID, #endif EL_STEELWALL, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE, EL_SIGN_EXCLAMATION, EL_SIGN_RADIOACTIVITY, EL_SIGN_STOP, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_UNUSED_1, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, EL_SIGN_UNUSED_2, EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_STEEL_EXIT_CLOSED, EL_STEEL_EXIT_OPEN, EL_DC_STEELWALL_1_LEFT, EL_DC_STEELWALL_1_RIGHT, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_STEELWALL_1_TOPLEFT_2, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_2_TOP, EL_DC_STEELWALL_2_BOTTOM, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_SINGLE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_CRYSTAL, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_SWITCHGATE_OPEN, EL_SWITCHGATE_OPENING, EL_SWITCHGATE_CLOSED, EL_SWITCHGATE_CLOSING, EL_TIMEGATE_OPEN, EL_TIMEGATE_OPENING, EL_TIMEGATE_CLOSED, EL_TIMEGATE_CLOSING, EL_TUBE_ANY, EL_TUBE_VERTICAL, EL_TUBE_HORIZONTAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, -1 }; static int ep_classic_enemy[] = { EL_BUG, EL_SPACESHIP, EL_BD_BUTTERFLY, EL_BD_FIREFLY, EL_YAMYAM, EL_DARK_YAMYAM, EL_ROBOT, EL_PACMAN, EL_SP_SNIKSNAK, EL_SP_ELECTRON, -1 }; static int ep_belt[] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_1_MIDDLE, EL_CONVEYOR_BELT_1_RIGHT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_2_MIDDLE, EL_CONVEYOR_BELT_2_RIGHT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_3_MIDDLE, EL_CONVEYOR_BELT_3_RIGHT, EL_CONVEYOR_BELT_4_LEFT, EL_CONVEYOR_BELT_4_MIDDLE, EL_CONVEYOR_BELT_4_RIGHT, -1 }; static int ep_belt_active[] = { EL_CONVEYOR_BELT_1_LEFT_ACTIVE, EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_1_RIGHT_ACTIVE, EL_CONVEYOR_BELT_2_LEFT_ACTIVE, EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_2_RIGHT_ACTIVE, EL_CONVEYOR_BELT_3_LEFT_ACTIVE, EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_3_RIGHT_ACTIVE, EL_CONVEYOR_BELT_4_LEFT_ACTIVE, EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE, EL_CONVEYOR_BELT_4_RIGHT_ACTIVE, -1 }; static int ep_belt_switch[] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, -1 }; static int ep_tube[] = { EL_TUBE_LEFT_UP, EL_TUBE_LEFT_DOWN, EL_TUBE_RIGHT_UP, EL_TUBE_RIGHT_DOWN, EL_TUBE_HORIZONTAL, EL_TUBE_HORIZONTAL_UP, EL_TUBE_HORIZONTAL_DOWN, EL_TUBE_VERTICAL, EL_TUBE_VERTICAL_LEFT, EL_TUBE_VERTICAL_RIGHT, EL_TUBE_ANY, -1 }; static int ep_acid_pool[] = { EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, -1 }; static int ep_keygate[] = { EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, -1 }; static int ep_amoeboid[] = { EL_AMOEBA_DEAD, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMC_DRIPPER, -1 }; static int ep_amoebalive[] = { EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMC_DRIPPER, -1 }; static int ep_has_editor_content[] = { EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, EL_PLAYER_4, EL_SOKOBAN_FIELD_PLAYER, EL_SP_MURPHY, EL_YAMYAM, EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT, EL_YAMYAM_UP, EL_YAMYAM_DOWN, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_BD_AMOEBA, EL_EMC_MAGIC_BALL, EL_EMC_ANDROID, -1 }; static int ep_can_turn_each_move[] = { /* !!! do something with this one !!! */ -1 }; static int ep_can_grow[] = { EL_BD_AMOEBA, EL_AMOEBA_DROP, EL_AMOEBA_WET, EL_AMOEBA_DRY, EL_AMOEBA_FULL, EL_GAME_OF_LIFE, EL_BIOMAZE, EL_EMC_DRIPPER, -1 }; static int ep_active_bomb[] = { EL_DYNAMITE_ACTIVE, EL_EM_DYNAMITE_ACTIVE, EL_DYNABOMB_PLAYER_1_ACTIVE, EL_DYNABOMB_PLAYER_2_ACTIVE, EL_DYNABOMB_PLAYER_3_ACTIVE, EL_DYNABOMB_PLAYER_4_ACTIVE, EL_SP_DISK_RED_ACTIVE, -1 }; static int ep_inactive[] = { EL_EMPTY, EL_SAND, EL_WALL, EL_BD_WALL, EL_WALL_SLIPPERY, EL_STEELWALL, EL_AMOEBA_DEAD, EL_QUICKSAND_EMPTY, EL_QUICKSAND_FAST_EMPTY, EL_STONEBLOCK, EL_ROBOT_WHEEL, EL_KEY_1, EL_KEY_2, EL_KEY_3, EL_KEY_4, EL_EM_KEY_1, EL_EM_KEY_2, EL_EM_KEY_3, EL_EM_KEY_4, EL_EMC_KEY_5, EL_EMC_KEY_6, EL_EMC_KEY_7, EL_EMC_KEY_8, EL_GATE_1, EL_GATE_2, EL_GATE_3, EL_GATE_4, EL_GATE_1_GRAY, EL_GATE_2_GRAY, EL_GATE_3_GRAY, EL_GATE_4_GRAY, EL_GATE_1_GRAY_ACTIVE, EL_GATE_2_GRAY_ACTIVE, EL_GATE_3_GRAY_ACTIVE, EL_GATE_4_GRAY_ACTIVE, EL_EM_GATE_1, EL_EM_GATE_2, EL_EM_GATE_3, EL_EM_GATE_4, EL_EM_GATE_1_GRAY, EL_EM_GATE_2_GRAY, EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, EL_EM_GATE_1_GRAY_ACTIVE, EL_EM_GATE_2_GRAY_ACTIVE, EL_EM_GATE_3_GRAY_ACTIVE, EL_EM_GATE_4_GRAY_ACTIVE, EL_EMC_GATE_5, EL_EMC_GATE_6, EL_EMC_GATE_7, EL_EMC_GATE_8, EL_EMC_GATE_5_GRAY, EL_EMC_GATE_6_GRAY, EL_EMC_GATE_7_GRAY, EL_EMC_GATE_8_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE, EL_EMC_GATE_6_GRAY_ACTIVE, EL_EMC_GATE_7_GRAY_ACTIVE, EL_EMC_GATE_8_GRAY_ACTIVE, EL_DC_GATE_WHITE, EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE, EL_DC_GATE_FAKE_GRAY, EL_DYNAMITE, EL_EM_DYNAMITE, EL_INVISIBLE_STEELWALL, EL_INVISIBLE_WALL, EL_INVISIBLE_SAND, EL_LAMP, EL_LAMP_ACTIVE, EL_WALL_EMERALD, EL_WALL_DIAMOND, EL_WALL_BD_DIAMOND, EL_WALL_EMERALD_YELLOW, EL_DYNABOMB_INCREASE_NUMBER, EL_DYNABOMB_INCREASE_SIZE, EL_DYNABOMB_INCREASE_POWER, #if 0 EL_SOKOBAN_OBJECT, #endif EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_WALL_EMERALD_RED, EL_WALL_EMERALD_PURPLE, EL_ACID_POOL_TOPLEFT, EL_ACID_POOL_TOPRIGHT, EL_ACID_POOL_BOTTOMLEFT, EL_ACID_POOL_BOTTOM, EL_ACID_POOL_BOTTOMRIGHT, EL_MAGIC_WALL, EL_MAGIC_WALL_DEAD, EL_BD_MAGIC_WALL, EL_BD_MAGIC_WALL_DEAD, EL_DC_MAGIC_WALL, EL_DC_MAGIC_WALL_DEAD, EL_AMOEBA_TO_DIAMOND, EL_BLOCKED, EL_SP_EMPTY, EL_SP_BASE, EL_SP_PORT_RIGHT, EL_SP_PORT_DOWN, EL_SP_PORT_LEFT, EL_SP_PORT_UP, EL_SP_GRAVITY_PORT_RIGHT, EL_SP_GRAVITY_PORT_DOWN, EL_SP_GRAVITY_PORT_LEFT, EL_SP_GRAVITY_PORT_UP, EL_SP_PORT_HORIZONTAL, EL_SP_PORT_VERTICAL, EL_SP_PORT_ANY, EL_SP_DISK_RED, #if 0 EL_SP_DISK_YELLOW, #endif EL_SP_CHIP_SINGLE, EL_SP_CHIP_LEFT, EL_SP_CHIP_RIGHT, EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, EL_SP_HARDWARE_GRAY, EL_SP_HARDWARE_GREEN, EL_SP_HARDWARE_BLUE, EL_SP_HARDWARE_RED, EL_SP_HARDWARE_YELLOW, EL_SP_HARDWARE_BASE_1, EL_SP_HARDWARE_BASE_2, EL_SP_HARDWARE_BASE_3, EL_SP_HARDWARE_BASE_4, EL_SP_HARDWARE_BASE_5, EL_SP_HARDWARE_BASE_6, EL_SP_GRAVITY_ON_PORT_LEFT, EL_SP_GRAVITY_ON_PORT_RIGHT, EL_SP_GRAVITY_ON_PORT_UP, EL_SP_GRAVITY_ON_PORT_DOWN, EL_SP_GRAVITY_OFF_PORT_LEFT, EL_SP_GRAVITY_OFF_PORT_RIGHT, EL_SP_GRAVITY_OFF_PORT_UP, EL_SP_GRAVITY_OFF_PORT_DOWN, EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_1_SWITCH_MIDDLE, EL_CONVEYOR_BELT_1_SWITCH_RIGHT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_MIDDLE, EL_CONVEYOR_BELT_2_SWITCH_RIGHT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_MIDDLE, EL_CONVEYOR_BELT_3_SWITCH_RIGHT, EL_CONVEYOR_BELT_4_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_MIDDLE, EL_CONVEYOR_BELT_4_SWITCH_RIGHT, EL_SIGN_EXCLAMATION, EL_SIGN_RADIOACTIVITY, EL_SIGN_STOP, EL_SIGN_WHEELCHAIR, EL_SIGN_PARKING, EL_SIGN_NO_ENTRY, EL_SIGN_UNUSED_1, EL_SIGN_GIVE_WAY, EL_SIGN_ENTRY_FORBIDDEN, EL_SIGN_EMERGENCY_EXIT, EL_SIGN_YIN_YANG, EL_SIGN_UNUSED_2, EL_SIGN_SPERMS, EL_SIGN_BULLET, EL_SIGN_HEART, EL_SIGN_CROSS, EL_SIGN_FRANKIE, EL_DC_STEELWALL_1_LEFT, EL_DC_STEELWALL_1_RIGHT, EL_DC_STEELWALL_1_TOP, EL_DC_STEELWALL_1_BOTTOM, EL_DC_STEELWALL_1_HORIZONTAL, EL_DC_STEELWALL_1_VERTICAL, EL_DC_STEELWALL_1_TOPLEFT, EL_DC_STEELWALL_1_TOPRIGHT, EL_DC_STEELWALL_1_BOTTOMLEFT, EL_DC_STEELWALL_1_BOTTOMRIGHT, EL_DC_STEELWALL_1_TOPLEFT_2, EL_DC_STEELWALL_1_TOPRIGHT_2, EL_DC_STEELWALL_1_BOTTOMLEFT_2, EL_DC_STEELWALL_1_BOTTOMRIGHT_2, EL_DC_STEELWALL_2_LEFT, EL_DC_STEELWALL_2_RIGHT, EL_DC_STEELWALL_2_TOP, EL_DC_STEELWALL_2_BOTTOM, EL_DC_STEELWALL_2_HORIZONTAL, EL_DC_STEELWALL_2_VERTICAL, EL_DC_STEELWALL_2_MIDDLE, EL_DC_STEELWALL_2_SINGLE, EL_STEELWALL_SLIPPERY, EL_EMC_STEELWALL_1, EL_EMC_STEELWALL_2, EL_EMC_STEELWALL_3, EL_EMC_STEELWALL_4, EL_EMC_WALL_SLIPPERY_1, EL_EMC_WALL_SLIPPERY_2, EL_EMC_WALL_SLIPPERY_3, EL_EMC_WALL_SLIPPERY_4, EL_EMC_WALL_1, EL_EMC_WALL_2, EL_EMC_WALL_3, EL_EMC_WALL_4, EL_EMC_WALL_5, EL_EMC_WALL_6, EL_EMC_WALL_7, EL_EMC_WALL_8, EL_EMC_WALL_9, EL_EMC_WALL_10, EL_EMC_WALL_11, EL_EMC_WALL_12, EL_EMC_WALL_13, EL_EMC_WALL_14, EL_EMC_WALL_15, EL_EMC_WALL_16, -1 }; static int ep_em_slippery_wall[] = { -1 }; static int ep_gfx_crumbled[] = { EL_SAND, EL_LANDMINE, EL_DC_LANDMINE, EL_TRAP, EL_TRAP_ACTIVE, -1 }; static int ep_editor_cascade_active[] = { EL_INTERNAL_CASCADE_BD_ACTIVE, EL_INTERNAL_CASCADE_EM_ACTIVE, EL_INTERNAL_CASCADE_EMC_ACTIVE, EL_INTERNAL_CASCADE_RND_ACTIVE, EL_INTERNAL_CASCADE_SB_ACTIVE, EL_INTERNAL_CASCADE_SP_ACTIVE, EL_INTERNAL_CASCADE_DC_ACTIVE, EL_INTERNAL_CASCADE_DX_ACTIVE, EL_INTERNAL_CASCADE_MM_ACTIVE, EL_INTERNAL_CASCADE_DF_ACTIVE, EL_INTERNAL_CASCADE_CHARS_ACTIVE, EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE, EL_INTERNAL_CASCADE_CE_ACTIVE, EL_INTERNAL_CASCADE_GE_ACTIVE, EL_INTERNAL_CASCADE_REF_ACTIVE, EL_INTERNAL_CASCADE_USER_ACTIVE, EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE, -1 }; static int ep_editor_cascade_inactive[] = { EL_INTERNAL_CASCADE_BD, EL_INTERNAL_CASCADE_EM, EL_INTERNAL_CASCADE_EMC, EL_INTERNAL_CASCADE_RND, EL_INTERNAL_CASCADE_SB, EL_INTERNAL_CASCADE_SP, EL_INTERNAL_CASCADE_DC, EL_INTERNAL_CASCADE_DX, EL_INTERNAL_CASCADE_MM, EL_INTERNAL_CASCADE_DF, EL_INTERNAL_CASCADE_CHARS, EL_INTERNAL_CASCADE_STEEL_CHARS, EL_INTERNAL_CASCADE_CE, EL_INTERNAL_CASCADE_GE, EL_INTERNAL_CASCADE_REF, EL_INTERNAL_CASCADE_USER, EL_INTERNAL_CASCADE_DYNAMIC, -1 }; static int ep_obsolete[] = { EL_PLAYER_OBSOLETE, EL_KEY_OBSOLETE, EL_EM_KEY_1_FILE_OBSOLETE, EL_EM_KEY_2_FILE_OBSOLETE, EL_EM_KEY_3_FILE_OBSOLETE, EL_EM_KEY_4_FILE_OBSOLETE, EL_ENVELOPE_OBSOLETE, -1 }; static struct { int *elements; int property; } element_properties[] = { { ep_diggable, EP_DIGGABLE }, { ep_collectible_only, EP_COLLECTIBLE_ONLY }, { ep_dont_run_into, EP_DONT_RUN_INTO }, { ep_dont_collide_with, EP_DONT_COLLIDE_WITH }, { ep_dont_touch, EP_DONT_TOUCH }, { ep_indestructible, EP_INDESTRUCTIBLE }, { ep_slippery, EP_SLIPPERY }, { ep_can_change, EP_CAN_CHANGE }, { ep_can_move, EP_CAN_MOVE }, { ep_can_fall, EP_CAN_FALL }, { ep_can_smash_player, EP_CAN_SMASH_PLAYER }, { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES }, { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING }, { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE }, { ep_explodes_smashed, EP_EXPLODES_SMASHED }, { ep_explodes_impact, EP_EXPLODES_IMPACT }, { ep_walkable_over, EP_WALKABLE_OVER }, { ep_walkable_inside, EP_WALKABLE_INSIDE }, { ep_walkable_under, EP_WALKABLE_UNDER }, { ep_passable_over, EP_PASSABLE_OVER }, { ep_passable_inside, EP_PASSABLE_INSIDE }, { ep_passable_under, EP_PASSABLE_UNDER }, { ep_droppable, EP_DROPPABLE }, { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD }, { ep_pushable, EP_PUSHABLE }, { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD }, { ep_protected, EP_PROTECTED }, { ep_throwable, EP_THROWABLE }, { ep_can_explode, EP_CAN_EXPLODE }, { ep_gravity_reachable, EP_GRAVITY_REACHABLE }, { ep_player, EP_PLAYER }, { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL }, { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL }, { ep_switchable, EP_SWITCHABLE }, { ep_bd_element, EP_BD_ELEMENT }, { ep_sp_element, EP_SP_ELEMENT }, { ep_sb_element, EP_SB_ELEMENT }, { ep_gem, EP_GEM }, { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM }, { ep_food_penguin, EP_FOOD_PENGUIN }, { ep_food_pig, EP_FOOD_PIG }, { ep_historic_wall, EP_HISTORIC_WALL }, { ep_historic_solid, EP_HISTORIC_SOLID }, { ep_classic_enemy, EP_CLASSIC_ENEMY }, { ep_belt, EP_BELT }, { ep_belt_active, EP_BELT_ACTIVE }, { ep_belt_switch, EP_BELT_SWITCH }, { ep_tube, EP_TUBE }, { ep_acid_pool, EP_ACID_POOL }, { ep_keygate, EP_KEYGATE }, { ep_amoeboid, EP_AMOEBOID }, { ep_amoebalive, EP_AMOEBALIVE }, { ep_has_editor_content, EP_HAS_EDITOR_CONTENT }, { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE }, { ep_can_grow, EP_CAN_GROW }, { ep_active_bomb, EP_ACTIVE_BOMB }, { ep_inactive, EP_INACTIVE }, { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL }, { ep_gfx_crumbled, EP_GFX_CRUMBLED }, { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE }, { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE }, { ep_obsolete, EP_OBSOLETE }, { NULL, -1 } }; int i, j, k; /* always start with reliable default values (element has no properties) */ /* (but never initialize clipboard elements after the very first time) */ /* (to be able to use clipboard elements between several levels) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized) for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++) SET_PROPERTY(i, j, FALSE); /* set all base element properties from above array definitions */ for (i = 0; element_properties[i].elements != NULL; i++) for (j = 0; (element_properties[i].elements)[j] != -1; j++) SET_PROPERTY((element_properties[i].elements)[j], element_properties[i].property, TRUE); /* copy properties to some elements that are only stored in level file */ for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) for (j = 0; copy_properties[j][0] != -1; j++) if (HAS_PROPERTY(copy_properties[j][0], i)) for (k = 1; k <= 4; k++) SET_PROPERTY(copy_properties[j][k], i, TRUE); /* set static element properties that are not listed in array definitions */ for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++) SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE); clipboard_elements_initialized = TRUE; } void InitElementPropertiesEngine(int engine_version) { static int no_wall_properties[] = { EP_DIGGABLE, EP_COLLECTIBLE_ONLY, EP_DONT_RUN_INTO, EP_DONT_COLLIDE_WITH, EP_CAN_MOVE, EP_CAN_FALL, EP_CAN_SMASH_PLAYER, EP_CAN_SMASH_ENEMIES, EP_CAN_SMASH_EVERYTHING, EP_PUSHABLE, EP_PLAYER, EP_GEM, EP_FOOD_DARK_YAMYAM, EP_FOOD_PENGUIN, EP_BELT, EP_BELT_ACTIVE, EP_TUBE, EP_AMOEBOID, EP_AMOEBALIVE, EP_ACTIVE_BOMB, EP_ACCESSIBLE, -1 }; int i, j; /* important: after initialization in InitElementPropertiesStatic(), the elements are not again initialized to a default value; therefore all changes have to make sure that they leave the element with a defined property (which means that conditional property changes must be set to a reliable default value before) */ /* resolve group elements */ for (i = 0; i < NUM_GROUP_ELEMENTS; i++) ResolveGroupElement(EL_GROUP_START + i); /* set all special, combined or engine dependent element properties */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { /* do not change (already initialized) clipboard elements here */ if (IS_CLIPBOARD_ELEMENT(i)) continue; /* ---------- INACTIVE ------------------------------------------------- */ SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START && i <= EL_CHAR_END) || (i >= EL_STEEL_CHAR_START && i <= EL_STEEL_CHAR_END))); /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */ SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) || IS_WALKABLE_INSIDE(i) || IS_WALKABLE_UNDER(i))); SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) || IS_PASSABLE_INSIDE(i) || IS_PASSABLE_UNDER(i))); SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) || IS_PASSABLE_OVER(i))); SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) || IS_PASSABLE_INSIDE(i))); SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) || IS_PASSABLE_UNDER(i))); SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) || IS_PASSABLE(i))); /* ---------- COLLECTIBLE ---------------------------------------------- */ SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) || IS_DROPPABLE(i) || IS_THROWABLE(i))); /* ---------- SNAPPABLE ------------------------------------------------ */ SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) || IS_COLLECTIBLE(i) || IS_SWITCHABLE(i) || i == EL_BD_ROCK)); /* ---------- WALL ----------------------------------------------------- */ SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */ for (j = 0; no_wall_properties[j] != -1; j++) if (HAS_PROPERTY(i, no_wall_properties[j]) || i >= EL_FIRST_RUNTIME_UNREAL) SET_PROPERTY(i, EP_WALL, FALSE); if (IS_HISTORIC_WALL(i)) SET_PROPERTY(i, EP_WALL, TRUE); /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */ if (engine_version < VERSION_IDENT(2,2,0,0)) SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i)); else SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) && !IS_DIGGABLE(i) && !IS_COLLECTIBLE(i))); /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */ if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION) SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE); else SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) && IS_INDESTRUCTIBLE(i))); /* ---------- EXPLOSION_PROOF ------------------------------------------ */ if (i == EL_FLAMES) SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE); else if (engine_version < VERSION_IDENT(2,2,0,0)) SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i)); else SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) && (!IS_WALKABLE(i) || IS_PROTECTED(i)))); if (IS_CUSTOM_ELEMENT(i)) { /* these are additional properties which are initially false when set */ /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */ if (DONT_TOUCH(i)) SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE); if (DONT_COLLIDE_WITH(i)) SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE); /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */ if (CAN_SMASH_EVERYTHING(i)) SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE); if (CAN_SMASH_ENEMIES(i)) SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE); } /* ---------- CAN_SMASH ------------------------------------------------ */ SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) || CAN_SMASH_ENEMIES(i) || CAN_SMASH_EVERYTHING(i))); /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) && EXPLODES_BY_FIRE(i))); /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) && EXPLODES_SMASHED(i))); /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) && EXPLODES_IMPACT(i))); /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i)); /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */ SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) || i == EL_BLACK_ORB)); /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */ SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) || CAN_MOVE(i) || IS_CUSTOM_ELEMENT(i))); /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */ SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK || i == EL_SP_ELECTRON)); /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */ if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i)) SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID, getMoveIntoAcidProperty(&level, i)); /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */ if (MAYBE_DONT_COLLIDE_WITH(i)) SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, getDontCollideWithProperty(&level, i)); /* ---------- SP_PORT -------------------------------------------------- */ SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) && IS_PASSABLE_INSIDE(i))); /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */ for (j = 0; j < level.num_android_clone_elements; j++) SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID, (i != EL_EMPTY && IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j]))); /* ---------- CAN_CHANGE ----------------------------------------------- */ SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */ for (j = 0; j < element_info[i].num_change_pages; j++) if (element_info[i].change_page[j].can_change) SET_PROPERTY(i, EP_CAN_CHANGE, TRUE); /* ---------- HAS_ACTION ----------------------------------------------- */ SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */ for (j = 0; j < element_info[i].num_change_pages; j++) if (element_info[i].change_page[j].has_action) SET_PROPERTY(i, EP_HAS_ACTION, TRUE); /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */ SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) || HAS_ACTION(i))); /* ---------- GFX_CRUMBLED --------------------------------------------- */ SET_PROPERTY(i, EP_GFX_CRUMBLED, element_info[i].crumbled[ACTION_DEFAULT] != element_info[i].graphic[ACTION_DEFAULT]); /* ---------- EDITOR_CASCADE ------------------------------------------- */ SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) || IS_EDITOR_CASCADE_INACTIVE(i))); } /* dynamically adjust element properties according to game engine version */ { static int ep_em_slippery_wall[] = { EL_WALL, EL_STEELWALL, EL_EXPANDABLE_WALL, EL_EXPANDABLE_WALL_HORIZONTAL, EL_EXPANDABLE_WALL_VERTICAL, EL_EXPANDABLE_WALL_ANY, EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL, EL_EXPANDABLE_STEELWALL_ANY, EL_EXPANDABLE_STEELWALL_GROWING, -1 }; static int ep_em_explodes_by_fire[] = { EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE, EL_MOLE, -1 }; /* special EM style gems behaviour */ for (i = 0; ep_em_slippery_wall[i] != -1; i++) SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL, level.em_slippery_gems); /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */ SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL, (level.em_slippery_gems && engine_version > VERSION_IDENT(2,0,1,0))); /* special EM style explosion behaviour regarding chain reactions */ for (i = 0; ep_em_explodes_by_fire[i] != -1; i++) SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE, level.em_explodes_by_fire); } /* this is needed because some graphics depend on element properties */ if (game_status == GAME_MODE_PLAYING) InitElementGraphicInfo(); } void InitElementPropertiesGfxElement() { int i; for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i); } } static void InitGlobal() { int graphic; int i; for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++) { /* check if element_name_info entry defined for each element in "main.h" */ if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL) Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i); element_info[i].token_name = element_name_info[i].token_name; element_info[i].class_name = element_name_info[i].class_name; element_info[i].editor_description= element_name_info[i].editor_description; } for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++) { /* check if global_anim_name_info defined for each entry in "main.h" */ if (i < NUM_GLOBAL_ANIM_TOKENS && global_anim_name_info[i].token_name == NULL) Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i); global_anim_info[i].token_name = global_anim_name_info[i].token_name; } /* create hash from image config list */ image_config_hash = newSetupFileHash(); for (i = 0; image_config[i].token != NULL; i++) setHashEntry(image_config_hash, image_config[i].token, image_config[i].value); /* create hash from element token list */ element_token_hash = newSetupFileHash(); for (i = 0; element_name_info[i].token_name != NULL; i++) setHashEntry(element_token_hash, element_name_info[i].token_name, int2str(i, 0)); /* create hash from graphic token list */ graphic_token_hash = newSetupFileHash(); for (graphic = 0, i = 0; image_config[i].token != NULL; i++) if (strSuffix(image_config[i].value, ".png") || strSuffix(image_config[i].value, ".pcx") || strSuffix(image_config[i].value, ".wav") || strEqual(image_config[i].value, UNDEFINED_FILENAME)) setHashEntry(graphic_token_hash, image_config[i].token, int2str(graphic++, 0)); /* create hash from font token list */ font_token_hash = newSetupFileHash(); for (i = 0; font_info[i].token_name != NULL; i++) setHashEntry(font_token_hash, font_info[i].token_name, int2str(i, 0)); /* set default filenames for all cloned graphics in static configuration */ for (i = 0; image_config[i].token != NULL; i++) { if (strEqual(image_config[i].value, UNDEFINED_FILENAME)) { char *token = image_config[i].token; char *token_clone_from = getStringCat2(token, ".clone_from"); char *token_cloned = getHashEntry(image_config_hash, token_clone_from); if (token_cloned != NULL) { char *value_cloned = getHashEntry(image_config_hash, token_cloned); if (value_cloned != NULL) { /* set default filename in static configuration */ image_config[i].value = value_cloned; /* set default filename in image config hash */ setHashEntry(image_config_hash, token, value_cloned); } } free(token_clone_from); } } /* always start with reliable default values (all elements) */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) ActiveElement[i] = i; /* now add all entries that have an active state (active elements) */ for (i = 0; element_with_active_state[i].element != -1; i++) { int element = element_with_active_state[i].element; int element_active = element_with_active_state[i].element_active; ActiveElement[element] = element_active; } /* always start with reliable default values (all buttons) */ for (i = 0; i < NUM_IMAGE_FILES; i++) ActiveButton[i] = i; /* now add all entries that have an active state (active buttons) */ for (i = 0; button_with_active_state[i].button != -1; i++) { int button = button_with_active_state[i].button; int button_active = button_with_active_state[i].button_active; ActiveButton[button] = button_active; } /* always start with reliable default values (all fonts) */ for (i = 0; i < NUM_FONTS; i++) ActiveFont[i] = i; /* now add all entries that have an active state (active fonts) */ for (i = 0; font_with_active_state[i].font_nr != -1; i++) { int font = font_with_active_state[i].font_nr; int font_active = font_with_active_state[i].font_nr_active; ActiveFont[font] = font_active; } global.autoplay_leveldir = NULL; global.convert_leveldir = NULL; global.create_images_dir = NULL; global.frames_per_second = 0; global.show_frames_per_second = FALSE; global.border_status = GAME_MODE_LOADING; global.anim_status = global.anim_status_next = GAME_MODE_LOADING; global.use_envelope_request = FALSE; } void Execute_Command(char *command) { int i; if (strEqual(command, "print graphicsinfo.conf")) { Print("# You can configure additional/alternative image files here.\n"); Print("# (The entries below are default and therefore commented out.)\n"); Print("\n"); Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics")); Print("\n"); Print("%s\n", getFormattedSetupEntry("sort_priority", "100")); Print("\n"); for (i = 0; image_config[i].token != NULL; i++) Print("# %s\n", getFormattedSetupEntry(image_config[i].token, image_config[i].value)); exit(0); } else if (strEqual(command, "print soundsinfo.conf")) { Print("# You can configure additional/alternative sound files here.\n"); Print("# (The entries below are default and therefore commented out.)\n"); Print("\n"); Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds")); Print("\n"); Print("%s\n", getFormattedSetupEntry("sort_priority", "100")); Print("\n"); for (i = 0; sound_config[i].token != NULL; i++) Print("# %s\n", getFormattedSetupEntry(sound_config[i].token, sound_config[i].value)); exit(0); } else if (strEqual(command, "print musicinfo.conf")) { Print("# You can configure additional/alternative music files here.\n"); Print("# (The entries below are default and therefore commented out.)\n"); Print("\n"); Print("%s\n", getFormattedSetupEntry("name", "Classic Music")); Print("\n"); Print("%s\n", getFormattedSetupEntry("sort_priority", "100")); Print("\n"); for (i = 0; music_config[i].token != NULL; i++) Print("# %s\n", getFormattedSetupEntry(music_config[i].token, music_config[i].value)); exit(0); } else if (strEqual(command, "print editorsetup.conf")) { Print("# You can configure your personal editor element list here.\n"); Print("# (The entries below are default and therefore commented out.)\n"); Print("\n"); /* this is needed to be able to check element list for cascade elements */ InitElementPropertiesStatic(); InitElementPropertiesEngine(GAME_VERSION_ACTUAL); PrintEditorElementList(); exit(0); } else if (strEqual(command, "print helpanim.conf")) { Print("# You can configure different element help animations here.\n"); Print("# (The entries below are default and therefore commented out.)\n"); Print("\n"); for (i = 0; helpanim_config[i].token != NULL; i++) { Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token, helpanim_config[i].value)); if (strEqual(helpanim_config[i].token, "end")) Print("#\n"); } exit(0); } else if (strEqual(command, "print helptext.conf")) { Print("# You can configure different element help text here.\n"); Print("# (The entries below are default and therefore commented out.)\n"); Print("\n"); for (i = 0; helptext_config[i].token != NULL; i++) Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token, helptext_config[i].value)); exit(0); } else if (strPrefix(command, "dump level ")) { char *filename = &command[11]; if (!fileExists(filename)) Error(ERR_EXIT, "cannot open file '%s'", filename); LoadLevelFromFilename(&level, filename); DumpLevel(&level); exit(0); } else if (strPrefix(command, "dump tape ")) { char *filename = &command[10]; if (!fileExists(filename)) Error(ERR_EXIT, "cannot open file '%s'", filename); LoadTapeFromFilename(filename); DumpTape(&tape); exit(0); } else if (strPrefix(command, "autotest ") || strPrefix(command, "autoplay ") || strPrefix(command, "autoffwd ") || strPrefix(command, "autowarp ")) { char *str_ptr = getStringCopy(&command[9]); /* read command parameters */ global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST : strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY : strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD : strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP : AUTOPLAY_MODE_NONE); while (*str_ptr != '\0') /* continue parsing string */ { /* cut leading whitespace from string, replace it by string terminator */ while (*str_ptr == ' ' || *str_ptr == '\t') *str_ptr++ = '\0'; if (*str_ptr == '\0') /* end of string reached */ break; if (global.autoplay_leveldir == NULL) /* read level set string */ { global.autoplay_leveldir = str_ptr; global.autoplay_all = TRUE; /* default: play all tapes */ for (i = 0; i < MAX_TAPES_PER_SET; i++) global.autoplay_level[i] = FALSE; } else /* read level number string */ { int level_nr = atoi(str_ptr); /* get level_nr value */ if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET) global.autoplay_level[level_nr] = TRUE; global.autoplay_all = FALSE; } /* advance string pointer to the next whitespace (or end of string) */ while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0') str_ptr++; } if (global.autoplay_mode == AUTOPLAY_MODE_TEST) program.headless = TRUE; } else if (strPrefix(command, "convert ")) { char *str_copy = getStringCopy(strchr(command, ' ') + 1); char *str_ptr = strchr(str_copy, ' '); global.convert_leveldir = str_copy; global.convert_level_nr = -1; if (str_ptr != NULL) /* level number follows */ { *str_ptr++ = '\0'; /* terminate leveldir string */ global.convert_level_nr = atoi(str_ptr); /* get level_nr value */ } program.headless = TRUE; } else if (strPrefix(command, "create images ")) { global.create_images_dir = getStringCopy(&command[14]); if (access(global.create_images_dir, W_OK) != 0) Error(ERR_EXIT, "image target directory '%s' not found or not writable", global.create_images_dir); } else if (strPrefix(command, "create CE image ")) { CreateCustomElementImages(&command[16]); exit(0); } else { Error(ERR_EXIT_HELP, "unrecognized command '%s'", command); } } static void InitSetup() { LoadSetup(); /* global setup info */ LoadSetup_AutoSetup(); /* global auto setup info */ /* set some options from setup file */ if (setup.options.verbose) options.verbose = TRUE; if (setup.debug.show_frames_per_second) global.show_frames_per_second = TRUE; } static void InitGameInfo() { game.restart_level = FALSE; game.restart_game_message = NULL; } static void InitPlayerInfo() { int i; /* choose default local player */ local_player = &stored_player[0]; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = FALSE; local_player->connected = TRUE; } static void InitArtworkInfo() { LoadArtworkInfo(); } static char *get_string_in_brackets(char *string) { char *string_in_brackets = checked_malloc(strlen(string) + 3); sprintf(string_in_brackets, "[%s]", string); return string_in_brackets; } static char *get_level_id_suffix(int id_nr) { char *id_suffix = checked_malloc(1 + 3 + 1); if (id_nr < 0 || id_nr > 999) id_nr = 0; sprintf(id_suffix, ".%03d", id_nr); return id_suffix; } static void InitArtworkConfig() { static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS + 1]; static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS + 1]; static char *music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS + 1]; static char *action_id_suffix[NUM_ACTIONS + 1]; static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1]; static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1]; static char *level_id_suffix[MAX_LEVELS + 1]; static char *dummy[1] = { NULL }; static char *ignore_generic_tokens[] = { "name", "sort_priority", "program_title", "program_copyright", "program_company", NULL }; static char **ignore_image_tokens; static char **ignore_sound_tokens; static char **ignore_music_tokens; int num_ignore_generic_tokens; int num_ignore_image_tokens; int num_ignore_sound_tokens; int num_ignore_music_tokens; int i; /* dynamically determine list of generic tokens to be ignored */ num_ignore_generic_tokens = 0; for (i = 0; ignore_generic_tokens[i] != NULL; i++) num_ignore_generic_tokens++; /* dynamically determine list of image tokens to be ignored */ num_ignore_image_tokens = num_ignore_generic_tokens; for (i = 0; image_config_vars[i].token != NULL; i++) num_ignore_image_tokens++; ignore_image_tokens = checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *)); for (i = 0; i < num_ignore_generic_tokens; i++) ignore_image_tokens[i] = ignore_generic_tokens[i]; for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++) ignore_image_tokens[num_ignore_generic_tokens + i] = image_config_vars[i].token; ignore_image_tokens[num_ignore_image_tokens] = NULL; /* dynamically determine list of sound tokens to be ignored */ num_ignore_sound_tokens = num_ignore_generic_tokens; ignore_sound_tokens = checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *)); for (i = 0; i < num_ignore_generic_tokens; i++) ignore_sound_tokens[i] = ignore_generic_tokens[i]; ignore_sound_tokens[num_ignore_sound_tokens] = NULL; /* dynamically determine list of music tokens to be ignored */ num_ignore_music_tokens = num_ignore_generic_tokens; ignore_music_tokens = checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *)); for (i = 0; i < num_ignore_generic_tokens; i++) ignore_music_tokens[i] = ignore_generic_tokens[i]; ignore_music_tokens[num_ignore_music_tokens] = NULL; for (i = 0; i < MAX_NUM_ELEMENTS; i++) image_id_prefix[i] = element_info[i].token_name; for (i = 0; i < NUM_FONTS; i++) image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name; for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] = global_anim_info[i].token_name; image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL; for (i = 0; i < MAX_NUM_ELEMENTS; i++) sound_id_prefix[i] = element_info[i].token_name; for (i = 0; i < MAX_NUM_ELEMENTS; i++) sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_string_in_brackets(element_info[i].class_name); for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] = global_anim_info[i].token_name; sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL; for (i = 0; i < NUM_MUSIC_PREFIXES; i++) music_id_prefix[i] = music_prefix_info[i].prefix; for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++) music_id_prefix[NUM_MUSIC_PREFIXES + i] = global_anim_info[i].token_name; music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL; for (i = 0; i < NUM_ACTIONS; i++) action_id_suffix[i] = element_action_info[i].suffix; action_id_suffix[NUM_ACTIONS] = NULL; for (i = 0; i < NUM_DIRECTIONS_FULL; i++) direction_id_suffix[i] = element_direction_info[i].suffix; direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL; for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) special_id_suffix[i] = special_suffix_info[i].suffix; special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL; for (i = 0; i < MAX_LEVELS; i++) level_id_suffix[i] = get_level_id_suffix(i); level_id_suffix[MAX_LEVELS] = NULL; InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix, image_id_prefix, action_id_suffix, direction_id_suffix, special_id_suffix, ignore_image_tokens); InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix, sound_id_prefix, action_id_suffix, dummy, special_id_suffix, ignore_sound_tokens); InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix, music_id_prefix, action_id_suffix, special_id_suffix, level_id_suffix, ignore_music_tokens); } static void InitMixer() { OpenAudio(); StartMixer(); } void InitGfxBuffers() { static int win_xsize_last = -1; static int win_ysize_last = -1; /* create additional image buffers for double-buffering and cross-fading */ if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last) { /* used to temporarily store the backbuffer -- only re-create if changed */ ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE); ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE); win_xsize_last = WIN_XSIZE; win_ysize_last = WIN_YSIZE; } ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE); ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE); ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE); ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE); /* initialize screen properties */ InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, bitmap_db_field); InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE); InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE); InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE); InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE); InitGfxScrollbufferInfo(FXSIZE, FYSIZE); InitGfxClipRegion(FALSE, -1, -1, -1, -1); /* required if door size definitions have changed */ InitGraphicCompatibilityInfo_Doors(); InitGfxBuffers_EM(); InitGfxBuffers_SP(); } void InitGfx() { struct GraphicInfo *graphic_info_last = graphic_info; char *filename_font_initial = NULL; char *filename_anim_initial = NULL; Bitmap *bitmap_font_initial = NULL; int font_height; int i, j; /* determine settings for initial font (for displaying startup messages) */ for (i = 0; image_config[i].token != NULL; i++) { for (j = 0; j < NUM_INITIAL_FONTS; j++) { char font_token[128]; int len_font_token; sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1); len_font_token = strlen(font_token); if (strEqual(image_config[i].token, font_token)) filename_font_initial = image_config[i].value; else if (strlen(image_config[i].token) > len_font_token && strncmp(image_config[i].token, font_token, len_font_token) == 0) { if (strEqual(&image_config[i].token[len_font_token], ".x")) font_initial[j].src_x = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_font_token], ".y")) font_initial[j].src_y = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_font_token], ".width")) font_initial[j].width = atoi(image_config[i].value); else if (strEqual(&image_config[i].token[len_font_token], ".height")) font_initial[j].height = atoi(image_config[i].value); } } } for (j = 0; j < NUM_INITIAL_FONTS; j++) { font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT; font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE; } if (filename_font_initial == NULL) /* should not happen */ Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL); InitGfxBuffers(); InitGfxCustomArtworkInfo(); InitGfxOtherSettings(); bitmap_font_initial = LoadCustomImage(filename_font_initial); for (j = 0; j < NUM_INITIAL_FONTS; j++) font_initial[j].bitmap = bitmap_font_initial; InitFontGraphicInfo(); font_height = getFontHeight(FC_RED); DrawInitText(getProgramInitString(), 20, FC_YELLOW); DrawInitText(setup.internal.program_copyright, 50, FC_RED); DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height, FC_RED); DrawInitText("Loading graphics", 120, FC_GREEN); /* initialize settings for busy animation with default values */ int parameter[NUM_GFX_ARGS]; for (i = 0; i < NUM_GFX_ARGS; i++) parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value, image_config_suffix[i].token, image_config_suffix[i].type); char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY; int len_anim_token = strlen(anim_token); /* read settings for busy animation from default custom artwork config */ char *gfx_config_filename = getPath3(options.graphics_directory, GFX_DEFAULT_SUBDIR, GRAPHICSINFO_FILENAME); if (fileExists(gfx_config_filename)) { SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename); if (setup_file_hash) { char *filename = getHashEntry(setup_file_hash, anim_token); if (filename) { filename_anim_initial = getStringCopy(filename); for (j = 0; image_config_suffix[j].token != NULL; j++) { int type = image_config_suffix[j].type; char *suffix = image_config_suffix[j].token; char *token = getStringCat2(anim_token, suffix); char *value = getHashEntry(setup_file_hash, token); checked_free(token); if (value) parameter[j] = get_graphic_parameter_value(value, suffix, type); } } freeSetupFileHash(setup_file_hash); } } if (filename_anim_initial == NULL) { /* read settings for busy animation from static default artwork config */ for (i = 0; image_config[i].token != NULL; i++) { if (strEqual(image_config[i].token, anim_token)) filename_anim_initial = getStringCopy(image_config[i].value); else if (strlen(image_config[i].token) > len_anim_token && strncmp(image_config[i].token, anim_token, len_anim_token) == 0) { for (j = 0; image_config_suffix[j].token != NULL; j++) { if (strEqual(&image_config[i].token[len_anim_token], image_config_suffix[j].token)) parameter[j] = get_graphic_parameter_value(image_config[i].value, image_config_suffix[j].token, image_config_suffix[j].type); } } } } if (filename_anim_initial == NULL) /* should not happen */ Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY); anim_initial.bitmaps = checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS); anim_initial.bitmaps[IMG_BITMAP_STANDARD] = LoadCustomImage(filename_anim_initial); checked_free(filename_anim_initial); graphic_info = &anim_initial; /* graphic == 0 => anim_initial */ set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps); graphic_info = graphic_info_last; init.busy.width = anim_initial.width; init.busy.height = anim_initial.height; InitMenuDesignSettings_Static(); InitGfxDrawBusyAnimFunction(DrawInitAnim); InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations); InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget); InitGfxDrawTileCursorFunction(DrawTileCursor); gfx.fade_border_source_status = global.border_status; gfx.fade_border_target_status = global.border_status; gfx.masked_border_bitmap_ptr = backbuffer; /* use copy of busy animation to prevent change while reloading artwork */ init_last = init; } void InitGfxBackground() { fieldbuffer = bitmap_db_field; SetDrawtoField(DRAW_TO_BACKBUFFER); ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE); redraw_mask = REDRAW_ALL; } static void InitLevelInfo() { LoadLevelInfo(); /* global level info */ LoadLevelSetup_LastSeries(); /* last played series info */ LoadLevelSetup_SeriesInfo(); /* last played level info */ if (global.autoplay_leveldir && global.autoplay_mode != AUTOPLAY_MODE_TEST) { leveldir_current = getTreeInfoFromIdentifier(leveldir_first, global.autoplay_leveldir); if (leveldir_current == NULL) leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); } } static void InitLevelArtworkInfo() { LoadLevelArtworkInfo(); } static void InitImages() { print_timestamp_init("InitImages"); #if 0 printf("::: leveldir_current->identifier == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier); printf("::: leveldir_current->graphics_path == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path); printf("::: leveldir_current->graphics_set == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set); printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n", leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS)); #endif setLevelArtworkDir(artwork.gfx_first); #if 0 printf("::: leveldir_current->identifier == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier); printf("::: leveldir_current->graphics_path == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path); printf("::: leveldir_current->graphics_set == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set); printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n", leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS)); #endif #if 0 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n", leveldir_current->identifier, artwork.gfx_current_identifier, artwork.gfx_current->identifier, leveldir_current->graphics_set, leveldir_current->graphics_path); #endif UPDATE_BUSY_STATE(); ReloadCustomImages(); print_timestamp_time("ReloadCustomImages"); UPDATE_BUSY_STATE(); LoadCustomElementDescriptions(); print_timestamp_time("LoadCustomElementDescriptions"); UPDATE_BUSY_STATE(); LoadMenuDesignSettings(); print_timestamp_time("LoadMenuDesignSettings"); UPDATE_BUSY_STATE(); ReinitializeGraphics(); print_timestamp_time("ReinitializeGraphics"); LoadMenuDesignSettings_AfterGraphics(); print_timestamp_time("LoadMenuDesignSettings_AfterGraphics"); UPDATE_BUSY_STATE(); print_timestamp_done("InitImages"); } static void InitSound(char *identifier) { print_timestamp_init("InitSound"); if (identifier == NULL) identifier = artwork.snd_current->identifier; /* set artwork path to send it to the sound server process */ setLevelArtworkDir(artwork.snd_first); InitReloadCustomSounds(identifier); print_timestamp_time("InitReloadCustomSounds"); ReinitializeSounds(); print_timestamp_time("ReinitializeSounds"); print_timestamp_done("InitSound"); } static void InitMusic(char *identifier) { print_timestamp_init("InitMusic"); if (identifier == NULL) identifier = artwork.mus_current->identifier; /* set artwork path to send it to the sound server process */ setLevelArtworkDir(artwork.mus_first); InitReloadCustomMusic(identifier); print_timestamp_time("InitReloadCustomMusic"); ReinitializeMusic(); print_timestamp_time("ReinitializeMusic"); print_timestamp_done("InitMusic"); } static void InitArtworkDone() { if (program.headless) return; InitGlobalAnimations(); } void InitNetworkServer() { #if defined(NETWORK_AVALIABLE) int nr_wanted; #endif if (!options.network) return; #if defined(NETWORK_AVALIABLE) 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 } static boolean CheckArtworkConfigForCustomElements(char *filename) { SetupFileHash *setup_file_hash; boolean redefined_ce_found = FALSE; /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */ if ((setup_file_hash = loadSetupFileHash(filename)) != NULL) { BEGIN_HASH_ITERATION(setup_file_hash, itr) { char *token = HASH_ITERATION_TOKEN(itr); if (strPrefix(token, "custom_")) { redefined_ce_found = TRUE; break; } } END_HASH_ITERATION(setup_file_hash, itr) freeSetupFileHash(setup_file_hash); } return redefined_ce_found; } static boolean CheckArtworkTypeForRedefinedCustomElements(int type) { char *filename_base, *filename_local; boolean redefined_ce_found = FALSE; setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type)); #if 0 printf("::: leveldir_current->identifier == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier); printf("::: leveldir_current->graphics_path == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path); printf("::: leveldir_current->graphics_set == '%s'\n", leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set); printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n", leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, type)); #endif /* first look for special artwork configured in level series config */ filename_base = getCustomArtworkLevelConfigFilename(type); #if 0 printf("::: filename_base == '%s'\n", filename_base); #endif if (fileExists(filename_base)) redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base); filename_local = getCustomArtworkConfigFilename(type); #if 0 printf("::: filename_local == '%s'\n", filename_local); #endif if (filename_local != NULL && !strEqual(filename_base, filename_local)) redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local); #if 0 printf("::: redefined_ce_found == %d\n", redefined_ce_found); #endif return redefined_ce_found; } static void InitOverrideArtwork() { boolean redefined_ce_found = FALSE; /* to check if this level set redefines any CEs, do not use overriding */ gfx.override_level_graphics = FALSE; gfx.override_level_sounds = FALSE; gfx.override_level_music = FALSE; /* now check if this level set has definitions for custom elements */ if (setup.override_level_graphics == AUTO || setup.override_level_sounds == AUTO || setup.override_level_music == AUTO) redefined_ce_found = (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) | CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) | CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC)); #if 0 printf("::: redefined_ce_found == %d\n", redefined_ce_found); #endif if (redefined_ce_found) { /* this level set has CE definitions: change "AUTO" to "FALSE" */ gfx.override_level_graphics = (setup.override_level_graphics == TRUE); gfx.override_level_sounds = (setup.override_level_sounds == TRUE); gfx.override_level_music = (setup.override_level_music == TRUE); } else { /* this level set has no CE definitions: change "AUTO" to "TRUE" */ gfx.override_level_graphics = (setup.override_level_graphics != FALSE); gfx.override_level_sounds = (setup.override_level_sounds != FALSE); gfx.override_level_music = (setup.override_level_music != FALSE); } #if 0 printf("::: => %d, %d, %d\n", gfx.override_level_graphics, gfx.override_level_sounds, gfx.override_level_music); #endif } static char *getNewArtworkIdentifier(int type) { static char *leveldir_current_identifier[3] = { NULL, NULL, NULL }; static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE }; static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE }; static boolean initialized[3] = { FALSE, FALSE, FALSE }; TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type); boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type); char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type); char *leveldir_identifier = leveldir_current->identifier; /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */ char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node); boolean has_level_artwork_set = (leveldir_artwork_set != NULL); char *artwork_current_identifier; char *artwork_new_identifier = NULL; /* default: nothing has changed */ /* leveldir_current may be invalid (level group, parent link) */ if (!validLevelSeries(leveldir_current)) return NULL; /* 1st step: determine artwork set to be activated in descending order: -------------------------------------------------------------------- 1. setup artwork (when configured to override everything else) 2. artwork set configured in "levelinfo.conf" of current level set (artwork in level directory will have priority when loading later) 3. artwork in level directory (stored in artwork sub-directory) 4. setup artwork (currently configured in setup menu) */ if (setup_override_artwork) artwork_current_identifier = setup_artwork_set; else if (leveldir_artwork_set != NULL) artwork_current_identifier = leveldir_artwork_set; else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier)) artwork_current_identifier = leveldir_identifier; else artwork_current_identifier = setup_artwork_set; /* 2nd step: check if it is really needed to reload artwork set ------------------------------------------------------------ */ /* ---------- reload if level set and also artwork set has changed ------- */ if (leveldir_current_identifier[type] != leveldir_identifier && (last_has_level_artwork_set[type] || has_level_artwork_set)) artwork_new_identifier = artwork_current_identifier; leveldir_current_identifier[type] = leveldir_identifier; last_has_level_artwork_set[type] = has_level_artwork_set; /* ---------- reload if "override artwork" setting has changed ----------- */ if (last_override_level_artwork[type] != setup_override_artwork) artwork_new_identifier = artwork_current_identifier; last_override_level_artwork[type] = setup_override_artwork; /* ---------- reload if current artwork identifier has changed ----------- */ if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type), artwork_current_identifier)) artwork_new_identifier = artwork_current_identifier; *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier; /* ---------- do not reload directly after starting ---------------------- */ if (!initialized[type]) artwork_new_identifier = NULL; initialized[type] = TRUE; return artwork_new_identifier; } void ReloadCustomArtwork(int force_reload) { int last_game_status = game_status; /* save current game status */ char *gfx_new_identifier; char *snd_new_identifier; char *mus_new_identifier; boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS)); boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS)); boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC)); boolean reload_needed; InitOverrideArtwork(); force_reload_gfx |= AdjustGraphicsForEMC(); gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS); snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS); mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC); reload_needed = (gfx_new_identifier != NULL || force_reload_gfx || snd_new_identifier != NULL || force_reload_snd || mus_new_identifier != NULL || force_reload_mus); if (!reload_needed) return; print_timestamp_init("ReloadCustomArtwork"); SetGameStatus(GAME_MODE_LOADING); FadeOut(REDRAW_ALL); ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); print_timestamp_time("ClearRectangle"); FadeIn(REDRAW_ALL); if (gfx_new_identifier != NULL || force_reload_gfx) { #if 0 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n", artwork.gfx_current_identifier, gfx_new_identifier, artwork.gfx_current->identifier, leveldir_current->graphics_set); #endif InitImages(); print_timestamp_time("InitImages"); } if (snd_new_identifier != NULL || force_reload_snd) { InitSound(snd_new_identifier); print_timestamp_time("InitSound"); } if (mus_new_identifier != NULL || force_reload_mus) { InitMusic(mus_new_identifier); print_timestamp_time("InitMusic"); } InitArtworkDone(); SetGameStatus(last_game_status); /* restore current game status */ init_last = init; /* switch to new busy animation */ FadeOut(REDRAW_ALL); RedrawGlobalBorder(); /* force redraw of (open or closed) door graphics */ SetDoorState(DOOR_OPEN_ALL); CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY); FadeSetEnterScreen(); FadeSkipNextFadeOut(); print_timestamp_done("ReloadCustomArtwork"); LimitScreenUpdates(FALSE); } void KeyboardAutoRepeatOffUnlessAutoplay() { if (global.autoplay_leveldir == NULL) KeyboardAutoRepeatOff(); } void DisplayExitMessage(char *format, va_list ap) { // also check for initialized video (headless flag may be temporarily unset) if (program.headless || !video.initialized) return; // check if draw buffer and fonts for exit message are already available if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL) return; int font_1 = FC_RED; int font_2 = FC_YELLOW; int font_3 = FC_BLUE; int font_width = getFontWidth(font_2); int font_height = getFontHeight(font_2); int sx = SX; int sy = SY; int sxsize = WIN_XSIZE - 2 * sx; int sysize = WIN_YSIZE - 2 * sy; int line_length = sxsize / font_width; int max_lines = sysize / font_height; int num_lines_printed; gfx.sx = sx; gfx.sy = sy; gfx.sxsize = sxsize; gfx.sysize = sysize; sy = 20; ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); DrawTextSCentered(sy, font_1, "Fatal error:"); sy += 3 * font_height;; num_lines_printed = DrawTextBufferVA(sx, sy, format, ap, font_2, line_length, line_length, max_lines, 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE); sy += (num_lines_printed + 3) * font_height; DrawTextSCentered(sy, font_1, "For details, see the following error file:"); sy += 3 * font_height; num_lines_printed = DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2, line_length, line_length, max_lines, 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE); DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit"); redraw_mask = REDRAW_ALL; /* force drawing exit message even if screen updates are currently limited */ LimitScreenUpdates(FALSE); BackToFront(); /* deactivate toons on error message screen */ setup.toons = FALSE; WaitForEventToContinue(); } /* ========================================================================= */ /* OpenAll() */ /* ========================================================================= */ void OpenAll() { print_timestamp_init("OpenAll"); SetGameStatus(GAME_MODE_LOADING); InitCounter(); InitGlobal(); /* initialize some global variables */ print_timestamp_time("[init global stuff]"); InitSetup(); print_timestamp_time("[init setup/config stuff (1)]"); InitScoresInfo(); if (options.execute_command) Execute_Command(options.execute_command); if (options.serveronly) { #if defined(PLATFORM_UNIX) NetworkServer(options.server_port, options.serveronly); #else Error(ERR_WARN, "networking only supported in Unix version"); #endif exit(0); /* never reached, server loops forever */ } InitGameInfo(); print_timestamp_time("[init setup/config stuff (2)]"); InitPlayerInfo(); print_timestamp_time("[init setup/config stuff (3)]"); InitArtworkInfo(); /* needed before loading gfx, sound & music */ print_timestamp_time("[init setup/config stuff (4)]"); InitArtworkConfig(); /* needed before forking sound child process */ print_timestamp_time("[init setup/config stuff (5)]"); InitMixer(); print_timestamp_time("[init setup/config stuff (6)]"); InitRND(NEW_RANDOMIZE); InitSimpleRandom(NEW_RANDOMIZE); InitJoysticks(); print_timestamp_time("[init setup/config stuff]"); InitVideoDefaults(); InitVideoDisplay(); InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen); InitTileCursorInfo(); InitOverlayInfo(); print_timestamp_time("[init video stuff]"); InitElementPropertiesStatic(); InitElementPropertiesEngine(GAME_VERSION_ACTUAL); InitElementPropertiesGfxElement(); print_timestamp_time("[init element properties stuff]"); InitGfx(); print_timestamp_time("InitGfx"); InitLevelInfo(); print_timestamp_time("InitLevelInfo"); InitLevelArtworkInfo(); print_timestamp_time("InitLevelArtworkInfo"); InitOverrideArtwork(); /* needs to know current level directory */ print_timestamp_time("InitOverrideArtwork"); InitImages(); /* needs to know current level directory */ print_timestamp_time("InitImages"); InitSound(NULL); /* needs to know current level directory */ print_timestamp_time("InitSound"); InitMusic(NULL); /* needs to know current level directory */ print_timestamp_time("InitMusic"); InitArtworkDone(); InitGfxBackground(); em_open_all(); sp_open_all(); mm_open_all(); if (global.autoplay_leveldir) { AutoPlayTape(); return; } else if (global.convert_leveldir) { ConvertLevels(); return; } else if (global.create_images_dir) { CreateLevelSketchImages(); return; } SetGameStatus(GAME_MODE_MAIN); FadeSetEnterScreen(); if (!(fading.fade_mode & FADE_TYPE_TRANSFORM)) FadeSkipNextFadeOut(); print_timestamp_time("[post-artwork]"); print_timestamp_done("OpenAll"); DrawMainMenu(); InitNetworkServer(); #if 0 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'", SDL_GetBasePath()); Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'", SDL_GetPrefPath("artsoft", "rocksndiamonds")); #if defined(PLATFORM_ANDROID) Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'", SDL_AndroidGetInternalStoragePath()); Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'", SDL_AndroidGetExternalStoragePath()); Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'", (SDL_AndroidGetExternalStorageState() & SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" : SDL_AndroidGetExternalStorageState() & SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available")); #endif #endif } void CloseAllAndExit(int exit_value) { StopSounds(); FreeAllSounds(); FreeAllMusic(); CloseAudio(); /* called after freeing sounds (needed for SDL) */ em_close_all(); sp_close_all(); FreeAllImages(); #if defined(TARGET_SDL) #if defined(TARGET_SDL2) // !!! TODO !!! // set a flag to tell the network server thread to quit and wait for it // using SDL_WaitThread() #else if (network_server) /* terminate network server */ SDL_KillThread(server_thread); #endif #endif CloseVideoDisplay(); ClosePlatformDependentStuff(); if (exit_value != 0 && !options.execute_command) { /* fall back to default level set (current set may have caused an error) */ SaveLevelSetup_LastSeries_Deactivate(); /* tell user where to find error log file which may contain more details */ // (error notification now directly displayed on screen inside R'n'D // NotifyUserAboutErrorFile(); /* currently only works for Windows */ } exit(exit_value); } mirrormagic-3.0.0/src/tools.c0000644000175000017500000072373313263212010015433 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // tools.c // ============================================================================ #include #include "libgame/libgame.h" #include "tools.h" #include "init.h" #include "game.h" #include "events.h" #include "anim.h" #include "network.h" #include "tape.h" #include "screens.h" /* select level set with EMC X11 graphics before activating EM GFX debugging */ #define DEBUG_EM_GFX FALSE #define DEBUG_FRAME_TIME FALSE /* tool button identifiers */ #define TOOL_CTRL_ID_YES 0 #define TOOL_CTRL_ID_NO 1 #define TOOL_CTRL_ID_CONFIRM 2 #define TOOL_CTRL_ID_PLAYER_1 3 #define TOOL_CTRL_ID_PLAYER_2 4 #define TOOL_CTRL_ID_PLAYER_3 5 #define TOOL_CTRL_ID_PLAYER_4 6 #define NUM_TOOL_BUTTONS 7 /* constants for number of doors and door parts */ #define NUM_DOORS 2 #define NUM_PANELS NUM_DOORS // #define NUM_PANELS 0 #define MAX_PARTS_PER_DOOR 8 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS) #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR) struct DoorPartOrderInfo { int nr; int sort_priority; }; static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS]; struct DoorPartControlInfo { int door_token; int graphic; struct DoorPartPosInfo *pos; }; static struct DoorPartControlInfo door_part_controls[] = { { DOOR_1, IMG_GFX_DOOR_1_PART_1, &door_1.part_1 }, { DOOR_1, IMG_GFX_DOOR_1_PART_2, &door_1.part_2 }, { DOOR_1, IMG_GFX_DOOR_1_PART_3, &door_1.part_3 }, { DOOR_1, IMG_GFX_DOOR_1_PART_4, &door_1.part_4 }, { DOOR_1, IMG_GFX_DOOR_1_PART_5, &door_1.part_5 }, { DOOR_1, IMG_GFX_DOOR_1_PART_6, &door_1.part_6 }, { DOOR_1, IMG_GFX_DOOR_1_PART_7, &door_1.part_7 }, { DOOR_1, IMG_GFX_DOOR_1_PART_8, &door_1.part_8 }, { DOOR_2, IMG_GFX_DOOR_2_PART_1, &door_2.part_1 }, { DOOR_2, IMG_GFX_DOOR_2_PART_2, &door_2.part_2 }, { DOOR_2, IMG_GFX_DOOR_2_PART_3, &door_2.part_3 }, { DOOR_2, IMG_GFX_DOOR_2_PART_4, &door_2.part_4 }, { DOOR_2, IMG_GFX_DOOR_2_PART_5, &door_2.part_5 }, { DOOR_2, IMG_GFX_DOOR_2_PART_6, &door_2.part_6 }, { DOOR_2, IMG_GFX_DOOR_2_PART_7, &door_2.part_7 }, { DOOR_2, IMG_GFX_DOOR_2_PART_8, &door_2.part_8 }, { DOOR_1, IMG_BACKGROUND_PANEL, &door_1.panel }, { DOOR_2, IMG_BACKGROUND_TAPE, &door_2.panel }, { -1, -1, NULL } }; /* forward declaration for internal use */ static void UnmapToolButtons(); static void HandleToolButtons(struct GadgetInfo *); static int el_act_dir2crm(int, int, int); static int el_act2crm(int, int); static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS]; static int request_gadget_id = -1; static char *print_if_not_empty(int element) { static char *s = NULL; char *token_name = element_info[element].token_name; if (s != NULL) free(s); s = checked_malloc(strlen(token_name) + 10 + 1); if (element != EL_EMPTY) sprintf(s, "%d\t['%s']", element, token_name); else sprintf(s, "%d", element); return s; } int correctLevelPosX_EM(int lx) { lx -= 1; lx -= (BorderElement != EL_EMPTY ? 1 : 0); return lx; } int correctLevelPosY_EM(int ly) { ly -= 1; ly -= (BorderElement != EL_EMPTY ? 1 : 0); return ly; } static int getFieldbufferOffsetX_RND() { int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0); int dx_var = dx * TILESIZE_VAR / TILESIZE; int fx = FX; if (EVEN(SCR_FIELDX)) { int ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var; if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR) fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR; else fx += (dx_var > 0 ? TILEX_VAR : 0); } else { fx += dx_var; } if (full_lev_fieldx <= SCR_FIELDX) { if (EVEN(SCR_FIELDX)) fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0); else fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0); } return fx; } static int getFieldbufferOffsetY_RND() { int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0); int dy_var = dy * TILESIZE_VAR / TILESIZE; int fy = FY; if (EVEN(SCR_FIELDY)) { int ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var; if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR) fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR; else fy += (dy_var > 0 ? TILEY_VAR : 0); } else { fy += dy_var; } if (full_lev_fieldy <= SCR_FIELDY) { if (EVEN(SCR_FIELDY)) fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0); else fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0); } return fy; } static int getLevelFromScreenX_RND(int sx) { int fx = getFieldbufferOffsetX_RND(); int dx = fx - FX; int px = sx - SX; int lx = LEVELX((px + dx) / TILESIZE_VAR); return lx; } static int getLevelFromScreenY_RND(int sy) { int fy = getFieldbufferOffsetY_RND(); int dy = fy - FY; int py = sy - SY; int ly = LEVELY((py + dy) / TILESIZE_VAR); return ly; } static int getLevelFromScreenX_EM(int sx) { int level_xsize = level.native_em_level->lev->width; int full_xsize = level_xsize * TILESIZE_VAR; sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); int fx = getFieldbufferOffsetX_EM(); int dx = fx; int px = sx - SX; int lx = LEVELX((px + dx) / TILESIZE_VAR); lx = correctLevelPosX_EM(lx); return lx; } static int getLevelFromScreenY_EM(int sy) { int level_ysize = level.native_em_level->lev->height; int full_ysize = level_ysize * TILESIZE_VAR; sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); int fy = getFieldbufferOffsetY_EM(); int dy = fy; int py = sy - SY; int ly = LEVELY((py + dy) / TILESIZE_VAR); ly = correctLevelPosY_EM(ly); return ly; } static int getLevelFromScreenX_SP(int sx) { int menBorder = setup.sp_show_border_elements; int level_xsize = level.native_sp_level->width; int full_xsize = (level_xsize - (menBorder ? 0 : 1)) * TILESIZE_VAR; sx += (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); int fx = getFieldbufferOffsetX_SP(); int dx = fx - FX; int px = sx - SX; int lx = LEVELX((px + dx) / TILESIZE_VAR); return lx; } static int getLevelFromScreenY_SP(int sy) { int menBorder = setup.sp_show_border_elements; int level_ysize = level.native_sp_level->height; int full_ysize = (level_ysize - (menBorder ? 0 : 1)) * TILESIZE_VAR; sy += (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); int fy = getFieldbufferOffsetY_SP(); int dy = fy - FY; int py = sy - SY; int ly = LEVELY((py + dy) / TILESIZE_VAR); return ly; } static int getLevelFromScreenX_MM(int sx) { int level_xsize = level.native_mm_level->fieldx; int full_xsize = level_xsize * TILESIZE_VAR; sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); int px = sx - SX; int lx = (px + TILESIZE_VAR) / TILESIZE_VAR - 1; return lx; } static int getLevelFromScreenY_MM(int sy) { int level_ysize = level.native_mm_level->fieldy; int full_ysize = level_ysize * TILESIZE_VAR; sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); int py = sy - SY; int ly = (py + TILESIZE_VAR) / TILESIZE_VAR - 1; return ly; } int getLevelFromScreenX(int x) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) return getLevelFromScreenX_EM(x); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return getLevelFromScreenX_SP(x); if (level.game_engine_type == GAME_ENGINE_TYPE_MM) return getLevelFromScreenX_MM(x); else return getLevelFromScreenX_RND(x); } int getLevelFromScreenY(int y) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) return getLevelFromScreenY_EM(y); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return getLevelFromScreenY_SP(y); if (level.game_engine_type == GAME_ENGINE_TYPE_MM) return getLevelFromScreenY_MM(y); else return getLevelFromScreenY_RND(y); } void DumpTile(int x, int y) { int sx = SCREENX(x); int sy = SCREENY(y); char *token_name; printf_line("-", 79); printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y); printf_line("-", 79); if (!IN_LEV_FIELD(x, y)) { printf("(not in level field)\n"); printf("\n"); return; } token_name = element_info[Feld[x][y]].token_name; printf(" Feld: %d\t['%s']\n", Feld[x][y], token_name); printf(" Back: %s\n", print_if_not_empty(Back[x][y])); printf(" Store: %s\n", print_if_not_empty(Store[x][y])); printf(" Store2: %s\n", print_if_not_empty(Store2[x][y])); printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y])); printf(" MovPos: %d\n", MovPos[x][y]); printf(" MovDir: %d\n", MovDir[x][y]); printf(" MovDelay: %d\n", MovDelay[x][y]); printf(" ChangeDelay: %d\n", ChangeDelay[x][y]); printf(" CustomValue: %d\n", CustomValue[x][y]); printf(" GfxElement: %d\n", GfxElement[x][y]); printf(" GfxAction: %d\n", GfxAction[x][y]); printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter); printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy); printf("\n"); } void DumpTileFromScreen(int sx, int sy) { int lx = getLevelFromScreenX(sx); int ly = getLevelFromScreenY(sy); DumpTile(lx, ly); } void SetDrawtoField(int mode) { if (mode == DRAW_TO_FIELDBUFFER) { FX = 2 * TILEX_VAR; FY = 2 * TILEY_VAR; BX1 = -2; BY1 = -2; BX2 = SCR_FIELDX + 1; BY2 = SCR_FIELDY + 1; drawto_field = fieldbuffer; } else /* DRAW_TO_BACKBUFFER */ { FX = SX; FY = SY; BX1 = 0; BY1 = 0; BX2 = SCR_FIELDX - 1; BY2 = SCR_FIELDY - 1; drawto_field = backbuffer; } } static void RedrawPlayfield_RND() { if (game.envelope_active) return; DrawLevel(REDRAW_ALL); DrawAllPlayers(); } void RedrawPlayfield() { if (game_status != GAME_MODE_PLAYING) return; if (level.game_engine_type == GAME_ENGINE_TYPE_EM) RedrawPlayfield_EM(TRUE); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) RedrawPlayfield_SP(TRUE); else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) RedrawPlayfield_MM(); else if (level.game_engine_type == GAME_ENGINE_TYPE_RND) RedrawPlayfield_RND(); BlitScreenToBitmap(backbuffer); BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize, gfx.sx, gfx.sy); } static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height, int draw_target) { Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status); Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr; if (x == -1 && y == -1) return; if (draw_target == DRAW_TO_SCREEN) BlitToScreenMasked(src_bitmap, x, y, width, height, x, y); else BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y); } static void DrawMaskedBorderExt_FIELD(int draw_target) { if (global.border_status >= GAME_MODE_MAIN && global.border_status <= GAME_MODE_PLAYING && border.draw_masked[global.border_status]) DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, draw_target); } static void DrawMaskedBorderExt_DOOR_1(int draw_target) { // when drawing to backbuffer, never draw border over open doors if (draw_target == DRAW_TO_BACKBUFFER && (GetDoorState() & DOOR_OPEN_1)) return; if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] && (global.border_status != GAME_MODE_EDITOR || border.draw_masked[GFX_SPECIAL_ARG_EDITOR])) DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target); } static void DrawMaskedBorderExt_DOOR_2(int draw_target) { // when drawing to backbuffer, never draw border over open doors if (draw_target == DRAW_TO_BACKBUFFER && (GetDoorState() & DOOR_OPEN_2)) return; if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] && global.border_status != GAME_MODE_EDITOR) DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target); } static void DrawMaskedBorderExt_DOOR_3(int draw_target) { /* currently not available */ } static void DrawMaskedBorderExt_ALL(int draw_target) { DrawMaskedBorderExt_FIELD(draw_target); DrawMaskedBorderExt_DOOR_1(draw_target); DrawMaskedBorderExt_DOOR_2(draw_target); DrawMaskedBorderExt_DOOR_3(draw_target); } static void DrawMaskedBorderExt(int redraw_mask, int draw_target) { /* never draw masked screen borders on borderless screens */ if (global.border_status == GAME_MODE_LOADING || global.border_status == GAME_MODE_TITLE) return; if (redraw_mask & REDRAW_ALL) DrawMaskedBorderExt_ALL(draw_target); else { if (redraw_mask & REDRAW_FIELD) DrawMaskedBorderExt_FIELD(draw_target); if (redraw_mask & REDRAW_DOOR_1) DrawMaskedBorderExt_DOOR_1(draw_target); if (redraw_mask & REDRAW_DOOR_2) DrawMaskedBorderExt_DOOR_2(draw_target); if (redraw_mask & REDRAW_DOOR_3) DrawMaskedBorderExt_DOOR_3(draw_target); } } void DrawMaskedBorder_FIELD() { DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER); } void DrawMaskedBorder(int redraw_mask) { DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER); } void DrawMaskedBorderToTarget(int draw_target) { if (draw_target == DRAW_TO_BACKBUFFER || draw_target == DRAW_TO_SCREEN) { DrawMaskedBorderExt(REDRAW_ALL, draw_target); } else { int last_border_status = global.border_status; if (draw_target == DRAW_TO_FADE_SOURCE) { global.border_status = gfx.fade_border_source_status; gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source; } else if (draw_target == DRAW_TO_FADE_TARGET) { global.border_status = gfx.fade_border_target_status; gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target; } DrawMaskedBorderExt(REDRAW_ALL, draw_target); global.border_status = last_border_status; gfx.masked_border_bitmap_ptr = backbuffer; } } void DrawTileCursor(int draw_target) { Bitmap *fade_bitmap; Bitmap *src_bitmap; int src_x, src_y; int dst_x, dst_y; int graphic = IMG_GLOBAL_TILE_CURSOR; int frame = 0; int tilesize = TILESIZE_VAR; int width = tilesize; int height = tilesize; if (game_status != GAME_MODE_PLAYING) return; if (!tile_cursor.enabled || !tile_cursor.active) return; if (tile_cursor.moving) { int step = TILESIZE_VAR / 4; int dx = tile_cursor.target_x - tile_cursor.x; int dy = tile_cursor.target_y - tile_cursor.y; if (ABS(dx) < step) tile_cursor.x = tile_cursor.target_x; else tile_cursor.x += SIGN(dx) * step; if (ABS(dy) < step) tile_cursor.y = tile_cursor.target_y; else tile_cursor.y += SIGN(dy) * step; if (tile_cursor.x == tile_cursor.target_x && tile_cursor.y == tile_cursor.target_y) tile_cursor.moving = FALSE; } dst_x = tile_cursor.x; dst_y = tile_cursor.y; frame = getGraphicAnimationFrame(graphic, -1); getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y); fade_bitmap = (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source : draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL); if (draw_target == DRAW_TO_SCREEN) BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height, dst_x, dst_y); } void BlitScreenToBitmap_RND(Bitmap *target_bitmap) { int fx = getFieldbufferOffsetX_RND(); int fy = getFieldbufferOffsetY_RND(); BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY); } void BlitScreenToBitmap(Bitmap *target_bitmap) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) BlitScreenToBitmap_EM(target_bitmap); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) BlitScreenToBitmap_SP(target_bitmap); else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) BlitScreenToBitmap_MM(target_bitmap); else if (level.game_engine_type == GAME_ENGINE_TYPE_RND) BlitScreenToBitmap_RND(target_bitmap); redraw_mask |= REDRAW_FIELD; } void DrawFramesPerSecond() { char text[100]; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); int draw_deactivation_mask = GetDrawDeactivationMask(); boolean draw_masked = (draw_deactivation_mask == REDRAW_NONE); /* draw FPS with leading space (needed if field buffer deactivated) */ sprintf(text, " %04.1f fps", global.frames_per_second); /* override draw deactivation mask (required for invisible warp mode) */ SetDrawDeactivationMask(REDRAW_NONE); /* draw opaque FPS if field buffer deactivated, else draw masked FPS */ DrawTextExt(backbuffer, SX + SXSIZE - font_width * strlen(text), SY, text, font_nr, (draw_masked ? BLIT_MASKED : BLIT_OPAQUE)); /* set draw deactivation mask to previous value */ SetDrawDeactivationMask(draw_deactivation_mask); /* force full-screen redraw in this frame */ redraw_mask = REDRAW_ALL; } #if DEBUG_FRAME_TIME static void PrintFrameTimeDebugging() { static unsigned int last_counter = 0; unsigned int counter = Counter(); int diff_1 = counter - last_counter; int diff_2 = diff_1 - GAME_FRAME_DELAY; int diff_2_max = 20; int diff_2_cut = MIN(ABS(diff_2), diff_2_max); char diff_bar[2 * diff_2_max + 5]; int pos = 0; int i; diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' '); for (i = 0; i < diff_2_max; i++) diff_bar[pos++] = (diff_2 >= 0 ? ' ' : i >= diff_2_max - diff_2_cut ? '-' : ' '); diff_bar[pos++] = '|'; for (i = 0; i < diff_2_max; i++) diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' '); diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' '); diff_bar[pos++] = '\0'; Error(ERR_INFO, "%06d [%02d] [%c%02d] %s", counter, diff_1, (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2), diff_bar); last_counter = counter; } #endif static int unifiedRedrawMask(int mask) { if (mask & REDRAW_ALL) return REDRAW_ALL; if (mask & REDRAW_FIELD && mask & REDRAW_DOORS) return REDRAW_ALL; return mask; } static boolean equalRedrawMasks(int mask_1, int mask_2) { return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2); } void BackToFront() { static int last_redraw_mask = REDRAW_NONE; // force screen redraw in every frame to continue drawing global animations // (but always use the last redraw mask to prevent unwanted side effects) if (redraw_mask == REDRAW_NONE) redraw_mask = last_redraw_mask; last_redraw_mask = redraw_mask; #if 1 // masked border now drawn immediately when blitting backbuffer to window #else // draw masked border to all viewports, if defined DrawMaskedBorder(redraw_mask); #endif // draw frames per second (only if debug mode is enabled) if (redraw_mask & REDRAW_FPS) DrawFramesPerSecond(); // remove playfield redraw before potentially merging with doors redraw if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE)) redraw_mask &= ~REDRAW_FIELD; // redraw complete window if both playfield and (some) doors need redraw if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS) redraw_mask = REDRAW_ALL; /* although redrawing the whole window would be fine for normal gameplay, being able to only redraw the playfield is required for deactivating certain drawing areas (mainly playfield) to work, which is needed for warp-forward to be fast enough (by skipping redraw of most frames) */ if (redraw_mask & REDRAW_ALL) { BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); } else if (redraw_mask & REDRAW_FIELD) { BlitBitmap(backbuffer, window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); } else if (redraw_mask & REDRAW_DOORS) { // merge door areas to prevent calling screen redraw more than once int x1 = WIN_XSIZE; int y1 = WIN_YSIZE; int x2 = 0; int y2 = 0; if (redraw_mask & REDRAW_DOOR_1) { x1 = MIN(x1, DX); y1 = MIN(y1, DY); x2 = MAX(x2, DX + DXSIZE); y2 = MAX(y2, DY + DYSIZE); } if (redraw_mask & REDRAW_DOOR_2) { x1 = MIN(x1, VX); y1 = MIN(y1, VY); x2 = MAX(x2, VX + VXSIZE); y2 = MAX(y2, VY + VYSIZE); } if (redraw_mask & REDRAW_DOOR_3) { x1 = MIN(x1, EX); y1 = MIN(y1, EY); x2 = MAX(x2, EX + EXSIZE); y2 = MAX(y2, EY + EYSIZE); } // make sure that at least one pixel is blitted, and inside the screen // (else nothing is blitted, causing the animations not to be updated) x1 = MIN(MAX(0, x1), WIN_XSIZE - 1); y1 = MIN(MAX(0, y1), WIN_YSIZE - 1); x2 = MIN(MAX(1, x2), WIN_XSIZE); y2 = MIN(MAX(1, y2), WIN_YSIZE); BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1); } redraw_mask = REDRAW_NONE; #if DEBUG_FRAME_TIME PrintFrameTimeDebugging(); #endif } void BackToFront_WithFrameDelay(unsigned int frame_delay_value) { unsigned int frame_delay_value_old = GetVideoFrameDelay(); SetVideoFrameDelay(frame_delay_value); BackToFront(); SetVideoFrameDelay(frame_delay_value_old); } static int fade_type_skip = FADE_TYPE_NONE; static void FadeExt(int fade_mask, int fade_mode, int fade_type) { void (*draw_border_function)(void) = NULL; int x, y, width, height; int fade_delay, post_delay; if (fade_type == FADE_TYPE_FADE_OUT) { if (fade_type_skip != FADE_TYPE_NONE) { /* skip all fade operations until specified fade operation */ if (fade_type & fade_type_skip) fade_type_skip = FADE_TYPE_NONE; return; } if (fading.fade_mode & FADE_TYPE_TRANSFORM) return; } redraw_mask |= fade_mask; if (fade_type == FADE_TYPE_SKIP) { fade_type_skip = fade_mode; return; } fade_delay = fading.fade_delay; post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0); if (fade_type_skip != FADE_TYPE_NONE) { /* skip all fade operations until specified fade operation */ if (fade_type & fade_type_skip) fade_type_skip = FADE_TYPE_NONE; fade_delay = 0; } if (global.autoplay_leveldir) { return; } if (fade_mask == REDRAW_FIELD) { x = FADE_SX; y = FADE_SY; width = FADE_SXSIZE; height = FADE_SYSIZE; if (border.draw_masked_when_fading) draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */ else DrawMaskedBorder_FIELD(); /* draw once */ } else /* REDRAW_ALL */ { x = 0; y = 0; width = WIN_XSIZE; height = WIN_YSIZE; } if (!setup.fade_screens || fade_delay == 0 || fading.fade_mode == FADE_MODE_NONE) { if (fade_mode == FADE_MODE_FADE_OUT) return; BlitBitmap(backbuffer, window, x, y, width, height, x, y); redraw_mask &= ~fade_mask; return; } FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); redraw_mask &= ~fade_mask; } static void SetScreenStates_BeforeFadingIn() { // temporarily set screen mode for animations to screen after fading in global.anim_status = global.anim_status_next; // store backbuffer with all animations that will be started after fading in if (fade_type_skip != FADE_MODE_SKIP_FADE_IN) PrepareFadeBitmap(DRAW_TO_FADE_TARGET); // set screen mode for animations back to fading global.anim_status = GAME_MODE_PSEUDO_FADING; } static void SetScreenStates_AfterFadingIn() { // store new source screen (to use correct masked border for fading) gfx.fade_border_source_status = global.border_status; global.anim_status = global.anim_status_next; } static void SetScreenStates_BeforeFadingOut() { // store new target screen (to use correct masked border for fading) gfx.fade_border_target_status = game_status; // set screen mode for animations to fading global.anim_status = GAME_MODE_PSEUDO_FADING; // store backbuffer with all animations that will be stopped for fading out if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT) PrepareFadeBitmap(DRAW_TO_FADE_SOURCE); } static void SetScreenStates_AfterFadingOut() { global.border_status = game_status; } void FadeIn(int fade_mask) { SetScreenStates_BeforeFadingIn(); #if 1 DrawMaskedBorder(REDRAW_ALL); #endif if (fading.fade_mode & FADE_TYPE_TRANSFORM) FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN); else FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN); FADE_SX = REAL_SX; FADE_SY = REAL_SY; FADE_SXSIZE = FULL_SXSIZE; FADE_SYSIZE = FULL_SYSIZE; if (game_status == GAME_MODE_PLAYING && strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS)) SetOverlayActive(TRUE); SetScreenStates_AfterFadingIn(); // force update of global animation status in case of rapid screen changes redraw_mask = REDRAW_ALL; BackToFront(); } void FadeOut(int fade_mask) { // update screen if areas covered by "fade_mask" and "redraw_mask" differ if (!equalRedrawMasks(fade_mask, redraw_mask)) BackToFront(); SetScreenStates_BeforeFadingOut(); SetTileCursorActive(FALSE); SetOverlayActive(FALSE); #if 0 DrawMaskedBorder(REDRAW_ALL); #endif if (fading.fade_mode & FADE_TYPE_TRANSFORM) FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT); else FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT); SetScreenStates_AfterFadingOut(); } static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set) { static struct TitleFadingInfo fading_leave_stored; if (set) fading_leave_stored = fading_leave; else fading = fading_leave_stored; } void FadeSetEnterMenu() { fading = menu.enter_menu; FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */ } void FadeSetLeaveMenu() { fading = menu.leave_menu; FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */ } void FadeSetEnterScreen() { fading = menu.enter_screen[game_status]; FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */ } void FadeSetNextScreen() { fading = menu.next_screen[game_status]; // (do not overwrite fade mode set by FadeSetEnterScreen) // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */ } void FadeSetLeaveScreen() { FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */ } void FadeSetFromType(int type) { if (type & TYPE_ENTER_SCREEN) FadeSetEnterScreen(); else if (type & TYPE_ENTER) FadeSetEnterMenu(); else if (type & TYPE_LEAVE) FadeSetLeaveMenu(); } void FadeSetDisabled() { static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 }; fading = fading_none; } void FadeSkipNextFadeIn() { FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP); } void FadeSkipNextFadeOut() { FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP); } Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic) { boolean redefined = getImageListEntryFromImageID(graphic)->redefined; return (graphic == IMG_UNDEFINED ? NULL : graphic_info[graphic].bitmap != NULL || redefined ? graphic_info[graphic].bitmap : graphic_info[default_graphic].bitmap); } Bitmap *getBackgroundBitmap(int graphic) { return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND); } Bitmap *getGlobalBorderBitmap(int graphic) { return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER); } Bitmap *getGlobalBorderBitmapFromStatus(int status) { int graphic = (status == GAME_MODE_MAIN || status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN : status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES : status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR : status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING : IMG_GLOBAL_BORDER); return getGlobalBorderBitmap(graphic); } void SetWindowBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) SetWindowBackgroundBitmap(graphic_info[graphic].bitmap); } void SetMainBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) SetMainBackgroundBitmap(graphic_info[graphic].bitmap); } void SetDoorBackgroundImageIfDefined(int graphic) { if (graphic_info[graphic].bitmap) SetDoorBackgroundBitmap(graphic_info[graphic].bitmap); } void SetWindowBackgroundImage(int graphic) { SetWindowBackgroundBitmap(getBackgroundBitmap(graphic)); } void SetMainBackgroundImage(int graphic) { SetMainBackgroundBitmap(getBackgroundBitmap(graphic)); } void SetDoorBackgroundImage(int graphic) { SetDoorBackgroundBitmap(getBackgroundBitmap(graphic)); } void SetPanelBackground() { struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL]; BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y, gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE); SetDoorBackgroundBitmap(bitmap_db_panel); } void DrawBackground(int x, int y, int width, int height) { /* "drawto" might still point to playfield buffer here (hall of fame) */ ClearRectangleOnBackground(backbuffer, x, y, width, height); if (IN_GFX_FIELD_FULL(x, y)) redraw_mask |= REDRAW_FIELD; else if (IN_GFX_DOOR_1(x, y)) redraw_mask |= REDRAW_DOOR_1; else if (IN_GFX_DOOR_2(x, y)) redraw_mask |= REDRAW_DOOR_2; else if (IN_GFX_DOOR_3(x, y)) redraw_mask |= REDRAW_DOOR_3; } void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr) { struct FontBitmapInfo *font = getFontBitmapInfo(font_nr); if (font->bitmap == NULL) return; DrawBackground(x, y, width, height); } void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic) { struct GraphicInfo *g = &graphic_info[graphic]; if (g->bitmap == NULL) return; DrawBackground(x, y, width, height); } static int game_status_last = -1; static Bitmap *global_border_bitmap_last = NULL; static Bitmap *global_border_bitmap = NULL; static int real_sx_last = -1, real_sy_last = -1; static int full_sxsize_last = -1, full_sysize_last = -1; static int dx_last = -1, dy_last = -1; static int dxsize_last = -1, dysize_last = -1; static int vx_last = -1, vy_last = -1; static int vxsize_last = -1, vysize_last = -1; static int ex_last = -1, ey_last = -1; static int exsize_last = -1, eysize_last = -1; boolean CheckIfGlobalBorderHasChanged() { // if game status has not changed, global border has not changed either if (game_status == game_status_last) return FALSE; // determine and store new global border bitmap for current game status global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status); return (global_border_bitmap_last != global_border_bitmap); } boolean CheckIfGlobalBorderRedrawIsNeeded() { // if game status has not changed, nothing has to be redrawn if (game_status == game_status_last) return FALSE; // redraw if last screen was title screen if (game_status_last == GAME_MODE_TITLE) return TRUE; // redraw if global screen border has changed if (CheckIfGlobalBorderHasChanged()) return TRUE; // redraw if position or size of playfield area has changed if (real_sx_last != REAL_SX || real_sy_last != REAL_SY || full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE) return TRUE; // redraw if position or size of door area has changed if (dx_last != DX || dy_last != DY || dxsize_last != DXSIZE || dysize_last != DYSIZE) return TRUE; // redraw if position or size of tape area has changed if (vx_last != VX || vy_last != VY || vxsize_last != VXSIZE || vysize_last != VYSIZE) return TRUE; // redraw if position or size of editor area has changed if (ex_last != EX || ey_last != EY || exsize_last != EXSIZE || eysize_last != EYSIZE) return TRUE; return FALSE; } void RedrawGlobalBorderFromBitmap(Bitmap *bitmap) { if (bitmap) BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); else ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE); } void RedrawGlobalBorder() { Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status); RedrawGlobalBorderFromBitmap(bitmap); redraw_mask = REDRAW_ALL; } #define ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED 0 static void RedrawGlobalBorderIfNeeded() { #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED if (game_status == game_status_last) return; #endif // copy current draw buffer to later copy back areas that have not changed if (game_status_last != GAME_MODE_TITLE) BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED if (CheckIfGlobalBorderRedrawIsNeeded()) #endif { // redraw global screen border (or clear, if defined to be empty) RedrawGlobalBorderFromBitmap(global_border_bitmap); if (game_status == GAME_MODE_EDITOR) DrawSpecialEditorDoor(); // copy previous playfield and door areas, if they are defined on both // previous and current screen and if they still have the same size if (real_sx_last != -1 && real_sy_last != -1 && REAL_SX != -1 && REAL_SY != -1 && full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE) BlitBitmap(bitmap_db_store_1, backbuffer, real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); if (dx_last != -1 && dy_last != -1 && DX != -1 && DY != -1 && dxsize_last == DXSIZE && dysize_last == DYSIZE) BlitBitmap(bitmap_db_store_1, backbuffer, dx_last, dy_last, DXSIZE, DYSIZE, DX, DY); if (game_status != GAME_MODE_EDITOR) { if (vx_last != -1 && vy_last != -1 && VX != -1 && VY != -1 && vxsize_last == VXSIZE && vysize_last == VYSIZE) BlitBitmap(bitmap_db_store_1, backbuffer, vx_last, vy_last, VXSIZE, VYSIZE, VX, VY); } else { if (ex_last != -1 && ey_last != -1 && EX != -1 && EY != -1 && exsize_last == EXSIZE && eysize_last == EYSIZE) BlitBitmap(bitmap_db_store_1, backbuffer, ex_last, ey_last, EXSIZE, EYSIZE, EX, EY); } redraw_mask = REDRAW_ALL; } game_status_last = game_status; global_border_bitmap_last = global_border_bitmap; real_sx_last = REAL_SX; real_sy_last = REAL_SY; full_sxsize_last = FULL_SXSIZE; full_sysize_last = FULL_SYSIZE; dx_last = DX; dy_last = DY; dxsize_last = DXSIZE; dysize_last = DYSIZE; vx_last = VX; vy_last = VY; vxsize_last = VXSIZE; vysize_last = VYSIZE; ex_last = EX; ey_last = EY; exsize_last = EXSIZE; eysize_last = EYSIZE; } void ClearField() { RedrawGlobalBorderIfNeeded(); /* !!! "drawto" might still point to playfield buffer here (see above) !!! */ /* (when entering hall of fame after playing) */ DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); /* !!! maybe this should be done before clearing the background !!! */ if (game_status == GAME_MODE_PLAYING) { ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE); SetDrawtoField(DRAW_TO_FIELDBUFFER); } else { SetDrawtoField(DRAW_TO_BACKBUFFER); } } void MarkTileDirty(int x, int y) { redraw_mask |= REDRAW_FIELD; } void SetBorderElement() { int x, y; BorderElement = EL_EMPTY; /* the MM game engine does not use a visible border element */ if (level.game_engine_type == GAME_ENGINE_TYPE_MM) return; for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++) { for (x = 0; x < lev_fieldx; x++) { if (!IS_INDESTRUCTIBLE(Feld[x][y])) BorderElement = EL_STEELWALL; if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1) x = lev_fieldx - 2; } } } void FloodFillLevelExt(int from_x, int from_y, int fill_element, int max_array_fieldx, int max_array_fieldy, short field[max_array_fieldx][max_array_fieldy], int max_fieldx, int max_fieldy) { int i,x,y; int old_element; 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 (field[from_x][from_y] == fill_element) return; safety++; if (safety > max_fieldx * max_fieldy) Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug."); old_element = field[from_x][from_y]; field[from_x][from_y] = fill_element; for (i = 0; i < 4; i++) { x = from_x + check[i][0]; y = from_y + check[i][1]; if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element) FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy, field, max_fieldx, max_fieldy); } safety--; } void FloodFillLevel(int from_x, int from_y, int fill_element, short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY], int max_fieldx, int max_fieldy) { FloodFillLevelExt(from_x, from_y, fill_element, MAX_LEV_FIELDX, MAX_LEV_FIELDY, field, max_fieldx, max_fieldy); } void SetRandomAnimationValue(int x, int y) { gfx.anim_random_frame = GfxRandom[x][y]; } int getGraphicAnimationFrame(int graphic, int sync_frame) { /* animation synchronized with global frame counter, not move position */ if (graphic_info[graphic].anim_global_sync || sync_frame < 0) sync_frame = FrameCounter; return getAnimationFrame(graphic_info[graphic].anim_frames, graphic_info[graphic].anim_delay, graphic_info[graphic].anim_mode, graphic_info[graphic].anim_start_frame, sync_frame); } void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap) { struct GraphicInfo *g = &graphic_info[graphic]; int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE); if (tilesize == gfx.standard_tile_size) *bitmap = g->bitmaps[IMG_BITMAP_STANDARD]; else if (tilesize == game.tile_size) *bitmap = g->bitmaps[IMG_BITMAP_GAME]; else *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)]; } void getGraphicSourceXY(int graphic, int frame, int *x, int *y, boolean get_backside) { struct GraphicInfo *g = &graphic_info[graphic]; int src_x = g->src_x + (get_backside ? g->offset2_x : 0); int src_y = g->src_y + (get_backside ? g->offset2_y : 0); if (g->offset_y == 0) /* frames are ordered horizontally */ { int max_width = g->anim_frames_per_line * g->width; int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x; *x = pos % max_width; *y = src_y % g->height + pos / max_width * g->height; } else if (g->offset_x == 0) /* frames are ordered vertically */ { int max_height = g->anim_frames_per_line * g->height; int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y; *x = src_x % g->width + pos / max_height * g->width; *y = pos % max_height; } else /* frames are ordered diagonally */ { *x = src_x + frame * g->offset_x; *y = src_y + frame * g->offset_y; } } void getSizedGraphicSourceExt(int graphic, int frame, int tilesize, Bitmap **bitmap, int *x, int *y, boolean get_backside) { struct GraphicInfo *g = &graphic_info[graphic]; // if no in-game graphics defined, always use standard graphic size if (g->bitmaps[IMG_BITMAP_GAME] == NULL) tilesize = TILESIZE; getGraphicSourceBitmap(graphic, tilesize, bitmap); getGraphicSourceXY(graphic, frame, x, y, get_backside); *x = *x * tilesize / g->tile_size; *y = *y * tilesize / g->tile_size; } void getSizedGraphicSource(int graphic, int frame, int tilesize, Bitmap **bitmap, int *x, int *y) { getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE); } void getFixedGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y) { getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE); } void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) { getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y); } inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap, int *x, int *y, boolean get_backside) { getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y, get_backside); } void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y) { getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE); } void DrawGraphic(int x, int y, int graphic, int frame) { #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, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic, frame); MarkTileDirty(x, y); } void DrawFixedGraphic(int x, int y, int graphic, int frame) { #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 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame); MarkTileDirty(x, y); } void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic, int frame) { Bitmap *src_bitmap; int src_x, src_y; getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y); } void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic, int frame) { Bitmap *src_bitmap; int src_x, src_y; getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y); } void DrawGraphicThruMask(int x, int y, int graphic, int frame) { #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_VAR, FY + y * TILEY_VAR, graphic, frame); MarkTileDirty(x, y); } void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame) { #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 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame); MarkTileDirty(x, y); } void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic, int frame) { Bitmap *src_bitmap; int src_x, src_y; getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR, dst_x, dst_y); } void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic, int frame) { Bitmap *src_bitmap; int src_x, src_y; getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y); } void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize) { DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic, frame, tilesize); MarkTileDirty(x / tilesize, y / tilesize); } void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame, int tilesize) { DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic, frame, tilesize); MarkTileDirty(x / tilesize, y / tilesize); } void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame, int tilesize) { Bitmap *src_bitmap; int src_x, src_y; getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y); } void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic, int frame, int tilesize) { Bitmap *src_bitmap; int src_x, src_y; getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y); } void DrawMiniGraphic(int x, int y, int graphic) { DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic); MarkTileDirty(x / 2, y / 2); } void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic) { Bitmap *src_bitmap; int src_x, src_y; getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y); } inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode, int mask_mode) { Bitmap *src_bitmap; int src_x, src_y; int dst_x, dst_y; int width = TILEX, height = TILEY; int cx = 0, cy = 0; if (dx || dy) /* shifted graphic */ { if (x < BX1) /* object enters playfield from the left */ { x = BX1; width = dx; cx = TILEX - dx; dx = 0; } else if (x > BX2) /* object enters playfield from the right */ { x = BX2; width = -dx; dx = TILEX + dx; } else if (x == BX1 && dx < 0) /* object leaves playfield to the left */ { width += dx; cx = -dx; dx = 0; } else if (x == BX2 && dx > 0) /* object leaves playfield to the right */ width -= dx; else if (dx) /* general horizontal movement */ MarkTileDirty(x + SIGN(dx), y); if (y < BY1) /* object enters playfield from the top */ { if (cut_mode == CUT_BELOW) /* object completely above top border */ return; y = BY1; height = dy; cy = TILEY - dy; dy = 0; } else if (y > BY2) /* object enters playfield from the bottom */ { y = BY2; height = -dy; dy = TILEY + dy; } else if (y == BY1 && dy < 0) /* object leaves playfield to the top */ { height += dy; cy = -dy; dy = 0; } else if (dy > 0 && cut_mode == CUT_ABOVE) { if (y == BY2) /* object completely above bottom border */ return; height = dy; cy = TILEY - dy; dy = TILEY; MarkTileDirty(x, y + 1); } /* object leaves playfield to the bottom */ else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW)) height -= dy; else if (dy) /* general vertical movement */ MarkTileDirty(x, y + SIGN(dy)); } #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 width = width * TILESIZE_VAR / TILESIZE; height = height * TILESIZE_VAR / TILESIZE; cx = cx * TILESIZE_VAR / TILESIZE; cy = cy * TILESIZE_VAR / TILESIZE; dx = dx * TILESIZE_VAR / TILESIZE; dy = dy * TILESIZE_VAR / TILESIZE; if (width > 0 && height > 0) { getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); src_x += cx; src_y += cy; dst_x = FX + x * TILEX_VAR + dx; dst_y = FY + y * TILEY_VAR + dy; if (mask_mode == USE_MASKING) BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); MarkTileDirty(x, y); } } inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode, int mask_mode) { Bitmap *src_bitmap; int src_x, src_y; int dst_x, dst_y; int width = TILEX_VAR, height = TILEY_VAR; int x1 = x; int y1 = y; int x2 = x + SIGN(dx); int y2 = y + SIGN(dy); /* movement with two-tile animations must be sync'ed with movement position, not with current GfxFrame (which can be higher when using slow movement) */ int anim_pos = (dx ? ABS(dx) : ABS(dy)); int anim_frames = graphic_info[graphic].anim_frames; /* (we also need anim_delay here for movement animations with less frames) */ int anim_delay = graphic_info[graphic].anim_delay; int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE; boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */ boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */ /* re-calculate animation frame for two-tile movement animation */ frame = getGraphicAnimationFrame(graphic, sync_frame); /* check if movement start graphic inside screen area and should be drawn */ if (draw_start_tile && IN_SCR_FIELD(x1, y1)) { getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE); dst_x = FX + x1 * TILEX_VAR; dst_y = FY + y1 * TILEY_VAR; if (mask_mode == USE_MASKING) BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); MarkTileDirty(x1, y1); } /* check if movement end graphic inside screen area and should be drawn */ if (draw_end_tile && IN_SCR_FIELD(x2, y2)) { getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE); dst_x = FX + x2 * TILEX_VAR; dst_y = FY + y2 * TILEY_VAR; if (mask_mode == USE_MASKING) BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dst_x, dst_y); MarkTileDirty(x2, y2); } } static void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode, int mask_mode) { if (graphic < 0) { DrawGraphic(x, y, graphic, frame); return; } if (graphic_info[graphic].double_movement) /* EM style movement images */ DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode); else DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode); } void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic, int frame, int cut_mode) { DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING); } void DrawScreenElementExt(int x, int y, int dx, int dy, int element, int cut_mode, int mask_mode) { int lx = LEVELX(x), ly = LEVELY(y); int graphic; int frame; if (IN_LEV_FIELD(lx, ly)) { SetRandomAnimationValue(lx, ly); graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]); frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]); /* do not use double (EM style) movement graphic when not moving */ if (graphic_info[graphic].double_movement && !dx && !dy) { graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]); frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]); } } else /* border element */ { graphic = el2img(element); frame = getGraphicAnimationFrame(graphic, -1); } if (element == EL_EXPANDABLE_WALL) { boolean left_stopped = FALSE, right_stopped = FALSE; if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly])) left_stopped = TRUE; if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly])) right_stopped = TRUE; if (left_stopped && right_stopped) graphic = IMG_WALL; else if (left_stopped) { graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT; frame = graphic_info[graphic].anim_frames - 1; } else if (right_stopped) { graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT; frame = graphic_info[graphic].anim_frames - 1; } } if (dx || dy) DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode); else if (mask_mode == USE_MASKING) DrawGraphicThruMask(x, y, graphic, frame); else DrawGraphic(x, y, graphic, frame); } 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 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); } /* !!! implementation of quicksand is totally broken !!! */ #define IS_CRUMBLED_TILE(x, y, e) \ (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \ !IS_MOVING(x, y) || \ (e) == EL_QUICKSAND_EMPTYING || \ (e) == EL_QUICKSAND_FAST_EMPTYING)) static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy, int graphic) { Bitmap *src_bitmap; int src_x, src_y; int width, height, cx, cy; int sx = SCREENX(x), sy = SCREENY(y); int crumbled_border_size = graphic_info[graphic].border_size; int crumbled_tile_size = graphic_info[graphic].tile_size; int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / crumbled_tile_size; int i; getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); for (i = 1; i < 4; i++) { int dxx = (i & 1 ? dx : 0); int dyy = (i & 2 ? dy : 0); int xx = x + dxx; int yy = y + dyy; int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ boolean same = (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class); /* return if check prevents inner corner */ if (same == (dxx == dx && dyy == dy)) return; } /* if we reach this point, we have an inner corner */ getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y); width = crumbled_border_size_var; height = crumbled_border_size_var; cx = (dx > 0 ? TILESIZE_VAR - width : 0); cy = (dy > 0 ? TILESIZE_VAR - height : 0); BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy); } static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame, int dir) { Bitmap *src_bitmap; int src_x, src_y; int width, height, bx, by, cx, cy; int sx = SCREENX(x), sy = SCREENY(y); int crumbled_border_size = graphic_info[graphic].border_size; int crumbled_tile_size = graphic_info[graphic].tile_size; int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / crumbled_tile_size; int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var; int i; getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); /* draw simple, sloppy, non-corner-accurate crumbled border */ width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR); height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR); cx = (dir == 2 ? crumbled_border_pos_var : 0); cy = (dir == 3 ? crumbled_border_pos_var : 0); BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy); /* (remaining middle border part must be at least as big as corner part) */ if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) || crumbled_border_size_var >= TILESIZE_VAR / 3) return; /* correct corners of crumbled border, if needed */ for (i = -1; i <= 1; i += 2) { int xx = x + (dir == 0 || dir == 3 ? i : 0); int yy = y + (dir == 1 || dir == 2 ? i : 0); int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ if (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class) { /* no crumbled corner, but continued crumbled border */ int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0); int c2 = (i == 1 ? crumbled_border_pos_var : 0); int b1 = (i == 1 ? crumbled_border_size_var : TILESIZE_VAR - 2 * crumbled_border_size_var); width = crumbled_border_size_var; height = crumbled_border_size_var; if (dir == 1 || dir == 2) { cx = c1; cy = c2; bx = cx; by = b1; } else { cx = c2; cy = c1; bx = b1; by = cy; } BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by, width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy); } } } static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame) { int sx = SCREENX(x), sy = SCREENY(y); int element; int i; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (!IN_LEV_FIELD(x, y)) return; element = TILE_GFX_ELEMENT(x, y); if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */ { if (!IN_SCR_FIELD(sx, sy)) return; /* crumble field borders towards direct neighbour fields */ for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) : BorderElement); /* check if neighbour field is of same crumble type */ if (IS_CRUMBLED_TILE(xx, yy, element) && graphic_info[graphic].class == graphic_info[el_act2crm(element, ACTION_DEFAULT)].class) continue; DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i); } /* crumble inner field corners towards corner neighbour fields */ if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && graphic_info[graphic].anim_frames == 2) { for (i = 0; i < 4; i++) { int dx = (i & 1 ? +1 : -1); int dy = (i & 2 ? +1 : -1); DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic); } } MarkTileDirty(sx, sy); } else /* center field is not crumbled -- crumble neighbour fields */ { /* crumble field borders of direct neighbour fields */ for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int sxx = sx + xy[i][0]; int syy = sy + xy[i][1]; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy)) continue; if (Feld[xx][yy] == EL_ELEMENT_SNAPPING) continue; element = TILE_GFX_ELEMENT(xx, yy); if (!IS_CRUMBLED_TILE(xx, yy, element)) continue; graphic = el_act2crm(element, ACTION_DEFAULT); DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i); MarkTileDirty(sxx, syy); } /* crumble inner field corners of corner neighbour fields */ for (i = 0; i < 4; i++) { int dx = (i & 1 ? +1 : -1); int dy = (i & 2 ? +1 : -1); int xx = x + dx; int yy = y + dy; int sxx = sx + dx; int syy = sy + dy; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy)) continue; if (Feld[xx][yy] == EL_ELEMENT_SNAPPING) continue; element = TILE_GFX_ELEMENT(xx, yy); if (!IS_CRUMBLED_TILE(xx, yy, element)) continue; graphic = el_act2crm(element, ACTION_DEFAULT); if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && graphic_info[graphic].anim_frames == 2) DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic); MarkTileDirty(sxx, syy); } } } void DrawLevelFieldCrumbled(int x, int y) { int graphic; if (!IN_LEV_FIELD(x, y)) return; if (Feld[x][y] == EL_ELEMENT_SNAPPING && GfxElement[x][y] != EL_UNDEFINED && GFX_CRUMBLED(GfxElement[x][y])) { DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]); return; } graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT); DrawLevelFieldCrumbledExt(x, y, graphic, 0); } void DrawLevelFieldCrumbledDigging(int x, int y, int direction, int step_frame) { int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction); int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction); int frame1 = getGraphicAnimationFrame(graphic1, step_frame); int frame2 = getGraphicAnimationFrame(graphic2, step_frame); int sx = SCREENX(x), sy = SCREENY(y); DrawGraphic(sx, sy, graphic1, frame1); DrawLevelFieldCrumbledExt(x, y, graphic2, frame2); } void DrawLevelFieldCrumbledNeighbours(int x, int y) { int sx = SCREENX(x), sy = SCREENY(y); static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; int i; /* crumble direct neighbour fields (required for field borders) */ for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int sxx = sx + xy[i][0]; int syy = sy + xy[i][1]; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy) || !GFX_CRUMBLED(Feld[xx][yy]) || IS_MOVING(xx, yy)) continue; DrawLevelField(xx, yy); } /* crumble corner neighbour fields (required for inner field corners) */ for (i = 0; i < 4; i++) { int dx = (i & 1 ? +1 : -1); int dy = (i & 2 ? +1 : -1); int xx = x + dx; int yy = y + dy; int sxx = sx + dx; int syy = sy + dy; if (!IN_LEV_FIELD(xx, yy) || !IN_SCR_FIELD(sxx, syy) || !GFX_CRUMBLED(Feld[xx][yy]) || IS_MOVING(xx, yy)) continue; int element = TILE_GFX_ELEMENT(xx, yy); int graphic = el_act2crm(element, ACTION_DEFAULT); if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) && graphic_info[graphic].anim_frames == 2) DrawLevelField(xx, yy); } } static int getBorderElement(int x, int y) { int border[7][2] = { { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT }, { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT }, { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT }, { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT }, { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL }, { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL }, { EL_STEELWALL, EL_INVISIBLE_STEELWALL } }; int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1); int steel_position = (x == -1 && y == -1 ? 0 : x == lev_fieldx && y == -1 ? 1 : x == -1 && y == lev_fieldy ? 2 : x == lev_fieldx && y == lev_fieldy ? 3 : x == -1 || x == lev_fieldx ? 4 : y == -1 || y == lev_fieldy ? 5 : 6); return border[steel_position][steel_type]; } void DrawScreenElement(int x, int y, int element) { DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING); DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y)); } void DrawLevelElement(int x, int y, int 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 lx = LEVELX(x), ly = LEVELY(y); int element, content; if (!IN_LEV_FIELD(lx, ly)) { if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy) element = EL_EMPTY; else element = getBorderElement(lx, ly); DrawScreenElement(x, y, element); return; } element = Feld[lx][ly]; content = Store[lx][ly]; if (IS_MOVING(lx, ly)) { int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT); boolean cut_mode = NO_CUTTING; if (element == EL_QUICKSAND_EMPTYING || element == EL_QUICKSAND_FAST_EMPTYING || element == EL_MAGIC_WALL_EMPTYING || element == EL_BD_MAGIC_WALL_EMPTYING || element == EL_DC_MAGIC_WALL_EMPTYING || element == EL_AMOEBA_DROPPING) cut_mode = CUT_ABOVE; else if (element == EL_QUICKSAND_FILLING || element == EL_QUICKSAND_FAST_FILLING || element == EL_MAGIC_WALL_FILLING || element == EL_BD_MAGIC_WALL_FILLING || element == EL_DC_MAGIC_WALL_FILLING) cut_mode = CUT_BELOW; if (cut_mode == CUT_ABOVE) DrawScreenElement(x, y, element); else DrawScreenElement(x, y, EL_EMPTY); if (horiz_move) DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING); else if (cut_mode == NO_CUTTING) DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode); else { DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode); if (cut_mode == CUT_BELOW && IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1)) DrawLevelElement(lx, ly + 1, element); } if (content == EL_ACID) { int dir = MovDir[lx][ly]; int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0); int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0); DrawLevelElementThruMask(newlx, newly, EL_ACID); // prevent target field from being drawn again (but without masking) // (this would happen if target field is scanned after moving element) Stop[newlx][newly] = TRUE; } } else if (IS_BLOCKED(lx, ly)) { int oldx, oldy; int sx, sy; int horiz_move; boolean cut_mode = NO_CUTTING; int element_old, content_old; Blocked2Moving(lx, ly, &oldx, &oldy); sx = SCREENX(oldx); sy = SCREENY(oldy); horiz_move = (MovDir[oldx][oldy] == MV_LEFT || MovDir[oldx][oldy] == MV_RIGHT); element_old = Feld[oldx][oldy]; content_old = Store[oldx][oldy]; if (element_old == EL_QUICKSAND_EMPTYING || element_old == EL_QUICKSAND_FAST_EMPTYING || element_old == EL_MAGIC_WALL_EMPTYING || element_old == EL_BD_MAGIC_WALL_EMPTYING || element_old == EL_DC_MAGIC_WALL_EMPTYING || element_old == EL_AMOEBA_DROPPING) cut_mode = CUT_ABOVE; DrawScreenElement(x, y, EL_EMPTY); if (horiz_move) DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old, NO_CUTTING); else if (cut_mode == NO_CUTTING) DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old, cut_mode); else DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old, cut_mode); } else if (IS_DRAWABLE(element)) DrawScreenElement(x, y, element); else DrawScreenElement(x, y, EL_EMPTY); } void DrawLevelField(int x, int 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(SCREENX(newx), SCREENY(newy))) DrawScreenField(SCREENX(newx), SCREENY(newy)); } else if (IS_BLOCKED(x, y)) { int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy))) DrawScreenField(SCREENX(oldx), SCREENY(oldy)); } } static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize, int (*el2img_function)(int), boolean masked, int element_bits_draw) { int element_base = map_mm_wall_element(element); int element_bits = (IS_DF_WALL(element) ? element - EL_DF_WALL_START : IS_MM_WALL(element) ? element - EL_MM_WALL_START : EL_EMPTY) & 0x000f; int graphic = el2img_function(element_base); int tilesize_draw = tilesize / 2; Bitmap *src_bitmap; int src_x, src_y; int i; getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y); for (i = 0; i < 4; i++) { int dst_draw_x = dst_x + (i % 2) * tilesize_draw; int dst_draw_y = dst_y + (i / 2) * tilesize_draw; if (!(element_bits_draw & (1 << i))) continue; if (element_bits & (1 << i)) { if (masked) BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y); else BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y); } else { if (!masked) ClearRectangle(drawto, dst_draw_x, dst_draw_y, tilesize_draw, tilesize_draw); } } } void DrawSizedWallParts_MM(int x, int y, int element, int tilesize, boolean masked, int element_bits_draw) { DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize, element, tilesize, el2edimg, masked, element_bits_draw); } void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize, int (*el2img_function)(int)) { DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE, 0x000f); } void DrawSizedElementExt(int x, int y, int element, int tilesize, boolean masked) { if (IS_MM_WALL(element)) { DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize, element, tilesize, el2edimg, masked, 0x000f); } else { int graphic = el2edimg(element); if (masked) DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize); else DrawSizedGraphic(x, y, graphic, 0, tilesize); } } void DrawSizedElement(int x, int y, int element, int tilesize) { DrawSizedElementExt(x, y, element, tilesize, FALSE); } void DrawSizedElementThruMask(int x, int y, int element, int tilesize) { DrawSizedElementExt(x, y, element, tilesize, TRUE); } void DrawMiniElement(int x, int y, int element) { int graphic; graphic = el2edimg(element); DrawMiniGraphic(x, y, graphic); } void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y, int tilesize) { int x = sx + scroll_x, y = sy + scroll_y; if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy) DrawSizedElement(sx, sy, EL_EMPTY, tilesize); else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy) DrawSizedElement(sx, sy, Feld[x][y], tilesize); else DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize); } void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y) { int x = sx + scroll_x, y = sy + scroll_y; if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy) DrawMiniElement(sx, sy, EL_EMPTY); else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy) DrawMiniElement(sx, sy, Feld[x][y]); else DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y))); } void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty, int x, int y, int xsize, int ysize, int tile_width, int tile_height) { Bitmap *src_bitmap; int src_x, src_y; int dst_x = startx + x * tile_width; int dst_y = starty + y * tile_height; int width = graphic_info[graphic].width; int height = graphic_info[graphic].height; int inner_width_raw = MAX(width - 2 * tile_width, tile_width); int inner_height_raw = MAX(height - 2 * tile_height, tile_height); int inner_width = inner_width_raw - (inner_width_raw % tile_width); int inner_height = inner_height_raw - (inner_height_raw % tile_height); int inner_sx = (width >= 3 * tile_width ? tile_width : 0); int inner_sy = (height >= 3 * tile_height ? tile_height : 0); boolean draw_masked = graphic_info[graphic].draw_masked; getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); if (src_bitmap == NULL || width < tile_width || height < tile_height) { ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height); return; } src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width : inner_sx + (x - 1) * tile_width % inner_width); src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height : inner_sy + (y - 1) * tile_height % inner_height); if (draw_masked) BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height, dst_x, dst_y); else BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height, dst_x, dst_y); } void DrawEnvelopeBackground(int graphic, int startx, int starty, int x, int y, int xsize, int ysize, int font_nr) { int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize, font_width, font_height); } void AnimateEnvelope(int envelope_nr, int anim_mode, int action) { int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; Bitmap *src_bitmap = graphic_info[graphic].bitmap; int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND); boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); unsigned int anim_delay = 0; int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2); int font_nr = FONT_ENVELOPE_1 + envelope_nr; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int max_xsize = level.envelope[envelope_nr].xsize; int max_ysize = level.envelope[envelope_nr].ysize; int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0); int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0); int xend = max_xsize; int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0); int xstep = (xstart < xend ? 1 : 0); int ystep = (ystart < yend || xstep == 0 ? 1 : 0); int start = 0; int end = MAX(xend - xstart, yend - ystart); int i; for (i = start; i <= end; i++) { int last_frame = end; // last frame of this "for" loop int x = xstart + i * xstep; int y = ystart + i * ystep; int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2; int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2; int sx = SX + (SXSIZE - xsize * font_width) / 2; int sy = SY + (SYSIZE - ysize * font_height) / 2; int xx, yy; SetDrawtoField(DRAW_TO_FIELDBUFFER); BlitScreenToBitmap(backbuffer); SetDrawtoField(DRAW_TO_BACKBUFFER); for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++) DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr); DrawTextBuffer(sx + font_width, sy + font_height, level.envelope[envelope_nr].text, font_nr, max_xsize, xsize - 2, ysize - 2, 0, mask_mode, level.envelope[envelope_nr].autowrap, level.envelope[envelope_nr].centered, FALSE); redraw_mask |= REDRAW_FIELD; BackToFront(); SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame); } } void ShowEnvelope(int envelope_nr) { int element = EL_ENVELOPE_1 + envelope_nr; int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr; int sound_opening = element_info[element].sound[ACTION_OPENING]; int sound_closing = element_info[element].sound[ACTION_CLOSING]; boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1); int wait_delay_value = (no_delay ? 0 : normal_delay_value); int anim_mode = graphic_info[graphic].anim_mode; int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL: anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode); game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */ PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE); if (anim_mode == ANIM_DEFAULT) AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING); AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING); if (tape.playing) Delay(wait_delay_value); else WaitForEventToContinue(); PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE); if (anim_mode != ANIM_NONE) AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING); if (anim_mode == ANIM_DEFAULT) AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING); game.envelope_active = FALSE; SetDrawtoField(DRAW_TO_FIELDBUFFER); redraw_mask |= REDRAW_FIELD; BackToFront(); } static void setRequestBasePosition(int *x, int *y) { int sx_base, sy_base; if (request.x != -1) sx_base = request.x; else if (request.align == ALIGN_LEFT) sx_base = SX; else if (request.align == ALIGN_RIGHT) sx_base = SX + SXSIZE; else sx_base = SX + SXSIZE / 2; if (request.y != -1) sy_base = request.y; else if (request.valign == VALIGN_TOP) sy_base = SY; else if (request.valign == VALIGN_BOTTOM) sy_base = SY + SYSIZE; else sy_base = SY + SYSIZE / 2; *x = sx_base; *y = sy_base; } static void setRequestPositionExt(int *x, int *y, int width, int height, boolean add_border_size) { int border_size = request.border_size; int sx_base, sy_base; int sx, sy; setRequestBasePosition(&sx_base, &sy_base); if (request.align == ALIGN_LEFT) sx = sx_base; else if (request.align == ALIGN_RIGHT) sx = sx_base - width; else sx = sx_base - width / 2; if (request.valign == VALIGN_TOP) sy = sy_base; else if (request.valign == VALIGN_BOTTOM) sy = sy_base - height; else sy = sy_base - height / 2; sx = MAX(0, MIN(sx, WIN_XSIZE - width)); sy = MAX(0, MIN(sy, WIN_YSIZE - height)); if (add_border_size) { sx += border_size; sy += border_size; } *x = sx; *y = sy; } static void setRequestPosition(int *x, int *y, boolean add_border_size) { setRequestPositionExt(x, y, request.width, request.height, add_border_size); } void DrawEnvelopeRequest(char *text) { char *text_final = text; char *text_door_style = NULL; int graphic = IMG_BACKGROUND_REQUEST; Bitmap *src_bitmap = graphic_info[graphic].bitmap; int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND); int font_nr = FONT_REQUEST; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_size = request.border_size; int line_spacing = request.line_spacing; int line_height = font_height + line_spacing; int max_text_width = request.width - 2 * border_size; int max_text_height = request.height - 2 * border_size; int line_length = max_text_width / font_width; int max_lines = max_text_height / line_height; int text_width = line_length * font_width; int width = request.width; int height = request.height; int tile_size = MAX(request.step_offset, 1); int x_steps = width / tile_size; int y_steps = height / tile_size; int sx_offset = border_size; int sy_offset = border_size; int sx, sy; int i, x, y; if (request.centered) sx_offset = (request.width - text_width) / 2; if (request.wrap_single_words && !request.autowrap) { char *src_text_ptr, *dst_text_ptr; text_door_style = checked_malloc(2 * strlen(text) + 1); src_text_ptr = text; dst_text_ptr = text_door_style; while (*src_text_ptr) { if (*src_text_ptr == ' ' || *src_text_ptr == '?' || *src_text_ptr == '!') *dst_text_ptr++ = '\n'; if (*src_text_ptr != ' ') *dst_text_ptr++ = *src_text_ptr; src_text_ptr++; } *dst_text_ptr = '\0'; text_final = text_door_style; } setRequestPosition(&sx, &sy, FALSE); ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE); for (y = 0; y < y_steps; y++) for (x = 0; x < x_steps; x++) DrawEnvelopeBackgroundTiles(graphic, sx, sy, x, y, x_steps, y_steps, tile_size, tile_size); /* force DOOR font inside door area */ SetFontStatus(GAME_MODE_PSEUDO_DOOR); DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr, line_length, -1, max_lines, line_spacing, mask_mode, request.autowrap, request.centered, FALSE); ResetFontStatus(); for (i = 0; i < NUM_TOOL_BUTTONS; i++) RedrawGadget(tool_gadget[i]); // store readily prepared envelope request for later use when animating BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); if (text_door_style) free(text_door_style); } void AnimateEnvelopeRequest(int anim_mode, int action) { int graphic = IMG_BACKGROUND_REQUEST; boolean draw_masked = graphic_info[graphic].draw_masked; int delay_value_normal = request.step_delay; int delay_value_fast = delay_value_normal / 2; boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal); int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2); unsigned int anim_delay = 0; int tile_size = MAX(request.step_offset, 1); int max_xsize = request.width / tile_size; int max_ysize = request.height / tile_size; int max_xsize_inner = max_xsize - 2; int max_ysize_inner = max_ysize - 2; int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0); int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0); int xend = max_xsize_inner; int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0); int xstep = (xstart < xend ? 1 : 0); int ystep = (ystart < yend || xstep == 0 ? 1 : 0); int start = 0; int end = MAX(xend - xstart, yend - ystart); int i; if (setup.quick_doors) { xstart = xend; ystart = yend; end = 0; } for (i = start; i <= end; i++) { int last_frame = end; // last frame of this "for" loop int x = xstart + i * xstep; int y = ystart + i * ystep; int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2; int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2; int xsize_size_left = (xsize - 1) * tile_size; int ysize_size_top = (ysize - 1) * tile_size; int max_xsize_pos = (max_xsize - 1) * tile_size; int max_ysize_pos = (max_ysize - 1) * tile_size; int width = xsize * tile_size; int height = ysize * tile_size; int src_x, src_y; int dst_x, dst_y; int xx, yy; setRequestPosition(&src_x, &src_y, FALSE); setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE); BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); for (yy = 0; yy < 2; yy++) { for (xx = 0; xx < 2; xx++) { int src_xx = src_x + xx * max_xsize_pos; int src_yy = src_y + yy * max_ysize_pos; int dst_xx = dst_x + xx * xsize_size_left; int dst_yy = dst_y + yy * ysize_size_top; int xx_size = (xx ? tile_size : xsize_size_left); int yy_size = (yy ? tile_size : ysize_size_top); if (draw_masked) BlitBitmapMasked(bitmap_db_store_2, backbuffer, src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy); else BlitBitmap(bitmap_db_store_2, backbuffer, src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy); } } redraw_mask |= REDRAW_FIELD; BackToFront(); SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame); } } void ShowEnvelopeRequest(char *text, unsigned int req_state, int action) { int graphic = IMG_BACKGROUND_REQUEST; int sound_opening = SND_REQUEST_OPENING; int sound_closing = SND_REQUEST_CLOSING; int anim_mode_1 = request.anim_mode; /* (higher priority) */ int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */ int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2); int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL: anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode); if (game_status == GAME_MODE_PLAYING) BlitScreenToBitmap(backbuffer); SetDrawtoField(DRAW_TO_BACKBUFFER); // SetDrawBackgroundMask(REDRAW_NONE); if (action == ACTION_OPENING) { BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); if (req_state & REQ_ASK) { MapGadget(tool_gadget[TOOL_CTRL_ID_YES]); MapGadget(tool_gadget[TOOL_CTRL_ID_NO]); } else if (req_state & REQ_CONFIRM) { MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]); } else if (req_state & REQ_PLAYER) { MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]); } DrawEnvelopeRequest(text); } game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */ if (action == ACTION_OPENING) { PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE); if (anim_mode == ANIM_DEFAULT) AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING); AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING); } else { PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE); if (anim_mode != ANIM_NONE) AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING); if (anim_mode == ANIM_DEFAULT) AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING); } game.envelope_active = FALSE; if (action == ACTION_CLOSING) BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); // SetDrawBackgroundMask(last_draw_background_mask); redraw_mask |= REDRAW_FIELD; BackToFront(); if (action == ACTION_CLOSING && game_status == GAME_MODE_PLAYING && level.game_engine_type == GAME_ENGINE_TYPE_RND) SetDrawtoField(DRAW_TO_FIELDBUFFER); } void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize) { if (IS_MM_WALL(element)) { DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg); } else { Bitmap *src_bitmap; int src_x, src_y; int graphic = el2preimg(element); getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y); BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x, dst_y); } } void DrawLevel(int draw_background_mask) { int x,y; SetMainBackgroundImage(IMG_BACKGROUND_PLAYING); SetDrawBackgroundMask(draw_background_mask); ClearField(); for (x = BX1; x <= BX2; x++) for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); redraw_mask |= REDRAW_FIELD; } void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y, int tilesize) { int x,y; for (x = 0; x < size_x; x++) for (y = 0; y < size_y; y++) DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize); redraw_mask |= REDRAW_FIELD; } void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y) { int x,y; for (x = 0; x < size_x; x++) for (y = 0; y < size_y; y++) DrawMiniElementOrWall(x, y, scroll_x, scroll_y); redraw_mask |= REDRAW_FIELD; } static void DrawPreviewLevelPlayfield(int from_x, int from_y) { boolean show_level_border = (BorderElement != EL_EMPTY); int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); int tile_size = preview.tile_size; int preview_width = preview.xsize * tile_size; int preview_height = preview.ysize * tile_size; int real_preview_xsize = MIN(level_xsize, preview.xsize); int real_preview_ysize = MIN(level_ysize, preview.ysize); int real_preview_width = real_preview_xsize * tile_size; int real_preview_height = real_preview_ysize * tile_size; int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align); int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign); int x, y; if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1)) return; DrawBackground(dst_x, dst_y, preview_width, preview_height); dst_x += (preview_width - real_preview_width) / 2; dst_y += (preview_height - real_preview_height) / 2; for (x = 0; x < real_preview_xsize; x++) { for (y = 0; y < real_preview_ysize; y++) { int lx = from_x + x + (show_level_border ? -1 : 0); int ly = from_y + y + (show_level_border ? -1 : 0); int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] : getBorderElement(lx, ly)); DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size, element, tile_size); } } redraw_mask |= REDRAW_FIELD; } #define MICROLABEL_EMPTY 0 #define MICROLABEL_LEVEL_NAME 1 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2 #define MICROLABEL_LEVEL_AUTHOR 3 #define MICROLABEL_IMPORTED_FROM_HEAD 4 #define MICROLABEL_IMPORTED_FROM 5 #define MICROLABEL_IMPORTED_BY_HEAD 6 #define MICROLABEL_IMPORTED_BY 7 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr) { int max_text_width = SXSIZE; int font_width = getFontWidth(font_nr); if (pos->align == ALIGN_CENTER) max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2); else if (pos->align == ALIGN_RIGHT) max_text_width = pos->x; else max_text_width = SXSIZE - pos->x; return max_text_width / font_width; } static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos) { char label_text[MAX_OUTPUT_LINESIZE + 1]; int max_len_label_text; int font_nr = pos->font; int i; if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font))) return; if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD || mode == MICROLABEL_IMPORTED_FROM_HEAD || mode == MICROLABEL_IMPORTED_BY_HEAD) font_nr = pos->font_alt; max_len_label_text = getMaxTextLength(pos, font_nr); if (pos->size != -1) max_len_label_text = pos->size; for (i = 0; i < max_len_label_text; i++) label_text[i] = ' '; label_text[max_len_label_text] = '\0'; if (strlen(label_text) > 0) DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name : mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" : mode == MICROLABEL_LEVEL_AUTHOR ? level.author : mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" : mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from : mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" : mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""), max_len_label_text); label_text[max_len_label_text] = '\0'; if (strlen(label_text) > 0) DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); redraw_mask |= REDRAW_FIELD; } static void DrawPreviewLevelLabel(int mode) { DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2); } static void DrawPreviewLevelInfo(int mode) { if (mode == MICROLABEL_LEVEL_NAME) DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name); else if (mode == MICROLABEL_LEVEL_AUTHOR) DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author); } static void DrawPreviewLevelExt(boolean restart) { static unsigned int scroll_delay = 0; static unsigned int label_delay = 0; static int from_x, from_y, scroll_direction; static int label_state, label_counter; unsigned int scroll_delay_value = preview.step_delay; boolean show_level_border = (BorderElement != EL_EMPTY); int level_xsize = lev_fieldx + (show_level_border ? 2 : 0); int level_ysize = lev_fieldy + (show_level_border ? 2 : 0); if (restart) { from_x = 0; from_y = 0; if (preview.anim_mode == ANIM_CENTERED) { if (level_xsize > preview.xsize) from_x = (level_xsize - preview.xsize) / 2; if (level_ysize > preview.ysize) from_y = (level_ysize - preview.ysize) / 2; } from_x += preview.xoffset; from_y += preview.yoffset; scroll_direction = MV_RIGHT; label_state = 1; label_counter = 0; DrawPreviewLevelPlayfield(from_x, from_y); DrawPreviewLevelLabel(label_state); DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME); DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR); /* initialize delay counters */ DelayReached(&scroll_delay, 0); DelayReached(&label_delay, 0); if (leveldir_current->name) { struct TextPosInfo *pos = &menu.main.text.level_info_1; char label_text[MAX_OUTPUT_LINESIZE + 1]; int font_nr = pos->font; int max_len_label_text = getMaxTextLength(pos, font_nr); if (pos->size != -1) max_len_label_text = pos->size; strncpy(label_text, leveldir_current->name, max_len_label_text); label_text[max_len_label_text] = '\0'; if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font))) DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align); } return; } /* scroll preview level, if needed */ if (preview.anim_mode != ANIM_NONE && (level_xsize > preview.xsize || level_ysize > preview.ysize) && DelayReached(&scroll_delay, scroll_delay_value)) { switch (scroll_direction) { case MV_LEFT: if (from_x > 0) { from_x -= preview.step_offset; from_x = (from_x < 0 ? 0 : from_x); } else scroll_direction = MV_UP; break; case MV_RIGHT: if (from_x < level_xsize - preview.xsize) { from_x += preview.step_offset; from_x = (from_x > level_xsize - preview.xsize ? level_xsize - preview.xsize : from_x); } else scroll_direction = MV_DOWN; break; case MV_UP: if (from_y > 0) { from_y -= preview.step_offset; from_y = (from_y < 0 ? 0 : from_y); } else scroll_direction = MV_RIGHT; break; case MV_DOWN: if (from_y < level_ysize - preview.ysize) { from_y += preview.step_offset; from_y = (from_y > level_ysize - preview.ysize ? level_ysize - preview.ysize : from_y); } else scroll_direction = MV_LEFT; break; default: break; } DrawPreviewLevelPlayfield(from_x, from_y); } /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */ /* redraw micro level label, if needed */ if (!strEqual(level.name, NAMELESS_LEVEL_NAME) && !strEqual(level.author, ANONYMOUS_NAME) && !strEqual(level.author, leveldir_current->name) && DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY)) { int max_label_counter = 23; if (leveldir_current->imported_from != NULL && strlen(leveldir_current->imported_from) > 0) max_label_counter += 14; if (leveldir_current->imported_by != NULL && strlen(leveldir_current->imported_by) > 0) max_label_counter += 14; label_counter = (label_counter + 1) % max_label_counter; label_state = (label_counter >= 0 && label_counter <= 7 ? MICROLABEL_LEVEL_NAME : label_counter >= 9 && label_counter <= 12 ? MICROLABEL_LEVEL_AUTHOR_HEAD : label_counter >= 14 && label_counter <= 21 ? MICROLABEL_LEVEL_AUTHOR : label_counter >= 23 && label_counter <= 26 ? MICROLABEL_IMPORTED_FROM_HEAD : label_counter >= 28 && label_counter <= 35 ? MICROLABEL_IMPORTED_FROM : label_counter >= 37 && label_counter <= 40 ? MICROLABEL_IMPORTED_BY_HEAD : label_counter >= 42 && label_counter <= 49 ? MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY); if (leveldir_current->imported_from == NULL && (label_state == MICROLABEL_IMPORTED_FROM_HEAD || label_state == MICROLABEL_IMPORTED_FROM)) label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ? MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY); DrawPreviewLevelLabel(label_state); } } void DrawPreviewLevelInitial() { DrawPreviewLevelExt(TRUE); } void DrawPreviewLevelAnimation() { DrawPreviewLevelExt(FALSE); } inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y, int graphic, int sync_frame, int mask_mode) { int frame = getGraphicAnimationFrame(graphic, sync_frame); if (mask_mode == USE_MASKING) DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame); else DrawGraphicExt(dst_bitmap, x, y, graphic, frame); } void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y, int graphic, int sync_frame, int mask_mode) { int frame = getGraphicAnimationFrame(graphic, sync_frame); if (mask_mode == USE_MASKING) DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame); else DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame); } inline static void DrawGraphicAnimation(int x, int y, int graphic) { int lx = LEVELX(x), ly = LEVELY(y); if (!IN_SCR_FIELD(x, y)) return; DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic, GfxFrame[lx][ly], NO_MASKING); MarkTileDirty(x, y); } void DrawFixedGraphicAnimation(int x, int y, int graphic) { int lx = LEVELX(x), ly = LEVELY(y); if (!IN_SCR_FIELD(x, y)) return; DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, GfxFrame[lx][ly], NO_MASKING); MarkTileDirty(x, y); } void DrawLevelGraphicAnimation(int x, int y, int graphic) { DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); } void DrawLevelElementAnimation(int x, int y, int element) { int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); } void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic) { int sx = SCREENX(x), sy = SCREENY(y); if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy)) return; if (!IS_NEW_FRAME(GfxFrame[x][y], graphic)) return; DrawGraphicAnimation(sx, sy, graphic); #if 1 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y))) DrawLevelFieldCrumbled(x, y); #else if (GFX_CRUMBLED(Feld[x][y])) DrawLevelFieldCrumbled(x, y); #endif } void DrawLevelElementAnimationIfNeeded(int x, int y, int element) { int sx = SCREENX(x), sy = SCREENY(y); int graphic; if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy)) return; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); if (!IS_NEW_FRAME(GfxFrame[x][y], graphic)) return; DrawGraphicAnimation(sx, sy, graphic); if (GFX_CRUMBLED(element)) DrawLevelFieldCrumbled(x, y); } static int getPlayerGraphic(struct PlayerInfo *player, int move_dir) { if (player->use_murphy) { /* this works only because currently only one player can be "murphy" ... */ static int last_horizontal_dir = MV_LEFT; int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir); if (move_dir == MV_LEFT || move_dir == MV_RIGHT) last_horizontal_dir = move_dir; if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */ { int direction = (player->is_snapping ? move_dir : last_horizontal_dir); graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction); } return graphic; } else return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir); } static boolean equalGraphics(int graphic1, int graphic2) { struct GraphicInfo *g1 = &graphic_info[graphic1]; struct GraphicInfo *g2 = &graphic_info[graphic2]; return (g1->bitmap == g2->bitmap && g1->src_x == g2->src_x && g1->src_y == g2->src_y && g1->anim_frames == g2->anim_frames && g1->anim_delay == g2->anim_delay && g1->anim_mode == g2->anim_mode); } void DrawAllPlayers() { int i; for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) DrawPlayer(&stored_player[i]); } void DrawPlayerField(int x, int y) { if (!IS_PLAYER(x, y)) return; DrawPlayer(PLAYERINFO(x, y)); } #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1 void DrawPlayer(struct PlayerInfo *player) { int jx = player->jx; int jy = player->jy; int move_dir = player->MovDir; int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0); int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0); int last_jx = (player->is_moving ? jx - dx : jx); int last_jy = (player->is_moving ? jy - dy : jy); int next_jx = jx + dx; int next_jy = jy + dy; boolean player_is_moving = (player->MovPos ? TRUE : FALSE); boolean player_is_opaque = FALSE; int sx = SCREENX(jx), sy = SCREENY(jy); int sxx = 0, syy = 0; int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy]; int graphic; int action = ACTION_DEFAULT; int last_player_graphic = getPlayerGraphic(player, move_dir); int last_player_frame = player->Frame; int frame = 0; /* GfxElement[][] is set to the element the player is digging or collecting; remove also for off-screen player if the player is not moving anymore */ if (IN_LEV_FIELD(jx, jy) && !player_is_moving) GfxElement[jx][jy] = EL_UNDEFINED; if (!player->active || !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_EXPLOSION) return; action = (player->is_pushing ? ACTION_PUSHING : player->is_digging ? ACTION_DIGGING : player->is_collecting ? ACTION_COLLECTING : player->is_moving ? ACTION_MOVING : player->is_snapping ? ACTION_SNAPPING : player->is_dropping ? ACTION_DROPPING : player->is_waiting ? player->action_waiting : ACTION_DEFAULT); if (player->is_waiting) move_dir = player->dir_waiting; InitPlayerGfxAnimation(player, action, move_dir); /* ----------------------------------------------------------------------- */ /* draw things in the field the player is leaving, if needed */ /* ----------------------------------------------------------------------- */ if (player->is_moving) { if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element)) { DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]); if (last_element == EL_DYNAMITE_ACTIVE || last_element == EL_EM_DYNAMITE_ACTIVE || last_element == EL_SP_DISK_RED_ACTIVE) DrawDynamite(last_jx, last_jy); else DrawLevelFieldThruMask(last_jx, last_jy); } else if (last_element == EL_DYNAMITE_ACTIVE || last_element == EL_EM_DYNAMITE_ACTIVE || last_element == EL_SP_DISK_RED_ACTIVE) DrawDynamite(last_jx, last_jy); #if 0 /* !!! this is not enough to prevent flickering of players which are moving next to each others without a free tile between them -- this can only be solved by drawing all players layer by layer (first the background, then the foreground etc.) !!! => TODO */ else if (!IS_PLAYER(last_jx, last_jy)) DrawLevelField(last_jx, last_jy); #else else DrawLevelField(last_jx, last_jy); #endif if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy))) DrawLevelElement(next_jx, next_jy, EL_EMPTY); } if (!IN_SCR_FIELD(sx, sy)) return; /* ----------------------------------------------------------------------- */ /* draw things behind the player, if needed */ /* ----------------------------------------------------------------------- */ if (Back[jx][jy]) DrawLevelElement(jx, jy, Back[jx][jy]); else if (IS_ACTIVE_BOMB(element)) DrawLevelElement(jx, jy, EL_EMPTY); else { if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED) { int old_element = GfxElement[jx][jy]; int old_graphic = el_act_dir2img(old_element, action, move_dir); int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame); if (GFX_CRUMBLED(old_element)) DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame); else DrawGraphic(sx, sy, old_graphic, frame); if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER) player_is_opaque = TRUE; } else { GfxElement[jx][jy] = EL_UNDEFINED; /* make sure that pushed elements are drawn with correct frame rate */ graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir); if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic)) GfxFrame[jx][jy] = player->StepFrame; DrawLevelField(jx, jy); } } #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT /* ----------------------------------------------------------------------- */ /* draw player himself */ /* ----------------------------------------------------------------------- */ graphic = getPlayerGraphic(player, move_dir); /* in the case of changed player action or direction, prevent the current animation frame from being restarted for identical animations */ if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic)) player->Frame = last_player_frame; frame = getGraphicAnimationFrame(graphic, player->Frame); if (player->GfxPos) { if (move_dir == MV_LEFT || move_dir == MV_RIGHT) sxx = player->GfxPos; else syy = player->GfxPos; } if (player_is_opaque) DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING); else DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); if (SHIELD_ON(player)) { int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE : IMG_SHIELD_NORMAL_ACTIVE); int frame = getGraphicAnimationFrame(graphic, -1); DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); } #endif #if DRAW_PLAYER_OVER_PUSHED_ELEMENT if (player->GfxPos) { if (move_dir == MV_LEFT || move_dir == MV_RIGHT) sxx = player->GfxPos; else syy = player->GfxPos; } #endif /* ----------------------------------------------------------------------- */ /* draw things the player is pushing, if needed */ /* ----------------------------------------------------------------------- */ if (player->is_pushing && player->is_moving) { int px = SCREENX(jx), py = SCREENY(jy); int pxx = (TILEX - ABS(sxx)) * dx; int pyy = (TILEY - ABS(syy)) * dy; int gfx_frame = GfxFrame[jx][jy]; int graphic; int sync_frame; int frame; if (!IS_MOVING(jx, jy)) /* push movement already finished */ { element = Feld[next_jx][next_jy]; gfx_frame = GfxFrame[next_jx][next_jy]; } graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir); sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame); frame = getGraphicAnimationFrame(graphic, sync_frame); /* draw background element under pushed element (like the Sokoban field) */ if (game.use_masked_pushing && IS_MOVING(jx, jy)) { /* this allows transparent pushing animation over non-black background */ if (Back[jx][jy]) DrawLevelElement(jx, jy, Back[jx][jy]); else DrawLevelElement(jx, jy, EL_EMPTY); if (Back[next_jx][next_jy]) DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]); else DrawLevelElement(next_jx, next_jy, EL_EMPTY); } else if (Back[next_jx][next_jy]) DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]); #if 1 /* do not draw (EM style) pushing animation when pushing is finished */ /* (two-tile animations usually do not contain start and end frame) */ if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy)) DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]); else DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING); #else /* masked drawing is needed for EMC style (double) movement graphics */ /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */ DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING); #endif } #if DRAW_PLAYER_OVER_PUSHED_ELEMENT /* ----------------------------------------------------------------------- */ /* draw player himself */ /* ----------------------------------------------------------------------- */ graphic = getPlayerGraphic(player, move_dir); /* in the case of changed player action or direction, prevent the current animation frame from being restarted for identical animations */ if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic)) player->Frame = last_player_frame; frame = getGraphicAnimationFrame(graphic, player->Frame); if (player->GfxPos) { if (move_dir == MV_LEFT || move_dir == MV_RIGHT) sxx = player->GfxPos; else syy = player->GfxPos; } if (player_is_opaque) DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING); else DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); if (SHIELD_ON(player)) { int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE : IMG_SHIELD_NORMAL_ACTIVE); int frame = getGraphicAnimationFrame(graphic, -1); DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING); } #endif /* ----------------------------------------------------------------------- */ /* draw things in front of player (active dynamite or dynabombs) */ /* ----------------------------------------------------------------------- */ if (IS_ACTIVE_BOMB(element)) { graphic = el2img(element); frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]); if (game.emulation == EMU_SUPAPLEX) DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame); else DrawGraphicThruMask(sx, sy, graphic, frame); } if (player_is_moving && last_element == EL_EXPLOSION) { int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ? GfxElement[last_jx][last_jy] : EL_EMPTY); int graphic = el_act2img(element, ACTION_EXPLODING); int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); int phase = ExplodePhase[last_jx][last_jy] - 1; int frame = getGraphicAnimationFrame(graphic, phase - delay); if (phase >= delay) DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame); } /* ----------------------------------------------------------------------- */ /* draw elements the player is just walking/passing through/under */ /* ----------------------------------------------------------------------- */ if (player_is_moving) { /* handle the field the player is leaving ... */ if (IS_ACCESSIBLE_INSIDE(last_element)) DrawLevelField(last_jx, last_jy); else if (IS_ACCESSIBLE_UNDER(last_element)) DrawLevelFieldThruMask(last_jx, last_jy); } /* do not redraw accessible elements if the player is just pushing them */ if (!player_is_moving || !player->is_pushing) { /* ... and the field the player is entering */ if (IS_ACCESSIBLE_INSIDE(element)) DrawLevelField(jx, jy); else if (IS_ACCESSIBLE_UNDER(element)) DrawLevelFieldThruMask(jx, jy); } MarkTileDirty(sx, sy); } /* ------------------------------------------------------------------------- */ void WaitForEventToContinue() { boolean still_wait = TRUE; if (program.headless) return; /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); button_status = MB_RELEASED; ClearEventQueue(); while (still_wait) { Event event; if (NextValidEvent(&event)) { switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_KEYPRESS: #if defined(TARGET_SDL2) case SDL_CONTROLLERBUTTONDOWN: #endif case SDL_JOYBUTTONDOWN: still_wait = FALSE; break; case EVENT_KEYRELEASE: ClearPlayerAction(); break; default: HandleOtherEvents(&event); break; } } else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED) { still_wait = FALSE; } BackToFront(); } } #define MAX_REQUEST_LINES 13 #define MAX_REQUEST_LINE_FONT1_LEN 7 #define MAX_REQUEST_LINE_FONT2_LEN 10 static int RequestHandleEvents(unsigned int req_state) { boolean level_solved = (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd); int width = request.width; int height = request.height; int sx, sy; int result; setRequestPosition(&sx, &sy, FALSE); button_status = MB_RELEASED; request_gadget_id = -1; result = -1; while (result < 0) { if (level_solved) { /* the MM game engine does not use a special (scrollable) field buffer */ if (level.game_engine_type != GAME_ENGINE_TYPE_MM) SetDrawtoField(DRAW_TO_FIELDBUFFER); HandleGameActions(); SetDrawtoField(DRAW_TO_BACKBUFFER); if (global.use_envelope_request) { /* copy current state of request area to middle of playfield area */ BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy); } } if (PendingEvent()) { Event event; while (NextValidEvent(&event)) { switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_BUTTONRELEASE: case EVENT_MOTIONNOTIFY: { int mx, my; if (event.type == EVENT_MOTIONNOTIFY) { if (!button_status) continue; motion_status = TRUE; mx = ((MotionEvent *) &event)->x; my = ((MotionEvent *) &event)->y; } else { motion_status = FALSE; mx = ((ButtonEvent *) &event)->x; my = ((ButtonEvent *) &event)->y; if (event.type == EVENT_BUTTONPRESS) button_status = ((ButtonEvent *) &event)->button; else button_status = MB_RELEASED; } /* this sets 'request_gadget_id' */ HandleGadgets(mx, my, button_status); switch (request_gadget_id) { case TOOL_CTRL_ID_YES: result = TRUE; break; case TOOL_CTRL_ID_NO: result = FALSE; break; case TOOL_CTRL_ID_CONFIRM: result = TRUE | FALSE; break; case TOOL_CTRL_ID_PLAYER_1: result = 1; break; case TOOL_CTRL_ID_PLAYER_2: result = 2; break; case TOOL_CTRL_ID_PLAYER_3: result = 3; break; case TOOL_CTRL_ID_PLAYER_4: result = 4; break; default: break; } break; } #if defined(TARGET_SDL2) case SDL_WINDOWEVENT: HandleWindowEvent((WindowEvent *) &event); break; case SDL_APP_WILLENTERBACKGROUND: case SDL_APP_DIDENTERBACKGROUND: case SDL_APP_WILLENTERFOREGROUND: case SDL_APP_DIDENTERFOREGROUND: HandlePauseResumeEvent((PauseResumeEvent *) &event); break; #endif case EVENT_KEYPRESS: { Key key = GetEventKey((KeyEvent *)&event, TRUE); switch (key) { case KSYM_space: if (req_state & REQ_CONFIRM) result = 1; break; case KSYM_Return: #if defined(TARGET_SDL2) case KSYM_Select: case KSYM_Menu: #if defined(KSYM_Rewind) case KSYM_Rewind: /* for Amazon Fire TV remote */ #endif #endif result = 1; break; case KSYM_Escape: #if defined(TARGET_SDL2) case KSYM_Back: #if defined(KSYM_FastForward) case KSYM_FastForward: /* for Amazon Fire TV remote */ #endif #endif result = 0; break; default: HandleKeysDebug(key); break; } if (req_state & REQ_PLAYER) result = 0; break; } case EVENT_KEYRELEASE: ClearPlayerAction(); break; #if defined(TARGET_SDL2) case SDL_CONTROLLERBUTTONDOWN: switch (event.cbutton.button) { case SDL_CONTROLLER_BUTTON_A: case SDL_CONTROLLER_BUTTON_X: case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: result = 1; break; case SDL_CONTROLLER_BUTTON_B: case SDL_CONTROLLER_BUTTON_Y: case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: case SDL_CONTROLLER_BUTTON_BACK: result = 0; break; } if (req_state & REQ_PLAYER) result = 0; break; case SDL_CONTROLLERBUTTONUP: HandleJoystickEvent(&event); ClearPlayerAction(); break; #endif default: HandleOtherEvents(&event); break; } } } else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED) { int joy = AnyJoystick(); if (joy & JOY_BUTTON_1) result = 1; else if (joy & JOY_BUTTON_2) result = 0; } if (level_solved) { if (global.use_envelope_request) { /* copy back current state of pressed buttons inside request area */ BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy); } } BackToFront(); } return result; } static boolean RequestDoor(char *text, unsigned int req_state) { unsigned int old_door_state; int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN; int font_nr = FONT_TEXT_2; char *text_ptr; int result; int ty; if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN) { max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN; font_nr = FONT_TEXT_1; } if (game_status == GAME_MODE_PLAYING) BlitScreenToBitmap(backbuffer); /* disable deactivated drawing when quick-loading level tape recording */ if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); SetMouseCursor(CURSOR_DEFAULT); #if defined(NETWORK_AVALIABLE) /* pause network game while waiting for request to answer */ if (options.network && game_status == GAME_MODE_PLAYING && req_state & REQUEST_WAIT_FOR_INPUT) SendToServer_PausePlaying(); #endif old_door_state = GetDoorState(); /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); UnmapAllGadgets(); /* draw released gadget before proceeding */ // BackToFront(); if (old_door_state & DOOR_OPEN_1) { CloseDoor(DOOR_CLOSE_1); /* save old door content */ BlitBitmap(bitmap_db_door_1, bitmap_db_door_1, 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0); } SetDoorBackgroundImage(IMG_BACKGROUND_DOOR); SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1); /* clear door drawing field */ DrawBackground(DX, DY, DXSIZE, DYSIZE); /* force DOOR font inside door area */ SetFontStatus(GAME_MODE_PSEUDO_DOOR); /* write text for request */ for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++) { char text_line[max_request_line_len + 1]; int tx, tl, tc = 0; if (!*text_ptr) break; for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++) { tc = *(text_ptr + tx); // if (!tc || tc == ' ') if (!tc || tc == ' ' || tc == '?' || tc == '!') break; } if ((tc == '?' || tc == '!') && tl == 0) tl = 1; if (!tl) { text_ptr++; ty--; continue; } strncpy(text_line, text_ptr, tl); text_line[tl] = 0; DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2, DY + 8 + ty * (getFontHeight(font_nr) + 2), text_line, font_nr); text_ptr += tl + (tc == ' ' ? 1 : 0); // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0); } ResetFontStatus(); if (req_state & REQ_ASK) { MapGadget(tool_gadget[TOOL_CTRL_ID_YES]); MapGadget(tool_gadget[TOOL_CTRL_ID_NO]); } else if (req_state & REQ_CONFIRM) { MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]); } else if (req_state & REQ_PLAYER) { MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]); MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]); } /* copy request gadgets to door backbuffer */ BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); OpenDoor(DOOR_OPEN_1); if (!(req_state & REQUEST_WAIT_FOR_INPUT)) { if (game_status == GAME_MODE_PLAYING) { SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); } else { SetDrawBackgroundMask(REDRAW_FIELD); } return FALSE; } SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1); // ---------- handle request buttons ---------- result = RequestHandleEvents(req_state); UnmapToolButtons(); if (!(req_state & REQ_STAY_OPEN)) { CloseDoor(DOOR_CLOSE_1); if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) || (req_state & REQ_REOPEN)) OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); } RemapAllGadgets(); if (game_status == GAME_MODE_PLAYING) { SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); } else { SetDrawBackgroundMask(REDRAW_FIELD); } #if defined(NETWORK_AVALIABLE) /* continue network game after request */ if (options.network && game_status == GAME_MODE_PLAYING && req_state & REQUEST_WAIT_FOR_INPUT) SendToServer_ContinuePlaying(); #endif /* restore deactivated drawing when quick-loading level tape recording */ if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOn(); return result; } static boolean RequestEnvelope(char *text, unsigned int req_state) { int result; if (game_status == GAME_MODE_PLAYING) BlitScreenToBitmap(backbuffer); /* disable deactivated drawing when quick-loading level tape recording */ if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); SetMouseCursor(CURSOR_DEFAULT); #if defined(NETWORK_AVALIABLE) /* pause network game while waiting for request to answer */ if (options.network && game_status == GAME_MODE_PLAYING && req_state & REQUEST_WAIT_FOR_INPUT) SendToServer_PausePlaying(); #endif /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); UnmapAllGadgets(); // (replace with setting corresponding request background) // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR); // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1); /* clear door drawing field */ // DrawBackground(DX, DY, DXSIZE, DYSIZE); ShowEnvelopeRequest(text, req_state, ACTION_OPENING); if (!(req_state & REQUEST_WAIT_FOR_INPUT)) { if (game_status == GAME_MODE_PLAYING) { SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); } else { SetDrawBackgroundMask(REDRAW_FIELD); } return FALSE; } SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1); // ---------- handle request buttons ---------- result = RequestHandleEvents(req_state); UnmapToolButtons(); ShowEnvelopeRequest(text, req_state, ACTION_CLOSING); RemapAllGadgets(); if (game_status == GAME_MODE_PLAYING) { SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); } else { SetDrawBackgroundMask(REDRAW_FIELD); } #if defined(NETWORK_AVALIABLE) /* continue network game after request */ if (options.network && game_status == GAME_MODE_PLAYING && req_state & REQUEST_WAIT_FOR_INPUT) SendToServer_ContinuePlaying(); #endif /* restore deactivated drawing when quick-loading level tape recording */ if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOn(); return result; } boolean Request(char *text, unsigned int req_state) { boolean overlay_active = GetOverlayActive(); boolean result; SetOverlayActive(FALSE); if (global.use_envelope_request) result = RequestEnvelope(text, req_state); else result = RequestDoor(text, req_state); SetOverlayActive(overlay_active); return result; } static int compareDoorPartOrderInfo(const void *object1, const void *object2) { const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1; const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2; int compare_result; if (dpo1->sort_priority != dpo2->sort_priority) compare_result = dpo1->sort_priority - dpo2->sort_priority; else compare_result = dpo1->nr - dpo2->nr; return compare_result; } void InitGraphicCompatibilityInfo_Doors() { struct { int door_token; int part_1, part_8; struct DoorInfo *door; } doors[] = { { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 }, { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 }, { -1, -1, -1, NULL } }; struct Rect door_rect_list[] = { { DX, DY, DXSIZE, DYSIZE }, { VX, VY, VXSIZE, VYSIZE } }; int i, j; for (i = 0; doors[i].door_token != -1; i++) { int door_token = doors[i].door_token; int door_index = DOOR_INDEX_FROM_TOKEN(door_token); int part_1 = doors[i].part_1; int part_8 = doors[i].part_8; int part_2 = part_1 + 1; int part_3 = part_1 + 2; struct DoorInfo *door = doors[i].door; struct Rect *door_rect = &door_rect_list[door_index]; boolean door_gfx_redefined = FALSE; /* check if any door part graphic definitions have been redefined */ for (j = 0; door_part_controls[j].door_token != -1; j++) { struct DoorPartControlInfo *dpc = &door_part_controls[j]; struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic); if (dpc->door_token == door_token && fi->redefined) door_gfx_redefined = TRUE; } /* check for old-style door graphic/animation modifications */ if (!door_gfx_redefined) { if (door->anim_mode & ANIM_STATIC_PANEL) { door->panel.step_xoffset = 0; door->panel.step_yoffset = 0; } if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL)) { struct GraphicInfo *g_part_1 = &graphic_info[part_1]; struct GraphicInfo *g_part_2 = &graphic_info[part_2]; int num_door_steps, num_panel_steps; /* remove door part graphics other than the two default wings */ for (j = 0; door_part_controls[j].door_token != -1; j++) { struct DoorPartControlInfo *dpc = &door_part_controls[j]; struct GraphicInfo *g = &graphic_info[dpc->graphic]; if (dpc->graphic >= part_3 && dpc->graphic <= part_8) g->bitmap = NULL; } /* set graphics and screen positions of the default wings */ g_part_1->width = door_rect->width; g_part_1->height = door_rect->height; g_part_2->width = door_rect->width; g_part_2->height = door_rect->height; g_part_2->src_x = door_rect->width; g_part_2->src_y = g_part_1->src_y; door->part_2.x = door->part_1.x; door->part_2.y = door->part_1.y; if (door->width != -1) { g_part_1->width = door->width; g_part_2->width = door->width; // special treatment for graphics and screen position of right wing g_part_2->src_x += door_rect->width - door->width; door->part_2.x += door_rect->width - door->width; } if (door->height != -1) { g_part_1->height = door->height; g_part_2->height = door->height; // special treatment for graphics and screen position of bottom wing g_part_2->src_y += door_rect->height - door->height; door->part_2.y += door_rect->height - door->height; } /* set animation delays for the default wings and panels */ door->part_1.step_delay = door->step_delay; door->part_2.step_delay = door->step_delay; door->panel.step_delay = door->step_delay; /* set animation draw order for the default wings */ door->part_1.sort_priority = 2; /* draw left wing over ... */ door->part_2.sort_priority = 1; /* ... right wing */ /* set animation draw offset for the default wings */ if (door->anim_mode & ANIM_HORIZONTAL) { door->part_1.step_xoffset = door->step_offset; door->part_1.step_yoffset = 0; door->part_2.step_xoffset = door->step_offset * -1; door->part_2.step_yoffset = 0; num_door_steps = g_part_1->width / door->step_offset; } else // ANIM_VERTICAL { door->part_1.step_xoffset = 0; door->part_1.step_yoffset = door->step_offset; door->part_2.step_xoffset = 0; door->part_2.step_yoffset = door->step_offset * -1; num_door_steps = g_part_1->height / door->step_offset; } /* set animation draw offset for the default panels */ if (door->step_offset > 1) { num_panel_steps = 2 * door_rect->height / door->step_offset; door->panel.start_step = num_panel_steps - num_door_steps; door->panel.start_step_closing = door->panel.start_step; } else { num_panel_steps = door_rect->height / door->step_offset; door->panel.start_step = num_panel_steps - num_door_steps / 2; door->panel.start_step_closing = door->panel.start_step; door->panel.step_delay *= 2; } } } } } void InitDoors() { int i; for (i = 0; door_part_controls[i].door_token != -1; i++) { struct DoorPartControlInfo *dpc = &door_part_controls[i]; struct DoorPartOrderInfo *dpo = &door_part_order[i]; /* initialize "start_step_opening" and "start_step_closing", if needed */ if (dpc->pos->start_step_opening == 0 && dpc->pos->start_step_closing == 0) { // dpc->pos->start_step_opening = dpc->pos->start_step; dpc->pos->start_step_closing = dpc->pos->start_step; } /* fill structure for door part draw order (sorted below) */ dpo->nr = i; dpo->sort_priority = dpc->pos->sort_priority; } /* sort door part controls according to sort_priority and graphic number */ qsort(door_part_order, MAX_DOOR_PARTS, sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo); } unsigned int OpenDoor(unsigned int door_state) { if (door_state & DOOR_COPY_BACK) { if (door_state & DOOR_OPEN_1) BlitBitmap(bitmap_db_door_1, bitmap_db_door_1, 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0); if (door_state & DOOR_OPEN_2) BlitBitmap(bitmap_db_door_2, bitmap_db_door_2, 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0); door_state &= ~DOOR_COPY_BACK; } return MoveDoor(door_state); } unsigned int CloseDoor(unsigned int door_state) { unsigned int old_door_state = GetDoorState(); if (!(door_state & DOOR_NO_COPY_BACK)) { if (old_door_state & DOOR_OPEN_1) BlitBitmap(backbuffer, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); if (old_door_state & DOOR_OPEN_2) BlitBitmap(backbuffer, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0); door_state &= ~DOOR_NO_COPY_BACK; } return MoveDoor(door_state); } unsigned int GetDoorState() { return MoveDoor(DOOR_GET_STATE); } unsigned int SetDoorState(unsigned int door_state) { return MoveDoor(door_state | DOOR_SET_STATE); } int euclid(int a, int b) { return (b ? euclid(b, a % b) : a); } unsigned int MoveDoor(unsigned int door_state) { struct Rect door_rect_list[] = { { DX, DY, DXSIZE, DYSIZE }, { VX, VY, VXSIZE, VYSIZE } }; static int door1 = DOOR_CLOSE_1; static int door2 = DOOR_CLOSE_2; unsigned int door_delay = 0; unsigned int door_delay_value; int i; if (door_state == DOOR_GET_STATE) return (door1 | door2); if (door_state & DOOR_SET_STATE) { 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); } if (!(door_state & DOOR_FORCE_REDRAW)) { 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) door_state &= ~DOOR_CLOSE_1; 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) door_state &= ~DOOR_CLOSE_2; } if (global.autoplay_leveldir) { door_state |= DOOR_NO_DELAY; door_state &= ~DOOR_CLOSE_ALL; } if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM)) door_state |= DOOR_NO_DELAY; if (door_state & DOOR_ACTION) { boolean door_panel_drawn[NUM_DOORS]; boolean panel_has_doors[NUM_DOORS]; boolean door_part_skip[MAX_DOOR_PARTS]; boolean door_part_done[MAX_DOOR_PARTS]; boolean door_part_done_all; int num_steps[MAX_DOOR_PARTS]; int max_move_delay = 0; // delay for complete animations of all doors int max_step_delay = 0; // delay (ms) between two animation frames int num_move_steps = 0; // number of animation steps for all doors int max_move_delay_doors_only = 0; // delay for doors only (no panel) int num_move_steps_doors_only = 0; // steps for doors only (no panel) int current_move_delay = 0; int start = 0; int k; for (i = 0; i < NUM_DOORS; i++) panel_has_doors[i] = FALSE; for (i = 0; i < MAX_DOOR_PARTS; i++) { struct DoorPartControlInfo *dpc = &door_part_controls[i]; struct GraphicInfo *g = &graphic_info[dpc->graphic]; int door_token = dpc->door_token; door_part_done[i] = FALSE; door_part_skip[i] = (!(door_state & door_token) || !g->bitmap); } for (i = 0; i < MAX_DOOR_PARTS; i++) { int nr = door_part_order[i].nr; struct DoorPartControlInfo *dpc = &door_part_controls[nr]; struct DoorPartPosInfo *pos = dpc->pos; struct GraphicInfo *g = &graphic_info[dpc->graphic]; int door_token = dpc->door_token; int door_index = DOOR_INDEX_FROM_TOKEN(door_token); boolean is_panel = DOOR_PART_IS_PANEL(nr); int step_xoffset = ABS(pos->step_xoffset); int step_yoffset = ABS(pos->step_yoffset); int step_delay = pos->step_delay; int current_door_state = door_state & door_token; boolean door_opening = ((current_door_state & DOOR_OPEN) != 0); boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0); boolean part_opening = (is_panel ? door_closing : door_opening); int start_step = (part_opening ? pos->start_step_opening : pos->start_step_closing); float move_xsize = (step_xoffset ? g->width : 0); float move_ysize = (step_yoffset ? g->height : 0); int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0); int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0); int move_steps = (move_xsteps && move_ysteps ? MIN(move_xsteps, move_ysteps) : move_xsteps ? move_xsteps : move_ysteps) - start_step; int move_delay = move_steps * step_delay; if (door_part_skip[nr]) continue; max_move_delay = MAX(max_move_delay, move_delay); max_step_delay = (max_step_delay == 0 ? step_delay : euclid(max_step_delay, step_delay)); num_steps[nr] = move_steps; if (!is_panel) { max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay); panel_has_doors[door_index] = TRUE; } } max_step_delay = MAX(1, max_step_delay); // prevent division by zero num_move_steps = max_move_delay / max_step_delay; num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay; door_delay_value = max_step_delay; if ((door_state & DOOR_NO_DELAY) || setup.quick_doors) { start = num_move_steps - 1; } else { /* opening door sound has priority over simultaneously closing door */ if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2)) { PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE); if (door_state & DOOR_OPEN_1) PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE); if (door_state & DOOR_OPEN_2) PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE); } else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2)) { PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE); if (door_state & DOOR_CLOSE_1) PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE); if (door_state & DOOR_CLOSE_2) PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE); } } for (k = start; k < num_move_steps; k++) { int last_frame = num_move_steps - 1; // last frame of this "for" loop door_part_done_all = TRUE; for (i = 0; i < NUM_DOORS; i++) door_panel_drawn[i] = FALSE; for (i = 0; i < MAX_DOOR_PARTS; i++) { int nr = door_part_order[i].nr; struct DoorPartControlInfo *dpc = &door_part_controls[nr]; struct DoorPartPosInfo *pos = dpc->pos; struct GraphicInfo *g = &graphic_info[dpc->graphic]; int door_token = dpc->door_token; int door_index = DOOR_INDEX_FROM_TOKEN(door_token); boolean is_panel = DOOR_PART_IS_PANEL(nr); boolean is_panel_and_door_has_closed = FALSE; struct Rect *door_rect = &door_rect_list[door_index]; Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 : bitmap_db_door_2); Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap); int current_door_state = door_state & door_token; boolean door_opening = ((current_door_state & DOOR_OPEN) != 0); boolean door_closing = !door_opening; boolean part_opening = (is_panel ? door_closing : door_opening); boolean part_closing = !part_opening; int start_step = (part_opening ? pos->start_step_opening : pos->start_step_closing); int step_delay = pos->step_delay; int step_factor = step_delay / max_step_delay; int k1 = (step_factor ? k / step_factor + 1 : k); int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1); int kk = MAX(0, k2); int g_src_x = 0; int g_src_y = 0; int src_x, src_y, src_xx, src_yy; int dst_x, dst_y, dst_xx, dst_yy; int width, height; if (door_part_skip[nr]) continue; if (!(door_state & door_token)) continue; if (!g->bitmap) continue; if (!is_panel) { int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1); int kk_door = MAX(0, k2_door); int sync_frame = kk_door * door_delay_value; int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame); getFixedGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y); } // draw door panel if (!door_panel_drawn[door_index]) { ClearRectangle(drawto, door_rect->x, door_rect->y, door_rect->width, door_rect->height); door_panel_drawn[door_index] = TRUE; } // draw opening or closing door parts if (pos->step_xoffset < 0) // door part on right side { src_xx = 0; dst_xx = pos->x + ABS(kk * pos->step_xoffset); width = g->width; if (dst_xx + width > door_rect->width) width = door_rect->width - dst_xx; } else // door part on left side { src_xx = 0; dst_xx = pos->x - kk * pos->step_xoffset; if (dst_xx < 0) { src_xx = ABS(dst_xx); dst_xx = 0; } width = g->width - src_xx; if (width > door_rect->width) width = door_rect->width; // printf("::: k == %d [%d] \n", k, start_step); } if (pos->step_yoffset < 0) // door part on bottom side { src_yy = 0; dst_yy = pos->y + ABS(kk * pos->step_yoffset); height = g->height; if (dst_yy + height > door_rect->height) height = door_rect->height - dst_yy; } else // door part on top side { src_yy = 0; dst_yy = pos->y - kk * pos->step_yoffset; if (dst_yy < 0) { src_yy = ABS(dst_yy); dst_yy = 0; } height = g->height - src_yy; } src_x = g_src_x + src_xx; src_y = g_src_y + src_yy; dst_x = door_rect->x + dst_xx; dst_y = door_rect->y + dst_yy; is_panel_and_door_has_closed = (is_panel && door_closing && panel_has_doors[door_index] && k >= num_move_steps_doors_only - 1); if (width >= 0 && width <= g->width && height >= 0 && height <= g->height && !is_panel_and_door_has_closed) { if (is_panel || !pos->draw_masked) BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); } redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token); if ((part_opening && (width < 0 || height < 0)) || (part_closing && (width >= g->width && height >= g->height))) door_part_done[nr] = TRUE; // continue door part animations, but not panel after door has closed if (!door_part_done[nr] && !is_panel_and_door_has_closed) door_part_done_all = FALSE; } if (!(door_state & DOOR_NO_DELAY)) { BackToFront(); SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame); current_move_delay += max_step_delay; /* prevent OS (Windows) from complaining about program not responding */ CheckQuitEvent(); } if (door_part_done_all) break; } if (!(door_state & DOOR_NO_DELAY)) { /* wait for specified door action post delay */ if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2) Delay(MAX(door_1.post_delay, door_2.post_delay)); else if (door_state & DOOR_ACTION_1) Delay(door_1.post_delay); else if (door_state & DOOR_ACTION_2) Delay(door_2.post_delay); } } if (door_state & DOOR_ACTION_1) door1 = door_state & DOOR_ACTION_1; if (door_state & DOOR_ACTION_2) door2 = door_state & DOOR_ACTION_2; // draw masked border over door area DrawMaskedBorder(REDRAW_DOOR_1); DrawMaskedBorder(REDRAW_DOOR_2); return (door1 | door2); } static boolean useSpecialEditorDoor() { int graphic = IMG_GLOBAL_BORDER_EDITOR; boolean redefined = getImageListEntryFromImageID(graphic)->redefined; // do not draw special editor door if editor border defined or redefined if (graphic_info[graphic].bitmap != NULL || redefined) return FALSE; // do not draw special editor door if global border defined to be empty if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL) return FALSE; // do not draw special editor door if viewport definitions do not match if (EX != VX || EY >= VY || EXSIZE != VXSIZE || EY + EYSIZE != VY + VYSIZE) return FALSE; return TRUE; } void DrawSpecialEditorDoor() { struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION]; int top_border_width = gfx1->width; int top_border_height = gfx1->height; int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size; int ex = EX - outer_border; int ey = EY - outer_border; int vy = VY - outer_border; int exsize = EXSIZE + 2 * outer_border; if (!useSpecialEditorDoor()) return; /* draw bigger level editor toolbox window */ BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y, top_border_width, top_border_height, ex, ey - top_border_height); BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy, exsize, EYSIZE - VYSIZE + outer_border, ex, ey); redraw_mask |= REDRAW_ALL; } void UndrawSpecialEditorDoor() { struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION]; int top_border_width = gfx1->width; int top_border_height = gfx1->height; int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size; int ex = EX - outer_border; int ey = EY - outer_border; int ey_top = ey - top_border_height; int exsize = EXSIZE + 2 * outer_border; int eysize = EYSIZE + 2 * outer_border; if (!useSpecialEditorDoor()) return; /* draw normal tape recorder window */ if (graphic_info[IMG_GLOBAL_BORDER].bitmap) { BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, ey_top, top_border_width, top_border_height, ex, ey_top); BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, ey, exsize, eysize, ex, ey); } else { // if screen background is set to "[NONE]", clear editor toolbox window ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height); ClearRectangle(drawto, ex, ey, exsize, eysize); } redraw_mask |= REDRAW_ALL; } /* ---------- new tool button stuff ---------------------------------------- */ static struct { int graphic; struct TextPosInfo *pos; int gadget_id; char *infotext; } toolbutton_info[NUM_TOOL_BUTTONS] = { { IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes, TOOL_CTRL_ID_YES, "yes" }, { IMG_GFX_REQUEST_BUTTON_NO, &request.button.no, TOOL_CTRL_ID_NO, "no" }, { IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm, TOOL_CTRL_ID_CONFIRM, "confirm" }, { IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1, TOOL_CTRL_ID_PLAYER_1, "player 1" }, { IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2, TOOL_CTRL_ID_PLAYER_2, "player 2" }, { IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3, TOOL_CTRL_ID_PLAYER_3, "player 3" }, { IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4, TOOL_CTRL_ID_PLAYER_4, "player 4" } }; void CreateToolButtons() { int i; for (i = 0; i < NUM_TOOL_BUTTONS; i++) { struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic]; struct TextPosInfo *pos = toolbutton_info[i].pos; struct GadgetInfo *gi; Bitmap *deco_bitmap = None; int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0; unsigned int event_mask = GD_EVENT_RELEASED; int dx = DX; int dy = DY; int gd_x = gfx->src_x; int gd_y = gfx->src_y; int gd_xp = gfx->src_x + gfx->pressed_xoffset; int gd_yp = gfx->src_y + gfx->pressed_yoffset; int id = i; if (global.use_envelope_request) setRequestPosition(&dx, &dy, TRUE); if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4) { int player_nr = id - TOOL_CTRL_ID_PLAYER_1; getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0, pos->size, &deco_bitmap, &deco_x, &deco_y); deco_xpos = (gfx->width - pos->size) / 2; deco_ypos = (gfx->height - pos->size) / 2; } gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, toolbutton_info[i].infotext, GDI_X, dx + GDI_ACTIVE_POS(pos->x), GDI_Y, dy + GDI_ACTIVE_POS(pos->y), GDI_WIDTH, gfx->width, GDI_HEIGHT, gfx->height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_DECORATION_POSITION, deco_xpos, deco_ypos, GDI_DECORATION_SIZE, pos->size, pos->size, GDI_DECORATION_SHIFTING, 1, 1, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleToolButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); tool_gadget[id] = gi; } } void FreeToolButtons() { int i; for (i = 0; i < NUM_TOOL_BUTTONS; i++) FreeGadget(tool_gadget[i]); } static void UnmapToolButtons() { int i; for (i = 0; i < NUM_TOOL_BUTTONS; i++) UnmapGadget(tool_gadget[i]); } static void HandleToolButtons(struct GadgetInfo *gi) { request_gadget_id = gi->custom_id; } static struct Mapping_EM_to_RND_object { int element_em; boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */ boolean is_backside; /* backside of moving element */ int element_rnd; int action; int direction; } em_object_mapping_list[] = { { Xblank, TRUE, FALSE, EL_EMPTY, -1, -1 }, { Yacid_splash_eB, FALSE, FALSE, EL_ACID_SPLASH_RIGHT, -1, -1 }, { Yacid_splash_wB, FALSE, FALSE, EL_ACID_SPLASH_LEFT, -1, -1 }, #ifdef EM_ENGINE_BAD_ROLL { Xstone_force_e, FALSE, FALSE, EL_ROCK, -1, MV_BIT_RIGHT }, { Xstone_force_w, FALSE, FALSE, EL_ROCK, -1, MV_BIT_LEFT }, { Xnut_force_e, FALSE, FALSE, EL_NUT, -1, MV_BIT_RIGHT }, { Xnut_force_w, FALSE, FALSE, EL_NUT, -1, MV_BIT_LEFT }, { Xspring_force_e, FALSE, FALSE, EL_SPRING, -1, MV_BIT_RIGHT }, { Xspring_force_w, FALSE, FALSE, EL_SPRING, -1, MV_BIT_LEFT }, { Xemerald_force_e, FALSE, FALSE, EL_EMERALD, -1, MV_BIT_RIGHT }, { Xemerald_force_w, FALSE, FALSE, EL_EMERALD, -1, MV_BIT_LEFT }, { Xdiamond_force_e, FALSE, FALSE, EL_DIAMOND, -1, MV_BIT_RIGHT }, { Xdiamond_force_w, FALSE, FALSE, EL_DIAMOND, -1, MV_BIT_LEFT }, { Xbomb_force_e, FALSE, FALSE, EL_BOMB, -1, MV_BIT_RIGHT }, { Xbomb_force_w, FALSE, FALSE, EL_BOMB, -1, MV_BIT_LEFT }, #endif /* EM_ENGINE_BAD_ROLL */ { Xstone, TRUE, FALSE, EL_ROCK, -1, -1 }, { Xstone_pause, FALSE, FALSE, EL_ROCK, -1, -1 }, { Xstone_fall, FALSE, FALSE, EL_ROCK, -1, -1 }, { Ystone_s, FALSE, FALSE, EL_ROCK, ACTION_FALLING, -1 }, { Ystone_sB, FALSE, TRUE, EL_ROCK, ACTION_FALLING, -1 }, { Ystone_e, FALSE, FALSE, EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT }, { Ystone_eB, FALSE, TRUE, EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT }, { Ystone_w, FALSE, FALSE, EL_ROCK, ACTION_MOVING, MV_BIT_LEFT }, { Ystone_wB, FALSE, TRUE, EL_ROCK, ACTION_MOVING, MV_BIT_LEFT }, { Xnut, TRUE, FALSE, EL_NUT, -1, -1 }, { Xnut_pause, FALSE, FALSE, EL_NUT, -1, -1 }, { Xnut_fall, FALSE, FALSE, EL_NUT, -1, -1 }, { Ynut_s, FALSE, FALSE, EL_NUT, ACTION_FALLING, -1 }, { Ynut_sB, FALSE, TRUE, EL_NUT, ACTION_FALLING, -1 }, { Ynut_e, FALSE, FALSE, EL_NUT, ACTION_MOVING, MV_BIT_RIGHT }, { Ynut_eB, FALSE, TRUE, EL_NUT, ACTION_MOVING, MV_BIT_RIGHT }, { Ynut_w, FALSE, FALSE, EL_NUT, ACTION_MOVING, MV_BIT_LEFT }, { Ynut_wB, FALSE, TRUE, EL_NUT, ACTION_MOVING, MV_BIT_LEFT }, { Xbug_n, TRUE, FALSE, EL_BUG_UP, -1, -1 }, { Xbug_e, TRUE, FALSE, EL_BUG_RIGHT, -1, -1 }, { Xbug_s, TRUE, FALSE, EL_BUG_DOWN, -1, -1 }, { Xbug_w, TRUE, FALSE, EL_BUG_LEFT, -1, -1 }, { Xbug_gon, FALSE, FALSE, EL_BUG_UP, -1, -1 }, { Xbug_goe, FALSE, FALSE, EL_BUG_RIGHT, -1, -1 }, { Xbug_gos, FALSE, FALSE, EL_BUG_DOWN, -1, -1 }, { Xbug_gow, FALSE, FALSE, EL_BUG_LEFT, -1, -1 }, { Ybug_n, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_UP }, { Ybug_nB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_UP }, { Ybug_e, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_RIGHT }, { Ybug_eB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_RIGHT }, { Ybug_s, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_DOWN }, { Ybug_sB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_DOWN }, { Ybug_w, FALSE, FALSE, EL_BUG, ACTION_MOVING, MV_BIT_LEFT }, { Ybug_wB, FALSE, TRUE, EL_BUG, ACTION_MOVING, MV_BIT_LEFT }, { Ybug_w_n, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP }, { Ybug_n_e, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT }, { Ybug_e_s, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN }, { Ybug_s_w, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT }, { Ybug_e_n, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP }, { Ybug_s_e, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT }, { Ybug_w_s, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN }, { Ybug_n_w, FALSE, FALSE, EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT }, { Ybug_stone, FALSE, FALSE, EL_BUG, ACTION_SMASHED_BY_ROCK, -1 }, { Ybug_spring, FALSE, FALSE, EL_BUG, ACTION_SMASHED_BY_SPRING, -1 }, { Xtank_n, TRUE, FALSE, EL_SPACESHIP_UP, -1, -1 }, { Xtank_e, TRUE, FALSE, EL_SPACESHIP_RIGHT, -1, -1 }, { Xtank_s, TRUE, FALSE, EL_SPACESHIP_DOWN, -1, -1 }, { Xtank_w, TRUE, FALSE, EL_SPACESHIP_LEFT, -1, -1 }, { Xtank_gon, FALSE, FALSE, EL_SPACESHIP_UP, -1, -1 }, { Xtank_goe, FALSE, FALSE, EL_SPACESHIP_RIGHT, -1, -1 }, { Xtank_gos, FALSE, FALSE, EL_SPACESHIP_DOWN, -1, -1 }, { Xtank_gow, FALSE, FALSE, EL_SPACESHIP_LEFT, -1, -1 }, { Ytank_n, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP }, { Ytank_nB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP }, { Ytank_e, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT }, { Ytank_eB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT }, { Ytank_s, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN }, { Ytank_sB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN }, { Ytank_w, FALSE, FALSE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT }, { Ytank_wB, FALSE, TRUE, EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT }, { Ytank_w_n, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP }, { Ytank_n_e, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT }, { Ytank_e_s, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN }, { Ytank_s_w, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT }, { Ytank_e_n, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP }, { Ytank_s_e, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT }, { Ytank_w_s, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN }, { Ytank_n_w, FALSE, FALSE, EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT }, { Ytank_stone, FALSE, FALSE, EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1 }, { Ytank_spring, FALSE, FALSE, EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1 }, { Xandroid, TRUE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, -1 }, { Xandroid_1_n, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP }, { Xandroid_2_n, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP }, { Xandroid_1_e, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT }, { Xandroid_2_e, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT }, { Xandroid_1_w, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT }, { Xandroid_2_w, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT }, { Xandroid_1_s, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN }, { Xandroid_2_s, FALSE, FALSE, EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN }, { Yandroid_n, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP }, { Yandroid_nB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP }, { Yandroid_ne, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT }, { Yandroid_neB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT }, { Yandroid_e, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT }, { Yandroid_eB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT }, { Yandroid_se, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT }, { Yandroid_seB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT }, { Yandroid_s, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN }, { Yandroid_sB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN }, { Yandroid_sw, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT }, { Yandroid_swB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT }, { Yandroid_w, FALSE, FALSE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT }, { Yandroid_wB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT }, { Yandroid_nw, FALSE, FALSE, EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT }, { Yandroid_nwB, FALSE, TRUE, EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT }, { Xspring, TRUE, FALSE, EL_SPRING, -1, -1 }, { Xspring_pause, FALSE, FALSE, EL_SPRING, -1, -1 }, { Xspring_e, FALSE, FALSE, EL_SPRING, -1, -1 }, { Xspring_w, FALSE, FALSE, EL_SPRING, -1, -1 }, { Xspring_fall, FALSE, FALSE, EL_SPRING, -1, -1 }, { Yspring_s, FALSE, FALSE, EL_SPRING, ACTION_FALLING, -1 }, { Yspring_sB, FALSE, TRUE, EL_SPRING, ACTION_FALLING, -1 }, { Yspring_e, FALSE, FALSE, EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT }, { Yspring_eB, FALSE, TRUE, EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT }, { Yspring_w, FALSE, FALSE, EL_SPRING, ACTION_MOVING, MV_BIT_LEFT }, { Yspring_wB, FALSE, TRUE, EL_SPRING, ACTION_MOVING, MV_BIT_LEFT }, { Yspring_kill_e, FALSE, FALSE, EL_SPRING, ACTION_EATING, MV_BIT_RIGHT }, { Yspring_kill_eB, FALSE, TRUE, EL_SPRING, ACTION_EATING, MV_BIT_RIGHT }, { Yspring_kill_w, FALSE, FALSE, EL_SPRING, ACTION_EATING, MV_BIT_LEFT }, { Yspring_kill_wB, FALSE, TRUE, EL_SPRING, ACTION_EATING, MV_BIT_LEFT }, { Xeater_n, TRUE, FALSE, EL_YAMYAM_UP, -1, -1 }, { Xeater_e, TRUE, FALSE, EL_YAMYAM_RIGHT, -1, -1 }, { Xeater_w, TRUE, FALSE, EL_YAMYAM_LEFT, -1, -1 }, { Xeater_s, TRUE, FALSE, EL_YAMYAM_DOWN, -1, -1 }, { Yeater_n, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_UP }, { Yeater_nB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_UP }, { Yeater_e, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT }, { Yeater_eB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT }, { Yeater_s, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN }, { Yeater_sB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN }, { Yeater_w, FALSE, FALSE, EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT }, { Yeater_wB, FALSE, TRUE, EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT }, { Yeater_stone, FALSE, FALSE, EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1 }, { Yeater_spring, FALSE, FALSE, EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1 }, { Xalien, TRUE, FALSE, EL_ROBOT, -1, -1 }, { Xalien_pause, FALSE, FALSE, EL_ROBOT, -1, -1 }, { Yalien_n, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_UP }, { Yalien_nB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_UP }, { Yalien_e, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT }, { Yalien_eB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT }, { Yalien_s, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN }, { Yalien_sB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN }, { Yalien_w, FALSE, FALSE, EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT }, { Yalien_wB, FALSE, TRUE, EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT }, { Yalien_stone, FALSE, FALSE, EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1 }, { Yalien_spring, FALSE, FALSE, EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1 }, { Xemerald, TRUE, FALSE, EL_EMERALD, -1, -1 }, { Xemerald_pause, FALSE, FALSE, EL_EMERALD, -1, -1 }, { Xemerald_fall, FALSE, FALSE, EL_EMERALD, -1, -1 }, { Xemerald_shine, FALSE, FALSE, EL_EMERALD, ACTION_TWINKLING, -1 }, { Yemerald_s, FALSE, FALSE, EL_EMERALD, ACTION_FALLING, -1 }, { Yemerald_sB, FALSE, TRUE, EL_EMERALD, ACTION_FALLING, -1 }, { Yemerald_e, FALSE, FALSE, EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT }, { Yemerald_eB, FALSE, TRUE, EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT }, { Yemerald_w, FALSE, FALSE, EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT }, { Yemerald_wB, FALSE, TRUE, EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT }, { Yemerald_eat, FALSE, FALSE, EL_EMERALD, ACTION_COLLECTING, -1 }, { Yemerald_stone, FALSE, FALSE, EL_NUT, ACTION_BREAKING, -1 }, { Xdiamond, TRUE, FALSE, EL_DIAMOND, -1, -1 }, { Xdiamond_pause, FALSE, FALSE, EL_DIAMOND, -1, -1 }, { Xdiamond_fall, FALSE, FALSE, EL_DIAMOND, -1, -1 }, { Xdiamond_shine, FALSE, FALSE, EL_DIAMOND, ACTION_TWINKLING, -1 }, { Ydiamond_s, FALSE, FALSE, EL_DIAMOND, ACTION_FALLING, -1 }, { Ydiamond_sB, FALSE, TRUE, EL_DIAMOND, ACTION_FALLING, -1 }, { Ydiamond_e, FALSE, FALSE, EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT }, { Ydiamond_eB, FALSE, TRUE, EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT }, { Ydiamond_w, FALSE, FALSE, EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT }, { Ydiamond_wB, FALSE, TRUE, EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT }, { Ydiamond_eat, FALSE, FALSE, EL_DIAMOND, ACTION_COLLECTING, -1 }, { Ydiamond_stone, FALSE, FALSE, EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1 }, { Xdrip_fall, TRUE, FALSE, EL_AMOEBA_DROP, -1, -1 }, { Xdrip_stretch, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Xdrip_stretchB, FALSE, TRUE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Xdrip_eat, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_GROWING, -1 }, { Ydrip_s1, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Ydrip_s1B, FALSE, TRUE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Ydrip_s2, FALSE, FALSE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Ydrip_s2B, FALSE, TRUE, EL_AMOEBA_DROP, ACTION_FALLING, -1 }, { Xbomb, TRUE, FALSE, EL_BOMB, -1, -1 }, { Xbomb_pause, FALSE, FALSE, EL_BOMB, -1, -1 }, { Xbomb_fall, FALSE, FALSE, EL_BOMB, -1, -1 }, { Ybomb_s, FALSE, FALSE, EL_BOMB, ACTION_FALLING, -1 }, { Ybomb_sB, FALSE, TRUE, EL_BOMB, ACTION_FALLING, -1 }, { Ybomb_e, FALSE, FALSE, EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT }, { Ybomb_eB, FALSE, TRUE, EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT }, { Ybomb_w, FALSE, FALSE, EL_BOMB, ACTION_MOVING, MV_BIT_LEFT }, { Ybomb_wB, FALSE, TRUE, EL_BOMB, ACTION_MOVING, MV_BIT_LEFT }, { Ybomb_eat, FALSE, FALSE, EL_BOMB, ACTION_ACTIVATING, -1 }, { Xballoon, TRUE, FALSE, EL_BALLOON, -1, -1 }, { Yballoon_n, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_UP }, { Yballoon_nB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_UP }, { Yballoon_e, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT }, { Yballoon_eB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT }, { Yballoon_s, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN }, { Yballoon_sB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN }, { Yballoon_w, FALSE, FALSE, EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT }, { Yballoon_wB, FALSE, TRUE, EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT }, { Xgrass, TRUE, FALSE, EL_EMC_GRASS, -1, -1 }, { Ygrass_nB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP }, { Ygrass_eB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT }, { Ygrass_sB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN }, { Ygrass_wB, FALSE, FALSE, EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT }, { Xdirt, TRUE, FALSE, EL_SAND, -1, -1 }, { Ydirt_nB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_UP }, { Ydirt_eB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT }, { Ydirt_sB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_DOWN }, { Ydirt_wB, FALSE, FALSE, EL_SAND, ACTION_DIGGING, MV_BIT_LEFT }, { Xacid_ne, TRUE, FALSE, EL_ACID_POOL_TOPRIGHT, -1, -1 }, { Xacid_se, TRUE, FALSE, EL_ACID_POOL_BOTTOMRIGHT, -1, -1 }, { Xacid_s, TRUE, FALSE, EL_ACID_POOL_BOTTOM, -1, -1 }, { Xacid_sw, TRUE, FALSE, EL_ACID_POOL_BOTTOMLEFT, -1, -1 }, { Xacid_nw, TRUE, FALSE, EL_ACID_POOL_TOPLEFT, -1, -1 }, { Xacid_1, TRUE, FALSE, EL_ACID, -1, -1 }, { Xacid_2, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_3, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_4, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_5, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_6, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_7, FALSE, FALSE, EL_ACID, -1, -1 }, { Xacid_8, FALSE, FALSE, EL_ACID, -1, -1 }, { Xball_1, TRUE, FALSE, EL_EMC_MAGIC_BALL, -1, -1 }, { Xball_1B, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1 }, { Xball_2, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1 }, { Xball_2B, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1 }, { Yball_eat, FALSE, FALSE, EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1 }, { Ykey_1_eat, FALSE, FALSE, EL_EM_KEY_1, ACTION_COLLECTING, -1 }, { Ykey_2_eat, FALSE, FALSE, EL_EM_KEY_2, ACTION_COLLECTING, -1 }, { Ykey_3_eat, FALSE, FALSE, EL_EM_KEY_3, ACTION_COLLECTING, -1 }, { Ykey_4_eat, FALSE, FALSE, EL_EM_KEY_4, ACTION_COLLECTING, -1 }, { Ykey_5_eat, FALSE, FALSE, EL_EMC_KEY_5, ACTION_COLLECTING, -1 }, { Ykey_6_eat, FALSE, FALSE, EL_EMC_KEY_6, ACTION_COLLECTING, -1 }, { Ykey_7_eat, FALSE, FALSE, EL_EMC_KEY_7, ACTION_COLLECTING, -1 }, { Ykey_8_eat, FALSE, FALSE, EL_EMC_KEY_8, ACTION_COLLECTING, -1 }, { Ylenses_eat, FALSE, FALSE, EL_EMC_LENSES, ACTION_COLLECTING, -1 }, { Ymagnify_eat, FALSE, FALSE, EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1 }, { Ygrass_eat, FALSE, FALSE, EL_EMC_GRASS, ACTION_SNAPPING, -1 }, { Ydirt_eat, FALSE, FALSE, EL_SAND, ACTION_SNAPPING, -1 }, { Xgrow_ns, TRUE, FALSE, EL_EXPANDABLE_WALL_VERTICAL, -1, -1 }, { Ygrow_ns_eat, FALSE, FALSE, EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1 }, { Xgrow_ew, TRUE, FALSE, EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1 }, { Ygrow_ew_eat, FALSE, FALSE, EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1 }, { Xwonderwall, TRUE, FALSE, EL_MAGIC_WALL, -1, -1 }, { XwonderwallB, FALSE, FALSE, EL_MAGIC_WALL, ACTION_ACTIVE, -1 }, { Xamoeba_1, TRUE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_2, FALSE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_3, FALSE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_4, FALSE, FALSE, EL_AMOEBA_DRY, ACTION_OTHER, -1 }, { Xamoeba_5, TRUE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xamoeba_6, FALSE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xamoeba_7, FALSE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xamoeba_8, FALSE, FALSE, EL_AMOEBA_WET, ACTION_OTHER, -1 }, { Xdoor_1, TRUE, FALSE, EL_EM_GATE_1, -1, -1 }, { Xdoor_2, TRUE, FALSE, EL_EM_GATE_2, -1, -1 }, { Xdoor_3, TRUE, FALSE, EL_EM_GATE_3, -1, -1 }, { Xdoor_4, TRUE, FALSE, EL_EM_GATE_4, -1, -1 }, { Xdoor_5, TRUE, FALSE, EL_EMC_GATE_5, -1, -1 }, { Xdoor_6, TRUE, FALSE, EL_EMC_GATE_6, -1, -1 }, { Xdoor_7, TRUE, FALSE, EL_EMC_GATE_7, -1, -1 }, { Xdoor_8, TRUE, FALSE, EL_EMC_GATE_8, -1, -1 }, { Xkey_1, TRUE, FALSE, EL_EM_KEY_1, -1, -1 }, { Xkey_2, TRUE, FALSE, EL_EM_KEY_2, -1, -1 }, { Xkey_3, TRUE, FALSE, EL_EM_KEY_3, -1, -1 }, { Xkey_4, TRUE, FALSE, EL_EM_KEY_4, -1, -1 }, { Xkey_5, TRUE, FALSE, EL_EMC_KEY_5, -1, -1 }, { Xkey_6, TRUE, FALSE, EL_EMC_KEY_6, -1, -1 }, { Xkey_7, TRUE, FALSE, EL_EMC_KEY_7, -1, -1 }, { Xkey_8, TRUE, FALSE, EL_EMC_KEY_8, -1, -1 }, { Xwind_n, TRUE, FALSE, EL_BALLOON_SWITCH_UP, -1, -1 }, { Xwind_e, TRUE, FALSE, EL_BALLOON_SWITCH_RIGHT, -1, -1 }, { Xwind_s, TRUE, FALSE, EL_BALLOON_SWITCH_DOWN, -1, -1 }, { Xwind_w, TRUE, FALSE, EL_BALLOON_SWITCH_LEFT, -1, -1 }, { Xwind_nesw, TRUE, FALSE, EL_BALLOON_SWITCH_ANY, -1, -1 }, { Xwind_stop, TRUE, FALSE, EL_BALLOON_SWITCH_NONE, -1, -1 }, { Xexit, TRUE, FALSE, EL_EM_EXIT_CLOSED, -1, -1 }, { Xexit_1, TRUE, FALSE, EL_EM_EXIT_OPEN, -1, -1 }, { Xexit_2, FALSE, FALSE, EL_EM_EXIT_OPEN, -1, -1 }, { Xexit_3, FALSE, FALSE, EL_EM_EXIT_OPEN, -1, -1 }, { Xdynamite, TRUE, FALSE, EL_EM_DYNAMITE, -1, -1 }, { Ydynamite_eat, FALSE, FALSE, EL_EM_DYNAMITE, ACTION_COLLECTING, -1 }, { Xdynamite_1, TRUE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xdynamite_2, FALSE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xdynamite_3, FALSE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xdynamite_4, FALSE, FALSE, EL_EM_DYNAMITE_ACTIVE, -1, -1 }, { Xbumper, TRUE, FALSE, EL_EMC_SPRING_BUMPER, -1, -1 }, { XbumperB, FALSE, FALSE, EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1 }, { Xwheel, TRUE, FALSE, EL_ROBOT_WHEEL, -1, -1 }, { XwheelB, FALSE, FALSE, EL_ROBOT_WHEEL, ACTION_ACTIVE, -1 }, { Xswitch, TRUE, FALSE, EL_EMC_MAGIC_BALL_SWITCH, -1, -1 }, { XswitchB, FALSE, FALSE, EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1 }, { Xsand, TRUE, FALSE, EL_QUICKSAND_EMPTY, -1, -1 }, { Xsand_stone, TRUE, FALSE, EL_QUICKSAND_FULL, -1, -1 }, { Xsand_stonein_1, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonein_2, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonein_3, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonein_4, FALSE, TRUE, EL_ROCK, ACTION_FILLING, -1 }, { Xsand_stonesand_1, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_2, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_3, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_4, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_quickout_1, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stonesand_quickout_2, FALSE, FALSE, EL_QUICKSAND_EMPTYING, -1, -1 }, { Xsand_stoneout_1, FALSE, FALSE, EL_ROCK, ACTION_EMPTYING, -1 }, { Xsand_stoneout_2, FALSE, FALSE, EL_ROCK, ACTION_EMPTYING, -1 }, { Xsand_sandstone_1, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xsand_sandstone_2, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xsand_sandstone_3, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xsand_sandstone_4, FALSE, FALSE, EL_QUICKSAND_FILLING, -1, -1 }, { Xplant, TRUE, FALSE, EL_EMC_PLANT, -1, -1 }, { Yplant, FALSE, FALSE, EL_EMC_PLANT, -1, -1 }, { Xlenses, TRUE, FALSE, EL_EMC_LENSES, -1, -1 }, { Xmagnify, TRUE, FALSE, EL_EMC_MAGNIFIER, -1, -1 }, { Xdripper, TRUE, FALSE, EL_EMC_DRIPPER, -1, -1 }, { XdripperB, FALSE, FALSE, EL_EMC_DRIPPER, ACTION_ACTIVE, -1 }, { Xfake_blank, TRUE, FALSE, EL_INVISIBLE_WALL, -1, -1 }, { Xfake_blankB, FALSE, FALSE, EL_INVISIBLE_WALL, ACTION_ACTIVE, -1 }, { Xfake_grass, TRUE, FALSE, EL_EMC_FAKE_GRASS, -1, -1 }, { Xfake_grassB, FALSE, FALSE, EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1 }, { Xfake_door_1, TRUE, FALSE, EL_EM_GATE_1_GRAY, -1, -1 }, { Xfake_door_2, TRUE, FALSE, EL_EM_GATE_2_GRAY, -1, -1 }, { Xfake_door_3, TRUE, FALSE, EL_EM_GATE_3_GRAY, -1, -1 }, { Xfake_door_4, TRUE, FALSE, EL_EM_GATE_4_GRAY, -1, -1 }, { Xfake_door_5, TRUE, FALSE, EL_EMC_GATE_5_GRAY, -1, -1 }, { Xfake_door_6, TRUE, FALSE, EL_EMC_GATE_6_GRAY, -1, -1 }, { Xfake_door_7, TRUE, FALSE, EL_EMC_GATE_7_GRAY, -1, -1 }, { Xfake_door_8, TRUE, FALSE, EL_EMC_GATE_8_GRAY, -1, -1 }, { Xfake_acid_1, TRUE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_2, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_3, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_4, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_5, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_6, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_7, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xfake_acid_8, FALSE, FALSE, EL_EMC_FAKE_ACID, -1, -1 }, { Xsteel_1, TRUE, FALSE, EL_STEELWALL, -1, -1 }, { Xsteel_2, TRUE, FALSE, EL_EMC_STEELWALL_2, -1, -1 }, { Xsteel_3, TRUE, FALSE, EL_EMC_STEELWALL_3, -1, -1 }, { Xsteel_4, TRUE, FALSE, EL_EMC_STEELWALL_4, -1, -1 }, { Xwall_1, TRUE, FALSE, EL_WALL, -1, -1 }, { Xwall_2, TRUE, FALSE, EL_EMC_WALL_14, -1, -1 }, { Xwall_3, TRUE, FALSE, EL_EMC_WALL_15, -1, -1 }, { Xwall_4, TRUE, FALSE, EL_EMC_WALL_16, -1, -1 }, { Xround_wall_1, TRUE, FALSE, EL_WALL_SLIPPERY, -1, -1 }, { Xround_wall_2, TRUE, FALSE, EL_EMC_WALL_SLIPPERY_2, -1, -1 }, { Xround_wall_3, TRUE, FALSE, EL_EMC_WALL_SLIPPERY_3, -1, -1 }, { Xround_wall_4, TRUE, FALSE, EL_EMC_WALL_SLIPPERY_4, -1, -1 }, { Xdecor_1, TRUE, FALSE, EL_EMC_WALL_8, -1, -1 }, { Xdecor_2, TRUE, FALSE, EL_EMC_WALL_6, -1, -1 }, { Xdecor_3, TRUE, FALSE, EL_EMC_WALL_4, -1, -1 }, { Xdecor_4, TRUE, FALSE, EL_EMC_WALL_7, -1, -1 }, { Xdecor_5, TRUE, FALSE, EL_EMC_WALL_5, -1, -1 }, { Xdecor_6, TRUE, FALSE, EL_EMC_WALL_9, -1, -1 }, { Xdecor_7, TRUE, FALSE, EL_EMC_WALL_10, -1, -1 }, { Xdecor_8, TRUE, FALSE, EL_EMC_WALL_1, -1, -1 }, { Xdecor_9, TRUE, FALSE, EL_EMC_WALL_2, -1, -1 }, { Xdecor_10, TRUE, FALSE, EL_EMC_WALL_3, -1, -1 }, { Xdecor_11, TRUE, FALSE, EL_EMC_WALL_11, -1, -1 }, { Xdecor_12, TRUE, FALSE, EL_EMC_WALL_12, -1, -1 }, { Xalpha_0, TRUE, FALSE, EL_CHAR('0'), -1, -1 }, { Xalpha_1, TRUE, FALSE, EL_CHAR('1'), -1, -1 }, { Xalpha_2, TRUE, FALSE, EL_CHAR('2'), -1, -1 }, { Xalpha_3, TRUE, FALSE, EL_CHAR('3'), -1, -1 }, { Xalpha_4, TRUE, FALSE, EL_CHAR('4'), -1, -1 }, { Xalpha_5, TRUE, FALSE, EL_CHAR('5'), -1, -1 }, { Xalpha_6, TRUE, FALSE, EL_CHAR('6'), -1, -1 }, { Xalpha_7, TRUE, FALSE, EL_CHAR('7'), -1, -1 }, { Xalpha_8, TRUE, FALSE, EL_CHAR('8'), -1, -1 }, { Xalpha_9, TRUE, FALSE, EL_CHAR('9'), -1, -1 }, { Xalpha_excla, TRUE, FALSE, EL_CHAR('!'), -1, -1 }, { Xalpha_quote, TRUE, FALSE, EL_CHAR('"'), -1, -1 }, { Xalpha_comma, TRUE, FALSE, EL_CHAR(','), -1, -1 }, { Xalpha_minus, TRUE, FALSE, EL_CHAR('-'), -1, -1 }, { Xalpha_perio, TRUE, FALSE, EL_CHAR('.'), -1, -1 }, { Xalpha_colon, TRUE, FALSE, EL_CHAR(':'), -1, -1 }, { Xalpha_quest, TRUE, FALSE, EL_CHAR('?'), -1, -1 }, { Xalpha_a, TRUE, FALSE, EL_CHAR('A'), -1, -1 }, { Xalpha_b, TRUE, FALSE, EL_CHAR('B'), -1, -1 }, { Xalpha_c, TRUE, FALSE, EL_CHAR('C'), -1, -1 }, { Xalpha_d, TRUE, FALSE, EL_CHAR('D'), -1, -1 }, { Xalpha_e, TRUE, FALSE, EL_CHAR('E'), -1, -1 }, { Xalpha_f, TRUE, FALSE, EL_CHAR('F'), -1, -1 }, { Xalpha_g, TRUE, FALSE, EL_CHAR('G'), -1, -1 }, { Xalpha_h, TRUE, FALSE, EL_CHAR('H'), -1, -1 }, { Xalpha_i, TRUE, FALSE, EL_CHAR('I'), -1, -1 }, { Xalpha_j, TRUE, FALSE, EL_CHAR('J'), -1, -1 }, { Xalpha_k, TRUE, FALSE, EL_CHAR('K'), -1, -1 }, { Xalpha_l, TRUE, FALSE, EL_CHAR('L'), -1, -1 }, { Xalpha_m, TRUE, FALSE, EL_CHAR('M'), -1, -1 }, { Xalpha_n, TRUE, FALSE, EL_CHAR('N'), -1, -1 }, { Xalpha_o, TRUE, FALSE, EL_CHAR('O'), -1, -1 }, { Xalpha_p, TRUE, FALSE, EL_CHAR('P'), -1, -1 }, { Xalpha_q, TRUE, FALSE, EL_CHAR('Q'), -1, -1 }, { Xalpha_r, TRUE, FALSE, EL_CHAR('R'), -1, -1 }, { Xalpha_s, TRUE, FALSE, EL_CHAR('S'), -1, -1 }, { Xalpha_t, TRUE, FALSE, EL_CHAR('T'), -1, -1 }, { Xalpha_u, TRUE, FALSE, EL_CHAR('U'), -1, -1 }, { Xalpha_v, TRUE, FALSE, EL_CHAR('V'), -1, -1 }, { Xalpha_w, TRUE, FALSE, EL_CHAR('W'), -1, -1 }, { Xalpha_x, TRUE, FALSE, EL_CHAR('X'), -1, -1 }, { Xalpha_y, TRUE, FALSE, EL_CHAR('Y'), -1, -1 }, { Xalpha_z, TRUE, FALSE, EL_CHAR('Z'), -1, -1 }, { Xalpha_arrow_e, TRUE, FALSE, EL_CHAR('>'), -1, -1 }, { Xalpha_arrow_w, TRUE, FALSE, EL_CHAR('<'), -1, -1 }, { Xalpha_copyr, TRUE, FALSE, EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1 }, { Xboom_bug, FALSE, FALSE, EL_BUG, ACTION_EXPLODING, -1 }, { Xboom_bomb, FALSE, FALSE, EL_BOMB, ACTION_EXPLODING, -1 }, { Xboom_android, FALSE, FALSE, EL_EMC_ANDROID, ACTION_OTHER, -1 }, { Xboom_1, FALSE, FALSE, EL_DEFAULT, ACTION_EXPLODING, -1 }, { Xboom_2, FALSE, FALSE, EL_DEFAULT, ACTION_EXPLODING, -1 }, { Znormal, FALSE, FALSE, EL_EMPTY, -1, -1 }, { Zdynamite, FALSE, FALSE, EL_EMPTY, -1, -1 }, { Zplayer, FALSE, FALSE, EL_EMPTY, -1, -1 }, { ZBORDER, FALSE, FALSE, EL_EMPTY, -1, -1 }, { -1, FALSE, FALSE, -1, -1, -1 } }; static struct Mapping_EM_to_RND_player { int action_em; int player_nr; int element_rnd; int action; int direction; } em_player_mapping_list[] = { { SPR_walk + 0, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 0, EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 0, EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 0, EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_walk + 0, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 1, EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 1, EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 1, EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_still, 0, EL_PLAYER_1, ACTION_DEFAULT, -1, }, { SPR_still, 1, EL_PLAYER_2, ACTION_DEFAULT, -1, }, { SPR_walk + 0, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 2, EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 2, EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 2, EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_walk + 0, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP, }, { SPR_walk + 1, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT, }, { SPR_walk + 2, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN, }, { SPR_walk + 3, 3, EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT, }, { SPR_push + 0, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP, }, { SPR_push + 1, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT, }, { SPR_push + 2, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN, }, { SPR_push + 3, 3, EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT, }, { SPR_spray + 0, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP, }, { SPR_spray + 1, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT, }, { SPR_spray + 2, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN, }, { SPR_spray + 3, 3, EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT, }, { SPR_still, 2, EL_PLAYER_3, ACTION_DEFAULT, -1, }, { SPR_still, 3, EL_PLAYER_4, ACTION_DEFAULT, -1, }, { -1, -1, -1, -1, -1 } }; int map_element_RND_to_EM(int element_rnd) { static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS]; static boolean mapping_initialized = FALSE; if (!mapping_initialized) { int i; /* return "Xalpha_quest" for all undefined elements in mapping array */ for (i = 0; i < NUM_FILE_ELEMENTS; i++) mapping_RND_to_EM[i] = Xalpha_quest; for (i = 0; em_object_mapping_list[i].element_em != -1; i++) if (em_object_mapping_list[i].is_rnd_to_em_mapping) mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] = em_object_mapping_list[i].element_em; mapping_initialized = TRUE; } if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS) return mapping_RND_to_EM[element_rnd]; Error(ERR_WARN, "invalid RND level element %d", element_rnd); return EL_UNKNOWN; } int map_element_EM_to_RND(int element_em) { static unsigned short mapping_EM_to_RND[TILE_MAX]; static boolean mapping_initialized = FALSE; if (!mapping_initialized) { int i; /* return "EL_UNKNOWN" for all undefined elements in mapping array */ for (i = 0; i < TILE_MAX; i++) mapping_EM_to_RND[i] = EL_UNKNOWN; for (i = 0; em_object_mapping_list[i].element_em != -1; i++) mapping_EM_to_RND[em_object_mapping_list[i].element_em] = em_object_mapping_list[i].element_rnd; mapping_initialized = TRUE; } if (element_em >= 0 && element_em < TILE_MAX) return mapping_EM_to_RND[element_em]; Error(ERR_WARN, "invalid EM level element %d", element_em); return EL_UNKNOWN; } void map_android_clone_elements_RND_to_EM(struct LevelInfo *level) { struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; int i, j; for (i = 0; i < TILE_MAX; i++) lev->android_array[i] = Xblank; for (i = 0; i < level->num_android_clone_elements; i++) { int element_rnd = level->android_clone_element[i]; int element_em = map_element_RND_to_EM(element_rnd); for (j = 0; em_object_mapping_list[j].element_em != -1; j++) if (em_object_mapping_list[j].element_rnd == element_rnd) lev->android_array[em_object_mapping_list[j].element_em] = element_em; } } void map_android_clone_elements_EM_to_RND(struct LevelInfo *level) { struct LevelInfo_EM *level_em = level->native_em_level; struct LEVEL *lev = level_em->lev; int i, j; level->num_android_clone_elements = 0; for (i = 0; i < TILE_MAX; i++) { int element_em = lev->android_array[i]; int element_rnd; boolean element_found = FALSE; if (element_em == Xblank) continue; element_rnd = map_element_EM_to_RND(element_em); for (j = 0; j < level->num_android_clone_elements; j++) if (level->android_clone_element[j] == element_rnd) element_found = TRUE; if (!element_found) { level->android_clone_element[level->num_android_clone_elements++] = element_rnd; if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS) break; } } if (level->num_android_clone_elements == 0) { level->num_android_clone_elements = 1; level->android_clone_element[0] = EL_EMPTY; } } int map_direction_RND_to_EM(int direction) { return (direction == MV_UP ? 0 : direction == MV_RIGHT ? 1 : direction == MV_DOWN ? 2 : direction == MV_LEFT ? 3 : -1); } int map_direction_EM_to_RND(int direction) { return (direction == 0 ? MV_UP : direction == 1 ? MV_RIGHT : direction == 2 ? MV_DOWN : direction == 3 ? MV_LEFT : MV_NONE); } int map_element_RND_to_SP(int element_rnd) { int element_sp = 0x20; /* map unknown elements to yellow "hardware" */ if (element_rnd >= EL_SP_START && element_rnd <= EL_SP_END) element_sp = element_rnd - EL_SP_START; else if (element_rnd == EL_EMPTY_SPACE) element_sp = 0x00; else if (element_rnd == EL_INVISIBLE_WALL) element_sp = 0x28; return element_sp; } int map_element_SP_to_RND(int element_sp) { int element_rnd = EL_UNKNOWN; if (element_sp >= 0x00 && element_sp <= 0x27) element_rnd = EL_SP_START + element_sp; else if (element_sp == 0x28) element_rnd = EL_INVISIBLE_WALL; return element_rnd; } int map_action_SP_to_RND(int action_sp) { switch (action_sp) { case actActive: return ACTION_ACTIVE; case actImpact: return ACTION_IMPACT; case actExploding: return ACTION_EXPLODING; case actDigging: return ACTION_DIGGING; case actSnapping: return ACTION_SNAPPING; case actCollecting: return ACTION_COLLECTING; case actPassing: return ACTION_PASSING; case actPushing: return ACTION_PUSHING; case actDropping: return ACTION_DROPPING; default: return ACTION_DEFAULT; } } int map_element_RND_to_MM(int element_rnd) { return (element_rnd >= EL_MM_START_1 && element_rnd <= EL_MM_END_1 ? EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 : element_rnd >= EL_MM_START_2 && element_rnd <= EL_MM_END_2 ? EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 : element_rnd >= EL_CHAR_START && element_rnd <= EL_CHAR_END ? EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START : element_rnd >= EL_MM_RUNTIME_START && element_rnd <= EL_MM_RUNTIME_END ? EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START : element_rnd >= EL_MM_DUMMY_START && element_rnd <= EL_MM_DUMMY_END ? EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START : EL_MM_EMPTY_NATIVE); } int map_element_MM_to_RND(int element_mm) { return (element_mm == EL_MM_EMPTY_NATIVE || element_mm == EL_DF_EMPTY_NATIVE ? EL_EMPTY : element_mm >= EL_MM_START_1_NATIVE && element_mm <= EL_MM_END_1_NATIVE ? EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE : element_mm >= EL_MM_START_2_NATIVE && element_mm <= EL_MM_END_2_NATIVE ? EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE : element_mm >= EL_MM_CHAR_START_NATIVE && element_mm <= EL_MM_CHAR_END_NATIVE ? EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE : element_mm >= EL_MM_RUNTIME_START_NATIVE && element_mm <= EL_MM_RUNTIME_END_NATIVE ? EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE : element_mm >= EL_MM_DUMMY_START_NATIVE && element_mm <= EL_MM_DUMMY_END_NATIVE ? EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE : EL_EMPTY); } int map_action_MM_to_RND(int action_mm) { /* all MM actions are defined to exactly match their RND counterparts */ return action_mm; } int map_sound_MM_to_RND(int sound_mm) { switch (sound_mm) { case SND_MM_GAME_LEVELTIME_CHARGING: return SND_GAME_LEVELTIME_CHARGING; case SND_MM_GAME_HEALTH_CHARGING: return SND_GAME_HEALTH_CHARGING; default: return SND_UNDEFINED; } } int map_mm_wall_element(int element) { return (element >= EL_MM_STEEL_WALL_START && element <= EL_MM_STEEL_WALL_END ? EL_MM_STEEL_WALL : element >= EL_MM_WOODEN_WALL_START && element <= EL_MM_WOODEN_WALL_END ? EL_MM_WOODEN_WALL : element >= EL_MM_ICE_WALL_START && element <= EL_MM_ICE_WALL_END ? EL_MM_ICE_WALL : element >= EL_MM_AMOEBA_WALL_START && element <= EL_MM_AMOEBA_WALL_END ? EL_MM_AMOEBA_WALL : element >= EL_DF_STEEL_WALL_START && element <= EL_DF_STEEL_WALL_END ? EL_DF_STEEL_WALL : element >= EL_DF_WOODEN_WALL_START && element <= EL_DF_WOODEN_WALL_END ? EL_DF_WOODEN_WALL : element); } int map_mm_wall_element_editor(int element) { switch (element) { case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START; case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START; case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START; case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START; case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START; case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START; default: return element; } } int get_next_element(int element) { switch (element) { case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL; case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY; case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL; case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY; case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL; case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE; case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL; case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE; case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL; case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE; case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET; default: return element; } } int el2img_mm(int element_mm) { return el2img(map_element_MM_to_RND(element_mm)); } int el_act_dir2img(int element, int action, int direction) { element = GFX_ELEMENT(element); direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */ /* direction_graphic[][] == graphic[] for undefined direction graphics */ return element_info[element].direction_graphic[action][direction]; } static int el_act_dir2crm(int element, int action, int direction) { element = GFX_ELEMENT(element); direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */ /* direction_graphic[][] == graphic[] for undefined direction graphics */ return element_info[element].direction_crumbled[action][direction]; } int el_act2img(int element, int action) { element = GFX_ELEMENT(element); return element_info[element].graphic[action]; } int el_act2crm(int element, int action) { element = GFX_ELEMENT(element); return element_info[element].crumbled[action]; } int el_dir2img(int element, int direction) { element = GFX_ELEMENT(element); return el_act_dir2img(element, ACTION_DEFAULT, direction); } int el2baseimg(int element) { return element_info[element].graphic[ACTION_DEFAULT]; } int el2img(int element) { element = GFX_ELEMENT(element); return element_info[element].graphic[ACTION_DEFAULT]; } int el2edimg(int element) { element = GFX_ELEMENT(element); return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR]; } int el2preimg(int element) { element = GFX_ELEMENT(element); return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW]; } int el2panelimg(int element) { element = GFX_ELEMENT(element); return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL]; } int font2baseimg(int font_nr) { return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT]; } int getBeltNrFromBeltElement(int element) { return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 : element < EL_CONVEYOR_BELT_3_LEFT ? 1 : element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3); } int getBeltNrFromBeltActiveElement(int element) { return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 : element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 : element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3); } int getBeltNrFromBeltSwitchElement(int element) { return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 : element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 : element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3); } int getBeltDirNrFromBeltElement(int element) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; int belt_nr = getBeltNrFromBeltElement(element); int belt_dir_nr = element - belt_base_element[belt_nr]; return (belt_dir_nr % 3); } int getBeltDirNrFromBeltSwitchElement(int element) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT }; int belt_nr = getBeltNrFromBeltSwitchElement(element); int belt_dir_nr = element - belt_base_element[belt_nr]; return (belt_dir_nr % 3); } int getBeltDirFromBeltElement(int element) { static int belt_move_dir[3] = { MV_LEFT, MV_NONE, MV_RIGHT }; int belt_dir_nr = getBeltDirNrFromBeltElement(element); return belt_move_dir[belt_dir_nr]; } int getBeltDirFromBeltSwitchElement(int element) { static int belt_move_dir[3] = { MV_LEFT, MV_NONE, MV_RIGHT }; int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element); return belt_move_dir[belt_dir_nr]; } int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_4_LEFT }; return belt_base_element[belt_nr] + belt_dir_nr; } int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir) { int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1); return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr); } int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr) { static int belt_base_element[4] = { EL_CONVEYOR_BELT_1_SWITCH_LEFT, EL_CONVEYOR_BELT_2_SWITCH_LEFT, EL_CONVEYOR_BELT_3_SWITCH_LEFT, EL_CONVEYOR_BELT_4_SWITCH_LEFT }; return belt_base_element[belt_nr] + belt_dir_nr; } int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir) { int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1); return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr); } boolean getTeamMode_EM() { return game.team_mode; } int getGameFrameDelay_EM(int native_em_game_frame_delay) { int game_frame_delay_value; game_frame_delay_value = (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay : GameFrameDelay); if (tape.playing && tape.warp_forward && !tape.pausing) game_frame_delay_value = 0; return game_frame_delay_value; } unsigned int InitRND(int seed) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) return InitEngineRandom_EM(seed); else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) return InitEngineRandom_SP(seed); else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) return InitEngineRandom_MM(seed); else return InitEngineRandom_RND(seed); } static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX]; static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX]; inline static int get_effective_element_EM(int tile, int frame_em) { int element = object_mapping[tile].element_rnd; int action = object_mapping[tile].action; boolean is_backside = object_mapping[tile].is_backside; boolean action_removing = (action == ACTION_DIGGING || action == ACTION_SNAPPING || action == ACTION_COLLECTING); if (frame_em < 7) { switch (tile) { case Yacid_splash_eB: case Yacid_splash_wB: return (frame_em > 5 ? EL_EMPTY : element); default: return element; } } else /* frame_em == 7 */ { switch (tile) { case Yacid_splash_eB: case Yacid_splash_wB: return EL_EMPTY; case Yemerald_stone: return EL_EMERALD; case Ydiamond_stone: return EL_ROCK; case Xdrip_stretch: case Xdrip_stretchB: case Ydrip_s1: case Ydrip_s1B: case Xball_1B: case Xball_2: case Xball_2B: case Yball_eat: case Ykey_1_eat: case Ykey_2_eat: case Ykey_3_eat: case Ykey_4_eat: case Ykey_5_eat: case Ykey_6_eat: case Ykey_7_eat: case Ykey_8_eat: case Ylenses_eat: case Ymagnify_eat: case Ygrass_eat: case Ydirt_eat: case Xsand_stonein_1: case Xsand_stonein_2: case Xsand_stonein_3: case Xsand_stonein_4: return element; default: return (is_backside || action_removing ? EL_EMPTY : element); } } } inline static boolean check_linear_animation_EM(int tile) { switch (tile) { case Xsand_stonesand_1: case Xsand_stonesand_quickout_1: case Xsand_sandstone_1: case Xsand_stonein_1: case Xsand_stoneout_1: case Xboom_1: case Xdynamite_1: case Ybug_w_n: case Ybug_n_e: case Ybug_e_s: case Ybug_s_w: case Ybug_e_n: case Ybug_s_e: case Ybug_w_s: case Ybug_n_w: case Ytank_w_n: case Ytank_n_e: case Ytank_e_s: case Ytank_s_w: case Ytank_e_n: case Ytank_s_e: case Ytank_w_s: case Ytank_n_w: case Yacid_splash_eB: case Yacid_splash_wB: case Yemerald_stone: return TRUE; } return FALSE; } inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em, boolean has_crumbled_graphics, int crumbled, int sync_frame) { /* if element can be crumbled, but certain action graphics are just empty space (like instantly snapping sand to empty space in 1 frame), do not treat these empty space graphics as crumbled graphics in EMC engine */ if (crumbled == IMG_EMPTY_SPACE) has_crumbled_graphics = FALSE; if (has_crumbled_graphics) { struct GraphicInfo *g_crumbled = &graphic_info[crumbled]; int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames, g_crumbled->anim_delay, g_crumbled->anim_mode, g_crumbled->anim_start_frame, sync_frame); getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap, &g_em->crumbled_src_x, &g_em->crumbled_src_y); g_em->crumbled_border_size = graphic_info[crumbled].border_size; g_em->crumbled_tile_size = graphic_info[crumbled].tile_size; g_em->has_crumbled_graphics = TRUE; } else { g_em->crumbled_bitmap = NULL; g_em->crumbled_src_x = 0; g_em->crumbled_src_y = 0; g_em->crumbled_border_size = 0; g_em->crumbled_tile_size = 0; g_em->has_crumbled_graphics = FALSE; } } void ResetGfxAnimation_EM(int x, int y, int tile) { GfxFrame[x][y] = 0; } void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em, int tile, int frame_em, int x, int y) { int action = object_mapping[tile].action; int direction = object_mapping[tile].direction; int effective_element = get_effective_element_EM(tile, frame_em); int graphic = (direction == MV_NONE ? el_act2img(effective_element, action) : el_act_dir2img(effective_element, action, direction)); struct GraphicInfo *g = &graphic_info[graphic]; int sync_frame; boolean action_removing = (action == ACTION_DIGGING || action == ACTION_SNAPPING || action == ACTION_COLLECTING); boolean action_moving = (action == ACTION_FALLING || action == ACTION_MOVING || action == ACTION_PUSHING || action == ACTION_EATING || action == ACTION_FILLING || action == ACTION_EMPTYING); boolean action_falling = (action == ACTION_FALLING || action == ACTION_FILLING || action == ACTION_EMPTYING); /* special case: graphic uses "2nd movement tile" and has defined 7 frames for movement animation (or less) => use default graphic for last (8th) frame which ends the movement animation */ if (g->double_movement && g->anim_frames < 8 && frame_em == 7) { action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */ graphic = (direction == MV_NONE ? el_act2img(effective_element, action) : el_act_dir2img(effective_element, action, direction)); g = &graphic_info[graphic]; } if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0) { GfxFrame[x][y] = 0; } else if (action_moving) { boolean is_backside = object_mapping[tile].is_backside; if (is_backside) { int direction = object_mapping[tile].direction; int move_dir = (action_falling ? MV_DOWN : direction); GfxFrame[x][y]++; #if 1 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */ if (g->double_movement && frame_em == 0) GfxFrame[x][y] = 0; #endif if (move_dir == MV_LEFT) GfxFrame[x - 1][y] = GfxFrame[x][y]; else if (move_dir == MV_RIGHT) GfxFrame[x + 1][y] = GfxFrame[x][y]; else if (move_dir == MV_UP) GfxFrame[x][y - 1] = GfxFrame[x][y]; else if (move_dir == MV_DOWN) GfxFrame[x][y + 1] = GfxFrame[x][y]; } } else { GfxFrame[x][y]++; /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */ if (tile == Xsand_stonesand_quickout_1 || tile == Xsand_stonesand_quickout_2) GfxFrame[x][y]++; } if (graphic_info[graphic].anim_global_sync) sync_frame = FrameCounter; else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY)) sync_frame = GfxFrame[x][y]; else sync_frame = 0; /* playfield border (pseudo steel) */ SetRandomAnimationValue(x, y); int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); g_em->unique_identifier = (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height; } void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em, int tile, int frame_em, int x, int y) { int action = object_mapping[tile].action; int direction = object_mapping[tile].direction; boolean is_backside = object_mapping[tile].is_backside; int effective_element = get_effective_element_EM(tile, frame_em); int effective_action = action; int graphic = (direction == MV_NONE ? el_act2img(effective_element, effective_action) : el_act_dir2img(effective_element, effective_action, direction)); int crumbled = (direction == MV_NONE ? el_act2crm(effective_element, effective_action) : el_act_dir2crm(effective_element, effective_action, direction)); int base_graphic = el_act2img(effective_element, ACTION_DEFAULT); int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT); boolean has_crumbled_graphics = (base_crumbled != base_graphic); struct GraphicInfo *g = &graphic_info[graphic]; int sync_frame; /* special case: graphic uses "2nd movement tile" and has defined 7 frames for movement animation (or less) => use default graphic for last (8th) frame which ends the movement animation */ if (g->double_movement && g->anim_frames < 8 && frame_em == 7) { effective_action = ACTION_DEFAULT; graphic = (direction == MV_NONE ? el_act2img(effective_element, effective_action) : el_act_dir2img(effective_element, effective_action, direction)); crumbled = (direction == MV_NONE ? el_act2crm(effective_element, effective_action) : el_act_dir2crm(effective_element, effective_action, direction)); g = &graphic_info[graphic]; } if (graphic_info[graphic].anim_global_sync) sync_frame = FrameCounter; else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY)) sync_frame = GfxFrame[x][y]; else sync_frame = 0; /* playfield border (pseudo steel) */ SetRandomAnimationValue(x, y); int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y, g->double_movement && is_backside); /* (updating the "crumbled" graphic definitions is probably not really needed, as animations for crumbled graphics can't be longer than one EMC cycle) */ set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled, sync_frame); } void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em, int player_nr, int anim, int frame_em) { int element = player_mapping[player_nr][anim].element_rnd; int action = player_mapping[player_nr][anim].action; int direction = player_mapping[player_nr][anim].direction; int graphic = (direction == MV_NONE ? el_act2img(element, action) : el_act_dir2img(element, action, direction)); struct GraphicInfo *g = &graphic_info[graphic]; int sync_frame; InitPlayerGfxAnimation(&stored_player[player_nr], action, direction); stored_player[player_nr].StepFrame = frame_em; sync_frame = stored_player[player_nr].Frame; int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y, FALSE); } void InitGraphicInfo_EM(void) { int i, j, p; #if DEBUG_EM_GFX int num_em_gfx_errors = 0; if (graphic_info_em_object[0][0].bitmap == NULL) { /* EM graphics not yet initialized in em_open_all() */ return; } printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n"); #endif /* always start with reliable default values */ for (i = 0; i < TILE_MAX; i++) { object_mapping[i].element_rnd = EL_UNKNOWN; object_mapping[i].is_backside = FALSE; object_mapping[i].action = ACTION_DEFAULT; object_mapping[i].direction = MV_NONE; } /* always start with reliable default values */ for (p = 0; p < MAX_PLAYERS; p++) { for (i = 0; i < SPR_MAX; i++) { player_mapping[p][i].element_rnd = EL_UNKNOWN; player_mapping[p][i].action = ACTION_DEFAULT; player_mapping[p][i].direction = MV_NONE; } } for (i = 0; em_object_mapping_list[i].element_em != -1; i++) { int e = em_object_mapping_list[i].element_em; object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd; object_mapping[e].is_backside = em_object_mapping_list[i].is_backside; if (em_object_mapping_list[i].action != -1) object_mapping[e].action = em_object_mapping_list[i].action; if (em_object_mapping_list[i].direction != -1) object_mapping[e].direction = MV_DIR_FROM_BIT(em_object_mapping_list[i].direction); } for (i = 0; em_player_mapping_list[i].action_em != -1; i++) { int a = em_player_mapping_list[i].action_em; int p = em_player_mapping_list[i].player_nr; player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd; if (em_player_mapping_list[i].action != -1) player_mapping[p][a].action = em_player_mapping_list[i].action; if (em_player_mapping_list[i].direction != -1) player_mapping[p][a].direction = MV_DIR_FROM_BIT(em_player_mapping_list[i].direction); } for (i = 0; i < TILE_MAX; i++) { int element = object_mapping[i].element_rnd; int action = object_mapping[i].action; int direction = object_mapping[i].direction; boolean is_backside = object_mapping[i].is_backside; boolean action_exploding = ((action == ACTION_EXPLODING || action == ACTION_SMASHED_BY_ROCK || action == ACTION_SMASHED_BY_SPRING) && element != EL_DIAMOND); boolean action_active = (action == ACTION_ACTIVE); boolean action_other = (action == ACTION_OTHER); for (j = 0; j < 8; j++) { int effective_element = get_effective_element_EM(i, j); int effective_action = (j < 7 ? action : i == Xdrip_stretch ? action : i == Xdrip_stretchB ? action : i == Ydrip_s1 ? action : i == Ydrip_s1B ? action : i == Xball_1B ? action : i == Xball_2 ? action : i == Xball_2B ? action : i == Yball_eat ? action : i == Ykey_1_eat ? action : i == Ykey_2_eat ? action : i == Ykey_3_eat ? action : i == Ykey_4_eat ? action : i == Ykey_5_eat ? action : i == Ykey_6_eat ? action : i == Ykey_7_eat ? action : i == Ykey_8_eat ? action : i == Ylenses_eat ? action : i == Ymagnify_eat ? action : i == Ygrass_eat ? action : i == Ydirt_eat ? action : i == Xsand_stonein_1 ? action : i == Xsand_stonein_2 ? action : i == Xsand_stonein_3 ? action : i == Xsand_stonein_4 ? action : i == Xsand_stoneout_1 ? action : i == Xsand_stoneout_2 ? action : i == Xboom_android ? ACTION_EXPLODING : action_exploding ? ACTION_EXPLODING : action_active ? action : action_other ? action : ACTION_DEFAULT); int graphic = (el_act_dir2img(effective_element, effective_action, direction)); int crumbled = (el_act_dir2crm(effective_element, effective_action, direction)); int base_graphic = el_act2img(effective_element, ACTION_DEFAULT); int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT); boolean has_action_graphics = (graphic != base_graphic); boolean has_crumbled_graphics = (base_crumbled != base_graphic); struct GraphicInfo *g = &graphic_info[graphic]; struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j]; Bitmap *src_bitmap; int src_x, src_y; /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */ boolean special_animation = (action != ACTION_DEFAULT && g->anim_frames == 3 && g->anim_delay == 2 && g->anim_mode & ANIM_LINEAR); int sync_frame = (i == Xdrip_stretch ? 7 : i == Xdrip_stretchB ? 7 : i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xacid_1 ? 0 : i == Xacid_2 ? 10 : i == Xacid_3 ? 20 : i == Xacid_4 ? 30 : i == Xacid_5 ? 40 : i == Xacid_6 ? 50 : i == Xacid_7 ? 60 : i == Xacid_8 ? 70 : i == Xfake_acid_1 ? 0 : i == Xfake_acid_2 ? 10 : i == Xfake_acid_3 ? 20 : i == Xfake_acid_4 ? 30 : i == Xfake_acid_5 ? 40 : i == Xfake_acid_6 ? 50 : i == Xfake_acid_7 ? 60 : i == Xfake_acid_8 ? 70 : i == Xball_2 ? 7 : i == Xball_2B ? j + 8 : i == Yball_eat ? j + 1 : i == Ykey_1_eat ? j + 1 : i == Ykey_2_eat ? j + 1 : i == Ykey_3_eat ? j + 1 : i == Ykey_4_eat ? j + 1 : i == Ykey_5_eat ? j + 1 : i == Ykey_6_eat ? j + 1 : i == Ykey_7_eat ? j + 1 : i == Ykey_8_eat ? j + 1 : i == Ylenses_eat ? j + 1 : i == Ymagnify_eat ? j + 1 : i == Ygrass_eat ? j + 1 : i == Ydirt_eat ? j + 1 : i == Xamoeba_1 ? 0 : i == Xamoeba_2 ? 1 : i == Xamoeba_3 ? 2 : i == Xamoeba_4 ? 3 : i == Xamoeba_5 ? 0 : i == Xamoeba_6 ? 1 : i == Xamoeba_7 ? 2 : i == Xamoeba_8 ? 3 : i == Xexit_2 ? j + 8 : i == Xexit_3 ? j + 16 : i == Xdynamite_1 ? 0 : i == Xdynamite_2 ? 8 : i == Xdynamite_3 ? 16 : i == Xdynamite_4 ? 24 : i == Xsand_stonein_1 ? j + 1 : i == Xsand_stonein_2 ? j + 9 : i == Xsand_stonein_3 ? j + 17 : i == Xsand_stonein_4 ? j + 25 : i == Xsand_stoneout_1 && j == 0 ? 0 : i == Xsand_stoneout_1 && j == 1 ? 0 : i == Xsand_stoneout_1 && j == 2 ? 1 : i == Xsand_stoneout_1 && j == 3 ? 2 : i == Xsand_stoneout_1 && j == 4 ? 2 : i == Xsand_stoneout_1 && j == 5 ? 3 : i == Xsand_stoneout_1 && j == 6 ? 4 : i == Xsand_stoneout_1 && j == 7 ? 4 : i == Xsand_stoneout_2 && j == 0 ? 5 : i == Xsand_stoneout_2 && j == 1 ? 6 : i == Xsand_stoneout_2 && j == 2 ? 7 : i == Xsand_stoneout_2 && j == 3 ? 8 : i == Xsand_stoneout_2 && j == 4 ? 9 : i == Xsand_stoneout_2 && j == 5 ? 11 : i == Xsand_stoneout_2 && j == 6 ? 13 : i == Xsand_stoneout_2 && j == 7 ? 15 : i == Xboom_bug && j == 1 ? 2 : i == Xboom_bug && j == 2 ? 2 : i == Xboom_bug && j == 3 ? 4 : i == Xboom_bug && j == 4 ? 4 : i == Xboom_bug && j == 5 ? 2 : i == Xboom_bug && j == 6 ? 2 : i == Xboom_bug && j == 7 ? 0 : i == Xboom_bomb && j == 1 ? 2 : i == Xboom_bomb && j == 2 ? 2 : i == Xboom_bomb && j == 3 ? 4 : i == Xboom_bomb && j == 4 ? 4 : i == Xboom_bomb && j == 5 ? 2 : i == Xboom_bomb && j == 6 ? 2 : i == Xboom_bomb && j == 7 ? 0 : i == Xboom_android && j == 7 ? 6 : i == Xboom_1 && j == 1 ? 2 : i == Xboom_1 && j == 2 ? 2 : i == Xboom_1 && j == 3 ? 4 : i == Xboom_1 && j == 4 ? 4 : i == Xboom_1 && j == 5 ? 6 : i == Xboom_1 && j == 6 ? 6 : i == Xboom_1 && j == 7 ? 8 : i == Xboom_2 && j == 0 ? 8 : i == Xboom_2 && j == 1 ? 8 : i == Xboom_2 && j == 2 ? 10 : i == Xboom_2 && j == 3 ? 10 : i == Xboom_2 && j == 4 ? 10 : i == Xboom_2 && j == 5 ? 12 : i == Xboom_2 && j == 6 ? 12 : i == Xboom_2 && j == 7 ? 12 : special_animation && j == 4 ? 3 : effective_action != action ? 0 : j); #if DEBUG_EM_GFX Bitmap *debug_bitmap = g_em->bitmap; int debug_src_x = g_em->src_x; int debug_src_y = g_em->src_y; #endif int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, g->double_movement && is_backside); g_em->bitmap = src_bitmap; g_em->src_x = src_x; g_em->src_y = src_y; g_em->src_offset_x = 0; g_em->src_offset_y = 0; g_em->dst_offset_x = 0; g_em->dst_offset_y = 0; g_em->width = TILEX; g_em->height = TILEY; g_em->preserve_background = FALSE; set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled, sync_frame); if ((!g->double_movement && (effective_action == ACTION_FALLING || effective_action == ACTION_MOVING || effective_action == ACTION_PUSHING || effective_action == ACTION_EATING)) || (!has_action_graphics && (effective_action == ACTION_FILLING || effective_action == ACTION_EMPTYING))) { int move_dir = (effective_action == ACTION_FALLING || effective_action == ACTION_FILLING || effective_action == ACTION_EMPTYING ? MV_DOWN : direction); int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0); int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0); int num_steps = (i == Ydrip_s1 ? 16 : i == Ydrip_s1B ? 16 : i == Ydrip_s2 ? 16 : i == Ydrip_s2B ? 16 : i == Xsand_stonein_1 ? 32 : i == Xsand_stonein_2 ? 32 : i == Xsand_stonein_3 ? 32 : i == Xsand_stonein_4 ? 32 : i == Xsand_stoneout_1 ? 16 : i == Xsand_stoneout_2 ? 16 : 8); int cx = ABS(dx) * (TILEX / num_steps); int cy = ABS(dy) * (TILEY / num_steps); int step_frame = (i == Ydrip_s2 ? j + 8 : i == Ydrip_s2B ? j + 8 : i == Xsand_stonein_2 ? j + 8 : i == Xsand_stonein_3 ? j + 16 : i == Xsand_stonein_4 ? j + 24 : i == Xsand_stoneout_2 ? j + 8 : j) + 1; int step = (is_backside ? step_frame : num_steps - step_frame); if (is_backside) /* tile where movement starts */ { if (dx < 0 || dy < 0) { g_em->src_offset_x = cx * step; g_em->src_offset_y = cy * step; } else { g_em->dst_offset_x = cx * step; g_em->dst_offset_y = cy * step; } } else /* tile where movement ends */ { if (dx < 0 || dy < 0) { g_em->dst_offset_x = cx * step; g_em->dst_offset_y = cy * step; } else { g_em->src_offset_x = cx * step; g_em->src_offset_y = cy * step; } } g_em->width = TILEX - cx * step; g_em->height = TILEY - cy * step; } /* create unique graphic identifier to decide if tile must be redrawn */ /* bit 31 - 16 (16 bit): EM style graphic bit 15 - 12 ( 4 bit): EM style frame bit 11 - 6 ( 6 bit): graphic width bit 5 - 0 ( 6 bit): graphic height */ g_em->unique_identifier = (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height; #if DEBUG_EM_GFX /* skip check for EMC elements not contained in original EMC artwork */ if (element == EL_EMC_FAKE_ACID) continue; if (g_em->bitmap != debug_bitmap || g_em->src_x != debug_src_x || g_em->src_y != debug_src_y || g_em->src_offset_x != 0 || g_em->src_offset_y != 0 || g_em->dst_offset_x != 0 || g_em->dst_offset_y != 0 || g_em->width != TILEX || g_em->height != TILEY) { static int last_i = -1; if (i != last_i) { printf("\n"); last_i = i; } printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)", i, element, element_info[element].token_name, element_action_info[effective_action].suffix, direction); if (element != effective_element) printf(" [%d ('%s')]", effective_element, element_info[effective_element].token_name); printf("\n"); if (g_em->bitmap != debug_bitmap) printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n", j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap)); if (g_em->src_x != debug_src_x || g_em->src_y != debug_src_y) printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n", j, (is_backside ? 'B' : 'F'), g_em->src_x, g_em->src_y, g_em->src_x / 32, g_em->src_y / 32, debug_src_x, debug_src_y, debug_src_x / 32, debug_src_y / 32); if (g_em->src_offset_x != 0 || g_em->src_offset_y != 0 || g_em->dst_offset_x != 0 || g_em->dst_offset_y != 0) printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n", j, is_backside, g_em->src_offset_x, g_em->src_offset_y, g_em->dst_offset_x, g_em->dst_offset_y); if (g_em->width != TILEX || g_em->height != TILEY) printf(" %d (%d): size %d,%d should be %d,%d\n", j, is_backside, g_em->width, g_em->height, TILEX, TILEY); num_em_gfx_errors++; } #endif } } for (i = 0; i < TILE_MAX; i++) { for (j = 0; j < 8; j++) { int element = object_mapping[i].element_rnd; int action = object_mapping[i].action; int direction = object_mapping[i].direction; boolean is_backside = object_mapping[i].is_backside; int graphic_action = el_act_dir2img(element, action, direction); int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction); if ((action == ACTION_SMASHED_BY_ROCK || action == ACTION_SMASHED_BY_SPRING || action == ACTION_EATING) && graphic_action == graphic_default) { int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s : action == ACTION_SMASHED_BY_SPRING ? Yspring_s : direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) : direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) : Xspring); /* no separate animation for "smashed by rock" -- use rock instead */ struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j]; struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j]; g_em->bitmap = g_xx->bitmap; g_em->src_x = g_xx->src_x; g_em->src_y = g_xx->src_y; g_em->src_offset_x = g_xx->src_offset_x; g_em->src_offset_y = g_xx->src_offset_y; g_em->dst_offset_x = g_xx->dst_offset_x; g_em->dst_offset_y = g_xx->dst_offset_y; g_em->width = g_xx->width; g_em->height = g_xx->height; g_em->unique_identifier = g_xx->unique_identifier; if (!is_backside) g_em->preserve_background = TRUE; } } } for (p = 0; p < MAX_PLAYERS; p++) { for (i = 0; i < SPR_MAX; i++) { int element = player_mapping[p][i].element_rnd; int action = player_mapping[p][i].action; int direction = player_mapping[p][i].direction; for (j = 0; j < 8; j++) { int effective_element = element; int effective_action = action; int graphic = (direction == MV_NONE ? el_act2img(effective_element, effective_action) : el_act_dir2img(effective_element, effective_action, direction)); struct GraphicInfo *g = &graphic_info[graphic]; struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j]; Bitmap *src_bitmap; int src_x, src_y; int sync_frame = j; #if DEBUG_EM_GFX Bitmap *debug_bitmap = g_em->bitmap; int debug_src_x = g_em->src_x; int debug_src_y = g_em->src_y; #endif int frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE); g_em->bitmap = src_bitmap; g_em->src_x = src_x; g_em->src_y = src_y; g_em->src_offset_x = 0; g_em->src_offset_y = 0; g_em->dst_offset_x = 0; g_em->dst_offset_y = 0; g_em->width = TILEX; g_em->height = TILEY; #if DEBUG_EM_GFX /* skip check for EMC elements not contained in original EMC artwork */ if (element == EL_PLAYER_3 || element == EL_PLAYER_4) continue; if (g_em->bitmap != debug_bitmap || g_em->src_x != debug_src_x || g_em->src_y != debug_src_y) { static int last_i = -1; if (i != last_i) { printf("\n"); last_i = i; } printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)", p, i, element, element_info[element].token_name, element_action_info[effective_action].suffix, direction); if (element != effective_element) printf(" [%d ('%s')]", effective_element, element_info[effective_element].token_name); printf("\n"); if (g_em->bitmap != debug_bitmap) printf(" %d: different bitmap! (0x%08x != 0x%08x)\n", j, (int)(g_em->bitmap), (int)(debug_bitmap)); if (g_em->src_x != debug_src_x || g_em->src_y != debug_src_y) printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n", j, g_em->src_x, g_em->src_y, g_em->src_x / 32, g_em->src_y / 32, debug_src_x, debug_src_y, debug_src_x / 32, debug_src_y / 32); num_em_gfx_errors++; } #endif } } } #if DEBUG_EM_GFX printf("\n"); printf("::: [%d errors found]\n", num_em_gfx_errors); exit(0); #endif } void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame, boolean any_player_moving, boolean any_player_snapping, boolean any_player_dropping) { if (frame == 0 && !any_player_dropping) { if (!local_player->was_waiting) { if (!CheckSaveEngineSnapshotToList()) return; local_player->was_waiting = TRUE; } } else if (any_player_moving || any_player_snapping || any_player_dropping) { local_player->was_waiting = FALSE; } } void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting, boolean murphy_is_dropping) { if (murphy_is_waiting) { if (!local_player->was_waiting) { if (!CheckSaveEngineSnapshotToList()) return; local_player->was_waiting = TRUE; } } else { local_player->was_waiting = FALSE; } } void CheckSaveEngineSnapshot_MM(boolean element_clicked, boolean button_released) { if (button_released) { if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE) CheckSaveEngineSnapshotToList(); } else if (element_clicked) { if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE) CheckSaveEngineSnapshotToList(); game.snapshot.changed_action = TRUE; } } void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame, boolean any_player_moving, boolean any_player_snapping, boolean any_player_dropping) { if (tape.single_step && tape.recording && !tape.pausing) if (frame == 0 && !any_player_dropping) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); CheckSaveEngineSnapshot_EM(action, frame, any_player_moving, any_player_snapping, any_player_dropping); } void CheckSingleStepMode_SP(boolean murphy_is_waiting, boolean murphy_is_dropping) { boolean murphy_starts_dropping = FALSE; int i; for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].force_dropping) murphy_starts_dropping = TRUE; if (tape.single_step && tape.recording && !tape.pausing) if (murphy_is_waiting && !murphy_starts_dropping) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping); } void CheckSingleStepMode_MM(boolean element_clicked, boolean button_released) { if (tape.single_step && tape.recording && !tape.pausing) if (button_released) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); CheckSaveEngineSnapshot_MM(element_clicked, button_released); } void getGraphicSource_SP(struct GraphicInfo_SP *g_sp, int graphic, int sync_frame, int x, int y) { int frame = getGraphicAnimationFrame(graphic, sync_frame); getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y); } boolean isNextAnimationFrame_SP(int graphic, int sync_frame) { return (IS_NEXT_FRAME(sync_frame, graphic)); } int getGraphicInfo_Delay(int graphic) { return graphic_info[graphic].anim_delay; } void PlayMenuSoundExt(int sound) { if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; if (IS_LOOP_SOUND(sound)) PlaySoundLoop(sound); else PlaySound(sound); } void PlayMenuSound() { PlayMenuSoundExt(menu.sound[game_status]); } void PlayMenuSoundStereo(int sound, int stereo_position) { if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; if (IS_LOOP_SOUND(sound)) PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP); else PlaySoundStereo(sound, stereo_position); } void PlayMenuSoundIfLoopExt(int sound) { if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; if (IS_LOOP_SOUND(sound)) PlaySoundLoop(sound); } void PlayMenuSoundIfLoop() { PlayMenuSoundIfLoopExt(menu.sound[game_status]); } void PlayMenuMusicExt(int music) { if (music == MUS_UNDEFINED) return; if (!setup.sound_music) return; PlayMusic(music); } void PlayMenuMusic() { char *curr_music = getCurrentlyPlayingMusicFilename(); char *next_music = getMusicInfoEntryFilename(menu.music[game_status]); if (!strEqual(curr_music, next_music)) PlayMenuMusicExt(menu.music[game_status]); } void PlayMenuSoundsAndMusic() { PlayMenuSound(); PlayMenuMusic(); } static void FadeMenuSounds() { FadeSounds(); } static void FadeMenuMusic() { char *curr_music = getCurrentlyPlayingMusicFilename(); char *next_music = getMusicInfoEntryFilename(menu.music[game_status]); if (!strEqual(curr_music, next_music)) FadeMusic(); } void FadeMenuSoundsAndMusic() { FadeMenuSounds(); FadeMenuMusic(); } void PlaySoundActivating() { #if 0 PlaySound(SND_MENU_ITEM_ACTIVATING); #endif } void PlaySoundSelecting() { #if 0 PlaySound(SND_MENU_ITEM_SELECTING); #endif } void ToggleFullscreenOrChangeWindowScalingIfNeeded() { boolean change_fullscreen = (setup.fullscreen != video.fullscreen_enabled); boolean change_window_scaling_percent = (!video.fullscreen_enabled && setup.window_scaling_percent != video.window_scaling_percent); if (change_window_scaling_percent && video.fullscreen_enabled) return; if (!change_window_scaling_percent && !video.fullscreen_available) return; #if defined(TARGET_SDL2) if (change_window_scaling_percent) { SDLSetWindowScaling(setup.window_scaling_percent); return; } else if (change_fullscreen) { SDLSetWindowFullscreen(setup.fullscreen); /* set setup value according to successfully changed fullscreen mode */ setup.fullscreen = video.fullscreen_enabled; return; } #endif if (change_fullscreen || change_window_scaling_percent) { Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH); /* save backbuffer content which gets lost when toggling fullscreen mode */ BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); if (change_window_scaling_percent) { /* keep window mode, but change window scaling */ video.fullscreen_enabled = TRUE; /* force new window scaling */ } /* toggle fullscreen */ ChangeVideoModeIfNeeded(setup.fullscreen); /* set setup value according to successfully changed fullscreen mode */ setup.fullscreen = video.fullscreen_enabled; /* restore backbuffer content from temporary backbuffer backup bitmap */ BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); FreeBitmap(tmp_backbuffer); /* update visible window/screen */ BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0); } } void JoinRectangles(int *x, int *y, int *width, int *height, int x2, int y2, int width2, int height2) { // do not join with "off-screen" rectangle if (x2 == -1 || y2 == -1) return; *x = MIN(*x, x2); *y = MIN(*y, y2); *width = MAX(*width, width2); *height = MAX(*height, height2); } void SetAnimStatus(int anim_status_new) { if (anim_status_new == GAME_MODE_MAIN) anim_status_new = GAME_MODE_PSEUDO_MAINONLY; else if (anim_status_new == GAME_MODE_SCORES) anim_status_new = GAME_MODE_PSEUDO_SCORESOLD; global.anim_status_next = anim_status_new; // directly set screen modes that are entered without fading if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY && global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) || (global.anim_status == GAME_MODE_PSEUDO_TYPENAME && global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY)) global.anim_status = global.anim_status_next; } void SetGameStatus(int game_status_new) { if (game_status_new != game_status) game_status_last_screen = game_status; game_status = game_status_new; SetAnimStatus(game_status_new); } void SetFontStatus(int game_status_new) { static int last_game_status = -1; if (game_status_new != -1) { // set game status for font use after storing last game status last_game_status = game_status; game_status = game_status_new; } else { // reset game status after font use from last stored game status game_status = last_game_status; } } void ResetFontStatus() { SetFontStatus(-1); } boolean CheckIfPlayfieldViewportHasChanged() { // if game status has not changed, playfield viewport has not changed either if (game_status == game_status_last) return FALSE; // check if playfield viewport has changed with current game status struct RectWithBorder *vp_playfield = &viewport.playfield[game_status]; int new_real_sx = vp_playfield->x; int new_real_sy = vp_playfield->y; int new_full_sxsize = vp_playfield->width; int new_full_sysize = vp_playfield->height; return (new_real_sx != REAL_SX || new_real_sy != REAL_SY || new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE); } boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged() { return (CheckIfGlobalBorderHasChanged() || CheckIfPlayfieldViewportHasChanged()); } void ChangeViewportPropertiesIfNeeded() { boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? FALSE : setup.small_game_graphics); int gfx_game_mode = game_status; int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT : game_status); struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode]; struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode]; struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode]; struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2]; struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR]; int new_win_xsize = vp_window->width; int new_win_ysize = vp_window->height; int border_size = vp_playfield->border_size; int new_sx = vp_playfield->x + border_size; int new_sy = vp_playfield->y + border_size; int new_sxsize = vp_playfield->width - 2 * border_size; int new_sysize = vp_playfield->height - 2 * border_size; int new_real_sx = vp_playfield->x; int new_real_sy = vp_playfield->y; int new_full_sxsize = vp_playfield->width; int new_full_sysize = vp_playfield->height; int new_dx = vp_door_1->x; int new_dy = vp_door_1->y; int new_dxsize = vp_door_1->width; int new_dysize = vp_door_1->height; int new_vx = vp_door_2->x; int new_vy = vp_door_2->y; int new_vxsize = vp_door_2->width; int new_vysize = vp_door_2->height; int new_ex = vp_door_3->x; int new_ey = vp_door_3->y; int new_exsize = vp_door_3->width; int new_eysize = vp_door_3->height; int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size); int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var : gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE); int new_scr_fieldx = new_sxsize / tilesize; int new_scr_fieldy = new_sysize / tilesize; int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var; int new_scr_fieldy_buffers = new_sysize / new_tilesize_var; boolean init_gfx_buffers = FALSE; boolean init_video_buffer = FALSE; boolean init_gadgets_and_anims = FALSE; boolean init_em_graphics = FALSE; if (new_win_xsize != WIN_XSIZE || new_win_ysize != WIN_YSIZE) { WIN_XSIZE = new_win_xsize; WIN_YSIZE = new_win_ysize; init_video_buffer = TRUE; init_gfx_buffers = TRUE; init_gadgets_and_anims = TRUE; // printf("::: video: init_video_buffer, init_gfx_buffers\n"); } if (new_scr_fieldx != SCR_FIELDX || new_scr_fieldy != SCR_FIELDY) { /* this always toggles between MAIN and GAME when using small tile size */ SCR_FIELDX = new_scr_fieldx; SCR_FIELDY = new_scr_fieldy; // printf("::: new_scr_fieldx != SCR_FIELDX ...\n"); } if (new_sx != SX || new_sy != SY || new_dx != DX || new_dy != DY || new_vx != VX || new_vy != VY || new_ex != EX || new_ey != EY || new_sxsize != SXSIZE || new_sysize != SYSIZE || new_dxsize != DXSIZE || new_dysize != DYSIZE || new_vxsize != VXSIZE || new_vysize != VYSIZE || new_exsize != EXSIZE || new_eysize != EYSIZE || new_real_sx != REAL_SX || new_real_sy != REAL_SY || new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE || new_tilesize_var != TILESIZE_VAR ) { // ------------------------------------------------------------------------ // determine next fading area for changed viewport definitions // ------------------------------------------------------------------------ // start with current playfield area (default fading area) FADE_SX = REAL_SX; FADE_SY = REAL_SY; FADE_SXSIZE = FULL_SXSIZE; FADE_SYSIZE = FULL_SYSIZE; // add new playfield area if position or size has changed if (new_real_sx != REAL_SX || new_real_sy != REAL_SY || new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE) { JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE, new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize); } // add current and new door 1 area if position or size has changed if (new_dx != DX || new_dy != DY || new_dxsize != DXSIZE || new_dysize != DYSIZE) { JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE, DX, DY, DXSIZE, DYSIZE); JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE, new_dx, new_dy, new_dxsize, new_dysize); } // add current and new door 2 area if position or size has changed if (new_dx != VX || new_dy != VY || new_dxsize != VXSIZE || new_dysize != VYSIZE) { JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE, VX, VY, VXSIZE, VYSIZE); JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE, new_vx, new_vy, new_vxsize, new_vysize); } // ------------------------------------------------------------------------ // handle changed tile size // ------------------------------------------------------------------------ if (new_tilesize_var != TILESIZE_VAR) { // printf("::: new_tilesize_var != TILESIZE_VAR\n"); // changing tile size invalidates scroll values of engine snapshots FreeEngineSnapshotSingle(); // changing tile size requires update of graphic mapping for EM engine init_em_graphics = TRUE; } SX = new_sx; SY = new_sy; DX = new_dx; DY = new_dy; VX = new_vx; VY = new_vy; EX = new_ex; EY = new_ey; SXSIZE = new_sxsize; SYSIZE = new_sysize; DXSIZE = new_dxsize; DYSIZE = new_dysize; VXSIZE = new_vxsize; VYSIZE = new_vysize; EXSIZE = new_exsize; EYSIZE = new_eysize; REAL_SX = new_real_sx; REAL_SY = new_real_sy; FULL_SXSIZE = new_full_sxsize; FULL_SYSIZE = new_full_sysize; TILESIZE_VAR = new_tilesize_var; init_gfx_buffers = TRUE; init_gadgets_and_anims = TRUE; // printf("::: viewports: init_gfx_buffers\n"); // printf("::: viewports: init_gadgets_and_anims\n"); } if (init_gfx_buffers) { // printf("::: init_gfx_buffers\n"); SCR_FIELDX = new_scr_fieldx_buffers; SCR_FIELDY = new_scr_fieldy_buffers; InitGfxBuffers(); SCR_FIELDX = new_scr_fieldx; SCR_FIELDY = new_scr_fieldy; SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); } if (init_video_buffer) { // printf("::: init_video_buffer\n"); InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen); InitImageTextures(); } if (init_gadgets_and_anims) { // printf("::: init_gadgets_and_anims\n"); InitGadgets(); InitGlobalAnimations(); } if (init_em_graphics) { InitGraphicInfo_EM(); } } mirrormagic-3.0.0/src/config.h0000644000175000017500000000162113263212010015526 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // config.h // ============================================================================ #ifndef CONFIG_H #define CONFIG_H #include "main.h" char *getSourceDateString(void); char *getProgramTitleString(void); char *getProgramRealVersionString(void); char *getProgramVersionString(void); char *getProgramInitString(void); char *getConfigProgramTitleString(); char *getConfigProgramCopyrightString(); char *getConfigProgramCompanyString(); char *getWindowTitleString(void); #endif /* CONFIG_H */ mirrormagic-3.0.0/src/network.c0000644000175000017500000003566013263212010015757 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // network.c // ============================================================================ #include "libgame/platform.h" #if defined(NETWORK_AVALIABLE) #include #include #include "main.h" #include "libgame/libgame.h" #include "network.h" #include "netserv.h" #include "game.h" #include "tape.h" #include "files.h" #include "tools.h" #include "screens.h" struct NetworkClientPlayerInfo { byte nr; char name[MAX_PLAYER_NAME_LEN + 1]; struct NetworkClientPlayerInfo *next; }; static struct NetworkClientPlayerInfo first_player = { 0, EMPTY_PLAYER_NAME, NULL }; /* server stuff */ static TCPsocket sfd; /* server socket */ static SDLNet_SocketSet rfds; /* socket set */ 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 boolean stop_network_game = FALSE; 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 */ SDLNet_TCP_Send(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 && strlen(player->name) > 0) return(player->name); return(EMPTY_PLAYER_NAME); } static void StartNetworkServer(int port) { static int p; p = port; #if defined(TARGET_SDL2) server_thread = SDL_CreateThread(NetworkServerThread, "NetworkServerThread", &p); #else server_thread = SDL_CreateThread(NetworkServerThread, &p); #endif network_server = TRUE; } boolean ConnectToServer(char *hostname, int port) { IPaddress ip; int i; if (port == 0) port = DEFAULT_SERVER_PORT; rfds = SDLNet_AllocSocketSet(1); if (hostname) { SDLNet_ResolveHost(&ip, hostname, port); if (ip.host == INADDR_NONE) Error(ERR_EXIT, "cannot locate host '%s'", hostname); } else { SDLNet_Write32(0x7f000001, &ip.host); /* 127.0.0.1 */ SDLNet_Write16(port, &ip.port); } sfd = SDLNet_TCP_Open(&ip); if (sfd) { SDLNet_TCP_AddSocket(rfds, sfd); return TRUE; } else { printf("SDLNet_TCP_Open(): %s\n", SDLNet_GetError()); } 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 */ if ((sfd = SDLNet_TCP_Open(&ip))) /* connected */ { SDLNet_TCP_AddSocket(rfds, sfd); 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 int new_random_seed = InitRND(level.random_seed); int dummy = 0; /* !!! HAS NO MEANING ANYMORE !!! */ /* the name of the level must be enough */ buffer[1] = OP_START_PLAYING; buffer[2] = (byte)(level_nr >> 8); buffer[3] = (byte)(level_nr & 0xff); buffer[4] = (byte)(dummy >> 8); buffer[5] = (byte)(dummy & 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_current->identifier); SendBufferToServer(10 + strlen(leveldir_current->identifier) + 1); } void SendToServer_PausePlaying() { buffer[1] = OP_PAUSE_PLAYING; SendBufferToServer(2); } void SendToServer_ContinuePlaying() { buffer[1] = OP_CONTINUE_PLAYING; SendBufferToServer(2); } void SendToServer_StopPlaying(int cause_for_stopping) { buffer[1] = OP_STOP_PLAYING; buffer[2] = cause_for_stopping; SendBufferToServer(3); } void SendToServer_MovePlayer(byte player_action) { buffer[1] = OP_MOVE_PLAYER; 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, more than %d players not allowed", 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 request[100]; sprintf(request, "Sorry! Player %d already exists! You are player %d!", index_nr_wanted + 1, new_index_nr + 1); 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() { LevelDirTree *new_leveldir; int new_level_nr; unsigned int new_random_seed; char *new_leveldir_identifier; new_level_nr = (buffer[2] << 8) + buffer[3]; new_random_seed = (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]); new_leveldir_identifier = (char *)&buffer[10]; new_leveldir = getTreeInfoFromIdentifier(leveldir_first, new_leveldir_identifier); if (new_leveldir == NULL) { Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier); new_leveldir = leveldir_first; Error(ERR_WARN, "using default level set: '%s'", new_leveldir->identifier); } printf("OP_START_PLAYING: %d\n", buffer[0]); Error(ERR_NETWORK_CLIENT, "client %d starts game [level %d from level identifier '%s']\n", buffer[0], new_level_nr, new_leveldir->identifier); leveldir_current = new_leveldir; level_nr = new_level_nr; TapeErase(); LoadTape(level_nr); LoadLevel(level_nr); StartGameActions(FALSE, setup.autorecord, new_random_seed); } 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 [%d]\n", buffer[0], buffer[2]); Error(ERR_NETWORK_CLIENT, "client %d stops game [%d]", buffer[0], buffer[2]); if (game_status == GAME_MODE_PLAYING) { if (buffer[2] == NETWORK_STOP_BY_PLAYER) Request("Network game stopped by player!", REQ_CONFIRM); else if (buffer[2] == NETWORK_STOP_BY_ERROR) Request("Network game stopped due to internal error!", REQ_CONFIRM); else Request("Network game stopped!", REQ_CONFIRM); } SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } static void Handle_OP_MOVE_PLAYER(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_INFO, "client and servers frame counters out of sync"); Error(ERR_INFO, "frame counter of client is %d", FrameCounter); Error(ERR_INFO, "frame counter of server is %d", server_frame_counter); Error(ERR_INFO, "this should not happen -- please debug"); stop_network_game = TRUE; return; } /* copy valid player actions */ for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = (i < len - 6 && stored_player[i].active ? buffer[6 + i] : 0); network_player_action_received = TRUE; } static void HandleNetworkingMessages() { unsigned int message_length; stop_network_game = FALSE; while (nread >= 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_PLAYER: Handle_OP_MOVE_PLAYER(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); /* in case of internal error, stop network game */ if (stop_network_game) SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR); } /* TODO */ void HandleNetworking() { int r = 0; do { if ((r = SDLNet_CheckSockets(rfds, 1)) < 0) Error(ERR_EXIT, "HandleNetworking(): SDLNet_CheckSockets() failed"); if (r > 0) { r = SDLNet_TCP_Recv(sfd, readbuffer + nread, 1); 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(); } } while (r > 0); } #endif /* NETWORK_AVALIABLE */ mirrormagic-3.0.0/src/main.c0000644000175000017500000037047613263212010015221 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // main.c // ============================================================================ #include "libgame/libgame.h" #include "main.h" #include "init.h" #include "game.h" #include "tape.h" #include "tools.h" #include "files.h" #include "events.h" #include "config.h" Bitmap *bitmap_db_field; Bitmap *bitmap_db_panel; Bitmap *bitmap_db_door_1; Bitmap *bitmap_db_door_2; Bitmap *bitmap_db_store_1; Bitmap *bitmap_db_store_2; DrawBuffer *fieldbuffer; DrawBuffer *drawto_field; int game_status = -1; boolean game_status_last_screen = -1; boolean level_editor_test_game = FALSE; boolean network_playing = FALSE; #if defined(TARGET_SDL) boolean network_server = FALSE; SDL_Thread *server_thread; #endif int key_joystick_mapping = 0; short Feld[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 ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short CustomValue[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 Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; boolean Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short AmoebaCnt[MAX_NUM_AMOEBA]; short AmoebaCnt2[MAX_NUM_AMOEBA]; short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; int ActiveElement[MAX_NUM_ELEMENTS]; int ActiveButton[NUM_IMAGE_FILES]; int ActiveFont[NUM_FONTS]; int lev_fieldx, lev_fieldy; int scroll_x, scroll_y; int WIN_XSIZE = WIN_XSIZE_DEFAULT; int WIN_YSIZE = WIN_YSIZE_DEFAULT; int SCR_FIELDX = SCR_FIELDX_DEFAULT; int SCR_FIELDY = SCR_FIELDY_DEFAULT; int REAL_SX = 6, REAL_SY = 6; int SX = 8, SY = 8; int DX = 566, DY = 60; int VX = 566, VY = 400; int EX = 566, EY = 356; int dDX, dDY; int FULL_SXSIZE = 2 + SXSIZE_DEFAULT + 2; int FULL_SYSIZE = 2 + SYSIZE_DEFAULT + 2; int SXSIZE = SXSIZE_DEFAULT; int SYSIZE = SYSIZE_DEFAULT; int FADE_SX = 6, FADE_SY = 6; int FADE_SXSIZE = 2 + SXSIZE_DEFAULT + 2; int FADE_SYSIZE = 2 + SXSIZE_DEFAULT + 2; int DXSIZE = 100; int DYSIZE = 280; int VXSIZE = 100; int VYSIZE = 100; int EXSIZE = 100; int EYSIZE = 144; int TILESIZE_VAR = TILESIZE; int FX, FY; int ScrollStepSize; int ScreenMovDir = MV_NONE, ScreenMovPos = 0; int ScreenGfxPos = 0; int BorderElement = EL_STEELWALL; int MenuFrameDelay = MENU_FRAME_DELAY; int GameFrameDelay = GAME_FRAME_DELAY; int FfwdFrameDelay = FFWD_FRAME_DELAY; int BX1, BY1; int BX2, BY2; int SBX_Left, SBX_Right; int SBY_Upper, SBY_Lower; int ZX, ZY; int ExitX, ExitY; int AllPlayersGone; int TimeFrames, TimePlayed, TimeLeft, TapeTime; boolean network_player_action_received = FALSE; struct LevelSetInfo levelset; struct LevelInfo level, level_template; struct PlayerInfo stored_player[MAX_PLAYERS], *local_player = NULL; struct HiScore highscore[MAX_SCORE_ENTRIES]; struct TapeInfo tape; struct SetupInfo setup; struct GameInfo game; struct GlobalInfo global; struct BorderInfo border; struct ViewportInfo viewport; struct TitleFadingInfo fading; struct TitleFadingInfo title_initial_first_default; struct TitleFadingInfo title_initial_default; struct TitleFadingInfo title_first_default; struct TitleFadingInfo title_default; struct TitleMessageInfo titlescreen_initial_first_default; struct TitleMessageInfo titlescreen_initial_first[MAX_NUM_TITLE_IMAGES]; struct TitleMessageInfo titlescreen_initial_default; struct TitleMessageInfo titlescreen_initial[MAX_NUM_TITLE_IMAGES]; struct TitleMessageInfo titlescreen_first_default; struct TitleMessageInfo titlescreen_first[MAX_NUM_TITLE_IMAGES]; struct TitleMessageInfo titlescreen_default; struct TitleMessageInfo titlescreen[MAX_NUM_TITLE_IMAGES]; struct TitleMessageInfo titlemessage_initial_first_default; struct TitleMessageInfo titlemessage_initial_first[MAX_NUM_TITLE_MESSAGES]; struct TitleMessageInfo titlemessage_initial_default; struct TitleMessageInfo titlemessage_initial[MAX_NUM_TITLE_MESSAGES]; struct TitleMessageInfo titlemessage_first_default; struct TitleMessageInfo titlemessage_first[MAX_NUM_TITLE_MESSAGES]; struct TitleMessageInfo titlemessage_default; struct TitleMessageInfo titlemessage[MAX_NUM_TITLE_MESSAGES]; struct TitleMessageInfo readme; struct InitInfo init, init_last; struct MenuInfo menu; struct DoorInfo door_1, door_2; struct RequestInfo request; struct PreviewInfo preview; struct EditorInfo editor; struct GraphicInfo *graphic_info = NULL; struct SoundInfo *sound_info = NULL; struct MusicInfo *music_info = NULL; struct MusicFileInfo *music_file_info = NULL; struct HelpAnimInfo *helpanim_info = NULL; SetupFileHash *helptext_info = NULL; SetupFileHash *image_config_hash = NULL; SetupFileHash *element_token_hash = NULL; SetupFileHash *graphic_token_hash = NULL; SetupFileHash *font_token_hash = NULL; SetupFileHash *hide_setup_hash = NULL; /* ------------------------------------------------------------------------- */ /* element definitions */ /* ------------------------------------------------------------------------- */ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1]; /* this contains predefined structure elements to initialize "element_info" */ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] = { /* keyword to start parser: "ELEMENT_INFO_START" <-- do not change! */ /* ----------------------------------------------------------------------- */ /* "real" level file elements */ /* ----------------------------------------------------------------------- */ { "empty_space", "empty_space", "empty space" }, { "sand", "sand", "sand" }, { "wall", "wall", "normal wall" }, { "wall_slippery", "wall", "slippery wall" }, { "rock", "rock", "rock" }, { "key_obsolete", "obsolete", "key (OBSOLETE)" }, { "emerald", "emerald", "emerald" }, { "exit_closed", "exit", "closed exit" }, { "player_obsolete", "obsolete", "player (OBSOLETE)" }, { "bug", "bug", "bug (random start direction)" }, { "spaceship", "spaceship", "spaceship (random start direction)" }, { "yamyam", "yamyam", "yam yam (random start direction)" }, { "robot", "robot", "robot" }, { "steelwall", "steelwall", "steel wall" }, { "diamond", "diamond", "diamond" }, { "amoeba_dead", "amoeba", "dead amoeba" }, { "quicksand_empty", "quicksand", "quicksand (empty)" }, { "quicksand_full", "quicksand", "quicksand (with rock)" }, { "amoeba_drop", "amoeba", "amoeba drop" }, { "bomb", "bomb", "bomb" }, { "magic_wall", "magic_wall", "magic wall" }, { "speed_pill", "speed_pill", "speed pill" }, { "acid", "acid", "acid" }, { "amoeba_wet", "amoeba", "dropping amoeba (EM style)" }, { "amoeba_dry", "amoeba", "normal amoeba" }, { "nut", "nut", "nut with emerald" }, { "game_of_life", "game_of_life", "Conway's wall of life" }, { "biomaze", "biomaze", "biomaze" }, { "dynamite.active", "dynamite", "burning dynamite" }, { "stoneblock", "wall", "wall" }, { "robot_wheel", "robot_wheel", "magic wheel" }, { "robot_wheel.active", "robot_wheel", "magic wheel (running)" }, { "key_1", "key", "key 1" }, { "key_2", "key", "key 2" }, { "key_3", "key", "key 3" }, { "key_4", "key", "key 4" }, { "gate_1", "gate", "door 1" }, { "gate_2", "gate", "door 2" }, { "gate_3", "gate", "door 3" }, { "gate_4", "gate", "door 4" }, { "gate_1_gray", "gate", "gray door (opened by key 1)" }, { "gate_2_gray", "gate", "gray door (opened by key 2)" }, { "gate_3_gray", "gate", "gray door (opened by key 3)" }, { "gate_4_gray", "gate", "gray door (opened by key 4)" }, { "dynamite", "dynamite", "dynamite" }, { "pacman", "pacman", "pac man (random start direction)" }, { "invisible_wall", "wall", "invisible normal wall" }, { "lamp", "lamp", "lamp (off)" }, { "lamp.active", "lamp", "lamp (on)" }, { "wall_emerald", "wall", "wall with emerald" }, { "wall_diamond", "wall", "wall with diamond" }, { "amoeba_full", "amoeba", "amoeba with content" }, { "bd_amoeba", "bd_amoeba", "amoeba (BD style)" }, { "time_orb_full", "time_orb_full", "time orb (full)" }, { "time_orb_empty", "time_orb_empty", "time orb (empty)" }, { "expandable_wall", "wall", "growing wall (horizontal, visible)" }, { "bd_diamond", "bd_diamond", "diamond (BD style)" }, { "emerald_yellow", "emerald", "yellow emerald" }, { "wall_bd_diamond", "wall", "wall with BD style diamond" }, { "wall_emerald_yellow", "wall", "wall with yellow emerald" }, { "dark_yamyam", "dark_yamyam", "dark yam yam" }, { "bd_magic_wall", "bd_magic_wall", "magic wall (BD style)" }, { "invisible_steelwall", "steelwall", "invisible steel wall" }, { "sokoban_field_player", "sokoban", "sokoban field with player" }, { "dynabomb_increase_number", "dynabomb", "increases number of bombs" }, { "dynabomb_increase_size", "dynabomb", "increases explosion size" }, { "dynabomb_increase_power", "dynabomb", "increases power of explosion" }, { "sokoban_object", "sokoban", "sokoban object" }, { "sokoban_field_empty", "sokoban", "sokoban empty field" }, { "sokoban_field_full", "sokoban", "sokoban field with object" }, { "bd_butterfly.right", "bd_butterfly", "butterfly (starts moving right)"}, { "bd_butterfly.up", "bd_butterfly", "butterfly (starts moving up)" }, { "bd_butterfly.left", "bd_butterfly", "butterfly (starts moving left)"}, { "bd_butterfly.down", "bd_butterfly", "butterfly (starts moving down)"}, { "bd_firefly.right", "bd_firefly", "firefly (starts moving right)" }, { "bd_firefly.up", "bd_firefly", "firefly (starts moving up)" }, { "bd_firefly.left", "bd_firefly", "firefly (starts moving left)" }, { "bd_firefly.down", "bd_firefly", "firefly (starts moving down)" }, { "bd_butterfly", "bd_butterfly", "butterfly (random start direction)" }, { "bd_firefly", "bd_firefly", "firefly (random start direction)" }, { "player_1", "player", "player 1" }, { "player_2", "player", "player 2" }, { "player_3", "player", "player 3" }, { "player_4", "player", "player 4" }, { "bug.right", "bug", "bug (starts moving right)" }, { "bug.up", "bug", "bug (starts moving up)" }, { "bug.left", "bug", "bug (starts moving left)" }, { "bug.down", "bug", "bug (starts moving down)" }, { "spaceship.right", "spaceship", "spaceship (starts moving right)"}, { "spaceship.up", "spaceship", "spaceship (starts moving up)" }, { "spaceship.left", "spaceship", "spaceship (starts moving left)"}, { "spaceship.down", "spaceship", "spaceship (starts moving down)"}, { "pacman.right", "pacman", "pac man (starts moving right)" }, { "pacman.up", "pacman", "pac man (starts moving up)" }, { "pacman.left", "pacman", "pac man (starts moving left)" }, { "pacman.down", "pacman", "pac man (starts moving down)" }, { "emerald_red", "emerald", "red emerald" }, { "emerald_purple", "emerald", "purple emerald" }, { "wall_emerald_red", "wall", "wall with red emerald" }, { "wall_emerald_purple", "wall", "wall with purple emerald" }, { "acid_pool_topleft", "wall", "acid pool (top left)" }, { "acid_pool_topright", "wall", "acid pool (top right)" }, { "acid_pool_bottomleft", "wall", "acid pool (bottom left)" }, { "acid_pool_bottom", "wall", "acid pool (bottom)" }, { "acid_pool_bottomright", "wall", "acid pool (bottom right)" }, { "bd_wall", "wall", "normal wall (BD style)" }, { "bd_rock", "bd_rock", "rock (BD style)" }, { "exit_open", "exit", "open exit" }, { "black_orb", "black_orb", "black orb bomb" }, { "amoeba_to_diamond", "amoeba", "amoeba" }, { "mole", "mole", "mole (random start direction)" }, { "penguin", "penguin", "penguin" }, { "satellite", "satellite", "satellite" }, { "arrow_left", "arrow", "arrow left" }, { "arrow_right", "arrow", "arrow right" }, { "arrow_up", "arrow", "arrow up" }, { "arrow_down", "arrow", "arrow down" }, { "pig", "pig", "pig" }, { "dragon", "dragon", "fire breathing dragon" }, { "em_key_1_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "char_space", "char", "letter ' '" }, { "char_exclam", "char", "letter '!'" }, { "char_quotedbl", "char", "letter '\"'" }, { "char_numbersign", "char", "letter '#'" }, { "char_dollar", "char", "letter '$'" }, { "char_percent", "char", "letter '%'" }, { "char_ampersand", "char", "letter '&'" }, { "char_apostrophe", "char", "letter '''" }, { "char_parenleft", "char", "letter '('" }, { "char_parenright", "char", "letter ')'" }, { "char_asterisk", "char", "letter '*'" }, { "char_plus", "char", "letter '+'" }, { "char_comma", "char", "letter ','" }, { "char_minus", "char", "letter '-'" }, { "char_period", "char", "letter '.'" }, { "char_slash", "char", "letter '/'" }, { "char_0", "char", "letter '0'" }, { "char_1", "char", "letter '1'" }, { "char_2", "char", "letter '2'" }, { "char_3", "char", "letter '3'" }, { "char_4", "char", "letter '4'" }, { "char_5", "char", "letter '5'" }, { "char_6", "char", "letter '6'" }, { "char_7", "char", "letter '7'" }, { "char_8", "char", "letter '8'" }, { "char_9", "char", "letter '9'" }, { "char_colon", "char", "letter ':'" }, { "char_semicolon", "char", "letter ';'" }, { "char_less", "char", "letter '<'" }, { "char_equal", "char", "letter '='" }, { "char_greater", "char", "letter '>'" }, { "char_question", "char", "letter '?'" }, { "char_at", "char", "letter '@'" }, { "char_a", "char", "letter 'A'" }, { "char_b", "char", "letter 'B'" }, { "char_c", "char", "letter 'C'" }, { "char_d", "char", "letter 'D'" }, { "char_e", "char", "letter 'E'" }, { "char_f", "char", "letter 'F'" }, { "char_g", "char", "letter 'G'" }, { "char_h", "char", "letter 'H'" }, { "char_i", "char", "letter 'I'" }, { "char_j", "char", "letter 'J'" }, { "char_k", "char", "letter 'K'" }, { "char_l", "char", "letter 'L'" }, { "char_m", "char", "letter 'M'" }, { "char_n", "char", "letter 'N'" }, { "char_o", "char", "letter 'O'" }, { "char_p", "char", "letter 'P'" }, { "char_q", "char", "letter 'Q'" }, { "char_r", "char", "letter 'R'" }, { "char_s", "char", "letter 'S'" }, { "char_t", "char", "letter 'T'" }, { "char_u", "char", "letter 'U'" }, { "char_v", "char", "letter 'V'" }, { "char_w", "char", "letter 'W'" }, { "char_x", "char", "letter 'X'" }, { "char_y", "char", "letter 'Y'" }, { "char_z", "char", "letter 'Z'" }, { "char_bracketleft", "char", "letter '['" }, { "char_backslash", "char", "letter '\\'" }, { "char_bracketright", "char", "letter ']'" }, { "char_asciicircum", "char", "letter '^'" }, { "char_underscore", "char", "letter '_'" }, { "char_copyright", "char", "letter '\xa9'" }, { "char_aumlaut", "char", "letter '\xc4'" }, { "char_oumlaut", "char", "letter '\xd6'" }, { "char_uumlaut", "char", "letter '\xdc'" }, { "char_degree", "char", "letter '\xb0'" }, { "char_trademark", "char", "letter '\xae'" }, { "char_cursor", "char", "letter '\xa0'" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter ''" }, { "char_unused", "char", "letter 'button'" }, { "char_unused", "char", "letter 'up'" }, { "char_unused", "char", "letter 'down'" }, { "expandable_wall_horizontal", "wall", "growing wall (horizontal)" }, { "expandable_wall_vertical", "wall", "growing wall (vertical)" }, { "expandable_wall_any", "wall", "growing wall (any direction)" }, { "em_gate_1", "gate", "door 1 (EM style)" }, { "em_gate_2", "gate", "door 2 (EM style)" }, { "em_gate_3", "gate", "door 3 (EM style)" }, { "em_gate_4", "gate", "door 4 (EM style)" }, { "em_key_2_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "em_key_3_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "em_key_4_file_obsolete", "obsolete", "key (OBSOLETE)" }, { "sp_empty_space", "empty_space", "empty space" }, { "sp_zonk", "sp_zonk", "zonk" }, { "sp_base", "sp_base", "base" }, { "sp_murphy", "player", "murphy" }, { "sp_infotron", "sp_infotron", "infotron" }, { "sp_chip_single", "wall", "chip (single)" }, { "sp_hardware_gray", "wall", "hardware" }, { "sp_exit_closed", "sp_exit", "exit" }, { "sp_disk_orange", "sp_disk_orange", "orange disk" }, { "sp_port_right", "sp_port", "port (leading right)" }, { "sp_port_down", "sp_port", "port (leading down)" }, { "sp_port_left", "sp_port", "port (leading left)" }, { "sp_port_up", "sp_port", "port (leading up)" }, { "sp_gravity_port_right", "sp_gravity_port", "gravity-on/off port (leading right)" }, { "sp_gravity_port_down", "sp_gravity_port", "gravity-on/off port (leading down)" }, { "sp_gravity_port_left", "sp_gravity_port", "gravity-on/off port (leading left)" }, { "sp_gravity_port_up", "sp_gravity_port", "gravity-on/off port (leading up)" }, { "sp_sniksnak", "sp_sniksnak", "snik snak" }, { "sp_disk_yellow", "sp_disk_yellow", "yellow disk" }, { "sp_terminal", "sp_terminal", "terminal" }, { "sp_disk_red", "dynamite", "red disk" }, { "sp_port_vertical", "sp_port", "port (vertical)" }, { "sp_port_horizontal", "sp_port", "port (horizontal)" }, { "sp_port_any", "sp_port", "port (any direction)" }, { "sp_electron", "sp_electron", "electron" }, { "sp_buggy_base", "sp_buggy_base", "buggy base" }, { "sp_chip_left", "wall", "chip (left half)" }, { "sp_chip_right", "wall", "chip (right half)" }, { "sp_hardware_base_1", "wall", "hardware" }, { "sp_hardware_green", "wall", "hardware" }, { "sp_hardware_blue", "wall", "hardware" }, { "sp_hardware_red", "wall", "hardware" }, { "sp_hardware_yellow", "wall", "hardware" }, { "sp_hardware_base_2", "wall", "hardware" }, { "sp_hardware_base_3", "wall", "hardware" }, { "sp_hardware_base_4", "wall", "hardware" }, { "sp_hardware_base_5", "wall", "hardware" }, { "sp_hardware_base_6", "wall", "hardware" }, { "sp_chip_top", "wall", "chip (upper half)" }, { "sp_chip_bottom", "wall", "chip (lower half)" }, { "em_gate_1_gray", "gate", "gray door (EM style, key 1)" }, { "em_gate_2_gray", "gate", "gray door (EM style, key 2)" }, { "em_gate_3_gray", "gate", "gray door (EM style, key 3)" }, { "em_gate_4_gray", "gate", "gray door (EM style, key 4)" }, { "em_dynamite", "dynamite", "dynamite (EM style)" }, { "em_dynamite.active", "dynamite", "burning dynamite (EM style)" }, { "pearl", "pearl", "pearl" }, { "crystal", "crystal", "crystal" }, { "wall_pearl", "wall", "wall with pearl" }, { "wall_crystal", "wall", "wall with crystal" }, { "dc_gate_white", "gate", "white door" }, { "dc_gate_white_gray", "gate", "gray door (opened by white key)" }, { "dc_key_white", "key", "white key" }, { "shield_normal", "shield_normal", "shield (normal)" }, { "extra_time", "extra_time", "extra time" }, { "switchgate_open", "switchgate", "switch gate (open)" }, { "switchgate_closed", "switchgate", "switch gate (closed)" }, { "switchgate_switch_up", "switchgate_switch", "switch for switch gate" }, { "switchgate_switch_down", "switchgate_switch", "switch for switch gate" }, { "unused_269", "unused", "-" }, { "unused_270", "unused", "-" }, { "conveyor_belt_1_left", "conveyor_belt", "conveyor belt 1 (left)" }, { "conveyor_belt_1_middle", "conveyor_belt", "conveyor belt 1 (middle)" }, { "conveyor_belt_1_right", "conveyor_belt", "conveyor belt 1 (right)" }, { "conveyor_belt_1_switch_left", "conveyor_belt_switch", "switch for conveyor belt 1 (left)" }, { "conveyor_belt_1_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 1 (middle)" }, { "conveyor_belt_1_switch_right", "conveyor_belt_switch", "switch for conveyor belt 1 (right)" }, { "conveyor_belt_2_left", "conveyor_belt", "conveyor belt 2 (left)" }, { "conveyor_belt_2_middle", "conveyor_belt", "conveyor belt 2 (middle)" }, { "conveyor_belt_2_right", "conveyor_belt", "conveyor belt 2 (right)" }, { "conveyor_belt_2_switch_left", "conveyor_belt_switch", "switch for conveyor belt 2 (left)" }, { "conveyor_belt_2_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 2 (middle)" }, { "conveyor_belt_2_switch_right", "conveyor_belt_switch", "switch for conveyor belt 2 (right)" }, { "conveyor_belt_3_left", "conveyor_belt", "conveyor belt 3 (left)" }, { "conveyor_belt_3_middle", "conveyor_belt", "conveyor belt 3 (middle)" }, { "conveyor_belt_3_right", "conveyor_belt", "conveyor belt 3 (right)" }, { "conveyor_belt_3_switch_left", "conveyor_belt_switch", "switch for conveyor belt 3 (left)" }, { "conveyor_belt_3_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 3 (middle)" }, { "conveyor_belt_3_switch_right", "conveyor_belt_switch", "switch for conveyor belt 3 (right)" }, { "conveyor_belt_4_left", "conveyor_belt", "conveyor belt 4 (left)" }, { "conveyor_belt_4_middle", "conveyor_belt", "conveyor belt 4 (middle)" }, { "conveyor_belt_4_right", "conveyor_belt", "conveyor belt 4 (right)" }, { "conveyor_belt_4_switch_left", "conveyor_belt_switch", "switch for conveyor belt 4 (left)" }, { "conveyor_belt_4_switch_middle", "conveyor_belt_switch", "switch for conveyor belt 4 (middle)" }, { "conveyor_belt_4_switch_right", "conveyor_belt_switch", "switch for conveyor belt 4 (right)" }, { "landmine", "landmine", "land mine (not removable)" }, { "envelope_obsolete", "obsolete", "envelope (OBSOLETE)" }, { "light_switch", "light_switch", "light switch (off)" }, { "light_switch.active", "light_switch", "light switch (on)" }, { "sign_exclamation", "sign", "sign (exclamation)" }, { "sign_radioactivity", "sign", "sign (radio activity)" }, { "sign_stop", "sign", "sign (stop)" }, { "sign_wheelchair", "sign", "sign (wheel chair)" }, { "sign_parking", "sign", "sign (parking)" }, { "sign_no_entry", "sign", "sign (no entry)" }, { "sign_unused_1", "sign", "sign (unused)" }, { "sign_give_way", "sign", "sign (give way)" }, { "sign_entry_forbidden", "sign", "sign (entry forbidden)" }, { "sign_emergency_exit", "sign", "sign (emergency exit)" }, { "sign_yin_yang", "sign", "sign (yin yang)" }, { "sign_unused_2", "sign", "sign (unused)" }, { "mole.left", "mole", "mole (starts moving left)" }, { "mole.right", "mole", "mole (starts moving right)" }, { "mole.up", "mole", "mole (starts moving up)" }, { "mole.down", "mole", "mole (starts moving down)" }, { "steelwall_slippery", "steelwall", "slippery steel wall" }, { "invisible_sand", "sand", "invisible sand" }, { "dx_unknown_15", "unknown", "dx unknown element 15" }, { "dx_unknown_42", "unknown", "dx unknown element 42" }, { "unused_319", "unused", "(not used)" }, { "unused_320", "unused", "(not used)" }, { "shield_deadly", "shield_deadly", "shield (deadly, kills enemies)" }, { "timegate_open", "timegate", "time gate (open)" }, { "timegate_closed", "timegate", "time gate (closed)" }, { "timegate_switch.active", "timegate_switch", "switch for time gate" }, { "timegate_switch", "timegate_switch", "switch for time gate" }, { "balloon", "balloon", "balloon" }, { "balloon_switch_left", "balloon_switch", "wind switch (left)" }, { "balloon_switch_right", "balloon_switch", "wind switch (right)" }, { "balloon_switch_up", "balloon_switch", "wind switch (up)" }, { "balloon_switch_down", "balloon_switch", "wind switch (down)" }, { "balloon_switch_any", "balloon_switch", "wind switch (any direction)" }, { "emc_steelwall_1", "steelwall", "steel wall" }, { "emc_steelwall_2", "steelwall", "steel wall" }, { "emc_steelwall_3", "steelwall", "steel wall" }, { "emc_steelwall_4", "steelwall", "steel wall" }, { "emc_wall_1", "wall", "normal wall" }, { "emc_wall_2", "wall", "normal wall" }, { "emc_wall_3", "wall", "normal wall" }, { "emc_wall_4", "wall", "normal wall" }, { "emc_wall_5", "wall", "normal wall" }, { "emc_wall_6", "wall", "normal wall" }, { "emc_wall_7", "wall", "normal wall" }, { "emc_wall_8", "wall", "normal wall" }, { "tube_any", "tube", "tube (any direction)" }, { "tube_vertical", "tube", "tube (vertical)" }, { "tube_horizontal", "tube", "tube (horizontal)" }, { "tube_vertical_left", "tube", "tube (vertical & left)" }, { "tube_vertical_right", "tube", "tube (vertical & right)" }, { "tube_horizontal_up", "tube", "tube (horizontal & up)" }, { "tube_horizontal_down", "tube", "tube (horizontal & down)" }, { "tube_left_up", "tube", "tube (left & up)" }, { "tube_left_down", "tube", "tube (left & down)" }, { "tube_right_up", "tube", "tube (right & up)" }, { "tube_right_down", "tube", "tube (right & down)" }, { "spring", "spring", "spring" }, { "trap", "trap", "trap" }, { "dx_supabomb", "bomb", "stable bomb (DX style)" }, { "unused_358", "unused", "-" }, { "unused_359", "unused", "-" }, { "custom_1", "custom", "custom element 1" }, { "custom_2", "custom", "custom element 2" }, { "custom_3", "custom", "custom element 3" }, { "custom_4", "custom", "custom element 4" }, { "custom_5", "custom", "custom element 5" }, { "custom_6", "custom", "custom element 6" }, { "custom_7", "custom", "custom element 7" }, { "custom_8", "custom", "custom element 8" }, { "custom_9", "custom", "custom element 9" }, { "custom_10", "custom", "custom element 10" }, { "custom_11", "custom", "custom element 11" }, { "custom_12", "custom", "custom element 12" }, { "custom_13", "custom", "custom element 13" }, { "custom_14", "custom", "custom element 14" }, { "custom_15", "custom", "custom element 15" }, { "custom_16", "custom", "custom element 16" }, { "custom_17", "custom", "custom element 17" }, { "custom_18", "custom", "custom element 18" }, { "custom_19", "custom", "custom element 19" }, { "custom_20", "custom", "custom element 20" }, { "custom_21", "custom", "custom element 21" }, { "custom_22", "custom", "custom element 22" }, { "custom_23", "custom", "custom element 23" }, { "custom_24", "custom", "custom element 24" }, { "custom_25", "custom", "custom element 25" }, { "custom_26", "custom", "custom element 26" }, { "custom_27", "custom", "custom element 27" }, { "custom_28", "custom", "custom element 28" }, { "custom_29", "custom", "custom element 29" }, { "custom_30", "custom", "custom element 30" }, { "custom_31", "custom", "custom element 31" }, { "custom_32", "custom", "custom element 32" }, { "custom_33", "custom", "custom element 33" }, { "custom_34", "custom", "custom element 34" }, { "custom_35", "custom", "custom element 35" }, { "custom_36", "custom", "custom element 36" }, { "custom_37", "custom", "custom element 37" }, { "custom_38", "custom", "custom element 38" }, { "custom_39", "custom", "custom element 39" }, { "custom_40", "custom", "custom element 40" }, { "custom_41", "custom", "custom element 41" }, { "custom_42", "custom", "custom element 42" }, { "custom_43", "custom", "custom element 43" }, { "custom_44", "custom", "custom element 44" }, { "custom_45", "custom", "custom element 45" }, { "custom_46", "custom", "custom element 46" }, { "custom_47", "custom", "custom element 47" }, { "custom_48", "custom", "custom element 48" }, { "custom_49", "custom", "custom element 49" }, { "custom_50", "custom", "custom element 50" }, { "custom_51", "custom", "custom element 51" }, { "custom_52", "custom", "custom element 52" }, { "custom_53", "custom", "custom element 53" }, { "custom_54", "custom", "custom element 54" }, { "custom_55", "custom", "custom element 55" }, { "custom_56", "custom", "custom element 56" }, { "custom_57", "custom", "custom element 57" }, { "custom_58", "custom", "custom element 58" }, { "custom_59", "custom", "custom element 59" }, { "custom_60", "custom", "custom element 60" }, { "custom_61", "custom", "custom element 61" }, { "custom_62", "custom", "custom element 62" }, { "custom_63", "custom", "custom element 63" }, { "custom_64", "custom", "custom element 64" }, { "custom_65", "custom", "custom element 65" }, { "custom_66", "custom", "custom element 66" }, { "custom_67", "custom", "custom element 67" }, { "custom_68", "custom", "custom element 68" }, { "custom_69", "custom", "custom element 69" }, { "custom_70", "custom", "custom element 70" }, { "custom_71", "custom", "custom element 71" }, { "custom_72", "custom", "custom element 72" }, { "custom_73", "custom", "custom element 73" }, { "custom_74", "custom", "custom element 74" }, { "custom_75", "custom", "custom element 75" }, { "custom_76", "custom", "custom element 76" }, { "custom_77", "custom", "custom element 77" }, { "custom_78", "custom", "custom element 78" }, { "custom_79", "custom", "custom element 79" }, { "custom_80", "custom", "custom element 80" }, { "custom_81", "custom", "custom element 81" }, { "custom_82", "custom", "custom element 82" }, { "custom_83", "custom", "custom element 83" }, { "custom_84", "custom", "custom element 84" }, { "custom_85", "custom", "custom element 85" }, { "custom_86", "custom", "custom element 86" }, { "custom_87", "custom", "custom element 87" }, { "custom_88", "custom", "custom element 88" }, { "custom_89", "custom", "custom element 89" }, { "custom_90", "custom", "custom element 90" }, { "custom_91", "custom", "custom element 91" }, { "custom_92", "custom", "custom element 92" }, { "custom_93", "custom", "custom element 93" }, { "custom_94", "custom", "custom element 94" }, { "custom_95", "custom", "custom element 95" }, { "custom_96", "custom", "custom element 96" }, { "custom_97", "custom", "custom element 97" }, { "custom_98", "custom", "custom element 98" }, { "custom_99", "custom", "custom element 99" }, { "custom_100", "custom", "custom element 100" }, { "custom_101", "custom", "custom element 101" }, { "custom_102", "custom", "custom element 102" }, { "custom_103", "custom", "custom element 103" }, { "custom_104", "custom", "custom element 104" }, { "custom_105", "custom", "custom element 105" }, { "custom_106", "custom", "custom element 106" }, { "custom_107", "custom", "custom element 107" }, { "custom_108", "custom", "custom element 108" }, { "custom_109", "custom", "custom element 109" }, { "custom_110", "custom", "custom element 110" }, { "custom_111", "custom", "custom element 111" }, { "custom_112", "custom", "custom element 112" }, { "custom_113", "custom", "custom element 113" }, { "custom_114", "custom", "custom element 114" }, { "custom_115", "custom", "custom element 115" }, { "custom_116", "custom", "custom element 116" }, { "custom_117", "custom", "custom element 117" }, { "custom_118", "custom", "custom element 118" }, { "custom_119", "custom", "custom element 119" }, { "custom_120", "custom", "custom element 120" }, { "custom_121", "custom", "custom element 121" }, { "custom_122", "custom", "custom element 122" }, { "custom_123", "custom", "custom element 123" }, { "custom_124", "custom", "custom element 124" }, { "custom_125", "custom", "custom element 125" }, { "custom_126", "custom", "custom element 126" }, { "custom_127", "custom", "custom element 127" }, { "custom_128", "custom", "custom element 128" }, { "custom_129", "custom", "custom element 129" }, { "custom_130", "custom", "custom element 130" }, { "custom_131", "custom", "custom element 131" }, { "custom_132", "custom", "custom element 132" }, { "custom_133", "custom", "custom element 133" }, { "custom_134", "custom", "custom element 134" }, { "custom_135", "custom", "custom element 135" }, { "custom_136", "custom", "custom element 136" }, { "custom_137", "custom", "custom element 137" }, { "custom_138", "custom", "custom element 138" }, { "custom_139", "custom", "custom element 139" }, { "custom_140", "custom", "custom element 140" }, { "custom_141", "custom", "custom element 141" }, { "custom_142", "custom", "custom element 142" }, { "custom_143", "custom", "custom element 143" }, { "custom_144", "custom", "custom element 144" }, { "custom_145", "custom", "custom element 145" }, { "custom_146", "custom", "custom element 146" }, { "custom_147", "custom", "custom element 147" }, { "custom_148", "custom", "custom element 148" }, { "custom_149", "custom", "custom element 149" }, { "custom_150", "custom", "custom element 150" }, { "custom_151", "custom", "custom element 151" }, { "custom_152", "custom", "custom element 152" }, { "custom_153", "custom", "custom element 153" }, { "custom_154", "custom", "custom element 154" }, { "custom_155", "custom", "custom element 155" }, { "custom_156", "custom", "custom element 156" }, { "custom_157", "custom", "custom element 157" }, { "custom_158", "custom", "custom element 158" }, { "custom_159", "custom", "custom element 159" }, { "custom_160", "custom", "custom element 160" }, { "custom_161", "custom", "custom element 161" }, { "custom_162", "custom", "custom element 162" }, { "custom_163", "custom", "custom element 163" }, { "custom_164", "custom", "custom element 164" }, { "custom_165", "custom", "custom element 165" }, { "custom_166", "custom", "custom element 166" }, { "custom_167", "custom", "custom element 167" }, { "custom_168", "custom", "custom element 168" }, { "custom_169", "custom", "custom element 169" }, { "custom_170", "custom", "custom element 170" }, { "custom_171", "custom", "custom element 171" }, { "custom_172", "custom", "custom element 172" }, { "custom_173", "custom", "custom element 173" }, { "custom_174", "custom", "custom element 174" }, { "custom_175", "custom", "custom element 175" }, { "custom_176", "custom", "custom element 176" }, { "custom_177", "custom", "custom element 177" }, { "custom_178", "custom", "custom element 178" }, { "custom_179", "custom", "custom element 179" }, { "custom_180", "custom", "custom element 180" }, { "custom_181", "custom", "custom element 181" }, { "custom_182", "custom", "custom element 182" }, { "custom_183", "custom", "custom element 183" }, { "custom_184", "custom", "custom element 184" }, { "custom_185", "custom", "custom element 185" }, { "custom_186", "custom", "custom element 186" }, { "custom_187", "custom", "custom element 187" }, { "custom_188", "custom", "custom element 188" }, { "custom_189", "custom", "custom element 189" }, { "custom_190", "custom", "custom element 190" }, { "custom_191", "custom", "custom element 191" }, { "custom_192", "custom", "custom element 192" }, { "custom_193", "custom", "custom element 193" }, { "custom_194", "custom", "custom element 194" }, { "custom_195", "custom", "custom element 195" }, { "custom_196", "custom", "custom element 196" }, { "custom_197", "custom", "custom element 197" }, { "custom_198", "custom", "custom element 198" }, { "custom_199", "custom", "custom element 199" }, { "custom_200", "custom", "custom element 200" }, { "custom_201", "custom", "custom element 201" }, { "custom_202", "custom", "custom element 202" }, { "custom_203", "custom", "custom element 203" }, { "custom_204", "custom", "custom element 204" }, { "custom_205", "custom", "custom element 205" }, { "custom_206", "custom", "custom element 206" }, { "custom_207", "custom", "custom element 207" }, { "custom_208", "custom", "custom element 208" }, { "custom_209", "custom", "custom element 209" }, { "custom_210", "custom", "custom element 210" }, { "custom_211", "custom", "custom element 211" }, { "custom_212", "custom", "custom element 212" }, { "custom_213", "custom", "custom element 213" }, { "custom_214", "custom", "custom element 214" }, { "custom_215", "custom", "custom element 215" }, { "custom_216", "custom", "custom element 216" }, { "custom_217", "custom", "custom element 217" }, { "custom_218", "custom", "custom element 218" }, { "custom_219", "custom", "custom element 219" }, { "custom_220", "custom", "custom element 220" }, { "custom_221", "custom", "custom element 221" }, { "custom_222", "custom", "custom element 222" }, { "custom_223", "custom", "custom element 223" }, { "custom_224", "custom", "custom element 224" }, { "custom_225", "custom", "custom element 225" }, { "custom_226", "custom", "custom element 226" }, { "custom_227", "custom", "custom element 227" }, { "custom_228", "custom", "custom element 228" }, { "custom_229", "custom", "custom element 229" }, { "custom_230", "custom", "custom element 230" }, { "custom_231", "custom", "custom element 231" }, { "custom_232", "custom", "custom element 232" }, { "custom_233", "custom", "custom element 233" }, { "custom_234", "custom", "custom element 234" }, { "custom_235", "custom", "custom element 235" }, { "custom_236", "custom", "custom element 236" }, { "custom_237", "custom", "custom element 237" }, { "custom_238", "custom", "custom element 238" }, { "custom_239", "custom", "custom element 239" }, { "custom_240", "custom", "custom element 240" }, { "custom_241", "custom", "custom element 241" }, { "custom_242", "custom", "custom element 242" }, { "custom_243", "custom", "custom element 243" }, { "custom_244", "custom", "custom element 244" }, { "custom_245", "custom", "custom element 245" }, { "custom_246", "custom", "custom element 246" }, { "custom_247", "custom", "custom element 247" }, { "custom_248", "custom", "custom element 248" }, { "custom_249", "custom", "custom element 249" }, { "custom_250", "custom", "custom element 250" }, { "custom_251", "custom", "custom element 251" }, { "custom_252", "custom", "custom element 252" }, { "custom_253", "custom", "custom element 253" }, { "custom_254", "custom", "custom element 254" }, { "custom_255", "custom", "custom element 255" }, { "custom_256", "custom", "custom element 256" }, { "em_key_1", "key", "key 1 (EM style)" }, { "em_key_2", "key", "key 2 (EM style)" }, { "em_key_3", "key", "key 3 (EM style)" }, { "em_key_4", "key", "key 4 (EM style)" }, { "envelope_1", "envelope", "mail envelope 1" }, { "envelope_2", "envelope", "mail envelope 2" }, { "envelope_3", "envelope", "mail envelope 3" }, { "envelope_4", "envelope", "mail envelope 4" }, { "group_1", "group", "group element 1" }, { "group_2", "group", "group element 2" }, { "group_3", "group", "group element 3" }, { "group_4", "group", "group element 4" }, { "group_5", "group", "group element 5" }, { "group_6", "group", "group element 6" }, { "group_7", "group", "group element 7" }, { "group_8", "group", "group element 8" }, { "group_9", "group", "group element 9" }, { "group_10", "group", "group element 10" }, { "group_11", "group", "group element 11" }, { "group_12", "group", "group element 12" }, { "group_13", "group", "group element 13" }, { "group_14", "group", "group element 14" }, { "group_15", "group", "group element 15" }, { "group_16", "group", "group element 16" }, { "group_17", "group", "group element 17" }, { "group_18", "group", "group element 18" }, { "group_19", "group", "group element 19" }, { "group_20", "group", "group element 20" }, { "group_21", "group", "group element 21" }, { "group_22", "group", "group element 22" }, { "group_23", "group", "group element 23" }, { "group_24", "group", "group element 24" }, { "group_25", "group", "group element 25" }, { "group_26", "group", "group element 26" }, { "group_27", "group", "group element 27" }, { "group_28", "group", "group element 28" }, { "group_29", "group", "group element 29" }, { "group_30", "group", "group element 30" }, { "group_31", "group", "group element 31" }, { "group_32", "group", "group element 32" }, { "unknown", "unknown", "unknown element" }, { "trigger_element", "trigger", "element triggering change" }, { "trigger_player", "trigger", "player triggering change" }, { "sp_gravity_on_port_right", "sp_gravity_on_port", "gravity-on port (leading right)" }, { "sp_gravity_on_port_down", "sp_gravity_on_port", "gravity-on port (leading down)" }, { "sp_gravity_on_port_left", "sp_gravity_on_port", "gravity-on port (leading left)" }, { "sp_gravity_on_port_up", "sp_gravity_on_port", "gravity-on port (leading up)" }, { "sp_gravity_off_port_right", "sp_gravity_off_port", "gravity-off port (leading right)" }, { "sp_gravity_off_port_down", "sp_gravity_off_port", "gravity-off port (leading down)" }, { "sp_gravity_off_port_left", "sp_gravity_off_port", "gravity-off port (leading left)" }, { "sp_gravity_off_port_up", "sp_gravity_off_port", "gravity-off port (leading up)" }, { "balloon_switch_none", "balloon_switch", "wind switch (off)" }, { "emc_gate_5", "gate", "door 5 (EMC style)", }, { "emc_gate_6", "gate", "door 6 (EMC style)", }, { "emc_gate_7", "gate", "door 7 (EMC style)", }, { "emc_gate_8", "gate", "door 8 (EMC style)", }, { "emc_gate_5_gray", "gate", "gray door (EMC style, key 5)", }, { "emc_gate_6_gray", "gate", "gray door (EMC style, key 6)", }, { "emc_gate_7_gray", "gate", "gray door (EMC style, key 7)", }, { "emc_gate_8_gray", "gate", "gray door (EMC style, key 8)", }, { "emc_key_5", "key", "key 5 (EMC style)", }, { "emc_key_6", "key", "key 6 (EMC style)", }, { "emc_key_7", "key", "key 7 (EMC style)", }, { "emc_key_8", "key", "key 8 (EMC style)", }, { "emc_android", "emc_android", "android", }, { "emc_grass", "emc_grass", "grass", }, { "emc_magic_ball", "emc_magic_ball", "magic ball", }, { "emc_magic_ball.active", "emc_magic_ball", "magic ball (activated)", }, { "emc_magic_ball_switch", "emc_magic_ball_switch", "magic ball switch (off)", }, { "emc_magic_ball_switch.active", "emc_magic_ball_switch", "magic ball switch (on)", }, { "emc_spring_bumper", "emc_spring_bumper", "spring bumper", }, { "emc_plant", "emc_plant", "plant", }, { "emc_lenses", "emc_lenses", "lenses", }, { "emc_magnifier", "emc_magnifier", "magnifier", }, { "emc_wall_9", "wall", "normal wall" }, { "emc_wall_10", "wall", "normal wall" }, { "emc_wall_11", "wall", "normal wall" }, { "emc_wall_12", "wall", "normal wall" }, { "emc_wall_13", "wall", "normal wall" }, { "emc_wall_14", "wall", "normal wall" }, { "emc_wall_15", "wall", "normal wall" }, { "emc_wall_16", "wall", "normal wall" }, { "emc_wall_slippery_1", "wall", "slippery wall" }, { "emc_wall_slippery_2", "wall", "slippery wall" }, { "emc_wall_slippery_3", "wall", "slippery wall" }, { "emc_wall_slippery_4", "wall", "slippery wall" }, { "emc_fake_grass", "fake_grass", "fake grass" }, { "emc_fake_acid", "fake_acid", "fake acid" }, { "emc_dripper", "dripper", "dripper" }, { "trigger_ce_value", "trigger", "CE value of element triggering change" }, { "trigger_ce_score", "trigger", "CE score of element triggering change" }, { "current_ce_value", "current", "CE value of current element" }, { "current_ce_score", "current", "CE score of current element" }, { "yamyam.left", "yamyam", "yam yam (starts moving left)" }, { "yamyam.right", "yamyam", "yam yam (starts moving right)" }, { "yamyam.up", "yamyam", "yam yam (starts moving up)" }, { "yamyam.down", "yamyam", "yam yam (starts moving down)" }, { "bd_expandable_wall", "wall", "growing wall (horizontal, BD style)" }, { "prev_ce_8", "prev_ce", "CE 8 positions earlier in list" }, { "prev_ce_7", "prev_ce", "CE 7 positions earlier in list" }, { "prev_ce_6", "prev_ce", "CE 6 positions earlier in list" }, { "prev_ce_5", "prev_ce", "CE 5 positions earlier in list" }, { "prev_ce_4", "prev_ce", "CE 4 positions earlier in list" }, { "prev_ce_3", "prev_ce", "CE 3 positions earlier in list" }, { "prev_ce_2", "prev_ce", "CE 2 positions earlier in list" }, { "prev_ce_1", "prev_ce", "CE 1 position earlier in list" }, { "self", "self", "the current custom element" }, { "next_ce_1", "next_ce", "CE 1 position later in list" }, { "next_ce_2", "next_ce", "CE 2 positions later in list" }, { "next_ce_3", "next_ce", "CE 3 positions later in list" }, { "next_ce_4", "next_ce", "CE 4 positions later in list" }, { "next_ce_5", "next_ce", "CE 5 positions later in list" }, { "next_ce_6", "next_ce", "CE 6 positions later in list" }, { "next_ce_7", "next_ce", "CE 7 positions later in list" }, { "next_ce_8", "next_ce", "CE 8 positions later in list" }, { "any_element", "any_element", "this element matches any element" }, { "steel_char_space", "steel_char", "steel letter ' '" }, { "steel_char_exclam", "steel_char", "steel letter '!'" }, { "steel_char_quotedbl", "steel_char", "steel letter '\"'" }, { "steel_char_numbersign", "steel_char", "steel letter '#'" }, { "steel_char_dollar", "steel_char", "steel letter '$'" }, { "steel_char_percent", "steel_char", "steel letter '%'" }, { "steel_char_ampersand", "steel_char", "steel letter '&'" }, { "steel_char_apostrophe", "steel_char", "steel letter '''" }, { "steel_char_parenleft", "steel_char", "steel letter '('" }, { "steel_char_parenright", "steel_char", "steel letter ')'" }, { "steel_char_asterisk", "steel_char", "steel letter '*'" }, { "steel_char_plus", "steel_char", "steel letter '+'" }, { "steel_char_comma", "steel_char", "steel letter ','" }, { "steel_char_minus", "steel_char", "steel letter '-'" }, { "steel_char_period", "steel_char", "steel letter '.'" }, { "steel_char_slash", "steel_char", "steel letter '/'" }, { "steel_char_0", "steel_char", "steel letter '0'" }, { "steel_char_1", "steel_char", "steel letter '1'" }, { "steel_char_2", "steel_char", "steel letter '2'" }, { "steel_char_3", "steel_char", "steel letter '3'" }, { "steel_char_4", "steel_char", "steel letter '4'" }, { "steel_char_5", "steel_char", "steel letter '5'" }, { "steel_char_6", "steel_char", "steel letter '6'" }, { "steel_char_7", "steel_char", "steel letter '7'" }, { "steel_char_8", "steel_char", "steel letter '8'" }, { "steel_char_9", "steel_char", "steel letter '9'" }, { "steel_char_colon", "steel_char", "steel letter ':'" }, { "steel_char_semicolon", "steel_char", "steel letter ';'" }, { "steel_char_less", "steel_char", "steel letter '<'" }, { "steel_char_equal", "steel_char", "steel letter '='" }, { "steel_char_greater", "steel_char", "steel letter '>'" }, { "steel_char_question", "steel_char", "steel letter '?'" }, { "steel_char_at", "steel_char", "steel letter '@'" }, { "steel_char_a", "steel_char", "steel letter 'A'" }, { "steel_char_b", "steel_char", "steel letter 'B'" }, { "steel_char_c", "steel_char", "steel letter 'C'" }, { "steel_char_d", "steel_char", "steel letter 'D'" }, { "steel_char_e", "steel_char", "steel letter 'E'" }, { "steel_char_f", "steel_char", "steel letter 'F'" }, { "steel_char_g", "steel_char", "steel letter 'G'" }, { "steel_char_h", "steel_char", "steel letter 'H'" }, { "steel_char_i", "steel_char", "steel letter 'I'" }, { "steel_char_j", "steel_char", "steel letter 'J'" }, { "steel_char_k", "steel_char", "steel letter 'K'" }, { "steel_char_l", "steel_char", "steel letter 'L'" }, { "steel_char_m", "steel_char", "steel letter 'M'" }, { "steel_char_n", "steel_char", "steel letter 'N'" }, { "steel_char_o", "steel_char", "steel letter 'O'" }, { "steel_char_p", "steel_char", "steel letter 'P'" }, { "steel_char_q", "steel_char", "steel letter 'Q'" }, { "steel_char_r", "steel_char", "steel letter 'R'" }, { "steel_char_s", "steel_char", "steel letter 'S'" }, { "steel_char_t", "steel_char", "steel letter 'T'" }, { "steel_char_u", "steel_char", "steel letter 'U'" }, { "steel_char_v", "steel_char", "steel letter 'V'" }, { "steel_char_w", "steel_char", "steel letter 'W'" }, { "steel_char_x", "steel_char", "steel letter 'X'" }, { "steel_char_y", "steel_char", "steel letter 'Y'" }, { "steel_char_z", "steel_char", "steel letter 'Z'" }, { "steel_char_bracketleft", "steel_char", "steel letter '['" }, { "steel_char_backslash", "steel_char", "steel letter '\\'" }, { "steel_char_bracketright", "steel_char", "steel letter ']'" }, { "steel_char_asciicircum", "steel_char", "steel letter '^'" }, { "steel_char_underscore", "steel_char", "steel letter '_'" }, { "steel_char_copyright", "steel_char", "steel letter '\xa9'" }, { "steel_char_aumlaut", "steel_char", "steel letter '\xc4'" }, { "steel_char_oumlaut", "steel_char", "steel letter '\xd6'" }, { "steel_char_uumlaut", "steel_char", "steel letter '\xdc'" }, { "steel_char_degree", "steel_char", "steel letter '\xb0'" }, { "steel_char_trademark", "steel_char", "steel letter '\xae'" }, { "steel_char_cursor", "steel_char", "steel letter '\xa0'" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter ''" }, { "steel_char_unused", "steel_char", "steel letter 'button'" }, { "steel_char_unused", "steel_char", "steel letter 'up'" }, { "steel_char_unused", "steel_char", "steel letter 'down'" }, { "sperms", "frankie", "sperms" }, { "bullet", "frankie", "bullet" }, { "heart", "frankie", "heart" }, { "cross", "frankie", "cross" }, { "frankie", "frankie", "frankie" }, { "sign_sperms", "sign", "sign (sperms)" }, { "sign_bullet", "sign", "sign (bullet)" }, { "sign_heart", "sign", "sign (heart)" }, { "sign_cross", "sign", "sign (cross)" }, { "sign_frankie", "sign", "sign (frankie)" }, { "steel_exit_closed", "steel_exit", "closed steel exit" }, { "steel_exit_open", "steel_exit", "open steel exit" }, { "dc_steelwall_1_left", "steelwall", "steel wall (left)" }, { "dc_steelwall_1_right", "steelwall", "steel wall (right)" }, { "dc_steelwall_1_top", "steelwall", "steel wall (top)" }, { "dc_steelwall_1_bottom", "steelwall", "steel wall (bottom)" }, { "dc_steelwall_1_horizontal", "steelwall", "steel wall (top/bottom)" }, { "dc_steelwall_1_vertical", "steelwall", "steel wall (left/right)" }, { "dc_steelwall_1_topleft", "steelwall", "steel wall (top/left)" }, { "dc_steelwall_1_topright", "steelwall", "steel wall (top/right)" }, { "dc_steelwall_1_bottomleft", "steelwall", "steel wall (bottom/left)" }, { "dc_steelwall_1_bottomright", "steelwall", "steel wall (bottom/right)" }, { "dc_steelwall_1_topleft_2", "steelwall", "steel wall (top/left corner)" }, { "dc_steelwall_1_topright_2", "steelwall", "steel wall (top/right corner)" }, { "dc_steelwall_1_bottomleft_2", "steelwall", "steel wall (bottom/left corner)" }, { "dc_steelwall_1_bottomright_2", "steelwall", "steel wall (bottom/right corner)" }, { "dc_steelwall_2_left", "steelwall", "steel wall (left)" }, { "dc_steelwall_2_right", "steelwall", "steel wall (right)" }, { "dc_steelwall_2_top", "steelwall", "steel wall (top)" }, { "dc_steelwall_2_bottom", "steelwall", "steel wall (bottom)" }, { "dc_steelwall_2_horizontal", "steelwall", "steel wall (horizontal)" }, { "dc_steelwall_2_vertical", "steelwall", "steel wall (vertical)" }, { "dc_steelwall_2_middle", "steelwall", "steel wall (middle)" }, { "dc_steelwall_2_single", "steelwall", "steel wall (single)" }, { "dc_switchgate_switch_up", "switchgate_switch", "switch for switch gate (steel)" }, { "dc_switchgate_switch_down", "switchgate_switch", "switch for switch gate (steel)" }, { "dc_timegate_switch", "timegate_switch", "switch for time gate (steel)" }, { "dc_timegate_switch.active", "timegate_switch", "switch for time gate (steel)" }, { "dc_landmine", "dc_landmine", "land mine (DC style, removable)" }, { "expandable_steelwall", "steelwall", "growing steel wall" }, { "expandable_steelwall_horizontal", "steelwall", "growing steel wall (horizontal)" }, { "expandable_steelwall_vertical", "steelwall", "growing steel wall (vertical)" }, { "expandable_steelwall_any", "steelwall", "growing steel wall (any direction)" }, { "em_exit_closed", "em_exit", "closed exit (EM style)" }, { "em_exit_open", "em_exit", "open exit (EM style)" }, { "em_steel_exit_closed", "em_steel_exit", "closed steel exit (EM style)" }, { "em_steel_exit_open", "em_steel_exit", "open steel exit (EM style)" }, { "dc_gate_fake_gray", "gate", "gray door (opened by no key)" }, { "dc_magic_wall", "dc_magic_wall", "magic wall (DC style)" }, { "quicksand_fast_empty", "quicksand", "fast quicksand (empty)" }, { "quicksand_fast_full", "quicksand", "fast quicksand (with rock)" }, { "from_level_template", "from_level_template", "element taken from level template" }, { "mm_empty_space", "empty_space", "empty space" }, { "mm_mirror_1", "mm_mirror", "mirror (0\xb0)" }, { "mm_mirror_2", "mm_mirror", "mirror (11.25\xb0)" }, { "mm_mirror_3", "mm_mirror", "mirror (22.5\xb0)" }, { "mm_mirror_4", "mm_mirror", "mirror (33.75\xb0)" }, { "mm_mirror_5", "mm_mirror", "mirror (45\xb0)" }, { "mm_mirror_6", "mm_mirror", "mirror (56.25\xb0)" }, { "mm_mirror_7", "mm_mirror", "mirror (67.5\xb0)" }, { "mm_mirror_8", "mm_mirror", "mirror (78.75\xb0)" }, { "mm_mirror_9", "mm_mirror", "mirror (90\xb0)" }, { "mm_mirror_10", "mm_mirror", "mirror (101.25\xb0)" }, { "mm_mirror_11", "mm_mirror", "mirror (112.5\xb0)" }, { "mm_mirror_12", "mm_mirror", "mirror (123.75\xb0)" }, { "mm_mirror_13", "mm_mirror", "mirror (135\xb0)" }, { "mm_mirror_14", "mm_mirror", "mirror (146.25\xb0)" }, { "mm_mirror_15", "mm_mirror", "mirror (157.5\xb0)" }, { "mm_mirror_16", "mm_mirror", "mirror (168.75\xb0)" }, { "mm_steel_grid_fixed_1", "mm_steel_grid_fixed", "fixed steel polarizer (0\xb0)" }, { "mm_steel_grid_fixed_2", "mm_steel_grid_fixed", "fixed steel polarizer (90\xb0)" }, { "mm_steel_grid_fixed_3", "mm_steel_grid_fixed", "fixed steel polarizer (45\xb0)" }, { "mm_steel_grid_fixed_4", "mm_steel_grid_fixed", "fixed steel polarizer (135\xb0)" }, { "mm_mcduffin.right", "mm_mcduffin", "Gregor McDuffin (looking right)" }, { "mm_mcduffin.up", "mm_mcduffin", "Gregor McDuffin (looking up)" }, { "mm_mcduffin.left", "mm_mcduffin", "Gregor McDuffin (looking left)" }, { "mm_mcduffin.down", "mm_mcduffin", "Gregor McDuffin (looking down)" }, { "mm_exit_closed", "mm_exit", "closed exit (MM style)" }, { "mm_exit_opening_1", "mm_exit", "opening exit 1" }, { "mm_exit_opening_2", "mm_exit", "opening exit 2" }, { "mm_exit_open", "mm_exit", "open exit (MM style)" }, { "mm_kettle", "mm_kettle", "magic kettle" }, { "mm_bomb", "mm_bomb", "bomb (MM style)" }, { "mm_prism", "mm_prism", "prism" }, { "mm_steel_wall_1", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_2", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_3", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_4", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_5", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_6", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_7", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_8", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_9", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_10", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_11", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_12", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_13", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_14", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_15", "mm_steel_wall", "steel wall" }, { "mm_steel_wall_16", "mm_steel_wall", "steel wall" }, { "mm_wooden_wall_1", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_2", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_3", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_4", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_5", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_6", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_7", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_8", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_9", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_10", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_11", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_12", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_13", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_14", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_15", "mm_wooden_wall", "wooden wall" }, { "mm_wooden_wall_16", "mm_wooden_wall", "wooden wall" }, { "mm_ice_wall_1", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_2", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_3", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_4", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_5", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_6", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_7", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_8", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_9", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_10", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_11", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_12", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_13", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_14", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_15", "mm_ice_wall", "ice wall" }, { "mm_ice_wall_16", "mm_ice_wall", "ice wall" }, { "mm_amoeba_wall_1", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_2", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_3", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_4", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_5", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_6", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_7", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_8", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_9", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_10", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_11", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_12", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_13", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_14", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_15", "mm_amoeba_wall", "amoeba wall" }, { "mm_amoeba_wall_16", "mm_amoeba_wall", "amoeba wall" }, { "mm_wooden_block", "mm_wooden_block", "wooden block" }, { "mm_gray_ball", "mm_gray_ball", "gray ball" }, { "mm_teleporter_1", "mm_teleporter", "teleporter (0\xb0)" }, { "mm_teleporter_2", "mm_teleporter", "teleporter (22.5\xb0)" }, { "mm_teleporter_3", "mm_teleporter", "teleporter (45\xb0)" }, { "mm_teleporter_4", "mm_teleporter", "teleporter (67.5\xb0)" }, { "mm_teleporter_5", "mm_teleporter", "teleporter (90\xb0)" }, { "mm_teleporter_6", "mm_teleporter", "teleporter (112.5\xb0)" }, { "mm_teleporter_7", "mm_teleporter", "teleporter (135\xb0)" }, { "mm_teleporter_8", "mm_teleporter", "teleporter (157.5\xb0)" }, { "mm_teleporter_9", "mm_teleporter", "teleporter (180\xb0)" }, { "mm_teleporter_10", "mm_teleporter", "teleporter (202.5\xb0)" }, { "mm_teleporter_11", "mm_teleporter", "teleporter (225\xb0)" }, { "mm_teleporter_12", "mm_teleporter", "teleporter (247.5\xb0)" }, { "mm_teleporter_13", "mm_teleporter", "teleporter (270\xb0)" }, { "mm_teleporter_14", "mm_teleporter", "teleporter (292.5\xb0)" }, { "mm_teleporter_15", "mm_teleporter", "teleporter (315\xb0)" }, { "mm_teleporter_16", "mm_teleporter", "teleporter (337.5\xb0)" }, { "mm_fuse.active", "mm_fuse", "fuse (on)" }, { "mm_pacman.right", "mm_pacman", "pac man (starts moving right)" }, { "mm_pacman.up", "mm_pacman", "pac man (starts moving up)" }, { "mm_pacman.left", "mm_pacman", "pac man (starts moving left)" }, { "mm_pacman.down", "mm_pacman", "pac man (starts moving down)" }, { "mm_polarizer_1", "mm_polarizer", "polarizer (0\xb0)" }, { "mm_polarizer_2", "mm_polarizer", "polarizer (11.25\xb0)" }, { "mm_polarizer_3", "mm_polarizer", "polarizer (22.5\xb0)" }, { "mm_polarizer_4", "mm_polarizer", "polarizer (33.75\xb0)" }, { "mm_polarizer_5", "mm_polarizer", "polarizer (45\xb0)" }, { "mm_polarizer_6", "mm_polarizer", "polarizer (56.25\xb0)" }, { "mm_polarizer_7", "mm_polarizer", "polarizer (67.5\xb0)" }, { "mm_polarizer_8", "mm_polarizer", "polarizer (78.75\xb0)" }, { "mm_polarizer_9", "mm_polarizer", "polarizer (90\xb0)" }, { "mm_polarizer_10", "mm_polarizer", "polarizer (101.25\xb0)" }, { "mm_polarizer_11", "mm_polarizer", "polarizer (112.5\xb0)" }, { "mm_polarizer_12", "mm_polarizer", "polarizer (123.75\xb0)" }, { "mm_polarizer_13", "mm_polarizer", "polarizer (135\xb0)" }, { "mm_polarizer_14", "mm_polarizer", "polarizer (146.25\xb0)" }, { "mm_polarizer_15", "mm_polarizer", "polarizer (157.5\xb0)" }, { "mm_polarizer_16", "mm_polarizer", "polarizer (168.75\xb0)" }, { "mm_polarizer_cross_1", "mm_polarizer_cross", "two-way polarizer (0\xb0)" }, { "mm_polarizer_cross_2", "mm_polarizer_cross", "two-way polarizer (22.5\xb0)" }, { "mm_polarizer_cross_3", "mm_polarizer_cross", "two-way polarizer (45\xb0)" }, { "mm_polarizer_cross_4", "mm_polarizer_cross", "two-way polarizer (67.5\xb0)" }, { "mm_mirror_fixed_1", "mm_mirror_fixed", "fixed mirror (0\xb0)" }, { "mm_mirror_fixed_2", "mm_mirror_fixed", "fixed mirror (0\xb0)" }, { "mm_mirror_fixed_3", "mm_mirror_fixed", "fixed mirror (0\xb0)" }, { "mm_mirror_fixed_4", "mm_mirror_fixed", "fixed mirror (0\xb0)" }, { "mm_steel_lock", "mm_steel_lock", "steel lock" }, { "mm_key", "mm_key", "key (MM style)" }, { "mm_lightbulb", "mm_lightbulb", "light bulb (off)" }, { "mm_lightbulb.active", "mm_lightbulb", "light bulb (on)" }, { "mm_lightball", "mm_lightball", "bonus ball" }, { "mm_steel_block", "mm_steel_block", "steel block" }, { "mm_wooden_lock", "mm_wooden_lock", "wooden lock" }, { "mm_fuel_full", "mm_fuel", "extra energy ball (full)" }, { "mm_wooden_grid_fixed_1", "mm_wooden_grid_fixed", "fixed wooden polarizer (0\xb0)" }, { "mm_wooden_grid_fixed_2", "mm_wooden_grid_fixed", "fixed wooden polarizer (90\xb0)" }, { "mm_wooden_grid_fixed_3", "mm_wooden_grid_fixed", "fixed wooden polarizer (45\xb0)" }, { "mm_wooden_grid_fixed_4", "mm_wooden_grid_fixed", "fixed wooden polarizer (135\xb0)" }, { "mm_fuel_empty", "mm_fuel", "extra energy ball (empty)" }, { "mm_unused_156", "unused", "(not used)" }, { "mm_unused_157", "unused", "(not used)" }, { "mm_unused_158", "unused", "(not used)" }, { "mm_unused_159", "unused", "(not used)" }, { "df_mirror_1", "df_mirror", "mirror (DF style) (0\xb0)" }, { "df_mirror_2", "df_mirror", "mirror (DF style) (11.25\xb0)" }, { "df_mirror_3", "df_mirror", "mirror (DF style) (22.5\xb0)" }, { "df_mirror_4", "df_mirror", "mirror (DF style) (33.75\xb0)" }, { "df_mirror_5", "df_mirror", "mirror (DF style) (45\xb0)" }, { "df_mirror_6", "df_mirror", "mirror (DF style) (56.25\xb0)" }, { "df_mirror_7", "df_mirror", "mirror (DF style) (67.5\xb0)" }, { "df_mirror_8", "df_mirror", "mirror (DF style) (78.75\xb0)" }, { "df_mirror_9", "df_mirror", "mirror (DF style) (90\xb0)" }, { "df_mirror_10", "df_mirror", "mirror (DF style) (101.25\xb0)" }, { "df_mirror_11", "df_mirror", "mirror (DF style) (112.5\xb0)" }, { "df_mirror_12", "df_mirror", "mirror (DF style) (123.75\xb0)" }, { "df_mirror_13", "df_mirror", "mirror (DF style) (135\xb0)" }, { "df_mirror_14", "df_mirror", "mirror (DF style) (146.25\xb0)" }, { "df_mirror_15", "df_mirror", "mirror (DF style) (157.5\xb0)" }, { "df_mirror_16", "df_mirror", "mirror (DF style) (168.75\xb0)" }, { "df_wooden_grid_fixed_1", "df_wooden_grid_fixed", "fixed wooden polarizer (0\xb0)" }, { "df_wooden_grid_fixed_2", "df_wooden_grid_fixed", "fixed wooden polarizer (22.5\xb0)" }, { "df_wooden_grid_fixed_3", "df_wooden_grid_fixed", "fixed wooden polarizer (45\xb0)" }, { "df_wooden_grid_fixed_4", "df_wooden_grid_fixed", "fixed wooden polarizer (67.5\xb0)" }, { "df_wooden_grid_fixed_5", "df_wooden_grid_fixed", "fixed wooden polarizer (90\xb0)" }, { "df_wooden_grid_fixed_6", "df_wooden_grid_fixed", "fixed wooden polarizer (112.5\xb0)" }, { "df_wooden_grid_fixed_7", "df_wooden_grid_fixed", "fixed wooden polarizer (135\xb0)" }, { "df_wooden_grid_fixed_8", "df_wooden_grid_fixed", "fixed wooden polarizer (157.5\xb0)" }, { "df_steel_grid_fixed_1", "df_steel_grid_fixed", "fixed steel polarizer (0\xb0)" }, { "df_steel_grid_fixed_2", "df_steel_grid_fixed", "fixed steel polarizer (22.5\xb0)" }, { "df_steel_grid_fixed_3", "df_steel_grid_fixed", "fixed steel polarizer (45\xb0)" }, { "df_steel_grid_fixed_4", "df_steel_grid_fixed", "fixed steel polarizer (67.5\xb0)" }, { "df_steel_grid_fixed_5", "df_steel_grid_fixed", "fixed steel polarizer (90\xb0)" }, { "df_steel_grid_fixed_6", "df_steel_grid_fixed", "fixed steel polarizer (112.5\xb0)" }, { "df_steel_grid_fixed_7", "df_steel_grid_fixed", "fixed steel polarizer (135\xb0)" }, { "df_steel_grid_fixed_8", "df_steel_grid_fixed", "fixed steel polarizer (157.5\xb0)" }, { "df_wooden_wall_1", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_2", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_3", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_4", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_5", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_6", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_7", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_8", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_9", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_10", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_11", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_12", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_13", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_14", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_15", "df_wooden_wall", "wooden wall (DF style)" }, { "df_wooden_wall_16", "df_wooden_wall", "wooden wall (DF style)" }, { "df_steel_wall_1", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_2", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_3", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_4", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_5", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_6", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_7", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_8", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_9", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_10", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_11", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_12", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_13", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_14", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_15", "df_steel_wall", "steel wall (DF style)" }, { "df_steel_wall_16", "df_steel_wall", "steel wall (DF style)" }, { "df_empty_space", "empty_space", "empty space" }, { "df_cell", "df_cell", "cell" }, { "df_mine", "df_mine", "mine" }, { "df_refractor", "df_refractor", "refractor" }, { "df_laser.right", "df_laser", "laser cannon (shooting right)" }, { "df_laser.up", "df_laser", "laser cannon (shooting up)" }, { "df_laser.left", "df_laser", "laser cannon (shooting left)" }, { "df_laser.down", "df_laser", "laser cannon (shooting down)" }, { "df_receiver.right", "df_receiver", "laser receiver (directed right)" }, { "df_receiver.up", "df_receiver", "laser receiver (directed up)" }, { "df_receiver.left", "df_receiver", "laser receiver (directed left)" }, { "df_receiver.down", "df_receiver", "laser receiver (directed down)" }, { "df_fibre_optic_red_1", "df_fibre_optic", "red fibre optic (part 1)" }, { "df_fibre_optic_red_2", "df_fibre_optic", "red fibre optic (part 2)" }, { "df_fibre_optic_yellow_1", "df_fibre_optic", "yellow fibre optic (part 1)" }, { "df_fibre_optic_yellow_2", "df_fibre_optic", "yellow fibre optic (part 2)" }, { "df_fibre_optic_green_1", "df_fibre_optic", "green fibre optic (part 1)" }, { "df_fibre_optic_green_2", "df_fibre_optic", "green fibre optic (part 2)" }, { "df_fibre_optic_blue_1", "df_fibre_optic", "blue fibre optic (part 1)" }, { "df_fibre_optic_blue_2", "df_fibre_optic", "blue fibre optic (part 2)" }, { "df_mirror_rotating_1", "df_mirror_rotating", "rotating mirror (0\xb0)" }, { "df_mirror_rotating_2", "df_mirror_rotating", "rotating mirror (11.25\xb0)" }, { "df_mirror_rotating_3", "df_mirror_rotating", "rotating mirror (22.5\xb0)" }, { "df_mirror_rotating_4", "df_mirror_rotating", "rotating mirror (33.75\xb0)" }, { "df_mirror_rotating_5", "df_mirror_rotating", "rotating mirror (45\xb0)" }, { "df_mirror_rotating_6", "df_mirror_rotating", "rotating mirror (56.25\xb0)" }, { "df_mirror_rotating_7", "df_mirror_rotating", "rotating mirror (67.5\xb0)" }, { "df_mirror_rotating_8", "df_mirror_rotating", "rotating mirror (78.75\xb0)" }, { "df_mirror_rotating_9", "df_mirror_rotating", "rotating mirror (90\xb0)" }, { "df_mirror_rotating_10", "df_mirror_rotating", "rotating mirror (101.25\xb0)" }, { "df_mirror_rotating_11", "df_mirror_rotating", "rotating mirror (112.5\xb0)" }, { "df_mirror_rotating_12", "df_mirror_rotating", "rotating mirror (123.75\xb0)" }, { "df_mirror_rotating_13", "df_mirror_rotating", "rotating mirror (135\xb0)" }, { "df_mirror_rotating_14", "df_mirror_rotating", "rotating mirror (146.25\xb0)" }, { "df_mirror_rotating_15", "df_mirror_rotating", "rotating mirror (157.5\xb0)" }, { "df_mirror_rotating_16", "df_mirror_rotating", "rotating mirror (168.75\xb0)" }, { "df_wooden_grid_rotating_1", "df_wooden_grid_rotating", "rotating wooden polarizer (0\xb0)" }, { "df_wooden_grid_rotating_2", "df_wooden_grid_rotating", "rotating wooden polarizer (22.5\xb0)" }, { "df_wooden_grid_rotating_3", "df_wooden_grid_rotating", "rotating wooden polarizer (45\xb0)" }, { "df_wooden_grid_rotating_4", "df_wooden_grid_rotating", "rotating wooden polarizer (67.5\xb0)" }, { "df_wooden_grid_rotating_5", "df_wooden_grid_rotating", "rotating wooden polarizer (90\xb0)" }, { "df_wooden_grid_rotating_6", "df_wooden_grid_rotating", "rotating wooden polarizer (112.5\xb0)" }, { "df_wooden_grid_rotating_7", "df_wooden_grid_rotating", "rotating wooden polarizer (135\xb0)" }, { "df_wooden_grid_rotating_8", "df_wooden_grid_rotating", "rotating wooden polarizer (157.5\xb0)" }, { "df_steel_grid_rotating_1", "df_steel_grid_rotating", "rotating steel polarizer (0\xb0)" }, { "df_steel_grid_rotating_2", "df_steel_grid_rotating", "rotating steel polarizer (22.5\xb0)" }, { "df_steel_grid_rotating_3", "df_steel_grid_rotating", "rotating steel polarizer (45\xb0)" }, { "df_steel_grid_rotating_4", "df_steel_grid_rotating", "rotating steel polarizer (67.5\xb0)" }, { "df_steel_grid_rotating_5", "df_steel_grid_rotating", "rotating steel polarizer (90\xb0)" }, { "df_steel_grid_rotating_6", "df_steel_grid_rotating", "rotating steel polarizer (112.5\xb0)" }, { "df_steel_grid_rotating_7", "df_steel_grid_rotating", "rotating steel polarizer (135\xb0)" }, { "df_steel_grid_rotating_8", "df_steel_grid_rotating", "rotating steel polarizer (157.5\xb0)" }, { "mm_teleporter_red_1", "mm_teleporter", "red teleporter (0\xb0)" }, { "mm_teleporter_red_2", "mm_teleporter", "red teleporter (22.5\xb0)" }, { "mm_teleporter_red_3", "mm_teleporter", "red teleporter (45\xb0)" }, { "mm_teleporter_red_4", "mm_teleporter", "red teleporter (67.5\xb0)" }, { "mm_teleporter_red_5", "mm_teleporter", "red teleporter (90\xb0)" }, { "mm_teleporter_red_6", "mm_teleporter", "red teleporter (112.5\xb0)" }, { "mm_teleporter_red_7", "mm_teleporter", "red teleporter (135\xb0)" }, { "mm_teleporter_red_8", "mm_teleporter", "red teleporter (157.5\xb0)" }, { "mm_teleporter_red_9", "mm_teleporter", "red teleporter (180\xb0)" }, { "mm_teleporter_red_10", "mm_teleporter", "red teleporter (202.5\xb0)" }, { "mm_teleporter_red_11", "mm_teleporter", "red teleporter (225\xb0)" }, { "mm_teleporter_red_12", "mm_teleporter", "red teleporter (247.5\xb0)" }, { "mm_teleporter_red_13", "mm_teleporter", "red teleporter (270\xb0)" }, { "mm_teleporter_red_14", "mm_teleporter", "red teleporter (292.5\xb0)" }, { "mm_teleporter_red_15", "mm_teleporter", "red teleporter (315\xb0)" }, { "mm_teleporter_red_16", "mm_teleporter", "red teleporter (337.5\xb0)" }, { "mm_teleporter_yellow_1", "mm_teleporter", "yellow teleporter (0\xb0)" }, { "mm_teleporter_yellow_2", "mm_teleporter", "yellow teleporter (22.5\xb0)" }, { "mm_teleporter_yellow_3", "mm_teleporter", "yellow teleporter (45\xb0)" }, { "mm_teleporter_yellow_4", "mm_teleporter", "yellow teleporter (67.5\xb0)" }, { "mm_teleporter_yellow_5", "mm_teleporter", "yellow teleporter (90\xb0)" }, { "mm_teleporter_yellow_6", "mm_teleporter", "yellow teleporter (112.5\xb0)" }, { "mm_teleporter_yellow_7", "mm_teleporter", "yellow teleporter (135\xb0)" }, { "mm_teleporter_yellow_8", "mm_teleporter", "yellow teleporter (157.5\xb0)" }, { "mm_teleporter_yellow_9", "mm_teleporter", "yellow teleporter (180\xb0)" }, { "mm_teleporter_yellow_10", "mm_teleporter", "yellow teleporter (202.5\xb0)" }, { "mm_teleporter_yellow_11", "mm_teleporter", "yellow teleporter (225\xb0)" }, { "mm_teleporter_yellow_12", "mm_teleporter", "yellow teleporter (247.5\xb0)" }, { "mm_teleporter_yellow_13", "mm_teleporter", "yellow teleporter (270\xb0)" }, { "mm_teleporter_yellow_14", "mm_teleporter", "yellow teleporter (292.5\xb0)" }, { "mm_teleporter_yellow_15", "mm_teleporter", "yellow teleporter (315\xb0)" }, { "mm_teleporter_yellow_16", "mm_teleporter", "yellow teleporter (337.5\xb0)" }, { "mm_teleporter_green_1", "mm_teleporter", "green teleporter (0\xb0)" }, { "mm_teleporter_green_2", "mm_teleporter", "green teleporter (22.5\xb0)" }, { "mm_teleporter_green_3", "mm_teleporter", "green teleporter (45\xb0)" }, { "mm_teleporter_green_4", "mm_teleporter", "green teleporter (67.5\xb0)" }, { "mm_teleporter_green_5", "mm_teleporter", "green teleporter (90\xb0)" }, { "mm_teleporter_green_6", "mm_teleporter", "green teleporter (112.5\xb0)" }, { "mm_teleporter_green_7", "mm_teleporter", "green teleporter (135\xb0)" }, { "mm_teleporter_green_8", "mm_teleporter", "green teleporter (157.5\xb0)" }, { "mm_teleporter_green_9", "mm_teleporter", "green teleporter (180\xb0)" }, { "mm_teleporter_green_10", "mm_teleporter", "green teleporter (202.5\xb0)" }, { "mm_teleporter_green_11", "mm_teleporter", "green teleporter (225\xb0)" }, { "mm_teleporter_green_12", "mm_teleporter", "green teleporter (247.5\xb0)" }, { "mm_teleporter_green_13", "mm_teleporter", "green teleporter (270\xb0)" }, { "mm_teleporter_green_14", "mm_teleporter", "green teleporter (292.5\xb0)" }, { "mm_teleporter_green_15", "mm_teleporter", "green teleporter (315\xb0)" }, { "mm_teleporter_green_16", "mm_teleporter", "green teleporter (337.5\xb0)" }, { "mm_teleporter_blue_1", "mm_teleporter", "blue teleporter (0\xb0)" }, { "mm_teleporter_blue_2", "mm_teleporter", "blue teleporter (22.5\xb0)" }, { "mm_teleporter_blue_3", "mm_teleporter", "blue teleporter (45\xb0)" }, { "mm_teleporter_blue_4", "mm_teleporter", "blue teleporter (67.5\xb0)" }, { "mm_teleporter_blue_5", "mm_teleporter", "blue teleporter (90\xb0)" }, { "mm_teleporter_blue_6", "mm_teleporter", "blue teleporter (112.5\xb0)" }, { "mm_teleporter_blue_7", "mm_teleporter", "blue teleporter (135\xb0)" }, { "mm_teleporter_blue_8", "mm_teleporter", "blue teleporter (157.5\xb0)" }, { "mm_teleporter_blue_9", "mm_teleporter", "blue teleporter (180\xb0)" }, { "mm_teleporter_blue_10", "mm_teleporter", "blue teleporter (202.5\xb0)" }, { "mm_teleporter_blue_11", "mm_teleporter", "blue teleporter (225\xb0)" }, { "mm_teleporter_blue_12", "mm_teleporter", "blue teleporter (247.5\xb0)" }, { "mm_teleporter_blue_13", "mm_teleporter", "blue teleporter (270\xb0)" }, { "mm_teleporter_blue_14", "mm_teleporter", "blue teleporter (292.5\xb0)" }, { "mm_teleporter_blue_15", "mm_teleporter", "blue teleporter (315\xb0)" }, { "mm_teleporter_blue_16", "mm_teleporter", "blue teleporter (337.5\xb0)" }, { "mm_mcduffin", "mm_mcduffin", "Gregor McDuffin" }, { "mm_pacman", "mm_pacman", "pac man (MM style)" }, { "mm_fuse", "mm_fuse", "fuse (off)", }, { "mm_steel_wall", "mm_steel_wall", "steel wall", }, { "mm_wooden_wall", "mm_wooden_wall", "wooden wall", }, { "mm_ice_wall", "mm_ice_wall", "ice wall", }, { "mm_amoeba_wall", "mm_amoeba_wall", "amoeba wall", }, { "df_laser", "df_laser", "laser cannon" }, { "df_receiver", "df_receiver", "laser receiver" }, { "df_steel_wall", "df_steel_wall", "steel wall (DF style)", }, { "df_wooden_wall", "df_wooden_wall", "wooden wall (DF style)", }, /* ----------------------------------------------------------------------- */ /* "real" (and therefore drawable) runtime elements */ /* ----------------------------------------------------------------------- */ { "dynabomb_player_1.active", "dynabomb", "-" }, { "dynabomb_player_2.active", "dynabomb", "-" }, { "dynabomb_player_3.active", "dynabomb", "-" }, { "dynabomb_player_4.active", "dynabomb", "-" }, { "sp_disk_red.active", "dynamite", "-" }, { "switchgate.opening", "switchgate", "-" }, { "switchgate.closing", "switchgate", "-" }, { "timegate.opening", "timegate", "-" }, { "timegate.closing", "timegate", "-" }, { "pearl.breaking", "pearl", "-" }, { "trap.active", "trap", "-" }, { "invisible_steelwall.active", "steelwall", "-" }, { "invisible_wall.active", "wall", "-" }, { "invisible_sand.active", "sand", "-" }, { "conveyor_belt_1_left.active", "conveyor_belt", "-" }, { "conveyor_belt_1_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_1_right.active", "conveyor_belt", "-" }, { "conveyor_belt_2_left.active", "conveyor_belt", "-" }, { "conveyor_belt_2_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_2_right.active", "conveyor_belt", "-" }, { "conveyor_belt_3_left.active", "conveyor_belt", "-" }, { "conveyor_belt_3_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_3_right.active", "conveyor_belt", "-" }, { "conveyor_belt_4_left.active", "conveyor_belt", "-" }, { "conveyor_belt_4_middle.active", "conveyor_belt", "-" }, { "conveyor_belt_4_right.active", "conveyor_belt", "-" }, { "exit.opening", "exit", "-" }, { "exit.closing", "exit", "-" }, { "steel_exit.opening", "steel_exit", "-" }, { "steel_exit.closing", "steel_exit", "-" }, { "em_exit.opening", "em_exit", "-" }, { "em_exit.closing", "em_exit", "-" }, { "em_steel_exit.opening", "em_steel_exit", "-" }, { "em_steel_exit.closing", "em_steel_exit", "-" }, { "sp_exit.opening", "sp_exit", "-" }, { "sp_exit.closing", "sp_exit", "-" }, { "sp_exit_open", "sp_exit", "-" }, { "sp_terminal.active", "sp_terminal", "-" }, { "sp_buggy_base.activating", "sp_buggy_base", "-" }, { "sp_buggy_base.active", "sp_buggy_base", "-" }, { "sp_murphy_clone", "murphy_clone", "-" }, { "amoeba.dropping", "amoeba", "-" }, { "quicksand.emptying", "quicksand", "-" }, { "quicksand_fast.emptying", "quicksand", "-" }, { "magic_wall.active", "magic_wall", "-" }, { "bd_magic_wall.active", "magic_wall", "-" }, { "dc_magic_wall.active", "magic_wall", "-" }, { "magic_wall_full", "magic_wall", "-" }, { "bd_magic_wall_full", "magic_wall", "-" }, { "dc_magic_wall_full", "magic_wall", "-" }, { "magic_wall.emptying", "magic_wall", "-" }, { "bd_magic_wall.emptying", "magic_wall", "-" }, { "dc_magic_wall.emptying", "magic_wall", "-" }, { "magic_wall_dead", "magic_wall", "-" }, { "bd_magic_wall_dead", "magic_wall", "-" }, { "dc_magic_wall_dead", "magic_wall", "-" }, { "emc_fake_grass.active", "fake_grass", "-" }, { "gate_1_gray.active", "gate", "" }, { "gate_2_gray.active", "gate", "" }, { "gate_3_gray.active", "gate", "" }, { "gate_4_gray.active", "gate", "" }, { "em_gate_1_gray.active", "gate", "" }, { "em_gate_2_gray.active", "gate", "" }, { "em_gate_3_gray.active", "gate", "" }, { "em_gate_4_gray.active", "gate", "" }, { "emc_gate_5_gray.active", "gate", "", }, { "emc_gate_6_gray.active", "gate", "", }, { "emc_gate_7_gray.active", "gate", "", }, { "emc_gate_8_gray.active", "gate", "", }, { "dc_gate_white_gray.active", "gate", "", }, { "emc_dripper.active", "dripper", "dripper" }, { "emc_spring_bumper.active", "emc_spring_bumper", "spring bumper", }, { "mm_exit.opening", "mm_exit", "-" }, { "mm_exit.closing", "mm_exit", "-" }, { "mm_gray_ball.opening", "mm_gray_ball", "-", }, { "mm_ice_wall.shrinking", "mm_ice_wall", "-", }, { "mm_amoeba_wall.growing", "mm_amoeba_wall", "-", }, { "mm_pacman.eating.right", "mm_pacman", "pac man (eating right)" }, { "mm_pacman.eating.up", "mm_pacman", "pac man (eating up)" }, { "mm_pacman.eating.left", "mm_pacman", "pac man (eating left)" }, { "mm_pacman.eating.down", "mm_pacman", "pac man (eating down)" }, /* ----------------------------------------------------------------------- */ /* "unreal" (and therefore not drawable) runtime elements */ /* ----------------------------------------------------------------------- */ { "blocked", "-", "-" }, { "explosion", "-", "-" }, { "nut.breaking", "-", "-" }, { "diamond.breaking", "-", "-" }, { "acid_splash_left", "-", "-" }, { "acid_splash_right", "-", "-" }, { "amoeba.growing", "-", "-" }, { "amoeba.shrinking", "-", "-" }, { "expandable_wall.growing", "-", "-" }, { "expandable_steelwall.growing", "-", "-" }, { "flames", "-", "-" }, { "player_is_leaving", "-", "-" }, { "player_is_exploding_1", "-", "-" }, { "player_is_exploding_2", "-", "-" }, { "player_is_exploding_3", "-", "-" }, { "player_is_exploding_4", "-", "-" }, { "quicksand.filling", "quicksand", "-" }, { "quicksand_fast.filling", "quicksand", "-" }, { "magic_wall.filling", "-", "-" }, { "bd_magic_wall.filling", "-", "-" }, { "dc_magic_wall.filling", "-", "-" }, { "element.snapping", "-", "-" }, { "diagonal.shrinking", "-", "-" }, { "diagonal.growing", "-", "-" }, /* ----------------------------------------------------------------------- */ /* dummy elements (never used as game elements, only used as graphics) */ /* ----------------------------------------------------------------------- */ { "steelwall_topleft", "-", "-" }, { "steelwall_topright", "-", "-" }, { "steelwall_bottomleft", "-", "-" }, { "steelwall_bottomright", "-", "-" }, { "steelwall_horizontal", "-", "-" }, { "steelwall_vertical", "-", "-" }, { "invisible_steelwall_topleft", "-", "-" }, { "invisible_steelwall_topright", "-", "-" }, { "invisible_steelwall_bottomleft", "-", "-" }, { "invisible_steelwall_bottomright", "-", "-" }, { "invisible_steelwall_horizontal", "-", "-" }, { "invisible_steelwall_vertical", "-", "-" }, { "dynabomb", "-", "-" }, { "dynabomb.active", "-", "-" }, { "dynabomb_player_1", "-", "-" }, { "dynabomb_player_2", "-", "-" }, { "dynabomb_player_3", "-", "-" }, { "dynabomb_player_4", "-", "-" }, { "shield_normal.active", "-", "-" }, { "shield_deadly.active", "-", "-" }, { "amoeba", "amoeba", "-" }, { "mm_lightball_red", "-", "-" }, { "mm_lightball_blue", "-", "-" }, { "mm_lightball_yellow", "-", "-" }, { "mm_mask_mcduffin.right", "-", "-" }, { "mm_mask_mcduffin.up", "-", "-" }, { "mm_mask_mcduffin.left", "-", "-" }, { "mm_mask_mcduffin.down", "-", "-" }, { "mm_mask_grid_1", "-", "-" }, { "mm_mask_grid_2", "-", "-" }, { "mm_mask_grid_3", "-", "-" }, { "mm_mask_grid_4", "-", "-" }, { "mm_mask_rectangle", "-", "-" }, { "mm_mask_circle", "-", "-" }, { "[default]", "default", "-" }, { "[bd_default]", "bd_default", "-" }, { "[sp_default]", "sp_default", "-" }, { "[sb_default]", "sb_default", "-" }, { "[mm_default]", "mm_default", "-" }, { "graphic_1", "graphic", "-" }, { "graphic_2", "graphic", "-" }, { "graphic_3", "graphic", "-" }, { "graphic_4", "graphic", "-" }, { "graphic_5", "graphic", "-" }, { "graphic_6", "graphic", "-" }, { "graphic_7", "graphic", "-" }, { "graphic_8", "graphic", "-" }, { "internal_clipboard_custom", "internal", "empty custom element" }, { "internal_clipboard_change", "internal", "empty change page" }, { "internal_clipboard_group", "internal", "empty group element" }, { "internal_dummy", "internal", "-" }, { "internal_cascade_bd", "internal", "show Boulder Dash elements" }, { "internal_cascade_bd.active", "internal", "hide Boulder Dash elements" }, { "internal_cascade_em", "internal", "show Emerald Mine elements" }, { "internal_cascade_em.active", "internal", "hide Emerald Mine elements" }, { "internal_cascade_emc", "internal", "show Emerald Mine Club elements" }, { "internal_cascade_emc.active", "internal", "hide Emerald Mine Club elements" }, { "internal_cascade_rnd", "internal", "show Rocks'n'Diamonds elements" }, { "internal_cascade_rnd.active", "internal", "hide Rocks'n'Diamonds elements" }, { "internal_cascade_sb", "internal", "show Sokoban elements" }, { "internal_cascade_sb.active", "internal", "hide Sokoban elements" }, { "internal_cascade_sp", "internal", "show Supaplex elements" }, { "internal_cascade_sp.active", "internal", "hide Supaplex elements" }, { "internal_cascade_dc", "internal", "show Diamond Caves II elements" }, { "internal_cascade_dc.active", "internal", "hide Diamond Caves II elements" }, { "internal_cascade_dx", "internal", "show DX Boulderdash elements" }, { "internal_cascade_dx.active", "internal", "hide DX Boulderdash elements" }, { "internal_cascade_mm", "internal", "show Mirror Magic elements" }, { "internal_cascade_mm.active", "internal", "hide Mirror Magic elements" }, { "internal_cascade_df", "internal", "show Deflektor elements" }, { "internal_cascade_df.active", "internal", "hide Deflektor elements" }, { "internal_cascade_chars", "internal", "show text elements" }, { "internal_cascade_chars.active", "internal", "hide text elements" }, { "internal_cascade_steel_chars", "internal", "show steel text elements" }, { "internal_cascade_steel_chars.active", "internal", "hide steel text elements" }, { "internal_cascade_ce", "internal", "show custom elements" }, { "internal_cascade_ce.active", "internal", "hide custom elements" }, { "internal_cascade_ge", "internal", "show group elements" }, { "internal_cascade_ge.active", "internal", "hide group elements" }, { "internal_cascade_ref", "internal", "show reference elements" }, { "internal_cascade_ref.active", "internal", "hide reference elements" }, { "internal_cascade_user", "internal", "show user defined elements" }, { "internal_cascade_user.active", "internal", "hide user defined elements" }, { "internal_cascade_dynamic", "internal", "show elements used in this level" }, { "internal_cascade_dynamic.active", "internal", "hide elements used in this level" }, /* keyword to stop parser: "ELEMENT_INFO_END" <-- do not change! */ { NULL, NULL, NULL } }; /* ------------------------------------------------------------------------- */ /* element action and direction definitions */ /* ------------------------------------------------------------------------- */ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] = { { ".[DEFAULT]", ACTION_DEFAULT, TRUE }, { ".waiting", ACTION_WAITING, TRUE }, { ".falling", ACTION_FALLING, TRUE }, { ".moving", ACTION_MOVING, TRUE }, { ".digging", ACTION_DIGGING, FALSE }, { ".snapping", ACTION_SNAPPING, FALSE }, { ".collecting", ACTION_COLLECTING, FALSE }, { ".dropping", ACTION_DROPPING, FALSE }, { ".pushing", ACTION_PUSHING, FALSE }, { ".walking", ACTION_WALKING, FALSE }, { ".passing", ACTION_PASSING, FALSE }, { ".impact", ACTION_IMPACT, FALSE }, { ".breaking", ACTION_BREAKING, FALSE }, { ".activating", ACTION_ACTIVATING, FALSE }, { ".deactivating", ACTION_DEACTIVATING, FALSE }, { ".opening", ACTION_OPENING, FALSE }, { ".closing", ACTION_CLOSING, FALSE }, { ".attacking", ACTION_ATTACKING, TRUE }, { ".growing", ACTION_GROWING, TRUE }, { ".shrinking", ACTION_SHRINKING, FALSE }, { ".active", ACTION_ACTIVE, TRUE }, { ".filling", ACTION_FILLING, FALSE }, { ".emptying", ACTION_EMPTYING, FALSE }, { ".changing", ACTION_CHANGING, FALSE }, { ".exploding", ACTION_EXPLODING, FALSE }, { ".boring", ACTION_BORING, FALSE }, { ".boring[1]", ACTION_BORING_1, FALSE }, { ".boring[2]", ACTION_BORING_2, FALSE }, { ".boring[3]", ACTION_BORING_3, FALSE }, { ".boring[4]", ACTION_BORING_4, FALSE }, { ".boring[5]", ACTION_BORING_5, FALSE }, { ".boring[6]", ACTION_BORING_6, FALSE }, { ".boring[7]", ACTION_BORING_7, FALSE }, { ".boring[8]", ACTION_BORING_8, FALSE }, { ".boring[9]", ACTION_BORING_9, FALSE }, { ".boring[10]", ACTION_BORING_10, FALSE }, { ".sleeping", ACTION_SLEEPING, FALSE }, { ".sleeping[1]", ACTION_SLEEPING_1, FALSE }, { ".sleeping[2]", ACTION_SLEEPING_2, FALSE }, { ".sleeping[3]", ACTION_SLEEPING_3, FALSE }, { ".awakening", ACTION_AWAKENING, FALSE }, { ".dying", ACTION_DYING, FALSE }, { ".turning", ACTION_TURNING, FALSE }, { ".turning_from_left", ACTION_TURNING_FROM_LEFT, FALSE }, { ".turning_from_right", ACTION_TURNING_FROM_RIGHT, FALSE }, { ".turning_from_up", ACTION_TURNING_FROM_UP, FALSE }, { ".turning_from_down", ACTION_TURNING_FROM_DOWN, FALSE }, { ".smashed_by_rock", ACTION_SMASHED_BY_ROCK, FALSE }, { ".smashed_by_spring", ACTION_SMASHED_BY_SPRING, FALSE }, { ".eating", ACTION_EATING, FALSE }, { ".twinkling", ACTION_TWINKLING, FALSE }, { ".splashing", ACTION_SPLASHING, FALSE }, { ".hitting", ACTION_HITTING, FALSE }, { ".page[1]", ACTION_PAGE_1, FALSE }, { ".page[2]", ACTION_PAGE_2, FALSE }, { ".page[3]", ACTION_PAGE_3, FALSE }, { ".page[4]", ACTION_PAGE_4, FALSE }, { ".page[5]", ACTION_PAGE_5, FALSE }, { ".page[6]", ACTION_PAGE_6, FALSE }, { ".page[7]", ACTION_PAGE_7, FALSE }, { ".page[8]", ACTION_PAGE_8, FALSE }, { ".page[9]", ACTION_PAGE_9, FALSE }, { ".page[10]", ACTION_PAGE_10, FALSE }, { ".page[11]", ACTION_PAGE_11, FALSE }, { ".page[12]", ACTION_PAGE_12, FALSE }, { ".page[13]", ACTION_PAGE_13, FALSE }, { ".page[14]", ACTION_PAGE_14, FALSE }, { ".page[15]", ACTION_PAGE_15, FALSE }, { ".page[16]", ACTION_PAGE_16, FALSE }, { ".page[17]", ACTION_PAGE_17, FALSE }, { ".page[18]", ACTION_PAGE_18, FALSE }, { ".page[19]", ACTION_PAGE_19, FALSE }, { ".page[20]", ACTION_PAGE_20, FALSE }, { ".page[21]", ACTION_PAGE_21, FALSE }, { ".page[22]", ACTION_PAGE_22, FALSE }, { ".page[23]", ACTION_PAGE_23, FALSE }, { ".page[24]", ACTION_PAGE_24, FALSE }, { ".page[25]", ACTION_PAGE_25, FALSE }, { ".page[26]", ACTION_PAGE_26, FALSE }, { ".page[27]", ACTION_PAGE_27, FALSE }, { ".page[28]", ACTION_PAGE_28, FALSE }, { ".page[29]", ACTION_PAGE_29, FALSE }, { ".page[30]", ACTION_PAGE_30, FALSE }, { ".page[31]", ACTION_PAGE_31, FALSE }, { ".page[32]", ACTION_PAGE_32, FALSE }, { ".part_1", ACTION_PART_1, FALSE }, { ".part_2", ACTION_PART_2, FALSE }, { ".part_3", ACTION_PART_3, FALSE }, { ".part_4", ACTION_PART_4, FALSE }, { ".part_5", ACTION_PART_5, FALSE }, { ".part_6", ACTION_PART_6, FALSE }, { ".part_7", ACTION_PART_7, FALSE }, { ".part_8", ACTION_PART_8, FALSE }, { ".part_9", ACTION_PART_9, FALSE }, { ".part_10", ACTION_PART_10, FALSE }, { ".part_11", ACTION_PART_11, FALSE }, { ".part_12", ACTION_PART_12, FALSE }, { ".part_13", ACTION_PART_13, FALSE }, { ".part_14", ACTION_PART_14, FALSE }, { ".part_15", ACTION_PART_15, FALSE }, { ".part_16", ACTION_PART_16, FALSE }, { ".part_17", ACTION_PART_17, FALSE }, { ".part_18", ACTION_PART_18, FALSE }, { ".part_19", ACTION_PART_19, FALSE }, { ".part_20", ACTION_PART_20, FALSE }, { ".part_21", ACTION_PART_21, FALSE }, { ".part_22", ACTION_PART_22, FALSE }, { ".part_23", ACTION_PART_23, FALSE }, { ".part_24", ACTION_PART_24, FALSE }, { ".part_25", ACTION_PART_25, FALSE }, { ".part_26", ACTION_PART_26, FALSE }, { ".part_27", ACTION_PART_27, FALSE }, { ".part_28", ACTION_PART_28, FALSE }, { ".part_29", ACTION_PART_29, FALSE }, { ".part_30", ACTION_PART_30, FALSE }, { ".part_31", ACTION_PART_31, FALSE }, { ".part_32", ACTION_PART_32, FALSE }, { ".other", ACTION_OTHER, FALSE }, /* empty suffix always matches -- check as last entry in InitSoundInfo() */ { "", ACTION_DEFAULT, TRUE }, { NULL, 0, 0 } }; struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS_FULL + 1] = { { ".left", MV_BIT_LEFT }, { ".right", MV_BIT_RIGHT }, { ".up", MV_BIT_UP }, { ".down", MV_BIT_DOWN }, { ".upleft", MV_BIT_UP }, { ".upright", MV_BIT_RIGHT }, { ".downleft", MV_BIT_LEFT }, { ".downright", MV_BIT_DOWN }, { NULL, 0 } }; struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] = { { ".[DEFAULT]", GFX_SPECIAL_ARG_DEFAULT, }, { ".LOADING", GFX_SPECIAL_ARG_LOADING, }, { ".TITLE_INITIAL", GFX_SPECIAL_ARG_TITLE_INITIAL, }, { ".TITLE_INITIAL_1", GFX_SPECIAL_ARG_TITLE_INITIAL_1, }, { ".TITLE_INITIAL_2", GFX_SPECIAL_ARG_TITLE_INITIAL_2, }, { ".TITLE_INITIAL_3", GFX_SPECIAL_ARG_TITLE_INITIAL_3, }, { ".TITLE_INITIAL_4", GFX_SPECIAL_ARG_TITLE_INITIAL_4, }, { ".TITLE_INITIAL_5", GFX_SPECIAL_ARG_TITLE_INITIAL_5, }, { ".TITLE", GFX_SPECIAL_ARG_TITLE, }, { ".TITLE_1", GFX_SPECIAL_ARG_TITLE_1, }, { ".TITLE_2", GFX_SPECIAL_ARG_TITLE_2, }, { ".TITLE_3", GFX_SPECIAL_ARG_TITLE_3, }, { ".TITLE_4", GFX_SPECIAL_ARG_TITLE_4, }, { ".TITLE_5", GFX_SPECIAL_ARG_TITLE_5, }, { ".MAIN", GFX_SPECIAL_ARG_MAIN, }, { ".LEVELS", GFX_SPECIAL_ARG_LEVELS }, { ".LEVELNR", GFX_SPECIAL_ARG_LEVELNR }, { ".SCORES", GFX_SPECIAL_ARG_SCORES, }, { ".EDITOR", GFX_SPECIAL_ARG_EDITOR, }, { ".INFO", GFX_SPECIAL_ARG_INFO, }, { ".SETUP", GFX_SPECIAL_ARG_SETUP, }, { ".PLAYING", GFX_SPECIAL_ARG_PLAYING, }, { ".DOOR", GFX_SPECIAL_ARG_DOOR, }, { ".TAPE", GFX_SPECIAL_ARG_TAPE, }, { ".PANEL", GFX_SPECIAL_ARG_PANEL, }, { ".PREVIEW", GFX_SPECIAL_ARG_PREVIEW, }, { ".CRUMBLED", GFX_SPECIAL_ARG_CRUMBLED, }, { ".MAINONLY", GFX_SPECIAL_ARG_MAINONLY, }, { ".TYPENAME", GFX_SPECIAL_ARG_TYPENAME, }, { ".SUBMENU", GFX_SPECIAL_ARG_SUBMENU, }, { ".MENU", GFX_SPECIAL_ARG_MENU, }, { ".TOONS", GFX_SPECIAL_ARG_TOONS, }, { ".SCORESOLD", GFX_SPECIAL_ARG_SCORESOLD, }, { ".SCORESNEW", GFX_SPECIAL_ARG_SCORESNEW, }, { ".FADING", GFX_SPECIAL_ARG_FADING, }, { ".QUIT", GFX_SPECIAL_ARG_QUIT, }, /* empty suffix always matches -- check as last entry in InitMusicInfo() */ { "", GFX_SPECIAL_ARG_DEFAULT, }, { NULL, 0, } }; #include "conf_var.c" /* include auto-generated data structure definitions */ /* ------------------------------------------------------------------------- */ /* font definitions */ /* ------------------------------------------------------------------------- */ /* Important: When one entry is a prefix of another entry, the longer entry must come first, because the dynamic configuration does prefix matching! (These definitions must match the corresponding definitions in "main.h"!) */ struct FontInfo font_info[NUM_FONTS + 1] = { { "font.initial_1" }, { "font.initial_2" }, { "font.initial_3" }, { "font.initial_4" }, { "font.title_1" }, { "font.title_2" }, { "font.menu_1.active" }, { "font.menu_2.active" }, { "font.menu_1" }, { "font.menu_2" }, { "font.text_1.active" }, { "font.text_2.active" }, { "font.text_3.active" }, { "font.text_4.active" }, { "font.text_1" }, { "font.text_2" }, { "font.text_3" }, { "font.text_4" }, { "font.envelope_1" }, { "font.envelope_2" }, { "font.envelope_3" }, { "font.envelope_4" }, { "font.request" }, { "font.input_1.active" }, { "font.input_2.active" }, { "font.input_1" }, { "font.input_2" }, { "font.option_off_narrow" }, { "font.option_off" }, { "font.option_on_narrow" }, { "font.option_on" }, { "font.value_1" }, { "font.value_2" }, { "font.value_old" }, { "font.value_narrow" }, { "font.level_number.active" }, { "font.level_number" }, { "font.tape_recorder" }, { "font.game_info" }, { "font.info.elements" }, { "font.info.levelset" }, { NULL } }; struct GlobalAnimInfo global_anim_info[NUM_GLOBAL_ANIM_TOKENS + 1]; /* this contains predefined structure elements to init "global_anim_info" */ struct GlobalAnimNameInfo global_anim_name_info[NUM_GLOBAL_ANIM_TOKENS + 1] = { /* (real) graphic definitions used to define animation graphics */ { "gfx.global.anim_1", }, { "gfx.global.anim_2", }, { "gfx.global.anim_3", }, { "gfx.global.anim_4", }, { "gfx.global.anim_5", }, { "gfx.global.anim_6", }, { "gfx.global.anim_7", }, { "gfx.global.anim_8", }, { "gfx.global.anim_9", }, { "gfx.global.anim_10", }, { "gfx.global.anim_11", }, { "gfx.global.anim_12", }, { "gfx.global.anim_13", }, { "gfx.global.anim_14", }, { "gfx.global.anim_15", }, { "gfx.global.anim_16", }, { "gfx.global.anim_17", }, { "gfx.global.anim_18", }, { "gfx.global.anim_19", }, { "gfx.global.anim_20", }, { "gfx.global.anim_21", }, { "gfx.global.anim_22", }, { "gfx.global.anim_23", }, { "gfx.global.anim_24", }, { "gfx.global.anim_25", }, { "gfx.global.anim_26", }, { "gfx.global.anim_27", }, { "gfx.global.anim_28", }, { "gfx.global.anim_29", }, { "gfx.global.anim_30", }, { "gfx.global.anim_31", }, { "gfx.global.anim_32", }, /* (dummy) graphic definitions used to define animation controls */ { "global.anim_1", }, { "global.anim_2", }, { "global.anim_3", }, { "global.anim_4", }, { "global.anim_5", }, { "global.anim_6", }, { "global.anim_7", }, { "global.anim_8", }, { "global.anim_9", }, { "global.anim_10", }, { "global.anim_11", }, { "global.anim_12", }, { "global.anim_13", }, { "global.anim_14", }, { "global.anim_15", }, { "global.anim_16", }, { "global.anim_17", }, { "global.anim_18", }, { "global.anim_19", }, { "global.anim_20", }, { "global.anim_21", }, { "global.anim_22", }, { "global.anim_23", }, { "global.anim_24", }, { "global.anim_25", }, { "global.anim_26", }, { "global.anim_27", }, { "global.anim_28", }, { "global.anim_29", }, { "global.anim_30", }, { "global.anim_31", }, { "global.anim_32", }, { NULL } }; /* ------------------------------------------------------------------------- */ /* music token prefix definitions */ /* ------------------------------------------------------------------------- */ struct MusicPrefixInfo music_prefix_info[NUM_MUSIC_PREFIXES + 1] = { { "background", TRUE }, { NULL, 0 } }; /* ========================================================================= */ /* main() */ /* ========================================================================= */ static void print_usage() { Print("\n" "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n" "\n" "Options:\n" " -b, --basepath DIRECTORY alternative base DIRECTORY\n" " -l, --level DIRECTORY alternative level DIRECTORY\n" " -g, --graphics DIRECTORY alternative graphics DIRECTORY\n" " -s, --sounds DIRECTORY alternative sounds DIRECTORY\n" " -m, --music DIRECTORY alternative music DIRECTORY\n" " --mytapes use private tapes for tape tests\n" " -n, --network network multiplayer game\n" " --serveronly only start network server\n" " -v, --verbose verbose mode\n" " -V, --version show program version\n" " --debug display debugging information\n" " -e, --execute COMMAND execute batch COMMAND\n" "\n" "Valid commands for '--execute' option:\n" " \"print graphicsinfo.conf\" print default graphics config\n" " \"print soundsinfo.conf\" print default sounds config\n" " \"print musicinfo.conf\" print default music config\n" " \"print editorsetup.conf\" print default editor config\n" " \"print helpanim.conf\" print default helpanim config\n" " \"print helptext.conf\" print default helptext config\n" " \"dump level FILE\" dump level data from FILE\n" " \"dump tape FILE\" dump tape data from FILE\n" " \"autotest LEVELDIR [NR ...]\" test level tapes for LEVELDIR\n" " \"autoplay LEVELDIR [NR ...]\" play level tapes for LEVELDIR\n" " \"autoffwd LEVELDIR [NR ...]\" ffwd level tapes for LEVELDIR\n" " \"autowarp LEVELDIR [NR ...]\" warp level tapes for LEVELDIR\n" " \"convert LEVELDIR [NR]\" convert levels in LEVELDIR\n" " \"create images DIRECTORY\" write BMP images to DIRECTORY\n" " \"create CE image DIRECTORY\" write BMP image to DIRECTORY\n" "\n", program.command_basename); } static void print_version() { Print("%s", getProgramInitString()); if (!strEqual(getProgramVersionString(), getProgramRealVersionString())) { Print(" (%s %d.%d.%d.%d%s)", PROGRAM_TITLE_STRING, PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_PATCH, PROGRAM_VERSION_BUILD, PROGRAM_VERSION_EXTRA); } Print("\n"); if (options.debug) { SDL_version sdl_version; SDL_VERSION(&sdl_version); Print("- SDL %d.%d.%d\n", sdl_version.major, sdl_version.minor, sdl_version.patch); SDL_IMAGE_VERSION(&sdl_version); Print("- SDL_image %d.%d.%d\n", sdl_version.major, sdl_version.minor, sdl_version.patch); SDL_MIXER_VERSION(&sdl_version); Print("- SDL_mixer %d.%d.%d\n", sdl_version.major, sdl_version.minor, sdl_version.patch); SDL_NET_VERSION(&sdl_version); Print("- SDL_net %d.%d.%d\n", sdl_version.major, sdl_version.minor, sdl_version.patch); } } static void InitProgramConfig(char *command_filename) { char *program_title = PROGRAM_TITLE_STRING; char *program_icon_file = PROGRAM_ICON_FILENAME; char *program_version = getProgramRealVersionString(); char *config_filename = getProgramConfigFilename(command_filename); char *userdata_basename = getBaseNameNoSuffix(command_filename); char *userdata_subdir; char *userdata_subdir_unix; // read default program config, if existing if (fileExists(config_filename)) { // if program config file exists, derive Unix user data directory from it // (but only if the program config file is not generic "setup.conf" file) if (!strEqual(getBaseNamePtr(config_filename), SETUP_FILENAME)) { userdata_basename = getBaseName(config_filename); if (strSuffix(userdata_basename, ".conf")) userdata_basename[strlen(userdata_basename) - 5] = '\0'; } LoadSetupFromFilename(config_filename); } // set user data directory for Linux/Unix (but not Mac OS X) userdata_subdir_unix = getStringCat2(".", userdata_basename); // set program title from potentially redefined program title if (setup.internal.program_title != NULL && strlen(setup.internal.program_title) > 0) program_title = getStringCopy(setup.internal.program_title); // set program version from potentially redefined program version if (setup.internal.program_version != NULL && strlen(setup.internal.program_version) > 0) program_version = getStringCopy(setup.internal.program_version); // set program icon file from potentially redefined program icon file if (setup.internal.program_icon_file != NULL && strlen(setup.internal.program_icon_file) > 0) program_icon_file = getStringCopy(setup.internal.program_icon_file); #if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX) userdata_subdir = program_title; #elif defined(PLATFORM_UNIX) userdata_subdir = userdata_subdir_unix; #else userdata_subdir = USERDATA_DIRECTORY_OTHER; #endif // set default window size (only relevant on program startup) if (setup.internal.default_window_width != 0 && setup.internal.default_window_height != 0) { WIN_XSIZE = setup.internal.default_window_width; WIN_YSIZE = setup.internal.default_window_height; } InitProgramInfo(command_filename, config_filename, userdata_subdir, program_title, program_title, program_icon_file, COOKIE_PREFIX, program_version, GAME_VERSION_ACTUAL); } int main(int argc, char *argv[]) { InitProgramConfig(argv[0]); InitWindowTitleFunction(getWindowTitleString); InitExitMessageFunction(DisplayExitMessage); InitExitFunction(CloseAllAndExit); InitPlatformDependentStuff(); GetOptions(argc, argv, print_usage, print_version); OpenAll(); EventLoop(); CloseAllAndExit(0); return 0; /* to keep compilers happy */ } mirrormagic-3.0.0/src/conftime.h0000644000175000017500000000005613263214171016100 0ustar aeglosaeglos#define SOURCE_DATE_STRING "2018-04-10 20:02" mirrormagic-3.0.0/src/conf_e2s.c0000644000175000017500000005045313263214151015771 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_e2s.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_E2S_C #define CONF_E2S_C /* values for element/sounds mapping configuration */ static struct { int element; boolean is_class; int action; int sound; } element_to_sound[] = { { EL_DEFAULT, TRUE, ACTION_DIGGING, SND_CLASS_DEFAULT_DIGGING }, { EL_DEFAULT, TRUE, ACTION_COLLECTING, SND_CLASS_DEFAULT_COLLECTING }, { EL_DEFAULT, TRUE, ACTION_SNAPPING, SND_CLASS_DEFAULT_SNAPPING }, { EL_DEFAULT, TRUE, ACTION_PUSHING, SND_CLASS_DEFAULT_PUSHING }, { EL_DEFAULT, TRUE, ACTION_IMPACT, SND_CLASS_DEFAULT_IMPACT }, { EL_DEFAULT, TRUE, ACTION_WALKING, SND_CLASS_DEFAULT_WALKING }, { EL_DEFAULT, TRUE, ACTION_PASSING, SND_CLASS_DEFAULT_PASSING }, { EL_DEFAULT, TRUE, ACTION_DYING, SND_CLASS_DEFAULT_DYING }, { EL_DEFAULT, TRUE, ACTION_EXPLODING, SND_CLASS_DEFAULT_EXPLODING }, { EL_DEFAULT, TRUE, ACTION_HITTING, SND_CLASS_DEFAULT_HITTING }, { EL_SP_DEFAULT, TRUE, ACTION_EXPLODING, SND_CLASS_SP_DEFAULT_EXPLODING }, { EL_MM_DEFAULT, TRUE, ACTION_EXPLODING, SND_CLASS_MM_DEFAULT_EXPLODING }, { EL_BD_DIAMOND, FALSE, ACTION_COLLECTING, SND_BD_DIAMOND_COLLECTING }, { EL_BD_DIAMOND, FALSE, ACTION_IMPACT, SND_BD_DIAMOND_IMPACT }, { EL_BD_ROCK, FALSE, ACTION_PUSHING, SND_BD_ROCK_PUSHING }, { EL_BD_ROCK, FALSE, ACTION_IMPACT, SND_BD_ROCK_IMPACT }, { EL_BD_MAGIC_WALL, FALSE, ACTION_ACTIVATING, SND_BD_MAGIC_WALL_ACTIVATING }, { EL_BD_MAGIC_WALL_ACTIVE, FALSE, -1, SND_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL, FALSE, ACTION_ACTIVE, SND_BD_MAGIC_WALL_ACTIVE }, { EL_BD_MAGIC_WALL_FILLING, FALSE, -1, SND_BD_MAGIC_WALL_FILLING }, { EL_BD_MAGIC_WALL, FALSE, ACTION_FILLING, SND_BD_MAGIC_WALL_FILLING }, { EL_BD_AMOEBA, FALSE, ACTION_WAITING, SND_BD_AMOEBA_WAITING }, { EL_BD_AMOEBA, FALSE, ACTION_GROWING, SND_BD_AMOEBA_GROWING }, { EL_BD_BUTTERFLY, FALSE, ACTION_MOVING, SND_BD_BUTTERFLY_MOVING }, { EL_BD_BUTTERFLY, FALSE, ACTION_WAITING, SND_BD_BUTTERFLY_WAITING }, { EL_BD_FIREFLY, FALSE, ACTION_MOVING, SND_BD_FIREFLY_MOVING }, { EL_BD_FIREFLY, FALSE, ACTION_WAITING, SND_BD_FIREFLY_WAITING }, { EL_SP_BASE, FALSE, ACTION_DIGGING, SND_SP_BASE_DIGGING }, { EL_SP_BUGGY_BASE, FALSE, ACTION_DIGGING, SND_SP_BUGGY_BASE_DIGGING }, { EL_SP_BUGGY_BASE_ACTIVE, FALSE, -1, SND_SP_BUGGY_BASE_ACTIVE }, { EL_SP_BUGGY_BASE, FALSE, ACTION_ACTIVE, SND_SP_BUGGY_BASE_ACTIVE }, { EL_SP_INFOTRON, FALSE, ACTION_COLLECTING, SND_SP_INFOTRON_COLLECTING }, { EL_SP_INFOTRON, FALSE, ACTION_IMPACT, SND_SP_INFOTRON_IMPACT }, { EL_SP_ZONK, FALSE, ACTION_PUSHING, SND_SP_ZONK_PUSHING }, { EL_SP_ZONK, FALSE, ACTION_IMPACT, SND_SP_ZONK_IMPACT }, { EL_SP_DISK_RED, FALSE, ACTION_COLLECTING, SND_SP_DISK_RED_COLLECTING }, { EL_SP_DISK_ORANGE, FALSE, ACTION_PUSHING, SND_SP_DISK_ORANGE_PUSHING }, { EL_SP_DISK_YELLOW, FALSE, ACTION_PUSHING, SND_SP_DISK_YELLOW_PUSHING }, { EL_SP_PORT_RIGHT, TRUE, ACTION_PASSING, SND_CLASS_SP_PORT_PASSING }, { EL_SP_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_SP_EXIT_PASSING }, { EL_SP_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_SP_EXIT_OPENING }, { EL_SP_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_SP_EXIT_CLOSING }, { EL_SP_SNIKSNAK, FALSE, ACTION_MOVING, SND_SP_SNIKSNAK_MOVING }, { EL_SP_SNIKSNAK, FALSE, ACTION_WAITING, SND_SP_SNIKSNAK_WAITING }, { EL_SP_ELECTRON, FALSE, ACTION_MOVING, SND_SP_ELECTRON_MOVING }, { EL_SP_ELECTRON, FALSE, ACTION_WAITING, SND_SP_ELECTRON_WAITING }, { EL_SP_TERMINAL, FALSE, ACTION_ACTIVATING, SND_SP_TERMINAL_ACTIVATING }, { EL_SP_TERMINAL_ACTIVE, FALSE, -1, SND_SP_TERMINAL_ACTIVE }, { EL_SP_TERMINAL, FALSE, ACTION_ACTIVE, SND_SP_TERMINAL_ACTIVE }, { EL_SOKOBAN_FIELD_PLAYER, TRUE, ACTION_PUSHING, SND_CLASS_SOKOBAN_PUSHING }, { EL_SOKOBAN_FIELD_PLAYER, TRUE, ACTION_FILLING, SND_CLASS_SOKOBAN_FILLING }, { EL_SOKOBAN_FIELD_PLAYER, TRUE, ACTION_EMPTYING, SND_CLASS_SOKOBAN_EMPTYING }, { EL_PLAYER_1, TRUE, ACTION_MOVING, SND_CLASS_PLAYER_MOVING }, { EL_SAND, FALSE, ACTION_DIGGING, SND_SAND_DIGGING }, { EL_EMERALD, TRUE, ACTION_COLLECTING, SND_CLASS_EMERALD_COLLECTING }, { EL_EMERALD, TRUE, ACTION_IMPACT, SND_CLASS_EMERALD_IMPACT }, { EL_DIAMOND, FALSE, ACTION_COLLECTING, SND_DIAMOND_COLLECTING }, { EL_DIAMOND, FALSE, ACTION_IMPACT, SND_DIAMOND_IMPACT }, { EL_DIAMOND_BREAKING, FALSE, -1, SND_DIAMOND_BREAKING }, { EL_DIAMOND, FALSE, ACTION_BREAKING, SND_DIAMOND_BREAKING }, { EL_ROCK, FALSE, ACTION_PUSHING, SND_ROCK_PUSHING }, { EL_ROCK, FALSE, ACTION_IMPACT, SND_ROCK_IMPACT }, { EL_BOMB, FALSE, ACTION_PUSHING, SND_BOMB_PUSHING }, { EL_NUT, FALSE, ACTION_PUSHING, SND_NUT_PUSHING }, { EL_NUT_BREAKING, FALSE, -1, SND_NUT_BREAKING }, { EL_NUT, FALSE, ACTION_BREAKING, SND_NUT_BREAKING }, { EL_NUT, FALSE, ACTION_IMPACT, SND_NUT_IMPACT }, { EL_DYNAMITE_ACTIVE, TRUE, ACTION_COLLECTING, SND_CLASS_DYNAMITE_COLLECTING }, { EL_DYNAMITE_ACTIVE, TRUE, ACTION_DROPPING, SND_CLASS_DYNAMITE_DROPPING }, { EL_DYNAMITE_ACTIVE, TRUE, ACTION_ACTIVE, SND_CLASS_DYNAMITE_ACTIVE }, { EL_KEY_1, TRUE, ACTION_COLLECTING, SND_CLASS_KEY_COLLECTING }, { EL_GATE_1, TRUE, ACTION_PASSING, SND_CLASS_GATE_PASSING }, { EL_BUG, FALSE, ACTION_MOVING, SND_BUG_MOVING }, { EL_BUG, FALSE, ACTION_WAITING, SND_BUG_WAITING }, { EL_SPACESHIP, FALSE, ACTION_MOVING, SND_SPACESHIP_MOVING }, { EL_SPACESHIP, FALSE, ACTION_WAITING, SND_SPACESHIP_WAITING }, { EL_YAMYAM, FALSE, ACTION_MOVING, SND_YAMYAM_MOVING }, { EL_YAMYAM, FALSE, ACTION_WAITING, SND_YAMYAM_WAITING }, { EL_YAMYAM, FALSE, ACTION_DIGGING, SND_YAMYAM_DIGGING }, { EL_ROBOT, FALSE, ACTION_MOVING, SND_ROBOT_MOVING }, { EL_ROBOT, FALSE, ACTION_WAITING, SND_ROBOT_WAITING }, { EL_ROBOT_WHEEL, FALSE, ACTION_ACTIVATING, SND_ROBOT_WHEEL_ACTIVATING }, { EL_ROBOT_WHEEL_ACTIVE, FALSE, -1, SND_ROBOT_WHEEL_ACTIVE }, { EL_ROBOT_WHEEL, FALSE, ACTION_ACTIVE, SND_ROBOT_WHEEL_ACTIVE }, { EL_MAGIC_WALL, FALSE, ACTION_ACTIVATING, SND_MAGIC_WALL_ACTIVATING }, { EL_MAGIC_WALL_ACTIVE, FALSE, -1, SND_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL, FALSE, ACTION_ACTIVE, SND_MAGIC_WALL_ACTIVE }, { EL_MAGIC_WALL_FILLING, FALSE, -1, SND_MAGIC_WALL_FILLING }, { EL_MAGIC_WALL, FALSE, ACTION_FILLING, SND_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL, FALSE, ACTION_ACTIVATING, SND_DC_MAGIC_WALL_ACTIVATING }, { EL_DC_MAGIC_WALL_ACTIVE, FALSE, -1, SND_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL, FALSE, ACTION_ACTIVE, SND_DC_MAGIC_WALL_ACTIVE }, { EL_DC_MAGIC_WALL_FILLING, FALSE, -1, SND_DC_MAGIC_WALL_FILLING }, { EL_DC_MAGIC_WALL, FALSE, ACTION_FILLING, SND_DC_MAGIC_WALL_FILLING }, { EL_AMOEBA_DEAD, TRUE, ACTION_WAITING, SND_CLASS_AMOEBA_WAITING }, { EL_AMOEBA_DEAD, TRUE, ACTION_GROWING, SND_CLASS_AMOEBA_GROWING }, { EL_AMOEBA_DEAD, TRUE, ACTION_DROPPING, SND_CLASS_AMOEBA_DROPPING }, { EL_ACID, FALSE, ACTION_SPLASHING, SND_ACID_SPLASHING }, { EL_QUICKSAND_EMPTY, TRUE, ACTION_FILLING, SND_CLASS_QUICKSAND_FILLING }, { EL_QUICKSAND_EMPTY, TRUE, ACTION_EMPTYING, SND_CLASS_QUICKSAND_EMPTYING }, { EL_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_EXIT_OPENING }, { EL_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_EXIT_CLOSING }, { EL_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_EXIT_PASSING }, { EL_STEEL_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_STEEL_EXIT_OPENING }, { EL_STEEL_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_STEEL_EXIT_CLOSING }, { EL_STEEL_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_STEEL_EXIT_PASSING }, { EL_EM_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_EM_EXIT_OPENING }, { EL_EM_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_EM_EXIT_CLOSING }, { EL_EM_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_EM_EXIT_PASSING }, { EL_EM_STEEL_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_EM_STEEL_EXIT_OPENING }, { EL_EM_STEEL_EXIT_CLOSED, TRUE, ACTION_CLOSING, SND_CLASS_EM_STEEL_EXIT_CLOSING }, { EL_EM_STEEL_EXIT_CLOSED, TRUE, ACTION_PASSING, SND_CLASS_EM_STEEL_EXIT_PASSING }, { EL_PENGUIN, FALSE, ACTION_PASSING, SND_PENGUIN_PASSING }, { EL_BALLOON, FALSE, ACTION_MOVING, SND_BALLOON_MOVING }, { EL_BALLOON, FALSE, ACTION_WAITING, SND_BALLOON_WAITING }, { EL_BALLOON, FALSE, ACTION_PUSHING, SND_BALLOON_PUSHING }, { EL_BALLOON_SWITCH_LEFT, TRUE, ACTION_ACTIVATING, SND_CLASS_BALLOON_SWITCH_ACTIVATING }, { EL_SPRING, FALSE, ACTION_MOVING, SND_SPRING_MOVING }, { EL_SPRING, FALSE, ACTION_PUSHING, SND_SPRING_PUSHING }, { EL_SPRING, FALSE, ACTION_IMPACT, SND_SPRING_IMPACT }, { EL_WALL, TRUE, ACTION_GROWING, SND_CLASS_WALL_GROWING }, { EL_EMC_ANDROID, FALSE, ACTION_PUSHING, SND_EMC_ANDROID_PUSHING }, { EL_EMC_ANDROID, FALSE, ACTION_MOVING, SND_EMC_ANDROID_MOVING }, { EL_EMC_ANDROID, FALSE, ACTION_DROPPING, SND_EMC_ANDROID_DROPPING }, { EL_EMC_MAGIC_BALL, FALSE, ACTION_DROPPING, SND_EMC_MAGIC_BALL_DROPPING }, { EL_PEARL, FALSE, ACTION_COLLECTING, SND_PEARL_COLLECTING }, { EL_PEARL_BREAKING, FALSE, -1, SND_PEARL_BREAKING }, { EL_PEARL, FALSE, ACTION_BREAKING, SND_PEARL_BREAKING }, { EL_PEARL, FALSE, ACTION_IMPACT, SND_PEARL_IMPACT }, { EL_CRYSTAL, FALSE, ACTION_COLLECTING, SND_CRYSTAL_COLLECTING }, { EL_CRYSTAL, FALSE, ACTION_IMPACT, SND_CRYSTAL_IMPACT }, { EL_ENVELOPE_1, TRUE, ACTION_COLLECTING, SND_CLASS_ENVELOPE_COLLECTING }, { EL_ENVELOPE_1, TRUE, ACTION_OPENING, SND_CLASS_ENVELOPE_OPENING }, { EL_ENVELOPE_1, TRUE, ACTION_CLOSING, SND_CLASS_ENVELOPE_CLOSING }, { EL_INVISIBLE_SAND, FALSE, ACTION_DIGGING, SND_INVISIBLE_SAND_DIGGING }, { EL_INVISIBLE_SAND_ACTIVE, FALSE, ACTION_DIGGING, SND_INVISIBLE_SAND_ACTIVE_DIGGING }, { EL_SHIELD_NORMAL, FALSE, ACTION_COLLECTING, SND_SHIELD_NORMAL_COLLECTING }, { EL_SHIELD_NORMAL_ACTIVE, FALSE, -1, SND_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_NORMAL, FALSE, ACTION_ACTIVE, SND_SHIELD_NORMAL_ACTIVE }, { EL_SHIELD_DEADLY, FALSE, ACTION_COLLECTING, SND_SHIELD_DEADLY_COLLECTING }, { EL_SHIELD_DEADLY_ACTIVE, FALSE, -1, SND_SHIELD_DEADLY_ACTIVE }, { EL_SHIELD_DEADLY, FALSE, ACTION_ACTIVE, SND_SHIELD_DEADLY_ACTIVE }, { EL_EXTRA_TIME, FALSE, ACTION_COLLECTING, SND_EXTRA_TIME_COLLECTING }, { EL_MOLE, FALSE, ACTION_MOVING, SND_MOLE_MOVING }, { EL_MOLE, FALSE, ACTION_WAITING, SND_MOLE_WAITING }, { EL_MOLE, FALSE, ACTION_DIGGING, SND_MOLE_DIGGING }, { EL_SWITCHGATE_SWITCH_UP, TRUE, ACTION_ACTIVATING, SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING }, { EL_SWITCHGATE_OPEN, TRUE, ACTION_OPENING, SND_CLASS_SWITCHGATE_OPENING }, { EL_SWITCHGATE_OPEN, TRUE, ACTION_CLOSING, SND_CLASS_SWITCHGATE_CLOSING }, { EL_SWITCHGATE_OPEN, TRUE, ACTION_PASSING, SND_CLASS_SWITCHGATE_PASSING }, { EL_TIMEGATE_SWITCH_ACTIVE, TRUE, ACTION_ACTIVATING, SND_CLASS_TIMEGATE_SWITCH_ACTIVATING }, { EL_TIMEGATE_SWITCH_ACTIVE, TRUE, ACTION_ACTIVE, SND_CLASS_TIMEGATE_SWITCH_ACTIVE }, { EL_TIMEGATE_SWITCH_ACTIVE, TRUE, ACTION_DEACTIVATING, SND_CLASS_TIMEGATE_SWITCH_DEACTIVATING }, { EL_TIMEGATE_OPEN, TRUE, ACTION_OPENING, SND_CLASS_TIMEGATE_OPENING }, { EL_TIMEGATE_OPEN, TRUE, ACTION_CLOSING, SND_CLASS_TIMEGATE_CLOSING }, { EL_TIMEGATE_OPEN, TRUE, ACTION_PASSING, SND_CLASS_TIMEGATE_PASSING }, { EL_CONVEYOR_BELT_1_SWITCH_LEFT, TRUE, ACTION_ACTIVATING, SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING }, { EL_CONVEYOR_BELT_1_LEFT, TRUE, ACTION_ACTIVE, SND_CLASS_CONVEYOR_BELT_ACTIVE }, { EL_CONVEYOR_BELT_1_SWITCH_LEFT, TRUE, ACTION_DEACTIVATING, SND_CLASS_CONVEYOR_BELT_SWITCH_DEACTIVATING }, { EL_LIGHT_SWITCH, FALSE, ACTION_ACTIVATING, SND_LIGHT_SWITCH_ACTIVATING }, { EL_LIGHT_SWITCH, FALSE, ACTION_DEACTIVATING, SND_LIGHT_SWITCH_DEACTIVATING }, { EL_DX_SUPABOMB, FALSE, ACTION_PUSHING, SND_DX_SUPABOMB_PUSHING }, { EL_TRAP, FALSE, ACTION_DIGGING, SND_TRAP_DIGGING }, { EL_TRAP, FALSE, ACTION_ACTIVATING, SND_TRAP_ACTIVATING }, { EL_TUBE_ANY, TRUE, ACTION_WALKING, SND_CLASS_TUBE_WALKING }, { EL_SPEED_PILL, FALSE, ACTION_COLLECTING, SND_SPEED_PILL_COLLECTING }, { EL_DYNABOMB_INCREASE_NUMBER, FALSE, ACTION_COLLECTING, SND_DYNABOMB_INCREASE_NUMBER_COLLECTING }, { EL_DYNABOMB_INCREASE_SIZE, FALSE, ACTION_COLLECTING, SND_DYNABOMB_INCREASE_SIZE_COLLECTING }, { EL_DYNABOMB_INCREASE_POWER, FALSE, ACTION_COLLECTING, SND_DYNABOMB_INCREASE_POWER_COLLECTING }, { EL_DYNABOMB_INCREASE_NUMBER, TRUE, ACTION_DROPPING, SND_CLASS_DYNABOMB_DROPPING }, { EL_DYNABOMB_INCREASE_NUMBER, TRUE, ACTION_ACTIVE, SND_CLASS_DYNABOMB_ACTIVE }, { EL_SATELLITE, FALSE, ACTION_MOVING, SND_SATELLITE_MOVING }, { EL_SATELLITE, FALSE, ACTION_WAITING, SND_SATELLITE_WAITING }, { EL_SATELLITE, FALSE, ACTION_PUSHING, SND_SATELLITE_PUSHING }, { EL_LAMP, FALSE, ACTION_ACTIVATING, SND_LAMP_ACTIVATING }, { EL_LAMP, FALSE, ACTION_DEACTIVATING, SND_LAMP_DEACTIVATING }, { EL_TIME_ORB_FULL, FALSE, ACTION_COLLECTING, SND_TIME_ORB_FULL_COLLECTING }, { EL_TIME_ORB_FULL, FALSE, ACTION_IMPACT, SND_TIME_ORB_FULL_IMPACT }, { EL_TIME_ORB_EMPTY, FALSE, ACTION_PUSHING, SND_TIME_ORB_EMPTY_PUSHING }, { EL_TIME_ORB_EMPTY, FALSE, ACTION_IMPACT, SND_TIME_ORB_EMPTY_IMPACT }, { EL_GAME_OF_LIFE, FALSE, ACTION_WAITING, SND_GAME_OF_LIFE_WAITING }, { EL_GAME_OF_LIFE, FALSE, ACTION_GROWING, SND_GAME_OF_LIFE_GROWING }, { EL_BIOMAZE, FALSE, ACTION_WAITING, SND_BIOMAZE_WAITING }, { EL_BIOMAZE, FALSE, ACTION_GROWING, SND_BIOMAZE_GROWING }, { EL_PACMAN, FALSE, ACTION_MOVING, SND_PACMAN_MOVING }, { EL_PACMAN, FALSE, ACTION_WAITING, SND_PACMAN_WAITING }, { EL_PACMAN, FALSE, ACTION_DIGGING, SND_PACMAN_DIGGING }, { EL_DARK_YAMYAM, FALSE, ACTION_MOVING, SND_DARK_YAMYAM_MOVING }, { EL_DARK_YAMYAM, FALSE, ACTION_WAITING, SND_DARK_YAMYAM_WAITING }, { EL_DARK_YAMYAM, FALSE, ACTION_DIGGING, SND_DARK_YAMYAM_DIGGING }, { EL_PENGUIN, FALSE, ACTION_MOVING, SND_PENGUIN_MOVING }, { EL_PENGUIN, FALSE, ACTION_WAITING, SND_PENGUIN_WAITING }, { EL_PIG, FALSE, ACTION_MOVING, SND_PIG_MOVING }, { EL_PIG, FALSE, ACTION_WAITING, SND_PIG_WAITING }, { EL_PIG, FALSE, ACTION_DIGGING, SND_PIG_DIGGING }, { EL_DRAGON, FALSE, ACTION_MOVING, SND_DRAGON_MOVING }, { EL_DRAGON, FALSE, ACTION_WAITING, SND_DRAGON_WAITING }, { EL_DRAGON, FALSE, ACTION_ATTACKING, SND_DRAGON_ATTACKING }, { EL_MM_MCDUFFIN_RIGHT, TRUE, ACTION_HITTING, SND_CLASS_MM_MCDUFFIN_HITTING }, { EL_MM_MIRROR_1, TRUE, ACTION_HITTING, SND_CLASS_MM_MIRROR_HITTING }, { EL_MM_MIRROR_FIXED_1, TRUE, ACTION_HITTING, SND_CLASS_MM_MIRROR_FIXED_HITTING }, { EL_MM_PRISM, TRUE, ACTION_HITTING, SND_CLASS_MM_PRISM_HITTING }, { EL_MM_EXIT_CLOSED, TRUE, ACTION_HITTING, SND_CLASS_MM_EXIT_HITTING }, { EL_MM_EXIT_CLOSED, TRUE, ACTION_OPENING, SND_CLASS_MM_EXIT_OPENING }, { EL_MM_EXIT_OPEN, FALSE, ACTION_HITTING, SND_MM_EXIT_OPEN_HITTING }, { EL_DF_MIRROR_1, TRUE, ACTION_HITTING, SND_CLASS_DF_MIRROR_HITTING }, { EL_DF_MIRROR_ROTATING_1, TRUE, ACTION_HITTING, SND_CLASS_DF_MIRROR_ROTATING_HITTING }, { EL_DF_REFRACTOR, TRUE, ACTION_HITTING, SND_CLASS_DF_REFRACTOR_HITTING }, { EL_DF_RECEIVER_RIGHT, TRUE, ACTION_HITTING, SND_CLASS_DF_RECEIVER_HITTING }, { EL_DF_RECEIVER_RIGHT, TRUE, ACTION_OPENING, SND_CLASS_DF_RECEIVER_OPENING }, { EL_MM_WOODEN_WALL_1, TRUE, ACTION_HITTING, SND_CLASS_MM_WOODEN_WALL_HITTING }, { EL_MM_WOODEN_BLOCK, TRUE, ACTION_HITTING, SND_CLASS_MM_WOODEN_BLOCK_HITTING }, { EL_MM_WOODEN_BLOCK, TRUE, ACTION_PUSHING, SND_CLASS_MM_WOODEN_BLOCK_PUSHING }, { EL_MM_WOODEN_LOCK, TRUE, ACTION_HITTING, SND_CLASS_MM_WOODEN_LOCK_HITTING }, { EL_MM_WOODEN_GRID_FIXED_1, TRUE, ACTION_HITTING, SND_CLASS_MM_WOODEN_GRID_FIXED_HITTING }, { EL_MM_FUSE_ACTIVE, TRUE, ACTION_HITTING, SND_CLASS_MM_FUSE_HITTING }, { EL_MM_ICE_WALL_1, TRUE, ACTION_HITTING, SND_CLASS_MM_ICE_WALL_HITTING }, { EL_MM_ICE_WALL_1, TRUE, ACTION_SHRINKING, SND_CLASS_MM_ICE_WALL_SHRINKING }, { EL_MM_AMOEBA_WALL_1, TRUE, ACTION_HITTING, SND_CLASS_MM_AMOEBA_WALL_HITTING }, { EL_MM_AMOEBA_WALL_1, TRUE, ACTION_GROWING, SND_CLASS_MM_AMOEBA_WALL_GROWING }, { EL_DF_WOODEN_WALL_1, TRUE, ACTION_HITTING, SND_CLASS_DF_WOODEN_WALL_HITTING }, { EL_DF_WOODEN_GRID_FIXED_1, TRUE, ACTION_HITTING, SND_CLASS_DF_WOODEN_GRID_FIXED_HITTING }, { EL_DF_WOODEN_GRID_ROTATING_1, TRUE, ACTION_HITTING, SND_CLASS_DF_WOODEN_GRID_ROTATING_HITTING }, { EL_MM_STEEL_WALL_1, TRUE, ACTION_HITTING, SND_CLASS_MM_STEEL_WALL_HITTING }, { EL_MM_STEEL_GRID_FIXED_1, TRUE, ACTION_HITTING, SND_CLASS_MM_STEEL_GRID_FIXED_HITTING }, { EL_MM_STEEL_BLOCK, TRUE, ACTION_HITTING, SND_CLASS_MM_STEEL_BLOCK_HITTING }, { EL_MM_STEEL_BLOCK, TRUE, ACTION_PUSHING, SND_CLASS_MM_STEEL_BLOCK_PUSHING }, { EL_MM_STEEL_LOCK, TRUE, ACTION_HITTING, SND_CLASS_MM_STEEL_LOCK_HITTING }, { EL_DF_STEEL_WALL_1, TRUE, ACTION_HITTING, SND_CLASS_DF_STEEL_WALL_HITTING }, { EL_DF_STEEL_GRID_FIXED_1, TRUE, ACTION_HITTING, SND_CLASS_DF_STEEL_GRID_FIXED_HITTING }, { EL_DF_STEEL_GRID_ROTATING_1, TRUE, ACTION_HITTING, SND_CLASS_DF_STEEL_GRID_ROTATING_HITTING }, { EL_MM_PACMAN_RIGHT, TRUE, ACTION_EXPLODING, SND_CLASS_MM_PACMAN_EXPLODING }, { EL_MM_MCDUFFIN_RIGHT, TRUE, ACTION_EXPLODING, SND_CLASS_MM_MCDUFFIN_EXPLODING }, { EL_MM_BOMB, TRUE, ACTION_EXPLODING, SND_CLASS_MM_BOMB_EXPLODING }, { EL_MM_KEY, TRUE, ACTION_EXPLODING, SND_CLASS_MM_KEY_EXPLODING }, { EL_MM_STEEL_LOCK, TRUE, ACTION_EXPLODING, SND_CLASS_MM_STEEL_LOCK_EXPLODING }, { EL_MM_WOODEN_LOCK, TRUE, ACTION_EXPLODING, SND_CLASS_MM_WOODEN_LOCK_EXPLODING }, { -1, -1, -1, -1 }, }; #endif /* CONF_E2S_C */ mirrormagic-3.0.0/src/conf_var.c0000644000175000017500000054652113263214151016076 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_var.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_VAR_C #define CONF_VAR_C /* values for image and layout parameter configuration */ struct TokenIntPtrInfo image_config_vars[] = { { "[title_initial].fade_mode", &title_initial_default.fade_mode }, { "[title_initial].fade_mode", &title_initial_first_default.fade_mode }, { "[title_initial].fade_delay", &title_initial_default.fade_delay }, { "[title_initial].fade_delay", &title_initial_first_default.fade_delay }, { "[title_initial].post_delay", &title_initial_default.post_delay }, { "[title_initial].post_delay", &title_initial_first_default.post_delay }, { "[title_initial].auto_delay", &title_initial_default.auto_delay }, { "[title_initial].auto_delay", &title_initial_first_default.auto_delay }, { "[title].fade_mode", &title_default.fade_mode }, { "[title].fade_mode", &title_first_default.fade_mode }, { "[title].fade_delay", &title_default.fade_delay }, { "[title].fade_delay", &title_first_default.fade_delay }, { "[title].post_delay", &title_default.post_delay }, { "[title].post_delay", &title_first_default.post_delay }, { "[title].auto_delay", &title_default.auto_delay }, { "[title].auto_delay", &title_first_default.auto_delay }, { "[titlescreen_initial].sort_priority", &titlescreen_initial_default.sort_priority }, { "[titlescreen_initial].fade_mode", &titlescreen_initial_default.fade_mode }, { "[titlescreen_initial].fade_delay", &titlescreen_initial_default.fade_delay }, { "[titlescreen_initial].post_delay", &titlescreen_initial_default.post_delay }, { "[titlescreen_initial].auto_delay", &titlescreen_initial_default.auto_delay }, { "[titlescreen].sort_priority", &titlescreen_default.sort_priority }, { "[titlescreen].fade_mode", &titlescreen_default.fade_mode }, { "[titlescreen].fade_delay", &titlescreen_default.fade_delay }, { "[titlescreen].post_delay", &titlescreen_default.post_delay }, { "[titlescreen].auto_delay", &titlescreen_default.auto_delay }, { "titlescreen_initial_1.sort_priority", &titlescreen_initial[0].sort_priority }, { "titlescreen_initial_1.sort_priority", &titlescreen_initial_first[0].sort_priority }, { "titlescreen_initial_1.fade_mode", &titlescreen_initial[0].fade_mode }, { "titlescreen_initial_1.fade_mode", &titlescreen_initial_first[0].fade_mode }, { "titlescreen_initial_1.fade_delay", &titlescreen_initial[0].fade_delay }, { "titlescreen_initial_1.fade_delay", &titlescreen_initial_first[0].fade_delay }, { "titlescreen_initial_1.post_delay", &titlescreen_initial[0].post_delay }, { "titlescreen_initial_1.post_delay", &titlescreen_initial_first[0].post_delay }, { "titlescreen_initial_1.auto_delay", &titlescreen_initial[0].auto_delay }, { "titlescreen_initial_1.auto_delay", &titlescreen_initial_first[0].auto_delay }, { "titlescreen_initial_2.sort_priority", &titlescreen_initial[1].sort_priority }, { "titlescreen_initial_2.sort_priority", &titlescreen_initial_first[1].sort_priority }, { "titlescreen_initial_2.fade_mode", &titlescreen_initial[1].fade_mode }, { "titlescreen_initial_2.fade_mode", &titlescreen_initial_first[1].fade_mode }, { "titlescreen_initial_2.fade_delay", &titlescreen_initial[1].fade_delay }, { "titlescreen_initial_2.fade_delay", &titlescreen_initial_first[1].fade_delay }, { "titlescreen_initial_2.post_delay", &titlescreen_initial[1].post_delay }, { "titlescreen_initial_2.post_delay", &titlescreen_initial_first[1].post_delay }, { "titlescreen_initial_2.auto_delay", &titlescreen_initial[1].auto_delay }, { "titlescreen_initial_2.auto_delay", &titlescreen_initial_first[1].auto_delay }, { "titlescreen_initial_3.sort_priority", &titlescreen_initial[2].sort_priority }, { "titlescreen_initial_3.sort_priority", &titlescreen_initial_first[2].sort_priority }, { "titlescreen_initial_3.fade_mode", &titlescreen_initial[2].fade_mode }, { "titlescreen_initial_3.fade_mode", &titlescreen_initial_first[2].fade_mode }, { "titlescreen_initial_3.fade_delay", &titlescreen_initial[2].fade_delay }, { "titlescreen_initial_3.fade_delay", &titlescreen_initial_first[2].fade_delay }, { "titlescreen_initial_3.post_delay", &titlescreen_initial[2].post_delay }, { "titlescreen_initial_3.post_delay", &titlescreen_initial_first[2].post_delay }, { "titlescreen_initial_3.auto_delay", &titlescreen_initial[2].auto_delay }, { "titlescreen_initial_3.auto_delay", &titlescreen_initial_first[2].auto_delay }, { "titlescreen_initial_4.sort_priority", &titlescreen_initial[3].sort_priority }, { "titlescreen_initial_4.sort_priority", &titlescreen_initial_first[3].sort_priority }, { "titlescreen_initial_4.fade_mode", &titlescreen_initial[3].fade_mode }, { "titlescreen_initial_4.fade_mode", &titlescreen_initial_first[3].fade_mode }, { "titlescreen_initial_4.fade_delay", &titlescreen_initial[3].fade_delay }, { "titlescreen_initial_4.fade_delay", &titlescreen_initial_first[3].fade_delay }, { "titlescreen_initial_4.post_delay", &titlescreen_initial[3].post_delay }, { "titlescreen_initial_4.post_delay", &titlescreen_initial_first[3].post_delay }, { "titlescreen_initial_4.auto_delay", &titlescreen_initial[3].auto_delay }, { "titlescreen_initial_4.auto_delay", &titlescreen_initial_first[3].auto_delay }, { "titlescreen_initial_5.sort_priority", &titlescreen_initial[4].sort_priority }, { "titlescreen_initial_5.sort_priority", &titlescreen_initial_first[4].sort_priority }, { "titlescreen_initial_5.fade_mode", &titlescreen_initial[4].fade_mode }, { "titlescreen_initial_5.fade_mode", &titlescreen_initial_first[4].fade_mode }, { "titlescreen_initial_5.fade_delay", &titlescreen_initial[4].fade_delay }, { "titlescreen_initial_5.fade_delay", &titlescreen_initial_first[4].fade_delay }, { "titlescreen_initial_5.post_delay", &titlescreen_initial[4].post_delay }, { "titlescreen_initial_5.post_delay", &titlescreen_initial_first[4].post_delay }, { "titlescreen_initial_5.auto_delay", &titlescreen_initial[4].auto_delay }, { "titlescreen_initial_5.auto_delay", &titlescreen_initial_first[4].auto_delay }, { "titlescreen_1.sort_priority", &titlescreen[0].sort_priority }, { "titlescreen_1.sort_priority", &titlescreen_first[0].sort_priority }, { "titlescreen_1.fade_mode", &titlescreen[0].fade_mode }, { "titlescreen_1.fade_mode", &titlescreen_first[0].fade_mode }, { "titlescreen_1.fade_delay", &titlescreen[0].fade_delay }, { "titlescreen_1.fade_delay", &titlescreen_first[0].fade_delay }, { "titlescreen_1.post_delay", &titlescreen[0].post_delay }, { "titlescreen_1.post_delay", &titlescreen_first[0].post_delay }, { "titlescreen_1.auto_delay", &titlescreen[0].auto_delay }, { "titlescreen_1.auto_delay", &titlescreen_first[0].auto_delay }, { "titlescreen_2.sort_priority", &titlescreen[1].sort_priority }, { "titlescreen_2.sort_priority", &titlescreen_first[1].sort_priority }, { "titlescreen_2.fade_mode", &titlescreen[1].fade_mode }, { "titlescreen_2.fade_mode", &titlescreen_first[1].fade_mode }, { "titlescreen_2.fade_delay", &titlescreen[1].fade_delay }, { "titlescreen_2.fade_delay", &titlescreen_first[1].fade_delay }, { "titlescreen_2.post_delay", &titlescreen[1].post_delay }, { "titlescreen_2.post_delay", &titlescreen_first[1].post_delay }, { "titlescreen_2.auto_delay", &titlescreen[1].auto_delay }, { "titlescreen_2.auto_delay", &titlescreen_first[1].auto_delay }, { "titlescreen_3.sort_priority", &titlescreen[2].sort_priority }, { "titlescreen_3.sort_priority", &titlescreen_first[2].sort_priority }, { "titlescreen_3.fade_mode", &titlescreen[2].fade_mode }, { "titlescreen_3.fade_mode", &titlescreen_first[2].fade_mode }, { "titlescreen_3.fade_delay", &titlescreen[2].fade_delay }, { "titlescreen_3.fade_delay", &titlescreen_first[2].fade_delay }, { "titlescreen_3.post_delay", &titlescreen[2].post_delay }, { "titlescreen_3.post_delay", &titlescreen_first[2].post_delay }, { "titlescreen_3.auto_delay", &titlescreen[2].auto_delay }, { "titlescreen_3.auto_delay", &titlescreen_first[2].auto_delay }, { "titlescreen_4.sort_priority", &titlescreen[3].sort_priority }, { "titlescreen_4.sort_priority", &titlescreen_first[3].sort_priority }, { "titlescreen_4.fade_mode", &titlescreen[3].fade_mode }, { "titlescreen_4.fade_mode", &titlescreen_first[3].fade_mode }, { "titlescreen_4.fade_delay", &titlescreen[3].fade_delay }, { "titlescreen_4.fade_delay", &titlescreen_first[3].fade_delay }, { "titlescreen_4.post_delay", &titlescreen[3].post_delay }, { "titlescreen_4.post_delay", &titlescreen_first[3].post_delay }, { "titlescreen_4.auto_delay", &titlescreen[3].auto_delay }, { "titlescreen_4.auto_delay", &titlescreen_first[3].auto_delay }, { "titlescreen_5.sort_priority", &titlescreen[4].sort_priority }, { "titlescreen_5.sort_priority", &titlescreen_first[4].sort_priority }, { "titlescreen_5.fade_mode", &titlescreen[4].fade_mode }, { "titlescreen_5.fade_mode", &titlescreen_first[4].fade_mode }, { "titlescreen_5.fade_delay", &titlescreen[4].fade_delay }, { "titlescreen_5.fade_delay", &titlescreen_first[4].fade_delay }, { "titlescreen_5.post_delay", &titlescreen[4].post_delay }, { "titlescreen_5.post_delay", &titlescreen_first[4].post_delay }, { "titlescreen_5.auto_delay", &titlescreen[4].auto_delay }, { "titlescreen_5.auto_delay", &titlescreen_first[4].auto_delay }, { "[titlemessage_initial].x", &titlemessage_initial_default.x }, { "[titlemessage_initial].y", &titlemessage_initial_default.y }, { "[titlemessage_initial].width", &titlemessage_initial_default.width }, { "[titlemessage_initial].height", &titlemessage_initial_default.height }, { "[titlemessage_initial].chars", &titlemessage_initial_default.chars }, { "[titlemessage_initial].lines", &titlemessage_initial_default.lines }, { "[titlemessage_initial].align", &titlemessage_initial_default.align }, { "[titlemessage_initial].valign", &titlemessage_initial_default.valign }, { "[titlemessage_initial].font", &titlemessage_initial_default.font }, { "[titlemessage_initial].autowrap", &titlemessage_initial_default.autowrap }, { "[titlemessage_initial].centered", &titlemessage_initial_default.centered }, { "[titlemessage_initial].parse_comments", &titlemessage_initial_default.parse_comments }, { "[titlemessage_initial].sort_priority", &titlemessage_initial_default.sort_priority }, { "[titlemessage_initial].fade_mode", &titlemessage_initial_default.fade_mode }, { "[titlemessage_initial].fade_delay", &titlemessage_initial_default.fade_delay }, { "[titlemessage_initial].post_delay", &titlemessage_initial_default.post_delay }, { "[titlemessage_initial].auto_delay", &titlemessage_initial_default.auto_delay }, { "[titlemessage].x", &titlemessage_default.x }, { "[titlemessage].y", &titlemessage_default.y }, { "[titlemessage].width", &titlemessage_default.width }, { "[titlemessage].height", &titlemessage_default.height }, { "[titlemessage].chars", &titlemessage_default.chars }, { "[titlemessage].lines", &titlemessage_default.lines }, { "[titlemessage].align", &titlemessage_default.align }, { "[titlemessage].valign", &titlemessage_default.valign }, { "[titlemessage].font", &titlemessage_default.font }, { "[titlemessage].autowrap", &titlemessage_default.autowrap }, { "[titlemessage].centered", &titlemessage_default.centered }, { "[titlemessage].parse_comments", &titlemessage_default.parse_comments }, { "[titlemessage].sort_priority", &titlemessage_default.sort_priority }, { "[titlemessage].fade_mode", &titlemessage_default.fade_mode }, { "[titlemessage].fade_delay", &titlemessage_default.fade_delay }, { "[titlemessage].post_delay", &titlemessage_default.post_delay }, { "[titlemessage].auto_delay", &titlemessage_default.auto_delay }, { "titlemessage_initial_1.x", &titlemessage_initial[0].x }, { "titlemessage_initial_1.x", &titlemessage_initial_first[0].x }, { "titlemessage_initial_1.y", &titlemessage_initial[0].y }, { "titlemessage_initial_1.y", &titlemessage_initial_first[0].y }, { "titlemessage_initial_1.width", &titlemessage_initial[0].width }, { "titlemessage_initial_1.width", &titlemessage_initial_first[0].width }, { "titlemessage_initial_1.height", &titlemessage_initial[0].height }, { "titlemessage_initial_1.height", &titlemessage_initial_first[0].height }, { "titlemessage_initial_1.chars", &titlemessage_initial[0].chars }, { "titlemessage_initial_1.chars", &titlemessage_initial_first[0].chars }, { "titlemessage_initial_1.lines", &titlemessage_initial[0].lines }, { "titlemessage_initial_1.lines", &titlemessage_initial_first[0].lines }, { "titlemessage_initial_1.align", &titlemessage_initial[0].align }, { "titlemessage_initial_1.align", &titlemessage_initial_first[0].align }, { "titlemessage_initial_1.valign", &titlemessage_initial[0].valign }, { "titlemessage_initial_1.valign", &titlemessage_initial_first[0].valign }, { "titlemessage_initial_1.font", &titlemessage_initial[0].font }, { "titlemessage_initial_1.font", &titlemessage_initial_first[0].font }, { "titlemessage_initial_1.autowrap", &titlemessage_initial[0].autowrap }, { "titlemessage_initial_1.autowrap", &titlemessage_initial_first[0].autowrap }, { "titlemessage_initial_1.centered", &titlemessage_initial[0].centered }, { "titlemessage_initial_1.centered", &titlemessage_initial_first[0].centered }, { "titlemessage_initial_1.parse_comments", &titlemessage_initial[0].parse_comments }, { "titlemessage_initial_1.parse_comments", &titlemessage_initial_first[0].parse_comments }, { "titlemessage_initial_1.sort_priority", &titlemessage_initial[0].sort_priority }, { "titlemessage_initial_1.sort_priority", &titlemessage_initial_first[0].sort_priority }, { "titlemessage_initial_1.fade_mode", &titlemessage_initial[0].fade_mode }, { "titlemessage_initial_1.fade_mode", &titlemessage_initial_first[0].fade_mode }, { "titlemessage_initial_1.fade_delay", &titlemessage_initial[0].fade_delay }, { "titlemessage_initial_1.fade_delay", &titlemessage_initial_first[0].fade_delay }, { "titlemessage_initial_1.post_delay", &titlemessage_initial[0].post_delay }, { "titlemessage_initial_1.post_delay", &titlemessage_initial_first[0].post_delay }, { "titlemessage_initial_1.auto_delay", &titlemessage_initial[0].auto_delay }, { "titlemessage_initial_1.auto_delay", &titlemessage_initial_first[0].auto_delay }, { "titlemessage_initial_2.x", &titlemessage_initial[1].x }, { "titlemessage_initial_2.x", &titlemessage_initial_first[1].x }, { "titlemessage_initial_2.y", &titlemessage_initial[1].y }, { "titlemessage_initial_2.y", &titlemessage_initial_first[1].y }, { "titlemessage_initial_2.width", &titlemessage_initial[1].width }, { "titlemessage_initial_2.width", &titlemessage_initial_first[1].width }, { "titlemessage_initial_2.height", &titlemessage_initial[1].height }, { "titlemessage_initial_2.height", &titlemessage_initial_first[1].height }, { "titlemessage_initial_2.chars", &titlemessage_initial[1].chars }, { "titlemessage_initial_2.chars", &titlemessage_initial_first[1].chars }, { "titlemessage_initial_2.lines", &titlemessage_initial[1].lines }, { "titlemessage_initial_2.lines", &titlemessage_initial_first[1].lines }, { "titlemessage_initial_2.align", &titlemessage_initial[1].align }, { "titlemessage_initial_2.align", &titlemessage_initial_first[1].align }, { "titlemessage_initial_2.valign", &titlemessage_initial[1].valign }, { "titlemessage_initial_2.valign", &titlemessage_initial_first[1].valign }, { "titlemessage_initial_2.font", &titlemessage_initial[1].font }, { "titlemessage_initial_2.font", &titlemessage_initial_first[1].font }, { "titlemessage_initial_2.autowrap", &titlemessage_initial[1].autowrap }, { "titlemessage_initial_2.autowrap", &titlemessage_initial_first[1].autowrap }, { "titlemessage_initial_2.centered", &titlemessage_initial[1].centered }, { "titlemessage_initial_2.centered", &titlemessage_initial_first[1].centered }, { "titlemessage_initial_2.parse_comments", &titlemessage_initial[1].parse_comments }, { "titlemessage_initial_2.parse_comments", &titlemessage_initial_first[1].parse_comments }, { "titlemessage_initial_2.sort_priority", &titlemessage_initial[1].sort_priority }, { "titlemessage_initial_2.sort_priority", &titlemessage_initial_first[1].sort_priority }, { "titlemessage_initial_2.fade_mode", &titlemessage_initial[1].fade_mode }, { "titlemessage_initial_2.fade_mode", &titlemessage_initial_first[1].fade_mode }, { "titlemessage_initial_2.fade_delay", &titlemessage_initial[1].fade_delay }, { "titlemessage_initial_2.fade_delay", &titlemessage_initial_first[1].fade_delay }, { "titlemessage_initial_2.post_delay", &titlemessage_initial[1].post_delay }, { "titlemessage_initial_2.post_delay", &titlemessage_initial_first[1].post_delay }, { "titlemessage_initial_2.auto_delay", &titlemessage_initial[1].auto_delay }, { "titlemessage_initial_2.auto_delay", &titlemessage_initial_first[1].auto_delay }, { "titlemessage_initial_3.x", &titlemessage_initial[2].x }, { "titlemessage_initial_3.x", &titlemessage_initial_first[2].x }, { "titlemessage_initial_3.y", &titlemessage_initial[2].y }, { "titlemessage_initial_3.y", &titlemessage_initial_first[2].y }, { "titlemessage_initial_3.width", &titlemessage_initial[2].width }, { "titlemessage_initial_3.width", &titlemessage_initial_first[2].width }, { "titlemessage_initial_3.height", &titlemessage_initial[2].height }, { "titlemessage_initial_3.height", &titlemessage_initial_first[2].height }, { "titlemessage_initial_3.chars", &titlemessage_initial[2].chars }, { "titlemessage_initial_3.chars", &titlemessage_initial_first[2].chars }, { "titlemessage_initial_3.lines", &titlemessage_initial[2].lines }, { "titlemessage_initial_3.lines", &titlemessage_initial_first[2].lines }, { "titlemessage_initial_3.align", &titlemessage_initial[2].align }, { "titlemessage_initial_3.align", &titlemessage_initial_first[2].align }, { "titlemessage_initial_3.valign", &titlemessage_initial[2].valign }, { "titlemessage_initial_3.valign", &titlemessage_initial_first[2].valign }, { "titlemessage_initial_3.font", &titlemessage_initial[2].font }, { "titlemessage_initial_3.font", &titlemessage_initial_first[2].font }, { "titlemessage_initial_3.autowrap", &titlemessage_initial[2].autowrap }, { "titlemessage_initial_3.autowrap", &titlemessage_initial_first[2].autowrap }, { "titlemessage_initial_3.centered", &titlemessage_initial[2].centered }, { "titlemessage_initial_3.centered", &titlemessage_initial_first[2].centered }, { "titlemessage_initial_3.parse_comments", &titlemessage_initial[2].parse_comments }, { "titlemessage_initial_3.parse_comments", &titlemessage_initial_first[2].parse_comments }, { "titlemessage_initial_3.sort_priority", &titlemessage_initial[2].sort_priority }, { "titlemessage_initial_3.sort_priority", &titlemessage_initial_first[2].sort_priority }, { "titlemessage_initial_3.fade_mode", &titlemessage_initial[2].fade_mode }, { "titlemessage_initial_3.fade_mode", &titlemessage_initial_first[2].fade_mode }, { "titlemessage_initial_3.fade_delay", &titlemessage_initial[2].fade_delay }, { "titlemessage_initial_3.fade_delay", &titlemessage_initial_first[2].fade_delay }, { "titlemessage_initial_3.post_delay", &titlemessage_initial[2].post_delay }, { "titlemessage_initial_3.post_delay", &titlemessage_initial_first[2].post_delay }, { "titlemessage_initial_3.auto_delay", &titlemessage_initial[2].auto_delay }, { "titlemessage_initial_3.auto_delay", &titlemessage_initial_first[2].auto_delay }, { "titlemessage_initial_4.x", &titlemessage_initial[3].x }, { "titlemessage_initial_4.x", &titlemessage_initial_first[3].x }, { "titlemessage_initial_4.y", &titlemessage_initial[3].y }, { "titlemessage_initial_4.y", &titlemessage_initial_first[3].y }, { "titlemessage_initial_4.width", &titlemessage_initial[3].width }, { "titlemessage_initial_4.width", &titlemessage_initial_first[3].width }, { "titlemessage_initial_4.height", &titlemessage_initial[3].height }, { "titlemessage_initial_4.height", &titlemessage_initial_first[3].height }, { "titlemessage_initial_4.chars", &titlemessage_initial[3].chars }, { "titlemessage_initial_4.chars", &titlemessage_initial_first[3].chars }, { "titlemessage_initial_4.lines", &titlemessage_initial[3].lines }, { "titlemessage_initial_4.lines", &titlemessage_initial_first[3].lines }, { "titlemessage_initial_4.align", &titlemessage_initial[3].align }, { "titlemessage_initial_4.align", &titlemessage_initial_first[3].align }, { "titlemessage_initial_4.valign", &titlemessage_initial[3].valign }, { "titlemessage_initial_4.valign", &titlemessage_initial_first[3].valign }, { "titlemessage_initial_4.font", &titlemessage_initial[3].font }, { "titlemessage_initial_4.font", &titlemessage_initial_first[3].font }, { "titlemessage_initial_4.autowrap", &titlemessage_initial[3].autowrap }, { "titlemessage_initial_4.autowrap", &titlemessage_initial_first[3].autowrap }, { "titlemessage_initial_4.centered", &titlemessage_initial[3].centered }, { "titlemessage_initial_4.centered", &titlemessage_initial_first[3].centered }, { "titlemessage_initial_4.parse_comments", &titlemessage_initial[3].parse_comments }, { "titlemessage_initial_4.parse_comments", &titlemessage_initial_first[3].parse_comments }, { "titlemessage_initial_4.sort_priority", &titlemessage_initial[3].sort_priority }, { "titlemessage_initial_4.sort_priority", &titlemessage_initial_first[3].sort_priority }, { "titlemessage_initial_4.fade_mode", &titlemessage_initial[3].fade_mode }, { "titlemessage_initial_4.fade_mode", &titlemessage_initial_first[3].fade_mode }, { "titlemessage_initial_4.fade_delay", &titlemessage_initial[3].fade_delay }, { "titlemessage_initial_4.fade_delay", &titlemessage_initial_first[3].fade_delay }, { "titlemessage_initial_4.post_delay", &titlemessage_initial[3].post_delay }, { "titlemessage_initial_4.post_delay", &titlemessage_initial_first[3].post_delay }, { "titlemessage_initial_4.auto_delay", &titlemessage_initial[3].auto_delay }, { "titlemessage_initial_4.auto_delay", &titlemessage_initial_first[3].auto_delay }, { "titlemessage_initial_5.x", &titlemessage_initial[4].x }, { "titlemessage_initial_5.x", &titlemessage_initial_first[4].x }, { "titlemessage_initial_5.y", &titlemessage_initial[4].y }, { "titlemessage_initial_5.y", &titlemessage_initial_first[4].y }, { "titlemessage_initial_5.width", &titlemessage_initial[4].width }, { "titlemessage_initial_5.width", &titlemessage_initial_first[4].width }, { "titlemessage_initial_5.height", &titlemessage_initial[4].height }, { "titlemessage_initial_5.height", &titlemessage_initial_first[4].height }, { "titlemessage_initial_5.chars", &titlemessage_initial[4].chars }, { "titlemessage_initial_5.chars", &titlemessage_initial_first[4].chars }, { "titlemessage_initial_5.lines", &titlemessage_initial[4].lines }, { "titlemessage_initial_5.lines", &titlemessage_initial_first[4].lines }, { "titlemessage_initial_5.align", &titlemessage_initial[4].align }, { "titlemessage_initial_5.align", &titlemessage_initial_first[4].align }, { "titlemessage_initial_5.valign", &titlemessage_initial[4].valign }, { "titlemessage_initial_5.valign", &titlemessage_initial_first[4].valign }, { "titlemessage_initial_5.font", &titlemessage_initial[4].font }, { "titlemessage_initial_5.font", &titlemessage_initial_first[4].font }, { "titlemessage_initial_5.autowrap", &titlemessage_initial[4].autowrap }, { "titlemessage_initial_5.autowrap", &titlemessage_initial_first[4].autowrap }, { "titlemessage_initial_5.centered", &titlemessage_initial[4].centered }, { "titlemessage_initial_5.centered", &titlemessage_initial_first[4].centered }, { "titlemessage_initial_5.parse_comments", &titlemessage_initial[4].parse_comments }, { "titlemessage_initial_5.parse_comments", &titlemessage_initial_first[4].parse_comments }, { "titlemessage_initial_5.sort_priority", &titlemessage_initial[4].sort_priority }, { "titlemessage_initial_5.sort_priority", &titlemessage_initial_first[4].sort_priority }, { "titlemessage_initial_5.fade_mode", &titlemessage_initial[4].fade_mode }, { "titlemessage_initial_5.fade_mode", &titlemessage_initial_first[4].fade_mode }, { "titlemessage_initial_5.fade_delay", &titlemessage_initial[4].fade_delay }, { "titlemessage_initial_5.fade_delay", &titlemessage_initial_first[4].fade_delay }, { "titlemessage_initial_5.post_delay", &titlemessage_initial[4].post_delay }, { "titlemessage_initial_5.post_delay", &titlemessage_initial_first[4].post_delay }, { "titlemessage_initial_5.auto_delay", &titlemessage_initial[4].auto_delay }, { "titlemessage_initial_5.auto_delay", &titlemessage_initial_first[4].auto_delay }, { "titlemessage_1.x", &titlemessage[0].x }, { "titlemessage_1.x", &titlemessage_first[0].x }, { "titlemessage_1.y", &titlemessage[0].y }, { "titlemessage_1.y", &titlemessage_first[0].y }, { "titlemessage_1.width", &titlemessage[0].width }, { "titlemessage_1.width", &titlemessage_first[0].width }, { "titlemessage_1.height", &titlemessage[0].height }, { "titlemessage_1.height", &titlemessage_first[0].height }, { "titlemessage_1.chars", &titlemessage[0].chars }, { "titlemessage_1.chars", &titlemessage_first[0].chars }, { "titlemessage_1.lines", &titlemessage[0].lines }, { "titlemessage_1.lines", &titlemessage_first[0].lines }, { "titlemessage_1.align", &titlemessage[0].align }, { "titlemessage_1.align", &titlemessage_first[0].align }, { "titlemessage_1.valign", &titlemessage[0].valign }, { "titlemessage_1.valign", &titlemessage_first[0].valign }, { "titlemessage_1.font", &titlemessage[0].font }, { "titlemessage_1.font", &titlemessage_first[0].font }, { "titlemessage_1.autowrap", &titlemessage[0].autowrap }, { "titlemessage_1.autowrap", &titlemessage_first[0].autowrap }, { "titlemessage_1.centered", &titlemessage[0].centered }, { "titlemessage_1.centered", &titlemessage_first[0].centered }, { "titlemessage_1.parse_comments", &titlemessage[0].parse_comments }, { "titlemessage_1.parse_comments", &titlemessage_first[0].parse_comments }, { "titlemessage_1.sort_priority", &titlemessage[0].sort_priority }, { "titlemessage_1.sort_priority", &titlemessage_first[0].sort_priority }, { "titlemessage_1.fade_mode", &titlemessage[0].fade_mode }, { "titlemessage_1.fade_mode", &titlemessage_first[0].fade_mode }, { "titlemessage_1.fade_delay", &titlemessage[0].fade_delay }, { "titlemessage_1.fade_delay", &titlemessage_first[0].fade_delay }, { "titlemessage_1.post_delay", &titlemessage[0].post_delay }, { "titlemessage_1.post_delay", &titlemessage_first[0].post_delay }, { "titlemessage_1.auto_delay", &titlemessage[0].auto_delay }, { "titlemessage_1.auto_delay", &titlemessage_first[0].auto_delay }, { "titlemessage_2.x", &titlemessage[1].x }, { "titlemessage_2.x", &titlemessage_first[1].x }, { "titlemessage_2.y", &titlemessage[1].y }, { "titlemessage_2.y", &titlemessage_first[1].y }, { "titlemessage_2.width", &titlemessage[1].width }, { "titlemessage_2.width", &titlemessage_first[1].width }, { "titlemessage_2.height", &titlemessage[1].height }, { "titlemessage_2.height", &titlemessage_first[1].height }, { "titlemessage_2.chars", &titlemessage[1].chars }, { "titlemessage_2.chars", &titlemessage_first[1].chars }, { "titlemessage_2.lines", &titlemessage[1].lines }, { "titlemessage_2.lines", &titlemessage_first[1].lines }, { "titlemessage_2.align", &titlemessage[1].align }, { "titlemessage_2.align", &titlemessage_first[1].align }, { "titlemessage_2.valign", &titlemessage[1].valign }, { "titlemessage_2.valign", &titlemessage_first[1].valign }, { "titlemessage_2.font", &titlemessage[1].font }, { "titlemessage_2.font", &titlemessage_first[1].font }, { "titlemessage_2.autowrap", &titlemessage[1].autowrap }, { "titlemessage_2.autowrap", &titlemessage_first[1].autowrap }, { "titlemessage_2.centered", &titlemessage[1].centered }, { "titlemessage_2.centered", &titlemessage_first[1].centered }, { "titlemessage_2.parse_comments", &titlemessage[1].parse_comments }, { "titlemessage_2.parse_comments", &titlemessage_first[1].parse_comments }, { "titlemessage_2.sort_priority", &titlemessage[1].sort_priority }, { "titlemessage_2.sort_priority", &titlemessage_first[1].sort_priority }, { "titlemessage_2.fade_mode", &titlemessage[1].fade_mode }, { "titlemessage_2.fade_mode", &titlemessage_first[1].fade_mode }, { "titlemessage_2.fade_delay", &titlemessage[1].fade_delay }, { "titlemessage_2.fade_delay", &titlemessage_first[1].fade_delay }, { "titlemessage_2.post_delay", &titlemessage[1].post_delay }, { "titlemessage_2.post_delay", &titlemessage_first[1].post_delay }, { "titlemessage_2.auto_delay", &titlemessage[1].auto_delay }, { "titlemessage_2.auto_delay", &titlemessage_first[1].auto_delay }, { "titlemessage_3.x", &titlemessage[2].x }, { "titlemessage_3.x", &titlemessage_first[2].x }, { "titlemessage_3.y", &titlemessage[2].y }, { "titlemessage_3.y", &titlemessage_first[2].y }, { "titlemessage_3.width", &titlemessage[2].width }, { "titlemessage_3.width", &titlemessage_first[2].width }, { "titlemessage_3.height", &titlemessage[2].height }, { "titlemessage_3.height", &titlemessage_first[2].height }, { "titlemessage_3.chars", &titlemessage[2].chars }, { "titlemessage_3.chars", &titlemessage_first[2].chars }, { "titlemessage_3.lines", &titlemessage[2].lines }, { "titlemessage_3.lines", &titlemessage_first[2].lines }, { "titlemessage_3.align", &titlemessage[2].align }, { "titlemessage_3.align", &titlemessage_first[2].align }, { "titlemessage_3.valign", &titlemessage[2].valign }, { "titlemessage_3.valign", &titlemessage_first[2].valign }, { "titlemessage_3.font", &titlemessage[2].font }, { "titlemessage_3.font", &titlemessage_first[2].font }, { "titlemessage_3.autowrap", &titlemessage[2].autowrap }, { "titlemessage_3.autowrap", &titlemessage_first[2].autowrap }, { "titlemessage_3.centered", &titlemessage[2].centered }, { "titlemessage_3.centered", &titlemessage_first[2].centered }, { "titlemessage_3.parse_comments", &titlemessage[2].parse_comments }, { "titlemessage_3.parse_comments", &titlemessage_first[2].parse_comments }, { "titlemessage_3.sort_priority", &titlemessage[2].sort_priority }, { "titlemessage_3.sort_priority", &titlemessage_first[2].sort_priority }, { "titlemessage_3.fade_mode", &titlemessage[2].fade_mode }, { "titlemessage_3.fade_mode", &titlemessage_first[2].fade_mode }, { "titlemessage_3.fade_delay", &titlemessage[2].fade_delay }, { "titlemessage_3.fade_delay", &titlemessage_first[2].fade_delay }, { "titlemessage_3.post_delay", &titlemessage[2].post_delay }, { "titlemessage_3.post_delay", &titlemessage_first[2].post_delay }, { "titlemessage_3.auto_delay", &titlemessage[2].auto_delay }, { "titlemessage_3.auto_delay", &titlemessage_first[2].auto_delay }, { "titlemessage_4.x", &titlemessage[3].x }, { "titlemessage_4.x", &titlemessage_first[3].x }, { "titlemessage_4.y", &titlemessage[3].y }, { "titlemessage_4.y", &titlemessage_first[3].y }, { "titlemessage_4.width", &titlemessage[3].width }, { "titlemessage_4.width", &titlemessage_first[3].width }, { "titlemessage_4.height", &titlemessage[3].height }, { "titlemessage_4.height", &titlemessage_first[3].height }, { "titlemessage_4.chars", &titlemessage[3].chars }, { "titlemessage_4.chars", &titlemessage_first[3].chars }, { "titlemessage_4.lines", &titlemessage[3].lines }, { "titlemessage_4.lines", &titlemessage_first[3].lines }, { "titlemessage_4.align", &titlemessage[3].align }, { "titlemessage_4.align", &titlemessage_first[3].align }, { "titlemessage_4.valign", &titlemessage[3].valign }, { "titlemessage_4.valign", &titlemessage_first[3].valign }, { "titlemessage_4.font", &titlemessage[3].font }, { "titlemessage_4.font", &titlemessage_first[3].font }, { "titlemessage_4.autowrap", &titlemessage[3].autowrap }, { "titlemessage_4.autowrap", &titlemessage_first[3].autowrap }, { "titlemessage_4.centered", &titlemessage[3].centered }, { "titlemessage_4.centered", &titlemessage_first[3].centered }, { "titlemessage_4.parse_comments", &titlemessage[3].parse_comments }, { "titlemessage_4.parse_comments", &titlemessage_first[3].parse_comments }, { "titlemessage_4.sort_priority", &titlemessage[3].sort_priority }, { "titlemessage_4.sort_priority", &titlemessage_first[3].sort_priority }, { "titlemessage_4.fade_mode", &titlemessage[3].fade_mode }, { "titlemessage_4.fade_mode", &titlemessage_first[3].fade_mode }, { "titlemessage_4.fade_delay", &titlemessage[3].fade_delay }, { "titlemessage_4.fade_delay", &titlemessage_first[3].fade_delay }, { "titlemessage_4.post_delay", &titlemessage[3].post_delay }, { "titlemessage_4.post_delay", &titlemessage_first[3].post_delay }, { "titlemessage_4.auto_delay", &titlemessage[3].auto_delay }, { "titlemessage_4.auto_delay", &titlemessage_first[3].auto_delay }, { "titlemessage_5.x", &titlemessage[4].x }, { "titlemessage_5.x", &titlemessage_first[4].x }, { "titlemessage_5.y", &titlemessage[4].y }, { "titlemessage_5.y", &titlemessage_first[4].y }, { "titlemessage_5.width", &titlemessage[4].width }, { "titlemessage_5.width", &titlemessage_first[4].width }, { "titlemessage_5.height", &titlemessage[4].height }, { "titlemessage_5.height", &titlemessage_first[4].height }, { "titlemessage_5.chars", &titlemessage[4].chars }, { "titlemessage_5.chars", &titlemessage_first[4].chars }, { "titlemessage_5.lines", &titlemessage[4].lines }, { "titlemessage_5.lines", &titlemessage_first[4].lines }, { "titlemessage_5.align", &titlemessage[4].align }, { "titlemessage_5.align", &titlemessage_first[4].align }, { "titlemessage_5.valign", &titlemessage[4].valign }, { "titlemessage_5.valign", &titlemessage_first[4].valign }, { "titlemessage_5.font", &titlemessage[4].font }, { "titlemessage_5.font", &titlemessage_first[4].font }, { "titlemessage_5.autowrap", &titlemessage[4].autowrap }, { "titlemessage_5.autowrap", &titlemessage_first[4].autowrap }, { "titlemessage_5.centered", &titlemessage[4].centered }, { "titlemessage_5.centered", &titlemessage_first[4].centered }, { "titlemessage_5.parse_comments", &titlemessage[4].parse_comments }, { "titlemessage_5.parse_comments", &titlemessage_first[4].parse_comments }, { "titlemessage_5.sort_priority", &titlemessage[4].sort_priority }, { "titlemessage_5.sort_priority", &titlemessage_first[4].sort_priority }, { "titlemessage_5.fade_mode", &titlemessage[4].fade_mode }, { "titlemessage_5.fade_mode", &titlemessage_first[4].fade_mode }, { "titlemessage_5.fade_delay", &titlemessage[4].fade_delay }, { "titlemessage_5.fade_delay", &titlemessage_first[4].fade_delay }, { "titlemessage_5.post_delay", &titlemessage[4].post_delay }, { "titlemessage_5.post_delay", &titlemessage_first[4].post_delay }, { "titlemessage_5.auto_delay", &titlemessage[4].auto_delay }, { "titlemessage_5.auto_delay", &titlemessage_first[4].auto_delay }, { "readme.x", &readme.x }, { "readme.y", &readme.y }, { "readme.width", &readme.width }, { "readme.height", &readme.height }, { "readme.chars", &readme.chars }, { "readme.lines", &readme.lines }, { "readme.align", &readme.align }, { "readme.valign", &readme.valign }, { "readme.font", &readme.font }, { "readme.autowrap", &readme.autowrap }, { "readme.centered", &readme.centered }, { "readme.parse_comments", &readme.parse_comments }, { "readme.sort_priority", &readme.sort_priority }, { "global.num_toons", &global.num_toons }, { "border.draw_masked.TITLE", &border.draw_masked[GFX_SPECIAL_ARG_TITLE] }, { "border.draw_masked.MAIN", &border.draw_masked[GFX_SPECIAL_ARG_MAIN] }, { "border.draw_masked.LEVELS", &border.draw_masked[GFX_SPECIAL_ARG_LEVELS] }, { "border.draw_masked.LEVELNR", &border.draw_masked[GFX_SPECIAL_ARG_LEVELNR] }, { "border.draw_masked.SCORES", &border.draw_masked[GFX_SPECIAL_ARG_SCORES] }, { "border.draw_masked.EDITOR", &border.draw_masked[GFX_SPECIAL_ARG_EDITOR] }, { "border.draw_masked.INFO", &border.draw_masked[GFX_SPECIAL_ARG_INFO] }, { "border.draw_masked.SETUP", &border.draw_masked[GFX_SPECIAL_ARG_SETUP] }, { "border.draw_masked.PLAYING", &border.draw_masked[GFX_SPECIAL_ARG_PLAYING] }, { "border.draw_masked.DOOR", &border.draw_masked[GFX_SPECIAL_ARG_DOOR] }, { "border.draw_masked_when_fading", &border.draw_masked_when_fading }, { "init.busy.x", &init.busy.x }, { "init.busy.y", &init.busy.y }, { "init.busy.align", &init.busy.align }, { "init.busy.valign", &init.busy.valign }, { "menu.enter_menu.fade_mode", &menu.enter_menu.fade_mode }, { "menu.enter_menu.fade_delay", &menu.enter_menu.fade_delay }, { "menu.enter_menu.post_delay", &menu.enter_menu.post_delay }, { "menu.leave_menu.fade_mode", &menu.leave_menu.fade_mode }, { "menu.leave_menu.fade_delay", &menu.leave_menu.fade_delay }, { "menu.leave_menu.post_delay", &menu.leave_menu.post_delay }, { "menu.enter_screen.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT].fade_mode }, { "menu.enter_screen.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT].fade_delay }, { "menu.enter_screen.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT].post_delay }, { "menu.leave_screen.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT].fade_mode }, { "menu.leave_screen.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT].fade_delay }, { "menu.leave_screen.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT].post_delay }, { "menu.next_screen.fade_mode", &menu.next_screen[GFX_SPECIAL_ARG_DEFAULT].fade_mode }, { "menu.next_screen.fade_delay", &menu.next_screen[GFX_SPECIAL_ARG_DEFAULT].fade_delay }, { "menu.next_screen.post_delay", &menu.next_screen[GFX_SPECIAL_ARG_DEFAULT].post_delay }, { "menu.enter_screen.TITLE.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_TITLE].fade_mode }, { "menu.enter_screen.TITLE.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_TITLE].fade_delay }, { "menu.enter_screen.TITLE.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_TITLE].post_delay }, { "menu.enter_screen.TITLE.auto_delay", &menu.enter_screen[GFX_SPECIAL_ARG_TITLE].auto_delay }, { "menu.enter_screen.SCORES.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_SCORES].fade_mode }, { "menu.enter_screen.SCORES.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_SCORES].fade_delay }, { "menu.enter_screen.SCORES.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_SCORES].post_delay }, { "menu.enter_screen.EDITOR.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_EDITOR].fade_mode }, { "menu.enter_screen.EDITOR.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_EDITOR].fade_delay }, { "menu.enter_screen.EDITOR.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_EDITOR].post_delay }, { "menu.enter_screen.INFO.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_INFO].fade_mode }, { "menu.enter_screen.INFO.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_INFO].fade_delay }, { "menu.enter_screen.INFO.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_INFO].post_delay }, { "menu.enter_screen.PLAYING.fade_mode", &menu.enter_screen[GFX_SPECIAL_ARG_PLAYING].fade_mode }, { "menu.enter_screen.PLAYING.fade_delay", &menu.enter_screen[GFX_SPECIAL_ARG_PLAYING].fade_delay }, { "menu.enter_screen.PLAYING.post_delay", &menu.enter_screen[GFX_SPECIAL_ARG_PLAYING].post_delay }, { "menu.leave_screen.TITLE.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_TITLE].fade_mode }, { "menu.leave_screen.TITLE.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_TITLE].fade_delay }, { "menu.leave_screen.TITLE.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_TITLE].post_delay }, { "menu.leave_screen.TITLE.auto_delay", &menu.leave_screen[GFX_SPECIAL_ARG_TITLE].auto_delay }, { "menu.leave_screen.SCORES.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_SCORES].fade_mode }, { "menu.leave_screen.SCORES.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_SCORES].fade_delay }, { "menu.leave_screen.SCORES.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_SCORES].post_delay }, { "menu.leave_screen.EDITOR.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_EDITOR].fade_mode }, { "menu.leave_screen.EDITOR.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_EDITOR].fade_delay }, { "menu.leave_screen.EDITOR.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_EDITOR].post_delay }, { "menu.leave_screen.INFO.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_INFO].fade_mode }, { "menu.leave_screen.INFO.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_INFO].fade_delay }, { "menu.leave_screen.INFO.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_INFO].post_delay }, { "menu.leave_screen.PLAYING.fade_mode", &menu.leave_screen[GFX_SPECIAL_ARG_PLAYING].fade_mode }, { "menu.leave_screen.PLAYING.fade_delay", &menu.leave_screen[GFX_SPECIAL_ARG_PLAYING].fade_delay }, { "menu.leave_screen.PLAYING.post_delay", &menu.leave_screen[GFX_SPECIAL_ARG_PLAYING].post_delay }, { "menu.next_screen.TITLE.fade_mode", &menu.next_screen[GFX_SPECIAL_ARG_TITLE].fade_mode }, { "menu.next_screen.TITLE.fade_delay", &menu.next_screen[GFX_SPECIAL_ARG_TITLE].fade_delay }, { "menu.next_screen.TITLE.post_delay", &menu.next_screen[GFX_SPECIAL_ARG_TITLE].post_delay }, { "menu.next_screen.TITLE.auto_delay", &menu.next_screen[GFX_SPECIAL_ARG_TITLE].auto_delay }, { "menu.next_screen.INFO.fade_mode", &menu.next_screen[GFX_SPECIAL_ARG_INFO].fade_mode }, { "menu.next_screen.INFO.fade_delay", &menu.next_screen[GFX_SPECIAL_ARG_INFO].fade_delay }, { "menu.next_screen.INFO.post_delay", &menu.next_screen[GFX_SPECIAL_ARG_INFO].post_delay }, { "menu.draw_xoffset", &menu.draw_xoffset[GFX_SPECIAL_ARG_DEFAULT] }, { "menu.draw_yoffset", &menu.draw_yoffset[GFX_SPECIAL_ARG_DEFAULT] }, { "menu.draw_xoffset.MAIN", &menu.draw_xoffset[GFX_SPECIAL_ARG_MAIN] }, { "menu.draw_yoffset.MAIN", &menu.draw_yoffset[GFX_SPECIAL_ARG_MAIN] }, { "menu.draw_xoffset.LEVELS", &menu.draw_xoffset[GFX_SPECIAL_ARG_LEVELS] }, { "menu.draw_yoffset.LEVELS", &menu.draw_yoffset[GFX_SPECIAL_ARG_LEVELS] }, { "menu.draw_xoffset.LEVELNR", &menu.draw_xoffset[GFX_SPECIAL_ARG_LEVELNR] }, { "menu.draw_yoffset.LEVELNR", &menu.draw_yoffset[GFX_SPECIAL_ARG_LEVELNR] }, { "menu.draw_xoffset.SCORES", &menu.draw_xoffset[GFX_SPECIAL_ARG_SCORES] }, { "menu.draw_yoffset.SCORES", &menu.draw_yoffset[GFX_SPECIAL_ARG_SCORES] }, { "menu.draw_xoffset.EDITOR", &menu.draw_xoffset[GFX_SPECIAL_ARG_EDITOR] }, { "menu.draw_yoffset.EDITOR", &menu.draw_yoffset[GFX_SPECIAL_ARG_EDITOR] }, { "menu.draw_xoffset.INFO", &menu.draw_xoffset[GFX_SPECIAL_ARG_INFO] }, { "menu.draw_yoffset.INFO", &menu.draw_yoffset[GFX_SPECIAL_ARG_INFO] }, { "menu.draw_xoffset.INFO[TITLE]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.draw_yoffset.INFO[TITLE]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.draw_xoffset.INFO[ELEMENTS]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.draw_yoffset.INFO[ELEMENTS]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.draw_xoffset.INFO[MUSIC]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.draw_yoffset.INFO[MUSIC]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.draw_xoffset.INFO[CREDITS]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.draw_yoffset.INFO[CREDITS]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.draw_xoffset.INFO[PROGRAM]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.draw_yoffset.INFO[PROGRAM]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.draw_xoffset.INFO[VERSION]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.draw_yoffset.INFO[VERSION]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.draw_xoffset.INFO[LEVELSET]", &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.draw_yoffset.INFO[LEVELSET]", &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.draw_xoffset.SETUP", &menu.draw_xoffset[GFX_SPECIAL_ARG_SETUP] }, { "menu.draw_yoffset.SETUP", &menu.draw_yoffset[GFX_SPECIAL_ARG_SETUP] }, { "menu.draw_xoffset.SETUP[GAME]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_GAME] }, { "menu.draw_yoffset.SETUP[GAME]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_GAME] }, { "menu.draw_xoffset.SETUP[EDITOR]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_EDITOR] }, { "menu.draw_yoffset.SETUP[EDITOR]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_EDITOR] }, { "menu.draw_xoffset.SETUP[GRAPHICS]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_GRAPHICS] }, { "menu.draw_yoffset.SETUP[GRAPHICS]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_GRAPHICS] }, { "menu.draw_xoffset.SETUP[SOUND]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SOUND] }, { "menu.draw_yoffset.SETUP[SOUND]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SOUND] }, { "menu.draw_xoffset.SETUP[ARTWORK]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_ARTWORK] }, { "menu.draw_yoffset.SETUP[ARTWORK]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_ARTWORK] }, { "menu.draw_xoffset.SETUP[INPUT]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.draw_yoffset.SETUP[INPUT]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.draw_xoffset.SETUP[TOUCH]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_TOUCH] }, { "menu.draw_yoffset.SETUP[TOUCH]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_TOUCH] }, { "menu.draw_xoffset.SETUP[SHORTCUTS]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS] }, { "menu.draw_yoffset.SETUP[SHORTCUTS]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_1]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_1] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_1]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_1] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_2]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_2] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_2]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_2] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_3]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_3]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_4]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_4]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4] }, { "menu.draw_xoffset.SETUP[SHORTCUTS_5]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_5] }, { "menu.draw_yoffset.SETUP[SHORTCUTS_5]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_SHORTCUTS_5] }, { "menu.draw_xoffset.SETUP[CHOOSE_ARTWORK]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK] }, { "menu.draw_yoffset.SETUP[CHOOSE_ARTWORK]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK] }, { "menu.draw_xoffset.SETUP[CHOOSE_OTHER]", &menu.draw_xoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER] }, { "menu.draw_yoffset.SETUP[CHOOSE_OTHER]", &menu.draw_yoffset_setup[GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER] }, { "menu.scrollbar_xoffset", &menu.scrollbar_xoffset }, { "menu.list_size", &menu.list_size[GFX_SPECIAL_ARG_DEFAULT] }, { "menu.list_size.LEVELS", &menu.list_size[GFX_SPECIAL_ARG_LEVELS] }, { "menu.list_size.LEVELNR", &menu.list_size[GFX_SPECIAL_ARG_LEVELNR] }, { "menu.list_size.SCORES", &menu.list_size[GFX_SPECIAL_ARG_SCORES] }, { "menu.list_size.INFO", &menu.list_size[GFX_SPECIAL_ARG_INFO] }, { "menu.list_size.INFO[ELEMENTS]", &menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.list_size.SETUP", &menu.list_size[GFX_SPECIAL_ARG_SETUP] }, { "menu.left_spacing.INFO", &menu.left_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.left_spacing.INFO[TITLE]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.left_spacing.INFO[ELEMENTS]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.left_spacing.INFO[MUSIC]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.left_spacing.INFO[CREDITS]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.left_spacing.INFO[PROGRAM]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.left_spacing.INFO[VERSION]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.left_spacing.INFO[LEVELSET]", &menu.left_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.left_spacing.SETUP[INPUT]", &menu.left_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.right_spacing.INFO", &menu.right_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.right_spacing.INFO[TITLE]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.right_spacing.INFO[ELEMENTS]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.right_spacing.INFO[MUSIC]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.right_spacing.INFO[CREDITS]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.right_spacing.INFO[PROGRAM]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.right_spacing.INFO[VERSION]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.right_spacing.INFO[LEVELSET]", &menu.right_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.right_spacing.SETUP[INPUT]", &menu.right_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.top_spacing.INFO", &menu.top_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.top_spacing.INFO[TITLE]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.top_spacing.INFO[ELEMENTS]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.top_spacing.INFO[MUSIC]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.top_spacing.INFO[CREDITS]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.top_spacing.INFO[PROGRAM]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.top_spacing.INFO[VERSION]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.top_spacing.INFO[LEVELSET]", &menu.top_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.top_spacing.SETUP[INPUT]", &menu.top_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.bottom_spacing.INFO", &menu.bottom_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.bottom_spacing.INFO[TITLE]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.bottom_spacing.INFO[ELEMENTS]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.bottom_spacing.INFO[MUSIC]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.bottom_spacing.INFO[CREDITS]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.bottom_spacing.INFO[PROGRAM]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.bottom_spacing.INFO[VERSION]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.bottom_spacing.INFO[LEVELSET]", &menu.bottom_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.bottom_spacing.SETUP[INPUT]", &menu.bottom_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.paragraph_spacing.INFO", &menu.paragraph_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.paragraph_spacing.INFO[TITLE]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.paragraph_spacing.INFO[ELEMENTS]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.paragraph_spacing.INFO[MUSIC]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.paragraph_spacing.INFO[CREDITS]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.paragraph_spacing.INFO[PROGRAM]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.paragraph_spacing.INFO[VERSION]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.paragraph_spacing.INFO[LEVELSET]", &menu.paragraph_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.paragraph_spacing.SETUP[INPUT]", &menu.paragraph_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.headline1_spacing.INFO", &menu.headline1_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.headline1_spacing.INFO[TITLE]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.headline1_spacing.INFO[ELEMENTS]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.headline1_spacing.INFO[MUSIC]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.headline1_spacing.INFO[CREDITS]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.headline1_spacing.INFO[PROGRAM]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.headline1_spacing.INFO[VERSION]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.headline1_spacing.INFO[LEVELSET]", &menu.headline1_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.headline1_spacing.SETUP[INPUT]", &menu.headline1_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.headline2_spacing.INFO", &menu.headline2_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.headline2_spacing.INFO[TITLE]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.headline2_spacing.INFO[ELEMENTS]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.headline2_spacing.INFO[MUSIC]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.headline2_spacing.INFO[CREDITS]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.headline2_spacing.INFO[PROGRAM]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.headline2_spacing.INFO[VERSION]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.headline2_spacing.INFO[LEVELSET]", &menu.headline2_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.headline2_spacing.SETUP[INPUT]", &menu.headline2_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.line_spacing.INFO", &menu.line_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.line_spacing.INFO[TITLE]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.line_spacing.INFO[ELEMENTS]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.line_spacing.INFO[MUSIC]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.line_spacing.INFO[CREDITS]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.line_spacing.INFO[PROGRAM]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.line_spacing.INFO[VERSION]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.line_spacing.INFO[LEVELSET]", &menu.line_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.line_spacing.SETUP[INPUT]", &menu.line_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "menu.extra_spacing.INFO", &menu.extra_spacing[GFX_SPECIAL_ARG_INFO] }, { "menu.extra_spacing.INFO[TITLE]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_TITLE] }, { "menu.extra_spacing.INFO[ELEMENTS]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] }, { "menu.extra_spacing.INFO[MUSIC]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_MUSIC] }, { "menu.extra_spacing.INFO[CREDITS]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_CREDITS] }, { "menu.extra_spacing.INFO[PROGRAM]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_PROGRAM] }, { "menu.extra_spacing.INFO[VERSION]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_VERSION] }, { "menu.extra_spacing.INFO[LEVELSET]", &menu.extra_spacing_info[GFX_SPECIAL_ARG_INFO_LEVELSET] }, { "menu.extra_spacing.SETUP[INPUT]", &menu.extra_spacing_setup[GFX_SPECIAL_ARG_SETUP_INPUT] }, { "main.button.name.x", &menu.main.button.name.x }, { "main.button.name.y", &menu.main.button.name.y }, { "main.button.levels.x", &menu.main.button.levels.x }, { "main.button.levels.y", &menu.main.button.levels.y }, { "main.button.scores.x", &menu.main.button.scores.x }, { "main.button.scores.y", &menu.main.button.scores.y }, { "main.button.editor.x", &menu.main.button.editor.x }, { "main.button.editor.y", &menu.main.button.editor.y }, { "main.button.info.x", &menu.main.button.info.x }, { "main.button.info.y", &menu.main.button.info.y }, { "main.button.game.x", &menu.main.button.game.x }, { "main.button.game.y", &menu.main.button.game.y }, { "main.button.setup.x", &menu.main.button.setup.x }, { "main.button.setup.y", &menu.main.button.setup.y }, { "main.button.quit.x", &menu.main.button.quit.x }, { "main.button.quit.y", &menu.main.button.quit.y }, { "main.button.prev_level.x", &menu.main.button.prev_level.x }, { "main.button.prev_level.y", &menu.main.button.prev_level.y }, { "main.button.next_level.x", &menu.main.button.next_level.x }, { "main.button.next_level.y", &menu.main.button.next_level.y }, { "main.text.name.x", &menu.main.text.name.x }, { "main.text.name.y", &menu.main.text.name.y }, { "main.text.name.width", &menu.main.text.name.width }, { "main.text.name.height", &menu.main.text.name.height }, { "main.text.name.align", &menu.main.text.name.align }, { "main.text.name.valign", &menu.main.text.name.valign }, { "main.text.name.font", &menu.main.text.name.font }, { "main.text.levels.x", &menu.main.text.levels.x }, { "main.text.levels.y", &menu.main.text.levels.y }, { "main.text.levels.width", &menu.main.text.levels.width }, { "main.text.levels.height", &menu.main.text.levels.height }, { "main.text.levels.align", &menu.main.text.levels.align }, { "main.text.levels.valign", &menu.main.text.levels.valign }, { "main.text.levels.font", &menu.main.text.levels.font }, { "main.text.scores.x", &menu.main.text.scores.x }, { "main.text.scores.y", &menu.main.text.scores.y }, { "main.text.scores.width", &menu.main.text.scores.width }, { "main.text.scores.height", &menu.main.text.scores.height }, { "main.text.scores.align", &menu.main.text.scores.align }, { "main.text.scores.valign", &menu.main.text.scores.valign }, { "main.text.scores.font", &menu.main.text.scores.font }, { "main.text.editor.x", &menu.main.text.editor.x }, { "main.text.editor.y", &menu.main.text.editor.y }, { "main.text.editor.width", &menu.main.text.editor.width }, { "main.text.editor.height", &menu.main.text.editor.height }, { "main.text.editor.align", &menu.main.text.editor.align }, { "main.text.editor.valign", &menu.main.text.editor.valign }, { "main.text.editor.font", &menu.main.text.editor.font }, { "main.text.info.x", &menu.main.text.info.x }, { "main.text.info.y", &menu.main.text.info.y }, { "main.text.info.width", &menu.main.text.info.width }, { "main.text.info.height", &menu.main.text.info.height }, { "main.text.info.align", &menu.main.text.info.align }, { "main.text.info.valign", &menu.main.text.info.valign }, { "main.text.info.font", &menu.main.text.info.font }, { "main.text.game.x", &menu.main.text.game.x }, { "main.text.game.y", &menu.main.text.game.y }, { "main.text.game.width", &menu.main.text.game.width }, { "main.text.game.height", &menu.main.text.game.height }, { "main.text.game.align", &menu.main.text.game.align }, { "main.text.game.valign", &menu.main.text.game.valign }, { "main.text.game.font", &menu.main.text.game.font }, { "main.text.setup.x", &menu.main.text.setup.x }, { "main.text.setup.y", &menu.main.text.setup.y }, { "main.text.setup.width", &menu.main.text.setup.width }, { "main.text.setup.height", &menu.main.text.setup.height }, { "main.text.setup.align", &menu.main.text.setup.align }, { "main.text.setup.valign", &menu.main.text.setup.valign }, { "main.text.setup.font", &menu.main.text.setup.font }, { "main.text.quit.x", &menu.main.text.quit.x }, { "main.text.quit.y", &menu.main.text.quit.y }, { "main.text.quit.width", &menu.main.text.quit.width }, { "main.text.quit.height", &menu.main.text.quit.height }, { "main.text.quit.align", &menu.main.text.quit.align }, { "main.text.quit.valign", &menu.main.text.quit.valign }, { "main.text.quit.font", &menu.main.text.quit.font }, { "main.text.first_level.x", &menu.main.text.first_level.x }, { "main.text.first_level.y", &menu.main.text.first_level.y }, { "main.text.first_level.align", &menu.main.text.first_level.align }, { "main.text.first_level.valign", &menu.main.text.first_level.valign }, { "main.text.first_level.digits", &menu.main.text.first_level.size }, { "main.text.first_level.font", &menu.main.text.first_level.font }, { "main.text.last_level.x", &menu.main.text.last_level.x }, { "main.text.last_level.y", &menu.main.text.last_level.y }, { "main.text.last_level.align", &menu.main.text.last_level.align }, { "main.text.last_level.valign", &menu.main.text.last_level.valign }, { "main.text.last_level.digits", &menu.main.text.last_level.size }, { "main.text.last_level.font", &menu.main.text.last_level.font }, { "main.text.level_number.x", &menu.main.text.level_number.x }, { "main.text.level_number.y", &menu.main.text.level_number.y }, { "main.text.level_number.align", &menu.main.text.level_number.align }, { "main.text.level_number.valign", &menu.main.text.level_number.valign }, { "main.text.level_number.digits", &menu.main.text.level_number.size }, { "main.text.level_number.font", &menu.main.text.level_number.font }, { "main.text.level_info_1.x", &menu.main.text.level_info_1.x }, { "main.text.level_info_1.y", &menu.main.text.level_info_1.y }, { "main.text.level_info_1.align", &menu.main.text.level_info_1.align }, { "main.text.level_info_1.valign", &menu.main.text.level_info_1.valign }, { "main.text.level_info_1.chars", &menu.main.text.level_info_1.size }, { "main.text.level_info_1.font", &menu.main.text.level_info_1.font }, { "main.text.level_info_2.x", &menu.main.text.level_info_2.x }, { "main.text.level_info_2.y", &menu.main.text.level_info_2.y }, { "main.text.level_info_2.align", &menu.main.text.level_info_2.align }, { "main.text.level_info_2.valign", &menu.main.text.level_info_2.valign }, { "main.text.level_info_2.chars", &menu.main.text.level_info_2.size }, { "main.text.level_info_2.font", &menu.main.text.level_info_2.font }, { "main.text.level_info_2.font_header", &menu.main.text.level_info_2.font_alt }, { "main.text.level_name.x", &menu.main.text.level_name.x }, { "main.text.level_name.y", &menu.main.text.level_name.y }, { "main.text.level_name.align", &menu.main.text.level_name.align }, { "main.text.level_name.valign", &menu.main.text.level_name.valign }, { "main.text.level_name.chars", &menu.main.text.level_name.size }, { "main.text.level_name.font", &menu.main.text.level_name.font }, { "main.text.level_author.x", &menu.main.text.level_author.x }, { "main.text.level_author.y", &menu.main.text.level_author.y }, { "main.text.level_author.align", &menu.main.text.level_author.align }, { "main.text.level_author.valign", &menu.main.text.level_author.valign }, { "main.text.level_author.chars", &menu.main.text.level_author.size }, { "main.text.level_author.font", &menu.main.text.level_author.font }, { "main.text.level_year.x", &menu.main.text.level_year.x }, { "main.text.level_year.y", &menu.main.text.level_year.y }, { "main.text.level_year.align", &menu.main.text.level_year.align }, { "main.text.level_year.valign", &menu.main.text.level_year.valign }, { "main.text.level_year.digits", &menu.main.text.level_year.size }, { "main.text.level_year.font", &menu.main.text.level_year.font }, { "main.text.level_imported_from.x", &menu.main.text.level_imported_from.x }, { "main.text.level_imported_from.y", &menu.main.text.level_imported_from.y }, { "main.text.level_imported_from.align", &menu.main.text.level_imported_from.align }, { "main.text.level_imported_from.valign", &menu.main.text.level_imported_from.valign }, { "main.text.level_imported_from.chars", &menu.main.text.level_imported_from.size }, { "main.text.level_imported_from.font", &menu.main.text.level_imported_from.font }, { "main.text.level_imported_by.x", &menu.main.text.level_imported_by.x }, { "main.text.level_imported_by.y", &menu.main.text.level_imported_by.y }, { "main.text.level_imported_by.align", &menu.main.text.level_imported_by.align }, { "main.text.level_imported_by.valign", &menu.main.text.level_imported_by.valign }, { "main.text.level_imported_by.chars", &menu.main.text.level_imported_by.size }, { "main.text.level_imported_by.font", &menu.main.text.level_imported_by.font }, { "main.text.level_tested_by.x", &menu.main.text.level_tested_by.x }, { "main.text.level_tested_by.y", &menu.main.text.level_tested_by.y }, { "main.text.level_tested_by.align", &menu.main.text.level_tested_by.align }, { "main.text.level_tested_by.valign", &menu.main.text.level_tested_by.valign }, { "main.text.level_tested_by.chars", &menu.main.text.level_tested_by.size }, { "main.text.level_tested_by.font", &menu.main.text.level_tested_by.font }, { "main.text.title_1.x", &menu.main.text.title_1.x }, { "main.text.title_1.y", &menu.main.text.title_1.y }, { "main.text.title_1.align", &menu.main.text.title_1.align }, { "main.text.title_1.valign", &menu.main.text.title_1.valign }, { "main.text.title_1.font", &menu.main.text.title_1.font }, { "main.text.title_2.x", &menu.main.text.title_2.x }, { "main.text.title_2.y", &menu.main.text.title_2.y }, { "main.text.title_2.align", &menu.main.text.title_2.align }, { "main.text.title_2.valign", &menu.main.text.title_2.valign }, { "main.text.title_2.font", &menu.main.text.title_2.font }, { "main.text.title_3.x", &menu.main.text.title_3.x }, { "main.text.title_3.y", &menu.main.text.title_3.y }, { "main.text.title_3.align", &menu.main.text.title_3.align }, { "main.text.title_3.valign", &menu.main.text.title_3.valign }, { "main.text.title_3.font", &menu.main.text.title_3.font }, { "main.input.name.x", &menu.main.input.name.x }, { "main.input.name.y", &menu.main.input.name.y }, { "main.input.name.align", &menu.main.input.name.align }, { "main.input.name.valign", &menu.main.input.name.valign }, { "main.input.name.font", &menu.main.input.name.font }, { "preview.x", &preview.x }, { "preview.y", &preview.y }, { "preview.align", &preview.align }, { "preview.valign", &preview.valign }, { "preview.xsize", &preview.xsize }, { "preview.ysize", &preview.ysize }, { "preview.xoffset", &preview.xoffset }, { "preview.yoffset", &preview.yoffset }, { "preview.tile_size", &preview.tile_size }, { "preview.step_offset", &preview.step_offset }, { "preview.step_delay", &preview.step_delay }, { "preview.anim_mode", &preview.anim_mode }, { "door_1.part_1.x", &door_1.part_1.x }, { "door_1.part_1.y", &door_1.part_1.y }, { "door_1.part_1.step_xoffset", &door_1.part_1.step_xoffset }, { "door_1.part_1.step_yoffset", &door_1.part_1.step_yoffset }, { "door_1.part_1.step_delay", &door_1.part_1.step_delay }, { "door_1.part_1.start_step", &door_1.part_1.start_step }, { "door_1.part_1.start_step_opening", &door_1.part_1.start_step_opening }, { "door_1.part_1.start_step_closing", &door_1.part_1.start_step_closing }, { "door_1.part_1.draw_masked", &door_1.part_1.draw_masked }, { "door_1.part_1.draw_order", &door_1.part_1.sort_priority }, { "door_1.part_2.x", &door_1.part_2.x }, { "door_1.part_2.y", &door_1.part_2.y }, { "door_1.part_2.step_xoffset", &door_1.part_2.step_xoffset }, { "door_1.part_2.step_yoffset", &door_1.part_2.step_yoffset }, { "door_1.part_2.step_delay", &door_1.part_2.step_delay }, { "door_1.part_2.start_step", &door_1.part_2.start_step }, { "door_1.part_2.start_step_opening", &door_1.part_2.start_step_opening }, { "door_1.part_2.start_step_closing", &door_1.part_2.start_step_closing }, { "door_1.part_2.draw_masked", &door_1.part_2.draw_masked }, { "door_1.part_2.draw_order", &door_1.part_2.sort_priority }, { "door_1.part_3.x", &door_1.part_3.x }, { "door_1.part_3.y", &door_1.part_3.y }, { "door_1.part_3.step_xoffset", &door_1.part_3.step_xoffset }, { "door_1.part_3.step_yoffset", &door_1.part_3.step_yoffset }, { "door_1.part_3.step_delay", &door_1.part_3.step_delay }, { "door_1.part_3.start_step", &door_1.part_3.start_step }, { "door_1.part_3.start_step_opening", &door_1.part_3.start_step_opening }, { "door_1.part_3.start_step_closing", &door_1.part_3.start_step_closing }, { "door_1.part_3.draw_masked", &door_1.part_3.draw_masked }, { "door_1.part_3.draw_order", &door_1.part_3.sort_priority }, { "door_1.part_4.x", &door_1.part_4.x }, { "door_1.part_4.y", &door_1.part_4.y }, { "door_1.part_4.step_xoffset", &door_1.part_4.step_xoffset }, { "door_1.part_4.step_yoffset", &door_1.part_4.step_yoffset }, { "door_1.part_4.step_delay", &door_1.part_4.step_delay }, { "door_1.part_4.start_step", &door_1.part_4.start_step }, { "door_1.part_4.start_step_opening", &door_1.part_4.start_step_opening }, { "door_1.part_4.start_step_closing", &door_1.part_4.start_step_closing }, { "door_1.part_4.draw_masked", &door_1.part_4.draw_masked }, { "door_1.part_4.draw_order", &door_1.part_4.sort_priority }, { "door_1.part_5.x", &door_1.part_5.x }, { "door_1.part_5.y", &door_1.part_5.y }, { "door_1.part_5.step_xoffset", &door_1.part_5.step_xoffset }, { "door_1.part_5.step_yoffset", &door_1.part_5.step_yoffset }, { "door_1.part_5.step_delay", &door_1.part_5.step_delay }, { "door_1.part_5.start_step", &door_1.part_5.start_step }, { "door_1.part_5.start_step_opening", &door_1.part_5.start_step_opening }, { "door_1.part_5.start_step_closing", &door_1.part_5.start_step_closing }, { "door_1.part_5.draw_masked", &door_1.part_5.draw_masked }, { "door_1.part_5.draw_order", &door_1.part_5.sort_priority }, { "door_1.part_6.x", &door_1.part_6.x }, { "door_1.part_6.y", &door_1.part_6.y }, { "door_1.part_6.step_xoffset", &door_1.part_6.step_xoffset }, { "door_1.part_6.step_yoffset", &door_1.part_6.step_yoffset }, { "door_1.part_6.step_delay", &door_1.part_6.step_delay }, { "door_1.part_6.start_step", &door_1.part_6.start_step }, { "door_1.part_6.start_step_opening", &door_1.part_6.start_step_opening }, { "door_1.part_6.start_step_closing", &door_1.part_6.start_step_closing }, { "door_1.part_6.draw_masked", &door_1.part_6.draw_masked }, { "door_1.part_6.draw_order", &door_1.part_6.sort_priority }, { "door_1.part_7.x", &door_1.part_7.x }, { "door_1.part_7.y", &door_1.part_7.y }, { "door_1.part_7.step_xoffset", &door_1.part_7.step_xoffset }, { "door_1.part_7.step_yoffset", &door_1.part_7.step_yoffset }, { "door_1.part_7.step_delay", &door_1.part_7.step_delay }, { "door_1.part_7.start_step", &door_1.part_7.start_step }, { "door_1.part_7.start_step_opening", &door_1.part_7.start_step_opening }, { "door_1.part_7.start_step_closing", &door_1.part_7.start_step_closing }, { "door_1.part_7.draw_masked", &door_1.part_7.draw_masked }, { "door_1.part_7.draw_order", &door_1.part_7.sort_priority }, { "door_1.part_8.x", &door_1.part_8.x }, { "door_1.part_8.y", &door_1.part_8.y }, { "door_1.part_8.step_xoffset", &door_1.part_8.step_xoffset }, { "door_1.part_8.step_yoffset", &door_1.part_8.step_yoffset }, { "door_1.part_8.step_delay", &door_1.part_8.step_delay }, { "door_1.part_8.start_step", &door_1.part_8.start_step }, { "door_1.part_8.start_step_opening", &door_1.part_8.start_step_opening }, { "door_1.part_8.start_step_closing", &door_1.part_8.start_step_closing }, { "door_1.part_8.draw_masked", &door_1.part_8.draw_masked }, { "door_1.part_8.draw_order", &door_1.part_8.sort_priority }, { "door_2.part_1.x", &door_2.part_1.x }, { "door_2.part_1.y", &door_2.part_1.y }, { "door_2.part_1.step_xoffset", &door_2.part_1.step_xoffset }, { "door_2.part_1.step_yoffset", &door_2.part_1.step_yoffset }, { "door_2.part_1.step_delay", &door_2.part_1.step_delay }, { "door_2.part_1.start_step", &door_2.part_1.start_step }, { "door_2.part_1.start_step_opening", &door_2.part_1.start_step_opening }, { "door_2.part_1.start_step_closing", &door_2.part_1.start_step_closing }, { "door_2.part_1.draw_masked", &door_2.part_1.draw_masked }, { "door_2.part_1.draw_order", &door_2.part_1.sort_priority }, { "door_2.part_2.x", &door_2.part_2.x }, { "door_2.part_2.y", &door_2.part_2.y }, { "door_2.part_2.step_xoffset", &door_2.part_2.step_xoffset }, { "door_2.part_2.step_yoffset", &door_2.part_2.step_yoffset }, { "door_2.part_2.step_delay", &door_2.part_2.step_delay }, { "door_2.part_2.start_step", &door_2.part_2.start_step }, { "door_2.part_2.start_step_opening", &door_2.part_2.start_step_opening }, { "door_2.part_2.start_step_closing", &door_2.part_2.start_step_closing }, { "door_2.part_2.draw_masked", &door_2.part_2.draw_masked }, { "door_2.part_2.draw_order", &door_2.part_2.sort_priority }, { "door_2.part_3.x", &door_2.part_3.x }, { "door_2.part_3.y", &door_2.part_3.y }, { "door_2.part_3.step_xoffset", &door_2.part_3.step_xoffset }, { "door_2.part_3.step_yoffset", &door_2.part_3.step_yoffset }, { "door_2.part_3.step_delay", &door_2.part_3.step_delay }, { "door_2.part_3.start_step", &door_2.part_3.start_step }, { "door_2.part_3.start_step_opening", &door_2.part_3.start_step_opening }, { "door_2.part_3.start_step_closing", &door_2.part_3.start_step_closing }, { "door_2.part_3.draw_masked", &door_2.part_3.draw_masked }, { "door_2.part_3.draw_order", &door_2.part_3.sort_priority }, { "door_2.part_4.x", &door_2.part_4.x }, { "door_2.part_4.y", &door_2.part_4.y }, { "door_2.part_4.step_xoffset", &door_2.part_4.step_xoffset }, { "door_2.part_4.step_yoffset", &door_2.part_4.step_yoffset }, { "door_2.part_4.step_delay", &door_2.part_4.step_delay }, { "door_2.part_4.start_step", &door_2.part_4.start_step }, { "door_2.part_4.start_step_opening", &door_2.part_4.start_step_opening }, { "door_2.part_4.start_step_closing", &door_2.part_4.start_step_closing }, { "door_2.part_4.draw_masked", &door_2.part_4.draw_masked }, { "door_2.part_4.draw_order", &door_2.part_4.sort_priority }, { "door_2.part_5.x", &door_2.part_5.x }, { "door_2.part_5.y", &door_2.part_5.y }, { "door_2.part_5.step_xoffset", &door_2.part_5.step_xoffset }, { "door_2.part_5.step_yoffset", &door_2.part_5.step_yoffset }, { "door_2.part_5.step_delay", &door_2.part_5.step_delay }, { "door_2.part_5.start_step", &door_2.part_5.start_step }, { "door_2.part_5.start_step_opening", &door_2.part_5.start_step_opening }, { "door_2.part_5.start_step_closing", &door_2.part_5.start_step_closing }, { "door_2.part_5.draw_masked", &door_2.part_5.draw_masked }, { "door_2.part_5.draw_order", &door_2.part_5.sort_priority }, { "door_2.part_6.x", &door_2.part_6.x }, { "door_2.part_6.y", &door_2.part_6.y }, { "door_2.part_6.step_xoffset", &door_2.part_6.step_xoffset }, { "door_2.part_6.step_yoffset", &door_2.part_6.step_yoffset }, { "door_2.part_6.step_delay", &door_2.part_6.step_delay }, { "door_2.part_6.start_step", &door_2.part_6.start_step }, { "door_2.part_6.start_step_opening", &door_2.part_6.start_step_opening }, { "door_2.part_6.start_step_closing", &door_2.part_6.start_step_closing }, { "door_2.part_6.draw_masked", &door_2.part_6.draw_masked }, { "door_2.part_6.draw_order", &door_2.part_6.sort_priority }, { "door_2.part_7.x", &door_2.part_7.x }, { "door_2.part_7.y", &door_2.part_7.y }, { "door_2.part_7.step_xoffset", &door_2.part_7.step_xoffset }, { "door_2.part_7.step_yoffset", &door_2.part_7.step_yoffset }, { "door_2.part_7.step_delay", &door_2.part_7.step_delay }, { "door_2.part_7.start_step", &door_2.part_7.start_step }, { "door_2.part_7.start_step_opening", &door_2.part_7.start_step_opening }, { "door_2.part_7.start_step_closing", &door_2.part_7.start_step_closing }, { "door_2.part_7.draw_masked", &door_2.part_7.draw_masked }, { "door_2.part_7.draw_order", &door_2.part_7.sort_priority }, { "door_2.part_8.x", &door_2.part_8.x }, { "door_2.part_8.y", &door_2.part_8.y }, { "door_2.part_8.step_xoffset", &door_2.part_8.step_xoffset }, { "door_2.part_8.step_yoffset", &door_2.part_8.step_yoffset }, { "door_2.part_8.step_delay", &door_2.part_8.step_delay }, { "door_2.part_8.start_step", &door_2.part_8.start_step }, { "door_2.part_8.start_step_opening", &door_2.part_8.start_step_opening }, { "door_2.part_8.start_step_closing", &door_2.part_8.start_step_closing }, { "door_2.part_8.draw_masked", &door_2.part_8.draw_masked }, { "door_2.part_8.draw_order", &door_2.part_8.sort_priority }, { "door_1.panel.x", &door_1.panel.x }, { "door_1.panel.y", &door_1.panel.y }, { "door_1.panel.step_xoffset", &door_1.panel.step_xoffset }, { "door_1.panel.step_yoffset", &door_1.panel.step_yoffset }, { "door_1.panel.step_delay", &door_1.panel.step_delay }, { "door_1.panel.start_step", &door_1.panel.start_step }, { "door_1.panel.start_step_opening", &door_1.panel.start_step_opening }, { "door_1.panel.start_step_closing", &door_1.panel.start_step_closing }, { "door_1.panel.draw_masked", &door_1.panel.draw_masked }, { "door_1.panel.draw_order", &door_1.panel.sort_priority }, { "door_2.panel.x", &door_2.panel.x }, { "door_2.panel.y", &door_2.panel.y }, { "door_2.panel.step_xoffset", &door_2.panel.step_xoffset }, { "door_2.panel.step_yoffset", &door_2.panel.step_yoffset }, { "door_2.panel.step_delay", &door_2.panel.step_delay }, { "door_2.panel.start_step", &door_2.panel.start_step }, { "door_2.panel.start_step_opening", &door_2.panel.start_step_opening }, { "door_2.panel.start_step_closing", &door_2.panel.start_step_closing }, { "door_2.panel.draw_masked", &door_2.panel.draw_masked }, { "door_2.panel.draw_order", &door_2.panel.sort_priority }, { "door_1.width", &door_1.width }, { "door_1.height", &door_1.height }, { "door_1.step_offset", &door_1.step_offset }, { "door_1.step_delay", &door_1.step_delay }, { "door_1.post_delay", &door_1.post_delay }, { "door_1.anim_mode", &door_1.anim_mode }, { "door_2.width", &door_2.width }, { "door_2.height", &door_2.height }, { "door_2.step_offset", &door_2.step_offset }, { "door_2.step_delay", &door_2.step_delay }, { "door_2.post_delay", &door_2.post_delay }, { "door_2.anim_mode", &door_2.anim_mode }, { "game.panel.level_number.x", &game.panel.level_number.x }, { "game.panel.level_number.y", &game.panel.level_number.y }, { "game.panel.level_number.align", &game.panel.level_number.align }, { "game.panel.level_number.valign", &game.panel.level_number.valign }, { "game.panel.level_number.digits", &game.panel.level_number.size }, { "game.panel.level_number.font", &game.panel.level_number.font }, { "game.panel.level_number.font_narrow", &game.panel.level_number.font_alt }, { "game.panel.level_number.draw_masked", &game.panel.level_number.draw_masked }, { "game.panel.level_number.draw_order", &game.panel.level_number.sort_priority }, { "game.panel.gems.x", &game.panel.gems.x }, { "game.panel.gems.y", &game.panel.gems.y }, { "game.panel.gems.align", &game.panel.gems.align }, { "game.panel.gems.valign", &game.panel.gems.valign }, { "game.panel.gems.digits", &game.panel.gems.size }, { "game.panel.gems.font", &game.panel.gems.font }, { "game.panel.gems.draw_masked", &game.panel.gems.draw_masked }, { "game.panel.gems.draw_order", &game.panel.gems.sort_priority }, { "game.panel.inventory_count.x", &game.panel.inventory_count.x }, { "game.panel.inventory_count.y", &game.panel.inventory_count.y }, { "game.panel.inventory_count.align", &game.panel.inventory_count.align }, { "game.panel.inventory_count.valign", &game.panel.inventory_count.valign }, { "game.panel.inventory_count.digits", &game.panel.inventory_count.size }, { "game.panel.inventory_count.font", &game.panel.inventory_count.font }, { "game.panel.inventory_count.draw_masked", &game.panel.inventory_count.draw_masked }, { "game.panel.inventory_count.draw_order", &game.panel.inventory_count.sort_priority }, { "game.panel.inventory_first_1.x", &game.panel.inventory_first[0].x }, { "game.panel.inventory_first_1.y", &game.panel.inventory_first[0].y }, { "game.panel.inventory_first_1.tile_size", &game.panel.inventory_first[0].size }, { "game.panel.inventory_first_1.draw_masked", &game.panel.inventory_first[0].draw_masked }, { "game.panel.inventory_first_1.draw_order", &game.panel.inventory_first[0].sort_priority }, { "game.panel.inventory_first_2.x", &game.panel.inventory_first[1].x }, { "game.panel.inventory_first_2.y", &game.panel.inventory_first[1].y }, { "game.panel.inventory_first_2.tile_size", &game.panel.inventory_first[1].size }, { "game.panel.inventory_first_2.draw_masked", &game.panel.inventory_first[1].draw_masked }, { "game.panel.inventory_first_2.draw_order", &game.panel.inventory_first[1].sort_priority }, { "game.panel.inventory_first_3.x", &game.panel.inventory_first[2].x }, { "game.panel.inventory_first_3.y", &game.panel.inventory_first[2].y }, { "game.panel.inventory_first_3.tile_size", &game.panel.inventory_first[2].size }, { "game.panel.inventory_first_3.draw_masked", &game.panel.inventory_first[2].draw_masked }, { "game.panel.inventory_first_3.draw_order", &game.panel.inventory_first[2].sort_priority }, { "game.panel.inventory_first_4.x", &game.panel.inventory_first[3].x }, { "game.panel.inventory_first_4.y", &game.panel.inventory_first[3].y }, { "game.panel.inventory_first_4.tile_size", &game.panel.inventory_first[3].size }, { "game.panel.inventory_first_4.draw_masked", &game.panel.inventory_first[3].draw_masked }, { "game.panel.inventory_first_4.draw_order", &game.panel.inventory_first[3].sort_priority }, { "game.panel.inventory_first_5.x", &game.panel.inventory_first[4].x }, { "game.panel.inventory_first_5.y", &game.panel.inventory_first[4].y }, { "game.panel.inventory_first_5.tile_size", &game.panel.inventory_first[4].size }, { "game.panel.inventory_first_5.draw_masked", &game.panel.inventory_first[4].draw_masked }, { "game.panel.inventory_first_5.draw_order", &game.panel.inventory_first[4].sort_priority }, { "game.panel.inventory_first_6.x", &game.panel.inventory_first[5].x }, { "game.panel.inventory_first_6.y", &game.panel.inventory_first[5].y }, { "game.panel.inventory_first_6.tile_size", &game.panel.inventory_first[5].size }, { "game.panel.inventory_first_6.draw_masked", &game.panel.inventory_first[5].draw_masked }, { "game.panel.inventory_first_6.draw_order", &game.panel.inventory_first[5].sort_priority }, { "game.panel.inventory_first_7.x", &game.panel.inventory_first[6].x }, { "game.panel.inventory_first_7.y", &game.panel.inventory_first[6].y }, { "game.panel.inventory_first_7.tile_size", &game.panel.inventory_first[6].size }, { "game.panel.inventory_first_7.draw_masked", &game.panel.inventory_first[6].draw_masked }, { "game.panel.inventory_first_7.draw_order", &game.panel.inventory_first[6].sort_priority }, { "game.panel.inventory_first_8.x", &game.panel.inventory_first[7].x }, { "game.panel.inventory_first_8.y", &game.panel.inventory_first[7].y }, { "game.panel.inventory_first_8.tile_size", &game.panel.inventory_first[7].size }, { "game.panel.inventory_first_8.draw_masked", &game.panel.inventory_first[7].draw_masked }, { "game.panel.inventory_first_8.draw_order", &game.panel.inventory_first[7].sort_priority }, { "game.panel.inventory_last_1.x", &game.panel.inventory_last[0].x }, { "game.panel.inventory_last_1.y", &game.panel.inventory_last[0].y }, { "game.panel.inventory_last_1.tile_size", &game.panel.inventory_last[0].size }, { "game.panel.inventory_last_1.draw_masked", &game.panel.inventory_last[0].draw_masked }, { "game.panel.inventory_last_1.draw_order", &game.panel.inventory_last[0].sort_priority }, { "game.panel.inventory_last_2.x", &game.panel.inventory_last[1].x }, { "game.panel.inventory_last_2.y", &game.panel.inventory_last[1].y }, { "game.panel.inventory_last_2.tile_size", &game.panel.inventory_last[1].size }, { "game.panel.inventory_last_2.draw_masked", &game.panel.inventory_last[1].draw_masked }, { "game.panel.inventory_last_2.draw_order", &game.panel.inventory_last[1].sort_priority }, { "game.panel.inventory_last_3.x", &game.panel.inventory_last[2].x }, { "game.panel.inventory_last_3.y", &game.panel.inventory_last[2].y }, { "game.panel.inventory_last_3.tile_size", &game.panel.inventory_last[2].size }, { "game.panel.inventory_last_3.draw_masked", &game.panel.inventory_last[2].draw_masked }, { "game.panel.inventory_last_3.draw_order", &game.panel.inventory_last[2].sort_priority }, { "game.panel.inventory_last_4.x", &game.panel.inventory_last[3].x }, { "game.panel.inventory_last_4.y", &game.panel.inventory_last[3].y }, { "game.panel.inventory_last_4.tile_size", &game.panel.inventory_last[3].size }, { "game.panel.inventory_last_4.draw_masked", &game.panel.inventory_last[3].draw_masked }, { "game.panel.inventory_last_4.draw_order", &game.panel.inventory_last[3].sort_priority }, { "game.panel.inventory_last_5.x", &game.panel.inventory_last[4].x }, { "game.panel.inventory_last_5.y", &game.panel.inventory_last[4].y }, { "game.panel.inventory_last_5.tile_size", &game.panel.inventory_last[4].size }, { "game.panel.inventory_last_5.draw_masked", &game.panel.inventory_last[4].draw_masked }, { "game.panel.inventory_last_5.draw_order", &game.panel.inventory_last[4].sort_priority }, { "game.panel.inventory_last_6.x", &game.panel.inventory_last[5].x }, { "game.panel.inventory_last_6.y", &game.panel.inventory_last[5].y }, { "game.panel.inventory_last_6.tile_size", &game.panel.inventory_last[5].size }, { "game.panel.inventory_last_6.draw_masked", &game.panel.inventory_last[5].draw_masked }, { "game.panel.inventory_last_6.draw_order", &game.panel.inventory_last[5].sort_priority }, { "game.panel.inventory_last_7.x", &game.panel.inventory_last[6].x }, { "game.panel.inventory_last_7.y", &game.panel.inventory_last[6].y }, { "game.panel.inventory_last_7.tile_size", &game.panel.inventory_last[6].size }, { "game.panel.inventory_last_7.draw_masked", &game.panel.inventory_last[6].draw_masked }, { "game.panel.inventory_last_7.draw_order", &game.panel.inventory_last[6].sort_priority }, { "game.panel.inventory_last_8.x", &game.panel.inventory_last[7].x }, { "game.panel.inventory_last_8.y", &game.panel.inventory_last[7].y }, { "game.panel.inventory_last_8.tile_size", &game.panel.inventory_last[7].size }, { "game.panel.inventory_last_8.draw_masked", &game.panel.inventory_last[7].draw_masked }, { "game.panel.inventory_last_8.draw_order", &game.panel.inventory_last[7].sort_priority }, { "game.panel.key_1.x", &game.panel.key[0].x }, { "game.panel.key_1.y", &game.panel.key[0].y }, { "game.panel.key_1.tile_size", &game.panel.key[0].size }, { "game.panel.key_1.draw_masked", &game.panel.key[0].draw_masked }, { "game.panel.key_1.draw_order", &game.panel.key[0].sort_priority }, { "game.panel.key_2.x", &game.panel.key[1].x }, { "game.panel.key_2.y", &game.panel.key[1].y }, { "game.panel.key_2.tile_size", &game.panel.key[1].size }, { "game.panel.key_2.draw_masked", &game.panel.key[1].draw_masked }, { "game.panel.key_2.draw_order", &game.panel.key[1].sort_priority }, { "game.panel.key_3.x", &game.panel.key[2].x }, { "game.panel.key_3.y", &game.panel.key[2].y }, { "game.panel.key_3.tile_size", &game.panel.key[2].size }, { "game.panel.key_3.draw_masked", &game.panel.key[2].draw_masked }, { "game.panel.key_3.draw_order", &game.panel.key[2].sort_priority }, { "game.panel.key_4.x", &game.panel.key[3].x }, { "game.panel.key_4.y", &game.panel.key[3].y }, { "game.panel.key_4.tile_size", &game.panel.key[3].size }, { "game.panel.key_4.draw_masked", &game.panel.key[3].draw_masked }, { "game.panel.key_4.draw_order", &game.panel.key[3].sort_priority }, { "game.panel.key_5.x", &game.panel.key[4].x }, { "game.panel.key_5.y", &game.panel.key[4].y }, { "game.panel.key_5.tile_size", &game.panel.key[4].size }, { "game.panel.key_5.draw_masked", &game.panel.key[4].draw_masked }, { "game.panel.key_5.draw_order", &game.panel.key[4].sort_priority }, { "game.panel.key_6.x", &game.panel.key[5].x }, { "game.panel.key_6.y", &game.panel.key[5].y }, { "game.panel.key_6.tile_size", &game.panel.key[5].size }, { "game.panel.key_6.draw_masked", &game.panel.key[5].draw_masked }, { "game.panel.key_6.draw_order", &game.panel.key[5].sort_priority }, { "game.panel.key_7.x", &game.panel.key[6].x }, { "game.panel.key_7.y", &game.panel.key[6].y }, { "game.panel.key_7.tile_size", &game.panel.key[6].size }, { "game.panel.key_7.draw_masked", &game.panel.key[6].draw_masked }, { "game.panel.key_7.draw_order", &game.panel.key[6].sort_priority }, { "game.panel.key_8.x", &game.panel.key[7].x }, { "game.panel.key_8.y", &game.panel.key[7].y }, { "game.panel.key_8.tile_size", &game.panel.key[7].size }, { "game.panel.key_8.draw_masked", &game.panel.key[7].draw_masked }, { "game.panel.key_8.draw_order", &game.panel.key[7].sort_priority }, { "game.panel.key_white.x", &game.panel.key_white.x }, { "game.panel.key_white.y", &game.panel.key_white.y }, { "game.panel.key_white.tile_size", &game.panel.key_white.size }, { "game.panel.key_white.draw_masked", &game.panel.key_white.draw_masked }, { "game.panel.key_white.draw_order", &game.panel.key_white.sort_priority }, { "game.panel.key_white_count.x", &game.panel.key_white_count.x }, { "game.panel.key_white_count.y", &game.panel.key_white_count.y }, { "game.panel.key_white_count.align", &game.panel.key_white_count.align }, { "game.panel.key_white_count.valign", &game.panel.key_white_count.valign }, { "game.panel.key_white_count.digits", &game.panel.key_white_count.size }, { "game.panel.key_white_count.font", &game.panel.key_white_count.font }, { "game.panel.key_white_count.draw_masked", &game.panel.key_white_count.draw_masked }, { "game.panel.key_white_count.draw_order", &game.panel.key_white_count.sort_priority }, { "game.panel.score.x", &game.panel.score.x }, { "game.panel.score.y", &game.panel.score.y }, { "game.panel.score.align", &game.panel.score.align }, { "game.panel.score.valign", &game.panel.score.valign }, { "game.panel.score.digits", &game.panel.score.size }, { "game.panel.score.font", &game.panel.score.font }, { "game.panel.score.draw_masked", &game.panel.score.draw_masked }, { "game.panel.score.draw_order", &game.panel.score.sort_priority }, { "game.panel.highscore.x", &game.panel.highscore.x }, { "game.panel.highscore.y", &game.panel.highscore.y }, { "game.panel.highscore.align", &game.panel.highscore.align }, { "game.panel.highscore.valign", &game.panel.highscore.valign }, { "game.panel.highscore.digits", &game.panel.highscore.size }, { "game.panel.highscore.font", &game.panel.highscore.font }, { "game.panel.highscore.draw_masked", &game.panel.highscore.draw_masked }, { "game.panel.highscore.draw_order", &game.panel.highscore.sort_priority }, { "game.panel.time.x", &game.panel.time.x }, { "game.panel.time.y", &game.panel.time.y }, { "game.panel.time.align", &game.panel.time.align }, { "game.panel.time.valign", &game.panel.time.valign }, { "game.panel.time.digits", &game.panel.time.size }, { "game.panel.time.font", &game.panel.time.font }, { "game.panel.time.font_narrow", &game.panel.time.font_alt }, { "game.panel.time.draw_masked", &game.panel.time.draw_masked }, { "game.panel.time.draw_order", &game.panel.time.sort_priority }, { "game.panel.time_hh.x", &game.panel.time_hh.x }, { "game.panel.time_hh.y", &game.panel.time_hh.y }, { "game.panel.time_hh.align", &game.panel.time_hh.align }, { "game.panel.time_hh.valign", &game.panel.time_hh.valign }, { "game.panel.time_hh.digits", &game.panel.time_hh.size }, { "game.panel.time_hh.font", &game.panel.time_hh.font }, { "game.panel.time_hh.draw_masked", &game.panel.time_hh.draw_masked }, { "game.panel.time_hh.draw_order", &game.panel.time_hh.sort_priority }, { "game.panel.time_mm.x", &game.panel.time_mm.x }, { "game.panel.time_mm.y", &game.panel.time_mm.y }, { "game.panel.time_mm.align", &game.panel.time_mm.align }, { "game.panel.time_mm.valign", &game.panel.time_mm.valign }, { "game.panel.time_mm.digits", &game.panel.time_mm.size }, { "game.panel.time_mm.font", &game.panel.time_mm.font }, { "game.panel.time_mm.draw_masked", &game.panel.time_mm.draw_masked }, { "game.panel.time_mm.draw_order", &game.panel.time_mm.sort_priority }, { "game.panel.time_ss.x", &game.panel.time_ss.x }, { "game.panel.time_ss.y", &game.panel.time_ss.y }, { "game.panel.time_ss.align", &game.panel.time_ss.align }, { "game.panel.time_ss.valign", &game.panel.time_ss.valign }, { "game.panel.time_ss.digits", &game.panel.time_ss.size }, { "game.panel.time_ss.font", &game.panel.time_ss.font }, { "game.panel.time_ss.draw_masked", &game.panel.time_ss.draw_masked }, { "game.panel.time_ss.draw_order", &game.panel.time_ss.sort_priority }, { "game.panel.time_anim.x", &game.panel.time_anim.x }, { "game.panel.time_anim.y", &game.panel.time_anim.y }, { "game.panel.time_anim.direction", &game.panel.time_anim.direction }, { "game.panel.time_anim.class", &game.panel.time_anim.class }, { "game.panel.health.x", &game.panel.health.x }, { "game.panel.health.y", &game.panel.health.y }, { "game.panel.health.align", &game.panel.health.align }, { "game.panel.health.valign", &game.panel.health.valign }, { "game.panel.health.digits", &game.panel.health.size }, { "game.panel.health.font", &game.panel.health.font }, { "game.panel.health.font_narrow", &game.panel.health.font_alt }, { "game.panel.health.draw_masked", &game.panel.health.draw_masked }, { "game.panel.health.draw_order", &game.panel.health.sort_priority }, { "game.panel.health_anim.x", &game.panel.health_anim.x }, { "game.panel.health_anim.y", &game.panel.health_anim.y }, { "game.panel.health_anim.direction", &game.panel.health_anim.direction }, { "game.panel.health_anim.class", &game.panel.health_anim.class }, { "game.panel.health_anim.style", &game.panel.health_anim.style }, { "game.panel.frame.x", &game.panel.frame.x }, { "game.panel.frame.y", &game.panel.frame.y }, { "game.panel.frame.align", &game.panel.frame.align }, { "game.panel.frame.valign", &game.panel.frame.valign }, { "game.panel.frame.digits", &game.panel.frame.size }, { "game.panel.frame.font", &game.panel.frame.font }, { "game.panel.frame.draw_masked", &game.panel.frame.draw_masked }, { "game.panel.frame.draw_order", &game.panel.frame.sort_priority }, { "game.panel.shield_normal.x", &game.panel.shield_normal.x }, { "game.panel.shield_normal.y", &game.panel.shield_normal.y }, { "game.panel.shield_normal.tile_size", &game.panel.shield_normal.size }, { "game.panel.shield_normal.draw_masked", &game.panel.shield_normal.draw_masked }, { "game.panel.shield_normal.draw_order", &game.panel.shield_normal.sort_priority }, { "game.panel.shield_normal_time.x", &game.panel.shield_normal_time.x }, { "game.panel.shield_normal_time.y", &game.panel.shield_normal_time.y }, { "game.panel.shield_normal_time.align", &game.panel.shield_normal_time.align }, { "game.panel.shield_normal_time.valign", &game.panel.shield_normal_time.valign }, { "game.panel.shield_normal_time.digits", &game.panel.shield_normal_time.size }, { "game.panel.shield_normal_time.font", &game.panel.shield_normal_time.font }, { "game.panel.shield_normal_time.draw_masked", &game.panel.shield_normal_time.draw_masked }, { "game.panel.shield_normal_time.draw_order", &game.panel.shield_normal_time.sort_priority }, { "game.panel.shield_deadly.x", &game.panel.shield_deadly.x }, { "game.panel.shield_deadly.y", &game.panel.shield_deadly.y }, { "game.panel.shield_deadly.tile_size", &game.panel.shield_deadly.size }, { "game.panel.shield_deadly.draw_masked", &game.panel.shield_deadly.draw_masked }, { "game.panel.shield_deadly.draw_order", &game.panel.shield_deadly.sort_priority }, { "game.panel.shield_deadly_time.x", &game.panel.shield_deadly_time.x }, { "game.panel.shield_deadly_time.y", &game.panel.shield_deadly_time.y }, { "game.panel.shield_deadly_time.align", &game.panel.shield_deadly_time.align }, { "game.panel.shield_deadly_time.valign", &game.panel.shield_deadly_time.valign }, { "game.panel.shield_deadly_time.digits", &game.panel.shield_deadly_time.size }, { "game.panel.shield_deadly_time.font", &game.panel.shield_deadly_time.font }, { "game.panel.shield_deadly_time.draw_masked", &game.panel.shield_deadly_time.draw_masked }, { "game.panel.shield_deadly_time.draw_order", &game.panel.shield_deadly_time.sort_priority }, { "game.panel.exit.x", &game.panel.exit.x }, { "game.panel.exit.y", &game.panel.exit.y }, { "game.panel.exit.tile_size", &game.panel.exit.size }, { "game.panel.exit.draw_masked", &game.panel.exit.draw_masked }, { "game.panel.exit.draw_order", &game.panel.exit.sort_priority }, { "game.panel.emc_magic_ball.x", &game.panel.emc_magic_ball.x }, { "game.panel.emc_magic_ball.y", &game.panel.emc_magic_ball.y }, { "game.panel.emc_magic_ball.tile_size", &game.panel.emc_magic_ball.size }, { "game.panel.emc_magic_ball.draw_masked", &game.panel.emc_magic_ball.draw_masked }, { "game.panel.emc_magic_ball.draw_order", &game.panel.emc_magic_ball.sort_priority }, { "game.panel.emc_magic_ball_switch.x", &game.panel.emc_magic_ball_switch.x }, { "game.panel.emc_magic_ball_switch.y", &game.panel.emc_magic_ball_switch.y }, { "game.panel.emc_magic_ball_switch.tile_size", &game.panel.emc_magic_ball_switch.size }, { "game.panel.emc_magic_ball_switch.draw_masked", &game.panel.emc_magic_ball_switch.draw_masked }, { "game.panel.emc_magic_ball_switch.draw_order", &game.panel.emc_magic_ball_switch.sort_priority }, { "game.panel.light_switch.x", &game.panel.light_switch.x }, { "game.panel.light_switch.y", &game.panel.light_switch.y }, { "game.panel.light_switch.tile_size", &game.panel.light_switch.size }, { "game.panel.light_switch.draw_masked", &game.panel.light_switch.draw_masked }, { "game.panel.light_switch.draw_order", &game.panel.light_switch.sort_priority }, { "game.panel.light_switch_time.x", &game.panel.light_switch_time.x }, { "game.panel.light_switch_time.y", &game.panel.light_switch_time.y }, { "game.panel.light_switch_time.align", &game.panel.light_switch_time.align }, { "game.panel.light_switch_time.valign", &game.panel.light_switch_time.valign }, { "game.panel.light_switch_time.digits", &game.panel.light_switch_time.size }, { "game.panel.light_switch_time.font", &game.panel.light_switch_time.font }, { "game.panel.light_switch_time.draw_masked", &game.panel.light_switch_time.draw_masked }, { "game.panel.light_switch_time.draw_order", &game.panel.light_switch_time.sort_priority }, { "game.panel.timegate_switch.x", &game.panel.timegate_switch.x }, { "game.panel.timegate_switch.y", &game.panel.timegate_switch.y }, { "game.panel.timegate_switch.tile_size", &game.panel.timegate_switch.size }, { "game.panel.timegate_switch.draw_masked", &game.panel.timegate_switch.draw_masked }, { "game.panel.timegate_switch.draw_order", &game.panel.timegate_switch.sort_priority }, { "game.panel.timegate_switch_time.x", &game.panel.timegate_switch_time.x }, { "game.panel.timegate_switch_time.y", &game.panel.timegate_switch_time.y }, { "game.panel.timegate_switch_time.align", &game.panel.timegate_switch_time.align }, { "game.panel.timegate_switch_time.valign", &game.panel.timegate_switch_time.valign }, { "game.panel.timegate_switch_time.digits", &game.panel.timegate_switch_time.size }, { "game.panel.timegate_switch_time.font", &game.panel.timegate_switch_time.font }, { "game.panel.timegate_switch_time.draw_masked", &game.panel.timegate_switch_time.draw_masked }, { "game.panel.timegate_switch_time.draw_order", &game.panel.timegate_switch_time.sort_priority }, { "game.panel.switchgate_switch.x", &game.panel.switchgate_switch.x }, { "game.panel.switchgate_switch.y", &game.panel.switchgate_switch.y }, { "game.panel.switchgate_switch.tile_size", &game.panel.switchgate_switch.size }, { "game.panel.switchgate_switch.draw_masked", &game.panel.switchgate_switch.draw_masked }, { "game.panel.switchgate_switch.draw_order", &game.panel.switchgate_switch.sort_priority }, { "game.panel.emc_lenses.x", &game.panel.emc_lenses.x }, { "game.panel.emc_lenses.y", &game.panel.emc_lenses.y }, { "game.panel.emc_lenses.tile_size", &game.panel.emc_lenses.size }, { "game.panel.emc_lenses.draw_masked", &game.panel.emc_lenses.draw_masked }, { "game.panel.emc_lenses.draw_order", &game.panel.emc_lenses.sort_priority }, { "game.panel.emc_lenses_time.x", &game.panel.emc_lenses_time.x }, { "game.panel.emc_lenses_time.y", &game.panel.emc_lenses_time.y }, { "game.panel.emc_lenses_time.align", &game.panel.emc_lenses_time.align }, { "game.panel.emc_lenses_time.valign", &game.panel.emc_lenses_time.valign }, { "game.panel.emc_lenses_time.digits", &game.panel.emc_lenses_time.size }, { "game.panel.emc_lenses_time.font", &game.panel.emc_lenses_time.font }, { "game.panel.emc_lenses_time.draw_masked", &game.panel.emc_lenses_time.draw_masked }, { "game.panel.emc_lenses_time.draw_order", &game.panel.emc_lenses_time.sort_priority }, { "game.panel.emc_magnifier.x", &game.panel.emc_magnifier.x }, { "game.panel.emc_magnifier.y", &game.panel.emc_magnifier.y }, { "game.panel.emc_magnifier.tile_size", &game.panel.emc_magnifier.size }, { "game.panel.emc_magnifier.draw_masked", &game.panel.emc_magnifier.draw_masked }, { "game.panel.emc_magnifier.draw_order", &game.panel.emc_magnifier.sort_priority }, { "game.panel.emc_magnifier_time.x", &game.panel.emc_magnifier_time.x }, { "game.panel.emc_magnifier_time.y", &game.panel.emc_magnifier_time.y }, { "game.panel.emc_magnifier_time.align", &game.panel.emc_magnifier_time.align }, { "game.panel.emc_magnifier_time.valign", &game.panel.emc_magnifier_time.valign }, { "game.panel.emc_magnifier_time.digits", &game.panel.emc_magnifier_time.size }, { "game.panel.emc_magnifier_time.font", &game.panel.emc_magnifier_time.font }, { "game.panel.emc_magnifier_time.draw_masked", &game.panel.emc_magnifier_time.draw_masked }, { "game.panel.emc_magnifier_time.draw_order", &game.panel.emc_magnifier_time.sort_priority }, { "game.panel.balloon_switch.x", &game.panel.balloon_switch.x }, { "game.panel.balloon_switch.y", &game.panel.balloon_switch.y }, { "game.panel.balloon_switch.tile_size", &game.panel.balloon_switch.size }, { "game.panel.balloon_switch.draw_masked", &game.panel.balloon_switch.draw_masked }, { "game.panel.balloon_switch.draw_order", &game.panel.balloon_switch.sort_priority }, { "game.panel.dynabomb_number.x", &game.panel.dynabomb_number.x }, { "game.panel.dynabomb_number.y", &game.panel.dynabomb_number.y }, { "game.panel.dynabomb_number.align", &game.panel.dynabomb_number.align }, { "game.panel.dynabomb_number.valign", &game.panel.dynabomb_number.valign }, { "game.panel.dynabomb_number.digits", &game.panel.dynabomb_number.size }, { "game.panel.dynabomb_number.font", &game.panel.dynabomb_number.font }, { "game.panel.dynabomb_number.draw_masked", &game.panel.dynabomb_number.draw_masked }, { "game.panel.dynabomb_number.draw_order", &game.panel.dynabomb_number.sort_priority }, { "game.panel.dynabomb_size.x", &game.panel.dynabomb_size.x }, { "game.panel.dynabomb_size.y", &game.panel.dynabomb_size.y }, { "game.panel.dynabomb_size.align", &game.panel.dynabomb_size.align }, { "game.panel.dynabomb_size.valign", &game.panel.dynabomb_size.valign }, { "game.panel.dynabomb_size.digits", &game.panel.dynabomb_size.size }, { "game.panel.dynabomb_size.font", &game.panel.dynabomb_size.font }, { "game.panel.dynabomb_size.draw_masked", &game.panel.dynabomb_size.draw_masked }, { "game.panel.dynabomb_size.draw_order", &game.panel.dynabomb_size.sort_priority }, { "game.panel.dynabomb_power.x", &game.panel.dynabomb_power.x }, { "game.panel.dynabomb_power.y", &game.panel.dynabomb_power.y }, { "game.panel.dynabomb_power.tile_size", &game.panel.dynabomb_power.size }, { "game.panel.dynabomb_power.draw_masked", &game.panel.dynabomb_power.draw_masked }, { "game.panel.dynabomb_power.draw_order", &game.panel.dynabomb_power.sort_priority }, { "game.panel.penguins.x", &game.panel.penguins.x }, { "game.panel.penguins.y", &game.panel.penguins.y }, { "game.panel.penguins.align", &game.panel.penguins.align }, { "game.panel.penguins.valign", &game.panel.penguins.valign }, { "game.panel.penguins.digits", &game.panel.penguins.size }, { "game.panel.penguins.font", &game.panel.penguins.font }, { "game.panel.penguins.draw_masked", &game.panel.penguins.draw_masked }, { "game.panel.penguins.draw_order", &game.panel.penguins.sort_priority }, { "game.panel.sokoban_objects.x", &game.panel.sokoban_objects.x }, { "game.panel.sokoban_objects.y", &game.panel.sokoban_objects.y }, { "game.panel.sokoban_objects.align", &game.panel.sokoban_objects.align }, { "game.panel.sokoban_objects.valign", &game.panel.sokoban_objects.valign }, { "game.panel.sokoban_objects.digits", &game.panel.sokoban_objects.size }, { "game.panel.sokoban_objects.font", &game.panel.sokoban_objects.font }, { "game.panel.sokoban_objects.draw_masked", &game.panel.sokoban_objects.draw_masked }, { "game.panel.sokoban_objects.draw_order", &game.panel.sokoban_objects.sort_priority }, { "game.panel.sokoban_fields.x", &game.panel.sokoban_fields.x }, { "game.panel.sokoban_fields.y", &game.panel.sokoban_fields.y }, { "game.panel.sokoban_fields.align", &game.panel.sokoban_fields.align }, { "game.panel.sokoban_fields.valign", &game.panel.sokoban_fields.valign }, { "game.panel.sokoban_fields.digits", &game.panel.sokoban_fields.size }, { "game.panel.sokoban_fields.font", &game.panel.sokoban_fields.font }, { "game.panel.sokoban_fields.draw_masked", &game.panel.sokoban_fields.draw_masked }, { "game.panel.sokoban_fields.draw_order", &game.panel.sokoban_fields.sort_priority }, { "game.panel.robot_wheel.x", &game.panel.robot_wheel.x }, { "game.panel.robot_wheel.y", &game.panel.robot_wheel.y }, { "game.panel.robot_wheel.tile_size", &game.panel.robot_wheel.size }, { "game.panel.robot_wheel.draw_masked", &game.panel.robot_wheel.draw_masked }, { "game.panel.robot_wheel.draw_order", &game.panel.robot_wheel.sort_priority }, { "game.panel.conveyor_belt_1.x", &game.panel.conveyor_belt[0].x }, { "game.panel.conveyor_belt_1.y", &game.panel.conveyor_belt[0].y }, { "game.panel.conveyor_belt_1.tile_size", &game.panel.conveyor_belt[0].size }, { "game.panel.conveyor_belt_1.draw_masked", &game.panel.conveyor_belt[0].draw_masked }, { "game.panel.conveyor_belt_1.draw_order", &game.panel.conveyor_belt[0].sort_priority }, { "game.panel.conveyor_belt_1_switch.x", &game.panel.conveyor_belt_switch[0].x }, { "game.panel.conveyor_belt_1_switch.y", &game.panel.conveyor_belt_switch[0].y }, { "game.panel.conveyor_belt_1_switch.tile_size", &game.panel.conveyor_belt_switch[0].size }, { "game.panel.conveyor_belt_1_switch.draw_masked", &game.panel.conveyor_belt_switch[0].draw_masked }, { "game.panel.conveyor_belt_1_switch.draw_order", &game.panel.conveyor_belt_switch[0].sort_priority }, { "game.panel.conveyor_belt_2.x", &game.panel.conveyor_belt[1].x }, { "game.panel.conveyor_belt_2.y", &game.panel.conveyor_belt[1].y }, { "game.panel.conveyor_belt_2.tile_size", &game.panel.conveyor_belt[1].size }, { "game.panel.conveyor_belt_2.draw_masked", &game.panel.conveyor_belt[1].draw_masked }, { "game.panel.conveyor_belt_2.draw_order", &game.panel.conveyor_belt[1].sort_priority }, { "game.panel.conveyor_belt_2_switch.x", &game.panel.conveyor_belt_switch[1].x }, { "game.panel.conveyor_belt_2_switch.y", &game.panel.conveyor_belt_switch[1].y }, { "game.panel.conveyor_belt_2_switch.tile_size", &game.panel.conveyor_belt_switch[1].size }, { "game.panel.conveyor_belt_2_switch.draw_masked", &game.panel.conveyor_belt_switch[1].draw_masked }, { "game.panel.conveyor_belt_2_switch.draw_order", &game.panel.conveyor_belt_switch[1].sort_priority }, { "game.panel.conveyor_belt_3.x", &game.panel.conveyor_belt[2].x }, { "game.panel.conveyor_belt_3.y", &game.panel.conveyor_belt[2].y }, { "game.panel.conveyor_belt_3.tile_size", &game.panel.conveyor_belt[2].size }, { "game.panel.conveyor_belt_3.draw_masked", &game.panel.conveyor_belt[2].draw_masked }, { "game.panel.conveyor_belt_3.draw_order", &game.panel.conveyor_belt[2].sort_priority }, { "game.panel.conveyor_belt_3_switch.x", &game.panel.conveyor_belt_switch[2].x }, { "game.panel.conveyor_belt_3_switch.y", &game.panel.conveyor_belt_switch[2].y }, { "game.panel.conveyor_belt_3_switch.tile_size", &game.panel.conveyor_belt_switch[2].size }, { "game.panel.conveyor_belt_3_switch.draw_masked", &game.panel.conveyor_belt_switch[2].draw_masked }, { "game.panel.conveyor_belt_3_switch.draw_order", &game.panel.conveyor_belt_switch[2].sort_priority }, { "game.panel.conveyor_belt_4.x", &game.panel.conveyor_belt[3].x }, { "game.panel.conveyor_belt_4.y", &game.panel.conveyor_belt[3].y }, { "game.panel.conveyor_belt_4.tile_size", &game.panel.conveyor_belt[3].size }, { "game.panel.conveyor_belt_4.draw_masked", &game.panel.conveyor_belt[3].draw_masked }, { "game.panel.conveyor_belt_4.draw_order", &game.panel.conveyor_belt[3].sort_priority }, { "game.panel.conveyor_belt_4_switch.x", &game.panel.conveyor_belt_switch[3].x }, { "game.panel.conveyor_belt_4_switch.y", &game.panel.conveyor_belt_switch[3].y }, { "game.panel.conveyor_belt_4_switch.tile_size", &game.panel.conveyor_belt_switch[3].size }, { "game.panel.conveyor_belt_4_switch.draw_masked", &game.panel.conveyor_belt_switch[3].draw_masked }, { "game.panel.conveyor_belt_4_switch.draw_order", &game.panel.conveyor_belt_switch[3].sort_priority }, { "game.panel.magic_wall.x", &game.panel.magic_wall.x }, { "game.panel.magic_wall.y", &game.panel.magic_wall.y }, { "game.panel.magic_wall.tile_size", &game.panel.magic_wall.size }, { "game.panel.magic_wall.draw_masked", &game.panel.magic_wall.draw_masked }, { "game.panel.magic_wall.draw_order", &game.panel.magic_wall.sort_priority }, { "game.panel.magic_wall_time.x", &game.panel.magic_wall_time.x }, { "game.panel.magic_wall_time.y", &game.panel.magic_wall_time.y }, { "game.panel.magic_wall_time.align", &game.panel.magic_wall_time.align }, { "game.panel.magic_wall_time.valign", &game.panel.magic_wall_time.valign }, { "game.panel.magic_wall_time.digits", &game.panel.magic_wall_time.size }, { "game.panel.magic_wall_time.font", &game.panel.magic_wall_time.font }, { "game.panel.magic_wall_time.draw_masked", &game.panel.magic_wall_time.draw_masked }, { "game.panel.magic_wall_time.draw_order", &game.panel.magic_wall_time.sort_priority }, { "game.panel.gravity_state.x", &game.panel.gravity_state.x }, { "game.panel.gravity_state.y", &game.panel.gravity_state.y }, { "game.panel.gravity_state.align", &game.panel.gravity_state.align }, { "game.panel.gravity_state.valign", &game.panel.gravity_state.valign }, { "game.panel.gravity_state.chars", &game.panel.gravity_state.size }, { "game.panel.gravity_state.font", &game.panel.gravity_state.font }, { "game.panel.gravity_state.font_active", &game.panel.gravity_state.font_alt }, { "game.panel.gravity_state.draw_masked", &game.panel.gravity_state.draw_masked }, { "game.panel.gravity_state.draw_order", &game.panel.gravity_state.sort_priority }, { "game.panel.graphic_1.x", &game.panel.graphic[0].x }, { "game.panel.graphic_1.y", &game.panel.graphic[0].y }, { "game.panel.graphic_1.draw_masked", &game.panel.graphic[0].draw_masked }, { "game.panel.graphic_1.draw_order", &game.panel.graphic[0].sort_priority }, { "game.panel.graphic_2.x", &game.panel.graphic[1].x }, { "game.panel.graphic_2.y", &game.panel.graphic[1].y }, { "game.panel.graphic_2.draw_masked", &game.panel.graphic[1].draw_masked }, { "game.panel.graphic_2.draw_order", &game.panel.graphic[1].sort_priority }, { "game.panel.graphic_3.x", &game.panel.graphic[2].x }, { "game.panel.graphic_3.y", &game.panel.graphic[2].y }, { "game.panel.graphic_3.draw_masked", &game.panel.graphic[2].draw_masked }, { "game.panel.graphic_3.draw_order", &game.panel.graphic[2].sort_priority }, { "game.panel.graphic_4.x", &game.panel.graphic[3].x }, { "game.panel.graphic_4.y", &game.panel.graphic[3].y }, { "game.panel.graphic_4.draw_masked", &game.panel.graphic[3].draw_masked }, { "game.panel.graphic_4.draw_order", &game.panel.graphic[3].sort_priority }, { "game.panel.graphic_5.x", &game.panel.graphic[4].x }, { "game.panel.graphic_5.y", &game.panel.graphic[4].y }, { "game.panel.graphic_5.draw_masked", &game.panel.graphic[4].draw_masked }, { "game.panel.graphic_5.draw_order", &game.panel.graphic[4].sort_priority }, { "game.panel.graphic_6.x", &game.panel.graphic[5].x }, { "game.panel.graphic_6.y", &game.panel.graphic[5].y }, { "game.panel.graphic_6.draw_masked", &game.panel.graphic[5].draw_masked }, { "game.panel.graphic_6.draw_order", &game.panel.graphic[5].sort_priority }, { "game.panel.graphic_7.x", &game.panel.graphic[6].x }, { "game.panel.graphic_7.y", &game.panel.graphic[6].y }, { "game.panel.graphic_7.draw_masked", &game.panel.graphic[6].draw_masked }, { "game.panel.graphic_7.draw_order", &game.panel.graphic[6].sort_priority }, { "game.panel.graphic_8.x", &game.panel.graphic[7].x }, { "game.panel.graphic_8.y", &game.panel.graphic[7].y }, { "game.panel.graphic_8.draw_masked", &game.panel.graphic[7].draw_masked }, { "game.panel.graphic_8.draw_order", &game.panel.graphic[7].sort_priority }, { "game.panel.element_1.x", &game.panel.element[0].x }, { "game.panel.element_1.y", &game.panel.element[0].y }, { "game.panel.element_1.tile_size", &game.panel.element[0].size }, { "game.panel.element_1.element", &game.panel.element[0].id }, { "game.panel.element_1.draw_masked", &game.panel.element[0].draw_masked }, { "game.panel.element_1.draw_order", &game.panel.element[0].sort_priority }, { "game.panel.element_1_count.x", &game.panel.element_count[0].x }, { "game.panel.element_1_count.y", &game.panel.element_count[0].y }, { "game.panel.element_1_count.align", &game.panel.element_count[0].align }, { "game.panel.element_1_count.valign", &game.panel.element_count[0].valign }, { "game.panel.element_1_count.digits", &game.panel.element_count[0].size }, { "game.panel.element_1_count.font", &game.panel.element_count[0].font }, { "game.panel.element_1_count.element", &game.panel.element_count[0].id }, { "game.panel.element_1_count.draw_masked", &game.panel.element_count[0].draw_masked }, { "game.panel.element_1_count.draw_order", &game.panel.element_count[0].sort_priority }, { "game.panel.element_2.x", &game.panel.element[1].x }, { "game.panel.element_2.y", &game.panel.element[1].y }, { "game.panel.element_2.tile_size", &game.panel.element[1].size }, { "game.panel.element_2.element", &game.panel.element[1].id }, { "game.panel.element_2.draw_masked", &game.panel.element[1].draw_masked }, { "game.panel.element_2.draw_order", &game.panel.element[1].sort_priority }, { "game.panel.element_2_count.x", &game.panel.element_count[1].x }, { "game.panel.element_2_count.y", &game.panel.element_count[1].y }, { "game.panel.element_2_count.align", &game.panel.element_count[1].align }, { "game.panel.element_2_count.valign", &game.panel.element_count[1].valign }, { "game.panel.element_2_count.digits", &game.panel.element_count[1].size }, { "game.panel.element_2_count.font", &game.panel.element_count[1].font }, { "game.panel.element_2_count.element", &game.panel.element_count[1].id }, { "game.panel.element_2_count.draw_masked", &game.panel.element_count[1].draw_masked }, { "game.panel.element_2_count.draw_order", &game.panel.element_count[1].sort_priority }, { "game.panel.element_3.x", &game.panel.element[2].x }, { "game.panel.element_3.y", &game.panel.element[2].y }, { "game.panel.element_3.tile_size", &game.panel.element[2].size }, { "game.panel.element_3.element", &game.panel.element[2].id }, { "game.panel.element_3.draw_masked", &game.panel.element[2].draw_masked }, { "game.panel.element_3.draw_order", &game.panel.element[2].sort_priority }, { "game.panel.element_3_count.x", &game.panel.element_count[2].x }, { "game.panel.element_3_count.y", &game.panel.element_count[2].y }, { "game.panel.element_3_count.align", &game.panel.element_count[2].align }, { "game.panel.element_3_count.valign", &game.panel.element_count[2].valign }, { "game.panel.element_3_count.digits", &game.panel.element_count[2].size }, { "game.panel.element_3_count.font", &game.panel.element_count[2].font }, { "game.panel.element_3_count.element", &game.panel.element_count[2].id }, { "game.panel.element_3_count.draw_masked", &game.panel.element_count[2].draw_masked }, { "game.panel.element_3_count.draw_order", &game.panel.element_count[2].sort_priority }, { "game.panel.element_4.x", &game.panel.element[3].x }, { "game.panel.element_4.y", &game.panel.element[3].y }, { "game.panel.element_4.tile_size", &game.panel.element[3].size }, { "game.panel.element_4.element", &game.panel.element[3].id }, { "game.panel.element_4.draw_masked", &game.panel.element[3].draw_masked }, { "game.panel.element_4.draw_order", &game.panel.element[3].sort_priority }, { "game.panel.element_4_count.x", &game.panel.element_count[3].x }, { "game.panel.element_4_count.y", &game.panel.element_count[3].y }, { "game.panel.element_4_count.align", &game.panel.element_count[3].align }, { "game.panel.element_4_count.valign", &game.panel.element_count[3].valign }, { "game.panel.element_4_count.digits", &game.panel.element_count[3].size }, { "game.panel.element_4_count.font", &game.panel.element_count[3].font }, { "game.panel.element_4_count.element", &game.panel.element_count[3].id }, { "game.panel.element_4_count.draw_masked", &game.panel.element_count[3].draw_masked }, { "game.panel.element_4_count.draw_order", &game.panel.element_count[3].sort_priority }, { "game.panel.element_5.x", &game.panel.element[4].x }, { "game.panel.element_5.y", &game.panel.element[4].y }, { "game.panel.element_5.tile_size", &game.panel.element[4].size }, { "game.panel.element_5.element", &game.panel.element[4].id }, { "game.panel.element_5.draw_masked", &game.panel.element[4].draw_masked }, { "game.panel.element_5.draw_order", &game.panel.element[4].sort_priority }, { "game.panel.element_5_count.x", &game.panel.element_count[4].x }, { "game.panel.element_5_count.y", &game.panel.element_count[4].y }, { "game.panel.element_5_count.align", &game.panel.element_count[4].align }, { "game.panel.element_5_count.valign", &game.panel.element_count[4].valign }, { "game.panel.element_5_count.digits", &game.panel.element_count[4].size }, { "game.panel.element_5_count.font", &game.panel.element_count[4].font }, { "game.panel.element_5_count.element", &game.panel.element_count[4].id }, { "game.panel.element_5_count.draw_masked", &game.panel.element_count[4].draw_masked }, { "game.panel.element_5_count.draw_order", &game.panel.element_count[4].sort_priority }, { "game.panel.element_6.x", &game.panel.element[5].x }, { "game.panel.element_6.y", &game.panel.element[5].y }, { "game.panel.element_6.tile_size", &game.panel.element[5].size }, { "game.panel.element_6.element", &game.panel.element[5].id }, { "game.panel.element_6.draw_masked", &game.panel.element[5].draw_masked }, { "game.panel.element_6.draw_order", &game.panel.element[5].sort_priority }, { "game.panel.element_6_count.x", &game.panel.element_count[5].x }, { "game.panel.element_6_count.y", &game.panel.element_count[5].y }, { "game.panel.element_6_count.align", &game.panel.element_count[5].align }, { "game.panel.element_6_count.valign", &game.panel.element_count[5].valign }, { "game.panel.element_6_count.digits", &game.panel.element_count[5].size }, { "game.panel.element_6_count.font", &game.panel.element_count[5].font }, { "game.panel.element_6_count.element", &game.panel.element_count[5].id }, { "game.panel.element_6_count.draw_masked", &game.panel.element_count[5].draw_masked }, { "game.panel.element_6_count.draw_order", &game.panel.element_count[5].sort_priority }, { "game.panel.element_7.x", &game.panel.element[6].x }, { "game.panel.element_7.y", &game.panel.element[6].y }, { "game.panel.element_7.tile_size", &game.panel.element[6].size }, { "game.panel.element_7.element", &game.panel.element[6].id }, { "game.panel.element_7.draw_masked", &game.panel.element[6].draw_masked }, { "game.panel.element_7.draw_order", &game.panel.element[6].sort_priority }, { "game.panel.element_7_count.x", &game.panel.element_count[6].x }, { "game.panel.element_7_count.y", &game.panel.element_count[6].y }, { "game.panel.element_7_count.align", &game.panel.element_count[6].align }, { "game.panel.element_7_count.valign", &game.panel.element_count[6].valign }, { "game.panel.element_7_count.digits", &game.panel.element_count[6].size }, { "game.panel.element_7_count.font", &game.panel.element_count[6].font }, { "game.panel.element_7_count.element", &game.panel.element_count[6].id }, { "game.panel.element_7_count.draw_masked", &game.panel.element_count[6].draw_masked }, { "game.panel.element_7_count.draw_order", &game.panel.element_count[6].sort_priority }, { "game.panel.element_8.x", &game.panel.element[7].x }, { "game.panel.element_8.y", &game.panel.element[7].y }, { "game.panel.element_8.tile_size", &game.panel.element[7].size }, { "game.panel.element_8.element", &game.panel.element[7].id }, { "game.panel.element_8.draw_masked", &game.panel.element[7].draw_masked }, { "game.panel.element_8.draw_order", &game.panel.element[7].sort_priority }, { "game.panel.element_8_count.x", &game.panel.element_count[7].x }, { "game.panel.element_8_count.y", &game.panel.element_count[7].y }, { "game.panel.element_8_count.align", &game.panel.element_count[7].align }, { "game.panel.element_8_count.valign", &game.panel.element_count[7].valign }, { "game.panel.element_8_count.digits", &game.panel.element_count[7].size }, { "game.panel.element_8_count.font", &game.panel.element_count[7].font }, { "game.panel.element_8_count.element", &game.panel.element_count[7].id }, { "game.panel.element_8_count.draw_masked", &game.panel.element_count[7].draw_masked }, { "game.panel.element_8_count.draw_order", &game.panel.element_count[7].sort_priority }, { "game.panel.ce_score_1.x", &game.panel.ce_score[0].x }, { "game.panel.ce_score_1.y", &game.panel.ce_score[0].y }, { "game.panel.ce_score_1.align", &game.panel.ce_score[0].align }, { "game.panel.ce_score_1.valign", &game.panel.ce_score[0].valign }, { "game.panel.ce_score_1.digits", &game.panel.ce_score[0].size }, { "game.panel.ce_score_1.font", &game.panel.ce_score[0].font }, { "game.panel.ce_score_1.element", &game.panel.ce_score[0].id }, { "game.panel.ce_score_1.draw_masked", &game.panel.ce_score[0].draw_masked }, { "game.panel.ce_score_1.draw_order", &game.panel.ce_score[0].sort_priority }, { "game.panel.ce_score_1_element.x", &game.panel.ce_score_element[0].x }, { "game.panel.ce_score_1_element.y", &game.panel.ce_score_element[0].y }, { "game.panel.ce_score_1_element.tile_size", &game.panel.ce_score_element[0].size }, { "game.panel.ce_score_1_element.element", &game.panel.ce_score_element[0].id }, { "game.panel.ce_score_1_element.draw_masked", &game.panel.ce_score_element[0].draw_masked }, { "game.panel.ce_score_1_element.draw_order", &game.panel.ce_score_element[0].sort_priority }, { "game.panel.ce_score_2.x", &game.panel.ce_score[1].x }, { "game.panel.ce_score_2.y", &game.panel.ce_score[1].y }, { "game.panel.ce_score_2.align", &game.panel.ce_score[1].align }, { "game.panel.ce_score_2.valign", &game.panel.ce_score[1].valign }, { "game.panel.ce_score_2.digits", &game.panel.ce_score[1].size }, { "game.panel.ce_score_2.font", &game.panel.ce_score[1].font }, { "game.panel.ce_score_2.element", &game.panel.ce_score[1].id }, { "game.panel.ce_score_2.draw_masked", &game.panel.ce_score[1].draw_masked }, { "game.panel.ce_score_2.draw_order", &game.panel.ce_score[1].sort_priority }, { "game.panel.ce_score_2_element.x", &game.panel.ce_score_element[1].x }, { "game.panel.ce_score_2_element.y", &game.panel.ce_score_element[1].y }, { "game.panel.ce_score_2_element.tile_size", &game.panel.ce_score_element[1].size }, { "game.panel.ce_score_2_element.element", &game.panel.ce_score_element[1].id }, { "game.panel.ce_score_2_element.draw_masked", &game.panel.ce_score_element[1].draw_masked }, { "game.panel.ce_score_2_element.draw_order", &game.panel.ce_score_element[1].sort_priority }, { "game.panel.ce_score_3.x", &game.panel.ce_score[2].x }, { "game.panel.ce_score_3.y", &game.panel.ce_score[2].y }, { "game.panel.ce_score_3.align", &game.panel.ce_score[2].align }, { "game.panel.ce_score_3.valign", &game.panel.ce_score[2].valign }, { "game.panel.ce_score_3.digits", &game.panel.ce_score[2].size }, { "game.panel.ce_score_3.font", &game.panel.ce_score[2].font }, { "game.panel.ce_score_3.element", &game.panel.ce_score[2].id }, { "game.panel.ce_score_3.draw_masked", &game.panel.ce_score[2].draw_masked }, { "game.panel.ce_score_3.draw_order", &game.panel.ce_score[2].sort_priority }, { "game.panel.ce_score_3_element.x", &game.panel.ce_score_element[2].x }, { "game.panel.ce_score_3_element.y", &game.panel.ce_score_element[2].y }, { "game.panel.ce_score_3_element.tile_size", &game.panel.ce_score_element[2].size }, { "game.panel.ce_score_3_element.element", &game.panel.ce_score_element[2].id }, { "game.panel.ce_score_3_element.draw_masked", &game.panel.ce_score_element[2].draw_masked }, { "game.panel.ce_score_3_element.draw_order", &game.panel.ce_score_element[2].sort_priority }, { "game.panel.ce_score_4.x", &game.panel.ce_score[3].x }, { "game.panel.ce_score_4.y", &game.panel.ce_score[3].y }, { "game.panel.ce_score_4.align", &game.panel.ce_score[3].align }, { "game.panel.ce_score_4.valign", &game.panel.ce_score[3].valign }, { "game.panel.ce_score_4.digits", &game.panel.ce_score[3].size }, { "game.panel.ce_score_4.font", &game.panel.ce_score[3].font }, { "game.panel.ce_score_4.element", &game.panel.ce_score[3].id }, { "game.panel.ce_score_4.draw_masked", &game.panel.ce_score[3].draw_masked }, { "game.panel.ce_score_4.draw_order", &game.panel.ce_score[3].sort_priority }, { "game.panel.ce_score_4_element.x", &game.panel.ce_score_element[3].x }, { "game.panel.ce_score_4_element.y", &game.panel.ce_score_element[3].y }, { "game.panel.ce_score_4_element.tile_size", &game.panel.ce_score_element[3].size }, { "game.panel.ce_score_4_element.element", &game.panel.ce_score_element[3].id }, { "game.panel.ce_score_4_element.draw_masked", &game.panel.ce_score_element[3].draw_masked }, { "game.panel.ce_score_4_element.draw_order", &game.panel.ce_score_element[3].sort_priority }, { "game.panel.ce_score_5.x", &game.panel.ce_score[4].x }, { "game.panel.ce_score_5.y", &game.panel.ce_score[4].y }, { "game.panel.ce_score_5.align", &game.panel.ce_score[4].align }, { "game.panel.ce_score_5.valign", &game.panel.ce_score[4].valign }, { "game.panel.ce_score_5.digits", &game.panel.ce_score[4].size }, { "game.panel.ce_score_5.font", &game.panel.ce_score[4].font }, { "game.panel.ce_score_5.element", &game.panel.ce_score[4].id }, { "game.panel.ce_score_5.draw_masked", &game.panel.ce_score[4].draw_masked }, { "game.panel.ce_score_5.draw_order", &game.panel.ce_score[4].sort_priority }, { "game.panel.ce_score_5_element.x", &game.panel.ce_score_element[4].x }, { "game.panel.ce_score_5_element.y", &game.panel.ce_score_element[4].y }, { "game.panel.ce_score_5_element.tile_size", &game.panel.ce_score_element[4].size }, { "game.panel.ce_score_5_element.element", &game.panel.ce_score_element[4].id }, { "game.panel.ce_score_5_element.draw_masked", &game.panel.ce_score_element[4].draw_masked }, { "game.panel.ce_score_5_element.draw_order", &game.panel.ce_score_element[4].sort_priority }, { "game.panel.ce_score_6.x", &game.panel.ce_score[5].x }, { "game.panel.ce_score_6.y", &game.panel.ce_score[5].y }, { "game.panel.ce_score_6.align", &game.panel.ce_score[5].align }, { "game.panel.ce_score_6.valign", &game.panel.ce_score[5].valign }, { "game.panel.ce_score_6.digits", &game.panel.ce_score[5].size }, { "game.panel.ce_score_6.font", &game.panel.ce_score[5].font }, { "game.panel.ce_score_6.element", &game.panel.ce_score[5].id }, { "game.panel.ce_score_6.draw_masked", &game.panel.ce_score[5].draw_masked }, { "game.panel.ce_score_6.draw_order", &game.panel.ce_score[5].sort_priority }, { "game.panel.ce_score_6_element.x", &game.panel.ce_score_element[5].x }, { "game.panel.ce_score_6_element.y", &game.panel.ce_score_element[5].y }, { "game.panel.ce_score_6_element.tile_size", &game.panel.ce_score_element[5].size }, { "game.panel.ce_score_6_element.element", &game.panel.ce_score_element[5].id }, { "game.panel.ce_score_6_element.draw_masked", &game.panel.ce_score_element[5].draw_masked }, { "game.panel.ce_score_6_element.draw_order", &game.panel.ce_score_element[5].sort_priority }, { "game.panel.ce_score_7.x", &game.panel.ce_score[6].x }, { "game.panel.ce_score_7.y", &game.panel.ce_score[6].y }, { "game.panel.ce_score_7.align", &game.panel.ce_score[6].align }, { "game.panel.ce_score_7.valign", &game.panel.ce_score[6].valign }, { "game.panel.ce_score_7.digits", &game.panel.ce_score[6].size }, { "game.panel.ce_score_7.font", &game.panel.ce_score[6].font }, { "game.panel.ce_score_7.element", &game.panel.ce_score[6].id }, { "game.panel.ce_score_7.draw_masked", &game.panel.ce_score[6].draw_masked }, { "game.panel.ce_score_7.draw_order", &game.panel.ce_score[6].sort_priority }, { "game.panel.ce_score_7_element.x", &game.panel.ce_score_element[6].x }, { "game.panel.ce_score_7_element.y", &game.panel.ce_score_element[6].y }, { "game.panel.ce_score_7_element.tile_size", &game.panel.ce_score_element[6].size }, { "game.panel.ce_score_7_element.element", &game.panel.ce_score_element[6].id }, { "game.panel.ce_score_7_element.draw_masked", &game.panel.ce_score_element[6].draw_masked }, { "game.panel.ce_score_7_element.draw_order", &game.panel.ce_score_element[6].sort_priority }, { "game.panel.ce_score_8.x", &game.panel.ce_score[7].x }, { "game.panel.ce_score_8.y", &game.panel.ce_score[7].y }, { "game.panel.ce_score_8.align", &game.panel.ce_score[7].align }, { "game.panel.ce_score_8.valign", &game.panel.ce_score[7].valign }, { "game.panel.ce_score_8.digits", &game.panel.ce_score[7].size }, { "game.panel.ce_score_8.font", &game.panel.ce_score[7].font }, { "game.panel.ce_score_8.element", &game.panel.ce_score[7].id }, { "game.panel.ce_score_8.draw_masked", &game.panel.ce_score[7].draw_masked }, { "game.panel.ce_score_8.draw_order", &game.panel.ce_score[7].sort_priority }, { "game.panel.ce_score_8_element.x", &game.panel.ce_score_element[7].x }, { "game.panel.ce_score_8_element.y", &game.panel.ce_score_element[7].y }, { "game.panel.ce_score_8_element.tile_size", &game.panel.ce_score_element[7].size }, { "game.panel.ce_score_8_element.element", &game.panel.ce_score_element[7].id }, { "game.panel.ce_score_8_element.draw_masked", &game.panel.ce_score_element[7].draw_masked }, { "game.panel.ce_score_8_element.draw_order", &game.panel.ce_score_element[7].sort_priority }, { "game.panel.player_name.x", &game.panel.player_name.x }, { "game.panel.player_name.y", &game.panel.player_name.y }, { "game.panel.player_name.align", &game.panel.player_name.align }, { "game.panel.player_name.valign", &game.panel.player_name.valign }, { "game.panel.player_name.chars", &game.panel.player_name.size }, { "game.panel.player_name.font", &game.panel.player_name.font }, { "game.panel.player_name.draw_masked", &game.panel.player_name.draw_masked }, { "game.panel.player_name.draw_order", &game.panel.player_name.sort_priority }, { "game.panel.level_name.x", &game.panel.level_name.x }, { "game.panel.level_name.y", &game.panel.level_name.y }, { "game.panel.level_name.align", &game.panel.level_name.align }, { "game.panel.level_name.valign", &game.panel.level_name.valign }, { "game.panel.level_name.chars", &game.panel.level_name.size }, { "game.panel.level_name.font", &game.panel.level_name.font }, { "game.panel.level_name.draw_masked", &game.panel.level_name.draw_masked }, { "game.panel.level_name.draw_order", &game.panel.level_name.sort_priority }, { "game.panel.level_author.x", &game.panel.level_author.x }, { "game.panel.level_author.y", &game.panel.level_author.y }, { "game.panel.level_author.align", &game.panel.level_author.align }, { "game.panel.level_author.valign", &game.panel.level_author.valign }, { "game.panel.level_author.chars", &game.panel.level_author.size }, { "game.panel.level_author.font", &game.panel.level_author.font }, { "game.panel.level_author.draw_masked", &game.panel.level_author.draw_masked }, { "game.panel.level_author.draw_order", &game.panel.level_author.sort_priority }, { "game.button.stop.x", &game.button.stop.x }, { "game.button.stop.y", &game.button.stop.y }, { "game.button.pause.x", &game.button.pause.x }, { "game.button.pause.y", &game.button.pause.y }, { "game.button.play.x", &game.button.play.x }, { "game.button.play.y", &game.button.play.y }, { "game.button.undo.x", &game.button.undo.x }, { "game.button.undo.y", &game.button.undo.y }, { "game.button.redo.x", &game.button.redo.x }, { "game.button.redo.y", &game.button.redo.y }, { "game.button.save.x", &game.button.save.x }, { "game.button.save.y", &game.button.save.y }, { "game.button.pause2.x", &game.button.pause2.x }, { "game.button.pause2.y", &game.button.pause2.y }, { "game.button.load.x", &game.button.load.x }, { "game.button.load.y", &game.button.load.y }, { "game.button.sound_music.x", &game.button.sound_music.x }, { "game.button.sound_music.y", &game.button.sound_music.y }, { "game.button.sound_loops.x", &game.button.sound_loops.x }, { "game.button.sound_loops.y", &game.button.sound_loops.y }, { "game.button.sound_simple.x", &game.button.sound_simple.x }, { "game.button.sound_simple.y", &game.button.sound_simple.y }, { "game.button.panel_stop.x", &game.button.panel_stop.x }, { "game.button.panel_stop.y", &game.button.panel_stop.y }, { "game.button.panel_pause.x", &game.button.panel_pause.x }, { "game.button.panel_pause.y", &game.button.panel_pause.y }, { "game.button.panel_play.x", &game.button.panel_play.x }, { "game.button.panel_play.y", &game.button.panel_play.y }, { "game.button.panel_sound_music.x", &game.button.panel_sound_music.x }, { "game.button.panel_sound_music.y", &game.button.panel_sound_music.y }, { "game.button.panel_sound_loops.x", &game.button.panel_sound_loops.x }, { "game.button.panel_sound_loops.y", &game.button.panel_sound_loops.y }, { "game.button.panel_sound_simple.x", &game.button.panel_sound_simple.x }, { "game.button.panel_sound_simple.y", &game.button.panel_sound_simple.y }, { "tape.button.eject.x", &tape.button.eject.x }, { "tape.button.eject.y", &tape.button.eject.y }, { "tape.button.stop.x", &tape.button.stop.x }, { "tape.button.stop.y", &tape.button.stop.y }, { "tape.button.pause.x", &tape.button.pause.x }, { "tape.button.pause.y", &tape.button.pause.y }, { "tape.button.record.x", &tape.button.record.x }, { "tape.button.record.y", &tape.button.record.y }, { "tape.button.play.x", &tape.button.play.x }, { "tape.button.play.y", &tape.button.play.y }, { "tape.symbol.eject.x", &tape.symbol.eject.x }, { "tape.symbol.eject.y", &tape.symbol.eject.y }, { "tape.symbol.stop.x", &tape.symbol.stop.x }, { "tape.symbol.stop.y", &tape.symbol.stop.y }, { "tape.symbol.pause.x", &tape.symbol.pause.x }, { "tape.symbol.pause.y", &tape.symbol.pause.y }, { "tape.symbol.record.x", &tape.symbol.record.x }, { "tape.symbol.record.y", &tape.symbol.record.y }, { "tape.symbol.play.x", &tape.symbol.play.x }, { "tape.symbol.play.y", &tape.symbol.play.y }, { "tape.symbol.fast_forward.x", &tape.symbol.fast_forward.x }, { "tape.symbol.fast_forward.y", &tape.symbol.fast_forward.y }, { "tape.symbol.warp_forward.x", &tape.symbol.warp_forward.x }, { "tape.symbol.warp_forward.y", &tape.symbol.warp_forward.y }, { "tape.symbol.warp_forward_blind.x", &tape.symbol.warp_forward_blind.x }, { "tape.symbol.warp_forward_blind.y", &tape.symbol.warp_forward_blind.y }, { "tape.symbol.pause_before_end.x", &tape.symbol.pause_before_end.x }, { "tape.symbol.pause_before_end.y", &tape.symbol.pause_before_end.y }, { "tape.symbol.single_step.x", &tape.symbol.single_step.x }, { "tape.symbol.single_step.y", &tape.symbol.single_step.y }, { "tape.label.eject.x", &tape.label.eject.x }, { "tape.label.eject.y", &tape.label.eject.y }, { "tape.label.stop.x", &tape.label.stop.x }, { "tape.label.stop.y", &tape.label.stop.y }, { "tape.label.pause.x", &tape.label.pause.x }, { "tape.label.pause.y", &tape.label.pause.y }, { "tape.label.record.x", &tape.label.record.x }, { "tape.label.record.y", &tape.label.record.y }, { "tape.label.play.x", &tape.label.play.x }, { "tape.label.play.y", &tape.label.play.y }, { "tape.label.fast_forward.x", &tape.label.fast_forward.x }, { "tape.label.fast_forward.y", &tape.label.fast_forward.y }, { "tape.label.warp_forward.x", &tape.label.warp_forward.x }, { "tape.label.warp_forward.y", &tape.label.warp_forward.y }, { "tape.label.warp_forward_blind.x", &tape.label.warp_forward_blind.x }, { "tape.label.warp_forward_blind.y", &tape.label.warp_forward_blind.y }, { "tape.label.pause_before_end.x", &tape.label.pause_before_end.x }, { "tape.label.pause_before_end.y", &tape.label.pause_before_end.y }, { "tape.label.single_step.x", &tape.label.single_step.x }, { "tape.label.single_step.y", &tape.label.single_step.y }, { "tape.label.date.x", &tape.label.date.x }, { "tape.label.date.y", &tape.label.date.y }, { "tape.label.time.x", &tape.label.time.x }, { "tape.label.time.y", &tape.label.time.y }, { "tape.text.date.x", &tape.text.date.x }, { "tape.text.date.y", &tape.text.date.y }, { "tape.text.date.align", &tape.text.date.align }, { "tape.text.date.valign", &tape.text.date.valign }, { "tape.text.date.digits", &tape.text.date.size }, { "tape.text.date.xoffset", &tape.text.date.xoffset }, { "tape.text.date.2nd_xoffset", &tape.text.date.xoffset2 }, { "tape.text.date.font", &tape.text.date.font }, { "tape.text.date.draw_masked", &tape.text.date.draw_masked }, { "tape.text.date_yyyy.x", &tape.text.date_yyyy.x }, { "tape.text.date_yyyy.y", &tape.text.date_yyyy.y }, { "tape.text.date_yyyy.align", &tape.text.date_yyyy.align }, { "tape.text.date_yyyy.valign", &tape.text.date_yyyy.valign }, { "tape.text.date_yyyy.digits", &tape.text.date_yyyy.size }, { "tape.text.date_yyyy.font", &tape.text.date_yyyy.font }, { "tape.text.date_yyyy.draw_masked", &tape.text.date_yyyy.draw_masked }, { "tape.text.date_yy.x", &tape.text.date_yy.x }, { "tape.text.date_yy.y", &tape.text.date_yy.y }, { "tape.text.date_yy.align", &tape.text.date_yy.align }, { "tape.text.date_yy.valign", &tape.text.date_yy.valign }, { "tape.text.date_yy.digits", &tape.text.date_yy.size }, { "tape.text.date_yy.font", &tape.text.date_yy.font }, { "tape.text.date_yy.draw_masked", &tape.text.date_yy.draw_masked }, { "tape.text.date_mon.x", &tape.text.date_mon.x }, { "tape.text.date_mon.y", &tape.text.date_mon.y }, { "tape.text.date_mon.align", &tape.text.date_mon.align }, { "tape.text.date_mon.valign", &tape.text.date_mon.valign }, { "tape.text.date_mon.chars", &tape.text.date_mon.size }, { "tape.text.date_mon.font", &tape.text.date_mon.font }, { "tape.text.date_mon.draw_masked", &tape.text.date_mon.draw_masked }, { "tape.text.date_mm.x", &tape.text.date_mm.x }, { "tape.text.date_mm.y", &tape.text.date_mm.y }, { "tape.text.date_mm.align", &tape.text.date_mm.align }, { "tape.text.date_mm.valign", &tape.text.date_mm.valign }, { "tape.text.date_mm.digits", &tape.text.date_mm.size }, { "tape.text.date_mm.font", &tape.text.date_mm.font }, { "tape.text.date_mm.draw_masked", &tape.text.date_mm.draw_masked }, { "tape.text.date_dd.x", &tape.text.date_dd.x }, { "tape.text.date_dd.y", &tape.text.date_dd.y }, { "tape.text.date_dd.align", &tape.text.date_dd.align }, { "tape.text.date_dd.valign", &tape.text.date_dd.valign }, { "tape.text.date_dd.digits", &tape.text.date_dd.size }, { "tape.text.date_dd.font", &tape.text.date_dd.font }, { "tape.text.date_dd.draw_masked", &tape.text.date_dd.draw_masked }, { "tape.text.time.x", &tape.text.time.x }, { "tape.text.time.y", &tape.text.time.y }, { "tape.text.time.align", &tape.text.time.align }, { "tape.text.time.valign", &tape.text.time.valign }, { "tape.text.time.digits", &tape.text.time.size }, { "tape.text.time.xoffset", &tape.text.time.xoffset }, { "tape.text.time.font", &tape.text.time.font }, { "tape.text.time.draw_masked", &tape.text.time.draw_masked }, { "tape.text.time_hh.x", &tape.text.time_hh.x }, { "tape.text.time_hh.y", &tape.text.time_hh.y }, { "tape.text.time_hh.align", &tape.text.time_hh.align }, { "tape.text.time_hh.valign", &tape.text.time_hh.valign }, { "tape.text.time_hh.digits", &tape.text.time_hh.size }, { "tape.text.time_hh.font", &tape.text.time_hh.font }, { "tape.text.time_hh.draw_masked", &tape.text.time_hh.draw_masked }, { "tape.text.time_mm.x", &tape.text.time_mm.x }, { "tape.text.time_mm.y", &tape.text.time_mm.y }, { "tape.text.time_mm.align", &tape.text.time_mm.align }, { "tape.text.time_mm.valign", &tape.text.time_mm.valign }, { "tape.text.time_mm.digits", &tape.text.time_mm.size }, { "tape.text.time_mm.font", &tape.text.time_mm.font }, { "tape.text.time_mm.draw_masked", &tape.text.time_mm.draw_masked }, { "tape.text.time_ss.x", &tape.text.time_ss.x }, { "tape.text.time_ss.y", &tape.text.time_ss.y }, { "tape.text.time_ss.align", &tape.text.time_ss.align }, { "tape.text.time_ss.valign", &tape.text.time_ss.valign }, { "tape.text.time_ss.digits", &tape.text.time_ss.size }, { "tape.text.time_ss.font", &tape.text.time_ss.font }, { "tape.text.time_ss.draw_masked", &tape.text.time_ss.draw_masked }, { "tape.text.frame.x", &tape.text.frame.x }, { "tape.text.frame.y", &tape.text.frame.y }, { "tape.text.frame.align", &tape.text.frame.align }, { "tape.text.frame.valign", &tape.text.frame.valign }, { "tape.text.frame.digits", &tape.text.frame.size }, { "tape.text.frame.font", &tape.text.frame.font }, { "tape.text.frame.draw_masked", &tape.text.frame.draw_masked }, { "tape.show_game_buttons", &tape.show_game_buttons }, { "editor.button.prev_level.x", &editor.button.prev_level.x }, { "editor.button.prev_level.y", &editor.button.prev_level.y }, { "editor.button.next_level.x", &editor.button.next_level.x }, { "editor.button.next_level.y", &editor.button.next_level.y }, { "editor.button.properties.x", &editor.button.properties.x }, { "editor.button.properties.y", &editor.button.properties.y }, { "editor.button.element_left.x", &editor.button.element_left.x }, { "editor.button.element_left.y", &editor.button.element_left.y }, { "editor.button.element_left.tile_size", &editor.button.element_left.tile_size }, { "editor.button.element_middle.x", &editor.button.element_middle.x }, { "editor.button.element_middle.y", &editor.button.element_middle.y }, { "editor.button.element_middle.tile_size", &editor.button.element_middle.tile_size }, { "editor.button.element_right.x", &editor.button.element_right.x }, { "editor.button.element_right.y", &editor.button.element_right.y }, { "editor.button.element_right.tile_size", &editor.button.element_right.tile_size }, { "editor.button.palette.x", &editor.button.palette.x }, { "editor.button.palette.y", &editor.button.palette.y }, { "editor.button.draw_single.x", &editor.button.draw_single.x }, { "editor.button.draw_single.y", &editor.button.draw_single.y }, { "editor.button.draw_connected.x", &editor.button.draw_connected.x }, { "editor.button.draw_connected.y", &editor.button.draw_connected.y }, { "editor.button.draw_line.x", &editor.button.draw_line.x }, { "editor.button.draw_line.y", &editor.button.draw_line.y }, { "editor.button.draw_arc.x", &editor.button.draw_arc.x }, { "editor.button.draw_arc.y", &editor.button.draw_arc.y }, { "editor.button.draw_rectangle.x", &editor.button.draw_rectangle.x }, { "editor.button.draw_rectangle.y", &editor.button.draw_rectangle.y }, { "editor.button.draw_filled_box.x", &editor.button.draw_filled_box.x }, { "editor.button.draw_filled_box.y", &editor.button.draw_filled_box.y }, { "editor.button.rotate_up.x", &editor.button.rotate_up.x }, { "editor.button.rotate_up.y", &editor.button.rotate_up.y }, { "editor.button.draw_text.x", &editor.button.draw_text.x }, { "editor.button.draw_text.y", &editor.button.draw_text.y }, { "editor.button.flood_fill.x", &editor.button.flood_fill.x }, { "editor.button.flood_fill.y", &editor.button.flood_fill.y }, { "editor.button.rotate_left.x", &editor.button.rotate_left.x }, { "editor.button.rotate_left.y", &editor.button.rotate_left.y }, { "editor.button.zoom_level.x", &editor.button.zoom_level.x }, { "editor.button.zoom_level.y", &editor.button.zoom_level.y }, { "editor.button.rotate_right.x", &editor.button.rotate_right.x }, { "editor.button.rotate_right.y", &editor.button.rotate_right.y }, { "editor.button.draw_random.x", &editor.button.draw_random.x }, { "editor.button.draw_random.y", &editor.button.draw_random.y }, { "editor.button.grab_brush.x", &editor.button.grab_brush.x }, { "editor.button.grab_brush.y", &editor.button.grab_brush.y }, { "editor.button.rotate_down.x", &editor.button.rotate_down.x }, { "editor.button.rotate_down.y", &editor.button.rotate_down.y }, { "editor.button.pick_element.x", &editor.button.pick_element.x }, { "editor.button.pick_element.y", &editor.button.pick_element.y }, { "editor.button.ce_copy_from.x", &editor.button.ce_copy_from.x }, { "editor.button.ce_copy_from.y", &editor.button.ce_copy_from.y }, { "editor.button.ce_copy_to.x", &editor.button.ce_copy_to.x }, { "editor.button.ce_copy_to.y", &editor.button.ce_copy_to.y }, { "editor.button.ce_swap.x", &editor.button.ce_swap.x }, { "editor.button.ce_swap.y", &editor.button.ce_swap.y }, { "editor.button.ce_copy.x", &editor.button.ce_copy.x }, { "editor.button.ce_copy.y", &editor.button.ce_copy.y }, { "editor.button.ce_paste.x", &editor.button.ce_paste.x }, { "editor.button.ce_paste.y", &editor.button.ce_paste.y }, { "editor.button.undo.x", &editor.button.undo.x }, { "editor.button.undo.y", &editor.button.undo.y }, { "editor.button.conf.x", &editor.button.conf.x }, { "editor.button.conf.y", &editor.button.conf.y }, { "editor.button.save.x", &editor.button.save.x }, { "editor.button.save.y", &editor.button.save.y }, { "editor.button.clear.x", &editor.button.clear.x }, { "editor.button.clear.y", &editor.button.clear.y }, { "editor.button.test.x", &editor.button.test.x }, { "editor.button.test.y", &editor.button.test.y }, { "editor.button.exit.x", &editor.button.exit.x }, { "editor.button.exit.y", &editor.button.exit.y }, { "editor.input.level_number.x", &editor.input.level_number.x }, { "editor.input.level_number.y", &editor.input.level_number.y }, { "editor.palette.x", &editor.palette.x }, { "editor.palette.y", &editor.palette.y }, { "editor.palette.cols", &editor.palette.cols }, { "editor.palette.rows", &editor.palette.rows }, { "editor.palette.tile_size", &editor.palette.tile_size }, { "editor.palette.show_as_separate_screen", &editor.palette.show_as_separate_screen }, { "editor.palette.show_on_element_buttons", &editor.palette.show_on_element_buttons }, { "editor.palette.element_left.x", &editor.palette.element_left.x }, { "editor.palette.element_left.y", &editor.palette.element_left.y }, { "editor.palette.element_left.tile_size", &editor.palette.element_left.tile_size }, { "editor.palette.element_middle.x", &editor.palette.element_middle.x }, { "editor.palette.element_middle.y", &editor.palette.element_middle.y }, { "editor.palette.element_middle.tile_size", &editor.palette.element_middle.tile_size }, { "editor.palette.element_right.x", &editor.palette.element_right.x }, { "editor.palette.element_right.y", &editor.palette.element_right.y }, { "editor.palette.element_right.tile_size", &editor.palette.element_right.tile_size }, { "editor.drawingarea.tile_size", &editor.drawingarea.tile_size }, { "editor.settings.headline.x", &editor.settings.headline.x }, { "editor.settings.headline.y", &editor.settings.headline.y }, { "editor.settings.headline.align", &editor.settings.headline.align }, { "editor.settings.element_graphic.x", &editor.settings.element_graphic.x }, { "editor.settings.element_graphic.y", &editor.settings.element_graphic.y }, { "editor.settings.element_name.x", &editor.settings.element_name.x }, { "editor.settings.element_name.y", &editor.settings.element_name.y }, { "editor.settings.tabs.x", &editor.settings.tabs.x }, { "editor.settings.tabs.y", &editor.settings.tabs.y }, { "editor.settings.tabs.2nd_yoffset", &editor.settings.tabs.yoffset2 }, { "editor.settings.tabs.draw_xoffset", &editor.settings.tabs.draw_xoffset }, { "editor.settings.tabs.draw_yoffset", &editor.settings.tabs.draw_yoffset }, { "editor.settings.tooltip.x", &editor.settings.tooltip.x }, { "editor.settings.tooltip.y", &editor.settings.tooltip.y }, { "editor.gadget.normal_spacing", &editor.gadget.normal_spacing }, { "editor.gadget.small_spacing", &editor.gadget.small_spacing }, { "editor.gadget.tiny_spacing", &editor.gadget.tiny_spacing }, { "editor.gadget.line_spacing", &editor.gadget.line_spacing }, { "editor.gadget.text_spacing", &editor.gadget.text_spacing }, { "editor.gadget.separator_line.height", &editor.gadget.separator_line.height }, { "request.button.yes.x", &request.button.yes.x }, { "request.button.yes.y", &request.button.yes.y }, { "request.button.no.x", &request.button.no.x }, { "request.button.no.y", &request.button.no.y }, { "request.button.confirm.x", &request.button.confirm.x }, { "request.button.confirm.y", &request.button.confirm.y }, { "request.button.player_1.x", &request.button.player_1.x }, { "request.button.player_1.y", &request.button.player_1.y }, { "request.button.player_1.draw_player", &request.button.player_1.draw_player }, { "request.button.player_1.tile_size", &request.button.player_1.size }, { "request.button.player_2.x", &request.button.player_2.x }, { "request.button.player_2.y", &request.button.player_2.y }, { "request.button.player_2.draw_player", &request.button.player_2.draw_player }, { "request.button.player_2.tile_size", &request.button.player_2.size }, { "request.button.player_3.x", &request.button.player_3.x }, { "request.button.player_3.y", &request.button.player_3.y }, { "request.button.player_3.draw_player", &request.button.player_3.draw_player }, { "request.button.player_3.tile_size", &request.button.player_3.size }, { "request.button.player_4.x", &request.button.player_4.x }, { "request.button.player_4.y", &request.button.player_4.y }, { "request.button.player_4.draw_player", &request.button.player_4.draw_player }, { "request.button.player_4.tile_size", &request.button.player_4.size }, { "request.x", &request.x }, { "request.y", &request.y }, { "request.width", &request.width }, { "request.height", &request.height }, { "request.border_size", &request.border_size }, { "request.line_spacing", &request.line_spacing }, { "request.step_offset", &request.step_offset }, { "request.step_delay", &request.step_delay }, { "request.anim_mode", &request.anim_mode }, { "request.align", &request.align }, { "request.valign", &request.valign }, { "request.autowrap", &request.autowrap }, { "request.centered", &request.centered }, { "request.wrap_single_words", &request.wrap_single_words }, { "global.use_envelope_request", &global.use_envelope_request }, { "game.graphics_engine_version", &game.graphics_engine_version }, { "game.forced_scroll_delay_value", &game.forced_scroll_delay_value }, { "game.use_native_emc_graphics_engine", &game.use_native_emc_graphics_engine }, { "game.use_native_sp_graphics_engine", &game.use_native_sp_graphics_engine }, { "game.use_masked_pushing", &game.use_masked_pushing }, { "game.tile_size", &game.tile_size }, { "[player].boring_delay_fixed", &game.player_boring_delay_fixed }, { "[player].boring_delay_random", &game.player_boring_delay_random }, { "[player].sleeping_delay_fixed", &game.player_sleeping_delay_fixed }, { "[player].sleeping_delay_random", &game.player_sleeping_delay_random }, { "viewport.window.width", &viewport.window[GFX_SPECIAL_ARG_DEFAULT].width }, { "viewport.window.height", &viewport.window[GFX_SPECIAL_ARG_DEFAULT].height }, { "viewport.window.TITLE.width", &viewport.window[GFX_SPECIAL_ARG_TITLE].width }, { "viewport.window.TITLE.height", &viewport.window[GFX_SPECIAL_ARG_TITLE].height }, { "viewport.playfield.x", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].x }, { "viewport.playfield.y", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].y }, { "viewport.playfield.width", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].width }, { "viewport.playfield.height", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].height }, { "viewport.playfield.border_size", &viewport.playfield[GFX_SPECIAL_ARG_DEFAULT].border_size }, { "viewport.playfield.MAIN.x", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].x }, { "viewport.playfield.MAIN.y", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].y }, { "viewport.playfield.MAIN.width", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].width }, { "viewport.playfield.MAIN.height", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].height }, { "viewport.playfield.MAIN.border_size", &viewport.playfield[GFX_SPECIAL_ARG_MAIN].border_size }, { "viewport.playfield.SCORES.x", &viewport.playfield[GFX_SPECIAL_ARG_SCORES].x }, { "viewport.playfield.SCORES.y", &viewport.playfield[GFX_SPECIAL_ARG_SCORES].y }, { "viewport.playfield.SCORES.width", &viewport.playfield[GFX_SPECIAL_ARG_SCORES].width }, { "viewport.playfield.SCORES.height", &viewport.playfield[GFX_SPECIAL_ARG_SCORES].height }, { "viewport.playfield.SCORES.border_size", &viewport.playfield[GFX_SPECIAL_ARG_SCORES].border_size }, { "viewport.playfield.EDITOR.x", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].x }, { "viewport.playfield.EDITOR.y", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].y }, { "viewport.playfield.EDITOR.width", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].width }, { "viewport.playfield.EDITOR.height", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].height }, { "viewport.playfield.EDITOR.border_size", &viewport.playfield[GFX_SPECIAL_ARG_EDITOR].border_size }, { "viewport.playfield.PLAYING.x", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].x }, { "viewport.playfield.PLAYING.y", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].y }, { "viewport.playfield.PLAYING.width", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].width }, { "viewport.playfield.PLAYING.height", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].height }, { "viewport.playfield.PLAYING.border_size", &viewport.playfield[GFX_SPECIAL_ARG_PLAYING].border_size }, { "viewport.door_1.x", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].x }, { "viewport.door_1.y", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].y }, { "viewport.door_1.width", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].width }, { "viewport.door_1.height", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].height }, { "viewport.door_1.border_size", &viewport.door_1[GFX_SPECIAL_ARG_DEFAULT].border_size }, { "viewport.door_1.MAIN.x", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].x }, { "viewport.door_1.MAIN.y", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].y }, { "viewport.door_1.MAIN.width", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].width }, { "viewport.door_1.MAIN.height", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].height }, { "viewport.door_1.MAIN.border_size", &viewport.door_1[GFX_SPECIAL_ARG_MAIN].border_size }, { "viewport.door_1.SCORES.x", &viewport.door_1[GFX_SPECIAL_ARG_SCORES].x }, { "viewport.door_1.SCORES.y", &viewport.door_1[GFX_SPECIAL_ARG_SCORES].y }, { "viewport.door_1.SCORES.width", &viewport.door_1[GFX_SPECIAL_ARG_SCORES].width }, { "viewport.door_1.SCORES.height", &viewport.door_1[GFX_SPECIAL_ARG_SCORES].height }, { "viewport.door_1.SCORES.border_size", &viewport.door_1[GFX_SPECIAL_ARG_SCORES].border_size }, { "viewport.door_1.EDITOR.x", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].x }, { "viewport.door_1.EDITOR.y", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].y }, { "viewport.door_1.EDITOR.width", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].width }, { "viewport.door_1.EDITOR.height", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].height }, { "viewport.door_1.EDITOR.border_size", &viewport.door_1[GFX_SPECIAL_ARG_EDITOR].border_size }, { "viewport.door_1.PLAYING.x", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].x }, { "viewport.door_1.PLAYING.y", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].y }, { "viewport.door_1.PLAYING.width", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].width }, { "viewport.door_1.PLAYING.height", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].height }, { "viewport.door_1.PLAYING.border_size", &viewport.door_1[GFX_SPECIAL_ARG_PLAYING].border_size }, { "viewport.door_2.x", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].x }, { "viewport.door_2.y", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].y }, { "viewport.door_2.width", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].width }, { "viewport.door_2.height", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].height }, { "viewport.door_2.border_size", &viewport.door_2[GFX_SPECIAL_ARG_DEFAULT].border_size }, { "viewport.door_2.MAIN.x", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].x }, { "viewport.door_2.MAIN.y", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].y }, { "viewport.door_2.MAIN.width", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].width }, { "viewport.door_2.MAIN.height", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].height }, { "viewport.door_2.MAIN.border_size", &viewport.door_2[GFX_SPECIAL_ARG_MAIN].border_size }, { "viewport.door_2.SCORES.x", &viewport.door_2[GFX_SPECIAL_ARG_SCORES].x }, { "viewport.door_2.SCORES.y", &viewport.door_2[GFX_SPECIAL_ARG_SCORES].y }, { "viewport.door_2.SCORES.width", &viewport.door_2[GFX_SPECIAL_ARG_SCORES].width }, { "viewport.door_2.SCORES.height", &viewport.door_2[GFX_SPECIAL_ARG_SCORES].height }, { "viewport.door_2.SCORES.border_size", &viewport.door_2[GFX_SPECIAL_ARG_SCORES].border_size }, { "viewport.door_2.EDITOR.x", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].x }, { "viewport.door_2.EDITOR.y", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].y }, { "viewport.door_2.EDITOR.width", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].width }, { "viewport.door_2.EDITOR.height", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].height }, { "viewport.door_2.EDITOR.border_size", &viewport.door_2[GFX_SPECIAL_ARG_EDITOR].border_size }, { "viewport.door_2.PLAYING.x", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].x }, { "viewport.door_2.PLAYING.y", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].y }, { "viewport.door_2.PLAYING.width", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].width }, { "viewport.door_2.PLAYING.height", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].height }, { "viewport.door_2.PLAYING.border_size", &viewport.door_2[GFX_SPECIAL_ARG_PLAYING].border_size }, { NULL, NULL }, }; #endif /* CONF_VAR_C */ mirrormagic-3.0.0/src/screens.c0000644000175000017500000063404713263212010015734 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // screens.c // ============================================================================ #include "libgame/libgame.h" #include "screens.h" #include "events.h" #include "game.h" #include "tools.h" #include "editor.h" #include "files.h" #include "tape.h" #include "anim.h" #include "network.h" #include "init.h" #include "config.h" #define DEBUG_JOYSTICKS 0 /* screens on the info screen */ #define INFO_MODE_MAIN 0 #define INFO_MODE_TITLE 1 #define INFO_MODE_ELEMENTS 2 #define INFO_MODE_MUSIC 3 #define INFO_MODE_CREDITS 4 #define INFO_MODE_PROGRAM 5 #define INFO_MODE_VERSION 6 #define INFO_MODE_LEVELSET 7 #define MAX_INFO_MODES 8 /* screens on the setup screen */ /* (must match GFX_SPECIAL_ARG_SETUP_* values as defined in src/main.h) */ /* (should also match corresponding entries in src/conf_gfx.c) */ #define SETUP_MODE_MAIN 0 #define SETUP_MODE_GAME 1 #define SETUP_MODE_EDITOR 2 #define SETUP_MODE_GRAPHICS 3 #define SETUP_MODE_SOUND 4 #define SETUP_MODE_ARTWORK 5 #define SETUP_MODE_INPUT 6 #define SETUP_MODE_TOUCH 7 #define SETUP_MODE_SHORTCUTS 8 #define SETUP_MODE_SHORTCUTS_1 9 #define SETUP_MODE_SHORTCUTS_2 10 #define SETUP_MODE_SHORTCUTS_3 11 #define SETUP_MODE_SHORTCUTS_4 12 #define SETUP_MODE_SHORTCUTS_5 13 /* sub-screens on the setup screen (generic) */ #define SETUP_MODE_CHOOSE_ARTWORK 14 #define SETUP_MODE_CHOOSE_OTHER 15 /* sub-screens on the setup screen (specific) */ #define SETUP_MODE_CHOOSE_GAME_SPEED 16 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 17 #define SETUP_MODE_CHOOSE_SNAPSHOT_MODE 18 #define SETUP_MODE_CHOOSE_WINDOW_SIZE 19 #define SETUP_MODE_CHOOSE_SCALING_TYPE 20 #define SETUP_MODE_CHOOSE_RENDERING 21 #define SETUP_MODE_CHOOSE_GRAPHICS 22 #define SETUP_MODE_CHOOSE_SOUNDS 23 #define SETUP_MODE_CHOOSE_MUSIC 24 #define SETUP_MODE_CHOOSE_VOLUME_SIMPLE 25 #define SETUP_MODE_CHOOSE_VOLUME_LOOPS 26 #define SETUP_MODE_CHOOSE_VOLUME_MUSIC 27 #define SETUP_MODE_CHOOSE_TOUCH_CONTROL 28 #define SETUP_MODE_CHOOSE_MOVE_DISTANCE 29 #define SETUP_MODE_CHOOSE_DROP_DISTANCE 30 #define MAX_SETUP_MODES 31 #define MAX_MENU_MODES MAX(MAX_INFO_MODES, MAX_SETUP_MODES) /* setup screen titles */ #define STR_SETUP_MAIN "Setup" #define STR_SETUP_GAME "Game & Menu" #define STR_SETUP_EDITOR "Editor" #define STR_SETUP_GRAPHICS "Graphics" #define STR_SETUP_SOUND "Sound & Music" #define STR_SETUP_ARTWORK "Custom Artwork" #define STR_SETUP_INPUT "Input Devices" #define STR_SETUP_TOUCH "Touch Controls" #define STR_SETUP_SHORTCUTS "Key Shortcuts" #define STR_SETUP_EXIT "Exit" #define STR_SETUP_SAVE_AND_EXIT "Save and Exit" #define STR_SETUP_CHOOSE_GAME_SPEED "Game Speed" #define STR_SETUP_CHOOSE_SCROLL_DELAY "Scroll Delay" #define STR_SETUP_CHOOSE_SNAPSHOT_MODE "Snapshot Mode" #define STR_SETUP_CHOOSE_WINDOW_SIZE "Window Scaling" #define STR_SETUP_CHOOSE_SCALING_TYPE "Anti-Aliasing" #define STR_SETUP_CHOOSE_RENDERING "Rendering Mode" #define STR_SETUP_CHOOSE_VOLUME_SIMPLE "Sound Volume" #define STR_SETUP_CHOOSE_VOLUME_LOOPS "Loops Volume" #define STR_SETUP_CHOOSE_VOLUME_MUSIC "Music Volume" #define STR_SETUP_CHOOSE_TOUCH_CONTROL "Control Type" #define STR_SETUP_CHOOSE_MOVE_DISTANCE "Move Distance" #define STR_SETUP_CHOOSE_DROP_DISTANCE "Drop Distance" /* for input setup functions */ #define SETUPINPUT_SCREEN_POS_START 0 #define SETUPINPUT_SCREEN_POS_END (SCR_FIELDY - 4) #define SETUPINPUT_SCREEN_POS_EMPTY1 (SETUPINPUT_SCREEN_POS_START + 3) #define SETUPINPUT_SCREEN_POS_EMPTY2 (SETUPINPUT_SCREEN_POS_END - 1) #define MENU_SETUP_FONT_TITLE FONT_TEXT_1 #define MENU_SETUP_FONT_TEXT FONT_TITLE_2 /* for various menu stuff */ #define MENU_SCREEN_START_XPOS 1 #define MENU_SCREEN_START_YPOS 2 #define MENU_SCREEN_VALUE_XPOS (SCR_FIELDX - 3) #define MENU_SCREEN_MAX_XPOS (SCR_FIELDX - 1) #define MENU_TITLE1_YPOS 8 #define MENU_TITLE2_YPOS 46 #define MENU_INFO_FONT_TITLE FONT_TEXT_1 #define MENU_INFO_FONT_HEAD FONT_TEXT_2 #define MENU_INFO_FONT_TEXT FONT_TEXT_3 #define MENU_INFO_FONT_FOOT FONT_TEXT_4 #define MENU_INFO_SPACE_HEAD (menu.headline2_spacing_info[info_mode]) #define MENU_SCREEN_INFO_SPACE_LEFT (menu.left_spacing_info[info_mode]) #define MENU_SCREEN_INFO_SPACE_RIGHT (menu.right_spacing_info[info_mode]) #define MENU_SCREEN_INFO_SPACE_TOP (menu.top_spacing_info[info_mode]) #define MENU_SCREEN_INFO_SPACE_BOTTOM (menu.bottom_spacing_info[info_mode]) #define MENU_SCREEN_INFO_YSTART1 MENU_SCREEN_INFO_SPACE_TOP #define MENU_SCREEN_INFO_YSTART2 (MENU_SCREEN_INFO_YSTART1 + \ getMenuTextStep(MENU_INFO_SPACE_HEAD, \ MENU_INFO_FONT_TITLE)) #define MENU_SCREEN_INFO_YSTEP (TILEY + 4) #define MENU_SCREEN_INFO_YBOTTOM (SYSIZE - MENU_SCREEN_INFO_SPACE_BOTTOM) #define MENU_SCREEN_INFO_YSIZE (MENU_SCREEN_INFO_YBOTTOM - \ MENU_SCREEN_INFO_YSTART2 - \ TILEY / 2) #define MAX_INFO_ELEMENTS_ON_SCREEN 128 #define STD_INFO_ELEMENTS_ON_SCREEN (MENU_SCREEN_INFO_YSIZE / \ MENU_SCREEN_INFO_YSTEP) #define NUM_INFO_ELEMENTS_FROM_CONF \ (menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] > 0 ? \ menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] : \ MAX_MENU_ENTRIES_ON_SCREEN) #define NUM_INFO_ELEMENTS_ON_SCREEN MIN(MIN(STD_INFO_ELEMENTS_ON_SCREEN, \ MAX_INFO_ELEMENTS_ON_SCREEN), \ NUM_INFO_ELEMENTS_FROM_CONF) #define MAX_MENU_ENTRIES_ON_SCREEN (SCR_FIELDY - MENU_SCREEN_START_YPOS) #define MAX_MENU_TEXT_LENGTH_BIG 13 #define MAX_MENU_TEXT_LENGTH_MEDIUM (MAX_MENU_TEXT_LENGTH_BIG * 2) /* buttons and scrollbars identifiers */ #define SCREEN_CTRL_ID_PREV_LEVEL 0 #define SCREEN_CTRL_ID_NEXT_LEVEL 1 #define SCREEN_CTRL_ID_PREV_PLAYER 2 #define SCREEN_CTRL_ID_NEXT_PLAYER 3 #define SCREEN_CTRL_ID_SCROLL_UP 4 #define SCREEN_CTRL_ID_SCROLL_DOWN 5 #define SCREEN_CTRL_ID_SCROLL_VERTICAL 6 #define NUM_SCREEN_GADGETS 7 #define NUM_SCREEN_MENUBUTTONS 4 #define NUM_SCREEN_SCROLLBUTTONS 2 #define NUM_SCREEN_SCROLLBARS 1 #define SCREEN_MASK_MAIN (1 << 0) #define SCREEN_MASK_INPUT (1 << 1) /* graphic position and size values for buttons and scrollbars */ #define SC_MENUBUTTON_XSIZE TILEX #define SC_MENUBUTTON_YSIZE TILEY #define SC_SCROLLBUTTON_XSIZE TILEX #define SC_SCROLLBUTTON_YSIZE TILEY #define SC_SCROLLBAR_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE) #define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE #define SC_SCROLL_VERTICAL_YSIZE ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \ SC_SCROLLBUTTON_YSIZE) #define SC_SCROLL_UP_XPOS SC_SCROLLBAR_XPOS #define SC_SCROLL_UP_YPOS (2 * SC_SCROLLBUTTON_YSIZE) #define SC_SCROLL_VERTICAL_XPOS SC_SCROLLBAR_XPOS #define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + \ SC_SCROLLBUTTON_YSIZE) #define SC_SCROLL_DOWN_XPOS SC_SCROLLBAR_XPOS #define SC_SCROLL_DOWN_YPOS (SC_SCROLL_VERTICAL_YPOS + \ SC_SCROLL_VERTICAL_YSIZE) #define SC_BORDER_SIZE 14 /* forward declarations of internal functions */ static void HandleScreenGadgets(struct GadgetInfo *); static void HandleSetupScreen_Generic(int, int, int, int, int); static void HandleSetupScreen_Input(int, int, int, int, int); static void CustomizeKeyboard(int); static void ConfigureJoystick(int); static void execSetupGame(void); static void execSetupGraphics(void); static void execSetupSound(void); static void execSetupTouch(void); static void execSetupArtwork(void); static void HandleChooseTree(int, int, int, int, int, TreeInfo **); static void DrawChooseLevelSet(void); static void DrawChooseLevelNr(void); static void DrawInfoScreen(void); static void DrawSetupScreen(void); static void DrawInfoScreen_NotAvailable(char *, char *); static void DrawInfoScreen_HelpAnim(int, int, boolean); static void DrawInfoScreen_HelpText(int, int, int, int); static void HandleInfoScreen_Main(int, int, int, int, int); static void HandleInfoScreen_TitleScreen(int); static void HandleInfoScreen_Elements(int); static void HandleInfoScreen_Music(int); static void HandleInfoScreen_Credits(int); static void HandleInfoScreen_Program(int); static void HandleInfoScreen_Version(int); static void MapScreenMenuGadgets(int); static void MapScreenGadgets(int); static void MapScreenTreeGadgets(TreeInfo *); static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS]; static int info_mode = INFO_MODE_MAIN; static int setup_mode = SETUP_MODE_MAIN; static TreeInfo *window_sizes = NULL; static TreeInfo *window_size_current = NULL; static TreeInfo *scaling_types = NULL; static TreeInfo *scaling_type_current = NULL; static TreeInfo *rendering_modes = NULL; static TreeInfo *rendering_mode_current = NULL; static TreeInfo *scroll_delays = NULL; static TreeInfo *scroll_delay_current = NULL; static TreeInfo *snapshot_modes = NULL; static TreeInfo *snapshot_mode_current = NULL; static TreeInfo *game_speeds = NULL; static TreeInfo *game_speed_current = NULL; static TreeInfo *volumes_simple = NULL; static TreeInfo *volume_simple_current = NULL; static TreeInfo *volumes_loops = NULL; static TreeInfo *volume_loops_current = NULL; static TreeInfo *volumes_music = NULL; static TreeInfo *volume_music_current = NULL; static TreeInfo *touch_controls = NULL; static TreeInfo *touch_control_current = NULL; static TreeInfo *move_distances = NULL; static TreeInfo *move_distance_current = NULL; static TreeInfo *drop_distances = NULL; static TreeInfo *drop_distance_current = NULL; static TreeInfo *level_number = NULL; static TreeInfo *level_number_current = NULL; static struct { int value; char *text; } window_sizes_list[] = { { 50, "50 %" }, { 80, "80 %" }, { 90, "90 %" }, { 100, "100 % (Default)" }, { 110, "110 %" }, { 120, "120 %" }, { 130, "130 %" }, { 140, "140 %" }, { 150, "150 %" }, { 200, "200 %" }, { 250, "250 %" }, { 300, "300 %" }, { -1, NULL }, }; static struct { char *value; char *text; } scaling_types_list[] = { { SCALING_QUALITY_NEAREST, "Off" }, { SCALING_QUALITY_LINEAR, "Linear" }, { SCALING_QUALITY_BEST, "Anisotropic" }, { NULL, NULL }, }; static struct { char *value; char *text; } rendering_modes_list[] = { { STR_SPECIAL_RENDERING_OFF, "Off (May show artifacts, fast)" }, { STR_SPECIAL_RENDERING_BITMAP, "Bitmap/Texture mode (slower)" }, #if DEBUG // this mode may work under certain conditions, but does not work on Windows { STR_SPECIAL_RENDERING_TARGET, "Target Texture mode (slower)" }, #endif { STR_SPECIAL_RENDERING_DOUBLE, "Double Texture mode (slower)" }, { NULL, NULL }, }; static struct { int value; char *text; } game_speeds_list[] = { #if 1 { 30, "Very Slow" }, { 25, "Slow" }, { 20, "Normal" }, { 15, "Fast" }, { 10, "Very Fast" }, #else { 1000, "1/1s (Extremely Slow)" }, { 500, "1/2s" }, { 200, "1/5s" }, { 100, "1/10s" }, { 50, "1/20s" }, { 29, "1/35s (Original Supaplex)" }, { 25, "1/40s" }, { 20, "1/50s (Normal Speed)" }, { 14, "1/70s (Maximum Supaplex)" }, { 10, "1/100s" }, { 5, "1/200s" }, { 2, "1/500s" }, { 1, "1/1000s (Extremely Fast)" }, #endif { -1, NULL }, }; static struct { int value; char *text; } scroll_delays_list[] = { { 0, "0 Tiles (No Scroll Delay)" }, { 1, "1 Tile" }, { 2, "2 Tiles" }, { 3, "3 Tiles (Default)" }, { 4, "4 Tiles" }, { 5, "5 Tiles" }, { 6, "6 Tiles" }, { 7, "7 Tiles" }, { 8, "8 Tiles (Maximum Scroll Delay)"}, { -1, NULL }, }; static struct { char *value; char *text; } snapshot_modes_list[] = { { STR_SNAPSHOT_MODE_OFF, "Off" }, { STR_SNAPSHOT_MODE_EVERY_STEP, "Every Step" }, { STR_SNAPSHOT_MODE_EVERY_MOVE, "Every Move" }, { STR_SNAPSHOT_MODE_EVERY_COLLECT, "Every Collect" }, { NULL, NULL }, }; static struct { int value; char *text; } volumes_list[] = { { 0, "0 %" }, { 1, "1 %" }, { 2, "2 %" }, { 5, "5 %" }, { 10, "10 %" }, { 20, "20 %" }, { 30, "30 %" }, { 40, "40 %" }, { 50, "50 %" }, { 60, "60 %" }, { 70, "70 %" }, { 80, "80 %" }, { 90, "90 %" }, { 100, "100 %" }, { -1, NULL }, }; static struct { char *value; char *text; } touch_controls_list[] = { { TOUCH_CONTROL_OFF, "Off" }, { TOUCH_CONTROL_VIRTUAL_BUTTONS, "Virtual Buttons" }, { TOUCH_CONTROL_WIPE_GESTURES, "Wipe Gestures" }, { TOUCH_CONTROL_FOLLOW_FINGER, "Follow Finger" }, { NULL, NULL }, }; static struct { int value; char *text; } distances_list[] = { { 1, "1 %" }, { 2, "2 %" }, { 3, "3 %" }, { 4, "4 %" }, { 5, "5 %" }, { 10, "10 %" }, { 15, "15 %" }, { 20, "20 %" }, { 25, "25 %" }, { -1, NULL }, }; #define DRAW_MODE(s) ((s) >= GAME_MODE_MAIN && \ (s) <= GAME_MODE_SETUP ? (s) : \ (s) == GAME_MODE_PSEUDO_TYPENAME ? \ GAME_MODE_MAIN : GAME_MODE_DEFAULT) /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */ #define DRAW_MODE_INFO(i) ((i) >= INFO_MODE_TITLE && \ (i) <= INFO_MODE_LEVELSET ? (i) : \ INFO_MODE_MAIN) #define DRAW_MODE_SETUP(i) ((i) >= SETUP_MODE_MAIN && \ (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) : \ (i) >= SETUP_MODE_CHOOSE_GRAPHICS && \ (i) <= SETUP_MODE_CHOOSE_MUSIC ? \ SETUP_MODE_CHOOSE_ARTWORK : \ SETUP_MODE_CHOOSE_OTHER) #define DRAW_XOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ menu.draw_xoffset[GAME_MODE_INFO] : \ menu.draw_xoffset_info[DRAW_MODE_INFO(i)]) #define DRAW_YOFFSET_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ menu.draw_yoffset[GAME_MODE_INFO] : \ menu.draw_yoffset_info[DRAW_MODE_INFO(i)]) #define EXTRA_SPACING_INFO(i) (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \ menu.extra_spacing[GAME_MODE_INFO] : \ menu.extra_spacing_info[DRAW_MODE_INFO(i)]) #define DRAW_XOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.draw_xoffset[GAME_MODE_SETUP] : \ menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)]) #define DRAW_YOFFSET_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.draw_yoffset[GAME_MODE_SETUP] : \ menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)]) #define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \ menu.extra_spacing[GAME_MODE_SETUP] : \ menu.extra_spacing_setup[DRAW_MODE_SETUP(i)]) #define DRAW_XOFFSET(s) ((s) == GAME_MODE_INFO ? \ DRAW_XOFFSET_INFO(info_mode) : \ (s) == GAME_MODE_SETUP ? \ DRAW_XOFFSET_SETUP(setup_mode) : \ menu.draw_xoffset[DRAW_MODE(s)]) #define DRAW_YOFFSET(s) ((s) == GAME_MODE_INFO ? \ DRAW_YOFFSET_INFO(info_mode) : \ (s) == GAME_MODE_SETUP ? \ DRAW_YOFFSET_SETUP(setup_mode) : \ menu.draw_yoffset[DRAW_MODE(s)]) #define EXTRA_SPACING(s) ((s) == GAME_MODE_INFO ? \ EXTRA_SPACING_INFO(info_mode) : \ (s) == GAME_MODE_SETUP ? \ EXTRA_SPACING_SETUP(setup_mode) : \ menu.extra_spacing[DRAW_MODE(s)]) #define mSX (SX + DRAW_XOFFSET(game_status)) #define mSY (SY + DRAW_YOFFSET(game_status)) #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ? \ menu.list_size[game_status] : \ MAX_MENU_ENTRIES_ON_SCREEN) #define IN_VIS_MENU(x, y) IN_FIELD(x, y, SCR_FIELDX, \ NUM_MENU_ENTRIES_ON_SCREEN) /* title display and control definitions */ #define MAX_NUM_TITLE_SCREENS (2 * MAX_NUM_TITLE_IMAGES + \ 2 * MAX_NUM_TITLE_MESSAGES) #define NO_DIRECT_LEVEL_SELECT (-1) static int num_title_screens = 0; struct TitleControlInfo { boolean is_image; boolean initial; boolean first; int local_nr; int sort_priority; }; struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS]; /* main menu display and control definitions */ #define MAIN_CONTROL_NAME 0 #define MAIN_CONTROL_LEVELS 1 #define MAIN_CONTROL_SCORES 2 #define MAIN_CONTROL_EDITOR 3 #define MAIN_CONTROL_INFO 4 #define MAIN_CONTROL_GAME 5 #define MAIN_CONTROL_SETUP 6 #define MAIN_CONTROL_QUIT 7 #define MAIN_CONTROL_PREV_LEVEL 8 #define MAIN_CONTROL_NEXT_LEVEL 9 #define MAIN_CONTROL_FIRST_LEVEL 10 #define MAIN_CONTROL_LAST_LEVEL 11 #define MAIN_CONTROL_LEVEL_NUMBER 12 #define MAIN_CONTROL_LEVEL_INFO_1 13 #define MAIN_CONTROL_LEVEL_INFO_2 14 #define MAIN_CONTROL_LEVEL_NAME 15 #define MAIN_CONTROL_LEVEL_AUTHOR 16 #define MAIN_CONTROL_LEVEL_YEAR 17 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM 18 #define MAIN_CONTROL_LEVEL_IMPORTED_BY 19 #define MAIN_CONTROL_LEVEL_TESTED_BY 20 #define MAIN_CONTROL_TITLE_1 21 #define MAIN_CONTROL_TITLE_2 22 #define MAIN_CONTROL_TITLE_3 23 static char str_main_text_name[10]; static char str_main_text_first_level[10]; static char str_main_text_last_level[10]; static char str_main_text_level_number[10]; static char *main_text_name = str_main_text_name; static char *main_text_first_level = str_main_text_first_level; static char *main_text_last_level = str_main_text_last_level; static char *main_text_level_number = str_main_text_level_number; static char *main_text_levels = "Levelset"; static char *main_text_scores = "Hall Of Fame"; static char *main_text_editor = "Level Creator"; static char *main_text_info = "Info Screen"; static char *main_text_game = "Start Game"; static char *main_text_setup = "Setup"; static char *main_text_quit = "Quit"; static char *main_text_level_name = level.name; static char *main_text_level_author = level.author; static char *main_text_level_year = NULL; static char *main_text_level_imported_from = NULL; static char *main_text_level_imported_by = NULL; static char *main_text_level_tested_by = NULL; static char *main_text_title_1 = NULL; static char *main_text_title_2 = NULL; static char *main_text_title_3 = NULL; struct MainControlInfo { int nr; struct MenuPosInfo *pos_button; int button_graphic; struct TextPosInfo *pos_text; char **text; struct TextPosInfo *pos_input; char **input; }; static struct MainControlInfo main_controls[] = { { MAIN_CONTROL_NAME, &menu.main.button.name, IMG_MENU_BUTTON_NAME, &menu.main.text.name, &main_text_name, &menu.main.input.name, &setup.player_name, }, { MAIN_CONTROL_LEVELS, &menu.main.button.levels, IMG_MENU_BUTTON_LEVELS, &menu.main.text.levels, &main_text_levels, NULL, NULL, }, { MAIN_CONTROL_SCORES, &menu.main.button.scores, IMG_MENU_BUTTON_SCORES, &menu.main.text.scores, &main_text_scores, NULL, NULL, }, { MAIN_CONTROL_EDITOR, &menu.main.button.editor, IMG_MENU_BUTTON_EDITOR, &menu.main.text.editor, &main_text_editor, NULL, NULL, }, { MAIN_CONTROL_INFO, &menu.main.button.info, IMG_MENU_BUTTON_INFO, &menu.main.text.info, &main_text_info, NULL, NULL, }, { MAIN_CONTROL_GAME, &menu.main.button.game, IMG_MENU_BUTTON_GAME, &menu.main.text.game, &main_text_game, NULL, NULL, }, { MAIN_CONTROL_SETUP, &menu.main.button.setup, IMG_MENU_BUTTON_SETUP, &menu.main.text.setup, &main_text_setup, NULL, NULL, }, { MAIN_CONTROL_QUIT, &menu.main.button.quit, IMG_MENU_BUTTON_QUIT, &menu.main.text.quit, &main_text_quit, NULL, NULL, }, #if 0 /* (these two buttons are real gadgets) */ { MAIN_CONTROL_PREV_LEVEL, &menu.main.button.prev_level, IMG_MENU_BUTTON_PREV_LEVEL, NULL, NULL, NULL, NULL, }, { MAIN_CONTROL_NEXT_LEVEL, &menu.main.button.next_level, IMG_MENU_BUTTON_NEXT_LEVEL, NULL, NULL, NULL, NULL, }, #endif { MAIN_CONTROL_FIRST_LEVEL, NULL, -1, &menu.main.text.first_level, &main_text_first_level, NULL, NULL, }, { MAIN_CONTROL_LAST_LEVEL, NULL, -1, &menu.main.text.last_level, &main_text_last_level, NULL, NULL, }, { MAIN_CONTROL_LEVEL_NUMBER, NULL, -1, &menu.main.text.level_number, &main_text_level_number, NULL, NULL, }, { MAIN_CONTROL_LEVEL_INFO_1, NULL, -1, &menu.main.text.level_info_1, NULL, NULL, NULL, }, { MAIN_CONTROL_LEVEL_INFO_2, NULL, -1, &menu.main.text.level_info_2, NULL, NULL, NULL, }, { MAIN_CONTROL_LEVEL_NAME, NULL, -1, &menu.main.text.level_name, &main_text_level_name, NULL, NULL, }, { MAIN_CONTROL_LEVEL_AUTHOR, NULL, -1, &menu.main.text.level_author, &main_text_level_author, NULL, NULL, }, { MAIN_CONTROL_LEVEL_YEAR, NULL, -1, &menu.main.text.level_year, &main_text_level_year, NULL, NULL, }, { MAIN_CONTROL_LEVEL_IMPORTED_FROM, NULL, -1, &menu.main.text.level_imported_from, &main_text_level_imported_from, NULL, NULL, }, { MAIN_CONTROL_LEVEL_IMPORTED_BY, NULL, -1, &menu.main.text.level_imported_by, &main_text_level_imported_by, NULL, NULL, }, { MAIN_CONTROL_LEVEL_TESTED_BY, NULL, -1, &menu.main.text.level_tested_by, &main_text_level_tested_by, NULL, NULL, }, { MAIN_CONTROL_TITLE_1, NULL, -1, &menu.main.text.title_1, &main_text_title_1, NULL, NULL, }, { MAIN_CONTROL_TITLE_2, NULL, -1, &menu.main.text.title_2, &main_text_title_2, NULL, NULL, }, { MAIN_CONTROL_TITLE_3, NULL, -1, &menu.main.text.title_3, &main_text_title_3, NULL, NULL, }, { -1, NULL, -1, NULL, NULL, NULL, NULL, } }; static int getTitleScreenGraphic(int nr, boolean initial) { return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr; } static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial) { return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]); } #if 0 static int getTitleScreenGameMode(boolean initial) { return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); } #endif static int getTitleMessageGameMode(boolean initial) { return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); } static int getTitleAnimMode(struct TitleControlInfo *tci) { int base = (tci->initial ? GAME_MODE_TITLE_INITIAL_1 : GAME_MODE_TITLE_1); return base + tci->local_nr; } #if 0 static int getTitleScreenBackground(boolean initial) { return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE); } #endif #if 0 static int getTitleMessageBackground(int nr, boolean initial) { return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE); } #endif static int getTitleBackground(int nr, boolean initial, boolean is_image) { int base = (is_image ? (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 : IMG_BACKGROUND_TITLESCREEN_1) : (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 : IMG_BACKGROUND_TITLEMESSAGE_1)); int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE); int graphic_local = base + nr; if (graphic_info[graphic_local].bitmap != NULL) return graphic_local; if (graphic_info[graphic_global].bitmap != NULL) return graphic_global; return IMG_UNDEFINED; } static int getTitleSound(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; int initial = tci->initial; int nr = tci->local_nr; int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); int base = (is_image ? (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 : SND_BACKGROUND_TITLESCREEN_1) : (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 : SND_BACKGROUND_TITLEMESSAGE_1)); int sound_global = menu.sound[mode]; int sound_local = base + nr; #if 0 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n", nr, initial, is_image, sound_global, getSoundListEntry(sound_global)->filename, sound_local, getSoundListEntry(sound_local)->filename); #endif if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME)) return sound_local; if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME)) return sound_global; return SND_UNDEFINED; } static int getTitleMusic(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; int initial = tci->initial; int nr = tci->local_nr; int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE); int base = (is_image ? (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 : MUS_BACKGROUND_TITLESCREEN_1) : (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 : MUS_BACKGROUND_TITLEMESSAGE_1)); int music_global = menu.music[mode]; int music_local = base + nr; #if 0 printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n", nr, initial, is_image, music_global, getMusicListEntry(music_global)->filename, music_local, getMusicListEntry(music_local)->filename); #endif if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME)) return music_local; if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME)) return music_global; return MUS_UNDEFINED; } static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci) { boolean is_image = tci->is_image; boolean initial = tci->initial; boolean first = tci->first; int nr = tci->local_nr; struct TitleMessageInfo tmi; struct TitleFadingInfo ti; tmi = (is_image ? (initial ? (first ? titlescreen_initial_first[nr] : titlescreen_initial[nr]) : (first ? titlescreen_first[nr] : titlescreen[nr])) : (initial ? (first ? titlemessage_initial_first[nr] : titlemessage_initial[nr]) : (first ? titlemessage_first[nr] : titlemessage[nr]))); ti.fade_mode = tmi.fade_mode; ti.fade_delay = tmi.fade_delay; ti.post_delay = tmi.post_delay; ti.auto_delay = tmi.auto_delay; return ti; } static int compareTitleControlInfo(const void *object1, const void *object2) { const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1; const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2; int compare_result; if (tci1->initial != tci2->initial) compare_result = (tci1->initial ? -1 : +1); else if (tci1->sort_priority != tci2->sort_priority) compare_result = tci1->sort_priority - tci2->sort_priority; else if (tci1->is_image != tci2->is_image) compare_result = (tci1->is_image ? -1 : +1); else compare_result = tci1->local_nr - tci2->local_nr; return compare_result; } static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image, boolean initial, int nr, int sort_priority) { title_controls[num_title_screens].is_image = is_image; title_controls[num_title_screens].initial = initial; title_controls[num_title_screens].local_nr = nr; title_controls[num_title_screens].sort_priority = sort_priority; title_controls[num_title_screens].first = FALSE; /* will be set later */ num_title_screens++; } static void InitializeTitleControls_CheckTitleInfo(boolean initial) { int i; for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++) { int graphic = getTitleScreenGraphic(i, initial); Bitmap *bitmap = graphic_info[graphic].bitmap; int sort_priority = graphic_info[graphic].sort_priority; if (bitmap != NULL) InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority); } for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++) { struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial); char *filename = getLevelSetTitleMessageFilename(i, initial); int sort_priority = tmi->sort_priority; if (filename != NULL) InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority); } } static void InitializeTitleControls(boolean show_title_initial) { num_title_screens = 0; /* 1st step: initialize title screens for game start (only when starting) */ if (show_title_initial) InitializeTitleControls_CheckTitleInfo(TRUE); /* 2nd step: initialize title screens for current level set */ InitializeTitleControls_CheckTitleInfo(FALSE); /* sort title screens according to sort_priority and title number */ qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo), compareTitleControlInfo); /* mark first title screen */ title_controls[0].first = TRUE; } static boolean visibleMenuPos(struct MenuPosInfo *pos) { return (pos != NULL && pos->x != -1 && pos->y != -1); } static boolean visibleTextPos(struct TextPosInfo *pos) { return (pos != NULL && pos->x != -1 && pos->y != -1); } static void InitializeMainControls() { boolean local_team_mode = (!options.network && setup.team_mode); int i; /* set main control text values to dynamically determined values */ sprintf(main_text_name, "%s", local_team_mode ? "Team:" : "Name:"); strcpy(main_text_first_level, int2str(leveldir_current->first_level, menu.main.text.first_level.size)); strcpy(main_text_last_level, int2str(leveldir_current->last_level, menu.main.text.last_level.size)); strcpy(main_text_level_number, int2str(level_nr, menu.main.text.level_number.size)); main_text_level_year = leveldir_current->year; main_text_level_imported_from = leveldir_current->imported_from; main_text_level_imported_by = leveldir_current->imported_by; main_text_level_tested_by = leveldir_current->tested_by; main_text_title_1 = getConfigProgramTitleString(); main_text_title_2 = getConfigProgramCopyrightString(); main_text_title_3 = getConfigProgramCompanyString(); /* set main control screen positions to dynamically determined values */ for (i = 0; main_controls[i].nr != -1; i++) { struct MainControlInfo *mci = &main_controls[i]; int nr = mci->nr; struct MenuPosInfo *pos_button = mci->pos_button; struct TextPosInfo *pos_text = mci->pos_text; struct TextPosInfo *pos_input = mci->pos_input; char *text = (mci->text ? *mci->text : NULL); char *input = (mci->input ? *mci->input : NULL); int button_graphic = mci->button_graphic; int font_text = (pos_text ? pos_text->font : -1); int font_input = (pos_input ? pos_input->font : -1); int font_text_width = (font_text != -1 ? getFontWidth(font_text) : 0); int font_text_height = (font_text != -1 ? getFontHeight(font_text) : 0); int font_input_width = (font_input != -1 ? getFontWidth(font_input) : 0); int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0); int text_chars = (text != NULL ? strlen(text) : 0); int input_chars = (input != NULL ? strlen(input) : 0); int button_width = (button_graphic != -1 ? graphic_info[button_graphic].width : 0); int button_height = (button_graphic != -1 ? graphic_info[button_graphic].height : 0); int text_width = font_text_width * text_chars; int text_height = font_text_height; int input_width = font_input_width * input_chars; int input_height = font_input_height; if (nr == MAIN_CONTROL_NAME) { menu.main.input.name.width = input_width; menu.main.input.name.height = input_height; } if (pos_button != NULL) /* (x/y may be -1/-1 here) */ { pos_button->width = button_width; pos_button->height = button_height; } if (pos_text != NULL) /* (x/y may be -1/-1 here) */ { /* calculate size for non-clickable text -- needed for text alignment */ boolean calculate_text_size = (pos_button == NULL && text != NULL); if (pos_text->width == -1 || calculate_text_size) pos_text->width = text_width; if (pos_text->height == -1 || calculate_text_size) pos_text->height = text_height; if (visibleMenuPos(pos_button)) { if (pos_text->x == -1) pos_text->x = pos_button->x + pos_button->width; if (pos_text->y == -1) pos_text->y = pos_button->y + (pos_button->height - pos_text->height) / 2; } } if (pos_input != NULL) /* (x/y may be -1/-1 here) */ { if (visibleTextPos(pos_text)) { if (pos_input->x == -1) pos_input->x = pos_text->x + pos_text->width; if (pos_input->y == -1) pos_input->y = pos_text->y; } if (pos_input->width == -1) pos_input->width = input_width; if (pos_input->height == -1) pos_input->height = input_height; } } } static void DrawPressedGraphicThruMask(int dst_x, int dst_y, int graphic, boolean pressed) { struct GraphicInfo *g = &graphic_info[graphic]; Bitmap *src_bitmap; int src_x, src_y; int xoffset = (pressed ? g->pressed_xoffset : 0); int yoffset = (pressed ? g->pressed_yoffset : 0); getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset, g->width, g->height, dst_x, dst_y); } static void DrawCursorAndText_Main_Ext(int nr, boolean active_text, boolean active_input, boolean pressed_button) { int i; for (i = 0; main_controls[i].nr != -1; i++) { struct MainControlInfo *mci = &main_controls[i]; if (mci->nr == nr || nr == -1) { struct MenuPosInfo *pos_button = mci->pos_button; struct TextPosInfo *pos_text = mci->pos_text; struct TextPosInfo *pos_input = mci->pos_input; char *text = (mci->text ? *mci->text : NULL); char *input = (mci->input ? *mci->input : NULL); int button_graphic = mci->button_graphic; int font_text = (pos_text ? pos_text->font : -1); int font_input = (pos_input ? pos_input->font : -1); if (active_text) { button_graphic = BUTTON_ACTIVE(button_graphic); font_text = FONT_ACTIVE(font_text); } if (active_input) { font_input = FONT_ACTIVE(font_input); } if (visibleMenuPos(pos_button)) { struct MenuPosInfo *pos = pos_button; int x = mSX + pos->x; int y = mSY + pos->y; DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic); DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button); } if (visibleTextPos(pos_text) && text != NULL) { struct TextPosInfo *pos = pos_text; int x = mSX + ALIGNED_TEXT_XPOS(pos); int y = mSY + ALIGNED_TEXT_YPOS(pos); #if 1 /* (check why/if this is needed) */ DrawBackgroundForFont(x, y, pos->width, pos->height, font_text); #endif DrawText(x, y, text, font_text); } if (visibleTextPos(pos_input) && input != NULL) { struct TextPosInfo *pos = pos_input; int x = mSX + ALIGNED_TEXT_XPOS(pos); int y = mSY + ALIGNED_TEXT_YPOS(pos); #if 1 /* (check why/if this is needed) */ DrawBackgroundForFont(x, y, pos->width, pos->height, font_input); #endif DrawText(x, y, input, font_input); } } } } static void DrawCursorAndText_Main(int nr, boolean active_text, boolean pressed_button) { DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button); } #if 0 static void DrawCursorAndText_Main_Input(int nr, boolean active_text, boolean pressed_button) { DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button); } #endif static struct MainControlInfo *getMainControlInfo(int nr) { int i; for (i = 0; main_controls[i].nr != -1; i++) if (main_controls[i].nr == nr) return &main_controls[i]; return NULL; } static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y) { if (rect == NULL) return FALSE; int rect_x = ALIGNED_TEXT_XPOS(rect); int rect_y = ALIGNED_TEXT_YPOS(rect); return (x >= rect_x && x < rect_x + rect->width && y >= rect_y && y < rect_y + rect->height); } static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y) { if (rect == NULL) return FALSE; int rect_x = ALIGNED_TEXT_XPOS(rect); int rect_y = ALIGNED_TEXT_YPOS(rect); #if 0 printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n", x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height, (x >= rect_x && x < rect_x + rect->width && y >= rect_y && y < rect_y + rect->height)); #endif return (x >= rect_x && x < rect_x + rect->width && y >= rect_y && y < rect_y + rect->height); } static boolean insidePreviewRect(struct PreviewInfo *preview, int x, int y) { int rect_width = preview->xsize * preview->tile_size; int rect_height = preview->ysize * preview->tile_size; int rect_x = ALIGNED_XPOS(preview->x, rect_width, preview->align); int rect_y = ALIGNED_YPOS(preview->y, rect_height, preview->valign); return (x >= rect_x && x < rect_x + rect_width && y >= rect_y && y < rect_y + rect_height); } static void AdjustScrollbar(int id, int items_max, int items_visible, int item_position) { struct GadgetInfo *gi = screen_gadget[id]; if (item_position > items_max - items_visible) item_position = items_max - items_visible; ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END); } static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti) { AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN, first_entry); } static void clearMenuListArea() { int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset; /* correct scrollbar position if placed outside menu (playfield) area */ if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS) scrollbar_xpos = SX + SC_SCROLLBAR_XPOS; /* clear menu list area, but not title or scrollbar */ DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32, scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32); } static void drawCursorExt(int xpos, int ypos, boolean active, int graphic) { static int cursor_array[MAX_LEV_FIELDY]; int x = mSX + TILEX * xpos; int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos); if (xpos == 0) { if (graphic != -1) cursor_array[ypos] = graphic; else graphic = cursor_array[ypos]; } if (active) graphic = BUTTON_ACTIVE(graphic); DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic); DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0); } static void initCursor(int ypos, int graphic) { drawCursorExt(0, ypos, FALSE, graphic); } static void drawCursor(int ypos, boolean active) { drawCursorExt(0, ypos, active, -1); } static void drawCursorXY(int xpos, int ypos, int graphic) { drawCursorExt(xpos, ypos, FALSE, graphic); } static void drawChooseTreeCursor(int ypos, boolean active) { drawCursorExt(0, ypos, active, -1); } void DrawHeadline() { DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1); DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2); } void DrawTitleScreenImage(int nr, boolean initial) { int graphic = getTitleScreenGraphic(nr, initial); Bitmap *bitmap = graphic_info[graphic].bitmap; int width = graphic_info[graphic].width; int height = graphic_info[graphic].height; int src_x = graphic_info[graphic].src_x; int src_y = graphic_info[graphic].src_y; int dst_x, dst_y; if (bitmap == NULL) return; if (width > WIN_XSIZE) { /* image width too large for window => center image horizontally */ src_x = (width - WIN_XSIZE) / 2; width = WIN_XSIZE; } if (height > WIN_YSIZE) { /* image height too large for window => center image vertically */ src_y = (height - WIN_YSIZE) / 2; height = WIN_YSIZE; } /* always display title screens centered */ dst_x = (WIN_XSIZE - width) / 2; dst_y = (WIN_YSIZE - height) / 2; SetDrawBackgroundMask(REDRAW_ALL); SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE)); ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); if (DrawingOnBackground(dst_x, dst_y)) BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); redraw_mask = REDRAW_ALL; } void DrawTitleScreenMessage(int nr, boolean initial) { char *filename = getLevelSetTitleMessageFilename(nr, initial); struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial); if (filename == NULL) return; /* force TITLE font on title message screen */ SetFontStatus(getTitleMessageGameMode(initial)); /* if chars *and* width set to "-1", automatically determine width */ if (tmi->chars == -1 && tmi->width == -1) tmi->width = viewport.window[game_status].width; /* if lines *and* height set to "-1", automatically determine height */ if (tmi->lines == -1 && tmi->height == -1) tmi->height = viewport.window[game_status].height; /* if chars set to "-1", automatically determine by text and font width */ if (tmi->chars == -1) tmi->chars = tmi->width / getFontWidth(tmi->font); else tmi->width = tmi->chars * getFontWidth(tmi->font); /* if lines set to "-1", automatically determine by text and font height */ if (tmi->lines == -1) tmi->lines = tmi->height / getFontHeight(tmi->font); else tmi->height = tmi->lines * getFontHeight(tmi->font); /* if x set to "-1", automatically determine by width and alignment */ if (tmi->x == -1) tmi->x = -1 * ALIGNED_XPOS(0, tmi->width, tmi->align); /* if y set to "-1", automatically determine by height and alignment */ if (tmi->y == -1) tmi->y = -1 * ALIGNED_YPOS(0, tmi->height, tmi->valign); SetDrawBackgroundMask(REDRAW_ALL); SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE)); ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi), filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1, tmi->autowrap, tmi->centered, tmi->parse_comments); ResetFontStatus(); } void DrawTitleScreen() { KeyboardAutoRepeatOff(); HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE); } boolean CheckTitleScreen(boolean levelset_has_changed) { static boolean show_title_initial = TRUE; boolean show_titlescreen = FALSE; /* needed to be able to skip title screen, if no image or message defined */ InitializeTitleControls(show_title_initial); if (setup.show_titlescreen && (show_title_initial || levelset_has_changed)) show_titlescreen = TRUE; /* show initial title images and messages only once at program start */ show_title_initial = FALSE; return (show_titlescreen && num_title_screens > 0); } void DrawMainMenu() { static LevelDirTree *leveldir_last_valid = NULL; boolean levelset_has_changed = FALSE; int fade_mask = REDRAW_FIELD; LimitScreenUpdates(FALSE); FadeSetLeaveScreen(); /* do not fade out here -- function may continue and fade on editor screen */ UnmapAllGadgets(); FadeMenuSoundsAndMusic(); ExpireSoundLoops(FALSE); KeyboardAutoRepeatOn(); audio.sound_deactivated = FALSE; GetPlayerConfig(); /* needed if last screen was the playing screen, invoked from level editor */ if (level_editor_test_game) { CloseDoor(DOOR_CLOSE_ALL); SetGameStatus(GAME_MODE_EDITOR); DrawLevelEd(); return; } /* needed if last screen was the setup screen and fullscreen state changed */ // (moved to "execSetupGraphics()" to change fullscreen state directly) // ToggleFullscreenOrChangeWindowScalingIfNeeded(); /* leveldir_current may be invalid (level group, parent link) */ if (!validLevelSeries(leveldir_current)) leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid); if (leveldir_current != leveldir_last_valid) levelset_has_changed = TRUE; /* store valid level series information */ leveldir_last_valid = leveldir_current; init_last = init; /* switch to new busy animation */ /* needed if last screen (level choice) changed graphics, sounds or music */ ReloadCustomArtwork(0); if (CheckTitleScreen(levelset_has_changed)) { SetGameStatus(GAME_MODE_TITLE); DrawTitleScreen(); return; } if (redraw_mask & REDRAW_ALL) fade_mask = REDRAW_ALL; if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; FadeOut(fade_mask); /* needed if different viewport properties defined for menues */ ChangeViewportPropertiesIfNeeded(); SetDrawtoField(DRAW_TO_BACKBUFFER); /* level_nr may have been set to value over handicap with level editor */ if (setup.handicap && level_nr > leveldir_current->handicap_level) level_nr = leveldir_current->handicap_level; LoadLevel(level_nr); LoadScore(level_nr); SaveLevelSetup_SeriesInfo(); // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it) SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); SetMainBackgroundImage(IMG_BACKGROUND_MAIN); #if 0 if (fade_mask == REDRAW_ALL) RedrawGlobalBorder(); #endif ClearField(); InitializeMainControls(); DrawCursorAndText_Main(-1, FALSE, FALSE); DrawPreviewLevelInitial(); HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE); TapeStop(); if (TAPE_IS_EMPTY(tape)) LoadTape(level_nr); DrawCompleteVideoDisplay(); PlayMenuSoundsAndMusic(); /* create gadgets for main menu screen */ FreeScreenGadgets(); CreateScreenGadgets(); /* map gadgets for main menu screen */ MapTapeButtons(); MapScreenMenuGadgets(SCREEN_MASK_MAIN); /* copy actual game door content to door double buffer for OpenDoor() */ BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); FadeSetEnterMenu(); /* update screen area with special editor door */ redraw_mask |= REDRAW_ALL; BackToFront(); SetMouseCursor(CURSOR_DEFAULT); OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2); } static void gotoTopLevelDir() { /* move upwards until inside (but not above) top level directory */ while (leveldir_current->node_parent && !strEqual(leveldir_current->node_parent->subdir, STRING_TOP_DIRECTORY)) { /* write a "path" into level tree for easy navigation to last level */ if (leveldir_current->node_parent->node_group->cl_first == -1) { int num_leveldirs = numTreeInfoInGroup(leveldir_current); int leveldir_pos = posTreeInfo(leveldir_current); int num_page_entries; int cl_first, cl_cursor; if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN) num_page_entries = num_leveldirs; else num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; cl_first = MAX(0, leveldir_pos - num_page_entries + 1); cl_cursor = leveldir_pos - cl_first; leveldir_current->node_parent->node_group->cl_first = cl_first; leveldir_current->node_parent->node_group->cl_cursor = cl_cursor; } leveldir_current = leveldir_current->node_parent; } } void HandleTitleScreen(int mx, int my, int dx, int dy, int button) { static unsigned int title_delay = 0; static int title_screen_nr = 0; static int last_sound = -1, last_music = -1; boolean return_to_main_menu = FALSE; struct TitleControlInfo *tci; int sound, music; if (button == MB_MENU_INITIALIZE) { title_delay = 0; title_screen_nr = 0; tci = &title_controls[title_screen_nr]; SetAnimStatus(getTitleAnimMode(tci)); last_sound = SND_UNDEFINED; last_music = MUS_UNDEFINED; if (num_title_screens != 0) { FadeSetEnterScreen(); /* use individual title fading instead of global "enter screen" fading */ fading = getTitleFading(tci); } if (game_status_last_screen == GAME_MODE_INFO) { if (num_title_screens == 0) { /* switch game mode from title screen mode back to info screen mode */ SetGameStatus(GAME_MODE_INFO); /* store that last screen was info screen, not main menu screen */ game_status_last_screen = GAME_MODE_INFO; DrawInfoScreen_NotAvailable("Title screen information:", "No title screen for this level set."); return; } FadeMenuSoundsAndMusic(); } FadeOut(REDRAW_ALL); /* title screens may have different window size */ ChangeViewportPropertiesIfNeeded(); /* only required to update logic for redrawing global border */ ClearField(); if (tci->is_image) DrawTitleScreenImage(tci->local_nr, tci->initial); else DrawTitleScreenMessage(tci->local_nr, tci->initial); sound = getTitleSound(tci); music = getTitleMusic(tci); if (sound != last_sound) PlayMenuSoundExt(sound); if (music != last_music) PlayMenuMusicExt(music); last_sound = sound; last_music = music; SetMouseCursor(CURSOR_NONE); FadeIn(REDRAW_ALL); DelayReached(&title_delay, 0); /* reset delay counter */ return; } if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay)) button = MB_MENU_CHOICE; if (button == MB_MENU_LEAVE) { return_to_main_menu = TRUE; } else if (button == MB_MENU_CHOICE) { if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0) { SetGameStatus(GAME_MODE_INFO); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } title_screen_nr++; if (title_screen_nr < num_title_screens) { tci = &title_controls[title_screen_nr]; SetAnimStatus(getTitleAnimMode(tci)); sound = getTitleSound(tci); music = getTitleMusic(tci); if (last_sound != SND_UNDEFINED && sound != last_sound) FadeSound(last_sound); if (last_music != MUS_UNDEFINED && music != last_music) FadeMusic(); fading = getTitleFading(tci); FadeOut(REDRAW_ALL); if (tci->is_image) DrawTitleScreenImage(tci->local_nr, tci->initial); else DrawTitleScreenMessage(tci->local_nr, tci->initial); sound = getTitleSound(tci); music = getTitleMusic(tci); if (sound != last_sound) PlayMenuSoundExt(sound); if (music != last_music) PlayMenuMusicExt(music); last_sound = sound; last_music = music; FadeIn(REDRAW_ALL); DelayReached(&title_delay, 0); /* reset delay counter */ } else { FadeMenuSoundsAndMusic(); return_to_main_menu = TRUE; } } if (return_to_main_menu) { SetMouseCursor(CURSOR_DEFAULT); /* force full menu screen redraw after displaying title screens */ redraw_mask = REDRAW_ALL; if (game_status_last_screen == GAME_MODE_INFO) { SetGameStatus(GAME_MODE_INFO); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else /* default: return to main menu */ { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } } } void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr) { int old_level_nr = level_nr; int new_level_nr; if (selected_level_nr != NO_DIRECT_LEVEL_SELECT) new_level_nr = selected_level_nr; else new_level_nr = old_level_nr + step * direction; if (new_level_nr < leveldir_current->first_level) new_level_nr = leveldir_current->first_level; if (new_level_nr > leveldir_current->last_level) new_level_nr = leveldir_current->last_level; if (setup.handicap && new_level_nr > leveldir_current->handicap_level) { /* skipping levels is only allowed when trying to skip single level */ if (setup.skip_levels && new_level_nr == old_level_nr + 1 && Request("Level still unsolved! Skip despite handicap?", REQ_ASK)) { leveldir_current->handicap_level++; SaveLevelSetup_SeriesInfo(); } new_level_nr = leveldir_current->handicap_level; } if (new_level_nr != old_level_nr) { struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER); PlaySound(SND_MENU_ITEM_SELECTING); level_nr = new_level_nr; DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y, int2str(level_nr, menu.main.text.level_number.size), mci->pos_text->font); LoadLevel(level_nr); DrawPreviewLevelInitial(); TapeErase(); LoadTape(level_nr); DrawCompleteVideoDisplay(); SaveLevelSetup_SeriesInfo(); /* needed because DrawPreviewLevelInitial() takes some time */ BackToFront(); /* SyncDisplay(); */ } } void HandleMainMenu(int mx, int my, int dx, int dy, int button) { static int choice = MAIN_CONTROL_GAME; static boolean button_pressed_last = FALSE; boolean button_pressed = FALSE; int pos = choice; int i; if (button == MB_MENU_INITIALIZE) { DrawCursorAndText_Main(choice, TRUE, FALSE); return; } if (mx || my) /* mouse input */ { pos = -1; for (i = 0; main_controls[i].nr != -1; i++) { if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) || insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY) || insideTextPosRect(main_controls[i].pos_input, mx - mSX, my - mSY)) { pos = main_controls[i].nr; break; } } /* check if level preview was clicked */ if (insidePreviewRect(&preview, mx - SX, my - SY)) pos = MAIN_CONTROL_GAME; // handle pressed/unpressed state for active/inactive menu buttons // (if pos != -1, "i" contains index position corresponding to "pos") if (button && pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT && insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY)) button_pressed = TRUE; if (button_pressed != button_pressed_last) { DrawCursorAndText_Main(choice, TRUE, button_pressed); if (button_pressed) PlaySound(SND_MENU_BUTTON_PRESSING); else PlaySound(SND_MENU_BUTTON_RELEASING); } } else if (dx || dy) /* keyboard input */ { if (dx > 0 && (choice == MAIN_CONTROL_INFO || choice == MAIN_CONTROL_SETUP)) button = MB_MENU_CHOICE; else if (dy) pos = choice + dy; } if (pos == MAIN_CONTROL_FIRST_LEVEL && !button) { HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT); } else if (pos == MAIN_CONTROL_LAST_LEVEL && !button) { HandleMainMenu_SelectLevel(MAX_LEVELS, +1, NO_DIRECT_LEVEL_SELECT); } else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button) { CloseDoor(DOOR_CLOSE_2); SetGameStatus(GAME_MODE_LEVELNR); DrawChooseLevelNr(); } else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT) { if (button) { if (pos != choice) { PlaySound(SND_MENU_ITEM_ACTIVATING); DrawCursorAndText_Main(choice, FALSE, FALSE); DrawCursorAndText_Main(pos, TRUE, button_pressed); choice = pos; } else if (dx != 0) { if (choice != MAIN_CONTROL_INFO && choice != MAIN_CONTROL_SETUP) HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT); } } else { PlaySound(SND_MENU_ITEM_SELECTING); if (pos == MAIN_CONTROL_NAME) { SetGameStatus(GAME_MODE_PSEUDO_TYPENAME); HandleTypeName(strlen(setup.player_name), 0); } else if (pos == MAIN_CONTROL_LEVELS) { if (leveldir_first) { CloseDoor(DOOR_CLOSE_2); SetGameStatus(GAME_MODE_LEVELS); SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); if (setup.internal.choose_from_top_leveldir) gotoTopLevelDir(); DrawChooseLevelSet(); } } else if (pos == MAIN_CONTROL_SCORES) { CloseDoor(DOOR_CLOSE_2); SetGameStatus(GAME_MODE_SCORES); DrawHallOfFame(-1); } else if (pos == MAIN_CONTROL_EDITOR) { if (leveldir_current->readonly && !strEqual(setup.player_name, "Artsoft")) Request("This level is read only!", REQ_CONFIRM); CloseDoor(DOOR_CLOSE_2); SetGameStatus(GAME_MODE_EDITOR); FadeSetEnterScreen(); DrawLevelEd(); } else if (pos == MAIN_CONTROL_INFO) { CloseDoor(DOOR_CLOSE_2); SetGameStatus(GAME_MODE_INFO); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else if (pos == MAIN_CONTROL_GAME) { StartGameActions(options.network, setup.autorecord, level.random_seed); } else if (pos == MAIN_CONTROL_SETUP) { CloseDoor(DOOR_CLOSE_2); SetGameStatus(GAME_MODE_SETUP); setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } else if (pos == MAIN_CONTROL_QUIT) { SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED)) SetGameStatus(GAME_MODE_QUIT); } } } button_pressed_last = button_pressed; } /* ========================================================================= */ /* info screen functions */ /* ========================================================================= */ static struct TokenInfo *info_info; static int num_info_info; /* number of info entries shown on screen */ static int max_info_info; /* total number of info entries in list */ static void execInfoTitleScreen() { info_mode = INFO_MODE_TITLE; DrawInfoScreen(); } static void execInfoElements() { info_mode = INFO_MODE_ELEMENTS; DrawInfoScreen(); } static void execInfoMusic() { info_mode = INFO_MODE_MUSIC; DrawInfoScreen(); } static void execInfoCredits() { info_mode = INFO_MODE_CREDITS; DrawInfoScreen(); } static void execInfoProgram() { info_mode = INFO_MODE_PROGRAM; DrawInfoScreen(); } static void execInfoVersion() { info_mode = INFO_MODE_VERSION; DrawInfoScreen(); } static void execInfoLevelSet() { info_mode = INFO_MODE_LEVELSET; DrawInfoScreen(); } static void execExitInfo() { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } static struct TokenInfo info_info_main[] = { { TYPE_ENTER_SCREEN, execInfoTitleScreen, "Title Screen" }, { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" }, { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" }, { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" }, { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" }, { TYPE_ENTER_SCREEN, execInfoVersion, "Version Info" }, { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execExitInfo, "Exit" }, { 0, NULL, NULL } }; static int getMenuTextFont(int type) { if (type & (TYPE_SWITCH | TYPE_YES_NO | TYPE_YES_NO_AUTO | TYPE_STRING | TYPE_ECS_AGA | TYPE_KEYTEXT | TYPE_ENTER_LIST)) return FONT_MENU_2; else return FONT_MENU_1; } static struct TokenInfo *setup_info; static struct TokenInfo setup_info_input[]; static struct TokenInfo *menu_info; static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info, int screen_pos, int menu_info_pos_raw, boolean active) { int pos = (menu_info_pos_raw < 0 ? screen_pos : menu_info_pos_raw); struct TokenInfo *ti = &token_info[pos]; int xpos = MENU_SCREEN_START_XPOS; int ypos = MENU_SCREEN_START_YPOS + screen_pos; int font_nr = getMenuTextFont(ti->type); if (token_info == setup_info_input) font_nr = FONT_MENU_1; if (active) font_nr = FONT_ACTIVE(font_nr); DrawText(mSX + xpos * 32, mSY + ypos * 32, ti->text, font_nr); if (ti->type & ~TYPE_SKIP_ENTRY) drawCursor(screen_pos, active); } static void DrawCursorAndText_Menu(int screen_pos, int menu_info_pos_raw, boolean active) { DrawCursorAndText_Menu_Ext(menu_info, screen_pos, menu_info_pos_raw, active); } static void DrawCursorAndText_Setup(int screen_pos, int menu_info_pos_raw, boolean active) { DrawCursorAndText_Menu_Ext(setup_info, screen_pos, menu_info_pos_raw, active); } static char *window_size_text; static char *scaling_type_text; static void drawSetupValue(int, int); static void drawMenuInfoList(int first_entry, int num_page_entries, int max_page_entries) { int i; if (first_entry + num_page_entries > max_page_entries) first_entry = 0; clearMenuListArea(); for (i = 0; i < num_page_entries; i++) { int menu_info_pos = first_entry + i; struct TokenInfo *si = &menu_info[menu_info_pos]; void *value_ptr = si->value; /* set some entries to "unchangeable" according to other variables */ if ((value_ptr == &setup.sound_simple && !audio.sound_available) || (value_ptr == &setup.sound_loops && !audio.loops_available) || (value_ptr == &setup.sound_music && !audio.music_available) || (value_ptr == &setup.fullscreen && !video.fullscreen_available) || (value_ptr == &window_size_text && !video.window_scaling_available) || (value_ptr == &scaling_type_text && !video.window_scaling_available)) si->type |= TYPE_GHOSTED; if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (si->type & ~TYPE_SKIP_ENTRY) initCursor(i, IMG_MENU_BUTTON); DrawCursorAndText_Menu(i, menu_info_pos, FALSE); if (si->type & TYPE_VALUE && menu_info == setup_info) drawSetupValue(i, menu_info_pos); } } static void DrawInfoScreen_Main() { int fade_mask = REDRAW_FIELD; int i; if (redraw_mask & REDRAW_ALL) fade_mask = REDRAW_ALL; if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; UnmapAllGadgets(); FadeMenuSoundsAndMusic(); FreeScreenGadgets(); CreateScreenGadgets(); /* (needed after displaying title screens which disable auto repeat) */ KeyboardAutoRepeatOn(); FadeSetLeaveScreen(); FadeOut(fade_mask); /* needed if different viewport properties defined for info screen */ ChangeViewportPropertiesIfNeeded(); SetMainBackgroundImage(IMG_BACKGROUND_INFO); ClearField(); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen"); info_info = info_info_main; // determine maximal number of info entries that can be displayed on screen num_info_info = 0; for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) num_info_info++; // determine maximal number of info entries available for menu of info screen max_info_info = 0; for (i = 0; info_info[i].type != 0; i++) max_info_info++; HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE); MapScreenGadgets(max_info_info); PlayMenuSoundsAndMusic(); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); } static void changeSetupValue(int, int, int); void HandleMenuScreen(int mx, int my, int dx, int dy, int button, int mode, int num_page_entries, int max_page_entries) { static int num_page_entries_all_last[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES]; static int choice_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES]; static int first_entry_stores[NUM_SPECIAL_GFX_ARGS][MAX_MENU_MODES]; int *num_page_entries_last = num_page_entries_all_last[game_status]; int *choice_store = choice_stores[game_status]; int *first_entry_store = first_entry_stores[game_status]; int choice = choice_store[mode]; /* starts with 0 */ int first_entry = first_entry_store[mode]; /* starts with 0 */ int x = 0; int y = choice - first_entry; int y_old = y; boolean position_set_by_scrollbar = (dx == 999); int step = (button == 1 ? 1 : button == 2 ? 5 : 10); int i; if (button == MB_MENU_INITIALIZE) { // check if number of menu page entries has changed (may happen by change // of custom artwork definition value for 'list_size' for this menu screen) // (in this case, the last menu position most probably has to be corrected) if (num_page_entries != num_page_entries_last[mode]) { choice_store[mode] = first_entry_store[mode] = 0; choice = first_entry = 0; y = y_old = 0; num_page_entries_last[mode] = num_page_entries; } /* advance to first valid menu entry */ while (choice < num_page_entries && menu_info[choice].type & TYPE_SKIP_ENTRY) choice++; if (position_set_by_scrollbar) first_entry = first_entry_store[mode] = dy; else AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries, NUM_MENU_ENTRIES_ON_SCREEN, first_entry); drawMenuInfoList(first_entry, num_page_entries, max_page_entries); if (choice < first_entry) { choice = first_entry; if (menu_info[choice].type & TYPE_SKIP_ENTRY) choice++; } else if (choice > first_entry + num_page_entries - 1) { choice = first_entry + num_page_entries - 1; if (menu_info[choice].type & TYPE_SKIP_ENTRY) choice--; } choice_store[mode] = choice; DrawCursorAndText_Menu(choice - first_entry, choice, TRUE); return; } else if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); for (i = 0; i < max_page_entries; i++) { if (menu_info[i].type & TYPE_LEAVE_MENU) { void (*menu_callback_function)(void) = menu_info[i].value; FadeSetLeaveMenu(); menu_callback_function(); break; /* absolutely needed because function changes 'menu_info'! */ } } return; } if (mx || my) /* mouse input */ { x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */ { /* move cursor instead of scrolling when already at start/end of list */ if (dy == -1 * SCROLL_LINE && first_entry == 0) dy = -1; else if (dy == +1 * SCROLL_LINE && first_entry + num_page_entries == max_page_entries) dy = 1; /* handle scrolling screen one line or page */ if (y + dy < 0 || y + dy > num_page_entries - 1) { boolean redraw = FALSE; if (ABS(dy) == SCROLL_PAGE) step = num_page_entries - 1; if (dy < 0 && first_entry > 0) { /* scroll page/line up */ first_entry -= step; if (first_entry < 0) first_entry = 0; redraw = TRUE; } else if (dy > 0 && first_entry + num_page_entries < max_page_entries) { /* scroll page/line down */ first_entry += step; if (first_entry + num_page_entries > max_page_entries) first_entry = MAX(0, max_page_entries - num_page_entries); redraw = TRUE; } if (redraw) { choice += first_entry - first_entry_store[mode]; if (choice < first_entry) { choice = first_entry; if (menu_info[choice].type & TYPE_SKIP_ENTRY) choice++; } else if (choice > first_entry + num_page_entries - 1) { choice = first_entry + num_page_entries - 1; if (menu_info[choice].type & TYPE_SKIP_ENTRY) choice--; } else if (menu_info[choice].type & TYPE_SKIP_ENTRY) { choice += SIGN(dy); if (choice < first_entry || choice > first_entry + num_page_entries - 1) first_entry += SIGN(dy); } first_entry_store[mode] = first_entry; choice_store[mode] = choice; drawMenuInfoList(first_entry, num_page_entries, max_page_entries); DrawCursorAndText_Menu(choice - first_entry, choice, TRUE); AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries, NUM_MENU_ENTRIES_ON_SCREEN, first_entry); } return; } if (dx) { int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER); if (menu_info[choice].type & menu_navigation_type || menu_info[choice].type & TYPE_BOOLEAN_STYLE || menu_info[choice].type & TYPE_YES_NO_AUTO) button = MB_MENU_CHOICE; } else if (dy) y += dy; /* jump to next non-empty menu entry (up or down) */ while (first_entry + y > 0 && first_entry + y < max_page_entries - 1 && menu_info[first_entry + y].type & TYPE_SKIP_ENTRY) y += dy; if (!IN_VIS_MENU(x, y)) { choice += y - y_old; if (choice < first_entry) first_entry = choice; else if (choice > first_entry + num_page_entries - 1) first_entry = choice - num_page_entries + 1; if (first_entry >= 0 && first_entry + num_page_entries <= max_page_entries) { first_entry_store[mode] = first_entry; if (choice < first_entry) choice = first_entry; else if (choice > first_entry + num_page_entries - 1) choice = first_entry + num_page_entries - 1; choice_store[mode] = choice; drawMenuInfoList(first_entry, num_page_entries, max_page_entries); DrawCursorAndText_Menu(choice - first_entry, choice, TRUE); AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_page_entries, NUM_MENU_ENTRIES_ON_SCREEN, first_entry); } return; } } if (!anyScrollbarGadgetActive() && IN_VIS_MENU(x, y) && mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x && y >= 0 && y < num_page_entries) { if (button) { if (first_entry + y != choice && menu_info[first_entry + y].type & ~TYPE_SKIP_ENTRY) { PlaySound(SND_MENU_ITEM_ACTIVATING); DrawCursorAndText_Menu(choice - first_entry, choice, FALSE); DrawCursorAndText_Menu(y, first_entry + y, TRUE); choice = choice_store[mode] = first_entry + y; } else if (dx < 0) { PlaySound(SND_MENU_ITEM_SELECTING); for (i = 0; menu_info[i].type != 0; i++) { if (menu_info[i].type & TYPE_LEAVE_MENU) { void (*menu_callback_function)(void) = menu_info[i].value; FadeSetLeaveMenu(); menu_callback_function(); /* absolutely needed because function changes 'menu_info'! */ break; } } return; } } else if (!(menu_info[first_entry + y].type & TYPE_GHOSTED)) { PlaySound(SND_MENU_ITEM_SELECTING); /* when selecting key headline, execute function for key value change */ if (menu_info[first_entry + y].type & TYPE_KEYTEXT && menu_info[first_entry + y + 1].type & TYPE_KEY) y++; /* when selecting string value, execute function for list selection */ if (menu_info[first_entry + y].type & TYPE_STRING && y > 0 && menu_info[first_entry + y - 1].type & TYPE_ENTER_LIST) y--; if (menu_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE) { void (*menu_callback_function)(void) = menu_info[first_entry + y].value; FadeSetFromType(menu_info[first_entry + y].type); menu_callback_function(); } else if (menu_info[first_entry + y].type & TYPE_VALUE && menu_info == setup_info) { changeSetupValue(y, first_entry + y, dx); } } } } void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button) { menu_info = info_info; HandleMenuScreen(mx, my, dx, dy, button, info_mode, num_info_info, max_info_info); } static int getMenuFontSpacing(int spacing_height, int font_nr) { int font_spacing = getFontHeight(font_nr) + EXTRA_SPACING(game_status); return (spacing_height < 0 ? ABS(spacing_height) * font_spacing : spacing_height); } static int getMenuTextSpacing(int spacing_height, int font_nr) { return (getMenuFontSpacing(spacing_height, font_nr) + EXTRA_SPACING(game_status)); } static int getMenuTextStep(int spacing_height, int font_nr) { return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr); } void DrawInfoScreen_NotAvailable(char *text_title, char *text_error) { int font_title = MENU_INFO_FONT_TITLE; int font_error = FONT_TEXT_2; int font_foot = MENU_INFO_FONT_FOOT; int spacing_title = menu.headline1_spacing_info[info_mode]; int ystep_title = getMenuTextStep(spacing_title, font_title); int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ystart2 = ystart1 + ystep_title; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO); FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, font_title, text_title); DrawTextSCentered(ystart2, font_error, text_error); DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); } void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init) { static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN]; static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN]; int font_title = MENU_INFO_FONT_TITLE; int font_foot = MENU_INFO_FONT_FOOT; int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT; int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; int ystep = MENU_SCREEN_INFO_YSTEP; int element, action, direction; int graphic; int delay; int sync_frame; int i, j; if (init) { for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++) infoscreen_step[i] = infoscreen_frame[i] = 0; ClearField(); DrawHeadline(); DrawTextSCentered(ystart1, font_title, "The Game Elements:"); DrawTextSCentered(ybottom, font_foot, "Press any key or button for next page"); FrameCounter = 0; } i = j = 0; while (helpanim_info[j].element != HELPANIM_LIST_END) { if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN || i >= max_anims) break; else if (i < start) { while (helpanim_info[j].element != HELPANIM_LIST_NEXT) j++; j++; i++; continue; } j += infoscreen_step[i - start]; element = helpanim_info[j].element; action = helpanim_info[j].action; direction = helpanim_info[j].direction; if (element < 0) element = EL_UNKNOWN; if (action != -1 && direction != -1) graphic = el_act_dir2img(element, action, direction); else if (action != -1) graphic = el_act2img(element, action); else if (direction != -1) graphic = el_dir2img(element, direction); else graphic = el2img(element); delay = helpanim_info[j++].delay; if (delay == -1) delay = 1000000; if (infoscreen_frame[i - start] == 0) { sync_frame = 0; infoscreen_frame[i - start] = delay - 1; } else { sync_frame = delay - infoscreen_frame[i - start]; infoscreen_frame[i - start]--; } if (helpanim_info[j].element == HELPANIM_LIST_NEXT) { if (!infoscreen_frame[i - start]) infoscreen_step[i - start] = 0; } else { if (!infoscreen_frame[i - start]) infoscreen_step[i - start]++; while (helpanim_info[j].element != HELPANIM_LIST_NEXT) j++; } j++; ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep, TILEX, TILEY); DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep, graphic, sync_frame, USE_MASKING); if (init) DrawInfoScreen_HelpText(element, action, direction, i - start); i++; } redraw_mask |= REDRAW_FIELD; FrameCounter++; } static char *getHelpText(int element, int action, int direction) { char token[MAX_LINE_LEN]; strcpy(token, element_info[element].token_name); if (action != -1) strcat(token, element_action_info[action].suffix); if (direction != -1) strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix); return getHashEntry(helptext_info, token); } void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos) { int font_nr = FONT_INFO_ELEMENTS; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int yoffset = (TILEX - 2 * font_height) / 2; int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT + TILEX + MINI_TILEX; int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset; int ystep = TILEY + 4; int pad_left = xstart - SX; int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT; int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width; int max_lines_per_text = 2; char *text = NULL; if (action != -1 && direction != -1) /* element.action.direction */ text = getHelpText(element, action, direction); if (text == NULL && action != -1) /* element.action */ text = getHelpText(element, action, -1); if (text == NULL && direction != -1) /* element.direction */ text = getHelpText(element, -1, direction); if (text == NULL) /* base element */ text = getHelpText(element, -1, -1); if (text == NULL) /* not found */ text = "No description available"; if (strlen(text) <= max_chars_per_line) /* only one line of text */ ystart += getFontHeight(font_nr) / 2; DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr, max_chars_per_line, -1, max_lines_per_text, 0, -1, TRUE, FALSE, FALSE); } void DrawInfoScreen_TitleScreen() { SetGameStatus(GAME_MODE_TITLE); DrawTitleScreen(); } void HandleInfoScreen_TitleScreen(int button) { HandleTitleScreen(0, 0, 0, 0, button); } void DrawInfoScreen_Elements() { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS); FadeOut(REDRAW_FIELD); LoadHelpAnimInfo(); LoadHelpTextInfo(); HandleInfoScreen_Elements(MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); } void HandleInfoScreen_Elements(int button) { static unsigned int info_delay = 0; static int num_anims; static int num_pages; static int page; int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN; int i; if (button == MB_MENU_INITIALIZE) { boolean new_element = TRUE; num_anims = 0; for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++) { if (helpanim_info[i].element == HELPANIM_LIST_NEXT) new_element = TRUE; else if (new_element) { num_anims++; new_element = FALSE; } } num_pages = (num_anims + anims_per_page - 1) / anims_per_page; page = 0; } if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); page++; } if (page >= num_pages) { FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } if (page > 0) FadeSetNextScreen(); if (button != MB_MENU_INITIALIZE) FadeOut(REDRAW_FIELD); DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE); if (button != MB_MENU_INITIALIZE) FadeIn(REDRAW_FIELD); } else { if (DelayReached(&info_delay, GameFrameDelay)) if (page < num_pages) DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE); PlayMenuSoundIfLoop(); } } void DrawInfoScreen_Music() { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC); FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); LoadMusicInfo(); HandleInfoScreen_Music(MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); } void HandleInfoScreen_Music(int button) { static struct MusicFileInfo *list = NULL; int font_title = MENU_INFO_FONT_TITLE; int font_head = MENU_INFO_FONT_HEAD; int font_text = MENU_INFO_FONT_TEXT; int font_foot = MENU_INFO_FONT_FOOT; int spacing_title = menu.headline1_spacing_info[info_mode]; int spacing_head = menu.headline2_spacing_info[info_mode]; int ystep_title = getMenuTextStep(spacing_title, font_title); int ystep_head = getMenuTextStep(spacing_head, font_head); int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; if (button == MB_MENU_INITIALIZE) { list = music_file_info; if (list == NULL) { FadeMenuSoundsAndMusic(); ClearField(); DrawHeadline(); DrawTextSCentered(ystart, font_title, "No music info for this level set."); DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); return; } } if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); if (list != NULL) list = list->next; } if (list == NULL) { FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } FadeMenuSoundsAndMusic(); if (list != music_file_info) FadeSetNextScreen(); if (button != MB_MENU_INITIALIZE) FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); if (list->is_sound) { int sound = list->music; if (sound_info[sound].loop) PlaySoundLoop(sound); else PlaySound(sound); DrawTextSCentered(ystart, font_title, "The Game Background Sounds:"); } else { PlayMusic(list->music); DrawTextSCentered(ystart, font_title, "The Game Background Music:"); } ystart += ystep_title; if (!strEqual(list->title, UNKNOWN_NAME)) { if (!strEqual(list->title_header, UNKNOWN_NAME)) { DrawTextSCentered(ystart, font_head, list->title_header); ystart += ystep_head; } DrawTextFCentered(ystart, font_text, "\"%s\"", list->title); ystart += ystep_head; } if (!strEqual(list->artist, UNKNOWN_NAME)) { if (!strEqual(list->artist_header, UNKNOWN_NAME)) DrawTextSCentered(ystart, font_head, list->artist_header); else DrawTextSCentered(ystart, font_head, "by"); ystart += ystep_head; DrawTextFCentered(ystart, font_text, "%s", list->artist); ystart += ystep_head; } if (!strEqual(list->album, UNKNOWN_NAME)) { if (!strEqual(list->album_header, UNKNOWN_NAME)) DrawTextSCentered(ystart, font_head, list->album_header); else DrawTextSCentered(ystart, font_head, "from the album"); ystart += ystep_head; DrawTextFCentered(ystart, font_text, "\"%s\"", list->album); ystart += ystep_head; } if (!strEqual(list->year, UNKNOWN_NAME)) { if (!strEqual(list->year_header, UNKNOWN_NAME)) DrawTextSCentered(ystart, font_head, list->year_header); else DrawTextSCentered(ystart, font_head, "from the year"); ystart += ystep_head; DrawTextFCentered(ystart, font_text, "%s", list->year); ystart += ystep_head; } DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for next page"); if (button != MB_MENU_INITIALIZE) FadeIn(REDRAW_FIELD); } if (list != NULL && list->is_sound && sound_info[list->music].loop) PlaySoundLoop(list->music); } static void DrawInfoScreen_CreditsScreen(int screen_nr) { int font_title = MENU_INFO_FONT_TITLE; int font_head = MENU_INFO_FONT_HEAD; int font_text = MENU_INFO_FONT_TEXT; int font_foot = MENU_INFO_FONT_FOOT; int spacing_title = menu.headline1_spacing_info[info_mode]; int spacing_head = menu.headline2_spacing_info[info_mode]; int spacing_para = menu.paragraph_spacing_info[info_mode]; int spacing_line = menu.line_spacing_info[info_mode]; int ystep_title = getMenuTextStep(spacing_title, font_title); int ystep_head = getMenuTextStep(spacing_head, font_head); int ystep_para = getMenuTextStep(spacing_para, font_text); int ystep_line = getMenuTextStep(spacing_line, font_text); int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; ClearField(); DrawHeadline(); DrawTextSCentered(ystart, font_title, "Credits:"); ystart += ystep_title; if (screen_nr == 0) { DrawTextSCentered(ystart, font_head, "Special thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Peter Liepa"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for creating"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "\"Boulder Dash\""); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "in the year"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "1984"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "published by"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "First Star Software"); } else if (screen_nr == 1) { DrawTextSCentered(ystart, font_head, "Special thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Klaus Heinz & Volker Wertich"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for creating"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "\"Emerald Mine\""); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "in the year"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "1987"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "published by"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Kingsoft"); } else if (screen_nr == 2) { DrawTextSCentered(ystart, font_head, "Special thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Michael Stopp & Philip Jespersen"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for creating"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "\"Supaplex\""); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "in the year"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "1991"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "published by"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Digital Integration"); } else if (screen_nr == 3) { DrawTextSCentered(ystart, font_head, "Special thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Hiroyuki Imabayashi"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for creating"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "\"Sokoban\""); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "in the year"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "1982"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "published by"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Thinking Rabbit"); } else if (screen_nr == 4) { DrawTextSCentered(ystart, font_head, "Special thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Alan Bond"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "and"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "J\xfcrgen Bonhagen"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for the continuous creation"); ystart += ystep_line; DrawTextSCentered(ystart, font_head, "of outstanding level sets"); } else if (screen_nr == 5) { DrawTextSCentered(ystart, font_head, "Thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Peter Elzner"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for ideas and inspiration by"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Diamond Caves"); ystart += ystep_para; DrawTextSCentered(ystart, font_head, "Thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Steffest"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for ideas and inspiration by"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "DX-Boulderdash"); } else if (screen_nr == 6) { DrawTextSCentered(ystart, font_head, "Thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "David Tritscher"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for the code base used for the"); ystart += ystep_line; DrawTextSCentered(ystart, font_head, "native Emerald Mine engine"); } else if (screen_nr == 7) { DrawTextSCentered(ystart, font_head, "Thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Guido Schulz"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for the initial DOS port"); ystart += ystep_para; DrawTextSCentered(ystart, font_head, "Thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "Karl H\xf6rnell"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "for some additional toons"); } else if (screen_nr == 8) { DrawTextSCentered(ystart, font_head, "And not to forget:"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "Many thanks to"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, "All those who contributed"); ystart += ystep_line; DrawTextSCentered(ystart, font_text, "levels to this game"); ystart += ystep_line; DrawTextSCentered(ystart, font_text, "since 1995"); } DrawTextSCentered(ybottom, font_foot, "Press any key or button for next page"); } void DrawInfoScreen_Credits() { SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS); FadeMenuSoundsAndMusic(); FadeOut(REDRAW_FIELD); HandleInfoScreen_Credits(MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); } void HandleInfoScreen_Credits(int button) { static int screen_nr = 0; int num_screens = 9; if (button == MB_MENU_INITIALIZE) { screen_nr = 0; // DrawInfoScreen_CreditsScreen(screen_nr); } if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE) { if (button != MB_MENU_INITIALIZE) { PlaySound(SND_MENU_ITEM_SELECTING); screen_nr++; } if (screen_nr >= num_screens) { FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } if (screen_nr > 0) FadeSetNextScreen(); if (button != MB_MENU_INITIALIZE) FadeOut(REDRAW_FIELD); DrawInfoScreen_CreditsScreen(screen_nr); if (button != MB_MENU_INITIALIZE) FadeIn(REDRAW_FIELD); } else { PlayMenuSoundIfLoop(); } } void DrawInfoScreen_Program() { int font_title = MENU_INFO_FONT_TITLE; int font_head = MENU_INFO_FONT_HEAD; int font_text = MENU_INFO_FONT_TEXT; int font_foot = MENU_INFO_FONT_FOOT; int spacing_title = menu.headline1_spacing_info[info_mode]; int spacing_head = menu.headline2_spacing_info[info_mode]; int spacing_para = menu.paragraph_spacing_info[info_mode]; int spacing_line = menu.line_spacing_info[info_mode]; int ystep_title = getMenuTextStep(spacing_title, font_title); int ystep_head = getMenuTextStep(spacing_head, font_head); int ystep_para = getMenuTextStep(spacing_para, font_text); int ystep_line = getMenuTextStep(spacing_line, font_text); int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM); FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); DrawTextSCentered(ystart, font_title, "Program Information:"); ystart += ystep_title; DrawTextSCentered(ystart, font_head, "This game is Freeware!"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, "If you like it, send e-mail to:"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, setup.internal.program_email); ystart += ystep_para; DrawTextSCentered(ystart, font_head, "More information and levels:"); ystart += ystep_head; DrawTextSCentered(ystart, font_text, setup.internal.program_website); ystart += ystep_para; DrawTextSCentered(ystart, font_head, "If you have created new levels,"); ystart += ystep_line; DrawTextSCentered(ystart, font_head, "send them to me to include them!"); ystart += ystep_head; DrawTextSCentered(ystart, font_head, ":-)"); DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); } void HandleInfoScreen_Program(int button) { if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else { PlayMenuSoundIfLoop(); } } void DrawInfoScreen_Version() { int font_title = MENU_INFO_FONT_TITLE; int font_head = MENU_INFO_FONT_HEAD; int font_text = MENU_INFO_FONT_TEXT; int font_foot = MENU_INFO_FONT_FOOT; int spacing_title = menu.headline1_spacing_info[info_mode]; int spacing_head = menu.headline2_spacing_info[info_mode]; int spacing_para = menu.paragraph_spacing_info[info_mode]; int spacing_line = menu.line_spacing_info[info_mode]; int xstep = getFontWidth(font_text); int ystep_title = getMenuTextStep(spacing_title, font_title); int ystep_head = getMenuTextStep(spacing_head, font_head); int ystep_para = getMenuTextStep(spacing_para, font_text); int ystep_line = getMenuTextStep(spacing_line, font_text); int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; int xstart1 = mSX - SX + 2 * xstep; int xstart2 = mSX - SX + 18 * xstep; int xstart3 = mSX - SX + 28 * xstep; SDL_version sdl_version_compiled; const SDL_version *sdl_version_linked; int driver_name_len = 10; #if defined(TARGET_SDL2) SDL_version sdl_version_linked_ext; const char *driver_name = NULL; #else char driver_name[driver_name_len]; #endif SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION); FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); DrawTextSCentered(ystart, font_title, "Version Information:"); ystart += ystep_title; DrawTextF(xstart1, ystart, font_head, "Name"); DrawTextF(xstart2, ystart, font_text, getProgramTitleString()); ystart += ystep_line; if (!strEqual(getProgramVersionString(), getProgramRealVersionString())) { DrawTextF(xstart1, ystart, font_head, "Version (fake)"); DrawTextF(xstart2, ystart, font_text, getProgramVersionString()); ystart += ystep_line; DrawTextF(xstart1, ystart, font_head, "Version (real)"); DrawTextF(xstart2, ystart, font_text, getProgramRealVersionString()); ystart += ystep_line; } else { DrawTextF(xstart1, ystart, font_head, "Version"); DrawTextF(xstart2, ystart, font_text, getProgramVersionString()); ystart += ystep_line; } DrawTextF(xstart1, ystart, font_head, "Platform"); DrawTextF(xstart2, ystart, font_text, PLATFORM_STRING); ystart += ystep_line; DrawTextF(xstart1, ystart, font_head, "Target"); DrawTextF(xstart2, ystart, font_text, TARGET_STRING); ystart += ystep_line; DrawTextF(xstart1, ystart, font_head, "Source date"); DrawTextF(xstart2, ystart, font_text, getSourceDateString()); ystart += ystep_para; DrawTextF(xstart1, ystart, font_head, "Library"); DrawTextF(xstart2, ystart, font_head, "compiled"); DrawTextF(xstart3, ystart, font_head, "linked"); ystart += ystep_head; SDL_VERSION(&sdl_version_compiled); #if defined(TARGET_SDL2) SDL_GetVersion(&sdl_version_linked_ext); sdl_version_linked = &sdl_version_linked_ext; #else sdl_version_linked = SDL_Linked_Version(); #endif DrawTextF(xstart1, ystart, font_text, "SDL"); DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); ystart += ystep_line; SDL_IMAGE_VERSION(&sdl_version_compiled); sdl_version_linked = IMG_Linked_Version(); DrawTextF(xstart1, ystart, font_text, "SDL_image"); DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); ystart += ystep_line; SDL_MIXER_VERSION(&sdl_version_compiled); sdl_version_linked = Mix_Linked_Version(); DrawTextF(xstart1, ystart, font_text, "SDL_mixer"); DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); ystart += ystep_line; SDL_NET_VERSION(&sdl_version_compiled); sdl_version_linked = SDLNet_Linked_Version(); DrawTextF(xstart1, ystart, font_text, "SDL_net"); DrawTextF(xstart2, ystart, font_text, "%d.%d.%d", sdl_version_compiled.major, sdl_version_compiled.minor, sdl_version_compiled.patch); DrawTextF(xstart3, ystart, font_text, "%d.%d.%d", sdl_version_linked->major, sdl_version_linked->minor, sdl_version_linked->patch); ystart += ystep_para; DrawTextF(xstart1, ystart, font_head, "Driver"); DrawTextF(xstart2, ystart, font_head, "Requested"); DrawTextF(xstart3, ystart, font_head, "Used"); ystart += ystep_head; #if defined(TARGET_SDL2) driver_name = getStringCopyNStatic(SDL_GetVideoDriver(0), driver_name_len); #else SDL_VideoDriverName(driver_name, driver_name_len); #endif DrawTextF(xstart1, ystart, font_text, "SDL_VideoDriver"); DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_videodriver); DrawTextF(xstart3, ystart, font_text, "%s", driver_name); ystart += ystep_line; #if defined(TARGET_SDL2) driver_name = getStringCopyNStatic(SDL_GetAudioDriver(0), driver_name_len); #else SDL_AudioDriverName(driver_name, driver_name_len); #endif DrawTextF(xstart1, ystart, font_text, "SDL_AudioDriver"); DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_audiodriver); DrawTextF(xstart3, ystart, font_text, "%s", driver_name); DrawTextSCentered(ybottom, font_foot, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); } void HandleInfoScreen_Version(int button) { if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else { PlayMenuSoundIfLoop(); } } void DrawInfoScreen_LevelSet() { struct TitleMessageInfo *tmi = &readme; char *filename = getLevelSetInfoFilename(); char *title = "Level Set Information:"; int ystart = mSY - SY + MENU_SCREEN_INFO_YSTART1; int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM; if (filename == NULL) { DrawInfoScreen_NotAvailable(title, "No information for this level set."); return; } SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET); FadeOut(REDRAW_FIELD); ClearField(); DrawHeadline(); DrawTextSCentered(ystart, FONT_TEXT_1, title); /* if x position set to "-1", automatically determine by playfield width */ if (tmi->x == -1) tmi->x = SXSIZE / 2; /* if y position set to "-1", use static default value */ if (tmi->y == -1) tmi->y = 150; /* if width set to "-1", automatically determine by playfield width */ if (tmi->width == -1) tmi->width = SXSIZE - 2 * TILEX; /* if height set to "-1", automatically determine by playfield height */ if (tmi->height == -1) tmi->height = MENU_SCREEN_INFO_YBOTTOM - tmi->y - 10; /* if chars set to "-1", automatically determine by text and font width */ if (tmi->chars == -1) tmi->chars = tmi->width / getFontWidth(tmi->font); else tmi->width = tmi->chars * getFontWidth(tmi->font); /* if lines set to "-1", automatically determine by text and font height */ if (tmi->lines == -1) tmi->lines = tmi->height / getFontHeight(tmi->font); else tmi->height = tmi->lines * getFontHeight(tmi->font); DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi), filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1, tmi->autowrap, tmi->centered, tmi->parse_comments); DrawTextSCentered(ybottom, FONT_TEXT_4, "Press any key or button for info menu"); FadeIn(REDRAW_FIELD); } void HandleInfoScreen_LevelSet(int button) { if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); return; } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeMenuSoundsAndMusic(); info_mode = INFO_MODE_MAIN; DrawInfoScreen(); } else { PlayMenuSoundIfLoop(); } } static void DrawInfoScreen() { if (info_mode == INFO_MODE_TITLE) DrawInfoScreen_TitleScreen(); else if (info_mode == INFO_MODE_ELEMENTS) DrawInfoScreen_Elements(); else if (info_mode == INFO_MODE_MUSIC) DrawInfoScreen_Music(); else if (info_mode == INFO_MODE_CREDITS) DrawInfoScreen_Credits(); else if (info_mode == INFO_MODE_PROGRAM) DrawInfoScreen_Program(); else if (info_mode == INFO_MODE_VERSION) DrawInfoScreen_Version(); else if (info_mode == INFO_MODE_LEVELSET) DrawInfoScreen_LevelSet(); else DrawInfoScreen_Main(); if (info_mode != INFO_MODE_MAIN && info_mode != INFO_MODE_TITLE && info_mode != INFO_MODE_MUSIC) PlayMenuSoundsAndMusic(); } void HandleInfoScreen(int mx, int my, int dx, int dy, int button) { if (info_mode == INFO_MODE_TITLE) HandleInfoScreen_TitleScreen(button); else if (info_mode == INFO_MODE_ELEMENTS) HandleInfoScreen_Elements(button); else if (info_mode == INFO_MODE_MUSIC) HandleInfoScreen_Music(button); else if (info_mode == INFO_MODE_CREDITS) HandleInfoScreen_Credits(button); else if (info_mode == INFO_MODE_PROGRAM) HandleInfoScreen_Program(button); else if (info_mode == INFO_MODE_VERSION) HandleInfoScreen_Version(button); else if (info_mode == INFO_MODE_LEVELSET) HandleInfoScreen_LevelSet(button); else HandleInfoScreen_Main(mx, my, dx, dy, button); } /* ========================================================================= */ /* type name functions */ /* ========================================================================= */ void HandleTypeName(int newxpos, Key key) { static char last_player_name[MAX_PLAYER_NAME_LEN + 1]; struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME); struct TextPosInfo *pos = mci->pos_input; int startx = mSX + ALIGNED_TEXT_XPOS(pos); int starty = mSY + ALIGNED_TEXT_YPOS(pos); static int xpos = 0; int font_nr = pos->font; int font_active_nr = FONT_ACTIVE(font_nr); int font_width = getFontWidth(font_active_nr); char key_char = getValidConfigValueChar(getCharFromKey(key)); boolean is_valid_key_char = (key_char != 0 && (key_char != ' ' || xpos > 0)); boolean is_active = TRUE; DrawBackgroundForFont(startx,starty, pos->width, pos->height, font_active_nr); if (newxpos) { strcpy(last_player_name, setup.player_name); xpos = newxpos; StartTextInput(startx, starty, pos->width, pos->height); } else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN) { setup.player_name[xpos] = key_char; setup.player_name[xpos + 1] = 0; xpos++; } else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0) { xpos--; setup.player_name[xpos] = 0; } else if (key == KSYM_Return && xpos > 0) { SaveSetup(); is_active = FALSE; SetGameStatus(GAME_MODE_MAIN); } else if (key == KSYM_Escape) { strcpy(setup.player_name, last_player_name); is_active = FALSE; SetGameStatus(GAME_MODE_MAIN); } if (is_active) { pos->width = (strlen(setup.player_name) + 1) * font_width; startx = mSX + ALIGNED_TEXT_XPOS(pos); DrawText(startx, starty, setup.player_name, font_active_nr); DrawText(startx + xpos * font_width, starty, "_", font_active_nr); } else { pos->width = strlen(setup.player_name) * font_width; startx = mSX + ALIGNED_TEXT_XPOS(pos); DrawText(startx, starty, setup.player_name, font_nr); StopTextInput(); } } /* ========================================================================= */ /* tree menu functions */ /* ========================================================================= */ static void DrawChooseTree(TreeInfo **ti_ptr) { int fade_mask = REDRAW_FIELD; if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY)) { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); return; } UnmapAllGadgets(); FreeScreenGadgets(); CreateScreenGadgets(); FadeOut(fade_mask); /* needed if different viewport properties defined for choosing level (set) */ ChangeViewportPropertiesIfNeeded(); if (game_status == GAME_MODE_LEVELNR) SetMainBackgroundImage(IMG_BACKGROUND_LEVELNR); else if (game_status == GAME_MODE_LEVELS) SetMainBackgroundImage(IMG_BACKGROUND_LEVELS); ClearField(); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr); MapScreenTreeGadgets(*ti_ptr); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); } static void drawChooseTreeList(int first_entry, int num_page_entries, TreeInfo *ti) { int i; char *title_string = NULL; int yoffset_sets = MENU_TITLE1_YPOS; int yoffset_setup = 16; int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR || ti->type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup); title_string = ti->infotext; DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string); clearMenuListArea(); for (i = 0; i < num_page_entries; i++) { TreeInfo *node, *node_first; int entry_pos = first_entry + i; int xpos = MENU_SCREEN_START_XPOS; int ypos = MENU_SCREEN_START_YPOS + i; int startx = mSX + xpos * 32; int starty = mSY + ypos * 32; int font_nr = FONT_TEXT_1; int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; int startx_text = startx + font_xoffset; int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset; int text_size = startx_scrollbar - startx_text; int max_buffer_len = text_size / getFontWidth(font_nr); char buffer[max_buffer_len + 1]; node_first = getTreeInfoFirstGroupEntry(ti); node = getTreeInfoFromPos(node_first, entry_pos); strncpy(buffer, node->name, max_buffer_len); buffer[max_buffer_len] = '\0'; DrawText(startx, starty, buffer, font_nr + node->color); if (node->parent_link) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (node->level_group) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else initCursor(i, IMG_MENU_BUTTON); } redraw_mask |= REDRAW_FIELD; } static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti) { TreeInfo *node, *node_first; int x, last_redraw_mask = redraw_mask; int ypos = MENU_TITLE2_YPOS; int font_nr = FONT_TITLE_2; if (ti->type == TREE_TYPE_LEVEL_NR) DrawTextFCentered(ypos, font_nr, leveldir_current->name); if (ti->type != TREE_TYPE_LEVEL_DIR) return; node_first = getTreeInfoFirstGroupEntry(ti); node = getTreeInfoFromPos(node_first, entry_pos); DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr); if (node->parent_link) DrawTextFCentered(ypos, font_nr, "leave \"%s\"", node->node_parent->name); else if (node->level_group) DrawTextFCentered(ypos, font_nr, "enter \"%s\"", node->name); else if (ti->type == TREE_TYPE_LEVEL_DIR) DrawTextFCentered(ypos, font_nr, "%3d %s (%s)", node->levels, (node->levels > 1 ? "levels" : "level"), node->class_desc); /* let BackToFront() redraw only what is needed */ redraw_mask = last_redraw_mask; for (x = 0; x < SCR_FIELDX; x++) MarkTileDirty(x, 1); } static void HandleChooseTree(int mx, int my, int dx, int dy, int button, TreeInfo **ti_ptr) { TreeInfo *ti = *ti_ptr; int x = 0; int y = ti->cl_cursor; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); int num_entries = numTreeInfoInGroup(ti); int num_page_entries; boolean position_set_by_scrollbar = (dx == 999); if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN) num_page_entries = num_entries; else num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; if (button == MB_MENU_INITIALIZE) { int num_entries = numTreeInfoInGroup(ti); int entry_pos = posTreeInfo(ti); if (ti->cl_first == -1) { /* only on initialization */ ti->cl_first = MAX(0, entry_pos - num_page_entries + 1); ti->cl_cursor = entry_pos - ti->cl_first; } else if (ti->cl_cursor >= num_page_entries || (num_entries > num_page_entries && num_entries - ti->cl_first < num_page_entries)) { /* only after change of list size (by custom graphic configuration) */ ti->cl_first = MAX(0, entry_pos - num_page_entries + 1); ti->cl_cursor = entry_pos - ti->cl_first; } if (position_set_by_scrollbar) ti->cl_first = dy; else AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, ti->cl_first, ti); drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); drawChooseTreeCursor(ti->cl_cursor, TRUE); return; } else if (button == MB_MENU_LEAVE) { FadeSetLeaveMenu(); PlaySound(SND_MENU_ITEM_SELECTING); if (ti->node_parent) { *ti_ptr = ti->node_parent; DrawChooseTree(ti_ptr); } else if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED || setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY || setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) execSetupGame(); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE || setup_mode == SETUP_MODE_CHOOSE_RENDERING) execSetupGraphics(); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE || setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS || setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC) execSetupSound(); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL || setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE || setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) execSetupTouch(); else execSetupArtwork(); } else { if (game_status == GAME_MODE_LEVELNR) { int new_level_nr = atoi(level_number_current->identifier); HandleMainMenu_SelectLevel(0, 0, new_level_nr); } SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } return; } if (mx || my) /* mouse input */ { x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } else if (dx || dy) /* keyboard or scrollbar/scrollbutton input */ { /* move cursor instead of scrolling when already at start/end of list */ if (dy == -1 * SCROLL_LINE && ti->cl_first == 0) dy = -1; else if (dy == +1 * SCROLL_LINE && ti->cl_first + num_page_entries == num_entries) dy = 1; /* handle scrolling screen one line or page */ if (ti->cl_cursor + dy < 0 || ti->cl_cursor + dy > num_page_entries - 1) { boolean redraw = FALSE; if (ABS(dy) == SCROLL_PAGE) step = num_page_entries - 1; if (dy < 0 && ti->cl_first > 0) { /* scroll page/line up */ ti->cl_first -= step; if (ti->cl_first < 0) ti->cl_first = 0; redraw = TRUE; } else if (dy > 0 && ti->cl_first + num_page_entries < num_entries) { /* scroll page/line down */ ti->cl_first += step; if (ti->cl_first + num_page_entries > num_entries) ti->cl_first = MAX(0, num_entries - num_page_entries); redraw = TRUE; } if (redraw) { drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); drawChooseTreeCursor(ti->cl_cursor, TRUE); AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, ti->cl_first, ti); } return; } /* handle moving cursor one line */ y = ti->cl_cursor + dy; } if (dx == 1) { TreeInfo *node_first, *node_cursor; int entry_pos = ti->cl_first + y; node_first = getTreeInfoFirstGroupEntry(ti); node_cursor = getTreeInfoFromPos(node_first, entry_pos); if (node_cursor->node_group) { FadeSetEnterMenu(); PlaySound(SND_MENU_ITEM_SELECTING); node_cursor->cl_first = ti->cl_first; node_cursor->cl_cursor = ti->cl_cursor; *ti_ptr = node_cursor->node_group; DrawChooseTree(ti_ptr); return; } } else if (dx == -1 && ti->node_parent) { FadeSetLeaveMenu(); PlaySound(SND_MENU_ITEM_SELECTING); *ti_ptr = ti->node_parent; DrawChooseTree(ti_ptr); return; } if (!anyScrollbarGadgetActive() && IN_VIS_MENU(x, y) && mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x && y >= 0 && y < num_page_entries) { if (button) { if (y != ti->cl_cursor) { PlaySound(SND_MENU_ITEM_ACTIVATING); drawChooseTreeCursor(ti->cl_cursor, FALSE); drawChooseTreeCursor(y, TRUE); drawChooseTreeInfo(ti->cl_first + y, ti); ti->cl_cursor = y; } else if (dx < 0) { if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED || setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY || setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) execSetupGame(); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE || setup_mode == SETUP_MODE_CHOOSE_RENDERING) execSetupGraphics(); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE || setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS || setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC) execSetupSound(); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL || setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE || setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) execSetupTouch(); else execSetupArtwork(); } } } else { TreeInfo *node_first, *node_cursor; int entry_pos = ti->cl_first + y; PlaySound(SND_MENU_ITEM_SELECTING); node_first = getTreeInfoFirstGroupEntry(ti); node_cursor = getTreeInfoFromPos(node_first, entry_pos); if (node_cursor->node_group) { FadeSetEnterMenu(); node_cursor->cl_first = ti->cl_first; node_cursor->cl_cursor = ti->cl_cursor; *ti_ptr = node_cursor->node_group; DrawChooseTree(ti_ptr); } else if (node_cursor->parent_link) { FadeSetLeaveMenu(); *ti_ptr = node_cursor->node_parent; DrawChooseTree(ti_ptr); } else { FadeSetEnterMenu(); node_cursor->cl_first = ti->cl_first; node_cursor->cl_cursor = ti->cl_cursor; *ti_ptr = node_cursor; if (ti->type == TREE_TYPE_LEVEL_DIR) { LoadLevelSetup_SeriesInfo(); SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); TapeErase(); } if (game_status == GAME_MODE_SETUP) { if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED || setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY || setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) execSetupGame(); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE || setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE || setup_mode == SETUP_MODE_CHOOSE_RENDERING) execSetupGraphics(); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE || setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS || setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC) execSetupSound(); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL || setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE || setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) execSetupTouch(); else execSetupArtwork(); } else { if (game_status == GAME_MODE_LEVELNR) { int new_level_nr = atoi(level_number_current->identifier); HandleMainMenu_SelectLevel(0, 0, new_level_nr); } SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } } } } } void DrawChooseLevelSet() { FadeMenuSoundsAndMusic(); DrawChooseTree(&leveldir_current); PlayMenuSoundsAndMusic(); } void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button) { HandleChooseTree(mx, my, dx, dy, button, &leveldir_current); } void DrawChooseLevelNr() { int i; FadeMenuSoundsAndMusic(); if (level_number != NULL) { freeTreeInfo(level_number); level_number = NULL; } for (i = leveldir_current->first_level; i <= leveldir_current->last_level;i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_LEVEL_NR); char identifier[32], name[32]; int value = i; /* temporarily load level info to get level name */ LoadLevelInfoOnly(i); ti->node_top = &level_number; ti->sort_priority = 10000 + value; ti->color = (level.no_level_file ? FC_BLUE : LevelStats_getSolved(i) ? FC_GREEN : LevelStats_getPlayed(i) ? FC_YELLOW : FC_RED); snprintf(identifier, sizeof(identifier), "%d", value); snprintf(name, sizeof(name), "%03d: %s", value, (level.no_level_file ? "(no file)" : level.name)); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); pushTreeInfo(&level_number, ti); } /* sort level number values to start with lowest level number */ sortTreeInfo(&level_number); /* set current level number to current level number */ level_number_current = getTreeInfoFromIdentifier(level_number, i_to_a(level_nr)); /* if that also fails, set current level number to first available level */ if (level_number_current == NULL) level_number_current = level_number; DrawChooseTree(&level_number_current); PlayMenuSoundsAndMusic(); } void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button) { HandleChooseTree(mx, my, dx, dy, button, &level_number_current); } void DrawHallOfFame(int highlight_position) { int fade_mask = REDRAW_FIELD; if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; UnmapAllGadgets(); FadeMenuSoundsAndMusic(); /* (this is needed when called from GameEnd() after winning a game) */ KeyboardAutoRepeatOn(); /* (this is needed when called from GameEnd() after winning a game) */ SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); if (highlight_position < 0) LoadScore(level_nr); else SetAnimStatus(GAME_MODE_PSEUDO_SCORESNEW); FadeSetEnterScreen(); FadeOut(fade_mask); /* needed if different viewport properties defined for scores */ ChangeViewportPropertiesIfNeeded(); PlayMenuSoundsAndMusic(); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); } static void drawHallOfFameList(int first_entry, int highlight_position) { int i, j; SetMainBackgroundImage(IMG_BACKGROUND_SCORES); ClearField(); DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame"); DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, "HighScores of Level %d", level_nr); for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++) { int entry = first_entry + i; boolean active = (entry == highlight_position); int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1); int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2); int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3); int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4); int dxoff = getFontDrawOffsetX(font_nr1); int dx1 = 3 * getFontWidth(font_nr1); int dx2 = dx1 + getFontWidth(font_nr1); int dx3 = SXSIZE - 2 * (mSX - SX + dxoff) - 5 * getFontWidth(font_nr4); int num_dots = (dx3 - dx2) / getFontWidth(font_nr3); int sy = mSY + 64 + i * 32; DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1); DrawText(mSX + dx1, sy, ".", font_nr1); for (j = 0; j < num_dots; j++) DrawText(mSX + dx2 + j * getFontWidth(font_nr3), sy, ".", font_nr3); if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME)) DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2); DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4); } redraw_mask |= REDRAW_FIELD; } void HandleHallOfFame(int mx, int my, int dx, int dy, int button) { static int first_entry = 0; static int highlight_position = 0; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); if (button == MB_MENU_INITIALIZE) { first_entry = 0; highlight_position = mx; drawHallOfFameList(first_entry, highlight_position); return; } if (ABS(dy) == SCROLL_PAGE) /* handle scrolling one page */ step = NUM_MENU_ENTRIES_ON_SCREEN - 1; if (dy < 0) { if (first_entry > 0) { first_entry -= step; if (first_entry < 0) first_entry = 0; drawHallOfFameList(first_entry, highlight_position); } } else if (dy > 0) { if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES) { first_entry += step; if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES) first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN); drawHallOfFameList(first_entry, highlight_position); } } else if (button == MB_MENU_LEAVE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSound(SND_BACKGROUND_SCORES); SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } else if (button == MB_MENU_CHOICE) { PlaySound(SND_MENU_ITEM_SELECTING); FadeSound(SND_BACKGROUND_SCORES); SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } if (game_status == GAME_MODE_SCORES) PlayMenuSoundIfLoop(); } /* ========================================================================= */ /* setup screen functions */ /* ========================================================================= */ static struct TokenInfo *setup_info; static int num_setup_info; /* number of setup entries shown on screen */ static int max_setup_info; /* total number of setup entries in list */ static char *window_size_text; static char *scaling_type_text; static char *rendering_mode_text; static char *scroll_delay_text; static char *snapshot_mode_text; static char *game_speed_text; static char *graphics_set_name; static char *sounds_set_name; static char *music_set_name; static char *volume_simple_text; static char *volume_loops_text; static char *volume_music_text; static char *touch_controls_text; static char *move_distance_text; static char *drop_distance_text; static void execSetupMain() { setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } static void execSetupGame_setGameSpeeds() { if (game_speeds == NULL) { int i; for (i = 0; game_speeds_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = game_speeds_list[i].value; char *text = game_speeds_list[i].text; ti->node_top = &game_speeds; ti->sort_priority = 10000 - value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_GAME_SPEED); pushTreeInfo(&game_speeds, ti); } /* sort game speed values to start with slowest game speed */ sortTreeInfo(&game_speeds); /* set current game speed to configured game speed value */ game_speed_current = getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay)); /* if that fails, set current game speed to reliable default value */ if (game_speed_current == NULL) game_speed_current = getTreeInfoFromIdentifier(game_speeds, i_to_a(GAME_FRAME_DELAY)); /* if that also fails, set current game speed to first available speed */ if (game_speed_current == NULL) game_speed_current = game_speeds; } setup.game_frame_delay = atoi(game_speed_current->identifier); /* needed for displaying game speed text instead of identifier */ game_speed_text = game_speed_current->name; } static void execSetupGame_setScrollDelays() { if (scroll_delays == NULL) { int i; for (i = 0; scroll_delays_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = scroll_delays_list[i].value; char *text = scroll_delays_list[i].text; ti->node_top = &scroll_delays; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_SCROLL_DELAY); pushTreeInfo(&scroll_delays, ti); } /* sort scroll delay values to start with lowest scroll delay value */ sortTreeInfo(&scroll_delays); /* set current scroll delay value to configured scroll delay value */ scroll_delay_current = getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value)); /* if that fails, set current scroll delay to reliable default value */ if (scroll_delay_current == NULL) scroll_delay_current = getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY)); /* if that also fails, set current scroll delay to first available value */ if (scroll_delay_current == NULL) scroll_delay_current = scroll_delays; } setup.scroll_delay_value = atoi(scroll_delay_current->identifier); /* needed for displaying scroll delay text instead of identifier */ scroll_delay_text = scroll_delay_current->name; } static void execSetupGame_setSnapshotModes() { if (snapshot_modes == NULL) { int i; for (i = 0; snapshot_modes_list[i].value != NULL; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; char *value = snapshot_modes_list[i].value; char *text = snapshot_modes_list[i].text; ti->node_top = &snapshot_modes; ti->sort_priority = i; sprintf(identifier, "%s", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_SNAPSHOT_MODE); pushTreeInfo(&snapshot_modes, ti); } /* sort snapshot mode values to start with lowest snapshot mode value */ sortTreeInfo(&snapshot_modes); /* set current snapshot mode value to configured snapshot mode value */ snapshot_mode_current = getTreeInfoFromIdentifier(snapshot_modes, setup.engine_snapshot_mode); /* if that fails, set current snapshot mode to reliable default value */ if (snapshot_mode_current == NULL) snapshot_mode_current = getTreeInfoFromIdentifier(snapshot_modes, STR_SNAPSHOT_MODE_DEFAULT); /* if that also fails, set current snapshot mode to first available value */ if (snapshot_mode_current == NULL) snapshot_mode_current = snapshot_modes; } setup.engine_snapshot_mode = snapshot_mode_current->identifier; /* needed for displaying snapshot mode text instead of identifier */ snapshot_mode_text = snapshot_mode_current->name; } static void execSetupGame() { execSetupGame_setGameSpeeds(); execSetupGame_setScrollDelays(); execSetupGame_setSnapshotModes(); setup_mode = SETUP_MODE_GAME; DrawSetupScreen(); } static void execSetupChooseGameSpeed() { setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED; DrawSetupScreen(); } static void execSetupChooseScrollDelay() { setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY; DrawSetupScreen(); } static void execSetupChooseSnapshotMode() { setup_mode = SETUP_MODE_CHOOSE_SNAPSHOT_MODE; DrawSetupScreen(); } static void execSetupEditor() { setup_mode = SETUP_MODE_EDITOR; DrawSetupScreen(); } static void execSetupGraphics_setWindowSizes(boolean update_list) { if (window_sizes != NULL && update_list) { freeTreeInfo(window_sizes); window_sizes = NULL; } if (window_sizes == NULL) { boolean current_window_size_found = FALSE; int i; for (i = 0; window_sizes_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = window_sizes_list[i].value; char *text = window_sizes_list[i].text; ti->node_top = &window_sizes; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_WINDOW_SIZE); pushTreeInfo(&window_sizes, ti); if (value == setup.window_scaling_percent) current_window_size_found = TRUE; } if (!current_window_size_found) { // add entry for non-preset window scaling value TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = setup.window_scaling_percent; ti->node_top = &window_sizes; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%d %% (Current)", value); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_WINDOW_SIZE); pushTreeInfo(&window_sizes, ti); } /* sort window size values to start with lowest window size value */ sortTreeInfo(&window_sizes); /* set current window size value to configured window size value */ window_size_current = getTreeInfoFromIdentifier(window_sizes, i_to_a(setup.window_scaling_percent)); /* if that fails, set current window size to reliable default value */ if (window_size_current == NULL) window_size_current = getTreeInfoFromIdentifier(window_sizes, i_to_a(STD_WINDOW_SCALING_PERCENT)); /* if that also fails, set current window size to first available value */ if (window_size_current == NULL) window_size_current = window_sizes; } setup.window_scaling_percent = atoi(window_size_current->identifier); /* needed for displaying window size text instead of identifier */ window_size_text = window_size_current->name; } static void execSetupGraphics_setScalingTypes() { if (scaling_types == NULL) { int i; for (i = 0; scaling_types_list[i].value != NULL; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; char *value = scaling_types_list[i].value; char *text = scaling_types_list[i].text; ti->node_top = &scaling_types; ti->sort_priority = i; sprintf(identifier, "%s", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_SCALING_TYPE); pushTreeInfo(&scaling_types, ti); } /* sort scaling type values to start with lowest scaling type value */ sortTreeInfo(&scaling_types); /* set current scaling type value to configured scaling type value */ scaling_type_current = getTreeInfoFromIdentifier(scaling_types, setup.window_scaling_quality); /* if that fails, set current scaling type to reliable default value */ if (scaling_type_current == NULL) scaling_type_current = getTreeInfoFromIdentifier(scaling_types, SCALING_QUALITY_DEFAULT); /* if that also fails, set current scaling type to first available value */ if (scaling_type_current == NULL) scaling_type_current = scaling_types; } setup.window_scaling_quality = scaling_type_current->identifier; /* needed for displaying scaling type text instead of identifier */ scaling_type_text = scaling_type_current->name; } static void execSetupGraphics_setRenderingModes() { if (rendering_modes == NULL) { int i; for (i = 0; rendering_modes_list[i].value != NULL; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; char *value = rendering_modes_list[i].value; char *text = rendering_modes_list[i].text; ti->node_top = &rendering_modes; ti->sort_priority = i; sprintf(identifier, "%s", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_RENDERING); pushTreeInfo(&rendering_modes, ti); } /* sort rendering mode values to start with lowest rendering mode value */ sortTreeInfo(&rendering_modes); /* set current rendering mode value to configured rendering mode value */ rendering_mode_current = getTreeInfoFromIdentifier(rendering_modes, setup.screen_rendering_mode); /* if that fails, set current rendering mode to reliable default value */ if (rendering_mode_current == NULL) rendering_mode_current = getTreeInfoFromIdentifier(rendering_modes, STR_SPECIAL_RENDERING_DEFAULT); /* if that also fails, set current rendering mode to first available one */ if (rendering_mode_current == NULL) rendering_mode_current = rendering_modes; } setup.screen_rendering_mode = rendering_mode_current->identifier; /* needed for displaying rendering mode text instead of identifier */ rendering_mode_text = rendering_mode_current->name; } static void execSetupGraphics() { // update "setup.window_scaling_percent" from list selection // (in this case, window scaling was changed on setup screen) if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) execSetupGraphics_setWindowSizes(FALSE); // update list selection from "setup.window_scaling_percent" // (window scaling may have changed by resizing the window) execSetupGraphics_setWindowSizes(TRUE); execSetupGraphics_setScalingTypes(); execSetupGraphics_setRenderingModes(); setup_mode = SETUP_MODE_GRAPHICS; DrawSetupScreen(); #if defined(TARGET_SDL2) // window scaling may have changed at this point ToggleFullscreenOrChangeWindowScalingIfNeeded(); // window scaling quality may have changed at this point if (!strEqual(setup.window_scaling_quality, video.window_scaling_quality)) SDLSetWindowScalingQuality(setup.window_scaling_quality); // screen rendering mode may have changed at this point SDLSetScreenRenderingMode(setup.screen_rendering_mode); #endif } #if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID) static void execSetupChooseWindowSize() { setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE; DrawSetupScreen(); } static void execSetupChooseScalingType() { setup_mode = SETUP_MODE_CHOOSE_SCALING_TYPE; DrawSetupScreen(); } static void execSetupChooseRenderingMode() { setup_mode = SETUP_MODE_CHOOSE_RENDERING; DrawSetupScreen(); } #endif static void execSetupChooseVolumeSimple() { setup_mode = SETUP_MODE_CHOOSE_VOLUME_SIMPLE; DrawSetupScreen(); } static void execSetupChooseVolumeLoops() { setup_mode = SETUP_MODE_CHOOSE_VOLUME_LOOPS; DrawSetupScreen(); } static void execSetupChooseVolumeMusic() { setup_mode = SETUP_MODE_CHOOSE_VOLUME_MUSIC; DrawSetupScreen(); } static void execSetupSound() { if (volumes_simple == NULL) { boolean current_volume_simple_found = FALSE; int i; for (i = 0; volumes_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = volumes_list[i].value; char *text = volumes_list[i].text; ti->node_top = &volumes_simple; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_SIMPLE); pushTreeInfo(&volumes_simple, ti); if (value == setup.volume_simple) current_volume_simple_found = TRUE; } if (!current_volume_simple_found) { // add entry for non-preset volume value TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = setup.volume_simple; ti->node_top = &volumes_simple; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%d %% (Current)", value); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_SIMPLE); pushTreeInfo(&volumes_simple, ti); } /* sort volume values to start with lowest volume value */ sortTreeInfo(&volumes_simple); /* set current volume value to configured volume value */ volume_simple_current = getTreeInfoFromIdentifier(volumes_simple,i_to_a(setup.volume_simple)); /* if that fails, set current volume to reliable default value */ if (volume_simple_current == NULL) volume_simple_current = getTreeInfoFromIdentifier(volumes_simple, i_to_a(100)); /* if that also fails, set current volume to first available value */ if (volume_simple_current == NULL) volume_simple_current = volumes_simple; } if (volumes_loops == NULL) { boolean current_volume_loops_found = FALSE; int i; for (i = 0; volumes_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = volumes_list[i].value; char *text = volumes_list[i].text; ti->node_top = &volumes_loops; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_LOOPS); pushTreeInfo(&volumes_loops, ti); if (value == setup.volume_loops) current_volume_loops_found = TRUE; } if (!current_volume_loops_found) { // add entry for non-preset volume value TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = setup.volume_loops; ti->node_top = &volumes_loops; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%d %% (Current)", value); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_LOOPS); pushTreeInfo(&volumes_loops, ti); } /* sort volume values to start with lowest volume value */ sortTreeInfo(&volumes_loops); /* set current volume value to configured volume value */ volume_loops_current = getTreeInfoFromIdentifier(volumes_loops,i_to_a(setup.volume_loops)); /* if that fails, set current volume to reliable default value */ if (volume_loops_current == NULL) volume_loops_current = getTreeInfoFromIdentifier(volumes_loops, i_to_a(100)); /* if that also fails, set current volume to first available value */ if (volume_loops_current == NULL) volume_loops_current = volumes_loops; } if (volumes_music == NULL) { boolean current_volume_music_found = FALSE; int i; for (i = 0; volumes_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = volumes_list[i].value; char *text = volumes_list[i].text; ti->node_top = &volumes_music; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_MUSIC); pushTreeInfo(&volumes_music, ti); if (value == setup.volume_music) current_volume_music_found = TRUE; } if (!current_volume_music_found) { // add entry for non-preset volume value TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = setup.volume_music; ti->node_top = &volumes_music; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%d %% (Current)", value); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_VOLUME_MUSIC); pushTreeInfo(&volumes_music, ti); } /* sort volume values to start with lowest volume value */ sortTreeInfo(&volumes_music); /* set current volume value to configured volume value */ volume_music_current = getTreeInfoFromIdentifier(volumes_music,i_to_a(setup.volume_music)); /* if that fails, set current volume to reliable default value */ if (volume_music_current == NULL) volume_music_current = getTreeInfoFromIdentifier(volumes_music, i_to_a(100)); /* if that also fails, set current volume to first available value */ if (volume_music_current == NULL) volume_music_current = volumes_music; } setup.volume_simple = atoi(volume_simple_current->identifier); setup.volume_loops = atoi(volume_loops_current->identifier); setup.volume_music = atoi(volume_music_current->identifier); /* needed for displaying volume text instead of identifier */ volume_simple_text = volume_simple_current->name; volume_loops_text = volume_loops_current->name; volume_music_text = volume_music_current->name; setup_mode = SETUP_MODE_SOUND; DrawSetupScreen(); } static void execSetupChooseTouchControls() { setup_mode = SETUP_MODE_CHOOSE_TOUCH_CONTROL; DrawSetupScreen(); } static void execSetupChooseMoveDistance() { setup_mode = SETUP_MODE_CHOOSE_MOVE_DISTANCE; DrawSetupScreen(); } static void execSetupChooseDropDistance() { setup_mode = SETUP_MODE_CHOOSE_DROP_DISTANCE; DrawSetupScreen(); } static void execSetupTouch() { if (touch_controls == NULL) { int i; for (i = 0; touch_controls_list[i].value != NULL; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; char *value = touch_controls_list[i].value; char *text = touch_controls_list[i].text; ti->node_top = &touch_controls; ti->sort_priority = i; sprintf(identifier, "%s", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_TOUCH_CONTROL); pushTreeInfo(&touch_controls, ti); } /* sort touch control values to start with lowest touch control value */ sortTreeInfo(&touch_controls); /* set current touch control value to configured touch control value */ touch_control_current = getTreeInfoFromIdentifier(touch_controls, setup.touch.control_type); /* if that fails, set current touch control to reliable default value */ if (touch_control_current == NULL) touch_control_current = getTreeInfoFromIdentifier(touch_controls, TOUCH_CONTROL_DEFAULT); /* if that also fails, set current touch control to first available value */ if (touch_control_current == NULL) touch_control_current = touch_controls; } if (move_distances == NULL) { int i; for (i = 0; distances_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = distances_list[i].value; char *text = distances_list[i].text; ti->node_top = &move_distances; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_MOVE_DISTANCE); pushTreeInfo(&move_distances, ti); } /* sort distance values to start with lowest distance value */ sortTreeInfo(&move_distances); /* set current distance value to configured distance value */ move_distance_current = getTreeInfoFromIdentifier(move_distances, i_to_a(setup.touch.move_distance)); /* if that fails, set current distance to reliable default value */ if (move_distance_current == NULL) move_distance_current = getTreeInfoFromIdentifier(move_distances, i_to_a(1)); /* if that also fails, set current distance to first available value */ if (move_distance_current == NULL) move_distance_current = move_distances; } if (drop_distances == NULL) { int i; for (i = 0; distances_list[i].value != -1; i++) { TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED); char identifier[32], name[32]; int value = distances_list[i].value; char *text = distances_list[i].text; ti->node_top = &drop_distances; ti->sort_priority = value; sprintf(identifier, "%d", value); sprintf(name, "%s", text); setString(&ti->identifier, identifier); setString(&ti->name, name); setString(&ti->name_sorting, name); setString(&ti->infotext, STR_SETUP_CHOOSE_DROP_DISTANCE); pushTreeInfo(&drop_distances, ti); } /* sort distance values to start with lowest distance value */ sortTreeInfo(&drop_distances); /* set current distance value to configured distance value */ drop_distance_current = getTreeInfoFromIdentifier(drop_distances, i_to_a(setup.touch.drop_distance)); /* if that fails, set current distance to reliable default value */ if (drop_distance_current == NULL) drop_distance_current = getTreeInfoFromIdentifier(drop_distances, i_to_a(1)); /* if that also fails, set current distance to first available value */ if (drop_distance_current == NULL) drop_distance_current = drop_distances; } setup.touch.control_type = touch_control_current->identifier; setup.touch.move_distance = atoi(move_distance_current->identifier); setup.touch.drop_distance = atoi(drop_distance_current->identifier); /* needed for displaying volume text instead of identifier */ touch_controls_text = touch_control_current->name; move_distance_text = move_distance_current->name; drop_distance_text = drop_distance_current->name; setup_mode = SETUP_MODE_TOUCH; DrawSetupScreen(); } static void execSetupArtwork() { #if 0 printf("::: '%s', '%s', '%s'\n", artwork.gfx_current->subdir, artwork.gfx_current->fullpath, artwork.gfx_current->basepath); #endif setup.graphics_set = artwork.gfx_current->identifier; setup.sounds_set = artwork.snd_current->identifier; setup.music_set = artwork.mus_current->identifier; /* needed if last screen (setup choice) changed graphics, sounds or music */ ReloadCustomArtwork(0); /* needed for displaying artwork name instead of artwork identifier */ graphics_set_name = artwork.gfx_current->name; sounds_set_name = artwork.snd_current->name; music_set_name = artwork.mus_current->name; setup_mode = SETUP_MODE_ARTWORK; DrawSetupScreen(); } static void execSetupChooseGraphics() { setup_mode = SETUP_MODE_CHOOSE_GRAPHICS; DrawSetupScreen(); } static void execSetupChooseSounds() { setup_mode = SETUP_MODE_CHOOSE_SOUNDS; DrawSetupScreen(); } static void execSetupChooseMusic() { setup_mode = SETUP_MODE_CHOOSE_MUSIC; DrawSetupScreen(); } static void execSetupInput() { setup_mode = SETUP_MODE_INPUT; DrawSetupScreen(); } static void execSetupShortcuts() { setup_mode = SETUP_MODE_SHORTCUTS; DrawSetupScreen(); } static void execSetupShortcuts1() { setup_mode = SETUP_MODE_SHORTCUTS_1; DrawSetupScreen(); } static void execSetupShortcuts2() { setup_mode = SETUP_MODE_SHORTCUTS_2; DrawSetupScreen(); } static void execSetupShortcuts3() { setup_mode = SETUP_MODE_SHORTCUTS_3; DrawSetupScreen(); } static void execSetupShortcuts4() { setup_mode = SETUP_MODE_SHORTCUTS_4; DrawSetupScreen(); } static void execSetupShortcuts5() { setup_mode = SETUP_MODE_SHORTCUTS_5; DrawSetupScreen(); } static void execExitSetup() { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } static void execSaveAndExitSetup() { SaveSetup(); execExitSetup(); } static struct TokenInfo setup_info_main[] = { { TYPE_ENTER_MENU, execSetupGame, STR_SETUP_GAME }, { TYPE_ENTER_MENU, execSetupEditor, STR_SETUP_EDITOR }, { TYPE_ENTER_MENU, execSetupGraphics, STR_SETUP_GRAPHICS }, { TYPE_ENTER_MENU, execSetupSound, STR_SETUP_SOUND }, { TYPE_ENTER_MENU, execSetupArtwork, STR_SETUP_ARTWORK }, { TYPE_ENTER_MENU, execSetupInput, STR_SETUP_INPUT }, { TYPE_ENTER_MENU, execSetupTouch, STR_SETUP_TOUCH }, { TYPE_ENTER_MENU, execSetupShortcuts, STR_SETUP_SHORTCUTS }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execExitSetup, STR_SETUP_EXIT }, { TYPE_LEAVE_MENU, execSaveAndExitSetup, STR_SETUP_SAVE_AND_EXIT }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_game[] = { { TYPE_SWITCH, &setup.team_mode, "Team-Mode (Multi-Player):" }, { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" }, { TYPE_SWITCH, &setup.time_limit, "Time Limit:" }, { TYPE_SWITCH, &setup.handicap, "Handicap:" }, { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" }, { TYPE_SWITCH, &setup.increment_levels,"Increment Solved Levels:" }, { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" }, { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" }, { TYPE_STRING, &game_speed_text, "" }, #if 1 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay:" }, { TYPE_STRING, &scroll_delay_text, "" }, #endif { TYPE_ENTER_LIST, execSetupChooseSnapshotMode,"Game Engine Snapshot Mode:" }, { TYPE_STRING, &snapshot_mode_text, "" }, { TYPE_SWITCH, &setup.show_snapshot_buttons,"Show Snapshot Buttons:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_editor[] = { #if 0 { TYPE_SWITCH, &setup.editor.el_boulderdash, "Boulder Dash:" }, { TYPE_SWITCH, &setup.editor.el_emerald_mine, "Emerald Mine:" }, { TYPE_SWITCH, &setup.editor.el_emerald_mine_club, "Emerald Mine Club:" }, { TYPE_SWITCH, &setup.editor.el_more, "Rocks'n'Diamonds:" }, { TYPE_SWITCH, &setup.editor.el_sokoban, "Sokoban:" }, { TYPE_SWITCH, &setup.editor.el_supaplex, "Supaplex:" }, { TYPE_SWITCH, &setup.editor.el_diamond_caves, "Diamond Caves II:" }, { TYPE_SWITCH, &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" }, { TYPE_SWITCH, &setup.editor.el_chars, "Text Characters:" }, { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" }, #endif { TYPE_SWITCH, &setup.editor.el_classic, "Classic Elements:" }, { TYPE_SWITCH, &setup.editor.el_custom, "Custom & Group Elements:" }, #if 0 { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" }, #endif { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" }, { TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" }, { TYPE_EMPTY, NULL, "" }, #if 0 { TYPE_SWITCH, &setup.editor.el_by_game, "Show elements by game:" }, { TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" }, { TYPE_EMPTY, NULL, "" }, #endif { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_graphics[] = { #if defined(TARGET_SDL2) && !defined(PLATFORM_ANDROID) { TYPE_SWITCH, &setup.fullscreen, "Fullscreen:" }, { TYPE_ENTER_LIST, execSetupChooseWindowSize, "Window Scaling:" }, { TYPE_STRING, &window_size_text, "" }, { TYPE_ENTER_LIST, execSetupChooseScalingType, "Anti-Aliasing:" }, { TYPE_STRING, &scaling_type_text, "" }, { TYPE_ENTER_LIST, execSetupChooseRenderingMode, "Special Rendering:" }, { TYPE_STRING, &rendering_mode_text, "" }, #endif #if 0 { TYPE_ENTER_LIST, execSetupChooseScrollDelay, "Scroll Delay:" }, { TYPE_STRING, &scroll_delay_text, "" }, #endif { TYPE_SWITCH, &setup.fade_screens, "Fade Screens:" }, { TYPE_SWITCH, &setup.quick_switch, "Quick Player Focus Switch:" }, { TYPE_SWITCH, &setup.quick_doors, "Quick Menu Doors:" }, { TYPE_SWITCH, &setup.show_titlescreen,"Show Title Screens:" }, { TYPE_SWITCH, &setup.toons, "Show Menu Animations:" }, { TYPE_ECS_AGA, &setup.prefer_aga_graphics,"EMC graphics preference:" }, { TYPE_SWITCH, &setup.sp_show_border_elements,"Supaplex Border Elements:" }, { TYPE_SWITCH, &setup.small_game_graphics, "Small Game Graphics:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_sound[] = { { TYPE_SWITCH, &setup.sound_simple, "Sound Effects (Normal):" }, { TYPE_SWITCH, &setup.sound_loops, "Sound Effects (Looping):" }, { TYPE_SWITCH, &setup.sound_music, "Music:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_ENTER_LIST, execSetupChooseVolumeSimple, "Sound Volume (Normal):" }, { TYPE_STRING, &volume_simple_text, "" }, { TYPE_ENTER_LIST, execSetupChooseVolumeLoops, "Sound Volume (Looping):" }, { TYPE_STRING, &volume_loops_text, "" }, { TYPE_ENTER_LIST, execSetupChooseVolumeMusic, "Music Volume:" }, { TYPE_STRING, &volume_music_text, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_artwork[] = { { TYPE_ENTER_LIST, execSetupChooseGraphics,"Custom Graphics:" }, { TYPE_STRING, &graphics_set_name, "" }, { TYPE_ENTER_LIST, execSetupChooseSounds, "Custom Sounds:" }, { TYPE_STRING, &sounds_set_name, "" }, { TYPE_ENTER_LIST, execSetupChooseMusic, "Custom Music:" }, { TYPE_STRING, &music_set_name, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_YES_NO_AUTO,&setup.override_level_graphics,"Override Level Graphics:"}, { TYPE_YES_NO_AUTO,&setup.override_level_sounds, "Override Level Sounds:" }, { TYPE_YES_NO_AUTO,&setup.override_level_music, "Override Level Music:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_input[] = { { TYPE_SWITCH, NULL, "Player:" }, { TYPE_SWITCH, NULL, "Device:" }, { TYPE_SWITCH, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_touch[] = { { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" }, { TYPE_STRING, &touch_controls_text, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_touch_wipe_gestures[] = { { TYPE_ENTER_LIST, execSetupChooseTouchControls, "Touch Control Type:" }, { TYPE_STRING, &touch_controls_text, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_ENTER_LIST, execSetupChooseMoveDistance, "Move Trigger Distance:" }, { TYPE_STRING, &move_distance_text, "" }, { TYPE_ENTER_LIST, execSetupChooseDropDistance, "Drop Trigger Distance:" }, { TYPE_STRING, &drop_distance_text, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts[] = { { TYPE_ENTER_MENU, execSetupShortcuts1, "Various Keys" }, { TYPE_ENTER_MENU, execSetupShortcuts2, "Player Focus" }, { TYPE_ENTER_MENU, execSetupShortcuts3, "Tape Buttons" }, { TYPE_ENTER_MENU, execSetupShortcuts4, "Sound & Music" }, { TYPE_ENTER_MENU, execSetupShortcuts5, "TAS Snap Keys" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_1[] = { { TYPE_KEYTEXT, NULL, "Quick Save Game to Tape:", }, { TYPE_KEY, &setup.shortcut.save_game, "" }, { TYPE_KEYTEXT, NULL, "Quick Load Game from Tape:", }, { TYPE_KEY, &setup.shortcut.load_game, "" }, { TYPE_KEYTEXT, NULL, "Start Game & Toggle Pause:", }, { TYPE_KEY, &setup.shortcut.toggle_pause, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_YES_NO, &setup.ask_on_escape, "Ask on 'Esc' Key:" }, { TYPE_YES_NO, &setup.ask_on_escape_editor, "Ask on 'Esc' Key (Editor):" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_2[] = { { TYPE_KEYTEXT, NULL, "Set Focus to Player 1:", }, { TYPE_KEY, &setup.shortcut.focus_player[0], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to Player 2:", }, { TYPE_KEY, &setup.shortcut.focus_player[1], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to Player 3:", }, { TYPE_KEY, &setup.shortcut.focus_player[2], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to Player 4:", }, { TYPE_KEY, &setup.shortcut.focus_player[3], "" }, { TYPE_KEYTEXT, NULL, "Set Focus to All Players:", }, { TYPE_KEY, &setup.shortcut.focus_player_all, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_3[] = { { TYPE_KEYTEXT, NULL, "Eject Tape:", }, { TYPE_KEY, &setup.shortcut.tape_eject, "" }, { TYPE_KEYTEXT, NULL, "Warp / Single Step:", }, { TYPE_KEY, &setup.shortcut.tape_extra, "" }, { TYPE_KEYTEXT, NULL, "Stop Tape:", }, { TYPE_KEY, &setup.shortcut.tape_stop, "" }, { TYPE_KEYTEXT, NULL, "Pause / Unpause Tape:",}, { TYPE_KEY, &setup.shortcut.tape_pause, "" }, { TYPE_KEYTEXT, NULL, "Record Tape:", }, { TYPE_KEY, &setup.shortcut.tape_record, "" }, { TYPE_KEYTEXT, NULL, "Play Tape:", }, { TYPE_KEY, &setup.shortcut.tape_play, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_4[] = { { TYPE_KEYTEXT, NULL, "Toggle Sound Effects (Normal):", }, { TYPE_KEY, &setup.shortcut.sound_simple, "" }, { TYPE_KEYTEXT, NULL, "Toggle Sound Effects (Looping):", }, { TYPE_KEY, &setup.shortcut.sound_loops, "" }, { TYPE_KEYTEXT, NULL, "Toggle Music:", }, { TYPE_KEY, &setup.shortcut.sound_music, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static struct TokenInfo setup_info_shortcuts_5[] = { { TYPE_KEYTEXT, NULL, "Snap Left:", }, { TYPE_KEY, &setup.shortcut.snap_left, "" }, { TYPE_KEYTEXT, NULL, "Snap Right:", }, { TYPE_KEY, &setup.shortcut.snap_right, "" }, { TYPE_KEYTEXT, NULL, "Snap Up:", }, { TYPE_KEY, &setup.shortcut.snap_up, "" }, { TYPE_KEYTEXT, NULL, "Snap Down:", }, { TYPE_KEY, &setup.shortcut.snap_down, "" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupShortcuts, "Back" }, { 0, NULL, NULL } }; static Key getSetupKey() { Key key = KSYM_UNDEFINED; boolean got_key_event = FALSE; while (!got_key_event) { Event event; if (NextValidEvent(&event)) { switch (event.type) { case EVENT_KEYPRESS: { key = GetEventKey((KeyEvent *)&event, TRUE); /* press 'Escape' or 'Enter' to keep the existing key binding */ if (key == KSYM_Escape || key == KSYM_Return) key = KSYM_UNDEFINED; /* keep old value */ got_key_event = TRUE; } break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; default: HandleOtherEvents(&event); break; } } BackToFront(); } return key; } static int getSetupValueFont(int type, void *value) { if (type & TYPE_GHOSTED) return FONT_OPTION_OFF; else if (type & TYPE_KEY) return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1); else if (type & TYPE_STRING) return FONT_VALUE_2; else if (type & TYPE_ECS_AGA) return FONT_VALUE_1; else if (type & TYPE_BOOLEAN_STYLE) return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF); else if (type & TYPE_YES_NO_AUTO) return (*(int *)value == AUTO ? FONT_OPTION_ON : *(int *)value == FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON); else return FONT_VALUE_1; } static int getSetupValueFontNarrow(int type, int font_nr) { return (font_nr == FONT_VALUE_1 ? FONT_VALUE_NARROW : font_nr == FONT_OPTION_ON ? FONT_OPTION_ON_NARROW : font_nr == FONT_OPTION_OFF ? FONT_OPTION_OFF_NARROW : font_nr); } static void drawSetupValue(int screen_pos, int setup_info_pos_raw) { int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw); struct TokenInfo *si = &setup_info[si_pos]; boolean font_draw_xoffset_modified = FALSE; boolean scrollbar_needed = (num_setup_info < max_setup_info); int font_draw_xoffset_old = -1; int xoffset = (scrollbar_needed ? -1 : 0); int menu_screen_value_xpos = MENU_SCREEN_VALUE_XPOS + xoffset; int menu_screen_max_xpos = MENU_SCREEN_MAX_XPOS + xoffset; int xpos = menu_screen_value_xpos; int ypos = MENU_SCREEN_START_YPOS + screen_pos; int startx = mSX + xpos * 32; int starty = mSY + ypos * 32; int font_nr, font_nr_default, font_width_default; int type = si->type; void *value = si->value; char *value_string = getSetupValue(type, value); int i; if (value_string == NULL) return; if (type & TYPE_KEY) { xpos = MENU_SCREEN_START_XPOS; if (type & TYPE_QUERY) value_string = ""; } else if (type & TYPE_STRING) { int max_value_len = (SCR_FIELDX - 2) * 2; xpos = MENU_SCREEN_START_XPOS; if (strlen(value_string) > max_value_len) value_string[max_value_len] = '\0'; } else if (type & TYPE_YES_NO_AUTO) { xpos = menu_screen_value_xpos - 1; } startx = mSX + xpos * 32; starty = mSY + ypos * 32; font_nr_default = getSetupValueFont(type, value); font_width_default = getFontWidth(font_nr_default); font_nr = font_nr_default; // special check if right-side setup values moved left due to scrollbar if (scrollbar_needed && xpos > MENU_SCREEN_START_XPOS) { int max_menu_text_length = 26; // maximum text length for classic menu int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; int text_startx = mSX + MENU_SCREEN_START_XPOS * 32; int text_font_nr = getMenuTextFont(FONT_MENU_2); int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset; int text_width = max_menu_text_length * getFontWidth(text_font_nr); if (startx + font_xoffset < text_startx + text_width + text_font_xoffset) { xpos += 1; startx = mSX + xpos * 32; font_nr = getSetupValueFontNarrow(type, font_nr); } } /* downward compatibility correction for Juergen Bonhagen's menu settings */ if (setup_mode != SETUP_MODE_INPUT) { int max_menu_text_length_big = (menu_screen_value_xpos - MENU_SCREEN_START_XPOS); int max_menu_text_length_medium = max_menu_text_length_big * 2; int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */ int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset; int text_startx = mSX + MENU_SCREEN_START_XPOS * 32; int text_font_nr = getMenuTextFont(FONT_MENU_2); int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset; int text_width = max_menu_text_length_medium * getFontWidth(text_font_nr); boolean correct_font_draw_xoffset = FALSE; if (xpos == MENU_SCREEN_START_XPOS && startx + font1_xoffset < text_startx + text_font_xoffset) correct_font_draw_xoffset = TRUE; if (xpos == menu_screen_value_xpos && startx + font2_xoffset < text_startx + text_width + text_font_xoffset) correct_font_draw_xoffset = TRUE; /* check if setup value would overlap with setup text when printed */ /* (this can happen for extreme/wrong values for font draw offset) */ if (correct_font_draw_xoffset) { font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset; font_draw_xoffset_modified = TRUE; if (type & TYPE_KEY) getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr); else if (!(type & TYPE_STRING)) getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 - max_menu_text_length_medium * (16 - getFontWidth(text_font_nr)); } } for (i = 0; i <= menu_screen_max_xpos - xpos; i++) DrawText(startx + i * font_width_default, starty, " ", font_nr_default); DrawText(startx, starty, value_string, font_nr); if (font_draw_xoffset_modified) getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old; } static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx) { int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw); struct TokenInfo *si = &setup_info[si_pos]; if (si->type & TYPE_BOOLEAN_STYLE) { *(boolean *)si->value ^= TRUE; } else if (si->type & TYPE_YES_NO_AUTO) { *(int *)si->value = (dx == -1 ? (*(int *)si->value == AUTO ? TRUE : *(int *)si->value == TRUE ? FALSE : AUTO) : (*(int *)si->value == TRUE ? AUTO : *(int *)si->value == AUTO ? FALSE : TRUE)); } else if (si->type & TYPE_KEY) { Key key; si->type |= TYPE_QUERY; drawSetupValue(screen_pos, setup_info_pos_raw); si->type &= ~TYPE_QUERY; key = getSetupKey(); if (key != KSYM_UNDEFINED) *(Key *)si->value = key; } drawSetupValue(screen_pos, setup_info_pos_raw); // fullscreen state may have changed at this point if (si->value == &setup.fullscreen) ToggleFullscreenOrChangeWindowScalingIfNeeded(); } static struct TokenInfo *getSetupInfoFinal(struct TokenInfo *setup_info_orig) { static struct TokenInfo *setup_info_hide = NULL; int list_size = 0; int list_pos = 0; int i; /* determine maximum list size of target list */ while (setup_info_orig[list_size++].type != 0); /* free, allocate and clear memory for target list */ checked_free(setup_info_hide); setup_info_hide = checked_calloc(list_size * sizeof(struct TokenInfo)); /* copy setup info list without setup entries marked as hidden */ for (i = 0; setup_info_orig[i].type != 0; i++) if (!hideSetupEntry(setup_info_orig[i].value)) setup_info_hide[list_pos++] = setup_info_orig[i]; return setup_info_hide; } static void DrawSetupScreen_Generic() { int fade_mask = REDRAW_FIELD; boolean redraw_all = FALSE; char *title_string = NULL; int i; if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; UnmapAllGadgets(); FadeMenuSoundsAndMusic(); FreeScreenGadgets(); CreateScreenGadgets(); if (redraw_mask & REDRAW_ALL) redraw_all = TRUE; FadeOut(fade_mask); /* needed if different viewport properties defined for setup screen */ ChangeViewportPropertiesIfNeeded(); SetMainBackgroundImage(IMG_BACKGROUND_SETUP); ClearField(); OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); if (setup_mode == SETUP_MODE_MAIN) { setup_info = setup_info_main; title_string = STR_SETUP_MAIN; } else if (setup_mode == SETUP_MODE_GAME) { setup_info = setup_info_game; title_string = STR_SETUP_GAME; } else if (setup_mode == SETUP_MODE_EDITOR) { setup_info = setup_info_editor; title_string = STR_SETUP_EDITOR; } else if (setup_mode == SETUP_MODE_GRAPHICS) { setup_info = setup_info_graphics; title_string = STR_SETUP_GRAPHICS; } else if (setup_mode == SETUP_MODE_SOUND) { setup_info = setup_info_sound; title_string = STR_SETUP_SOUND; } else if (setup_mode == SETUP_MODE_ARTWORK) { setup_info = setup_info_artwork; title_string = STR_SETUP_ARTWORK; } else if (setup_mode == SETUP_MODE_TOUCH) { setup_info = setup_info_touch; title_string = STR_SETUP_TOUCH; if (strEqual(setup.touch.control_type, TOUCH_CONTROL_WIPE_GESTURES)) setup_info = setup_info_touch_wipe_gestures; } else if (setup_mode == SETUP_MODE_SHORTCUTS) { setup_info = setup_info_shortcuts; title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_1) { setup_info = setup_info_shortcuts_1; title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_2) { setup_info = setup_info_shortcuts_2; title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_3) { setup_info = setup_info_shortcuts_3; title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_4) { setup_info = setup_info_shortcuts_4; title_string = STR_SETUP_SHORTCUTS; } else if (setup_mode == SETUP_MODE_SHORTCUTS_5) { setup_info = setup_info_shortcuts_5; title_string = STR_SETUP_SHORTCUTS; } /* use modified setup info without setup entries marked as hidden */ setup_info = getSetupInfoFinal(setup_info); DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string); // determine maximal number of setup entries that can be displayed on screen num_setup_info = 0; for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) num_setup_info++; // determine maximal number of setup entries available for this setup screen max_setup_info = 0; for (i = 0; setup_info[i].type != 0; i++) max_setup_info++; HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE); MapScreenGadgets(max_setup_info); if (redraw_all) redraw_mask = fade_mask = REDRAW_ALL; DrawMaskedBorder(fade_mask); FadeIn(fade_mask); } void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button) { menu_info = setup_info; HandleMenuScreen(mx, my, dx, dy, button, setup_mode, num_setup_info, max_setup_info); } void DrawSetupScreen_Input() { int i; FadeOut(REDRAW_FIELD); ClearField(); setup_info = setup_info_input; DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, STR_SETUP_INPUT); for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++) { if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST)) initCursor(i, IMG_MENU_BUTTON_ENTER_MENU); else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST)) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); else if (setup_info[i].type & ~TYPE_SKIP_ENTRY) initCursor(i, IMG_MENU_BUTTON); DrawCursorAndText_Setup(i, -1, FALSE); } /* create gadgets for setup input menu screen */ FreeScreenGadgets(); CreateScreenGadgets(); /* map gadgets for setup input menu screen */ MapScreenMenuGadgets(SCREEN_MASK_INPUT); HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE); FadeIn(REDRAW_FIELD); } static void setJoystickDeviceToNr(char *device_name, int device_nr) { if (device_name == NULL) return; if (device_nr < 0 || device_nr >= MAX_PLAYERS) device_nr = 0; if (strlen(device_name) > 1) { 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, getDeviceNameFromJoystickNr(device_nr), strlen(device_name)); } static void drawPlayerSetupInputInfo(int player_nr, boolean active) { int i; static struct SetupKeyboardInfo custom_key; static struct { Key *key; char *text; } custom[] = { { &custom_key.left, "Axis/Pad Left" }, { &custom_key.right, "Axis/Pad Right" }, { &custom_key.up, "Axis/Pad Up" }, { &custom_key.down, "Axis/Pad Down" }, { &custom_key.snap, "Button 1/A/X" }, { &custom_key.drop, "Button 2/B/Y" } }; static char *joystick_name[MAX_PLAYERS] = { "Joystick1", "Joystick2", "Joystick3", "Joystick4" }; int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1); custom_key = setup.input[player_nr].key; DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1), FONT_INPUT_1_ACTIVE); ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY, TILEX, TILEY); DrawFixedGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY, PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0); if (setup.input[player_nr].use_joystick) { char *device_name = setup.input[player_nr].joy.device_name; int joystick_nr = getJoystickNrFromDeviceName(device_name); boolean joystick_active = CheckJoystickOpened(joystick_nr); char *text = joystick_name[joystick_nr]; int font_nr = (joystick_active ? FONT_VALUE_1 : FONT_VALUE_OLD); DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr); DrawText(mSX + 32, mSY + 4 * 32, "Configure", text_font_nr); } else { DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1); DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr); } DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1); drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT); drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT); drawCursorXY(1, 6, IMG_MENU_BUTTON_UP); drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN); DrawText(mSX + 2 * 32, mSY + 6 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 2 * 32, mSY + 7 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 2 * 32, mSY + 8 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 2 * 32, mSY + 9 * 32, ":", FONT_VALUE_OLD); DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD); DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD); for (i = 0; i < 6; i++) { int ypos = 6 + i + (i > 3 ? i-3 : 0); DrawText(mSX + 3 * 32, mSY + ypos * 32, " ", FONT_VALUE_1); DrawText(mSX + 3 * 32, mSY + ypos * 32, (setup.input[player_nr].use_joystick ? custom[i].text : getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1); } } static int input_player_nr = 0; void HandleSetupScreen_Input_Player(int step, int direction) { int old_player_nr = input_player_nr; int new_player_nr; new_player_nr = old_player_nr + step * direction; if (new_player_nr < 0) new_player_nr = 0; if (new_player_nr > MAX_PLAYERS - 1) new_player_nr = MAX_PLAYERS - 1; if (new_player_nr != old_player_nr) { input_player_nr = new_player_nr; drawPlayerSetupInputInfo(input_player_nr, FALSE); } } void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) { static int choice = 0; int x = 0; int y = choice; int pos_start = SETUPINPUT_SCREEN_POS_START; int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1; int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2; int pos_end = SETUPINPUT_SCREEN_POS_END; if (button == MB_MENU_INITIALIZE) { drawPlayerSetupInputInfo(input_player_nr, (choice == 2)); DrawCursorAndText_Setup(choice, -1, TRUE); return; } else if (button == MB_MENU_LEAVE) { setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); InitJoysticks(); return; } if (mx || my) /* mouse input */ { x = (mx - mSX) / 32; y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; } else if (dx || dy) /* keyboard input */ { if (dx && choice == 0) x = (dx < 0 ? 10 : 12); else if ((dx && choice == 1) || (dx == -1 && choice == pos_end)) button = MB_MENU_CHOICE; else if (dy) y = choice + dy; if (y >= pos_empty1 && y <= pos_empty2) y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1); } if (y == 0 && dx != 0 && button) { HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1); } else if (IN_VIS_FIELD(x, y) && // (does not use "IN_VIS_MENU()" yet) y >= pos_start && y <= pos_end && !(y >= pos_empty1 && y <= pos_empty2)) { if (button) { if (y != choice) { DrawCursorAndText_Setup(choice, -1, FALSE); DrawCursorAndText_Setup(y, -1, TRUE); drawPlayerSetupInputInfo(input_player_nr, (y == 2)); choice = y; } } else { if (y == 1) { char *device_name = setup.input[input_player_nr].joy.device_name; if (!setup.input[input_player_nr].use_joystick) { int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1); setJoystickDeviceToNr(device_name, new_device_nr); setup.input[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[input_player_nr].use_joystick = FALSE; else setJoystickDeviceToNr(device_name, new_device_nr); } drawPlayerSetupInputInfo(input_player_nr, FALSE); } else if (y == 2) { if (setup.input[input_player_nr].use_joystick) ConfigureJoystick(input_player_nr); else CustomizeKeyboard(input_player_nr); } else if (y == pos_end) { InitJoysticks(); FadeSetLeaveMenu(); setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); } } } } void CustomizeKeyboard(int player_nr) { int i; int step_nr; boolean finished = FALSE; static struct SetupKeyboardInfo custom_key; static struct { Key *key; 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.drop, "Drop Element" } }; /* read existing key bindings from player setup */ custom_key = setup.input[player_nr].key; FadeSetEnterMenu(); FadeOut(REDRAW_FIELD); ClearField(); DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input"); step_nr = 0; DrawText(mSX, mSY + (2 + 2 * step_nr) * 32, customize_step[step_nr].text, FONT_INPUT_1_ACTIVE); DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32, "Key:", FONT_INPUT_1_ACTIVE); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD); FadeIn(REDRAW_FIELD); while (!finished) { Event event; if (NextValidEvent(&event)) { switch (event.type) { case EVENT_KEYPRESS: { Key key = GetEventKey((KeyEvent *)&event, FALSE); if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6)) { if (key == KSYM_Escape) FadeSkipNextFadeIn(); finished = TRUE; break; } /* all keys configured -- wait for "Escape" or "Return" key */ if (step_nr == 6) break; /* press 'Enter' to keep the existing key binding */ if (key == KSYM_Return) key = *customize_step[step_nr].key; /* check if key already used */ for (i = 0; i < step_nr; i++) if (*customize_step[i].key == key) break; if (i < step_nr) break; /* got new key binding */ *customize_step[step_nr].key = key; DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, " ", FONT_VALUE_1); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(key), FONT_VALUE_1); step_nr++; /* un-highlight last query */ DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32, customize_step[step_nr - 1].text, FONT_MENU_1); DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32, "Key:", FONT_MENU_1); /* press 'Enter' to leave */ if (step_nr == 6) { DrawText(mSX + 16, mSY + 15 * 32 + 16, "Press Enter", FONT_TITLE_1); break; } /* query next key binding */ DrawText(mSX, mSY + (2 + 2 * step_nr) * 32, customize_step[step_nr].text, FONT_INPUT_1_ACTIVE); DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32, "Key:", FONT_INPUT_1_ACTIVE); DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32, getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD); } break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; default: HandleOtherEvents(&event); break; } } BackToFront(); } /* write new key bindings back to player setup */ setup.input[player_nr].key = custom_key; DrawSetupScreen_Input(); } /* game controller mapping generator by Gabriel Jacobo */ #define MARKER_BUTTON 1 #define MARKER_AXIS_X 2 #define MARKER_AXIS_Y 3 static boolean ConfigureJoystickMapButtonsAndAxes(SDL_Joystick *joystick) { #if defined(TARGET_SDL2) static boolean bitmaps_initialized = FALSE; boolean screen_initialized = FALSE; static Bitmap *controller, *button, *axis_x, *axis_y; char *name; boolean success = TRUE; boolean done = FALSE, next = FALSE; Event event; int alpha = 200, alpha_step = -1; int alpha_ticks = 0; char mapping[4096], temp[4096]; int font_name = MENU_SETUP_FONT_TITLE; int font_info = MENU_SETUP_FONT_TEXT; int spacing_name = menu.line_spacing_setup[SETUP_MODE_INPUT]; int spacing_line = menu.line_spacing_setup[SETUP_MODE_INPUT]; int spacing_para = menu.paragraph_spacing_setup[SETUP_MODE_INPUT]; int ystep_name = getMenuTextStep(spacing_name, font_name); int ystep_line = getMenuTextStep(spacing_line, font_info); int ystep_para = getMenuTextStep(spacing_para, font_info); int i, j; struct { int x, y; int marker; char *field; int axis, button, hat, hat_value; char mapping[4096]; } *step, *prev_step, steps[] = { { 356, 155, MARKER_BUTTON, "a", }, { 396, 122, MARKER_BUTTON, "b", }, { 320, 125, MARKER_BUTTON, "x", }, { 358, 95, MARKER_BUTTON, "y", }, { 162, 125, MARKER_BUTTON, "back", }, { 216, 125, MARKER_BUTTON, "guide", }, { 271, 125, MARKER_BUTTON, "start", }, { 110, 200, MARKER_BUTTON, "dpleft", }, { 146, 228, MARKER_BUTTON, "dpdown", }, { 178, 200, MARKER_BUTTON, "dpright", }, { 146, 172, MARKER_BUTTON, "dpup", }, { 50, 40, MARKER_BUTTON, "leftshoulder", }, { 88, -10, MARKER_AXIS_Y, "lefttrigger", }, { 382, 40, MARKER_BUTTON, "rightshoulder", }, { 346, -10, MARKER_AXIS_Y, "righttrigger", }, { 73, 141, MARKER_BUTTON, "leftstick", }, { 282, 210, MARKER_BUTTON, "rightstick", }, { 73, 141, MARKER_AXIS_X, "leftx", }, { 73, 141, MARKER_AXIS_Y, "lefty", }, { 282, 210, MARKER_AXIS_X, "rightx", }, { 282, 210, MARKER_AXIS_Y, "righty", }, }; unsigned int event_frame_delay = 0; unsigned int event_frame_delay_value = GAME_FRAME_DELAY; ResetDelayCounter(&event_frame_delay); if (!bitmaps_initialized) { controller = LoadCustomImage("joystick/controller.png"); button = LoadCustomImage("joystick/button.png"); axis_x = LoadCustomImage("joystick/axis_x.png"); axis_y = LoadCustomImage("joystick/axis_y.png"); bitmaps_initialized = TRUE; } name = getFormattedJoystickName(SDL_JoystickName(joystick)); #if DEBUG_JOYSTICKS /* print info about the joystick we are watching */ Error(ERR_DEBUG, "watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick), name); Error(ERR_DEBUG, "joystick has %d axes, %d hats, %d balls, and %d buttons\n", SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick)); #endif /* initialize mapping with GUID and name */ SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), temp, sizeof(temp)); snprintf(mapping, sizeof(mapping), "%s,%s,platform:%s,", temp, name, SDL_GetPlatform()); /* loop through all steps (buttons and axes), getting joystick events */ for (i = 0; i < SDL_arraysize(steps) && !done;) { Bitmap *marker = button; /* initialize with reliable default value */ step = &steps[i]; strcpy(step->mapping, mapping); step->axis = -1; step->button = -1; step->hat = -1; step->hat_value = -1; marker = (step->marker == MARKER_BUTTON ? button : step->marker == MARKER_AXIS_X ? axis_x : step->marker == MARKER_AXIS_Y ? axis_y : marker); next = FALSE; while (!done && !next) { alpha += alpha_step * (int)(SDL_GetTicks() - alpha_ticks) / 5; alpha_ticks = SDL_GetTicks(); if (alpha >= 255) { alpha = 255; alpha_step = -1; } else if (alpha < 128) { alpha = 127; alpha_step = 1; } int controller_x = SX + (SXSIZE - controller->width) / 2; int controller_y = SY + ystep_line; int marker_x = controller_x + step->x; int marker_y = controller_y + step->y; int ystart1 = mSY - 2 * SY + controller_y + controller->height; int ystart2 = ystart1 + ystep_name + ystep_line; ClearField(); DrawTextSCentered(ystart1, font_name, name); DrawTextSCentered(ystart2, font_info, "Press buttons and move axes on"); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "your controller when indicated."); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "(Your controller may look different.)"); ystart2 += ystep_para; #if defined(PLATFORM_ANDROID) DrawTextSCentered(ystart2, font_info, "To correct a mistake,"); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "press the 'back' button."); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "To skip a button or axis,"); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "press the 'menu' button."); #else DrawTextSCentered(ystart2, font_info, "To correct a mistake,"); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "press the 'backspace' key."); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "To skip a button or axis,"); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "press the 'return' key."); ystart2 += ystep_line; DrawTextSCentered(ystart2, font_info, "To exit, press the 'escape' key."); #endif BlitBitmapMasked(controller, drawto, 0, 0, controller->width, controller->height, controller_x, controller_y); SDL_SetSurfaceAlphaMod(marker->surface_masked, alpha); BlitBitmapMasked(marker, drawto, 0, 0, marker->width, marker->height, marker_x, marker_y); if (!screen_initialized) FadeIn(REDRAW_FIELD); else BackToFront(); screen_initialized = TRUE; while (NextValidEvent(&event)) { switch (event.type) { case SDL_JOYAXISMOTION: if (event.jaxis.value > 20000 || event.jaxis.value < -20000) { for (j = 0; j < i; j++) if (steps[j].axis == event.jaxis.axis) break; if (j == i) { if (step->marker != MARKER_AXIS_X && step->marker != MARKER_AXIS_Y) break; step->axis = event.jaxis.axis; strcat(mapping, step->field); snprintf(temp, sizeof(temp), ":a%u,", event.jaxis.axis); strcat(mapping, temp); i++; next = TRUE; } } break; case SDL_JOYHATMOTION: /* ignore centering; we're probably just coming back to the center from the previous item we set */ if (event.jhat.value == SDL_HAT_CENTERED) break; for (j = 0; j < i; j++) if (steps[j].hat == event.jhat.hat && steps[j].hat_value == event.jhat.value) break; if (j == i) { step->hat = event.jhat.hat; step->hat_value = event.jhat.value; strcat(mapping, step->field); snprintf(temp, sizeof(temp), ":h%u.%u,", event.jhat.hat, event.jhat.value ); strcat(mapping, temp); i++; next = TRUE; } break; case SDL_JOYBALLMOTION: break; case SDL_JOYBUTTONUP: for (j = 0; j < i; j++) if (steps[j].button == event.jbutton.button) break; if (j == i) { step->button = event.jbutton.button; strcat(mapping, step->field); snprintf(temp, sizeof(temp), ":b%u,", event.jbutton.button); strcat(mapping, temp); i++; next = TRUE; } break; case SDL_FINGERDOWN: case SDL_MOUSEBUTTONDOWN: /* skip this step */ i++; next = TRUE; break; case SDL_KEYDOWN: if (event.key.keysym.sym == KSYM_BackSpace || event.key.keysym.sym == KSYM_Back) { if (i == 0) { /* leave screen */ success = FALSE; done = TRUE; } /* undo this step */ prev_step = &steps[i - 1]; strcpy(mapping, prev_step->mapping); i--; next = TRUE; break; } if (event.key.keysym.sym == KSYM_space || event.key.keysym.sym == KSYM_Return || event.key.keysym.sym == KSYM_Menu) { /* skip this step */ i++; next = TRUE; break; } if (event.key.keysym.sym == KSYM_Escape) { /* leave screen */ success = FALSE; done = TRUE; } break; case SDL_QUIT: program.exit_function(0); break; default: break; } // do not handle events for longer than standard frame delay period if (DelayReached(&event_frame_delay, event_frame_delay_value)) break; } } } if (success) { #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "New game controller mapping:\n\n%s\n\n", mapping); #endif // activate mapping for this game SDL_GameControllerAddMapping(mapping); // save mapping to personal mappings SaveSetup_AddGameControllerMapping(mapping); } /* wait until the last pending event was removed from event queue */ while (NextValidEvent(&event)); return success; #else return TRUE; #endif } static int ConfigureJoystickMain(int player_nr) { char *device_name = setup.input[player_nr].joy.device_name; int joystick_nr = getJoystickNrFromDeviceName(device_name); boolean joystick_active = CheckJoystickOpened(joystick_nr); int success = FALSE; int i; if (joystick.status == JOYSTICK_NOT_AVAILABLE) return JOYSTICK_NOT_AVAILABLE; if (!joystick_active || !setup.input[player_nr].use_joystick) return JOYSTICK_NOT_AVAILABLE; FadeSetEnterMenu(); FadeOut(REDRAW_FIELD); // close all joystick devices (potentially opened as game controllers) for (i = 0; i < SDL_NumJoysticks(); i++) SDLCloseJoystick(i); // open joystick device as plain joystick to configure as game controller SDL_Joystick *joystick = SDL_JoystickOpen(joystick_nr); // as the joystick was successfully opened before, this should not happen if (joystick == NULL) return FALSE; // create new game controller mapping (buttons and axes) for joystick device success = ConfigureJoystickMapButtonsAndAxes(joystick); // close joystick (and maybe re-open as configured game controller later) SDL_JoystickClose(joystick); // re-open all joystick devices (potentially as game controllers) for (i = 0; i < SDL_NumJoysticks(); i++) SDLOpenJoystick(i); // clear all joystick input actions for all joystick devices SDLClearJoystickState(); return (success ? JOYSTICK_CONFIGURED : JOYSTICK_NOT_CONFIGURED); } void ConfigureJoystick(int player_nr) { boolean state = ConfigureJoystickMain(player_nr); if (state != JOYSTICK_NOT_CONFIGURED) { boolean success = (state == JOYSTICK_CONFIGURED); char *message = (success ? " IS CONFIGURED! " : " NOT AVAILABLE! "); char *device_name = setup.input[player_nr].joy.device_name; int nr = getJoystickNrFromDeviceName(device_name) + 1; int xpos = mSX - SX; int ypos = mSY - SY; unsigned int wait_frame_delay = 0; unsigned int wait_frame_delay_value = 2000; ResetDelayCounter(&wait_frame_delay); ClearField(); DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, " JOYSTICK %d ", nr); DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, message); while (!DelayReached(&wait_frame_delay, wait_frame_delay_value)) BackToFront(); ClearEventQueue(); } DrawSetupScreen_Input(); } void DrawSetupScreen() { if (setup_mode == SETUP_MODE_INPUT) DrawSetupScreen_Input(); else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) DrawChooseTree(&game_speed_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) DrawChooseTree(&scroll_delay_current); else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) DrawChooseTree(&snapshot_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) DrawChooseTree(&window_size_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE) DrawChooseTree(&scaling_type_current); else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING) DrawChooseTree(&rendering_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS) DrawChooseTree(&artwork.gfx_current); else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS) DrawChooseTree(&artwork.snd_current); else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC) DrawChooseTree(&artwork.mus_current); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE) DrawChooseTree(&volume_simple_current); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS) DrawChooseTree(&volume_loops_current); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC) DrawChooseTree(&volume_music_current); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL) DrawChooseTree(&touch_control_current); else if (setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE) DrawChooseTree(&move_distance_current); else if (setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) DrawChooseTree(&drop_distance_current); else DrawSetupScreen_Generic(); PlayMenuSoundsAndMusic(); } void RedrawSetupScreenAfterFullscreenToggle() { if (setup_mode == SETUP_MODE_GRAPHICS || setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) { // update list selection from "setup.window_scaling_percent" execSetupGraphics_setWindowSizes(TRUE); DrawSetupScreen(); } } void HandleSetupScreen(int mx, int my, int dx, int dy, int button) { if (setup_mode == SETUP_MODE_INPUT) HandleSetupScreen_Input(mx, my, dx, dy, button); else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED) HandleChooseTree(mx, my, dx, dy, button, &game_speed_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY) HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current); else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE) HandleChooseTree(mx, my, dx, dy, button, &snapshot_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE) HandleChooseTree(mx, my, dx, dy, button, &window_size_current); else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE) HandleChooseTree(mx, my, dx, dy, button, &scaling_type_current); else if (setup_mode == SETUP_MODE_CHOOSE_RENDERING) HandleChooseTree(mx, my, dx, dy, button, &rendering_mode_current); else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS) HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current); else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS) HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current); else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC) HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE) HandleChooseTree(mx, my, dx, dy, button, &volume_simple_current); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS) HandleChooseTree(mx, my, dx, dy, button, &volume_loops_current); else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC) HandleChooseTree(mx, my, dx, dy, button, &volume_music_current); else if (setup_mode == SETUP_MODE_CHOOSE_TOUCH_CONTROL) HandleChooseTree(mx, my, dx, dy, button, &touch_control_current); else if (setup_mode == SETUP_MODE_CHOOSE_MOVE_DISTANCE) HandleChooseTree(mx, my, dx, dy, button, &move_distance_current); else if (setup_mode == SETUP_MODE_CHOOSE_DROP_DISTANCE) HandleChooseTree(mx, my, dx, dy, button, &drop_distance_current); else HandleSetupScreen_Generic(mx, my, dx, dy, button); } void HandleGameActions() { if (game.restart_game_message != NULL) RequestRestartGame(game.restart_game_message); if (game_status != GAME_MODE_PLAYING) return; GameActions(); /* main game loop */ if (tape.auto_play && !tape.playing) AutoPlayTape(); /* continue automatically playing next tape */ } /* ---------- new screen button stuff -------------------------------------- */ static void getScreenMenuButtonPos(int *x, int *y, int gadget_id) { switch (gadget_id) { case SCREEN_CTRL_ID_PREV_LEVEL: *x = mSX + GDI_ACTIVE_POS(menu.main.button.prev_level.x); *y = mSY + GDI_ACTIVE_POS(menu.main.button.prev_level.y); break; case SCREEN_CTRL_ID_NEXT_LEVEL: *x = mSX + GDI_ACTIVE_POS(menu.main.button.next_level.x); *y = mSY + GDI_ACTIVE_POS(menu.main.button.next_level.y); break; case SCREEN_CTRL_ID_PREV_PLAYER: *x = mSX + TILEX * 10; *y = mSY + TILEY * MENU_SCREEN_START_YPOS; break; case SCREEN_CTRL_ID_NEXT_PLAYER: *x = mSX + TILEX * 12; *y = mSY + TILEY * MENU_SCREEN_START_YPOS; break; default: Error(ERR_EXIT, "unknown gadget ID %d", gadget_id); } } static struct { int gfx_unpressed, gfx_pressed; void (*get_gadget_position)(int *, int *, int); int gadget_id; int screen_mask; char *infotext; } menubutton_info[NUM_SCREEN_MENUBUTTONS] = { { IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_PREV_LEVEL, SCREEN_MASK_MAIN, "last level" }, { IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_NEXT_LEVEL, SCREEN_MASK_MAIN, "next level" }, { IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_PREV_PLAYER, SCREEN_MASK_INPUT, "last player" }, { IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE, getScreenMenuButtonPos, SCREEN_CTRL_ID_NEXT_PLAYER, SCREEN_MASK_INPUT, "next player" }, }; static struct { int gfx_unpressed, gfx_pressed; int x, y; int gadget_id; char *infotext; } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] = { { IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE, -1, -1, /* these values are not constant, but can change at runtime */ SCREEN_CTRL_ID_SCROLL_UP, "scroll up" }, { IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE, -1, -1, /* these values are not constant, but can change at runtime */ SCREEN_CTRL_ID_SCROLL_DOWN, "scroll down" } }; static struct { int gfx_unpressed, gfx_pressed; int x, y; int width, height; int type; int gadget_id; char *infotext; } scrollbar_info[NUM_SCREEN_SCROLLBARS] = { { IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE, -1, -1, /* these values are not constant, but can change at runtime */ -1, -1, /* these values are not constant, but can change at runtime */ GD_TYPE_SCROLLBAR_VERTICAL, SCREEN_CTRL_ID_SCROLL_VERTICAL, "scroll level series vertically" } }; static void CreateScreenMenubuttons() { struct GadgetInfo *gi; unsigned int event_mask; int i; for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++) { Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed; int gfx_unpressed, gfx_pressed; int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; int id = menubutton_info[i].gadget_id; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; menubutton_info[i].get_gadget_position(&x, &y, id); width = SC_MENUBUTTON_XSIZE; height = SC_MENUBUTTON_YSIZE; gfx_unpressed = menubutton_info[i].gfx_unpressed; gfx_pressed = menubutton_info[i].gfx_pressed; gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap; gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap; gd_x1 = graphic_info[gfx_unpressed].src_x; gd_y1 = graphic_info[gfx_unpressed].src_y; gd_x2 = graphic_info[gfx_pressed].src_x; gd_y2 = graphic_info[gfx_pressed].src_y; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, menubutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleScreenGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); screen_gadget[id] = gi; } } static void CreateScreenScrollbuttons() { struct GadgetInfo *gi; unsigned int event_mask; int i; /* these values are not constant, but can change at runtime */ scrollbutton_info[0].x = SC_SCROLL_UP_XPOS; scrollbutton_info[0].y = SC_SCROLL_UP_YPOS; scrollbutton_info[1].x = SC_SCROLL_DOWN_XPOS; scrollbutton_info[1].y = SC_SCROLL_DOWN_YPOS; for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++) { Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed; int gfx_unpressed, gfx_pressed; int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; int id = scrollbutton_info[i].gadget_id; event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset; y = mSY + scrollbutton_info[i].y; width = SC_SCROLLBUTTON_XSIZE; height = SC_SCROLLBUTTON_YSIZE; /* correct scrollbar position if placed outside menu (playfield) area */ if (x > SX + SC_SCROLL_UP_XPOS) x = SX + SC_SCROLL_UP_XPOS; if (id == SCREEN_CTRL_ID_SCROLL_DOWN) y = mSY + (SC_SCROLL_VERTICAL_YPOS + (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE); gfx_unpressed = scrollbutton_info[i].gfx_unpressed; gfx_pressed = scrollbutton_info[i].gfx_pressed; gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap; gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap; gd_x1 = graphic_info[gfx_unpressed].src_x; gd_y1 = graphic_info[gfx_unpressed].src_y; gd_x2 = graphic_info[gfx_pressed].src_x; gd_y2 = graphic_info[gfx_pressed].src_y; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbutton_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleScreenGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); screen_gadget[id] = gi; } } static void CreateScreenScrollbars() { int i; /* these values are not constant, but can change at runtime */ scrollbar_info[0].x = SC_SCROLL_VERTICAL_XPOS; scrollbar_info[0].y = SC_SCROLL_VERTICAL_YPOS; scrollbar_info[0].width = SC_SCROLL_VERTICAL_XSIZE; scrollbar_info[0].height = SC_SCROLL_VERTICAL_YSIZE; for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++) { Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed; int gfx_unpressed, gfx_pressed; int x, y, width, height; int gd_x1, gd_x2, gd_y1, gd_y2; struct GadgetInfo *gi; int items_max, items_visible, item_position; unsigned int event_mask; int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN; int id = scrollbar_info[i].gadget_id; event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS; x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset; y = mSY + scrollbar_info[i].y; width = scrollbar_info[i].width; height = scrollbar_info[i].height; /* correct scrollbar position if placed outside menu (playfield) area */ if (x > SX + SC_SCROLL_VERTICAL_XPOS) x = SX + SC_SCROLL_VERTICAL_XPOS; if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL) height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE; items_max = num_page_entries; items_visible = num_page_entries; item_position = 0; gfx_unpressed = scrollbar_info[i].gfx_unpressed; gfx_pressed = scrollbar_info[i].gfx_pressed; gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap; gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap; gd_x1 = graphic_info[gfx_unpressed].src_x; gd_y1 = graphic_info[gfx_unpressed].src_y; gd_x2 = graphic_info[gfx_pressed].src_x; gd_y2 = graphic_info[gfx_pressed].src_y; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_CUSTOM_TYPE_ID, i, GDI_INFO_TEXT, scrollbar_info[i].infotext, GDI_X, x, GDI_Y, y, GDI_WIDTH, width, GDI_HEIGHT, height, GDI_TYPE, scrollbar_info[i].type, GDI_SCROLLBAR_ITEMS_MAX, items_max, GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible, GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_WHEEL_AREA_X, SX, GDI_WHEEL_AREA_Y, SY, GDI_WHEEL_AREA_WIDTH, SXSIZE, GDI_WHEEL_AREA_HEIGHT, SYSIZE, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1, GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2, GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleScreenGadgets, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); screen_gadget[id] = gi; } } void CreateScreenGadgets() { CreateScreenMenubuttons(); CreateScreenScrollbuttons(); CreateScreenScrollbars(); } void FreeScreenGadgets() { int i; for (i = 0; i < NUM_SCREEN_GADGETS; i++) FreeGadget(screen_gadget[i]); } void MapScreenMenuGadgets(int screen_mask) { int i; for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++) if (screen_mask & menubutton_info[i].screen_mask) MapGadget(screen_gadget[menubutton_info[i].gadget_id]); } void MapScreenGadgets(int num_entries) { int i; if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN) return; for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++) MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]); for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++) MapGadget(screen_gadget[scrollbar_info[i].gadget_id]); } void MapScreenTreeGadgets(TreeInfo *ti) { MapScreenGadgets(numTreeInfoInGroup(ti)); } static void HandleScreenGadgets(struct GadgetInfo *gi) { int id = gi->custom_id; int button = gi->event.button; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); switch (id) { case SCREEN_CTRL_ID_PREV_LEVEL: HandleMainMenu_SelectLevel(step, -1, NO_DIRECT_LEVEL_SELECT); break; case SCREEN_CTRL_ID_NEXT_LEVEL: HandleMainMenu_SelectLevel(step, +1, NO_DIRECT_LEVEL_SELECT); break; case SCREEN_CTRL_ID_PREV_PLAYER: HandleSetupScreen_Input_Player(step, -1); break; case SCREEN_CTRL_ID_NEXT_PLAYER: HandleSetupScreen_Input_Player(step, +1); break; case SCREEN_CTRL_ID_SCROLL_UP: if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK); break; case SCREEN_CTRL_ID_SCROLL_DOWN: if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK); break; case SCREEN_CTRL_ID_SCROLL_VERTICAL: if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE); break; default: break; } } mirrormagic-3.0.0/src/main.h0000644000175000017500000040530213263212010015211 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // main.h // ============================================================================ #ifndef MAIN_H #define MAIN_H #include #include #include #include #include #include #include #include "libgame/libgame.h" #include "game_em/game_em.h" #include "game_sp/game_sp.h" #include "game_mm/game_mm.h" #include "conf_gfx.h" /* include auto-generated data structure definitions */ #include "conf_snd.h" /* include auto-generated data structure definitions */ #include "conf_mus.h" /* include auto-generated data structure definitions */ #define IMG_UNDEFINED (-1) #define IMG_EMPTY IMG_EMPTY_SPACE #define IMG_SP_EMPTY IMG_EMPTY_SPACE #define IMG_SP_EMPTY_SPACE IMG_EMPTY_SPACE #define IMG_EXPLOSION IMG_DEFAULT_EXPLODING #define IMG_CHAR_START IMG_CHAR_SPACE #define IMG_STEEL_CHAR_START IMG_STEEL_CHAR_SPACE #define IMG_CUSTOM_START IMG_CUSTOM_1 #define SND_UNDEFINED (-1) #define MUS_UNDEFINED (-1) #define WIN_XSIZE_DEFAULT 672 #define WIN_YSIZE_DEFAULT 560 #define SCR_FIELDX_DEFAULT 17 #define SCR_FIELDY_DEFAULT 17 #define SXSIZE_DEFAULT (SCR_FIELDX_DEFAULT * TILEX) #define SYSIZE_DEFAULT (SCR_FIELDY_DEFAULT * TILEY) #define MAX_BUF_XSIZE (SCR_FIELDX + 2) #define MAX_BUF_YSIZE (SCR_FIELDY + 2) #define MIN_LEV_FIELDX 3 #define MIN_LEV_FIELDY 3 #define STD_LEV_FIELDX 64 #define STD_LEV_FIELDY 32 #define MAX_LEV_FIELDX MAX_PLAYFIELD_WIDTH #define MAX_LEV_FIELDY MAX_PLAYFIELD_HEIGHT #define MIN_SCROLL_DELAY 0 #define STD_SCROLL_DELAY 3 #define MAX_SCROLL_DELAY 8 #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_FIELD(x, y, xsize, ysize) ((x) >= 0 && (x) < (xsize) && \ (y) >= 0 && (y) < (ysize)) #define IN_FIELD_MINMAX(x, y, xmin, ymin, xmax, ymax) \ ((x) >= (xmin) && (x) <= (xmax) && \ (y) >= (ymin) && (y) <= (ymax)) #define IN_PIX_FIELD(x, y) IN_FIELD(x, y, SXSIZE, SYSIZE) #define IN_VIS_FIELD(x, y) IN_FIELD(x, y, SCR_FIELDX, SCR_FIELDY) #define IN_LEV_FIELD(x, y) IN_FIELD(x, y, lev_fieldx, lev_fieldy) #define IN_SCR_FIELD(x, y) IN_FIELD_MINMAX(x,y, BX1,BY1, BX2,BY2) /* values for configurable properties (custom elem's only, else pre-defined) */ /* (never change these values, as they are stored in level files!) */ #define EP_DIGGABLE 0 #define EP_COLLECTIBLE_ONLY 1 #define EP_DONT_RUN_INTO 2 #define EP_DONT_COLLIDE_WITH 3 #define EP_DONT_TOUCH 4 #define EP_INDESTRUCTIBLE 5 #define EP_SLIPPERY 6 #define EP_CAN_CHANGE 7 #define EP_CAN_MOVE 8 #define EP_CAN_FALL 9 #define EP_CAN_SMASH_PLAYER 10 #define EP_CAN_SMASH_ENEMIES 11 #define EP_CAN_SMASH_EVERYTHING 12 #define EP_EXPLODES_BY_FIRE 13 #define EP_EXPLODES_SMASHED 14 #define EP_EXPLODES_IMPACT 15 #define EP_WALKABLE_OVER 16 #define EP_WALKABLE_INSIDE 17 #define EP_WALKABLE_UNDER 18 #define EP_PASSABLE_OVER 19 #define EP_PASSABLE_INSIDE 20 #define EP_PASSABLE_UNDER 21 #define EP_DROPPABLE 22 #define EP_EXPLODES_1X1_OLD 23 #define EP_PUSHABLE 24 #define EP_EXPLODES_CROSS_OLD 25 #define EP_PROTECTED 26 #define EP_CAN_MOVE_INTO_ACID 27 #define EP_THROWABLE 28 #define EP_CAN_EXPLODE 29 #define EP_GRAVITY_REACHABLE 30 #define EP_DONT_GET_HIT_BY 31 /* values for pre-defined properties */ /* (from here on, values can be changed by inserting new values) */ #define EP_PLAYER 32 #define EP_CAN_PASS_MAGIC_WALL 33 #define EP_CAN_PASS_DC_MAGIC_WALL 34 #define EP_SWITCHABLE 35 #define EP_BD_ELEMENT 36 #define EP_SP_ELEMENT 37 #define EP_SB_ELEMENT 38 #define EP_GEM 39 #define EP_FOOD_DARK_YAMYAM 40 #define EP_FOOD_PENGUIN 41 #define EP_FOOD_PIG 42 #define EP_HISTORIC_WALL 43 #define EP_HISTORIC_SOLID 44 #define EP_CLASSIC_ENEMY 45 #define EP_BELT 46 #define EP_BELT_ACTIVE 47 #define EP_BELT_SWITCH 48 #define EP_TUBE 49 #define EP_ACID_POOL 50 #define EP_KEYGATE 51 #define EP_AMOEBOID 52 #define EP_AMOEBALIVE 53 #define EP_HAS_EDITOR_CONTENT 54 #define EP_CAN_TURN_EACH_MOVE 55 #define EP_CAN_GROW 56 #define EP_ACTIVE_BOMB 57 #define EP_INACTIVE 58 /* values for special configurable properties (depending on level settings) */ #define EP_EM_SLIPPERY_WALL 59 /* values for special graphics properties (no effect on game engine) */ #define EP_GFX_CRUMBLED 60 /* values for derived properties (determined from properties above) */ #define EP_ACCESSIBLE_OVER 61 #define EP_ACCESSIBLE_INSIDE 62 #define EP_ACCESSIBLE_UNDER 63 #define EP_WALKABLE 64 #define EP_PASSABLE 65 #define EP_ACCESSIBLE 66 #define EP_COLLECTIBLE 67 #define EP_SNAPPABLE 68 #define EP_WALL 69 #define EP_SOLID_FOR_PUSHING 70 #define EP_DRAGONFIRE_PROOF 71 #define EP_EXPLOSION_PROOF 72 #define EP_CAN_SMASH 73 #define EP_EXPLODES_3X3_OLD 74 #define EP_CAN_EXPLODE_BY_FIRE 75 #define EP_CAN_EXPLODE_SMASHED 76 #define EP_CAN_EXPLODE_IMPACT 77 #define EP_SP_PORT 78 #define EP_CAN_EXPLODE_BY_DRAGONFIRE 79 #define EP_CAN_EXPLODE_BY_EXPLOSION 80 #define EP_COULD_MOVE_INTO_ACID 81 #define EP_MAYBE_DONT_COLLIDE_WITH 82 #define EP_CAN_BE_CLONED_BY_ANDROID 83 /* values for internal purpose only (level editor) */ #define EP_WALK_TO_OBJECT 84 #define EP_DEADLY 85 #define EP_EDITOR_CASCADE 86 #define EP_EDITOR_CASCADE_ACTIVE 87 #define EP_EDITOR_CASCADE_INACTIVE 88 /* values for internal purpose only (game engine) */ #define EP_HAS_ACTION 89 #define EP_CAN_CHANGE_OR_HAS_ACTION 90 /* values for internal purpose only (other) */ #define EP_OBSOLETE 91 #define NUM_ELEMENT_PROPERTIES 92 #define NUM_EP_BITFIELDS ((NUM_ELEMENT_PROPERTIES + 31) / 32) #define EP_BITFIELD_BASE_NR 0 #define EP_BITMASK_BASE_DEFAULT (1 << EP_CAN_MOVE_INTO_ACID) #define EP_BITMASK_DEFAULT 0 #define PROPERTY_BIT(p) (1 << ((p) % 32)) #define PROPERTY_VAR(e,p) (element_info[e].properties[(p) / 32]) #define HAS_PROPERTY(e,p) ((PROPERTY_VAR(e, p) & PROPERTY_BIT(p)) != 0) #define SET_PROPERTY(e,p,v) ((v) ? \ (PROPERTY_VAR(e,p) |= PROPERTY_BIT(p)) : \ (PROPERTY_VAR(e,p) &= ~PROPERTY_BIT(p))) /* values for change events for custom elements (stored in level file) */ #define CE_DELAY 0 #define CE_TOUCHED_BY_PLAYER 1 #define CE_PRESSED_BY_PLAYER 2 #define CE_PUSHED_BY_PLAYER 3 #define CE_DROPPED_BY_PLAYER 4 #define CE_HITTING_SOMETHING 5 #define CE_IMPACT 6 #define CE_SMASHED 7 #define CE_TOUCHING_X 8 #define CE_CHANGE_OF_X 9 #define CE_EXPLOSION_OF_X 10 #define CE_PLAYER_TOUCHES_X 11 #define CE_PLAYER_PRESSES_X 12 #define CE_PLAYER_PUSHES_X 13 #define CE_PLAYER_COLLECTS_X 14 #define CE_PLAYER_DROPS_X 15 #define CE_VALUE_GETS_ZERO 16 #define CE_VALUE_GETS_ZERO_OF_X 17 #define CE_BY_OTHER_ACTION 18 #define CE_BY_DIRECT_ACTION 19 #define CE_PLAYER_DIGS_X 20 #define CE_ENTERED_BY_PLAYER 21 #define CE_LEFT_BY_PLAYER 22 #define CE_PLAYER_ENTERS_X 23 #define CE_PLAYER_LEAVES_X 24 #define CE_SWITCHED 25 #define CE_SWITCH_OF_X 26 #define CE_HIT_BY_SOMETHING 27 #define CE_HITTING_X 28 #define CE_HIT_BY_X 29 #define CE_BLOCKED 30 #define CE_SWITCHED_BY_PLAYER 31 #define CE_PLAYER_SWITCHES_X 32 #define CE_SNAPPED_BY_PLAYER 33 #define CE_PLAYER_SNAPS_X 34 #define CE_MOVE_OF_X 35 #define CE_DIGGING_X 36 #define CE_CREATION_OF_X 37 #define CE_SCORE_GETS_ZERO 38 #define CE_SCORE_GETS_ZERO_OF_X 39 #define CE_VALUE_CHANGES 40 #define CE_VALUE_CHANGES_OF_X 41 #define CE_SCORE_CHANGES 42 #define CE_SCORE_CHANGES_OF_X 43 #define NUM_CHANGE_EVENTS 44 #define NUM_CE_BITFIELDS ((NUM_CHANGE_EVENTS + 31) / 32) #define CE_BITMASK_DEFAULT 0 #define CH_EVENT_BITFIELD_NR(e) (e / 32) #define CH_EVENT_BIT(e) (1 << ((e) % 32)) #define CH_EVENT_VAR(e,c) (element_info[e].change->has_event[c]) #define CH_ANY_EVENT_VAR(e,c) (element_info[e].has_change_event[c]) #define PAGE_HAS_CHANGE_EVENT(p,c) ((p)->has_event[c]) #define HAS_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) && \ CH_EVENT_VAR(e,c)) #define HAS_ANY_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) && \ CH_ANY_EVENT_VAR(e,c)) #define SET_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ? \ CH_EVENT_VAR(e,c) = (v) : 0) #define SET_ANY_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ? \ CH_ANY_EVENT_VAR(e,c) = (v) : 0) /* values for player bitmasks */ #define PLAYER_BITS_NONE 0 #define PLAYER_BITS_1 (1 << 0) #define PLAYER_BITS_2 (1 << 1) #define PLAYER_BITS_3 (1 << 2) #define PLAYER_BITS_4 (1 << 3) #define PLAYER_BITS_ANY (PLAYER_BITS_1 | \ PLAYER_BITS_2 | \ PLAYER_BITS_3 | \ PLAYER_BITS_4) #define PLAYER_BITS_TRIGGER (1 << 4) #define PLAYER_BITS_ACTION (1 << 5) /* values for move directions (bits 0 - 3: basic move directions) */ #define MV_BIT_PREVIOUS 4 #define MV_BIT_TRIGGER 5 #define MV_BIT_TRIGGER_BACK 6 #define MV_BIT_NORMAL MV_BIT_TRIGGER #define MV_BIT_REVERSE MV_BIT_TRIGGER_BACK #define MV_PREVIOUS (1 << MV_BIT_PREVIOUS) #define MV_TRIGGER (1 << MV_BIT_TRIGGER) #define MV_TRIGGER_BACK (1 << MV_BIT_TRIGGER_BACK) #define MV_NORMAL (1 << MV_BIT_NORMAL) #define MV_REVERSE (1 << MV_BIT_REVERSE) /* values for move stepsize */ #define STEPSIZE_NOT_MOVING 0 #define STEPSIZE_VERY_SLOW 1 #define STEPSIZE_SLOW 2 #define STEPSIZE_NORMAL 4 #define STEPSIZE_FAST 8 #define STEPSIZE_VERY_FAST 16 #define STEPSIZE_EVEN_FASTER 32 #define STEPSIZE_SLOWER 50 /* (symbolic value only) */ #define STEPSIZE_FASTER 200 /* (symbolic value only) */ #define STEPSIZE_RESET 100 /* (symbolic value only) */ /* values for change side for custom elements */ #define CH_SIDE_NONE MV_NONE #define CH_SIDE_LEFT MV_LEFT #define CH_SIDE_RIGHT MV_RIGHT #define CH_SIDE_TOP MV_UP #define CH_SIDE_BOTTOM MV_DOWN #define CH_SIDE_LEFT_RIGHT MV_HORIZONTAL #define CH_SIDE_TOP_BOTTOM MV_VERTICAL #define CH_SIDE_ANY MV_ANY_DIRECTION /* values for change player for custom elements */ #define CH_PLAYER_NONE PLAYER_BITS_NONE #define CH_PLAYER_1 PLAYER_BITS_1 #define CH_PLAYER_2 PLAYER_BITS_2 #define CH_PLAYER_3 PLAYER_BITS_3 #define CH_PLAYER_4 PLAYER_BITS_4 #define CH_PLAYER_ANY PLAYER_BITS_ANY /* values for change page for custom elements */ #define CH_PAGE_ANY_FILE (0xff) #define CH_PAGE_ANY (0xffffffff) /* values for change power for custom elements */ #define CP_WHEN_EMPTY 0 #define CP_WHEN_DIGGABLE 1 #define CP_WHEN_DESTRUCTIBLE 2 #define CP_WHEN_COLLECTIBLE 3 #define CP_WHEN_REMOVABLE 4 #define CP_WHEN_WALKABLE 5 /* values for change actions for custom elements (stored in level file) */ #define CA_NO_ACTION 0 #define CA_EXIT_PLAYER 1 #define CA_KILL_PLAYER 2 #define CA_MOVE_PLAYER 3 #define CA_RESTART_LEVEL 4 #define CA_SHOW_ENVELOPE 5 #define CA_SET_LEVEL_TIME 6 #define CA_SET_LEVEL_GEMS 7 #define CA_SET_LEVEL_SCORE 8 #define CA_SET_LEVEL_WIND 9 #define CA_SET_PLAYER_GRAVITY 10 #define CA_SET_PLAYER_KEYS 11 #define CA_SET_PLAYER_SPEED 12 #define CA_SET_PLAYER_SHIELD 13 #define CA_SET_PLAYER_ARTWORK 14 #define CA_SET_CE_SCORE 15 #define CA_SET_CE_VALUE 16 #define CA_SET_ENGINE_SCAN_MODE 17 #define CA_SET_PLAYER_INVENTORY 18 #define CA_SET_CE_ARTWORK 19 #define CA_SET_LEVEL_RANDOM_SEED 20 #define CA_HEADLINE_LEVEL_ACTIONS 250 #define CA_HEADLINE_PLAYER_ACTIONS 251 #define CA_HEADLINE_CE_ACTIONS 252 #define CA_HEADLINE_ENGINE_ACTIONS 253 #define CA_UNDEFINED 255 /* values for change action mode for custom elements */ #define CA_MODE_UNDEFINED 0 #define CA_MODE_SET 1 #define CA_MODE_ADD 2 #define CA_MODE_SUBTRACT 3 #define CA_MODE_MULTIPLY 4 #define CA_MODE_DIVIDE 5 #define CA_MODE_MODULO 6 /* values for change action parameters for custom elements */ #define CA_ARG_MIN 0 #define CA_ARG_0 0 #define CA_ARG_1 1 #define CA_ARG_2 2 #define CA_ARG_3 3 #define CA_ARG_4 4 #define CA_ARG_5 5 #define CA_ARG_6 6 #define CA_ARG_7 7 #define CA_ARG_8 8 #define CA_ARG_9 9 #define CA_ARG_10 10 #define CA_ARG_100 100 #define CA_ARG_1000 1000 #define CA_ARG_MAX 9999 #define CA_ARG_PLAYER 10000 #define CA_ARG_PLAYER_1 (CA_ARG_PLAYER + PLAYER_BITS_1) #define CA_ARG_PLAYER_2 (CA_ARG_PLAYER + PLAYER_BITS_2) #define CA_ARG_PLAYER_3 (CA_ARG_PLAYER + PLAYER_BITS_3) #define CA_ARG_PLAYER_4 (CA_ARG_PLAYER + PLAYER_BITS_4) #define CA_ARG_PLAYER_ANY (CA_ARG_PLAYER + PLAYER_BITS_ANY) #define CA_ARG_PLAYER_TRIGGER (CA_ARG_PLAYER + PLAYER_BITS_TRIGGER) #define CA_ARG_PLAYER_ACTION (CA_ARG_PLAYER + PLAYER_BITS_ACTION) #define CA_ARG_PLAYER_HEADLINE (CA_ARG_PLAYER + 999) #define CA_ARG_NUMBER 11000 #define CA_ARG_NUMBER_MIN (CA_ARG_NUMBER + 0) #define CA_ARG_NUMBER_MAX (CA_ARG_NUMBER + 1) #define CA_ARG_NUMBER_RESET (CA_ARG_NUMBER + 2) #define CA_ARG_NUMBER_CE_SCORE (CA_ARG_NUMBER + 3) #define CA_ARG_NUMBER_CE_VALUE (CA_ARG_NUMBER + 4) #define CA_ARG_NUMBER_CE_DELAY (CA_ARG_NUMBER + 5) #define CA_ARG_NUMBER_LEVEL_TIME (CA_ARG_NUMBER + 6) #define CA_ARG_NUMBER_LEVEL_GEMS (CA_ARG_NUMBER + 7) #define CA_ARG_NUMBER_LEVEL_SCORE (CA_ARG_NUMBER + 8) #define CA_ARG_NUMBER_HEADLINE (CA_ARG_NUMBER + 999) #define CA_ARG_ELEMENT 12000 #define CA_ARG_ELEMENT_RESET (CA_ARG_ELEMENT + 0) #define CA_ARG_ELEMENT_TARGET (CA_ARG_ELEMENT + 1) #define CA_ARG_ELEMENT_TRIGGER (CA_ARG_ELEMENT + 2) #define CA_ARG_ELEMENT_ACTION (CA_ARG_ELEMENT + 7) #define CA_ARG_ELEMENT_HEADLINE (CA_ARG_ELEMENT + 997) #define CA_ARG_ELEMENT_CV_TARGET (CA_ARG_ELEMENT_TARGET) #define CA_ARG_ELEMENT_CV_TRIGGER (CA_ARG_ELEMENT_TRIGGER) #define CA_ARG_ELEMENT_CV_ACTION (CA_ARG_ELEMENT_ACTION) #define CA_ARG_ELEMENT_CV_HEADLINE (CA_ARG_ELEMENT_HEADLINE) #define CA_ARG_ELEMENT_NR_TARGET (CA_ARG_ELEMENT + 3) #define CA_ARG_ELEMENT_NR_TRIGGER (CA_ARG_ELEMENT + 4) #define CA_ARG_ELEMENT_NR_ACTION (CA_ARG_ELEMENT + 8) #define CA_ARG_ELEMENT_NR_HEADLINE (CA_ARG_ELEMENT + 998) #define CA_ARG_ELEMENT_CS_TARGET (CA_ARG_ELEMENT + 5) #define CA_ARG_ELEMENT_CS_TRIGGER (CA_ARG_ELEMENT + 6) #define CA_ARG_ELEMENT_CS_ACTION (CA_ARG_ELEMENT + 9) #define CA_ARG_ELEMENT_CS_HEADLINE (CA_ARG_ELEMENT + 999) #define CA_ARG_SPEED 13000 #define CA_ARG_SPEED_NOT_MOVING (CA_ARG_SPEED + STEPSIZE_NOT_MOVING) #define CA_ARG_SPEED_VERY_SLOW (CA_ARG_SPEED + STEPSIZE_VERY_SLOW) #define CA_ARG_SPEED_SLOW (CA_ARG_SPEED + STEPSIZE_SLOW) #define CA_ARG_SPEED_NORMAL (CA_ARG_SPEED + STEPSIZE_NORMAL) #define CA_ARG_SPEED_FAST (CA_ARG_SPEED + STEPSIZE_FAST) #define CA_ARG_SPEED_VERY_FAST (CA_ARG_SPEED + STEPSIZE_VERY_FAST) #define CA_ARG_SPEED_EVEN_FASTER (CA_ARG_SPEED + STEPSIZE_EVEN_FASTER) #define CA_ARG_SPEED_SLOWER (CA_ARG_SPEED + STEPSIZE_SLOWER) #define CA_ARG_SPEED_FASTER (CA_ARG_SPEED + STEPSIZE_FASTER) #define CA_ARG_SPEED_RESET (CA_ARG_SPEED + STEPSIZE_RESET) #define CA_ARG_SPEED_HEADLINE (CA_ARG_SPEED + 999) #define CA_ARG_GRAVITY 14000 #define CA_ARG_GRAVITY_OFF (CA_ARG_GRAVITY + 0) #define CA_ARG_GRAVITY_ON (CA_ARG_GRAVITY + 1) #define CA_ARG_GRAVITY_TOGGLE (CA_ARG_GRAVITY + 2) #define CA_ARG_GRAVITY_HEADLINE (CA_ARG_GRAVITY + 999) #define CA_ARG_DIRECTION 15000 #define CA_ARG_DIRECTION_NONE (CA_ARG_DIRECTION + MV_NONE) #define CA_ARG_DIRECTION_LEFT (CA_ARG_DIRECTION + MV_LEFT) #define CA_ARG_DIRECTION_RIGHT (CA_ARG_DIRECTION + MV_RIGHT) #define CA_ARG_DIRECTION_UP (CA_ARG_DIRECTION + MV_UP) #define CA_ARG_DIRECTION_DOWN (CA_ARG_DIRECTION + MV_DOWN) #define CA_ARG_DIRECTION_TRIGGER (CA_ARG_DIRECTION + MV_TRIGGER) #define CA_ARG_DIRECTION_TRIGGER_BACK (CA_ARG_DIRECTION + MV_TRIGGER_BACK) #define CA_ARG_DIRECTION_HEADLINE (CA_ARG_DIRECTION + 999) #define CA_ARG_SHIELD 16000 #define CA_ARG_SHIELD_OFF (CA_ARG_SHIELD + 0) #define CA_ARG_SHIELD_NORMAL (CA_ARG_SHIELD + 1) #define CA_ARG_SHIELD_DEADLY (CA_ARG_SHIELD + 2) #define CA_ARG_SHIELD_HEADLINE (CA_ARG_SHIELD + 999) #define CA_ARG_SCAN_MODE 17000 #define CA_ARG_SCAN_MODE_NORMAL (CA_ARG_SCAN_MODE + MV_NORMAL) #define CA_ARG_SCAN_MODE_REVERSE (CA_ARG_SCAN_MODE + MV_REVERSE) #define CA_ARG_SCAN_MODE_HEADLINE (CA_ARG_SCAN_MODE + 999) #define CA_ARG_INVENTORY 18000 #define CA_ARG_INVENTORY_RESET (CA_ARG_INVENTORY + 0) #define CA_ARG_INVENTORY_RM_TARGET (CA_ARG_INVENTORY + 1) #define CA_ARG_INVENTORY_RM_TRIGGER (CA_ARG_INVENTORY + 2) #define CA_ARG_INVENTORY_RM_ACTION (CA_ARG_INVENTORY + 3) #define CA_ARG_INVENTORY_RM_FIRST (CA_ARG_INVENTORY + 4) #define CA_ARG_INVENTORY_RM_LAST (CA_ARG_INVENTORY + 5) #define CA_ARG_INVENTORY_RM_ALL (CA_ARG_INVENTORY + 6) #define CA_ARG_INVENTORY_HEADLINE (CA_ARG_INVENTORY + 998) #define CA_ARG_INVENTORY_RM_HEADLINE (CA_ARG_INVENTORY + 999) #define CA_ARG_UNDEFINED 65535 /* values for custom move patterns (bits 0 - 3: basic move directions) */ #define MV_BIT_TOWARDS_PLAYER 4 #define MV_BIT_AWAY_FROM_PLAYER 5 #define MV_BIT_ALONG_LEFT_SIDE 6 #define MV_BIT_ALONG_RIGHT_SIDE 7 #define MV_BIT_TURNING_LEFT 8 #define MV_BIT_TURNING_RIGHT 9 #define MV_BIT_WHEN_PUSHED 10 #define MV_BIT_MAZE_RUNNER 11 #define MV_BIT_MAZE_HUNTER 12 #define MV_BIT_WHEN_DROPPED 13 #define MV_BIT_TURNING_LEFT_RIGHT 14 #define MV_BIT_TURNING_RIGHT_LEFT 15 #define MV_BIT_TURNING_RANDOM 16 #define MV_BIT_WIND_DIRECTION 17 /* values for custom move patterns */ #define MV_TOWARDS_PLAYER (1 << MV_BIT_TOWARDS_PLAYER) #define MV_AWAY_FROM_PLAYER (1 << MV_BIT_AWAY_FROM_PLAYER) #define MV_ALONG_LEFT_SIDE (1 << MV_BIT_ALONG_LEFT_SIDE) #define MV_ALONG_RIGHT_SIDE (1 << MV_BIT_ALONG_RIGHT_SIDE) #define MV_TURNING_LEFT (1 << MV_BIT_TURNING_LEFT) #define MV_TURNING_RIGHT (1 << MV_BIT_TURNING_RIGHT) #define MV_WHEN_PUSHED (1 << MV_BIT_WHEN_PUSHED) #define MV_MAZE_RUNNER (1 << MV_BIT_MAZE_RUNNER) #define MV_MAZE_HUNTER (1 << MV_BIT_MAZE_HUNTER) #define MV_MAZE_RUNNER_STYLE (MV_MAZE_RUNNER | MV_MAZE_HUNTER) #define MV_WHEN_DROPPED (1 << MV_BIT_WHEN_DROPPED) #define MV_TURNING_LEFT_RIGHT (1 << MV_BIT_TURNING_LEFT_RIGHT) #define MV_TURNING_RIGHT_LEFT (1 << MV_BIT_TURNING_RIGHT_LEFT) #define MV_TURNING_RANDOM (1 << MV_BIT_TURNING_RANDOM) #define MV_WIND_DIRECTION (1 << MV_BIT_WIND_DIRECTION) /* values for initial move direction */ #define MV_START_NONE (MV_NONE) #define MV_START_AUTOMATIC (MV_NONE) #define MV_START_LEFT (MV_LEFT) #define MV_START_RIGHT (MV_RIGHT) #define MV_START_UP (MV_UP) #define MV_START_DOWN (MV_DOWN) #define MV_START_RANDOM (MV_ALL_DIRECTIONS) #define MV_START_PREVIOUS (MV_PREVIOUS) /* values for elements left behind by custom elements */ #define LEAVE_TYPE_UNLIMITED 0 #define LEAVE_TYPE_LIMITED 1 /* values for slippery property for custom elements */ #define SLIPPERY_ANY_RANDOM 0 #define SLIPPERY_ANY_LEFT_RIGHT 1 #define SLIPPERY_ANY_RIGHT_LEFT 2 #define SLIPPERY_ONLY_LEFT 3 #define SLIPPERY_ONLY_RIGHT 4 /* values for explosion type for custom elements */ #define EXPLODES_3X3 0 #define EXPLODES_1X1 1 #define EXPLODES_CROSS 2 /* macros for configurable properties */ #define IS_DIGGABLE(e) HAS_PROPERTY(e, EP_DIGGABLE) #define IS_COLLECTIBLE_ONLY(e) HAS_PROPERTY(e, EP_COLLECTIBLE_ONLY) #define DONT_RUN_INTO(e) HAS_PROPERTY(e, EP_DONT_RUN_INTO) #define DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_DONT_COLLIDE_WITH) #define DONT_TOUCH(e) HAS_PROPERTY(e, EP_DONT_TOUCH) #define IS_INDESTRUCTIBLE(e) HAS_PROPERTY(e, EP_INDESTRUCTIBLE) #define IS_SLIPPERY(e) HAS_PROPERTY(e, EP_SLIPPERY) #define CAN_CHANGE(e) HAS_PROPERTY(e, EP_CAN_CHANGE) #define CAN_MOVE(e) HAS_PROPERTY(e, EP_CAN_MOVE) #define CAN_FALL(e) HAS_PROPERTY(e, EP_CAN_FALL) #define CAN_SMASH_PLAYER(e) HAS_PROPERTY(e, EP_CAN_SMASH_PLAYER) #define CAN_SMASH_ENEMIES(e) HAS_PROPERTY(e, EP_CAN_SMASH_ENEMIES) #define CAN_SMASH_EVERYTHING(e) HAS_PROPERTY(e, EP_CAN_SMASH_EVERYTHING) #define EXPLODES_BY_FIRE(e) HAS_PROPERTY(e, EP_EXPLODES_BY_FIRE) #define EXPLODES_SMASHED(e) HAS_PROPERTY(e, EP_EXPLODES_SMASHED) #define EXPLODES_IMPACT(e) HAS_PROPERTY(e, EP_EXPLODES_IMPACT) #define IS_WALKABLE_OVER(e) HAS_PROPERTY(e, EP_WALKABLE_OVER) #define IS_WALKABLE_INSIDE(e) HAS_PROPERTY(e, EP_WALKABLE_INSIDE) #define IS_WALKABLE_UNDER(e) HAS_PROPERTY(e, EP_WALKABLE_UNDER) #define IS_PASSABLE_OVER(e) HAS_PROPERTY(e, EP_PASSABLE_OVER) #define IS_PASSABLE_INSIDE(e) HAS_PROPERTY(e, EP_PASSABLE_INSIDE) #define IS_PASSABLE_UNDER(e) HAS_PROPERTY(e, EP_PASSABLE_UNDER) #define IS_DROPPABLE(e) HAS_PROPERTY(e, EP_DROPPABLE) #define EXPLODES_1X1_OLD(e) HAS_PROPERTY(e, EP_EXPLODES_1X1_OLD) #define IS_PUSHABLE(e) HAS_PROPERTY(e, EP_PUSHABLE) #define EXPLODES_CROSS_OLD(e) HAS_PROPERTY(e, EP_EXPLODES_CROSS_OLD) #define IS_PROTECTED(e) HAS_PROPERTY(e, EP_PROTECTED) #define CAN_MOVE_INTO_ACID(e) HAS_PROPERTY(e, EP_CAN_MOVE_INTO_ACID) #define IS_THROWABLE(e) HAS_PROPERTY(e, EP_THROWABLE) #define CAN_EXPLODE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE) #define IS_GRAVITY_REACHABLE(e) HAS_PROPERTY(e, EP_GRAVITY_REACHABLE) #define DONT_GET_HIT_BY(e) HAS_PROPERTY(e, EP_DONT_GET_HIT_BY) /* macros for special configurable properties */ #define IS_EM_SLIPPERY_WALL(e) HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL) /* macros for special graphics properties */ #define GFX_CRUMBLED(e) HAS_PROPERTY(GFX_ELEMENT(e), EP_GFX_CRUMBLED) /* macros for pre-defined properties */ #define ELEM_IS_PLAYER(e) HAS_PROPERTY(e, EP_PLAYER) #define CAN_PASS_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_MAGIC_WALL) #define CAN_PASS_DC_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_DC_MAGIC_WALL) #define IS_SWITCHABLE(e) HAS_PROPERTY(e, EP_SWITCHABLE) #define IS_BD_ELEMENT(e) HAS_PROPERTY(e, EP_BD_ELEMENT) #define IS_SP_ELEMENT(e) HAS_PROPERTY(e, EP_SP_ELEMENT) #define IS_SB_ELEMENT(e) HAS_PROPERTY(e, EP_SB_ELEMENT) #define IS_GEM(e) HAS_PROPERTY(e, EP_GEM) #define IS_FOOD_DARK_YAMYAM(e) HAS_PROPERTY(e, EP_FOOD_DARK_YAMYAM) #define IS_FOOD_PENGUIN(e) HAS_PROPERTY(e, EP_FOOD_PENGUIN) #define IS_FOOD_PIG(e) HAS_PROPERTY(e, EP_FOOD_PIG) #define IS_HISTORIC_WALL(e) HAS_PROPERTY(e, EP_HISTORIC_WALL) #define IS_HISTORIC_SOLID(e) HAS_PROPERTY(e, EP_HISTORIC_SOLID) #define IS_CLASSIC_ENEMY(e) HAS_PROPERTY(e, EP_CLASSIC_ENEMY) #define IS_BELT(e) HAS_PROPERTY(e, EP_BELT) #define IS_BELT_ACTIVE(e) HAS_PROPERTY(e, EP_BELT_ACTIVE) #define IS_BELT_SWITCH(e) HAS_PROPERTY(e, EP_BELT_SWITCH) #define IS_TUBE(e) HAS_PROPERTY(e, EP_TUBE) #define IS_ACID_POOL(e) HAS_PROPERTY(e, EP_ACID_POOL) #define IS_KEYGATE(e) HAS_PROPERTY(e, EP_KEYGATE) #define IS_AMOEBOID(e) HAS_PROPERTY(e, EP_AMOEBOID) #define IS_AMOEBALIVE(e) HAS_PROPERTY(e, EP_AMOEBALIVE) #define HAS_EDITOR_CONTENT(e) HAS_PROPERTY(e, EP_HAS_EDITOR_CONTENT) #define CAN_TURN_EACH_MOVE(e) HAS_PROPERTY(e, EP_CAN_TURN_EACH_MOVE) #define CAN_GROW(e) HAS_PROPERTY(e, EP_CAN_GROW) #define IS_ACTIVE_BOMB(e) HAS_PROPERTY(e, EP_ACTIVE_BOMB) #define IS_INACTIVE(e) HAS_PROPERTY(e, EP_INACTIVE) /* macros for derived properties */ #define IS_ACCESSIBLE_OVER(e) HAS_PROPERTY(e, EP_ACCESSIBLE_OVER) #define IS_ACCESSIBLE_INSIDE(e) HAS_PROPERTY(e, EP_ACCESSIBLE_INSIDE) #define IS_ACCESSIBLE_UNDER(e) HAS_PROPERTY(e, EP_ACCESSIBLE_UNDER) #define IS_WALKABLE(e) HAS_PROPERTY(e, EP_WALKABLE) #define IS_PASSABLE(e) HAS_PROPERTY(e, EP_PASSABLE) #define IS_ACCESSIBLE(e) HAS_PROPERTY(e, EP_ACCESSIBLE) #define IS_COLLECTIBLE(e) HAS_PROPERTY(e, EP_COLLECTIBLE) #define IS_SNAPPABLE(e) HAS_PROPERTY(e, EP_SNAPPABLE) #define IS_WALL(e) HAS_PROPERTY(e, EP_WALL) #define IS_SOLID_FOR_PUSHING(e) HAS_PROPERTY(e, EP_SOLID_FOR_PUSHING) #define IS_DRAGONFIRE_PROOF(e) HAS_PROPERTY(e, EP_DRAGONFIRE_PROOF) #define IS_EXPLOSION_PROOF(e) HAS_PROPERTY(e, EP_EXPLOSION_PROOF) #define CAN_SMASH(e) HAS_PROPERTY(e, EP_CAN_SMASH) #define EXPLODES_3X3_OLD(e) HAS_PROPERTY(e, EP_EXPLODES_3X3_OLD) #define CAN_EXPLODE_BY_FIRE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_FIRE) #define CAN_EXPLODE_SMASHED(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_SMASHED) #define CAN_EXPLODE_IMPACT(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_IMPACT) #define IS_SP_PORT(e) HAS_PROPERTY(e, EP_SP_PORT) #define CAN_EXPLODE_BY_DRAGONFIRE(e) \ HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_DRAGONFIRE) #define CAN_EXPLODE_BY_EXPLOSION(e) \ HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION) #define COULD_MOVE_INTO_ACID(e) HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID) #define MAYBE_DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH) #define CAN_BE_CLONED_BY_ANDROID(e) \ HAS_PROPERTY(e, EP_CAN_BE_CLONED_BY_ANDROID) #define IS_EDITOR_CASCADE(e) HAS_PROPERTY(e, EP_EDITOR_CASCADE) #define IS_EDITOR_CASCADE_ACTIVE(e) \ HAS_PROPERTY(e, EP_EDITOR_CASCADE_ACTIVE) #define IS_EDITOR_CASCADE_INACTIVE(e) \ HAS_PROPERTY(e, EP_EDITOR_CASCADE_INACTIVE) #define HAS_ACTION(e) HAS_PROPERTY(e, EP_HAS_ACTION) #define CAN_CHANGE_OR_HAS_ACTION(e) \ HAS_PROPERTY(e, EP_CAN_CHANGE_OR_HAS_ACTION) #define IS_OBSOLETE(e) HAS_PROPERTY(e, EP_OBSOLETE) /* special macros used in game engine */ #define IS_FILE_ELEMENT(e) ((e) >= 0 && \ (e) <= NUM_FILE_ELEMENTS) #define IS_DRAWABLE_ELEMENT(e) ((e) >= 0 && \ (e) <= NUM_DRAWABLE_ELEMENTS) #define IS_RUNTIME_ELEMENT(e) ((e) >= 0 && \ (e) <= NUM_RUNTIME_ELEMENTS) #define IS_VALID_ELEMENT(e) ((e) >= 0 && \ (e) <= MAX_NUM_ELEMENTS) #define IS_CUSTOM_ELEMENT(e) ((e) >= EL_CUSTOM_START && \ (e) <= EL_CUSTOM_END) #define IS_GROUP_ELEMENT(e) ((e) >= EL_GROUP_START && \ (e) <= EL_GROUP_END) #define IS_CLIPBOARD_ELEMENT(e) ((e) >= EL_INTERNAL_CLIPBOARD_START && \ (e) <= EL_INTERNAL_CLIPBOARD_END) #define IS_INTERNAL_ELEMENT(e) ((e) >= EL_INTERNAL_START && \ (e) <= EL_INTERNAL_END) #define IS_MM_ELEMENT(e) ((e) >= EL_MM_START && \ (e) <= EL_MM_END) #define IS_DF_ELEMENT(e) ((e) >= EL_DF_START && \ (e) <= EL_DF_END) #define IS_MM_MCDUFFIN(e) ((e) >= EL_MM_MCDUFFIN_START && \ (e) <= EL_MM_MCDUFFIN_END) #define IS_DF_LASER(e) ((e) >= EL_DF_LASER_START && \ (e) <= EL_DF_LASER_END) #define IS_MM_WALL(e) (((e) >= EL_MM_WALL_START && \ (e) <= EL_MM_WALL_END) || \ ((e) >= EL_DF_WALL_START && \ (e) <= EL_DF_WALL_END)) #define IS_DF_WALL(e) ((e) >= EL_DF_WALL_START && \ (e) <= EL_DF_WALL_END) #define IS_MM_WALL_EDITOR(e) ((e) == EL_MM_STEEL_WALL || \ (e) == EL_MM_WOODEN_WALL || \ (e) == EL_MM_ICE_WALL || \ (e) == EL_MM_AMOEBA_WALL || \ (e) == EL_DF_STEEL_WALL || \ (e) == EL_DF_WOODEN_WALL) #define IS_ENVELOPE(e) ((e) >= EL_ENVELOPE_1 && \ (e) <= EL_ENVELOPE_4) #define IS_BALLOON_ELEMENT(e) ((e) == EL_BALLOON || \ (e) == EL_BALLOON_SWITCH_LEFT || \ (e) == EL_BALLOON_SWITCH_RIGHT || \ (e) == EL_BALLOON_SWITCH_UP || \ (e) == EL_BALLOON_SWITCH_DOWN || \ (e) == EL_BALLOON_SWITCH_ANY || \ (e) == EL_BALLOON_SWITCH_NONE) #define IS_RND_KEY(e) ((e) >= EL_KEY_1 && \ (e) <= EL_KEY_4) #define IS_EM_KEY(e) ((e) >= EL_EM_KEY_1 && \ (e) <= EL_EM_KEY_4) #define IS_EMC_KEY(e) ((e) >= EL_EMC_KEY_5 && \ (e) <= EL_EMC_KEY_8) #define IS_KEY(e) (IS_RND_KEY(e) || \ IS_EM_KEY(e) || \ IS_EMC_KEY(e)) #define RND_KEY_NR(e) ((e) - EL_KEY_1) #define EM_KEY_NR(e) ((e) - EL_EM_KEY_1) #define EMC_KEY_NR(e) ((e) - EL_EMC_KEY_5 + 4) #define KEY_NR(e) (IS_RND_KEY(e) ? RND_KEY_NR(e) : \ IS_EM_KEY(e) ? EM_KEY_NR(e) : \ IS_EMC_KEY(e) ? EMC_KEY_NR(e) : 0) #define IS_RND_GATE(e) ((e) >= EL_GATE_1 && \ (e) <= EL_GATE_4) #define IS_EM_GATE(e) ((e) >= EL_EM_GATE_1 && \ (e) <= EL_EM_GATE_4) #define IS_EMC_GATE(e) ((e) >= EL_EMC_GATE_5 && \ (e) <= EL_EMC_GATE_8) #define IS_DC_GATE(e) ((e) == EL_DC_GATE_WHITE) #define IS_GATE(e) (IS_RND_GATE(e) || \ IS_EM_GATE(e) || \ IS_EMC_GATE(e) || \ IS_DC_GATE(e)) #define RND_GATE_NR(e) ((e) - EL_GATE_1) #define EM_GATE_NR(e) ((e) - EL_EM_GATE_1) #define EMC_GATE_NR(e) ((e) - EL_EMC_GATE_5 + 4) #define GATE_NR(e) (IS_RND_GATE(e) ? RND_GATE_NR(e) : \ IS_EM_GATE(e) ? EM_GATE_NR(e) : \ IS_EMC_GATE(e) ? EMC_GATE_NR(e) : 0) #define IS_RND_GATE_GRAY(e) ((e) >= EL_GATE_1_GRAY && \ (e) <= EL_GATE_4_GRAY) #define IS_RND_GATE_GRAY_ACTIVE(e) ((e) >= EL_GATE_1_GRAY_ACTIVE && \ (e) <= EL_GATE_4_GRAY_ACTIVE) #define IS_EM_GATE_GRAY(e) ((e) >= EL_EM_GATE_1_GRAY && \ (e) <= EL_EM_GATE_4_GRAY) #define IS_EM_GATE_GRAY_ACTIVE(e) ((e) >= EL_EM_GATE_1_GRAY_ACTIVE && \ (e) <= EL_EM_GATE_4_GRAY_ACTIVE) #define IS_EMC_GATE_GRAY(e) ((e) >= EL_EMC_GATE_5_GRAY && \ (e) <= EL_EMC_GATE_8_GRAY) #define IS_EMC_GATE_GRAY_ACTIVE(e) ((e) >= EL_EMC_GATE_5_GRAY_ACTIVE && \ (e) <= EL_EMC_GATE_8_GRAY_ACTIVE) #define IS_DC_GATE_GRAY(e) ((e) == EL_DC_GATE_WHITE_GRAY) #define IS_DC_GATE_GRAY_ACTIVE(e) ((e) == EL_DC_GATE_WHITE_GRAY_ACTIVE) #define IS_GATE_GRAY(e) (IS_RND_GATE_GRAY(e) || \ IS_EM_GATE_GRAY(e) || \ IS_EMC_GATE_GRAY(e) || \ IS_DC_GATE_GRAY(e)) #define IS_GATE_GRAY_ACTIVE(e) (IS_RND_GATE_GRAY_ACTIVE(e) || \ IS_EM_GATE_GRAY_ACTIVE(e) || \ IS_EMC_GATE_GRAY_ACTIVE(e) || \ IS_DC_GATE_GRAY_ACTIVE(e)) #define RND_GATE_GRAY_NR(e) ((e) - EL_GATE_1_GRAY) #define RND_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_GATE_1_GRAY_ACTIVE) #define EM_GATE_GRAY_NR(e) ((e) - EL_EM_GATE_1_GRAY) #define EM_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EM_GATE_1_GRAY_ACTIVE) #define EMC_GATE_GRAY_NR(e) ((e) - EL_EMC_GATE_5_GRAY + 4) #define EMC_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EMC_GATE_5_GRAY_ACTIVE + 4) #define GATE_GRAY_NR(e) (IS_RND_GATE_GRAY(e) ? RND_GATE_GRAY_NR(e) : \ IS_EM_GATE_GRAY(e) ? EM_GATE_GRAY_NR(e) : \ IS_EMC_GATE_GRAY(e) ? EMC_GATE_GRAY_NR(e) : 0) #define IS_ACID_POOL_OR_ACID(e) (IS_ACID_POOL(e) || (e) == EL_ACID) #define IS_EMC_PILLAR(e) ((e) >= EL_EMC_WALL_1 && \ (e) <= EL_EMC_WALL_3) #define IS_SP_CHIP(e) ((e) == EL_SP_CHIP_SINGLE || \ (e) == EL_SP_CHIP_LEFT || \ (e) == EL_SP_CHIP_RIGHT || \ (e) == EL_SP_CHIP_TOP || \ (e) == EL_SP_CHIP_BOTTOM) #define IS_SP_HARDWARE_BASE(e) ((e) == EL_SP_HARDWARE_BASE_1 || \ (e) == EL_SP_HARDWARE_BASE_2 || \ (e) == EL_SP_HARDWARE_BASE_3 || \ (e) == EL_SP_HARDWARE_BASE_4 || \ (e) == EL_SP_HARDWARE_BASE_5 || \ (e) == EL_SP_HARDWARE_BASE_6) #define IS_DC_STEELWALL_2(e) ((e) >= EL_DC_STEELWALL_2_LEFT && \ (e) <= EL_DC_STEELWALL_2_SINGLE) #define MM_WALL_BASE(e) ((e) & 0xfff0) #define MM_WALL_BITS(e) ((e) & 0x000f) #define GFX_ELEMENT(e) (element_info[e].gfx_element) /* !!! CHECK THIS !!! */ #if 1 #define TILE_GFX_ELEMENT(x, y) \ (GfxElement[x][y] != EL_UNDEFINED && \ Feld[x][y] != EL_EXPLOSION ? \ GfxElement[x][y] : Feld[x][y]) #else #define TILE_GFX_ELEMENT(x, y) \ GFX_ELEMENT(GfxElement[x][y] != EL_UNDEFINED && \ Feld[x][y] != EL_EXPLOSION ? \ GfxElement[x][y] : Feld[x][y]) #endif /* !!! "use sound" deactivated due to problems with level "bug machine" !!! */ /* (solution: add separate "use sound of element" to level file and editor) */ #if 0 #define SND_ELEMENT(e) GFX_ELEMENT(e) #else #define SND_ELEMENT(e) (e) #endif #define GROUP_NR(e) ((e) - EL_GROUP_START) #define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE) #define IS_IN_GROUP_EL(e, ge) (IS_IN_GROUP(e, (ge) - EL_GROUP_START)) #define IS_EQUAL_OR_IN_GROUP(e, ge) \ (ge == EL_ANY_ELEMENT ? TRUE : \ IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge)) #define IS_PLAYER(x, y) (ELEM_IS_PLAYER(StorePlayer[x][y])) #define IS_FREE(x, y) (Feld[x][y] == EL_EMPTY && !IS_PLAYER(x, y)) #define IS_FREE_OR_PLAYER(x, y) (Feld[x][y] == EL_EMPTY) #define IS_MOVING(x,y) (MovPos[x][y] != 0) #define IS_FALLING(x,y) (MovPos[x][y] != 0 && MovDir[x][y] == MV_DOWN) #define IS_BLOCKED(x,y) (Feld[x][y] == EL_BLOCKED) #define IS_MV_DIAGONAL(x) ((x) & MV_HORIZONTAL && (x) & MV_VERTICAL) #define EL_CHANGED(e) ((e) == EL_ROCK ? EL_EMERALD : \ (e) == EL_BD_ROCK ? EL_BD_DIAMOND : \ (e) == EL_EMERALD ? EL_DIAMOND : \ (e) == EL_EMERALD_YELLOW ? EL_DIAMOND : \ (e) == EL_EMERALD_RED ? EL_DIAMOND : \ (e) == EL_EMERALD_PURPLE ? EL_DIAMOND : \ EL_ROCK) #define EL_CHANGED_BD(e) ((e) == EL_ROCK ? EL_BD_DIAMOND : \ (e) == EL_BD_ROCK ? EL_BD_DIAMOND : \ EL_BD_ROCK) #define EL_CHANGED_DC(e) ((e) == EL_ROCK ? EL_EMERALD : \ (e) == EL_BD_ROCK ? EL_BD_DIAMOND : \ (e) == EL_EMERALD ? EL_DIAMOND : \ (e) == EL_EMERALD_YELLOW ? EL_DIAMOND : \ (e) == EL_EMERALD_RED ? EL_DIAMOND : \ (e) == EL_EMERALD_PURPLE ? EL_DIAMOND : \ (e) == EL_PEARL ? EL_BOMB : \ (e) == EL_CRYSTAL ? EL_CRYSTAL : \ EL_ROCK) #define IS_DRAWABLE(e) ((e) < EL_BLOCKED) #define IS_NOT_DRAWABLE(e) ((e) >= EL_BLOCKED) #define TAPE_IS_EMPTY(x) ((x).length == 0) #define TAPE_IS_STOPPED(x) (!(x).recording && !(x).playing) #define PLAYERINFO(x,y) (&stored_player[StorePlayer[x][y]-EL_PLAYER_1]) #define SHIELD_ON(p) ((p)->shield_normal_time_left > 0) #define ENEMY_PROTECTED_FIELD(x,y) (IS_PROTECTED(Feld[x][y]) || \ IS_PROTECTED(Back[x][y])) #define EXPLOSION_PROTECTED_FIELD(x,y) (IS_EXPLOSION_PROOF(Feld[x][y])) #define PLAYER_ENEMY_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) || \ ENEMY_PROTECTED_FIELD(x, y)) #define PLAYER_EXPLOSION_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) || \ EXPLOSION_PROTECTED_FIELD(x, y)) #define PLAYER_SWITCHING(p,x,y) ((p)->is_switching && \ (p)->switch_x == (x) && (p)->switch_y == (y)) #define PLAYER_DROPPING(p,x,y) ((p)->is_dropping && \ (p)->drop_x == (x) && (p)->drop_y == (y)) #define PLAYER_NR_GFX(g,i) ((g) + i * (IMG_PLAYER_2 - IMG_PLAYER_1)) #define GET_PLAYER_ELEMENT(e) ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? \ (e) : EL_PLAYER_1) #define GET_PLAYER_NR(e) (GET_PLAYER_ELEMENT(e) - EL_PLAYER_1) #define ANIM_FRAMES(g) (graphic_info[g].anim_frames) #define ANIM_DELAY(g) (graphic_info[g].anim_delay) #define ANIM_MODE(g) (graphic_info[g].anim_mode) #define IS_ANIM_MODE_CE(g) (graphic_info[g].anim_mode & (ANIM_CE_VALUE | \ ANIM_CE_SCORE | \ ANIM_CE_DELAY)) #define IS_ANIMATED(g) (ANIM_FRAMES(g) > 1) #define IS_NEW_DELAY(f, g) ((f) % ANIM_DELAY(g) == 0) #define IS_NEW_FRAME(f, g) (IS_ANIMATED(g) && IS_NEW_DELAY(f, g)) #define IS_NEXT_FRAME(f, g) (IS_NEW_FRAME(f, g) && (f) > 0) #define IS_LOOP_SOUND(s) (sound_info[s].loop) #define IS_SPECIAL_GFX_ARG(a) ((a) >= 0 && (a) < NUM_SPECIAL_GFX_ARGS) #define IS_GLOBAL_ANIM_PART(a) ((a) >= 0 && (a) < NUM_GLOBAL_ANIM_PARTS) #define EL_CASCADE_ACTIVE(e) (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : (e)) #define EL_CASCADE_INACTIVE(e) (IS_EDITOR_CASCADE_ACTIVE(e) ? (e) - 1 : (e)) #define EL_CASCADE_TOGGLE(e) (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : \ IS_EDITOR_CASCADE_ACTIVE(e) ? (e) - 1 : (e)) #define EL_NAME(e) ((e) >= 0 ? element_info[e].token_name : "(?)") #define MV_TEXT(d) ((d) == MV_NONE ? "MV_NONE" : \ (d) == MV_LEFT ? "MV_LEFT" : \ (d) == MV_RIGHT ? "MV_RIGHT" : \ (d) == MV_UP ? "MV_UP" : \ (d) == MV_DOWN ? "MV_DOWN" : "(various)") #define ELEMENT_ACTIVE(e) (ActiveElement[e]) #define BUTTON_ACTIVE(b) (ActiveButton[b]) #define FONT_ACTIVE(f) (ActiveFont[f]) /* fundamental game speed values */ #define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */ #define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */ /* boundaries of arrays etc. */ #define MAX_LEVEL_NAME_LEN 32 #define MAX_LEVEL_AUTHOR_LEN 32 #define MAX_ELEMENT_NAME_LEN 32 #define MAX_TAPES_PER_SET 1024 #define MAX_SCORE_ENTRIES 100 #define MAX_NUM_TITLE_IMAGES 5 #define MAX_NUM_TITLE_MESSAGES 5 #define MAX_NUM_AMOEBA 100 #define NUM_ENVELOPES 4 #define MIN_ENVELOPE_XSIZE 1 #define MIN_ENVELOPE_YSIZE 1 #define MAX_ENVELOPE_XSIZE 30 #define MAX_ENVELOPE_YSIZE 20 #define MAX_ENVELOPE_TEXT_LEN (MAX_ENVELOPE_XSIZE * MAX_ENVELOPE_YSIZE) #define MIN_CHANGE_PAGES 1 #define MAX_CHANGE_PAGES 32 #define MIN_ELEMENTS_IN_GROUP 1 #define MAX_ELEMENTS_IN_GROUP 16 #define MIN_ANDROID_ELEMENTS 1 #define MAX_ANDROID_ELEMENTS 16 /* values for elements with content */ #define MIN_ELEMENT_CONTENTS 1 #define STD_ELEMENT_CONTENTS 4 #define MAX_ELEMENT_CONTENTS 8 /* values for initial player inventory */ #define MIN_INITIAL_INVENTORY_SIZE 1 #define MAX_INITIAL_INVENTORY_SIZE 8 /* often used screen positions */ #define TILESIZE 32 #define TILEX TILESIZE #define TILEY TILESIZE #define TILEX_VAR TILESIZE_VAR #define TILEY_VAR TILESIZE_VAR #define MINI_TILESIZE (TILESIZE / 2) #define MINI_TILEX MINI_TILESIZE #define MINI_TILEY MINI_TILESIZE #define MICRO_TILESIZE (TILESIZE / 8) #define MICRO_TILEX MICRO_TILESIZE #define MICRO_TILEY MICRO_TILESIZE #define MIDPOSX (SCR_FIELDX / 2) #define MIDPOSY (SCR_FIELDY / 2) #define FXSIZE ((2 + SCR_FIELDX + 2) * TILEX_VAR) #define FYSIZE ((2 + SCR_FIELDY + 2) * TILEY_VAR) #define MICROLEVEL_XSIZE ((STD_LEV_FIELDX + 2) * MICRO_TILEX) #define MICROLEVEL_YSIZE ((STD_LEV_FIELDY + 2) * MICRO_TILEY) #define MICROLEVEL_XPOS (SX + (SXSIZE - MICROLEVEL_XSIZE) / 2) #define MICROLEVEL_YPOS (SY + 12 * TILEY - MICRO_TILEY) #define MICROLABEL1_YPOS (MICROLEVEL_YPOS - 36) #define MICROLABEL2_YPOS (MICROLEVEL_YPOS + MICROLEVEL_YSIZE + 7) /* values for GfxRedraw */ #define GFX_REDRAW_NONE (0) #define GFX_REDRAW_TILE (1 << 0) #define GFX_REDRAW_TILE_CRUMBLED (1 << 1) #define GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS (1 << 2) #define GFX_REDRAW_TILE_TWINKLED (1 << 3) /* score for elements */ #define SC_EMERALD 0 #define SC_DIAMOND 1 #define SC_BUG 2 #define SC_SPACESHIP 3 #define SC_YAMYAM 4 #define SC_ROBOT 5 #define SC_PACMAN 6 #define SC_NUT 7 #define SC_DYNAMITE 8 #define SC_KEY 9 #define SC_TIME_BONUS 10 #define SC_CRYSTAL 11 #define SC_PEARL 12 #define SC_SHIELD 13 #define SC_ELEM_BONUS 14 #define SC_UNKNOWN_15 15 #define LEVEL_SCORE_ELEMENTS 16 /* level elements with score */ /* "real" level file elements */ #define EL_UNDEFINED -1 #define EL_EMPTY_SPACE 0 #define EL_EMPTY EL_EMPTY_SPACE #define EL_SAND 1 #define EL_WALL 2 #define EL_WALL_SLIPPERY 3 #define EL_ROCK 4 #define EL_KEY_OBSOLETE 5 /* obsolete; now EL_KEY_1 */ #define EL_EMERALD 6 #define EL_EXIT_CLOSED 7 #define EL_PLAYER_OBSOLETE 8 /* obsolete; now EL_PLAYER_1 */ #define EL_BUG 9 #define EL_SPACESHIP 10 #define EL_YAMYAM 11 #define EL_ROBOT 12 #define EL_STEELWALL 13 #define EL_DIAMOND 14 #define EL_AMOEBA_DEAD 15 #define EL_QUICKSAND_EMPTY 16 #define EL_QUICKSAND_FULL 17 #define EL_AMOEBA_DROP 18 #define EL_BOMB 19 #define EL_MAGIC_WALL 20 #define EL_SPEED_PILL 21 #define EL_ACID 22 #define EL_AMOEBA_WET 23 #define EL_AMOEBA_DRY 24 #define EL_NUT 25 #define EL_GAME_OF_LIFE 26 #define EL_BIOMAZE 27 #define EL_DYNAMITE_ACTIVE 28 #define EL_STONEBLOCK 29 #define EL_ROBOT_WHEEL 30 #define EL_ROBOT_WHEEL_ACTIVE 31 #define EL_KEY_1 32 #define EL_KEY_2 33 #define EL_KEY_3 34 #define EL_KEY_4 35 #define EL_GATE_1 36 #define EL_GATE_2 37 #define EL_GATE_3 38 #define EL_GATE_4 39 #define EL_GATE_1_GRAY 40 #define EL_GATE_2_GRAY 41 #define EL_GATE_3_GRAY 42 #define EL_GATE_4_GRAY 43 #define EL_DYNAMITE 44 #define EL_PACMAN 45 #define EL_INVISIBLE_WALL 46 #define EL_LAMP 47 #define EL_LAMP_ACTIVE 48 #define EL_WALL_EMERALD 49 #define EL_WALL_DIAMOND 50 #define EL_AMOEBA_FULL 51 #define EL_BD_AMOEBA 52 #define EL_TIME_ORB_FULL 53 #define EL_TIME_ORB_EMPTY 54 #define EL_EXPANDABLE_WALL 55 #define EL_BD_DIAMOND 56 #define EL_EMERALD_YELLOW 57 #define EL_WALL_BD_DIAMOND 58 #define EL_WALL_EMERALD_YELLOW 59 #define EL_DARK_YAMYAM 60 #define EL_BD_MAGIC_WALL 61 #define EL_INVISIBLE_STEELWALL 62 #define EL_SOKOBAN_FIELD_PLAYER 63 #define EL_DYNABOMB_INCREASE_NUMBER 64 #define EL_DYNABOMB_INCREASE_SIZE 65 #define EL_DYNABOMB_INCREASE_POWER 66 #define EL_SOKOBAN_OBJECT 67 #define EL_SOKOBAN_FIELD_EMPTY 68 #define EL_SOKOBAN_FIELD_FULL 69 #define EL_BD_BUTTERFLY_RIGHT 70 #define EL_BD_BUTTERFLY_UP 71 #define EL_BD_BUTTERFLY_LEFT 72 #define EL_BD_BUTTERFLY_DOWN 73 #define EL_BD_FIREFLY_RIGHT 74 #define EL_BD_FIREFLY_UP 75 #define EL_BD_FIREFLY_LEFT 76 #define EL_BD_FIREFLY_DOWN 77 #define EL_BD_BUTTERFLY_1 EL_BD_BUTTERFLY_DOWN #define EL_BD_BUTTERFLY_2 EL_BD_BUTTERFLY_LEFT #define EL_BD_BUTTERFLY_3 EL_BD_BUTTERFLY_UP #define EL_BD_BUTTERFLY_4 EL_BD_BUTTERFLY_RIGHT #define EL_BD_FIREFLY_1 EL_BD_FIREFLY_LEFT #define EL_BD_FIREFLY_2 EL_BD_FIREFLY_DOWN #define EL_BD_FIREFLY_3 EL_BD_FIREFLY_RIGHT #define EL_BD_FIREFLY_4 EL_BD_FIREFLY_UP #define EL_BD_BUTTERFLY 78 #define EL_BD_FIREFLY 79 #define EL_PLAYER_1 80 #define EL_PLAYER_2 81 #define EL_PLAYER_3 82 #define EL_PLAYER_4 83 #define EL_BUG_RIGHT 84 #define EL_BUG_UP 85 #define EL_BUG_LEFT 86 #define EL_BUG_DOWN 87 #define EL_SPACESHIP_RIGHT 88 #define EL_SPACESHIP_UP 89 #define EL_SPACESHIP_LEFT 90 #define EL_SPACESHIP_DOWN 91 #define EL_PACMAN_RIGHT 92 #define EL_PACMAN_UP 93 #define EL_PACMAN_LEFT 94 #define EL_PACMAN_DOWN 95 #define EL_EMERALD_RED 96 #define EL_EMERALD_PURPLE 97 #define EL_WALL_EMERALD_RED 98 #define EL_WALL_EMERALD_PURPLE 99 #define EL_ACID_POOL_TOPLEFT 100 #define EL_ACID_POOL_TOPRIGHT 101 #define EL_ACID_POOL_BOTTOMLEFT 102 #define EL_ACID_POOL_BOTTOM 103 #define EL_ACID_POOL_BOTTOMRIGHT 104 #define EL_BD_WALL 105 #define EL_BD_ROCK 106 #define EL_EXIT_OPEN 107 #define EL_BLACK_ORB 108 #define EL_AMOEBA_TO_DIAMOND 109 #define EL_MOLE 110 #define EL_PENGUIN 111 #define EL_SATELLITE 112 #define EL_ARROW_LEFT 113 #define EL_ARROW_RIGHT 114 #define EL_ARROW_UP 115 #define EL_ARROW_DOWN 116 #define EL_PIG 117 #define EL_DRAGON 118 #define EL_EM_KEY_1_FILE_OBSOLETE 119 /* obsolete; now EL_EM_KEY_1 */ #define EL_CHAR_START 120 #define EL_CHAR_ASCII0 (EL_CHAR_START - 32) #define EL_CHAR_ASCII0_START (EL_CHAR_ASCII0 + 32) #include "conf_chr.h" /* include auto-generated data structure definitions */ #define EL_CHAR_ASCII0_END (EL_CHAR_ASCII0 + 111) #define EL_CHAR_END (EL_CHAR_START + 79) #define EL_CHAR(c) (EL_CHAR_ASCII0 + MAP_FONT_ASCII(c)) #define EL_EXPANDABLE_WALL_HORIZONTAL 200 #define EL_EXPANDABLE_WALL_VERTICAL 201 #define EL_EXPANDABLE_WALL_ANY 202 #define EL_EM_GATE_1 203 #define EL_EM_GATE_2 204 #define EL_EM_GATE_3 205 #define EL_EM_GATE_4 206 #define EL_EM_KEY_2_FILE_OBSOLETE 207 /* obsolete; now EL_EM_KEY_2 */ #define EL_EM_KEY_3_FILE_OBSOLETE 208 /* obsolete; now EL_EM_KEY_3 */ #define EL_EM_KEY_4_FILE_OBSOLETE 209 /* obsolete; now EL_EM_KEY_4 */ #define EL_SP_START 210 #define EL_SP_EMPTY_SPACE (EL_SP_START + 0) #define EL_SP_EMPTY EL_SP_EMPTY_SPACE #define EL_SP_ZONK (EL_SP_START + 1) #define EL_SP_BASE (EL_SP_START + 2) #define EL_SP_MURPHY (EL_SP_START + 3) #define EL_SP_INFOTRON (EL_SP_START + 4) #define EL_SP_CHIP_SINGLE (EL_SP_START + 5) #define EL_SP_HARDWARE_GRAY (EL_SP_START + 6) #define EL_SP_EXIT_CLOSED (EL_SP_START + 7) #define EL_SP_DISK_ORANGE (EL_SP_START + 8) #define EL_SP_PORT_RIGHT (EL_SP_START + 9) #define EL_SP_PORT_DOWN (EL_SP_START + 10) #define EL_SP_PORT_LEFT (EL_SP_START + 11) #define EL_SP_PORT_UP (EL_SP_START + 12) #define EL_SP_GRAVITY_PORT_RIGHT (EL_SP_START + 13) #define EL_SP_GRAVITY_PORT_DOWN (EL_SP_START + 14) #define EL_SP_GRAVITY_PORT_LEFT (EL_SP_START + 15) #define EL_SP_GRAVITY_PORT_UP (EL_SP_START + 16) #define EL_SP_SNIKSNAK (EL_SP_START + 17) #define EL_SP_DISK_YELLOW (EL_SP_START + 18) #define EL_SP_TERMINAL (EL_SP_START + 19) #define EL_SP_DISK_RED (EL_SP_START + 20) #define EL_SP_PORT_VERTICAL (EL_SP_START + 21) #define EL_SP_PORT_HORIZONTAL (EL_SP_START + 22) #define EL_SP_PORT_ANY (EL_SP_START + 23) #define EL_SP_ELECTRON (EL_SP_START + 24) #define EL_SP_BUGGY_BASE (EL_SP_START + 25) #define EL_SP_CHIP_LEFT (EL_SP_START + 26) #define EL_SP_CHIP_RIGHT (EL_SP_START + 27) #define EL_SP_HARDWARE_BASE_1 (EL_SP_START + 28) #define EL_SP_HARDWARE_GREEN (EL_SP_START + 29) #define EL_SP_HARDWARE_BLUE (EL_SP_START + 30) #define EL_SP_HARDWARE_RED (EL_SP_START + 31) #define EL_SP_HARDWARE_YELLOW (EL_SP_START + 32) #define EL_SP_HARDWARE_BASE_2 (EL_SP_START + 33) #define EL_SP_HARDWARE_BASE_3 (EL_SP_START + 34) #define EL_SP_HARDWARE_BASE_4 (EL_SP_START + 35) #define EL_SP_HARDWARE_BASE_5 (EL_SP_START + 36) #define EL_SP_HARDWARE_BASE_6 (EL_SP_START + 37) #define EL_SP_CHIP_TOP (EL_SP_START + 38) #define EL_SP_CHIP_BOTTOM (EL_SP_START + 39) #define EL_SP_END (EL_SP_START + 39) #define EL_EM_GATE_1_GRAY 250 #define EL_EM_GATE_2_GRAY 251 #define EL_EM_GATE_3_GRAY 252 #define EL_EM_GATE_4_GRAY 253 #define EL_EM_DYNAMITE 254 #define EL_EM_DYNAMITE_ACTIVE 255 #define EL_PEARL 256 #define EL_CRYSTAL 257 #define EL_WALL_PEARL 258 #define EL_WALL_CRYSTAL 259 #define EL_DC_GATE_WHITE 260 #define EL_DC_GATE_WHITE_GRAY 261 #define EL_DC_KEY_WHITE 262 #define EL_SHIELD_NORMAL 263 #define EL_EXTRA_TIME 264 #define EL_SWITCHGATE_OPEN 265 #define EL_SWITCHGATE_CLOSED 266 #define EL_SWITCHGATE_SWITCH_UP 267 #define EL_SWITCHGATE_SWITCH_DOWN 268 #define EL_UNUSED_269 269 #define EL_UNUSED_270 270 #define EL_CONVEYOR_BELT_1_LEFT 271 #define EL_CONVEYOR_BELT_1_MIDDLE 272 #define EL_CONVEYOR_BELT_1_RIGHT 273 #define EL_CONVEYOR_BELT_1_SWITCH_LEFT 274 #define EL_CONVEYOR_BELT_1_SWITCH_MIDDLE 275 #define EL_CONVEYOR_BELT_1_SWITCH_RIGHT 276 #define EL_CONVEYOR_BELT_2_LEFT 277 #define EL_CONVEYOR_BELT_2_MIDDLE 278 #define EL_CONVEYOR_BELT_2_RIGHT 279 #define EL_CONVEYOR_BELT_2_SWITCH_LEFT 280 #define EL_CONVEYOR_BELT_2_SWITCH_MIDDLE 281 #define EL_CONVEYOR_BELT_2_SWITCH_RIGHT 282 #define EL_CONVEYOR_BELT_3_LEFT 283 #define EL_CONVEYOR_BELT_3_MIDDLE 284 #define EL_CONVEYOR_BELT_3_RIGHT 285 #define EL_CONVEYOR_BELT_3_SWITCH_LEFT 286 #define EL_CONVEYOR_BELT_3_SWITCH_MIDDLE 287 #define EL_CONVEYOR_BELT_3_SWITCH_RIGHT 288 #define EL_CONVEYOR_BELT_4_LEFT 289 #define EL_CONVEYOR_BELT_4_MIDDLE 290 #define EL_CONVEYOR_BELT_4_RIGHT 291 #define EL_CONVEYOR_BELT_4_SWITCH_LEFT 292 #define EL_CONVEYOR_BELT_4_SWITCH_MIDDLE 293 #define EL_CONVEYOR_BELT_4_SWITCH_RIGHT 294 #define EL_LANDMINE 295 #define EL_ENVELOPE_OBSOLETE 296 /* obsolete; now EL_ENVELOPE_1 */ #define EL_LIGHT_SWITCH 297 #define EL_LIGHT_SWITCH_ACTIVE 298 #define EL_SIGN_EXCLAMATION 299 #define EL_SIGN_RADIOACTIVITY 300 #define EL_SIGN_STOP 301 #define EL_SIGN_WHEELCHAIR 302 #define EL_SIGN_PARKING 303 #define EL_SIGN_NO_ENTRY 304 #define EL_SIGN_UNUSED_1 305 #define EL_SIGN_GIVE_WAY 306 #define EL_SIGN_ENTRY_FORBIDDEN 307 #define EL_SIGN_EMERGENCY_EXIT 308 #define EL_SIGN_YIN_YANG 309 #define EL_SIGN_UNUSED_2 310 #define EL_MOLE_LEFT 311 #define EL_MOLE_RIGHT 312 #define EL_MOLE_UP 313 #define EL_MOLE_DOWN 314 #define EL_STEELWALL_SLIPPERY 315 #define EL_INVISIBLE_SAND 316 #define EL_DX_UNKNOWN_15 317 #define EL_DX_UNKNOWN_42 318 #define EL_UNUSED_319 319 #define EL_UNUSED_320 320 #define EL_SHIELD_DEADLY 321 #define EL_TIMEGATE_OPEN 322 #define EL_TIMEGATE_CLOSED 323 #define EL_TIMEGATE_SWITCH_ACTIVE 324 #define EL_TIMEGATE_SWITCH 325 #define EL_BALLOON 326 #define EL_BALLOON_SWITCH_LEFT 327 #define EL_BALLOON_SWITCH_RIGHT 328 #define EL_BALLOON_SWITCH_UP 329 #define EL_BALLOON_SWITCH_DOWN 330 #define EL_BALLOON_SWITCH_ANY 331 #define EL_EMC_STEELWALL_1 332 #define EL_EMC_STEELWALL_2 333 #define EL_EMC_STEELWALL_3 334 #define EL_EMC_STEELWALL_4 335 #define EL_EMC_WALL_1 336 #define EL_EMC_WALL_2 337 #define EL_EMC_WALL_3 338 #define EL_EMC_WALL_4 339 #define EL_EMC_WALL_5 340 #define EL_EMC_WALL_6 341 #define EL_EMC_WALL_7 342 #define EL_EMC_WALL_8 343 #define EL_TUBE_ANY 344 #define EL_TUBE_VERTICAL 345 #define EL_TUBE_HORIZONTAL 346 #define EL_TUBE_VERTICAL_LEFT 347 #define EL_TUBE_VERTICAL_RIGHT 348 #define EL_TUBE_HORIZONTAL_UP 349 #define EL_TUBE_HORIZONTAL_DOWN 350 #define EL_TUBE_LEFT_UP 351 #define EL_TUBE_LEFT_DOWN 352 #define EL_TUBE_RIGHT_UP 353 #define EL_TUBE_RIGHT_DOWN 354 #define EL_SPRING 355 #define EL_TRAP 356 #define EL_DX_SUPABOMB 357 #define EL_UNUSED_358 358 #define EL_UNUSED_359 359 /* ---------- begin of custom elements section ----------------------------- */ #define EL_CUSTOM_START 360 #include "conf_cus.h" /* include auto-generated data structure definitions */ #define NUM_CUSTOM_ELEMENTS 256 #define EL_CUSTOM_END 615 /* ---------- end of custom elements section ------------------------------- */ #define EL_EM_KEY_1 616 #define EL_EM_KEY_2 617 #define EL_EM_KEY_3 618 #define EL_EM_KEY_4 619 #define EL_ENVELOPE_1 620 #define EL_ENVELOPE_2 621 #define EL_ENVELOPE_3 622 #define EL_ENVELOPE_4 623 /* ---------- begin of group elements section ------------------------------ */ #define EL_GROUP_START 624 #include "conf_grp.h" /* include auto-generated data structure definitions */ #define NUM_GROUP_ELEMENTS 32 #define EL_GROUP_END 655 /* ---------- end of custom elements section ------------------------------- */ #define EL_UNKNOWN 656 #define EL_TRIGGER_ELEMENT 657 #define EL_TRIGGER_PLAYER 658 /* SP style elements */ #define EL_SP_GRAVITY_ON_PORT_RIGHT 659 #define EL_SP_GRAVITY_ON_PORT_DOWN 660 #define EL_SP_GRAVITY_ON_PORT_LEFT 661 #define EL_SP_GRAVITY_ON_PORT_UP 662 #define EL_SP_GRAVITY_OFF_PORT_RIGHT 663 #define EL_SP_GRAVITY_OFF_PORT_DOWN 664 #define EL_SP_GRAVITY_OFF_PORT_LEFT 665 #define EL_SP_GRAVITY_OFF_PORT_UP 666 /* EMC style elements */ #define EL_BALLOON_SWITCH_NONE 667 #define EL_EMC_GATE_5 668 #define EL_EMC_GATE_6 669 #define EL_EMC_GATE_7 670 #define EL_EMC_GATE_8 671 #define EL_EMC_GATE_5_GRAY 672 #define EL_EMC_GATE_6_GRAY 673 #define EL_EMC_GATE_7_GRAY 674 #define EL_EMC_GATE_8_GRAY 675 #define EL_EMC_KEY_5 676 #define EL_EMC_KEY_6 677 #define EL_EMC_KEY_7 678 #define EL_EMC_KEY_8 679 #define EL_EMC_ANDROID 680 #define EL_EMC_GRASS 681 #define EL_EMC_MAGIC_BALL 682 #define EL_EMC_MAGIC_BALL_ACTIVE 683 #define EL_EMC_MAGIC_BALL_SWITCH 684 #define EL_EMC_MAGIC_BALL_SWITCH_ACTIVE 685 #define EL_EMC_SPRING_BUMPER 686 #define EL_EMC_PLANT 687 #define EL_EMC_LENSES 688 #define EL_EMC_MAGNIFIER 689 #define EL_EMC_WALL_9 690 #define EL_EMC_WALL_10 691 #define EL_EMC_WALL_11 692 #define EL_EMC_WALL_12 693 #define EL_EMC_WALL_13 694 #define EL_EMC_WALL_14 695 #define EL_EMC_WALL_15 696 #define EL_EMC_WALL_16 697 #define EL_EMC_WALL_SLIPPERY_1 698 #define EL_EMC_WALL_SLIPPERY_2 699 #define EL_EMC_WALL_SLIPPERY_3 700 #define EL_EMC_WALL_SLIPPERY_4 701 #define EL_EMC_FAKE_GRASS 702 #define EL_EMC_FAKE_ACID 703 #define EL_EMC_DRIPPER 704 #define EL_TRIGGER_CE_VALUE 705 #define EL_TRIGGER_CE_SCORE 706 #define EL_CURRENT_CE_VALUE 707 #define EL_CURRENT_CE_SCORE 708 #define EL_YAMYAM_LEFT 709 #define EL_YAMYAM_RIGHT 710 #define EL_YAMYAM_UP 711 #define EL_YAMYAM_DOWN 712 #define EL_BD_EXPANDABLE_WALL 713 #define EL_PREV_CE_8 714 #define EL_PREV_CE_7 715 #define EL_PREV_CE_6 716 #define EL_PREV_CE_5 717 #define EL_PREV_CE_4 718 #define EL_PREV_CE_3 719 #define EL_PREV_CE_2 720 #define EL_PREV_CE_1 721 #define EL_SELF 722 #define EL_NEXT_CE_1 723 #define EL_NEXT_CE_2 724 #define EL_NEXT_CE_3 725 #define EL_NEXT_CE_4 726 #define EL_NEXT_CE_5 727 #define EL_NEXT_CE_6 728 #define EL_NEXT_CE_7 729 #define EL_NEXT_CE_8 730 #define EL_ANY_ELEMENT 731 #define EL_STEEL_CHAR_START 732 #define EL_STEEL_CHAR_ASCII0 (EL_STEEL_CHAR_START - 32) #define EL_STEEL_CHAR_ASCII0_START (EL_STEEL_CHAR_ASCII0 + 32) /* (auto-generated data structure definitions included with normal chars) */ #define EL_STEEL_CHAR_ASCII0_END (EL_STEEL_CHAR_ASCII0 + 111) #define EL_STEEL_CHAR_END (EL_STEEL_CHAR_START + 79) #define EL_STEEL_CHAR(c) (EL_STEEL_CHAR_ASCII0+MAP_FONT_ASCII(c)) #define EL_SPERMS 812 #define EL_BULLET 813 #define EL_HEART 814 #define EL_CROSS 815 #define EL_FRANKIE 816 #define EL_SIGN_SPERMS 817 #define EL_SIGN_BULLET 818 #define EL_SIGN_HEART 819 #define EL_SIGN_CROSS 820 #define EL_SIGN_FRANKIE 821 #define EL_STEEL_EXIT_CLOSED 822 #define EL_STEEL_EXIT_OPEN 823 #define EL_DC_STEELWALL_1_LEFT 824 #define EL_DC_STEELWALL_1_RIGHT 825 #define EL_DC_STEELWALL_1_TOP 826 #define EL_DC_STEELWALL_1_BOTTOM 827 #define EL_DC_STEELWALL_1_HORIZONTAL 828 #define EL_DC_STEELWALL_1_VERTICAL 829 #define EL_DC_STEELWALL_1_TOPLEFT 830 #define EL_DC_STEELWALL_1_TOPRIGHT 831 #define EL_DC_STEELWALL_1_BOTTOMLEFT 832 #define EL_DC_STEELWALL_1_BOTTOMRIGHT 833 #define EL_DC_STEELWALL_1_TOPLEFT_2 834 #define EL_DC_STEELWALL_1_TOPRIGHT_2 835 #define EL_DC_STEELWALL_1_BOTTOMLEFT_2 836 #define EL_DC_STEELWALL_1_BOTTOMRIGHT_2 837 #define EL_DC_STEELWALL_2_LEFT 838 #define EL_DC_STEELWALL_2_RIGHT 839 #define EL_DC_STEELWALL_2_TOP 840 #define EL_DC_STEELWALL_2_BOTTOM 841 #define EL_DC_STEELWALL_2_HORIZONTAL 842 #define EL_DC_STEELWALL_2_VERTICAL 843 #define EL_DC_STEELWALL_2_MIDDLE 844 #define EL_DC_STEELWALL_2_SINGLE 845 #define EL_DC_SWITCHGATE_SWITCH_UP 846 #define EL_DC_SWITCHGATE_SWITCH_DOWN 847 #define EL_DC_TIMEGATE_SWITCH 848 #define EL_DC_TIMEGATE_SWITCH_ACTIVE 849 #define EL_DC_LANDMINE 850 #define EL_EXPANDABLE_STEELWALL 851 #define EL_EXPANDABLE_STEELWALL_HORIZONTAL 852 #define EL_EXPANDABLE_STEELWALL_VERTICAL 853 #define EL_EXPANDABLE_STEELWALL_ANY 854 #define EL_EM_EXIT_CLOSED 855 #define EL_EM_EXIT_OPEN 856 #define EL_EM_STEEL_EXIT_CLOSED 857 #define EL_EM_STEEL_EXIT_OPEN 858 #define EL_DC_GATE_FAKE_GRAY 859 #define EL_DC_MAGIC_WALL 860 #define EL_QUICKSAND_FAST_EMPTY 861 #define EL_QUICKSAND_FAST_FULL 862 #define EL_FROM_LEVEL_TEMPLATE 863 #define EL_MM_START 864 #define EL_MM_START_1 EL_MM_START #define EL_MM_EMPTY_SPACE (EL_MM_START + 0) #define EL_MM_EMPTY EL_MM_EMPTY_SPACE #define EL_MM_MIRROR_START (EL_MM_START + 1) #define EL_MM_MIRROR_1 (EL_MM_MIRROR_START + 0) #define EL_MM_MIRROR_2 (EL_MM_MIRROR_START + 1) #define EL_MM_MIRROR_3 (EL_MM_MIRROR_START + 2) #define EL_MM_MIRROR_4 (EL_MM_MIRROR_START + 3) #define EL_MM_MIRROR_5 (EL_MM_MIRROR_START + 4) #define EL_MM_MIRROR_6 (EL_MM_MIRROR_START + 5) #define EL_MM_MIRROR_7 (EL_MM_MIRROR_START + 6) #define EL_MM_MIRROR_8 (EL_MM_MIRROR_START + 7) #define EL_MM_MIRROR_9 (EL_MM_MIRROR_START + 8) #define EL_MM_MIRROR_10 (EL_MM_MIRROR_START + 9) #define EL_MM_MIRROR_11 (EL_MM_MIRROR_START + 10) #define EL_MM_MIRROR_12 (EL_MM_MIRROR_START + 11) #define EL_MM_MIRROR_13 (EL_MM_MIRROR_START + 12) #define EL_MM_MIRROR_14 (EL_MM_MIRROR_START + 13) #define EL_MM_MIRROR_15 (EL_MM_MIRROR_START + 14) #define EL_MM_MIRROR_16 (EL_MM_MIRROR_START + 15) #define EL_MM_MIRROR_END EL_MM_MIRROR_15 #define EL_MM_STEEL_GRID_FIXED_START (EL_MM_START + 17) #define EL_MM_STEEL_GRID_FIXED_1 (EL_MM_STEEL_GRID_FIXED_START + 0) #define EL_MM_STEEL_GRID_FIXED_2 (EL_MM_STEEL_GRID_FIXED_START + 1) #define EL_MM_STEEL_GRID_FIXED_3 (EL_MM_STEEL_GRID_FIXED_START + 2) #define EL_MM_STEEL_GRID_FIXED_4 (EL_MM_STEEL_GRID_FIXED_START + 3) #define EL_MM_STEEL_GRID_FIXED_END EL_MM_STEEL_GRID_FIXED_03 #define EL_MM_MCDUFFIN_START (EL_MM_START + 21) #define EL_MM_MCDUFFIN_RIGHT (EL_MM_MCDUFFIN_START + 0) #define EL_MM_MCDUFFIN_UP (EL_MM_MCDUFFIN_START + 1) #define EL_MM_MCDUFFIN_LEFT (EL_MM_MCDUFFIN_START + 2) #define EL_MM_MCDUFFIN_DOWN (EL_MM_MCDUFFIN_START + 3) #define EL_MM_MCDUFFIN_END EL_MM_MCDUFFIN_DOWN #define EL_MM_EXIT_CLOSED (EL_MM_START + 25) #define EL_MM_EXIT_OPENING_1 (EL_MM_START + 26) #define EL_MM_EXIT_OPENING_2 (EL_MM_START + 27) #define EL_MM_EXIT_OPEN (EL_MM_START + 28) #define EL_MM_KETTLE (EL_MM_START + 29) #define EL_MM_BOMB (EL_MM_START + 30) #define EL_MM_PRISM (EL_MM_START + 31) #define EL_MM_WALL_START (EL_MM_START + 32) #define EL_MM_WALL_EMPTY EL_MM_WALL_START #define EL_MM_WALL_00 EL_MM_WALL_START #define EL_MM_STEEL_WALL_START EL_MM_WALL_00 #define EL_MM_STEEL_WALL_1 EL_MM_STEEL_WALL_START #define EL_MM_WALL_15 (EL_MM_START + 47) #define EL_MM_STEEL_WALL_END EL_MM_WALL_15 #define EL_MM_WALL_16 (EL_MM_START + 48) #define EL_MM_WOODEN_WALL_START EL_MM_WALL_16 #define EL_MM_WOODEN_WALL_1 EL_MM_WOODEN_WALL_START #define EL_MM_WALL_31 (EL_MM_START + 63) #define EL_MM_WOODEN_WALL_END EL_MM_WALL_31 #define EL_MM_WALL_32 (EL_MM_START + 64) #define EL_MM_ICE_WALL_START EL_MM_WALL_32 #define EL_MM_ICE_WALL_1 EL_MM_ICE_WALL_START #define EL_MM_WALL_47 (EL_MM_START + 79) #define EL_MM_ICE_WALL_END EL_MM_WALL_47 #define EL_MM_WALL_48 (EL_MM_START + 80) #define EL_MM_AMOEBA_WALL_START EL_MM_WALL_48 #define EL_MM_AMOEBA_WALL_1 EL_MM_AMOEBA_WALL_START #define EL_MM_WALL_63 (EL_MM_START + 95) #define EL_MM_AMOEBA_WALL_END EL_MM_WALL_63 #define EL_MM_WALL_END EL_MM_WALL_63 #define EL_MM_WOODEN_BLOCK (EL_MM_START + 96) #define EL_MM_GRAY_BALL (EL_MM_START + 97) #define EL_MM_TELEPORTER_START (EL_MM_START + 98) #define EL_MM_TELEPORTER_1 (EL_MM_TELEPORTER_START + 0) #define EL_MM_TELEPORTER_2 (EL_MM_TELEPORTER_START + 1) #define EL_MM_TELEPORTER_3 (EL_MM_TELEPORTER_START + 2) #define EL_MM_TELEPORTER_4 (EL_MM_TELEPORTER_START + 3) #define EL_MM_TELEPORTER_5 (EL_MM_TELEPORTER_START + 4) #define EL_MM_TELEPORTER_6 (EL_MM_TELEPORTER_START + 5) #define EL_MM_TELEPORTER_7 (EL_MM_TELEPORTER_START + 6) #define EL_MM_TELEPORTER_8 (EL_MM_TELEPORTER_START + 7) #define EL_MM_TELEPORTER_9 (EL_MM_TELEPORTER_START + 8) #define EL_MM_TELEPORTER_10 (EL_MM_TELEPORTER_START + 9) #define EL_MM_TELEPORTER_11 (EL_MM_TELEPORTER_START + 10) #define EL_MM_TELEPORTER_12 (EL_MM_TELEPORTER_START + 11) #define EL_MM_TELEPORTER_13 (EL_MM_TELEPORTER_START + 12) #define EL_MM_TELEPORTER_14 (EL_MM_TELEPORTER_START + 13) #define EL_MM_TELEPORTER_15 (EL_MM_TELEPORTER_START + 14) #define EL_MM_TELEPORTER_16 (EL_MM_TELEPORTER_START + 15) #define EL_MM_TELEPORTER_END EL_MM_TELEPORTER_15 #define EL_MM_FUSE_ACTIVE (EL_MM_START + 114) #define EL_MM_PACMAN_START (EL_MM_START + 115) #define EL_MM_PACMAN_RIGHT (EL_MM_PACMAN_START + 0) #define EL_MM_PACMAN_UP (EL_MM_PACMAN_START + 1) #define EL_MM_PACMAN_LEFT (EL_MM_PACMAN_START + 2) #define EL_MM_PACMAN_DOWN (EL_MM_PACMAN_START + 3) #define EL_MM_PACMAN_END EL_MM_PACMAN_DOWN #define EL_MM_POLARIZER_START (EL_MM_START + 119) #define EL_MM_POLARIZER_1 (EL_MM_POLARIZER_START + 0) #define EL_MM_POLARIZER_2 (EL_MM_POLARIZER_START + 1) #define EL_MM_POLARIZER_3 (EL_MM_POLARIZER_START + 2) #define EL_MM_POLARIZER_4 (EL_MM_POLARIZER_START + 3) #define EL_MM_POLARIZER_5 (EL_MM_POLARIZER_START + 4) #define EL_MM_POLARIZER_6 (EL_MM_POLARIZER_START + 5) #define EL_MM_POLARIZER_7 (EL_MM_POLARIZER_START + 6) #define EL_MM_POLARIZER_8 (EL_MM_POLARIZER_START + 7) #define EL_MM_POLARIZER_9 (EL_MM_POLARIZER_START + 8) #define EL_MM_POLARIZER_10 (EL_MM_POLARIZER_START + 9) #define EL_MM_POLARIZER_11 (EL_MM_POLARIZER_START + 10) #define EL_MM_POLARIZER_12 (EL_MM_POLARIZER_START + 11) #define EL_MM_POLARIZER_13 (EL_MM_POLARIZER_START + 12) #define EL_MM_POLARIZER_14 (EL_MM_POLARIZER_START + 13) #define EL_MM_POLARIZER_15 (EL_MM_POLARIZER_START + 14) #define EL_MM_POLARIZER_16 (EL_MM_POLARIZER_START + 15) #define EL_MM_POLARIZER_END EL_MM_POLARIZER_15 #define EL_MM_POLARIZER_CROSS_START (EL_MM_START + 135) #define EL_MM_POLARIZER_CROSS_1 (EL_MM_POLARIZER_CROSS_START + 0) #define EL_MM_POLARIZER_CROSS_2 (EL_MM_POLARIZER_CROSS_START + 1) #define EL_MM_POLARIZER_CROSS_3 (EL_MM_POLARIZER_CROSS_START + 2) #define EL_MM_POLARIZER_CROSS_4 (EL_MM_POLARIZER_CROSS_START + 3) #define EL_MM_POLARIZER_CROSS_END EL_MM_POLARIZER_CROSS_03 #define EL_MM_MIRROR_FIXED_START (EL_MM_START + 139) #define EL_MM_MIRROR_FIXED_1 (EL_MM_MIRROR_FIXED_START + 0) #define EL_MM_MIRROR_FIXED_2 (EL_MM_MIRROR_FIXED_START + 1) #define EL_MM_MIRROR_FIXED_3 (EL_MM_MIRROR_FIXED_START + 2) #define EL_MM_MIRROR_FIXED_4 (EL_MM_MIRROR_FIXED_START + 3) #define EL_MM_MIRROR_FIXED_END EL_MM_MIRROR_FIXED_03 #define EL_MM_STEEL_LOCK (EL_MM_START + 143) #define EL_MM_KEY (EL_MM_START + 144) #define EL_MM_LIGHTBULB (EL_MM_START + 145) #define EL_MM_LIGHTBULB_ACTIVE (EL_MM_START + 146) #define EL_MM_LIGHTBALL (EL_MM_START + 147) #define EL_MM_STEEL_BLOCK (EL_MM_START + 148) #define EL_MM_WOODEN_LOCK (EL_MM_START + 149) #define EL_MM_FUEL_FULL (EL_MM_START + 150) #define EL_MM_WOODEN_GRID_FIXED_START (EL_MM_START + 151) #define EL_MM_WOODEN_GRID_FIXED_1 (EL_MM_WOODEN_GRID_FIXED_START + 0) #define EL_MM_WOODEN_GRID_FIXED_2 (EL_MM_WOODEN_GRID_FIXED_START + 1) #define EL_MM_WOODEN_GRID_FIXED_3 (EL_MM_WOODEN_GRID_FIXED_START + 2) #define EL_MM_WOODEN_GRID_FIXED_4 (EL_MM_WOODEN_GRID_FIXED_START + 3) #define EL_MM_WOODEN_GRID_FIXED_END EL_MM_WOODEN_GRID_FIXED_03 #define EL_MM_FUEL_EMPTY (EL_MM_START + 155) #define EL_MM_UNUSED_156 (EL_MM_START + 156) #define EL_MM_UNUSED_157 (EL_MM_START + 157) #define EL_MM_UNUSED_158 (EL_MM_START + 158) #define EL_MM_UNUSED_159 (EL_MM_START + 159) #define EL_MM_END_1 (EL_MM_START + 159) #define EL_MM_START_2 (EL_MM_START + 160) #define EL_DF_START EL_MM_START_2 #define EL_DF_START2 (EL_DF_START - 240) #define EL_DF_MIRROR_START EL_DF_START #define EL_DF_MIRROR_1 (EL_DF_MIRROR_START + 0) #define EL_DF_MIRROR_2 (EL_DF_MIRROR_START + 1) #define EL_DF_MIRROR_3 (EL_DF_MIRROR_START + 2) #define EL_DF_MIRROR_4 (EL_DF_MIRROR_START + 3) #define EL_DF_MIRROR_5 (EL_DF_MIRROR_START + 4) #define EL_DF_MIRROR_6 (EL_DF_MIRROR_START + 5) #define EL_DF_MIRROR_7 (EL_DF_MIRROR_START + 6) #define EL_DF_MIRROR_8 (EL_DF_MIRROR_START + 7) #define EL_DF_MIRROR_9 (EL_DF_MIRROR_START + 8) #define EL_DF_MIRROR_10 (EL_DF_MIRROR_START + 9) #define EL_DF_MIRROR_11 (EL_DF_MIRROR_START + 10) #define EL_DF_MIRROR_12 (EL_DF_MIRROR_START + 11) #define EL_DF_MIRROR_13 (EL_DF_MIRROR_START + 12) #define EL_DF_MIRROR_14 (EL_DF_MIRROR_START + 13) #define EL_DF_MIRROR_15 (EL_DF_MIRROR_START + 14) #define EL_DF_MIRROR_16 (EL_DF_MIRROR_START + 15) #define EL_DF_MIRROR_END EL_DF_MIRROR_15 #define EL_DF_WOODEN_GRID_FIXED_START (EL_DF_START2 + 256) #define EL_DF_WOODEN_GRID_FIXED_1 (EL_DF_WOODEN_GRID_FIXED_START + 0) #define EL_DF_WOODEN_GRID_FIXED_2 (EL_DF_WOODEN_GRID_FIXED_START + 1) #define EL_DF_WOODEN_GRID_FIXED_3 (EL_DF_WOODEN_GRID_FIXED_START + 2) #define EL_DF_WOODEN_GRID_FIXED_4 (EL_DF_WOODEN_GRID_FIXED_START + 3) #define EL_DF_WOODEN_GRID_FIXED_5 (EL_DF_WOODEN_GRID_FIXED_START + 4) #define EL_DF_WOODEN_GRID_FIXED_6 (EL_DF_WOODEN_GRID_FIXED_START + 5) #define EL_DF_WOODEN_GRID_FIXED_7 (EL_DF_WOODEN_GRID_FIXED_START + 6) #define EL_DF_WOODEN_GRID_FIXED_8 (EL_DF_WOODEN_GRID_FIXED_START + 7) #define EL_DF_WOODEN_GRID_FIXED_END EL_DF_WOODEN_GRID_FIXED_07 #define EL_DF_STEEL_GRID_FIXED_START (EL_DF_START2 + 264) #define EL_DF_STEEL_GRID_FIXED_1 (EL_DF_STEEL_GRID_FIXED_START + 0) #define EL_DF_STEEL_GRID_FIXED_2 (EL_DF_STEEL_GRID_FIXED_START + 1) #define EL_DF_STEEL_GRID_FIXED_3 (EL_DF_STEEL_GRID_FIXED_START + 2) #define EL_DF_STEEL_GRID_FIXED_4 (EL_DF_STEEL_GRID_FIXED_START + 3) #define EL_DF_STEEL_GRID_FIXED_5 (EL_DF_STEEL_GRID_FIXED_START + 4) #define EL_DF_STEEL_GRID_FIXED_6 (EL_DF_STEEL_GRID_FIXED_START + 5) #define EL_DF_STEEL_GRID_FIXED_7 (EL_DF_STEEL_GRID_FIXED_START + 6) #define EL_DF_STEEL_GRID_FIXED_8 (EL_DF_STEEL_GRID_FIXED_START + 7) #define EL_DF_STEEL_GRID_FIXED_END EL_DF_STEEL_GRID_FIXED_07 #define EL_DF_WOODEN_WALL_START (EL_DF_START2 + 272) #define EL_DF_WOODEN_WALL_1 (EL_DF_WOODEN_WALL_START + 0) #define EL_DF_WOODEN_WALL_END (EL_DF_WOODEN_WALL_START + 15) #define EL_DF_STEEL_WALL_START (EL_DF_START2 + 288) #define EL_DF_STEEL_WALL_1 (EL_DF_STEEL_WALL_START + 0) #define EL_DF_STEEL_WALL_END (EL_DF_STEEL_WALL_START + 15) #define EL_DF_WALL_START EL_DF_WOODEN_WALL_START #define EL_DF_WALL_END EL_DF_STEEL_WALL_END #define EL_DF_EMPTY (EL_DF_START2 + 304) #define EL_DF_CELL (EL_DF_START2 + 305) #define EL_DF_MINE (EL_DF_START2 + 306) #define EL_DF_REFRACTOR (EL_DF_START2 + 307) #define EL_DF_LASER_START (EL_DF_START2 + 308) #define EL_DF_LASER_RIGHT (EL_DF_LASER_START + 0) #define EL_DF_LASER_UP (EL_DF_LASER_START + 1) #define EL_DF_LASER_LEFT (EL_DF_LASER_START + 2) #define EL_DF_LASER_DOWN (EL_DF_LASER_START + 3) #define EL_DF_LASER_END EL_DF_LASER_DOWN #define EL_DF_RECEIVER_START (EL_DF_START2 + 312) #define EL_DF_RECEIVER_RIGHT (EL_DF_RECEIVER_START + 0) #define EL_DF_RECEIVER_UP (EL_DF_RECEIVER_START + 1) #define EL_DF_RECEIVER_LEFT (EL_DF_RECEIVER_START + 2) #define EL_DF_RECEIVER_DOWN (EL_DF_RECEIVER_START + 3) #define EL_DF_RECEIVER_END EL_DF_RECEIVER_DOWN #define EL_DF_FIBRE_OPTIC_START (EL_DF_START2 + 316) #define EL_DF_FIBRE_OPTIC_RED_1 (EL_DF_FIBRE_OPTIC_START + 0) #define EL_DF_FIBRE_OPTIC_RED_2 (EL_DF_FIBRE_OPTIC_START + 1) #define EL_DF_FIBRE_OPTIC_YELLOW_1 (EL_DF_FIBRE_OPTIC_START + 2) #define EL_DF_FIBRE_OPTIC_YELLOW_2 (EL_DF_FIBRE_OPTIC_START + 3) #define EL_DF_FIBRE_OPTIC_GREEN_1 (EL_DF_FIBRE_OPTIC_START + 4) #define EL_DF_FIBRE_OPTIC_GREEN_2 (EL_DF_FIBRE_OPTIC_START + 5) #define EL_DF_FIBRE_OPTIC_BLUE_1 (EL_DF_FIBRE_OPTIC_START + 6) #define EL_DF_FIBRE_OPTIC_BLUE_2 (EL_DF_FIBRE_OPTIC_START + 7) #define EL_DF_FIBRE_OPTIC_END EL_DF_FIBRE_OPTIC_07 #define EL_DF_MIRROR_ROTATING_START (EL_DF_START2 + 324) #define EL_DF_MIRROR_ROTATING_1 (EL_DF_MIRROR_ROTATING_START + 0) #define EL_DF_MIRROR_ROTATING_2 (EL_DF_MIRROR_ROTATING_START + 1) #define EL_DF_MIRROR_ROTATING_3 (EL_DF_MIRROR_ROTATING_START + 2) #define EL_DF_MIRROR_ROTATING_4 (EL_DF_MIRROR_ROTATING_START + 3) #define EL_DF_MIRROR_ROTATING_5 (EL_DF_MIRROR_ROTATING_START + 4) #define EL_DF_MIRROR_ROTATING_6 (EL_DF_MIRROR_ROTATING_START + 5) #define EL_DF_MIRROR_ROTATING_7 (EL_DF_MIRROR_ROTATING_START + 6) #define EL_DF_MIRROR_ROTATING_8 (EL_DF_MIRROR_ROTATING_START + 7) #define EL_DF_MIRROR_ROTATING_9 (EL_DF_MIRROR_ROTATING_START + 8) #define EL_DF_MIRROR_ROTATING_10 (EL_DF_MIRROR_ROTATING_START + 9) #define EL_DF_MIRROR_ROTATING_11 (EL_DF_MIRROR_ROTATING_START + 10) #define EL_DF_MIRROR_ROTATING_12 (EL_DF_MIRROR_ROTATING_START + 11) #define EL_DF_MIRROR_ROTATING_13 (EL_DF_MIRROR_ROTATING_START + 12) #define EL_DF_MIRROR_ROTATING_14 (EL_DF_MIRROR_ROTATING_START + 13) #define EL_DF_MIRROR_ROTATING_15 (EL_DF_MIRROR_ROTATING_START + 14) #define EL_DF_MIRROR_ROTATING_16 (EL_DF_MIRROR_ROTATING_START + 15) #define EL_DF_MIRROR_ROTATING_END EL_DF_MIRROR_ROTATING_15 #define EL_DF_WOODEN_GRID_ROTATING_START (EL_DF_START2 + 340) #define EL_DF_WOODEN_GRID_ROTATING_1 (EL_DF_WOODEN_GRID_ROTATING_START + 0) #define EL_DF_WOODEN_GRID_ROTATING_2 (EL_DF_WOODEN_GRID_ROTATING_START + 1) #define EL_DF_WOODEN_GRID_ROTATING_3 (EL_DF_WOODEN_GRID_ROTATING_START + 2) #define EL_DF_WOODEN_GRID_ROTATING_4 (EL_DF_WOODEN_GRID_ROTATING_START + 3) #define EL_DF_WOODEN_GRID_ROTATING_5 (EL_DF_WOODEN_GRID_ROTATING_START + 4) #define EL_DF_WOODEN_GRID_ROTATING_6 (EL_DF_WOODEN_GRID_ROTATING_START + 5) #define EL_DF_WOODEN_GRID_ROTATING_7 (EL_DF_WOODEN_GRID_ROTATING_START + 6) #define EL_DF_WOODEN_GRID_ROTATING_8 (EL_DF_WOODEN_GRID_ROTATING_START + 7) #define EL_DF_WOODEN_GRID_ROTATING_END EL_DF_WOODEN_GRID_ROTATING_07 #define EL_DF_STEEL_GRID_ROTATING_START (EL_DF_START2 + 348) #define EL_DF_STEEL_GRID_ROTATING_1 (EL_DF_STEEL_GRID_ROTATING_START + 0) #define EL_DF_STEEL_GRID_ROTATING_2 (EL_DF_STEEL_GRID_ROTATING_START + 1) #define EL_DF_STEEL_GRID_ROTATING_3 (EL_DF_STEEL_GRID_ROTATING_START + 2) #define EL_DF_STEEL_GRID_ROTATING_4 (EL_DF_STEEL_GRID_ROTATING_START + 3) #define EL_DF_STEEL_GRID_ROTATING_5 (EL_DF_STEEL_GRID_ROTATING_START + 4) #define EL_DF_STEEL_GRID_ROTATING_6 (EL_DF_STEEL_GRID_ROTATING_START + 5) #define EL_DF_STEEL_GRID_ROTATING_7 (EL_DF_STEEL_GRID_ROTATING_START + 6) #define EL_DF_STEEL_GRID_ROTATING_8 (EL_DF_STEEL_GRID_ROTATING_START + 7) #define EL_DF_STEEL_GRID_ROTATING_END EL_DF_STEEL_GRID_ROTATING_07 #define EL_DF_END (EL_DF_START2 + 355) #define EL_MM_TELEPORTER_RED_START (EL_DF_START2 + 356) #define EL_MM_TELEPORTER_RED_1 (EL_MM_TELEPORTER_RED_START + 0) #define EL_MM_TELEPORTER_RED_2 (EL_MM_TELEPORTER_RED_START + 1) #define EL_MM_TELEPORTER_RED_3 (EL_MM_TELEPORTER_RED_START + 2) #define EL_MM_TELEPORTER_RED_4 (EL_MM_TELEPORTER_RED_START + 3) #define EL_MM_TELEPORTER_RED_5 (EL_MM_TELEPORTER_RED_START + 4) #define EL_MM_TELEPORTER_RED_6 (EL_MM_TELEPORTER_RED_START + 5) #define EL_MM_TELEPORTER_RED_7 (EL_MM_TELEPORTER_RED_START + 6) #define EL_MM_TELEPORTER_RED_8 (EL_MM_TELEPORTER_RED_START + 7) #define EL_MM_TELEPORTER_RED_9 (EL_MM_TELEPORTER_RED_START + 8) #define EL_MM_TELEPORTER_RED_10 (EL_MM_TELEPORTER_RED_START + 9) #define EL_MM_TELEPORTER_RED_11 (EL_MM_TELEPORTER_RED_START + 10) #define EL_MM_TELEPORTER_RED_12 (EL_MM_TELEPORTER_RED_START + 11) #define EL_MM_TELEPORTER_RED_13 (EL_MM_TELEPORTER_RED_START + 12) #define EL_MM_TELEPORTER_RED_14 (EL_MM_TELEPORTER_RED_START + 13) #define EL_MM_TELEPORTER_RED_15 (EL_MM_TELEPORTER_RED_START + 14) #define EL_MM_TELEPORTER_RED_16 (EL_MM_TELEPORTER_RED_START + 15) #define EL_MM_TELEPORTER_RED_END EL_MM_TELEPORTER_RED_16 #define EL_MM_TELEPORTER_YELLOW_START (EL_DF_START2 + 372) #define EL_MM_TELEPORTER_YELLOW_1 (EL_MM_TELEPORTER_YELLOW_START + 0) #define EL_MM_TELEPORTER_YELLOW_2 (EL_MM_TELEPORTER_YELLOW_START + 1) #define EL_MM_TELEPORTER_YELLOW_3 (EL_MM_TELEPORTER_YELLOW_START + 2) #define EL_MM_TELEPORTER_YELLOW_4 (EL_MM_TELEPORTER_YELLOW_START + 3) #define EL_MM_TELEPORTER_YELLOW_5 (EL_MM_TELEPORTER_YELLOW_START + 4) #define EL_MM_TELEPORTER_YELLOW_6 (EL_MM_TELEPORTER_YELLOW_START + 5) #define EL_MM_TELEPORTER_YELLOW_7 (EL_MM_TELEPORTER_YELLOW_START + 6) #define EL_MM_TELEPORTER_YELLOW_8 (EL_MM_TELEPORTER_YELLOW_START + 7) #define EL_MM_TELEPORTER_YELLOW_9 (EL_MM_TELEPORTER_YELLOW_START + 8) #define EL_MM_TELEPORTER_YELLOW_10 (EL_MM_TELEPORTER_YELLOW_START + 9) #define EL_MM_TELEPORTER_YELLOW_11 (EL_MM_TELEPORTER_YELLOW_START + 10) #define EL_MM_TELEPORTER_YELLOW_12 (EL_MM_TELEPORTER_YELLOW_START + 11) #define EL_MM_TELEPORTER_YELLOW_13 (EL_MM_TELEPORTER_YELLOW_START + 12) #define EL_MM_TELEPORTER_YELLOW_14 (EL_MM_TELEPORTER_YELLOW_START + 13) #define EL_MM_TELEPORTER_YELLOW_15 (EL_MM_TELEPORTER_YELLOW_START + 14) #define EL_MM_TELEPORTER_YELLOW_16 (EL_MM_TELEPORTER_YELLOW_START + 15) #define EL_MM_TELEPORTER_YELLOW_END EL_MM_TELEPORTER_YELLOW_16 #define EL_MM_TELEPORTER_GREEN_START (EL_DF_START2 + 388) #define EL_MM_TELEPORTER_GREEN_1 (EL_MM_TELEPORTER_GREEN_START + 0) #define EL_MM_TELEPORTER_GREEN_2 (EL_MM_TELEPORTER_GREEN_START + 1) #define EL_MM_TELEPORTER_GREEN_3 (EL_MM_TELEPORTER_GREEN_START + 2) #define EL_MM_TELEPORTER_GREEN_4 (EL_MM_TELEPORTER_GREEN_START + 3) #define EL_MM_TELEPORTER_GREEN_5 (EL_MM_TELEPORTER_GREEN_START + 4) #define EL_MM_TELEPORTER_GREEN_6 (EL_MM_TELEPORTER_GREEN_START + 5) #define EL_MM_TELEPORTER_GREEN_7 (EL_MM_TELEPORTER_GREEN_START + 6) #define EL_MM_TELEPORTER_GREEN_8 (EL_MM_TELEPORTER_GREEN_START + 7) #define EL_MM_TELEPORTER_GREEN_9 (EL_MM_TELEPORTER_GREEN_START + 8) #define EL_MM_TELEPORTER_GREEN_10 (EL_MM_TELEPORTER_GREEN_START + 9) #define EL_MM_TELEPORTER_GREEN_11 (EL_MM_TELEPORTER_GREEN_START + 10) #define EL_MM_TELEPORTER_GREEN_12 (EL_MM_TELEPORTER_GREEN_START + 11) #define EL_MM_TELEPORTER_GREEN_13 (EL_MM_TELEPORTER_GREEN_START + 12) #define EL_MM_TELEPORTER_GREEN_14 (EL_MM_TELEPORTER_GREEN_START + 13) #define EL_MM_TELEPORTER_GREEN_15 (EL_MM_TELEPORTER_GREEN_START + 14) #define EL_MM_TELEPORTER_GREEN_16 (EL_MM_TELEPORTER_GREEN_START + 15) #define EL_MM_TELEPORTER_GREEN_END EL_MM_TELEPORTER_GREEN_16 #define EL_MM_TELEPORTER_BLUE_START (EL_DF_START2 + 404) #define EL_MM_TELEPORTER_BLUE_1 (EL_MM_TELEPORTER_BLUE_START + 0) #define EL_MM_TELEPORTER_BLUE_2 (EL_MM_TELEPORTER_BLUE_START + 1) #define EL_MM_TELEPORTER_BLUE_3 (EL_MM_TELEPORTER_BLUE_START + 2) #define EL_MM_TELEPORTER_BLUE_4 (EL_MM_TELEPORTER_BLUE_START + 3) #define EL_MM_TELEPORTER_BLUE_5 (EL_MM_TELEPORTER_BLUE_START + 4) #define EL_MM_TELEPORTER_BLUE_6 (EL_MM_TELEPORTER_BLUE_START + 5) #define EL_MM_TELEPORTER_BLUE_7 (EL_MM_TELEPORTER_BLUE_START + 6) #define EL_MM_TELEPORTER_BLUE_8 (EL_MM_TELEPORTER_BLUE_START + 7) #define EL_MM_TELEPORTER_BLUE_9 (EL_MM_TELEPORTER_BLUE_START + 8) #define EL_MM_TELEPORTER_BLUE_10 (EL_MM_TELEPORTER_BLUE_START + 9) #define EL_MM_TELEPORTER_BLUE_11 (EL_MM_TELEPORTER_BLUE_START + 10) #define EL_MM_TELEPORTER_BLUE_12 (EL_MM_TELEPORTER_BLUE_START + 11) #define EL_MM_TELEPORTER_BLUE_13 (EL_MM_TELEPORTER_BLUE_START + 12) #define EL_MM_TELEPORTER_BLUE_14 (EL_MM_TELEPORTER_BLUE_START + 13) #define EL_MM_TELEPORTER_BLUE_15 (EL_MM_TELEPORTER_BLUE_START + 14) #define EL_MM_TELEPORTER_BLUE_16 (EL_MM_TELEPORTER_BLUE_START + 15) #define EL_MM_TELEPORTER_BLUE_END EL_MM_TELEPORTER_BLUE_16 #define EL_MM_MCDUFFIN 1204 #define EL_MM_PACMAN 1205 #define EL_MM_FUSE 1206 #define EL_MM_STEEL_WALL 1207 #define EL_MM_WOODEN_WALL 1208 #define EL_MM_ICE_WALL 1209 #define EL_MM_AMOEBA_WALL 1210 #define EL_DF_LASER 1211 #define EL_DF_RECEIVER 1212 #define EL_DF_STEEL_WALL 1213 #define EL_DF_WOODEN_WALL 1214 #define EL_MM_END_2 (EL_DF_START2 + 430) #define EL_MM_END EL_MM_END_2 #define NUM_FILE_ELEMENTS 1215 /* "real" (and therefore drawable) runtime elements */ #define EL_FIRST_RUNTIME_REAL NUM_FILE_ELEMENTS #define EL_DYNABOMB_PLAYER_1_ACTIVE (EL_FIRST_RUNTIME_REAL + 0) #define EL_DYNABOMB_PLAYER_2_ACTIVE (EL_FIRST_RUNTIME_REAL + 1) #define EL_DYNABOMB_PLAYER_3_ACTIVE (EL_FIRST_RUNTIME_REAL + 2) #define EL_DYNABOMB_PLAYER_4_ACTIVE (EL_FIRST_RUNTIME_REAL + 3) #define EL_SP_DISK_RED_ACTIVE (EL_FIRST_RUNTIME_REAL + 4) #define EL_SWITCHGATE_OPENING (EL_FIRST_RUNTIME_REAL + 5) #define EL_SWITCHGATE_CLOSING (EL_FIRST_RUNTIME_REAL + 6) #define EL_TIMEGATE_OPENING (EL_FIRST_RUNTIME_REAL + 7) #define EL_TIMEGATE_CLOSING (EL_FIRST_RUNTIME_REAL + 8) #define EL_PEARL_BREAKING (EL_FIRST_RUNTIME_REAL + 9) #define EL_TRAP_ACTIVE (EL_FIRST_RUNTIME_REAL + 10) #define EL_INVISIBLE_STEELWALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 11) #define EL_INVISIBLE_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 12) #define EL_INVISIBLE_SAND_ACTIVE (EL_FIRST_RUNTIME_REAL + 13) #define EL_CONVEYOR_BELT_1_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 14) #define EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 15) #define EL_CONVEYOR_BELT_1_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 16) #define EL_CONVEYOR_BELT_2_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 17) #define EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 18) #define EL_CONVEYOR_BELT_2_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 19) #define EL_CONVEYOR_BELT_3_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 20) #define EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 21) #define EL_CONVEYOR_BELT_3_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 22) #define EL_CONVEYOR_BELT_4_LEFT_ACTIVE (EL_FIRST_RUNTIME_REAL + 23) #define EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 24) #define EL_CONVEYOR_BELT_4_RIGHT_ACTIVE (EL_FIRST_RUNTIME_REAL + 25) #define EL_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 26) #define EL_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 27) #define EL_STEEL_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 28) #define EL_STEEL_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 29) #define EL_EM_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 30) #define EL_EM_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 31) #define EL_EM_STEEL_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 32) #define EL_EM_STEEL_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 33) #define EL_SP_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 34) #define EL_SP_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 35) #define EL_SP_EXIT_OPEN (EL_FIRST_RUNTIME_REAL + 36) #define EL_SP_TERMINAL_ACTIVE (EL_FIRST_RUNTIME_REAL + 37) #define EL_SP_BUGGY_BASE_ACTIVATING (EL_FIRST_RUNTIME_REAL + 38) #define EL_SP_BUGGY_BASE_ACTIVE (EL_FIRST_RUNTIME_REAL + 39) #define EL_SP_MURPHY_CLONE (EL_FIRST_RUNTIME_REAL + 40) #define EL_AMOEBA_DROPPING (EL_FIRST_RUNTIME_REAL + 41) #define EL_QUICKSAND_EMPTYING (EL_FIRST_RUNTIME_REAL + 42) #define EL_QUICKSAND_FAST_EMPTYING (EL_FIRST_RUNTIME_REAL + 43) #define EL_MAGIC_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 44) #define EL_BD_MAGIC_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 45) #define EL_DC_MAGIC_WALL_ACTIVE (EL_FIRST_RUNTIME_REAL + 46) #define EL_MAGIC_WALL_FULL (EL_FIRST_RUNTIME_REAL + 47) #define EL_BD_MAGIC_WALL_FULL (EL_FIRST_RUNTIME_REAL + 48) #define EL_DC_MAGIC_WALL_FULL (EL_FIRST_RUNTIME_REAL + 49) #define EL_MAGIC_WALL_EMPTYING (EL_FIRST_RUNTIME_REAL + 50) #define EL_BD_MAGIC_WALL_EMPTYING (EL_FIRST_RUNTIME_REAL + 51) #define EL_DC_MAGIC_WALL_EMPTYING (EL_FIRST_RUNTIME_REAL + 52) #define EL_MAGIC_WALL_DEAD (EL_FIRST_RUNTIME_REAL + 53) #define EL_BD_MAGIC_WALL_DEAD (EL_FIRST_RUNTIME_REAL + 54) #define EL_DC_MAGIC_WALL_DEAD (EL_FIRST_RUNTIME_REAL + 55) #define EL_EMC_FAKE_GRASS_ACTIVE (EL_FIRST_RUNTIME_REAL + 56) #define EL_GATE_1_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 57) #define EL_GATE_2_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 58) #define EL_GATE_3_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 59) #define EL_GATE_4_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 60) #define EL_EM_GATE_1_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 61) #define EL_EM_GATE_2_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 62) #define EL_EM_GATE_3_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 63) #define EL_EM_GATE_4_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 64) #define EL_EMC_GATE_5_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 65) #define EL_EMC_GATE_6_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 66) #define EL_EMC_GATE_7_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 67) #define EL_EMC_GATE_8_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 68) #define EL_DC_GATE_WHITE_GRAY_ACTIVE (EL_FIRST_RUNTIME_REAL + 69) #define EL_EMC_DRIPPER_ACTIVE (EL_FIRST_RUNTIME_REAL + 70) #define EL_EMC_SPRING_BUMPER_ACTIVE (EL_FIRST_RUNTIME_REAL + 71) #define EL_MM_EXIT_OPENING (EL_FIRST_RUNTIME_REAL + 72) #define EL_MM_EXIT_CLOSING (EL_FIRST_RUNTIME_REAL + 73) #define EL_MM_GRAY_BALL_OPENING (EL_FIRST_RUNTIME_REAL + 74) #define EL_MM_ICE_WALL_SHRINKING (EL_FIRST_RUNTIME_REAL + 75) #define EL_MM_AMOEBA_WALL_GROWING (EL_FIRST_RUNTIME_REAL + 76) #define EL_MM_PACMAN_EATING_RIGHT (EL_FIRST_RUNTIME_REAL + 77) #define EL_MM_PACMAN_EATING_UP (EL_FIRST_RUNTIME_REAL + 78) #define EL_MM_PACMAN_EATING_LEFT (EL_FIRST_RUNTIME_REAL + 79) #define EL_MM_PACMAN_EATING_DOWN (EL_FIRST_RUNTIME_REAL + 80) #define NUM_DRAWABLE_ELEMENTS (EL_FIRST_RUNTIME_REAL + 81) #define EL_MM_RUNTIME_START EL_MM_EXIT_OPENING #define EL_MM_RUNTIME_END EL_MM_AMOEBA_WALL_GROWING /* "unreal" (and therefore not drawable) runtime elements */ #define EL_FIRST_RUNTIME_UNREAL (NUM_DRAWABLE_ELEMENTS) #define EL_BLOCKED (EL_FIRST_RUNTIME_UNREAL + 0) #define EL_EXPLOSION (EL_FIRST_RUNTIME_UNREAL + 1) #define EL_NUT_BREAKING (EL_FIRST_RUNTIME_UNREAL + 2) #define EL_DIAMOND_BREAKING (EL_FIRST_RUNTIME_UNREAL + 3) #define EL_ACID_SPLASH_LEFT (EL_FIRST_RUNTIME_UNREAL + 4) #define EL_ACID_SPLASH_RIGHT (EL_FIRST_RUNTIME_UNREAL + 5) #define EL_AMOEBA_GROWING (EL_FIRST_RUNTIME_UNREAL + 6) #define EL_AMOEBA_SHRINKING (EL_FIRST_RUNTIME_UNREAL + 7) #define EL_EXPANDABLE_WALL_GROWING (EL_FIRST_RUNTIME_UNREAL + 8) #define EL_EXPANDABLE_STEELWALL_GROWING (EL_FIRST_RUNTIME_UNREAL + 9) #define EL_FLAMES (EL_FIRST_RUNTIME_UNREAL + 10) #define EL_PLAYER_IS_LEAVING (EL_FIRST_RUNTIME_UNREAL + 11) #define EL_PLAYER_IS_EXPLODING_1 (EL_FIRST_RUNTIME_UNREAL + 12) #define EL_PLAYER_IS_EXPLODING_2 (EL_FIRST_RUNTIME_UNREAL + 13) #define EL_PLAYER_IS_EXPLODING_3 (EL_FIRST_RUNTIME_UNREAL + 14) #define EL_PLAYER_IS_EXPLODING_4 (EL_FIRST_RUNTIME_UNREAL + 15) #define EL_QUICKSAND_FILLING (EL_FIRST_RUNTIME_UNREAL + 16) #define EL_QUICKSAND_FAST_FILLING (EL_FIRST_RUNTIME_UNREAL + 17) #define EL_MAGIC_WALL_FILLING (EL_FIRST_RUNTIME_UNREAL + 18) #define EL_BD_MAGIC_WALL_FILLING (EL_FIRST_RUNTIME_UNREAL + 19) #define EL_DC_MAGIC_WALL_FILLING (EL_FIRST_RUNTIME_UNREAL + 20) #define EL_ELEMENT_SNAPPING (EL_FIRST_RUNTIME_UNREAL + 21) #define EL_DIAGONAL_SHRINKING (EL_FIRST_RUNTIME_UNREAL + 22) #define EL_DIAGONAL_GROWING (EL_FIRST_RUNTIME_UNREAL + 23) #define NUM_RUNTIME_ELEMENTS (EL_FIRST_RUNTIME_UNREAL + 24) /* dummy elements (never used as game elements, only used as graphics) */ #define EL_FIRST_DUMMY NUM_RUNTIME_ELEMENTS #define EL_STEELWALL_TOPLEFT (EL_FIRST_DUMMY + 0) #define EL_STEELWALL_TOPRIGHT (EL_FIRST_DUMMY + 1) #define EL_STEELWALL_BOTTOMLEFT (EL_FIRST_DUMMY + 2) #define EL_STEELWALL_BOTTOMRIGHT (EL_FIRST_DUMMY + 3) #define EL_STEELWALL_HORIZONTAL (EL_FIRST_DUMMY + 4) #define EL_STEELWALL_VERTICAL (EL_FIRST_DUMMY + 5) #define EL_INVISIBLE_STEELWALL_TOPLEFT (EL_FIRST_DUMMY + 6) #define EL_INVISIBLE_STEELWALL_TOPRIGHT (EL_FIRST_DUMMY + 7) #define EL_INVISIBLE_STEELWALL_BOTTOMLEFT (EL_FIRST_DUMMY + 8) #define EL_INVISIBLE_STEELWALL_BOTTOMRIGHT (EL_FIRST_DUMMY + 9) #define EL_INVISIBLE_STEELWALL_HORIZONTAL (EL_FIRST_DUMMY + 10) #define EL_INVISIBLE_STEELWALL_VERTICAL (EL_FIRST_DUMMY + 11) #define EL_DYNABOMB (EL_FIRST_DUMMY + 12) #define EL_DYNABOMB_ACTIVE (EL_FIRST_DUMMY + 13) #define EL_DYNABOMB_PLAYER_1 (EL_FIRST_DUMMY + 14) #define EL_DYNABOMB_PLAYER_2 (EL_FIRST_DUMMY + 15) #define EL_DYNABOMB_PLAYER_3 (EL_FIRST_DUMMY + 16) #define EL_DYNABOMB_PLAYER_4 (EL_FIRST_DUMMY + 17) #define EL_SHIELD_NORMAL_ACTIVE (EL_FIRST_DUMMY + 18) #define EL_SHIELD_DEADLY_ACTIVE (EL_FIRST_DUMMY + 19) #define EL_AMOEBA (EL_FIRST_DUMMY + 20) #define EL_MM_LIGHTBALL_RED (EL_FIRST_DUMMY + 21) #define EL_MM_LIGHTBALL_BLUE (EL_FIRST_DUMMY + 22) #define EL_MM_LIGHTBALL_YELLOW (EL_FIRST_DUMMY + 23) #define EL_MM_MASK_MCDUFFIN_RIGHT (EL_FIRST_DUMMY + 24) #define EL_MM_MASK_MCDUFFIN_UP (EL_FIRST_DUMMY + 25) #define EL_MM_MASK_MCDUFFIN_LEFT (EL_FIRST_DUMMY + 26) #define EL_MM_MASK_MCDUFFIN_DOWN (EL_FIRST_DUMMY + 27) #define EL_MM_MASK_GRID_1 (EL_FIRST_DUMMY + 28) #define EL_MM_MASK_GRID_2 (EL_FIRST_DUMMY + 29) #define EL_MM_MASK_GRID_3 (EL_FIRST_DUMMY + 30) #define EL_MM_MASK_GRID_4 (EL_FIRST_DUMMY + 31) #define EL_MM_MASK_RECTANGLE (EL_FIRST_DUMMY + 32) #define EL_MM_MASK_CIRCLE (EL_FIRST_DUMMY + 33) #define EL_DEFAULT (EL_FIRST_DUMMY + 34) #define EL_BD_DEFAULT (EL_FIRST_DUMMY + 35) #define EL_SP_DEFAULT (EL_FIRST_DUMMY + 36) #define EL_SB_DEFAULT (EL_FIRST_DUMMY + 37) #define EL_MM_DEFAULT (EL_FIRST_DUMMY + 38) #define EL_GRAPHIC_1 (EL_FIRST_DUMMY + 39) #define EL_GRAPHIC_2 (EL_FIRST_DUMMY + 40) #define EL_GRAPHIC_3 (EL_FIRST_DUMMY + 41) #define EL_GRAPHIC_4 (EL_FIRST_DUMMY + 42) #define EL_GRAPHIC_5 (EL_FIRST_DUMMY + 43) #define EL_GRAPHIC_6 (EL_FIRST_DUMMY + 44) #define EL_GRAPHIC_7 (EL_FIRST_DUMMY + 45) #define EL_GRAPHIC_8 (EL_FIRST_DUMMY + 46) #define EL_MM_DUMMY_START EL_MM_MASK_MCDUFFIN_RIGHT #define EL_MM_DUMMY_END EL_MM_MASK_CIRCLE /* internal elements (only used for internal purposes like copying) */ #define EL_FIRST_INTERNAL (EL_FIRST_DUMMY + 47) #define EL_INTERNAL_CLIPBOARD_CUSTOM (EL_FIRST_INTERNAL + 0) #define EL_INTERNAL_CLIPBOARD_CHANGE (EL_FIRST_INTERNAL + 1) #define EL_INTERNAL_CLIPBOARD_GROUP (EL_FIRST_INTERNAL + 2) #define EL_INTERNAL_DUMMY (EL_FIRST_INTERNAL + 3) #define EL_INTERNAL_CASCADE_BD (EL_FIRST_INTERNAL + 4) #define EL_INTERNAL_CASCADE_BD_ACTIVE (EL_FIRST_INTERNAL + 5) #define EL_INTERNAL_CASCADE_EM (EL_FIRST_INTERNAL + 6) #define EL_INTERNAL_CASCADE_EM_ACTIVE (EL_FIRST_INTERNAL + 7) #define EL_INTERNAL_CASCADE_EMC (EL_FIRST_INTERNAL + 8) #define EL_INTERNAL_CASCADE_EMC_ACTIVE (EL_FIRST_INTERNAL + 9) #define EL_INTERNAL_CASCADE_RND (EL_FIRST_INTERNAL + 10) #define EL_INTERNAL_CASCADE_RND_ACTIVE (EL_FIRST_INTERNAL + 11) #define EL_INTERNAL_CASCADE_SB (EL_FIRST_INTERNAL + 12) #define EL_INTERNAL_CASCADE_SB_ACTIVE (EL_FIRST_INTERNAL + 13) #define EL_INTERNAL_CASCADE_SP (EL_FIRST_INTERNAL + 14) #define EL_INTERNAL_CASCADE_SP_ACTIVE (EL_FIRST_INTERNAL + 15) #define EL_INTERNAL_CASCADE_DC (EL_FIRST_INTERNAL + 16) #define EL_INTERNAL_CASCADE_DC_ACTIVE (EL_FIRST_INTERNAL + 17) #define EL_INTERNAL_CASCADE_DX (EL_FIRST_INTERNAL + 18) #define EL_INTERNAL_CASCADE_DX_ACTIVE (EL_FIRST_INTERNAL + 19) #define EL_INTERNAL_CASCADE_MM (EL_FIRST_INTERNAL + 20) #define EL_INTERNAL_CASCADE_MM_ACTIVE (EL_FIRST_INTERNAL + 21) #define EL_INTERNAL_CASCADE_DF (EL_FIRST_INTERNAL + 22) #define EL_INTERNAL_CASCADE_DF_ACTIVE (EL_FIRST_INTERNAL + 23) #define EL_INTERNAL_CASCADE_CHARS (EL_FIRST_INTERNAL + 24) #define EL_INTERNAL_CASCADE_CHARS_ACTIVE (EL_FIRST_INTERNAL + 25) #define EL_INTERNAL_CASCADE_STEEL_CHARS (EL_FIRST_INTERNAL + 26) #define EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE (EL_FIRST_INTERNAL + 27) #define EL_INTERNAL_CASCADE_CE (EL_FIRST_INTERNAL + 28) #define EL_INTERNAL_CASCADE_CE_ACTIVE (EL_FIRST_INTERNAL + 29) #define EL_INTERNAL_CASCADE_GE (EL_FIRST_INTERNAL + 30) #define EL_INTERNAL_CASCADE_GE_ACTIVE (EL_FIRST_INTERNAL + 31) #define EL_INTERNAL_CASCADE_REF (EL_FIRST_INTERNAL + 32) #define EL_INTERNAL_CASCADE_REF_ACTIVE (EL_FIRST_INTERNAL + 33) #define EL_INTERNAL_CASCADE_USER (EL_FIRST_INTERNAL + 34) #define EL_INTERNAL_CASCADE_USER_ACTIVE (EL_FIRST_INTERNAL + 35) #define EL_INTERNAL_CASCADE_DYNAMIC (EL_FIRST_INTERNAL + 36) #define EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE (EL_FIRST_INTERNAL + 37) #define EL_INTERNAL_CLIPBOARD_START (EL_FIRST_INTERNAL + 0) #define EL_INTERNAL_CLIPBOARD_END (EL_FIRST_INTERNAL + 2) #define EL_INTERNAL_START (EL_FIRST_INTERNAL + 0) #define EL_INTERNAL_END (EL_FIRST_INTERNAL + 37) #define MAX_NUM_ELEMENTS (EL_FIRST_INTERNAL + 38) /* values for graphics/sounds action types */ #define ACTION_DEFAULT 0 #define ACTION_WAITING 1 #define ACTION_FALLING 2 #define ACTION_MOVING 3 #define ACTION_DIGGING 4 #define ACTION_SNAPPING 5 #define ACTION_COLLECTING 6 #define ACTION_DROPPING 7 #define ACTION_PUSHING 8 #define ACTION_WALKING 9 #define ACTION_PASSING 10 #define ACTION_IMPACT 11 #define ACTION_BREAKING 12 #define ACTION_ACTIVATING 13 #define ACTION_DEACTIVATING 14 #define ACTION_OPENING 15 #define ACTION_CLOSING 16 #define ACTION_ATTACKING 17 #define ACTION_GROWING 18 #define ACTION_SHRINKING 19 #define ACTION_ACTIVE 20 #define ACTION_FILLING 21 #define ACTION_EMPTYING 22 #define ACTION_CHANGING 23 #define ACTION_EXPLODING 24 #define ACTION_BORING 25 #define ACTION_BORING_1 26 #define ACTION_BORING_2 27 #define ACTION_BORING_3 28 #define ACTION_BORING_4 29 #define ACTION_BORING_5 30 #define ACTION_BORING_6 31 #define ACTION_BORING_7 32 #define ACTION_BORING_8 33 #define ACTION_BORING_9 34 #define ACTION_BORING_10 35 #define ACTION_SLEEPING 36 #define ACTION_SLEEPING_1 37 #define ACTION_SLEEPING_2 38 #define ACTION_SLEEPING_3 39 #define ACTION_AWAKENING 40 #define ACTION_DYING 41 #define ACTION_TURNING 42 #define ACTION_TURNING_FROM_LEFT 43 #define ACTION_TURNING_FROM_RIGHT 44 #define ACTION_TURNING_FROM_UP 45 #define ACTION_TURNING_FROM_DOWN 46 #define ACTION_SMASHED_BY_ROCK 47 #define ACTION_SMASHED_BY_SPRING 48 #define ACTION_EATING 49 #define ACTION_TWINKLING 50 #define ACTION_SPLASHING 51 #define ACTION_HITTING 52 #define ACTION_PAGE_1 53 #define ACTION_PAGE_2 54 #define ACTION_PAGE_3 55 #define ACTION_PAGE_4 56 #define ACTION_PAGE_5 57 #define ACTION_PAGE_6 58 #define ACTION_PAGE_7 59 #define ACTION_PAGE_8 60 #define ACTION_PAGE_9 61 #define ACTION_PAGE_10 62 #define ACTION_PAGE_11 63 #define ACTION_PAGE_12 64 #define ACTION_PAGE_13 65 #define ACTION_PAGE_14 66 #define ACTION_PAGE_15 67 #define ACTION_PAGE_16 68 #define ACTION_PAGE_17 69 #define ACTION_PAGE_18 70 #define ACTION_PAGE_19 71 #define ACTION_PAGE_20 72 #define ACTION_PAGE_21 73 #define ACTION_PAGE_22 74 #define ACTION_PAGE_23 75 #define ACTION_PAGE_24 76 #define ACTION_PAGE_25 77 #define ACTION_PAGE_26 78 #define ACTION_PAGE_27 79 #define ACTION_PAGE_28 80 #define ACTION_PAGE_29 81 #define ACTION_PAGE_30 82 #define ACTION_PAGE_31 83 #define ACTION_PAGE_32 84 #define ACTION_PART_1 85 #define ACTION_PART_2 86 #define ACTION_PART_3 87 #define ACTION_PART_4 88 #define ACTION_PART_5 89 #define ACTION_PART_6 90 #define ACTION_PART_7 91 #define ACTION_PART_8 92 #define ACTION_PART_9 93 #define ACTION_PART_10 94 #define ACTION_PART_11 95 #define ACTION_PART_12 96 #define ACTION_PART_13 97 #define ACTION_PART_14 98 #define ACTION_PART_15 99 #define ACTION_PART_16 100 #define ACTION_PART_17 101 #define ACTION_PART_18 102 #define ACTION_PART_19 103 #define ACTION_PART_20 104 #define ACTION_PART_21 105 #define ACTION_PART_22 106 #define ACTION_PART_23 107 #define ACTION_PART_24 108 #define ACTION_PART_25 109 #define ACTION_PART_26 110 #define ACTION_PART_27 111 #define ACTION_PART_28 112 #define ACTION_PART_29 113 #define ACTION_PART_30 114 #define ACTION_PART_31 115 #define ACTION_PART_32 116 #define ACTION_OTHER 117 #define NUM_ACTIONS 118 #define ACTION_BORING_LAST ACTION_BORING_10 #define ACTION_SLEEPING_LAST ACTION_SLEEPING_3 /* values for special image configuration suffixes (must match game mode) */ #define GFX_SPECIAL_ARG_DEFAULT 0 #define GFX_SPECIAL_ARG_LOADING 1 #define GFX_SPECIAL_ARG_TITLE_INITIAL 2 #define GFX_SPECIAL_ARG_TITLE_INITIAL_1 3 #define GFX_SPECIAL_ARG_TITLE_INITIAL_2 4 #define GFX_SPECIAL_ARG_TITLE_INITIAL_3 5 #define GFX_SPECIAL_ARG_TITLE_INITIAL_4 6 #define GFX_SPECIAL_ARG_TITLE_INITIAL_5 7 #define GFX_SPECIAL_ARG_TITLE 8 #define GFX_SPECIAL_ARG_TITLE_1 9 #define GFX_SPECIAL_ARG_TITLE_2 10 #define GFX_SPECIAL_ARG_TITLE_3 11 #define GFX_SPECIAL_ARG_TITLE_4 12 #define GFX_SPECIAL_ARG_TITLE_5 13 #define GFX_SPECIAL_ARG_MAIN 14 #define GFX_SPECIAL_ARG_LEVELS 15 #define GFX_SPECIAL_ARG_LEVELNR 16 #define GFX_SPECIAL_ARG_SCORES 17 #define GFX_SPECIAL_ARG_EDITOR 18 #define GFX_SPECIAL_ARG_INFO 19 #define GFX_SPECIAL_ARG_SETUP 20 #define GFX_SPECIAL_ARG_PLAYING 21 #define GFX_SPECIAL_ARG_DOOR 22 #define GFX_SPECIAL_ARG_TAPE 23 #define GFX_SPECIAL_ARG_PANEL 24 #define GFX_SPECIAL_ARG_PREVIEW 25 #define GFX_SPECIAL_ARG_CRUMBLED 26 #define GFX_SPECIAL_ARG_MAINONLY 27 #define GFX_SPECIAL_ARG_TYPENAME 28 #define GFX_SPECIAL_ARG_SUBMENU 29 #define GFX_SPECIAL_ARG_MENU 30 #define GFX_SPECIAL_ARG_TOONS 31 #define GFX_SPECIAL_ARG_SCORESOLD 32 #define GFX_SPECIAL_ARG_SCORESNEW 33 #define GFX_SPECIAL_ARG_FADING 34 #define GFX_SPECIAL_ARG_QUIT 35 #define NUM_SPECIAL_GFX_ARGS 36 /* these additional definitions are currently only used for draw offsets */ #define GFX_SPECIAL_ARG_INFO_MAIN 0 #define GFX_SPECIAL_ARG_INFO_TITLE 1 #define GFX_SPECIAL_ARG_INFO_ELEMENTS 2 #define GFX_SPECIAL_ARG_INFO_MUSIC 3 #define GFX_SPECIAL_ARG_INFO_CREDITS 4 #define GFX_SPECIAL_ARG_INFO_PROGRAM 5 #define GFX_SPECIAL_ARG_INFO_VERSION 6 #define GFX_SPECIAL_ARG_INFO_LEVELSET 7 #define NUM_SPECIAL_GFX_INFO_ARGS 8 /* these additional definitions are currently only used for draw offsets */ /* (must match SETUP_MODE_* values as defined in src/screens.c) */ /* (should also match corresponding entries in src/conf_gfx.c) */ #define GFX_SPECIAL_ARG_SETUP_MAIN 0 #define GFX_SPECIAL_ARG_SETUP_GAME 1 #define GFX_SPECIAL_ARG_SETUP_EDITOR 2 #define GFX_SPECIAL_ARG_SETUP_GRAPHICS 3 #define GFX_SPECIAL_ARG_SETUP_SOUND 4 #define GFX_SPECIAL_ARG_SETUP_ARTWORK 5 #define GFX_SPECIAL_ARG_SETUP_INPUT 6 #define GFX_SPECIAL_ARG_SETUP_TOUCH 7 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS 8 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_1 9 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_2 10 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3 11 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4 12 #define GFX_SPECIAL_ARG_SETUP_SHORTCUTS_5 13 #define GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK 14 #define GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER 15 #define NUM_SPECIAL_GFX_SETUP_ARGS 16 /* values for image configuration suffixes */ #define GFX_ARG_X 0 #define GFX_ARG_Y 1 #define GFX_ARG_XPOS 2 #define GFX_ARG_YPOS 3 #define GFX_ARG_WIDTH 4 #define GFX_ARG_HEIGHT 5 #define GFX_ARG_VERTICAL 6 #define GFX_ARG_OFFSET 7 #define GFX_ARG_XOFFSET 8 #define GFX_ARG_YOFFSET 9 #define GFX_ARG_2ND_MOVEMENT_TILE 10 #define GFX_ARG_2ND_VERTICAL 11 #define GFX_ARG_2ND_OFFSET 12 #define GFX_ARG_2ND_XOFFSET 13 #define GFX_ARG_2ND_YOFFSET 14 #define GFX_ARG_2ND_SWAP_TILES 15 #define GFX_ARG_FRAMES 16 #define GFX_ARG_FRAMES_PER_LINE 17 #define GFX_ARG_START_FRAME 18 #define GFX_ARG_DELAY 19 #define GFX_ARG_ANIM_MODE 20 #define GFX_ARG_GLOBAL_SYNC 21 #define GFX_ARG_CRUMBLED_LIKE 22 #define GFX_ARG_DIGGABLE_LIKE 23 #define GFX_ARG_BORDER_SIZE 24 #define GFX_ARG_STEP_OFFSET 25 #define GFX_ARG_STEP_XOFFSET 26 #define GFX_ARG_STEP_YOFFSET 27 #define GFX_ARG_STEP_DELAY 28 #define GFX_ARG_DIRECTION 29 #define GFX_ARG_POSITION 30 #define GFX_ARG_DRAW_XOFFSET 31 #define GFX_ARG_DRAW_YOFFSET 32 #define GFX_ARG_DRAW_MASKED 33 #define GFX_ARG_DRAW_ORDER 34 #define GFX_ARG_INIT_DELAY_FIXED 35 #define GFX_ARG_INIT_DELAY_RANDOM 36 #define GFX_ARG_ANIM_DELAY_FIXED 37 #define GFX_ARG_ANIM_DELAY_RANDOM 38 #define GFX_ARG_POST_DELAY_FIXED 39 #define GFX_ARG_POST_DELAY_RANDOM 40 #define GFX_ARG_INIT_EVENT 41 #define GFX_ARG_ANIM_EVENT 42 #define GFX_ARG_NAME 43 #define GFX_ARG_SCALE_UP_FACTOR 44 #define GFX_ARG_TILE_SIZE 45 #define GFX_ARG_CLONE_FROM 46 #define GFX_ARG_FADE_MODE 47 #define GFX_ARG_FADE_DELAY 48 #define GFX_ARG_POST_DELAY 49 #define GFX_ARG_AUTO_DELAY 50 #define GFX_ARG_ALIGN 51 #define GFX_ARG_VALIGN 52 #define GFX_ARG_SORT_PRIORITY 53 #define GFX_ARG_CLASS 54 #define GFX_ARG_STYLE 55 #define GFX_ARG_ACTIVE_XOFFSET 56 #define GFX_ARG_ACTIVE_YOFFSET 57 #define GFX_ARG_PRESSED_XOFFSET 58 #define GFX_ARG_PRESSED_YOFFSET 59 #define NUM_GFX_ARGS 60 /* values for sound configuration suffixes */ #define SND_ARG_MODE_LOOP 0 #define SND_ARG_VOLUME 1 #define SND_ARG_PRIORITY 2 #define NUM_SND_ARGS 3 /* values for music configuration suffixes */ #define MUS_ARG_MODE_LOOP 0 #define NUM_MUS_ARGS 1 /* values for font configuration (definitions must match those from main.c) */ #define FONT_INITIAL_1 0 #define FONT_INITIAL_2 1 #define FONT_INITIAL_3 2 #define FONT_INITIAL_4 3 #define FONT_TITLE_1 4 #define FONT_TITLE_2 5 #define FONT_MENU_1_ACTIVE 6 #define FONT_MENU_2_ACTIVE 7 #define FONT_MENU_1 8 #define FONT_MENU_2 9 #define FONT_TEXT_1_ACTIVE 10 #define FONT_TEXT_2_ACTIVE 11 #define FONT_TEXT_3_ACTIVE 12 #define FONT_TEXT_4_ACTIVE 13 #define FONT_TEXT_1 14 #define FONT_TEXT_2 15 #define FONT_TEXT_3 16 #define FONT_TEXT_4 17 #define FONT_ENVELOPE_1 18 #define FONT_ENVELOPE_2 19 #define FONT_ENVELOPE_3 20 #define FONT_ENVELOPE_4 21 #define FONT_REQUEST 22 #define FONT_INPUT_1_ACTIVE 23 #define FONT_INPUT_2_ACTIVE 24 #define FONT_INPUT_1 25 #define FONT_INPUT_2 26 #define FONT_OPTION_OFF_NARROW 27 #define FONT_OPTION_OFF 28 #define FONT_OPTION_ON_NARROW 29 #define FONT_OPTION_ON 30 #define FONT_VALUE_1 31 #define FONT_VALUE_2 32 #define FONT_VALUE_OLD 33 #define FONT_VALUE_NARROW 34 #define FONT_LEVEL_NUMBER_ACTIVE 35 #define FONT_LEVEL_NUMBER 36 #define FONT_TAPE_RECORDER 37 #define FONT_GAME_INFO 38 #define FONT_INFO_ELEMENTS 39 #define FONT_INFO_LEVELSET 40 #define NUM_FONTS 41 #define NUM_INITIAL_FONTS 4 /* values for toon animation configuration */ #define MAX_NUM_TOONS 20 /* values for global animation configuration (must match those from main.c) */ #define NUM_GLOBAL_ANIMS MAX_GLOBAL_ANIMS #define NUM_GLOBAL_ANIM_PARTS MAX_GLOBAL_ANIM_PARTS #define NUM_GLOBAL_ANIM_PARTS_ALL (NUM_GLOBAL_ANIM_PARTS + 1) #define NUM_GLOBAL_ANIM_TOKENS (2 * NUM_GLOBAL_ANIMS) #define GLOBAL_ANIM_ID_GRAPHIC_FIRST 0 #define GLOBAL_ANIM_ID_GRAPHIC_LAST (NUM_GLOBAL_ANIMS - 1) #define GLOBAL_ANIM_ID_CONTROL_FIRST (NUM_GLOBAL_ANIMS) #define GLOBAL_ANIM_ID_CONTROL_LAST (2 * NUM_GLOBAL_ANIMS - 1) #define GLOBAL_ANIM_ID_PART_FIRST 0 #define GLOBAL_ANIM_ID_PART_LAST (NUM_GLOBAL_ANIM_PARTS - 1) #define GLOBAL_ANIM_ID_PART_BASE (NUM_GLOBAL_ANIM_PARTS) /* values for global border graphics */ #define IMG_GLOBAL_BORDER_FIRST IMG_GLOBAL_BORDER #define IMG_GLOBAL_BORDER_LAST IMG_GLOBAL_BORDER_PLAYING /* values for game_status (must match special image configuration suffixes) */ #define GAME_MODE_DEFAULT 0 #define GAME_MODE_LOADING 1 #define GAME_MODE_TITLE_INITIAL 2 #define GAME_MODE_TITLE_INITIAL_1 3 #define GAME_MODE_TITLE_INITIAL_2 4 #define GAME_MODE_TITLE_INITIAL_3 5 #define GAME_MODE_TITLE_INITIAL_4 6 #define GAME_MODE_TITLE_INITIAL_5 7 #define GAME_MODE_TITLE 8 #define GAME_MODE_TITLE_1 9 #define GAME_MODE_TITLE_2 10 #define GAME_MODE_TITLE_3 11 #define GAME_MODE_TITLE_4 12 #define GAME_MODE_TITLE_5 13 #define GAME_MODE_MAIN 14 #define GAME_MODE_LEVELS 15 #define GAME_MODE_LEVELNR 16 #define GAME_MODE_SCORES 17 #define GAME_MODE_EDITOR 18 #define GAME_MODE_INFO 19 #define GAME_MODE_SETUP 20 #define GAME_MODE_PLAYING 21 #define GAME_MODE_PSEUDO_DOOR 22 #define GAME_MODE_PSEUDO_TAPE 23 #define GAME_MODE_PSEUDO_PANEL 24 #define GAME_MODE_PSEUDO_PREVIEW 25 #define GAME_MODE_PSEUDO_CRUMBLED 26 #define GAME_MODE_PSEUDO_MAINONLY 27 #define GAME_MODE_PSEUDO_TYPENAME 28 #define GAME_MODE_PSEUDO_SUBMENU 29 #define GAME_MODE_PSEUDO_MENU 30 #define GAME_MODE_PSEUDO_TOONS 31 #define GAME_MODE_PSEUDO_SCORESOLD 32 #define GAME_MODE_PSEUDO_SCORESNEW 33 #define GAME_MODE_PSEUDO_FADING 34 #define GAME_MODE_QUIT 35 #define NUM_GAME_MODES 36 /* special definitions currently only used for custom artwork configuration */ #define MUSIC_PREFIX_BACKGROUND 0 #define NUM_MUSIC_PREFIXES 1 /* definitions for demo animation lists */ #define HELPANIM_LIST_NEXT -1 #define HELPANIM_LIST_END -999 /* program information and versioning definitions */ #define PROGRAM_VERSION_MAJOR 4 #define PROGRAM_VERSION_MINOR 1 #define PROGRAM_VERSION_PATCH 0 #define PROGRAM_VERSION_BUILD 0 #define PROGRAM_VERSION_EXTRA "" #define PROGRAM_TITLE_STRING "Rocks'n'Diamonds" #define PROGRAM_AUTHOR_STRING "Holger Schemel" #define PROGRAM_EMAIL_STRING "info@artsoft.org" #define PROGRAM_WEBSITE_STRING "http://www.artsoft.org/" #define PROGRAM_COPYRIGHT_STRING "Copyright \xa9""1995-2018 by Holger Schemel" #define PROGRAM_COMPANY_STRING "A Game by Artsoft Entertainment" #define PROGRAM_ICON_FILENAME "RocksIcon32x32.png" #define COOKIE_PREFIX "ROCKSNDIAMONDS" #define USERDATA_DIRECTORY_OTHER "userdata" /* file version numbers for resource files (levels, tapes, score, setup, etc.) ** currently supported/known file version numbers: ** 1.0 (old) ** 1.2 (still in use) ** 1.4 (still in use) ** 2.0 (actual) */ #define FILE_VERSION_1_0 VERSION_IDENT(1,0,0,0) #define FILE_VERSION_1_2 VERSION_IDENT(1,2,0,0) #define FILE_VERSION_1_4 VERSION_IDENT(1,4,0,0) #define FILE_VERSION_2_0 VERSION_IDENT(2,0,0,0) #define FILE_VERSION_3_0 VERSION_IDENT(3,0,0,0) /* file version does not change for every program version, but is changed when new features are introduced that are incompatible with older file versions, so that they can be treated accordingly */ #define FILE_VERSION_ACTUAL FILE_VERSION_3_0 #define GAME_VERSION_1_0 FILE_VERSION_1_0 #define GAME_VERSION_1_2 FILE_VERSION_1_2 #define GAME_VERSION_1_4 FILE_VERSION_1_4 #define GAME_VERSION_2_0 FILE_VERSION_2_0 #define GAME_VERSION_3_0 FILE_VERSION_3_0 #define GAME_VERSION_ACTUAL VERSION_IDENT(PROGRAM_VERSION_MAJOR, \ PROGRAM_VERSION_MINOR, \ PROGRAM_VERSION_PATCH, \ PROGRAM_VERSION_BUILD) /* values for game_emulation */ #define EMU_NONE 0 #define EMU_BOULDERDASH 1 #define EMU_SOKOBAN 2 #define EMU_SUPAPLEX 3 /* values for level file type identifier */ #define LEVEL_FILE_TYPE_UNKNOWN 0 #define LEVEL_FILE_TYPE_RND 1 #define LEVEL_FILE_TYPE_BD 2 #define LEVEL_FILE_TYPE_EM 3 #define LEVEL_FILE_TYPE_SP 4 #define LEVEL_FILE_TYPE_DX 5 #define LEVEL_FILE_TYPE_SB 6 #define LEVEL_FILE_TYPE_DC 7 #define LEVEL_FILE_TYPE_MM 8 #define NUM_LEVEL_FILE_TYPES 9 /* values for game engine type identifier */ #define GAME_ENGINE_TYPE_UNKNOWN LEVEL_FILE_TYPE_UNKNOWN #define GAME_ENGINE_TYPE_RND LEVEL_FILE_TYPE_RND #define GAME_ENGINE_TYPE_EM LEVEL_FILE_TYPE_EM #define GAME_ENGINE_TYPE_SP LEVEL_FILE_TYPE_SP #define GAME_ENGINE_TYPE_MM LEVEL_FILE_TYPE_MM #define NUM_ENGINE_TYPES 4 /* values for automatically playing tapes */ #define AUTOPLAY_NONE 0 #define AUTOPLAY_PLAY (1 << 0) #define AUTOPLAY_FFWD (1 << 1) #define AUTOPLAY_WARP (1 << 2) #define AUTOPLAY_TEST (1 << 3) #define AUTOPLAY_WARP_NO_DISPLAY AUTOPLAY_TEST #define AUTOPLAY_MODE_NONE 0 #define AUTOPLAY_MODE_PLAY (AUTOPLAY_MODE_NONE | AUTOPLAY_PLAY) #define AUTOPLAY_MODE_FFWD (AUTOPLAY_MODE_PLAY | AUTOPLAY_FFWD) #define AUTOPLAY_MODE_WARP (AUTOPLAY_MODE_FFWD | AUTOPLAY_WARP) #define AUTOPLAY_MODE_TEST (AUTOPLAY_MODE_WARP | AUTOPLAY_TEST) #define AUTOPLAY_MODE_WARP_NO_DISPLAY AUTOPLAY_MODE_TEST struct BorderInfo { boolean draw_masked[NUM_SPECIAL_GFX_ARGS]; boolean draw_masked_when_fading; }; struct RequestButtonInfo { struct TextPosInfo yes; struct TextPosInfo no; struct TextPosInfo confirm; struct TextPosInfo player_1; struct TextPosInfo player_2; struct TextPosInfo player_3; struct TextPosInfo player_4; }; struct MenuMainButtonInfo { struct MenuPosInfo name; struct MenuPosInfo levels; struct MenuPosInfo scores; struct MenuPosInfo editor; struct MenuPosInfo info; struct MenuPosInfo game; struct MenuPosInfo setup; struct MenuPosInfo quit; struct MenuPosInfo prev_level; struct MenuPosInfo next_level; }; struct MenuMainTextInfo { struct TextPosInfo name; struct TextPosInfo levels; struct TextPosInfo scores; struct TextPosInfo editor; struct TextPosInfo info; struct TextPosInfo game; struct TextPosInfo setup; struct TextPosInfo quit; struct TextPosInfo first_level; struct TextPosInfo last_level; struct TextPosInfo level_number; struct TextPosInfo level_info_1; struct TextPosInfo level_info_2; struct TextPosInfo level_name; struct TextPosInfo level_author; struct TextPosInfo level_year; struct TextPosInfo level_imported_from; struct TextPosInfo level_imported_by; struct TextPosInfo level_tested_by; struct TextPosInfo title_1; struct TextPosInfo title_2; struct TextPosInfo title_3; }; struct MenuMainInputInfo { struct TextPosInfo name; }; struct MenuMainInfo { struct MenuMainButtonInfo button; struct MenuMainTextInfo text; struct MenuMainInputInfo input; }; struct TitleFadingInfo { int fade_mode; int fade_delay; int post_delay; int auto_delay; }; struct TitleMessageInfo { int x, y; int width, height; int chars, lines; int align, valign; int font; boolean autowrap; boolean centered; boolean parse_comments; int sort_priority; int fade_mode; int fade_delay; int post_delay; int auto_delay; }; struct InitInfo { struct MenuPosInfo busy; }; struct MenuInfo { int draw_xoffset[NUM_SPECIAL_GFX_ARGS]; int draw_yoffset[NUM_SPECIAL_GFX_ARGS]; int draw_xoffset_info[NUM_SPECIAL_GFX_INFO_ARGS]; int draw_yoffset_info[NUM_SPECIAL_GFX_INFO_ARGS]; int draw_xoffset_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int draw_yoffset_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int scrollbar_xoffset; int list_size[NUM_SPECIAL_GFX_ARGS]; int list_size_info[NUM_SPECIAL_GFX_INFO_ARGS]; int left_spacing[NUM_SPECIAL_GFX_ARGS]; int left_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int left_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int right_spacing[NUM_SPECIAL_GFX_ARGS]; int right_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int right_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int top_spacing[NUM_SPECIAL_GFX_ARGS]; int top_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int top_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int bottom_spacing[NUM_SPECIAL_GFX_ARGS]; int bottom_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int bottom_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int paragraph_spacing[NUM_SPECIAL_GFX_ARGS]; int paragraph_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int paragraph_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int headline1_spacing[NUM_SPECIAL_GFX_ARGS]; int headline1_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int headline1_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int headline2_spacing[NUM_SPECIAL_GFX_ARGS]; int headline2_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int headline2_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int line_spacing[NUM_SPECIAL_GFX_ARGS]; int line_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int line_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; int extra_spacing[NUM_SPECIAL_GFX_ARGS]; int extra_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS]; int extra_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS]; struct TitleFadingInfo enter_menu; struct TitleFadingInfo leave_menu; struct TitleFadingInfo enter_screen[NUM_SPECIAL_GFX_ARGS]; struct TitleFadingInfo leave_screen[NUM_SPECIAL_GFX_ARGS]; struct TitleFadingInfo next_screen[NUM_SPECIAL_GFX_ARGS]; int sound[NUM_SPECIAL_GFX_ARGS]; int music[NUM_SPECIAL_GFX_ARGS]; struct MenuMainInfo main; }; struct DoorInfo { struct DoorPartPosInfo part_1; struct DoorPartPosInfo part_2; struct DoorPartPosInfo part_3; struct DoorPartPosInfo part_4; struct DoorPartPosInfo part_5; struct DoorPartPosInfo part_6; struct DoorPartPosInfo part_7; struct DoorPartPosInfo part_8; struct DoorPartPosInfo panel; int width; int height; int step_offset; int step_delay; int post_delay; int anim_mode; }; struct RequestInfo { struct RequestButtonInfo button; int x, y; int width, height; int border_size; int line_spacing; int step_offset; int step_delay; int anim_mode; int align; int valign; boolean autowrap; boolean centered; boolean wrap_single_words; }; struct PreviewInfo { int x, y; int align, valign; int xsize, ysize; int xoffset, yoffset; int tile_size; int step_offset; int step_delay; int anim_mode; }; struct EditorTabsInfo { int x; int y; int yoffset2; int width; int height; int draw_xoffset; int draw_yoffset; }; struct EditorSettingsInfo { struct MenuPosInfo headline; struct XY element_graphic; struct XY element_name; struct EditorTabsInfo tabs; struct XY tooltip; }; struct EditorGadgetInfo { int normal_spacing; int small_spacing; int tiny_spacing; int line_spacing; int text_spacing; int tab_spacing; struct Rect separator_line; }; struct EditorButtonInfo { struct XYTileSize prev_level; struct XYTileSize next_level; struct XYTileSize properties; struct XYTileSize element_left; struct XYTileSize element_middle; struct XYTileSize element_right; struct XYTileSize palette; struct XYTileSize draw_single; struct XYTileSize draw_connected; struct XYTileSize draw_line; struct XYTileSize draw_arc; struct XYTileSize draw_rectangle; struct XYTileSize draw_filled_box; struct XYTileSize rotate_up; struct XYTileSize draw_text; struct XYTileSize flood_fill; struct XYTileSize rotate_left; struct XYTileSize zoom_level; struct XYTileSize rotate_right; struct XYTileSize draw_random; struct XYTileSize grab_brush; struct XYTileSize rotate_down; struct XYTileSize pick_element; struct XYTileSize ce_copy_from; struct XYTileSize ce_copy_to; struct XYTileSize ce_swap; struct XYTileSize ce_copy; struct XYTileSize ce_paste; struct XYTileSize undo; struct XYTileSize conf; struct XYTileSize save; struct XYTileSize clear; struct XYTileSize test; struct XYTileSize exit; }; struct EditorInputInfo { struct XY level_number; }; struct EditorPaletteInfo { int x, y; int cols, rows; int tile_size; boolean show_as_separate_screen; boolean show_on_element_buttons; struct XYTileSize element_left; struct XYTileSize element_middle; struct XYTileSize element_right; }; struct EditorDrawingAreaInfo { int tile_size; }; struct EditorInfo { struct EditorSettingsInfo settings; struct EditorGadgetInfo gadget; struct EditorButtonInfo button; struct EditorInputInfo input; struct EditorPaletteInfo palette; struct EditorDrawingAreaInfo drawingarea; }; struct ViewportInfo { struct RectWithBorder window[NUM_SPECIAL_GFX_ARGS]; struct RectWithBorder playfield[NUM_SPECIAL_GFX_ARGS]; struct RectWithBorder door_1[NUM_SPECIAL_GFX_ARGS]; struct RectWithBorder door_2[NUM_SPECIAL_GFX_ARGS]; }; struct HiScore { char Name[MAX_PLAYER_NAME_LEN + 1]; int Score; }; struct Content { int e[3][3]; }; struct EnvelopeInfo { int xsize; int ysize; boolean autowrap; boolean centered; char text[MAX_ENVELOPE_TEXT_LEN + 1]; }; struct LevelSetInfo { int music[MAX_LEVELS]; }; struct LevelFileInfo { int nr; int type; boolean packed; char *basename; char *filename; }; struct DateInfo { int year; int month; int day; enum { DATE_SRC_CLOCK, DATE_SRC_LEVELFILE } src; }; struct LevelInfo { struct LevelFileInfo file_info; int game_engine_type; /* level stored in native format for the alternative native game engines */ struct LevelInfo_EM *native_em_level; struct LevelInfo_SP *native_sp_level; struct LevelInfo_MM *native_mm_level; int file_version; /* file format version the level is stored with */ int game_version; /* game release version the level was created with */ struct DateInfo creation_date; boolean encoding_16bit_field; /* level contains 16-bit elements */ boolean encoding_16bit_yamyam; /* yamyam contains 16-bit elements */ boolean encoding_16bit_amoeba; /* amoeba contains 16-bit elements */ int fieldx, fieldy; int time; /* available time (seconds) */ int gems_needed; boolean auto_count_gems; char name[MAX_LEVEL_NAME_LEN + 1]; char author[MAX_LEVEL_AUTHOR_LEN + 1]; int random_seed; struct EnvelopeInfo envelope[NUM_ENVELOPES]; int score[LEVEL_SCORE_ELEMENTS]; struct Content yamyam_content[MAX_ELEMENT_CONTENTS]; int num_yamyam_contents; int amoeba_speed; int amoeba_content; int game_of_life[4]; int biomaze[4]; int time_magic_wall; int time_wheel; int time_light; int time_timegate; int shield_normal_time; int shield_deadly_time; int extra_time; int time_orb_time; int extra_time_score; int start_element[MAX_PLAYERS]; boolean use_start_element[MAX_PLAYERS]; int artwork_element[MAX_PLAYERS]; boolean use_artwork_element[MAX_PLAYERS]; int explosion_element[MAX_PLAYERS]; boolean use_explosion_element[MAX_PLAYERS]; /* values for the new EMC elements */ int android_move_time; int android_clone_time; boolean ball_random; boolean ball_state_initial; int ball_time; int lenses_score; int magnify_score; int slurp_score; int lenses_time; int magnify_time; int wind_direction_initial; struct Content ball_content[MAX_ELEMENT_CONTENTS]; int num_ball_contents; int num_android_clone_elements; int android_clone_element[MAX_ANDROID_ELEMENTS]; int can_move_into_acid_bits; /* bitfield to store property for elements */ int dont_collide_with_bits; /* bitfield to store property for elements */ int initial_player_stepsize[MAX_PLAYERS]; /* initial player speed */ boolean initial_player_gravity[MAX_PLAYERS]; boolean use_initial_inventory[MAX_PLAYERS]; int initial_inventory_size[MAX_PLAYERS]; int initial_inventory_content[MAX_PLAYERS][MAX_INITIAL_INVENTORY_SIZE]; boolean em_slippery_gems; /* EM style "gems slip from wall" behaviour */ boolean em_explodes_by_fire; /* EM style chain explosion behaviour */ boolean use_spring_bug; /* for compatibility with old levels */ boolean use_time_orb_bug; /* for compatibility with old levels */ boolean instant_relocation; /* no visual delay when relocating player */ boolean shifted_relocation; /* no level centering when relocating player */ boolean lazy_relocation; /* only redraw off-screen player relocation */ boolean can_pass_to_walkable; /* player can pass to empty or walkable tile */ boolean grow_into_diggable; /* amoeba can grow into anything diggable */ boolean auto_exit_sokoban; /* automatically finish solved Sokoban levels */ boolean continuous_snapping; /* repeated snapping without releasing key */ boolean block_snap_field; /* snapping blocks field to show animation */ boolean block_last_field; /* player blocks previous field while moving */ boolean sp_block_last_field; /* player blocks previous field while moving */ /* values for MM/DF elements */ boolean mm_laser_red, mm_laser_green, mm_laser_blue; boolean df_laser_red, df_laser_green, df_laser_blue; int mm_time_fuse; int mm_time_bomb; int mm_time_ball; int mm_time_block; /* ('int' instead of 'boolean' because used as selectbox value in editor) */ int use_step_counter; /* count steps instead of seconds for level */ short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; boolean use_custom_template; /* use custom properties from template file */ boolean file_has_custom_elements; /* set when level file contains CEs */ boolean no_valid_file; /* set when level file missing or invalid */ boolean no_level_file; /* set when falling back to level template */ boolean changed; /* set when level was changed in the editor */ /* runtime flags to handle bugs in old levels (not stored in level file) */ boolean use_action_after_change_bug; }; struct GlobalInfo { char *autoplay_leveldir; int autoplay_level[MAX_TAPES_PER_SET]; boolean autoplay_all; boolean autoplay_mode; char *convert_leveldir; int convert_level_nr; char *create_images_dir; int num_toons; float frames_per_second; boolean show_frames_per_second; /* global values for fading screens and masking borders */ int border_status; /* values for global animations */ int anim_status; int anim_status_next; boolean use_envelope_request; }; struct ElementChangeInfo { boolean can_change; /* use or ignore this change info */ boolean has_event[NUM_CHANGE_EVENTS]; /* change events */ int trigger_player; /* player triggering change */ int trigger_side; /* side triggering change */ int trigger_page; /* page triggering change */ int target_element; /* target element after change */ int delay_fixed; /* added frame delay before changed (fixed) */ int delay_random; /* added frame delay before changed (random) */ int delay_frames; /* either 1 (frames) or 50 (seconds; 50 fps) */ int initial_trigger_element; /* initial element triggering change */ struct Content target_content;/* elements for extended change target */ boolean use_target_content; /* use extended change target */ boolean only_if_complete; /* only use complete target content */ boolean use_random_replace; /* use random value for replacing elements */ int random_percentage; /* random value for replacing elements */ int replace_when; /* type of elements that can be replaced */ boolean explode; /* explode instead of change */ boolean has_action; /* execute action on specified condition */ int action_type; /* type of action */ int action_mode; /* mode of action */ int action_arg; /* parameter of action */ int action_element; /* element related to action */ /* ---------- internal values used at runtime when playing ---------- */ int trigger_element; /* element triggering change */ /* functions that are called before, while and after the change of an element -- currently only used for non-custom elements */ void (*pre_change_function)(int x, int y); void (*change_function)(int x, int y); void (*post_change_function)(int x, int y); short actual_trigger_element; /* element that actually triggered change */ int actual_trigger_side; /* element side that triggered the change */ int actual_trigger_player; /* player which actually triggered change */ int actual_trigger_player_bits; /* player bits of triggering players */ int actual_trigger_ce_value; /* CE value of element that triggered change */ int actual_trigger_ce_score; /* CE score of element that triggered change */ boolean can_change_or_has_action; /* can_change | has_action */ /* ---------- internal values used in level editor ---------- */ int direct_action; /* change triggered by actions on element */ int other_action; /* change triggered by other element actions */ }; struct ElementGroupInfo { int num_elements; /* number of elements in this group */ int element[MAX_ELEMENTS_IN_GROUP]; /* list of elements in this group */ int choice_mode; /* how to choose element from group */ /* ---------- internal values used at runtime when playing ---------- */ /* the following is the same as above, but with recursively resolved group elements (group elements may also contain further group elements!) */ int num_elements_resolved; short element_resolved[NUM_FILE_ELEMENTS]; int choice_pos; /* current element choice position */ }; struct ElementNameInfo { /* ---------- token and description strings ---------- */ char *token_name; /* element token used in config files */ char *class_name; /* element class used in config files */ char *editor_description; /* pre-defined description for level editor */ }; struct ElementInfo { /* ---------- token and description strings ---------- */ char *token_name; /* element token used in config files */ char *class_name; /* element class used in config files */ char *editor_description; /* pre-defined description for level editor */ char *custom_description; /* alternative description from config file */ char description[MAX_ELEMENT_NAME_LEN + 1]; /* for custom/group elements */ /* ---------- graphic and sound definitions ---------- */ int graphic[NUM_ACTIONS]; /* default graphics for several actions */ int direction_graphic[NUM_ACTIONS][NUM_DIRECTIONS_FULL]; /* special graphics for left/right/up/down */ int crumbled[NUM_ACTIONS]; /* crumbled graphics for several actions */ int direction_crumbled[NUM_ACTIONS][NUM_DIRECTIONS_FULL]; /* crumbled graphics for left/right/up/down */ int special_graphic[NUM_SPECIAL_GFX_ARGS]; /* special graphics for certain screens */ int sound[NUM_ACTIONS]; /* default sounds for several actions */ /* ---------- special element property values ---------- */ unsigned int properties[NUM_EP_BITFIELDS]; /* element base properties */ boolean use_gfx_element; /* use custom graphic element */ int gfx_element_initial; /* initial optional custom graphic element */ int access_direction; /* accessible from which direction */ int collect_score_initial; /* initial score value for collecting */ int collect_count_initial; /* initial count value for collecting */ int ce_value_fixed_initial; /* initial value for custom variable (fix) */ int ce_value_random_initial; /* initial value for custom variable (rnd) */ boolean use_last_ce_value; /* use value from element before change */ int push_delay_fixed; /* constant delay before pushing */ int push_delay_random; /* additional random delay before pushing */ int drop_delay_fixed; /* constant delay after dropping */ int drop_delay_random; /* additional random delay after dropping */ int move_delay_fixed; /* constant delay after moving */ int move_delay_random; /* additional random delay after moving */ int move_pattern; /* direction movable element moves to */ int move_direction_initial; /* initial direction element moves to */ int move_stepsize; /* step size element moves with */ int move_enter_element; /* element that can be entered (and removed) */ int move_leave_element; /* element that can be left behind */ int move_leave_type; /* change (limited) or leave (unlimited) */ int slippery_type; /* how/where other elements slip away */ struct Content content; /* new elements after explosion */ int explosion_type; /* type of explosion, like 3x3, 3+3 or 1x1 */ int explosion_delay; /* duration of explosion of this element */ int ignition_delay; /* delay for explosion by other explosion */ struct ElementChangeInfo *change_page; /* actual list of change pages */ struct ElementChangeInfo *change; /* pointer to current change page */ int num_change_pages; /* actual number of change pages */ int current_change_page; /* currently edited change page */ struct ElementGroupInfo *group; /* pointer to element group info */ /* ---------- internal values used at runtime when playing ---------- */ boolean has_change_event[NUM_CHANGE_EVENTS]; int event_page_nr[NUM_CHANGE_EVENTS]; /* page number for each event */ struct ElementChangeInfo *event_page[NUM_CHANGE_EVENTS]; /* page for event */ boolean in_group[NUM_GROUP_ELEMENTS]; int gfx_element; /* runtime optional custom graphic element */ int collect_score; /* runtime score value for collecting */ /* count of this element on playfield, calculated after each frame */ int element_count; /* ---------- internal values used in level editor ---------- */ int access_type; /* walkable or passable */ int access_layer; /* accessible over/inside/under */ int access_protected; /* protection against deadly elements */ int walk_to_action; /* diggable/collectible/pushable */ int smash_targets; /* can smash player/enemies/everything */ int deadliness; /* deadly when running/colliding/touching */ boolean can_explode_by_fire; /* element explodes by fire */ boolean can_explode_smashed; /* element explodes when smashed */ boolean can_explode_impact; /* element explodes on impact */ boolean modified_settings; /* set for all modified custom elements */ }; struct FontInfo { char *token_name; /* font token used in config files */ int graphic; /* default graphic for this font */ int special_graphic[NUM_SPECIAL_GFX_ARGS]; /* special graphics for certain screens */ int special_bitmap_id[NUM_SPECIAL_GFX_ARGS]; /* internal bitmap ID for special graphics */ }; struct GlobalAnimNameInfo { char *token_name; /* global animation token in config files */ }; struct GlobalAnimInfo { char *token_name; /* global animation token in config files */ /* global animation graphic and control definitions */ int graphic[NUM_GLOBAL_ANIM_PARTS_ALL][NUM_SPECIAL_GFX_ARGS]; /* global animation sound and music definitions */ int sound[NUM_GLOBAL_ANIM_PARTS_ALL][NUM_SPECIAL_GFX_ARGS]; int music[NUM_GLOBAL_ANIM_PARTS_ALL][NUM_SPECIAL_GFX_ARGS]; }; struct GraphicInfo { Bitmap **bitmaps; /* bitmaps in all required sizes */ Bitmap *bitmap; /* bitmap in default size */ int src_image_width; /* scaled bitmap size, but w/o small images */ int src_image_height; /* scaled bitmap size, but w/o small images */ int src_x, src_y; /* start position of animation frames */ int width, height; /* width/height of each animation frame */ int offset_x, offset_y; /* x/y offset to next animation frame */ int offset2_x, offset2_y; /* x/y offset to second movement tile */ boolean double_movement; /* animation has second movement tile */ int swap_double_tiles; /* explicitely force or forbid tile swapping */ int anim_frames; int anim_frames_per_line; int anim_start_frame; int anim_delay; /* important: delay of 1 means "no delay"! */ int anim_mode; boolean anim_global_sync; int crumbled_like; /* element for cloning crumble graphics */ int diggable_like; /* element for cloning digging graphics */ int border_size; /* border size for "crumbled" graphics */ int scale_up_factor; /* optional factor for scaling image up */ int tile_size; /* optional explicitly defined tile size */ int clone_from; /* graphic for cloning *all* settings */ int init_delay_fixed; /* optional initial delay values for global */ int init_delay_random; /* animations (pause interval before start) */ int anim_delay_fixed; /* optional delay values for bored/sleeping */ int anim_delay_random; /* and global animations (animation length) */ int post_delay_fixed; /* optional delay values after bored/global */ int post_delay_random; /* animations (pause before next animation) */ int init_event; /* optional event triggering animation start */ int anim_event; /* optional event triggering animation end */ int step_offset; /* optional step offset of toon animations */ int step_xoffset; /* optional step offset of toon animations */ int step_yoffset; /* optional step offset of toon animations */ int step_delay; /* optional step delay of toon animations */ int direction; /* optional move direction of toon animations */ int position; /* optional draw position of toon animations */ int x; /* optional draw position of toon animations */ int y; /* optional draw position of toon animations */ int draw_xoffset; /* optional offset for drawing font chars */ int draw_yoffset; /* optional offset for drawing font chars */ int draw_masked; /* optional setting for drawing envelope gfx */ int draw_order; /* optional draw order for global animations */ int fade_mode; /* optional setting for drawing title screens */ int fade_delay; /* optional setting for drawing title screens */ int post_delay; /* optional setting for drawing title screens */ int auto_delay; /* optional setting for drawing title screens */ int align, valign; /* optional setting for drawing title screens */ int sort_priority; /* optional setting for drawing title screens */ int class; int style; int active_xoffset; int active_yoffset; int pressed_xoffset; int pressed_yoffset; boolean use_image_size; /* use image size as default width and height */ }; struct SoundInfo { boolean loop; int volume; int priority; }; struct MusicInfo { boolean loop; }; struct MusicPrefixInfo { char *prefix; boolean is_loop_music; }; struct MusicFileInfo { char *basename; char *title_header; char *artist_header; char *album_header; char *year_header; char *title; char *artist; char *album; char *year; int music; boolean is_sound; struct MusicFileInfo *next; }; struct ElementActionInfo { char *suffix; int value; boolean is_loop_sound; }; struct ElementDirectionInfo { char *suffix; int value; }; struct SpecialSuffixInfo { char *suffix; int value; }; struct HelpAnimInfo { int element; int action; int direction; int delay; }; extern Bitmap *bitmap_db_field; extern Bitmap *bitmap_db_panel; extern Bitmap *bitmap_db_door_1; extern Bitmap *bitmap_db_door_2; extern Bitmap *bitmap_db_store_1; extern Bitmap *bitmap_db_store_2; extern DrawBuffer *fieldbuffer; extern DrawBuffer *drawto_field; extern int game_status; extern boolean game_status_last_screen; extern boolean level_editor_test_game; extern boolean network_playing; #if defined(TARGET_SDL) extern boolean network_server; extern SDL_Thread *server_thread; #endif extern int key_joystick_mapping; extern short Feld[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 ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short CustomValue[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 Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern boolean Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short AmoebaCnt[MAX_NUM_AMOEBA]; extern short AmoebaCnt2[MAX_NUM_AMOEBA]; extern short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int ActiveElement[MAX_NUM_ELEMENTS]; extern int ActiveButton[NUM_IMAGE_FILES]; extern int ActiveFont[NUM_FONTS]; extern int lev_fieldx, lev_fieldy; extern int scroll_x, scroll_y; extern int WIN_XSIZE, WIN_YSIZE; extern int SCR_FIELDX, SCR_FIELDY; extern int REAL_SX, REAL_SY; extern int SX, SY; extern int DX, DY; extern int VX, VY; extern int EX, EY; extern int dDX, dDY; extern int FULL_SXSIZE, FULL_SYSIZE; extern int SXSIZE, SYSIZE; extern int DXSIZE, DYSIZE; extern int VXSIZE, VYSIZE; extern int EXSIZE, EYSIZE; extern int TILESIZE_VAR; extern int FADE_SX, FADE_SY; extern int FADE_SXSIZE, FADE_SYSIZE; extern int FX, FY; extern int ScrollStepSize; extern int ScreenMovDir, ScreenMovPos, ScreenGfxPos; extern int BorderElement; extern int MenuFrameDelay; extern int GameFrameDelay; extern int FfwdFrameDelay; extern int BX1, BY1; extern int BX2, BY2; extern int SBX_Left, SBX_Right; extern int SBY_Upper, SBY_Lower; extern int ZX, ZY; extern int ExitX, ExitY; extern int AllPlayersGone; extern int TimeFrames, TimePlayed, TimeLeft, TapeTime; extern boolean network_player_action_received; extern int graphics_action_mapping[]; extern struct LevelSetInfo levelset; extern struct LevelInfo level, level_template; extern struct HiScore highscore[]; extern struct TapeInfo tape; extern struct GlobalInfo global; extern struct BorderInfo border; extern struct ViewportInfo viewport; extern struct TitleFadingInfo fading; extern struct TitleFadingInfo fading_none; extern struct TitleFadingInfo title_initial_first_default; extern struct TitleFadingInfo title_initial_default; extern struct TitleFadingInfo title_first_default; extern struct TitleFadingInfo title_default; extern struct TitleMessageInfo titlescreen_initial_first_default; extern struct TitleMessageInfo titlescreen_initial_first[]; extern struct TitleMessageInfo titlescreen_initial_default; extern struct TitleMessageInfo titlescreen_initial[]; extern struct TitleMessageInfo titlescreen_first_default; extern struct TitleMessageInfo titlescreen_first[]; extern struct TitleMessageInfo titlescreen_default; extern struct TitleMessageInfo titlescreen[]; extern struct TitleMessageInfo titlemessage_initial_first_default; extern struct TitleMessageInfo titlemessage_initial_first[]; extern struct TitleMessageInfo titlemessage_initial_default; extern struct TitleMessageInfo titlemessage_initial[]; extern struct TitleMessageInfo titlemessage_first_default; extern struct TitleMessageInfo titlemessage_first[]; extern struct TitleMessageInfo titlemessage_default; extern struct TitleMessageInfo titlemessage[]; extern struct TitleMessageInfo readme; extern struct InitInfo init, init_last; extern struct MenuInfo menu; extern struct DoorInfo door_1, door_2; extern struct RequestInfo request; extern struct PreviewInfo preview; extern struct EditorInfo editor; extern struct ElementInfo element_info[]; extern struct ElementNameInfo element_name_info[]; extern struct ElementActionInfo element_action_info[]; extern struct ElementDirectionInfo element_direction_info[]; extern struct SpecialSuffixInfo special_suffix_info[]; extern struct TokenIntPtrInfo image_config_vars[]; extern struct FontInfo font_info[]; extern struct GlobalAnimInfo global_anim_info[]; extern struct GlobalAnimNameInfo global_anim_name_info[]; extern struct MusicPrefixInfo music_prefix_info[]; extern struct GraphicInfo *graphic_info; extern struct SoundInfo *sound_info; extern struct MusicInfo *music_info; extern struct MusicFileInfo *music_file_info; extern struct HelpAnimInfo *helpanim_info; extern SetupFileHash *helptext_info; extern SetupFileHash *image_config_hash; extern SetupFileHash *element_token_hash; extern SetupFileHash *graphic_token_hash; extern SetupFileHash *font_token_hash; extern SetupFileHash *hide_setup_hash; extern struct ConfigTypeInfo image_config_suffix[]; extern struct ConfigTypeInfo sound_config_suffix[]; extern struct ConfigTypeInfo music_config_suffix[]; extern struct ConfigInfo image_config[]; extern struct ConfigInfo sound_config[]; extern struct ConfigInfo music_config[]; extern struct ConfigInfo helpanim_config[]; extern struct ConfigInfo helptext_config[]; #endif /* MAIN_H */ mirrormagic-3.0.0/src/conf_hlp.c0000644000175000017500000003714213263212010016053 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_hlp.c // ============================================================================ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is GFX_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigInfo helpanim_config[] = { { "player_1.moving.down", "16" }, { "player_1.moving.up", "16" }, { "player_1.moving.left", "16" }, { "player_1.moving.right", "16" }, { "player_1.pushing.left", "16" }, { "player_1.pushing.right", "16" }, { "end", "" }, { "sand", "50" }, { "sand.digging.left", "8" }, { "empty_space", "10" }, { "sand", "50" }, { "sand.digging.right", "8" }, { "empty_space", "10" }, { "sand", "50" }, { "sand.digging.up", "8" }, { "empty_space", "10" }, { "sand", "50" }, { "sand.digging.down", "8" }, { "empty_space", "10" }, { "end", "" }, { "empty_space", "-1" }, { "end", "" }, { "quicksand_empty", "-1" }, { "end", "" }, { "steelwall", "-1" }, { "end", "" }, { "wall", "-1" }, { "end", "" }, { "expandable_wall.growing.left", "20" }, { "wall", "50" }, { "expandable_wall.growing.right", "20" }, { "wall", "50" }, { "expandable_wall.growing.up", "20" }, { "wall", "50" }, { "expandable_wall.growing.down", "20" }, { "wall", "50" }, { "empty_space", "20" }, { "end", "" }, { "invisible_wall", "-1" }, { "end", "" }, { "wall_slippery", "-1" }, { "end", "" }, { "char_space", "10" }, { "char_exclam", "10" }, { "char_quotedbl", "10" }, { "char_numbersign", "10" }, { "char_dollar", "10" }, { "char_percent", "10" }, { "char_ampersand", "10" }, { "char_apostrophe", "10" }, { "char_parenleft", "10" }, { "char_parenright", "10" }, { "char_asterisk", "10" }, { "char_plus", "10" }, { "char_comma", "10" }, { "char_minus", "10" }, { "char_period", "10" }, { "char_slash", "10" }, { "char_0", "10" }, { "char_1", "10" }, { "char_2", "10" }, { "char_3", "10" }, { "char_4", "10" }, { "char_5", "10" }, { "char_6", "10" }, { "char_7", "10" }, { "char_8", "10" }, { "char_9", "10" }, { "char_colon", "10" }, { "char_semicolon", "10" }, { "char_less", "10" }, { "char_equal", "10" }, { "char_greater", "10" }, { "char_question", "10" }, { "char_at", "10" }, { "char_a", "10" }, { "char_b", "10" }, { "char_c", "10" }, { "char_d", "10" }, { "char_e", "10" }, { "char_f", "10" }, { "char_g", "10" }, { "char_h", "10" }, { "char_i", "10" }, { "char_j", "10" }, { "char_k", "10" }, { "char_l", "10" }, { "char_m", "10" }, { "char_n", "10" }, { "char_o", "10" }, { "char_p", "10" }, { "char_q", "10" }, { "char_r", "10" }, { "char_s", "10" }, { "char_t", "10" }, { "char_u", "10" }, { "char_v", "10" }, { "char_w", "10" }, { "char_x", "10" }, { "char_y", "10" }, { "char_z", "10" }, { "char_bracketleft", "10" }, { "char_backslash", "10" }, { "char_bracketright", "10" }, { "char_asciicircum", "10" }, { "char_underscore", "10" }, { "char_copyright", "10" }, { "char_aumlaut", "10" }, { "char_oumlaut", "10" }, { "char_uumlaut", "10" }, { "char_degree", "10" }, { "char_trademark", "10" }, { "char_cursor", "10" }, { "end", "" }, { "emerald", "50" }, { "emerald.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "diamond", "50" }, { "diamond.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "bd_diamond", "50" }, { "bd_diamond.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "emerald_yellow", "50" }, { "emerald_yellow.collecting", "8" }, { "empty_space", "10" }, { "emerald_red", "50" }, { "emerald_red.collecting", "8" }, { "empty_space", "10" }, { "emerald_purple", "50" }, { "emerald_purple.collecting", "8" }, { "empty_space", "10" }, { "end", "" }, { "bd_rock", "-1" }, { "end", "" }, { "bomb", "100" }, { "bomb.exploding", "16" }, { "empty_space", "10" }, { "end", "" }, { "nut", "100" }, { "nut.breaking", "6" }, { "emerald", "20" }, { "end", "" }, { "wall_emerald", "100" }, { "wall_emerald.exploding", "16" }, { "emerald", "20" }, { "end", "" }, { "wall_diamond", "100" }, { "wall_diamond.exploding", "16" }, { "diamond", "20" }, { "end", "" }, { "wall_bd_diamond", "100" }, { "wall_bd_diamond.exploding", "16" }, { "bd_diamond", "20" }, { "end", "" }, { "wall_emerald_yellow", "100" }, { "wall_emerald_yellow.exploding", "16" }, { "emerald_yellow", "20" }, { "wall_emerald_red", "100" }, { "wall_emerald_red.exploding", "16" }, { "emerald_red", "20" }, { "wall_emerald_purple", "100" }, { "wall_emerald_purple.exploding", "16" }, { "emerald_purple", "20" }, { "end", "" }, { "acid", "-1" }, { "end", "" }, { "key_1", "50" }, { "key_2", "50" }, { "key_3", "50" }, { "key_4", "50" }, { "end", "" }, { "gate_1", "50" }, { "gate_2", "50" }, { "gate_3", "50" }, { "gate_4", "50" }, { "end", "" }, { "gate_1_gray", "50" }, { "gate_2_gray", "50" }, { "gate_3_gray", "50" }, { "gate_4_gray", "50" }, { "end", "" }, { "dynamite", "-1" }, { "end", "" }, { "dynamite.active", "96" }, { "dynamite.exploding", "16" }, { "empty_space", "20" }, { "end", "" }, { "dynabomb.active", "100" }, { "dynabomb.exploding", "16" }, { "empty_space", "20" }, { "end", "" }, { "dynabomb_increase_number", "-1" }, { "end", "" }, { "dynabomb_increase_size", "-1" }, { "end", "" }, { "dynabomb_increase_power", "-1" }, { "end", "" }, { "spaceship.turning_from_right.up", "8" }, { "spaceship.turning_from_up.left", "8" }, { "spaceship.turning_from_left.down", "8" }, { "spaceship.turning_from_down.right", "8" }, { "end", "" }, { "bug.turning_from_right.up", "8" }, { "bug.turning_from_up.left", "8" }, { "bug.turning_from_left.down", "8" }, { "bug.turning_from_down.right", "8" }, { "end", "" }, { "bd_butterfly", "-1" }, { "end", "" }, { "bd_firefly", "-1" }, { "end", "" }, { "pacman.right", "16" }, { "pacman.up", "16" }, { "pacman.left", "16" }, { "pacman.down", "16" }, { "end", "" }, { "yamyam", "-1" }, { "end", "" }, { "dark_yamyam", "-1" }, { "end", "" }, { "robot", "-1" }, { "end", "" }, { "mole.moving.right", "16" }, { "mole.moving.up", "16" }, { "mole.moving.left", "16" }, { "mole.moving.down", "16" }, { "end", "" }, { "penguin.moving.right", "16" }, { "penguin.moving.up", "16" }, { "penguin.moving.left", "16" }, { "penguin.moving.down", "16" }, { "end", "" }, { "pig.moving.right", "16" }, { "pig.moving.up", "16" }, { "pig.moving.left", "16" }, { "pig.moving.down", "16" }, { "end", "" }, { "dragon.moving.right", "16" }, { "dragon.moving.up", "16" }, { "dragon.moving.left", "16" }, { "dragon.moving.down", "16" }, { "end", "" }, { "satellite", "-1" }, { "end", "" }, { "robot_wheel", "50" }, { "robot_wheel.active", "100" }, { "end", "" }, { "lamp", "50" }, { "lamp.active", "50" }, { "end", "" }, { "time_orb_full", "50" }, { "time_orb_empty", "50" }, { "end", "" }, { "amoeba_drop", "50" }, { "amoeba.growing", "6" }, { "amoeba_wet", "20" }, { "end", "" }, { "amoeba_dead", "-1" }, { "end", "" }, { "amoeba_wet", "-1" }, { "end", "" }, { "amoeba_wet", "100" }, { "amoeba.growing", "6" }, { "end", "" }, { "amoeba_full", "50" }, { "amoeba_dead", "50" }, { "amoeba.exploding", "16" }, { "diamond", "20" }, { "end", "" }, { "game_of_life", "-1" }, { "end", "" }, { "biomaze", "-1" }, { "end", "" }, { "magic_wall.active", "-1" }, { "end", "" }, { "bd_magic_wall.active", "-1" }, { "end", "" }, { "exit_closed", "200" }, { "exit.opening", "30" }, { "exit_open", "100" }, { "exit.closing", "30" }, { "end", "" }, { "exit_open", "-1" }, { "end", "" }, { "sokoban_object", "-1" }, { "end", "" }, { "sokoban_field_empty", "-1" }, { "end", "" }, { "sokoban_field_full", "-1" }, { "end", "" }, { "speed_pill", "-1" }, { "end", "" }, { NULL, NULL } }; struct ConfigInfo helptext_config[] = { { "player_1", "THE HERO: (Is _this_ guy good old Rockford?)" }, { "sand", "Normal sand: You can dig through it" }, { "empty_space", "Empty field: You can walk through it" }, { "quicksand_empty", "Quicksand: You cannot pass it, but rocks can fall through it" }, { "steelwall", "Massive Wall: Nothing can go through it" }, { "wall", "Normal Wall: You can't go through it, but you can bomb it away" }, { "expandable_wall", "Growing Wall: Grows in several directions if there is an empty field" }, { "invisible_wall", "Invisible Wall: Behaves like normal wall, but is invisible" }, { "wall_slippery", "Old Wall: Like normal wall, but some things can fall down from it" }, { "char_space", "Letter Wall: Looks like a letter, behaves like a normal wall" }, { "emerald", "Emerald: You must collect enough of them to finish a level" }, { "diamond", "Diamond: Counts as 3 emeralds, but can be destroyed by rocks" }, { "bd_diamond", "Diamond (BD style): Counts like one emerald and behaves a bit different" }, { "emerald_yellow", "Colorful Gems: Seem to behave like Emeralds" }, { "bd_rock", "Rock: Smashes several things; Can be moved by the player" }, { "bomb", "Bomb: You can move it, but be careful when dropping it" }, { "nut", "Nut: Throw a rock on it to open it; Each nut contains an emerald" }, { "wall_emerald", "Wall with an emerald inside: Bomb the wall away to get it" }, { "wall_diamond", "Wall with a diamond inside: Bomb the wall away to get it" }, { "wall_bd_diamond", "Wall with BD style diamond inside: Bomb the wall away to get it" }, { "wall_emerald_yellow", "Wall with colorful gem inside: Bomb the wall away to get it" }, { "acid", "Acid: Things that fall in are gone forever (including our hero)" }, { "key_1", "Key: Opens the door that has the same color (red/yellow/green/blue)" }, { "gate_1", "Door: Can be opened by the key with the same color" }, { "gate_1_gray", "Door: You have to find out the right color of the key for it" }, { "dynamite", "Dynamite: Collect it and use it to destroy walls or kill enemies" }, { "dynamite.active", "Dynamite: This one explodes after a few seconds" }, { "dynabomb", "Dyna Bomb: Explodes in 4 directions with variable explosion size" }, { "dynabomb_increase_number", "Dyna Bomb: Increases the number of dyna bombs available at a time" }, { "dynabomb_increase_size", "Dyna Bomb: Increases the size of explosion of dyna bombs" }, { "dynabomb_increase_power", "Dyna Bomb: Increases the power of explosion of dyna bombs" }, { "spaceship", "Spaceship: Moves at the left side of walls; don't touch it!" }, { "bug", "Bug: Moves at the right side of walls; don't touch it!" }, { "bd_butterfly", "Butterfly: Moves at the right side of walls; don't touch it!" }, { "bd_firefly", "Firefly: Moves at the left side of walls; don't touch it!" }, { "pacman", "Pacman: Eats the amoeba and you, if you're not careful" }, { "yamyam", "Yam Yam: Eats diamonds and you, if you're not careful" }, { "dark_yamyam", "Dark Yam Yam: Eats almost everything" }, { "robot", "Robot: Tries to kill the player" }, { "mole", "The mole: Eats the amoeba and turns empty space into normal sand" }, { "penguin", "The penguin: Guide him to the exit, but keep him away from monsters!" }, { "pig", "The Pig: Harmless, but eats all gems it can get" }, { "dragon", "The Dragon: Breathes fire, especially to some monsters" }, { "satellite", "Sonde: Follows you everywhere; harmless, but may block your way" }, { "robot_wheel", "Magic Wheel: Touch it to get rid of the robots for some seconds" }, { "lamp", "Light Bulb: All of them must be switched on to finish a level" }, { "time_orb_full", "Extra Time Orb: Adds some seconds to the time available for the level" }, { "amoeba_drop", "Amoeba Drop: Grows to an amoeba on the ground - don't touch it" }, { "amoeba_dead", "Dead Amoeba: Does not grow, but can still kill bugs and spaceships" }, { "amoeba_wet", "Normal Amoeba: Grows through empty fields, sand and quicksand" }, { "amoeba_wet", "Dropping Amoeba: This one makes drops that grow to a new amoeba" }, { "amoeba_full", "Living Amoeba (BD style): Contains other element, when surrounded" }, { "game_of_life", "Game Of Life: Behaves like the well known 'Game Of Life' (2333 style)" }, { "biomaze", "Biomaze: A bit like the 'Game Of Life', but builds crazy mazes" }, { "magic_wall", "Magic Wall: Changes rocks, emeralds and diamonds when they pass it" }, { "bd_magic_wall", "Magic Wall (BD style): Changes rocks and BD style diamonds" }, { "exit_closed", "Exit door: Opens if you have enough emeralds to finish the level" }, { "exit_open", "Open exit door: Enter here to leave the level and exit the actual game" }, { "sokoban_object", "Sokoban element: Object which must be pushed to an empty field" }, { "sokoban_field_empty", "Sokoban element: Empty field where a Sokoban object can be placed on" }, { "sokoban_field_full", "Sokoban element: Field with object which can be pushed away" }, { "speed_pill", "Speed pill: Lets the player run twice as fast as normally" }, { NULL, NULL } }; mirrormagic-3.0.0/src/conf_g2s.c0000644000175000017500000000257713263214151015777 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_g2s.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_G2S_C #define CONF_G2S_C /* values for gamemode/sound mapping configuration */ static struct { int gamemode; int sound; } gamemode_to_sound[] = { { GFX_SPECIAL_ARG_TITLE_INITIAL, SND_BACKGROUND_TITLE_INITIAL }, { GFX_SPECIAL_ARG_TITLE, SND_BACKGROUND_TITLE }, { GFX_SPECIAL_ARG_MAIN, SND_BACKGROUND_MAIN }, { GFX_SPECIAL_ARG_LEVELS, SND_BACKGROUND_LEVELS }, { GFX_SPECIAL_ARG_LEVELNR, SND_BACKGROUND_LEVELNR }, { GFX_SPECIAL_ARG_SCORES, SND_BACKGROUND_SCORES }, { GFX_SPECIAL_ARG_EDITOR, SND_BACKGROUND_EDITOR }, { GFX_SPECIAL_ARG_INFO, SND_BACKGROUND_INFO }, { GFX_SPECIAL_ARG_SETUP, SND_BACKGROUND_SETUP }, { -1, -1 }, }; #endif /* CONF_G2S_C */ mirrormagic-3.0.0/src/conf_snd.h0000644000175000017500000002702313263214151016066 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_snd.h // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_SND_H #define CONF_SND_H /* values for sounds configuration */ #define SND_CLASS_DEFAULT_DIGGING 0 #define SND_CLASS_DEFAULT_COLLECTING 1 #define SND_CLASS_DEFAULT_SNAPPING 2 #define SND_CLASS_DEFAULT_PUSHING 3 #define SND_CLASS_DEFAULT_IMPACT 4 #define SND_CLASS_DEFAULT_WALKING 5 #define SND_CLASS_DEFAULT_PASSING 6 #define SND_CLASS_DEFAULT_DYING 7 #define SND_CLASS_DEFAULT_EXPLODING 8 #define SND_CLASS_DEFAULT_HITTING 9 #define SND_CLASS_SP_DEFAULT_EXPLODING 10 #define SND_CLASS_MM_DEFAULT_EXPLODING 11 #define SND_BD_DIAMOND_COLLECTING 12 #define SND_BD_DIAMOND_IMPACT 13 #define SND_BD_ROCK_PUSHING 14 #define SND_BD_ROCK_IMPACT 15 #define SND_BD_MAGIC_WALL_ACTIVATING 16 #define SND_BD_MAGIC_WALL_ACTIVE 17 #define SND_BD_MAGIC_WALL_FILLING 18 #define SND_BD_AMOEBA_WAITING 19 #define SND_BD_AMOEBA_GROWING 20 #define SND_BD_AMOEBA_TURNING_TO_GEM 21 #define SND_BD_AMOEBA_TURNING_TO_ROCK 22 #define SND_BD_BUTTERFLY_MOVING 23 #define SND_BD_BUTTERFLY_WAITING 24 #define SND_BD_FIREFLY_MOVING 25 #define SND_BD_FIREFLY_WAITING 26 #define SND_SP_BASE_DIGGING 27 #define SND_SP_BUGGY_BASE_DIGGING 28 #define SND_SP_BUGGY_BASE_ACTIVE 29 #define SND_SP_INFOTRON_COLLECTING 30 #define SND_SP_INFOTRON_IMPACT 31 #define SND_SP_ZONK_PUSHING 32 #define SND_SP_ZONK_IMPACT 33 #define SND_SP_DISK_RED_COLLECTING 34 #define SND_SP_DISK_ORANGE_PUSHING 35 #define SND_SP_DISK_YELLOW_PUSHING 36 #define SND_CLASS_SP_PORT_PASSING 37 #define SND_CLASS_SP_EXIT_PASSING 38 #define SND_CLASS_SP_EXIT_OPENING 39 #define SND_CLASS_SP_EXIT_CLOSING 40 #define SND_SP_SNIKSNAK_MOVING 41 #define SND_SP_SNIKSNAK_WAITING 42 #define SND_SP_ELECTRON_MOVING 43 #define SND_SP_ELECTRON_WAITING 44 #define SND_SP_TERMINAL_ACTIVATING 45 #define SND_SP_TERMINAL_ACTIVE 46 #define SND_CLASS_SOKOBAN_PUSHING 47 #define SND_CLASS_SOKOBAN_FILLING 48 #define SND_CLASS_SOKOBAN_EMPTYING 49 #define SND_CLASS_PLAYER_MOVING 50 #define SND_SAND_DIGGING 51 #define SND_CLASS_EMERALD_COLLECTING 52 #define SND_CLASS_EMERALD_IMPACT 53 #define SND_DIAMOND_COLLECTING 54 #define SND_DIAMOND_IMPACT 55 #define SND_DIAMOND_BREAKING 56 #define SND_ROCK_PUSHING 57 #define SND_ROCK_IMPACT 58 #define SND_BOMB_PUSHING 59 #define SND_NUT_PUSHING 60 #define SND_NUT_BREAKING 61 #define SND_NUT_IMPACT 62 #define SND_CLASS_DYNAMITE_COLLECTING 63 #define SND_CLASS_DYNAMITE_DROPPING 64 #define SND_CLASS_DYNAMITE_ACTIVE 65 #define SND_CLASS_KEY_COLLECTING 66 #define SND_CLASS_GATE_PASSING 67 #define SND_BUG_MOVING 68 #define SND_BUG_WAITING 69 #define SND_SPACESHIP_MOVING 70 #define SND_SPACESHIP_WAITING 71 #define SND_YAMYAM_MOVING 72 #define SND_YAMYAM_WAITING 73 #define SND_YAMYAM_DIGGING 74 #define SND_ROBOT_MOVING 75 #define SND_ROBOT_WAITING 76 #define SND_ROBOT_WHEEL_ACTIVATING 77 #define SND_ROBOT_WHEEL_ACTIVE 78 #define SND_MAGIC_WALL_ACTIVATING 79 #define SND_MAGIC_WALL_ACTIVE 80 #define SND_MAGIC_WALL_FILLING 81 #define SND_DC_MAGIC_WALL_ACTIVATING 82 #define SND_DC_MAGIC_WALL_ACTIVE 83 #define SND_DC_MAGIC_WALL_FILLING 84 #define SND_CLASS_AMOEBA_WAITING 85 #define SND_CLASS_AMOEBA_GROWING 86 #define SND_CLASS_AMOEBA_DROPPING 87 #define SND_ACID_SPLASHING 88 #define SND_CLASS_QUICKSAND_FILLING 89 #define SND_CLASS_QUICKSAND_EMPTYING 90 #define SND_CLASS_EXIT_OPENING 91 #define SND_CLASS_EXIT_CLOSING 92 #define SND_CLASS_EXIT_PASSING 93 #define SND_CLASS_STEEL_EXIT_OPENING 94 #define SND_CLASS_STEEL_EXIT_CLOSING 95 #define SND_CLASS_STEEL_EXIT_PASSING 96 #define SND_CLASS_EM_EXIT_OPENING 97 #define SND_CLASS_EM_EXIT_CLOSING 98 #define SND_CLASS_EM_EXIT_PASSING 99 #define SND_CLASS_EM_STEEL_EXIT_OPENING 100 #define SND_CLASS_EM_STEEL_EXIT_CLOSING 101 #define SND_CLASS_EM_STEEL_EXIT_PASSING 102 #define SND_PENGUIN_PASSING 103 #define SND_BALLOON_MOVING 104 #define SND_BALLOON_WAITING 105 #define SND_BALLOON_PUSHING 106 #define SND_CLASS_BALLOON_SWITCH_ACTIVATING 107 #define SND_SPRING_MOVING 108 #define SND_SPRING_PUSHING 109 #define SND_SPRING_IMPACT 110 #define SND_CLASS_WALL_GROWING 111 #define SND_EMC_ANDROID_PUSHING 112 #define SND_EMC_ANDROID_MOVING 113 #define SND_EMC_ANDROID_DROPPING 114 #define SND_EMC_MAGIC_BALL_DROPPING 115 #define SND_PEARL_COLLECTING 116 #define SND_PEARL_BREAKING 117 #define SND_PEARL_IMPACT 118 #define SND_CRYSTAL_COLLECTING 119 #define SND_CRYSTAL_IMPACT 120 #define SND_CLASS_ENVELOPE_COLLECTING 121 #define SND_CLASS_ENVELOPE_OPENING 122 #define SND_CLASS_ENVELOPE_CLOSING 123 #define SND_INVISIBLE_SAND_DIGGING 124 #define SND_INVISIBLE_SAND_ACTIVE_DIGGING 125 #define SND_SHIELD_NORMAL_COLLECTING 126 #define SND_SHIELD_NORMAL_ACTIVE 127 #define SND_SHIELD_DEADLY_COLLECTING 128 #define SND_SHIELD_DEADLY_ACTIVE 129 #define SND_EXTRA_TIME_COLLECTING 130 #define SND_MOLE_MOVING 131 #define SND_MOLE_WAITING 132 #define SND_MOLE_DIGGING 133 #define SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING 134 #define SND_CLASS_SWITCHGATE_OPENING 135 #define SND_CLASS_SWITCHGATE_CLOSING 136 #define SND_CLASS_SWITCHGATE_PASSING 137 #define SND_CLASS_TIMEGATE_SWITCH_ACTIVATING 138 #define SND_CLASS_TIMEGATE_SWITCH_ACTIVE 139 #define SND_CLASS_TIMEGATE_SWITCH_DEACTIVATING 140 #define SND_CLASS_TIMEGATE_OPENING 141 #define SND_CLASS_TIMEGATE_CLOSING 142 #define SND_CLASS_TIMEGATE_PASSING 143 #define SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING 144 #define SND_CLASS_CONVEYOR_BELT_ACTIVE 145 #define SND_CLASS_CONVEYOR_BELT_SWITCH_DEACTIVATING 146 #define SND_LIGHT_SWITCH_ACTIVATING 147 #define SND_LIGHT_SWITCH_DEACTIVATING 148 #define SND_DX_SUPABOMB_PUSHING 149 #define SND_TRAP_DIGGING 150 #define SND_TRAP_ACTIVATING 151 #define SND_CLASS_TUBE_WALKING 152 #define SND_AMOEBA_TURNING_TO_GEM 153 #define SND_AMOEBA_TURNING_TO_ROCK 154 #define SND_SPEED_PILL_COLLECTING 155 #define SND_DYNABOMB_INCREASE_NUMBER_COLLECTING 156 #define SND_DYNABOMB_INCREASE_SIZE_COLLECTING 157 #define SND_DYNABOMB_INCREASE_POWER_COLLECTING 158 #define SND_CLASS_DYNABOMB_DROPPING 159 #define SND_CLASS_DYNABOMB_ACTIVE 160 #define SND_SATELLITE_MOVING 161 #define SND_SATELLITE_WAITING 162 #define SND_SATELLITE_PUSHING 163 #define SND_LAMP_ACTIVATING 164 #define SND_LAMP_DEACTIVATING 165 #define SND_TIME_ORB_FULL_COLLECTING 166 #define SND_TIME_ORB_FULL_IMPACT 167 #define SND_TIME_ORB_EMPTY_PUSHING 168 #define SND_TIME_ORB_EMPTY_IMPACT 169 #define SND_GAME_OF_LIFE_WAITING 170 #define SND_GAME_OF_LIFE_GROWING 171 #define SND_BIOMAZE_WAITING 172 #define SND_BIOMAZE_GROWING 173 #define SND_PACMAN_MOVING 174 #define SND_PACMAN_WAITING 175 #define SND_PACMAN_DIGGING 176 #define SND_DARK_YAMYAM_MOVING 177 #define SND_DARK_YAMYAM_WAITING 178 #define SND_DARK_YAMYAM_DIGGING 179 #define SND_PENGUIN_MOVING 180 #define SND_PENGUIN_WAITING 181 #define SND_PIG_MOVING 182 #define SND_PIG_WAITING 183 #define SND_PIG_DIGGING 184 #define SND_DRAGON_MOVING 185 #define SND_DRAGON_WAITING 186 #define SND_DRAGON_ATTACKING 187 #define SND_CLASS_MM_MCDUFFIN_HITTING 188 #define SND_CLASS_MM_MIRROR_HITTING 189 #define SND_CLASS_MM_MIRROR_FIXED_HITTING 190 #define SND_CLASS_MM_PRISM_HITTING 191 #define SND_CLASS_MM_EXIT_HITTING 192 #define SND_CLASS_MM_EXIT_OPENING 193 #define SND_MM_EXIT_OPEN_HITTING 194 #define SND_CLASS_DF_MIRROR_HITTING 195 #define SND_CLASS_DF_MIRROR_ROTATING_HITTING 196 #define SND_CLASS_DF_REFRACTOR_HITTING 197 #define SND_CLASS_DF_RECEIVER_HITTING 198 #define SND_CLASS_DF_RECEIVER_OPENING 199 #define SND_CLASS_MM_WOODEN_WALL_HITTING 200 #define SND_CLASS_MM_WOODEN_BLOCK_HITTING 201 #define SND_CLASS_MM_WOODEN_BLOCK_PUSHING 202 #define SND_CLASS_MM_WOODEN_LOCK_HITTING 203 #define SND_CLASS_MM_WOODEN_GRID_FIXED_HITTING 204 #define SND_CLASS_MM_FUSE_HITTING 205 #define SND_CLASS_MM_ICE_WALL_HITTING 206 #define SND_CLASS_MM_ICE_WALL_SHRINKING 207 #define SND_CLASS_MM_AMOEBA_WALL_HITTING 208 #define SND_CLASS_MM_AMOEBA_WALL_GROWING 209 #define SND_CLASS_DF_WOODEN_WALL_HITTING 210 #define SND_CLASS_DF_WOODEN_GRID_FIXED_HITTING 211 #define SND_CLASS_DF_WOODEN_GRID_ROTATING_HITTING 212 #define SND_CLASS_MM_STEEL_WALL_HITTING 213 #define SND_CLASS_MM_STEEL_GRID_FIXED_HITTING 214 #define SND_CLASS_MM_STEEL_BLOCK_HITTING 215 #define SND_CLASS_MM_STEEL_BLOCK_PUSHING 216 #define SND_CLASS_MM_STEEL_LOCK_HITTING 217 #define SND_CLASS_DF_STEEL_WALL_HITTING 218 #define SND_CLASS_DF_STEEL_GRID_FIXED_HITTING 219 #define SND_CLASS_DF_STEEL_GRID_ROTATING_HITTING 220 #define SND_CLASS_MM_PACMAN_EXPLODING 221 #define SND_CLASS_MM_MCDUFFIN_EXPLODING 222 #define SND_CLASS_MM_BOMB_EXPLODING 223 #define SND_CLASS_MM_KEY_EXPLODING 224 #define SND_CLASS_MM_STEEL_LOCK_EXPLODING 225 #define SND_CLASS_MM_WOODEN_LOCK_EXPLODING 226 #define SND_GAME_STARTING 227 #define SND_GAME_LEVELTIME_CHARGING 228 #define SND_GAME_HEALTH_CHARGING 229 #define SND_GAME_RUNNING_OUT_OF_TIME 230 #define SND_GAME_LEVELTIME_BONUS 231 #define SND_GAME_HEALTH_BONUS 232 #define SND_GAME_LOSING 233 #define SND_GAME_WINNING 234 #define SND_GAME_SOKOBAN_SOLVING 235 #define SND_DOOR_OPENING 236 #define SND_DOOR_CLOSING 237 #define SND_DOOR_1_OPENING 238 #define SND_DOOR_1_CLOSING 239 #define SND_DOOR_2_OPENING 240 #define SND_DOOR_2_CLOSING 241 #define SND_REQUEST_OPENING 242 #define SND_REQUEST_CLOSING 243 #define SND_MENU_ITEM_ACTIVATING 244 #define SND_MENU_ITEM_SELECTING 245 #define SND_MENU_BUTTON_PRESSING 246 #define SND_MENU_BUTTON_RELEASING 247 #define SND_BACKGROUND_TITLE_INITIAL 248 #define SND_BACKGROUND_TITLE 249 #define SND_BACKGROUND_MAIN 250 #define SND_BACKGROUND_LEVELS 251 #define SND_BACKGROUND_LEVELNR 252 #define SND_BACKGROUND_SCORES 253 #define SND_BACKGROUND_EDITOR 254 #define SND_BACKGROUND_INFO 255 #define SND_BACKGROUND_SETUP 256 #define SND_BACKGROUND_TITLESCREEN_INITIAL_1 257 #define SND_BACKGROUND_TITLESCREEN_INITIAL_2 258 #define SND_BACKGROUND_TITLESCREEN_INITIAL_3 259 #define SND_BACKGROUND_TITLESCREEN_INITIAL_4 260 #define SND_BACKGROUND_TITLESCREEN_INITIAL_5 261 #define SND_BACKGROUND_TITLESCREEN_1 262 #define SND_BACKGROUND_TITLESCREEN_2 263 #define SND_BACKGROUND_TITLESCREEN_3 264 #define SND_BACKGROUND_TITLESCREEN_4 265 #define SND_BACKGROUND_TITLESCREEN_5 266 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 267 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_2 268 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_3 269 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_4 270 #define SND_BACKGROUND_TITLEMESSAGE_INITIAL_5 271 #define SND_BACKGROUND_TITLEMESSAGE_1 272 #define SND_BACKGROUND_TITLEMESSAGE_2 273 #define SND_BACKGROUND_TITLEMESSAGE_3 274 #define SND_BACKGROUND_TITLEMESSAGE_4 275 #define SND_BACKGROUND_TITLEMESSAGE_5 276 #define NUM_SOUND_FILES 277 #endif /* CONF_SND_H */ mirrormagic-3.0.0/src/conf_act.c0000644000175000017500000001646713263214151016056 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_act.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_ACT_C #define CONF_ACT_C /* values for active states of elements and fonts */ static struct { int element; int element_active; } element_with_active_state[] = { { EL_BD_MAGIC_WALL, EL_BD_MAGIC_WALL_ACTIVE }, { EL_CONVEYOR_BELT_1_LEFT, EL_CONVEYOR_BELT_1_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_1_MIDDLE, EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_1_RIGHT, EL_CONVEYOR_BELT_1_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_2_LEFT, EL_CONVEYOR_BELT_2_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_2_MIDDLE, EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_2_RIGHT, EL_CONVEYOR_BELT_2_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_3_LEFT, EL_CONVEYOR_BELT_3_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_3_MIDDLE, EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_3_RIGHT, EL_CONVEYOR_BELT_3_RIGHT_ACTIVE }, { EL_CONVEYOR_BELT_4_LEFT, EL_CONVEYOR_BELT_4_LEFT_ACTIVE }, { EL_CONVEYOR_BELT_4_MIDDLE, EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE }, { EL_CONVEYOR_BELT_4_RIGHT, EL_CONVEYOR_BELT_4_RIGHT_ACTIVE }, { EL_DC_GATE_WHITE_GRAY, EL_DC_GATE_WHITE_GRAY_ACTIVE }, { EL_DC_MAGIC_WALL, EL_DC_MAGIC_WALL_ACTIVE }, { EL_DC_TIMEGATE_SWITCH, EL_DC_TIMEGATE_SWITCH_ACTIVE }, { EL_DYNABOMB, EL_DYNABOMB_ACTIVE }, { EL_DYNABOMB_PLAYER_1, EL_DYNABOMB_PLAYER_1_ACTIVE }, { EL_DYNABOMB_PLAYER_2, EL_DYNABOMB_PLAYER_2_ACTIVE }, { EL_DYNABOMB_PLAYER_3, EL_DYNABOMB_PLAYER_3_ACTIVE }, { EL_DYNABOMB_PLAYER_4, EL_DYNABOMB_PLAYER_4_ACTIVE }, { EL_DYNAMITE, EL_DYNAMITE_ACTIVE }, { EL_EMC_DRIPPER, EL_EMC_DRIPPER_ACTIVE }, { EL_EMC_FAKE_GRASS, EL_EMC_FAKE_GRASS_ACTIVE }, { EL_EMC_GATE_5_GRAY, EL_EMC_GATE_5_GRAY_ACTIVE }, { EL_EMC_GATE_6_GRAY, EL_EMC_GATE_6_GRAY_ACTIVE }, { EL_EMC_GATE_7_GRAY, EL_EMC_GATE_7_GRAY_ACTIVE }, { EL_EMC_GATE_8_GRAY, EL_EMC_GATE_8_GRAY_ACTIVE }, { EL_EMC_MAGIC_BALL, EL_EMC_MAGIC_BALL_ACTIVE }, { EL_EMC_MAGIC_BALL_SWITCH, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE }, { EL_EMC_SPRING_BUMPER, EL_EMC_SPRING_BUMPER_ACTIVE }, { EL_EM_DYNAMITE, EL_EM_DYNAMITE_ACTIVE }, { EL_EM_GATE_1_GRAY, EL_EM_GATE_1_GRAY_ACTIVE }, { EL_EM_GATE_2_GRAY, EL_EM_GATE_2_GRAY_ACTIVE }, { EL_EM_GATE_3_GRAY, EL_EM_GATE_3_GRAY_ACTIVE }, { EL_EM_GATE_4_GRAY, EL_EM_GATE_4_GRAY_ACTIVE }, { EL_GATE_1_GRAY, EL_GATE_1_GRAY_ACTIVE }, { EL_GATE_2_GRAY, EL_GATE_2_GRAY_ACTIVE }, { EL_GATE_3_GRAY, EL_GATE_3_GRAY_ACTIVE }, { EL_GATE_4_GRAY, EL_GATE_4_GRAY_ACTIVE }, { EL_INTERNAL_CASCADE_BD, EL_INTERNAL_CASCADE_BD_ACTIVE }, { EL_INTERNAL_CASCADE_CE, EL_INTERNAL_CASCADE_CE_ACTIVE }, { EL_INTERNAL_CASCADE_CHARS, EL_INTERNAL_CASCADE_CHARS_ACTIVE }, { EL_INTERNAL_CASCADE_DC, EL_INTERNAL_CASCADE_DC_ACTIVE }, { EL_INTERNAL_CASCADE_DF, EL_INTERNAL_CASCADE_DF_ACTIVE }, { EL_INTERNAL_CASCADE_DX, EL_INTERNAL_CASCADE_DX_ACTIVE }, { EL_INTERNAL_CASCADE_DYNAMIC, EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE }, { EL_INTERNAL_CASCADE_EM, EL_INTERNAL_CASCADE_EM_ACTIVE }, { EL_INTERNAL_CASCADE_EMC, EL_INTERNAL_CASCADE_EMC_ACTIVE }, { EL_INTERNAL_CASCADE_GE, EL_INTERNAL_CASCADE_GE_ACTIVE }, { EL_INTERNAL_CASCADE_MM, EL_INTERNAL_CASCADE_MM_ACTIVE }, { EL_INTERNAL_CASCADE_REF, EL_INTERNAL_CASCADE_REF_ACTIVE }, { EL_INTERNAL_CASCADE_RND, EL_INTERNAL_CASCADE_RND_ACTIVE }, { EL_INTERNAL_CASCADE_SB, EL_INTERNAL_CASCADE_SB_ACTIVE }, { EL_INTERNAL_CASCADE_SP, EL_INTERNAL_CASCADE_SP_ACTIVE }, { EL_INTERNAL_CASCADE_STEEL_CHARS, EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE }, { EL_INTERNAL_CASCADE_USER, EL_INTERNAL_CASCADE_USER_ACTIVE }, { EL_INVISIBLE_SAND, EL_INVISIBLE_SAND_ACTIVE }, { EL_INVISIBLE_STEELWALL, EL_INVISIBLE_STEELWALL_ACTIVE }, { EL_INVISIBLE_WALL, EL_INVISIBLE_WALL_ACTIVE }, { EL_LAMP, EL_LAMP_ACTIVE }, { EL_LIGHT_SWITCH, EL_LIGHT_SWITCH_ACTIVE }, { EL_MAGIC_WALL, EL_MAGIC_WALL_ACTIVE }, { EL_MM_FUSE, EL_MM_FUSE_ACTIVE }, { EL_MM_LIGHTBULB, EL_MM_LIGHTBULB_ACTIVE }, { EL_ROBOT_WHEEL, EL_ROBOT_WHEEL_ACTIVE }, { EL_SHIELD_DEADLY, EL_SHIELD_DEADLY_ACTIVE }, { EL_SHIELD_NORMAL, EL_SHIELD_NORMAL_ACTIVE }, { EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVE }, { EL_SP_DISK_RED, EL_SP_DISK_RED_ACTIVE }, { EL_SP_TERMINAL, EL_SP_TERMINAL_ACTIVE }, { EL_TIMEGATE_SWITCH, EL_TIMEGATE_SWITCH_ACTIVE }, { EL_TRAP, EL_TRAP_ACTIVE }, { -1, -1 }, }; static struct { int button; int button_active; } button_with_active_state[] = { { IMG_MENU_BUTTON, IMG_MENU_BUTTON_ACTIVE }, { IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE }, { IMG_MENU_BUTTON_EDITOR, IMG_MENU_BUTTON_EDITOR_ACTIVE }, { IMG_MENU_BUTTON_ENTER_MENU, IMG_MENU_BUTTON_ENTER_MENU_ACTIVE }, { IMG_MENU_BUTTON_GAME, IMG_MENU_BUTTON_GAME_ACTIVE }, { IMG_MENU_BUTTON_INFO, IMG_MENU_BUTTON_INFO_ACTIVE }, { IMG_MENU_BUTTON_LEAVE_MENU, IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE }, { IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE }, { IMG_MENU_BUTTON_LEVELS, IMG_MENU_BUTTON_LEVELS_ACTIVE }, { IMG_MENU_BUTTON_NAME, IMG_MENU_BUTTON_NAME_ACTIVE }, { IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE }, { IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE }, { IMG_MENU_BUTTON_QUIT, IMG_MENU_BUTTON_QUIT_ACTIVE }, { IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE }, { IMG_MENU_BUTTON_SCORES, IMG_MENU_BUTTON_SCORES_ACTIVE }, { IMG_MENU_BUTTON_SETUP, IMG_MENU_BUTTON_SETUP_ACTIVE }, { IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE }, { -1, -1 }, }; static struct { int font_nr; int font_nr_active; } font_with_active_state[] = { { FONT_INPUT_1, FONT_INPUT_1_ACTIVE }, { FONT_INPUT_2, FONT_INPUT_2_ACTIVE }, { FONT_LEVEL_NUMBER, FONT_LEVEL_NUMBER_ACTIVE }, { FONT_MENU_1, FONT_MENU_1_ACTIVE }, { FONT_MENU_2, FONT_MENU_2_ACTIVE }, { FONT_TEXT_1, FONT_TEXT_1_ACTIVE }, { FONT_TEXT_2, FONT_TEXT_2_ACTIVE }, { FONT_TEXT_3, FONT_TEXT_3_ACTIVE }, { FONT_TEXT_4, FONT_TEXT_4_ACTIVE }, { -1, -1 }, }; #endif /* CONF_ACT_C */ mirrormagic-3.0.0/src/game.h0000644000175000017500000002723113263212010015177 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // game.h // ============================================================================ #ifndef GAME_H #define GAME_H /* (not included here due to collisions with Emerald Mine engine definitions) */ /* #include "main.h" */ #define MAX_INVENTORY_SIZE 1000 #define MAX_HEALTH 100 #define STD_NUM_KEYS 4 #define MAX_NUM_KEYS 8 #define NUM_BELTS 4 #define NUM_BELT_PARTS 3 #define NUM_PANEL_INVENTORY 8 #define NUM_PANEL_GRAPHICS 8 #define NUM_PANEL_ELEMENTS 8 #define NUM_PANEL_CE_SCORE 8 #define STR_SNAPSHOT_MODE_OFF "off" #define STR_SNAPSHOT_MODE_EVERY_STEP "every_step" #define STR_SNAPSHOT_MODE_EVERY_MOVE "every_move" #define STR_SNAPSHOT_MODE_EVERY_COLLECT "every_collect" #define STR_SNAPSHOT_MODE_DEFAULT STR_SNAPSHOT_MODE_OFF #define SNAPSHOT_MODE_OFF 0 #define SNAPSHOT_MODE_EVERY_STEP 1 #define SNAPSHOT_MODE_EVERY_MOVE 2 #define SNAPSHOT_MODE_EVERY_COLLECT 3 #define SNAPSHOT_MODE_DEFAULT SNAPSHOT_MODE_OFF struct GamePanelInfo { struct TextPosInfo level_number; struct TextPosInfo gems; struct TextPosInfo inventory_count; struct TextPosInfo inventory_first[NUM_PANEL_INVENTORY]; struct TextPosInfo inventory_last[NUM_PANEL_INVENTORY]; struct TextPosInfo key[MAX_NUM_KEYS]; struct TextPosInfo key_white; struct TextPosInfo key_white_count; struct TextPosInfo score; struct TextPosInfo highscore; struct TextPosInfo time; struct TextPosInfo time_hh; struct TextPosInfo time_mm; struct TextPosInfo time_ss; struct TextPosInfo time_anim; struct TextPosInfo health; struct TextPosInfo health_anim; struct TextPosInfo frame; struct TextPosInfo shield_normal; struct TextPosInfo shield_normal_time; struct TextPosInfo shield_deadly; struct TextPosInfo shield_deadly_time; struct TextPosInfo exit; struct TextPosInfo emc_magic_ball; struct TextPosInfo emc_magic_ball_switch; struct TextPosInfo light_switch; struct TextPosInfo light_switch_time; struct TextPosInfo timegate_switch; struct TextPosInfo timegate_switch_time; struct TextPosInfo switchgate_switch; struct TextPosInfo emc_lenses; struct TextPosInfo emc_lenses_time; struct TextPosInfo emc_magnifier; struct TextPosInfo emc_magnifier_time; struct TextPosInfo balloon_switch; struct TextPosInfo dynabomb_number; struct TextPosInfo dynabomb_size; struct TextPosInfo dynabomb_power; struct TextPosInfo penguins; struct TextPosInfo sokoban_objects; struct TextPosInfo sokoban_fields; struct TextPosInfo robot_wheel; struct TextPosInfo conveyor_belt[NUM_BELTS]; struct TextPosInfo conveyor_belt_switch[NUM_BELTS]; struct TextPosInfo magic_wall; struct TextPosInfo magic_wall_time; struct TextPosInfo gravity_state; struct TextPosInfo graphic[NUM_PANEL_GRAPHICS]; struct TextPosInfo element[NUM_PANEL_ELEMENTS]; struct TextPosInfo element_count[NUM_PANEL_ELEMENTS]; struct TextPosInfo ce_score[NUM_PANEL_CE_SCORE]; struct TextPosInfo ce_score_element[NUM_PANEL_CE_SCORE]; struct TextPosInfo player_name; struct TextPosInfo level_name; struct TextPosInfo level_author; }; struct GameButtonInfo { struct XY stop; struct XY pause; struct XY play; struct XY undo; struct XY redo; struct XY save; struct XY pause2; struct XY load; struct XY sound_music; struct XY sound_loops; struct XY sound_simple; struct XY panel_stop; struct XY panel_pause; struct XY panel_play; struct XY panel_sound_music; struct XY panel_sound_loops; struct XY panel_sound_simple; }; struct GameSnapshotInfo { int mode; byte last_action[MAX_PLAYERS]; boolean changed_action; boolean collected_item; boolean save_snapshot; }; struct GameInfo { /* values for control panel */ struct GamePanelInfo panel; struct GameButtonInfo button; /* values for graphics engine customization */ int graphics_engine_version; boolean use_native_emc_graphics_engine; boolean use_native_sp_graphics_engine; boolean use_masked_pushing; int forced_scroll_delay_value; int scroll_delay_value; int tile_size; /* values for engine initialization */ int default_push_delay_fixed; int default_push_delay_random; /* constant within running game */ int engine_version; int emulation; int initial_move_delay[MAX_PLAYERS]; int initial_move_delay_value[MAX_PLAYERS]; int initial_push_delay_value; /* flag for single or multi-player mode (needed for playing tapes) */ /* (when playing/recording games, this is identical to "setup.team_mode" */ boolean team_mode; /* flags to handle bugs in and changes between different engine versions */ /* (for the latest engine version, these flags should always be "FALSE") */ boolean use_change_when_pushing_bug; boolean use_block_last_field_bug; boolean max_num_changes_per_frame; boolean use_reverse_scan_direction; /* variable within running game */ int yamyam_content_nr; boolean robot_wheel_active; boolean magic_wall_active; int magic_wall_time_left; int light_time_left; int timegate_time_left; int belt_dir[4]; int belt_dir_nr[4]; int switchgate_pos; int wind_direction; boolean gravity; boolean explosions_delayed; boolean envelope_active; boolean no_time_limit; /* (variable only in very special case) */ /* values for the new EMC elements */ int lenses_time_left; int magnify_time_left; boolean ball_state; int ball_content_nr; /* values for player idle animation (no effect on engine) */ int player_boring_delay_fixed; int player_boring_delay_random; int player_sleeping_delay_fixed; int player_sleeping_delay_random; /* values for special game initialization control */ boolean restart_level; /* trigger message to ask for restarting the game */ char *restart_game_message; /* values for special game control */ int centered_player_nr; int centered_player_nr_next; boolean set_centered_player; /* values for random number generator initialization after snapshot */ unsigned int num_random_calls; /* values for game engine snapshot control */ struct GameSnapshotInfo snapshot; }; struct PlayerInfo { boolean present; /* player present in level playfield */ boolean connected; /* player connected (locally or via network) */ boolean active; /* player present and connected */ boolean mapped; /* player already mapped to input device */ boolean killed; /* player maybe present/active, but killed */ boolean reanimated; /* player maybe killed, but reanimated */ int index_nr; /* player number (0 to 3) */ int index_bit; /* player number bit (1 << 0 to 1 << 3) */ int element_nr; /* element (EL_PLAYER_1 to EL_PLAYER_4) */ int client_nr; /* network client identifier */ byte action; /* action from local input device */ byte mapped_action; /* action mapped from device to player */ byte effective_action; /* action acknowledged from network server or summarized over all configured input devices when in single player mode */ byte programmed_action; /* action forced by game itself (like moving through doors); overrides other actions */ struct MouseActionInfo mouse_action; /* (used by MM engine only) */ struct MouseActionInfo effective_mouse_action; /* (used by MM engine only) */ int jx, jy, last_jx, last_jy; int MovDir, MovPos, GfxDir, GfxPos; int Frame, StepFrame; int GfxAction; int initial_element; /* EL_PLAYER_1 to EL_PLAYER_4 or EL_SP_MURPHY */ int artwork_element; boolean use_murphy; boolean block_last_field; int block_delay_adjustment; /* needed for different engine versions */ boolean can_fall_into_acid; boolean gravity; boolean LevelSolved, GameOver; boolean LevelSolved_GameWon; boolean LevelSolved_GameEnd; boolean LevelSolved_PanelOff; boolean LevelSolved_SaveTape; boolean LevelSolved_SaveScore; int LevelSolved_CountingTime; int LevelSolved_CountingScore; int LevelSolved_CountingHealth; int last_move_dir; boolean is_active; boolean is_waiting; boolean is_moving; boolean is_auto_moving; boolean is_digging; boolean is_snapping; boolean is_collecting; boolean is_pushing; boolean is_switching; boolean is_dropping; boolean is_dropping_pressed; boolean is_bored; boolean is_sleeping; boolean was_waiting; boolean was_moving; boolean was_snapping; boolean was_dropping; boolean cannot_move; boolean force_dropping; /* needed for single step mode */ int frame_counter_bored; int frame_counter_sleeping; int anim_delay_counter; int post_delay_counter; int dir_waiting; int action_waiting, last_action_waiting; int special_action_bored; int special_action_sleeping; int num_special_action_bored; int num_special_action_sleeping; int switch_x, switch_y; int drop_x, drop_y; int show_envelope; int move_delay; int move_delay_value; int move_delay_value_next; int move_delay_reset_counter; int push_delay; int push_delay_value; unsigned int actual_frame_counter; int drop_delay; int drop_pressed_delay; int step_counter; int score; int score_final; int health; int health_final; int gems_still_needed; int sokobanfields_still_needed; int lights_still_needed; int friends_still_needed; int key[MAX_NUM_KEYS]; int num_white_keys; int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl; int shield_normal_time_left; int shield_deadly_time_left; int inventory_element[MAX_INVENTORY_SIZE]; int inventory_infinite_element; int inventory_size; }; extern struct GameInfo game; extern struct PlayerInfo stored_player[MAX_PLAYERS], *local_player; #ifdef DEBUG void DEBUG_SetMaximumDynamite(); #endif void GetPlayerConfig(void); int GetElementFromGroupElement(int); int getPlayerInventorySize(int); void DrawGameValue_Time(int); void DrawGameDoorValues(void); void UpdateAndDisplayGameControlValues(); void InitGameSound(); void InitGame(); void UpdateEngineValues(int, int, int, int); void GameWon(void); void GameEnd(void); void InitPlayerGfxAnimation(struct PlayerInfo *, int, int); void Moving2Blocked(int, int, int *, int *); void Blocked2Moving(int, int, int *, int *); void DrawDynamite(int, int); void StartGameActions(boolean, boolean, int); void GameActions(void); void GameActions_EM_Main(); void GameActions_SP_Main(); void GameActions_MM_Main(); void GameActions_RND_Main(); void GameActions_RND(); void ScrollLevel(int, int); void InitPlayLevelSound(); void PlayLevelSound_EM(int, int, int, int); void PlayLevelSound_SP(int, int, int, int); void PlayLevelSound_MM(int, int, int, int); void PlaySound_MM(int); void PlaySoundLoop_MM(int); void StopSound_MM(int); void RaiseScore(int); void RaiseScoreElement(int); void RequestQuitGameExt(boolean, boolean, char *); void RequestQuitGame(boolean); void RequestRestartGame(char *); unsigned int InitEngineRandom_RND(int); unsigned int RND(int); void FreeEngineSnapshotSingle(); void FreeEngineSnapshotList(); void LoadEngineSnapshotSingle(); void SaveEngineSnapshotSingle(); boolean CheckSaveEngineSnapshotToList(); void SaveEngineSnapshotToList(); void SaveEngineSnapshotToListInitial(); boolean CheckEngineSnapshotSingle(); boolean CheckEngineSnapshotList(); void CreateGameButtons(); void FreeGameButtons(); void MapUndoRedoButtons(); void UnmapUndoRedoButtons(); void MapGameButtons(); void UnmapGameButtons(); void RedrawGameButtons(); void MapGameButtonsOnTape(); void UnmapGameButtonsOnTape(); void RedrawGameButtonsOnTape(); void HandleSoundButtonKeys(Key); #endif mirrormagic-3.0.0/src/conf_mus.c0000644000175000017500000000544713263212010016077 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_mus.c // ============================================================================ #include "libgame/libgame.h" #include "main.h" /* List values that are not defined in the configuration file are set to reliable default values. If that value is MUS_ARG_UNDEFINED, it will be dynamically determined, using some of the other list values. */ struct ConfigTypeInfo music_config_suffix[] = { { ".mode_loop", ARG_UNDEFINED, TYPE_BOOLEAN }, { NULL, NULL, 0 } }; struct ConfigInfo music_config[] = { { "background", UNDEFINED_FILENAME }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, { "background.MAIN", UNDEFINED_FILENAME }, { "background.LEVELS", UNDEFINED_FILENAME }, { "background.LEVELNR", UNDEFINED_FILENAME }, { "background.SCORES", UNDEFINED_FILENAME }, { "background.EDITOR", UNDEFINED_FILENAME }, { "background.INFO", "rhythmloop.wav" }, { "background.SETUP", UNDEFINED_FILENAME }, { "background.titlescreen_initial_1", UNDEFINED_FILENAME }, { "background.titlescreen_initial_2", UNDEFINED_FILENAME }, { "background.titlescreen_initial_3", UNDEFINED_FILENAME }, { "background.titlescreen_initial_4", UNDEFINED_FILENAME }, { "background.titlescreen_initial_5", UNDEFINED_FILENAME }, { "background.titlescreen_1", UNDEFINED_FILENAME }, { "background.titlescreen_2", UNDEFINED_FILENAME }, { "background.titlescreen_3", UNDEFINED_FILENAME }, { "background.titlescreen_4", UNDEFINED_FILENAME }, { "background.titlescreen_5", UNDEFINED_FILENAME }, { "background.titlemessage_initial_1",UNDEFINED_FILENAME }, { "background.titlemessage_initial_2",UNDEFINED_FILENAME }, { "background.titlemessage_initial_3",UNDEFINED_FILENAME }, { "background.titlemessage_initial_4",UNDEFINED_FILENAME }, { "background.titlemessage_initial_5",UNDEFINED_FILENAME }, { "background.titlemessage_1", UNDEFINED_FILENAME }, { "background.titlemessage_2", UNDEFINED_FILENAME }, { "background.titlemessage_3", UNDEFINED_FILENAME }, { "background.titlemessage_4", UNDEFINED_FILENAME }, { "background.titlemessage_5", UNDEFINED_FILENAME }, /* there is no definition for "background.PLAYING", because this would prevent selecting music from music directory that is not defined in "musicinfo.conf", when no default music is defined here */ { NULL, NULL } }; mirrormagic-3.0.0/src/events.h0000644000175000017500000000274713263212010015577 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // events.h // ============================================================================ #ifndef EVENTS_H #define EVENTS_H #include "main.h" boolean NextValidEvent(Event *); void EventLoop(void); void HandleOtherEvents(Event *); void ClearEventQueue(void); void ClearPlayerAction(void); void SleepWhileUnmapped(void); void HandleExposeEvent(ExposeEvent *); void HandleButtonEvent(ButtonEvent *); void HandleMotionEvent(MotionEvent *); #if defined(TARGET_SDL2) void HandleWheelEvent(WheelEvent *); void HandleWindowEvent(WindowEvent *); void HandleFingerEvent(FingerEvent *); void HandleTextEvent(TextEvent *); void HandlePauseResumeEvent(PauseResumeEvent *); #endif void HandleKeysDebug(Key); void HandleKeyEvent(KeyEvent *); void HandleFocusEvent(FocusChangeEvent *); void HandleClientMessageEvent(ClientMessageEvent *); void HandleWindowManagerEvent(Event *); void HandleToonAnimations(void); void HandleButton(int, int, int, int); void HandleKey(Key, int); void HandleJoystick(); void HandleSpecialGameControllerButtons(Event *); void HandleSpecialGameControllerKeys(Key, int); #endif mirrormagic-3.0.0/src/conf_grp.c0000644000175000017500000002172113263214151016064 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_grp.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_GRP_C #define CONF_GRP_C /* values for graphics configuration (group elements) */ { "group_1", "RocksCE.png" }, { "group_1.xpos", "0" }, { "group_1.ypos", "16" }, { "group_1.frames", "1" }, { "group_1.EDITOR", "RocksCE.png" }, { "group_1.EDITOR.xpos", "16" }, { "group_1.EDITOR.ypos", "16" }, { "group_2", "RocksCE.png" }, { "group_2.xpos", "1" }, { "group_2.ypos", "16" }, { "group_2.frames", "1" }, { "group_2.EDITOR", "RocksCE.png" }, { "group_2.EDITOR.xpos", "17" }, { "group_2.EDITOR.ypos", "16" }, { "group_3", "RocksCE.png" }, { "group_3.xpos", "2" }, { "group_3.ypos", "16" }, { "group_3.frames", "1" }, { "group_3.EDITOR", "RocksCE.png" }, { "group_3.EDITOR.xpos", "18" }, { "group_3.EDITOR.ypos", "16" }, { "group_4", "RocksCE.png" }, { "group_4.xpos", "3" }, { "group_4.ypos", "16" }, { "group_4.frames", "1" }, { "group_4.EDITOR", "RocksCE.png" }, { "group_4.EDITOR.xpos", "19" }, { "group_4.EDITOR.ypos", "16" }, { "group_5", "RocksCE.png" }, { "group_5.xpos", "4" }, { "group_5.ypos", "16" }, { "group_5.frames", "1" }, { "group_5.EDITOR", "RocksCE.png" }, { "group_5.EDITOR.xpos", "20" }, { "group_5.EDITOR.ypos", "16" }, { "group_6", "RocksCE.png" }, { "group_6.xpos", "5" }, { "group_6.ypos", "16" }, { "group_6.frames", "1" }, { "group_6.EDITOR", "RocksCE.png" }, { "group_6.EDITOR.xpos", "21" }, { "group_6.EDITOR.ypos", "16" }, { "group_7", "RocksCE.png" }, { "group_7.xpos", "6" }, { "group_7.ypos", "16" }, { "group_7.frames", "1" }, { "group_7.EDITOR", "RocksCE.png" }, { "group_7.EDITOR.xpos", "22" }, { "group_7.EDITOR.ypos", "16" }, { "group_8", "RocksCE.png" }, { "group_8.xpos", "7" }, { "group_8.ypos", "16" }, { "group_8.frames", "1" }, { "group_8.EDITOR", "RocksCE.png" }, { "group_8.EDITOR.xpos", "23" }, { "group_8.EDITOR.ypos", "16" }, { "group_9", "RocksCE.png" }, { "group_9.xpos", "8" }, { "group_9.ypos", "16" }, { "group_9.frames", "1" }, { "group_9.EDITOR", "RocksCE.png" }, { "group_9.EDITOR.xpos", "24" }, { "group_9.EDITOR.ypos", "16" }, { "group_10", "RocksCE.png" }, { "group_10.xpos", "9" }, { "group_10.ypos", "16" }, { "group_10.frames", "1" }, { "group_10.EDITOR", "RocksCE.png" }, { "group_10.EDITOR.xpos", "25" }, { "group_10.EDITOR.ypos", "16" }, { "group_11", "RocksCE.png" }, { "group_11.xpos", "10" }, { "group_11.ypos", "16" }, { "group_11.frames", "1" }, { "group_11.EDITOR", "RocksCE.png" }, { "group_11.EDITOR.xpos", "26" }, { "group_11.EDITOR.ypos", "16" }, { "group_12", "RocksCE.png" }, { "group_12.xpos", "11" }, { "group_12.ypos", "16" }, { "group_12.frames", "1" }, { "group_12.EDITOR", "RocksCE.png" }, { "group_12.EDITOR.xpos", "27" }, { "group_12.EDITOR.ypos", "16" }, { "group_13", "RocksCE.png" }, { "group_13.xpos", "12" }, { "group_13.ypos", "16" }, { "group_13.frames", "1" }, { "group_13.EDITOR", "RocksCE.png" }, { "group_13.EDITOR.xpos", "28" }, { "group_13.EDITOR.ypos", "16" }, { "group_14", "RocksCE.png" }, { "group_14.xpos", "13" }, { "group_14.ypos", "16" }, { "group_14.frames", "1" }, { "group_14.EDITOR", "RocksCE.png" }, { "group_14.EDITOR.xpos", "29" }, { "group_14.EDITOR.ypos", "16" }, { "group_15", "RocksCE.png" }, { "group_15.xpos", "14" }, { "group_15.ypos", "16" }, { "group_15.frames", "1" }, { "group_15.EDITOR", "RocksCE.png" }, { "group_15.EDITOR.xpos", "30" }, { "group_15.EDITOR.ypos", "16" }, { "group_16", "RocksCE.png" }, { "group_16.xpos", "15" }, { "group_16.ypos", "16" }, { "group_16.frames", "1" }, { "group_16.EDITOR", "RocksCE.png" }, { "group_16.EDITOR.xpos", "31" }, { "group_16.EDITOR.ypos", "16" }, { "group_17", "RocksCE.png" }, { "group_17.xpos", "0" }, { "group_17.ypos", "17" }, { "group_17.frames", "1" }, { "group_17.EDITOR", "RocksCE.png" }, { "group_17.EDITOR.xpos", "16" }, { "group_17.EDITOR.ypos", "17" }, { "group_18", "RocksCE.png" }, { "group_18.xpos", "1" }, { "group_18.ypos", "17" }, { "group_18.frames", "1" }, { "group_18.EDITOR", "RocksCE.png" }, { "group_18.EDITOR.xpos", "17" }, { "group_18.EDITOR.ypos", "17" }, { "group_19", "RocksCE.png" }, { "group_19.xpos", "2" }, { "group_19.ypos", "17" }, { "group_19.frames", "1" }, { "group_19.EDITOR", "RocksCE.png" }, { "group_19.EDITOR.xpos", "18" }, { "group_19.EDITOR.ypos", "17" }, { "group_20", "RocksCE.png" }, { "group_20.xpos", "3" }, { "group_20.ypos", "17" }, { "group_20.frames", "1" }, { "group_20.EDITOR", "RocksCE.png" }, { "group_20.EDITOR.xpos", "19" }, { "group_20.EDITOR.ypos", "17" }, { "group_21", "RocksCE.png" }, { "group_21.xpos", "4" }, { "group_21.ypos", "17" }, { "group_21.frames", "1" }, { "group_21.EDITOR", "RocksCE.png" }, { "group_21.EDITOR.xpos", "20" }, { "group_21.EDITOR.ypos", "17" }, { "group_22", "RocksCE.png" }, { "group_22.xpos", "5" }, { "group_22.ypos", "17" }, { "group_22.frames", "1" }, { "group_22.EDITOR", "RocksCE.png" }, { "group_22.EDITOR.xpos", "21" }, { "group_22.EDITOR.ypos", "17" }, { "group_23", "RocksCE.png" }, { "group_23.xpos", "6" }, { "group_23.ypos", "17" }, { "group_23.frames", "1" }, { "group_23.EDITOR", "RocksCE.png" }, { "group_23.EDITOR.xpos", "22" }, { "group_23.EDITOR.ypos", "17" }, { "group_24", "RocksCE.png" }, { "group_24.xpos", "7" }, { "group_24.ypos", "17" }, { "group_24.frames", "1" }, { "group_24.EDITOR", "RocksCE.png" }, { "group_24.EDITOR.xpos", "23" }, { "group_24.EDITOR.ypos", "17" }, { "group_25", "RocksCE.png" }, { "group_25.xpos", "8" }, { "group_25.ypos", "17" }, { "group_25.frames", "1" }, { "group_25.EDITOR", "RocksCE.png" }, { "group_25.EDITOR.xpos", "24" }, { "group_25.EDITOR.ypos", "17" }, { "group_26", "RocksCE.png" }, { "group_26.xpos", "9" }, { "group_26.ypos", "17" }, { "group_26.frames", "1" }, { "group_26.EDITOR", "RocksCE.png" }, { "group_26.EDITOR.xpos", "25" }, { "group_26.EDITOR.ypos", "17" }, { "group_27", "RocksCE.png" }, { "group_27.xpos", "10" }, { "group_27.ypos", "17" }, { "group_27.frames", "1" }, { "group_27.EDITOR", "RocksCE.png" }, { "group_27.EDITOR.xpos", "26" }, { "group_27.EDITOR.ypos", "17" }, { "group_28", "RocksCE.png" }, { "group_28.xpos", "11" }, { "group_28.ypos", "17" }, { "group_28.frames", "1" }, { "group_28.EDITOR", "RocksCE.png" }, { "group_28.EDITOR.xpos", "27" }, { "group_28.EDITOR.ypos", "17" }, { "group_29", "RocksCE.png" }, { "group_29.xpos", "12" }, { "group_29.ypos", "17" }, { "group_29.frames", "1" }, { "group_29.EDITOR", "RocksCE.png" }, { "group_29.EDITOR.xpos", "28" }, { "group_29.EDITOR.ypos", "17" }, { "group_30", "RocksCE.png" }, { "group_30.xpos", "13" }, { "group_30.ypos", "17" }, { "group_30.frames", "1" }, { "group_30.EDITOR", "RocksCE.png" }, { "group_30.EDITOR.xpos", "29" }, { "group_30.EDITOR.ypos", "17" }, { "group_31", "RocksCE.png" }, { "group_31.xpos", "14" }, { "group_31.ypos", "17" }, { "group_31.frames", "1" }, { "group_31.EDITOR", "RocksCE.png" }, { "group_31.EDITOR.xpos", "30" }, { "group_31.EDITOR.ypos", "17" }, { "group_32", "RocksCE.png" }, { "group_32.xpos", "15" }, { "group_32.ypos", "17" }, { "group_32.frames", "1" }, { "group_32.EDITOR", "RocksCE.png" }, { "group_32.EDITOR.xpos", "31" }, { "group_32.EDITOR.ypos", "17" }, #endif /* CONF_GRP_C */ mirrormagic-3.0.0/src/conf_fnt.c0000644000175000017500000001314213263214151016061 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_fnt.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_FNT_C #define CONF_FNT_C /* values for font/graphics mapping configuration */ static struct { int font_nr; int special; int graphic; } font_to_graphic[] = { { FONT_INITIAL_1, -1, IMG_FONT_INITIAL_1 }, { FONT_INITIAL_2, -1, IMG_FONT_INITIAL_2 }, { FONT_INITIAL_3, -1, IMG_FONT_INITIAL_3 }, { FONT_INITIAL_4, -1, IMG_FONT_INITIAL_4 }, { FONT_TITLE_1, -1, IMG_FONT_TITLE_1 }, { FONT_TITLE_2, -1, IMG_FONT_TITLE_2 }, { FONT_TITLE_2, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TITLE_2_SETUP }, { FONT_MENU_1, -1, IMG_FONT_MENU_1 }, { FONT_MENU_1_ACTIVE, -1, IMG_FONT_MENU_1_ACTIVE }, { FONT_MENU_2, -1, IMG_FONT_MENU_2 }, { FONT_MENU_2_ACTIVE, -1, IMG_FONT_MENU_2_ACTIVE }, { FONT_TEXT_1, -1, IMG_FONT_TEXT_1 }, { FONT_TEXT_1, GFX_SPECIAL_ARG_MAIN, IMG_FONT_TEXT_1_MAIN }, { FONT_TEXT_1, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_1_LEVELS }, { FONT_TEXT_1, GFX_SPECIAL_ARG_LEVELNR, IMG_FONT_TEXT_1_LEVELNR }, { FONT_TEXT_1, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_1_SETUP }, { FONT_TEXT_1, GFX_SPECIAL_ARG_PREVIEW, IMG_FONT_TEXT_1_PREVIEW }, { FONT_TEXT_1, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_1_SCORES }, { FONT_TEXT_1_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_1_ACTIVE_SCORES }, { FONT_TEXT_1, GFX_SPECIAL_ARG_PANEL, IMG_FONT_TEXT_1_PANEL }, { FONT_TEXT_1, GFX_SPECIAL_ARG_DOOR, IMG_FONT_TEXT_1_DOOR }, { FONT_TEXT_2, -1, IMG_FONT_TEXT_2 }, { FONT_TEXT_2, GFX_SPECIAL_ARG_MAIN, IMG_FONT_TEXT_2_MAIN }, { FONT_TEXT_2, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_2_LEVELS }, { FONT_TEXT_2, GFX_SPECIAL_ARG_LEVELNR, IMG_FONT_TEXT_2_LEVELNR }, { FONT_TEXT_2, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_2_SETUP }, { FONT_TEXT_2, GFX_SPECIAL_ARG_PREVIEW, IMG_FONT_TEXT_2_PREVIEW }, { FONT_TEXT_2, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_2_SCORES }, { FONT_TEXT_2_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_2_ACTIVE_SCORES }, { FONT_TEXT_3, -1, IMG_FONT_TEXT_3 }, { FONT_TEXT_3, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_3_LEVELS }, { FONT_TEXT_3, GFX_SPECIAL_ARG_LEVELNR, IMG_FONT_TEXT_3_LEVELNR }, { FONT_TEXT_3, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_3_SETUP }, { FONT_TEXT_3, GFX_SPECIAL_ARG_PREVIEW, IMG_FONT_TEXT_3_PREVIEW }, { FONT_TEXT_3, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_3_SCORES }, { FONT_TEXT_3_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_3_ACTIVE_SCORES }, { FONT_TEXT_4, -1, IMG_FONT_TEXT_4 }, { FONT_TEXT_4, GFX_SPECIAL_ARG_MAIN, IMG_FONT_TEXT_4_MAIN }, { FONT_TEXT_4, GFX_SPECIAL_ARG_LEVELS, IMG_FONT_TEXT_4_LEVELS }, { FONT_TEXT_4, GFX_SPECIAL_ARG_LEVELNR, IMG_FONT_TEXT_4_LEVELNR }, { FONT_TEXT_4, GFX_SPECIAL_ARG_SETUP, IMG_FONT_TEXT_4_SETUP }, { FONT_TEXT_4, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_4_SCORES }, { FONT_TEXT_4_ACTIVE, GFX_SPECIAL_ARG_SCORES, IMG_FONT_TEXT_4_ACTIVE_SCORES }, { FONT_ENVELOPE_1, -1, IMG_FONT_ENVELOPE_1 }, { FONT_ENVELOPE_2, -1, IMG_FONT_ENVELOPE_2 }, { FONT_ENVELOPE_3, -1, IMG_FONT_ENVELOPE_3 }, { FONT_ENVELOPE_4, -1, IMG_FONT_ENVELOPE_4 }, { FONT_REQUEST, -1, IMG_FONT_REQUEST }, { FONT_INPUT_1, -1, IMG_FONT_INPUT_1 }, { FONT_INPUT_1, GFX_SPECIAL_ARG_MAIN, IMG_FONT_INPUT_1_MAIN }, { FONT_INPUT_1_ACTIVE, -1, IMG_FONT_INPUT_1_ACTIVE }, { FONT_INPUT_1_ACTIVE, GFX_SPECIAL_ARG_MAIN, IMG_FONT_INPUT_1_ACTIVE_MAIN }, { FONT_INPUT_1_ACTIVE, GFX_SPECIAL_ARG_SETUP, IMG_FONT_INPUT_1_ACTIVE_SETUP }, { FONT_INPUT_2, -1, IMG_FONT_INPUT_2 }, { FONT_INPUT_2_ACTIVE, -1, IMG_FONT_INPUT_2_ACTIVE }, { FONT_OPTION_OFF, -1, IMG_FONT_OPTION_OFF }, { FONT_OPTION_OFF_NARROW, -1, IMG_FONT_OPTION_OFF_NARROW }, { FONT_OPTION_ON, -1, IMG_FONT_OPTION_ON }, { FONT_OPTION_ON_NARROW, -1, IMG_FONT_OPTION_ON_NARROW }, { FONT_VALUE_1, -1, IMG_FONT_VALUE_1 }, { FONT_VALUE_2, -1, IMG_FONT_VALUE_2 }, { FONT_VALUE_OLD, -1, IMG_FONT_VALUE_OLD }, { FONT_VALUE_NARROW, -1, IMG_FONT_VALUE_NARROW }, { FONT_LEVEL_NUMBER, -1, IMG_FONT_LEVEL_NUMBER }, { FONT_LEVEL_NUMBER_ACTIVE, -1, IMG_FONT_LEVEL_NUMBER_ACTIVE }, { FONT_TAPE_RECORDER, -1, IMG_FONT_TAPE_RECORDER }, { FONT_GAME_INFO, -1, IMG_FONT_GAME_INFO }, { FONT_INFO_ELEMENTS, -1, IMG_FONT_INFO_ELEMENTS }, { FONT_INFO_LEVELSET, -1, IMG_FONT_INFO_LEVELSET }, { -1, -1, -1 }, }; #endif /* CONF_FNT_C */ mirrormagic-3.0.0/src/netserv.c0000644000175000017500000003501213263212010015743 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // netserv.c // ============================================================================ #include "libgame/platform.h" #if defined(NETWORK_AVALIABLE) #include #include #include #include #include "main.h" #include "libgame/libgame.h" #include "netserv.h" static int clients = 0; static int onceonly = 0; struct NetworkServerPlayerInfo { TCPsocket 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) /* TODO: peer address */ static TCPsocket lfd; /* listening socket */ static SDLNet_SocketSet fds; /* socket set */ static unsigned char realbuffer[512], *buffer = realbuffer + 4; static int interrupt; static unsigned int ServerFrameCounter = 0; 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) { SDLNet_TCP_Send(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->introduced && (player->active || !activeonly)) 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; } } } SDLNet_TCP_DelSocket(fds, player->fd); SDLNet_TCP_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(TCPsocket fd) { struct NetworkServerPlayerInfo *player, *v; unsigned char nxn; boolean again = TRUE; 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; SDLNet_TCP_AddSocket(fds, fd); first_player = player; nxn = 1; while (again) { again = FALSE; v = player->next; while (v) { if (v->number == nxn) { nxn++; again = TRUE; break; } v = v->next; } } player->number = nxn; 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) already has # %d", player->number, player->player_name, nr_wanted); else Error(ERR_NETWORK_SERVER, "client %d (%s) cannot switch (client %d already 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; i < len - 2; i++) { if (player->player_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 leveldir %d (%s)]", player->number, player->player_name, (buffer[2] << 8) + buffer[3], (buffer[4] << 8) + buffer[5], &buffer[10]); for (w = first_player; w; w = w->next) if (w->introduced) w->active = 1; /* reset frame counter */ ServerFrameCounter = 0; Error(ERR_NETWORK_SERVER, "resetting ServerFrameCounter to 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) { int cause_for_stopping = buffer[2]; if (options.verbose) Error(ERR_NETWORK_SERVER, "client %d (%s) stops game [%d]", player->number, player->player_name, cause_for_stopping); broadcast(NULL, 3, 0); } static void Handle_OP_MOVE_PLAYER(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; i < last_client_nr; i++) buffer[6 + i] = 0; /* broadcast actions of all players to all players */ for (v = first_player; v; v = v->next) { 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++; } /* the following is not used for a standalone server; the pointer points to an integer containing the port-number */ int NetworkServerThread(void *ptr) { NetworkServer(*((int *) ptr), 0); /* should never be reached */ return 0; } void NetworkServer(int port, int serveronly) { int sl; struct NetworkServerPlayerInfo *player; int r; unsigned int len; IPaddress ip; #if defined(PLATFORM_UNIX) && !defined(PLATFORM_NEXT) struct sigaction sact; #endif if (port == 0) port = DEFAULT_SERVER_PORT; if (!serveronly) onceonly = 1; #if defined(PLATFORM_UNIX) #if defined(PLATFORM_NEXT) signal(SIGPIPE, SIG_IGN); #else sact.sa_handler = SIG_IGN; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sigaction(SIGPIPE, &sact, NULL); #endif #endif if (SDLNet_ResolveHost(&ip, NULL, port) == -1) Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_ResolveHost() failed"); lfd = SDLNet_TCP_Open(&ip); if (!lfd) Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_Open() failed"); fds = SDLNet_AllocSocketSet(MAX_PLAYERS+1); SDLNet_TCP_AddSocket(fds, lfd); 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); if ((sl = SDLNet_CheckSockets(fds, 500000)) < 1) { Error(ERR_NETWORK_SERVER, "SDLNet_CheckSockets failed: %s", SDLNet_GetError()); perror("SDLNet_CheckSockets"); } if (sl < 0) continue; if (sl == 0) continue; /* accept incoming connections */ if (SDLNet_SocketReady(lfd)) { TCPsocket newsock; newsock = SDLNet_TCP_Accept(lfd); if (newsock) AddPlayer(newsock); } player = first_player; do { if (SDLNet_SocketReady(player->fd)) { /* read only 1 byte, because SDLNet blocks when we want more than is in the buffer */ r = SDLNet_TCP_Recv(player->fd, player->readbuffer + player->nread, 1); 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_PLAYER: Handle_OP_MOVE_PLAYER(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 /* NETWORK_AVALIABLE */ mirrormagic-3.0.0/src/conf_esg.c0000644000175000017500000010663713263214151016064 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_esg.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_ESG_C #define CONF_ESG_C /* values for element/graphics mapping configuration (special) */ static struct { int element; int special; int graphic; } element_to_special_graphic[] = { { EL_BD_WALL, GFX_SPECIAL_ARG_EDITOR, IMG_BD_WALL_EDITOR }, { EL_BD_ROCK, GFX_SPECIAL_ARG_EDITOR, IMG_BD_ROCK_EDITOR }, { EL_BD_AMOEBA, GFX_SPECIAL_ARG_EDITOR, IMG_BD_AMOEBA_EDITOR }, { EL_BD_BUTTERFLY_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_RIGHT_EDITOR }, { EL_BD_BUTTERFLY_UP, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_UP_EDITOR }, { EL_BD_BUTTERFLY_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_LEFT_EDITOR }, { EL_BD_BUTTERFLY_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_BD_BUTTERFLY_DOWN_EDITOR }, { EL_BD_FIREFLY_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_RIGHT_EDITOR }, { EL_BD_FIREFLY_UP, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_UP_EDITOR }, { EL_BD_FIREFLY_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_LEFT_EDITOR }, { EL_BD_FIREFLY_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_BD_FIREFLY_DOWN_EDITOR }, { EL_SP_INFOTRON, GFX_SPECIAL_ARG_EDITOR, IMG_SP_INFOTRON_EDITOR }, { EL_SP_GRAVITY_PORT_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_RIGHT_EDITOR }, { EL_SP_GRAVITY_PORT_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_DOWN_EDITOR }, { EL_SP_GRAVITY_PORT_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_LEFT_EDITOR }, { EL_SP_GRAVITY_PORT_UP, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_PORT_UP_EDITOR }, { EL_SP_GRAVITY_ON_PORT_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR }, { EL_SP_GRAVITY_ON_PORT_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR }, { EL_SP_GRAVITY_ON_PORT_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR }, { EL_SP_GRAVITY_ON_PORT_UP, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_ON_PORT_UP_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR }, { EL_SP_GRAVITY_OFF_PORT_UP, GFX_SPECIAL_ARG_EDITOR, IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR }, { EL_SP_ELECTRON, GFX_SPECIAL_ARG_EDITOR, IMG_SP_ELECTRON_EDITOR }, { EL_SP_TERMINAL, GFX_SPECIAL_ARG_EDITOR, IMG_SP_TERMINAL_EDITOR }, { EL_SP_BUGGY_BASE, GFX_SPECIAL_ARG_EDITOR, IMG_SP_BUGGY_BASE_EDITOR }, { EL_SOKOBAN_OBJECT, GFX_SPECIAL_ARG_EDITOR, IMG_SOKOBAN_OBJECT_EDITOR }, { EL_SOKOBAN_FIELD_PLAYER, GFX_SPECIAL_ARG_EDITOR, IMG_SOKOBAN_FIELD_PLAYER_EDITOR }, { EL_DYNAMITE, GFX_SPECIAL_ARG_EDITOR, IMG_DYNAMITE_EDITOR }, { EL_DYNAMITE_ACTIVE, GFX_SPECIAL_ARG_EDITOR, IMG_DYNAMITE_ACTIVE_EDITOR }, { EL_EM_DYNAMITE_ACTIVE, GFX_SPECIAL_ARG_EDITOR, IMG_EM_DYNAMITE_ACTIVE_EDITOR }, { EL_YAMYAM_LEFT, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_LEFT_EDITOR }, { EL_YAMYAM_RIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_RIGHT_EDITOR }, { EL_YAMYAM_UP, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_UP_EDITOR }, { EL_YAMYAM_DOWN, GFX_SPECIAL_ARG_EDITOR, IMG_YAMYAM_DOWN_EDITOR }, { EL_QUICKSAND_FULL, GFX_SPECIAL_ARG_EDITOR, IMG_QUICKSAND_FULL_EDITOR }, { EL_QUICKSAND_FAST_FULL, GFX_SPECIAL_ARG_EDITOR, IMG_QUICKSAND_FAST_FULL_EDITOR }, { EL_AMOEBA_WET, GFX_SPECIAL_ARG_EDITOR, IMG_AMOEBA_WET_EDITOR }, { EL_AMOEBA_FULL, GFX_SPECIAL_ARG_EDITOR, IMG_AMOEBA_FULL_EDITOR }, { EL_AMOEBA_DEAD, GFX_SPECIAL_ARG_EDITOR, IMG_AMOEBA_DEAD_EDITOR }, { EL_EM_GATE_1_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_1_GRAY_EDITOR }, { EL_EM_GATE_2_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_2_GRAY_EDITOR }, { EL_EM_GATE_3_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_3_GRAY_EDITOR }, { EL_EM_GATE_4_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EM_GATE_4_GRAY_EDITOR }, { EL_DC_GATE_WHITE_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_DC_GATE_WHITE_GRAY_EDITOR }, { EL_INVISIBLE_STEELWALL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_EDITOR }, { EL_INVISIBLE_WALL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_WALL_EDITOR }, { EL_INVISIBLE_SAND, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_SAND_EDITOR }, { EL_KEY_1, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_1_EDITOR }, { EL_KEY_2, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_2_EDITOR }, { EL_KEY_3, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_3_EDITOR }, { EL_KEY_4, GFX_SPECIAL_ARG_EDITOR, IMG_KEY_4_EDITOR }, { EL_GATE_1_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_1_GRAY_EDITOR }, { EL_GATE_2_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_2_GRAY_EDITOR }, { EL_GATE_3_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_3_GRAY_EDITOR }, { EL_GATE_4_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_GATE_4_GRAY_EDITOR }, { EL_LAMP, GFX_SPECIAL_ARG_EDITOR, IMG_LAMP_EDITOR }, { EL_EXPANDABLE_WALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR }, { EL_EXPANDABLE_WALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_WALL_VERTICAL_EDITOR }, { EL_EXPANDABLE_WALL_ANY, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_WALL_ANY_EDITOR }, { EL_EXPANDABLE_STEELWALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_STEELWALL_HORIZONTAL_EDITOR }, { EL_EXPANDABLE_STEELWALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_STEELWALL_VERTICAL_EDITOR }, { EL_EXPANDABLE_STEELWALL_ANY, GFX_SPECIAL_ARG_EDITOR, IMG_EXPANDABLE_STEELWALL_ANY_EDITOR }, { EL_BD_EXPANDABLE_WALL, GFX_SPECIAL_ARG_EDITOR, IMG_BD_EXPANDABLE_WALL_EDITOR }, { EL_PENGUIN, GFX_SPECIAL_ARG_EDITOR, IMG_PENGUIN_EDITOR }, { EL_PLAYER_1, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_1_EDITOR }, { EL_PLAYER_2, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_2_EDITOR }, { EL_PLAYER_3, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_3_EDITOR }, { EL_PLAYER_4, GFX_SPECIAL_ARG_EDITOR, IMG_PLAYER_4_EDITOR }, { EL_STEELWALL_TOPLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_TOPLEFT_EDITOR }, { EL_STEELWALL_TOPRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_TOPRIGHT_EDITOR }, { EL_STEELWALL_BOTTOMLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_BOTTOMLEFT_EDITOR }, { EL_STEELWALL_BOTTOMRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_BOTTOMRIGHT_EDITOR }, { EL_STEELWALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_HORIZONTAL_EDITOR }, { EL_STEELWALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_STEELWALL_VERTICAL_EDITOR }, { EL_INVISIBLE_STEELWALL_TOPLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR }, { EL_INVISIBLE_STEELWALL_TOPRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR }, { EL_INVISIBLE_STEELWALL_BOTTOMLEFT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR }, { EL_INVISIBLE_STEELWALL_BOTTOMRIGHT, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR }, { EL_INVISIBLE_STEELWALL_HORIZONTAL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR }, { EL_INVISIBLE_STEELWALL_VERTICAL, GFX_SPECIAL_ARG_EDITOR, IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR }, { EL_EMC_GATE_5_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_5_GRAY_EDITOR }, { EL_EMC_GATE_6_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_6_GRAY_EDITOR }, { EL_EMC_GATE_7_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_7_GRAY_EDITOR }, { EL_EMC_GATE_8_GRAY, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_GATE_8_GRAY_EDITOR }, { EL_EMC_FAKE_GRASS, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_FAKE_GRASS_EDITOR }, { EL_EMC_DRIPPER, GFX_SPECIAL_ARG_EDITOR, IMG_EMC_DRIPPER_EDITOR }, { EL_DF_MIRROR_ROTATING_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_1_EDITOR }, { EL_DF_MIRROR_ROTATING_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_2_EDITOR }, { EL_DF_MIRROR_ROTATING_3, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_3_EDITOR }, { EL_DF_MIRROR_ROTATING_4, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_4_EDITOR }, { EL_DF_MIRROR_ROTATING_5, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_5_EDITOR }, { EL_DF_MIRROR_ROTATING_6, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_6_EDITOR }, { EL_DF_MIRROR_ROTATING_7, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_7_EDITOR }, { EL_DF_MIRROR_ROTATING_8, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_8_EDITOR }, { EL_DF_MIRROR_ROTATING_9, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_9_EDITOR }, { EL_DF_MIRROR_ROTATING_10, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_10_EDITOR }, { EL_DF_MIRROR_ROTATING_11, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_11_EDITOR }, { EL_DF_MIRROR_ROTATING_12, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_12_EDITOR }, { EL_DF_MIRROR_ROTATING_13, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_13_EDITOR }, { EL_DF_MIRROR_ROTATING_14, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_14_EDITOR }, { EL_DF_MIRROR_ROTATING_15, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_15_EDITOR }, { EL_DF_MIRROR_ROTATING_16, GFX_SPECIAL_ARG_EDITOR, IMG_DF_MIRROR_ROTATING_16_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_1_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_2_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_3, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_3_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_4, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_4_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_5, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_5_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_6, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_6_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_7, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_7_EDITOR }, { EL_DF_STEEL_GRID_ROTATING_8, GFX_SPECIAL_ARG_EDITOR, IMG_DF_STEEL_GRID_ROTATING_8_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_1_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_2_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_3, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_3_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_4, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_4_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_5, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_5_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_6, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_6_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_7, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_7_EDITOR }, { EL_DF_WOODEN_GRID_ROTATING_8, GFX_SPECIAL_ARG_EDITOR, IMG_DF_WOODEN_GRID_ROTATING_8_EDITOR }, { EL_DF_FIBRE_OPTIC_RED_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_RED_1_EDITOR }, { EL_DF_FIBRE_OPTIC_RED_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_RED_2_EDITOR }, { EL_DF_FIBRE_OPTIC_YELLOW_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_YELLOW_1_EDITOR }, { EL_DF_FIBRE_OPTIC_YELLOW_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_YELLOW_2_EDITOR }, { EL_DF_FIBRE_OPTIC_GREEN_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_GREEN_1_EDITOR }, { EL_DF_FIBRE_OPTIC_GREEN_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_GREEN_2_EDITOR }, { EL_DF_FIBRE_OPTIC_BLUE_1, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_BLUE_1_EDITOR }, { EL_DF_FIBRE_OPTIC_BLUE_2, GFX_SPECIAL_ARG_EDITOR, IMG_DF_FIBRE_OPTIC_BLUE_2_EDITOR }, { EL_CUSTOM_1, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_1_EDITOR }, { EL_CUSTOM_2, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_2_EDITOR }, { EL_CUSTOM_3, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_3_EDITOR }, { EL_CUSTOM_4, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_4_EDITOR }, { EL_CUSTOM_5, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_5_EDITOR }, { EL_CUSTOM_6, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_6_EDITOR }, { EL_CUSTOM_7, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_7_EDITOR }, { EL_CUSTOM_8, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_8_EDITOR }, { EL_CUSTOM_9, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_9_EDITOR }, { EL_CUSTOM_10, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_10_EDITOR }, { EL_CUSTOM_11, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_11_EDITOR }, { EL_CUSTOM_12, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_12_EDITOR }, { EL_CUSTOM_13, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_13_EDITOR }, { EL_CUSTOM_14, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_14_EDITOR }, { EL_CUSTOM_15, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_15_EDITOR }, { EL_CUSTOM_16, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_16_EDITOR }, { EL_CUSTOM_17, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_17_EDITOR }, { EL_CUSTOM_18, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_18_EDITOR }, { EL_CUSTOM_19, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_19_EDITOR }, { EL_CUSTOM_20, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_20_EDITOR }, { EL_CUSTOM_21, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_21_EDITOR }, { EL_CUSTOM_22, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_22_EDITOR }, { EL_CUSTOM_23, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_23_EDITOR }, { EL_CUSTOM_24, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_24_EDITOR }, { EL_CUSTOM_25, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_25_EDITOR }, { EL_CUSTOM_26, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_26_EDITOR }, { EL_CUSTOM_27, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_27_EDITOR }, { EL_CUSTOM_28, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_28_EDITOR }, { EL_CUSTOM_29, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_29_EDITOR }, { EL_CUSTOM_30, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_30_EDITOR }, { EL_CUSTOM_31, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_31_EDITOR }, { EL_CUSTOM_32, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_32_EDITOR }, { EL_CUSTOM_33, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_33_EDITOR }, { EL_CUSTOM_34, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_34_EDITOR }, { EL_CUSTOM_35, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_35_EDITOR }, { EL_CUSTOM_36, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_36_EDITOR }, { EL_CUSTOM_37, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_37_EDITOR }, { EL_CUSTOM_38, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_38_EDITOR }, { EL_CUSTOM_39, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_39_EDITOR }, { EL_CUSTOM_40, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_40_EDITOR }, { EL_CUSTOM_41, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_41_EDITOR }, { EL_CUSTOM_42, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_42_EDITOR }, { EL_CUSTOM_43, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_43_EDITOR }, { EL_CUSTOM_44, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_44_EDITOR }, { EL_CUSTOM_45, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_45_EDITOR }, { EL_CUSTOM_46, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_46_EDITOR }, { EL_CUSTOM_47, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_47_EDITOR }, { EL_CUSTOM_48, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_48_EDITOR }, { EL_CUSTOM_49, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_49_EDITOR }, { EL_CUSTOM_50, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_50_EDITOR }, { EL_CUSTOM_51, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_51_EDITOR }, { EL_CUSTOM_52, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_52_EDITOR }, { EL_CUSTOM_53, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_53_EDITOR }, { EL_CUSTOM_54, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_54_EDITOR }, { EL_CUSTOM_55, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_55_EDITOR }, { EL_CUSTOM_56, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_56_EDITOR }, { EL_CUSTOM_57, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_57_EDITOR }, { EL_CUSTOM_58, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_58_EDITOR }, { EL_CUSTOM_59, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_59_EDITOR }, { EL_CUSTOM_60, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_60_EDITOR }, { EL_CUSTOM_61, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_61_EDITOR }, { EL_CUSTOM_62, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_62_EDITOR }, { EL_CUSTOM_63, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_63_EDITOR }, { EL_CUSTOM_64, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_64_EDITOR }, { EL_CUSTOM_65, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_65_EDITOR }, { EL_CUSTOM_66, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_66_EDITOR }, { EL_CUSTOM_67, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_67_EDITOR }, { EL_CUSTOM_68, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_68_EDITOR }, { EL_CUSTOM_69, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_69_EDITOR }, { EL_CUSTOM_70, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_70_EDITOR }, { EL_CUSTOM_71, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_71_EDITOR }, { EL_CUSTOM_72, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_72_EDITOR }, { EL_CUSTOM_73, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_73_EDITOR }, { EL_CUSTOM_74, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_74_EDITOR }, { EL_CUSTOM_75, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_75_EDITOR }, { EL_CUSTOM_76, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_76_EDITOR }, { EL_CUSTOM_77, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_77_EDITOR }, { EL_CUSTOM_78, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_78_EDITOR }, { EL_CUSTOM_79, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_79_EDITOR }, { EL_CUSTOM_80, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_80_EDITOR }, { EL_CUSTOM_81, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_81_EDITOR }, { EL_CUSTOM_82, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_82_EDITOR }, { EL_CUSTOM_83, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_83_EDITOR }, { EL_CUSTOM_84, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_84_EDITOR }, { EL_CUSTOM_85, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_85_EDITOR }, { EL_CUSTOM_86, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_86_EDITOR }, { EL_CUSTOM_87, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_87_EDITOR }, { EL_CUSTOM_88, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_88_EDITOR }, { EL_CUSTOM_89, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_89_EDITOR }, { EL_CUSTOM_90, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_90_EDITOR }, { EL_CUSTOM_91, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_91_EDITOR }, { EL_CUSTOM_92, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_92_EDITOR }, { EL_CUSTOM_93, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_93_EDITOR }, { EL_CUSTOM_94, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_94_EDITOR }, { EL_CUSTOM_95, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_95_EDITOR }, { EL_CUSTOM_96, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_96_EDITOR }, { EL_CUSTOM_97, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_97_EDITOR }, { EL_CUSTOM_98, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_98_EDITOR }, { EL_CUSTOM_99, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_99_EDITOR }, { EL_CUSTOM_100, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_100_EDITOR }, { EL_CUSTOM_101, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_101_EDITOR }, { EL_CUSTOM_102, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_102_EDITOR }, { EL_CUSTOM_103, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_103_EDITOR }, { EL_CUSTOM_104, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_104_EDITOR }, { EL_CUSTOM_105, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_105_EDITOR }, { EL_CUSTOM_106, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_106_EDITOR }, { EL_CUSTOM_107, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_107_EDITOR }, { EL_CUSTOM_108, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_108_EDITOR }, { EL_CUSTOM_109, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_109_EDITOR }, { EL_CUSTOM_110, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_110_EDITOR }, { EL_CUSTOM_111, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_111_EDITOR }, { EL_CUSTOM_112, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_112_EDITOR }, { EL_CUSTOM_113, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_113_EDITOR }, { EL_CUSTOM_114, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_114_EDITOR }, { EL_CUSTOM_115, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_115_EDITOR }, { EL_CUSTOM_116, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_116_EDITOR }, { EL_CUSTOM_117, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_117_EDITOR }, { EL_CUSTOM_118, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_118_EDITOR }, { EL_CUSTOM_119, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_119_EDITOR }, { EL_CUSTOM_120, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_120_EDITOR }, { EL_CUSTOM_121, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_121_EDITOR }, { EL_CUSTOM_122, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_122_EDITOR }, { EL_CUSTOM_123, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_123_EDITOR }, { EL_CUSTOM_124, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_124_EDITOR }, { EL_CUSTOM_125, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_125_EDITOR }, { EL_CUSTOM_126, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_126_EDITOR }, { EL_CUSTOM_127, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_127_EDITOR }, { EL_CUSTOM_128, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_128_EDITOR }, { EL_CUSTOM_129, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_129_EDITOR }, { EL_CUSTOM_130, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_130_EDITOR }, { EL_CUSTOM_131, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_131_EDITOR }, { EL_CUSTOM_132, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_132_EDITOR }, { EL_CUSTOM_133, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_133_EDITOR }, { EL_CUSTOM_134, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_134_EDITOR }, { EL_CUSTOM_135, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_135_EDITOR }, { EL_CUSTOM_136, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_136_EDITOR }, { EL_CUSTOM_137, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_137_EDITOR }, { EL_CUSTOM_138, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_138_EDITOR }, { EL_CUSTOM_139, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_139_EDITOR }, { EL_CUSTOM_140, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_140_EDITOR }, { EL_CUSTOM_141, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_141_EDITOR }, { EL_CUSTOM_142, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_142_EDITOR }, { EL_CUSTOM_143, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_143_EDITOR }, { EL_CUSTOM_144, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_144_EDITOR }, { EL_CUSTOM_145, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_145_EDITOR }, { EL_CUSTOM_146, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_146_EDITOR }, { EL_CUSTOM_147, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_147_EDITOR }, { EL_CUSTOM_148, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_148_EDITOR }, { EL_CUSTOM_149, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_149_EDITOR }, { EL_CUSTOM_150, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_150_EDITOR }, { EL_CUSTOM_151, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_151_EDITOR }, { EL_CUSTOM_152, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_152_EDITOR }, { EL_CUSTOM_153, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_153_EDITOR }, { EL_CUSTOM_154, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_154_EDITOR }, { EL_CUSTOM_155, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_155_EDITOR }, { EL_CUSTOM_156, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_156_EDITOR }, { EL_CUSTOM_157, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_157_EDITOR }, { EL_CUSTOM_158, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_158_EDITOR }, { EL_CUSTOM_159, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_159_EDITOR }, { EL_CUSTOM_160, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_160_EDITOR }, { EL_CUSTOM_161, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_161_EDITOR }, { EL_CUSTOM_162, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_162_EDITOR }, { EL_CUSTOM_163, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_163_EDITOR }, { EL_CUSTOM_164, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_164_EDITOR }, { EL_CUSTOM_165, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_165_EDITOR }, { EL_CUSTOM_166, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_166_EDITOR }, { EL_CUSTOM_167, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_167_EDITOR }, { EL_CUSTOM_168, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_168_EDITOR }, { EL_CUSTOM_169, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_169_EDITOR }, { EL_CUSTOM_170, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_170_EDITOR }, { EL_CUSTOM_171, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_171_EDITOR }, { EL_CUSTOM_172, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_172_EDITOR }, { EL_CUSTOM_173, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_173_EDITOR }, { EL_CUSTOM_174, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_174_EDITOR }, { EL_CUSTOM_175, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_175_EDITOR }, { EL_CUSTOM_176, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_176_EDITOR }, { EL_CUSTOM_177, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_177_EDITOR }, { EL_CUSTOM_178, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_178_EDITOR }, { EL_CUSTOM_179, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_179_EDITOR }, { EL_CUSTOM_180, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_180_EDITOR }, { EL_CUSTOM_181, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_181_EDITOR }, { EL_CUSTOM_182, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_182_EDITOR }, { EL_CUSTOM_183, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_183_EDITOR }, { EL_CUSTOM_184, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_184_EDITOR }, { EL_CUSTOM_185, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_185_EDITOR }, { EL_CUSTOM_186, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_186_EDITOR }, { EL_CUSTOM_187, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_187_EDITOR }, { EL_CUSTOM_188, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_188_EDITOR }, { EL_CUSTOM_189, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_189_EDITOR }, { EL_CUSTOM_190, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_190_EDITOR }, { EL_CUSTOM_191, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_191_EDITOR }, { EL_CUSTOM_192, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_192_EDITOR }, { EL_CUSTOM_193, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_193_EDITOR }, { EL_CUSTOM_194, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_194_EDITOR }, { EL_CUSTOM_195, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_195_EDITOR }, { EL_CUSTOM_196, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_196_EDITOR }, { EL_CUSTOM_197, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_197_EDITOR }, { EL_CUSTOM_198, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_198_EDITOR }, { EL_CUSTOM_199, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_199_EDITOR }, { EL_CUSTOM_200, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_200_EDITOR }, { EL_CUSTOM_201, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_201_EDITOR }, { EL_CUSTOM_202, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_202_EDITOR }, { EL_CUSTOM_203, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_203_EDITOR }, { EL_CUSTOM_204, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_204_EDITOR }, { EL_CUSTOM_205, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_205_EDITOR }, { EL_CUSTOM_206, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_206_EDITOR }, { EL_CUSTOM_207, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_207_EDITOR }, { EL_CUSTOM_208, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_208_EDITOR }, { EL_CUSTOM_209, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_209_EDITOR }, { EL_CUSTOM_210, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_210_EDITOR }, { EL_CUSTOM_211, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_211_EDITOR }, { EL_CUSTOM_212, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_212_EDITOR }, { EL_CUSTOM_213, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_213_EDITOR }, { EL_CUSTOM_214, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_214_EDITOR }, { EL_CUSTOM_215, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_215_EDITOR }, { EL_CUSTOM_216, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_216_EDITOR }, { EL_CUSTOM_217, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_217_EDITOR }, { EL_CUSTOM_218, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_218_EDITOR }, { EL_CUSTOM_219, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_219_EDITOR }, { EL_CUSTOM_220, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_220_EDITOR }, { EL_CUSTOM_221, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_221_EDITOR }, { EL_CUSTOM_222, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_222_EDITOR }, { EL_CUSTOM_223, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_223_EDITOR }, { EL_CUSTOM_224, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_224_EDITOR }, { EL_CUSTOM_225, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_225_EDITOR }, { EL_CUSTOM_226, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_226_EDITOR }, { EL_CUSTOM_227, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_227_EDITOR }, { EL_CUSTOM_228, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_228_EDITOR }, { EL_CUSTOM_229, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_229_EDITOR }, { EL_CUSTOM_230, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_230_EDITOR }, { EL_CUSTOM_231, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_231_EDITOR }, { EL_CUSTOM_232, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_232_EDITOR }, { EL_CUSTOM_233, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_233_EDITOR }, { EL_CUSTOM_234, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_234_EDITOR }, { EL_CUSTOM_235, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_235_EDITOR }, { EL_CUSTOM_236, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_236_EDITOR }, { EL_CUSTOM_237, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_237_EDITOR }, { EL_CUSTOM_238, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_238_EDITOR }, { EL_CUSTOM_239, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_239_EDITOR }, { EL_CUSTOM_240, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_240_EDITOR }, { EL_CUSTOM_241, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_241_EDITOR }, { EL_CUSTOM_242, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_242_EDITOR }, { EL_CUSTOM_243, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_243_EDITOR }, { EL_CUSTOM_244, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_244_EDITOR }, { EL_CUSTOM_245, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_245_EDITOR }, { EL_CUSTOM_246, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_246_EDITOR }, { EL_CUSTOM_247, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_247_EDITOR }, { EL_CUSTOM_248, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_248_EDITOR }, { EL_CUSTOM_249, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_249_EDITOR }, { EL_CUSTOM_250, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_250_EDITOR }, { EL_CUSTOM_251, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_251_EDITOR }, { EL_CUSTOM_252, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_252_EDITOR }, { EL_CUSTOM_253, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_253_EDITOR }, { EL_CUSTOM_254, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_254_EDITOR }, { EL_CUSTOM_255, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_255_EDITOR }, { EL_CUSTOM_256, GFX_SPECIAL_ARG_EDITOR, IMG_CUSTOM_256_EDITOR }, { EL_GROUP_1, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_1_EDITOR }, { EL_GROUP_2, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_2_EDITOR }, { EL_GROUP_3, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_3_EDITOR }, { EL_GROUP_4, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_4_EDITOR }, { EL_GROUP_5, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_5_EDITOR }, { EL_GROUP_6, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_6_EDITOR }, { EL_GROUP_7, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_7_EDITOR }, { EL_GROUP_8, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_8_EDITOR }, { EL_GROUP_9, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_9_EDITOR }, { EL_GROUP_10, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_10_EDITOR }, { EL_GROUP_11, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_11_EDITOR }, { EL_GROUP_12, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_12_EDITOR }, { EL_GROUP_13, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_13_EDITOR }, { EL_GROUP_14, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_14_EDITOR }, { EL_GROUP_15, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_15_EDITOR }, { EL_GROUP_16, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_16_EDITOR }, { EL_GROUP_17, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_17_EDITOR }, { EL_GROUP_18, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_18_EDITOR }, { EL_GROUP_19, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_19_EDITOR }, { EL_GROUP_20, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_20_EDITOR }, { EL_GROUP_21, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_21_EDITOR }, { EL_GROUP_22, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_22_EDITOR }, { EL_GROUP_23, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_23_EDITOR }, { EL_GROUP_24, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_24_EDITOR }, { EL_GROUP_25, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_25_EDITOR }, { EL_GROUP_26, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_26_EDITOR }, { EL_GROUP_27, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_27_EDITOR }, { EL_GROUP_28, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_28_EDITOR }, { EL_GROUP_29, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_29_EDITOR }, { EL_GROUP_30, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_30_EDITOR }, { EL_GROUP_31, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_31_EDITOR }, { EL_GROUP_32, GFX_SPECIAL_ARG_EDITOR, IMG_GROUP_32_EDITOR }, { EL_CHAR_SPACE, GFX_SPECIAL_ARG_EDITOR, IMG_CHAR_SPACE_EDITOR }, { -1, -1, -1 }, }; #endif /* CONF_ESG_C */ mirrormagic-3.0.0/src/game_sp/0000755000175000017500000000000013263214225015535 5ustar aeglosaeglosmirrormagic-3.0.0/src/game_sp/MainForm.h0000644000175000017500000000124213263212010017403 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // MainForm.h // ---------------------------------------------------------------------------- #ifndef MAINFORM_H #define MAINFORM_H #include "global.h" extern void DrawFrameIfNeeded(); extern void DisplayLevel(); extern void DrawField(int X, int Y); extern void DrawFieldAnimated(int X, int Y); extern void DrawFieldNoAnimated(int X, int Y); extern void DrawSprite(int X, int Y, int SpritePos); extern void DrawImage(int X, int Y, int graphic); extern void SetDisplayRegion(); extern void SetScrollEdges(); extern void menPlay_Click(); extern void Form_Load(); #endif /* MAINFORM_H */ mirrormagic-3.0.0/src/game_sp/Zonk.h0000644000175000017500000000043113263212010016613 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Zonk.h // ---------------------------------------------------------------------------- #ifndef ZONK_H #define ZONK_H #include "global.h" extern void subAnimateZonks(int si); #endif /* ZONK_H */ mirrormagic-3.0.0/src/game_sp/InitGameConditions.c0000644000175000017500000001600713263212010021422 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // InitGameConditions.c // ---------------------------------------------------------------------------- #include "InitGameConditions.h" // ========================================================================== // SUBROUTINE // Init game conditions (variables) // ========================================================================== void subInitGameConditions() { MurphyVarFaceLeft = 0; KillMurphyFlag = 0; // no "kill Murphy" ExitToMenuFlag = 0; LeadOutCounter = 0; // quit flag: lead-out counter RedDiskCount = 0; // Red disk counter YawnSleepCounter = 0; // Wake up sleeping Murphy ExplosionShake = 0; // Force explosion flag off ExplosionShakeMurphy = 0; // Force explosion flag off TerminalMaxCycles = 0x7F; YellowDisksExploded = 0; TimerVar = 0; SnikSnaksElectronsFrozen = 0; // Snik-Snaks and Electrons move! SplitMoveFlag = 0; // Reset Split-through-ports RedDiskReleasePhase = 0; // (re-)enable red disk release RedDiskReleaseMurphyPos = 0; // Red disk was released here } // ========================================================================== // SUBROUTINE // Locate Murphy and init location. // ========================================================================== void InitMurphyPos() { int si; for (si = 0; si < LevelMax; si++) if (PlayField16[si] == fiMurphy) break; InitMurphyPosB(si); MurphyPosIndex = si; } void InitMurphyPosB(int si) { MurphyScreenXPos = MurphyXPos = GetStretchX(si); // Murphy's screen x-position MurphyScreenYPos = MurphyYPos = GetStretchY(si); // Murphy's screen y-position // To Do: draw Murphy in location ax DDSpriteBuffer_BltImg(MurphyScreenXPos, MurphyScreenYPos, aniMurphy, 0); subCalculateScreenScrollPos(); // calculate screen start addrs if (AutoScrollFlag) { if (bPlaying) SoftScrollTo(ScreenScrollXPos, ScreenScrollYPos, 1000, 25); else ScrollTo(ScreenScrollXPos, ScreenScrollYPos); } } // ========================================================================== // SUBROUTINE // Convert to easy symbols and reset Infotron count If not ThenVer62 // ========================================================================== int subConvertToEasySymbols() { int ax, bx, cx, dx, i; int al; bx = 0; dx = 0; cx = LevelMax + 1; i = 0; loc_g_26C9: ax = PlayField16[i]; al = LowByte(ax); if (al == 0xF1) // converted explosion? { MovLowByte(&PlayField16[i], 0x1F); // restore explosions goto loc_g_2778; } if (LowByte(GameBusyFlag) != 1) // free screen write? { if (ax == fiInfotron) // Infotron? -> yes--count! goto loc_g_2704; if (ax == fiSnikSnak) // Snik Snak? -> yes--rearrange goto loc_g_2713; if (ax == fiElectron) // Electron? -> yes--rearrange goto loc_g_2741; } // test for fancy RAM Chips: if (ax == fiRAMLeft || ax == fiRAMRight) goto loc_g_2707; if (ax == fiRAMTop || ax == fiRAMBottom) goto loc_g_2707; if (ax < fiHWFirst) // All but deco hardware? goto loc_g_26F8; if (ax < fiRAMTop) // Decorative hardware? goto loc_g_270D; loc_g_26F8: if (ax < fiSpPortRight) // Gravity change ports only? goto loc_g_2778; if (ax < fiSnikSnak) // Gravity change port! 'loc_g_2702: goto loc_g_276F; goto loc_g_2778; loc_g_2704: // INFOTRON dx = dx + 1; // Count Infotrons goto loc_g_2778; loc_g_2707: // DECO RAM CHIPS PlayField16[i] = fiRAM; // Convert to standard RAM chip goto loc_g_2778; loc_g_270D: // DECO HARDWARE PlayField16[i] = fiHardWare; // Convert to standard hardware goto loc_g_2778; loc_g_2713: // SNIK-SNAK if (PlayField16[i - 1] != 0) // 1 field left empty? -> no--try up goto loc_g_271F; MovHighByte(&PlayField16[i], 1); // turn left, step = NorthWest goto loc_g_2778; loc_g_271F: if (PlayField16[i - FieldWidth] != 0) // 1 field up empty? -> no--try right goto loc_g_2730; PlayField16[i - FieldWidth] = 0x1011; // SnikSnak accessing from below, step = 0 PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_2730: if (PlayField16[i + 1] != 0) // 1 field right empty? -> point up goto loc_g_2778; PlayField16[i + 1] = 0x2811; // SnikSnak accessing from left, step = 0 PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_2741: // ELECTRON if (PlayField16[i - 1] != 0) // 1 field left empty? -> no--try up goto loc_g_274D; MovHighByte(&PlayField16[i], 1); goto loc_g_2778; loc_g_274D: if (PlayField16[i - FieldWidth] != 0) // 1 field up empty? -> no--try right goto loc_g_275E; PlayField16[i - FieldWidth] = 0x1018; // 1 field up PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_275E: if (PlayField16[i + 1] != 0) // 1 field right empty? -> no--point down goto loc_g_2778; PlayField16[i + 1] = 0x2818; PlayField16[i] = 0xFFFF; goto loc_g_2778; loc_g_276F: // GRAVITY CHANGING PORTS PlayField16[i] = (ax - 4) | 0x100; // Convert to standard ports goto loc_g_2778; loc_g_2778: i = i + 1; // Next field bx = bx + 1; cx = cx - 1; if (0 < cx) // Until all done 'loc_g_2782: goto loc_g_26C9; return dx; // return InfotronCount } // ========================================================================== // SUBROUTINE // Reset Infotron count. Call immediately after subConvertToEasySymbols // ========================================================================== void ResetInfotronsNeeded(int dx) { if (LInfo.InfotronsNeeded != 0) // Jump If equal (autodetect) dx = LInfo.InfotronsNeeded; InfotronsNeeded = LowByte(dx); // Remaining Infotrons needed TotalInfotronsNeeded = InfotronsNeeded; // Number of Infotrons needed } // ========================================================================== // SUBROUTINE // Fetch and initialize a level // ========================================================================== void subFetchAndInitLevelB() { subFetchAndInitLevelA(); } void subFetchAndInitLevelA() { GameBusyFlag = 0; // restore scissors too subFetchAndInitLevel(); // fetch and initialize a level GameBusyFlag = 1; // no free screen write DemoKeyCode = 0; // delete last demo key! } void subFetchAndInitLevel() { int InfoCountInLevel; PrepareLevel(); // initialize level data GameBusyFlag = -GameBusyFlag; // make != 1 InfoCountInLevel = subConvertToEasySymbols(); // convert to easy symbols GameBusyFlag = -GameBusyFlag; // restore subDisplayLevel(); // paint (init) game field ResetInfotronsNeeded(InfoCountInLevel); // and reset Infotron count subInitGameConditions(); // init game conditions (vars) InitMurphyPos(); // locate Murphy + screen pos } mirrormagic-3.0.0/src/game_sp/Explosions.h0000644000175000017500000000072113263212010020037 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Explosions.h // ---------------------------------------------------------------------------- #ifndef EXPLOSIONS_H #define EXPLOSIONS_H #include "global.h" extern void ExplodeFieldSP(int); extern void subAnimateExplosion(int); extern void subClearFieldDueToExplosion(int); extern void subFollowUpExplosions(); extern void subRedDiskReleaseExplosion(); #endif /* EXPLOSIONS_H */ mirrormagic-3.0.0/src/game_sp/Infotrons.c0000644000175000017500000002476213263212010017663 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Infotrons.c // ---------------------------------------------------------------------------- #include "Infotrons.h" // ========================================================================== // SUBROUTINE // Animate Infotrons (falling) // ========================================================================== void subAnimateInfotrons(int si) { int tFld; int ax, bx, dx, X, Y; int al, bl; tFld = PlayField16[si]; if ((tFld & 0xFF) != fiInfotron) return; if (tFld == fiInfotron) { ax = PlayField16[si + FieldWidth]; // select case playfield16(si+60) if (ax == 0) goto loc_g_11D5; if (ax == fiZonk) goto loc_g_11A6; if (ax == fiInfotron) goto loc_g_11A6; if (ax == fiRAM) goto loc_g_11A6; return; loc_g_11A6: // Case fiZonk, fiInfotron, fiRAM ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_11DC; loc_g_11BD: ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_11F2; return; loc_g_11D5: // Case fiSpace MovHighByte(&PlayField16[si], 0x40); goto loc_g_1207; loc_g_11DC: // roll left? if (PlayField16[si - 1] == 0) goto loc_g_11E5; goto loc_g_11BD; loc_g_11E5: MovHighByte(&PlayField16[si], 0x50); PlayField16[si - 1] = 0x8888; goto loc_g_1207; loc_g_11F2: // roll right? if (PlayField16[si + 1] == 0) goto loc_g_11FA; return; loc_g_11FA: MovHighByte(&PlayField16[si], 0x60); PlayField16[si + 1] = 0x8888; } // tFld = fiInfotron loc_g_1207: // from now on the infotron is definitely moving, // maybe the sequence is in an advanced frame // or just beeing initialized due to the code above bl = HighByte(PlayField16[si]); bx = 0; MovLowByte(&bx, bl); al = bl & 0xF0; if (al == 0x10) // infotron comes falling from above goto loc_g_1242; if (al == 0x20) // infotron comes rolling from right to left goto loc_g_138D; if (al == 0x30) // infotron comes rolling from left to right goto loc_g_13E9; if (al == 0x40) // infotron falls straight down goto loc_g_1444; if (al == 0x50) // infotron rolls left goto loc_g_1472; if (al == 0x60) // infotron rolls right goto loc_g_14E0; if (al == 0x70) // intermediate state goto loc_g_154E; return; loc_g_1242: // infotron comes falling from above // To Do: draw infotron falling from above // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); dx = bl & 0x7; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + TwoPixels * (dx + 1), aniInfotron, dx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x16) { MovHighByte(&PlayField16[si], bl); subCleanUpForInfotronsAbove(si - FieldWidth); return; } // loc_g_1285: if (bl < 0x18) { MovHighByte(&PlayField16[si], bl); return; } // loc_g_128F: MovHighByte(&PlayField16[si], 0); // infotron arrived at the field // now check if the zonk may go on falling somehow ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty!-> go on falling goto loc_g_132D; if (ax == 0x9999) // below is only temporarily used goto loc_g_132D; if ((ax & 0xFF) == fiMurphy) // Murphy dies goto loc_g_1364; if (ax == fiRedDisk) // red disk hit goto loc_g_1386; if ((ax & 0xFF) == fiSnikSnak) // SnikSnak dies goto loc_g_1386; if ((ax & 0xFF) == fiElectron) // Electron cracked! goto loc_g_1386; if (ax == fiYellowDisk) // yellow disk hit goto loc_g_1386; if (ax == fiOrangeDisk) // orange disk hit goto loc_g_1386; // play the infotron sound, 'cause infotron hits something "hard" subSoundFX(si, fiInfotron, actImpact); if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) return; // infotron rolls somewhere ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll left goto loc_g_133A; ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll right goto loc_g_1350; return; loc_g_132D: // go on falling down? PlayField16[si] = 0x7004; // go into intermediate waitstate PlayField16[si + FieldWidth] = 0x9999; // mark as "zonk waiting to access" return; loc_g_133A: // test if infotron may roll left // This if(if true) jumps up far above // to the according rountine for fixed infotrons! if (PlayField16[si - 1] != 0) // Remarkable!!! ' loc_g_0EF4: goto loc_g_11BD; MovHighByte(&PlayField16[si], 0x50); // infotron rolls left PlayField16[si - 1] = 0x8888; return; loc_g_1350: // test if infotron may roll right if (PlayField16[si + 1] != 0) return; MovHighByte(&PlayField16[si], 0x60); // infotron rolls right PlayField16[si + 1] = 0x8888; return; loc_g_1364: // Murphy dies, but not in any case bl = HighByte(PlayField16[si + FieldWidth]); if (bl == 0xE || bl == 0xF || bl == 0x28) return; if (bl == 0x29 || bl == 0x25 || bl == 0x26) return; loc_g_1386: // someone dies/explodes immediately si = si + FieldWidth; // 1 field down ExplodeFieldSP(si); // Explode return; loc_g_138D: // infotron comes rolling from right to left // To Do: draw infotron rolling from right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniInfotronRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // get and increment sequence# if (bl == 0x24) PlayField16[si + 1] = 0xAAAA; if (bl == 0x26) { MovHighByte(&PlayField16[si], bl); subCleanUpForInfotronsAbove(si + 1); } else if (bl < 0x28) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0x7004; // go into intermediate state } return; loc_g_13E9: // infotron comes rolling from left to right // To Do: draw infotron rolling from left // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniInfotronRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x34) PlayField16[si - 1] = 0xAAAA; if (bl == 0x36) { MovHighByte(&PlayField16[si], bl); subCleanUpForInfotronsAbove(si - 1); } else if (bl < 0x38) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0x7004; // go into intermediate state } return; loc_g_1444: // infotron falls straight down bl = bl + 1; if (bl < 0x42) { MovHighByte(&PlayField16[si], bl); } else if (PlayField16[si + FieldWidth] != 0) { bl = bl - 1; // stay waiting MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1004; // go falling } return; loc_g_1472: // infotron rolls left // To Do: draw infotron rolling to left // according to position in (bl And &H0F) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0xF) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniInfotronRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // retrieve and increment sequence# if (bl < 0x52) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth - 1] != 0) goto loc_g_14D9; if (PlayField16[si - 1] != 0) { if (PlayField16[si - 1] != 0x8888) goto loc_g_14D9; } PlayField16[si] = 0xFFFF; si = si - 1; // 1 field left PlayField16[si] = 0x2204; PlayField16[si + FieldWidth] = 0x9999; return; loc_g_14D9: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_14E0: // infotron rolls right // To Do: draw infotron rolling to right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniInfotronRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl < 0x62) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth + 1] != 0) goto loc_g_1547; if (PlayField16[si + 1] != 0) { if (PlayField16[si + 1] != 0x8888) goto loc_g_1547; } PlayField16[si] = 0xFFFF; si = si + 1; PlayField16[si] = 0x3204; PlayField16[si + FieldWidth] = 0x9999; return; loc_g_1547: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_154E: // intermediate state ax = PlayField16[si + FieldWidth]; if (ax == 0 || ax == 0x9999) { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1004; // start falling down goto loc_g_1242; } } void subCleanUpForInfotronsAbove(int si) { int ax; if (LowByte(PlayField16[si]) != fiExplosion) PlayField16[si] = 0; if (PlayField16[si - FieldWidth] != 0) { if (PlayField16[si - FieldWidth] != 0x9999) return; if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiZonk) return; } if (PlayField16[si - FieldWidth - 1] == fiInfotron) goto loc_g_16FE; loc_g_16F6: if (PlayField16[si - FieldWidth + 1] == fiInfotron) goto loc_g_1722; return; loc_g_16FE: ax = PlayField16[si - 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth - 1] = 0x6004; PlayField16[si - FieldWidth] = 0x8888; return; } goto loc_g_16F6; loc_g_1722: ax = PlayField16[si + 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth + 1] = 0x5004; PlayField16[si - FieldWidth] = 0x8888; } } mirrormagic-3.0.0/src/game_sp/main_sp.h0000644000175000017500000000547713263212010017337 0ustar aeglosaeglos#ifndef MAIN_SP_H #define MAIN_SP_H /* ========================================================================= */ /* external functions and definitions imported from main program to game_sp */ /* ========================================================================= */ #include "../engines.h" #include "../conf_gfx.h" /* ========================================================================= */ /* functions and definitions that are exported from game_sp to main program */ /* ========================================================================= */ #include "export.h" /* ========================================================================= */ /* internal functions and definitions that are not exported to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* screen sizes and positions for SP engine */ extern int TILESIZE_VAR; #define TILESIZE 32 #define TILEX TILESIZE #define TILEY TILESIZE #define TILEX_VAR TILESIZE_VAR #define TILEY_VAR TILESIZE_VAR extern int SCR_FIELDX, SCR_FIELDY; #define MAX_BUF_XSIZE (2 + SCR_FIELDX + 2) #define MAX_BUF_YSIZE (2 + SCR_FIELDY + 2) /* often used screen positions */ extern int SX, SY; #define SXSIZE (SCR_FIELDX * TILEX_VAR) #define SYSIZE (SCR_FIELDY * TILEY_VAR) #define FXSIZE (MAX_BUF_XSIZE * TILEX_VAR) #define FYSIZE (MAX_BUF_YSIZE * TILEY_VAR) extern int REAL_SX, REAL_SY; #define FULL_SXSIZE (2 + SXSIZE + 2) #define FULL_SYSIZE (2 + SYSIZE + 2) /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* exported variables */ /* ------------------------------------------------------------------------- */ extern struct LevelInfo_SP native_sp_level; extern Bitmap *bitmap_db_field_sp; extern int GfxElementLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; extern int GfxGraphicLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; extern int GfxGraphic[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; extern int GfxFrame[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ #endif /* MAIN_SP_H */ mirrormagic-3.0.0/src/game_sp/global.h0000644000175000017500000000134213263212010017134 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // global.h // ---------------------------------------------------------------------------- #ifndef GAME_SP_GLOBAL_H #define GAME_SP_GLOBAL_H #include "main_sp.h" #include "vb_lib.h" #include "ASM.h" #include "BugsTerminals.h" #include "DDScrollBuffer.h" #include "DDSpriteBuffer.h" #include "Display.h" #include "DoGameStuff.h" #include "Electrons.h" #include "Explosions.h" #include "Globals.h" #include "Infotrons.h" #include "InitGameConditions.h" #include "Input.h" #include "MainForm.h" #include "MainGameLoop.h" #include "Murphy.h" #include "OrangeDisk.h" #include "SnikSnaks.h" #include "Sound.h" #include "Zonk.h" #endif /* GAME_SP_GLOBAL_H */ mirrormagic-3.0.0/src/game_sp/MainGameLoop.c0000644000175000017500000000623113263212010020201 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // MainGameLoop.c // ---------------------------------------------------------------------------- #include "MainGameLoop.h" boolean bPlaying; int LeadOutCounter; int ExitToMenuFlag; boolean AutoScrollFlag; // ========================================================================== // SUBROUTINE // Play a game/demo // ========================================================================== void subMainGameLoop_Init() { // This was a bug in the original Supaplex: sometimes red disks could not // be released. This happened if Murphy was killed DURING a red disk release // and the next try started. RedDiskReleasePhase = 0; // (re-)enable red disk release } void subMainGameLoop_Main(byte action, boolean warp_mode) { // --------------------------------------------------------------------------- // --------------------- START OF GAME-BUSY LOOP ----------------------------- // --------------------------------------------------------------------------- subProcessKeyboardInput(action); // check keyboard, act on keys // --------------------------------------------------------------------------- // subDoGameStuff(); // do all game stuff // // --------------------------------------------------------------------------- subRedDiskReleaseExplosion(); // Red Disk release and explode subFollowUpExplosions(); // every explosion may cause up to 8 following explosions subCalculateScreenScrollPos(); // calculate screen start addrs if (AutoScrollFlag) ScrollTowards(ScreenScrollXPos, ScreenScrollYPos); TimerVar = TimerVar + 1; if (ExplosionShakeMurphy > 0) ExplosionShakeMurphy--; if (ExitToMenuFlag == 1) { // happens when demo ends or when Murphy enters exit (to be checked) } if (LeadOutCounter == 0) // no lead-out: game busy return; // --------------------------------------------------------------------------- // ---------------------- END OF GAME-BUSY LOOP ------------------------------ // --------------------------------------------------------------------------- LeadOutCounter = LeadOutCounter - 1; // do more lead-out after quit if (LeadOutCounter != 0) // lead-out not ready: more return; // lead-out done: exit now // ---------------------- END OF GAME-BUSY LOOP (including lead-out) --------- /* if the game is not won when reaching this point, then it is lost */ if (!game_sp.LevelSolved) game_sp.GameOver = TRUE; } void subCalculateScreenScrollPos() { int jump_pos = TILEX / 2; /* handle wrap-around */ if (MurphyScreenXPos < -jump_pos) { MurphyScreenXPos = FieldWidth * TILEX + MurphyScreenXPos; MurphyScreenYPos -= TILEY; } else if (MurphyScreenXPos >= FieldWidth * TILEX - jump_pos) { MurphyScreenXPos = MurphyScreenXPos - FieldWidth * TILEX; MurphyScreenYPos += TILEY; } if (ExplosionShake != 0) { subGetRandomNumber(); // printf("::: ExplosionShake [%d]\n", FrameCounter); } ScreenScrollXPos = MurphyScreenXPos - (SCR_FIELDX / 2) * TILESIZE; ScreenScrollYPos = MurphyScreenYPos - (SCR_FIELDY / 2) * TILESIZE; } mirrormagic-3.0.0/src/game_sp/OrangeDisk.c0000644000175000017500000000414513263212010017721 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // OrangeDisk.c // ---------------------------------------------------------------------------- #include "OrangeDisk.h" // ========================================================================== // SUBROUTINE // Animate/move orange disks (falling) // ========================================================================== void subAnimateOrangeDisks(int si) { int ax, bl, dx, X, Y; ax = PlayField16[si]; if (LowByte(ax) != fiOrangeDisk) return; if (ax >= 0x3008) // disk is falling goto loc_g_2804; if (ax >= 0x2008) // disk is in wait state before falling goto loc_g_27DA; if (PlayField16[si + FieldWidth] == 0) goto loc_g_27CF; return; loc_g_27CF: // below is empty -> disk may start to fall MovHighByte(&PlayField16[si], 0x20); MovHighByte(&PlayField16[si + FieldWidth], fiOrangeDisk); return; loc_g_27DA: if (PlayField16[si + FieldWidth] == 0) { PlayField16[si] = fiOrangeDisk; return; } // loc_g_27E8: bl = HighByte(PlayField16[si]) + 1; if (bl == 0x22) // wait phase is finished bl = 0x30; MovHighByte(&PlayField16[si], bl); return; loc_g_2804: // disk is falling // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dx = HighByte(PlayField16[si]) & 0x7; X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + TwoPixels * (dx + 1), aniOrangeDisk, dx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if ((bl & 0x7) != 0) { MovHighByte(&PlayField16[si], bl); return; } PlayField16[si] = 0; PlayField16[si + FieldWidth] = fiOrangeDisk; si = si + FieldWidth; if (PlayField16[si + FieldWidth] == 0) { MovHighByte(&PlayField16[si], 0x30); // go on falling down MovHighByte(&PlayField16[si + FieldWidth], fiOrangeDisk); return; } // loc_g_2867: if (LowByte(PlayField16[si + FieldWidth]) == fiExplosion) return; ExplodeFieldSP(si); // Explode } mirrormagic-3.0.0/src/game_sp/Display.h0000644000175000017500000000113613263212010017302 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Display.h // ---------------------------------------------------------------------------- #ifndef DISPLAY_H #define DISPLAY_H #include "global.h" extern int ScreenScrollXPos, ScreenScrollYPos; extern int ExplosionShake, ExplosionShakeMurphy; extern boolean NoDisplayFlag; extern int DisplayMinX, DisplayMaxX; extern int DisplayMinY, DisplayMaxY; extern void subDisplayLevel(); extern void ScrollTo(int, int); extern void ScrollTowards(int, int); extern void SoftScrollTo(int, int, int, int); #endif /* DISPLAY_H */ mirrormagic-3.0.0/src/game_sp/Globals.c0000644000175000017500000000761613263212010017264 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Globals.c // ---------------------------------------------------------------------------- #include "Globals.h" boolean LevelLoaded; boolean DemoAvailable; boolean menBorder; int FieldWidth; // standard size = 60 int FieldHeight; // standard size = 24 int HeaderSize; // standard size = 96 int FieldMax, LevelMax; int *PlayField16; byte *PlayField8; byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; int TimerVar; short RandomSeed; int FreezeZonks; LevelInfoType LInfo; int ScrollMinX, ScrollMaxX, ScrollMinY, ScrollMaxY; int ScrollX, ScrollY; int MurphyPosIndex, MurphyXPos, MurphyYPos; int MurphyScreenXPos, MurphyScreenYPos; int MurphyExplodePos, SplitMoveFlag, RedDiskReleaseMurphyPos; int KillMurphyFlag, MurphyMoveCounter; int YawnSleepCounter; int MurphyVarFaceLeft; int ScratchGravity, GravityFlag; int RedDiskReleaseFlag, MovingPictureSequencePhase; int YellowDisksExploded; int AllowRedDiskCheat, AllowEatRightRedDiskBug; int GameBusyFlag; int InfotronsNeeded, TotalInfotronsNeeded; int RedDiskCount; int SnikSnaksElectronsFrozen; int DemoKeyCode; int RedDiskReleasePhase; int fiGraphic[] = { aniSpace, aniZonk, aniBase, aniMurphy, aniInfotron, aniRAM, aniHardWare, aniExit, aniOrangeDisk, aniPortRight, aniPortDown, aniPortLeft, aniPortUp, aniSpPortRight, aniSpPortDown, aniSpPortLeft, aniSpPortUp, aniSnikSnak, aniYellowDisk, aniTerminal, aniRedDisk, aniPortUpAndDown, aniPortLeftAndRight, aniPortAllDirections, aniElectron, aniBug, aniRAMLeft, aniRAMRight, aniHW0, aniHW1, aniHW2, aniHW3, aniHW4, aniHW5, aniHW6, aniHW7, aniHW8, aniHW9, aniRAMTop, aniRAMBottom, aniWallSpace }; int aniSnikSnakTurningLeft[] = { aniSnikSnakTurnUpToLeft, aniSnikSnakTurnLeftToDown, aniSnikSnakTurnDownToRight, aniSnikSnakTurnRightToUp }; int aniSnikSnakTurningRight[] = { aniSnikSnakTurnUpToRight, aniSnikSnakTurnRightToDown, aniSnikSnakTurnDownToLeft, aniSnikSnakTurnLeftToUp }; int getSequenceLength(int sequence) { switch (sequence) { case aniBug: return 14; case aniElectron: case aniExplosion: return 9; case aniTouchInfotron: return 7; case aniMurphyExit: return 40; case aniRedDisk: return 1; default: return 8; } } boolean isSnappingSequence(int sequence) { switch (sequence) { case aniTouchBase: case aniTouchInfotron: case aniTouchRedDisk: return TRUE; default: return FALSE; } } void InitGlobals() { InitPrecedingPlayfieldMemory(); AutoScrollFlag = True; FreezeZonks = 0; LevelLoaded = False; FieldWidth = 60; FieldHeight = 24; HeaderSize = 96; FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1; LevelMax = (FieldWidth * FieldHeight) - 1; bPlaying = False; menBorder = False; /* add preceding playfield buffer (as large as preceding memory area) */ PlayField16 = checked_calloc((game_sp.preceding_buffer_size + SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE) * sizeof(int)); PlayField16 = &PlayField16[game_sp.preceding_buffer_size]; /* add preceding playfield buffer (as large as one playfield row) */ PlayField8 = checked_calloc((SP_MAX_PLAYFIELD_WIDTH + SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE) * sizeof(byte)); PlayField8 = &PlayField8[SP_MAX_PLAYFIELD_WIDTH]; } int GetSI(int X, int Y) { return Y * FieldWidth + X; } int GetX(int si) { return si % FieldWidth; } int GetY(int si) { return si / FieldWidth; } int GetStretchX(int si) { return StretchWidth * (si % FieldWidth); } int GetStretchY(int si) { return StretchWidth * (si / FieldWidth); } void PrepareLevel() { copyInternalEngineVars_SP(); SetDisplayRegion(); SetScrollEdges(); LevelLoaded = True; } int Min(int A, int B) { return (A < B ? A : B); } int Max(int A, int B) { return (A < B ? B : A); } mirrormagic-3.0.0/src/game_sp/Globals.h0000644000175000017500000002520113263212010017257 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Globals.h // ---------------------------------------------------------------------------- #ifndef GLOBALS_H #define GLOBALS_H #include "global.h" #ifndef False #define False 0 #define True (!False) #endif #define ScrollDelta ((int)1) #define ZoomFactor (2) #define StretchWidth (ZoomFactor * 16) #define TwoPixels (ZoomFactor * 2) // ---------------------------------------------------------------------------- // elements (stored in file and playfield) // ---------------------------------------------------------------------------- #define fiSpace (0) #define fiZonk (1) #define fiBase (2) #define fiMurphy (3) #define fiInfotron (4) #define fiRAM (5) #define fiHardWare (6) #define fiExit (7) #define fiOrangeDisk (8) #define fiPortRight (9) #define fiPortDown (10) #define fiPortLeft (11) #define fiPortUp (12) #define fiSpPortRight (13) #define fiSpPortDown (14) #define fiSpPortLeft (15) #define fiSpPortUp (16) #define fiSnikSnak (17) #define fiYellowDisk (18) #define fiTerminal (19) #define fiRedDisk (20) #define fiPortUpAndDown (21) #define fiPortLeftAndRight (22) #define fiPortAllDirections (23) #define fiElectron (24) #define fiBug (25) #define fiRAMLeft (26) #define fiRAMRight (27) #define fiHWFirst (28) #define fiHW0 (fiHWFirst + 0) // fiHWFirst #define fiHW1 (fiHWFirst + 1) #define fiHW2 (fiHWFirst + 2) #define fiHW3 (fiHWFirst + 3) #define fiHW4 (fiHWFirst + 4) #define fiHW5 (fiHWFirst + 5) #define fiHW6 (fiHWFirst + 6) #define fiHW7 (fiHWFirst + 7) #define fiHW8 (fiHWFirst + 8) #define fiHW9 (fiHWFirst + 9) // fiHWLast #define fiHWLast (37) #define fiRAMTop (38) #define fiRAMBottom (39) #define fiWallSpace (40) #define fiExplosion (0x1F) #define fiFirst (0) #define fiLast (40) // ---------------------------------------------------------------------------- // graphics and animations (used at runtime to display the elements) // ---------------------------------------------------------------------------- // graphics and animations directly related to file elements #define aniSpace IMG_EMPTY_SPACE #define aniZonk IMG_SP_ZONK #define aniBase IMG_SP_BASE #define aniMurphy IMG_SP_MURPHY #define aniInfotron IMG_SP_INFOTRON #define aniRAM IMG_SP_CHIP_SINGLE #define aniHardWare IMG_SP_HARDWARE_GRAY #define aniExit IMG_SP_EXIT_CLOSED #define aniOrangeDisk IMG_SP_DISK_ORANGE #define aniPortRight IMG_SP_PORT_RIGHT #define aniPortDown IMG_SP_PORT_DOWN #define aniPortLeft IMG_SP_PORT_LEFT #define aniPortUp IMG_SP_PORT_UP #define aniSpPortRight IMG_SP_GRAVITY_PORT_RIGHT #define aniSpPortDown IMG_SP_GRAVITY_PORT_DOWN #define aniSpPortLeft IMG_SP_GRAVITY_PORT_LEFT #define aniSpPortUp IMG_SP_GRAVITY_PORT_UP #define aniSnikSnak IMG_SP_SNIKSNAK #define aniYellowDisk IMG_SP_DISK_YELLOW #define aniTerminal IMG_SP_TERMINAL #define aniRedDisk IMG_SP_DISK_RED #define aniPortUpAndDown IMG_SP_PORT_VERTICAL #define aniPortLeftAndRight IMG_SP_PORT_HORIZONTAL #define aniPortAllDirections IMG_SP_PORT_ANY #define aniElectron IMG_SP_ELECTRON #define aniBug IMG_SP_BUGGY_BASE #define aniRAMLeft IMG_SP_CHIP_LEFT #define aniRAMRight IMG_SP_CHIP_RIGHT #define aniHWFirst IMG_SP_HARDWARE_BASE_1 #define aniHW0 IMG_SP_HARDWARE_BASE_1 #define aniHW1 IMG_SP_HARDWARE_GREEN #define aniHW2 IMG_SP_HARDWARE_BLUE #define aniHW3 IMG_SP_HARDWARE_RED #define aniHW4 IMG_SP_HARDWARE_YELLOW #define aniHW5 IMG_SP_HARDWARE_BASE_2 #define aniHW6 IMG_SP_HARDWARE_BASE_3 #define aniHW7 IMG_SP_HARDWARE_BASE_4 #define aniHW8 IMG_SP_HARDWARE_BASE_5 #define aniHW9 IMG_SP_HARDWARE_BASE_6 #define aniHWLast IMG_SP_HARDWARE_BASE_6 #define aniRAMTop IMG_SP_CHIP_TOP #define aniRAMBottom IMG_SP_CHIP_BOTTOM #define aniWallSpace IMG_INVISIBLE_WALL #define aniHWTrash1 #define aniHWTrash2 #define aniHWMurphy // graphics and animations related to in-game animations for element actions #define aniMurphyDropping IMG_SP_MURPHY_DROPPING #define aniMurphySleepLeft IMG_SP_MURPHY_SLEEPING_LEFT #define aniMurphySleepRight IMG_SP_MURPHY_SLEEPING_RIGHT #define aniMurphyTouchLeft IMG_SP_MURPHY_SNAPPING_LEFT #define aniMurphyTouchRight IMG_SP_MURPHY_SNAPPING_RIGHT #define aniMurphyTouchUp IMG_SP_MURPHY_SNAPPING_UP #define aniMurphyTouchDown IMG_SP_MURPHY_SNAPPING_DOWN #define aniMurphyYawn IMG_SP_MURPHY_BORING_1 #define aniPushLeft IMG_SP_MURPHY_PUSHING_LEFT #define aniPushRight IMG_SP_MURPHY_PUSHING_RIGHT #define aniBugActivating IMG_SP_BUGGY_BASE_ACTIVATING #define aniBugDeactivating IMG_SP_BUGGY_BASE_ACTIVATING #define aniBugActive IMG_SP_BUGGY_BASE_ACTIVE #define aniZonkRollLeft IMG_SP_ZONK_MOVING_LEFT #define aniZonkRollRight IMG_SP_ZONK_MOVING_RIGHT #define aniEatInfotronLeft IMG_SP_MURPHY_COLLECTING_LEFT #define aniEatInfotronRight IMG_SP_MURPHY_COLLECTING_RIGHT #define aniInfotronRollLeft IMG_SP_INFOTRON_MOVING_LEFT #define aniInfotronRollRight IMG_SP_INFOTRON_MOVING_RIGHT #define aniMurphyMoveLeft IMG_SP_MURPHY_MOVING_LEFT #define aniMurphyMoveRight IMG_SP_MURPHY_MOVING_RIGHT #define aniMurphyMoveUpLeft IMG_SP_MURPHY_MOVING_LEFT #define aniMurphyMoveUpRight IMG_SP_MURPHY_MOVING_RIGHT #define aniMurphyDigLeft IMG_SP_MURPHY_DIGGING_LEFT #define aniMurphyDigRight IMG_SP_MURPHY_DIGGING_RIGHT #define aniMurphyDigUpLeft IMG_SP_MURPHY_DIGGING_LEFT #define aniMurphyDigUpRight IMG_SP_MURPHY_DIGGING_RIGHT #define aniMurphyEatLeft IMG_SP_MURPHY_COLLECTING_LEFT #define aniMurphyEatRight IMG_SP_MURPHY_COLLECTING_RIGHT #define aniMurphyEatUpLeft IMG_SP_MURPHY_COLLECTING_LEFT #define aniMurphyEatUpRight IMG_SP_MURPHY_COLLECTING_RIGHT #define aniSplitUpDown IMG_SP_MURPHY #define aniMurphyExit IMG_SP_MURPHY_SHRINKING #define aniElectron IMG_SP_ELECTRON #define aniExplosion IMG_SP_DEFAULT_EXPLODING #define aniTouchBase IMG_SP_BASE_SNAPPING #define aniTouchInfotron IMG_SP_INFOTRON_COLLECTING #define aniTouchRedDisk IMG_SP_DISK_RED_COLLECTING #define aniYellowDisk IMG_SP_DISK_YELLOW #define aniOrangeDisk IMG_SP_DISK_ORANGE #define aniRedDisk IMG_SP_DISK_RED #define aniSnikSnakDown IMG_SP_SNIKSNAK_DOWN #define aniSnikSnakLeft IMG_SP_SNIKSNAK_LEFT #define aniSnikSnakRight IMG_SP_SNIKSNAK_RIGHT #define aniSnikSnakUp IMG_SP_SNIKSNAK_UP #define aniSnikSnakTurnLeftToUp IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP #define aniSnikSnakTurnLeftToDown IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN #define aniSnikSnakTurnRightToUp IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP #define aniSnikSnakTurnRightToDown IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN #define aniSnikSnakTurnUpToLeft IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT #define aniSnikSnakTurnUpToRight IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT #define aniSnikSnakTurnDownToLeft IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT #define aniSnikSnakTurnDownToRight IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT #define aniTerminalActive IMG_SP_TERMINAL_ACTIVE #define aniDefaultExplosion IMG_SP_DEFAULT_EXPLODING #define aniElectronExplosion IMG_SP_ELECTRON_EXPLODING #define imgFrameCorner IMG_SP_FRAME_CORNER #define imgFrameHorizontal IMG_SP_FRAME_HORIZONTAL #define imgFrameVertical IMG_SP_FRAME_VERTICAL // ---------------------------------------------------------------------------- // input keys // ---------------------------------------------------------------------------- #define keyNone (0) #define keyUp (1) #define keyLeft (2) #define keyDown (3) #define keyRight (4) #define keySpaceUp (5) #define keySpaceLeft (6) #define keySpaceDown (7) #define keySpaceRight (8) #define keySpace (9) // ---------------------------------------------------------------------------- // data structures // ---------------------------------------------------------------------------- #ifndef HAS_LevelDescriptor typedef struct { int Width; int Height; int OffSet; int Size; } LevelDescriptor; #define HAS_LevelDescriptor #endif #ifndef HAS_SpecialPortType typedef struct { short PortLocation; // = 2*(x+(y*60)) byte Gravity; // 1 = turn on, anything else (0) = turn off byte FreezeZonks; // 2 = turn on, anything else (0) = turn off (1=off!) byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off byte UnUsed; } SpecialPortType; #define HAS_SpecialPortType #endif #ifndef HAS_LevelInfoType typedef struct { byte UnUsed[4]; byte InitialGravity; // 1=on, anything else (0) = off byte Version; // SpeedFixVersion XOR &H20 char LevelTitle[23]; byte InitialFreezeZonks; // 2=on, anything else (0) = off. (1=off too!) byte InfotronsNeeded; // Number of Infotrons needed. 0 means that Supaplex will count the total // amount of Infotrons in the level, and use the low byte of that number. // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!) byte SpecialPortCount; // Maximum 10 allowed! SpecialPortType SpecialPort[10]; byte SpeedByte; // = Speed XOR Highbyte(RandomSeed) byte CheckSumByte; // = CheckSum XOR SpeedByte short DemoRandomSeed; } LevelInfoType; #define HAS_LevelInfoType #endif extern int GetSI(int X, int Y); extern int GetStretchX(int si); extern int GetStretchY(int si); extern int GetX(int si); extern int GetY(int si); extern void InitGlobals(); extern void PrepareLevel(); extern int getSequenceLength(int sequence); extern boolean isSnappingSequence(int sequence); extern int Min(int A, int B); extern int Max(int A, int B); extern int fiGraphic[]; extern int aniSnikSnakTurningLeft[]; extern int aniSnikSnakTurningRight[]; extern boolean LevelLoaded; extern boolean DemoAvailable; extern boolean menBorder; extern int *PlayField16; extern byte *PlayField8; extern byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; extern int FieldHeight; extern int FieldMax, LevelMax; extern int FieldWidth; extern int FreezeZonks; extern int HeaderSize; extern int TimerVar; extern short RandomSeed; extern LevelInfoType LInfo; extern int ScrollMinX, ScrollMaxX, ScrollMinY, ScrollMaxY; extern int ScrollX, ScrollY; extern int AllowRedDiskCheat, AllowEatRightRedDiskBug; extern int Data_SubRest, Data_SubRstFlg; extern int DemoKeyCode; extern int GameBusyFlag; extern int InfotronsNeeded, TotalInfotronsNeeded; extern int KillMurphyFlag, MurphyMoveCounter; extern int MurphyExplodePos, SplitMoveFlag, RedDiskReleaseMurphyPos; extern int MurphyPosIndex, MurphyXPos, MurphyYPos; extern int MurphyScreenXPos, MurphyScreenYPos; extern int MurphyVarFaceLeft; extern int RedDiskCount; extern int RedDiskReleaseFlag, MovingPictureSequencePhase; extern int RedDiskReleasePhase; extern int ScratchGravity, GravityFlag; extern int SnikSnaksElectronsFrozen; extern int YellowDisksExploded; extern int YawnSleepCounter; #endif /* GLOBALS_H */ mirrormagic-3.0.0/src/game_sp/Makefile0000644000175000017500000000455413263212010017173 0ustar aeglosaeglos# ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1995-2014 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # The native Supaplex game engine is based on: # - MegaPlex version 0.5 beta release xmas 2001 by Frank Schindler # - Speed Fix 6.3+ by Herman Perk # - Supaplex by Michael Stopp & Philip Jespersen # ----------------------------------------------------------------------------- # src/game_sp/Makefile # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = init.c \ file.c \ main.c \ vb_lib.c \ \ ASM.c \ BugsTerminals.c \ DDScrollBuffer.c \ DDSpriteBuffer.c \ Display.c \ DoGameStuff.c \ Electrons.c \ Explosions.c \ Globals.c \ Infotrons.c \ InitGameConditions.c \ Input.c \ MainForm.c \ MainGameLoop.c \ Murphy.c \ OrangeDisk.c \ SnikSnaks.c \ Sound.c \ Zonk.c OBJS = init.o \ file.o \ main.o \ vb_lib.o \ \ ASM.o \ BugsTerminals.o \ DDScrollBuffer.o \ DDSpriteBuffer.o \ Display.o \ DoGameStuff.o \ Electrons.o \ Explosions.o \ Globals.o \ Infotrons.o \ InitGameConditions.o \ Input.o \ MainForm.o \ MainGameLoop.o \ Murphy.o \ OrangeDisk.o \ SnikSnaks.o \ Sound.o \ Zonk.o GAME_SP = game_sp.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(GAME_SP) $(GAME_SP): $(OBJS) $(AR) cru $(GAME_SP) $(OBJS) $(RANLIB) $(GAME_SP) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(GAME_SP) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif mirrormagic-3.0.0/src/game_sp/Electrons.h0000644000175000017500000000157613263212010017643 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Electrons.h // ---------------------------------------------------------------------------- #ifndef ELECTRONS_H #define ELECTRONS_H #include "global.h" extern void subAnimateElectrons(int); extern void subDrawAnimatedElectrons(int); extern void subDrawElectronFromAbove(int, int); extern void subDrawElectronFromBelow(int, int); extern void subDrawElectronFromLeft(int, int); extern void subDrawElectronFromRight(int, int); extern void subDrawElectronTurnLeft(int, int); extern void subDrawElectronTurnRight(int, int); extern void subElectronFromAbove(int, int); extern void subElectronFromBelow(int, int); extern void subElectronFromLeft(int, int); extern void subElectronFromRight(int, int); extern void subElectronTurnLeft(int, int); extern void subElectronTurnRight(int, int); #endif /* ELECTRONS_H */ mirrormagic-3.0.0/src/game_sp/Infotrons.h0000644000175000017500000000053513263212010017660 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Infotrons.h // ---------------------------------------------------------------------------- #ifndef INFOTRONS_H #define INFOTRONS_H #include "global.h" extern void subAnimateInfotrons(int); extern void subCleanUpForInfotronsAbove(int); #endif /* INFOTRONS_H */ mirrormagic-3.0.0/src/game_sp/Zonk.c0000644000175000017500000002760513263212010016622 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Zonk.c // ---------------------------------------------------------------------------- #include "Zonk.h" void subCleanUpForZonksAbove(int si); // static char *VB_Name = "modZonk"; // --- Option Explicit // ========================================================================== // SUBROUTINE // Animate Zonks (falling) // ========================================================================== void subAnimateZonks(int si) { int tFld; // PseudoRegisters: // int ax, bx, cx, dx, di, X, Y; int ax, bx, dx, X, Y; // int ah, bh, ch, dh, al, bl, cl, dl; int al, bl; tFld = PlayField16[si]; if ((tFld & 0xFF) != fiZonk) return; if (tFld == fiZonk) { if (FreezeZonks == 2) // Do Zonks fall? (debug) return; ax = PlayField16[si + FieldWidth]; // select case playfield16(si+60) if (ax == 0) goto loc_g_0D64; if (ax == fiZonk) goto loc_g_0D35; if (ax == fiInfotron) goto loc_g_0D35; if (ax == fiRAM) goto loc_g_0D35; return; loc_g_0D35: // Case fiZonk, fiInfotron, fiRAM ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_0D6B; loc_g_0D4C: ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) goto loc_g_0D81; return; loc_g_0D64: // Case fiSpace MovHighByte(&PlayField16[si], 0x40); goto loc_g_0DA5; loc_g_0D6B: // roll left? if (PlayField16[si - 1] == 0) goto loc_g_0D74; goto loc_g_0D4C; loc_g_0D74: MovHighByte(&PlayField16[si], 0x50); PlayField16[si - 1] = 0x8888; goto loc_g_0DA5; loc_g_0D81: // roll right? if (PlayField16[si + 1] == 0) goto loc_g_0D98; if (PlayField16[si + 1] != 0x9999) // wow right is different from left! return; if (LowByte(PlayField16[si - FieldWidth + 1]) != 1) return; loc_g_0D98: MovHighByte(&PlayField16[si], 0x60); PlayField16[si + 1] = 0x8888; } // tFld = fiZonk loc_g_0DA5: // from now on the zonk is definitely moving, // maybe the sequence is in an advanced frame // or just beeing initialized due to the code above bl = HighByte(PlayField16[si]); bx = 0; MovLowByte(&bx, bl); al = bl & 0xF0; if (al == 0x10) // zonk comes falling from above goto loc_g_0DE8; if (al == 0x20) // zonk comes rolling from right to left goto loc_g_0F83; if (al == 0x30) // zonk comes rolling from left to right goto loc_g_0FE8; if (FreezeZonks == 2) return; if (al == 0x40) // zonk falls straight down goto loc_g_104D; if (al == 0x50) // zonk rolls left goto loc_g_107B; if (al == 0x60) // zonk rolls right goto loc_g_10E9; if (al == 0x70) // intermediate state goto loc_g_1157; return; loc_g_0DE8: // zonk comes falling from above // To Do: draw zonk falling from above // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); dx = bl & 0x7; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + TwoPixels * (dx + 1), aniZonk, dx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x16) { MovHighByte(&PlayField16[si], bl); subCleanUpForZonksAbove(si - FieldWidth); return; } // loc_g_0E2B: if (bl < 0x18) { MovHighByte(&PlayField16[si], bl); return; } // loc_g_0E35: MovHighByte(&PlayField16[si], 0); // zonk arrived at the field if ((FreezeZonks & 0xFF) == 2) return; // loc_g_0E42: // now check if the zonk may go on falling somehow ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty!-> go on falling 'loc_g_0E4C: goto loc_g_0EDD; if (ax == 0x9999) // below is only temporarily used ' loc_g_0E57: goto loc_g_0EDD; if ((ax & 0xFF) == fiMurphy) // Murphy dies 'loc_g_0E61: goto loc_g_0F14; if ((ax & 0xFF) == fiSnikSnak) // SnikSnak dies 'loc_g_0E6B: goto loc_g_0F6E; if (ax == 0x2BB) // loc_g_0E76: goto loc_g_0F36; if (ax == 0x4BB) // loc_g_0E81: goto loc_g_0F52; if ((ax & 0xFF) == fiElectron) // Electron cracked! 'loc_g_0E8B: goto loc_g_0F6E; if (ax == fiOrangeDisk) // OrangeDisk explodes 'loc_g_0E95: goto loc_g_0F75; // play the zonk sound, 'cause zonk hits something "hard" subSoundFX(si, fiZonk, actImpact); if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) return; // loc_g_0EAE: ' Zonk rolls somewhere ax = PlayField16[si + FieldWidth - 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll left goto loc_g_0EEA; ax = PlayField16[si + FieldWidth + 1]; if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll right goto loc_g_0F00; return; loc_g_0EDD: // go on falling down? PlayField16[si] = 0x7001; // go into intermediate waitstate PlayField16[si + FieldWidth] = 0x9999; // mark as "zonk waiting to access" return; loc_g_0EEA: // test if zonk may roll left // This if(if true) jumps up far above // to the according rountine for fixed zonks! if (PlayField16[si - 1] != 0) // Remarkable!!! ' loc_g_0EF4: goto loc_g_0D4C; MovHighByte(&PlayField16[si], 0x50); // zonk rolls left PlayField16[si - 1] = 0x8888; // mark as zonk accessing? return; loc_g_0F00: // test if zonk may roll right if (PlayField16[si + 1] != 0) // loc_g_0F08: return; MovHighByte(&PlayField16[si], 0x60); // zonk rolls right PlayField16[si + 1] = 0x8888; // mark as zonk accessing? return; loc_g_0F14: // Murphy dies, but not in any case bl = HighByte(PlayField16[si + FieldWidth]); if (bl == 0xE || bl == 0xF || bl == 0x28) return; if (bl == 0x29 || bl == 0x25 || bl == 0x26) return; loc_g_0F36: // ?? ax = LowByte(PlayField16[si + FieldWidth - 1]); if (ax == fiElectron) // loc_g_0F43: PlayField16[si + FieldWidth] = fiElectron; if (ax != 0x1F) PlayField16[si + FieldWidth - 1] = 0; goto loc_g_0F6E; loc_g_0F52: // ?? ax = LowByte(PlayField16[si + FieldWidth + 1]); if (ax == fiElectron) // loc_g_0F5F: PlayField16[si + FieldWidth] = fiElectron; if (ax != 0x1F) PlayField16[si + FieldWidth + 1] = 0; goto loc_g_0F6E; loc_g_0F6E: // someone dies/explodes si = si + FieldWidth; // 1 field down ExplodeFieldSP(si); // Explode return; loc_g_0F75: // OrangeDisk explodes next cycle si = si + FieldWidth; // 1 field down PlayField8[si] = fiHardWare; return; loc_g_0F83: // zonk comes rolling from right to left // To Do: draw zonk rolling from right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniZonkRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // get and increment sequence# if (bl == 0x24) PlayField16[si + 1] = 0xAAAA; if (bl == 0x26) { MovHighByte(&PlayField16[si], bl); subCleanUpForZonksAbove(si + 1); } else if (bl < 0x28) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // convert rolling zonk to a falling zonk } return; loc_g_0FE8: // zonk comes rolling from left to right // To Do: draw zonk rolling from left // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniZonkRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl == 0x34) PlayField16[si - 1] = 0xAAAA; if (bl == 0x36) { MovHighByte(&PlayField16[si], bl); subCleanUpForZonksAbove(si - 1); } else if (bl < 0x38) { MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // convert rolling zonk to a falling zonk } return; loc_g_104D: // zonk falls straight down bl = bl + 1; if (bl < 0x42) { MovHighByte(&PlayField16[si], bl); } else if (PlayField16[si + FieldWidth] != 0) { bl = bl - 1; // stay waiting MovHighByte(&PlayField16[si], bl); } else { PlayField16[si] = 0xFFFF; // mark as "zonk leaving" si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // go falling } return; loc_g_107B: // zonk rolls left // To Do: draw zonk rolling to left // according to position in (bl And &H0F) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0xF) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - (TwoPixels * dx), Y, aniZonkRollLeft, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; // retrieve and increment sequence# if (bl < 0x52) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth - 1] != 0) goto loc_g_10E2; if (PlayField16[si - 1] != 0) { if (PlayField16[si - 1] != 0x8888) goto loc_g_10E2; } // loc_g_10C8: PlayField16[si] = 0xFFFF; si = si - 1; // 1 field left PlayField16[si] = 0x2201; PlayField16[si + FieldWidth] = 0xFFFF; return; loc_g_10E2: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_10E9: // zonk rolls right // To Do: draw zonk rolling to right // according to position in (bl And &H07) // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); dx = (bl & 0x7) + 1; DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + (TwoPixels * dx), Y, aniZonkRollRight, dx - 1); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bl = HighByte(PlayField16[si]) + 1; if (bl < 0x62) { MovHighByte(&PlayField16[si], bl); return; } if (PlayField16[si + FieldWidth + 1] != 0) goto loc_g_1150; if (PlayField16[si + 1] != 0) { if (PlayField16[si + 1] != 0x8888) goto loc_g_1150; } PlayField16[si] = 0xFFFF; si = si + 1; PlayField16[si] = 0x3201; PlayField16[si + FieldWidth] = 0xFFFF; return; loc_g_1150: // stay waiting bl = bl - 1; MovHighByte(&PlayField16[si], bl); return; loc_g_1157: // intermediate state ax = PlayField16[si + FieldWidth]; if (ax == 0 || ax == 0x9999) { PlayField16[si] = 0xFFFF; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x1001; // start falling down goto loc_g_0DE8; } return; } // subAnimateZonks endp void subCleanUpForZonksAbove(int si) { int ax; if (LowByte(PlayField16[si]) != fiExplosion) PlayField16[si] = 0; if (PlayField16[si - FieldWidth] != 0) { if (PlayField16[si - FieldWidth] != 0x9999) return; if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiInfotron) return; } // loc_g_1674: if (PlayField16[si - FieldWidth - 1] != fiZonk) { if (PlayField16[si - FieldWidth + 1] != fiZonk) return; goto loc_g_16A7; } ax = PlayField16[si - 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth - 1] = 0x6001; PlayField16[si - FieldWidth] = 0x8888; return; } if (PlayField16[si - FieldWidth + 1] != fiZonk) return; loc_g_16A7: ax = PlayField16[si + 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { PlayField16[si - FieldWidth + 1] = 0x5001; PlayField16[si - FieldWidth] = 0x8888; } return; } // subCleanUpForZonksAbove mirrormagic-3.0.0/src/game_sp/ASM.c0000644000175000017500000000104713263212010016311 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // ASM.c // ---------------------------------------------------------------------------- #include "ASM.h" void MovLowByte(int *p, int i) { *p = (*p & 0xff00) | (i & 0xff); } void MovHighByte(int *p, int i) { *p = (*p & 0xff) | ((i << 8) & 0xff00); } int LowByte(int i) { return (i & 0xff); } int HighByte(int i) { return ((i >> 8) & 0xff); } int SgnHighByte(int i) { return (signed char)HighByte(i); } int ByteToInt(byte b) { return (signed char)b; } mirrormagic-3.0.0/src/game_sp/MainForm.c0000644000175000017500000001200313263212010017373 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // MainForm.c // ---------------------------------------------------------------------------- #include "MainForm.h" static void DrawFrame(int Delta); static void ReStretch(); void DrawField(int X, int Y); void DrawFieldAnimated(int X, int Y); void DrawFieldNoAnimated(int X, int Y); void DrawFrameIfNeeded() { DrawFrame(0); /* !!! CHECK THIS !!! */ if (! menBorder) DrawFrame(1); } void DisplayLevel() { int X, Y; if (! LevelLoaded) return; ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); ClearRectangle(bitmap_db_field_sp, 0, 0, FXSIZE, FYSIZE); SetDisplayRegion(); DrawFrameIfNeeded(); if (bPlaying) { for (Y = DisplayMinY; Y <= DisplayMaxY; Y++) for (X = DisplayMinX; X <= DisplayMaxX; X++) DrawFieldNoAnimated(X, Y); for (Y = DisplayMinY; Y <= DisplayMaxY; Y++) for (X = DisplayMinX; X <= DisplayMaxX; X++) DrawFieldAnimated(X, Y); } else { for (Y = DisplayMinY; Y <= DisplayMaxY; Y++) for (X = DisplayMinX; X <= DisplayMaxX; X++) DrawField(X, Y); } } void Form_Load() { InitGlobals(); ReStretch(); } static void DrawFrame(int Delta) { int i, LX, tY, RX, BY; LX = -1 + Delta; tY = -1 + Delta; RX = FieldWidth - Delta; BY = FieldHeight - Delta; DrawImage(LX, tY, (Delta > 0 ? imgFrameCorner : aniSpace)); DrawImage(LX, BY, (Delta > 0 ? imgFrameCorner : aniSpace)); DrawImage(RX, tY, (Delta > 0 ? imgFrameCorner : aniSpace)); DrawImage(RX, BY, (Delta > 0 ? imgFrameCorner : aniSpace)); for (i = LX + 1; i <= RX - 1; i++) { DrawImage(i, tY, (Delta > 0 ? imgFrameHorizontal : aniSpace)); DrawImage(i, BY, (Delta > 0 ? imgFrameHorizontal : aniSpace)); } for (i = tY + 1; i <= BY - 1; i++) { DrawImage(LX, i, (Delta > 0 ? imgFrameVertical : aniSpace)); DrawImage(RX, i, (Delta > 0 ? imgFrameVertical : aniSpace)); } if (Delta > 0) { // ... // ClearRectangle(bitmap_db_field_sp, } } static void RestoreFrame() { int i, LX, tY, RX, BY; LX = 0; tY = 0; RX = FieldWidth - 1; BY = FieldHeight - 1; for (i = LX; i <= RX; i++) { DrawField(i, tY); DrawField(i, BY); } for (i = tY + 1; i <= BY - 1; i++) { DrawField(LX, i); DrawField(RX, i); } } void SetDisplayRegion() { if (! menBorder) { DisplayMinX = 1; DisplayMinY = 1; DisplayMaxX = FieldWidth - 2; DisplayMaxY = FieldHeight - 2; if (LevelLoaded) DrawFrame(1); } else { DisplayMinX = 0; DisplayMinY = 0; DisplayMaxX = FieldWidth - 1; DisplayMaxY = FieldHeight - 1; if (LevelLoaded) RestoreFrame(); } } void menPlay_Click() { bPlaying = True; subFetchAndInitLevelB(); ReStretch(); subMainGameLoop_Init(); } static void ReStretch() { if (LevelLoaded) { SetDisplayRegion(); SetScrollEdges(); ScrollTo(ScrollX, ScrollY); DisplayLevel(); } subCalculateScreenScrollPos(); ScrollTo(ScreenScrollXPos, ScreenScrollYPos); } void SetScrollEdges() { int border1_offset = (menBorder ? 1 : 2); int border2_offset = (menBorder ? 0 : TILESIZE / 2); /* scroll correction for border frame (1 tile) or border element (2 tiles) */ ScrollMinX = 0; ScrollMinY = 0; ScrollMaxX = (DisplayMaxX + border1_offset - SCR_FIELDX) * TILEX; ScrollMaxY = (DisplayMaxY + border1_offset - SCR_FIELDY) * TILEY; /* scroll correction for border element (half tile on left and right side) */ ScrollMinX += border2_offset; ScrollMinY += border2_offset; ScrollMaxX -= border2_offset; ScrollMaxY -= border2_offset; /* scroll correction for even number of visible tiles (half tile shifted) */ ScrollMinX -= game_sp.scroll_xoffset; ScrollMaxX -= game_sp.scroll_xoffset; ScrollMinY -= game_sp.scroll_yoffset; ScrollMaxY -= game_sp.scroll_yoffset; } void DrawField(int X, int Y) { int tsi = GetSI(X, Y); int Tmp = LowByte(PlayField16[tsi]); if (Tmp < fiFirst || Tmp > fiLast) Tmp = fiSpace; if (Tmp == fiRAM || Tmp == fiHardWare || Tmp == fiBug || Tmp == fiWallSpace) Tmp = DisPlayField[tsi]; subCopyImageToScreen(tsi, fiGraphic[Tmp]); if (Tmp != fiSpace && Tmp != fiSnikSnak && Tmp != fiElectron) GfxGraphic[X][Y] = fiGraphic[Tmp]; } void DrawFieldAnimated(int X, int Y) { int tsi = GetSI(X, Y); int Tmp = LowByte(PlayField16[tsi]); switch (Tmp) { case fiSnikSnak: subDrawAnimatedSnikSnaks(tsi); break; case fiElectron: subDrawAnimatedElectrons(tsi); break; default: break; } } void DrawFieldNoAnimated(int X, int Y) { int tsi = GetSI(X, Y); int Tmp = LowByte(PlayField16[tsi]); switch (Tmp) { case fiSnikSnak: subCopyImageToScreen(tsi, aniSpace); break; case fiElectron: subCopyImageToScreen(tsi, aniSpace); break; default: DrawField(X, Y); break; } } void DrawImage(int X, int Y, int graphic) { DDSpriteBuffer_BltImg(StretchWidth * X, StretchWidth * Y, graphic, 0); } mirrormagic-3.0.0/src/game_sp/init.c0000644000175000017500000002337513263212010016644 0ustar aeglosaeglos #include "main_sp.h" #include "global.h" char *preceding_playfield_memory[] = { "95 89 95 89 95 89 3b 8a 3b 8a 3b 8a 3b 8a 3b 8a", // |......;.;.;.;.;.| "3b 8a 3b 8a 3b 8a e8 8a e8 8a e8 8a e8 8a e8 8a", // |;.;.;...........| "e8 8a e8 8a e8 8a b1 8b b1 8b b1 8b b1 8b b1 8b", // |................| "b1 8b b1 8b b1 8b 85 8c 85 8c 85 8c 85 8c 85 8c", // |................| "85 8c 85 8c 85 8c 5b 8d 5b 8d 5b 8d 5b 8d 5b 8d", // |......[.[.[.[.[.| "5b 8d 5b 8d 5b 8d 06 8e 06 8e 06 8e 06 8e 06 8e", // |[.[.[...........| "06 8e 06 8e 06 8e ac 8e ac 8e ac 8e ac 8e ac 8e", // |................| "ac 8e ac 8e ac 8e 59 8f 59 8f 59 8f 59 8f 59 8f", // |......Y.Y.Y.Y.Y.| "59 8f 59 8f 59 8f 00 00 70 13 00 00 00 00 e8 17", // |Y.Y.Y...p.......| "00 00 00 00 00 00 69 38 00 00 00 00 00 00 00 00", // |......i8........| "00 00 00 00 00 00 00 00 d0 86 00 00 b2 34 00 00", // |.............4..| "00 00 00 00 00 00 8f 8b 1d 34 00 00 00 00 00 00", // |.........4......| "00 00 00 00 23 39 09 09 00 0c 00 08 00 58 00 00", // |....#9.......X..| "00 00 00 25 77 06 7f 00 00 00 01 00 00 00 00 00", // |...%w...........| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 ec 06 26 05 00 00 00", // |...........&....| "00 00 00 01 00 00 00 00 31 32 33 34 35 36 37 38", // |........12345678| "39 30 2d 00 08 00 51 57 45 52 54 59 55 49 4f 50", // |90-...QWERTYUIOP| "00 00 0a 00 41 53 44 46 47 48 4a 4b 4c 00 00 00", // |....ASDFGHJKL...| "00 00 5a 58 43 56 42 4e 4d 00 00 00 00 00 00 20", // |..ZXCVBNM...... | "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 2e 00 1e 00 31 00 14 00 39 00", // |..........1...9.| "1f 00 14 00 18 00 ff ff 01 00 01 4c 45 56 45 4c", // |...........LEVEL| "53 2e 44 41 54 00 00 00 00 00 00 00 00 00 00 00", // |S.DAT...........| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| NULL }; Bitmap *bitmap_db_field_sp; struct EngineSnapshotInfo_SP engine_snapshot_sp; void sp_open_all() { Form_Load(); } void sp_close_all() { } void InitPrecedingPlayfieldMemory() { int preceding_buffer_size = 0; int i; for (i = 0; preceding_playfield_memory[i] != NULL; i++) preceding_buffer_size += 8; /* eight 16-bit integer values */ game_sp.preceding_buffer = preceding_playfield_memory; game_sp.preceding_buffer_size = preceding_buffer_size; } void InitGfxBuffers_SP() { ReCreateBitmap(&bitmap_db_field_sp, FXSIZE, FYSIZE); } unsigned int InitEngineRandom_SP(int seed) { if (seed == NEW_RANDOMIZE) { subRandomize(); seed = (int)RandomSeed; } RandomSeed = (short)seed; return (unsigned int) seed; } /* ------------------------------------------------------------------------- */ /* Supaplex game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ void SaveEngineSnapshotValues_SP(ListNode **buffers) { int i; engine_snapshot_sp.game_sp = game_sp; /* these arrays have playfield-size dependent variable size */ for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.PlayField16[i] = PlayField16[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.PlayField8[i] = PlayField8[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.DisPlayField[i] = DisPlayField[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) engine_snapshot_sp.AnimationPosTable[i] = AnimationPosTable[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) engine_snapshot_sp.AnimationSubTable[i] = AnimationSubTable[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) engine_snapshot_sp.TerminalState[i] = TerminalState[i]; /* store special data into engine snapshot buffers */ SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FieldWidth)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FieldHeight)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FieldMax)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(LevelMax)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(TimerVar)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RandomSeed)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FreezeZonks)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(TerminalMaxCycles)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollX)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollY)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollX_last)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollY_last)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenScrollXPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenScrollYPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMinX)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMinY)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMaxX)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMaxY)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(InfotronsNeeded)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(KillMurphyFlag)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyMoveCounter)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyExplodePos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(SplitMoveFlag)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseMurphyPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyPosIndex)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyXPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyYPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyScreenXPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyScreenYPos)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyVarFaceLeft)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskCount)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseFlag)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MovingPictureSequencePhase)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskReleasePhase)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScratchGravity)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GravityFlag)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(SnikSnaksElectronsFrozen)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(YellowDisksExploded)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(YawnSleepCounter)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(LeadOutCounter)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElementLast)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxGraphicLast)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxGraphic)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMinX)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMinY)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMaxX)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMaxY)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollX)); SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollY)); SaveSnapshotBuffer(buffers, &PlayField16[-game_sp.preceding_buffer_size], game_sp.preceding_buffer_size * sizeof(int)); } void LoadEngineSnapshotValues_SP() { int i; /* stored engine snapshot buffers already restored at this point */ game_sp = engine_snapshot_sp.game_sp; /* these arrays have playfield-size dependent variable size */ for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) PlayField16[i] = engine_snapshot_sp.PlayField16[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) PlayField8[i] = engine_snapshot_sp.PlayField8[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) DisPlayField[i] = engine_snapshot_sp.DisPlayField[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) AnimationPosTable[i] = engine_snapshot_sp.AnimationPosTable[i]; for (i = 0; i < FieldWidth * (FieldHeight - 2); i++) AnimationSubTable[i] = engine_snapshot_sp.AnimationSubTable[i]; for (i = 0; i < FieldWidth * FieldHeight + HeaderSize; i++) TerminalState[i] = engine_snapshot_sp.TerminalState[i]; RedrawPlayfield_SP(TRUE); } mirrormagic-3.0.0/src/game_sp/MainGameLoop.h0000644000175000017500000000100413263212010020177 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // MainGameLoop.h // ---------------------------------------------------------------------------- #ifndef MAINGAMELOOP_H #define MAINGAMELOOP_H #include "global.h" extern boolean AutoScrollFlag; extern boolean bPlaying; extern int ExitToMenuFlag; extern int LeadOutCounter; extern void subMainGameLoop_Init(); extern void subMainGameLoop_Main(byte, boolean); extern void subCalculateScreenScrollPos(); #endif /* MAINGAMELOOP_H */ mirrormagic-3.0.0/src/game_sp/BugsTerminals.h0000644000175000017500000000100513263212010020447 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // BugsTerminals.h // ---------------------------------------------------------------------------- #ifndef BUGSTERMINALS_H #define BUGSTERMINALS_H #include "global.h" extern byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; extern int TerminalMaxCycles; extern void subAnimateBugs(int si); extern void subAnimateTerminals(int si); extern void subRandomize(); extern int subGetRandomNumber(); #endif /* BUGSTERMINALS_H */ mirrormagic-3.0.0/src/game_sp/DDSpriteBuffer.c0000644000175000017500000000221113263212010020473 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // DDSpriteBuffer.c // ---------------------------------------------------------------------------- #include "DDSpriteBuffer.h" static void Blt(int pX, int pY, Bitmap *bitmap, int SpriteX, int SpriteY) { int scx = (mScrollX_last < 0 ? 0 : mScrollX_last); int scy = (mScrollY_last < 0 ? 0 : mScrollY_last); int sx1 = scx - 2 * TILEX; int sy1 = scy - 2 * TILEY; int sx2 = scx + (SCR_FIELDX + 1) * TILEX; int sy2 = scy + (SCR_FIELDY + 1) * TILEY; int sx = pX - sx1; int sy = pY - sy1; if (NoDisplayFlag) return; /* do not draw fields that are outside the visible screen area */ if (pX < sx1 || pX > sx2 || pY < sy1 || pY > sy2) return; sx = sx * TILESIZE_VAR / TILESIZE; sy = sy * TILESIZE_VAR / TILESIZE; BlitBitmap(bitmap, bitmap_db_field_sp, SpriteX, SpriteY, TILEX_VAR, TILEY_VAR, sx, sy); } void DDSpriteBuffer_BltImg(int pX, int pY, int graphic, int sync_frame) { struct GraphicInfo_SP g; if (NoDisplayFlag) return; getGraphicSource_SP(&g, graphic, sync_frame, -1, -1); Blt(pX, pY, g.bitmap, g.src_x, g.src_y); } mirrormagic-3.0.0/src/game_sp/file.c0000644000175000017500000004136113263212010016613 0ustar aeglosaeglos #include "main_sp.h" #include "global.h" /* ------------------------------------------------------------------------- */ /* functions for loading Supaplex level */ /* ------------------------------------------------------------------------- */ void setTapeInfoToDefaults_SP() { native_sp_level.demo.is_available = FALSE; native_sp_level.demo.length = 0; } void setLevelInfoToDefaults_SP() { LevelInfoType *header = &native_sp_level.header; char *empty_title = "-------- EMPTY --------"; int i, x, y; native_sp_level.game_sp = &game_sp; native_sp_level.width = SP_STD_PLAYFIELD_WIDTH; native_sp_level.height = SP_STD_PLAYFIELD_HEIGHT; for (x = 0; x < native_sp_level.width; x++) for (y = 0; y < native_sp_level.height; y++) native_sp_level.playfield[x][y] = fiSpace; /* copy string (without terminating '\0' character!) */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) header->LevelTitle[i] = empty_title[i]; header->InitialGravity = 0; header->Version = 0; header->InitialFreezeZonks = 0; header->InfotronsNeeded = 0; header->SpecialPortCount = 0; header->SpeedByte = 0; header->CheckSumByte = 0; header->DemoRandomSeed = 0; for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) { SpecialPortType *port = &header->SpecialPort[i]; port->PortLocation = 0; port->Gravity = 0; port->FreezeZonks = 0; port->FreezeEnemies = 0; } /* set raw header bytes (used for subsequent buffer zone) to "hardware" */ for (i = 0; i < SP_HEADER_SIZE; i++) native_sp_level.header_raw_bytes[i] = 0x20; setTapeInfoToDefaults_SP(); } void copyInternalEngineVars_SP() { int count; int i, x, y; LInfo = native_sp_level.header; FieldWidth = native_sp_level.width; FieldHeight = native_sp_level.height; HeaderSize = 96; FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1; LevelMax = (FieldWidth * FieldHeight) - 1; /* initialize preceding playfield buffer */ for (i = -game_sp.preceding_buffer_size; i < 0; i++) PlayField16[i] = 0; /* initialize preceding playfield buffer */ for (i = -SP_MAX_PLAYFIELD_WIDTH; i < 0; i++) PlayField8[i] = 0; count = 0; for (i = 0; game_sp.preceding_buffer[i] != NULL; i++) { char *s = game_sp.preceding_buffer[i]; boolean hi_byte = FALSE; /* little endian data => start with low byte */ while (s[0] != '\0' && s[1] != '\0') { int hi_nibble = s[0] - (s[0] > '9' ? 'a' - 10 : '0'); int lo_nibble = s[1] - (s[1] > '9' ? 'a' - 10 : '0'); int byte = (hi_nibble << 4) | lo_nibble; if (hi_byte) byte <<= 8; PlayField16[-game_sp.preceding_buffer_size + count] |= byte; if (hi_byte) count++; hi_byte = !hi_byte; s += 2; while (*s == ' ') s++; } } count = 0; for (y = 0; y < native_sp_level.height; y++) for (x = 0; x < native_sp_level.width; x++) PlayField8[count++] = native_sp_level.playfield[x][y]; /* add raw header bytes to subsequent playfield buffer zone */ for (i = 0; i < SP_HEADER_SIZE; i++) PlayField8[count++] = native_sp_level.header_raw_bytes[i]; for (i = 0; i < count; i++) { PlayField16[i] = PlayField8[i]; DisPlayField[i] = PlayField8[i]; PlayField8[i] = 0; } if (native_sp_level.demo.is_available) DemoAvailable = True; GravityFlag = LInfo.InitialGravity; FreezeZonks = LInfo.InitialFreezeZonks; LevelLoaded = True; /* random seed set by main game tape code to native random generator seed */ } static void LoadNativeLevelFromFileStream_SP(File *file, int width, int height, boolean demo_available) { LevelInfoType *header = &native_sp_level.header; int i, x, y; /* for details of the Supaplex level format, see Herman Perk's Supaplex documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */ native_sp_level.width = MIN(width, SP_MAX_PLAYFIELD_WIDTH); native_sp_level.height = MIN(height, SP_MAX_PLAYFIELD_HEIGHT); /* read level playfield (width * height == 60 * 24 tiles == 1440 bytes) */ /* (MPX levels may have non-standard playfield size -- check max. size) */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { byte element = getFile8Bit(file); if (x < SP_MAX_PLAYFIELD_WIDTH && y < SP_MAX_PLAYFIELD_HEIGHT) native_sp_level.playfield[x][y] = element; } } /* read level header (96 bytes) */ ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */ /* initial gravity: 1 == "on", anything else (0) == "off" */ header->InitialGravity = getFile8Bit(file); /* SpeedFixVersion XOR 0x20 */ header->Version = getFile8Bit(file); /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */ for (i = 0; i < SP_LEVEL_NAME_LEN; i++) header->LevelTitle[i] = getFile8Bit(file); /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */ header->InitialFreezeZonks = getFile8Bit(file); /* number of infotrons needed; 0 means that Supaplex will count the total amount of infotrons in the level and use the low byte of that number (a multiple of 256 infotrons will result in "0 infotrons needed"!) */ header->InfotronsNeeded = getFile8Bit(file); /* number of special ("gravity") port entries below (maximum 10 allowed) */ header->SpecialPortCount = getFile8Bit(file); /* database of properties of up to 10 special ports (6 bytes per port) */ for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) { SpecialPortType *port = &header->SpecialPort[i]; /* high and low byte of the location of a special port; if (x, y) are the coordinates of a port in the field and (0, 0) is the top-left corner, the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice of what may be expected: Supaplex works with a game field in memory which is 2 bytes per tile) */ port->PortLocation = getFile16BitBE(file); /* yes, big endian */ /* change gravity: 1 == "turn on", anything else (0) == "turn off" */ port->Gravity = getFile8Bit(file); /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */ port->FreezeZonks = getFile8Bit(file); /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */ port->FreezeEnemies = getFile8Bit(file); ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */ } /* SpeedByte XOR Highbyte(RandomSeed) */ header->SpeedByte = getFile8Bit(file); /* CheckSum XOR SpeedByte */ header->CheckSumByte = getFile8Bit(file); /* random seed used for recorded demos */ header->DemoRandomSeed = getFile16BitLE(file); /* yes, little endian */ /* auto-determine number of infotrons if it was stored as "0" -- see above */ if (header->InfotronsNeeded == 0) { for (x = 0; x < native_sp_level.width; x++) for (y = 0; y < native_sp_level.height; y++) if (native_sp_level.playfield[x][y] == fiInfotron) header->InfotronsNeeded++; header->InfotronsNeeded &= 0xff; /* only use low byte -- see above */ } /* read raw level header bytes (96 bytes) */ seekFile(file, -(SP_HEADER_SIZE), SEEK_CUR); /* rewind file */ for (i = 0; i < SP_HEADER_SIZE; i++) native_sp_level.header_raw_bytes[i] = getByteFromFile(file); /* also load demo tape, if available (only in single level files) */ if (demo_available) { int level_nr = getFile8Bit(file); level_nr &= 0x7f; /* clear highest bit */ level_nr = (level_nr < 1 ? 1 : level_nr > 111 ? 111 : level_nr); native_sp_level.demo.level_nr = level_nr; for (i = 0; i < SP_MAX_TAPE_LEN && !checkEndOfFile(file); i++) { native_sp_level.demo.data[i] = getFile8Bit(file); if (native_sp_level.demo.data[i] == 0xff) /* "end of demo" byte */ break; } if (i >= SP_MAX_TAPE_LEN) Error(ERR_WARN, "SP demo truncated: size exceeds maximum SP demo size %d", SP_MAX_TAPE_LEN); native_sp_level.demo.length = i; native_sp_level.demo.is_available = (native_sp_level.demo.length > 0); } } boolean LoadNativeLevel_SP(char *filename, int level_pos, boolean level_info_only) { File *file; int i, l, x, y; char name_first, name_last; struct LevelInfo_SP multipart_level; int multipart_xpos, multipart_ypos; boolean is_multipart_level; boolean is_first_part; boolean reading_multipart_level = FALSE; boolean use_empty_level = FALSE; LevelInfoType *header = &native_sp_level.header; boolean is_single_level_file = (strSuffixLower(filename, ".sp") || strSuffixLower(filename, ".mpx")); boolean demo_available = is_single_level_file; boolean is_mpx_file = strSuffixLower(filename, ".mpx"); int file_seek_pos = level_pos * SP_STD_LEVEL_SIZE; int level_width = SP_STD_PLAYFIELD_WIDTH; int level_height = SP_STD_PLAYFIELD_HEIGHT; /* always start with reliable default values */ setLevelInfoToDefaults_SP(); copyInternalEngineVars_SP(); if (!(file = openFile(filename, MODE_READ))) { if (!level_info_only) Error(ERR_WARN, "cannot open file '%s' -- using empty level", filename); return FALSE; } if (is_mpx_file) { char mpx_chunk_name[4 + 1]; int mpx_version; int mpx_level_count; LevelDescriptor *mpx_level_desc; getFileChunkBE(file, mpx_chunk_name, NULL); if (!strEqual(mpx_chunk_name, "MPX ")) { Error(ERR_WARN, "cannot find MPX ID in file '%s' -- using empty level", filename); return FALSE; } mpx_version = getFile16BitLE(file); if (mpx_version != 1) { Error(ERR_WARN, "unknown MPX version in file '%s' -- using empty level", filename); return FALSE; } mpx_level_count = getFile16BitLE(file); if (mpx_level_count < 1) { Error(ERR_WARN, "no MPX levels found in file '%s' -- using empty level", filename); return FALSE; } if (level_pos >= mpx_level_count) { Error(ERR_WARN, "MPX level not found in file '%s' -- using empty level", filename); return FALSE; } mpx_level_desc = checked_calloc(mpx_level_count * sizeof(LevelDescriptor)); for (i = 0; i < mpx_level_count; i++) { LevelDescriptor *ldesc = &mpx_level_desc[i]; ldesc->Width = getFile16BitLE(file); ldesc->Height = getFile16BitLE(file); ldesc->OffSet = getFile32BitLE(file); /* starts with 1, not with 0 */ ldesc->Size = getFile32BitLE(file); } level_width = mpx_level_desc[level_pos].Width; level_height = mpx_level_desc[level_pos].Height; file_seek_pos = mpx_level_desc[level_pos].OffSet - 1; } /* position file stream to the requested level (in case of level package) */ if (seekFile(file, file_seek_pos, SEEK_SET) != 0) { Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); return FALSE; } /* there exist Supaplex level package files with multi-part levels which can be detected as follows: instead of leading and trailing dashes ('-') to pad the level name, they have leading and trailing numbers which are the x and y coordinations of the current part of the multi-part level; if there are '?' characters instead of numbers on the left or right side of the level name, the multi-part level consists of only horizontal or vertical parts */ for (l = level_pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++) { LoadNativeLevelFromFileStream_SP(file, level_width, level_height, demo_available); /* check if this level is a part of a bigger multi-part level */ if (is_single_level_file) break; name_first = header->LevelTitle[0]; name_last = header->LevelTitle[SP_LEVEL_NAME_LEN - 1]; is_multipart_level = ((name_first == '?' || (name_first >= '0' && name_first <= '9')) && (name_last == '?' || (name_last >= '0' && name_last <= '9'))); is_first_part = ((name_first == '?' || name_first == '1') && (name_last == '?' || name_last == '1')); if (is_multipart_level) { /* correct leading multipart level meta information in level name */ for (i = 0; i < SP_LEVEL_NAME_LEN && header->LevelTitle[i] == name_first; i++) header->LevelTitle[i] = '-'; /* correct trailing multipart level meta information in level name */ for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && header->LevelTitle[i] == name_last; i--) header->LevelTitle[i] = '-'; } /* ---------- check for normal single level ---------- */ if (!reading_multipart_level && !is_multipart_level) { /* the current level is simply a normal single-part level, and we are not reading a multi-part level yet, so return the level as it is */ break; } /* ---------- check for empty level (unused multi-part) ---------- */ if (!reading_multipart_level && is_multipart_level && !is_first_part) { /* this is a part of a multi-part level, but not the first part (and we are not already reading parts of a multi-part level); in this case, use an empty level instead of the single part */ use_empty_level = TRUE; break; } /* ---------- check for finished multi-part level ---------- */ if (reading_multipart_level && (!is_multipart_level || !strEqualN(header->LevelTitle, multipart_level.header.LevelTitle, SP_LEVEL_NAME_LEN))) { /* we are already reading parts of a multi-part level, but this level is either not a multi-part level, or a part of a different multi-part level; in both cases, the multi-part level seems to be complete */ break; } /* ---------- here we have one part of a multi-part level ---------- */ reading_multipart_level = TRUE; if (is_first_part) /* start with first part of new multi-part level */ { /* copy level info structure from first part */ multipart_level = native_sp_level; /* clear playfield of new multi-part level */ for (x = 0; x < SP_MAX_PLAYFIELD_WIDTH; x++) for (y = 0; y < SP_MAX_PLAYFIELD_HEIGHT; y++) multipart_level.playfield[x][y] = fiSpace; } if (name_first == '?') name_first = '1'; if (name_last == '?') name_last = '1'; multipart_xpos = (int)(name_first - '0'); multipart_ypos = (int)(name_last - '0'); if (multipart_xpos * SP_STD_PLAYFIELD_WIDTH > SP_MAX_PLAYFIELD_WIDTH || multipart_ypos * SP_STD_PLAYFIELD_HEIGHT > SP_MAX_PLAYFIELD_HEIGHT) { Error(ERR_WARN, "multi-part level is too big -- ignoring part of it"); break; } multipart_level.width = MAX(multipart_level.width, multipart_xpos * SP_STD_PLAYFIELD_WIDTH); multipart_level.height = MAX(multipart_level.height, multipart_ypos * SP_STD_PLAYFIELD_HEIGHT); /* copy level part at the right position of multi-part level */ for (x = 0; x < SP_STD_PLAYFIELD_WIDTH; x++) { for (y = 0; y < SP_STD_PLAYFIELD_HEIGHT; y++) { int start_x = (multipart_xpos - 1) * SP_STD_PLAYFIELD_WIDTH; int start_y = (multipart_ypos - 1) * SP_STD_PLAYFIELD_HEIGHT; multipart_level.playfield[start_x + x][start_y + y] = native_sp_level.playfield[x][y]; } } } closeFile(file); if (use_empty_level) { setLevelInfoToDefaults_SP(); Error(ERR_WARN, "single part of multi-part level -- using empty level"); } if (reading_multipart_level) native_sp_level = multipart_level; copyInternalEngineVars_SP(); return TRUE; } void SaveNativeLevel_SP(char *filename) { LevelInfoType *header = &native_sp_level.header; FILE *file; int i, x, y; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save native level file '%s'", filename); return; } /* write level playfield (width * height == 60 * 24 tiles == 1440 bytes) */ for (y = 0; y < native_sp_level.height; y++) for (x = 0; x < native_sp_level.width; x++) putFile8Bit(file, native_sp_level.playfield[x][y]); /* write level header (96 bytes) */ WriteUnusedBytesToFile(file, 4); putFile8Bit(file, header->InitialGravity); putFile8Bit(file, header->Version); for (i = 0; i < SP_LEVEL_NAME_LEN; i++) putFile8Bit(file, header->LevelTitle[i]); putFile8Bit(file, header->InitialFreezeZonks); putFile8Bit(file, header->InfotronsNeeded); putFile8Bit(file, header->SpecialPortCount); for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) { SpecialPortType *port = &header->SpecialPort[i]; putFile16BitBE(file, port->PortLocation); putFile8Bit(file, port->Gravity); putFile8Bit(file, port->FreezeZonks); putFile8Bit(file, port->FreezeEnemies); WriteUnusedBytesToFile(file, 1); } putFile8Bit(file, header->SpeedByte); putFile8Bit(file, header->CheckSumByte); putFile16BitLE(file, header->DemoRandomSeed); /* also save demo tape, if available */ if (native_sp_level.demo.is_available) { putFile8Bit(file, native_sp_level.demo.level_nr); for (i = 0; i < native_sp_level.demo.length; i++) putFile8Bit(file, native_sp_level.demo.data[i]); putFile8Bit(file, 0xff); /* "end of demo" byte */ } fclose(file); } mirrormagic-3.0.0/src/game_sp/DDSpriteBuffer.h0000644000175000017500000000055513263212010020511 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // DDSpriteBuffer.h // ---------------------------------------------------------------------------- #ifndef DDSPRITEBUFFER_H #define DDSPRITEBUFFER_H #include "global.h" extern void DDSpriteBuffer_BltImg(int pX, int pY, int graphic, int sync_frame); #endif /* DDSPRITEBUFFER_H */ mirrormagic-3.0.0/src/game_sp/BugsTerminals.c0000644000175000017500000001033513263212010020450 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // BugsTerminals.c // ---------------------------------------------------------------------------- #include "BugsTerminals.h" byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; int TerminalMaxCycles; // ========================================================================== // SUBROUTINE // Animate bugs // ========================================================================== void subAnimateBugs(int si) { int bl; if (fiBug != LowByte(PlayField16[si])) return; bl = SgnHighByte(PlayField16[si]); // get and increment sequence number if ((TimerVar & 3) == 0) { bl = bl + 1; if (bl >= 14) // bugs animation has 14 frames { bl = subGetRandomNumber(); // generate new random number bl = -((bl & 0x3F) + 0x20); } MovHighByte(&PlayField16[si], bl); // save sequence number } if (bl < 0) // bug sleeps / is inactive return; // now the bug is active! Beware Murphy! if ((TimerVar & 3) == 0 && (LowByte(PlayField16[si - FieldWidth - 1]) == fiMurphy || LowByte(PlayField16[si - FieldWidth]) == fiMurphy || LowByte(PlayField16[si - FieldWidth + 1]) == fiMurphy || LowByte(PlayField16[si - 1]) == fiMurphy || LowByte(PlayField16[si + 1]) == fiMurphy || LowByte(PlayField16[si + FieldWidth - 1]) == fiMurphy || LowByte(PlayField16[si + FieldWidth]) == fiMurphy || LowByte(PlayField16[si + FieldWidth + 1]) == fiMurphy)) subSoundFX(si, fiBug, actActive); // play dangerous sound // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = (bl == 0 ? aniBugActivating : bl == 12 ? aniBugDeactivating : bl == 13 ? aniBug : aniBugActive); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ========================================================================== // SUBROUTINE // Animate terminals // ========================================================================== void subAnimateTerminals(int si) { int bl; int lx = GetX(si); int ly = GetY(si); int graphic; if (LowByte(PlayField16[si]) != fiTerminal) return; /* use native frame handling (undo frame incrementation in main loop) */ if (game.use_native_sp_graphics_engine) GfxFrame[lx][ly]--; /* get last random animation delay */ bl = SgnHighByte(PlayField16[si]); bl = bl + 1; if (bl <= 0) /* return if random animation delay not yet reached */ { MovHighByte(&PlayField16[si], bl); return; } /* calculate new random animation delay */ bl = -(subGetRandomNumber() & TerminalMaxCycles); // generate new random number MovHighByte(&PlayField16[si], bl); // save new sequence number /* check terminal state (active or inactive) */ bl = TerminalState[si] + 1; if (bl == 8) bl = 0; else if (15 < bl) bl = 8; TerminalState[si] = bl; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ graphic = (bl < 8 ? aniTerminal : aniTerminalActive); if (game.use_native_sp_graphics_engine) GfxFrame[lx][ly] += getGraphicInfo_Delay(graphic); GfxGraphic[lx][ly] = (bl < 8 ? aniTerminal : aniTerminalActive); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ========================================================================== // SUBROUTINE // Randomize random number generator // ========================================================================== void subRandomize() { int Tick = MyGetTickCount(); RandomSeed = (Tick ^ (Tick >> 16)) & 0xFFFF; } // ========================================================================== // SUBROUTINE // Generate new random number, first method (see also sub_g_8580) // ========================================================================== int subGetRandomNumber() { RandomSeed = (RandomSeed * 0x5E5 + 0x31) & 0xFFFF; return (RandomSeed >> 1); // Mov ax, randomseed // Mov bx, &H5E5 // mul bx ' dx:ax = reg * ax // Add ax, &H31 // Mov randomseed, ax // shr ax,1 } mirrormagic-3.0.0/src/game_sp/main.c0000644000175000017500000000510613263212010016615 0ustar aeglosaeglos #include "main_sp.h" #include "global.h" struct GameInfo_SP game_sp; struct LevelInfo_SP native_sp_level; int GfxElementLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; int GfxGraphicLast[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; int GfxGraphic[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; int GfxFrame[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; void InitGameEngine_SP() { int x, y; gfx.anim_random_frame = -1; // (use simple, ad-hoc random numbers) game_sp.LevelSolved = FALSE; game_sp.GameOver = FALSE; game_sp.time_played = 0; game_sp.infotrons_still_needed = native_sp_level.header.InfotronsNeeded; game_sp.red_disk_count = 0; game_sp.score = 0; menBorder = setup.sp_show_border_elements; game_sp.scroll_xoffset = (EVEN(SCR_FIELDX) ? TILEX / 2 : 0); game_sp.scroll_yoffset = (EVEN(SCR_FIELDY) ? TILEY / 2 : 0); if (native_sp_level.width <= SCR_FIELDX) game_sp.scroll_xoffset = TILEX / 2; if (native_sp_level.height <= SCR_FIELDY) game_sp.scroll_yoffset = TILEY / 2; for (x = 0; x < SP_MAX_PLAYFIELD_WIDTH; x++) { for (y = 0; y < SP_MAX_PLAYFIELD_HEIGHT; y++) { GfxElementLast[x][y] = -1; GfxGraphicLast[x][y] = -1; GfxGraphic[x][y] = -1; GfxFrame[x][y] = 0; } } InitScrollPlayfield(); menPlay_Click(); } void RedrawPlayfield_SP(boolean force_redraw) { // skip redrawing playfield in warp mode or when testing tapes with "autotest" if (DrawingDeactivatedField()) return; if (force_redraw) RestorePlayfield(); UpdatePlayfield(force_redraw); } void UpdateGameDoorValues_SP() { game_sp.time_played = TimerVar / FRAMES_PER_SECOND; game_sp.infotrons_still_needed = InfotronsNeeded; game_sp.red_disk_count = RedDiskCount; game_sp.score = 0; // (currently no score in Supaplex engine) } void GameActions_SP(byte action[MAX_PLAYERS], boolean warp_mode) { byte single_player_action = action[0]; int x, y; UpdateEngineValues(mScrollX / TILEX, mScrollY / TILEY, MurphyScreenXPos / TILEX, MurphyScreenYPos / TILEY); subMainGameLoop_Main(single_player_action, warp_mode); RedrawPlayfield_SP(FALSE); UpdateGameDoorValues_SP(); CheckSingleStepMode_SP(PlayField16[MurphyPosIndex] == fiMurphy, HighByte(PlayField16[MurphyPosIndex]) == 0x2A); for (x = DisplayMinX; x <= DisplayMaxX; x++) for (y = DisplayMinY; y <= DisplayMaxY; y++) GfxFrame[x][y]++; } int getRedDiskReleaseFlag_SP() { /* 0: when Murphy is moving (including the destination tile!) */ /* 1: when Murphy is not moving for at least one game frame */ return RedDiskReleaseFlag; } mirrormagic-3.0.0/src/game_sp/Explosions.c0000644000175000017500000001673513263212010020046 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Explosions.c // ---------------------------------------------------------------------------- #include "Explosions.h" static void LetExplodeFieldSP(int tsi, int cx, int dh); static void subExplodeInfotron(int tsi, int cx); static void subExplodeZonk(int tsi, int cx); // ========================================================================== // SUBROUTINE // Animate explosion // ========================================================================== void subAnimateExplosion(int si) { int ax, bl; if (LowByte(PlayField16[si]) != fiExplosion) return; ax = (TimerVar & 3); if (ax != 0) return; bl = HighByte(PlayField16[si]); if ((bl & 0x80) != 0) // infotron explosion! goto loc_g_28D0; bl = bl + 1; MovHighByte(&PlayField16[si], bl); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniDefaultExplosion; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (bl == 8) { PlayField16[si] = 0; ExplosionShake = 0; // nothing explodes // ExplosionShakeMurphy = 0; // nothing explodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSpace; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // loc_ret_g_28CF: return; loc_g_28D0: // explosion produces infotron bl = bl + 1; if (bl == 0x89) { PlayField16[si] = fiInfotron; MovLowByte(&ExplosionShake, 0); // nothing explodes // MovLowByte(&ExplosionShakeMurphy, 0); // nothing explodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniInfotron; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ return; } // loc_g_28E3: MovHighByte(&PlayField16[si], bl); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniElectronExplosion; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } // ========================================================================== // SUBROUTINE // Explode // ========================================================================== void ExplodeFieldSP(int si) { int ax, cx, dl; ax = LowByte(PlayField16[si]); if (ax == fiHardWare) return; ExplosionShake = 1; // something explodes if (ax == fiMurphy) { KillMurphyFlag = 1; ExplosionShakeMurphy = 30; // Murphy explodes } if (ax == fiElectron) { cx = 0x801F; // produce infotrons dl = 0xF3; } else // loc_g_2977: { cx = 0x1F; // normal explosion dl = 0xD; } // loc_g_297C: LetExplodeFieldSP(si - FieldWidth - 1, cx, dl); LetExplodeFieldSP(si - FieldWidth, cx, dl); LetExplodeFieldSP(si - FieldWidth + 1, cx, dl); LetExplodeFieldSP(si - 1, cx, dl); PlayField16[si] = cx; LetExplodeFieldSP(si + 1, cx, dl); LetExplodeFieldSP(si + FieldWidth - 1, cx, dl); LetExplodeFieldSP(si + FieldWidth, cx, dl); LetExplodeFieldSP(si + FieldWidth + 1, cx, dl); GfxGraphic[GetX(si)][GetY(si)] = -1; // restart for chain-explosions // loc_g_2C3B: subSoundFX(si, ax, actExploding); } static void LetExplodeFieldSP(int tsi, int cx, int dh) { int al; if (tsi < -FieldWidth) return; al = LowByte(PlayField16[tsi]); switch (al) { case fiHardWare: return; break; case fiOrangeDisk: case fiYellowDisk: case fiSnikSnak: PlayField8[tsi] = dh; PlayField16[tsi] = cx; break; case fiZonk: subExplodeZonk(tsi, cx); break; case fiInfotron: subExplodeInfotron(tsi, cx); break; case fiElectron: PlayField8[tsi] = (-dh) & 0xFF; PlayField16[tsi] = 0x801F; break; case fiMurphy: KillMurphyFlag = 1; PlayField8[tsi] = dh; PlayField16[tsi] = cx; break; default: PlayField16[tsi] = cx; break; } GfxGraphic[GetX(tsi)][GetY(tsi)] = -1; // restart for chain-explosions } static void subExplodeZonk(int tsi, int cx) { int ah; ah = HighByte(PlayField16[tsi]) & 0xF0; PlayField16[tsi] = cx; switch (ah) { case 0x10: case 0x70: subClearFieldDueToExplosion(tsi - FieldWidth); tsi = tsi + FieldWidth; if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x20: subClearFieldDueToExplosion(tsi + 1); subClearFieldDueToExplosion(tsi + FieldWidth); break; case 0x30: subClearFieldDueToExplosion(tsi - 1); subClearFieldDueToExplosion(tsi + FieldWidth); break; case 0x50: subClearFieldDueToExplosion(tsi - 1); break; case 0x60: subClearFieldDueToExplosion(tsi + 1); break; case 0xFF000070: // !!! 0x70; this will never be reached! ...?? subClearFieldDueToExplosion(tsi + FieldWidth); break; } } static void subExplodeInfotron(int tsi, int cx) { int ah; ah = HighByte(PlayField16[tsi]) & 0xF0; PlayField16[tsi] = cx; switch (ah) { case 0x10: case 0x70: subClearFieldDueToExplosion(tsi - FieldWidth); tsi = tsi + FieldWidth; if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x20: subClearFieldDueToExplosion(tsi + 1); tsi = tsi + FieldWidth; // differnt from zonk version if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x30: subClearFieldDueToExplosion(tsi - 1); tsi = tsi + FieldWidth; // differnt from zonk version if (PlayField16[tsi] == 0x9999) subClearFieldDueToExplosion(tsi); break; case 0x50: subClearFieldDueToExplosion(tsi - 1); break; case 0x60: subClearFieldDueToExplosion(tsi + 1); break; case 0xFF000070: // !!! 0x70; this will never be reached! ...?? subClearFieldDueToExplosion(tsi + FieldWidth); break; } } void subClearFieldDueToExplosion(int si) { if (LowByte(PlayField16[si]) == fiExplosion) return; PlayField16[si] = 0; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSpace; // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subRedDiskReleaseExplosion() { int al, X, Y, si; al = RedDiskReleasePhase; // Red disk release phase if (al <= 1) return; si = RedDiskReleaseMurphyPos; if (PlayField16[si] == 0) // Release red disk PlayField16[si] = fiRedDisk; // +++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniRedDisk, 0); // +++++++++++++++++++++++++++++++++++++++++ RedDiskReleasePhase = RedDiskReleasePhase + 1; if (RedDiskReleasePhase >= 0x28) { // si = RedDiskReleaseMurphyPos ' Red disk was released here ExplodeFieldSP(si); // Explode RedDiskReleasePhase = 0; } } void subFollowUpExplosions() { int ax, si; // locloop_g_2919: for (si = 0; si <= LevelMax; si++) { ax = ByteToInt(PlayField8[si]); if (ax != 0) { if (ax < 0) { ax = ax + 1; PlayField8[si] = ax & 0xFF; if (ax == 0) { PlayField16[si] = 0xFF18; ExplodeFieldSP(si); // Explode } } else { ax = ax - 1; PlayField8[si] = ax; if (ax == 0) ExplodeFieldSP(si); } } } } mirrormagic-3.0.0/src/game_sp/game_sp.h0000644000175000017500000000115213263212010017306 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // game_sp.h // ============================================================================ #ifndef GAME_SP_H #define GAME_SP_H #define GAME_SP_VERSION_1_0_0 #include "export.h" #endif /* GAME_SP_H */ mirrormagic-3.0.0/src/game_sp/SnikSnaks.c0000644000175000017500000003560313263212010017602 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // SnikSnaks.c // ---------------------------------------------------------------------------- #include "SnikSnaks.h" static void subDrawSnikSnakFromAbove(int, int); static void subDrawSnikSnakFromBelow(int, int); static void subDrawSnikSnakFromLeft(int, int); static void subDrawSnikSnakFromRight(int, int); static void subDrawSnikSnakTurnLeft(int, int); static void subDrawSnikSnakTurnRight(int, int); static void subSnikSnakFromAbove(int, int); static void subSnikSnakFromBelow(int, int); static void subSnikSnakFromLeft(int, int); static void subSnikSnakFromRight(int, int); static void subSnikSnakTurnLeft(int, int); static void subSnikSnakTurnRight(int, int); // static char *VB_Name = "modSnikSnak"; // --- Option Explicit // ========================================================================== // SUBROUTINE // Animate/move Snik-Snaks // ========================================================================== void subAnimateSnikSnaks(int si) { int bx, Tmp; if (SnikSnaksElectronsFrozen == 1) return; /* (not sure why this was removed -- this broke several level solutions) */ if (LowByte(PlayField16[si]) != fiSnikSnak) return; // If LowByte(PlayField16(si)) <> fiSnikSnak Then Exit Function // Debug.Assert (LowByte(PlayField16[si]) == fiSnikSnak); bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subSnikSnakTurnRight(si, bx); // turn right break; case 2: subSnikSnakFromBelow(si, bx); // access si from below break; case 3: subSnikSnakFromRight(si, bx); // access si from right break; case 4: subSnikSnakFromAbove(si, bx); // access si from above break; case 5: subSnikSnakFromLeft(si, bx); // access si from left break; default: // Debug.Assert(False); break; } } void subDrawAnimatedSnikSnaks(int si) { int bx, Tmp; // If SnikSnaksElectronsFrozen = 1 Then Exit Function if (LowByte(PlayField16[si]) != fiSnikSnak) return; bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subDrawSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subDrawSnikSnakTurnRight(si, bx); // turn right break; case 2: subDrawSnikSnakFromBelow(si, bx); // access si from below break; case 3: subDrawSnikSnakFromRight(si, bx); // access si from right break; case 4: subDrawSnikSnakFromAbove(si, bx); // access si from above break; case 5: subDrawSnikSnakFromLeft(si, bx); // access si from left break; } } static void subSnikSnakTurnLeft(int si, int bx) { int ax, ah, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_7622; return; } // loc_g_75E0: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakTurnLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = (bx + 1) & 0x7; MovHighByte(&PlayField16[si], bx); return; locMayExplode760A: ah = HighByte(ax); if (ah == 0x1B) return; if (ah == 0x19) return; if (ah == 0x18) return; if (ah == 0x1A) return; ExplodeFieldSP(si); // Explode return; loc_g_7622: bl = HighByte(PlayField16[si]); if (bl == 0) goto loc_g_763B; if (bl == 2) goto loc_g_765E; if (bl == 4) goto loc_g_7681; if (bl == 6) goto loc_g_76A7; return; loc_g_763B: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_764E; if (LowByte(ax) == fiMurphy) // above is murphy -> explode goto locMayExplode760A; return; loc_g_764E: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; PlayField16[si] = 0x1011; return; loc_g_765E: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_7671; if (LowByte(ax) == fiMurphy) // left is murphy -> explode goto locMayExplode760A; return; loc_g_7671: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; PlayField16[si] = 0x1811; return; loc_g_7681: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7697; if (LowByte(ax) == fiMurphy) // below is murphy -> explode goto locMayExplode760A; return; loc_g_7697: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; PlayField16[si] = 0x2011; return; loc_g_76A7: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_76BD; if (LowByte(ax) == fiMurphy) // right is murphy -> explode goto locMayExplode760A; return; loc_g_76BD: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; PlayField16[si] = 0x2811; } static void subSnikSnakTurnRight(int si, int bx) { int ax, ah, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_771F; return; } // loc_g_76DB: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakTurnRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = ((bx + 1) & 0x7) | 8; MovHighByte(&PlayField16[si], bx); return; locMayExplode7707: ah = HighByte(ax); if (ah == 0x1B) return; if (ah == 0x19) return; if (ah == 0x18) return; if (ah == 0x1A) return; ExplodeFieldSP(si); // Explode return; loc_g_771F: bl = HighByte(PlayField16[si]); if (bl == 0x8) goto loc_g_7738; if (bl == 0xA) goto loc_g_77A4; if (bl == 0xC) goto loc_g_777E; if (bl == 0xE) goto loc_g_775B; return; loc_g_7738: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_774B; if (LowByte(ax) == fiMurphy) // above is murphy -> explode goto locMayExplode7707; return; loc_g_774B: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; PlayField16[si] = 0x1011; return; loc_g_775B: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_776E; if (LowByte(ax) == fiMurphy) // left is murphy -> explode goto locMayExplode7707; return; loc_g_776E: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; PlayField16[si] = 0x1811; return; loc_g_777E: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7794; if (LowByte(ax) == fiMurphy) // below is murphy -> explode goto locMayExplode7707; return; loc_g_7794: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; PlayField16[si] = 0x2011; return; loc_g_77A4: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_77BA; if (LowByte(ax) == fiMurphy) // right is murphy -> explode goto locMayExplode7707; return; loc_g_77BA: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; PlayField16[si] = 0x2811; } static void subSnikSnakFromBelow(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromBelow(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0xF; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion) { PlayField16[si + FieldWidth] = 0; // sniknak left that field } if (bl < 8) // sniksnak still goes up { bl = bl + 0x10; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7813 PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si - 1]; // check left field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 1); // start to turn left return; } // loc_g_7826: and 'loc_g_7833: ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above if (ax == 0) // check if empty { PlayField16[si] = 0x1BB; // mark as "sniksnak leaving" si = si - FieldWidth; // go up! PlayField16[si] = 0x1011; return; } // loc_g_784A: if (LowByte(ax) == fiMurphy) // check for murphy above { ExplodeFieldSP(si); // Explode return; } // loc_g_7855: ax = PlayField16[si + 1]; // check right field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 9); // start to turn right return; } // loc_g_7862: and 'loc_g_786F: // else: no way to go, start turning around MovHighByte(&PlayField16[si], 1); } static void subSnikSnakFromRight(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x17; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion) { PlayField16[si + 1] = 0; // sniknak left that field } // loc_g_78AC: if (bl < 8) // sniksnak still goes left { bl = bl + 0x18; MovHighByte(&PlayField16[si], bl); return; } // loc_g_78B9: PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy? { MovHighByte(&PlayField16[si], 3); // yes -> turn left down return; } // loc_g_78CC: and 'loc_g_78D9: ax = PlayField16[si - 1]; // check left, etc ... see the comments on subSnikSnakFromBelow() if (ax == 0) { PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1811; return; } // loc_g_78F0: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_78FB: ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xF); return; } // loc_g_7908:loc_g_7915: MovHighByte(&PlayField16[si], 3); } static void subSnikSnakFromAbove(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromAbove(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x1F; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion) { PlayField16[si - FieldWidth] = 0; // sniknak left that field } if (bl < 8) // sniksnak still goes down { bl = bl + 0x20; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7813 PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si + 1]; // check right if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 5); return; } // loc_g_7986: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0) { PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2011; return; } // loc_g_799D: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_79A8: ax = PlayField16[si - 1]; // check left if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xD); return; } // loc_g_79C2: MovHighByte(&PlayField16[si], 5); } static void subSnikSnakFromLeft(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawSnikSnakFromLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x27; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion) { PlayField16[si - 1] = 0; // sniknak left that field } if (bl < 8) // sniksnak still goes right { bl = bl + 0x28; MovHighByte(&PlayField16[si], bl); return; } // loc_g_78B9: PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 7); return; } // loc_g_7A2D: ax = PlayField16[si + 1]; // check right(straight on) if (ax == 0) { PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2811; return; } // loc_g_7A44: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7A4F: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xB); return; } // loc_g_7A69: MovHighByte(&PlayField16[si], 7); } static void subDrawSnikSnakTurnLeft(int si, int bx) { int pos = ((bx + 7) % 8) / 2; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSnikSnakTurningLeft[pos]; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakTurnRight(int si, int bx) { int pos = ((bx - 1) % 8) / 2; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ GfxGraphic[GetX(si)][GetY(si)] = aniSnikSnakTurningRight[pos]; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromBelow(int si, int bx) { int X, Y; bx = bx - 0xF; // get and anti-increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si + FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y - bx * TwoPixels, aniSnikSnakUp, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromRight(int si, int bx) { int X, Y; bx = bx - 0x17; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - bx * TwoPixels, Y, aniSnikSnakLeft, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromAbove(int si, int bx) { int X, Y; bx = bx - 0x1F; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + bx * TwoPixels, aniSnikSnakDown, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } static void subDrawSnikSnakFromLeft(int si, int bx) { int X, Y; bx = bx - 0x27; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + bx * TwoPixels, Y, aniSnikSnakRight, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } mirrormagic-3.0.0/src/game_sp/Murphy.h0000644000175000017500000000105113263212010017155 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Murphy.h // ---------------------------------------------------------------------------- #ifndef MURPHY_H #define MURPHY_H #include "global.h" extern void subAdjustZonksInfotronsAboveMurphy(int); extern void subAnimateMurphy(int *); extern void subCopyFieldToScreen(int, int); extern void subCopyImageToScreen(int, int); extern void subCopyAnimToScreen(int, int, int); extern void subExplodeSnikSnaksBelow(int); extern void subSpPortTest(int); #endif /* MURPHY_H */ mirrormagic-3.0.0/src/game_sp/ASM.h0000644000175000017500000000064613263212010016322 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // ASM.h // ---------------------------------------------------------------------------- #ifndef ASM_H #define ASM_H #include "global.h" extern void MovLowByte(int *, int); extern void MovHighByte(int *, int); extern int LowByte(int); extern int HighByte(int); extern int SgnHighByte(int); extern int ByteToInt(byte); #endif /* ASM_H */ mirrormagic-3.0.0/src/game_sp/DoGameStuff.c0000644000175000017500000000737613263212010020050 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // DoGameStuff.c // ---------------------------------------------------------------------------- #include "DoGameStuff.h" static void CallAnimation(int si, byte bl); static boolean IsToBeAnimated(int bl); int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE]; byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE]; // ========================================================================== // SUBROUTINE // Do game stuff // ========================================================================== void subDoGameStuff() { int si, cx, dx, bl; int InfotronsNeeded_last = InfotronsNeeded; subAnimateMurphy(&MurphyPosIndex); // move Murphy in any direction if (InfotronsNeeded != InfotronsNeeded_last) game.snapshot.collected_item = TRUE; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Build a database of locations and subs-to-call of animatable fields only: // Make a snapshot from the field before the animation cycle starts. // first and last line are not animated. si = FieldWidth + 1; cx = LevelMax - 2 * FieldWidth - 1; dx = 0; do // locloop_g_2282: { bl = LowByte(PlayField16[si]); if (((bl & 0xD) != 0) && (bl < 0x20)) // all animatables have 1's in &H0D' above &H1F? (&H1F=explosion!) { if (IsToBeAnimated(bl)) { AnimationPosTable[dx] = si; AnimationSubTable[dx] = bl; dx = dx + 1; // count database entries } } si = si + 1; // next field cx = cx - 1; } while (0 < cx); // locloop_g_2282' until all lines scanned(not top- and bottom edge) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Now use the database to animate all animatables the fastest way. // All the other fields are not checked anymore: those have no database entry. // The field from before animation is frozen in the database in order not to // do follow-up animations in the same loop. if (dx != 0) // any database entries? { dx = dx - 1; for (cx = 0; cx <= dx; cx++) { CallAnimation(AnimationPosTable[cx], AnimationSubTable[cx]); } // loop locloop_g_22B8 ' until all animatables done } // All animations are done now // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (KillMurphyFlag == 1 || MurphyMoveCounter == 0) { if (LeadOutCounter == 0 && !game_sp.LevelSolved && !game_sp.GameOver) { KillMurphyFlag = 0; // no more "kill Murphy" ExplodeFieldSP(MurphyExplodePos); // Explode LeadOutCounter = 0x40; // quit: start lead-out /* give Murphy some more time (LeadOutCounter) to reach the exit */ } } // loc_g_22FB: } static boolean IsToBeAnimated(int bl) { static boolean IsToBeAnimated; switch (bl) { case fiZonk: case fiInfotron: case fiOrangeDisk: case fiSnikSnak: case fiTerminal: case fiElectron: case fiBug: case fiExplosion: IsToBeAnimated = True; break; default: IsToBeAnimated = False; break; } return IsToBeAnimated; } static void CallAnimation(int si, byte bl) { switch (bl) { case fiZonk: subAnimateZonks(si); break; case fiInfotron: subAnimateInfotrons(si); break; case fiOrangeDisk: subAnimateOrangeDisks(si); break; case fiSnikSnak: subAnimateSnikSnaks(si); break; case fiTerminal: subAnimateTerminals(si); break; case fiElectron: subAnimateElectrons(si); break; case fiBug: subAnimateBugs(si); break; case fiExplosion: subAnimateExplosion(si); break; default: // Debug.Assert(False); break; } } mirrormagic-3.0.0/src/game_sp/Sound.h0000644000175000017500000000047013263212010016765 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Sound.h // ---------------------------------------------------------------------------- #ifndef GAME_SP_SOUND_H #define GAME_SP_SOUND_H #include "global.h" extern void subSoundFX(int, int, int); #endif /* GAME_SP_SOUND_H */ mirrormagic-3.0.0/src/game_sp/OrangeDisk.h0000644000175000017500000000046513263212010017727 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // OrangeDisk.h // ---------------------------------------------------------------------------- #ifndef ORANGEDISK_H #define ORANGEDISK_H #include "global.h" extern void subAnimateOrangeDisks(int); #endif /* ORANGEDISK_H */ mirrormagic-3.0.0/src/game_sp/Input.c0000644000175000017500000000205513263212010016770 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Input.c // ---------------------------------------------------------------------------- #include "Input.h" int map_key_RND_to_SP(int key) { if (key & KEY_BUTTON) { return (key & MV_UP ? keySpaceUp : key & MV_LEFT ? keySpaceLeft : key & MV_DOWN ? keySpaceDown : key & MV_RIGHT ? keySpaceRight : keySpace); } else { return (key & MV_UP ? keyUp : key & MV_LEFT ? keyLeft : key & MV_DOWN ? keyDown : key & MV_RIGHT ? keyRight : keyNone); } } int map_key_SP_to_RND(int key) { return (key == keyUp ? MV_UP : key == keyLeft ? MV_LEFT : key == keyDown ? MV_DOWN : key == keyRight ? MV_RIGHT : key == keySpaceUp ? KEY_BUTTON | MV_UP : key == keySpaceLeft ? KEY_BUTTON | MV_LEFT : key == keySpaceDown ? KEY_BUTTON | MV_DOWN : key == keySpaceRight ? KEY_BUTTON | MV_RIGHT : key == keySpace ? KEY_BUTTON : MV_NONE); } void subProcessKeyboardInput(byte action) { DemoKeyCode = map_key_RND_to_SP(action); } mirrormagic-3.0.0/src/game_sp/export.h0000644000175000017500000001370713263212010017225 0ustar aeglosaeglos#ifndef GAME_SP_EXPORT_H #define GAME_SP_EXPORT_H /* ========================================================================= */ /* functions and definitions exported from game_sp to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ #define SP_MAX_PLAYFIELD_WIDTH MAX_PLAYFIELD_WIDTH #define SP_MAX_PLAYFIELD_HEIGHT MAX_PLAYFIELD_HEIGHT #define SP_NUM_LEVELS_PER_PACKAGE 111 #define SP_STD_PLAYFIELD_WIDTH 60 #define SP_STD_PLAYFIELD_HEIGHT 24 #define SP_LEVEL_NAME_LEN 23 #define SP_MAX_SPECIAL_PORTS 10 #define SP_HEADER_SIZE 96 #define SP_STD_PLAYFIELD_SIZE (SP_STD_PLAYFIELD_WIDTH * \ SP_STD_PLAYFIELD_HEIGHT) #define SP_MAX_PLAYFIELD_SIZE (SP_MAX_PLAYFIELD_WIDTH * \ SP_MAX_PLAYFIELD_HEIGHT) #define SP_STD_LEVEL_SIZE (SP_HEADER_SIZE + SP_STD_PLAYFIELD_SIZE) #define SP_FRAMES_PER_SECOND 35 // use a much higher value to be able to load ultra-long MPX demo files // (like for level collection 78, level 88 ("WAITING FOR GODOT AGAIN")) // #define SP_MAX_TAPE_LEN 500000 #define SP_MAX_TAPE_LEN 64010 /* (see "spfix63.doc") */ /* sound actions */ #define actActive 0 #define actImpact 1 #define actExploding 2 #define actDigging 3 #define actSnapping 4 #define actCollecting 5 #define actPassing 6 #define actPushing 7 #define actDropping 8 /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ #ifndef HAS_SpecialPortType typedef struct { short PortLocation; // = 2*(x+(y*60)) /* big endian format */ byte Gravity; // 1 = turn on, anything else (0) = turn off byte FreezeZonks; // 2 = turn on, anything else (0) = turn off (1=off!) byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off byte UnUsed; } SpecialPortType; #define HAS_SpecialPortType #endif #ifndef HAS_LevelInfoType typedef struct { byte UnUsed[4]; byte InitialGravity; // 1=on, anything else (0) = off byte Version; // SpeedFixVersion XOR &H20 char LevelTitle[23]; byte InitialFreezeZonks; // 2=on, anything else (0) = off. (1=off too!) byte InfotronsNeeded; // Number of Infotrons needed. 0 means that Supaplex will count the total // amount of Infotrons in the level, and use the low byte of that number. // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!) byte SpecialPortCount; // Maximum 10 allowed! SpecialPortType SpecialPort[10]; byte SpeedByte; // = Speed XOR Highbyte(RandomSeed) byte CheckSumByte; // = CheckSum XOR SpeedByte short DemoRandomSeed; /* little endian format */ } LevelInfoType; #define HAS_LevelInfoType #endif struct GlobalInfo_SP { }; struct GameInfo_SP { boolean LevelSolved; boolean GameOver; /* needed for updating panel */ int time_played; int infotrons_still_needed; int red_disk_count; int score; /* needed for engine snapshots */ char **preceding_buffer; int preceding_buffer_size; int scroll_xoffset, scroll_yoffset; }; struct DemoInfo_SP { boolean is_available; /* structure contains valid demo */ int level_nr; /* number of corresponding level */ int length; /* number of demo entries */ byte data[SP_MAX_TAPE_LEN]; /* array of demo entries */ }; struct LevelInfo_SP { LevelInfoType header; byte header_raw_bytes[SP_HEADER_SIZE]; int width, height; byte playfield[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT]; struct DemoInfo_SP demo; /* used for runtime values */ struct GameInfo_SP *game_sp; }; struct GraphicInfo_SP { Bitmap *bitmap; int src_x, src_y; int src_offset_x, src_offset_y; int dst_offset_x, dst_offset_y; int width, height; Bitmap *crumbled_bitmap; int crumbled_src_x, crumbled_src_y; int crumbled_border_size; boolean has_crumbled_graphics; boolean preserve_background; int unique_identifier; /* used to identify needed screen updates */ }; struct EngineSnapshotInfo_SP { struct GameInfo_SP game_sp; int PlayField16[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; byte PlayField8[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE]; byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE]; byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE]; }; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ extern struct GlobalInfo_SP global_sp_info; extern struct GameInfo_SP game_sp; extern struct LevelInfo_SP native_sp_level; extern struct GraphicInfo_SP graphic_info_sp_object[TILE_MAX][8]; extern struct GraphicInfo_SP graphic_info_sp_player[MAX_PLAYERS][SPR_MAX][8]; extern struct EngineSnapshotInfo_SP engine_snapshot_sp; extern void sp_open_all(); extern void sp_close_all(); extern void InitPrecedingPlayfieldMemory(); extern void InitGfxBuffers_SP(); extern void InitGameEngine_SP(); extern void GameActions_SP(byte *, boolean); extern unsigned int InitEngineRandom_SP(int); extern void setLevelInfoToDefaults_SP(); extern void copyInternalEngineVars_SP(); extern boolean LoadNativeLevel_SP(char *, int, boolean); extern void SaveNativeLevel_SP(char *); extern int getFieldbufferOffsetX_SP(); extern int getFieldbufferOffsetY_SP(); extern void BlitScreenToBitmap_SP(Bitmap *); extern void RedrawPlayfield_SP(boolean); extern void LoadEngineSnapshotValues_SP(); extern void SaveEngineSnapshotValues_SP(ListNode **); extern int map_key_RND_to_SP(int); extern int map_key_SP_to_RND(int); extern int getRedDiskReleaseFlag_SP(); #endif /* GAME_SP_EXPORT_H */ mirrormagic-3.0.0/src/game_sp/SnikSnaks.h0000644000175000017500000000053213263212010017600 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // SnikSnaks.h // ---------------------------------------------------------------------------- #ifndef SNIKSNAKS_H #define SNIKSNAKS_H #include "global.h" extern void subAnimateSnikSnaks(int); extern void subDrawAnimatedSnikSnaks(int); #endif /* SNIKSNAKS_H */ mirrormagic-3.0.0/src/game_sp/Display.c0000644000175000017500000000254313263212010017300 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Display.c // ---------------------------------------------------------------------------- #include "Display.h" int ScreenScrollXPos, ScreenScrollYPos; int ExplosionShake, ExplosionShakeMurphy; boolean NoDisplayFlag; int DisplayMinX, DisplayMaxX; int DisplayMinY, DisplayMaxY; void subDisplayLevel() { if (NoDisplayFlag || ! LevelLoaded) return; DisplayLevel(); } void ScrollTo(int X, int Y) { if (NoDisplayFlag) return; X = ScrollDelta * (X / ScrollDelta); X = Max(X, ScrollMinX); X = Min(X, ScrollMaxX); Y = ScrollDelta * (Y / ScrollDelta); Y = Max(Y, ScrollMinY); Y = Min(Y, ScrollMaxY); DDScrollBuffer_ScrollTo(X, Y); } void ScrollTowards(int X, int Y) { if (NoDisplayFlag) return; X = ScrollDelta * (X / ScrollDelta); X = Max(X, ScrollMinX); X = Min(X, ScrollMaxX); Y = ScrollDelta * (Y / ScrollDelta); Y = Max(Y, ScrollMinY); Y = Min(Y, ScrollMaxY); DDScrollBuffer_ScrollTowards(X, Y, 2 * ZoomFactor); } void SoftScrollTo(int X, int Y, int TimeMS, int FPS) { if (NoDisplayFlag) return; X = ScrollDelta * (X / ScrollDelta); X = Max(X, ScrollMinX); X = Min(X, ScrollMaxX); Y = ScrollDelta * (Y / ScrollDelta); Y = Max(Y, ScrollMinY); Y = Min(Y, ScrollMaxY); DDScrollBuffer_SoftScrollTo(X, Y, TimeMS, FPS); } mirrormagic-3.0.0/src/game_sp/vb_lib.h0000644000175000017500000000055513263212010017136 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // vb_lib.h // ---------------------------------------------------------------------------- #ifndef VB_LIB_H #define VB_LIB_H #define Abs(x) ABS(x) #define Sqr(x) sqrt(x) /* helper functions for constructs not supported by C */ extern int MyGetTickCount(); #endif /* VB_LIB_H */ mirrormagic-3.0.0/src/game_sp/vb_lib.c0000644000175000017500000000052713263212010017130 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // vb_lib.c // ---------------------------------------------------------------------------- #include "main_sp.h" #include "vb_lib.h" /* helper functions for constructs not supported by C */ int MyGetTickCount() { return random_linux_libc(RANDOM_SIMPLE); } mirrormagic-3.0.0/src/game_sp/DDScrollBuffer.c0000644000175000017500000001656013263212010020477 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // DDScrollBuffer.c // ---------------------------------------------------------------------------- #include "DDScrollBuffer.h" #include int mScrollX, mScrollY; int mScrollX_last, mScrollY_last; int ScreenBuffer[2 + MAX_PLAYFIELD_WIDTH + 2][2 + MAX_PLAYFIELD_HEIGHT + 2]; int getFieldbufferOffsetX_SP() { int px = 2 * TILEX + (mScrollX - mScrollX_last) % TILEX; /* scroll correction for even number of visible tiles (half tile shifted) */ px += game_sp.scroll_xoffset; if (ExplosionShakeMurphy != 0) px += TILEX / 2 - GetSimpleRandom(TILEX + 1); px = px * TILESIZE_VAR / TILESIZE; return px; } int getFieldbufferOffsetY_SP() { int py = 2 * TILEY + (mScrollY - mScrollY_last) % TILEY; /* scroll correction for even number of visible tiles (half tile shifted) */ py += game_sp.scroll_yoffset; if (ExplosionShakeMurphy != 0) py += TILEY / 2 - GetSimpleRandom(TILEX + 1); py = py * TILESIZE_VAR / TILESIZE; return py; } void RestorePlayfield() { int x1 = mScrollX / TILEX - 2; int y1 = mScrollY / TILEY - 2; int x2 = mScrollX / TILEX + (SCR_FIELDX - 1) + 2; int y2 = mScrollY / TILEY + (SCR_FIELDY - 1) + 2; int x, y; DrawFrameIfNeeded(); for (y = DisplayMinY; y <= DisplayMaxY; y++) { for (x = DisplayMinX; x <= DisplayMaxX; x++) { if (x >= x1 && x <= x2 && y >= y1 && y <= y2) { DrawFieldNoAnimated(x, y); DrawFieldAnimated(x, y); } } } } static void ScrollPlayfield(int dx, int dy) { int x1 = mScrollX_last / TILEX - 2; int y1 = mScrollY_last / TILEY - 2; int x2 = mScrollX_last / TILEX + (SCR_FIELDX - 1) + 2; int y2 = mScrollY_last / TILEY + (SCR_FIELDY - 1) + 2; int x, y; BlitBitmap(bitmap_db_field_sp, bitmap_db_field_sp, TILEX_VAR * (dx == -1), TILEY_VAR * (dy == -1), (MAX_BUF_XSIZE * TILEX_VAR) - TILEX_VAR * (dx != 0), (MAX_BUF_YSIZE * TILEY_VAR) - TILEY_VAR * (dy != 0), TILEX_VAR * (dx == 1), TILEY_VAR * (dy == 1)); DrawFrameIfNeeded(); for (y = DisplayMinY; y <= DisplayMaxY; y++) { for (x = DisplayMinX; x <= DisplayMaxX; x++) { if (x >= x1 && x <= x2 && y >= y1 && y <= y2) { int sx = x - x1; int sy = y - y1; int tsi = GetSI(x, y); int id = ((PlayField16[tsi]) | (PlayField8[tsi] << 16) | (DisPlayField[tsi] << 24)); if ((dx == -1 && x == x2) || (dx == +1 && x == x1) || (dy == -1 && y == y2) || (dy == +1 && y == y1)) { DrawFieldNoAnimated(x, y); DrawFieldAnimated(x, y); } ScreenBuffer[sx][sy] = id; } } } } static void ScrollPlayfieldIfNeededExt(boolean reset) { if (reset) { mScrollX_last = -1; mScrollY_last = -1; return; } if (mScrollX_last == -1 || mScrollY_last == -1) { mScrollX_last = (mScrollX / TILESIZE) * TILESIZE; mScrollY_last = (mScrollY / TILESIZE) * TILESIZE; return; } /* check if scrolling the playfield requires redrawing the viewport bitmap */ if ((mScrollX != mScrollX_last || mScrollY != mScrollY_last) && (ABS(mScrollX - mScrollX_last) >= TILEX || ABS(mScrollY - mScrollY_last) >= TILEY)) { int dx = (ABS(mScrollX - mScrollX_last) < TILEX ? 0 : mScrollX < mScrollX_last ? 1 : mScrollX > mScrollX_last ? -1 : 0); int dy = (ABS(mScrollY - mScrollY_last) < TILEY ? 0 : mScrollY < mScrollY_last ? 1 : mScrollY > mScrollY_last ? -1 : 0); mScrollX_last -= dx * TILEX; mScrollY_last -= dy * TILEY; ScrollPlayfield(dx, dy); } } static void ScrollPlayfieldIfNeeded() { ScrollPlayfieldIfNeededExt(FALSE); } void InitScrollPlayfield() { ScrollPlayfieldIfNeededExt(TRUE); } #define DEBUG_REDRAW 0 void UpdatePlayfield(boolean force_redraw) { int x, y; #if DEBUG_REDRAW int num_redrawn = 0; #endif if (force_redraw) { // force re-initialization of graphics status variables for (y = DisplayMinY; y <= DisplayMaxY; y++) for (x = DisplayMinX; x <= DisplayMaxX; x++) GfxGraphic[x][y] = -1; // force complete playfield redraw DisplayLevel(); } for (y = DisplayMinY; y <= DisplayMaxY; y++) { for (x = DisplayMinX; x <= DisplayMaxX; x++) { int element = LowByte(PlayField16[GetSI(x, y)]); int graphic = GfxGraphic[x][y]; int sync_frame = GfxFrame[x][y]; boolean redraw = force_redraw; if (graphic < 0) { GfxGraphicLast[x][y] = GfxGraphic[x][y]; continue; } if (element != GfxElementLast[x][y] && graphic == GfxGraphicLast[x][y]) { /* element changed, but not graphic => disable updating graphic */ GfxElementLast[x][y] = element; GfxGraphicLast[x][y] = GfxGraphic[x][y] = -1; continue; } if (graphic != GfxGraphicLast[x][y]) // new graphic { redraw = TRUE; GfxElementLast[x][y] = element; GfxGraphicLast[x][y] = GfxGraphic[x][y]; sync_frame = GfxFrame[x][y] = 0; } else if (isNextAnimationFrame_SP(graphic, sync_frame)) // new frame { redraw = TRUE; } if (redraw) { int sx = x * StretchWidth; int sy = y * StretchWidth; DDSpriteBuffer_BltImg(sx, sy, graphic, sync_frame); #if DEBUG_REDRAW num_redrawn++; #endif } } } #if DEBUG_REDRAW printf("::: FRAME %d: %d redrawn\n", FrameCounter, num_redrawn); #endif } void BlitScreenToBitmap_SP(Bitmap *target_bitmap) { /* copy playfield buffer to target bitmap at scroll position */ int px = getFieldbufferOffsetX_SP(); int py = getFieldbufferOffsetY_SP(); int xsize = SXSIZE; int ysize = SYSIZE; int full_xsize = (FieldWidth - (menBorder ? 0 : 1)) * TILEX_VAR; int full_ysize = (FieldHeight - (menBorder ? 0 : 1)) * TILEY_VAR; int sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0); int sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0); int sxsize = (full_xsize < xsize ? full_xsize : xsize); int sysize = (full_ysize < ysize ? full_ysize : ysize); BlitBitmap(bitmap_db_field_sp, target_bitmap, px, py, sxsize, sysize, sx, sy); } void DDScrollBuffer_ScrollTo(int X, int Y) { if (NoDisplayFlag) return; ScrollX = mScrollX = X; ScrollY = mScrollY = Y; ScrollPlayfieldIfNeeded(); } void DDScrollBuffer_ScrollTowards(int X, int Y, double Step) { double dx, dY, r; if (NoDisplayFlag) return; dx = X - mScrollX; dY = Y - mScrollY; r = Sqr(dx * dx + dY * dY); if (r == 0) // we are there already return; if (Step < r) r = Step / r; else r = 1; ScrollX = mScrollX = mScrollX + dx * r; ScrollY = mScrollY = mScrollY + dY * r; ScrollPlayfieldIfNeeded(); } void DDScrollBuffer_SoftScrollTo(int X, int Y, int TimeMS, int FPS) { double dx, dY; int StepCount; double T, tStep; int oldX, oldY, maxD; static boolean AlreadyRunning = False; if (NoDisplayFlag) return; if (AlreadyRunning) return; AlreadyRunning = True; dx = X - mScrollX; dY = Y - mScrollY; maxD = (Abs(dx) < Abs(dY) ? Abs(dY) : Abs(dx)); StepCount = FPS * (TimeMS / (double)1000); if (StepCount > maxD) StepCount = maxD; if (StepCount == 0) StepCount = 1; tStep = (double)1 / StepCount; oldX = mScrollX; oldY = mScrollY; for (T = (double)tStep; T <= (double)1; T += tStep) { ScrollX = mScrollX = oldX + T * dx; ScrollY = mScrollY = oldY + T * dY; } ScrollX = mScrollX = X; ScrollY = mScrollY = Y; AlreadyRunning = False; ScrollPlayfieldIfNeeded(); } mirrormagic-3.0.0/src/game_sp/DDScrollBuffer.h0000644000175000017500000000122513263212010020474 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // DDScrollBuffer.h // ---------------------------------------------------------------------------- #ifndef DDSCROLLBUFFER_H #define DDSCROLLBUFFER_H #include "global.h" extern int mScrollX, mScrollY; extern int mScrollX_last, mScrollY_last; extern void InitScrollPlayfield(); extern void UpdatePlayfield(boolean); extern void RestorePlayfield(); extern void DDScrollBuffer_ScrollTo(int X, int Y); extern void DDScrollBuffer_ScrollTowards(int X, int Y, double Step); extern void DDScrollBuffer_SoftScrollTo(int X, int Y, int TimeMS, int FPS); #endif /* DDSCROLLBUFFER_H */ mirrormagic-3.0.0/src/game_sp/Input.h0000644000175000017500000000044413263212010016775 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Input.h // ---------------------------------------------------------------------------- #ifndef INPUT_H #define INPUT_H #include "global.h" extern void subProcessKeyboardInput(byte); #endif /* INPUT_H */ mirrormagic-3.0.0/src/game_sp/Murphy.c0000644000175000017500000020327413263212010017163 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Murphy.c // ---------------------------------------------------------------------------- #include "Murphy.h" static void subEatRedDisk(int si); static boolean subMoveKillsMurphy(int si, int ax, int bl); #define LocalStretch (2) #define MurphyZoomFactor (ZoomFactor) // ========================================================================== // SUBROUTINE // Move Murphy in any direction // ========================================================================== void subAnimateMurphy(int *si) { int ax, al, bl, i, X, Y; int time1, time2; int tDeltaX, tDeltaY, tPos, Tmp; // Variables that hold information about the animation sequence static int dx1 = 0; // image/animation token static int dx2 = 0; // an additional image position of a second sprite, for instance: yellow disk if pushed static int MurphyDX = 0, MurphyDY = 0; // murphys move steps static int SeqPos = 0; // index into dx() static int ClearPos = 0; // Position to clear before blitting sprites, none=-1 static int dxPos = 0; // field-position to draw dx(SeqPos) static int dx2Step = 0; // position of dx2 relative to dx-position static int dx1SequenceLength = 0; ax = PlayField16[*si]; al = LowByte(ax); if (al != fiMurphy) { MurphyMoveCounter = 0; // We have no Murphy! Exit! return; } MurphyMoveCounter = 1; // We have a Murphy! MurphyExplodePos = *si; // (check if high byte of PlayField16 has stored movement information) if (ax != fiMurphy) // yes--go proceed moving murphy? goto locProceedMovingMurphy; // FS: reset moving sequence variables MurphyDX = 0; MurphyDY = 0; ClearPos = *si; dxPos = *si; dx1 = -1; dx2 = -1; SeqPos = 0; // end of FS ScratchGravity = 0; // scratch gravity off if (GravityFlag != 0) // Gravity? (1=gravity on) { bl = LowByte(PlayField16[*si - FieldWidth]); // check above if (! (bl == fiPortUp || bl == fiPortUpAndDown || bl == fiPortAllDirections)) { if (PlayField16[*si + FieldWidth] == 0) // gravity on and space below! ScratchGravity = 1; } } // loc_g_5E8B: bl = DemoKeyCode; if (bl != 0) // a key was pressed! goto locKeyPressed5FCF; RedDiskReleaseFlag = 1; if (ScratchGravity != 0) // gravity pulls & space below?'-> force Space up to down { MurphyDY = 2; goto loc_g_6364; } // ------------------------------------------------------------------ // Murphy's YAWN & SLEEP sequence, counted down by YawnSleepCounter: YawnSleepCounter = YawnSleepCounter + 1; if (YawnSleepCounter < 16) return; if (YawnSleepCounter < 2000) { // normal grin // (default: single graphic, no animation) subCopyAnimToScreen(*si, aniMurphy, YawnSleepCounter - 16); return; } if (YawnSleepCounter < 4000) { // yawn! and look depressed afterwards... // (default: 12 animation frames with delay of 8) subCopyAnimToScreen(*si, aniMurphyYawn, YawnSleepCounter - 2000); return; } if (YawnSleepCounter < 6400) { // yawn again! // (default: 12 animation frames with delay of 8) subCopyAnimToScreen(*si, aniMurphyYawn, YawnSleepCounter - 4000); return; } // time1 = 6400 + 12 * 8; // (default: 6496 == 6400 + 12 * 8) time1 = 6400 + 12 * 10; if (YawnSleepCounter < time1) { // yawn again! - third time // (default: 12 animation frames with delay of 8) subCopyAnimToScreen(*si, aniMurphyYawn, YawnSleepCounter - 6400); return; } // time2 = 6496 + 3 * 64; // (default: 6688 == 6496 + 3 * 64) time2 = 6496 + 3 * 100; if (YawnSleepCounter > time2) // Murphy already went to sleep return; if (PlayField16[*si - 1] == 0) { if (PlayField16[*si + 1] == 0) { // no sleep -- go back to "wait and start yawning" phase YawnSleepCounter = 144; return; } else { // go to sleep (right side) // (default: 3 animation frames with delay of 64) subCopyAnimToScreen(*si, aniMurphySleepRight, YawnSleepCounter - time1); return; } } // go to sleep (left side) // (default: 3 animation frames with delay of 64) subCopyAnimToScreen(*si, aniMurphySleepLeft, YawnSleepCounter - time1); return; // end of YAWN-SLEEP-Sequence // ------------------------------------------------------------------ // ========================================================================== // (Direct Jump) a key was pressed // ========================================================================== locKeyPressed5FCF: if (ScratchGravity == 0) goto loc_g_6003; if (PlayField16[*si + FieldWidth] != 0) goto loc_g_6003; if (bl == keyUp) { if (PlayField16[*si - FieldWidth] == fiBase) goto loc_g_6003; } else if (bl == keyLeft) { if (PlayField16[*si - 1] == fiBase) goto loc_g_6003; } else if (bl == keyRight) { if (PlayField16[*si + 1] == fiBase) goto loc_g_6003; } // loc_g_6001: bl = keyDown; // force moving down! loc_g_6003: switch (bl) { case keyUp: // 1 RedDiskReleaseFlag = 0; // moving down to up ... goto loc_g_6078; break; case keyLeft: // 2 RedDiskReleaseFlag = 0; // moving right to left ... goto loc_g_60DA; break; case keyDown: // 3 RedDiskReleaseFlag = 0; // moving up to down ... goto loc_g_6154; break; case keyRight: // 4 RedDiskReleaseFlag = 0; // moving left to right ... goto loc_g_61B6; break; case keySpaceUp: // 5 RedDiskReleaseFlag = 0; // touching down to up ... goto loc_g_622E; break; case keySpaceLeft: // 6 RedDiskReleaseFlag = 0; // touching right to left ... goto loc_g_6258; break; case keySpaceDown: // 7 RedDiskReleaseFlag = 0; // touching up to down ... goto loc_g_6288; break; case keySpaceRight: // 8 RedDiskReleaseFlag = 0; // touching left to right ... goto loc_g_62B2; break; case keySpace: // 9 goto loc_g_62E2; // no move ... break; default: RedDiskReleaseFlag = 0; return; break; } // ========================================================================== // moving down to up ... // ========================================================================== loc_g_6078: // FS: MurphyDY = -2; // end of FS ax = PlayField16[*si - FieldWidth]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6312; if (ax == fiBase) goto loc_g_63D3; if (al == fiBug) goto loc_g_63C2; if (ax == fiInfotron) goto loc_g_65C6; if (ax == fiExit) goto loc_g_6756; if (al == fiTerminal) goto loc_g_6817; if (al == fiPortUp || al == fiPortUpAndDown || al == fiPortAllDirections) goto loc_g_6916; if (al == fiRedDisk) goto loc_g_69A6; if (al == fiYellowDisk) goto loc_g_6AB8; if (! subMoveKillsMurphy(*si - FieldWidth, ax, bl)) goto loc_g_6078; return; // ========================================================================== // moving right to left ... // ========================================================================== loc_g_60DA: // FS: MurphyDX = -2; // end of FS MurphyVarFaceLeft = 1; ax = PlayField16[*si - 1]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6341; if (ax == fiBase) goto loc_g_641C; if (al == fiBug) goto loc_g_640B; if (ax == fiInfotron) goto loc_g_65FE; if (ax == fiExit) goto loc_g_6756; if (ax == fiZonk) goto loc_g_679B; if (al == fiTerminal) goto loc_g_684E; if (al == fiPortLeft || al == fiPortLeftAndRight || al == fiPortAllDirections) goto loc_g_693A; if (ax == fiRedDisk) goto loc_g_69CE; if (ax == fiYellowDisk) goto loc_g_6AF1; if (ax == fiOrangeDisk) goto loc_g_6B9B; if (! subMoveKillsMurphy(*si - 1, ax, bl)) goto loc_g_60DA; return; // ========================================================================== // moving up to down ... // ========================================================================== loc_g_6154: // FS: MurphyDY = 2; // end of FS ax = PlayField16[*si + FieldWidth]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6364; if (ax == fiBase) goto loc_g_6459; if (al == fiBug) goto loc_g_6448; if (ax == fiInfotron) goto loc_g_662A; if (ax == fiExit) goto loc_g_6756; if (al == fiTerminal) goto loc_g_6884; if (al == fiPortDown || al == fiPortUpAndDown || al == fiPortAllDirections) goto loc_g_695E; if (al == fiRedDisk) goto loc_g_69F7; if (al == fiYellowDisk) goto loc_g_6B2A; if (! subMoveKillsMurphy(*si + FieldWidth, ax, bl)) goto loc_g_6154; return; // ========================================================================== // moving left to right ... // ========================================================================== loc_g_61B6: // FS: MurphyDX = 2; // end of FS MurphyVarFaceLeft = 0; ax = PlayField16[*si + 1]; al = LowByte(ax); if (ax == fiSpace) goto loc_g_6399; if (ax == fiBase) goto loc_g_64A2; if (al == fiBug) goto loc_g_6491; if (ax == fiInfotron) goto loc_g_6662; if (ax == fiExit) goto loc_g_6756; if (ax == fiZonk) goto loc_g_67D4; if (al == fiTerminal) goto loc_g_68BA; if (al == fiPortRight || al == fiPortLeftAndRight || al == fiPortAllDirections) goto loc_g_6982; if (al == fiRedDisk) goto loc_g_6A1F; if (al == fiYellowDisk) goto loc_g_6B63; if (ax == fiOrangeDisk) goto loc_g_6BD3; if (! subMoveKillsMurphy(*si + 1, ax, bl)) goto loc_g_61B6; return; // ========================================================================== // touching down to up ... // ========================================================================== loc_g_622E: // FS: ClearPos = -1; dxPos = *si - FieldWidth; // end of FS ax = PlayField16[*si - FieldWidth]; al = LowByte(ax); al = LowByte(ax); if (ax == fiBase) goto loc_g_64DF; if (al == fiBug) goto loc_g_64CE; if (ax == fiInfotron) goto loc_g_668E; if (al == fiTerminal) goto loc_g_6817; if (al == fiRedDisk) goto loc_g_6A48; return; // ========================================================================== // touching right to left ... // ========================================================================== loc_g_6258: // FS: ClearPos = -1; dxPos = *si - 1; // end of FS MurphyVarFaceLeft = 1; ax = PlayField16[*si - 1]; al = LowByte(ax); if (ax == fiBase) goto loc_g_651D; if (al == fiBug) goto loc_g_650C; if (ax == fiInfotron) goto loc_g_66C0; if (al == fiTerminal) goto loc_g_684E; if (al == fiRedDisk) goto loc_g_6A64; return; // ========================================================================== // touching up to down ... // ========================================================================== loc_g_6288: // FS: ClearPos = -1; dxPos = *si + FieldWidth; // end of FS ax = PlayField16[*si + FieldWidth]; al = LowByte(ax); if (ax == fiBase) goto loc_g_655B; if (al == fiBug) goto loc_g_654A; if (ax == fiInfotron) goto loc_g_66F2; if (al == fiTerminal) goto loc_g_6884; if (al == fiRedDisk) goto loc_g_6A80; return; // ========================================================================== // touching left to right ... // ========================================================================== loc_g_62B2: // FS: ClearPos = -1; dxPos = *si + 1; // end of FS MurphyVarFaceLeft = 0; ax = PlayField16[*si + 1]; al = LowByte(ax); if (ax == fiBase) goto loc_g_6599; if (al == fiBug) goto loc_g_6588; if (ax == fiInfotron) goto loc_g_6724; if (al == fiTerminal) goto loc_g_68BA; if (al == fiRedDisk) goto loc_g_6A9C; return; // ========================================================================== // Release Red disk: no move ... // ========================================================================== loc_g_62E2: // FS: ClearPos = -1; // end of FS if (LowByte(RedDiskCount) == 0) return; if (LowByte(RedDiskReleasePhase) != 0) return; if (LowByte(RedDiskReleaseFlag) != 1) return; MovHighByte(&PlayField16[*si], 0x2A); MovingPictureSequencePhase = 0x40; // init picture move sequence dx1 = aniRedDisk; MovLowByte(&RedDiskReleasePhase, 1); RedDiskReleaseMurphyPos = *si; // remember Murphy's location goto loc_Split; // ========================================================================== // SPACE moving down to up // ========================================================================== loc_g_6312: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyMoveUpRight : aniMurphyMoveUpLeft); PlayField16[*si - FieldWidth] = 0x103; PlayField16[*si] = 0x300; *si = *si - FieldWidth; goto loc_StopNoSplit; // ========================================================================== // SPACE moving right to left // ========================================================================== loc_g_6341: dx1 = aniMurphyMoveLeft; PlayField16[*si - 1] = 0x203; PlayField16[*si] = 0x300; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // SPACE moving up to down, and when gravity is pulling! // ========================================================================== loc_g_6364: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyMoveUpRight : aniMurphyMoveUpLeft); PlayField16[*si + FieldWidth] = 0x303; PlayField16[*si] = 0x300; *si = *si + FieldWidth; goto loc_StopNoSplit; // ========================================================================== // SPACE moving left to right // ========================================================================== loc_g_6399: dx1 = aniMurphyMoveRight; PlayField16[*si + 1] = 0x403; PlayField16[*si] = 0x300; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // BUG moving down to up // ========================================================================== loc_g_63C2: if (SgnHighByte(PlayField16[*si - FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - FieldWidth] = fiBase; // ========================================================================== // BASE moving down to up // ========================================================================== loc_g_63D3: subSoundFX(*si, fiBase, actDigging); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyDigUpRight : aniMurphyDigUpLeft); PlayField16[*si - FieldWidth] = 0x503; PlayField16[*si] = 0x300; *si = *si - FieldWidth; goto loc_StopNoSplit; // ========================================================================== // BUG moving right to left // ========================================================================== loc_g_640B: if (SgnHighByte(PlayField16[*si - 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - 1] = fiBase; // ========================================================================== // BASE moving right to left // ========================================================================== loc_g_641C: subSoundFX(*si, fiBase, actDigging); dx1 = aniMurphyDigLeft; PlayField16[*si - 1] = 0x203; PlayField16[*si] = 0x300; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // BUG moving up to down // ========================================================================== loc_g_6448: if (SgnHighByte(PlayField16[*si + FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + FieldWidth] = fiBase; // ========================================================================== // BASE moving up to down // ========================================================================== loc_g_6459: subSoundFX(*si, fiBase, actDigging); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyDigUpRight : aniMurphyDigUpLeft); PlayField16[*si + FieldWidth] = 0x703; PlayField16[*si] = 0x300; *si = *si + FieldWidth; goto loc_StopNoSplit; // ========================================================================== // BUG moving left to right // ========================================================================== loc_g_6491: if (SgnHighByte(PlayField16[*si + 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + 1] = fiBase; // ========================================================================== // BASE moving left to right // ========================================================================== loc_g_64A2: subSoundFX(*si, fiBase, actDigging); dx1 = aniMurphyDigRight; PlayField16[*si + 1] = 0x803; PlayField16[*si] = 0x300; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // BUG touching down to up // ========================================================================== loc_g_64CE: if (SgnHighByte(PlayField16[*si - FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - FieldWidth] = fiBase; // ========================================================================== // BASE touching down to up // ========================================================================== loc_g_64DF: subCopyImageToScreen(*si, aniMurphyTouchUp); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si - FieldWidth; MovHighByte(&PlayField16[*si], 0x10); goto loc_StopNoSplit; // ========================================================================== // BUG touching right to left // ========================================================================== loc_g_650C: if (SgnHighByte(PlayField16[*si - 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si - 1] = fiBase; // ========================================================================== // BASE touching right to left // ========================================================================== loc_g_651D: subCopyImageToScreen(*si, aniMurphyTouchLeft); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si - 1; MovHighByte(&PlayField16[*si], 0x11); goto loc_StopNoSplit; // ========================================================================== // BUG touching up to down // ========================================================================== loc_g_654A: if (SgnHighByte(PlayField16[*si + FieldWidth]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + FieldWidth] = fiBase; // ========================================================================== // BASE touching up to down // ========================================================================== loc_g_655B: subCopyImageToScreen(*si, aniMurphyTouchDown); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si + FieldWidth; MovHighByte(&PlayField16[*si], 0x12); goto loc_StopNoSplit; // ========================================================================== // BUG touching left to right // ========================================================================== loc_g_6588: if (SgnHighByte(PlayField16[*si + 1]) >= 0) { ExplodeFieldSP(*si); // Explode return; } PlayField16[*si + 1] = fiBase; // ========================================================================== // BASE touching left to right // ========================================================================== loc_g_6599: subCopyImageToScreen(*si, aniMurphyTouchRight); subSoundFX(*si, fiBase, actDigging); dx1 = aniTouchBase; dxPos = *si + 1; MovHighByte(&PlayField16[*si], 0x13); goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving down to up // ========================================================================== loc_g_65C6: subSoundFX(*si, fiInfotron, actCollecting); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si - FieldWidth] = 0x903; PlayField16[*si] = 0x300; *si = *si - FieldWidth; goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving right to left // ========================================================================== loc_g_65FE: subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniEatInfotronLeft; PlayField16[*si - 1] = 0xA03; PlayField16[*si] = 0x300; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving up to down // ========================================================================== loc_g_662A: subSoundFX(*si, fiInfotron, actCollecting); dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si + FieldWidth] = 0xB03; PlayField16[*si] = 0x300; *si = *si + FieldWidth; goto loc_StopNoSplit; // ========================================================================== // INFOTRON moving left to right // ========================================================================== loc_g_6662: subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniEatInfotronRight; PlayField16[*si + 1] = 0xC03; PlayField16[*si] = 0x300; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching down to up // ========================================================================== loc_g_668E: subCopyImageToScreen(*si, aniMurphyTouchUp); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x14); MovHighByte(&PlayField16[*si - FieldWidth], 0xFF); goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching right to left // ========================================================================== loc_g_66C0: subCopyImageToScreen(*si, aniMurphyTouchLeft); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x15); MovHighByte(&PlayField16[*si - 1], 0xFF); goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching up to down // ========================================================================== loc_g_66F2: subCopyImageToScreen(*si, aniMurphyTouchDown); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x16); MovHighByte(&PlayField16[*si + FieldWidth], 0xFF); goto loc_StopNoSplit; // ========================================================================== // INFOTRON touching left to right // ========================================================================== loc_g_6724: subCopyImageToScreen(*si, aniMurphyTouchRight); subSoundFX(*si, fiInfotron, actCollecting); dx1 = aniTouchInfotron; MovHighByte(&PlayField16[*si], 0x17); MovHighByte(&PlayField16[*si + 1], 0xFF); goto loc_StopNoSplit; // ========================================================================== // EXIT pressed from any direction // ========================================================================== loc_g_6756: // FS ClearPos = -1; MurphyDX = 0; MurphyDY = 0; // end of FS if (LowByte(InfotronsNeeded) != 0) return; game_sp.LevelSolved = TRUE; subSoundFX(*si, fiExit, actPassing); LeadOutCounter = 0x40; // quit: start lead-out dx1 = aniMurphyExit; MovHighByte(&PlayField16[*si], 0xD); goto loc_StopNoSplit; // ========================================================================== // ZONK moving right to left // ========================================================================== loc_g_679B: ax = PlayField16[*si - 2]; if (ax != 0) return; MovHighByte(&PlayField16[*si - 2], 1); subCopyImageToScreen(*si, aniPushLeft); // draw pushing murphy dx1 = aniZonkRollLeft; dxPos = *si - 1; dx2 = aniPushLeft; dx2Step = 1; MovHighByte(&PlayField16[*si], 0xE); goto loc_MoveNoSplit; // ========================================================================== // ZONK moving left to right // ========================================================================== loc_g_67D4: ax = PlayField16[*si + 2]; if (ax != 0) return; ax = PlayField16[*si + FieldWidth + 1]; if (ax == 0) // zonk falls return; MovHighByte(&PlayField16[*si + 2], 1); subCopyImageToScreen(*si, aniPushRight); // draw pushing murphy dx1 = aniZonkRollRight; dxPos = *si + 1; dx2 = aniPushRight; dx2Step = -1; MovHighByte(&PlayField16[*si], 0xF); goto loc_MoveNoSplit; // ========================================================================== // TERMINAL moving/touching down to up // ========================================================================== loc_g_6817: subCopyImageToScreen(*si, aniMurphyTouchUp); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: // draw new terminal type GfxGraphic[GetX(*si - FieldWidth)][GetY(*si - FieldWidth)] = aniTerminalActive; TerminalState[*si - FieldWidth] = 8; goto loc_g_68F0; // ========================================================================== // TERMINAL moving/touching right to left // ========================================================================== loc_g_684E: subCopyImageToScreen(*si, aniMurphyTouchLeft); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: // draw new terminal type GfxGraphic[GetX(*si - 1)][GetY(*si - 1)] = aniTerminalActive; TerminalState[*si - 1] = 8; goto loc_g_68F0; // ========================================================================== // TERMINAL moving/touching up to down // ========================================================================== loc_g_6884: subCopyImageToScreen(*si, aniMurphyTouchDown); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: // draw new terminal type GfxGraphic[GetX(*si + FieldWidth)][GetY(*si + FieldWidth)] = aniTerminalActive; TerminalState[*si + FieldWidth] = 8; goto loc_g_68F0; // ========================================================================== // TERMINAL moving/touching left to right // ========================================================================== loc_g_68BA: subCopyImageToScreen(*si, aniMurphyTouchRight); if (YellowDisksExploded != 0) { YawnSleepCounter = 40; // stay hypnotized return; } // loc_g_6838: // draw new terminal type GfxGraphic[GetX(*si + 1)][GetY(*si + 1)] = aniTerminalActive; TerminalState[*si + 1] = 8; // ========================================================================== // common TERMINAL stuff moving/touching from all directions // ========================================================================== loc_g_68F0: TerminalMaxCycles = 7; YellowDisksExploded = 1; for (i = 0; i <= LevelMax; i++) { if (PlayField16[i] == fiYellowDisk) ExplodeFieldSP (i); } return; // ========================================================================== // PORT down to up, VERTICAL PORT, CROSS PORT all moving down to up // ========================================================================== loc_g_6916: if (PlayField16[*si - 2 * FieldWidth] != 0) return; dx1 = aniSplitUpDown; dx2Step = -FieldWidth; PlayField16[*si] = 0x1803; PlayField16[*si - 2 * FieldWidth] = 0x300; goto loc_StopSplit; // ========================================================================== // PORT right to left, HORIZONTAL PORT, CROSS PORT all moving right to left // ========================================================================== loc_g_693A: if (PlayField16[*si - 2] != 0) return; dx1 = aniMurphyMoveLeft; dx2Step = -1; PlayField16[*si] = 0x1903; PlayField16[*si - 2] = 0x300; goto loc_StopSplit; // ========================================================================== // PORT up to down, VERTICAL PORT, CROSS PORT all moving up to down // ========================================================================== loc_g_695E: if (PlayField16[*si + 2 * FieldWidth] != 0) return; dx1 = aniSplitUpDown; dx2Step = FieldWidth; PlayField16[*si] = 0x1A03; PlayField16[*si + 2 * FieldWidth] = 0x300; goto loc_StopSplit; // ========================================================================== // PORT left to right, HORIZONTAL PORT, CROSS PORT all moving left to right // ========================================================================== loc_g_6982: if (PlayField16[*si + 2] != 0) return; dx1 = aniMurphyMoveRight; dx2Step = 1; PlayField16[*si] = 0x1B03; PlayField16[*si + 2] = 0x300; loc_StopSplit: MovingPictureSequencePhase = 0; // stop picture move sequence SplitMoveFlag = 1; // port: split movement goto loc_Split; // ========================================================================== // RED DISK moving down to up // ========================================================================== loc_g_69A6: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si] = 0x1C03; PlayField16[*si - FieldWidth] = 0x300; goto loc_StopNoSplit; // ========================================================================== // RED DISK moving right to left // ========================================================================== loc_g_69CE: dx1 = aniMurphyEatLeft; PlayField16[*si] = 0x300; // !!!!!! this time we move murphy at sequence-start! PlayField16[*si - 1] = 0x1D03; *si = *si - 1; goto loc_StopNoSplit; // ========================================================================== // RED DISK moving up to down // ========================================================================== loc_g_69F7: dx1 = (MurphyVarFaceLeft == 0 ? aniMurphyEatUpRight : aniMurphyEatUpLeft); PlayField16[*si] = 0x1E03; PlayField16[*si + FieldWidth] = 0x300; goto loc_StopNoSplit; // ========================================================================== // RED DISK moving left to right // ========================================================================== loc_g_6A1F: // dx = aniMurphyEatRightRedDisk 'this sequence is 9 steps long! dx1 = aniMurphyEatRight; // -------------------------------------------------------------------------- // BugFix // Table data_h_145A, pointed to by table data_h_105E, has a severe bug: // The Red Disk sequence is 8 pictures long, but 9 are displayed, because it // has 1 extra entry, which causes Murphy to end slightly shifted to the left! // We may not fix the table, because then the timing of the game changes // and several existing demo's do not run properly anymore. // We only correct Murphies x-location here, when the sequence starts. // Remember that this is not the real bug-fix, but we must live with // this existing bug and correct for the consequences of it. if (AllowEatRightRedDiskBug == 0) // Murphy's screen x-position MurphyScreenXPos = MurphyScreenXPos - 2 * MurphyZoomFactor; SeqPos = -1; // FS: for me this means to blit the first animation frame twice // end of BugFix // -------------------------------------------------------------------------- PlayField16[*si] = 0x300; // !!!!!! this time we move murphy at sequence-start! PlayField16[*si + 1] = 0x1F03; *si = *si + 1; goto loc_StopNoSplit; // ========================================================================== // RED DISK touching down to up // ========================================================================== loc_g_6A48: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x20); MovHighByte(&PlayField16[*si - FieldWidth], 3); goto loc_StopNoSplit; // ========================================================================== // RED DISK touching right to left // ========================================================================== loc_g_6A64: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x21); MovHighByte(&PlayField16[*si - 1], 3); goto loc_StopNoSplit; // ========================================================================== // RED DISK touching up to down // ========================================================================== loc_g_6A80: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x22); MovHighByte(&PlayField16[*si + FieldWidth], 3); goto loc_StopNoSplit; // ========================================================================== // RED DISK touching left to right // ========================================================================== loc_g_6A9C: dx1 = aniTouchRedDisk; MovHighByte(&PlayField16[*si], 0x23); MovHighByte(&PlayField16[*si + 1], 3); loc_StopNoSplit: MovingPictureSequencePhase = 0; // stop picture move sequence goto loc_NoSplit; // ========================================================================== // YELLOW DISK moving down to up // ========================================================================== loc_g_6AB8: if (PlayField16[*si - 2 * FieldWidth] != 0) return; PlayField16[*si - 2 * FieldWidth] = 0x1200; dx1 = aniYellowDisk; dxPos = *si - FieldWidth; dx2 = (MurphyVarFaceLeft == 0 ? aniPushRight : aniPushLeft); dx2Step = FieldWidth; PlayField16[*si] = 0x2403; subCopyImageToScreen(*si, dx2); goto loc_MoveNoSplit; // ========================================================================== // YELLOW DISK moving right to left // ========================================================================== loc_g_6AF1: if (PlayField16[*si - 2] != 0) return; PlayField16[*si - 2] = 0x1200; subCopyImageToScreen(*si, aniPushLeft); dx1 = aniYellowDisk; dxPos = *si - 1; dx2 = aniPushLeft; dx2Step = 1; PlayField16[*si] = 0x2503; goto loc_MoveNoSplit; // ========================================================================== // YELLOW DISK moving up to down // ========================================================================== loc_g_6B2A: if (PlayField16[*si + 2 * FieldWidth] != 0) return; PlayField16[*si + 2 * FieldWidth] = 0x1200; dx1 = aniYellowDisk; dxPos = *si + FieldWidth; dx2 = (MurphyVarFaceLeft == 0 ? aniPushRight : aniPushLeft); dx2Step = -FieldWidth; PlayField16[*si] = 0x2703; subCopyImageToScreen(*si, dx2); goto loc_MoveNoSplit; // ========================================================================== // YELLOW DISK moving left to right // ========================================================================== loc_g_6B63: if (PlayField16[*si + 2] != 0) return; PlayField16[*si + 2] = 0x1200; subCopyImageToScreen(*si, aniPushRight); dx1 = aniYellowDisk; dxPos = *si + 1; dx2 = aniPushRight; dx2Step = -1; PlayField16[*si] = 0x2603; goto loc_MoveNoSplit; // ========================================================================== // ORANGE DISK moving right to left // ========================================================================== loc_g_6B9B: if (PlayField16[*si - 2] != 0) return; PlayField16[*si - 2] = 0x800; subCopyImageToScreen(*si, aniPushLeft); dx1 = aniOrangeDisk; dxPos = *si - 1; dx2 = aniPushLeft; dx2Step = 1; PlayField16[*si] = 0x2803; goto loc_MoveNoSplit; // ========================================================================== // ORANGE DISK moving left to right // ========================================================================== loc_g_6BD3: if (PlayField16[*si + 2] != 0) return; if (PlayField16[*si + FieldWidth + 1] == 0) // falling goes before pushing return; PlayField16[*si + 2] = 0x100; subCopyImageToScreen(*si, aniPushRight); dx1 = aniOrangeDisk; dxPos = *si + 1; dx2 = aniPushRight; dx2Step = -1; PlayField16[*si] = 0x2903; // ========================================================================== // Copy screen animation action table to action work space // (To paint sequence: Push Zonk/Disk / release red disk / Port passing) // ========================================================================== loc_MoveNoSplit: MovingPictureSequencePhase = 8; // init picture move sequence loc_NoSplit: SplitMoveFlag = 0; // no port: no split movement loc_Split: // copy/store global move sequence info???????????????????????????????????? // ... dont think so ...(FS) // ========================================================================== // Proceed with all movements // ========================================================================== locProceedMovingMurphy: // proceed moving murphy YawnSleepCounter = 0; // Wake up sleeping Murphy ax = MovingPictureSequencePhase; // sequence busy? if (ax == 0) // no -- start sequence! goto loc_g_6C8F; ax = ax - 1; // next picture of sequence MovingPictureSequencePhase = ax; // store for later if (ax == 0) // Sound effects { switch (HighByte(PlayField16[*si])) { case 0xE: case 0xF: subSoundFX(*si, fiZonk, actPushing); break; case 0x28: case 0x29: subSoundFX(*si, fiOrangeDisk, actPushing); break; case 0x24: case 0x25: case 0x26: case 0x27: subSoundFX(*si, fiYellowDisk, actPushing); break; default: break; } } bl = HighByte(PlayField16[*si]); if (bl == 0xE) // Push Zonk to left goto loc_g_6F7E; if (bl == 0xF) // Push Zonk to right goto loc_g_6FBC; if (bl == 0x28) // Push orange disk to left goto loc_g_6FFA; if (bl == 0x29) // Push orange disk to right goto loc_g_7038; if (bl == 0x24) // Push yellow disk up goto loc_g_7076; if (bl == 0x25) // Push yellow disk to left goto loc_g_70B4; if (bl == 0x27) // Push yellow disk down goto loc_g_70F2; if (bl == 0x26) // Push yellow disk to right goto loc_g_7130; if (bl == 0x2A) // Red disk release timer goto loc_g_716E; return; // ========================================================================== // Paint frame of MOVING.DAT sequence // ========================================================================== loc_g_6C8F: if (SeqPos <= 0) dx1SequenceLength = getSequenceLength(dx1); if (SplitMoveFlag == 0) { // ++++++++++++++++++++++++++ // Begin of normal movement MurphyScreenXPos = MurphyScreenXPos + MurphyDX * MurphyZoomFactor; MurphyScreenYPos = MurphyScreenYPos + MurphyDY * MurphyZoomFactor; if (!(ClearPos < 0)) // clear field that murphy is leaving subCopyImageToScreen(ClearPos, aniSpace); tDeltaX = MurphyDX * LocalStretch * (SeqPos + 1); tDeltaY = MurphyDY * LocalStretch * (SeqPos + 1); X = GetStretchX(dxPos) + tDeltaX; Y = GetStretchY(dxPos) + tDeltaY; Tmp = (SeqPos < 0 ? 0 : SeqPos); // 9StepBugFix!(red disk move right) if (isSnappingSequence(dx1) && SeqPos == dx1SequenceLength - 1) dx1 = aniSpace; DDSpriteBuffer_BltImg(X, Y, dx1, Tmp); GfxGraphic[GetX(*si)][GetY(*si)] = -1; // (Murphy's position) GfxGraphic[GetX(dxPos)][GetY(dxPos)] = -1; // (snapping position) if (!(dx2 < 0)) { tPos = dxPos + dx2Step; X = GetStretchX(tPos); Y = GetStretchY(tPos); // (SeqPos iterates from 0 to 7 while pushing) DDSpriteBuffer_BltImg(X + tDeltaX, Y + tDeltaY, dx2, SeqPos); } // End of normal movement // ------------------------ } else { // ++++++++++++++++++++++++++++++++ // Begin of split movement (port) MurphyScreenXPos = MurphyScreenXPos + 2 * MurphyDX * MurphyZoomFactor; MurphyScreenYPos = MurphyScreenYPos + 2 * MurphyDY * MurphyZoomFactor; subCopyImageToScreen(ClearPos, aniSpace); // clear the field that murphy leaves tDeltaX = MurphyDX * LocalStretch * (SeqPos + 1); tDeltaY = MurphyDY * LocalStretch * (SeqPos + 1); X = GetStretchX(dxPos) + tDeltaX; Y = GetStretchY(dxPos) + tDeltaY; DDSpriteBuffer_BltImg(X, Y, dx1, SeqPos); // plot first murphy tPos = dxPos + dx2Step; X = GetStretchX(tPos); Y = GetStretchY(tPos); DDSpriteBuffer_BltImg(X + tDeltaX, Y + tDeltaY, dx1, SeqPos); // plot second murphy DDSpriteBuffer_BltImg(X, Y, fiGraphic[LowByte(PlayField16[tPos])], 0); // replot the port on top // End of split movement (port) // ------------------------------ } // loc_g_6D1E:'loc_g_6D28: SeqPos = SeqPos + 1; if (SeqPos < dx1SequenceLength) return; // Follow-up after movement completed 'loc_g_6D35: MurphyXPos = MurphyXPos + MurphyDX; MurphyYPos = MurphyYPos + MurphyDY; bl = HighByte(PlayField16[*si]); // animation phase MovHighByte(&PlayField16[*si], 0); if (bl == 0x1) // space, moving up goto loc_g_6EC8; if (bl == 0x2) // space, moving left goto loc_g_6EE6; if (bl == 0x3) // space, moving down goto loc_g_6F04; if (bl == 0x4) // space, moving right goto loc_g_71C4; if (bl == 0x5) // base , moving up goto loc_g_6EC8; if (bl == 0x6) // base , moving left -> 6 is not used, value is set to 2 instead of 6! goto loc_g_6EE6; if (bl == 0x7) // base , moving down goto loc_g_6F04; if (bl == 0x8) // base , moving right goto loc_g_71C4; if (bl == 0x9) // infotron, moving up goto loc_g_6EBA; if (bl == 0xA) // infotron, moving left goto loc_g_6ED8; if (bl == 0xB) // infotron, moving down goto loc_g_6EF6; if (bl == 0xC) // infotron, moving right goto loc_g_71B6; if (bl == 0xD) // exit goto loc_g_6F77; if (bl == 0xE) // zonk, pushing left goto loc_g_6F18; if (bl == 0xF) // zonk, pushing right goto loc_g_6F3B; if (bl == 0x10) // base , touching up goto loc_g_71E2; if (bl == 0x11) // base , touching left goto loc_g_71FE; if (bl == 0x12) // base , touching down goto loc_g_721A; if (bl == 0x13) // base , touching right goto loc_g_7236; if (bl == 0x14) // infotron touching up goto loc_g_71D4; if (bl == 0x15) // infotron touching left goto loc_g_71F0; if (bl == 0x16) // infotron touching down goto loc_g_720C; if (bl == 0x17) // infotron touching right goto loc_g_7228; if (bl == 0x18) // port up goto loc_g_7244; if (bl == 0x19) // port left goto loc_g_7272; if (bl == 0x1A) // port down goto loc_g_729F; if (bl == 0x1B) // port right goto loc_g_72CD; if (bl == 0x1C) // red disk, moving up goto loc_g_72FA; if (bl == 0x1D) // red disk, moving left goto loc_g_7318; if (bl == 0x1E) // red disk, moving down goto loc_g_7333; if (bl == 0x1F) // red disk, moving right -> 9-Step-Bug! goto loc_g_7351; if (bl == 0x20) // red disk, touching up goto loc_g_736C; if (bl == 0x21) // red disk, touching left goto loc_g_7381; if (bl == 0x22) // red disk, touching down goto loc_g_7396; if (bl == 0x23) // red disk, touching right goto loc_g_73AB; if (bl == 0x24) // yellow disk, pushing up goto loc_g_73C0; if (bl == 0x25) // yellow disk, pushing left goto loc_g_73DD; if (bl == 0x26) // yellow disk, pushing right -> order of "down" exchanged with "right"! goto loc_g_7417; if (bl == 0x27) // yellow disk, pushing down -> order of "down" exchanged with "right"! goto loc_g_73FA; if (bl == 0x28) // orange disk, pushing left goto loc_g_7434; if (bl == 0x29) // orange disk, pushing right goto loc_g_7451; if (bl == 0x2A) // red disk, release goto loc_g_747F; ExitToMenuFlag = 1; return; // ========================================================================== // infotron, moving up // ========================================================================== loc_g_6EBA: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_6EC8: // space, base PlayField16[*si] = fiMurphy; subAdjustZonksInfotronsAboveMurphy(*si + FieldWidth); return; // ========================================================================== // infotron, moving left // ========================================================================== loc_g_6ED8: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_6EE6: // space, base PlayField16[*si] = fiMurphy; subAdjustZonksInfotronsAboveMurphy(*si + 1); return; // ========================================================================== // infotron, moving down // ========================================================================== loc_g_6EF6: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_6F04: // space, base if (LowByte(PlayField16[*si - FieldWidth]) != fiExplosion) PlayField16[*si - FieldWidth] = 0; PlayField16[*si] = fiMurphy; return; // ========================================================================== // infotron, moving right // ========================================================================== loc_g_71B6: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_71C4: // space, base subAdjustZonksInfotronsAboveMurphy(*si - 1); PlayField16[*si] = fiMurphy; return; // ========================================================================== // infotron, touching up // ========================================================================== loc_g_71D4: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_71E2: // base if (LowByte(PlayField16[*si - FieldWidth]) != fiExplosion) PlayField16[*si - FieldWidth] = 0; return; // ========================================================================== // infotron, touching left // ========================================================================== loc_g_71F0: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_71FE: // base if (LowByte(PlayField16[*si - 1]) != fiExplosion) PlayField16[*si - 1] = 0; return; // ========================================================================== // infotron, touching down // ========================================================================== loc_g_720C: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_721A: // base if (LowByte(PlayField16[*si + FieldWidth]) != fiExplosion) PlayField16[*si + FieldWidth] = 0; return; // ========================================================================== // infotron, touching right // ========================================================================== loc_g_7228: if (0 < LowByte(InfotronsNeeded)) InfotronsNeeded = InfotronsNeeded - 1; loc_g_7236: // base if (LowByte(PlayField16[*si + 1]) != fiExplosion) PlayField16[*si + 1] = 0; return; // ========================================================================== // zonk, pushing left // ========================================================================== loc_g_6F18: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si - 1] = fiMurphy; PlayField16[*si - 2] = fiZonk; subExplodeSnikSnaksBelow(*si - 2); *si = *si - 1; return; // ========================================================================== // zonk, pushing right // ========================================================================== loc_g_6F3B: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si + 1] = fiMurphy; PlayField16[*si + 2] = fiZonk; subExplodeSnikSnaksBelow(*si + 2); *si = *si + 1; return; // ========================================================================== // exit // ========================================================================== loc_g_6F77: ExitToMenuFlag = 1; PlayField16[*si] = fiSpace; // remove Murphy from playfield after exiting return; // ========================================================================== // Push Zonk from right to left // ========================================================================== loc_g_6F7E: if (DemoKeyCode == keyLeft && PlayField16[*si - 1] == fiZonk) return; PlayField16[*si] = fiMurphy; // else restore - no more zonk pushing! PlayField16[*si - 1] = fiZonk; if (LowByte(PlayField16[*si - 2]) != fiExplosion) PlayField16[*si - 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push Zonk from left to right // ========================================================================== loc_g_6FBC: if (DemoKeyCode == keyRight && PlayField16[*si + 1] == fiZonk) return; PlayField16[*si] = fiMurphy; // else restore - no more zonk pushing! PlayField16[*si + 1] = fiZonk; if (LowByte(PlayField16[*si + 2]) != fiExplosion) PlayField16[*si + 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push orange disk from right to left // ========================================================================== loc_g_6FFA: if (DemoKeyCode == keyLeft && PlayField16[*si - 1] == fiOrangeDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si - 1] = fiOrangeDisk; if (LowByte(PlayField16[*si - 2]) != fiExplosion) PlayField16[*si - 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push orange disk from left to right // ========================================================================== loc_g_7038: if (DemoKeyCode == keyRight && PlayField16[*si + 1] == fiOrangeDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si + 1] = fiOrangeDisk; if (LowByte(PlayField16[*si + 2]) != fiExplosion) PlayField16[*si + 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from down to up // ========================================================================== loc_g_7076: if (DemoKeyCode == keyUp && PlayField16[*si - FieldWidth] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si - FieldWidth] = fiYellowDisk; if (LowByte(PlayField16[*si - 2 * FieldWidth]) != fiExplosion) PlayField16[*si - 2 * FieldWidth] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from right to left // ========================================================================== loc_g_70B4: if (DemoKeyCode == keyLeft && PlayField16[*si - 1] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si - 1] = fiYellowDisk; if (LowByte(PlayField16[*si - 2]) != fiExplosion) PlayField16[*si - 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from up to down // ========================================================================== loc_g_70F2: if (DemoKeyCode == keyDown && PlayField16[*si + FieldWidth] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si + FieldWidth] = fiYellowDisk; if (LowByte(PlayField16[*si + 2 * FieldWidth]) != fiExplosion) PlayField16[*si + 2 * FieldWidth] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // Push yellow disk from left to right // ========================================================================== loc_g_7130: if (DemoKeyCode == keyRight && PlayField16[*si + 1] == fiYellowDisk) return; PlayField16[*si] = fiMurphy; // else restore - no more pushing! PlayField16[*si + 1] = fiYellowDisk; if (LowByte(PlayField16[*si + 2]) != fiExplosion) PlayField16[*si + 2] = 0; subCopyImageToScreen(*si, aniMurphy); return; // ========================================================================== // time red disk release (space) // ========================================================================== loc_g_716E: if (DemoKeyCode != keySpace) { PlayField16[*si] = fiMurphy; subCopyImageToScreen(*si, aniMurphy); RedDiskReleasePhase = 0; } else if (MovingPictureSequencePhase == 0x20) { // anxious murphy, dropping red disk subCopyImageToScreen(*si, aniMurphyDropping); RedDiskReleasePhase = 1; } return; // ========================================================================== // Special port down to up // ========================================================================== loc_g_7244: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si - 2 * FieldWidth] = fiMurphy; SplitMoveFlag = 0; *si = *si - FieldWidth; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si - FieldWidth; return; // ========================================================================== // Special port right to left // ========================================================================== loc_g_7272: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si - 2] = fiMurphy; SplitMoveFlag = 0; *si = *si - 1; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si - 1; return; // ========================================================================== // Special port up to down // ========================================================================== loc_g_729F: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si + 2 * FieldWidth] = fiMurphy; SplitMoveFlag = 0; *si = *si + FieldWidth; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si + FieldWidth; return; // ========================================================================== // Special port left to right // ========================================================================== loc_g_72CD: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; PlayField16[*si + 2] = fiMurphy; SplitMoveFlag = 0; *si = *si + 1; if (HighByte(PlayField16[*si]) == 1) subSpPortTest(*si); *si = *si + 1; return; // ========================================================================== // Move Red Disk up // ========================================================================== loc_g_72FA: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - FieldWidth; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Move Red Disk left // ========================================================================== loc_g_7318: if (LowByte(PlayField16[*si + 1]) != fiExplosion) PlayField16[*si + 1] = 0; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Move Red Disk down // ========================================================================== loc_g_7333: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + FieldWidth; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Move Red Disk right // ========================================================================== loc_g_7351: if (LowByte(PlayField16[*si - 1]) != fiExplosion) PlayField16[*si - 1] = 0; PlayField16[*si] = fiMurphy; subEatRedDisk(*si); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk up // ========================================================================== loc_g_736C: if (LowByte(PlayField16[*si - FieldWidth]) != fiExplosion) PlayField16[*si - FieldWidth] = 0; subEatRedDisk(*si - FieldWidth); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk left // ========================================================================== loc_g_7381: if (LowByte(PlayField16[*si - 1]) != fiExplosion) PlayField16[*si - 1] = 0; subEatRedDisk(*si - 1); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk down // ========================================================================== loc_g_7396: if (LowByte(PlayField16[*si + FieldWidth]) != fiExplosion) PlayField16[*si + FieldWidth] = 0; subEatRedDisk(*si + FieldWidth); // inc+show Murphy's red disks return; // ========================================================================== // Eat Red Disk right // ========================================================================== loc_g_73AB: if (LowByte(PlayField16[*si + 1]) != fiExplosion) PlayField16[*si + 1] = 0; subEatRedDisk(*si + 1); // inc+show Murphy's red disks return; // ========================================================================== // yellow disk, pushing up // ========================================================================== loc_g_73C0: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - FieldWidth; PlayField16[*si] = fiMurphy; PlayField16[*si - FieldWidth] = fiYellowDisk; return; // ========================================================================== // yellow disk, pushing left // ========================================================================== loc_g_73DD: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - 1; PlayField16[*si] = fiMurphy; PlayField16[*si - 1] = fiYellowDisk; return; // ========================================================================== // yellow disk, pushing down // ========================================================================== loc_g_73FA: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + FieldWidth; PlayField16[*si] = fiMurphy; PlayField16[*si + FieldWidth] = fiYellowDisk; return; // ========================================================================== // yellow disk pushing right // ========================================================================== loc_g_7417: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + 1; PlayField16[*si] = fiMurphy; PlayField16[*si + 1] = fiYellowDisk; return; // ========================================================================== // orange disk, pushing left // ========================================================================== loc_g_7434: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si - 1; PlayField16[*si] = fiMurphy; PlayField16[*si - 1] = fiOrangeDisk; return; // ========================================================================== // orange disk, pushing right // ========================================================================== loc_g_7451: if (LowByte(PlayField16[*si]) != fiExplosion) PlayField16[*si] = 0; *si = *si + 1; PlayField16[*si] = fiMurphy; PlayField16[*si + 1] = fiOrangeDisk; if (PlayField16[*si + FieldWidth + 1] == 0) // make it fall down if below is empty { MovHighByte(&PlayField16[*si + 1], 0x20); MovHighByte(&PlayField16[*si + FieldWidth + 1], fiOrangeDisk); } return; // ========================================================================== // Release a red disk // ========================================================================== loc_g_747F: PlayField16[*si] = fiMurphy; RedDiskReleasePhase = 2; RedDiskCount = RedDiskCount - 1; subSoundFX(*si, fiRedDisk, actDropping); } // subAnimateMurphy // ========================================================================== // SUBROUTINE // ========================================================================== void subExplodeSnikSnaksBelow(int si) { int ax; ax = LowByte(PlayField16[si + FieldWidth]); if (ax == 0x11 || ax == 0xBB) ExplodeFieldSP(si + FieldWidth); } // subExplodeSnikSnaksBelow // ========================================================================== // SUBROUTINE // Does pushing against an object kill Murphy? // ========================================================================== static boolean subMoveKillsMurphy(int si, int ax, int bl) { static boolean subMoveKillsMurphy; int al, ah; al = LowByte(ax); ah = HighByte(ax); if (ax == 0xFFFF || ax == 0xAAAA || ah == 0) goto loc_g_752E; if (al == fiZonk) goto loc_g_74E7; if (al == fiExplosion) goto loc_g_7530; if (fiOrangeDisk <= al && al <= fiPortUp) goto loc_g_752E; ExplodeFieldSP(si); // Explode subMoveKillsMurphy = True; return subMoveKillsMurphy; loc_g_74E7: // zonk if (bl == keyLeft) goto loc_g_74F6; if (bl == keyRight) goto loc_g_7512; ExplodeFieldSP(si); // Explode subMoveKillsMurphy = True; return subMoveKillsMurphy; loc_g_74F6: // zonk left ah = ah & 0xF0; if (! (ah == 0x20 || ah == 0x40 || ah == 0x50 || ah == 0x70)) ExplodeFieldSP(si); subMoveKillsMurphy = True; // Set carry flag return subMoveKillsMurphy; loc_g_7512: // zonk right ah = ah & 0xF0; if (! (ah == 0x30 || ah == 0x40 || ah == 0x60 || ah == 0x70)) ExplodeFieldSP(si); loc_g_752E: // Marked fields and Ports subMoveKillsMurphy = True; // Set carry flag return subMoveKillsMurphy; loc_g_7530: // explosion if ((ah & 0x80) != 0) goto loc_g_753A; if (ah >= 4) goto loc_g_753F; loc_g_753A: ExplodeFieldSP(si); // Explode subMoveKillsMurphy = True; // Set carry flag return subMoveKillsMurphy; loc_g_753F: PlayField16[si] = 0; subMoveKillsMurphy = False; return subMoveKillsMurphy; } // subMoveKillsMurphy // ========================================================================== // SUBROUTINE // Test If si 's a special (grav) port and If so Then fetch new values (see below) // change conditions to port specs // The 10-port data base is at data_h_0D28, 10 entries of 6 bytes each: // (hi),(lo),(gravity),(freeze zonks),(freeze enemies),(unused) // ========================================================================== void subSpPortTest(int si) { int i; for (i = 0; i < LInfo.SpecialPortCount; i++) { if (LInfo.SpecialPort[i].PortLocation / 2 == si) { GravityFlag = LInfo.SpecialPort[i].Gravity; FreezeZonks = LInfo.SpecialPort[i].FreezeZonks; SnikSnaksElectronsFrozen = LInfo.SpecialPort[i].FreezeEnemies; break; } } } void subCopyAnimToScreen(int si, int graphic, int sync_frame) { int X, Y; // +++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, graphic, sync_frame); // +++++++++++++++++++++++++++++++++++++++++ } void subCopyImageToScreen(int si, int graphic) { subCopyAnimToScreen(si, graphic, 0); } static void subEatRedDisk(int si) { if (AllowRedDiskCheat == 0) { if (RedDiskReleasePhase != 0) { if (RedDiskReleaseMurphyPos == si) return; } } RedDiskCount = (RedDiskCount + 1) % 256; } void subAdjustZonksInfotronsAboveMurphy(int si) { int ax; if (LowByte(PlayField16[si]) != fiExplosion) PlayField16[si] = 0; ax = PlayField16[si - FieldWidth]; if (ax == 0 || ax == 0x9999) goto loc_g_15A8; if (ax == fiZonk || ax == fiInfotron) { MovHighByte(&PlayField16[si - FieldWidth], 0x40); // make falling straigt down } return; loc_g_15A8: // empty above ax = PlayField16[si - FieldWidth - 1]; if (ax == fiZonk || ax == fiInfotron) goto loc_g_15C5; loc_g_15B6: ax = PlayField16[si - FieldWidth + 1]; if (ax == fiZonk || ax == fiInfotron) goto loc_g_15E8; return; loc_g_15C5: // zonk/infotron above left ax = PlayField16[si - 1]; if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) // continue testing right above goto loc_g_15B6; MovHighByte(&PlayField16[si - FieldWidth - 1], 0x60); // make roll right PlayField16[si - FieldWidth] = 0x8888; return; loc_g_15E8: // zonk/infotron above right ax = PlayField16[si + 1]; if (ax == fiZonk || ax == fiInfotron || ax == fiRAM) { MovHighByte(&PlayField16[si - FieldWidth + 1], 0x50); // make roll left PlayField16[si - FieldWidth] = 0x8888; } } mirrormagic-3.0.0/src/game_sp/Electrons.c0000644000175000017500000003307013263212010017630 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Electrons.c // ---------------------------------------------------------------------------- #include "Electrons.h" // ========================================================================== // SUBROUTINE // Animate/move Electrons // ========================================================================== void subAnimateElectrons(int si) { int bx, Tmp; if (SnikSnaksElectronsFrozen == 1) return; if (LowByte(PlayField16[si]) != fiElectron) return; bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subElectronTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subElectronTurnRight(si, bx); // turn right break; case 2: subElectronFromBelow(si, bx); // access si from below break; case 3: subElectronFromRight(si, bx); // access si from right break; case 4: subElectronFromAbove(si, bx); // access si from above break; case 5: subElectronFromLeft(si, bx); // access si from left break; } } void subDrawAnimatedElectrons(int si) { int bx, Tmp; // If SnikSnaksElectronsFrozen = 1 Then Exit Function if (LowByte(PlayField16[si]) != fiElectron) return; bx = HighByte(PlayField16[si]); Tmp = bx / 8; switch (Tmp) { case 0: subDrawElectronTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc. break; case 1: subDrawElectronTurnRight(si, bx); // turn right break; case 2: subDrawElectronFromBelow(si, bx); // access si from below break; case 3: subDrawElectronFromRight(si, bx); // access si from right break; case 4: subDrawElectronFromAbove(si, bx); // access si from above break; case 5: subDrawElectronFromLeft(si, bx); // access si from left break; } } void subElectronTurnLeft(int si, int bx) { int ax, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_7ACD; return; } // loc_g_7A9F: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronTurnLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = (bx + 1) & 0x7; MovHighByte(&PlayField16[si], bx); return; loc_g_7ACD: bl = HighByte(PlayField16[si]); if (bl == 0) goto loc_g_7AE6; if (bl == 2) goto loc_g_7B05; if (bl == 4) goto loc_g_7B24; if (bl == 6) goto loc_g_7B43; return; loc_g_7AE6: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_7AF5; if (LowByte(ax) == fiMurphy) // above is murphy -> explode ExplodeFieldSP(si); return; loc_g_7AF5: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; // 1 field up PlayField16[si] = 0x1018; return; loc_g_7B05: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_7B14; if (LowByte(ax) == fiMurphy) // left is murphy -> explode ExplodeFieldSP(si); return; loc_g_7B14: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1818; return; loc_g_7B24: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7B33; if (LowByte(ax) == fiMurphy) // below is murphy -> explode ExplodeFieldSP(si); return; loc_g_7B33: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2018; return; loc_g_7B43: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_7B55; if (LowByte(ax) == fiMurphy) // right is murphy -> explode ExplodeFieldSP(si); return; loc_g_7B55: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2818; } void subElectronTurnRight(int si, int bx) { int ax, bl; ax = (TimerVar & 3); if (ax != 0) { if (ax == 3) goto loc_g_7BA3; return; } // loc_g_7B73: // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronTurnRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = ((bx + 1) & 0x7) | 8; MovHighByte(&PlayField16[si], bx); return; loc_g_7BA3: bl = HighByte(PlayField16[si]); if (bl == 0x8) goto loc_g_7BBC; if (bl == 0xA) goto loc_g_7C19; if (bl == 0xC) goto loc_g_7BFA; if (bl == 0xE) goto loc_g_7BDB; return; loc_g_7BBC: // pointing up ax = PlayField16[si - FieldWidth]; if (ax == 0) // above is empty -> go up goto loc_g_7BCB; if (LowByte(ax) == fiMurphy) // above is murphy -> explode ExplodeFieldSP(si); return; loc_g_7BCB: // above is empty -> go up PlayField16[si] = 0x1BB; si = si - FieldWidth; // 1 field up PlayField16[si] = 0x1018; return; loc_g_7BDB: // pointing left ax = PlayField16[si - 1]; if (ax == 0) // left is empty -> go there goto loc_g_7BEA; if (LowByte(ax) == fiMurphy) // left is murphy -> explode ExplodeFieldSP(si); return; loc_g_7BEA: // left is empty -> go there PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1818; return; loc_g_7BFA: // pointing down ax = PlayField16[si + FieldWidth]; if (ax == 0) // below is empty -> go down goto loc_g_7C09; if (LowByte(ax) == fiMurphy) // below is murphy -> explode ExplodeFieldSP(si); return; loc_g_7C09: // below is empty -> go down PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2018; return; loc_g_7C19: // pointing Right ax = PlayField16[si + 1]; if (ax == 0) // right is empty -> go there goto loc_g_7C2B; if (LowByte(ax) == fiMurphy) // right is murphy -> explode ExplodeFieldSP(si); return; loc_g_7C2B: // right is empty -> go there PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2818; } void subElectronFromBelow(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromBelow(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0xF; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion) { PlayField16[si + FieldWidth] = 0; // electron left that field } if (bl < 8) // electron still goes up { bl = bl + 0x10; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7C84 PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si - 1]; // check left field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 1); // start to turn left return; } // loc_g_7CA4: ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above if (ax == 0) // check if empty { PlayField16[si] = 0x1BB; // mark as "electron leaving" si = si - FieldWidth; // go up! PlayField16[si] = 0x1018; return; } if (LowByte(ax) == fiMurphy) // check for murphy above { ExplodeFieldSP(si); // Explode return; } // loc_g_7CC6: ax = PlayField16[si + 1]; // check right field if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy { MovHighByte(&PlayField16[si], 9); // start to turn right return; } // loc_g_7CE0: // else: no way to go, start turning around MovHighByte(&PlayField16[si], 1); } void subElectronFromRight(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromRight(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x17; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion) { PlayField16[si + 1] = 0; // electron left that field } // loc_g_7D1D: if (bl < 8) // sniksnak still goes left { bl = bl + 0x18; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7D2A: PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy? { MovHighByte(&PlayField16[si], 3); // yes -> turn left down return; } // loc_g_7D4A: ax = PlayField16[si - 1]; // check left, etc ... see the comments on subElectronFromBelow() if (ax == 0) { PlayField16[si] = 0x2BB; si = si - 1; // 1 field left PlayField16[si] = 0x1818; return; } // loc_g_7D61: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7D6C: ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xF); return; } // loc_g_7D86: MovHighByte(&PlayField16[si], 3); } void subElectronFromAbove(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromAbove(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x1F; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion) { PlayField16[si - FieldWidth] = 0; // electron left that field } if (bl < 8) // electron still goes down { bl = bl + 0x20; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7DD7 PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si + 1]; // check right if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 5); return; } // loc_g_7DF7: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0) { PlayField16[si] = 0x3BB; si = si + FieldWidth; // 1 field down PlayField16[si] = 0x2018; return; } // loc_g_7E0E: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7E19: ax = PlayField16[si - 1]; // check left if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xD); return; } // loc_g_7E33: MovHighByte(&PlayField16[si], 5); } void subElectronFromLeft(int si, int bx) { int ax, bl; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ subDrawElectronFromLeft(si, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ bx = bx - 0x27; // get and increment sequence# bl = LowByte(bx); if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion) { PlayField16[si - 1] = 0; // electron left that field } if (bl < 8) // electron still goes right { bl = bl + 0x28; MovHighByte(&PlayField16[si], bl); return; } // loc_g_7E7E: PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field ax = PlayField16[si - FieldWidth]; // check above if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 7); return; } // loc_g_7E9E: ax = PlayField16[si + 1]; // check right(straight on) if (ax == 0) { PlayField16[si] = 0x4BB; si = si + 1; // 1 field right PlayField16[si] = 0x2818; return; } // loc_g_7EB5: if (LowByte(ax) == fiMurphy) { ExplodeFieldSP(si); // Explode return; } // loc_g_7EC0: ax = PlayField16[si + FieldWidth]; // check below if (ax == 0 || LowByte(ax) == fiMurphy) { MovHighByte(&PlayField16[si], 0xB); return; } // loc_g_7A69: MovHighByte(&PlayField16[si], 7); } void subDrawElectronTurnLeft(int si, int bx) { int X, Y; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronTurnRight(int si, int bx) { int X, Y; // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniElectron, 0x10 - bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromBelow(int si, int bx) { int X, Y; bx = bx - 0xF; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si + FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y - bx * TwoPixels, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromRight(int si, int bx) { int X, Y; bx = bx - 0x17; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si + 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X - bx * TwoPixels, Y, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromAbove(int si, int bx) { int X, Y; bx = bx - 0x1F; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si); Y = GetStretchY(si - FieldWidth); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X, Y + bx * TwoPixels, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } void subDrawElectronFromLeft(int si, int bx) { int X, Y; bx = bx - 0x27; // get and increment sequence# // +++++++++++++++++++++++++++++++++++++++++++++++++++++ X = GetStretchX(si - 1); Y = GetStretchY(si); DDSpriteBuffer_BltImg(X, Y, aniSpace, 0); DDSpriteBuffer_BltImg(X + bx * TwoPixels, Y, aniElectron, bx); // +++++++++++++++++++++++++++++++++++++++++++++++++++++ } mirrormagic-3.0.0/src/game_sp/InitGameConditions.h0000644000175000017500000000111413263212010021420 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // InitGameConditions.h // ---------------------------------------------------------------------------- #ifndef INITGAMECONDITIONS_H #define INITGAMECONDITIONS_H #include "global.h" extern int subConvertToEasySymbols(); extern void InitMurphyPos(); extern void InitMurphyPosB(int); extern void ResetInfotronsNeeded(int); extern void subFetchAndInitLevel(); extern void subFetchAndInitLevelA(); extern void subFetchAndInitLevelB(); extern void subInitGameConditions(); #endif /* INITGAMECONDITIONS_H */ mirrormagic-3.0.0/src/game_sp/DoGameStuff.h0000644000175000017500000000063213263212010020041 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // DoGameStuff.h // ---------------------------------------------------------------------------- #ifndef DOGAMESTUFF_H #define DOGAMESTUFF_H #include "global.h" extern int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE]; extern byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE]; extern void subDoGameStuff(); #endif /* DOGAMESTUFF_H */ mirrormagic-3.0.0/src/game_sp/Sound.c0000644000175000017500000000051313263212010016756 0ustar aeglosaeglos// ---------------------------------------------------------------------------- // Sound.c // ---------------------------------------------------------------------------- #include "Sound.h" void subSoundFX(int si, int element, int action) { int x = GetX(si); int y = GetY(si); PlayLevelSound_SP(x, y, element, action); } mirrormagic-3.0.0/src/tape.c0000644000175000017500000010747613263212010015224 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // tape.c // ============================================================================ #include "libgame/libgame.h" #include "tape.h" #include "init.h" #include "game.h" #include "tools.h" #include "files.h" #include "network.h" #include "anim.h" #define DEBUG_TAPE_WHEN_PLAYING FALSE /* tape button identifiers */ #define TAPE_CTRL_ID_EJECT 0 #define TAPE_CTRL_ID_EXTRA 1 #define TAPE_CTRL_ID_STOP 2 #define TAPE_CTRL_ID_PAUSE 3 #define TAPE_CTRL_ID_RECORD 4 #define TAPE_CTRL_ID_PLAY 5 #define NUM_TAPE_BUTTONS 6 /* values for tape handling */ #define TAPE_PAUSE_SECONDS_BEFORE_DEATH 5 /* forward declaration for internal use */ static void HandleTapeButtons(struct GadgetInfo *); static void TapeStopWarpForward(); static float GetTapeLengthSecondsFloat(); static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS]; /* ========================================================================= */ /* video tape definitions */ /* ========================================================================= */ #define VIDEO_INFO_OFF (VIDEO_STATE_DATE_OFF | \ VIDEO_STATE_TIME_OFF | \ VIDEO_STATE_FRAME_OFF) #define VIDEO_STATE_OFF (VIDEO_STATE_PLAY_OFF | \ VIDEO_STATE_REC_OFF | \ VIDEO_STATE_PAUSE_OFF | \ VIDEO_STATE_FFWD_OFF | \ VIDEO_STATE_WARP_OFF | \ VIDEO_STATE_WARP2_OFF | \ VIDEO_STATE_PBEND_OFF | \ VIDEO_STATE_1STEP_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_INFO_OFF | \ VIDEO_STATE_OFF | \ VIDEO_PRESS_OFF) #define VIDEO_INFO_ON (VIDEO_STATE_DATE_ON | \ VIDEO_STATE_TIME_ON | \ VIDEO_STATE_FRAME_ON) #define VIDEO_STATE_ON (VIDEO_STATE_PLAY_ON | \ VIDEO_STATE_REC_ON | \ VIDEO_STATE_PAUSE_ON | \ VIDEO_STATE_FFWD_ON | \ VIDEO_STATE_WARP_ON | \ VIDEO_STATE_WARP2_ON | \ VIDEO_STATE_PBEND_ON | \ VIDEO_STATE_1STEP_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_INFO_ON | \ VIDEO_STATE_ON | \ VIDEO_PRESS_ON) #define VIDEO_INFO (VIDEO_INFO_ON | VIDEO_INFO_OFF) #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) #define NUM_TAPE_FUNCTIONS 11 #define NUM_TAPE_FUNCTION_PARTS 2 #define NUM_TAPE_FUNCTION_STATES 2 /* ========================================================================= */ /* video display functions */ /* ========================================================================= */ static void DrawVideoDisplay_Graphics(unsigned int state, unsigned int value) { int i, j, k; static struct { int graphic; struct XY *pos; } video_pos[NUM_TAPE_FUNCTIONS][NUM_TAPE_FUNCTION_PARTS] = { { { IMG_GFX_TAPE_LABEL_PLAY, &tape.label.play }, { IMG_GFX_TAPE_SYMBOL_PLAY, &tape.symbol.play }, }, { { IMG_GFX_TAPE_LABEL_RECORD, &tape.label.record }, { IMG_GFX_TAPE_SYMBOL_RECORD, &tape.symbol.record }, }, { { IMG_GFX_TAPE_LABEL_PAUSE, &tape.label.pause }, { IMG_GFX_TAPE_SYMBOL_PAUSE, &tape.symbol.pause }, }, { { IMG_GFX_TAPE_LABEL_DATE, &tape.label.date }, { -1, NULL }, }, { { IMG_GFX_TAPE_LABEL_TIME, &tape.label.time }, { -1, NULL }, }, { /* (no label for displaying optional frame) */ { -1, NULL }, { -1, NULL }, }, { { IMG_GFX_TAPE_LABEL_FAST_FORWARD, &tape.label.fast_forward }, { IMG_GFX_TAPE_SYMBOL_FAST_FORWARD, &tape.symbol.fast_forward }, }, { { IMG_GFX_TAPE_LABEL_WARP_FORWARD, &tape.label.warp_forward }, { IMG_GFX_TAPE_SYMBOL_WARP_FORWARD, &tape.symbol.warp_forward }, }, { { IMG_GFX_TAPE_LABEL_WARP_FORWARD_BLIND, &tape.label.warp_forward_blind}, { IMG_GFX_TAPE_SYMBOL_WARP_FORWARD_BLIND, &tape.symbol.warp_forward_blind}, }, { { IMG_GFX_TAPE_LABEL_PAUSE_BEFORE_END, &tape.label.pause_before_end }, { IMG_GFX_TAPE_SYMBOL_PAUSE_BEFORE_END, &tape.symbol.pause_before_end }, }, { { IMG_GFX_TAPE_LABEL_SINGLE_STEP, &tape.label.single_step }, { IMG_GFX_TAPE_SYMBOL_SINGLE_STEP, &tape.symbol.single_step }, }, }; for (k = 0; k < NUM_TAPE_FUNCTION_STATES; k++) /* on or off states */ { for (i = 0; i < NUM_TAPE_FUNCTIONS; i++) /* record, play, ... */ { for (j = 0; j < NUM_TAPE_FUNCTION_PARTS; j++) /* label or symbol */ { int graphic = video_pos[i][j].graphic; struct XY *pos = video_pos[i][j].pos; if (graphic == -1 || pos->x == -1 || pos->y == -1) continue; if (state & (1 << (i * 2 + k))) { struct GraphicInfo *gfx_bg = &graphic_info[IMG_BACKGROUND_TAPE]; struct GraphicInfo *gfx = &graphic_info[graphic]; Bitmap *gd_bitmap; int gd_x, gd_y; int skip_value = (j == 0 ? VIDEO_DISPLAY_SYMBOL_ONLY : VIDEO_DISPLAY_LABEL_ONLY); if (value == skip_value) continue; if (k == 1) /* on */ { gd_bitmap = gfx->bitmap; gd_x = gfx->src_x; gd_y = gfx->src_y; } else /* off */ { gd_bitmap = gfx_bg->bitmap; gd_x = gfx_bg->src_x + pos->x; gd_y = gfx_bg->src_y + pos->y; } /* some tape graphics may be undefined -- only draw if defined */ if (gd_bitmap != NULL) BlitBitmap(gd_bitmap, drawto, gd_x, gd_y, gfx->width, gfx->height, VX + pos->x, VY + pos->y); redraw_mask |= REDRAW_DOOR_2; } } } } } #define DATETIME_NONE (0) #define DATETIME_DATE_YYYY (1 << 0) #define DATETIME_DATE_YY (1 << 1) #define DATETIME_DATE_MON (1 << 2) #define DATETIME_DATE_MM (1 << 3) #define DATETIME_DATE_DD (1 << 4) #define DATETIME_TIME_HH (1 << 5) #define DATETIME_TIME_MIN (1 << 6) #define DATETIME_TIME_MM (1 << 7) #define DATETIME_TIME_SS (1 << 8) #define DATETIME_FRAME (1 << 9) #define DATETIME_XOFFSET_1 (1 << 10) #define DATETIME_XOFFSET_2 (1 << 11) #define DATETIME_DATE (DATETIME_DATE_YYYY | \ DATETIME_DATE_YY | \ DATETIME_DATE_MON | \ DATETIME_DATE_MM | \ DATETIME_DATE_DD) #define DATETIME_TIME (DATETIME_TIME_HH | \ DATETIME_TIME_MIN | \ DATETIME_TIME_MM | \ DATETIME_TIME_SS) #define MAX_DATETIME_STRING_SIZE 32 static void DrawVideoDisplay_DateTime(unsigned int state, unsigned int value) { int i; static char *month_shortnames[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; static struct { struct TextPosInfo *pos; int type; } datetime_info[] = { { &tape.text.date, DATETIME_DATE_DD }, { &tape.text.date, DATETIME_DATE_MON | DATETIME_XOFFSET_1 }, { &tape.text.date, DATETIME_DATE_YY | DATETIME_XOFFSET_2 }, { &tape.text.date_yyyy, DATETIME_DATE_YYYY }, { &tape.text.date_yy, DATETIME_DATE_YY }, { &tape.text.date_mon, DATETIME_DATE_MON }, { &tape.text.date_mm, DATETIME_DATE_MM }, { &tape.text.date_dd, DATETIME_DATE_DD }, { &tape.text.time, DATETIME_TIME_MIN }, { &tape.text.time, DATETIME_TIME_SS | DATETIME_XOFFSET_1 }, { &tape.text.time_hh, DATETIME_TIME_HH }, { &tape.text.time_mm, DATETIME_TIME_MM }, { &tape.text.time_ss, DATETIME_TIME_SS }, { &tape.text.frame, DATETIME_FRAME }, { NULL, DATETIME_NONE }, }; for (i = 0; datetime_info[i].pos != NULL; i++) { struct TextPosInfo *pos = datetime_info[i].pos; int type = datetime_info[i].type; int xpos, ypos; if (pos->x == -1 && pos->y == -1) continue; xpos = VX + pos->x + (type & DATETIME_XOFFSET_1 ? pos->xoffset : type & DATETIME_XOFFSET_2 ? pos->xoffset2 : 0); ypos = VY + pos->y; if ((type & DATETIME_DATE) && (state & VIDEO_STATE_DATE_ON)) { char s[MAX_DATETIME_STRING_SIZE]; int year2 = value / 10000; int year4 = (year2 < 70 ? 2000 + year2 : 1900 + year2); int month_index = (value / 100) % 100; int month = month_index + 1; int day = value % 100; strcpy(s, (type & DATETIME_DATE_YYYY ? int2str(year4, 4) : type & DATETIME_DATE_YY ? int2str(year2, 2) : type & DATETIME_DATE_MON ? month_shortnames[month_index] : type & DATETIME_DATE_MM ? int2str(month, 2) : type & DATETIME_DATE_DD ? int2str(day, 2) : "")); DrawText(xpos, ypos, s, pos->font); } else if ((type & DATETIME_TIME) && (state & VIDEO_STATE_TIME_ON)) { char s[MAX_DATETIME_STRING_SIZE]; int hh = (value / 3600) % 100; int min = value / 60; int mm = (value / 60) % 60; int ss = value % 60; strcpy(s, (type & DATETIME_TIME_HH ? int2str(hh, 2) : type & DATETIME_TIME_MIN ? int2str(min, 2) : type & DATETIME_TIME_MM ? int2str(mm, 2) : type & DATETIME_TIME_SS ? int2str(ss, 2) : "")); DrawText(xpos, ypos, s, pos->font); } else if ((type & DATETIME_FRAME) && (state & VIDEO_STATE_FRAME_ON)) { DrawText(xpos, ypos, int2str(value, pos->size), pos->font); } } } void DrawVideoDisplay(unsigned int state, unsigned int value) { DrawVideoDisplay_Graphics(state, value); DrawVideoDisplay_DateTime(state, value); } void DrawVideoDisplayLabel(unsigned int state) { DrawVideoDisplay(state, VIDEO_DISPLAY_LABEL_ONLY); } void DrawVideoDisplaySymbol(unsigned int state) { DrawVideoDisplay(state, VIDEO_DISPLAY_SYMBOL_ONLY); } void DrawVideoDisplayCurrentState() { int state = 0; DrawVideoDisplay(VIDEO_STATE_OFF, 0); if (tape.pausing) state |= VIDEO_STATE_PAUSE_ON; if (tape.recording) { state |= VIDEO_STATE_REC_ON; if (tape.single_step) state |= VIDEO_STATE_1STEP_ON; } else if (tape.playing) { state |= VIDEO_STATE_PLAY_ON; if (!tape.pausing) { if (tape.deactivate_display) state |= VIDEO_STATE_WARP2_ON; else if (tape.warp_forward) state |= VIDEO_STATE_WARP_ON; else if (tape.fast_forward) state |= VIDEO_STATE_FFWD_ON; if (tape.pause_before_end) state |= VIDEO_STATE_PBEND_ON; } } // draw labels and symbols separately to prevent labels overlapping symbols DrawVideoDisplayLabel(state); DrawVideoDisplaySymbol(state); } void DrawCompleteVideoDisplay() { struct GraphicInfo *g_tape = &graphic_info[IMG_BACKGROUND_TAPE]; /* draw tape background */ BlitBitmap(g_tape->bitmap, drawto, g_tape->src_x, g_tape->src_y, gfx.vxsize, gfx.vysize, gfx.vx, gfx.vy); /* draw tape buttons (forced) */ RedrawOrRemapTapeButtons(); DrawVideoDisplay(VIDEO_ALL_OFF, 0); if (tape.recording) { DrawVideoDisplay(VIDEO_STATE_REC_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, tape.length_frames); if (tape.pausing) DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0); } else if (tape.playing) { DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, 0); if (tape.pausing) DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0); } else if (tape.date && tape.length) { DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, tape.length_frames); } BlitBitmap(drawto, bitmap_db_door_2, gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize, 0, 0); } void TapeDeactivateDisplayOn() { SetDrawDeactivationMask(REDRAW_FIELD); audio.sound_deactivated = TRUE; } void TapeDeactivateDisplayOff(boolean redraw_display) { SetDrawDeactivationMask(REDRAW_NONE); audio.sound_deactivated = FALSE; if (redraw_display) { RedrawPlayfield(); DrawGameDoorValues(); } } /* ========================================================================= */ /* tape logging functions */ /* ========================================================================= */ void PrintTapeReplayProgress(boolean replay_finished) { static unsigned int counter_last = -1; unsigned int counter = Counter(); unsigned int counter_seconds = counter / 1000; if (!replay_finished) { unsigned int counter_delay = 50; if (counter > counter_last + counter_delay) { PrintNoLog("\r"); PrintNoLog("Level %03d [%02d:%02d]: [%02d:%02d] - playing tape ... ", level_nr, tape.length_seconds / 60, tape.length_seconds % 60, TapeTime / 60, TapeTime % 60); counter_last = counter; } } else { float tape_length_seconds = GetTapeLengthSecondsFloat(); PrintNoLog("\r"); Print("Level %03d [%02d:%02d]: (%02d:%02d.%03d / %.2f %%) - %s.\n", level_nr, tape.length_seconds / 60, tape.length_seconds % 60, counter_seconds / 60, counter_seconds % 60, counter % 1000, (float)counter / tape_length_seconds / 10, tape.auto_play_level_solved ? "solved" : "NOT SOLVED"); counter_last = -1; } } /* ========================================================================= */ /* tape control functions */ /* ========================================================================= */ void TapeSetDateFromEpochSeconds(time_t epoch_seconds) { struct tm *lt = localtime(&epoch_seconds); tape.date = 10000 * (lt->tm_year % 100) + 100 * lt->tm_mon + lt->tm_mday; } void TapeSetDateFromNow() { TapeSetDateFromEpochSeconds(time(NULL)); } void TapeErase() { int i; tape.counter = 0; tape.length = 0; tape.length_frames = 0; tape.length_seconds = 0; if (leveldir_current) setString(&tape.level_identifier, leveldir_current->identifier); tape.level_nr = level_nr; tape.pos[tape.counter].delay = 0; tape.changed = TRUE; tape.random_seed = InitRND(level.random_seed); tape.file_version = FILE_VERSION_ACTUAL; tape.game_version = GAME_VERSION_ACTUAL; tape.engine_version = level.game_version; TapeSetDateFromNow(); for (i = 0; i < MAX_PLAYERS; i++) tape.player_participates[i] = FALSE; tape.centered_player_nr_next = -1; tape.set_centered_player = FALSE; tape.use_mouse = (level.game_engine_type == GAME_ENGINE_TYPE_MM); } static void TapeRewind() { tape.counter = 0; tape.delay_played = 0; tape.pause_before_end = FALSE; tape.recording = FALSE; tape.playing = FALSE; tape.fast_forward = FALSE; tape.warp_forward = FALSE; tape.deactivate_display = FALSE; tape.auto_play = (global.autoplay_leveldir != NULL); tape.auto_play_level_solved = FALSE; tape.quick_resume = FALSE; tape.single_step = FALSE; tape.centered_player_nr_next = -1; tape.set_centered_player = FALSE; InitRND(tape.random_seed); } static void TapeSetRandomSeed(int random_seed) { tape.random_seed = InitRND(random_seed); } void TapeStartRecording(int random_seed) { if (!TAPE_IS_STOPPED(tape)) TapeStop(); TapeErase(); TapeRewind(); TapeSetRandomSeed(random_seed); tape.recording = TRUE; DrawVideoDisplay(VIDEO_STATE_REC_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, 0); MapTapeWarpButton(); SetDrawDeactivationMask(REDRAW_NONE); audio.sound_deactivated = FALSE; } static void TapeStartGameRecording() { StartGameActions(options.network, TRUE, level.random_seed); } static void TapeAppendRecording() { if (!tape.playing || !tape.pausing) return; // stop playing tape.playing = FALSE; tape.fast_forward = FALSE; tape.warp_forward = FALSE; tape.pause_before_end = FALSE; tape.deactivate_display = FALSE; // start recording tape.recording = TRUE; tape.changed = TRUE; // set current delay (for last played move) tape.pos[tape.counter].delay = tape.delay_played; // set current date TapeSetDateFromNow(); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0); UpdateAndDisplayGameControlValues(); } void TapeHaltRecording() { tape.counter++; // initialize delay for next tape entry (to be able to continue recording) if (tape.counter < MAX_TAPE_LEN) tape.pos[tape.counter].delay = 0; tape.length = tape.counter; tape.length_frames = GetTapeLengthFrames(); tape.length_seconds = GetTapeLengthSeconds(); } void TapeStopRecording() { if (tape.recording) TapeHaltRecording(); tape.recording = FALSE; tape.pausing = FALSE; DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0); MapTapeEjectButton(); } boolean TapeAddAction(byte action[MAX_PLAYERS]) { int i; if (tape.pos[tape.counter].delay > 0) /* already stored action */ { boolean changed_events = FALSE; for (i = 0; i < MAX_PLAYERS; i++) if (tape.pos[tape.counter].action[i] != action[i]) changed_events = TRUE; if (changed_events || tape.pos[tape.counter].delay >= 255) { if (tape.counter >= MAX_TAPE_LEN - 1) return FALSE; tape.counter++; tape.pos[tape.counter].delay = 0; } else tape.pos[tape.counter].delay++; } if (tape.pos[tape.counter].delay == 0) /* store new action */ { for (i = 0; i < MAX_PLAYERS; i++) tape.pos[tape.counter].action[i] = action[i]; tape.pos[tape.counter].delay++; } return TRUE; } void TapeRecordAction(byte action_raw[MAX_PLAYERS]) { byte action[MAX_PLAYERS]; int i; if (!tape.recording) /* (record action even when tape is paused) */ return; for (i = 0; i < MAX_PLAYERS; i++) action[i] = action_raw[i]; if (!tape.use_mouse && tape.set_centered_player) { for (i = 0; i < MAX_PLAYERS; i++) if (tape.centered_player_nr_next == i || tape.centered_player_nr_next == -1) action[i] |= KEY_SET_FOCUS; tape.set_centered_player = FALSE; } if (!TapeAddAction(action)) TapeStopRecording(); } void TapeTogglePause(boolean toggle_mode) { if (tape.playing && tape.pausing && (toggle_mode & TAPE_TOGGLE_PLAY_PAUSE)) { // continue playing in normal mode tape.fast_forward = FALSE; tape.warp_forward = FALSE; tape.deactivate_display = FALSE; tape.pause_before_end = FALSE; } tape.pausing = !tape.pausing; if (tape.single_step && (toggle_mode & TAPE_TOGGLE_MANUAL)) tape.single_step = FALSE; DrawVideoDisplayCurrentState(); if (tape.deactivate_display) { if (tape.pausing) TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING); else TapeDeactivateDisplayOn(); } if (tape.quick_resume) { tape.quick_resume = FALSE; TapeStopWarpForward(); TapeAppendRecording(); if (!CheckEngineSnapshotSingle()) SaveEngineSnapshotSingle(); // restart step/move snapshots after quick loading tape SaveEngineSnapshotToListInitial(); // do not map undo/redo buttons after quick loading tape return; } if (setup.show_snapshot_buttons && game_status == GAME_MODE_PLAYING && CheckEngineSnapshotList()) { if (tape.pausing) MapUndoRedoButtons(); else if (!tape.single_step) UnmapUndoRedoButtons(); } } void TapeStartPlaying() { if (TAPE_IS_EMPTY(tape)) return; if (!TAPE_IS_STOPPED(tape)) TapeStop(); TapeRewind(); tape.playing = TRUE; DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0); DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, 0); MapTapeWarpButton(); SetDrawDeactivationMask(REDRAW_NONE); audio.sound_deactivated = FALSE; } static void TapeStartGamePlaying() { TapeStartPlaying(); InitGame(); } void TapeStopPlaying() { tape.playing = FALSE; tape.pausing = FALSE; if (tape.warp_forward) TapeStopWarpForward(); DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0); MapTapeEjectButton(); } byte *TapePlayAction() { int update_delay = FRAMES_PER_SECOND / 2; boolean update_video_display = (FrameCounter % update_delay == 0); boolean update_draw_label_on = ((FrameCounter / update_delay) % 2 == 1); static byte action[MAX_PLAYERS]; int i; if (!tape.playing || tape.pausing) return NULL; if (tape.pause_before_end) // stop some seconds before end of tape { if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH) { TapeStopWarpForward(); TapeTogglePause(TAPE_TOGGLE_MANUAL); return NULL; } } if (tape.counter >= tape.length) /* end of tape reached */ { if (tape.warp_forward && !tape.auto_play) { TapeStopWarpForward(); TapeTogglePause(TAPE_TOGGLE_MANUAL); } else { TapeStop(); } return NULL; } if (update_video_display && !tape.deactivate_display) { int state = 0; if (tape.warp_forward) state |= VIDEO_STATE_WARP(update_draw_label_on); else if (tape.fast_forward) state |= VIDEO_STATE_FFWD(update_draw_label_on); if (tape.pause_before_end) state |= VIDEO_STATE_PBEND(update_draw_label_on); // draw labels and symbols separately to prevent labels overlapping symbols DrawVideoDisplayLabel(state); DrawVideoDisplaySymbol(state); } for (i = 0; i < MAX_PLAYERS; i++) action[i] = tape.pos[tape.counter].action[i]; #if DEBUG_TAPE_WHEN_PLAYING printf("%05d", FrameCounter); for (i = 0; i < MAX_PLAYERS; i++) printf(" %08x", action[i]); printf("\n"); #endif tape.set_centered_player = FALSE; tape.centered_player_nr_next = -999; if (!tape.use_mouse) { for (i = 0; i < MAX_PLAYERS; i++) { if (action[i] & KEY_SET_FOCUS) { tape.set_centered_player = TRUE; tape.centered_player_nr_next = (tape.centered_player_nr_next == -999 ? i : -1); } action[i] &= ~KEY_SET_FOCUS; } } tape.delay_played++; if (tape.delay_played >= tape.pos[tape.counter].delay) { tape.counter++; tape.delay_played = 0; } if (tape.auto_play) PrintTapeReplayProgress(FALSE); return action; } void TapeStop() { if (tape.pausing) TapeTogglePause(TAPE_TOGGLE_MANUAL); TapeStopRecording(); TapeStopPlaying(); DrawVideoDisplay(VIDEO_STATE_OFF, 0); if (tape.date && tape.length) { DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date); DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds); DrawVideoDisplay(VIDEO_STATE_FRAME_ON, tape.length_frames); } } unsigned int GetTapeLengthFrames() { unsigned int tape_length_frames = 0; int i; if (TAPE_IS_EMPTY(tape)) return(0); for (i = 0; i < tape.length; i++) tape_length_frames += tape.pos[i].delay; return tape_length_frames; } unsigned int GetTapeLengthSeconds() { return (GetTapeLengthFrames() * GAME_FRAME_DELAY / 1000); } static float GetTapeLengthSecondsFloat() { return ((float)GetTapeLengthFrames() * GAME_FRAME_DELAY / 1000); } static void TapeStartWarpForward(int mode) { tape.fast_forward = (mode & AUTOPLAY_FFWD); tape.warp_forward = (mode & AUTOPLAY_WARP); tape.deactivate_display = (mode & AUTOPLAY_WARP_NO_DISPLAY); tape.pausing = FALSE; if (tape.deactivate_display) TapeDeactivateDisplayOn(); DrawVideoDisplayCurrentState(); } static void TapeStopWarpForward() { tape.fast_forward = FALSE; tape.warp_forward = FALSE; tape.deactivate_display = FALSE; tape.pause_before_end = FALSE; TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING); DrawVideoDisplayCurrentState(); } static void TapeSingleStep() { if (options.network) return; if (!tape.pausing) TapeTogglePause(TAPE_TOGGLE_MANUAL); tape.single_step = !tape.single_step; DrawVideoDisplay(VIDEO_STATE_1STEP(tape.single_step), 0); } void TapeQuickSave() { if (game_status == GAME_MODE_MAIN) { Request("No game that can be saved!", REQ_CONFIRM); return; } if (game_status != GAME_MODE_PLAYING) return; if (tape.recording) TapeHaltRecording(); /* prepare tape for saving on-the-fly */ if (TAPE_IS_EMPTY(tape)) { Request("No tape that can be saved!", REQ_CONFIRM); return; } if (SaveTapeChecked(tape.level_nr)) SaveEngineSnapshotSingle(); } void TapeQuickLoad() { char *filename = getTapeFilename(level_nr); if (!fileExists(filename)) { Request("No tape for this level!", REQ_CONFIRM); return; } if (tape.recording && !Request("Stop recording and load tape?", REQ_ASK | REQ_STAY_CLOSED)) { OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); return; } if (game_status != GAME_MODE_PLAYING && game_status != GAME_MODE_MAIN) return; if (CheckEngineSnapshotSingle()) { TapeStartGamePlaying(); LoadEngineSnapshotSingle(); DrawCompleteVideoDisplay(); tape.playing = TRUE; tape.pausing = TRUE; TapeStopWarpForward(); TapeAppendRecording(); // restart step/move snapshots after quick loading tape SaveEngineSnapshotToListInitial(); if (FrameCounter > 0) return; } TapeStop(); TapeErase(); LoadTape(level_nr); if (!TAPE_IS_EMPTY(tape)) { TapeStartGamePlaying(); TapeStartWarpForward(AUTOPLAY_MODE_WARP_NO_DISPLAY); tape.quick_resume = TRUE; } else /* this should not happen (basically checked above) */ { int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0); Request("No tape for this level!", REQ_CONFIRM | reopen_door); } } void InsertSolutionTape() { boolean level_has_tape = (level.game_engine_type == GAME_ENGINE_TYPE_SP && level.native_sp_level->demo.is_available); if (!fileExists(getSolutionTapeFilename(level_nr)) && !level_has_tape) { Request("No solution tape for this level!", REQ_CONFIRM); return; } // if tape recorder already contains a tape, remove it without asking TapeErase(); LoadSolutionTape(level_nr); if (TAPE_IS_EMPTY(tape)) Request("Loading solution tape for this level failed!", REQ_CONFIRM); DrawCompleteVideoDisplay(); } /* ------------------------------------------------------------------------- * * tape autoplay functions * ------------------------------------------------------------------------- */ void AutoPlayTape() { static LevelDirTree *autoplay_leveldir = NULL; static boolean autoplay_initialized = FALSE; static int autoplay_level_nr = -1; static int num_levels_played = 0; static int num_levels_solved = 0; static int num_tape_missing = 0; static boolean level_failed[MAX_TAPES_PER_SET]; int i; if (autoplay_initialized) { /* just finished auto-playing tape */ PrintTapeReplayProgress(TRUE); num_levels_played++; if (tape.auto_play_level_solved) num_levels_solved++; else if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET) level_failed[level_nr] = TRUE; } else { DrawCompleteVideoDisplay(); audio.sound_enabled = FALSE; setup.engine_snapshot_mode = getStringCopy(STR_SNAPSHOT_MODE_OFF); autoplay_leveldir = getTreeInfoFromIdentifier(leveldir_first, global.autoplay_leveldir); if (autoplay_leveldir == NULL) Error(ERR_EXIT, "no such level identifier: '%s'", global.autoplay_leveldir); leveldir_current = autoplay_leveldir; if (autoplay_leveldir->first_level < 0) autoplay_leveldir->first_level = 0; if (autoplay_leveldir->last_level >= MAX_TAPES_PER_SET) autoplay_leveldir->last_level = MAX_TAPES_PER_SET - 1; autoplay_level_nr = autoplay_leveldir->first_level; PrintLine("=", 79); Print("Automatically playing level tapes\n"); PrintLine("-", 79); Print("Level series identifier: '%s'\n", autoplay_leveldir->identifier); Print("Level series name: '%s'\n", autoplay_leveldir->name); Print("Level series author: '%s'\n", autoplay_leveldir->author); Print("Number of levels: %d\n", autoplay_leveldir->levels); PrintLine("=", 79); Print("\n"); for (i = 0; i < MAX_TAPES_PER_SET; i++) level_failed[i] = FALSE; autoplay_initialized = TRUE; } while (autoplay_level_nr <= autoplay_leveldir->last_level) { level_nr = autoplay_level_nr++; if (!global.autoplay_all && !global.autoplay_level[level_nr]) continue; TapeErase(); LoadLevel(level_nr); if (level.no_level_file || level.no_valid_file) { Print("Level %03d: (no level)\n", level_nr); continue; } #if 0 /* ACTIVATE THIS FOR LOADING/TESTING OF LEVELS ONLY */ Print("Level %03d: (only testing level)\n", level_nr); continue; #endif if (options.mytapes) LoadTape(level_nr); else LoadSolutionTape(level_nr); if (tape.no_valid_file) { num_tape_missing++; Print("Level %03d: (no tape)\n", level_nr); continue; } InitCounter(); TapeStartGamePlaying(); TapeStartWarpForward(global.autoplay_mode); return; } Print("\n"); PrintLine("=", 79); Print("Number of levels played: %d\n", num_levels_played); Print("Number of levels solved: %d (%d%%)\n", num_levels_solved, (num_levels_played ? num_levels_solved * 100 / num_levels_played :0)); PrintLine("-", 79); Print("Summary (for automatic parsing by scripts):\n"); Print("LEVELDIR '%s', SOLVED %d/%d (%d%%)", autoplay_leveldir->identifier, num_levels_solved, num_levels_played, (num_levels_played ? num_levels_solved * 100 / num_levels_played :0)); if (num_levels_played != num_levels_solved) { Print(", FAILED:"); for (i = 0; i < MAX_TAPES_PER_SET; i++) if (level_failed[i]) Print(" %03d", i); } Print("\n"); PrintLine("=", 79); CloseAllAndExit(0); } /* ---------- new tape button stuff ---------------------------------------- */ static struct { int graphic; struct XY *pos; int gadget_id; char *infotext; } tapebutton_info[NUM_TAPE_BUTTONS] = { { IMG_GFX_TAPE_BUTTON_EJECT, &tape.button.eject, TAPE_CTRL_ID_EJECT, "eject tape" }, { /* (same position as "eject" button) */ IMG_GFX_TAPE_BUTTON_EXTRA, &tape.button.eject, TAPE_CTRL_ID_EXTRA, "extra functions" }, { IMG_GFX_TAPE_BUTTON_STOP, &tape.button.stop, TAPE_CTRL_ID_STOP, "stop tape" }, { IMG_GFX_TAPE_BUTTON_PAUSE, &tape.button.pause, TAPE_CTRL_ID_PAUSE, "pause tape" }, { IMG_GFX_TAPE_BUTTON_RECORD, &tape.button.record, TAPE_CTRL_ID_RECORD, "record tape" }, { IMG_GFX_TAPE_BUTTON_PLAY, &tape.button.play, TAPE_CTRL_ID_PLAY, "play tape" } }; void CreateTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) { struct GraphicInfo *gfx = &graphic_info[tapebutton_info[i].graphic]; struct XY *pos = tapebutton_info[i].pos; struct GadgetInfo *gi; int gd_x = gfx->src_x; int gd_y = gfx->src_y; int gd_xp = gfx->src_x + gfx->pressed_xoffset; int gd_yp = gfx->src_y + gfx->pressed_yoffset; int id = i; gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, tapebutton_info[i].infotext, GDI_X, VX + pos->x, GDI_Y, VY + pos->y, GDI_WIDTH, gfx->width, GDI_HEIGHT, gfx->height, GDI_TYPE, GD_TYPE_NORMAL_BUTTON, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y, GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp, GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, GD_EVENT_RELEASED, GDI_CALLBACK_ACTION, HandleTapeButtons, GDI_END); if (gi == NULL) Error(ERR_EXIT, "cannot create gadget"); tape_gadget[id] = gi; } } void FreeTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) FreeGadget(tape_gadget[i]); } void MapTapeEjectButton() { UnmapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]); MapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]); } void MapTapeWarpButton() { UnmapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]); MapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]); } void MapTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) if (i != TAPE_CTRL_ID_EXTRA) MapGadget(tape_gadget[i]); if (tape.recording || tape.playing) MapTapeWarpButton(); if (tape.show_game_buttons) MapGameButtonsOnTape(); } void UnmapTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) UnmapGadget(tape_gadget[i]); if (tape.show_game_buttons) UnmapGameButtonsOnTape(); } void RedrawTapeButtons() { int i; for (i = 0; i < NUM_TAPE_BUTTONS; i++) RedrawGadget(tape_gadget[i]); if (tape.show_game_buttons) RedrawGameButtonsOnTape(); // RedrawGadget() may have set REDRAW_ALL if buttons are defined off-area redraw_mask &= ~REDRAW_ALL; } void RedrawOrRemapTapeButtons() { if (tape_gadget[TAPE_CTRL_ID_PLAY]->mapped) { // tape buttons already mapped RedrawTapeButtons(); } else { UnmapTapeButtons(); MapTapeButtons(); } } static void HandleTapeButtonsExt(int id) { if (game_status != GAME_MODE_MAIN && game_status != GAME_MODE_PLAYING) return; switch (id) { case TAPE_CTRL_ID_EJECT: TapeStop(); if (TAPE_IS_EMPTY(tape)) { LoadTape(level_nr); if (TAPE_IS_EMPTY(tape)) Request("No tape for this level!", REQ_CONFIRM); } else { if (tape.changed) SaveTapeChecked(level_nr); TapeErase(); } DrawCompleteVideoDisplay(); break; case TAPE_CTRL_ID_EXTRA: if (tape.playing) { tape.pause_before_end = !tape.pause_before_end; DrawVideoDisplayCurrentState(); } else if (tape.recording) { TapeSingleStep(); } break; case TAPE_CTRL_ID_STOP: TapeStop(); break; case TAPE_CTRL_ID_PAUSE: TapeTogglePause(TAPE_TOGGLE_MANUAL); break; case TAPE_CTRL_ID_RECORD: if (TAPE_IS_STOPPED(tape)) { TapeStartGameRecording(); } else if (tape.pausing) { if (tape.playing) /* PLAY -> PAUSE -> RECORD */ TapeAppendRecording(); else TapeTogglePause(TAPE_TOGGLE_MANUAL); } break; case TAPE_CTRL_ID_PLAY: if (tape.recording && tape.pausing) /* PAUSE -> RECORD */ { // ("TAPE_IS_EMPTY(tape)" is TRUE here -- probably fix this) TapeTogglePause(TAPE_TOGGLE_MANUAL); } if (TAPE_IS_EMPTY(tape)) break; if (TAPE_IS_STOPPED(tape)) { TapeStartGamePlaying(); } else if (tape.playing) { if (tape.pausing) /* PAUSE -> PLAY */ { TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE); } else if (!tape.fast_forward) /* PLAY -> FFWD */ { tape.fast_forward = TRUE; } else if (!tape.warp_forward) /* FFWD -> WARP */ { tape.warp_forward = TRUE; } else if (!tape.deactivate_display) /* WARP -> WARP BLIND */ { tape.deactivate_display = TRUE; TapeDeactivateDisplayOn(); } else /* WARP BLIND -> PLAY */ { tape.fast_forward = FALSE; tape.warp_forward = FALSE; tape.deactivate_display = FALSE; TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING); } DrawVideoDisplayCurrentState(); } break; default: break; } } static void HandleTapeButtons(struct GadgetInfo *gi) { HandleTapeButtonsExt(gi->custom_id); } void HandleTapeButtonKeys(Key key) { boolean eject_button_is_active = TAPE_IS_STOPPED(tape); boolean extra_button_is_active = !eject_button_is_active; if (key == setup.shortcut.tape_eject && eject_button_is_active) HandleTapeButtonsExt(TAPE_CTRL_ID_EJECT); else if (key == setup.shortcut.tape_extra && extra_button_is_active) HandleTapeButtonsExt(TAPE_CTRL_ID_EXTRA); else if (key == setup.shortcut.tape_stop) HandleTapeButtonsExt(TAPE_CTRL_ID_STOP); else if (key == setup.shortcut.tape_pause) HandleTapeButtonsExt(TAPE_CTRL_ID_PAUSE); else if (key == setup.shortcut.tape_record) HandleTapeButtonsExt(TAPE_CTRL_ID_RECORD); else if (key == setup.shortcut.tape_play) HandleTapeButtonsExt(TAPE_CTRL_ID_PLAY); } mirrormagic-3.0.0/src/anim.h0000644000175000017500000000130613263212010015205 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // anim.h // ============================================================================ #ifndef ANIM_H #define ANIM_H int getAnimationFrame(int, int, int, int, int); void InitGlobalAnimations(void); void DrawGlobalAnimations(int, int); boolean HandleGlobalAnimClicks(int, int, int); #endif mirrormagic-3.0.0/src/game_em/0000755000175000017500000000000013263214225015514 5ustar aeglosaeglosmirrormagic-3.0.0/src/game_em/synchro_3.c0000644000175000017500000000531413263212010017560 0ustar aeglosaeglos/* third part of synchro. * * handle global elements. * * this should be spread over the frames for reduced cpu load. */ #include "main_em.h" void synchro_3(void) { int x; int y; int count; unsigned int random; /* update variables */ if (lev.score > 9999) lev.score = 9999; if (lev.android_move_cnt-- == 0) lev.android_move_cnt = lev.android_move_time; if (lev.android_clone_cnt-- == 0) lev.android_clone_cnt = lev.android_clone_time; if (lev.ball_state) if (lev.ball_cnt-- == 0) lev.ball_cnt = lev.ball_time; if (lev.lenses_cnt) lev.lenses_cnt--; if (lev.magnify_cnt) lev.magnify_cnt--; if (lev.wheel_cnt) lev.wheel_cnt--; if (lev.wind_cnt) lev.wind_cnt--; if (lev.wonderwall_time && lev.wonderwall_state) lev.wonderwall_time--; if (lev.wheel_cnt) play_element_sound(lev.wheel_x, lev.wheel_y, SAMPLE_wheel, Xwheel); /* grow amoeba */ random = RandomEM; for (count = lev.amoeba_time; count--;) { x = (random >> 10) % (WIDTH - 2); y = (random >> 20) % (HEIGHT - 2); switch (Cave[y][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xgrass: case Xdirt: case Xsand: case Xplant: case Yplant: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) Cave[y][x] = Xdrip_eat; } random = random * 129 + 1; } RandomEM = random; /* handle explosions */ for (y = 1; y < HEIGHT - 1; y++) for (x = 1; x < WIDTH - 1; x++) { switch (Cave[y][x]) { case Znormal: Cave[y][x] = Xboom_1; Cave[y-1][x] = tab_explode_normal[Cave[y-1][x]]; Cave[y][x-1] = tab_explode_normal[Cave[y][x-1]]; Cave[y][x+1] = tab_explode_normal[Cave[y][x+1]]; Cave[y+1][x] = tab_explode_normal[Cave[y+1][x]]; Cave[y-1][x-1] = tab_explode_normal[Cave[y-1][x-1]]; Cave[y-1][x+1] = tab_explode_normal[Cave[y-1][x+1]]; Cave[y+1][x-1] = tab_explode_normal[Cave[y+1][x-1]]; Cave[y+1][x+1] = tab_explode_normal[Cave[y+1][x+1]]; break; case Zdynamite: Cave[y][x] = Xboom_1; Cave[y-1][x] = tab_explode_dynamite[Cave[y-1][x]]; Cave[y][x-1] = tab_explode_dynamite[Cave[y][x-1]]; Cave[y][x+1] = tab_explode_dynamite[Cave[y][x+1]]; Cave[y+1][x] = tab_explode_dynamite[Cave[y+1][x]]; Cave[y-1][x-1] = tab_explode_dynamite[Cave[y-1][x-1]]; Cave[y-1][x+1] = tab_explode_dynamite[Cave[y-1][x+1]]; Cave[y+1][x-1] = tab_explode_dynamite[Cave[y+1][x-1]]; Cave[y+1][x+1] = tab_explode_dynamite[Cave[y+1][x+1]]; break; } } /* triple buffering */ for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Next[y][x] = Cave[y][x]; } mirrormagic-3.0.0/src/game_em/convert.c0000644000175000017500000007710113263212010017334 0ustar aeglosaeglos/* 2000-08-20T09:41:18Z * * identify all emerald mine caves and turn them into v6 format. * fixes illegal tiles, acid, wheel, limits times, cleans flags. * * these tables weed out bad tiles for older caves (eg. wheel on -> wheel off) * and clean up v6 caves (acid, number limits) which should(!) be * inconsequential, but no doubt it will break some caves. */ #include "main_em.h" #define ALLOW_ROLLING_SPRING static unsigned char remap_v6[256] = { /* filter crap for v6 */ 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15, 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28, 0,16,2,18, 36,37,37,37, 40,41,42,43, 44,45,128,128, 128,148,148, 148,45,45,45, 148,0,57,58, 59,60,61,62,63, #ifdef ALLOW_ROLLING_SPRING 64,65,66,67, 68,69,69,71, 72,73,74,75, 118,75,75,75, #else 64,65,66,67, 68,69,69,69, 69,73,74,75, 118,75,75,75, #endif 75,75,75,75, 75,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,99, 100,68,68,68, 68,68,68,68, 68,118,118,118, 118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118, 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, 160,161,162,163, 164,165,165,118, 168,169,170,171, 172,173,174,175, 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,191, 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, 240,241,242,243, 244,245,153,153, 153,153,153,153, 153,153,153,153 }; static unsigned char remap_v5[256] = { /* filter crap for v5 */ 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15, 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28, 0,16,2,18, 36,37,37,37, 147,41,42,43, 44,45,128,128, 128,148,148,148, 45,45,45,148, 0,57,58,59, 60,61,62,63, 64,65,66,67, 68,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,68,68,68,68, 68,68,68,68,118, 118,118, 118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118, 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, 160,153,153,153, 153,153,153,118, 168,169,170,171, 172,173,174,175, 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,153, 153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207, 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, 240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153 }; static unsigned char remap_v4[256] = { /* filter crap for v4 */ 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15, 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28, 0,16,2,18, 36,37,37,37, 147,41,42,43, 44,45,128,128, 128,148,148,148, 45,45,45,148, 0,153,153,59, 60,61,62,63, 64,65,66,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118, 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, 144,145,146,147, 148,149,150,151, 152,68,154,155, 156,157,158,160, 160,160,160,160, 160,160,160,160, 160,160,160,160, 160,160,160,175, 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,68,153, 153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207, 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, 240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153 }; static unsigned char remap_v4eater[28] = { /* filter crap for v4 */ 128,18,2,0,4,8,16,20,28,37, 41,45,130,129,131,132,133,134,135,136, 146,147,175,65,66,64,2,18 }; static boolean filename_has_v1_format(char *filename) { char *basename = getBaseNamePtr(filename); return (strlen(basename) == 3 && basename[0] == 'a' && basename[1] >= 'a' && basename[1] <= 'k' && basename[2] >= '0' && basename[2] <= '9'); } int cleanup_em_level(unsigned char *src, int length, char *filename) { int file_version = FILE_VERSION_EM_UNKNOWN; int i; if (length >= 2172 && src[2106] == 255 && /* version id: */ src[2107] == 54 && /* '6' */ src[2108] == 48 && /* '0' */ src[2109] == 48) /* '0' */ { /* ---------- this cave has V6 file format ---------- */ file_version = FILE_VERSION_EM_V6; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v6[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v6[src[i]]; for (i = 2112; i < 2148; i++) src[i] = remap_v6[src[i]]; } else if (length >= 2110 && src[2106] == 255 && /* version id: */ src[2107] == 53 && /* '5' */ src[2108] == 48 && /* '0' */ src[2109] == 48) /* '0' */ { /* ---------- this cave has V5 file format ---------- */ file_version = FILE_VERSION_EM_V5; /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v5[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v5[src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; } else if (length >= 2106 && (src[1983] == 27 || /* encrypted (only EM I/II/III) */ src[1983] == 116 || /* unencrypted (usual case) */ src[1983] == 131)) /* unencrypted (rare case) */ { /* ---------- this cave has V1, V2 or V3 file format ---------- */ boolean fix_copyright = FALSE; /* byte at position 1983 (0x07bf) is used as "magic byte": - 27 (0x1b) => encrypted level (V3 only / Kingsoft original games) - 116 (0x74) => unencrypted level (byte is corrected to 131 (0x83)) - 131 (0x83) => unencrypted level (happens only in very rare cases) */ if (src[1983] == 27) /* (0x1b) -- after decryption: 116 (0x74) */ { /* this is original (encrypted) Emerald Mine I, II or III level file */ int first_byte = src[0]; unsigned char code0 = 0x65; unsigned char code1 = 0x11; /* decode encrypted level data */ for (i = 0; i < 2106; i++) { src[i] ^= code0; src[i] -= code1; code0 = (code0 + 7) & 0xff; } src[1] = 131; /* needed for all Emerald Mine levels */ /* first byte is either 0xf1 (EM I and III) or 0xf5 (EM II) */ if (first_byte == 0xf5) { src[0] = 131; /* only needed for Emerald Mine II levels */ fix_copyright = TRUE; } /* ---------- this cave has V3 file format ---------- */ file_version = FILE_VERSION_EM_V3; } else if (filename_has_v1_format(filename)) { /* ---------- this cave has V1 file format ---------- */ file_version = FILE_VERSION_EM_V1; } else { /* ---------- this cave has V2 file format ---------- */ file_version = FILE_VERSION_EM_V2; } /* remap elements to internal EMC level format */ for (i = 0; i < 2048; i++) src[i] = remap_v4[src[i]]; for (i = 2048; i < 2084; i++) src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]]; for (i = 2112; i < 2148; i++) src[i] = src[i - 64]; if (fix_copyright) /* fix "(c)" sign in Emerald Mine II levels */ { for (i = 0; i < 2048; i++) if (src[i] == 241) src[i] = 254; /* replace 'Xdecor_1' with 'Xalpha_copyr' */ } } else { /* ---------- this cave has unknown file format ---------- */ /* if file has length of old-style level file, print (wrong) magic byte */ if (length < 2110) Error(ERR_WARN, "unknown magic byte 0x%02x at position 0x%04x", src[1983], 1983); return FILE_VERSION_EM_UNKNOWN; } if (file_version < FILE_VERSION_EM_V6) { /* id */ src[2106] = 255; /* version id: */ src[2107] = 54; /* '6' */ src[2108] = 48; /* '0' */ src[2109] = 48; /* '0' */ /* time */ i = src[2094] * 10; /* stored level time of levels for the V2 player was changed to 50% of the time for the V1 player (original V3 levels already considered this) */ if (file_version != FILE_VERSION_EM_V1 && file_version != FILE_VERSION_EM_V3) i /= 2; src[2110] = i >> 8; src[2111] = i; for (i = 2148; i < 2172; i++) src[i] = 0; /* ball data */ src[2159] = 128; } /* ---------- at this stage, the cave data always has V6 format ---------- */ /* fix wheel */ for (i = 0; i < 2048; i++) if (src[i] == 40) break; for (i++; i < 2048; i++) if (src[i] == 40) src[i] = 147; #if 0 /* fix acid */ for (i = 64; i < 2048; i++) if (src[i] == 63) /* replace element above 'Xacid_s' ... */ src[i - 64] = 101; /* ... with 'Xacid_1' */ #else #if 1 /* fix acid */ for (i = 64; i < 2048; i++) if (src[i] == 63) /* replace element above 'Xacid_s' ... */ src[i - 64] = 101; /* ... with 'Xacid_1' */ /* fix acid with no base beneath it (see below for details (*)) */ for (i = 64; i < 2048 - 1; i++) { if (file_version <= FILE_VERSION_EM_V2 && src[i - 64] == 101 && src[i] != 63) /* acid without base */ { if (src[i - 1] == 101 || /* remove acid over acid row */ src[i + 1] == 101) src[i - 64] = 6; /* replace element above with 'Xblank' */ else src[i - 64] = 255; /* replace element above with 'Xfake_acid_1' */ } } #else /* fix acid */ for (i = 64; i < 2048; i++) { if (src[i] == 63) /* 'Xacid_s' (acid pool, bottom middle) */ { if (file_version <= FILE_VERSION_EM_V2 && i < 2048 - 64 && src[i + 64] == 63) { int obj_left = remap_emerald[src[i - 1]]; int obj_right = remap_emerald[src[i + 1]]; if (obj_left == Xblank || obj_right == Xblank || obj_left == Xplant || obj_right == Xplant) src[i - 64] = 6; /* replace element above with 'Xblank' */ else src[i - 64] = 255; /* replace element above with 'Xfake_acid_1' */ } else { src[i - 64] = 101; /* replace element above with 'Xacid_1' */ } } } #endif #endif /* fix acid in eater 1 */ for (i = 2051; i < 2057; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 2 */ for (i = 2060; i < 2066; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 3 */ for (i = 2069; i < 2075; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 4 */ for (i = 2078; i < 2084; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 5 */ for (i = 2115; i < 2121; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 6 */ for (i = 2124; i < 2130; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 7 */ for (i = 2133; i < 2139; i++) if (src[i] == 63) src[i - 3] = 101; /* fix acid in eater 8 */ for (i = 2142; i < 2148; i++) if (src[i] == 63) src[i - 3] = 101; /* old style time */ src[2094] = 0; /* player 1 pos */ src[2096] &= 7; src[src[2096] << 8 | src[2097]] = 128; /* player 2 pos */ src[2098] &= 7; src[src[2098] << 8 | src[2099]] = 128; /* amoeba speed */ if ((src[2100] << 8 | src[2101]) > 9999) { src[2100] = 39; src[2101] = 15; } /* time wonderwall */ if ((src[2102] << 8 | src[2103]) > 9999) { src[2102] = 39; src[2103] = 15; } /* time */ if ((src[2110] << 8 | src[2111]) > 9999) { src[2110] = 39; src[2111] = 15; } /* wind direction */ i = src[2149]; i &= 15; i &= -i; src[2149] = i; /* time lenses */ if ((src[2154] << 8 | src[2155]) > 9999) { src[2154] = 39; src[2155] = 15; } /* time magnify */ if ((src[2156] << 8 | src[2157]) > 9999) { src[2156] = 39; src[2157] = 15; } /* ball object */ src[2158] = 0; src[2159] = remap_v6[src[2159]]; /* ball pause */ if ((src[2160] << 8 | src[2161]) > 9999) { src[2160] = 39; src[2161] = 15; } /* ball data */ src[2162] &= 129; if (src[2162] & 1) src[2163] = 0; /* android move pause */ if ((src[2164] << 8 | src[2165]) > 9999) { src[2164] = 39; src[2165] = 15; } /* android clone pause */ if ((src[2166] << 8 | src[2167]) > 9999) { src[2166] = 39; src[2167] = 15; } /* android data */ src[2168] &= 31; /* size of v6 cave */ length = 2172; if (options.debug) printf("::: EM level file version: %d\n", file_version); return file_version; } /* 2000-07-30T00:26:00Z * * Read emerald mine caves version 6 * * v4 and v5 emerald mine caves are converted to v6 (which completely supports * older versions) * * converting to the internal format loses /significant/ information which can * break lots of caves. * * major incompatibilities: * - borderless caves behave completely differently, the player no longer * "warps" to the other side. * - a compile time option for spring can make it behave differently when it * rolls. * - a compile time option for rolling objects (stone, nut, spring, bomb) only * in eater. * - acid is always deadly even with no base beneath it (this breaks cave 0 in * downunder mine 16) * (*) fixed (see above): * - downunder mine 16, level 0, works again * - downunder mine 11, level 71, corrected (only cosmetically) * * so far all below have not broken any caves: * * - active wheel inside an eater will not function, eater explosions will not * change settings. * - initial collect objects (emerald, diamond, dynamite) don't exist. * - initial rolling objects will be moved manually and made into sitting * objects. * - drips always appear from dots. * - more than one thing can fall into acid at the same time. * - acid explodes when the player walks into it, rather than splashing. * - simultaneous explosions may be in a slightly different order. * - quicksand states have been reduced. * - acid base is effectively an indestructable wall now which can affect eater * explosions. * - android can clone forever with a clone pause of 0 (emeralds, diamonds, * nuts, stones, bombs, springs). * * 2001-03-12T02:46:55Z * - rolling stuff is now allowed in the cave, i didn't like making this * decision. * - if BAD_ROLL is not defined, initial rolling objects are moved by hand. * - initial collect objects break some cave in elvis mine 5. * - different timing for wonderwall break some cave in exception mine 2. * - i think i'm pretty locked into always using the bad roll. *sigh* * - rolling spring is now turned into regular spring. it appears the emc * editor only uses the force code for initially moving spring. i will * follow this in my editor. * * 2006-04-02 * - introduced ALLOW_ROLLING_SPRING; if defined, do NOT turn rolling spring * into regular spring, because this breaks at least E.M.C. Mine 3, level 79 * (see comment directly above) */ static unsigned short remap_emerald[256] = { Xstone, Xstone, Xdiamond, Xdiamond, Xalien, Xalien, Xblank, Xblank, Xtank_n, Xtank_e, Xtank_s, Xtank_w, Xtank_gon, Xtank_goe, Xtank_gos, Xtank_gow, Xbomb, Xbomb, Xemerald, Xemerald, Xbug_n, Xbug_e, Xbug_s, Xbug_w, Xbug_gon, Xbug_goe, Xbug_gos, Xbug_gow, Xdrip_eat, Xdrip_eat, Xdrip_eat, Xdrip_eat, Xstone, Xbomb, Xdiamond, Xemerald, Xwonderwall, Xnut, Xnut, Xnut, Xwheel, Xeater_n, Xeater_s, Xeater_w, Xeater_e, Xsand_stone, Xblank, Xblank, Xblank, Xsand, Xsand, Xsand, Xsand_stone, Xsand_stone, Xsand_stone, Xsand, Xstone, Xgrow_ew, Xgrow_ns, Xdynamite_1, Xdynamite_2, Xdynamite_3, Xdynamite_4, Xacid_s, #ifdef ALLOW_ROLLING_SPRING Xexit_1, Xexit_2, Xexit_3, Xballoon, Xplant, Xspring, Xspring_fall, Xspring_w, Xspring_e, Xball_1, Xball_2, Xandroid, Xblank, Xandroid, Xandroid, Xandroid, #else Xexit_1, Xexit_2, Xexit_3, Xballoon, Xplant, Xspring, Xspring, Xspring, Xspring, Xball_1, Xball_2, Xandroid, Xblank, Xandroid, Xandroid, Xandroid, #endif Xandroid, Xandroid, Xandroid, Xandroid, Xandroid, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, #ifdef BAD_ROLL Xblank, Xblank, Xblank, Xspring_force_w, Xspring_force_e, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xblank, Xblank, Xblank, Xblank, Xblank, Xnut_force_w, Xnut_force_e, Xsteel_1, Xblank, Xblank, Xbomb_force_w, Xbomb_force_e, Xstone_force_w, Xstone_force_e, Xblank, Xblank, Xblank, Xblank, Xblank, #else Xblank, Xblank, Xblank, Xspring, Xspring, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xblank, Xblank, Xblank, Xblank, Xblank, Xnut, Xnut, Xsteel_1, Xblank, Xblank, Xbomb, Xbomb, Xstone, Xstone, Xblank, Xblank, Xblank, Xblank, Xblank, #endif Xblank, Xround_wall_1, Xgrass, Xsteel_1, Xwall_1, Xkey_1, Xkey_2, Xkey_3, Xkey_4, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdripper, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xwonderwall, Xwheel, Xsand, Xacid_nw, Xacid_ne, Xacid_sw, Xacid_se, Xfake_blank, Xamoeba_1, Xamoeba_2, Xamoeba_3, Xamoeba_4, Xexit, Xalpha_arrow_w, Xfake_grass, Xlenses, Xmagnify, Xfake_blank, Xfake_grass, Xswitch, Xswitch, Xblank, Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_5, Xalpha_comma, Xalpha_quote, Xalpha_minus, Xdynamite, Xsteel_3, Xdecor_6, Xdecor_7, Xsteel_2, Xround_wall_2, Xdecor_2, Xdecor_4, Xdecor_3, Xwind_nesw, Xwind_e, Xwind_s, Xwind_w, Xwind_n, Xdirt, Xplant, Xkey_5, Xkey_6, Xkey_7, Xkey_8, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xbumper, Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d, Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h, Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l, Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p, Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t, Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x, Xalpha_y, Xalpha_z, Xalpha_0, Xalpha_1, Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5, Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9, Xalpha_perio, Xalpha_excla, Xalpha_colon, Xalpha_quest, Xalpha_arrow_e, Xdecor_1, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, Xblank, Xblank, Xblank, Xblank, Xblank, Xblank, #if 0 Xblank, Xblank, Xblank, Xblank, #else /* special elements added to solve compatibility problems */ Xblank, Xblank, Xalpha_copyr, Xfake_acid_1 #endif }; static int get_em_element(unsigned short em_element_raw, int file_version) { int em_element = remap_emerald[em_element_raw]; if (file_version < FILE_VERSION_EM_V5) { /* versions below V5 had no grass, but only sand/dirt */ if (em_element == Xgrass) em_element = Xdirt; } return em_element; } void convert_em_level(unsigned char *src, int file_version) { static int eater_offset[8] = { 0x800, 0x809, 0x812, 0x81B, 0x840, 0x849, 0x852, 0x85B }; int i, x, y, temp; #if 1 lev.time_seconds = src[0x83E] << 8 | src[0x83F]; if (lev.time_seconds > 9999) lev.time_seconds = 9999; #else temp = ((src[0x83E] << 8 | src[0x83F]) * 25 + 3) / 4; if (temp == 0 || temp > 9999) temp = 9999; lev.time_initial = temp; #endif lev.required_initial = src[0x82F]; for (i = 0; i < 2; i++) { temp = src[0x830 + i * 2] << 8 | src[0x831 + i * 2]; ply[i].x_initial = (temp & 63) + 1; ply[i].y_initial = (temp >> 6 & 31) + 1; } temp = (src[0x834] << 8 | src[0x835]) * 28; if (temp > 9999) temp = 9999; lev.amoeba_time = temp; lev.android_move_time = src[0x874] << 8 | src[0x875]; lev.android_clone_time = src[0x876] << 8 | src[0x877]; lev.ball_random = src[0x872] & 1 ? 1 : 0; lev.ball_state_initial = src[0x872] & 128 ? 1 : 0; lev.ball_time = src[0x870] << 8 | src[0x871]; lev.emerald_score = src[0x824]; lev.diamond_score = src[0x825]; lev.alien_score = src[0x826]; lev.tank_score = src[0x827]; lev.bug_score = src[0x828]; lev.eater_score = src[0x829]; lev.nut_score = src[0x82A]; lev.dynamite_score = src[0x82B]; lev.key_score = src[0x82C]; lev.exit_score = src[0x82D] * 8 / 5; lev.lenses_score = src[0x867]; lev.magnify_score = src[0x868]; lev.slurp_score = src[0x869]; lev.lenses_time = src[0x86A] << 8 | src[0x86B]; lev.magnify_time = src[0x86C] << 8 | src[0x86D]; lev.wheel_time = src[0x838] << 8 | src[0x839]; lev.wind_cnt_initial = src[0x865] & 15 ? lev.wind_time : 0; temp = src[0x865]; lev.wind_direction_initial = (temp & 8 ? 0 : temp & 1 ? 1 : temp & 2 ? 2 : temp & 4 ? 3 : 0); lev.wonderwall_time_initial = src[0x836] << 8 | src[0x837]; for (i = 0; i < 8; i++) for (x = 0; x < 9; x++) lev.eater_array[i][x] = get_em_element(src[eater_offset[i] + x], file_version); temp = get_em_element(src[0x86F], file_version); for (y = 0; y < 8; y++) { if (src[0x872] & 1) { for (x = 0; x < 8; x++) lev.ball_array[y][x] = temp; } else { lev.ball_array[y][1] = (src[0x873] & 1) ? temp : Xblank; /* north */ lev.ball_array[y][6] = (src[0x873] & 2) ? temp : Xblank; /* south */ lev.ball_array[y][3] = (src[0x873] & 4) ? temp : Xblank; /* west */ lev.ball_array[y][4] = (src[0x873] & 8) ? temp : Xblank; /* east */ lev.ball_array[y][7] = (src[0x873] & 16) ? temp : Xblank; /* southeast */ lev.ball_array[y][5] = (src[0x873] & 32) ? temp : Xblank; /* southwest */ lev.ball_array[y][2] = (src[0x873] & 64) ? temp : Xblank; /* northeast */ lev.ball_array[y][0] = (src[0x873] & 128)? temp : Xblank; /* northwest */ } } temp = src[0x878] << 8 | src[0x879]; if (temp & 1) { lev.android_array[Xemerald] = Xemerald; lev.android_array[Xemerald_pause] = Xemerald; lev.android_array[Xemerald_fall] = Xemerald; lev.android_array[Yemerald_sB] = Xemerald; lev.android_array[Yemerald_eB] = Xemerald; lev.android_array[Yemerald_wB] = Xemerald; } if (temp & 2) { lev.android_array[Xdiamond] = Xdiamond; lev.android_array[Xdiamond_pause] = Xdiamond; lev.android_array[Xdiamond_fall] = Xdiamond; lev.android_array[Ydiamond_sB] = Xdiamond; lev.android_array[Ydiamond_eB] = Xdiamond; lev.android_array[Ydiamond_wB] = Xdiamond; } if (temp & 4) { lev.android_array[Xstone] = Xstone; lev.android_array[Xstone_pause] = Xstone; lev.android_array[Xstone_fall] = Xstone; lev.android_array[Ystone_sB] = Xstone; lev.android_array[Ystone_eB] = Xstone; lev.android_array[Ystone_wB] = Xstone; } if (temp & 8) { lev.android_array[Xbomb] = Xbomb; lev.android_array[Xbomb_pause] = Xbomb; lev.android_array[Xbomb_fall] = Xbomb; lev.android_array[Ybomb_sB] = Xbomb; lev.android_array[Ybomb_eB] = Xbomb; lev.android_array[Ybomb_wB] = Xbomb; } if (temp & 16) { lev.android_array[Xnut] = Xnut; lev.android_array[Xnut_pause] = Xnut; lev.android_array[Xnut_fall] = Xnut; lev.android_array[Ynut_sB] = Xnut; lev.android_array[Ynut_eB] = Xnut; lev.android_array[Ynut_wB] = Xnut; } if (temp & 32) { lev.android_array[Xtank_n] = Xtank_n; lev.android_array[Xtank_gon] = Xtank_n; lev.android_array[Ytank_nB] = Xtank_n; lev.android_array[Ytank_n_e] = Xtank_n; lev.android_array[Ytank_n_w] = Xtank_n; lev.android_array[Xtank_e] = Xtank_e; lev.android_array[Xtank_goe] = Xtank_e; lev.android_array[Ytank_eB] = Xtank_e; lev.android_array[Ytank_e_s] = Xtank_e; lev.android_array[Ytank_e_n] = Xtank_e; lev.android_array[Xtank_s] = Xtank_s; lev.android_array[Xtank_gos] = Xtank_s; lev.android_array[Ytank_sB] = Xtank_s; lev.android_array[Ytank_s_w] = Xtank_s; lev.android_array[Ytank_s_e] = Xtank_s; lev.android_array[Xtank_w] = Xtank_w; lev.android_array[Xtank_gow] = Xtank_w; lev.android_array[Ytank_wB] = Xtank_w; lev.android_array[Ytank_w_n] = Xtank_w; lev.android_array[Ytank_w_s] = Xtank_w; } if (temp & 64) { lev.android_array[Xeater_n] = Xeater_n; lev.android_array[Yeater_nB] = Xeater_n; lev.android_array[Xeater_e] = Xeater_e; lev.android_array[Yeater_eB] = Xeater_e; lev.android_array[Xeater_s] = Xeater_s; lev.android_array[Yeater_sB] = Xeater_s; lev.android_array[Xeater_w] = Xeater_w; lev.android_array[Yeater_wB] = Xeater_w; } if (temp & 128) { lev.android_array[Xbug_n] = Xbug_gon; lev.android_array[Xbug_gon] = Xbug_gon; lev.android_array[Ybug_nB] = Xbug_gon; lev.android_array[Ybug_n_e] = Xbug_gon; lev.android_array[Ybug_n_w] = Xbug_gon; lev.android_array[Xbug_e] = Xbug_goe; lev.android_array[Xbug_goe] = Xbug_goe; lev.android_array[Ybug_eB] = Xbug_goe; lev.android_array[Ybug_e_s] = Xbug_goe; lev.android_array[Ybug_e_n] = Xbug_goe; lev.android_array[Xbug_s] = Xbug_gos; lev.android_array[Xbug_gos] = Xbug_gos; lev.android_array[Ybug_sB] = Xbug_gos; lev.android_array[Ybug_s_w] = Xbug_gos; lev.android_array[Ybug_s_e] = Xbug_gos; lev.android_array[Xbug_w] = Xbug_gow; lev.android_array[Xbug_gow] = Xbug_gow; lev.android_array[Ybug_wB] = Xbug_gow; lev.android_array[Ybug_w_n] = Xbug_gow; lev.android_array[Ybug_w_s] = Xbug_gow; } if (temp & 256) { lev.android_array[Xalien] = Xalien; lev.android_array[Xalien_pause] = Xalien; lev.android_array[Yalien_nB] = Xalien; lev.android_array[Yalien_eB] = Xalien; lev.android_array[Yalien_sB] = Xalien; lev.android_array[Yalien_wB] = Xalien; } if (temp & 512) { lev.android_array[Xspring] = Xspring; lev.android_array[Xspring_pause] = Xspring; lev.android_array[Xspring_e] = Xspring; lev.android_array[Yspring_eB] = Xspring; lev.android_array[Yspring_kill_eB] = Xspring; lev.android_array[Xspring_w] = Xspring; lev.android_array[Yspring_wB] = Xspring; lev.android_array[Yspring_kill_wB] = Xspring; lev.android_array[Xspring_fall] = Xspring; lev.android_array[Yspring_sB] = Xspring; } if (temp & 1024) { lev.android_array[Yballoon_nB] = Xballoon; lev.android_array[Yballoon_eB] = Xballoon; lev.android_array[Yballoon_sB] = Xballoon; lev.android_array[Yballoon_wB] = Xballoon; lev.android_array[Xballoon] = Xballoon; } if (temp & 2048) { lev.android_array[Xdripper] = Xdrip_eat; lev.android_array[XdripperB] = Xdrip_eat; lev.android_array[Xamoeba_1] = Xdrip_eat; lev.android_array[Xamoeba_2] = Xdrip_eat; lev.android_array[Xamoeba_3] = Xdrip_eat; lev.android_array[Xamoeba_4] = Xdrip_eat; lev.android_array[Xamoeba_5] = Xdrip_eat; lev.android_array[Xamoeba_6] = Xdrip_eat; lev.android_array[Xamoeba_7] = Xdrip_eat; lev.android_array[Xamoeba_8] = Xdrip_eat; } if (temp & 4096) { lev.android_array[Xdynamite] = Xdynamite; } for (temp = 1; temp < 2047; temp++) { switch (src[temp]) { case 0x24: /* wonderwall */ lev.wonderwall_state_initial = 1; lev.wonderwall_time_initial = 9999; break; case 0x28: /* wheel */ lev.wheel_x_initial = temp & 63; lev.wheel_y_initial = temp >> 6; lev.wheel_cnt_initial = lev.wheel_time; break; #ifndef BAD_ROLL case 0x63: /* spring roll left */ src[temp - 1] = 0x45; src[temp] = 0x80; break; case 0x64: /* spring roll right */ src[temp + 1] = 0x45; src[temp] = 0x80; break; case 0x72: /* nut roll left */ src[temp - 1] = 0x25; src[temp] = 0x80; break; case 0x73: /* nut roll right */ src[temp + 1] = 0x25; src[temp] = 0x80; break; case 0x77: /* bomb roll left */ src[temp - 1] = 0x10; src[temp] = 0x80; break; case 0x78: /* bomb roll right */ src[temp + 1] = 0x10; src[temp] = 0x80; break; case 0x79: /* stone roll left */ src[temp - 1] = 0x00; src[temp] = 0x80; break; case 0x7A: /* stone roll right */ src[temp + 1] = 0x00; src[temp] = 0x80; break; #endif case 0xA3: /* fake blank */ lev.lenses_cnt_initial = 9999; break; case 0xA4: /* fake grass */ lev.magnify_cnt_initial = 9999; break; } } /* first fill the complete playfield with the default border element */ for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) native_em_level.cave[x][y] = ZBORDER; /* then copy the real level contents from level file into the playfield */ temp = 0; for (y = 0; y < lev.height; y++) for (x = 0; x < lev.width; x++) native_em_level.cave[x + 1][y + 1] = get_em_element(src[temp++], file_version); /* at last, set the two players at their positions in the playfield */ /* (native EM[C] levels always have exactly two players in a level) */ for (i = 0; i < 2; i++) native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer; native_em_level.file_version = file_version; } void prepare_em_level(void) { int i, x, y; int players_left; boolean team_mode; /* reset all runtime variables to their initial values */ for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Cave[y][x] = native_em_level.cave[x][y]; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Next[y][x] = Cave[y][x]; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Draw[y][x] = Cave[y][x]; lev.time_initial = lev.time_seconds; lev.time = lev.time_initial; lev.required = lev.required_initial; lev.score = 0; lev.android_move_cnt = lev.android_move_time; lev.android_clone_cnt = lev.android_clone_time; lev.ball_pos = 0; lev.ball_state = lev.ball_state_initial; lev.ball_cnt = lev.ball_time; lev.eater_pos = 0; lev.shine_cnt = 0; lev.lenses_cnt = lev.lenses_cnt_initial; lev.magnify_cnt = lev.magnify_cnt_initial; lev.wheel_cnt = lev.wheel_cnt_initial; lev.wheel_x = lev.wheel_x_initial; lev.wheel_y = lev.wheel_y_initial; lev.wind_direction = lev.wind_direction_initial; lev.wind_cnt = lev.wind_cnt_initial; lev.wonderwall_state = lev.wonderwall_state_initial; lev.wonderwall_time = lev.wonderwall_time_initial; lev.killed_out_of_time = FALSE; /* determine number of players in this level */ lev.home_initial = 0; for (i = 0; i < MAX_PLAYERS; i++) { ply[i].exists = 0; ply[i].alive_initial = FALSE; if (ply[i].x_initial > 0 && ply[i].y_initial > 0) { ply[i].exists = 1; lev.home_initial++; } } team_mode = getTeamMode_EM(); if (!team_mode) lev.home_initial = 1; lev.home = lev.home_initial; players_left = lev.home_initial; for (i = 0; i < MAX_PLAYERS; i++) { if (ply[i].exists) { if (players_left) { ply[i].alive_initial = TRUE; players_left--; } else { int x = ply[i].x_initial; int y = ply[i].y_initial; native_em_level.cave[x][y] = Xblank; Cave[y][x] = Next[y][x] = Draw[y][x] = Xblank; } } } for (i = 0; i < MAX_PLAYERS; i++) { ply[i].num = i; ply[i].alive = ply[i].alive_initial; ply[i].dynamite = 0; ply[i].dynamite_cnt = 0; ply[i].keys = 0; ply[i].anim = 0; ply[i].oldx = ply[i].x = ply[i].x_initial; ply[i].oldy = ply[i].y = ply[i].y_initial; ply[i].last_move_dir = MV_NONE; ply[i].joy_n = ply[i].joy_e = ply[i].joy_s = ply[i].joy_w = 0; ply[i].joy_snap = ply[i].joy_drop = 0; ply[i].joy_stick = ply[i].joy_spin = 0; } // the following engine variables are initialized to version-specific values // in function InitGameEngine() (src/game.c): // // - game_em.use_single_button (default: TRUE) // - game_em.use_snap_key_bug (default: FALSE) game_em.any_player_moving = FALSE; game_em.any_player_snapping = FALSE; game_em.last_moving_player = 0; /* default: first player */ for (i = 0; i < MAX_PLAYERS; i++) game_em.last_player_direction[i] = MV_NONE; lev.exit_x = lev.exit_y = -1; /* kludge for playing player exit sound */ } mirrormagic-3.0.0/src/game_em/global.h0000644000175000017500000000205413263212010017114 0ustar aeglosaeglos#ifndef GLOBAL_H #define GLOBAL_H #include "main_em.h" #define EM_GFX_DIR "graphics.EM" #define EM_SND_DIR "sounds.EM" #define EM_LVL_DIR "levels.EM" /* arbitrary maximum length of filenames (cos i am lazy) */ #define MAXNAME 1024 extern int debug; extern char *progname; extern char *arg_basedir; extern int frame; extern short ulaw_to_linear[256]; extern unsigned char linear_to_ulaw[65536]; /* all global function prototypes */ int open_all(void); void close_all(void); void readjoy(byte, struct PLAYER *); void input_eventloop(void); void game_initscreen(void); void play_sound(int, int, int); void sound_play(void); int cave_convert(char *); void game_init_vars(void); void game_play_init(int, char *); void game_loop(byte); void synchro_1(void); void synchro_2(void); void synchro_3(void); int cleanup_em_level(unsigned char *, int, char *); void convert_em_level(unsigned char *, int); void prepare_em_level(void); int sound_thread(void); int read_sample(char *, short **, int *); void read_cave_list(void); void free_cave_list(void); #endif mirrormagic-3.0.0/src/game_em/ulaw_generate.c0000644000175000017500000000022313263212010020465 0ustar aeglosaeglos/* 2000-08-10T04:29:10Z * * generate ulaw<->linear conversion tables to be included * directly in emerald mine source */ #include "main_em.h" mirrormagic-3.0.0/src/game_em/input.c0000644000175000017500000001110713263212010017005 0ustar aeglosaeglos/* 2000-08-13T15:29:40Z * * handle input from x11 and keyboard and joystick */ #include "main_em.h" unsigned int RandomEM; struct LEVEL lev; struct PLAYER ply[MAX_PLAYERS]; short **Boom; short **Cave; short **Next; short **Draw; static short *Index[4][HEIGHT]; static short Array[4][HEIGHT][WIDTH]; extern int screen_x; extern int screen_y; struct EngineSnapshotInfo_EM engine_snapshot_em; void game_init_vars(void) { int x, y; RandomEM = 1684108901; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[0][y][x] = ZBORDER; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[1][y][x] = ZBORDER; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[2][y][x] = ZBORDER; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) Array[3][y][x] = Xblank; for (y = 0; y < HEIGHT; y++) Index[0][y] = Array[0][y]; for (y = 0; y < HEIGHT; y++) Index[1][y] = Array[1][y]; for (y = 0; y < HEIGHT; y++) Index[2][y] = Array[2][y]; for (y = 0; y < HEIGHT; y++) Index[3][y] = Array[3][y]; Cave = Index[0]; Next = Index[1]; Draw = Index[2]; Boom = Index[3]; } void InitGameEngine_EM() { prepare_em_level(); game_initscreen(); RedrawPlayfield_EM(FALSE); } void UpdateGameDoorValues_EM() { } void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode) { int i; boolean any_player_dropping = FALSE; RandomEM = RandomEM * 129 + 1; frame = (frame - 1) & 7; for (i = 0; i < MAX_PLAYERS; i++) readjoy(action[i], &ply[i]); UpdateEngineValues(screen_x / TILEX, screen_y / TILEY, ply[0].x, ply[0].y); if (frame == 7) { synchro_1(); synchro_2(); } if (frame == 6) { synchro_3(); sound_play(); UpdateGameDoorValues_EM(); } for (i = 0; i < MAX_PLAYERS; i++) if (ply[i].joy_drop && ply[i].dynamite && ply[i].dynamite_cnt > 0 && ply[i].dynamite_cnt < 5) any_player_dropping = TRUE; CheckSingleStepMode_EM(action, frame, game_em.any_player_moving, game_em.any_player_snapping, any_player_dropping); RedrawPlayfield_EM(FALSE); } /* read input device for players */ void readjoy(byte action, struct PLAYER *ply) { int north = 0, east = 0, south = 0, west = 0; int snap = 0, drop = 0; if (game_em.use_single_button && action & (JOY_BUTTON_1 | JOY_BUTTON_2)) action |= JOY_BUTTON_1 | JOY_BUTTON_2; if (action & JOY_LEFT) west = 1; if (action & JOY_RIGHT) east = 1; if (action & JOY_UP) north = 1; if (action & JOY_DOWN) south = 1; if (action & JOY_BUTTON_1) snap = 1; if (action & JOY_BUTTON_2) drop = 1; /* always update drop action */ ply->joy_drop = drop; if (ply->joy_stick || (north | east | south | west)) /* (no "| snap"!) */ { ply->joy_n = north; ply->joy_e = east; ply->joy_s = south; ply->joy_w = west; /* when storing last action, only update snap action with direction */ /* (prevents clearing direction if snapping stopped before frame 7) */ ply->joy_snap = snap; } /* if no direction was stored before, allow setting snap to current state */ if (!ply->joy_n && !ply->joy_e && !ply->joy_s && !ply->joy_w) ply->joy_snap = snap; /* use bug with snap key (mainly TAS keys) sometimes moving the player */ if (game_em.use_snap_key_bug) ply->joy_snap = snap; } void SaveEngineSnapshotValues_EM() { int i, j, k; engine_snapshot_em.game_em = game_em; engine_snapshot_em.lev = lev; engine_snapshot_em.RandomEM = RandomEM; engine_snapshot_em.frame = frame; engine_snapshot_em.screen_x = screen_x; engine_snapshot_em.screen_y = screen_y; engine_snapshot_em.Boom = Boom; engine_snapshot_em.Cave = Cave; engine_snapshot_em.Next = Next; engine_snapshot_em.Draw = Draw; for (i = 0; i < 4; i++) engine_snapshot_em.ply[i] = ply[i]; for (i = 0; i < 4; i++) for (j = 0; j < HEIGHT; j++) for (k = 0; k < WIDTH; k++) engine_snapshot_em.Array[i][j][k] = Array[i][j][k]; } void LoadEngineSnapshotValues_EM() { int i, j, k; game_em = engine_snapshot_em.game_em; lev = engine_snapshot_em.lev; RandomEM = engine_snapshot_em.RandomEM; frame = engine_snapshot_em.frame; screen_x = engine_snapshot_em.screen_x; screen_y = engine_snapshot_em.screen_y; Boom = engine_snapshot_em.Boom; Cave = engine_snapshot_em.Cave; Next = engine_snapshot_em.Next; Draw = engine_snapshot_em.Draw; for (i = 0; i < 4; i++) ply[i] = engine_snapshot_em.ply[i]; for (i = 0; i < 4; i++) for (j = 0; j < HEIGHT; j++) for (k = 0; k < WIDTH; k++) Array[i][j][k] = engine_snapshot_em.Array[i][j][k]; } mirrormagic-3.0.0/src/game_em/Makefile0000644000175000017500000000361113263212010017143 0ustar aeglosaeglos# ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1995-2014 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # The native Emerald Mine game engine is based on: # Emerald Mine for X11 (c) 2000,2001 David Tritscher # ----------------------------------------------------------------------------- # src/game_em/Makefile # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = cave.c \ convert.c \ graphics.c \ init.c \ input.c \ main.c \ sound.c \ synchro_1.c \ synchro_2.c \ synchro_3.c \ tab_generate.c \ ulaw_generate.c OBJS = cave.o \ convert.o \ graphics.o \ init.o \ input.o \ main.o \ sound.o \ synchro_1.o \ synchro_2.o \ synchro_3.o \ tab_generate.o \ ulaw_generate.o GAME_EM = game_em.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(GAME_EM) $(GAME_EM): $(OBJS) $(AR) cru $(GAME_EM) $(OBJS) $(RANLIB) $(GAME_EM) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(GAME_EM) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif mirrormagic-3.0.0/src/game_em/tile.h0000644000175000017500000001525113263212010016614 0ustar aeglosaeglos#ifndef TILE_H #define TILE_H #include "main_em.h" #ifdef EM_ENGINE_BAD_ROLL #define BAD_ROLL #endif #ifdef EM_ENGINE_BAD_SPRING #define BAD_SPRING #endif #if 0 /* 2000-07-30T11:06:03Z */ /* define these for backwards compatibility */ #define BAD_ROLL #define BAD_SPRING enum { Xblank = 0, /* still */ Yacid_splash_eB, /* hmm */ Yacid_splash_wB, /* hmm */ #ifdef BAD_ROLL Xstone_force_e, /* only use these in eater */ Xstone_force_w, Xnut_force_e, Xnut_force_w, Xspring_force_e, Xspring_force_w, Xemerald_force_e, Xemerald_force_w, Xdiamond_force_e, Xdiamond_force_w, Xbomb_force_e, Xbomb_force_w, #endif Xstone, Xstone_pause, Xstone_fall, Ystone_s, Ystone_sB, Ystone_e, Ystone_eB, Ystone_w, Ystone_wB, Xnut, Xnut_pause, Xnut_fall, Ynut_s, Ynut_sB, Ynut_e, Ynut_eB, Ynut_w, Ynut_wB, Xbug_n, Xbug_e, Xbug_s, Xbug_w, Xbug_gon, Xbug_goe, Xbug_gos, Xbug_gow, Ybug_n, Ybug_nB, Ybug_e, Ybug_eB, Ybug_s, Ybug_sB, Ybug_w, Ybug_wB, Ybug_w_n, Ybug_n_e, Ybug_e_s, Ybug_s_w, Ybug_e_n, Ybug_s_e, Ybug_w_s, Ybug_n_w, Ybug_stone, Ybug_spring, Xtank_n, Xtank_e, Xtank_s, Xtank_w, Xtank_gon, Xtank_goe, Xtank_gos, Xtank_gow, Ytank_n, Ytank_nB, Ytank_e, Ytank_eB, Ytank_s, Ytank_sB, Ytank_w, Ytank_wB, Ytank_w_n, Ytank_n_e, Ytank_e_s, Ytank_s_w, Ytank_e_n, Ytank_s_e, Ytank_w_s, Ytank_n_w, Ytank_stone, Ytank_spring, Xandroid, Xandroid_1_n, Xandroid_2_n, Xandroid_1_e, Xandroid_2_e, Xandroid_1_w, Xandroid_2_w, Xandroid_1_s, Xandroid_2_s, Yandroid_n, Yandroid_nB, Yandroid_ne, Yandroid_neB, Yandroid_e, Yandroid_eB, Yandroid_se, Yandroid_seB, Yandroid_s, Yandroid_sB, Yandroid_sw, Yandroid_swB, Yandroid_w, Yandroid_wB, Yandroid_nw, Yandroid_nwB, Xspring, Xspring_pause, Xspring_e, Xspring_w, Xspring_fall, Yspring_s, Yspring_sB, Yspring_e, Yspring_eB, Yspring_w, Yspring_wB, Yspring_kill_e, Yspring_kill_eB, Yspring_kill_w, Yspring_kill_wB, Xeater_n, Xeater_e, Xeater_w, Xeater_s, Yeater_n, Yeater_nB, Yeater_e, Yeater_eB, Yeater_s, Yeater_sB, Yeater_w, Yeater_wB, Yeater_stone, Yeater_spring, Xalien, Xalien_pause, Yalien_n, Yalien_nB, Yalien_e, Yalien_eB, Yalien_s, Yalien_sB, Yalien_w, Yalien_wB, Yalien_stone, Yalien_spring, Xemerald, Xemerald_pause, Xemerald_fall, Xemerald_shine, Yemerald_s, Yemerald_sB, Yemerald_e, Yemerald_eB, Yemerald_w, Yemerald_wB, Yemerald_eat, Yemerald_stone, Xdiamond, Xdiamond_pause, Xdiamond_fall, Xdiamond_shine, Ydiamond_s, Ydiamond_sB, Ydiamond_e, Ydiamond_eB, Ydiamond_w, Ydiamond_wB, Ydiamond_eat, Ydiamond_stone, Xdrip_fall, Xdrip_stretch, Xdrip_stretchB, Xdrip_eat, Ydrip_s1, Ydrip_s1B, Ydrip_s2, Ydrip_s2B, Xbomb, Xbomb_pause, Xbomb_fall, Ybomb_s, Ybomb_sB, Ybomb_e, Ybomb_eB, Ybomb_w, Ybomb_wB, Ybomb_eat, Xballoon, Yballoon_n, Yballoon_nB, Yballoon_e, Yballoon_eB, Yballoon_s, Yballoon_sB, Yballoon_w, Yballoon_wB, Xgrass, Ygrass_nB, Ygrass_eB, Ygrass_sB, Ygrass_wB, Xdirt, Ydirt_nB, Ydirt_eB, Ydirt_sB, Ydirt_wB, Xacid_ne, Xacid_se, Xacid_s, Xacid_sw, Xacid_nw, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xball_1, Xball_1B, Xball_2, Xball_2B, Yball_eat, Xgrow_ns, Ygrow_ns_eat, Xgrow_ew, Ygrow_ew_eat, Xwonderwall, XwonderwallB, Xamoeba_1, Xamoeba_2, Xamoeba_3, Xamoeba_4, Xamoeba_5, Xamoeba_6, Xamoeba_7, Xamoeba_8, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xkey_1, Xkey_2, Xkey_3, Xkey_4, Xkey_5, Xkey_6, Xkey_7, Xkey_8, Xwind_n, Xwind_e, Xwind_s, Xwind_w, Xwind_nesw, Xwind_stop, Xexit, Xexit_1, Xexit_2, Xexit_3, Xdynamite, Ydynamite_eat, Xdynamite_1, Xdynamite_2, Xdynamite_3, Xdynamite_4, Xbumper, XbumperB, Xwheel, XwheelB, Xswitch, XswitchB, Xsand, Xsand_stone, Xsand_stonein_1, Xsand_stonein_2, Xsand_stonein_3, Xsand_stonein_4, Xsand_stonesand_1, Xsand_stonesand_2, Xsand_stonesand_3, Xsand_stonesand_4, Xsand_stoneout_1, Xsand_stoneout_2, Xsand_sandstone_1, Xsand_sandstone_2, Xsand_sandstone_3, Xsand_sandstone_4, Xplant, Yplant, Xlenses, Xmagnify, Xdripper, XdripperB, Xfake_blank, Xfake_blankB, Xfake_grass, Xfake_grassB, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, Xsteel_1, Xsteel_2, Xsteel_3, Xsteel_4, Xwall_1, Xwall_2, Xwall_3, Xwall_4, Xround_wall_1, Xround_wall_2, Xround_wall_3, Xround_wall_4, Xdecor_1, Xdecor_2, Xdecor_3, Xdecor_4, Xdecor_5, Xdecor_6, Xdecor_7, Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_11, Xdecor_12, Xalpha_0, Xalpha_1, Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5, Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9, Xalpha_excla, Xalpha_quote, Xalpha_comma, Xalpha_minus, Xalpha_perio, Xalpha_colon, Xalpha_quest, Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d, Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h, Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l, Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p, Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t, Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x, Xalpha_y, Xalpha_z, Xalpha_arrow_e, Xalpha_arrow_w, Xalpha_copyr, Xboom_bug, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_bomb, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_android, /* passed from explode to synchro; transition to boom_2 */ Xboom_1, /* passed from explode to synchro; transition to boom_2 */ Xboom_2, /* transition to boom[] */ Znormal, /* no picture */ /* this tile is passed from synchro to explode, only in next[] */ Zdynamite, /* no picture */ /* this tile is passed from synchro to explode, only in next[] */ Zplayer, /* no picture */ /* special code to indicate player */ ZBORDER, /* no picture */ /* special code to indicate border */ TILE_MAX }; enum { SPR_still = 0, SPR_walk = 1, SPR_push = 5, SPR_spray = 9, SPR_MAX = 13 }; #endif extern unsigned char tab_blank[TILE_MAX]; extern unsigned char tab_acid[TILE_MAX]; extern unsigned char tab_amoeba[TILE_MAX]; extern unsigned char tab_android_move[TILE_MAX]; extern unsigned short tab_explode_normal[TILE_MAX]; extern unsigned short tab_explode_dynamite[TILE_MAX]; extern unsigned short map_obj[8][TILE_MAX]; extern unsigned short map_spr[2][8][SPR_MAX]; extern unsigned short map_ttl[128]; #endif mirrormagic-3.0.0/src/game_em/init.c0000644000175000017500000000335113263212010016613 0ustar aeglosaeglos/* 2000-08-10T18:03:54Z * * open X11 display and sound */ #include "main_em.h" #include Bitmap *objBitmap; Bitmap *sprBitmap; Bitmap *screenBitmap; char play[SAMPLE_MAX]; int play_x[SAMPLE_MAX]; int play_y[SAMPLE_MAX]; int play_element[SAMPLE_MAX]; struct GlobalInfo_EM global_em_info; struct GameInfo_EM game_em; char *progname; char *arg_basedir; extern void tab_generate(); extern void tab_generate_graphics_info_em(); int open_all(void) { Bitmap *emc_bitmaps[2]; SetBitmaps_EM(emc_bitmaps); objBitmap = emc_bitmaps[0]; sprBitmap = emc_bitmaps[1]; return 0; } void InitGfxBuffers_EM() { ReCreateBitmap(&screenBitmap, MAX_BUF_XSIZE * TILEX, MAX_BUF_YSIZE * TILEY); global_em_info.screenbuffer = screenBitmap; } void em_open_all() { /* pre-calculate some data */ tab_generate(); progname = "emerald mine"; if (open_all() != 0) Error(ERR_EXIT, "em_open_all(): open_all() failed"); /* after "open_all()", because we need the graphic bitmaps to be defined */ tab_generate_graphics_info_em(); game_init_vars(); } void em_close_all(void) { } /* ---------------------------------------------------------------------- */ extern int screen_x; extern int screen_y; void play_element_sound(int x, int y, int sample, int element) { PlayLevelSound_EM(x, y, element, sample); } void play_sound(int x, int y, int sample) { play_element_sound(x, y, sample, -1); } void sound_play(void) { } unsigned int InitEngineRandom_EM(int seed) { if (seed == NEW_RANDOMIZE) { int simple_rnd = GetSimpleRandom(1000); int i; for (i = 0; i < simple_rnd || RandomEM == NEW_RANDOMIZE; i++) RandomEM = RandomEM * 129 + 1; seed = RandomEM; } RandomEM = seed; return (unsigned int) seed; } mirrormagic-3.0.0/src/game_em/main.c0000644000175000017500000000017613263212010016576 0ustar aeglosaeglos/* Emerald Mine * * David Tritscher * * v0.0 2000-01-06T06:43:39Z * * set everything up and close everything down */ mirrormagic-3.0.0/src/game_em/main_em.h0000644000175000017500000001041313263212010017257 0ustar aeglosaeglos#ifndef MAIN_EM_H #define MAIN_EM_H /* ========================================================================= */ /* external functions and definitions imported from main program to game_em */ /* ========================================================================= */ #include "../engines.h" /* ========================================================================= */ /* functions and definitions that are exported from game_em to main program */ /* ========================================================================= */ #include "export.h" /* ========================================================================= */ /* internal functions and definitions that are not exported to main program */ /* ========================================================================= */ #include "global.h" #include "sample.h" /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* values for native Emerald Mine game version */ #define FILE_VERSION_EM_UNKNOWN 0 #define FILE_VERSION_EM_V1 1 #define FILE_VERSION_EM_V2 2 #define FILE_VERSION_EM_V3 3 #define FILE_VERSION_EM_V4 4 /* (there really was no version 4) */ #define FILE_VERSION_EM_V5 5 #define FILE_VERSION_EM_V6 6 #define FILE_VERSION_EM_ACTUAL FILE_VERSION_EM_V6 /* level sizes and positions for EM engine */ #define WIDTH EM_MAX_CAVE_WIDTH #define HEIGHT EM_MAX_CAVE_HEIGHT /* screen sizes and positions for EM engine */ #define TILESIZE 32 extern int TILESIZE_VAR; #define TILEX TILESIZE_VAR #define TILEY TILESIZE_VAR extern int SCR_FIELDX, SCR_FIELDY; #define MAX_BUF_XSIZE (SCR_FIELDX + 2) #define MAX_BUF_YSIZE (SCR_FIELDY + 2) /* often used screen positions */ extern int SX, SY; #define SXSIZE (SCR_FIELDX * TILEX) #define SYSIZE (SCR_FIELDY * TILEY) /* other settings */ #define PLAY_ELEMENT_SOUND FALSE /* ------------------------------------------------------------------------- */ /* macro function definitions */ /* ------------------------------------------------------------------------- */ #define ROUNDED_DIVIDE(x, y) (((x) + (y) - 1) / (y)) #define SECONDS_TO_FRAMES(x) ((x) * FRAMES_PER_SECOND) #define FRAMES_TO_SECONDS(x) ((x) / FRAMES_PER_SECOND) #define SECONDS_TO_CYCLES(x) ROUNDED_DIVIDE((x) * FRAMES_PER_SECOND, 8) #define CYCLES_TO_SECONDS(x) ROUNDED_DIVIDE((x) * 8, FRAMES_PER_SECOND) #define DISPLAY_TIME(x) ROUNDED_DIVIDE(x, FRAMES_PER_SECOND) /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* exported variables */ /* ------------------------------------------------------------------------- */ extern unsigned int RandomEM; extern struct LEVEL lev; extern struct PLAYER ply[MAX_PLAYERS]; extern struct LevelInfo_EM native_em_level; extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; extern short **Boom; extern short **Cave; extern short **Next; extern short **Draw; extern struct GameInfo_EM game_em; extern unsigned char tab_blank[TILE_MAX]; extern unsigned char tab_acid[TILE_MAX]; extern unsigned char tab_amoeba[TILE_MAX]; extern unsigned char tab_android_move[TILE_MAX]; extern unsigned short tab_explode_normal[TILE_MAX]; extern unsigned short tab_explode_dynamite[TILE_MAX]; extern unsigned short map_obj[8][TILE_MAX]; extern unsigned short map_spr[2][8][SPR_MAX]; extern unsigned short map_ttl[128]; extern Bitmap *screenBitmap; extern Bitmap *scoreBitmap; extern Bitmap *objBitmap; extern Bitmap *sprBitmap; extern Bitmap *ttlBitmap; extern Bitmap *botBitmap; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ #endif /* MAIN_EM_H */ mirrormagic-3.0.0/src/game_em/sample.h0000644000175000017500000000057113263212010017137 0ustar aeglosaeglos#ifndef SAMPLE_H #define SAMPLE_H #include "main_em.h" extern void play_sound(int, int, int); extern void play_element_sound(int, int, int, int); extern char play[SAMPLE_MAX]; extern int sound_pipe[2]; extern short *sound_data[SAMPLE_MAX]; extern int sound_length[SAMPLE_MAX]; #define MIXER_MAX 4 /* maximum number of samples we can play at once */ #endif /* SAMPLE_H */ mirrormagic-3.0.0/src/game_em/graphics.c0000644000175000017500000005141713263212010017456 0ustar aeglosaeglos/* 2000-08-13T14:36:17Z * * graphics manipulation crap */ #include "main_em.h" #define MIN_SCREEN_XPOS 1 #define MIN_SCREEN_YPOS 1 #define MAX_SCREEN_XPOS MAX(1, lev.width - (SCR_FIELDX - 1)) #define MAX_SCREEN_YPOS MAX(1, lev.height - (SCR_FIELDY - 1)) #define MIN_SCREEN_X (MIN_SCREEN_XPOS * TILEX) #define MIN_SCREEN_Y (MIN_SCREEN_YPOS * TILEY) #define MAX_SCREEN_X (MAX_SCREEN_XPOS * TILEX) #define MAX_SCREEN_Y (MAX_SCREEN_YPOS * TILEY) #define VALID_SCREEN_X(x) ((x) < MIN_SCREEN_X ? MIN_SCREEN_X : \ (x) > MAX_SCREEN_X ? MAX_SCREEN_X : (x)) #define VALID_SCREEN_Y(y) ((y) < MIN_SCREEN_Y ? MIN_SCREEN_Y : \ (y) > MAX_SCREEN_Y ? MAX_SCREEN_Y : (y)) #define PLAYER_SCREEN_X(p) ((( frame) * ply[p].oldx + \ (8 - frame) * ply[p].x) * TILEX / 8 \ - ((SCR_FIELDX - 1) * TILEX) / 2) #define PLAYER_SCREEN_Y(p) ((( frame) * ply[p].oldy + \ (8 - frame) * ply[p].y) * TILEY / 8 \ - ((SCR_FIELDY - 1) * TILEY) / 2) #define USE_EXTENDED_GRAPHICS_ENGINE 1 int frame; /* current screen frame */ int screen_x, screen_y; /* current scroll position */ /* tiles currently on screen */ static int screentiles[MAX_PLAYFIELD_HEIGHT + 2][MAX_PLAYFIELD_WIDTH + 2]; static int crumbled_state[MAX_PLAYFIELD_HEIGHT + 2][MAX_PLAYFIELD_WIDTH + 2]; int getFieldbufferOffsetX_EM() { return screen_x % TILEX; } int getFieldbufferOffsetY_EM() { return screen_y % TILEY; } void BlitScreenToBitmap_EM(Bitmap *target_bitmap) { /* blit all (up to four) parts of the scroll buffer to the target bitmap */ int x = screen_x % (MAX_BUF_XSIZE * TILEX); int y = screen_y % (MAX_BUF_YSIZE * TILEY); int xsize = SXSIZE; int ysize = SYSIZE; int full_xsize = lev.width * TILEX; int full_ysize = lev.height * TILEY; int sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0); int sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0); int sxsize = (full_xsize < xsize ? full_xsize : xsize); int sysize = (full_ysize < ysize ? full_ysize : ysize); if (x < 2 * TILEX && y < 2 * TILEY) { BlitBitmap(screenBitmap, target_bitmap, x, y, sxsize, sysize, sx, sy); } else if (x < 2 * TILEX && y >= 2 * TILEY) { BlitBitmap(screenBitmap, target_bitmap, x, y, sxsize, MAX_BUF_YSIZE * TILEY - y, sx, sy); BlitBitmap(screenBitmap, target_bitmap, x, 0, sxsize, y - 2 * TILEY, sx, sy + MAX_BUF_YSIZE * TILEY - y); } else if (x >= 2 * TILEX && y < 2 * TILEY) { BlitBitmap(screenBitmap, target_bitmap, x, y, MAX_BUF_XSIZE * TILEX - x, sysize, sx, sy); BlitBitmap(screenBitmap, target_bitmap, 0, y, x - 2 * TILEX, sysize, sx + MAX_BUF_XSIZE * TILEX - x, sy); } else { BlitBitmap(screenBitmap, target_bitmap, x, y, MAX_BUF_XSIZE * TILEX - x, MAX_BUF_YSIZE * TILEY - y, sx, sy); BlitBitmap(screenBitmap, target_bitmap, 0, y, x - 2 * TILEX, MAX_BUF_YSIZE * TILEY - y, sx + MAX_BUF_XSIZE * TILEX - x, sy); BlitBitmap(screenBitmap, target_bitmap, x, 0, MAX_BUF_XSIZE * TILEX - x, y - 2 * TILEY, sx, sy + MAX_BUF_YSIZE * TILEY - y); BlitBitmap(screenBitmap, target_bitmap, 0, 0, x - 2 * TILEX, y - 2 * TILEY, sx + MAX_BUF_XSIZE * TILEX - x, sy + MAX_BUF_YSIZE * TILEY - y); } } void BackToFront_EM(void) { BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY); } static struct GraphicInfo_EM *getObjectGraphic(int x, int y) { int tile = Draw[y][x]; struct GraphicInfo_EM *g = &graphic_info_em_object[tile][frame]; if (!game.use_native_emc_graphics_engine) getGraphicSourceObjectExt_EM(g, tile, 7 - frame, x - 2, y - 2); return g; } static struct GraphicInfo_EM *getPlayerGraphic(int player_nr, int anim) { struct GraphicInfo_EM *g = &graphic_info_em_player[player_nr][anim][frame]; if (!game.use_native_emc_graphics_engine) getGraphicSourcePlayerExt_EM(g, player_nr, anim, 7 - frame); return g; } static void DrawLevelField_EM(int x, int y, int sx, int sy, boolean draw_masked) { struct GraphicInfo_EM *g = getObjectGraphic(x, y); int src_x = g->src_x + g->src_offset_x * TILESIZE_VAR / TILESIZE; int src_y = g->src_y + g->src_offset_y * TILESIZE_VAR / TILESIZE; int dst_x = sx * TILEX + g->dst_offset_x * TILESIZE_VAR / TILESIZE; int dst_y = sy * TILEY + g->dst_offset_y * TILESIZE_VAR / TILESIZE; int width = g->width * TILESIZE_VAR / TILESIZE; int height = g->height * TILESIZE_VAR / TILESIZE; int left = screen_x / TILEX; int top = screen_y / TILEY; /* do not draw fields that are outside the visible screen area */ if (x < left || x >= left + MAX_BUF_XSIZE || y < top || y >= top + MAX_BUF_YSIZE) return; if (draw_masked) { if (width > 0 && height > 0) BlitBitmapMasked(g->bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } else { if ((width != TILEX || height != TILEY) && !g->preserve_background) ClearRectangle(screenBitmap, sx * TILEX, sy * TILEY, TILEX, TILEY); if (width > 0 && height > 0) BlitBitmap(g->bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } } static void DrawLevelFieldCrumbled_EM(int x, int y, int sx, int sy, int crm, boolean draw_masked) { struct GraphicInfo_EM *g; int crumbled_border_size; int left = screen_x / TILEX; int top = screen_y / TILEY; int i; /* do not draw fields that are outside the visible screen area */ if (x < left || x >= left + MAX_BUF_XSIZE || y < top || y >= top + MAX_BUF_YSIZE) return; if (crm == 0) /* no crumbled edges for this tile */ return; g = getObjectGraphic(x, y); crumbled_border_size = g->crumbled_border_size * TILESIZE_VAR / g->crumbled_tile_size; for (i = 0; i < 4; i++) { if (crm & (1 << i)) { int width, height, cx, cy; if (i == 1 || i == 2) { width = crumbled_border_size; height = TILEY; cx = (i == 2 ? TILEX - crumbled_border_size : 0); cy = 0; } else { width = TILEX; height = crumbled_border_size; cx = 0; cy = (i == 3 ? TILEY - crumbled_border_size : 0); } if (width > 0 && height > 0) { int src_x = g->crumbled_src_x + cx; int src_y = g->crumbled_src_y + cy; int dst_x = sx * TILEX + cx; int dst_y = sy * TILEY + cy; if (draw_masked) BlitBitmapMasked(g->crumbled_bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); else BlitBitmap(g->crumbled_bitmap, screenBitmap, src_x, src_y, width, height, dst_x, dst_y); } } } } static void DrawLevelPlayer_EM(int x1, int y1, int player_nr, int anim, boolean draw_masked) { struct GraphicInfo_EM *g = getPlayerGraphic(player_nr, anim); int src_x = g->src_x, src_y = g->src_y; int dst_x, dst_y; /* do not draw fields that are outside the visible screen area */ if (x1 < screen_x - TILEX || x1 >= screen_x + MAX_BUF_XSIZE * TILEX || y1 < screen_y - TILEY || y1 >= screen_y + MAX_BUF_YSIZE * TILEY) return; x1 %= MAX_BUF_XSIZE * TILEX; y1 %= MAX_BUF_YSIZE * TILEY; if (draw_masked) { /* draw the player to current location */ dst_x = x1; dst_y = y1; BlitBitmapMasked(g->bitmap, screenBitmap, src_x, src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around column */ dst_x = x1 - MAX_BUF_XSIZE * TILEX; dst_y = y1; BlitBitmapMasked(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around row */ dst_x = x1; dst_y = y1 - MAX_BUF_YSIZE * TILEY; BlitBitmapMasked(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); } else { /* draw the player to current location */ dst_x = x1; dst_y = y1; BlitBitmap(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around column */ dst_x = x1 - MAX_BUF_XSIZE * TILEX; dst_y = y1; BlitBitmap(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); /* draw the player to opposite wrap-around row */ dst_x = x1; dst_y = y1 - MAX_BUF_YSIZE * TILEY; BlitBitmap(g->bitmap, screenBitmap, g->src_x, g->src_y, TILEX, TILEY, dst_x, dst_y); } } /* draw differences between game tiles and screen tiles * * implicitly handles scrolling and restoring background under the sprites */ static void animscreen(void) { int x, y, i; int left = screen_x / TILEX; int top = screen_y / TILEY; static int xy[4][2] = { { 0, -1 }, { -1, 0 }, { +1, 0 }, { 0, +1 } }; if (!game.use_native_emc_graphics_engine) for (y = 2; y < EM_MAX_CAVE_HEIGHT - 2; y++) for (x = 2; x < EM_MAX_CAVE_WIDTH - 2; x++) SetGfxAnimation_EM(&graphic_info_em_object[Draw[y][x]][frame], Draw[y][x], 7 - frame, x - 2, y - 2); for (y = top; y < top + MAX_BUF_YSIZE; y++) { for (x = left; x < left + MAX_BUF_XSIZE; x++) { int sx = x % MAX_BUF_XSIZE; int sy = y % MAX_BUF_YSIZE; int tile = Draw[y][x]; struct GraphicInfo_EM *g = &graphic_info_em_object[tile][frame]; int obj = g->unique_identifier; int crm = 0; boolean redraw_screen_tile = FALSE; /* re-calculate crumbled state of this tile */ if (g->has_crumbled_graphics) { for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; int tile_next; if (xx < 0 || xx >= EM_MAX_CAVE_WIDTH || yy < 0 || yy >= EM_MAX_CAVE_HEIGHT) continue; tile_next = Draw[yy][xx]; if (!graphic_info_em_object[tile_next][frame].has_crumbled_graphics) crm |= (1 << i); } } redraw_screen_tile = (screentiles[sy][sx] != obj || crumbled_state[sy][sx] != crm); /* only redraw screen tiles if they (or their crumbled state) changed */ if (redraw_screen_tile) { DrawLevelField_EM(x, y, sx, sy, FALSE); DrawLevelFieldCrumbled_EM(x, y, sx, sy, crm, FALSE); screentiles[sy][sx] = obj; crumbled_state[sy][sx] = crm; } } } } /* blit players to the screen * * handles transparency and movement */ static void blitplayer(struct PLAYER *ply) { int x1, y1, x2, y2; if (!ply->alive) return; /* x1/y1 are left/top and x2/y2 are right/down part of the player movement */ x1 = (frame * ply->oldx + (8 - frame) * ply->x) * TILEX / 8; y1 = (frame * ply->oldy + (8 - frame) * ply->y) * TILEY / 8; x2 = x1 + TILEX - 1; y2 = y1 + TILEY - 1; if ((int)(x2 - screen_x) < ((MAX_BUF_XSIZE - 1) * TILEX - 1) && (int)(y2 - screen_y) < ((MAX_BUF_YSIZE - 1) * TILEY - 1)) { /* some casts to "int" are needed because of negative calculation values */ int dx = (int)ply->x - (int)ply->oldx; int dy = (int)ply->y - (int)ply->oldy; int old_x = (int)ply->oldx + (7 - (int)frame) * dx / 8; int old_y = (int)ply->oldy + (7 - (int)frame) * dy / 8; int new_x = old_x + SIGN(dx); int new_y = old_y + SIGN(dy); int old_sx = old_x % MAX_BUF_XSIZE; int old_sy = old_y % MAX_BUF_YSIZE; int new_sx = new_x % MAX_BUF_XSIZE; int new_sy = new_y % MAX_BUF_YSIZE; int new_crm = crumbled_state[new_sy][new_sx]; /* only diggable elements can be crumbled in the classic EM engine */ boolean player_is_digging = (new_crm != 0); if (player_is_digging) { /* draw the field the player is moving to (under the player) */ DrawLevelField_EM(new_x, new_y, new_sx, new_sy, FALSE); DrawLevelFieldCrumbled_EM(new_x, new_y, new_sx, new_sy, new_crm, FALSE); /* draw the player (masked) over the element he is just digging away */ DrawLevelPlayer_EM(x1, y1, ply->num, ply->anim, TRUE); /* draw the field the player is moving from (masked over the player) */ DrawLevelField_EM(old_x, old_y, old_sx, old_sy, TRUE); } else { /* draw the player under the element which is on the same field */ DrawLevelPlayer_EM(x1, y1, ply->num, ply->anim, FALSE); /* draw the field the player is moving from (masked over the player) */ DrawLevelField_EM(old_x, old_y, old_sx, old_sy, TRUE); /* draw the field the player is moving to (masked over the player) */ DrawLevelField_EM(new_x, new_y, new_sx, new_sy, TRUE); } /* redraw screen tiles in the next frame (player may have left the tiles) */ screentiles[old_sy][old_sx] = -1; screentiles[new_sy][new_sx] = -1; } } void game_initscreen(void) { int player_nr; int x,y; frame = 6; player_nr = (game.centered_player_nr != -1 ? game.centered_player_nr : 0); screen_x = VALID_SCREEN_X(PLAYER_SCREEN_X(player_nr)); screen_y = VALID_SCREEN_Y(PLAYER_SCREEN_Y(player_nr)); for (y = 0; y < MAX_BUF_YSIZE; y++) { for (x = 0; x < MAX_BUF_XSIZE; x++) { screentiles[y][x] = -1; crumbled_state[y][x] = 0; } } } static int getMaxCenterDistancePlayerNr(int center_x, int center_y) { int max_dx = 0, max_dy = 0; int player_nr = game_em.last_moving_player; int i; for (i = 0; i < MAX_PLAYERS; i++) { if (ply[i].alive) { int sx = PLAYER_SCREEN_X(i); int sy = PLAYER_SCREEN_Y(i); if (game_em.last_player_direction[i] != MV_NONE && (ABS(sx - center_x) > max_dx || ABS(sy - center_y) > max_dy)) { max_dx = MAX(max_dx, ABS(sx - center_x)); max_dy = MAX(max_dy, ABS(sy - center_y)); player_nr = i; } } } return player_nr; } static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2) { boolean num_checked_players = 0; int i; for (i = 0; i < MAX_PLAYERS; i++) { if (ply[i].alive) { int sx = PLAYER_SCREEN_X(i); int sy = PLAYER_SCREEN_Y(i); if (num_checked_players == 0) { *sx1 = *sx2 = sx; *sy1 = *sy2 = sy; } else { *sx1 = MIN(*sx1, sx); *sy1 = MIN(*sy1, sy); *sx2 = MAX(*sx2, sx); *sy2 = MAX(*sy2, sy); } num_checked_players++; } } } boolean checkIfAllPlayersFitToScreen() { int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); return (sx2 - sx1 <= SCR_FIELDX * TILEX && sy2 - sy1 <= SCR_FIELDY * TILEY); } static void setScreenCenteredToAllPlayers(int *sx, int *sy) { int sx1 = screen_x, sy1 = screen_y, sx2 = screen_x, sy2 = screen_y; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); *sx = (sx1 + sx2) / 2; *sy = (sy1 + sy2) / 2; } static void setMaxCenterDistanceForAllPlayers(int *max_dx, int *max_dy, int center_x, int center_y) { int sx1 = center_x, sy1 = center_y, sx2 = center_x, sy2 = center_y; setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2); *max_dx = MAX(ABS(sx1 - center_x), ABS(sx2 - center_x)); *max_dy = MAX(ABS(sy1 - center_y), ABS(sy2 - center_y)); } static boolean checkIfAllPlayersAreVisible(int center_x, int center_y) { int max_dx, max_dy; setMaxCenterDistanceForAllPlayers(&max_dx, &max_dy, center_x, center_y); return (max_dx <= SCR_FIELDX * TILEX / 2 && max_dy <= SCR_FIELDY * TILEY / 2); } void RedrawPlayfield_EM(boolean force_redraw) { boolean draw_new_player_location = FALSE; boolean quick_relocation = setup.quick_switch; int max_center_distance_player_nr = getMaxCenterDistancePlayerNr(screen_x, screen_y); int stepsize = TILEX / 8; int offset = game.scroll_delay_value * TILEX; int offset_x = offset; int offset_y = offset; int screen_x_old = screen_x; int screen_y_old = screen_y; int x, y, sx, sy; int i; if (game.set_centered_player) { boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen(); /* switching to "all players" only possible if all players fit to screen */ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } /* do not switch focus to non-existing (or non-active) player */ if (game.centered_player_nr_next >= 0 && !ply[game.centered_player_nr_next].alive) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } } /* also allow focus switching when screen is scrolled to half tile */ if (game.set_centered_player) { game.centered_player_nr = game.centered_player_nr_next; draw_new_player_location = TRUE; force_redraw = TRUE; game.set_centered_player = FALSE; } if (game.centered_player_nr == -1) { if (draw_new_player_location || offset == 0) { setScreenCenteredToAllPlayers(&sx, &sy); } else { sx = PLAYER_SCREEN_X(max_center_distance_player_nr); sy = PLAYER_SCREEN_Y(max_center_distance_player_nr); } } else { sx = PLAYER_SCREEN_X(game.centered_player_nr); sy = PLAYER_SCREEN_Y(game.centered_player_nr); } if (draw_new_player_location && quick_relocation) { screen_x = VALID_SCREEN_X(sx); screen_y = VALID_SCREEN_Y(sy); screen_x_old = screen_x; screen_y_old = screen_y; } if (draw_new_player_location && !quick_relocation) { unsigned int game_frame_delay_value = getGameFrameDelay_EM(20); int wait_delay_value = game_frame_delay_value; int screen_xx = VALID_SCREEN_X(sx); int screen_yy = VALID_SCREEN_Y(sy); while (screen_x != screen_xx || screen_y != screen_yy) { int dx = (screen_xx < screen_x ? +1 : screen_xx > screen_x ? -1 : 0); int dy = (screen_yy < screen_y ? +1 : screen_yy > screen_y ? -1 : 0); int dxx = 0, dyy = 0; if (dx == 0 && dy == 0) /* no scrolling needed at all */ break; if (ABS(screen_xx - screen_x) >= TILEX) { screen_x -= dx * TILEX; dxx = dx * TILEX / 2; } else { screen_x = screen_xx; dxx = 0; } if (ABS(screen_yy - screen_y) >= TILEY) { screen_y -= dy * TILEY; dyy = dy * TILEY / 2; } else { screen_y = screen_yy; dyy = 0; } /* scroll in two steps of half tile size to make things smoother */ screen_x += dxx; screen_y += dyy; animscreen(); for (i = 0; i < MAX_PLAYERS; i++) blitplayer(&ply[i]); BlitScreenToBitmap_EM(backbuffer); BackToFront_EM(); Delay(wait_delay_value); /* scroll second step to align at full tile size */ screen_x -= dxx; screen_y -= dyy; animscreen(); for (i = 0; i < MAX_PLAYERS; i++) blitplayer(&ply[i]); BlitScreenToBitmap_EM(backbuffer); BackToFront_EM(); Delay(wait_delay_value); } screen_x_old = screen_x; screen_y_old = screen_y; } if (force_redraw) { for (y = 0; y < MAX_BUF_YSIZE; y++) { for (x = 0; x < MAX_BUF_XSIZE; x++) { screentiles[y][x] = -1; crumbled_state[y][x] = 0; } } } /* calculate new screen scrolling position, with regard to scroll delay */ screen_x = VALID_SCREEN_X(sx + offset_x < screen_x ? sx + offset_x : sx - offset_x > screen_x ? sx - offset_x : screen_x); screen_y = VALID_SCREEN_Y(sy + offset_y < screen_y ? sy + offset_y : sy - offset_y > screen_y ? sy - offset_y : screen_y); /* prevent scrolling further than double player step size when scrolling */ if (ABS(screen_x - screen_x_old) > 2 * stepsize) { int dx = SIGN(screen_x - screen_x_old); screen_x = screen_x_old + dx * 2 * stepsize; } if (ABS(screen_y - screen_y_old) > 2 * stepsize) { int dy = SIGN(screen_y - screen_y_old); screen_y = screen_y_old + dy * 2 * stepsize; } /* prevent scrolling away from the other players when focus on all players */ if (game.centered_player_nr == -1) { /* check if all players are still visible with new scrolling position */ if (checkIfAllPlayersAreVisible(screen_x_old, screen_y_old) && !checkIfAllPlayersAreVisible(screen_x, screen_y)) { /* reset horizontal scroll position to last value, if needed */ if (!checkIfAllPlayersAreVisible(screen_x, screen_y_old)) screen_x = screen_x_old; /* reset vertical scroll position to last value, if needed */ if (!checkIfAllPlayersAreVisible(screen_x_old, screen_y)) screen_y = screen_y_old; } } /* prevent scrolling (for screen correcting) if no player is moving */ if (!game_em.any_player_moving) { screen_x = screen_x_old; screen_y = screen_y_old; } else { /* prevent scrolling against the players move direction */ int player_nr = (game.centered_player_nr == -1 ? max_center_distance_player_nr : game.centered_player_nr); int player_move_dir = game_em.last_player_direction[player_nr]; int dx = SIGN(screen_x - screen_x_old); int dy = SIGN(screen_y - screen_y_old); if ((dx < 0 && player_move_dir != MV_LEFT) || (dx > 0 && player_move_dir != MV_RIGHT)) screen_x = screen_x_old; if ((dy < 0 && player_move_dir != MV_UP) || (dy > 0 && player_move_dir != MV_DOWN)) screen_y = screen_y_old; } // skip redrawing playfield in warp mode or when testing tapes with "autotest" if (DrawingDeactivatedField()) return; animscreen(); for (i = 0; i < MAX_PLAYERS; i++) blitplayer(&ply[i]); } mirrormagic-3.0.0/src/game_em/synchro_1.c0000644000175000017500000006070113263212010017557 0ustar aeglosaeglos/* first part of synchro. * * game logic for players. * * large switch statement for tiles the player interacts with. */ #include "main_em.h" #define USE_CHANGED_ACID_STUFF 1 extern boolean checkIfAllPlayersFitToScreen(); static void check_player(struct PLAYER *); static void kill_player(struct PLAYER *); static boolean player_digfield(struct PLAYER *, int, int); static boolean player_killed(struct PLAYER *); void synchro_1(void) { int start_check_nr; int i; game_em.any_player_moving = FALSE; game_em.any_player_snapping = FALSE; /* must test for death and actually kill separately */ for (i = 0; i < MAX_PLAYERS; i++) { boolean ply_kill = player_killed(&ply[i]); if (ply[i].alive && ply_kill) kill_player(&ply[i]); } for (i = 0; i < MAX_PLAYERS; i++) { ply[i].oldx = ply[i].x; ply[i].oldy = ply[i].y; ply[i].anim = SPR_still; } start_check_nr = (RandomEM & 128 ? 0 : 1) * 2 + (RandomEM & 256 ? 0 : 1); for (i = 0; i < MAX_PLAYERS; i++) { int check_nr = (start_check_nr + i) % MAX_PLAYERS; if (ply[check_nr].alive) check_player(&ply[check_nr]); } for (i = 0; i < MAX_PLAYERS; i++) { if (!ply[i].alive) continue; if (Cave[ply[i].oldy][ply[i].oldx] == Zplayer) { Cave[ply[i].oldy][ply[i].oldx] = Xblank; Next[ply[i].oldy][ply[i].oldx] = Xblank; } if (Cave[ply[i].y][ply[i].x] == Xblank) { Cave[ply[i].y][ply[i].x] = Zplayer; Next[ply[i].y][ply[i].x] = Zplayer; } } } static boolean player_killed(struct PLAYER *ply) { int x = ply->x; int y = ply->y; if (!ply->alive) return FALSE; if (lev.killed_out_of_time && setup.time_limit) return TRUE; switch(Cave[y-1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y][x+1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y+1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y][x-1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: return TRUE; } switch(Cave[y][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: case Xdynamite_1: case Xdynamite_2: case Xdynamite_3: case Xdynamite_4: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif return FALSE; } return TRUE; } static void kill_player(struct PLAYER *ply) { int x = ply->x; int y = ply->y; ply->alive = 0; switch(Cave[y-1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y-1][x] = Xboom_bug; break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y-1][x] = Xboom_bomb; break; } switch(Cave[y][x+1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x+1] = Xboom_bug; break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x+1] = Xboom_bomb; break; } switch(Cave[y+1][x]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y+1][x] = Xboom_bug; break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y+1][x] = Xboom_bomb; break; } switch(Cave[y][x-1]) { case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x-1] = Xboom_bug; break; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x-1] = Xboom_bomb; break; } switch(Cave[y][x]) { case Xexit_1: case Xexit_2: case Xexit_3: lev.exit_x = x; lev.exit_y = y; play_element_sound(x, y, SAMPLE_exit_leave, Xexit_1); break; default: play_element_sound(x, y, SAMPLE_die, Zplayer); break; } switch(Cave[y][x]) { #if USE_CHANGED_ACID_STUFF case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: break; #endif default: Cave[y][x] = Xboom_1; Boom[y][x] = Xblank; break; } } static void check_player(struct PLAYER *ply) { int oldx = ply->x; int oldy = ply->y; int x = oldx; int y = oldy; int dx = 0, dy = 0; game_em.last_player_direction[ply->num] = MV_NONE; if (ply->joy_w) /* west */ { x--; dx = -1; } else if (ply->joy_e) /* east */ { x++; dx = 1; } if (ply->joy_n) /* north */ { y--; dy = -1; } else if (ply->joy_s) /* south */ { y++; dy = 1; } if (dx || dy) { int oldx = ply->x; int oldy = ply->y; int x = oldx + dx; int y = oldy + dy; boolean players_visible_before_move; boolean players_visible_after_move; boolean can_move; players_visible_before_move = checkIfAllPlayersFitToScreen(); ply->x = x; ply->y = y; players_visible_after_move = checkIfAllPlayersFitToScreen(); /* player is allowed to move only in the following cases: - it is not needed to display all players (not focussed to all players) - all players are (still or again) visible after the move - some players were already outside visible screen area before the move */ can_move = (game.centered_player_nr != -1 || players_visible_after_move || !players_visible_before_move); ply->x = oldx; ply->y = oldy; if (!can_move) { ply->joy_n = ply->joy_e = ply->joy_s = ply->joy_w = 0; return; } } if (dx == 0 && dy == 0) { ply->joy_stick = 0; if (ply->joy_drop) { if (++ply->dynamite_cnt == 5 && ply->dynamite) { Cave[y][x] = Xdynamite_1; play_element_sound(x, y, SAMPLE_dynamite, Xdynamite_1); ply->dynamite--; } } else { ply->dynamite_cnt = 0; } RandomEM += 7; /* be a bit more random if the player doesn't move */ return; } ply->joy_stick = 1; ply->joy_n = ply->joy_e = ply->joy_s = ply->joy_w = 0; ply->dynamite_cnt = 0; /* reset dynamite timer if we move */ ply->joy_spin = !ply->joy_spin; if (ply->joy_snap == 0) /* player wants to move */ { boolean moved = FALSE; if (ply->last_move_dir & MV_HORIZONTAL) { if (!(moved = player_digfield(ply, 0, dy))) moved = player_digfield(ply, dx, 0); } else { if (!(moved = player_digfield(ply, dx, 0))) moved = player_digfield(ply, 0, dy); } if (moved) { if (oldx != ply->x) ply->last_move_dir = (dx < 0 ? MV_LEFT : MV_RIGHT); else if (oldy != ply->y) ply->last_move_dir = (dy < 0 ? MV_UP : MV_DOWN); game_em.any_player_moving = TRUE; game_em.last_moving_player = ply->num; game_em.last_player_direction[ply->num] = ply->last_move_dir; } } else /* player wants to snap */ { game_em.any_player_snapping = player_digfield(ply, dx, dy); } } static boolean player_digfield(struct PLAYER *ply, int dx, int dy) { int anim = (dx < 0 ? 3 : dx > 0 ? 1 : dy < 0 ? 0 : dy > 0 ? 2 : 2); int oldx = ply->x; int oldy = ply->y; int x = oldx + dx; int y = oldy + dy; boolean result = TRUE; if (!dx && !dy) /* no direction specified */ return FALSE; if (dx && dy && ply->joy_snap) /* more than one direction specified */ return FALSE; if (ply->joy_snap == 0) /* player wants to move */ { int element = Cave[y][x]; switch(Cave[y][x]) { /* fire is released */ case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Zplayer; Next[y][x] = Zplayer; #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif play_element_sound(x, y, SAMPLE_blank, Xblank); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; #if USE_CHANGED_ACID_STUFF case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+1] == Xblank) Cave[y-1][x+1] = Yacid_splash_eB; if (Cave[y-1][x-1] == Xblank) Cave[y-1][x-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); #endif case Xboom_android: case Xboom_1: case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: #if !USE_CHANGED_ACID_STUFF case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: #endif ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xgrass: Cave[y][x] = (dy ? (dy < 0 ? Ygrass_nB : Ygrass_sB) : (dx > 0 ? Ygrass_eB : Ygrass_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_dirt, Xgrass); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xdirt: Cave[y][x] = (dy ? (dy < 0 ? Ydirt_nB : Ydirt_sB) : (dx > 0 ? Ydirt_eB : Ydirt_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_dirt, Xdirt); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xdiamond: case Xdiamond_pause: Cave[y][x] = Ydiamond_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.diamond_score; lev.required = lev.required < 3 ? 0 : lev.required - 3; game.snapshot.collected_item = TRUE; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xemerald: case Xemerald_pause: Cave[y][x] = Yemerald_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.emerald_score; lev.required = lev.required < 1 ? 0 : lev.required - 1; game.snapshot.collected_item = TRUE; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xdynamite: Cave[y][x] = Ydynamite_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.dynamite_score; ply->dynamite = ply->dynamite > 9998 ? 9999 : ply->dynamite + 1; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xkey_1: ply->keys |= 0x01; Cave[y][x] = Ykey_1_eat; goto key_walk; case Xkey_2: ply->keys |= 0x02; Cave[y][x] = Ykey_2_eat; goto key_walk; case Xkey_3: ply->keys |= 0x04; Cave[y][x] = Ykey_3_eat; goto key_walk; case Xkey_4: ply->keys |= 0x08; Cave[y][x] = Ykey_4_eat; goto key_walk; case Xkey_5: ply->keys |= 0x10; Cave[y][x] = Ykey_5_eat; goto key_walk; case Xkey_6: ply->keys |= 0x20; Cave[y][x] = Ykey_6_eat; goto key_walk; case Xkey_7: ply->keys |= 0x40; Cave[y][x] = Ykey_7_eat; goto key_walk; case Xkey_8: ply->keys |= 0x80; Cave[y][x] = Ykey_8_eat; goto key_walk; key_walk: Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.key_score; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xlenses: Cave[y][x] = Ylenses_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.lenses_score; lev.lenses_cnt = lev.lenses_time; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xmagnify: Cave[y][x] = Ymagnify_eat; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.magnify_score; lev.magnify_cnt = lev.magnify_time; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xstone: if (dy) break; switch(Cave[y][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto stone_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Ystone_e : Ystone_w; Next[y][x+dx] = Xstone_pause; stone_walk: Cave[y][x] = dx > 0 ? Ystone_eB : Ystone_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xstone); ply->x = x; } ply->anim = SPR_push + anim; break; case Xbomb: if (dy) break; switch(Cave[y][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto bomb_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Ybomb_e : Ybomb_w; Next[y][x+dx] = Xbomb_pause; bomb_walk: Cave[y][x] = dx > 0 ? Ybomb_eB : Ybomb_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xbomb); ply->x = x; } ply->anim = SPR_push + anim; break; case Xnut: if (dy) break; switch(Cave[y][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto nut_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Ynut_e : Ynut_w; Next[y][x+dx] = Xnut_pause; nut_walk: Cave[y][x] = dx > 0 ? Ynut_eB : Ynut_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xnut); ply->x = x; } ply->anim = SPR_push + anim; break; case Xspring: if (dy) break; switch(Cave[y][x+dx]) { case Xalien: case Xalien_pause: Cave[y][x] = dx > 0 ? Yspring_kill_eB : Yspring_kill_wB; Cave[y][x+dx] = dx > 0 ? Yspring_kill_e : Yspring_kill_w; Next[y][x] = Zplayer; Next[y][x+dx] = dx > 0 ? Xspring_e : Xspring_w; play_element_sound(x, y, SAMPLE_slurp, Xalien); lev.score += lev.slurp_score; ply->x = x; break; case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y-1][x+dx+1] == Xblank) Cave[y-1][x+dx+1] = Yacid_splash_eB; if (Cave[y-1][x+dx-1] == Xblank) Cave[y-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto spring_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x+dx] = dx > 0 ? Yspring_e : Yspring_w; Next[y][x+dx] = dx > 0 ? Xspring_e : Xspring_w; spring_walk: Cave[y][x] = dx > 0 ? Yspring_eB : Yspring_wB; Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_roll, Xspring); ply->x = x; } ply->anim = SPR_push + anim; break; case Xspring_pause: case Xstone_pause: case Xbomb_pause: case Xnut_pause: case Xsand_stonein_1: case Xsand_stonein_2: case Xsand_stonein_3: case Xsand_stonein_4: if (dy) break; ply->anim = SPR_push + anim; break; case Xballoon: switch(Cave[y+dy][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y+dy-1][x+dx+1] == Xblank) Cave[y+dy-1][x+dx+1] = Yacid_splash_eB; if (Cave[y+dy-1][x+dx-1] == Xblank) Cave[y+dy-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto balloon_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y+dy][x+dx] = (dy ? (dy < 0 ? Yballoon_n : Yballoon_s) : (dx > 0 ? Yballoon_e : Yballoon_w)); Next[y+dy][x+dx] = Xballoon; balloon_walk: Cave[y][x] = (dy ? (dy < 0 ? Yballoon_nB : Yballoon_sB) : (dx > 0 ? Yballoon_eB : Yballoon_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_push, Xballoon); ply->x = x; ply->y = y; } ply->anim = SPR_push + anim; break; case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: switch(Cave[y+dy][x+dx]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: if (Cave[y+dy-1][x+dx+1] == Xblank) Cave[y+dy-1][x+dx+1] = Yacid_splash_eB; if (Cave[y+dy-1][x+dx-1] == Xblank) Cave[y+dy-1][x+dx-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto android_walk; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y+dy][x+dx] = (dy ? (dy < 0 ? Yandroid_n : Yandroid_s) : (dx > 0 ? Yandroid_e : Yandroid_w)); Next[y+dy][x+dx] = (dy ? (dy < 0 ? Xandroid_2_n : Xandroid_2_s) : (dx > 0 ? Xandroid_2_e : Xandroid_2_w)); android_walk: Cave[y][x] = (dy ? (dy < 0 ? Yandroid_nB : Yandroid_sB) : (dx > 0 ? Yandroid_eB : Yandroid_wB)); Next[y][x] = Zplayer; play_element_sound(x, y, SAMPLE_push, Xandroid); ply->x = x; ply->y = y; } ply->anim = SPR_push + anim; break; case Xdoor_1: case Xfake_door_1: if (ply->keys & 0x01) goto door_walk; else break; case Xdoor_2: case Xfake_door_2: if (ply->keys & 0x02) goto door_walk; else break; case Xdoor_3: case Xfake_door_3: if (ply->keys & 0x04) goto door_walk; else break; case Xdoor_4: case Xfake_door_4: if (ply->keys & 0x08) goto door_walk; else break; case Xdoor_5: case Xfake_door_5: if (ply->keys & 0x10) goto door_walk; else break; case Xdoor_6: case Xfake_door_6: if (ply->keys & 0x20) goto door_walk; else break; case Xdoor_7: case Xfake_door_7: if (ply->keys & 0x40) goto door_walk; else break; case Xdoor_8: case Xfake_door_8: if (ply->keys & 0x80) goto door_walk; else break; door_walk: if (!tab_blank[Cave[y+dy][x+dx]]) break; Cave[y+dy][x+dx] = Zplayer; Next[y+dy][x+dx] = Zplayer; play_element_sound(x, y, SAMPLE_door, element); ply->anim = SPR_walk + anim; ply->x = x + dx; ply->y = y + dy; break; case Xwheel: play_element_sound(x, y, SAMPLE_press, element); lev.wheel_cnt = lev.wheel_time; lev.wheel_x = x; lev.wheel_y = y; break; case Xwind_n: lev.wind_direction = 0; goto wind_walk; case Xwind_e: lev.wind_direction = 1; goto wind_walk; case Xwind_s: lev.wind_direction = 2; goto wind_walk; case Xwind_w: lev.wind_direction = 3; goto wind_walk; case Xwind_nesw: lev.wind_direction = dy ? (dy < 0 ? 0 : 2) : (dx > 0 ? 1 : 3); goto wind_walk; wind_walk: play_element_sound(x, y, SAMPLE_press, element); lev.wind_cnt = lev.wind_time; break; case Xwind_stop: play_element_sound(x, y, SAMPLE_press, element); lev.wind_cnt = 0; break; case Xswitch: play_element_sound(x, y, SAMPLE_press, element); lev.ball_cnt = lev.ball_time; lev.ball_state = !lev.ball_state; break; case Xplant: Cave[y][x] = Yplant; Next[y][x] = Xplant; play_element_sound(x, y, SAMPLE_blank, Xplant); ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; case Xexit_1: case Xexit_2: case Xexit_3: lev.home--; ply->anim = SPR_walk + anim; ply->x = x; ply->y = y; break; } if (ply->x == oldx && ply->y == oldy) /* no movement */ result = FALSE; } else /* player wants to snap */ { int element = Cave[y][x]; switch(Cave[y][x]) { /* fire is pressed */ case Xgrass: Cave[y][x] = Ygrass_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_dirt, element); ply->anim = SPR_spray + anim; break; case Xdirt: Cave[y][x] = Ydirt_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_dirt, element); ply->anim = SPR_spray + anim; break; case Xdiamond: case Xdiamond_pause: Cave[y][x] = Ydiamond_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.diamond_score; lev.required = lev.required < 3 ? 0 : lev.required - 3; game.snapshot.collected_item = TRUE; ply->anim = SPR_walk + anim; break; case Xemerald: case Xemerald_pause: Cave[y][x] = Yemerald_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.emerald_score; lev.required = lev.required < 1 ? 0 : lev.required - 1; game.snapshot.collected_item = TRUE; ply->anim = SPR_walk + anim; break; case Xdynamite: Cave[y][x] = Ydynamite_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.dynamite_score; ply->dynamite = ply->dynamite > 9998 ? 9999 : ply->dynamite + 1; ply->anim = SPR_walk + anim; break; case Xkey_1: ply->keys |= 0x01; Cave[y][x] = Ykey_1_eat; goto key_shoot; case Xkey_2: ply->keys |= 0x02; Cave[y][x] = Ykey_2_eat; goto key_shoot; case Xkey_3: ply->keys |= 0x04; Cave[y][x] = Ykey_3_eat; goto key_shoot; case Xkey_4: ply->keys |= 0x08; Cave[y][x] = Ykey_4_eat; goto key_shoot; case Xkey_5: ply->keys |= 0x10; Cave[y][x] = Ykey_5_eat; goto key_shoot; case Xkey_6: ply->keys |= 0x20; Cave[y][x] = Ykey_6_eat; goto key_shoot; case Xkey_7: ply->keys |= 0x40; Cave[y][x] = Ykey_7_eat; goto key_shoot; case Xkey_8: ply->keys |= 0x80; Cave[y][x] = Ykey_8_eat; goto key_shoot; key_shoot: Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.key_score; ply->anim = SPR_walk + anim; break; case Xlenses: Cave[y][x] = Ylenses_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.lenses_score; lev.lenses_cnt = lev.lenses_time; ply->anim = SPR_walk + anim; break; case Xmagnify: Cave[y][x] = Ymagnify_eat; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_collect, element); lev.score += lev.magnify_score; lev.magnify_cnt = lev.magnify_time; ply->anim = SPR_walk + anim; break; default: result = FALSE; } } return result; } mirrormagic-3.0.0/src/game_em/tab_generate.c0000644000175000017500000020324313263212010020272 0ustar aeglosaeglos/* 2000-04-19T13:26:05Z * * construct some tables to be included directly in emerald mine source. * i made this because dynamically building the tables every time sucks and i * need to be able to easily modify tile.h. * * this is key data which almost everything depends on. * * this is supposed to be fairly easy to read and modify. the tab values * are still hard coded constants but that should be less of a problem to * modify. */ #include "main_em.h" /* ------------------------------------------------------------------------- */ /* 0=stop 1=blank */ int tile_blank[] = { Xblank, 1, Yacid_splash_eB, 1, Yacid_splash_wB, 1, TILE_MAX }; /* 0=stop 1=acid */ int tile_acid[] = { Xblank, 1, Yacid_splash_eB, 1, Yacid_splash_wB, 1, Xacid_1, 1, Xacid_2, 1, Xacid_3, 1, Xacid_4, 1, Xacid_5, 1, Xacid_6, 1, Xacid_7, 1, Xacid_8, 1, TILE_MAX }; /* 0=stop 1=amoeba */ int tile_amoeba[] = { Xdripper, 1, XdripperB, 1, Xamoeba_1, 1, Xamoeba_2, 1, Xamoeba_3, 1, Xamoeba_4, 1, Xamoeba_5, 1, Xamoeba_6, 1, Xamoeba_7, 1, Xamoeba_8, 1, TILE_MAX }; /* 0=stop 1=move */ int tile_android_move[] = { Xblank, 1, Yacid_splash_eB, 1, Yacid_splash_wB, 1, Xplant, 1, TILE_MAX }; /* ------------------------------------------------------------------------- */ /* explosions: special format */ /* everything is initially filled with Xboom_1 */ int tile_explode[] = { ZBORDER, Znormal, Zdynamite, Xboom_bug, Xboom_bomb, Xboom_android, Xandroid, Xandroid_1_n, Xandroid_2_n, Xandroid_1_e, Xandroid_2_e, Xandroid_1_s, Xandroid_2_s, Xandroid_1_w, Xandroid_2_w, Xacid_ne, Xacid_nw, Xacid_s, Xacid_se, Xacid_sw, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xplant, Yplant, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, Xsteel_1, Xsteel_2, Xsteel_3, Xsteel_4, TILE_MAX, /* up till here are indestructable */ Xbug_n, Xboom_bug, Xbug_e, Xboom_bug, Xbug_s, Xboom_bug, Xbug_w, Xboom_bug, Xbug_gon, Xboom_bug, Xbug_goe, Xboom_bug, Xbug_gos, Xboom_bug, Xbug_gow, Xboom_bug, Xbomb, Xboom_bomb, Xbomb_pause, Xboom_bomb, Xbomb_fall, Xboom_bomb, TILE_MAX, /* up till here are special explosions */ Xandroid, Xboom_android, Xandroid_1_n, Xboom_android, Xandroid_2_n, Xboom_android, Xandroid_1_e, Xboom_android, Xandroid_2_e, Xboom_android, Xandroid_1_s, Xboom_android, Xandroid_2_s, Xboom_android, Xandroid_1_w, Xboom_android, Xandroid_2_w, Xboom_android, TILE_MAX /* up until here are dynamite explosions */ }; /* ------------------------------------------------------------------------- */ /* map the graphics file to internal tiles and animations * * one graphics icon maps to many tiles and animations */ int obj_map[] = { /* special */ Ystone_sB, 7, Xsand_stonein_4, 7, -1, Xsand_stonein_4, 5, Xsand_stonein_4, 6, -1, Ystone_sB, 6, Xsand_stonein_4, 3, Xsand_stonein_4, 4, -1, Xsand_stonein_4, 1, Xsand_stonein_4, 2, -1, Ystone_sB, 5, Xsand_stonein_3, 7, Xsand_stonein_4, 0, -1, Xsand_stonein_3, 5, Xsand_stonein_3, 6, -1, Ystone_sB, 4, Xsand_stonein_3, 3, Xsand_stonein_3, 4, -1, Xsand_stonein_3, 1, Xsand_stonein_3, 2, -1, Ystone_sB, 3, Xsand_stonein_2, 7, Xsand_stonein_3, 0, -1, Xsand_stonein_2, 5, Xsand_stonein_2, 6, -1, Ystone_sB, 2, Xsand_stonein_2, 3, Xsand_stonein_2, 4, -1, Xsand_stonein_2, 1, Xsand_stonein_2, 2, -1, Ystone_sB, 1, Xsand_stonein_1, 7, Xsand_stonein_2, 0, -1, Xsand_stonein_1, 5, Xsand_stonein_1, 6, -1, Ystone_sB, 0, Xsand_stonein_1, 3, Xsand_stonein_1, 4, -1, Xsand_stonein_1, 1, Xsand_stonein_1, 2, -1, Xstone, 0, Xstone, 1, Xstone, 2, Xstone, 3, Xstone, 4, Xstone, 5, Xstone, 6, Xstone, 7, Xstone_pause, 0, Xstone_pause, 1, Xstone_pause, 2, Xstone_pause, 3, Xstone_pause, 4, Xstone_pause, 5, Xstone_pause, 6, Xstone_pause, 7, Xstone_fall, 0, Xstone_fall, 1, Xstone_fall, 2, Xstone_fall, 3, Xstone_fall, 4, Xstone_fall, 5, Xstone_fall, 6, Xstone_fall, 7, #ifdef BAD_ROLL Xstone_force_e, 0, Xstone_force_e, 1, Xstone_force_e, 2, Xstone_force_e, 3, Xstone_force_e, 4, Xstone_force_e, 5, Xstone_force_e, 6, Xstone_force_e, 7, Xstone_force_w, 0, Xstone_force_w, 1, Xstone_force_w, 2, Xstone_force_w, 3, Xstone_force_w, 4, Xstone_force_w, 5, Xstone_force_w, 6, Xstone_force_w, 7, #endif Ystone_s, 7, Xsand_stoneout_2, 7, Xsand_stonein_1, 0, Ystone_e, 7, Ystone_w, 7, Ydiamond_stone, 7, -1, -1, Ystone_s, 6, Xsand_stoneout_2, 6, -1, -1, Ystone_s, 5, Xsand_stoneout_2, 5, -1, -1, Ystone_s, 4, Xsand_stoneout_2, 4, -1, Xsand_stoneout_2, 3, -1, Ystone_s, 3, Xsand_stoneout_2, 2, -1, Xsand_stoneout_2, 1, -1, Ystone_s, 2, Xsand_stoneout_2, 0, -1, Xsand_stoneout_1, 7, Xsand_stoneout_1, 6, -1, Ystone_s, 1, Xsand_stoneout_1, 5, -1, Xsand_stoneout_1, 4, Xsand_stoneout_1, 3, -1, Ystone_s, 0, Xsand_stoneout_1, 2, -1, Xsand_stoneout_1, 1, Xsand_stoneout_1, 0, -1, #if 0 /* use normal "Xblank" instead of explicit x==0, y==2 empty space graphic */ Ynut_sB, 7, #endif -1, -1, Ynut_sB, 6, -1, -1, Ynut_sB, 5, -1, -1, Ynut_sB, 4, -1, -1, Ynut_sB, 3, -1, -1, Ynut_sB, 2, -1, -1, Ynut_sB, 1, -1, -1, Ynut_sB, 0, -1, -1, Ynut_s, 7, Ynut_e, 7, Ynut_w, 7, Xnut, 0, Xnut, 1, Xnut, 2, Xnut, 3, Xnut, 4, Xnut, 5, Xnut, 6, Xnut, 7, Xnut_pause, 0, Xnut_pause, 1, Xnut_pause, 2, Xnut_pause, 3, Xnut_pause, 4, Xnut_pause, 5, Xnut_pause, 6, Xnut_pause, 7, Xnut_fall, 0, Xnut_fall, 1, Xnut_fall, 2, Xnut_fall, 3, Xnut_fall, 4, Xnut_fall, 5, Xnut_fall, 6, Xnut_fall, 7, #ifdef BAD_ROLL Xnut_force_e, 0, Xnut_force_e, 1, Xnut_force_e, 2, Xnut_force_e, 3, Xnut_force_e, 4, Xnut_force_e, 5, Xnut_force_e, 6, Xnut_force_e, 7, Xnut_force_w, 0, Xnut_force_w, 1, Xnut_force_w, 2, Xnut_force_w, 3, Xnut_force_w, 4, Xnut_force_w, 5, Xnut_force_w, 6, Xnut_force_w, 7, #endif -1, -1, Ynut_s, 6, -1, -1, Ynut_s, 5, -1, -1, Ynut_s, 4, -1, -1, Ynut_s, 3, -1, -1, Ynut_s, 2, -1, -1, Ynut_s, 1, -1, -1, Ynut_s, 0, -1, -1, /* normal */ Xblank, 0, Xblank, 1, Xblank, 2, Xblank, 3, Xblank, 4, Xblank, 5, Xblank, 6, Xblank, 7, Xfake_blank, 0, Xfake_blank, 1, Xfake_blank, 2, Xfake_blank, 3, Xfake_blank, 4, Xfake_blank, 5, Xfake_blank, 6, Xfake_blank, 7, Xdripper, 0, Xdripper, 1, Xdripper, 2, Xdripper, 3, Xdripper, 4, Xdripper, 5, Xdripper, 6, Xdripper, 7, Zplayer, 0, Zplayer, 1, Zplayer, 2, Zplayer, 3, Zplayer, 4, Zplayer, 5, Zplayer, 6, Zplayer, 7, Ydynamite_eat, 3, Ydynamite_eat, 4, Ydynamite_eat, 5, Ydynamite_eat, 6, Ydynamite_eat, 7, -1, -1, -1, -1, -1, Ystone_eB, 6, Ystone_w, 0, -1, Ystone_e, 6, Ystone_wB, 0, -1, Ystone_eB, 5, Ystone_w, 1, -1, Ystone_e, 5, Ystone_wB, 1, -1, Ystone_eB, 4, Ystone_w, 2, -1, Ystone_e, 4, Ystone_wB, 2, -1, Ystone_eB, 3, Ystone_w, 3, -1, Ystone_e, 3, Ystone_wB, 3, -1, Ystone_eB, 2, Ystone_w, 4, -1, Ystone_e, 2, Ystone_wB, 4, -1, Ystone_eB, 1, Ystone_w, 5, -1, Ystone_e, 1, Ystone_wB, 5, -1, Ystone_eB, 0, Ystone_w, 6, -1, Ystone_e, 0, Ystone_wB, 6, -1, Ynut_eB, 6, Ynut_w, 0, -1, Ynut_e, 6, Ynut_wB, 0, -1, Ynut_eB, 5, Ynut_w, 1, -1, Ynut_e, 5, Ynut_wB, 1, -1, Ynut_eB, 4, Ynut_w, 2, -1, Ynut_e, 4, Ynut_wB, 2, -1, Ynut_eB, 3, Ynut_w, 3, -1, Ynut_e, 3, Ynut_wB, 3, -1, Ynut_eB, 2, Ynut_w, 4, -1, Ynut_e, 2, Ynut_wB, 4, -1, Ynut_eB, 1, Ynut_w, 5, -1, Ynut_e, 1, Ynut_wB, 5, -1, Ynut_eB, 0, Ynut_w, 6, -1, Ynut_e, 0, Ynut_wB, 6, -1, Ybug_w_n, 7, Ybug_e_n, 7, Ybug_n, 7, Xbug_n, 0, Xbug_n, 1, Xbug_n, 2, Xbug_n, 3, Xbug_n, 4, Xbug_n, 5, Xbug_n, 6, Xbug_n, 7, Xbug_gon, 0, Xbug_gon, 1, Xbug_gon, 2, Xbug_gon, 3, Xbug_gon, 4, Xbug_gon, 5, Xbug_gon, 6, Xbug_gon, 7, -1, Ybug_n_e, 7, Ybug_s_e, 7, Ybug_e, 7, Xbug_e, 0, Xbug_e, 1, Xbug_e, 2, Xbug_e, 3, Xbug_e, 4, Xbug_e, 5, Xbug_e, 6, Xbug_e, 7, Xbug_goe, 0, Xbug_goe, 1, Xbug_goe, 2, Xbug_goe, 3, Xbug_goe, 4, Xbug_goe, 5, Xbug_goe, 6, Xbug_goe, 7, -1, Ybug_e_s, 7, Ybug_w_s, 7, Ybug_s, 7, Xbug_s, 0, Xbug_s, 1, Xbug_s, 2, Xbug_s, 3, Xbug_s, 4, Xbug_s, 5, Xbug_s, 6, Xbug_s, 7, Xbug_gos, 0, Xbug_gos, 1, Xbug_gos, 2, Xbug_gos, 3, Xbug_gos, 4, Xbug_gos, 5, Xbug_gos, 6, Xbug_gos, 7, -1, Ybug_n_w, 7, Ybug_s_w, 7, Ybug_w, 7, Xbug_w, 0, Xbug_w, 1, Xbug_w, 2, Xbug_w, 3, Xbug_w, 4, Xbug_w, 5, Xbug_w, 6, Xbug_w, 7, Xbug_gow, 0, Xbug_gow, 1, Xbug_gow, 2, Xbug_gow, 3, Xbug_gow, 4, Xbug_gow, 5, Xbug_gow, 6, Xbug_gow, 7, -1, Ybug_n, 0, -1, Ybug_nB, 0, -1, Ybug_n, 1, -1, Ybug_nB, 1, -1, Ybug_n, 2, -1, Ybug_nB, 2, -1, Ybug_n, 3, -1, Ybug_nB, 3, -1, Ybug_n, 4, -1, Ybug_nB, 4, -1, Ybug_n, 5, -1, Ybug_nB, 5, -1, Ybug_n, 6, -1, Ybug_nB, 6, -1, Ybug_eB, 6, -1, Ybug_e, 6, -1, Ybug_eB, 5, -1, Ybug_e, 5, -1, Ybug_eB, 4, -1, Ybug_e, 4, -1, Ybug_eB, 3, -1, Ybug_e, 3, -1, Ybug_eB, 2, -1, Ybug_e, 2, -1, Ybug_eB, 1, -1, Ybug_e, 1, -1, Ybug_eB, 0, -1, Ybug_e, 0, -1, Ybug_sB, 6, -1, Ybug_s, 6, -1, Ybug_sB, 5, -1, Ybug_s, 5, -1, Ybug_sB, 4, -1, Ybug_s, 4, -1, Ybug_sB, 3, -1, Ybug_s, 3, -1, Ybug_sB, 2, -1, Ybug_s, 2, -1, Ybug_sB, 1, -1, Ybug_s, 1, -1, Ybug_sB, 0, -1, Ybug_s, 0, -1, Ybug_w, 0, -1, Ybug_wB, 0, -1, Ybug_w, 1, -1, Ybug_wB, 1, -1, Ybug_w, 2, -1, Ybug_wB, 2, -1, Ybug_w, 3, -1, Ybug_wB, 3, -1, Ybug_w, 4, -1, Ybug_wB, 4, -1, Ybug_w, 5, -1, Ybug_wB, 5, -1, Ybug_w, 6, -1, Ybug_wB, 6, -1, Ybug_n_e, 0, Ybug_e_n, 6, -1, Ybug_n_e, 1, Ybug_e_n, 5, -1, Ybug_n_e, 2, Ybug_e_n, 4, -1, Ybug_n_e, 3, Ybug_e_n, 3, -1, Ybug_n_e, 4, Ybug_e_n, 2, -1, Ybug_n_e, 5, Ybug_e_n, 1, -1, Ybug_n_e, 6, Ybug_e_n, 0, -1, Ybug_e_s, 0, Ybug_s_e, 6, -1, Ybug_e_s, 1, Ybug_s_e, 5, -1, Ybug_e_s, 2, Ybug_s_e, 4, -1, Ybug_e_s, 3, Ybug_s_e, 3, -1, Ybug_e_s, 4, Ybug_s_e, 2, -1, Ybug_e_s, 5, Ybug_s_e, 1, -1, Ybug_e_s, 6, Ybug_s_e, 0, -1, Ybug_s_w, 0, Ybug_w_s, 6, -1, Ybug_s_w, 1, Ybug_w_s, 5, -1, Ybug_s_w, 2, Ybug_w_s, 4, -1, Ybug_s_w, 3, Ybug_w_s, 3, -1, Ybug_s_w, 4, Ybug_w_s, 2, -1, Ybug_s_w, 5, Ybug_w_s, 1, -1, Ybug_s_w, 6, Ybug_w_s, 0, -1, Ybug_n_w, 6, Ybug_w_n, 0, -1, Ybug_n_w, 5, Ybug_w_n, 1, -1, Ybug_n_w, 4, Ybug_w_n, 2, -1, Ybug_n_w, 3, Ybug_w_n, 3, -1, Ybug_n_w, 2, Ybug_w_n, 4, -1, Ybug_n_w, 1, Ybug_w_n, 5, -1, Ybug_n_w, 0, Ybug_w_n, 6, -1, Ybug_stone, 0, -1, Ybug_stone, 1, -1, Ybug_stone, 2, -1, Ybug_stone, 3, -1, Ybug_stone, 4, -1, Ybug_stone, 5, -1, Ybug_stone, 6, -1, Ybug_spring, 0, -1, Ybug_spring, 1, -1, Ybug_spring, 2, -1, Ybug_spring, 3, -1, Ybug_spring, 4, -1, Ybug_spring, 5, -1, Ybug_spring, 6, -1, Ytank_w_n, 7, Ytank_e_n, 7, Ytank_n, 7, Xtank_n, 0, Xtank_n, 1, Xtank_n, 2, Xtank_n, 3, Xtank_n, 4, Xtank_n, 5, Xtank_n, 6, Xtank_n, 7, Xtank_gon, 0, Xtank_gon, 1, Xtank_gon, 2, Xtank_gon, 3, Xtank_gon, 4, Xtank_gon, 5, Xtank_gon, 6, Xtank_gon, 7, -1, Ytank_n_e, 7, Ytank_s_e, 7, Ytank_e, 7, Xtank_e, 0, Xtank_e, 1, Xtank_e, 2, Xtank_e, 3, Xtank_e, 4, Xtank_e, 5, Xtank_e, 6, Xtank_e, 7, Xtank_goe, 0, Xtank_goe, 1, Xtank_goe, 2, Xtank_goe, 3, Xtank_goe, 4, Xtank_goe, 5, Xtank_goe, 6, Xtank_goe, 7, -1, Ytank_e_s, 7, Ytank_w_s, 7, Ytank_s, 7, Xtank_s, 0, Xtank_s, 1, Xtank_s, 2, Xtank_s, 3, Xtank_s, 4, Xtank_s, 5, Xtank_s, 6, Xtank_s, 7, Xtank_gos, 0, Xtank_gos, 1, Xtank_gos, 2, Xtank_gos, 3, Xtank_gos, 4, Xtank_gos, 5, Xtank_gos, 6, Xtank_gos, 7, -1, Ytank_n_w, 7, Ytank_s_w, 7, Ytank_w, 7, Xtank_w, 0, Xtank_w, 1, Xtank_w, 2, Xtank_w, 3, Xtank_w, 4, Xtank_w, 5, Xtank_w, 6, Xtank_w, 7, Xtank_gow, 0, Xtank_gow, 1, Xtank_gow, 2, Xtank_gow, 3, Xtank_gow, 4, Xtank_gow, 5, Xtank_gow, 6, Xtank_gow, 7, -1, Ytank_n, 0, -1, Ytank_nB, 0, -1, Ytank_n, 1, -1, Ytank_nB, 1, -1, Ytank_n, 2, -1, Ytank_nB, 2, -1, Ytank_n, 3, -1, Ytank_nB, 3, -1, Ytank_n, 4, -1, Ytank_nB, 4, -1, Ytank_n, 5, -1, Ytank_nB, 5, -1, Ytank_n, 6, -1, Ytank_nB, 6, -1, Ytank_eB, 6, -1, Ytank_e, 6, -1, Ytank_eB, 5, -1, Ytank_e, 5, -1, Ytank_eB, 4, -1, Ytank_e, 4, -1, Ytank_eB, 3, -1, Ytank_e, 3, -1, Ytank_eB, 2, -1, Ytank_e, 2, -1, Ytank_eB, 1, -1, Ytank_e, 1, -1, Ytank_eB, 0, -1, Ytank_e, 0, -1, Ytank_sB, 6, -1, Ytank_s, 6, -1, Ytank_sB, 5, -1, Ytank_s, 5, -1, Ytank_sB, 4, -1, Ytank_s, 4, -1, Ytank_sB, 3, -1, Ytank_s, 3, -1, Ytank_sB, 2, -1, Ytank_s, 2, -1, Ytank_sB, 1, -1, Ytank_s, 1, -1, Ytank_sB, 0, -1, Ytank_s, 0, -1, Ytank_w, 0, -1, Ytank_wB, 0, -1, Ytank_w, 1, -1, Ytank_wB, 1, -1, Ytank_w, 2, -1, Ytank_wB, 2, -1, Ytank_w, 3, -1, Ytank_wB, 3, -1, Ytank_w, 4, -1, Ytank_wB, 4, -1, Ytank_w, 5, -1, Ytank_wB, 5, -1, Ytank_w, 6, -1, Ytank_wB, 6, -1, Ytank_n_e, 0, Ytank_e_n, 6, -1, Ytank_n_e, 1, Ytank_e_n, 5, -1, Ytank_n_e, 2, Ytank_e_n, 4, -1, Ytank_n_e, 3, Ytank_e_n, 3, -1, Ytank_n_e, 4, Ytank_e_n, 2, -1, Ytank_n_e, 5, Ytank_e_n, 1, -1, Ytank_n_e, 6, Ytank_e_n, 0, -1, Ytank_e_s, 0, Ytank_s_e, 6, -1, Ytank_e_s, 1, Ytank_s_e, 5, -1, Ytank_e_s, 2, Ytank_s_e, 4, -1, Ytank_e_s, 3, Ytank_s_e, 3, -1, Ytank_e_s, 4, Ytank_s_e, 2, -1, Ytank_e_s, 5, Ytank_s_e, 1, -1, Ytank_e_s, 6, Ytank_s_e, 0, -1, Ytank_s_w, 0, Ytank_w_s, 6, -1, Ytank_s_w, 1, Ytank_w_s, 5, -1, Ytank_s_w, 2, Ytank_w_s, 4, -1, Ytank_s_w, 3, Ytank_w_s, 3, -1, Ytank_s_w, 4, Ytank_w_s, 2, -1, Ytank_s_w, 5, Ytank_w_s, 1, -1, Ytank_s_w, 6, Ytank_w_s, 0, -1, Ytank_n_w, 6, Ytank_w_n, 0, -1, Ytank_n_w, 5, Ytank_w_n, 1, -1, Ytank_n_w, 4, Ytank_w_n, 2, -1, Ytank_n_w, 3, Ytank_w_n, 3, -1, Ytank_n_w, 2, Ytank_w_n, 4, -1, Ytank_n_w, 1, Ytank_w_n, 5, -1, Ytank_n_w, 0, Ytank_w_n, 6, -1, Ytank_stone, 0, -1, Ytank_stone, 1, -1, Ytank_stone, 2, -1, Ytank_stone, 3, -1, Ytank_stone, 4, -1, Ytank_stone, 5, -1, Ytank_stone, 6, -1, Ytank_spring, 0, -1, Ytank_spring, 1, -1, Ytank_spring, 2, -1, Ytank_spring, 3, -1, Ytank_spring, 4, -1, Ytank_spring, 5, -1, Ytank_spring, 6, -1, Yandroid_n, 7, Yandroid_ne, 7, Yandroid_e, 7, Yandroid_se, 7, Yandroid_s, 7, Yandroid_sw, 7, Yandroid_w, 7, Yandroid_nw, 7, Xandroid, 7, Xandroid_1_n, 7, Xandroid_2_n, 7, Xandroid_1_e, 7, Xandroid_2_e, 7, Xandroid_1_w, 7, Xandroid_2_w, 7, Xandroid_1_s, 7, Xandroid_2_s, 7, -1, Xandroid, 0, Xandroid_1_n, 0, Xandroid_2_n, 0, Xandroid_1_e, 0, Xandroid_2_e, 0, Xandroid_1_w, 0, Xandroid_2_w, 0, Xandroid_1_s, 0, Xandroid_2_s, 0, -1, Xandroid, 1, Xandroid_1_n, 1, Xandroid_2_n, 1, Xandroid_1_e, 1, Xandroid_2_e, 1, Xandroid_1_w, 1, Xandroid_2_w, 1, Xandroid_1_s, 1, Xandroid_2_s, 1, -1, Xandroid, 2, Xandroid_1_n, 2, Xandroid_2_n, 2, Xandroid_1_e, 2, Xandroid_2_e, 2, Xandroid_1_w, 2, Xandroid_2_w, 2, Xandroid_1_s, 2, Xandroid_2_s, 2, -1, Xandroid, 3, Xandroid_1_n, 3, Xandroid_2_n, 3, Xandroid_1_e, 3, Xandroid_2_e, 3, Xandroid_1_w, 3, Xandroid_2_w, 3, Xandroid_1_s, 3, Xandroid_2_s, 3, -1, Xandroid, 4, Xandroid_1_n, 4, Xandroid_2_n, 4, Xandroid_1_e, 4, Xandroid_2_e, 4, Xandroid_1_w, 4, Xandroid_2_w, 4, Xandroid_1_s, 4, Xandroid_2_s, 4, -1, Xandroid, 5, Xandroid_1_n, 5, Xandroid_2_n, 5, Xandroid_1_e, 5, Xandroid_2_e, 5, Xandroid_1_w, 5, Xandroid_2_w, 5, Xandroid_1_s, 5, Xandroid_2_s, 5, -1, Xandroid, 6, Xandroid_1_n, 6, Xandroid_2_n, 6, Xandroid_1_e, 6, Xandroid_2_e, 6, Xandroid_1_w, 6, Xandroid_2_w, 6, Xandroid_1_s, 6, Xandroid_2_s, 6, -1, Yandroid_n, 0, Yandroid_sB, 6, -1, Yandroid_nB, 0, Yandroid_s, 6, -1, Yandroid_n, 1, Yandroid_sB, 5, -1, Yandroid_nB, 1, Yandroid_s, 5, -1, Yandroid_n, 2, Yandroid_sB, 4, Xboom_android, 0, -1, Yandroid_nB, 2, Yandroid_s, 4, Xboom_android, 1, -1, Yandroid_n, 3, Yandroid_sB, 3, Xboom_android, 2, -1, Yandroid_nB, 3, Yandroid_s, 3, Xboom_android, 3, -1, Yandroid_n, 4, Yandroid_sB, 2, Xboom_android, 4, -1, Yandroid_nB, 4, Yandroid_s, 2, Xboom_android, 5, -1, Yandroid_n, 5, Yandroid_sB, 1, Xboom_android, 6, -1, Yandroid_nB, 5, Yandroid_s, 1, -1, Yandroid_n, 6, Yandroid_sB, 0, -1, Yandroid_nB, 6, Yandroid_s, 0, -1, Yandroid_eB, 6, Yandroid_w, 0, -1, Yandroid_e, 6, Yandroid_wB, 0, -1, Yandroid_eB, 5, Yandroid_w, 1, -1, Yandroid_e, 5, Yandroid_wB, 1, -1, Yandroid_eB, 4, Yandroid_w, 2, -1, Yandroid_e, 4, Yandroid_wB, 2, -1, Yandroid_eB, 3, Yandroid_w, 3, -1, Yandroid_e, 3, Yandroid_wB, 3, -1, Yandroid_eB, 2, Yandroid_w, 4, -1, Yandroid_e, 2, Yandroid_wB, 4, -1, Yandroid_eB, 1, Yandroid_w, 5, -1, Yandroid_e, 1, Yandroid_wB, 5, -1, Yandroid_eB, 0, Yandroid_w, 6, -1, Yandroid_e, 0, Yandroid_wB, 6, -1, Yandroid_neB, 6, Yandroid_sw, 0, -1, Yandroid_ne, 6, Yandroid_swB, 0, -1, Yandroid_neB, 5, Yandroid_sw, 1, -1, Yandroid_ne, 5, Yandroid_swB, 1, -1, Yandroid_neB, 4, Yandroid_sw, 2, -1, Yandroid_ne, 4, Yandroid_swB, 2, -1, Yandroid_neB, 3, Yandroid_sw, 3, -1, Yandroid_ne, 3, Yandroid_swB, 3, -1, Yandroid_neB, 2, Yandroid_sw, 4, -1, Yandroid_ne, 2, Yandroid_swB, 4, -1, Yandroid_neB, 1, Yandroid_sw, 5, -1, Yandroid_ne, 1, Yandroid_swB, 5, -1, Yandroid_neB, 0, Yandroid_sw, 6, -1, Yandroid_ne, 0, Yandroid_swB, 6, -1, Yandroid_nw, 0, Yandroid_seB, 6, -1, Yandroid_nwB, 0, Yandroid_se, 6, -1, Yandroid_nw, 1, Yandroid_seB, 5, -1, Yandroid_nwB, 1, Yandroid_se, 5, -1, Yandroid_nw, 2, Yandroid_seB, 4, -1, Yandroid_nwB, 2, Yandroid_se, 4, -1, Yandroid_nw, 3, Yandroid_seB, 3, -1, Yandroid_nwB, 3, Yandroid_se, 3, -1, Yandroid_nw, 4, Yandroid_seB, 2, -1, Yandroid_nwB, 4, Yandroid_se, 2, -1, Yandroid_nw, 5, Yandroid_seB, 1, -1, Yandroid_nwB, 5, Yandroid_se, 1, -1, Yandroid_nw, 6, Yandroid_seB, 0, -1, Yandroid_nwB, 6, Yandroid_se, 0, -1, Yspring_e, 7, Yspring_w, 7, Yspring_kill_e, 7, Yspring_kill_w, 7, Yspring_s, 7, Xspring, 0, Xspring, 1, Xspring, 2, Xspring, 3, Xspring, 4, Xspring, 5, Xspring, 6, Xspring, 7, Xspring_pause, 0, Xspring_pause, 1, Xspring_pause, 2, Xspring_pause, 3, Xspring_pause, 4, Xspring_pause, 5, Xspring_pause, 6, Xspring_pause, 7, Xspring_e, 0, Xspring_e, 1, Xspring_e, 2, Xspring_e, 3, Xspring_e, 4, Xspring_e, 5, Xspring_e, 6, Xspring_e, 7, Xspring_w, 0, Xspring_w, 1, Xspring_w, 2, Xspring_w, 3, Xspring_w, 4, Xspring_w, 5, Xspring_w, 6, Xspring_w, 7, Xspring_fall, 0, Xspring_fall, 1, Xspring_fall, 2, Xspring_fall, 3, Xspring_fall, 4, Xspring_fall, 5, Xspring_fall, 6, Xspring_fall, 7, #ifdef BAD_ROLL Xspring_force_e, 0, Xspring_force_e, 1, Xspring_force_e, 2, Xspring_force_e, 3, Xspring_force_e, 4, Xspring_force_e, 5, Xspring_force_e, 6, Xspring_force_e, 7, Xspring_force_w, 0, Xspring_force_w, 1, Xspring_force_w, 2, Xspring_force_w, 3, Xspring_force_w, 4, Xspring_force_w, 5, Xspring_force_w, 6, Xspring_force_w, 7, #endif -1, Yspring_sB, 6, -1, Yspring_s, 6, -1, Yspring_sB, 5, -1, Yspring_s, 5, -1, Yspring_sB, 4, -1, Yspring_s, 4, -1, Yspring_sB, 3, -1, Yspring_s, 3, -1, Yspring_sB, 2, -1, Yspring_s, 2, -1, Yspring_sB, 1, -1, Yspring_s, 1, -1, Yspring_sB, 0, -1, Yspring_s, 0, -1, Yspring_eB, 6, Yspring_w, 0, -1, Yspring_e, 6, Yspring_wB, 0, -1, Yspring_eB, 5, Yspring_w, 1, -1, Yspring_e, 5, Yspring_wB, 1, -1, Yspring_eB, 4, Yspring_w, 2, -1, Yspring_e, 4, Yspring_wB, 2, -1, Yspring_eB, 3, Yspring_w, 3, -1, Yspring_e, 3, Yspring_wB, 3, -1, Yspring_eB, 2, Yspring_w, 4, -1, Yspring_e, 2, Yspring_wB, 4, -1, Yspring_eB, 1, Yspring_w, 5, -1, Yspring_e, 1, Yspring_wB, 5, -1, Yspring_eB, 0, Yspring_w, 6, -1, Yspring_e, 0, Yspring_wB, 6, -1, Yspring_kill_eB, 6, -1, Yspring_kill_e, 6, -1, Yspring_kill_eB, 5, -1, Yspring_kill_e, 5, -1, Yspring_kill_eB, 4, -1, Yspring_kill_e, 4, -1, Yspring_kill_eB, 3, -1, Yspring_kill_e, 3, -1, Yspring_kill_eB, 2, -1, Yspring_kill_e, 2, -1, Yspring_kill_eB, 1, -1, Yspring_kill_e, 1, -1, Yspring_kill_eB, 0, -1, Yspring_kill_e, 0, -1, Yspring_kill_w, 0, -1, Yspring_kill_wB, 0, -1, Yspring_kill_w, 1, -1, Yspring_kill_wB, 1, -1, Yspring_kill_w, 2, -1, Yspring_kill_wB, 2, -1, Yspring_kill_w, 3, -1, Yspring_kill_wB, 3, -1, Yspring_kill_w, 4, -1, Yspring_kill_wB, 4, -1, Yspring_kill_w, 5, -1, Yspring_kill_wB, 5, -1, Yspring_kill_w, 6, -1, Yspring_kill_wB, 6, -1, Xeater_n, 0, Xeater_e, 0, Xeater_w, 0, Xeater_s, 0, Xeater_n, 7, Xeater_e, 7, Xeater_s, 7, Xeater_w, 7, Yeater_n, 7, Yeater_e, 7, Yeater_s, 7, Yeater_w, 7, -1, Xeater_n, 1, Xeater_e, 1, Xeater_w, 1, Xeater_s, 1, Xeater_n, 6, Xeater_e, 6, Xeater_w, 6, Xeater_s, 6, -1, Xeater_n, 2, Xeater_e, 2, Xeater_w, 2, Xeater_s, 2, Xeater_n, 5, Xeater_e, 5, Xeater_w, 5, Xeater_s, 5, -1, Xeater_n, 3, Xeater_e, 3, Xeater_w, 3, Xeater_s, 3, Xeater_n, 4, Xeater_e, 4, Xeater_w, 4, Xeater_s, 4, -1, Yeater_n, 0, Yeater_sB, 6, -1, Yeater_nB, 0, Yeater_s, 6, -1, Yeater_n, 1, Yeater_sB, 5, -1, Yeater_nB, 1, Yeater_s, 5, -1, Yeater_n, 2, Yeater_sB, 4, -1, Yeater_nB, 2, Yeater_s, 4, -1, Yeater_n, 3, Yeater_sB, 3, -1, Yeater_nB, 3, Yeater_s, 3, -1, Yeater_n, 4, Yeater_sB, 2, -1, Yeater_nB, 4, Yeater_s, 2, -1, Yeater_n, 5, Yeater_sB, 1, -1, Yeater_nB, 5, Yeater_s, 1, -1, Yeater_n, 6, Yeater_sB, 0, -1, Yeater_nB, 6, Yeater_s, 0, -1, Yeater_eB, 6, Yeater_w, 0, -1, Yeater_e, 6, Yeater_wB, 0, -1, Yeater_eB, 5, Yeater_w, 1, -1, Yeater_e, 5, Yeater_wB, 1, -1, Yeater_eB, 4, Yeater_w, 2, -1, Yeater_e, 4, Yeater_wB, 2, -1, Yeater_eB, 3, Yeater_w, 3, -1, Yeater_e, 3, Yeater_wB, 3, -1, Yeater_eB, 2, Yeater_w, 4, -1, Yeater_e, 2, Yeater_wB, 4, -1, Yeater_eB, 1, Yeater_w, 5, -1, Yeater_e, 1, Yeater_wB, 5, -1, Yeater_eB, 0, Yeater_w, 6, -1, Yeater_e, 0, Yeater_wB, 6, -1, Yeater_stone, 0, -1, Yeater_stone, 1, -1, Yeater_stone, 2, -1, Yeater_stone, 3, -1, Yeater_stone, 4, -1, Yeater_stone, 5, -1, Yeater_stone, 6, -1, Yeater_spring, 0, -1, Yeater_spring, 1, -1, Yeater_spring, 2, -1, Yeater_spring, 3, -1, Yeater_spring, 4, -1, Yeater_spring, 5, -1, Yeater_spring, 6, -1, Xalien, 0, Xalien_pause, 0, Xalien, 7, Xalien_pause, 7, Yalien_n, 7, Yalien_e, 7, Yalien_s, 7, Yalien_w, 7, -1, Xalien, 1, Xalien_pause, 1, Xalien, 6, Xalien_pause, 6, -1, Xalien, 2, Xalien_pause, 2, Xalien, 5, Xalien_pause, 5, -1, Xalien, 3, Xalien_pause, 3, Xalien, 4, Xalien_pause, 4, -1, Yalien_n, 0, Yalien_sB, 6, -1, Yalien_nB, 0, Yalien_s, 6, -1, Yalien_n, 1, Yalien_sB, 5, -1, Yalien_nB, 1, Yalien_s, 5, -1, Yalien_n, 2, Yalien_sB, 4, -1, Yalien_nB, 2, Yalien_s, 4, -1, Yalien_n, 3, Yalien_sB, 3, -1, Yalien_nB, 3, Yalien_s, 3, -1, Yalien_n, 4, Yalien_sB, 2, -1, Yalien_nB, 4, Yalien_s, 2, -1, Yalien_n, 5, Yalien_sB, 1, -1, Yalien_nB, 5, Yalien_s, 1, -1, Yalien_n, 6, Yalien_sB, 0, -1, Yalien_nB, 6, Yalien_s, 0, -1, Yalien_eB, 6, Yalien_w, 0, -1, Yalien_e, 6, Yalien_wB, 0, -1, Yalien_eB, 5, Yalien_w, 1, -1, Yalien_e, 5, Yalien_wB, 1, -1, Yalien_eB, 4, Yalien_w, 2, -1, Yalien_e, 4, Yalien_wB, 2, -1, Yalien_eB, 3, Yalien_w, 3, -1, Yalien_e, 3, Yalien_wB, 3, -1, Yalien_eB, 2, Yalien_w, 4, -1, Yalien_e, 2, Yalien_wB, 4, -1, Yalien_eB, 1, Yalien_w, 5, -1, Yalien_e, 1, Yalien_wB, 5, -1, Yalien_eB, 0, Yalien_w, 6, -1, Yalien_e, 0, Yalien_wB, 6, -1, Yalien_stone, 0, -1, Yalien_stone, 1, -1, Yalien_stone, 2, -1, Yalien_stone, 3, -1, Yalien_stone, 4, -1, Yalien_stone, 5, -1, Yalien_stone, 6, -1, Yalien_spring, 0, -1, Yalien_spring, 1, -1, Yalien_spring, 2, -1, Yalien_spring, 3, -1, Yalien_spring, 4, -1, Yalien_spring, 5, -1, Yalien_spring, 6, -1, Xemerald, 0, Xemerald, 1, Xemerald, 2, Xemerald, 3, Xemerald, 4, Xemerald, 5, Xemerald, 6, Xemerald, 7, Xemerald_pause, 0, Xemerald_pause, 1, Xemerald_pause, 2, Xemerald_pause, 3, Xemerald_pause, 4, Xemerald_pause, 5, Xemerald_pause, 6, Xemerald_pause, 7, Xemerald_fall, 0, Xemerald_fall, 1, Xemerald_fall, 2, Xemerald_fall, 3, Xemerald_fall, 4, Xemerald_fall, 5, Xemerald_fall, 6, Xemerald_fall, 7, #ifdef BAD_ROLL Xemerald_force_e, 0, Xemerald_force_e, 1, Xemerald_force_e, 2, Xemerald_force_e, 3, Xemerald_force_e, 4, Xemerald_force_e, 5, Xemerald_force_e, 6, Xemerald_force_e, 7, Xemerald_force_w, 0, Xemerald_force_w, 1, Xemerald_force_w, 2, Xemerald_force_w, 3, Xemerald_force_w, 4, Xemerald_force_w, 5, Xemerald_force_w, 6, Xemerald_force_w, 7, #endif Xemerald_shine, 0, Xemerald_shine, 7, Yemerald_stone, 7, Yemerald_s, 7, Yemerald_e, 7, Yemerald_w, 7, -1, Xemerald_shine, 1, Xemerald_shine, 6, -1, Xemerald_shine, 2, Xemerald_shine, 5, -1, Xemerald_shine, 3, Xemerald_shine, 4, -1, Yemerald_sB, 6, -1, Yemerald_s, 6, -1, Yemerald_sB, 5, -1, Yemerald_s, 5, -1, Yemerald_sB, 4, -1, Yemerald_s, 4, -1, Yemerald_sB, 3, -1, Yemerald_s, 3, -1, Yemerald_sB, 2, -1, Yemerald_s, 2, -1, Yemerald_sB, 1, -1, Yemerald_s, 1, -1, Yemerald_sB, 0, -1, Yemerald_s, 0, -1, Yemerald_eB, 6, Yemerald_w, 0, -1, Yemerald_e, 6, Yemerald_wB, 0, -1, Yemerald_eB, 5, Yemerald_w, 1, -1, Yemerald_e, 5, Yemerald_wB, 1, -1, Yemerald_eB, 4, Yemerald_w, 2, -1, Yemerald_e, 4, Yemerald_wB, 2, -1, Yemerald_eB, 3, Yemerald_w, 3, -1, Yemerald_e, 3, Yemerald_wB, 3, -1, Yemerald_eB, 2, Yemerald_w, 4, -1, Yemerald_e, 2, Yemerald_wB, 4, -1, Yemerald_eB, 1, Yemerald_w, 5, -1, Yemerald_e, 1, Yemerald_wB, 5, -1, Yemerald_eB, 0, Yemerald_w, 6, -1, Yemerald_e, 0, Yemerald_wB, 6, -1, Yemerald_eat, 6, -1, Yemerald_eat, 5, -1, Yemerald_eat, 4, -1, Yemerald_eat, 3, -1, Yemerald_eat, 2, -1, Yemerald_eat, 1, -1, Yemerald_eat, 0, -1, Yemerald_stone, 0, -1, Yemerald_stone, 1, -1, Yemerald_stone, 2, -1, Yemerald_stone, 3, -1, Yemerald_stone, 4, -1, Yemerald_stone, 5, -1, Yemerald_stone, 6, -1, Xdiamond, 0, Xdiamond, 1, Xdiamond, 2, Xdiamond, 3, Xdiamond, 4, Xdiamond, 5, Xdiamond, 6, Xdiamond, 7, Xdiamond_pause, 0, Xdiamond_pause, 1, Xdiamond_pause, 2, Xdiamond_pause, 3, Xdiamond_pause, 4, Xdiamond_pause, 5, Xdiamond_pause, 6, Xdiamond_pause, 7, Xdiamond_fall, 0, Xdiamond_fall, 1, Xdiamond_fall, 2, Xdiamond_fall, 3, Xdiamond_fall, 4, Xdiamond_fall, 5, Xdiamond_fall, 6, Xdiamond_fall, 7, #ifdef BAD_ROLL Xdiamond_force_e, 0, Xdiamond_force_e, 1, Xdiamond_force_e, 2, Xdiamond_force_e, 3, Xdiamond_force_e, 4, Xdiamond_force_e, 5, Xdiamond_force_e, 6, Xdiamond_force_e, 7, Xdiamond_force_w, 0, Xdiamond_force_w, 1, Xdiamond_force_w, 2, Xdiamond_force_w, 3, Xdiamond_force_w, 4, Xdiamond_force_w, 5, Xdiamond_force_w, 6, Xdiamond_force_w, 7, #endif Xdiamond_shine, 0, Xdiamond_shine, 7, Ydiamond_s, 7, Ydiamond_e, 7, Ydiamond_w, 7, -1, Xdiamond_shine, 1, Xdiamond_shine, 6, -1, Xdiamond_shine, 2, Xdiamond_shine, 5, -1, Xdiamond_shine, 3, Xdiamond_shine, 4, -1, Ydiamond_sB, 6, -1, Ydiamond_s, 6, -1, Ydiamond_sB, 5, -1, Ydiamond_s, 5, -1, Ydiamond_sB, 4, -1, Ydiamond_s, 4, -1, Ydiamond_sB, 3, -1, Ydiamond_s, 3, -1, Ydiamond_sB, 2, -1, Ydiamond_s, 2, -1, Ydiamond_sB, 1, -1, Ydiamond_s, 1, -1, Ydiamond_sB, 0, -1, Ydiamond_s, 0, -1, Ydiamond_eB, 6, Ydiamond_w, 0, -1, Ydiamond_e, 6, Ydiamond_wB, 0, -1, Ydiamond_eB, 5, Ydiamond_w, 1, -1, Ydiamond_e, 5, Ydiamond_wB, 1, -1, Ydiamond_eB, 4, Ydiamond_w, 2, -1, Ydiamond_e, 4, Ydiamond_wB, 2, -1, Ydiamond_eB, 3, Ydiamond_w, 3, -1, Ydiamond_e, 3, Ydiamond_wB, 3, -1, Ydiamond_eB, 2, Ydiamond_w, 4, -1, Ydiamond_e, 2, Ydiamond_wB, 4, -1, Ydiamond_eB, 1, Ydiamond_w, 5, -1, Ydiamond_e, 1, Ydiamond_wB, 5, -1, Ydiamond_eB, 0, Ydiamond_w, 6, -1, Ydiamond_e, 0, Ydiamond_wB, 6, -1, Ydiamond_eat, 6, -1, Ydiamond_eat, 5, -1, Ydiamond_eat, 4, -1, Ydiamond_eat, 3, -1, Ydiamond_eat, 2, -1, Ydiamond_eat, 1, -1, Ydiamond_eat, 0, -1, Ydiamond_stone, 0, -1, Ydiamond_stone, 1, -1, Ydiamond_stone, 2, -1, Ydiamond_stone, 3, -1, Ydiamond_stone, 4, -1, Ydiamond_stone, 5, -1, Ydiamond_stone, 6, -1, Xdrip_fall, 0, Xdrip_fall, 1, Xdrip_fall, 2, Xdrip_fall, 3, Xdrip_fall, 4, Xdrip_fall, 5, Xdrip_fall, 6, Xdrip_fall, 7, Xdrip_eat, 7, Ydrip_s2, 7, -1, Ydrip_s2B, 6, -1, Ydrip_s2, 6, -1, Ydrip_s2B, 5, -1, Ydrip_s2, 5, -1, Ydrip_s2B, 4, -1, Ydrip_s2, 4, -1, Ydrip_s2B, 3, -1, Ydrip_s2, 3, -1, Ydrip_s2B, 2, -1, Ydrip_s2, 2, -1, Ydrip_s2B, 1, -1, Ydrip_s2, 1, -1, Ydrip_s2B, 0, -1, Ydrip_s2, 0, -1, Xdrip_stretchB, 0, Xdrip_stretchB, 1, Xdrip_stretchB, 2, Xdrip_stretchB, 3, Xdrip_stretchB, 4, Xdrip_stretchB, 5, Xdrip_stretchB, 6, Xdrip_stretchB, 7, Ydrip_s1B, 7, -1, Xdrip_stretch, 0, Xdrip_stretch, 1, Xdrip_stretch, 2, Xdrip_stretch, 3, Xdrip_stretch, 4, Xdrip_stretch, 5, Xdrip_stretch, 6, Xdrip_stretch, 7, Ydrip_s1, 7, -1, Ydrip_s1B, 6, -1, Ydrip_s1, 6, -1, Ydrip_s1B, 5, -1, Ydrip_s1, 5, -1, Ydrip_s1B, 4, -1, Ydrip_s1, 4, -1, Ydrip_s1B, 3, -1, Ydrip_s1, 3, -1, Ydrip_s1B, 2, -1, Ydrip_s1, 2, -1, Ydrip_s1B, 1, -1, Ydrip_s1, 1, -1, Ydrip_s1B, 0, -1, Ydrip_s1, 0, -1, Xdrip_eat, 0, -1, Xdrip_eat, 1, -1, Xdrip_eat, 2, -1, Xdrip_eat, 3, -1, Xdrip_eat, 4, -1, Xdrip_eat, 5, -1, Xdrip_eat, 6, -1, Xbomb, 0, Xbomb, 1, Xbomb, 2, Xbomb, 3, Xbomb, 4, Xbomb, 5, Xbomb, 6, Xbomb, 7, Xbomb_pause, 0, Xbomb_pause, 1, Xbomb_pause, 2, Xbomb_pause, 3, Xbomb_pause, 4, Xbomb_pause, 5, Xbomb_pause, 6, Xbomb_pause, 7, Xbomb_fall, 0, Xbomb_fall, 1, Xbomb_fall, 2, Xbomb_fall, 3, Xbomb_fall, 4, Xbomb_fall, 5, Xbomb_fall, 6, Xbomb_fall, 7, #ifdef BAD_ROLL Xbomb_force_e, 0, Xbomb_force_e, 1, Xbomb_force_e, 2, Xbomb_force_e, 3, Xbomb_force_e, 4, Xbomb_force_e, 5, Xbomb_force_e, 6, Xbomb_force_e, 7, Xbomb_force_w, 0, Xbomb_force_w, 1, Xbomb_force_w, 2, Xbomb_force_w, 3, Xbomb_force_w, 4, Xbomb_force_w, 5, Xbomb_force_w, 6, Xbomb_force_w, 7, #endif Ybomb_s, 7, Ybomb_e, 7, Ybomb_w, 7, -1, Ybomb_sB, 6, -1, Ybomb_s, 6, -1, Ybomb_sB, 5, -1, Ybomb_s, 5, -1, Ybomb_sB, 4, -1, Ybomb_s, 4, -1, Ybomb_sB, 3, -1, Ybomb_s, 3, -1, Ybomb_sB, 2, -1, Ybomb_s, 2, -1, Ybomb_sB, 1, -1, Ybomb_s, 1, -1, Ybomb_sB, 0, -1, Ybomb_s, 0, -1, Ybomb_eB, 6, Ybomb_w, 0, -1, Ybomb_e, 6, Ybomb_wB, 0, -1, Ybomb_eB, 5, Ybomb_w, 1, -1, Ybomb_e, 5, Ybomb_wB, 1, -1, Ybomb_eB, 4, Ybomb_w, 2, -1, Ybomb_e, 4, Ybomb_wB, 2, -1, Ybomb_eB, 3, Ybomb_w, 3, -1, Ybomb_e, 3, Ybomb_wB, 3, -1, Ybomb_eB, 2, Ybomb_w, 4, -1, Ybomb_e, 2, Ybomb_wB, 4, -1, Ybomb_eB, 1, Ybomb_w, 5, -1, Ybomb_e, 1, Ybomb_wB, 5, -1, Ybomb_eB, 0, Ybomb_w, 6, -1, Ybomb_e, 0, Ybomb_wB, 6, -1, Ybomb_eat, 6, -1, Ybomb_eat, 5, -1, Ybomb_eat, 4, -1, Ybomb_eat, 3, -1, Ybomb_eat, 2, -1, Ybomb_eat, 1, -1, Ybomb_eat, 0, -1, Yballoon_n, 7, Yballoon_e, 7, Yballoon_s, 7, Yballoon_w, 7, Xballoon, 0, Xballoon, 1, Xballoon, 2, Xballoon, 3, Xballoon, 4, Xballoon, 5, Xballoon, 6, Xballoon, 7, -1, Yballoon_n, 0, Yballoon_sB, 6, -1, Yballoon_nB, 0, Yballoon_s, 6, -1, Yballoon_n, 1, Yballoon_sB, 5, -1, Yballoon_nB, 1, Yballoon_s, 5, -1, Yballoon_n, 2, Yballoon_sB, 4, -1, Yballoon_nB, 2, Yballoon_s, 4, -1, Yballoon_n, 3, Yballoon_sB, 3, -1, Yballoon_nB, 3, Yballoon_s, 3, -1, Yballoon_n, 4, Yballoon_sB, 2, -1, Yballoon_nB, 4, Yballoon_s, 2, -1, Yballoon_n, 5, Yballoon_sB, 1, -1, Yballoon_nB, 5, Yballoon_s, 1, -1, Yballoon_n, 6, Yballoon_sB, 0, -1, Yballoon_nB, 6, Yballoon_s, 0, -1, Yballoon_eB, 6, Yballoon_w, 0, -1, Yballoon_e, 6, Yballoon_wB, 0, -1, Yballoon_eB, 5, Yballoon_w, 1, -1, Yballoon_e, 5, Yballoon_wB, 1, -1, Yballoon_eB, 4, Yballoon_w, 2, -1, Yballoon_e, 4, Yballoon_wB, 2, -1, Yballoon_eB, 3, Yballoon_w, 3, -1, Yballoon_e, 3, Yballoon_wB, 3, -1, Yballoon_eB, 2, Yballoon_w, 4, -1, Yballoon_e, 2, Yballoon_wB, 4, -1, Yballoon_eB, 1, Yballoon_w, 5, -1, Yballoon_e, 1, Yballoon_wB, 5, -1, Yballoon_eB, 0, Yballoon_w, 6, -1, Yballoon_e, 0, Yballoon_wB, 6, -1, Xgrass, 0, Xgrass, 1, Xgrass, 2, Xgrass, 3, Xgrass, 4, Xgrass, 5, Xgrass, 6, Xgrass, 7, Xfake_grass, 0, Xfake_grass, 1, Xfake_grass, 2, Xfake_grass, 3, Xfake_grass, 4, Xfake_grass, 5, Xfake_grass, 6, Xfake_grass, 7, -1, Ygrass_nB, 6, -1, Ygrass_nB, 5, -1, Ygrass_nB, 4, -1, Ygrass_nB, 3, -1, Ygrass_nB, 2, -1, Ygrass_nB, 1, -1, Ygrass_nB, 0, -1, Ygrass_eB, 6, -1, Ygrass_eB, 5, -1, Ygrass_eB, 4, -1, Ygrass_eB, 3, -1, Ygrass_eB, 2, -1, Ygrass_eB, 1, -1, Ygrass_eB, 0, -1, Ygrass_sB, 6, -1, Ygrass_sB, 5, -1, Ygrass_sB, 4, -1, Ygrass_sB, 3, -1, Ygrass_sB, 2, -1, Ygrass_sB, 1, -1, Ygrass_sB, 0, -1, Ygrass_wB, 6, -1, Ygrass_wB, 5, -1, Ygrass_wB, 4, -1, Ygrass_wB, 3, -1, Ygrass_wB, 2, -1, Ygrass_wB, 1, -1, Ygrass_wB, 0, -1, Xdirt, 0, Xdirt, 1, Xdirt, 2, Xdirt, 3, Xdirt, 4, Xdirt, 5, Xdirt, 6, Xdirt, 7, -1, Ydirt_nB, 6, -1, Ydirt_nB, 5, -1, Ydirt_nB, 4, -1, Ydirt_nB, 3, -1, Ydirt_nB, 2, -1, Ydirt_nB, 1, -1, Ydirt_nB, 0, -1, Ydirt_eB, 6, -1, Ydirt_eB, 5, -1, Ydirt_eB, 4, -1, Ydirt_eB, 3, -1, Ydirt_eB, 2, -1, Ydirt_eB, 1, -1, Ydirt_eB, 0, -1, Ydirt_sB, 6, -1, Ydirt_sB, 5, -1, Ydirt_sB, 4, -1, Ydirt_sB, 3, -1, Ydirt_sB, 2, -1, Ydirt_sB, 1, -1, Ydirt_sB, 0, -1, Ydirt_wB, 6, -1, Ydirt_wB, 5, -1, Ydirt_wB, 4, -1, Ydirt_wB, 3, -1, Ydirt_wB, 2, -1, Ydirt_wB, 1, -1, Ydirt_wB, 0, -1, Xacid_nw, 0, Xacid_nw, 1, Xacid_nw, 2, Xacid_nw, 3, Xacid_nw, 4, Xacid_nw, 5, Xacid_nw, 6, Xacid_nw, 7, -1, Xacid_ne, 0, Xacid_ne, 1, Xacid_ne, 2, Xacid_ne, 3, Xacid_ne, 4, Xacid_ne, 5, Xacid_ne, 6, Xacid_ne, 7, -1, Xacid_sw, 0, Xacid_sw, 1, Xacid_sw, 2, Xacid_sw, 3, Xacid_sw, 4, Xacid_sw, 5, Xacid_sw, 6, Xacid_sw, 7, -1, Xacid_s, 0, Xacid_s, 1, Xacid_s, 2, Xacid_s, 3, Xacid_s, 4, Xacid_s, 5, Xacid_s, 6, Xacid_s, 7, -1, Xacid_se, 0, Xacid_se, 1, Xacid_se, 2, Xacid_se, 3, Xacid_se, 4, Xacid_se, 5, Xacid_se, 6, Xacid_se, 7, -1, Xacid_1, 0, Xacid_1, 1, Xacid_1, 2, Xacid_1, 3, Xacid_1, 4, Xacid_1, 5, Xacid_1, 6, Xacid_1, 7, -1, Xacid_2, 0, Xacid_2, 1, Xacid_2, 2, Xacid_2, 3, Xacid_2, 4, Xacid_2, 5, Xacid_2, 6, Xacid_2, 7, -1, Xacid_3, 0, Xacid_3, 1, Xacid_3, 2, Xacid_3, 3, Xacid_3, 4, Xacid_3, 5, Xacid_3, 6, Xacid_3, 7, -1, Xacid_4, 0, Xacid_4, 1, Xacid_4, 2, Xacid_4, 3, Xacid_4, 4, Xacid_4, 5, Xacid_4, 6, Xacid_4, 7, -1, Xacid_5, 0, Xacid_5, 1, Xacid_5, 2, Xacid_5, 3, Xacid_5, 4, Xacid_5, 5, Xacid_5, 6, Xacid_5, 7, -1, Xacid_6, 0, Xacid_6, 1, Xacid_6, 2, Xacid_6, 3, Xacid_6, 4, Xacid_6, 5, Xacid_6, 6, Xacid_6, 7, -1, Xacid_7, 0, Xacid_7, 1, Xacid_7, 2, Xacid_7, 3, Xacid_7, 4, Xacid_7, 5, Xacid_7, 6, Xacid_7, 7, -1, Xacid_8, 0, Xacid_8, 1, Xacid_8, 2, Xacid_8, 3, Xacid_8, 4, Xacid_8, 5, Xacid_8, 6, Xacid_8, 7, -1, Yacid_splash_wB, 4, Yacid_splash_wB, 5, -1, Yacid_splash_wB, 2, Yacid_splash_wB, 3, -1, Yacid_splash_wB, 0, Yacid_splash_wB, 1, -1, Yacid_splash_eB, 4, Yacid_splash_eB, 5, -1, Yacid_splash_eB, 2, Yacid_splash_eB, 3, -1, Yacid_splash_eB, 0, Yacid_splash_eB, 1, -1, Xball_2B, 7, Xball_1, 0, Xball_1, 1, Xball_1, 2, Xball_1, 3, Xball_1, 4, Xball_1, 5, Xball_1, 6, Xball_1, 7, -1, Xball_1B, 0, -1, Xball_1B, 1, -1, Xball_1B, 2, -1, Xball_1B, 3, -1, Xball_1B, 4, -1, Xball_1B, 5, -1, Xball_1B, 6, -1, Xball_1B, 7, Xball_2, 0, Xball_2, 1, Xball_2, 2, Xball_2, 3, Xball_2, 4, Xball_2, 5, Xball_2, 6, Xball_2, 7, -1, Xball_2B, 0, -1, Xball_2B, 1, -1, Xball_2B, 2, -1, Xball_2B, 3, -1, Xball_2B, 4, -1, Xball_2B, 5, -1, Xball_2B, 6, -1, Ygrow_ew_eat, 7, Xgrow_ew, 0, Xgrow_ew, 1, Xgrow_ew, 2, Xgrow_ew, 3, Xgrow_ew, 4, Xgrow_ew, 5, Xgrow_ew, 6, Xgrow_ew, 7, -1, Ygrow_ew_eat, 0, -1, Ygrow_ew_eat, 1, -1, Ygrow_ew_eat, 2, -1, Ygrow_ew_eat, 3, -1, Ygrow_ew_eat, 4, -1, Ygrow_ew_eat, 5, -1, Ygrow_ew_eat, 6, -1, Ygrow_ns_eat, 7, Xgrow_ns, 0, Xgrow_ns, 1, Xgrow_ns, 2, Xgrow_ns, 3, Xgrow_ns, 4, Xgrow_ns, 5, Xgrow_ns, 6, Xgrow_ns, 7, -1, Ygrow_ns_eat, 0, -1, Ygrow_ns_eat, 1, -1, Ygrow_ns_eat, 2, -1, Ygrow_ns_eat, 3, -1, Ygrow_ns_eat, 4, -1, Ygrow_ns_eat, 5, -1, Ygrow_ns_eat, 6, -1, XwonderwallB, 7, Xwonderwall, 0, Xwonderwall, 1, Xwonderwall, 2, Xwonderwall, 3, Xwonderwall, 4, Xwonderwall, 5, Xwonderwall, 6, Xwonderwall, 7, -1, XwonderwallB, 0, -1, XwonderwallB, 1, -1, XwonderwallB, 2, -1, XwonderwallB, 3, -1, XwonderwallB, 4, -1, XwonderwallB, 5, -1, XwonderwallB, 6, -1, Xamoeba_1, 0, Xamoeba_1, 1, Xamoeba_1, 2, Xamoeba_1, 3, Xamoeba_1, 4, Xamoeba_1, 5, Xamoeba_1, 6, Xamoeba_1, 7, -1, Xamoeba_2, 0, Xamoeba_2, 1, Xamoeba_2, 2, Xamoeba_2, 3, Xamoeba_2, 4, Xamoeba_2, 5, Xamoeba_2, 6, Xamoeba_2, 7, -1, Xamoeba_3, 0, Xamoeba_3, 1, Xamoeba_3, 2, Xamoeba_3, 3, Xamoeba_3, 4, Xamoeba_3, 5, Xamoeba_3, 6, Xamoeba_3, 7, -1, Xamoeba_4, 0, Xamoeba_4, 1, Xamoeba_4, 2, Xamoeba_4, 3, Xamoeba_4, 4, Xamoeba_4, 5, Xamoeba_4, 6, Xamoeba_4, 7, -1, Xamoeba_5, 0, Xamoeba_5, 1, Xamoeba_5, 2, Xamoeba_5, 3, Xamoeba_5, 4, Xamoeba_5, 5, Xamoeba_5, 6, Xamoeba_5, 7, -1, Xamoeba_6, 0, Xamoeba_6, 1, Xamoeba_6, 2, Xamoeba_6, 3, Xamoeba_6, 4, Xamoeba_6, 5, Xamoeba_6, 6, Xamoeba_6, 7, -1, Xamoeba_7, 0, Xamoeba_7, 1, Xamoeba_7, 2, Xamoeba_7, 3, Xamoeba_7, 4, Xamoeba_7, 5, Xamoeba_7, 6, Xamoeba_7, 7, -1, Xamoeba_8, 0, Xamoeba_8, 1, Xamoeba_8, 2, Xamoeba_8, 3, Xamoeba_8, 4, Xamoeba_8, 5, Xamoeba_8, 6, Xamoeba_8, 7, -1, Xdoor_1, 0, Xdoor_1, 1, Xdoor_1, 2, Xdoor_1, 3, Xdoor_1, 4, Xdoor_1, 5, Xdoor_1, 6, Xdoor_1, 7, -1, Xdoor_2, 0, Xdoor_2, 1, Xdoor_2, 2, Xdoor_2, 3, Xdoor_2, 4, Xdoor_2, 5, Xdoor_2, 6, Xdoor_2, 7, -1, Xdoor_3, 0, Xdoor_3, 1, Xdoor_3, 2, Xdoor_3, 3, Xdoor_3, 4, Xdoor_3, 5, Xdoor_3, 6, Xdoor_3, 7, -1, Xdoor_4, 0, Xdoor_4, 1, Xdoor_4, 2, Xdoor_4, 3, Xdoor_4, 4, Xdoor_4, 5, Xdoor_4, 6, Xdoor_4, 7, -1, Xdoor_5, 0, Xdoor_5, 1, Xdoor_5, 2, Xdoor_5, 3, Xdoor_5, 4, Xdoor_5, 5, Xdoor_5, 6, Xdoor_5, 7, -1, Xdoor_6, 0, Xdoor_6, 1, Xdoor_6, 2, Xdoor_6, 3, Xdoor_6, 4, Xdoor_6, 5, Xdoor_6, 6, Xdoor_6, 7, -1, Xdoor_7, 0, Xdoor_7, 1, Xdoor_7, 2, Xdoor_7, 3, Xdoor_7, 4, Xdoor_7, 5, Xdoor_7, 6, Xdoor_7, 7, -1, Xdoor_8, 0, Xdoor_8, 1, Xdoor_8, 2, Xdoor_8, 3, Xdoor_8, 4, Xdoor_8, 5, Xdoor_8, 6, Xdoor_8, 7, -1, Xkey_1, 0, Xkey_1, 1, Xkey_1, 2, Xkey_1, 3, Xkey_1, 4, Xkey_1, 5, Xkey_1, 6, Xkey_1, 7, -1, Xkey_2, 0, Xkey_2, 1, Xkey_2, 2, Xkey_2, 3, Xkey_2, 4, Xkey_2, 5, Xkey_2, 6, Xkey_2, 7, -1, Xkey_3, 0, Xkey_3, 1, Xkey_3, 2, Xkey_3, 3, Xkey_3, 4, Xkey_3, 5, Xkey_3, 6, Xkey_3, 7, -1, Xkey_4, 0, Xkey_4, 1, Xkey_4, 2, Xkey_4, 3, Xkey_4, 4, Xkey_4, 5, Xkey_4, 6, Xkey_4, 7, -1, Xkey_5, 0, Xkey_5, 1, Xkey_5, 2, Xkey_5, 3, Xkey_5, 4, Xkey_5, 5, Xkey_5, 6, Xkey_5, 7, -1, Xkey_6, 0, Xkey_6, 1, Xkey_6, 2, Xkey_6, 3, Xkey_6, 4, Xkey_6, 5, Xkey_6, 6, Xkey_6, 7, -1, Xkey_7, 0, Xkey_7, 1, Xkey_7, 2, Xkey_7, 3, Xkey_7, 4, Xkey_7, 5, Xkey_7, 6, Xkey_7, 7, -1, Xkey_8, 0, Xkey_8, 1, Xkey_8, 2, Xkey_8, 3, Xkey_8, 4, Xkey_8, 5, Xkey_8, 6, Xkey_8, 7, -1, Xwind_n, 0, Xwind_n, 1, Xwind_n, 2, Xwind_n, 3, Xwind_n, 4, Xwind_n, 5, Xwind_n, 6, Xwind_n, 7, -1, Xwind_e, 0, Xwind_e, 1, Xwind_e, 2, Xwind_e, 3, Xwind_e, 4, Xwind_e, 5, Xwind_e, 6, Xwind_e, 7, -1, Xwind_s, 0, Xwind_s, 1, Xwind_s, 2, Xwind_s, 3, Xwind_s, 4, Xwind_s, 5, Xwind_s, 6, Xwind_s, 7, -1, Xwind_w, 0, Xwind_w, 1, Xwind_w, 2, Xwind_w, 3, Xwind_w, 4, Xwind_w, 5, Xwind_w, 6, Xwind_w, 7, -1, Xwind_nesw, 0, Xwind_nesw, 1, Xwind_nesw, 2, Xwind_nesw, 3, Xwind_nesw, 4, Xwind_nesw, 5, Xwind_nesw, 6, Xwind_nesw, 7, -1, Xwind_stop, 0, Xwind_stop, 1, Xwind_stop, 2, Xwind_stop, 3, Xwind_stop, 4, Xwind_stop, 5, Xwind_stop, 6, Xwind_stop, 7, -1, Xexit, 0, Xexit, 1, Xexit, 2, Xexit, 3, Xexit, 4, Xexit, 5, Xexit, 6, Xexit, 7, -1, Xexit_1, 0, Xexit_1, 1, Xexit_1, 2, -1, Xexit_1, 3, Xexit_1, 4, Xexit_1, 5, Xexit_3, 7, Xexit_3, 6, Xexit_3, 5, -1, Xexit_1, 6, Xexit_1, 7, Xexit_2, 0, Xexit_3, 4, Xexit_3, 3, Xexit_3, 2, -1, Xexit_2, 1, Xexit_2, 2, Xexit_2, 3, Xexit_3, 1, Xexit_3, 0, Xexit_2, 7, -1, Xexit_2, 4, Xexit_2, 5, Xexit_2, 6, -1, Ydynamite_eat, 0, Ydynamite_eat, 1, Ydynamite_eat, 2, Xdynamite, 0, Xdynamite, 1, Xdynamite, 2, Xdynamite, 3, Xdynamite, 4, Xdynamite, 5, Xdynamite, 6, Xdynamite, 7, -1, Xdynamite_4, 0, Xdynamite_4, 1, Xdynamite_4, 2, Xdynamite_4, 3, Xdynamite_4, 4, Xdynamite_4, 5, Xdynamite_4, 6, Xdynamite_4, 7, -1, Xdynamite_3, 0, Xdynamite_3, 1, Xdynamite_3, 2, Xdynamite_3, 3, Xdynamite_3, 4, Xdynamite_3, 5, Xdynamite_3, 6, Xdynamite_3, 7, -1, Xdynamite_2, 0, Xdynamite_2, 1, Xdynamite_2, 2, Xdynamite_2, 3, Xdynamite_2, 4, Xdynamite_2, 5, Xdynamite_2, 6, Xdynamite_2, 7, -1, Xdynamite_1, 0, Xdynamite_1, 1, Xdynamite_1, 2, Xdynamite_1, 3, Xdynamite_1, 4, Xdynamite_1, 5, Xdynamite_1, 6, Xdynamite_1, 7, -1, Xbumper, 0, Xbumper, 1, Xbumper, 2, Xbumper, 3, Xbumper, 4, Xbumper, 5, Xbumper, 6, Xbumper, 7, XbumperB, 0, XbumperB, 7, -1, XbumperB, 1, XbumperB, 6, -1, XbumperB, 2, XbumperB, 5, -1, XbumperB, 3, XbumperB, 4, -1, Xwheel, 0, Xwheel, 1, Xwheel, 2, Xwheel, 3, Xwheel, 4, Xwheel, 5, Xwheel, 6, Xwheel, 7, XwheelB, 7, XwheelB, 6, XwheelB, 5, XwheelB, 4, -1, XwheelB, 3, XwheelB, 2, XwheelB, 1, XwheelB, 0, -1, XswitchB, 0, XswitchB, 1, XswitchB, 2, XswitchB, 3, XswitchB, 4, XswitchB, 5, XswitchB, 6, XswitchB, 7, -1, Xswitch, 0, Xswitch, 1, Xswitch, 2, Xswitch, 3, Xswitch, 4, Xswitch, 5, Xswitch, 6, Xswitch, 7, -1, Xsand, 0, Xsand, 1, Xsand, 2, Xsand, 3, Xsand, 4, Xsand, 5, Xsand, 6, Xsand, 7, Xsand_stone, 0, Xsand_stone, 1, Xsand_stone, 2, Xsand_stone, 3, Xsand_stone, 4, Xsand_stone, 5, Xsand_stone, 6, Xsand_stone, 7, Xsand_stonesand_1, 0, Xsand_stonesand_1, 1, Xsand_stonesand_1, 2, Xsand_stonesand_1, 3, Xsand_stonesand_1, 4, Xsand_stonesand_1, 5, Xsand_stonesand_1, 6, Xsand_stonesand_1, 7, Xsand_stonesand_2, 0, Xsand_stonesand_2, 1, Xsand_stonesand_2, 2, Xsand_stonesand_2, 3, Xsand_stonesand_2, 4, Xsand_stonesand_2, 5, Xsand_stonesand_2, 6, Xsand_stonesand_2, 7, Xsand_stonesand_3, 0, Xsand_stonesand_3, 1, Xsand_stonesand_3, 2, Xsand_stonesand_3, 3, Xsand_stonesand_3, 4, Xsand_stonesand_3, 5, Xsand_stonesand_3, 6, Xsand_stonesand_3, 7, Xsand_stonesand_4, 0, Xsand_stonesand_4, 1, Xsand_stonesand_4, 2, Xsand_stonesand_4, 3, Xsand_stonesand_4, 4, Xsand_stonesand_4, 5, Xsand_stonesand_4, 6, Xsand_stonesand_4, 7, Xsand_sandstone_1, 0, Xsand_sandstone_1, 1, Xsand_sandstone_1, 2, Xsand_sandstone_1, 3, Xsand_sandstone_1, 4, Xsand_sandstone_1, 5, Xsand_sandstone_1, 6, Xsand_sandstone_1, 7, Xsand_sandstone_2, 0, Xsand_sandstone_2, 1, Xsand_sandstone_2, 2, Xsand_sandstone_2, 3, Xsand_sandstone_2, 4, Xsand_sandstone_2, 5, Xsand_sandstone_2, 6, Xsand_sandstone_2, 7, Xsand_sandstone_3, 0, Xsand_sandstone_3, 1, Xsand_sandstone_3, 2, Xsand_sandstone_3, 3, Xsand_sandstone_3, 4, Xsand_sandstone_3, 5, Xsand_sandstone_3, 6, Xsand_sandstone_3, 7, Xsand_sandstone_4, 0, Xsand_sandstone_4, 1, Xsand_sandstone_4, 2, Xsand_sandstone_4, 3, Xsand_sandstone_4, 4, Xsand_sandstone_4, 5, Xsand_sandstone_4, 6, Xsand_sandstone_4, 7, -1, Xplant, 0, Xplant, 1, Xplant, 2, Xplant, 3, Xplant, 4, Xplant, 5, Xplant, 6, Xplant, 7, Yplant, 0, Yplant, 1, Yplant, 2, Yplant, 3, Yplant, 4, Yplant, 5, Yplant, 6, Yplant, 7, -1, Xlenses, 0, Xlenses, 1, Xlenses, 2, Xlenses, 3, Xlenses, 4, Xlenses, 5, Xlenses, 6, Xlenses, 7, -1, Xmagnify, 0, Xmagnify, 1, Xmagnify, 2, Xmagnify, 3, Xmagnify, 4, Xmagnify, 5, Xmagnify, 6, Xmagnify, 7, -1, XdripperB, 0, XdripperB, 1, XdripperB, 2, XdripperB, 3, XdripperB, 4, XdripperB, 5, XdripperB, 6, XdripperB, 7, -1, Xfake_blankB, 0, Xfake_blankB, 1, Xfake_blankB, 2, Xfake_blankB, 3, Xfake_blankB, 4, Xfake_blankB, 5, Xfake_blankB, 6, Xfake_blankB, 7, -1, Xfake_grassB, 0, Xfake_grassB, 1, Xfake_grassB, 2, Xfake_grassB, 3, Xfake_grassB, 4, Xfake_grassB, 5, Xfake_grassB, 6, Xfake_grassB, 7, -1, Xfake_door_1, 0, Xfake_door_1, 1, Xfake_door_1, 2, Xfake_door_1, 3, Xfake_door_1, 4, Xfake_door_1, 5, Xfake_door_1, 6, Xfake_door_1, 7, Xfake_door_2, 0, Xfake_door_2, 1, Xfake_door_2, 2, Xfake_door_2, 3, Xfake_door_2, 4, Xfake_door_2, 5, Xfake_door_2, 6, Xfake_door_2, 7, Xfake_door_3, 0, Xfake_door_3, 1, Xfake_door_3, 2, Xfake_door_3, 3, Xfake_door_3, 4, Xfake_door_3, 5, Xfake_door_3, 6, Xfake_door_3, 7, Xfake_door_4, 0, Xfake_door_4, 1, Xfake_door_4, 2, Xfake_door_4, 3, Xfake_door_4, 4, Xfake_door_4, 5, Xfake_door_4, 6, Xfake_door_4, 7, Xfake_door_5, 0, Xfake_door_5, 1, Xfake_door_5, 2, Xfake_door_5, 3, Xfake_door_5, 4, Xfake_door_5, 5, Xfake_door_5, 6, Xfake_door_5, 7, Xfake_door_6, 0, Xfake_door_6, 1, Xfake_door_6, 2, Xfake_door_6, 3, Xfake_door_6, 4, Xfake_door_6, 5, Xfake_door_6, 6, Xfake_door_6, 7, Xfake_door_7, 0, Xfake_door_7, 1, Xfake_door_7, 2, Xfake_door_7, 3, Xfake_door_7, 4, Xfake_door_7, 5, Xfake_door_7, 6, Xfake_door_7, 7, Xfake_door_8, 0, Xfake_door_8, 1, Xfake_door_8, 2, Xfake_door_8, 3, Xfake_door_8, 4, Xfake_door_8, 5, Xfake_door_8, 6, Xfake_door_8, 7, -1, Xsteel_1, 0, Xsteel_1, 1, Xsteel_1, 2, Xsteel_1, 3, Xsteel_1, 4, Xsteel_1, 5, Xsteel_1, 6, Xsteel_1, 7, -1, Xsteel_2, 0, Xsteel_2, 1, Xsteel_2, 2, Xsteel_2, 3, Xsteel_2, 4, Xsteel_2, 5, Xsteel_2, 6, Xsteel_2, 7, -1, Xsteel_3, 0, Xsteel_3, 1, Xsteel_3, 2, Xsteel_3, 3, Xsteel_3, 4, Xsteel_3, 5, Xsteel_3, 6, Xsteel_3, 7, -1, Xsteel_4, 0, Xsteel_4, 1, Xsteel_4, 2, Xsteel_4, 3, Xsteel_4, 4, Xsteel_4, 5, Xsteel_4, 6, Xsteel_4, 7, -1, Xwall_1, 0, Xwall_1, 1, Xwall_1, 2, Xwall_1, 3, Xwall_1, 4, Xwall_1, 5, Xwall_1, 6, Xwall_1, 7, -1, Xwall_2, 0, Xwall_2, 1, Xwall_2, 2, Xwall_2, 3, Xwall_2, 4, Xwall_2, 5, Xwall_2, 6, Xwall_2, 7, -1, Xwall_3, 0, Xwall_3, 1, Xwall_3, 2, Xwall_3, 3, Xwall_3, 4, Xwall_3, 5, Xwall_3, 6, Xwall_3, 7, -1, Xwall_4, 0, Xwall_4, 1, Xwall_4, 2, Xwall_4, 3, Xwall_4, 4, Xwall_4, 5, Xwall_4, 6, Xwall_4, 7, -1, Xround_wall_1, 0, Xround_wall_1, 1, Xround_wall_1, 2, Xround_wall_1, 3, Xround_wall_1, 4, Xround_wall_1, 5, Xround_wall_1, 6, Xround_wall_1, 7, -1, Xround_wall_2, 0, Xround_wall_2, 1, Xround_wall_2, 2, Xround_wall_2, 3, Xround_wall_2, 4, Xround_wall_2, 5, Xround_wall_2, 6, Xround_wall_2, 7, -1, Xround_wall_3, 0, Xround_wall_3, 1, Xround_wall_3, 2, Xround_wall_3, 3, Xround_wall_3, 4, Xround_wall_3, 5, Xround_wall_3, 6, Xround_wall_3, 7, -1, Xround_wall_4, 0, Xround_wall_4, 1, Xround_wall_4, 2, Xround_wall_4, 3, Xround_wall_4, 4, Xround_wall_4, 5, Xround_wall_4, 6, Xround_wall_4, 7, -1, Xdecor_1, 0, Xdecor_1, 1, Xdecor_1, 2, Xdecor_1, 3, Xdecor_1, 4, Xdecor_1, 5, Xdecor_1, 6, Xdecor_1, 7, -1, Xdecor_2, 0, Xdecor_2, 1, Xdecor_2, 2, Xdecor_2, 3, Xdecor_2, 4, Xdecor_2, 5, Xdecor_2, 6, Xdecor_2, 7, -1, Xdecor_3, 0, Xdecor_3, 1, Xdecor_3, 2, Xdecor_3, 3, Xdecor_3, 4, Xdecor_3, 5, Xdecor_3, 6, Xdecor_3, 7, -1, Xdecor_4, 0, Xdecor_4, 1, Xdecor_4, 2, Xdecor_4, 3, Xdecor_4, 4, Xdecor_4, 5, Xdecor_4, 6, Xdecor_4, 7, -1, Xdecor_5, 0, Xdecor_5, 1, Xdecor_5, 2, Xdecor_5, 3, Xdecor_5, 4, Xdecor_5, 5, Xdecor_5, 6, Xdecor_5, 7, -1, Xdecor_6, 0, Xdecor_6, 1, Xdecor_6, 2, Xdecor_6, 3, Xdecor_6, 4, Xdecor_6, 5, Xdecor_6, 6, Xdecor_6, 7, -1, Xdecor_7, 0, Xdecor_7, 1, Xdecor_7, 2, Xdecor_7, 3, Xdecor_7, 4, Xdecor_7, 5, Xdecor_7, 6, Xdecor_7, 7, -1, Xdecor_8, 0, Xdecor_8, 1, Xdecor_8, 2, Xdecor_8, 3, Xdecor_8, 4, Xdecor_8, 5, Xdecor_8, 6, Xdecor_8, 7, -1, Xdecor_9, 0, Xdecor_9, 1, Xdecor_9, 2, Xdecor_9, 3, Xdecor_9, 4, Xdecor_9, 5, Xdecor_9, 6, Xdecor_9, 7, -1, Xdecor_10, 0, Xdecor_10, 1, Xdecor_10, 2, Xdecor_10, 3, Xdecor_10, 4, Xdecor_10, 5, Xdecor_10, 6, Xdecor_10, 7, -1, Xdecor_11, 0, Xdecor_11, 1, Xdecor_11, 2, Xdecor_11, 3, Xdecor_11, 4, Xdecor_11, 5, Xdecor_11, 6, Xdecor_11, 7, -1, Xdecor_12, 0, Xdecor_12, 1, Xdecor_12, 2, Xdecor_12, 3, Xdecor_12, 4, Xdecor_12, 5, Xdecor_12, 6, Xdecor_12, 7, -1, Xalpha_excla, 0, Xalpha_excla, 1, Xalpha_excla, 2, Xalpha_excla, 3, Xalpha_excla, 4, Xalpha_excla, 5, Xalpha_excla, 6, Xalpha_excla, 7, -1, Xalpha_quote, 0, Xalpha_quote, 1, Xalpha_quote, 2, Xalpha_quote, 3, Xalpha_quote, 4, Xalpha_quote, 5, Xalpha_quote, 6, Xalpha_quote, 7, -1, Xalpha_comma, 0, Xalpha_comma, 1, Xalpha_comma, 2, Xalpha_comma, 3, Xalpha_comma, 4, Xalpha_comma, 5, Xalpha_comma, 6, Xalpha_comma, 7, -1, Xalpha_minus, 0, Xalpha_minus, 1, Xalpha_minus, 2, Xalpha_minus, 3, Xalpha_minus, 4, Xalpha_minus, 5, Xalpha_minus, 6, Xalpha_minus, 7, -1, Xalpha_perio, 0, Xalpha_perio, 1, Xalpha_perio, 2, Xalpha_perio, 3, Xalpha_perio, 4, Xalpha_perio, 5, Xalpha_perio, 6, Xalpha_perio, 7, -1, Xalpha_0, 0, Xalpha_0, 1, Xalpha_0, 2, Xalpha_0, 3, Xalpha_0, 4, Xalpha_0, 5, Xalpha_0, 6, Xalpha_0, 7, -1, Xalpha_1, 0, Xalpha_1, 1, Xalpha_1, 2, Xalpha_1, 3, Xalpha_1, 4, Xalpha_1, 5, Xalpha_1, 6, Xalpha_1, 7, -1, Xalpha_2, 0, Xalpha_2, 1, Xalpha_2, 2, Xalpha_2, 3, Xalpha_2, 4, Xalpha_2, 5, Xalpha_2, 6, Xalpha_2, 7, -1, Xalpha_3, 0, Xalpha_3, 1, Xalpha_3, 2, Xalpha_3, 3, Xalpha_3, 4, Xalpha_3, 5, Xalpha_3, 6, Xalpha_3, 7, -1, Xalpha_4, 0, Xalpha_4, 1, Xalpha_4, 2, Xalpha_4, 3, Xalpha_4, 4, Xalpha_4, 5, Xalpha_4, 6, Xalpha_4, 7, -1, Xalpha_5, 0, Xalpha_5, 1, Xalpha_5, 2, Xalpha_5, 3, Xalpha_5, 4, Xalpha_5, 5, Xalpha_5, 6, Xalpha_5, 7, -1, Xalpha_6, 0, Xalpha_6, 1, Xalpha_6, 2, Xalpha_6, 3, Xalpha_6, 4, Xalpha_6, 5, Xalpha_6, 6, Xalpha_6, 7, -1, Xalpha_7, 0, Xalpha_7, 1, Xalpha_7, 2, Xalpha_7, 3, Xalpha_7, 4, Xalpha_7, 5, Xalpha_7, 6, Xalpha_7, 7, -1, Xalpha_8, 0, Xalpha_8, 1, Xalpha_8, 2, Xalpha_8, 3, Xalpha_8, 4, Xalpha_8, 5, Xalpha_8, 6, Xalpha_8, 7, -1, Xalpha_9, 0, Xalpha_9, 1, Xalpha_9, 2, Xalpha_9, 3, Xalpha_9, 4, Xalpha_9, 5, Xalpha_9, 6, Xalpha_9, 7, -1, Xalpha_colon, 0, Xalpha_colon, 1, Xalpha_colon, 2, Xalpha_colon, 3, Xalpha_colon, 4, Xalpha_colon, 5, Xalpha_colon, 6, Xalpha_colon, 7, -1, Xalpha_arrow_w, 0, Xalpha_arrow_w, 1, Xalpha_arrow_w, 2, Xalpha_arrow_w, 3, Xalpha_arrow_w, 4, Xalpha_arrow_w, 5, Xalpha_arrow_w, 6, Xalpha_arrow_w, 7, -1, Xalpha_arrow_e, 0, Xalpha_arrow_e, 1, Xalpha_arrow_e, 2, Xalpha_arrow_e, 3, Xalpha_arrow_e, 4, Xalpha_arrow_e, 5, Xalpha_arrow_e, 6, Xalpha_arrow_e, 7, -1, Xalpha_quest, 0, Xalpha_quest, 1, Xalpha_quest, 2, Xalpha_quest, 3, Xalpha_quest, 4, Xalpha_quest, 5, Xalpha_quest, 6, Xalpha_quest, 7, -1, Xalpha_a, 0, Xalpha_a, 1, Xalpha_a, 2, Xalpha_a, 3, Xalpha_a, 4, Xalpha_a, 5, Xalpha_a, 6, Xalpha_a, 7, -1, Xalpha_b, 0, Xalpha_b, 1, Xalpha_b, 2, Xalpha_b, 3, Xalpha_b, 4, Xalpha_b, 5, Xalpha_b, 6, Xalpha_b, 7, -1, Xalpha_c, 0, Xalpha_c, 1, Xalpha_c, 2, Xalpha_c, 3, Xalpha_c, 4, Xalpha_c, 5, Xalpha_c, 6, Xalpha_c, 7, -1, Xalpha_d, 0, Xalpha_d, 1, Xalpha_d, 2, Xalpha_d, 3, Xalpha_d, 4, Xalpha_d, 5, Xalpha_d, 6, Xalpha_d, 7, -1, Xalpha_e, 0, Xalpha_e, 1, Xalpha_e, 2, Xalpha_e, 3, Xalpha_e, 4, Xalpha_e, 5, Xalpha_e, 6, Xalpha_e, 7, -1, Xalpha_f, 0, Xalpha_f, 1, Xalpha_f, 2, Xalpha_f, 3, Xalpha_f, 4, Xalpha_f, 5, Xalpha_f, 6, Xalpha_f, 7, -1, Xalpha_g, 0, Xalpha_g, 1, Xalpha_g, 2, Xalpha_g, 3, Xalpha_g, 4, Xalpha_g, 5, Xalpha_g, 6, Xalpha_g, 7, -1, Xalpha_h, 0, Xalpha_h, 1, Xalpha_h, 2, Xalpha_h, 3, Xalpha_h, 4, Xalpha_h, 5, Xalpha_h, 6, Xalpha_h, 7, -1, Xalpha_i, 0, Xalpha_i, 1, Xalpha_i, 2, Xalpha_i, 3, Xalpha_i, 4, Xalpha_i, 5, Xalpha_i, 6, Xalpha_i, 7, -1, Xalpha_j, 0, Xalpha_j, 1, Xalpha_j, 2, Xalpha_j, 3, Xalpha_j, 4, Xalpha_j, 5, Xalpha_j, 6, Xalpha_j, 7, -1, Xalpha_k, 0, Xalpha_k, 1, Xalpha_k, 2, Xalpha_k, 3, Xalpha_k, 4, Xalpha_k, 5, Xalpha_k, 6, Xalpha_k, 7, -1, Xalpha_l, 0, Xalpha_l, 1, Xalpha_l, 2, Xalpha_l, 3, Xalpha_l, 4, Xalpha_l, 5, Xalpha_l, 6, Xalpha_l, 7, -1, Xalpha_m, 0, Xalpha_m, 1, Xalpha_m, 2, Xalpha_m, 3, Xalpha_m, 4, Xalpha_m, 5, Xalpha_m, 6, Xalpha_m, 7, -1, Xalpha_n, 0, Xalpha_n, 1, Xalpha_n, 2, Xalpha_n, 3, Xalpha_n, 4, Xalpha_n, 5, Xalpha_n, 6, Xalpha_n, 7, -1, Xalpha_o, 0, Xalpha_o, 1, Xalpha_o, 2, Xalpha_o, 3, Xalpha_o, 4, Xalpha_o, 5, Xalpha_o, 6, Xalpha_o, 7, -1, Xalpha_p, 0, Xalpha_p, 1, Xalpha_p, 2, Xalpha_p, 3, Xalpha_p, 4, Xalpha_p, 5, Xalpha_p, 6, Xalpha_p, 7, -1, Xalpha_q, 0, Xalpha_q, 1, Xalpha_q, 2, Xalpha_q, 3, Xalpha_q, 4, Xalpha_q, 5, Xalpha_q, 6, Xalpha_q, 7, -1, Xalpha_r, 0, Xalpha_r, 1, Xalpha_r, 2, Xalpha_r, 3, Xalpha_r, 4, Xalpha_r, 5, Xalpha_r, 6, Xalpha_r, 7, -1, Xalpha_s, 0, Xalpha_s, 1, Xalpha_s, 2, Xalpha_s, 3, Xalpha_s, 4, Xalpha_s, 5, Xalpha_s, 6, Xalpha_s, 7, -1, Xalpha_t, 0, Xalpha_t, 1, Xalpha_t, 2, Xalpha_t, 3, Xalpha_t, 4, Xalpha_t, 5, Xalpha_t, 6, Xalpha_t, 7, -1, Xalpha_u, 0, Xalpha_u, 1, Xalpha_u, 2, Xalpha_u, 3, Xalpha_u, 4, Xalpha_u, 5, Xalpha_u, 6, Xalpha_u, 7, -1, Xalpha_v, 0, Xalpha_v, 1, Xalpha_v, 2, Xalpha_v, 3, Xalpha_v, 4, Xalpha_v, 5, Xalpha_v, 6, Xalpha_v, 7, -1, Xalpha_w, 0, Xalpha_w, 1, Xalpha_w, 2, Xalpha_w, 3, Xalpha_w, 4, Xalpha_w, 5, Xalpha_w, 6, Xalpha_w, 7, -1, Xalpha_x, 0, Xalpha_x, 1, Xalpha_x, 2, Xalpha_x, 3, Xalpha_x, 4, Xalpha_x, 5, Xalpha_x, 6, Xalpha_x, 7, -1, Xalpha_y, 0, Xalpha_y, 1, Xalpha_y, 2, Xalpha_y, 3, Xalpha_y, 4, Xalpha_y, 5, Xalpha_y, 6, Xalpha_y, 7, -1, Xalpha_z, 0, Xalpha_z, 1, Xalpha_z, 2, Xalpha_z, 3, Xalpha_z, 4, Xalpha_z, 5, Xalpha_z, 6, Xalpha_z, 7, -1, Xalpha_copyr, 0, Xalpha_copyr, 1, Xalpha_copyr, 2, Xalpha_copyr, 3, Xalpha_copyr, 4, Xalpha_copyr, 5, Xalpha_copyr, 6, Xalpha_copyr, 7, -1, Yball_eat, 7, Yball_eat, 6, Yball_eat, 5, Ykey_1_eat, 7, Ykey_1_eat, 6, Ykey_1_eat, 5, Ykey_2_eat, 7, Ykey_2_eat, 6, Ykey_2_eat, 5, Ykey_3_eat, 7, Ykey_3_eat, 6, Ykey_3_eat, 5, Ykey_4_eat, 7, Ykey_4_eat, 6, Ykey_4_eat, 5, Ykey_5_eat, 7, Ykey_5_eat, 6, Ykey_5_eat, 5, Ykey_6_eat, 7, Ykey_6_eat, 6, Ykey_6_eat, 5, Ykey_7_eat, 7, Ykey_7_eat, 6, Ykey_7_eat, 5, Ykey_8_eat, 7, Ykey_8_eat, 6, Ykey_8_eat, 5, Ylenses_eat, 7, Ylenses_eat, 6, Ylenses_eat, 5, Ymagnify_eat, 7, Ymagnify_eat, 6, Ymagnify_eat, 5, Ygrass_eat, 7, Ygrass_eat, 6, Ygrass_eat, 5, Ydirt_eat, 7, Ydirt_eat, 6, Ydirt_eat, 5, Xboom_2, 7, Xboom_2, 6, Xboom_2, 5, -1, Yball_eat, 4, Yball_eat, 3, Yball_eat, 2, Ykey_1_eat, 4, Ykey_1_eat, 3, Ykey_1_eat, 2, Ykey_2_eat, 4, Ykey_2_eat, 3, Ykey_2_eat, 2, Ykey_3_eat, 4, Ykey_3_eat, 3, Ykey_3_eat, 2, Ykey_4_eat, 4, Ykey_4_eat, 3, Ykey_4_eat, 2, Ykey_5_eat, 4, Ykey_5_eat, 3, Ykey_5_eat, 2, Ykey_6_eat, 4, Ykey_6_eat, 3, Ykey_6_eat, 2, Ykey_7_eat, 4, Ykey_7_eat, 3, Ykey_7_eat, 2, Ykey_8_eat, 4, Ykey_8_eat, 3, Ykey_8_eat, 2, Ylenses_eat, 4, Ylenses_eat, 3, Ylenses_eat, 2, Ymagnify_eat, 4, Ymagnify_eat, 3, Ymagnify_eat, 2, Ygrass_eat, 4, Ygrass_eat, 3, Ygrass_eat, 2, Ydirt_eat, 4, Ydirt_eat, 3, Ydirt_eat, 2, Xboom_2, 4, Xboom_2, 3, Xboom_2, 2, -1, Yball_eat, 1, Yball_eat, 0, Ykey_1_eat, 1, Ykey_1_eat, 0, Ykey_2_eat, 1, Ykey_2_eat, 0, Ykey_3_eat, 1, Ykey_3_eat, 0, Ykey_4_eat, 1, Ykey_4_eat, 0, Ykey_5_eat, 1, Ykey_5_eat, 0, Ykey_6_eat, 1, Ykey_6_eat, 0, Ykey_7_eat, 1, Ykey_7_eat, 0, Ykey_8_eat, 1, Ykey_8_eat, 0, Ylenses_eat, 1, Ylenses_eat, 0, Ymagnify_eat, 1, Ymagnify_eat, 0, Ygrass_eat, 1, Ygrass_eat, 0, Ydirt_eat, 1, Ydirt_eat, 0, Xboom_2, 1, Xboom_2, 0, Xboom_1, 7, -1, Xboom_1, 6, Xboom_1, 5, Xboom_android, 7, -1, Xboom_1, 4, Xboom_1, 3, Xboom_bug, 4, Xboom_bomb, 4, Xboom_bug, 3, Xboom_bomb, 3, -1, Xboom_1, 2, Xboom_1, 1, Xboom_bug, 6, Xboom_bomb, 6, Xboom_bug, 5, Xboom_bomb, 5, Xboom_bug, 2, Xboom_bomb, 2, Xboom_bug, 1, Xboom_bomb, 1, -1, Xboom_bug, 0, Xboom_bug, 7, Xboom_bomb, 0, Xboom_bomb, 7, Xboom_1, 0, Ybug_stone, 7, Ybug_spring, 7, Ytank_stone, 7, Ytank_spring, 7, Yeater_stone, 7, Yeater_spring, 7, Yalien_stone, 7, Yalien_spring, 7, Ybomb_eat, 7, -1 }; int spr_map[] = { SPR_walk + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, SPR_walk + 1, 0, 8, 9, 10, 11, 12, 13, 14, 15, SPR_walk + 2, 0, 16, 17, 18, 19, 20, 21, 22, 23, SPR_walk + 3, 0, 24, 25, 26, 27, 28, 29, 30, 31, SPR_push + 0, 0, 32, 33, 34, 35, 36, 35, 34, 33, SPR_push + 1, 0, 37, 38, 39, 40, 41, 40, 39, 38, SPR_push + 2, 0, 42, 43, 44, 45, 46, 45, 44, 43, SPR_push + 3, 0, 47, 48, 49, 50, 51, 50, 49, 48, SPR_spray + 0, 0, 52, 52, 52, 52, 52, 52, 52, 52, SPR_spray + 1, 0, 53, 53, 53, 53, 53, 53, 53, 53, SPR_spray + 2, 0, 54, 54, 54, 54, 54, 54, 54, 54, SPR_spray + 3, 0, 55, 55, 55, 55, 55, 55, 55, 55, SPR_walk + 0, 1, 56, 57, 58, 59, 60, 61, 62, 63, SPR_walk + 1, 1, 64, 65, 66, 67, 68, 69, 70, 71, SPR_walk + 2, 1, 72, 73, 74, 75, 76, 77, 78, 79, SPR_walk + 3, 1, 80, 81, 82, 83, 84, 85, 86, 87, SPR_push + 0, 1, 88, 89, 90, 91, 92, 91, 90, 89, SPR_push + 1, 1, 93, 94, 95, 96, 97, 96, 95, 94, SPR_push + 2, 1, 98, 99, 100, 101, 102, 101, 100, 99, SPR_push + 3, 1, 103, 104, 105, 106, 107, 106, 105, 104, SPR_spray + 0, 1, 108, 108, 108, 108, 108, 108, 108, 108, SPR_spray + 1, 1, 109, 109, 109, 109, 109, 109, 109, 109, SPR_spray + 2, 1, 110, 110, 110, 110, 110, 110, 110, 110, SPR_spray + 3, 1, 111, 111, 111, 111, 111, 111, 111, 111, SPR_still, 0, 112,112, 112, 112, 112, 112, 112, 112, SPR_still, 1, 113,113, 113, 113, 113, 113, 113, 113, SPR_MAX }; /* 0=stop 1=blank */ unsigned char tab_blank[TILE_MAX]; /* 0=stop 1=acid */ unsigned char tab_acid[TILE_MAX]; /* 0=stop 1=amoeba */ unsigned char tab_amoeba[TILE_MAX]; /* 0=stop 1=move */ unsigned char tab_android_move[TILE_MAX]; /* normal explosion */ unsigned short tab_explode_normal[TILE_MAX]; /* dynamite explosion */ unsigned short tab_explode_dynamite[TILE_MAX]; /* map tiles to coords */ unsigned short map_obj[8][TILE_MAX]; /* map sprites to coords */ unsigned short map_spr[2][8][13]; /* map ascii to coords */ unsigned short map_ttl[128]; /* map tiles and frames to graphic info */ struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; /* map player number, frames and action to graphic info */ struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; void create_tab(int *invert, unsigned char *array) { int i; int buffer[TILE_MAX]; for (i = 0; i < TILE_MAX; i++) buffer[i] = 0; for (;invert[0] < TILE_MAX; invert += 2) buffer[invert[0]] = invert[1]; for (i = 0; i < TILE_MAX; i++) array[i] = buffer[i]; } void create_explode() { int i; int *tile = tile_explode; int buffer[TILE_MAX]; for (i = 0; i < TILE_MAX; i++) buffer[i] = Xboom_1; while ((i = *tile++) < TILE_MAX) buffer[i] = i; /* these tiles are indestructable */ while ((i = *tile++) < TILE_MAX) buffer[i] = *tile++; /* these tiles are special */ for (i = 0; i < TILE_MAX; i++) tab_explode_normal[i] = buffer[i]; while ((i = *tile++) < TILE_MAX) buffer[i] = *tile++; /* these tiles for dynamite */ for (i = 0; i < TILE_MAX; i++) tab_explode_dynamite[i] = buffer[i]; } void create_obj() { int i, j; int *map = obj_map; int buffer[8][TILE_MAX]; for (i = 0; i < 8; i++) for (j = 0; j < TILE_MAX; j++) buffer[i][j] = Xblank; /* special case for first 64 entries */ for (i = 0; i < 64; i++) { for (;*map != -1; map += 2) buffer[map[1]][map[0]] = i; map++; } /* now regular entries */ for (i = 0; i < 896 * 16; i += 16) { for (;*map != -1; map += 2) buffer[map[1]][map[0]] = i; map++; } for (i = 0; i < 8; i++) for (j = 0; j < TILE_MAX; j++) map_obj[i][j] = buffer[7 - i][j]; } void create_obj_graphics_info_em() { int i, j; for (i = 0; i < TILE_MAX; i++) { for (j = 0; j < 8; j++) { struct GraphicInfo_EM *g = &graphic_info_em_object[i][j]; int obj = map_obj[j][i]; g->bitmap = objBitmap; g->src_x = (obj / 512) * TILEX; g->src_y = (obj % 512) * TILEY / 16; g->src_offset_x = 0; g->src_offset_y = 0; g->dst_offset_x = 0; g->dst_offset_y = 0; g->width = TILEX; g->height = TILEY; g->crumbled_bitmap = NULL; g->crumbled_src_x = 0; g->crumbled_src_y = 0; g->crumbled_border_size = 0; g->crumbled_tile_size = 0; g->has_crumbled_graphics = FALSE; g->preserve_background = FALSE; /* create unique graphic identifier to decide if tile must be redrawn */ g->unique_identifier = obj; } } } void create_spr() { int i, j, k; int *map = spr_map; int buffer[2][8][SPR_MAX]; while (*map < SPR_MAX) { i = *map++; j = *map++; for (k = 0; k < 8; k++) buffer[j][k][i] = *map++; } for (i = 0; i < 2; i++) for (j = 0; j < 8; j++) for (k = 0; k < SPR_MAX; k++) map_spr[i][j][k] = buffer[i][7 - j][k]; } void create_spr_graphics_info_em() { int i, j, k; for (i = 0; i < MAX_PLAYERS; i++) { for (j = 0; j < SPR_MAX; j++) { for (k = 0; k < 8; k++) { struct GraphicInfo_EM *g = &graphic_info_em_player[i][j][k]; int spr = map_spr[i % 2][k][j]; g->bitmap = sprBitmap; g->src_x = (spr / 8) * TILEX; g->src_y = (spr % 8) * TILEY; g->src_offset_x = 0; g->src_offset_y = 0; g->dst_offset_x = 0; g->dst_offset_y = 0; g->width = TILEX; g->height = TILEY; g->has_crumbled_graphics = FALSE; g->crumbled_bitmap = NULL; g->crumbled_src_x = 0; g->crumbled_src_y = 0; g->crumbled_border_size = 0; g->unique_identifier = 0; } } } } void tab_generate() { create_tab(tile_blank, tab_blank); create_tab(tile_acid, tab_acid); create_tab(tile_amoeba, tab_amoeba); create_tab(tile_android_move, tab_android_move); create_explode(); create_obj(); create_spr(); } void tab_generate_graphics_info_em() { create_obj_graphics_info_em(); create_spr_graphics_info_em(); InitGraphicInfo_EM(); } mirrormagic-3.0.0/src/game_em/export.h0000644000175000017500000003750713263212010017210 0ustar aeglosaeglos#ifndef EXPORT_H #define EXPORT_H /* ========================================================================= */ /* functions and definitions exported from game_em to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* define these for backwards compatibility */ #define EM_ENGINE_BAD_ROLL #define EM_ENGINE_BAD_SPRING /* define these to use additional elements */ #define EM_ENGINE_USE_ADDITIONAL_ELEMENTS /* internal definitions for EM engine */ #ifdef EM_ENGINE_BAD_ROLL #define BAD_ROLL #endif #ifdef EM_ENGINE_BAD_SPRING #define BAD_SPRING #endif /* one border for ZBORDER elements, one border for steelwall, if needed */ #define EM_MAX_CAVE_WIDTH (MAX_PLAYFIELD_WIDTH + 2 + 2) #define EM_MAX_CAVE_HEIGHT (MAX_PLAYFIELD_HEIGHT + 2 + 2) /* ----------------------------------------------------------------------------- definition of elements used in the Emerald Mine Club engine; the element names have the following properties: - elements that start with 'X' can be stored in a level file - elements that start with 'Y' indicate moving elements - elements that end with 'B' are the "backside" of moving elements ----------------------------------------------------------------------------- */ enum { Xblank = 0, /* still */ Yacid_splash_eB, /* hmm */ Yacid_splash_wB, /* hmm */ #ifdef EM_ENGINE_BAD_ROLL Xstone_force_e, /* only use these in eater */ Xstone_force_w, Xnut_force_e, Xnut_force_w, Xspring_force_e, Xspring_force_w, Xemerald_force_e, Xemerald_force_w, Xdiamond_force_e, Xdiamond_force_w, Xbomb_force_e, Xbomb_force_w, #endif Xstone, Xstone_pause, Xstone_fall, Ystone_s, Ystone_sB, Ystone_e, Ystone_eB, Ystone_w, Ystone_wB, Xnut, Xnut_pause, Xnut_fall, Ynut_s, Ynut_sB, Ynut_e, Ynut_eB, Ynut_w, Ynut_wB, Xbug_n, Xbug_e, Xbug_s, Xbug_w, Xbug_gon, Xbug_goe, Xbug_gos, Xbug_gow, Ybug_n, Ybug_nB, Ybug_e, Ybug_eB, Ybug_s, Ybug_sB, Ybug_w, Ybug_wB, Ybug_w_n, Ybug_n_e, Ybug_e_s, Ybug_s_w, Ybug_e_n, Ybug_s_e, Ybug_w_s, Ybug_n_w, Ybug_stone, Ybug_spring, Xtank_n, Xtank_e, Xtank_s, Xtank_w, Xtank_gon, Xtank_goe, Xtank_gos, Xtank_gow, Ytank_n, Ytank_nB, Ytank_e, Ytank_eB, Ytank_s, Ytank_sB, Ytank_w, Ytank_wB, Ytank_w_n, Ytank_n_e, Ytank_e_s, Ytank_s_w, Ytank_e_n, Ytank_s_e, Ytank_w_s, Ytank_n_w, Ytank_stone, Ytank_spring, Xandroid, Xandroid_1_n, Xandroid_2_n, Xandroid_1_e, Xandroid_2_e, Xandroid_1_w, Xandroid_2_w, Xandroid_1_s, Xandroid_2_s, Yandroid_n, Yandroid_nB, Yandroid_ne, Yandroid_neB, Yandroid_e, Yandroid_eB, Yandroid_se, Yandroid_seB, Yandroid_s, Yandroid_sB, Yandroid_sw, Yandroid_swB, Yandroid_w, Yandroid_wB, Yandroid_nw, Yandroid_nwB, Xspring, Xspring_pause, Xspring_e, Xspring_w, Xspring_fall, Yspring_s, Yspring_sB, Yspring_e, Yspring_eB, Yspring_w, Yspring_wB, Yspring_kill_e, Yspring_kill_eB, Yspring_kill_w, Yspring_kill_wB, Xeater_n, Xeater_e, Xeater_w, Xeater_s, Yeater_n, Yeater_nB, Yeater_e, Yeater_eB, Yeater_s, Yeater_sB, Yeater_w, Yeater_wB, Yeater_stone, Yeater_spring, Xalien, Xalien_pause, Yalien_n, Yalien_nB, Yalien_e, Yalien_eB, Yalien_s, Yalien_sB, Yalien_w, Yalien_wB, Yalien_stone, Yalien_spring, Xemerald, Xemerald_pause, Xemerald_fall, Xemerald_shine, Yemerald_s, Yemerald_sB, Yemerald_e, Yemerald_eB, Yemerald_w, Yemerald_wB, Yemerald_eat, Yemerald_stone, Xdiamond, Xdiamond_pause, Xdiamond_fall, Xdiamond_shine, Ydiamond_s, Ydiamond_sB, Ydiamond_e, Ydiamond_eB, Ydiamond_w, Ydiamond_wB, Ydiamond_eat, Ydiamond_stone, Xdrip_fall, Xdrip_stretch, Xdrip_stretchB, Xdrip_eat, Ydrip_s1, Ydrip_s1B, Ydrip_s2, Ydrip_s2B, Xbomb, Xbomb_pause, Xbomb_fall, Ybomb_s, Ybomb_sB, Ybomb_e, Ybomb_eB, Ybomb_w, Ybomb_wB, Ybomb_eat, Xballoon, Yballoon_n, Yballoon_nB, Yballoon_e, Yballoon_eB, Yballoon_s, Yballoon_sB, Yballoon_w, Yballoon_wB, Xgrass, Ygrass_nB, Ygrass_eB, Ygrass_sB, Ygrass_wB, Xdirt, Ydirt_nB, Ydirt_eB, Ydirt_sB, Ydirt_wB, Xacid_ne, Xacid_se, Xacid_s, Xacid_sw, Xacid_nw, Xacid_1, Xacid_2, Xacid_3, Xacid_4, Xacid_5, Xacid_6, Xacid_7, Xacid_8, Xball_1, Xball_1B, Xball_2, Xball_2B, Yball_eat, #ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS Ykey_1_eat, Ykey_2_eat, Ykey_3_eat, Ykey_4_eat, Ykey_5_eat, Ykey_6_eat, Ykey_7_eat, Ykey_8_eat, Ylenses_eat, Ymagnify_eat, Ygrass_eat, Ydirt_eat, #endif Xgrow_ns, Ygrow_ns_eat, Xgrow_ew, Ygrow_ew_eat, Xwonderwall, XwonderwallB, Xamoeba_1, Xamoeba_2, Xamoeba_3, Xamoeba_4, Xamoeba_5, Xamoeba_6, Xamoeba_7, Xamoeba_8, Xdoor_1, Xdoor_2, Xdoor_3, Xdoor_4, Xdoor_5, Xdoor_6, Xdoor_7, Xdoor_8, Xkey_1, Xkey_2, Xkey_3, Xkey_4, Xkey_5, Xkey_6, Xkey_7, Xkey_8, Xwind_n, Xwind_e, Xwind_s, Xwind_w, Xwind_nesw, Xwind_stop, Xexit, Xexit_1, Xexit_2, Xexit_3, Xdynamite, Ydynamite_eat, Xdynamite_1, Xdynamite_2, Xdynamite_3, Xdynamite_4, Xbumper, XbumperB, Xwheel, XwheelB, Xswitch, XswitchB, Xsand, Xsand_stone, Xsand_stonein_1, Xsand_stonein_2, Xsand_stonein_3, Xsand_stonein_4, Xsand_stonesand_1, Xsand_stonesand_2, Xsand_stonesand_3, Xsand_stonesand_4, #ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS Xsand_stonesand_quickout_1, Xsand_stonesand_quickout_2, #endif Xsand_stoneout_1, Xsand_stoneout_2, Xsand_sandstone_1, Xsand_sandstone_2, Xsand_sandstone_3, Xsand_sandstone_4, Xplant, Yplant, Xlenses, Xmagnify, Xdripper, XdripperB, Xfake_blank, Xfake_blankB, Xfake_grass, Xfake_grassB, Xfake_door_1, Xfake_door_2, Xfake_door_3, Xfake_door_4, Xfake_door_5, Xfake_door_6, Xfake_door_7, Xfake_door_8, #ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS Xfake_acid_1, Xfake_acid_2, Xfake_acid_3, Xfake_acid_4, Xfake_acid_5, Xfake_acid_6, Xfake_acid_7, Xfake_acid_8, #endif Xsteel_1, Xsteel_2, Xsteel_3, Xsteel_4, Xwall_1, Xwall_2, Xwall_3, Xwall_4, Xround_wall_1, Xround_wall_2, Xround_wall_3, Xround_wall_4, Xdecor_1, Xdecor_2, Xdecor_3, Xdecor_4, Xdecor_5, Xdecor_6, Xdecor_7, Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_11, Xdecor_12, Xalpha_0, Xalpha_1, Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5, Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9, Xalpha_excla, Xalpha_quote, Xalpha_comma, Xalpha_minus, Xalpha_perio, Xalpha_colon, Xalpha_quest, Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d, Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h, Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l, Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p, Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t, Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x, Xalpha_y, Xalpha_z, Xalpha_arrow_e, Xalpha_arrow_w, Xalpha_copyr, Xboom_bug, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_bomb, /* passed from explode to synchro (linked explosion); transition to explode_normal */ Xboom_android, /* passed from explode to synchro; transition to boom_2 */ Xboom_1, /* passed from explode to synchro; transition to boom_2 */ Xboom_2, /* transition to boom[] */ Znormal, /* passed from synchro to explode, only in next[]; no picture */ Zdynamite, /* passed from synchro to explode, only in next[]; no picture */ Zplayer, /* special code to indicate player; no picture */ ZBORDER, /* special code to indicate border; no picture */ TILE_MAX }; /* other definitions */ enum { SPR_still = 0, SPR_walk = 1, SPR_push = 5, SPR_spray = 9, SPR_MAX = 13 }; enum { SAMPLE_blank = 0, /* player walks on blank */ SAMPLE_roll, /* player pushes stone/bomb/nut/spring */ SAMPLE_stone, /* stone hits ground */ SAMPLE_nut, /* nut hits ground */ SAMPLE_crack, /* stone hits nut */ SAMPLE_bug, /* bug moves */ SAMPLE_tank, /* tank moves */ SAMPLE_android_clone, /* android places something */ SAMPLE_android_move, /* android moves */ SAMPLE_spring, /* spring hits ground/wall/bumper, stone hits spring */ SAMPLE_slurp, /* spring kills alien */ SAMPLE_eater, /* eater sits */ SAMPLE_eater_eat, /* eater eats diamond */ SAMPLE_alien, /* alien moves */ SAMPLE_collect, /* player collects object */ SAMPLE_diamond, /* diamond/emerald hits ground */ SAMPLE_squash, /* stone squashes diamond */ SAMPLE_wonderfall, /* object falls thru wonderwall */ SAMPLE_drip, /* drip hits ground */ SAMPLE_push, /* player pushes balloon/android */ SAMPLE_dirt, /* player walks on dirt */ SAMPLE_acid, /* acid splashes */ SAMPLE_ball, /* ball places something */ SAMPLE_grow, /* growing wall grows */ SAMPLE_wonder, /* wonderwall is active */ SAMPLE_door, /* player goes thru door (gate) */ SAMPLE_exit_open, /* exit opens */ SAMPLE_exit_leave, /* player goes into exit */ SAMPLE_dynamite, /* player places dynamite */ SAMPLE_tick, /* dynamite ticks */ SAMPLE_press, /* player presses wheel/wind/switch */ SAMPLE_wheel, /* wheel moves */ SAMPLE_boom, /* explosion */ SAMPLE_time, /* time runs out */ SAMPLE_die, /* player dies */ SAMPLE_MAX }; /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ struct LEVEL { int home_initial; /* number of players (initial) */ int home; /* number of players not yet at home */ /* 0 == all players at home */ int width; /* playfield width */ int height; /* playfield height */ int time_seconds; /* available time (seconds) */ int time_initial; /* available time (initial) */ int time; /* time remaining (runtime) */ boolean killed_out_of_time; /* kill player due to time out */ int required_initial; /* emeralds needed (initial) */ int required; /* emeralds needed (runtime) */ int score; /* score */ /* all below entries must be filled every time a level is read */ int alien_score; /* score for killing alien */ int amoeba_time; /* amoeba speed */ int android_move_cnt_initial; /* android move counter (initial) */ int android_move_cnt; /* android move counter */ int android_move_time; /* android move reset time */ int android_clone_cnt_initial;/* android clone counter (initial) */ int android_clone_cnt; /* android clone counter */ int android_clone_time; /* android clone reset time */ int ball_cnt; /* ball counter */ int ball_pos; /* ball array pos counter */ int ball_random; /* ball is random flag */ int ball_state_initial; /* ball active flag (initial) */ int ball_state; /* ball active flag */ int ball_time; /* ball reset time */ int bug_score; /* score for killing bug */ int diamond_score; /* score for collecting diamond */ int dynamite_score; /* score for collecting dynamite */ int eater_pos; /* eater array pos */ int eater_score; /* score for killing eater */ int emerald_score; /* score for collecting emerald */ int exit_score; /* score for entering exit */ int key_score; /* score for colleting key */ int lenses_cnt_initial; /* lenses counter (initial) */ int lenses_cnt; /* lenses counter */ int lenses_score; /* score for collecting lenses */ int lenses_time; /* lenses reset time */ int magnify_cnt_initial; /* magnify counter (initial) */ int magnify_cnt; /* magnify counter */ int magnify_score; /* score for collecting magnifier */ int magnify_time; /* magnify reset time */ int nut_score; /* score for cracking nut */ int shine_cnt; /* shine counter for emerald/diamond */ int slurp_score; /* score for slurping alien */ int tank_score; /* score for killing tank */ int wheel_cnt_initial; /* wheel counter (initial) */ int wheel_cnt; /* wheel counter */ int wheel_x_initial; /* wheel x pos (initial) */ int wheel_x; /* wheel x pos */ int wheel_y_initial; /* wheel y pos (initial) */ int wheel_y; /* wheel y pos */ int wheel_time; /* wheel reset time */ int wind_cnt_initial; /* wind counter (initial) */ int wind_cnt; /* wind time counter */ int wind_direction_initial; /* wind direction (initial) */ int wind_direction; /* wind direction */ int wind_time; /* wind reset time */ int wonderwall_state_initial; /* wonderwall active flag (initial) */ int wonderwall_state; /* wonderwall active flag */ int wonderwall_time_initial; /* wonderwall time (initial) */ int wonderwall_time; /* wonderwall time */ short eater_array[8][9]; /* eater data */ short ball_array[8][8]; /* ball data */ short android_array[TILE_MAX];/* android clone table */ int num_ball_arrays; /* number of ball data arrays used */ int exit_x, exit_y; /* kludge for playing player exit sound */ }; struct PLAYER { int num; int exists; int alive_initial; int alive; int dynamite; int dynamite_cnt; int keys; int anim; int x_initial; int y_initial; int x; int y; int oldx; int oldy; int last_move_dir; int joy_n:1; int joy_e:1; int joy_s:1; int joy_w:1; int joy_snap:1; int joy_drop:1; int joy_stick:1; int joy_spin:1; }; struct GlobalInfo_EM { Bitmap *screenbuffer; }; struct GameInfo_EM { boolean any_player_moving; boolean any_player_snapping; boolean use_single_button; boolean use_snap_key_bug; int last_moving_player; int last_player_direction[MAX_PLAYERS]; }; struct LevelInfo_EM { int file_version; short cave[EM_MAX_CAVE_WIDTH][EM_MAX_CAVE_HEIGHT]; struct LEVEL *lev; struct PLAYER *ply[MAX_PLAYERS]; /* used for runtime values */ struct GameInfo_EM *game_em; }; struct GraphicInfo_EM { Bitmap *bitmap; int src_x, src_y; int src_offset_x, src_offset_y; int dst_offset_x, dst_offset_y; int width, height; Bitmap *crumbled_bitmap; int crumbled_src_x, crumbled_src_y; int crumbled_border_size; int crumbled_tile_size; boolean has_crumbled_graphics; boolean preserve_background; int unique_identifier; /* used to identify needed screen updates */ }; struct EngineSnapshotInfo_EM { struct GameInfo_EM game_em; unsigned int RandomEM; struct LEVEL lev; struct PLAYER ply[MAX_PLAYERS]; short Array[4][EM_MAX_CAVE_HEIGHT][EM_MAX_CAVE_WIDTH]; int screen_x; int screen_y; int frame; short **Boom; short **Cave; short **Next; short **Draw; }; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ extern struct GlobalInfo_EM global_em_info; extern struct GameInfo_EM game_em; extern struct LevelInfo_EM native_em_level; extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; extern struct EngineSnapshotInfo_EM engine_snapshot_em; extern void em_open_all(); extern void em_close_all(); extern void InitGfxBuffers_EM(); extern void InitGameEngine_EM(); extern void GameActions_EM(byte *, boolean); extern unsigned int InitEngineRandom_EM(int); extern void setLevelInfoToDefaults_EM(); extern boolean LoadNativeLevel_EM(char *, boolean); extern int getFieldbufferOffsetX_EM(); extern int getFieldbufferOffsetY_EM(); extern void BackToFront_EM(void); extern void BlitScreenToBitmap_EM(Bitmap *); extern void RedrawPlayfield_EM(boolean); extern void LoadEngineSnapshotValues_EM(); extern void SaveEngineSnapshotValues_EM(); #endif /* EXPORT_H */ mirrormagic-3.0.0/src/game_em/game_em.h0000644000175000017500000000115213263212010017244 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // game_em.h // ============================================================================ #ifndef GAME_EM_H #define GAME_EM_H #define GAME_EM_VERSION_1_0_0 #include "export.h" #endif /* GAME_EM_H */ mirrormagic-3.0.0/src/game_em/synchro_2.c0000644000175000017500000034022113263212010017556 0ustar aeglosaeglos/* second part of synchro. * * game logic for monsters. * * one giant switch statement to process everything. * * this whole thing is a major bottleneck. the compiler must use registers. * compilers suck. */ #include "main_em.h" #define RANDOM (random = random << 31 | random >> 1) static void set_nearest_player_xy(int x, int y, int *dx, int *dy) { int distance, distance_shortest = EM_MAX_CAVE_WIDTH + EM_MAX_CAVE_HEIGHT; int i; /* default values if no players are alive anymore */ *dx = 0; *dy = 0; for (i = 0; i < MAX_PLAYERS; i++) { if (!ply[i].alive) continue; distance = ABS(ply[i].x - x) + ABS(ply[i].y - y); if (distance < distance_shortest) { *dx = ply[i].x; *dy = ply[i].y; distance_shortest = distance; } } } void synchro_2(void) { int x = 0; int y = 1; unsigned int random = RandomEM; short *cave_cache = Cave[y]; /* might be a win */ int score = 0; int temp = 0; /* initialized to make compilers happy */ int dx; /* only needed to find closest player */ int dy; int element; loop: element = cave_cache[++x]; switch (element) { default: goto loop; /* --------------------------------------------------------------------- */ #ifdef BAD_ROLL case Xstone_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xstone; Next[y][x] = Xstone; goto loop; default: Cave[y][x] = Ystone_eB; Cave[y][x+1] = Ystone_e; Next[y][x] = Xblank; Next[y][x+1] = Xstone_pause; goto loop; } case Xstone_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xstone; Next[y][x] = Xstone; goto loop; default: Cave[y][x] = Ystone_wB; Cave[y][x-1] = Ystone_w; Next[y][x] = Xblank; Next[y][x-1] = Xstone_pause; goto loop; } case Xnut_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xnut; Next[y][x] = Xnut; goto loop; default: Cave[y][x] = Ynut_eB; Cave[y][x+1] = Ynut_e; Next[y][x] = Xblank; Next[y][x+1] = Xnut_pause; goto loop; } case Xnut_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xnut; Next[y][x] = Xnut; goto loop; default: Cave[y][x] = Ynut_wB; Cave[y][x-1] = Ynut_w; Next[y][x] = Xblank; Next[y][x-1] = Xnut_pause; goto loop; } case Xspring_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xspring; Next[y][x] = Xspring; goto loop; default: Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x+1] = Xspring_e; #else Next[y][x+1] = Xspring_pause; #endif goto loop; } case Xspring_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xspring; Next[y][x] = Xspring; goto loop; default: Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x-1] = Xspring_w; #else Next[y][x-1] = Xspring_pause; #endif goto loop; } case Xemerald_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; goto loop; default: Cave[y][x] = Yemerald_eB; Cave[y][x+1] = Yemerald_e; Next[y][x] = Xblank; Next[y][x+1] = Xemerald_pause; goto loop; } case Xemerald_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; goto loop; default: Cave[y][x] = Yemerald_wB; Cave[y][x-1] = Yemerald_w; Next[y][x] = Xblank; Next[y][x-1] = Xemerald_pause; goto loop; } case Xdiamond_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; goto loop; default: Cave[y][x] = Ydiamond_eB; Cave[y][x+1] = Ydiamond_e; Next[y][x] = Xblank; Next[y][x+1] = Xdiamond_pause; goto loop; } case Xdiamond_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; goto loop; default: Cave[y][x] = Ydiamond_wB; Cave[y][x-1] = Ydiamond_w; Next[y][x] = Xblank; Next[y][x-1] = Xdiamond_pause; goto loop; } case Xbomb_force_e: switch (Cave[y][x+1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xbomb; Next[y][x] = Xbomb; goto loop; default: Cave[y][x] = Ybomb_eB; Cave[y][x+1] = Ybomb_e; Next[y][x] = Xblank; Next[y][x+1] = Xbomb_pause; goto loop; } case Xbomb_force_w: switch (Cave[y][x-1]) { case ZBORDER: case Znormal: case Zdynamite: case Xboom_bug: case Xboom_bomb: case Xboom_android: case Xboom_1: case Zplayer: Cave[y][x] = Xbomb; Next[y][x] = Xbomb; goto loop; default: Cave[y][x] = Ybomb_wB; Cave[y][x-1] = Ybomb_w; Next[y][x] = Xblank; Next[y][x-1] = Xbomb_pause; goto loop; } #endif /* BAD_ROLL */ /* --------------------------------------------------------------------- */ case Xstone: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ystone_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ystone_s; Next[y][x] = Xblank; Next[y+1][x] = Xstone_fall; goto loop; case Xsand: Cave[y][x] = Xsand_stonein_1; Cave[y+1][x] = Xsand_sandstone_1; Next[y][x] = Xsand_stonein_2; Next[y+1][x] = Xsand_sandstone_2; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xlenses: case Xmagnify: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ystone_eB; Cave[y][x+1] = Ystone_e; Next[y][x] = Xblank; Next[y][x+1] = Xstone_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ystone_wB; Cave[y][x-1] = Ystone_w; Next[y][x] = Xblank; Next[y][x-1] = Xstone_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ystone_wB; Cave[y][x-1] = Ystone_w; Next[y][x] = Xblank; Next[y][x-1] = Xstone_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ystone_eB; Cave[y][x+1] = Ystone_e; Next[y][x] = Xblank; Next[y][x+1] = Xstone_pause; goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xstone_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ystone_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ystone_s; Next[y][x] = Xblank; Next[y+1][x] = Xstone_fall; goto loop; default: Cave[y][x] = Xstone; Next[y][x] = Xstone; goto loop; } /* --------------------------------------------------------------------- */ case Xstone_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ystone_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: #if 1 case Xfake_acid_1: case Xfake_acid_2: case Xfake_acid_3: case Xfake_acid_4: case Xfake_acid_5: case Xfake_acid_6: case Xfake_acid_7: case Xfake_acid_8: #endif Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ystone_s; Next[y][x] = Xblank; Next[y+1][x] = Xstone_fall; goto loop; case Xnut: case Xnut_pause: Cave[y+1][x] = Yemerald_stone; Next[y][x] = Xstone; Next[y+1][x] = Xemerald; play_element_sound(x, y, SAMPLE_crack, Xnut); score += lev.nut_score; goto loop; case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ybug_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = Xemerald; Boom[y][x] = Xemerald; Boom[y][x+1] = Xemerald; Boom[y+1][x-1] = Xemerald; Boom[y+1][x] = Xdiamond; Boom[y+1][x+1] = Xemerald; Boom[y+2][x-1] = Xemerald; Boom[y+2][x] = Xemerald; Boom[y+2][x+1] = Xemerald; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.bug_score; goto loop; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ytank_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.tank_score; goto loop; case Xspring: if (RANDOM & 1) { switch (Cave[y+1][x+1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xalien: case Xalien_pause: Cave[y+1][x] = Xspring_e; break; default: Cave[y+1][x] = Xspring_w; break; } } else { switch (Cave[y+1][x-1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xalien: case Xalien_pause: Cave[y+1][x] = Xspring_w; break; default: Cave[y+1][x] = Xspring_e; break; } } Next[y][x] = Xstone; goto loop; case Xeater_n: case Xeater_e: case Xeater_s: case Xeater_w: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Yeater_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = lev.eater_array[lev.eater_pos][0]; Boom[y][x] = lev.eater_array[lev.eater_pos][1]; Boom[y][x+1] = lev.eater_array[lev.eater_pos][2]; Boom[y+1][x-1] = lev.eater_array[lev.eater_pos][3]; Boom[y+1][x] = lev.eater_array[lev.eater_pos][4]; Boom[y+1][x+1] = lev.eater_array[lev.eater_pos][5]; Boom[y+2][x-1] = lev.eater_array[lev.eater_pos][6]; Boom[y+2][x] = lev.eater_array[lev.eater_pos][7]; Boom[y+2][x+1] = lev.eater_array[lev.eater_pos][8]; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif lev.eater_pos = (lev.eater_pos + 1) & 7; score += lev.eater_score; goto loop; case Xalien: case Xalien_pause: Cave[y][x] = Ystone_sB; Cave[y+1][x] = Yalien_stone; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.alien_score; goto loop; case Xdiamond: case Xdiamond_pause: switch (Cave[y+2][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: case Xspring_fall: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone_fall: case Xemerald_fall: case Xdiamond_fall: case Xbomb_fall: case Xacid_s: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Xnut_fall: case Xplant: case Yplant: Next[y][x] = Xstone; play_element_sound(x, y, SAMPLE_stone, Xstone); goto loop; } Cave[y][x] = Ystone_sB; Cave[y+1][x] = Ydiamond_stone; Next[y][x] = Xblank; Next[y+1][x] = Xstone_pause; play_element_sound(x, y, SAMPLE_squash, Xdiamond); goto loop; case Xbomb: case Xbomb_pause: Cave[y+1][x] = Ybomb_eat; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xwonderwall: if (lev.wonderwall_time) { lev.wonderwall_state = 1; Cave[y][x] = Ystone_sB; if (tab_blank[Cave[y+2][x]]) { Cave[y+2][x] = Yemerald_s; Next[y+2][x] = Xemerald_fall; } Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_wonderfall, Xwonderwall); goto loop; } default: Cave[y][x] = Xstone; Next[y][x] = Xstone; play_element_sound(x, y, SAMPLE_stone, Xstone); goto loop; } /* --------------------------------------------------------------------- */ case Xnut: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ynut_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ynut_sB; Cave[y+1][x] = Ynut_s; Next[y][x] = Xblank; Next[y+1][x] = Xnut_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ynut_eB; Cave[y][x+1] = Ynut_e; Next[y][x] = Xblank; Next[y][x+1] = Xnut_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ynut_wB; Cave[y][x-1] = Ynut_w; Next[y][x] = Xblank; Next[y][x-1] = Xnut_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ynut_wB; Cave[y][x-1] = Ynut_w; Next[y][x] = Xblank; Next[y][x-1] = Xnut_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ynut_eB; Cave[y][x+1] = Ynut_e; Next[y][x] = Xblank; Next[y][x+1] = Xnut_pause; goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xnut_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ynut_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ynut_sB; Cave[y+1][x] = Ynut_s; Next[y][x] = Xblank; Next[y+1][x] = Xnut_fall; goto loop; default: Cave[y][x] = Xnut; Next[y][x] = Xnut; goto loop; } /* --------------------------------------------------------------------- */ case Xnut_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ynut_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Ynut_sB; Cave[y+1][x] = Ynut_s; Next[y][x] = Xblank; Next[y+1][x] = Xnut_fall; goto loop; default: Cave[y][x] = Xnut; Next[y][x] = Xnut; play_element_sound(x, y, SAMPLE_nut, Xnut); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_n: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y][x+1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_n_e; Next[y][x] = Xbug_goe; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_gon; } case Xbug_gon: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_gon: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_nB; Cave[y-1][x] = Ybug_n; Next[y][x] = Xblank; Next[y-1][x] = Xbug_n; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_n_w; Next[y][x] = Xbug_gow; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_e: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y+1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_e_s; Next[y][x] = Xbug_gos; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_goe; } case Xbug_goe: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_goe: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_eB; Cave[y][x+1] = Ybug_e; Next[y][x] = Xblank; Next[y][x+1] = Xbug_e; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_e_n; Next[y][x] = Xbug_gon; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_s: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y][x-1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_s_w; Next[y][x] = Xbug_gow; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_gos; } case Xbug_gos: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_gos: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_sB; Cave[y+1][x] = Ybug_s; Next[y][x] = Xblank; Next[y+1][x] = Xbug_s; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_s_e; Next[y][x] = Xbug_goe; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xbug_w: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; switch (Cave[y-1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ybug_w_n; Next[y][x] = Xbug_gon; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: goto bug_gow; } case Xbug_gow: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto bug_boom; bug_gow: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybug_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ybug_wB; Cave[y][x-1] = Ybug_w; Next[y][x] = Xblank; Next[y][x-1] = Xbug_w; play_element_sound(x, y, SAMPLE_bug, element); goto loop; default: Cave[y][x] = Ybug_w_s; Next[y][x] = Xbug_gos; play_element_sound(x, y, SAMPLE_bug, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_n: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y][x-1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_n_w; Next[y][x] = Xtank_gow; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_gon; } case Xtank_gon: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_gon: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_nB; Cave[y-1][x] = Ytank_n; Next[y][x] = Xblank; Next[y-1][x] = Xtank_n; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_n_e; Next[y][x] = Xtank_goe; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_e: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y-1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_e_n; Next[y][x] = Xtank_gon; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_goe; } case Xtank_goe: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_goe: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_eB; Cave[y][x+1] = Ytank_e; Next[y][x] = Xblank; Next[y][x+1] = Xtank_e; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_e_s; Next[y][x] = Xtank_gos; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_s: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y][x+1]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_s_e; Next[y][x] = Xtank_goe; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_gos; } case Xtank_gos: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_gos: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_sB; Cave[y+1][x] = Ytank_s; Next[y][x] = Xblank; Next[y+1][x] = Xtank_s; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_s_w; Next[y][x] = Xtank_gow; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xtank_w: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; switch (Cave[y+1][x]) { case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: case Zplayer: Cave[y][x] = Ytank_w_s; Next[y][x] = Xtank_gos; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: goto tank_gow; } case Xtank_gow: if (tab_amoeba[Cave[y-1][x]] || tab_amoeba[Cave[y][x+1]] || tab_amoeba[Cave[y+1][x]] || tab_amoeba[Cave[y][x-1]]) goto tank_boom; tank_gow: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ytank_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ytank_wB; Cave[y][x-1] = Ytank_w; Next[y][x] = Xblank; Next[y][x-1] = Xtank_w; play_element_sound(x, y, SAMPLE_tank, element); goto loop; default: Cave[y][x] = Ytank_w_n; Next[y][x] = Xtank_gon; play_element_sound(x, y, SAMPLE_tank, element); goto loop; } /* --------------------------------------------------------------------- */ case Xandroid: android: if (lev.android_clone_cnt == 0) { if (Cave[y-1][x-1] != Xblank && Cave[y-1][x] != Xblank && Cave[y-1][x+1] != Xblank && Cave[y][x-1] != Xblank && Cave[y][x+1] != Xblank && Cave[y+1][x-1] != Xblank && Cave[y+1][x] != Xblank && Cave[y+1][x+1] != Xblank) goto android_move; switch (RANDOM & 7) { /* randomly find an object to clone */ case 0: /* S,NE,W,NW,SE,E,SW,N */ temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; goto android_move; case 1: /* NW,SE,N,S,NE,SW,E,W */ temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; goto android_move; case 2: /* SW,E,S,W,N,NW,SE,NE */ temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; goto android_move; case 3: /* N,SE,NE,E,W,S,NW,SW */ temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; goto android_move; case 4: /* SE,NW,E,NE,SW,W,N,S */ temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; goto android_move; case 5: /* NE,W,SE,SW,S,N,E,NW */ temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; goto android_move; case 6: /* E,N,SW,S,NW,NE,SE,W */ temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; goto android_move; case 7: /* W,SW,NW,N,E,SE,NE,S */ temp= lev.android_array[Cave[y][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x-1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y-1][x+1]]; if (temp != Xblank) break; temp= lev.android_array[Cave[y+1][x]]; if (temp != Xblank) break; goto android_move; } Next[y][x] = temp; /* the item we chose to clone */ play_element_sound(x, y, SAMPLE_android_clone, temp); switch (RANDOM & 7) { /* randomly find a direction to move */ case 0: /* S,NE,W,NW,SE,E,SW,N */ if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y-1][x] == Xblank) goto android_n; goto android_move; case 1: /* NW,SE,N,S,NE,SW,E,W */ if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y][x-1] == Xblank) goto android_w; goto android_move; case 2: /* SW,E,S,W,N,NW,SE,NE */ if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x+1] == Xblank) goto android_ne; goto android_move; case 3: /* N,SE,NE,E,W,S,NW,SW */ if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y+1][x-1] == Xblank) goto android_sw; goto android_move; case 4: /* SE,NW,E,NE,SW,W,N,S */ if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x] == Xblank) goto android_s; goto android_move; case 5: /* NE,W,SE,SW,S,N,E,NW */ if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y-1][x-1] == Xblank) goto android_nw; goto android_move; case 6: /* E,N,SW,S,NW,NE,SE,W */ if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y+1][x] == Xblank) goto android_s; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y][x-1] == Xblank) goto android_w; goto android_move; case 7: /* W,SW,NW,N,E,SE,NE,S */ if (Cave[y][x-1] == Xblank) goto android_w; if (Cave[y+1][x-1] == Xblank) goto android_sw; if (Cave[y-1][x-1] == Xblank) goto android_nw; if (Cave[y-1][x] == Xblank) goto android_n; if (Cave[y][x+1] == Xblank) goto android_e; if (Cave[y+1][x+1] == Xblank) goto android_se; if (Cave[y-1][x+1] == Xblank) goto android_ne; if (Cave[y+1][x] == Xblank) goto android_s; goto android_move; } } android_move: if (lev.android_move_cnt == 0) { if (Cave[y-1][x-1] == Zplayer || Cave[y-1][x] == Zplayer || Cave[y-1][x+1] == Zplayer || Cave[y][x-1] == Zplayer || Cave[y][x+1] == Zplayer || Cave[y+1][x-1] == Zplayer || Cave[y+1][x] == Zplayer || Cave[y+1][x+1] == Zplayer) goto android_still; set_nearest_player_xy(x, y, &dx, &dy); Next[y][x] = Xblank; /* assume we will move */ temp = ((x < dx) + 1 - (x > dx)) + ((y < dy) + 1 - (y > dy)) * 3; if (RANDOM & 1) { switch (temp) { /* attempt clockwise move first if direct path is blocked */ case 0: /* north west */ if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y][x-1]]) goto android_w; break; case 1: /* north */ if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; break; case 2: /* north east */ if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y-1][x]]) goto android_n; break; case 3: /* west */ if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; break; case 4: /* nowhere */ break; case 5: /* east */ if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; break; case 6: /* south west */ if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y+1][x]]) goto android_s; break; case 7: /* south */ if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; break; case 8: /* south east */ if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y][x+1]]) goto android_e; break; } } else { switch (temp) { /* attempt counterclockwise move first if direct path is blocked */ case 0: /* north west */ if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y-1][x]]) goto android_n; break; case 1: /* north */ if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; break; case 2: /* north east */ if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y-1][x]]) goto android_n; if (tab_android_move[Cave[y][x+1]]) goto android_e; break; case 3: /* west */ if (tab_android_move[Cave[y][x-1]]) goto android_w; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y-1][x-1]]) goto android_nw; break; case 4: /* nowhere */ break; case 5: /* east */ if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y-1][x+1]]) goto android_ne; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; break; case 6: /* south west */ if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y][x-1]]) goto android_w; break; case 7: /* south */ if (tab_android_move[Cave[y+1][x]]) goto android_s; if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y+1][x-1]]) goto android_sw; break; case 8: /* south east */ if (tab_android_move[Cave[y+1][x+1]]) goto android_se; if (tab_android_move[Cave[y][x+1]]) goto android_e; if (tab_android_move[Cave[y+1][x]]) goto android_s; break; } } } android_still: Next[y][x] = Xandroid; goto loop; android_n: Cave[y][x] = Yandroid_nB; Cave[y-1][x] = Yandroid_n; Next[y-1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_ne: Cave[y][x] = Yandroid_neB; Cave[y-1][x+1] = Yandroid_ne; Next[y-1][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_e: Cave[y][x] = Yandroid_eB; Cave[y][x+1] = Yandroid_e; Next[y][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_se: Cave[y][x] = Yandroid_seB; Cave[y+1][x+1] = Yandroid_se; Next[y+1][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_s: Cave[y][x] = Yandroid_sB; Cave[y+1][x] = Yandroid_s; Next[y+1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_sw: Cave[y][x] = Yandroid_swB; Cave[y+1][x-1] = Yandroid_sw; Next[y+1][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_w: Cave[y][x] = Yandroid_wB; Cave[y][x-1] = Yandroid_w; Next[y][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; android_nw: Cave[y][x] = Yandroid_nwB; Cave[y-1][x-1] = Yandroid_nw; Next[y-1][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; /* --------------------------------------------------------------------- */ case Xandroid_1_n: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_nB; Cave[y-1][x] = Yandroid_n; Next[y][x] = Xblank; Next[y-1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_n: switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_nB; Cave[y-1][x] = Yandroid_n; Next[y][x] = Xblank; Next[y-1][x] = Xandroid_1_n; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xandroid_1_e: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_eB; Cave[y][x+1] = Yandroid_e; Next[y][x] = Xblank; Next[y][x+1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_e: switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_eB; Cave[y][x+1] = Yandroid_e; Next[y][x] = Xblank; Next[y][x+1] = Xandroid_1_e; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xandroid_1_s: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_sB; Cave[y+1][x] = Yandroid_s; Next[y][x] = Xblank; Next[y+1][x] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_s: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_sB; Cave[y+1][x] = Yandroid_s; Next[y][x] = Xblank; Next[y+1][x] = Xandroid_1_s; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xandroid_1_w: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_wB; Cave[y][x-1] = Yandroid_w; Next[y][x] = Xblank; Next[y][x-1] = Xandroid; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } case Xandroid_2_w: switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yandroid_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yandroid_wB; Cave[y][x-1] = Yandroid_w; Next[y][x] = Xblank; Next[y][x-1] = Xandroid_1_w; play_element_sound(x, y, SAMPLE_android_move, element); goto loop; default: goto android; } /* --------------------------------------------------------------------- */ case Xspring: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x+1] = Xspring_e; #else Next[y][x+1] = Xspring_pause; #endif goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x-1] = Xspring_w; #else Next[y][x-1] = Xspring_pause; #endif goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x-1] = Xspring_w; #else Next[y][x-1] = Xspring_pause; #endif goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; if (Cave[y+1][x] == Xbumper) Cave[y+1][x] = XbumperB; Next[y][x] = Xblank; #ifdef BAD_SPRING Next[y][x+1] = Xspring_e; #else Next[y][x+1] = Xspring_pause; #endif goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xspring_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; goto loop; } /* --------------------------------------------------------------------- */ case Xspring_e: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xbumper: Cave[y+1][x] = XbumperB; } switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Yalien_nB: case Yalien_eB: case Yalien_sB: case Yalien_wB: Cave[y][x] = Yspring_eB; Cave[y][x+1] = Yspring_e; Next[y][x] = Xblank; Next[y][x+1] = Xspring_e; goto loop; case Xalien: case Xalien_pause: case Yalien_n: case Yalien_e: case Yalien_s: case Yalien_w: Cave[y][x] = Yspring_kill_eB; Cave[y][x+1] = Yspring_kill_e; Next[y][x] = Xblank; Next[y][x+1] = Xspring_e; play_element_sound(x, y, SAMPLE_slurp, Xalien); score += lev.slurp_score; goto loop; case Xbumper: case XbumperB: Cave[y][x+1] = XbumperB; Next[y][x] = Xspring_w; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; } /* --------------------------------------------------------------------- */ case Xspring_w: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xbumper: Cave[y+1][x] = XbumperB; } switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Yalien_nB: case Yalien_eB: case Yalien_sB: case Yalien_wB: Cave[y][x] = Yspring_wB; Cave[y][x-1] = Yspring_w; Next[y][x] = Xblank; Next[y][x-1] = Xspring_w; goto loop; case Xalien: case Xalien_pause: case Yalien_n: case Yalien_e: case Yalien_s: case Yalien_w: Cave[y][x] = Yspring_kill_wB; Cave[y][x-1] = Yspring_kill_w; Next[y][x] = Xblank; Next[y][x-1] = Xspring_w; play_element_sound(x, y, SAMPLE_slurp, Xalien); score += lev.slurp_score; goto loop; case Xbumper: case XbumperB: Cave[y][x-1] = XbumperB; Next[y][x] = Xspring_e; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; } /* --------------------------------------------------------------------- */ case Xspring_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yspring_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yspring_s; Next[y][x] = Xblank; Next[y+1][x] = Xspring_fall; goto loop; case Xbomb: case Xbomb_pause: Cave[y+1][x] = Ybomb_eat; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xbug_n: case Xbug_e: case Xbug_s: case Xbug_w: case Xbug_gon: case Xbug_goe: case Xbug_gos: case Xbug_gow: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Ybug_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = Xemerald; Boom[y][x] = Xemerald; Boom[y][x+1] = Xemerald; Boom[y+1][x-1] = Xemerald; Boom[y+1][x] = Xdiamond; Boom[y+1][x+1] = Xemerald; Boom[y+2][x-1] = Xemerald; Boom[y+2][x] = Xemerald; Boom[y+2][x+1] = Xemerald; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.bug_score; goto loop; case Xtank_n: case Xtank_e: case Xtank_s: case Xtank_w: case Xtank_gon: case Xtank_goe: case Xtank_gos: case Xtank_gow: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Ytank_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.tank_score; goto loop; case Xeater_n: case Xeater_e: case Xeater_s: case Xeater_w: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yeater_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = lev.eater_array[lev.eater_pos][0]; Boom[y][x] = lev.eater_array[lev.eater_pos][1]; Boom[y][x+1] = lev.eater_array[lev.eater_pos][2]; Boom[y+1][x-1] = lev.eater_array[lev.eater_pos][3]; Boom[y+1][x] = lev.eater_array[lev.eater_pos][4]; Boom[y+1][x+1] = lev.eater_array[lev.eater_pos][5]; Boom[y+2][x-1] = lev.eater_array[lev.eater_pos][6]; Boom[y+2][x] = lev.eater_array[lev.eater_pos][7]; Boom[y+2][x+1] = lev.eater_array[lev.eater_pos][8]; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif lev.eater_pos = (lev.eater_pos + 1) & 7; score += lev.eater_score; goto loop; case Xalien: case Xalien_pause: Cave[y][x] = Yspring_sB; Cave[y+1][x] = Yalien_spring; Next[y+1][x] = Znormal; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; Boom[y+2][x-1] = Xblank; Boom[y+2][x] = Xblank; Boom[y+2][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif score += lev.alien_score; goto loop; default: Cave[y][x] = Xspring; Next[y][x] = Xspring; play_element_sound(x, y, SAMPLE_spring, Xspring); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_n: if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_nB; Cave[y-1][x] = Yeater_n; Next[y][x] = Xblank; Next[y-1][x] = Xeater_n; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_e : Xeater_w; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_e: if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_eB; Cave[y][x+1] = Yeater_e; Next[y][x] = Xblank; Next[y][x+1] = Xeater_e; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_n : Xeater_s; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_s: if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_sB; Cave[y+1][x] = Yeater_s; Next[y][x] = Xblank; Next[y+1][x] = Xeater_s; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_e : Xeater_w; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xeater_w: if (Cave[y-1][x] == Xdiamond) { Cave[y-1][x] = Ydiamond_eat; Next[y-1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x+1] == Xdiamond) { Cave[y][x+1] = Ydiamond_eat; Next[y][x+1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y+1][x] == Xdiamond) { Cave[y+1][x] = Ydiamond_eat; Next[y+1][x] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } if (Cave[y][x-1] == Xdiamond) { Cave[y][x-1] = Ydiamond_eat; Next[y][x-1] = Xblank; play_element_sound(x, y, SAMPLE_eater_eat, element); goto loop; } switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yeater_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yeater_wB; Cave[y][x-1] = Yeater_w; Next[y][x] = Xblank; Next[y][x-1] = Xeater_w; goto loop; default: Next[y][x] = RANDOM & 1 ? Xeater_n : Xeater_s; play_element_sound(x, y, SAMPLE_eater, element); goto loop; } /* --------------------------------------------------------------------- */ case Xalien: if (lev.wheel_cnt) { dx = lev.wheel_x; dy = lev.wheel_y; } else { set_nearest_player_xy(x, y, &dx, &dy); } if (RANDOM & 1) { if (y > dy) { switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_nB; Cave[y-1][x] = Yalien_n; Next[y][x] = Xblank; Next[y-1][x] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } else if (y < dy) { switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_sB; Next[y][x] = Xblank; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_sB; Cave[y+1][x] = Yalien_s; Next[y][x] = Xblank; Next[y+1][x] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } } else { if (x < dx) { switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_eB; Cave[y][x+1] = Yalien_e; Next[y][x] = Xblank; Next[y][x+1] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } else if (x > dx) { switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yalien_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Yalien_wB; Cave[y][x-1] = Yalien_w; Next[y][x] = Xblank; Next[y][x-1] = Xalien_pause; play_element_sound(x, y, SAMPLE_alien, Xalien); goto loop; } } } goto loop; case Xalien_pause: Next[y][x] = Xalien; goto loop; /* --------------------------------------------------------------------- */ case Xemerald: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yemerald_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yemerald_sB; Cave[y+1][x] = Yemerald_s; Next[y][x] = Xblank; Next[y+1][x] = Xemerald_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xwonderwall: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xsteel_1: case Xsteel_2: case Xsteel_3: case Xsteel_4: case Xwall_1: case Xwall_2: case Xwall_3: case Xwall_4: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yemerald_eB; Cave[y][x+1] = Yemerald_e; Next[y][x] = Xblank; Next[y][x+1] = Xemerald_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yemerald_wB; Cave[y][x-1] = Yemerald_w; Next[y][x] = Xblank; Next[y][x-1] = Xemerald_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Yemerald_wB; Cave[y][x-1] = Yemerald_w; Next[y][x] = Xblank; Next[y][x-1] = Xemerald_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Yemerald_eB; Cave[y][x+1] = Yemerald_e; Next[y][x] = Xblank; Next[y][x+1] = Xemerald_pause; goto loop; } } default: if (++lev.shine_cnt > 50) { lev.shine_cnt = RANDOM & 7; Cave[y][x] = Xemerald_shine; } goto loop; } /* --------------------------------------------------------------------- */ case Xemerald_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yemerald_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yemerald_sB; Cave[y+1][x] = Yemerald_s; Next[y][x] = Xblank; Next[y+1][x] = Xemerald_fall; goto loop; default: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; goto loop; } /* --------------------------------------------------------------------- */ case Xemerald_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yemerald_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Yemerald_sB; Cave[y+1][x] = Yemerald_s; Next[y][x] = Xblank; Next[y+1][x] = Xemerald_fall; goto loop; case Xwonderwall: if (lev.wonderwall_time) { lev.wonderwall_state = 1; Cave[y][x] = Yemerald_sB; if (tab_blank[Cave[y+2][x]]) { Cave[y+2][x] = Ydiamond_s; Next[y+2][x] = Xdiamond_fall; } Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_wonderfall, Xwonderwall); goto loop; } default: Cave[y][x] = Xemerald; Next[y][x] = Xemerald; play_element_sound(x, y, SAMPLE_diamond, Xemerald); goto loop; } /* --------------------------------------------------------------------- */ case Xdiamond: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydiamond_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ydiamond_sB; Cave[y+1][x] = Ydiamond_s; Next[y][x] = Xblank; Next[y+1][x] = Xdiamond_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xwonderwall: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xsteel_1: case Xsteel_2: case Xsteel_3: case Xsteel_4: case Xwall_1: case Xwall_2: case Xwall_3: case Xwall_4: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ydiamond_eB; Cave[y][x+1] = Ydiamond_e; Next[y][x] = Xblank; Next[y][x+1] = Xdiamond_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ydiamond_wB; Cave[y][x-1] = Ydiamond_w; Next[y][x] = Xblank; Next[y][x-1] = Xdiamond_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ydiamond_wB; Cave[y][x-1] = Ydiamond_w; Next[y][x] = Xblank; Next[y][x-1] = Xdiamond_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ydiamond_eB; Cave[y][x+1] = Ydiamond_e; Next[y][x] = Xblank; Next[y][x+1] = Xdiamond_pause; goto loop; } } default: if (++lev.shine_cnt > 50) { lev.shine_cnt = RANDOM & 7; Cave[y][x] = Xdiamond_shine; } goto loop; } /* --------------------------------------------------------------------- */ case Xdiamond_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydiamond_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ydiamond_sB; Cave[y+1][x] = Ydiamond_s; Next[y][x] = Xblank; Next[y+1][x] = Xdiamond_fall; goto loop; default: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; goto loop; } /* --------------------------------------------------------------------- */ case Xdiamond_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydiamond_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Zplayer: Cave[y][x] = Ydiamond_sB; Cave[y+1][x] = Ydiamond_s; Next[y][x] = Xblank; Next[y+1][x] = Xdiamond_fall; goto loop; case Xwonderwall: if (lev.wonderwall_time) { lev.wonderwall_state = 1; Cave[y][x] = Ydiamond_sB; if (tab_blank[Cave[y+2][x]]) { Cave[y+2][x] = Ystone_s; Next[y+2][x] = Xstone_fall; } Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_wonderfall, Xwonderwall); goto loop; } default: Cave[y][x] = Xdiamond; Next[y][x] = Xdiamond; play_element_sound(x, y, SAMPLE_diamond, Xdiamond); goto loop; } /* --------------------------------------------------------------------- */ case Xdrip_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ydrip_s1B; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xdrip_stretchB; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: case Xplant: case Yplant: case Zplayer: Cave[y][x] = Ydrip_s1B; Cave[y+1][x] = Ydrip_s1; Next[y][x] = Xdrip_stretchB; Next[y+1][x] = Xdrip_stretch; goto loop; default: switch (RANDOM & 7) { case 0: temp = Xamoeba_1; break; case 1: temp = Xamoeba_2; break; case 2: temp = Xamoeba_3; break; case 3: temp = Xamoeba_4; break; case 4: temp = Xamoeba_5; break; case 5: temp = Xamoeba_6; break; case 6: temp = Xamoeba_7; break; case 7: temp = Xamoeba_8; break; } Cave[y][x] = temp; Next[y][x] = temp; play_element_sound(x, y, SAMPLE_drip, Xdrip_fall); goto loop; } /* --------------------------------------------------------------------- */ case Xdrip_stretch: Cave[y][x] = Ydrip_s2; Next[y][x] = Xdrip_fall; goto loop; case Xdrip_stretchB: Cave[y][x] = Ydrip_s2B; Next[y][x] = Xblank; goto loop; case Xdrip_eat: Next[y][x] = Xdrip_fall; goto loop; /* --------------------------------------------------------------------- */ case Xbomb: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybomb_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ybomb_sB; Cave[y+1][x] = Ybomb_s; Next[y][x] = Xblank; Next[y+1][x] = Xbomb_fall; goto loop; case Xspring: case Xspring_pause: case Xspring_e: case Xspring_w: case Xandroid: case Xandroid_1_n: case Xandroid_2_n: case Xandroid_1_e: case Xandroid_2_e: case Xandroid_1_s: case Xandroid_2_s: case Xandroid_1_w: case Xandroid_2_w: case Xstone: case Xstone_pause: case Xemerald: case Xemerald_pause: case Xdiamond: case Xdiamond_pause: case Xbomb: case Xbomb_pause: case Xballoon: case Xacid_ne: case Xacid_nw: case Xball_1: case Xball_2: case Xnut: case Xnut_pause: case Xgrow_ns: case Xgrow_ew: case Xkey_1: case Xkey_2: case Xkey_3: case Xkey_4: case Xkey_5: case Xkey_6: case Xkey_7: case Xkey_8: case Xbumper: case Xswitch: case Xround_wall_1: case Xround_wall_2: case Xround_wall_3: case Xround_wall_4: if (RANDOM & 1) { if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ybomb_eB; Cave[y][x+1] = Ybomb_e; Next[y][x] = Xblank; Next[y][x+1] = Xbomb_pause; goto loop; } if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ybomb_wB; Cave[y][x-1] = Ybomb_w; Next[y][x] = Xblank; Next[y][x-1] = Xbomb_pause; goto loop; } } else { if (tab_blank[Cave[y][x-1]] && tab_acid[Cave[y+1][x-1]]) { Cave[y][x] = Ybomb_wB; Cave[y][x-1] = Ybomb_w; Next[y][x] = Xblank; Next[y][x-1] = Xbomb_pause; goto loop; } if (tab_blank[Cave[y][x+1]] && tab_acid[Cave[y+1][x+1]]) { Cave[y][x] = Ybomb_eB; Cave[y][x+1] = Ybomb_e; Next[y][x] = Xblank; Next[y][x+1] = Xbomb_pause; goto loop; } } default: goto loop; } /* --------------------------------------------------------------------- */ case Xbomb_pause: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybomb_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ybomb_sB; Cave[y+1][x] = Ybomb_s; Next[y][x] = Xblank; Next[y+1][x] = Xbomb_fall; goto loop; default: Cave[y][x] = Xbomb; Next[y][x] = Xbomb; goto loop; } /* --------------------------------------------------------------------- */ case Xbomb_fall: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Ybomb_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Ybomb_sB; Cave[y+1][x] = Ybomb_s; Next[y][x] = Xblank; Next[y+1][x] = Xbomb_fall; goto loop; default: Cave[y][x] = Ybomb_eat; Next[y][x] = Znormal; Boom[y-1][x-1] = Xblank; Boom[y-1][x] = Xblank; Boom[y-1][x+1] = Xblank; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; } /* --------------------------------------------------------------------- */ case Xballoon: if (lev.wind_cnt == 0) goto loop; switch (lev.wind_direction) { case 0: /* north */ switch (Cave[y-1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_nB; if (Cave[y-2][x+1] == Xblank) Cave[y-2][x+1] = Yacid_splash_eB; if (Cave[y-2][x-1] == Xblank) Cave[y-2][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_nB; Cave[y-1][x] = Yballoon_n; Next[y][x] = Xblank; Next[y-1][x] = Xballoon; goto loop; default: goto loop; } case 1: /* east */ switch (Cave[y][x+1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_eB; if (Cave[y-1][x+2] == Xblank) Cave[y-1][x+2] = Yacid_splash_eB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_eB; Cave[y][x+1] = Yballoon_e; Next[y][x] = Xblank; Next[y][x+1] = Xballoon; goto loop; default: goto loop; } case 2: /* south */ switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_sB; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_sB; Cave[y+1][x] = Yballoon_s; Next[y][x] = Xblank; Next[y+1][x] = Xballoon; goto loop; default: goto loop; } case 3: /* west */ switch (Cave[y][x-1]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Yballoon_wB; if (Cave[y-1][x] == Xblank) Cave[y-1][x] = Yacid_splash_eB; if (Cave[y-1][x-2] == Xblank) Cave[y-1][x-2] = Yacid_splash_wB; Next[y][x] = Xblank; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Yballoon_wB; Cave[y][x-1] = Yballoon_w; Next[y][x] = Xblank; Next[y][x-1] = Xballoon; goto loop; default: goto loop; } } /* --------------------------------------------------------------------- */ case Xacid_1: Next[y][x] = Xacid_2; goto loop; case Xacid_2: Next[y][x] = Xacid_3; goto loop; case Xacid_3: Next[y][x] = Xacid_4; goto loop; case Xacid_4: Next[y][x] = Xacid_5; goto loop; case Xacid_5: Next[y][x] = Xacid_6; goto loop; case Xacid_6: Next[y][x] = Xacid_7; goto loop; case Xacid_7: Next[y][x] = Xacid_8; goto loop; case Xacid_8: Next[y][x] = Xacid_1; goto loop; case Xfake_acid_1: Next[y][x] = Xfake_acid_2; goto loop; case Xfake_acid_2: Next[y][x] = Xfake_acid_3; goto loop; case Xfake_acid_3: Next[y][x] = Xfake_acid_4; goto loop; case Xfake_acid_4: Next[y][x] = Xfake_acid_5; goto loop; case Xfake_acid_5: Next[y][x] = Xfake_acid_6; goto loop; case Xfake_acid_6: Next[y][x] = Xfake_acid_7; goto loop; case Xfake_acid_7: Next[y][x] = Xfake_acid_8; goto loop; case Xfake_acid_8: Next[y][x] = Xfake_acid_1; goto loop; /* --------------------------------------------------------------------- */ case Xball_1: if (lev.ball_state == 0) goto loop; Cave[y][x] = Xball_1B; Next[y][x] = Xball_2; if (lev.ball_cnt) goto loop; goto ball_common; case Xball_2: if (lev.ball_state == 0) goto loop; Cave[y][x] = Xball_2B; Next[y][x] = Xball_1; if (lev.ball_cnt) goto loop; goto ball_common; ball_common: play_element_sound(x, y, SAMPLE_ball, element); if (lev.ball_random) { switch (RANDOM & 7) { case 0: if (lev.ball_array[lev.ball_pos][0] != Xblank && tab_blank[Cave[y-1][x-1]]) { Cave[y-1][x-1] = Yball_eat; Next[y-1][x-1] = lev.ball_array[lev.ball_pos][0]; } break; case 1: if (lev.ball_array[lev.ball_pos][1] != Xblank && tab_blank[Cave[y-1][x]]) { Cave[y-1][x] = Yball_eat; Next[y-1][x] = lev.ball_array[lev.ball_pos][1]; } break; case 2: if (lev.ball_array[lev.ball_pos][2] != Xblank && tab_blank[Cave[y-1][x+1]]) { Cave[y-1][x+1] = Yball_eat; Next[y-1][x+1] = lev.ball_array[lev.ball_pos][2]; } break; case 3: if (lev.ball_array[lev.ball_pos][3] != Xblank && tab_blank[Cave[y][x-1]]) { Cave[y][x-1] = Yball_eat; Next[y][x-1] = lev.ball_array[lev.ball_pos][3]; } break; case 4: if (lev.ball_array[lev.ball_pos][4] != Xblank && tab_blank[Cave[y][x+1]]) { Cave[y][x+1] = Yball_eat; Next[y][x+1] = lev.ball_array[lev.ball_pos][4]; } break; case 5: if (lev.ball_array[lev.ball_pos][5] != Xblank && tab_blank[Cave[y+1][x-1]]) { Cave[y+1][x-1] = Yball_eat; Next[y+1][x-1] = lev.ball_array[lev.ball_pos][5]; } break; case 6: if (lev.ball_array[lev.ball_pos][6] != Xblank && tab_blank[Cave[y+1][x]]) { Cave[y+1][x] = Yball_eat; Next[y+1][x] = lev.ball_array[lev.ball_pos][6]; } break; case 7: if (lev.ball_array[lev.ball_pos][7] != Xblank && tab_blank[Cave[y+1][x+1]]) { Cave[y+1][x+1] = Yball_eat; Next[y+1][x+1] = lev.ball_array[lev.ball_pos][7]; } break; } } else { if (lev.ball_array[lev.ball_pos][0] != Xblank && tab_blank[Cave[y-1][x-1]]) { Cave[y-1][x-1] = Yball_eat; Next[y-1][x-1] = lev.ball_array[lev.ball_pos][0]; } if (lev.ball_array[lev.ball_pos][1] != Xblank && tab_blank[Cave[y-1][x]]) { Cave[y-1][x] = Yball_eat; Next[y-1][x] = lev.ball_array[lev.ball_pos][1]; } if (lev.ball_array[lev.ball_pos][2] != Xblank && tab_blank[Cave[y-1][x+1]]) { Cave[y-1][x+1] = Yball_eat; Next[y-1][x+1] = lev.ball_array[lev.ball_pos][2]; } if (lev.ball_array[lev.ball_pos][3] != Xblank && tab_blank[Cave[y][x-1]]) { Cave[y][x-1] = Yball_eat; Next[y][x-1] = lev.ball_array[lev.ball_pos][3]; } if (lev.ball_array[lev.ball_pos][4] != Xblank && tab_blank[Cave[y][x+1]]) { Cave[y][x+1] = Yball_eat; Next[y][x+1] = lev.ball_array[lev.ball_pos][4]; } if (lev.ball_array[lev.ball_pos][5] != Xblank && tab_blank[Cave[y+1][x-1]]) { Cave[y+1][x-1] = Yball_eat; Next[y+1][x-1] = lev.ball_array[lev.ball_pos][5]; } if (lev.ball_array[lev.ball_pos][6] != Xblank && tab_blank[Cave[y+1][x]]) { Cave[y+1][x] = Yball_eat; Next[y+1][x] = lev.ball_array[lev.ball_pos][6]; } if (lev.ball_array[lev.ball_pos][7] != Xblank && tab_blank[Cave[y+1][x+1]]) { Cave[y+1][x+1] = Yball_eat; Next[y+1][x+1] = lev.ball_array[lev.ball_pos][7]; } } lev.ball_pos = (lev.ball_pos + 1) % lev.num_ball_arrays; goto loop; /* --------------------------------------------------------------------- */ case Xgrow_ns: if (tab_blank[Cave[y-1][x]]) { Cave[y-1][x] = Ygrow_ns_eat; Next[y-1][x] = Xgrow_ns; play_element_sound(x, y, SAMPLE_grow, Xgrow_ns); } if (tab_blank[Cave[y+1][x]]) { Cave[y+1][x] = Ygrow_ns_eat; Next[y+1][x] = Xgrow_ns; play_element_sound(x, y, SAMPLE_grow, Xgrow_ns); } goto loop; case Xgrow_ew: if (tab_blank[Cave[y][x+1]]) { Cave[y][x+1] = Ygrow_ew_eat; Next[y][x+1] = Xgrow_ew; play_element_sound(x, y, SAMPLE_grow, Xgrow_ew); } if (tab_blank[Cave[y][x-1]]) { Cave[y][x-1] = Ygrow_ew_eat; Next[y][x-1] = Xgrow_ew; play_element_sound(x, y, SAMPLE_grow, Xgrow_ew); } goto loop; /* --------------------------------------------------------------------- */ case Xwonderwall: if (lev.wonderwall_time && lev.wonderwall_state) { Cave[y][x] = XwonderwallB; play_element_sound(x, y, SAMPLE_wonder, Xwonderwall); } goto loop; /* --------------------------------------------------------------------- */ case Xexit: if (lev.required > 0) goto loop; temp = RANDOM & 63; if (temp < 21) { Cave[y][x] = Xexit_1; Next[y][x] = Xexit_2; } else if (temp < 42) { Cave[y][x] = Xexit_2; Next[y][x] = Xexit_3; } else { Cave[y][x] = Xexit_3; Next[y][x] = Xexit_1; } play_element_sound(x, y, SAMPLE_exit_open, Xexit); goto loop; case Xexit_1: Next[y][x] = Xexit_2; goto loop; case Xexit_2: Next[y][x] = Xexit_3; goto loop; case Xexit_3: Next[y][x] = Xexit_1; goto loop; /* --------------------------------------------------------------------- */ case Xdynamite_1: play_element_sound(x, y, SAMPLE_tick, Xdynamite_1); Next[y][x] = Xdynamite_2; goto loop; case Xdynamite_2: play_element_sound(x, y, SAMPLE_tick, Xdynamite_2); Next[y][x] = Xdynamite_3; goto loop; case Xdynamite_3: play_element_sound(x, y, SAMPLE_tick, Xdynamite_3); Next[y][x] = Xdynamite_4; goto loop; case Xdynamite_4: play_element_sound(x, y, SAMPLE_tick, Xdynamite_4); Next[y][x] = Zdynamite; Boom[y-1][x-1] = Xblank; Boom[y-1][x] = Xblank; Boom[y-1][x+1] = Xblank; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; goto loop; /* --------------------------------------------------------------------- */ case Xwheel: if (lev.wheel_cnt && x == lev.wheel_x && y == lev.wheel_y) Cave[y][x] = XwheelB; goto loop; /* --------------------------------------------------------------------- */ case Xswitch: if (lev.ball_state) Cave[y][x] = XswitchB; goto loop; /* --------------------------------------------------------------------- */ case Xsand_stone: switch (Cave[y+1][x]) { case Xacid_1: case Xacid_2: case Xacid_3: case Xacid_4: case Xacid_5: case Xacid_6: case Xacid_7: case Xacid_8: Cave[y][x] = Xsand_stonesand_quickout_1; if (Cave[y][x+1] == Xblank) Cave[y][x+1] = Yacid_splash_eB; if (Cave[y][x-1] == Xblank) Cave[y][x-1] = Yacid_splash_wB; Next[y][x] = Xsand_stonesand_quickout_2; play_element_sound(x, y, SAMPLE_acid, Xacid_1); goto loop; case Xblank: case Yacid_splash_eB: case Yacid_splash_wB: Cave[y][x] = Xsand_stonesand_quickout_1; Cave[y+1][x] = Xsand_stoneout_1; Next[y][x] = Xsand_stonesand_quickout_2; Next[y+1][x] = Xsand_stoneout_2; goto loop; case Xsand: Cave[y][x] = Xsand_stonesand_1; Cave[y+1][x] = Xsand_sandstone_1; Next[y][x] = Xsand_stonesand_2; Next[y+1][x] = Xsand_sandstone_2; goto loop; default: goto loop; } case Xsand_stonein_1: Next[y][x] = Xsand_stonein_2; goto loop; case Xsand_stonein_2: Next[y][x] = Xsand_stonein_3; goto loop; case Xsand_stonein_3: Next[y][x] = Xsand_stonein_4; goto loop; case Xsand_stonein_4: Next[y][x] = Xblank; goto loop; case Xsand_stonesand_1: Next[y][x] = Xsand_stonesand_2; goto loop; case Xsand_stonesand_2: Next[y][x] = Xsand_stonesand_3; goto loop; case Xsand_stonesand_3: Next[y][x] = Xsand_stonesand_4; goto loop; case Xsand_stonesand_4: Next[y][x] = Xsand; goto loop; #if 1 case Xsand_stonesand_quickout_1: Next[y][x] = Xsand_stonesand_quickout_2; goto loop; case Xsand_stonesand_quickout_2: Next[y][x] = Xsand; goto loop; #endif case Xsand_stoneout_1: Next[y][x] = Xsand_stoneout_2; goto loop; case Xsand_stoneout_2: Next[y][x] = Xstone_fall; goto loop; case Xsand_sandstone_1: Next[y][x] = Xsand_sandstone_2; goto loop; case Xsand_sandstone_2: Next[y][x] = Xsand_sandstone_3; goto loop; case Xsand_sandstone_3: Next[y][x] = Xsand_sandstone_4; goto loop; case Xsand_sandstone_4: Next[y][x] = Xsand_stone; goto loop; /* --------------------------------------------------------------------- */ case Xdripper: if (lev.lenses_cnt) Cave[y][x] = XdripperB; goto loop; /* --------------------------------------------------------------------- */ case Xfake_blank: if (lev.lenses_cnt) Cave[y][x] = Xfake_blankB; goto loop; /* --------------------------------------------------------------------- */ case Xfake_grass: if (lev.magnify_cnt) Cave[y][x] = Xfake_grassB; goto loop; /* --------------------------------------------------------------------- */ case Xfake_door_1: if (lev.magnify_cnt) Cave[y][x] = Xdoor_1; goto loop; case Xfake_door_2: if (lev.magnify_cnt) Cave[y][x] = Xdoor_2; goto loop; case Xfake_door_3: if (lev.magnify_cnt) Cave[y][x] = Xdoor_3; goto loop; case Xfake_door_4: if (lev.magnify_cnt) Cave[y][x] = Xdoor_4; goto loop; case Xfake_door_5: if (lev.magnify_cnt) Cave[y][x] = Xdoor_5; goto loop; case Xfake_door_6: if (lev.magnify_cnt) Cave[y][x] = Xdoor_6; goto loop; case Xfake_door_7: if (lev.magnify_cnt) Cave[y][x] = Xdoor_7; goto loop; case Xfake_door_8: if (lev.magnify_cnt) Cave[y][x] = Xdoor_8; goto loop; /* --------------------------------------------------------------------- */ case Xboom_bug: bug_boom: Next[y][x] = Znormal; Boom[y-1][x-1] = Xemerald; Boom[y-1][x] = Xemerald; Boom[y-1][x+1] = Xemerald; Boom[y][x-1] = Xemerald; Boom[y][x] = Xdiamond; Boom[y][x+1] = Xemerald; Boom[y+1][x-1] = Xemerald; Boom[y+1][x] = Xemerald; Boom[y+1][x+1] = Xemerald; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xboom_bomb: tank_boom: Next[y][x] = Znormal; Boom[y-1][x-1] = Xblank; Boom[y-1][x] = Xblank; Boom[y-1][x+1] = Xblank; Boom[y][x-1] = Xblank; Boom[y][x] = Xblank; Boom[y][x+1] = Xblank; Boom[y+1][x-1] = Xblank; Boom[y+1][x] = Xblank; Boom[y+1][x+1] = Xblank; #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, element); #endif goto loop; case Xboom_android: #if PLAY_ELEMENT_SOUND play_element_sound(x, y, SAMPLE_boom, Xandroid); #endif case Xboom_1: Next[y][x] = Xboom_2; #if !PLAY_ELEMENT_SOUND if (x != lev.exit_x && y != lev.exit_y) play_sound(x, y, SAMPLE_boom); else lev.exit_x = lev.exit_y = -1; #endif goto loop; case Xboom_2: Next[y][x] = Boom[y][x]; goto loop; /* --------------------------------------------------------------------- */ case ZBORDER: if (++y < HEIGHT - 1) { x = 0; cave_cache = Cave[y]; goto loop; } goto done; } #undef RANDOM #undef PLAY #undef PLAY_FORCE done: if (ply[0].alive || ply[1].alive || ply[2].alive || ply[3].alive) lev.score += score; /* only add a score if someone is alive */ RandomEM = random; { void *temp = Cave; /* triple buffering */ Cave = Next; Next = Draw; Draw = temp; } } mirrormagic-3.0.0/src/game_em/cave.c0000644000175000017500000000413113263212010016563 0ustar aeglosaeglos/* 2000-08-10T16:43:50Z * * cave data structures */ #include "main_em.h" struct LevelInfo_EM native_em_level; void setLevelInfoToDefaults_EM(void) { int i; native_em_level.file_version = FILE_VERSION_EM_ACTUAL; native_em_level.lev = &lev; for (i = 0; i < MAX_PLAYERS; i++) native_em_level.ply[i] = &ply[i]; lev.width = 64; lev.height = 32; for (i = 0; i < MAX_PLAYERS; i++) { ply[i].x_initial = 0; ply[i].y_initial = 0; } lev.lenses_cnt_initial = 0; lev.magnify_cnt_initial = 0; lev.wheel_cnt_initial = 0; lev.wheel_x_initial = 1; lev.wheel_y_initial = 1; lev.wind_time = 9999; lev.wind_cnt_initial = 0; lev.wonderwall_state_initial = 0; lev.wonderwall_time_initial = 0; lev.num_ball_arrays = 8; for (i = 0; i < TILE_MAX; i++) lev.android_array[i] = Xblank; /* initial number of players in this level */ lev.home_initial = 0; for (i = 0; i < MAX_PLAYERS; i++) { ply[i].exists = 0; ply[i].alive_initial = FALSE; } } /* load cave * * completely initializes the level structure, ready for a game */ #define MAX_EM_LEVEL_SIZE 16384 boolean LoadNativeLevel_EM(char *filename, boolean level_info_only) { unsigned char raw_leveldata[MAX_EM_LEVEL_SIZE]; int raw_leveldata_length; int file_version; File *file; /* always start with reliable default values */ setLevelInfoToDefaults_EM(); if (!(file = openFile(filename, MODE_READ))) { if (!level_info_only) Error(ERR_WARN, "cannot open level '%s' -- using empty level", filename); return FALSE; } raw_leveldata_length = readFile(file, raw_leveldata, 1, MAX_EM_LEVEL_SIZE); closeFile(file); if (raw_leveldata_length <= 0) { Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return FALSE; } file_version = cleanup_em_level(raw_leveldata, raw_leveldata_length,filename); if (file_version == FILE_VERSION_EM_UNKNOWN) { Error(ERR_WARN, "unknown EM level '%s' -- using empty level", filename); return FALSE; } convert_em_level(raw_leveldata, file_version); prepare_em_level(); return TRUE; } mirrormagic-3.0.0/src/game_em/sound.c0000644000175000017500000000012613263212010016775 0ustar aeglosaeglos/* 2000-08-10T17:39:15Z * * handle sounds in emerald mine */ #include "main_em.h" mirrormagic-3.0.0/src/conf_chr.c0000644000175000017500000005733713263214151016064 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_chr.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CHR_C #define CONF_CHR_C /* values for graphics configuration (character elements) */ { "char_space", "RocksFontEM.png" }, { "char_space.xpos", "0" }, { "char_space.ypos", "0" }, { "char_space.frames", "1" }, { "char_space.EDITOR", "RocksFontEM.png" }, { "char_space.EDITOR.xpos", "7" }, { "char_space.EDITOR.ypos", "4" }, { "char_space.EDITOR.frames", "1" }, { "char_exclam", "RocksFontEM.png" }, { "char_exclam.xpos", "1" }, { "char_exclam.ypos", "0" }, { "char_exclam.frames", "1" }, { "char_quotedbl", "RocksFontEM.png" }, { "char_quotedbl.xpos", "2" }, { "char_quotedbl.ypos", "0" }, { "char_quotedbl.frames", "1" }, { "char_numbersign", "RocksFontEM.png" }, { "char_numbersign.xpos", "3" }, { "char_numbersign.ypos", "0" }, { "char_numbersign.frames", "1" }, { "char_dollar", "RocksFontEM.png" }, { "char_dollar.xpos", "4" }, { "char_dollar.ypos", "0" }, { "char_dollar.frames", "1" }, { "char_percent", "RocksFontEM.png" }, { "char_percent.xpos", "5" }, { "char_percent.ypos", "0" }, { "char_percent.frames", "1" }, { "char_ampersand", "RocksFontEM.png" }, { "char_ampersand.xpos", "6" }, { "char_ampersand.ypos", "0" }, { "char_ampersand.frames", "1" }, { "char_apostrophe", "RocksFontEM.png" }, { "char_apostrophe.xpos", "7" }, { "char_apostrophe.ypos", "0" }, { "char_apostrophe.frames", "1" }, { "char_parenleft", "RocksFontEM.png" }, { "char_parenleft.xpos", "8" }, { "char_parenleft.ypos", "0" }, { "char_parenleft.frames", "1" }, { "char_parenright", "RocksFontEM.png" }, { "char_parenright.xpos", "9" }, { "char_parenright.ypos", "0" }, { "char_parenright.frames", "1" }, { "char_asterisk", "RocksFontEM.png" }, { "char_asterisk.xpos", "10" }, { "char_asterisk.ypos", "0" }, { "char_asterisk.frames", "1" }, { "char_plus", "RocksFontEM.png" }, { "char_plus.xpos", "11" }, { "char_plus.ypos", "0" }, { "char_plus.frames", "1" }, { "char_comma", "RocksFontEM.png" }, { "char_comma.xpos", "12" }, { "char_comma.ypos", "0" }, { "char_comma.frames", "1" }, { "char_minus", "RocksFontEM.png" }, { "char_minus.xpos", "13" }, { "char_minus.ypos", "0" }, { "char_minus.frames", "1" }, { "char_period", "RocksFontEM.png" }, { "char_period.xpos", "14" }, { "char_period.ypos", "0" }, { "char_period.frames", "1" }, { "char_slash", "RocksFontEM.png" }, { "char_slash.xpos", "15" }, { "char_slash.ypos", "0" }, { "char_slash.frames", "1" }, { "char_0", "RocksFontEM.png" }, { "char_0.xpos", "0" }, { "char_0.ypos", "1" }, { "char_0.frames", "1" }, { "char_1", "RocksFontEM.png" }, { "char_1.xpos", "1" }, { "char_1.ypos", "1" }, { "char_1.frames", "1" }, { "char_2", "RocksFontEM.png" }, { "char_2.xpos", "2" }, { "char_2.ypos", "1" }, { "char_2.frames", "1" }, { "char_3", "RocksFontEM.png" }, { "char_3.xpos", "3" }, { "char_3.ypos", "1" }, { "char_3.frames", "1" }, { "char_4", "RocksFontEM.png" }, { "char_4.xpos", "4" }, { "char_4.ypos", "1" }, { "char_4.frames", "1" }, { "char_5", "RocksFontEM.png" }, { "char_5.xpos", "5" }, { "char_5.ypos", "1" }, { "char_5.frames", "1" }, { "char_6", "RocksFontEM.png" }, { "char_6.xpos", "6" }, { "char_6.ypos", "1" }, { "char_6.frames", "1" }, { "char_7", "RocksFontEM.png" }, { "char_7.xpos", "7" }, { "char_7.ypos", "1" }, { "char_7.frames", "1" }, { "char_8", "RocksFontEM.png" }, { "char_8.xpos", "8" }, { "char_8.ypos", "1" }, { "char_8.frames", "1" }, { "char_9", "RocksFontEM.png" }, { "char_9.xpos", "9" }, { "char_9.ypos", "1" }, { "char_9.frames", "1" }, { "char_colon", "RocksFontEM.png" }, { "char_colon.xpos", "10" }, { "char_colon.ypos", "1" }, { "char_colon.frames", "1" }, { "char_semicolon", "RocksFontEM.png" }, { "char_semicolon.xpos", "11" }, { "char_semicolon.ypos", "1" }, { "char_semicolon.frames", "1" }, { "char_less", "RocksFontEM.png" }, { "char_less.xpos", "12" }, { "char_less.ypos", "1" }, { "char_less.frames", "1" }, { "char_equal", "RocksFontEM.png" }, { "char_equal.xpos", "13" }, { "char_equal.ypos", "1" }, { "char_equal.frames", "1" }, { "char_greater", "RocksFontEM.png" }, { "char_greater.xpos", "14" }, { "char_greater.ypos", "1" }, { "char_greater.frames", "1" }, { "char_question", "RocksFontEM.png" }, { "char_question.xpos", "15" }, { "char_question.ypos", "1" }, { "char_question.frames", "1" }, { "char_at", "RocksFontEM.png" }, { "char_at.xpos", "0" }, { "char_at.ypos", "2" }, { "char_at.frames", "1" }, { "char_a", "RocksFontEM.png" }, { "char_a.xpos", "1" }, { "char_a.ypos", "2" }, { "char_a.frames", "1" }, { "char_b", "RocksFontEM.png" }, { "char_b.xpos", "2" }, { "char_b.ypos", "2" }, { "char_b.frames", "1" }, { "char_c", "RocksFontEM.png" }, { "char_c.xpos", "3" }, { "char_c.ypos", "2" }, { "char_c.frames", "1" }, { "char_d", "RocksFontEM.png" }, { "char_d.xpos", "4" }, { "char_d.ypos", "2" }, { "char_d.frames", "1" }, { "char_e", "RocksFontEM.png" }, { "char_e.xpos", "5" }, { "char_e.ypos", "2" }, { "char_e.frames", "1" }, { "char_f", "RocksFontEM.png" }, { "char_f.xpos", "6" }, { "char_f.ypos", "2" }, { "char_f.frames", "1" }, { "char_g", "RocksFontEM.png" }, { "char_g.xpos", "7" }, { "char_g.ypos", "2" }, { "char_g.frames", "1" }, { "char_h", "RocksFontEM.png" }, { "char_h.xpos", "8" }, { "char_h.ypos", "2" }, { "char_h.frames", "1" }, { "char_i", "RocksFontEM.png" }, { "char_i.xpos", "9" }, { "char_i.ypos", "2" }, { "char_i.frames", "1" }, { "char_j", "RocksFontEM.png" }, { "char_j.xpos", "10" }, { "char_j.ypos", "2" }, { "char_j.frames", "1" }, { "char_k", "RocksFontEM.png" }, { "char_k.xpos", "11" }, { "char_k.ypos", "2" }, { "char_k.frames", "1" }, { "char_l", "RocksFontEM.png" }, { "char_l.xpos", "12" }, { "char_l.ypos", "2" }, { "char_l.frames", "1" }, { "char_m", "RocksFontEM.png" }, { "char_m.xpos", "13" }, { "char_m.ypos", "2" }, { "char_m.frames", "1" }, { "char_n", "RocksFontEM.png" }, { "char_n.xpos", "14" }, { "char_n.ypos", "2" }, { "char_n.frames", "1" }, { "char_o", "RocksFontEM.png" }, { "char_o.xpos", "15" }, { "char_o.ypos", "2" }, { "char_o.frames", "1" }, { "char_p", "RocksFontEM.png" }, { "char_p.xpos", "0" }, { "char_p.ypos", "3" }, { "char_p.frames", "1" }, { "char_q", "RocksFontEM.png" }, { "char_q.xpos", "1" }, { "char_q.ypos", "3" }, { "char_q.frames", "1" }, { "char_r", "RocksFontEM.png" }, { "char_r.xpos", "2" }, { "char_r.ypos", "3" }, { "char_r.frames", "1" }, { "char_s", "RocksFontEM.png" }, { "char_s.xpos", "3" }, { "char_s.ypos", "3" }, { "char_s.frames", "1" }, { "char_t", "RocksFontEM.png" }, { "char_t.xpos", "4" }, { "char_t.ypos", "3" }, { "char_t.frames", "1" }, { "char_u", "RocksFontEM.png" }, { "char_u.xpos", "5" }, { "char_u.ypos", "3" }, { "char_u.frames", "1" }, { "char_v", "RocksFontEM.png" }, { "char_v.xpos", "6" }, { "char_v.ypos", "3" }, { "char_v.frames", "1" }, { "char_w", "RocksFontEM.png" }, { "char_w.xpos", "7" }, { "char_w.ypos", "3" }, { "char_w.frames", "1" }, { "char_x", "RocksFontEM.png" }, { "char_x.xpos", "8" }, { "char_x.ypos", "3" }, { "char_x.frames", "1" }, { "char_y", "RocksFontEM.png" }, { "char_y.xpos", "9" }, { "char_y.ypos", "3" }, { "char_y.frames", "1" }, { "char_z", "RocksFontEM.png" }, { "char_z.xpos", "10" }, { "char_z.ypos", "3" }, { "char_z.frames", "1" }, { "char_bracketleft", "RocksFontEM.png" }, { "char_bracketleft.xpos", "11" }, { "char_bracketleft.ypos", "3" }, { "char_bracketleft.frames", "1" }, { "char_backslash", "RocksFontEM.png" }, { "char_backslash.xpos", "12" }, { "char_backslash.ypos", "3" }, { "char_backslash.frames", "1" }, { "char_bracketright", "RocksFontEM.png" }, { "char_bracketright.xpos", "13" }, { "char_bracketright.ypos", "3" }, { "char_bracketright.frames", "1" }, { "char_asciicircum", "RocksFontEM.png" }, { "char_asciicircum.xpos", "14" }, { "char_asciicircum.ypos", "3" }, { "char_asciicircum.frames", "1" }, { "char_underscore", "RocksFontEM.png" }, { "char_underscore.xpos", "15" }, { "char_underscore.ypos", "3" }, { "char_underscore.frames", "1" }, { "char_copyright", "RocksFontEM.png" }, { "char_copyright.xpos", "0" }, { "char_copyright.ypos", "4" }, { "char_copyright.frames", "1" }, { "char_aumlaut", "RocksFontEM.png" }, { "char_aumlaut.xpos", "1" }, { "char_aumlaut.ypos", "4" }, { "char_aumlaut.frames", "1" }, { "char_oumlaut", "RocksFontEM.png" }, { "char_oumlaut.xpos", "2" }, { "char_oumlaut.ypos", "4" }, { "char_oumlaut.frames", "1" }, { "char_uumlaut", "RocksFontEM.png" }, { "char_uumlaut.xpos", "3" }, { "char_uumlaut.ypos", "4" }, { "char_uumlaut.frames", "1" }, { "char_degree", "RocksFontEM.png" }, { "char_degree.xpos", "4" }, { "char_degree.ypos", "4" }, { "char_degree.frames", "1" }, { "char_trademark", "RocksFontEM.png" }, { "char_trademark.xpos", "5" }, { "char_trademark.ypos", "4" }, { "char_trademark.frames", "1" }, { "char_cursor", "RocksFontEM.png" }, { "char_cursor.xpos", "6" }, { "char_cursor.ypos", "4" }, { "char_cursor.frames", "1" }, { "char_button", "RocksFontEM.png" }, { "char_button.xpos", "13" }, { "char_button.ypos", "4" }, { "char_button.frames", "1" }, { "char_up", "RocksFontEM.png" }, { "char_up.xpos", "14" }, { "char_up.ypos", "4" }, { "char_up.frames", "1" }, { "char_down", "RocksFontEM.png" }, { "char_down.xpos", "15" }, { "char_down.ypos", "4" }, { "char_down.frames", "1" }, { "steel_char_space", "RocksFontDC.png" }, { "steel_char_space.xpos", "0" }, { "steel_char_space.ypos", "0" }, { "steel_char_space.frames", "1" }, { "steel_char_space.EDITOR", "RocksFontDC.png" }, { "steel_char_space.EDITOR.xpos", "7" }, { "steel_char_space.EDITOR.ypos", "4" }, { "steel_char_space.EDITOR.frames", "1" }, { "steel_char_exclam", "RocksFontDC.png" }, { "steel_char_exclam.xpos", "1" }, { "steel_char_exclam.ypos", "0" }, { "steel_char_exclam.frames", "1" }, { "steel_char_quotedbl", "RocksFontDC.png" }, { "steel_char_quotedbl.xpos", "2" }, { "steel_char_quotedbl.ypos", "0" }, { "steel_char_quotedbl.frames", "1" }, { "steel_char_numbersign", "RocksFontDC.png" }, { "steel_char_numbersign.xpos", "3" }, { "steel_char_numbersign.ypos", "0" }, { "steel_char_numbersign.frames", "1" }, { "steel_char_dollar", "RocksFontDC.png" }, { "steel_char_dollar.xpos", "4" }, { "steel_char_dollar.ypos", "0" }, { "steel_char_dollar.frames", "1" }, { "steel_char_percent", "RocksFontDC.png" }, { "steel_char_percent.xpos", "5" }, { "steel_char_percent.ypos", "0" }, { "steel_char_percent.frames", "1" }, { "steel_char_ampersand", "RocksFontDC.png" }, { "steel_char_ampersand.xpos", "6" }, { "steel_char_ampersand.ypos", "0" }, { "steel_char_ampersand.frames", "1" }, { "steel_char_apostrophe", "RocksFontDC.png" }, { "steel_char_apostrophe.xpos", "7" }, { "steel_char_apostrophe.ypos", "0" }, { "steel_char_apostrophe.frames", "1" }, { "steel_char_parenleft", "RocksFontDC.png" }, { "steel_char_parenleft.xpos", "8" }, { "steel_char_parenleft.ypos", "0" }, { "steel_char_parenleft.frames", "1" }, { "steel_char_parenright", "RocksFontDC.png" }, { "steel_char_parenright.xpos", "9" }, { "steel_char_parenright.ypos", "0" }, { "steel_char_parenright.frames", "1" }, { "steel_char_asterisk", "RocksFontDC.png" }, { "steel_char_asterisk.xpos", "10" }, { "steel_char_asterisk.ypos", "0" }, { "steel_char_asterisk.frames", "1" }, { "steel_char_plus", "RocksFontDC.png" }, { "steel_char_plus.xpos", "11" }, { "steel_char_plus.ypos", "0" }, { "steel_char_plus.frames", "1" }, { "steel_char_comma", "RocksFontDC.png" }, { "steel_char_comma.xpos", "12" }, { "steel_char_comma.ypos", "0" }, { "steel_char_comma.frames", "1" }, { "steel_char_minus", "RocksFontDC.png" }, { "steel_char_minus.xpos", "13" }, { "steel_char_minus.ypos", "0" }, { "steel_char_minus.frames", "1" }, { "steel_char_period", "RocksFontDC.png" }, { "steel_char_period.xpos", "14" }, { "steel_char_period.ypos", "0" }, { "steel_char_period.frames", "1" }, { "steel_char_slash", "RocksFontDC.png" }, { "steel_char_slash.xpos", "15" }, { "steel_char_slash.ypos", "0" }, { "steel_char_slash.frames", "1" }, { "steel_char_0", "RocksFontDC.png" }, { "steel_char_0.xpos", "0" }, { "steel_char_0.ypos", "1" }, { "steel_char_0.frames", "1" }, { "steel_char_1", "RocksFontDC.png" }, { "steel_char_1.xpos", "1" }, { "steel_char_1.ypos", "1" }, { "steel_char_1.frames", "1" }, { "steel_char_2", "RocksFontDC.png" }, { "steel_char_2.xpos", "2" }, { "steel_char_2.ypos", "1" }, { "steel_char_2.frames", "1" }, { "steel_char_3", "RocksFontDC.png" }, { "steel_char_3.xpos", "3" }, { "steel_char_3.ypos", "1" }, { "steel_char_3.frames", "1" }, { "steel_char_4", "RocksFontDC.png" }, { "steel_char_4.xpos", "4" }, { "steel_char_4.ypos", "1" }, { "steel_char_4.frames", "1" }, { "steel_char_5", "RocksFontDC.png" }, { "steel_char_5.xpos", "5" }, { "steel_char_5.ypos", "1" }, { "steel_char_5.frames", "1" }, { "steel_char_6", "RocksFontDC.png" }, { "steel_char_6.xpos", "6" }, { "steel_char_6.ypos", "1" }, { "steel_char_6.frames", "1" }, { "steel_char_7", "RocksFontDC.png" }, { "steel_char_7.xpos", "7" }, { "steel_char_7.ypos", "1" }, { "steel_char_7.frames", "1" }, { "steel_char_8", "RocksFontDC.png" }, { "steel_char_8.xpos", "8" }, { "steel_char_8.ypos", "1" }, { "steel_char_8.frames", "1" }, { "steel_char_9", "RocksFontDC.png" }, { "steel_char_9.xpos", "9" }, { "steel_char_9.ypos", "1" }, { "steel_char_9.frames", "1" }, { "steel_char_colon", "RocksFontDC.png" }, { "steel_char_colon.xpos", "10" }, { "steel_char_colon.ypos", "1" }, { "steel_char_colon.frames", "1" }, { "steel_char_semicolon", "RocksFontDC.png" }, { "steel_char_semicolon.xpos", "11" }, { "steel_char_semicolon.ypos", "1" }, { "steel_char_semicolon.frames", "1" }, { "steel_char_less", "RocksFontDC.png" }, { "steel_char_less.xpos", "12" }, { "steel_char_less.ypos", "1" }, { "steel_char_less.frames", "1" }, { "steel_char_equal", "RocksFontDC.png" }, { "steel_char_equal.xpos", "13" }, { "steel_char_equal.ypos", "1" }, { "steel_char_equal.frames", "1" }, { "steel_char_greater", "RocksFontDC.png" }, { "steel_char_greater.xpos", "14" }, { "steel_char_greater.ypos", "1" }, { "steel_char_greater.frames", "1" }, { "steel_char_question", "RocksFontDC.png" }, { "steel_char_question.xpos", "15" }, { "steel_char_question.ypos", "1" }, { "steel_char_question.frames", "1" }, { "steel_char_at", "RocksFontDC.png" }, { "steel_char_at.xpos", "0" }, { "steel_char_at.ypos", "2" }, { "steel_char_at.frames", "1" }, { "steel_char_a", "RocksFontDC.png" }, { "steel_char_a.xpos", "1" }, { "steel_char_a.ypos", "2" }, { "steel_char_a.frames", "1" }, { "steel_char_b", "RocksFontDC.png" }, { "steel_char_b.xpos", "2" }, { "steel_char_b.ypos", "2" }, { "steel_char_b.frames", "1" }, { "steel_char_c", "RocksFontDC.png" }, { "steel_char_c.xpos", "3" }, { "steel_char_c.ypos", "2" }, { "steel_char_c.frames", "1" }, { "steel_char_d", "RocksFontDC.png" }, { "steel_char_d.xpos", "4" }, { "steel_char_d.ypos", "2" }, { "steel_char_d.frames", "1" }, { "steel_char_e", "RocksFontDC.png" }, { "steel_char_e.xpos", "5" }, { "steel_char_e.ypos", "2" }, { "steel_char_e.frames", "1" }, { "steel_char_f", "RocksFontDC.png" }, { "steel_char_f.xpos", "6" }, { "steel_char_f.ypos", "2" }, { "steel_char_f.frames", "1" }, { "steel_char_g", "RocksFontDC.png" }, { "steel_char_g.xpos", "7" }, { "steel_char_g.ypos", "2" }, { "steel_char_g.frames", "1" }, { "steel_char_h", "RocksFontDC.png" }, { "steel_char_h.xpos", "8" }, { "steel_char_h.ypos", "2" }, { "steel_char_h.frames", "1" }, { "steel_char_i", "RocksFontDC.png" }, { "steel_char_i.xpos", "9" }, { "steel_char_i.ypos", "2" }, { "steel_char_i.frames", "1" }, { "steel_char_j", "RocksFontDC.png" }, { "steel_char_j.xpos", "10" }, { "steel_char_j.ypos", "2" }, { "steel_char_j.frames", "1" }, { "steel_char_k", "RocksFontDC.png" }, { "steel_char_k.xpos", "11" }, { "steel_char_k.ypos", "2" }, { "steel_char_k.frames", "1" }, { "steel_char_l", "RocksFontDC.png" }, { "steel_char_l.xpos", "12" }, { "steel_char_l.ypos", "2" }, { "steel_char_l.frames", "1" }, { "steel_char_m", "RocksFontDC.png" }, { "steel_char_m.xpos", "13" }, { "steel_char_m.ypos", "2" }, { "steel_char_m.frames", "1" }, { "steel_char_n", "RocksFontDC.png" }, { "steel_char_n.xpos", "14" }, { "steel_char_n.ypos", "2" }, { "steel_char_n.frames", "1" }, { "steel_char_o", "RocksFontDC.png" }, { "steel_char_o.xpos", "15" }, { "steel_char_o.ypos", "2" }, { "steel_char_o.frames", "1" }, { "steel_char_p", "RocksFontDC.png" }, { "steel_char_p.xpos", "0" }, { "steel_char_p.ypos", "3" }, { "steel_char_p.frames", "1" }, { "steel_char_q", "RocksFontDC.png" }, { "steel_char_q.xpos", "1" }, { "steel_char_q.ypos", "3" }, { "steel_char_q.frames", "1" }, { "steel_char_r", "RocksFontDC.png" }, { "steel_char_r.xpos", "2" }, { "steel_char_r.ypos", "3" }, { "steel_char_r.frames", "1" }, { "steel_char_s", "RocksFontDC.png" }, { "steel_char_s.xpos", "3" }, { "steel_char_s.ypos", "3" }, { "steel_char_s.frames", "1" }, { "steel_char_t", "RocksFontDC.png" }, { "steel_char_t.xpos", "4" }, { "steel_char_t.ypos", "3" }, { "steel_char_t.frames", "1" }, { "steel_char_u", "RocksFontDC.png" }, { "steel_char_u.xpos", "5" }, { "steel_char_u.ypos", "3" }, { "steel_char_u.frames", "1" }, { "steel_char_v", "RocksFontDC.png" }, { "steel_char_v.xpos", "6" }, { "steel_char_v.ypos", "3" }, { "steel_char_v.frames", "1" }, { "steel_char_w", "RocksFontDC.png" }, { "steel_char_w.xpos", "7" }, { "steel_char_w.ypos", "3" }, { "steel_char_w.frames", "1" }, { "steel_char_x", "RocksFontDC.png" }, { "steel_char_x.xpos", "8" }, { "steel_char_x.ypos", "3" }, { "steel_char_x.frames", "1" }, { "steel_char_y", "RocksFontDC.png" }, { "steel_char_y.xpos", "9" }, { "steel_char_y.ypos", "3" }, { "steel_char_y.frames", "1" }, { "steel_char_z", "RocksFontDC.png" }, { "steel_char_z.xpos", "10" }, { "steel_char_z.ypos", "3" }, { "steel_char_z.frames", "1" }, { "steel_char_bracketleft", "RocksFontDC.png" }, { "steel_char_bracketleft.xpos", "11" }, { "steel_char_bracketleft.ypos", "3" }, { "steel_char_bracketleft.frames", "1" }, { "steel_char_backslash", "RocksFontDC.png" }, { "steel_char_backslash.xpos", "12" }, { "steel_char_backslash.ypos", "3" }, { "steel_char_backslash.frames", "1" }, { "steel_char_bracketright", "RocksFontDC.png" }, { "steel_char_bracketright.xpos", "13" }, { "steel_char_bracketright.ypos", "3" }, { "steel_char_bracketright.frames", "1" }, { "steel_char_asciicircum", "RocksFontDC.png" }, { "steel_char_asciicircum.xpos", "14" }, { "steel_char_asciicircum.ypos", "3" }, { "steel_char_asciicircum.frames", "1" }, { "steel_char_underscore", "RocksFontDC.png" }, { "steel_char_underscore.xpos", "15" }, { "steel_char_underscore.ypos", "3" }, { "steel_char_underscore.frames", "1" }, { "steel_char_copyright", "RocksFontDC.png" }, { "steel_char_copyright.xpos", "0" }, { "steel_char_copyright.ypos", "4" }, { "steel_char_copyright.frames", "1" }, { "steel_char_aumlaut", "RocksFontDC.png" }, { "steel_char_aumlaut.xpos", "1" }, { "steel_char_aumlaut.ypos", "4" }, { "steel_char_aumlaut.frames", "1" }, { "steel_char_oumlaut", "RocksFontDC.png" }, { "steel_char_oumlaut.xpos", "2" }, { "steel_char_oumlaut.ypos", "4" }, { "steel_char_oumlaut.frames", "1" }, { "steel_char_uumlaut", "RocksFontDC.png" }, { "steel_char_uumlaut.xpos", "3" }, { "steel_char_uumlaut.ypos", "4" }, { "steel_char_uumlaut.frames", "1" }, { "steel_char_degree", "RocksFontDC.png" }, { "steel_char_degree.xpos", "4" }, { "steel_char_degree.ypos", "4" }, { "steel_char_degree.frames", "1" }, { "steel_char_trademark", "RocksFontDC.png" }, { "steel_char_trademark.xpos", "5" }, { "steel_char_trademark.ypos", "4" }, { "steel_char_trademark.frames", "1" }, { "steel_char_cursor", "RocksFontDC.png" }, { "steel_char_cursor.xpos", "6" }, { "steel_char_cursor.ypos", "4" }, { "steel_char_cursor.frames", "1" }, { "steel_char_button", "RocksFontDC.png" }, { "steel_char_button.xpos", "13" }, { "steel_char_button.ypos", "4" }, { "steel_char_button.frames", "1" }, { "steel_char_up", "RocksFontDC.png" }, { "steel_char_up.xpos", "14" }, { "steel_char_up.ypos", "4" }, { "steel_char_up.frames", "1" }, { "steel_char_down", "RocksFontDC.png" }, { "steel_char_down.xpos", "15" }, { "steel_char_down.ypos", "4" }, { "steel_char_down.frames", "1" }, #endif /* CONF_CHR_C */ mirrormagic-3.0.0/src/conf_cus.c0000644000175000017500000021174013263214151016070 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_cus.c // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CUS_C #define CONF_CUS_C /* values for graphics configuration (custom elements) */ { "custom_1", "RocksCE.png" }, { "custom_1.xpos", "0" }, { "custom_1.ypos", "0" }, { "custom_1.frames", "1" }, { "custom_1.EDITOR", "RocksCE.png" }, { "custom_1.EDITOR.xpos", "16" }, { "custom_1.EDITOR.ypos", "0" }, { "custom_2", "RocksCE.png" }, { "custom_2.xpos", "1" }, { "custom_2.ypos", "0" }, { "custom_2.frames", "1" }, { "custom_2.EDITOR", "RocksCE.png" }, { "custom_2.EDITOR.xpos", "17" }, { "custom_2.EDITOR.ypos", "0" }, { "custom_3", "RocksCE.png" }, { "custom_3.xpos", "2" }, { "custom_3.ypos", "0" }, { "custom_3.frames", "1" }, { "custom_3.EDITOR", "RocksCE.png" }, { "custom_3.EDITOR.xpos", "18" }, { "custom_3.EDITOR.ypos", "0" }, { "custom_4", "RocksCE.png" }, { "custom_4.xpos", "3" }, { "custom_4.ypos", "0" }, { "custom_4.frames", "1" }, { "custom_4.EDITOR", "RocksCE.png" }, { "custom_4.EDITOR.xpos", "19" }, { "custom_4.EDITOR.ypos", "0" }, { "custom_5", "RocksCE.png" }, { "custom_5.xpos", "4" }, { "custom_5.ypos", "0" }, { "custom_5.frames", "1" }, { "custom_5.EDITOR", "RocksCE.png" }, { "custom_5.EDITOR.xpos", "20" }, { "custom_5.EDITOR.ypos", "0" }, { "custom_6", "RocksCE.png" }, { "custom_6.xpos", "5" }, { "custom_6.ypos", "0" }, { "custom_6.frames", "1" }, { "custom_6.EDITOR", "RocksCE.png" }, { "custom_6.EDITOR.xpos", "21" }, { "custom_6.EDITOR.ypos", "0" }, { "custom_7", "RocksCE.png" }, { "custom_7.xpos", "6" }, { "custom_7.ypos", "0" }, { "custom_7.frames", "1" }, { "custom_7.EDITOR", "RocksCE.png" }, { "custom_7.EDITOR.xpos", "22" }, { "custom_7.EDITOR.ypos", "0" }, { "custom_8", "RocksCE.png" }, { "custom_8.xpos", "7" }, { "custom_8.ypos", "0" }, { "custom_8.frames", "1" }, { "custom_8.EDITOR", "RocksCE.png" }, { "custom_8.EDITOR.xpos", "23" }, { "custom_8.EDITOR.ypos", "0" }, { "custom_9", "RocksCE.png" }, { "custom_9.xpos", "8" }, { "custom_9.ypos", "0" }, { "custom_9.frames", "1" }, { "custom_9.EDITOR", "RocksCE.png" }, { "custom_9.EDITOR.xpos", "24" }, { "custom_9.EDITOR.ypos", "0" }, { "custom_10", "RocksCE.png" }, { "custom_10.xpos", "9" }, { "custom_10.ypos", "0" }, { "custom_10.frames", "1" }, { "custom_10.EDITOR", "RocksCE.png" }, { "custom_10.EDITOR.xpos", "25" }, { "custom_10.EDITOR.ypos", "0" }, { "custom_11", "RocksCE.png" }, { "custom_11.xpos", "10" }, { "custom_11.ypos", "0" }, { "custom_11.frames", "1" }, { "custom_11.EDITOR", "RocksCE.png" }, { "custom_11.EDITOR.xpos", "26" }, { "custom_11.EDITOR.ypos", "0" }, { "custom_12", "RocksCE.png" }, { "custom_12.xpos", "11" }, { "custom_12.ypos", "0" }, { "custom_12.frames", "1" }, { "custom_12.EDITOR", "RocksCE.png" }, { "custom_12.EDITOR.xpos", "27" }, { "custom_12.EDITOR.ypos", "0" }, { "custom_13", "RocksCE.png" }, { "custom_13.xpos", "12" }, { "custom_13.ypos", "0" }, { "custom_13.frames", "1" }, { "custom_13.EDITOR", "RocksCE.png" }, { "custom_13.EDITOR.xpos", "28" }, { "custom_13.EDITOR.ypos", "0" }, { "custom_14", "RocksCE.png" }, { "custom_14.xpos", "13" }, { "custom_14.ypos", "0" }, { "custom_14.frames", "1" }, { "custom_14.EDITOR", "RocksCE.png" }, { "custom_14.EDITOR.xpos", "29" }, { "custom_14.EDITOR.ypos", "0" }, { "custom_15", "RocksCE.png" }, { "custom_15.xpos", "14" }, { "custom_15.ypos", "0" }, { "custom_15.frames", "1" }, { "custom_15.EDITOR", "RocksCE.png" }, { "custom_15.EDITOR.xpos", "30" }, { "custom_15.EDITOR.ypos", "0" }, { "custom_16", "RocksCE.png" }, { "custom_16.xpos", "15" }, { "custom_16.ypos", "0" }, { "custom_16.frames", "1" }, { "custom_16.EDITOR", "RocksCE.png" }, { "custom_16.EDITOR.xpos", "31" }, { "custom_16.EDITOR.ypos", "0" }, { "custom_17", "RocksCE.png" }, { "custom_17.xpos", "0" }, { "custom_17.ypos", "1" }, { "custom_17.frames", "1" }, { "custom_17.EDITOR", "RocksCE.png" }, { "custom_17.EDITOR.xpos", "16" }, { "custom_17.EDITOR.ypos", "1" }, { "custom_18", "RocksCE.png" }, { "custom_18.xpos", "1" }, { "custom_18.ypos", "1" }, { "custom_18.frames", "1" }, { "custom_18.EDITOR", "RocksCE.png" }, { "custom_18.EDITOR.xpos", "17" }, { "custom_18.EDITOR.ypos", "1" }, { "custom_19", "RocksCE.png" }, { "custom_19.xpos", "2" }, { "custom_19.ypos", "1" }, { "custom_19.frames", "1" }, { "custom_19.EDITOR", "RocksCE.png" }, { "custom_19.EDITOR.xpos", "18" }, { "custom_19.EDITOR.ypos", "1" }, { "custom_20", "RocksCE.png" }, { "custom_20.xpos", "3" }, { "custom_20.ypos", "1" }, { "custom_20.frames", "1" }, { "custom_20.EDITOR", "RocksCE.png" }, { "custom_20.EDITOR.xpos", "19" }, { "custom_20.EDITOR.ypos", "1" }, { "custom_21", "RocksCE.png" }, { "custom_21.xpos", "4" }, { "custom_21.ypos", "1" }, { "custom_21.frames", "1" }, { "custom_21.EDITOR", "RocksCE.png" }, { "custom_21.EDITOR.xpos", "20" }, { "custom_21.EDITOR.ypos", "1" }, { "custom_22", "RocksCE.png" }, { "custom_22.xpos", "5" }, { "custom_22.ypos", "1" }, { "custom_22.frames", "1" }, { "custom_22.EDITOR", "RocksCE.png" }, { "custom_22.EDITOR.xpos", "21" }, { "custom_22.EDITOR.ypos", "1" }, { "custom_23", "RocksCE.png" }, { "custom_23.xpos", "6" }, { "custom_23.ypos", "1" }, { "custom_23.frames", "1" }, { "custom_23.EDITOR", "RocksCE.png" }, { "custom_23.EDITOR.xpos", "22" }, { "custom_23.EDITOR.ypos", "1" }, { "custom_24", "RocksCE.png" }, { "custom_24.xpos", "7" }, { "custom_24.ypos", "1" }, { "custom_24.frames", "1" }, { "custom_24.EDITOR", "RocksCE.png" }, { "custom_24.EDITOR.xpos", "23" }, { "custom_24.EDITOR.ypos", "1" }, { "custom_25", "RocksCE.png" }, { "custom_25.xpos", "8" }, { "custom_25.ypos", "1" }, { "custom_25.frames", "1" }, { "custom_25.EDITOR", "RocksCE.png" }, { "custom_25.EDITOR.xpos", "24" }, { "custom_25.EDITOR.ypos", "1" }, { "custom_26", "RocksCE.png" }, { "custom_26.xpos", "9" }, { "custom_26.ypos", "1" }, { "custom_26.frames", "1" }, { "custom_26.EDITOR", "RocksCE.png" }, { "custom_26.EDITOR.xpos", "25" }, { "custom_26.EDITOR.ypos", "1" }, { "custom_27", "RocksCE.png" }, { "custom_27.xpos", "10" }, { "custom_27.ypos", "1" }, { "custom_27.frames", "1" }, { "custom_27.EDITOR", "RocksCE.png" }, { "custom_27.EDITOR.xpos", "26" }, { "custom_27.EDITOR.ypos", "1" }, { "custom_28", "RocksCE.png" }, { "custom_28.xpos", "11" }, { "custom_28.ypos", "1" }, { "custom_28.frames", "1" }, { "custom_28.EDITOR", "RocksCE.png" }, { "custom_28.EDITOR.xpos", "27" }, { "custom_28.EDITOR.ypos", "1" }, { "custom_29", "RocksCE.png" }, { "custom_29.xpos", "12" }, { "custom_29.ypos", "1" }, { "custom_29.frames", "1" }, { "custom_29.EDITOR", "RocksCE.png" }, { "custom_29.EDITOR.xpos", "28" }, { "custom_29.EDITOR.ypos", "1" }, { "custom_30", "RocksCE.png" }, { "custom_30.xpos", "13" }, { "custom_30.ypos", "1" }, { "custom_30.frames", "1" }, { "custom_30.EDITOR", "RocksCE.png" }, { "custom_30.EDITOR.xpos", "29" }, { "custom_30.EDITOR.ypos", "1" }, { "custom_31", "RocksCE.png" }, { "custom_31.xpos", "14" }, { "custom_31.ypos", "1" }, { "custom_31.frames", "1" }, { "custom_31.EDITOR", "RocksCE.png" }, { "custom_31.EDITOR.xpos", "30" }, { "custom_31.EDITOR.ypos", "1" }, { "custom_32", "RocksCE.png" }, { "custom_32.xpos", "15" }, { "custom_32.ypos", "1" }, { "custom_32.frames", "1" }, { "custom_32.EDITOR", "RocksCE.png" }, { "custom_32.EDITOR.xpos", "31" }, { "custom_32.EDITOR.ypos", "1" }, { "custom_33", "RocksCE.png" }, { "custom_33.xpos", "0" }, { "custom_33.ypos", "2" }, { "custom_33.frames", "1" }, { "custom_33.EDITOR", "RocksCE.png" }, { "custom_33.EDITOR.xpos", "16" }, { "custom_33.EDITOR.ypos", "2" }, { "custom_34", "RocksCE.png" }, { "custom_34.xpos", "1" }, { "custom_34.ypos", "2" }, { "custom_34.frames", "1" }, { "custom_34.EDITOR", "RocksCE.png" }, { "custom_34.EDITOR.xpos", "17" }, { "custom_34.EDITOR.ypos", "2" }, { "custom_35", "RocksCE.png" }, { "custom_35.xpos", "2" }, { "custom_35.ypos", "2" }, { "custom_35.frames", "1" }, { "custom_35.EDITOR", "RocksCE.png" }, { "custom_35.EDITOR.xpos", "18" }, { "custom_35.EDITOR.ypos", "2" }, { "custom_36", "RocksCE.png" }, { "custom_36.xpos", "3" }, { "custom_36.ypos", "2" }, { "custom_36.frames", "1" }, { "custom_36.EDITOR", "RocksCE.png" }, { "custom_36.EDITOR.xpos", "19" }, { "custom_36.EDITOR.ypos", "2" }, { "custom_37", "RocksCE.png" }, { "custom_37.xpos", "4" }, { "custom_37.ypos", "2" }, { "custom_37.frames", "1" }, { "custom_37.EDITOR", "RocksCE.png" }, { "custom_37.EDITOR.xpos", "20" }, { "custom_37.EDITOR.ypos", "2" }, { "custom_38", "RocksCE.png" }, { "custom_38.xpos", "5" }, { "custom_38.ypos", "2" }, { "custom_38.frames", "1" }, { "custom_38.EDITOR", "RocksCE.png" }, { "custom_38.EDITOR.xpos", "21" }, { "custom_38.EDITOR.ypos", "2" }, { "custom_39", "RocksCE.png" }, { "custom_39.xpos", "6" }, { "custom_39.ypos", "2" }, { "custom_39.frames", "1" }, { "custom_39.EDITOR", "RocksCE.png" }, { "custom_39.EDITOR.xpos", "22" }, { "custom_39.EDITOR.ypos", "2" }, { "custom_40", "RocksCE.png" }, { "custom_40.xpos", "7" }, { "custom_40.ypos", "2" }, { "custom_40.frames", "1" }, { "custom_40.EDITOR", "RocksCE.png" }, { "custom_40.EDITOR.xpos", "23" }, { "custom_40.EDITOR.ypos", "2" }, { "custom_41", "RocksCE.png" }, { "custom_41.xpos", "8" }, { "custom_41.ypos", "2" }, { "custom_41.frames", "1" }, { "custom_41.EDITOR", "RocksCE.png" }, { "custom_41.EDITOR.xpos", "24" }, { "custom_41.EDITOR.ypos", "2" }, { "custom_42", "RocksCE.png" }, { "custom_42.xpos", "9" }, { "custom_42.ypos", "2" }, { "custom_42.frames", "1" }, { "custom_42.EDITOR", "RocksCE.png" }, { "custom_42.EDITOR.xpos", "25" }, { "custom_42.EDITOR.ypos", "2" }, { "custom_43", "RocksCE.png" }, { "custom_43.xpos", "10" }, { "custom_43.ypos", "2" }, { "custom_43.frames", "1" }, { "custom_43.EDITOR", "RocksCE.png" }, { "custom_43.EDITOR.xpos", "26" }, { "custom_43.EDITOR.ypos", "2" }, { "custom_44", "RocksCE.png" }, { "custom_44.xpos", "11" }, { "custom_44.ypos", "2" }, { "custom_44.frames", "1" }, { "custom_44.EDITOR", "RocksCE.png" }, { "custom_44.EDITOR.xpos", "27" }, { "custom_44.EDITOR.ypos", "2" }, { "custom_45", "RocksCE.png" }, { "custom_45.xpos", "12" }, { "custom_45.ypos", "2" }, { "custom_45.frames", "1" }, { "custom_45.EDITOR", "RocksCE.png" }, { "custom_45.EDITOR.xpos", "28" }, { "custom_45.EDITOR.ypos", "2" }, { "custom_46", "RocksCE.png" }, { "custom_46.xpos", "13" }, { "custom_46.ypos", "2" }, { "custom_46.frames", "1" }, { "custom_46.EDITOR", "RocksCE.png" }, { "custom_46.EDITOR.xpos", "29" }, { "custom_46.EDITOR.ypos", "2" }, { "custom_47", "RocksCE.png" }, { "custom_47.xpos", "14" }, { "custom_47.ypos", "2" }, { "custom_47.frames", "1" }, { "custom_47.EDITOR", "RocksCE.png" }, { "custom_47.EDITOR.xpos", "30" }, { "custom_47.EDITOR.ypos", "2" }, { "custom_48", "RocksCE.png" }, { "custom_48.xpos", "15" }, { "custom_48.ypos", "2" }, { "custom_48.frames", "1" }, { "custom_48.EDITOR", "RocksCE.png" }, { "custom_48.EDITOR.xpos", "31" }, { "custom_48.EDITOR.ypos", "2" }, { "custom_49", "RocksCE.png" }, { "custom_49.xpos", "0" }, { "custom_49.ypos", "3" }, { "custom_49.frames", "1" }, { "custom_49.EDITOR", "RocksCE.png" }, { "custom_49.EDITOR.xpos", "16" }, { "custom_49.EDITOR.ypos", "3" }, { "custom_50", "RocksCE.png" }, { "custom_50.xpos", "1" }, { "custom_50.ypos", "3" }, { "custom_50.frames", "1" }, { "custom_50.EDITOR", "RocksCE.png" }, { "custom_50.EDITOR.xpos", "17" }, { "custom_50.EDITOR.ypos", "3" }, { "custom_51", "RocksCE.png" }, { "custom_51.xpos", "2" }, { "custom_51.ypos", "3" }, { "custom_51.frames", "1" }, { "custom_51.EDITOR", "RocksCE.png" }, { "custom_51.EDITOR.xpos", "18" }, { "custom_51.EDITOR.ypos", "3" }, { "custom_52", "RocksCE.png" }, { "custom_52.xpos", "3" }, { "custom_52.ypos", "3" }, { "custom_52.frames", "1" }, { "custom_52.EDITOR", "RocksCE.png" }, { "custom_52.EDITOR.xpos", "19" }, { "custom_52.EDITOR.ypos", "3" }, { "custom_53", "RocksCE.png" }, { "custom_53.xpos", "4" }, { "custom_53.ypos", "3" }, { "custom_53.frames", "1" }, { "custom_53.EDITOR", "RocksCE.png" }, { "custom_53.EDITOR.xpos", "20" }, { "custom_53.EDITOR.ypos", "3" }, { "custom_54", "RocksCE.png" }, { "custom_54.xpos", "5" }, { "custom_54.ypos", "3" }, { "custom_54.frames", "1" }, { "custom_54.EDITOR", "RocksCE.png" }, { "custom_54.EDITOR.xpos", "21" }, { "custom_54.EDITOR.ypos", "3" }, { "custom_55", "RocksCE.png" }, { "custom_55.xpos", "6" }, { "custom_55.ypos", "3" }, { "custom_55.frames", "1" }, { "custom_55.EDITOR", "RocksCE.png" }, { "custom_55.EDITOR.xpos", "22" }, { "custom_55.EDITOR.ypos", "3" }, { "custom_56", "RocksCE.png" }, { "custom_56.xpos", "7" }, { "custom_56.ypos", "3" }, { "custom_56.frames", "1" }, { "custom_56.EDITOR", "RocksCE.png" }, { "custom_56.EDITOR.xpos", "23" }, { "custom_56.EDITOR.ypos", "3" }, { "custom_57", "RocksCE.png" }, { "custom_57.xpos", "8" }, { "custom_57.ypos", "3" }, { "custom_57.frames", "1" }, { "custom_57.EDITOR", "RocksCE.png" }, { "custom_57.EDITOR.xpos", "24" }, { "custom_57.EDITOR.ypos", "3" }, { "custom_58", "RocksCE.png" }, { "custom_58.xpos", "9" }, { "custom_58.ypos", "3" }, { "custom_58.frames", "1" }, { "custom_58.EDITOR", "RocksCE.png" }, { "custom_58.EDITOR.xpos", "25" }, { "custom_58.EDITOR.ypos", "3" }, { "custom_59", "RocksCE.png" }, { "custom_59.xpos", "10" }, { "custom_59.ypos", "3" }, { "custom_59.frames", "1" }, { "custom_59.EDITOR", "RocksCE.png" }, { "custom_59.EDITOR.xpos", "26" }, { "custom_59.EDITOR.ypos", "3" }, { "custom_60", "RocksCE.png" }, { "custom_60.xpos", "11" }, { "custom_60.ypos", "3" }, { "custom_60.frames", "1" }, { "custom_60.EDITOR", "RocksCE.png" }, { "custom_60.EDITOR.xpos", "27" }, { "custom_60.EDITOR.ypos", "3" }, { "custom_61", "RocksCE.png" }, { "custom_61.xpos", "12" }, { "custom_61.ypos", "3" }, { "custom_61.frames", "1" }, { "custom_61.EDITOR", "RocksCE.png" }, { "custom_61.EDITOR.xpos", "28" }, { "custom_61.EDITOR.ypos", "3" }, { "custom_62", "RocksCE.png" }, { "custom_62.xpos", "13" }, { "custom_62.ypos", "3" }, { "custom_62.frames", "1" }, { "custom_62.EDITOR", "RocksCE.png" }, { "custom_62.EDITOR.xpos", "29" }, { "custom_62.EDITOR.ypos", "3" }, { "custom_63", "RocksCE.png" }, { "custom_63.xpos", "14" }, { "custom_63.ypos", "3" }, { "custom_63.frames", "1" }, { "custom_63.EDITOR", "RocksCE.png" }, { "custom_63.EDITOR.xpos", "30" }, { "custom_63.EDITOR.ypos", "3" }, { "custom_64", "RocksCE.png" }, { "custom_64.xpos", "15" }, { "custom_64.ypos", "3" }, { "custom_64.frames", "1" }, { "custom_64.EDITOR", "RocksCE.png" }, { "custom_64.EDITOR.xpos", "31" }, { "custom_64.EDITOR.ypos", "3" }, { "custom_65", "RocksCE.png" }, { "custom_65.xpos", "0" }, { "custom_65.ypos", "4" }, { "custom_65.frames", "1" }, { "custom_65.EDITOR", "RocksCE.png" }, { "custom_65.EDITOR.xpos", "16" }, { "custom_65.EDITOR.ypos", "4" }, { "custom_66", "RocksCE.png" }, { "custom_66.xpos", "1" }, { "custom_66.ypos", "4" }, { "custom_66.frames", "1" }, { "custom_66.EDITOR", "RocksCE.png" }, { "custom_66.EDITOR.xpos", "17" }, { "custom_66.EDITOR.ypos", "4" }, { "custom_67", "RocksCE.png" }, { "custom_67.xpos", "2" }, { "custom_67.ypos", "4" }, { "custom_67.frames", "1" }, { "custom_67.EDITOR", "RocksCE.png" }, { "custom_67.EDITOR.xpos", "18" }, { "custom_67.EDITOR.ypos", "4" }, { "custom_68", "RocksCE.png" }, { "custom_68.xpos", "3" }, { "custom_68.ypos", "4" }, { "custom_68.frames", "1" }, { "custom_68.EDITOR", "RocksCE.png" }, { "custom_68.EDITOR.xpos", "19" }, { "custom_68.EDITOR.ypos", "4" }, { "custom_69", "RocksCE.png" }, { "custom_69.xpos", "4" }, { "custom_69.ypos", "4" }, { "custom_69.frames", "1" }, { "custom_69.EDITOR", "RocksCE.png" }, { "custom_69.EDITOR.xpos", "20" }, { "custom_69.EDITOR.ypos", "4" }, { "custom_70", "RocksCE.png" }, { "custom_70.xpos", "5" }, { "custom_70.ypos", "4" }, { "custom_70.frames", "1" }, { "custom_70.EDITOR", "RocksCE.png" }, { "custom_70.EDITOR.xpos", "21" }, { "custom_70.EDITOR.ypos", "4" }, { "custom_71", "RocksCE.png" }, { "custom_71.xpos", "6" }, { "custom_71.ypos", "4" }, { "custom_71.frames", "1" }, { "custom_71.EDITOR", "RocksCE.png" }, { "custom_71.EDITOR.xpos", "22" }, { "custom_71.EDITOR.ypos", "4" }, { "custom_72", "RocksCE.png" }, { "custom_72.xpos", "7" }, { "custom_72.ypos", "4" }, { "custom_72.frames", "1" }, { "custom_72.EDITOR", "RocksCE.png" }, { "custom_72.EDITOR.xpos", "23" }, { "custom_72.EDITOR.ypos", "4" }, { "custom_73", "RocksCE.png" }, { "custom_73.xpos", "8" }, { "custom_73.ypos", "4" }, { "custom_73.frames", "1" }, { "custom_73.EDITOR", "RocksCE.png" }, { "custom_73.EDITOR.xpos", "24" }, { "custom_73.EDITOR.ypos", "4" }, { "custom_74", "RocksCE.png" }, { "custom_74.xpos", "9" }, { "custom_74.ypos", "4" }, { "custom_74.frames", "1" }, { "custom_74.EDITOR", "RocksCE.png" }, { "custom_74.EDITOR.xpos", "25" }, { "custom_74.EDITOR.ypos", "4" }, { "custom_75", "RocksCE.png" }, { "custom_75.xpos", "10" }, { "custom_75.ypos", "4" }, { "custom_75.frames", "1" }, { "custom_75.EDITOR", "RocksCE.png" }, { "custom_75.EDITOR.xpos", "26" }, { "custom_75.EDITOR.ypos", "4" }, { "custom_76", "RocksCE.png" }, { "custom_76.xpos", "11" }, { "custom_76.ypos", "4" }, { "custom_76.frames", "1" }, { "custom_76.EDITOR", "RocksCE.png" }, { "custom_76.EDITOR.xpos", "27" }, { "custom_76.EDITOR.ypos", "4" }, { "custom_77", "RocksCE.png" }, { "custom_77.xpos", "12" }, { "custom_77.ypos", "4" }, { "custom_77.frames", "1" }, { "custom_77.EDITOR", "RocksCE.png" }, { "custom_77.EDITOR.xpos", "28" }, { "custom_77.EDITOR.ypos", "4" }, { "custom_78", "RocksCE.png" }, { "custom_78.xpos", "13" }, { "custom_78.ypos", "4" }, { "custom_78.frames", "1" }, { "custom_78.EDITOR", "RocksCE.png" }, { "custom_78.EDITOR.xpos", "29" }, { "custom_78.EDITOR.ypos", "4" }, { "custom_79", "RocksCE.png" }, { "custom_79.xpos", "14" }, { "custom_79.ypos", "4" }, { "custom_79.frames", "1" }, { "custom_79.EDITOR", "RocksCE.png" }, { "custom_79.EDITOR.xpos", "30" }, { "custom_79.EDITOR.ypos", "4" }, { "custom_80", "RocksCE.png" }, { "custom_80.xpos", "15" }, { "custom_80.ypos", "4" }, { "custom_80.frames", "1" }, { "custom_80.EDITOR", "RocksCE.png" }, { "custom_80.EDITOR.xpos", "31" }, { "custom_80.EDITOR.ypos", "4" }, { "custom_81", "RocksCE.png" }, { "custom_81.xpos", "0" }, { "custom_81.ypos", "5" }, { "custom_81.frames", "1" }, { "custom_81.EDITOR", "RocksCE.png" }, { "custom_81.EDITOR.xpos", "16" }, { "custom_81.EDITOR.ypos", "5" }, { "custom_82", "RocksCE.png" }, { "custom_82.xpos", "1" }, { "custom_82.ypos", "5" }, { "custom_82.frames", "1" }, { "custom_82.EDITOR", "RocksCE.png" }, { "custom_82.EDITOR.xpos", "17" }, { "custom_82.EDITOR.ypos", "5" }, { "custom_83", "RocksCE.png" }, { "custom_83.xpos", "2" }, { "custom_83.ypos", "5" }, { "custom_83.frames", "1" }, { "custom_83.EDITOR", "RocksCE.png" }, { "custom_83.EDITOR.xpos", "18" }, { "custom_83.EDITOR.ypos", "5" }, { "custom_84", "RocksCE.png" }, { "custom_84.xpos", "3" }, { "custom_84.ypos", "5" }, { "custom_84.frames", "1" }, { "custom_84.EDITOR", "RocksCE.png" }, { "custom_84.EDITOR.xpos", "19" }, { "custom_84.EDITOR.ypos", "5" }, { "custom_85", "RocksCE.png" }, { "custom_85.xpos", "4" }, { "custom_85.ypos", "5" }, { "custom_85.frames", "1" }, { "custom_85.EDITOR", "RocksCE.png" }, { "custom_85.EDITOR.xpos", "20" }, { "custom_85.EDITOR.ypos", "5" }, { "custom_86", "RocksCE.png" }, { "custom_86.xpos", "5" }, { "custom_86.ypos", "5" }, { "custom_86.frames", "1" }, { "custom_86.EDITOR", "RocksCE.png" }, { "custom_86.EDITOR.xpos", "21" }, { "custom_86.EDITOR.ypos", "5" }, { "custom_87", "RocksCE.png" }, { "custom_87.xpos", "6" }, { "custom_87.ypos", "5" }, { "custom_87.frames", "1" }, { "custom_87.EDITOR", "RocksCE.png" }, { "custom_87.EDITOR.xpos", "22" }, { "custom_87.EDITOR.ypos", "5" }, { "custom_88", "RocksCE.png" }, { "custom_88.xpos", "7" }, { "custom_88.ypos", "5" }, { "custom_88.frames", "1" }, { "custom_88.EDITOR", "RocksCE.png" }, { "custom_88.EDITOR.xpos", "23" }, { "custom_88.EDITOR.ypos", "5" }, { "custom_89", "RocksCE.png" }, { "custom_89.xpos", "8" }, { "custom_89.ypos", "5" }, { "custom_89.frames", "1" }, { "custom_89.EDITOR", "RocksCE.png" }, { "custom_89.EDITOR.xpos", "24" }, { "custom_89.EDITOR.ypos", "5" }, { "custom_90", "RocksCE.png" }, { "custom_90.xpos", "9" }, { "custom_90.ypos", "5" }, { "custom_90.frames", "1" }, { "custom_90.EDITOR", "RocksCE.png" }, { "custom_90.EDITOR.xpos", "25" }, { "custom_90.EDITOR.ypos", "5" }, { "custom_91", "RocksCE.png" }, { "custom_91.xpos", "10" }, { "custom_91.ypos", "5" }, { "custom_91.frames", "1" }, { "custom_91.EDITOR", "RocksCE.png" }, { "custom_91.EDITOR.xpos", "26" }, { "custom_91.EDITOR.ypos", "5" }, { "custom_92", "RocksCE.png" }, { "custom_92.xpos", "11" }, { "custom_92.ypos", "5" }, { "custom_92.frames", "1" }, { "custom_92.EDITOR", "RocksCE.png" }, { "custom_92.EDITOR.xpos", "27" }, { "custom_92.EDITOR.ypos", "5" }, { "custom_93", "RocksCE.png" }, { "custom_93.xpos", "12" }, { "custom_93.ypos", "5" }, { "custom_93.frames", "1" }, { "custom_93.EDITOR", "RocksCE.png" }, { "custom_93.EDITOR.xpos", "28" }, { "custom_93.EDITOR.ypos", "5" }, { "custom_94", "RocksCE.png" }, { "custom_94.xpos", "13" }, { "custom_94.ypos", "5" }, { "custom_94.frames", "1" }, { "custom_94.EDITOR", "RocksCE.png" }, { "custom_94.EDITOR.xpos", "29" }, { "custom_94.EDITOR.ypos", "5" }, { "custom_95", "RocksCE.png" }, { "custom_95.xpos", "14" }, { "custom_95.ypos", "5" }, { "custom_95.frames", "1" }, { "custom_95.EDITOR", "RocksCE.png" }, { "custom_95.EDITOR.xpos", "30" }, { "custom_95.EDITOR.ypos", "5" }, { "custom_96", "RocksCE.png" }, { "custom_96.xpos", "15" }, { "custom_96.ypos", "5" }, { "custom_96.frames", "1" }, { "custom_96.EDITOR", "RocksCE.png" }, { "custom_96.EDITOR.xpos", "31" }, { "custom_96.EDITOR.ypos", "5" }, { "custom_97", "RocksCE.png" }, { "custom_97.xpos", "0" }, { "custom_97.ypos", "6" }, { "custom_97.frames", "1" }, { "custom_97.EDITOR", "RocksCE.png" }, { "custom_97.EDITOR.xpos", "16" }, { "custom_97.EDITOR.ypos", "6" }, { "custom_98", "RocksCE.png" }, { "custom_98.xpos", "1" }, { "custom_98.ypos", "6" }, { "custom_98.frames", "1" }, { "custom_98.EDITOR", "RocksCE.png" }, { "custom_98.EDITOR.xpos", "17" }, { "custom_98.EDITOR.ypos", "6" }, { "custom_99", "RocksCE.png" }, { "custom_99.xpos", "2" }, { "custom_99.ypos", "6" }, { "custom_99.frames", "1" }, { "custom_99.EDITOR", "RocksCE.png" }, { "custom_99.EDITOR.xpos", "18" }, { "custom_99.EDITOR.ypos", "6" }, { "custom_100", "RocksCE.png" }, { "custom_100.xpos", "3" }, { "custom_100.ypos", "6" }, { "custom_100.frames", "1" }, { "custom_100.EDITOR", "RocksCE.png" }, { "custom_100.EDITOR.xpos", "19" }, { "custom_100.EDITOR.ypos", "6" }, { "custom_101", "RocksCE.png" }, { "custom_101.xpos", "4" }, { "custom_101.ypos", "6" }, { "custom_101.frames", "1" }, { "custom_101.EDITOR", "RocksCE.png" }, { "custom_101.EDITOR.xpos", "20" }, { "custom_101.EDITOR.ypos", "6" }, { "custom_102", "RocksCE.png" }, { "custom_102.xpos", "5" }, { "custom_102.ypos", "6" }, { "custom_102.frames", "1" }, { "custom_102.EDITOR", "RocksCE.png" }, { "custom_102.EDITOR.xpos", "21" }, { "custom_102.EDITOR.ypos", "6" }, { "custom_103", "RocksCE.png" }, { "custom_103.xpos", "6" }, { "custom_103.ypos", "6" }, { "custom_103.frames", "1" }, { "custom_103.EDITOR", "RocksCE.png" }, { "custom_103.EDITOR.xpos", "22" }, { "custom_103.EDITOR.ypos", "6" }, { "custom_104", "RocksCE.png" }, { "custom_104.xpos", "7" }, { "custom_104.ypos", "6" }, { "custom_104.frames", "1" }, { "custom_104.EDITOR", "RocksCE.png" }, { "custom_104.EDITOR.xpos", "23" }, { "custom_104.EDITOR.ypos", "6" }, { "custom_105", "RocksCE.png" }, { "custom_105.xpos", "8" }, { "custom_105.ypos", "6" }, { "custom_105.frames", "1" }, { "custom_105.EDITOR", "RocksCE.png" }, { "custom_105.EDITOR.xpos", "24" }, { "custom_105.EDITOR.ypos", "6" }, { "custom_106", "RocksCE.png" }, { "custom_106.xpos", "9" }, { "custom_106.ypos", "6" }, { "custom_106.frames", "1" }, { "custom_106.EDITOR", "RocksCE.png" }, { "custom_106.EDITOR.xpos", "25" }, { "custom_106.EDITOR.ypos", "6" }, { "custom_107", "RocksCE.png" }, { "custom_107.xpos", "10" }, { "custom_107.ypos", "6" }, { "custom_107.frames", "1" }, { "custom_107.EDITOR", "RocksCE.png" }, { "custom_107.EDITOR.xpos", "26" }, { "custom_107.EDITOR.ypos", "6" }, { "custom_108", "RocksCE.png" }, { "custom_108.xpos", "11" }, { "custom_108.ypos", "6" }, { "custom_108.frames", "1" }, { "custom_108.EDITOR", "RocksCE.png" }, { "custom_108.EDITOR.xpos", "27" }, { "custom_108.EDITOR.ypos", "6" }, { "custom_109", "RocksCE.png" }, { "custom_109.xpos", "12" }, { "custom_109.ypos", "6" }, { "custom_109.frames", "1" }, { "custom_109.EDITOR", "RocksCE.png" }, { "custom_109.EDITOR.xpos", "28" }, { "custom_109.EDITOR.ypos", "6" }, { "custom_110", "RocksCE.png" }, { "custom_110.xpos", "13" }, { "custom_110.ypos", "6" }, { "custom_110.frames", "1" }, { "custom_110.EDITOR", "RocksCE.png" }, { "custom_110.EDITOR.xpos", "29" }, { "custom_110.EDITOR.ypos", "6" }, { "custom_111", "RocksCE.png" }, { "custom_111.xpos", "14" }, { "custom_111.ypos", "6" }, { "custom_111.frames", "1" }, { "custom_111.EDITOR", "RocksCE.png" }, { "custom_111.EDITOR.xpos", "30" }, { "custom_111.EDITOR.ypos", "6" }, { "custom_112", "RocksCE.png" }, { "custom_112.xpos", "15" }, { "custom_112.ypos", "6" }, { "custom_112.frames", "1" }, { "custom_112.EDITOR", "RocksCE.png" }, { "custom_112.EDITOR.xpos", "31" }, { "custom_112.EDITOR.ypos", "6" }, { "custom_113", "RocksCE.png" }, { "custom_113.xpos", "0" }, { "custom_113.ypos", "7" }, { "custom_113.frames", "1" }, { "custom_113.EDITOR", "RocksCE.png" }, { "custom_113.EDITOR.xpos", "16" }, { "custom_113.EDITOR.ypos", "7" }, { "custom_114", "RocksCE.png" }, { "custom_114.xpos", "1" }, { "custom_114.ypos", "7" }, { "custom_114.frames", "1" }, { "custom_114.EDITOR", "RocksCE.png" }, { "custom_114.EDITOR.xpos", "17" }, { "custom_114.EDITOR.ypos", "7" }, { "custom_115", "RocksCE.png" }, { "custom_115.xpos", "2" }, { "custom_115.ypos", "7" }, { "custom_115.frames", "1" }, { "custom_115.EDITOR", "RocksCE.png" }, { "custom_115.EDITOR.xpos", "18" }, { "custom_115.EDITOR.ypos", "7" }, { "custom_116", "RocksCE.png" }, { "custom_116.xpos", "3" }, { "custom_116.ypos", "7" }, { "custom_116.frames", "1" }, { "custom_116.EDITOR", "RocksCE.png" }, { "custom_116.EDITOR.xpos", "19" }, { "custom_116.EDITOR.ypos", "7" }, { "custom_117", "RocksCE.png" }, { "custom_117.xpos", "4" }, { "custom_117.ypos", "7" }, { "custom_117.frames", "1" }, { "custom_117.EDITOR", "RocksCE.png" }, { "custom_117.EDITOR.xpos", "20" }, { "custom_117.EDITOR.ypos", "7" }, { "custom_118", "RocksCE.png" }, { "custom_118.xpos", "5" }, { "custom_118.ypos", "7" }, { "custom_118.frames", "1" }, { "custom_118.EDITOR", "RocksCE.png" }, { "custom_118.EDITOR.xpos", "21" }, { "custom_118.EDITOR.ypos", "7" }, { "custom_119", "RocksCE.png" }, { "custom_119.xpos", "6" }, { "custom_119.ypos", "7" }, { "custom_119.frames", "1" }, { "custom_119.EDITOR", "RocksCE.png" }, { "custom_119.EDITOR.xpos", "22" }, { "custom_119.EDITOR.ypos", "7" }, { "custom_120", "RocksCE.png" }, { "custom_120.xpos", "7" }, { "custom_120.ypos", "7" }, { "custom_120.frames", "1" }, { "custom_120.EDITOR", "RocksCE.png" }, { "custom_120.EDITOR.xpos", "23" }, { "custom_120.EDITOR.ypos", "7" }, { "custom_121", "RocksCE.png" }, { "custom_121.xpos", "8" }, { "custom_121.ypos", "7" }, { "custom_121.frames", "1" }, { "custom_121.EDITOR", "RocksCE.png" }, { "custom_121.EDITOR.xpos", "24" }, { "custom_121.EDITOR.ypos", "7" }, { "custom_122", "RocksCE.png" }, { "custom_122.xpos", "9" }, { "custom_122.ypos", "7" }, { "custom_122.frames", "1" }, { "custom_122.EDITOR", "RocksCE.png" }, { "custom_122.EDITOR.xpos", "25" }, { "custom_122.EDITOR.ypos", "7" }, { "custom_123", "RocksCE.png" }, { "custom_123.xpos", "10" }, { "custom_123.ypos", "7" }, { "custom_123.frames", "1" }, { "custom_123.EDITOR", "RocksCE.png" }, { "custom_123.EDITOR.xpos", "26" }, { "custom_123.EDITOR.ypos", "7" }, { "custom_124", "RocksCE.png" }, { "custom_124.xpos", "11" }, { "custom_124.ypos", "7" }, { "custom_124.frames", "1" }, { "custom_124.EDITOR", "RocksCE.png" }, { "custom_124.EDITOR.xpos", "27" }, { "custom_124.EDITOR.ypos", "7" }, { "custom_125", "RocksCE.png" }, { "custom_125.xpos", "12" }, { "custom_125.ypos", "7" }, { "custom_125.frames", "1" }, { "custom_125.EDITOR", "RocksCE.png" }, { "custom_125.EDITOR.xpos", "28" }, { "custom_125.EDITOR.ypos", "7" }, { "custom_126", "RocksCE.png" }, { "custom_126.xpos", "13" }, { "custom_126.ypos", "7" }, { "custom_126.frames", "1" }, { "custom_126.EDITOR", "RocksCE.png" }, { "custom_126.EDITOR.xpos", "29" }, { "custom_126.EDITOR.ypos", "7" }, { "custom_127", "RocksCE.png" }, { "custom_127.xpos", "14" }, { "custom_127.ypos", "7" }, { "custom_127.frames", "1" }, { "custom_127.EDITOR", "RocksCE.png" }, { "custom_127.EDITOR.xpos", "30" }, { "custom_127.EDITOR.ypos", "7" }, { "custom_128", "RocksCE.png" }, { "custom_128.xpos", "15" }, { "custom_128.ypos", "7" }, { "custom_128.frames", "1" }, { "custom_128.EDITOR", "RocksCE.png" }, { "custom_128.EDITOR.xpos", "31" }, { "custom_128.EDITOR.ypos", "7" }, { "custom_129", "RocksCE.png" }, { "custom_129.xpos", "0" }, { "custom_129.ypos", "8" }, { "custom_129.frames", "1" }, { "custom_129.EDITOR", "RocksCE.png" }, { "custom_129.EDITOR.xpos", "16" }, { "custom_129.EDITOR.ypos", "8" }, { "custom_130", "RocksCE.png" }, { "custom_130.xpos", "1" }, { "custom_130.ypos", "8" }, { "custom_130.frames", "1" }, { "custom_130.EDITOR", "RocksCE.png" }, { "custom_130.EDITOR.xpos", "17" }, { "custom_130.EDITOR.ypos", "8" }, { "custom_131", "RocksCE.png" }, { "custom_131.xpos", "2" }, { "custom_131.ypos", "8" }, { "custom_131.frames", "1" }, { "custom_131.EDITOR", "RocksCE.png" }, { "custom_131.EDITOR.xpos", "18" }, { "custom_131.EDITOR.ypos", "8" }, { "custom_132", "RocksCE.png" }, { "custom_132.xpos", "3" }, { "custom_132.ypos", "8" }, { "custom_132.frames", "1" }, { "custom_132.EDITOR", "RocksCE.png" }, { "custom_132.EDITOR.xpos", "19" }, { "custom_132.EDITOR.ypos", "8" }, { "custom_133", "RocksCE.png" }, { "custom_133.xpos", "4" }, { "custom_133.ypos", "8" }, { "custom_133.frames", "1" }, { "custom_133.EDITOR", "RocksCE.png" }, { "custom_133.EDITOR.xpos", "20" }, { "custom_133.EDITOR.ypos", "8" }, { "custom_134", "RocksCE.png" }, { "custom_134.xpos", "5" }, { "custom_134.ypos", "8" }, { "custom_134.frames", "1" }, { "custom_134.EDITOR", "RocksCE.png" }, { "custom_134.EDITOR.xpos", "21" }, { "custom_134.EDITOR.ypos", "8" }, { "custom_135", "RocksCE.png" }, { "custom_135.xpos", "6" }, { "custom_135.ypos", "8" }, { "custom_135.frames", "1" }, { "custom_135.EDITOR", "RocksCE.png" }, { "custom_135.EDITOR.xpos", "22" }, { "custom_135.EDITOR.ypos", "8" }, { "custom_136", "RocksCE.png" }, { "custom_136.xpos", "7" }, { "custom_136.ypos", "8" }, { "custom_136.frames", "1" }, { "custom_136.EDITOR", "RocksCE.png" }, { "custom_136.EDITOR.xpos", "23" }, { "custom_136.EDITOR.ypos", "8" }, { "custom_137", "RocksCE.png" }, { "custom_137.xpos", "8" }, { "custom_137.ypos", "8" }, { "custom_137.frames", "1" }, { "custom_137.EDITOR", "RocksCE.png" }, { "custom_137.EDITOR.xpos", "24" }, { "custom_137.EDITOR.ypos", "8" }, { "custom_138", "RocksCE.png" }, { "custom_138.xpos", "9" }, { "custom_138.ypos", "8" }, { "custom_138.frames", "1" }, { "custom_138.EDITOR", "RocksCE.png" }, { "custom_138.EDITOR.xpos", "25" }, { "custom_138.EDITOR.ypos", "8" }, { "custom_139", "RocksCE.png" }, { "custom_139.xpos", "10" }, { "custom_139.ypos", "8" }, { "custom_139.frames", "1" }, { "custom_139.EDITOR", "RocksCE.png" }, { "custom_139.EDITOR.xpos", "26" }, { "custom_139.EDITOR.ypos", "8" }, { "custom_140", "RocksCE.png" }, { "custom_140.xpos", "11" }, { "custom_140.ypos", "8" }, { "custom_140.frames", "1" }, { "custom_140.EDITOR", "RocksCE.png" }, { "custom_140.EDITOR.xpos", "27" }, { "custom_140.EDITOR.ypos", "8" }, { "custom_141", "RocksCE.png" }, { "custom_141.xpos", "12" }, { "custom_141.ypos", "8" }, { "custom_141.frames", "1" }, { "custom_141.EDITOR", "RocksCE.png" }, { "custom_141.EDITOR.xpos", "28" }, { "custom_141.EDITOR.ypos", "8" }, { "custom_142", "RocksCE.png" }, { "custom_142.xpos", "13" }, { "custom_142.ypos", "8" }, { "custom_142.frames", "1" }, { "custom_142.EDITOR", "RocksCE.png" }, { "custom_142.EDITOR.xpos", "29" }, { "custom_142.EDITOR.ypos", "8" }, { "custom_143", "RocksCE.png" }, { "custom_143.xpos", "14" }, { "custom_143.ypos", "8" }, { "custom_143.frames", "1" }, { "custom_143.EDITOR", "RocksCE.png" }, { "custom_143.EDITOR.xpos", "30" }, { "custom_143.EDITOR.ypos", "8" }, { "custom_144", "RocksCE.png" }, { "custom_144.xpos", "15" }, { "custom_144.ypos", "8" }, { "custom_144.frames", "1" }, { "custom_144.EDITOR", "RocksCE.png" }, { "custom_144.EDITOR.xpos", "31" }, { "custom_144.EDITOR.ypos", "8" }, { "custom_145", "RocksCE.png" }, { "custom_145.xpos", "0" }, { "custom_145.ypos", "9" }, { "custom_145.frames", "1" }, { "custom_145.EDITOR", "RocksCE.png" }, { "custom_145.EDITOR.xpos", "16" }, { "custom_145.EDITOR.ypos", "9" }, { "custom_146", "RocksCE.png" }, { "custom_146.xpos", "1" }, { "custom_146.ypos", "9" }, { "custom_146.frames", "1" }, { "custom_146.EDITOR", "RocksCE.png" }, { "custom_146.EDITOR.xpos", "17" }, { "custom_146.EDITOR.ypos", "9" }, { "custom_147", "RocksCE.png" }, { "custom_147.xpos", "2" }, { "custom_147.ypos", "9" }, { "custom_147.frames", "1" }, { "custom_147.EDITOR", "RocksCE.png" }, { "custom_147.EDITOR.xpos", "18" }, { "custom_147.EDITOR.ypos", "9" }, { "custom_148", "RocksCE.png" }, { "custom_148.xpos", "3" }, { "custom_148.ypos", "9" }, { "custom_148.frames", "1" }, { "custom_148.EDITOR", "RocksCE.png" }, { "custom_148.EDITOR.xpos", "19" }, { "custom_148.EDITOR.ypos", "9" }, { "custom_149", "RocksCE.png" }, { "custom_149.xpos", "4" }, { "custom_149.ypos", "9" }, { "custom_149.frames", "1" }, { "custom_149.EDITOR", "RocksCE.png" }, { "custom_149.EDITOR.xpos", "20" }, { "custom_149.EDITOR.ypos", "9" }, { "custom_150", "RocksCE.png" }, { "custom_150.xpos", "5" }, { "custom_150.ypos", "9" }, { "custom_150.frames", "1" }, { "custom_150.EDITOR", "RocksCE.png" }, { "custom_150.EDITOR.xpos", "21" }, { "custom_150.EDITOR.ypos", "9" }, { "custom_151", "RocksCE.png" }, { "custom_151.xpos", "6" }, { "custom_151.ypos", "9" }, { "custom_151.frames", "1" }, { "custom_151.EDITOR", "RocksCE.png" }, { "custom_151.EDITOR.xpos", "22" }, { "custom_151.EDITOR.ypos", "9" }, { "custom_152", "RocksCE.png" }, { "custom_152.xpos", "7" }, { "custom_152.ypos", "9" }, { "custom_152.frames", "1" }, { "custom_152.EDITOR", "RocksCE.png" }, { "custom_152.EDITOR.xpos", "23" }, { "custom_152.EDITOR.ypos", "9" }, { "custom_153", "RocksCE.png" }, { "custom_153.xpos", "8" }, { "custom_153.ypos", "9" }, { "custom_153.frames", "1" }, { "custom_153.EDITOR", "RocksCE.png" }, { "custom_153.EDITOR.xpos", "24" }, { "custom_153.EDITOR.ypos", "9" }, { "custom_154", "RocksCE.png" }, { "custom_154.xpos", "9" }, { "custom_154.ypos", "9" }, { "custom_154.frames", "1" }, { "custom_154.EDITOR", "RocksCE.png" }, { "custom_154.EDITOR.xpos", "25" }, { "custom_154.EDITOR.ypos", "9" }, { "custom_155", "RocksCE.png" }, { "custom_155.xpos", "10" }, { "custom_155.ypos", "9" }, { "custom_155.frames", "1" }, { "custom_155.EDITOR", "RocksCE.png" }, { "custom_155.EDITOR.xpos", "26" }, { "custom_155.EDITOR.ypos", "9" }, { "custom_156", "RocksCE.png" }, { "custom_156.xpos", "11" }, { "custom_156.ypos", "9" }, { "custom_156.frames", "1" }, { "custom_156.EDITOR", "RocksCE.png" }, { "custom_156.EDITOR.xpos", "27" }, { "custom_156.EDITOR.ypos", "9" }, { "custom_157", "RocksCE.png" }, { "custom_157.xpos", "12" }, { "custom_157.ypos", "9" }, { "custom_157.frames", "1" }, { "custom_157.EDITOR", "RocksCE.png" }, { "custom_157.EDITOR.xpos", "28" }, { "custom_157.EDITOR.ypos", "9" }, { "custom_158", "RocksCE.png" }, { "custom_158.xpos", "13" }, { "custom_158.ypos", "9" }, { "custom_158.frames", "1" }, { "custom_158.EDITOR", "RocksCE.png" }, { "custom_158.EDITOR.xpos", "29" }, { "custom_158.EDITOR.ypos", "9" }, { "custom_159", "RocksCE.png" }, { "custom_159.xpos", "14" }, { "custom_159.ypos", "9" }, { "custom_159.frames", "1" }, { "custom_159.EDITOR", "RocksCE.png" }, { "custom_159.EDITOR.xpos", "30" }, { "custom_159.EDITOR.ypos", "9" }, { "custom_160", "RocksCE.png" }, { "custom_160.xpos", "15" }, { "custom_160.ypos", "9" }, { "custom_160.frames", "1" }, { "custom_160.EDITOR", "RocksCE.png" }, { "custom_160.EDITOR.xpos", "31" }, { "custom_160.EDITOR.ypos", "9" }, { "custom_161", "RocksCE.png" }, { "custom_161.xpos", "0" }, { "custom_161.ypos", "10" }, { "custom_161.frames", "1" }, { "custom_161.EDITOR", "RocksCE.png" }, { "custom_161.EDITOR.xpos", "16" }, { "custom_161.EDITOR.ypos", "10" }, { "custom_162", "RocksCE.png" }, { "custom_162.xpos", "1" }, { "custom_162.ypos", "10" }, { "custom_162.frames", "1" }, { "custom_162.EDITOR", "RocksCE.png" }, { "custom_162.EDITOR.xpos", "17" }, { "custom_162.EDITOR.ypos", "10" }, { "custom_163", "RocksCE.png" }, { "custom_163.xpos", "2" }, { "custom_163.ypos", "10" }, { "custom_163.frames", "1" }, { "custom_163.EDITOR", "RocksCE.png" }, { "custom_163.EDITOR.xpos", "18" }, { "custom_163.EDITOR.ypos", "10" }, { "custom_164", "RocksCE.png" }, { "custom_164.xpos", "3" }, { "custom_164.ypos", "10" }, { "custom_164.frames", "1" }, { "custom_164.EDITOR", "RocksCE.png" }, { "custom_164.EDITOR.xpos", "19" }, { "custom_164.EDITOR.ypos", "10" }, { "custom_165", "RocksCE.png" }, { "custom_165.xpos", "4" }, { "custom_165.ypos", "10" }, { "custom_165.frames", "1" }, { "custom_165.EDITOR", "RocksCE.png" }, { "custom_165.EDITOR.xpos", "20" }, { "custom_165.EDITOR.ypos", "10" }, { "custom_166", "RocksCE.png" }, { "custom_166.xpos", "5" }, { "custom_166.ypos", "10" }, { "custom_166.frames", "1" }, { "custom_166.EDITOR", "RocksCE.png" }, { "custom_166.EDITOR.xpos", "21" }, { "custom_166.EDITOR.ypos", "10" }, { "custom_167", "RocksCE.png" }, { "custom_167.xpos", "6" }, { "custom_167.ypos", "10" }, { "custom_167.frames", "1" }, { "custom_167.EDITOR", "RocksCE.png" }, { "custom_167.EDITOR.xpos", "22" }, { "custom_167.EDITOR.ypos", "10" }, { "custom_168", "RocksCE.png" }, { "custom_168.xpos", "7" }, { "custom_168.ypos", "10" }, { "custom_168.frames", "1" }, { "custom_168.EDITOR", "RocksCE.png" }, { "custom_168.EDITOR.xpos", "23" }, { "custom_168.EDITOR.ypos", "10" }, { "custom_169", "RocksCE.png" }, { "custom_169.xpos", "8" }, { "custom_169.ypos", "10" }, { "custom_169.frames", "1" }, { "custom_169.EDITOR", "RocksCE.png" }, { "custom_169.EDITOR.xpos", "24" }, { "custom_169.EDITOR.ypos", "10" }, { "custom_170", "RocksCE.png" }, { "custom_170.xpos", "9" }, { "custom_170.ypos", "10" }, { "custom_170.frames", "1" }, { "custom_170.EDITOR", "RocksCE.png" }, { "custom_170.EDITOR.xpos", "25" }, { "custom_170.EDITOR.ypos", "10" }, { "custom_171", "RocksCE.png" }, { "custom_171.xpos", "10" }, { "custom_171.ypos", "10" }, { "custom_171.frames", "1" }, { "custom_171.EDITOR", "RocksCE.png" }, { "custom_171.EDITOR.xpos", "26" }, { "custom_171.EDITOR.ypos", "10" }, { "custom_172", "RocksCE.png" }, { "custom_172.xpos", "11" }, { "custom_172.ypos", "10" }, { "custom_172.frames", "1" }, { "custom_172.EDITOR", "RocksCE.png" }, { "custom_172.EDITOR.xpos", "27" }, { "custom_172.EDITOR.ypos", "10" }, { "custom_173", "RocksCE.png" }, { "custom_173.xpos", "12" }, { "custom_173.ypos", "10" }, { "custom_173.frames", "1" }, { "custom_173.EDITOR", "RocksCE.png" }, { "custom_173.EDITOR.xpos", "28" }, { "custom_173.EDITOR.ypos", "10" }, { "custom_174", "RocksCE.png" }, { "custom_174.xpos", "13" }, { "custom_174.ypos", "10" }, { "custom_174.frames", "1" }, { "custom_174.EDITOR", "RocksCE.png" }, { "custom_174.EDITOR.xpos", "29" }, { "custom_174.EDITOR.ypos", "10" }, { "custom_175", "RocksCE.png" }, { "custom_175.xpos", "14" }, { "custom_175.ypos", "10" }, { "custom_175.frames", "1" }, { "custom_175.EDITOR", "RocksCE.png" }, { "custom_175.EDITOR.xpos", "30" }, { "custom_175.EDITOR.ypos", "10" }, { "custom_176", "RocksCE.png" }, { "custom_176.xpos", "15" }, { "custom_176.ypos", "10" }, { "custom_176.frames", "1" }, { "custom_176.EDITOR", "RocksCE.png" }, { "custom_176.EDITOR.xpos", "31" }, { "custom_176.EDITOR.ypos", "10" }, { "custom_177", "RocksCE.png" }, { "custom_177.xpos", "0" }, { "custom_177.ypos", "11" }, { "custom_177.frames", "1" }, { "custom_177.EDITOR", "RocksCE.png" }, { "custom_177.EDITOR.xpos", "16" }, { "custom_177.EDITOR.ypos", "11" }, { "custom_178", "RocksCE.png" }, { "custom_178.xpos", "1" }, { "custom_178.ypos", "11" }, { "custom_178.frames", "1" }, { "custom_178.EDITOR", "RocksCE.png" }, { "custom_178.EDITOR.xpos", "17" }, { "custom_178.EDITOR.ypos", "11" }, { "custom_179", "RocksCE.png" }, { "custom_179.xpos", "2" }, { "custom_179.ypos", "11" }, { "custom_179.frames", "1" }, { "custom_179.EDITOR", "RocksCE.png" }, { "custom_179.EDITOR.xpos", "18" }, { "custom_179.EDITOR.ypos", "11" }, { "custom_180", "RocksCE.png" }, { "custom_180.xpos", "3" }, { "custom_180.ypos", "11" }, { "custom_180.frames", "1" }, { "custom_180.EDITOR", "RocksCE.png" }, { "custom_180.EDITOR.xpos", "19" }, { "custom_180.EDITOR.ypos", "11" }, { "custom_181", "RocksCE.png" }, { "custom_181.xpos", "4" }, { "custom_181.ypos", "11" }, { "custom_181.frames", "1" }, { "custom_181.EDITOR", "RocksCE.png" }, { "custom_181.EDITOR.xpos", "20" }, { "custom_181.EDITOR.ypos", "11" }, { "custom_182", "RocksCE.png" }, { "custom_182.xpos", "5" }, { "custom_182.ypos", "11" }, { "custom_182.frames", "1" }, { "custom_182.EDITOR", "RocksCE.png" }, { "custom_182.EDITOR.xpos", "21" }, { "custom_182.EDITOR.ypos", "11" }, { "custom_183", "RocksCE.png" }, { "custom_183.xpos", "6" }, { "custom_183.ypos", "11" }, { "custom_183.frames", "1" }, { "custom_183.EDITOR", "RocksCE.png" }, { "custom_183.EDITOR.xpos", "22" }, { "custom_183.EDITOR.ypos", "11" }, { "custom_184", "RocksCE.png" }, { "custom_184.xpos", "7" }, { "custom_184.ypos", "11" }, { "custom_184.frames", "1" }, { "custom_184.EDITOR", "RocksCE.png" }, { "custom_184.EDITOR.xpos", "23" }, { "custom_184.EDITOR.ypos", "11" }, { "custom_185", "RocksCE.png" }, { "custom_185.xpos", "8" }, { "custom_185.ypos", "11" }, { "custom_185.frames", "1" }, { "custom_185.EDITOR", "RocksCE.png" }, { "custom_185.EDITOR.xpos", "24" }, { "custom_185.EDITOR.ypos", "11" }, { "custom_186", "RocksCE.png" }, { "custom_186.xpos", "9" }, { "custom_186.ypos", "11" }, { "custom_186.frames", "1" }, { "custom_186.EDITOR", "RocksCE.png" }, { "custom_186.EDITOR.xpos", "25" }, { "custom_186.EDITOR.ypos", "11" }, { "custom_187", "RocksCE.png" }, { "custom_187.xpos", "10" }, { "custom_187.ypos", "11" }, { "custom_187.frames", "1" }, { "custom_187.EDITOR", "RocksCE.png" }, { "custom_187.EDITOR.xpos", "26" }, { "custom_187.EDITOR.ypos", "11" }, { "custom_188", "RocksCE.png" }, { "custom_188.xpos", "11" }, { "custom_188.ypos", "11" }, { "custom_188.frames", "1" }, { "custom_188.EDITOR", "RocksCE.png" }, { "custom_188.EDITOR.xpos", "27" }, { "custom_188.EDITOR.ypos", "11" }, { "custom_189", "RocksCE.png" }, { "custom_189.xpos", "12" }, { "custom_189.ypos", "11" }, { "custom_189.frames", "1" }, { "custom_189.EDITOR", "RocksCE.png" }, { "custom_189.EDITOR.xpos", "28" }, { "custom_189.EDITOR.ypos", "11" }, { "custom_190", "RocksCE.png" }, { "custom_190.xpos", "13" }, { "custom_190.ypos", "11" }, { "custom_190.frames", "1" }, { "custom_190.EDITOR", "RocksCE.png" }, { "custom_190.EDITOR.xpos", "29" }, { "custom_190.EDITOR.ypos", "11" }, { "custom_191", "RocksCE.png" }, { "custom_191.xpos", "14" }, { "custom_191.ypos", "11" }, { "custom_191.frames", "1" }, { "custom_191.EDITOR", "RocksCE.png" }, { "custom_191.EDITOR.xpos", "30" }, { "custom_191.EDITOR.ypos", "11" }, { "custom_192", "RocksCE.png" }, { "custom_192.xpos", "15" }, { "custom_192.ypos", "11" }, { "custom_192.frames", "1" }, { "custom_192.EDITOR", "RocksCE.png" }, { "custom_192.EDITOR.xpos", "31" }, { "custom_192.EDITOR.ypos", "11" }, { "custom_193", "RocksCE.png" }, { "custom_193.xpos", "0" }, { "custom_193.ypos", "12" }, { "custom_193.frames", "1" }, { "custom_193.EDITOR", "RocksCE.png" }, { "custom_193.EDITOR.xpos", "16" }, { "custom_193.EDITOR.ypos", "12" }, { "custom_194", "RocksCE.png" }, { "custom_194.xpos", "1" }, { "custom_194.ypos", "12" }, { "custom_194.frames", "1" }, { "custom_194.EDITOR", "RocksCE.png" }, { "custom_194.EDITOR.xpos", "17" }, { "custom_194.EDITOR.ypos", "12" }, { "custom_195", "RocksCE.png" }, { "custom_195.xpos", "2" }, { "custom_195.ypos", "12" }, { "custom_195.frames", "1" }, { "custom_195.EDITOR", "RocksCE.png" }, { "custom_195.EDITOR.xpos", "18" }, { "custom_195.EDITOR.ypos", "12" }, { "custom_196", "RocksCE.png" }, { "custom_196.xpos", "3" }, { "custom_196.ypos", "12" }, { "custom_196.frames", "1" }, { "custom_196.EDITOR", "RocksCE.png" }, { "custom_196.EDITOR.xpos", "19" }, { "custom_196.EDITOR.ypos", "12" }, { "custom_197", "RocksCE.png" }, { "custom_197.xpos", "4" }, { "custom_197.ypos", "12" }, { "custom_197.frames", "1" }, { "custom_197.EDITOR", "RocksCE.png" }, { "custom_197.EDITOR.xpos", "20" }, { "custom_197.EDITOR.ypos", "12" }, { "custom_198", "RocksCE.png" }, { "custom_198.xpos", "5" }, { "custom_198.ypos", "12" }, { "custom_198.frames", "1" }, { "custom_198.EDITOR", "RocksCE.png" }, { "custom_198.EDITOR.xpos", "21" }, { "custom_198.EDITOR.ypos", "12" }, { "custom_199", "RocksCE.png" }, { "custom_199.xpos", "6" }, { "custom_199.ypos", "12" }, { "custom_199.frames", "1" }, { "custom_199.EDITOR", "RocksCE.png" }, { "custom_199.EDITOR.xpos", "22" }, { "custom_199.EDITOR.ypos", "12" }, { "custom_200", "RocksCE.png" }, { "custom_200.xpos", "7" }, { "custom_200.ypos", "12" }, { "custom_200.frames", "1" }, { "custom_200.EDITOR", "RocksCE.png" }, { "custom_200.EDITOR.xpos", "23" }, { "custom_200.EDITOR.ypos", "12" }, { "custom_201", "RocksCE.png" }, { "custom_201.xpos", "8" }, { "custom_201.ypos", "12" }, { "custom_201.frames", "1" }, { "custom_201.EDITOR", "RocksCE.png" }, { "custom_201.EDITOR.xpos", "24" }, { "custom_201.EDITOR.ypos", "12" }, { "custom_202", "RocksCE.png" }, { "custom_202.xpos", "9" }, { "custom_202.ypos", "12" }, { "custom_202.frames", "1" }, { "custom_202.EDITOR", "RocksCE.png" }, { "custom_202.EDITOR.xpos", "25" }, { "custom_202.EDITOR.ypos", "12" }, { "custom_203", "RocksCE.png" }, { "custom_203.xpos", "10" }, { "custom_203.ypos", "12" }, { "custom_203.frames", "1" }, { "custom_203.EDITOR", "RocksCE.png" }, { "custom_203.EDITOR.xpos", "26" }, { "custom_203.EDITOR.ypos", "12" }, { "custom_204", "RocksCE.png" }, { "custom_204.xpos", "11" }, { "custom_204.ypos", "12" }, { "custom_204.frames", "1" }, { "custom_204.EDITOR", "RocksCE.png" }, { "custom_204.EDITOR.xpos", "27" }, { "custom_204.EDITOR.ypos", "12" }, { "custom_205", "RocksCE.png" }, { "custom_205.xpos", "12" }, { "custom_205.ypos", "12" }, { "custom_205.frames", "1" }, { "custom_205.EDITOR", "RocksCE.png" }, { "custom_205.EDITOR.xpos", "28" }, { "custom_205.EDITOR.ypos", "12" }, { "custom_206", "RocksCE.png" }, { "custom_206.xpos", "13" }, { "custom_206.ypos", "12" }, { "custom_206.frames", "1" }, { "custom_206.EDITOR", "RocksCE.png" }, { "custom_206.EDITOR.xpos", "29" }, { "custom_206.EDITOR.ypos", "12" }, { "custom_207", "RocksCE.png" }, { "custom_207.xpos", "14" }, { "custom_207.ypos", "12" }, { "custom_207.frames", "1" }, { "custom_207.EDITOR", "RocksCE.png" }, { "custom_207.EDITOR.xpos", "30" }, { "custom_207.EDITOR.ypos", "12" }, { "custom_208", "RocksCE.png" }, { "custom_208.xpos", "15" }, { "custom_208.ypos", "12" }, { "custom_208.frames", "1" }, { "custom_208.EDITOR", "RocksCE.png" }, { "custom_208.EDITOR.xpos", "31" }, { "custom_208.EDITOR.ypos", "12" }, { "custom_209", "RocksCE.png" }, { "custom_209.xpos", "0" }, { "custom_209.ypos", "13" }, { "custom_209.frames", "1" }, { "custom_209.EDITOR", "RocksCE.png" }, { "custom_209.EDITOR.xpos", "16" }, { "custom_209.EDITOR.ypos", "13" }, { "custom_210", "RocksCE.png" }, { "custom_210.xpos", "1" }, { "custom_210.ypos", "13" }, { "custom_210.frames", "1" }, { "custom_210.EDITOR", "RocksCE.png" }, { "custom_210.EDITOR.xpos", "17" }, { "custom_210.EDITOR.ypos", "13" }, { "custom_211", "RocksCE.png" }, { "custom_211.xpos", "2" }, { "custom_211.ypos", "13" }, { "custom_211.frames", "1" }, { "custom_211.EDITOR", "RocksCE.png" }, { "custom_211.EDITOR.xpos", "18" }, { "custom_211.EDITOR.ypos", "13" }, { "custom_212", "RocksCE.png" }, { "custom_212.xpos", "3" }, { "custom_212.ypos", "13" }, { "custom_212.frames", "1" }, { "custom_212.EDITOR", "RocksCE.png" }, { "custom_212.EDITOR.xpos", "19" }, { "custom_212.EDITOR.ypos", "13" }, { "custom_213", "RocksCE.png" }, { "custom_213.xpos", "4" }, { "custom_213.ypos", "13" }, { "custom_213.frames", "1" }, { "custom_213.EDITOR", "RocksCE.png" }, { "custom_213.EDITOR.xpos", "20" }, { "custom_213.EDITOR.ypos", "13" }, { "custom_214", "RocksCE.png" }, { "custom_214.xpos", "5" }, { "custom_214.ypos", "13" }, { "custom_214.frames", "1" }, { "custom_214.EDITOR", "RocksCE.png" }, { "custom_214.EDITOR.xpos", "21" }, { "custom_214.EDITOR.ypos", "13" }, { "custom_215", "RocksCE.png" }, { "custom_215.xpos", "6" }, { "custom_215.ypos", "13" }, { "custom_215.frames", "1" }, { "custom_215.EDITOR", "RocksCE.png" }, { "custom_215.EDITOR.xpos", "22" }, { "custom_215.EDITOR.ypos", "13" }, { "custom_216", "RocksCE.png" }, { "custom_216.xpos", "7" }, { "custom_216.ypos", "13" }, { "custom_216.frames", "1" }, { "custom_216.EDITOR", "RocksCE.png" }, { "custom_216.EDITOR.xpos", "23" }, { "custom_216.EDITOR.ypos", "13" }, { "custom_217", "RocksCE.png" }, { "custom_217.xpos", "8" }, { "custom_217.ypos", "13" }, { "custom_217.frames", "1" }, { "custom_217.EDITOR", "RocksCE.png" }, { "custom_217.EDITOR.xpos", "24" }, { "custom_217.EDITOR.ypos", "13" }, { "custom_218", "RocksCE.png" }, { "custom_218.xpos", "9" }, { "custom_218.ypos", "13" }, { "custom_218.frames", "1" }, { "custom_218.EDITOR", "RocksCE.png" }, { "custom_218.EDITOR.xpos", "25" }, { "custom_218.EDITOR.ypos", "13" }, { "custom_219", "RocksCE.png" }, { "custom_219.xpos", "10" }, { "custom_219.ypos", "13" }, { "custom_219.frames", "1" }, { "custom_219.EDITOR", "RocksCE.png" }, { "custom_219.EDITOR.xpos", "26" }, { "custom_219.EDITOR.ypos", "13" }, { "custom_220", "RocksCE.png" }, { "custom_220.xpos", "11" }, { "custom_220.ypos", "13" }, { "custom_220.frames", "1" }, { "custom_220.EDITOR", "RocksCE.png" }, { "custom_220.EDITOR.xpos", "27" }, { "custom_220.EDITOR.ypos", "13" }, { "custom_221", "RocksCE.png" }, { "custom_221.xpos", "12" }, { "custom_221.ypos", "13" }, { "custom_221.frames", "1" }, { "custom_221.EDITOR", "RocksCE.png" }, { "custom_221.EDITOR.xpos", "28" }, { "custom_221.EDITOR.ypos", "13" }, { "custom_222", "RocksCE.png" }, { "custom_222.xpos", "13" }, { "custom_222.ypos", "13" }, { "custom_222.frames", "1" }, { "custom_222.EDITOR", "RocksCE.png" }, { "custom_222.EDITOR.xpos", "29" }, { "custom_222.EDITOR.ypos", "13" }, { "custom_223", "RocksCE.png" }, { "custom_223.xpos", "14" }, { "custom_223.ypos", "13" }, { "custom_223.frames", "1" }, { "custom_223.EDITOR", "RocksCE.png" }, { "custom_223.EDITOR.xpos", "30" }, { "custom_223.EDITOR.ypos", "13" }, { "custom_224", "RocksCE.png" }, { "custom_224.xpos", "15" }, { "custom_224.ypos", "13" }, { "custom_224.frames", "1" }, { "custom_224.EDITOR", "RocksCE.png" }, { "custom_224.EDITOR.xpos", "31" }, { "custom_224.EDITOR.ypos", "13" }, { "custom_225", "RocksCE.png" }, { "custom_225.xpos", "0" }, { "custom_225.ypos", "14" }, { "custom_225.frames", "1" }, { "custom_225.EDITOR", "RocksCE.png" }, { "custom_225.EDITOR.xpos", "16" }, { "custom_225.EDITOR.ypos", "14" }, { "custom_226", "RocksCE.png" }, { "custom_226.xpos", "1" }, { "custom_226.ypos", "14" }, { "custom_226.frames", "1" }, { "custom_226.EDITOR", "RocksCE.png" }, { "custom_226.EDITOR.xpos", "17" }, { "custom_226.EDITOR.ypos", "14" }, { "custom_227", "RocksCE.png" }, { "custom_227.xpos", "2" }, { "custom_227.ypos", "14" }, { "custom_227.frames", "1" }, { "custom_227.EDITOR", "RocksCE.png" }, { "custom_227.EDITOR.xpos", "18" }, { "custom_227.EDITOR.ypos", "14" }, { "custom_228", "RocksCE.png" }, { "custom_228.xpos", "3" }, { "custom_228.ypos", "14" }, { "custom_228.frames", "1" }, { "custom_228.EDITOR", "RocksCE.png" }, { "custom_228.EDITOR.xpos", "19" }, { "custom_228.EDITOR.ypos", "14" }, { "custom_229", "RocksCE.png" }, { "custom_229.xpos", "4" }, { "custom_229.ypos", "14" }, { "custom_229.frames", "1" }, { "custom_229.EDITOR", "RocksCE.png" }, { "custom_229.EDITOR.xpos", "20" }, { "custom_229.EDITOR.ypos", "14" }, { "custom_230", "RocksCE.png" }, { "custom_230.xpos", "5" }, { "custom_230.ypos", "14" }, { "custom_230.frames", "1" }, { "custom_230.EDITOR", "RocksCE.png" }, { "custom_230.EDITOR.xpos", "21" }, { "custom_230.EDITOR.ypos", "14" }, { "custom_231", "RocksCE.png" }, { "custom_231.xpos", "6" }, { "custom_231.ypos", "14" }, { "custom_231.frames", "1" }, { "custom_231.EDITOR", "RocksCE.png" }, { "custom_231.EDITOR.xpos", "22" }, { "custom_231.EDITOR.ypos", "14" }, { "custom_232", "RocksCE.png" }, { "custom_232.xpos", "7" }, { "custom_232.ypos", "14" }, { "custom_232.frames", "1" }, { "custom_232.EDITOR", "RocksCE.png" }, { "custom_232.EDITOR.xpos", "23" }, { "custom_232.EDITOR.ypos", "14" }, { "custom_233", "RocksCE.png" }, { "custom_233.xpos", "8" }, { "custom_233.ypos", "14" }, { "custom_233.frames", "1" }, { "custom_233.EDITOR", "RocksCE.png" }, { "custom_233.EDITOR.xpos", "24" }, { "custom_233.EDITOR.ypos", "14" }, { "custom_234", "RocksCE.png" }, { "custom_234.xpos", "9" }, { "custom_234.ypos", "14" }, { "custom_234.frames", "1" }, { "custom_234.EDITOR", "RocksCE.png" }, { "custom_234.EDITOR.xpos", "25" }, { "custom_234.EDITOR.ypos", "14" }, { "custom_235", "RocksCE.png" }, { "custom_235.xpos", "10" }, { "custom_235.ypos", "14" }, { "custom_235.frames", "1" }, { "custom_235.EDITOR", "RocksCE.png" }, { "custom_235.EDITOR.xpos", "26" }, { "custom_235.EDITOR.ypos", "14" }, { "custom_236", "RocksCE.png" }, { "custom_236.xpos", "11" }, { "custom_236.ypos", "14" }, { "custom_236.frames", "1" }, { "custom_236.EDITOR", "RocksCE.png" }, { "custom_236.EDITOR.xpos", "27" }, { "custom_236.EDITOR.ypos", "14" }, { "custom_237", "RocksCE.png" }, { "custom_237.xpos", "12" }, { "custom_237.ypos", "14" }, { "custom_237.frames", "1" }, { "custom_237.EDITOR", "RocksCE.png" }, { "custom_237.EDITOR.xpos", "28" }, { "custom_237.EDITOR.ypos", "14" }, { "custom_238", "RocksCE.png" }, { "custom_238.xpos", "13" }, { "custom_238.ypos", "14" }, { "custom_238.frames", "1" }, { "custom_238.EDITOR", "RocksCE.png" }, { "custom_238.EDITOR.xpos", "29" }, { "custom_238.EDITOR.ypos", "14" }, { "custom_239", "RocksCE.png" }, { "custom_239.xpos", "14" }, { "custom_239.ypos", "14" }, { "custom_239.frames", "1" }, { "custom_239.EDITOR", "RocksCE.png" }, { "custom_239.EDITOR.xpos", "30" }, { "custom_239.EDITOR.ypos", "14" }, { "custom_240", "RocksCE.png" }, { "custom_240.xpos", "15" }, { "custom_240.ypos", "14" }, { "custom_240.frames", "1" }, { "custom_240.EDITOR", "RocksCE.png" }, { "custom_240.EDITOR.xpos", "31" }, { "custom_240.EDITOR.ypos", "14" }, { "custom_241", "RocksCE.png" }, { "custom_241.xpos", "0" }, { "custom_241.ypos", "15" }, { "custom_241.frames", "1" }, { "custom_241.EDITOR", "RocksCE.png" }, { "custom_241.EDITOR.xpos", "16" }, { "custom_241.EDITOR.ypos", "15" }, { "custom_242", "RocksCE.png" }, { "custom_242.xpos", "1" }, { "custom_242.ypos", "15" }, { "custom_242.frames", "1" }, { "custom_242.EDITOR", "RocksCE.png" }, { "custom_242.EDITOR.xpos", "17" }, { "custom_242.EDITOR.ypos", "15" }, { "custom_243", "RocksCE.png" }, { "custom_243.xpos", "2" }, { "custom_243.ypos", "15" }, { "custom_243.frames", "1" }, { "custom_243.EDITOR", "RocksCE.png" }, { "custom_243.EDITOR.xpos", "18" }, { "custom_243.EDITOR.ypos", "15" }, { "custom_244", "RocksCE.png" }, { "custom_244.xpos", "3" }, { "custom_244.ypos", "15" }, { "custom_244.frames", "1" }, { "custom_244.EDITOR", "RocksCE.png" }, { "custom_244.EDITOR.xpos", "19" }, { "custom_244.EDITOR.ypos", "15" }, { "custom_245", "RocksCE.png" }, { "custom_245.xpos", "4" }, { "custom_245.ypos", "15" }, { "custom_245.frames", "1" }, { "custom_245.EDITOR", "RocksCE.png" }, { "custom_245.EDITOR.xpos", "20" }, { "custom_245.EDITOR.ypos", "15" }, { "custom_246", "RocksCE.png" }, { "custom_246.xpos", "5" }, { "custom_246.ypos", "15" }, { "custom_246.frames", "1" }, { "custom_246.EDITOR", "RocksCE.png" }, { "custom_246.EDITOR.xpos", "21" }, { "custom_246.EDITOR.ypos", "15" }, { "custom_247", "RocksCE.png" }, { "custom_247.xpos", "6" }, { "custom_247.ypos", "15" }, { "custom_247.frames", "1" }, { "custom_247.EDITOR", "RocksCE.png" }, { "custom_247.EDITOR.xpos", "22" }, { "custom_247.EDITOR.ypos", "15" }, { "custom_248", "RocksCE.png" }, { "custom_248.xpos", "7" }, { "custom_248.ypos", "15" }, { "custom_248.frames", "1" }, { "custom_248.EDITOR", "RocksCE.png" }, { "custom_248.EDITOR.xpos", "23" }, { "custom_248.EDITOR.ypos", "15" }, { "custom_249", "RocksCE.png" }, { "custom_249.xpos", "8" }, { "custom_249.ypos", "15" }, { "custom_249.frames", "1" }, { "custom_249.EDITOR", "RocksCE.png" }, { "custom_249.EDITOR.xpos", "24" }, { "custom_249.EDITOR.ypos", "15" }, { "custom_250", "RocksCE.png" }, { "custom_250.xpos", "9" }, { "custom_250.ypos", "15" }, { "custom_250.frames", "1" }, { "custom_250.EDITOR", "RocksCE.png" }, { "custom_250.EDITOR.xpos", "25" }, { "custom_250.EDITOR.ypos", "15" }, { "custom_251", "RocksCE.png" }, { "custom_251.xpos", "10" }, { "custom_251.ypos", "15" }, { "custom_251.frames", "1" }, { "custom_251.EDITOR", "RocksCE.png" }, { "custom_251.EDITOR.xpos", "26" }, { "custom_251.EDITOR.ypos", "15" }, { "custom_252", "RocksCE.png" }, { "custom_252.xpos", "11" }, { "custom_252.ypos", "15" }, { "custom_252.frames", "1" }, { "custom_252.EDITOR", "RocksCE.png" }, { "custom_252.EDITOR.xpos", "27" }, { "custom_252.EDITOR.ypos", "15" }, { "custom_253", "RocksCE.png" }, { "custom_253.xpos", "12" }, { "custom_253.ypos", "15" }, { "custom_253.frames", "1" }, { "custom_253.EDITOR", "RocksCE.png" }, { "custom_253.EDITOR.xpos", "28" }, { "custom_253.EDITOR.ypos", "15" }, { "custom_254", "RocksCE.png" }, { "custom_254.xpos", "13" }, { "custom_254.ypos", "15" }, { "custom_254.frames", "1" }, { "custom_254.EDITOR", "RocksCE.png" }, { "custom_254.EDITOR.xpos", "29" }, { "custom_254.EDITOR.ypos", "15" }, { "custom_255", "RocksCE.png" }, { "custom_255.xpos", "14" }, { "custom_255.ypos", "15" }, { "custom_255.frames", "1" }, { "custom_255.EDITOR", "RocksCE.png" }, { "custom_255.EDITOR.xpos", "30" }, { "custom_255.EDITOR.ypos", "15" }, { "custom_256", "RocksCE.png" }, { "custom_256.xpos", "15" }, { "custom_256.ypos", "15" }, { "custom_256.frames", "1" }, { "custom_256.EDITOR", "RocksCE.png" }, { "custom_256.EDITOR.xpos", "31" }, { "custom_256.EDITOR.ypos", "15" }, #endif /* CONF_CUS_C */ mirrormagic-3.0.0/src/events.c0000644000175000017500000017716513263212010015601 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // events.c // ============================================================================ #include "libgame/libgame.h" #include "events.h" #include "init.h" #include "screens.h" #include "tools.h" #include "game.h" #include "editor.h" #include "files.h" #include "tape.h" #include "anim.h" #include "network.h" #define DEBUG_EVENTS 0 #define DEBUG_EVENTS_BUTTON (DEBUG_EVENTS * 0) #define DEBUG_EVENTS_MOTION (DEBUG_EVENTS * 0) #define DEBUG_EVENTS_WHEEL (DEBUG_EVENTS * 1) #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0) #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0) #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1) #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1) static boolean cursor_inside_playfield = FALSE; static int cursor_mode_last = CURSOR_DEFAULT; static unsigned int special_cursor_delay = 0; static unsigned int special_cursor_delay_value = 1000; /* forward declarations for internal use */ static void HandleNoEvent(void); static void HandleEventActions(void); /* event filter especially needed for SDL event filtering due to delay problems with lots of mouse motion events when mouse button not pressed (X11 can handle this with 'PointerMotionHintMask') */ /* event filter addition for SDL2: as SDL2 does not have a function to enable or disable keyboard auto-repeat, filter repeated keyboard events instead */ static int FilterEvents(const Event *event) { MotionEvent *motion; #if defined(TARGET_SDL2) /* skip repeated key press events if keyboard auto-repeat is disabled */ if (event->type == EVENT_KEYPRESS && event->key.repeat && !keyrepeat_status) return 0; #endif if (event->type == EVENT_BUTTONPRESS || event->type == EVENT_BUTTONRELEASE) { ((ButtonEvent *)event)->x -= video.screen_xoffset; ((ButtonEvent *)event)->y -= video.screen_yoffset; } else if (event->type == EVENT_MOTIONNOTIFY) { ((MotionEvent *)event)->x -= video.screen_xoffset; ((MotionEvent *)event)->y -= video.screen_yoffset; } /* non-motion events are directly passed to event handler functions */ if (event->type != EVENT_MOTIONNOTIFY) return 1; motion = (MotionEvent *)event; cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE && motion->y >= SY && motion->y < SY + SYSIZE); /* do no reset mouse cursor before all pending events have been processed */ if (gfx.cursor_mode == cursor_mode_last && ((game_status == GAME_MODE_TITLE && gfx.cursor_mode == CURSOR_NONE) || (game_status == GAME_MODE_PLAYING && gfx.cursor_mode == CURSOR_PLAYFIELD))) { SetMouseCursor(CURSOR_DEFAULT); DelayReached(&special_cursor_delay, 0); cursor_mode_last = CURSOR_DEFAULT; } /* skip mouse motion events without pressed button outside level editor */ if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING) return 0; return 1; } /* to prevent delay problems, skip mouse motion events if the very next event is also a mouse motion event (and therefore effectively only handling the last of a row of mouse motion events in the event queue) */ static boolean SkipPressedMouseMotionEvent(const Event *event) { /* nothing to do if the current event is not a mouse motion event */ if (event->type != EVENT_MOTIONNOTIFY) return FALSE; /* only skip motion events with pressed button outside the game */ if (button_status == MB_RELEASED || game_status == GAME_MODE_PLAYING) return FALSE; if (PendingEvent()) { Event next_event; PeekEvent(&next_event); /* if next event is also a mouse motion event, skip the current one */ if (next_event.type == EVENT_MOTIONNOTIFY) return TRUE; } return FALSE; } static boolean WaitValidEvent(Event *event) { WaitEvent(event); if (!FilterEvents(event)) return FALSE; if (SkipPressedMouseMotionEvent(event)) return FALSE; return TRUE; } /* this is especially needed for event modifications for the Android target: if mouse coordinates should be modified in the event filter function, using a properly installed SDL event filter does not work, because in the event filter, mouse coordinates in the event structure are still physical pixel positions, not logical (scaled) screen positions, so this has to be handled at a later stage in the event processing functions (when device pixel positions are already converted to screen positions) */ boolean NextValidEvent(Event *event) { while (PendingEvent()) if (WaitValidEvent(event)) return TRUE; return FALSE; } void HandleEvents() { Event event; unsigned int event_frame_delay = 0; unsigned int event_frame_delay_value = GAME_FRAME_DELAY; ResetDelayCounter(&event_frame_delay); while (NextValidEvent(&event)) { switch (event.type) { case EVENT_BUTTONPRESS: case EVENT_BUTTONRELEASE: HandleButtonEvent((ButtonEvent *) &event); break; case EVENT_MOTIONNOTIFY: HandleMotionEvent((MotionEvent *) &event); break; #if defined(TARGET_SDL2) case EVENT_WHEELMOTION: HandleWheelEvent((WheelEvent *) &event); break; case SDL_WINDOWEVENT: HandleWindowEvent((WindowEvent *) &event); break; case EVENT_FINGERPRESS: case EVENT_FINGERRELEASE: case EVENT_FINGERMOTION: HandleFingerEvent((FingerEvent *) &event); break; case EVENT_TEXTINPUT: HandleTextEvent((TextEvent *) &event); break; case SDL_APP_WILLENTERBACKGROUND: case SDL_APP_DIDENTERBACKGROUND: case SDL_APP_WILLENTERFOREGROUND: case SDL_APP_DIDENTERFOREGROUND: HandlePauseResumeEvent((PauseResumeEvent *) &event); break; #endif case EVENT_KEYPRESS: case EVENT_KEYRELEASE: HandleKeyEvent((KeyEvent *) &event); break; default: HandleOtherEvents(&event); break; } // do not handle events for longer than standard frame delay period if (DelayReached(&event_frame_delay, event_frame_delay_value)) break; } } void HandleOtherEvents(Event *event) { switch (event->type) { case EVENT_EXPOSE: HandleExposeEvent((ExposeEvent *) event); break; case EVENT_UNMAPNOTIFY: #if 0 /* This causes the game to stop not only when iconified, but also when on another virtual desktop, which might be not desired. */ SleepWhileUnmapped(); #endif break; case EVENT_FOCUSIN: case EVENT_FOCUSOUT: HandleFocusEvent((FocusChangeEvent *) event); break; case EVENT_CLIENTMESSAGE: HandleClientMessageEvent((ClientMessageEvent *) event); break; #if defined(TARGET_SDL) #if defined(TARGET_SDL2) case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: // for any game controller button event, disable overlay buttons SetOverlayEnabled(FALSE); HandleSpecialGameControllerButtons(event); /* FALL THROUGH */ case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEREMOVED: case SDL_CONTROLLERAXISMOTION: #endif case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: HandleJoystickEvent(event); break; case SDL_SYSWMEVENT: HandleWindowManagerEvent(event); break; #endif default: break; } } void HandleMouseCursor() { if (game_status == GAME_MODE_TITLE) { /* when showing title screens, hide mouse pointer (if not moved) */ if (gfx.cursor_mode != CURSOR_NONE && DelayReached(&special_cursor_delay, special_cursor_delay_value)) { SetMouseCursor(CURSOR_NONE); } } else if (game_status == GAME_MODE_PLAYING && (!tape.pausing || tape.single_step)) { /* when playing, display a special mouse pointer inside the playfield */ if (gfx.cursor_mode != CURSOR_PLAYFIELD && cursor_inside_playfield && DelayReached(&special_cursor_delay, special_cursor_delay_value)) { if (level.game_engine_type != GAME_ENGINE_TYPE_MM || tile_cursor.enabled) SetMouseCursor(CURSOR_PLAYFIELD); } } else if (gfx.cursor_mode != CURSOR_DEFAULT) { SetMouseCursor(CURSOR_DEFAULT); } /* this is set after all pending events have been processed */ cursor_mode_last = gfx.cursor_mode; } void EventLoop(void) { while (1) { if (PendingEvent()) HandleEvents(); else HandleNoEvent(); /* execute event related actions after pending events have been processed */ HandleEventActions(); /* 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 == GAME_MODE_PLAYING) HandleGameActions(); /* always copy backbuffer to visible screen for every video frame */ BackToFront(); /* reset video frame delay to default (may change again while playing) */ SetVideoFrameDelay(MenuFrameDelay); if (game_status == GAME_MODE_QUIT) return; } } void ClearEventQueue() { Event event; while (NextValidEvent(&event)) { switch (event.type) { case EVENT_BUTTONRELEASE: button_status = MB_RELEASED; break; case EVENT_KEYRELEASE: ClearPlayerAction(); break; #if defined(TARGET_SDL2) case SDL_CONTROLLERBUTTONUP: HandleJoystickEvent(&event); ClearPlayerAction(); break; #endif default: HandleOtherEvents(&event); break; } } } void ClearPlayerMouseAction() { local_player->mouse_action.lx = 0; local_player->mouse_action.ly = 0; local_player->mouse_action.button = 0; } void ClearPlayerAction() { int i; /* simulate key release events for still pressed keys */ key_joystick_mapping = 0; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].action = 0; ClearJoystickState(); ClearPlayerMouseAction(); } void SetPlayerMouseAction(int mx, int my, int button) { int lx = getLevelFromScreenX(mx); int ly = getLevelFromScreenY(my); int new_button = (!local_player->mouse_action.button && button); if (local_player->mouse_action.button_hint) button = local_player->mouse_action.button_hint; ClearPlayerMouseAction(); if (!IN_GFX_FIELD_PLAY(mx, my) || !IN_LEV_FIELD(lx, ly)) return; local_player->mouse_action.lx = lx; local_player->mouse_action.ly = ly; local_player->mouse_action.button = button; if (tape.recording && tape.pausing && tape.use_mouse) { /* un-pause a paused game only if mouse button was newly pressed down */ if (new_button) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); } SetTileCursorXY(lx, ly); } void SleepWhileUnmapped() { boolean window_unmapped = TRUE; KeyboardAutoRepeatOn(); while (window_unmapped) { Event event; if (!WaitValidEvent(&event)) continue; switch (event.type) { case EVENT_BUTTONRELEASE: button_status = MB_RELEASED; break; case EVENT_KEYRELEASE: key_joystick_mapping = 0; break; #if defined(TARGET_SDL2) case SDL_CONTROLLERBUTTONUP: HandleJoystickEvent(&event); key_joystick_mapping = 0; break; #endif case EVENT_MAPNOTIFY: window_unmapped = FALSE; break; case EVENT_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; } } if (game_status == GAME_MODE_PLAYING) KeyboardAutoRepeatOffUnlessAutoplay(); } void HandleExposeEvent(ExposeEvent *event) { } void HandleButtonEvent(ButtonEvent *event) { #if DEBUG_EVENTS_BUTTON Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n", event->button, event->type == EVENT_BUTTONPRESS ? "pressed" : "released", event->x, event->y); #endif // for any mouse button event, disable playfield tile cursor SetTileCursorEnabled(FALSE); #if defined(HAS_SCREEN_KEYBOARD) if (video.shifted_up) event->y += video.shifted_up_pos; #endif motion_status = FALSE; if (event->type == EVENT_BUTTONPRESS) button_status = event->button; else button_status = MB_RELEASED; HandleButton(event->x, event->y, button_status, event->button); } void HandleMotionEvent(MotionEvent *event) { if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR) return; motion_status = TRUE; #if DEBUG_EVENTS_MOTION Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n", button_status, event->x, event->y); #endif HandleButton(event->x, event->y, button_status, button_status); } #if defined(TARGET_SDL2) void HandleWheelEvent(WheelEvent *event) { int button_nr; #if DEBUG_EVENTS_WHEEL #if 1 Error(ERR_DEBUG, "WHEEL EVENT: mouse == %d, x/y == %d/%d\n", event->which, event->x, event->y); #else // (SDL_MOUSEWHEEL_NORMAL/SDL_MOUSEWHEEL_FLIPPED needs SDL 2.0.4 or newer) Error(ERR_DEBUG, "WHEEL EVENT: mouse == %d, x/y == %d/%d, direction == %s\n", event->which, event->x, event->y, (event->direction == SDL_MOUSEWHEEL_NORMAL ? "SDL_MOUSEWHEEL_NORMAL" : "SDL_MOUSEWHEEL_FLIPPED")); #endif #endif button_nr = (event->x < 0 ? MB_WHEEL_LEFT : event->x > 0 ? MB_WHEEL_RIGHT : event->y < 0 ? MB_WHEEL_DOWN : event->y > 0 ? MB_WHEEL_UP : 0); #if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX) // accelerated mouse wheel available on Mac and Windows wheel_steps = (event->x ? ABS(event->x) : ABS(event->y)); #else // no accelerated mouse wheel available on Unix/Linux wheel_steps = DEFAULT_WHEEL_STEPS; #endif motion_status = FALSE; button_status = button_nr; HandleButton(0, 0, button_status, -button_nr); button_status = MB_RELEASED; HandleButton(0, 0, button_status, -button_nr); } void HandleWindowEvent(WindowEvent *event) { #if DEBUG_EVENTS_WINDOW int subtype = event->event; char *event_name = (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" : subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" : subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" : subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" : subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" : subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" : subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" : subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" : subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" : subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" : subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" : subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" : subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" : subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" : "(UNKNOWN)"); Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld", event_name, event->data1, event->data2); #endif #if 0 // (not needed, as the screen gets redrawn every 20 ms anyway) if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED || event->event == SDL_WINDOWEVENT_RESIZED || event->event == SDL_WINDOWEVENT_EXPOSED) SDLRedrawWindow(); #endif if (event->event == SDL_WINDOWEVENT_RESIZED) { if (!video.fullscreen_enabled) { int new_window_width = event->data1; int new_window_height = event->data2; // if window size has changed after resizing, calculate new scaling factor if (new_window_width != video.window_width || new_window_height != video.window_height) { int new_xpercent = 100.0 * new_window_width / video.screen_width + .5; int new_ypercent = 100.0 * new_window_height / video.screen_height + .5; // (extreme window scaling allowed, but cannot be saved permanently) video.window_scaling_percent = MIN(new_xpercent, new_ypercent); setup.window_scaling_percent = MIN(MAX(MIN_WINDOW_SCALING_PERCENT, video.window_scaling_percent), MAX_WINDOW_SCALING_PERCENT); video.window_width = new_window_width; video.window_height = new_window_height; if (game_status == GAME_MODE_SETUP) RedrawSetupScreenAfterFullscreenToggle(); SetWindowTitle(); } } #if defined(PLATFORM_ANDROID) else { int new_display_width = event->data1; int new_display_height = event->data2; // if fullscreen display size has changed, device has been rotated if (new_display_width != video.display_width || new_display_height != video.display_height) { video.display_width = new_display_width; video.display_height = new_display_height; SDLSetScreenProperties(); } } #endif } } #define NUM_TOUCH_FINGERS 3 static struct { boolean touched; SDL_FingerID finger_id; int counter; Key key; } touch_info[NUM_TOUCH_FINGERS]; void HandleFingerEvent_VirtualButtons(FingerEvent *event) { float ypos = 1.0 - 1.0 / 3.0 * video.display_width / video.display_height; float event_x = (event->x); float event_y = (event->y - ypos) / (1 - ypos); Key key = (event_x > 0 && event_x < 1.0 / 6.0 && event_y > 2.0 / 3.0 && event_y < 1 ? setup.input[0].key.snap : event_x > 1.0 / 6.0 && event_x < 1.0 / 3.0 && event_y > 2.0 / 3.0 && event_y < 1 ? setup.input[0].key.drop : event_x > 7.0 / 9.0 && event_x < 8.0 / 9.0 && event_y > 0 && event_y < 1.0 / 3.0 ? setup.input[0].key.up : event_x > 6.0 / 9.0 && event_x < 7.0 / 9.0 && event_y > 1.0 / 3.0 && event_y < 2.0 / 3.0 ? setup.input[0].key.left : event_x > 8.0 / 9.0 && event_x < 1 && event_y > 1.0 / 3.0 && event_y < 2.0 / 3.0 ? setup.input[0].key.right : event_x > 7.0 / 9.0 && event_x < 8.0 / 9.0 && event_y > 2.0 / 3.0 && event_y < 1 ? setup.input[0].key.down : KSYM_UNDEFINED); int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED : KEY_PRESSED); char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" : "KEY_PRESSED"); int i; // for any touch input event, enable overlay buttons (if activated) SetOverlayEnabled(TRUE); Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]", getKeyNameFromKey(key), key_status_name, event->fingerId); // check if we already know this touch event's finger id for (i = 0; i < NUM_TOUCH_FINGERS; i++) { if (touch_info[i].touched && touch_info[i].finger_id == event->fingerId) { // Error(ERR_DEBUG, "MARK 1: %d", i); break; } } if (i >= NUM_TOUCH_FINGERS) { if (key_status == KEY_PRESSED) { int oldest_pos = 0, oldest_counter = touch_info[0].counter; // unknown finger id -- get new, empty slot, if available for (i = 0; i < NUM_TOUCH_FINGERS; i++) { if (touch_info[i].counter < oldest_counter) { oldest_pos = i; oldest_counter = touch_info[i].counter; // Error(ERR_DEBUG, "MARK 2: %d", i); } if (!touch_info[i].touched) { // Error(ERR_DEBUG, "MARK 3: %d", i); break; } } if (i >= NUM_TOUCH_FINGERS) { // all slots allocated -- use oldest slot i = oldest_pos; // Error(ERR_DEBUG, "MARK 4: %d", i); } } else { // release of previously unknown key (should not happen) if (key != KSYM_UNDEFINED) { HandleKey(key, KEY_RELEASED); Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]", getKeyNameFromKey(key), "KEY_RELEASED", i); } } } if (i < NUM_TOUCH_FINGERS) { if (key_status == KEY_PRESSED) { if (touch_info[i].key != key) { if (touch_info[i].key != KSYM_UNDEFINED) { HandleKey(touch_info[i].key, KEY_RELEASED); Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]", getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i); } if (key != KSYM_UNDEFINED) { HandleKey(key, KEY_PRESSED); Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]", getKeyNameFromKey(key), "KEY_PRESSED", i); } } touch_info[i].touched = TRUE; touch_info[i].finger_id = event->fingerId; touch_info[i].counter = Counter(); touch_info[i].key = key; } else { if (touch_info[i].key != KSYM_UNDEFINED) { HandleKey(touch_info[i].key, KEY_RELEASED); Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]", getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i); } touch_info[i].touched = FALSE; touch_info[i].finger_id = 0; touch_info[i].counter = 0; touch_info[i].key = 0; } } } void HandleFingerEvent_WipeGestures(FingerEvent *event) { static Key motion_key_x = KSYM_UNDEFINED; static Key motion_key_y = KSYM_UNDEFINED; static Key button_key = KSYM_UNDEFINED; static float motion_x1, motion_y1; static float button_x1, button_y1; static SDL_FingerID motion_id = -1; static SDL_FingerID button_id = -1; int move_trigger_distance_percent = setup.touch.move_distance; int drop_trigger_distance_percent = setup.touch.drop_distance; float move_trigger_distance = (float)move_trigger_distance_percent / 100; float drop_trigger_distance = (float)drop_trigger_distance_percent / 100; float event_x = event->x; float event_y = event->y; if (event->type == EVENT_FINGERPRESS) { if (event_x > 1.0 / 3.0) { // motion area motion_id = event->fingerId; motion_x1 = event_x; motion_y1 = event_y; motion_key_x = KSYM_UNDEFINED; motion_key_y = KSYM_UNDEFINED; Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------"); } else { // button area button_id = event->fingerId; button_x1 = event_x; button_y1 = event_y; button_key = setup.input[0].key.snap; HandleKey(button_key, KEY_PRESSED); Error(ERR_DEBUG, "---------- SNAP STARTED ----------"); } } else if (event->type == EVENT_FINGERRELEASE) { if (event->fingerId == motion_id) { motion_id = -1; if (motion_key_x != KSYM_UNDEFINED) HandleKey(motion_key_x, KEY_RELEASED); if (motion_key_y != KSYM_UNDEFINED) HandleKey(motion_key_y, KEY_RELEASED); motion_key_x = KSYM_UNDEFINED; motion_key_y = KSYM_UNDEFINED; Error(ERR_DEBUG, "---------- MOVE STOPPED ----------"); } else if (event->fingerId == button_id) { button_id = -1; if (button_key != KSYM_UNDEFINED) HandleKey(button_key, KEY_RELEASED); button_key = KSYM_UNDEFINED; Error(ERR_DEBUG, "---------- SNAP STOPPED ----------"); } } else if (event->type == EVENT_FINGERMOTION) { if (event->fingerId == motion_id) { float distance_x = ABS(event_x - motion_x1); float distance_y = ABS(event_y - motion_y1); Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left : event_x > motion_x1 ? setup.input[0].key.right : KSYM_UNDEFINED); Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up : event_y > motion_y1 ? setup.input[0].key.down : KSYM_UNDEFINED); if (distance_x < move_trigger_distance / 2 || distance_x < distance_y) new_motion_key_x = KSYM_UNDEFINED; if (distance_y < move_trigger_distance / 2 || distance_y < distance_x) new_motion_key_y = KSYM_UNDEFINED; if (distance_x > move_trigger_distance || distance_y > move_trigger_distance) { if (new_motion_key_x != motion_key_x) { if (motion_key_x != KSYM_UNDEFINED) HandleKey(motion_key_x, KEY_RELEASED); if (new_motion_key_x != KSYM_UNDEFINED) HandleKey(new_motion_key_x, KEY_PRESSED); } if (new_motion_key_y != motion_key_y) { if (motion_key_y != KSYM_UNDEFINED) HandleKey(motion_key_y, KEY_RELEASED); if (new_motion_key_y != KSYM_UNDEFINED) HandleKey(new_motion_key_y, KEY_PRESSED); } motion_x1 = event_x; motion_y1 = event_y; motion_key_x = new_motion_key_x; motion_key_y = new_motion_key_y; Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------"); } } else if (event->fingerId == button_id) { float distance_x = ABS(event_x - button_x1); float distance_y = ABS(event_y - button_y1); if (distance_x < drop_trigger_distance / 2 && distance_y > drop_trigger_distance) { if (button_key == setup.input[0].key.snap) HandleKey(button_key, KEY_RELEASED); button_x1 = event_x; button_y1 = event_y; button_key = setup.input[0].key.drop; HandleKey(button_key, KEY_PRESSED); Error(ERR_DEBUG, "---------- DROP STARTED ----------"); } } } } void HandleFingerEvent(FingerEvent *event) { #if DEBUG_EVENTS_FINGER Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f", event->type == EVENT_FINGERPRESS ? "pressed" : event->type == EVENT_FINGERRELEASE ? "released" : "moved", event->touchId, event->fingerId, event->x, event->y, event->dx, event->dy, event->pressure); #endif if (game_status != GAME_MODE_PLAYING) return; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { if (strEqual(setup.touch.control_type, TOUCH_CONTROL_OFF)) local_player->mouse_action.button_hint = (event->type == EVENT_FINGERRELEASE ? MB_NOT_PRESSED : event->x < 0.5 ? MB_LEFTBUTTON : event->x > 0.5 ? MB_RIGHTBUTTON : MB_NOT_PRESSED); return; } if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS)) HandleFingerEvent_VirtualButtons(event); else if (strEqual(setup.touch.control_type, TOUCH_CONTROL_WIPE_GESTURES)) HandleFingerEvent_WipeGestures(event); } #endif static void HandleButtonOrFinger_WipeGestures_MM(int mx, int my, int button) { static int old_mx = 0, old_my = 0; static int last_button = MB_LEFTBUTTON; static boolean touched = FALSE; static boolean tapped = FALSE; // screen tile was tapped (but finger not touching the screen anymore) // (this point will also be reached without receiving a touch event) if (tapped && !touched) { SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); tapped = FALSE; } // stop here if this function was not triggered by a touch event if (button == -1) return; if (button == MB_PRESSED && IN_GFX_FIELD_PLAY(mx, my)) { // finger started touching the screen touched = TRUE; tapped = TRUE; if (!motion_status) { old_mx = mx; old_my = my; ClearPlayerMouseAction(); Error(ERR_DEBUG, "---------- TOUCH ACTION STARTED ----------"); } } else if (button == MB_RELEASED && touched) { // finger stopped touching the screen touched = FALSE; if (tapped) SetPlayerMouseAction(old_mx, old_my, last_button); else SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); Error(ERR_DEBUG, "---------- TOUCH ACTION STOPPED ----------"); } if (touched) { // finger moved while touching the screen int old_x = getLevelFromScreenX(old_mx); int old_y = getLevelFromScreenY(old_my); int new_x = getLevelFromScreenX(mx); int new_y = getLevelFromScreenY(my); if (new_x != old_x || new_y != old_y) tapped = FALSE; if (new_x != old_x) { // finger moved left or right from (horizontal) starting position int button_nr = (new_x < old_x ? MB_LEFTBUTTON : MB_RIGHTBUTTON); SetPlayerMouseAction(old_mx, old_my, button_nr); last_button = button_nr; Error(ERR_DEBUG, "---------- TOUCH ACTION: ROTATING ----------"); } else { // finger stays at or returned to (horizontal) starting position SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); Error(ERR_DEBUG, "---------- TOUCH ACTION PAUSED ----------"); } } } static void HandleButtonOrFinger_FollowFinger_MM(int mx, int my, int button) { static int old_mx = 0, old_my = 0; static int last_button = MB_LEFTBUTTON; static boolean touched = FALSE; static boolean tapped = FALSE; // screen tile was tapped (but finger not touching the screen anymore) // (this point will also be reached without receiving a touch event) if (tapped && !touched) { SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); tapped = FALSE; } // stop here if this function was not triggered by a touch event if (button == -1) return; if (button == MB_PRESSED && IN_GFX_FIELD_PLAY(mx, my)) { // finger started touching the screen touched = TRUE; tapped = TRUE; if (!motion_status) { old_mx = mx; old_my = my; ClearPlayerMouseAction(); Error(ERR_DEBUG, "---------- TOUCH ACTION STARTED ----------"); } } else if (button == MB_RELEASED && touched) { // finger stopped touching the screen touched = FALSE; if (tapped) SetPlayerMouseAction(old_mx, old_my, last_button); else SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); Error(ERR_DEBUG, "---------- TOUCH ACTION STOPPED ----------"); } if (touched) { // finger moved while touching the screen int old_x = getLevelFromScreenX(old_mx); int old_y = getLevelFromScreenY(old_my); int new_x = getLevelFromScreenX(mx); int new_y = getLevelFromScreenY(my); if (new_x != old_x || new_y != old_y) { // finger moved away from starting position int button_nr = getButtonFromTouchPosition(old_x, old_y, mx, my); // quickly alternate between clicking and releasing for maximum speed if (FrameCounter % 2 == 0) button_nr = MB_RELEASED; SetPlayerMouseAction(old_mx, old_my, button_nr); if (button_nr) last_button = button_nr; tapped = FALSE; Error(ERR_DEBUG, "---------- TOUCH ACTION: ROTATING ----------"); } else { // finger stays at or returned to starting position SetPlayerMouseAction(old_mx, old_my, MB_RELEASED); Error(ERR_DEBUG, "---------- TOUCH ACTION PAUSED ----------"); } } } static void HandleButtonOrFinger_FollowFinger(int mx, int my, int button) { static int old_mx = 0, old_my = 0; static Key motion_key_x = KSYM_UNDEFINED; static Key motion_key_y = KSYM_UNDEFINED; static boolean touched = FALSE; static boolean started_on_player = FALSE; static boolean player_is_dropping = FALSE; static int player_drop_count = 0; static int last_player_x = -1; static int last_player_y = -1; if (button == MB_PRESSED && IN_GFX_FIELD_PLAY(mx, my)) { touched = TRUE; old_mx = mx; old_my = my; if (!motion_status) { started_on_player = FALSE; player_is_dropping = FALSE; player_drop_count = 0; last_player_x = -1; last_player_y = -1; motion_key_x = KSYM_UNDEFINED; motion_key_y = KSYM_UNDEFINED; Error(ERR_DEBUG, "---------- TOUCH ACTION STARTED ----------"); } } else if (button == MB_RELEASED && touched) { touched = FALSE; old_mx = 0; old_my = 0; if (motion_key_x != KSYM_UNDEFINED) HandleKey(motion_key_x, KEY_RELEASED); if (motion_key_y != KSYM_UNDEFINED) HandleKey(motion_key_y, KEY_RELEASED); if (started_on_player) { if (player_is_dropping) { Error(ERR_DEBUG, "---------- DROP STOPPED ----------"); HandleKey(setup.input[0].key.drop, KEY_RELEASED); } else { Error(ERR_DEBUG, "---------- SNAP STOPPED ----------"); HandleKey(setup.input[0].key.snap, KEY_RELEASED); } } motion_key_x = KSYM_UNDEFINED; motion_key_y = KSYM_UNDEFINED; Error(ERR_DEBUG, "---------- TOUCH ACTION STOPPED ----------"); } if (touched) { int src_x = local_player->jx; int src_y = local_player->jy; int dst_x = getLevelFromScreenX(old_mx); int dst_y = getLevelFromScreenY(old_my); int dx = dst_x - src_x; int dy = dst_y - src_y; Key new_motion_key_x = (dx < 0 ? setup.input[0].key.left : dx > 0 ? setup.input[0].key.right : KSYM_UNDEFINED); Key new_motion_key_y = (dy < 0 ? setup.input[0].key.up : dy > 0 ? setup.input[0].key.down : KSYM_UNDEFINED); if (dx != 0 && dy != 0 && ABS(dx) != ABS(dy) && (last_player_x != local_player->jx || last_player_y != local_player->jy)) { // in case of asymmetric diagonal movement, use "preferred" direction int last_move_dir = (ABS(dx) > ABS(dy) ? MV_VERTICAL : MV_HORIZONTAL); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) level.native_em_level->ply[0]->last_move_dir = last_move_dir; else local_player->last_move_dir = last_move_dir; // (required to prevent accidentally forcing direction for next movement) last_player_x = local_player->jx; last_player_y = local_player->jy; } if (button == MB_PRESSED && !motion_status && dx == 0 && dy == 0) { started_on_player = TRUE; player_drop_count = getPlayerInventorySize(0); player_is_dropping = (player_drop_count > 0); if (player_is_dropping) { Error(ERR_DEBUG, "---------- DROP STARTED ----------"); HandleKey(setup.input[0].key.drop, KEY_PRESSED); } else { Error(ERR_DEBUG, "---------- SNAP STARTED ----------"); HandleKey(setup.input[0].key.snap, KEY_PRESSED); } } else if (dx != 0 || dy != 0) { if (player_is_dropping && player_drop_count == getPlayerInventorySize(0)) { Error(ERR_DEBUG, "---------- DROP -> SNAP ----------"); HandleKey(setup.input[0].key.drop, KEY_RELEASED); HandleKey(setup.input[0].key.snap, KEY_PRESSED); player_is_dropping = FALSE; } } if (new_motion_key_x != motion_key_x) { Error(ERR_DEBUG, "---------- %s %s ----------", started_on_player && !player_is_dropping ? "SNAPPING" : "MOVING", dx < 0 ? "LEFT" : dx > 0 ? "RIGHT" : "PAUSED"); if (motion_key_x != KSYM_UNDEFINED) HandleKey(motion_key_x, KEY_RELEASED); if (new_motion_key_x != KSYM_UNDEFINED) HandleKey(new_motion_key_x, KEY_PRESSED); } if (new_motion_key_y != motion_key_y) { Error(ERR_DEBUG, "---------- %s %s ----------", started_on_player && !player_is_dropping ? "SNAPPING" : "MOVING", dy < 0 ? "UP" : dy > 0 ? "DOWN" : "PAUSED"); if (motion_key_y != KSYM_UNDEFINED) HandleKey(motion_key_y, KEY_RELEASED); if (new_motion_key_y != KSYM_UNDEFINED) HandleKey(new_motion_key_y, KEY_PRESSED); } motion_key_x = new_motion_key_x; motion_key_y = new_motion_key_y; } } static void HandleButtonOrFinger(int mx, int my, int button) { if (game_status != GAME_MODE_PLAYING) return; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { if (strEqual(setup.touch.control_type, TOUCH_CONTROL_WIPE_GESTURES)) HandleButtonOrFinger_WipeGestures_MM(mx, my, button); else if (strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER)) HandleButtonOrFinger_FollowFinger_MM(mx, my, button); } else { if (strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER)) HandleButtonOrFinger_FollowFinger(mx, my, button); } } #if defined(TARGET_SDL2) static boolean checkTextInputKeyModState() { // when playing, only handle raw key events and ignore text input if (game_status == GAME_MODE_PLAYING) return FALSE; return ((GetKeyModState() & KMOD_TextInput) != KMOD_None); } void HandleTextEvent(TextEvent *event) { char *text = event->text; Key key = getKeyFromKeyName(text); #if DEBUG_EVENTS_TEXT Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]", text, strlen(text), text[0], (int)(text[0]), key, getKeyNameFromKey(key), GetKeyModState()); #endif #if !defined(HAS_SCREEN_KEYBOARD) // non-mobile devices: only handle key input with modifier keys pressed here // (every other key input is handled directly as physical key input event) if (!checkTextInputKeyModState()) return; #endif // process text input as "classic" (with uppercase etc.) key input event HandleKey(key, KEY_PRESSED); HandleKey(key, KEY_RELEASED); } void HandlePauseResumeEvent(PauseResumeEvent *event) { if (event->type == SDL_APP_WILLENTERBACKGROUND) { Mix_PauseMusic(); } else if (event->type == SDL_APP_DIDENTERFOREGROUND) { Mix_ResumeMusic(); } } #endif void HandleKeyEvent(KeyEvent *event) { int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED); boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE); Key key = GetEventKey(event, with_modifiers); Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key); #if DEBUG_EVENTS_KEY Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)", event->type == EVENT_KEYPRESS ? "pressed" : "released", event->keysym.scancode, event->keysym.sym, keymod, GetKeyModState(), key, getKeyNameFromKey(key)); #endif #if defined(PLATFORM_ANDROID) if (key == KSYM_Back) { // always map the "back" button to the "escape" key on Android devices key = KSYM_Escape; } else { // for any key event other than "back" button, disable overlay buttons SetOverlayEnabled(FALSE); } #endif HandleKeyModState(keymod, key_status); #if defined(TARGET_SDL2) // only handle raw key input without text modifier keys pressed if (!checkTextInputKeyModState()) HandleKey(key, key_status); #else HandleKey(key, key_status); #endif } void HandleFocusEvent(FocusChangeEvent *event) { static int old_joystick_status = -1; if (event->type == EVENT_FOCUSOUT) { KeyboardAutoRepeatOn(); old_joystick_status = joystick.status; joystick.status = JOYSTICK_NOT_AVAILABLE; ClearPlayerAction(); } else if (event->type == EVENT_FOCUSIN) { /* When there are two Rocks'n'Diamonds windows which overlap and the player moves the pointer from one game window to the other, a 'FocusOut' event is generated for the window the pointer is leaving and a 'FocusIn' event is generated for the window the pointer is entering. In some cases, it can happen that the 'FocusIn' event is handled by the one game process before the 'FocusOut' event by the other game process. In this case the X11 environment would end up with activated keyboard auto repeat, because unfortunately this is a global setting and not (which would be far better) set for each X11 window individually. The effect would be keyboard auto repeat while playing the game (game_status == GAME_MODE_PLAYING), which is not desired. To avoid this special case, we just wait 1/10 second before processing the 'FocusIn' event. */ if (game_status == GAME_MODE_PLAYING) { Delay(100); KeyboardAutoRepeatOffUnlessAutoplay(); } if (old_joystick_status != -1) joystick.status = old_joystick_status; } } void HandleClientMessageEvent(ClientMessageEvent *event) { if (CheckCloseWindowEvent(event)) CloseAllAndExit(0); } void HandleWindowManagerEvent(Event *event) { #if defined(TARGET_SDL) SDLHandleWindowManagerEvent(event); #endif } void HandleButton(int mx, int my, int button, int button_nr) { static int old_mx = 0, old_my = 0; boolean button_hold = FALSE; boolean handle_gadgets = TRUE; if (button_nr < 0) { mx = old_mx; my = old_my; button_nr = -button_nr; button_hold = TRUE; } else { old_mx = mx; old_my = my; } #if defined(PLATFORM_ANDROID) // when playing, only handle gadgets when using "follow finger" controls // or when using touch controls in combination with the MM game engine handle_gadgets = (game_status != GAME_MODE_PLAYING || level.game_engine_type == GAME_ENGINE_TYPE_MM || strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER)); #endif if (handle_gadgets && HandleGadgets(mx, my, button)) { /* do not handle this button event anymore */ mx = my = -32; /* force mouse event to be outside screen tiles */ } if (HandleGlobalAnimClicks(mx, my, button)) { /* do not handle this button event anymore */ return; /* force mouse event not to be handled at all */ } if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing) return; /* do not use scroll wheel button events for anything other than gadgets */ if (IS_WHEEL_BUTTON(button_nr)) return; switch (game_status) { case GAME_MODE_TITLE: HandleTitleScreen(mx, my, 0, 0, button); break; case GAME_MODE_MAIN: HandleMainMenu(mx, my, 0, 0, button); break; case GAME_MODE_PSEUDO_TYPENAME: HandleTypeName(0, KSYM_Return); break; case GAME_MODE_LEVELS: HandleChooseLevelSet(mx, my, 0, 0, button); break; case GAME_MODE_LEVELNR: HandleChooseLevelNr(mx, my, 0, 0, button); break; case GAME_MODE_SCORES: HandleHallOfFame(0, 0, 0, 0, button); break; case GAME_MODE_EDITOR: HandleLevelEditorIdle(); break; case GAME_MODE_INFO: HandleInfoScreen(mx, my, 0, 0, button); break; case GAME_MODE_SETUP: HandleSetupScreen(mx, my, 0, 0, button); break; case GAME_MODE_PLAYING: if (!strEqual(setup.touch.control_type, TOUCH_CONTROL_OFF)) HandleButtonOrFinger(mx, my, button); else SetPlayerMouseAction(mx, my, button); #ifdef DEBUG if (button == MB_PRESSED && !motion_status && !button_hold && IN_GFX_FIELD_PLAY(mx, my) && GetKeyModState() & KMOD_Control) DumpTileFromScreen(mx, my); #endif break; default: break; } } static boolean is_string_suffix(char *string, char *suffix) { int string_len = strlen(string); int suffix_len = strlen(suffix); if (suffix_len > string_len) return FALSE; return (strEqual(&string[string_len - suffix_len], suffix)); } #define MAX_CHEAT_INPUT_LEN 32 static void HandleKeysSpecial(Key key) { static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = ""; char letter = getCharFromKey(key); int cheat_input_len = strlen(cheat_input); int i; if (letter == 0) return; if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN) { for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++) cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i]; cheat_input_len = MAX_CHEAT_INPUT_LEN; } cheat_input[cheat_input_len++] = letter; cheat_input[cheat_input_len] = '\0'; #if DEBUG_EVENTS_KEY Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len); #endif if (game_status == GAME_MODE_MAIN) { if (is_string_suffix(cheat_input, ":insert-solution-tape") || is_string_suffix(cheat_input, ":ist")) { InsertSolutionTape(); } else if (is_string_suffix(cheat_input, ":reload-graphics") || is_string_suffix(cheat_input, ":rg")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":reload-sounds") || is_string_suffix(cheat_input, ":rs")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":reload-music") || is_string_suffix(cheat_input, ":rm")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":reload-artwork") || is_string_suffix(cheat_input, ":ra")) { ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS | 1 << ARTWORK_TYPE_SOUNDS | 1 << ARTWORK_TYPE_MUSIC); DrawMainMenu(); } else if (is_string_suffix(cheat_input, ":dump-level") || is_string_suffix(cheat_input, ":dl")) { DumpLevel(&level); } else if (is_string_suffix(cheat_input, ":dump-tape") || is_string_suffix(cheat_input, ":dt")) { DumpTape(&tape); } else if (is_string_suffix(cheat_input, ":fix-tape") || is_string_suffix(cheat_input, ":ft")) { /* fix single-player tapes that contain player input for more than one player (due to a bug in 3.3.1.2 and earlier versions), which results in playing levels with more than one player in multi-player mode, even though the tape was originally recorded in single-player mode */ /* remove player input actions for all players but the first one */ for (i = 1; i < MAX_PLAYERS; i++) tape.player_participates[i] = FALSE; tape.changed = TRUE; } else if (is_string_suffix(cheat_input, ":save-native-level") || is_string_suffix(cheat_input, ":snl")) { SaveNativeLevel(&level); } else if (is_string_suffix(cheat_input, ":frames-per-second") || is_string_suffix(cheat_input, ":fps")) { global.show_frames_per_second = !global.show_frames_per_second; } } else if (game_status == GAME_MODE_PLAYING) { #ifdef DEBUG if (is_string_suffix(cheat_input, ".q")) DEBUG_SetMaximumDynamite(); #endif } else if (game_status == GAME_MODE_EDITOR) { if (is_string_suffix(cheat_input, ":dump-brush") || is_string_suffix(cheat_input, ":DB")) { DumpBrush(); } else if (is_string_suffix(cheat_input, ":DDB")) { DumpBrush_Small(); } } } void HandleKeysDebug(Key key) { #ifdef DEBUG int i; if (game_status == GAME_MODE_PLAYING || !setup.debug.frame_delay_game_only) { boolean mod_key_pressed = ((GetKeyModState() & KMOD_Valid) != KMOD_None); for (i = 0; i < NUM_DEBUG_FRAME_DELAY_KEYS; i++) { if (key == setup.debug.frame_delay_key[i] && (mod_key_pressed == setup.debug.frame_delay_use_mod_key)) { GameFrameDelay = (GameFrameDelay != setup.debug.frame_delay[i] ? setup.debug.frame_delay[i] : setup.game_frame_delay); if (!setup.debug.frame_delay_game_only) MenuFrameDelay = GameFrameDelay; SetVideoFrameDelay(GameFrameDelay); if (GameFrameDelay > ONE_SECOND_DELAY) Error(ERR_DEBUG, "frame delay == %d ms", GameFrameDelay); else if (GameFrameDelay != 0) Error(ERR_DEBUG, "frame delay == %d ms (max. %d fps / %d %%)", GameFrameDelay, ONE_SECOND_DELAY / GameFrameDelay, GAME_FRAME_DELAY * 100 / GameFrameDelay); else Error(ERR_DEBUG, "frame delay == 0 ms (maximum speed)"); break; } } } if (game_status == GAME_MODE_PLAYING) { if (key == KSYM_d) { options.debug = !options.debug; Error(ERR_DEBUG, "debug mode %s", (options.debug ? "enabled" : "disabled")); } else if (key == KSYM_v) { Error(ERR_DEBUG, "currently using game engine version %d", game.engine_version); } } #endif } void HandleKey(Key key, int key_status) { boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive(); static boolean ignore_repeated_key = FALSE; static struct SetupKeyboardInfo ski; static struct SetupShortcutInfo ssi; static struct { Key *key_custom; Key *key_snap; Key key_default; byte action; } key_info[] = { { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT }, { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT }, { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP }, { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN }, { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP }, { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP } }; int joy = 0; int i; #if defined(TARGET_SDL2) /* map special keys (media keys / remote control buttons) to default keys */ if (key == KSYM_PlayPause) key = KSYM_space; else if (key == KSYM_Select) key = KSYM_Return; #endif HandleSpecialGameControllerKeys(key, key_status); if (game_status == GAME_MODE_PLAYING) { /* only needed for single-step tape recording mode */ static boolean has_snapped[MAX_PLAYERS] = { FALSE, FALSE, FALSE, FALSE }; int pnr; for (pnr = 0; pnr < MAX_PLAYERS; pnr++) { byte key_action = 0; if (setup.input[pnr].use_joystick) continue; ski = setup.input[pnr].key; for (i = 0; i < NUM_PLAYER_ACTIONS; i++) if (key == *key_info[i].key_custom) key_action |= key_info[i].action; /* use combined snap+direction keys for the first player only */ if (pnr == 0) { ssi = setup.shortcut; for (i = 0; i < NUM_DIRECTIONS; i++) if (key == *key_info[i].key_snap) key_action |= key_info[i].action | JOY_BUTTON_SNAP; } if (key_status == KEY_PRESSED) stored_player[pnr].action |= key_action; else stored_player[pnr].action &= ~key_action; if (tape.single_step && tape.recording && tape.pausing && !tape.use_mouse) { if (key_status == KEY_PRESSED && key_action & KEY_MOTION) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); /* if snap key already pressed, keep pause mode when releasing */ if (stored_player[pnr].action & KEY_BUTTON_SNAP) has_snapped[pnr] = TRUE; } else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); if (level.game_engine_type == GAME_ENGINE_TYPE_SP && getRedDiskReleaseFlag_SP() == 0) { /* add a single inactive frame before dropping starts */ stored_player[pnr].action &= ~KEY_BUTTON_DROP; stored_player[pnr].force_dropping = TRUE; } } else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON_SNAP) { /* if snap key was pressed without direction, leave pause mode */ if (!has_snapped[pnr]) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); has_snapped[pnr] = FALSE; } } else if (tape.recording && tape.pausing && !tape.use_mouse) { /* prevent key release events from un-pausing a paused game */ if (key_status == KEY_PRESSED && key_action & KEY_ACTION) TapeTogglePause(TAPE_TOGGLE_MANUAL); } // for MM style levels, handle in-game keyboard input in HandleJoystick() if (level.game_engine_type == GAME_ENGINE_TYPE_MM) joy |= key_action; } } else { for (i = 0; i < NUM_PLAYER_ACTIONS; i++) if (key == key_info[i].key_default) joy |= key_info[i].action; } if (joy) { if (key_status == KEY_PRESSED) key_joystick_mapping |= joy; else key_joystick_mapping &= ~joy; HandleJoystick(); } if (game_status != GAME_MODE_PLAYING) key_joystick_mapping = 0; if (key_status == KEY_RELEASED) { // reset flag to ignore repeated "key pressed" events after key release ignore_repeated_key = FALSE; return; } if ((key == KSYM_F11 || ((key == KSYM_Return || key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) && video.fullscreen_available && !ignore_repeated_key) { setup.fullscreen = !setup.fullscreen; ToggleFullscreenOrChangeWindowScalingIfNeeded(); if (game_status == GAME_MODE_SETUP) RedrawSetupScreenAfterFullscreenToggle(); // set flag to ignore repeated "key pressed" events ignore_repeated_key = TRUE; return; } if ((key == KSYM_0 || key == KSYM_KP_0 || key == KSYM_minus || key == KSYM_KP_Subtract || key == KSYM_plus || key == KSYM_KP_Add || key == KSYM_equal) && // ("Shift-=" is "+" on US keyboards) (GetKeyModState() & (KMOD_Control | KMOD_Meta)) && video.window_scaling_available && !video.fullscreen_enabled) { if (key == KSYM_0 || key == KSYM_KP_0) setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT; else if (key == KSYM_minus || key == KSYM_KP_Subtract) setup.window_scaling_percent -= STEP_WINDOW_SCALING_PERCENT; else setup.window_scaling_percent += STEP_WINDOW_SCALING_PERCENT; if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT) setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT; else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT) setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT; ToggleFullscreenOrChangeWindowScalingIfNeeded(); if (game_status == GAME_MODE_SETUP) RedrawSetupScreenAfterFullscreenToggle(); return; } if (HandleGlobalAnimClicks(-1, -1, (key == KSYM_space || key == KSYM_Return || key == KSYM_Escape))) { /* do not handle this key event anymore */ if (key != KSYM_Escape) /* always allow ESC key to be handled */ return; } if (game_status == GAME_MODE_PLAYING && AllPlayersGone && (key == KSYM_Return || key == setup.shortcut.toggle_pause)) { GameEnd(); return; } if (game_status == GAME_MODE_MAIN && (key == setup.shortcut.toggle_pause || key == KSYM_space)) { StartGameActions(options.network, setup.autorecord, level.random_seed); return; } if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING) { if (key == setup.shortcut.save_game) TapeQuickSave(); else if (key == setup.shortcut.load_game) TapeQuickLoad(); else if (key == setup.shortcut.toggle_pause) TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE); HandleTapeButtonKeys(key); HandleSoundButtonKeys(key); } if (game_status == GAME_MODE_PLAYING && !network_playing) { int centered_player_nr_next = -999; if (key == setup.shortcut.focus_player_all) centered_player_nr_next = -1; else for (i = 0; i < MAX_PLAYERS; i++) if (key == setup.shortcut.focus_player[i]) centered_player_nr_next = i; if (centered_player_nr_next != -999) { game.centered_player_nr_next = centered_player_nr_next; game.set_centered_player = TRUE; if (tape.recording) { tape.centered_player_nr_next = game.centered_player_nr_next; tape.set_centered_player = TRUE; } } } HandleKeysSpecial(key); if (HandleGadgetsKeyInput(key)) { if (key != KSYM_Escape) /* always allow ESC key to be handled */ key = KSYM_UNDEFINED; } switch (game_status) { case GAME_MODE_PSEUDO_TYPENAME: HandleTypeName(0, key); break; case GAME_MODE_TITLE: case GAME_MODE_MAIN: case GAME_MODE_LEVELS: case GAME_MODE_LEVELNR: case GAME_MODE_SETUP: case GAME_MODE_INFO: case GAME_MODE_SCORES: switch (key) { case KSYM_space: case KSYM_Return: if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_MAIN) HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE); break; case KSYM_Escape: if (game_status != GAME_MODE_MAIN) FadeSkipNextFadeIn(); if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE); break; case KSYM_Page_Up: if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK); break; case KSYM_Page_Down: if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK); break; default: break; } break; case GAME_MODE_EDITOR: if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape) HandleLevelEditorKeyInput(key); break; case GAME_MODE_PLAYING: { switch (key) { case KSYM_Escape: RequestQuitGame(setup.ask_on_escape); break; default: break; } break; } default: if (key == KSYM_Escape) { SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); return; } } HandleKeysDebug(key); } void HandleNoEvent() { HandleMouseCursor(); switch (game_status) { case GAME_MODE_PLAYING: HandleButtonOrFinger(-1, -1, -1); break; } } void HandleEventActions() { // if (button_status && game_status != GAME_MODE_PLAYING) if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing || level.game_engine_type == GAME_ENGINE_TYPE_MM)) { HandleButton(0, 0, button_status, -button_status); } else { HandleJoystick(); } #if defined(NETWORK_AVALIABLE) if (options.network) HandleNetworking(); #endif switch (game_status) { case GAME_MODE_MAIN: DrawPreviewLevelAnimation(); break; case GAME_MODE_EDITOR: HandleLevelEditorIdle(); break; default: break; } } static void HandleTileCursor(int dx, int dy, int button) { if (!dx || !button) ClearPlayerMouseAction(); if (!dx && !dy) return; if (button) { SetPlayerMouseAction(tile_cursor.x, tile_cursor.y, (dx < 0 ? MB_LEFTBUTTON : dx > 0 ? MB_RIGHTBUTTON : MB_RELEASED)); } else if (!tile_cursor.moving) { int old_xpos = tile_cursor.xpos; int old_ypos = tile_cursor.ypos; int new_xpos = old_xpos; int new_ypos = old_ypos; if (IN_LEV_FIELD(old_xpos + dx, old_ypos)) new_xpos = old_xpos + dx; if (IN_LEV_FIELD(old_xpos, old_ypos + dy)) new_ypos = old_ypos + dy; SetTileCursorTargetXY(new_xpos, new_ypos); } } static int HandleJoystickForAllPlayers() { int i; int result = 0; boolean no_joysticks_configured = TRUE; boolean use_as_joystick_nr = (game_status != GAME_MODE_PLAYING); static byte joy_action_last[MAX_PLAYERS]; for (i = 0; i < MAX_PLAYERS; i++) if (setup.input[i].use_joystick) no_joysticks_configured = FALSE; /* if no joysticks configured, map connected joysticks to players */ if (no_joysticks_configured) use_as_joystick_nr = TRUE; for (i = 0; i < MAX_PLAYERS; i++) { byte joy_action = 0; joy_action = JoystickExt(i, use_as_joystick_nr); result |= joy_action; if ((setup.input[i].use_joystick || no_joysticks_configured) && joy_action != joy_action_last[i]) stored_player[i].action = joy_action; joy_action_last[i] = joy_action; } return result; } void HandleJoystick() { static unsigned int joytest_delay = 0; static unsigned int joytest_delay_value = GADGET_FRAME_DELAY; static int joytest_last = 0; int delay_value_first = GADGET_FRAME_DELAY_FIRST; int delay_value = GADGET_FRAME_DELAY; int joystick = HandleJoystickForAllPlayers(); int keyboard = key_joystick_mapping; int joy = (joystick | keyboard); int joytest = joystick; int left = joy & JOY_LEFT; int right = joy & JOY_RIGHT; int up = joy & JOY_UP; int down = joy & JOY_DOWN; int button = joy & JOY_BUTTON; int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED); int dx = (left ? -1 : right ? 1 : 0); int dy = (up ? -1 : down ? 1 : 0); boolean use_delay_value_first = (joytest != joytest_last); if (HandleGlobalAnimClicks(-1, -1, newbutton)) { /* do not handle this button event anymore */ return; } if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { if (game_status == GAME_MODE_PLAYING) { // when playing MM style levels, also use delay for keyboard events joytest |= keyboard; // only use first delay value for new events, but not for changed events use_delay_value_first = (!joytest != !joytest_last); // only use delay after the initial keyboard event delay_value = 0; } // for any joystick or keyboard event, enable playfield tile cursor if (dx || dy || button) SetTileCursorEnabled(TRUE); } if (joytest && !button && !DelayReached(&joytest_delay, joytest_delay_value)) { /* delay joystick/keyboard actions if axes/keys continually pressed */ newbutton = dx = dy = 0; } else { /* first start with longer delay, then continue with shorter delay */ joytest_delay_value = (use_delay_value_first ? delay_value_first : delay_value); } joytest_last = joytest; switch (game_status) { case GAME_MODE_TITLE: case GAME_MODE_MAIN: case GAME_MODE_LEVELS: case GAME_MODE_LEVELNR: case GAME_MODE_SETUP: case GAME_MODE_INFO: case GAME_MODE_SCORES: { if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_MAIN) HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELS) HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_LEVELNR) HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_SETUP) HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_INFO) HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); break; } case GAME_MODE_PLAYING: #if 0 // !!! causes immediate GameEnd() when solving MM level with keyboard !!! if (tape.playing || keyboard) newbutton = ((joy & JOY_BUTTON) != 0); #endif if (newbutton && AllPlayersGone) { GameEnd(); return; } if (tape.single_step && tape.recording && tape.pausing && !tape.use_mouse) { if (joystick & JOY_ACTION) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); } else if (tape.recording && tape.pausing && !tape.use_mouse) { if (joystick & JOY_ACTION) TapeTogglePause(TAPE_TOGGLE_MANUAL); } if (level.game_engine_type == GAME_ENGINE_TYPE_MM) HandleTileCursor(dx, dy, button); break; default: break; } } void HandleSpecialGameControllerButtons(Event *event) { #if defined(TARGET_SDL2) switch (event->type) { case SDL_CONTROLLERBUTTONDOWN: if (event->cbutton.button == SDL_CONTROLLER_BUTTON_START) HandleKey(KSYM_space, KEY_PRESSED); else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_BACK) HandleKey(KSYM_Escape, KEY_PRESSED); break; case SDL_CONTROLLERBUTTONUP: if (event->cbutton.button == SDL_CONTROLLER_BUTTON_START) HandleKey(KSYM_space, KEY_RELEASED); else if (event->cbutton.button == SDL_CONTROLLER_BUTTON_BACK) HandleKey(KSYM_Escape, KEY_RELEASED); break; } #endif } void HandleSpecialGameControllerKeys(Key key, int key_status) { #if defined(TARGET_SDL2) #if defined(KSYM_Rewind) && defined(KSYM_FastForward) int button = SDL_CONTROLLER_BUTTON_INVALID; /* map keys to joystick buttons (special hack for Amazon Fire TV remote) */ if (key == KSYM_Rewind) button = SDL_CONTROLLER_BUTTON_A; else if (key == KSYM_FastForward || key == KSYM_Menu) button = SDL_CONTROLLER_BUTTON_B; if (button != SDL_CONTROLLER_BUTTON_INVALID) { Event event; event.type = (key_status == KEY_PRESSED ? SDL_CONTROLLERBUTTONDOWN : SDL_CONTROLLERBUTTONUP); event.cbutton.which = 0; /* first joystick (Amazon Fire TV remote) */ event.cbutton.button = button; event.cbutton.state = (key_status == KEY_PRESSED ? SDL_PRESSED : SDL_RELEASED); HandleJoystickEvent(&event); } #endif #endif } mirrormagic-3.0.0/src/conf_gfx.h0000644000175000017500000025232413263214151016072 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_gfx.h // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_GFX_H #define CONF_GFX_H /* values for graphics configuration (normal elements) */ #define IMG_BD_WALL 0 #define IMG_BD_WALL_EDITOR 1 #define IMG_BD_ROCK 2 #define IMG_BD_ROCK_EDITOR 3 #define IMG_BD_ROCK_MOVING_LEFT 4 #define IMG_BD_ROCK_MOVING_RIGHT 5 #define IMG_BD_ROCK_PUSHING_LEFT 6 #define IMG_BD_ROCK_PUSHING_RIGHT 7 #define IMG_BD_DIAMOND 8 #define IMG_BD_DIAMOND_MOVING 9 #define IMG_BD_DIAMOND_FALLING 10 #define IMG_BD_MAGIC_WALL 11 #define IMG_BD_MAGIC_WALL_ACTIVE 12 #define IMG_BD_MAGIC_WALL_FILLING 13 #define IMG_BD_MAGIC_WALL_FULL 14 #define IMG_BD_MAGIC_WALL_EMPTYING 15 #define IMG_BD_MAGIC_WALL_DEAD 16 #define IMG_BD_AMOEBA 17 #define IMG_BD_AMOEBA_EDITOR 18 #define IMG_BD_BUTTERFLY 19 #define IMG_BD_BUTTERFLY_RIGHT 20 #define IMG_BD_BUTTERFLY_RIGHT_EDITOR 21 #define IMG_BD_BUTTERFLY_UP 22 #define IMG_BD_BUTTERFLY_UP_EDITOR 23 #define IMG_BD_BUTTERFLY_LEFT 24 #define IMG_BD_BUTTERFLY_LEFT_EDITOR 25 #define IMG_BD_BUTTERFLY_DOWN 26 #define IMG_BD_BUTTERFLY_DOWN_EDITOR 27 #define IMG_BD_FIREFLY 28 #define IMG_BD_FIREFLY_RIGHT 29 #define IMG_BD_FIREFLY_RIGHT_EDITOR 30 #define IMG_BD_FIREFLY_UP 31 #define IMG_BD_FIREFLY_UP_EDITOR 32 #define IMG_BD_FIREFLY_LEFT 33 #define IMG_BD_FIREFLY_LEFT_EDITOR 34 #define IMG_BD_FIREFLY_DOWN 35 #define IMG_BD_FIREFLY_DOWN_EDITOR 36 #define IMG_SP_DEFAULT_EXPLODING 37 #define IMG_SP_ZONK 38 #define IMG_SP_ZONK_MOVING_LEFT 39 #define IMG_SP_ZONK_MOVING_RIGHT 40 #define IMG_SP_ZONK_PUSHING_LEFT 41 #define IMG_SP_ZONK_PUSHING_RIGHT 42 #define IMG_SP_BASE 43 #define IMG_SP_BASE_DIGGING 44 #define IMG_SP_BASE_SNAPPING 45 #define IMG_SP_MURPHY 46 #define IMG_SP_MURPHY_MOVING_LEFT 47 #define IMG_SP_MURPHY_MOVING_RIGHT 48 #define IMG_SP_MURPHY_DIGGING_LEFT 49 #define IMG_SP_MURPHY_DIGGING_RIGHT 50 #define IMG_SP_MURPHY_COLLECTING_LEFT 51 #define IMG_SP_MURPHY_COLLECTING_RIGHT 52 #define IMG_SP_MURPHY_PUSHING_LEFT 53 #define IMG_SP_MURPHY_PUSHING_RIGHT 54 #define IMG_SP_MURPHY_SNAPPING_LEFT 55 #define IMG_SP_MURPHY_SNAPPING_RIGHT 56 #define IMG_SP_MURPHY_SNAPPING_UP 57 #define IMG_SP_MURPHY_SNAPPING_DOWN 58 #define IMG_SP_MURPHY_BORING 59 #define IMG_SP_MURPHY_BORING_1 60 #define IMG_SP_MURPHY_SLEEPING_LEFT 61 #define IMG_SP_MURPHY_SLEEPING_RIGHT 62 #define IMG_SP_MURPHY_DROPPING 63 #define IMG_SP_MURPHY_SHRINKING 64 #define IMG_SP_MURPHY_CLONE 65 #define IMG_SP_INFOTRON 66 #define IMG_SP_INFOTRON_EDITOR 67 #define IMG_SP_INFOTRON_MOVING_LEFT 68 #define IMG_SP_INFOTRON_MOVING_RIGHT 69 #define IMG_SP_INFOTRON_COLLECTING 70 #define IMG_SP_CHIP_SINGLE 71 #define IMG_SP_CHIP_LEFT 72 #define IMG_SP_CHIP_RIGHT 73 #define IMG_SP_CHIP_TOP 74 #define IMG_SP_CHIP_BOTTOM 75 #define IMG_SP_HARDWARE_GRAY 76 #define IMG_SP_HARDWARE_GREEN 77 #define IMG_SP_HARDWARE_BLUE 78 #define IMG_SP_HARDWARE_RED 79 #define IMG_SP_HARDWARE_YELLOW 80 #define IMG_SP_EXIT_CLOSED 81 #define IMG_SP_EXIT_OPENING 82 #define IMG_SP_EXIT_OPEN 83 #define IMG_SP_EXIT_CLOSING 84 #define IMG_SP_DISK_ORANGE 85 #define IMG_SP_DISK_YELLOW 86 #define IMG_SP_DISK_RED 87 #define IMG_SP_DISK_RED_COLLECTING 88 #define IMG_SP_DISK_RED_ACTIVE 89 #define IMG_SP_PORT_RIGHT 90 #define IMG_SP_PORT_DOWN 91 #define IMG_SP_PORT_LEFT 92 #define IMG_SP_PORT_UP 93 #define IMG_SP_PORT_HORIZONTAL 94 #define IMG_SP_PORT_VERTICAL 95 #define IMG_SP_PORT_ANY 96 #define IMG_SP_GRAVITY_PORT_RIGHT 97 #define IMG_SP_GRAVITY_PORT_RIGHT_EDITOR 98 #define IMG_SP_GRAVITY_PORT_DOWN 99 #define IMG_SP_GRAVITY_PORT_DOWN_EDITOR 100 #define IMG_SP_GRAVITY_PORT_LEFT 101 #define IMG_SP_GRAVITY_PORT_LEFT_EDITOR 102 #define IMG_SP_GRAVITY_PORT_UP 103 #define IMG_SP_GRAVITY_PORT_UP_EDITOR 104 #define IMG_SP_GRAVITY_ON_PORT_RIGHT 105 #define IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR 106 #define IMG_SP_GRAVITY_ON_PORT_DOWN 107 #define IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR 108 #define IMG_SP_GRAVITY_ON_PORT_LEFT 109 #define IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR 110 #define IMG_SP_GRAVITY_ON_PORT_UP 111 #define IMG_SP_GRAVITY_ON_PORT_UP_EDITOR 112 #define IMG_SP_GRAVITY_OFF_PORT_RIGHT 113 #define IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR 114 #define IMG_SP_GRAVITY_OFF_PORT_DOWN 115 #define IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR 116 #define IMG_SP_GRAVITY_OFF_PORT_LEFT 117 #define IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR 118 #define IMG_SP_GRAVITY_OFF_PORT_UP 119 #define IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR 120 #define IMG_SP_SNIKSNAK 121 #define IMG_SP_SNIKSNAK_LEFT 122 #define IMG_SP_SNIKSNAK_RIGHT 123 #define IMG_SP_SNIKSNAK_UP 124 #define IMG_SP_SNIKSNAK_DOWN 125 #define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP 126 #define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN 127 #define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP 128 #define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN 129 #define IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT 130 #define IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT 131 #define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT 132 #define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT 133 #define IMG_SP_ELECTRON 134 #define IMG_SP_ELECTRON_EDITOR 135 #define IMG_SP_ELECTRON_EXPLODING 136 #define IMG_SP_TERMINAL 137 #define IMG_SP_TERMINAL_EDITOR 138 #define IMG_SP_TERMINAL_ACTIVE 139 #define IMG_SP_BUGGY_BASE 140 #define IMG_SP_BUGGY_BASE_EDITOR 141 #define IMG_SP_BUGGY_BASE_ACTIVATING 142 #define IMG_SP_BUGGY_BASE_ACTIVE 143 #define IMG_SP_HARDWARE_BASE_1 144 #define IMG_SP_HARDWARE_BASE_2 145 #define IMG_SP_HARDWARE_BASE_3 146 #define IMG_SP_HARDWARE_BASE_4 147 #define IMG_SP_HARDWARE_BASE_5 148 #define IMG_SP_HARDWARE_BASE_6 149 #define IMG_SOKOBAN_OBJECT 150 #define IMG_SOKOBAN_OBJECT_EDITOR 151 #define IMG_SOKOBAN_FIELD_EMPTY 152 #define IMG_SOKOBAN_FIELD_FULL 153 #define IMG_SOKOBAN_FIELD_PLAYER 154 #define IMG_SOKOBAN_FIELD_PLAYER_EDITOR 155 #define IMG_EMPTY_SPACE 156 #define IMG_SAND 157 #define IMG_SAND_CRUMBLED 158 #define IMG_SAND_DIGGING_LEFT 159 #define IMG_SAND_DIGGING_RIGHT 160 #define IMG_SAND_DIGGING_UP 161 #define IMG_SAND_DIGGING_DOWN 162 #define IMG_SAND_DIGGING_LEFT_CRUMBLED 163 #define IMG_SAND_DIGGING_RIGHT_CRUMBLED 164 #define IMG_SAND_DIGGING_UP_CRUMBLED 165 #define IMG_SAND_DIGGING_DOWN_CRUMBLED 166 #define IMG_WALL 167 #define IMG_WALL_SLIPPERY 168 #define IMG_STEELWALL 169 #define IMG_ROCK 170 #define IMG_ROCK_MOVING_LEFT 171 #define IMG_ROCK_MOVING_RIGHT 172 #define IMG_ROCK_PUSHING_LEFT 173 #define IMG_ROCK_PUSHING_RIGHT 174 #define IMG_EMERALD 175 #define IMG_EMERALD_MOVING 176 #define IMG_EMERALD_FALLING 177 #define IMG_EMERALD_COLLECTING 178 #define IMG_DIAMOND 179 #define IMG_DIAMOND_MOVING 180 #define IMG_DIAMOND_FALLING 181 #define IMG_DIAMOND_COLLECTING 182 #define IMG_BOMB 183 #define IMG_NUT 184 #define IMG_NUT_BREAKING 185 #define IMG_DYNAMITE 186 #define IMG_DYNAMITE_EDITOR 187 #define IMG_DYNAMITE_ACTIVE 188 #define IMG_DYNAMITE_ACTIVE_EDITOR 189 #define IMG_EM_DYNAMITE 190 #define IMG_EM_DYNAMITE_ACTIVE 191 #define IMG_EM_DYNAMITE_ACTIVE_EDITOR 192 #define IMG_WALL_EMERALD 193 #define IMG_WALL_DIAMOND 194 #define IMG_BUG 195 #define IMG_BUG_RIGHT 196 #define IMG_BUG_UP 197 #define IMG_BUG_LEFT 198 #define IMG_BUG_DOWN 199 #define IMG_BUG_MOVING_RIGHT 200 #define IMG_BUG_MOVING_UP 201 #define IMG_BUG_MOVING_LEFT 202 #define IMG_BUG_MOVING_DOWN 203 #define IMG_BUG_TURNING_FROM_RIGHT_UP 204 #define IMG_BUG_TURNING_FROM_UP_LEFT 205 #define IMG_BUG_TURNING_FROM_LEFT_DOWN 206 #define IMG_BUG_TURNING_FROM_DOWN_RIGHT 207 #define IMG_BUG_TURNING_FROM_RIGHT_DOWN 208 #define IMG_BUG_TURNING_FROM_UP_RIGHT 209 #define IMG_BUG_TURNING_FROM_LEFT_UP 210 #define IMG_BUG_TURNING_FROM_DOWN_LEFT 211 #define IMG_SPACESHIP 212 #define IMG_SPACESHIP_RIGHT 213 #define IMG_SPACESHIP_UP 214 #define IMG_SPACESHIP_LEFT 215 #define IMG_SPACESHIP_DOWN 216 #define IMG_SPACESHIP_MOVING_RIGHT 217 #define IMG_SPACESHIP_MOVING_UP 218 #define IMG_SPACESHIP_MOVING_LEFT 219 #define IMG_SPACESHIP_MOVING_DOWN 220 #define IMG_SPACESHIP_TURNING_FROM_RIGHT_UP 221 #define IMG_SPACESHIP_TURNING_FROM_UP_LEFT 222 #define IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN 223 #define IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT 224 #define IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN 225 #define IMG_SPACESHIP_TURNING_FROM_UP_RIGHT 226 #define IMG_SPACESHIP_TURNING_FROM_LEFT_UP 227 #define IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT 228 #define IMG_YAMYAM 229 #define IMG_YAMYAM_LEFT 230 #define IMG_YAMYAM_LEFT_EDITOR 231 #define IMG_YAMYAM_RIGHT 232 #define IMG_YAMYAM_RIGHT_EDITOR 233 #define IMG_YAMYAM_UP 234 #define IMG_YAMYAM_UP_EDITOR 235 #define IMG_YAMYAM_DOWN 236 #define IMG_YAMYAM_DOWN_EDITOR 237 #define IMG_YAMYAM_MOVING 238 #define IMG_ROBOT 239 #define IMG_ROBOT_MOVING 240 #define IMG_ROBOT_WHEEL 241 #define IMG_ROBOT_WHEEL_ACTIVE 242 #define IMG_MAGIC_WALL 243 #define IMG_MAGIC_WALL_ACTIVE 244 #define IMG_MAGIC_WALL_FILLING 245 #define IMG_MAGIC_WALL_FULL 246 #define IMG_MAGIC_WALL_EMPTYING 247 #define IMG_MAGIC_WALL_DEAD 248 #define IMG_DC_MAGIC_WALL 249 #define IMG_DC_MAGIC_WALL_ACTIVE 250 #define IMG_DC_MAGIC_WALL_FILLING 251 #define IMG_DC_MAGIC_WALL_FULL 252 #define IMG_DC_MAGIC_WALL_EMPTYING 253 #define IMG_DC_MAGIC_WALL_DEAD 254 #define IMG_QUICKSAND_EMPTY 255 #define IMG_QUICKSAND_FILLING 256 #define IMG_QUICKSAND_FULL 257 #define IMG_QUICKSAND_FULL_EDITOR 258 #define IMG_QUICKSAND_EMPTYING 259 #define IMG_QUICKSAND_FAST_EMPTY 260 #define IMG_QUICKSAND_FAST_FILLING 261 #define IMG_QUICKSAND_FAST_FULL 262 #define IMG_QUICKSAND_FAST_FULL_EDITOR 263 #define IMG_QUICKSAND_FAST_EMPTYING 264 #define IMG_ACID_POOL_TOPLEFT 265 #define IMG_ACID_POOL_TOPRIGHT 266 #define IMG_ACID_POOL_BOTTOMLEFT 267 #define IMG_ACID_POOL_BOTTOM 268 #define IMG_ACID_POOL_BOTTOMRIGHT 269 #define IMG_ACID 270 #define IMG_ACID_SPLASH_LEFT 271 #define IMG_ACID_SPLASH_RIGHT 272 #define IMG_AMOEBA_DROP 273 #define IMG_AMOEBA_GROWING 274 #define IMG_AMOEBA_SHRINKING 275 #define IMG_AMOEBA_WET 276 #define IMG_AMOEBA_WET_EDITOR 277 #define IMG_AMOEBA_DROPPING 278 #define IMG_AMOEBA_DRY 279 #define IMG_AMOEBA_FULL 280 #define IMG_AMOEBA_FULL_EDITOR 281 #define IMG_AMOEBA_DEAD 282 #define IMG_AMOEBA_DEAD_EDITOR 283 #define IMG_EM_KEY_1 284 #define IMG_EM_KEY_2 285 #define IMG_EM_KEY_3 286 #define IMG_EM_KEY_4 287 #define IMG_DC_KEY_WHITE 288 #define IMG_EM_GATE_1 289 #define IMG_EM_GATE_2 290 #define IMG_EM_GATE_3 291 #define IMG_EM_GATE_4 292 #define IMG_DC_GATE_WHITE 293 #define IMG_EM_GATE_1_GRAY 294 #define IMG_EM_GATE_1_GRAY_EDITOR 295 #define IMG_EM_GATE_1_GRAY_ACTIVE 296 #define IMG_EM_GATE_2_GRAY 297 #define IMG_EM_GATE_2_GRAY_EDITOR 298 #define IMG_EM_GATE_2_GRAY_ACTIVE 299 #define IMG_EM_GATE_3_GRAY 300 #define IMG_EM_GATE_3_GRAY_EDITOR 301 #define IMG_EM_GATE_3_GRAY_ACTIVE 302 #define IMG_EM_GATE_4_GRAY 303 #define IMG_EM_GATE_4_GRAY_EDITOR 304 #define IMG_EM_GATE_4_GRAY_ACTIVE 305 #define IMG_DC_GATE_WHITE_GRAY 306 #define IMG_DC_GATE_WHITE_GRAY_EDITOR 307 #define IMG_DC_GATE_WHITE_GRAY_ACTIVE 308 #define IMG_DC_GATE_FAKE_GRAY 309 #define IMG_EXIT_CLOSED 310 #define IMG_EXIT_OPENING 311 #define IMG_EXIT_OPEN 312 #define IMG_EXIT_CLOSING 313 #define IMG_STEEL_EXIT_CLOSED 314 #define IMG_STEEL_EXIT_OPENING 315 #define IMG_STEEL_EXIT_OPEN 316 #define IMG_STEEL_EXIT_CLOSING 317 #define IMG_EM_EXIT_CLOSED 318 #define IMG_EM_EXIT_OPENING 319 #define IMG_EM_EXIT_OPEN 320 #define IMG_EM_EXIT_CLOSING 321 #define IMG_EM_STEEL_EXIT_CLOSED 322 #define IMG_EM_STEEL_EXIT_OPENING 323 #define IMG_EM_STEEL_EXIT_OPEN 324 #define IMG_EM_STEEL_EXIT_CLOSING 325 #define IMG_BALLOON 326 #define IMG_BALLOON_MOVING 327 #define IMG_BALLOON_PUSHING 328 #define IMG_BALLOON_SWITCH_LEFT 329 #define IMG_BALLOON_SWITCH_RIGHT 330 #define IMG_BALLOON_SWITCH_UP 331 #define IMG_BALLOON_SWITCH_DOWN 332 #define IMG_BALLOON_SWITCH_ANY 333 #define IMG_BALLOON_SWITCH_NONE 334 #define IMG_SPRING 335 #define IMG_EMC_STEELWALL_1 336 #define IMG_EMC_STEELWALL_2 337 #define IMG_EMC_STEELWALL_3 338 #define IMG_EMC_STEELWALL_4 339 #define IMG_EMC_WALL_1 340 #define IMG_EMC_WALL_2 341 #define IMG_EMC_WALL_3 342 #define IMG_EMC_WALL_4 343 #define IMG_EMC_WALL_5 344 #define IMG_EMC_WALL_6 345 #define IMG_EMC_WALL_7 346 #define IMG_EMC_WALL_8 347 #define IMG_INVISIBLE_STEELWALL 348 #define IMG_INVISIBLE_STEELWALL_EDITOR 349 #define IMG_INVISIBLE_STEELWALL_ACTIVE 350 #define IMG_INVISIBLE_WALL 351 #define IMG_INVISIBLE_WALL_EDITOR 352 #define IMG_INVISIBLE_WALL_ACTIVE 353 #define IMG_INVISIBLE_SAND 354 #define IMG_INVISIBLE_SAND_EDITOR 355 #define IMG_INVISIBLE_SAND_ACTIVE 356 #define IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED 357 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT 358 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT 359 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP 360 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN 361 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT_CRUMBLED 362 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT_CRUMBLED 363 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP_CRUMBLED 364 #define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN_CRUMBLED 365 #define IMG_CONVEYOR_BELT_1_MIDDLE 366 #define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE 367 #define IMG_CONVEYOR_BELT_1_LEFT 368 #define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE 369 #define IMG_CONVEYOR_BELT_1_RIGHT 370 #define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE 371 #define IMG_CONVEYOR_BELT_1_SWITCH_LEFT 372 #define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE 373 #define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT 374 #define IMG_CONVEYOR_BELT_2_MIDDLE 375 #define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE 376 #define IMG_CONVEYOR_BELT_2_LEFT 377 #define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE 378 #define IMG_CONVEYOR_BELT_2_RIGHT 379 #define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE 380 #define IMG_CONVEYOR_BELT_2_SWITCH_LEFT 381 #define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE 382 #define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT 383 #define IMG_CONVEYOR_BELT_3_MIDDLE 384 #define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE 385 #define IMG_CONVEYOR_BELT_3_LEFT 386 #define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE 387 #define IMG_CONVEYOR_BELT_3_RIGHT 388 #define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE 389 #define IMG_CONVEYOR_BELT_3_SWITCH_LEFT 390 #define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE 391 #define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT 392 #define IMG_CONVEYOR_BELT_4_MIDDLE 393 #define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE 394 #define IMG_CONVEYOR_BELT_4_LEFT 395 #define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE 396 #define IMG_CONVEYOR_BELT_4_RIGHT 397 #define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE 398 #define IMG_CONVEYOR_BELT_4_SWITCH_LEFT 399 #define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE 400 #define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT 401 #define IMG_SWITCHGATE_SWITCH_UP 402 #define IMG_SWITCHGATE_SWITCH_DOWN 403 #define IMG_DC_SWITCHGATE_SWITCH_UP 404 #define IMG_DC_SWITCHGATE_SWITCH_DOWN 405 #define IMG_LIGHT_SWITCH 406 #define IMG_LIGHT_SWITCH_ACTIVE 407 #define IMG_TIMEGATE_SWITCH 408 #define IMG_TIMEGATE_SWITCH_ACTIVE 409 #define IMG_DC_TIMEGATE_SWITCH 410 #define IMG_DC_TIMEGATE_SWITCH_ACTIVE 411 #define IMG_ENVELOPE_1 412 #define IMG_ENVELOPE_1_COLLECTING 413 #define IMG_ENVELOPE_2 414 #define IMG_ENVELOPE_2_COLLECTING 415 #define IMG_ENVELOPE_3 416 #define IMG_ENVELOPE_3_COLLECTING 417 #define IMG_ENVELOPE_4 418 #define IMG_ENVELOPE_4_COLLECTING 419 #define IMG_SIGN_RADIOACTIVITY 420 #define IMG_SIGN_GIVE_WAY 421 #define IMG_SIGN_NO_ENTRY 422 #define IMG_SIGN_EMERGENCY_EXIT 423 #define IMG_SIGN_YIN_YANG 424 #define IMG_SIGN_EXCLAMATION 425 #define IMG_SIGN_STOP 426 #define IMG_SIGN_PARKING 427 #define IMG_SIGN_WHEELCHAIR 428 #define IMG_SIGN_ENTRY_FORBIDDEN 429 #define IMG_SPERMS 430 #define IMG_BULLET 431 #define IMG_HEART 432 #define IMG_CROSS 433 #define IMG_FRANKIE 434 #define IMG_SIGN_SPERMS 435 #define IMG_SIGN_BULLET 436 #define IMG_SIGN_HEART 437 #define IMG_SIGN_CROSS 438 #define IMG_SIGN_FRANKIE 439 #define IMG_LANDMINE 440 #define IMG_DC_LANDMINE 441 #define IMG_STEELWALL_SLIPPERY 442 #define IMG_EXTRA_TIME 443 #define IMG_SHIELD_NORMAL 444 #define IMG_SHIELD_NORMAL_ACTIVE 445 #define IMG_SHIELD_DEADLY 446 #define IMG_SHIELD_DEADLY_ACTIVE 447 #define IMG_SWITCHGATE_CLOSED 448 #define IMG_SWITCHGATE_OPENING 449 #define IMG_SWITCHGATE_OPEN 450 #define IMG_SWITCHGATE_CLOSING 451 #define IMG_TIMEGATE_CLOSED 452 #define IMG_TIMEGATE_OPENING 453 #define IMG_TIMEGATE_OPEN 454 #define IMG_TIMEGATE_CLOSING 455 #define IMG_PEARL 456 #define IMG_PEARL_BREAKING 457 #define IMG_CRYSTAL 458 #define IMG_WALL_PEARL 459 #define IMG_WALL_CRYSTAL 460 #define IMG_DC_STEELWALL_1_LEFT 461 #define IMG_DC_STEELWALL_1_RIGHT 462 #define IMG_DC_STEELWALL_1_TOP 463 #define IMG_DC_STEELWALL_1_BOTTOM 464 #define IMG_DC_STEELWALL_1_HORIZONTAL 465 #define IMG_DC_STEELWALL_1_VERTICAL 466 #define IMG_DC_STEELWALL_1_TOPLEFT 467 #define IMG_DC_STEELWALL_1_TOPRIGHT 468 #define IMG_DC_STEELWALL_1_BOTTOMLEFT 469 #define IMG_DC_STEELWALL_1_BOTTOMRIGHT 470 #define IMG_DC_STEELWALL_1_TOPLEFT_2 471 #define IMG_DC_STEELWALL_1_TOPRIGHT_2 472 #define IMG_DC_STEELWALL_1_BOTTOMLEFT_2 473 #define IMG_DC_STEELWALL_1_BOTTOMRIGHT_2 474 #define IMG_DC_STEELWALL_2_LEFT 475 #define IMG_DC_STEELWALL_2_RIGHT 476 #define IMG_DC_STEELWALL_2_TOP 477 #define IMG_DC_STEELWALL_2_BOTTOM 478 #define IMG_DC_STEELWALL_2_HORIZONTAL 479 #define IMG_DC_STEELWALL_2_VERTICAL 480 #define IMG_DC_STEELWALL_2_MIDDLE 481 #define IMG_DC_STEELWALL_2_SINGLE 482 #define IMG_TUBE_RIGHT_DOWN 483 #define IMG_TUBE_HORIZONTAL_DOWN 484 #define IMG_TUBE_LEFT_DOWN 485 #define IMG_TUBE_HORIZONTAL 486 #define IMG_TUBE_VERTICAL_RIGHT 487 #define IMG_TUBE_ANY 488 #define IMG_TUBE_VERTICAL_LEFT 489 #define IMG_TUBE_VERTICAL 490 #define IMG_TUBE_RIGHT_UP 491 #define IMG_TUBE_HORIZONTAL_UP 492 #define IMG_TUBE_LEFT_UP 493 #define IMG_TRAP 494 #define IMG_TRAP_ACTIVE 495 #define IMG_DX_SUPABOMB 496 #define IMG_KEY_1 497 #define IMG_KEY_1_EDITOR 498 #define IMG_KEY_2 499 #define IMG_KEY_2_EDITOR 500 #define IMG_KEY_3 501 #define IMG_KEY_3_EDITOR 502 #define IMG_KEY_4 503 #define IMG_KEY_4_EDITOR 504 #define IMG_GATE_1 505 #define IMG_GATE_2 506 #define IMG_GATE_3 507 #define IMG_GATE_4 508 #define IMG_GATE_1_GRAY 509 #define IMG_GATE_1_GRAY_EDITOR 510 #define IMG_GATE_1_GRAY_ACTIVE 511 #define IMG_GATE_2_GRAY 512 #define IMG_GATE_2_GRAY_EDITOR 513 #define IMG_GATE_2_GRAY_ACTIVE 514 #define IMG_GATE_3_GRAY 515 #define IMG_GATE_3_GRAY_EDITOR 516 #define IMG_GATE_3_GRAY_ACTIVE 517 #define IMG_GATE_4_GRAY 518 #define IMG_GATE_4_GRAY_EDITOR 519 #define IMG_GATE_4_GRAY_ACTIVE 520 #define IMG_GAME_OF_LIFE 521 #define IMG_BIOMAZE 522 #define IMG_PACMAN 523 #define IMG_PACMAN_RIGHT 524 #define IMG_PACMAN_UP 525 #define IMG_PACMAN_LEFT 526 #define IMG_PACMAN_DOWN 527 #define IMG_PACMAN_TURNING_FROM_RIGHT 528 #define IMG_PACMAN_TURNING_FROM_UP 529 #define IMG_PACMAN_TURNING_FROM_LEFT 530 #define IMG_PACMAN_TURNING_FROM_DOWN 531 #define IMG_LAMP 532 #define IMG_LAMP_EDITOR 533 #define IMG_LAMP_ACTIVE 534 #define IMG_TIME_ORB_FULL 535 #define IMG_TIME_ORB_EMPTY 536 #define IMG_EMERALD_YELLOW 537 #define IMG_EMERALD_YELLOW_MOVING 538 #define IMG_EMERALD_YELLOW_FALLING 539 #define IMG_EMERALD_RED 540 #define IMG_EMERALD_RED_MOVING 541 #define IMG_EMERALD_RED_FALLING 542 #define IMG_EMERALD_PURPLE 543 #define IMG_EMERALD_PURPLE_MOVING 544 #define IMG_EMERALD_PURPLE_FALLING 545 #define IMG_WALL_EMERALD_YELLOW 546 #define IMG_WALL_EMERALD_RED 547 #define IMG_WALL_EMERALD_PURPLE 548 #define IMG_WALL_BD_DIAMOND 549 #define IMG_EXPANDABLE_WALL 550 #define IMG_EXPANDABLE_WALL_HORIZONTAL 551 #define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR 552 #define IMG_EXPANDABLE_WALL_VERTICAL 553 #define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR 554 #define IMG_EXPANDABLE_WALL_ANY 555 #define IMG_EXPANDABLE_WALL_ANY_EDITOR 556 #define IMG_EXPANDABLE_STEELWALL_HORIZONTAL 557 #define IMG_EXPANDABLE_STEELWALL_HORIZONTAL_EDITOR 558 #define IMG_EXPANDABLE_STEELWALL_VERTICAL 559 #define IMG_EXPANDABLE_STEELWALL_VERTICAL_EDITOR 560 #define IMG_EXPANDABLE_STEELWALL_ANY 561 #define IMG_EXPANDABLE_STEELWALL_ANY_EDITOR 562 #define IMG_BD_EXPANDABLE_WALL 563 #define IMG_BD_EXPANDABLE_WALL_EDITOR 564 #define IMG_EXPANDABLE_WALL_GROWING_LEFT 565 #define IMG_EXPANDABLE_WALL_GROWING_RIGHT 566 #define IMG_EXPANDABLE_WALL_GROWING_UP 567 #define IMG_EXPANDABLE_WALL_GROWING_DOWN 568 #define IMG_EXPANDABLE_STEELWALL_GROWING_LEFT 569 #define IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT 570 #define IMG_EXPANDABLE_STEELWALL_GROWING_UP 571 #define IMG_EXPANDABLE_STEELWALL_GROWING_DOWN 572 #define IMG_BLACK_ORB 573 #define IMG_SPEED_PILL 574 #define IMG_DARK_YAMYAM 575 #define IMG_DYNABOMB 576 #define IMG_DYNABOMB_ACTIVE 577 #define IMG_DYNABOMB_PLAYER_1 578 #define IMG_DYNABOMB_PLAYER_1_ACTIVE 579 #define IMG_DYNABOMB_PLAYER_2 580 #define IMG_DYNABOMB_PLAYER_2_ACTIVE 581 #define IMG_DYNABOMB_PLAYER_3 582 #define IMG_DYNABOMB_PLAYER_3_ACTIVE 583 #define IMG_DYNABOMB_PLAYER_4 584 #define IMG_DYNABOMB_PLAYER_4_ACTIVE 585 #define IMG_DYNABOMB_INCREASE_NUMBER 586 #define IMG_DYNABOMB_INCREASE_SIZE 587 #define IMG_DYNABOMB_INCREASE_POWER 588 #define IMG_PIG 589 #define IMG_PIG_DOWN 590 #define IMG_PIG_UP 591 #define IMG_PIG_LEFT 592 #define IMG_PIG_RIGHT 593 #define IMG_PIG_MOVING_DOWN 594 #define IMG_PIG_MOVING_UP 595 #define IMG_PIG_MOVING_LEFT 596 #define IMG_PIG_MOVING_RIGHT 597 #define IMG_PIG_DIGGING_DOWN 598 #define IMG_PIG_DIGGING_UP 599 #define IMG_PIG_DIGGING_LEFT 600 #define IMG_PIG_DIGGING_RIGHT 601 #define IMG_DRAGON 602 #define IMG_DRAGON_DOWN 603 #define IMG_DRAGON_UP 604 #define IMG_DRAGON_LEFT 605 #define IMG_DRAGON_RIGHT 606 #define IMG_DRAGON_MOVING_DOWN 607 #define IMG_DRAGON_MOVING_UP 608 #define IMG_DRAGON_MOVING_LEFT 609 #define IMG_DRAGON_MOVING_RIGHT 610 #define IMG_DRAGON_ATTACKING_DOWN 611 #define IMG_DRAGON_ATTACKING_UP 612 #define IMG_DRAGON_ATTACKING_LEFT 613 #define IMG_DRAGON_ATTACKING_RIGHT 614 #define IMG_MOLE 615 #define IMG_MOLE_DOWN 616 #define IMG_MOLE_UP 617 #define IMG_MOLE_LEFT 618 #define IMG_MOLE_RIGHT 619 #define IMG_MOLE_MOVING_DOWN 620 #define IMG_MOLE_MOVING_UP 621 #define IMG_MOLE_MOVING_LEFT 622 #define IMG_MOLE_MOVING_RIGHT 623 #define IMG_MOLE_DIGGING_DOWN 624 #define IMG_MOLE_DIGGING_UP 625 #define IMG_MOLE_DIGGING_LEFT 626 #define IMG_MOLE_DIGGING_RIGHT 627 #define IMG_PENGUIN 628 #define IMG_PENGUIN_EDITOR 629 #define IMG_PENGUIN_DOWN 630 #define IMG_PENGUIN_UP 631 #define IMG_PENGUIN_LEFT 632 #define IMG_PENGUIN_RIGHT 633 #define IMG_PENGUIN_MOVING_DOWN 634 #define IMG_PENGUIN_MOVING_UP 635 #define IMG_PENGUIN_MOVING_LEFT 636 #define IMG_PENGUIN_MOVING_RIGHT 637 #define IMG_SATELLITE 638 #define IMG_FLAMES_1_LEFT 639 #define IMG_FLAMES_2_LEFT 640 #define IMG_FLAMES_3_LEFT 641 #define IMG_FLAMES_1_RIGHT 642 #define IMG_FLAMES_2_RIGHT 643 #define IMG_FLAMES_3_RIGHT 644 #define IMG_FLAMES_1_UP 645 #define IMG_FLAMES_2_UP 646 #define IMG_FLAMES_3_UP 647 #define IMG_FLAMES_1_DOWN 648 #define IMG_FLAMES_2_DOWN 649 #define IMG_FLAMES_3_DOWN 650 #define IMG_STONEBLOCK 651 #define IMG_PLAYER_1 652 #define IMG_PLAYER_1_EDITOR 653 #define IMG_PLAYER_1_DOWN 654 #define IMG_PLAYER_1_UP 655 #define IMG_PLAYER_1_LEFT 656 #define IMG_PLAYER_1_RIGHT 657 #define IMG_PLAYER_1_MOVING_DOWN 658 #define IMG_PLAYER_1_MOVING_UP 659 #define IMG_PLAYER_1_MOVING_LEFT 660 #define IMG_PLAYER_1_MOVING_RIGHT 661 #define IMG_PLAYER_1_DIGGING_DOWN 662 #define IMG_PLAYER_1_DIGGING_UP 663 #define IMG_PLAYER_1_DIGGING_LEFT 664 #define IMG_PLAYER_1_DIGGING_RIGHT 665 #define IMG_PLAYER_1_COLLECTING_DOWN 666 #define IMG_PLAYER_1_COLLECTING_UP 667 #define IMG_PLAYER_1_COLLECTING_LEFT 668 #define IMG_PLAYER_1_COLLECTING_RIGHT 669 #define IMG_PLAYER_1_PUSHING_DOWN 670 #define IMG_PLAYER_1_PUSHING_UP 671 #define IMG_PLAYER_1_PUSHING_LEFT 672 #define IMG_PLAYER_1_PUSHING_RIGHT 673 #define IMG_PLAYER_1_SNAPPING_DOWN 674 #define IMG_PLAYER_1_SNAPPING_UP 675 #define IMG_PLAYER_1_SNAPPING_LEFT 676 #define IMG_PLAYER_1_SNAPPING_RIGHT 677 #define IMG_PLAYER_2 678 #define IMG_PLAYER_2_EDITOR 679 #define IMG_PLAYER_2_DOWN 680 #define IMG_PLAYER_2_UP 681 #define IMG_PLAYER_2_LEFT 682 #define IMG_PLAYER_2_RIGHT 683 #define IMG_PLAYER_2_MOVING_DOWN 684 #define IMG_PLAYER_2_MOVING_UP 685 #define IMG_PLAYER_2_MOVING_LEFT 686 #define IMG_PLAYER_2_MOVING_RIGHT 687 #define IMG_PLAYER_2_DIGGING_DOWN 688 #define IMG_PLAYER_2_DIGGING_UP 689 #define IMG_PLAYER_2_DIGGING_LEFT 690 #define IMG_PLAYER_2_DIGGING_RIGHT 691 #define IMG_PLAYER_2_COLLECTING_DOWN 692 #define IMG_PLAYER_2_COLLECTING_UP 693 #define IMG_PLAYER_2_COLLECTING_LEFT 694 #define IMG_PLAYER_2_COLLECTING_RIGHT 695 #define IMG_PLAYER_2_PUSHING_DOWN 696 #define IMG_PLAYER_2_PUSHING_UP 697 #define IMG_PLAYER_2_PUSHING_LEFT 698 #define IMG_PLAYER_2_PUSHING_RIGHT 699 #define IMG_PLAYER_2_SNAPPING_DOWN 700 #define IMG_PLAYER_2_SNAPPING_UP 701 #define IMG_PLAYER_2_SNAPPING_LEFT 702 #define IMG_PLAYER_2_SNAPPING_RIGHT 703 #define IMG_PLAYER_3 704 #define IMG_PLAYER_3_EDITOR 705 #define IMG_PLAYER_3_DOWN 706 #define IMG_PLAYER_3_UP 707 #define IMG_PLAYER_3_LEFT 708 #define IMG_PLAYER_3_RIGHT 709 #define IMG_PLAYER_3_MOVING_DOWN 710 #define IMG_PLAYER_3_MOVING_UP 711 #define IMG_PLAYER_3_MOVING_LEFT 712 #define IMG_PLAYER_3_MOVING_RIGHT 713 #define IMG_PLAYER_3_DIGGING_DOWN 714 #define IMG_PLAYER_3_DIGGING_UP 715 #define IMG_PLAYER_3_DIGGING_LEFT 716 #define IMG_PLAYER_3_DIGGING_RIGHT 717 #define IMG_PLAYER_3_COLLECTING_DOWN 718 #define IMG_PLAYER_3_COLLECTING_UP 719 #define IMG_PLAYER_3_COLLECTING_LEFT 720 #define IMG_PLAYER_3_COLLECTING_RIGHT 721 #define IMG_PLAYER_3_PUSHING_DOWN 722 #define IMG_PLAYER_3_PUSHING_UP 723 #define IMG_PLAYER_3_PUSHING_LEFT 724 #define IMG_PLAYER_3_PUSHING_RIGHT 725 #define IMG_PLAYER_3_SNAPPING_DOWN 726 #define IMG_PLAYER_3_SNAPPING_UP 727 #define IMG_PLAYER_3_SNAPPING_LEFT 728 #define IMG_PLAYER_3_SNAPPING_RIGHT 729 #define IMG_PLAYER_4 730 #define IMG_PLAYER_4_EDITOR 731 #define IMG_PLAYER_4_DOWN 732 #define IMG_PLAYER_4_UP 733 #define IMG_PLAYER_4_LEFT 734 #define IMG_PLAYER_4_RIGHT 735 #define IMG_PLAYER_4_MOVING_DOWN 736 #define IMG_PLAYER_4_MOVING_UP 737 #define IMG_PLAYER_4_MOVING_LEFT 738 #define IMG_PLAYER_4_MOVING_RIGHT 739 #define IMG_PLAYER_4_DIGGING_DOWN 740 #define IMG_PLAYER_4_DIGGING_UP 741 #define IMG_PLAYER_4_DIGGING_LEFT 742 #define IMG_PLAYER_4_DIGGING_RIGHT 743 #define IMG_PLAYER_4_COLLECTING_DOWN 744 #define IMG_PLAYER_4_COLLECTING_UP 745 #define IMG_PLAYER_4_COLLECTING_LEFT 746 #define IMG_PLAYER_4_COLLECTING_RIGHT 747 #define IMG_PLAYER_4_PUSHING_DOWN 748 #define IMG_PLAYER_4_PUSHING_UP 749 #define IMG_PLAYER_4_PUSHING_LEFT 750 #define IMG_PLAYER_4_PUSHING_RIGHT 751 #define IMG_PLAYER_4_SNAPPING_DOWN 752 #define IMG_PLAYER_4_SNAPPING_UP 753 #define IMG_PLAYER_4_SNAPPING_LEFT 754 #define IMG_PLAYER_4_SNAPPING_RIGHT 755 #define IMG_DEFAULT_EXPLODING 756 #define IMG_TWINKLE_BLUE 757 #define IMG_TWINKLE_WHITE 758 #define IMG_STEELWALL_TOPLEFT 759 #define IMG_STEELWALL_TOPRIGHT 760 #define IMG_STEELWALL_BOTTOMLEFT 761 #define IMG_STEELWALL_BOTTOMRIGHT 762 #define IMG_STEELWALL_HORIZONTAL 763 #define IMG_STEELWALL_VERTICAL 764 #define IMG_STEELWALL_TOPLEFT_EDITOR 765 #define IMG_STEELWALL_TOPRIGHT_EDITOR 766 #define IMG_STEELWALL_BOTTOMLEFT_EDITOR 767 #define IMG_STEELWALL_BOTTOMRIGHT_EDITOR 768 #define IMG_STEELWALL_HORIZONTAL_EDITOR 769 #define IMG_STEELWALL_VERTICAL_EDITOR 770 #define IMG_INVISIBLE_STEELWALL_TOPLEFT 771 #define IMG_INVISIBLE_STEELWALL_TOPRIGHT 772 #define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT 773 #define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT 774 #define IMG_INVISIBLE_STEELWALL_HORIZONTAL 775 #define IMG_INVISIBLE_STEELWALL_VERTICAL 776 #define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR 777 #define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR 778 #define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR 779 #define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR 780 #define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR 781 #define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR 782 #define IMG_ARROW_LEFT 783 #define IMG_ARROW_RIGHT 784 #define IMG_ARROW_UP 785 #define IMG_ARROW_DOWN 786 #define IMG_UNKNOWN 787 #define IMG_TRIGGER_ELEMENT 788 #define IMG_TRIGGER_PLAYER 789 #define IMG_TRIGGER_CE_VALUE 790 #define IMG_TRIGGER_CE_SCORE 791 #define IMG_CURRENT_CE_VALUE 792 #define IMG_CURRENT_CE_SCORE 793 #define IMG_PREV_CE_1 794 #define IMG_PREV_CE_2 795 #define IMG_PREV_CE_3 796 #define IMG_PREV_CE_4 797 #define IMG_PREV_CE_5 798 #define IMG_PREV_CE_6 799 #define IMG_PREV_CE_7 800 #define IMG_PREV_CE_8 801 #define IMG_NEXT_CE_1 802 #define IMG_NEXT_CE_2 803 #define IMG_NEXT_CE_3 804 #define IMG_NEXT_CE_4 805 #define IMG_NEXT_CE_5 806 #define IMG_NEXT_CE_6 807 #define IMG_NEXT_CE_7 808 #define IMG_NEXT_CE_8 809 #define IMG_SELF 810 #define IMG_ANY_ELEMENT 811 #define IMG_EMC_KEY_5 812 #define IMG_EMC_KEY_6 813 #define IMG_EMC_KEY_7 814 #define IMG_EMC_KEY_8 815 #define IMG_EMC_GATE_5 816 #define IMG_EMC_GATE_6 817 #define IMG_EMC_GATE_7 818 #define IMG_EMC_GATE_8 819 #define IMG_EMC_GATE_5_GRAY 820 #define IMG_EMC_GATE_5_GRAY_EDITOR 821 #define IMG_EMC_GATE_5_GRAY_ACTIVE 822 #define IMG_EMC_GATE_6_GRAY 823 #define IMG_EMC_GATE_6_GRAY_EDITOR 824 #define IMG_EMC_GATE_6_GRAY_ACTIVE 825 #define IMG_EMC_GATE_7_GRAY 826 #define IMG_EMC_GATE_7_GRAY_EDITOR 827 #define IMG_EMC_GATE_7_GRAY_ACTIVE 828 #define IMG_EMC_GATE_8_GRAY 829 #define IMG_EMC_GATE_8_GRAY_EDITOR 830 #define IMG_EMC_GATE_8_GRAY_ACTIVE 831 #define IMG_EMC_ANDROID 832 #define IMG_EMC_ANDROID_SHRINKING_UPLEFT 833 #define IMG_EMC_ANDROID_GROWING_DOWNRIGHT 834 #define IMG_EMC_ANDROID_SHRINKING_DOWNLEFT 835 #define IMG_EMC_ANDROID_GROWING_UPRIGHT 836 #define IMG_EMC_ANDROID_SHRINKING_UPRIGHT 837 #define IMG_EMC_ANDROID_GROWING_DOWNLEFT 838 #define IMG_EMC_ANDROID_SHRINKING_DOWNRIGHT 839 #define IMG_EMC_ANDROID_GROWING_UPLEFT 840 #define IMG_EMC_GRASS 841 #define IMG_EMC_GRASS_CRUMBLED 842 #define IMG_EMC_GRASS_DIGGING_LEFT 843 #define IMG_EMC_GRASS_DIGGING_RIGHT 844 #define IMG_EMC_GRASS_DIGGING_UP 845 #define IMG_EMC_GRASS_DIGGING_DOWN 846 #define IMG_EMC_GRASS_DIGGING_LEFT_CRUMBLED 847 #define IMG_EMC_GRASS_DIGGING_RIGHT_CRUMBLED 848 #define IMG_EMC_GRASS_DIGGING_UP_CRUMBLED 849 #define IMG_EMC_GRASS_DIGGING_DOWN_CRUMBLED 850 #define IMG_EMC_MAGIC_BALL 851 #define IMG_EMC_MAGIC_BALL_ACTIVE 852 #define IMG_EMC_MAGIC_BALL_DROPPING 853 #define IMG_EMC_MAGIC_BALL_SWITCH 854 #define IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE 855 #define IMG_EMC_SPRING_BUMPER 856 #define IMG_EMC_SPRING_BUMPER_ACTIVE 857 #define IMG_EMC_PLANT 858 #define IMG_EMC_PLANT_CRUMBLED 859 #define IMG_EMC_LENSES 860 #define IMG_EMC_MAGNIFIER 861 #define IMG_EMC_WALL_9 862 #define IMG_EMC_WALL_10 863 #define IMG_EMC_WALL_11 864 #define IMG_EMC_WALL_12 865 #define IMG_EMC_WALL_13 866 #define IMG_EMC_WALL_14 867 #define IMG_EMC_WALL_15 868 #define IMG_EMC_WALL_16 869 #define IMG_EMC_WALL_SLIPPERY_1 870 #define IMG_EMC_WALL_SLIPPERY_2 871 #define IMG_EMC_WALL_SLIPPERY_3 872 #define IMG_EMC_WALL_SLIPPERY_4 873 #define IMG_EMC_FAKE_GRASS 874 #define IMG_EMC_FAKE_GRASS_CRUMBLED 875 #define IMG_EMC_FAKE_GRASS_ACTIVE 876 #define IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED 877 #define IMG_EMC_FAKE_GRASS_EDITOR 878 #define IMG_EMC_FAKE_ACID 879 #define IMG_EMC_DRIPPER 880 #define IMG_EMC_DRIPPER_EDITOR 881 #define IMG_EMC_DRIPPER_ACTIVE 882 #define IMG_MM_MCDUFFIN 883 #define IMG_MM_MCDUFFIN_RIGHT 884 #define IMG_MM_MCDUFFIN_UP 885 #define IMG_MM_MCDUFFIN_LEFT 886 #define IMG_MM_MCDUFFIN_DOWN 887 #define IMG_MM_EXIT_CLOSED 888 #define IMG_MM_EXIT_OPENING 889 #define IMG_MM_EXIT_OPEN 890 #define IMG_MM_EXIT_CLOSING 891 #define IMG_MM_MIRROR_1 892 #define IMG_MM_MIRROR_2 893 #define IMG_MM_MIRROR_3 894 #define IMG_MM_MIRROR_4 895 #define IMG_MM_MIRROR_5 896 #define IMG_MM_MIRROR_6 897 #define IMG_MM_MIRROR_7 898 #define IMG_MM_MIRROR_8 899 #define IMG_MM_MIRROR_9 900 #define IMG_MM_MIRROR_10 901 #define IMG_MM_MIRROR_11 902 #define IMG_MM_MIRROR_12 903 #define IMG_MM_MIRROR_13 904 #define IMG_MM_MIRROR_14 905 #define IMG_MM_MIRROR_15 906 #define IMG_MM_MIRROR_16 907 #define IMG_MM_MIRROR_FIXED_1 908 #define IMG_MM_MIRROR_FIXED_2 909 #define IMG_MM_MIRROR_FIXED_3 910 #define IMG_MM_MIRROR_FIXED_4 911 #define IMG_MM_STEEL_GRID_FIXED_1 912 #define IMG_MM_STEEL_GRID_FIXED_2 913 #define IMG_MM_STEEL_GRID_FIXED_3 914 #define IMG_MM_STEEL_GRID_FIXED_4 915 #define IMG_MM_WOODEN_GRID_FIXED_1 916 #define IMG_MM_WOODEN_GRID_FIXED_2 917 #define IMG_MM_WOODEN_GRID_FIXED_3 918 #define IMG_MM_WOODEN_GRID_FIXED_4 919 #define IMG_MM_POLARIZER_1 920 #define IMG_MM_POLARIZER_2 921 #define IMG_MM_POLARIZER_3 922 #define IMG_MM_POLARIZER_4 923 #define IMG_MM_POLARIZER_5 924 #define IMG_MM_POLARIZER_6 925 #define IMG_MM_POLARIZER_7 926 #define IMG_MM_POLARIZER_8 927 #define IMG_MM_POLARIZER_9 928 #define IMG_MM_POLARIZER_10 929 #define IMG_MM_POLARIZER_11 930 #define IMG_MM_POLARIZER_12 931 #define IMG_MM_POLARIZER_13 932 #define IMG_MM_POLARIZER_14 933 #define IMG_MM_POLARIZER_15 934 #define IMG_MM_POLARIZER_16 935 #define IMG_MM_POLARIZER_CROSS_1 936 #define IMG_MM_POLARIZER_CROSS_2 937 #define IMG_MM_POLARIZER_CROSS_3 938 #define IMG_MM_POLARIZER_CROSS_4 939 #define IMG_MM_TELEPORTER_1 940 #define IMG_MM_TELEPORTER_2 941 #define IMG_MM_TELEPORTER_3 942 #define IMG_MM_TELEPORTER_4 943 #define IMG_MM_TELEPORTER_5 944 #define IMG_MM_TELEPORTER_6 945 #define IMG_MM_TELEPORTER_7 946 #define IMG_MM_TELEPORTER_8 947 #define IMG_MM_TELEPORTER_9 948 #define IMG_MM_TELEPORTER_10 949 #define IMG_MM_TELEPORTER_11 950 #define IMG_MM_TELEPORTER_12 951 #define IMG_MM_TELEPORTER_13 952 #define IMG_MM_TELEPORTER_14 953 #define IMG_MM_TELEPORTER_15 954 #define IMG_MM_TELEPORTER_16 955 #define IMG_MM_TELEPORTER_RED_1 956 #define IMG_MM_TELEPORTER_RED_2 957 #define IMG_MM_TELEPORTER_RED_3 958 #define IMG_MM_TELEPORTER_RED_4 959 #define IMG_MM_TELEPORTER_RED_5 960 #define IMG_MM_TELEPORTER_RED_6 961 #define IMG_MM_TELEPORTER_RED_7 962 #define IMG_MM_TELEPORTER_RED_8 963 #define IMG_MM_TELEPORTER_RED_9 964 #define IMG_MM_TELEPORTER_RED_10 965 #define IMG_MM_TELEPORTER_RED_11 966 #define IMG_MM_TELEPORTER_RED_12 967 #define IMG_MM_TELEPORTER_RED_13 968 #define IMG_MM_TELEPORTER_RED_14 969 #define IMG_MM_TELEPORTER_RED_15 970 #define IMG_MM_TELEPORTER_RED_16 971 #define IMG_MM_TELEPORTER_YELLOW_1 972 #define IMG_MM_TELEPORTER_YELLOW_2 973 #define IMG_MM_TELEPORTER_YELLOW_3 974 #define IMG_MM_TELEPORTER_YELLOW_4 975 #define IMG_MM_TELEPORTER_YELLOW_5 976 #define IMG_MM_TELEPORTER_YELLOW_6 977 #define IMG_MM_TELEPORTER_YELLOW_7 978 #define IMG_MM_TELEPORTER_YELLOW_8 979 #define IMG_MM_TELEPORTER_YELLOW_9 980 #define IMG_MM_TELEPORTER_YELLOW_10 981 #define IMG_MM_TELEPORTER_YELLOW_11 982 #define IMG_MM_TELEPORTER_YELLOW_12 983 #define IMG_MM_TELEPORTER_YELLOW_13 984 #define IMG_MM_TELEPORTER_YELLOW_14 985 #define IMG_MM_TELEPORTER_YELLOW_15 986 #define IMG_MM_TELEPORTER_YELLOW_16 987 #define IMG_MM_TELEPORTER_GREEN_1 988 #define IMG_MM_TELEPORTER_GREEN_2 989 #define IMG_MM_TELEPORTER_GREEN_3 990 #define IMG_MM_TELEPORTER_GREEN_4 991 #define IMG_MM_TELEPORTER_GREEN_5 992 #define IMG_MM_TELEPORTER_GREEN_6 993 #define IMG_MM_TELEPORTER_GREEN_7 994 #define IMG_MM_TELEPORTER_GREEN_8 995 #define IMG_MM_TELEPORTER_GREEN_9 996 #define IMG_MM_TELEPORTER_GREEN_10 997 #define IMG_MM_TELEPORTER_GREEN_11 998 #define IMG_MM_TELEPORTER_GREEN_12 999 #define IMG_MM_TELEPORTER_GREEN_13 1000 #define IMG_MM_TELEPORTER_GREEN_14 1001 #define IMG_MM_TELEPORTER_GREEN_15 1002 #define IMG_MM_TELEPORTER_GREEN_16 1003 #define IMG_MM_TELEPORTER_BLUE_1 1004 #define IMG_MM_TELEPORTER_BLUE_2 1005 #define IMG_MM_TELEPORTER_BLUE_3 1006 #define IMG_MM_TELEPORTER_BLUE_4 1007 #define IMG_MM_TELEPORTER_BLUE_5 1008 #define IMG_MM_TELEPORTER_BLUE_6 1009 #define IMG_MM_TELEPORTER_BLUE_7 1010 #define IMG_MM_TELEPORTER_BLUE_8 1011 #define IMG_MM_TELEPORTER_BLUE_9 1012 #define IMG_MM_TELEPORTER_BLUE_10 1013 #define IMG_MM_TELEPORTER_BLUE_11 1014 #define IMG_MM_TELEPORTER_BLUE_12 1015 #define IMG_MM_TELEPORTER_BLUE_13 1016 #define IMG_MM_TELEPORTER_BLUE_14 1017 #define IMG_MM_TELEPORTER_BLUE_15 1018 #define IMG_MM_TELEPORTER_BLUE_16 1019 #define IMG_MM_KETTLE 1020 #define IMG_MM_KETTLE_EXPLODING 1021 #define IMG_MM_BOMB 1022 #define IMG_MM_PRISM 1023 #define IMG_MM_FUSE 1024 #define IMG_MM_FUSE_ACTIVE 1025 #define IMG_MM_STEEL_LOCK 1026 #define IMG_MM_WOODEN_LOCK 1027 #define IMG_MM_STEEL_BLOCK 1028 #define IMG_MM_WOODEN_BLOCK 1029 #define IMG_MM_KEY 1030 #define IMG_MM_LIGHTBULB 1031 #define IMG_MM_LIGHTBULB_ACTIVE 1032 #define IMG_MM_LIGHTBALL 1033 #define IMG_MM_LIGHTBALL_RED 1034 #define IMG_MM_LIGHTBALL_BLUE 1035 #define IMG_MM_LIGHTBALL_YELLOW 1036 #define IMG_MM_GRAY_BALL 1037 #define IMG_MM_FUEL_FULL 1038 #define IMG_MM_FUEL_EMPTY 1039 #define IMG_MM_STEEL_WALL 1040 #define IMG_MM_WOODEN_WALL 1041 #define IMG_MM_ICE_WALL 1042 #define IMG_MM_ICE_WALL_SHRINKING 1043 #define IMG_MM_AMOEBA_WALL 1044 #define IMG_MM_AMOEBA_WALL_GROWING 1045 #define IMG_MM_PACMAN 1046 #define IMG_MM_PACMAN_RIGHT 1047 #define IMG_MM_PACMAN_UP 1048 #define IMG_MM_PACMAN_LEFT 1049 #define IMG_MM_PACMAN_DOWN 1050 #define IMG_MM_PACMAN_EATING_RIGHT 1051 #define IMG_MM_PACMAN_EATING_UP 1052 #define IMG_MM_PACMAN_EATING_LEFT 1053 #define IMG_MM_PACMAN_EATING_DOWN 1054 #define IMG_MM_MASK_MCDUFFIN_RIGHT 1055 #define IMG_MM_MASK_MCDUFFIN_UP 1056 #define IMG_MM_MASK_MCDUFFIN_LEFT 1057 #define IMG_MM_MASK_MCDUFFIN_DOWN 1058 #define IMG_MM_MASK_GRID_1 1059 #define IMG_MM_MASK_GRID_2 1060 #define IMG_MM_MASK_GRID_3 1061 #define IMG_MM_MASK_GRID_4 1062 #define IMG_MM_MASK_RECTANGLE 1063 #define IMG_MM_MASK_CIRCLE 1064 #define IMG_MM_DEFAULT_EXPLODING 1065 #define IMG_DF_LASER 1066 #define IMG_DF_LASER_RIGHT 1067 #define IMG_DF_LASER_UP 1068 #define IMG_DF_LASER_LEFT 1069 #define IMG_DF_LASER_DOWN 1070 #define IMG_DF_RECEIVER 1071 #define IMG_DF_RECEIVER_RIGHT 1072 #define IMG_DF_RECEIVER_UP 1073 #define IMG_DF_RECEIVER_LEFT 1074 #define IMG_DF_RECEIVER_DOWN 1075 #define IMG_DF_MIRROR_1 1076 #define IMG_DF_MIRROR_2 1077 #define IMG_DF_MIRROR_3 1078 #define IMG_DF_MIRROR_4 1079 #define IMG_DF_MIRROR_5 1080 #define IMG_DF_MIRROR_6 1081 #define IMG_DF_MIRROR_7 1082 #define IMG_DF_MIRROR_8 1083 #define IMG_DF_MIRROR_9 1084 #define IMG_DF_MIRROR_10 1085 #define IMG_DF_MIRROR_11 1086 #define IMG_DF_MIRROR_12 1087 #define IMG_DF_MIRROR_13 1088 #define IMG_DF_MIRROR_14 1089 #define IMG_DF_MIRROR_15 1090 #define IMG_DF_MIRROR_16 1091 #define IMG_DF_MIRROR_ROTATING_1 1092 #define IMG_DF_MIRROR_ROTATING_1_EDITOR 1093 #define IMG_DF_MIRROR_ROTATING_2 1094 #define IMG_DF_MIRROR_ROTATING_2_EDITOR 1095 #define IMG_DF_MIRROR_ROTATING_3 1096 #define IMG_DF_MIRROR_ROTATING_3_EDITOR 1097 #define IMG_DF_MIRROR_ROTATING_4 1098 #define IMG_DF_MIRROR_ROTATING_4_EDITOR 1099 #define IMG_DF_MIRROR_ROTATING_5 1100 #define IMG_DF_MIRROR_ROTATING_5_EDITOR 1101 #define IMG_DF_MIRROR_ROTATING_6 1102 #define IMG_DF_MIRROR_ROTATING_6_EDITOR 1103 #define IMG_DF_MIRROR_ROTATING_7 1104 #define IMG_DF_MIRROR_ROTATING_7_EDITOR 1105 #define IMG_DF_MIRROR_ROTATING_8 1106 #define IMG_DF_MIRROR_ROTATING_8_EDITOR 1107 #define IMG_DF_MIRROR_ROTATING_9 1108 #define IMG_DF_MIRROR_ROTATING_9_EDITOR 1109 #define IMG_DF_MIRROR_ROTATING_10 1110 #define IMG_DF_MIRROR_ROTATING_10_EDITOR 1111 #define IMG_DF_MIRROR_ROTATING_11 1112 #define IMG_DF_MIRROR_ROTATING_11_EDITOR 1113 #define IMG_DF_MIRROR_ROTATING_12 1114 #define IMG_DF_MIRROR_ROTATING_12_EDITOR 1115 #define IMG_DF_MIRROR_ROTATING_13 1116 #define IMG_DF_MIRROR_ROTATING_13_EDITOR 1117 #define IMG_DF_MIRROR_ROTATING_14 1118 #define IMG_DF_MIRROR_ROTATING_14_EDITOR 1119 #define IMG_DF_MIRROR_ROTATING_15 1120 #define IMG_DF_MIRROR_ROTATING_15_EDITOR 1121 #define IMG_DF_MIRROR_ROTATING_16 1122 #define IMG_DF_MIRROR_ROTATING_16_EDITOR 1123 #define IMG_DF_STEEL_GRID_FIXED_1 1124 #define IMG_DF_STEEL_GRID_FIXED_2 1125 #define IMG_DF_STEEL_GRID_FIXED_3 1126 #define IMG_DF_STEEL_GRID_FIXED_4 1127 #define IMG_DF_STEEL_GRID_FIXED_5 1128 #define IMG_DF_STEEL_GRID_FIXED_6 1129 #define IMG_DF_STEEL_GRID_FIXED_7 1130 #define IMG_DF_STEEL_GRID_FIXED_8 1131 #define IMG_DF_WOODEN_GRID_FIXED_1 1132 #define IMG_DF_WOODEN_GRID_FIXED_2 1133 #define IMG_DF_WOODEN_GRID_FIXED_3 1134 #define IMG_DF_WOODEN_GRID_FIXED_4 1135 #define IMG_DF_WOODEN_GRID_FIXED_5 1136 #define IMG_DF_WOODEN_GRID_FIXED_6 1137 #define IMG_DF_WOODEN_GRID_FIXED_7 1138 #define IMG_DF_WOODEN_GRID_FIXED_8 1139 #define IMG_DF_STEEL_GRID_ROTATING_1 1140 #define IMG_DF_STEEL_GRID_ROTATING_1_EDITOR 1141 #define IMG_DF_STEEL_GRID_ROTATING_2 1142 #define IMG_DF_STEEL_GRID_ROTATING_2_EDITOR 1143 #define IMG_DF_STEEL_GRID_ROTATING_3 1144 #define IMG_DF_STEEL_GRID_ROTATING_3_EDITOR 1145 #define IMG_DF_STEEL_GRID_ROTATING_4 1146 #define IMG_DF_STEEL_GRID_ROTATING_4_EDITOR 1147 #define IMG_DF_STEEL_GRID_ROTATING_5 1148 #define IMG_DF_STEEL_GRID_ROTATING_5_EDITOR 1149 #define IMG_DF_STEEL_GRID_ROTATING_6 1150 #define IMG_DF_STEEL_GRID_ROTATING_6_EDITOR 1151 #define IMG_DF_STEEL_GRID_ROTATING_7 1152 #define IMG_DF_STEEL_GRID_ROTATING_7_EDITOR 1153 #define IMG_DF_STEEL_GRID_ROTATING_8 1154 #define IMG_DF_STEEL_GRID_ROTATING_8_EDITOR 1155 #define IMG_DF_WOODEN_GRID_ROTATING_1 1156 #define IMG_DF_WOODEN_GRID_ROTATING_1_EDITOR 1157 #define IMG_DF_WOODEN_GRID_ROTATING_2 1158 #define IMG_DF_WOODEN_GRID_ROTATING_2_EDITOR 1159 #define IMG_DF_WOODEN_GRID_ROTATING_3 1160 #define IMG_DF_WOODEN_GRID_ROTATING_3_EDITOR 1161 #define IMG_DF_WOODEN_GRID_ROTATING_4 1162 #define IMG_DF_WOODEN_GRID_ROTATING_4_EDITOR 1163 #define IMG_DF_WOODEN_GRID_ROTATING_5 1164 #define IMG_DF_WOODEN_GRID_ROTATING_5_EDITOR 1165 #define IMG_DF_WOODEN_GRID_ROTATING_6 1166 #define IMG_DF_WOODEN_GRID_ROTATING_6_EDITOR 1167 #define IMG_DF_WOODEN_GRID_ROTATING_7 1168 #define IMG_DF_WOODEN_GRID_ROTATING_7_EDITOR 1169 #define IMG_DF_WOODEN_GRID_ROTATING_8 1170 #define IMG_DF_WOODEN_GRID_ROTATING_8_EDITOR 1171 #define IMG_DF_FIBRE_OPTIC_RED_1 1172 #define IMG_DF_FIBRE_OPTIC_RED_1_EDITOR 1173 #define IMG_DF_FIBRE_OPTIC_RED_2 1174 #define IMG_DF_FIBRE_OPTIC_RED_2_EDITOR 1175 #define IMG_DF_FIBRE_OPTIC_YELLOW_1 1176 #define IMG_DF_FIBRE_OPTIC_YELLOW_1_EDITOR 1177 #define IMG_DF_FIBRE_OPTIC_YELLOW_2 1178 #define IMG_DF_FIBRE_OPTIC_YELLOW_2_EDITOR 1179 #define IMG_DF_FIBRE_OPTIC_GREEN_1 1180 #define IMG_DF_FIBRE_OPTIC_GREEN_1_EDITOR 1181 #define IMG_DF_FIBRE_OPTIC_GREEN_2 1182 #define IMG_DF_FIBRE_OPTIC_GREEN_2_EDITOR 1183 #define IMG_DF_FIBRE_OPTIC_BLUE_1 1184 #define IMG_DF_FIBRE_OPTIC_BLUE_1_EDITOR 1185 #define IMG_DF_FIBRE_OPTIC_BLUE_2 1186 #define IMG_DF_FIBRE_OPTIC_BLUE_2_EDITOR 1187 #define IMG_DF_STEEL_WALL 1188 #define IMG_DF_WOODEN_WALL 1189 #define IMG_DF_REFRACTOR 1190 #define IMG_DF_CELL 1191 #define IMG_DF_MINE 1192 #define IMG_GRAPHIC_1 1193 #define IMG_GRAPHIC_2 1194 #define IMG_GRAPHIC_3 1195 #define IMG_GRAPHIC_4 1196 #define IMG_GRAPHIC_5 1197 #define IMG_GRAPHIC_6 1198 #define IMG_GRAPHIC_7 1199 #define IMG_GRAPHIC_8 1200 #define IMG_CHAR_SPACE 1201 #define IMG_CHAR_SPACE_EDITOR 1202 #define IMG_CHAR_EXCLAM 1203 #define IMG_CHAR_QUOTEDBL 1204 #define IMG_CHAR_NUMBERSIGN 1205 #define IMG_CHAR_DOLLAR 1206 #define IMG_CHAR_PERCENT 1207 #define IMG_CHAR_AMPERSAND 1208 #define IMG_CHAR_APOSTROPHE 1209 #define IMG_CHAR_PARENLEFT 1210 #define IMG_CHAR_PARENRIGHT 1211 #define IMG_CHAR_ASTERISK 1212 #define IMG_CHAR_PLUS 1213 #define IMG_CHAR_COMMA 1214 #define IMG_CHAR_MINUS 1215 #define IMG_CHAR_PERIOD 1216 #define IMG_CHAR_SLASH 1217 #define IMG_CHAR_0 1218 #define IMG_CHAR_1 1219 #define IMG_CHAR_2 1220 #define IMG_CHAR_3 1221 #define IMG_CHAR_4 1222 #define IMG_CHAR_5 1223 #define IMG_CHAR_6 1224 #define IMG_CHAR_7 1225 #define IMG_CHAR_8 1226 #define IMG_CHAR_9 1227 #define IMG_CHAR_COLON 1228 #define IMG_CHAR_SEMICOLON 1229 #define IMG_CHAR_LESS 1230 #define IMG_CHAR_EQUAL 1231 #define IMG_CHAR_GREATER 1232 #define IMG_CHAR_QUESTION 1233 #define IMG_CHAR_AT 1234 #define IMG_CHAR_A 1235 #define IMG_CHAR_B 1236 #define IMG_CHAR_C 1237 #define IMG_CHAR_D 1238 #define IMG_CHAR_E 1239 #define IMG_CHAR_F 1240 #define IMG_CHAR_G 1241 #define IMG_CHAR_H 1242 #define IMG_CHAR_I 1243 #define IMG_CHAR_J 1244 #define IMG_CHAR_K 1245 #define IMG_CHAR_L 1246 #define IMG_CHAR_M 1247 #define IMG_CHAR_N 1248 #define IMG_CHAR_O 1249 #define IMG_CHAR_P 1250 #define IMG_CHAR_Q 1251 #define IMG_CHAR_R 1252 #define IMG_CHAR_S 1253 #define IMG_CHAR_T 1254 #define IMG_CHAR_U 1255 #define IMG_CHAR_V 1256 #define IMG_CHAR_W 1257 #define IMG_CHAR_X 1258 #define IMG_CHAR_Y 1259 #define IMG_CHAR_Z 1260 #define IMG_CHAR_BRACKETLEFT 1261 #define IMG_CHAR_BACKSLASH 1262 #define IMG_CHAR_BRACKETRIGHT 1263 #define IMG_CHAR_ASCIICIRCUM 1264 #define IMG_CHAR_UNDERSCORE 1265 #define IMG_CHAR_COPYRIGHT 1266 #define IMG_CHAR_AUMLAUT 1267 #define IMG_CHAR_OUMLAUT 1268 #define IMG_CHAR_UUMLAUT 1269 #define IMG_CHAR_DEGREE 1270 #define IMG_CHAR_TRADEMARK 1271 #define IMG_CHAR_CURSOR 1272 #define IMG_CHAR_BUTTON 1273 #define IMG_CHAR_UP 1274 #define IMG_CHAR_DOWN 1275 #define IMG_STEEL_CHAR_SPACE 1276 #define IMG_STEEL_CHAR_SPACE_EDITOR 1277 #define IMG_STEEL_CHAR_EXCLAM 1278 #define IMG_STEEL_CHAR_QUOTEDBL 1279 #define IMG_STEEL_CHAR_NUMBERSIGN 1280 #define IMG_STEEL_CHAR_DOLLAR 1281 #define IMG_STEEL_CHAR_PERCENT 1282 #define IMG_STEEL_CHAR_AMPERSAND 1283 #define IMG_STEEL_CHAR_APOSTROPHE 1284 #define IMG_STEEL_CHAR_PARENLEFT 1285 #define IMG_STEEL_CHAR_PARENRIGHT 1286 #define IMG_STEEL_CHAR_ASTERISK 1287 #define IMG_STEEL_CHAR_PLUS 1288 #define IMG_STEEL_CHAR_COMMA 1289 #define IMG_STEEL_CHAR_MINUS 1290 #define IMG_STEEL_CHAR_PERIOD 1291 #define IMG_STEEL_CHAR_SLASH 1292 #define IMG_STEEL_CHAR_0 1293 #define IMG_STEEL_CHAR_1 1294 #define IMG_STEEL_CHAR_2 1295 #define IMG_STEEL_CHAR_3 1296 #define IMG_STEEL_CHAR_4 1297 #define IMG_STEEL_CHAR_5 1298 #define IMG_STEEL_CHAR_6 1299 #define IMG_STEEL_CHAR_7 1300 #define IMG_STEEL_CHAR_8 1301 #define IMG_STEEL_CHAR_9 1302 #define IMG_STEEL_CHAR_COLON 1303 #define IMG_STEEL_CHAR_SEMICOLON 1304 #define IMG_STEEL_CHAR_LESS 1305 #define IMG_STEEL_CHAR_EQUAL 1306 #define IMG_STEEL_CHAR_GREATER 1307 #define IMG_STEEL_CHAR_QUESTION 1308 #define IMG_STEEL_CHAR_AT 1309 #define IMG_STEEL_CHAR_A 1310 #define IMG_STEEL_CHAR_B 1311 #define IMG_STEEL_CHAR_C 1312 #define IMG_STEEL_CHAR_D 1313 #define IMG_STEEL_CHAR_E 1314 #define IMG_STEEL_CHAR_F 1315 #define IMG_STEEL_CHAR_G 1316 #define IMG_STEEL_CHAR_H 1317 #define IMG_STEEL_CHAR_I 1318 #define IMG_STEEL_CHAR_J 1319 #define IMG_STEEL_CHAR_K 1320 #define IMG_STEEL_CHAR_L 1321 #define IMG_STEEL_CHAR_M 1322 #define IMG_STEEL_CHAR_N 1323 #define IMG_STEEL_CHAR_O 1324 #define IMG_STEEL_CHAR_P 1325 #define IMG_STEEL_CHAR_Q 1326 #define IMG_STEEL_CHAR_R 1327 #define IMG_STEEL_CHAR_S 1328 #define IMG_STEEL_CHAR_T 1329 #define IMG_STEEL_CHAR_U 1330 #define IMG_STEEL_CHAR_V 1331 #define IMG_STEEL_CHAR_W 1332 #define IMG_STEEL_CHAR_X 1333 #define IMG_STEEL_CHAR_Y 1334 #define IMG_STEEL_CHAR_Z 1335 #define IMG_STEEL_CHAR_BRACKETLEFT 1336 #define IMG_STEEL_CHAR_BACKSLASH 1337 #define IMG_STEEL_CHAR_BRACKETRIGHT 1338 #define IMG_STEEL_CHAR_ASCIICIRCUM 1339 #define IMG_STEEL_CHAR_UNDERSCORE 1340 #define IMG_STEEL_CHAR_COPYRIGHT 1341 #define IMG_STEEL_CHAR_AUMLAUT 1342 #define IMG_STEEL_CHAR_OUMLAUT 1343 #define IMG_STEEL_CHAR_UUMLAUT 1344 #define IMG_STEEL_CHAR_DEGREE 1345 #define IMG_STEEL_CHAR_TRADEMARK 1346 #define IMG_STEEL_CHAR_CURSOR 1347 #define IMG_STEEL_CHAR_BUTTON 1348 #define IMG_STEEL_CHAR_UP 1349 #define IMG_STEEL_CHAR_DOWN 1350 #define IMG_CUSTOM_1 1351 #define IMG_CUSTOM_1_EDITOR 1352 #define IMG_CUSTOM_2 1353 #define IMG_CUSTOM_2_EDITOR 1354 #define IMG_CUSTOM_3 1355 #define IMG_CUSTOM_3_EDITOR 1356 #define IMG_CUSTOM_4 1357 #define IMG_CUSTOM_4_EDITOR 1358 #define IMG_CUSTOM_5 1359 #define IMG_CUSTOM_5_EDITOR 1360 #define IMG_CUSTOM_6 1361 #define IMG_CUSTOM_6_EDITOR 1362 #define IMG_CUSTOM_7 1363 #define IMG_CUSTOM_7_EDITOR 1364 #define IMG_CUSTOM_8 1365 #define IMG_CUSTOM_8_EDITOR 1366 #define IMG_CUSTOM_9 1367 #define IMG_CUSTOM_9_EDITOR 1368 #define IMG_CUSTOM_10 1369 #define IMG_CUSTOM_10_EDITOR 1370 #define IMG_CUSTOM_11 1371 #define IMG_CUSTOM_11_EDITOR 1372 #define IMG_CUSTOM_12 1373 #define IMG_CUSTOM_12_EDITOR 1374 #define IMG_CUSTOM_13 1375 #define IMG_CUSTOM_13_EDITOR 1376 #define IMG_CUSTOM_14 1377 #define IMG_CUSTOM_14_EDITOR 1378 #define IMG_CUSTOM_15 1379 #define IMG_CUSTOM_15_EDITOR 1380 #define IMG_CUSTOM_16 1381 #define IMG_CUSTOM_16_EDITOR 1382 #define IMG_CUSTOM_17 1383 #define IMG_CUSTOM_17_EDITOR 1384 #define IMG_CUSTOM_18 1385 #define IMG_CUSTOM_18_EDITOR 1386 #define IMG_CUSTOM_19 1387 #define IMG_CUSTOM_19_EDITOR 1388 #define IMG_CUSTOM_20 1389 #define IMG_CUSTOM_20_EDITOR 1390 #define IMG_CUSTOM_21 1391 #define IMG_CUSTOM_21_EDITOR 1392 #define IMG_CUSTOM_22 1393 #define IMG_CUSTOM_22_EDITOR 1394 #define IMG_CUSTOM_23 1395 #define IMG_CUSTOM_23_EDITOR 1396 #define IMG_CUSTOM_24 1397 #define IMG_CUSTOM_24_EDITOR 1398 #define IMG_CUSTOM_25 1399 #define IMG_CUSTOM_25_EDITOR 1400 #define IMG_CUSTOM_26 1401 #define IMG_CUSTOM_26_EDITOR 1402 #define IMG_CUSTOM_27 1403 #define IMG_CUSTOM_27_EDITOR 1404 #define IMG_CUSTOM_28 1405 #define IMG_CUSTOM_28_EDITOR 1406 #define IMG_CUSTOM_29 1407 #define IMG_CUSTOM_29_EDITOR 1408 #define IMG_CUSTOM_30 1409 #define IMG_CUSTOM_30_EDITOR 1410 #define IMG_CUSTOM_31 1411 #define IMG_CUSTOM_31_EDITOR 1412 #define IMG_CUSTOM_32 1413 #define IMG_CUSTOM_32_EDITOR 1414 #define IMG_CUSTOM_33 1415 #define IMG_CUSTOM_33_EDITOR 1416 #define IMG_CUSTOM_34 1417 #define IMG_CUSTOM_34_EDITOR 1418 #define IMG_CUSTOM_35 1419 #define IMG_CUSTOM_35_EDITOR 1420 #define IMG_CUSTOM_36 1421 #define IMG_CUSTOM_36_EDITOR 1422 #define IMG_CUSTOM_37 1423 #define IMG_CUSTOM_37_EDITOR 1424 #define IMG_CUSTOM_38 1425 #define IMG_CUSTOM_38_EDITOR 1426 #define IMG_CUSTOM_39 1427 #define IMG_CUSTOM_39_EDITOR 1428 #define IMG_CUSTOM_40 1429 #define IMG_CUSTOM_40_EDITOR 1430 #define IMG_CUSTOM_41 1431 #define IMG_CUSTOM_41_EDITOR 1432 #define IMG_CUSTOM_42 1433 #define IMG_CUSTOM_42_EDITOR 1434 #define IMG_CUSTOM_43 1435 #define IMG_CUSTOM_43_EDITOR 1436 #define IMG_CUSTOM_44 1437 #define IMG_CUSTOM_44_EDITOR 1438 #define IMG_CUSTOM_45 1439 #define IMG_CUSTOM_45_EDITOR 1440 #define IMG_CUSTOM_46 1441 #define IMG_CUSTOM_46_EDITOR 1442 #define IMG_CUSTOM_47 1443 #define IMG_CUSTOM_47_EDITOR 1444 #define IMG_CUSTOM_48 1445 #define IMG_CUSTOM_48_EDITOR 1446 #define IMG_CUSTOM_49 1447 #define IMG_CUSTOM_49_EDITOR 1448 #define IMG_CUSTOM_50 1449 #define IMG_CUSTOM_50_EDITOR 1450 #define IMG_CUSTOM_51 1451 #define IMG_CUSTOM_51_EDITOR 1452 #define IMG_CUSTOM_52 1453 #define IMG_CUSTOM_52_EDITOR 1454 #define IMG_CUSTOM_53 1455 #define IMG_CUSTOM_53_EDITOR 1456 #define IMG_CUSTOM_54 1457 #define IMG_CUSTOM_54_EDITOR 1458 #define IMG_CUSTOM_55 1459 #define IMG_CUSTOM_55_EDITOR 1460 #define IMG_CUSTOM_56 1461 #define IMG_CUSTOM_56_EDITOR 1462 #define IMG_CUSTOM_57 1463 #define IMG_CUSTOM_57_EDITOR 1464 #define IMG_CUSTOM_58 1465 #define IMG_CUSTOM_58_EDITOR 1466 #define IMG_CUSTOM_59 1467 #define IMG_CUSTOM_59_EDITOR 1468 #define IMG_CUSTOM_60 1469 #define IMG_CUSTOM_60_EDITOR 1470 #define IMG_CUSTOM_61 1471 #define IMG_CUSTOM_61_EDITOR 1472 #define IMG_CUSTOM_62 1473 #define IMG_CUSTOM_62_EDITOR 1474 #define IMG_CUSTOM_63 1475 #define IMG_CUSTOM_63_EDITOR 1476 #define IMG_CUSTOM_64 1477 #define IMG_CUSTOM_64_EDITOR 1478 #define IMG_CUSTOM_65 1479 #define IMG_CUSTOM_65_EDITOR 1480 #define IMG_CUSTOM_66 1481 #define IMG_CUSTOM_66_EDITOR 1482 #define IMG_CUSTOM_67 1483 #define IMG_CUSTOM_67_EDITOR 1484 #define IMG_CUSTOM_68 1485 #define IMG_CUSTOM_68_EDITOR 1486 #define IMG_CUSTOM_69 1487 #define IMG_CUSTOM_69_EDITOR 1488 #define IMG_CUSTOM_70 1489 #define IMG_CUSTOM_70_EDITOR 1490 #define IMG_CUSTOM_71 1491 #define IMG_CUSTOM_71_EDITOR 1492 #define IMG_CUSTOM_72 1493 #define IMG_CUSTOM_72_EDITOR 1494 #define IMG_CUSTOM_73 1495 #define IMG_CUSTOM_73_EDITOR 1496 #define IMG_CUSTOM_74 1497 #define IMG_CUSTOM_74_EDITOR 1498 #define IMG_CUSTOM_75 1499 #define IMG_CUSTOM_75_EDITOR 1500 #define IMG_CUSTOM_76 1501 #define IMG_CUSTOM_76_EDITOR 1502 #define IMG_CUSTOM_77 1503 #define IMG_CUSTOM_77_EDITOR 1504 #define IMG_CUSTOM_78 1505 #define IMG_CUSTOM_78_EDITOR 1506 #define IMG_CUSTOM_79 1507 #define IMG_CUSTOM_79_EDITOR 1508 #define IMG_CUSTOM_80 1509 #define IMG_CUSTOM_80_EDITOR 1510 #define IMG_CUSTOM_81 1511 #define IMG_CUSTOM_81_EDITOR 1512 #define IMG_CUSTOM_82 1513 #define IMG_CUSTOM_82_EDITOR 1514 #define IMG_CUSTOM_83 1515 #define IMG_CUSTOM_83_EDITOR 1516 #define IMG_CUSTOM_84 1517 #define IMG_CUSTOM_84_EDITOR 1518 #define IMG_CUSTOM_85 1519 #define IMG_CUSTOM_85_EDITOR 1520 #define IMG_CUSTOM_86 1521 #define IMG_CUSTOM_86_EDITOR 1522 #define IMG_CUSTOM_87 1523 #define IMG_CUSTOM_87_EDITOR 1524 #define IMG_CUSTOM_88 1525 #define IMG_CUSTOM_88_EDITOR 1526 #define IMG_CUSTOM_89 1527 #define IMG_CUSTOM_89_EDITOR 1528 #define IMG_CUSTOM_90 1529 #define IMG_CUSTOM_90_EDITOR 1530 #define IMG_CUSTOM_91 1531 #define IMG_CUSTOM_91_EDITOR 1532 #define IMG_CUSTOM_92 1533 #define IMG_CUSTOM_92_EDITOR 1534 #define IMG_CUSTOM_93 1535 #define IMG_CUSTOM_93_EDITOR 1536 #define IMG_CUSTOM_94 1537 #define IMG_CUSTOM_94_EDITOR 1538 #define IMG_CUSTOM_95 1539 #define IMG_CUSTOM_95_EDITOR 1540 #define IMG_CUSTOM_96 1541 #define IMG_CUSTOM_96_EDITOR 1542 #define IMG_CUSTOM_97 1543 #define IMG_CUSTOM_97_EDITOR 1544 #define IMG_CUSTOM_98 1545 #define IMG_CUSTOM_98_EDITOR 1546 #define IMG_CUSTOM_99 1547 #define IMG_CUSTOM_99_EDITOR 1548 #define IMG_CUSTOM_100 1549 #define IMG_CUSTOM_100_EDITOR 1550 #define IMG_CUSTOM_101 1551 #define IMG_CUSTOM_101_EDITOR 1552 #define IMG_CUSTOM_102 1553 #define IMG_CUSTOM_102_EDITOR 1554 #define IMG_CUSTOM_103 1555 #define IMG_CUSTOM_103_EDITOR 1556 #define IMG_CUSTOM_104 1557 #define IMG_CUSTOM_104_EDITOR 1558 #define IMG_CUSTOM_105 1559 #define IMG_CUSTOM_105_EDITOR 1560 #define IMG_CUSTOM_106 1561 #define IMG_CUSTOM_106_EDITOR 1562 #define IMG_CUSTOM_107 1563 #define IMG_CUSTOM_107_EDITOR 1564 #define IMG_CUSTOM_108 1565 #define IMG_CUSTOM_108_EDITOR 1566 #define IMG_CUSTOM_109 1567 #define IMG_CUSTOM_109_EDITOR 1568 #define IMG_CUSTOM_110 1569 #define IMG_CUSTOM_110_EDITOR 1570 #define IMG_CUSTOM_111 1571 #define IMG_CUSTOM_111_EDITOR 1572 #define IMG_CUSTOM_112 1573 #define IMG_CUSTOM_112_EDITOR 1574 #define IMG_CUSTOM_113 1575 #define IMG_CUSTOM_113_EDITOR 1576 #define IMG_CUSTOM_114 1577 #define IMG_CUSTOM_114_EDITOR 1578 #define IMG_CUSTOM_115 1579 #define IMG_CUSTOM_115_EDITOR 1580 #define IMG_CUSTOM_116 1581 #define IMG_CUSTOM_116_EDITOR 1582 #define IMG_CUSTOM_117 1583 #define IMG_CUSTOM_117_EDITOR 1584 #define IMG_CUSTOM_118 1585 #define IMG_CUSTOM_118_EDITOR 1586 #define IMG_CUSTOM_119 1587 #define IMG_CUSTOM_119_EDITOR 1588 #define IMG_CUSTOM_120 1589 #define IMG_CUSTOM_120_EDITOR 1590 #define IMG_CUSTOM_121 1591 #define IMG_CUSTOM_121_EDITOR 1592 #define IMG_CUSTOM_122 1593 #define IMG_CUSTOM_122_EDITOR 1594 #define IMG_CUSTOM_123 1595 #define IMG_CUSTOM_123_EDITOR 1596 #define IMG_CUSTOM_124 1597 #define IMG_CUSTOM_124_EDITOR 1598 #define IMG_CUSTOM_125 1599 #define IMG_CUSTOM_125_EDITOR 1600 #define IMG_CUSTOM_126 1601 #define IMG_CUSTOM_126_EDITOR 1602 #define IMG_CUSTOM_127 1603 #define IMG_CUSTOM_127_EDITOR 1604 #define IMG_CUSTOM_128 1605 #define IMG_CUSTOM_128_EDITOR 1606 #define IMG_CUSTOM_129 1607 #define IMG_CUSTOM_129_EDITOR 1608 #define IMG_CUSTOM_130 1609 #define IMG_CUSTOM_130_EDITOR 1610 #define IMG_CUSTOM_131 1611 #define IMG_CUSTOM_131_EDITOR 1612 #define IMG_CUSTOM_132 1613 #define IMG_CUSTOM_132_EDITOR 1614 #define IMG_CUSTOM_133 1615 #define IMG_CUSTOM_133_EDITOR 1616 #define IMG_CUSTOM_134 1617 #define IMG_CUSTOM_134_EDITOR 1618 #define IMG_CUSTOM_135 1619 #define IMG_CUSTOM_135_EDITOR 1620 #define IMG_CUSTOM_136 1621 #define IMG_CUSTOM_136_EDITOR 1622 #define IMG_CUSTOM_137 1623 #define IMG_CUSTOM_137_EDITOR 1624 #define IMG_CUSTOM_138 1625 #define IMG_CUSTOM_138_EDITOR 1626 #define IMG_CUSTOM_139 1627 #define IMG_CUSTOM_139_EDITOR 1628 #define IMG_CUSTOM_140 1629 #define IMG_CUSTOM_140_EDITOR 1630 #define IMG_CUSTOM_141 1631 #define IMG_CUSTOM_141_EDITOR 1632 #define IMG_CUSTOM_142 1633 #define IMG_CUSTOM_142_EDITOR 1634 #define IMG_CUSTOM_143 1635 #define IMG_CUSTOM_143_EDITOR 1636 #define IMG_CUSTOM_144 1637 #define IMG_CUSTOM_144_EDITOR 1638 #define IMG_CUSTOM_145 1639 #define IMG_CUSTOM_145_EDITOR 1640 #define IMG_CUSTOM_146 1641 #define IMG_CUSTOM_146_EDITOR 1642 #define IMG_CUSTOM_147 1643 #define IMG_CUSTOM_147_EDITOR 1644 #define IMG_CUSTOM_148 1645 #define IMG_CUSTOM_148_EDITOR 1646 #define IMG_CUSTOM_149 1647 #define IMG_CUSTOM_149_EDITOR 1648 #define IMG_CUSTOM_150 1649 #define IMG_CUSTOM_150_EDITOR 1650 #define IMG_CUSTOM_151 1651 #define IMG_CUSTOM_151_EDITOR 1652 #define IMG_CUSTOM_152 1653 #define IMG_CUSTOM_152_EDITOR 1654 #define IMG_CUSTOM_153 1655 #define IMG_CUSTOM_153_EDITOR 1656 #define IMG_CUSTOM_154 1657 #define IMG_CUSTOM_154_EDITOR 1658 #define IMG_CUSTOM_155 1659 #define IMG_CUSTOM_155_EDITOR 1660 #define IMG_CUSTOM_156 1661 #define IMG_CUSTOM_156_EDITOR 1662 #define IMG_CUSTOM_157 1663 #define IMG_CUSTOM_157_EDITOR 1664 #define IMG_CUSTOM_158 1665 #define IMG_CUSTOM_158_EDITOR 1666 #define IMG_CUSTOM_159 1667 #define IMG_CUSTOM_159_EDITOR 1668 #define IMG_CUSTOM_160 1669 #define IMG_CUSTOM_160_EDITOR 1670 #define IMG_CUSTOM_161 1671 #define IMG_CUSTOM_161_EDITOR 1672 #define IMG_CUSTOM_162 1673 #define IMG_CUSTOM_162_EDITOR 1674 #define IMG_CUSTOM_163 1675 #define IMG_CUSTOM_163_EDITOR 1676 #define IMG_CUSTOM_164 1677 #define IMG_CUSTOM_164_EDITOR 1678 #define IMG_CUSTOM_165 1679 #define IMG_CUSTOM_165_EDITOR 1680 #define IMG_CUSTOM_166 1681 #define IMG_CUSTOM_166_EDITOR 1682 #define IMG_CUSTOM_167 1683 #define IMG_CUSTOM_167_EDITOR 1684 #define IMG_CUSTOM_168 1685 #define IMG_CUSTOM_168_EDITOR 1686 #define IMG_CUSTOM_169 1687 #define IMG_CUSTOM_169_EDITOR 1688 #define IMG_CUSTOM_170 1689 #define IMG_CUSTOM_170_EDITOR 1690 #define IMG_CUSTOM_171 1691 #define IMG_CUSTOM_171_EDITOR 1692 #define IMG_CUSTOM_172 1693 #define IMG_CUSTOM_172_EDITOR 1694 #define IMG_CUSTOM_173 1695 #define IMG_CUSTOM_173_EDITOR 1696 #define IMG_CUSTOM_174 1697 #define IMG_CUSTOM_174_EDITOR 1698 #define IMG_CUSTOM_175 1699 #define IMG_CUSTOM_175_EDITOR 1700 #define IMG_CUSTOM_176 1701 #define IMG_CUSTOM_176_EDITOR 1702 #define IMG_CUSTOM_177 1703 #define IMG_CUSTOM_177_EDITOR 1704 #define IMG_CUSTOM_178 1705 #define IMG_CUSTOM_178_EDITOR 1706 #define IMG_CUSTOM_179 1707 #define IMG_CUSTOM_179_EDITOR 1708 #define IMG_CUSTOM_180 1709 #define IMG_CUSTOM_180_EDITOR 1710 #define IMG_CUSTOM_181 1711 #define IMG_CUSTOM_181_EDITOR 1712 #define IMG_CUSTOM_182 1713 #define IMG_CUSTOM_182_EDITOR 1714 #define IMG_CUSTOM_183 1715 #define IMG_CUSTOM_183_EDITOR 1716 #define IMG_CUSTOM_184 1717 #define IMG_CUSTOM_184_EDITOR 1718 #define IMG_CUSTOM_185 1719 #define IMG_CUSTOM_185_EDITOR 1720 #define IMG_CUSTOM_186 1721 #define IMG_CUSTOM_186_EDITOR 1722 #define IMG_CUSTOM_187 1723 #define IMG_CUSTOM_187_EDITOR 1724 #define IMG_CUSTOM_188 1725 #define IMG_CUSTOM_188_EDITOR 1726 #define IMG_CUSTOM_189 1727 #define IMG_CUSTOM_189_EDITOR 1728 #define IMG_CUSTOM_190 1729 #define IMG_CUSTOM_190_EDITOR 1730 #define IMG_CUSTOM_191 1731 #define IMG_CUSTOM_191_EDITOR 1732 #define IMG_CUSTOM_192 1733 #define IMG_CUSTOM_192_EDITOR 1734 #define IMG_CUSTOM_193 1735 #define IMG_CUSTOM_193_EDITOR 1736 #define IMG_CUSTOM_194 1737 #define IMG_CUSTOM_194_EDITOR 1738 #define IMG_CUSTOM_195 1739 #define IMG_CUSTOM_195_EDITOR 1740 #define IMG_CUSTOM_196 1741 #define IMG_CUSTOM_196_EDITOR 1742 #define IMG_CUSTOM_197 1743 #define IMG_CUSTOM_197_EDITOR 1744 #define IMG_CUSTOM_198 1745 #define IMG_CUSTOM_198_EDITOR 1746 #define IMG_CUSTOM_199 1747 #define IMG_CUSTOM_199_EDITOR 1748 #define IMG_CUSTOM_200 1749 #define IMG_CUSTOM_200_EDITOR 1750 #define IMG_CUSTOM_201 1751 #define IMG_CUSTOM_201_EDITOR 1752 #define IMG_CUSTOM_202 1753 #define IMG_CUSTOM_202_EDITOR 1754 #define IMG_CUSTOM_203 1755 #define IMG_CUSTOM_203_EDITOR 1756 #define IMG_CUSTOM_204 1757 #define IMG_CUSTOM_204_EDITOR 1758 #define IMG_CUSTOM_205 1759 #define IMG_CUSTOM_205_EDITOR 1760 #define IMG_CUSTOM_206 1761 #define IMG_CUSTOM_206_EDITOR 1762 #define IMG_CUSTOM_207 1763 #define IMG_CUSTOM_207_EDITOR 1764 #define IMG_CUSTOM_208 1765 #define IMG_CUSTOM_208_EDITOR 1766 #define IMG_CUSTOM_209 1767 #define IMG_CUSTOM_209_EDITOR 1768 #define IMG_CUSTOM_210 1769 #define IMG_CUSTOM_210_EDITOR 1770 #define IMG_CUSTOM_211 1771 #define IMG_CUSTOM_211_EDITOR 1772 #define IMG_CUSTOM_212 1773 #define IMG_CUSTOM_212_EDITOR 1774 #define IMG_CUSTOM_213 1775 #define IMG_CUSTOM_213_EDITOR 1776 #define IMG_CUSTOM_214 1777 #define IMG_CUSTOM_214_EDITOR 1778 #define IMG_CUSTOM_215 1779 #define IMG_CUSTOM_215_EDITOR 1780 #define IMG_CUSTOM_216 1781 #define IMG_CUSTOM_216_EDITOR 1782 #define IMG_CUSTOM_217 1783 #define IMG_CUSTOM_217_EDITOR 1784 #define IMG_CUSTOM_218 1785 #define IMG_CUSTOM_218_EDITOR 1786 #define IMG_CUSTOM_219 1787 #define IMG_CUSTOM_219_EDITOR 1788 #define IMG_CUSTOM_220 1789 #define IMG_CUSTOM_220_EDITOR 1790 #define IMG_CUSTOM_221 1791 #define IMG_CUSTOM_221_EDITOR 1792 #define IMG_CUSTOM_222 1793 #define IMG_CUSTOM_222_EDITOR 1794 #define IMG_CUSTOM_223 1795 #define IMG_CUSTOM_223_EDITOR 1796 #define IMG_CUSTOM_224 1797 #define IMG_CUSTOM_224_EDITOR 1798 #define IMG_CUSTOM_225 1799 #define IMG_CUSTOM_225_EDITOR 1800 #define IMG_CUSTOM_226 1801 #define IMG_CUSTOM_226_EDITOR 1802 #define IMG_CUSTOM_227 1803 #define IMG_CUSTOM_227_EDITOR 1804 #define IMG_CUSTOM_228 1805 #define IMG_CUSTOM_228_EDITOR 1806 #define IMG_CUSTOM_229 1807 #define IMG_CUSTOM_229_EDITOR 1808 #define IMG_CUSTOM_230 1809 #define IMG_CUSTOM_230_EDITOR 1810 #define IMG_CUSTOM_231 1811 #define IMG_CUSTOM_231_EDITOR 1812 #define IMG_CUSTOM_232 1813 #define IMG_CUSTOM_232_EDITOR 1814 #define IMG_CUSTOM_233 1815 #define IMG_CUSTOM_233_EDITOR 1816 #define IMG_CUSTOM_234 1817 #define IMG_CUSTOM_234_EDITOR 1818 #define IMG_CUSTOM_235 1819 #define IMG_CUSTOM_235_EDITOR 1820 #define IMG_CUSTOM_236 1821 #define IMG_CUSTOM_236_EDITOR 1822 #define IMG_CUSTOM_237 1823 #define IMG_CUSTOM_237_EDITOR 1824 #define IMG_CUSTOM_238 1825 #define IMG_CUSTOM_238_EDITOR 1826 #define IMG_CUSTOM_239 1827 #define IMG_CUSTOM_239_EDITOR 1828 #define IMG_CUSTOM_240 1829 #define IMG_CUSTOM_240_EDITOR 1830 #define IMG_CUSTOM_241 1831 #define IMG_CUSTOM_241_EDITOR 1832 #define IMG_CUSTOM_242 1833 #define IMG_CUSTOM_242_EDITOR 1834 #define IMG_CUSTOM_243 1835 #define IMG_CUSTOM_243_EDITOR 1836 #define IMG_CUSTOM_244 1837 #define IMG_CUSTOM_244_EDITOR 1838 #define IMG_CUSTOM_245 1839 #define IMG_CUSTOM_245_EDITOR 1840 #define IMG_CUSTOM_246 1841 #define IMG_CUSTOM_246_EDITOR 1842 #define IMG_CUSTOM_247 1843 #define IMG_CUSTOM_247_EDITOR 1844 #define IMG_CUSTOM_248 1845 #define IMG_CUSTOM_248_EDITOR 1846 #define IMG_CUSTOM_249 1847 #define IMG_CUSTOM_249_EDITOR 1848 #define IMG_CUSTOM_250 1849 #define IMG_CUSTOM_250_EDITOR 1850 #define IMG_CUSTOM_251 1851 #define IMG_CUSTOM_251_EDITOR 1852 #define IMG_CUSTOM_252 1853 #define IMG_CUSTOM_252_EDITOR 1854 #define IMG_CUSTOM_253 1855 #define IMG_CUSTOM_253_EDITOR 1856 #define IMG_CUSTOM_254 1857 #define IMG_CUSTOM_254_EDITOR 1858 #define IMG_CUSTOM_255 1859 #define IMG_CUSTOM_255_EDITOR 1860 #define IMG_CUSTOM_256 1861 #define IMG_CUSTOM_256_EDITOR 1862 #define IMG_GROUP_1 1863 #define IMG_GROUP_1_EDITOR 1864 #define IMG_GROUP_2 1865 #define IMG_GROUP_2_EDITOR 1866 #define IMG_GROUP_3 1867 #define IMG_GROUP_3_EDITOR 1868 #define IMG_GROUP_4 1869 #define IMG_GROUP_4_EDITOR 1870 #define IMG_GROUP_5 1871 #define IMG_GROUP_5_EDITOR 1872 #define IMG_GROUP_6 1873 #define IMG_GROUP_6_EDITOR 1874 #define IMG_GROUP_7 1875 #define IMG_GROUP_7_EDITOR 1876 #define IMG_GROUP_8 1877 #define IMG_GROUP_8_EDITOR 1878 #define IMG_GROUP_9 1879 #define IMG_GROUP_9_EDITOR 1880 #define IMG_GROUP_10 1881 #define IMG_GROUP_10_EDITOR 1882 #define IMG_GROUP_11 1883 #define IMG_GROUP_11_EDITOR 1884 #define IMG_GROUP_12 1885 #define IMG_GROUP_12_EDITOR 1886 #define IMG_GROUP_13 1887 #define IMG_GROUP_13_EDITOR 1888 #define IMG_GROUP_14 1889 #define IMG_GROUP_14_EDITOR 1890 #define IMG_GROUP_15 1891 #define IMG_GROUP_15_EDITOR 1892 #define IMG_GROUP_16 1893 #define IMG_GROUP_16_EDITOR 1894 #define IMG_GROUP_17 1895 #define IMG_GROUP_17_EDITOR 1896 #define IMG_GROUP_18 1897 #define IMG_GROUP_18_EDITOR 1898 #define IMG_GROUP_19 1899 #define IMG_GROUP_19_EDITOR 1900 #define IMG_GROUP_20 1901 #define IMG_GROUP_20_EDITOR 1902 #define IMG_GROUP_21 1903 #define IMG_GROUP_21_EDITOR 1904 #define IMG_GROUP_22 1905 #define IMG_GROUP_22_EDITOR 1906 #define IMG_GROUP_23 1907 #define IMG_GROUP_23_EDITOR 1908 #define IMG_GROUP_24 1909 #define IMG_GROUP_24_EDITOR 1910 #define IMG_GROUP_25 1911 #define IMG_GROUP_25_EDITOR 1912 #define IMG_GROUP_26 1913 #define IMG_GROUP_26_EDITOR 1914 #define IMG_GROUP_27 1915 #define IMG_GROUP_27_EDITOR 1916 #define IMG_GROUP_28 1917 #define IMG_GROUP_28_EDITOR 1918 #define IMG_GROUP_29 1919 #define IMG_GROUP_29_EDITOR 1920 #define IMG_GROUP_30 1921 #define IMG_GROUP_30_EDITOR 1922 #define IMG_GROUP_31 1923 #define IMG_GROUP_31_EDITOR 1924 #define IMG_GROUP_32 1925 #define IMG_GROUP_32_EDITOR 1926 #define IMG_EMC_OBJECT 1927 #define IMG_EMC_SPRITE 1928 #define IMG_SP_FRAME_HORIZONTAL 1929 #define IMG_SP_FRAME_VERTICAL 1930 #define IMG_SP_FRAME_CORNER 1931 #define IMG_TOON_1 1932 #define IMG_TOON_2 1933 #define IMG_TOON_3 1934 #define IMG_TOON_4 1935 #define IMG_TOON_5 1936 #define IMG_TOON_6 1937 #define IMG_TOON_7 1938 #define IMG_TOON_8 1939 #define IMG_TOON_9 1940 #define IMG_TOON_10 1941 #define IMG_TOON_11 1942 #define IMG_TOON_12 1943 #define IMG_TOON_13 1944 #define IMG_TOON_14 1945 #define IMG_TOON_15 1946 #define IMG_TOON_16 1947 #define IMG_TOON_17 1948 #define IMG_TOON_18 1949 #define IMG_TOON_19 1950 #define IMG_TOON_20 1951 #define IMG_GFX_GLOBAL_ANIM_1 1952 #define IMG_GFX_GLOBAL_ANIM_2 1953 #define IMG_GFX_GLOBAL_ANIM_3 1954 #define IMG_GFX_GLOBAL_ANIM_4 1955 #define IMG_GFX_GLOBAL_ANIM_5 1956 #define IMG_GFX_GLOBAL_ANIM_6 1957 #define IMG_GFX_GLOBAL_ANIM_7 1958 #define IMG_GFX_GLOBAL_ANIM_8 1959 #define IMG_GFX_GLOBAL_ANIM_9 1960 #define IMG_GFX_GLOBAL_ANIM_10 1961 #define IMG_GFX_GLOBAL_ANIM_11 1962 #define IMG_GFX_GLOBAL_ANIM_12 1963 #define IMG_GFX_GLOBAL_ANIM_13 1964 #define IMG_GFX_GLOBAL_ANIM_14 1965 #define IMG_GFX_GLOBAL_ANIM_15 1966 #define IMG_GFX_GLOBAL_ANIM_16 1967 #define IMG_GFX_GLOBAL_ANIM_17 1968 #define IMG_GFX_GLOBAL_ANIM_18 1969 #define IMG_GFX_GLOBAL_ANIM_19 1970 #define IMG_GFX_GLOBAL_ANIM_20 1971 #define IMG_GFX_GLOBAL_ANIM_21 1972 #define IMG_GFX_GLOBAL_ANIM_22 1973 #define IMG_GFX_GLOBAL_ANIM_23 1974 #define IMG_GFX_GLOBAL_ANIM_24 1975 #define IMG_GFX_GLOBAL_ANIM_25 1976 #define IMG_GFX_GLOBAL_ANIM_26 1977 #define IMG_GFX_GLOBAL_ANIM_27 1978 #define IMG_GFX_GLOBAL_ANIM_28 1979 #define IMG_GFX_GLOBAL_ANIM_29 1980 #define IMG_GFX_GLOBAL_ANIM_30 1981 #define IMG_GFX_GLOBAL_ANIM_31 1982 #define IMG_GFX_GLOBAL_ANIM_32 1983 #define IMG_GLOBAL_ANIM_1 1984 #define IMG_GLOBAL_ANIM_2 1985 #define IMG_GLOBAL_ANIM_3 1986 #define IMG_GLOBAL_ANIM_4 1987 #define IMG_GLOBAL_ANIM_5 1988 #define IMG_GLOBAL_ANIM_6 1989 #define IMG_GLOBAL_ANIM_7 1990 #define IMG_GLOBAL_ANIM_8 1991 #define IMG_GLOBAL_ANIM_9 1992 #define IMG_GLOBAL_ANIM_10 1993 #define IMG_GLOBAL_ANIM_11 1994 #define IMG_GLOBAL_ANIM_12 1995 #define IMG_GLOBAL_ANIM_13 1996 #define IMG_GLOBAL_ANIM_14 1997 #define IMG_GLOBAL_ANIM_15 1998 #define IMG_GLOBAL_ANIM_16 1999 #define IMG_GLOBAL_ANIM_17 2000 #define IMG_GLOBAL_ANIM_18 2001 #define IMG_GLOBAL_ANIM_19 2002 #define IMG_GLOBAL_ANIM_20 2003 #define IMG_GLOBAL_ANIM_21 2004 #define IMG_GLOBAL_ANIM_22 2005 #define IMG_GLOBAL_ANIM_23 2006 #define IMG_GLOBAL_ANIM_24 2007 #define IMG_GLOBAL_ANIM_25 2008 #define IMG_GLOBAL_ANIM_26 2009 #define IMG_GLOBAL_ANIM_27 2010 #define IMG_GLOBAL_ANIM_28 2011 #define IMG_GLOBAL_ANIM_29 2012 #define IMG_GLOBAL_ANIM_30 2013 #define IMG_GLOBAL_ANIM_31 2014 #define IMG_GLOBAL_ANIM_32 2015 #define IMG_INTERNAL_GLOBAL_TOON_DEFAULT 2016 #define IMG_INTERNAL_GLOBAL_ANIM_DEFAULT 2017 #define IMG_MENU_CALIBRATE_RED 2018 #define IMG_MENU_CALIBRATE_BLUE 2019 #define IMG_MENU_CALIBRATE_YELLOW 2020 #define IMG_MENU_BUTTON 2021 #define IMG_MENU_BUTTON_ACTIVE 2022 #define IMG_MENU_BUTTON_LEFT 2023 #define IMG_MENU_BUTTON_LEFT_ACTIVE 2024 #define IMG_MENU_BUTTON_RIGHT 2025 #define IMG_MENU_BUTTON_RIGHT_ACTIVE 2026 #define IMG_MENU_BUTTON_UP 2027 #define IMG_MENU_BUTTON_UP_ACTIVE 2028 #define IMG_MENU_BUTTON_DOWN 2029 #define IMG_MENU_BUTTON_DOWN_ACTIVE 2030 #define IMG_MENU_BUTTON_ENTER_MENU 2031 #define IMG_MENU_BUTTON_ENTER_MENU_ACTIVE 2032 #define IMG_MENU_BUTTON_LEAVE_MENU 2033 #define IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE 2034 #define IMG_MENU_BUTTON_NEXT_LEVEL 2035 #define IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE 2036 #define IMG_MENU_BUTTON_PREV_LEVEL 2037 #define IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE 2038 #define IMG_MENU_BUTTON_NAME 2039 #define IMG_MENU_BUTTON_NAME_ACTIVE 2040 #define IMG_MENU_BUTTON_LEVELS 2041 #define IMG_MENU_BUTTON_LEVELS_ACTIVE 2042 #define IMG_MENU_BUTTON_SCORES 2043 #define IMG_MENU_BUTTON_SCORES_ACTIVE 2044 #define IMG_MENU_BUTTON_EDITOR 2045 #define IMG_MENU_BUTTON_EDITOR_ACTIVE 2046 #define IMG_MENU_BUTTON_INFO 2047 #define IMG_MENU_BUTTON_INFO_ACTIVE 2048 #define IMG_MENU_BUTTON_GAME 2049 #define IMG_MENU_BUTTON_GAME_ACTIVE 2050 #define IMG_MENU_BUTTON_SETUP 2051 #define IMG_MENU_BUTTON_SETUP_ACTIVE 2052 #define IMG_MENU_BUTTON_QUIT 2053 #define IMG_MENU_BUTTON_QUIT_ACTIVE 2054 #define IMG_MENU_SCROLLBAR 2055 #define IMG_MENU_SCROLLBAR_ACTIVE 2056 #define IMG_GFX_GAME_PANEL_TIME_ANIM 2057 #define IMG_GFX_GAME_PANEL_TIME_ANIM_ACTIVE 2058 #define IMG_GFX_GAME_PANEL_HEALTH_ANIM 2059 #define IMG_GFX_GAME_PANEL_HEALTH_ANIM_ACTIVE 2060 #define IMG_GFX_GAME_BUTTON_STOP 2061 #define IMG_GFX_GAME_BUTTON_PAUSE 2062 #define IMG_GFX_GAME_BUTTON_PLAY 2063 #define IMG_GFX_GAME_BUTTON_UNDO 2064 #define IMG_GFX_GAME_BUTTON_REDO 2065 #define IMG_GFX_GAME_BUTTON_SAVE 2066 #define IMG_GFX_GAME_BUTTON_PAUSE2 2067 #define IMG_GFX_GAME_BUTTON_LOAD 2068 #define IMG_GFX_GAME_BUTTON_SOUND_MUSIC 2069 #define IMG_GFX_GAME_BUTTON_SOUND_LOOPS 2070 #define IMG_GFX_GAME_BUTTON_SOUND_SIMPLE 2071 #define IMG_GFX_GAME_BUTTON_PANEL_STOP 2072 #define IMG_GFX_GAME_BUTTON_PANEL_PAUSE 2073 #define IMG_GFX_GAME_BUTTON_PANEL_PLAY 2074 #define IMG_GFX_GAME_BUTTON_PANEL_SOUND_MUSIC 2075 #define IMG_GFX_GAME_BUTTON_PANEL_SOUND_LOOPS 2076 #define IMG_GFX_GAME_BUTTON_PANEL_SOUND_SIMPLE 2077 #define IMG_GFX_TAPE_BUTTON_EJECT 2078 #define IMG_GFX_TAPE_BUTTON_EXTRA 2079 #define IMG_GFX_TAPE_BUTTON_STOP 2080 #define IMG_GFX_TAPE_BUTTON_PAUSE 2081 #define IMG_GFX_TAPE_BUTTON_RECORD 2082 #define IMG_GFX_TAPE_BUTTON_PLAY 2083 #define IMG_GFX_TAPE_SYMBOL_EJECT 2084 #define IMG_GFX_TAPE_SYMBOL_STOP 2085 #define IMG_GFX_TAPE_SYMBOL_PAUSE 2086 #define IMG_GFX_TAPE_SYMBOL_RECORD 2087 #define IMG_GFX_TAPE_SYMBOL_PLAY 2088 #define IMG_GFX_TAPE_SYMBOL_FAST_FORWARD 2089 #define IMG_GFX_TAPE_SYMBOL_WARP_FORWARD 2090 #define IMG_GFX_TAPE_SYMBOL_WARP_FORWARD_BLIND 2091 #define IMG_GFX_TAPE_SYMBOL_PAUSE_BEFORE_END 2092 #define IMG_GFX_TAPE_SYMBOL_SINGLE_STEP 2093 #define IMG_GFX_TAPE_LABEL_EJECT 2094 #define IMG_GFX_TAPE_LABEL_STOP 2095 #define IMG_GFX_TAPE_LABEL_PAUSE 2096 #define IMG_GFX_TAPE_LABEL_RECORD 2097 #define IMG_GFX_TAPE_LABEL_PLAY 2098 #define IMG_GFX_TAPE_LABEL_FAST_FORWARD 2099 #define IMG_GFX_TAPE_LABEL_WARP_FORWARD 2100 #define IMG_GFX_TAPE_LABEL_WARP_FORWARD_BLIND 2101 #define IMG_GFX_TAPE_LABEL_PAUSE_BEFORE_END 2102 #define IMG_GFX_TAPE_LABEL_SINGLE_STEP 2103 #define IMG_GFX_TAPE_LABEL_DATE 2104 #define IMG_GFX_TAPE_LABEL_TIME 2105 #define IMG_GFX_REQUEST_BUTTON_YES 2106 #define IMG_GFX_REQUEST_BUTTON_NO 2107 #define IMG_GFX_REQUEST_BUTTON_CONFIRM 2108 #define IMG_GFX_REQUEST_BUTTON_PLAYER_1 2109 #define IMG_GFX_REQUEST_BUTTON_PLAYER_2 2110 #define IMG_GFX_REQUEST_BUTTON_PLAYER_3 2111 #define IMG_GFX_REQUEST_BUTTON_PLAYER_4 2112 #define IMG_FONT_INITIAL_1 2113 #define IMG_FONT_INITIAL_2 2114 #define IMG_FONT_INITIAL_3 2115 #define IMG_FONT_INITIAL_4 2116 #define IMG_FONT_TITLE_1 2117 #define IMG_FONT_TITLE_2 2118 #define IMG_FONT_TITLE_2_SETUP 2119 #define IMG_FONT_MENU_1 2120 #define IMG_FONT_MENU_1_ACTIVE 2121 #define IMG_FONT_MENU_2 2122 #define IMG_FONT_MENU_2_ACTIVE 2123 #define IMG_FONT_TEXT_1 2124 #define IMG_FONT_TEXT_1_MAIN 2125 #define IMG_FONT_TEXT_1_LEVELS 2126 #define IMG_FONT_TEXT_1_LEVELNR 2127 #define IMG_FONT_TEXT_1_SETUP 2128 #define IMG_FONT_TEXT_1_PREVIEW 2129 #define IMG_FONT_TEXT_1_SCORES 2130 #define IMG_FONT_TEXT_1_ACTIVE_SCORES 2131 #define IMG_FONT_TEXT_1_PANEL 2132 #define IMG_FONT_TEXT_1_DOOR 2133 #define IMG_FONT_TEXT_2 2134 #define IMG_FONT_TEXT_2_MAIN 2135 #define IMG_FONT_TEXT_2_LEVELS 2136 #define IMG_FONT_TEXT_2_LEVELNR 2137 #define IMG_FONT_TEXT_2_SETUP 2138 #define IMG_FONT_TEXT_2_PREVIEW 2139 #define IMG_FONT_TEXT_2_SCORES 2140 #define IMG_FONT_TEXT_2_ACTIVE_SCORES 2141 #define IMG_FONT_TEXT_3 2142 #define IMG_FONT_TEXT_3_LEVELS 2143 #define IMG_FONT_TEXT_3_LEVELNR 2144 #define IMG_FONT_TEXT_3_SETUP 2145 #define IMG_FONT_TEXT_3_PREVIEW 2146 #define IMG_FONT_TEXT_3_SCORES 2147 #define IMG_FONT_TEXT_3_ACTIVE_SCORES 2148 #define IMG_FONT_TEXT_4 2149 #define IMG_FONT_TEXT_4_MAIN 2150 #define IMG_FONT_TEXT_4_LEVELS 2151 #define IMG_FONT_TEXT_4_LEVELNR 2152 #define IMG_FONT_TEXT_4_SETUP 2153 #define IMG_FONT_TEXT_4_SCORES 2154 #define IMG_FONT_TEXT_4_ACTIVE_SCORES 2155 #define IMG_FONT_ENVELOPE_1 2156 #define IMG_FONT_ENVELOPE_2 2157 #define IMG_FONT_ENVELOPE_3 2158 #define IMG_FONT_ENVELOPE_4 2159 #define IMG_FONT_REQUEST 2160 #define IMG_FONT_INPUT_1 2161 #define IMG_FONT_INPUT_1_MAIN 2162 #define IMG_FONT_INPUT_1_ACTIVE 2163 #define IMG_FONT_INPUT_1_ACTIVE_MAIN 2164 #define IMG_FONT_INPUT_1_ACTIVE_SETUP 2165 #define IMG_FONT_INPUT_2 2166 #define IMG_FONT_INPUT_2_ACTIVE 2167 #define IMG_FONT_OPTION_OFF 2168 #define IMG_FONT_OPTION_OFF_NARROW 2169 #define IMG_FONT_OPTION_ON 2170 #define IMG_FONT_OPTION_ON_NARROW 2171 #define IMG_FONT_VALUE_1 2172 #define IMG_FONT_VALUE_2 2173 #define IMG_FONT_VALUE_OLD 2174 #define IMG_FONT_VALUE_NARROW 2175 #define IMG_FONT_LEVEL_NUMBER 2176 #define IMG_FONT_LEVEL_NUMBER_ACTIVE 2177 #define IMG_FONT_TAPE_RECORDER 2178 #define IMG_FONT_GAME_INFO 2179 #define IMG_FONT_INFO_ELEMENTS 2180 #define IMG_FONT_INFO_LEVELSET 2181 #define IMG_EDITOR_ELEMENT_BORDER 2182 #define IMG_EDITOR_ELEMENT_BORDER_INPUT 2183 #define IMG_EDITOR_COUNTER_DOWN 2184 #define IMG_EDITOR_COUNTER_UP 2185 #define IMG_EDITOR_COUNTER_INPUT 2186 #define IMG_EDITOR_SELECTBOX_INPUT 2187 #define IMG_EDITOR_SELECTBOX_BUTTON 2188 #define IMG_EDITOR_CHECKBOX 2189 #define IMG_EDITOR_RADIOBUTTON 2190 #define IMG_EDITOR_STICKYBUTTON 2191 #define IMG_EDITOR_TABBUTTON 2192 #define IMG_EDITOR_TEXTBUTTON 2193 #define IMG_EDITOR_INPUT_TEXT 2194 #define IMG_EDITOR_INPUT_TEXTAREA 2195 #define IMG_EDITOR_CASCADE_LIST 2196 #define IMG_EDITOR_CASCADE_LIST_ACTIVE 2197 #define IMG_EDITOR_PALETTE_BUTTON 2198 #define IMG_EDITOR_PALETTE_SCROLL_UP 2199 #define IMG_EDITOR_PALETTE_SCROLL_DOWN 2200 #define IMG_EDITOR_PALETTE_SCROLLBAR 2201 #define IMG_EDITOR_PLAYFIELD_SCROLL_UP 2202 #define IMG_EDITOR_PLAYFIELD_SCROLL_DOWN 2203 #define IMG_EDITOR_PLAYFIELD_SCROLL_LEFT 2204 #define IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT 2205 #define IMG_EDITOR_PLAYFIELD_SCROLLBAR 2206 #define IMG_GFX_EDITOR_BUTTON_PREV_LEVEL 2207 #define IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL 2208 #define IMG_GFX_EDITOR_BUTTON_PROPERTIES 2209 #define IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT 2210 #define IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE 2211 #define IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT 2212 #define IMG_GFX_EDITOR_BUTTON_PALETTE 2213 #define IMG_EDITOR_NO_TOOLBOX_BUTTON 2214 #define IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE 2215 #define IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED 2216 #define IMG_GFX_EDITOR_BUTTON_DRAW_LINE 2217 #define IMG_GFX_EDITOR_BUTTON_DRAW_ARC 2218 #define IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE 2219 #define IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX 2220 #define IMG_GFX_EDITOR_BUTTON_ROTATE_UP 2221 #define IMG_GFX_EDITOR_BUTTON_DRAW_TEXT 2222 #define IMG_GFX_EDITOR_BUTTON_FLOOD_FILL 2223 #define IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT 2224 #define IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL 2225 #define IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT 2226 #define IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM 2227 #define IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH 2228 #define IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN 2229 #define IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT 2230 #define IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM 2231 #define IMG_GFX_EDITOR_BUTTON_CE_COPY_TO 2232 #define IMG_GFX_EDITOR_BUTTON_CE_SWAP 2233 #define IMG_GFX_EDITOR_BUTTON_CE_COPY 2234 #define IMG_GFX_EDITOR_BUTTON_CE_PASTE 2235 #define IMG_GFX_EDITOR_BUTTON_CP_COPY 2236 #define IMG_GFX_EDITOR_BUTTON_CP_PASTE 2237 #define IMG_GFX_EDITOR_BUTTON_UNDO 2238 #define IMG_GFX_EDITOR_BUTTON_CONF 2239 #define IMG_GFX_EDITOR_BUTTON_SAVE 2240 #define IMG_GFX_EDITOR_BUTTON_CLEAR 2241 #define IMG_GFX_EDITOR_BUTTON_TEST 2242 #define IMG_GFX_EDITOR_BUTTON_EXIT 2243 #define IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER 2244 #define IMG_GLOBAL_BORDER 2245 #define IMG_GLOBAL_BORDER_MAIN 2246 #define IMG_GLOBAL_BORDER_SCORES 2247 #define IMG_GLOBAL_BORDER_EDITOR 2248 #define IMG_GLOBAL_BORDER_PLAYING 2249 #define IMG_GLOBAL_DOOR 2250 #define IMG_GLOBAL_BUSY 2251 #define IMG_GLOBAL_TILE_CURSOR 2252 #define IMG_BACKGROUND 2253 #define IMG_BACKGROUND_TITLE_INITIAL 2254 #define IMG_BACKGROUND_TITLE 2255 #define IMG_BACKGROUND_MAIN 2256 #define IMG_BACKGROUND_LEVELS 2257 #define IMG_BACKGROUND_LEVELNR 2258 #define IMG_BACKGROUND_SCORES 2259 #define IMG_BACKGROUND_EDITOR 2260 #define IMG_BACKGROUND_INFO 2261 #define IMG_BACKGROUND_INFO_ELEMENTS 2262 #define IMG_BACKGROUND_INFO_MUSIC 2263 #define IMG_BACKGROUND_INFO_CREDITS 2264 #define IMG_BACKGROUND_INFO_PROGRAM 2265 #define IMG_BACKGROUND_INFO_VERSION 2266 #define IMG_BACKGROUND_INFO_LEVELSET 2267 #define IMG_BACKGROUND_SETUP 2268 #define IMG_BACKGROUND_PLAYING 2269 #define IMG_BACKGROUND_DOOR 2270 #define IMG_BACKGROUND_TAPE 2271 #define IMG_BACKGROUND_PANEL 2272 #define IMG_BACKGROUND_PALETTE 2273 #define IMG_BACKGROUND_TOOLBOX 2274 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_1 2275 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_2 2276 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_3 2277 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_4 2278 #define IMG_BACKGROUND_TITLESCREEN_INITIAL_5 2279 #define IMG_BACKGROUND_TITLESCREEN_1 2280 #define IMG_BACKGROUND_TITLESCREEN_2 2281 #define IMG_BACKGROUND_TITLESCREEN_3 2282 #define IMG_BACKGROUND_TITLESCREEN_4 2283 #define IMG_BACKGROUND_TITLESCREEN_5 2284 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 2285 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2 2286 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3 2287 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4 2288 #define IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5 2289 #define IMG_BACKGROUND_TITLEMESSAGE_1 2290 #define IMG_BACKGROUND_TITLEMESSAGE_2 2291 #define IMG_BACKGROUND_TITLEMESSAGE_3 2292 #define IMG_BACKGROUND_TITLEMESSAGE_4 2293 #define IMG_BACKGROUND_TITLEMESSAGE_5 2294 #define IMG_BACKGROUND_ENVELOPE_1 2295 #define IMG_BACKGROUND_ENVELOPE_2 2296 #define IMG_BACKGROUND_ENVELOPE_3 2297 #define IMG_BACKGROUND_ENVELOPE_4 2298 #define IMG_BACKGROUND_REQUEST 2299 #define IMG_TITLESCREEN_INITIAL_1 2300 #define IMG_TITLESCREEN_INITIAL_2 2301 #define IMG_TITLESCREEN_INITIAL_3 2302 #define IMG_TITLESCREEN_INITIAL_4 2303 #define IMG_TITLESCREEN_INITIAL_5 2304 #define IMG_TITLESCREEN_1 2305 #define IMG_TITLESCREEN_2 2306 #define IMG_TITLESCREEN_3 2307 #define IMG_TITLESCREEN_4 2308 #define IMG_TITLESCREEN_5 2309 #define IMG_GFX_DOOR_1_PART_1 2310 #define IMG_GFX_DOOR_1_PART_2 2311 #define IMG_GFX_DOOR_1_PART_3 2312 #define IMG_GFX_DOOR_1_PART_4 2313 #define IMG_GFX_DOOR_1_PART_5 2314 #define IMG_GFX_DOOR_1_PART_6 2315 #define IMG_GFX_DOOR_1_PART_7 2316 #define IMG_GFX_DOOR_1_PART_8 2317 #define IMG_GFX_DOOR_2_PART_1 2318 #define IMG_GFX_DOOR_2_PART_2 2319 #define IMG_GFX_DOOR_2_PART_3 2320 #define IMG_GFX_DOOR_2_PART_4 2321 #define IMG_GFX_DOOR_2_PART_5 2322 #define IMG_GFX_DOOR_2_PART_6 2323 #define IMG_GFX_DOOR_2_PART_7 2324 #define IMG_GFX_DOOR_2_PART_8 2325 #define IMG_DOOR_2_TOP_BORDER_CORRECTION 2326 #define IMG_LAST_IMAGE_ENTRY_BUG 2327 #define NUM_IMAGE_FILES 2328 #endif /* CONF_GFX_H */ mirrormagic-3.0.0/src/anim.c0000644000175000017500000012330313263212010015202 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // anim.c // ============================================================================ #include "libgame/libgame.h" #include "anim.h" #include "main.h" #include "tools.h" /* values for global toon animation definition */ #define NUM_GLOBAL_TOON_ANIMS 1 #define NUM_GLOBAL_TOON_PARTS MAX_NUM_TOONS /* values for global animation definition (including toons) */ #define NUM_GLOBAL_ANIMS_AND_TOONS (NUM_GLOBAL_ANIMS + \ NUM_GLOBAL_TOON_ANIMS) #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL, \ NUM_GLOBAL_TOON_PARTS) #define ANIM_CLASS_BIT_TITLE_INITIAL 0 #define ANIM_CLASS_BIT_TITLE 1 #define ANIM_CLASS_BIT_MAIN 2 #define ANIM_CLASS_BIT_SCORES 3 #define ANIM_CLASS_BIT_SUBMENU 4 #define ANIM_CLASS_BIT_MENU 5 #define ANIM_CLASS_BIT_TOONS 6 #define NUM_ANIM_CLASSES 7 #define ANIM_CLASS_NONE 0 #define ANIM_CLASS_TITLE_INITIAL (1 << ANIM_CLASS_BIT_TITLE_INITIAL) #define ANIM_CLASS_TITLE (1 << ANIM_CLASS_BIT_TITLE) #define ANIM_CLASS_MAIN (1 << ANIM_CLASS_BIT_MAIN) #define ANIM_CLASS_SCORES (1 << ANIM_CLASS_BIT_SCORES) #define ANIM_CLASS_SUBMENU (1 << ANIM_CLASS_BIT_SUBMENU) #define ANIM_CLASS_MENU (1 << ANIM_CLASS_BIT_MENU) #define ANIM_CLASS_TOONS (1 << ANIM_CLASS_BIT_TOONS) #define ANIM_CLASS_TOONS_SCORES (ANIM_CLASS_TOONS | \ ANIM_CLASS_SCORES) #define ANIM_CLASS_TOONS_MENU_MAIN (ANIM_CLASS_TOONS | \ ANIM_CLASS_MENU | \ ANIM_CLASS_MAIN) #define ANIM_CLASS_TOONS_MENU_SUBMENU (ANIM_CLASS_TOONS | \ ANIM_CLASS_MENU | \ ANIM_CLASS_SUBMENU) /* values for global animation states */ #define ANIM_STATE_INACTIVE 0 #define ANIM_STATE_RESTART (1 << 0) #define ANIM_STATE_WAITING (1 << 1) #define ANIM_STATE_RUNNING (1 << 2) /* values for global animation control */ #define ANIM_NO_ACTION 0 #define ANIM_START 1 #define ANIM_CONTINUE 2 #define ANIM_STOP 3 struct GlobalAnimPartControlInfo { int old_nr; // position before mapping animation parts linearly int old_anim_nr; // position before mapping animations linearly int nr; int anim_nr; int mode_nr; boolean is_base; // animation part is base/main/default animation part int sound; int music; int graphic; struct GraphicInfo graphic_info; struct GraphicInfo control_info; int viewport_x; int viewport_y; int viewport_width; int viewport_height; int x, y; int step_xoffset, step_yoffset; unsigned int initial_anim_sync_frame; unsigned int step_delay, step_delay_value; int init_delay_counter; int anim_delay_counter; int post_delay_counter; boolean init_event_state; boolean anim_event_state; boolean clickable; boolean clicked; int drawing_stage; int state; int last_anim_status; }; struct GlobalAnimMainControlInfo { struct GlobalAnimPartControlInfo base; struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS]; int nr; int mode_nr; struct GraphicInfo control_info; int num_parts; // number of animation parts, but without base part int num_parts_all; // number of animation parts, including base part int part_counter; int active_part_nr; boolean has_base; // animation has base/main/default animation part int last_x, last_y; int init_delay_counter; int state; int last_state, last_active_part_nr; }; struct GlobalAnimControlInfo { struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS]; int nr; int num_anims; }; struct GameModeAnimClass { int game_mode; int class; } game_mode_anim_classes_list[] = { { GAME_MODE_TITLE_INITIAL_1, ANIM_CLASS_TITLE_INITIAL }, { GAME_MODE_TITLE_INITIAL_2, ANIM_CLASS_TITLE_INITIAL }, { GAME_MODE_TITLE_INITIAL_3, ANIM_CLASS_TITLE_INITIAL }, { GAME_MODE_TITLE_INITIAL_4, ANIM_CLASS_TITLE_INITIAL }, { GAME_MODE_TITLE_INITIAL_5, ANIM_CLASS_TITLE_INITIAL }, { GAME_MODE_TITLE_1, ANIM_CLASS_TITLE }, { GAME_MODE_TITLE_2, ANIM_CLASS_TITLE }, { GAME_MODE_TITLE_3, ANIM_CLASS_TITLE }, { GAME_MODE_TITLE_4, ANIM_CLASS_TITLE }, { GAME_MODE_TITLE_5, ANIM_CLASS_TITLE }, { GAME_MODE_LEVELS, ANIM_CLASS_TOONS_MENU_SUBMENU }, { GAME_MODE_LEVELNR, ANIM_CLASS_TOONS_MENU_SUBMENU }, { GAME_MODE_INFO, ANIM_CLASS_TOONS_MENU_SUBMENU }, { GAME_MODE_SETUP, ANIM_CLASS_TOONS_MENU_SUBMENU }, { GAME_MODE_PSEUDO_MAINONLY, ANIM_CLASS_TOONS_MENU_MAIN }, { GAME_MODE_PSEUDO_TYPENAME, ANIM_CLASS_TOONS_MENU_MAIN }, { GAME_MODE_PSEUDO_SCORESOLD, ANIM_CLASS_TOONS_SCORES }, { GAME_MODE_PSEUDO_SCORESNEW, ANIM_CLASS_TOONS_SCORES }, { -1, -1 } }; struct AnimClassGameMode { int class_bit; int game_mode; } anim_class_game_modes_list[] = { { ANIM_CLASS_BIT_TITLE_INITIAL, GAME_MODE_TITLE_INITIAL }, { ANIM_CLASS_BIT_TITLE, GAME_MODE_TITLE }, { ANIM_CLASS_BIT_MAIN, GAME_MODE_MAIN }, { ANIM_CLASS_BIT_SCORES, GAME_MODE_SCORES }, { ANIM_CLASS_BIT_SUBMENU, GAME_MODE_PSEUDO_SUBMENU }, { ANIM_CLASS_BIT_MENU, GAME_MODE_PSEUDO_MENU }, { ANIM_CLASS_BIT_TOONS, GAME_MODE_PSEUDO_TOONS }, { -1, -1 } }; /* forward declaration for internal use */ static void HandleGlobalAnim(int, int); static void DoAnimationExt(void); static void ResetGlobalAnim_Clickable(); static void ResetGlobalAnim_Clicked(); static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES]; static unsigned int anim_sync_frame = 0; static int game_mode_anim_classes[NUM_GAME_MODES]; static int anim_class_game_modes[NUM_ANIM_CLASSES]; static int anim_status_last_before_fading = GAME_MODE_DEFAULT; static int anim_status_last = GAME_MODE_DEFAULT; static int anim_classes_last = ANIM_CLASS_NONE; static boolean drawing_to_fading_buffer = FALSE; /* ========================================================================= */ /* generic animation frame calculation */ /* ========================================================================= */ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, int sync_frame) { int frame = 0; sync_frame += start_frame * delay; if (mode & ANIM_LOOP) /* looping animation */ { frame = (sync_frame % (delay * num_frames)) / delay; } else if (mode & ANIM_LINEAR) /* linear (non-looping) animation */ { frame = sync_frame / delay; if (frame > num_frames - 1) frame = num_frames - 1; } else if (mode & ANIM_PINGPONG) /* oscillate (border frames once) */ { int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1); frame = (sync_frame % (delay * max_anim_frames)) / delay; frame = (frame < num_frames ? frame : max_anim_frames - frame); } else if (mode & ANIM_PINGPONG2) /* oscillate (border frames twice) */ { int max_anim_frames = 2 * num_frames; frame = (sync_frame % (delay * max_anim_frames)) / delay; frame = (frame < num_frames ? frame : max_anim_frames - frame - 1); } else if (mode & ANIM_RANDOM) /* play frames in random order */ { /* note: expect different frames for the same delay cycle! */ if (gfx.anim_random_frame < 0) frame = GetSimpleRandom(num_frames); else frame = gfx.anim_random_frame % num_frames; } else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY)) { frame = sync_frame % num_frames; } if (mode & ANIM_REVERSE) /* use reverse animation direction */ frame = num_frames - frame - 1; return frame; } /* ========================================================================= */ /* global animation functions */ /* ========================================================================= */ static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim) { struct GraphicInfo *c = &anim->control_info; int last_anim_random_frame = gfx.anim_random_frame; int part_nr; gfx.anim_random_frame = -1; // (use simple, ad-hoc random numbers) part_nr = getAnimationFrame(anim->num_parts, 1, c->anim_mode, c->anim_start_frame, anim->part_counter); gfx.anim_random_frame = last_anim_random_frame; return part_nr; } static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2) { const struct GlobalAnimPartControlInfo *o1 = (struct GlobalAnimPartControlInfo *)obj1; const struct GlobalAnimPartControlInfo *o2 = (struct GlobalAnimPartControlInfo *)obj2; int compare_result; if (o1->control_info.draw_order != o2->control_info.draw_order) compare_result = o1->control_info.draw_order - o2->control_info.draw_order; else compare_result = o1->nr - o2->nr; return compare_result; } static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2) { const struct GlobalAnimMainControlInfo *o1 = (struct GlobalAnimMainControlInfo *)obj1; const struct GlobalAnimMainControlInfo *o2 = (struct GlobalAnimMainControlInfo *)obj2; int compare_result; if (o1->control_info.draw_order != o2->control_info.draw_order) compare_result = o1->control_info.draw_order - o2->control_info.draw_order; else compare_result = o1->nr - o2->nr; return compare_result; } static void InitToonControls() { int mode_nr_toons = GAME_MODE_PSEUDO_TOONS; struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons]; struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims]; int mode_nr, anim_nr, part_nr; int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT; int num_toons = MAX_NUM_TOONS; int i; if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS) num_toons = global.num_toons; mode_nr = mode_nr_toons; anim_nr = ctrl->num_anims; anim->nr = anim_nr; anim->mode_nr = mode_nr; anim->control_info = graphic_info[control]; anim->num_parts = 0; anim->num_parts_all = 0; anim->part_counter = 0; anim->active_part_nr = 0; anim->has_base = FALSE; anim->last_x = POS_OFFSCREEN; anim->last_y = POS_OFFSCREEN; anim->init_delay_counter = 0; anim->state = ANIM_STATE_INACTIVE; part_nr = 0; for (i = 0; i < num_toons; i++) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; int sound = SND_UNDEFINED; int music = MUS_UNDEFINED; int graphic = IMG_TOON_1 + i; int control = graphic; part->nr = part_nr; part->anim_nr = anim_nr; part->mode_nr = mode_nr; part->is_base = FALSE; part->sound = sound; part->music = music; part->graphic = graphic; part->graphic_info = graphic_info[graphic]; part->control_info = graphic_info[control]; part->graphic_info.anim_delay *= part->graphic_info.step_delay; part->control_info.init_delay_fixed = 0; part->control_info.init_delay_random = 150; part->control_info.x = ARG_UNDEFINED_VALUE; part->control_info.y = ARG_UNDEFINED_VALUE; part->initial_anim_sync_frame = 0; part->step_delay = 0; part->step_delay_value = graphic_info[control].step_delay; part->state = ANIM_STATE_INACTIVE; part->last_anim_status = -1; anim->num_parts++; anim->num_parts_all++; part_nr++; } ctrl->num_anims++; } void InitGlobalAnimControls() { int i, m, a, p; int mode_nr, anim_nr, part_nr; int sound, music, graphic, control; anim_sync_frame = 0; for (m = 0; m < NUM_GAME_MODES; m++) { mode_nr = m; struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; ctrl->nr = mode_nr; ctrl->num_anims = 0; anim_nr = 0; for (a = 0; a < NUM_GLOBAL_ANIMS; a++) { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a; control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m]; // if no base animation parameters defined, use default values if (control == IMG_UNDEFINED) control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT; anim->nr = anim_nr; anim->mode_nr = mode_nr; anim->control_info = graphic_info[control]; anim->num_parts = 0; anim->num_parts_all = 0; anim->part_counter = 0; anim->active_part_nr = 0; anim->has_base = FALSE; anim->last_x = POS_OFFSCREEN; anim->last_y = POS_OFFSCREEN; anim->init_delay_counter = 0; anim->state = ANIM_STATE_INACTIVE; part_nr = 0; for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; sound = global_anim_info[a].sound[p][m]; music = global_anim_info[a].music[p][m]; graphic = global_anim_info[a].graphic[p][m]; control = global_anim_info[ctrl_id].graphic[p][m]; if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL || control == IMG_UNDEFINED) continue; #if 0 printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n", m, a, p, mode_nr, anim_nr, part_nr, control); #endif #if 0 printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n", m, a, p, mode_nr, anim_nr, part_nr, sound); #endif part->old_nr = p; part->old_anim_nr = a; part->nr = part_nr; part->anim_nr = anim_nr; part->mode_nr = mode_nr; part->sound = sound; part->music = music; part->graphic = graphic; part->graphic_info = graphic_info[graphic]; part->control_info = graphic_info[control]; part->initial_anim_sync_frame = 0; part->step_delay = 0; part->step_delay_value = graphic_info[control].step_delay; part->state = ANIM_STATE_INACTIVE; part->last_anim_status = -1; anim->num_parts_all++; if (p < GLOBAL_ANIM_ID_PART_BASE) { part->is_base = FALSE; anim->num_parts++; part_nr++; } else { part->is_base = TRUE; anim->base = *part; anim->has_base = TRUE; } } if (anim->num_parts > 0 || anim->has_base) { ctrl->num_anims++; anim_nr++; } } } InitToonControls(); /* sort all animations according to draw_order and animation number */ for (m = 0; m < NUM_GAME_MODES; m++) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m]; /* sort all main animations for this game mode */ qsort(ctrl->anim, ctrl->num_anims, sizeof(struct GlobalAnimMainControlInfo), compareGlobalAnimMainControlInfo); for (a = 0; a < ctrl->num_anims; a++) { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a]; /* sort all animation parts for this main animation */ qsort(anim->part, anim->num_parts, sizeof(struct GlobalAnimPartControlInfo), compareGlobalAnimPartControlInfo); } } for (i = 0; i < NUM_GAME_MODES; i++) game_mode_anim_classes[i] = ANIM_CLASS_NONE; for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++) game_mode_anim_classes[game_mode_anim_classes_list[i].game_mode] = game_mode_anim_classes_list[i].class; for (i = 0; i < NUM_ANIM_CLASSES; i++) anim_class_game_modes[i] = GAME_MODE_DEFAULT; for (i = 0; anim_class_game_modes_list[i].game_mode != -1; i++) anim_class_game_modes[anim_class_game_modes_list[i].class_bit] = anim_class_game_modes_list[i].game_mode; anim_status_last_before_fading = GAME_MODE_LOADING; anim_status_last = GAME_MODE_LOADING; anim_classes_last = ANIM_CLASS_NONE; } void InitGlobalAnimations() { InitGlobalAnimControls(); } void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) { Bitmap *fade_bitmap = (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source : drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL); int game_mode_anim_action[NUM_GAME_MODES]; int mode_nr; if (!setup.toons) return; if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 && drawing_target == DRAW_TO_SCREEN) DoAnimationExt(); // always start with reliable default values (no animation actions) for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) game_mode_anim_action[mode_nr] = ANIM_NO_ACTION; if (global.anim_status != anim_status_last) { boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING); boolean after_fading = (anim_status_last == GAME_MODE_PSEUDO_FADING); int anim_classes_next = game_mode_anim_classes[global.anim_status_next]; int i; if (drawing_target == DRAW_TO_FADE_TARGET) after_fading = TRUE; // special case: changing from/to this screen is done without fading if (global.anim_status == GAME_MODE_PSEUDO_TYPENAME || anim_status_last == GAME_MODE_PSEUDO_TYPENAME) after_fading = TRUE; // ---------- part 1 ------------------------------------------------------ // start or stop global animations by change of game mode // (special handling of animations for "current screen" and "all screens") if (global.anim_status_next != anim_status_last_before_fading) { // stop animations for last screen before fading to new screen game_mode_anim_action[anim_status_last] = ANIM_STOP; // start animations for current screen after fading to new screen game_mode_anim_action[global.anim_status] = ANIM_START; } // start animations for all screens after loading new artwork set if (anim_status_last == GAME_MODE_LOADING) game_mode_anim_action[GAME_MODE_DEFAULT] = ANIM_START; // ---------- part 2 ------------------------------------------------------ // start or stop global animations by change of animation class // (generic handling of animations for "class of screens") for (i = 0; i < NUM_ANIM_CLASSES; i++) { int anim_class_check = (1 << i); int anim_class_game_mode = anim_class_game_modes[i]; int anim_class_last = anim_classes_last & anim_class_check; int anim_class_next = anim_classes_next & anim_class_check; // stop animations for changed screen class before fading to new screen if (before_fading && anim_class_last && !anim_class_next) game_mode_anim_action[anim_class_game_mode] = ANIM_STOP; // start animations for changed screen class after fading to new screen if (after_fading && !anim_class_last && anim_class_next) game_mode_anim_action[anim_class_game_mode] = ANIM_START; } if (drawing_target == DRAW_TO_SCREEN) { if (after_fading) { anim_classes_last = anim_classes_next; anim_status_last_before_fading = global.anim_status; } anim_status_last = global.anim_status; // start or stop animations determined to be started or stopped above for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) if (game_mode_anim_action[mode_nr] != ANIM_NO_ACTION) HandleGlobalAnim(game_mode_anim_action[mode_nr], mode_nr); } else if (drawing_target == DRAW_TO_FADE_TARGET) { drawing_to_fading_buffer = TRUE; // start animations determined to be (temporary) started above for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) if (game_mode_anim_action[mode_nr] == ANIM_START) HandleGlobalAnim(ANIM_START, mode_nr); } } if (global.anim_status == GAME_MODE_LOADING) return; for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; int anim_nr; // when preparing source fading buffer, only draw animations to be stopped if (drawing_target == DRAW_TO_FADE_SOURCE && game_mode_anim_action[mode_nr] != ANIM_STOP) continue; // when preparing target fading buffer, only draw animations to be started if (drawing_target == DRAW_TO_FADE_TARGET && game_mode_anim_action[mode_nr] != ANIM_START) continue; #if 0 if (mode_nr != GFX_SPECIAL_ARG_DEFAULT && mode_nr != game_status) continue; #endif for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++) { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; struct GraphicInfo *c = &anim->control_info; int part_first, part_last; int part_nr; if (!(anim->state & ANIM_STATE_RUNNING)) continue; part_first = part_last = anim->active_part_nr; if (c->anim_mode & ANIM_ALL || anim->num_parts == 0) { int num_parts = anim->num_parts + (anim->has_base ? 1 : 0); part_first = 0; part_last = num_parts - 1; } for (part_nr = part_first; part_nr <= part_last; part_nr++) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; struct GraphicInfo *g = &part->graphic_info; Bitmap *src_bitmap; int src_x, src_y; int width = g->width; int height = g->height; int dst_x = part->x; int dst_y = part->y; int cut_x = 0; int cut_y = 0; int sync_frame; int frame; void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) = (g->draw_masked ? BlitBitmapMasked : BlitBitmap); void (*blit_screen)(Bitmap *, int, int, int, int, int, int) = (g->draw_masked ? BlitToScreenMasked : BlitToScreen); if (!(part->state & ANIM_STATE_RUNNING)) continue; if (part->drawing_stage != drawing_stage) continue; if (part->x < 0) { dst_x = 0; width += part->x; cut_x = -part->x; } else if (part->x > part->viewport_width - g->width) width -= (part->x - (part->viewport_width - g->width)); if (part->y < 0) { dst_y = 0; height += part->y; cut_y = -part->y; } else if (part->y > part->viewport_height - g->height) height -= (part->y - (part->viewport_height - g->height)); if (width <= 0 || height <= 0) continue; dst_x += part->viewport_x; dst_y += part->viewport_y; sync_frame = anim_sync_frame - part->initial_anim_sync_frame; frame = getAnimationFrame(g->anim_frames, g->anim_delay, g->anim_mode, g->anim_start_frame, sync_frame); getFixedGraphicSource(part->graphic, frame, &src_bitmap, &src_x, &src_y); src_x += cut_x; src_y += cut_y; if (drawing_target == DRAW_TO_SCREEN) blit_screen(src_bitmap, src_x, src_y, width, height, dst_x, dst_y); else blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height, dst_x, dst_y); } } } if (drawing_target == DRAW_TO_FADE_TARGET) { // stop animations determined to be (temporary) started above for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) if (game_mode_anim_action[mode_nr] == ANIM_START) HandleGlobalAnim(ANIM_STOP, mode_nr); drawing_to_fading_buffer = FALSE; } } void DrawGlobalAnimations(int drawing_target, int drawing_stage) { if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1) ResetGlobalAnim_Clickable(); DrawGlobalAnimationsExt(drawing_target, drawing_stage); if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2) ResetGlobalAnim_Clicked(); } boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part) { int viewport_x; int viewport_y; int viewport_width; int viewport_height; boolean changed = FALSE; if (part->last_anim_status == global.anim_status) return FALSE; part->last_anim_status = global.anim_status; part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1; if (part->control_info.class == get_hash_from_key("window") || part->control_info.class == get_hash_from_key("border")) { viewport_x = 0; viewport_y = 0; viewport_width = WIN_XSIZE; viewport_height = WIN_YSIZE; part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2; } else if (part->control_info.class == get_hash_from_key("door_1")) { viewport_x = DX; viewport_y = DY; viewport_width = DXSIZE; viewport_height = DYSIZE; } else if (part->control_info.class == get_hash_from_key("door_2")) { viewport_x = VX; viewport_y = VY; viewport_width = VXSIZE; viewport_height = VYSIZE; } else // default: "playfield" { viewport_x = REAL_SX; viewport_y = REAL_SY; viewport_width = FULL_SXSIZE; viewport_height = FULL_SYSIZE; } if (viewport_x != part->viewport_x || viewport_y != part->viewport_y || viewport_width != part->viewport_width || viewport_height != part->viewport_height) { part->viewport_x = viewport_x; part->viewport_y = viewport_y; part->viewport_width = viewport_width; part->viewport_height = viewport_height; changed = TRUE; } return changed; } static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part) { int sound = part->sound; if (sound == SND_UNDEFINED) return; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || (!setup.sound_loops && IS_LOOP_SOUND(sound))) return; // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!! if (IS_LOOP_SOUND(sound)) PlaySoundLoop(sound); else PlaySound(sound); #if 0 printf("::: PLAY SOUND %d.%d.%d: %d\n", part->anim_nr, part->nr, part->mode_nr, sound); #endif } static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part) { int sound = part->sound; if (sound == SND_UNDEFINED) return; StopSound(sound); #if 0 printf("::: STOP SOUND %d.%d.%d: %d\n", part->anim_nr, part->nr, part->mode_nr, sound); #endif } static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part) { int music = part->music; if (music == MUS_UNDEFINED) return; if (!setup.sound_music) return; PlayMusic(music); #if 0 printf("::: PLAY MUSIC %d.%d.%d: %d\n", part->anim_nr, part->nr, part->mode_nr, music); #endif } static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part) { int music = part->music; if (music == MUS_UNDEFINED) return; StopMusic(); #if 0 printf("::: STOP MUSIC %d.%d.%d: %d\n", part->anim_nr, part->nr, part->mode_nr, music); #endif } static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part) { // when drawing animations to fading buffer, do not play sounds or music if (drawing_to_fading_buffer) return; PlayGlobalAnimSound(part); PlayGlobalAnimMusic(part); } static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part) { StopGlobalAnimSound(part); StopGlobalAnimMusic(part); } static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask) { struct GraphicInfo *c = &part->control_info; int trigger_mask = ANIM_EVENT_ANIM_MASK | ANIM_EVENT_PART_MASK; int mask_anim_only = mask & ANIM_EVENT_ANIM_MASK; if (mask & ANIM_EVENT_ANY) return (c->init_event & ANIM_EVENT_ANY || c->anim_event & ANIM_EVENT_ANY); else if (mask & ANIM_EVENT_SELF) return (c->init_event & ANIM_EVENT_SELF || c->anim_event & ANIM_EVENT_SELF); else return ((c->init_event & trigger_mask) == mask || (c->anim_event & trigger_mask) == mask || (c->init_event & trigger_mask) == mask_anim_only || (c->anim_event & trigger_mask) == mask_anim_only); } static boolean isClickedPart(struct GlobalAnimPartControlInfo *part, int mx, int my, boolean clicked) { struct GraphicInfo *g = &part->graphic_info; int part_x = part->viewport_x + part->x; int part_y = part->viewport_y + part->y; int part_width = g->width; int part_height = g->height; // check if mouse click was detected at all if (!clicked) return FALSE; // check if mouse click is inside the animation part's viewport if (mx < part->viewport_x || mx >= part->viewport_x + part->viewport_width || my < part->viewport_y || my >= part->viewport_y + part->viewport_height) return FALSE; // check if mouse click is inside the animation part's graphic if (mx < part_x || mx >= part_x + part_width || my < part_y || my >= part_y + part_height) return FALSE; return TRUE; } int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr]; struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr]; struct GraphicInfo *g = &part->graphic_info; struct GraphicInfo *c = &part->control_info; boolean viewport_changed = SetGlobalAnimPart_Viewport(part); if (viewport_changed) state |= ANIM_STATE_RESTART; if (state & ANIM_STATE_RESTART) { // when drawing animations to fading buffer, only start fixed animations if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE || c->y == ARG_UNDEFINED_VALUE)) return ANIM_STATE_INACTIVE; ResetDelayCounterExt(&part->step_delay, anim_sync_frame); part->init_delay_counter = (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random)); part->anim_delay_counter = (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random)); part->init_event_state = c->init_event; part->anim_event_state = c->anim_event; part->initial_anim_sync_frame = (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter); if (c->direction & MV_HORIZONTAL) { int pos_bottom = part->viewport_height - g->height; if (c->position == POS_TOP) part->y = 0; else if (c->position == POS_UPPER) part->y = GetSimpleRandom(pos_bottom / 2); else if (c->position == POS_MIDDLE) part->y = pos_bottom / 2; else if (c->position == POS_LOWER) part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2); else if (c->position == POS_BOTTOM) part->y = pos_bottom; else part->y = GetSimpleRandom(pos_bottom); if (c->direction == MV_RIGHT) { part->step_xoffset = c->step_offset; part->x = -g->width + part->step_xoffset; } else { part->step_xoffset = -c->step_offset; part->x = part->viewport_width + part->step_xoffset; } part->step_yoffset = 0; } else if (c->direction & MV_VERTICAL) { int pos_right = part->viewport_width - g->width; if (c->position == POS_LEFT) part->x = 0; else if (c->position == POS_RIGHT) part->x = pos_right; else part->x = GetSimpleRandom(pos_right); if (c->direction == MV_DOWN) { part->step_yoffset = c->step_offset; part->y = -g->height + part->step_yoffset; } else { part->step_yoffset = -c->step_offset; part->y = part->viewport_height + part->step_yoffset; } part->step_xoffset = 0; } else { part->x = 0; part->y = 0; part->step_xoffset = 0; part->step_yoffset = 0; } if (c->x != ARG_UNDEFINED_VALUE) part->x = c->x; if (c->y != ARG_UNDEFINED_VALUE) part->y = c->y; if (c->position == POS_LAST && anim->last_x > -g->width && anim->last_x < part->viewport_width && anim->last_y > -g->height && anim->last_y < part->viewport_height) { part->x = anim->last_x; part->y = anim->last_y; } if (c->step_xoffset != ARG_UNDEFINED_VALUE) part->step_xoffset = c->step_xoffset; if (c->step_yoffset != ARG_UNDEFINED_VALUE) part->step_yoffset = c->step_yoffset; if (part->init_delay_counter == 0 && part->init_event_state == ANIM_EVENT_NONE) PlayGlobalAnimSoundAndMusic(part); } if (part->clicked && part->init_event_state != ANIM_EVENT_NONE) { if (part->initial_anim_sync_frame > 0) part->initial_anim_sync_frame -= part->init_delay_counter - 1; part->init_delay_counter = 1; part->init_event_state = ANIM_EVENT_NONE; part->clicked = FALSE; } if (part->clicked && part->anim_event_state != ANIM_EVENT_NONE) { part->anim_delay_counter = 1; part->anim_event_state = ANIM_EVENT_NONE; part->clicked = FALSE; } if (part->init_delay_counter > 0) { part->init_delay_counter--; if (part->init_delay_counter == 0) { part->init_event_state = ANIM_EVENT_NONE; PlayGlobalAnimSoundAndMusic(part); } return ANIM_STATE_WAITING; } if (part->init_event_state != ANIM_EVENT_NONE) return ANIM_STATE_WAITING; // animation part is now running/visible and therefore clickable part->clickable = TRUE; // check if moving animation has left the visible screen area if ((part->x <= -g->width && part->step_xoffset <= 0) || (part->x >= part->viewport_width && part->step_xoffset >= 0) || (part->y <= -g->height && part->step_yoffset <= 0) || (part->y >= part->viewport_height && part->step_yoffset >= 0)) { // do not wait for "anim" events for off-screen animations part->anim_event_state = ANIM_EVENT_NONE; // do not stop animation before "anim" or "post" counter are finished if (part->anim_delay_counter == 0 && part->post_delay_counter == 0) { StopGlobalAnimSoundAndMusic(part); part->post_delay_counter = (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random)); if (part->post_delay_counter > 0) return ANIM_STATE_RUNNING; // drawing last frame not needed here -- animation not visible anymore return ANIM_STATE_RESTART; } } if (part->anim_delay_counter > 0) { part->anim_delay_counter--; if (part->anim_delay_counter == 0) { part->anim_event_state = ANIM_EVENT_NONE; StopGlobalAnimSoundAndMusic(part); part->post_delay_counter = (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random)); if (part->post_delay_counter > 0) return ANIM_STATE_RUNNING; // additional state "RUNNING" required to not skip drawing last frame return ANIM_STATE_RESTART | ANIM_STATE_RUNNING; } } if (part->post_delay_counter > 0) { part->post_delay_counter--; if (part->post_delay_counter == 0) return ANIM_STATE_RESTART; return ANIM_STATE_WAITING; } if (!DelayReachedExt(&part->step_delay, part->step_delay_value, anim_sync_frame)) return ANIM_STATE_RUNNING; #if 0 { static unsigned int last_counter = -1; unsigned int counter = Counter(); printf("::: NEXT ANIM PART [%d, %d]\n", anim_sync_frame, counter - last_counter); last_counter = counter; } #endif part->x += part->step_xoffset; part->y += part->step_yoffset; anim->last_x = part->x; anim->last_y = part->y; return ANIM_STATE_RUNNING; } void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) { struct GlobalAnimPartControlInfo *part; struct GraphicInfo *c = &anim->control_info; int state, active_part_nr; #if 0 printf("::: HandleGlobalAnim_Main: %d, %d => %d\n", anim->mode_nr, anim->nr, anim->num_parts); printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons); #endif #if 0 printf("::: %s(%d): %d, %d, %d [%d]\n", (action == ANIM_START ? "ANIM_START" : action == ANIM_CONTINUE ? "ANIM_CONTINUE" : action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"), anim->nr, anim->state & ANIM_STATE_RESTART, anim->state & ANIM_STATE_WAITING, anim->state & ANIM_STATE_RUNNING, anim->num_parts); #endif switch (action) { case ANIM_START: anim->state = anim->last_state = ANIM_STATE_RESTART; anim->active_part_nr = anim->last_active_part_nr = 0; anim->part_counter = 0; break; case ANIM_CONTINUE: if (anim->state == ANIM_STATE_INACTIVE) return; anim->state = anim->last_state; anim->active_part_nr = anim->last_active_part_nr; break; case ANIM_STOP: anim->state = ANIM_STATE_INACTIVE; { int num_parts = anim->num_parts + (anim->has_base ? 1 : 0); int i; for (i = 0; i < num_parts; i++) StopGlobalAnimSoundAndMusic(&anim->part[i]); } return; default: break; } if (c->anim_mode & ANIM_ALL || anim->num_parts == 0) { int num_parts = anim->num_parts + (anim->has_base ? 1 : 0); int i; #if 0 printf("::: HandleGlobalAnim_Main: %d, %d => %d\n", anim->mode_nr, anim->nr, num_parts); #endif for (i = 0; i < num_parts; i++) { part = &anim->part[i]; switch (action) { case ANIM_START: anim->state = ANIM_STATE_RUNNING; part->state = ANIM_STATE_RESTART; break; case ANIM_CONTINUE: if (part->state == ANIM_STATE_INACTIVE) continue; break; case ANIM_STOP: part->state = ANIM_STATE_INACTIVE; continue; default: break; } part->state = HandleGlobalAnim_Part(part, part->state); // when animation mode is "once", stop after animation was played once if (c->anim_mode & ANIM_ONCE && part->state & ANIM_STATE_RESTART) part->state = ANIM_STATE_INACTIVE; } anim->last_state = anim->state; anim->last_active_part_nr = anim->active_part_nr; return; } if (anim->state & ANIM_STATE_RESTART) // directly after restart anim->active_part_nr = getGlobalAnimationPart(anim); part = &anim->part[anim->active_part_nr]; part->state = ANIM_STATE_RUNNING; anim->state = HandleGlobalAnim_Part(part, anim->state); if (anim->state & ANIM_STATE_RESTART) anim->part_counter++; // when animation mode is "once", stop after all animations were played once if (c->anim_mode & ANIM_ONCE && anim->part_counter == anim->num_parts) anim->state = ANIM_STATE_INACTIVE; state = anim->state; active_part_nr = anim->active_part_nr; // while the animation parts are pausing (waiting or inactive), play the base // (main) animation; this corresponds to the "boring player animation" logic // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!) if (anim->has_base) { if (anim->state == ANIM_STATE_WAITING || anim->state == ANIM_STATE_INACTIVE) { anim->active_part_nr = anim->num_parts; // part nr of base animation part = &anim->part[anim->active_part_nr]; if (anim->state != anim->last_state) part->state = ANIM_STATE_RESTART; anim->state = ANIM_STATE_RUNNING; part->state = HandleGlobalAnim_Part(part, part->state); } } anim->last_state = state; anim->last_active_part_nr = active_part_nr; } void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action) { int i; #if 0 printf("::: HandleGlobalAnim_Mode: %d => %d\n", ctrl->nr, ctrl->num_anims); #endif for (i = 0; i < ctrl->num_anims; i++) HandleGlobalAnim_Main(&ctrl->anim[i], action); } static void HandleGlobalAnim(int action, int game_mode) { #if 0 printf("::: HandleGlobalAnim [mode == %d]\n", game_status); #endif HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action); } static void DoAnimationExt() { int i; #if 0 printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter()); #endif // global animations now synchronized with frame delay of screen update anim_sync_frame++; for (i = 0; i < NUM_GAME_MODES; i++) HandleGlobalAnim(ANIM_CONTINUE, i); #if 0 // force screen redraw in next frame to continue drawing global animations redraw_mask = REDRAW_ALL; #endif } static void InitGlobalAnim_Clickable() { int mode_nr; for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; int anim_nr; for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++) { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; int part_nr; for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; part->clickable = FALSE; } } } } static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) { boolean anything_clicked = FALSE; boolean any_part_clicked = FALSE; int mode_nr; for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; int anim_nr; // check animations in reverse draw order (to stop when clicked) for (anim_nr = ctrl->num_anims - 1; anim_nr >= 0; anim_nr--) { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; int part_nr; // check animation parts in reverse draw order (to stop when clicked) for (part_nr = anim->num_parts_all - 1; part_nr >= 0; part_nr--) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; if (!clicked) { part->clicked = FALSE; continue; } if (!part->clickable) continue; // always handle "any" click events (clicking anywhere on screen) ... if (isClickablePart(part, ANIM_EVENT_ANY)) anything_clicked = part->clicked = TRUE; // ... but only handle the first (topmost) clickable animation if (any_part_clicked) continue; if (isClickedPart(part, mx, my, clicked)) { #if 0 printf("::: %d.%d CLICKED\n", anim_nr, part_nr); #endif any_part_clicked = TRUE; if (isClickablePart(part, ANIM_EVENT_SELF)) anything_clicked = part->clicked = TRUE; // check if this click is defined to trigger other animations int gic_anim_nr = part->old_anim_nr + 1; // X as in "anim_X" int gic_part_nr = part->old_nr + 1; // Y as in "part_Y" int mask = gic_anim_nr << ANIM_EVENT_ANIM_BIT; if (!part->is_base) mask |= gic_part_nr << ANIM_EVENT_PART_BIT; int anim2_nr; for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++) { struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr]; int part2_nr; for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++) { struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr]; if (isClickablePart(part2, mask)) anything_clicked = part2->clicked = TRUE; #if 0 struct GraphicInfo *c = &part2->control_info; printf("::: - %d.%d: 0x%08x, 0x%08x [0x%08x]", anim2_nr, part2_nr, c->init_event, c->anim_event, mask); if (isClickablePart(part2, mask)) printf(" <--- TRIGGERED BY %d.%d", anim_nr, part_nr); printf("\n"); #endif } } } } } } return anything_clicked; } static void ResetGlobalAnim_Clickable() { InitGlobalAnim_Clickable(); } static void ResetGlobalAnim_Clicked() { InitGlobalAnim_Clicked(-1, -1, FALSE); } boolean HandleGlobalAnimClicks(int mx, int my, int button) { static boolean click_consumed = FALSE; static int last_button = 0; boolean press_event; boolean release_event; boolean click_consumed_current = click_consumed; /* check if button state has changed since last invocation */ press_event = (button != 0 && last_button == 0); release_event = (button == 0 && last_button != 0); last_button = button; if (press_event) { click_consumed = InitGlobalAnim_Clicked(mx, my, TRUE); click_consumed_current = click_consumed; } if (release_event) click_consumed = FALSE; return click_consumed_current; } mirrormagic-3.0.0/src/conf_chr.h0000644000175000017500000002010513263214151016050 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // conf_chr.h // ============================================================================ /* ----- this file was automatically generated -- do not edit by hand ----- */ #ifndef CONF_CHR_H #define CONF_CHR_H /* values for elements configuration (character elements) */ #define EL_CHAR_SPACE (EL_CHAR_ASCII0 + 32) #define EL_CHAR_EXCLAM (EL_CHAR_ASCII0 + 33) #define EL_CHAR_QUOTEDBL (EL_CHAR_ASCII0 + 34) #define EL_CHAR_NUMBERSIGN (EL_CHAR_ASCII0 + 35) #define EL_CHAR_DOLLAR (EL_CHAR_ASCII0 + 36) #define EL_CHAR_PERCENT (EL_CHAR_ASCII0 + 37) #define EL_CHAR_AMPERSAND (EL_CHAR_ASCII0 + 38) #define EL_CHAR_APOSTROPHE (EL_CHAR_ASCII0 + 39) #define EL_CHAR_PARENLEFT (EL_CHAR_ASCII0 + 40) #define EL_CHAR_PARENRIGHT (EL_CHAR_ASCII0 + 41) #define EL_CHAR_ASTERISK (EL_CHAR_ASCII0 + 42) #define EL_CHAR_PLUS (EL_CHAR_ASCII0 + 43) #define EL_CHAR_COMMA (EL_CHAR_ASCII0 + 44) #define EL_CHAR_MINUS (EL_CHAR_ASCII0 + 45) #define EL_CHAR_PERIOD (EL_CHAR_ASCII0 + 46) #define EL_CHAR_SLASH (EL_CHAR_ASCII0 + 47) #define EL_CHAR_0 (EL_CHAR_ASCII0 + 48) #define EL_CHAR_1 (EL_CHAR_ASCII0 + 49) #define EL_CHAR_2 (EL_CHAR_ASCII0 + 50) #define EL_CHAR_3 (EL_CHAR_ASCII0 + 51) #define EL_CHAR_4 (EL_CHAR_ASCII0 + 52) #define EL_CHAR_5 (EL_CHAR_ASCII0 + 53) #define EL_CHAR_6 (EL_CHAR_ASCII0 + 54) #define EL_CHAR_7 (EL_CHAR_ASCII0 + 55) #define EL_CHAR_8 (EL_CHAR_ASCII0 + 56) #define EL_CHAR_9 (EL_CHAR_ASCII0 + 57) #define EL_CHAR_COLON (EL_CHAR_ASCII0 + 58) #define EL_CHAR_SEMICOLON (EL_CHAR_ASCII0 + 59) #define EL_CHAR_LESS (EL_CHAR_ASCII0 + 60) #define EL_CHAR_EQUAL (EL_CHAR_ASCII0 + 61) #define EL_CHAR_GREATER (EL_CHAR_ASCII0 + 62) #define EL_CHAR_QUESTION (EL_CHAR_ASCII0 + 63) #define EL_CHAR_AT (EL_CHAR_ASCII0 + 64) #define EL_CHAR_A (EL_CHAR_ASCII0 + 65) #define EL_CHAR_B (EL_CHAR_ASCII0 + 66) #define EL_CHAR_C (EL_CHAR_ASCII0 + 67) #define EL_CHAR_D (EL_CHAR_ASCII0 + 68) #define EL_CHAR_E (EL_CHAR_ASCII0 + 69) #define EL_CHAR_F (EL_CHAR_ASCII0 + 70) #define EL_CHAR_G (EL_CHAR_ASCII0 + 71) #define EL_CHAR_H (EL_CHAR_ASCII0 + 72) #define EL_CHAR_I (EL_CHAR_ASCII0 + 73) #define EL_CHAR_J (EL_CHAR_ASCII0 + 74) #define EL_CHAR_K (EL_CHAR_ASCII0 + 75) #define EL_CHAR_L (EL_CHAR_ASCII0 + 76) #define EL_CHAR_M (EL_CHAR_ASCII0 + 77) #define EL_CHAR_N (EL_CHAR_ASCII0 + 78) #define EL_CHAR_O (EL_CHAR_ASCII0 + 79) #define EL_CHAR_P (EL_CHAR_ASCII0 + 80) #define EL_CHAR_Q (EL_CHAR_ASCII0 + 81) #define EL_CHAR_R (EL_CHAR_ASCII0 + 82) #define EL_CHAR_S (EL_CHAR_ASCII0 + 83) #define EL_CHAR_T (EL_CHAR_ASCII0 + 84) #define EL_CHAR_U (EL_CHAR_ASCII0 + 85) #define EL_CHAR_V (EL_CHAR_ASCII0 + 86) #define EL_CHAR_W (EL_CHAR_ASCII0 + 87) #define EL_CHAR_X (EL_CHAR_ASCII0 + 88) #define EL_CHAR_Y (EL_CHAR_ASCII0 + 89) #define EL_CHAR_Z (EL_CHAR_ASCII0 + 90) #define EL_CHAR_BRACKETLEFT (EL_CHAR_ASCII0 + 91) #define EL_CHAR_BACKSLASH (EL_CHAR_ASCII0 + 92) #define EL_CHAR_BRACKETRIGHT (EL_CHAR_ASCII0 + 93) #define EL_CHAR_ASCIICIRCUM (EL_CHAR_ASCII0 + 94) #define EL_CHAR_UNDERSCORE (EL_CHAR_ASCII0 + 95) #define EL_CHAR_COPYRIGHT (EL_CHAR_ASCII0 + 96) #define EL_CHAR_AUMLAUT (EL_CHAR_ASCII0 + 97) #define EL_CHAR_OUMLAUT (EL_CHAR_ASCII0 + 98) #define EL_CHAR_UUMLAUT (EL_CHAR_ASCII0 + 99) #define EL_CHAR_DEGREE (EL_CHAR_ASCII0 + 100) #define EL_CHAR_TRADEMARK (EL_CHAR_ASCII0 + 101) #define EL_CHAR_CURSOR (EL_CHAR_ASCII0 + 102) #define EL_CHAR_BUTTON (EL_CHAR_ASCII0 + 109) #define EL_CHAR_UP (EL_CHAR_ASCII0 + 110) #define EL_CHAR_DOWN (EL_CHAR_ASCII0 + 111) #define EL_STEEL_CHAR_SPACE (EL_STEEL_CHAR_ASCII0 + 32) #define EL_STEEL_CHAR_EXCLAM (EL_STEEL_CHAR_ASCII0 + 33) #define EL_STEEL_CHAR_QUOTEDBL (EL_STEEL_CHAR_ASCII0 + 34) #define EL_STEEL_CHAR_NUMBERSIGN (EL_STEEL_CHAR_ASCII0 + 35) #define EL_STEEL_CHAR_DOLLAR (EL_STEEL_CHAR_ASCII0 + 36) #define EL_STEEL_CHAR_PERCENT (EL_STEEL_CHAR_ASCII0 + 37) #define EL_STEEL_CHAR_AMPERSAND (EL_STEEL_CHAR_ASCII0 + 38) #define EL_STEEL_CHAR_APOSTROPHE (EL_STEEL_CHAR_ASCII0 + 39) #define EL_STEEL_CHAR_PARENLEFT (EL_STEEL_CHAR_ASCII0 + 40) #define EL_STEEL_CHAR_PARENRIGHT (EL_STEEL_CHAR_ASCII0 + 41) #define EL_STEEL_CHAR_ASTERISK (EL_STEEL_CHAR_ASCII0 + 42) #define EL_STEEL_CHAR_PLUS (EL_STEEL_CHAR_ASCII0 + 43) #define EL_STEEL_CHAR_COMMA (EL_STEEL_CHAR_ASCII0 + 44) #define EL_STEEL_CHAR_MINUS (EL_STEEL_CHAR_ASCII0 + 45) #define EL_STEEL_CHAR_PERIOD (EL_STEEL_CHAR_ASCII0 + 46) #define EL_STEEL_CHAR_SLASH (EL_STEEL_CHAR_ASCII0 + 47) #define EL_STEEL_CHAR_0 (EL_STEEL_CHAR_ASCII0 + 48) #define EL_STEEL_CHAR_1 (EL_STEEL_CHAR_ASCII0 + 49) #define EL_STEEL_CHAR_2 (EL_STEEL_CHAR_ASCII0 + 50) #define EL_STEEL_CHAR_3 (EL_STEEL_CHAR_ASCII0 + 51) #define EL_STEEL_CHAR_4 (EL_STEEL_CHAR_ASCII0 + 52) #define EL_STEEL_CHAR_5 (EL_STEEL_CHAR_ASCII0 + 53) #define EL_STEEL_CHAR_6 (EL_STEEL_CHAR_ASCII0 + 54) #define EL_STEEL_CHAR_7 (EL_STEEL_CHAR_ASCII0 + 55) #define EL_STEEL_CHAR_8 (EL_STEEL_CHAR_ASCII0 + 56) #define EL_STEEL_CHAR_9 (EL_STEEL_CHAR_ASCII0 + 57) #define EL_STEEL_CHAR_COLON (EL_STEEL_CHAR_ASCII0 + 58) #define EL_STEEL_CHAR_SEMICOLON (EL_STEEL_CHAR_ASCII0 + 59) #define EL_STEEL_CHAR_LESS (EL_STEEL_CHAR_ASCII0 + 60) #define EL_STEEL_CHAR_EQUAL (EL_STEEL_CHAR_ASCII0 + 61) #define EL_STEEL_CHAR_GREATER (EL_STEEL_CHAR_ASCII0 + 62) #define EL_STEEL_CHAR_QUESTION (EL_STEEL_CHAR_ASCII0 + 63) #define EL_STEEL_CHAR_AT (EL_STEEL_CHAR_ASCII0 + 64) #define EL_STEEL_CHAR_A (EL_STEEL_CHAR_ASCII0 + 65) #define EL_STEEL_CHAR_B (EL_STEEL_CHAR_ASCII0 + 66) #define EL_STEEL_CHAR_C (EL_STEEL_CHAR_ASCII0 + 67) #define EL_STEEL_CHAR_D (EL_STEEL_CHAR_ASCII0 + 68) #define EL_STEEL_CHAR_E (EL_STEEL_CHAR_ASCII0 + 69) #define EL_STEEL_CHAR_F (EL_STEEL_CHAR_ASCII0 + 70) #define EL_STEEL_CHAR_G (EL_STEEL_CHAR_ASCII0 + 71) #define EL_STEEL_CHAR_H (EL_STEEL_CHAR_ASCII0 + 72) #define EL_STEEL_CHAR_I (EL_STEEL_CHAR_ASCII0 + 73) #define EL_STEEL_CHAR_J (EL_STEEL_CHAR_ASCII0 + 74) #define EL_STEEL_CHAR_K (EL_STEEL_CHAR_ASCII0 + 75) #define EL_STEEL_CHAR_L (EL_STEEL_CHAR_ASCII0 + 76) #define EL_STEEL_CHAR_M (EL_STEEL_CHAR_ASCII0 + 77) #define EL_STEEL_CHAR_N (EL_STEEL_CHAR_ASCII0 + 78) #define EL_STEEL_CHAR_O (EL_STEEL_CHAR_ASCII0 + 79) #define EL_STEEL_CHAR_P (EL_STEEL_CHAR_ASCII0 + 80) #define EL_STEEL_CHAR_Q (EL_STEEL_CHAR_ASCII0 + 81) #define EL_STEEL_CHAR_R (EL_STEEL_CHAR_ASCII0 + 82) #define EL_STEEL_CHAR_S (EL_STEEL_CHAR_ASCII0 + 83) #define EL_STEEL_CHAR_T (EL_STEEL_CHAR_ASCII0 + 84) #define EL_STEEL_CHAR_U (EL_STEEL_CHAR_ASCII0 + 85) #define EL_STEEL_CHAR_V (EL_STEEL_CHAR_ASCII0 + 86) #define EL_STEEL_CHAR_W (EL_STEEL_CHAR_ASCII0 + 87) #define EL_STEEL_CHAR_X (EL_STEEL_CHAR_ASCII0 + 88) #define EL_STEEL_CHAR_Y (EL_STEEL_CHAR_ASCII0 + 89) #define EL_STEEL_CHAR_Z (EL_STEEL_CHAR_ASCII0 + 90) #define EL_STEEL_CHAR_BRACKETLEFT (EL_STEEL_CHAR_ASCII0 + 91) #define EL_STEEL_CHAR_BACKSLASH (EL_STEEL_CHAR_ASCII0 + 92) #define EL_STEEL_CHAR_BRACKETRIGHT (EL_STEEL_CHAR_ASCII0 + 93) #define EL_STEEL_CHAR_ASCIICIRCUM (EL_STEEL_CHAR_ASCII0 + 94) #define EL_STEEL_CHAR_UNDERSCORE (EL_STEEL_CHAR_ASCII0 + 95) #define EL_STEEL_CHAR_COPYRIGHT (EL_STEEL_CHAR_ASCII0 + 96) #define EL_STEEL_CHAR_AUMLAUT (EL_STEEL_CHAR_ASCII0 + 97) #define EL_STEEL_CHAR_OUMLAUT (EL_STEEL_CHAR_ASCII0 + 98) #define EL_STEEL_CHAR_UUMLAUT (EL_STEEL_CHAR_ASCII0 + 99) #define EL_STEEL_CHAR_DEGREE (EL_STEEL_CHAR_ASCII0 + 100) #define EL_STEEL_CHAR_TRADEMARK (EL_STEEL_CHAR_ASCII0 + 101) #define EL_STEEL_CHAR_CURSOR (EL_STEEL_CHAR_ASCII0 + 102) #define EL_STEEL_CHAR_BUTTON (EL_STEEL_CHAR_ASCII0 + 109) #define EL_STEEL_CHAR_UP (EL_STEEL_CHAR_ASCII0 + 110) #define EL_STEEL_CHAR_DOWN (EL_STEEL_CHAR_ASCII0 + 111) #endif /* CONF_CHR_C */ mirrormagic-3.0.0/src/game_mm/0000755000175000017500000000000013263214225015524 5ustar aeglosaeglosmirrormagic-3.0.0/src/game_mm/main_mm.h0000644000175000017500000000545313263212010017307 0ustar aeglosaeglos#ifndef MAIN_MM_H #define MAIN_MM_H /* ========================================================================= */ /* external functions and definitions imported from main program to game_mm */ /* ========================================================================= */ #include "../engines.h" #include "../conf_gfx.h" /* ========================================================================= */ /* functions and definitions that are exported from game_mm to main program */ /* ========================================================================= */ #include "export.h" /* ========================================================================= */ /* internal functions and definitions that are not exported to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ /* screen sizes and positions for MM engine */ extern int TILESIZE_VAR; #define TILESIZE 32 #define TILEX TILESIZE #define TILEY TILESIZE #define TILEX_VAR TILESIZE_VAR #define TILEY_VAR TILESIZE_VAR extern int SCR_FIELDX, SCR_FIELDY; #define MAX_BUF_XSIZE SCR_FIELDX #define MAX_BUF_YSIZE SCR_FIELDY /* often used screen positions */ extern int SX, SY; #define SXSIZE (SCR_FIELDX * TILEX_VAR) #define SYSIZE (SCR_FIELDY * TILEY_VAR) #define FXSIZE (MAX_BUF_XSIZE * TILEX_VAR) #define FYSIZE (MAX_BUF_YSIZE * TILEY_VAR) extern int REAL_SX, REAL_SY; #define FULL_SXSIZE (2 + SXSIZE + 2) #define FULL_SYSIZE (2 + SYSIZE + 2) /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* exported variables */ /* ------------------------------------------------------------------------- */ extern struct LevelInfo_MM native_mm_level; extern Bitmap *bitmap_db_field_mm; extern int GfxElementLast[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT]; extern int GfxGraphicLast[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT]; extern int GfxGraphic[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT]; extern int GfxFrame[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT]; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ #endif /* MAIN_MM_H */ mirrormagic-3.0.0/src/game_mm/game_mm.h0000644000175000017500000000114313263212010017264 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // game_mm.h // ============================================================================ #ifndef GAME_MM_H #define GAME_MM_H #define GAME_MM_VERSION_1_0_0 #include "export.h" #endif /* GAME_MM_H */ mirrormagic-3.0.0/src/game_mm/Makefile0000644000175000017500000000342513263212010017156 0ustar aeglosaeglos# ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1989-2017 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # The native Mirror Magic game engine is based on: # - Mirror Magic II by Holger Schemel (Linux/DOS/Windows version, 1995) # - Mindbender by Holger Schemel (Amiga version, 1989) # ----------------------------------------------------------------------------- # src/game_mm/Makefile # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = mm_init.c \ mm_main.c \ mm_game.c \ mm_files.c \ mm_tools.c OBJS = mm_init.o \ mm_main.o \ mm_game.o \ mm_files.o \ mm_tools.o GAME_MM = game_mm.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(GAME_MM) $(GAME_MM): $(OBJS) $(AR) cru $(GAME_MM) $(OBJS) $(RANLIB) $(GAME_MM) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(GAME_MM) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif mirrormagic-3.0.0/src/game_mm/mm_main.c0000644000175000017500000003205713263212010017302 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // mm_main.c // ============================================================================ #include "main_mm.h" #include "mm_main.h" struct GameInfo_MM game_mm; struct LevelInfo_MM native_mm_level; short Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Hit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Box[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Angle[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; unsigned int Elementeigenschaften[MAX_ELEMENTS]; struct LaserInfo laser; short LX,LY, XS,YS, ELX,ELY; short CT,Ct; int dSX, dSY; int cSX, cSY; int cSX2, cSY2; int cFX, cFY; Pixel pen_fg, pen_bg, pen_ray, pen_magicolor[2]; int color_status; struct XY Step[16] = { { 1, 0 }, { 2, -1 }, { 1, -1 }, { 1, -2 }, { 0, -1 }, { -1, -2 }, { -1, -1 }, { -2, -1 }, { -1, 0 }, { -2, 1 }, { -1, 1 }, { -1, 2 }, { 0, 1 }, { 1, 2 }, { 1, 1 }, { 2, 1 } }; /* "Sign" has the following structure: each 4-bit-value represents the values d*8 + c*4 + b*2 + a*1 at the pixel positions a b 1 2 c d 4 8 so the value "0xA" (=> (d=1)*8 + (c=0)*4 + (b=1)*2 + (a=0)*1) would result in the pixel pattern 0 1 _ x 0 1 or _ x x x x x x x x x x x x _ x x _ _ x x _ x 6 2 x x 5 4 3 x x x x 7 1 x x x _ _ x x _ 8 0 _ x x x 9 15 x x x x 11 12 13 x x 10 14 x _ x x _ _ x x _ x x x x x x x x x x x */ short Sign[16] = { 0xA, 0xF, 0xB, 0xF, 0x3, 0xF, 0x7, 0xF, 0x5, 0xF, 0xD, 0xF, 0xC, 0xF, 0xE, 0xF }; char *element_info_mm[] = { "empty space", /* 0 */ "mirror (0\xb0)", "mirror (11.25\xb0)", "mirror (22.5\xb0)", "mirror (33.75\xb0)", "mirror (45\xb0)", "mirror (56.25\xb0)", "mirror (67.5\xb0)", "mirror (78.75\xb0)", "mirror (90\xb0)", "mirror (101.25\xb0)", /* 10 */ "mirror (112.5\xb0)", "mirror (123.75\xb0)", "mirror (135\xb0)", "mirror (146.25\xb0)", "mirror (157.5\xb0)", "mirror (168.75\xb0)", "fixed steel polarizer (0\xb0)", "fixed steel polarizer (90\xb0)", "fixed steel polarizer (45\xb0)", "fixed steel polarizer (135\xb0)", /* 20 */ "Gregor McDuffin (looking right)", "Gregor McDuffin (looking up)", "Gregor McDuffin (looking left)", "Gregor McDuffin (looking down)", "closed exit", "opening exit", "opening exit", "open exit", "magic kettle", "bomb", /* 30 */ "prism", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", /* 40 */ "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "steel wall", "wooden wall", "wooden wall", "wooden wall", /* 50 */ "wooden wall", "wooden wall", "wooden wall", "wooden wall", "wooden wall", "wooden wall", "wooden wall", "wooden wall", "wooden wall", "wooden wall", /* 60 */ "wooden wall", "wooden wall", "wooden wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", /* 70 */ "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "ice wall", "amoeba wall", /* 80 */ "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", /* 90 */ "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "amoeba wall", "wooden block", "gray ball", "teleporter (0\xb0)", "teleporter (22.5\xb0)", "teleporter (45\xb0)", /* 100 */ "teleporter (67.5\xb0)", "teleporter (90\xb0)", "teleporter (112.5\xb0)", "teleporter (135\xb0)", "teleporter (157.5\xb0)", "teleporter (180\xb0)", "teleporter (202.5\xb0)", "teleporter (225\xb0)", "teleporter (247.5\xb0)", "teleporter (270\xb0)", /* 110 */ "teleporter (292.5\xb0)", "teleporter (315\xb0)", "teleporter (337.5\xb0)", "fuse", "pac man (starts moving right)", "pac man (starts moving up)", "pac man (starts moving left)", "pac man (starts moving down)", "polarizer (0\xb0)", "polarizer (11.25\xb0)", /* 120 */ "polarizer (22.5\xb0)", "polarizer (33.75\xb0)", "polarizer (45\xb0)", "polarizer (56.25\xb0)", "polarizer (67.5\xb0)", "polarizer (78.75\xb0)", "polarizer (90\xb0)", "polarizer (101.25\xb0)", "polarizer (112.5\xb0)", "polarizer (123.75\xb0)", /* 130 */ "polarizer (135\xb0)", "polarizer (146.25\xb0)", "polarizer (157.5\xb0)", "polarizer (168.75\xb0)", "two-way polarizer (0\xb0)", "two-way polarizer (22.5\xb0)", "two-way polarizer (45\xb0)", "two-way polarizer (67.5\xb0)", "fixed mirror (0\xb0)", "fixed mirror (45\xb0)", /* 140 */ "fixed mirror (90\xb0)", "fixed mirror (135\xb0)", "reflecting stone lock", "key", "light bulb (dark)", "light bulb (glowing)", "bonus ball", "reflecting stone block", "wooden lock", "extra energy ball (full)", /* 150 */ "fixed wooden polarizer (0\xb0)", "fixed wooden polarizer (90\xb0)", "fixed wooden polarizer (45\xb0)", "fixed wooden polarizer (135\xb0)", "extra energy ball (empty)", "unused", "unused", "unused", "unused", "letter ' '", /* 160 */ "letter '!'", "letter '\"'", "letter '#'", "letter '$'", "letter '%'", "letter '&'", "letter '''", "letter '('", "letter ')'", "letter '*'", /* 170 */ "letter '+'", "letter ','", "letter '-'", "letter '.'", "letter '/'", "letter '0'", "letter '1'", "letter '2'", "letter '3'", "letter '4'", /* 180 */ "letter '5'", "letter '6'", "letter '7'", "letter '8'", "letter '9'", "letter ':'", "letter ';'", "letter '<'", "letter '='", "letter '>'", /* 190 */ "letter '?'", "letter '@'", "letter 'A'", "letter 'B'", "letter 'C'", "letter 'D'", "letter 'E'", "letter 'F'", "letter 'G'", "letter 'H'", /* 200 */ "letter 'I'", "letter 'J'", "letter 'K'", "letter 'L'", "letter 'M'", "letter 'N'", "letter 'O'", "letter 'P'", "letter 'Q'", "letter 'R'", /* 210 */ "letter 'S'", "letter 'T'", "letter 'U'", "letter 'V'", "letter 'W'", "letter 'X'", "letter 'Y'", "letter 'Z'", "letter '\xc4'", "letter '\xd6'", /* 220 */ "letter '\xdc'", "letter '^'", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", /* 230 */ "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "letter ''", "mirror (0\xb0)", /* 240 */ "mirror (11.25\xb0)", "mirror (22.5\xb0)", "mirror (33.75\xb0)", "mirror (45\xb0)", "mirror (56.25\xb0)", "mirror (67.5\xb0)", "mirror (78.75\xb0)", "mirror (90\xb0)", "mirror (101.25\xb0)", "mirror (112.5\xb0)", /* 250 */ "mirror (123.75\xb0)", "mirror (135\xb0)", "mirror (146.25\xb0)", "mirror (157.5\xb0)", "mirror (168.75\xb0)", "fixed wooden polarizer (0\xb0)", "fixed wooden polarizer (22.5\xb0)", "fixed wooden polarizer (45\xb0)", "fixed wooden polarizer (67.5\xb0)", "fixed wooden polarizer (90\xb0)", /* 260 */ "fixed wooden polarizer (112.5\xb0)", "fixed wooden polarizer (135\xb0)", "fixed wooden polarizer (157.5\xb0)", "fixed steel polarizer (0\xb0)", "fixed steel polarizer (22.5\xb0)", "fixed steel polarizer (45\xb0)", "fixed steel polarizer (67.5\xb0)", "fixed steel polarizer (90\xb0)", "fixed steel polarizer (112.5\xb0)", "fixed steel polarizer (135\xb0)", /* 270 */ "fixed steel polarizer (157.5\xb0)", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", /* 280 */ "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style wooden wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", /* 290 */ "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", /* 300 */ "deflektor style steel wall", "deflektor style steel wall", "deflektor style steel wall", "empty space", "cell", "mine", "refractor", "laser cannon (shooting right)", "laser cannon (shooting up)", "laser cannon (shooting left)", /* 310 */ "laser cannon (shooting down)", "laser receiver (directed right)", "laser receiver (directed up)", "laser receiver (directed left)", "laser receiver (directed down)", "fibre optic (1a)", "fibre optic (1b)", "fibre optic (2a)", "fibre optic (2b)", "fibre optic (3a)", /* 320 */ "fibre optic (3b)", "fibre optic (4a)", "fibre optic (4b)", "rotating mirror (0\xb0)", "rotating mirror (11.25\xb0)", "rotating mirror (22.5\xb0)", "rotating mirror (33.75\xb0)", "rotating mirror (45\xb0)", "rotating mirror (56.25\xb0)", "rotating mirror (67.5\xb0)", /* 330 */ "rotating mirror (78.75\xb0)", "rotating mirror (90\xb0)", "rotating mirror (101.25\xb0)", "rotating mirror (112.5\xb0)", "rotating mirror (123.75\xb0)", "rotating mirror (135\xb0)", "rotating mirror (146.25\xb0)", "rotating mirror (157.5\xb0)", "rotating mirror (168.75\xb0)", "rotating wooden polarizer (0\xb0)", /* 340 */ "rotating wooden polarizer (22.5\xb0)", "rotating wooden polarizer (45\xb0)", "rotating wooden polarizer (67.5\xb0)", "rotating wooden polarizer (90\xb0)", "rotating wooden polarizer (112.5\xb0)", "rotating wooden polarizer (135\xb0)", "rotating wooden polarizer (157.5\xb0)", "rotating steel polarizer (0\xb0)", "rotating steel polarizer (22.5\xb0)", "rotating steel polarizer (45\xb0)", /* 350 */ "rotating steel polarizer (67.5\xb0)", "rotating steel polarizer (90\xb0)", "rotating steel polarizer (112.5\xb0)", "rotating steel polarizer (135\xb0)", "rotating steel polarizer (157.5\xb0)", "red teleporter (0\xb0)", "red teleporter (22.5\xb0)", "red teleporter (45\xb0)", "red teleporter (67.5\xb0)", "red teleporter (90\xb0)", /* 360 */ "red teleporter (112.5\xb0)", "red teleporter (135\xb0)", "red teleporter (157.5\xb0)", "red teleporter (180\xb0)", "red teleporter (202.5\xb0)", "red teleporter (225\xb0)", "red teleporter (247.5\xb0)", "red teleporter (270\xb0)", "red teleporter (292.5\xb0)", "red teleporter (315\xb0)", /* 370 */ "red teleporter (337.5\xb0)", "yellow teleporter (0\xb0)", "yellow teleporter (22.5\xb0)", "yellow teleporter (45\xb0)", "yellow teleporter (67.5\xb0)", "yellow teleporter (90\xb0)", "yellow teleporter (112.5\xb0)", "yellow teleporter (135\xb0)", "yellow teleporter (157.5\xb0)", "yellow teleporter (180\xb0)", /* 380 */ "yellow teleporter (202.5\xb0)", "yellow teleporter (225\xb0)", "yellow teleporter (247.5\xb0)", "yellow teleporter (270\xb0)", "yellow teleporter (292.5\xb0)", "yellow teleporter (315\xb0)", "yellow teleporter (337.5\xb0)", "green teleporter (0\xb0)", "green teleporter (22.5\xb0)", "green teleporter (45\xb0)", /* 390 */ "green teleporter (67.5\xb0)", "green teleporter (90\xb0)", "green teleporter (112.5\xb0)", "green teleporter (135\xb0)", "green teleporter (157.5\xb0)", "green teleporter (180\xb0)", "green teleporter (202.5\xb0)", "green teleporter (225\xb0)", "green teleporter (247.5\xb0)", "green teleporter (270\xb0)", /* 400 */ "green teleporter (292.5\xb0)", "green teleporter (315\xb0)", "green teleporter (337.5\xb0)", "blue teleporter (0\xb0)", "blue teleporter (22.5\xb0)", "blue teleporter (45\xb0)", "blue teleporter (67.5\xb0)", "blue teleporter (90\xb0)", "blue teleporter (112.5\xb0)", "blue teleporter (135\xb0)", /* 410 */ "blue teleporter (157.5\xb0)", "blue teleporter (180\xb0)", "blue teleporter (202.5\xb0)", "blue teleporter (225\xb0)", "blue teleporter (247.5\xb0)", "blue teleporter (270\xb0)", "blue teleporter (292.5\xb0)", "blue teleporter (315\xb0)", "blue teleporter (337.5\xb0)", "unknown", /* 420 */ /* "-------------------------------", */ }; int num_element_info_mm = sizeof(element_info_mm) / sizeof(char *); mirrormagic-3.0.0/src/game_mm/mm_game.c0000644000175000017500000030103113263212010017256 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // mm_game.c // ============================================================================ #include #include "main_mm.h" #include "mm_main.h" #include "mm_game.h" #include "mm_tools.h" /* graphic position values for game controls */ #define ENERGY_XSIZE 32 #define ENERGY_YSIZE MAX_LASER_ENERGY #define OVERLOAD_XSIZE ENERGY_XSIZE #define OVERLOAD_YSIZE MAX_LASER_OVERLOAD /* values for Explode_MM() */ #define EX_PHASE_START 0 #define EX_NORMAL 0 #define EX_KETTLE 1 #define EX_SHORT 2 /* special positions in the game control window (relative to control window) */ #define XX_LEVEL 36 #define YY_LEVEL 23 #define XX_KETTLES 29 #define YY_KETTLES 63 #define XX_SCORE 22 #define YY_SCORE 101 #define XX_ENERGY 8 #define YY_ENERGY 158 #define XX_OVERLOAD 60 #define YY_OVERLOAD YY_ENERGY /* 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_KETTLES (DX + XX_KETTLES) #define DY_KETTLES (DY + YY_KETTLES) #define DX_SCORE (DX + XX_SCORE) #define DY_SCORE (DY + YY_SCORE) #define DX_ENERGY (DX + XX_ENERGY) #define DY_ENERGY (DY + YY_ENERGY) #define DX_OVERLOAD (DX + XX_OVERLOAD) #define DY_OVERLOAD (DY + YY_OVERLOAD) #define IS_LOOP_SOUND(s) ((s) == SND_FUEL) #define IS_MUSIC_SOUND(s) ((s) == SND_TYGER || (s) == SND_VOYAGER) /* game button identifiers */ #define GAME_CTRL_ID_LEFT 0 #define GAME_CTRL_ID_MIDDLE 1 #define GAME_CTRL_ID_RIGHT 2 #define NUM_GAME_BUTTONS 3 /* values for DrawLaser() */ #define DL_LASER_DISABLED 0 #define DL_LASER_ENABLED 1 /* values for 'click_delay_value' in ClickElement() */ #define CLICK_DELAY_FIRST 12 /* delay (frames) after first click */ #define CLICK_DELAY 6 /* delay (frames) for pressed butten */ #define AUTO_ROTATE_DELAY CLICK_DELAY #define INIT_GAME_ACTIONS_DELAY (ONE_SECOND_DELAY / GAME_FRAME_DELAY) #define NUM_INIT_CYCLE_STEPS 16 #define PACMAN_MOVE_DELAY 12 #define ENERGY_DELAY (ONE_SECOND_DELAY / GAME_FRAME_DELAY) #define HEALTH_DEC_DELAY 3 #define HEALTH_INC_DELAY 9 #define HEALTH_DELAY(x) ((x) ? HEALTH_DEC_DELAY : HEALTH_INC_DELAY) #define BEGIN_NO_HEADLESS \ { \ boolean last_headless = program.headless; \ \ program.headless = FALSE; \ #define END_NO_HEADLESS \ program.headless = last_headless; \ } \ /* forward declaration for internal use */ static int MovingOrBlocked2Element_MM(int, int); static void Bang_MM(int, int); static void RaiseScore_MM(int); static void RaiseScoreElement_MM(int); static void RemoveMovingField_MM(int, int); static void InitMovingField_MM(int, int, int); static void ContinueMoving_MM(int, int); static void Moving2Blocked_MM(int, int, int *, int *); /* bitmap for laser beam detection */ static Bitmap *laser_bitmap = NULL; /* variables for laser control */ static int last_LX = 0, last_LY = 0, last_hit_mask = 0; static int hold_x = -1, hold_y = -1; /* variables for pacman control */ static int pacman_nr = -1; /* various game engine delay counters */ static unsigned int rotate_delay = 0; static unsigned int pacman_delay = 0; static unsigned int energy_delay = 0; static unsigned int overload_delay = 0; /* element masks for scanning pixels of MM elements */ static const char mm_masks[10][16][16 + 1] = { { " ", " XXXXX ", " XXXXXXX ", " XXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXXX", " XXXXXXXXXXXXXX", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", }, { " ", " XXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", }, { " ", " XXXXXX ", " XXXXXXXXX ", " XXXXXXXXXXX ", "XXXXXXXXXXXXX ", "XXXXXXXXXXXXX ", "XXXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", }, { " ", " XXXXXX ", " XXXXXXXX ", " XXXXXXXXXX ", " XXXXXXXXXXX ", " XXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXX XXXXX ", }, { " XXXXXX XXXXXX ", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", " ", " ", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", " XXXXXX XXXXXX ", }, { " XXXXXX XXXXXX ", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", " XXXXXX XXXXXX ", " XXXXXX XXXXXX ", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", "XXXXXXX XXXXXXX", " XXXXXX XXXXXX ", }, { " XX XXXXX ", " XXX XXXX ", " XXXX XXX X", " XXXXXXXXX XX", " XXXXXXXXX XXX", "XXXXXXXXX XXXX", "XXXXXXXX XXXXX", " XXXX XXX ", " XXX XXXX ", "XXXXX XXXXXXXX", "XXXX XXXXXXXXX", "XXX XXXXXXXXX ", "XX XXXXXXXXX ", "X XXX XXXX ", " XXXX XXX ", " XXXXX XX ", }, { " XXXXX XX ", " XXXX XXX ", "X XXX XXXX ", "XX XXXXXXXXX ", "XXX XXXXXXXXX ", "XXXX XXXXXXXXX", "XXXXX XXXXXXXX", " XXX XXXX ", " XXXX XXX ", "XXXXXXXX XXXXX", "XXXXXXXXX XXXX", " XXXXXXXXX XXX", " XXXXXXXXX XX", " XXXX XXX X", " XXX XXXX ", " XX XXXXX ", }, { "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", }, { " ", " XXXX ", " XXXXXXXX ", " XXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXXXX ", " XXXXXXXXXX ", " XXXXXXXX ", " XXXX ", " ", }, }; static int get_element_angle(int element) { int element_phase = get_element_phase(element); if (IS_MIRROR_FIXED(element) || IS_MCDUFFIN(element) || IS_LASER(element) || IS_RECEIVER(element)) return 4 * element_phase; else return element_phase; } static int get_opposite_angle(int angle) { int opposite_angle = angle + ANG_RAY_180; /* make sure "opposite_angle" is in valid interval [0, 15] */ return (opposite_angle + 16) % 16; } static int get_mirrored_angle(int laser_angle, int mirror_angle) { int reflected_angle = 16 - laser_angle + mirror_angle; /* make sure "reflected_angle" is in valid interval [0, 15] */ return (reflected_angle + 16) % 16; } static void DrawLaserLines(struct XY *points, int num_points, int mode) { Pixel pixel_drawto = (mode == DL_LASER_ENABLED ? pen_ray : pen_bg); Pixel pixel_buffer = (mode == DL_LASER_ENABLED ? WHITE_PIXEL : BLACK_PIXEL); DrawLines(drawto, points, num_points, pixel_drawto); BEGIN_NO_HEADLESS { DrawLines(laser_bitmap, points, num_points, pixel_buffer); } END_NO_HEADLESS } static boolean CheckLaserPixel(int x, int y) { Pixel pixel; BEGIN_NO_HEADLESS { pixel = ReadPixel(laser_bitmap, x, y); } END_NO_HEADLESS return (pixel == WHITE_PIXEL); } static void CheckExitMM() { int exit_element = EL_EMPTY; int exit_x = 0; int exit_y = 0; int x, y; static int xy[4][2] = { { +1, 0 }, { 0, -1 }, { -1, 0 }, { 0, +1 } }; for (y = 0; y < lev_fieldy; y++) { for (x = 0; x < lev_fieldx; x++) { if (Feld[x][y] == EL_EXIT_CLOSED) { /* initiate opening animation of exit door */ Feld[x][y] = EL_EXIT_OPENING; exit_element = EL_EXIT_OPEN; exit_x = x; exit_y = y; } else if (IS_RECEIVER(Feld[x][y])) { /* remove field that blocks receiver */ int phase = Feld[x][y] - EL_RECEIVER_START; int blocking_x, blocking_y; blocking_x = x + xy[phase][0]; blocking_y = y + xy[phase][1]; if (IN_LEV_FIELD(blocking_x, blocking_y)) { Feld[blocking_x][blocking_y] = EL_EMPTY; DrawField_MM(blocking_x, blocking_y); } exit_element = EL_RECEIVER; exit_x = x; exit_y = y; } } } if (exit_element != EL_EMPTY) PlayLevelSound_MM(exit_x, exit_y, exit_element, MM_ACTION_OPENING); } static void InitMovDir_MM(int x, int y) { int element = Feld[x][y]; static int direction[3][4] = { { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN }, { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }, { MV_LEFT, MV_RIGHT, MV_UP, MV_DOWN } }; switch(element) { case EL_PACMAN_RIGHT: case EL_PACMAN_UP: case EL_PACMAN_LEFT: case EL_PACMAN_DOWN: Feld[x][y] = EL_PACMAN; MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT]; break; default: break; } } static void InitField(int x, int y, boolean init_game) { int element = Feld[x][y]; switch (element) { case EL_DF_EMPTY: Feld[x][y] = EL_EMPTY; break; case EL_KETTLE: case EL_CELL: if (native_mm_level.auto_count_kettles) game_mm.kettles_still_needed++; break; case EL_LIGHTBULB_OFF: game_mm.lights_still_needed++; break; default: if (IS_MIRROR(element) || IS_BEAMER_OLD(element) || IS_BEAMER(element) || IS_POLAR(element) || IS_POLAR_CROSS(element) || IS_DF_MIRROR(element) || IS_DF_MIRROR_AUTO(element) || IS_GRID_STEEL_AUTO(element) || IS_GRID_WOOD_AUTO(element) || IS_FIBRE_OPTIC(element)) { if (IS_BEAMER_OLD(element)) { Feld[x][y] = EL_BEAMER_BLUE_START + (element - EL_BEAMER_START); element = Feld[x][y]; } if (!IS_FIBRE_OPTIC(element)) { static int steps_grid_auto = 0; if (game_mm.num_cycle == 0) /* initialize cycle steps for grids */ steps_grid_auto = RND(16) * (RND(2) ? -1 : +1); if (IS_GRID_STEEL_AUTO(element) || IS_GRID_WOOD_AUTO(element)) game_mm.cycle[game_mm.num_cycle].steps = steps_grid_auto; else game_mm.cycle[game_mm.num_cycle].steps = RND(16) * (RND(2) ? -1 : +1); game_mm.cycle[game_mm.num_cycle].x = x; game_mm.cycle[game_mm.num_cycle].y = y; game_mm.num_cycle++; } if (IS_BEAMER(element) || IS_FIBRE_OPTIC(element)) { int beamer_nr = BEAMER_NR(element); int nr = laser.beamer[beamer_nr][0].num; laser.beamer[beamer_nr][nr].x = x; laser.beamer[beamer_nr][nr].y = y; laser.beamer[beamer_nr][nr].num = 1; } } else if (IS_PACMAN(element)) { InitMovDir_MM(x, y); } else if (IS_MCDUFFIN(element) || IS_LASER(element)) { laser.start_edge.x = x; laser.start_edge.y = y; laser.start_angle = get_element_angle(element); } break; } } static void InitCycleElements_RotateSingleStep() { int i; if (game_mm.num_cycle == 0) /* no elements to cycle */ return; for (i = 0; i < game_mm.num_cycle; i++) { int x = game_mm.cycle[i].x; int y = game_mm.cycle[i].y; int step = SIGN(game_mm.cycle[i].steps); int last_element = Feld[x][y]; int next_element = get_rotated_element(last_element, step); if (!game_mm.cycle[i].steps) continue; Feld[x][y] = next_element; DrawField_MM(x, y); game_mm.cycle[i].steps -= step; } } static void InitLaser() { int start_element = Feld[laser.start_edge.x][laser.start_edge.y]; int step = (IS_LASER(start_element) ? 4 : 0); LX = laser.start_edge.x * TILEX; if (laser.start_angle == ANG_RAY_UP || laser.start_angle == ANG_RAY_DOWN) LX += 14; else LX += (laser.start_angle == ANG_RAY_RIGHT ? 28 + step : 0 - step); LY = laser.start_edge.y * TILEY; if (laser.start_angle == ANG_RAY_UP || laser.start_angle == ANG_RAY_DOWN) LY += (laser.start_angle == ANG_RAY_DOWN ? 28 + step : 0 - step); else LY += 14; XS = 2 * Step[laser.start_angle].x; YS = 2 * Step[laser.start_angle].y; laser.current_angle = laser.start_angle; laser.num_damages = 0; laser.num_edges = 0; laser.num_beamers = 0; laser.beamer_edge[0] = 0; laser.dest_element = EL_EMPTY; laser.wall_mask = 0; AddLaserEdge(LX, LY); /* set laser starting edge */ pen_ray = GetPixelFromRGB(window, native_mm_level.laser_red * 0xFF, native_mm_level.laser_green * 0xFF, native_mm_level.laser_blue * 0xFF); } void InitGameEngine_MM() { int i, x, y; BEGIN_NO_HEADLESS { /* initialize laser bitmap to current playfield (screen) size */ ReCreateBitmap(&laser_bitmap, drawto->width, drawto->height); ClearRectangle(laser_bitmap, 0, 0, drawto->width, drawto->height); } END_NO_HEADLESS /* set global game control values */ game_mm.num_cycle = 0; game_mm.num_pacman = 0; game_mm.score = 0; game_mm.energy_left = 0; // later set to "native_mm_level.time" game_mm.kettles_still_needed = (native_mm_level.auto_count_kettles ? 0 : native_mm_level.kettles_needed); game_mm.lights_still_needed = 0; game_mm.num_keys = 0; game_mm.level_solved = FALSE; game_mm.game_over = FALSE; game_mm.game_over_cause = 0; game_mm.laser_overload_value = 0; game_mm.laser_enabled = FALSE; /* set global laser control values (must be set before "InitLaser()") */ laser.start_edge.x = 0; laser.start_edge.y = 0; laser.start_angle = 0; for (i = 0; i < MAX_NUM_BEAMERS; i++) laser.beamer[i][0].num = laser.beamer[i][1].num = 0; laser.overloaded = FALSE; laser.overload_value = 0; laser.fuse_off = FALSE; laser.fuse_x = laser.fuse_y = -1; laser.dest_element = EL_EMPTY; laser.wall_mask = 0; last_LX = 0; last_LY = 0; last_hit_mask = 0; hold_x = -1; hold_y = -1; pacman_nr = -1; CT = Ct = 0; rotate_delay = 0; pacman_delay = 0; energy_delay = 0; overload_delay = 0; ClickElement(-1, -1, -1); for (x = 0; x < lev_fieldx; x++) { for (y = 0; y < lev_fieldy; y++) { Feld[x][y] = Ur[x][y]; Hit[x][y] = Box[x][y] = 0; Angle[x][y] = 0; MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; Store[x][y] = Store2[x][y] = 0; Frame[x][y] = 0; Stop[x][y] = FALSE; InitField(x, y, TRUE); } } #if 0 CloseDoor(DOOR_CLOSE_1); #endif DrawLevel_MM(); } void InitGameActions_MM() { int num_init_game_frames = INIT_GAME_ACTIONS_DELAY; int cycle_steps_done = 0; int i; InitLaser(); #if 0 /* copy default game door content to main double buffer */ BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); #endif #if 0 DrawText(DX_LEVEL, DY_LEVEL, int2str(level_nr, 2), FONT_TEXT_2); DrawText(DX_KETTLES, DY_KETTLES, int2str(game_mm.kettles_still_needed, 3), FONT_TEXT_2); DrawText(DX_SCORE, DY_SCORE, int2str(game_mm.score, 4), FONT_TEXT_2); #endif #if 0 UnmapGameButtons(); MapGameButtons(); #endif #if 0 /* copy actual game door content to door double buffer for OpenDoor() */ BlitBitmap(drawto, pix[PIX_DB_DOOR], DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); #endif #if 0 OpenDoor(DOOR_OPEN_ALL); #endif for (i = 0; i <= num_init_game_frames; i++) { if (i == num_init_game_frames) StopSound_MM(SND_MM_GAME_LEVELTIME_CHARGING); else if (setup.sound_loops) PlaySoundLoop_MM(SND_MM_GAME_LEVELTIME_CHARGING); else PlaySound_MM(SND_MM_GAME_LEVELTIME_CHARGING); game_mm.energy_left = native_mm_level.time * i / num_init_game_frames; UpdateAndDisplayGameControlValues(); while (cycle_steps_done < NUM_INIT_CYCLE_STEPS * i / num_init_game_frames) { InitCycleElements_RotateSingleStep(); cycle_steps_done++; } BackToFront(); ColorCycling(); #ifdef DEBUG if (setup.quick_doors) continue; #endif } #if 0 if (setup.sound_music && num_bg_loops) PlayMusic(level_nr % num_bg_loops); #endif ScanLaser(); if (game_mm.kettles_still_needed == 0) CheckExitMM(); SetTileCursorXY(laser.start_edge.x, laser.start_edge.y); SetTileCursorActive(TRUE); } void AddLaserEdge(int lx, int ly) { int clx = dSX + lx; int cly = dSY + ly; if (clx < -2 || cly < -2 || clx >= SXSIZE + 2 || cly >= SYSIZE + 2) { Error(ERR_WARN, "AddLaserEdge: out of bounds: %d, %d", lx, ly); return; } laser.edge[laser.num_edges].x = cSX2 + lx; laser.edge[laser.num_edges].y = cSY2 + ly; laser.num_edges++; laser.redraw = TRUE; } void AddDamagedField(int ex, int ey) { laser.damage[laser.num_damages].is_mirror = FALSE; laser.damage[laser.num_damages].angle = laser.current_angle; laser.damage[laser.num_damages].edge = laser.num_edges; laser.damage[laser.num_damages].x = ex; laser.damage[laser.num_damages].y = ey; laser.num_damages++; } boolean StepBehind() { if (laser.num_edges) { int x = LX - XS; int y = LY - YS; int last_x = laser.edge[laser.num_edges - 1].x - cSX2; int last_y = laser.edge[laser.num_edges - 1].y - cSY2; return ((x - last_x) * XS < 0 || (y - last_y) * YS < 0); } return FALSE; } static int getMaskFromElement(int element) { if (IS_GRID(element)) return IMG_MM_MASK_GRID_1 + get_element_phase(element); else if (IS_MCDUFFIN(element)) return IMG_MM_MASK_MCDUFFIN_RIGHT + get_element_phase(element); else if (IS_RECTANGLE(element) || IS_DF_GRID(element)) return IMG_MM_MASK_RECTANGLE; else return IMG_MM_MASK_CIRCLE; } int ScanPixel() { int hit_mask = 0; #if 0 printf("ScanPixel: start scanning at (%d, %d) [%d, %d] [%d, %d]\n", LX, LY, LX / TILEX, LY / TILEY, LX % TILEX, LY % TILEY); #endif /* follow laser beam until it hits something (at least the screen border) */ while (hit_mask == HIT_MASK_NO_HIT) { int i; #if 0 /* for safety */ if (SX + LX < REAL_SX || SX + LX >= REAL_SX + FULL_SXSIZE || SY + LY < REAL_SY || SY + LY >= REAL_SY + FULL_SYSIZE) { printf("ScanPixel: touched screen border!\n"); return HIT_MASK_ALL; } #endif for (i = 0; i < 4; i++) { int px = LX + (i % 2) * 2; int py = LY + (i / 2) * 2; int dx = px % TILEX; int dy = py % TILEY; int lx = (px + TILEX) / TILEX - 1; /* ...+TILEX...-1 to get correct */ int ly = (py + TILEY) / TILEY - 1; /* negative values! */ Pixel pixel; if (IN_LEV_FIELD(lx, ly)) { int element = Feld[lx][ly]; if (element == EL_EMPTY || element == EL_EXPLODING_TRANSP) { pixel = 0; } else if (IS_WALL(element) || IS_WALL_CHANGING(element)) { int pos = dy / MINI_TILEY * 2 + dx / MINI_TILEX; pixel = ((element & (1 << pos)) ? 1 : 0); } else { int pos = getMaskFromElement(element) - IMG_MM_MASK_MCDUFFIN_RIGHT; pixel = (mm_masks[pos][dy / 2][dx / 2] == 'X' ? 1 : 0); } } else { pixel = (cSX + px < REAL_SX || cSX + px >= REAL_SX + FULL_SXSIZE || cSY + py < REAL_SY || cSY + py >= REAL_SY + FULL_SYSIZE); } if ((Sign[laser.current_angle] & (1 << i)) && pixel) hit_mask |= (1 << i); } if (hit_mask == HIT_MASK_NO_HIT) { /* hit nothing -- go on with another step */ LX += XS; LY += YS; } } return hit_mask; } void ScanLaser() { int element; int end = 0, rf = laser.num_edges; /* do not scan laser again after the game was lost for whatever reason */ if (game_mm.game_over) return; laser.overloaded = FALSE; laser.stops_inside_element = FALSE; DrawLaser(0, DL_LASER_ENABLED); #if 0 printf("Start scanning with LX == %d, LY == %d, XS == %d, YS == %d\n", LX, LY, XS, YS); #endif while (1) { int hit_mask; if (laser.num_edges > MAX_LASER_LEN || laser.num_damages > MAX_LASER_LEN) { end = 1; laser.overloaded = TRUE; break; } hit_mask = ScanPixel(); #if 0 printf("Hit something at LX == %d, LY == %d, XS == %d, YS == %d\n", LX, LY, XS, YS); #endif /* hit something -- check out what it was */ ELX = (LX + XS) / TILEX; ELY = (LY + YS) / TILEY; #if 0 printf("hit_mask (1) == '%x' (%d, %d) (%d, %d)\n", hit_mask, LX, LY, ELX, ELY); #endif if (!IN_LEV_FIELD(ELX, ELY) || !IN_PIX_FIELD(LX, LY)) { element = EL_EMPTY; laser.dest_element = element; break; } if (hit_mask == (HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT)) { /* we have hit the top-right and bottom-left element -- choose the bottom-left one */ /* !!! THIS CAN BE DONE MORE INTELLIGENTLY, FOR EXAMPLE, IF ONE ELEMENT WAS STEEL AND THE OTHER ONE WAS ICE => ALWAYS CHOOSE THE ICE AND MELT IT AWAY INSTEAD OF OVERLOADING LASER !!! */ ELX = (LX - 2) / TILEX; ELY = (LY + 2) / TILEY; } if (hit_mask == (HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT)) { /* we have hit the top-left and bottom-right element -- choose the top-left one */ /* !!! SEE ABOVE !!! */ ELX = (LX - 2) / TILEX; ELY = (LY - 2) / TILEY; } #if 0 printf("hit_mask (2) == '%x' (%d, %d) (%d, %d)\n", hit_mask, LX, LY, ELX, ELY); #endif element = Feld[ELX][ELY]; laser.dest_element = element; #if 0 printf("Hit element %d at (%d, %d) [%d, %d] [%d, %d] [%d]\n", element, ELX, ELY, LX, LY, LX % TILEX, LY % TILEY, hit_mask); #endif #if 0 if (!IN_LEV_FIELD(ELX, ELY)) printf("WARNING! (1) %d, %d (%d)\n", ELX, ELY, element); #endif if (element == EL_EMPTY) { if (!HitOnlyAnEdge(element, hit_mask)) break; } else if (element == EL_FUSE_ON) { if (HitPolarizer(element, hit_mask)) break; } else if (IS_GRID(element) || IS_DF_GRID(element)) { if (HitPolarizer(element, hit_mask)) break; } else if (element == EL_BLOCK_STONE || element == EL_BLOCK_WOOD || element == EL_GATE_STONE || element == EL_GATE_WOOD) { if (HitBlock(element, hit_mask)) { rf = 1; break; } } else if (IS_MCDUFFIN(element)) { if (HitLaserSource(element, hit_mask)) break; } else if ((element >= EL_EXIT_CLOSED && element <= EL_EXIT_OPEN) || IS_RECEIVER(element)) { if (HitLaserDestination(element, hit_mask)) break; } else if (IS_WALL(element)) { if (IS_WALL_STEEL(element) || IS_DF_WALL_STEEL(element)) { if (HitReflectingWalls(element, hit_mask)) break; } else { if (HitAbsorbingWalls(element, hit_mask)) break; } } else { if (HitElement(element, hit_mask)) break; } if (rf) DrawLaser(rf - 1, DL_LASER_ENABLED); rf = laser.num_edges; } #if 0 if (laser.dest_element != Feld[ELX][ELY]) { printf("ALARM: laser.dest_element == %d, Feld[ELX][ELY] == %d\n", laser.dest_element, Feld[ELX][ELY]); } #endif if (!end && !laser.stops_inside_element && !StepBehind()) { #if 0 printf("ScanLaser: Go one step back\n"); #endif LX -= XS; LY -= YS; AddLaserEdge(LX, LY); } if (rf) DrawLaser(rf - 1, DL_LASER_ENABLED); Ct = CT = FrameCounter; #if 0 if (!IN_LEV_FIELD(ELX, ELY)) printf("WARNING! (2) %d, %d\n", ELX, ELY); #endif } void DrawLaserExt(int start_edge, int num_edges, int mode) { int element; int elx, ely; #if 0 printf("DrawLaserExt: start_edge, num_edges, mode == %d, %d, %d\n", start_edge, num_edges, mode); #endif if (start_edge < 0) { Error(ERR_WARN, "DrawLaserExt: start_edge < 0"); return; } if (num_edges < 0) { Error(ERR_WARN, "DrawLaserExt: num_edges < 0"); return; } #if 0 if (mode == DL_LASER_DISABLED) { printf("DrawLaser: Delete laser from edge %d\n", start_edge); } #endif /* now draw the laser to the backbuffer and (if enabled) to the screen */ DrawLaserLines(&laser.edge[start_edge], num_edges, mode); redraw_mask |= REDRAW_FIELD; if (mode == DL_LASER_ENABLED) return; /* after the laser was deleted, the "damaged" graphics must be restored */ if (laser.num_damages) { int damage_start = 0; int i; /* determine the starting edge, from which graphics need to be restored */ if (start_edge > 0) { for (i = 0; i < laser.num_damages; i++) { if (laser.damage[i].edge == start_edge + 1) { damage_start = i; break; } } } /* restore graphics from this starting edge to the end of damage list */ for (i = damage_start; i < laser.num_damages; i++) { int lx = laser.damage[i].x; int ly = laser.damage[i].y; int element = Feld[lx][ly]; if (Hit[lx][ly] == laser.damage[i].edge) if (!((IS_BEAMER(element) || IS_FIBRE_OPTIC(element)) && i == damage_start)) Hit[lx][ly] = 0; if (Box[lx][ly] == laser.damage[i].edge) Box[lx][ly] = 0; if (IS_DRAWABLE(element)) DrawField_MM(lx, ly); } elx = laser.damage[damage_start].x; ely = laser.damage[damage_start].y; element = Feld[elx][ely]; #if 0 if (IS_BEAMER(element)) { int i; for (i = 0; i < laser.num_beamers; i++) printf("-> %d\n", laser.beamer_edge[i]); printf("DrawLaserExt: IS_BEAMER: [%d]: Hit[%d][%d] == %d [%d]\n", mode, elx, ely, Hit[elx][ely], start_edge); printf("DrawLaserExt: IS_BEAMER: %d / %d\n", get_element_angle(element), laser.damage[damage_start].angle); } #endif if ((IS_BEAMER(element) || IS_FIBRE_OPTIC(element)) && laser.num_beamers > 0 && start_edge == laser.beamer_edge[laser.num_beamers - 1]) { /* element is outgoing beamer */ laser.num_damages = damage_start + 1; if (IS_BEAMER(element)) laser.current_angle = get_element_angle(element); } else { /* element is incoming beamer or other element */ laser.num_damages = damage_start; laser.current_angle = laser.damage[laser.num_damages].angle; } } else { /* no damages but McDuffin himself (who needs to be redrawn anyway) */ elx = laser.start_edge.x; ely = laser.start_edge.y; element = Feld[elx][ely]; } laser.num_edges = start_edge + 1; if (start_edge == 0) laser.current_angle = laser.start_angle; LX = laser.edge[start_edge].x - cSX2; LY = laser.edge[start_edge].y - cSY2; XS = 2 * Step[laser.current_angle].x; YS = 2 * Step[laser.current_angle].y; #if 0 printf("DrawLaser: Set (LX, LY) to (%d, %d) [%d]\n", LX, LY, element); #endif if (start_edge > 0) { if (IS_BEAMER(element) || IS_FIBRE_OPTIC(element) || IS_PACMAN(element) || IS_POLAR(element) || IS_POLAR_CROSS(element) || element == EL_FUSE_ON) { int step_size; #if 0 printf("element == %d\n", element); #endif if (IS_22_5_ANGLE(laser.current_angle)) /* neither 90° nor 45° angle */ step_size = ((IS_BEAMER(element) || IS_FIBRE_OPTIC(element)) ? 4 : 3); else step_size = 8; if (IS_POLAR(element) || IS_POLAR_CROSS(element) || ((IS_BEAMER(element) || IS_FIBRE_OPTIC(element)) && (laser.num_beamers == 0 || start_edge != laser.beamer_edge[laser.num_beamers - 1]))) { /* element is incoming beamer or other element */ step_size = -step_size; laser.num_edges--; } #if 0 if (IS_BEAMER(element)) { printf("start_edge == %d, laser.beamer_edge == %d\n", start_edge, laser.beamer_edge); } #endif LX += step_size * XS; LY += step_size * YS; } else if (element != EL_EMPTY) { LX -= 3 * XS; LY -= 3 * YS; laser.num_edges--; } } #if 0 printf("DrawLaser: Finally: (LX, LY) to (%d, %d) [%d]\n", LX, LY, element); #endif } void DrawLaser(int start_edge, int mode) { if (laser.num_edges - start_edge < 0) { Error(ERR_WARN, "DrawLaser: laser.num_edges - start_edge < 0"); return; } /* check if laser is interrupted by beamer element */ if (laser.num_beamers > 0 && start_edge < laser.beamer_edge[laser.num_beamers - 1]) { if (mode == DL_LASER_ENABLED) { int i; int tmp_start_edge = start_edge; /* draw laser segments forward from the start to the last beamer */ for (i = 0; i < laser.num_beamers; i++) { int tmp_num_edges = laser.beamer_edge[i] - tmp_start_edge; if (tmp_num_edges <= 0) continue; #if 0 printf("DrawLaser: DL_LASER_ENABLED: i==%d: %d, %d\n", i, laser.beamer_edge[i], tmp_start_edge); #endif DrawLaserExt(tmp_start_edge, tmp_num_edges, DL_LASER_ENABLED); tmp_start_edge = laser.beamer_edge[i]; } /* draw last segment from last beamer to the end */ DrawLaserExt(tmp_start_edge, laser.num_edges - tmp_start_edge, DL_LASER_ENABLED); } else { int i; int last_num_edges = laser.num_edges; int num_beamers = laser.num_beamers; /* delete laser segments backward from the end to the first beamer */ for (i = num_beamers - 1; i >= 0; i--) { int tmp_num_edges = last_num_edges - laser.beamer_edge[i]; if (laser.beamer_edge[i] - start_edge <= 0) break; DrawLaserExt(laser.beamer_edge[i], tmp_num_edges, DL_LASER_DISABLED); last_num_edges = laser.beamer_edge[i]; laser.num_beamers--; } #if 0 if (last_num_edges - start_edge <= 0) printf("DrawLaser: DL_LASER_DISABLED: %d, %d\n", last_num_edges, start_edge); #endif // special case when rotating first beamer: delete laser edge on beamer // (but do not start scanning on previous edge to prevent mirror sound) if (last_num_edges - start_edge == 1 && start_edge > 0) DrawLaserLines(&laser.edge[start_edge - 1], 2, DL_LASER_DISABLED); /* delete first segment from start to the first beamer */ DrawLaserExt(start_edge, last_num_edges - start_edge, DL_LASER_DISABLED); } } else { DrawLaserExt(start_edge, laser.num_edges - start_edge, mode); } game_mm.laser_enabled = mode; } void DrawLaser_MM() { DrawLaser(0, game_mm.laser_enabled); } boolean HitElement(int element, int hit_mask) { if (HitOnlyAnEdge(element, hit_mask)) return FALSE; if (IS_MOVING(ELX, ELY) || IS_BLOCKED(ELX, ELY)) element = MovingOrBlocked2Element_MM(ELX, ELY); #if 0 printf("HitElement (1): element == %d\n", element); #endif #if 0 if ((ELX * TILEX + 14 - LX) * YS == (ELY * TILEY + 14 - LY) * XS) printf("HitElement (%d): EXACT MATCH @ (%d, %d)\n", element, ELX, ELY); else printf("HitElement (%d): FUZZY MATCH @ (%d, %d)\n", element, ELX, ELY); #endif AddDamagedField(ELX, ELY); /* this is more precise: check if laser would go through the center */ if ((ELX * TILEX + 14 - LX) * YS != (ELY * TILEY + 14 - LY) * XS) { /* skip the whole element before continuing the scan */ do { LX += XS; LY += YS; } while (ELX == LX/TILEX && ELY == LY/TILEY && LX > 0 && LY > 0); if (LX/TILEX > ELX || LY/TILEY > ELY) { /* skipping scan positions to the right and down skips one scan position too much, because this is only the top left scan position of totally four scan positions (plus one to the right, one to the bottom and one to the bottom right) */ LX -= XS; LY -= YS; } return FALSE; } #if 0 printf("HitElement (2): element == %d\n", element); #endif if (LX + 5 * XS < 0 || LY + 5 * YS < 0) { LX += 2 * XS; LY += 2 * YS; return FALSE; } #if 0 printf("HitElement (3): element == %d\n", element); #endif if (IS_POLAR(element) && ((element - EL_POLAR_START) % 2 || (element - EL_POLAR_START) / 2 != laser.current_angle % 8)) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); laser.num_damages--; return TRUE; } if (IS_POLAR_CROSS(element) && (element - EL_POLAR_CROSS_START) != laser.current_angle % 4) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); laser.num_damages--; return TRUE; } if (!IS_BEAMER(element) && !IS_FIBRE_OPTIC(element) && !IS_GRID_WOOD(element) && element != EL_FUEL_EMPTY) { #if 0 if ((ELX * TILEX + 14 - LX) * YS == (ELY * TILEY + 14 - LY) * XS) printf("EXACT MATCH @ (%d, %d)\n", ELX, ELY); else printf("FUZZY MATCH @ (%d, %d)\n", ELX, ELY); #endif LX = ELX * TILEX + 14; LY = ELY * TILEY + 14; AddLaserEdge(LX, LY); } if (IS_MIRROR(element) || IS_MIRROR_FIXED(element) || IS_POLAR(element) || IS_POLAR_CROSS(element) || IS_DF_MIRROR(element) || IS_DF_MIRROR_AUTO(element) || element == EL_PRISM || element == EL_REFRACTOR) { int current_angle = laser.current_angle; int step_size; laser.num_damages--; AddDamagedField(ELX, ELY); laser.damage[laser.num_damages - 1].is_mirror = TRUE; if (!Hit[ELX][ELY]) Hit[ELX][ELY] = laser.damage[laser.num_damages - 1].edge; if (IS_MIRROR(element) || IS_MIRROR_FIXED(element) || IS_DF_MIRROR(element) || IS_DF_MIRROR_AUTO(element)) laser.current_angle = get_mirrored_angle(laser.current_angle, get_element_angle(element)); if (element == EL_PRISM || element == EL_REFRACTOR) laser.current_angle = RND(16); XS = 2 * Step[laser.current_angle].x; YS = 2 * Step[laser.current_angle].y; if (!IS_22_5_ANGLE(laser.current_angle)) /* 90° or 45° angle */ step_size = 8; else step_size = 4; LX += step_size * XS; LY += step_size * YS; #if 0 /* draw sparkles on mirror */ if ((IS_MIRROR(element) || IS_MIRROR_FIXED(element)) && current_angle != laser.current_angle) { MoveSprite(vp, &Pfeil[2], 4 + 16 * ELX, 5 + 16 * ELY + 1); } #endif if ((!IS_POLAR(element) && !IS_POLAR_CROSS(element)) && current_angle != laser.current_angle) PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); laser.overloaded = (get_opposite_angle(laser.current_angle) == laser.damage[laser.num_damages - 1].angle ? TRUE : FALSE); return (laser.overloaded ? TRUE : FALSE); } if (element == EL_FUEL_FULL) { laser.stops_inside_element = TRUE; return TRUE; } if (element == EL_BOMB || element == EL_MINE) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); if (element == EL_MINE) laser.overloaded = TRUE; } if (element == EL_KETTLE || element == EL_CELL || element == EL_KEY || element == EL_LIGHTBALL || element == EL_PACMAN || IS_PACMAN(element)) { if (!IS_PACMAN(element)) Bang_MM(ELX, ELY); if (element == EL_PACMAN) Bang_MM(ELX, ELY); if (element == EL_KETTLE || element == EL_CELL) { if (game_mm.kettles_still_needed > 0) game_mm.kettles_still_needed--; game.snapshot.collected_item = TRUE; if (game_mm.kettles_still_needed == 0) { CheckExitMM(); DrawLaser(0, DL_LASER_ENABLED); } } else if (element == EL_KEY) { game_mm.num_keys++; } else if (IS_PACMAN(element)) { DeletePacMan(ELX, ELY); } RaiseScoreElement_MM(element); return FALSE; } if (element == EL_LIGHTBULB_OFF || element == EL_LIGHTBULB_ON) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); DrawLaser(0, DL_LASER_ENABLED); if (Feld[ELX][ELY] == EL_LIGHTBULB_OFF) { Feld[ELX][ELY] = EL_LIGHTBULB_ON; game_mm.lights_still_needed--; } else { Feld[ELX][ELY] = EL_LIGHTBULB_OFF; game_mm.lights_still_needed++; } DrawField_MM(ELX, ELY); DrawLaser(0, DL_LASER_ENABLED); /* BackToFront(); */ laser.stops_inside_element = TRUE; return TRUE; } #if 0 printf("HitElement (4): element == %d\n", element); #endif if ((IS_BEAMER(element) || IS_FIBRE_OPTIC(element)) && laser.num_beamers < MAX_NUM_BEAMERS && laser.beamer[BEAMER_NR(element)][1].num) { int beamer_angle = get_element_angle(element); int beamer_nr = BEAMER_NR(element); int step_size; #if 0 printf("HitElement (BEAMER): element == %d\n", element); #endif laser.num_damages--; if (IS_FIBRE_OPTIC(element) || laser.current_angle == get_opposite_angle(beamer_angle)) { int pos; LX = ELX * TILEX + 14; LY = ELY * TILEY + 14; AddLaserEdge(LX, LY); AddDamagedField(ELX, ELY); laser.damage[laser.num_damages - 1].is_mirror = TRUE; if (!Hit[ELX][ELY]) Hit[ELX][ELY] = laser.damage[laser.num_damages - 1].edge; pos = (ELX == laser.beamer[beamer_nr][0].x && ELY == laser.beamer[beamer_nr][0].y ? 1 : 0); ELX = laser.beamer[beamer_nr][pos].x; ELY = laser.beamer[beamer_nr][pos].y; LX = ELX * TILEX + 14; LY = ELY * TILEY + 14; if (IS_BEAMER(element)) { laser.current_angle = get_element_angle(Feld[ELX][ELY]); XS = 2 * Step[laser.current_angle].x; YS = 2 * Step[laser.current_angle].y; } laser.beamer_edge[laser.num_beamers] = laser.num_edges; AddLaserEdge(LX, LY); AddDamagedField(ELX, ELY); laser.damage[laser.num_damages - 1].is_mirror = TRUE; if (!Hit[ELX][ELY]) Hit[ELX][ELY] = laser.damage[laser.num_damages - 1].edge; if (laser.current_angle == (laser.current_angle >> 1) << 1) step_size = 8; else step_size = 4; LX += step_size * XS; LY += step_size * YS; laser.num_beamers++; return FALSE; } } return TRUE; } boolean HitOnlyAnEdge(int element, int hit_mask) { /* check if the laser hit only the edge of an element and, if so, go on */ #if 0 printf("LX, LY, hit_mask == %d, %d, %d\n", LX, LY, hit_mask); #endif if ((hit_mask == HIT_MASK_TOPLEFT || hit_mask == HIT_MASK_TOPRIGHT || hit_mask == HIT_MASK_BOTTOMLEFT || hit_mask == HIT_MASK_BOTTOMRIGHT) && laser.current_angle % 4) /* angle is not 90° */ { int dx, dy; if (hit_mask == HIT_MASK_TOPLEFT) { dx = -1; dy = -1; } else if (hit_mask == HIT_MASK_TOPRIGHT) { dx = +1; dy = -1; } else if (hit_mask == HIT_MASK_BOTTOMLEFT) { dx = -1; dy = +1; } else /* (hit_mask == HIT_MASK_BOTTOMRIGHT) */ { dx = +1; dy = +1; } AddDamagedField((LX + 2 * dx) / TILEX, (LY + 2 * dy) / TILEY); LX += XS; LY += YS; #if 0 printf("[HitOnlyAnEdge() == TRUE]\n"); #endif return TRUE; } #if 0 printf("[HitOnlyAnEdge() == FALSE]\n"); #endif return FALSE; } boolean HitPolarizer(int element, int hit_mask) { if (HitOnlyAnEdge(element, hit_mask)) return FALSE; if (IS_DF_GRID(element)) { int grid_angle = get_element_angle(element); #if 0 printf("HitPolarizer: angle: grid == %d, laser == %d\n", grid_angle, laser.current_angle); #endif AddLaserEdge(LX, LY); AddDamagedField(ELX, ELY); if (!Hit[ELX][ELY]) Hit[ELX][ELY] = laser.damage[laser.num_damages - 1].edge; if (laser.current_angle == grid_angle || laser.current_angle == get_opposite_angle(grid_angle)) { /* skip the whole element before continuing the scan */ do { LX += XS; LY += YS; } while (ELX == LX/TILEX && ELY == LY/TILEY && LX > 0 && LY > 0); if (LX/TILEX > ELX || LY/TILEY > ELY) { /* skipping scan positions to the right and down skips one scan position too much, because this is only the top left scan position of totally four scan positions (plus one to the right, one to the bottom and one to the bottom right) */ LX -= XS; LY -= YS; } AddLaserEdge(LX, LY); LX += XS; LY += YS; #if 0 printf("HitPolarizer: LX, LY == %d, %d [%d, %d] [%d, %d]\n", LX, LY, LX / TILEX, LY / TILEY, LX % TILEX, LY % TILEY); #endif return FALSE; } else if (IS_GRID_STEEL_FIXED(element) || IS_GRID_STEEL_AUTO(element)) { return HitReflectingWalls(element, hit_mask); } else { return HitAbsorbingWalls(element, hit_mask); } } else if (IS_GRID_STEEL(element)) { return HitReflectingWalls(element, hit_mask); } else /* IS_GRID_WOOD */ { return HitAbsorbingWalls(element, hit_mask); } return TRUE; } boolean HitBlock(int element, int hit_mask) { boolean check = FALSE; if ((element == EL_GATE_STONE || element == EL_GATE_WOOD) && game_mm.num_keys == 0) check = TRUE; if (element == EL_BLOCK_STONE || element == EL_BLOCK_WOOD) { int i, x, y; int ex = ELX * TILEX + 14; int ey = ELY * TILEY + 14; check = TRUE; for (i = 1; i < 32; i++) { x = LX + i * XS; y = LY + i * YS; if ((x == ex || x == ex + 1) && (y == ey || y == ey + 1)) check = FALSE; } } if (check && (element == EL_BLOCK_WOOD || element == EL_GATE_WOOD)) return HitAbsorbingWalls(element, hit_mask); if (check) { AddLaserEdge(LX - XS, LY - YS); AddDamagedField(ELX, ELY); if (!Box[ELX][ELY]) Box[ELX][ELY] = laser.num_edges; return HitReflectingWalls(element, hit_mask); } if (element == EL_GATE_STONE || element == EL_GATE_WOOD) { int xs = XS / 2, ys = YS / 2; int hit_mask_diagonal1 = HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT; int hit_mask_diagonal2 = HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT; if ((hit_mask & hit_mask_diagonal1) == hit_mask_diagonal1 || (hit_mask & hit_mask_diagonal2) == hit_mask_diagonal2) { laser.overloaded = (element == EL_GATE_STONE); return TRUE; } if (ABS(xs) == 1 && ABS(ys) == 1 && (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT || hit_mask == HIT_MASK_BOTTOM)) AddDamagedField(ELX - xs * (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_BOTTOM), ELY - ys * (hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT)); AddLaserEdge(LX, LY); Bang_MM(ELX, ELY); game_mm.num_keys--; if (element == EL_GATE_STONE && Box[ELX][ELY]) { DrawLaser(Box[ELX][ELY] - 1, DL_LASER_DISABLED); /* BackToFront(); */ ScanLaser(); return TRUE; } return FALSE; } if (element == EL_BLOCK_STONE || element == EL_BLOCK_WOOD) { int xs = XS / 2, ys = YS / 2; int hit_mask_diagonal1 = HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT; int hit_mask_diagonal2 = HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT; if ((hit_mask & hit_mask_diagonal1) == hit_mask_diagonal1 || (hit_mask & hit_mask_diagonal2) == hit_mask_diagonal2) { laser.overloaded = (element == EL_BLOCK_STONE); return TRUE; } if (ABS(xs) == 1 && ABS(ys) == 1 && (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT || hit_mask == HIT_MASK_BOTTOM)) AddDamagedField(ELX - xs * (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_BOTTOM), ELY - ys * (hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT)); AddDamagedField(ELX, ELY); LX = ELX * TILEX + 14; LY = ELY * TILEY + 14; AddLaserEdge(LX, LY); laser.stops_inside_element = TRUE; return TRUE; } return TRUE; } boolean HitLaserSource(int element, int hit_mask) { if (HitOnlyAnEdge(element, hit_mask)) return FALSE; PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); laser.overloaded = TRUE; return TRUE; } boolean HitLaserDestination(int element, int hit_mask) { if (HitOnlyAnEdge(element, hit_mask)) return FALSE; if (element != EL_EXIT_OPEN && !(IS_RECEIVER(element) && game_mm.kettles_still_needed == 0 && laser.current_angle == get_opposite_angle(get_element_angle(element)))) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); return TRUE; } if (IS_RECEIVER(element) || (IS_22_5_ANGLE(laser.current_angle) && (ELX != (LX + 6 * XS) / TILEX || ELY != (LY + 6 * YS) / TILEY || LX + 6 * XS < 0 || LY + 6 * YS < 0))) { LX -= XS; LY -= YS; } else { LX = ELX * TILEX + 14; LY = ELY * TILEY + 14; laser.stops_inside_element = TRUE; } AddLaserEdge(LX, LY); AddDamagedField(ELX, ELY); if (game_mm.lights_still_needed == 0) { game_mm.level_solved = TRUE; SetTileCursorActive(FALSE); } return TRUE; } boolean HitReflectingWalls(int element, int hit_mask) { /* check if laser hits side of a wall with an angle that is not 90° */ if (!IS_90_ANGLE(laser.current_angle) && (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT || hit_mask == HIT_MASK_BOTTOM)) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); LX -= XS; LY -= YS; if (!IS_DF_GRID(element)) AddLaserEdge(LX, LY); /* check if laser hits wall with an angle of 45° */ if (!IS_22_5_ANGLE(laser.current_angle)) { if (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_BOTTOM) { LX += 2 * XS; laser.current_angle = get_mirrored_angle(laser.current_angle, ANG_MIRROR_0); } else /* hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT */ { LY += 2 * YS; laser.current_angle = get_mirrored_angle(laser.current_angle, ANG_MIRROR_90); } AddLaserEdge(LX, LY); XS = 2 * Step[laser.current_angle].x; YS = 2 * Step[laser.current_angle].y; return FALSE; } else if (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_BOTTOM) { laser.current_angle = get_mirrored_angle(laser.current_angle, ANG_MIRROR_0); if (ABS(XS) == 4) { LX += 2 * XS; if (!IS_DF_GRID(element)) AddLaserEdge(LX, LY); } else { LX += XS; if (!IS_DF_GRID(element)) AddLaserEdge(LX, LY + YS / 2); LX += XS; if (!IS_DF_GRID(element)) AddLaserEdge(LX, LY); } YS = 2 * Step[laser.current_angle].y; return FALSE; } else /* hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT */ { laser.current_angle = get_mirrored_angle(laser.current_angle, ANG_MIRROR_90); if (ABS(YS) == 4) { LY += 2 * YS; if (!IS_DF_GRID(element)) AddLaserEdge(LX, LY); } else { LY += YS; if (!IS_DF_GRID(element)) AddLaserEdge(LX + XS / 2, LY); LY += YS; if (!IS_DF_GRID(element)) AddLaserEdge(LX, LY); } XS = 2 * Step[laser.current_angle].x; return FALSE; } } /* reflection at the edge of reflecting DF style wall */ if (IS_DF_WALL_STEEL(element) && IS_22_5_ANGLE(laser.current_angle)) { if (((laser.current_angle == 1 || laser.current_angle == 3) && hit_mask == HIT_MASK_TOPRIGHT) || ((laser.current_angle == 5 || laser.current_angle == 7) && hit_mask == HIT_MASK_TOPLEFT) || ((laser.current_angle == 9 || laser.current_angle == 11) && hit_mask == HIT_MASK_BOTTOMLEFT) || ((laser.current_angle == 13 || laser.current_angle == 15) && hit_mask == HIT_MASK_BOTTOMRIGHT)) { int mirror_angle = (hit_mask == HIT_MASK_TOPRIGHT || hit_mask == HIT_MASK_BOTTOMLEFT ? ANG_MIRROR_135 : ANG_MIRROR_45); PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); AddDamagedField(ELX, ELY); AddLaserEdge(LX, LY); laser.current_angle = get_mirrored_angle(laser.current_angle, mirror_angle); XS = 8 / -XS; YS = 8 / -YS; LX += XS; LY += YS; AddLaserEdge(LX, LY); return FALSE; } } /* reflection inside an edge of reflecting DF style wall */ if (IS_DF_WALL_STEEL(element) && IS_22_5_ANGLE(laser.current_angle)) { if (((laser.current_angle == 1 || laser.current_angle == 3) && hit_mask == (HIT_MASK_ALL ^ HIT_MASK_BOTTOMLEFT)) || ((laser.current_angle == 5 || laser.current_angle == 7) && hit_mask == (HIT_MASK_ALL ^ HIT_MASK_BOTTOMRIGHT)) || ((laser.current_angle == 9 || laser.current_angle == 11) && hit_mask == (HIT_MASK_ALL ^ HIT_MASK_TOPRIGHT)) || ((laser.current_angle == 13 || laser.current_angle == 15) && hit_mask == (HIT_MASK_ALL ^ HIT_MASK_TOPLEFT))) { int mirror_angle = (hit_mask == (HIT_MASK_ALL ^ HIT_MASK_BOTTOMLEFT) || hit_mask == (HIT_MASK_ALL ^ HIT_MASK_TOPRIGHT) ? ANG_MIRROR_135 : ANG_MIRROR_45); PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); /* AddDamagedField(ELX, ELY); */ AddLaserEdge(LX - XS, LY - YS); AddLaserEdge(LX - XS + (ABS(XS) == 4 ? XS/2 : 0), LY - YS + (ABS(YS) == 4 ? YS/2 : 0)); laser.current_angle = get_mirrored_angle(laser.current_angle, mirror_angle); XS = 8 / -XS; YS = 8 / -YS; LX += XS; LY += YS; AddLaserEdge(LX, LY); return FALSE; } } /* check if laser hits DF style wall with an angle of 90° */ if (IS_DF_WALL(element) && IS_90_ANGLE(laser.current_angle)) { if ((IS_HORIZ_ANGLE(laser.current_angle) && (!(hit_mask & HIT_MASK_TOP) || !(hit_mask & HIT_MASK_BOTTOM))) || (IS_VERT_ANGLE(laser.current_angle) && (!(hit_mask & HIT_MASK_LEFT) || !(hit_mask & HIT_MASK_RIGHT)))) { /* laser at last step touched nothing or the same side of the wall */ if (LX != last_LX || LY != last_LY || hit_mask == last_hit_mask) { AddDamagedField(ELX, ELY); LX += 8 * XS; LY += 8 * YS; last_LX = LX; last_LY = LY; last_hit_mask = hit_mask; return FALSE; } } } if (!HitOnlyAnEdge(element, hit_mask)) { laser.overloaded = TRUE; return TRUE; } return FALSE; } boolean HitAbsorbingWalls(int element, int hit_mask) { if (HitOnlyAnEdge(element, hit_mask)) return FALSE; if (ABS(XS) == 4 && (hit_mask == HIT_MASK_LEFT || hit_mask == HIT_MASK_RIGHT)) { AddLaserEdge(LX - XS, LY - YS); LX = LX + XS / 2; LY = LY + YS; } if (ABS(YS) == 4 && (hit_mask == HIT_MASK_TOP || hit_mask == HIT_MASK_BOTTOM)) { AddLaserEdge(LX - XS, LY - YS); LX = LX + XS; LY = LY + YS / 2; } if (IS_WALL_WOOD(element) || IS_DF_WALL_WOOD(element) || IS_GRID_WOOD(element) || IS_GRID_WOOD_FIXED(element) || IS_GRID_WOOD_AUTO(element) || element == EL_FUSE_ON || element == EL_BLOCK_WOOD || element == EL_GATE_WOOD) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING); return TRUE; } if (IS_WALL_ICE(element)) { int mask; mask = (LX + XS) / MINI_TILEX - ELX * 2 + 1; /* Quadrant (horizontal) */ mask <<= (((LY + YS) / MINI_TILEY - ELY * 2) > 0) * 2; /* || (vertical) */ /* check if laser hits wall with an angle of 90° */ if (IS_90_ANGLE(laser.current_angle)) mask += mask * (2 + IS_HORIZ_ANGLE(laser.current_angle) * 2); if (mask == 1 || mask == 2 || mask == 4 || mask == 8) { int i; for (i = 0; i < 4; i++) { if (mask == (1 << i) && (XS > 0) == (i % 2) && (YS > 0) == (i / 2)) mask = 15 - (8 >> i); else if (ABS(XS) == 4 && mask == (1 << i) && (XS > 0) == (i % 2) && (YS < 0) == (i / 2)) mask = 3 + (i / 2) * 9; else if (ABS(YS) == 4 && mask == (1 << i) && (XS < 0) == (i % 2) && (YS > 0) == (i / 2)) mask = 5 + (i % 2) * 5; } } laser.wall_mask = mask; } else if (IS_WALL_AMOEBA(element)) { int elx = (LX - 2 * XS) / TILEX; int ely = (LY - 2 * YS) / TILEY; int element2 = Feld[elx][ely]; int mask; if (element2 != EL_EMPTY && !IS_WALL_AMOEBA(element2)) { laser.dest_element = EL_EMPTY; return TRUE; } ELX = elx; ELY = ely; mask = (LX - 2 * XS) / 16 - ELX * 2 + 1; mask <<= ((LY - 2 * YS) / 16 - ELY * 2) * 2; if (IS_90_ANGLE(laser.current_angle)) mask += mask * (2 + IS_HORIZ_ANGLE(laser.current_angle) * 2); laser.dest_element = element2 | EL_WALL_AMOEBA; laser.wall_mask = mask; } return TRUE; } void OpenExit(int x, int y) { int delay = 6; if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 4 * delay; if (MovDelay[x][y]) /* wait some time before next frame */ { int phase; MovDelay[x][y]--; phase = MovDelay[x][y] / delay; if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y)) DrawGraphicAnimation_MM(x, y, IMG_MM_EXIT_OPENING, 3 - phase); if (!MovDelay[x][y]) { Feld[x][y] = EL_EXIT_OPEN; DrawField_MM(x, y); } } } void OpenSurpriseBall(int x, int y) { int delay = 2; if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 50 * delay; if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y)) { Bitmap *bitmap; int graphic = el2gfx(Store[x][y]); int gx, gy; int dx = RND(26), dy = RND(26); getGraphicSource(graphic, 0, &bitmap, &gx, &gy); BlitBitmap(bitmap, drawto, gx + dx, gy + dy, 6, 6, cSX + x * TILEX + dx, cSY + y * TILEY + dy); MarkTileDirty(x, y); } if (!MovDelay[x][y]) { Feld[x][y] = Store[x][y]; Store[x][y] = 0; DrawField_MM(x, y); ScanLaser(); } } } void MeltIce(int x, int y) { int frames = 5; int delay = 5; if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = frames * delay; if (MovDelay[x][y]) /* wait some time before next frame */ { int phase; int wall_mask = Store2[x][y]; int real_element = Feld[x][y] - EL_WALL_CHANGING + EL_WALL_ICE; MovDelay[x][y]--; phase = frames - MovDelay[x][y] / delay - 1; if (!MovDelay[x][y]) { int i; Feld[x][y] = real_element & (wall_mask ^ 0xFF); Store[x][y] = Store2[x][y] = 0; DrawWalls_MM(x, y, Feld[x][y]); if (Feld[x][y] == EL_WALL_ICE) Feld[x][y] = EL_EMPTY; for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i >= 0; i--) if (laser.damage[i].is_mirror) break; if (i > 0) DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED); else DrawLaser(0, DL_LASER_DISABLED); ScanLaser(); } else if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y)) { DrawWallsAnimation_MM(x, y, real_element, phase, wall_mask); laser.redraw = TRUE; } } } void GrowAmoeba(int x, int y) { int frames = 5; int delay = 1; if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = frames * delay; if (MovDelay[x][y]) /* wait some time before next frame */ { int phase; int wall_mask = Store2[x][y]; int real_element = Feld[x][y] - EL_WALL_CHANGING + EL_WALL_AMOEBA; MovDelay[x][y]--; phase = MovDelay[x][y] / delay; if (!MovDelay[x][y]) { Feld[x][y] = real_element; Store[x][y] = Store2[x][y] = 0; DrawWalls_MM(x, y, Feld[x][y]); DrawLaser(0, DL_LASER_ENABLED); } else if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y)) { DrawWallsAnimation_MM(x, y, real_element, phase, wall_mask); } } } static void Explode_MM(int x, int y, int phase, int mode) { int num_phase = 9, delay = 2; int last_phase = num_phase * delay; int half_phase = (num_phase / 2) * delay; laser.redraw = TRUE; if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */ { int center_element = Feld[x][y]; if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) { /* put moving element to center field (and let it explode there) */ center_element = MovingOrBlocked2Element_MM(x, y); RemoveMovingField_MM(x, y); Feld[x][y] = center_element; } if (center_element == EL_BOMB || IS_MCDUFFIN(center_element)) Store[x][y] = center_element; else Store[x][y] = EL_EMPTY; Store2[x][y] = mode; Feld[x][y] = EL_EXPLODING_OPAQUE; MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0; Frame[x][y] = 1; return; } Frame[x][y] = (phase < last_phase ? phase + 1 : 0); if (phase == half_phase) { Feld[x][y] = EL_EXPLODING_TRANSP; if (x == ELX && y == ELY) ScanLaser(); } if (phase == last_phase) { if (Store[x][y] == EL_BOMB) { DrawLaser(0, DL_LASER_DISABLED); InitLaser(); Bang_MM(laser.start_edge.x, laser.start_edge.y); Store[x][y] = EL_EMPTY; game_mm.game_over = TRUE; game_mm.game_over_cause = GAME_OVER_BOMB; SetTileCursorActive(FALSE); laser.overloaded = FALSE; } else if (IS_MCDUFFIN(Store[x][y])) { Store[x][y] = EL_EMPTY; game.restart_game_message = "Bomb killed Mc Duffin ! Play it again ?"; } Feld[x][y] = Store[x][y]; Store[x][y] = Store2[x][y] = 0; MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0; InitField(x, y, FALSE); DrawField_MM(x, y); } else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { int graphic = IMG_MM_DEFAULT_EXPLODING; int graphic_phase = (phase / delay - 1); Bitmap *bitmap; int src_x, src_y; if (Store2[x][y] == EX_KETTLE) { if (graphic_phase < 3) { graphic = IMG_MM_KETTLE_EXPLODING; } else if (graphic_phase < 5) { graphic_phase += 3; } else { graphic = IMG_EMPTY; graphic_phase = 0; } } else if (Store2[x][y] == EX_SHORT) { if (graphic_phase < 4) { graphic_phase += 4; } else { graphic = IMG_EMPTY; graphic_phase = 0; } } getGraphicSource(graphic, graphic_phase, &bitmap, &src_x, &src_y); BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY, cFX + x * TILEX, cFY + y * TILEY); MarkTileDirty(x, y); } } static void Bang_MM(int x, int y) { int element = Feld[x][y]; int mode = EX_NORMAL; #if 0 DrawLaser(0, DL_LASER_ENABLED); #endif switch(element) { case EL_KETTLE: mode = EX_KETTLE; break; case EL_GATE_STONE: case EL_GATE_WOOD: mode = EX_SHORT; break; default: mode = EX_NORMAL; break; } if (IS_PACMAN(element)) PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING); else if (element == EL_BOMB || IS_MCDUFFIN(element)) PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING); else if (element == EL_KEY) PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING); else PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING); Explode_MM(x, y, EX_PHASE_START, mode); } 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 old_move_dir = MovDir[x][y]; int right_dir = turn[old_move_dir].right; int back_dir = turn[old_move_dir].back; int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y; int right_x = x + right_dx, right_y = y + right_dy; if (element == EL_PACMAN) { boolean can_turn_right = FALSE; if (IN_LEV_FIELD(right_x, right_y) && IS_EATABLE4PACMAN(Feld[right_x][right_y])) can_turn_right = TRUE; if (can_turn_right) MovDir[x][y] = right_dir; else MovDir[x][y] = back_dir; MovDelay[x][y] = 0; } } static void StartMoving_MM(int x, int y) { int element = Feld[x][y]; if (Stop[x][y]) return; if (CAN_MOVE(element)) { int newx, newy; if (MovDelay[x][y]) /* wait some time before next movement */ { MovDelay[x][y]--; if (MovDelay[x][y]) return; } /* now make next step */ Moving2Blocked_MM(x, y, &newx, &newy); /* get next screen position */ if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) && IS_EATABLE4PACMAN(Feld[newx][newy]) && !ObjHit(newx, newy, HIT_POS_CENTER)) { Store[newx][newy] = Feld[newx][newy]; Feld[newx][newy] = EL_EMPTY; DrawField_MM(newx, newy); } else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy) || ObjHit(newx, newy, HIT_POS_CENTER)) { /* object was running against a wall */ TurnRound(x, y); return; } InitMovingField_MM(x, y, MovDir[x][y]); } if (MovDir[x][y]) ContinueMoving_MM(x, y); } static void ContinueMoving_MM(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 horiz_move = (dx!=0); int newx = x + dx, newy = y + dy; int step = (horiz_move ? dx : dy) * TILEX / 8; MovPos[x][y] += step; if (ABS(MovPos[x][y]) >= TILEX) /* object reached its destination */ { Feld[x][y] = EL_EMPTY; Feld[newx][newy] = element; MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; MovDelay[newx][newy] = 0; if (!CAN_MOVE(element)) MovDir[newx][newy] = 0; DrawField_MM(x, y); DrawField_MM(newx, newy); Stop[newx][newy] = TRUE; if (element == EL_PACMAN) { if (Store[newx][newy] == EL_BOMB) Bang_MM(newx, newy); if (IS_WALL_AMOEBA(Store[newx][newy]) && (LX + 2 * XS) / TILEX == newx && (LY + 2 * YS) / TILEY == newy) { laser.num_edges--; ScanLaser(); } } } else /* still moving on */ { DrawField_MM(x, y); } laser.redraw = TRUE; } boolean ClickElement(int x, int y, int button) { static unsigned int click_delay = 0; static int click_delay_value = CLICK_DELAY; static boolean new_button = TRUE; boolean element_clicked = FALSE; int element; if (button == -1) { /* initialize static variables */ click_delay = 0; click_delay_value = CLICK_DELAY; new_button = TRUE; return FALSE; } /* do not rotate objects hit by the laser after the game was solved */ if (game_mm.level_solved && Hit[x][y]) return FALSE; if (button == MB_RELEASED) { new_button = TRUE; click_delay_value = CLICK_DELAY; /* release eventually hold auto-rotating mirror */ RotateMirror(x, y, MB_RELEASED); return FALSE; } if (!FrameReached(&click_delay, click_delay_value) && !new_button) return FALSE; if (button == MB_MIDDLEBUTTON) /* middle button has no function */ return FALSE; if (!IN_LEV_FIELD(x, y)) return FALSE; if (Feld[x][y] == EL_EMPTY) return FALSE; element = Feld[x][y]; if (IS_MIRROR(element) || IS_BEAMER(element) || IS_POLAR(element) || IS_POLAR_CROSS(element) || IS_DF_MIRROR(element) || IS_DF_MIRROR_AUTO(element)) { RotateMirror(x, y, button); element_clicked = TRUE; } else if (IS_MCDUFFIN(element)) { if (!laser.fuse_off) { DrawLaser(0, DL_LASER_DISABLED); /* BackToFront(); */ } element = get_rotated_element(element, BUTTON_ROTATION(button)); laser.start_angle = get_element_angle(element); InitLaser(); Feld[x][y] = element; DrawField_MM(x, y); /* BackToFront(); */ if (!laser.fuse_off) ScanLaser(); element_clicked = TRUE; } else if (element == EL_FUSE_ON && laser.fuse_off) { if (x != laser.fuse_x || y != laser.fuse_y) return FALSE; laser.fuse_off = FALSE; laser.fuse_x = laser.fuse_y = -1; DrawGraphic_MM(x, y, IMG_MM_FUSE_ACTIVE); ScanLaser(); element_clicked = TRUE; } else if (element == EL_FUSE_ON && !laser.fuse_off && new_button) { laser.fuse_off = TRUE; laser.fuse_x = x; laser.fuse_y = y; laser.overloaded = FALSE; DrawLaser(0, DL_LASER_DISABLED); DrawGraphic_MM(x, y, IMG_MM_FUSE); element_clicked = TRUE; } else if (element == EL_LIGHTBALL) { Bang_MM(x, y); RaiseScoreElement_MM(element); DrawLaser(0, DL_LASER_ENABLED); element_clicked = TRUE; } click_delay_value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY); new_button = FALSE; return element_clicked; } void RotateMirror(int x, int y, int button) { if (button == MB_RELEASED) { /* release eventually hold auto-rotating mirror */ hold_x = -1; hold_y = -1; return; } if (IS_MIRROR(Feld[x][y]) || IS_POLAR_CROSS(Feld[x][y]) || IS_POLAR(Feld[x][y]) || IS_BEAMER(Feld[x][y]) || IS_DF_MIRROR(Feld[x][y]) || IS_GRID_STEEL_AUTO(Feld[x][y]) || IS_GRID_WOOD_AUTO(Feld[x][y])) { Feld[x][y] = get_rotated_element(Feld[x][y], BUTTON_ROTATION(button)); } else if (IS_DF_MIRROR_AUTO(Feld[x][y])) { if (button == MB_LEFTBUTTON) { /* left mouse button only for manual adjustment, no auto-rotating; freeze mirror for until mouse button released */ hold_x = x; hold_y = y; } else if (button == MB_RIGHTBUTTON && (hold_x != x || hold_y != y)) { Feld[x][y] = get_rotated_element(Feld[x][y], ROTATE_RIGHT); } } if (IS_GRID_STEEL_AUTO(Feld[x][y]) || IS_GRID_WOOD_AUTO(Feld[x][y])) { int edge = Hit[x][y]; DrawField_MM(x, y); if (edge > 0) { DrawLaser(edge - 1, DL_LASER_DISABLED); ScanLaser(); } } else if (ObjHit(x, y, HIT_POS_CENTER)) { int edge = Hit[x][y]; if (edge == 0) { Error(ERR_WARN, "RotateMirror: inconsistent field Hit[][]!\n"); edge = 1; } DrawLaser(edge - 1, DL_LASER_DISABLED); ScanLaser(); } else { int check = 1; if (ObjHit(x, y, HIT_POS_EDGE | HIT_POS_BETWEEN)) check = 2; DrawField_MM(x, y); if ((IS_BEAMER(Feld[x][y]) || IS_POLAR(Feld[x][y]) || IS_POLAR_CROSS(Feld[x][y])) && x == ELX && y == ELY) { check = 0; if (IS_BEAMER(Feld[x][y])) { #if 0 printf("TEST (%d, %d) [%d] [%d]\n", LX, LY, laser.beamer_edge, laser.beamer[1].num); #endif laser.num_edges--; } ScanLaser(); } if (check == 2) DrawLaser(0, DL_LASER_ENABLED); } } void AutoRotateMirrors() { int x, y; if (!FrameReached(&rotate_delay, AUTO_ROTATE_DELAY)) return; for (x = 0; x < lev_fieldx; x++) { for (y = 0; y < lev_fieldy; y++) { int element = Feld[x][y]; /* do not rotate objects hit by the laser after the game was solved */ if (game_mm.level_solved && Hit[x][y]) continue; if (IS_DF_MIRROR_AUTO(element) || IS_GRID_WOOD_AUTO(element) || IS_GRID_STEEL_AUTO(element) || element == EL_REFRACTOR) RotateMirror(x, y, MB_RIGHTBUTTON); } } } boolean ObjHit(int obx, int oby, int bits) { int i; obx *= TILEX; oby *= TILEY; if (bits & HIT_POS_CENTER) { if (CheckLaserPixel(cSX + obx + 15, cSY + oby + 15)) return TRUE; } if (bits & HIT_POS_EDGE) { for (i = 0; i < 4; i++) if (CheckLaserPixel(cSX + obx + 31 * (i % 2), cSY + oby + 31 * (i / 2))) return TRUE; } if (bits & HIT_POS_BETWEEN) { for (i = 0; i < 4; i++) if (CheckLaserPixel(cSX + 4 + obx + 22 * (i % 2), cSY + 4 + oby + 22 * (i / 2))) return TRUE; } return FALSE; } void DeletePacMan(int px, int py) { int i, j; Bang_MM(px, py); if (game_mm.num_pacman <= 1) { game_mm.num_pacman = 0; return; } for (i = 0; i < game_mm.num_pacman; i++) if (game_mm.pacman[i].x == px && game_mm.pacman[i].y == py) break; game_mm.num_pacman--; for (j = i; j < game_mm.num_pacman; j++) { game_mm.pacman[j].x = game_mm.pacman[j + 1].x; game_mm.pacman[j].y = game_mm.pacman[j + 1].y; game_mm.pacman[j].dir = game_mm.pacman[j + 1].dir; } } void ColorCycling(void) { static int CC, Cc = 0; static int color, old = 0xF00, new = 0x010, mult = 1; static unsigned short red, green, blue; if (color_status == STATIC_COLORS) return; CC = FrameCounter; if (CC < Cc || CC > Cc + 2) { Cc = CC; color = old + new * mult; if (mult > 0) mult++; else mult--; if (ABS(mult) == 16) { mult =- mult / 16; old = color; new = new << 4; if (new > 0x100) new = 0x001; } red = 0x0e00 * ((color & 0xF00) >> 8); green = 0x0e00 * ((color & 0x0F0) >> 4); blue = 0x0e00 * ((color & 0x00F)); SetRGB(pen_magicolor[0], red, green, blue); red = 0x1111 * ((color & 0xF00) >> 8); green = 0x1111 * ((color & 0x0F0) >> 4); blue = 0x1111 * ((color & 0x00F)); SetRGB(pen_magicolor[1], red, green, blue); } } static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode) { int element; int x, y, i; int r, d; for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) Stop[x][y] = FALSE; for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) { element = Feld[x][y]; if (!IS_MOVING(x, y) && CAN_MOVE(element)) StartMoving_MM(x, y); else if (IS_MOVING(x, y)) ContinueMoving_MM(x, y); else if (IS_EXPLODING(element)) Explode_MM(x, y, Frame[x][y], EX_NORMAL); else if (element == EL_EXIT_OPENING) OpenExit(x, y); else if (element == EL_GRAY_BALL_OPENING) OpenSurpriseBall(x, y); else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_ICE) MeltIce(x, y); else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_AMOEBA) GrowAmoeba(x, y); } AutoRotateMirrors(); #if 1 /* !!! CHANGE THIS: REDRAW ONLY WHEN NEEDED !!! */ /* redraw after Explode_MM() ... */ if (laser.redraw) DrawLaser(0, DL_LASER_ENABLED); laser.redraw = FALSE; #endif CT = FrameCounter; if (game_mm.num_pacman && FrameReached(&pacman_delay, PACMAN_MOVE_DELAY)) { MovePacMen(); if (laser.num_damages > MAX_LASER_LEN && !laser.fuse_off) { DrawLaser(0, DL_LASER_DISABLED); ScanLaser(); } } if (FrameReached(&energy_delay, ENERGY_DELAY)) { if (game_mm.energy_left > 0) { game_mm.energy_left--; #if 0 BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX5 + XX_ENERGY, DOOR_GFX_PAGEY1 + YY_ENERGY, ENERGY_XSIZE, ENERGY_YSIZE - game_mm.energy_left, DX_ENERGY, DY_ENERGY); #endif redraw_mask |= REDRAW_DOOR_1; } else if (setup.time_limit && !game_mm.game_over) { int i; for (i = 15; i >= 0; i--) { #if 0 SetRGB(pen_ray, 0x0000, 0x0000, i * color_scale); #endif pen_ray = GetPixelFromRGB(window, native_mm_level.laser_red * 0x11 * i, native_mm_level.laser_green * 0x11 * i, native_mm_level.laser_blue * 0x11 * i); DrawLaser(0, DL_LASER_ENABLED); BackToFront(); Delay(50); } StopSound_MM(SND_MM_GAME_HEALTH_CHARGING); #if 0 FadeMusic(); #endif DrawLaser(0, DL_LASER_DISABLED); game_mm.game_over = TRUE; game_mm.game_over_cause = GAME_OVER_NO_ENERGY; SetTileCursorActive(FALSE); game.restart_game_message = "Out of magic energy ! Play it again ?"; #if 0 if (Request("Out of magic energy ! Play it again ?", REQ_ASK | REQ_STAY_CLOSED)) { InitGame(); } else { game_status = MAINMENU; DrawMainMenu(); } #endif return; } } element = laser.dest_element; #if 0 if (element != Feld[ELX][ELY]) { printf("element == %d, Feld[ELX][ELY] == %d\n", element, Feld[ELX][ELY]); } #endif if (!laser.overloaded && laser.overload_value == 0 && element != EL_BOMB && element != EL_MINE && element != EL_BALL_GRAY && element != EL_BLOCK_STONE && element != EL_BLOCK_WOOD && element != EL_FUSE_ON && element != EL_FUEL_FULL && !IS_WALL_ICE(element) && !IS_WALL_AMOEBA(element)) return; if (((laser.overloaded && laser.overload_value < MAX_LASER_OVERLOAD) || (!laser.overloaded && laser.overload_value > 0)) && FrameReached(&overload_delay, HEALTH_DELAY(laser.overloaded))) { if (laser.overloaded) laser.overload_value++; else laser.overload_value--; if (game_mm.cheat_no_overload) { laser.overloaded = FALSE; laser.overload_value = 0; } game_mm.laser_overload_value = laser.overload_value; if (laser.overload_value < MAX_LASER_OVERLOAD - 8) { int color_up = 0xFF * laser.overload_value / MAX_LASER_OVERLOAD; int color_down = 0xFF - color_up; #if 0 SetRGB(pen_ray, (laser.overload_value / 6) * color_scale, 0x0000, (15 - (laser.overload_value / 6)) * color_scale); #endif pen_ray = GetPixelFromRGB(window, (native_mm_level.laser_red ? 0xFF : color_up), (native_mm_level.laser_green ? color_down : 0x00), (native_mm_level.laser_blue ? color_down : 0x00)); DrawLaser(0, DL_LASER_ENABLED); #if 0 BackToFront(); #endif } if (!laser.overloaded) StopSound_MM(SND_MM_GAME_HEALTH_CHARGING); else if (setup.sound_loops) PlaySoundLoop_MM(SND_MM_GAME_HEALTH_CHARGING); else PlaySound_MM(SND_MM_GAME_HEALTH_CHARGING); if (laser.overloaded) { #if 0 BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX4 + XX_OVERLOAD, DOOR_GFX_PAGEY1 + YY_OVERLOAD + OVERLOAD_YSIZE - laser.overload_value, OVERLOAD_XSIZE, laser.overload_value, DX_OVERLOAD, DY_OVERLOAD + OVERLOAD_YSIZE - laser.overload_value); #endif redraw_mask |= REDRAW_DOOR_1; } else { #if 0 BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX5 + XX_OVERLOAD, DOOR_GFX_PAGEY1 + YY_OVERLOAD, OVERLOAD_XSIZE, OVERLOAD_YSIZE - laser.overload_value, DX_OVERLOAD, DY_OVERLOAD); #endif redraw_mask |= REDRAW_DOOR_1; } if (laser.overload_value == MAX_LASER_OVERLOAD) { int i; for (i = 15; i >= 0; i--) { #if 0 SetRGB(pen_ray, i * color_scale, 0x0000, 0x0000); #endif pen_ray = GetPixelFromRGB(window, 0x11 * i, 0x00, 0x00); DrawLaser(0, DL_LASER_ENABLED); BackToFront(); Delay(50); } DrawLaser(0, DL_LASER_DISABLED); game_mm.game_over = TRUE; game_mm.game_over_cause = GAME_OVER_OVERLOADED; SetTileCursorActive(FALSE); game.restart_game_message = "Magic spell hit Mc Duffin ! Play it again ?"; #if 0 if (Request("Magic spell hit Mc Duffin ! Play it again ?", REQ_ASK | REQ_STAY_CLOSED)) { InitGame(); } else { game_status = MAINMENU; DrawMainMenu(); } #endif return; } } if (laser.fuse_off) return; CT -= Ct; if (element == EL_BOMB && CT > native_mm_level.time_bomb) { if (game_mm.cheat_no_explosion) return; #if 0 laser.num_damages--; DrawLaser(0, DL_LASER_DISABLED); laser.num_edges = 0; #endif Bang_MM(ELX, ELY); laser.dest_element = EL_EXPLODING_OPAQUE; #if 0 Bang_MM(ELX, ELY); laser.num_damages--; DrawLaser(0, DL_LASER_DISABLED); laser.num_edges = 0; Bang_MM(laser.start_edge.x, laser.start_edge.y); if (Request("Bomb killed Mc Duffin ! Play it again ?", REQ_ASK | REQ_STAY_CLOSED)) { InitGame(); } else { game_status = MAINMENU; DrawMainMenu(); } #endif return; } if (element == EL_FUSE_ON && CT > native_mm_level.time_fuse) { laser.fuse_off = TRUE; laser.fuse_x = ELX; laser.fuse_y = ELY; DrawLaser(0, DL_LASER_DISABLED); DrawGraphic_MM(ELX, ELY, IMG_MM_FUSE); } if (element == EL_BALL_GRAY && CT > native_mm_level.time_ball) { static int new_elements[] = { EL_MIRROR_START, EL_MIRROR_FIXED_START, EL_POLAR_START, EL_POLAR_CROSS_START, EL_PACMAN_START, EL_KETTLE, EL_BOMB, EL_PRISM }; int num_new_elements = sizeof(new_elements) / sizeof(int); int new_element = new_elements[RND(num_new_elements)]; Store[ELX][ELY] = new_element + RND(get_num_elements(new_element)); Feld[ELX][ELY] = EL_GRAY_BALL_OPENING; /* !!! CHECK AGAIN: Laser on Polarizer !!! */ ScanLaser(); return; #if 0 int graphic; switch (RND(5)) { case 0: element = EL_MIRROR_START + RND(16); break; case 1: { int rnd = RND(3); element = (rnd == 0 ? EL_KETTLE : rnd == 1 ? EL_BOMB : EL_PRISM); } break; default: { int rnd = RND(3); element = (rnd == 0 ? EL_FUSE_ON : rnd >= 1 && rnd <= 4 ? EL_PACMAN_RIGHT + rnd - 1 : rnd >= 5 && rnd <= 20 ? EL_POLAR_START + rnd - 5 : rnd >= 21 && rnd <= 24 ? EL_POLAR_CROSS_START + rnd - 21 : EL_MIRROR_FIXED_START + rnd - 25); } break; } graphic = el2gfx(element); for (i = 0; i < 50; i++) { int x = RND(26); int y = RND(26); #if 0 BlitBitmap(pix[PIX_BACK], drawto, SX + (graphic % GFX_PER_LINE) * TILEX + x, SY + (graphic / GFX_PER_LINE) * TILEY + y, 6, 6, SX + ELX * TILEX + x, SY + ELY * TILEY + y); #endif MarkTileDirty(ELX, ELY); BackToFront(); DrawLaser(0, DL_LASER_ENABLED); Delay(50); } Feld[ELX][ELY] = element; DrawField_MM(ELX, ELY); #if 0 printf("NEW ELEMENT: (%d, %d)\n", ELX, ELY); #endif /* above stuff: GRAY BALL -> PRISM !!! */ /* LX = ELX * TILEX + 14; LY = ELY * TILEY + 14; if (laser.current_angle == (laser.current_angle >> 1) << 1) OK = 8; else OK = 4; LX -= OK * XS; LY -= OK * YS; laser.num_edges -= 2; laser.num_damages--; */ #if 0 for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i>=0; i--) if (laser.damage[i].is_mirror) break; if (i > 0) DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED); else DrawLaser(0, DL_LASER_DISABLED); #else DrawLaser(0, DL_LASER_DISABLED); #endif ScanLaser(); /* printf("TEST ELEMENT: %d\n", Feld[0][0]); */ #endif return; } if (IS_WALL_ICE(element) && CT > 50) { PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_SHRINKING); { Feld[ELX][ELY] = Feld[ELX][ELY] - EL_WALL_ICE + EL_WALL_CHANGING; Store[ELX][ELY] = EL_WALL_ICE; Store2[ELX][ELY] = laser.wall_mask; laser.dest_element = Feld[ELX][ELY]; return; } for (i = 0; i < 5; i++) { int phase = i + 1; if (i == 4) { Feld[ELX][ELY] &= (laser.wall_mask ^ 0xFF); phase = 0; } DrawWallsAnimation_MM(ELX, ELY, Feld[ELX][ELY], phase, laser.wall_mask); BackToFront(); Delay(100); } if (Feld[ELX][ELY] == EL_WALL_ICE) Feld[ELX][ELY] = EL_EMPTY; /* laser.num_edges--; LX = laser.edge[laser.num_edges].x - cSX2; LY = laser.edge[laser.num_edges].y - cSY2; */ for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i >= 0; i--) if (laser.damage[i].is_mirror) break; if (i > 0) DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED); else DrawLaser(0, DL_LASER_DISABLED); ScanLaser(); return; } if (IS_WALL_AMOEBA(element) && CT > 60) { int k1, k2, k3, dx, dy, de, dm; int element2 = Feld[ELX][ELY]; if (element2 != EL_EMPTY && !IS_WALL_AMOEBA(element)) return; for (i = laser.num_damages - 1; i >= 0; i--) if (laser.damage[i].is_mirror) break; r = laser.num_edges; d = laser.num_damages; k1 = i; if (k1 > 0) { int x, y; DrawLaser(laser.damage[k1].edge - 1, DL_LASER_DISABLED); laser.num_edges++; DrawLaser(0, DL_LASER_ENABLED); laser.num_edges--; x = laser.damage[k1].x; y = laser.damage[k1].y; DrawField_MM(x, y); } for (i = 0; i < 4; i++) { if (laser.wall_mask & (1 << i)) { if (CheckLaserPixel(cSX + ELX * TILEX + 14 + (i % 2) * 2, cSY + ELY * TILEY + 31 * (i / 2))) break; if (CheckLaserPixel(cSX + ELX * TILEX + 31 * (i % 2), cSY + ELY * TILEY + 14 + (i / 2) * 2)) break; } } k2 = i; for (i = 0; i < 4; i++) { if (laser.wall_mask & (1 << i)) { if (CheckLaserPixel(cSX + ELX * TILEX + 31 * (i % 2), cSY + ELY * TILEY + 31 * (i / 2))) break; } } k3 = i; if (laser.num_beamers > 0 || k1 < 1 || k2 < 4 || k3 < 4 || CheckLaserPixel(cSX + ELX * TILEX + 14, cSY + ELY * TILEY + 14)) { laser.num_edges = r; laser.num_damages = d; DrawLaser(0, DL_LASER_DISABLED); } Feld[ELX][ELY] = element | laser.wall_mask; dx = ELX; dy = ELY; de = Feld[ELX][ELY]; dm = laser.wall_mask; #if 1 { int x = ELX, y = ELY; int wall_mask = laser.wall_mask; ScanLaser(); DrawLaser(0, DL_LASER_ENABLED); PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING); Feld[x][y] = Feld[x][y] - EL_WALL_AMOEBA + EL_WALL_CHANGING; Store[x][y] = EL_WALL_AMOEBA; Store2[x][y] = wall_mask; return; } #endif DrawWallsAnimation_MM(dx, dy, de, 4, dm); ScanLaser(); DrawLaser(0, DL_LASER_ENABLED); PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING); for (i = 4; i >= 0; i--) { DrawWallsAnimation_MM(dx, dy, de, i, dm); BackToFront(); Delay(20); } DrawLaser(0, DL_LASER_ENABLED); return; } if ((element == EL_BLOCK_WOOD || element == EL_BLOCK_STONE) && laser.stops_inside_element && CT > native_mm_level.time_block) { int x, y; int k; if (ABS(XS) > ABS(YS)) k = 0; else k = 1; if (XS < YS) k += 2; for (i = 0; i < 4; i++) { if (i) k++; if (k > 3) k = 0; x = ELX + Step[k * 4].x; y = ELY + Step[k * 4].y; if (!IN_LEV_FIELD(x, y) || Feld[x][y] != EL_EMPTY) continue; if (ObjHit(x, y, HIT_POS_CENTER | HIT_POS_EDGE | HIT_POS_BETWEEN)) continue; break; } if (i > 3) { laser.overloaded = (element == EL_BLOCK_STONE); return; } PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_PUSHING); Feld[ELX][ELY] = 0; Feld[x][y] = element; DrawGraphic_MM(ELX, ELY, IMG_EMPTY); DrawField_MM(x, y); if (element == EL_BLOCK_STONE && Box[ELX][ELY]) { DrawLaser(Box[ELX][ELY] - 1, DL_LASER_DISABLED); DrawLaser(laser.num_edges - 1, DL_LASER_ENABLED); } ScanLaser(); return; } if (element == EL_FUEL_FULL && CT > 10) { for (i = game_mm.energy_left; i <= MAX_LASER_ENERGY; i+=2) { #if 0 BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX4 + XX_ENERGY, DOOR_GFX_PAGEY1 + YY_ENERGY + ENERGY_YSIZE - i, ENERGY_XSIZE, i, DX_ENERGY, DY_ENERGY + ENERGY_YSIZE - i); #endif redraw_mask |= REDRAW_DOOR_1; BackToFront(); Delay(20); } game_mm.energy_left = MAX_LASER_ENERGY; Feld[ELX][ELY] = EL_FUEL_EMPTY; DrawField_MM(ELX, ELY); DrawLaser(0, DL_LASER_ENABLED); return; } return; } void GameActions_MM(struct MouseActionInfo action, boolean warp_mode) { boolean element_clicked = ClickElement(action.lx, action.ly, action.button); boolean button_released = (action.button == MB_RELEASED); GameActions_MM_Ext(action, warp_mode); CheckSingleStepMode_MM(element_clicked, button_released); } void MovePacMen() { int mx, my, ox, oy, nx, ny; int element; int l; if (++pacman_nr >= game_mm.num_pacman) pacman_nr = 0; game_mm.pacman[pacman_nr].dir--; for (l = 1; l < 5; l++) { game_mm.pacman[pacman_nr].dir++; if (game_mm.pacman[pacman_nr].dir > 4) game_mm.pacman[pacman_nr].dir = 1; if (game_mm.pacman[pacman_nr].dir % 2) { mx = 0; my = game_mm.pacman[pacman_nr].dir - 2; } else { my = 0; mx = 3 - game_mm.pacman[pacman_nr].dir; } ox = game_mm.pacman[pacman_nr].x; oy = game_mm.pacman[pacman_nr].y; nx = ox + mx; ny = oy + my; element = Feld[nx][ny]; if (nx < 0 || nx > 15 || ny < 0 || ny > 11) continue; if (!IS_EATABLE4PACMAN(element)) continue; if (ObjHit(nx, ny, HIT_POS_CENTER)) continue; Feld[ox][oy] = EL_EMPTY; Feld[nx][ny] = EL_PACMAN_RIGHT - 1 + (game_mm.pacman[pacman_nr].dir - 1 + (game_mm.pacman[pacman_nr].dir % 2) * 2); game_mm.pacman[pacman_nr].x = nx; game_mm.pacman[pacman_nr].y = ny; DrawGraphic_MM(ox, oy, IMG_EMPTY); if (element != EL_EMPTY) { int graphic = el2gfx(Feld[nx][ny]); Bitmap *bitmap; int src_x, src_y; int i; getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y); CT = FrameCounter; ox = cSX + ox * TILEX; oy = cSY + oy * TILEY; for (i = 1; i < 33; i += 2) BlitBitmap(bitmap, window, src_x, src_y, TILEX, TILEY, ox + i * mx, oy + i * my); Ct = Ct + FrameCounter - CT; } DrawField_MM(nx, ny); BackToFront(); if (!laser.fuse_off) { DrawLaser(0, DL_LASER_ENABLED); if (ObjHit(nx, ny, HIT_POS_BETWEEN)) { AddDamagedField(nx, ny); laser.damage[laser.num_damages - 1].edge = 0; } } if (element == EL_BOMB) DeletePacMan(nx, ny); if (IS_WALL_AMOEBA(element) && (LX + 2 * XS) / TILEX == nx && (LY + 2 * YS) / TILEY == ny) { laser.num_edges--; ScanLaser(); } break; } } void GameWon_MM() { int hi_pos; boolean raise_level = FALSE; #if 0 if (local_player->MovPos) return; local_player->LevelSolved = FALSE; #endif if (game_mm.energy_left) { if (setup.sound_loops) PlaySoundExt(SND_SIRR, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT, SND_CTRL_PLAY_LOOP); while (game_mm.energy_left > 0) { if (!setup.sound_loops) PlaySoundStereo(SND_SIRR, SOUND_MAX_RIGHT); /* if (game_mm.energy_left > 0 && !(game_mm.energy_left % 10)) RaiseScore_MM(native_mm_level.score[SC_ZEITBONUS]); */ RaiseScore_MM(5); game_mm.energy_left--; if (game_mm.energy_left >= 0) { #if 0 BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX5 + XX_ENERGY, DOOR_GFX_PAGEY1 + YY_ENERGY, ENERGY_XSIZE, ENERGY_YSIZE - game_mm.energy_left, DX_ENERGY, DY_ENERGY); #endif redraw_mask |= REDRAW_DOOR_1; } BackToFront(); Delay(10); } if (setup.sound_loops) StopSound(SND_SIRR); } else if (native_mm_level.time == 0) /* level without time limit */ { if (setup.sound_loops) PlaySoundExt(SND_SIRR, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT, SND_CTRL_PLAY_LOOP); while (TimePlayed < 999) { if (!setup.sound_loops) PlaySoundStereo(SND_SIRR, SOUND_MAX_RIGHT); if (TimePlayed < 999 && !(TimePlayed % 10)) RaiseScore_MM(native_mm_level.score[SC_TIME_BONUS]); if (TimePlayed < 900 && !(TimePlayed % 10)) TimePlayed += 10; else TimePlayed++; /* DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2); */ BackToFront(); Delay(10); } if (setup.sound_loops) StopSound(SND_SIRR); } #if 0 FadeSounds(); #endif CloseDoor(DOOR_CLOSE_1); Request("Level solved !", REQ_CONFIRM); if (level_nr == leveldir_current->handicap_level) { leveldir_current->handicap_level++; SaveLevelSetup_SeriesInfo(); } if (level_editor_test_game) game_mm.score = -1; /* no highscore when playing from editor */ else if (level_nr < leveldir_current->last_level) raise_level = TRUE; /* advance to next level */ if ((hi_pos = NewHiScore_MM()) >= 0) { game_status = HALLOFFAME; // DrawHallOfFame(hi_pos); if (raise_level) level_nr++; } else { game_status = MAINMENU; if (raise_level) level_nr++; // DrawMainMenu(); } BackToFront(); } int NewHiScore_MM() { int k, l; int position = -1; // LoadScore(level_nr); if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 || game_mm.score < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; for (k = 0; k < MAX_SCORE_ENTRIES; k++) { if (game_mm.score > highscore[k].Score) { /* player has made it to the hall of fame */ if (k < MAX_SCORE_ENTRIES - 1) { int m = MAX_SCORE_ENTRIES - 1; #ifdef ONE_PER_NAME for (l = k; l < MAX_SCORE_ENTRIES; l++) if (!strcmp(setup.player_name, highscore[l].Name)) m = l; if (m == k) /* player's new highscore overwrites his old one */ goto put_into_list; #endif for (l = m; l>k; l--) { strcpy(highscore[l].Name, highscore[l - 1].Name); highscore[l].Score = highscore[l - 1].Score; } } #ifdef ONE_PER_NAME put_into_list: #endif strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN); highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0'; highscore[k].Score = game_mm.score; position = k; break; } #ifdef ONE_PER_NAME else if (!strncmp(setup.player_name, highscore[k].Name, MAX_PLAYER_NAME_LEN)) break; /* player already there with a higher score */ #endif } // if (position >= 0) // SaveScore(level_nr); return position; } static void InitMovingField_MM(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); MovDir[x][y] = direction; MovDir[newx][newy] = direction; if (Feld[newx][newy] == EL_EMPTY) Feld[newx][newy] = EL_BLOCKED; } static void Moving2Blocked_MM(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); *goes_to_x = newx; *goes_to_y = newy; } static void Blocked2Moving_MM(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) oldx++; else if (direction == MV_RIGHT) oldx--; else if (direction == MV_UP) oldy++; else if (direction == MV_DOWN) oldy--; *comes_from_x = oldx; *comes_from_y = oldy; } static int MovingOrBlocked2Element_MM(int x, int y) { int element = Feld[x][y]; if (element == EL_BLOCKED) { int oldx, oldy; Blocked2Moving_MM(x, y, &oldx, &oldy); return Feld[oldx][oldy]; } return element; } #if 0 static void RemoveField(int x, int y) { Feld[x][y] = EL_EMPTY; MovPos[x][y] = 0; MovDir[x][y] = 0; MovDelay[x][y] = 0; } #endif static void RemoveMovingField_MM(int x, int y) { int oldx = x, oldy = y, newx = x, newy = y; if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y)) return; if (IS_MOVING(x, y)) { Moving2Blocked_MM(x, y, &newx, &newy); if (Feld[newx][newy] != EL_BLOCKED) return; } else if (Feld[x][y] == EL_BLOCKED) { Blocked2Moving_MM(x, y, &oldx, &oldy); if (!IS_MOVING(oldx, oldy)) return; } Feld[oldx][oldy] = EL_EMPTY; Feld[newx][newy] = EL_EMPTY; MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0; MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0; DrawLevelField_MM(oldx, oldy); DrawLevelField_MM(newx, newy); } void PlaySoundLevel(int x, int y, int sound_nr) { int sx = SCREENX(x), sy = SCREENY(y); int volume, stereo; int silence_distance = 8; if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) || (!setup.sound_loops && IS_LOOP_SOUND(sound_nr))) return; if (!IN_LEV_FIELD(x, y) || sx < -silence_distance || sx >= SCR_FIELDX+silence_distance || sy < -silence_distance || sy >= SCR_FIELDY+silence_distance) return; volume = SOUND_MAX_VOLUME; #ifndef MSDOS stereo = (sx - SCR_FIELDX/2) * 12; #else stereo = SOUND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5; if (stereo > SOUND_MAX_RIGHT) stereo = SOUND_MAX_RIGHT; if (stereo < SOUND_MAX_LEFT) stereo = SOUND_MAX_LEFT; #endif if (!IN_SCR_FIELD(sx, sy)) { int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2; int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2; volume -= volume * (dx > dy ? dx : dy) / silence_distance; } PlaySoundExt(sound_nr, volume, stereo, SND_CTRL_PLAY_SOUND); } static void RaiseScore_MM(int value) { game_mm.score += value; #if 0 DrawText(DX_SCORE, DY_SCORE, int2str(game_mm.score, 4), FONT_TEXT_2); #endif } void RaiseScoreElement_MM(int element) { switch(element) { case EL_PACMAN: case EL_PACMAN_RIGHT: case EL_PACMAN_UP: case EL_PACMAN_LEFT: case EL_PACMAN_DOWN: RaiseScore_MM(native_mm_level.score[SC_PACMAN]); break; case EL_KEY: RaiseScore_MM(native_mm_level.score[SC_KEY]); break; case EL_KETTLE: case EL_CELL: RaiseScore_MM(native_mm_level.score[SC_COLLECTIBLE]); break; case EL_LIGHTBALL: RaiseScore_MM(native_mm_level.score[SC_LIGHTBALL]); break; default: break; } } /* ------------------------------------------------------------------------- */ /* Mirror Magic game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ void SaveEngineSnapshotValues_MM(ListNode **buffers) { int x, y; engine_snapshot_mm.game_mm = game_mm; engine_snapshot_mm.laser = laser; for (x = 0; x < MAX_PLAYFIELD_WIDTH; x++) { for (y = 0; y < MAX_PLAYFIELD_HEIGHT; y++) { engine_snapshot_mm.Ur[x][y] = Ur[x][y]; engine_snapshot_mm.Hit[x][y] = Hit[x][y]; engine_snapshot_mm.Box[x][y] = Box[x][y]; engine_snapshot_mm.Angle[x][y] = Angle[x][y]; engine_snapshot_mm.Frame[x][y] = Frame[x][y]; } } engine_snapshot_mm.LX = LX; engine_snapshot_mm.LY = LY; engine_snapshot_mm.XS = XS; engine_snapshot_mm.YS = YS; engine_snapshot_mm.ELX = ELX; engine_snapshot_mm.ELY = ELY; engine_snapshot_mm.CT = CT; engine_snapshot_mm.Ct = Ct; engine_snapshot_mm.last_LX = last_LX; engine_snapshot_mm.last_LY = last_LY; engine_snapshot_mm.last_hit_mask = last_hit_mask; engine_snapshot_mm.hold_x = hold_x; engine_snapshot_mm.hold_y = hold_y; engine_snapshot_mm.pacman_nr = pacman_nr; engine_snapshot_mm.rotate_delay = rotate_delay; engine_snapshot_mm.pacman_delay = pacman_delay; engine_snapshot_mm.energy_delay = energy_delay; engine_snapshot_mm.overload_delay = overload_delay; } void LoadEngineSnapshotValues_MM() { int x, y; /* stored engine snapshot buffers already restored at this point */ game_mm = engine_snapshot_mm.game_mm; laser = engine_snapshot_mm.laser; for (x = 0; x < MAX_PLAYFIELD_WIDTH; x++) { for (y = 0; y < MAX_PLAYFIELD_HEIGHT; y++) { Ur[x][y] = engine_snapshot_mm.Ur[x][y]; Hit[x][y] = engine_snapshot_mm.Hit[x][y]; Box[x][y] = engine_snapshot_mm.Box[x][y]; Angle[x][y] = engine_snapshot_mm.Angle[x][y]; Frame[x][y] = engine_snapshot_mm.Frame[x][y]; } } LX = engine_snapshot_mm.LX; LY = engine_snapshot_mm.LY; XS = engine_snapshot_mm.XS; YS = engine_snapshot_mm.YS; ELX = engine_snapshot_mm.ELX; ELY = engine_snapshot_mm.ELY; CT = engine_snapshot_mm.CT; Ct = engine_snapshot_mm.Ct; last_LX = engine_snapshot_mm.last_LX; last_LY = engine_snapshot_mm.last_LY; last_hit_mask = engine_snapshot_mm.last_hit_mask; hold_x = engine_snapshot_mm.hold_x; hold_y = engine_snapshot_mm.hold_y; pacman_nr = engine_snapshot_mm.pacman_nr; rotate_delay = engine_snapshot_mm.rotate_delay; pacman_delay = engine_snapshot_mm.pacman_delay; energy_delay = engine_snapshot_mm.energy_delay; overload_delay = engine_snapshot_mm.overload_delay; RedrawPlayfield_MM(TRUE); } static int getAngleFromTouchDelta(int dx, int dy, int base) { double pi = 3.141592653; double rad = atan2((double)-dy, (double)dx); double rad2 = (rad < 0 ? rad + 2 * pi : rad); double deg = rad2 * 180.0 / pi; return (int)(deg * base / 360.0 + 0.5) % base; } int getButtonFromTouchPosition(int x, int y, int dst_mx, int dst_my) { // calculate start (source) position to be at the middle of the tile int src_mx = cSX + x * TILESIZE_VAR + TILESIZE_VAR / 2; int src_my = cSY + y * TILESIZE_VAR + TILESIZE_VAR / 2; int dx = dst_mx - src_mx; int dy = dst_my - src_my; int element; int base = 16; int phases = 16; int angle_old = -1; int angle_new = -1; int button = 0; int i; if (!IN_LEV_FIELD(x, y)) return 0; element = Feld[x][y]; if (!IS_MCDUFFIN(element) && !IS_MIRROR(element) && !IS_BEAMER(element) && !IS_POLAR(element) && !IS_POLAR_CROSS(element) && !IS_DF_MIRROR(element)) return 0; angle_old = get_element_angle(element); if (IS_MCDUFFIN(element)) { angle_new = (dx > 0 && ABS(dy) < ABS(dx) ? ANG_RAY_RIGHT : dy < 0 && ABS(dx) < ABS(dy) ? ANG_RAY_UP : dx < 0 && ABS(dy) < ABS(dx) ? ANG_RAY_LEFT : dy > 0 && ABS(dx) < ABS(dy) ? ANG_RAY_DOWN : -1); } else if (IS_MIRROR(element) || IS_DF_MIRROR(element)) { for (i = 0; i < laser.num_damages; i++) { if (laser.damage[i].x == x && laser.damage[i].y == y && ObjHit(x, y, HIT_POS_CENTER)) { angle_old = get_mirrored_angle(laser.damage[i].angle, angle_old); angle_new = getAngleFromTouchDelta(dx, dy, base) % phases; break; } } } if (angle_new == -1) { if (IS_MIRROR(element) || IS_DF_MIRROR(element) || IS_POLAR(element)) base = 32; if (IS_POLAR_CROSS(element)) phases = 4; angle_new = getAngleFromTouchDelta(dx, dy, base) % phases; } button = (angle_new == angle_old ? 0 : (angle_new - angle_old + phases) % phases < (phases / 2) ? MB_LEFTBUTTON : MB_RIGHTBUTTON); return button; } mirrormagic-3.0.0/src/game_mm/mm_tools.h0000644000175000017500000001007713263212010017521 0ustar aeglosaeglos/*********************************************************** * Mirror Magic -- McDuffin's Revenge * *----------------------------------------------------------* * (c) 1994-2001 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tools.h * ***********************************************************/ #ifndef MM_TOOLS_H #define MM_TOOLS_H #include "main_mm.h" /* 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) /* 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_ALL (DOOR_OPEN_1 | DOOR_OPEN_2) #define DOOR_CLOSE_ALL (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) /* 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 REQUEST_WAIT_FOR (REQ_ASK | REQ_CONFIRM) /* font types */ #define FS_SMALL 0 #define FS_BIG 1 #define FS_MEDIUM 2 void SetDrawtoField_MM(int); void BackToFront(); void FadeToFront(); void ClearWindow(); void MarkTileDirty(int, int); void DrawAllPlayers_MM(void); void DrawPlayerField_MM(int, int); void DrawPlayer_MM(struct PlayerInfo *); void DrawGraphicAnimation_MM(int, int, int, int); void DrawGraphic_MM(int, int, int); void DrawGraphicExt_MM(DrawBuffer *, int, int, int); void DrawGraphicThruMask_MM(int, int, int); void DrawGraphicThruMaskExt_MM(DrawBuffer *, int, int, int); void DrawMiniGraphic_MM(int, int, int); void getMiniGraphicSource(int, Bitmap **, int *, int *); void DrawMiniGraphicExt_MM(DrawBuffer *, int, int, int); void DrawGraphicShifted_MM(int, int, int, int, int, int, int); void DrawGraphicShiftedThruMask_MM(int, int, int, int, int, int); void DrawScreenElementExt_MM(int, int, int, int, int, int, int); void DrawLevelElementExt_MM(int, int, int, int, int, int, int); void DrawScreenElementShifted_MM(int, int, int, int, int, int); void DrawLevelElementShifted_MM(int, int, int, int, int, int); void DrawScreenElementThruMask_MM(int, int, int); void DrawLevelElementThruMask_MM(int, int, int); void DrawLevelFieldThruMask_MM(int, int); void ErdreichAnbroeckeln(int, int); void DrawScreenElement_MM(int, int, int); void DrawLevelElement_MM(int, int, int); void DrawScreenField_MM(int, int); void DrawLevelField_MM(int, int); void DrawMiniElement_MM(int, int, int); void DrawMiniElementOrWall_MM(int, int, int, int); void DrawField_MM(int, int); void DrawLevel_MM(void); void DrawLaser_MM(void); void DrawElement_MM(int, int, int); void DrawWallsExt_MM(int, int, int, int); void DrawWalls_MM(int, int, int); void DrawWallsAnimation_MM(int, int, int, int, int); void DrawMiniLevel_MM(int, int, int, int); void DrawMicroLevel_MM(int, int, boolean); boolean Request(char *, unsigned int); unsigned int OpenDoor(unsigned int); unsigned int CloseDoor(unsigned int); unsigned int GetDoorState(void); unsigned int MoveDoor(unsigned int); void DrawSpecialEditorDoor_MM(); void UndrawSpecialEditorDoor(); Pixel ReadPixel(DrawBuffer *, int, int); void SetRGB(unsigned int, unsigned short, unsigned short, unsigned short); void CreateToolButtons(); int get_base_element(int); int get_element_phase(int); int get_num_elements(int); int get_rotated_element(int, int); int el2gfx(int); #endif mirrormagic-3.0.0/src/game_mm/export.h0000644000175000017500000001331713263212010017211 0ustar aeglosaeglos#ifndef GAME_MM_EXPORT_H #define GAME_MM_EXPORT_H /* ========================================================================= */ /* functions and definitions exported from game_mm to main program */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* constant definitions */ /* ------------------------------------------------------------------------- */ #define MM_MAX_PLAYFIELD_WIDTH MAX_PLAYFIELD_WIDTH #define MM_MAX_PLAYFIELD_HEIGHT MAX_PLAYFIELD_HEIGHT #define MM_STD_PLAYFIELD_WIDTH 16 #define MM_STD_PLAYFIELD_HEIGHT 12 #define MM_MAX_PLAYFIELD_SIZE (MM_MAX_PLAYFIELD_WIDTH * \ MM_MAX_PLAYFIELD_HEIGHT) #define MAX_NUM_AMOEBA 100 #define MAX_NUM_BEAMERS 8 #define MAX_LASER_LEN 256 #define MAX_LASER_ENERGY 100 #define MAX_LASER_OVERLOAD 100 #define MM_LEVEL_SCORE_ELEMENTS 16 #define MM_MAX_LEVEL_NAME_LEN 32 #define MM_MAX_LEVEL_AUTHOR_LEN 32 #define EL_MM_START_1_NATIVE 0 #define EL_MM_END_1_NATIVE 155 #define EL_MM_CHAR_START_NATIVE 160 #define EL_MM_CHAR_END_NATIVE 239 #define EL_MM_START_2_NATIVE 240 #define EL_MM_END_2_NATIVE 430 #define EL_MM_RUNTIME_START_NATIVE 500 #define EL_MM_RUNTIME_END_NATIVE 504 #define EL_MM_DUMMY_START_NATIVE 700 #define EL_MM_DUMMY_END_NATIVE 709 /* elements to be specially mapped */ #define EL_MM_EMPTY_NATIVE 0 #define EL_DF_EMPTY_NATIVE 304 /* sounds */ #define SND_MM_GAME_LEVELTIME_CHARGING 0 #define SND_MM_GAME_HEALTH_CHARGING 1 /* ------------------------------------------------------------------------- */ /* data structure definitions */ /* ------------------------------------------------------------------------- */ struct GlobalInfo_MM { }; struct CycleList { int x, y; int steps; }; struct MovingList { int x, y; int dir; }; struct DamageList { int x, y; int edge, angle; boolean is_mirror; }; struct BeamerInfo { int x, y; int num; }; struct PacMan { int XP, YP; int Dr; }; struct LaserInfo { struct XY start_edge; int start_angle; int current_angle; struct DamageList damage[MAX_LASER_LEN + 10]; int num_damages; struct XY edge[MAX_LASER_LEN + 10]; int num_edges; struct BeamerInfo beamer[MAX_NUM_BEAMERS][2]; int beamer_edge[MAX_NUM_BEAMERS]; int beamer_nr[MAX_NUM_BEAMERS]; int num_beamers; boolean overloaded; int overload_value; boolean fuse_off; int fuse_x, fuse_y; int dest_element; boolean stops_inside_element; boolean redraw; int wall_mask; }; struct GameInfo_MM { boolean LevelSolved; boolean GameOver; struct CycleList cycle[MM_MAX_PLAYFIELD_SIZE]; int num_cycle; struct MovingList pacman[MM_MAX_PLAYFIELD_SIZE]; int num_pacman; int score; int energy_left; int kettles_still_needed; int lights_still_needed; int num_keys; boolean level_solved; boolean game_over; int game_over_cause; boolean cheat_no_overload; boolean cheat_no_explosion; int laser_overload_value; boolean laser_enabled; }; struct LevelInfo_MM { int file_version; /* version of file the level was stored with */ int game_version; /* version of game engine to play this level */ boolean encoding_16bit_field; /* level contains 16-bit elements */ int fieldx; int fieldy; int time; int kettles_needed; boolean auto_count_kettles; boolean laser_red, laser_green, laser_blue; char name[MM_MAX_LEVEL_NAME_LEN + 1]; char author[MM_MAX_LEVEL_AUTHOR_LEN + 1]; int score[MM_LEVEL_SCORE_ELEMENTS]; int amoeba_speed; int time_fuse; int time_bomb; int time_ball; int time_block; short field[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT]; }; struct GraphicInfo_MM { }; struct EngineSnapshotInfo_MM { struct GameInfo_MM game_mm; struct LaserInfo laser; short Ur[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT]; short Hit[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT]; short Box[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT]; short Angle[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT]; short Frame[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT]; short LX,LY, XS,YS, ELX,ELY; short CT,Ct; int last_LX, last_LY, last_hit_mask; int hold_x, hold_y; int pacman_nr; unsigned int rotate_delay; unsigned int pacman_delay; unsigned int energy_delay; unsigned int overload_delay; }; /* ------------------------------------------------------------------------- */ /* exported functions */ /* ------------------------------------------------------------------------- */ extern struct GlobalInfo_MM global_mm_info; extern struct GameInfo_MM game_mm; extern struct LevelInfo_MM native_mm_level; extern struct EngineSnapshotInfo_MM engine_snapshot_mm; extern short Ur[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT]; extern void mm_open_all(); extern void mm_close_all(); void InitElementProperties_MM(); extern void InitGfxBuffers_MM(); extern void InitGameEngine_MM(); extern void InitGameActions_MM(); extern void GameActions_MM(struct MouseActionInfo, boolean); extern void DrawLaser_MM(); extern boolean ClickElement(int, int, int); extern unsigned int InitEngineRandom_MM(int); extern void setLevelInfoToDefaults_MM(); extern void copyInternalEngineVars_MM(); extern boolean LoadNativeLevel_MM(char *, boolean); extern void SaveNativeLevel_MM(char *); extern int getFieldbufferOffsetX_MM(); extern int getFieldbufferOffsetY_MM(); extern void BlitScreenToBitmap_MM(Bitmap *); extern void RedrawPlayfield_MM(); extern void LoadEngineSnapshotValues_MM(); extern void SaveEngineSnapshotValues_MM(ListNode **); extern int getButtonFromTouchPosition(int, int, int, int); #endif /* GAME_MM_EXPORT_H */ mirrormagic-3.0.0/src/game_mm/mm_init.c0000644000175000017500000001163713263212010017322 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // mm_init.c // ============================================================================ #include "main_mm.h" #include "mm_main.h" struct EngineSnapshotInfo_MM engine_snapshot_mm; unsigned int InitEngineRandom_MM(int seed) { return InitEngineRandom(seed); } void InitElementProperties_MM() { int i,j; static int ep_grid[] = { EL_GRID_STEEL_00, EL_GRID_STEEL_01, EL_GRID_STEEL_02, EL_GRID_STEEL_03, EL_GRID_WOOD_00, EL_GRID_WOOD_01, EL_GRID_WOOD_02, EL_GRID_WOOD_03, }; static int ep_grid_num = sizeof(ep_grid) / sizeof(int); static int ep_mcduffin[] = { EL_MCDUFFIN_RIGHT, EL_MCDUFFIN_UP, EL_MCDUFFIN_LEFT, EL_MCDUFFIN_DOWN, }; static int ep_mcduffin_num = sizeof(ep_mcduffin) / sizeof(int); static int ep_rectangle[] = { EL_EXIT_CLOSED, EL_EXIT_OPENING_1, EL_EXIT_OPENING_2, EL_EXIT_OPEN, EL_BLOCK_STONE, EL_BLOCK_WOOD, EL_GATE_STONE, EL_GATE_WOOD }; static int ep_rectangle_num = sizeof(ep_rectangle) / sizeof(int); static int ep_mirror[] = { EL_MIRROR_00, EL_MIRROR_01, EL_MIRROR_02, EL_MIRROR_03, EL_MIRROR_04, EL_MIRROR_05, EL_MIRROR_06, EL_MIRROR_07, EL_MIRROR_08, EL_MIRROR_09, EL_MIRROR_10, EL_MIRROR_11, EL_MIRROR_12, EL_MIRROR_13, EL_MIRROR_14, EL_MIRROR_15, }; static int ep_mirror_num = sizeof(ep_mirror) / sizeof(int); static int ep_mirror_fixed[] = { EL_MIRROR_FIXED_00, EL_MIRROR_FIXED_01, EL_MIRROR_FIXED_02, EL_MIRROR_FIXED_03, }; static int ep_mirror_fixed_num = sizeof(ep_mirror_fixed) / sizeof(int); static int ep_polar[] = { EL_POLAR_00, EL_POLAR_01, EL_POLAR_02, EL_POLAR_03, EL_POLAR_04, EL_POLAR_05, EL_POLAR_06, EL_POLAR_07, EL_POLAR_08, EL_POLAR_09, EL_POLAR_10, EL_POLAR_11, EL_POLAR_12, EL_POLAR_13, EL_POLAR_14, EL_POLAR_15, }; static int ep_polar_num = sizeof(ep_polar) / sizeof(int); static int ep_polar_cross[] = { EL_POLAR_CROSS_00, EL_POLAR_CROSS_01, EL_POLAR_CROSS_02, EL_POLAR_CROSS_03, }; static int ep_polar_cross_num = sizeof(ep_polar_cross) / sizeof(int); static int ep_beamer[] = { EL_BEAMER_00, EL_BEAMER_01, EL_BEAMER_02, EL_BEAMER_03, EL_BEAMER_04, EL_BEAMER_05, EL_BEAMER_06, EL_BEAMER_07, EL_BEAMER_08, EL_BEAMER_09, EL_BEAMER_10, EL_BEAMER_11, EL_BEAMER_12, EL_BEAMER_13, EL_BEAMER_14, EL_BEAMER_15, }; static int ep_beamer_num = sizeof(ep_beamer) / sizeof(int); static int ep_reflecting[] = { }; static int ep_reflecting_num = sizeof(ep_reflecting) / sizeof(int); static int ep_absorbing[] = { }; static int ep_absorbing_num = sizeof(ep_absorbing) / sizeof(int); static int ep_inactive[] = { }; static int ep_inactive_num = sizeof(ep_inactive) / sizeof(int); static int ep_wall[] = { }; static int ep_wall_num = sizeof(ep_wall) / sizeof(int); static int ep_pacman[] = { EL_PACMAN_RIGHT, EL_PACMAN_UP, EL_PACMAN_LEFT, EL_PACMAN_DOWN, }; static int ep_pacman_num = sizeof(ep_pacman) / sizeof(int); static long ep_bit[] = { EP_BIT_GRID, EP_BIT_MCDUFFIN, EP_BIT_RECTANGLE, EP_BIT_MIRROR, EP_BIT_MIRROR_FIXED, EP_BIT_POLAR, EP_BIT_POLAR_CROSS, EP_BIT_BEAMER, EP_BIT_REFLECTING, EP_BIT_ABSORBING, EP_BIT_INACTIVE, EP_BIT_WALL, EP_BIT_PACMAN, }; static int *ep_array[] = { ep_grid, ep_mcduffin, ep_rectangle, ep_mirror, ep_mirror_fixed, ep_polar, ep_polar_cross, ep_beamer, ep_reflecting, ep_absorbing, ep_inactive, ep_wall, ep_pacman, }; static int *ep_num[] = { &ep_grid_num, &ep_mcduffin_num, &ep_rectangle_num, &ep_mirror_num, &ep_mirror_fixed_num, &ep_polar_num, &ep_polar_cross_num, &ep_beamer_num, &ep_reflecting_num, &ep_absorbing_num, &ep_inactive_num, &ep_wall_num, &ep_pacman_num, }; static int num_properties = sizeof(ep_num) / sizeof(int *); for(i = 0; i < MAX_ELEMENTS; i++) Elementeigenschaften[i] = 0; for(i = 0; i < num_properties; i++) for(j = 0; j < *(ep_num[i]); j++) Elementeigenschaften[(ep_array[i])[j]] |= ep_bit[i]; for(i = EL_CHAR_START; i <= EL_CHAR_END; i++) Elementeigenschaften[i] |= (EP_BIT_CHAR | EP_BIT_INACTIVE); for(i = EL_WALL_START; i <= EL_WALL_END; i++) Elementeigenschaften[i] |= EP_BIT_WALL; } void mm_open_all() { InitElementProperties_MM(); } void mm_close_all() { } mirrormagic-3.0.0/src/game_mm/mm_main.h0000644000175000017500000013320113263212010017300 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // mm_main.h // ============================================================================ #ifndef MM_MAIN_H #define MM_MAIN_H #define STD_LEV_FIELDX MM_STD_PLAYFIELD_WIDTH #define STD_LEV_FIELDY MM_STD_PLAYFIELD_HEIGHT #define MAX_LEV_FIELDX MM_MAX_PLAYFIELD_WIDTH #define MAX_LEV_FIELDY MM_MAX_PLAYFIELD_HEIGHT #define SCREENX(a) (a) #define SCREENY(a) (a) #define LEVELX(a) (a) #define LEVELY(a) (a) #define IN_FIELD(x, y, xsize, ysize) ((x) >= 0 && (x) < (xsize) && \ (y) >= 0 && (y) < (ysize)) #define IN_FIELD_MINMAX(x, y, xmin, ymin, xmax, ymax) \ ((x) >= (xmin) && (x) <= (xmax) && \ (y) >= (ymin) && (y) <= (ymax)) #define IN_PIX_FIELD(x, y) IN_FIELD(x, y, SXSIZE, SYSIZE) #define IN_VIS_FIELD(x, y) IN_FIELD(x, y, SCR_FIELDX, SCR_FIELDY) #define IN_LEV_FIELD(x, y) IN_FIELD(x, y, lev_fieldx, lev_fieldy) #define IN_SCR_FIELD(x, y) IN_FIELD_MINMAX(x, y, BX1, BY1, BX2, BY2) /* values for 'Elementeigenschaften' */ #define EP_BIT_GRID (1 << 0) #define EP_BIT_MCDUFFIN (1 << 1) #define EP_BIT_RECTANGLE (1 << 2) #define EP_BIT_MIRROR (1 << 3) #define EP_BIT_MIRROR_FIXED (1 << 4) #define EP_BIT_POLAR (1 << 5) #define EP_BIT_POLAR_CROSS (1 << 6) #define EP_BIT_BEAMER (1 << 7) #define EP_BIT_CHAR (1 << 8) #define EP_BIT_REFLECTING (1 << 9) #define EP_BIT_ABSORBING (1 << 10) #define EP_BIT_INACTIVE (1 << 11) #define EP_BIT_WALL (1 << 12) #define EP_BIT_PACMAN (1 << 13) #define IS_GRID(e) (Elementeigenschaften[e] & EP_BIT_GRID) #define IS_MCDUFFIN(e) (Elementeigenschaften[e] & EP_BIT_MCDUFFIN) #define IS_RECTANGLE(e) (Elementeigenschaften[e] & EP_BIT_RECTANGLE) #define IS_MIRROR(e) (Elementeigenschaften[e] & EP_BIT_MIRROR) #define IS_MIRROR_FIXED(e) (Elementeigenschaften[e] & EP_BIT_MIRROR_FIXED) #define IS_POLAR(e) (Elementeigenschaften[e] & EP_BIT_POLAR) #define IS_POLAR_CROSS(e) (Elementeigenschaften[e] & EP_BIT_POLAR_CROSS) #define IS_BEAMER_OLD(e) (Elementeigenschaften[e] & EP_BIT_BEAMER) #define IS_CHAR(e) (Elementeigenschaften[e] & EP_BIT_CHAR) #define IS_REFLECTING(e) (Elementeigenschaften[e] & EP_BIT_REFLECTING) #define IS_ABSORBING(e) (Elementeigenschaften[e] & EP_BIT_ABSORBING) #define IS_INACTIVE(e) (Elementeigenschaften[e] & EP_BIT_INACTIVE) #define IS_MM_WALL(e) (Elementeigenschaften[e] & EP_BIT_WALL) #define IS_PACMAN(e) (Elementeigenschaften[e] & EP_BIT_PACMAN) #define IS_WALL_STEEL(e) ((e) >= EL_WALL_STEEL_START && \ (e) <= EL_WALL_STEEL_END) #define IS_WALL_WOOD(e) ((e) >= EL_WALL_WOOD_START && \ (e) <= EL_WALL_WOOD_END) #define IS_WALL_ICE(e) ((e) >= EL_WALL_ICE_START && \ (e) <= EL_WALL_ICE_END) #define IS_WALL_AMOEBA(e) ((e) >= EL_WALL_AMOEBA_START && \ (e) <= EL_WALL_AMOEBA_END) #define IS_DF_WALL_STEEL(e) ((e) >= EL_DF_WALL_STEEL_START && \ (e) <= EL_DF_WALL_STEEL_END) #define IS_DF_WALL_WOOD(e) ((e) >= EL_DF_WALL_WOOD_START && \ (e) <= EL_DF_WALL_WOOD_END) #define IS_DF_WALL(e) ((e) >= EL_DF_WALL_START && \ (e) <= EL_DF_WALL_END) #define IS_WALL(e) (IS_MM_WALL(e) || IS_DF_WALL(e)) #define IS_WALL_CHANGING(e) ((e) >= EL_WALL_CHANGING_START && \ (e) <= EL_WALL_CHANGING_END) #define IS_GRID_STEEL(e) ((e) >= EL_GRID_STEEL_START && \ (e) <= EL_GRID_STEEL_END) #define IS_GRID_WOOD(e) ((e) >= EL_GRID_WOOD_START && \ (e) <= EL_GRID_WOOD_END) #define IS_GRID_WOOD_FIXED(e) ((e) >= EL_GRID_WOOD_FIXED_START && \ (e) <= EL_GRID_WOOD_FIXED_END) #define IS_GRID_STEEL_FIXED(e) ((e) >= EL_GRID_STEEL_FIXED_START && \ (e) <= EL_GRID_STEEL_FIXED_END) #define IS_GRID_WOOD_AUTO(e) ((e) >= EL_GRID_WOOD_AUTO_START && \ (e) <= EL_GRID_WOOD_AUTO_END) #define IS_GRID_STEEL_AUTO(e) ((e) >= EL_GRID_STEEL_AUTO_START && \ (e) <= EL_GRID_STEEL_AUTO_END) #define IS_DF_GRID(e) (IS_GRID_WOOD_FIXED(e) || \ IS_GRID_STEEL_FIXED(e) || \ IS_GRID_WOOD_AUTO(e) || \ IS_GRID_STEEL_AUTO(e)) #define IS_DF_MIRROR(e) ((e) >= EL_DF_MIRROR_START && \ (e) <= EL_DF_MIRROR_END) #define IS_DF_MIRROR_AUTO(e) ((e) >= EL_DF_MIRROR_AUTO_START && \ (e) <= EL_DF_MIRROR_AUTO_END) #define IS_LASER(e) ((e) >= EL_LASER_START && \ (e) <= EL_LASER_END) #define IS_RECEIVER(e) ((e) >= EL_RECEIVER_START && \ (e) <= EL_RECEIVER_END) #define IS_FIBRE_OPTIC(e) ((e) >= EL_FIBRE_OPTIC_START && \ (e) <= EL_FIBRE_OPTIC_END) #define FIBRE_OPTIC_NR(e) (((e) - EL_FIBRE_OPTIC_START) / 2) #define IS_BEAMER(e) ((e) >= EL_BEAMER_RED_START && \ (e) <= EL_BEAMER_BLUE_END) #define BEAMER_CLASSIC_NR(e) (((e) - EL_BEAMER_RED_START) / 16) #define BEAMER_NR(e) (IS_BEAMER(e) ? BEAMER_CLASSIC_NR(e) : \ IS_FIBRE_OPTIC(e) ? (FIBRE_OPTIC_NR(e)+4) : 0) #define IS_EXPLODING(e) ((e) == EL_EXPLODING_OPAQUE || \ (e) == EL_EXPLODING_TRANSP) #define IS_EATABLE4PACMAN(e) ((e) == EL_EMPTY || \ (e) == EL_KETTLE || \ (e) == EL_CELL || \ (e) == EL_BOMB || \ IS_WALL_AMOEBA(e)) #define CAN_MOVE(e) ((e) == EL_PACMAN) #define IS_FREE(x,y) (Feld[x][y] == EL_EMPTY) #define IS_MOVING(x,y) (MovPos[x][y] != 0) #define IS_BLOCKED(x,y) (Feld[x][y] == EL_BLOCKED) #define IS_DRAWABLE(e) ((e) < EL_BLOCKED) #define IS_NOT_DRAWABLE(e) ((e) >= EL_BLOCKED) #define PLAYERINFO(x,y) (&stored_player[StorePlayer[x][y]-EL_SPIELER1]) #define WALL_BASE(e) ((e) & 0xfff0) #define WALL_BITS(e) ((e) & 0x000f) /* Bitmaps with graphic file */ #define PIX_BACK 0 #define PIX_DOOR 1 #define PIX_TOONS 2 #define PIX_DF 3 #define PIX_BIGFONT 4 #define PIX_SMALLFONT 5 #define PIX_MEDIUMFONT 6 /* Bitmaps without graphic file */ #define PIX_DB_DOOR 7 #define NUM_PICTURES 7 #define NUM_BITMAPS 8 /* boundaries of arrays etc. */ #define MAX_PLAYER_NAME_LEN 10 #define MAX_LEVEL_NAME_LEN 32 #define MAX_LEVEL_AUTHOR_LEN 32 #define MAX_SCORE_ENTRIES 100 #define MAX_ELEMENTS 700 /* 500 static + 200 runtime */ #define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */ #define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */ /* score for elements */ #define SC_COLLECTIBLE 0 #define SC_UNUSED_1 1 #define SC_UNUSED_2 2 #define SC_UNUSED_3 3 #define SC_UNUSED_4 4 #define SC_UNUSED_5 5 #define SC_PACMAN 6 #define SC_UNUSED_7 7 #define SC_UNUSED_8 8 #define SC_KEY 9 #define SC_TIME_BONUS 10 #define SC_UNUSED_11 11 #define SC_UNUSED_12 12 #define SC_UNUSED_13 13 #define SC_LIGHTBALL 14 #define SC_UNUSED_15 15 #define LEVEL_SCORE_ELEMENTS 16 /* level elements with score */ struct HiScore_MM { char Name[MAX_PLAYER_NAME_LEN + 1]; int Score; }; extern Bitmap *pix[]; extern DrawBuffer *fieldbuffer; extern DrawBuffer *drawto_field; extern int joystick_device; extern char *joystick_device_name[]; extern int game_status; extern boolean level_editor_test_game; extern boolean network_playing; extern int key_joystick_mapping; extern int global_joystick_status, joystick_status; extern int sound_status; extern boolean sound_loops_allowed; extern boolean redraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern int redraw_x1, redraw_y1; extern short Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Hit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Box[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short Angle[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 JustStopped[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 int Elementeigenschaften[MAX_ELEMENTS]; extern int level_nr; extern int lev_fieldx, lev_fieldy, scroll_x, scroll_y; extern int FX, FY, ScrollStepSize; extern int ScreenMovDir, ScreenMovPos, ScreenGfxPos; extern int GameFrameDelay; extern int FfwdFrameDelay; extern int BX1, BY1, BX2, BY2; extern int SBX_Left, SBX_Right; extern int SBY_Upper, SBY_Lower; extern int ZX, ZY, ExitX, ExitY; extern int AllPlayersGone; extern int TimeFrames, TimePlayed, TimeLeft; extern boolean SiebAktiv; extern int SiebCount; extern struct LevelInfo_MM native_mm_level; extern struct HiScore_MM highscore[]; extern struct TapeInfo tape; extern struct SetupInfo setup; extern struct GameInfo_MM game_mm; extern struct LaserInfo laser; extern struct GlobalInfo global; extern short LX, LY, XS, YS, ELX, ELY; extern short CT, Ct; extern int dSX, dSY; extern int cSX, cSY; extern int cSX2, cSY2; extern int cFX, cFY; extern Pixel pen_fg, pen_bg, pen_ray, pen_magicolor[2]; extern int color_status; extern struct XY Step[]; extern short Sign[16]; extern char *sound_name[]; extern int background_loop[]; extern int num_bg_loops; extern char *element_info[]; extern int num_element_info; /* often used screen positions */ #define DX 534 #define DY 60 #define EX DX #define EY (DY + 178) #define TILEX TILESIZE #define TILEY TILESIZE #define MINI_TILESIZE (TILESIZE / 2) #define MINI_TILEX (TILEX / 2) #define MINI_TILEY (TILEY / 2) #define MICRO_TILEX (TILEX / 4) #define MICRO_TILEY (TILEY / 4) #define MICRO_WALLX (TILEX / 8) #define MICRO_WALLY (TILEY / 8) #define MIDPOSX (SCR_FIELDX / 2) #define MIDPOSY (SCR_FIELDY / 2) #define DXSIZE 100 #define DYSIZE 280 #define VXSIZE DXSIZE #define VYSIZE 100 #define EXSIZE DXSIZE #define EYSIZE (VXSIZE + 44) #define FULL_SXSIZE (2 + SXSIZE + 2) #define FULL_SYSIZE (2 + SYSIZE + 2) #define MICROLEV_XPOS (SX + 12 * TILEX) #define MICROLEV_YPOS (SY + 6 * TILEY) #define MICROLEV_XSIZE (STD_LEV_FIELDX * MICRO_TILEX) #define MICROLEV_YSIZE (STD_LEV_FIELDY * MICRO_TILEY) #define MICROLABEL_XPOS (SY) #define MICROLABEL_YPOS (SY + 352) #define MICROLABEL_XSIZE (SXSIZE) #define MICROLABEL_YSIZE (FONT4_YSIZE) #define GFX_STARTX SX #define GFX_STARTY SY #define MINI_GFX_STARTX (SX + 8 * TILEX) #define MINI_GFX_STARTY (SY + 6 * TILEY) #define MICRO_GFX_STARTX (MINI_GFX_STARTX + 8 * MINI_TILEX) #define MICRO_GFX_STARTY (MINI_GFX_STARTY + 6 * MINI_TILEY) #define GFX_PER_LINE 16 #define MINI_GFX_PER_LINE GFX_PER_LINE #define MICRO_GFX_PER_LINE GFX_PER_LINE #define MINI_DF_STARTX (8 * TILEX) #define MINI_DF_STARTY (8 * TILEY) #define MICRO_DF_STARTX (MINI_DF_STARTX + 8 * MINI_TILEX) #define MICRO_DF_STARTY (MINI_DF_STARTY + 8 * MINI_TILEY) #define DF_PER_LINE 16 #define MINI_DF_PER_LINE DF_PER_LINE #define MICRO_DF_PER_LINE DF_PER_LINE #define MICRO_FONT_STARTX (MICRO_DF_STARTX + 8 * MICRO_TILEX) #define MICRO_FONT_STARTY (MICRO_DF_STARTY + 8 * MICRO_TILEY) #define MICRO_FONT_PER_LINE 8 /* wall positions (that can be OR'ed together) */ #define WALL_TOPLEFT 1 #define WALL_TOPRIGHT 2 #define WALL_BOTTOMLEFT 4 #define WALL_BOTTOMRIGHT 8 #define WALL_LEFT (WALL_TOPLEFT | WALL_BOTTOMLEFT) #define WALL_RIGHT (WALL_TOPRIGHT | WALL_BOTTOMRIGHT) #define WALL_TOP (WALL_TOPLEFT | WALL_TOPRIGHT) #define WALL_BOTTOM (WALL_BOTTOMLEFT | WALL_BOTTOMRIGHT) /* game elements: ** 0 - 499: real elements, stored in level file ** 500 - 699: flag elements, only used at runtime */ /* "real" level elements */ #define EL_MM_START 0 #define EL_MM_START_1 EL_MM_START #define EL_EMPTY 0 #define EL_MIRROR_START 1 #define EL_MIRROR_00 (EL_MIRROR_START + 0) #define EL_MIRROR_01 (EL_MIRROR_START + 1) #define EL_MIRROR_02 (EL_MIRROR_START + 2) #define EL_MIRROR_03 (EL_MIRROR_START + 3) #define EL_MIRROR_04 (EL_MIRROR_START + 4) #define EL_MIRROR_05 (EL_MIRROR_START + 5) #define EL_MIRROR_06 (EL_MIRROR_START + 6) #define EL_MIRROR_07 (EL_MIRROR_START + 7) #define EL_MIRROR_08 (EL_MIRROR_START + 8) #define EL_MIRROR_09 (EL_MIRROR_START + 9) #define EL_MIRROR_10 (EL_MIRROR_START + 10) #define EL_MIRROR_11 (EL_MIRROR_START + 11) #define EL_MIRROR_12 (EL_MIRROR_START + 12) #define EL_MIRROR_13 (EL_MIRROR_START + 13) #define EL_MIRROR_14 (EL_MIRROR_START + 14) #define EL_MIRROR_15 (EL_MIRROR_START + 15) #define EL_MIRROR_END EL_MIRROR_15 #define EL_GRID_STEEL_START 17 #define EL_GRID_STEEL_00 (EL_GRID_STEEL_START + 0) #define EL_GRID_STEEL_01 (EL_GRID_STEEL_START + 1) #define EL_GRID_STEEL_02 (EL_GRID_STEEL_START + 2) #define EL_GRID_STEEL_03 (EL_GRID_STEEL_START + 3) #define EL_GRID_STEEL_END EL_GRID_STEEL_03 #define EL_MCDUFFIN_START 21 #define EL_MCDUFFIN_RIGHT (EL_MCDUFFIN_START + 0) #define EL_MCDUFFIN_UP (EL_MCDUFFIN_START + 1) #define EL_MCDUFFIN_LEFT (EL_MCDUFFIN_START + 2) #define EL_MCDUFFIN_DOWN (EL_MCDUFFIN_START + 3) #define EL_MCDUFFIN_END EL_MCDUFFIN_DOWN #define EL_EXIT_CLOSED 25 #define EL_EXIT_OPENING_1 26 #define EL_EXIT_OPENING_2 27 #define EL_EXIT_OPEN 28 #define EL_KETTLE 29 #define EL_BOMB 30 #define EL_PRISM 31 #define EL_WALL_START 32 #define EL_WALL_EMPTY EL_WALL_START #define EL_WALL_00 EL_WALL_START #define EL_WALL_STEEL EL_WALL_00 #define EL_WALL_STEEL_START EL_WALL_00 #define EL_WALL_15 47 #define EL_WALL_STEEL_END EL_WALL_15 #define EL_WALL_16 48 #define EL_WALL_WOOD EL_WALL_16 #define EL_WALL_WOOD_START EL_WALL_16 #define EL_WALL_31 63 #define EL_WALL_WOOD_END EL_WALL_31 #define EL_WALL_32 64 #define EL_WALL_ICE EL_WALL_32 #define EL_WALL_ICE_START EL_WALL_32 #define EL_WALL_47 79 #define EL_WALL_ICE_END EL_WALL_47 #define EL_WALL_48 80 #define EL_WALL_AMOEBA EL_WALL_48 #define EL_WALL_AMOEBA_START EL_WALL_48 #define EL_WALL_63 95 #define EL_WALL_AMOEBA_END EL_WALL_63 #define EL_WALL_END EL_WALL_63 #define EL_BLOCK_WOOD 96 #define EL_BALL_GRAY 97 #define EL_BEAMER_START 98 #define EL_BEAMER_00 (EL_BEAMER_START + 0) #define EL_BEAMER_01 (EL_BEAMER_START + 1) #define EL_BEAMER_02 (EL_BEAMER_START + 2) #define EL_BEAMER_03 (EL_BEAMER_START + 3) #define EL_BEAMER_04 (EL_BEAMER_START + 4) #define EL_BEAMER_05 (EL_BEAMER_START + 5) #define EL_BEAMER_06 (EL_BEAMER_START + 6) #define EL_BEAMER_07 (EL_BEAMER_START + 7) #define EL_BEAMER_08 (EL_BEAMER_START + 8) #define EL_BEAMER_09 (EL_BEAMER_START + 9) #define EL_BEAMER_10 (EL_BEAMER_START + 10) #define EL_BEAMER_11 (EL_BEAMER_START + 11) #define EL_BEAMER_12 (EL_BEAMER_START + 12) #define EL_BEAMER_13 (EL_BEAMER_START + 13) #define EL_BEAMER_14 (EL_BEAMER_START + 14) #define EL_BEAMER_15 (EL_BEAMER_START + 15) #define EL_BEAMER_END EL_BEAMER_15 #define EL_FUSE_ON 114 #define EL_PACMAN_START 115 #define EL_PACMAN_RIGHT (EL_PACMAN_START + 0) #define EL_PACMAN_UP (EL_PACMAN_START + 1) #define EL_PACMAN_LEFT (EL_PACMAN_START + 2) #define EL_PACMAN_DOWN (EL_PACMAN_START + 3) #define EL_PACMAN_END EL_PACMAN_DOWN #define EL_POLAR_START 119 #define EL_POLAR_00 (EL_POLAR_START + 0) #define EL_POLAR_01 (EL_POLAR_START + 1) #define EL_POLAR_02 (EL_POLAR_START + 2) #define EL_POLAR_03 (EL_POLAR_START + 3) #define EL_POLAR_04 (EL_POLAR_START + 4) #define EL_POLAR_05 (EL_POLAR_START + 5) #define EL_POLAR_06 (EL_POLAR_START + 6) #define EL_POLAR_07 (EL_POLAR_START + 7) #define EL_POLAR_08 (EL_POLAR_START + 8) #define EL_POLAR_09 (EL_POLAR_START + 9) #define EL_POLAR_10 (EL_POLAR_START + 10) #define EL_POLAR_11 (EL_POLAR_START + 11) #define EL_POLAR_12 (EL_POLAR_START + 12) #define EL_POLAR_13 (EL_POLAR_START + 13) #define EL_POLAR_14 (EL_POLAR_START + 14) #define EL_POLAR_15 (EL_POLAR_START + 15) #define EL_POLAR_END EL_POLAR_15 #define EL_POLAR_CROSS_START 135 #define EL_POLAR_CROSS_00 (EL_POLAR_CROSS_START + 0) #define EL_POLAR_CROSS_01 (EL_POLAR_CROSS_START + 1) #define EL_POLAR_CROSS_02 (EL_POLAR_CROSS_START + 2) #define EL_POLAR_CROSS_03 (EL_POLAR_CROSS_START + 3) #define EL_POLAR_CROSS_END EL_POLAR_CROSS_03 #define EL_MIRROR_FIXED_START 139 #define EL_MIRROR_FIXED_00 (EL_MIRROR_FIXED_START + 0) #define EL_MIRROR_FIXED_01 (EL_MIRROR_FIXED_START + 1) #define EL_MIRROR_FIXED_02 (EL_MIRROR_FIXED_START + 2) #define EL_MIRROR_FIXED_03 (EL_MIRROR_FIXED_START + 3) #define EL_MIRROR_FIXED_END EL_MIRROR_FIXED_03 #define EL_GATE_STONE 143 #define EL_KEY 144 #define EL_LIGHTBULB_OFF 145 #define EL_LIGHTBULB_ON 146 #define EL_LIGHTBALL 147 #define EL_BLOCK_STONE 148 #define EL_GATE_WOOD 149 #define EL_FUEL_FULL 150 #define EL_GRID_WOOD_START 151 #define EL_GRID_WOOD_00 (EL_GRID_WOOD_START + 0) #define EL_GRID_WOOD_01 (EL_GRID_WOOD_START + 1) #define EL_GRID_WOOD_02 (EL_GRID_WOOD_START + 2) #define EL_GRID_WOOD_03 (EL_GRID_WOOD_START + 3) #define EL_GRID_WOOD_END EL_GRID_WOOD_03 #define EL_FUEL_EMPTY 155 #define EL_MM_END_1 155 #define EL_CHAR_START 160 #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_RAUTE (EL_CHAR_ASCII0 + 35) #define EL_CHAR_DOLLAR (EL_CHAR_ASCII0 + 36) #define EL_CHAR_PROZ (EL_CHAR_ASCII0 + 37) #define EL_CHAR_AMPERSAND (EL_CHAR_ASCII0 + 38) #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_MULT (EL_CHAR_ASCII0 + 42) #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_CHAR(x) ((x) == CHAR_BYTE_UMLAUT_A ? EL_CHAR_AE : \ (x) == CHAR_BYTE_UMLAUT_O ? EL_CHAR_OE : \ (x) == CHAR_BYTE_UMLAUT_U ? EL_CHAR_UE : \ EL_CHAR_A + (x) - 'A') #define EL_MM_START_2 240 /* elements for "Deflektor" style levels */ #define EL_DF_START EL_MM_START_2 #define EL_DF_MIRROR_START EL_DF_START #define EL_DF_MIRROR_00 (EL_DF_MIRROR_START + 0) #define EL_DF_MIRROR_01 (EL_DF_MIRROR_START + 1) #define EL_DF_MIRROR_02 (EL_DF_MIRROR_START + 2) #define EL_DF_MIRROR_03 (EL_DF_MIRROR_START + 3) #define EL_DF_MIRROR_04 (EL_DF_MIRROR_START + 4) #define EL_DF_MIRROR_05 (EL_DF_MIRROR_START + 5) #define EL_DF_MIRROR_06 (EL_DF_MIRROR_START + 6) #define EL_DF_MIRROR_07 (EL_DF_MIRROR_START + 7) #define EL_DF_MIRROR_08 (EL_DF_MIRROR_START + 8) #define EL_DF_MIRROR_09 (EL_DF_MIRROR_START + 9) #define EL_DF_MIRROR_10 (EL_DF_MIRROR_START + 10) #define EL_DF_MIRROR_11 (EL_DF_MIRROR_START + 11) #define EL_DF_MIRROR_12 (EL_DF_MIRROR_START + 12) #define EL_DF_MIRROR_13 (EL_DF_MIRROR_START + 13) #define EL_DF_MIRROR_14 (EL_DF_MIRROR_START + 14) #define EL_DF_MIRROR_15 (EL_DF_MIRROR_START + 15) #define EL_DF_MIRROR_END EL_DF_MIRROR_15 #define EL_GRID_WOOD_FIXED_START 256 #define EL_GRID_WOOD_FIXED_00 (EL_GRID_WOOD_FIXED_START + 0) /* 0.0° */ #define EL_GRID_WOOD_FIXED_01 (EL_GRID_WOOD_FIXED_START + 1) /* 22.5° */ #define EL_GRID_WOOD_FIXED_02 (EL_GRID_WOOD_FIXED_START + 2) /* 45.0° */ #define EL_GRID_WOOD_FIXED_03 (EL_GRID_WOOD_FIXED_START + 3) /* 67.5° */ #define EL_GRID_WOOD_FIXED_04 (EL_GRID_WOOD_FIXED_START + 4) /* 90.0° */ #define EL_GRID_WOOD_FIXED_05 (EL_GRID_WOOD_FIXED_START + 5) /* 112.5° */ #define EL_GRID_WOOD_FIXED_06 (EL_GRID_WOOD_FIXED_START + 6) /* 135.0° */ #define EL_GRID_WOOD_FIXED_07 (EL_GRID_WOOD_FIXED_START + 7) /* 157.5° */ #define EL_GRID_WOOD_FIXED_END EL_GRID_WOOD_FIXED_07 #define EL_GRID_STEEL_FIXED_START 264 #define EL_GRID_STEEL_FIXED_00 (EL_GRID_STEEL_FIXED_START + 0) /* 0.0° */ #define EL_GRID_STEEL_FIXED_01 (EL_GRID_STEEL_FIXED_START + 1) /* 22.5° */ #define EL_GRID_STEEL_FIXED_02 (EL_GRID_STEEL_FIXED_START + 2) /* 45.0° */ #define EL_GRID_STEEL_FIXED_03 (EL_GRID_STEEL_FIXED_START + 3) /* 67.5° */ #define EL_GRID_STEEL_FIXED_04 (EL_GRID_STEEL_FIXED_START + 4) /* 90.0° */ #define EL_GRID_STEEL_FIXED_05 (EL_GRID_STEEL_FIXED_START + 5) /* 112.5° */ #define EL_GRID_STEEL_FIXED_06 (EL_GRID_STEEL_FIXED_START + 6) /* 135.0° */ #define EL_GRID_STEEL_FIXED_07 (EL_GRID_STEEL_FIXED_START + 7) /* 157.5° */ #define EL_GRID_STEEL_FIXED_END EL_GRID_STEEL_FIXED_07 #define EL_DF_WALL_WOOD 272 #define EL_DF_WALL_START EL_DF_WALL_WOOD_START #define EL_DF_WALL_WOOD_START (EL_DF_WALL_WOOD + 0) #define EL_DF_WALL_WOOD_END (EL_DF_WALL_WOOD + 15) #define EL_DF_WALL_STEEL 288 #define EL_DF_WALL_STEEL_START (EL_DF_WALL_STEEL + 0) #define EL_DF_WALL_STEEL_END (EL_DF_WALL_STEEL + 15) #define EL_DF_WALL_END EL_DF_WALL_STEEL_END #define EL_DF_EMPTY 304 #define EL_CELL 305 #define EL_MINE 306 #define EL_REFRACTOR 307 #define EL_LASER_START 308 #define EL_LASER_RIGHT (EL_LASER_START + 0) #define EL_LASER_UP (EL_LASER_START + 1) #define EL_LASER_LEFT (EL_LASER_START + 2) #define EL_LASER_DOWN (EL_LASER_START + 3) #define EL_LASER_END EL_LASER_DOWN #define EL_RECEIVER_START 312 #define EL_RECEIVER_RIGHT (EL_RECEIVER_START + 0) #define EL_RECEIVER_UP (EL_RECEIVER_START + 1) #define EL_RECEIVER_LEFT (EL_RECEIVER_START + 2) #define EL_RECEIVER_DOWN (EL_RECEIVER_START + 3) #define EL_RECEIVER_END EL_RECEIVER_DOWN #define EL_FIBRE_OPTIC_START 316 #define EL_FIBRE_OPTIC_00 (EL_FIBRE_OPTIC_START + 0) #define EL_FIBRE_OPTIC_01 (EL_FIBRE_OPTIC_START + 1) #define EL_FIBRE_OPTIC_02 (EL_FIBRE_OPTIC_START + 2) #define EL_FIBRE_OPTIC_03 (EL_FIBRE_OPTIC_START + 3) #define EL_FIBRE_OPTIC_04 (EL_FIBRE_OPTIC_START + 4) #define EL_FIBRE_OPTIC_05 (EL_FIBRE_OPTIC_START + 5) #define EL_FIBRE_OPTIC_06 (EL_FIBRE_OPTIC_START + 6) #define EL_FIBRE_OPTIC_07 (EL_FIBRE_OPTIC_START + 7) #define EL_FIBRE_OPTIC_END EL_FIBRE_OPTIC_07 #define EL_DF_MIRROR_AUTO_START 324 #define EL_DF_MIRROR_AUTO_00 (EL_DF_MIRROR_AUTO_START + 0) #define EL_DF_MIRROR_AUTO_01 (EL_DF_MIRROR_AUTO_START + 1) #define EL_DF_MIRROR_AUTO_02 (EL_DF_MIRROR_AUTO_START + 2) #define EL_DF_MIRROR_AUTO_03 (EL_DF_MIRROR_AUTO_START + 3) #define EL_DF_MIRROR_AUTO_04 (EL_DF_MIRROR_AUTO_START + 4) #define EL_DF_MIRROR_AUTO_05 (EL_DF_MIRROR_AUTO_START + 5) #define EL_DF_MIRROR_AUTO_06 (EL_DF_MIRROR_AUTO_START + 6) #define EL_DF_MIRROR_AUTO_07 (EL_DF_MIRROR_AUTO_START + 7) #define EL_DF_MIRROR_AUTO_08 (EL_DF_MIRROR_AUTO_START + 8) #define EL_DF_MIRROR_AUTO_09 (EL_DF_MIRROR_AUTO_START + 9) #define EL_DF_MIRROR_AUTO_10 (EL_DF_MIRROR_AUTO_START + 10) #define EL_DF_MIRROR_AUTO_11 (EL_DF_MIRROR_AUTO_START + 11) #define EL_DF_MIRROR_AUTO_12 (EL_DF_MIRROR_AUTO_START + 12) #define EL_DF_MIRROR_AUTO_13 (EL_DF_MIRROR_AUTO_START + 13) #define EL_DF_MIRROR_AUTO_14 (EL_DF_MIRROR_AUTO_START + 14) #define EL_DF_MIRROR_AUTO_15 (EL_DF_MIRROR_AUTO_START + 15) #define EL_DF_MIRROR_AUTO_END EL_DF_MIRROR_AUTO_15 #define EL_GRID_WOOD_AUTO_START 340 #define EL_GRID_WOOD_AUTO_00 (EL_GRID_WOOD_AUTO_START + 0) #define EL_GRID_WOOD_AUTO_01 (EL_GRID_WOOD_AUTO_START + 1) #define EL_GRID_WOOD_AUTO_02 (EL_GRID_WOOD_AUTO_START + 2) #define EL_GRID_WOOD_AUTO_03 (EL_GRID_WOOD_AUTO_START + 3) #define EL_GRID_WOOD_AUTO_04 (EL_GRID_WOOD_AUTO_START + 4) #define EL_GRID_WOOD_AUTO_05 (EL_GRID_WOOD_AUTO_START + 5) #define EL_GRID_WOOD_AUTO_06 (EL_GRID_WOOD_AUTO_START + 6) #define EL_GRID_WOOD_AUTO_07 (EL_GRID_WOOD_AUTO_START + 7) #define EL_GRID_WOOD_AUTO_END EL_GRID_WOOD_AUTO_07 #define EL_GRID_STEEL_AUTO_START 348 #define EL_GRID_STEEL_AUTO_00 (EL_GRID_STEEL_AUTO_START + 0) #define EL_GRID_STEEL_AUTO_01 (EL_GRID_STEEL_AUTO_START + 1) #define EL_GRID_STEEL_AUTO_02 (EL_GRID_STEEL_AUTO_START + 2) #define EL_GRID_STEEL_AUTO_03 (EL_GRID_STEEL_AUTO_START + 3) #define EL_GRID_STEEL_AUTO_04 (EL_GRID_STEEL_AUTO_START + 4) #define EL_GRID_STEEL_AUTO_05 (EL_GRID_STEEL_AUTO_START + 5) #define EL_GRID_STEEL_AUTO_06 (EL_GRID_STEEL_AUTO_START + 6) #define EL_GRID_STEEL_AUTO_07 (EL_GRID_STEEL_AUTO_START + 7) #define EL_GRID_STEEL_AUTO_END EL_GRID_STEEL_AUTO_07 #define EL_DF_END 355 #define EL_BEAMER_RED_START 356 #define EL_BEAMER_RED_END (EL_BEAMER_RED_START + 15) #define EL_BEAMER_YELLOW_START 372 #define EL_BEAMER_YELLOW_END (EL_BEAMER_YELLOW_START + 15) #define EL_BEAMER_GREEN_START 388 #define EL_BEAMER_GREEN_END (EL_BEAMER_GREEN_START + 15) #define EL_BEAMER_BLUE_START 404 #define EL_BEAMER_BLUE_END (EL_BEAMER_BLUE_START + 15) /* element definitions partially used for drawing graphics */ #define EL_MCDUFFIN 420 #define EL_PACMAN 421 #define EL_FUSE_OFF 422 #define EL_STEEL_WALL 423 #define EL_WOODEN_WALL 424 #define EL_ICE_WALL 425 #define EL_AMOEBA_WALL 426 #define EL_LASER 427 #define EL_RECEIVER 428 #define EL_DF_STEEL_WALL 429 #define EL_DF_WOODEN_WALL 430 #define EL_MM_END_2 430 #define EL_MM_END EL_MM_END_2 /* "real" (and therefore drawable) runtime elements */ #define EL_EXIT_OPENING 500 #define EL_EXIT_CLOSING 501 #define EL_GRAY_BALL_OPENING 502 #define EL_ICE_WALL_SHRINKING 503 #define EL_AMOEBA_WALL_GROWING 504 #define EL_WALL_CHANGING 512 #define EL_WALL_CHANGING_START (EL_WALL_CHANGING + 0) #define EL_WALL_CHANGING_END (EL_WALL_CHANGING + 15) #define EL_FIRST_RUNTIME_EL EL_EXIT_OPENING /* "unreal" (and therefore not drawable) runtime elements */ #define EL_BLOCKED 600 #define EL_EXPLODING_OPAQUE 601 #define EL_EXPLODING_TRANSP 602 /* dummy elements (never used as game elements, only used as graphics) */ #define EL_MM_MASK_MCDUFFIN_RIGHT 700 #define EL_MM_MASK_MCDUFFIN_UP 701 #define EL_MM_MASK_MCDUFFIN_LEFT 702 #define EL_MM_MASK_MCDUFFIN_DOWN 703 #define EL_MM_MASK_GRID_1 704 #define EL_MM_MASK_GRID_2 705 #define EL_MM_MASK_GRID_3 706 #define EL_MM_MASK_GRID_4 707 #define EL_MM_MASK_RECTANGE 708 #define EL_MM_MASK_CIRCLE 709 /* game graphics: ** 0 - 191: graphics from "MirrorScreen" ** 192 - 255: pseudo graphics mapped to "MirrorScreen" ** 256 - 511: graphics from "MirrorFont" ** 512 - 767: graphics from "MirrorDF" */ #define IMG_EMPTY IMG_EMPTY_SPACE #define GFX_START_MIRRORSCREEN 0 #define GFX_END_MIRRORSCREEN 191 #define GFX_START_PSEUDO 192 #define GFX_END_PSEUDO 255 #define GFX_START_MIRRORFONT 256 #define GFX_END_MIRRORFONT 511 #define GFX_START_MIRRORDF 512 #define GFX_END_MIRRORDF 767 #define NUM_TILES 512 /* graphics from "MirrorScreen" */ #define GFX_EMPTY (-1) /* row 0 (0) */ #define GFX_MIRROR_START 0 #define GFX_MIRROR GFX_MIRROR_START #define GFX_MIRROR_00 (GFX_MIRROR_START + 0) #define GFX_MIRROR_01 (GFX_MIRROR_START + 1) #define GFX_MIRROR_02 (GFX_MIRROR_START + 2) #define GFX_MIRROR_03 (GFX_MIRROR_START + 3) #define GFX_MIRROR_04 (GFX_MIRROR_START + 4) #define GFX_MIRROR_05 (GFX_MIRROR_START + 5) #define GFX_MIRROR_06 (GFX_MIRROR_START + 6) #define GFX_MIRROR_07 (GFX_MIRROR_START + 7) #define GFX_MIRROR_08 (GFX_MIRROR_START + 8) #define GFX_MIRROR_09 (GFX_MIRROR_START + 9) #define GFX_MIRROR_10 (GFX_MIRROR_START + 10) #define GFX_MIRROR_11 (GFX_MIRROR_START + 11) #define GFX_MIRROR_12 (GFX_MIRROR_START + 12) #define GFX_MIRROR_13 (GFX_MIRROR_START + 13) #define GFX_MIRROR_14 (GFX_MIRROR_START + 14) #define GFX_MIRROR_15 (GFX_MIRROR_START + 15) #define GFX_MIRROR_END GFX_MIRROR_15 /* row 1 (16) */ #define GFX_GRID_STEEL_START 16 #define GFX_GRID_STEEL GFX_GRID_STEEL_START #define GFX_GRID_STEEL_00 (GFX_GRID_STEEL_START + 0) #define GFX_GRID_STEEL_01 (GFX_GRID_STEEL_START + 1) #define GFX_GRID_STEEL_02 (GFX_GRID_STEEL_START + 2) #define GFX_GRID_STEEL_03 (GFX_GRID_STEEL_START + 3) #define GFX_MCDUFFIN_START 20 #define GFX_MCDUFFIN GFX_MCDUFFIN_START #define GFX_MCDUFFIN_RIGHT (GFX_MCDUFFIN_START + 0) #define GFX_MCDUFFIN_UP (GFX_MCDUFFIN_START + 1) #define GFX_MCDUFFIN_LEFT (GFX_MCDUFFIN_START + 2) #define GFX_MCDUFFIN_DOWN (GFX_MCDUFFIN_START + 3) #define GFX_EXIT_CLOSED 24 #define GFX_EXIT_OPENING_1 25 #define GFX_EXIT_OPENING_2 26 #define GFX_EXIT_OPEN 27 #define GFX_KETTLE 28 #define GFX_EXPLOSION_KETTLE 29 /* row 2 (32) */ #define GFX_PRISM 32 #define GFX_WALL_SEVERAL 33 #define GFX_WALL_ANIMATION 34 #define GFX_BLOCK_WOOD 36 #define GFX_BOMB 37 #define GFX_FUSE_ON 38 #define GFX_FUSE_OFF 39 #define GFX_GATE_STONE 40 #define GFX_KEY 41 #define GFX_LIGHTBULB_OFF 42 #define GFX_LIGHTBULB_ON 43 #define GFX_BALL_RED 44 #define GFX_BALL_BLUE 45 #define GFX_BALL_YELLOW 46 #define GFX_BALL_GRAY 47 /* row 3 (48) */ #define GFX_BEAMER_START 48 #define GFX_BEAMER_END 63 /* row 4 (64) */ #define GFX_PACMAN_START 64 #define GFX_PACMAN GFX_PACMAN_START #define GFX_PACMAN_RIGHT (GFX_PACMAN_START + 0) #define GFX_PACMAN_UP (GFX_PACMAN_START + 1) #define GFX_PACMAN_LEFT (GFX_PACMAN_START + 2) #define GFX_PACMAN_DOWN (GFX_PACMAN_START + 3) #define GFX_EXPLOSION_START 72 #define GFX_EXPLOSION_SHORT 76 #define GFX_EXPLOSION_LAST 78 /* row 5 (80) */ #define GFX_POLAR_START 80 #define GFX_POLAR_END 95 /* row 6 (96) */ #define GFX_POLAR_CROSS_START 96 #define GFX_POLAR_CROSS GFX_POLAR_CROSS_START #define GFX_POLAR_CROSS_00 (GFX_POLAR_CROSS_START + 0) #define GFX_POLAR_CROSS_01 (GFX_POLAR_CROSS_START + 1) #define GFX_POLAR_CROSS_02 (GFX_POLAR_CROSS_START + 2) #define GFX_POLAR_CROSS_03 (GFX_POLAR_CROSS_START + 3) #define GFX_MIRROR_FIXED_START 100 #define GFX_MIRROR_FIXED GFX_MIRROR_FIXED_START #define GFX_MIRROR_FIXED_00 (GFX_MIRROR_FIXED_START + 0) #define GFX_MIRROR_FIXED_01 (GFX_MIRROR_FIXED_START + 1) #define GFX_MIRROR_FIXED_02 (GFX_MIRROR_FIXED_START + 2) #define GFX_MIRROR_FIXED_03 (GFX_MIRROR_FIXED_START + 3) /* row 7 (112) */ #define GFX_BLOCK_STONE 112 #define GFX_GATE_WOOD 113 #define GFX_FUEL_FULL 114 #define GFX_FUEL_EMPTY 115 #define GFX_GRID_WOOD_00 116 #define GFX_GRID_WOOD_01 117 #define GFX_GRID_WOOD_02 118 #define GFX_GRID_WOOD_03 119 /* row 8 (128) */ #define GFX_ARROW_BLUE_LEFT 128 #define GFX_ARROW_BLUE_RIGHT 129 #define GFX_ARROW_BLUE_UP 130 #define GFX_ARROW_BLUE_DOWN 131 #define GFX_ARROW_RED_LEFT 132 #define GFX_ARROW_RED_RIGHT 133 #define GFX_ARROW_RED_UP 134 #define GFX_ARROW_RED_DOWN 135 /* row 9 (144) */ #define GFX_SCROLLBAR_BLUE 144 #define GFX_SCROLLBAR_RED 145 /* row 10 (160) */ #define GFX_MASK_CIRCLE 160 #define GFX_MASK_RECTANGLE 161 #define GFX_MASK_RECTANGLE2 162 #define GFX_MASK_RECTANGLE3 163 #define GFX_MASK_GRID_00 164 #define GFX_MASK_GRID_01 165 #define GFX_MASK_GRID_02 166 #define GFX_MASK_GRID_03 167 /* row 11 (176) */ #define GFX_MASK_MCDUFFIN_00 176 #define GFX_MASK_MCDUFFIN_01 177 #define GFX_MASK_MCDUFFIN_02 178 #define GFX_MASK_MCDUFFIN_03 179 /* pseudo-graphics; will be mapped to other graphics */ #define GFX_WALL_STEEL 192 #define GFX_WALL_WOOD 193 #define GFX_WALL_ICE 194 #define GFX_WALL_AMOEBA 195 #define GFX_DF_WALL_STEEL 196 #define GFX_DF_WALL_WOOD 197 #define GFX_KUGEL_ROT GFX_BALL_RED #define GFX_KUGEL_BLAU GFX_BALL_BLUE #define GFX_KUGEL_GELB GFX_BALL_YELLOW #define GFX_KUGEL_GRAU GFX_BALL_GRAY /* graphics from "MirrorFont" */ #define GFX_CHAR_START (GFX_START_MIRRORFONT) #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) /* graphics from "MirrorDF" */ #define GFX_DF_MIRROR_00 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 0) #define GFX_DF_MIRROR_01 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 1) #define GFX_DF_MIRROR_02 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 2) #define GFX_DF_MIRROR_03 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 3) #define GFX_DF_MIRROR_04 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 4) #define GFX_DF_MIRROR_05 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 5) #define GFX_DF_MIRROR_06 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 6) #define GFX_DF_MIRROR_07 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 7) #define GFX_DF_MIRROR_08 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 8) #define GFX_DF_MIRROR_09 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 9) #define GFX_DF_MIRROR_10 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 10) #define GFX_DF_MIRROR_11 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 11) #define GFX_DF_MIRROR_12 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 12) #define GFX_DF_MIRROR_13 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 13) #define GFX_DF_MIRROR_14 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 14) #define GFX_DF_MIRROR_15 (GFX_START_MIRRORDF + 0 * DF_PER_LINE + 15) #define GFX_DF_MIRROR_AUTO_00 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 0) #define GFX_DF_MIRROR_AUTO_01 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 1) #define GFX_DF_MIRROR_AUTO_02 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 2) #define GFX_DF_MIRROR_AUTO_03 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 3) #define GFX_DF_MIRROR_AUTO_04 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 4) #define GFX_DF_MIRROR_AUTO_05 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 5) #define GFX_DF_MIRROR_AUTO_06 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 6) #define GFX_DF_MIRROR_AUTO_07 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 7) #define GFX_DF_MIRROR_AUTO_08 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 8) #define GFX_DF_MIRROR_AUTO_09 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 9) #define GFX_DF_MIRROR_AUTO_10 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 10) #define GFX_DF_MIRROR_AUTO_11 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 11) #define GFX_DF_MIRROR_AUTO_12 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 12) #define GFX_DF_MIRROR_AUTO_13 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 13) #define GFX_DF_MIRROR_AUTO_14 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 14) #define GFX_DF_MIRROR_AUTO_15 (GFX_START_MIRRORDF + 1 * DF_PER_LINE + 15) #define GFX_GRID_STEEL_FIXED_00 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 0) #define GFX_GRID_STEEL_FIXED_01 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 1) #define GFX_GRID_STEEL_FIXED_02 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 2) #define GFX_GRID_STEEL_FIXED_03 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 3) #define GFX_GRID_STEEL_FIXED_04 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 4) #define GFX_GRID_STEEL_FIXED_05 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 5) #define GFX_GRID_STEEL_FIXED_06 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 6) #define GFX_GRID_STEEL_FIXED_07 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 7) #define GFX_GRID_STEEL_FIXED GFX_GRID_STEEL_FIXED_00 #define GFX_GRID_WOOD_FIXED_00 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 8) #define GFX_GRID_WOOD_FIXED_01 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 9) #define GFX_GRID_WOOD_FIXED_02 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 10) #define GFX_GRID_WOOD_FIXED_03 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 11) #define GFX_GRID_WOOD_FIXED_04 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 12) #define GFX_GRID_WOOD_FIXED_05 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 13) #define GFX_GRID_WOOD_FIXED_06 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 14) #define GFX_GRID_WOOD_FIXED_07 (GFX_START_MIRRORDF + 2 * DF_PER_LINE + 15) #define GFX_GRID_WOOD_FIXED GFX_GRID_WOOD_FIXED_00 #define GFX_GRID_STEEL_AUTO_00 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 0) #define GFX_GRID_STEEL_AUTO_01 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 1) #define GFX_GRID_STEEL_AUTO_02 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 2) #define GFX_GRID_STEEL_AUTO_03 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 3) #define GFX_GRID_STEEL_AUTO_04 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 4) #define GFX_GRID_STEEL_AUTO_05 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 5) #define GFX_GRID_STEEL_AUTO_06 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 6) #define GFX_GRID_STEEL_AUTO_07 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 7) #define GFX_GRID_STEEL_AUTO GFX_GRID_STEEL_AUTO_00 #define GFX_GRID_WOOD_AUTO_00 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 8) #define GFX_GRID_WOOD_AUTO_01 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 9) #define GFX_GRID_WOOD_AUTO_02 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 10) #define GFX_GRID_WOOD_AUTO_03 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 11) #define GFX_GRID_WOOD_AUTO_04 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 12) #define GFX_GRID_WOOD_AUTO_05 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 13) #define GFX_GRID_WOOD_AUTO_06 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 14) #define GFX_GRID_WOOD_AUTO_07 (GFX_START_MIRRORDF + 3 * DF_PER_LINE + 15) #define GFX_GRID_WOOD_AUTO GFX_GRID_WOOD_AUTO_00 #define GFX_BEAMER_RED_START (GFX_START_MIRRORDF + 4 * DF_PER_LINE + 0) #define GFX_BEAMER_RED_END (GFX_START_MIRRORDF + 4 * DF_PER_LINE + 15) #define GFX_BEAMER_YELLOW_START (GFX_START_MIRRORDF + 5 * DF_PER_LINE + 0) #define GFX_BEAMER_YELLOW_END (GFX_START_MIRRORDF + 5 * DF_PER_LINE + 15) #define GFX_BEAMER_GREEN_START (GFX_START_MIRRORDF + 6 * DF_PER_LINE + 0) #define GFX_BEAMER_GREEN_END (GFX_START_MIRRORDF + 6 * DF_PER_LINE + 15) #define GFX_BEAMER_BLUE_START (GFX_START_MIRRORDF + 7 * DF_PER_LINE + 0) #define GFX_BEAMER_BLUE_END (GFX_START_MIRRORDF + 7 * DF_PER_LINE + 15) #define GFX_DF_WALL_SEVERAL (GFX_START_MIRRORDF + 8 * DF_PER_LINE + 0) #define GFX_REFRACTOR (GFX_START_MIRRORDF + 8 * DF_PER_LINE + 1) #define GFX_CELL (GFX_START_MIRRORDF + 8 * DF_PER_LINE + 2) #define GFX_MINE (GFX_START_MIRRORDF + 8 * DF_PER_LINE + 4) #define GFX_LASER_RIGHT (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 0) #define GFX_LASER_UP (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 1) #define GFX_LASER_LEFT (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 2) #define GFX_LASER_DOWN (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 3) #define GFX_RECEIVER_RIGHT (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 4) #define GFX_RECEIVER_UP (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 5) #define GFX_RECEIVER_LEFT (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 6) #define GFX_RECEIVER_DOWN (GFX_START_MIRRORDF + 9 * DF_PER_LINE + 7) #define GFX_FIBRE_OPTIC_00 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 0) #define GFX_FIBRE_OPTIC_01 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 1) #define GFX_FIBRE_OPTIC_02 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 2) #define GFX_FIBRE_OPTIC_03 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 3) #define GFX_FIBRE_OPTIC_04 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 4) #define GFX_FIBRE_OPTIC_05 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 5) #define GFX_FIBRE_OPTIC_06 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 6) #define GFX_FIBRE_OPTIC_07 (GFX_START_MIRRORDF + 10 * DF_PER_LINE + 7) #define GFX_FIBRE_OPTIC_ED_00 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 0) #define GFX_FIBRE_OPTIC_ED_01 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 1) #define GFX_FIBRE_OPTIC_ED_02 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 2) #define GFX_FIBRE_OPTIC_ED_03 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 3) #define GFX_FIBRE_OPTIC_ED_04 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 4) #define GFX_FIBRE_OPTIC_ED_05 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 5) #define GFX_FIBRE_OPTIC_ED_06 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 6) #define GFX_FIBRE_OPTIC_ED_07 (GFX_START_MIRRORDF + 11 * DF_PER_LINE + 7) /* the names of the sounds */ #define SND_AMOEBE 0 #define SND_ANTIGRAV 1 #define SND_AUTSCH 2 #define SND_BONG 3 #define SND_FUEL 4 #define SND_HALLOFFAME 5 #define SND_HOLZ 6 #define SND_HUI 7 #define SND_KABUMM 8 #define SND_KINK 9 #define SND_KLING 10 #define SND_LASER 11 #define SND_OEFFNEN 12 #define SND_QUIEK 13 #define SND_RHYTHMLOOP 14 #define SND_ROAAAR 15 #define SND_SIRR 16 #define SND_SLURP 17 #define SND_WARNTON 18 #define SND_WHOOSH 19 #define NUM_SOUNDS 20 /* values for graphics/sounds action types */ #define MM_ACTION_DEFAULT 0 #define MM_ACTION_WAITING 1 #define MM_ACTION_FALLING 2 #define MM_ACTION_MOVING 3 #define MM_ACTION_DIGGING 4 #define MM_ACTION_SNAPPING 5 #define MM_ACTION_COLLECTING 6 #define MM_ACTION_DROPPING 7 #define MM_ACTION_PUSHING 8 #define MM_ACTION_WALKING 9 #define MM_ACTION_PASSING 10 #define MM_ACTION_IMPACT 11 #define MM_ACTION_BREAKING 12 #define MM_ACTION_ACTIVATING 13 #define MM_ACTION_DEACTIVATING 14 #define MM_ACTION_OPENING 15 #define MM_ACTION_CLOSING 16 #define MM_ACTION_ATTACKING 17 #define MM_ACTION_GROWING 18 #define MM_ACTION_SHRINKING 19 #define MM_ACTION_ACTIVE 20 #define MM_ACTION_FILLING 21 #define MM_ACTION_EMPTYING 22 #define MM_ACTION_CHANGING 23 #define MM_ACTION_EXPLODING 24 #define MM_ACTION_BORING 25 #define MM_ACTION_BORING_1 26 #define MM_ACTION_BORING_2 27 #define MM_ACTION_BORING_3 28 #define MM_ACTION_BORING_4 29 #define MM_ACTION_BORING_5 30 #define MM_ACTION_BORING_6 31 #define MM_ACTION_BORING_7 32 #define MM_ACTION_BORING_8 33 #define MM_ACTION_BORING_9 34 #define MM_ACTION_BORING_10 35 #define MM_ACTION_SLEEPING 36 #define MM_ACTION_SLEEPING_1 37 #define MM_ACTION_SLEEPING_2 38 #define MM_ACTION_SLEEPING_3 39 #define MM_ACTION_AWAKENING 40 #define MM_ACTION_DYING 41 #define MM_ACTION_TURNING 42 #define MM_ACTION_TURNING_FROM_LEFT 43 #define MM_ACTION_TURNING_FROM_RIGHT 44 #define MM_ACTION_TURNING_FROM_UP 45 #define MM_ACTION_TURNING_FROM_DOWN 46 #define MM_ACTION_SMASHED_BY_ROCK 47 #define MM_ACTION_SMASHED_BY_SPRING 48 #define MM_ACTION_EATING 49 #define MM_ACTION_TWINKLING 50 #define MM_ACTION_SPLASHING 51 #define MM_ACTION_HITTING 52 /* laser angles (directions) */ #define ANG_RAY_RIGHT 0 #define ANG_RAY_UP 4 #define ANG_RAY_LEFT 8 #define ANG_RAY_DOWN 12 /* laser angles (degree) */ #define ANG_RAY_0 0 #define ANG_RAY_90 4 #define ANG_RAY_180 8 #define ANG_RAY_270 12 #define IS_22_5_ANGLE(angle) ((angle) % 2) #define IS_90_ANGLE(angle) (!((angle) % 4)) #define IS_HORIZ_ANGLE(angle) (!((angle) % 8)) #define IS_VERT_ANGLE(angle) ((angle) % 8) /* mirror angles */ #define ANG_MIRROR_0 0 #define ANG_MIRROR_45 4 #define ANG_MIRROR_90 8 #define ANG_MIRROR_135 12 /* positions for checking where laser already hits element */ #define HIT_POS_CENTER 1 #define HIT_POS_EDGE 2 #define HIT_POS_BETWEEN 4 /* masks for scanning elements */ #define HIT_MASK_NO_HIT 0 #define HIT_MASK_TOPLEFT 1 #define HIT_MASK_TOPRIGHT 2 #define HIT_MASK_BOTTOMLEFT 4 #define HIT_MASK_BOTTOMRIGHT 8 #define HIT_MASK_LEFT (HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMLEFT) #define HIT_MASK_RIGHT (HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMRIGHT) #define HIT_MASK_TOP (HIT_MASK_TOPLEFT | HIT_MASK_TOPRIGHT) #define HIT_MASK_BOTTOM (HIT_MASK_BOTTOMLEFT | HIT_MASK_BOTTOMRIGHT) #define HIT_MASK_ALL (HIT_MASK_LEFT | HIT_MASK_RIGHT) /* step values for rotating elements */ #define ROTATE_NO_ROTATING 0 #define ROTATE_LEFT (+1) #define ROTATE_RIGHT (-1) #define BUTTON_ROTATION(button) ((button) == MB_LEFTBUTTON ? ROTATE_LEFT : \ (button) == MB_RIGHTBUTTON ? ROTATE_RIGHT : \ ROTATE_NO_ROTATING) /* game over values */ #define GAME_OVER_NO_ENERGY 1 #define GAME_OVER_OVERLOADED 2 #define GAME_OVER_BOMB 3 /* values for game_status */ #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 /* return values for GameActions */ #define ACT_GO_ON 0 #define ACT_GAME_OVER 1 #define ACT_NEW_GAME 2 /* values for color_status */ #define STATIC_COLORS 0 #define DYNAMIC_COLORS 1 #define PROGRAM_VERSION_MAJOR 2 #define PROGRAM_VERSION_MINOR 0 #define PROGRAM_VERSION_PATCH 2 #define PROGRAM_VERSION_STRING "2.0.2" #define PROGRAM_TITLE_STRING "Mirror Magic II" #define PROGRAM_AUTHOR_STRING "Holger Schemel" #define PROGRAM_RIGHTS_STRING "Copyright ^1994-2001" #define PROGRAM_DOS_PORT_STRING "DOS port based on code by Guido Schulz" #define PROGRAM_IDENT_STRING PROGRAM_VERSION_STRING " " TARGET_STRING #define WINDOW_TITLE_STRING PROGRAM_TITLE_STRING " " PROGRAM_IDENT_STRING #define WINDOW_SUBTITLE_STRING PROGRAM_RIGHTS_STRING " " PROGRAM_AUTHOR_STRING #define ICON_TITLE_STRING PROGRAM_TITLE_STRING #define UNIX_USERDATA_DIRECTORY ".mirrormagic" #define X11_ICON_FILENAME "mirrormagic_icon.xbm" #define X11_ICONMASK_FILENAME "mirrormagic_iconmask.xbm" #define MSDOS_POINTER_FILENAME "mouse.pcx" /* functions for version handling */ #define MM_VERSION_IDENT(x,y,z) VERSION_IDENT(x,y,z,0) #define MM_VERSION_MAJOR(x) VERSION_MAJOR(x) #define MM_VERSION_MINOR(x) VERSION_MINOR(x) #define MM_VERSION_PATCH(x) VERSION_PATCH(x) /* file version numbers for resource files (levels, score, setup, etc.) ** currently supported/known file version numbers: ** 1.4 (still in use) ** 2.0 (actual) */ #define MM_FILE_VERSION_1_4 MM_VERSION_IDENT(1,4,0) #define MM_FILE_VERSION_2_0 MM_VERSION_IDENT(2,0,0) /* file version does not change for every program version, but is changed when new features are introduced that are incompatible with older file versions, so that they can be treated accordingly */ #define MM_FILE_VERSION_ACTUAL MM_FILE_VERSION_2_0 #define MM_GAME_VERSION_ACTUAL MM_VERSION_IDENT(PROGRAM_VERSION_MAJOR, \ PROGRAM_VERSION_MINOR, \ PROGRAM_VERSION_PATCH) /* sound control */ #define ST(x) (((x) - 8) * 16) #endif /* MM_MAIN_H */ mirrormagic-3.0.0/src/game_mm/mm_tools.c0000644000175000017500000004437313263212010017522 0ustar aeglosaeglos/*********************************************************** * Mirror Magic -- McDuffin's Revenge * *----------------------------------------------------------* * (c) 1994-2001 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * tools.c * ***********************************************************/ #include "main_mm.h" #include "mm_main.h" #include "mm_tools.h" void SetDrawtoField_MM(int mode) { int full_xsize = lev_fieldx * TILESIZE_VAR; int full_ysize = lev_fieldy * TILESIZE_VAR; // distance (delta) from screen border (SX/SY) to centered level playfield dSX = (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0); dSY = (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0); // for convenience, absolute screen position to centered level playfield cSX = SX + dSX; cSY = SY + dSY; cSX2 = SX + dSX + 2; // including playfield border cSY2 = SY + dSY + 2; // including playfield border if (mode == DRAW_TO_BACKBUFFER) { cFX = FX + dSX; cFY = FY + dSY; } SetTileCursorSXSY(cSX, cSY); } void ClearWindow() { ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE); SetDrawtoField(DRAW_TO_BACKBUFFER); SetDrawtoField_MM(DRAW_TO_BACKBUFFER); redraw_mask |= REDRAW_FIELD; } void DrawGraphicAnimation_MM(int x, int y, int graphic, int frame) { Bitmap *bitmap; int src_x, src_y; getGraphicSource(graphic, frame, &bitmap, &src_x, &src_y); BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY, cFX + x * TILEX, cFY + y * TILEY); } void DrawGraphic_MM(int x, int y, int graphic) { #if DEBUG if (!IN_SCR_FIELD(x,y)) { printf("DrawGraphic_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic); printf("DrawGraphic_MM(): This should never happen!\n"); return; } #endif DrawGraphicExt_MM(drawto_field, cFX + x * TILEX, cFY + y * TILEY, graphic); MarkTileDirty(x, y); } void DrawGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic) { Bitmap *bitmap; int src_x, src_y; getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y); BlitBitmap(bitmap, d, src_x, src_y, TILEX, TILEY, x, y); } void DrawGraphicThruMask_MM(int x, int y, int graphic) { #if DEBUG if (!IN_SCR_FIELD(x,y)) { printf("DrawGraphicThruMask_MM(): x = %d,y = %d, graphic = %d\n",x,y,graphic); printf("DrawGraphicThruMask_MM(): This should never happen!\n"); return; } #endif DrawGraphicThruMaskExt_MM(drawto_field, cFX + x * TILEX, cFY + y * TILEY, graphic); MarkTileDirty(x,y); } void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y, int graphic) { int src_x, src_y; Bitmap *src_bitmap; if (graphic == IMG_EMPTY) return; getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y); } void DrawMiniGraphic_MM(int x, int y, int graphic) { DrawMiniGraphicExt_MM(drawto, cSX + x * MINI_TILEX, cSY + y * MINI_TILEY, graphic); MarkTileDirty(x / 2, y / 2); } void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y) { getSizedGraphicSource(graphic, 0, TILESIZE / 4, bitmap, x, y); } void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic) { Bitmap *bitmap; int src_x, src_y; getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y); BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y); } void DrawGraphicShifted_MM(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; Bitmap *src_bitmap; if (graphic < 0) { DrawGraphic_MM(x, y, graphic); return; } if (dx || dy) /* Verschiebung der Grafik? */ { if (x < BX1) /* Element kommt von links ins Bild */ { x = BX1; width = dx; cx = TILEX - dx; dx = 0; } else if (x > BX2) /* Element kommt von rechts ins Bild */ { x = BX2; width = -dx; dx = TILEX + dx; } else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */ { width += dx; cx = -dx; dx = 0; } else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */ width -= dx; else if (dx) /* allg. Bewegung in x-Richtung */ MarkTileDirty(x + SIGN(dx), y); if (y < BY1) /* Element kommt von oben ins Bild */ { if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */ return; y = BY1; height = dy; cy = TILEY - dy; dy = 0; } else if (y > BY2) /* Element kommt von unten ins Bild */ { y = BY2; height = -dy; dy = TILEY + dy; } else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */ { height += dy; cy = -dy; dy = 0; } else if (dy > 0 && cut_mode == CUT_ABOVE) { if (y == BY2) /* Element unterhalb des Bildes */ return; height = dy; cy = TILEY - dy; dy = TILEY; MarkTileDirty(x, y + 1); } /* Element verläßt unten das Bild */ else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW)) { height -= dy; } else if (dy) /* allg. Bewegung in y-Richtung */ { MarkTileDirty(x, y + SIGN(dy)); } } getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); src_x += cx; src_y += cy; dest_x = cFX + x * TILEX + dx; dest_y = cFY + y * TILEY + dy; #if DEBUG if (!IN_SCR_FIELD(x,y)) { printf("DrawGraphicShifted_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic); printf("DrawGraphicShifted_MM(): This should never happen!\n"); return; } #endif if (mask_mode == USE_MASKING) BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, TILEX, TILEY, dest_x, dest_y); else BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height, dest_x, dest_y); MarkTileDirty(x,y); } void DrawGraphicShiftedThruMask_MM(int x,int y, int dx,int dy, int graphic, int cut_mode) { DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, USE_MASKING); } void DrawScreenElementExt_MM(int x, int y, int dx, int dy, int element, int cut_mode, int mask_mode) { int ux = LEVELX(x), uy = LEVELY(y); int graphic = el2gfx(element); int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8); int phase2 = phase8 / 4; int dir = MovDir[ux][uy]; if (element == EL_PACMAN) { graphic = (phase2 ? IMG_MM_PACMAN_RIGHT : IMG_MM_PACMAN_EATING_RIGHT); if (dir == MV_UP) graphic += 1; else if (dir == MV_LEFT) graphic += 2; else if (dir == MV_DOWN) graphic += 3; } if (dx || dy) DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, mask_mode); else if (mask_mode == USE_MASKING) DrawGraphicThruMask_MM(x, y, graphic); else DrawGraphic_MM(x, y, graphic); } void DrawLevelElementExt_MM(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_MM(SCREENX(x), SCREENY(y), dx, dy, element, cut_mode, mask_mode); } void DrawScreenElementShifted_MM(int x, int y, int dx, int dy, int element, int cut_mode) { DrawScreenElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING); } void DrawLevelElementShifted_MM(int x, int y, int dx, int dy, int element, int cut_mode) { DrawLevelElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING); } void DrawScreenElementThruMask_MM(int x, int y, int element) { DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING); } void DrawLevelElementThruMask_MM(int x, int y, int element) { DrawLevelElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING); } void DrawLevelFieldThruMask_MM(int x, int y) { DrawLevelElementExt_MM(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING); } void DrawScreenElement_MM(int x, int y, int element) { DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, NO_MASKING); } void DrawLevelElement_MM(int x, int y, int element) { if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) DrawScreenElement_MM(SCREENX(x), SCREENY(y), element); } void DrawScreenField_MM(int x, int y) { int element = Feld[x][y]; if (!IN_LEV_FIELD(x, y)) return; if (IS_MOVING(x, y)) { int horiz_move = (MovDir[x][y] == MV_LEFT || MovDir[x][y] == MV_RIGHT); DrawScreenElement_MM(x, y, EL_EMPTY); if (horiz_move) DrawScreenElementShifted_MM(x, y, MovPos[x][y], 0, element, NO_CUTTING); else DrawScreenElementShifted_MM(x, y, 0, MovPos[x][y], element, NO_CUTTING); } else if (IS_BLOCKED(x, y)) { int oldx, oldy; int sx, sy; int horiz_move; Blocked2Moving(x, y, &oldx, &oldy); sx = SCREENX(oldx); sy = SCREENY(oldy); horiz_move = (MovDir[oldx][oldy] == MV_LEFT || MovDir[oldx][oldy] == MV_RIGHT); DrawScreenElement_MM(x, y, EL_EMPTY); element = Feld[oldx][oldy]; if (horiz_move) DrawScreenElementShifted_MM(sx, sy, MovPos[oldx][oldy], 0, element, NO_CUTTING); else DrawScreenElementShifted_MM(sx, sy, 0, MovPos[oldx][oldy], element, NO_CUTTING); } else if (IS_DRAWABLE(element)) { DrawScreenElement_MM(x, y, element); } else { DrawScreenElement_MM(x, y, EL_EMPTY); } } void DrawLevelField_MM(int x, int y) { DrawScreenField_MM(x, y); } void DrawMiniElement_MM(int x, int y, int element) { int graphic; if (!element) { DrawMiniGraphic_MM(x, y, IMG_EMPTY); return; } graphic = el2gfx(element); DrawMiniGraphic_MM(x, y, graphic); } void DrawMiniElementOrWall_MM(int sx, int sy, int scroll_x, int scroll_y) { int x = sx + scroll_x, y = sy + scroll_y; if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy) DrawMiniElement_MM(sx, sy, EL_EMPTY); else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy) DrawMiniElement_MM(sx, sy, Feld[x][y]); } void DrawField_MM(int x, int y) { int element = Feld[x][y]; DrawElement_MM(x, y, element); } void DrawLevel_MM() { int x,y; ClearWindow(); for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) DrawField_MM(x, y); redraw_mask |= REDRAW_FIELD; } void DrawWallsExt_MM(int x, int y, int element, int draw_mask) { Bitmap *bitmap; int graphic = el2gfx(WALL_BASE(element)); int gx, gy; int i; getMiniGraphicSource(graphic, &bitmap, &gx, &gy); DrawGraphic_MM(x, y, IMG_EMPTY); /* if (IS_WALL_WOOD(element) || IS_WALL_AMOEBA(element) || IS_DF_WALL_WOOD(element)) gx += MINI_TILEX; if (IS_WALL_ICE(element) || IS_WALL_AMOEBA(element)) gy += MINI_TILEY; */ for (i = 0; i < 4; i++) { int dest_x = cSX + x * TILEX + MINI_TILEX * (i % 2); int dest_y = cSY + y * TILEY + MINI_TILEY * (i / 2); if (!((1 << i) & draw_mask)) continue; if (element & (1 << i)) BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY, dest_x, dest_y); else ClearRectangle(drawto, dest_x, dest_y, MINI_TILEX, MINI_TILEY); } MarkTileDirty(x, y); } void DrawWalls_MM(int x, int y, int element) { DrawWallsExt_MM(x, y, element, HIT_MASK_ALL); } void DrawWallsAnimation_MM(int x, int y, int element, int phase, int bit_mask) { int i; if (phase == 0) { DrawWalls_MM(x, y, element); return; } for (i = 0; i < 4; i++) { if (element & (1 << i)) { int graphic; int frame; Bitmap *bitmap; int src_x, src_y; int dst_x = cSX + x * TILEX + (i % 2) * MINI_TILEX; int dst_y = cSY + y * TILEY + (i / 2) * MINI_TILEY; if (bit_mask & (1 << i)) { graphic = (IS_WALL_AMOEBA(element) ? IMG_MM_AMOEBA_WALL_GROWING : IMG_MM_ICE_WALL_SHRINKING); frame = phase; } else { graphic = (IS_WALL_AMOEBA(element) ? IMG_MM_AMOEBA_WALL : IMG_MM_ICE_WALL); frame = 0; } getSizedGraphicSource(graphic, frame, MINI_TILESIZE, &bitmap, &src_x, &src_y); BlitBitmap(bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dst_x, dst_y); } } MarkTileDirty(x, y); } void DrawElement_MM(int x, int y, int element) { if (element == EL_EMPTY) DrawGraphic_MM(x, y, IMG_EMPTY); else if (IS_WALL(element)) DrawWalls_MM(x, y, element); #if 0 else if (IS_WALL_CHANGING(element) && IS_WALL_CHANGING(Feld[x][y])) { int wall_element = Feld[x][y] - EL_WALL_CHANGING + Store[x][y]; DrawWalls_MM(x, y, wall_element); } #endif else if (element == EL_PACMAN) DrawLevelField_MM(x, y); else if (element == EL_FUSE_ON && laser.fuse_off && laser.fuse_x == x && laser.fuse_y == y) DrawGraphic_MM(x, y, IMG_MM_FUSE); else DrawGraphic_MM(x, y, el2gfx(element)); } void DrawMicroWalls_MM(int x, int y, int element) { Bitmap *bitmap; int graphic = el2gfx(WALL_BASE(element)); int gx, gy; int i; getMicroGraphicSource(graphic, &bitmap, &gx, &gy); for (i = 0; i < 4; i++) { int xpos = MICROLEV_XPOS + x * MICRO_TILEX + MICRO_WALLX * (i % 2); int ypos = MICROLEV_YPOS + y * MICRO_TILEY + MICRO_WALLY * (i / 2); if (element & (1 << i)) BlitBitmap(bitmap, drawto, gx, gy, MICRO_WALLX, MICRO_WALLY, xpos, ypos); else ClearRectangle(drawto, xpos, ypos, MICRO_WALLX, MICRO_WALLY); } } void DrawMicroElement_MM(int x, int y, int element) { Bitmap *bitmap; int graphic = el2gfx(element); int gx, gy; if (element == EL_EMPTY) return; if (IS_WALL(element)) { DrawMicroWalls_MM(x, y, element); return; } getMicroGraphicSource(graphic, &bitmap, &gx, &gy); BlitBitmap(bitmap, drawto, gx, gy, MICRO_TILEX, MICRO_TILEY, MICROLEV_XPOS + x * MICRO_TILEX, MICROLEV_YPOS + y * MICRO_TILEY); } void DrawMicroLevelExt_MM(int xpos, int ypos) { int x, y; ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE); for (x = 0; x < STD_LEV_FIELDX; x++) for (y = 0; y < STD_LEV_FIELDY; y++) DrawMicroElement_MM(x, y, Ur[x][y]); redraw_mask |= REDRAW_FIELD; } void DrawMiniLevel_MM(int size_x, int size_y, int scroll_x, int scroll_y) { int x, y; for(x = 0; x < size_x; x++) for(y = 0; y < size_y; y++) DrawMiniElementOrWall_MM(x, y, scroll_x, scroll_y); redraw_mask |= REDRAW_FIELD; } int REQ_in_range(int x, int y) { if (y > DY + 249 && y < DY + 278) { if (x > DX + 1 && x < DX + 48) return 1; else if (x > DX + 51 && x < DX + 98) return 2; } return 0; } Pixel ReadPixel(DrawBuffer *bitmap, int x, int y) { return GetPixel(bitmap, x, y); } void SetRGB(unsigned int pixel, unsigned short red, unsigned short green, unsigned short blue) { } int get_base_element(int element) { if (IS_MIRROR(element)) return EL_MIRROR_START; else if (IS_MIRROR_FIXED(element)) return EL_MIRROR_FIXED_START; else if (IS_POLAR(element)) return EL_POLAR_START; else if (IS_POLAR_CROSS(element)) return EL_POLAR_CROSS_START; else if (IS_BEAMER(element)) return EL_BEAMER_RED_START + BEAMER_NR(element) * 16; else if (IS_FIBRE_OPTIC(element)) return EL_FIBRE_OPTIC_START + FIBRE_OPTIC_NR(element) * 2; else if (IS_MCDUFFIN(element)) return EL_MCDUFFIN_START; else if (IS_LASER(element)) return EL_LASER_START; else if (IS_RECEIVER(element)) return EL_RECEIVER_START; else if (IS_DF_MIRROR(element)) return EL_DF_MIRROR_START; else if (IS_DF_MIRROR_AUTO(element)) return EL_DF_MIRROR_AUTO_START; else if (IS_PACMAN(element)) return EL_PACMAN_START; else if (IS_GRID_STEEL(element)) return EL_GRID_STEEL_START; else if (IS_GRID_WOOD(element)) return EL_GRID_WOOD_START; else if (IS_GRID_STEEL_FIXED(element)) return EL_GRID_STEEL_FIXED_START; else if (IS_GRID_WOOD_FIXED(element)) return EL_GRID_WOOD_FIXED_START; else if (IS_GRID_STEEL_AUTO(element)) return EL_GRID_STEEL_AUTO_START; else if (IS_GRID_WOOD_AUTO(element)) return EL_GRID_WOOD_AUTO_START; else if (IS_WALL_STEEL(element)) return EL_WALL_STEEL_START; else if (IS_WALL_WOOD(element)) return EL_WALL_WOOD_START; else if (IS_WALL_ICE(element)) return EL_WALL_ICE_START; else if (IS_WALL_AMOEBA(element)) return EL_WALL_AMOEBA_START; else if (IS_DF_WALL_STEEL(element)) return EL_DF_WALL_STEEL_START; else if (IS_DF_WALL_WOOD(element)) return EL_DF_WALL_WOOD_START; else if (IS_CHAR(element)) return EL_CHAR_START; else return element; } int get_element_phase(int element) { return element - get_base_element(element); } int get_num_elements(int element) { if (IS_MIRROR(element) || IS_POLAR(element) || IS_BEAMER(element) || IS_DF_MIRROR(element) || IS_DF_MIRROR_AUTO(element)) return 16; else if (IS_GRID_STEEL_FIXED(element) || IS_GRID_WOOD_FIXED(element) || IS_GRID_STEEL_AUTO(element) || IS_GRID_WOOD_AUTO(element)) return 8; else if (IS_MIRROR_FIXED(element) || IS_POLAR_CROSS(element) || IS_MCDUFFIN(element) || IS_LASER(element) || IS_RECEIVER(element) || IS_PACMAN(element) || IS_GRID_STEEL(element) || IS_GRID_WOOD(element)) return 4; else return 1; } int get_rotated_element(int element, int step) { int base_element = get_base_element(element); int num_elements = get_num_elements(element); int element_phase = element - base_element; return base_element + (element_phase + step + num_elements) % num_elements; } static int map_element(int element) { switch (element) { case EL_WALL_STEEL: return EL_STEEL_WALL; case EL_WALL_WOOD: return EL_WOODEN_WALL; case EL_WALL_ICE: return EL_ICE_WALL; case EL_WALL_AMOEBA: return EL_AMOEBA_WALL; case EL_DF_WALL_STEEL: return EL_DF_STEEL_WALL; case EL_DF_WALL_WOOD: return EL_DF_WOODEN_WALL; default: return element; } } int el2gfx(int element) { element = map_element(element); switch (element) { case EL_LIGHTBALL: return IMG_MM_LIGHTBALL_RED + RND(3); default: return el2img_mm(element); } } void RedrawPlayfield_MM() { DrawLevel_MM(); DrawLaser_MM(); } void BlitScreenToBitmap_MM(Bitmap *target_bitmap) { BlitBitmap(drawto_field, target_bitmap, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY); } mirrormagic-3.0.0/src/game_mm/mm_files.c0000644000175000017500000003230313263212010017452 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // mm_files.c // ============================================================================ #include #include #include #include #include "main_mm.h" #include "mm_main.h" #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */ #define CHUNK_SIZE_NONE -1 /* do not write chunk size */ #define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */ #define LEVEL_HEADER_SIZE 80 /* size of level file header */ #define LEVEL_HEADER_UNUSED 19 /* unused level header bytes */ /* file identifier strings */ #define LEVEL_COOKIE_TMPL "MIRRORMAGIC_LEVEL_FILE_VERSION_x.x" #define SCORE_COOKIE "MIRRORMAGIC_SCORE_FILE_VERSION_1.4" int default_score[LEVEL_SCORE_ELEMENTS] = { [SC_COLLECTIBLE] = 10, [SC_PACMAN] = 50, [SC_KEY] = 10, [SC_TIME_BONUS] = 1, [SC_LIGHTBALL] = 10, }; /* ========================================================================= */ /* level file functions */ /* ========================================================================= */ static void ReadChunk_MM_VERS(File *file, int *file_version, int *game_version) { int file_version_major, file_version_minor, file_version_patch; int game_version_major, game_version_minor, game_version_patch; file_version_major = getFile8Bit(file); file_version_minor = getFile8Bit(file); file_version_patch = getFile8Bit(file); getFile8Bit(file); /* not used */ game_version_major = getFile8Bit(file); game_version_minor = getFile8Bit(file); game_version_patch = getFile8Bit(file); getFile8Bit(file); /* not used */ *file_version = MM_VERSION_IDENT(file_version_major, file_version_minor, file_version_patch); *game_version = MM_VERSION_IDENT(game_version_major, game_version_minor, game_version_patch); } static void WriteChunk_MM_VERS(FILE *file, int file_version, int game_version) { int file_version_major = MM_VERSION_MAJOR(file_version); int file_version_minor = MM_VERSION_MINOR(file_version); int file_version_patch = MM_VERSION_PATCH(file_version); int game_version_major = MM_VERSION_MAJOR(game_version); int game_version_minor = MM_VERSION_MINOR(game_version); int game_version_patch = MM_VERSION_PATCH(game_version); fputc(file_version_major, file); fputc(file_version_minor, file); fputc(file_version_patch, file); fputc(0, file); /* not used */ fputc(game_version_major, file); fputc(game_version_minor, file); fputc(game_version_patch, file); fputc(0, file); /* not used */ } void setLevelInfoToDefaults_MM() { int i, x, y; native_mm_level.file_version = MM_FILE_VERSION_ACTUAL; native_mm_level.game_version = MM_GAME_VERSION_ACTUAL; native_mm_level.encoding_16bit_field = FALSE; /* default: only 8-bit elements */ lev_fieldx = native_mm_level.fieldx = STD_LEV_FIELDX; lev_fieldy = native_mm_level.fieldy = STD_LEV_FIELDY; for (x = 0; x < MAX_LEV_FIELDX; x++) for (y = 0; y < MAX_LEV_FIELDY; y++) native_mm_level.field[x][y] = Feld[x][y] = Ur[x][y] = EL_EMPTY; native_mm_level.time = 100; native_mm_level.kettles_needed = 0; native_mm_level.auto_count_kettles = TRUE; native_mm_level.amoeba_speed = 0; native_mm_level.time_fuse = 25; native_mm_level.time_bomb = 75; native_mm_level.time_ball = 75; native_mm_level.time_block = 75; native_mm_level.laser_red = FALSE; native_mm_level.laser_green = FALSE; native_mm_level.laser_blue = TRUE; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) native_mm_level.name[i] = '\0'; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) native_mm_level.author[i] = '\0'; strcpy(native_mm_level.name, NAMELESS_LEVEL_NAME); strcpy(native_mm_level.author, ANONYMOUS_NAME); for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) native_mm_level.score[i] = 10; native_mm_level.field[0][0] = Feld[0][0] = Ur[0][0] = EL_MCDUFFIN_RIGHT; native_mm_level.field[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED; } static int checkLevelElement(int element) { if (element >= EL_FIRST_RUNTIME_EL) { Error(ERR_WARN, "invalid level element %d", element); element = EL_CHAR_FRAGE; } return element; } static int LoadLevel_MM_VERS(File *file, int chunk_size, struct LevelInfo_MM *level) { ReadChunk_MM_VERS(file, &level->file_version, &level->game_version); return chunk_size; } static int LoadLevel_MM_HEAD(File *file, int chunk_size, struct LevelInfo_MM *level) { int i; int laser_color; lev_fieldx = level->fieldx = getFile8Bit(file); lev_fieldy = level->fieldy = getFile8Bit(file); level->time = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN); level->kettles_needed = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN); // one time unit was equivalent to four seconds in level files up to 2.0.x if (level->file_version <= MM_FILE_VERSION_2_0) level->time *= 4; for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) level->name[i] = getFile8Bit(file); level->name[MAX_LEVEL_NAME_LEN] = 0; for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) level->score[i] = getFile8Bit(file); // scores were 0 and hardcoded in game engine in level files up to 2.0.x if (level->file_version <= MM_FILE_VERSION_2_0) for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) if (level->score[i] == 0) level->score[i] = default_score[i]; level->auto_count_kettles = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->amoeba_speed = getFile8Bit(file); level->time_fuse = getFile8Bit(file); // fuse time was 0 and hardcoded in game engine in level files up to 2.0.x if (level->file_version <= MM_FILE_VERSION_2_0) level->time_fuse = 25; laser_color = getFile8Bit(file); level->laser_red = (laser_color >> 2) & 0x01; level->laser_green = (laser_color >> 1) & 0x01; level->laser_blue = (laser_color >> 0) & 0x01; level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED); return chunk_size; } static int LoadLevel_MM_AUTH(File *file, int chunk_size, struct LevelInfo_MM *level) { int i; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) level->author[i] = getFile8Bit(file); level->author[MAX_LEVEL_NAME_LEN] = 0; return chunk_size; } static int LoadLevel_MM_BODY(File *file, int chunk_size, struct LevelInfo_MM *level) { int x, y; int chunk_size_expected = level->fieldx * level->fieldy; /* Note: "chunk_size" was wrong before version 2.0 when elements are stored with 16-bit encoding (and should be twice as big then). Even worse, playfield data was stored 16-bit when only yamyam content contained 16-bit elements and vice versa. */ if (level->encoding_16bit_field && level->file_version >= MM_FILE_VERSION_2_0) chunk_size_expected *= 2; if (chunk_size_expected != chunk_size) { ReadUnusedBytesFromFile(file, chunk_size); return chunk_size_expected; } for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) native_mm_level.field[x][y] = Feld[x][y] = Ur[x][y] = checkLevelElement(level->encoding_16bit_field ? getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) : getFile8Bit(file)); return chunk_size; } boolean LoadNativeLevel_MM(char *filename, boolean level_info_only) { char cookie[MAX_LINE_LEN]; char chunk_name[CHUNK_ID_LEN + 1]; int chunk_size; File *file; static struct { char *name; int size; int (*loader)(File *, int, struct LevelInfo_MM *); } chunk_info[] = { { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_MM_VERS }, { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_MM_HEAD }, { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_MM_AUTH }, { "BODY", -1, LoadLevel_MM_BODY }, { NULL, 0, NULL } }; /* always start with reliable default values */ setLevelInfoToDefaults_MM(); if (!(file = openFile(filename, MODE_READ))) { if (!level_info_only) Error(ERR_WARN, "cannot read level '%s' - creating new level", filename); return FALSE; } getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN); if (strcmp(chunk_name, "MMII") == 0) { getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); /* not used */ getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN); if (strcmp(chunk_name, "CAVE") != 0) { Error(ERR_WARN, "unknown format of level file '%s'", filename); closeFile(file); return FALSE; } } else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4); if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL)) { Error(ERR_WARN, "unknown format of level file '%s'", filename); closeFile(file); return FALSE; } if ((native_mm_level.file_version = getFileVersionFromCookieString(cookie)) == -1) { Error(ERR_WARN, "unsupported version of level file '%s'", filename); closeFile(file); return FALSE; } } while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN)) { int i = 0; while (chunk_info[i].name != NULL && strcmp(chunk_name, chunk_info[i].name) != 0) i++; if (chunk_info[i].name == NULL) { Error(ERR_WARN, "unknown chunk '%s' in level file '%s'", chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else if (chunk_info[i].size != -1 && chunk_info[i].size != chunk_size) { Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); ReadUnusedBytesFromFile(file, chunk_size); } else { /* call function to load this level chunk */ int chunk_size_expected = (chunk_info[i].loader)(file, chunk_size, &native_mm_level); /* the size of some chunks cannot be checked before reading other chunks first (like "HEAD" and "BODY") that contain some header information, so check them here */ if (chunk_size_expected != chunk_size) Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); } } closeFile(file); return TRUE; } static void SaveLevel_MM_HEAD(FILE *file, struct LevelInfo_MM *level) { int i; int laser_color; fputc(level->fieldx, file); fputc(level->fieldy, file); putFile16BitInteger(file, level->time, BYTE_ORDER_BIG_ENDIAN); putFile16BitInteger(file, level->kettles_needed, BYTE_ORDER_BIG_ENDIAN); for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) fputc(level->name[i], file); for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) fputc(level->score[i], file); fputc((level->auto_count_kettles ? 1 : 0), file); fputc(level->amoeba_speed, file); fputc(level->time_fuse, file); laser_color = ((level->laser_red << 2) | (level->laser_green << 1) | (level->laser_blue << 0)); fputc(laser_color, file); fputc((level->encoding_16bit_field ? 1 : 0), file); WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED); } static void SaveLevel_MM_AUTH(FILE *file, struct LevelInfo_MM *level) { int i; for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) fputc(level->author[i], file); } static void SaveLevel_MM_BODY(FILE *file, struct LevelInfo_MM *level) { int x, y; for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++) if (level->encoding_16bit_field) putFile16BitInteger(file, Ur[x][y], BYTE_ORDER_BIG_ENDIAN); else fputc(Ur[x][y], file); } void SaveNativeLevel_MM(char *filename) { int x, y; int body_chunk_size; FILE *file; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot save level file '%s'", filename); return; } /* check level field for 16-bit elements */ native_mm_level.encoding_16bit_field = FALSE; for (y = 0; y < native_mm_level.fieldy; y++) for (x = 0; x < native_mm_level.fieldx; x++) if (Ur[x][y] > 255) native_mm_level.encoding_16bit_field = TRUE; body_chunk_size = native_mm_level.fieldx * native_mm_level.fieldy * (native_mm_level.encoding_16bit_field ? 2 : 1); putFileChunk(file, "MMII", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN); putFileChunk(file, "CAVE", CHUNK_SIZE_NONE, BYTE_ORDER_BIG_ENDIAN); putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN); WriteChunk_MM_VERS(file, MM_FILE_VERSION_ACTUAL, MM_GAME_VERSION_ACTUAL); putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN); SaveLevel_MM_HEAD(file, &native_mm_level); putFileChunk(file, "AUTH", MAX_LEVEL_AUTHOR_LEN, BYTE_ORDER_BIG_ENDIAN); SaveLevel_MM_AUTH(file, &native_mm_level); putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN); SaveLevel_MM_BODY(file, &native_mm_level); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); } mirrormagic-3.0.0/src/game_mm/mm_game.h0000644000175000017500000000503413263212010017267 0ustar aeglosaeglos// ============================================================================ // Mirror Magic -- McDuffin's Revenge // ---------------------------------------------------------------------------- // (c) 1994-2017 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // mm_game.h // ============================================================================ #ifndef MM_GAME_H #define MM_GAME_H #include "main_mm.h" void InitAmoebaNr(int, int); void GameWon_MM(void); int NewHiScore_MM(void); void Blurb(int, int); void Impact(int, int); void TurnRound(int, int); int AmoebeNachbarNr(int, int); void AmoebeUmwandeln(int, int); void AmoebeUmwandelnBD(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, 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); 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(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 CreateGameButtons(); void UnmapGameButtons(); void AddLaserEdge(int, int); void AddDamagedField(int, int); void ScanLaser(void); void DrawLaser(int, int); boolean HitElement(int, int); boolean HitOnlyAnEdge(int, int); boolean HitPolarizer(int, int); boolean HitBlock(int, int); boolean HitLaserSource(int, int); boolean HitLaserDestination(int, int); boolean HitReflectingWalls(int, int); boolean HitAbsorbingWalls(int, int); void RotateMirror(int, int, int); boolean ObjHit(int, int, int); void DeletePacMan(int, int); void ColorCycling(void); void MovePacMen(void); #endif mirrormagic-3.0.0/src/init.h0000644000175000017500000000312313263212010015223 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // init.h // ============================================================================ #ifndef INIT_H #define INIT_H #include "main.h" #define setMoveIntoAcidProperty(l, e, v) \ (setBitfieldProperty(&(l)->can_move_into_acid_bits, \ EP_CAN_MOVE_INTO_ACID, e, v)) #define getMoveIntoAcidProperty(l, e) \ (getBitfieldProperty(&(l)->can_move_into_acid_bits, \ EP_CAN_MOVE_INTO_ACID, e)) #define setDontCollideWithProperty(l, e, v) \ (setBitfieldProperty(&(l)->dont_collide_with_bits, \ EP_DONT_COLLIDE_WITH, e, v)) #define getDontCollideWithProperty(l, e) \ (getBitfieldProperty(&(l)->dont_collide_with_bits, \ EP_DONT_COLLIDE_WITH, e)) void setBitfieldProperty(int *, int, int, boolean); boolean getBitfieldProperty(int *, int, int); void ResolveGroupElement(int); void InitElementPropertiesStatic(void); void InitElementPropertiesEngine(int); void InitElementPropertiesGfxElement(); void ReloadCustomArtwork(int); void RedrawGlobalBorder(); void KeyboardAutoRepeatOffUnlessAutoplay(); void InitGfxBuffers(); void InitGadgets(); void InitImageTextures(); void DisplayExitMessage(char *, va_list); void OpenAll(void); void CloseAllAndExit(int); #endif mirrormagic-3.0.0/src/tools.h0000644000175000017500000002153513263212010015427 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // tools.h // ============================================================================ #ifndef TOOLS_H #define TOOLS_H #include "main.h" #include "game.h" /* 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) /* 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_ALL (DOOR_OPEN_1 | DOOR_OPEN_2) #define DOOR_CLOSE_ALL (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_COPY_BACK (1 << 5) #define DOOR_NO_DELAY (1 << 6) #define DOOR_FORCE_ANIM (1 << 7) #define DOOR_FORCE_REDRAW (1 << 8) #define DOOR_GET_STATE (1 << 9) #define DOOR_SET_STATE (1 << 10) #define DOOR_1 (DOOR_ACTION_1) #define DOOR_2 (DOOR_ACTION_2) #define DOOR_OPEN (DOOR_OPEN_ALL) #define DOOR_CLOSE (DOOR_CLOSE_ALL) #define DOOR_INDEX_FROM_TOKEN(x) ((x) == DOOR_1 ? 0 : 1) #define DOOR_TOKEN_FROM_INDEX(x) ((x) == 0 ? DOOR_1 ? : DOOR_2) #define REDRAW_DOOR_FROM_TOKEN(x) ((x) == DOOR_1 ? REDRAW_DOOR_1 : \ REDRAW_DOOR_2) /* for Request */ #define REQ_ASK (1 << 0) #define REQ_CONFIRM (1 << 1) #define REQ_PLAYER (1 << 2) #define REQ_STAY_OPEN (1 << 3) #define REQ_STAY_CLOSED (1 << 4) #define REQ_REOPEN (1 << 5) #define REQUEST_WAIT_FOR_INPUT (REQ_ASK | REQ_CONFIRM | REQ_PLAYER) int correctLevelPosX_EM(int); int correctLevelPosY_EM(int); int getLevelFromScreenX(int); int getLevelFromScreenY(int); void DumpTile(int, int); void DumpTileFromScreen(int, int); void DrawMaskedBorder_FIELD(); void DrawMaskedBorder_DOOR_1(); void DrawMaskedBorder_DOOR_2(); void DrawMaskedBorder_DOOR_3(); void DrawMaskedBorder_ALL(); void DrawMaskedBorder(int); void DrawMaskedBorderToTarget(int); void DrawTileCursor(int); void SetDrawtoField(int); void RedrawPlayfield(); void BlitScreenToBitmap_RND(Bitmap *); void BlitScreenToBitmap(Bitmap *); void BackToFront(); void BackToFront_WithFrameDelay(unsigned int); void FadeIn(int); void FadeOut(int); void FadeSetEnterMenu(); void FadeSetLeaveMenu(); void FadeSetEnterScreen(); void FadeSetNextScreen(); void FadeSetLeaveScreen(); void FadeSetFromType(int); void FadeSetDisabled(); void FadeSkipNextFadeIn(); void FadeSkipNextFadeOut(); Bitmap *getGlobalBorderBitmapFromStatus(int); void ClearField(); void SetWindowBackgroundImageIfDefined(int); void SetMainBackgroundImageIfDefined(int); void SetDoorBackgroundImageIfDefined(int); void SetWindowBackgroundImage(int); void SetMainBackgroundImage(int); void SetDoorBackgroundImage(int); void SetPanelBackground(); void DrawBackground(int, int, int, int); void DrawBackgroundForFont(int, int, int, int, int); void DrawBackgroundForGraphic(int, int, int, int, int); boolean CheckIfGlobalBorderHasChanged(); void RedrawGlobalBorder(); void MarkTileDirty(int, int); void SetBorderElement(); void FloodFillLevel(int, int, int, short[][MAX_LEV_FIELDY], int, int); void FloodFillLevelExt(int, int, int, int, int y, short field[][y], int, int); void SetRandomAnimationValue(int, int); int getGraphicAnimationFrame(int, int); void DrawFixedGraphicAnimation(int, int, int); void DrawFixedGraphicAnimationExt(DrawBuffer *, int, int, int, int, int); void DrawLevelGraphicAnimation(int, int, int); void DrawLevelElementAnimation(int, int, int); void DrawLevelGraphicAnimationIfNeeded(int, int, int); void DrawLevelElementAnimationIfNeeded(int, int, int); void DrawAllPlayers(void); void DrawPlayerField(int, int); void DrawPlayer(struct PlayerInfo *); void getGraphicSourceBitmap(int, int, Bitmap **); void getGraphicSourceXY(int, int, int *, int *, boolean); void getSizedGraphicSourceExt(int, int, int, Bitmap **, int *, int *, boolean); void getSizedGraphicSource(int, int, int, Bitmap **, int *, int *); void getFixedGraphicSource(int, int, Bitmap **, int *, int *); void getMiniGraphicSource(int, Bitmap **, int *, int *); void getGraphicSource(int, int, Bitmap **, int *, int *); void DrawGraphic(int, int, int, int); void DrawGraphicExt(DrawBuffer *, int, int, int, int); void DrawGraphicThruMask(int, int, int, int); void DrawGraphicThruMaskExt(DrawBuffer *, int, int, int, int); void DrawFixedGraphic(int, int, int, int); void DrawFixedGraphicExt(DrawBuffer *, int, int, int, int); void DrawFixedGraphicThruMask(int, int, int, int); void DrawFixedGraphicThruMaskExt(DrawBuffer *, int, int, int, int); void DrawSizedGraphic(int, int, int, int, int); void DrawSizedGraphicExt(DrawBuffer *, int, int, int, int, int); void DrawSizedGraphicThruMask(int, int, int, int, int); void DrawSizedGraphicThruMaskExt(DrawBuffer *, int, int, int, int, int); void DrawMiniGraphic(int, int, int); void DrawMiniGraphicExt(DrawBuffer *, 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 DrawLevelFieldCrumbled(int, int); void DrawLevelFieldCrumbledDigging(int, int, int, int); void DrawLevelFieldCrumbledNeighbours(int, int); void DrawScreenElement(int, int, int); void DrawLevelElement(int, int, int); void DrawScreenField(int, int); void DrawLevelField(int, int); void DrawSizedWallParts_MM(int, int, int, int, boolean, int); void DrawSizedElement(int, int, int, int); void DrawSizedElementThruMask(int, int, int, int); void DrawSizedElementOrWall(int, int, int, int, int); void DrawMiniElement(int, int, int); void DrawMiniElementOrWall(int, int, int, int); void ShowEnvelope(int); void ShowEnvelopeDoor(char *text, int); void DrawLevel(int); void DrawSizedLevel(int, int, int, int, int); void DrawMiniLevel(int, int, int, int); void DrawPreviewLevelInitial(void); void DrawPreviewLevelAnimation(void); void WaitForEventToContinue(void); boolean Request(char *, unsigned int); void InitGraphicCompatibilityInfo_Doors(void); void InitDoors(void); unsigned int OpenDoor(unsigned int); unsigned int CloseDoor(unsigned int); unsigned int GetDoorState(void); unsigned int SetDoorState(unsigned int); unsigned int MoveDoor(unsigned int); void DrawSpecialEditorDoor(); void UndrawSpecialEditorDoor(); void CreateToolButtons(); void FreeToolButtons(); int map_element_RND_to_EM(int); int map_element_EM_to_RND(int); int map_direction_RND_to_EM(int); int map_direction_EM_to_RND(int); void map_android_clone_elements_RND_to_EM(struct LevelInfo *); void map_android_clone_elements_EM_to_RND(struct LevelInfo *); int map_element_RND_to_SP(int); int map_element_SP_to_RND(int); int map_action_SP_to_RND(int); int map_element_RND_to_MM(int); int map_element_MM_to_RND(int); int map_action_MM_to_RND(int); int map_sound_MM_to_RND(int); int map_mm_wall_element(int); int map_mm_wall_element_editor(int); int get_next_element(int); int el_act_dir2img(int, int, int); int el_act2img(int, int); int el_dir2img(int, int); int el2baseimg(int); int el2img(int); int el2edimg(int); int el2preimg(int); int el2panelimg(int); int font2baseimg(int); int getBeltNrFromBeltElement(int); int getBeltNrFromBeltActiveElement(int); int getBeltNrFromBeltSwitchElement(int); int getBeltDirNrFromBeltElement(int); int getBeltDirNrFromBeltSwitchElement(int); int getBeltDirFromBeltElement(int); int getBeltDirFromBeltSwitchElement(int); int getBeltElementFromBeltNrAndBeltDirNr(int, int); int getBeltElementFromBeltNrAndBeltDir(int, int); int getBeltSwitchElementFromBeltNrAndBeltDirNr(int, int); int getBeltSwitchElementFromBeltNrAndBeltDir(int, int); unsigned int InitRND(int); void InitGraphicInfo_EM(void); void PlayMenuSoundExt(int); void PlayMenuSound(); void PlayMenuSoundStereo(int, int); void PlayMenuSoundIfLoopExt(int); void PlayMenuSoundIfLoop(); void PlayMenuMusicExt(int); void PlayMenuMusic(); void PlayMenuSoundsAndMusic(); void FadeMenuSoundsAndMusic(); void PlaySoundActivating(); void PlaySoundSelecting(); void SetAnimStatus(int); void SetGameStatus(int); void SetFontStatus(int); void ResetFontStatus(); void ToggleFullscreenOrChangeWindowScalingIfNeeded(); void ChangeViewportPropertiesIfNeeded(); boolean CheckIfPlayfieldViewportHasChanged(); boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged(); #endif /* TOOLS_H */ mirrormagic-3.0.0/src/editor.h0000644000175000017500000000162713263212010015555 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // editor.h // ============================================================================ #ifndef EDITOR_H #define EDITOR_H #include "main.h" void CreateLevelEditorGadgets(); void FreeLevelEditorGadgets(); void UnmapLevelEditorGadgets(); void DrawLevelEd(void); void HandleLevelEditorKeyInput(Key); void HandleLevelEditorIdle(); void HandleEditorGadgetInfoText(void *ptr); void RequestExitLevelEditor(boolean, boolean); void PrintEditorElementList(); void DumpBrush(); void DumpBrush_Small(); #endif mirrormagic-3.0.0/src/screens.h0000644000175000017500000000247513263212010015733 0ustar aeglosaeglos// ============================================================================ // Rocks'n'Diamonds - McDuffin Strikes Back! // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // screens.h // ============================================================================ #ifndef SCREENS_H #define SCREENS_H #include "main.h" /* (arbitrary, but unique) values for HandleChooseTree() */ #define SCROLL_LINE (1 * SCR_FIELDY) #define SCROLL_PAGE (2 * SCR_FIELDY) void DrawMainMenuExt(int); void DrawAndFadeInMainMenu(int); void DrawMainMenu(void); void DrawHallOfFame(int); void RedrawSetupScreenAfterFullscreenToggle(); void HandleTitleScreen(int, int, int, int, int); void HandleMainMenu(int, int, int, int, int); void HandleChooseLevelSet(int, int, int, int, int); void HandleChooseLevelNr(int, int, int, int, int); void HandleHallOfFame(int, int, int, int, int); void HandleInfoScreen(int, int, int, int, int); void HandleSetupScreen(int, int, int, int, int); void HandleTypeName(int, Key); void HandleGameActions(void); void CreateScreenGadgets(); void FreeScreenGadgets(); #endif /* SCREENS_H */ mirrormagic-3.0.0/src/libgame/0000755000175000017500000000000013263214225015522 5ustar aeglosaeglosmirrormagic-3.0.0/src/libgame/sdl.h0000644000175000017500000003207513263212010016452 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // sdl.h // ============================================================================ #ifndef SDL_H #define SDL_H #include #include #include #include #include #if defined(PLATFORM_WIN32) #include #endif /* definitions needed for "system.c" */ #if defined(TARGET_SDL2) #define SURFACE_FLAGS (0) #else #define SURFACE_FLAGS (SDL_SWSURFACE) #endif #if defined(TARGET_SDL2) #define SET_TRANSPARENT_PIXEL (SDL_TRUE) #define UNSET_TRANSPARENT_PIXEL (SDL_FALSE) #else #define SET_TRANSPARENT_PIXEL (SDL_SRCCOLORKEY) #define UNSET_TRANSPARENT_PIXEL (0) #endif /* system dependent definitions */ #if defined(TARGET_SDL2) #define TARGET_STRING "SDL2" #else #define TARGET_STRING "SDL" #endif #if defined(PLATFORM_ANDROID) #define WINDOW_SCALING_STATUS WINDOW_SCALING_NOT_AVAILABLE #define FULLSCREEN_STATUS FULLSCREEN_AVAILABLE #elif defined(TARGET_SDL2) #define WINDOW_SCALING_STATUS WINDOW_SCALING_AVAILABLE #define FULLSCREEN_STATUS FULLSCREEN_AVAILABLE #else // SDL 1.2 #define WINDOW_SCALING_STATUS WINDOW_SCALING_NOT_AVAILABLE #define FULLSCREEN_STATUS FULLSCREEN_AVAILABLE #endif #define CURSOR_MAX_WIDTH 32 #define CURSOR_MAX_HEIGHT 32 /* SDL type definitions */ typedef struct SDLSurfaceInfo Bitmap; typedef struct SDLSurfaceInfo DrawBuffer; typedef struct SDLSurfaceInfo DrawWindow; typedef Uint32 Pixel; typedef SDL_Cursor *Cursor; #if defined(TARGET_SDL2) typedef SDL_Keycode Key; typedef SDL_Keymod KeyMod; #else typedef SDLKey Key; typedef unsigned int KeyMod; #endif typedef SDL_Event Event; typedef SDL_MouseButtonEvent ButtonEvent; typedef SDL_MouseMotionEvent MotionEvent; #if defined(TARGET_SDL2) typedef SDL_MouseWheelEvent WheelEvent; typedef SDL_TouchFingerEvent FingerEvent; typedef SDL_TextInputEvent TextEvent; typedef SDL_Event PauseResumeEvent; typedef SDL_WindowEvent WindowEvent; #endif typedef SDL_KeyboardEvent KeyEvent; typedef SDL_Event ExposeEvent; typedef SDL_Event FocusChangeEvent; typedef SDL_Event ClientMessageEvent; /* structure definitions */ struct SDLSurfaceInfo { char *source_filename; int width, height; SDL_Surface *surface; SDL_Surface *surface_masked; #if defined(TARGET_SDL2) SDL_Texture *texture; SDL_Texture *texture_masked; #endif }; struct MouseCursorInfo { int width, height; int hot_x, hot_y; byte data[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8]; byte mask[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8]; }; /* SDL symbol definitions */ #define None 0L #define BLACK_PIXEL 0x000000 #define WHITE_PIXEL 0xffffff #define EVENT_BUTTONPRESS SDL_MOUSEBUTTONDOWN #define EVENT_BUTTONRELEASE SDL_MOUSEBUTTONUP #define EVENT_MOTIONNOTIFY SDL_MOUSEMOTION #if defined(TARGET_SDL2) #define EVENT_WHEELMOTION SDL_MOUSEWHEEL #define EVENT_FINGERPRESS SDL_FINGERDOWN #define EVENT_FINGERRELEASE SDL_FINGERUP #define EVENT_FINGERMOTION SDL_FINGERMOTION #define EVENT_TEXTINPUT SDL_TEXTINPUT #endif #define EVENT_KEYPRESS SDL_KEYDOWN #define EVENT_KEYRELEASE SDL_KEYUP #define EVENT_EXPOSE SDL_USEREVENT + 0 #define EVENT_FOCUSIN SDL_USEREVENT + 1 #define EVENT_FOCUSOUT SDL_USEREVENT + 2 #define EVENT_CLIENTMESSAGE SDL_QUIT #define EVENT_MAPNOTIFY SDL_USEREVENT + 4 #define EVENT_UNMAPNOTIFY SDL_USEREVENT + 5 #define KSYM_UNDEFINED SDLK_UNKNOWN #define KSYM_Return SDLK_RETURN #define KSYM_Escape SDLK_ESCAPE #define KSYM_Left SDLK_LEFT #define KSYM_Right SDLK_RIGHT #define KSYM_Up SDLK_UP #define KSYM_Down SDLK_DOWN #ifdef SDLK_KP_LEFT #define KSYM_KP_Left SDLK_KP_LEFT #define KSYM_KP_Right SDLK_KP_RIGHT #define KSYM_KP_Up SDLK_KP_UP #define KSYM_KP_Down SDLK_KP_DOWN #endif #define KSYM_KP_Enter SDLK_KP_ENTER #define KSYM_KP_Add SDLK_KP_PLUS #define KSYM_KP_Subtract SDLK_KP_MINUS #define KSYM_KP_Multiply SDLK_KP_MULTIPLY #define KSYM_KP_Divide SDLK_KP_DIVIDE #define KSYM_KP_Separator SDLK_KP_PERIOD #define KSYM_Shift_L SDLK_LSHIFT #define KSYM_Shift_R SDLK_RSHIFT #define KSYM_Control_L SDLK_LCTRL #define KSYM_Control_R SDLK_RCTRL #if defined(TARGET_SDL2) #define KSYM_Meta_L SDLK_LGUI #define KSYM_Meta_R SDLK_RGUI #else #define KSYM_Meta_L SDLK_LMETA #define KSYM_Meta_R SDLK_RMETA #endif #define KSYM_Alt_L SDLK_LALT #define KSYM_Alt_R SDLK_RALT #if !defined(TARGET_SDL2) #define KSYM_Super_L SDLK_LSUPER #define KSYM_Super_R SDLK_RSUPER #endif #define KSYM_Mode_switch SDLK_MODE #define KSYM_Multi_key SDLK_RCTRL #define KSYM_BackSpace SDLK_BACKSPACE #define KSYM_Delete SDLK_DELETE #define KSYM_Insert SDLK_INSERT #define KSYM_Tab SDLK_TAB #define KSYM_Home SDLK_HOME #define KSYM_End SDLK_END #define KSYM_Page_Up SDLK_PAGEUP #define KSYM_Page_Down SDLK_PAGEDOWN #if defined(TARGET_SDL2) #define KSYM_Select SDLK_SELECT #define KSYM_Menu SDLK_MENU #define KSYM_Back SDLK_AC_BACK #define KSYM_PlayPause SDLK_AUDIOPLAY #if defined(PLATFORM_ANDROID) #define KSYM_Rewind SDLK_AUDIOREWIND #define KSYM_FastForward SDLK_AUDIOFASTFORWARD #endif #endif #define KSYM_space SDLK_SPACE #define KSYM_exclam SDLK_EXCLAIM #define KSYM_quotedbl SDLK_QUOTEDBL #define KSYM_numbersign SDLK_HASH #define KSYM_dollar SDLK_DOLLAR #if defined(TARGET_SDL2) #define KSYM_percent SDLK_PERCENT #else #define KSYM_percent 37 /* undefined in SDL */ #endif #define KSYM_ampersand SDLK_AMPERSAND #define KSYM_apostrophe SDLK_QUOTE #define KSYM_parenleft SDLK_LEFTPAREN #define KSYM_parenright SDLK_RIGHTPAREN #define KSYM_asterisk SDLK_ASTERISK #define KSYM_plus SDLK_PLUS #define KSYM_comma SDLK_COMMA #define KSYM_minus SDLK_MINUS #define KSYM_period SDLK_PERIOD #define KSYM_slash SDLK_SLASH #define KSYM_colon SDLK_COLON #define KSYM_semicolon SDLK_SEMICOLON #define KSYM_less SDLK_LESS #define KSYM_equal SDLK_EQUALS #define KSYM_greater SDLK_GREATER #define KSYM_question SDLK_QUESTION #define KSYM_at SDLK_AT #define KSYM_bracketleft SDLK_LEFTBRACKET #define KSYM_backslash SDLK_BACKSLASH #define KSYM_bracketright SDLK_RIGHTBRACKET #define KSYM_asciicircum SDLK_CARET #define KSYM_underscore SDLK_UNDERSCORE #define KSYM_grave SDLK_BACKQUOTE #define KSYM_quoteleft KSYM_UNDEFINED /* undefined */ #define KSYM_braceleft KSYM_UNDEFINED /* undefined */ #define KSYM_bar KSYM_UNDEFINED /* undefined */ #define KSYM_braceright KSYM_UNDEFINED /* undefined */ #define KSYM_asciitilde KSYM_UNDEFINED /* undefined */ #if defined(TARGET_SDL2) #define KSYM_degree 176 #define KSYM_Adiaeresis 196 #define KSYM_Odiaeresis 214 #define KSYM_Udiaeresis 220 #define KSYM_adiaeresis 228 #define KSYM_odiaeresis 246 #define KSYM_udiaeresis 252 #define KSYM_ssharp 223 #else #define KSYM_degree SDLK_WORLD_16 #define KSYM_Adiaeresis SDLK_WORLD_36 #define KSYM_Odiaeresis SDLK_WORLD_54 #define KSYM_Udiaeresis SDLK_WORLD_60 #define KSYM_adiaeresis SDLK_WORLD_68 #define KSYM_odiaeresis SDLK_WORLD_86 #define KSYM_udiaeresis SDLK_WORLD_92 #define KSYM_ssharp SDLK_WORLD_63 #endif #ifndef SDLK_A #define SDLK_A 65 #define SDLK_B 66 #define SDLK_C 67 #define SDLK_D 68 #define SDLK_E 69 #define SDLK_F 70 #define SDLK_G 71 #define SDLK_H 72 #define SDLK_I 73 #define SDLK_J 74 #define SDLK_K 75 #define SDLK_L 76 #define SDLK_M 77 #define SDLK_N 78 #define SDLK_O 79 #define SDLK_P 80 #define SDLK_Q 81 #define SDLK_R 82 #define SDLK_S 83 #define SDLK_T 84 #define SDLK_U 85 #define SDLK_V 86 #define SDLK_W 87 #define SDLK_X 88 #define SDLK_Y 89 #define SDLK_Z 90 #endif #define KSYM_A SDLK_A #define KSYM_B SDLK_B #define KSYM_C SDLK_C #define KSYM_D SDLK_D #define KSYM_E SDLK_E #define KSYM_F SDLK_F #define KSYM_G SDLK_G #define KSYM_H SDLK_H #define KSYM_I SDLK_I #define KSYM_J SDLK_J #define KSYM_K SDLK_K #define KSYM_L SDLK_L #define KSYM_M SDLK_M #define KSYM_N SDLK_N #define KSYM_O SDLK_O #define KSYM_P SDLK_P #define KSYM_Q SDLK_Q #define KSYM_R SDLK_R #define KSYM_S SDLK_S #define KSYM_T SDLK_T #define KSYM_U SDLK_U #define KSYM_V SDLK_V #define KSYM_W SDLK_W #define KSYM_X SDLK_X #define KSYM_Y SDLK_Y #define KSYM_Z SDLK_Z #define KSYM_a SDLK_a #define KSYM_b SDLK_b #define KSYM_c SDLK_c #define KSYM_d SDLK_d #define KSYM_e SDLK_e #define KSYM_f SDLK_f #define KSYM_g SDLK_g #define KSYM_h SDLK_h #define KSYM_i SDLK_i #define KSYM_j SDLK_j #define KSYM_k SDLK_k #define KSYM_l SDLK_l #define KSYM_m SDLK_m #define KSYM_n SDLK_n #define KSYM_o SDLK_o #define KSYM_p SDLK_p #define KSYM_q SDLK_q #define KSYM_r SDLK_r #define KSYM_s SDLK_s #define KSYM_t SDLK_t #define KSYM_u SDLK_u #define KSYM_v SDLK_v #define KSYM_w SDLK_w #define KSYM_x SDLK_x #define KSYM_y SDLK_y #define KSYM_z SDLK_z #define KSYM_0 SDLK_0 #define KSYM_1 SDLK_1 #define KSYM_2 SDLK_2 #define KSYM_3 SDLK_3 #define KSYM_4 SDLK_4 #define KSYM_5 SDLK_5 #define KSYM_6 SDLK_6 #define KSYM_7 SDLK_7 #define KSYM_8 SDLK_8 #define KSYM_9 SDLK_9 #if defined(TARGET_SDL2) #define KSYM_KP_0 SDLK_KP_0 #define KSYM_KP_1 SDLK_KP_1 #define KSYM_KP_2 SDLK_KP_2 #define KSYM_KP_3 SDLK_KP_3 #define KSYM_KP_4 SDLK_KP_4 #define KSYM_KP_5 SDLK_KP_5 #define KSYM_KP_6 SDLK_KP_6 #define KSYM_KP_7 SDLK_KP_7 #define KSYM_KP_8 SDLK_KP_8 #define KSYM_KP_9 SDLK_KP_9 #else #define KSYM_KP_0 SDLK_KP0 #define KSYM_KP_1 SDLK_KP1 #define KSYM_KP_2 SDLK_KP2 #define KSYM_KP_3 SDLK_KP3 #define KSYM_KP_4 SDLK_KP4 #define KSYM_KP_5 SDLK_KP5 #define KSYM_KP_6 SDLK_KP6 #define KSYM_KP_7 SDLK_KP7 #define KSYM_KP_8 SDLK_KP8 #define KSYM_KP_9 SDLK_KP9 #endif #define KSYM_F1 SDLK_F1 #define KSYM_F2 SDLK_F2 #define KSYM_F3 SDLK_F3 #define KSYM_F4 SDLK_F4 #define KSYM_F5 SDLK_F5 #define KSYM_F6 SDLK_F6 #define KSYM_F7 SDLK_F7 #define KSYM_F8 SDLK_F8 #define KSYM_F9 SDLK_F9 #define KSYM_F10 SDLK_F10 #define KSYM_F11 SDLK_F11 #define KSYM_F12 SDLK_F12 #define KSYM_FKEY_FIRST KSYM_F1 #define KSYM_FKEY_LAST KSYM_F12 #define KSYM_NUM_FKEYS (KSYM_FKEY_LAST - KSYM_FKEY_FIRST + 1) #define KMOD_None KMOD_NONE #define KMOD_Shift_L KMOD_LSHIFT #define KMOD_Shift_R KMOD_RSHIFT #define KMOD_Control_L KMOD_LCTRL #define KMOD_Control_R KMOD_RCTRL #if defined(TARGET_SDL2) #define KMOD_Meta_L KMOD_LGUI #define KMOD_Meta_R KMOD_RGUI #else #define KMOD_Meta_L KMOD_LMETA #define KMOD_Meta_R KMOD_RMETA #endif #define KMOD_Alt_L KMOD_LALT #define KMOD_Alt_R KMOD_RALT #define KMOD_Shift (KMOD_Shift_L | KMOD_Shift_R) #define KMOD_Control (KMOD_Control_L | KMOD_Control_R) #define KMOD_Meta (KMOD_Meta_L | KMOD_Meta_R) #define KMOD_Alt (KMOD_Alt_L | KMOD_Alt_R) /* this only contains "valid" key modifiers (and ignores keys like "NumLock") */ #define KMOD_Valid (KMOD_Shift | \ KMOD_Control | \ KMOD_Meta | \ KMOD_Alt) #if defined(TARGET_SDL2) #define KMOD_TextInput (KMOD_Shift | KMOD_Alt_R) #endif /* SDL function definitions */ boolean SDLSetNativeSurface(SDL_Surface **); SDL_Surface *SDLGetNativeSurface(SDL_Surface *); void SDLCreateBitmapTextures(Bitmap *); void SDLFreeBitmapTextures(Bitmap *); #if defined(TARGET_SDL2) SDL_Surface *SDL_DisplayFormat(SDL_Surface *); void SDLSetWindowScaling(int); void SDLSetWindowScalingQuality(char *); void SDLSetWindowFullscreen(boolean); void SDLSetDisplaySize(void); void SDLSetScreenSizeAndOffsets(int, int); void SDLSetScreenSizeForRenderer(int, int); void SDLSetScreenProperties(void); #endif void SDLSetScreenRenderingMode(char *); void SDLRedrawWindow(); void SDLSetWindowTitle(void); void SDLLimitScreenUpdates(boolean); void SDLInitVideoDisplay(void); void SDLInitVideoBuffer(boolean); boolean SDLSetVideoMode(boolean); void SDLCreateBitmapContent(Bitmap *, int, int, int); void SDLFreeBitmapPointers(Bitmap *); void SDLCopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int); void SDLBlitTexture(Bitmap *, int, int, int, int, int, int, int); void SDLFillRectangle(Bitmap *, int, int, int, int, Uint32); void SDLFadeRectangle(int, int, int, int, int, int, int, void (*draw_border_function)(void)); void SDLDrawSimpleLine(Bitmap *, int, int, int, int, Uint32); void SDLDrawLine(Bitmap *, int, int, int, int, Uint32); Pixel SDLGetPixel(Bitmap *, int, int); void SDLPutPixel(Bitmap *, int, int, Pixel); void SDLInvertArea(Bitmap *, int, int, int, int, Uint32); void SDLCopyInverseMasked(Bitmap *, Bitmap *, int, int, int, int, int, int); Bitmap *SDLZoomBitmap(Bitmap *, int, int); Bitmap *SDLLoadImage(char *); void SDLSetMouseCursor(struct MouseCursorInfo *); void SDLOpenAudio(void); void SDLCloseAudio(void); void SDLWaitEvent(Event *); void SDLHandleWindowManagerEvent(Event *); void HandleJoystickEvent(Event *); void SDLInitJoysticks(void); boolean SDLReadJoystick(int, int *, int *, boolean *, boolean *); boolean SDLCheckJoystickOpened(int); void SDLClearJoystickState(); boolean SDLOpenJoystick(int); void SDLCloseJoystick(int); void PrepareFadeBitmap(int); #endif /* SDL_H */ mirrormagic-3.0.0/src/libgame/system.h0000644000175000017500000013316113263212010017212 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // system.h // ============================================================================ #ifndef SYSTEM_H #define SYSTEM_H #include "platform.h" #include "types.h" #if defined(PLATFORM_MACOSX) #include "macosx.h" #elif defined(PLATFORM_WIN32) #include "windows.h" #elif defined(PLATFORM_ANDROID) #include "android.h" #endif #include "sdl.h" /* the additional 'b' is needed for Win32 to open files in binary mode */ #define MODE_READ "rb" #define MODE_WRITE "wb" #define MODE_APPEND "ab" #define DEFAULT_DEPTH 0 #define BLIT_OPAQUE 0 #define BLIT_MASKED 1 #define BLIT_INVERSE 2 #define BLIT_ON_BACKGROUND 3 /* values for fullscreen status */ #define FULLSCREEN_NOT_AVAILABLE FALSE #define FULLSCREEN_AVAILABLE TRUE /* values for window scaling */ #define WINDOW_SCALING_NOT_AVAILABLE FALSE #define WINDOW_SCALING_AVAILABLE TRUE #define MIN_WINDOW_SCALING_PERCENT 30 #define STD_WINDOW_SCALING_PERCENT 100 #define MAX_WINDOW_SCALING_PERCENT 400 #define STEP_WINDOW_SCALING_PERCENT 10 /* values for window scaling quality */ #define SCALING_QUALITY_NEAREST "nearest" #define SCALING_QUALITY_LINEAR "linear" #define SCALING_QUALITY_BEST "best" #define SCALING_QUALITY_DEFAULT SCALING_QUALITY_LINEAR /* values for screen rendering mode */ #define STR_SPECIAL_RENDERING_OFF "stream_texture_only" #define STR_SPECIAL_RENDERING_BITMAP "bitmap_and_stream_texture" #define STR_SPECIAL_RENDERING_TARGET "target_texture_only" #define STR_SPECIAL_RENDERING_DOUBLE "stream_and_target_texture" #if defined(TARGET_SDL2) #define STR_SPECIAL_RENDERING_DEFAULT STR_SPECIAL_RENDERING_DOUBLE #else #define STR_SPECIAL_RENDERING_DEFAULT STR_SPECIAL_RENDERING_BITMAP #endif #define SPECIAL_RENDERING_OFF 0 #define SPECIAL_RENDERING_BITMAP 1 #define SPECIAL_RENDERING_TARGET 2 #define SPECIAL_RENDERING_DOUBLE 3 #if defined(TARGET_SDL2) #define SPECIAL_RENDERING_DEFAULT SPECIAL_RENDERING_DOUBLE #else #define SPECIAL_RENDERING_DEFAULT SPECIAL_RENDERING_BITMAP #endif /* values for touch control */ #define TOUCH_CONTROL_OFF "off" #define TOUCH_CONTROL_VIRTUAL_BUTTONS "virtual_buttons" #define TOUCH_CONTROL_WIPE_GESTURES "wipe_gestures" #define TOUCH_CONTROL_FOLLOW_FINGER "follow_finger" #if defined(PLATFORM_ANDROID) #define TOUCH_CONTROL_DEFAULT TOUCH_CONTROL_VIRTUAL_BUTTONS #else #define TOUCH_CONTROL_DEFAULT TOUCH_CONTROL_OFF #endif #define TOUCH_MOVE_DISTANCE_DEFAULT 2 #define TOUCH_DROP_DISTANCE_DEFAULT 5 /* values for special settings for mobile devices */ #if defined(PLATFORM_ANDROID) #define USE_TOUCH_INPUT_OVERLAY #define USE_COMPLETE_DISPLAY #define HAS_SCREEN_KEYBOARD #define SCREEN_KEYBOARD_POS(h) ((h) / 2) #endif /* default input keys */ #define DEFAULT_KEY_LEFT KSYM_Left #define DEFAULT_KEY_RIGHT KSYM_Right #define DEFAULT_KEY_UP KSYM_Up #define DEFAULT_KEY_DOWN KSYM_Down #if defined(PLATFORM_MACOSX) #define DEFAULT_KEY_SNAP KSYM_Control_L #define DEFAULT_KEY_DROP KSYM_KP_Enter #else #define DEFAULT_KEY_SNAP KSYM_Control_L #define DEFAULT_KEY_DROP KSYM_Control_R #endif #define DEFAULT_KEY_OKAY KSYM_Return #define DEFAULT_KEY_CANCEL KSYM_Escape /* default shortcut keys */ #define DEFAULT_KEY_SAVE_GAME KSYM_F1 #define DEFAULT_KEY_LOAD_GAME KSYM_F2 #define DEFAULT_KEY_TOGGLE_PAUSE KSYM_space #define DEFAULT_KEY_FOCUS_PLAYER_1 KSYM_F5 #define DEFAULT_KEY_FOCUS_PLAYER_2 KSYM_F6 #define DEFAULT_KEY_FOCUS_PLAYER_3 KSYM_F7 #define DEFAULT_KEY_FOCUS_PLAYER_4 KSYM_F8 #define DEFAULT_KEY_FOCUS_PLAYER_ALL KSYM_F9 #define DEFAULT_KEY_TAPE_EJECT KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_EXTRA KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_STOP KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_PAUSE KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_RECORD KSYM_UNDEFINED #define DEFAULT_KEY_TAPE_PLAY KSYM_UNDEFINED #define DEFAULT_KEY_SOUND_SIMPLE KSYM_UNDEFINED #define DEFAULT_KEY_SOUND_LOOPS KSYM_UNDEFINED #define DEFAULT_KEY_SOUND_MUSIC KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_LEFT KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_RIGHT KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_UP KSYM_UNDEFINED #define DEFAULT_KEY_SNAP_DOWN KSYM_UNDEFINED /* default debug setup keys and values */ #define DEFAULT_FRAME_DELAY_0 20 // 100 % speed #define DEFAULT_FRAME_DELAY_1 500 // 4 % speed #define DEFAULT_FRAME_DELAY_2 250 // 8 % speed #define DEFAULT_FRAME_DELAY_3 125 // 16 % speed #define DEFAULT_FRAME_DELAY_4 60 // 33 % speed #define DEFAULT_FRAME_DELAY_5 40 // 50 % speed #define DEFAULT_FRAME_DELAY_6 30 // 66 % speed #define DEFAULT_FRAME_DELAY_7 10 // 200 % speed #define DEFAULT_FRAME_DELAY_8 5 // 400 % speed #define DEFAULT_FRAME_DELAY_9 0 // maximum speed #define DEFAULT_KEY_FRAME_DELAY_0 KSYM_0 #define DEFAULT_KEY_FRAME_DELAY_1 KSYM_1 #define DEFAULT_KEY_FRAME_DELAY_2 KSYM_2 #define DEFAULT_KEY_FRAME_DELAY_3 KSYM_3 #define DEFAULT_KEY_FRAME_DELAY_4 KSYM_4 #define DEFAULT_KEY_FRAME_DELAY_5 KSYM_5 #define DEFAULT_KEY_FRAME_DELAY_6 KSYM_6 #define DEFAULT_KEY_FRAME_DELAY_7 KSYM_7 #define DEFAULT_KEY_FRAME_DELAY_8 KSYM_8 #define DEFAULT_KEY_FRAME_DELAY_9 KSYM_9 #define NUM_DEBUG_FRAME_DELAY_KEYS 10 #define DEFAULT_FRAME_DELAY_USE_MOD_KEY FALSE #define DEFAULT_FRAME_DELAY_GAME_ONLY TRUE /* values for key_status */ #define KEY_NOT_PRESSED FALSE #define KEY_RELEASED FALSE #define KEY_PRESSED TRUE /* values for button status */ #define MB_NOT_PRESSED FALSE #define MB_NOT_RELEASED TRUE #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_MENU_LEAVE (-2) #define MB_LEFTBUTTON 1 #define MB_MIDDLEBUTTON 2 #define MB_RIGHTBUTTON 3 #define MB_WHEEL_UP 4 #define MB_WHEEL_DOWN 5 #define MB_WHEEL_LEFT 6 #define MB_WHEEL_RIGHT 7 #define IS_WHEEL_BUTTON_VERTICAL(b) ((b) == MB_WHEEL_UP || \ (b) == MB_WHEEL_DOWN) #define IS_WHEEL_BUTTON_HORIZONTAL(b) ((b) == MB_WHEEL_LEFT || \ (b) == MB_WHEEL_RIGHT) #define IS_WHEEL_BUTTON(b) (IS_WHEEL_BUTTON_VERTICAL(b) || \ IS_WHEEL_BUTTON_HORIZONTAL(b)) #define DEFAULT_WHEEL_STEPS 3 #define BUTTON_STEPSIZE(b) ((b) == MB_LEFTBUTTON ? 1 : \ (b) == MB_MIDDLEBUTTON ? 5 : \ (b) == MB_RIGHTBUTTON ? 10 : 1) /* values for move directions */ #define MV_BIT_LEFT 0 #define MV_BIT_RIGHT 1 #define MV_BIT_UP 2 #define MV_BIT_DOWN 3 #define NUM_DIRECTIONS 4 /* diagonal movement directions are used in a different contect than buttons */ #define MV_BIT_UPLEFT 4 #define MV_BIT_UPRIGHT 5 #define MV_BIT_DOWNLEFT 6 #define MV_BIT_DOWNRIGHT 7 #define NUM_DIRECTIONS_FULL 8 /* values for special "button" bitmasks */ #define BUTTON_1 4 #define BUTTON_2 5 #define NUM_PLAYER_ACTIONS 6 /* values for special "focus player" bitmasks */ #define BIT_SET_FOCUS 6 /* values for drawing stages for global animations */ #define DRAW_GLOBAL_ANIM_STAGE_1 1 #define DRAW_GLOBAL_ANIM_STAGE_2 2 /* values for drawing target (various functions) */ #define DRAW_TO_BACKBUFFER 0 #define DRAW_TO_FIELDBUFFER 1 #define DRAW_TO_SCREEN 2 #define DRAW_TO_FADE_SOURCE 3 #define DRAW_TO_FADE_TARGET 4 /* values for move directions and special "button" key bitmasks */ #define MV_NONE 0 #define MV_LEFT (1 << MV_BIT_LEFT) #define MV_RIGHT (1 << MV_BIT_RIGHT) #define MV_UP (1 << MV_BIT_UP) #define MV_DOWN (1 << MV_BIT_DOWN) #define MV_UPLEFT (MV_UP | MV_LEFT) #define MV_UPRIGHT (MV_UP | MV_RIGHT) #define MV_DOWNLEFT (MV_DOWN | MV_LEFT) #define MV_DOWNRIGHT (MV_DOWN | MV_RIGHT) #define MV_HORIZONTAL (MV_LEFT | MV_RIGHT) #define MV_VERTICAL (MV_UP | MV_DOWN) #define MV_ALL_DIRECTIONS (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN) #define MV_ANY_DIRECTION (MV_ALL_DIRECTIONS) #define MV_NO_DIRECTION (MV_NONE) #define KEY_BUTTON_1 (1 << BUTTON_1) #define KEY_BUTTON_2 (1 << BUTTON_2) #define KEY_BUTTON_SNAP KEY_BUTTON_1 #define KEY_BUTTON_DROP KEY_BUTTON_2 #define KEY_MOTION (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN) #define KEY_BUTTON (KEY_BUTTON_1 | KEY_BUTTON_2) #define KEY_ACTION (KEY_MOTION | KEY_BUTTON) #define KEY_SET_FOCUS (1 << BIT_SET_FOCUS) #define MV_DIR_FROM_BIT(x) ((x) < NUM_DIRECTIONS ? 1 << (x) : \ (x) == MV_BIT_UPLEFT ? MV_UPLEFT : \ (x) == MV_BIT_UPRIGHT ? MV_UPRIGHT : \ (x) == MV_BIT_DOWNLEFT ? MV_DOWNLEFT : \ (x) == MV_BIT_DOWNRIGHT ? MV_DOWNRIGHT : \ MV_NONE) #define MV_DIR_TO_BIT(x) ((x) == MV_LEFT ? MV_BIT_LEFT : \ (x) == MV_RIGHT ? MV_BIT_RIGHT : \ (x) == MV_UP ? MV_BIT_UP : \ (x) == MV_DOWN ? MV_BIT_DOWN : \ (x) == MV_UPLEFT ? MV_BIT_UPLEFT : \ (x) == MV_UPRIGHT ? MV_BIT_UPRIGHT : \ (x) == MV_DOWNLEFT ? MV_BIT_DOWNLEFT : \ (x) == MV_DOWNRIGHT ? MV_BIT_DOWNRIGHT : \ MV_BIT_DOWN) #define MV_DIR_OPPOSITE(x) ((x) == MV_LEFT ? MV_RIGHT : \ (x) == MV_RIGHT ? MV_LEFT : \ (x) == MV_UP ? MV_DOWN : \ (x) == MV_DOWN ? MV_UP : \ (x) == MV_UPLEFT ? MV_DOWNRIGHT : \ (x) == MV_UPRIGHT ? MV_DOWNLEFT : \ (x) == MV_DOWNLEFT ? MV_UPRIGHT : \ (x) == MV_DOWNRIGHT ? MV_UPLEFT : \ MV_NONE) /* values for animation mode (frame order and direction) */ /* (stored in level files -- never change existing values) */ #define ANIM_NONE 0 #define ANIM_LOOP (1 << 0) #define ANIM_LINEAR (1 << 1) #define ANIM_PINGPONG (1 << 2) #define ANIM_PINGPONG2 (1 << 3) #define ANIM_RANDOM (1 << 4) #define ANIM_CE_VALUE (1 << 5) #define ANIM_CE_SCORE (1 << 6) #define ANIM_CE_DELAY (1 << 7) #define ANIM_REVERSE (1 << 8) #define ANIM_OPAQUE_PLAYER (1 << 9) /* values for special (non game element) animation modes */ /* (not stored in level files -- can be changed, if needed) */ #define ANIM_HORIZONTAL (1 << 10) #define ANIM_VERTICAL (1 << 11) #define ANIM_CENTERED (1 << 12) #define ANIM_STATIC_PANEL (1 << 13) #define ANIM_ALL (1 << 14) #define ANIM_ONCE (1 << 15) #define ANIM_DEFAULT ANIM_LOOP /* values for special drawing styles (currently only for crumbled graphics) */ #define STYLE_NONE 0 #define STYLE_ACCURATE_BORDERS (1 << 0) #define STYLE_INNER_CORNERS (1 << 1) #define STYLE_REVERSE (1 << 2) #define STYLE_DEFAULT STYLE_NONE /* values for special global animation events */ #define ANIM_EVENT_NONE 0 #define ANIM_EVENT_SELF (1 << 16) #define ANIM_EVENT_ANY (1 << 17) #define ANIM_EVENT_ANIM_BIT 0 #define ANIM_EVENT_PART_BIT 8 #define ANIM_EVENT_ANIM_MASK (0xff << ANIM_EVENT_ANIM_BIT) #define ANIM_EVENT_PART_MASK (0xff << ANIM_EVENT_PART_BIT) #define ANIM_EVENT_DEFAULT ANIM_EVENT_NONE /* values for fade mode */ #define FADE_TYPE_NONE 0 #define FADE_TYPE_FADE_IN (1 << 0) #define FADE_TYPE_FADE_OUT (1 << 1) #define FADE_TYPE_TRANSFORM (1 << 2) #define FADE_TYPE_CROSSFADE (1 << 3) #define FADE_TYPE_MELT (1 << 4) #define FADE_TYPE_CURTAIN (1 << 5) #define FADE_TYPE_SKIP (1 << 6) #define FADE_MODE_NONE (FADE_TYPE_NONE) #define FADE_MODE_FADE_IN (FADE_TYPE_FADE_IN) #define FADE_MODE_FADE_OUT (FADE_TYPE_FADE_OUT) #define FADE_MODE_FADE (FADE_TYPE_FADE_IN | FADE_TYPE_FADE_OUT) #define FADE_MODE_TRANSFORM (FADE_TYPE_TRANSFORM | FADE_TYPE_FADE_IN) #define FADE_MODE_CROSSFADE (FADE_MODE_TRANSFORM | FADE_TYPE_CROSSFADE) #define FADE_MODE_MELT (FADE_MODE_TRANSFORM | FADE_TYPE_MELT) #define FADE_MODE_CURTAIN (FADE_MODE_TRANSFORM | FADE_TYPE_CURTAIN) #define FADE_MODE_SKIP_FADE_IN (FADE_TYPE_SKIP | FADE_TYPE_FADE_IN) #define FADE_MODE_SKIP_FADE_OUT (FADE_TYPE_SKIP | FADE_TYPE_FADE_OUT) #define FADE_MODE_DEFAULT FADE_MODE_FADE /* values for toon positions */ #define POS_UNDEFINED -1 #define POS_LEFT 0 #define POS_RIGHT 1 #define POS_TOP 2 #define POS_UPPER 3 #define POS_MIDDLE 4 #define POS_LOWER 5 #define POS_BOTTOM 6 #define POS_ANY 7 #define POS_LAST 8 /* values for text alignment */ #define ALIGN_LEFT (1 << 0) #define ALIGN_RIGHT (1 << 1) #define ALIGN_CENTER (1 << 2) #define ALIGN_DEFAULT ALIGN_LEFT #define VALIGN_TOP (1 << 0) #define VALIGN_BOTTOM (1 << 1) #define VALIGN_MIDDLE (1 << 2) #define VALIGN_DEFAULT VALIGN_TOP #define ALIGNED_XPOS(x,w,a) ((a) == ALIGN_CENTER ? (x) - (w) / 2 : \ (a) == ALIGN_RIGHT ? (x) - (w) : (x)) #define ALIGNED_YPOS(y,h,v) ((v) == VALIGN_MIDDLE ? (y) - (h) / 2 : \ (v) == VALIGN_BOTTOM ? (y) - (h) : (y)) #define ALIGNED_TEXT_XPOS(p) ALIGNED_XPOS((p)->x, (p)->width, (p)->align) #define ALIGNED_TEXT_YPOS(p) ALIGNED_YPOS((p)->y, (p)->height, (p)->valign) /* values for redraw_mask */ #define REDRAW_NONE (0) #define REDRAW_ALL (1 << 0) #define REDRAW_FIELD (1 << 1) #define REDRAW_DOOR_1 (1 << 2) #define REDRAW_DOOR_2 (1 << 3) #define REDRAW_DOOR_3 (1 << 4) #define REDRAW_FPS (1 << 5) #define REDRAW_DOORS (REDRAW_DOOR_1 | \ REDRAW_DOOR_2 | \ REDRAW_DOOR_3) #define IN_GFX_FIELD_PLAY(x, y) (x >= gfx.sx && x < gfx.sx + gfx.sxsize && \ y >= gfx.sy && y < gfx.sy + gfx.sysize) #define IN_GFX_FIELD_FULL(x, y) (x >= gfx.real_sx && \ x < gfx.real_sx + gfx.full_sxsize && \ y >= gfx.real_sy && \ y < gfx.real_sy + gfx.full_sysize) #define IN_GFX_DOOR_1(x, y) (x >= gfx.dx && x < gfx.dx + gfx.dxsize && \ y >= gfx.dy && y < gfx.dy + gfx.dysize) #define IN_GFX_DOOR_2(x, y) (x >= gfx.vx && x < gfx.vx + gfx.vxsize && \ y >= gfx.vy && y < gfx.vy + gfx.vysize) #define IN_GFX_DOOR_3(x, y) (x >= gfx.ex && x < gfx.ex + gfx.exsize && \ y >= gfx.ey && y < gfx.ey + gfx.eysize) /* values for mouse cursor */ #define CURSOR_DEFAULT 0 #define CURSOR_NONE 1 #define CURSOR_PLAYFIELD 2 /* fundamental game speed values */ #define ONE_SECOND_DELAY 1000 /* delay value for one second */ #define MENU_FRAME_DELAY 20 /* frame delay in milliseconds */ #define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */ #define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */ #define FRAMES_PER_SECOND (ONE_SECOND_DELAY / GAME_FRAME_DELAY) #define FRAMES_PER_SECOND_SP 35 /* maximum playfield size supported by libgame functions */ #define MAX_PLAYFIELD_WIDTH 128 #define MAX_PLAYFIELD_HEIGHT 128 /* maximum number of parallel players supported by libgame functions */ #define MAX_PLAYERS 4 /* maximum allowed length of player name */ #define MAX_PLAYER_NAME_LEN 10 /* maximum number of levels in a level set */ #define MAX_LEVELS 1000 /* maximum number of global animation and parts */ #define MAX_GLOBAL_ANIMS 32 #define MAX_GLOBAL_ANIM_PARTS 32 /* default name for empty highscore entry */ #define EMPTY_PLAYER_NAME "no name" /* default name for unknown player names */ #define ANONYMOUS_NAME "anonymous" /* default for other unknown names */ #define UNKNOWN_NAME "unknown" /* default name for new levels */ #define NAMELESS_LEVEL_NAME "nameless level" /* default text for non-existant artwork */ #define NOT_AVAILABLE "(not available)" /* default value for undefined filename */ #define UNDEFINED_FILENAME "[NONE]" /* default value for undefined levelset */ #define UNDEFINED_LEVELSET "[NONE]" /* default value for undefined parameter */ #define ARG_DEFAULT "[DEFAULT]" /* default values for undefined configuration file parameters */ #define ARG_UNDEFINED "-1000000" #define ARG_UNDEFINED_VALUE (-1000000) /* default value for off-screen positions */ #define POS_OFFSCREEN (-1000000) /* definitions for game sub-directories */ #ifndef RO_GAME_DIR #define RO_GAME_DIR "." #endif #ifndef RW_GAME_DIR #define RW_GAME_DIR "." #endif #define RO_BASE_PATH RO_GAME_DIR #define RW_BASE_PATH RW_GAME_DIR /* directory names */ #define GRAPHICS_DIRECTORY "graphics" #define SOUNDS_DIRECTORY "sounds" #define MUSIC_DIRECTORY "music" #define LEVELS_DIRECTORY "levels" #define TAPES_DIRECTORY "tapes" #define SCORES_DIRECTORY "scores" #define DOCS_DIRECTORY "docs" #define CACHE_DIRECTORY "cache" #define CONF_DIRECTORY "conf" #define GFX_CLASSIC_SUBDIR "gfx_classic" #define SND_CLASSIC_SUBDIR "snd_classic" #define MUS_CLASSIC_SUBDIR "mus_classic" #define GFX_DEFAULT_SUBDIR (setup.internal.default_graphics_set) #define SND_DEFAULT_SUBDIR (setup.internal.default_sounds_set) #define MUS_DEFAULT_SUBDIR (setup.internal.default_music_set) #define GFX_FALLBACK_FILENAME (setup.internal.fallback_graphics_file) #define SND_FALLBACK_FILENAME (setup.internal.fallback_sounds_file) #define MUS_FALLBACK_FILENAME (setup.internal.fallback_music_file) #define DEFAULT_LEVELSET (setup.internal.default_level_series) /* file names and filename extensions */ #define LEVELSETUP_DIRECTORY "levelsetup" #define SETUP_FILENAME "setup.conf" #define AUTOSETUP_FILENAME "autosetup.conf" #define LEVELSETUP_FILENAME "levelsetup.conf" #define EDITORSETUP_FILENAME "editorsetup.conf" #define EDITORCASCADE_FILENAME "editorcascade.conf" #define HELPANIM_FILENAME "helpanim.conf" #define HELPTEXT_FILENAME "helptext.conf" #define LEVELINFO_FILENAME "levelinfo.conf" #define GRAPHICSINFO_FILENAME "graphicsinfo.conf" #define SOUNDSINFO_FILENAME "soundsinfo.conf" #define MUSICINFO_FILENAME "musicinfo.conf" #define ARTWORKINFO_CACHE_FILE "artworkinfo.cache" #define LEVELTEMPLATE_FILENAME "template.level" #define LEVELFILE_EXTENSION "level" #define TAPEFILE_EXTENSION "tape" #define SCOREFILE_EXTENSION "score" #define GAMECONTROLLER_BASENAME "gamecontrollerdb.txt" #define LOG_OUT_BASENAME "stdout.txt" #define LOG_ERR_BASENAME "stderr.txt" #define LOG_OUT_ID 0 #define LOG_ERR_ID 1 #define NUM_LOGS 2 #define STRING_PARENT_DIRECTORY ".." #define STRING_TOP_DIRECTORY "/" #define CHAR_PATH_SEPARATOR_UNIX '/' #define CHAR_PATH_SEPARATOR_DOS '\\' #define STRING_PATH_SEPARATOR_UNIX "/" #define STRING_PATH_SEPARATOR_DOS "\\" #define STRING_NEWLINE_UNIX "\n" #define STRING_NEWLINE_DOS "\r\n" #if defined(PLATFORM_WIN32) #define CHAR_PATH_SEPARATOR CHAR_PATH_SEPARATOR_DOS #define STRING_PATH_SEPARATOR STRING_PATH_SEPARATOR_DOS #define STRING_NEWLINE STRING_NEWLINE_DOS #else #define CHAR_PATH_SEPARATOR CHAR_PATH_SEPARATOR_UNIX #define STRING_PATH_SEPARATOR STRING_PATH_SEPARATOR_UNIX #define STRING_NEWLINE STRING_NEWLINE_UNIX #endif /* areas in bitmap 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 */ /* these values are hard-coded to be able to use them in initialization */ #define DOOR_GFX_PAGE_WIDTH 100 /* should be set to "gfx.dxsize" */ #define DOOR_GFX_PAGE_HEIGHT 280 /* should be set to "gfx.dysize" */ #define DOOR_GFX_PAGESIZE (DOOR_GFX_PAGE_WIDTH) #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_PAGEX7 (6 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEX8 (7 * DOOR_GFX_PAGESIZE) #define DOOR_GFX_PAGEY1 (0) #define DOOR_GFX_PAGEY2 (DOOR_GFX_PAGE_HEIGHT) /* macros for version handling */ #define VERSION_MAJOR(x) ((x) / 1000000) #define VERSION_MINOR(x) (((x) % 1000000) / 10000) #define VERSION_PATCH(x) (((x) % 10000) / 100) #define VERSION_BUILD(x) ((x) % 100) #define VERSION_IDENT(a,b,c,d) ((a) * 1000000 + (b) * 10000 + (c) * 100 + (d)) /* macros for parent/child process identification */ #if defined(PLATFORM_UNIX) #define IS_PARENT_PROCESS() (audio.mixer_pid != getpid()) #define IS_CHILD_PROCESS() (audio.mixer_pid == getpid()) #define HAS_CHILD_PROCESS() (audio.mixer_pid > 0) #else #define IS_PARENT_PROCESS() TRUE #define IS_CHILD_PROCESS() FALSE #define HAS_CHILD_PROCESS() FALSE #endif /* values for artwork type */ #define ARTWORK_TYPE_GRAPHICS 0 #define ARTWORK_TYPE_SOUNDS 1 #define ARTWORK_TYPE_MUSIC 2 #define NUM_ARTWORK_TYPES 3 /* values for tree type (chosen to match artwork type) */ #define TREE_TYPE_UNDEFINED -1 #define TREE_TYPE_GRAPHICS_DIR ARTWORK_TYPE_GRAPHICS #define TREE_TYPE_SOUNDS_DIR ARTWORK_TYPE_SOUNDS #define TREE_TYPE_MUSIC_DIR ARTWORK_TYPE_MUSIC #define TREE_TYPE_LEVEL_DIR 3 #define TREE_TYPE_LEVEL_NR 4 #define NUM_TREE_TYPES 5 #define INFOTEXT_UNDEFINED "" #define INFOTEXT_GRAPHICS_DIR "Custom Graphics" #define INFOTEXT_SOUNDS_DIR "Custom Sounds" #define INFOTEXT_MUSIC_DIR "Custom Music" #define INFOTEXT_LEVEL_DIR "Level Sets" #define INFOTEXT_LEVEL_NR "Levels" #define TREE_INFOTEXT(t) ((t) == TREE_TYPE_LEVEL_NR ? \ INFOTEXT_LEVEL_NR : \ (t) == TREE_TYPE_LEVEL_DIR ? \ INFOTEXT_LEVEL_DIR : \ (t) == TREE_TYPE_GRAPHICS_DIR ? \ INFOTEXT_GRAPHICS_DIR : \ (t) == TREE_TYPE_SOUNDS_DIR ? \ INFOTEXT_SOUNDS_DIR : \ (t) == TREE_TYPE_MUSIC_DIR ? \ INFOTEXT_MUSIC_DIR : \ INFOTEXT_UNDEFINED) /* values for artwork handling */ #define LEVELDIR_ARTWORK_SET_PTR(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ &(leveldir)->graphics_set : \ (type) == ARTWORK_TYPE_SOUNDS ? \ &(leveldir)->sounds_set : \ &(leveldir)->music_set) #define LEVELDIR_ARTWORK_SET(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (leveldir)->graphics_set : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (leveldir)->sounds_set : \ (leveldir)->music_set) #define LEVELDIR_ARTWORK_PATH_PTR(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ &(leveldir)->graphics_path : \ (type) == ARTWORK_TYPE_SOUNDS ? \ &(leveldir)->sounds_path : \ &(leveldir)->music_path) #define LEVELDIR_ARTWORK_PATH(leveldir, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (leveldir)->graphics_path : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (leveldir)->sounds_path : \ (leveldir)->music_path) #define SETUP_ARTWORK_SET(setup, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (setup).graphics_set : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (setup).sounds_set : \ (setup).music_set) #define SETUP_OVERRIDE_ARTWORK(setup, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (setup).override_level_graphics : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (setup).override_level_sounds : \ (setup).override_level_music) #define GFX_OVERRIDE_ARTWORK(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ gfx.override_level_graphics : \ (type) == ARTWORK_TYPE_SOUNDS ? \ gfx.override_level_sounds : \ gfx.override_level_music) #define ARTWORK_FIRST_NODE(artwork, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (artwork).gfx_first : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (artwork).snd_first : \ (artwork).mus_first) #define ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ &(artwork).gfx_current_identifier : \ (type) == ARTWORK_TYPE_SOUNDS ? \ &(artwork).snd_current_identifier : \ &(artwork).mus_current_identifier) #define ARTWORK_CURRENT_IDENTIFIER(artwork, type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ (artwork).gfx_current_identifier : \ (type) == ARTWORK_TYPE_SOUNDS ? \ (artwork).snd_current_identifier : \ (artwork).mus_current_identifier) #define ARTWORKINFO_FILENAME(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ GRAPHICSINFO_FILENAME : \ (type) == ARTWORK_TYPE_SOUNDS ? \ SOUNDSINFO_FILENAME : \ (type) == ARTWORK_TYPE_MUSIC ? \ MUSICINFO_FILENAME : "") #define ARTWORK_DIRECTORY(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ GRAPHICS_DIRECTORY : \ (type) == ARTWORK_TYPE_SOUNDS ? \ SOUNDS_DIRECTORY : \ (type) == ARTWORK_TYPE_MUSIC ? \ MUSIC_DIRECTORY : "") #define OPTIONS_ARTWORK_DIRECTORY(type) \ ((type) == ARTWORK_TYPE_GRAPHICS ? \ options.graphics_directory : \ (type) == ARTWORK_TYPE_SOUNDS ? \ options.sounds_directory : \ (type) == ARTWORK_TYPE_MUSIC ? \ options.music_directory : "") #define UPDATE_BUSY_STATE() \ { \ if (gfx.draw_busy_anim_function != NULL) \ gfx.draw_busy_anim_function(); \ } /* structure definitions */ struct ProgramInfo { char *command_basepath; /* path to the program binary */ char *command_basename; /* base filename of the program binary */ char *config_filename; /* optional global program config filename */ char *maindata_path; /* main game data (installation) directory */ char *userdata_subdir; /* personal user game data directory */ char *userdata_path; /* resulting full path to game data directory */ char *program_title; char *window_title; char *icon_title; char *icon_filename; char *cookie_prefix; char *log_filename[NUM_LOGS]; /* log filenames for out/err messages */ FILE *log_file[NUM_LOGS]; /* log file handles for out/err files */ FILE *log_file_default[NUM_LOGS]; /* default log file handles (out/err) */ int version_major; int version_minor; int version_patch; int version_build; int version_ident; char *version_string; char *(*window_title_function)(void); void (*exit_message_function)(char *, va_list); void (*exit_function)(int); boolean global_scores; boolean many_scores_per_name; boolean headless; }; struct OptionInfo { char *server_host; int server_port; char *ro_base_directory; char *rw_base_directory; char *level_directory; char *graphics_directory; char *sounds_directory; char *music_directory; char *docs_directory; char *conf_directory; char *execute_command; char *special_flags; boolean mytapes; boolean serveronly; boolean network; boolean verbose; boolean debug; }; struct VideoSystemInfo { int default_depth; int width, height, depth; int window_width, window_height; int display_width, display_height; int screen_width, screen_height; int screen_xoffset, screen_yoffset; boolean fullscreen_available; boolean fullscreen_enabled; boolean fullscreen_initial; boolean window_scaling_available; int window_scaling_percent; char *window_scaling_quality; int screen_rendering_mode; unsigned int frame_delay; unsigned int frame_delay_value; boolean shifted_up; int shifted_up_pos; int shifted_up_pos_last; unsigned int shifted_up_delay; unsigned int shifted_up_delay_value; boolean initialized; }; struct AudioSystemInfo { boolean sound_available; boolean loops_available; boolean music_available; boolean sound_enabled; boolean sound_deactivated; /* for temporarily disabling sound */ int mixer_pipe[2]; int mixer_pid; char *device_name; int device_fd; int num_channels; int music_channel; int first_sound_channel; }; struct FontBitmapInfo { Bitmap *bitmap; int src_x, src_y; /* start position of font characters */ int width, height; /* width / height of font characters */ int offset_x; /* offset to next font character */ int offset_y; /* offset to next font character */ int draw_xoffset; /* offset for drawing font characters */ int draw_yoffset; /* offset for drawing font characters */ int num_chars; int num_chars_per_line; }; struct GfxInfo { int sx, sy; int sxsize, sysize; int real_sx, real_sy; int full_sxsize, full_sysize; int scrollbuffer_width, scrollbuffer_height; int game_tile_size, standard_tile_size; int dx, dy; int dxsize, dysize; int vx, vy; int vxsize, vysize; int ex, ey; int exsize, eysize; int win_xsize, win_ysize; int draw_deactivation_mask; int draw_background_mask; Bitmap *field_save_buffer; Bitmap *background_bitmap; int background_bitmap_mask; Bitmap *fade_bitmap_backup; Bitmap *fade_bitmap_source; Bitmap *fade_bitmap_target; Bitmap *fade_bitmap_black; int fade_border_source_status; int fade_border_target_status; Bitmap *masked_border_bitmap_ptr; Bitmap *final_screen_bitmap; boolean clipping_enabled; int clip_x, clip_y; int clip_width, clip_height; boolean override_level_graphics; boolean override_level_sounds; boolean override_level_music; boolean draw_init_text; int num_fonts; struct FontBitmapInfo *font_bitmap_info; int (*select_font_function)(int); int (*get_font_from_token_function)(char *); int anim_random_frame; void (*draw_busy_anim_function)(void); void (*draw_global_anim_function)(int, int); void (*draw_global_border_function)(int); void (*draw_tile_cursor_function)(int); int cursor_mode; }; struct TileCursorInfo { boolean enabled; /* tile cursor generally enabled or disabled */ boolean active; /* tile cursor activated (depending on game) */ boolean moving; /* tile cursor moving to target position */ int xpos, ypos; /* tile cursor level playfield position */ int x, y; /* tile cursor current screen position */ int target_x, target_y; /* tile cursor target screen position */ int sx, sy; /* tile cursor screen start position */ }; struct OverlayInfo { boolean enabled; /* overlay generally enabled or disabled */ boolean active; /* overlay activated (depending on game mode) */ }; struct JoystickInfo { int status; int nr[MAX_PLAYERS]; /* joystick number for each player */ }; struct SetupJoystickInfo { char *device_name; /* device name of player's joystick */ int xleft, xmiddle, xright; int yupper, ymiddle, ylower; int snap, drop; }; struct SetupKeyboardInfo { Key left, right, up, down; Key snap, drop; }; struct SetupTouchInfo { char *control_type; int move_distance; int drop_distance; }; struct SetupInputInfo { boolean use_joystick; struct SetupJoystickInfo joy; struct SetupKeyboardInfo key; }; struct SetupEditorInfo { boolean el_boulderdash; boolean el_emerald_mine; boolean el_emerald_mine_club; boolean el_more; boolean el_sokoban; boolean el_supaplex; boolean el_diamond_caves; boolean el_dx_boulderdash; boolean el_mirror_magic; boolean el_deflektor; boolean el_chars; boolean el_steel_chars; boolean el_classic; boolean el_custom; boolean el_user_defined; boolean el_dynamic; boolean el_headlines; boolean el_by_game; boolean el_by_type; boolean show_element_token; boolean use_template_for_new_levels; }; struct SetupAutoSetupInfo { int editor_zoom_tilesize; }; struct SetupEditorCascadeInfo { boolean el_bd; boolean el_em; boolean el_emc; boolean el_rnd; boolean el_sb; boolean el_sp; boolean el_dc; boolean el_dx; boolean el_mm; boolean el_df; boolean el_chars; boolean el_steel_chars; boolean el_ce; boolean el_ge; boolean el_ref; boolean el_user; boolean el_dynamic; }; struct SetupShortcutInfo { Key save_game; Key load_game; Key toggle_pause; Key focus_player[MAX_PLAYERS]; Key focus_player_all; Key tape_eject; Key tape_extra; Key tape_stop; Key tape_pause; Key tape_record; Key tape_play; Key sound_simple; Key sound_loops; Key sound_music; Key snap_left; Key snap_right; Key snap_up; Key snap_down; }; struct SetupSystemInfo { char *sdl_videodriver; char *sdl_audiodriver; int audio_fragment_size; }; struct SetupInternalInfo { char *program_title; char *program_version; char *program_author; char *program_email; char *program_website; char *program_copyright; char *program_company; char *program_icon_file; char *default_graphics_set; char *default_sounds_set; char *default_music_set; char *fallback_graphics_file; char *fallback_sounds_file; char *fallback_music_file; char *default_level_series; int default_window_width; int default_window_height; boolean choose_from_top_leveldir; boolean show_scaling_in_title; }; struct SetupDebugInfo { int frame_delay[10]; Key frame_delay_key[10]; boolean frame_delay_use_mod_key; boolean frame_delay_game_only; boolean show_frames_per_second; }; struct SetupInfo { char *player_name; boolean sound; boolean sound_loops; boolean sound_music; boolean sound_simple; boolean toons; boolean scroll_delay; boolean scroll_delay_value; char *engine_snapshot_mode; int engine_snapshot_memory; boolean fade_screens; boolean autorecord; boolean show_titlescreen; boolean quick_doors; boolean team_mode; boolean handicap; boolean skip_levels; boolean increment_levels; boolean time_limit; boolean fullscreen; int window_scaling_percent; char *window_scaling_quality; char *screen_rendering_mode; boolean ask_on_escape; boolean ask_on_escape_editor; boolean quick_switch; boolean input_on_focus; boolean prefer_aga_graphics; int game_frame_delay; boolean sp_show_border_elements; boolean small_game_graphics; boolean show_snapshot_buttons; char *graphics_set; char *sounds_set; char *music_set; int override_level_graphics; /* not boolean -- can also be "AUTO" */ int override_level_sounds; /* not boolean -- can also be "AUTO" */ int override_level_music; /* not boolean -- can also be "AUTO" */ int volume_simple; int volume_loops; int volume_music; struct SetupAutoSetupInfo auto_setup; struct SetupEditorInfo editor; struct SetupEditorCascadeInfo editor_cascade; struct SetupShortcutInfo shortcut; struct SetupInputInfo input[MAX_PLAYERS]; struct SetupTouchInfo touch; struct SetupSystemInfo system; struct SetupInternalInfo internal; struct SetupDebugInfo debug; struct OptionInfo options; }; struct TreeInfo { struct TreeInfo **node_top; /* topmost node in tree */ struct TreeInfo *node_parent; /* parent level directory info */ struct TreeInfo *node_group; /* level group sub-directory info */ struct TreeInfo *next; /* next level series structure node */ int cl_first; /* internal control field for setup screen */ int cl_cursor; /* internal control field for setup screen */ int type; /* type of tree content */ /* fields for "type == TREE_TYPE_LEVEL_DIR" */ char *subdir; /* tree info sub-directory basename (may be ".") */ char *fullpath; /* complete path relative to tree base directory */ char *basepath; /* absolute base path of tree base directory */ char *identifier; /* identifier string for configuration files */ char *name; /* tree info name, as displayed in selection menues */ char *name_sorting; /* optional sorting name for correct name sorting */ char *author; /* level or artwork author name */ char *year; /* optional year of creation for levels or artwork */ char *program_title; /* optional alternative text for program title */ char *program_copyright; /* optional alternative text for program copyright */ char *program_company; /* optional alternative text for program company */ char *imported_from; /* optional comment for imported levels or artwork */ char *imported_by; /* optional comment for imported levels or artwork */ char *tested_by; /* optional comment to name people who tested a set */ char *graphics_set_ecs; /* special EMC custom graphics set (ECS graphics) */ char *graphics_set_aga; /* special EMC custom graphics set (AGA graphics) */ char *graphics_set; /* optional custom graphics set (level tree only) */ char *sounds_set; /* optional custom sounds set (level tree only) */ char *music_set; /* optional custom music set (level tree only) */ char *graphics_path; /* path to optional custom graphics set (level only) */ char *sounds_path; /* path to optional custom sounds set (level only) */ char *music_path; /* path to optional custom music set (level only) */ char *level_filename; /* filename of level file (for packed level file) */ char *level_filetype; /* type of levels in level directory or level file */ char *special_flags; /* flags for special actions performed on level file */ int levels; /* number of levels in level series */ int first_level; /* first level number (to allow start with 0 or 1) */ int last_level; /* last level number (automatically calculated) */ int sort_priority; /* sort levels by 'sort_priority' and then by name */ boolean latest_engine;/* force level set to use the latest game engine */ boolean level_group; /* directory contains more level series directories */ boolean parent_link; /* entry links back to parent directory */ boolean in_user_dir; /* user defined levels are stored in home directory */ boolean user_defined; /* levels in user directory and marked as "private" */ boolean readonly; /* readonly levels can not be changed with editor */ boolean handicap; /* level set has no handicap when set to "false" */ boolean skip_levels; /* levels can be skipped when set to "true" */ int color; /* color to use on selection screen for this level */ char *class_desc; /* description of level series class */ int handicap_level; /* number of the lowest unsolved level */ char *infotext; /* optional text to describe the tree type (headline) */ }; typedef struct TreeInfo TreeInfo; typedef struct TreeInfo LevelDirTree; typedef struct TreeInfo ArtworkDirTree; typedef struct TreeInfo GraphicsDirTree; typedef struct TreeInfo SoundsDirTree; typedef struct TreeInfo MusicDirTree; struct ArtworkInfo { GraphicsDirTree *gfx_first; GraphicsDirTree *gfx_current; SoundsDirTree *snd_first; SoundsDirTree *snd_current; MusicDirTree *mus_first; MusicDirTree *mus_current; char *gfx_current_identifier; char *snd_current_identifier; char *mus_current_identifier; }; struct ValueTextInfo { int value; char *text; }; struct ConfigInfo { char *token; char *value; }; struct ConfigTypeInfo { char *token; char *value; int type; }; struct TokenIntPtrInfo { char *token; int *value; }; struct FileInfo { char *token; char *default_filename; char *filename; char **default_parameter; /* array of file parameters */ char **parameter; /* array of file parameters */ boolean redefined; boolean fallback_to_default; boolean default_is_cloned; }; struct SetupFileList { char *token; char *value; struct SetupFileList *next; }; struct ListNodeInfo { char *source_filename; /* primary key for node list */ int num_references; }; struct PropertyMapping { int base_index; int ext1_index; int ext2_index; int ext3_index; int artwork_index; }; struct ArtworkListInfo { int type; /* type of artwork */ int num_file_list_entries; int num_dynamic_file_list_entries; struct FileInfo *file_list; /* static artwork file array */ struct FileInfo *dynamic_file_list; /* dynamic artwrk file array */ int num_suffix_list_entries; struct ConfigTypeInfo *suffix_list; /* parameter suffixes array */ int num_base_prefixes; int num_ext1_suffixes; int num_ext2_suffixes; int num_ext3_suffixes; char **base_prefixes; /* base token prefixes array */ char **ext1_suffixes; /* property suffixes array 1 */ char **ext2_suffixes; /* property suffixes array 2 */ char **ext3_suffixes; /* property suffixes array 3 */ int num_ignore_tokens; char **ignore_tokens; /* file tokens to be ignored */ int num_property_mapping_entries; struct PropertyMapping *property_mapping; /* mapping token -> artwork */ int sizeof_artwork_list_entry; struct ListNodeInfo **artwork_list; /* static artwork node array */ struct ListNodeInfo **dynamic_artwork_list; /* dynamic artwrk node array */ struct ListNode *content_list; /* dynamic artwork node list */ void *(*load_artwork)(char *); /* constructor function */ void (*free_artwork)(void *); /* destructor function */ }; struct XY { int x, y; }; struct XYTileSize { int x, y; int tile_size; }; struct Rect { int x, y; int width, height; }; struct RectWithBorder { int x, y; int width, height; int border_size; }; struct MenuPosInfo { int x, y; int width, height; int align, valign; }; struct DoorPartPosInfo { int x, y; int step_xoffset; int step_yoffset; int step_delay; int start_step; int start_step_opening; int start_step_closing; boolean draw_masked; int sort_priority; }; struct TextPosInfo { int x, y; int xoffset; /* special case for tape date and time */ int xoffset2; /* special case for tape date */ int width, height; int align, valign; int size; /* also used for suffix ".digits" */ int font, font_alt; boolean draw_masked; boolean draw_player; /* special case for network player buttons */ int sort_priority; /* also used for suffix ".draw_order" */ int id; int direction; /* needed for panel time/health graphics */ int class; /* needed for panel time/health graphics */ int style; /* needed for panel time/health graphics */ }; struct MouseActionInfo { int lx, ly; int button; int button_hint; }; struct LevelStats { int played; int solved; }; /* ========================================================================= */ /* exported variables */ /* ========================================================================= */ extern struct ProgramInfo program; extern struct OptionInfo options; extern struct VideoSystemInfo video; extern struct AudioSystemInfo audio; extern struct GfxInfo gfx; extern struct TileCursorInfo tile_cursor; extern struct OverlayInfo overlay; extern struct AnimInfo anim; extern struct ArtworkInfo artwork; extern struct JoystickInfo joystick; extern struct SetupInfo setup; extern LevelDirTree *leveldir_first_all; extern LevelDirTree *leveldir_first; extern LevelDirTree *leveldir_current; extern int level_nr; extern struct LevelStats level_stats[]; extern DrawWindow *window; extern DrawBuffer *backbuffer; extern DrawBuffer *drawto; extern int button_status; extern boolean motion_status; extern int wheel_steps; #if defined(TARGET_SDL2) extern boolean keyrepeat_status; #endif extern int redraw_mask; extern int FrameCounter; /* function definitions */ void InitProgramInfo(char *, char *, char *, char *, char *, char *, char *, char *, int); void InitScoresInfo(); void SetWindowTitle(); void InitWindowTitleFunction(char *(*window_title_function)(void)); void InitExitMessageFunction(void (*exit_message_function)(char *, va_list)); void InitExitFunction(void (*exit_function)(int)); void InitPlatformDependentStuff(void); void ClosePlatformDependentStuff(void); void InitGfxFieldInfo(int, int, int, int, int, int, int, int, Bitmap *); void InitGfxTileSizeInfo(int, int); void InitGfxDoor1Info(int, int, int, int); void InitGfxDoor2Info(int, int, int, int); void InitGfxDoor3Info(int, int, int, int); void InitGfxWindowInfo(int, int); void InitGfxScrollbufferInfo(int, int); void InitGfxClipRegion(boolean, int, int, int, int); void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void)); void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int)); void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int)); void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int)); void InitGfxCustomArtworkInfo(); void InitGfxOtherSettings(); void InitTileCursorInfo(); void InitOverlayInfo(); void SetTileCursorEnabled(boolean); void SetTileCursorActive(boolean); void SetTileCursorTargetXY(int, int); void SetTileCursorXY(int, int); void SetTileCursorSXSY(int, int); void SetOverlayEnabled(boolean); void SetOverlayActive(boolean); boolean GetOverlayActive(); void SetDrawDeactivationMask(int); int GetDrawDeactivationMask(void); void SetDrawBackgroundMask(int); void SetWindowBackgroundBitmap(Bitmap *); void SetMainBackgroundBitmap(Bitmap *); void SetDoorBackgroundBitmap(Bitmap *); void SetRedrawMaskFromArea(int, int, int, int); void LimitScreenUpdates(boolean); void InitVideoDefaults(void); void InitVideoDisplay(void); void CloseVideoDisplay(void); void InitVideoBuffer(int, int, int, boolean); Bitmap *CreateBitmapStruct(void); Bitmap *CreateBitmap(int, int, int); void ReCreateBitmap(Bitmap **, int, int); void FreeBitmap(Bitmap *); void BlitBitmap(Bitmap *, Bitmap *, int, int, int, int, int, int); void BlitBitmapTiled(Bitmap *, Bitmap *, int, int, int, int, int, int, int,int); void FadeRectangle(int, int, int, int, int, int, int, void (*draw_border_function)(void)); void FillRectangle(Bitmap *, int, int, int, int, Pixel); void ClearRectangle(Bitmap *, int, int, int, int); void ClearRectangleOnBackground(Bitmap *, int, int, int, int); void BlitBitmapMasked(Bitmap *, Bitmap *, int, int, int, int, int, int); boolean DrawingDeactivatedField(void); boolean DrawingDeactivated(int, int, int, int); boolean DrawingOnBackground(int, int); boolean DrawingAreaChanged(); void BlitBitmapOnBackground(Bitmap *, Bitmap *, int, int, int, int, int, int); void BlitTexture(Bitmap *, int, int, int, int, int, int); void BlitTextureMasked(Bitmap *, int, int, int, int, int, int); void BlitToScreen(Bitmap *, int, int, int, int, int, int); void BlitToScreenMasked(Bitmap *, int, int, int, int, int, int); void DrawSimpleBlackLine(Bitmap *, int, int, int, int); void DrawSimpleWhiteLine(Bitmap *, int, int, int, int); void DrawLines(Bitmap *, struct XY *, int, Pixel); Pixel GetPixel(Bitmap *, int, int); Pixel GetPixelFromRGB(Bitmap *, unsigned int,unsigned int,unsigned int); Pixel GetPixelFromRGBcompact(Bitmap *, unsigned int); void KeyboardAutoRepeatOn(void); void KeyboardAutoRepeatOff(void); boolean SetVideoMode(boolean); void SetVideoFrameDelay(unsigned int); unsigned int GetVideoFrameDelay(); boolean ChangeVideoModeIfNeeded(boolean); Bitmap *LoadImage(char *); Bitmap *LoadCustomImage(char *); void ReloadCustomImage(Bitmap *, char *); void ReCreateGameTileSizeBitmap(Bitmap **); void CreateBitmapWithSmallBitmaps(Bitmap **, int, int); void CreateBitmapTextures(Bitmap **); void FreeBitmapTextures(Bitmap **); void ScaleBitmap(Bitmap **, int); void SetMouseCursor(int); void OpenAudio(void); void CloseAudio(void); void SetAudioMode(boolean); boolean PendingEvent(void); void WaitEvent(Event *event); void PeekEvent(Event *event); void CheckQuitEvent(void); Key GetEventKey(KeyEvent *, boolean); KeyMod HandleKeyModState(Key, int); KeyMod GetKeyModState(); KeyMod GetKeyModStateFromEvents(); void StartTextInput(int, int, int, int); void StopTextInput(); boolean CheckCloseWindowEvent(ClientMessageEvent *); void InitJoysticks(); boolean ReadJoystick(int, int *, int *, boolean *, boolean *); boolean CheckJoystickOpened(int); void ClearJoystickState(); #endif /* SYSTEM_H */ mirrormagic-3.0.0/src/libgame/snapshot.c0000644000175000017500000001362013263212010017515 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // snapshot.c // ============================================================================ #include "snapshot.h" #ifdef DEBUG #define DEBUG_SNAPSHOTS 0 #endif static ListNode *snapshot_single = NULL; static ListNode *snapshot_list = NULL; static ListNode *snapshot_current = NULL; static int num_snapshots = 0; static int num_snapshot_buffers = 0; static int num_snapshot_bytes = 0; static int next_snapshot_key = 0; // ----------------------------------------------------------------------------- // functions for handling buffers for a single snapshot // ----------------------------------------------------------------------------- void SaveSnapshotBuffer(ListNode **snapshot_buffers, void *buffer, int size) { struct SnapshotNodeInfo *bi = checked_calloc(sizeof(struct SnapshotNodeInfo)); bi->buffer_orig = buffer; bi->buffer_copy = checked_malloc(size); bi->size = size; memcpy(bi->buffer_copy, buffer, size); addNodeToList(snapshot_buffers, NULL, bi); num_snapshot_buffers++; num_snapshot_bytes += size; } static void LoadSnapshotBuffer(struct SnapshotNodeInfo *bi) { memcpy(bi->buffer_orig, bi->buffer_copy, bi->size); } void LoadSnapshotBuffers(ListNode *snapshot_buffers) { while (snapshot_buffers != NULL) { LoadSnapshotBuffer((struct SnapshotNodeInfo *)snapshot_buffers->content); snapshot_buffers = snapshot_buffers->next; } } static void FreeSnapshotBuffer(void *bi_raw) { struct SnapshotNodeInfo *bi = (struct SnapshotNodeInfo *)bi_raw; num_snapshot_buffers--; num_snapshot_bytes -= bi->size; checked_free(bi->buffer_copy); checked_free(bi); } void FreeSnapshotBuffers(ListNode *snapshot_buffers) { while (snapshot_buffers != NULL) deleteNodeFromList(&snapshot_buffers, NULL, FreeSnapshotBuffer); } // ----------------------------------------------------------------------------- // functions for handling single shapshot or list of snapshots // ----------------------------------------------------------------------------- static void FreeSnapshot(void *snapshot_buffers_ptr) { FreeSnapshotBuffers(snapshot_buffers_ptr); } void FreeSnapshotSingle() { FreeSnapshotBuffers(snapshot_single); snapshot_single = NULL; } static void FreeSnapshotList_UpToNode(ListNode *node) { while (snapshot_list != node) { #if DEBUG_SNAPSHOTS printf("::: FreeSnapshotList_*() [%s, %d, %d]\n", snapshot_list->key, num_snapshot_buffers, num_snapshot_bytes); #endif deleteNodeFromList(&snapshot_list, snapshot_list->key, FreeSnapshot); num_snapshots--; next_snapshot_key = (snapshot_list ? atoi(snapshot_list->key) + 1 : 0); } } void FreeSnapshotList() { #if DEBUG_SNAPSHOTS printf("::: FreeSnapshotList()\n"); #endif FreeSnapshotList_UpToNode(NULL); num_snapshots = 0; num_snapshot_buffers = 0; num_snapshot_bytes = 0; next_snapshot_key = 0; snapshot_current = NULL; } void ReduceSnapshotList() { #if DEBUG_SNAPSHOTS printf("::: (Reducing number of snapshots from %d ", num_snapshots); #endif // maximum number of snapshots exceeded -- thin out list of snapshots ListNode *node = snapshot_list; int num_snapshots_to_skip = num_snapshots / 10; // do not remove the newest snapshots from the list while (node && num_snapshots_to_skip--) node = node->next; // remove every second snapshot from the remaining list while (node) { // never delete the first list node (snapshot at game start) if (node->next == NULL) break; // in alternation, delete one node from the list ... deleteNodeFromList(&node, node->key, FreeSnapshot); num_snapshots--; // ... and keep one node (which always exists here) node = node->next; } #if DEBUG_SNAPSHOTS printf("to %d.)\n", num_snapshots); #if 0 node = snapshot_list; while (node) { printf("::: key: %s\n", node->key); node = node->next; } #endif #endif } void SaveSnapshotSingle(ListNode *snapshot_buffers) { if (snapshot_single) FreeSnapshotSingle(); snapshot_single = snapshot_buffers; } void SaveSnapshotToList(ListNode *snapshot_buffers) { if (snapshot_current != snapshot_list) FreeSnapshotList_UpToNode(snapshot_current); #if DEBUG_SNAPSHOTS printf("::: SaveSnapshotToList() [%d] [%d snapshots, %d buffers, %d bytes]\n", next_snapshot_key, num_snapshots, num_snapshot_buffers, num_snapshot_bytes); #endif addNodeToList(&snapshot_list, i_to_a(next_snapshot_key), snapshot_buffers); snapshot_current = snapshot_list; num_snapshots++; next_snapshot_key++; if (num_snapshot_bytes > setup.engine_snapshot_memory) ReduceSnapshotList(); } boolean LoadSnapshotSingle() { if (snapshot_single) { LoadSnapshotBuffers(snapshot_single); return TRUE; } return FALSE; } boolean LoadSnapshotFromList_Older(int steps) { if (snapshot_current && snapshot_current->next) { while (snapshot_current->next && steps--) snapshot_current = snapshot_current->next; LoadSnapshotBuffers(snapshot_current->content); #if DEBUG_SNAPSHOTS printf("::: LoadSnapshotFromList_Older() [%s]\n", snapshot_current->key); #endif return TRUE; } return FALSE; } boolean LoadSnapshotFromList_Newer(int steps) { if (snapshot_current && snapshot_current->prev) { while (snapshot_current->prev && steps--) snapshot_current = snapshot_current->prev; LoadSnapshotBuffers(snapshot_current->content); #if DEBUG_SNAPSHOTS printf("::: LoadSnapshotFromList_Newer() [%s]\n", snapshot_current->key); #endif return TRUE; } return FALSE; } boolean CheckSnapshotList() { return (snapshot_list ? TRUE : FALSE); } mirrormagic-3.0.0/src/libgame/windows.h0000644000175000017500000000220513263212010017352 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // windows.h // ============================================================================ #ifndef WINDOWS_H #define WINDOWS_H /* prevent including lots of conflicting macros */ #define WIN32_LEAN_AND_MEAN #include /* some symbols are already defined on Windows */ typedef int boolean_internal; #define boolean boolean_internal #define CreateBitmap CreateBitmap_internal #define GetPixel GetPixel_internal #define CloseWindow CloseWindow_internal #define FloodFill FloodFill_internal #ifdef LoadImage #undef LoadImage #define LoadImage LoadImage_internal #endif #ifdef PlaySound #undef PlaySound #define PlaySound PlaySound_internal #endif #ifdef DrawText #undef DrawText #define DrawText DrawText_internal #endif #endif /* WINDOWS_H */ mirrormagic-3.0.0/src/libgame/libgame.h0000644000175000017500000000146613263212010017270 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // libgame.h // ============================================================================ #ifndef LIBGAME_H #define LIBGAME_H #define LIBGAME_VERSION_1_0_0 #include "platform.h" #include "types.h" #include "system.h" #include "random.h" #include "gadgets.h" #include "text.h" #include "sound.h" #include "snapshot.h" #include "joystick.h" #include "image.h" #include "setup.h" #include "misc.h" #endif /* LIBGAME_H */ mirrormagic-3.0.0/src/libgame/sdl.c0000644000175000017500000023036613263212010016450 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // sdl.c // ============================================================================ #include "system.h" #include "sound.h" #include "joystick.h" #include "misc.h" #include "setup.h" #define ENABLE_UNUSED_CODE 0 /* currently unused functions */ #define DEBUG_JOYSTICKS 0 /* ========================================================================= */ /* video functions */ /* ========================================================================= */ /* SDL internal variables */ #if defined(TARGET_SDL2) static SDL_Window *sdl_window = NULL; static SDL_Renderer *sdl_renderer = NULL; static SDL_Texture *sdl_texture_stream = NULL; static SDL_Texture *sdl_texture_target = NULL; static boolean fullscreen_enabled = FALSE; #endif static boolean limit_screen_updates = FALSE; /* functions from SGE library */ void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32); #if defined(USE_TOUCH_INPUT_OVERLAY) /* functions to draw overlay graphics for touch device input */ static void DrawTouchInputOverlay(); #endif void SDLLimitScreenUpdates(boolean enable) { limit_screen_updates = enable; } static void FinalizeScreen(int draw_target) { // copy global animations to render target buffer, if defined (below border) if (gfx.draw_global_anim_function != NULL) gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_1); // copy global masked border to render target buffer, if defined if (gfx.draw_global_border_function != NULL) gfx.draw_global_border_function(draw_target); // copy global animations to render target buffer, if defined (above border) if (gfx.draw_global_anim_function != NULL) gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2); // copy tile selection cursor to render target buffer, if defined (above all) if (gfx.draw_tile_cursor_function != NULL) gfx.draw_tile_cursor_function(draw_target); } static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay) { static unsigned int update_screen_delay = 0; unsigned int update_screen_delay_value = 50; /* (milliseconds) */ SDL_Surface *screen = backbuffer->surface; if (limit_screen_updates && !DelayReached(&update_screen_delay, update_screen_delay_value)) return; LimitScreenUpdates(FALSE); #if 0 { static int LastFrameCounter = 0; boolean changed = (FrameCounter != LastFrameCounter); printf("::: FrameCounter == %d [%s]\n", FrameCounter, (changed ? "-" : "SAME FRAME UPDATED")); LastFrameCounter = FrameCounter; /* if (FrameCounter % 2) return; */ } #endif if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP && gfx.final_screen_bitmap != NULL) // may not be initialized yet { // draw global animations using bitmaps instead of using textures // to prevent texture scaling artefacts (this is potentially slower) BlitBitmap(backbuffer, gfx.final_screen_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0); FinalizeScreen(DRAW_TO_SCREEN); screen = gfx.final_screen_bitmap->surface; // force full window redraw rect = NULL; } #if defined(TARGET_SDL2) SDL_Texture *sdl_texture = sdl_texture_stream; // deactivate use of target texture if render targets are not supported if ((video.screen_rendering_mode == SPECIAL_RENDERING_TARGET || video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) && sdl_texture_target == NULL) video.screen_rendering_mode = SPECIAL_RENDERING_OFF; if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET) sdl_texture = sdl_texture_target; if (rect) { int bytes_x = screen->pitch / video.width; int bytes_y = screen->pitch; SDL_UpdateTexture(sdl_texture, rect, screen->pixels + rect->x * bytes_x + rect->y * bytes_y, screen->pitch); } else { SDL_UpdateTexture(sdl_texture, NULL, screen->pixels, screen->pitch); } int xoff = video.screen_xoffset; int yoff = video.screen_yoffset; SDL_Rect dst_rect_screen = { xoff, yoff, video.width, video.height }; SDL_Rect *src_rect1 = NULL, *dst_rect1 = NULL; SDL_Rect *src_rect2 = NULL, *dst_rect2 = NULL; if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET || video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) dst_rect2 = &dst_rect_screen; else dst_rect1 = &dst_rect_screen; #if defined(HAS_SCREEN_KEYBOARD) if (video.shifted_up || video.shifted_up_delay) { int time_current = SDL_GetTicks(); int pos = video.shifted_up_pos; int pos_last = video.shifted_up_pos_last; if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value, time_current)) { int delay = time_current - video.shifted_up_delay; int delay_value = video.shifted_up_delay_value; pos = pos_last + (pos - pos_last) * delay / delay_value; } else { video.shifted_up_pos_last = pos; video.shifted_up_delay = 0; } SDL_Rect src_rect_up = { 0, pos, video.width, video.height - pos }; SDL_Rect dst_rect_up = { xoff, yoff, video.width, video.height - pos }; if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET || video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) { src_rect2 = &src_rect_up; dst_rect2 = &dst_rect_up; } else { src_rect1 = &src_rect_up; dst_rect1 = &dst_rect_up; } } #endif // clear render target buffer SDL_RenderClear(sdl_renderer); // set renderer to use target texture for rendering if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET || video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) SDL_SetRenderTarget(sdl_renderer, sdl_texture_target); // copy backbuffer texture to render target buffer if (video.screen_rendering_mode != SPECIAL_RENDERING_TARGET) SDL_RenderCopy(sdl_renderer, sdl_texture_stream, src_rect1, dst_rect1); if (video.screen_rendering_mode != SPECIAL_RENDERING_BITMAP) FinalizeScreen(DRAW_TO_SCREEN); // when using target texture, copy it to screen buffer if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET || video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE) { SDL_SetRenderTarget(sdl_renderer, NULL); SDL_RenderCopy(sdl_renderer, sdl_texture_target, src_rect2, dst_rect2); } #if defined(USE_TOUCH_INPUT_OVERLAY) // draw overlay graphics for touch device input, if needed DrawTouchInputOverlay(); #endif #endif // global synchronization point of the game to align video frame delay if (with_frame_delay) WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value); #if defined(TARGET_SDL2) // show render target buffer on screen SDL_RenderPresent(sdl_renderer); #else // TARGET_SDL if (rect) SDL_UpdateRects(screen, 1, rect); else SDL_UpdateRect(screen, 0, 0, 0, 0); #endif } static void UpdateScreen_WithFrameDelay(SDL_Rect *rect) { UpdateScreenExt(rect, TRUE); } static void UpdateScreen_WithoutFrameDelay(SDL_Rect *rect) { UpdateScreenExt(rect, FALSE); } static void SDLSetWindowIcon(char *basename) { /* (setting the window icon on Mac OS X would replace the high-quality dock icon with the currently smaller (and uglier) icon from file) */ #if !defined(PLATFORM_MACOSX) char *filename = getCustomImageFilename(basename); SDL_Surface *surface; if (filename == NULL) { Error(ERR_WARN, "SDLSetWindowIcon(): cannot find file '%s'", basename); return; } if ((surface = IMG_Load(filename)) == NULL) { Error(ERR_WARN, "IMG_Load() failed: %s", SDL_GetError()); return; } /* set transparent color */ SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL, SDL_MapRGB(surface->format, 0x00, 0x00, 0x00)); #if defined(TARGET_SDL2) SDL_SetWindowIcon(sdl_window, surface); #else SDL_WM_SetIcon(surface, NULL); #endif #endif } #if defined(TARGET_SDL2) static boolean equalSDLPixelFormat(SDL_PixelFormat *format1, SDL_PixelFormat *format2) { return (format1->format == format2->format && format1->BitsPerPixel == format2->BitsPerPixel && format1->BytesPerPixel == format2->BytesPerPixel && format1->Rmask == format2->Rmask && format1->Gmask == format2->Gmask && format1->Bmask == format2->Bmask); } static Pixel SDLGetColorKey(SDL_Surface *surface) { Pixel color_key; if (SDL_GetColorKey(surface, &color_key) != 0) return -1; return color_key; } static boolean SDLHasColorKey(SDL_Surface *surface) { return (SDLGetColorKey(surface) != -1); } static boolean SDLHasAlpha(SDL_Surface *surface) { SDL_BlendMode blend_mode; if (SDL_GetSurfaceBlendMode(surface, &blend_mode) != 0) return FALSE; return (blend_mode == SDL_BLENDMODE_BLEND); } static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha) { SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE); SDL_SetSurfaceBlendMode(surface, blend_mode); SDL_SetSurfaceAlphaMod(surface, alpha); } SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface) { SDL_PixelFormat format; SDL_Surface *new_surface; if (surface == NULL) return NULL; if (backbuffer && backbuffer->surface) { format = *backbuffer->surface->format; format.Amask = surface->format->Amask; // keep alpha channel } else { format = *surface->format; } new_surface = SDL_ConvertSurface(surface, &format, 0); if (new_surface == NULL) Error(ERR_EXIT, "SDL_ConvertSurface() failed: %s", SDL_GetError()); return new_surface; } boolean SDLSetNativeSurface(SDL_Surface **surface) { SDL_Surface *new_surface; if (surface == NULL || *surface == NULL || backbuffer == NULL || backbuffer->surface == NULL) return FALSE; // if pixel format already optimized for destination surface, do nothing if (equalSDLPixelFormat((*surface)->format, backbuffer->surface->format)) return FALSE; new_surface = SDLGetNativeSurface(*surface); SDL_FreeSurface(*surface); *surface = new_surface; return TRUE; } #else static Pixel SDLGetColorKey(SDL_Surface *surface) { if ((surface->flags & SDL_SRCCOLORKEY) == 0) return -1; return surface->format->colorkey; } static boolean SDLHasColorKey(SDL_Surface *surface) { return (SDLGetColorKey(surface) != -1); } static boolean SDLHasAlpha(SDL_Surface *surface) { return ((surface->flags & SDL_SRCALPHA) != 0); } static void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha) { SDL_SetAlpha(surface, (set ? SDL_SRCALPHA : 0), alpha); } SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface) { SDL_Surface *new_surface; if (surface == NULL) return NULL; if (!video.initialized) new_surface = SDL_ConvertSurface(surface, surface->format, SURFACE_FLAGS); else if (SDLHasAlpha(surface)) new_surface = SDL_DisplayFormatAlpha(surface); else new_surface = SDL_DisplayFormat(surface); if (new_surface == NULL) Error(ERR_EXIT, "%s() failed: %s", (video.initialized ? "SDL_DisplayFormat" : "SDL_ConvertSurface"), SDL_GetError()); return new_surface; } boolean SDLSetNativeSurface(SDL_Surface **surface) { SDL_Surface *new_surface; if (surface == NULL || *surface == NULL || !video.initialized) return FALSE; new_surface = SDLGetNativeSurface(*surface); SDL_FreeSurface(*surface); *surface = new_surface; return TRUE; } #endif #if defined(TARGET_SDL2) static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface) { if (program.headless) return NULL; SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_renderer, surface); if (texture == NULL) Error(ERR_EXIT, "SDL_CreateTextureFromSurface() failed: %s", SDL_GetError()); return texture; } #endif void SDLCreateBitmapTextures(Bitmap *bitmap) { #if defined(TARGET_SDL2) if (bitmap == NULL) return; if (bitmap->texture) SDL_DestroyTexture(bitmap->texture); if (bitmap->texture_masked) SDL_DestroyTexture(bitmap->texture_masked); bitmap->texture = SDLCreateTextureFromSurface(bitmap->surface); bitmap->texture_masked = SDLCreateTextureFromSurface(bitmap->surface_masked); #endif } void SDLFreeBitmapTextures(Bitmap *bitmap) { #if defined(TARGET_SDL2) if (bitmap == NULL) return; if (bitmap->texture) SDL_DestroyTexture(bitmap->texture); if (bitmap->texture_masked) SDL_DestroyTexture(bitmap->texture_masked); bitmap->texture = NULL; bitmap->texture_masked = NULL; #endif } void SDLInitVideoDisplay(void) { #if !defined(TARGET_SDL2) if (!strEqual(setup.system.sdl_videodriver, ARG_DEFAULT)) SDL_putenv(getStringCat2("SDL_VIDEODRIVER=", setup.system.sdl_videodriver)); SDL_putenv("SDL_VIDEO_CENTERED=1"); #endif /* initialize SDL video */ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError()); /* set default SDL depth */ #if !defined(TARGET_SDL2) video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel; #else video.default_depth = 32; // (how to determine video depth in SDL2?) #endif } inline static void SDLInitVideoBuffer_VideoBuffer(boolean fullscreen) { if (program.headless) return; video.window_scaling_percent = setup.window_scaling_percent; video.window_scaling_quality = setup.window_scaling_quality; SDLSetScreenRenderingMode(setup.screen_rendering_mode); #if defined(TARGET_SDL2) // SDL 2.0: support for (desktop) fullscreen mode available video.fullscreen_available = TRUE; #else // SDL 1.2: no support for fullscreen mode in R'n'D anymore video.fullscreen_available = FALSE; #endif /* open SDL video output device (window or fullscreen mode) */ if (!SDLSetVideoMode(fullscreen)) Error(ERR_EXIT, "setting video mode failed"); /* !!! SDL2 can only set the window icon if the window already exists !!! */ /* set window icon */ SDLSetWindowIcon(program.icon_filename); /* set window and icon title */ SDLSetWindowTitle(); } inline static void SDLInitVideoBuffer_DrawBuffer() { /* SDL cannot directly draw to the visible video framebuffer like X11, but always uses a backbuffer, which is then blitted to the visible video framebuffer with 'SDL_UpdateRect' (or replaced with the current visible video framebuffer with 'SDL_Flip', if the hardware supports this). Therefore do not use an additional backbuffer for drawing, but use a symbolic buffer (distinguishable from the SDL backbuffer) called 'window', which indicates that the SDL backbuffer should be updated to the visible video framebuffer when attempting to blit to it. For convenience, it seems to be a good idea to create this symbolic buffer 'window' at the same size as the SDL backbuffer. Although it should never be drawn to directly, it would do no harm nevertheless. */ /* create additional (symbolic) buffer for double-buffering */ ReCreateBitmap(&window, video.width, video.height); /* create dummy drawing buffer for headless mode, if needed */ if (program.headless) ReCreateBitmap(&backbuffer, video.width, video.height); } void SDLInitVideoBuffer(boolean fullscreen) { SDLInitVideoBuffer_VideoBuffer(fullscreen); SDLInitVideoBuffer_DrawBuffer(); } static boolean SDLCreateScreen(boolean fullscreen) { SDL_Surface *new_surface = NULL; #if defined(TARGET_SDL2) int surface_flags_window = SURFACE_FLAGS | SDL_WINDOW_RESIZABLE; int surface_flags_fullscreen = SURFACE_FLAGS | SDL_WINDOW_FULLSCREEN_DESKTOP; #else int surface_flags_window = SURFACE_FLAGS; int surface_flags_fullscreen = SURFACE_FLAGS; // (no fullscreen in SDL 1.2) #endif #if defined(TARGET_SDL2) #if 1 int renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE; #else /* If SDL_CreateRenderer() is called from within a VirtualBox Windows VM _without_ enabling 2D/3D acceleration and/or guest additions installed, it will crash if flags are *not* set to SDL_RENDERER_SOFTWARE (because it will try to use accelerated graphics and apparently fails miserably) */ int renderer_flags = SDL_RENDERER_SOFTWARE; #endif SDLSetScreenSizeAndOffsets(video.width, video.height); #endif int width = video.width; int height = video.height; int screen_width = video.screen_width; int screen_height = video.screen_height; int surface_flags = (fullscreen ? surface_flags_fullscreen : surface_flags_window); // default window size is unscaled video.window_width = screen_width; video.window_height = screen_height; #if defined(TARGET_SDL2) // store if initial screen mode is fullscreen mode when changing screen size video.fullscreen_initial = fullscreen; float window_scaling_factor = (float)setup.window_scaling_percent / 100; video.window_width = window_scaling_factor * screen_width; video.window_height = window_scaling_factor * screen_height; if (sdl_texture_stream) { SDL_DestroyTexture(sdl_texture_stream); sdl_texture_stream = NULL; } if (sdl_texture_target) { SDL_DestroyTexture(sdl_texture_target); sdl_texture_target = NULL; } if (!(fullscreen && fullscreen_enabled)) { if (sdl_renderer) { SDL_DestroyRenderer(sdl_renderer); sdl_renderer = NULL; } if (sdl_window) { SDL_DestroyWindow(sdl_window); sdl_window = NULL; } } if (sdl_window == NULL) sdl_window = SDL_CreateWindow(program.window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, video.window_width, video.window_height, surface_flags); if (sdl_window != NULL) { if (sdl_renderer == NULL) sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags); if (sdl_renderer != NULL) { SDL_RenderSetLogicalSize(sdl_renderer, screen_width, screen_height); // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, setup.window_scaling_quality); sdl_texture_stream = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); if (SDL_RenderTargetSupported(sdl_renderer)) sdl_texture_target = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, width, height); if (sdl_texture_stream != NULL) { // use SDL default values for RGB masks and no alpha channel new_surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0, 0); if (new_surface == NULL) Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); } else { Error(ERR_WARN, "SDL_CreateTexture() failed: %s", SDL_GetError()); } } else { Error(ERR_WARN, "SDL_CreateRenderer() failed: %s", SDL_GetError()); } } else { Error(ERR_WARN, "SDL_CreateWindow() failed: %s", SDL_GetError()); } #else // TARGET_SDL if (gfx.final_screen_bitmap == NULL) gfx.final_screen_bitmap = CreateBitmapStruct(); gfx.final_screen_bitmap->width = width; gfx.final_screen_bitmap->height = height; gfx.final_screen_bitmap->surface = SDL_SetVideoMode(width, height, video.depth, surface_flags); if (gfx.final_screen_bitmap->surface != NULL) { new_surface = SDL_CreateRGBSurface(surface_flags, width, height, video.depth, 0,0,0, 0); if (new_surface == NULL) Error(ERR_WARN, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); #if 0 new_surface = gfx.final_screen_bitmap->surface; gfx.final_screen_bitmap = NULL; #endif } else { Error(ERR_WARN, "SDL_SetVideoMode() failed: %s", SDL_GetError()); } #endif #if defined(TARGET_SDL2) // store fullscreen state ("video.fullscreen_enabled" may not reflect this!) if (new_surface != NULL) fullscreen_enabled = fullscreen; #endif if (backbuffer == NULL) backbuffer = CreateBitmapStruct(); backbuffer->width = video.width; backbuffer->height = video.height; if (backbuffer->surface) SDL_FreeSurface(backbuffer->surface); backbuffer->surface = new_surface; return (new_surface != NULL); } boolean SDLSetVideoMode(boolean fullscreen) { boolean success = FALSE; SetWindowTitle(); if (fullscreen && !video.fullscreen_enabled && video.fullscreen_available) { /* switch display to fullscreen mode, if available */ success = SDLCreateScreen(TRUE); if (!success) { /* switching display to fullscreen mode failed -- do not try it again */ video.fullscreen_available = FALSE; } else { video.fullscreen_enabled = TRUE; } } if ((!fullscreen && video.fullscreen_enabled) || !success) { /* switch display to window mode */ success = SDLCreateScreen(FALSE); if (!success) { /* switching display to window mode failed -- should not happen */ } else { video.fullscreen_enabled = FALSE; video.window_scaling_percent = setup.window_scaling_percent; video.window_scaling_quality = setup.window_scaling_quality; SDLSetScreenRenderingMode(setup.screen_rendering_mode); } } #if defined(TARGET_SDL2) SDLRedrawWindow(); // map window #endif #ifdef DEBUG #if defined(PLATFORM_WIN32) // experimental drag and drop code SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); { SDL_SysWMinfo wminfo; HWND hwnd; boolean wminfo_success = FALSE; SDL_VERSION(&wminfo.version); #if defined(TARGET_SDL2) if (sdl_window) wminfo_success = SDL_GetWindowWMInfo(sdl_window, &wminfo); #else wminfo_success = (SDL_GetWMInfo(&wminfo) == 1); #endif if (wminfo_success) { #if defined(TARGET_SDL2) hwnd = wminfo.info.win.window; #else hwnd = wminfo.window; #endif DragAcceptFiles(hwnd, TRUE); } } #endif #endif return success; } void SDLSetWindowTitle() { #if defined(TARGET_SDL2) if (sdl_window == NULL) return; SDL_SetWindowTitle(sdl_window, program.window_title); #else SDL_WM_SetCaption(program.window_title, program.window_title); #endif } #if defined(TARGET_SDL2) void SDLSetWindowScaling(int window_scaling_percent) { if (sdl_window == NULL) return; float window_scaling_factor = (float)window_scaling_percent / 100; int new_window_width = (int)(window_scaling_factor * video.screen_width); int new_window_height = (int)(window_scaling_factor * video.screen_height); SDL_SetWindowSize(sdl_window, new_window_width, new_window_height); video.window_scaling_percent = window_scaling_percent; video.window_width = new_window_width; video.window_height = new_window_height; SetWindowTitle(); } void SDLSetWindowScalingQuality(char *window_scaling_quality) { SDL_Texture *new_texture; if (sdl_texture_stream == NULL) return; SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, window_scaling_quality); new_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, video.width, video.height); if (new_texture != NULL) { SDL_DestroyTexture(sdl_texture_stream); sdl_texture_stream = new_texture; } if (SDL_RenderTargetSupported(sdl_renderer)) new_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, video.width, video.height); else new_texture = NULL; if (new_texture != NULL) { SDL_DestroyTexture(sdl_texture_target); sdl_texture_target = new_texture; } SDLRedrawWindow(); video.window_scaling_quality = window_scaling_quality; } void SDLSetWindowFullscreen(boolean fullscreen) { if (sdl_window == NULL) return; int flags = (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); if (SDL_SetWindowFullscreen(sdl_window, flags) == 0) video.fullscreen_enabled = fullscreen_enabled = fullscreen; // if screen size was changed in fullscreen mode, correct desktop window size if (!fullscreen && video.fullscreen_initial) { SDLSetWindowScaling(setup.window_scaling_percent); SDL_SetWindowPosition(sdl_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); video.fullscreen_initial = FALSE; } } void SDLSetDisplaySize() { SDL_Rect display_bounds; SDL_GetDisplayBounds(0, &display_bounds); video.display_width = display_bounds.w; video.display_height = display_bounds.h; #if 0 Error(ERR_DEBUG, "SDL real screen size: %d x %d", video.display_width, video.display_height); #endif } void SDLSetScreenSizeAndOffsets(int width, int height) { // set default video screen size and offsets video.screen_width = width; video.screen_height = height; video.screen_xoffset = 0; video.screen_yoffset = 0; #if defined(USE_COMPLETE_DISPLAY) float ratio_video = (float) width / height; float ratio_display = (float) video.display_width / video.display_height; if (ratio_video != ratio_display) { // adjust drawable screen size to cover the whole device display if (ratio_video < ratio_display) video.screen_width *= ratio_display / ratio_video; else video.screen_height *= ratio_video / ratio_display; video.screen_xoffset = (video.screen_width - width) / 2; video.screen_yoffset = (video.screen_height - height) / 2; #if 0 Error(ERR_DEBUG, "Changing screen from %dx%d to %dx%d (%.2f to %.2f)", width, height, video.screen_width, video.screen_height, ratio_video, ratio_display); #endif } #endif } void SDLSetScreenSizeForRenderer(int width, int height) { SDL_RenderSetLogicalSize(sdl_renderer, width, height); } void SDLSetScreenProperties() { SDLSetScreenSizeAndOffsets(video.width, video.height); SDLSetScreenSizeForRenderer(video.screen_width, video.screen_height); } #endif void SDLSetScreenRenderingMode(char *screen_rendering_mode) { #if defined(TARGET_SDL2) video.screen_rendering_mode = (strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_BITMAP) ? SPECIAL_RENDERING_BITMAP : strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_TARGET) ? SPECIAL_RENDERING_TARGET: strEqual(screen_rendering_mode, STR_SPECIAL_RENDERING_DOUBLE) ? SPECIAL_RENDERING_DOUBLE : SPECIAL_RENDERING_OFF); #else video.screen_rendering_mode = SPECIAL_RENDERING_BITMAP; #endif } void SDLRedrawWindow() { UpdateScreen_WithoutFrameDelay(NULL); } void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height, int depth) { if (program.headless) return; SDL_Surface *surface = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0); if (surface == NULL) Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError()); SDLSetNativeSurface(&surface); bitmap->surface = surface; } void SDLFreeBitmapPointers(Bitmap *bitmap) { if (bitmap->surface) SDL_FreeSurface(bitmap->surface); if (bitmap->surface_masked) SDL_FreeSurface(bitmap->surface_masked); bitmap->surface = NULL; bitmap->surface_masked = NULL; #if defined(TARGET_SDL2) if (bitmap->texture) SDL_DestroyTexture(bitmap->texture); if (bitmap->texture_masked) SDL_DestroyTexture(bitmap->texture_masked); bitmap->texture = NULL; bitmap->texture_masked = NULL; #endif } void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap); SDL_Rect src_rect, dst_rect; src_rect.x = src_x; src_rect.y = src_y; src_rect.w = width; src_rect.h = height; dst_rect.x = dst_x; dst_rect.y = dst_y; dst_rect.w = width; dst_rect.h = height; // if (src_bitmap != backbuffer || dst_bitmap != window) if (!(src_bitmap == backbuffer && dst_bitmap == window)) SDL_BlitSurface((mask_mode == BLIT_MASKED ? src_bitmap->surface_masked : src_bitmap->surface), &src_rect, real_dst_bitmap->surface, &dst_rect); if (dst_bitmap == window) UpdateScreen_WithFrameDelay(&dst_rect); } void SDLBlitTexture(Bitmap *bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { #if defined(TARGET_SDL2) SDL_Texture *texture; SDL_Rect src_rect; SDL_Rect dst_rect; texture = (mask_mode == BLIT_MASKED ? bitmap->texture_masked : bitmap->texture); if (texture == NULL) return; src_rect.x = src_x; src_rect.y = src_y; src_rect.w = width; src_rect.h = height; dst_rect.x = dst_x; dst_rect.y = dst_y; dst_rect.w = width; dst_rect.h = height; SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect); #endif } void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y, int width, int height, Uint32 color) { Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap); SDL_Rect rect; rect.x = x; rect.y = y; rect.w = width; rect.h = height; SDL_FillRect(real_dst_bitmap->surface, &rect, color); if (dst_bitmap == window) UpdateScreen_WithFrameDelay(&rect); } void PrepareFadeBitmap(int draw_target) { Bitmap *fade_bitmap = (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source : draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL); if (fade_bitmap == NULL) return; // copy backbuffer to fading buffer BlitBitmap(backbuffer, fade_bitmap, 0, 0, gfx.win_xsize, gfx.win_ysize, 0, 0); // add border and animations to fading buffer FinalizeScreen(draw_target); } void SDLFadeRectangle(int x, int y, int width, int height, int fade_mode, int fade_delay, int post_delay, void (*draw_border_function)(void)) { SDL_Surface *surface_backup = gfx.fade_bitmap_backup->surface; SDL_Surface *surface_source = gfx.fade_bitmap_source->surface; SDL_Surface *surface_target = gfx.fade_bitmap_target->surface; SDL_Surface *surface_black = gfx.fade_bitmap_black->surface; SDL_Surface *surface_screen = backbuffer->surface; SDL_Rect src_rect, dst_rect; SDL_Rect dst_rect2; int src_x = x, src_y = y; int dst_x = x, dst_y = y; unsigned int time_last, time_current; // store function for drawing global masked border void (*draw_global_border_function)(int) = gfx.draw_global_border_function; // deactivate drawing of global border while fading, if needed if (draw_border_function == NULL) gfx.draw_global_border_function = NULL; src_rect.x = src_x; src_rect.y = src_y; src_rect.w = width; src_rect.h = height; dst_rect.x = dst_x; dst_rect.y = dst_y; dst_rect.w = width; /* (ignored) */ dst_rect.h = height; /* (ignored) */ dst_rect2 = dst_rect; // before fading in, store backbuffer (without animation graphics) if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM)) SDL_BlitSurface(surface_screen, &dst_rect, surface_backup, &src_rect); /* copy source and target surfaces to temporary surfaces for fading */ if (fade_mode & FADE_TYPE_TRANSFORM) { // (source and target fading buffer already prepared) } else if (fade_mode & FADE_TYPE_FADE_IN) { // (target fading buffer already prepared) SDL_BlitSurface(surface_black, &src_rect, surface_source, &src_rect); } else /* FADE_TYPE_FADE_OUT */ { // (source fading buffer already prepared) SDL_BlitSurface(surface_black, &src_rect, surface_target, &src_rect); } time_current = SDL_GetTicks(); if (fade_mode == FADE_MODE_MELT) { boolean done = FALSE; int melt_pixels = 2; int melt_columns = width / melt_pixels; int ypos[melt_columns]; int max_steps = height / 8 + 32; int steps_done = 0; float steps = 0; int i; SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); SDLSetAlpha(surface_target, FALSE, 0); /* disable alpha blending */ ypos[0] = -GetSimpleRandom(16); for (i = 1 ; i < melt_columns; i++) { int r = GetSimpleRandom(3) - 1; /* randomly choose from { -1, 0, -1 } */ ypos[i] = ypos[i - 1] + r; if (ypos[i] > 0) ypos[i] = 0; else if (ypos[i] == -16) ypos[i] = -15; } while (!done) { int steps_final; time_last = time_current; time_current = SDL_GetTicks(); steps += max_steps * ((float)(time_current - time_last) / fade_delay); steps_final = MIN(MAX(0, steps), max_steps); steps_done++; done = (steps_done >= steps_final); for (i = 0 ; i < melt_columns; i++) { if (ypos[i] < 0) { ypos[i]++; done = FALSE; } else if (ypos[i] < height) { int y1 = 16; int y2 = 8; int y3 = 8; int dy = (ypos[i] < y1) ? ypos[i] + 1 : y2 + GetSimpleRandom(y3); if (ypos[i] + dy >= height) dy = height - ypos[i]; /* copy part of (appearing) target surface to upper area */ src_rect.x = src_x + i * melt_pixels; // src_rect.y = src_y + ypos[i]; src_rect.y = src_y; src_rect.w = melt_pixels; // src_rect.h = dy; src_rect.h = ypos[i] + dy; dst_rect.x = dst_x + i * melt_pixels; // dst_rect.y = dst_y + ypos[i]; dst_rect.y = dst_y; if (steps_done >= steps_final) SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); ypos[i] += dy; /* copy part of (disappearing) source surface to lower area */ src_rect.x = src_x + i * melt_pixels; src_rect.y = src_y; src_rect.w = melt_pixels; src_rect.h = height - ypos[i]; dst_rect.x = dst_x + i * melt_pixels; dst_rect.y = dst_y + ypos[i]; if (steps_done >= steps_final) SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); done = FALSE; } else { src_rect.x = src_x + i * melt_pixels; src_rect.y = src_y; src_rect.w = melt_pixels; src_rect.h = height; dst_rect.x = dst_x + i * melt_pixels; dst_rect.y = dst_y; if (steps_done >= steps_final) SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); } } if (steps_done >= steps_final) { if (draw_border_function != NULL) draw_border_function(); UpdateScreen_WithFrameDelay(&dst_rect2); } } } else if (fade_mode == FADE_MODE_CURTAIN) { float xx; int xx_final; int xx_size = width / 2; SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); SDLSetAlpha(surface_source, FALSE, 0); /* disable alpha blending */ for (xx = 0; xx < xx_size;) { time_last = time_current; time_current = SDL_GetTicks(); xx += xx_size * ((float)(time_current - time_last) / fade_delay); xx_final = MIN(MAX(0, xx), xx_size); src_rect.x = src_x; src_rect.y = src_y; src_rect.w = width; src_rect.h = height; dst_rect.x = dst_x; dst_rect.y = dst_y; /* draw new (target) image to screen buffer */ SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); if (xx_final < xx_size) { src_rect.w = xx_size - xx_final; src_rect.h = height; /* draw old (source) image to screen buffer (left side) */ src_rect.x = src_x + xx_final; dst_rect.x = dst_x; SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); /* draw old (source) image to screen buffer (right side) */ src_rect.x = src_x + xx_size; dst_rect.x = dst_x + xx_size + xx_final; SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); } if (draw_border_function != NULL) draw_border_function(); /* only update the region of the screen that is affected from fading */ UpdateScreen_WithFrameDelay(&dst_rect2); } } else /* fading in, fading out or cross-fading */ { float alpha; int alpha_final; for (alpha = 0.0; alpha < 255.0;) { time_last = time_current; time_current = SDL_GetTicks(); alpha += 255 * ((float)(time_current - time_last) / fade_delay); alpha_final = MIN(MAX(0, alpha), 255); /* draw existing (source) image to screen buffer */ SDL_BlitSurface(surface_source, &src_rect, surface_screen, &dst_rect); /* draw new (target) image to screen buffer using alpha blending */ SDLSetAlpha(surface_target, TRUE, alpha_final); SDL_BlitSurface(surface_target, &src_rect, surface_screen, &dst_rect); if (draw_border_function != NULL) draw_border_function(); /* only update the region of the screen that is affected from fading */ UpdateScreen_WithFrameDelay(&dst_rect); } } if (post_delay > 0) { unsigned int time_post_delay; time_current = SDL_GetTicks(); time_post_delay = time_current + post_delay; while (time_current < time_post_delay) { // updating the screen contains waiting for frame delay (non-busy) UpdateScreen_WithFrameDelay(NULL); time_current = SDL_GetTicks(); } } // restore function for drawing global masked border gfx.draw_global_border_function = draw_global_border_function; // after fading in, restore backbuffer (without animation graphics) if (fade_mode & (FADE_TYPE_FADE_IN | FADE_TYPE_TRANSFORM)) SDL_BlitSurface(surface_backup, &dst_rect, surface_screen, &src_rect); } void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y, int to_x, int to_y, Uint32 color) { SDL_Surface *surface = dst_bitmap->surface; SDL_Rect rect; if (from_x > to_x) swap_numbers(&from_x, &to_x); if (from_y > to_y) swap_numbers(&from_y, &to_y); rect.x = from_x; rect.y = from_y; rect.w = (to_x - from_x + 1); rect.h = (to_y - from_y + 1); SDL_FillRect(surface, &rect, color); } void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y, int to_x, int to_y, Uint32 color) { sge_Line(dst_bitmap->surface, from_x, from_y, to_x, to_y, color); } #if ENABLE_UNUSED_CODE void SDLDrawLines(SDL_Surface *surface, struct XY *points, int num_points, Uint32 color) { int i, x, y; int line_width = 4; for (i = 0; i < num_points - 1; i++) { for (x = 0; x < line_width; x++) { for (y = 0; y < line_width; y++) { int dx = x - line_width / 2; int dy = y - line_width / 2; if ((x == 0 && y == 0) || (x == 0 && y == line_width - 1) || (x == line_width - 1 && y == 0) || (x == line_width - 1 && y == line_width - 1)) continue; sge_Line(surface, points[i].x + dx, points[i].y + dy, points[i+1].x + dx, points[i+1].y + dy, color); } } } } #endif Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y) { SDL_Surface *surface = src_bitmap->surface; switch (surface->format->BytesPerPixel) { case 1: /* assuming 8-bpp */ { return *((Uint8 *)surface->pixels + y * surface->pitch + x); } break; case 2: /* probably 15-bpp or 16-bpp */ { return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x); } break; case 3: /* slow 24-bpp mode; usually not used */ { /* does this work? */ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3; Uint32 color = 0; int shift; shift = surface->format->Rshift; color |= *(pix + shift / 8) >> shift; shift = surface->format->Gshift; color |= *(pix + shift / 8) >> shift; shift = surface->format->Bshift; color |= *(pix + shift / 8) >> shift; return color; } break; case 4: /* probably 32-bpp */ { return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x); } break; } return 0; } /* ========================================================================= */ /* The following functions were taken from the SGE library */ /* (SDL Graphics Extension Library) by Anders Lindström */ /* http://www.etek.chalmers.se/~e8cal1/sge/index.html */ /* ========================================================================= */ void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { if (x >= 0 && x <= surface->w - 1 && y >= 0 && y <= surface->h - 1) { switch (surface->format->BytesPerPixel) { case 1: { /* Assuming 8-bpp */ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color; } break; case 2: { /* Probably 15-bpp or 16-bpp */ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color; } break; case 3: { /* Slow 24-bpp mode, usually not used */ Uint8 *pix; int shift; /* Gack - slow, but endian correct */ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; shift = surface->format->Rshift; *(pix+shift/8) = color>>shift; shift = surface->format->Gshift; *(pix+shift/8) = color>>shift; shift = surface->format->Bshift; *(pix+shift/8) = color>>shift; } break; case 4: { /* Probably 32-bpp */ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color; } break; } } } void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B) { _PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B)); } void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { *((Uint8 *)surface->pixels + y*surface->pitch + x) = color; } void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color; } void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { Uint8 *pix; int shift; /* Gack - slow, but endian correct */ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; shift = surface->format->Rshift; *(pix+shift/8) = color>>shift; shift = surface->format->Gshift; *(pix+shift/8) = color>>shift; shift = surface->format->Bshift; *(pix+shift/8) = color>>shift; } void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color; } void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color) { switch (dest->format->BytesPerPixel) { case 1: *((Uint8 *)dest->pixels + y*dest->pitch + x) = color; break; case 2: *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color; break; case 3: _PutPixel24(dest,x,y,color); break; case 4: *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color; break; } } void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color) { if (SDL_MUSTLOCK(surface)) { if (SDL_LockSurface(surface) < 0) { return; } } _PutPixel(surface, x, y, color); if (SDL_MUSTLOCK(surface)) { SDL_UnlockSurface(surface); } } void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b) { sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b)); } Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y) { if (y >= 0 && y <= dest->h - 1) { switch (dest->format->BytesPerPixel) { case 1: return y*dest->pitch; break; case 2: return y*dest->pitch/2; break; case 3: return y*dest->pitch; break; case 4: return y*dest->pitch/4; break; } } return -1; } void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color) { if (x >= 0 && x <= surface->w - 1 && ypitch >= 0) { switch (surface->format->BytesPerPixel) { case 1: { /* Assuming 8-bpp */ *((Uint8 *)surface->pixels + ypitch + x) = color; } break; case 2: { /* Probably 15-bpp or 16-bpp */ *((Uint16 *)surface->pixels + ypitch + x) = color; } break; case 3: { /* Slow 24-bpp mode, usually not used */ Uint8 *pix; int shift; /* Gack - slow, but endian correct */ pix = (Uint8 *)surface->pixels + ypitch + x*3; shift = surface->format->Rshift; *(pix+shift/8) = color>>shift; shift = surface->format->Gshift; *(pix+shift/8) = color>>shift; shift = surface->format->Bshift; *(pix+shift/8) = color>>shift; } break; case 4: { /* Probably 32-bpp */ *((Uint32 *)surface->pixels + ypitch + x) = color; } break; } } } void sge_HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color) { SDL_Rect l; if (SDL_MUSTLOCK(Surface)) { if (SDL_LockSurface(Surface) < 0) { return; } } if (x1 > x2) { Sint16 tmp = x1; x1 = x2; x2 = tmp; } /* Do the clipping */ if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0) return; if (x1 < 0) x1 = 0; if (x2 > Surface->w - 1) x2 = Surface->w - 1; l.x = x1; l.y = y; l.w = x2 - x1 + 1; l.h = 1; SDL_FillRect(Surface, &l, Color); if (SDL_MUSTLOCK(Surface)) { SDL_UnlockSurface(Surface); } } void sge_HLineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint8 R, Uint8 G, Uint8 B) { sge_HLine(Surface, x1, x2, y, SDL_MapRGB(Surface->format, R, G, B)); } void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color) { SDL_Rect l; if (x1 > x2) { Sint16 tmp = x1; x1 = x2; x2 = tmp; } /* Do the clipping */ if (y < 0 || y > Surface->h - 1 || x1 > Surface->w - 1 || x2 < 0) return; if (x1 < 0) x1 = 0; if (x2 > Surface->w - 1) x2 = Surface->w - 1; l.x = x1; l.y = y; l.w = x2 - x1 + 1; l.h = 1; SDL_FillRect(Surface, &l, Color); } void sge_VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color) { SDL_Rect l; if (SDL_MUSTLOCK(Surface)) { if (SDL_LockSurface(Surface) < 0) { return; } } if (y1 > y2) { Sint16 tmp = y1; y1 = y2; y2 = tmp; } /* Do the clipping */ if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0) return; if (y1 < 0) y1 = 0; if (y2 > Surface->h - 1) y2 = Surface->h - 1; l.x = x; l.y = y1; l.w = 1; l.h = y2 - y1 + 1; SDL_FillRect(Surface, &l, Color); if (SDL_MUSTLOCK(Surface)) { SDL_UnlockSurface(Surface); } } void sge_VLineRGB(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) { sge_VLine(Surface, x, y1, y2, SDL_MapRGB(Surface->format, R, G, B)); } void _VLine(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color) { SDL_Rect l; if (y1 > y2) { Sint16 tmp = y1; y1 = y2; y2 = tmp; } /* Do the clipping */ if (x < 0 || x > Surface->w - 1 || y1 > Surface->h - 1 || y2 < 0) return; if (y1 < 0) y1 = 0; if (y2 > Surface->h - 1) y2 = Surface->h - 1; l.x = x; l.y = y1; l.w = 1; l.h = y2 - y1 + 1; SDL_FillRect(Surface, &l, Color); } void sge_DoLine(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color)) { Sint16 dx, dy, sdx, sdy, x, y, px, py; dx = x2 - x1; dy = y2 - y1; sdx = (dx < 0) ? -1 : 1; sdy = (dy < 0) ? -1 : 1; dx = sdx * dx + 1; dy = sdy * dy + 1; x = y = 0; px = x1; py = y1; if (dx >= dy) { for (x = 0; x < dx; x++) { Callback(Surface, px, py, Color); y += dy; if (y >= dx) { y -= dx; py += sdy; } px += sdx; } } else { for (y = 0; y < dy; y++) { Callback(Surface, px, py, Color); x += dx; if (x >= dy) { x -= dy; px += sdx; } py += sdy; } } } void sge_DoLineRGB(SDL_Surface *Surface, Sint16 X1, Sint16 Y1, Sint16 X2, Sint16 Y2, Uint8 R, Uint8 G, Uint8 B, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color)) { sge_DoLine(Surface, X1, Y1, X2, Y2, SDL_MapRGB(Surface->format, R, G, B), Callback); } void sge_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color) { if (SDL_MUSTLOCK(Surface)) { if (SDL_LockSurface(Surface) < 0) return; } /* Draw the line */ sge_DoLine(Surface, x1, y1, x2, y2, Color, _PutPixel); /* unlock the display */ if (SDL_MUSTLOCK(Surface)) { SDL_UnlockSurface(Surface); } } void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 R, Uint8 G, Uint8 B) { sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B)); } void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel) { sge_PutPixel(dst_bitmap->surface, x, y, pixel); } /* ----------------------------------------------------------------------------- quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface ----------------------------------------------------------------------------- */ void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y, int width, int height, Uint32 color) { int x, y; for (y = src_y; y < src_y + height; y++) { for (x = src_x; x < src_x + width; x++) { Uint32 pixel = SDLGetPixel(bitmap, x, y); SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL); } } } void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y); if (pixel != BLACK_PIXEL) SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL); } } } /* ========================================================================= */ /* The following functions were taken from the SDL_gfx library version 2.0.3 */ /* (Rotozoomer) by Andreas Schiffler */ /* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html */ /* ========================================================================= */ /* ----------------------------------------------------------------------------- 32 bit zoomer zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface. ----------------------------------------------------------------------------- */ typedef struct { Uint8 r; Uint8 g; Uint8 b; Uint8 a; } tColorRGBA; int zoomSurfaceRGBA_scaleDownBy2(SDL_Surface *src, SDL_Surface *dst) { int x, y; tColorRGBA *sp, *csp, *dp; int dgap; /* pointer setup */ sp = csp = (tColorRGBA *) src->pixels; dp = (tColorRGBA *) dst->pixels; dgap = dst->pitch - dst->w * 4; for (y = 0; y < dst->h; y++) { sp = csp; for (x = 0; x < dst->w; x++) { tColorRGBA *sp0 = sp; tColorRGBA *sp1 = (tColorRGBA *) ((Uint8 *) sp + src->pitch); tColorRGBA *sp00 = &sp0[0]; tColorRGBA *sp01 = &sp0[1]; tColorRGBA *sp10 = &sp1[0]; tColorRGBA *sp11 = &sp1[1]; tColorRGBA new; /* create new color pixel from all four source color pixels */ new.r = (sp00->r + sp01->r + sp10->r + sp11->r) / 4; new.g = (sp00->g + sp01->g + sp10->g + sp11->g) / 4; new.b = (sp00->b + sp01->b + sp10->b + sp11->b) / 4; new.a = (sp00->a + sp01->a + sp10->a + sp11->a) / 4; /* draw */ *dp = new; /* advance source pointers */ sp += 2; /* advance destination pointer */ dp++; } /* advance source pointer */ csp = (tColorRGBA *) ((Uint8 *) csp + 2 * src->pitch); /* advance destination pointers */ dp = (tColorRGBA *) ((Uint8 *) dp + dgap); } return 0; } int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst) { int x, y, *sax, *say, *csax, *csay; float sx, sy; tColorRGBA *sp, *csp, *csp0, *dp; int dgap; /* use specialized zoom function when scaling down to exactly half size */ if (src->w == 2 * dst->w && src->h == 2 * dst->h) return zoomSurfaceRGBA_scaleDownBy2(src, dst); /* variable setup */ sx = (float) src->w / (float) dst->w; sy = (float) src->h / (float) dst->h; /* allocate memory for row increments */ csax = sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32)); csay = say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32)); /* precalculate row increments */ for (x = 0; x <= dst->w; x++) *csax++ = (int)(sx * x); for (y = 0; y <= dst->h; y++) *csay++ = (int)(sy * y); /* pointer setup */ sp = csp = csp0 = (tColorRGBA *) src->pixels; dp = (tColorRGBA *) dst->pixels; dgap = dst->pitch - dst->w * 4; csay = say; for (y = 0; y < dst->h; y++) { sp = csp; csax = sax; for (x = 0; x < dst->w; x++) { /* draw */ *dp = *sp; /* advance source pointers */ csax++; sp = csp + *csax; /* advance destination pointer */ dp++; } /* advance source pointer */ csay++; csp = (tColorRGBA *) ((Uint8 *) csp0 + *csay * src->pitch); /* advance destination pointers */ dp = (tColorRGBA *) ((Uint8 *) dp + dgap); } free(sax); free(say); return 0; } /* ----------------------------------------------------------------------------- 8 bit zoomer zoomes 8 bit palette/Y 'src' surface to 'dst' surface ----------------------------------------------------------------------------- */ int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst) { Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy; Uint8 *sp, *dp, *csp; int dgap; /* variable setup */ sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w); sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h); /* allocate memory for row increments */ sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32)); say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32)); /* precalculate row increments */ csx = 0; csax = sax; for (x = 0; x < dst->w; x++) { csx += sx; *csax = (csx >> 16); csx &= 0xffff; csax++; } csy = 0; csay = say; for (y = 0; y < dst->h; y++) { csy += sy; *csay = (csy >> 16); csy &= 0xffff; csay++; } csx = 0; csax = sax; for (x = 0; x < dst->w; x++) { csx += (*csax); csax++; } csy = 0; csay = say; for (y = 0; y < dst->h; y++) { csy += (*csay); csay++; } /* pointer setup */ sp = csp = (Uint8 *) src->pixels; dp = (Uint8 *) dst->pixels; dgap = dst->pitch - dst->w; /* draw */ csay = say; for (y = 0; y < dst->h; y++) { csax = sax; sp = csp; for (x = 0; x < dst->w; x++) { /* draw */ *dp = *sp; /* advance source pointers */ sp += (*csax); csax++; /* advance destination pointer */ dp++; } /* advance source pointer (for row) */ csp += ((*csay) * src->pitch); csay++; /* advance destination pointers */ dp += dgap; } free(sax); free(say); return 0; } /* ----------------------------------------------------------------------------- zoomSurface() Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface. 'zoomx' and 'zoomy' are scaling factors for width and height. If the surface is not 8bit or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. ----------------------------------------------------------------------------- */ SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height) { SDL_Surface *zoom_src = NULL; SDL_Surface *zoom_dst = NULL; boolean is_converted = FALSE; boolean is_32bit; int i; if (src == NULL) return NULL; /* determine if source surface is 32 bit or 8 bit */ is_32bit = (src->format->BitsPerPixel == 32); if (is_32bit || src->format->BitsPerPixel == 8) { /* use source surface 'as is' */ zoom_src = src; } else { /* new source surface is 32 bit with a defined RGB ordering */ zoom_src = SDL_CreateRGBSurface(SURFACE_FLAGS, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, (src->format->Amask ? 0xff000000 : 0)); SDL_BlitSurface(src, NULL, zoom_src, NULL); is_32bit = TRUE; is_converted = TRUE; } /* allocate surface to completely contain the zoomed surface */ if (is_32bit) { /* target surface is 32 bit with source RGBA/ABGR ordering */ zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 32, zoom_src->format->Rmask, zoom_src->format->Gmask, zoom_src->format->Bmask, zoom_src->format->Amask); } else { /* target surface is 8 bit */ zoom_dst = SDL_CreateRGBSurface(SURFACE_FLAGS, dst_width, dst_height, 8, 0, 0, 0, 0); } /* lock source surface */ SDL_LockSurface(zoom_src); /* check which kind of surface we have */ if (is_32bit) { /* call the 32 bit transformation routine to do the zooming */ zoomSurfaceRGBA(zoom_src, zoom_dst); } else { /* copy palette */ for (i = 0; i < zoom_src->format->palette->ncolors; i++) zoom_dst->format->palette->colors[i] = zoom_src->format->palette->colors[i]; zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors; /* call the 8 bit transformation routine to do the zooming */ zoomSurfaceY(zoom_src, zoom_dst); } /* unlock source surface */ SDL_UnlockSurface(zoom_src); /* free temporary surface */ if (is_converted) SDL_FreeSurface(zoom_src); /* return destination surface */ return zoom_dst; } static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface) { SDL_Surface *new_surface; if (surface == NULL) return NULL; if ((new_surface = SDLGetNativeSurface(surface)) == NULL) Error(ERR_EXIT, "SDLGetNativeSurface() failed"); /* remove alpha channel from native non-transparent surface, if defined */ SDLSetAlpha(new_surface, FALSE, 0); /* remove transparent color from native non-transparent surface, if defined */ SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0); return new_surface; } Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height) { Bitmap *dst_bitmap = CreateBitmapStruct(); SDL_Surface *src_surface = src_bitmap->surface_masked; SDL_Surface *dst_surface; dst_width = MAX(1, dst_width); /* prevent zero bitmap width */ dst_height = MAX(1, dst_height); /* prevent zero bitmap height */ dst_bitmap->width = dst_width; dst_bitmap->height = dst_height; /* create zoomed temporary surface from source surface */ dst_surface = zoomSurface(src_surface, dst_width, dst_height); /* create native format destination surface from zoomed temporary surface */ SDLSetNativeSurface(&dst_surface); /* set color key for zoomed surface from source surface, if defined */ if (SDLHasColorKey(src_surface)) SDL_SetColorKey(dst_surface, SET_TRANSPARENT_PIXEL, SDLGetColorKey(src_surface)); /* create native non-transparent surface for opaque blitting */ dst_bitmap->surface = SDLGetOpaqueSurface(dst_surface); /* set native transparent surface for masked blitting */ dst_bitmap->surface_masked = dst_surface; return dst_bitmap; } /* ========================================================================= */ /* load image to bitmap */ /* ========================================================================= */ Bitmap *SDLLoadImage(char *filename) { Bitmap *new_bitmap = CreateBitmapStruct(); SDL_Surface *sdl_image_tmp; if (program.headless) { /* prevent sanity check warnings at later stage */ new_bitmap->width = new_bitmap->height = 1; return new_bitmap; } print_timestamp_init("SDLLoadImage"); print_timestamp_time(getBaseNamePtr(filename)); /* load image to temporary surface */ if ((sdl_image_tmp = IMG_Load(filename)) == NULL) Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError()); print_timestamp_time("IMG_Load"); UPDATE_BUSY_STATE(); /* create native non-transparent surface for current image */ if ((new_bitmap->surface = SDLGetOpaqueSurface(sdl_image_tmp)) == NULL) Error(ERR_EXIT, "SDLGetOpaqueSurface() failed"); print_timestamp_time("SDLGetNativeSurface (opaque)"); UPDATE_BUSY_STATE(); /* set black pixel to transparent if no alpha channel / transparent color */ if (!SDLHasAlpha(sdl_image_tmp) && !SDLHasColorKey(sdl_image_tmp)) SDL_SetColorKey(sdl_image_tmp, SET_TRANSPARENT_PIXEL, SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00)); /* create native transparent surface for current image */ if ((new_bitmap->surface_masked = SDLGetNativeSurface(sdl_image_tmp)) == NULL) Error(ERR_EXIT, "SDLGetNativeSurface() failed"); print_timestamp_time("SDLGetNativeSurface (masked)"); UPDATE_BUSY_STATE(); /* free temporary surface */ SDL_FreeSurface(sdl_image_tmp); new_bitmap->width = new_bitmap->surface->w; new_bitmap->height = new_bitmap->surface->h; print_timestamp_done("SDLLoadImage"); return new_bitmap; } /* ------------------------------------------------------------------------- */ /* custom cursor fuctions */ /* ------------------------------------------------------------------------- */ static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info) { return SDL_CreateCursor(cursor_info->data, cursor_info->mask, cursor_info->width, cursor_info->height, cursor_info->hot_x, cursor_info->hot_y); } void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info) { static struct MouseCursorInfo *last_cursor_info = NULL; static struct MouseCursorInfo *last_cursor_info2 = NULL; static SDL_Cursor *cursor_default = NULL; static SDL_Cursor *cursor_current = NULL; /* if invoked for the first time, store the SDL default cursor */ if (cursor_default == NULL) cursor_default = SDL_GetCursor(); /* only create new cursor if cursor info (custom only) has changed */ if (cursor_info != NULL && cursor_info != last_cursor_info) { cursor_current = create_cursor(cursor_info); last_cursor_info = cursor_info; } /* only set new cursor if cursor info (custom or NULL) has changed */ if (cursor_info != last_cursor_info2) SDL_SetCursor(cursor_info ? cursor_current : cursor_default); last_cursor_info2 = cursor_info; } /* ========================================================================= */ /* audio functions */ /* ========================================================================= */ void SDLOpenAudio(void) { if (program.headless) return; #if !defined(TARGET_SDL2) if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT)) SDL_putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver)); #endif if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError()); return; } if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT, AUDIO_NUM_CHANNELS_STEREO, setup.system.audio_fragment_size) < 0) { Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError()); return; } audio.sound_available = TRUE; audio.music_available = TRUE; audio.loops_available = TRUE; audio.sound_enabled = TRUE; /* set number of available mixer channels */ audio.num_channels = Mix_AllocateChannels(NUM_MIXER_CHANNELS); audio.music_channel = MUSIC_CHANNEL; audio.first_sound_channel = FIRST_SOUND_CHANNEL; Mixer_InitChannels(); } void SDLCloseAudio(void) { Mix_HaltMusic(); Mix_HaltChannel(-1); Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); } /* ========================================================================= */ /* event functions */ /* ========================================================================= */ void SDLWaitEvent(Event *event) { SDL_WaitEvent(event); } void SDLHandleWindowManagerEvent(Event *event) { #ifdef DEBUG #if defined(PLATFORM_WIN32) // experimental drag and drop code SDL_SysWMEvent *syswmevent = (SDL_SysWMEvent *)event; SDL_SysWMmsg *syswmmsg = (SDL_SysWMmsg *)(syswmevent->msg); #if defined(TARGET_SDL2) if (syswmmsg->msg.win.msg == WM_DROPFILES) #else if (syswmmsg->msg == WM_DROPFILES) #endif { #if defined(TARGET_SDL2) HDROP hdrop = (HDROP)syswmmsg->msg.win.wParam; #else HDROP hdrop = (HDROP)syswmmsg->wParam; #endif int i, num_files; printf("::: SDL_SYSWMEVENT:\n"); num_files = DragQueryFile(hdrop, 0xffffffff, NULL, 0); for (i = 0; i < num_files; i++) { int buffer_len = DragQueryFile(hdrop, i, NULL, 0); char buffer[buffer_len + 1]; DragQueryFile(hdrop, i, buffer, buffer_len + 1); printf("::: - '%s'\n", buffer); } #if defined(TARGET_SDL2) DragFinish((HDROP)syswmmsg->msg.win.wParam); #else DragFinish((HDROP)syswmmsg->wParam); #endif } #endif #endif } /* ========================================================================= */ /* joystick functions */ /* ========================================================================= */ #if defined(TARGET_SDL2) static void *sdl_joystick[MAX_PLAYERS]; // game controller or joystick #else static SDL_Joystick *sdl_joystick[MAX_PLAYERS]; // only joysticks supported #endif static int sdl_js_axis_raw[MAX_PLAYERS][2]; static int sdl_js_axis[MAX_PLAYERS][2]; static int sdl_js_button[MAX_PLAYERS][2]; static boolean sdl_is_controller[MAX_PLAYERS]; void SDLClearJoystickState() { int i, j; for (i = 0; i < MAX_PLAYERS; i++) { for (j = 0; j < 2; j++) { sdl_js_axis_raw[i][j] = -1; sdl_js_axis[i][j] = 0; sdl_js_button[i][j] = 0; } } } boolean SDLOpenJoystick(int nr) { if (nr < 0 || nr >= MAX_PLAYERS) return FALSE; #if defined(TARGET_SDL2) sdl_is_controller[nr] = SDL_IsGameController(nr); #else sdl_is_controller[nr] = FALSE; #endif #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "opening joystick %d (%s)", nr, (sdl_is_controller[nr] ? "game controller" : "joystick")); #endif #if defined(TARGET_SDL2) if (sdl_is_controller[nr]) sdl_joystick[nr] = SDL_GameControllerOpen(nr); else sdl_joystick[nr] = SDL_JoystickOpen(nr); #else sdl_joystick[nr] = SDL_JoystickOpen(nr); #endif return (sdl_joystick[nr] != NULL); } void SDLCloseJoystick(int nr) { if (nr < 0 || nr >= MAX_PLAYERS) return; #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "closing joystick %d", nr); #endif #if defined(TARGET_SDL2) if (sdl_is_controller[nr]) SDL_GameControllerClose(sdl_joystick[nr]); else SDL_JoystickClose(sdl_joystick[nr]); #else SDL_JoystickClose(sdl_joystick[nr]); #endif sdl_joystick[nr] = NULL; } boolean SDLCheckJoystickOpened(int nr) { if (nr < 0 || nr >= MAX_PLAYERS) return FALSE; #if defined(TARGET_SDL2) return (sdl_joystick[nr] != NULL ? TRUE : FALSE); #else return (SDL_JoystickOpened(nr) ? TRUE : FALSE); #endif } static void setJoystickAxis(int nr, int axis_id_raw, int axis_value) { #if defined(TARGET_SDL2) int axis_id = (axis_id_raw == SDL_CONTROLLER_AXIS_LEFTX || axis_id_raw == SDL_CONTROLLER_AXIS_RIGHTX ? 0 : axis_id_raw == SDL_CONTROLLER_AXIS_LEFTY || axis_id_raw == SDL_CONTROLLER_AXIS_RIGHTY ? 1 : -1); #else int axis_id = axis_id_raw % 2; #endif if (nr < 0 || nr >= MAX_PLAYERS) return; if (axis_id == -1) return; // prevent (slightly jittering, but centered) axis A from resetting axis B if (ABS(axis_value) < JOYSTICK_PERCENT * JOYSTICK_MAX_AXIS_POS / 100 && axis_id_raw != sdl_js_axis_raw[nr][axis_id]) return; sdl_js_axis[nr][axis_id] = axis_value; sdl_js_axis_raw[nr][axis_id] = axis_id_raw; } static void setJoystickButton(int nr, int button_id_raw, int button_state) { #if defined(TARGET_SDL2) int button_id = (button_id_raw == SDL_CONTROLLER_BUTTON_A || button_id_raw == SDL_CONTROLLER_BUTTON_X || button_id_raw == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || button_id_raw == SDL_CONTROLLER_BUTTON_LEFTSTICK || button_id_raw == SDL_CONTROLLER_BUTTON_RIGHTSTICK ? 0 : button_id_raw == SDL_CONTROLLER_BUTTON_B || button_id_raw == SDL_CONTROLLER_BUTTON_Y || button_id_raw == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ? 1 : -1); if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_LEFT) sdl_js_axis[nr][0] = button_state * JOYSTICK_XLEFT; else if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) sdl_js_axis[nr][0] = button_state * JOYSTICK_XRIGHT; else if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_UP) sdl_js_axis[nr][1] = button_state * JOYSTICK_YUPPER; else if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_DOWN) sdl_js_axis[nr][1] = button_state * JOYSTICK_YLOWER; if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_LEFT || button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_RIGHT || button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_UP || button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_DOWN) sdl_js_axis_raw[nr][0] = sdl_js_axis_raw[nr][1] = -1; #else int button_id = button_id_raw % 2; #endif if (nr < 0 || nr >= MAX_PLAYERS) return; if (button_id == -1) return; sdl_js_button[nr][button_id] = button_state; } void HandleJoystickEvent(Event *event) { switch(event->type) { #if defined(TARGET_SDL2) case SDL_CONTROLLERDEVICEADDED: #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_CONTROLLERDEVICEADDED: device %d added", event->cdevice.which); #endif InitJoysticks(); break; case SDL_CONTROLLERDEVICEREMOVED: #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_CONTROLLERDEVICEREMOVED: device %d removed", event->cdevice.which); #endif InitJoysticks(); break; case SDL_CONTROLLERAXISMOTION: #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_CONTROLLERAXISMOTION: device %d, axis %d: %d", event->caxis.which, event->caxis.axis, event->caxis.value); #endif setJoystickAxis(event->caxis.which, event->caxis.axis, event->caxis.value); break; case SDL_CONTROLLERBUTTONDOWN: #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_CONTROLLERBUTTONDOWN: device %d, button %d", event->cbutton.which, event->cbutton.button); #endif setJoystickButton(event->cbutton.which, event->cbutton.button, TRUE); break; case SDL_CONTROLLERBUTTONUP: #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_CONTROLLERBUTTONUP: device %d, button %d", event->cbutton.which, event->cbutton.button); #endif setJoystickButton(event->cbutton.which, event->cbutton.button, FALSE); break; #endif case SDL_JOYAXISMOTION: if (sdl_is_controller[event->jaxis.which]) break; #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_JOYAXISMOTION: device %d, axis %d: %d", event->jaxis.which, event->jaxis.axis, event->jaxis.value); #endif if (event->jaxis.axis < 4) setJoystickAxis(event->jaxis.which, event->jaxis.axis, event->jaxis.value); break; case SDL_JOYBUTTONDOWN: if (sdl_is_controller[event->jaxis.which]) break; #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_JOYBUTTONDOWN: device %d, button %d", event->jbutton.which, event->jbutton.button); #endif if (event->jbutton.button < 4) setJoystickButton(event->jbutton.which, event->jbutton.button, TRUE); break; case SDL_JOYBUTTONUP: if (sdl_is_controller[event->jaxis.which]) break; #if DEBUG_JOYSTICKS Error(ERR_DEBUG, "SDL_JOYBUTTONUP: device %d, button %d", event->jbutton.which, event->jbutton.button); #endif if (event->jbutton.button < 4) setJoystickButton(event->jbutton.which, event->jbutton.button, FALSE); break; default: break; } } void SDLInitJoysticks() { static boolean sdl_joystick_subsystem_initialized = FALSE; boolean print_warning = !sdl_joystick_subsystem_initialized; #if defined(TARGET_SDL2) char *mappings_file_base = getPath2(options.conf_directory, GAMECONTROLLER_BASENAME); char *mappings_file_user = getPath2(getUserGameDataDir(), GAMECONTROLLER_BASENAME); int num_mappings; #endif int i; if (!sdl_joystick_subsystem_initialized) { sdl_joystick_subsystem_initialized = TRUE; #if defined(TARGET_SDL2) SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) #else if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) #endif { Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError()); return; } #if defined(TARGET_SDL2) num_mappings = SDL_GameControllerAddMappingsFromFile(mappings_file_base); /* the included game controller base mappings should always be found */ if (num_mappings == -1) Error(ERR_WARN, "no game controller base mappings found"); #if DEBUG_JOYSTICKS else Error(ERR_INFO, "%d game controller base mapping(s) added", num_mappings); #endif num_mappings = SDL_GameControllerAddMappingsFromFile(mappings_file_user); #if DEBUG_JOYSTICKS /* the personal game controller user mappings may or may not be found */ if (num_mappings == -1) Error(ERR_WARN, "no game controller user mappings found"); else Error(ERR_INFO, "%d game controller user mapping(s) added", num_mappings); Error(ERR_INFO, "%d joystick(s) found:", SDL_NumJoysticks()); #endif checked_free(mappings_file_base); checked_free(mappings_file_user); #if DEBUG_JOYSTICKS for (i = 0; i < SDL_NumJoysticks(); i++) { const char *name, *type; if (SDL_IsGameController(i)) { name = SDL_GameControllerNameForIndex(i); type = "game controller"; } else { name = SDL_JoystickNameForIndex(i); type = "joystick"; } Error(ERR_INFO, "- joystick %d (%s): '%s'", i, type, (name ? name : "(Unknown)")); } #endif #endif } /* assign joysticks from configured to connected joystick for all players */ for (i = 0; i < MAX_PLAYERS; i++) { /* get configured joystick for this player */ char *device_name = setup.input[i].joy.device_name; int joystick_nr = getJoystickNrFromDeviceName(device_name); if (joystick_nr >= SDL_NumJoysticks()) { if (setup.input[i].use_joystick && print_warning) Error(ERR_WARN, "cannot find joystick %d", joystick_nr); joystick_nr = -1; } /* store configured joystick number for each player */ joystick.nr[i] = joystick_nr; } /* now open all connected joysticks (regardless if configured or not) */ for (i = 0; i < SDL_NumJoysticks(); i++) { /* this allows subsequent calls to 'InitJoysticks' for re-initialization */ if (SDLCheckJoystickOpened(i)) SDLCloseJoystick(i); if (SDLOpenJoystick(i)) joystick.status = JOYSTICK_ACTIVATED; else if (print_warning) Error(ERR_WARN, "cannot open joystick %d", i); } SDLClearJoystickState(); } boolean SDLReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2) { if (nr < 0 || nr >= MAX_PLAYERS) return FALSE; if (x != NULL) *x = sdl_js_axis[nr][0]; if (y != NULL) *y = sdl_js_axis[nr][1]; if (b1 != NULL) *b1 = sdl_js_button[nr][0]; if (b2 != NULL) *b2 = sdl_js_button[nr][1]; return TRUE; } /* ========================================================================= */ /* touch input overlay functions */ /* ========================================================================= */ #if defined(USE_TOUCH_INPUT_OVERLAY) static void DrawTouchInputOverlay() { static SDL_Texture *texture = NULL; static boolean initialized = FALSE; static boolean deactivated = TRUE; static int width = 0, height = 0; static int alpha_max = SDL_ALPHA_OPAQUE / 2; static int alpha_step = 5; static int alpha_last = 0; static int alpha = 0; boolean active = (overlay.enabled && overlay.active); if (!active && deactivated) return; if (active) { if (alpha < alpha_max) alpha = MIN(alpha + alpha_step, alpha_max); deactivated = FALSE; } else { alpha = MAX(0, alpha - alpha_step); if (alpha == 0) deactivated = TRUE; } if (!initialized) { char *basename = "overlay/VirtualButtons.png"; char *filename = getCustomImageFilename(basename); if (filename == NULL) Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename); SDL_Surface *surface; if ((surface = IMG_Load(filename)) == NULL) Error(ERR_EXIT, "IMG_Load() failed: %s", SDL_GetError()); width = surface->w; height = surface->h; /* set black pixel to transparent if no alpha channel / transparent color */ if (!SDLHasAlpha(surface) && !SDLHasColorKey(surface)) SDL_SetColorKey(surface, SET_TRANSPARENT_PIXEL, SDL_MapRGB(surface->format, 0x00, 0x00, 0x00)); if ((texture = SDLCreateTextureFromSurface(surface)) == NULL) Error(ERR_EXIT, "SDLCreateTextureFromSurface() failed"); SDL_FreeSurface(surface); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(texture, alpha_max); initialized = TRUE; } if (alpha != alpha_last) SDL_SetTextureAlphaMod(texture, alpha); alpha_last = alpha; float ratio_overlay = (float) width / height; float ratio_screen = (float) video.screen_width / video.screen_height; int width_scaled, height_scaled; int xpos, ypos; if (ratio_overlay > ratio_screen) { width_scaled = video.screen_width; height_scaled = video.screen_height * ratio_screen / ratio_overlay; xpos = 0; ypos = video.screen_height - height_scaled; } else { width_scaled = video.screen_width * ratio_overlay / ratio_screen; height_scaled = video.screen_height; xpos = (video.screen_width - width_scaled) / 2; ypos = 0; } SDL_Rect src_rect = { 0, 0, width, height }; SDL_Rect dst_rect = { xpos, ypos, width_scaled, height_scaled }; SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect); } #endif mirrormagic-3.0.0/src/libgame/types.h0000644000175000017500000000274313263212010017033 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // types.h // ============================================================================ #ifndef TYPES_H #define TYPES_H #include #include #include #include #include #if !defined(PLATFORM_WIN32) typedef int boolean; typedef unsigned char byte; #endif #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif #ifdef AUTO #undef AUTO #endif #define TRUE 1 #define FALSE 0 #define AUTO -1 #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 #ifndef ODD #define ODD(a) (((a) & 1) == 1) #endif #ifndef EVEN #define EVEN(a) (((a) & 1) == 0) #endif #define SIZEOF_ARRAY(array, type) (sizeof(array) / sizeof(type)) #define SIZEOF_ARRAY_INT(array) SIZEOF_ARRAY(array, int) struct ListNode { char *key; void *content; struct ListNode *prev; struct ListNode *next; }; typedef struct ListNode ListNode; #endif /* TYPES_H */ mirrormagic-3.0.0/src/libgame/platform.h0000644000175000017500000001066713263212010017517 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // platform.h // ============================================================================ #ifndef PLATFORM_H #define PLATFORM_H /* ========================================================================= */ /* define main platform keywords */ /* ========================================================================= */ #if defined(WIN32) || defined(_WIN32) #define PLATFORM_WIN32 #define PLATFORM_STRING "Windows" #else #define PLATFORM_UNIX #define PLATFORM_STRING "Unix" #endif /* ========================================================================= */ /* define additional platform keywords */ /* ========================================================================= */ #if defined(_AIX) #define PLATFORM_AIX #undef PLATFORM_STRING #define PLATFORM_STRING "AIX" #endif #if defined(AMIGA) || defined(__AMIGA) || defined(__amigados__) #define PLATFORM_AMIGA #undef PLATFORM_STRING #define PLATFORM_STRING "AmigaOS" #endif #if defined(__BEOS__) #define PLATFORM_BEOS #undef PLATFORM_STRING #define PLATFORM_STRING "BeOS" #endif #if defined(bsdi) || defined(__bsdi) || defined(__bsdi__) #define PLATFORM_BSDI #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "BSDI" #endif #if defined(_arch_dreamcast) #define PLATFORM_DREAMCAST #undef PLATFORM_STRING #define PLATFORM_STRING "Dreamcast" #endif #if defined(__FreeBSD__) || defined(__DragonFly__) #define PLATFORM_FREEBSD #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "FreeBSD" #endif #if defined(hpux) || defined(__hpux) || defined(__hpux__) #define PLATFORM_HPUX #undef PLATFORM_STRING #define PLATFORM_STRING "HP-UX" #endif #if defined(sgi) || defined(__sgi) || defined(__sgi__) || defined(_SGI_SOURCE) #define PLATFORM_IRIX #undef PLATFORM_STRING #define PLATFORM_STRING "IRIX" #endif #if defined(linux) || defined(__linux) || defined(__linux__) #define PLATFORM_LINUX #undef PLATFORM_STRING #define PLATFORM_STRING "Linux" #endif #if defined(__APPLE__) && defined(__MACH__) #define PLATFORM_MACOSX #undef PLATFORM_STRING #define PLATFORM_STRING "Mac OS X" #endif #if defined(__NetBSD__) #define PLATFORM_NETBSD #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "NetBSD" #endif #if defined(NeXT) #define PLATFORM_NEXT #undef PLATFORM_STRING #define PLATFORM_STRING "NeXT" #endif #if defined(__OpenBSD__) #define PLATFORM_OPENBSD #define PLATFORM_BSD #undef PLATFORM_STRING #define PLATFORM_STRING "OpenBSD" #endif #if defined(__OS2__) #define PLATFORM_OS2 #undef PLATFORM_STRING #define PLATFORM_STRING "OS/2" #endif #if defined(osf) || defined(__osf) || defined(__osf__) || defined(_OSF_SOURCE) #define PLATFORM_OSF #undef PLATFORM_STRING #define PLATFORM_STRING "OSF/1" #endif #if defined(__QNXNTO__) #define PLATFORM_QNX #undef PLATFORM_STRING #define PLATFORM_STRING "QNX" #endif #if defined(riscos) || defined(__riscos) || defined(__riscos__) #define PLATFORM_RISCOS #undef PLATFORM_STRING #define PLATFORM_STRING "RISC OS" #endif #if defined(sparc) || defined(sun) || defined(__SVR4) #define PLATFORM_SOLARIS #undef PLATFORM_STRING #define PLATFORM_STRING "Solaris" #endif #if defined(_WIN32_WCE) #define PLATFORM_WINDOWS_CE #undef PLATFORM_STRING #define PLATFORM_STRING "Windows CE" #endif #if defined(__ANDROID__) #define PLATFORM_ANDROID #undef PLATFORM_STRING #define PLATFORM_STRING "Android" #endif /* ========================================================================= */ /* define additional target keywords */ /* ========================================================================= */ #if defined(TARGET_SDL2) #ifndef TARGET_SDL #define TARGET_SDL #endif #endif /* ========================================================================= */ /* this should better go into "system.h" or "features.h" (yet to be created) */ /* ========================================================================= */ #if defined(PLATFORM_UNIX) || defined(TARGET_SDL) #define NETWORK_AVALIABLE #endif #endif /* PLATFORM_H */ mirrormagic-3.0.0/src/libgame/joystick.h0000644000175000017500000000500613263212010017521 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // joystick.h // ============================================================================ #ifndef JOYSTICK_H #define JOYSTICK_H #include "system.h" #define JOYSTICK_NOT_AVAILABLE 0 #define JOYSTICK_AVAILABLE (1 << 0) #define JOYSTICK_ACTIVE (1 << 1) #define JOYSTICK_CONFIGURED (1 << 2) #define JOYSTICK_NOT_CONFIGURED (1 << 3) #define JOYSTICK_ACTIVATED (JOYSTICK_AVAILABLE | JOYSTICK_ACTIVE) #define MAX_JOYSTICK_NAME_LEN 40 #if defined(PLATFORM_FREEBSD) #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_MAX_AXIS_POS 32767 #define JOYSTICK_XLEFT -JOYSTICK_MAX_AXIS_POS #define JOYSTICK_XMIDDLE 0 #define JOYSTICK_XRIGHT +JOYSTICK_MAX_AXIS_POS #define JOYSTICK_YUPPER -JOYSTICK_MAX_AXIS_POS #define JOYSTICK_YMIDDLE 0 #define JOYSTICK_YLOWER +JOYSTICK_MAX_AXIS_POS #define JOYSTICK_PERCENT 25 #define JOY_NO_ACTION 0 #define JOY_LEFT MV_LEFT #define JOY_RIGHT MV_RIGHT #define JOY_UP MV_UP #define JOY_DOWN MV_DOWN #define JOY_BUTTON_1 KEY_BUTTON_1 #define JOY_BUTTON_2 KEY_BUTTON_2 #define JOY_BUTTON_SNAP KEY_BUTTON_SNAP #define JOY_BUTTON_DROP KEY_BUTTON_DROP #define JOY_MOTION KEY_MOTION #define JOY_BUTTON KEY_BUTTON #define JOY_ACTION KEY_ACTION #define JOY_BUTTON_NOT_PRESSED 0 #define JOY_BUTTON_PRESSED 1 #define JOY_BUTTON_NEW_PRESSED 2 #define JOY_BUTTON_NEW_RELEASED 3 char *getJoyNameFromJoySymbol(int); int getJoySymbolFromJoyName(char *); int getJoystickNrFromDeviceName(char *); char *getDeviceNameFromJoystickNr(int); char *getFormattedJoystickName(const char *); void CheckJoystickData(void); int Joystick(int); int JoystickExt(int, boolean); int JoystickButton(int); int AnyJoystick(void); int AnyJoystickButton(void); void DeactivateJoystick(); void ActivateJoystick(); #endif /* JOYSTICK_H */ mirrormagic-3.0.0/src/libgame/random.h0000644000175000017500000000113513263212010017141 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // random.h // ============================================================================ #ifndef RANDOM_H #define RANDOM_H void srandom_linux_libc(int, unsigned int); int random_linux_libc(int); #endif mirrormagic-3.0.0/src/libgame/android.h0000644000175000017500000000110213263212010017273 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // android.h // ============================================================================ #ifndef ANDROID_H #define ANDROID_H #include #endif /* ANDROID_H */ mirrormagic-3.0.0/src/libgame/Makefile0000644000175000017500000000324313263212010017152 0ustar aeglosaeglos# ============================================================================= # Rocks'n'Diamonds - McDuffin Strikes Back! # ----------------------------------------------------------------------------- # (c) 1995-2014 by Artsoft Entertainment # Holger Schemel # info@artsoft.org # http://www.artsoft.org/ # ----------------------------------------------------------------------------- # src/libgame/Makefile # ============================================================================= # ----------------------------------------------------------------------------- # configuration # ----------------------------------------------------------------------------- SRCS = system.c \ gadgets.c \ text.c \ sound.c \ joystick.c \ snapshot.c \ image.c \ random.c \ hash.c \ setup.c \ misc.c \ sdl.c OBJS = system.o \ gadgets.o \ text.o \ sound.o \ snapshot.o \ joystick.o \ image.o \ random.o \ hash.o \ setup.o \ misc.o \ sdl.o LIBGAME = libgame.a # ----------------------------------------------------------------------------- # build targets # ----------------------------------------------------------------------------- all: $(LIBGAME) $(LIBGAME): $(OBJS) $(AR) cru $(LIBGAME) $(OBJS) $(RANLIB) $(LIBGAME) .c.o: $(CC) $(PROFILING) $(CFLAGS) -c $*.c clean: $(RM) $(OBJS) $(RM) $(LIBGAME) # ----------------------------------------------------------------------------- # development only # ----------------------------------------------------------------------------- depend: for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif mirrormagic-3.0.0/src/libgame/gadgets.h0000644000175000017500000002370713263212010017310 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // gadgets.h // ============================================================================ #ifndef GADGETS_H #define GADGETS_H #include "system.h" #define GADGET_FRAME_DELAY_FIRST 250 /* delay after first click */ #define GADGET_FRAME_DELAY 100 /* delay for pressed butten */ /* gadget types */ #define GD_TYPE_NORMAL_BUTTON (1 << 0) #define GD_TYPE_TEXT_BUTTON (1 << 1) #define GD_TYPE_CHECK_BUTTON (1 << 2) #define GD_TYPE_RADIO_BUTTON (1 << 3) #define GD_TYPE_DRAWING_AREA (1 << 4) #define GD_TYPE_TEXT_INPUT_ALPHANUMERIC (1 << 5) #define GD_TYPE_TEXT_INPUT_NUMERIC (1 << 6) #define GD_TYPE_TEXT_AREA (1 << 7) #define GD_TYPE_SELECTBOX (1 << 8) #define GD_TYPE_SCROLLBAR_VERTICAL (1 << 9) #define GD_TYPE_SCROLLBAR_HORIZONTAL (1 << 10) #define GD_TYPE_BUTTON (GD_TYPE_NORMAL_BUTTON | \ GD_TYPE_TEXT_BUTTON | \ GD_TYPE_CHECK_BUTTON | \ GD_TYPE_RADIO_BUTTON) #define GD_TYPE_SCROLLBAR (GD_TYPE_SCROLLBAR_VERTICAL | \ GD_TYPE_SCROLLBAR_HORIZONTAL) #define GD_TYPE_TEXT_INPUT (GD_TYPE_TEXT_INPUT_ALPHANUMERIC | \ GD_TYPE_TEXT_INPUT_NUMERIC) /* gadget events */ #define GD_EVENT_PRESSED (1 << 0) #define GD_EVENT_RELEASED (1 << 1) #define GD_EVENT_MOVING (1 << 2) #define GD_EVENT_REPEATED (1 << 3) #define GD_EVENT_OFF_BORDERS (1 << 4) #define GD_EVENT_TEXT_RETURN (1 << 5) #define GD_EVENT_TEXT_LEAVING (1 << 6) #define GD_EVENT_INFO_ENTERING (1 << 7) #define GD_EVENT_INFO_LEAVING (1 << 8) #define GD_EVENT_PIXEL_PRECISE (1 << 9) /* gadget button states */ #define GD_BUTTON_UNPRESSED 0 #define GD_BUTTON_PRESSED 1 /* gadget structure constants */ #define MAX_GADGET_TEXTSIZE 1024 #define MAX_INFO_TEXTSIZE 1024 /* gadget creation tags */ #define GDI_END 0 #define GDI_CUSTOM_ID 1 #define GDI_CUSTOM_TYPE_ID 2 #define GDI_X 3 #define GDI_Y 4 #define GDI_WIDTH 5 #define GDI_HEIGHT 6 #define GDI_TYPE 7 #define GDI_STATE 8 #define GDI_CHECKED 9 #define GDI_RADIO_NR 10 #define GDI_NUMBER_VALUE 11 #define GDI_NUMBER_MIN 12 #define GDI_NUMBER_MAX 13 #define GDI_TEXT_VALUE 14 #define GDI_TEXT_SIZE 15 #define GDI_TEXT_FONT 16 #define GDI_TEXT_FONT_ACTIVE 17 #define GDI_TEXT_FONT_UNSELECTABLE 18 #define GDI_SELECTBOX_OPTIONS 19 #define GDI_SELECTBOX_INDEX 20 #define GDI_SELECTBOX_CHAR_UNSELECTABLE 21 #define GDI_DESIGN_UNPRESSED 22 #define GDI_DESIGN_PRESSED 23 #define GDI_ALT_DESIGN_UNPRESSED 24 #define GDI_ALT_DESIGN_PRESSED 25 #define GDI_BORDER_SIZE 26 #define GDI_BORDER_SIZE_SELECTBUTTON 27 #define GDI_DESIGN_WIDTH 28 #define GDI_DECORATION_DESIGN 29 #define GDI_DECORATION_POSITION 30 #define GDI_DECORATION_SIZE 31 #define GDI_DECORATION_SHIFTING 32 #define GDI_DECORATION_MASKED 33 #define GDI_EVENT_MASK 34 #define GDI_EVENT 35 #define GDI_CALLBACK_INFO 36 #define GDI_CALLBACK_ACTION 37 #define GDI_AREA_SIZE 38 #define GDI_ITEM_SIZE 39 #define GDI_SCROLLBAR_ITEMS_MAX 40 #define GDI_SCROLLBAR_ITEMS_VISIBLE 41 #define GDI_SCROLLBAR_ITEM_POSITION 42 #define GDI_WHEEL_AREA_X 43 #define GDI_WHEEL_AREA_Y 44 #define GDI_WHEEL_AREA_WIDTH 45 #define GDI_WHEEL_AREA_HEIGHT 46 #define GDI_INFO_TEXT 47 #define GDI_ACTIVE 48 #define GDI_DIRECT_DRAW 49 /* gadget deactivation hack */ #define GDI_ACTIVE_POS(a) ((a) < 0 ? POS_OFFSCREEN : (a)) typedef void (*gadget_function)(void *); struct GadgetBorder { int xsize, ysize; /* size of gadget border */ int xsize_selectbutton; /* for selectbox gadgets */ int width; /* for selectbox/text input gadgets */ }; struct GadgetDesign { Bitmap *bitmap; /* Bitmap with gadget surface */ int x, y; /* position of rectangle in Bitmap */ }; struct GadgetDecoration { struct GadgetDesign design; /* decoration design structure */ int x, y; /* position of deco on the gadget */ int width, height; /* width and height of decoration */ int xshift, yshift; /* deco shifting when gadget pressed */ boolean masked; /* draw decoration masked over button */ }; struct GadgetEvent { unsigned int type; /* event type */ int button; /* button number for button events */ int mx, my; /* raw gadget position at event time */ int x, y; /* gadget position at event time */ boolean off_borders; /* mouse pointer outside gadget? */ int item_x, item_y, item_position; /* new item position */ }; struct GadgetDrawingArea { int area_xsize, area_ysize; /* size of drawing area (in items) */ int item_xsize, item_ysize; /* size of each item in drawing area */ }; struct GadgetTextButton { char value[MAX_GADGET_TEXTSIZE + 1]; /* text written on the button */ int size; /* maximal size of button text */ }; struct GadgetTextInput { char value[MAX_GADGET_TEXTSIZE + 1]; /* text string in input field */ char last_value[MAX_GADGET_TEXTSIZE + 1];/* last text string in input field */ int cursor_position; /* actual text cursor position */ int number_value; /* integer value, if numeric */ int number_min; /* minimal allowed numeric value */ int number_max; /* maximal allowed numeric value */ int size; /* maximal size of input text */ }; struct GadgetTextArea { char value[MAX_GADGET_TEXTSIZE + 1]; /* text string in input field */ char last_value[MAX_GADGET_TEXTSIZE + 1];/* last text string in input field */ int cursor_position; /* actual text cursor position */ int cursor_x; /* actual x cursor position */ int cursor_y; /* actual y cursor position */ int cursor_x_preferred; /* "preferred" x cursor position */ int size; /* maximal size of input text */ int xsize, ysize; /* size of text area (in chars) */ }; struct GadgetSelectbox { struct ValueTextInfo *options; /* pointer to text/value array */ int index; /* index of actual text string */ int size; /* maximal size of text strings */ char char_unselectable; /* first char of unselectable options */ /* automatically determined values */ int x, y; /* open selectbox position */ int width, height; /* open selectbox size */ int num_values; /* number of text strings */ Pixel inverse_color; /* color for highlighting */ /* runtime values */ boolean open; /* opening state of selectbox */ boolean stay_open; /* open after button release */ int current_index; /* index of text while selecting */ }; struct GadgetScrollbar { int items_max; /* number of items to access */ int items_visible; /* number of visible items */ int item_position; /* actual item position */ int size_min; /* minimal scrollbar size */ int size_max; /* this is either width or height */ int size_max_cmp; /* needed for minimal scrollbar size */ int size; /* scrollbar size on screen */ int position; /* scrollbar position on screen */ int position_max; /* bottom/right scrollbar position */ int drag_position; /* drag position on scrollbar */ int correction; /* scrollbar position correction */ }; struct GadgetWheelArea { int x, y; /* active area for wheel (start) */ int width, height; /* active area for wheel (size) */ }; struct GadgetInfo { boolean deactivated; /* flag to deactivate gadget */ int id; /* internal gadget identifier */ int custom_id; /* custom gadget identifier */ int custom_type_id; /* custom gadget type identifier */ char info_text[MAX_INFO_TEXTSIZE + 1];/* short popup info text */ int x, y; /* gadget position */ int width, height; /* gadget size */ unsigned int type; /* type (button, text input, ...) */ unsigned int state; /* state (pressed, released, ...) */ boolean checked; /* check/radio button state */ int radio_nr; /* number of radio button series */ boolean mapped; /* gadget is mapped on the screen */ boolean active; /* gadget is active */ boolean direct_draw; /* directly draw to frontbuffer */ int font; /* font to use when inactive */ int font_active; /* font to use when active */ int font_unselectable; /* font to use when unselectable */ struct GadgetBorder border; /* gadget border design */ struct GadgetDesign design[2]; /* 0: normal; 1: pressed */ struct GadgetDesign alt_design[2]; /* alternative design */ struct GadgetDecoration deco; /* decoration on top of gadget */ unsigned int event_mask; /* possible events for this gadget */ struct GadgetEvent event; /* actual gadget event */ gadget_function callback_info; /* function for pop-up info text */ gadget_function callback_action; /* function for gadget action */ struct GadgetDrawingArea drawing; /* fields for drawing area gadget */ struct GadgetTextButton textbutton; /* fields for text button gadget */ struct GadgetTextInput textinput; /* fields for text input gadget */ struct GadgetTextArea textarea; /* fields for text area gadget */ struct GadgetSelectbox selectbox; /* fields for selectbox gadget */ struct GadgetScrollbar scrollbar; /* fields for scrollbar gadget */ struct GadgetWheelArea wheelarea; /* fields for scroll wheel area */ struct GadgetInfo *next; /* next list entry */ }; void InitGadgetsSoundCallback(void (*activating_function)(void), void (*selecting_function)(void)); struct GadgetInfo *CreateGadget(int, ...); void FreeGadget(struct GadgetInfo *); void ModifyGadget(struct GadgetInfo *, int, ...); void RedrawGadget(struct GadgetInfo *); void MapGadget(struct GadgetInfo *); void UnmapGadget(struct GadgetInfo *); void UnmapAllGadgets(); void RemapAllGadgets(); boolean anyTextInputGadgetActive(); boolean anyTextAreaGadgetActive(); boolean anySelectboxGadgetActive(); boolean anyScrollbarGadgetActive(); boolean anyTextGadgetActive(); void ClickOnGadget(struct GadgetInfo *, int); boolean HandleGadgets(int, int, int); boolean HandleGadgetsKeyInput(Key); #endif /* GADGETS_H */ mirrormagic-3.0.0/src/libgame/misc.h0000644000175000017500000002122013263212010016611 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // misc.h // ============================================================================ #ifndef MISC_H #define MISC_H #include #include #include #include "system.h" /* values for InitCounter() and Counter() */ #define INIT_COUNTER 0 #define READ_COUNTER 1 /* values for InitRND() */ #define NEW_RANDOMIZE 0 #define RANDOM_ENGINE 0 #define RANDOM_SIMPLE 1 #define InitEngineRandom(seed) init_random_number(RANDOM_ENGINE, seed) #define InitSimpleRandom(seed) init_random_number(RANDOM_SIMPLE, seed) #define GetEngineRandom(max) get_random_number(RANDOM_ENGINE, max) #define GetSimpleRandom(max) get_random_number(RANDOM_SIMPLE, max) /* values for Error() */ #define ERR_UNKNOWN 0 #define ERR_DEBUG (1 << 0) #define ERR_INFO (1 << 1) #define ERR_INFO_LINE (1 << 2) #define ERR_WARN (1 << 3) #define ERR_EXIT (1 << 4) #define ERR_HELP (1 << 5) #define ERR_SOUND_SERVER (1 << 6) #define ERR_NETWORK_SERVER (1 << 7) #define ERR_NETWORK_CLIENT (1 << 8) #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) /* values for getFile...() and putFile...() */ #define BYTE_ORDER_BIG_ENDIAN 0 #define BYTE_ORDER_LITTLE_ENDIAN 1 /* values for cursor bitmap creation */ #define BIT_ORDER_MSB 0 #define BIT_ORDER_LSB 1 /* values for createDirectory() */ #define PERMS_PRIVATE 0 #define PERMS_PUBLIC 1 /* values for general file handling stuff */ #define MAX_FILENAME_LEN 256 #define MAX_LINE_LEN 1024 /* values for general username handling stuff */ #define MAX_USERNAME_LEN 1024 #if defined(PLATFORM_ANDROID) /* values for Android asset handling */ #define ASSET_TOC_BASENAME ".toc" #endif /* structure definitions */ typedef struct { char *filename; FILE *file; boolean end_of_file; #if defined(PLATFORM_ANDROID) boolean file_is_asset; SDL_RWops *asset_file; #endif } File; typedef struct { boolean is_directory; char *basename; char *filename; } DirectoryEntry; typedef struct { char *filename; DIR *dir; DirectoryEntry *dir_entry; #if defined(PLATFORM_ANDROID) boolean directory_is_asset; SDL_RWops *asset_toc_file; char *current_entry; #endif } Directory; /* function definitions */ void fprintf_line(FILE *, char *, int); void fprintf_line_with_prefix(FILE *, char *, char *, int); void printf_line(char *, int); void printf_line_with_prefix(char *, char *, int); void Print(char *, ...); void PrintNoLog(char *, ...); void PrintLine(char *, int); void PrintLineWithPrefix(char *, char *, int); char *int2str(int, int); char *i_to_a(unsigned int); int log_2(unsigned int); boolean getTokenValueFromString(char *, char **, char **); void InitCounter(void); unsigned int Counter(void); void Delay(unsigned int); boolean DelayReachedExt(unsigned int *, unsigned int, unsigned int); boolean FrameReached(unsigned int *, unsigned int); boolean DelayReached(unsigned int *, unsigned int); void ResetDelayCounterExt(unsigned int *, unsigned int); void ResetFrameCounter(unsigned int *); void ResetDelayCounter(unsigned int *); int WaitUntilDelayReached(unsigned int *, unsigned int); void SkipUntilDelayReached(unsigned int *, unsigned int, int *, int); unsigned int init_random_number(int, int); unsigned int get_random_number(int, int); char *getLoginName(void); char *getRealName(void); time_t getFileTimestampEpochSeconds(char *); char *getBasePath(char *); char *getBaseName(char *); char *getBaseNamePtr(char *); char *getBaseNameNoSuffix(char *); char *getStringCat2WithSeparator(char *, char *, char *); char *getStringCat3WithSeparator(char *, char *, char *, char *); char *getStringCat2(char *, char *); char *getStringCat3(char *, char *, char *); char *getPath2(char *, char *); char *getPath3(char *, char *, char*); char *getImg2(char *, char *); char *getImg3(char *, char *, char*); char *getStringCopy(const char *); char *getStringCopyN(const char *, int); char *getStringCopyNStatic(const char *, int); char *getStringToLower(const char *); void setString(char **, char *); boolean strEqual(char *, char *); boolean strEqualN(char *, char *, int); boolean strPrefix(char *, char *); boolean strSuffix(char *, char *); boolean strPrefixLower(char *, char *); boolean strSuffixLower(char *, char *); void GetOptions(int, char **, void (*print_usage_function)(void), void (*print_version_function)(void)); void SetError(char *, ...); char *GetError(void); void Error(int, char *, ...); void *checked_malloc(unsigned int); void *checked_calloc(unsigned int); void *checked_realloc(void *, unsigned int); void checked_free(void *); void clear_mem(void *, unsigned int); void swap_numbers(int *, int *); void swap_number_pairs(int *, int *, int *, int *); int getFile8BitInteger(File *); int putFile8BitInteger(FILE *, int); int getFile16BitInteger(File *, int); int putFile16BitInteger(FILE *, int, int); int getFile32BitInteger(File *, int); int putFile32BitInteger(FILE *, int, int); boolean getFileChunk(File *, char *, int *, int); int putFileChunk(FILE *, char *, int, int); int getFileVersion(File *); int putFileVersion(FILE *, int); void ReadBytesFromFile(File *, byte *, unsigned int); void WriteBytesToFile(FILE *, byte *, unsigned int); void ReadUnusedBytesFromFile(File *, unsigned int); void WriteUnusedBytesToFile(FILE *, unsigned int); #define getFile8Bit(f) getFile8BitInteger(f) #define putFile8Bit(f,x) putFile8BitInteger(f,x) #define getFile16BitBE(f) getFile16BitInteger(f,BYTE_ORDER_BIG_ENDIAN) #define getFile16BitLE(f) getFile16BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN) #define putFile16BitBE(f,x) putFile16BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN) #define putFile16BitLE(f,x) putFile16BitInteger(f,x,BYTE_ORDER_LITTLE_ENDIAN) #define getFile32BitBE(f) getFile32BitInteger(f,BYTE_ORDER_BIG_ENDIAN) #define getFile32BitLE(f) getFile32BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN) #define putFile32BitBE(f,x) putFile32BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN) #define putFile32BitLE(f,x) putFile32BitInteger(f,x,BYTE_ORDER_LITTLE_ENDIAN) #define getFileChunkBE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN) #define getFileChunkLE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_LITTLE_ENDIAN) #define putFileChunkBE(f,s,x) putFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN) #define putFileChunkLE(f,s,x) putFileChunk(f,s,x,BYTE_ORDER_LITTLE_ENDIAN) char *getKeyNameFromKey(Key); char *getX11KeyNameFromKey(Key); Key getKeyFromKeyName(char *); Key getKeyFromX11KeyName(char *); char getCharFromKey(Key); char getValidConfigValueChar(char); int get_integer_from_string(char *); boolean get_boolean_from_string(char *); int get_switch3_from_string(char *); ListNode *newListNode(void); void addNodeToList(ListNode **, char *, void *); void deleteNodeFromList(ListNode **, char *, void (*function)(void *)); ListNode *getNodeFromKey(ListNode *, char *); int getNumNodes(ListNode *); File *openFile(char *, char *); int closeFile(File *); int checkEndOfFile(File *); size_t readFile(File *, void *, size_t, size_t); size_t writeFile(File *, void *, size_t, size_t); int seekFile(File *, long, int); int getByteFromFile(File *); char *getStringFromFile(File *, char *, int); int copyFile(char *, char *); Directory *openDirectory(char *); int closeDirectory(Directory *); DirectoryEntry *readDirectory(Directory *); void freeDirectoryEntry(DirectoryEntry *); boolean directoryExists(char *); boolean fileExists(char *); boolean FileIsGraphic(char *); boolean FileIsSound(char *); boolean FileIsMusic(char *); boolean FileIsArtworkType(char *, int); char *get_mapped_token(char *); int get_parameter_value(char *, char *, int); struct FileInfo *getFileListFromConfigList(struct ConfigInfo *, struct ConfigTypeInfo *, char **, int); void LoadArtworkConfig(struct ArtworkListInfo *); void ReloadCustomArtworkList(struct ArtworkListInfo *); void FreeCustomArtworkLists(struct ArtworkListInfo *); char *getLogFilename(char *); void OpenLogFiles(); void CloseLogFiles(); void DumpLogFile(int); void NotifyUserAboutErrorFile(); #if DEBUG void debug_print_timestamp(int, char *); #endif void print_timestamp_init(char *); void print_timestamp_time(char *); void print_timestamp_done(char *); #endif /* MISC_H */ mirrormagic-3.0.0/src/libgame/setup.h0000644000175000017500000002632413263212010017030 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // setup.h // ============================================================================ #ifndef SETUP_H #define SETUP_H #include "system.h" #include "hash.h" /* values for setup file handling */ #define TYPE_BOOLEAN (1 << 0) #define TYPE_SWITCH (1 << 1) #define TYPE_SWITCH3 (1 << 2) #define TYPE_YES_NO (1 << 3) #define TYPE_YES_NO_AUTO (1 << 4) #define TYPE_ECS_AGA (1 << 5) #define TYPE_KEY (1 << 6) #define TYPE_KEY_X11 (1 << 7) #define TYPE_INTEGER (1 << 8) #define TYPE_STRING (1 << 9) #define TYPE_ELEMENT (1 << 10) #define TYPE_GRAPHIC (1 << 11) /* additional values for setup screen */ #define TYPE_ENTER_SCREEN (1 << 12) #define TYPE_LEAVE_SCREEN (1 << 13) #define TYPE_ENTER_MENU (1 << 14) #define TYPE_LEAVE_MENU (1 << 15) #define TYPE_ENTER_LIST (1 << 16) #define TYPE_LEAVE_LIST (1 << 17) #define TYPE_EMPTY (1 << 18) #define TYPE_KEYTEXT (1 << 19) #define TYPE_GHOSTED (1 << 20) #define TYPE_QUERY (1 << 21) /* additional values for internal purposes */ #define TYPE_BITFIELD (1 << 22) #define TYPE_CONTENT (1 << 23) #define TYPE_ELEMENT_LIST (1 << 24) #define TYPE_CONTENT_LIST (1 << 25) /* derived values for setup file handling */ #define TYPE_BOOLEAN_STYLE (TYPE_BOOLEAN | \ TYPE_SWITCH | \ TYPE_YES_NO | \ TYPE_ECS_AGA ) /* derived values for setup screen */ #define TYPE_VALUE (TYPE_BOOLEAN_STYLE | \ TYPE_SWITCH3 | \ TYPE_YES_NO_AUTO | \ TYPE_KEY | \ TYPE_KEY_X11 | \ TYPE_INTEGER | \ TYPE_STRING | \ TYPE_ELEMENT | \ TYPE_GRAPHIC) #define TYPE_SKIP_ENTRY (TYPE_EMPTY | \ TYPE_KEY | \ TYPE_STRING | \ TYPE_GHOSTED) #define TYPE_ENTER (TYPE_ENTER_SCREEN | \ TYPE_ENTER_MENU | \ TYPE_ENTER_LIST) #define TYPE_LEAVE (TYPE_LEAVE_SCREEN | \ TYPE_LEAVE_MENU | \ TYPE_LEAVE_LIST) #define TYPE_ENTER_OR_LEAVE (TYPE_ENTER | TYPE_LEAVE) struct TokenInfo { int type; void *value; char *text; }; /* some definitions for list and hash handling */ typedef struct SetupFileList SetupFileList; typedef struct hashtable SetupFileHash; #define BEGIN_HASH_ITERATION(hash, itr) \ if (hash != NULL && hashtable_count(hash) > 0) \ { \ struct hashtable_itr *itr = hashtable_iterator(hash); \ do { \ #define HASH_ITERATION_TOKEN(itr) ((char *)hashtable_iterator_key(itr)) #define HASH_ITERATION_VALUE(itr) ((char *)hashtable_iterator_value(itr)) #define END_HASH_ITERATION(hash, itr) \ } while (hashtable_iterator_advance(itr)); \ free(itr); \ } \ /* sort priorities of level series (also used as level series classes) */ #define LEVELCLASS_TUTORIAL_START 10 #define LEVELCLASS_TUTORIAL_END 99 #define LEVELCLASS_CLASSICS_START 100 #define LEVELCLASS_CLASSICS_END 199 #define LEVELCLASS_CONTRIB_START 200 #define LEVELCLASS_CONTRIB_END 299 #define LEVELCLASS_PRIVATE_START 300 #define LEVELCLASS_PRIVATE_END 399 #define LEVELCLASS_BD_START 400 #define LEVELCLASS_BD_END 499 #define LEVELCLASS_EM_START 500 #define LEVELCLASS_EM_END 599 #define LEVELCLASS_SP_START 600 #define LEVELCLASS_SP_END 699 #define LEVELCLASS_DX_START 700 #define LEVELCLASS_DX_END 799 #define LEVELCLASS_SB_START 800 #define LEVELCLASS_SB_END 899 #define LEVELCLASS_PREDEFINED_START LEVELCLASS_TUTORIAL_START #define LEVELCLASS_PREDEFINED_END LEVELCLASS_SB_END #define LEVELCLASS_TUTORIAL LEVELCLASS_TUTORIAL_START #define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START #define LEVELCLASS_CONTRIB LEVELCLASS_CONTRIB_START #define LEVELCLASS_PRIVATE LEVELCLASS_PRIVATE_START #define LEVELCLASS_BD LEVELCLASS_BD_START #define LEVELCLASS_EM LEVELCLASS_EM_START #define LEVELCLASS_SP LEVELCLASS_SP_START #define LEVELCLASS_DX LEVELCLASS_DX_START #define LEVELCLASS_SB LEVELCLASS_SB_START #define LEVELCLASS_UNDEFINED 999 #define IS_LEVELCLASS_TUTORIAL(p) \ ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \ (p)->sort_priority <= LEVELCLASS_TUTORIAL_END) #define IS_LEVELCLASS_CLASSICS(p) \ ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \ (p)->sort_priority <= LEVELCLASS_CLASSICS_END) #define IS_LEVELCLASS_CONTRIB(p) \ ((p)->sort_priority >= LEVELCLASS_CONTRIB_START && \ (p)->sort_priority <= LEVELCLASS_CONTRIB_END) #define IS_LEVELCLASS_PRIVATE(p) \ ((p)->sort_priority >= LEVELCLASS_PRIVATE_START && \ (p)->sort_priority <= LEVELCLASS_PRIVATE_END) #define IS_LEVELCLASS_BD(p) \ ((p)->sort_priority >= LEVELCLASS_BD_START && \ (p)->sort_priority <= LEVELCLASS_BD_END) #define IS_LEVELCLASS_EM(p) \ ((p)->sort_priority >= LEVELCLASS_EM_START && \ (p)->sort_priority <= LEVELCLASS_EM_END) #define IS_LEVELCLASS_SP(p) \ ((p)->sort_priority >= LEVELCLASS_SP_START && \ (p)->sort_priority <= LEVELCLASS_SP_END) #define IS_LEVELCLASS_DX(p) \ ((p)->sort_priority >= LEVELCLASS_DX_START && \ (p)->sort_priority <= LEVELCLASS_DX_END) #define IS_LEVELCLASS_SB(p) \ ((p)->sort_priority >= LEVELCLASS_SB_START && \ (p)->sort_priority <= LEVELCLASS_SB_END) #define IS_LEVELCLASS_UNDEFINED(p) \ ((p)->sort_priority < LEVELCLASS_PREDEFINED_START || \ (p)->sort_priority > LEVELCLASS_PREDEFINED_END) #define LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \ IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \ IS_LEVELCLASS_CONTRIB(n) ? LEVELCLASS_CONTRIB : \ IS_LEVELCLASS_PRIVATE(n) ? LEVELCLASS_PRIVATE : \ IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \ IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \ IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \ IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \ IS_LEVELCLASS_SB(n) ? LEVELCLASS_SB : \ LEVELCLASS_UNDEFINED) /* sort priorities of artwork */ #define ARTWORKCLASS_CLASSICS_START 100 #define ARTWORKCLASS_CLASSICS_END 199 #define ARTWORKCLASS_CONTRIB_START 200 #define ARTWORKCLASS_CONTRIB_END 299 #define ARTWORKCLASS_PRIVATE_START 300 #define ARTWORKCLASS_PRIVATE_END 399 #define ARTWORKCLASS_LEVEL_START 400 #define ARTWORKCLASS_LEVEL_END 499 #define ARTWORKCLASS_CLASSICS ARTWORKCLASS_CLASSICS_START #define ARTWORKCLASS_CONTRIB ARTWORKCLASS_CONTRIB_START #define ARTWORKCLASS_PRIVATE ARTWORKCLASS_PRIVATE_START #define ARTWORKCLASS_LEVEL ARTWORKCLASS_LEVEL_START #define ARTWORKCLASS_UNDEFINED 999 #define IS_ARTWORKCLASS_CLASSICS(p) \ ((p)->sort_priority >= ARTWORKCLASS_CLASSICS_START && \ (p)->sort_priority <= ARTWORKCLASS_CLASSICS_END) #define IS_ARTWORKCLASS_CONTRIB(p) \ ((p)->sort_priority >= ARTWORKCLASS_CONTRIB_START && \ (p)->sort_priority <= ARTWORKCLASS_CONTRIB_END) #define IS_ARTWORKCLASS_PRIVATE(p) \ ((p)->sort_priority >= ARTWORKCLASS_PRIVATE_START && \ (p)->sort_priority <= ARTWORKCLASS_PRIVATE_END) #define IS_ARTWORKCLASS_LEVEL(p) \ ((p)->sort_priority >= ARTWORKCLASS_LEVEL_START && \ (p)->sort_priority <= ARTWORKCLASS_LEVEL_END) #define ARTWORKCLASS(n) (IS_ARTWORKCLASS_CLASSICS(n) ? ARTWORKCLASS_CLASSICS :\ IS_ARTWORKCLASS_CONTRIB(n) ? ARTWORKCLASS_CONTRIB : \ IS_ARTWORKCLASS_PRIVATE(n) ? ARTWORKCLASS_PRIVATE : \ IS_ARTWORKCLASS_LEVEL(n) ? ARTWORKCLASS_LEVEL : \ ARTWORKCLASS_UNDEFINED) char *setLevelArtworkDir(TreeInfo *); char *getProgramMainDataPath(char *, char *); char *getProgramConfigFilename(char *); char *getTapeFilename(int); char *getSolutionTapeFilename(int); char *getScoreFilename(int); char *getSetupFilename(void); char *getDefaultSetupFilename(void); char *getEditorSetupFilename(void); char *getHelpAnimFilename(void); char *getHelpTextFilename(void); char *getLevelSetInfoFilename(void); char *getLevelSetTitleMessageFilename(int, boolean); char *getImageFilename(char *); char *getCustomImageFilename(char *); char *getCustomSoundFilename(char *); char *getCustomMusicFilename(char *); char *getCustomArtworkFilename(char *, int); char *getCustomArtworkConfigFilename(int); char *getCustomArtworkLevelConfigFilename(int); char *getCustomMusicDirectory(void); void InitTapeDirectory(char *); void InitScoreDirectory(char *); void InitUserLevelDirectory(char *); void InitLevelSetupDirectory(char *); TreeInfo *newTreeInfo(); TreeInfo *newTreeInfo_setDefaults(int); void pushTreeInfo(TreeInfo **, TreeInfo *); int numTreeInfo(TreeInfo *); boolean validLevelSeries(TreeInfo *); TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *); TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *); int numTreeInfoInGroup(TreeInfo *); int posTreeInfo(TreeInfo *); TreeInfo *getTreeInfoFromPos(TreeInfo *, int); TreeInfo *getTreeInfoFromIdentifier(TreeInfo *, char *); void dumpTreeInfo(TreeInfo *, int); void sortTreeInfoBySortFunction(TreeInfo **, int (*compare_function)(const void *, const void *)); void sortTreeInfo(TreeInfo **); void freeTreeInfo(TreeInfo *); char *getHomeDir(void); char *getCommonDataDir(void); char *getPersonalDataDir(void); char *getUserGameDataDir(void); char *getSetupDir(void); char *getUserLevelDir(char *); char *getCurrentLevelDir(void); char *getNewUserLevelSubdir(void); void createDirectory(char *, char *, int); void InitUserDataDirectory(void); void SetFilePermissions(char *, int); char *getCookie(char *); void fprintFileHeader(FILE *, char *); int getFileVersionFromCookieString(const char *); boolean checkCookieString(const char *, const char *); char *getFormattedSetupEntry(char *, char *); boolean getTokenValueFromSetupLine(char *, char **, char **); SetupFileList *newSetupFileList(char *, char *); void freeSetupFileList(SetupFileList *); char *getListEntry(SetupFileList *, char *); SetupFileList *setListEntry(SetupFileList *, char *, char *); SetupFileList *addListEntry(SetupFileList *, char *, char *); SetupFileList *loadSetupFileList(char *); SetupFileHash *newSetupFileHash(); void freeSetupFileHash(SetupFileHash *); char *getHashEntry(SetupFileHash *, char *); void setHashEntry(SetupFileHash *, char *, char *); char *removeHashEntry(SetupFileHash *, char *); SetupFileHash *loadSetupFileHash(char *); void setSetupInfo(struct TokenInfo *, int, char *); char *getSetupValue(int, void *); char *getSetupLine(struct TokenInfo *, char *, int); unsigned int get_hash_from_key(void *); boolean AdjustGraphicsForEMC(); void LoadLevelInfo(void); void LoadArtworkInfo(void); void LoadLevelArtworkInfo(void); char *getArtworkIdentifierForUserLevelSet(int); TreeInfo *getArtworkTreeInfoForUserLevelSet(int); boolean checkIfCustomArtworkExistsForCurrentLevelSet(); void AddUserLevelSetToLevelInfo(char *); boolean UpdateUserLevelSet(char *, char *, char *, int); boolean CreateUserLevelSet(char *, char *, char *, int, boolean); void LoadLevelSetup_LastSeries(void); void SaveLevelSetup_LastSeries(void); void SaveLevelSetup_LastSeries_Deactivate(); void LoadLevelSetup_SeriesInfo(void); void SaveLevelSetup_SeriesInfo(void); int LevelStats_getPlayed(int); int LevelStats_getSolved(int); void LevelStats_setPlayed(int, int); void LevelStats_setSolved(int, int); void LevelStats_incPlayed(int); void LevelStats_incSolved(int); #endif /* MISC_H */ mirrormagic-3.0.0/src/libgame/image.h0000644000175000017500000000455313263212010016752 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // image.h // ============================================================================ #ifndef IMAGE_H #define IMAGE_H #include "system.h" // these bitmap pointers either point to allocated bitmaps or are NULL #define IMG_BITMAP_32x32 0 #define IMG_BITMAP_16x16 1 #define IMG_BITMAP_8x8 2 #define IMG_BITMAP_4x4 3 #define IMG_BITMAP_2x2 4 #define IMG_BITMAP_1x1 5 #define IMG_BITMAP_CUSTOM 6 #define NUM_IMG_BITMAPS 7 // this bitmap pointer points to one of the above bitmaps (do not free it) #define IMG_BITMAP_GAME 7 #define NUM_IMG_BITMAP_POINTERS 8 // this bitmap pointer points to the bitmap with default image size #define IMG_BITMAP_STANDARD IMG_BITMAP_32x32 #define GET_BITMAP_ID_FROM_TILESIZE(x) ((x) == 1 ? IMG_BITMAP_1x1 : \ (x) == 2 ? IMG_BITMAP_2x2 : \ (x) == 4 ? IMG_BITMAP_4x4 : \ (x) == 8 ? IMG_BITMAP_8x8 : \ (x) == 16 ? IMG_BITMAP_16x16 : \ (x) == 32 ? IMG_BITMAP_32x32 : \ IMG_BITMAP_CUSTOM) #define GET_TILESIZE_FROM_BITMAP_ID(x) ((x) == IMG_BITMAP_1x1 ? 1 : \ (x) == IMG_BITMAP_2x2 ? 2 : \ (x) == IMG_BITMAP_4x4 ? 4 : \ (x) == IMG_BITMAP_8x8 ? 8 : \ (x) == IMG_BITMAP_16x16 ? 16 : \ (x) == IMG_BITMAP_32x32 ? 32 : \ 0) int getImageListSize(); struct FileInfo *getImageListEntryFromImageID(int); Bitmap **getBitmapsFromImageID(int); int getOriginalImageWidthFromImageID(int); int getOriginalImageHeightFromImageID(int); char *getTokenFromImageID(int); char *getFilenameFromImageID(int); int getImageIDFromToken(char *); char *getImageConfigFilename(); int getImageListPropertyMappingSize(); struct PropertyMapping *getImageListPropertyMapping(); void InitImageList(struct ConfigInfo *, int, struct ConfigTypeInfo *, char **, char **, char **, char **, char **); void ReloadCustomImages(); void CreateImageWithSmallImages(int, int, int); void CreateImageTextures(int); void FreeAllImageTextures(); void ScaleImage(int, int); void FreeAllImages(); #endif /* IMAGE_H */ mirrormagic-3.0.0/src/libgame/hash.c0000644000175000017500000002373213263212010016606 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // hash.c // ============================================================================ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software and its documentation and acknowledgment shall be * given in the documentation and software packages that this Software was * used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "hash.h" /*****************************************************************************/ struct hashtable * create_hashtable(unsigned int minsize, float maxloadfactor, unsigned int (*hashf) (void*), int (*eqf) (void*,void*)) { struct hashtable *h; unsigned int i, size = 1u; /* Check requested hashtable isn't too large */ if (minsize > (1u << 31)) return NULL; /* Enforce size as power of 2 */ while (size < minsize) size <<= 1; h = (struct hashtable *)malloc(sizeof(struct hashtable)); if (h == NULL) return NULL; h->table = (struct entry **)malloc(sizeof(struct entry*) * size); if (h->table == NULL) { free(h); return NULL; } for (i=0; i < size; i++) h->table[i] = NULL; h->tablelength = size; h->entrycount = 0; h->hashfn = hashf; h->eqfn = eqf; h->loadlimit = (unsigned int) ((float)size * maxloadfactor); return h; } /*****************************************************************************/ static unsigned int hash(struct hashtable *h, void *k) { /* Aim to protect against poor hash functions by adding logic here * - logic taken from java 1.4 hashtable source */ unsigned int i = h->hashfn(k); i += ~(i << 9); i ^= ((i >> 14) | (i << 18)); /* >>> */ i += (i << 4); i ^= ((i >> 10) | (i << 22)); /* >>> */ return i; } /*****************************************************************************/ static unsigned int indexFor(unsigned int tablelength, unsigned int hashvalue) { /* Only works if tablelength == 2^N */ return (hashvalue & (tablelength - 1u)); } /*****************************************************************************/ static int hashtable_expand(struct hashtable *h) { /* Double the size of the table to accomodate more entries */ struct entry **newtable; struct entry *e; struct entry **pE; unsigned int newsize, i, index; /* Check we're not hitting max capacity */ if (0 == (newsize = (h->tablelength << 1))) return 0; newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); if (newtable != NULL) { memset(newtable, 0, newsize * sizeof(struct entry *)); /* This algorithm is not 'stable'. ie. it reverses the list * when it transfers entries between the tables */ for (i = 0; i < h->tablelength; i++) { while ((e = h->table[i]) != NULL) { h->table[i] = e->next; index = indexFor(newsize,e->h); e->next = newtable[index]; newtable[index] = e; } } free(h->table); h->table = newtable; } else /* Plan B: realloc instead */ { newtable = (struct entry **) realloc(h->table, newsize * sizeof(struct entry *)); if (newtable == NULL) return 0; h->table = newtable; for (i = h->tablelength; i < newsize; i++) newtable[i] = NULL; for (i = 0; i < h->tablelength; i++) { for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { index = indexFor(newsize,e->h); if (index == i) { pE = &(e->next); } else { *pE = e->next; e->next = newtable[index]; newtable[index] = e; } } } } h->tablelength = newsize; h->loadlimit <<= 1; return -1; } /*****************************************************************************/ unsigned int hashtable_count(struct hashtable *h) { return h->entrycount; } /*****************************************************************************/ int hashtable_insert(struct hashtable *h, void *k, void *v) { /* This method allows duplicate keys - but they shouldn't be used */ unsigned int index; struct entry *e; if (++(h->entrycount) > h->loadlimit) { /* Ignore the return value. If expand fails, we should * still try cramming just this value into the existing table * -- we may not have memory for a larger table, but one more * element may be ok. Next time we insert, we'll try expanding again.*/ hashtable_expand(h); } e = (struct entry *)malloc(sizeof(struct entry)); if (e == NULL) { --(h->entrycount); return 0; } e->h = hash(h,k); index = indexFor(h->tablelength,e->h); e->k = k; e->v = v; e->next = h->table[index]; h->table[index] = e; return -1; } /*****************************************************************************/ int hashtable_change(struct hashtable *h, void *k, void *v) { struct entry *e; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; while (e != NULL) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { free(e->v); e->v = v; return -1; } e = e->next; } return 0; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_search(struct hashtable *h, void *k) { struct entry *e; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; while (e != NULL) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v; e = e->next; } return NULL; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_remove(struct hashtable *h, void *k) { /* TODO: consider compacting the table when the load factor drops enough, * or provide a 'compact' method. */ struct entry *e; struct entry **pE; void *v; unsigned int index = indexFor(h->tablelength,hash(h,k)); pE = &(h->table[index]); e = *pE; while (e != NULL) { if (h->eqfn(k, e->k)) { *pE = e->next; h->entrycount--; v = e->v; free(e->k); free(e); return v; } pE = &(e->next); e = e->next; } return NULL; } /*****************************************************************************/ /* destroy */ void hashtable_destroy(struct hashtable *h, int free_values) { unsigned int i; struct entry *e, *f; struct entry **table = h->table; for (i = 0; i < h->tablelength; i++) { e = table[i]; while (e != NULL) { f = e; e = e->next; free(f->k); if (free_values) free(f->v); free(f); } } free(h->table); free(h); } /*****************************************************************************/ /* hashtable_iterator - iterator constructor */ struct hashtable_itr * hashtable_iterator(struct hashtable *h) { unsigned int i, tablelength; struct hashtable_itr *itr = (struct hashtable_itr *) malloc(sizeof(struct hashtable_itr)); if (itr == NULL) return NULL; itr->h = h; itr->e = NULL; tablelength = h->tablelength; itr->index = tablelength; if (0 == h->entrycount) return itr; for (i = 0; i < tablelength; i++) { if (h->table[i] != NULL) { itr->e = h->table[i]; itr->index = i; break; } } return itr; } /*****************************************************************************/ /* key - return the key of the (key,value) pair at the current position */ void * hashtable_iterator_key(struct hashtable_itr *i) { return i->e->k; } /*****************************************************************************/ /* value - return the value of the (key,value) pair at the current position */ void * hashtable_iterator_value(struct hashtable_itr *i) { return i->e->v; } /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr) { unsigned int j,tablelength; struct entry **table; struct entry *next; if (itr->e == NULL) return 0; /* stupidity check */ next = itr->e->next; if (next != NULL) { itr->e = next; return -1; } tablelength = itr->h->tablelength; if (tablelength <= (j = ++(itr->index))) { itr->e = NULL; return 0; } table = itr->h->table; while ((next = table[j]) == NULL) { if (++j >= tablelength) { itr->index = tablelength; return 0; } } itr->index = j; itr->e = next; return -1; } mirrormagic-3.0.0/src/libgame/joystick.c0000644000175000017500000001701613263212010017520 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // joystick.c // ============================================================================ #if defined(PLATFORM_FREEBSD) #include #endif #include "joystick.h" #include "misc.h" /* ========================================================================= */ /* platform independent joystick functions */ /* ========================================================================= */ #define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0 #define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1 void translate_joyname(int *joysymbol, char **name, int mode) { static struct { 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" }, }; int i; if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME) { *name = "[undefined]"; 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) { *joysymbol = 0; for (i = 0; i < 6; i++) { if (strEqual(*name, translate_joy[i].name)) { *joysymbol = translate_joy[i].joysymbol; break; } } } } char *getJoyNameFromJoySymbol(int joysymbol) { char *name; translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME); return name; } int getJoySymbolFromJoyName(char *name) { int joysymbol; 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; } char *getDeviceNameFromJoystickNr(int joystick_nr) { static char *joystick_device_name[MAX_PLAYERS] = { DEV_JOYSTICK_0, DEV_JOYSTICK_1, DEV_JOYSTICK_2, DEV_JOYSTICK_3 }; return (joystick_nr >= 0 && joystick_nr <= 3 ? joystick_device_name[joystick_nr] : ""); } char *getFormattedJoystickName(const char *name_raw) { static char name[MAX_JOYSTICK_NAME_LEN + 1]; boolean name_skip_space = TRUE; int i, j; if (name_raw == NULL) name_raw = "(unknown joystick)"; // copy joystick name, cutting leading and multiple spaces for (i = 0, j = 0; i < strlen(name_raw) && i < MAX_JOYSTICK_NAME_LEN; i++) { if (name_raw[i] != ' ') { name[j++] = name_raw[i]; name_skip_space = FALSE; } else if (!name_skip_space) { name[j++] = name_raw[i]; name_skip_space = TRUE; } } // cut trailing space if (j > 0 && name[j - 1] == ' ') j--; name[j] = '\0'; return name; } static int JoystickPositionPercent(int center, int border, int actual) { int range, position; int percent; if (border < center && actual > center) return 0; if (border > center && actual < center) return 0; range = ABS(border - center); position = ABS(actual - center); percent = (int)(position * 100 / range); if (percent > 100) percent = 100; return percent; } void CheckJoystickData() { int i; int distance = 100; for (i = 0; i < MAX_PLAYERS; i++) { if (setup.input[i].joy.xleft >= 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; } } int JoystickExt(int player_nr, boolean use_as_joystick_nr) { int joystick_nr = joystick.nr[player_nr]; int js_x, js_y; boolean js_b1, js_b2; int left, right, up, down; int result = JOY_NO_ACTION; if (use_as_joystick_nr) joystick_nr = player_nr; if (joystick.status != JOYSTICK_ACTIVATED) return JOY_NO_ACTION; if (joystick_nr < 0) return JOY_NO_ACTION; if (!ReadJoystick(joystick_nr, &js_x, &js_y, &js_b1, &js_b2)) { Error(ERR_WARN, "cannot read joystick device '%s'", setup.input[player_nr].joy.device_name); joystick.status = JOYSTICK_NOT_AVAILABLE; return JOY_NO_ACTION; } left = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle, setup.input[player_nr].joy.xleft, js_x); right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle, setup.input[player_nr].joy.xright, js_x); up = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle, setup.input[player_nr].joy.yupper, js_y); down = JoystickPositionPercent(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; } int Joystick(int player_nr) { return JoystickExt(player_nr, FALSE); } int JoystickButtonExt(int player_nr, boolean use_as_joystick_nr) { static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 }; int joy_button = (JoystickExt(player_nr, use_as_joystick_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 JoystickButton(int player_nr) { return JoystickButtonExt(player_nr, FALSE); } int AnyJoystick() { int i; int result = 0; for (i = 0; i < MAX_PLAYERS; i++) result |= JoystickExt(i, TRUE); return result; } int AnyJoystickButton() { int i; int result = JOY_BUTTON_NOT_PRESSED; for (i = 0; i < MAX_PLAYERS; i++) { result = JoystickButtonExt(i, TRUE); if (result != JOY_BUTTON_NOT_PRESSED) break; } return result; } void DeactivateJoystick() { /* Temporarily deactivate joystick. This is needed for calibration screens, where the player has to select a joystick device that should be calibrated. If there is a totally uncalibrated joystick active, it may be impossible (due to messed up input from joystick) to select the joystick device to calibrate even when trying to use the mouse or keyboard to select the device. */ if (joystick.status & JOYSTICK_AVAILABLE) joystick.status &= ~JOYSTICK_ACTIVE; } void ActivateJoystick() { /* reactivate temporarily deactivated joystick */ if (joystick.status & JOYSTICK_AVAILABLE) joystick.status |= JOYSTICK_ACTIVE; } mirrormagic-3.0.0/src/libgame/snapshot.h0000644000175000017500000000233613263212010017524 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // snapshot.h // ============================================================================ #ifndef SNAPSHOT_H #define SNAPSHOT_H #include "system.h" #include "misc.h" #define SNAPSHOT_MEMORY_DEFAULT (512 * 1024 * 1024) /* needed for comfortably saving engine snapshot buffers */ #define ARGS_ADDRESS_AND_SIZEOF(x) (&(x)), (sizeof(x)) struct SnapshotNodeInfo { void *buffer_orig; void *buffer_copy; int size; }; void SaveSnapshotBuffer(ListNode **, void *, int); void LoadSnapshotBuffers(ListNode *); void FreeSnapshotBuffers(ListNode *); void SaveSnapshotSingle(ListNode *); void SaveSnapshotToList(ListNode *); boolean LoadSnapshotSingle(); boolean LoadSnapshotFromList_Older(int); boolean LoadSnapshotFromList_Newer(int); boolean CheckSnapshotList(); void FreeSnapshotSingle(); void FreeSnapshotList(); #endif /* SNAPSHOT_H */ mirrormagic-3.0.0/src/libgame/hash.h0000644000175000017500000002217113263212010016607 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // hash.h // ============================================================================ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software and its documentation and acknowledgment shall be * given in the documentation and software packages that this Software was * used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #ifndef HASH_H #define HASH_H /* Example of use: * * struct hashtable *h; * struct some_key *k; * struct some_value *v; * * static unsigned int hash_from_key_fn( void *k ); * static int keys_equal_fn ( void *key1, void *key2 ); * * h = create_hashtable(16, 0.75, hash_from_key_fn, keys_equal_fn); * k = (struct some_key *) malloc(sizeof(struct some_key)); * v = (struct some_value *) malloc(sizeof(struct some_value)); * * (initialise k and v to suitable values) * * if (! hashtable_insert(h,k,v) ) * { exit(-1); } * * if (NULL == (found = hashtable_search(h,k) )) * { printf("not found!"); } * * if (NULL == (found = hashtable_remove(h,k) )) * { printf("Not found\n"); } * */ /* Macros may be used to define type-safe(r) hashtable access functions, with * methods specialized to take known key and value types as parameters. * * Example: * * Insert this at the start of your file: * * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); * * This defines the functions 'insert_some', 'search_some' and 'remove_some'. * These operate just like hashtable_insert etc., with the same parameters, * but their function signatures have 'struct some_key *' rather than * 'void *', and hence can generate compile time errors if your program is * supplying incorrect data as a key (and similarly for value). * * Note that the hash and key equality functions passed to create_hashtable * still take 'void *' parameters instead of 'some key *'. This shouldn't be * a difficult issue as they're only defined and passed once, and the other * functions will ensure that only valid keys are supplied to them. * * The cost for this checking is increased code size and runtime overhead * - if performance is important, it may be worth switching back to the * unsafe methods once your program has been debugged with the safe methods. * This just requires switching to some simple alternative defines - eg: * #define insert_some hashtable_insert * */ /*****************************************************************************/ struct entry { void *k, *v; unsigned int h; struct entry *next; }; struct hashtable { unsigned int tablelength; struct entry **table; unsigned int entrycount; unsigned int loadlimit; unsigned int (*hashfn) (void *k); int (*eqfn) (void *k1, void *k2); }; /*****************************************************************************/ struct hashtable_itr { struct hashtable *h; struct entry *e; unsigned int index; }; /***************************************************************************** * create_hashtable * @name create_hashtable * @param minsize minimum initial size of hashtable * @param maxloadfactor maximum ratio entries / tablesize * @param hashfunction function for hashing keys * @param key_eq_fn function for determining key equality * @return newly created hashtable or NULL on failure */ struct hashtable * create_hashtable(unsigned int minsize, float maxloadfactor, unsigned int (*hashfunction) (void*), int (*key_eq_fn) (void*,void*)); /***************************************************************************** * hashtable_insert * @name hashtable_insert * @param h the hashtable to insert into * @param k the key - hashtable claims ownership and will free on removal * @param v the value - does not claim ownership * @return non-zero for successful insertion * * This function will cause the table to expand if the insertion would take * the ratio of entries to table size over the maximum load factor. * * This function does not check for repeated insertions with a duplicate key. * The value returned when using a duplicate key is undefined -- when * the hashtable changes size, the order of retrieval of duplicate key * entries is reversed. * If in doubt, remove before insert. */ int hashtable_insert(struct hashtable *h, void *k, void *v); #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ int fnname (struct hashtable *h, keytype *k, valuetype *v) \ { \ return hashtable_insert(h,k,v); \ } /***************************************************************************** * hashtable_change * @name hashtable_change * @param h the hashtable to search * @param k the key of the entry to change * @param v the new value * @return non-zero for successful change */ int hashtable_change(struct hashtable *h, void *k, void *v); #define DEFINE_HASHTABLE_CHANGE(fnname, keytype, valuetype) \ int fnname (struct hashtable *h, keytype *k, valuetype *v) \ { \ return hashtable_change(h,k,v); \ } /***************************************************************************** * hashtable_search * @name hashtable_search * @param h the hashtable to search * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * hashtable_search(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_search(h,k)); \ } /***************************************************************************** * hashtable_remove * @name hashtable_remove * @param h the hashtable to remove the item from * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * /* returns value */ hashtable_remove(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_remove(h,k)); \ } /***************************************************************************** * hashtable_count * @name hashtable_count * @return the number of items stored in the hashtable */ unsigned int hashtable_count(struct hashtable *h); /***************************************************************************** * hashtable_destroy * @name hashtable_destroy * @param free_values whether to call 'free' on the remaining values */ void hashtable_destroy(struct hashtable *h, int free_values); /*****************************************************************************/ /* hashtable_iterator */ struct hashtable_itr * hashtable_iterator(struct hashtable *h); /*****************************************************************************/ /* key - return the key of the (key,value) pair at the current position */ void * hashtable_iterator_key(struct hashtable_itr *i); /*****************************************************************************/ /* value - return the value of the (key,value) pair at the current position */ void * hashtable_iterator_value(struct hashtable_itr *i); /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr); #endif mirrormagic-3.0.0/src/libgame/setup.c0000644000175000017500000034201113263212010017015 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // setup.c // ============================================================================ #include #include #include #include #include #include #include "platform.h" #if !defined(PLATFORM_WIN32) #include #include #endif #include "setup.h" #include "joystick.h" #include "text.h" #include "misc.h" #include "hash.h" #define ENABLE_UNUSED_CODE FALSE /* for currently unused functions */ #define NUM_LEVELCLASS_DESC 8 static char *levelclass_desc[NUM_LEVELCLASS_DESC] = { "Tutorial Levels", "Classic Originals", "Contributions", "Private Levels", "Boulderdash", "Emerald Mine", "Supaplex", "DX Boulderdash" }; #define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \ IS_LEVELCLASS_BD(n) ? FC_YELLOW : \ IS_LEVELCLASS_EM(n) ? FC_YELLOW : \ IS_LEVELCLASS_SP(n) ? FC_YELLOW : \ IS_LEVELCLASS_DX(n) ? FC_YELLOW : \ IS_LEVELCLASS_SB(n) ? FC_YELLOW : \ IS_LEVELCLASS_CONTRIB(n) ? FC_GREEN : \ IS_LEVELCLASS_PRIVATE(n) ? FC_RED : \ FC_BLUE) #define LEVELSORTING(n) (IS_LEVELCLASS_TUTORIAL(n) ? 0 : \ IS_LEVELCLASS_CLASSICS(n) ? 1 : \ IS_LEVELCLASS_BD(n) ? 2 : \ IS_LEVELCLASS_EM(n) ? 3 : \ IS_LEVELCLASS_SP(n) ? 4 : \ IS_LEVELCLASS_DX(n) ? 5 : \ IS_LEVELCLASS_SB(n) ? 6 : \ IS_LEVELCLASS_CONTRIB(n) ? 7 : \ IS_LEVELCLASS_PRIVATE(n) ? 8 : \ 9) #define ARTWORKCOLOR(n) (IS_ARTWORKCLASS_CLASSICS(n) ? FC_RED : \ IS_ARTWORKCLASS_CONTRIB(n) ? FC_GREEN : \ IS_ARTWORKCLASS_PRIVATE(n) ? FC_RED : \ IS_ARTWORKCLASS_LEVEL(n) ? FC_YELLOW : \ FC_BLUE) #define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ? 0 : \ IS_ARTWORKCLASS_LEVEL(n) ? 1 : \ IS_ARTWORKCLASS_CONTRIB(n) ? 2 : \ IS_ARTWORKCLASS_PRIVATE(n) ? 3 : \ 9) #define TOKEN_VALUE_POSITION_SHORT 32 #define TOKEN_VALUE_POSITION_DEFAULT 40 #define TOKEN_COMMENT_POSITION_DEFAULT 60 #define MAX_COOKIE_LEN 256 static void setTreeInfoToDefaults(TreeInfo *, int); static TreeInfo *getTreeInfoCopy(TreeInfo *ti); static int compareTreeInfoEntries(const void *, const void *); static int token_value_position = TOKEN_VALUE_POSITION_DEFAULT; static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT; static SetupFileHash *artworkinfo_cache_old = NULL; static SetupFileHash *artworkinfo_cache_new = NULL; static boolean use_artworkinfo_cache = TRUE; /* ------------------------------------------------------------------------- */ /* file functions */ /* ------------------------------------------------------------------------- */ static char *getLevelClassDescription(TreeInfo *ti) { int position = ti->sort_priority / 100; if (position >= 0 && position < NUM_LEVELCLASS_DESC) return levelclass_desc[position]; else return "Unknown Level Class"; } static char *getScoreDir(char *level_subdir) { static char *score_dir = NULL; static char *score_level_dir = NULL; char *score_subdir = SCORES_DIRECTORY; if (score_dir == NULL) { if (program.global_scores) score_dir = getPath2(getCommonDataDir(), score_subdir); else score_dir = getPath2(getUserGameDataDir(), score_subdir); } if (level_subdir != NULL) { checked_free(score_level_dir); score_level_dir = getPath2(score_dir, level_subdir); return score_level_dir; } return score_dir; } static char *getLevelSetupDir(char *level_subdir) { static char *levelsetup_dir = NULL; char *data_dir = getUserGameDataDir(); char *levelsetup_subdir = LEVELSETUP_DIRECTORY; checked_free(levelsetup_dir); if (level_subdir != NULL) levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir); else levelsetup_dir = getPath2(data_dir, levelsetup_subdir); return levelsetup_dir; } static char *getCacheDir() { static char *cache_dir = NULL; if (cache_dir == NULL) cache_dir = getPath2(getUserGameDataDir(), CACHE_DIRECTORY); return cache_dir; } static char *getLevelDirFromTreeInfo(TreeInfo *node) { static char *level_dir = NULL; if (node == NULL) return options.level_directory; checked_free(level_dir); level_dir = getPath2((node->in_user_dir ? getUserLevelDir(NULL) : options.level_directory), node->fullpath); return level_dir; } char *getUserLevelDir(char *level_subdir) { static char *userlevel_dir = NULL; char *data_dir = getUserGameDataDir(); char *userlevel_subdir = LEVELS_DIRECTORY; checked_free(userlevel_dir); if (level_subdir != NULL) userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); else userlevel_dir = getPath2(data_dir, userlevel_subdir); return userlevel_dir; } char *getCurrentLevelDir() { return getLevelDirFromTreeInfo(leveldir_current); } char *getNewUserLevelSubdir() { static char *new_level_subdir = NULL; char *subdir_prefix = getLoginName(); char subdir_suffix[10]; int max_suffix_number = 1000; int i = 0; while (++i < max_suffix_number) { sprintf(subdir_suffix, "_%d", i); checked_free(new_level_subdir); new_level_subdir = getStringCat2(subdir_prefix, subdir_suffix); if (!directoryExists(getUserLevelDir(new_level_subdir))) break; } return new_level_subdir; } static char *getTapeDir(char *level_subdir) { static char *tape_dir = NULL; char *data_dir = getUserGameDataDir(); char *tape_subdir = TAPES_DIRECTORY; checked_free(tape_dir); if (level_subdir != NULL) tape_dir = getPath3(data_dir, tape_subdir, level_subdir); else tape_dir = getPath2(data_dir, tape_subdir); return tape_dir; } static char *getSolutionTapeDir() { static char *tape_dir = NULL; char *data_dir = getCurrentLevelDir(); char *tape_subdir = TAPES_DIRECTORY; checked_free(tape_dir); tape_dir = getPath2(data_dir, tape_subdir); return tape_dir; } static char *getDefaultGraphicsDir(char *graphics_subdir) { static char *graphics_dir = NULL; if (graphics_subdir == NULL) return options.graphics_directory; checked_free(graphics_dir); graphics_dir = getPath2(options.graphics_directory, graphics_subdir); return graphics_dir; } static char *getDefaultSoundsDir(char *sounds_subdir) { static char *sounds_dir = NULL; if (sounds_subdir == NULL) return options.sounds_directory; checked_free(sounds_dir); sounds_dir = getPath2(options.sounds_directory, sounds_subdir); return sounds_dir; } static char *getDefaultMusicDir(char *music_subdir) { static char *music_dir = NULL; if (music_subdir == NULL) return options.music_directory; checked_free(music_dir); music_dir = getPath2(options.music_directory, music_subdir); return music_dir; } static char *getClassicArtworkSet(int type) { return (type == TREE_TYPE_GRAPHICS_DIR ? GFX_CLASSIC_SUBDIR : type == TREE_TYPE_SOUNDS_DIR ? SND_CLASSIC_SUBDIR : type == TREE_TYPE_MUSIC_DIR ? MUS_CLASSIC_SUBDIR : ""); } static char *getClassicArtworkDir(int type) { return (type == TREE_TYPE_GRAPHICS_DIR ? getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR) : type == TREE_TYPE_SOUNDS_DIR ? getDefaultSoundsDir(SND_CLASSIC_SUBDIR) : type == TREE_TYPE_MUSIC_DIR ? getDefaultMusicDir(MUS_CLASSIC_SUBDIR) : ""); } static char *getUserGraphicsDir() { static char *usergraphics_dir = NULL; if (usergraphics_dir == NULL) usergraphics_dir = getPath2(getUserGameDataDir(), GRAPHICS_DIRECTORY); return usergraphics_dir; } static char *getUserSoundsDir() { static char *usersounds_dir = NULL; if (usersounds_dir == NULL) usersounds_dir = getPath2(getUserGameDataDir(), SOUNDS_DIRECTORY); return usersounds_dir; } static char *getUserMusicDir() { static char *usermusic_dir = NULL; if (usermusic_dir == NULL) usermusic_dir = getPath2(getUserGameDataDir(), MUSIC_DIRECTORY); return usermusic_dir; } static char *getSetupArtworkDir(TreeInfo *ti) { static char *artwork_dir = NULL; if (ti == NULL) return NULL; checked_free(artwork_dir); artwork_dir = getPath2(ti->basepath, ti->fullpath); return artwork_dir; } char *setLevelArtworkDir(TreeInfo *ti) { char **artwork_path_ptr, **artwork_set_ptr; TreeInfo *level_artwork; if (ti == NULL || leveldir_current == NULL) return NULL; artwork_path_ptr = LEVELDIR_ARTWORK_PATH_PTR(leveldir_current, ti->type); artwork_set_ptr = LEVELDIR_ARTWORK_SET_PTR( leveldir_current, ti->type); checked_free(*artwork_path_ptr); if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr))) { *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork)); } else { /* No (or non-existing) artwork configured in "levelinfo.conf". This would normally result in using the artwork configured in the setup menu. But if an artwork subdirectory exists (which might contain custom artwork or an artwork configuration file), this level artwork must be treated as relative to the default "classic" artwork, not to the artwork that is currently configured in the setup menu. Update: For "special" versions of R'n'D (like "R'n'D jue"), do not use the "default" artwork (which would be "jue0" for "R'n'D jue"), but use the real "classic" artwork from the original R'n'D (like "gfx_classic"). */ char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type)); checked_free(*artwork_set_ptr); if (directoryExists(dir)) { *artwork_path_ptr = getStringCopy(getClassicArtworkDir(ti->type)); *artwork_set_ptr = getStringCopy(getClassicArtworkSet(ti->type)); } else { *artwork_path_ptr = getStringCopy(UNDEFINED_FILENAME); *artwork_set_ptr = NULL; } free(dir); } return *artwork_set_ptr; } inline static char *getLevelArtworkSet(int type) { if (leveldir_current == NULL) return NULL; return LEVELDIR_ARTWORK_SET(leveldir_current, type); } inline static char *getLevelArtworkDir(int type) { if (leveldir_current == NULL) return UNDEFINED_FILENAME; return LEVELDIR_ARTWORK_PATH(leveldir_current, type); } char *getProgramMainDataPath(char *command_filename, char *base_path) { /* check if the program's main data base directory is configured */ if (!strEqual(base_path, ".")) return base_path; /* if the program is configured to start from current directory (default), determine program package directory from program binary (some versions of KDE/Konqueror and Mac OS X (especially "Mavericks") apparently do not set the current working directory to the program package directory) */ char *main_data_path = getBasePath(command_filename); #if defined(PLATFORM_MACOSX) if (strSuffix(main_data_path, MAC_APP_BINARY_SUBDIR)) { char *main_data_path_old = main_data_path; // cut relative path to Mac OS X application binary directory from path main_data_path[strlen(main_data_path) - strlen(MAC_APP_BINARY_SUBDIR)] = '\0'; // cut trailing path separator from path (but not if path is root directory) if (strSuffix(main_data_path, "/") && !strEqual(main_data_path, "/")) main_data_path[strlen(main_data_path) - 1] = '\0'; // replace empty path with current directory if (strEqual(main_data_path, "")) main_data_path = "."; // add relative path to Mac OS X application resources directory to path main_data_path = getPath2(main_data_path, MAC_APP_FILES_SUBDIR); free(main_data_path_old); } #endif return main_data_path; } char *getProgramConfigFilename(char *command_filename) { char *command_filename_1 = getStringCopy(command_filename); // strip trailing executable suffix from command filename if (strSuffix(command_filename_1, ".exe")) command_filename_1[strlen(command_filename_1) - 4] = '\0'; char *ro_base_path = getProgramMainDataPath(command_filename, RO_BASE_PATH); char *conf_directory = getPath2(ro_base_path, CONF_DIRECTORY); char *command_basepath = getBasePath(command_filename); char *command_basename = getBaseNameNoSuffix(command_filename); char *command_filename_2 = getPath2(command_basepath, command_basename); char *config_filename_1 = getStringCat2(command_filename_1, ".conf"); char *config_filename_2 = getStringCat2(command_filename_2, ".conf"); char *config_filename_3 = getPath2(conf_directory, SETUP_FILENAME); // 1st try: look for config file that exactly matches the binary filename if (fileExists(config_filename_1)) return config_filename_1; // 2nd try: look for config file that matches binary filename without suffix if (fileExists(config_filename_2)) return config_filename_2; // 3rd try: return setup config filename in global program config directory return config_filename_3; } char *getTapeFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getTapeDir(leveldir_current->subdir), basename); return filename; } char *getSolutionTapeFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getSolutionTapeDir(), basename); if (!fileExists(filename)) { static char *filename_sln = NULL; checked_free(filename_sln); sprintf(basename, "%03d.sln", nr); filename_sln = getPath2(getSolutionTapeDir(), basename); if (fileExists(filename_sln)) return filename_sln; } return filename; } char *getScoreFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; checked_free(filename); sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION); filename = getPath2(getScoreDir(leveldir_current->subdir), basename); return filename; } char *getSetupFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getSetupDir(), SETUP_FILENAME); return filename; } char *getDefaultSetupFilename() { return program.config_filename; } char *getEditorSetupFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), EDITORSETUP_FILENAME); if (fileExists(filename)) return filename; checked_free(filename); filename = getPath2(getSetupDir(), EDITORSETUP_FILENAME); return filename; } char *getHelpAnimFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), HELPANIM_FILENAME); return filename; } char *getHelpTextFilename() { static char *filename = NULL; checked_free(filename); filename = getPath2(getCurrentLevelDir(), HELPTEXT_FILENAME); return filename; } char *getLevelSetInfoFilename() { static char *filename = NULL; char *basenames[] = { "README", "README.TXT", "README.txt", "Readme", "Readme.txt", "readme", "readme.txt", NULL }; int i; for (i = 0; basenames[i] != NULL; i++) { checked_free(filename); filename = getPath2(getCurrentLevelDir(), basenames[i]); if (fileExists(filename)) return filename; } return NULL; } char *getLevelSetTitleMessageBasename(int nr, boolean initial) { static char basename[32]; sprintf(basename, "%s_%d.txt", (initial ? "titlemessage_initial" : "titlemessage"), nr + 1); return basename; } char *getLevelSetTitleMessageFilename(int nr, boolean initial) { static char *filename = NULL; char *basename; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getLevelSetTitleMessageBasename(nr, initial); if (!gfx.override_level_graphics) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* 2nd try: look for message file in current level set directory */ filename = getPath2(getCurrentLevelDir(), basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL) { /* 3rd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 4th try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 5th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 6th try: look for default artwork in old default artwork directory */ filename = getPath2(options.graphics_directory, basename); if (fileExists(filename)) return filename; return NULL; /* cannot find specified artwork file anywhere */ } static char *getCorrectedArtworkBasename(char *basename) { return basename; } char *getCustomImageFilename(char *basename) { static char *filename = NULL; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getCorrectedArtworkBasename(basename); if (!gfx.override_level_graphics) { /* 1st try: look for special artwork in current level series directory */ filename = getImg3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL) { /* 2nd try: look for special artwork configured in level series config */ filename = getImg2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ filename = getImg2(getSetupArtworkDir(artwork.gfx_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 4th try: look for default artwork in new default artwork directory */ filename = getImg2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 5th try: look for default artwork in old default artwork directory */ filename = getImg2(options.graphics_directory, basename); if (fileExists(filename)) return filename; if (!strEqual(GFX_FALLBACK_FILENAME, UNDEFINED_FILENAME)) { free(filename); if (options.debug) Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); /* 6th try: look for fallback artwork in old default artwork directory */ /* (needed to prevent errors when trying to access unused artwork files) */ filename = getImg2(options.graphics_directory, GFX_FALLBACK_FILENAME); if (fileExists(filename)) return filename; } return NULL; /* cannot find specified artwork file anywhere */ } char *getCustomSoundFilename(char *basename) { static char *filename = NULL; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getCorrectedArtworkBasename(basename); if (!gfx.override_level_sounds) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_SOUNDS) != NULL) { /* 2nd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 4th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultSoundsDir(SND_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 5th try: look for default artwork in old default artwork directory */ filename = getPath2(options.sounds_directory, basename); if (fileExists(filename)) return filename; if (!strEqual(SND_FALLBACK_FILENAME, UNDEFINED_FILENAME)) { free(filename); if (options.debug) Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); /* 6th try: look for fallback artwork in old default artwork directory */ /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME); if (fileExists(filename)) return filename; } return NULL; /* cannot find specified artwork file anywhere */ } char *getCustomMusicFilename(char *basename) { static char *filename = NULL; boolean skip_setup_artwork = FALSE; checked_free(filename); basename = getCorrectedArtworkBasename(basename); if (!gfx.override_level_music) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), MUSIC_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL) { /* 2nd try: look for special artwork configured in level series config */ filename = getPath2(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR), basename); if (fileExists(filename)) return filename; free(filename); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ filename = getPath2(getSetupArtworkDir(artwork.mus_current), basename); if (fileExists(filename)) return filename; free(filename); } /* 4th try: look for default artwork in new default artwork directory */ filename = getPath2(getDefaultMusicDir(MUS_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; free(filename); /* 5th try: look for default artwork in old default artwork directory */ filename = getPath2(options.music_directory, basename); if (fileExists(filename)) return filename; if (!strEqual(MUS_FALLBACK_FILENAME, UNDEFINED_FILENAME)) { free(filename); if (options.debug) Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); /* 6th try: look for fallback artwork in old default artwork directory */ /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME); if (fileExists(filename)) return filename; } return NULL; /* cannot find specified artwork file anywhere */ } char *getCustomArtworkFilename(char *basename, int type) { if (type == ARTWORK_TYPE_GRAPHICS) return getCustomImageFilename(basename); else if (type == ARTWORK_TYPE_SOUNDS) return getCustomSoundFilename(basename); else if (type == ARTWORK_TYPE_MUSIC) return getCustomMusicFilename(basename); else return UNDEFINED_FILENAME; } char *getCustomArtworkConfigFilename(int type) { return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type); } char *getCustomArtworkLevelConfigFilename(int type) { static char *filename = NULL; checked_free(filename); filename = getPath2(getLevelArtworkDir(type), ARTWORKINFO_FILENAME(type)); return filename; } char *getCustomMusicDirectory(void) { static char *directory = NULL; boolean skip_setup_artwork = FALSE; checked_free(directory); if (!gfx.override_level_music) { /* 1st try: look for special artwork in current level series directory */ directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY); if (directoryExists(directory)) return directory; free(directory); /* check if there is special artwork configured in level series config */ if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL) { /* 2nd try: look for special artwork configured in level series config */ directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR)); if (directoryExists(directory)) return directory; free(directory); /* take missing artwork configured in level set config from default */ skip_setup_artwork = TRUE; } } if (!skip_setup_artwork) { /* 3rd try: look for special artwork in configured artwork directory */ directory = getStringCopy(getSetupArtworkDir(artwork.mus_current)); if (directoryExists(directory)) return directory; free(directory); } /* 4th try: look for default artwork in new default artwork directory */ directory = getStringCopy(getDefaultMusicDir(MUS_DEFAULT_SUBDIR)); if (directoryExists(directory)) return directory; free(directory); /* 5th try: look for default artwork in old default artwork directory */ directory = getStringCopy(options.music_directory); if (directoryExists(directory)) return directory; return NULL; /* cannot find specified artwork file anywhere */ } void InitTapeDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE); createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE); } void InitScoreDirectory(char *level_subdir) { int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE); if (program.global_scores) createDirectory(getCommonDataDir(), "common data", permissions); else createDirectory(getUserGameDataDir(), "user data", permissions); createDirectory(getScoreDir(NULL), "main score", permissions); createDirectory(getScoreDir(level_subdir), "level score", permissions); } static void SaveUserLevelInfo(); void InitUserLevelDirectory(char *level_subdir) { if (!directoryExists(getUserLevelDir(level_subdir))) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE); createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE); SaveUserLevelInfo(); } } void InitLevelSetupDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE); createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE); } void InitCacheDirectory() { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE); } /* ------------------------------------------------------------------------- */ /* some functions to handle lists of level and artwork directories */ /* ------------------------------------------------------------------------- */ TreeInfo *newTreeInfo() { return checked_calloc(sizeof(TreeInfo)); } TreeInfo *newTreeInfo_setDefaults(int type) { TreeInfo *ti = newTreeInfo(); setTreeInfoToDefaults(ti, type); return ti; } void pushTreeInfo(TreeInfo **node_first, TreeInfo *node_new) { node_new->next = *node_first; *node_first = node_new; } int numTreeInfo(TreeInfo *node) { int num = 0; while (node) { num++; node = node->next; } return num; } boolean validLevelSeries(TreeInfo *node) { return (node != NULL && !node->node_group && !node->parent_link); } TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *node) { if (node == NULL) return NULL; if (node->node_group) /* enter level group (step down into tree) */ return getFirstValidTreeInfoEntry(node->node_group); else if (node->parent_link) /* skip start entry of level group */ { if (node->next) /* get first real level series entry */ return getFirstValidTreeInfoEntry(node->next); else /* leave empty level group and go on */ return getFirstValidTreeInfoEntry(node->node_parent->next); } else /* this seems to be a regular level series */ return node; } TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *node) { if (node == NULL) return NULL; if (node->node_parent == NULL) /* top level group */ return *node->node_top; else /* sub level group */ return node->node_parent->node_group; } int numTreeInfoInGroup(TreeInfo *node) { return numTreeInfo(getTreeInfoFirstGroupEntry(node)); } int posTreeInfo(TreeInfo *node) { TreeInfo *node_cmp = getTreeInfoFirstGroupEntry(node); int pos = 0; while (node_cmp) { if (node_cmp == node) return pos; pos++; node_cmp = node_cmp->next; } return 0; } TreeInfo *getTreeInfoFromPos(TreeInfo *node, int pos) { TreeInfo *node_default = node; int pos_cmp = 0; while (node) { if (pos_cmp == pos) return node; pos_cmp++; node = node->next; } return node_default; } TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier) { if (identifier == NULL) return NULL; while (node) { if (node->node_group) { TreeInfo *node_group; node_group = getTreeInfoFromIdentifier(node->node_group, identifier); if (node_group) return node_group; } else if (!node->parent_link) { if (strEqual(identifier, node->identifier)) return node; } node = node->next; } return NULL; } TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent, TreeInfo *node, boolean skip_sets_without_levels) { TreeInfo *node_new; if (node == NULL) return NULL; if (!node->parent_link && !node->level_group && skip_sets_without_levels && node->levels == 0) return cloneTreeNode(node_top, node_parent, node->next, skip_sets_without_levels); node_new = getTreeInfoCopy(node); /* copy complete node */ node_new->node_top = node_top; /* correct top node link */ node_new->node_parent = node_parent; /* correct parent node link */ if (node->level_group) node_new->node_group = cloneTreeNode(node_top, node_new, node->node_group, skip_sets_without_levels); node_new->next = cloneTreeNode(node_top, node_parent, node->next, skip_sets_without_levels); return node_new; } void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets) { TreeInfo *ti_cloned = cloneTreeNode(ti_new, NULL, ti, skip_empty_sets); *ti_new = ti_cloned; } static boolean adjustTreeGraphicsForEMC(TreeInfo *node) { boolean settings_changed = FALSE; while (node) { if (node->graphics_set_ecs && !setup.prefer_aga_graphics && !strEqual(node->graphics_set, node->graphics_set_ecs)) { setString(&node->graphics_set, node->graphics_set_ecs); settings_changed = TRUE; } else if (node->graphics_set_aga && setup.prefer_aga_graphics && !strEqual(node->graphics_set, node->graphics_set_aga)) { setString(&node->graphics_set, node->graphics_set_aga); settings_changed = TRUE; } if (node->node_group != NULL) settings_changed |= adjustTreeGraphicsForEMC(node->node_group); node = node->next; } return settings_changed; } void dumpTreeInfo(TreeInfo *node, int depth) { int i; printf("Dumping TreeInfo:\n"); while (node) { for (i = 0; i < (depth + 1) * 3; i++) printf(" "); printf("'%s' / '%s'\n", node->identifier, node->name); /* // use for dumping artwork info tree printf("subdir == '%s' ['%s', '%s'] [%d])\n", node->subdir, node->fullpath, node->basepath, node->in_user_dir); */ if (node->node_group != NULL) dumpTreeInfo(node->node_group, depth + 1); node = node->next; } } void sortTreeInfoBySortFunction(TreeInfo **node_first, int (*compare_function)(const void *, const void *)) { int num_nodes = numTreeInfo(*node_first); TreeInfo **sort_array; TreeInfo *node = *node_first; int i = 0; if (num_nodes == 0) return; /* allocate array for sorting structure pointers */ sort_array = checked_calloc(num_nodes * sizeof(TreeInfo *)); /* writing structure pointers to sorting array */ while (i < num_nodes && node) /* double boundary check... */ { sort_array[i] = node; i++; node = node->next; } /* sorting the structure pointers in the sorting array */ qsort(sort_array, num_nodes, sizeof(TreeInfo *), compare_function); /* update the linkage of list elements with the sorted node array */ for (i = 0; i < num_nodes - 1; i++) sort_array[i]->next = sort_array[i + 1]; sort_array[num_nodes - 1]->next = NULL; /* update the linkage of the main list anchor pointer */ *node_first = sort_array[0]; free(sort_array); /* now recursively sort the level group structures */ node = *node_first; while (node) { if (node->node_group != NULL) sortTreeInfoBySortFunction(&node->node_group, compare_function); node = node->next; } } void sortTreeInfo(TreeInfo **node_first) { sortTreeInfoBySortFunction(node_first, compareTreeInfoEntries); } /* ========================================================================= */ /* some stuff from "files.c" */ /* ========================================================================= */ #if defined(PLATFORM_WIN32) #ifndef S_IRGRP #define S_IRGRP S_IRUSR #endif #ifndef S_IROTH #define S_IROTH S_IRUSR #endif #ifndef S_IWGRP #define S_IWGRP S_IWUSR #endif #ifndef S_IWOTH #define S_IWOTH S_IWUSR #endif #ifndef S_IXGRP #define S_IXGRP S_IXUSR #endif #ifndef S_IXOTH #define S_IXOTH S_IXUSR #endif #ifndef S_IRWXG #define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #endif #ifndef S_ISGID #define S_ISGID 0 #endif #endif /* PLATFORM_WIN32 */ /* 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 MODE_W_PRIVATE (S_IWUSR) #define MODE_W_PUBLIC_FILE (S_IWUSR | S_IWGRP) #define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) #define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) #define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) #define DIR_PERMS_PUBLIC_ALL (MODE_R_ALL | MODE_X_ALL | MODE_W_ALL) #define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) #define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC_FILE) #define FILE_PERMS_PUBLIC_ALL (MODE_R_ALL | MODE_W_ALL) char *getHomeDir() { static char *dir = NULL; #if defined(PLATFORM_WIN32) if (dir == NULL) { dir = checked_malloc(MAX_PATH + 1); if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir))) strcpy(dir, "."); } #elif defined(PLATFORM_UNIX) if (dir == NULL) { if ((dir = getenv("HOME")) == NULL) { struct passwd *pwd; if ((pwd = getpwuid(getuid())) != NULL) dir = getStringCopy(pwd->pw_dir); else dir = "."; } } #else dir = "."; #endif return dir; } char *getCommonDataDir(void) { static char *common_data_dir = NULL; #if defined(PLATFORM_WIN32) if (common_data_dir == NULL) { char *dir = checked_malloc(MAX_PATH + 1); if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir)) && !strEqual(dir, "")) /* empty for Windows 95/98 */ common_data_dir = getPath2(dir, program.userdata_subdir); else common_data_dir = options.rw_base_directory; } #else if (common_data_dir == NULL) common_data_dir = options.rw_base_directory; #endif return common_data_dir; } char *getPersonalDataDir(void) { static char *personal_data_dir = NULL; #if defined(PLATFORM_MACOSX) if (personal_data_dir == NULL) personal_data_dir = getPath2(getHomeDir(), "Documents"); #else if (personal_data_dir == NULL) personal_data_dir = getHomeDir(); #endif return personal_data_dir; } char *getUserGameDataDir(void) { static char *user_game_data_dir = NULL; #if defined(PLATFORM_ANDROID) if (user_game_data_dir == NULL) user_game_data_dir = (char *)(SDL_AndroidGetExternalStorageState() & SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? SDL_AndroidGetExternalStoragePath() : SDL_AndroidGetInternalStoragePath()); #else if (user_game_data_dir == NULL) user_game_data_dir = getPath2(getPersonalDataDir(), program.userdata_subdir); #endif return user_game_data_dir; } char *getSetupDir() { return getUserGameDataDir(); } static mode_t posix_umask(mode_t mask) { #if defined(PLATFORM_UNIX) return umask(mask); #else return 0; #endif } static int posix_mkdir(const char *pathname, mode_t mode) { #if defined(PLATFORM_WIN32) return mkdir(pathname); #else return mkdir(pathname, mode); #endif } static boolean posix_process_running_setgid() { #if defined(PLATFORM_UNIX) return (getgid() != getegid()); #else return FALSE; #endif } void createDirectory(char *dir, char *text, int permission_class) { if (directoryExists(dir)) return; /* leave "other" permissions in umask untouched, but ensure group parts of USERDATA_DIR_MODE are not masked */ mode_t dir_mode = (permission_class == PERMS_PRIVATE ? DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); mode_t last_umask = posix_umask(0); mode_t group_umask = ~(dir_mode & S_IRWXG); int running_setgid = posix_process_running_setgid(); if (permission_class == PERMS_PUBLIC) { /* if we're setgid, protect files against "other" */ /* else keep umask(0) to make the dir world-writable */ if (running_setgid) posix_umask(last_umask & group_umask); else dir_mode = DIR_PERMS_PUBLIC_ALL; } if (posix_mkdir(dir, dir_mode) != 0) Error(ERR_WARN, "cannot create %s directory '%s': %s", text, dir, strerror(errno)); if (permission_class == PERMS_PUBLIC && !running_setgid) chmod(dir, dir_mode); posix_umask(last_umask); /* restore previous umask */ } void InitUserDataDirectory() { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); } void SetFilePermissions(char *filename, int permission_class) { int running_setgid = posix_process_running_setgid(); int perms = (permission_class == PERMS_PRIVATE ? FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC); if (permission_class == PERMS_PUBLIC && !running_setgid) perms = FILE_PERMS_PUBLIC_ALL; chmod(filename, perms); } char *getCookie(char *file_type) { static char cookie[MAX_COOKIE_LEN + 1]; if (strlen(program.cookie_prefix) + 1 + strlen(file_type) + strlen("_FILE_VERSION_x.x") > MAX_COOKIE_LEN) return "[COOKIE ERROR]"; /* should never happen */ sprintf(cookie, "%s_%s_FILE_VERSION_%d.%d", program.cookie_prefix, file_type, program.version_major, program.version_minor); return cookie; } void fprintFileHeader(FILE *file, char *basename) { char *prefix = "# "; char *sep1 = "="; fprintf_line_with_prefix(file, prefix, sep1, 77); fprintf(file, "%s%s\n", prefix, basename); fprintf_line_with_prefix(file, prefix, sep1, 77); fprintf(file, "\n"); } int getFileVersionFromCookieString(const char *cookie) { const char *ptr_cookie1, *ptr_cookie2; const char *pattern1 = "_FILE_VERSION_"; const char *pattern2 = "?.?"; const int len_cookie = strlen(cookie); const int len_pattern1 = strlen(pattern1); const int len_pattern2 = strlen(pattern2); const int len_pattern = len_pattern1 + len_pattern2; int version_major, version_minor; if (len_cookie <= len_pattern) return -1; ptr_cookie1 = &cookie[len_cookie - len_pattern]; ptr_cookie2 = &cookie[len_cookie - len_pattern2]; if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0) return -1; if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' || ptr_cookie2[1] != '.' || ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9') return -1; version_major = ptr_cookie2[0] - '0'; version_minor = ptr_cookie2[2] - '0'; return VERSION_IDENT(version_major, version_minor, 0, 0); } boolean checkCookieString(const char *cookie, const char *template) { const char *pattern = "_FILE_VERSION_?.?"; const int len_cookie = strlen(cookie); const int len_template = strlen(template); const int len_pattern = strlen(pattern); if (len_cookie != len_template) return FALSE; if (strncmp(cookie, template, len_cookie - len_pattern) != 0) return FALSE; return TRUE; } /* ------------------------------------------------------------------------- */ /* setup file list and hash handling functions */ /* ------------------------------------------------------------------------- */ char *getFormattedSetupEntry(char *token, char *value) { int i; static char entry[MAX_LINE_LEN]; /* if value is an empty string, just return token without value */ if (*value == '\0') return token; /* start with the token and some spaces to format output line */ sprintf(entry, "%s:", token); for (i = strlen(entry); i < token_value_position; i++) strcat(entry, " "); /* continue with the token's value */ strcat(entry, value); return entry; } SetupFileList *newSetupFileList(char *token, char *value) { SetupFileList *new = checked_malloc(sizeof(SetupFileList)); new->token = getStringCopy(token); new->value = getStringCopy(value); new->next = NULL; return new; } void freeSetupFileList(SetupFileList *list) { if (list == NULL) return; checked_free(list->token); checked_free(list->value); if (list->next) freeSetupFileList(list->next); free(list); } char *getListEntry(SetupFileList *list, char *token) { if (list == NULL) return NULL; if (strEqual(list->token, token)) return list->value; else return getListEntry(list->next, token); } SetupFileList *setListEntry(SetupFileList *list, char *token, char *value) { if (list == NULL) return NULL; if (strEqual(list->token, token)) { checked_free(list->value); list->value = getStringCopy(value); return list; } else if (list->next == NULL) return (list->next = newSetupFileList(token, value)); else return setListEntry(list->next, token, value); } SetupFileList *addListEntry(SetupFileList *list, char *token, char *value) { if (list == NULL) return NULL; if (list->next == NULL) return (list->next = newSetupFileList(token, value)); else return addListEntry(list->next, token, value); } #if ENABLE_UNUSED_CODE #ifdef DEBUG static void printSetupFileList(SetupFileList *list) { if (!list) return; printf("token: '%s'\n", list->token); printf("value: '%s'\n", list->value); printSetupFileList(list->next); } #endif #endif #ifdef DEBUG DEFINE_HASHTABLE_INSERT(insert_hash_entry, char, char); DEFINE_HASHTABLE_SEARCH(search_hash_entry, char, char); DEFINE_HASHTABLE_CHANGE(change_hash_entry, char, char); DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char); #else #define insert_hash_entry hashtable_insert #define search_hash_entry hashtable_search #define change_hash_entry hashtable_change #define remove_hash_entry hashtable_remove #endif unsigned int get_hash_from_key(void *key) { /* djb2 This algorithm (k=33) was first reported by Dan Bernstein many years ago in 'comp.lang.c'. Another version of this algorithm (now favored by Bernstein) uses XOR: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why it works better than many other constants, prime or not) has never been adequately explained. If you just want to have a good hash function, and cannot wait, djb2 is one of the best string hash functions i know. It has excellent distribution and speed on many different sets of keys and table sizes. You are not likely to do better with one of the "well known" functions such as PJW, K&R, etc. Ozan (oz) Yigit [http://www.cs.yorku.ca/~oz/hash.html] */ char *str = (char *)key; unsigned int hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ return hash; } static int keys_are_equal(void *key1, void *key2) { return (strEqual((char *)key1, (char *)key2)); } SetupFileHash *newSetupFileHash() { SetupFileHash *new_hash = create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal); if (new_hash == NULL) Error(ERR_EXIT, "create_hashtable() failed -- out of memory"); return new_hash; } void freeSetupFileHash(SetupFileHash *hash) { if (hash == NULL) return; hashtable_destroy(hash, 1); /* 1 == also free values stored in hash */ } char *getHashEntry(SetupFileHash *hash, char *token) { if (hash == NULL) return NULL; return search_hash_entry(hash, token); } void setHashEntry(SetupFileHash *hash, char *token, char *value) { char *value_copy; if (hash == NULL) return; value_copy = getStringCopy(value); /* change value; if it does not exist, insert it as new */ if (!change_hash_entry(hash, token, value_copy)) if (!insert_hash_entry(hash, getStringCopy(token), value_copy)) Error(ERR_EXIT, "cannot insert into hash -- aborting"); } char *removeHashEntry(SetupFileHash *hash, char *token) { if (hash == NULL) return NULL; return remove_hash_entry(hash, token); } #if ENABLE_UNUSED_CODE #if DEBUG static void printSetupFileHash(SetupFileHash *hash) { BEGIN_HASH_ITERATION(hash, itr) { printf("token: '%s'\n", HASH_ITERATION_TOKEN(itr)); printf("value: '%s'\n", HASH_ITERATION_VALUE(itr)); } END_HASH_ITERATION(hash, itr) } #endif #endif #define ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE 1 #define CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING 0 #define CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH 0 static boolean token_value_separator_found = FALSE; #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING static boolean token_value_separator_warning = FALSE; #endif #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH static boolean token_already_exists_warning = FALSE; #endif static boolean getTokenValueFromSetupLineExt(char *line, char **token_ptr, char **value_ptr, char *filename, char *line_raw, int line_nr, boolean separator_required) { static char line_copy[MAX_LINE_LEN + 1], line_raw_copy[MAX_LINE_LEN + 1]; char *token, *value, *line_ptr; /* when externally invoked via ReadTokenValueFromLine(), copy line buffers */ if (line_raw == NULL) { strncpy(line_copy, line, MAX_LINE_LEN); line_copy[MAX_LINE_LEN] = '\0'; line = line_copy; strcpy(line_raw_copy, line_copy); line_raw = line_raw_copy; } /* cut trailing comment from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr == '#') { *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') return FALSE; /* cut leading whitespaces from token */ for (token = line; *token; token++) if (*token != ' ' && *token != '\t') break; /* start with empty value as reliable default */ value = ""; token_value_separator_found = FALSE; /* find end of token to determine start of value */ for (line_ptr = token; *line_ptr; line_ptr++) { /* first look for an explicit token/value separator, like ':' or '=' */ if (*line_ptr == ':' || *line_ptr == '=') { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ token_value_separator_found = TRUE; break; } } #if ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE /* fallback: if no token/value separator found, also allow whitespaces */ if (!token_value_separator_found && !separator_required) { for (line_ptr = token; *line_ptr; line_ptr++) { if (*line_ptr == ' ' || *line_ptr == '\t') { *line_ptr = '\0'; /* terminate token string */ value = line_ptr + 1; /* set beginning of value */ token_value_separator_found = TRUE; break; } } #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING if (token_value_separator_found) { if (!token_value_separator_warning) { Error(ERR_INFO_LINE, "-"); if (filename != NULL) { Error(ERR_WARN, "missing token/value separator(s) in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); } else { Error(ERR_WARN, "missing token/value separator(s):"); } token_value_separator_warning = TRUE; } if (filename != NULL) Error(ERR_INFO, "- line %d: '%s'", line_nr, line_raw); else Error(ERR_INFO, "- line: '%s'", line_raw); } #endif } #endif /* cut trailing whitespaces from token */ for (line_ptr = &token[strlen(token)]; line_ptr >= token; line_ptr--) if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* cut leading whitespaces from value */ for (; *value; value++) if (*value != ' ' && *value != '\t') break; *token_ptr = token; *value_ptr = value; return TRUE; } boolean getTokenValueFromSetupLine(char *line, char **token, char **value) { /* while the internal (old) interface does not require a token/value separator (for downwards compatibility with existing files which don't use them), it is mandatory for the external (new) interface */ return getTokenValueFromSetupLineExt(line, token, value, NULL, NULL, 0, TRUE); } static boolean loadSetupFileData(void *setup_file_data, char *filename, boolean top_recursion_level, boolean is_hash) { static SetupFileHash *include_filename_hash = NULL; char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; char *token, *value, *line_ptr; void *insert_ptr = NULL; boolean read_continued_line = FALSE; File *file; int line_nr = 0, token_count = 0, include_count = 0; #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING token_value_separator_warning = FALSE; #endif #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH token_already_exists_warning = FALSE; #endif if (!(file = openFile(filename, MODE_READ))) { Error(ERR_DEBUG, "cannot open configuration file '%s'", filename); return FALSE; } /* use "insert pointer" to store list end for constant insertion complexity */ if (!is_hash) insert_ptr = setup_file_data; /* on top invocation, create hash to mark included files (to prevent loops) */ if (top_recursion_level) include_filename_hash = newSetupFileHash(); /* mark this file as already included (to prevent including it again) */ setHashEntry(include_filename_hash, getBaseNamePtr(filename), "true"); while (!checkEndOfFile(file)) { /* read next line of input file */ if (!getStringFromFile(file, line, MAX_LINE_LEN)) break; /* check if line was completely read and is terminated by line break */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line_nr++; /* cut trailing line break (this can be newline and/or carriage return) */ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0') *line_ptr = '\0'; /* copy raw input line for later use (mainly debugging output) */ strcpy(line_raw, line); if (read_continued_line) { /* append new line to existing line, if there is enough space */ if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN) strcat(previous_line, line_ptr); strcpy(line, previous_line); /* copy storage buffer to line */ read_continued_line = FALSE; } /* if the last character is '\', continue at next line */ if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') { line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */ strcpy(previous_line, line); /* copy line to storage buffer */ read_continued_line = TRUE; continue; } if (!getTokenValueFromSetupLineExt(line, &token, &value, filename, line_raw, line_nr, FALSE)) continue; if (*token) { if (strEqual(token, "include")) { if (getHashEntry(include_filename_hash, value) == NULL) { char *basepath = getBasePath(filename); char *basename = getBaseName(value); char *filename_include = getPath2(basepath, basename); loadSetupFileData(setup_file_data, filename_include, FALSE, is_hash); free(basepath); free(basename); free(filename_include); include_count++; } else { Error(ERR_WARN, "ignoring already processed file '%s'", value); } } else { if (is_hash) { #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH char *old_value = getHashEntry((SetupFileHash *)setup_file_data, token); if (old_value != NULL) { if (!token_already_exists_warning) { Error(ERR_INFO_LINE, "-"); Error(ERR_WARN, "duplicate token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); token_already_exists_warning = TRUE; } Error(ERR_INFO, "- token: '%s' (in line %d)", token, line_nr); Error(ERR_INFO, " old value: '%s'", old_value); Error(ERR_INFO, " new value: '%s'", value); } #endif setHashEntry((SetupFileHash *)setup_file_data, token, value); } else { insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value); } token_count++; } } } closeFile(file); #if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING if (token_value_separator_warning) Error(ERR_INFO_LINE, "-"); #endif #if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH if (token_already_exists_warning) Error(ERR_INFO_LINE, "-"); #endif if (token_count == 0 && include_count == 0) Error(ERR_WARN, "configuration file '%s' is empty", filename); if (top_recursion_level) freeSetupFileHash(include_filename_hash); return TRUE; } void saveSetupFileHash(SetupFileHash *hash, char *filename) { FILE *file; if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write configuration file '%s'", filename); return; } BEGIN_HASH_ITERATION(hash, itr) { fprintf(file, "%s\n", getFormattedSetupEntry(HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr))); } END_HASH_ITERATION(hash, itr) fclose(file); } SetupFileList *loadSetupFileList(char *filename) { SetupFileList *setup_file_list = newSetupFileList("", ""); SetupFileList *first_valid_list_entry; if (!loadSetupFileData(setup_file_list, filename, TRUE, FALSE)) { freeSetupFileList(setup_file_list); return NULL; } first_valid_list_entry = setup_file_list->next; /* free empty list header */ setup_file_list->next = NULL; freeSetupFileList(setup_file_list); return first_valid_list_entry; } SetupFileHash *loadSetupFileHash(char *filename) { SetupFileHash *setup_file_hash = newSetupFileHash(); if (!loadSetupFileData(setup_file_hash, filename, TRUE, TRUE)) { freeSetupFileHash(setup_file_hash); return NULL; } return setup_file_hash; } /* ========================================================================= */ /* setup file stuff */ /* ========================================================================= */ #define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series" #define TOKEN_STR_LAST_PLAYED_LEVEL "last_played_level" #define TOKEN_STR_HANDICAP_LEVEL "handicap_level" /* level directory info */ #define LEVELINFO_TOKEN_IDENTIFIER 0 #define LEVELINFO_TOKEN_NAME 1 #define LEVELINFO_TOKEN_NAME_SORTING 2 #define LEVELINFO_TOKEN_AUTHOR 3 #define LEVELINFO_TOKEN_YEAR 4 #define LEVELINFO_TOKEN_PROGRAM_TITLE 5 #define LEVELINFO_TOKEN_PROGRAM_COPYRIGHT 6 #define LEVELINFO_TOKEN_PROGRAM_COMPANY 7 #define LEVELINFO_TOKEN_IMPORTED_FROM 8 #define LEVELINFO_TOKEN_IMPORTED_BY 9 #define LEVELINFO_TOKEN_TESTED_BY 10 #define LEVELINFO_TOKEN_LEVELS 11 #define LEVELINFO_TOKEN_FIRST_LEVEL 12 #define LEVELINFO_TOKEN_SORT_PRIORITY 13 #define LEVELINFO_TOKEN_LATEST_ENGINE 14 #define LEVELINFO_TOKEN_LEVEL_GROUP 15 #define LEVELINFO_TOKEN_READONLY 16 #define LEVELINFO_TOKEN_GRAPHICS_SET_ECS 17 #define LEVELINFO_TOKEN_GRAPHICS_SET_AGA 18 #define LEVELINFO_TOKEN_GRAPHICS_SET 19 #define LEVELINFO_TOKEN_SOUNDS_SET 20 #define LEVELINFO_TOKEN_MUSIC_SET 21 #define LEVELINFO_TOKEN_FILENAME 22 #define LEVELINFO_TOKEN_FILETYPE 23 #define LEVELINFO_TOKEN_SPECIAL_FLAGS 24 #define LEVELINFO_TOKEN_HANDICAP 25 #define LEVELINFO_TOKEN_SKIP_LEVELS 26 #define NUM_LEVELINFO_TOKENS 27 static LevelDirTree ldi; static struct TokenInfo levelinfo_tokens[] = { /* level directory info */ { TYPE_STRING, &ldi.identifier, "identifier" }, { TYPE_STRING, &ldi.name, "name" }, { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, { TYPE_STRING, &ldi.author, "author" }, { TYPE_STRING, &ldi.year, "year" }, { TYPE_STRING, &ldi.program_title, "program_title" }, { TYPE_STRING, &ldi.program_copyright, "program_copyright" }, { TYPE_STRING, &ldi.program_company, "program_company" }, { TYPE_STRING, &ldi.imported_from, "imported_from" }, { TYPE_STRING, &ldi.imported_by, "imported_by" }, { TYPE_STRING, &ldi.tested_by, "tested_by" }, { TYPE_INTEGER, &ldi.levels, "levels" }, { TYPE_INTEGER, &ldi.first_level, "first_level" }, { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, { TYPE_BOOLEAN, &ldi.latest_engine, "latest_engine" }, { TYPE_BOOLEAN, &ldi.level_group, "level_group" }, { TYPE_BOOLEAN, &ldi.readonly, "readonly" }, { TYPE_STRING, &ldi.graphics_set_ecs, "graphics_set.ecs" }, { TYPE_STRING, &ldi.graphics_set_aga, "graphics_set.aga" }, { TYPE_STRING, &ldi.graphics_set, "graphics_set" }, { TYPE_STRING, &ldi.sounds_set, "sounds_set" }, { TYPE_STRING, &ldi.music_set, "music_set" }, { TYPE_STRING, &ldi.level_filename, "filename" }, { TYPE_STRING, &ldi.level_filetype, "filetype" }, { TYPE_STRING, &ldi.special_flags, "special_flags" }, { TYPE_BOOLEAN, &ldi.handicap, "handicap" }, { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" } }; static struct TokenInfo artworkinfo_tokens[] = { /* artwork directory info */ { TYPE_STRING, &ldi.identifier, "identifier" }, { TYPE_STRING, &ldi.subdir, "subdir" }, { TYPE_STRING, &ldi.name, "name" }, { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, { TYPE_STRING, &ldi.author, "author" }, { TYPE_STRING, &ldi.program_title, "program_title" }, { TYPE_STRING, &ldi.program_copyright, "program_copyright" }, { TYPE_STRING, &ldi.program_company, "program_company" }, { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, { TYPE_STRING, &ldi.basepath, "basepath" }, { TYPE_STRING, &ldi.fullpath, "fullpath" }, { TYPE_BOOLEAN, &ldi.in_user_dir, "in_user_dir" }, { TYPE_INTEGER, &ldi.color, "color" }, { TYPE_STRING, &ldi.class_desc, "class_desc" }, { -1, NULL, NULL }, }; static void setTreeInfoToDefaults(TreeInfo *ti, int type) { ti->type = type; ti->node_top = (ti->type == TREE_TYPE_LEVEL_DIR ? &leveldir_first : ti->type == TREE_TYPE_GRAPHICS_DIR ? &artwork.gfx_first : ti->type == TREE_TYPE_SOUNDS_DIR ? &artwork.snd_first : ti->type == TREE_TYPE_MUSIC_DIR ? &artwork.mus_first : NULL); ti->node_parent = NULL; ti->node_group = NULL; ti->next = NULL; ti->cl_first = -1; ti->cl_cursor = -1; ti->subdir = NULL; ti->fullpath = NULL; ti->basepath = NULL; ti->identifier = NULL; ti->name = getStringCopy(ANONYMOUS_NAME); ti->name_sorting = NULL; ti->author = getStringCopy(ANONYMOUS_NAME); ti->year = NULL; ti->program_title = NULL; ti->program_copyright = NULL; ti->program_company = NULL; ti->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ ti->latest_engine = FALSE; /* default: get from level */ ti->parent_link = FALSE; ti->in_user_dir = FALSE; ti->user_defined = FALSE; ti->color = 0; ti->class_desc = NULL; ti->infotext = getStringCopy(TREE_INFOTEXT(ti->type)); if (ti->type == TREE_TYPE_LEVEL_DIR) { ti->imported_from = NULL; ti->imported_by = NULL; ti->tested_by = NULL; ti->graphics_set_ecs = NULL; ti->graphics_set_aga = NULL; ti->graphics_set = NULL; ti->sounds_set = NULL; ti->music_set = NULL; ti->graphics_path = getStringCopy(UNDEFINED_FILENAME); ti->sounds_path = getStringCopy(UNDEFINED_FILENAME); ti->music_path = getStringCopy(UNDEFINED_FILENAME); ti->level_filename = NULL; ti->level_filetype = NULL; ti->special_flags = NULL; ti->levels = 0; ti->first_level = 0; ti->last_level = 0; ti->level_group = FALSE; ti->handicap_level = 0; ti->readonly = TRUE; ti->handicap = TRUE; ti->skip_levels = FALSE; } } static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) { if (parent == NULL) { Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL"); setTreeInfoToDefaults(ti, TREE_TYPE_UNDEFINED); return; } /* copy all values from the parent structure */ ti->type = parent->type; ti->node_top = parent->node_top; ti->node_parent = parent; ti->node_group = NULL; ti->next = NULL; ti->cl_first = -1; ti->cl_cursor = -1; ti->subdir = NULL; ti->fullpath = NULL; ti->basepath = NULL; ti->identifier = NULL; ti->name = getStringCopy(ANONYMOUS_NAME); ti->name_sorting = NULL; ti->author = getStringCopy(parent->author); ti->year = getStringCopy(parent->year); ti->program_title = getStringCopy(parent->program_title); ti->program_copyright = getStringCopy(parent->program_copyright); ti->program_company = getStringCopy(parent->program_company); ti->sort_priority = parent->sort_priority; ti->latest_engine = parent->latest_engine; ti->parent_link = FALSE; ti->in_user_dir = parent->in_user_dir; ti->user_defined = parent->user_defined; ti->color = parent->color; ti->class_desc = getStringCopy(parent->class_desc); ti->infotext = getStringCopy(parent->infotext); if (ti->type == TREE_TYPE_LEVEL_DIR) { ti->imported_from = getStringCopy(parent->imported_from); ti->imported_by = getStringCopy(parent->imported_by); ti->tested_by = getStringCopy(parent->tested_by); ti->graphics_set_ecs = getStringCopy(parent->graphics_set_ecs); ti->graphics_set_aga = getStringCopy(parent->graphics_set_aga); ti->graphics_set = getStringCopy(parent->graphics_set); ti->sounds_set = getStringCopy(parent->sounds_set); ti->music_set = getStringCopy(parent->music_set); ti->graphics_path = getStringCopy(UNDEFINED_FILENAME); ti->sounds_path = getStringCopy(UNDEFINED_FILENAME); ti->music_path = getStringCopy(UNDEFINED_FILENAME); ti->level_filename = getStringCopy(parent->level_filename); ti->level_filetype = getStringCopy(parent->level_filetype); ti->special_flags = getStringCopy(parent->special_flags); ti->levels = parent->levels; ti->first_level = parent->first_level; ti->last_level = parent->last_level; ti->level_group = FALSE; ti->handicap_level = parent->handicap_level; ti->readonly = parent->readonly; ti->handicap = parent->handicap; ti->skip_levels = parent->skip_levels; } } static TreeInfo *getTreeInfoCopy(TreeInfo *ti) { TreeInfo *ti_copy = newTreeInfo(); /* copy all values from the original structure */ ti_copy->type = ti->type; ti_copy->node_top = ti->node_top; ti_copy->node_parent = ti->node_parent; ti_copy->node_group = ti->node_group; ti_copy->next = ti->next; ti_copy->cl_first = ti->cl_first; ti_copy->cl_cursor = ti->cl_cursor; ti_copy->subdir = getStringCopy(ti->subdir); ti_copy->fullpath = getStringCopy(ti->fullpath); ti_copy->basepath = getStringCopy(ti->basepath); ti_copy->identifier = getStringCopy(ti->identifier); ti_copy->name = getStringCopy(ti->name); ti_copy->name_sorting = getStringCopy(ti->name_sorting); ti_copy->author = getStringCopy(ti->author); ti_copy->year = getStringCopy(ti->year); ti_copy->program_title = getStringCopy(ti->program_title); ti_copy->program_copyright = getStringCopy(ti->program_copyright); ti_copy->program_company = getStringCopy(ti->program_company); ti_copy->imported_from = getStringCopy(ti->imported_from); ti_copy->imported_by = getStringCopy(ti->imported_by); ti_copy->tested_by = getStringCopy(ti->tested_by); ti_copy->graphics_set_ecs = getStringCopy(ti->graphics_set_ecs); ti_copy->graphics_set_aga = getStringCopy(ti->graphics_set_aga); ti_copy->graphics_set = getStringCopy(ti->graphics_set); ti_copy->sounds_set = getStringCopy(ti->sounds_set); ti_copy->music_set = getStringCopy(ti->music_set); ti_copy->graphics_path = getStringCopy(ti->graphics_path); ti_copy->sounds_path = getStringCopy(ti->sounds_path); ti_copy->music_path = getStringCopy(ti->music_path); ti_copy->level_filename = getStringCopy(ti->level_filename); ti_copy->level_filetype = getStringCopy(ti->level_filetype); ti_copy->special_flags = getStringCopy(ti->special_flags); ti_copy->levels = ti->levels; ti_copy->first_level = ti->first_level; ti_copy->last_level = ti->last_level; ti_copy->sort_priority = ti->sort_priority; ti_copy->latest_engine = ti->latest_engine; ti_copy->level_group = ti->level_group; ti_copy->parent_link = ti->parent_link; ti_copy->in_user_dir = ti->in_user_dir; ti_copy->user_defined = ti->user_defined; ti_copy->readonly = ti->readonly; ti_copy->handicap = ti->handicap; ti_copy->skip_levels = ti->skip_levels; ti_copy->color = ti->color; ti_copy->class_desc = getStringCopy(ti->class_desc); ti_copy->handicap_level = ti->handicap_level; ti_copy->infotext = getStringCopy(ti->infotext); return ti_copy; } void freeTreeInfo(TreeInfo *ti) { if (ti == NULL) return; checked_free(ti->subdir); checked_free(ti->fullpath); checked_free(ti->basepath); checked_free(ti->identifier); checked_free(ti->name); checked_free(ti->name_sorting); checked_free(ti->author); checked_free(ti->year); checked_free(ti->program_title); checked_free(ti->program_copyright); checked_free(ti->program_company); checked_free(ti->class_desc); checked_free(ti->infotext); if (ti->type == TREE_TYPE_LEVEL_DIR) { checked_free(ti->imported_from); checked_free(ti->imported_by); checked_free(ti->tested_by); checked_free(ti->graphics_set_ecs); checked_free(ti->graphics_set_aga); checked_free(ti->graphics_set); checked_free(ti->sounds_set); checked_free(ti->music_set); checked_free(ti->graphics_path); checked_free(ti->sounds_path); checked_free(ti->music_path); checked_free(ti->level_filename); checked_free(ti->level_filetype); checked_free(ti->special_flags); } // recursively free child node if (ti->node_group) freeTreeInfo(ti->node_group); // recursively free next node if (ti->next) freeTreeInfo(ti->next); checked_free(ti); } void setSetupInfo(struct TokenInfo *token_info, 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_boolean_from_string(token_value); break; case TYPE_SWITCH3: *(int *)setup_value = get_switch3_from_string(token_value); break; case TYPE_KEY: *(Key *)setup_value = getKeyFromKeyName(token_value); break; case TYPE_KEY_X11: *(Key *)setup_value = getKeyFromX11KeyName(token_value); break; case TYPE_INTEGER: *(int *)setup_value = get_integer_from_string(token_value); break; case TYPE_STRING: checked_free(*(char **)setup_value); *(char **)setup_value = getStringCopy(token_value); break; default: break; } } static int compareTreeInfoEntries(const void *object1, const void *object2) { const TreeInfo *entry1 = *((TreeInfo **)object1); const TreeInfo *entry2 = *((TreeInfo **)object2); int class_sorting1 = 0, class_sorting2 = 0; int compare_result; if (entry1->type == TREE_TYPE_LEVEL_DIR) { class_sorting1 = LEVELSORTING(entry1); class_sorting2 = LEVELSORTING(entry2); } else if (entry1->type == TREE_TYPE_GRAPHICS_DIR || entry1->type == TREE_TYPE_SOUNDS_DIR || entry1->type == TREE_TYPE_MUSIC_DIR) { class_sorting1 = ARTWORKSORTING(entry1); class_sorting2 = ARTWORKSORTING(entry2); } if (entry1->parent_link || entry2->parent_link) compare_result = (entry1->parent_link ? -1 : +1); else if (entry1->sort_priority == entry2->sort_priority) { char *name1 = getStringToLower(entry1->name_sorting); char *name2 = getStringToLower(entry2->name_sorting); compare_result = strcmp(name1, name2); free(name1); free(name2); } else if (class_sorting1 == class_sorting2) compare_result = entry1->sort_priority - entry2->sort_priority; else compare_result = class_sorting1 - class_sorting2; return compare_result; } static TreeInfo *createParentTreeInfoNode(TreeInfo *node_parent) { TreeInfo *ti_new; if (node_parent == NULL) return NULL; ti_new = newTreeInfo(); setTreeInfoToDefaults(ti_new, node_parent->type); ti_new->node_parent = node_parent; ti_new->parent_link = TRUE; setString(&ti_new->identifier, node_parent->identifier); setString(&ti_new->name, ".. (parent directory)"); setString(&ti_new->name_sorting, ti_new->name); setString(&ti_new->subdir, STRING_PARENT_DIRECTORY); setString(&ti_new->fullpath, node_parent->fullpath); ti_new->sort_priority = node_parent->sort_priority; ti_new->latest_engine = node_parent->latest_engine; setString(&ti_new->class_desc, getLevelClassDescription(ti_new)); pushTreeInfo(&node_parent->node_group, ti_new); return ti_new; } static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first) { TreeInfo *ti_new, *ti_new2; if (node_first == NULL) return NULL; ti_new = newTreeInfo(); setTreeInfoToDefaults(ti_new, TREE_TYPE_LEVEL_DIR); ti_new->node_parent = NULL; ti_new->parent_link = FALSE; setString(&ti_new->identifier, node_first->identifier); setString(&ti_new->name, "level sets"); setString(&ti_new->name_sorting, ti_new->name); setString(&ti_new->subdir, STRING_TOP_DIRECTORY); setString(&ti_new->fullpath, "."); ti_new->sort_priority = node_first->sort_priority;; ti_new->latest_engine = node_first->latest_engine; setString(&ti_new->class_desc, "level sets"); ti_new->node_group = node_first; ti_new->level_group = TRUE; ti_new2 = createParentTreeInfoNode(ti_new); setString(&ti_new2->name, ".. (main menu)"); setString(&ti_new2->name_sorting, ti_new2->name); return ti_new; } /* -------------------------------------------------------------------------- */ /* functions for handling level and custom artwork info cache */ /* -------------------------------------------------------------------------- */ static void LoadArtworkInfoCache() { InitCacheDirectory(); if (artworkinfo_cache_old == NULL) { char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); /* try to load artwork info hash from already existing cache file */ artworkinfo_cache_old = loadSetupFileHash(filename); /* if no artwork info cache file was found, start with empty hash */ if (artworkinfo_cache_old == NULL) artworkinfo_cache_old = newSetupFileHash(); free(filename); } if (artworkinfo_cache_new == NULL) artworkinfo_cache_new = newSetupFileHash(); } static void SaveArtworkInfoCache() { char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); InitCacheDirectory(); saveSetupFileHash(artworkinfo_cache_new, filename); free(filename); } static char *getCacheTokenPrefix(char *prefix1, char *prefix2) { static char *prefix = NULL; checked_free(prefix); prefix = getStringCat2WithSeparator(prefix1, prefix2, "."); return prefix; } /* (identical to above function, but separate string buffer needed -- nasty) */ static char *getCacheToken(char *prefix, char *suffix) { static char *token = NULL; checked_free(token); token = getStringCat2WithSeparator(prefix, suffix, "."); return token; } static char *getFileTimestampString(char *filename) { return getStringCopy(i_to_a(getFileTimestampEpochSeconds(filename))); } static boolean modifiedFileTimestamp(char *filename, char *timestamp_string) { struct stat file_status; if (timestamp_string == NULL) return TRUE; if (stat(filename, &file_status) != 0) /* cannot stat file */ return TRUE; return (file_status.st_mtime != atoi(timestamp_string)); } static TreeInfo *getArtworkInfoCacheEntry(LevelDirTree *level_node, int type) { char *identifier = level_node->subdir; char *type_string = ARTWORK_DIRECTORY(type); char *token_prefix = getCacheTokenPrefix(type_string, identifier); char *token_main = getCacheToken(token_prefix, "CACHED"); char *cache_entry = getHashEntry(artworkinfo_cache_old, token_main); boolean cached = (cache_entry != NULL && strEqual(cache_entry, "true")); TreeInfo *artwork_info = NULL; if (!use_artworkinfo_cache) return NULL; if (cached) { int i; artwork_info = newTreeInfo(); setTreeInfoToDefaults(artwork_info, type); /* set all structure fields according to the token/value pairs */ ldi = *artwork_info; for (i = 0; artworkinfo_tokens[i].type != -1; i++) { char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); char *value = getHashEntry(artworkinfo_cache_old, token); /* if defined, use value from cache, else keep default value */ if (value != NULL) setSetupInfo(artworkinfo_tokens, i, value); } *artwork_info = ldi; char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), ARTWORKINFO_FILENAME(type)); /* check if corresponding "levelinfo.conf" file has changed */ token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); cache_entry = getHashEntry(artworkinfo_cache_old, token_main); if (modifiedFileTimestamp(filename_levelinfo, cache_entry)) cached = FALSE; /* check if corresponding ".conf" file has changed */ token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO"); cache_entry = getHashEntry(artworkinfo_cache_old, token_main); if (modifiedFileTimestamp(filename_artworkinfo, cache_entry)) cached = FALSE; checked_free(filename_levelinfo); checked_free(filename_artworkinfo); } if (!cached && artwork_info != NULL) { freeTreeInfo(artwork_info); return NULL; } return artwork_info; } static void setArtworkInfoCacheEntry(TreeInfo *artwork_info, LevelDirTree *level_node, int type) { char *identifier = level_node->subdir; char *type_string = ARTWORK_DIRECTORY(type); char *token_prefix = getCacheTokenPrefix(type_string, identifier); char *token_main = getCacheToken(token_prefix, "CACHED"); boolean set_cache_timestamps = TRUE; int i; setHashEntry(artworkinfo_cache_new, token_main, "true"); if (set_cache_timestamps) { char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), ARTWORKINFO_FILENAME(type)); char *timestamp_levelinfo = getFileTimestampString(filename_levelinfo); char *timestamp_artworkinfo = getFileTimestampString(filename_artworkinfo); token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); setHashEntry(artworkinfo_cache_new, token_main, timestamp_levelinfo); token_main = getCacheToken(token_prefix, "TIMESTAMP_ARTWORKINFO"); setHashEntry(artworkinfo_cache_new, token_main, timestamp_artworkinfo); checked_free(filename_levelinfo); checked_free(filename_artworkinfo); checked_free(timestamp_levelinfo); checked_free(timestamp_artworkinfo); } ldi = *artwork_info; for (i = 0; artworkinfo_tokens[i].type != -1; i++) { char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); char *value = getSetupValue(artworkinfo_tokens[i].type, artworkinfo_tokens[i].value); if (value != NULL) setHashEntry(artworkinfo_cache_new, token, value); } } /* -------------------------------------------------------------------------- */ /* functions for loading level info and custom artwork info */ /* -------------------------------------------------------------------------- */ /* forward declaration for recursive call by "LoadLevelInfoFromLevelDir()" */ static void LoadLevelInfoFromLevelDir(TreeInfo **, TreeInfo *, char *); static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, TreeInfo *node_parent, char *level_directory, char *directory_name) { char *directory_path = getPath2(level_directory, directory_name); char *filename = getPath2(directory_path, LEVELINFO_FILENAME); SetupFileHash *setup_file_hash; LevelDirTree *leveldir_new = NULL; int i; /* unless debugging, silently ignore directories without "levelinfo.conf" */ if (!options.debug && !fileExists(filename)) { free(directory_path); free(filename); return FALSE; } setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash == NULL) { Error(ERR_WARN, "ignoring level directory '%s'", directory_path); free(directory_path); free(filename); return FALSE; } leveldir_new = newTreeInfo(); if (node_parent) setTreeInfoToDefaultsFromParent(leveldir_new, node_parent); else setTreeInfoToDefaults(leveldir_new, TREE_TYPE_LEVEL_DIR); leveldir_new->subdir = getStringCopy(directory_name); /* set all structure fields according to the token/value pairs */ ldi = *leveldir_new; for (i = 0; i < NUM_LEVELINFO_TOKENS; i++) setSetupInfo(levelinfo_tokens, i, getHashEntry(setup_file_hash, levelinfo_tokens[i].text)); *leveldir_new = ldi; if (strEqual(leveldir_new->name, ANONYMOUS_NAME)) setString(&leveldir_new->name, leveldir_new->subdir); if (leveldir_new->identifier == NULL) leveldir_new->identifier = getStringCopy(leveldir_new->subdir); if (leveldir_new->name_sorting == NULL) leveldir_new->name_sorting = getStringCopy(leveldir_new->name); if (node_parent == NULL) /* top level group */ { leveldir_new->basepath = getStringCopy(level_directory); leveldir_new->fullpath = getStringCopy(leveldir_new->subdir); } else /* sub level group */ { leveldir_new->basepath = getStringCopy(node_parent->basepath); leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name); } leveldir_new->last_level = leveldir_new->first_level + leveldir_new->levels - 1; leveldir_new->in_user_dir = (!strEqual(leveldir_new->basepath, options.level_directory)); /* adjust some settings if user's private level directory was detected */ if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED && leveldir_new->in_user_dir && (strEqual(leveldir_new->subdir, getLoginName()) || strEqual(leveldir_new->name, getLoginName()) || strEqual(leveldir_new->author, getRealName()))) { leveldir_new->sort_priority = LEVELCLASS_PRIVATE_START; leveldir_new->readonly = FALSE; } leveldir_new->user_defined = (leveldir_new->in_user_dir && IS_LEVELCLASS_PRIVATE(leveldir_new)); leveldir_new->color = LEVELCOLOR(leveldir_new); setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new)); leveldir_new->handicap_level = /* set handicap to default value */ (leveldir_new->user_defined || !leveldir_new->handicap ? leveldir_new->last_level : leveldir_new->first_level); DrawInitText(leveldir_new->name, 150, FC_YELLOW); pushTreeInfo(node_first, leveldir_new); freeSetupFileHash(setup_file_hash); if (leveldir_new->level_group) { /* create node to link back to current level directory */ createParentTreeInfoNode(leveldir_new); /* recursively step into sub-directory and look for more level series */ LoadLevelInfoFromLevelDir(&leveldir_new->node_group, leveldir_new, directory_path); } free(directory_path); free(filename); return TRUE; } static void LoadLevelInfoFromLevelDir(TreeInfo **node_first, TreeInfo *node_parent, char *level_directory) { Directory *dir; DirectoryEntry *dir_entry; boolean valid_entry_found = FALSE; if ((dir = openDirectory(level_directory)) == NULL) { Error(ERR_WARN, "cannot read level directory '%s'", level_directory); return; } while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ { char *directory_name = dir_entry->basename; char *directory_path = getPath2(level_directory, directory_name); /* skip entries for current and parent directory */ if (strEqual(directory_name, ".") || strEqual(directory_name, "..")) { free(directory_path); continue; } /* find out if directory entry is itself a directory */ if (!dir_entry->is_directory) /* not a directory */ { free(directory_path); continue; } free(directory_path); if (strEqual(directory_name, GRAPHICS_DIRECTORY) || strEqual(directory_name, SOUNDS_DIRECTORY) || strEqual(directory_name, MUSIC_DIRECTORY)) continue; valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent, level_directory, directory_name); } closeDirectory(dir); /* special case: top level directory may directly contain "levelinfo.conf" */ if (node_parent == NULL && !valid_entry_found) { /* check if this directory directly contains a file "levelinfo.conf" */ valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent, level_directory, "."); } if (!valid_entry_found) Error(ERR_WARN, "cannot find any valid level series in directory '%s'", level_directory); } boolean AdjustGraphicsForEMC() { boolean settings_changed = FALSE; settings_changed |= adjustTreeGraphicsForEMC(leveldir_first_all); settings_changed |= adjustTreeGraphicsForEMC(leveldir_first); return settings_changed; } void LoadLevelInfo() { InitUserLevelDirectory(getLoginName()); DrawInitText("Loading level series", 120, FC_GREEN); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL)); leveldir_first = createTopTreeInfoNode(leveldir_first); /* after loading all level set information, clone the level directory tree and remove all level sets without levels (these may still contain artwork to be offered in the setup menu as "custom artwork", and are therefore checked for existing artwork in the function "LoadLevelArtworkInfo()") */ leveldir_first_all = leveldir_first; cloneTree(&leveldir_first, leveldir_first_all, TRUE); AdjustGraphicsForEMC(); /* before sorting, the first entries will be from the user directory */ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); if (leveldir_first == NULL) Error(ERR_EXIT, "cannot find any valid level series in any directory"); sortTreeInfo(&leveldir_first); #if ENABLE_UNUSED_CODE dumpTreeInfo(leveldir_first, 0); #endif } static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, TreeInfo *node_parent, char *base_directory, char *directory_name, int type) { char *directory_path = getPath2(base_directory, directory_name); char *filename = getPath2(directory_path, ARTWORKINFO_FILENAME(type)); SetupFileHash *setup_file_hash = NULL; TreeInfo *artwork_new = NULL; int i; if (fileExists(filename)) setup_file_hash = loadSetupFileHash(filename); if (setup_file_hash == NULL) /* no config file -- look for artwork files */ { Directory *dir; DirectoryEntry *dir_entry; boolean valid_file_found = FALSE; if ((dir = openDirectory(directory_path)) != NULL) { while ((dir_entry = readDirectory(dir)) != NULL) { if (FileIsArtworkType(dir_entry->filename, type)) { valid_file_found = TRUE; break; } } closeDirectory(dir); } if (!valid_file_found) { if (!strEqual(directory_name, ".")) Error(ERR_WARN, "ignoring artwork directory '%s'", directory_path); free(directory_path); free(filename); return FALSE; } } artwork_new = newTreeInfo(); if (node_parent) setTreeInfoToDefaultsFromParent(artwork_new, node_parent); else setTreeInfoToDefaults(artwork_new, type); artwork_new->subdir = getStringCopy(directory_name); if (setup_file_hash) /* (before defining ".color" and ".class_desc") */ { /* set all structure fields according to the token/value pairs */ ldi = *artwork_new; for (i = 0; i < NUM_LEVELINFO_TOKENS; i++) setSetupInfo(levelinfo_tokens, i, getHashEntry(setup_file_hash, levelinfo_tokens[i].text)); *artwork_new = ldi; if (strEqual(artwork_new->name, ANONYMOUS_NAME)) setString(&artwork_new->name, artwork_new->subdir); if (artwork_new->identifier == NULL) artwork_new->identifier = getStringCopy(artwork_new->subdir); if (artwork_new->name_sorting == NULL) artwork_new->name_sorting = getStringCopy(artwork_new->name); } if (node_parent == NULL) /* top level group */ { artwork_new->basepath = getStringCopy(base_directory); artwork_new->fullpath = getStringCopy(artwork_new->subdir); } else /* sub level group */ { artwork_new->basepath = getStringCopy(node_parent->basepath); artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name); } artwork_new->in_user_dir = (!strEqual(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type))); /* (may use ".sort_priority" from "setup_file_hash" above) */ artwork_new->color = ARTWORKCOLOR(artwork_new); setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); if (setup_file_hash == NULL) /* (after determining ".user_defined") */ { if (strEqual(artwork_new->subdir, ".")) { if (artwork_new->user_defined) { setString(&artwork_new->identifier, "private"); artwork_new->sort_priority = ARTWORKCLASS_PRIVATE; } else { setString(&artwork_new->identifier, "classic"); artwork_new->sort_priority = ARTWORKCLASS_CLASSICS; } /* set to new values after changing ".sort_priority" */ artwork_new->color = ARTWORKCOLOR(artwork_new); setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); } else { setString(&artwork_new->identifier, artwork_new->subdir); } setString(&artwork_new->name, artwork_new->identifier); setString(&artwork_new->name_sorting, artwork_new->name); } pushTreeInfo(node_first, artwork_new); freeSetupFileHash(setup_file_hash); free(directory_path); free(filename); return TRUE; } static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first, TreeInfo *node_parent, char *base_directory, int type) { Directory *dir; DirectoryEntry *dir_entry; boolean valid_entry_found = FALSE; if ((dir = openDirectory(base_directory)) == NULL) { /* display error if directory is main "options.graphics_directory" etc. */ if (base_directory == OPTIONS_ARTWORK_DIRECTORY(type)) Error(ERR_WARN, "cannot read directory '%s'", base_directory); return; } while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ { char *directory_name = dir_entry->basename; char *directory_path = getPath2(base_directory, directory_name); /* skip directory entries for current and parent directory */ if (strEqual(directory_name, ".") || strEqual(directory_name, "..")) { free(directory_path); continue; } /* skip directory entries which are not a directory */ if (!dir_entry->is_directory) /* not a directory */ { free(directory_path); continue; } free(directory_path); /* check if this directory contains artwork with or without config file */ valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent, base_directory, directory_name, type); } closeDirectory(dir); /* check if this directory directly contains artwork itself */ valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent, base_directory, ".", type); if (!valid_entry_found) Error(ERR_WARN, "cannot find any valid artwork in directory '%s'", base_directory); } static TreeInfo *getDummyArtworkInfo(int type) { /* this is only needed when there is completely no artwork available */ TreeInfo *artwork_new = newTreeInfo(); setTreeInfoToDefaults(artwork_new, type); setString(&artwork_new->subdir, UNDEFINED_FILENAME); setString(&artwork_new->fullpath, UNDEFINED_FILENAME); setString(&artwork_new->basepath, UNDEFINED_FILENAME); setString(&artwork_new->identifier, UNDEFINED_FILENAME); setString(&artwork_new->name, UNDEFINED_FILENAME); setString(&artwork_new->name_sorting, UNDEFINED_FILENAME); return artwork_new; } void LoadArtworkInfo() { LoadArtworkInfoCache(); DrawInitText("Looking for custom artwork", 120, FC_GREEN); LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL, options.graphics_directory, TREE_TYPE_GRAPHICS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL, getUserGraphicsDir(), TREE_TYPE_GRAPHICS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.snd_first, NULL, options.sounds_directory, TREE_TYPE_SOUNDS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.snd_first, NULL, getUserSoundsDir(), TREE_TYPE_SOUNDS_DIR); LoadArtworkInfoFromArtworkDir(&artwork.mus_first, NULL, options.music_directory, TREE_TYPE_MUSIC_DIR); LoadArtworkInfoFromArtworkDir(&artwork.mus_first, NULL, getUserMusicDir(), TREE_TYPE_MUSIC_DIR); if (artwork.gfx_first == NULL) artwork.gfx_first = getDummyArtworkInfo(TREE_TYPE_GRAPHICS_DIR); if (artwork.snd_first == NULL) artwork.snd_first = getDummyArtworkInfo(TREE_TYPE_SOUNDS_DIR); if (artwork.mus_first == NULL) artwork.mus_first = getDummyArtworkInfo(TREE_TYPE_MUSIC_DIR); /* before sorting, the first entries will be from the user directory */ artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set); if (artwork.gfx_current == NULL) artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR); if (artwork.gfx_current == NULL) artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first); artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set); if (artwork.snd_current == NULL) artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR); if (artwork.snd_current == NULL) artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first); artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set); if (artwork.mus_current == NULL) artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR); if (artwork.mus_current == NULL) artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first); artwork.gfx_current_identifier = artwork.gfx_current->identifier; artwork.snd_current_identifier = artwork.snd_current->identifier; artwork.mus_current_identifier = artwork.mus_current->identifier; #if ENABLE_UNUSED_CODE printf("graphics set == %s\n\n", artwork.gfx_current_identifier); printf("sounds set == %s\n\n", artwork.snd_current_identifier); printf("music set == %s\n\n", artwork.mus_current_identifier); #endif sortTreeInfo(&artwork.gfx_first); sortTreeInfo(&artwork.snd_first); sortTreeInfo(&artwork.mus_first); #if ENABLE_UNUSED_CODE dumpTreeInfo(artwork.gfx_first, 0); dumpTreeInfo(artwork.snd_first, 0); dumpTreeInfo(artwork.mus_first, 0); #endif } void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, LevelDirTree *level_node) { int type = (*artwork_node)->type; /* recursively check all level directories for artwork sub-directories */ while (level_node) { /* check all tree entries for artwork, but skip parent link entries */ if (!level_node->parent_link) { TreeInfo *artwork_new = getArtworkInfoCacheEntry(level_node, type); boolean cached = (artwork_new != NULL); if (cached) { pushTreeInfo(artwork_node, artwork_new); } else { TreeInfo *topnode_last = *artwork_node; char *path = getPath2(getLevelDirFromTreeInfo(level_node), ARTWORK_DIRECTORY(type)); LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path, type); if (topnode_last != *artwork_node) /* check for newly added node */ { artwork_new = *artwork_node; setString(&artwork_new->identifier, level_node->subdir); setString(&artwork_new->name, level_node->name); setString(&artwork_new->name_sorting, level_node->name_sorting); artwork_new->sort_priority = level_node->sort_priority; artwork_new->color = LEVELCOLOR(artwork_new); } free(path); } /* insert artwork info (from old cache or filesystem) into new cache */ if (artwork_new != NULL) setArtworkInfoCacheEntry(artwork_new, level_node, type); } DrawInitText(level_node->name, 150, FC_YELLOW); if (level_node->node_group != NULL) LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group); level_node = level_node->next; } } void LoadLevelArtworkInfo() { print_timestamp_init("LoadLevelArtworkInfo"); DrawInitText("Looking for custom level artwork", 120, FC_GREEN); print_timestamp_time("DrawTimeText"); LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all); print_timestamp_time("LoadArtworkInfoFromLevelInfo (gfx)"); LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all); print_timestamp_time("LoadArtworkInfoFromLevelInfo (snd)"); LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all); print_timestamp_time("LoadArtworkInfoFromLevelInfo (mus)"); SaveArtworkInfoCache(); print_timestamp_time("SaveArtworkInfoCache"); /* needed for reloading level artwork not known at ealier stage */ if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set)) { artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set); if (artwork.gfx_current == NULL) artwork.gfx_current = getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR); if (artwork.gfx_current == NULL) artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first); } if (!strEqual(artwork.snd_current_identifier, setup.sounds_set)) { artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set); if (artwork.snd_current == NULL) artwork.snd_current = getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR); if (artwork.snd_current == NULL) artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first); } if (!strEqual(artwork.mus_current_identifier, setup.music_set)) { artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set); if (artwork.mus_current == NULL) artwork.mus_current = getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR); if (artwork.mus_current == NULL) artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first); } print_timestamp_time("getTreeInfoFromIdentifier"); sortTreeInfo(&artwork.gfx_first); sortTreeInfo(&artwork.snd_first); sortTreeInfo(&artwork.mus_first); print_timestamp_time("sortTreeInfo"); #if ENABLE_UNUSED_CODE dumpTreeInfo(artwork.gfx_first, 0); dumpTreeInfo(artwork.snd_first, 0); dumpTreeInfo(artwork.mus_first, 0); #endif print_timestamp_done("LoadLevelArtworkInfo"); } static boolean AddUserLevelSetToLevelInfoExt(char *level_subdir_new) { // get level info tree node of first (original) user level set char *level_subdir_old = getLoginName(); LevelDirTree *leveldir_old = getTreeInfoFromIdentifier(leveldir_first, level_subdir_old); if (leveldir_old == NULL) // should not happen return FALSE; int draw_deactivation_mask = GetDrawDeactivationMask(); // override draw deactivation mask (temporarily disable drawing) SetDrawDeactivationMask(REDRAW_ALL); // load new level set config and add it next to first user level set LoadLevelInfoFromLevelConf(&leveldir_old->next, NULL, leveldir_old->basepath, level_subdir_new); // set draw deactivation mask to previous value SetDrawDeactivationMask(draw_deactivation_mask); // get level info tree node of newly added user level set LevelDirTree *leveldir_new = getTreeInfoFromIdentifier(leveldir_first, level_subdir_new); if (leveldir_new == NULL) // should not happen return FALSE; // correct top link and parent node link of newly created tree node leveldir_new->node_top = leveldir_old->node_top; leveldir_new->node_parent = leveldir_old->node_parent; // sort level info tree to adjust position of newly added level set sortTreeInfo(&leveldir_first); return TRUE; } void AddUserLevelSetToLevelInfo(char *level_subdir_new) { if (!AddUserLevelSetToLevelInfoExt(level_subdir_new)) Error(ERR_EXIT, "internal level set structure corrupted -- aborting"); } char *getArtworkIdentifierForUserLevelSet(int type) { char *classic_artwork_set = getClassicArtworkSet(type); /* check for custom artwork configured in "levelinfo.conf" */ char *leveldir_artwork_set = *LEVELDIR_ARTWORK_SET_PTR(leveldir_current, type); boolean has_leveldir_artwork_set = (leveldir_artwork_set != NULL && !strEqual(leveldir_artwork_set, classic_artwork_set)); /* check for custom artwork in sub-directory "graphics" etc. */ TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type); char *leveldir_identifier = leveldir_current->identifier; boolean has_artwork_subdir = (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier) != NULL); return (has_leveldir_artwork_set ? leveldir_artwork_set : has_artwork_subdir ? leveldir_identifier : classic_artwork_set); } TreeInfo *getArtworkTreeInfoForUserLevelSet(int type) { char *artwork_set = getArtworkIdentifierForUserLevelSet(type); TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type); return getTreeInfoFromIdentifier(artwork_first_node, artwork_set); } boolean checkIfCustomArtworkExistsForCurrentLevelSet() { char *graphics_set = getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_GRAPHICS); char *sounds_set = getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_SOUNDS); char *music_set = getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_MUSIC); return (!strEqual(graphics_set, GFX_CLASSIC_SUBDIR) || !strEqual(sounds_set, SND_CLASSIC_SUBDIR) || !strEqual(music_set, MUS_CLASSIC_SUBDIR)); } boolean UpdateUserLevelSet(char *level_subdir, char *level_name, char *level_author, int num_levels) { char *filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME); char *filename_tmp = getStringCat2(filename, ".tmp"); FILE *file = NULL; FILE *file_tmp = NULL; char line[MAX_LINE_LEN]; boolean success = FALSE; LevelDirTree *leveldir = getTreeInfoFromIdentifier(leveldir_first, level_subdir); // update values in level directory tree if (level_name != NULL) setString(&leveldir->name, level_name); if (level_author != NULL) setString(&leveldir->author, level_author); if (num_levels != -1) leveldir->levels = num_levels; // update values that depend on other values setString(&leveldir->name_sorting, leveldir->name); leveldir->last_level = leveldir->first_level + leveldir->levels - 1; // sort order of level sets may have changed sortTreeInfo(&leveldir_first); if ((file = fopen(filename, MODE_READ)) && (file_tmp = fopen(filename_tmp, MODE_WRITE))) { while (fgets(line, MAX_LINE_LEN, file)) { if (strPrefix(line, "name:") && level_name != NULL) fprintf(file_tmp, "%-32s%s\n", "name:", level_name); else if (strPrefix(line, "author:") && level_author != NULL) fprintf(file_tmp, "%-32s%s\n", "author:", level_author); else if (strPrefix(line, "levels:") && num_levels != -1) fprintf(file_tmp, "%-32s%d\n", "levels:", num_levels); else fputs(line, file_tmp); } success = TRUE; } if (file) fclose(file); if (file_tmp) fclose(file_tmp); if (success) success = (rename(filename_tmp, filename) == 0); free(filename); free(filename_tmp); return success; } boolean CreateUserLevelSet(char *level_subdir, char *level_name, char *level_author, int num_levels, boolean use_artwork_set) { LevelDirTree *level_info; char *filename; FILE *file; int i; // create user level sub-directory, if needed createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE); filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write level info file '%s'", filename); free(filename); return FALSE; } level_info = newTreeInfo(); /* always start with reliable default values */ setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR); setString(&level_info->name, level_name); setString(&level_info->author, level_author); level_info->levels = num_levels; level_info->first_level = 1; level_info->sort_priority = LEVELCLASS_PRIVATE_START; level_info->readonly = FALSE; if (use_artwork_set) { level_info->graphics_set = getStringCopy(getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_GRAPHICS)); level_info->sounds_set = getStringCopy(getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_SOUNDS)); level_info->music_set = getStringCopy(getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_MUSIC)); } token_value_position = TOKEN_VALUE_POSITION_SHORT; fprintFileHeader(file, LEVELINFO_FILENAME); ldi = *level_info; for (i = 0; i < NUM_LEVELINFO_TOKENS; i++) { if (i == LEVELINFO_TOKEN_NAME || i == LEVELINFO_TOKEN_AUTHOR || i == LEVELINFO_TOKEN_LEVELS || i == LEVELINFO_TOKEN_FIRST_LEVEL || i == LEVELINFO_TOKEN_SORT_PRIORITY || i == LEVELINFO_TOKEN_READONLY || (use_artwork_set && (i == LEVELINFO_TOKEN_GRAPHICS_SET || i == LEVELINFO_TOKEN_SOUNDS_SET || i == LEVELINFO_TOKEN_MUSIC_SET))) fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i)); /* just to make things nicer :) */ if (i == LEVELINFO_TOKEN_AUTHOR || i == LEVELINFO_TOKEN_FIRST_LEVEL || (use_artwork_set && i == LEVELINFO_TOKEN_READONLY)) fprintf(file, "\n"); } token_value_position = TOKEN_VALUE_POSITION_DEFAULT; fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); freeTreeInfo(level_info); free(filename); return TRUE; } static void SaveUserLevelInfo() { CreateUserLevelSet(getLoginName(), getLoginName(), getRealName(), 100, FALSE); } char *getSetupValue(int type, void *value) { static char value_string[MAX_LINE_LEN]; if (value == NULL) return NULL; switch (type) { case TYPE_BOOLEAN: strcpy(value_string, (*(boolean *)value ? "true" : "false")); break; case TYPE_SWITCH: strcpy(value_string, (*(boolean *)value ? "on" : "off")); break; case TYPE_SWITCH3: strcpy(value_string, (*(int *)value == AUTO ? "auto" : *(int *)value == FALSE ? "off" : "on")); break; case TYPE_YES_NO: strcpy(value_string, (*(boolean *)value ? "yes" : "no")); break; case TYPE_YES_NO_AUTO: strcpy(value_string, (*(int *)value == AUTO ? "auto" : *(int *)value == FALSE ? "no" : "yes")); break; case TYPE_ECS_AGA: strcpy(value_string, (*(boolean *)value ? "AGA" : "ECS")); break; case TYPE_KEY: strcpy(value_string, getKeyNameFromKey(*(Key *)value)); break; case TYPE_KEY_X11: strcpy(value_string, getX11KeyNameFromKey(*(Key *)value)); break; case TYPE_INTEGER: sprintf(value_string, "%d", *(int *)value); break; case TYPE_STRING: if (*(char **)value == NULL) return NULL; strcpy(value_string, *(char **)value); break; default: value_string[0] = '\0'; break; } if (type & TYPE_GHOSTED) strcpy(value_string, "n/a"); return value_string; } char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr) { int i; char *line; static char token_string[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; char *value_string = getSetupValue(token_type, setup_value); /* build complete token string */ sprintf(token_string, "%s%s", prefix, token_text); /* build setup entry line */ line = getFormattedSetupEntry(token_string, value_string); if (token_type == TYPE_KEY_X11) { Key key = *(Key *)setup_value; char *keyname = getKeyNameFromKey(key); /* add comment, if useful */ if (!strEqual(keyname, "(undefined)") && !strEqual(keyname, "(unknown)")) { /* add at least one whitespace */ strcat(line, " "); for (i = strlen(line); i < token_comment_position; i++) strcat(line, " "); strcat(line, "# "); strcat(line, keyname); } } return line; } void LoadLevelSetup_LastSeries() { /* ----------------------------------------------------------------------- */ /* ~/./levelsetup.conf */ /* ----------------------------------------------------------------------- */ char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); SetupFileHash *level_setup_hash = NULL; /* always start with reliable default values */ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); if (!strEqual(DEFAULT_LEVELSET, UNDEFINED_LEVELSET)) { leveldir_current = getTreeInfoFromIdentifier(leveldir_first, DEFAULT_LEVELSET); if (leveldir_current == NULL) leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); } if ((level_setup_hash = loadSetupFileHash(filename))) { char *last_level_series = getHashEntry(level_setup_hash, TOKEN_STR_LAST_LEVEL_SERIES); leveldir_current = getTreeInfoFromIdentifier(leveldir_first, last_level_series); if (leveldir_current == NULL) leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); freeSetupFileHash(level_setup_hash); } else { Error(ERR_DEBUG, "using default setup values"); } free(filename); } static void SaveLevelSetup_LastSeries_Ext(boolean deactivate_last_level_series) { /* ----------------------------------------------------------------------- */ /* ~/./levelsetup.conf */ /* ----------------------------------------------------------------------- */ // check if the current level directory structure is available at this point if (leveldir_current == NULL) return; char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); char *level_subdir = leveldir_current->subdir; FILE *file; InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); free(filename); return; } fprintFileHeader(file, LEVELSETUP_FILENAME); if (deactivate_last_level_series) fprintf(file, "# %s\n# ", "the following level set may have caused a problem and was deactivated"); fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES, level_subdir)); fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } void SaveLevelSetup_LastSeries() { SaveLevelSetup_LastSeries_Ext(FALSE); } void SaveLevelSetup_LastSeries_Deactivate() { SaveLevelSetup_LastSeries_Ext(TRUE); } static void checkSeriesInfo() { static char *level_directory = NULL; Directory *dir; /* check for more levels besides the 'levels' field of 'levelinfo.conf' */ level_directory = getPath2((leveldir_current->in_user_dir ? getUserLevelDir(NULL) : options.level_directory), leveldir_current->fullpath); if ((dir = openDirectory(level_directory)) == NULL) { Error(ERR_WARN, "cannot read level directory '%s'", level_directory); return; } closeDirectory(dir); } void LoadLevelSetup_SeriesInfo() { char *filename; SetupFileHash *level_setup_hash = NULL; char *level_subdir = leveldir_current->subdir; int i; /* always start with reliable default values */ level_nr = leveldir_current->first_level; for (i = 0; i < MAX_LEVELS; i++) { LevelStats_setPlayed(i, 0); LevelStats_setSolved(i, 0); } checkSeriesInfo(); /* ----------------------------------------------------------------------- */ /* ~/./levelsetup//levelsetup.conf */ /* ----------------------------------------------------------------------- */ level_subdir = leveldir_current->subdir; filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); if ((level_setup_hash = loadSetupFileHash(filename))) { char *token_value; /* get last played level in this level set */ token_value = getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_LEVEL); if (token_value) { level_nr = atoi(token_value); if (level_nr < leveldir_current->first_level) level_nr = leveldir_current->first_level; if (level_nr > leveldir_current->last_level) level_nr = leveldir_current->last_level; } /* get handicap level in this level set */ token_value = getHashEntry(level_setup_hash, TOKEN_STR_HANDICAP_LEVEL); if (token_value) { int level_nr = atoi(token_value); if (level_nr < leveldir_current->first_level) level_nr = leveldir_current->first_level; if (level_nr > leveldir_current->last_level + 1) level_nr = leveldir_current->last_level; if (leveldir_current->user_defined || !leveldir_current->handicap) level_nr = leveldir_current->last_level; leveldir_current->handicap_level = level_nr; } /* get number of played and solved levels in this level set */ BEGIN_HASH_ITERATION(level_setup_hash, itr) { char *token = HASH_ITERATION_TOKEN(itr); char *value = HASH_ITERATION_VALUE(itr); if (strlen(token) == 3 && token[0] >= '0' && token[0] <= '9' && token[1] >= '0' && token[1] <= '9' && token[2] >= '0' && token[2] <= '9') { int level_nr = atoi(token); if (value != NULL) LevelStats_setPlayed(level_nr, atoi(value)); /* read 1st column */ value = strchr(value, ' '); if (value != NULL) LevelStats_setSolved(level_nr, atoi(value)); /* read 2nd column */ } } END_HASH_ITERATION(hash, itr) freeSetupFileHash(level_setup_hash); } else { Error(ERR_DEBUG, "using default setup values"); } free(filename); } void SaveLevelSetup_SeriesInfo() { char *filename; char *level_subdir = leveldir_current->subdir; char *level_nr_str = int2str(level_nr, 0); char *handicap_level_str = int2str(leveldir_current->handicap_level, 0); FILE *file; int i; /* ----------------------------------------------------------------------- */ /* ~/./levelsetup//levelsetup.conf */ /* ----------------------------------------------------------------------- */ InitLevelSetupDirectory(level_subdir); filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); free(filename); return; } fprintFileHeader(file, LEVELSETUP_FILENAME); fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL, level_nr_str)); fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, handicap_level_str)); for (i = leveldir_current->first_level; i <= leveldir_current->last_level; i++) { if (LevelStats_getPlayed(i) > 0 || LevelStats_getSolved(i) > 0) { char token[16]; char value[16]; sprintf(token, "%03d", i); sprintf(value, "%d %d", LevelStats_getPlayed(i), LevelStats_getSolved(i)); fprintf(file, "%s\n", getFormattedSetupEntry(token, value)); } } fclose(file); SetFilePermissions(filename, PERMS_PRIVATE); free(filename); } int LevelStats_getPlayed(int nr) { return (nr >= 0 && nr < MAX_LEVELS ? level_stats[nr].played : 0); } int LevelStats_getSolved(int nr) { return (nr >= 0 && nr < MAX_LEVELS ? level_stats[nr].solved : 0); } void LevelStats_setPlayed(int nr, int value) { if (nr >= 0 && nr < MAX_LEVELS) level_stats[nr].played = value; } void LevelStats_setSolved(int nr, int value) { if (nr >= 0 && nr < MAX_LEVELS) level_stats[nr].solved = value; } void LevelStats_incPlayed(int nr) { if (nr >= 0 && nr < MAX_LEVELS) level_stats[nr].played++; } void LevelStats_incSolved(int nr) { if (nr >= 0 && nr < MAX_LEVELS) level_stats[nr].solved++; } mirrormagic-3.0.0/src/libgame/misc.c0000644000175000017500000031607013263212010016616 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // misc.c // ============================================================================ #include #include #include #include #include #include #include #include #include #include "platform.h" #if !defined(PLATFORM_WIN32) #include #include #endif #include "misc.h" #include "setup.h" #include "random.h" #include "text.h" #include "image.h" /* ========================================================================= */ /* some generic helper functions */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* logging functions */ /* ------------------------------------------------------------------------- */ #define DUPLICATE_LOG_OUT_TO_STDOUT TRUE #define DUPLICATE_LOG_ERR_TO_STDERR TRUE #if defined(PLATFORM_ANDROID) static int android_log_prio = ANDROID_LOG_INFO; static char *android_log_buffer = NULL; static void append_to_android_log_buffer(char *format, va_list ap) { char text_new[MAX_OUTPUT_LINESIZE]; // print text to temporary string vsnprintf(text_new, MAX_OUTPUT_LINESIZE, format, ap); if (android_log_buffer == NULL) { android_log_buffer = getStringCopy(text_new); } else { char *android_log_buffer_old = android_log_buffer; // append new text to existing text android_log_buffer = getStringCat2(android_log_buffer, text_new); checked_free(android_log_buffer_old); } } static void vprintf_log_nonewline(char *format, va_list ap) { // add log output to buffer until text with newline is printed append_to_android_log_buffer(format, ap); } static void vprintf_log(char *format, va_list ap) { // add log output to buffer append_to_android_log_buffer(format, ap); // __android_log_vprint(android_log_prio, program.program_title, format, ap); __android_log_write(android_log_prio, program.program_title, android_log_buffer); checked_free(android_log_buffer); android_log_buffer = NULL; } #else static void vprintf_log_nonewline(char *format, va_list ap) { FILE *file = program.log_file[LOG_ERR_ID]; #if DUPLICATE_LOG_ERR_TO_STDERR if (file != program.log_file_default[LOG_ERR_ID]) { va_list ap2; va_copy(ap2, ap); vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2); va_end(ap2); } #endif vfprintf(file, format, ap); } static void vprintf_log(char *format, va_list ap) { FILE *file = program.log_file[LOG_ERR_ID]; char *newline = STRING_NEWLINE; #if DUPLICATE_LOG_ERR_TO_STDERR if (file != program.log_file_default[LOG_ERR_ID]) { va_list ap2; va_copy(ap2, ap); vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2); fprintf(program.log_file_default[LOG_ERR_ID], "%s", newline); va_end(ap2); } #endif vfprintf(file, format, ap); fprintf(file, "%s", newline); } #endif static void printf_log_nonewline(char *format, ...) { va_list ap; va_start(ap, format); vprintf_log_nonewline(format, ap); va_end(ap); } static void printf_log(char *format, ...) { va_list ap; va_start(ap, format); vprintf_log(format, ap); va_end(ap); } static void printf_log_line(char *line_chars, int line_length) { int i; for (i = 0; i < line_length; i++) printf_log_nonewline("%s", line_chars); printf_log(""); } /* ------------------------------------------------------------------------- */ /* platform independent wrappers for printf() et al. */ /* ------------------------------------------------------------------------- */ void fprintf_line(FILE *file, char *line_chars, int line_length) { int i; for (i = 0; i < line_length; i++) fprintf(file, "%s", line_chars); fprintf(file, "\n"); } void fprintf_line_with_prefix(FILE *file, char *prefix, char *line_chars, int line_length) { fprintf(file, "%s", prefix); fprintf_line(file, line_chars, line_length); } void printf_line(char *line_chars, int line_length) { fprintf_line(stdout, line_chars, line_length); } void printf_line_with_prefix(char *prefix, char *line_chars, int line_length) { fprintf_line_with_prefix(stdout, prefix, line_chars, line_length); } static void vPrint(char *format, va_list ap) { FILE *file = program.log_file[LOG_OUT_ID]; #if DUPLICATE_LOG_OUT_TO_STDOUT if (file != program.log_file_default[LOG_OUT_ID]) { va_list ap2; va_copy(ap2, ap); vfprintf(program.log_file_default[LOG_OUT_ID], format, ap2); va_end(ap2); } #endif vfprintf(file, format, ap); } void Print(char *format, ...) { va_list ap; va_start(ap, format); vPrint(format, ap); va_end(ap); } void PrintNoLog(char *format, ...) { FILE *file = program.log_file_default[LOG_OUT_ID]; va_list ap; va_start(ap, format); vfprintf(file, format, ap); va_end(ap); fflush(file); } void PrintLine(char *line_chars, int line_length) { int i; for (i = 0; i < line_length; i++) Print(line_chars); Print("\n"); } void PrintLineWithPrefix(char *prefix, char *line_chars, int line_length) { Print(prefix); PrintLine(line_chars, line_length); } /* ------------------------------------------------------------------------- */ /* string functions */ /* ------------------------------------------------------------------------- */ /* int2str() returns a number converted to a string; the used memory is static, but will be overwritten by later calls, so if you want to save the result, copy it to a private string buffer; there can be 10 local calls of int2str() without buffering the result -- the 11th call will then destroy the result from the first call and so on. */ char *int2str(int number, int size) { static char shift_array[10][40]; static int shift_counter = 0; char *s = shift_array[shift_counter]; shift_counter = (shift_counter + 1) % 10; if (size > 20) size = 20; if (size > 0) { sprintf(s, " %09d", number); return &s[strlen(s) - size]; } else { sprintf(s, "%d", number); return s; } } /* something similar to "int2str()" above, but allocates its own memory and has a different interface; we cannot use "itoa()", because this seems to be already defined when cross-compiling to the win32 target */ char *i_to_a(unsigned int i) { static char *a = NULL; checked_free(a); if (i > 2147483647) /* yes, this is a kludge */ i = 2147483647; a = checked_malloc(10 + 1); sprintf(a, "%d", i); return a; } /* calculate base-2 logarithm of argument (rounded down to integer; this function returns the number of the highest bit set in argument) */ int log_2(unsigned int x) { int e = 0; while ((1 << e) < x) { x -= (1 << e); /* for rounding down (rounding up: remove this line) */ e++; } return e; } boolean getTokenValueFromString(char *string, char **token, char **value) { return getTokenValueFromSetupLine(string, token, value); } /* ------------------------------------------------------------------------- */ /* counter functions */ /* ------------------------------------------------------------------------- */ /* maximal allowed length of a command line option */ #define MAX_OPTION_LEN 256 static unsigned int getCurrentMS() { return SDL_GetTicks(); } static unsigned int mainCounter(int mode) { static unsigned int base_ms = 0; unsigned int current_ms; /* get current system milliseconds */ current_ms = getCurrentMS(); /* reset base timestamp in case of counter reset or wrap-around */ if (mode == INIT_COUNTER || current_ms < base_ms) base_ms = current_ms; /* return milliseconds since last counter reset */ return current_ms - base_ms; } void InitCounter() /* set counter back to zero */ { mainCounter(INIT_COUNTER); } unsigned int Counter() /* get milliseconds since last call of InitCounter() */ { return mainCounter(READ_COUNTER); } static void sleep_milliseconds(unsigned int milliseconds_delay) { SDL_Delay(milliseconds_delay); } void Delay(unsigned int delay) /* Sleep specified number of milliseconds */ { sleep_milliseconds(delay); } boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay, unsigned int actual_counter) { if (actual_counter >= *counter_var && actual_counter < *counter_var + delay) return FALSE; *counter_var = actual_counter; return TRUE; } boolean FrameReached(unsigned int *frame_counter_var, unsigned int frame_delay) { return DelayReachedExt(frame_counter_var, frame_delay, FrameCounter); } boolean DelayReached(unsigned int *counter_var, unsigned int delay) { return DelayReachedExt(counter_var, delay, Counter()); } void ResetDelayCounterExt(unsigned int *counter_var, unsigned int actual_counter) { DelayReachedExt(counter_var, 0, actual_counter); } void ResetFrameCounter(unsigned int *frame_counter_var) { FrameReached(frame_counter_var, 0); } void ResetDelayCounter(unsigned int *counter_var) { DelayReached(counter_var, 0); } int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay) { unsigned int actual_counter; int skip_frames = 0; while (1) { actual_counter = Counter(); if (actual_counter >= *counter_var && actual_counter < *counter_var + delay) sleep_milliseconds((*counter_var + delay - actual_counter) / 2); else break; } if (*counter_var != 0 && delay != 0 && actual_counter >= *counter_var + delay) { int lag = actual_counter - (*counter_var + delay); int delay2 = (delay + 1) / 2; if (lag >= delay2) skip_frames = (lag + delay2) / delay; } *counter_var = actual_counter; return skip_frames; } void SkipUntilDelayReached(unsigned int *counter_var, unsigned int delay, int *loop_var, int last_loop_value) { int skip_frames = WaitUntilDelayReached(counter_var, delay); #if 0 #if DEBUG printf("::: %d: %d ms", *loop_var, delay); if (skip_frames) printf(" -> SKIP %d FRAME(S) [%d ms]", skip_frames, skip_frames * delay); printf("\n"); #endif #endif if (skip_frames == 0) return; // when skipping frames, make sure to never skip the last frame, as // this may be needed for animations to reach a defined end state; // furthermore, we assume that this function is called at the end // of a "for" loop, which continues by incrementing the loop variable // by one before checking the loop condition again; therefore we have // to check against the last loop value minus one here last_loop_value--; if (*loop_var < last_loop_value) // never skip the last frame { *loop_var += skip_frames; if (*loop_var > last_loop_value) // never skip the last frame *loop_var = last_loop_value; } } /* ------------------------------------------------------------------------- */ /* random generator functions */ /* ------------------------------------------------------------------------- */ unsigned int init_random_number(int nr, int seed) { if (seed == NEW_RANDOMIZE) { /* default random seed */ seed = (int)time(NULL); // seconds since the epoch #if !defined(PLATFORM_WIN32) /* add some more randomness */ struct timeval current_time; gettimeofday(¤t_time, NULL); seed += (int)current_time.tv_usec; // microseconds since the epoch #endif /* add some more randomness */ seed += (int)SDL_GetTicks(); // milliseconds since SDL init /* add some more randomness */ seed += GetSimpleRandom(1000000); } srandom_linux_libc(nr, (unsigned int) seed); return (unsigned int) seed; } unsigned int get_random_number(int nr, int max) { return (max > 0 ? random_linux_libc(nr) % max : 0); } /* ------------------------------------------------------------------------- */ /* system info functions */ /* ------------------------------------------------------------------------- */ #if !defined(PLATFORM_ANDROID) static char *get_corrected_real_name(char *real_name) { char *real_name_new = checked_malloc(MAX_USERNAME_LEN + 1); char *from_ptr = real_name; char *to_ptr = real_name_new; /* copy the name string, but not more than MAX_USERNAME_LEN characters */ while (*from_ptr && (int)(to_ptr - real_name_new) < MAX_USERNAME_LEN - 1) { /* the name field read from "passwd" file may also contain additional user information, separated by commas, which will be removed here */ if (*from_ptr == ',') break; /* the user's real name may contain 'german sharp s' characters, which have no equivalent in upper case letters (used by our fonts) */ if (*from_ptr == CHAR_BYTE_SHARP_S) { from_ptr++; *to_ptr++ = 's'; *to_ptr++ = 's'; } else *to_ptr++ = *from_ptr++; } *to_ptr = '\0'; return real_name_new; } #endif char *getLoginName() { static char *login_name = NULL; #if defined(PLATFORM_WIN32) if (login_name == NULL) { unsigned long buffer_size = MAX_USERNAME_LEN + 1; login_name = checked_malloc(buffer_size); if (GetUserName(login_name, &buffer_size) == 0) strcpy(login_name, ANONYMOUS_NAME); } #elif defined(PLATFORM_UNIX) && !defined(PLATFORM_ANDROID) if (login_name == NULL) { struct passwd *pwd; if ((pwd = getpwuid(getuid())) == NULL) login_name = ANONYMOUS_NAME; else login_name = getStringCopy(pwd->pw_name); } #else login_name = ANONYMOUS_NAME; #endif return login_name; } char *getRealName() { static char *real_name = NULL; #if defined(PLATFORM_WIN32) if (real_name == NULL) { static char buffer[MAX_USERNAME_LEN + 1]; unsigned long buffer_size = MAX_USERNAME_LEN + 1; if (GetUserName(buffer, &buffer_size) != 0) real_name = get_corrected_real_name(buffer); else real_name = ANONYMOUS_NAME; } #elif defined(PLATFORM_UNIX) && !defined(PLATFORM_ANDROID) if (real_name == NULL) { struct passwd *pwd; if ((pwd = getpwuid(getuid())) != NULL && strlen(pwd->pw_gecos) != 0) real_name = get_corrected_real_name(pwd->pw_gecos); else real_name = ANONYMOUS_NAME; } #else real_name = ANONYMOUS_NAME; #endif return real_name; } time_t getFileTimestampEpochSeconds(char *filename) { struct stat file_status; if (stat(filename, &file_status) != 0) /* cannot stat file */ return 0; return file_status.st_mtime; } /* ------------------------------------------------------------------------- */ /* path manipulation functions */ /* ------------------------------------------------------------------------- */ static char *getLastPathSeparatorPtr(char *filename) { char *last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_UNIX); if (last_separator == NULL) /* also try DOS/Windows variant */ last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_DOS); return last_separator; } char *getBaseNamePtr(char *filename) { char *last_separator = getLastPathSeparatorPtr(filename); if (last_separator != NULL) return last_separator + 1; /* separator found: strip base path */ else return filename; /* no separator found: filename has no path */ } char *getBaseName(char *filename) { return getStringCopy(getBaseNamePtr(filename)); } char *getBaseNameNoSuffix(char *filename) { char *basename = getStringCopy(getBaseNamePtr(filename)); // remove trailing suffix (separated by dot or hyphen) if (basename[0] != '.' && basename[0] != '-') { if (strchr(basename, '.') != NULL) *strchr(basename, '.') = '\0'; if (strchr(basename, '-') != NULL) *strchr(basename, '-') = '\0'; } return basename; } char *getBasePath(char *filename) { char *basepath = getStringCopy(filename); char *last_separator = getLastPathSeparatorPtr(basepath); /* if no separator was found, use current directory */ if (last_separator == NULL) { free(basepath); return getStringCopy("."); } /* separator found: strip basename */ *last_separator = '\0'; return basepath; } /* ------------------------------------------------------------------------- */ /* various string functions */ /* ------------------------------------------------------------------------- */ char *getStringCat2WithSeparator(char *s1, char *s2, char *sep) { if (s1 == NULL || s2 == NULL || sep == NULL) return NULL; char *complete_string = checked_malloc(strlen(s1) + strlen(sep) + strlen(s2) + 1); sprintf(complete_string, "%s%s%s", s1, sep, s2); return complete_string; } char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep) { if (s1 == NULL || s2 == NULL || s3 == NULL || sep == NULL) return NULL; char *complete_string = checked_malloc(strlen(s1) + strlen(sep) + strlen(s2) + strlen(sep) + strlen(s3) + 1); sprintf(complete_string, "%s%s%s%s%s", s1, sep, s2, sep, s3); return complete_string; } char *getStringCat2(char *s1, char *s2) { return getStringCat2WithSeparator(s1, s2, ""); } char *getStringCat3(char *s1, char *s2, char *s3) { return getStringCat3WithSeparator(s1, s2, s3, ""); } char *getPath2(char *path1, char *path2) { #if defined(PLATFORM_ANDROID) // workaround for reading from assets directory -- skip "." subdirs in path if (strEqual(path1, ".")) return getStringCopy(path2); else if (strEqual(path2, ".")) return getStringCopy(path1); #endif return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR); } char *getPath3(char *path1, char *path2, char *path3) { #if defined(PLATFORM_ANDROID) // workaround for reading from assets directory -- skip "." subdirs in path if (strEqual(path1, ".")) return getStringCat2WithSeparator(path2, path3, STRING_PATH_SEPARATOR); else if (strEqual(path2, ".")) return getStringCat2WithSeparator(path1, path3, STRING_PATH_SEPARATOR); else if (strEqual(path3, ".")) return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR); #endif return getStringCat3WithSeparator(path1, path2, path3, STRING_PATH_SEPARATOR); } static char *getPngOrPcxIfNotExists(char *filename) { // switch from PNG to PCX file and vice versa, if file does not exist // (backwards compatibility with PCX files used in previous versions) if (!fileExists(filename) && strSuffix(filename, ".png")) strcpy(&filename[strlen(filename) - 3], "pcx"); else if (!fileExists(filename) && strSuffix(filename, ".pcx")) strcpy(&filename[strlen(filename) - 3], "png"); return filename; } char *getImg2(char *path1, char *path2) { return getPngOrPcxIfNotExists(getPath2(path1, path2)); } char *getImg3(char *path1, char *path2, char *path3) { return getPngOrPcxIfNotExists(getPath3(path1, path2, path3)); } char *getStringCopy(const char *s) { char *s_copy; if (s == NULL) return NULL; s_copy = checked_malloc(strlen(s) + 1); strcpy(s_copy, s); return s_copy; } char *getStringCopyN(const char *s, int n) { char *s_copy; int s_len = MAX(0, n); if (s == NULL) return NULL; s_copy = checked_malloc(s_len + 1); strncpy(s_copy, s, s_len); s_copy[s_len] = '\0'; return s_copy; } char *getStringCopyNStatic(const char *s, int n) { static char *s_copy = NULL; checked_free(s_copy); s_copy = getStringCopyN(s, n); return s_copy; } char *getStringToLower(const char *s) { char *s_copy = checked_malloc(strlen(s) + 1); char *s_ptr = s_copy; while (*s) *s_ptr++ = tolower(*s++); *s_ptr = '\0'; return s_copy; } void setString(char **old_value, char *new_value) { checked_free(*old_value); *old_value = getStringCopy(new_value); } boolean strEqual(char *s1, char *s2) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : s1 != NULL && s2 == NULL ? FALSE : strcmp(s1, s2) == 0); } boolean strEqualN(char *s1, char *s2, int n) { return (s1 == NULL && s2 == NULL ? TRUE : s1 == NULL && s2 != NULL ? FALSE : s1 != NULL && s2 == NULL ? FALSE : strncmp(s1, s2, n) == 0); } boolean strPrefix(char *s, char *prefix) { return (s == NULL && prefix == NULL ? TRUE : s == NULL && prefix != NULL ? FALSE : s != NULL && prefix == NULL ? FALSE : strncmp(s, prefix, strlen(prefix)) == 0); } boolean strSuffix(char *s, char *suffix) { return (s == NULL && suffix == NULL ? TRUE : s == NULL && suffix != NULL ? FALSE : s != NULL && suffix == NULL ? FALSE : strlen(s) < strlen(suffix) ? FALSE : strncmp(&s[strlen(s) - strlen(suffix)], suffix, strlen(suffix)) == 0); } boolean strPrefixLower(char *s, char *prefix) { char *s_lower = getStringToLower(s); boolean match = strPrefix(s_lower, prefix); free(s_lower); return match; } boolean strSuffixLower(char *s, char *suffix) { char *s_lower = getStringToLower(s); boolean match = strSuffix(s_lower, suffix); free(s_lower); return match; } /* ------------------------------------------------------------------------- */ /* command line option handling functions */ /* ------------------------------------------------------------------------- */ void GetOptions(int argc, char *argv[], void (*print_usage_function)(void), void (*print_version_function)(void)) { char *ro_base_path = getProgramMainDataPath(argv[0], RO_BASE_PATH); char *rw_base_path = getProgramMainDataPath(argv[0], RW_BASE_PATH); char **argvplus = checked_calloc((argc + 1) * sizeof(char **)); char **options_left = &argvplus[1]; /* replace original "argv" with null-terminated array of string pointers */ while (argc--) argvplus[argc] = argv[argc]; /* initialize global program options */ options.server_host = NULL; options.server_port = 0; options.ro_base_directory = ro_base_path; options.rw_base_directory = rw_base_path; options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY); options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY); options.sounds_directory = getPath2(ro_base_path, SOUNDS_DIRECTORY); options.music_directory = getPath2(ro_base_path, MUSIC_DIRECTORY); options.docs_directory = getPath2(ro_base_path, DOCS_DIRECTORY); options.conf_directory = getPath2(ro_base_path, CONF_DIRECTORY); options.execute_command = NULL; options.special_flags = NULL; options.mytapes = FALSE; options.serveronly = FALSE; options.network = FALSE; options.verbose = FALSE; options.debug = FALSE; #if 1 options.verbose = TRUE; #else #if !defined(PLATFORM_UNIX) if (*options_left == NULL) /* no options given -- enable verbose mode */ options.verbose = TRUE; #endif #endif #if DEBUG #if defined(PLATFORM_ANDROID) options.debug = TRUE; #endif #endif while (*options_left) { 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 (strEqual(option, "--")) /* stop scanning arguments */ break; if (strPrefix(option, "--")) /* 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 (strEqual(option, "-")) { Error(ERR_EXIT_HELP, "unrecognized option '%s'", option); } else if (strncmp(option, "-help", option_len) == 0) { print_usage_function(); exit(0); } else if (strncmp(option, "-basepath", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); /* this should be extended to separate options for ro and rw data */ options.ro_base_directory = ro_base_path = option_arg; options.rw_base_directory = rw_base_path = option_arg; if (option_arg == next_option) options_left++; /* adjust paths for sub-directories in base directory accordingly */ options.level_directory = getPath2(ro_base_path, LEVELS_DIRECTORY); options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY); options.sounds_directory = getPath2(ro_base_path, SOUNDS_DIRECTORY); options.music_directory = getPath2(ro_base_path, MUSIC_DIRECTORY); options.docs_directory = getPath2(ro_base_path, DOCS_DIRECTORY); options.conf_directory = getPath2(ro_base_path, CONF_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, "-graphics", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.graphics_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-sounds", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.sounds_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-music", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.music_directory = option_arg; if (option_arg == next_option) options_left++; } else if (strncmp(option, "-mytapes", option_len) == 0) { options.mytapes = TRUE; } 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, "-debug", option_len) == 0) { options.debug = TRUE; } else if (strncmp(option, "-verbose", option_len) == 0) { options.verbose = TRUE; } else if (strncmp(option, "-version", option_len) == 0 || strncmp(option, "-V", option_len) == 0) { print_version_function(); exit(0); } else if (strPrefix(option, "-D")) { options.special_flags = getStringCopy(&option[2]); } else if (strncmp(option, "-execute", option_len) == 0) { if (option_arg == NULL) Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str); options.execute_command = option_arg; if (option_arg == next_option) options_left++; /* when doing batch processing, always enable verbose mode (warnings) */ options.verbose = TRUE; } #if defined(PLATFORM_MACOSX) else if (strPrefix(option, "-psn")) { /* ignore process serial number when launched via GUI on Mac OS X */ } #endif 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++; } } /* ------------------------------------------------------------------------- */ /* error handling functions */ /* ------------------------------------------------------------------------- */ #define MAX_INTERNAL_ERROR_SIZE 1024 /* used by SetError() and GetError() to store internal error messages */ static char internal_error[MAX_INTERNAL_ERROR_SIZE]; void SetError(char *format, ...) { va_list ap; va_start(ap, format); vsnprintf(internal_error, MAX_INTERNAL_ERROR_SIZE, format, ap); va_end(ap); } char *GetError() { return internal_error; } void Error(int mode, char *format, ...) { static boolean last_line_was_separator = FALSE; char *process_name = ""; if (program.log_file[LOG_ERR_ID] == NULL) return; #if defined(PLATFORM_ANDROID) android_log_prio = (mode & ERR_DEBUG ? ANDROID_LOG_DEBUG : mode & ERR_INFO ? ANDROID_LOG_INFO : mode & ERR_WARN ? ANDROID_LOG_WARN : mode & ERR_EXIT ? ANDROID_LOG_FATAL : ANDROID_LOG_UNKNOWN); #endif /* display debug messages only when running in debug mode */ if (mode & ERR_DEBUG && !options.debug) return; /* display warnings only when running in verbose mode */ if (mode & ERR_WARN && !options.verbose) return; if (mode == ERR_INFO_LINE) { if (!last_line_was_separator) printf_log_line(format, 79); last_line_was_separator = TRUE; return; } last_line_was_separator = FALSE; 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 !defined(PLATFORM_ANDROID) printf_log_nonewline("%s%s: ", program.command_basename, process_name); #endif if (mode & ERR_WARN) printf_log_nonewline("warning: "); if (mode & ERR_EXIT) printf_log_nonewline("fatal error: "); va_list ap; va_start(ap, format); vprintf_log(format, ap); va_end(ap); if ((mode & ERR_EXIT) && !(mode & ERR_FROM_SERVER)) { va_start(ap, format); program.exit_message_function(format, ap); va_end(ap); } } if (mode & ERR_HELP) printf_log("%s: Try option '--help' for more information.", program.command_basename); if (mode & ERR_EXIT) printf_log("%s%s: aborting", program.command_basename, process_name); if (mode & ERR_EXIT) { if (mode & ERR_FROM_SERVER) exit(1); /* child process: normal exit */ else program.exit_function(1); /* main process: clean up stuff */ } } /* ------------------------------------------------------------------------- */ /* checked memory allocation and freeing functions */ /* ------------------------------------------------------------------------- */ void *checked_malloc(unsigned int size) { void *ptr; ptr = malloc(size); if (ptr == NULL) Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); return ptr; } void *checked_calloc(unsigned int size) { void *ptr; ptr = calloc(1, size); if (ptr == NULL) Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); return ptr; } void *checked_realloc(void *ptr, unsigned int size) { ptr = realloc(ptr, size); if (ptr == NULL) Error(ERR_EXIT, "cannot allocate %d bytes -- out of memory", size); return ptr; } void checked_free(void *ptr) { if (ptr != NULL) /* this check should be done by free() anyway */ free(ptr); } void clear_mem(void *ptr, unsigned int size) { #if defined(PLATFORM_WIN32) /* for unknown reason, memset() sometimes crashes when compiled with MinGW */ char *cptr = (char *)ptr; while (size--) *cptr++ = 0; #else memset(ptr, 0, size); #endif } /* ------------------------------------------------------------------------- */ /* various helper functions */ /* ------------------------------------------------------------------------- */ void swap_numbers(int *i1, int *i2) { int help = *i1; *i1 = *i2; *i2 = help; } void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) { int help_x = *x1; int help_y = *y1; *x1 = *x2; *x2 = help_x; *y1 = *y2; *y2 = help_y; } /* the "put" variants of the following file access functions check for the file pointer being != NULL and return the number of bytes they have or would have written; this allows for chunk writing functions to first determine the size of the (not yet written) chunk, write the correct chunk size and finally write the chunk itself */ int getFile8BitInteger(File *file) { return getByteFromFile(file); } int putFile8BitInteger(FILE *file, int value) { if (file != NULL) fputc(value, file); return 1; } int getFile16BitInteger(File *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) return ((getByteFromFile(file) << 8) | (getByteFromFile(file) << 0)); else /* BYTE_ORDER_LITTLE_ENDIAN */ return ((getByteFromFile(file) << 0) | (getByteFromFile(file) << 8)); } int putFile16BitInteger(FILE *file, int value, int byte_order) { if (file != NULL) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) { fputc((value >> 8) & 0xff, file); fputc((value >> 0) & 0xff, file); } else /* BYTE_ORDER_LITTLE_ENDIAN */ { fputc((value >> 0) & 0xff, file); fputc((value >> 8) & 0xff, file); } } return 2; } int getFile32BitInteger(File *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) return ((getByteFromFile(file) << 24) | (getByteFromFile(file) << 16) | (getByteFromFile(file) << 8) | (getByteFromFile(file) << 0)); else /* BYTE_ORDER_LITTLE_ENDIAN */ return ((getByteFromFile(file) << 0) | (getByteFromFile(file) << 8) | (getByteFromFile(file) << 16) | (getByteFromFile(file) << 24)); } int putFile32BitInteger(FILE *file, int value, int byte_order) { if (file != NULL) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) { fputc((value >> 24) & 0xff, file); fputc((value >> 16) & 0xff, file); fputc((value >> 8) & 0xff, file); fputc((value >> 0) & 0xff, file); } else /* BYTE_ORDER_LITTLE_ENDIAN */ { fputc((value >> 0) & 0xff, file); fputc((value >> 8) & 0xff, file); fputc((value >> 16) & 0xff, file); fputc((value >> 24) & 0xff, file); } } return 4; } boolean getFileChunk(File *file, char *chunk_name, int *chunk_size, int byte_order) { const int chunk_name_length = 4; /* read chunk name */ if (getStringFromFile(file, chunk_name, chunk_name_length + 1) == NULL) return FALSE; if (chunk_size != NULL) { /* read chunk size */ *chunk_size = getFile32BitInteger(file, byte_order); } return (checkEndOfFile(file) ? FALSE : TRUE); } int putFileChunk(FILE *file, char *chunk_name, int chunk_size, int byte_order) { int num_bytes = 0; /* write chunk name */ if (file != NULL) fputs(chunk_name, file); num_bytes += strlen(chunk_name); if (chunk_size >= 0) { /* write chunk size */ if (file != NULL) putFile32BitInteger(file, chunk_size, byte_order); num_bytes += 4; } return num_bytes; } int getFileVersion(File *file) { int version_major = getByteFromFile(file); int version_minor = getByteFromFile(file); int version_patch = getByteFromFile(file); int version_build = getByteFromFile(file); return VERSION_IDENT(version_major, version_minor, version_patch, version_build); } int putFileVersion(FILE *file, int version) { if (file != NULL) { int version_major = VERSION_MAJOR(version); int version_minor = VERSION_MINOR(version); int version_patch = VERSION_PATCH(version); int version_build = VERSION_BUILD(version); fputc(version_major, file); fputc(version_minor, file); fputc(version_patch, file); fputc(version_build, file); } return 4; } void ReadBytesFromFile(File *file, byte *buffer, unsigned int bytes) { int i; for (i = 0; i < bytes && !checkEndOfFile(file); i++) buffer[i] = getByteFromFile(file); } void WriteBytesToFile(FILE *file, byte *buffer, unsigned int bytes) { int i; for(i = 0; i < bytes; i++) fputc(buffer[i], file); } void ReadUnusedBytesFromFile(File *file, unsigned int bytes) { while (bytes-- && !checkEndOfFile(file)) getByteFromFile(file); } void WriteUnusedBytesToFile(FILE *file, unsigned int bytes) { while (bytes--) fputc(0, file); } /* ------------------------------------------------------------------------- */ /* functions to translate key identifiers between different format */ /* ------------------------------------------------------------------------- */ #define TRANSLATE_KEYSYM_TO_KEYNAME 0 #define TRANSLATE_KEYSYM_TO_X11KEYNAME 1 #define TRANSLATE_KEYNAME_TO_KEYSYM 2 #define TRANSLATE_X11KEYNAME_TO_KEYSYM 3 void translate_keyname(Key *keysym, char **x11name, char **name, int mode) { static struct { Key key; char *x11name; char *name; } translate_key[] = { /* normal cursor keys */ { KSYM_Left, "XK_Left", "cursor left" }, { KSYM_Right, "XK_Right", "cursor right" }, { KSYM_Up, "XK_Up", "cursor up" }, { KSYM_Down, "XK_Down", "cursor down" }, /* keypad cursor keys */ #ifdef KSYM_KP_Left { KSYM_KP_Left, "XK_KP_Left", "keypad left" }, { KSYM_KP_Right, "XK_KP_Right", "keypad right" }, { KSYM_KP_Up, "XK_KP_Up", "keypad up" }, { KSYM_KP_Down, "XK_KP_Down", "keypad down" }, #endif /* other keypad keys */ #ifdef KSYM_KP_Enter { KSYM_KP_Enter, "XK_KP_Enter", "keypad enter" }, { KSYM_KP_Add, "XK_KP_Add", "keypad +" }, { KSYM_KP_Subtract, "XK_KP_Subtract", "keypad -" }, { KSYM_KP_Multiply, "XK_KP_Multiply", "keypad mltply" }, { KSYM_KP_Divide, "XK_KP_Divide", "keypad /" }, { KSYM_KP_Separator,"XK_KP_Separator", "keypad ," }, #endif /* modifier keys */ { KSYM_Shift_L, "XK_Shift_L", "left shift" }, { KSYM_Shift_R, "XK_Shift_R", "right shift" }, { KSYM_Control_L, "XK_Control_L", "left control" }, { KSYM_Control_R, "XK_Control_R", "right control" }, { KSYM_Meta_L, "XK_Meta_L", "left meta" }, { KSYM_Meta_R, "XK_Meta_R", "right meta" }, { KSYM_Alt_L, "XK_Alt_L", "left alt" }, { KSYM_Alt_R, "XK_Alt_R", "right alt" }, #if !defined(TARGET_SDL2) { KSYM_Super_L, "XK_Super_L", "left super" }, /* Win-L */ { KSYM_Super_R, "XK_Super_R", "right super" }, /* Win-R */ #endif { KSYM_Mode_switch, "XK_Mode_switch", "mode switch" }, /* Alt-R */ { KSYM_Multi_key, "XK_Multi_key", "multi key" }, /* Ctrl-R */ /* some special keys */ { KSYM_BackSpace, "XK_BackSpace", "backspace" }, { KSYM_Delete, "XK_Delete", "delete" }, { KSYM_Insert, "XK_Insert", "insert" }, { KSYM_Tab, "XK_Tab", "tab" }, { KSYM_Home, "XK_Home", "home" }, { KSYM_End, "XK_End", "end" }, { KSYM_Page_Up, "XK_Page_Up", "page up" }, { KSYM_Page_Down, "XK_Page_Down", "page down" }, #if defined(TARGET_SDL2) { KSYM_Select, "XK_Select", "select" }, { KSYM_Menu, "XK_Menu", "menu" }, /* menu key */ { KSYM_Back, "XK_Back", "back" }, /* back key */ { KSYM_PlayPause, "XK_PlayPause", "play/pause" }, #if defined(PLATFORM_ANDROID) { KSYM_Rewind, "XK_Rewind", "rewind" }, { KSYM_FastForward, "XK_FastForward", "fast forward" }, #endif #endif /* ASCII 0x20 to 0x40 keys (except numbers) */ { KSYM_space, "XK_space", "space" }, { KSYM_exclam, "XK_exclam", "!" }, { KSYM_quotedbl, "XK_quotedbl", "\"" }, { KSYM_numbersign, "XK_numbersign", "#" }, { KSYM_dollar, "XK_dollar", "$" }, { KSYM_percent, "XK_percent", "%" }, { KSYM_ampersand, "XK_ampersand", "&" }, { KSYM_apostrophe, "XK_apostrophe", "'" }, { KSYM_parenleft, "XK_parenleft", "(" }, { KSYM_parenright, "XK_parenright", ")" }, { KSYM_asterisk, "XK_asterisk", "*" }, { KSYM_plus, "XK_plus", "+" }, { KSYM_comma, "XK_comma", "," }, { KSYM_minus, "XK_minus", "-" }, { KSYM_period, "XK_period", "." }, { KSYM_slash, "XK_slash", "/" }, { KSYM_colon, "XK_colon", ":" }, { KSYM_semicolon, "XK_semicolon", ";" }, { KSYM_less, "XK_less", "<" }, { KSYM_equal, "XK_equal", "=" }, { KSYM_greater, "XK_greater", ">" }, { KSYM_question, "XK_question", "?" }, { KSYM_at, "XK_at", "@" }, /* more ASCII keys */ { KSYM_bracketleft, "XK_bracketleft", "[" }, { KSYM_backslash, "XK_backslash", "\\" }, { KSYM_bracketright,"XK_bracketright", "]" }, { KSYM_asciicircum, "XK_asciicircum", "^" }, { KSYM_underscore, "XK_underscore", "_" }, { KSYM_grave, "XK_grave", "grave" }, { KSYM_quoteleft, "XK_quoteleft", "quote left" }, { KSYM_braceleft, "XK_braceleft", "brace left" }, { KSYM_bar, "XK_bar", "bar" }, { KSYM_braceright, "XK_braceright", "brace right" }, { KSYM_asciitilde, "XK_asciitilde", "~" }, /* special (non-ASCII) keys */ { KSYM_degree, "XK_degree", "degree" }, { KSYM_Adiaeresis, "XK_Adiaeresis", "A umlaut" }, { KSYM_Odiaeresis, "XK_Odiaeresis", "O umlaut" }, { KSYM_Udiaeresis, "XK_Udiaeresis", "U umlaut" }, { KSYM_adiaeresis, "XK_adiaeresis", "a umlaut" }, { KSYM_odiaeresis, "XK_odiaeresis", "o umlaut" }, { KSYM_udiaeresis, "XK_udiaeresis", "u umlaut" }, { KSYM_ssharp, "XK_ssharp", "sharp s" }, #if defined(TARGET_SDL2) /* special (non-ASCII) keys (UTF-8, for reverse mapping only) */ { KSYM_degree, "XK_degree", "\xc2\xb0" }, { KSYM_Adiaeresis, "XK_Adiaeresis", "\xc3\x84" }, { KSYM_Odiaeresis, "XK_Odiaeresis", "\xc3\x96" }, { KSYM_Udiaeresis, "XK_Udiaeresis", "\xc3\x9c" }, { KSYM_adiaeresis, "XK_adiaeresis", "\xc3\xa4" }, { KSYM_odiaeresis, "XK_odiaeresis", "\xc3\xb6" }, { KSYM_udiaeresis, "XK_udiaeresis", "\xc3\xbc" }, { KSYM_ssharp, "XK_ssharp", "\xc3\x9f" }, /* other keys (for reverse mapping only) */ { KSYM_space, "XK_space", " " }, #endif #if defined(TARGET_SDL2) /* keypad keys are not in numerical order in SDL2 */ { KSYM_KP_0, "XK_KP_0", "keypad 0" }, { KSYM_KP_1, "XK_KP_1", "keypad 1" }, { KSYM_KP_2, "XK_KP_2", "keypad 2" }, { KSYM_KP_3, "XK_KP_3", "keypad 3" }, { KSYM_KP_4, "XK_KP_4", "keypad 4" }, { KSYM_KP_5, "XK_KP_5", "keypad 5" }, { KSYM_KP_6, "XK_KP_6", "keypad 6" }, { KSYM_KP_7, "XK_KP_7", "keypad 7" }, { KSYM_KP_8, "XK_KP_8", "keypad 8" }, { KSYM_KP_9, "XK_KP_9", "keypad 9" }, #endif /* end-of-array identifier */ { 0, NULL, NULL } }; int i; if (mode == TRANSLATE_KEYSYM_TO_KEYNAME) { static char name_buffer[30]; Key key = *keysym; if (key >= KSYM_A && key <= KSYM_Z) sprintf(name_buffer, "%c", 'A' + (char)(key - KSYM_A)); else if (key >= KSYM_a && key <= KSYM_z) sprintf(name_buffer, "%c", 'a' + (char)(key - KSYM_a)); else if (key >= KSYM_0 && key <= KSYM_9) sprintf(name_buffer, "%c", '0' + (char)(key - KSYM_0)); #if !defined(TARGET_SDL2) else if (key >= KSYM_KP_0 && key <= KSYM_KP_9) sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0)); #endif else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST) sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1)); else if (key == KSYM_UNDEFINED) strcpy(name_buffer, "(undefined)"); else { i = 0; do { if (key == translate_key[i].key) { strcpy(name_buffer, translate_key[i].name); break; } } 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]; Key key = *keysym; if (key >= KSYM_A && key <= KSYM_Z) sprintf(name_buffer, "XK_%c", 'A' + (char)(key - KSYM_A)); else if (key >= KSYM_a && key <= KSYM_z) sprintf(name_buffer, "XK_%c", 'a' + (char)(key - KSYM_a)); else if (key >= KSYM_0 && key <= KSYM_9) sprintf(name_buffer, "XK_%c", '0' + (char)(key - KSYM_0)); #if !defined(TARGET_SDL2) else if (key >= KSYM_KP_0 && key <= KSYM_KP_9) sprintf(name_buffer, "XK_KP_%c", '0' + (char)(key - KSYM_KP_0)); #endif else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST) sprintf(name_buffer, "XK_F%d", (int)(key - KSYM_FKEY_FIRST + 1)); else if (key == KSYM_UNDEFINED) strcpy(name_buffer, "[undefined]"); else { i = 0; do { if (key == translate_key[i].key) { strcpy(name_buffer, translate_key[i].x11name); break; } } while (translate_key[++i].x11name); if (!translate_key[i].x11name) sprintf(name_buffer, "0x%04x", (unsigned int)key); } *x11name = name_buffer; } else if (mode == TRANSLATE_KEYNAME_TO_KEYSYM) { Key key = KSYM_UNDEFINED; char *name_ptr = *name; if (strlen(*name) == 1) { char c = name_ptr[0]; if (c >= 'A' && c <= 'Z') key = KSYM_A + (Key)(c - 'A'); else if (c >= 'a' && c <= 'z') key = KSYM_a + (Key)(c - 'a'); else if (c >= '0' && c <= '9') key = KSYM_0 + (Key)(c - '0'); } if (key == KSYM_UNDEFINED) { i = 0; do { if (strEqual(translate_key[i].name, *name)) { key = translate_key[i].key; break; } } while (translate_key[++i].x11name); } if (key == KSYM_UNDEFINED) Error(ERR_WARN, "getKeyFromKeyName(): not completely implemented"); *keysym = key; } else if (mode == TRANSLATE_X11KEYNAME_TO_KEYSYM) { Key key = KSYM_UNDEFINED; char *name_ptr = *x11name; if (strPrefix(name_ptr, "XK_") && strlen(name_ptr) == 4) { char c = name_ptr[3]; if (c >= 'A' && c <= 'Z') key = KSYM_A + (Key)(c - 'A'); else if (c >= 'a' && c <= 'z') key = KSYM_a + (Key)(c - 'a'); else if (c >= '0' && c <= '9') key = KSYM_0 + (Key)(c - '0'); } #if !defined(TARGET_SDL2) else if (strPrefix(name_ptr, "XK_KP_") && strlen(name_ptr) == 7) { char c = name_ptr[6]; if (c >= '0' && c <= '9') key = KSYM_KP_0 + (Key)(c - '0'); } #endif else if (strPrefix(name_ptr, "XK_F") && 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 (d >= 1 && d <= KSYM_NUM_FKEYS) key = KSYM_F1 + (Key)(d - 1); } else if (strPrefix(name_ptr, "XK_")) { i = 0; do { if (strEqual(name_ptr, translate_key[i].x11name)) { key = translate_key[i].key; break; } } while (translate_key[++i].x11name); } else if (strPrefix(name_ptr, "0x")) { unsigned int value = 0; name_ptr += 2; while (name_ptr) { 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; } if (value != -1) key = (Key)value; } *keysym = key; } } char *getKeyNameFromKey(Key key) { char *name; translate_keyname(&key, NULL, &name, TRANSLATE_KEYSYM_TO_KEYNAME); return name; } char *getX11KeyNameFromKey(Key key) { char *x11name; translate_keyname(&key, &x11name, NULL, TRANSLATE_KEYSYM_TO_X11KEYNAME); return x11name; } Key getKeyFromKeyName(char *name) { Key key; translate_keyname(&key, NULL, &name, TRANSLATE_KEYNAME_TO_KEYSYM); return key; } Key getKeyFromX11KeyName(char *x11name) { Key key; translate_keyname(&key, &x11name, NULL, TRANSLATE_X11KEYNAME_TO_KEYSYM); return key; } char getCharFromKey(Key key) { static struct { Key key; byte key_char; } translate_key_char[] = { /* special (non-ASCII) keys (ISO-8859-1) */ { KSYM_degree, CHAR_BYTE_DEGREE }, { KSYM_Adiaeresis, CHAR_BYTE_UMLAUT_A }, { KSYM_Odiaeresis, CHAR_BYTE_UMLAUT_O }, { KSYM_Udiaeresis, CHAR_BYTE_UMLAUT_U }, { KSYM_adiaeresis, CHAR_BYTE_UMLAUT_a }, { KSYM_odiaeresis, CHAR_BYTE_UMLAUT_o }, { KSYM_udiaeresis, CHAR_BYTE_UMLAUT_u }, { KSYM_ssharp, CHAR_BYTE_SHARP_S }, /* end-of-array identifier */ { 0, 0 } }; char *keyname = getKeyNameFromKey(key); char c = 0; if (strlen(keyname) == 1) c = keyname[0]; else if (strEqual(keyname, "space")) c = ' '; else { int i = 0; do { if (key == translate_key_char[i].key) { c = translate_key_char[i].key_char; break; } } while (translate_key_char[++i].key_char); } return c; } char getValidConfigValueChar(char c) { if (c == '#' || /* used to mark comments */ c == '\\') /* used to mark continued lines */ c = 0; return c; } /* ------------------------------------------------------------------------- */ /* functions to translate string identifiers to integer or boolean value */ /* ------------------------------------------------------------------------- */ int get_integer_from_string(char *s) { static char *number_text[][3] = { { "0", "zero", "null", }, { "1", "one", "first" }, { "2", "two", "second" }, { "3", "three", "third" }, { "4", "four", "fourth" }, { "5", "five", "fifth" }, { "6", "six", "sixth" }, { "7", "seven", "seventh" }, { "8", "eight", "eighth" }, { "9", "nine", "ninth" }, { "10", "ten", "tenth" }, { "11", "eleven", "eleventh" }, { "12", "twelve", "twelfth" }, { NULL, NULL, NULL }, }; int i, j; char *s_lower = getStringToLower(s); int result = -1; for (i = 0; number_text[i][0] != NULL; i++) for (j = 0; j < 3; j++) if (strEqual(s_lower, number_text[i][j])) result = i; if (result == -1) { if (strEqual(s_lower, "false") || strEqual(s_lower, "no") || strEqual(s_lower, "off")) result = 0; else if (strEqual(s_lower, "true") || strEqual(s_lower, "yes") || strEqual(s_lower, "on")) result = 1; else result = atoi(s); } free(s_lower); return result; } boolean get_boolean_from_string(char *s) { char *s_lower = getStringToLower(s); boolean result = FALSE; if (strEqual(s_lower, "true") || strEqual(s_lower, "yes") || strEqual(s_lower, "on") || get_integer_from_string(s) == 1) result = TRUE; free(s_lower); return result; } int get_switch3_from_string(char *s) { char *s_lower = getStringToLower(s); int result = FALSE; if (strEqual(s_lower, "true") || strEqual(s_lower, "yes") || strEqual(s_lower, "on") || get_integer_from_string(s) == 1) result = TRUE; else if (strEqual(s_lower, "auto")) result = AUTO; free(s_lower); return result; } /* ------------------------------------------------------------------------- */ /* functions for generic lists */ /* ------------------------------------------------------------------------- */ ListNode *newListNode() { return checked_calloc(sizeof(ListNode)); } void addNodeToList(ListNode **node_first, char *key, void *content) { ListNode *node_new = newListNode(); node_new->key = getStringCopy(key); node_new->content = content; node_new->next = *node_first; if (*node_first) (*node_first)->prev = node_new; *node_first = node_new; } void deleteNodeFromList(ListNode **node_first, char *key, void (*destructor_function)(void *)) { if (node_first == NULL || *node_first == NULL) return; if (strEqual((*node_first)->key, key)) { // after first recursion, (*node_first)->prev->next == *node_first, // so *node_first would be overwritten with (*node_first)->next // => use a copy of *node_first (and later of (*node_first)->next) ListNode *node = *node_first; ListNode *node_next = node->next; checked_free(node->key); if (destructor_function) destructor_function(node->content); if (node->prev) node->prev->next = node->next; if (node->next) node->next->prev = node->prev; checked_free(node); // after removing node, set list pointer to next valid list node // (this is important if the first node of the list was deleted) *node_first = node_next; } else { deleteNodeFromList(&(*node_first)->next, key, destructor_function); } } ListNode *getNodeFromKey(ListNode *node_first, char *key) { if (node_first == NULL) return NULL; if (strEqual(node_first->key, key)) return node_first; else return getNodeFromKey(node_first->next, key); } int getNumNodes(ListNode *node_first) { return (node_first ? 1 + getNumNodes(node_first->next) : 0); } void dumpList(ListNode *node_first) { ListNode *node = node_first; while (node) { printf("['%s' (%d)]\n", node->key, ((struct ListNodeInfo *)node->content)->num_references); node = node->next; } printf("[%d nodes]\n", getNumNodes(node_first)); } /* ------------------------------------------------------------------------- */ /* functions for file handling */ /* ------------------------------------------------------------------------- */ #define MAX_BUFFER_SIZE 4096 File *openFile(char *filename, char *mode) { File *file = checked_calloc(sizeof(File)); file->file = fopen(filename, mode); if (file->file != NULL) { file->filename = getStringCopy(filename); return file; } #if defined(PLATFORM_ANDROID) file->asset_file = SDL_RWFromFile(filename, mode); if (file->asset_file != NULL) { file->file_is_asset = TRUE; file->filename = getStringCopy(filename); return file; } #endif checked_free(file); return NULL; } int closeFile(File *file) { if (file == NULL) return -1; int result = 0; #if defined(PLATFORM_ANDROID) if (file->asset_file) result = SDL_RWclose(file->asset_file); #endif if (file->file) result = fclose(file->file); checked_free(file->filename); checked_free(file); return result; } int checkEndOfFile(File *file) { #if defined(PLATFORM_ANDROID) if (file->file_is_asset) return file->end_of_file; #endif return feof(file->file); } size_t readFile(File *file, void *buffer, size_t item_size, size_t num_items) { #if defined(PLATFORM_ANDROID) if (file->file_is_asset) { if (file->end_of_file) return 0; size_t num_items_read = SDL_RWread(file->asset_file, buffer, item_size, num_items); if (num_items_read < num_items) file->end_of_file = TRUE; return num_items_read; } #endif return fread(buffer, item_size, num_items, file->file); } size_t writeFile(File *file, void *buffer, size_t item_size, size_t num_items) { return fwrite(buffer, item_size, num_items, file->file); } int seekFile(File *file, long offset, int whence) { #if defined(PLATFORM_ANDROID) if (file->file_is_asset) { int sdl_whence = (whence == SEEK_SET ? RW_SEEK_SET : whence == SEEK_CUR ? RW_SEEK_CUR : whence == SEEK_END ? RW_SEEK_END : 0); return (SDL_RWseek(file->asset_file, offset, sdl_whence) == -1 ? -1 : 0); } #endif return fseek(file->file, offset, whence); } int getByteFromFile(File *file) { #if defined(PLATFORM_ANDROID) if (file->file_is_asset) { if (file->end_of_file) return EOF; byte c; size_t num_bytes_read = SDL_RWread(file->asset_file, &c, 1, 1); if (num_bytes_read < 1) file->end_of_file = TRUE; return (file->end_of_file ? EOF : (int)c); } #endif return fgetc(file->file); } char *getStringFromFile(File *file, char *line, int size) { #if defined(PLATFORM_ANDROID) if (file->file_is_asset) { if (file->end_of_file) return NULL; char *line_ptr = line; int num_bytes_read = 0; while (num_bytes_read < size - 1 && SDL_RWread(file->asset_file, line_ptr, 1, 1) == 1 && *line_ptr++ != '\n') num_bytes_read++; *line_ptr = '\0'; if (strlen(line) == 0) { file->end_of_file = TRUE; return NULL; } return line; } #endif return fgets(line, size, file->file); } int copyFile(char *filename_from, char *filename_to) { File *file_from, *file_to; if ((file_from = openFile(filename_from, MODE_READ)) == NULL) { return -1; } if ((file_to = openFile(filename_to, MODE_WRITE)) == NULL) { closeFile(file_from); return -1; } while (!checkEndOfFile(file_from)) { byte buffer[MAX_BUFFER_SIZE]; size_t bytes_read = readFile(file_from, buffer, 1, MAX_BUFFER_SIZE); writeFile(file_to, buffer, 1, bytes_read); } closeFile(file_from); closeFile(file_to); return 0; } /* ------------------------------------------------------------------------- */ /* functions for directory handling */ /* ------------------------------------------------------------------------- */ Directory *openDirectory(char *dir_name) { Directory *dir = checked_calloc(sizeof(Directory)); dir->dir = opendir(dir_name); if (dir->dir != NULL) { dir->filename = getStringCopy(dir_name); return dir; } #if defined(PLATFORM_ANDROID) char *asset_toc_filename = getPath2(dir_name, ASSET_TOC_BASENAME); dir->asset_toc_file = SDL_RWFromFile(asset_toc_filename, MODE_READ); checked_free(asset_toc_filename); if (dir->asset_toc_file != NULL) { dir->directory_is_asset = TRUE; dir->filename = getStringCopy(dir_name); return dir; } #endif checked_free(dir); return NULL; } int closeDirectory(Directory *dir) { if (dir == NULL) return -1; int result = 0; #if defined(PLATFORM_ANDROID) if (dir->asset_toc_file) result = SDL_RWclose(dir->asset_toc_file); #endif if (dir->dir) result = closedir(dir->dir); if (dir->dir_entry) freeDirectoryEntry(dir->dir_entry); checked_free(dir->filename); checked_free(dir); return result; } DirectoryEntry *readDirectory(Directory *dir) { if (dir->dir_entry) freeDirectoryEntry(dir->dir_entry); dir->dir_entry = NULL; #if defined(PLATFORM_ANDROID) if (dir->directory_is_asset) { char line[MAX_LINE_LEN]; char *line_ptr = line; int num_bytes_read = 0; while (num_bytes_read < MAX_LINE_LEN - 1 && SDL_RWread(dir->asset_toc_file, line_ptr, 1, 1) == 1 && *line_ptr != '\n') { line_ptr++; num_bytes_read++; } *line_ptr = '\0'; if (strlen(line) == 0) return NULL; dir->dir_entry = checked_calloc(sizeof(DirectoryEntry)); dir->dir_entry->is_directory = FALSE; if (line[strlen(line) - 1] == '/') { dir->dir_entry->is_directory = TRUE; line[strlen(line) - 1] = '\0'; } dir->dir_entry->basename = getStringCopy(line); dir->dir_entry->filename = getPath2(dir->filename, line); return dir->dir_entry; } #endif struct dirent *dir_entry = readdir(dir->dir); if (dir_entry == NULL) return NULL; dir->dir_entry = checked_calloc(sizeof(DirectoryEntry)); dir->dir_entry->basename = getStringCopy(dir_entry->d_name); dir->dir_entry->filename = getPath2(dir->filename, dir_entry->d_name); struct stat file_status; dir->dir_entry->is_directory = (stat(dir->dir_entry->filename, &file_status) == 0 && S_ISDIR(file_status.st_mode)); return dir->dir_entry; } void freeDirectoryEntry(DirectoryEntry *dir_entry) { if (dir_entry == NULL) return; checked_free(dir_entry->basename); checked_free(dir_entry->filename); checked_free(dir_entry); } /* ------------------------------------------------------------------------- */ /* functions for checking files and filenames */ /* ------------------------------------------------------------------------- */ boolean directoryExists(char *dir_name) { if (dir_name == NULL) return FALSE; struct stat file_status; boolean success = (stat(dir_name, &file_status) == 0 && S_ISDIR(file_status.st_mode)); #if defined(PLATFORM_ANDROID) if (!success) { // this might be an asset directory; check by trying to open toc file char *asset_toc_filename = getPath2(dir_name, ASSET_TOC_BASENAME); SDL_RWops *file = SDL_RWFromFile(asset_toc_filename, MODE_READ); checked_free(asset_toc_filename); success = (file != NULL); if (success) SDL_RWclose(file); } #endif return success; } boolean fileExists(char *filename) { if (filename == NULL) return FALSE; boolean success = (access(filename, F_OK) == 0); #if defined(PLATFORM_ANDROID) if (!success) { // this might be an asset file; check by trying to open it SDL_RWops *file = SDL_RWFromFile(filename, MODE_READ); success = (file != NULL); if (success) SDL_RWclose(file); } #endif return success; } boolean fileHasPrefix(char *basename, char *prefix) { static char *basename_lower = NULL; int basename_length, prefix_length; checked_free(basename_lower); if (basename == NULL || prefix == NULL) return FALSE; basename_lower = getStringToLower(basename); basename_length = strlen(basename_lower); prefix_length = strlen(prefix); if (basename_length > prefix_length + 1 && basename_lower[prefix_length] == '.' && strncmp(basename_lower, prefix, prefix_length) == 0) return TRUE; return FALSE; } boolean fileHasSuffix(char *basename, char *suffix) { static char *basename_lower = NULL; int basename_length, suffix_length; checked_free(basename_lower); if (basename == NULL || suffix == NULL) return FALSE; basename_lower = getStringToLower(basename); basename_length = strlen(basename_lower); suffix_length = strlen(suffix); if (basename_length > suffix_length + 1 && basename_lower[basename_length - suffix_length - 1] == '.' && strEqual(&basename_lower[basename_length - suffix_length], suffix)) return TRUE; return FALSE; } static boolean FileCouldBeArtwork(char *filename) { char *basename = getBaseNamePtr(filename); return (!strEqual(basename, ".") && !strEqual(basename, "..") && !fileHasSuffix(basename, "txt") && !fileHasSuffix(basename, "conf") && !directoryExists(filename)); } boolean FileIsGraphic(char *filename) { return FileCouldBeArtwork(filename); } boolean FileIsSound(char *filename) { return FileCouldBeArtwork(filename); } boolean FileIsMusic(char *filename) { return FileCouldBeArtwork(filename); } boolean FileIsArtworkType(char *filename, int type) { if ((type == TREE_TYPE_GRAPHICS_DIR && FileIsGraphic(filename)) || (type == TREE_TYPE_SOUNDS_DIR && FileIsSound(filename)) || (type == TREE_TYPE_MUSIC_DIR && FileIsMusic(filename))) return TRUE; return FALSE; } /* ------------------------------------------------------------------------- */ /* functions for loading artwork configuration information */ /* ------------------------------------------------------------------------- */ char *get_mapped_token(char *token) { /* !!! make this dynamically configurable (init.c:InitArtworkConfig) !!! */ static char *map_token_prefix[][2] = { { "char_procent", "char_percent" }, { NULL, } }; int i; for (i = 0; map_token_prefix[i][0] != NULL; i++) { int len_token_prefix = strlen(map_token_prefix[i][0]); if (strncmp(token, map_token_prefix[i][0], len_token_prefix) == 0) return getStringCat2(map_token_prefix[i][1], &token[len_token_prefix]); } // change tokens containing ".gfx" by moving the "gfx" part to the very left char *gfx_substring = ".gfx"; char *gfx_prefix = "gfx."; if (strstr(token, gfx_substring) != NULL) { char *token_prefix = getStringCopy(token); char *token_gfx_pos = strstr(token_prefix, gfx_substring); char *token_suffix = &token_gfx_pos[strlen(gfx_substring)]; char *mapped_token; // cut off token string at ".gfx" substring position *token_gfx_pos = '\0'; // put together prefix "gfx." and token prefix and suffix without ".gfx" mapped_token = getStringCat3(gfx_prefix, token_prefix, token_suffix); free(token_prefix); return mapped_token; } return NULL; } char *get_special_base_token(struct ArtworkListInfo *artwork_info, char *token) { /* !!! make this dynamically configurable (init.c:InitArtworkConfig) !!! */ static struct ConfigTypeInfo prefix_list[] = { { "global.anim_1" }, { "global.anim_2" }, { "global.anim_3" }, { "global.anim_4" }, { "global.anim_5" }, { "global.anim_6" }, { "global.anim_7" }, { "global.anim_8" }, { "global.anim_9" }, { "global.anim_10" }, { "global.anim_11" }, { "global.anim_12" }, { "global.anim_13" }, { "global.anim_14" }, { "global.anim_15" }, { "global.anim_16" }, { "global.anim_17" }, { "global.anim_18" }, { "global.anim_19" }, { "global.anim_20" }, { "global.anim_21" }, { "global.anim_22" }, { "global.anim_23" }, { "global.anim_24" }, { "global.anim_25" }, { "global.anim_26" }, { "global.anim_27" }, { "global.anim_28" }, { "global.anim_29" }, { "global.anim_30" }, { "global.anim_31" }, { "global.anim_32" }, { NULL } }; struct ConfigTypeInfo *suffix_list = artwork_info->suffix_list; boolean prefix_found = FALSE; int len_suffix = 0; int i; /* search for prefix to check if base token has to be created */ for (i = 0; prefix_list[i].token != NULL; i++) if (strPrefix(token, prefix_list[i].token)) prefix_found = TRUE; if (!prefix_found) return NULL; /* search for suffix (parameter) to determine base token length */ for (i = 0; suffix_list[i].token != NULL; i++) if (strSuffix(token, suffix_list[i].token)) len_suffix = strlen(suffix_list[i].token); return getStringCopyN(token, strlen(token) - len_suffix); } /* This function checks if a string of the format "string1, string2, ..." exactly contains a string . */ static boolean string_has_parameter(char *s, char *s_contained) { char *substring; if (s == NULL || s_contained == NULL) return FALSE; if (strlen(s_contained) > strlen(s)) return FALSE; if (strncmp(s, s_contained, strlen(s_contained)) == 0) { char next_char = s[strlen(s_contained)]; /* check if next character is delimiter or whitespace */ return (next_char == ',' || next_char == '\0' || next_char == ' ' || next_char == '\t' ? TRUE : FALSE); } /* check if string contains another parameter string after a comma */ substring = strchr(s, ','); if (substring == NULL) /* string does not contain a comma */ return FALSE; /* advance string pointer to next character after the comma */ substring++; /* skip potential whitespaces after the comma */ while (*substring == ' ' || *substring == '\t') substring++; return string_has_parameter(substring, s_contained); } int get_anim_parameter_value(char *s) { char *pattern_1 = "click:anim_"; char *pattern_2 = ".part_"; char *matching_char = NULL; char *s_ptr = s; int result = ANIM_EVENT_NONE; matching_char = strstr(s_ptr, pattern_1); if (matching_char == NULL) return ANIM_EVENT_NONE; s_ptr = matching_char + strlen(pattern_1); // check for main animation number ("anim_X" or "anim_XX") if (*s_ptr >= '0' && *s_ptr <= '9') { int gic_anim_nr = (*s_ptr++ - '0'); if (*s_ptr >= '0' && *s_ptr <= '9') gic_anim_nr = 10 * gic_anim_nr + (*s_ptr++ - '0'); if (gic_anim_nr < 1 || gic_anim_nr > MAX_GLOBAL_ANIMS) return ANIM_EVENT_NONE; result |= gic_anim_nr << ANIM_EVENT_ANIM_BIT; } else { // invalid main animation number specified return ANIM_EVENT_NONE; } // check for animation part number ("part_X" or "part_XX") (optional) if (strPrefix(s_ptr, pattern_2)) { s_ptr += strlen(pattern_2); if (*s_ptr >= '0' && *s_ptr <= '9') { int gic_part_nr = (*s_ptr++ - '0'); if (*s_ptr >= '0' && *s_ptr <= '9') gic_part_nr = 10 * gic_part_nr + (*s_ptr++ - '0'); if (gic_part_nr < 1 || gic_part_nr > MAX_GLOBAL_ANIM_PARTS) return ANIM_EVENT_NONE; result |= gic_part_nr << ANIM_EVENT_PART_BIT; } else { // invalid animation part number specified return ANIM_EVENT_NONE; } } /* discard result if next character is neither delimiter nor whitespace */ if (!(*s_ptr == ',' || *s_ptr == '\0' || *s_ptr == ' ' || *s_ptr == '\t')) return ANIM_EVENT_NONE; return result; } int get_parameter_value(char *value_raw, char *suffix, int type) { char *value = getStringToLower(value_raw); int result = 0; /* probably a save default value */ if (strEqual(suffix, ".direction")) { result = (strEqual(value, "left") ? MV_LEFT : strEqual(value, "right") ? MV_RIGHT : strEqual(value, "up") ? MV_UP : strEqual(value, "down") ? MV_DOWN : MV_NONE); } else if (strEqual(suffix, ".position")) { result = (strEqual(value, "left") ? POS_LEFT : strEqual(value, "right") ? POS_RIGHT : strEqual(value, "top") ? POS_TOP : strEqual(value, "upper") ? POS_UPPER : strEqual(value, "middle") ? POS_MIDDLE : strEqual(value, "lower") ? POS_LOWER : strEqual(value, "bottom") ? POS_BOTTOM : strEqual(value, "any") ? POS_ANY : strEqual(value, "last") ? POS_LAST : POS_UNDEFINED); } else if (strEqual(suffix, ".align")) { result = (strEqual(value, "left") ? ALIGN_LEFT : strEqual(value, "right") ? ALIGN_RIGHT : strEqual(value, "center") ? ALIGN_CENTER : strEqual(value, "middle") ? ALIGN_CENTER : ALIGN_DEFAULT); } else if (strEqual(suffix, ".valign")) { result = (strEqual(value, "top") ? VALIGN_TOP : strEqual(value, "bottom") ? VALIGN_BOTTOM : strEqual(value, "middle") ? VALIGN_MIDDLE : strEqual(value, "center") ? VALIGN_MIDDLE : VALIGN_DEFAULT); } else if (strEqual(suffix, ".anim_mode")) { result = (string_has_parameter(value, "none") ? ANIM_NONE : string_has_parameter(value, "loop") ? ANIM_LOOP : string_has_parameter(value, "linear") ? ANIM_LINEAR : string_has_parameter(value, "pingpong") ? ANIM_PINGPONG : string_has_parameter(value, "pingpong2") ? ANIM_PINGPONG2 : string_has_parameter(value, "random") ? ANIM_RANDOM : string_has_parameter(value, "ce_value") ? ANIM_CE_VALUE : string_has_parameter(value, "ce_score") ? ANIM_CE_SCORE : string_has_parameter(value, "ce_delay") ? ANIM_CE_DELAY : string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL : string_has_parameter(value, "vertical") ? ANIM_VERTICAL : string_has_parameter(value, "centered") ? ANIM_CENTERED : string_has_parameter(value, "all") ? ANIM_ALL : ANIM_DEFAULT); if (string_has_parameter(value, "once")) result |= ANIM_ONCE; if (string_has_parameter(value, "reverse")) result |= ANIM_REVERSE; if (string_has_parameter(value, "opaque_player")) result |= ANIM_OPAQUE_PLAYER; if (string_has_parameter(value, "static_panel")) result |= ANIM_STATIC_PANEL; } else if (strEqual(suffix, ".init_event") || strEqual(suffix, ".anim_event")) { result = ANIM_EVENT_DEFAULT; if (string_has_parameter(value, "any")) result |= ANIM_EVENT_ANY; if (string_has_parameter(value, "click")) result |= ANIM_EVENT_SELF; // add optional "click:anim_X" or "click:anim_X.part_X" parameter result |= get_anim_parameter_value(value); } else if (strEqual(suffix, ".class")) { result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE : get_hash_from_key(value)); } else if (strEqual(suffix, ".style")) { result = STYLE_DEFAULT; if (string_has_parameter(value, "accurate_borders")) result |= STYLE_ACCURATE_BORDERS; if (string_has_parameter(value, "inner_corners")) result |= STYLE_INNER_CORNERS; if (string_has_parameter(value, "reverse")) result |= STYLE_REVERSE; } else if (strEqual(suffix, ".fade_mode")) { result = (string_has_parameter(value, "none") ? FADE_MODE_NONE : string_has_parameter(value, "fade") ? FADE_MODE_FADE : string_has_parameter(value, "crossfade") ? FADE_MODE_CROSSFADE : string_has_parameter(value, "melt") ? FADE_MODE_MELT : string_has_parameter(value, "curtain") ? FADE_MODE_CURTAIN : FADE_MODE_DEFAULT); } else if (strPrefix(suffix, ".font")) /* (may also be ".font_xyz") */ { result = gfx.get_font_from_token_function(value); } else /* generic parameter of type integer or boolean */ { result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE : type == TYPE_INTEGER ? get_integer_from_string(value) : type == TYPE_BOOLEAN ? get_boolean_from_string(value) : ARG_UNDEFINED_VALUE); } free(value); return result; } static void FreeCustomArtworkList(struct ArtworkListInfo *, struct ListNodeInfo ***, int *); struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, struct ConfigTypeInfo *suffix_list, char **ignore_tokens, int num_file_list_entries) { SetupFileHash *ignore_tokens_hash; struct FileInfo *file_list; int num_file_list_entries_found = 0; int num_suffix_list_entries = 0; int list_pos; int i, j; /* create hash from list of tokens to be ignored (for quick access) */ ignore_tokens_hash = newSetupFileHash(); for (i = 0; ignore_tokens[i] != NULL; i++) setHashEntry(ignore_tokens_hash, ignore_tokens[i], ""); file_list = checked_calloc(num_file_list_entries * sizeof(struct FileInfo)); for (i = 0; suffix_list[i].token != NULL; i++) num_suffix_list_entries++; /* always start with reliable default values */ for (i = 0; i < num_file_list_entries; i++) { file_list[i].token = NULL; file_list[i].default_filename = NULL; file_list[i].filename = NULL; if (num_suffix_list_entries > 0) { int parameter_array_size = num_suffix_list_entries * sizeof(char *); file_list[i].default_parameter = checked_calloc(parameter_array_size); file_list[i].parameter = checked_calloc(parameter_array_size); for (j = 0; j < num_suffix_list_entries; j++) { setString(&file_list[i].default_parameter[j], suffix_list[j].value); setString(&file_list[i].parameter[j], suffix_list[j].value); } file_list[i].redefined = FALSE; file_list[i].fallback_to_default = FALSE; file_list[i].default_is_cloned = FALSE; } } list_pos = 0; for (i = 0; config_list[i].token != NULL; i++) { int len_config_token = strlen(config_list[i].token); boolean is_file_entry = TRUE; for (j = 0; suffix_list[j].token != NULL; j++) { int len_suffix = strlen(suffix_list[j].token); if (len_suffix < len_config_token && strEqual(&config_list[i].token[len_config_token - len_suffix], suffix_list[j].token)) { setString(&file_list[list_pos].default_parameter[j], config_list[i].value); is_file_entry = FALSE; break; } } /* the following tokens are no file definitions, but other config tokens */ if (getHashEntry(ignore_tokens_hash, config_list[i].token) != NULL) is_file_entry = FALSE; if (is_file_entry) { if (i > 0) list_pos++; if (list_pos >= num_file_list_entries) break; file_list[list_pos].token = config_list[i].token; file_list[list_pos].default_filename = config_list[i].value; } if (strSuffix(config_list[i].token, ".clone_from")) file_list[list_pos].default_is_cloned = TRUE; } num_file_list_entries_found = list_pos + 1; if (num_file_list_entries_found != num_file_list_entries) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "inconsistant config list information:"); Error(ERR_INFO, "- should be: %d (according to 'src/conf_xxx.h')", num_file_list_entries); Error(ERR_INFO, "- found to be: %d (according to 'src/conf_xxx.c')", num_file_list_entries_found); Error(ERR_EXIT, "please fix"); } freeSetupFileHash(ignore_tokens_hash); return file_list; } static boolean token_suffix_match(char *token, char *suffix, int start_pos) { int len_token = strlen(token); int len_suffix = strlen(suffix); if (start_pos < 0) /* compare suffix from end of string */ start_pos += len_token; if (start_pos < 0 || start_pos + len_suffix > len_token) return FALSE; if (strncmp(&token[start_pos], suffix, len_suffix) != 0) return FALSE; if (token[start_pos + len_suffix] == '\0') return TRUE; if (token[start_pos + len_suffix] == '.') return TRUE; return FALSE; } #define KNOWN_TOKEN_VALUE "[KNOWN_TOKEN_VALUE]" static void read_token_parameters(SetupFileHash *setup_file_hash, struct ConfigTypeInfo *suffix_list, struct FileInfo *file_list_entry) { /* check for config token that is the base token without any suffixes */ char *filename = getHashEntry(setup_file_hash, file_list_entry->token); char *known_token_value = KNOWN_TOKEN_VALUE; int i; if (filename != NULL) { setString(&file_list_entry->filename, filename); /* when file definition found, set all parameters to default values */ for (i = 0; suffix_list[i].token != NULL; i++) setString(&file_list_entry->parameter[i], suffix_list[i].value); file_list_entry->redefined = TRUE; /* mark config file token as well known from default config */ setHashEntry(setup_file_hash, file_list_entry->token, known_token_value); } /* check for config tokens that can be build by base token and suffixes */ for (i = 0; suffix_list[i].token != NULL; i++) { char *token = getStringCat2(file_list_entry->token, suffix_list[i].token); char *value = getHashEntry(setup_file_hash, token); if (value != NULL) { setString(&file_list_entry->parameter[i], value); /* mark config file token as well known from default config */ setHashEntry(setup_file_hash, token, known_token_value); } free(token); } } static void add_dynamic_file_list_entry(struct FileInfo **list, int *num_list_entries, SetupFileHash *extra_file_hash, struct ConfigTypeInfo *suffix_list, int num_suffix_list_entries, char *token) { struct FileInfo *new_list_entry; int parameter_array_size = num_suffix_list_entries * sizeof(char *); (*num_list_entries)++; *list = checked_realloc(*list, *num_list_entries * sizeof(struct FileInfo)); new_list_entry = &(*list)[*num_list_entries - 1]; new_list_entry->token = getStringCopy(token); new_list_entry->default_filename = NULL; new_list_entry->filename = NULL; new_list_entry->parameter = checked_calloc(parameter_array_size); new_list_entry->redefined = FALSE; new_list_entry->fallback_to_default = FALSE; new_list_entry->default_is_cloned = FALSE; read_token_parameters(extra_file_hash, suffix_list, new_list_entry); } static void add_property_mapping(struct PropertyMapping **list, int *num_list_entries, int base_index, int ext1_index, int ext2_index, int ext3_index, int artwork_index) { struct PropertyMapping *new_list_entry; (*num_list_entries)++; *list = checked_realloc(*list, *num_list_entries * sizeof(struct PropertyMapping)); new_list_entry = &(*list)[*num_list_entries - 1]; new_list_entry->base_index = base_index; new_list_entry->ext1_index = ext1_index; new_list_entry->ext2_index = ext2_index; new_list_entry->ext3_index = ext3_index; new_list_entry->artwork_index = artwork_index; } static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info, char *filename) { struct FileInfo *file_list = artwork_info->file_list; struct ConfigTypeInfo *suffix_list = artwork_info->suffix_list; char **base_prefixes = artwork_info->base_prefixes; char **ext1_suffixes = artwork_info->ext1_suffixes; char **ext2_suffixes = artwork_info->ext2_suffixes; char **ext3_suffixes = artwork_info->ext3_suffixes; char **ignore_tokens = artwork_info->ignore_tokens; int num_file_list_entries = artwork_info->num_file_list_entries; int num_suffix_list_entries = artwork_info->num_suffix_list_entries; int num_base_prefixes = artwork_info->num_base_prefixes; int num_ext1_suffixes = artwork_info->num_ext1_suffixes; int num_ext2_suffixes = artwork_info->num_ext2_suffixes; int num_ext3_suffixes = artwork_info->num_ext3_suffixes; int num_ignore_tokens = artwork_info->num_ignore_tokens; SetupFileHash *setup_file_hash, *valid_file_hash, *valid_file_hash_tmp; SetupFileHash *extra_file_hash, *empty_file_hash; char *known_token_value = KNOWN_TOKEN_VALUE; char *base_token_value = UNDEFINED_FILENAME; int i, j, k, l; if (filename == NULL) return; if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; /* separate valid (defined) from empty (undefined) config token values */ valid_file_hash = newSetupFileHash(); empty_file_hash = newSetupFileHash(); BEGIN_HASH_ITERATION(setup_file_hash, itr) { char *value = HASH_ITERATION_VALUE(itr); setHashEntry(*value ? valid_file_hash : empty_file_hash, HASH_ITERATION_TOKEN(itr), value); } END_HASH_ITERATION(setup_file_hash, itr) /* at this point, we do not need the setup file hash anymore -- free it */ freeSetupFileHash(setup_file_hash); /* prevent changing hash while iterating over it by using a temporary copy */ valid_file_hash_tmp = newSetupFileHash(); BEGIN_HASH_ITERATION(valid_file_hash, itr) { setHashEntry(valid_file_hash_tmp, HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr)); } END_HASH_ITERATION(valid_file_hash, itr) /* (iterate over same temporary hash, as modifications are independent) */ /* map deprecated to current tokens (using prefix match and replace) */ BEGIN_HASH_ITERATION(valid_file_hash_tmp, itr) { char *token = HASH_ITERATION_TOKEN(itr); char *mapped_token = get_mapped_token(token); if (mapped_token != NULL) { char *value = HASH_ITERATION_VALUE(itr); /* add mapped token */ setHashEntry(valid_file_hash, mapped_token, value); /* ignore old token (by setting it to "known" keyword) */ setHashEntry(valid_file_hash, token, known_token_value); free(mapped_token); } } END_HASH_ITERATION(valid_file_hash_tmp, itr) /* add special base tokens (using prefix match and replace) */ BEGIN_HASH_ITERATION(valid_file_hash_tmp, itr) { char *token = HASH_ITERATION_TOKEN(itr); char *base_token = get_special_base_token(artwork_info, token); if (base_token != NULL) { /* add base token only if it does not already exist */ if (getHashEntry(valid_file_hash, base_token) == NULL) setHashEntry(valid_file_hash, base_token, base_token_value); free(base_token); } } END_HASH_ITERATION(valid_file_hash_tmp, itr) /* free temporary hash used for iteration */ freeSetupFileHash(valid_file_hash_tmp); /* read parameters for all known config file tokens */ for (i = 0; i < num_file_list_entries; i++) read_token_parameters(valid_file_hash, suffix_list, &file_list[i]); /* set all tokens that can be ignored here to "known" keyword */ for (i = 0; i < num_ignore_tokens; i++) setHashEntry(valid_file_hash, ignore_tokens[i], known_token_value); /* copy all unknown config file tokens to extra config hash */ extra_file_hash = newSetupFileHash(); BEGIN_HASH_ITERATION(valid_file_hash, itr) { char *value = HASH_ITERATION_VALUE(itr); if (!strEqual(value, known_token_value)) setHashEntry(extra_file_hash, HASH_ITERATION_TOKEN(itr), value); } END_HASH_ITERATION(valid_file_hash, itr) /* at this point, we do not need the valid file hash anymore -- free it */ freeSetupFileHash(valid_file_hash); /* now try to determine valid, dynamically defined config tokens */ BEGIN_HASH_ITERATION(extra_file_hash, itr) { struct FileInfo **dynamic_file_list = &artwork_info->dynamic_file_list; int *num_dynamic_file_list_entries = &artwork_info->num_dynamic_file_list_entries; struct PropertyMapping **property_mapping = &artwork_info->property_mapping; int *num_property_mapping_entries = &artwork_info->num_property_mapping_entries; int current_summarized_file_list_entry = artwork_info->num_file_list_entries + artwork_info->num_dynamic_file_list_entries; char *token = HASH_ITERATION_TOKEN(itr); int len_token = strlen(token); int start_pos; boolean base_prefix_found = FALSE; boolean parameter_suffix_found = FALSE; /* skip all parameter definitions (handled by read_token_parameters()) */ for (i = 0; i < num_suffix_list_entries && !parameter_suffix_found; i++) { int len_suffix = strlen(suffix_list[i].token); if (token_suffix_match(token, suffix_list[i].token, -len_suffix)) parameter_suffix_found = TRUE; } if (parameter_suffix_found) continue; /* ---------- step 0: search for matching base prefix ---------- */ start_pos = 0; for (i = 0; i < num_base_prefixes && !base_prefix_found; i++) { char *base_prefix = base_prefixes[i]; int len_base_prefix = strlen(base_prefix); boolean ext1_suffix_found = FALSE; boolean ext2_suffix_found = FALSE; boolean ext3_suffix_found = FALSE; boolean exact_match = FALSE; int base_index = -1; int ext1_index = -1; int ext2_index = -1; int ext3_index = -1; base_prefix_found = token_suffix_match(token, base_prefix, start_pos); if (!base_prefix_found) continue; base_index = i; if (start_pos + len_base_prefix == len_token) /* exact match */ { exact_match = TRUE; add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, -1, -1, -1, current_summarized_file_list_entry); continue; } /* ---------- step 1: search for matching first suffix ---------- */ start_pos += len_base_prefix; for (j = 0; j < num_ext1_suffixes && !ext1_suffix_found; j++) { char *ext1_suffix = ext1_suffixes[j]; int len_ext1_suffix = strlen(ext1_suffix); ext1_suffix_found = token_suffix_match(token, ext1_suffix, start_pos); if (!ext1_suffix_found) continue; ext1_index = j; if (start_pos + len_ext1_suffix == len_token) /* exact match */ { exact_match = TRUE; add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, ext1_index, -1, -1, current_summarized_file_list_entry); continue; } start_pos += len_ext1_suffix; } if (exact_match) break; /* ---------- step 2: search for matching second suffix ---------- */ for (k = 0; k < num_ext2_suffixes && !ext2_suffix_found; k++) { char *ext2_suffix = ext2_suffixes[k]; int len_ext2_suffix = strlen(ext2_suffix); ext2_suffix_found = token_suffix_match(token, ext2_suffix, start_pos); if (!ext2_suffix_found) continue; ext2_index = k; if (start_pos + len_ext2_suffix == len_token) /* exact match */ { exact_match = TRUE; add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, ext1_index, ext2_index, -1, current_summarized_file_list_entry); continue; } start_pos += len_ext2_suffix; } if (exact_match) break; /* ---------- step 3: search for matching third suffix ---------- */ for (l = 0; l < num_ext3_suffixes && !ext3_suffix_found; l++) { char *ext3_suffix = ext3_suffixes[l]; int len_ext3_suffix = strlen(ext3_suffix); ext3_suffix_found = token_suffix_match(token, ext3_suffix, start_pos); if (!ext3_suffix_found) continue; ext3_index = l; if (start_pos + len_ext3_suffix == len_token) /* exact match */ { exact_match = TRUE; add_dynamic_file_list_entry(dynamic_file_list, num_dynamic_file_list_entries, extra_file_hash, suffix_list, num_suffix_list_entries, token); add_property_mapping(property_mapping, num_property_mapping_entries, base_index, ext1_index, ext2_index, ext3_index, current_summarized_file_list_entry); continue; } } } } END_HASH_ITERATION(extra_file_hash, itr) if (artwork_info->num_dynamic_file_list_entries > 0) { artwork_info->dynamic_artwork_list = checked_calloc(artwork_info->num_dynamic_file_list_entries * artwork_info->sizeof_artwork_list_entry); } if (options.verbose && IS_PARENT_PROCESS()) { SetupFileList *setup_file_list, *list; boolean dynamic_tokens_found = FALSE; boolean unknown_tokens_found = FALSE; boolean undefined_values_found = (hashtable_count(empty_file_hash) != 0); /* list may be NULL for empty artwork config files */ setup_file_list = loadSetupFileList(filename); BEGIN_HASH_ITERATION(extra_file_hash, itr) { if (strEqual(HASH_ITERATION_VALUE(itr), known_token_value)) dynamic_tokens_found = TRUE; else unknown_tokens_found = TRUE; } END_HASH_ITERATION(extra_file_hash, itr) if (options.debug && dynamic_tokens_found) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "dynamic token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(extra_file_hash, list->token); if (value != NULL && strEqual(value, known_token_value)) Error(ERR_INFO, "- dynamic token: '%s'", list->token); } Error(ERR_INFO_LINE, "-"); } if (unknown_tokens_found) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: unknown token(s) found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(extra_file_hash, list->token); if (value != NULL && !strEqual(value, known_token_value)) Error(ERR_INFO, "- dynamic token: '%s'", list->token); } Error(ERR_INFO_LINE, "-"); } if (undefined_values_found) { Error(ERR_INFO_LINE, "-"); Error(ERR_INFO, "warning: undefined values found in config file:"); Error(ERR_INFO, "- config file: '%s'", filename); for (list = setup_file_list; list != NULL; list = list->next) { char *value = getHashEntry(empty_file_hash, list->token); if (value != NULL) Error(ERR_INFO, "- undefined value for token: '%s'", list->token); } Error(ERR_INFO_LINE, "-"); } freeSetupFileList(setup_file_list); } freeSetupFileHash(extra_file_hash); freeSetupFileHash(empty_file_hash); } void LoadArtworkConfig(struct ArtworkListInfo *artwork_info) { struct FileInfo *file_list = artwork_info->file_list; int num_file_list_entries = artwork_info->num_file_list_entries; int num_suffix_list_entries = artwork_info->num_suffix_list_entries; char *filename_base = UNDEFINED_FILENAME, *filename_local; int i, j; DrawInitText("Loading artwork config", 120, FC_GREEN); DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW); /* always start with reliable default values */ for (i = 0; i < num_file_list_entries; i++) { setString(&file_list[i].filename, file_list[i].default_filename); for (j = 0; j < num_suffix_list_entries; j++) setString(&file_list[i].parameter[j], file_list[i].default_parameter[j]); file_list[i].redefined = FALSE; file_list[i].fallback_to_default = FALSE; } /* free previous dynamic artwork file array */ if (artwork_info->dynamic_file_list != NULL) { for (i = 0; i < artwork_info->num_dynamic_file_list_entries; i++) { free(artwork_info->dynamic_file_list[i].token); free(artwork_info->dynamic_file_list[i].filename); free(artwork_info->dynamic_file_list[i].parameter); } free(artwork_info->dynamic_file_list); artwork_info->dynamic_file_list = NULL; FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list, &artwork_info->num_dynamic_file_list_entries); } /* free previous property mapping */ if (artwork_info->property_mapping != NULL) { free(artwork_info->property_mapping); artwork_info->property_mapping = NULL; artwork_info->num_property_mapping_entries = 0; } if (!GFX_OVERRIDE_ARTWORK(artwork_info->type)) { /* first look for special artwork configured in level series config */ filename_base = getCustomArtworkLevelConfigFilename(artwork_info->type); if (fileExists(filename_base)) LoadArtworkConfigFromFilename(artwork_info, filename_base); } filename_local = getCustomArtworkConfigFilename(artwork_info->type); if (filename_local != NULL && !strEqual(filename_base, filename_local)) LoadArtworkConfigFromFilename(artwork_info, filename_local); } static void deleteArtworkListEntry(struct ArtworkListInfo *artwork_info, struct ListNodeInfo **listnode) { if (*listnode) { char *filename = (*listnode)->source_filename; if (--(*listnode)->num_references <= 0) deleteNodeFromList(&artwork_info->content_list, filename, artwork_info->free_artwork); *listnode = NULL; } } static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info, struct ListNodeInfo **listnode, struct FileInfo *file_list_entry) { char *init_text[] = { "Loading graphics", "Loading sounds", "Loading music" }; ListNode *node; char *basename = file_list_entry->filename; char *filename = getCustomArtworkFilename(basename, artwork_info->type); if (filename == NULL) { Error(ERR_WARN, "cannot find artwork file '%s'", basename); basename = file_list_entry->default_filename; /* fail for cloned default artwork that has no default filename defined */ if (file_list_entry->default_is_cloned && strEqual(basename, UNDEFINED_FILENAME)) { int error_mode = ERR_WARN; /* we can get away without sounds and music, but not without graphics */ if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS) error_mode = ERR_EXIT; Error(error_mode, "token '%s' was cloned and has no default filename", file_list_entry->token); return; } /* dynamic artwork has no default filename / skip empty default artwork */ if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME)) return; file_list_entry->fallback_to_default = TRUE; Error(ERR_WARN, "trying default artwork file '%s'", basename); filename = getCustomArtworkFilename(basename, artwork_info->type); if (filename == NULL) { int error_mode = ERR_WARN; /* we can get away without sounds and music, but not without graphics */ if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS) error_mode = ERR_EXIT; Error(error_mode, "cannot find default artwork file '%s'", basename); return; } } /* check if the old and the new artwork file are the same */ if (*listnode && strEqual((*listnode)->source_filename, filename)) { /* The old and new artwork are the same (have the same filename and path). This usually means that this artwork does not exist in this artwork set and a fallback to the existing artwork is done. */ return; } /* delete existing artwork file entry */ deleteArtworkListEntry(artwork_info, listnode); /* check if the new artwork file already exists in the list of artwork */ if ((node = getNodeFromKey(artwork_info->content_list, filename)) != NULL) { *listnode = (struct ListNodeInfo *)node->content; (*listnode)->num_references++; return; } DrawInitText(init_text[artwork_info->type], 120, FC_GREEN); DrawInitText(basename, 150, FC_YELLOW); if ((*listnode = artwork_info->load_artwork(filename)) != NULL) { /* add new artwork file entry to the list of artwork files */ (*listnode)->num_references = 1; addNodeToList(&artwork_info->content_list, (*listnode)->source_filename, *listnode); } else { int error_mode = ERR_WARN; /* we can get away without sounds and music, but not without graphics */ if (artwork_info->type == ARTWORK_TYPE_GRAPHICS) error_mode = ERR_EXIT; Error(error_mode, "cannot load artwork file '%s'", basename); return; } } static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info, struct ListNodeInfo **listnode, struct FileInfo *file_list_entry) { if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME)) { deleteArtworkListEntry(artwork_info, listnode); return; } replaceArtworkListEntry(artwork_info, listnode, file_list_entry); } void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info) { struct FileInfo *file_list = artwork_info->file_list; struct FileInfo *dynamic_file_list = artwork_info->dynamic_file_list; int num_file_list_entries = artwork_info->num_file_list_entries; int num_dynamic_file_list_entries = artwork_info->num_dynamic_file_list_entries; int i; print_timestamp_init("ReloadCustomArtworkList"); for (i = 0; i < num_file_list_entries; i++) LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[i], &file_list[i]); for (i = 0; i < num_dynamic_file_list_entries; i++) LoadCustomArtwork(artwork_info, &artwork_info->dynamic_artwork_list[i], &dynamic_file_list[i]); print_timestamp_done("ReloadCustomArtworkList"); #if 0 dumpList(artwork_info->content_list); #endif } static void FreeCustomArtworkList(struct ArtworkListInfo *artwork_info, struct ListNodeInfo ***list, int *num_list_entries) { int i; if (*list == NULL) return; for (i = 0; i < *num_list_entries; i++) deleteArtworkListEntry(artwork_info, &(*list)[i]); free(*list); *list = NULL; *num_list_entries = 0; } void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info) { if (artwork_info == NULL) return; FreeCustomArtworkList(artwork_info, &artwork_info->artwork_list, &artwork_info->num_file_list_entries); FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list, &artwork_info->num_dynamic_file_list_entries); } /* ------------------------------------------------------------------------- */ /* functions only needed for non-Unix (non-command-line) systems */ /* (MS-DOS only; SDL/Windows creates files "stdout.txt" and "stderr.txt") */ /* (now also added for Windows, to create files in user data directory) */ /* ------------------------------------------------------------------------- */ char *getLogFilename(char *basename) { return getPath2(getUserGameDataDir(), basename); } void OpenLogFiles() { int i; InitUserDataDirectory(); for (i = 0; i < NUM_LOGS; i++) { if ((program.log_file[i] = fopen(program.log_filename[i], MODE_WRITE)) == NULL) { program.log_file[i] = program.log_file_default[i]; // reset to default Error(ERR_WARN, "cannot open file '%s' for writing: %s", program.log_filename[i], strerror(errno)); } /* output should be unbuffered so it is not truncated in a crash */ setbuf(program.log_file[i], NULL); } } void CloseLogFiles() { int i; for (i = 0; i < NUM_LOGS; i++) if (program.log_file[i] != program.log_file_default[i]) fclose(program.log_file[i]); } void DumpLogFile(int nr) { FILE *log_file = fopen(program.log_filename[nr], MODE_READ); if (log_file == NULL) return; while (!feof(log_file)) fputc(fgetc(log_file), stdout); fclose(log_file); } void NotifyUserAboutErrorFile() { #if defined(PLATFORM_WIN32) char *title_text = getStringCat2(program.program_title, " Error Message"); char *error_text = getStringCat2("The program was aborted due to an error; " "for details, see the following error file:" STRING_NEWLINE, program.log_filename[LOG_ERR_ID]); MessageBox(NULL, error_text, title_text, MB_OK); #endif } /* ------------------------------------------------------------------------- */ /* the following is only for debugging purpose and normally not used */ /* ------------------------------------------------------------------------- */ #if DEBUG #define DEBUG_PRINT_INIT_TIMESTAMPS FALSE #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 10 #define DEBUG_NUM_TIMESTAMPS 10 #define DEBUG_TIME_IN_MICROSECONDS 0 #if DEBUG_TIME_IN_MICROSECONDS static double Counter_Microseconds() { static struct timeval base_time = { 0, 0 }; struct timeval current_time; double counter; gettimeofday(¤t_time, NULL); /* reset base time in case of wrap-around */ if (current_time.tv_sec < base_time.tv_sec) base_time = current_time; counter = ((double)(current_time.tv_sec - base_time.tv_sec)) * 1000000 + ((double)(current_time.tv_usec - base_time.tv_usec)); return counter; /* return microseconds since last init */ } #endif char *debug_print_timestamp_get_padding(int padding_size) { static char *padding = NULL; int max_padding_size = 100; if (padding == NULL) { padding = checked_calloc(max_padding_size + 1); memset(padding, ' ', max_padding_size); } return &padding[MAX(0, max_padding_size - padding_size)]; } void debug_print_timestamp(int counter_nr, char *message) { int indent_size = 8; int padding_size = 40; float timestamp_interval; if (counter_nr < 0) Error(ERR_EXIT, "debugging: invalid negative counter"); else if (counter_nr >= DEBUG_NUM_TIMESTAMPS) Error(ERR_EXIT, "debugging: increase DEBUG_NUM_TIMESTAMPS in misc.c"); #if DEBUG_TIME_IN_MICROSECONDS static double counter[DEBUG_NUM_TIMESTAMPS][2]; char *unit = "ms"; counter[counter_nr][0] = Counter_Microseconds(); #else static int counter[DEBUG_NUM_TIMESTAMPS][2]; char *unit = "s"; counter[counter_nr][0] = Counter(); #endif timestamp_interval = counter[counter_nr][0] - counter[counter_nr][1]; counter[counter_nr][1] = counter[counter_nr][0]; if (message) Error(ERR_DEBUG, "%s%s%s %.3f %s", debug_print_timestamp_get_padding(counter_nr * indent_size), message, debug_print_timestamp_get_padding(padding_size - strlen(message)), timestamp_interval / 1000, unit); } void debug_print_parent_only(char *format, ...) { if (!IS_PARENT_PROCESS()) return; if (format) { va_list ap; va_start(ap, format); vprintf(format, ap); va_end(ap); printf("\n"); } } #endif /* DEBUG */ void print_timestamp_ext(char *message, char *mode) { #if DEBUG_PRINT_INIT_TIMESTAMPS static char *debug_message = NULL; static char *last_message = NULL; static int counter_nr = 0; int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH; checked_free(debug_message); debug_message = getStringCat3(mode, " ", message); if (strEqual(mode, "INIT")) { debug_print_timestamp(counter_nr, NULL); if (counter_nr + 1 < max_depth) debug_print_timestamp(counter_nr, debug_message); counter_nr++; debug_print_timestamp(counter_nr, NULL); } else if (strEqual(mode, "DONE")) { counter_nr--; if (counter_nr + 1 < max_depth || (counter_nr == 0 && max_depth == 1)) { last_message = message; if (counter_nr == 0 && max_depth == 1) { checked_free(debug_message); debug_message = getStringCat3("TIME", " ", message); } debug_print_timestamp(counter_nr, debug_message); } } else if (!strEqual(mode, "TIME") || !strEqual(message, last_message)) { if (counter_nr < max_depth) debug_print_timestamp(counter_nr, debug_message); } #endif } void print_timestamp_init(char *message) { print_timestamp_ext(message, "INIT"); } void print_timestamp_time(char *message) { print_timestamp_ext(message, "TIME"); } void print_timestamp_done(char *message) { print_timestamp_ext(message, "DONE"); } mirrormagic-3.0.0/src/libgame/system.c0000644000175000017500000013001413263212010017177 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // system.c // ============================================================================ #include #include #include "platform.h" #include "system.h" #include "image.h" #include "sound.h" #include "setup.h" #include "joystick.h" #include "misc.h" #define ENABLE_UNUSED_CODE 0 /* currently unused functions */ /* ========================================================================= */ /* exported variables */ /* ========================================================================= */ struct ProgramInfo program; struct OptionInfo options; struct VideoSystemInfo video; struct AudioSystemInfo audio; struct GfxInfo gfx; struct TileCursorInfo tile_cursor; struct OverlayInfo overlay; struct ArtworkInfo artwork; struct JoystickInfo joystick; struct SetupInfo setup; LevelDirTree *leveldir_first_all = NULL; LevelDirTree *leveldir_first = NULL; LevelDirTree *leveldir_current = NULL; int level_nr; struct LevelStats level_stats[MAX_LEVELS]; DrawWindow *window = NULL; DrawBuffer *backbuffer = NULL; DrawBuffer *drawto = NULL; int button_status = MB_NOT_PRESSED; boolean motion_status = FALSE; int wheel_steps = DEFAULT_WHEEL_STEPS; #if defined(TARGET_SDL2) boolean keyrepeat_status = TRUE; #endif int redraw_mask = REDRAW_NONE; int FrameCounter = 0; /* ========================================================================= */ /* init/close functions */ /* ========================================================================= */ void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir, char *program_title, char *icon_title, char *icon_filename, char *cookie_prefix, char *program_version_string, int program_version) { program.command_basepath = getBasePath(argv0); program.command_basename = getBaseName(argv0); program.config_filename = config_filename; program.userdata_subdir = userdata_subdir; program.userdata_path = getUserGameDataDir(); program.program_title = program_title; program.window_title = "(undefined)"; program.icon_title = icon_title; program.icon_filename = icon_filename; program.cookie_prefix = cookie_prefix; program.version_major = VERSION_MAJOR(program_version); program.version_minor = VERSION_MINOR(program_version); program.version_patch = VERSION_PATCH(program_version); program.version_build = VERSION_BUILD(program_version); program.version_ident = program_version; program.version_string = program_version_string; program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME); program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME); program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout; program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr; program.headless = FALSE; } void InitScoresInfo() { char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY); program.global_scores = directoryExists(global_scores_dir); program.many_scores_per_name = !program.global_scores; if (options.debug) { if (program.global_scores) { Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.", global_scores_dir); Error(ERR_DEBUG, "Remove to enable single-user scores directory."); Error(ERR_DEBUG, "(This enables multipe score entries per user.)"); } else { Error(ERR_DEBUG, "Using private, single-user scores directory."); } } free(global_scores_dir); } void SetWindowTitle() { program.window_title = program.window_title_function(); SDLSetWindowTitle(); } void InitWindowTitleFunction(char *(*window_title_function)(void)) { program.window_title_function = window_title_function; } void InitExitMessageFunction(void (*exit_message_function)(char *, va_list)) { program.exit_message_function = exit_message_function; } void InitExitFunction(void (*exit_function)(int)) { program.exit_function = exit_function; /* set signal handlers to custom exit function */ // signal(SIGINT, exit_function); signal(SIGTERM, exit_function); /* set exit function to automatically cleanup SDL stuff after exit() */ atexit(SDL_Quit); } void InitPlatformDependentStuff(void) { // this is initialized in GetOptions(), but may already be used before options.verbose = TRUE; OpenLogFiles(); #if defined(TARGET_SDL2) int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE; #else int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE; #endif if (SDL_Init(sdl_init_flags) < 0) Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError()); SDLNet_Init(); } void ClosePlatformDependentStuff(void) { CloseLogFiles(); } void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize, int real_sx, int real_sy, int full_sxsize, int full_sysize, Bitmap *field_save_buffer) { gfx.sx = sx; gfx.sy = sy; gfx.sxsize = sxsize; gfx.sysize = sysize; gfx.real_sx = real_sx; gfx.real_sy = real_sy; gfx.full_sxsize = full_sxsize; gfx.full_sysize = full_sysize; gfx.field_save_buffer = field_save_buffer; SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */ SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */ } void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size) { gfx.game_tile_size = game_tile_size; gfx.standard_tile_size = standard_tile_size; } void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize) { gfx.dx = dx; gfx.dy = dy; gfx.dxsize = dxsize; gfx.dysize = dysize; } void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize) { gfx.vx = vx; gfx.vy = vy; gfx.vxsize = vxsize; gfx.vysize = vysize; } void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize) { gfx.ex = ex; gfx.ey = ey; gfx.exsize = exsize; gfx.eysize = eysize; } void InitGfxWindowInfo(int win_xsize, int win_ysize) { if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize) { ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize); #if defined(TARGET_SDL2) ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize); #endif ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize); ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize); ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize); ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize); ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize); } gfx.win_xsize = win_xsize; gfx.win_ysize = win_ysize; gfx.background_bitmap_mask = REDRAW_NONE; } void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height) { /* currently only used by MSDOS code to alloc VRAM buffer, if available */ /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */ gfx.scrollbuffer_width = scrollbuffer_width; gfx.scrollbuffer_height = scrollbuffer_height; } void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height) { gfx.clipping_enabled = enabled; gfx.clip_x = x; gfx.clip_y = y; gfx.clip_width = width; gfx.clip_height = height; } void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void)) { gfx.draw_busy_anim_function = draw_busy_anim_function; } void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int)) { gfx.draw_global_anim_function = draw_global_anim_function; } void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int)) { gfx.draw_global_border_function = draw_global_border_function; } void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int)) { gfx.draw_tile_cursor_function = draw_tile_cursor_function; } void InitGfxCustomArtworkInfo() { gfx.override_level_graphics = FALSE; gfx.override_level_sounds = FALSE; gfx.override_level_music = FALSE; gfx.draw_init_text = TRUE; } void InitGfxOtherSettings() { gfx.cursor_mode = CURSOR_DEFAULT; } void InitTileCursorInfo() { tile_cursor.enabled = FALSE; tile_cursor.active = FALSE; tile_cursor.moving = FALSE; tile_cursor.xpos = 0; tile_cursor.ypos = 0; tile_cursor.x = 0; tile_cursor.y = 0; tile_cursor.target_x = 0; tile_cursor.target_y = 0; tile_cursor.sx = 0; tile_cursor.sy = 0; } void InitOverlayInfo() { overlay.enabled = FALSE; overlay.active = FALSE; #if defined(PLATFORM_ANDROID) if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS)) overlay.enabled = TRUE; #endif } void SetTileCursorEnabled(boolean enabled) { tile_cursor.enabled = enabled; } void SetTileCursorActive(boolean active) { tile_cursor.active = active; } void SetTileCursorTargetXY(int x, int y) { // delayed placement of tile selection cursor at target position // (tile cursor will be moved to target position step by step) tile_cursor.xpos = x; tile_cursor.ypos = y; tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size; tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size; tile_cursor.moving = TRUE; } void SetTileCursorXY(int x, int y) { // immediate placement of tile selection cursor at target position SetTileCursorTargetXY(x, y); tile_cursor.x = tile_cursor.target_x; tile_cursor.y = tile_cursor.target_y; tile_cursor.moving = FALSE; } void SetTileCursorSXSY(int sx, int sy) { tile_cursor.sx = sx; tile_cursor.sy = sy; } void SetOverlayEnabled(boolean enabled) { overlay.enabled = enabled; } void SetOverlayActive(boolean active) { overlay.active = active; } boolean GetOverlayActive() { return overlay.active; } void SetDrawDeactivationMask(int draw_deactivation_mask) { gfx.draw_deactivation_mask = draw_deactivation_mask; } int GetDrawDeactivationMask() { return gfx.draw_deactivation_mask; } void SetDrawBackgroundMask(int draw_background_mask) { gfx.draw_background_mask = draw_background_mask; } void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask) { if (background_bitmap_tile != NULL) gfx.background_bitmap_mask |= mask; else gfx.background_bitmap_mask &= ~mask; if (background_bitmap_tile == NULL) /* empty background requested */ return; if (mask == REDRAW_ALL) BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0, 0, 0, video.width, video.height); else if (mask == REDRAW_FIELD) BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0, gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize); else if (mask == REDRAW_DOOR_1) BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0, gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize); } void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove every mask before setting mask for window */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL); } void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove window area mask before setting mask for main area */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD); } void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove window area mask before setting mask for door area */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1); } /* ========================================================================= */ /* video functions */ /* ========================================================================= */ inline static int GetRealDepth(int depth) { return (depth == DEFAULT_DEPTH ? video.default_depth : depth); } inline static void sysFillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { SDLFillRectangle(bitmap, x, y, width, height, color); if (bitmap == backbuffer) SetRedrawMaskFromArea(x, y, width, height); } inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, mask_mode); if (dst_bitmap == backbuffer) SetRedrawMaskFromArea(dst_x, dst_y, width, height); } void LimitScreenUpdates(boolean enable) { SDLLimitScreenUpdates(enable); } void InitVideoDefaults(void) { video.default_depth = 32; } void InitVideoDisplay(void) { if (program.headless) return; SDLInitVideoDisplay(); #if defined(TARGET_SDL2) SDLSetDisplaySize(); #endif } void CloseVideoDisplay(void) { KeyboardAutoRepeatOn(); SDL_QuitSubSystem(SDL_INIT_VIDEO); } void InitVideoBuffer(int width, int height, int depth, boolean fullscreen) { video.width = width; video.height = height; video.depth = GetRealDepth(depth); video.screen_width = width; video.screen_height = height; video.screen_xoffset = 0; video.screen_yoffset = 0; video.fullscreen_available = FULLSCREEN_STATUS; video.fullscreen_enabled = FALSE; video.window_scaling_available = WINDOW_SCALING_STATUS; video.frame_delay = 0; video.frame_delay_value = GAME_FRAME_DELAY; video.shifted_up = FALSE; video.shifted_up_pos = 0; video.shifted_up_pos_last = 0; video.shifted_up_delay = 0; video.shifted_up_delay_value = ONE_SECOND_DELAY / 4; SDLInitVideoBuffer(fullscreen); video.initialized = !program.headless; drawto = backbuffer; } inline static void FreeBitmapPointers(Bitmap *bitmap) { if (bitmap == NULL) return; SDLFreeBitmapPointers(bitmap); checked_free(bitmap->source_filename); bitmap->source_filename = NULL; } inline static void TransferBitmapPointers(Bitmap *src_bitmap, Bitmap *dst_bitmap) { if (src_bitmap == NULL || dst_bitmap == NULL) return; FreeBitmapPointers(dst_bitmap); *dst_bitmap = *src_bitmap; } void FreeBitmap(Bitmap *bitmap) { if (bitmap == NULL) return; FreeBitmapPointers(bitmap); free(bitmap); } Bitmap *CreateBitmapStruct(void) { return checked_calloc(sizeof(Bitmap)); } Bitmap *CreateBitmap(int width, int height, int depth) { Bitmap *new_bitmap = CreateBitmapStruct(); int real_width = MAX(1, width); /* prevent zero bitmap width */ int real_height = MAX(1, height); /* prevent zero bitmap height */ int real_depth = GetRealDepth(depth); SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth); new_bitmap->width = real_width; new_bitmap->height = real_height; return new_bitmap; } void ReCreateBitmap(Bitmap **bitmap, int width, int height) { if (*bitmap != NULL) { /* if new bitmap size fits into old one, no need to re-create it */ if (width <= (*bitmap)->width && height <= (*bitmap)->height) return; /* else adjust size so that old and new bitmap size fit into it */ width = MAX(width, (*bitmap)->width); height = MAX(height, (*bitmap)->height); } Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH); if (*bitmap == NULL) { *bitmap = new_bitmap; } else { TransferBitmapPointers(new_bitmap, *bitmap); free(new_bitmap); } } void CloseWindow(DrawWindow *window) { } void SetRedrawMaskFromArea(int x, int y, int width, int height) { int x1 = x; int y1 = y; int x2 = x + width - 1; int y2 = y + height - 1; if (width == 0 || height == 0) return; if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2)) redraw_mask |= REDRAW_FIELD; else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2)) redraw_mask |= REDRAW_DOOR_1; else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2)) redraw_mask |= REDRAW_DOOR_2; else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2)) redraw_mask |= REDRAW_DOOR_3; else redraw_mask = REDRAW_ALL; } inline static boolean CheckDrawingArea(int x, int y, int width, int height, int draw_mask) { if (draw_mask == REDRAW_NONE) return FALSE; if (draw_mask & REDRAW_ALL) return TRUE; if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y)) return TRUE; if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y)) return TRUE; if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y)) return TRUE; if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y)) return TRUE; return FALSE; } boolean DrawingDeactivatedField() { if (program.headless) return TRUE; if (gfx.draw_deactivation_mask & REDRAW_FIELD) return TRUE; return FALSE; } boolean DrawingDeactivated(int x, int y, int width, int height) { return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask); } boolean DrawingOnBackground(int x, int y) { return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) && CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask)); } static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y, int *width, int *height, boolean is_dest) { int clip_x, clip_y, clip_width, clip_height; if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */ { clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width); clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height); clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x); clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y); } else { clip_x = 0; clip_y = 0; clip_width = bitmap->width; clip_height = bitmap->height; } /* skip if rectangle completely outside bitmap */ if (*x + *width <= clip_x || *y + *height <= clip_y || *x >= clip_x + clip_width || *y >= clip_y + clip_height) return FALSE; /* clip if rectangle overlaps bitmap */ if (*x < clip_x) { *width -= clip_x - *x; *x = clip_x; } else if (*x + *width > clip_x + clip_width) { *width = clip_x + clip_width - *x; } if (*y < clip_y) { *height -= clip_y - *y; *y = clip_y; } else if (*y + *height > clip_y + clip_height) { *height = clip_y + clip_height - *y; } return TRUE; } void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { int dst_x_unclipped = dst_x; int dst_y_unclipped = dst_y; if (program.headless) return; if (src_bitmap == NULL || dst_bitmap == NULL) return; if (DrawingDeactivated(dst_x, dst_y, width, height)) return; if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) || !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE)) return; /* source x/y might need adjustment if destination x/y was clipped top/left */ src_x += dst_x - dst_x_unclipped; src_y += dst_y - dst_y_unclipped; #if defined(TARGET_SDL2) /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */ /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */ /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13, but is already fixed in SVN and should therefore finally be fixed with the next official SDL release, which is probably version 1.2.14.) */ /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */ if (src_bitmap == dst_bitmap) { /* needed when blitting directly to same bitmap -- should not be needed with recent SDL libraries, but apparently does not work in 1.2.11 directly */ static Bitmap *tmp_bitmap = NULL; static int tmp_bitmap_xsize = 0; static int tmp_bitmap_ysize = 0; /* start with largest static bitmaps for initial bitmap size ... */ if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0) { tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width); tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height); } /* ... and allow for later re-adjustments due to custom artwork bitmaps */ if (src_bitmap->width > tmp_bitmap_xsize || src_bitmap->height > tmp_bitmap_ysize) { tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width); tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height); FreeBitmap(tmp_bitmap); tmp_bitmap = NULL; } if (tmp_bitmap == NULL) tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize, DEFAULT_DEPTH); sysCopyArea(src_bitmap, tmp_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE); sysCopyArea(tmp_bitmap, dst_bitmap, dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE); return; } #endif sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE); } void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int src_width, int src_height, int dst_x, int dst_y, int dst_width, int dst_height) { int src_xsize = (src_width == 0 ? src_bitmap->width : src_width); int src_ysize = (src_height == 0 ? src_bitmap->height : src_height); int dst_xsize = dst_width; int dst_ysize = dst_height; int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize; int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize; int x, y; for (y = 0; y < src_ysteps; y++) { for (x = 0; x < src_xsteps; x++) { int draw_x = dst_x + x * src_xsize; int draw_y = dst_y + y * src_ysize; int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize); int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize); BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize, draw_x, draw_y); } } } void FadeRectangle(int x, int y, int width, int height, int fade_mode, int fade_delay, int post_delay, void (*draw_border_function)(void)) { /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */ if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE)) return; SDLFadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); } void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { if (DrawingDeactivated(x, y, width, height)) return; if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE)) return; sysFillRectangle(bitmap, x, y, width, height, color); } void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height) { FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL); } void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y, int width, int height) { if (DrawingOnBackground(x, y)) BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y); else ClearRectangle(bitmap, x, y, width, height); } void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingDeactivated(dst_x, dst_y, width, height)) return; sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_MASKED); } void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingOnBackground(dst_x, dst_y)) { /* draw background */ BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height, dst_x, dst_y); /* draw foreground */ BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y); } void BlitTexture(Bitmap *bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (bitmap == NULL) return; SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE); } void BlitTextureMasked(Bitmap *bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (bitmap == NULL) return; SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_MASKED); } void BlitToScreen(Bitmap *bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (bitmap == NULL) return; if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP) BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y, width, height, dst_x, dst_y); else BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y); } void BlitToScreenMasked(Bitmap *bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (bitmap == NULL) return; if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP) BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y, width, height, dst_x, dst_y); else BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y); } void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y) { SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL); } void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y) { SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL); } void DrawLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y, Pixel pixel, int line_width) { int x, y; if (program.headless) return; for (x = 0; x < line_width; x++) { for (y = 0; y < line_width; y++) { int dx = x - line_width / 2; int dy = y - line_width / 2; if ((x == 0 && y == 0) || (x == 0 && y == line_width - 1) || (x == line_width - 1 && y == 0) || (x == line_width - 1 && y == line_width - 1)) continue; SDLDrawLine(bitmap, from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel); } } } void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel) { int line_width = 4; int i; for (i = 0; i < num_points - 1; i++) DrawLine(bitmap, points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, pixel, line_width); /* SDLDrawLines(bitmap->surface, points, num_points, pixel); */ } Pixel GetPixel(Bitmap *bitmap, int x, int y) { if (program.headless) return BLACK_PIXEL; if (x < 0 || x >= bitmap->width || y < 0 || y >= bitmap->height) return BLACK_PIXEL; return SDLGetPixel(bitmap, x, y); } Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r, unsigned int color_g, unsigned int color_b) { if (program.headless) return BLACK_PIXEL; return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b); } Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color) { unsigned int color_r = (color >> 16) & 0xff; unsigned int color_g = (color >> 8) & 0xff; unsigned int color_b = (color >> 0) & 0xff; return GetPixelFromRGB(bitmap, color_r, color_g, color_b); } void KeyboardAutoRepeatOn(void) { #if defined(TARGET_SDL2) keyrepeat_status = TRUE; #else SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2, SDL_DEFAULT_REPEAT_INTERVAL / 2); SDL_EnableUNICODE(1); #endif } void KeyboardAutoRepeatOff(void) { #if defined(TARGET_SDL2) keyrepeat_status = FALSE; #else SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL); SDL_EnableUNICODE(0); #endif } boolean SetVideoMode(boolean fullscreen) { return SDLSetVideoMode(fullscreen); } void SetVideoFrameDelay(unsigned int frame_delay_value) { video.frame_delay_value = frame_delay_value; } unsigned int GetVideoFrameDelay() { return video.frame_delay_value; } boolean ChangeVideoModeIfNeeded(boolean fullscreen) { if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)|| (!fullscreen && video.fullscreen_enabled)) fullscreen = SetVideoMode(fullscreen); return fullscreen; } Bitmap *LoadImage(char *filename) { Bitmap *new_bitmap; new_bitmap = SDLLoadImage(filename); if (new_bitmap) new_bitmap->source_filename = getStringCopy(filename); return new_bitmap; } Bitmap *LoadCustomImage(char *basename) { char *filename = getCustomImageFilename(basename); Bitmap *new_bitmap; if (filename == NULL) Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename); if ((new_bitmap = LoadImage(filename)) == NULL) Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError()); return new_bitmap; } void ReloadCustomImage(Bitmap *bitmap, char *basename) { char *filename = getCustomImageFilename(basename); Bitmap *new_bitmap; if (filename == NULL) /* (should never happen) */ { Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename); return; } if (strEqual(filename, bitmap->source_filename)) { /* The old and new image are the same (have the same filename and path). This usually means that this image does not exist in this graphic set and a fallback to the existing image is done. */ return; } if ((new_bitmap = LoadImage(filename)) == NULL) { Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError()); return; } if (bitmap->width != new_bitmap->width || bitmap->height != new_bitmap->height) { Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions", filename); FreeBitmap(new_bitmap); return; } TransferBitmapPointers(new_bitmap, bitmap); free(new_bitmap); } static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height) { return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height); } void ReCreateGameTileSizeBitmap(Bitmap **bitmaps) { if (bitmaps[IMG_BITMAP_CUSTOM]) { FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]); bitmaps[IMG_BITMAP_CUSTOM] = NULL; } if (gfx.game_tile_size == gfx.standard_tile_size) { bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD]; return; } Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD]; int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;; int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;; Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height); bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new; bitmaps[IMG_BITMAP_GAME] = bitmap_new; } static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor, int tile_size, boolean create_small_bitmaps) { Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD]; Bitmap *tmp_bitmap_final = NULL; Bitmap *tmp_bitmap_0 = NULL; Bitmap *tmp_bitmap_1 = NULL; Bitmap *tmp_bitmap_2 = NULL; Bitmap *tmp_bitmap_4 = NULL; Bitmap *tmp_bitmap_8 = NULL; Bitmap *tmp_bitmap_16 = NULL; Bitmap *tmp_bitmap_32 = NULL; int width_final, height_final; int width_0, height_0; int width_1, height_1; int width_2, height_2; int width_4, height_4; int width_8, height_8; int width_16, height_16; int width_32, height_32; int old_width, old_height; int i; print_timestamp_init("CreateScaledBitmaps"); old_width = old_bitmap->width; old_height = old_bitmap->height; /* calculate new image dimensions for final image size */ width_final = old_width * zoom_factor; height_final = old_height * zoom_factor; /* get image with final size (this might require scaling up) */ /* ("final" size may result in non-standard tile size image) */ if (zoom_factor != 1) tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final); else tmp_bitmap_final = old_bitmap; UPDATE_BUSY_STATE(); width_0 = width_1 = width_final; height_0 = height_1 = height_final; tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final; if (create_small_bitmaps) { /* check if we have a non-gameplay tile size image */ if (tile_size != gfx.game_tile_size) { /* get image with gameplay tile size */ width_0 = width_final * gfx.game_tile_size / tile_size; height_0 = height_final * gfx.game_tile_size / tile_size; if (width_0 == old_width) tmp_bitmap_0 = old_bitmap; else if (width_0 == width_final) tmp_bitmap_0 = tmp_bitmap_final; else tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0); UPDATE_BUSY_STATE(); } /* check if we have a non-standard tile size image */ if (tile_size != gfx.standard_tile_size) { /* get image with standard tile size */ width_1 = width_final * gfx.standard_tile_size / tile_size; height_1 = height_final * gfx.standard_tile_size / tile_size; if (width_1 == old_width) tmp_bitmap_1 = old_bitmap; else if (width_1 == width_final) tmp_bitmap_1 = tmp_bitmap_final; else if (width_1 == width_0) tmp_bitmap_1 = tmp_bitmap_0; else tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1); UPDATE_BUSY_STATE(); } /* calculate new image dimensions for small images */ width_2 = width_1 / 2; height_2 = height_1 / 2; width_4 = width_1 / 4; height_4 = height_1 / 4; width_8 = width_1 / 8; height_8 = height_1 / 8; width_16 = width_1 / 16; height_16 = height_1 / 16; width_32 = width_1 / 32; height_32 = height_1 / 32; /* get image with 1/2 of normal size (for use in the level editor) */ if (width_2 == old_width) tmp_bitmap_2 = old_bitmap; else tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2); UPDATE_BUSY_STATE(); /* get image with 1/4 of normal size (for use in the level editor) */ if (width_4 == old_width) tmp_bitmap_4 = old_bitmap; else tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4); UPDATE_BUSY_STATE(); /* get image with 1/8 of normal size (for use on the preview screen) */ if (width_8 == old_width) tmp_bitmap_8 = old_bitmap; else tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8); UPDATE_BUSY_STATE(); /* get image with 1/16 of normal size (for use on the preview screen) */ if (width_16 == old_width) tmp_bitmap_16 = old_bitmap; else tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16); UPDATE_BUSY_STATE(); /* get image with 1/32 of normal size (for use on the preview screen) */ if (width_32 == old_width) tmp_bitmap_32 = old_bitmap; else tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32); UPDATE_BUSY_STATE(); bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1; bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2; bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4; bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8; bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16; bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32; if (width_0 != width_1) bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0; if (bitmaps[IMG_BITMAP_CUSTOM]) bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM]; else bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD]; boolean free_old_bitmap = TRUE; for (i = 0; i < NUM_IMG_BITMAPS; i++) if (bitmaps[i] == old_bitmap) free_old_bitmap = FALSE; if (free_old_bitmap) FreeBitmap(old_bitmap); } else { bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1; } UPDATE_BUSY_STATE(); print_timestamp_done("CreateScaledBitmaps"); } void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor, int tile_size) { CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE); } void CreateBitmapTextures(Bitmap **bitmaps) { SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]); } void FreeBitmapTextures(Bitmap **bitmaps) { SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]); } void ScaleBitmap(Bitmap **bitmaps, int zoom_factor) { CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE); } /* ------------------------------------------------------------------------- */ /* mouse pointer functions */ /* ------------------------------------------------------------------------- */ #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0 /* XPM image definitions */ static const char *cursor_image_none[] = { /* width height num_colors chars_per_pixel */ " 16 16 3 1", /* colors */ "X c #000000", ". c #ffffff", " c None", /* pixels */ " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", /* hot spot */ "0,0" }; #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER static const char *cursor_image_dot[] = { /* width height num_colors chars_per_pixel */ " 16 16 3 1", /* colors */ "X c #000000", ". c #ffffff", " c None", /* pixels */ " X ", "X.X ", " X ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", /* hot spot */ "1,1" }; static const char **cursor_image_playfield = cursor_image_dot; #else /* some people complained about a "white dot" on the screen and thought it was a graphical error... OK, let's just remove the whole pointer :-) */ static const char **cursor_image_playfield = cursor_image_none; #endif static const int cursor_bit_order = BIT_ORDER_MSB; static struct MouseCursorInfo *get_cursor_from_image(const char **image) { struct MouseCursorInfo *cursor; boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB); int header_lines = 4; int x, y, i; cursor = checked_calloc(sizeof(struct MouseCursorInfo)); sscanf(image[0], " %d %d ", &cursor->width, &cursor->height); i = -1; for (y = 0; y < cursor->width; y++) { for (x = 0; x < cursor->height; x++) { int bit_nr = x % 8; int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr ); if (bit_nr == 0) { i++; cursor->data[i] = cursor->mask[i] = 0; } switch (image[header_lines + y][x]) { case 'X': cursor->data[i] |= bit_mask; cursor->mask[i] |= bit_mask; break; case '.': cursor->mask[i] |= bit_mask; break; case ' ': break; } } } sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y); return cursor; } void SetMouseCursor(int mode) { static struct MouseCursorInfo *cursor_none = NULL; static struct MouseCursorInfo *cursor_playfield = NULL; struct MouseCursorInfo *cursor_new; if (cursor_none == NULL) cursor_none = get_cursor_from_image(cursor_image_none); if (cursor_playfield == NULL) cursor_playfield = get_cursor_from_image(cursor_image_playfield); cursor_new = (mode == CURSOR_DEFAULT ? NULL : mode == CURSOR_NONE ? cursor_none : mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL); SDLSetMouseCursor(cursor_new); gfx.cursor_mode = mode; } /* ========================================================================= */ /* audio functions */ /* ========================================================================= */ void OpenAudio(void) { /* always start with reliable default values */ audio.sound_available = FALSE; audio.music_available = FALSE; audio.loops_available = FALSE; audio.sound_enabled = FALSE; audio.sound_deactivated = FALSE; audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0; audio.mixer_pid = 0; audio.device_name = NULL; audio.device_fd = -1; audio.num_channels = 0; audio.music_channel = 0; audio.first_sound_channel = 0; SDLOpenAudio(); } void CloseAudio(void) { SDLCloseAudio(); audio.sound_enabled = FALSE; } void SetAudioMode(boolean enabled) { if (!audio.sound_available) return; audio.sound_enabled = enabled; } /* ========================================================================= */ /* event functions */ /* ========================================================================= */ boolean PendingEvent(void) { return (SDL_PollEvent(NULL) ? TRUE : FALSE); } void WaitEvent(Event *event) { SDLWaitEvent(event); } void PeekEvent(Event *event) { #if defined(TARGET_SDL2) SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); #else SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS); #endif } void CheckQuitEvent(void) { if (SDL_QuitRequested()) program.exit_function(0); } Key GetEventKey(KeyEvent *event, boolean with_modifiers) { #if defined(TARGET_SDL2) /* key up/down events in SDL2 do not return text characters anymore */ return event->keysym.sym; #else #if ENABLE_UNUSED_CODE printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n", (int)event->keysym.unicode, (int)event->keysym.sym, (int)SDL_GetModState()); #endif if (with_modifiers && event->keysym.unicode > 0x0000 && event->keysym.unicode < 0x2000) return event->keysym.unicode; else return event->keysym.sym; #endif } KeyMod HandleKeyModState(Key key, int key_status) { static KeyMod current_modifiers = KMOD_None; if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */ { KeyMod new_modifier = KMOD_None; switch(key) { case KSYM_Shift_L: new_modifier = KMOD_Shift_L; break; case KSYM_Shift_R: new_modifier = KMOD_Shift_R; break; case KSYM_Control_L: new_modifier = KMOD_Control_L; break; case KSYM_Control_R: new_modifier = KMOD_Control_R; break; case KSYM_Meta_L: new_modifier = KMOD_Meta_L; break; case KSYM_Meta_R: new_modifier = KMOD_Meta_R; break; case KSYM_Alt_L: new_modifier = KMOD_Alt_L; break; case KSYM_Alt_R: new_modifier = KMOD_Alt_R; break; default: break; } if (key_status == KEY_PRESSED) current_modifiers |= new_modifier; else current_modifiers &= ~new_modifier; } return current_modifiers; } KeyMod GetKeyModState() { return (KeyMod)SDL_GetModState(); } KeyMod GetKeyModStateFromEvents() { /* always use key modifier state as tracked from key events (this is needed if the modifier key event was injected into the event queue, but the key was not really pressed on keyboard -- SDL_GetModState() seems to directly query the keys as held pressed on the keyboard) -- this case is currently only used to filter out clipboard insert events from "True X-Mouse" tool */ return HandleKeyModState(KSYM_UNDEFINED, 0); } void StartTextInput(int x, int y, int width, int height) { #if defined(TARGET_SDL2) #if defined(HAS_SCREEN_KEYBOARD) SDL_StartTextInput(); if (y + height > SCREEN_KEYBOARD_POS(video.height)) { video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height); video.shifted_up_delay = SDL_GetTicks(); video.shifted_up = TRUE; } #endif #endif } void StopTextInput() { #if defined(TARGET_SDL2) #if defined(HAS_SCREEN_KEYBOARD) SDL_StopTextInput(); if (video.shifted_up) { video.shifted_up_pos = 0; video.shifted_up_delay = SDL_GetTicks(); video.shifted_up = FALSE; } #endif #endif } boolean CheckCloseWindowEvent(ClientMessageEvent *event) { if (event->type != EVENT_CLIENTMESSAGE) return FALSE; return TRUE; /* the only possible message here is SDL_QUIT */ } /* ========================================================================= */ /* joystick functions */ /* ========================================================================= */ void InitJoysticks() { int i; #if defined(NO_JOYSTICK) return; /* joysticks generally deactivated by compile-time directive */ #endif /* always start with reliable default values */ joystick.status = JOYSTICK_NOT_AVAILABLE; for (i = 0; i < MAX_PLAYERS; i++) joystick.nr[i] = -1; /* no joystick configured */ SDLInitJoysticks(); } boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2) { return SDLReadJoystick(nr, x, y, b1, b2); } boolean CheckJoystickOpened(int nr) { return SDLCheckJoystickOpened(nr); } void ClearJoystickState() { SDLClearJoystickState(); } mirrormagic-3.0.0/src/libgame/gadgets.c0000644000175000017500000020112613263212010017274 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // gadgets.c // ============================================================================ #include #include #include "gadgets.h" #include "text.h" #include "misc.h" /* values for DrawGadget() */ #define DG_UNPRESSED 0 #define DG_PRESSED 1 #define DG_BUFFERED 0 #define DG_DIRECT 1 #define OPTION_TEXT_SELECTABLE(g, t) \ (t[0] != g->selectbox.char_unselectable && \ t[0] != '\0' && \ !strEqual(t, " ")) #define CURRENT_OPTION_SELECTABLE(g) \ OPTION_TEXT_SELECTABLE(g, g->selectbox.options[g->selectbox.current_index].text) static struct GadgetInfo *gadget_list_first_entry = NULL; static struct GadgetInfo *gadget_list_last_entry = NULL; static struct GadgetInfo *last_info_gi = NULL; static int next_free_gadget_id = 1; static boolean gadget_id_wrapped = FALSE; static void (*PlayGadgetSoundActivating)(void) = NULL; static void (*PlayGadgetSoundSelecting)(void) = NULL; void InitGadgetsSoundCallback(void (*activating_function)(void), void (*selecting_function)(void)) { PlayGadgetSoundActivating = activating_function; PlayGadgetSoundSelecting = selecting_function; } static struct GadgetInfo *getGadgetInfoFromGadgetID(int id) { struct GadgetInfo *gi = gadget_list_first_entry; while (gi && gi->id != id) gi = gi->next; return gi; } static int getNewGadgetID() { int id = next_free_gadget_id++; if (next_free_gadget_id <= 0) /* counter overrun */ { gadget_id_wrapped = TRUE; /* now we must check each ID */ next_free_gadget_id = 0; } if (gadget_id_wrapped) { next_free_gadget_id++; while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL) next_free_gadget_id++; } if (next_free_gadget_id <= 0) /* cannot get new gadget id */ Error(ERR_EXIT, "too much gadgets -- this should not happen"); return id; } static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my, int button) { struct GadgetInfo *gi; /* first check for scrollbars in case of mouse scroll wheel button events */ if (IS_WHEEL_BUTTON(button)) { /* real horizontal wheel or vertical wheel with modifier key pressed */ boolean check_horizontal = (IS_WHEEL_BUTTON_HORIZONTAL(button) || GetKeyModState() & KMOD_Shift); /* check for the first active scrollbar directly under the mouse pointer */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && (gi->type & GD_TYPE_SCROLLBAR) && mx >= gi->x && mx < gi->x + gi->width && my >= gi->y && my < gi->y + gi->height) return gi; } /* check for the first active scrollbar with matching mouse wheel area */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && ((gi->type & GD_TYPE_SCROLLBAR_HORIZONTAL && check_horizontal) || (gi->type & GD_TYPE_SCROLLBAR_VERTICAL && !check_horizontal)) && mx >= gi->wheelarea.x && mx < gi->wheelarea.x + gi->wheelarea.width && my >= gi->wheelarea.y && my < gi->wheelarea.y + gi->wheelarea.height) return gi; } /* no active scrollbar found -- ignore this scroll wheel button event */ return NULL; } /* open selectboxes may overlap other active gadgets, so check them first */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open && mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) return gi; } /* check all other gadgets */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { if (gi->mapped && gi->active && mx >= gi->x && mx < gi->x + gi->width && my >= gi->y && my < gi->y + gi->height) return gi; } return NULL; } static void setTextAreaCursorExt(struct GadgetInfo *gi, boolean set_cursor_pos) { char *text = gi->textarea.value; int area_xsize = gi->textarea.xsize; int area_ysize = gi->textarea.ysize; int cursor_position = gi->textarea.cursor_position; int cursor_x = gi->textarea.cursor_x; int cursor_y = gi->textarea.cursor_y; int pos = 0; int x = 0; int y = 0; while (*text) { if (set_cursor_pos) /* x/y => position */ { if (y == cursor_y && (x == cursor_x || (x < cursor_x && *text == '\n'))) break; } else /* position => x/y */ { if (pos == cursor_position) break; } if (x + 1 >= area_xsize || *text == '\n') { if (y + 1 >= area_ysize) break; x = 0; y++; } else x++; text++; pos++; } gi->textarea.cursor_x = x; gi->textarea.cursor_y = y; gi->textarea.cursor_x_preferred = x; gi->textarea.cursor_position = pos; } static void setTextAreaCursorXY(struct GadgetInfo *gi, int x, int y) { gi->textarea.cursor_x = x; gi->textarea.cursor_y = y; setTextAreaCursorExt(gi, TRUE); } static void setTextAreaCursorPosition(struct GadgetInfo *gi, int pos) { gi->textarea.cursor_position = pos; setTextAreaCursorExt(gi, FALSE); } static void default_callback_info(void *ptr) { return; } static void default_callback_action(void *ptr) { return; } static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) { struct GadgetDesign *gd; int state = (pressed ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED); boolean redraw_selectbox = FALSE; if (gi == NULL || gi->deactivated) return; gd = (!gi->active ? &gi->alt_design[state] : gi->checked ? &gi->alt_design[state] : &gi->design[state]); switch (gi->type) { case GD_TYPE_NORMAL_BUTTON: case GD_TYPE_CHECK_BUTTON: case GD_TYPE_RADIO_BUTTON: BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->width, gi->height, gi->x, gi->y); if (gi->deco.design.bitmap) { // make sure that decoration does not overlap gadget border int deco_x = gi->deco.x + (pressed ? gi->deco.xshift : 0); int deco_y = gi->deco.y + (pressed ? gi->deco.yshift : 0); int deco_width = MIN(gi->deco.width, gi->width - deco_x); int deco_height = MIN(gi->deco.height, gi->height - deco_y); if (gi->deco.masked) BlitBitmapMasked(gi->deco.design.bitmap, drawto, gi->deco.design.x, gi->deco.design.y, deco_width, deco_height, gi->x + deco_x, gi->y + deco_y); else BlitBitmap(gi->deco.design.bitmap, drawto, gi->deco.design.x, gi->deco.design.y, deco_width, deco_height, gi->x + deco_x, gi->y + deco_y); } break; case GD_TYPE_TEXT_BUTTON: { int i; int font_nr = (gi->active ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; int text_size = strlen(gi->textbutton.value); int text_start = (gi->width - text_size * font_width) / 2; /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ for (i=0; i < gi->textbutton.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, gi->height, gi->x + gi->width - border_x, gi->y); /* gadget text value */ DrawTextExt(drawto, gi->x + text_start + (pressed ? gi->deco.xshift : 0), gi->y + border_y + (pressed ? gi->deco.yshift : 0), gi->textbutton.value, font_nr, BLIT_MASKED); } break; case GD_TYPE_TEXT_INPUT_ALPHANUMERIC: case GD_TYPE_TEXT_INPUT_NUMERIC: { int i; char cursor_letter; char cursor_string[2]; char text[MAX_GADGET_TEXTSIZE + 1]; int font_nr = (pressed ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ for (i=0; i < gi->textinput.size + 1; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, gi->height, gi->x + gi->width - border_x, gi->y); /* set text value */ strcpy(text, gi->textinput.value); strcat(text, " "); /* gadget text value */ DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text, font_nr, BLIT_MASKED); cursor_letter = gi->textinput.value[gi->textinput.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); cursor_string[1] = '\0'; /* draw cursor, if active */ if (pressed) DrawTextExt(drawto, gi->x + border_x + gi->textinput.cursor_position * font_width, gi->y + border_y, cursor_string, font_nr, BLIT_INVERSE); } break; case GD_TYPE_TEXT_AREA: { int i; char cursor_letter; char cursor_string[2]; int font_nr = (pressed ? gi->font_active : gi->font); int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; int gd_height = 2 * border_y + font_height; /* top left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, border_y, gi->x, gi->y); /* top middle part of gadget border */ for (i=0; i < gi->textarea.xsize; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, border_y, gi->x + border_x + i * font_width, gi->y); /* top right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, border_y, gi->x + gi->width - border_x, gi->y); /* left and right part of gadget border for each row */ for (i=0; i < gi->textarea.ysize; i++) { BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y, border_x, font_height, gi->x, gi->y + border_y + i * font_height); BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + border_y, border_x, font_height, gi->x + gi->width - border_x, gi->y + border_y + i * font_height); } /* bottom left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gd_height - border_y, border_x, border_y, gi->x, gi->y + gi->height - border_y); /* bottom middle part of gadget border */ for (i=0; i < gi->textarea.xsize; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y + gd_height - border_y, font_width, border_y, gi->x + border_x + i * font_width, gi->y + gi->height - border_y); /* bottom right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + gd_height - border_y, border_x, border_y, gi->x + gi->width - border_x, gi->y + gi->height - border_y); ClearRectangleOnBackground(drawto, gi->x + border_x, gi->y + border_y, gi->width - 2 * border_x, gi->height - 2 * border_y); /* gadget text value */ DrawTextBuffer(gi->x + border_x, gi->y + border_y, gi->textarea.value, font_nr, gi->textarea.xsize, -1, gi->textarea.ysize, 0, BLIT_ON_BACKGROUND, FALSE, FALSE, FALSE); cursor_letter = gi->textarea.value[gi->textarea.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); cursor_string[1] = '\0'; /* draw cursor, if active */ if (pressed) DrawTextExt(drawto, gi->x + border_x + gi->textarea.cursor_x * font_width, gi->y + border_y + gi->textarea.cursor_y * font_height, cursor_string, font_nr, BLIT_INVERSE); } break; case GD_TYPE_SELECTBOX: { int i; char text[MAX_GADGET_TEXTSIZE + 1]; int font_nr_default = (pressed ? gi->font_active : gi->font); int font_nr = font_nr_default; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_x = gi->border.xsize; int border_y = gi->border.ysize; int button = gi->border.xsize_selectbutton; int width_inner = gi->border.width - button - 2 * border_x; int box_width = gi->selectbox.width; int box_height = gi->selectbox.height; /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ for (i=0; i < gi->selectbox.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); /* button part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x + width_inner, gd->y, button, gi->height, gi->x + gi->width - border_x - button, gi->y); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, gi->height, gi->x + gi->width - border_x, gi->y); /* set text value */ strncpy(text, gi->selectbox.options[gi->selectbox.index].text, gi->selectbox.size); text[gi->selectbox.size] = '\0'; /* set font value */ font_nr = (OPTION_TEXT_SELECTABLE(gi, text) ? font_nr_default : gi->font_unselectable); /* gadget text value */ DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text, font_nr, BLIT_MASKED); if (pressed) { if (!gi->selectbox.open) { gi->selectbox.open = TRUE; gi->selectbox.stay_open = FALSE; gi->selectbox.current_index = gi->selectbox.index; /* save background under selectbox */ BlitBitmap(drawto, gfx.field_save_buffer, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); } /* draw open selectbox */ /* top left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, border_x, border_y, gi->selectbox.x, gi->selectbox.y); /* top middle part of gadget border */ for (i=0; i < gi->selectbox.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, border_y, gi->selectbox.x + border_x + i * font_width, gi->selectbox.y); /* top button part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x + width_inner, gd->y, button, border_y, gi->selectbox.x + box_width -border_x -button, gi->selectbox.y); /* top right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y, border_x, border_y, gi->selectbox.x + box_width - border_x, gi->selectbox.y); /* left and right part of gadget border for each row */ for (i=0; i < gi->selectbox.num_values; i++) { BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y, border_x, font_height, gi->selectbox.x, gi->selectbox.y + border_y + i*font_height); BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + border_y, border_x, font_height, gi->selectbox.x + box_width - border_x, gi->selectbox.y + border_y + i*font_height); } /* bottom left part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gi->height - border_y, border_x, border_y, gi->selectbox.x, gi->selectbox.y + box_height - border_y); /* bottom middle part of gadget border */ for (i=0; i < gi->selectbox.size; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y + gi->height - border_y, font_width, border_y, gi->selectbox.x + border_x + i * font_width, gi->selectbox.y + box_height - border_y); /* bottom button part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x + width_inner, gd->y + gi->height - border_y, button, border_y, gi->selectbox.x + box_width -border_x -button, gi->selectbox.y + box_height - border_y); /* bottom right part of gadget border */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.width - border_x, gd->y + gi->height - border_y, border_x, border_y, gi->selectbox.x + box_width - border_x, gi->selectbox.y + box_height - border_y); ClearRectangleOnBackground(drawto, gi->selectbox.x + border_x, gi->selectbox.y + border_y, gi->selectbox.width - 2 * border_x, gi->selectbox.height - 2 * border_y); /* selectbox text values */ for (i=0; i < gi->selectbox.num_values; i++) { int mask_mode = BLIT_MASKED; strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size); text[gi->selectbox.size] = '\0'; font_nr = (OPTION_TEXT_SELECTABLE(gi, text) ? font_nr_default : gi->font_unselectable); if (i == gi->selectbox.current_index && OPTION_TEXT_SELECTABLE(gi, text)) { FillRectangle(drawto, gi->selectbox.x + border_x, gi->selectbox.y + border_y + i * font_height, gi->selectbox.width - 2 * border_x, font_height, gi->selectbox.inverse_color); /* prevent use of cursor graphic by drawing at least two chars */ strcat(text, " "); text[gi->selectbox.size] = '\0'; mask_mode = BLIT_INVERSE; } DrawTextExt(drawto, gi->selectbox.x + border_x, gi->selectbox.y + border_y + i * font_height, text, font_nr, mask_mode); } redraw_selectbox = TRUE; } else if (gi->selectbox.open) { gi->selectbox.open = FALSE; /* restore background under selectbox */ BlitBitmap(gfx.field_save_buffer, drawto, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); /* redraw closed selectbox */ DrawGadget(gi, FALSE, FALSE); redraw_selectbox = TRUE; } } break; case GD_TYPE_SCROLLBAR_VERTICAL: { int i; int xpos = gi->x; int ypos = gi->y + gi->scrollbar.position; int design_full = gi->width; int design_body = design_full - 2 * gi->border.ysize; int size_full = gi->scrollbar.size; int size_body = size_full - 2 * gi->border.ysize; int num_steps = size_body / design_body; int step_size_remain = size_body - num_steps * design_body; /* clear scrollbar area */ ClearRectangleOnBackground(backbuffer, gi->x, gi->y, gi->width, gi->height); /* upper part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->width, gi->border.ysize, xpos, ypos); /* middle part of gadget */ for (i=0; i < num_steps; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gi->border.ysize, gi->width, design_body, xpos, ypos + gi->border.ysize + i * design_body); /* remaining middle part of gadget */ if (step_size_remain > 0) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + gi->border.ysize, gi->width, step_size_remain, xpos, ypos + gi->border.ysize + num_steps * design_body); /* lower part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + design_full - gi->border.ysize, gi->width, gi->border.ysize, xpos, ypos + size_full - gi->border.ysize); } break; case GD_TYPE_SCROLLBAR_HORIZONTAL: { int i; int xpos = gi->x + gi->scrollbar.position; int ypos = gi->y; int design_full = gi->height; int design_body = design_full - 2 * gi->border.xsize; int size_full = gi->scrollbar.size; int size_body = size_full - 2 * gi->border.xsize; int num_steps = size_body / design_body; int step_size_remain = size_body - num_steps * design_body; /* clear scrollbar area */ ClearRectangleOnBackground(backbuffer, gi->x, gi->y, gi->width, gi->height); /* left part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->border.xsize, gi->height, xpos, ypos); /* middle part of gadget */ for (i=0; i < num_steps; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.xsize, gd->y, design_body, gi->height, xpos + gi->border.xsize + i * design_body, ypos); /* remaining middle part of gadget */ if (step_size_remain > 0) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + gi->border.xsize, gd->y, step_size_remain, gi->height, xpos + gi->border.xsize + num_steps * design_body, ypos); /* right part of gadget */ BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + design_full - gi->border.xsize, gd->y, gi->border.xsize, gi->height, xpos + size_full - gi->border.xsize, ypos); } break; default: return; } // do not use direct gadget drawing anymore; this worked as a speed-up once, // but would slow things down a lot now the screen is always fully redrawn direct = FALSE; if (direct) { BlitBitmap(drawto, window, gi->x, gi->y, gi->width, gi->height, gi->x, gi->y); if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox) BlitBitmap(drawto, window, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); } else { int x = gi->x; int y = gi->y; redraw_mask |= (IN_GFX_FIELD_FULL(x, y) ? REDRAW_FIELD : IN_GFX_DOOR_1(x, y) ? REDRAW_DOOR_1 : IN_GFX_DOOR_2(x, y) ? REDRAW_DOOR_2 : IN_GFX_DOOR_3(x, y) ? REDRAW_DOOR_3 : REDRAW_ALL); } } static int get_minimal_size_for_numeric_input(int minmax_value) { int min_size = 1; /* value needs at least one digit */ int i; /* add number of digits needed for absolute value */ for (i = 10; i <= ABS(minmax_value); i *= 10) min_size++; /* if min/max value is negative, add one digit for minus sign */ if (minmax_value < 0) min_size++; return min_size; } static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) { int tag = first_tag; if (gi == NULL || gi->deactivated) return; while (tag != GDI_END) { switch(tag) { case GDI_CUSTOM_ID: gi->custom_id = va_arg(ap, int); break; case GDI_CUSTOM_TYPE_ID: gi->custom_type_id = va_arg(ap, int); break; case GDI_INFO_TEXT: { int max_textsize = MAX_INFO_TEXTSIZE; char *text = va_arg(ap, char *); if (text != NULL) strncpy(gi->info_text, text, max_textsize); else max_textsize = 0; gi->info_text[max_textsize] = '\0'; } break; case GDI_X: gi->x = va_arg(ap, int); break; case GDI_Y: gi->y = va_arg(ap, int); break; case GDI_WIDTH: gi->width = va_arg(ap, int); break; case GDI_HEIGHT: gi->height = va_arg(ap, int); break; case GDI_TYPE: gi->type = va_arg(ap, unsigned int); break; case GDI_STATE: gi->state = va_arg(ap, unsigned int); break; case GDI_ACTIVE: gi->active = (boolean)va_arg(ap, int); break; case GDI_DIRECT_DRAW: gi->direct_draw = (boolean)va_arg(ap, int); break; case GDI_CHECKED: gi->checked = (boolean)va_arg(ap, int); break; case GDI_RADIO_NR: gi->radio_nr = va_arg(ap, unsigned int); break; case GDI_NUMBER_VALUE: gi->textinput.number_value = va_arg(ap, int); sprintf(gi->textinput.value, "%d", gi->textinput.number_value); strcpy(gi->textinput.last_value, gi->textinput.value); gi->textinput.cursor_position = strlen(gi->textinput.value); break; case GDI_NUMBER_MIN: gi->textinput.number_min = va_arg(ap, int); if (gi->textinput.number_value < gi->textinput.number_min) { gi->textinput.number_value = gi->textinput.number_min; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); strcpy(gi->textinput.last_value, gi->textinput.value); } break; case GDI_NUMBER_MAX: gi->textinput.number_max = va_arg(ap, int); if (gi->textinput.number_value > gi->textinput.number_max) { gi->textinput.number_value = gi->textinput.number_max; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); strcpy(gi->textinput.last_value, gi->textinput.value); } break; case GDI_TEXT_VALUE: { int max_textsize = MAX_GADGET_TEXTSIZE; if (gi->textinput.size) max_textsize = MIN(gi->textinput.size, MAX_GADGET_TEXTSIZE); strncpy(gi->textinput.value, va_arg(ap, char *), max_textsize); strcpy(gi->textinput.last_value, gi->textinput.value); gi->textinput.value[max_textsize] = '\0'; gi->textinput.cursor_position = strlen(gi->textinput.value); /* same tag also used for other gadget definitions */ strcpy(gi->textbutton.value, gi->textinput.value); strcpy(gi->textarea.value, gi->textinput.value); strcpy(gi->textarea.last_value, gi->textinput.value); } break; case GDI_TEXT_SIZE: { int tag_value = va_arg(ap, int); int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE); gi->textinput.size = max_textsize; gi->textinput.value[max_textsize] = '\0'; strcpy(gi->textinput.last_value, gi->textinput.value); /* same tag also used for other gadget definitions */ gi->textarea.size = max_textsize; gi->textarea.value[max_textsize] = '\0'; strcpy(gi->textarea.last_value, gi->textinput.value); gi->textbutton.size = max_textsize; gi->textbutton.value[max_textsize] = '\0'; gi->selectbox.size = gi->textinput.size; } break; case GDI_TEXT_FONT: gi->font = va_arg(ap, int); if (gi->font_active == 0) gi->font_active = gi->font; if (gi->font_unselectable == 0) gi->font_unselectable = gi->font; break; case GDI_TEXT_FONT_ACTIVE: gi->font_active = va_arg(ap, int); break; case GDI_TEXT_FONT_UNSELECTABLE: gi->font_unselectable = va_arg(ap, int); break; case GDI_SELECTBOX_OPTIONS: gi->selectbox.options = va_arg(ap, struct ValueTextInfo *); break; case GDI_SELECTBOX_INDEX: gi->selectbox.index = va_arg(ap, int); break; case GDI_SELECTBOX_CHAR_UNSELECTABLE: gi->selectbox.char_unselectable = (char)va_arg(ap, int); break; case GDI_DESIGN_UNPRESSED: gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *); gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int); gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int); break; case GDI_DESIGN_PRESSED: gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *); gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int); gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int); break; case GDI_ALT_DESIGN_UNPRESSED: gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *); gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int); gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int); break; case GDI_ALT_DESIGN_PRESSED: gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *); gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int); gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int); break; case GDI_BORDER_SIZE: gi->border.xsize = va_arg(ap, int); gi->border.ysize = va_arg(ap, int); break; case GDI_BORDER_SIZE_SELECTBUTTON: gi->border.xsize_selectbutton = va_arg(ap, int); break; case GDI_DESIGN_WIDTH: gi->border.width = va_arg(ap, int); break; case GDI_DECORATION_DESIGN: gi->deco.design.bitmap = va_arg(ap, Bitmap *); gi->deco.design.x = va_arg(ap, int); gi->deco.design.y = va_arg(ap, int); break; case GDI_DECORATION_POSITION: gi->deco.x = va_arg(ap, int); gi->deco.y = va_arg(ap, int); break; case GDI_DECORATION_SIZE: gi->deco.width = va_arg(ap, int); gi->deco.height = va_arg(ap, int); break; case GDI_DECORATION_SHIFTING: gi->deco.xshift = va_arg(ap, int); gi->deco.yshift = va_arg(ap, int); break; case GDI_DECORATION_MASKED: gi->deco.masked = (boolean)va_arg(ap, int); break; case GDI_EVENT_MASK: gi->event_mask = va_arg(ap, unsigned int); break; case GDI_AREA_SIZE: gi->drawing.area_xsize = va_arg(ap, int); gi->drawing.area_ysize = va_arg(ap, int); /* determine dependent values for drawing area gadget, if needed */ if (gi->drawing.item_xsize != 0 && gi->drawing.item_ysize != 0) { gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize; gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize; } else if (gi->width != 0 && gi->height != 0) { gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize; gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize; } /* same tag also used for other gadget definitions */ gi->textarea.xsize = gi->drawing.area_xsize; gi->textarea.ysize = gi->drawing.area_ysize; if (gi->type & GD_TYPE_TEXT_AREA) /* force recalculation */ { gi->width = 0; gi->height = 0; } break; case GDI_ITEM_SIZE: gi->drawing.item_xsize = va_arg(ap, int); gi->drawing.item_ysize = va_arg(ap, int); /* determine dependent values for drawing area gadget, if needed */ if (gi->drawing.area_xsize != 0 && gi->drawing.area_ysize != 0) { gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize; gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize; } else if (gi->width != 0 && gi->height != 0) { gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize; gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize; } break; case GDI_SCROLLBAR_ITEMS_MAX: gi->scrollbar.items_max = va_arg(ap, int); break; case GDI_SCROLLBAR_ITEMS_VISIBLE: gi->scrollbar.items_visible = va_arg(ap, int); break; case GDI_SCROLLBAR_ITEM_POSITION: gi->scrollbar.item_position = va_arg(ap, int); break; case GDI_WHEEL_AREA_X: gi->wheelarea.x = va_arg(ap, int); break; case GDI_WHEEL_AREA_Y: gi->wheelarea.y = va_arg(ap, int); break; case GDI_WHEEL_AREA_WIDTH: gi->wheelarea.width = va_arg(ap, int); break; case GDI_WHEEL_AREA_HEIGHT: gi->wheelarea.height = va_arg(ap, int); break; case GDI_CALLBACK_INFO: gi->callback_info = va_arg(ap, gadget_function); break; case GDI_CALLBACK_ACTION: gi->callback_action = va_arg(ap, gadget_function); break; default: Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag); } tag = va_arg(ap, int); /* read next tag */ } gi->deactivated = FALSE; /* check if gadget has undefined bitmaps */ if (gi->type != GD_TYPE_DRAWING_AREA && (gi->design[GD_BUTTON_UNPRESSED].bitmap == NULL || gi->design[GD_BUTTON_PRESSED].bitmap == NULL)) gi->deactivated = TRUE; /* check if gadget is placed off-screen */ if (gi->x < 0 || gi->y < 0) gi->deactivated = TRUE; /* adjust gadget values in relation to other gadget values */ if (gi->type & GD_TYPE_TEXT_INPUT) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; if (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC) { int number_min = gi->textinput.number_min; int number_max = gi->textinput.number_max; int min_size_min = get_minimal_size_for_numeric_input(number_min); int min_size_max = get_minimal_size_for_numeric_input(number_max); int min_size = MAX(min_size_min, min_size_max); /* expand gadget text input size, if maximal value is too large */ if (gi->textinput.size < min_size) gi->textinput.size = min_size; } gi->width = 2 * border_xsize + (gi->textinput.size + 1) * font_width; gi->height = 2 * border_ysize + font_height; } if (gi->type & GD_TYPE_SELECTBOX) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; int button_size = gi->border.xsize_selectbutton; int bottom_screen_border = gfx.sy + gfx.sysize - font_height; Bitmap *src_bitmap; int src_x, src_y; gi->width = 2 * border_xsize + gi->textinput.size*font_width +button_size; gi->height = 2 * border_ysize + font_height; if (gi->selectbox.options == NULL) Error(ERR_EXIT, "selectbox gadget incomplete (missing options array)"); gi->selectbox.num_values = 0; while (gi->selectbox.options[gi->selectbox.num_values].text != NULL) gi->selectbox.num_values++; /* calculate values for open selectbox */ gi->selectbox.width = gi->width; gi->selectbox.height = 2 * border_ysize + gi->selectbox.num_values * font_height; gi->selectbox.x = gi->x; gi->selectbox.y = gi->y + gi->height; if (gi->selectbox.y + gi->selectbox.height > bottom_screen_border) gi->selectbox.y = gi->y - gi->selectbox.height; if (gi->selectbox.y < 0) gi->selectbox.y = bottom_screen_border - gi->selectbox.height; getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y); src_x += font_width / 2; src_y += font_height / 2; /* there may be esoteric cases with missing or too small font bitmap */ if (src_bitmap != NULL && src_x < src_bitmap->width && src_y < src_bitmap->height) gi->selectbox.inverse_color = GetPixel(src_bitmap, src_x, src_y); /* always start with closed selectbox */ gi->selectbox.open = FALSE; } if (gi->type & GD_TYPE_TEXT_INPUT_NUMERIC) { struct GadgetTextInput *text = &gi->textinput; int value = text->number_value; text->number_value = (value < text->number_min ? text->number_min : value > text->number_max ? text->number_max : value); sprintf(text->value, "%d", text->number_value); } if (gi->type & GD_TYPE_TEXT_BUTTON) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; gi->width = 2 * border_xsize + gi->textbutton.size * font_width; gi->height = 2 * border_ysize + font_height; } if (gi->type & GD_TYPE_SCROLLBAR) { struct GadgetScrollbar *gs = &gi->scrollbar; int scrollbar_size_cmp; if (gi->width == 0 || gi->height == 0 || gs->items_max == 0 || gs->items_visible == 0) Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)"); /* calculate internal scrollbar values */ gs->size_min = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ? gi->width : gi->height); gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ? gi->height : gi->width); scrollbar_size_cmp = gs->size_max * gs->items_visible / gs->items_max; gs->size = MAX(scrollbar_size_cmp, gs->size_min); gs->size_max_cmp = (gs->size_max - (gs->size - scrollbar_size_cmp)); gs->position = gs->size_max_cmp * gs->item_position / gs->items_max; gs->position_max = gs->size_max - gs->size; gs->correction = gs->size_max / gs->items_max / 2; /* finetuning for maximal right/bottom position */ if (gs->item_position == gs->items_max - gs->items_visible) gs->position = gs->position_max; } if (gi->type & GD_TYPE_TEXT_AREA) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; if (gi->width == 0 || gi->height == 0) { gi->width = 2 * border_xsize + gi->textarea.xsize * font_width; gi->height = 2 * border_ysize + gi->textarea.ysize * font_height; } else { gi->textarea.xsize = (gi->width - 2 * border_xsize) / font_width; gi->textarea.ysize = (gi->height - 2 * border_ysize) / font_height; } } } void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...) { va_list ap; va_start(ap, first_tag); HandleGadgetTags(gi, first_tag, ap); va_end(ap); RedrawGadget(gi); } void RedrawGadget(struct GadgetInfo *gi) { if (gi == NULL || gi->deactivated) return; if (gi->mapped) DrawGadget(gi, gi->state, gi->direct_draw); } struct GadgetInfo *CreateGadget(int first_tag, ...) { struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo)); va_list ap; /* always start with reliable default values */ new_gadget->id = getNewGadgetID(); new_gadget->callback_info = default_callback_info; new_gadget->callback_action = default_callback_action; new_gadget->active = TRUE; new_gadget->direct_draw = TRUE; new_gadget->next = NULL; va_start(ap, first_tag); HandleGadgetTags(new_gadget, first_tag, ap); va_end(ap); /* insert new gadget into global gadget list */ if (gadget_list_last_entry) { gadget_list_last_entry->next = new_gadget; gadget_list_last_entry = gadget_list_last_entry->next; } else gadget_list_first_entry = gadget_list_last_entry = new_gadget; return new_gadget; } void FreeGadget(struct GadgetInfo *gi) { struct GadgetInfo *gi_previous = gadget_list_first_entry; if (gi == NULL) return; /* prevent "last_info_gi" from pointing to memory that will be freed */ if (last_info_gi == gi) last_info_gi = NULL; while (gi_previous != NULL && gi_previous->next != gi) gi_previous = gi_previous->next; if (gi == gadget_list_first_entry) gadget_list_first_entry = gi->next; if (gi == gadget_list_last_entry) gadget_list_last_entry = gi_previous; if (gi_previous != NULL) gi_previous->next = gi->next; free(gi); } static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi) { if (gi->type != GD_TYPE_TEXT_INPUT_NUMERIC) return; gi->textinput.number_value = atoi(gi->textinput.value); if (gi->textinput.number_value < gi->textinput.number_min) gi->textinput.number_value = gi->textinput.number_min; if (gi->textinput.number_value > gi->textinput.number_max) gi->textinput.number_value = gi->textinput.number_max; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); if (gi->textinput.cursor_position < 0) gi->textinput.cursor_position = 0; else if (gi->textinput.cursor_position > strlen(gi->textinput.value)) gi->textinput.cursor_position = strlen(gi->textinput.value); } /* global pointer to gadget actually in use (when mouse button pressed) */ static struct GadgetInfo *last_gi = NULL; static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw) { if (gi == NULL || gi->deactivated || gi->mapped) return; gi->mapped = TRUE; if (redraw) DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED); } void MapGadget(struct GadgetInfo *gi) { MapGadgetExt(gi, TRUE); } void UnmapGadget(struct GadgetInfo *gi) { if (gi == NULL || gi->deactivated || !gi->mapped) return; gi->mapped = FALSE; if (gi == last_gi) last_gi = NULL; } #define MAX_NUM_GADGETS 1024 #define MULTIMAP_UNMAP (1 << 0) #define MULTIMAP_REMAP (1 << 1) #define MULTIMAP_REDRAW (1 << 2) #define MULTIMAP_PLAYFIELD (1 << 3) #define MULTIMAP_DOOR_1 (1 << 4) #define MULTIMAP_DOOR_2 (1 << 5) #define MULTIMAP_DOOR_3 (1 << 6) #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \ MULTIMAP_DOOR_1 | \ MULTIMAP_DOOR_2 | \ MULTIMAP_DOOR_3) static void MultiMapGadgets(int mode) { struct GadgetInfo *gi = gadget_list_first_entry; static boolean map_state[MAX_NUM_GADGETS]; int map_count = 0; while (gi != NULL) { int x = gi->x; int y = gi->y; if ((mode & MULTIMAP_PLAYFIELD && IN_GFX_FIELD_FULL(x, y)) || (mode & MULTIMAP_DOOR_1 && IN_GFX_DOOR_1(x, y)) || (mode & MULTIMAP_DOOR_2 && IN_GFX_DOOR_2(x, y)) || (mode & MULTIMAP_DOOR_3 && IN_GFX_DOOR_3(x, y)) || (mode & MULTIMAP_ALL) == MULTIMAP_ALL) { if (mode & MULTIMAP_UNMAP) { map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped; UnmapGadget(gi); } else { if (map_state[map_count++ % MAX_NUM_GADGETS]) MapGadgetExt(gi, (mode & MULTIMAP_REDRAW)); } } gi = gi->next; } } void UnmapAllGadgets() { MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP); } void RemapAllGadgets() { MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP); } boolean anyTextInputGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_TEXT_INPUT) && last_gi->mapped); } boolean anyTextAreaGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_TEXT_AREA) && last_gi->mapped); } boolean anySelectboxGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped); } boolean anyScrollbarGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_SCROLLBAR) && last_gi->mapped); } boolean anyTextGadgetActive() { return (anyTextInputGadgetActive() || anyTextAreaGadgetActive() || anySelectboxGadgetActive()); } static boolean insideSelectboxLine(struct GadgetInfo *gi, int mx, int my) { return (gi != NULL && gi->type & GD_TYPE_SELECTBOX && mx >= gi->x && mx < gi->x + gi->width && my >= gi->y && my < gi->y + gi->height); } static boolean insideSelectboxArea(struct GadgetInfo *gi, int mx, int my) { return (gi != NULL && gi->type & GD_TYPE_SELECTBOX && mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height); } void ClickOnGadget(struct GadgetInfo *gi, int button) { if (gi == NULL || gi->deactivated || !gi->mapped) return; /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); /* simulate pressing mouse button over specified gadget */ HandleGadgets(gi->x, gi->y, button); /* simulate releasing mouse button over specified gadget */ HandleGadgets(gi->x, gi->y, 0); } boolean HandleGadgets(int mx, int my, int button) { static unsigned int pressed_delay = 0; static unsigned int pressed_delay_value = GADGET_FRAME_DELAY; static int last_button = 0; static int last_mx = 0, last_my = 0; static int pressed_mx = 0, pressed_my = 0; static boolean keep_selectbox_open = FALSE; static boolean gadget_stopped = FALSE; int scrollbar_mouse_pos = 0; struct GadgetInfo *new_gi, *gi; boolean press_event; boolean release_event; boolean mouse_moving; boolean mouse_inside_select_line; boolean mouse_inside_select_area; boolean mouse_released_where_pressed; boolean gadget_pressed; boolean gadget_pressed_repeated; boolean gadget_pressed_off_borders; boolean gadget_pressed_inside_select_line; boolean gadget_pressed_delay_reached; boolean gadget_moving; boolean gadget_moving_inside; boolean gadget_moving_off_borders; boolean gadget_draggable; boolean gadget_dragging; boolean gadget_released; boolean gadget_released_inside; boolean gadget_released_inside_select_area; boolean gadget_released_off_borders; boolean changed_position = FALSE; /* check if there are any gadgets defined */ if (gadget_list_first_entry == NULL) return FALSE; /* simulated release of mouse button over last gadget */ if (mx == -1 && my == -1 && button == 0) { mx = last_mx; my = last_my; } /* check which gadget is under the mouse pointer */ new_gi = getGadgetInfoFromMousePosition(mx, my, button); /* check if button state has changed since last invocation */ press_event = (button != 0 && last_button == 0); release_event = (button == 0 && last_button != 0); last_button = button; /* check if mouse has been moved since last invocation */ mouse_moving = ((mx != last_mx || my != last_my) && motion_status); last_mx = mx; last_my = my; if (press_event && new_gi != last_gi) { pressed_mx = mx; pressed_my = my; } mouse_released_where_pressed = (release_event && mx == pressed_mx && my == pressed_my); mouse_inside_select_line = insideSelectboxLine(new_gi, mx, my); mouse_inside_select_area = insideSelectboxArea(new_gi, mx, my); gadget_pressed_off_borders = (press_event && new_gi != last_gi); gadget_pressed_inside_select_line = (press_event && new_gi != NULL && new_gi->type & GD_TYPE_SELECTBOX && new_gi->selectbox.open && insideSelectboxLine(new_gi, mx, my)); /* if mouse button pressed outside text or selectbox gadget, deactivate it */ if (anyTextGadgetActive() && (gadget_pressed_off_borders || (gadget_pressed_inside_select_line && !mouse_inside_select_area))) { struct GadgetInfo *gi = last_gi; boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_LEAVING) != 0); /* check if text gadget has changed its value */ if (gi->type & GD_TYPE_TEXT_INPUT) { CheckRangeOfNumericInputGadget(gi); if (!strEqual(gi->textinput.last_value, gi->textinput.value)) strcpy(gi->textinput.last_value, gi->textinput.value); else gadget_changed = FALSE; } /* selectbox does not change its value when closed by clicking outside */ if (gi->type & GD_TYPE_SELECTBOX) gadget_changed = FALSE; DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->event.type = GD_EVENT_TEXT_LEAVING; if (gadget_changed && !(gi->type & GD_TYPE_SELECTBOX)) gi->callback_action(gi); last_gi = NULL; if (gadget_pressed_inside_select_line) new_gi = NULL; StopTextInput(); } gadget_pressed = (button != 0 && last_gi == NULL && new_gi != NULL && press_event); gadget_pressed_repeated = (button != 0 && last_gi != NULL && new_gi == last_gi); gadget_pressed_delay_reached = DelayReached(&pressed_delay, pressed_delay_value); gadget_released = (release_event && last_gi != NULL); gadget_released_inside = (gadget_released && new_gi == last_gi); gadget_released_off_borders = (gadget_released && new_gi != last_gi); gadget_moving = (button != 0 && last_gi != NULL && mouse_moving); gadget_moving_inside = (gadget_moving && new_gi == last_gi); gadget_moving_off_borders = (gadget_moving && new_gi != last_gi); /* when handling selectbox, set additional state values */ if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX)) gadget_released_inside_select_area = insideSelectboxArea(last_gi, mx, my); else gadget_released_inside_select_area = FALSE; /* setting state for handling over-large selectbox */ if (keep_selectbox_open && (press_event || !mouse_inside_select_line)) keep_selectbox_open = FALSE; /* if new gadget pressed, store this gadget */ if (gadget_pressed) last_gi = new_gi; /* 'gi' is actually handled gadget */ gi = last_gi; /* if gadget is scrollbar, choose mouse position value */ if (gi && gi->type & GD_TYPE_SCROLLBAR) scrollbar_mouse_pos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y); /* if mouse button released, no gadget needs to be handled anymore */ if (gadget_released) { if (gi->type & GD_TYPE_SELECTBOX && (keep_selectbox_open || mouse_released_where_pressed || !gadget_released_inside_select_area || !CURRENT_OPTION_SELECTABLE(gi))) /* selectbox stays open */ { gi->selectbox.stay_open = TRUE; pressed_mx = 0; pressed_my = 0; } else if (!(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ last_gi = NULL; } /* modify event position values even if no gadget is pressed */ if (button == 0 && !release_event) gi = new_gi; /* if new gadget or if no gadget was pressed, release stopped processing */ if (gadget_pressed || new_gi == NULL) gadget_stopped = FALSE; /* if gadget was stopped while being handled, stop gadget processing here */ if (gadget_stopped) return TRUE; if (gi != NULL) { int last_x = gi->event.x; int last_y = gi->event.y; int last_mx = gi->event.mx; int last_my = gi->event.my; gi->event.x = gi->event.mx = mx - gi->x; gi->event.y = gi->event.my = my - gi->y; if (gi->type == GD_TYPE_DRAWING_AREA) { gi->event.x /= gi->drawing.item_xsize; gi->event.y /= gi->drawing.item_ysize; if (last_x != gi->event.x || last_y != gi->event.y || ((last_mx != gi->event.mx || last_my != gi->event.my) && gi->event_mask & GD_EVENT_PIXEL_PRECISE)) changed_position = TRUE; } else if (gi->type & GD_TYPE_TEXT_INPUT && button != 0 && !motion_status) { int old_cursor_position = gi->textinput.cursor_position; /* if mouse button pressed inside activated text gadget, set cursor */ gi->textinput.cursor_position = (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); if (gi->textinput.cursor_position < 0) gi->textinput.cursor_position = 0; else if (gi->textinput.cursor_position > strlen(gi->textinput.value)) gi->textinput.cursor_position = strlen(gi->textinput.value); if (gi->textinput.cursor_position != old_cursor_position) DrawGadget(gi, DG_PRESSED, gi->direct_draw); if (press_event) StartTextInput(gi->x, gi->y, gi->width, gi->height); } else if (gi->type & GD_TYPE_TEXT_AREA && button != 0 && !motion_status) { int old_cursor_position = gi->textarea.cursor_position; int x = (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); int y = (my - gi->y - gi->border.ysize) / getFontHeight(gi->font); x = (x < 0 ? 0 : x >= gi->textarea.xsize ? gi->textarea.xsize - 1 : x); y = (y < 0 ? 0 : y >= gi->textarea.ysize ? gi->textarea.ysize - 1 : y); setTextAreaCursorXY(gi, x, y); if (gi->textarea.cursor_position != old_cursor_position) DrawGadget(gi, DG_PRESSED, gi->direct_draw); if (press_event) StartTextInput(gi->x, gi->y, gi->width, gi->height); } else if (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open && !keep_selectbox_open) { int old_index = gi->selectbox.current_index; /* if mouse moving inside activated selectbox, select value */ if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) gi->selectbox.current_index = (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font); if (gi->selectbox.current_index < 0) gi->selectbox.current_index = 0; else if (gi->selectbox.current_index > gi->selectbox.num_values - 1) gi->selectbox.current_index = gi->selectbox.num_values - 1; if (gi->selectbox.current_index != old_index) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } /* handle gadget popup info text */ if (last_info_gi != new_gi || (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position)) { if (new_gi != NULL && (button == 0 || new_gi == last_gi)) { new_gi->event.type = GD_EVENT_INFO_ENTERING; new_gi->callback_info(new_gi); } else if (last_info_gi != NULL && last_info_gi->mapped) { last_info_gi->event.type = GD_EVENT_INFO_LEAVING; last_info_gi->callback_info(last_info_gi); } last_info_gi = new_gi; } gadget_draggable = (gi && gi->type & GD_TYPE_SCROLLBAR); /* reset drag position for newly pressed scrollbar to "not dragging" */ if (gadget_pressed && gadget_draggable) gi->scrollbar.drag_position = -1; gadget_dragging = (gadget_draggable && gi->scrollbar.drag_position != -1); /* clicking next to a scrollbar to move it is not considered "moving" */ if (gadget_draggable && !gadget_dragging) gadget_moving = FALSE; /* when leaving scrollbar area when jump-scrolling, stop gadget processing */ if (gadget_draggable && !gadget_dragging && gadget_moving_off_borders) gadget_stopped = TRUE; if ((gadget_pressed) || (gadget_pressed_repeated && gadget_pressed_delay_reached)) { if (gadget_pressed) /* gadget pressed the first time */ { /* initialize delay counter */ DelayReached(&pressed_delay, 0); /* start gadget delay with longer delay after first click on gadget */ pressed_delay_value = GADGET_FRAME_DELAY_FIRST; } else /* gadget hold pressed for some time */ { /* after first repeated gadget click, continue with shorter delay value */ pressed_delay_value = GADGET_FRAME_DELAY; } if (gi->type & GD_TYPE_SCROLLBAR && !gadget_dragging) { int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx : my); int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y); int slider_start = gpos + gi->scrollbar.position; int slider_end = gpos + gi->scrollbar.position + gi->scrollbar.size - 1; boolean inside_slider = (mpos >= slider_start && mpos <= slider_end); if (IS_WHEEL_BUTTON(button) || !inside_slider) { /* click scrollbar one scrollbar length up/left or down/right */ struct GadgetScrollbar *gs = &gi->scrollbar; int old_item_position = gs->item_position; int item_steps = gs->items_visible - 1; int item_direction = (mpos < gpos + gi->scrollbar.position ? -1 : +1); if (IS_WHEEL_BUTTON(button)) { boolean scroll_single_step = ((GetKeyModState() & KMOD_Alt) != 0); item_steps = (scroll_single_step ? 1 : wheel_steps); item_direction = (button == MB_WHEEL_UP || button == MB_WHEEL_LEFT ? -1 : +1); } changed_position = FALSE; gs->item_position += item_steps * item_direction; if (gs->item_position < 0) gs->item_position = 0; else if (gs->item_position > gs->items_max - gs->items_visible) gs->item_position = gs->items_max - gs->items_visible; if (old_item_position != gs->item_position) { gi->event.item_position = gs->item_position; changed_position = TRUE; } ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position, GDI_END); gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_MOVING; gi->event.off_borders = FALSE; if (gi->event_mask & GD_EVENT_MOVING && changed_position) gi->callback_action(gi); return TRUE; } else { /* don't handle this scrollbar anymore when mouse position reached */ if (gadget_pressed_repeated) { gadget_stopped = TRUE; return TRUE; } } } } if (gadget_pressed) { PlayGadgetSoundActivating(); if (gi->type == GD_TYPE_CHECK_BUTTON) { gi->checked = !gi->checked; } else if (gi->type == GD_TYPE_RADIO_BUTTON) { struct GadgetInfo *rgi = gadget_list_first_entry; while (rgi) { if (rgi->mapped && rgi->type == GD_TYPE_RADIO_BUTTON && rgi->radio_nr == gi->radio_nr && rgi != gi) { rgi->checked = FALSE; DrawGadget(rgi, DG_UNPRESSED, rgi->direct_draw); } rgi = rgi->next; } gi->checked = TRUE; } else if (gi->type & GD_TYPE_SCROLLBAR) { int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx : my); int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y); int slider_start = gpos + gi->scrollbar.position; int slider_end = gpos + gi->scrollbar.position + gi->scrollbar.size - 1; boolean inside_slider = (mpos >= slider_start && mpos <= slider_end); if (!IS_WHEEL_BUTTON(button) && inside_slider) { /* start dragging scrollbar */ gi->scrollbar.drag_position = scrollbar_mouse_pos - gi->scrollbar.position; } } else if (gi->type & GD_TYPE_SELECTBOX) { /* keep selectbox open in case of over-large selectbox */ keep_selectbox_open = (mouse_inside_select_line && mouse_inside_select_area); } DrawGadget(gi, DG_PRESSED, gi->direct_draw); gi->state = GD_BUTTON_PRESSED; gi->event.type = GD_EVENT_PRESSED; gi->event.button = button; gi->event.off_borders = FALSE; if (gi->event_mask & GD_EVENT_PRESSED) gi->callback_action(gi); } if (gadget_pressed_repeated) { gi->event.type = GD_EVENT_PRESSED; if (gi->event_mask & GD_EVENT_REPEATED && gadget_pressed_delay_reached) gi->callback_action(gi); } if (gadget_moving) { if (gi->type & GD_TYPE_BUTTON) { if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED) DrawGadget(gi, DG_PRESSED, gi->direct_draw); else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED) DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); } else if (gi->type & GD_TYPE_SELECTBOX && !keep_selectbox_open) { int old_index = gi->selectbox.current_index; /* if mouse moving inside activated selectbox, select value */ if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) gi->selectbox.current_index = (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font); if (gi->selectbox.current_index < 0) gi->selectbox.current_index = 0; else if (gi->selectbox.current_index > gi->selectbox.num_values - 1) gi->selectbox.current_index = gi->selectbox.num_values - 1; if (gi->selectbox.current_index != old_index) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (gi->type & GD_TYPE_SCROLLBAR) { struct GadgetScrollbar *gs = &gi->scrollbar; int old_item_position = gs->item_position; gs->position = scrollbar_mouse_pos - gs->drag_position; /* make sure to always precisely reach end positions when dragging */ if (gs->position <= 0) { gs->position = 0; gs->item_position = 0; } else if (gs->position >= gs->position_max) { gs->position = gs->position_max; gs->item_position = gs->items_max - gs->items_visible; } else { gs->item_position = gs->items_max * (gs->position + gs->correction) / gs->size_max_cmp; } if (gs->item_position < 0) gs->item_position = 0; if (gs->item_position > gs->items_max - 1) gs->item_position = gs->items_max - 1; if (old_item_position != gs->item_position) { gi->event.item_position = gs->item_position; changed_position = TRUE; } DrawGadget(gi, DG_PRESSED, gi->direct_draw); } gi->state = (gadget_moving_inside || gadget_draggable ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED); gi->event.type = GD_EVENT_MOVING; gi->event.off_borders = gadget_moving_off_borders; if (gi->event_mask & GD_EVENT_MOVING && changed_position && (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS)) gi->callback_action(gi); } if (gadget_released_inside) { boolean deactivate_gadget = TRUE; boolean gadget_changed = TRUE; if (gi->type & GD_TYPE_SELECTBOX) { if (keep_selectbox_open || mouse_released_where_pressed || !gadget_released_inside_select_area || !CURRENT_OPTION_SELECTABLE(gi)) /* selectbox stays open */ { deactivate_gadget = FALSE; gadget_changed = FALSE; } else if (gi->selectbox.index != gi->selectbox.current_index) gi->selectbox.index = gi->selectbox.current_index; else gadget_changed = FALSE; } if (deactivate_gadget && !(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_RELEASED; if ((gi->event_mask & GD_EVENT_RELEASED) && gadget_changed) { gi->callback_action(gi); } } if (gadget_released_off_borders) { if (gi->type & GD_TYPE_SCROLLBAR) DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_RELEASED; if (gi->event_mask & GD_EVENT_RELEASED && gi->event_mask & GD_EVENT_OFF_BORDERS) gi->callback_action(gi); } /* handle gadgets unmapped/mapped between pressing and releasing */ if (release_event && !gadget_released && new_gi) new_gi->state = GD_BUTTON_UNPRESSED; return (gadget_pressed || gadget_pressed_repeated || gadget_released || gadget_moving); } static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) { char text[MAX_GADGET_TEXTSIZE + 1]; int cursor_position = gi->textarea.cursor_position; if (strlen(gi->textarea.value) >= MAX_GADGET_TEXTSIZE) /* no space left */ return; strcpy(text, gi->textarea.value); strcpy(&gi->textarea.value[cursor_position + 1], &text[cursor_position]); gi->textarea.value[cursor_position] = c; setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); } boolean HandleGadgetsKeyInput(Key key) { struct GadgetInfo *gi = last_gi; if (gi == NULL || gi->deactivated || !gi->mapped || !(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA || gi->type & GD_TYPE_SELECTBOX)) return FALSE; if (key == KSYM_Escape) { StopTextInput(); } else if (key == KSYM_Return) /* valid for both text input and selectbox */ { boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_RETURN) != 0); if (gi->type & GD_TYPE_TEXT_INPUT) { CheckRangeOfNumericInputGadget(gi); if (!strEqual(gi->textinput.last_value, gi->textinput.value)) strcpy(gi->textinput.last_value, gi->textinput.value); else gadget_changed = FALSE; StopTextInput(); } else if (gi->type & GD_TYPE_SELECTBOX) { if (gi->selectbox.index != gi->selectbox.current_index) gi->selectbox.index = gi->selectbox.current_index; else gadget_changed = FALSE; } if (gi->type & GD_TYPE_TEXT_AREA) { insertCharIntoTextArea(gi, '\n'); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else { DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->event.type = GD_EVENT_TEXT_RETURN; last_gi = NULL; } if (gadget_changed) gi->callback_action(gi); } else if (gi->type & GD_TYPE_TEXT_INPUT) /* only valid for text input */ { char text[MAX_GADGET_TEXTSIZE + 1]; int text_length = strlen(gi->textinput.value); int cursor_pos = gi->textinput.cursor_position; char letter = getCharFromKey(key); boolean legal_letter = (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC ? letter >= '0' && letter <= '9' : letter != 0); if (legal_letter && text_length < gi->textinput.size) { strcpy(text, gi->textinput.value); strcpy(&gi->textinput.value[cursor_pos + 1], &text[cursor_pos]); gi->textinput.value[cursor_pos] = letter; gi->textinput.cursor_position++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Left && cursor_pos > 0) { gi->textinput.cursor_position--; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Right && cursor_pos < text_length) { gi->textinput.cursor_position++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_BackSpace && cursor_pos > 0) { strcpy(text, gi->textinput.value); strcpy(&gi->textinput.value[cursor_pos - 1], &text[cursor_pos]); gi->textinput.cursor_position--; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Delete && cursor_pos < text_length) { strcpy(text, gi->textinput.value); strcpy(&gi->textinput.value[cursor_pos], &text[cursor_pos + 1]); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } else if (gi->type & GD_TYPE_TEXT_AREA) /* only valid for text area */ { char text[MAX_GADGET_TEXTSIZE + 1]; int text_length = strlen(gi->textarea.value); int area_ysize = gi->textarea.ysize; int cursor_x_pref = gi->textarea.cursor_x_preferred; int cursor_y = gi->textarea.cursor_y; int cursor_pos = gi->textarea.cursor_position; char letter = getCharFromKey(key); boolean legal_letter = (letter != 0); if (legal_letter) { insertCharIntoTextArea(gi, letter); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Left && cursor_pos > 0) { setTextAreaCursorPosition(gi, gi->textarea.cursor_position - 1); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Right && cursor_pos < text_length) { setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Up && cursor_y > 0) { setTextAreaCursorXY(gi, cursor_x_pref, cursor_y - 1); gi->textarea.cursor_x_preferred = cursor_x_pref; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Down && cursor_y < area_ysize - 1) { setTextAreaCursorXY(gi, cursor_x_pref, cursor_y + 1); gi->textarea.cursor_x_preferred = cursor_x_pref; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_BackSpace && cursor_pos > 0) { strcpy(text, gi->textarea.value); strcpy(&gi->textarea.value[cursor_pos - 1], &text[cursor_pos]); setTextAreaCursorPosition(gi, gi->textarea.cursor_position - 1); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Delete && cursor_pos < text_length) { strcpy(text, gi->textarea.value); strcpy(&gi->textarea.value[cursor_pos], &text[cursor_pos + 1]); DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */ { int index = gi->selectbox.current_index; int num_values = gi->selectbox.num_values; if (key == KSYM_Up && index > 0) { gi->selectbox.current_index--; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Down && index < num_values - 1) { gi->selectbox.current_index++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } return TRUE; } mirrormagic-3.0.0/src/libgame/text.c0000644000175000017500000004272713263212010016654 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // text.c // ============================================================================ #include #include #include "text.h" #include "misc.h" /* ========================================================================= */ /* font functions */ /* ========================================================================= */ void InitFontInfo(struct FontBitmapInfo *font_bitmap_info, int num_fonts, int (*select_font_function)(int), int (*get_font_from_token_function)(char *)) { gfx.num_fonts = num_fonts; gfx.font_bitmap_info = font_bitmap_info; gfx.select_font_function = select_font_function; gfx.get_font_from_token_function = get_font_from_token_function; } void FreeFontInfo(struct FontBitmapInfo *font_bitmap_info) { if (font_bitmap_info == NULL) return; free(font_bitmap_info); } struct FontBitmapInfo *getFontBitmapInfo(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return &gfx.font_bitmap_info[font_bitmap_id]; } int getFontWidth(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return gfx.font_bitmap_info[font_bitmap_id].width; } int getFontHeight(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return gfx.font_bitmap_info[font_bitmap_id].height; } int getFontDrawOffsetX(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return gfx.font_bitmap_info[font_bitmap_id].draw_xoffset; } int getFontDrawOffsetY(int font_nr) { int font_bitmap_id = gfx.select_font_function(font_nr); return gfx.font_bitmap_info[font_bitmap_id].draw_yoffset; } int getTextWidth(char *text, int font_nr) { return (text != NULL ? strlen(text) * getFontWidth(font_nr) : 0); } static int getFontCharPosition(int font_nr, char c) { int font_bitmap_id = gfx.select_font_function(font_nr); struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id]; boolean default_font = (font->num_chars == DEFAULT_NUM_CHARS_PER_FONT); int font_pos = (unsigned char)c - 32; /* map some special characters to their ascii values in default font */ if (default_font) font_pos = MAP_FONT_ASCII(c) - 32; /* this allows dynamic special characters together with special font */ if (font_pos < 0 || font_pos >= font->num_chars) font_pos = 0; return font_pos; } void getFontCharSource(int font_nr, char c, Bitmap **bitmap, int *x, int *y) { int font_bitmap_id = gfx.select_font_function(font_nr); struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id]; int font_pos = getFontCharPosition(font_nr, c); int offset_x = (font->offset_x != 0 ? font->offset_x : font->width); int offset_y = (font->offset_y != 0 ? font->offset_y : font->height); *bitmap = font->bitmap; *x = font->src_x + (font_pos % font->num_chars_per_line) * offset_x; *y = font->src_y + (font_pos / font->num_chars_per_line) * offset_y; } /* ========================================================================= */ /* text string helper functions */ /* ========================================================================= */ int maxWordLengthInString(char *text) { char *text_ptr; int word_len = 0, max_word_len = 0; for (text_ptr = text; *text_ptr; text_ptr++) { word_len = (*text_ptr != ' ' ? word_len + 1 : 0); max_word_len = MAX(word_len, max_word_len); } return max_word_len; } /* ========================================================================= */ /* simple text drawing functions */ /* ========================================================================= */ void DrawInitText(char *text, int ypos, int font_nr) { LimitScreenUpdates(TRUE); UPDATE_BUSY_STATE(); if (window != NULL && gfx.draw_init_text && gfx.num_fonts > 0 && gfx.font_bitmap_info[font_nr].bitmap != NULL) { int x = (video.width - getTextWidth(text, font_nr)) / 2; int y = ypos; int width = video.width; int height = getFontHeight(font_nr); ClearRectangle(drawto, 0, y, width, height); DrawTextExt(drawto, x, y, text, font_nr, BLIT_OPAQUE); BlitBitmap(drawto, window, 0, 0, video.width, video.height, 0, 0); } } void DrawTextF(int x, int y, int font_nr, char *format, ...) { char buffer[MAX_OUTPUT_LINESIZE + 1]; va_list ap; va_start(ap, format); vsprintf(buffer, format, ap); va_end(ap); if (strlen(buffer) > MAX_OUTPUT_LINESIZE) Error(ERR_EXIT, "string too long in DrawTextF() -- aborting"); DrawText(gfx.sx + x, gfx.sy + y, buffer, font_nr); } void DrawTextFCentered(int y, int font_nr, char *format, ...) { char buffer[MAX_OUTPUT_LINESIZE + 1]; va_list ap; va_start(ap, format); vsprintf(buffer, format, ap); va_end(ap); if (strlen(buffer) > MAX_OUTPUT_LINESIZE) Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting"); DrawText(gfx.sx + (gfx.sxsize - getTextWidth(buffer, font_nr)) / 2, gfx.sy + y, buffer, font_nr); } void DrawTextS(int x, int y, int font_nr, char *text) { DrawText(gfx.sx + x, gfx.sy + y, text, font_nr); } void DrawTextSCentered(int y, int font_nr, char *text) { DrawText(gfx.sx + (gfx.sxsize - getTextWidth(text, font_nr)) / 2, gfx.sy + y, text, font_nr); } void DrawTextSAligned(int x, int y, char *text, int font_nr, int align) { DrawText(gfx.sx + ALIGNED_XPOS(x, getTextWidth(text, font_nr), align), gfx.sx + y, text, font_nr); } void DrawTextAligned(int x, int y, char *text, int font_nr, int align) { DrawText(ALIGNED_XPOS(x, getTextWidth(text, font_nr), align), y, text, font_nr); } void DrawText(int x, int y, char *text, int font_nr) { int mask_mode = BLIT_OPAQUE; if (DrawingOnBackground(x, y)) mask_mode = BLIT_ON_BACKGROUND; DrawTextExt(drawto, x, y, text, font_nr, mask_mode); if (IN_GFX_FIELD_FULL(x, y)) redraw_mask |= REDRAW_FIELD; else if (IN_GFX_DOOR_1(x, y)) redraw_mask |= REDRAW_DOOR_1; else if (IN_GFX_DOOR_2(x, y)) redraw_mask |= REDRAW_DOOR_2; else if (IN_GFX_DOOR_3(x, y)) redraw_mask |= REDRAW_DOOR_3; else redraw_mask |= REDRAW_ALL; } void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text, int font_nr, int mask_mode) { struct FontBitmapInfo *font = getFontBitmapInfo(font_nr); int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); Bitmap *src_bitmap; int src_x, src_y; char *text_ptr = text; if (font->bitmap == NULL) return; /* skip text to be printed outside the window (left/right will be clipped) */ if (dst_y < 0 || dst_y + font_height > video.height) return; /* add offset for drawing font characters */ dst_x += font->draw_xoffset; dst_y += font->draw_yoffset; while (*text_ptr) { char c = *text_ptr++; if (c == '\n') c = ' '; /* print space instead of newline */ getFontCharSource(font_nr, c, &src_bitmap, &src_x, &src_y); /* clip text at the left side of the window */ if (dst_x < 0) { dst_x += font_width; continue; } /* clip text at the right side of the window */ if (dst_x + font_width > video.width) break; if (mask_mode == BLIT_INVERSE) /* special mode for text gadgets */ { /* first step: draw solid colored rectangle (use "cursor" character) */ if (strlen(text) == 1) /* only one char inverted => draw cursor */ { Bitmap *cursor_bitmap; int cursor_x, cursor_y; getFontCharSource(font_nr, FONT_ASCII_CURSOR, &cursor_bitmap, &cursor_x, &cursor_y); BlitBitmap(cursor_bitmap, dst_bitmap, cursor_x, cursor_y, font_width, font_height, dst_x, dst_y); } /* second step: draw masked inverted character */ SDLCopyInverseMasked(src_bitmap, dst_bitmap, src_x, src_y, font_width, font_height, dst_x, dst_y); } else if (mask_mode == BLIT_MASKED || mask_mode == BLIT_ON_BACKGROUND) { if (mask_mode == BLIT_ON_BACKGROUND) { /* clear font character background */ ClearRectangleOnBackground(dst_bitmap, dst_x, dst_y, font_width, font_height); } BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, font_width, font_height, dst_x, dst_y); } else /* normal, non-masked font blitting */ { BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, font_width, font_height, dst_x, dst_y); } dst_x += font_width; } } /* ========================================================================= */ /* text buffer drawing functions */ /* ========================================================================= */ #define MAX_LINES_FROM_FILE 1024 char *GetTextBufferFromFile(char *filename, int max_lines) { File *file; char *buffer; int num_lines = 0; if (filename == NULL) return NULL; if (!(file = openFile(filename, MODE_READ))) return NULL; buffer = checked_calloc(1); /* start with valid, but empty text buffer */ while (!checkEndOfFile(file) && num_lines < max_lines) { char line[MAX_LINE_LEN]; /* read next line of input file */ if (!getStringFromFile(file, line, MAX_LINE_LEN)) break; buffer = checked_realloc(buffer, strlen(buffer) + strlen(line) + 1); strcat(buffer, line); num_lines++; } closeFile(file); return buffer; } static boolean RenderLineToBuffer(char **src_buffer_ptr, char *dst_buffer, int *dst_buffer_len, int line_length, boolean last_line_was_empty) { char *text_ptr = *src_buffer_ptr; char *buffer = dst_buffer; int buffer_len = *dst_buffer_len; boolean buffer_filled = FALSE; while (*text_ptr) { char *word_ptr; int word_len; /* skip leading whitespaces */ while (*text_ptr == ' ' || *text_ptr == '\t') text_ptr++; word_ptr = text_ptr; word_len = 0; /* look for end of next word */ while (*word_ptr != ' ' && *word_ptr != '\t' && *word_ptr != '\0') { word_ptr++; word_len++; } if (word_len == 0) { continue; } else if (*text_ptr == '\n') /* special case: force empty line */ { if (buffer_len == 0) text_ptr++; /* prevent printing of multiple empty lines */ if (buffer_len > 0 || !last_line_was_empty) buffer_filled = TRUE; } else if (word_len < line_length - buffer_len) { /* word fits into text buffer -- add word */ if (buffer_len > 0) buffer[buffer_len++] = ' '; strncpy(&buffer[buffer_len], text_ptr, word_len); buffer_len += word_len; buffer[buffer_len] = '\0'; text_ptr += word_len; } else if (buffer_len > 0) { /* not enough space left for word in text buffer -- print buffer */ buffer_filled = TRUE; } else { /* word does not fit at all into empty text buffer -- cut word */ strncpy(buffer, text_ptr, line_length); buffer[line_length] = '\0'; text_ptr += line_length; buffer_filled = TRUE; } if (buffer_filled) break; } *src_buffer_ptr = text_ptr; *dst_buffer_len = buffer_len; return buffer_filled; } static boolean getCheckedTokenValueFromString(char *string, char **token, char **value) { char *ptr; if (!getTokenValueFromString(string, token, value)) return FALSE; if (**token != '.') /* token should begin with dot */ return FALSE; for (ptr = *token; *ptr; ptr++) /* token should contain no whitespace */ if (*ptr == ' ' || *ptr == '\t') return FALSE; for (ptr = *value; *ptr; ptr++) /* value should contain no whitespace */ if (*ptr == ' ' || *ptr == '\t') return FALSE; return TRUE; } static void DrawTextBuffer_Flush(int x, int y, char *buffer, int font_nr, int line_length, int cut_length, int mask_mode, boolean centered, int current_ypos) { int buffer_len = strlen(buffer); int font_width = getFontWidth(font_nr); int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0); int offset_xsize = (centered ? font_width * (line_length - buffer_len) / 2 : 0); int final_cut_length = MAX(0, cut_length - offset_chars); int xx = x + offset_xsize; int yy = y + current_ypos; buffer[final_cut_length] = '\0'; if (mask_mode != -1) DrawTextExt(drawto, xx, yy, buffer, font_nr, mask_mode); else DrawText(xx, yy, buffer, font_nr); } int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr, int line_length, int cut_length, int max_lines, int line_spacing, int mask_mode, boolean autowrap, boolean centered, boolean parse_comments) { char buffer[line_length + 1]; int buffer_len; int font_height = getFontHeight(font_nr); int line_height = font_height + line_spacing; int current_line = 0; int current_ypos = 0; int max_ysize = max_lines * line_height; if (text_buffer == NULL || *text_buffer == '\0') return 0; if (current_line >= max_lines) return 0; if (cut_length == -1) cut_length = line_length; buffer[0] = '\0'; buffer_len = 0; while (*text_buffer && current_ypos < max_ysize) { char line[MAX_LINE_LEN + 1]; char *line_ptr; boolean last_line_was_empty = TRUE; int num_line_chars = MAX_LINE_LEN; int i; /* copy next line from text buffer to line buffer (nearly fgets() style) */ for (i = 0; i < num_line_chars && *text_buffer; i++) if ((line[i] = *text_buffer++) == '\n') break; line[i] = '\0'; /* prevent 'num_line_chars' sized lines to cause additional empty line */ if (i == num_line_chars && *text_buffer == '\n') text_buffer++; /* skip comments (lines directly beginning with '#') */ if (line[0] == '#' && parse_comments) { char *token, *value; /* try to read generic token/value pair definition after comment sign */ if (getCheckedTokenValueFromString(line + 1, &token, &value)) { /* if found, flush the current buffer, if non-empty */ if (buffer_len > 0 && current_ypos < max_ysize) { DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length, mask_mode, centered, current_ypos); current_ypos += line_height; current_line++; buffer[0] = '\0'; buffer_len = 0; } if (strEqual(token, ".font")) font_nr = gfx.get_font_from_token_function(value); else if (strEqual(token, ".autowrap")) autowrap = get_boolean_from_string(value); else if (strEqual(token, ".centered")) centered = get_boolean_from_string(value); else if (strEqual(token, ".parse_comments")) parse_comments = get_boolean_from_string(value); // if font has changed, depending values need to be updated as well font_height = getFontHeight(font_nr); line_height = font_height + line_spacing; } continue; } /* cut trailing newline and carriage return from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { if (*line_ptr == '\n' || *line_ptr == '\r') { *line_ptr = '\0'; break; } } if (strlen(line) == 0) /* special case: force empty line */ strcpy(line, "\n"); line_ptr = line; while (*line_ptr && current_ypos < max_ysize) { boolean buffer_filled; if (autowrap) { buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len, line_length, last_line_was_empty); } else { if (strlen(line_ptr) <= line_length) { buffer_len = strlen(line_ptr); strcpy(buffer, line_ptr); } else { buffer_len = line_length; strncpy(buffer, line_ptr, line_length); } buffer[buffer_len] = '\0'; line_ptr += buffer_len; buffer_filled = TRUE; } if (buffer_filled) { DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length, mask_mode, centered, current_ypos); current_ypos += line_height; current_line++; last_line_was_empty = (buffer_len == 0); buffer[0] = '\0'; buffer_len = 0; } } } if (buffer_len > 0 && current_ypos < max_ysize) { DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length, mask_mode, centered, current_ypos); current_ypos += line_height; current_line++; } return current_line; } int DrawTextBufferVA(int x, int y, char *format, va_list ap, int font_nr, int line_length, int cut_length, int max_lines, int line_spacing, int mask_mode, boolean autowrap, boolean centered, boolean parse_comments) { char text_buffer[MAX_OUTPUT_LINESIZE]; int text_length = vsnprintf(text_buffer, MAX_OUTPUT_LINESIZE, format, ap); if (text_length >= MAX_OUTPUT_LINESIZE) Error(ERR_WARN, "string too long in DrawTextBufferVA() -- truncated"); int num_lines_printed = DrawTextBuffer(x, y, text_buffer, font_nr, line_length, cut_length, max_lines, line_spacing, mask_mode, autowrap, centered, parse_comments); return num_lines_printed; } int DrawTextFile(int x, int y, char *filename, int font_nr, int line_length, int cut_length, int max_lines, int line_spacing, int mask_mode, boolean autowrap, boolean centered, boolean parse_comments) { char *text_buffer = GetTextBufferFromFile(filename, MAX_LINES_FROM_FILE); int num_lines_printed = DrawTextBuffer(x, y, text_buffer, font_nr, line_length, cut_length, max_lines, line_spacing, mask_mode, autowrap, centered, parse_comments); checked_free(text_buffer); return num_lines_printed; } mirrormagic-3.0.0/src/libgame/random.c0000644000175000017500000002402613263212010017140 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // random.c // ============================================================================ /* * 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 int randtbl_0[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, }; static int randtbl_1[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 int *fptr[2] = { &randtbl_0[SEP_3 + 1], &randtbl_1[SEP_3 + 1] }; static int *rptr[2] = { &randtbl_0[1], &randtbl_1[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 int *state[2] = { &randtbl_0[1], &randtbl_1[1] }; static int rand_type[2] = { TYPE_3, TYPE_3 }; static int rand_deg[2] = { DEG_3, DEG_3 }; static int rand_sep[2] = { SEP_3, SEP_3 }; static int *end_ptr[2] = { &randtbl_0[sizeof(randtbl_0) / sizeof(randtbl_0[0])], &randtbl_1[sizeof(randtbl_1) / sizeof(randtbl_1[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(int nr, unsigned int x) { state[nr][0] = x; if (rand_type[nr] != TYPE_0) { register int i; for (i = 1; i < rand_deg[nr]; ++i) state[nr][i] = (1103515145 * state[nr][i - 1]) + 12345; fptr[nr] = &state[nr][rand_sep[nr]]; rptr[nr] = &state[nr][0]; for (i = 0; i < 10 * rand_deg[nr]; ++i) random_linux_libc(nr); } } /* 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. */ int random_linux_libc(int nr) { if (rand_type[nr] == TYPE_0) { state[nr][0] = ((state[nr][0] * 1103515245) + 12345) & INT_MAX; return state[nr][0]; } else { int i; *fptr[nr] += *rptr[nr]; /* Chucking least random bit. */ i = (*fptr[nr] >> 1) & INT_MAX; fptr[nr]++; if (fptr[nr] >= end_ptr[nr]) { fptr[nr] = state[nr]; rptr[nr]++; } else { rptr[nr]++; if (rptr[nr] >= end_ptr[nr]) rptr[nr] = state[nr]; } return i; } } mirrormagic-3.0.0/src/libgame/text.h0000644000175000017500000000727213263212010016655 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // text.h // ============================================================================ #ifndef TEXT_H #define TEXT_H #include "system.h" /* default fonts */ #define FONT_INITIAL_1 0 #define FONT_INITIAL_2 1 #define FONT_INITIAL_3 2 #define FONT_INITIAL_4 3 /* font colors */ #define FC_RED FONT_INITIAL_1 #define FC_BLUE FONT_INITIAL_2 #define FC_GREEN FONT_INITIAL_3 #define FC_YELLOW FONT_INITIAL_4 /* text output definitions */ #define MAX_OUTPUT_LINESIZE 1024 /* special constants for old ISO-8859-1 character byte values */ #define CHAR_BYTE_UMLAUT_A ((char)0xc4) #define CHAR_BYTE_UMLAUT_O ((char)0xd6) #define CHAR_BYTE_UMLAUT_U ((char)0xdc) #define CHAR_BYTE_UMLAUT_a ((char)0xe4) #define CHAR_BYTE_UMLAUT_o ((char)0xf6) #define CHAR_BYTE_UMLAUT_u ((char)0xfc) #define CHAR_BYTE_SHARP_S ((char)0xdf) #define CHAR_BYTE_COPYRIGHT ((char)0xa9) #define CHAR_BYTE_REGISTERED ((char)0xae) #define CHAR_BYTE_DEGREE ((char)0xb0) #define CHAR_BYTE_CURSOR ((char)0xa0) /* special character mapping for default fonts */ #define FONT_ASCII_CURSOR ((char)160) #define FONT_ASCII_BUTTON ((char)128) #define FONT_ASCII_UP ((char)129) #define FONT_ASCII_DOWN ((char)130) #define FONT_ASCII_LEFT ((char)'<') #define FONT_ASCII_RIGHT ((char)'>') #define MAP_FONT_ASCII(c) ((c) >= 'a' && (c) <= 'z' ? 'A' + (c) - 'a' : \ (c) == CHAR_BYTE_COPYRIGHT ? 96 : \ (c) == CHAR_BYTE_UMLAUT_a ? 97 : \ (c) == CHAR_BYTE_UMLAUT_A ? 97 : \ (c) == CHAR_BYTE_UMLAUT_o ? 98 : \ (c) == CHAR_BYTE_UMLAUT_O ? 98 : \ (c) == CHAR_BYTE_UMLAUT_u ? 99 : \ (c) == CHAR_BYTE_UMLAUT_U ? 99 : \ (c) == CHAR_BYTE_DEGREE ? 100 : \ (c) == CHAR_BYTE_REGISTERED ? 101 : \ (c) == FONT_ASCII_CURSOR ? 102 : \ (c) == FONT_ASCII_BUTTON ? 109 : \ (c) == FONT_ASCII_UP ? 110 : \ (c) == FONT_ASCII_DOWN ? 111 : \ (c)) /* 64 regular ordered ASCII characters, 6 special characters, 1 cursor char. */ #define MIN_NUM_CHARS_PER_FONT 64 #define DEFAULT_NUM_CHARS_PER_FONT (MIN_NUM_CHARS_PER_FONT + 6 +1) #define DEFAULT_NUM_CHARS_PER_LINE 16 /* font structure definitions */ void InitFontInfo(struct FontBitmapInfo *, int, int (*function1)(int), int (*function2)(char *)); void FreeFontInfo(struct FontBitmapInfo *); struct FontBitmapInfo *getFontBitmapInfo(int); int getFontWidth(int); int getFontHeight(int); int getFontDrawOffsetX(int); int getFontDrawOffsetY(int); int getTextWidth(char *, int); void getFontCharSource(int, char, Bitmap **, int *, int *); int maxWordLengthInString(char *); void DrawInitText(char *, int, int); void DrawTextF(int, int, int, char *, ...); void DrawTextFCentered(int, int, char *, ...); void DrawTextS(int, int, int, char *); void DrawTextSCentered(int, int, char *); void DrawTextSAligned(int, int, char *, int, int); void DrawTextAligned(int, int, char *, int, int); void DrawText(int, int, char *, int); void DrawTextExt(DrawBuffer *, int, int, char *, int, int); char *GetTextBufferFromFile(char *, int); int DrawTextBuffer(int, int, char *, int, int, int, int, int, int, boolean, boolean, boolean); int DrawTextBufferVA(int, int, char *, va_list, int, int, int, int, int, int, boolean, boolean, boolean); int DrawTextFile(int, int, char *, int, int, int, int, int, int, boolean, boolean, boolean); #endif /* TEXT_H */ mirrormagic-3.0.0/src/libgame/macosx.h0000644000175000017500000000155413263212010017160 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // macosx.h // ============================================================================ #ifndef MACOSX_H #define MACOSX_H /* define some Mac OS X specific paths */ #define MAC_APP_BINARY_SUBDIR "Contents/MacOS" #define MAC_APP_FILES_SUBDIR "Contents/Resources" /* some symbols are already defined on Mac OS X */ #define Delay Delay_internal #define DrawLine DrawLine_internal #define DrawText DrawText_internal #define GetPixel GetPixel_internal #endif /* MACOSX_H */ mirrormagic-3.0.0/src/libgame/image.c0000644000175000017500000002572013263212010016744 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // image.c // ============================================================================ #include "image.h" #include "misc.h" #include "setup.h" struct ImageInfo { char *source_filename; int num_references; Bitmap *bitmaps[NUM_IMG_BITMAP_POINTERS]; int original_width; /* original image file width */ int original_height; /* original image file height */ boolean contains_small_images; /* set after adding small images */ boolean contains_textures; /* set after adding GPU textures */ boolean scaled_up; /* set after scaling up */ int conf_tile_size; /* tile size as defined in config */ int game_tile_size; /* tile size as resized for game */ char *leveldir; /* level set when image was loaded */ }; typedef struct ImageInfo ImageInfo; static struct ArtworkListInfo *image_info = NULL; static void *Load_Image(char *filename) { ImageInfo *img_info = checked_calloc(sizeof(ImageInfo)); if ((img_info->bitmaps[IMG_BITMAP_STANDARD] = LoadImage(filename)) == NULL) { Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s", filename, GetError()); free(img_info); return NULL; } img_info->source_filename = getStringCopy(filename); img_info->original_width = img_info->bitmaps[IMG_BITMAP_STANDARD]->width; img_info->original_height = img_info->bitmaps[IMG_BITMAP_STANDARD]->height; img_info->contains_small_images = FALSE; img_info->contains_textures = FALSE; img_info->scaled_up = FALSE; img_info->conf_tile_size = 0; // will be set later img_info->game_tile_size = 0; // will be set later img_info->leveldir = NULL; // will be set later return img_info; } static void FreeImage(void *ptr) { ImageInfo *image = (ImageInfo *)ptr; int i; if (image == NULL) return; for (i = 0; i < NUM_IMG_BITMAPS; i++) if (image->bitmaps[i]) FreeBitmap(image->bitmaps[i]); if (image->source_filename) free(image->source_filename); free(image); } int getImageListSize() { return (image_info->num_file_list_entries + image_info->num_dynamic_file_list_entries); } struct FileInfo *getImageListEntryFromImageID(int pos) { int num_list_entries = image_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); return (pos < num_list_entries ? &image_info->file_list[list_pos] : &image_info->dynamic_file_list[list_pos]); } static ImageInfo *getImageInfoEntryFromImageID(int pos) { int num_list_entries = image_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); ImageInfo **img_info = (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list : image_info->dynamic_artwork_list); return img_info[list_pos]; } Bitmap **getBitmapsFromImageID(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); return (img_info != NULL ? img_info->bitmaps : NULL); } int getOriginalImageWidthFromImageID(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); return (img_info != NULL ? img_info->original_width : 0); } int getOriginalImageHeightFromImageID(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); return (img_info != NULL ? img_info->original_height : 0); } char *getTokenFromImageID(int graphic) { struct FileInfo *file_list = getImageListEntryFromImageID(graphic); return (file_list != NULL ? file_list->token : NULL); } char *getFilenameFromImageID(int graphic) { struct FileInfo *file_list = getImageListEntryFromImageID(graphic); return (file_list != NULL ? file_list->filename : NULL); } int getImageIDFromToken(char *token) { struct FileInfo *file_list = image_info->file_list; int num_list_entries = image_info->num_file_list_entries; int i; for (i = 0; i < num_list_entries; i++) if (strEqual(file_list[i].token, token)) return i; return -1; } char *getImageConfigFilename() { return getCustomArtworkConfigFilename(image_info->type); } int getImageListPropertyMappingSize() { return image_info->num_property_mapping_entries; } struct PropertyMapping *getImageListPropertyMapping() { return image_info->property_mapping; } void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigTypeInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, char **ext2_suffixes, char **ext3_suffixes, char **ignore_tokens) { int i; image_info = checked_calloc(sizeof(struct ArtworkListInfo)); image_info->type = ARTWORK_TYPE_GRAPHICS; /* ---------- initialize file list and suffix lists ---------- */ image_info->num_file_list_entries = num_file_list_entries; image_info->num_dynamic_file_list_entries = 0; image_info->file_list = getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); image_info->dynamic_file_list = NULL; image_info->num_suffix_list_entries = 0; for (i = 0; config_suffix_list[i].token != NULL; i++) image_info->num_suffix_list_entries++; image_info->suffix_list = config_suffix_list; /* ---------- initialize base prefix and suffixes lists ---------- */ image_info->num_base_prefixes = 0; for (i = 0; base_prefixes[i] != NULL; i++) image_info->num_base_prefixes++; image_info->num_ext1_suffixes = 0; for (i = 0; ext1_suffixes[i] != NULL; i++) image_info->num_ext1_suffixes++; image_info->num_ext2_suffixes = 0; for (i = 0; ext2_suffixes[i] != NULL; i++) image_info->num_ext2_suffixes++; image_info->num_ext3_suffixes = 0; for (i = 0; ext3_suffixes[i] != NULL; i++) image_info->num_ext3_suffixes++; image_info->num_ignore_tokens = 0; for (i = 0; ignore_tokens[i] != NULL; i++) image_info->num_ignore_tokens++; image_info->base_prefixes = base_prefixes; image_info->ext1_suffixes = ext1_suffixes; image_info->ext2_suffixes = ext2_suffixes; image_info->ext3_suffixes = ext3_suffixes; image_info->ignore_tokens = ignore_tokens; image_info->num_property_mapping_entries = 0; image_info->property_mapping = NULL; /* ---------- initialize artwork reference and content lists ---------- */ image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *); image_info->artwork_list = checked_calloc(num_file_list_entries * sizeof(ImageInfo *)); image_info->dynamic_artwork_list = NULL; image_info->content_list = NULL; /* ---------- initialize artwork loading/freeing functions ---------- */ image_info->load_artwork = Load_Image; image_info->free_artwork = FreeImage; } void ReloadCustomImages() { print_timestamp_init("ReloadCustomImages"); LoadArtworkConfig(image_info); print_timestamp_time("LoadArtworkConfig"); ReloadCustomArtworkList(image_info); print_timestamp_time("ReloadCustomArtworkList"); print_timestamp_done("ReloadCustomImages"); } static boolean CheckIfImageContainsSmallImages(ImageInfo *img_info, int tile_size) { if (!img_info->contains_small_images) return FALSE; // at this point, small images already exist for this image; // now do some checks that may require re-creating small (or in-game) images // special case 1: // // check if the configured tile size for an already loaded image has changed // from one level set to another; this should usually not happen, but if a // custom artwork set redefines classic (or default) graphics with wrong tile // size (by mistake or by intention), it will be corrected to its original // tile size here by forcing complete re-creation of all small images again if (!strEqual(img_info->leveldir, leveldir_current->identifier) && img_info->conf_tile_size != tile_size) { int bitmap_nr = GET_BITMAP_ID_FROM_TILESIZE(img_info->conf_tile_size); int i; // free all calculated, resized bitmaps, but keep last configured size for (i = 0; i < NUM_IMG_BITMAPS; i++) { if (i == bitmap_nr) continue; if (img_info->bitmaps[i]) { FreeBitmap(img_info->bitmaps[i]); img_info->bitmaps[i] = NULL; } } // re-create small bitmaps from last configured size as new default size if (bitmap_nr != IMG_BITMAP_STANDARD) { img_info->bitmaps[IMG_BITMAP_STANDARD] = img_info->bitmaps[bitmap_nr]; img_info->bitmaps[bitmap_nr] = NULL; } img_info->contains_small_images = FALSE; return FALSE; } // special case 1 (continued): // // if different tile sizes are used in same image file (usually by mistake, // like forgetting option ".tile_size" for one or more graphic definitions), // make sure to use only the first tile size that is processed for this image // (and ignore all subsequent, potentially different tile size definitions // for this image within the current level set by disabling the above check) setString(&img_info->leveldir, leveldir_current->identifier); // special case 2: // // graphic config setting "game.tile_size" has changed since last level set; // this may require resizing image to new size required for in-game graphics if (img_info->game_tile_size != gfx.game_tile_size) { ReCreateGameTileSizeBitmap(img_info->bitmaps); img_info->game_tile_size = gfx.game_tile_size; } return TRUE; } void CreateImageWithSmallImages(int pos, int zoom_factor, int tile_size) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); if (img_info == NULL) return; if (CheckIfImageContainsSmallImages(img_info, tile_size)) return; CreateBitmapWithSmallBitmaps(img_info->bitmaps, zoom_factor, tile_size); img_info->contains_small_images = TRUE; img_info->scaled_up = TRUE; // scaling was also done here img_info->conf_tile_size = tile_size; img_info->game_tile_size = gfx.game_tile_size; setString(&img_info->leveldir, leveldir_current->identifier); } void CreateImageTextures(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); if (img_info == NULL || img_info->contains_textures) return; CreateBitmapTextures(img_info->bitmaps); img_info->contains_textures = TRUE; } void FreeImageTextures(int pos) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); if (img_info == NULL || !img_info->contains_textures) return; FreeBitmapTextures(img_info->bitmaps); img_info->contains_textures = FALSE; } void FreeAllImageTextures() { int num_images = getImageListSize(); int i; for (i = 0; i < num_images; i++) FreeImageTextures(i); } void ScaleImage(int pos, int zoom_factor) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); if (img_info == NULL || img_info->scaled_up) return; if (zoom_factor != 1) ScaleBitmap(img_info->bitmaps, zoom_factor); img_info->scaled_up = TRUE; } void FreeAllImages() { FreeCustomArtworkLists(image_info); } mirrormagic-3.0.0/src/libgame/sound.h0000644000175000017500000001042013263212010017006 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // sound.h // ============================================================================ #ifndef SOUND_H #define SOUND_H #include "system.h" /* values for platform specific sound initialization */ #define AUDIO_SAMPLE_RATE_22050 22050 #define AUDIO_FRAGMENT_SIZE_512 512 #define AUDIO_FRAGMENT_SIZE_1024 1024 #define AUDIO_FRAGMENT_SIZE_2048 2048 #define AUDIO_FRAGMENT_SIZE_4096 4096 #define AUDIO_FRAGMENT_SIZE_32768 32768 #define AUDIO_NUM_CHANNELS_MONO 1 #define AUDIO_NUM_CHANNELS_STEREO 2 #define AUDIO_FORMAT_UNKNOWN (0) #define AUDIO_FORMAT_U8 (1 << 0) #define AUDIO_FORMAT_S16 (1 << 1) #define AUDIO_FORMAT_LE (1 << 2) #define AUDIO_FORMAT_BE (1 << 3) #define DEFAULT_AUDIO_SAMPLE_RATE AUDIO_SAMPLE_RATE_22050 #if defined(PLATFORM_WIN32) #define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_1024 #else #define DEFAULT_AUDIO_FRAGMENT_SIZE AUDIO_FRAGMENT_SIZE_512 #endif #define NUM_MIXER_CHANNELS MIX_CHANNELS #define MUSIC_CHANNEL 0 #define FIRST_SOUND_CHANNEL 1 /* values for PlaySound(), StopSound() and friends */ #define SND_CTRL_NONE (0) #define SND_CTRL_MUSIC (1 << 0) #define SND_CTRL_LOOP (1 << 1) #define SND_CTRL_FADE (1 << 2) #define SND_CTRL_STOP (1 << 3) #define SND_CTRL_ALL_SOUNDS (1 << 4) #define SND_CTRL_RELOAD_SOUNDS (1 << 5) #define SND_CTRL_RELOAD_MUSIC (1 << 6) #define SND_CTRL_EXPIRE_LOOPS (1 << 7) #define SND_CTRL_PLAY_SOUND (SND_CTRL_NONE) #define SND_CTRL_PLAY_LOOP (SND_CTRL_LOOP) #define SND_CTRL_PLAY_MUSIC (SND_CTRL_LOOP | SND_CTRL_MUSIC) #define SND_CTRL_FADE_SOUND (SND_CTRL_FADE) #define SND_CTRL_FADE_MUSIC (SND_CTRL_FADE | SND_CTRL_MUSIC) #define SND_CTRL_FADE_ALL (SND_CTRL_FADE | SND_CTRL_ALL_SOUNDS) #define SND_CTRL_STOP_SOUND (SND_CTRL_STOP) #define SND_CTRL_STOP_MUSIC (SND_CTRL_STOP | SND_CTRL_MUSIC) #define SND_CTRL_STOP_ALL (SND_CTRL_STOP | SND_CTRL_ALL_SOUNDS) #define IS_MUSIC(x) ((x).state & SND_CTRL_MUSIC) #define IS_LOOP(x) ((x).state & SND_CTRL_LOOP) #define IS_FADING(x) ((x).state & SND_CTRL_FADE) #define IS_STOPPING(x) ((x).state & SND_CTRL_STOP) #define IS_RELOADING(x) ((x).state & (SND_CTRL_RELOAD_SOUNDS |\ SND_CTRL_RELOAD_MUSIC)) #define ALL_SOUNDS(x) ((x).state & SND_CTRL_ALL_SOUNDS) #define SET_EXPIRE_LOOPS(x) ((x).state & SND_CTRL_EXPIRE_LOOPS) #define MAP_NOCONF_MUSIC(x) (-((x) + 1)) #define UNMAP_NOCONF_MUSIC(x) MAP_NOCONF_MUSIC(x) #define SOUND_MIN_VOLUME 0 #define SOUND_MAX_VOLUME SDL_MIX_MAXVOLUME #define SOUND_MAX_LEFT 0 #define SOUND_MAX_RIGHT 255 #define SOUND_MAX_LEFT2RIGHT 255 #define SOUND_MIDDLE (SOUND_MAX_LEFT2RIGHT / 2) /* general sound functions */ void UnixOpenAudio(void); void UnixCloseAudio(void); /* mixer functions */ void Mixer_InitChannels(void); void StartMixer(void); /* sound client functions */ void PlayMusic(int); void PlaySound(int); void PlaySoundStereo(int, int); void PlaySoundLoop(int); void PlaySoundMusic(int); void PlaySoundExt(int, int, int, int); void FadeMusic(void); void FadeSound(int); void FadeSounds(void); void FadeSoundsAndMusic(void); void StopMusic(void); void StopSound(int); void StopSounds(void); void StopSoundExt(int, int); void ExpireSoundLoops(boolean); int getSoundListSize(); int getMusicListSize(); struct FileInfo *getSoundListEntry(int); struct FileInfo *getMusicListEntry(int); char *getMusicInfoEntryFilename(int); char *getCurrentlyPlayingMusicFilename(); int getSoundListPropertyMappingSize(); int getMusicListPropertyMappingSize(); struct PropertyMapping *getSoundListPropertyMapping(); struct PropertyMapping *getMusicListPropertyMapping(); void InitSoundList(struct ConfigInfo *, int, struct ConfigTypeInfo *, char **, char **, char **, char **, char **); void InitMusicList(struct ConfigInfo *, int, struct ConfigTypeInfo *, char **, char **, char **, char **, char **); void InitReloadCustomSounds(char *); void InitReloadCustomMusic(char *); void FreeAllSounds(void); void FreeAllMusic(void); #endif mirrormagic-3.0.0/src/libgame/sound.c0000644000175000017500000007114113263212010017010 0ustar aeglosaeglos// ============================================================================ // Artsoft Retro-Game Library // ---------------------------------------------------------------------------- // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org // http://www.artsoft.org/ // ---------------------------------------------------------------------------- // sound.c // ============================================================================ #include #include #include #include #include #include #include #include #include #include "platform.h" #include "system.h" #include "sound.h" #include "misc.h" #include "setup.h" #include "text.h" /* expiration time (in milliseconds) for sound loops */ #define SOUND_LOOP_EXPIRATION_TIME 200 /* one second fading interval == 1000 ticks (milliseconds) */ #define SOUND_FADING_INTERVAL 1000 #define SND_TYPE_NONE 0 #define SND_TYPE_WAV 1 #define MUS_TYPE_NONE 0 #define MUS_TYPE_WAV 1 #define MUS_TYPE_MOD 2 #define DEVICENAME_DSP "/dev/dsp" #define DEVICENAME_SOUND_DSP "/dev/sound/dsp" #define DEVICENAME_AUDIO "/dev/audio" #define DEVICENAME_AUDIOCTL "/dev/audioCtl" #define SOUND_VOLUME_LEFT(x) (stereo_volume[x]) #define SOUND_VOLUME_RIGHT(x) (stereo_volume[SOUND_MAX_LEFT2RIGHT-x]) #define SAME_SOUND_NR(x,y) ((x).nr == (y).nr) #define SAME_SOUND_DATA(x,y) ((x).data_ptr == (y).data_ptr) #define SOUND_VOLUME_FROM_PERCENT(v,p) ((p) < 0 ? SOUND_MIN_VOLUME : \ (p) > 100 ? (v) : \ (p) * (v) / 100) #define SOUND_VOLUME_SIMPLE(v) SOUND_VOLUME_FROM_PERCENT(v, setup.volume_simple) #define SOUND_VOLUME_LOOPS(v) SOUND_VOLUME_FROM_PERCENT(v, setup.volume_loops) #define SOUND_VOLUME_MUSIC(v) SOUND_VOLUME_FROM_PERCENT(v, setup.volume_music) #define SETUP_SOUND_VOLUME(v,s) ((s) == SND_CTRL_PLAY_MUSIC ? \ SOUND_VOLUME_MUSIC(v) : \ (s) == SND_CTRL_PLAY_LOOP ? \ SOUND_VOLUME_LOOPS(v) : \ SOUND_VOLUME_SIMPLE(v)) struct AudioFormatInfo { boolean stereo; /* availability of stereo sound */ int format; /* size and endianess of sample data */ int sample_rate; /* sample frequency */ int fragment_size; /* audio device fragment size in bytes */ }; struct SampleInfo { char *source_filename; int num_references; int type; int format; void *data_ptr; /* pointer to first sample (8 or 16 bit) */ int data_len; /* number of samples, NOT number of bytes */ int num_channels; /* mono: 1 channel, stereo: 2 channels */ }; typedef struct SampleInfo SoundInfo; typedef struct SampleInfo MusicInfo; struct SoundControl { boolean active; int nr; int volume; int stereo_position; int state; unsigned int playing_starttime; unsigned int playing_pos; int type; int format; void *data_ptr; /* pointer to first sample (8 or 16 bit) */ int data_len; /* number of samples, NOT number of bytes */ int num_channels; /* mono: 1 channel, stereo: 2 channels */ }; typedef struct SoundControl SoundControl; static struct ArtworkListInfo *sound_info = NULL; static struct ArtworkListInfo *music_info = NULL; static MusicInfo **Music_NoConf = NULL; static int num_music_noconf = 0; static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1]; static char *currently_playing_music_filename = NULL; /* ========================================================================= */ /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ static struct SoundControl mixer[NUM_MIXER_CHANNELS]; static int mixer_active_channels = 0; static boolean expire_loop_sounds = FALSE; static void ReloadCustomSounds(); static void ReloadCustomMusic(); static void FreeSound(void *); static void FreeMusic(void *); static void FreeAllMusic_NoConf(); static SoundInfo *getSoundInfoEntryFromSoundID(int); static MusicInfo *getMusicInfoEntryFromMusicID(int); /* ------------------------------------------------------------------------- */ /* mixer functions */ /* ------------------------------------------------------------------------- */ void Mixer_InitChannels() { int i; for (i = 0; i < audio.num_channels; i++) mixer[i].active = FALSE; mixer_active_channels = 0; } static void Mixer_ResetChannelExpiration(int channel) { mixer[channel].playing_starttime = Counter(); if (expire_loop_sounds && IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel])) Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME); } static boolean Mixer_ChannelExpired(int channel) { if (!mixer[channel].active) return TRUE; if (expire_loop_sounds && IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) && DelayReached(&mixer[channel].playing_starttime, SOUND_LOOP_EXPIRATION_TIME)) return TRUE; if (!Mix_Playing(channel)) return TRUE; return FALSE; } static boolean Mixer_AllocateChannel(int channel) { return TRUE; } static void Mixer_SetChannelProperties(int channel) { Mix_Volume(channel, mixer[channel].volume); Mix_SetPanning(channel, SOUND_VOLUME_LEFT(mixer[channel].stereo_position), SOUND_VOLUME_RIGHT(mixer[channel].stereo_position)); } static void Mixer_StartChannel(int channel) { Mix_PlayChannel(channel, mixer[channel].data_ptr, IS_LOOP(mixer[channel]) ? -1 : 0); } static void Mixer_PlayChannel(int channel) { /* start with inactive channel in case something goes wrong */ mixer[channel].active = FALSE; if (mixer[channel].type != MUS_TYPE_WAV) return; if (!Mixer_AllocateChannel(channel)) return; Mixer_SetChannelProperties(channel); Mixer_StartChannel(channel); Mixer_ResetChannelExpiration(channel); mixer[channel].playing_pos = 0; mixer[channel].active = TRUE; mixer_active_channels++; } static void Mixer_PlayMusicChannel() { Mixer_PlayChannel(audio.music_channel); if (mixer[audio.music_channel].type != MUS_TYPE_WAV) { // use short fade-in to prevent "plop" sound for certain music files // (this may happen when switching on music while playing the game) Mix_VolumeMusic(mixer[audio.music_channel].volume); Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, -1, 100); #if defined(PLATFORM_WIN32) // playing MIDI music is broken since Windows Vista, as it sets the volume // for MIDI music also for all other sounds and music, which cannot be set // back to normal unless playing MIDI music again with that desired volume // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253) // => workaround: always play MIDI music with maximum volume if (Mix_GetMusicType(NULL) == MUS_MID) Mix_VolumeMusic(SOUND_MAX_VOLUME); #endif } } static void Mixer_StopChannel(int channel) { if (!mixer[channel].active) return; Mix_HaltChannel(channel); mixer[channel].active = FALSE; mixer_active_channels--; } static void Mixer_StopMusicChannel() { Mixer_StopChannel(audio.music_channel); Mix_HaltMusic(); setString(¤tly_playing_music_filename, NULL); } static void Mixer_FadeChannel(int channel) { if (!mixer[channel].active) return; mixer[channel].state |= SND_CTRL_FADE; Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL); } static void Mixer_FadeMusicChannel() { Mixer_FadeChannel(audio.music_channel); Mix_FadeOutMusic(SOUND_FADING_INTERVAL); #if defined(PLATFORM_WIN32) // playing MIDI music is broken since Windows Vista, as it sets the volume // for MIDI music also for all other sounds and music, which cannot be set // back to normal unless playing MIDI music again with that desired volume // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253) // => workaround: never fade MIDI music to lower volume, but just stop it if (Mix_GetMusicType(NULL) == MUS_MID) Mixer_StopMusicChannel(); #endif setString(¤tly_playing_music_filename, NULL); } static void Mixer_UnFadeChannel(int channel) { if (!mixer[channel].active || !IS_FADING(mixer[channel])) return; mixer[channel].state &= ~SND_CTRL_FADE; mixer[channel].volume = SOUND_MAX_VOLUME; Mix_ExpireChannel(channel, -1); Mix_Volume(channel, mixer[channel].volume); } static void Mixer_InsertSound(SoundControl snd_ctrl) { SoundInfo *snd_info; int i, k; if (IS_MUSIC(snd_ctrl)) snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr); else snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr); if (snd_info == NULL) return; /* copy sound sample and format information */ snd_ctrl.type = snd_info->type; snd_ctrl.format = snd_info->format; snd_ctrl.data_ptr = snd_info->data_ptr; snd_ctrl.data_len = snd_info->data_len; snd_ctrl.num_channels = snd_info->num_channels; /* play music samples on a dedicated music channel */ if (IS_MUSIC(snd_ctrl)) { Mixer_StopMusicChannel(); mixer[audio.music_channel] = snd_ctrl; Mixer_PlayMusicChannel(); setString(¤tly_playing_music_filename, getBaseNamePtr(snd_info->source_filename)); return; } /* check if (and how often) this sound sample is already playing */ for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++) if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl)) k++; /* reset expiration delay for already playing loop sounds */ if (k > 0 && IS_LOOP(snd_ctrl)) { for (i = audio.first_sound_channel; i < audio.num_channels; i++) { if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl)) { if (IS_FADING(mixer[i])) Mixer_UnFadeChannel(i); /* restore settings like volume and stereo position */ mixer[i].volume = snd_ctrl.volume; mixer[i].stereo_position = snd_ctrl.stereo_position; Mixer_SetChannelProperties(i); Mixer_ResetChannelExpiration(i); } } return; } /* don't play sound more than n times simultaneously (with n == 2 for now) */ if (k >= 2) { unsigned int playing_current = Counter(); int longest = 0, longest_nr = audio.first_sound_channel; /* look for oldest equal sound */ for (i = audio.first_sound_channel; i < audio.num_channels; i++) { int playing_time = playing_current - mixer[i].playing_starttime; int actual; if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl)) continue; actual = 1000 * playing_time / mixer[i].data_len; if (actual >= longest) { longest = actual; longest_nr = i; } } Mixer_StopChannel(longest_nr); } /* If all (non-music) channels are active, stop the channel that has played its sound sample most completely (in percent of the sample length). As we cannot currently get the actual playing position of the channel's sound sample when compiling with the SDL mixer library, we use the current playing time (in milliseconds) instead. */ #if DEBUG /* channel allocation sanity check -- should not be needed */ if (mixer_active_channels == audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1)) { for (i = audio.first_sound_channel; i < audio.num_channels; i++) { if (!mixer[i].active) { Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i); Error(ERR_INFO, "Mixer_InsertSound: This should never happen!"); mixer_active_channels--; } } } #endif if (mixer_active_channels == audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1)) { unsigned int playing_current = Counter(); int longest = 0, longest_nr = audio.first_sound_channel; for (i = audio.first_sound_channel; i < audio.num_channels; i++) { int playing_time = playing_current - mixer[i].playing_starttime; int actual = 1000 * playing_time / mixer[i].data_len; if (!IS_LOOP(mixer[i]) && actual > longest) { longest = actual; longest_nr = i; } } Mixer_StopChannel(longest_nr); } /* add the new sound to the mixer */ for (i = audio.first_sound_channel; i < audio.num_channels; i++) { if (!mixer[i].active) { mixer[i] = snd_ctrl; Mixer_PlayChannel(i); break; } } } static void HandleSoundRequest(SoundControl snd_ctrl) { int i; /* deactivate channels that have expired since the last request */ for (i = 0; i < audio.num_channels; i++) if (mixer[i].active && Mixer_ChannelExpired(i)) Mixer_StopChannel(i); if (IS_RELOADING(snd_ctrl)) /* load new sound or music files */ { Mixer_StopMusicChannel(); for (i = audio.first_sound_channel; i < audio.num_channels; i++) Mixer_StopChannel(i); if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS) ReloadCustomSounds(); else ReloadCustomMusic(); } else if (IS_FADING(snd_ctrl)) /* fade out existing sound or music */ { if (IS_MUSIC(snd_ctrl)) { Mixer_FadeMusicChannel(); return; } for (i = audio.first_sound_channel; i < audio.num_channels; i++) if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl)) Mixer_FadeChannel(i); } else if (IS_STOPPING(snd_ctrl)) /* stop existing sound or music */ { if (IS_MUSIC(snd_ctrl)) { Mixer_StopMusicChannel(); return; } for (i = audio.first_sound_channel; i < audio.num_channels; i++) if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl)) Mixer_StopChannel(i); } else if (SET_EXPIRE_LOOPS(snd_ctrl)) /* set loop expiration on or off */ { expire_loop_sounds = snd_ctrl.active; } else if (snd_ctrl.active) /* add new sound to mixer */ { Mixer_InsertSound(snd_ctrl); } } void StartMixer(void) { int i; if (!audio.sound_available) return; /* initialize stereo position conversion information */ for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++) stereo_volume[i] = (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i)); } /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ /* ========================================================================= */ /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */ #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define WAV_HEADER_SIZE 16 /* size of WAV file header */ static void *Load_WAV(char *filename) { SoundInfo *snd_info; if (!audio.sound_available) return NULL; snd_info = checked_calloc(sizeof(SoundInfo)); if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL) { Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError()); free(snd_info); return NULL; } snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen; snd_info->type = SND_TYPE_WAV; snd_info->source_filename = getStringCopy(filename); return snd_info; } static void *Load_MOD(char *filename) { MusicInfo *mod_info; if (!audio.sound_available) return NULL; mod_info = checked_calloc(sizeof(MusicInfo)); if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL) { Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError()); free(mod_info); return NULL; } mod_info->type = MUS_TYPE_MOD; mod_info->source_filename = getStringCopy(filename); return mod_info; } static void *Load_WAV_or_MOD(char *filename) { if (FileIsMusic(filename)) return Load_MOD(filename); else if (FileIsSound(filename)) return Load_WAV(filename); else return NULL; } void LoadCustomMusic_NoConf(void) { static boolean draw_init_text = TRUE; /* only draw at startup */ static char *last_music_directory = NULL; char *music_directory = getCustomMusicDirectory(); Directory *dir; DirectoryEntry *dir_entry; int num_music = getMusicListSize(); if (!audio.sound_available) return; if (last_music_directory != NULL && strEqual(last_music_directory, music_directory)) return; /* old and new music directory are the same */ if (last_music_directory != NULL) free(last_music_directory); last_music_directory = getStringCopy(music_directory); FreeAllMusic_NoConf(); if ((dir = openDirectory(music_directory)) == NULL) { Error(ERR_WARN, "cannot read music directory '%s'", music_directory); audio.music_available = FALSE; return; } if (draw_init_text) DrawInitText("Loading music", 120, FC_GREEN); while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ { char *basename = dir_entry->basename; MusicInfo *mus_info = NULL; boolean music_already_used = FALSE; int i; /* skip all music files that are configured in music config file */ for (i = 0; i < num_music; i++) { struct FileInfo *music = getMusicListEntry(i); if (strEqual(basename, music->filename)) { music_already_used = TRUE; break; } } if (music_already_used) continue; if (draw_init_text) DrawInitText(basename, 150, FC_YELLOW); if (FileIsMusic(dir_entry->filename)) mus_info = Load_WAV_or_MOD(dir_entry->filename); if (mus_info) { num_music_noconf++; Music_NoConf = checked_realloc(Music_NoConf, num_music_noconf * sizeof(MusicInfo *)); Music_NoConf[num_music_noconf - 1] = mus_info; } } closeDirectory(dir); draw_init_text = FALSE; } int getSoundListSize() { return (sound_info->num_file_list_entries + sound_info->num_dynamic_file_list_entries); } int getMusicListSize() { return (music_info->num_file_list_entries + music_info->num_dynamic_file_list_entries); } struct FileInfo *getSoundListEntry(int pos) { int num_sounds = getSoundListSize(); int num_list_entries = sound_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); if (pos < 0 || pos >= num_sounds) /* invalid sound */ return NULL; return (pos < num_list_entries ? &sound_info->file_list[list_pos] : &sound_info->dynamic_file_list[list_pos]); } struct FileInfo *getMusicListEntry(int pos) { int num_music = getMusicListSize(); int num_list_entries = music_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); if (pos < 0 || pos >= num_music) /* invalid music */ return NULL; return (pos < num_list_entries ? &music_info->file_list[list_pos] : &music_info->dynamic_file_list[list_pos]); } static SoundInfo *getSoundInfoEntryFromSoundID(int pos) { int num_sounds = getSoundListSize(); int num_list_entries = sound_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); SoundInfo **snd_info = (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list : sound_info->dynamic_artwork_list); if (pos < 0 || pos >= num_sounds) /* invalid sound */ return NULL; return snd_info[list_pos]; } static MusicInfo *getMusicInfoEntryFromMusicID(int pos) { int num_music = getMusicListSize(); int num_list_entries = music_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); MusicInfo **mus_info = (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list : music_info->dynamic_artwork_list); if (pos >= num_music) /* invalid music */ return NULL; if (pos < 0) /* undefined music */ { if (num_music_noconf == 0) /* no fallback music available */ return NULL; pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf; return Music_NoConf[pos]; } return mus_info[list_pos]; } char *getMusicInfoEntryFilename(int pos) { MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos); if (mus_info == NULL) return NULL; return getBaseNamePtr(mus_info->source_filename); } char *getCurrentlyPlayingMusicFilename() { return currently_playing_music_filename; } int getSoundListPropertyMappingSize() { return sound_info->num_property_mapping_entries; } int getMusicListPropertyMappingSize() { return music_info->num_property_mapping_entries; } struct PropertyMapping *getSoundListPropertyMapping() { return sound_info->property_mapping; } struct PropertyMapping *getMusicListPropertyMapping() { return music_info->property_mapping; } void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigTypeInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, char **ext2_suffixes, char **ext3_suffixes, char **ignore_tokens) { int i; sound_info = checked_calloc(sizeof(struct ArtworkListInfo)); sound_info->type = ARTWORK_TYPE_SOUNDS; /* ---------- initialize file list and suffix lists ---------- */ sound_info->num_file_list_entries = num_file_list_entries; sound_info->num_dynamic_file_list_entries = 0; sound_info->file_list = getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); sound_info->dynamic_file_list = NULL; sound_info->num_suffix_list_entries = 0; for (i = 0; config_suffix_list[i].token != NULL; i++) sound_info->num_suffix_list_entries++; sound_info->suffix_list = config_suffix_list; /* ---------- initialize base prefix and suffixes lists ---------- */ sound_info->num_base_prefixes = 0; for (i = 0; base_prefixes[i] != NULL; i++) sound_info->num_base_prefixes++; sound_info->num_ext1_suffixes = 0; for (i = 0; ext1_suffixes[i] != NULL; i++) sound_info->num_ext1_suffixes++; sound_info->num_ext2_suffixes = 0; for (i = 0; ext2_suffixes[i] != NULL; i++) sound_info->num_ext2_suffixes++; sound_info->num_ext3_suffixes = 0; for (i = 0; ext3_suffixes[i] != NULL; i++) sound_info->num_ext3_suffixes++; sound_info->num_ignore_tokens = 0; for (i = 0; ignore_tokens[i] != NULL; i++) sound_info->num_ignore_tokens++; sound_info->base_prefixes = base_prefixes; sound_info->ext1_suffixes = ext1_suffixes; sound_info->ext2_suffixes = ext2_suffixes; sound_info->ext3_suffixes = ext3_suffixes; sound_info->ignore_tokens = ignore_tokens; sound_info->num_property_mapping_entries = 0; sound_info->property_mapping = NULL; /* ---------- initialize artwork reference and content lists ---------- */ sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *); sound_info->artwork_list = checked_calloc(num_file_list_entries * sizeof(SoundInfo *)); sound_info->dynamic_artwork_list = NULL; sound_info->content_list = NULL; /* ---------- initialize artwork loading/freeing functions ---------- */ sound_info->load_artwork = Load_WAV; sound_info->free_artwork = FreeSound; } void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigTypeInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, char **ext2_suffixes, char **ext3_suffixes, char **ignore_tokens) { int i; music_info = checked_calloc(sizeof(struct ArtworkListInfo)); music_info->type = ARTWORK_TYPE_MUSIC; /* ---------- initialize file list and suffix lists ---------- */ music_info->num_file_list_entries = num_file_list_entries; music_info->num_dynamic_file_list_entries = 0; music_info->file_list = getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); music_info->dynamic_file_list = NULL; music_info->num_suffix_list_entries = 0; for (i = 0; config_suffix_list[i].token != NULL; i++) music_info->num_suffix_list_entries++; music_info->suffix_list = config_suffix_list; /* ---------- initialize base prefix and suffixes lists ---------- */ music_info->num_base_prefixes = 0; for (i = 0; base_prefixes[i] != NULL; i++) music_info->num_base_prefixes++; music_info->num_ext1_suffixes = 0; for (i = 0; ext1_suffixes[i] != NULL; i++) music_info->num_ext1_suffixes++; music_info->num_ext2_suffixes = 0; for (i = 0; ext2_suffixes[i] != NULL; i++) music_info->num_ext2_suffixes++; music_info->num_ext3_suffixes = 0; for (i = 0; ext3_suffixes[i] != NULL; i++) music_info->num_ext3_suffixes++; music_info->num_ignore_tokens = 0; for (i = 0; ignore_tokens[i] != NULL; i++) music_info->num_ignore_tokens++; music_info->base_prefixes = base_prefixes; music_info->ext1_suffixes = ext1_suffixes; music_info->ext2_suffixes = ext2_suffixes; music_info->ext3_suffixes = ext3_suffixes; music_info->ignore_tokens = ignore_tokens; music_info->num_property_mapping_entries = 0; music_info->property_mapping = NULL; /* ---------- initialize artwork reference and content lists ---------- */ music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *); music_info->artwork_list = checked_calloc(num_file_list_entries * sizeof(MusicInfo *)); music_info->dynamic_artwork_list = NULL; music_info->content_list = NULL; /* ---------- initialize artwork loading/freeing functions ---------- */ music_info->load_artwork = Load_WAV_or_MOD; music_info->free_artwork = FreeMusic; } void PlayMusic(int nr) { if (!audio.music_available) return; PlaySoundMusic(nr); } void PlaySound(int nr) { if (!setup.sound_simple) return; PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND); } void PlaySoundStereo(int nr, int stereo_position) { if (!setup.sound_simple) return; PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND); } void PlaySoundLoop(int nr) { if (!setup.sound_loops) return; PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP); } void PlaySoundMusic(int nr) { if (!setup.sound_music) return; PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC); } void PlaySoundExt(int nr, int volume, int stereo_position, int state) { SoundControl snd_ctrl; if (!audio.sound_available || !audio.sound_enabled || audio.sound_deactivated) return; volume = SETUP_SOUND_VOLUME(volume, state); if (volume < SOUND_MIN_VOLUME) volume = SOUND_MIN_VOLUME; else if (volume > SOUND_MAX_VOLUME) volume = SOUND_MAX_VOLUME; if (stereo_position < SOUND_MAX_LEFT) stereo_position = SOUND_MAX_LEFT; else if (stereo_position > SOUND_MAX_RIGHT) stereo_position = SOUND_MAX_RIGHT; clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ snd_ctrl.active = TRUE; snd_ctrl.nr = nr; snd_ctrl.volume = volume; snd_ctrl.stereo_position = stereo_position; snd_ctrl.state = state; HandleSoundRequest(snd_ctrl); } void FadeMusic(void) { if (!audio.music_available) return; StopSoundExt(-1, SND_CTRL_FADE_MUSIC); } void FadeSound(int nr) { StopSoundExt(nr, SND_CTRL_FADE_SOUND); } void FadeSounds() { StopSoundExt(-1, SND_CTRL_FADE_ALL); } void FadeSoundsAndMusic() { FadeSounds(); FadeMusic(); } void StopMusic(void) { if (!audio.music_available) return; StopSoundExt(-1, SND_CTRL_STOP_MUSIC); } void StopSound(int nr) { StopSoundExt(nr, SND_CTRL_STOP_SOUND); } void StopSounds() { StopMusic(); StopSoundExt(-1, SND_CTRL_STOP_ALL); } void StopSoundExt(int nr, int state) { SoundControl snd_ctrl; if (!audio.sound_available) return; clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ snd_ctrl.active = FALSE; snd_ctrl.nr = nr; snd_ctrl.state = state; HandleSoundRequest(snd_ctrl); } void ExpireSoundLoops(boolean active) { SoundControl snd_ctrl; if (!audio.sound_available) return; clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ snd_ctrl.active = active; snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS; HandleSoundRequest(snd_ctrl); } static void ReloadCustomSounds() { LoadArtworkConfig(sound_info); ReloadCustomArtworkList(sound_info); } static void ReloadCustomMusic() { LoadArtworkConfig(music_info); ReloadCustomArtworkList(music_info); /* load all music files from directory not defined in "musicinfo.conf" */ LoadCustomMusic_NoConf(); } void InitReloadCustomSounds(char *set_identifier) { if (!audio.sound_available) return; ReloadCustomSounds(); } void InitReloadCustomMusic(char *set_identifier) { if (!audio.music_available) return; ReloadCustomMusic(); } void FreeSound(void *ptr) { SoundInfo *sound = (SoundInfo *)ptr; if (sound == NULL) return; if (sound->data_ptr) { Mix_FreeChunk(sound->data_ptr); } checked_free(sound->source_filename); free(sound); } void FreeMusic(void *ptr) { MusicInfo *music = (MusicInfo *)ptr; if (music == NULL) return; if (music->data_ptr) { if (music->type == MUS_TYPE_MOD) Mix_FreeMusic(music->data_ptr); else Mix_FreeChunk(music->data_ptr); } free(music); } static void FreeAllMusic_NoConf() { int i; if (Music_NoConf == NULL) return; for (i = 0; i < num_music_noconf; i++) FreeMusic(Music_NoConf[i]); free(Music_NoConf); Music_NoConf = NULL; num_music_noconf = 0; } void FreeAllSounds() { FreeCustomArtworkLists(sound_info); } void FreeAllMusic() { FreeCustomArtworkLists(music_info); FreeAllMusic_NoConf(); } /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */ /* ========================================================================= */ mirrormagic-3.0.0/music/0000755000175000017500000000000013263214147014456 5ustar aeglosaeglos