From fb4801bb596a2fa248e3e5f76a263f4258d33b31 Mon Sep 17 00:00:00 2001 From: pelya Date: Fri, 30 Jul 2010 13:10:35 +0300 Subject: [PATCH] Added OpenTyrian sources - it does not work yet --- alienblaster/build.sh | 2 +- alienblaster/project/AndroidManifest.xml | 6 +- alienblaster/project/jni/Android.mk | 6 +- alienblaster/project/jni/Application.mk | 2 +- .../jni/application/alienblaster/video.cpp | 2 +- .../application/opentyrian/AppSettings.cfg | 16 + .../jni/application/opentyrian/COPYING | 339 + .../jni/application/opentyrian/CREDITS | 31 + .../project/jni/application/opentyrian/NEWS | 15 + .../project/jni/application/opentyrian/README | 49 + .../jni/application/opentyrian/icon.png | Bin 0 -> 5197 bytes .../application/opentyrian/src/animlib.cpp | 431 + .../jni/application/opentyrian/src/animlib.h | 28 + .../application/opentyrian/src/arg_parse.cpp | 247 + .../application/opentyrian/src/arg_parse.h | 58 + .../application/opentyrian/src/backgrnd.cpp | 468 + .../jni/application/opentyrian/src/backgrnd.h | 59 + .../jni/application/opentyrian/src/cJSON.cpp | 680 + .../jni/application/opentyrian/src/cJSON.h | 117 + .../jni/application/opentyrian/src/config.cpp | 1040 ++ .../jni/application/opentyrian/src/config.h | 163 + .../application/opentyrian/src/destruct.cpp | 2833 ++++ .../jni/application/opentyrian/src/destruct.h | 28 + .../application/opentyrian/src/editship.cpp | 92 + .../jni/application/opentyrian/src/editship.h | 37 + .../application/opentyrian/src/episodes.cpp | 267 + .../jni/application/opentyrian/src/episodes.h | 173 + .../jni/application/opentyrian/src/file.cpp | 192 + .../jni/application/opentyrian/src/file.h | 53 + .../application/opentyrian/src/fm_synth.cpp | 54 + .../jni/application/opentyrian/src/fm_synth.h | 35 + .../jni/application/opentyrian/src/fmopl.cpp | 2400 ++++ .../jni/application/opentyrian/src/fmopl.h | 253 + .../jni/application/opentyrian/src/font.cpp | 171 + .../jni/application/opentyrian/src/font.h | 48 + .../application/opentyrian/src/fonthand.cpp | 333 + .../jni/application/opentyrian/src/fonthand.h | 60 + .../application/opentyrian/src/game_menu.cpp | 3346 +++++ .../application/opentyrian/src/game_menu.h | 59 + .../application/opentyrian/src/helptext.cpp | 383 + .../jni/application/opentyrian/src/helptext.h | 66 + .../application/opentyrian/src/hg_revision.h | 8 + .../application/opentyrian/src/joystick.cpp | 659 + .../jni/application/opentyrian/src/joystick.h | 98 + .../application/opentyrian/src/jukebox.cpp | 201 + .../jni/application/opentyrian/src/jukebox.h | 28 + .../application/opentyrian/src/keyboard.cpp | 246 + .../jni/application/opentyrian/src/keyboard.h | 59 + .../application/opentyrian/src/lds_play.cpp | 768 + .../jni/application/opentyrian/src/lds_play.h | 73 + .../application/opentyrian/src/loudness.cpp | 293 + .../jni/application/opentyrian/src/loudness.h | 60 + .../jni/application/opentyrian/src/lvllib.cpp | 42 + .../jni/application/opentyrian/src/lvllib.h | 35 + .../application/opentyrian/src/lvlmast.cpp | 174 + .../jni/application/opentyrian/src/lvlmast.h | 49 + .../jni/application/opentyrian/src/main.m | 101 + .../application/opentyrian/src/mainint.cpp | 4561 ++++++ .../jni/application/opentyrian/src/mainint.h | 94 + .../jni/application/opentyrian/src/menus.cpp | 269 + .../jni/application/opentyrian/src/menus.h | 32 + .../opentyrian/src/mingw_fixes.cpp | 26 + .../application/opentyrian/src/mingw_fixes.h | 24 + .../jni/application/opentyrian/src/mouse.cpp | 114 + .../jni/application/opentyrian/src/mouse.h | 44 + .../jni/application/opentyrian/src/mtrand.cpp | 108 + .../jni/application/opentyrian/src/mtrand.h | 31 + .../application/opentyrian/src/musmast.cpp | 117 + .../jni/application/opentyrian/src/musmast.h | 42 + .../application/opentyrian/src/network.cpp | 788 + .../jni/application/opentyrian/src/network.h | 100 + .../application/opentyrian/src/nortsong.cpp | 225 + .../jni/application/opentyrian/src/nortsong.h | 65 + .../application/opentyrian/src/nortvars.cpp | 88 + .../jni/application/opentyrian/src/nortvars.h | 36 + .../application/opentyrian/src/opentyr.cpp | 349 + .../jni/application/opentyrian/src/opentyr.h | 61 + .../application/opentyrian/src/palette.cpp | 214 + .../jni/application/opentyrian/src/palette.h | 52 + .../jni/application/opentyrian/src/params.cpp | 268 + .../jni/application/opentyrian/src/params.h | 30 + .../application/opentyrian/src/pcxload.cpp | 67 + .../jni/application/opentyrian/src/pcxload.h | 28 + .../application/opentyrian/src/pcxmast.cpp | 49 + .../jni/application/opentyrian/src/pcxmast.h | 36 + .../application/opentyrian/src/picload.cpp | 87 + .../jni/application/opentyrian/src/picload.h | 28 + .../jni/application/opentyrian/src/player.cpp | 55 + .../jni/application/opentyrian/src/player.h | 129 + .../application/opentyrian/src/scroller.cpp | 313 + .../jni/application/opentyrian/src/scroller.h | 33 + .../jni/application/opentyrian/src/setup.cpp | 96 + .../jni/application/opentyrian/src/setup.h | 28 + .../application/opentyrian/src/sizebuf.cpp | 222 + .../jni/application/opentyrian/src/sizebuf.h | 50 + .../application/opentyrian/src/sndmast.cpp | 78 + .../jni/application/opentyrian/src/sndmast.h | 76 + .../jni/application/opentyrian/src/sprite.cpp | 732 + .../jni/application/opentyrian/src/sprite.h | 115 + .../application/opentyrian/src/starlib.cpp | 432 + .../jni/application/opentyrian/src/starlib.h | 33 + .../application/opentyrian/src/tyrian2.cpp | 5307 +++++++ .../jni/application/opentyrian/src/tyrian2.h | 71 + .../jni/application/opentyrian/src/varz.cpp | 1412 ++ .../jni/application/opentyrian/src/varz.h | 385 + .../application/opentyrian/src/vga256d.cpp | 160 + .../jni/application/opentyrian/src/vga256d.h | 43 + .../opentyrian/src/vga_palette.cpp | 71 + .../application/opentyrian/src/vga_palette.h | 8 + .../jni/application/opentyrian/src/video.cpp | 187 + .../jni/application/opentyrian/src/video.h | 47 + .../opentyrian/src/video_scale.cpp | 442 + .../application/opentyrian/src/video_scale.h | 43 + .../opentyrian/src/video_scale_hqNx.cpp | 11896 ++++++++++++++++ .../jni/application/opentyrian/src/xmas.cpp | 99 + .../jni/application/opentyrian/src/xmas.h | 31 + alienblaster/project/jni/application/src | 2 +- alienblaster/project/res/values/strings.xml | 2 +- alienblaster/project/src/Accelerometer.java | 2 +- alienblaster/project/src/Audio.java | 2 +- alienblaster/project/src/DataDownloader.java | 2 +- .../project/src/GLSurfaceView_SDL.java | 2 +- alienblaster/project/src/Globals.java | 12 +- alienblaster/project/src/MainActivity.java | 2 +- alienblaster/project/src/Settings.java | 2 +- alienblaster/project/src/Video.java | 2 +- alienblaster/readme.txt | 27 +- 127 files changed, 48194 insertions(+), 26 deletions(-) create mode 100644 alienblaster/project/jni/application/opentyrian/AppSettings.cfg create mode 100644 alienblaster/project/jni/application/opentyrian/COPYING create mode 100644 alienblaster/project/jni/application/opentyrian/CREDITS create mode 100644 alienblaster/project/jni/application/opentyrian/NEWS create mode 100644 alienblaster/project/jni/application/opentyrian/README create mode 100644 alienblaster/project/jni/application/opentyrian/icon.png create mode 100644 alienblaster/project/jni/application/opentyrian/src/animlib.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/animlib.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/arg_parse.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/arg_parse.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/backgrnd.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/backgrnd.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/cJSON.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/cJSON.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/config.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/config.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/destruct.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/destruct.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/editship.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/editship.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/episodes.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/episodes.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/file.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/file.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/fm_synth.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/fm_synth.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/fmopl.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/fmopl.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/font.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/font.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/fonthand.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/fonthand.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/game_menu.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/game_menu.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/helptext.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/helptext.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/hg_revision.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/joystick.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/joystick.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/jukebox.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/jukebox.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/keyboard.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/keyboard.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/lds_play.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/lds_play.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/loudness.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/loudness.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/lvllib.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/lvllib.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/lvlmast.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/lvlmast.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/main.m create mode 100644 alienblaster/project/jni/application/opentyrian/src/mainint.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/mainint.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/menus.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/menus.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/mingw_fixes.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/mingw_fixes.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/mouse.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/mouse.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/mtrand.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/mtrand.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/musmast.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/musmast.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/network.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/network.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/nortsong.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/nortsong.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/nortvars.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/nortvars.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/opentyr.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/opentyr.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/palette.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/palette.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/params.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/params.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/pcxload.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/pcxload.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/pcxmast.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/pcxmast.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/picload.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/picload.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/player.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/player.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/scroller.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/scroller.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/setup.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/setup.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/sizebuf.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/sizebuf.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/sndmast.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/sndmast.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/sprite.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/sprite.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/starlib.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/starlib.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/tyrian2.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/tyrian2.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/varz.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/varz.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/vga256d.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/vga256d.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/vga_palette.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/vga_palette.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/video.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/video.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/video_scale.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/video_scale.h create mode 100644 alienblaster/project/jni/application/opentyrian/src/video_scale_hqNx.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/xmas.cpp create mode 100644 alienblaster/project/jni/application/opentyrian/src/xmas.h diff --git a/alienblaster/build.sh b/alienblaster/build.sh index c6de26713..6842bfc81 100755 --- a/alienblaster/build.sh +++ b/alienblaster/build.sh @@ -3,5 +3,5 @@ # Set here your own NDK path if needed # export PATH=$PATH:~/src/endless_space/android-ndk-r4 -cd project && nice -n5 ndk-build V=1 -j2 && ant debug && cd bin && adb install -r DemoActivity-debug.apk +cd project && nice -n5 ndk-build V=1 && ant debug && cd bin && adb install -r DemoActivity-debug.apk diff --git a/alienblaster/project/AndroidManifest.xml b/alienblaster/project/AndroidManifest.xml index 8672682c5..fbb1c1b0e 100644 --- a/alienblaster/project/AndroidManifest.xml +++ b/alienblaster/project/AndroidManifest.xml @@ -1,8 +1,8 @@ + Copyright (C) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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 Lesser General +Public License instead of this License. diff --git a/alienblaster/project/jni/application/opentyrian/CREDITS b/alienblaster/project/jni/application/opentyrian/CREDITS new file mode 100644 index 000000000..da4b3f0b6 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/CREDITS @@ -0,0 +1,31 @@ +OpenTyrian Classic Development Team +================================================================================ + +Carl W. Reinke (Mindless) +Yuri K. Schlesner (yuriks) +Casey A. McCann (syntaxglitch) + +== Contributors ================================================================ + +awoodland patch that fixed 64-bit support +simx added Mac OS X support +filmor updated Mac OS X support +Tony Vroon patch that made Makefile more packager-friendly +jeff250 patch that fixed a buffer overflow +a.h.vandijk patch that fixed a buffer overflow, + patch that fixed an input handling bug, + patch that fixed some handling of unprintable characters +ECA Destruct rewrite +spudd86.2 patch that fixed an audio bug +Jan "heftig" Steffens clean-up patches + +== Further Thanks ============================================================== + +Jason Emery + * Tyrian source code + +MAME and DOSBox + * FM emulator code + +AdPlug + * Loudness player diff --git a/alienblaster/project/jni/application/opentyrian/NEWS b/alienblaster/project/jni/application/opentyrian/NEWS new file mode 100644 index 000000000..9bca3e51c --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/NEWS @@ -0,0 +1,15 @@ +06/02/2007 +HOLOVID RELEASE ALPHA 01 +Breaking News + +Authorities report that a Gencore special task force, working from a secret +lab at Deliani, are engaged in a project to reimplent the historically +significant "videogame" entitled ~Tyrian~, a work regarded by historians as +a cultural artifact of utmost importance, and by the Church of Zinglon as a +holy prophecy. News of this effort have caused uproar through the galaxy, +but Gencore remains silent on the matter and officially-released details are +sparse. When approached for comment, Gencore Chancellor Transon Lohk +replied, "Who are you and what are you doing in my house? Get out!" + +Stay tuned for updates to this galaxy-shaking event! + diff --git a/alienblaster/project/jni/application/opentyrian/README b/alienblaster/project/jni/application/opentyrian/README new file mode 100644 index 000000000..029d735fa --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/README @@ -0,0 +1,49 @@ +OpenTyrian Classic +================================================================================ + +OpenTyrian is an open-source port of the DOS game Tyrian. + +Tyrian is an arcade-style vertical scrolling shooter. The story is set +in 20,031 where you play as Trent Hawkins, a skilled fighter-pilot employed +to fight MicroSol and save the galaxy. + +Tyrian features a story mode, one- and two-player arcade modes, and networked +multiplayer. + +== Additional Necessary Files ================================================== + +Tyrian 2.1 data files which have been released as freeware: + http://camanis.net/tyrian/tyrian21.zip + +== Keyboard Controls =========================================================== + +ctrl-backspace -- kill OpenTyrian +alt-enter -- fullscreen +ctrl-f10 -- ungrab mouse + +arrow keys -- ship movement +space -- fire weapons +enter -- toggle rear weapon mode +ctrl/alt -- fire left/right sidekick + +== Network Multiplayer ========================================================= + +Currently OpenTyrian does not have an arena; as such, networked games must be +initiated manually via the command line simultaniously by both players. + +syntax: + opentyrian --net HOSTNAME --net-player-name NAME --net-player-number NUMBER + +where HOSTNAME is the IP address of your opponent, NUMBER is either 1 or 2 +depending on which ship you intend to pilot, and NAME is your alias + +OpenTyrian uses UDP port 1333 for multiplayer, but in most cases players will +not need to open any ports because OpenTyrian makes use of UDP hole punching. + +== Links ======================================================================= + +project: http://opentyrian.googlecode.com/ +irc: irc://irc.freenode.net/#tyrian +forums: http://tyrian2k.proboards.com/index.cgi?board=opentyriangeneral + +README: AshTR diff --git a/alienblaster/project/jni/application/opentyrian/icon.png b/alienblaster/project/jni/application/opentyrian/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5301878755f85c797edf4e05ed079bf22e9aac83 GIT binary patch literal 5197 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&Aj0nH z;uunK>+M|qEi$fR$L2dIC<%0MurLV75Gaoth+`r1M5)zv?Yx1RE~>3-+jJ^fMOzPfUTu)7{BmM}LwS{PR! zUiehT>7$m=rk3A-ettf?IsJUweASY!fBaKwo(Jg0J>R3hses{MNx3S+mZ-^E;fxG2 zTEBW&K0TQH-Mrpz|7H!2phbt5rC0p=@^b2f%?nsWHi)oj{Oj)CJzHOX4u8=Br64T^ zJ-fW6bZ~!t>BgT=-dQ`RMlmRe{N-i%QY-4l^E*W3#E#|j8tudw zgjm=e?jLS?yZVRY!}vW~3BG+d4^31y)UF*7_m5b?`tSnEU@F#ahAtNei^Vc z*wy@>yKq6t965#y&r8ByUzvIFu#CW$O7SJp(swsAHB`U;@6h@6()r@!AAjwc7kvF{ z@YJ{(}`>P&f`yZ ze+p%p`TgRQ-`~%zUvu@w-her0%ysYmuA2KXf7Kc(he<#J?mw(fAugsOq{T1k%s&Ej;25}uB(w;_e2@igqAt3;-0tr zx4^GFtNCl0ZtP}i;F0ju7T2{5=dRd={M<2PrXHuDeguDvW%F7l29f-^>nud&Lo#C_{rr;Qsfld#|R;Fg!fV%FumegTdKiEu*RD zjSWP6y^j=stY>eS(a3zjw&PN-{s|(cWKY9)Av>=58M@=pgb)Az`fyLw`C$qxKG?pX+L-9~ClETeorhxflQM zzR|VaRj}H@<4SvQi%T@4NVw3o1xqW!TkO6+ZvM^8^2;(hE!A*FJVOGzg5rheA>!uW zuNdV?J+|BMG*=8;@2UpNJR zg=Dia{3^87PE4L;FEQQQ;?Mf0GnpH@_Pt&vz0mKc;lDqY;u}Nk`ybV&UHH4;sE%o$ zf}Fvjg{}`vbPJuuHNq4po9tm|(0YG?mIHG=^eyr&sOb}fG+v_;x?&5nxqQyKQ{`TcJz=j5f13rbVV9sV5H&B*ES{fnab`4Gkh|2-3K zx?b=V@Lygbx0t!%srS*vGHE84qhx|UzH495ezfS-k`hJ-PY!`yaygvBQ`WMvR&qo# z1-RC}*{jcBnJ3T8V6VZL5V6x`(aSqx{yNNePwb54VTgSZFFv0~{Ocpjyhx5$ZyqaG zlm{?AU@CaHz(rI3_&G*}R9$aTwquRTg`sJp0vVZ{4Q^iVRNhCGm%lsaV|%{wQRuuo z*70Ht$4*C{xFH$keP*fhna}+9?%h;kaAa-Z-!0Im9nLVJ?HR+Cng*?+2maX5+ec`;r1cr(w9|UyoO|`dpvG7kb^Mda54Qi9+WLZL=?A~v?31>)Ia8fZs zhM}D4>*s9@Dc2v|v|1$~ws7h*SG{^xhthsA28)s&h9X{u#oX&mSsUJMo zg?H&^SR0lEGhFz2Z+E^vx5KypyDSgQ}OpTzJZV$Sb{HEmfMLGzc^Uy1Bm{xp1HNYdXc zYr8BBzC5X1#!#SNFVA3fs=~y2!w;s`ScVG$8=o>)I9hTt9CCNGOMJ{77@_1RxBoe# zN5`6Dg(qSI*Ktfc#^`WNO=wjuV}!}EdJhghR)&vx4h{)C3uA6rCcE1>p8EgxX!k+$ z1eF74<}S}zT6{fd2J?c?3mGh`o?5d=U3<&yaBl76nn%qSSPg^@RQosXR*GDH{6xc* z%~}gvGVd62?AXU#U>aEVQe*O;gO%Y799DDJKK<}+LDcOyUS2`Jcd`!_o@-%XKO_2p zwO@ik!u+?r$Ni_X(kU!JiqfBeoJq;JAICN}VtOIM~bgqU!J^#XT#U}o& zniulwrcE+K%If7IoC|IjVd}bd&%cFw6*F2`KHaXc;u*^&&Ju<_77R!3Z)ZHvK6Te|GX{aP%0^ra zp}VY%=S8g6WC(lx;Vm;`F{98235GmB$ykqseY@Sc8S-}qx3+4CE@3$Em(%_EF@KwK zCWmbStOrhN?`LKFyI;MlqJBoL7Q+iGyTB*sQl9+~l)6@a?)*8k`2D5ZDyv@Se12aZ zFZy?0V&44K>*A}PHO|+uJLmuOb^g_3LYxid-2Cxc z(Y5=!eD+V7&mB~|Ix5^Q_PPkmTGf}{Z<=c+F;t|iOZ_IxFeN@!J(S@^dMcBqq|4Fp zx0B>os0iwKvNC*6dSc78HLH{He{*^!a z8PTN0s;8K+V+3o!tzlQVpE`wM!nSv_V=A1jq8My+y`3f>xGHsZx+TL-+wSmntc}e9 zYfl!lck3MxwY<)mvT;?u)K#Vf;w@?nx=&x{Ti)?yP|-ix`}|YQiN&l55z+aUMSKkU z-Lsey_*mwJT&$Yr_49TgQv-wg2Gx?Fi_exE`2Fo;WInsYr&SCRLIF9;zbs~Q5RKq! zFyuHk<^1Ls|163Rhv^G5q$qUcHEF(D={r4QnccEKF|+n*GyGfEGMS~pqK3O^Wvr{m zo(s=y*e2}mh?i!)F~R?+aZO~6k!p#KeW_aMK`R>KmS2aSh2R7{WVrHn9PBXo_yO(taGsF6r;-}%Ovub}v zZeil7yrTrY)gXkQtA-}(OX z7U8Cy)ekO-E-6|*W&Zrx+HbfTdU~q9oBxnIDzJU)UY}FnGlKUNMO|;VyLv`${^v-W zdP`?L)A_SKCx8B-%Mm55o3s0PKGTEK$NxtCySLBZ{2A95TuR0o* zJM(Pw&e^~D9_5~m*DjjgC3pK*?d`k*zj^l8k1=hS=IA;>+4wta&GIdaSsU(dDKa^r zaiI9SZT-6oVVd4sU30$fbhf{K_0{v~pBR`J6)Km0KhJI0C&eH*i(y0bcCA^b_OHzK zx4GEzm+{ZjkQ|YR^LMWd+0oLF`Do!)b_Vx+Mj?hh)xT_~MNAIyym#l)`HMvyl3f>F zHwL<}9-Q;~-S0U+n0jg^@c+NOc^wzSx68^&tqu$4h~#~5<5#?~M~%t#;!gVlr-0i3 z0_SJ0zm&R;dAS4!!vl@Q4UvlVlc&Ge=rVtw>EEtk)n2yG^U57@%jJhp-1)Dlvuyck z!=*lF8WwIiuPRd;7SQ+D*8JY)l#|j+7I`y0IQ5O8=e&E0C&wyQS?^O_b@RR}{1B_Y z*%3Bb=9OaN@@uRwUo-F-Zt-MTwKUD=Z_uji*W{%bWCHKcHfT=&d1ti;*V&5g%oBGu zb0nTTWyvu0Wvn!~4L7jQITP$^83X26HpqFN#yW|8;l&r&_By;sHI8Q{K2uy}Tf|o}>|-s) zfQwQ4e@|aOWA^KVN(Jl(pC2xt$@fk7spigwC0jEeZ##89anARL``9nV#5-OORGy?0 z&VOJVUyuIYq?q}AH_c{R?G(+<(~i%*yU+Jo;A_e9oBSu*8)wNl{anqOFu#5NDdRh$ zO!wc-{my5>a66`aWzQn7wpU)^+y^#Ze68@4TYitX*+BU$jxdrowiQO{98-sHnxHfU4Ag@xQAXx36Tm+rYe` zYtJ|3NpqPutU9*Xi$~uxZ^lMG$J<{n*H%4_41K-6hH*R7cm49)uU^?*yf!~Gh-|hlSQh)3U0OiOMjT36F*g2 zeNT1*$IdhXqundNKAT`CV<+vuCc>CudDwE?18(49xQ+WB|5w{%==GMj=QRTZ1B0il KpUXO@geCyREPWvW literal 0 HcmV?d00001 diff --git a/alienblaster/project/jni/application/opentyrian/src/animlib.cpp b/alienblaster/project/jni/application/opentyrian/src/animlib.cpp new file mode 100644 index 000000000..4c83b1744 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/animlib.cpp @@ -0,0 +1,431 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "animlib.h" +#include "file.h" +#include "keyboard.h" +#include "network.h" +#include "nortsong.h" +#include "palette.h" +#include "sizebuf.h" +#include "video.h" + +#include + +/*** Structs ***/ +/* The actual header has a lot of fields that are basically useless to us since + * we both set our own framerate and the format itself only allows for + * 320x200x8. Should a (nonexistent) ani be played that doesn't have the same + * assumed values we are going to use, TOO BAD. It'll just be treated as + * corrupt in playback. + */ +#define PALETTE_OFFSET 0x100 // 128 + sizeof(header) +#define PAGEHEADER_OFFSET 0x500 // PALETTE_OFFSET + sizeof(palette) +#define ANIM_OFFSET 0x0B00 // PAGEHEADER_OFFSET + sizeof(largepageheader) * 256 +#define ANI_PAGE_SIZE 0x10000 // 65536. +typedef struct anim_FileHeader_s +{ + unsigned int nlps; /* Number of 'pages', max 256. */ + unsigned int nRecords; /* Number of 'records', max 65535 */ +} anim_FileHeader_t; +typedef struct anim_LargePageHeader_s +{ + unsigned int baseRecord; /* The first record's number */ + unsigned int nRecords; /* Number of records. Supposedly there are bit flags but I saw no such code */ + unsigned int nBytes; /* Number of bytes used, excluding headers */ +} anim_LargePageHeader_t; + + +/*** Globals ***/ +Uint8 CurrentPageBuffer[65536]; +anim_LargePageHeader_t PageHeader[256]; +unsigned int CurrentPageRecordSizes[256]; + +anim_LargePageHeader_t CurrentPageHeader; +anim_FileHeader_t FileHeader; + +unsigned int Curlpnum; + +FILE * InFile; + + +/*** Function decs ***/ +int JE_playRunSkipDump( Uint8 *, unsigned int ); +void JE_closeAnim( void ); +int JE_loadAnim( const char * ); +int JE_renderFrame( unsigned int ); +int JE_findPage ( unsigned int ); +int JE_drawFrame( unsigned int ); +int JE_loadPage( unsigned int ); + +/*** Implementation ***/ + + +/* Loads the given page into memory. + * + * Returns 0 on success or nonzero on failure (bad data) + */ +int JE_loadPage( unsigned int pagenumber ) +{ + unsigned int i, pageSize; + + + if (Curlpnum == pagenumber) { return(0); } /* Already loaded */ + Curlpnum = pagenumber; + + /* We need to seek to the page and load it into our buffer. + * Pages have a fixed size of 0x10000; any left over space is padded + * unless it's the end of the file. + * + * Pages repeat their headers for some reason. They then have two bytes of + * padding folowed by a word for every record. THEN the data starts. + */ + fseek(InFile, ANIM_OFFSET + (pagenumber * ANI_PAGE_SIZE), SEEK_SET); + efread(&CurrentPageHeader.baseRecord, 2, 1, InFile); + efread(&CurrentPageHeader.nRecords, 2, 1, InFile); + efread(&CurrentPageHeader.nBytes, 2, 1, InFile); + + fseek(InFile, 2, SEEK_CUR); + for (i = 0; i < CurrentPageHeader.nRecords; i++) + { + efread(&CurrentPageRecordSizes[i], 2, 1, InFile); + } + + /* What remains is the 'compressed' data */ + efread(CurrentPageBuffer, 1, CurrentPageHeader.nBytes, InFile); + + /* Okay, we've succeeded in all our IO checks. Now, make sure the + * headers aren't lying or damaged or something. + */ + pageSize = 0; + for (i = 0; i < CurrentPageHeader.nRecords; i++) + { + pageSize += CurrentPageRecordSizes[i]; + } + + if(pageSize != CurrentPageHeader.nBytes) { return(-1); } + + /* So far, so good */ + return(0); +} + +int JE_drawFrame( unsigned int framenumber ) +{ + int ret; + + + ret = JE_loadPage(framenumber); + if (ret) { return(ret); } + + ret = JE_renderFrame (framenumber); + if (ret) { return(ret); } + + return(0); +} + +int JE_findPage( unsigned int framenumber ) +{ + unsigned int i; + + + for (i = 0; i < FileHeader.nlps; i++) + { + if (PageHeader[i].baseRecord <= framenumber + && PageHeader[i].baseRecord + PageHeader[i].nRecords > framenumber) + { + return(i); + } + } + + return(-1); /* Did not find */ +} + +int JE_renderFrame( unsigned int framenumber ) +{ + unsigned int i, offset, destframe; + + + destframe = framenumber - CurrentPageHeader.baseRecord; + + offset = 0; + for (i = 0; i < destframe; i++) + { + offset += CurrentPageRecordSizes[i]; + } + + return (JE_playRunSkipDump(CurrentPageBuffer + offset + 4, CurrentPageRecordSizes[destframe] - 4)); +} + +void JE_playAnim( const char *animfile, JE_byte startingframe, JE_byte speed ) +{ + unsigned int i; + int pageNum; + + if (JE_loadAnim(animfile) != 0) + { + return; /* Failed to open or process file */ + } + + /* Blank screen */ + JE_clr256(VGAScreen); + JE_showVGA(); + + + /* re FileHeader.nRecords-1: It's -1 in the pascal too. + * The final frame is a delta of the first, and we don't need that. + * We could also, if we ever ended up needing to loop anis, check + * the bools in the header to see if we should render the last + * frame. But that's never going to be encessary :) + */ + for (i = startingframe; i < FileHeader.nRecords-1; i++) + { + /* Handle boring crap */ + setjasondelay(speed); + + /* Load required frame. The loading function is smart enough to not re-load an already loaded frame */ + pageNum = JE_findPage(i); + if(pageNum == -1) { break; } + if (JE_loadPage(pageNum) != 0) { break; } + + /* render frame. */ + if (JE_renderFrame(i) != 0) { break; } + JE_showVGA(); + + + /* Return early if user presses a key */ + service_SDL_events(true); + if (newkey) + { + break; + } + + /* Wait until we need the next frame */ + NETWORK_KEEP_ALIVE(); + wait_delay(); + } + + JE_closeAnim(); +} + +/* loadAnim opens the file and loads data from it into the header structs. + * It should take care to clean up after itself should an error occur. + */ +int JE_loadAnim( const char *filename ) +{ + unsigned int i, fileSize; + char temp[4]; + + + Curlpnum = -1; + InFile = dir_fopen(data_dir(), filename, "rb"); + if(InFile == NULL) + { + return(-1); + } + + fileSize = ftell_eof(InFile); + if(fileSize < ANIM_OFFSET) + { + /* We don't know the exact size our file should be yet, + * but we do know it should be way more than this */ + fclose(InFile); + return(-1); + } + + /* Read in the header. The header is 256 bytes long or so, + * but that includes a lot of padding as well as several + * vars we really don't care about. We shall check the ID and extract + * the handful of vars we care about. Every value in the header that + * is constant will be ignored. + */ + + efread(&temp, 1, 4, InFile); /* The ID, should equal "LPF " */ + fseek(InFile, 2, SEEK_CUR); /* skip over this word */ + efread(&FileHeader.nlps, 2, 1, InFile); /* Number of pages */ + efread(&FileHeader.nRecords, 4, 1, InFile); /* Number of records */ + + if (memcmp(temp, "LPF ", 4) != 0 + || FileHeader.nlps == 0 || FileHeader.nRecords == 0 + || FileHeader.nlps > 256 || FileHeader.nRecords > 65535) + { + fclose(InFile); + return(-1); + } + + /* Read in headers */ + fseek(InFile, PAGEHEADER_OFFSET, SEEK_SET); + for (i = 0; i < FileHeader.nlps; i++) + { + efread(&PageHeader[i].baseRecord, 2, 1, InFile); + efread(&PageHeader[i].nRecords, 2, 1, InFile); + efread(&PageHeader[i].nBytes, 2, 1, InFile); + } + + + /* Now we have enough information to calculate the 'expected' file size. + * Our calculation SHOULD be equal to fileSize, but we won't begrudge + * padding */ + if (fileSize < (FileHeader.nlps-1) * ANI_PAGE_SIZE + ANIM_OFFSET + + PageHeader[FileHeader.nlps-1].nBytes + + PageHeader[FileHeader.nlps-1].nRecords * 2 + 8) + { + fclose(InFile); + return(-1); + } + + + /* Now read in the palette. */ + fseek(InFile, PALETTE_OFFSET, SEEK_SET); + for (i = 0; i < 256; i++) + { + efread(&colors[i].b, 1, 1, InFile); + efread(&colors[i].g, 1, 1, InFile); + efread(&colors[i].r, 1, 1, InFile); + efread(&colors[i].unused, 1, 1, InFile); + } + set_palette(colors, 0, 255); + + /* Whew! That was hard. Let's go grab some beers! */ + return(0); +} + +void JE_closeAnim( void ) +{ + fclose(InFile); +} + +/* RunSkipDump decompresses the video. There are three operations, run, skip, + * and dump. They can be used in either byte or word variations, making six + * possible actions, and there's a seventh 'stop' action, which looks + * like 0x80 0x00 0x00. + * + * Run is a memset. + * Dump is a memcpy. + * Skip leaves the old data intact and simply increments the pointers. + * + * returns 0 on success or 1 if decompressing failed. Failure to decompress + * indicates a broken or malicious file; playback should terminate. + */ +int JE_playRunSkipDump( Uint8 *incomingBuffer, unsigned int IncomingBufferLength ) +{ + sizebuf_t Buffer_IN, Buffer_OUT; + sizebuf_t * pBuffer_IN = &Buffer_IN, * pBuffer_OUT = &Buffer_OUT; + + #define ANI_SHORT_RLE 0x00 + #define ANI_SHORT_SKIP 0x80 + #define ANI_LONG_OP 0x80 + #define ANI_LONG_COPY_OR_RLE 0x8000 + #define ANI_LONG_RLE 0x4000 + #define ANI_STOP 0x0000 + + SZ_Init(pBuffer_IN, incomingBuffer, IncomingBufferLength); + SZ_Init(pBuffer_OUT, (Uint8 *)VGAScreen->pixels, VGAScreen->h * VGAScreen->pitch); + + + /* 320x200 is the only supported format. + * Assert is here as a hint should our screen size ever changes. + * As for how to decompress to the wrong screen size... */ + assert(VGAScreen->h * VGAScreen->pitch == 320 * 200); + + + while (1) + { + /* Get one byte. This byte may have flags that tell us more */ + unsigned int opcode = MSG_ReadByte(pBuffer_IN); + + /* Before we continue, check the error states/ + * We should *probably* check these after every read and write, but + * I've rigged it so that the buffers will never go out of bounds. + * So we can afford to be lazy; if the buffer overflows below it will + * silently fail its writes and we'll catch the failure on our next + * run through the loop. A failure means we should be + * leaving ANYWAY. The contents of our buffers doesn't matter. + */ + if (SZ_Error(pBuffer_IN) || SZ_Error(pBuffer_OUT)) + { + return(-1); + } + + /* Divide into 'short' and 'long' */ + if (opcode == ANI_LONG_OP) /* long ops */ + { + opcode = MSG_ReadWord(pBuffer_IN); + + if (opcode == ANI_STOP) /* We are done decompressing. Leave */ + { + break; + } + else if (!(opcode & ANI_LONG_COPY_OR_RLE)) /* If it's not those two, it's a skip */ + { + unsigned int count = opcode; + SZ_Seek(pBuffer_OUT, count, SEEK_CUR); + } + else /* Now things get a bit more interesting... */ + { + opcode &= ~ANI_LONG_COPY_OR_RLE; /* Clear that flag */ + + if (opcode & ANI_LONG_RLE) /* RLE */ + { + unsigned int count = opcode & ~ANI_LONG_RLE; /* Clear flag */ + + /* Extract another byte */ + unsigned int value = MSG_ReadByte(pBuffer_IN); + + /* The actual run */ + SZ_Memset(pBuffer_OUT, value, count); + } + else + { /* Long copy */ + unsigned int count = opcode; + + /* Copy */ + SZ_Memcpy2(pBuffer_OUT, pBuffer_IN, count); + } + } + } /* End of long ops */ + else /* short ops */ + { + if (opcode & ANI_SHORT_SKIP) /* Short skip, move pointer only */ + { + unsigned int count = opcode & ~ANI_SHORT_SKIP; /* clear flag to get count */ + SZ_Seek(pBuffer_OUT, count, SEEK_CUR); + } + else if (opcode == ANI_SHORT_RLE) /* Short RLE, memset the destination */ + { + /* Extract a few more bytes */ + unsigned int count = MSG_ReadByte(pBuffer_IN); + unsigned int value = MSG_ReadByte(pBuffer_IN); + + /* Run */ + SZ_Memset(pBuffer_OUT, value, count); + } + else /* Short copy, memcpy from src to dest. */ + { + unsigned int count = opcode; + + /* Dump */ + SZ_Memcpy2(pBuffer_OUT, pBuffer_IN, count); + } + } /* End of short ops */ + } + + /* And that's that */ + return(0); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/animlib.h b/alienblaster/project/jni/application/opentyrian/src/animlib.h new file mode 100644 index 000000000..298e3cfd6 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/animlib.h @@ -0,0 +1,28 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef ANIMLIB_H +#define ANIMLIB_H + +#include "opentyr.h" + +void JE_playAnim( const char *animfile, JE_byte startingframe, JE_byte speed ); + +#endif /* ANIMLIB_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/arg_parse.cpp b/alienblaster/project/jni/application/opentyrian/src/arg_parse.cpp new file mode 100644 index 000000000..4d7c2c487 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/arg_parse.cpp @@ -0,0 +1,247 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "arg_parse.h" +#include "mingw_fixes.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt ); + +static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option ); +static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option ); + +Option parse_args( int argc, const char *argv[], const Options *options ) +{ + static int argn = 1; + static bool no_more_options = false; + + static int first_nonopt = 1; + + Option option = { NOT_OPTION, NULL, 0 }; + option.argn = first_nonopt; + + while (argn < argc) + { + size_t arg_len = strlen(argv[argn]); + + if (!no_more_options && + argv[argn][0] == '-' && // first char is '-' + arg_len > 1) // option is not "-" + { + option.argn = argn; + + if (argv[argn][1] == '-') // string begins with "--" + { + if (arg_len == 2) // "--" alone indicates end of options + { + ++argn; + no_more_options = true; + } + else + { + argn = parse_long_opt(argc, argv, options, &option); + } + } + else + { + argn = parse_short_opt(argc, argv, options, &option); + } + + // shift option in front of non-options + permute(argv, &first_nonopt, &option.argn, argn); + + // don't include "--" in non-options + if (no_more_options) + ++option.argn; + break; + } + else + { + // skip non-options, permute later when option encountered + ++argn; + } + } + + return option; +} + +static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt ) +{ + const int nonopts = *first_opt - *first_nonopt; + + // slide each of the options in front of the non-options + for (int i = *first_opt; i < after_opt; ++i) + { + for (int j = i; j > *first_nonopt; --j) + { + // swap argv[j] and argv[j - 1] + const char *temp = argv[j]; + argv[j] = argv[j - 1]; + argv[j - 1] = temp; + } + + // position of first non-option shifts right once for each option + ++(*first_nonopt); + } + + // position of first option is initial position of first non-option + *first_opt -= nonopts; +} + +static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option ) +{ + static size_t offset = 1; // ignore the "-" + + int argn = option->argn; + + const char *arg = argv[argn]; + + const size_t arg_len = strlen(arg); + + const bool arg_attached = (offset + 1 < arg_len), // possible argument attached? + last_in_argv = (argn == argc - 1); + + option->value = INVALID_OPTION; + + for (; !(options->short_opt == 0 && + options->long_opt == NULL); ++options) + { + if (options->short_opt != 0 && + options->short_opt == arg[offset]) + { + option->value = options->value; + + if (options->has_arg) + { + if (arg_attached) // arg direclty follows option + { + option->arg = arg + offset + 1; + + offset = arg_len; + } + else if (!last_in_argv) // arg is next in argv + { + option->arg = argv[++argn]; + + offset = arg_len; + } + else + { + option->value = OPTION_MISSING_ARG; + break; + } + } + + break; + } + } + + switch (option->value) + { + case INVALID_OPTION: + fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], argv[option->argn][offset]); + break; + case OPTION_MISSING_ARG: + fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], argv[option->argn][offset]); + break; + } + + if (++offset >= arg_len) + { + ++argn; + offset = 1; + } + + return argn; // which arg in argv that parse_args() should examine when called again +} + +static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option ) +{ + int argn = option->argn; + + const char *arg = argv[argn] + 2; // ignore the "--" + + const size_t arg_len = strlen(arg), + arg_opt_len = strchrnul(arg, '=') - arg; // length before "=" + + const bool arg_attached = (arg_opt_len < arg_len), // argument attached using "="? + last_in_argv = (argn == argc - 1); + + option->value = INVALID_OPTION; + + for (; !(options->short_opt == 0 && + options->long_opt == NULL); ++options) + { + if (options->long_opt != NULL && + strncmp(options->long_opt, arg, arg_opt_len) == 0) // matches (partially, at least) + { + if (option->value != INVALID_OPTION) // other match already found + { + option->value = AMBIGUOUS_OPTION; + break; + } + + option->value = options->value; + + if (options->has_arg) + { + if (arg_attached) // arg is after "=" + { + option->arg = arg + arg_opt_len + 1; + } + else if (!last_in_argv) // arg is next in argv + { + option->arg = argv[++argn]; + } + else // arg is missing + { + option->value = OPTION_MISSING_ARG; + // can't break, gotta check for ambiguity + } + } + + if (arg_opt_len == strlen(options->long_opt)) // exact match + break; + // can't break for partial match, gotta check for ambiguity + } + } + + switch (option->value) + { + case INVALID_OPTION: + fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[option->argn]); + break; + case AMBIGUOUS_OPTION: + fprintf(stderr, "%s: option '%s' is ambiguous\n", argv[0], argv[option->argn]); + break; + case OPTION_MISSING_ARG: + fprintf(stderr, "%s: option '%s' requires an argument\n", argv[0], argv[option->argn]); + break; + } + + ++argn; + + return argn; // which arg in argv that parse_args() should examine when called again +} diff --git a/alienblaster/project/jni/application/opentyrian/src/arg_parse.h b/alienblaster/project/jni/application/opentyrian/src/arg_parse.h new file mode 100644 index 000000000..0334f5be7 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/arg_parse.h @@ -0,0 +1,58 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef ARG_PARSE_H +#define ARG_PARSE_H + +#include + +// this is essentially a reimplementation of getopt_long() + +typedef struct +{ + int value; + char short_opt; + const char *long_opt; + bool has_arg; +} +Options; + +enum +{ + // indicates that argv[argn..argc) are not options + NOT_OPTION = 0, + + /* behavior of parse_args() is undefined after + it has returned any of the following values */ + INVALID_OPTION = -1, + AMBIGUOUS_OPTION = -2, + OPTION_MISSING_ARG = -3 +}; + +typedef struct +{ + int value; + const char *arg; + + int argn; +} +Option; + +Option parse_args( int argc, const char *argv[], const Options *options ); + +#endif /* ARG_PARSE_H */ diff --git a/alienblaster/project/jni/application/opentyrian/src/backgrnd.cpp b/alienblaster/project/jni/application/opentyrian/src/backgrnd.cpp new file mode 100644 index 000000000..ec1ab7e77 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/backgrnd.cpp @@ -0,0 +1,468 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "opentyr.h" +#include "backgrnd.h" + +#include "config.h" +#include "varz.h" +#include "video.h" + +#include + +/*Special Background 2 and Background 3*/ + +/*Back Pos 3*/ +JE_word backPos, backPos2, backPos3; +JE_word backMove, backMove2, backMove3; + +/*Main Maps*/ +JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3; +JE_byte **mapYPos, **mapY2Pos, **mapY3Pos; +JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs; +intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos; +JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax; + + +JE_boolean anySmoothies; +JE_byte smoothie_data[9]; /* [1..9] */ + +void JE_darkenBackground( JE_word neat ) /* wild detail level */ +{ + Uint8 *s = (Uint8 *)VGAScreen->pixels; /* screen pointer, 8-bit specific */ + int x, y; + + s += 24; + + for (y = 184; y; y--) + { + for (x = 264; x; x--) + { + *s = ((((*s & 0x0f) << 4) - (*s & 0x0f) + ((((x - neat - y) >> 2) + *(s-2) + (y == 184 ? 0 : *(s-(VGAScreen->pitch-1)))) & 0x0f)) >> 4) | (*s & 0xf0); + s++; + } + s += VGAScreen->pitch - 264; + } +} + +void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map ) +{ + assert(surface->format->BitsPerPixel == 8); + + Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x, + *pixels_ll = (Uint8 *)surface->pixels, // lower limit + *pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (int y = 0; y < 28; y++) + { + // not drawing on screen yet; skip y + if ((pixels + (12 * 24)) < pixels_ll) + { + pixels += surface->pitch; + continue; + } + + for (int tile = 0; tile < 12; tile++) + { + Uint8 *data = *(map + tile); + + // no tile; skip tile + if (data == NULL) + { + pixels += 24; + continue; + } + + data += y * 24; + + for (int x = 24; x; x--) + { + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll && *data != 0) + *pixels = *data; + + pixels++; + data++; + } + } + + pixels += surface->pitch - 12 * 24; + } +} + +void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map ) +{ + assert(surface->format->BitsPerPixel == 8); + + Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x, + *pixels_ll = (Uint8 *)surface->pixels, // lower limit + *pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (int y = 0; y < 28; y++) + { + // not drawing on screen yet; skip y + if ((pixels + (12 * 24)) < pixels_ll) + { + pixels += surface->pitch; + continue; + } + + for (int tile = 0; tile < 12; tile++) + { + Uint8 *data = *(map + tile); + + // no tile; skip tile + if (data == NULL) + { + pixels += 24; + continue; + } + + data += y * 24; + + for (int x = 24; x; x--) + { + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll && *data != 0) + *pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2); + + pixels++; + data++; + } + } + + pixels += surface->pitch - 12 * 24; + } +} + +void draw_background_1( SDL_Surface *surface ) +{ + SDL_FillRect(surface, NULL, 0); + + Uint8 **map = (Uint8 **)mapYPos + mapXbpPos - 12; + + for (int i = -1; i < 7; i++) + { + blit_background_row(surface, mapXPos, (i * 28) + backPos, map); + + map += 14; + } +} + +void draw_background_2( SDL_Surface *surface ) +{ + if (map2YDelayMax > 1 && backMove2 < 2) + backMove2 = (map2YDelay == 1) ? 1 : 0; + + if (background2 != 0) + { + // water effect combines background 1 and 2 by syncronizing the x coordinate + int x = smoothies[1] ? mapXPos : mapX2Pos; + + Uint8 **map = (Uint8 **)mapY2Pos + (smoothies[1] ? mapXbpPos : mapX2bpPos) - 12; + + for (int i = -1; i < 7; i++) + { + blit_background_row(surface, x, (i * 28) + backPos2, map); + + map += 14; + } + } + + /*Set Movement of background*/ + if (--map2YDelay == 0) + { + map2YDelay = map2YDelayMax; + + backPos2 += backMove2; + + if (backPos2 > 27) + { + backPos2 -= 28; + mapY2--; + mapY2Pos -= 14; /*Map Width*/ + } + } +} + +void draw_background_2_blend( SDL_Surface *surface ) +{ + if (map2YDelayMax > 1 && backMove2 < 2) + backMove2 = (map2YDelay == 1) ? 1 : 0; + + Uint8 **map = (Uint8 **)mapY2Pos + mapX2bpPos - 12; + + for (int i = -1; i < 7; i++) + { + blit_background_row_blend(surface, mapX2Pos, (i * 28) + backPos2, map); + + map += 14; + } + + /*Set Movement of background*/ + if (--map2YDelay == 0) + { + map2YDelay = map2YDelayMax; + + backPos2 += backMove2; + + if (backPos2 > 27) + { + backPos2 -= 28; + mapY2--; + mapY2Pos -= 14; /*Map Width*/ + } + } +} + +void draw_background_3( SDL_Surface *surface ) +{ + /* Movement of background */ + backPos3 += backMove3; + + if (backPos3 > 27) + { + backPos3 -= 28; + mapY3--; + mapY3Pos -= 15; /*Map Width*/ + } + + Uint8 **map = (Uint8 **)mapY3Pos + mapX3bpPos - 12; + + for (int i = -1; i < 7; i++) + { + blit_background_row(surface, mapX3Pos, (i * 28) + backPos3, map); + + map += 15; + } +} + +void JE_filterScreen( JE_shortint col, JE_shortint int_) +{ + Uint8 *s = NULL; /* screen pointer, 8-bit specific */ + int x, y; + unsigned int temp; + + if (filterFade) + { + levelBrightness += levelBrightnessChg; + if ((filterFadeStart && levelBrightness < -14) || levelBrightness > 14) + { + levelBrightnessChg = -levelBrightnessChg; + filterFadeStart = false; + levelFilter = levelFilterNew; + } + if (!filterFadeStart && levelBrightness == 0) + { + filterFade = false; + levelBrightness = -99; + } + } + + if (col != -99 && filtrationAvail) + { + s = (Uint8 *)VGAScreen->pixels; + s += 24; + + col <<= 4; + + for (y = 184; y; y--) + { + for (x = 264; x; x--) + { + *s = col | (*s & 0x0f); + s++; + } + s += VGAScreen->pitch - 264; + } + } + + if (int_ != -99 && explosionTransparent) + { + s = (Uint8 *)VGAScreen->pixels; + s += 24; + + for (y = 184; y; y--) + { + for (x = 264; x; x--) + { + temp = (*s & 0x0f) + int_; + *s = (*s & 0xf0) | (temp >= 0x1f ? 0 : (temp >= 0x0f ? 0x0f : temp)); + s++; + } + s += VGAScreen->pitch - 264; + } + } +} + +void JE_checkSmoothies( void ) +{ + anySmoothies = (processorType > 2 && (smoothies[1-1] || smoothies[2-1])) || (processorType > 1 && (smoothies[3-1] || smoothies[4-1] || smoothies[5-1])); +} + +void lava_filter( SDL_Surface *dst, SDL_Surface *src ) +{ + assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8); + + /* we don't need to check for over-reading the pixel surfaces since we only + * read from the top 185+1 scanlines, and there should be 320 */ + + const int dst_pitch = dst->pitch; + Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch); + const Uint8 * const dst_pixel_ll = (Uint8 *)dst->pixels; // lower limit + + const int src_pitch = src->pitch; + const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch); + const Uint8 * const src_pixel_ll = (Uint8 *)src->pixels; // lower limit + + int w = 320 * 185 - 1; + + for (int y = 185 - 1; y >= 0; --y) + { + dst_pixel -= (dst_pitch - 320); // in case pitch is not 320 + src_pixel -= (src_pitch - 320); // in case pitch is not 320 + + for (int x = 320 - 1; x >= 0; x -= 8) + { + int waver = abs(((w >> 9) & 0x0f) - 8) - 1; + w -= 8; + + for (int xi = 8 - 1; xi >= 0; --xi) + { + --dst_pixel; + --src_pixel; + + // value is average value of source pixel (2x), destination pixel above, and destination pixel below (all with waver) + // hue is red + Uint8 value = 0; + + if (src_pixel + waver >= src_pixel_ll) + value += (*(src_pixel + waver) & 0x0f) * 2; + value += *(dst_pixel + waver + dst_pitch) & 0x0f; + if (dst_pixel + waver - dst_pitch >= dst_pixel_ll) + value += *(dst_pixel + waver - dst_pitch) & 0x0f; + + *dst_pixel = (value / 4) | 0x70; + } + } + } +} + +void water_filter( SDL_Surface *dst, SDL_Surface *src ) +{ + assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8); + + Uint8 hue = smoothie_data[1] << 4; + + /* we don't need to check for over-reading the pixel surfaces since we only + * read from the top 185+1 scanlines, and there should be 320 */ + + const int dst_pitch = dst->pitch; + Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch); + + const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch); + + int w = 320 * 185 - 1; + + for (int y = 185 - 1; y >= 0; --y) + { + dst_pixel -= (dst_pitch - 320); // in case pitch is not 320 + src_pixel -= (src->pitch - 320); // in case pitch is not 320 + + for (int x = 320 - 1; x >= 0; x -= 8) + { + int waver = abs(((w >> 10) & 0x07) - 4) - 1; + w -= 8; + + for (int xi = 8 - 1; xi >= 0; --xi) + { + --dst_pixel; + --src_pixel; + + // pixel is copied from source if not blue + // otherwise, value is average of value of source pixel and destination pixel below (with waver) + if ((*src_pixel & 0x30) == 0) + { + *dst_pixel = *src_pixel; + } + else + { + Uint8 value = *src_pixel & 0x0f; + value += *(dst_pixel + waver + dst_pitch) & 0x0f; + *dst_pixel = (value / 2) | hue; + } + } + } + } +} + +void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src ) +{ + assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8); + + Uint8 *dst_pixel = (Uint8 *)dst->pixels; + const Uint8 *src_pixel = (Uint8 *)src->pixels; + + for (int y = 0; y < 184; ++y) + { + for (int x = 0; x < 320; ++x) + { + // value is average value of source pixel and destination pixel + // hue is icy blue + + const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f); + *dst_pixel = (value / 2) | 0x80; + + ++dst_pixel; + ++src_pixel; + } + + dst_pixel += (dst->pitch - 320); // in case pitch is not 320 + src_pixel += (src->pitch - 320); // in case pitch is not 320 + } +} + +void blur_filter( SDL_Surface *dst, SDL_Surface *src ) +{ + assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8); + + Uint8 *dst_pixel = (Uint8 *)dst->pixels; + const Uint8 *src_pixel = (Uint8 *)src->pixels; + + for (int y = 0; y < 184; ++y) + { + for (int x = 0; x < 320; ++x) + { + // value is average value of source pixel and destination pixel + // hue is source pixel hue + + const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f); + *dst_pixel = (value / 2) | (*src_pixel & 0xf0); + + ++dst_pixel; + ++src_pixel; + } + + dst_pixel += (dst->pitch - 320); // in case pitch is not 320 + src_pixel += (src->pitch - 320); // in case pitch is not 320 + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/backgrnd.h b/alienblaster/project/jni/application/opentyrian/src/backgrnd.h new file mode 100644 index 000000000..9287ed76e --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/backgrnd.h @@ -0,0 +1,59 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef BACKGRND_H +#define BACKGRND_H + +#include "opentyr.h" + +#include +#include "SDL.h" + +extern JE_word backPos, backPos2, backPos3; +extern JE_word backMove, backMove2, backMove3; +extern JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3; +extern JE_byte **mapYPos, **mapY2Pos, **mapY3Pos; +extern JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs; +extern intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos; +extern JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax; +extern JE_boolean anySmoothies; // if yes, I want one :D +extern JE_byte smoothie_data[9]; + +void JE_darkenBackground( JE_word neat ); + +void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map ); +void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map ); + +void draw_background_1( SDL_Surface *surface ); +void draw_background_2( SDL_Surface *surface ); +void draw_background_2_blend( SDL_Surface *surface ); +void draw_background_3( SDL_Surface *surface ); + +void JE_filterScreen( JE_shortint col, JE_shortint generic_int ); + +void JE_checkSmoothies( void ); +void lava_filter( SDL_Surface *dst, SDL_Surface *src ); +void water_filter( SDL_Surface *dst, SDL_Surface *src ); +void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src ); +void blur_filter( SDL_Surface *dst, SDL_Surface *src ); +/*smoothies #5 is used for 3*/ +/*smoothies #9 is a vertical flip*/ + +#endif /* BACKGRND_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/cJSON.cpp b/alienblaster/project/jni/application/opentyrian/src/cJSON.cpp new file mode 100644 index 000000000..2435dc9c4 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/cJSON.cpp @@ -0,0 +1,680 @@ +/* + Copyright (c) 2009 Dave Gamble + Copyright (c) 2009 The OpenTyrian Development Team + + 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 or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +// cJSON +// JSON parser in C. + +#include "cJSON.h" +#include "mingw_fixes.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static void *(*cJSON_malloc)( size_t ) = malloc; +static void *(*cJSON_realloc)( void *, size_t ) = realloc; +static void (*cJSON_free)( void *ptr ) = free; + +// helper for compilers without strdup +static char *cJSON_strdup( const char *str ) +{ + size_t size = strlen(str) + 1; + char *copy = (char *)cJSON_malloc(size); + + if (copy != NULL) + memcpy(copy, str, size); + + return copy; +} + +// helper for compilers without strcasecmp +static int cJSON_strcasecmp( const char *s1, const char *s2 ) +{ + for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2) + if (*s1 == 0) + return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + +// construct empty item +static cJSON *cJSON_NewItem( cJSON_Type type ) +{ + cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON)); + + if (node != NULL) + { + node->type = type; + node->child = + node->prev = + node->next = NULL; + + node->string = NULL; + + node->valuestring = NULL; + node->valueint = + node->valuedouble = 0; + } + + return node; +} + +// destroy item chain +void cJSON_Delete( cJSON *item ) +{ + while (item != NULL) + { + if (item->child) + cJSON_Delete(item->child); + + cJSON *next = item->next; + + if (item->string) + cJSON_free(item->string); + if (item->valuestring) + cJSON_free(item->valuestring); + cJSON_free(item); + + item = next; + } +} + +// parser/emitter prototypes + +static const char *parse_value( cJSON *item, const char *in ); +static char *print_value(cJSON *item,int depth); + +static const char *parse_number( cJSON *item, const char *in ); +static char *print_number( cJSON *item ); + +static const char *parse_string(cJSON *item,const char *str); +static char *print_string(cJSON *item); + +static const char *parse_array_or_object( cJSON *item, const char *in, cJSON_Type type ); +static char *print_array(cJSON *item,int depth); +static char *print_object(cJSON *item,int depth); + +static inline const char *parse_array( cJSON *item, const char *in ) +{ + return parse_array_or_object(item, in, cJSON_Array); +} +static inline const char *parse_object( cJSON *item, const char *in ) +{ + return parse_array_or_object(item, in, cJSON_Object); +} + +// helper to skip whitespace +static inline const char *skip_space( const char *str ) +{ + if (str != NULL) + while (isspace(*str)) + ++str; + return str; +} + +// parse root of JSON into cJSON item +cJSON *cJSON_Parse( const char *in ) +{ + cJSON *item = cJSON_NewItem(cJSON_NULL); + + if (item != NULL) + { + if (parse_value(item, skip_space(in)) == NULL) // if malformed or out-of-memory + { + cJSON_Delete(item); + item = NULL; + } + } + + return item; +} + +// emit cJSON item as JSON value +char *cJSON_Print( cJSON *item ) +{ + return print_value(item, 0); +} + +// parse JSON value into cJSON item +static const char *parse_value( cJSON *item, const char *in ) +{ + if (in == NULL) + return in; + + if (!strncmp(in, "null", 4)) + { + item->type = cJSON_NULL; + return in + 4; + } + if (!strncmp(in, "false", 5)) + { + item->type = cJSON_False; + return in + 5; + } + if (!strncmp(in, "true", 4)) + { + item->type = cJSON_True; + return in + 4; + } + if (*in == '\"') + return parse_string(item, in); + if (*in == '-' || (*in >= '0' && *in <= '9')) + return parse_number(item, in); + if (*in == '[') + return parse_array(item, in); + if (*in == '{') + return parse_object(item, in); + + return NULL; // malformed: expected value +} + +// emit cJSON item as JSON value +static char *print_value( cJSON *item, int depth ) +{ + char *out = NULL; + + switch (item->type) + { + case cJSON_NULL: + out = cJSON_strdup("null"); + break; + case cJSON_False: + out = cJSON_strdup("false"); + break; + case cJSON_True: + out = cJSON_strdup("true"); + break; + case cJSON_Number: + out = print_number(item); + break; + case cJSON_String: + out = print_string(item); + break; + case cJSON_Array: + out = print_array(item, depth); + break; + case cJSON_Object: + out = print_object(item, depth); + break; + } + + return out; +} + +// parse JSON number value into cJSON item +static const char *parse_number( cJSON *item, const char *in ) +{ + double n = 0; + int sign = 1, decimal_shift = 0; + int exponent_sign = 1, exponent = 0; + + if (*in == '-') + sign = -1, ++in; + + // integer part + if (*in == '0') + ++in; + else if (*in >= '1' && *in <= '9') + do + n = (n * 10.0) + (*(in++) - '0'); + while (*in >= '0' && *in <= '9'); + + // fractional part + if (*in == '.') + { + ++in; + + while (*in >= '0' && *in <= '9') + n = (n * 10.0) + (*(in++) - '0'), decimal_shift--; + } + + // exponent part + if (*in == 'e' || *in == 'E') + { + ++in; + + if (*in == '+') + ++in; + else if (*in == '-') + exponent_sign = -1, ++in; + + while (*in >= '0' && *in <= '9') + exponent = (exponent * 10) + (*(in++) - '0'); + } + + // number = +/- number.fraction * (10 ^ +/- exponent) + n = sign * n * pow(10.0, decimal_shift + exponent_sign * exponent); + + item->valuedouble = n; + item->valueint = n; + item->type = cJSON_Number; + + return in; +} + +// emit string containing numeric value of cJSON item +static char *print_number( cJSON *item ) +{ + char *str = (char *)cJSON_malloc(DBL_DIG + 10); + snprintf(str, DBL_DIG + 10, "%.*g", DBL_DIG, item->valuedouble); + return str; +} + +// Parse the input text into an unescaped cstring, and populate item. +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; + if (*str!='\"') return 0; // not a string! + + while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // skip escaped quotes. + + out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr>31) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. + sscanf(ptr+1,"%4x",&uc); // get the unicode char. + len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; + + switch (len) { + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len;ptr+=4; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +// Render the cstring provided to an escaped version that can be printed. +static char *print_string_ptr(const char *str) +{ + const char *ptr;char *ptr2,*out;int len=0; + + ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + + out=(char*)cJSON_malloc(len+3); + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: ptr2--; break; // eviscerate with prejudice. + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +// Invote print_string_ptr (which is useful) on an item. +static char *print_string(cJSON *item) +{ + return (item->valuestring != NULL) ? print_string_ptr(item->valuestring) : cJSON_strdup(""); +} + +// parse JSON array/object into cJSON item chain +static const char *parse_array_or_object( cJSON *const item, const char *in, cJSON_Type type ) +{ + assert(type == cJSON_Array || type == cJSON_Object); + + const char opening = (type == cJSON_Object) ? '{' : '[', + closing = (type == cJSON_Object) ? '}' : ']'; + + if (*in != opening) // not an array/object! + return NULL; + else + in = skip_space(++in); + + item->type = type; + + if (*in == closing) // empty array/object + return ++in; + + cJSON *prev_child = NULL; + for (; ; ) + { + cJSON *child = cJSON_NewItem(cJSON_NULL); + if (child == NULL) // memory fail + return NULL; + + if (prev_child == NULL) + { + // attach first child to parent + item->child = child; + } + else + { + // attach other children to older sibling + prev_child->next = child; + child->prev = prev_child; + } + + if (type == cJSON_Object) + { + // object children have identifier string + + in = skip_space(parse_string(child, skip_space(in))); + if (in == NULL) // malformed or memory fail + return NULL; + + // parse_string parses into the item's value; we can use it to parse the identifier string, we just have to move the results + child->string = child->valuestring; + child->valuestring = NULL; + + if (*in != ':') // malformed + return NULL; + else + ++in; + } + + in = skip_space(parse_value(child, skip_space(in))); + if (in == NULL) // malformed or memory fail + return NULL; + + prev_child = child; + + if (*in == ',') + ++in; + else + break; + } + + if (*in == closing) // end of array/object + return ++in; + + return NULL; // malformed +} + +// Render an array to text +static char *print_array(cJSON *item,int depth) +{ + char *out, *ptr; + size_t len = 3; // minimum needed to print empty array + + ptr = out = (char*)cJSON_malloc(len); + + strcpy(ptr, "["); + ptr += 1; + + cJSON *child = item->child; + + while (child) + { + char *ret = print_value(child, depth + 1); + if (!ret) + { + cJSON_free(out); + return NULL; + } + size_t ret_len = strlen(ret); + + len += ret_len + 2; + ptr = out = (char*)cJSON_realloc(out, len); + ptr += strlen(out); + + strcpy(ptr, ret); // strcat(out, ret); + ptr += ret_len; + + cJSON_free(ret); + + if (child->next) + { + strcpy(ptr, ", "); // strcat(out, ", "); + ptr += 2; + } + + child = child->next; + } + + strcpy(ptr, "]"); // strcat(out, "]"); + + return out; +} + +// Render an object to text. +static char *print_object(cJSON *item,int depth) +{ + char *out, *ptr; + size_t len = 4 + depth; // minimum needed to print empty object + + ++depth; + + ptr = out = (char*)cJSON_malloc(len); + + strcpy(ptr, "{\n"); + ptr += 2; + + cJSON *child = item->child; + + while (child) + { + char *str = print_string_ptr(child->string); + if (!str) + { + cJSON_free(out); + return NULL; + } + size_t str_len = strlen(str); + + char *ret = print_value(child, depth); + if (!ret) + { + cJSON_free(str); + cJSON_free(out); + return NULL; + } + size_t ret_len = strlen(ret); + + len += depth + str_len + ret_len + 4; + out = (char*)cJSON_realloc(out, len); + ptr = out + strlen(out); + + for (int i = 0; i < depth; ++i) + *(ptr++) = '\t'; + + strcpy(ptr, str); // strcat(out, str); + ptr += str_len; + + cJSON_free(str); + + strcpy(ptr, ":\t"); // strcat(out, ":\t"); + ptr += 2; + + strcpy(ptr, ret); // strcat(out, ret); + ptr += ret_len; + + cJSON_free(ret); + + if (child->next) + { + strcpy(ptr, ",\n"); // strcat(out, ",\n"); + ptr += 2; + } + else + { + strcpy(ptr, "\n"); // strcat(out, "\n"); + ptr += 1; + } + + child = child->next; + } + + --depth; + + for (int i = 0; i < depth; ++i) + *(ptr++) = '\t'; + + strcpy(ptr, "}"); // strcat(out, "}"); + + return out; +} + +// Get Array size/item / object item. +int cJSON_GetArraySize( cJSON *array ) +{ + int size = 0; + cJSON *item = array->child; + while (item != NULL) + item = item->next, ++size; + return size; +} +cJSON *cJSON_GetArrayItem( cJSON *array, int index ) +{ + cJSON *item = array->child; + while (item != NULL && index > 0) + item = item->next, --index; + return item; +} +cJSON *cJSON_GetObjectItem( cJSON *object, const char *string) +{ + cJSON *item=object->child; + while (item != NULL && cJSON_strcasecmp(item->string, string) != 0) + item = item->next; + return item; +} + +cJSON *cJSON_CreateOrGetObjectItem( cJSON *object, const char *string ) +{ + cJSON *child = cJSON_GetObjectItem(object, string); + if (child == NULL) + cJSON_AddItemToObject(object, string, child = cJSON_CreateNull()); + + return child; +} + +// Utility for array list handling. +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} + +// Add item to array/object. +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} + +// remove all items from array/object +void cJSON_ClearArray( cJSON *array ) +{ + cJSON_Delete(array->child); + array->child = NULL; +} + +// create basic types + +cJSON *cJSON_CreateNull( void ) +{ + return cJSON_NewItem(cJSON_NULL); +} +cJSON *cJSON_CreateBoolean( bool value ) +{ + return cJSON_NewItem(value ? cJSON_True : cJSON_False); +} +cJSON *cJSON_CreateNumber( double value ) +{ + cJSON *item = cJSON_NewItem(cJSON_Number); + item->valueint = item->valuedouble = value; + return item; +} +cJSON *cJSON_CreateString( const char *value ) +{ + cJSON *item = cJSON_NewItem(cJSON_String); + item->valuestring = cJSON_strdup(value); + return item; +} +cJSON *cJSON_CreateArray( void ) +{ + return cJSON_NewItem(cJSON_Array); +} +cJSON *cJSON_CreateObject( void ) +{ + return cJSON_NewItem(cJSON_Object); +} + +void cJSON_ForceType( cJSON *item, cJSON_Type type ) +{ + if (item->type != type) + { + cJSON_Delete(item->child); + item->child = NULL; + + item->type = type; + } +} + +void cJSON_SetBoolean( cJSON *item, bool value ) +{ + cJSON_ForceType(item, value ? cJSON_True : cJSON_False); +} +void cJSON_SetNumber( cJSON *item, double value ) +{ + cJSON_ForceType(item, cJSON_Number); + item->valueint = item->valuedouble = value; +} +void cJSON_SetString( cJSON *item, const char *value ) +{ + cJSON_ForceType(item, cJSON_String); + cJSON_free(item->valuestring); + item->valuestring = cJSON_strdup(value); +} + +// Create Arrays: +cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;ichild=n;else suffix_object(p,n);p=n;}return a;} diff --git a/alienblaster/project/jni/application/opentyrian/src/cJSON.h b/alienblaster/project/jni/application/opentyrian/src/cJSON.h new file mode 100644 index 000000000..6146150aa --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/cJSON.h @@ -0,0 +1,117 @@ +/* + Copyright (c) 2009 Dave Gamble + Copyright (c) 2009 The OpenTyrian Development Team + + 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 or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +typedef enum +{ + cJSON_NULL, + cJSON_False, + cJSON_True, + cJSON_Number, + cJSON_String, + cJSON_Array, + cJSON_Object +} +cJSON_Type; + +typedef struct cJSON +{ + cJSON_Type type; // type of this item + + // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem + struct cJSON *next, *prev; // sibling items in chain (parent item is array or object) + struct cJSON *child; // chain of child items (this item is array or object) + + char *string; // identifying string of this item (parent item is object) + + char *valuestring; // The item's string, if type==cJSON_String + int valueint; // The item's number, if type==cJSON_Number + double valuedouble; // The item's number, if type==cJSON_Number +} +cJSON; + + +// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. +cJSON *cJSON_Parse(const char *value); +// Render a cJSON entity to text for transfer/storage. Free the char* when finished. +char *cJSON_Print(cJSON *item); +// Delete a cJSON entity and all subentities. +void cJSON_Delete(cJSON *c); + +// Returns the number of items in an array (or object). +int cJSON_GetArraySize(cJSON *array); +// Retrieve item number "item" from array "array". Returns NULL if unsuccessful. +cJSON *cJSON_GetArrayItem(cJSON *array,int item); +// Get item "string" from object. Case insensitive. +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +cJSON *cJSON_CreateOrGetObjectItem( cJSON *object, const char *string ); + +// These calls create a cJSON item of the appropriate type. +cJSON *cJSON_CreateNull( void ); +cJSON *cJSON_CreateBoolean( bool ); +cJSON *cJSON_CreateNumber( double ); +cJSON *cJSON_CreateString( const char * ); +cJSON *cJSON_CreateArray( void ); +cJSON *cJSON_CreateObject( void ); + +void cJSON_ForceType( cJSON *, cJSON_Type ); + +void cJSON_SetBoolean( cJSON *, bool ); +void cJSON_SetNumber( cJSON *, double ); +void cJSON_SetString( cJSON *, const char * ); + +// These utilities create an Array of count items. +cJSON *cJSON_CreateIntArray(int *numbers,int count); +cJSON *cJSON_CreateFloatArray(float *numbers,int count); +cJSON *cJSON_CreateDoubleArray(double *numbers,int count); +cJSON *cJSON_CreateStringArray(const char **strings,int count); + +// Append item to the specified array/object. +void cJSON_AddItemToArray(cJSON *array, cJSON *item); +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); + +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +void cJSON_ClearArray( cJSON *array ); +#define cJSON_ClearObject( object ) cJSON_ClearArray(object) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/alienblaster/project/jni/application/opentyrian/src/config.cpp b/alienblaster/project/jni/application/opentyrian/src/config.cpp new file mode 100644 index 000000000..5beff05ff --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/config.cpp @@ -0,0 +1,1040 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "episodes.h" +#include "file.h" +#include "joystick.h" +#include "loudness.h" +#include "mtrand.h" +#include "nortsong.h" +#include "opentyr.h" +#include "player.h" +#include "varz.h" +#include "vga256d.h" +#include "video.h" +#include "video_scale.h" + +#include +#include + + +/* Configuration Load/Save handler */ + +const JE_byte cryptKey[10] = /* [1..10] */ +{ + 15, 50, 89, 240, 147, 34, 86, 9, 32, 208 +}; + +const JE_KeySettingType defaultKeySettings = +{ + SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, SDLK_SPACE, SDLK_RETURN, SDLK_LCTRL, SDLK_LALT +/* 72, 80, 75, 77, 57, 28, 29, 56*/ +}; + +const char defaultHighScoreNames[34][23] = /* [1..34] of string [22] */ +{/*1P*/ +/*TYR*/ "The Prime Chair", /*13*/ + "Transon Lohk", + "Javi Onukala", + "Mantori", + "Nortaneous", + "Dougan", + "Reid", + "General Zinglon", + "Late Gyges Phildren", + "Vykromod", + "Beppo", + "Borogar", + "ShipMaster Carlos", + +/*OTHER*/ "Jill", /*5*/ + "Darcy", + "Jake Stone", + "Malvineous Havershim", + "Marta Louise Velasquez", + +/*JAZZ*/ "Jazz Jackrabbit", /*3*/ + "Eva Earlong", + "Devan Shell", + +/*OMF*/ "Crystal Devroe", /*11*/ + "Steffan Tommas", + "Milano Angston", + "Christian", + "Shirro", + "Jean-Paul", + "Ibrahim Hothe", + "Angel", + "Cossette Akira", + "Raven", + "Hans Kreissack", + +/*DARE*/ "Tyler", /*2*/ + "Rennis the Rat Guard" +}; + +const char defaultTeamNames[22][25] = /* [1..22] of string [24] */ +{ + "Jackrabbits", + "Team Tyrian", + "The Elam Brothers", + "Dare to Dream Team", + "Pinball Freaks", + "Extreme Pinball Freaks", + "Team Vykromod", + "Epic All-Stars", + "Hans Keissack's WARriors", + "Team Overkill", + "Pied Pipers", + "Gencore Growlers", + "Microsol Masters", + "Beta Warriors", + "Team Loco", + "The Shellians", + "Jungle Jills", + "Murderous Malvineous", + "The Traffic Department", + "Clan Mikal", + "Clan Patrok", + "Carlos' Crawlers" +}; + + +const JE_EditorItemAvailType initialItemAvail = +{ + 1,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* Front/Rear Weapons 1-38 */ + 0,0,0,0,0,0,0,0,0,0,1, /* Fill */ + 1,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0,0, /* Sidekicks 51-68 */ + 0,0,0,0,0,0,0,0,0,0,0, /* Fill */ + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Special Weapons 81-93 */ + 0,0,0,0,0 /* Fill */ +}; + +/* Last 2 bytes = Word + * + * Max Value = 1680 + * X div 60 = Armor (1-28) + * X div 168 = Shield (1-12) + * X div 280 = Engine (1-06) + */ + + +JE_boolean smoothies[9] = /* [1..9] */ +{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + +JE_byte starShowVGASpecialCode; + +/* Stars */ +StarDatType starDat[MAX_STARS]; /* [1..Maxstars] */ +JE_word starY; + + +/* CubeData */ +JE_word lastCubeMax, cubeMax; +JE_word cubeList[4]; /* [1..4] */ + +/* High-Score Stuff */ +JE_boolean gameHasRepeated; // can only get highscore on first play-through + +/* Difficulty */ +JE_shortint difficultyLevel, oldDifficultyLevel, + initialDifficulty; // can only get highscore on initial episode + +/* Player Stuff */ +uint power, lastPower, powerAdd; +JE_byte shieldWait, shieldT; + +JE_byte shotRepeat[11], shotMultiPos[11]; +JE_boolean portConfigChange, portConfigDone; + +/* Level Data */ +char lastLevelName[11], levelName[11]; /* string [10] */ +JE_byte mainLevel, nextLevel, saveLevel; /*Current Level #*/ + +/* Keyboard Junk */ +JE_KeySettingType keySettings; + +/* Configuration */ +JE_shortint levelFilter, levelFilterNew, levelBrightness, levelBrightnessChg; +JE_boolean filtrationAvail, filterActive, filterFade, filterFadeStart; + +JE_boolean gameJustLoaded; + +JE_boolean galagaMode; + +JE_boolean extraGame; + +JE_boolean twoPlayerMode, twoPlayerLinked, onePlayerAction, superTyrian; +JE_boolean trentWin = false; +JE_byte superArcadeMode; + +JE_byte superArcadePowerUp; + +JE_real linkGunDirec; +JE_byte inputDevice[2] = { 1, 2 }; // 0:any 1:keyboard 2:mouse 3+:joystick + +JE_byte secretHint; +JE_byte background3over; +JE_byte background2over; +JE_byte gammaCorrection; +JE_boolean superPause = false; +JE_boolean explosionTransparent, + youAreCheating, + displayScore, + background2, smoothScroll, wild, superWild, starActive, + topEnemyOver, + skyEnemyOverAll, + background2notTransparent; + +JE_byte soundEffects; // dummy value for config +JE_byte versionNum; /* SW 1.0 and SW/Reg 1.1 = 0 or 1 + * EA 1.2 = 2 */ + +JE_byte fastPlay; +JE_boolean pentiumMode; + +/* Savegame files */ +JE_byte gameSpeed; +JE_byte processorType; /* 1=386 2=486 3=Pentium Hyper */ + +JE_SaveFilesType saveFiles; /*array[1..saveLevelnum] of savefiletype;*/ +JE_SaveGameTemp saveTemp; + +JE_word editorLevel; /*Initial value 800*/ + + +cJSON *load_json( const char *filename ) +{ + FILE *f = dir_fopen_warn(get_user_directory(), filename, "rb"); + if (f == NULL) + return NULL; + + size_t buffer_len = ftell_eof(f); + char *buffer = (char *)malloc(buffer_len + 1); + + fread(buffer, 1, buffer_len, f); + buffer[buffer_len] = '\0'; + + fclose(f); + + cJSON *root = cJSON_Parse(buffer); + + free(buffer); + + return root; +} + +void save_json( cJSON *root, const char *filename ) +{ + FILE *f = dir_fopen_warn(get_user_directory(), filename, "w+"); + if (f == NULL) + return; + + char *buffer = cJSON_Print(root); + + if (buffer != NULL) + { + fputs(buffer, f); + free(buffer); + } + + fclose(f); +} + +bool load_opentyrian_config( void ) +{ + // defaults + fullscreen_enabled = false; + set_scaler_by_name("Scale2x"); + + cJSON *root = load_json("opentyrian.conf"); + if (root == NULL) + return false; + + cJSON *section = cJSON_GetObjectItem(root, "video"); + if (section != NULL) + { + cJSON *setting; + + if ((setting = cJSON_GetObjectItem(section, "fullscreen"))) + fullscreen_enabled = (setting->type == cJSON_True); + + if ((setting = cJSON_GetObjectItem(section, "scaler"))) + set_scaler_by_name(setting->valuestring); + } + + cJSON_Delete(root); + + return true; +} + +bool save_opentyrian_config( void ) +{ + cJSON *root = load_json("opentyrian.conf"); + if (root == NULL) + root = cJSON_CreateObject(); + + cJSON *section; + + section = cJSON_CreateOrGetObjectItem(root, "video"); + cJSON_ForceType(section, cJSON_Object); + + { + cJSON *setting; + + setting = cJSON_CreateOrGetObjectItem(section, "fullscreen"); + cJSON_SetBoolean(setting, fullscreen_enabled); + + setting = cJSON_CreateOrGetObjectItem(section, "scaler"); + cJSON_SetString(setting, scalers[scaler].name); + } + + save_json(root, "opentyrian.conf"); + + cJSON_Delete(root); + + return true; +} + + +void JE_setupStars( void ) +{ + int z; + + for (z = MAX_STARS; z--; ) + { + starDat[z].sLoc = (mt_rand() % 320) + (mt_rand() % 200) * VGAScreen->pitch; + starDat[z].sMov = ((mt_rand() % 3) + 2) * VGAScreen->pitch; + starDat[z].sC = (mt_rand() % 16) + (9 * 16); + } +} + +static void playeritems_to_pitems( JE_PItemsType pItems, PlayerItems *items, JE_byte initial_episode_num ) +{ + pItems[0] = items->weapon[FRONT_WEAPON].id; + pItems[1] = items->weapon[REAR_WEAPON].id; + pItems[2] = items->super_arcade_mode; + pItems[3] = items->sidekick[LEFT_SIDEKICK]; + pItems[4] = items->sidekick[RIGHT_SIDEKICK]; + pItems[5] = items->generator; + pItems[6] = items->sidekick_level; + pItems[7] = items->sidekick_series; + pItems[8] = initial_episode_num; + pItems[9] = items->shield; + pItems[10] = items->special; + pItems[11] = items->ship; +} + +static void pitems_to_playeritems( PlayerItems *items, JE_PItemsType pItems, JE_byte *initial_episode_num ) +{ + items->weapon[FRONT_WEAPON].id = pItems[0]; + items->weapon[REAR_WEAPON].id = pItems[1]; + items->super_arcade_mode = pItems[2]; + items->sidekick[LEFT_SIDEKICK] = pItems[3]; + items->sidekick[RIGHT_SIDEKICK] = pItems[4]; + items->generator = pItems[5]; + items->sidekick_level = pItems[6]; + items->sidekick_series = pItems[7]; + if (initial_episode_num != NULL) + *initial_episode_num = pItems[8]; + items->shield = pItems[9]; + items->special = pItems[10]; + items->ship = pItems[11]; +} + +void JE_saveGame( JE_byte slot, const char *name ) +{ + saveFiles[slot-1].initialDifficulty = initialDifficulty; + saveFiles[slot-1].gameHasRepeated = gameHasRepeated; + saveFiles[slot-1].level = saveLevel; + + if (superTyrian) + player[0].items.super_arcade_mode = SA_SUPERTYRIAN; + else if (superArcadeMode == SA_NONE && onePlayerAction) + player[0].items.super_arcade_mode = SA_ARCADE; + else + player[0].items.super_arcade_mode = superArcadeMode; + + playeritems_to_pitems(saveFiles[slot-1].items, &player[0].items, initial_episode_num); + + if (twoPlayerMode) + playeritems_to_pitems(saveFiles[slot-1].lastItems, &player[1].items, 0); + else + playeritems_to_pitems(saveFiles[slot-1].lastItems, &player[0].last_items, 0); + + saveFiles[slot-1].score = player[0].cash; + saveFiles[slot-1].score2 = player[1].cash; + + memcpy(&saveFiles[slot-1].levelName, &lastLevelName, sizeof(lastLevelName)); + saveFiles[slot-1].cubes = lastCubeMax; + + if (strcmp(lastLevelName, "Completed") == 0) + { + temp = episodeNum - 1; + if (temp < 1) + { + temp = 4; /* JE: {Episodemax is 4 for completion purposes} */ + } + saveFiles[slot-1].episode = temp; + } + else + { + saveFiles[slot-1].episode = episodeNum; + } + + saveFiles[slot-1].difficulty = difficultyLevel; + saveFiles[slot-1].secretHint = secretHint; + saveFiles[slot-1].input1 = inputDevice[0]; + saveFiles[slot-1].input2 = inputDevice[1]; + + strcpy(saveFiles[slot-1].name, name); + + for (uint port = 0; port < 2; ++port) + { + // if two-player, use first player's front and second player's rear weapon + saveFiles[slot-1].power[port] = player[twoPlayerMode ? port : 0].items.weapon[port].power; + } + + JE_saveConfiguration(); +} + +void JE_loadGame( JE_byte slot ) +{ + JE_byte temp5; + + superTyrian = false; + onePlayerAction = false; + twoPlayerMode = false; + extraGame = false; + galagaMode = false; + + initialDifficulty = saveFiles[slot-1].initialDifficulty; + gameHasRepeated = saveFiles[slot-1].gameHasRepeated; + twoPlayerMode = (slot-1) > 10; + difficultyLevel = saveFiles[slot-1].difficulty; + + pitems_to_playeritems(&player[0].items, saveFiles[slot-1].items, &initial_episode_num); + + superArcadeMode = player[0].items.super_arcade_mode; + + if (superArcadeMode == SA_SUPERTYRIAN) + superTyrian = true; + if (superArcadeMode != SA_NONE) + onePlayerAction = true; + if (superArcadeMode > SA_NORTSHIPZ) + superArcadeMode = SA_NONE; + + if (twoPlayerMode) + { + onePlayerAction = false; + + pitems_to_playeritems(&player[1].items, saveFiles[slot-1].lastItems, NULL); + } + else + { + pitems_to_playeritems(&player[0].last_items, saveFiles[slot-1].lastItems, NULL); + } + + /* Compatibility with old version */ + if (player[1].items.sidekick_level < 101) + { + player[1].items.sidekick_level = 101; + player[1].items.sidekick_series = player[1].items.sidekick[LEFT_SIDEKICK]; + } + + player[0].cash = saveFiles[slot-1].score; + player[1].cash = saveFiles[slot-1].score2; + + mainLevel = saveFiles[slot-1].level; + cubeMax = saveFiles[slot-1].cubes; + lastCubeMax = cubeMax; + + secretHint = saveFiles[slot-1].secretHint; + inputDevice[0] = saveFiles[slot-1].input1; + inputDevice[1] = saveFiles[slot-1].input2; + + for (uint port = 0; port < 2; ++port) + { + // if two-player, use first player's front and second player's rear weapon + player[twoPlayerMode ? port : 0].items.weapon[port].power = saveFiles[slot-1].power[port]; + } + + temp5 = saveFiles[slot-1].episode; + + memcpy(&levelName, &saveFiles[slot-1].levelName, sizeof(levelName)); + + if (strcmp(levelName, "Completed") == 0) + { + if (temp5 == 4) + { + temp5 = 1; + } else if (temp5 < 4) { + temp5++; + } + /* Increment 1-3 to 2-4. Episode 4 goes to 1. Episode 5 stands still. */ + } + + JE_initEpisode(temp5); + saveLevel = mainLevel; + memcpy(&lastLevelName, &levelName, sizeof(levelName)); +} + +void JE_initProcessorType( void ) +{ + /* SYN: Originally this proc looked at your hardware specs and chose appropriate options. We don't care, so I'll just set + decent defaults here. */ + + wild = false; + superWild = false; + smoothScroll = true; + explosionTransparent = true; + filtrationAvail = false; + background2 = true; + displayScore = true; + + switch (processorType) + { + case 1: /* 386 */ + background2 = false; + displayScore = false; + explosionTransparent = false; + break; + case 2: /* 486 - Default */ + break; + case 3: /* High Detail */ + smoothScroll = false; + break; + case 4: /* Pentium */ + wild = true; + filtrationAvail = true; + break; + case 5: /* Nonstandard VGA */ + smoothScroll = false; + break; + case 6: /* SuperWild */ + wild = true; + superWild = true; + filtrationAvail = true; + break; + } + + switch (gameSpeed) + { + case 1: /* Slug Mode */ + fastPlay = 3; + break; + case 2: /* Slower */ + fastPlay = 4; + break; + case 3: /* Slow */ + fastPlay = 5; + break; + case 4: /* Normal */ + fastPlay = 0; + break; + case 5: /* Pentium Hyper */ + fastPlay = 1; + break; + } + +} + +void JE_setNewGameSpeed( void ) +{ + pentiumMode = false; + + switch (fastPlay) + { + case 0: + speed = 0x4300; + smoothScroll = true; + frameCountMax = 2; + break; + case 1: + speed = 0x3000; + smoothScroll = true; + frameCountMax = 2; + break; + case 2: + speed = 0x2000; + smoothScroll = false; + frameCountMax = 2; + break; + case 3: + speed = 0x5300; + smoothScroll = true; + frameCountMax = 4; + break; + case 4: + speed = 0x4300; + smoothScroll = true; + frameCountMax = 3; + break; + case 5: + speed = 0x4300; + smoothScroll = true; + frameCountMax = 2; + pentiumMode = true; + break; + } + + frameCount = frameCountMax; + JE_resetTimerInt(); + JE_setTimerInt(); +} + +void JE_encryptSaveTemp( void ) +{ + JE_SaveGameTemp s3; + JE_word x; + JE_byte y; + + memcpy(&s3, &saveTemp, sizeof(s3)); + + y = 0; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y += s3[x]; + } + saveTemp[SAVE_FILE_SIZE] = y; + + y = 0; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y -= s3[x]; + } + saveTemp[SAVE_FILE_SIZE+1] = y; + + y = 1; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y = (y * s3[x]) + 1; + } + saveTemp[SAVE_FILE_SIZE+2] = y; + + y = 0; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y = y ^ s3[x]; + } + saveTemp[SAVE_FILE_SIZE+3] = y; + + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + saveTemp[x] = saveTemp[x] ^ cryptKey[(x+1) % 10]; + if (x > 0) + { + saveTemp[x] = saveTemp[x] ^ saveTemp[x - 1]; + } + } +} + +void JE_decryptSaveTemp( void ) +{ + JE_boolean correct = true; + JE_SaveGameTemp s2; + int x; + JE_byte y; + + /* Decrypt save game file */ + for (x = (SAVE_FILE_SIZE - 1); x >= 0; x--) + { + s2[x] = (JE_byte)saveTemp[x] ^ (JE_byte)(cryptKey[(x+1) % 10]); + if (x > 0) + { + s2[x] ^= (JE_byte)saveTemp[x - 1]; + } + + } + + /* for (x = 0; x < SAVE_FILE_SIZE; x++) printf("%c", s2[x]); */ + + /* Check save file for correctitude */ + y = 0; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y += s2[x]; + } + if (saveTemp[SAVE_FILE_SIZE] != y) + { + correct = false; + printf("Failed additive checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE], y); + } + + y = 0; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y -= s2[x]; + } + if (saveTemp[SAVE_FILE_SIZE+1] != y) + { + correct = false; + printf("Failed subtractive checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+1], y); + } + + y = 1; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y = (y * s2[x]) + 1; + } + if (saveTemp[SAVE_FILE_SIZE+2] != y) + { + correct = false; + printf("Failed multiplicative checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+2], y); + } + + y = 0; + for (x = 0; x < SAVE_FILE_SIZE; x++) + { + y = y ^ s2[x]; + } + if (saveTemp[SAVE_FILE_SIZE+3] != y) + { + correct = false; + printf("Failed XOR'd checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+3], y); + } + + /* Barf and die if save file doesn't validate */ + if (!correct) + { + fprintf(stderr, "Error reading save file!\n"); + exit(255); + } + + /* Keep decrypted version plz */ + memcpy(&saveTemp, &s2, sizeof(s2)); +} + +#ifndef TARGET_MACOSX +const char *get_user_directory( void ) +{ + static char user_dir[500] = ""; + + if (strlen(user_dir) == 0) + { +#ifdef TARGET_UNIX + if (getenv("HOME")) + snprintf(user_dir, sizeof(user_dir), "%s/.opentyrian", getenv("HOME")); +#else + strcpy(user_dir, "."); +#endif // TARGET_UNIX + } + + return user_dir; +} +#endif // TARGET_MACOSX + +// for compatibility +Uint8 joyButtonAssign[4] = {1, 4, 5, 5}; +Uint8 inputDevice_ = 0, jConfigure = 0, midiPort = 1; + +void JE_loadConfiguration( void ) +{ + FILE *fi; + int z; + JE_byte *p; + int y; + + fi = dir_fopen_warn(get_user_directory(), "tyrian.cfg", "rb"); + if (fi && ftell_eof(fi) == 20 + sizeof(keySettings)) + { + /* SYN: I've hardcoded the sizes here because the .CFG file format is fixed + anyways, so it's not like they'll change. */ + background2 = 0; + efread(&background2, 1, 1, fi); + efread(&gameSpeed, 1, 1, fi); + + efread(&inputDevice_, 1, 1, fi); + efread(&jConfigure, 1, 1, fi); + + efread(&versionNum, 1, 1, fi); + + efread(&processorType, 1, 1, fi); + efread(&midiPort, 1, 1, fi); + efread(&soundEffects, 1, 1, fi); + efread(&gammaCorrection, 1, 1, fi); + efread(&difficultyLevel, 1, 1, fi); + + efread(joyButtonAssign, 1, 4, fi); + + efread(&tyrMusicVolume, 2, 1, fi); + efread(&fxVolume, 2, 1, fi); + + efread(inputDevice, 1, 2, fi); + + efread(keySettings, sizeof(*keySettings), COUNTOF(keySettings), fi); + + fclose(fi); + } + else + { + printf("\nInvalid or missing TYRIAN.CFG! Continuing using defaults.\n\n"); + + soundEffects = 1; + memcpy(&keySettings, &defaultKeySettings, sizeof(keySettings)); + background2 = true; + tyrMusicVolume = fxVolume = 128; + gammaCorrection = 0; + processorType = 3; + gameSpeed = 4; + } + + load_opentyrian_config(); + + if (tyrMusicVolume > 255) + tyrMusicVolume = 255; + if (fxVolume > 255) + fxVolume = 255; + + JE_calcFXVol(); + + set_volume(tyrMusicVolume, fxVolume); + + fi = dir_fopen_warn(get_user_directory(), "tyrian.sav", "rb"); + if (fi) + { + + fseek(fi, 0, SEEK_SET); + efread(saveTemp, 1, sizeof(saveTemp), fi); + JE_decryptSaveTemp(); + + /* SYN: The original mostly blasted the save file into raw memory. However, our lives are not so + easy, because the C struct is necessarily a different size. So instead we have to loop + through each record and load fields manually. *emo tear* :'( */ + + p = saveTemp; + for (z = 0; z < SAVE_FILES_NUM; z++) + { + memcpy(&saveFiles[z].encode, p, sizeof(JE_word)); p += 2; + saveFiles[z].encode = SDL_SwapLE16(saveFiles[z].encode); + + memcpy(&saveFiles[z].level, p, sizeof(JE_word)); p += 2; + saveFiles[z].level = SDL_SwapLE16(saveFiles[z].level); + + memcpy(&saveFiles[z].items, p, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType); + + memcpy(&saveFiles[z].score, p, sizeof(JE_longint)); p += 4; + saveFiles[z].score = SDL_SwapLE32(saveFiles[z].score); + + memcpy(&saveFiles[z].score2, p, sizeof(JE_longint)); p += 4; + saveFiles[z].score2 = SDL_SwapLE32(saveFiles[z].score2); + + /* SYN: Pascal strings are prefixed by a byte holding the length! */ + memset(&saveFiles[z].levelName, 0, sizeof(saveFiles[z].levelName)); + memcpy(&saveFiles[z].levelName, &p[1], *p); + p += 10; + + /* This was a BYTE array, not a STRING, in the original. Go fig. */ + memcpy(&saveFiles[z].name, p, 14); + p += 14; + + memcpy(&saveFiles[z].cubes, p, sizeof(JE_byte)); p++; + memcpy(&saveFiles[z].power, p, sizeof(JE_byte) * 2); p += 2; + memcpy(&saveFiles[z].episode, p, sizeof(JE_byte)); p++; + memcpy(&saveFiles[z].lastItems, p, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType); + memcpy(&saveFiles[z].difficulty, p, sizeof(JE_byte)); p++; + memcpy(&saveFiles[z].secretHint, p, sizeof(JE_byte)); p++; + memcpy(&saveFiles[z].input1, p, sizeof(JE_byte)); p++; + memcpy(&saveFiles[z].input2, p, sizeof(JE_byte)); p++; + + /* booleans were 1 byte in pascal -- working around it */ + Uint8 temp; + memcpy(&temp, p, 1); p++; + saveFiles[z].gameHasRepeated = temp != 0; + + memcpy(&saveFiles[z].initialDifficulty, p, sizeof(JE_byte)); p++; + + memcpy(&saveFiles[z].highScore1, p, sizeof(JE_longint)); p += 4; + saveFiles[z].highScore1 = SDL_SwapLE32(saveFiles[z].highScore1); + + memcpy(&saveFiles[z].highScore2, p, sizeof(JE_longint)); p += 4; + saveFiles[z].highScore2 = SDL_SwapLE32(saveFiles[z].highScore2); + + memset(&saveFiles[z].highScoreName, 0, sizeof(saveFiles[z].highScoreName)); + memcpy(&saveFiles[z].highScoreName, &p[1], *p); + p += 30; + + memcpy(&saveFiles[z].highScoreDiff, p, sizeof(JE_byte)); p++; + } + + /* SYN: This is truncating to bytes. I have no idea what this is doing or why. */ + /* TODO: Figure out what this is about and make sure it isn't broked. */ + editorLevel = (saveTemp[SIZEOF_SAVEGAMETEMP - 5] << 8) | saveTemp[SIZEOF_SAVEGAMETEMP - 6]; + + fclose(fi); + } else { + /* We didn't have a save file! Let's make up random stuff! */ + editorLevel = 800; + + for (z = 0; z < 100; z++) + { + saveTemp[SAVE_FILES_SIZE + z] = initialItemAvail[z]; + } + + for (z = 0; z < SAVE_FILES_NUM; z++) + { + saveFiles[z].level = 0; + + for (y = 0; y < 14; y++) + { + saveFiles[z].name[y] = ' '; + } + saveFiles[z].name[14] = 0; + + saveFiles[z].highScore1 = ((mt_rand() % 20) + 1) * 1000; + + if (z % 6 > 2) + { + saveFiles[z].highScore2 = ((mt_rand() % 20) + 1) * 1000; + strcpy(saveFiles[z].highScoreName, defaultTeamNames[mt_rand() % 22]); + } else { + strcpy(saveFiles[z].highScoreName, defaultHighScoreNames[mt_rand() % 34]); + } + } + } + + JE_initProcessorType(); +} + +void JE_saveConfiguration( void ) +{ +#ifdef TARGET_UNIX + if (getenv("HOME")) + { + char dir[1000]; + snprintf(dir, sizeof(dir), "%s/.opentyrian", getenv("HOME")); + mkdir(dir, 0755); + } +#endif /* HOME */ + + FILE *f; + JE_byte *p; + int z; + + p = saveTemp; + for (z = 0; z < SAVE_FILES_NUM; z++) + { + JE_SaveFileType tempSaveFile; + memcpy(&tempSaveFile, &saveFiles[z], sizeof(tempSaveFile)); + + tempSaveFile.encode = SDL_SwapLE16(tempSaveFile.encode); + memcpy(p, &tempSaveFile.encode, sizeof(JE_word)); p += 2; + + tempSaveFile.level = SDL_SwapLE16(tempSaveFile.level); + memcpy(p, &tempSaveFile.level, sizeof(JE_word)); p += 2; + + memcpy(p, &tempSaveFile.items, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType); + + tempSaveFile.score = SDL_SwapLE32(tempSaveFile.score); + memcpy(p, &tempSaveFile.score, sizeof(JE_longint)); p += 4; + + tempSaveFile.score2 = SDL_SwapLE32(tempSaveFile.score2); + memcpy(p, &tempSaveFile.score2, sizeof(JE_longint)); p += 4; + + /* SYN: Pascal strings are prefixed by a byte holding the length! */ + memset(p, 0, sizeof(tempSaveFile.levelName)); + *p = strlen(tempSaveFile.levelName); + memcpy(&p[1], &tempSaveFile.levelName, *p); + p += 10; + + /* This was a BYTE array, not a STRING, in the original. Go fig. */ + memcpy(p, &tempSaveFile.name, 14); + p += 14; + + memcpy(p, &tempSaveFile.cubes, sizeof(JE_byte)); p++; + memcpy(p, &tempSaveFile.power, sizeof(JE_byte) * 2); p += 2; + memcpy(p, &tempSaveFile.episode, sizeof(JE_byte)); p++; + memcpy(p, &tempSaveFile.lastItems, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType); + memcpy(p, &tempSaveFile.difficulty, sizeof(JE_byte)); p++; + memcpy(p, &tempSaveFile.secretHint, sizeof(JE_byte)); p++; + memcpy(p, &tempSaveFile.input1, sizeof(JE_byte)); p++; + memcpy(p, &tempSaveFile.input2, sizeof(JE_byte)); p++; + + /* booleans were 1 byte in pascal -- working around it */ + Uint8 temp = tempSaveFile.gameHasRepeated != false; + memcpy(p, &temp, 1); p++; + + memcpy(p, &tempSaveFile.initialDifficulty, sizeof(JE_byte)); p++; + + tempSaveFile.highScore1 = SDL_SwapLE32(tempSaveFile.highScore1); + memcpy(p, &tempSaveFile.highScore1, sizeof(JE_longint)); p += 4; + + tempSaveFile.highScore2 = SDL_SwapLE32(tempSaveFile.highScore2); + memcpy(p, &tempSaveFile.highScore2, sizeof(JE_longint)); p += 4; + + memset(p, 0, sizeof(tempSaveFile.highScoreName)); + *p = strlen(tempSaveFile.highScoreName); + memcpy(&p[1], &tempSaveFile.highScoreName, *p); + p += 30; + + memcpy(p, &tempSaveFile.highScoreDiff, sizeof(JE_byte)); p++; + } + + saveTemp[SIZEOF_SAVEGAMETEMP - 6] = editorLevel >> 8; + saveTemp[SIZEOF_SAVEGAMETEMP - 5] = editorLevel; + + JE_encryptSaveTemp(); + + f = dir_fopen_warn(get_user_directory(), "tyrian.sav", "wb"); + if (f) + { + efwrite(saveTemp, 1, sizeof(saveTemp), f); + fclose(f); +#if (_BSD_SOURCE || _XOPEN_SOURCE >= 500) + sync(); +#endif + } + JE_decryptSaveTemp(); + + f = dir_fopen_warn(get_user_directory(), "tyrian.cfg", "wb"); + if (f) + { + efwrite(&background2, 1, 1, f); + efwrite(&gameSpeed, 1, 1, f); + + efwrite(&inputDevice_, 1, 1, f); + efwrite(&jConfigure, 1, 1, f); + + efwrite(&versionNum, 1, 1, f); + efwrite(&processorType, 1, 1, f); + efwrite(&midiPort, 1, 1, f); + efwrite(&soundEffects, 1, 1, f); + efwrite(&gammaCorrection, 1, 1, f); + efwrite(&difficultyLevel, 1, 1, f); + efwrite(joyButtonAssign, 1, 4, f); + + efwrite(&tyrMusicVolume, 2, 1, f); + efwrite(&fxVolume, 2, 1, f); + + efwrite(inputDevice, 1, 2, f); + + efwrite(keySettings, sizeof(*keySettings), COUNTOF(keySettings), f); + + fclose(f); + } + + save_opentyrian_config(); + +#if (_BSD_SOURCE || _XOPEN_SOURCE >= 500) + sync(); +#endif +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/config.h b/alienblaster/project/jni/application/opentyrian/src/config.h new file mode 100644 index 000000000..99c9583a1 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/config.h @@ -0,0 +1,163 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef CONFIG_H +#define CONFIG_H + +#include "cJSON.h" +#include "opentyr.h" + +#include +#include "SDL.h" + + +#define SAVE_FILES_NUM (11 * 2) + +#define MAX_STARS 100 + +/* These are necessary because the size of the structure has changed from the original, but we + need to know the original sizes in order to find things in TYRIAN.SAV */ +#define SAVE_FILES_SIZE 2398 +#define SIZEOF_SAVEGAMETEMP SAVE_FILES_SIZE + 4 + 100 +#define SAVE_FILE_SIZE (SIZEOF_SAVEGAMETEMP - 4) + +/*#define SAVE_FILES_SIZE (2502 - 4) +#define SAVE_FILE_SIZE (SAVE_FILES_SIZE)*/ + +typedef SDLKey JE_KeySettingType[8]; /* [1..8] */ +typedef JE_byte JE_PItemsType[12]; /* [1..12] */ + +typedef JE_byte JE_EditorItemAvailType[100]; /* [1..100] */ + +typedef struct +{ + JE_word encode; + JE_word level; + JE_PItemsType items; + JE_longint score; + JE_longint score2; + char levelName[11]; /* string [9]; */ /* SYN: Added one more byte to match lastLevelName below */ + JE_char name[15]; /* [1..14] */ /* SYN: Added extra byte for null */ + JE_byte cubes; + JE_byte power[2]; /* [1..2] */ + JE_byte episode; + JE_PItemsType lastItems; + JE_byte difficulty; + JE_byte secretHint; + JE_byte input1; + JE_byte input2; + JE_boolean gameHasRepeated; /*See if you went from one episode to another*/ + JE_byte initialDifficulty; + + /* High Scores - Each episode has both sets of 1&2 player selections - with 3 in each */ + JE_longint highScore1, + highScore2; + char highScoreName[30]; /* string [29] */ + JE_byte highScoreDiff; +} JE_SaveFileType; + +typedef JE_SaveFileType JE_SaveFilesType[SAVE_FILES_NUM]; /* [1..savefilesnum] */ +typedef JE_byte JE_SaveGameTemp[SAVE_FILES_SIZE + 4 + 100]; /* [1..sizeof(savefilestype) + 4 + 100] */ + +typedef struct +{ + JE_byte sC; + JE_word sLoc; + JE_word sMov; +} StarDatType; + +extern const JE_byte cryptKey[10]; +extern const JE_KeySettingType defaultKeySettings; +extern const char defaultHighScoreNames[34][23]; +extern const char defaultTeamNames[22][25]; +extern const JE_EditorItemAvailType initialItemAvail; +extern JE_boolean smoothies[9]; +extern JE_byte starShowVGASpecialCode; +extern StarDatType starDat[MAX_STARS]; +extern JE_word starY; +extern JE_word lastCubeMax, cubeMax; +extern JE_word cubeList[4]; +extern JE_boolean gameHasRepeated; +extern JE_shortint difficultyLevel, oldDifficultyLevel, initialDifficulty; +extern uint power, lastPower, powerAdd; +extern JE_byte shieldWait, shieldT; + +enum +{ + SHOT_FRONT, + SHOT_REAR, + SHOT_LEFT_SIDEKICK, + SHOT_RIGHT_SIDEKICK, + SHOT_MISC, + SHOT_P2_CHARGE, + SHOT_P1_SUPERBOMB, + SHOT_P2_SUPERBOMB, + SHOT_SPECIAL, + SHOT_NORTSPARKS, + SHOT_SPECIAL2 +}; + +extern JE_byte shotRepeat[11], shotMultiPos[11]; +extern JE_boolean portConfigChange, portConfigDone; +extern char lastLevelName[11], levelName[11]; +extern JE_byte mainLevel, nextLevel, saveLevel; +extern JE_KeySettingType keySettings; +extern JE_shortint levelFilter, levelFilterNew, levelBrightness, levelBrightnessChg; +extern JE_boolean filtrationAvail, filterActive, filterFade, filterFadeStart; +extern JE_boolean gameJustLoaded; +extern JE_boolean galagaMode; +extern JE_boolean extraGame; +extern JE_boolean twoPlayerMode, twoPlayerLinked, onePlayerAction, superTyrian, trentWin; +extern JE_byte superArcadeMode; +extern JE_byte superArcadePowerUp; +extern JE_real linkGunDirec; +extern JE_byte inputDevice[2]; +extern JE_byte secretHint; +extern JE_byte background3over; +extern JE_byte background2over; +extern JE_byte gammaCorrection; +extern JE_boolean superPause, explosionTransparent, youAreCheating, displayScore, background2, smoothScroll, wild, superWild, starActive, topEnemyOver, skyEnemyOverAll, background2notTransparent; +extern JE_byte versionNum; +extern JE_byte fastPlay; +extern JE_boolean pentiumMode; +extern JE_byte gameSpeed; +extern JE_byte processorType; +extern JE_SaveFilesType saveFiles; +extern JE_SaveGameTemp saveTemp; +extern JE_word editorLevel; + +void JE_initProcessorType( void ); +void JE_setNewGameSpeed( void ); +const char *get_user_directory( void ); +void JE_loadConfiguration( void ); +void JE_saveConfiguration( void ); + +void JE_setupStars( void ); + +void JE_saveGame( JE_byte slot, const char *name ); +void JE_loadGame( JE_byte slot ); + +void JE_encryptSaveTemp( void ); +void JE_decryptSaveTemp( void ); + +cJSON *load_json( const char *filename ); +void save_json( cJSON *root, const char *filename ); + +#endif /* CONFIG_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/destruct.cpp b/alienblaster/project/jni/application/opentyrian/src/destruct.cpp new file mode 100644 index 000000000..5288a34b9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/destruct.cpp @@ -0,0 +1,2833 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* File notes: + * Two players duke it out in a Scorched Earth style game. + * Most of the variables referring to the players are global as + * they are often edited and that's how the original was written. + * + * Currently this file is at its final stage for vanilla destruct. + * Almost all of the left/right code duplications is gone. Most of the + * functions have been examined and tightened up, none of the enums + * start with '1', and the various large functions have been divided into + * smaller chunks. + * + * Destruct also supports some 'hidden' configuration that's just too awesome + * to not have available. Destruct has no configuration options in game, but + * that doesn't stop us from changing various limiting vars and letting + * people remap the keyboard. AIs may also be introduced here; fighting a + * stateless AI isn't really challenging afterall. + * + * This hidden config also allows for a hidden game mode! Though as a custom + * game mode wouldn't show up in the data files it forces us to distinguish + * between the constant DESTRUCT_MODES (5) and MAX_MODES (6). DESTRUCT_MODES + * is only used with loaded data. + * + * Things I wanted to do but can't: Remove references to VGAScreen. For + * a multitude of reasons this just isn't feasable. It would have been nice + * to increase the playing field though... + */ + +/*** Headers ***/ +#include "opentyr.h" +#include "destruct.h" + +#include "config.h" +#include "fonthand.h" +#include "helptext.h" +#include "keyboard.h" +#include "loudness.h" +#include "mtrand.h" +#include "nortsong.h" +#include "palette.h" +#include "picload.h" +#include "sprite.h" +#include "vga256d.h" +#include "video.h" + +#include + +extern JE_byte soundQueue[8]; + +/*** Defines ***/ +#define UNIT_HEIGHT 12 +#define MAX_KEY_OPTIONS 4 + +/*** Enums ***/ +enum de_state_t { STATE_INIT, STATE_RELOAD, STATE_CONTINUE }; +enum de_player_t { PLAYER_LEFT = 0, PLAYER_RIGHT = 1, MAX_PLAYERS = 2 }; +enum de_team_t { TEAM_LEFT = 0, TEAM_RIGHT = 1, MAX_TEAMS = 2 }; +enum de_mode_t { MODE_5CARDWAR = 0, MODE_TRADITIONAL, MODE_HELIASSAULT, + MODE_HELIDEFENSE, MODE_OUTGUNNED, MODE_CUSTOM, + MODE_FIRST = MODE_5CARDWAR, MODE_LAST = MODE_CUSTOM, + MAX_MODES = 6, MODE_NONE = -1 }; +enum de_unit_t { UNIT_TANK = 0, UNIT_NUKE, UNIT_DIRT, UNIT_SATELLITE, + UNIT_MAGNET, UNIT_LASER, UNIT_JUMPER, UNIT_HELI, + UNIT_FIRST = UNIT_TANK, UNIT_LAST = UNIT_HELI, + MAX_UNITS = 8, UNIT_NONE = -1 }; +enum de_shot_t { SHOT_TRACER = 0, SHOT_SMALL, SHOT_LARGE, SHOT_MICRO, + SHOT_SUPER, SHOT_DEMO, SHOT_SMALLNUKE, SHOT_LARGENUKE, + SHOT_SMALLDIRT, SHOT_LARGEDIRT, SHOT_MAGNET, SHOT_MINILASER, + SHOT_MEGALASER, SHOT_LASERTRACER, SHOT_MEGABLAST, SHOT_MINI, + SHOT_BOMB, + SHOT_FIRST = SHOT_TRACER, SHOT_LAST = SHOT_BOMB, + MAX_SHOT_TYPES = 17, SHOT_INVALID = -1 }; +enum de_expl_t { EXPL_NONE, EXPL_MAGNET, EXPL_DIRT, EXPL_NORMAL }; /* this needs a better name */ +enum de_trails_t { TRAILS_NONE, TRAILS_NORMAL, TRAILS_FULL }; +enum de_pixel_t { PIXEL_BLACK = 0, PIXEL_DIRT = 25 }; +enum de_mapflags_t { MAP_NORMAL = 0x00, MAP_WALLS = 0x01, MAP_RINGS = 0x02, + MAP_HOLES = 0x04, MAP_FUZZY = 0x08, MAP_TALL = 0x10 }; + +/* keys and moves should line up. */ +enum de_keys_t { KEY_LEFT = 0, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_CHANGE, KEY_FIRE, KEY_CYUP, KEY_CYDN, MAX_KEY = 8}; +enum de_move_t { MOVE_LEFT = 0, MOVE_RIGHT, MOVE_UP, MOVE_DOWN, MOVE_CHANGE, MOVE_FIRE, MOVE_CYUP, MOVE_CYDN, MAX_MOVE = 8}; + +/* The tracerlaser is dummied out. It works but (probably due to the low + * MAX_SHOTS) is not assigned to anything. The bomb does not work. + */ + + +/*** Structs ***/ +struct destruct_config_s { + + unsigned int max_shots; + unsigned int min_walls; + unsigned int max_walls; + unsigned int max_explosions; + unsigned int max_installations; + bool allow_custom; + bool alwaysalias; + bool jumper_straight[2]; + bool ai[2]; +}; +struct destruct_unit_s { + + /* Positioning/movement */ + unsigned int unitX; /* yep, one's an int and the other is a real */ + float unitY; + float unitYMov; + bool isYInAir; + + /* What it is and what it fires */ + enum de_unit_t unitType; + enum de_shot_t shotType; + + /* What it's pointed */ + float angle; + float power; + + /* Misc */ + int lastMove; + unsigned int ani_frame; + int health; +}; +struct destruct_shot_s { + + bool isAvailable; + + float x; + float y; + float xmov; + float ymov; + bool gravity; + unsigned int shottype; + //int shotdur; /* This looks to be unused */ + unsigned int trailx[4], traily[4], trailc[4]; +}; +struct destruct_explo_s { + + bool isAvailable; + + unsigned int x, y; + unsigned int explowidth; + unsigned int explomax; + unsigned int explofill; + enum de_expl_t exploType; +}; +struct destruct_moves_s { + bool actions[MAX_MOVE]; +}; +struct destruct_keys_s { + SDLKey Config[MAX_KEY][MAX_KEY_OPTIONS]; +}; +struct destruct_ai_s { + + int c_Angle, c_Power, c_Fire; + unsigned int c_noDown; +}; +struct destruct_player_s { + + bool is_cpu; + struct destruct_ai_s aiMemory; + + struct destruct_unit_s * unit; + struct destruct_moves_s moves; + struct destruct_keys_s keys; + + enum de_team_t team; + unsigned int unitsRemaining; + unsigned int unitSelected; + unsigned int shotDelay; + unsigned int score; +}; +struct destruct_wall_s { + + bool wallExist; + unsigned int wallX, wallY; +}; +struct destruct_world_s { + + /* Map data & screen pointer */ + unsigned int baseMap[320]; + SDL_Surface * VGAScreen; + struct destruct_wall_s * mapWalls; + + /* Map configuration */ + enum de_mode_t destructMode; + unsigned int mapFlags; +}; + +/*** Function decs ***/ +//Prep functions +void JE_destructMain( void ); +void JE_introScreen( void ); +enum de_mode_t JE_modeSelect( void ); +void JE_helpScreen( void ); +void JE_pauseScreen( void ); + +//level generating functions +void JE_generateTerrain( void ); +void DE_generateBaseTerrain( unsigned int, unsigned int *); +void DE_drawBaseTerrain( unsigned int * ); +void DE_generateUnits( unsigned int * ); +void DE_generateWalls( struct destruct_world_s * ); +void DE_generateRings(SDL_Surface *, Uint8 ); +void DE_ResetLevel( void ); +unsigned int JE_placementPosition( unsigned int, unsigned int, unsigned int * ); + +//drawing functions +void JE_aliasDirt( SDL_Surface * ); +void DE_RunTickDrawCrosshairs( void ); +void DE_RunTickDrawHUD( void ); +void DE_GravityDrawUnit( enum de_player_t, struct destruct_unit_s * ); +void DE_RunTickAnimate( void ); +void DE_RunTickDrawWalls( void ); +void DE_DrawTrails( struct destruct_shot_s *, unsigned int, unsigned int, unsigned int ); +void JE_tempScreenChecking( void ); +void JE_superPixel( unsigned int, unsigned int ); +void JE_pixCool( unsigned int, unsigned int, Uint8 ); + +//player functions +void DE_RunTickGetInput( void ); +void DE_ProcessInput( void ); +void DE_ResetPlayers( void ); +void DE_ResetAI( void ); +void DE_ResetActions( void ); +void DE_RunTickAI( void ); + +//unit functions +void DE_RaiseAngle( struct destruct_unit_s * ); +void DE_LowerAngle( struct destruct_unit_s * ); +void DE_RaisePower( struct destruct_unit_s * ); +void DE_LowerPower( struct destruct_unit_s * ); +void DE_CycleWeaponUp( struct destruct_unit_s * ); +void DE_CycleWeaponDown( struct destruct_unit_s * ); +void DE_RunMagnet( enum de_player_t, struct destruct_unit_s * ); +void DE_GravityFlyUnit( struct destruct_unit_s * ); +void DE_GravityLowerUnit( struct destruct_unit_s * ); +void DE_DestroyUnit( enum de_player_t, struct destruct_unit_s * ); +void DE_ResetUnits( void ); +static inline bool DE_isValidUnit( struct destruct_unit_s *); + +//weapon functions +void DE_ResetWeapons( void ); +void DE_RunTickShots( void ); +void DE_RunTickExplosions( void ); +void DE_TestExplosionCollision( unsigned int, unsigned int); +void JE_makeExplosion( unsigned int, unsigned int, enum de_shot_t ); +void DE_MakeShot( enum de_player_t, const struct destruct_unit_s *, int ); + +//gameplay functions +enum de_state_t DE_RunTick( void ); +void DE_RunTickCycleDeadUnits( void ); +void DE_RunTickGravity( void ); +bool DE_RunTickCheckEndgame( void ); +bool JE_stabilityCheck( unsigned int, unsigned int ); + +//sound +void DE_RunTickPlaySounds( void ); +void JE_eSound( unsigned int ); + + + +/*** Weapon configurations ***/ + +/* Part of me wants to leave these as bytes to save space. */ +const bool demolish[MAX_SHOT_TYPES] = {false, false, false, false, false, true, true, true, false, false, false, false, true, false, true, false, true}; +//const int shotGr[MAX_SHOT_TYPES] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101}; +const int shotTrail[MAX_SHOT_TYPES] = {TRAILS_NONE, TRAILS_NONE, TRAILS_NONE, TRAILS_NORMAL, TRAILS_NORMAL, TRAILS_NORMAL, TRAILS_FULL, TRAILS_FULL, TRAILS_NONE, TRAILS_NONE, TRAILS_NONE, TRAILS_NORMAL, TRAILS_FULL, TRAILS_NORMAL, TRAILS_FULL, TRAILS_NORMAL, TRAILS_NONE}; +//const int shotFuse[MAX_SHOT_TYPES] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}; +const int shotDelay[MAX_SHOT_TYPES] = {10, 30, 80, 20, 60, 100, 140, 200, 20, 60, 5, 15, 50, 5, 80, 16, 0}; +const int shotSound[MAX_SHOT_TYPES] = {S_SELECT, S_WEAPON_2, S_WEAPON_1, S_WEAPON_7, S_WEAPON_7, S_EXPLOSION_9, S_EXPLOSION_22, S_EXPLOSION_22, S_WEAPON_5, S_WEAPON_13, S_WEAPON_10, S_WEAPON_15, S_WEAPON_15, S_WEAPON_26, S_WEAPON_14, S_WEAPON_7, S_WEAPON_7}; +const int exploSize[MAX_SHOT_TYPES] = {4, 20, 30, 14, 22, 16, 40, 60, 10, 30, 0, 5, 10, 3, 15, 7, 0}; +const bool shotBounce[MAX_SHOT_TYPES] = {false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, false, true}; +const int exploDensity[MAX_SHOT_TYPES] = { 2, 5, 10, 15, 20, 15, 25, 30, 40, 80, 0, 30, 30, 4, 30, 5, 0}; +const int shotDirt[MAX_SHOT_TYPES] = {EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_DIRT, EXPL_DIRT, EXPL_MAGNET, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NORMAL, EXPL_NONE}; +const int shotColor[MAX_SHOT_TYPES] = {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 10, 10, 10, 10, 16, 0}; + +const int defaultWeapon[MAX_UNITS] = {SHOT_SMALL, SHOT_MICRO, SHOT_SMALLDIRT, SHOT_INVALID, SHOT_MAGNET, SHOT_MINILASER, SHOT_MICRO, SHOT_MINI}; +const int defaultCpuWeapon[MAX_UNITS] = {SHOT_SMALL, SHOT_MICRO, SHOT_DEMO, SHOT_INVALID, SHOT_MAGNET, SHOT_MINILASER, SHOT_MICRO, SHOT_MINI}; +const int defaultCpuWeaponB[MAX_UNITS] = {SHOT_DEMO, SHOT_SMALLNUKE, SHOT_DEMO, SHOT_INVALID, SHOT_MAGNET, SHOT_MEGALASER, SHOT_MICRO, SHOT_MINI}; +const int systemAngle[MAX_UNITS] = {true, true, true, false, false, true, false, false}; +const int baseDamage[MAX_UNITS] = {200, 120, 400, 300, 80, 150, 600, 40}; +const int systemAni[MAX_UNITS] = {false, false, false, true, false, false, false, true}; + +bool weaponSystems[MAX_UNITS][MAX_SHOT_TYPES] = +{ + {1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // normal + {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // nuke + {0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // dirt + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // worthless + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // magnet + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}, // laser + {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, // jumper + {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0} // helicopter +}; + +/* More constant configuration settings. */ +/* Music that destruct will play. You can check out musmast.c to see what is what. */ +const JE_byte goodsel[14] /*[1..14]*/ = {1, 2, 6, 12, 13, 14, 17, 23, 24, 26, 28, 29, 32, 33}; + +/* Unit creation. Need to move this later: Doesn't belong here */ +JE_byte basetypes[10][11] /*[1..8, 1..11]*/ = /* [0] is amount of units*/ +{ + {5, UNIT_TANK, UNIT_TANK, UNIT_NUKE, UNIT_DIRT, UNIT_DIRT, UNIT_SATELLITE, UNIT_MAGNET, UNIT_LASER, UNIT_JUMPER, UNIT_HELI}, /*Normal*/ + {1, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK}, /*Traditional*/ + {4, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI}, /*Weak Heli attack fleet*/ + {8, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_NUKE, UNIT_NUKE, UNIT_NUKE, UNIT_DIRT, UNIT_MAGNET, UNIT_LASER, UNIT_JUMPER}, /*Strong Heli defense fleet*/ + {8, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI, UNIT_HELI}, /*Strong Heli attack fleet*/ + {4, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_NUKE, UNIT_NUKE, UNIT_DIRT, UNIT_MAGNET, UNIT_JUMPER, UNIT_JUMPER}, /*Weak Heli defense fleet*/ + {8, UNIT_TANK, UNIT_NUKE, UNIT_DIRT, UNIT_SATELLITE, UNIT_MAGNET, UNIT_LASER, UNIT_JUMPER, UNIT_HELI, UNIT_TANK, UNIT_NUKE}, /*Overpowering fleet*/ + {4, UNIT_TANK, UNIT_TANK, UNIT_NUKE, UNIT_DIRT, UNIT_TANK, UNIT_LASER, UNIT_JUMPER, UNIT_HELI, UNIT_NUKE, UNIT_JUMPER}, /*Weak fleet*/ + {1, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK}, /*Custom1, to be edited*/ + {1, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK, UNIT_TANK} /*Custom2, to be edited*/ +}; +const unsigned int baseLookup[MAX_PLAYERS][MAX_MODES] = +{ + {0, 1, 3, 4, 6, 8}, + {0, 1, 2, 5, 7, 9} +}; + + +const JE_byte GraphicBase[MAX_PLAYERS][MAX_UNITS] = +{ + { 1, 6, 11, 58, 63, 68, 96, 153}, + { 20, 25, 30, 77, 82, 87, 115, 172} +}; + +const JE_byte ModeScore[MAX_PLAYERS][MAX_MODES] = +{ + {1, 0, 0, 5, 0, 1}, + {1, 0, 5, 0, 1, 1} +}; + +SDLKey defaultKeyConfig[MAX_PLAYERS][MAX_KEY][MAX_KEY_OPTIONS] = +{ + { {SDLK_c}, + {SDLK_v}, + {SDLK_a}, + {SDLK_z}, + {SDLK_LALT}, + {SDLK_x, SDLK_LSHIFT}, + {SDLK_LCTRL}, + {SDLK_SPACE} + }, + { {SDLK_LEFT, SDLK_KP4}, + {SDLK_RIGHT, SDLK_KP6}, + {SDLK_UP, SDLK_KP8}, + {SDLK_DOWN, SDLK_KP2}, + {SDLK_BACKSLASH, SDLK_KP5}, + {SDLK_INSERT, SDLK_RETURN, SDLK_KP0, SDLK_KP_ENTER}, + {SDLK_PAGEUP, SDLK_KP9}, + {SDLK_PAGEDOWN, SDLK_KP3} + } +}; + + +/*** Globals ***/ +SDL_Surface *destructTempScreen; +JE_boolean destructFirstTime; + +static struct destruct_config_s config = { 40, 20, 20, 40, 10, false, false, {true, false}, {true, false} }; +static struct destruct_player_s player[MAX_PLAYERS]; +static struct destruct_world_s world; +static struct destruct_shot_s * shotRec; +static struct destruct_explo_s * exploRec; + + +/*** Startup ***/ +enum de_unit_t string_to_unit_enum(const char * str) { + + // A config helper function. Probably not useful anywhere else. + //enum de_unit_t i; + int i; + static const char * unit_names[] = + { "UNIT_TANK", "UNIT_NUKE", "UNIT_DIRT", "UNIT_SATELLITE", + "UNIT_MAGNET", "UNIT_LASER", "UNIT_JUMPER", "UNIT_HELI" }; + + for (i = UNIT_FIRST; i < MAX_UNITS; i++) { + if(strcmp(unit_names[i], str) == 0) { return((enum de_unit_t)i); } + } + + return(UNIT_NONE); +} +bool write_default_destruct_config( void ) { + + cJSON * root; + cJSON * level1, * level2, * level3, * setting; + + + //If I read the file right, all of these will return NULL on failure. + //Well that'll be a little bit tedious to check for each time, but using + //gotos can help clear everything up since only one thing is freed. + if((root = cJSON_CreateObject()) == NULL) { goto label_failure; } + + + if((level1 = cJSON_CreateOrGetObjectItem(root, "general")) == NULL) { goto label_failure; } + cJSON_ForceType(level1, cJSON_Object); + + //general + if((setting = cJSON_CreateOrGetObjectItem(level1, "alwaysalias")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, false); + if((setting = cJSON_CreateOrGetObjectItem(level1, "tracerlaser")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, false); + if((setting = cJSON_CreateOrGetObjectItem(level1, "max_shots")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, 40); + if((setting = cJSON_CreateOrGetObjectItem(level1, "min_walls")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, 20); + if((setting = cJSON_CreateOrGetObjectItem(level1, "max_walls")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, 20); + if((setting = cJSON_CreateOrGetObjectItem(level1, "max_explosions")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, 40); + + //players general + if((level2 = cJSON_CreateOrGetObjectItem(level1, "player1")) == NULL) { goto label_failure; } + cJSON_ForceType(level2, cJSON_Object); + if((setting = cJSON_CreateOrGetObjectItem(level2, "ai")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, true); + if((setting = cJSON_CreateOrGetObjectItem(level2, "jumper_fires_straight")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, true); + + if((level3 = cJSON_CreateOrGetObjectItem(level2, "keys")) == NULL) { goto label_failure; } + cJSON_ForceType(level3, cJSON_Object); + if((setting = cJSON_CreateOrGetObjectItem(level3, "__comment")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "You may configure the keys here. Nums correspond to SDL defines. It's better than nothing."); + if((setting = cJSON_CreateOrGetObjectItem(level3, "left1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_c); + if((setting = cJSON_CreateOrGetObjectItem(level3, "right1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_v); + if((setting = cJSON_CreateOrGetObjectItem(level3, "up1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_a); + if((setting = cJSON_CreateOrGetObjectItem(level3, "down1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_z); + if((setting = cJSON_CreateOrGetObjectItem(level3, "change1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_LALT); + if((setting = cJSON_CreateOrGetObjectItem(level3, "fire1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_x); + if((setting = cJSON_CreateOrGetObjectItem(level3, "fire2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_LSHIFT); + if((setting = cJSON_CreateOrGetObjectItem(level3, "cyup1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_LCTRL); + if((setting = cJSON_CreateOrGetObjectItem(level3, "cydn1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_SPACE); + + if((level2 = cJSON_CreateOrGetObjectItem(level1, "player2")) == NULL) { goto label_failure; } + cJSON_ForceType(level2, cJSON_Object); + if((setting = cJSON_CreateOrGetObjectItem(level2, "ai")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, false); + if((setting = cJSON_CreateOrGetObjectItem(level2, "jumper_fires_straight")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, false); + + if((level3 = cJSON_CreateOrGetObjectItem(level2, "keys")) == NULL) { goto label_failure; } + cJSON_ForceType(level3, cJSON_Object); + if((setting = cJSON_CreateOrGetObjectItem(level3, "left1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_LEFT); + if((setting = cJSON_CreateOrGetObjectItem(level3, "left2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP4); + if((setting = cJSON_CreateOrGetObjectItem(level3, "right1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_RIGHT); + if((setting = cJSON_CreateOrGetObjectItem(level3, "right2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP6); + if((setting = cJSON_CreateOrGetObjectItem(level3, "up1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_UP); + if((setting = cJSON_CreateOrGetObjectItem(level3, "up2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP8); + if((setting = cJSON_CreateOrGetObjectItem(level3, "down1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_DOWN); + if((setting = cJSON_CreateOrGetObjectItem(level3, "down2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP2); + if((setting = cJSON_CreateOrGetObjectItem(level3, "change1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_BACKSLASH); + if((setting = cJSON_CreateOrGetObjectItem(level3, "change2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP5); + if((setting = cJSON_CreateOrGetObjectItem(level3, "fire1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_INSERT); + if((setting = cJSON_CreateOrGetObjectItem(level3, "fire2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_RETURN); + if((setting = cJSON_CreateOrGetObjectItem(level3, "fire3")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP0); + if((setting = cJSON_CreateOrGetObjectItem(level3, "fire4")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP_ENTER); + if((setting = cJSON_CreateOrGetObjectItem(level3, "cyup1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_PAGEUP); + if((setting = cJSON_CreateOrGetObjectItem(level3, "cyup2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP9); + if((setting = cJSON_CreateOrGetObjectItem(level3, "cydn1")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_PAGEDOWN); + if((setting = cJSON_CreateOrGetObjectItem(level3, "cydn2")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, SDLK_KP3); + + //custom mode + if((level1 = cJSON_CreateOrGetObjectItem(root, "custom")) == NULL) { goto label_failure; } + cJSON_ForceType(level1, cJSON_Object); + + if((setting = cJSON_CreateOrGetObjectItem(level1, "enable")) == NULL) { goto label_failure; } + cJSON_SetBoolean(setting, false); + + //player 1 (I could but won't bother looping this) + if((level2 = cJSON_CreateOrGetObjectItem(level1, "player1")) == NULL) { goto label_failure; } + cJSON_ForceType(level2, cJSON_Object); + if((setting = cJSON_CreateOrGetObjectItem(level2, "num_units")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, 10); + if((setting = cJSON_CreateOrGetObjectItem(level2, "__comment")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "This handles probability. Always have 10 entries."); + + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit1")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_TANK"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit2")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_TANK"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit3")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_NUKE"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit4")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_DIRT"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit5")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_DIRT"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit6")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_SATELLITE"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit7")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_MAGNET"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit8")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_LASER"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit9")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_JUMPER"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit10")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_HELI"); + + if((level2 = cJSON_CreateOrGetObjectItem(level1, "player2")) == NULL) { goto label_failure; } + cJSON_ForceType(level2, cJSON_Object); + if((setting = cJSON_CreateOrGetObjectItem(level2, "num_units")) == NULL) { goto label_failure; } + cJSON_SetNumber(setting, 10); + + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit1")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_TANK"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit2")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_TANK"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit3")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_NUKE"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit4")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_DIRT"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit5")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_DIRT"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit6")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_SATELLITE"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit7")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_MAGNET"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit8")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_LASER"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit9")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_JUMPER"); + if((setting = cJSON_CreateOrGetObjectItem(level2, "unit10")) == NULL) { goto label_failure; } + cJSON_SetString(setting, "UNIT_HELI"); + + save_json(root, "destruct.conf"); + return(true); + +label_failure: + cJSON_Delete(root); + return(false); +} +void load_destruct_config( void ) { + + unsigned int j, k; + int i;//enum de_player_t i; + enum de_unit_t temp; + char buffer[40]; + const char * key_names[] = { "left", "right", "up", "down", "change", "fire", "cyup", "cydn" }; + cJSON * root; + cJSON * level1, * level2, * level3, * setting; + + // The config file is not modified in game in order to 'keep' with the + // original (unconfigurable) feel. This code was copied from elsewhere. + root = load_json("destruct.conf"); + if (root == NULL) { + write_default_destruct_config(); + return; + } + + //load these general config items. I don't consider sanity checks + //necessary; either the game isn't playable or you eat up all your memory + //when using unreasonable values. Either way, no exploit here. + level1 = cJSON_GetObjectItem(root, "general"); + if (level1 != NULL) + { + if ((setting = cJSON_GetObjectItem(level1, "alwaysalias"))) { + config.alwaysalias = (setting->type == cJSON_True); + } + if ((setting = cJSON_GetObjectItem(level1, "tracerlaser"))) { + weaponSystems[UNIT_LASER][SHOT_LASERTRACER] = (setting->type == cJSON_True); + } + if ((setting = cJSON_GetObjectItem(level1, "max_shots")) && setting->type == cJSON_Number) { + config.max_shots = setting->valueint; + } + if ((setting = cJSON_GetObjectItem(level1, "min_walls")) && setting->type == cJSON_Number) { + config.min_walls = setting->valueint; + } + if ((setting = cJSON_GetObjectItem(level1, "max_walls")) && setting->type == cJSON_Number) { + config.max_walls = setting->valueint; + if(config.min_walls > config.max_walls) { config.min_walls = config.max_walls; } + } + if ((setting = cJSON_GetObjectItem(level1, "max_explosions")) && setting->type == cJSON_Number) { + config.max_explosions = setting->valueint; + } + + //player configuration + for(i = PLAYER_LEFT; i < MAX_PLAYERS; i++) { + sprintf(buffer, "player%i", i+1); + level2 = cJSON_GetObjectItem(level1, buffer); + if (level2 != NULL) + { + if ((setting = cJSON_GetObjectItem(level2, "jumper_fires_straight"))) { + config.jumper_straight[i] = (setting->type == cJSON_True); + } + if ((setting = cJSON_GetObjectItem(level2, "ai"))) { + config.ai[i] = (setting->type == cJSON_True); + } + //key configuration + level3 = cJSON_GetObjectItem(level2, "keys"); + if (level3 != NULL) + { + for (j = 0; j < COUNTOF(key_names); j++) { + for (k = 0; k < MAX_KEY_OPTIONS; k++) { + sprintf(buffer, "%s%i", key_names[j], k+1); + if ((setting = cJSON_GetObjectItem(level3, buffer)) && setting->type == cJSON_Number) { + defaultKeyConfig[i][j][k] = (SDLKey)setting->valueint; + } + else { //assume that if we are reading keys the defaults are null and void + defaultKeyConfig[i][j][k] = SDLK_UNKNOWN; + } + } + } + } + } + } + } + + //Now let's hit the custom mode... + level1 = cJSON_GetObjectItem(root, "custom"); + + if (level1 != NULL) + { + //general custom + if ((setting = cJSON_GetObjectItem(level1, "enable"))) { + config.allow_custom = (setting->type == cJSON_True); + } + + //player configuration + for(i = PLAYER_LEFT; i < MAX_PLAYERS; i++) { + sprintf(buffer, "player%i", i+1); + level2 = cJSON_GetObjectItem(level1, buffer); + if (level2 != NULL) + { + if ((setting = cJSON_GetObjectItem(level2, "num_units"))) { + basetypes[8 + i][0] = setting->valueint; + } + for(j = 1; j < 11; j++) { + sprintf(buffer, "unit%i", j); + if ((setting = cJSON_GetObjectItem(level2, buffer)) && setting->type == cJSON_String) { + temp = string_to_unit_enum(setting->valuestring); + if(temp != UNIT_NONE) { + basetypes[8 + i][j] = temp; + } + } + } + } + } + } + + //wrap up + cJSON_Delete(root); +} +void JE_destructGame( void ) +{ + unsigned int i; + + /* This is the entry function. Any one-time actions we need to + * perform can go in here. */ + JE_clr256(VGAScreen); + JE_showVGA(); + + load_destruct_config(); + + //malloc things that have customizable sizes + shotRec = (destruct_shot_s *)malloc(sizeof(struct destruct_shot_s) * config.max_shots); + exploRec = (destruct_explo_s *)malloc(sizeof(struct destruct_explo_s) * config.max_explosions); + world.mapWalls = (destruct_wall_s *)malloc(sizeof(struct destruct_wall_s) * config.max_walls); + + //Malloc enough structures to cover all of this session's possible needs. + for(i = 0; i < 10; i++) { + config.max_installations = MAX(config.max_installations, basetypes[i][0]); + } + player[PLAYER_LEFT ].unit = (destruct_unit_s *)malloc(sizeof(struct destruct_unit_s) * config.max_installations); + player[PLAYER_RIGHT].unit = (destruct_unit_s *)malloc(sizeof(struct destruct_unit_s) * config.max_installations); + + destructTempScreen = game_screen; + world.VGAScreen = VGAScreen; + + JE_loadCompShapes(&eShapes1, '~'); + fade_black(1); + + JE_destructMain(); + + //and of course exit actions go here. + free(shotRec); + free(exploRec); + free(world.mapWalls); + free(player[PLAYER_LEFT ].unit); + free(player[PLAYER_RIGHT].unit); +} + +void JE_destructMain( void ) +{ + enum de_state_t curState; + + + JE_loadPic(VGAScreen, 11, false); + JE_introScreen(); + + DE_ResetPlayers(); + + player[PLAYER_LEFT ].is_cpu = config.ai[PLAYER_LEFT]; + player[PLAYER_RIGHT].is_cpu = config.ai[PLAYER_RIGHT]; + + while(1) + { + world.destructMode = JE_modeSelect(); + + if(world.destructMode == MODE_NONE) { + break; /* User is quitting */ + } + + do + { + + destructFirstTime = true; + JE_loadPic(VGAScreen, 11, false); + + DE_ResetUnits(); + DE_ResetLevel(); + do { + curState = DE_RunTick(); + } while(curState == STATE_CONTINUE); + + fade_black(25); + } + while (curState == STATE_RELOAD); + } +} + +void JE_introScreen( void ) +{ + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->h * VGAScreen2->pitch); + JE_outText(VGAScreen, JE_fontCenter(specialName[7], TINY_FONT), 90, specialName[7], 12, 5); + JE_outText(VGAScreen, JE_fontCenter(miscText[64], TINY_FONT), 180, miscText[64], 15, 2); + JE_outText(VGAScreen, JE_fontCenter(miscText[65], TINY_FONT), 190, miscText[65], 15, 2); + JE_showVGA(); + fade_palette(colors, 15, 0, 255); + + newkey = false; + while (!newkey) + { + service_SDL_events(false); + SDL_Delay(16); + } + + fade_black(15); + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->h * VGAScreen->pitch); + JE_showVGA(); +} + +/* JE_modeSelect + * + * This function prints the DESTRUCT mode selection menu. + * The return value is the selected mode, or -1 (MODE_NONE) + * if the user quits. + */ +void DrawModeSelectMenu( enum de_mode_t mode ) { + + int i; + + /* Helper function of JE_modeSelect. Do not use elsewhere. */ + for (i = 0; i < DESTRUCT_MODES; i++) + { /* What a large function call. */ + JE_textShade(VGAScreen, JE_fontCenter(destructModeName[i], TINY_FONT), 82 + i * 12, destructModeName[i], 12, (i == mode) * 4, FULL_SHADE); + } + if (config.allow_custom == true) + { + JE_textShade(VGAScreen, JE_fontCenter("Custom", TINY_FONT), 82 + i * 12, "Custom", 12, (i == mode) * 4, FULL_SHADE); + } +} +enum de_mode_t JE_modeSelect( void ) +{ + int mode; //enum de_mode_t mode; + + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->h * VGAScreen2->pitch); + mode = MODE_5CARDWAR; + + // Draw the menu and fade us in + DrawModeSelectMenu((de_mode_t)mode); + + JE_showVGA(); + fade_palette(colors, 15, 0, 255); + + /* Get input in a loop. */ + while(1) + { + /* Re-draw the menu every iteration */ + DrawModeSelectMenu((de_mode_t)mode); + JE_showVGA(); + + /* Grab keys */ + newkey = false; + do { + service_SDL_events(false); + SDL_Delay(16); + } while(!newkey); + + /* See what was pressed */ + if (keysactive[SDLK_ESCAPE]) + { + mode = MODE_NONE; /* User is quitting, return failure */ + break; + } + if (keysactive[SDLK_RETURN]) + { + break; /* User has selected, return choice */ + } + if (keysactive[SDLK_UP]) + { + if(mode == MODE_FIRST) + { + if (config.allow_custom == true) + { + mode = MODE_LAST; + } else { + mode = MODE_LAST-1; + } + } else { + mode--; + } + } + if (keysactive[SDLK_DOWN]) + { + if(mode >= MODE_LAST-1) + { + if (config.allow_custom == true && mode == MODE_LAST-1) + { + mode++; + } else { + mode = MODE_FIRST; + } + } else { + mode++; + } + } + } + + fade_black(15); + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->h * VGAScreen->pitch); + JE_showVGA(); + return((de_mode_t)mode); +} + +void JE_generateTerrain( void ) +{ + /* The unique modifiers: + Altered generation (really tall) + Fuzzy hills + Rings of dirt + + The non-unique ones;: + Rings of not dirt (holes) + Walls + */ + + world.mapFlags = MAP_NORMAL; + + if(mt_rand() % 2 == 0) + { + world.mapFlags |= MAP_WALLS; + } + if(mt_rand() % 4 == 0) + { + world.mapFlags |= MAP_HOLES; + } + switch(mt_rand() % 4) + { + case 0: + world.mapFlags |= MAP_FUZZY; + break; + + case 1: + world.mapFlags |= MAP_TALL; + break; + + case 2: + world.mapFlags |= MAP_RINGS; + break; + } + + play_song(goodsel[mt_rand() % 14] - 1); + + DE_generateBaseTerrain(world.mapFlags, world.baseMap); + DE_generateUnits(world.baseMap); + DE_generateWalls(&world); + DE_drawBaseTerrain(world.baseMap); + + if (world.mapFlags & MAP_RINGS) + { + DE_generateRings(world.VGAScreen, PIXEL_DIRT); + } + if (world.mapFlags & MAP_HOLES) + { + DE_generateRings(world.VGAScreen, PIXEL_BLACK); + } + + JE_aliasDirt(world.VGAScreen); + JE_showVGA(); + + memcpy(destructTempScreen->pixels, VGAScreen->pixels, destructTempScreen->pitch * destructTempScreen->h); +} +void DE_generateBaseTerrain( unsigned int mapFlags, unsigned int * baseWorld) +{ + unsigned int i; + unsigned int newheight, HeightMul; + float sinewave, sinewave2, cosinewave, cosinewave2; + + + /* The 'terrain' is actually the video buffer :). If it's brown, flu... er, + * brown pixels are what we check for collisions with. */ + + /* The ranges here are between .01 and roughly 0.07283...*/ + sinewave = mt_rand_lt1() * M_PI / 50 + 0.01f; + sinewave2 = mt_rand_lt1() * M_PI / 50 + 0.01f; + cosinewave = mt_rand_lt1() * M_PI / 50 + 0.01f; + cosinewave2 = mt_rand_lt1() * M_PI / 50 + 0.01f; + HeightMul = 20; + + /* This block just exists to mix things up. */ + if(mapFlags & MAP_FUZZY) + { + sinewave = M_PI - mt_rand_lt1() * 0.3f; + sinewave2 = M_PI - mt_rand_lt1() * 0.3f; + } + if(mapFlags & MAP_TALL) + { + HeightMul = 100; + } + + /* Now compute a height for each of our lines. */ + for (i = 1; i <= 318; i++) + { + newheight = roundf(sinf(sinewave * i) * HeightMul + sinf(sinewave2 * i) * 15 + + cosf(cosinewave * i) * 10 + sinf(cosinewave2 * i) * 15) + 130; + + /* Bind it; we have mins and maxs */ + if (newheight < 40) + { + newheight = 40; + } + else if (newheight > 195) { + newheight = 195; + } + baseWorld[i] = newheight; + } + /* The base world has been created. */ +} +void DE_drawBaseTerrain( unsigned int * baseWorld) +{ + unsigned int i; + + + for (i = 1; i <= 318; i++) + { + JE_rectangle(VGAScreen, i, baseWorld[i], i, 199, PIXEL_DIRT); + } +} + +void DE_generateUnits( unsigned int * baseWorld ) +{ + unsigned int i, j, numSatellites; + + + for (i = 0; i < MAX_PLAYERS; i++) + { + numSatellites = 0; + player[i].unitsRemaining = 0; + + for (j = 0; j < basetypes[baseLookup[i][world.destructMode]][0]; j++) + { + /* Not everything is the same between players */ + if(i == PLAYER_LEFT) + { + player[i].unit[j].unitX = (mt_rand() % 120) + 10; + } + else + { + player[i].unit[j].unitX = 320 - ((mt_rand() % 120) + 22); + } + + player[i].unit[j].unitY = JE_placementPosition(player[i].unit[j].unitX - 1, 14, baseWorld); + player[i].unit[j].unitType = (de_unit_t)basetypes[baseLookup[i][world.destructMode]][(mt_rand() % 10) + 1]; + + /* Sats are special cases since they are useless. They don't count + * as active units and we can't have a team of all sats */ + if (player[i].unit[j].unitType == UNIT_SATELLITE) + { + if (numSatellites == basetypes[baseLookup[i][world.destructMode]][0]) + { + player[i].unit[j].unitType = UNIT_TANK; + player[i].unitsRemaining++; + } else { + /* Place the satellite. Note: Earlier we cleared + * space with JE_placementPosition. Now we are randomly + * placing the sat's Y. It can be generated in hills + * and there is a clearing underneath it. This CAN + * be fixed but won't be for classic. + */ + player[i].unit[j].unitY = 30 + (mt_rand() % 40); + numSatellites++; + } + } + else + { + player[i].unitsRemaining++; + } + + /* Now just fill in the rest of the unit's values. */ + player[i].unit[j].lastMove = 0; + player[i].unit[j].unitYMov = 0; + player[i].unit[j].isYInAir = false; + player[i].unit[j].angle = 0; + player[i].unit[j].power = (player[i].unit[j].unitType == UNIT_LASER) ? 6 : 3; + player[i].unit[j].shotType = (de_shot_t)defaultWeapon[player[i].unit[j].unitType]; + player[i].unit[j].health = baseDamage[player[i].unit[j].unitType]; + player[i].unit[j].ani_frame = 0; + } + } +} +void DE_generateWalls( struct destruct_world_s * gameWorld ) +{ + unsigned int i, j, wallX; + unsigned int wallHeight, remainWalls; + unsigned int tries; + bool isGood; + + + if ((world.mapFlags & MAP_WALLS) == false) + { + /* Just clear them out */ + for (i = 0; i < config.max_walls; i++) + { + gameWorld->mapWalls[i].wallExist = false; + } + return; + } + + remainWalls = (rand() % (config.max_walls - config.min_walls + 1)) + config.min_walls; + + do { + + /* Create a wall. Decide how tall the wall will be */ + wallHeight = (mt_rand() % 5) + 1; + if(wallHeight > remainWalls) + { + wallHeight = remainWalls; + } + + /* Now find a good place to put the wall. */ + tries = 0; + do { + + isGood = true; + wallX = (mt_rand() % 300) + 10; + + /* Is this X already occupied? In the original Tyrian we only + * checked to make sure four units on each side were unobscured. + * That's not very scalable; instead I will check every unit, + * but I'll only try plotting an unobstructed X four times. + * After that we'll cover up what may; having a few units + * stuck behind walls makes things mildly interesting. + */ + for (i = 0; i < MAX_PLAYERS; i++) + { + for (j = 0; j < config.max_installations; j++) + { + if ((wallX > player[i].unit[j].unitX - 12) + && (wallX < player[i].unit[j].unitX + 13)) + { + isGood = false; + goto label_outer_break; /* I do feel that outer breaking is a legitimate goto use. */ + } + } + } + +label_outer_break: + tries++; + + } while(isGood == false && tries < 5); + + + /* We now have a valid X. Create the wall. */ + for (i = 1; i <= wallHeight; i++) + { + gameWorld->mapWalls[remainWalls - i].wallExist = true; + gameWorld->mapWalls[remainWalls - i].wallX = wallX; + gameWorld->mapWalls[remainWalls - i].wallY = JE_placementPosition(wallX, 12, gameWorld->baseMap) - 14 * i; + } + + remainWalls -= wallHeight; + + } while (remainWalls != 0); +} + +void DE_generateRings( SDL_Surface * screen, Uint8 pixel ) +{ + unsigned int i, j, tempSize, rings; + int tempPosX1, tempPosY1, tempPosX2, tempPosY2; + float tempRadian; + + + rings = mt_rand() % 6 + 1; + for (i = 1; i <= rings; i++) + { + tempPosX1 = (mt_rand() % 320); + tempPosY1 = (mt_rand() % 160) + 20; + tempSize = (mt_rand() % 40) + 10; /*Size*/ + + for (j = 1; j <= tempSize * tempSize * 2; j++) + { + tempRadian = mt_rand_lt1() * (2 * M_PI); + tempPosY2 = tempPosY1 + roundf(cosf(tempRadian) * (mt_rand_lt1() * 0.1f + 0.9f) * tempSize); + tempPosX2 = tempPosX1 + roundf(sinf(tempRadian) * (mt_rand_lt1() * 0.1f + 0.9f) * tempSize); + if ((tempPosY2 > 12) && (tempPosY2 < 200) + && (tempPosX2 > 0) && (tempPosX2 < 319)) + { + ((Uint8 *)screen->pixels)[tempPosX2 + tempPosY2 * screen->pitch] = pixel; + } + } + } +} + +unsigned int __aliasDirtPixel(const SDL_Surface * screen, unsigned int x, unsigned int y, const Uint8 * s) { + + //A helper function used when aliasing dirt. That's a messy process; + //let's contain the mess here. + unsigned int newColor = PIXEL_BLACK; + + + if ((y > 0) && (*(s - screen->pitch) == PIXEL_DIRT)) { // look up + newColor += 1; + } + if ((y < screen->h - 1u) && (*(s + screen->pitch) == PIXEL_DIRT)) { // look down + newColor += 3; + } + if ((x > 0) && (*(s - 1) == PIXEL_DIRT)) { // look left + newColor += 2; + } + if ((x < screen->pitch - 1u) && (*(s + 1) == PIXEL_DIRT)) { // look right + newColor += 2; + } + if (newColor != PIXEL_BLACK) { + return(newColor + 16); // 16 must be the start of the brown pixels. + } + + return(PIXEL_BLACK); +} +void JE_aliasDirt( SDL_Surface * screen ) +{ + /* This complicated looking function goes through the whole screen + * looking for brown pixels which just happen to be next to non-brown + * pixels. It's an aliaser, just like it says. */ + unsigned int x, y; + + + /* This is a pointer to a screen. If you don't like pointer arithmetic, + * you won't like this function. */ + Uint8 *s = (Uint8 *)screen->pixels; + s += 12 * screen->pitch; + + for (y = 12; y < (unsigned)screen->h; y++) { + for (x = 0; x < screen->pitch; x++) { + if (*s == PIXEL_BLACK) { + *s = __aliasDirtPixel(screen, x, y, s); + } + + s++; + } + } +} + +unsigned int JE_placementPosition( unsigned int passed_x, unsigned int width, unsigned int * world ) +{ + unsigned int i, new_y; + + + /* This is the function responsible for carving out chunks of land. + * There's a bug here, but it's a pretty major gameplay altering one: + * areas can be carved out for units that are aerial or in mountains. + * This can result in huge caverns. Ergo, it's a feature :) + * + * I wondered if it might be better to not carve out land at all. + * On testing I determined that was distracting and added nothing. */ + new_y = 0; + for (i = passed_x; i <= passed_x + width - 1; i++) + { + if (new_y < world[i]) + new_y = world[i]; + } + + for (i = passed_x; i <= passed_x + width - 1; i++) + { + world[i] = new_y; + } + + return new_y; +} + +bool JE_stabilityCheck( unsigned int x, unsigned int y ) +{ + unsigned int i, numDirtPixels; + Uint8 * s; + + + numDirtPixels = 0; + s = (Uint8 *)destructTempScreen->pixels; + s += x + (y * destructTempScreen->pitch) - 1; + + /* Check the 12 pixels on the bottom border of our object */ + for (i = 0; i < 12; i++) + { + if (*s == PIXEL_DIRT) + numDirtPixels++; + + s++; + } + + /* If there are fewer than 10 brown pixels we don't consider it a solid base */ + return (numDirtPixels < 10); +} + +void JE_tempScreenChecking( void ) /*and copy to vgascreen*/ +{ + Uint8 *s = (Uint8 *)VGAScreen->pixels; + s += 12 * VGAScreen->pitch; + + Uint8 *temps = (Uint8 *)destructTempScreen->pixels; + temps += 12 * destructTempScreen->pitch; + + for (int y = 12; y < VGAScreen->h; y++) + { + for (int x = 0; x < VGAScreen->pitch; x++) + { + // This block is what fades out explosions. The palette from 241 + // to 255 fades from a very dark red to a very bright yellow. + if (*temps >= 241) + { + if (*temps == 241) + *temps = PIXEL_BLACK; + else + (*temps)--; + } + + // This block is for aliasing dirt. Computers are fast these days, + // and it's fun. + if (config.alwaysalias == true && *temps == PIXEL_BLACK) { + *temps = __aliasDirtPixel(VGAScreen, x, y, temps); + } + + /* This is copying from our temp screen to VGAScreen */ + *s = *temps; + + s++; + temps++; + } + } +} + +void JE_makeExplosion( unsigned int tempPosX, unsigned int tempPosY, enum de_shot_t shottype ) +{ + unsigned int i, tempExploSize; + + + /* First find an open explosion. If we can't find one, return.*/ + for (i = 0; i < config.max_explosions; i++) + { + if (exploRec[i].isAvailable == true) + break; + } + if (i == config.max_explosions) /* No empty slots */ + { + return; + } + + + exploRec[i].isAvailable = false; + exploRec[i].x = tempPosX; + exploRec[i].y = tempPosY; + exploRec[i].explowidth = 2; + + if(shottype != SHOT_INVALID) + { + tempExploSize = exploSize[shottype]; + if (tempExploSize < 5) + JE_eSound(3); + else if (tempExploSize < 15) + JE_eSound(4); + else if (tempExploSize < 20) + JE_eSound(12); + else if (tempExploSize < 40) + JE_eSound(11); + else + { + JE_eSound(12); + JE_eSound(11); + } + + exploRec[i].explomax = tempExploSize; + exploRec[i].explofill = exploDensity[shottype]; + exploRec[i].exploType = (de_expl_t)shotDirt[shottype]; + } + else + { + JE_eSound(4); + exploRec[i].explomax = (mt_rand() % 40) + 10; + exploRec[i].explofill = (mt_rand() % 60) + 20; + exploRec[i].exploType = EXPL_NORMAL; + } +} + +void JE_eSound( unsigned int sound ) +{ + static int exploSoundChannel = 0; + + if (++exploSoundChannel > 5) + { + exploSoundChannel = 1; + } + + soundQueue[exploSoundChannel] = sound; +} + +void JE_superPixel( unsigned int tempPosX, unsigned int tempPosY ) +{ + const unsigned int starPattern[5][5] = { + { 0, 0, 246, 0, 0 }, + { 0, 247, 249, 247, 0 }, + { 246, 249, 252, 249, 246 }, + { 0, 247, 249, 247, 0 }, + { 0, 0, 246, 0, 0 } + }; + const unsigned int starIntensity[5][5] = { + { 0, 0, 1, 0, 0 }, + { 0, 1, 2, 1, 0 }, + { 1, 2, 4, 2, 1 }, + { 0, 1, 2, 1, 0 }, + { 0, 0, 1, 0, 0 } + }; + + int x, y, maxX, maxY; + unsigned int rowLen; + Uint8 *s; + + + maxX = destructTempScreen->pitch; + maxY = destructTempScreen->h; + + rowLen = destructTempScreen->pitch; + s = (Uint8 *)destructTempScreen->pixels; + s += (rowLen * (tempPosY - 2)) + (tempPosX - 2); + + for (y = 0; y < 5; y++, s += rowLen - 5) + { + if ((signed)tempPosY + y - 2 < 0 /* would be out of bounds */ + || (signed)tempPosY + y - 2 >= maxY) { continue; } + + for (x = 0; x < 5; x++, s++) + { + if ((signed)tempPosX + x - 2 < 0 + || (signed)tempPosX + x - 2 >= maxX) { continue; } + + if (starPattern[y][x] == 0) { continue; } /* this is just to speed it up */ + + /* at this point *s is our pixel. Our constant arrays tell us what + * to do with it. */ + if (*s < starPattern[y][x]) + { + *s = starPattern[y][x]; + } + else if (*s + starIntensity[y][x] > 255) + { + *s = 255; + } + else + { + *s += starIntensity[y][x]; + } + } + } +} + +void JE_helpScreen( void ) +{ + unsigned int i, j; + + + //JE_getVGA(); didn't do anything anyway? + fade_black(15); + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->h * VGAScreen2->pitch); + JE_clr256(VGAScreen); + + for(i = 0; i < 2; i++) + { + JE_outText(VGAScreen, 100, 5 + i * 90, destructHelp[i * 12 + 0], 2, 4); + JE_outText(VGAScreen, 100, 15 + i * 90, destructHelp[i * 12 + 1], 2, 1); + for (j = 3; j <= 12; j++) + { + JE_outText(VGAScreen, ((j - 1) % 2) * 160 + 10, 15 + ((j - 1) / 2) * 12 + i * 90, destructHelp[i * 12 + j-1], 1, 3); + } + } + JE_outText(VGAScreen, 30, 190, destructHelp[24], 3, 4); + JE_showVGA(); + fade_palette(colors, 15, 0, 255); + + do /* wait until user hits a key */ + { + service_SDL_events(true); + SDL_Delay(16); + } + while (!newkey); + + fade_black(15); + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->h * VGAScreen->pitch); + JE_showVGA(); + fade_palette(colors, 15, 0, 255); +} + + +void JE_pauseScreen( void ) +{ + set_volume(tyrMusicVolume / 2, fxVolume); + + /* Save our current screen/game world. We don't want to screw it up while paused. */ + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->h * VGAScreen2->pitch); + JE_outText(VGAScreen, JE_fontCenter(miscText[22], TINY_FONT), 90, miscText[22], 12, 5); + JE_showVGA(); + + do /* wait until user hits a key */ + { + service_SDL_events(true); + SDL_Delay(16); + } + while (!newkey); + + /* Restore current screen & volume*/ + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->h * VGAScreen->pitch); + JE_showVGA(); + + set_volume(tyrMusicVolume, fxVolume); +} + +/* DE_ResetX + * + * The reset functions clear the state of whatefer they are assigned to. + */ +void DE_ResetUnits( void ) +{ + unsigned int p, u; + + + for (p = 0; p < MAX_PLAYERS; ++p) + for (u = 0; u < config.max_installations; ++u) + player[p].unit[u].health = 0; +} +void DE_ResetPlayers( void ) +{ + unsigned int i; + + + for (i = 0; i < MAX_PLAYERS; ++i) + { + player[i].is_cpu = false; + player[i].unitSelected = 0; + player[i].shotDelay = 0; + player[i].score = 0; + player[i].aiMemory.c_Angle = 0; + player[i].aiMemory.c_Power = 0; + player[i].aiMemory.c_Fire = 0; + player[i].aiMemory.c_noDown = 0; + memcpy(player[i].keys.Config, defaultKeyConfig[i], sizeof(player[i].keys.Config)); + } +} +void DE_ResetWeapons( void ) +{ + unsigned int i; + + + for (i = 0; i < config.max_shots; i++) + shotRec[i].isAvailable = true; + + for (i = 0; i < config.max_explosions; i++) + exploRec[i].isAvailable = true; +} +void DE_ResetLevel( void ) +{ + /* Okay, let's prep the arena */ + + DE_ResetWeapons(); + + JE_generateTerrain(); + DE_ResetAI(); +} +void DE_ResetAI( void ) +{ + unsigned int i, j; + struct destruct_unit_s * ptr; + + + for (i = PLAYER_LEFT; i < MAX_PLAYERS; i++) + { + if (player[i].is_cpu == false) { continue; } + ptr = player[i].unit; + + for( j = 0; j < config.max_installations; j++, ptr++) + { + if(DE_isValidUnit(ptr) == false) + continue; + + if (systemAngle[ptr->unitType] || ptr->unitType == UNIT_HELI) + ptr->angle = M_PI_4; + else + ptr->angle = 0; + + ptr->power = (ptr->unitType == UNIT_LASER) ? 6 : 4; + + if (world.mapFlags & MAP_WALLS) + ptr->shotType = (de_shot_t)defaultCpuWeaponB[ptr->unitType]; + else + ptr->shotType = (de_shot_t)defaultCpuWeapon[ptr->unitType]; + } + } +} +void DE_ResetActions( void ) +{ + unsigned int i; + + + for(i = 0; i < MAX_PLAYERS; i++) + { /* Zero it all. A memset would do the trick */ + memset(&(player[i].moves), 0, sizeof(player[i].moves)); + } +} +/* DE_RunTick + * + * Runs one tick. One tick involves handling physics, drawing crap, + * moving projectiles and explosions, and getting input. + * Returns true while the game is running or false if the game is + * to be terminated. + */ +enum de_state_t DE_RunTick( void ) +{ + static unsigned int endDelay; + + + setjasondelay(1); + + memset(soundQueue, 0, sizeof(soundQueue)); + JE_tempScreenChecking(); + + DE_ResetActions(); + DE_RunTickCycleDeadUnits(); + + + DE_RunTickGravity(); + DE_RunTickAnimate(); + DE_RunTickDrawWalls(); + DE_RunTickExplosions(); + DE_RunTickShots(); + DE_RunTickAI(); + DE_RunTickDrawCrosshairs(); + DE_RunTickDrawHUD(); + JE_showVGA(); + + if (destructFirstTime) + { + fade_palette(colors, 25, 0, 255); + destructFirstTime = false; + endDelay = 0; + } + + DE_RunTickGetInput(); + DE_ProcessInput(); + + if (endDelay > 0) + { + if(--endDelay == 0) + { + return(STATE_RELOAD); + } + } + else if ( DE_RunTickCheckEndgame() == true) + { + endDelay = 80; + } + + DE_RunTickPlaySounds(); + + /* The rest of this cruft needs to be put in appropriate sections */ + if (keysactive[SDLK_F10]) + { + player[PLAYER_LEFT].is_cpu = !player[PLAYER_LEFT].is_cpu; + keysactive[SDLK_F10] = false; + } + if (keysactive[SDLK_F11]) + { + player[PLAYER_RIGHT].is_cpu = !player[PLAYER_RIGHT].is_cpu; + keysactive[SDLK_F11] = false; + } + if (keysactive[SDLK_p]) + { + JE_pauseScreen(); + keysactive[lastkey_sym] = false; + } + + if (keysactive[SDLK_F1]) + { + JE_helpScreen(); + keysactive[lastkey_sym] = false; + } + + wait_delay(); + + if (keysactive[SDLK_ESCAPE]) + { + keysactive[SDLK_ESCAPE] = false; + return(STATE_INIT); /* STATE_INIT drops us to the mode select */ + } + + if (keysactive[SDLK_BACKSPACE]) + { + keysactive[SDLK_BACKSPACE] = false; + return(STATE_RELOAD); /* STATE_RELOAD creates a new map */ + } + + return(STATE_CONTINUE); +} + +/* DE_RunTickX + * + * Handles something that we do once per tick, such as + * track ammo and move asplosions. + */ +void DE_RunTickCycleDeadUnits( void ) +{ + unsigned int i; + struct destruct_unit_s * unit; + + + /* This code automatically switches the active unit if it is destroyed + * and skips over the useless satellite */ + for (i = 0; i < MAX_PLAYERS; i++) + { + if (player[i].unitsRemaining == 0) { continue; } + + unit = &(player[i].unit[player[i].unitSelected]); + while(DE_isValidUnit(unit) == false + || unit->shotType == SHOT_INVALID) + { + player[i].unitSelected++; + unit++; + if (player[i].unitSelected >= config.max_installations) + { + player[i].unitSelected = 0; + unit = player[i].unit; + } + } + } +} +void DE_RunTickGravity( void ) +{ + unsigned int i, j; + struct destruct_unit_s * unit; + + + for (i = 0; i < MAX_PLAYERS; i++) + { + + unit = player[i].unit; + for (j = 0; j < config.max_installations; j++, unit++) + { + if (DE_isValidUnit(unit) == false) /* invalid unit */ + continue; + + switch(unit->unitType) + { + case UNIT_SATELLITE: /* satellites don't fall down */ + break; + + case UNIT_HELI: + case UNIT_JUMPER: + if (unit->isYInAir == true) /* unit is falling down, at least in theory */ + { + DE_GravityFlyUnit(unit); + break; + } + /* else fall through and treat as a normal unit */ + + default: + DE_GravityLowerUnit(unit); + } + + /* Draw the unit. */ + DE_GravityDrawUnit((de_player_t)i, unit); + } + } +} +void DE_GravityDrawUnit( enum de_player_t team, struct destruct_unit_s * unit ) +{ + unsigned int anim_index; + + + anim_index = GraphicBase[team][unit->unitType] + unit->ani_frame; + if (unit->unitType == UNIT_HELI) + { + /* Adjust animation index if we are travelling right or left. */ + if (unit->lastMove < -2) + anim_index += 5; + else if (unit->lastMove > 2) + anim_index += 10; + } + else /* This handles our cannons and the like */ + { + anim_index += floorf(unit->angle * 9.99f / M_PI); + } + + blit_sprite2(VGAScreen, unit->unitX, roundf(unit->unitY) - 13, eShapes1, anim_index); +} +void DE_GravityLowerUnit( struct destruct_unit_s * unit ) +{ + /* units fall at a constant speed. The heli is an odd case though; + * we simply give it a downward velocity, but due to a buggy implementation + * the chopper didn't lower until you tried to fly it up. Tyrian 2000 fixes + * this by not making the chopper a special case. I've decided to actually + * mix both; the chopper is given a slight downward acceleration (simulating + * a 'rocky' takeoff), and it is lowered like a regular unit, but not as + * quickly. + */ + if(unit->unitY < 199) { /* checking takes time, don't check if it's at the bottom */ + if (JE_stabilityCheck(unit->unitX, roundf(unit->unitY))) + { + switch(unit->unitType) + { + case UNIT_HELI: + unit->unitYMov = 1.5f; + unit->unitY += 0.2f; + break; + + default: + unit->unitY += 1; + } + + if (unit->unitY > 199) /* could be possible */ + unit->unitY = 199; + } + } +} +void DE_GravityFlyUnit( struct destruct_unit_s * unit ) +{ + if (unit->unitY + unit->unitYMov > 199) /* would hit bottom of screen */ + { + unit->unitY = 199; + unit->unitYMov = 0; + unit->isYInAir = false; + return; + } + + /* move the unit and alter acceleration */ + unit->unitY += unit->unitYMov; + if (unit->unitY < 24) /* This stops units from going above the screen */ + { + unit->unitYMov = 0; + unit->unitY = 24; + } + + if (unit->unitType == UNIT_HELI) /* helicopters fall more slowly */ + unit->unitYMov += 0.0001f; + else + unit->unitYMov += 0.03f; + + if (!JE_stabilityCheck(unit->unitX, roundf(unit->unitY))) + { + unit->unitYMov = 0; + unit->isYInAir = false; + } +} +void DE_RunTickAnimate( void ) +{ + unsigned int p, u; + struct destruct_unit_s * ptr; + + + for (p = 0; p < MAX_PLAYERS; ++p) + { + ptr = player[p].unit; + for (u = 0; u < config.max_installations; ++u, ++ptr) + { + /* Don't mess with any unit that is unallocated + * or doesn't animate and is set to frame 0 */ + if(DE_isValidUnit(ptr) == false) { continue; } + if(systemAni[ptr->unitType] == false && ptr->ani_frame == 0) { continue; } + + if (++(ptr->ani_frame) > 3) + { + ptr->ani_frame = 0; + } + } + } +} +void DE_RunTickDrawWalls( void ) +{ + unsigned int i; + + + for (i = 0; i < config.max_walls; i++) + { + if (world.mapWalls[i].wallExist) + { + blit_sprite2(VGAScreen, world.mapWalls[i].wallX, world.mapWalls[i].wallY, eShapes1, 42); + } + } +} +void DE_RunTickExplosions( void ) +{ + unsigned int i, j; + int tempPosX, tempPosY; + float tempRadian; + + + /* Run through all open explosions. They are not sorted in any way */ + for (i = 0; i < config.max_explosions; i++) + { + if (exploRec[i].isAvailable == true) { continue; } /* Nothing to do */ + + for (j = 0; j < exploRec[i].explofill; j++) + { + /* An explosion is comprised of multiple 'flares' that fan out. + Calculate where this 'flare' will end up */ + tempRadian = mt_rand_lt1() * (2 * M_PI); + tempPosY = exploRec[i].y + roundf(cosf(tempRadian) * mt_rand_lt1() * exploRec[i].explowidth); + tempPosX = exploRec[i].x + roundf(sinf(tempRadian) * mt_rand_lt1() * exploRec[i].explowidth); + + /* Our game allows explosions to wrap around. This looks to have + * originally been a bug that was left in as being fun, but we are + * going to replicate it w/o risking out of bound arrays. */ + + while(tempPosX < 0) { tempPosX += 320; } + while(tempPosX > 320) { tempPosX -= 320; } + + /* We don't draw our explosion if it's out of bounds vertically */ + if (tempPosY >= 200 || tempPosY <= 15) { continue; } + + /* And now the drawing. There are only two types of explosions + * right now; dirt and flares. Dirt simply draws a brown pixel; + * flares explode and have a star formation. */ + switch(exploRec[i].exploType) + { + case EXPL_DIRT: + ((Uint8 *)destructTempScreen->pixels)[tempPosX + tempPosY * destructTempScreen->pitch] = PIXEL_DIRT; + break; + + case EXPL_NORMAL: + JE_superPixel(tempPosX, tempPosY); + DE_TestExplosionCollision(tempPosX, tempPosY); + break; + + default: + assert(false); + break; + } + } + + /* Widen the explosion and delete it if necessary. */ + exploRec[i].explowidth++; + if (exploRec[i].explowidth == exploRec[i].explomax) + { + exploRec[i].isAvailable = true; + } + } +} +void DE_TestExplosionCollision( unsigned int PosX, unsigned int PosY) +{ + unsigned int i, j; + struct destruct_unit_s * unit; + + + for (i = PLAYER_LEFT; i < MAX_PLAYERS; i++) + { + unit = player[i].unit; + for (j = 0; j < config.max_installations; j++, unit++) + { + if (DE_isValidUnit(unit) == true + && PosX > unit->unitX && PosX < unit->unitX + 11 + && PosY < unit->unitY && PosY > unit->unitY - 11) + { + unit->health--; + if (unit->health <= 0) + { + DE_DestroyUnit((de_player_t)i, unit); + } + } + } + } +} +void DE_DestroyUnit( enum de_player_t playerID, struct destruct_unit_s * unit ) +{ + /* This function call was an evil evil piece of brilliance before. Go on. + * Look at the older revisions. It passed the result of a comparison. + * MULTIPLIED. This is at least a little clearer... */ + JE_makeExplosion(unit->unitX + 5, roundf(unit->unitY) - 5, (unit->unitType == UNIT_HELI) ? SHOT_SMALL : SHOT_INVALID); /* Helicopters explode like small shots do. Invalids are their own special case. */ + + if (unit->unitType != UNIT_SATELLITE) /* increment score */ + { /* todo: change when teams are created. Hacky kludge for now.*/ + player[playerID].unitsRemaining--; + player[((playerID == PLAYER_LEFT) ? PLAYER_RIGHT : PLAYER_LEFT)].score++; + } +} + +void DE_RunTickShots( void ) +{ + unsigned int i, j, k; + unsigned int tempTrails; + unsigned int tempPosX, tempPosY; + struct destruct_unit_s * unit; + + + for (i = 0; i < config.max_shots; i++) + { + if (shotRec[i].isAvailable == true) { continue; } /* Nothing to do */ + + /* Move the shot. Simple displacement */ + shotRec[i].x += shotRec[i].xmov; + shotRec[i].y += shotRec[i].ymov; + + /* If the shot can bounce off the map, bounce it */ + if (shotBounce[shotRec[i].shottype]) + { + if (shotRec[i].y > 199 || shotRec[i].y < 14) + { + shotRec[i].y -= shotRec[i].ymov; + shotRec[i].ymov = -shotRec[i].ymov; + } + if (shotRec[i].x < 1 || shotRec[i].x > 318) + { + shotRec[i].x -= shotRec[i].xmov; + shotRec[i].xmov = -shotRec[i].xmov; + } + } + else /* If it cannot, apply normal physics */ + { + shotRec[i].ymov += 0.05f; /* add gravity */ + + if (shotRec[i].y > 199) /* We hit the floor */ + { + shotRec[i].y -= shotRec[i].ymov; + shotRec[i].ymov = -shotRec[i].ymov * 0.8f; /* bounce at reduced velocity */ + + /* Don't allow a bouncing shot to bounce straight up and down */ + if (shotRec[i].xmov == 0) + { + shotRec[i].xmov += mt_rand_lt1() - 0.5f; + } + } + } + + /* Shot has gone out of bounds. Eliminate it. */ + if (shotRec[i].x > 318 || shotRec[i].x < 1) + { + shotRec[i].isAvailable = true; + continue; + } + + /* Now check for collisions. */ + + /* Don't bother checking for collisions above the map :) */ + if (shotRec[i].y <= 14) + continue; + + tempPosX = roundf(shotRec[i].x); + tempPosY = roundf(shotRec[i].y); + + /*Check building hits*/ + for(j = 0; j < MAX_PLAYERS; j++) + { + unit = player[j].unit; + for(k = 0; k < config.max_installations; k++, unit++) + { + if (DE_isValidUnit(unit) == false) + continue; + + if (tempPosX > unit->unitX && tempPosX < unit->unitX + 11 + && tempPosY < unit->unitY && tempPosY > unit->unitY - 13) + { + shotRec[i].isAvailable = true; + JE_makeExplosion(tempPosX, tempPosY, (de_shot_t)shotRec[i].shottype); + } + } + } + + tempTrails = (shotColor[shotRec[i].shottype] << 4) - 3; + JE_pixCool(tempPosX, tempPosY, tempTrails); + + /*Draw the shot trail (if applicable) */ + switch (shotTrail[shotRec[i].shottype]) + { + case TRAILS_NONE: + break; + case TRAILS_NORMAL: + DE_DrawTrails( &(shotRec[i]), 2, 4, tempTrails - 3 ); + break; + case TRAILS_FULL: + DE_DrawTrails( &(shotRec[i]), 4, 3, tempTrails - 1 ); + break; + } + + /* Bounce off of or destroy walls */ + for (j = 0; j < config.max_walls; j++) + { + if (world.mapWalls[j].wallExist == true + && tempPosX >= world.mapWalls[j].wallX && tempPosX <= world.mapWalls[j].wallX + 11 + && tempPosY >= world.mapWalls[j].wallY && tempPosY <= world.mapWalls[j].wallY + 14) + { + if (demolish[shotRec[i].shottype]) + { + /* Blow up the wall and remove the shot. */ + world.mapWalls[j].wallExist = false; + shotRec[i].isAvailable = true; + JE_makeExplosion(tempPosX, tempPosY, (de_shot_t)shotRec[i].shottype); + continue; + } + else + { + /* Otherwise, bounce. */ + if (shotRec[i].x - shotRec[i].xmov < world.mapWalls[j].wallX + || shotRec[i].x - shotRec[i].xmov > world.mapWalls[j].wallX + 11) + { + shotRec[i].xmov = -shotRec[i].xmov; + } + if (shotRec[i].y - shotRec[i].ymov < world.mapWalls[j].wallY + || shotRec[i].y - shotRec[i].ymov > world.mapWalls[j].wallY + 14) + { + if (shotRec[i].ymov < 0) + shotRec[i].ymov = -shotRec[i].ymov; + else + shotRec[i].ymov = -shotRec[i].ymov * 0.8f; + } + + tempPosX = roundf(shotRec[i].x); + tempPosY = roundf(shotRec[i].y); + } + } + } + + /* Our last collision check, at least for now. We hit dirt. */ + if((((Uint8 *)destructTempScreen->pixels)[tempPosX + tempPosY * destructTempScreen->pitch]) == PIXEL_DIRT) + { + shotRec[i].isAvailable = true; + JE_makeExplosion(tempPosX, tempPosY, (de_shot_t)shotRec[i].shottype); + continue; + } + } +} +void DE_DrawTrails( struct destruct_shot_s * shot, unsigned int count, unsigned int decay, unsigned int startColor ) +{ + int i; + + + for (i = count-1; i >= 0; i--) /* going in reverse is important as it affects how we draw */ + { + if (shot->trailc[i] > 0 && shot->traily[i] > 12) /* If it exists and if it's not out of bounds, draw it. */ + { + JE_pixCool(shot->trailx[i], shot->traily[i], shot->trailc[i]); + } + + if (i == 0) /* The first trail we create. */ + { + shot->trailx[i] = roundf(shot->x); + shot->traily[i] = roundf(shot->y); + shot->trailc[i] = startColor; + } + else /* The newer trails decay into the older trails.*/ + { + shot->trailx[i] = shot->trailx[i-1]; + shot->traily[i] = shot->traily[i-1]; + if (shot->trailc[i-1] > 0) + { + shot->trailc[i] = shot->trailc[i-1] - decay; + } + } + } +} +void DE_RunTickAI( void ) +{ + unsigned int i, j; + struct destruct_player_s * ptrPlayer, * ptrTarget; + struct destruct_unit_s * ptrUnit, * ptrCurUnit; + + + for (i = 0; i < MAX_PLAYERS; i++) + { + ptrPlayer = &(player[i]); + if (ptrPlayer->is_cpu == false) + { + continue; + } + + + /* I've been thinking, purely hypothetically, about what it would take + * to have multiple computer opponents. The answer? A lot of crap + * and a 'target' variable in the player struct. */ + j = i + 1; + if (j >= MAX_PLAYERS) + { + j = 0; + } + + ptrTarget = &(player[j]); + ptrCurUnit = &(ptrPlayer->unit[ptrPlayer->unitSelected]); + + + /* This is the start of the original AI. Heh. AI. */ + + if (ptrPlayer->aiMemory.c_noDown > 0) + ptrPlayer->aiMemory.c_noDown--; + + /* Until all structs are properly divvied up this must only apply to player1 */ + if (mt_rand() % 100 > 80) + { + ptrPlayer->aiMemory.c_Angle += (mt_rand() % 3) - 1; + + if (ptrPlayer->aiMemory.c_Angle > 1) + ptrPlayer->aiMemory.c_Angle = 1; + else + if (ptrPlayer->aiMemory.c_Angle < -1) + ptrPlayer->aiMemory.c_Angle = -1; + } + if (mt_rand() % 100 > 90) + { + if (ptrPlayer->aiMemory.c_Angle > 0 && ptrCurUnit->angle > (M_PI_2) - (M_PI / 9)) + ptrPlayer->aiMemory.c_Angle = 0; + else + if (ptrPlayer->aiMemory.c_Angle < 0 && ptrCurUnit->angle < M_PI / 8) + ptrPlayer->aiMemory.c_Angle = 0; + } + + if (mt_rand() % 100 > 93) + { + ptrPlayer->aiMemory.c_Power += (mt_rand() % 3) - 1; + + if (ptrPlayer->aiMemory.c_Power > 1) + ptrPlayer->aiMemory.c_Power = 1; + else + if (ptrPlayer->aiMemory.c_Power < -1) + ptrPlayer->aiMemory.c_Power = -1; + } + if (mt_rand() % 100 > 90) + { + if (ptrPlayer->aiMemory.c_Power > 0 && ptrCurUnit->power > 4) + ptrPlayer->aiMemory.c_Power = 0; + else + if (ptrPlayer->aiMemory.c_Power < 0 && ptrCurUnit->power < 3) + ptrPlayer->aiMemory.c_Power = 0; + else + if (ptrCurUnit->power < 2) + ptrPlayer->aiMemory.c_Power = 1; + } + + // prefer helicopter + ptrUnit = ptrPlayer->unit; + for (j = 0; j < config.max_installations; j++, ptrUnit++) + { + if (DE_isValidUnit(ptrUnit) && ptrUnit->unitType == UNIT_HELI) + { + ptrPlayer->unitSelected = j; + break; + } + } + + if (ptrCurUnit->unitType == UNIT_HELI) + { + if (ptrCurUnit->isYInAir == false) + { + ptrPlayer->aiMemory.c_Power = 1; + } + if (mt_rand() % ptrCurUnit->unitX > 100) + { + ptrPlayer->aiMemory.c_Power = 1; + } + if (mt_rand() % 240 > ptrCurUnit->unitX) + { + ptrPlayer->moves.actions[MOVE_RIGHT] = true; + } + else if ((mt_rand() % 20) + 300 < ptrCurUnit->unitX) + { + ptrPlayer->moves.actions[MOVE_LEFT] = true; + } + else if (mt_rand() % 30 == 1) + { + ptrPlayer->aiMemory.c_Angle = (mt_rand() % 3) - 1; + } + if (ptrCurUnit->unitX > 295 && ptrCurUnit->lastMove > 1) + { + ptrPlayer->moves.actions[MOVE_LEFT] = true; + ptrPlayer->moves.actions[MOVE_RIGHT] = false; + } + if (ptrCurUnit->unitType != UNIT_HELI || ptrCurUnit->lastMove > 3 || (ptrCurUnit->unitX > 160 && ptrCurUnit->lastMove > -3)) + { + if (mt_rand() % (int)roundf(ptrCurUnit->unitY) < 150 && ptrCurUnit->unitYMov < 0.01f && (ptrCurUnit->unitX < 160 || ptrCurUnit->lastMove < 2)) + { + ptrPlayer->moves.actions[MOVE_FIRE] = true; + } + ptrPlayer->aiMemory.c_noDown = (5 - abs(ptrCurUnit->lastMove)) * (5 - abs(ptrCurUnit->lastMove)) + 3; + ptrPlayer->aiMemory.c_Power = 1; + } else { + ptrPlayer->moves.actions[MOVE_FIRE] = false; + } + + ptrUnit = ptrTarget->unit; + for (j = 0; j < config.max_installations; j++, ptrUnit++) + { + if (abs(ptrUnit->unitX - ptrCurUnit->unitX) < 8) + { + /* I get it. This makes helicoptors hover over + * their enemies. */ + if (ptrUnit->unitType == UNIT_SATELLITE) + { + ptrPlayer->moves.actions[MOVE_FIRE] = false; + } + else + { + ptrPlayer->moves.actions[MOVE_LEFT] = false; + ptrPlayer->moves.actions[MOVE_RIGHT] = false; + if (ptrCurUnit->lastMove < -1) + { + ptrCurUnit->lastMove++; + } + else if (ptrCurUnit->lastMove > 1) + { + ptrCurUnit->lastMove--; + } + } + } + } + } else { + ptrPlayer->moves.actions[MOVE_FIRE] = 1; + } + + if (mt_rand() % 200 > 198) + { + ptrPlayer->moves.actions[MOVE_CHANGE] = true; + ptrPlayer->aiMemory.c_Angle = 0; + ptrPlayer->aiMemory.c_Power = 0; + ptrPlayer->aiMemory.c_Fire = 0; + } + + if (mt_rand() % 100 > 98 || ptrCurUnit->shotType == SHOT_TRACER) + { /* Clearly the CPU doesn't like the tracer :) */ + ptrPlayer->moves.actions[MOVE_CYDN] = true; + } + if (ptrPlayer->aiMemory.c_Angle > 0) + { + ptrPlayer->moves.actions[MOVE_LEFT] = true; + } + if (ptrPlayer->aiMemory.c_Angle < 0) + { + ptrPlayer->moves.actions[MOVE_RIGHT] = true; + } + if (ptrPlayer->aiMemory.c_Power > 0) + { + ptrPlayer->moves.actions[MOVE_UP] = true; + } + if (ptrPlayer->aiMemory.c_Power < 0 && ptrPlayer->aiMemory.c_noDown == 0) + { + ptrPlayer->moves.actions[MOVE_DOWN] = true; + } + if (ptrPlayer->aiMemory.c_Fire > 0) + { + ptrPlayer->moves.actions[MOVE_FIRE] = true; + } + + if (ptrCurUnit->unitYMov < -0.1f && ptrCurUnit->unitType == UNIT_HELI) + { + ptrPlayer->moves.actions[MOVE_FIRE] = false; + } + + /* This last hack was down in the processing section. + * What exactly it was doing there I do not know */ + if(ptrCurUnit->unitType == UNIT_LASER || ptrCurUnit->isYInAir == true) { + ptrPlayer->aiMemory.c_Power = 0; + } + } +} +void DE_RunTickDrawCrosshairs( void ) +{ + unsigned int i; + int tempPosX, tempPosY; + int direction; + struct destruct_unit_s * curUnit; + + + /* Draw the crosshairs. Most vehicles aim left or right. Helis can aim + * either way and this must be accounted for. + */ + for (i = 0; i < MAX_PLAYERS; i++) + { + direction = (i == PLAYER_LEFT) ? -1 : 1; + curUnit = &(player[i].unit[player[i].unitSelected]); + + if (curUnit->unitType == UNIT_HELI) + { + tempPosX = curUnit->unitX + roundf(0.1f * curUnit->lastMove * curUnit->lastMove * curUnit->lastMove) + 5; + tempPosY = roundf(curUnit->unitY) + 1; + } else { + tempPosX = roundf(curUnit->unitX + 6 - cosf(curUnit->angle) * (curUnit->power * 8 + 7) * direction); + tempPosY = roundf(curUnit->unitY - 7 - sinf(curUnit->angle) * (curUnit->power * 8 + 7)); + } + + /* Draw it. Clip away from the HUD though. */ + if(tempPosY > 9) + { + if(tempPosY > 11) + { + if(tempPosY > 13) + { + /* Top pixel */ + JE_pix(VGAScreen, tempPosX, tempPosY - 2, 3); + } + /* Middle three pixels */ + JE_pix(VGAScreen, tempPosX + 3, tempPosY, 3); + JE_pix(VGAScreen, tempPosX, tempPosY, 14); + JE_pix(VGAScreen, tempPosX - 3, tempPosY, 3); + } + /* Bottom pixel */ + JE_pix(VGAScreen, tempPosX, tempPosY + 2, 3); + } + } +} +void DE_RunTickDrawHUD( void ) +{ + unsigned int i; + unsigned int startX; + char tempstr[16]; /* Max size needed: 16 assuming 10 digit int max. */ + struct destruct_unit_s * curUnit; + + + for (i = 0; i < MAX_PLAYERS; i++) + { + curUnit = &(player[i].unit[player[i].unitSelected]); + startX = ((i == PLAYER_LEFT) ? 0 : 320 - 150); + + fill_rectangle_xy(VGAScreen, startX + 5, 3, startX + 14, 8, 241); + JE_rectangle(VGAScreen, startX + 4, 2, startX + 15, 9, 242); + JE_rectangle(VGAScreen, startX + 3, 1, startX + 16, 10, 240); + fill_rectangle_xy(VGAScreen, startX + 18, 3, startX + 140, 8, 241); + JE_rectangle(VGAScreen, startX + 17, 2, startX + 143, 9, 242); + JE_rectangle(VGAScreen, startX + 16, 1, startX + 144, 10, 240); + + blit_sprite2(VGAScreen, startX + 4, 0, eShapes1, 191 + curUnit->shotType); + + JE_outText (VGAScreen, startX + 20, 3, weaponNames[curUnit->shotType], 15, 2); + sprintf (tempstr, "dmg~%d~", curUnit->health); + JE_outText (VGAScreen, startX + 75, 3, tempstr, 15, 0); + sprintf (tempstr, "pts~%d~", player[i].score); + JE_outText (VGAScreen, startX + 110, 3, tempstr, 15, 0); + } +} +void DE_RunTickGetInput( void ) +{ + unsigned int player_index, key_index, slot_index; + SDLKey key; + + /* player.keys holds our key config. Players will eventually be allowed + * to can change their key mappings. player.moves and player.keys + * line up; rather than manually checking left and right we can + * just loop through the indexes and set the actions as needed. */ + service_SDL_events(true); + + for(player_index = 0; player_index < MAX_PLAYERS; player_index++) + { + for(key_index = 0; key_index < MAX_KEY; key_index++) + { + for(slot_index = 0; slot_index < MAX_KEY_OPTIONS; slot_index++) + { + key = player[player_index].keys.Config[key_index][slot_index]; + if(key == SDLK_UNKNOWN) { break; } + if(keysactive[key] == true) + { + /* The right key was clearly pressed */ + player[player_index].moves.actions[key_index] = true; + + /* Some keys we want to toggle afterwards */ + if(key_index == KEY_CHANGE || + key_index == KEY_CYUP || + key_index == KEY_CYDN) + { + keysactive[key] = false; + } + break; + } + } + } + } +} +void DE_ProcessInput( void ) +{ + int direction; + + unsigned int player_index; + struct destruct_unit_s * curUnit; + + + for (player_index = 0; player_index < MAX_PLAYERS; player_index++) + { + if (player[player_index].unitsRemaining <= 0) { continue; } + + direction = (player_index == PLAYER_LEFT) ? -1 : 1; + curUnit = &(player[player_index].unit[player[player_index].unitSelected]); + + if (systemAngle[curUnit->unitType] == true) /* selected unit may change shot angle */ + { + if (player[player_index].moves.actions[MOVE_LEFT] == true) + { + (player_index == PLAYER_LEFT) ? DE_RaiseAngle(curUnit) : DE_LowerAngle(curUnit); + } + if (player[player_index].moves.actions[MOVE_RIGHT] == true) + { + (player_index == PLAYER_LEFT) ? DE_LowerAngle(curUnit) : DE_RaiseAngle(curUnit); + + } + } else if (curUnit->unitType == UNIT_HELI) { + if (player[player_index].moves.actions[MOVE_LEFT] == true && curUnit->unitX > 5) + if (JE_stabilityCheck(curUnit->unitX - 5, roundf(curUnit->unitY))) + { + if (curUnit->lastMove > -5) + { + curUnit->lastMove--; + } + curUnit->unitX--; + if (JE_stabilityCheck(curUnit->unitX, roundf(curUnit->unitY))) + { + curUnit->isYInAir = true; + } + } + if (player[player_index].moves.actions[MOVE_RIGHT] == true && curUnit->unitX < 305) + { + if (JE_stabilityCheck(curUnit->unitX + 5, roundf(curUnit->unitY))) + { + if (curUnit->lastMove < 5) + { + curUnit->lastMove++; + } + curUnit->unitX++; + if (JE_stabilityCheck(curUnit->unitX, roundf(curUnit->unitY))) + { + curUnit->isYInAir = true; + } + } + } + } + + if (curUnit->unitType != UNIT_LASER) + + { /*increasepower*/ + if (player[player_index].moves.actions[MOVE_UP] == true) + { + if (curUnit->unitType == UNIT_HELI) + { + curUnit->isYInAir = true; + curUnit->unitYMov -= 0.1f; + } + else if (curUnit->unitType == UNIT_JUMPER + && curUnit->isYInAir == false) { + curUnit->unitYMov = -3; + curUnit->isYInAir = true; + } + else { + DE_RaisePower(curUnit); + } + } + /*decreasepower*/ + if (player[player_index].moves.actions[MOVE_DOWN] == true) + { + if (curUnit->unitType == UNIT_HELI && curUnit->isYInAir == true) + { + curUnit->unitYMov += 0.1f; + } else { + DE_LowerPower(curUnit); + } + } + } + + /*up/down weapon. These just cycle until a valid weapon is found */ + if (player[player_index].moves.actions[MOVE_CYUP] == true) + { + DE_CycleWeaponUp(curUnit); + } + if (player[player_index].moves.actions[MOVE_CYDN] == true) + { + DE_CycleWeaponDown(curUnit); + } + + /* Change. Since change would change out curUnit pointer, let's just do it last. + * Validity checking is performed at the beginning of the tick. */ + if (player[player_index].moves.actions[MOVE_CHANGE] == true) + { + player[player_index].unitSelected++; + if (player[player_index].unitSelected >= config.max_installations) + { + player[player_index].unitSelected = 0; + } + } + + /*Newshot*/ + if (player[player_index].shotDelay > 0) + { + player[player_index].shotDelay--; + } + if (player[player_index].moves.actions[MOVE_FIRE] == true + && (player[player_index].shotDelay == 0)) + { + player[player_index].shotDelay = shotDelay[curUnit->shotType]; + + switch(shotDirt[curUnit->shotType]) + { + case EXPL_NONE: + break; + + case EXPL_MAGNET: + DE_RunMagnet((de_player_t)player_index, curUnit); + break; + + case EXPL_DIRT: + case EXPL_NORMAL: + DE_MakeShot((de_player_t)player_index, curUnit, direction); + break; + + default: + assert(false); + } + } + } +} + +void DE_CycleWeaponUp( struct destruct_unit_s * unit ) +{ + do + { + unit->shotType = (de_shot_t)((int)unit->shotType + 1); + if (unit->shotType > SHOT_LAST) + { + unit->shotType = SHOT_FIRST; + } + } while (weaponSystems[unit->unitType][unit->shotType] == 0); +} +void DE_CycleWeaponDown( struct destruct_unit_s * unit ) +{ + do + { + unit->shotType = (de_shot_t)((int)unit->shotType - 1); + if (unit->shotType < SHOT_FIRST) + { + unit->shotType = SHOT_LAST; + } + } while (weaponSystems[unit->unitType][unit->shotType] == 0); +} + + +void DE_MakeShot( enum de_player_t curPlayer, const struct destruct_unit_s * curUnit, int direction ) +{ + unsigned int i; + unsigned int shotIndex; + + + /* First, find an empty shot struct we can use */ + for (i = 0; ; i++) + { + if (i >= config.max_shots) { return; } /* no empty slots. Do nothing. */ + + if (shotRec[i].isAvailable) + { + shotIndex = i; + break; + } + } + if (curUnit->unitType == UNIT_HELI && curUnit->isYInAir == false) + { /* Helis can't fire when they are on the ground. */ + return; + } + + /* Play the firing sound */ + soundQueue[curPlayer] = shotSound[curUnit->shotType]; + + /* Create our shot. Some units have differing logic here */ + switch (curUnit->unitType) + { + case UNIT_HELI: + + shotRec[shotIndex].x = curUnit->unitX + curUnit->lastMove * 2 + 5; + shotRec[shotIndex].xmov = 0.02f * curUnit->lastMove * curUnit->lastMove * curUnit->lastMove; + + /* If we are trying in vain to move up off the screen, act differently.*/ + if (player[curPlayer].moves.actions[MOVE_UP] && curUnit->unitY < 30) + { + shotRec[shotIndex].y = curUnit->unitY; + shotRec[shotIndex].ymov = 0.1f; + + if (shotRec[shotIndex].xmov < 0) + { + shotRec[shotIndex].xmov += 0.1f; + } + else if (shotRec[shotIndex].xmov > 0) + { + shotRec[shotIndex].xmov -= 0.1f; + } + } + else + { + shotRec[shotIndex].y = curUnit->unitY + 1; + shotRec[shotIndex].ymov = 0.5f + curUnit->unitYMov * 0.1f; + } + break; + + case UNIT_JUMPER: /* Jumpers are normally only special for the left hand player. Bug? Or feature? */ + + if(config.jumper_straight[curPlayer]) + { + /* This is identical to the default case. + * I considered letting the switch fall through + * but that's more confusing to people who aren't used + * to that quirk of switch. */ + + shotRec[shotIndex].x = curUnit->unitX + 6 - cosf(curUnit->angle) * 10 * direction; + shotRec[shotIndex].y = curUnit->unitY - 7 - sinf(curUnit->angle) * 10; + shotRec[shotIndex].xmov = -cosf(curUnit->angle) * curUnit->power * direction; + shotRec[shotIndex].ymov = -sinf(curUnit->angle) * curUnit->power; + } + else + { + /* This is not identical to the default case. */ + + shotRec[shotIndex].x = curUnit->unitX + 2; + shotRec[shotIndex].xmov = -cosf(curUnit->angle) * curUnit->power * direction; + + if (curUnit->isYInAir == true) + { + shotRec[shotIndex].ymov = 1; + shotRec[shotIndex].y = curUnit->unitY + 2; + } else { + shotRec[shotIndex].ymov = -2; + shotRec[shotIndex].y = curUnit->unitY - 12; + } + } + break; + + default: + + shotRec[shotIndex].x = curUnit->unitX + 6 - cosf(curUnit->angle) * 10 * direction; + shotRec[shotIndex].y = curUnit->unitY - 7 - sinf(curUnit->angle) * 10; + shotRec[shotIndex].xmov = -cosf(curUnit->angle) * curUnit->power * direction; + shotRec[shotIndex].ymov = -sinf(curUnit->angle) * curUnit->power; + break; + } + + /* Now set/clear out a few last details. */ + shotRec[shotIndex].isAvailable = false; + + shotRec[shotIndex].shottype = curUnit->shotType; + //shotRec[shotIndex].shotdur = shotFuse[shotRec[shotIndex].shottype]; + + shotRec[shotIndex].trailc[0] = 0; + shotRec[shotIndex].trailc[1] = 0; + shotRec[shotIndex].trailc[2] = 0; + shotRec[shotIndex].trailc[3] = 0; +} +void DE_RunMagnet( enum de_player_t curPlayer, struct destruct_unit_s * magnet ) +{ + unsigned int i; + enum de_player_t curEnemy; + int direction; + struct destruct_unit_s * enemyUnit; + + + curEnemy = (curPlayer == PLAYER_LEFT) ? PLAYER_RIGHT : PLAYER_LEFT; + direction = (curPlayer == PLAYER_LEFT) ? -1 : 1; + + /* Push all shots that are in front of the magnet */ + for (i = 0; i < config.max_shots; i++) + { + if (shotRec[i].isAvailable == false) + { + if ((curPlayer == PLAYER_LEFT && shotRec[i].x > magnet->unitX) + || (curPlayer == PLAYER_RIGHT && shotRec[i].x < magnet->unitX)) + { + shotRec[i].xmov += magnet->power * 0.1f * -direction; + } + } + } + + enemyUnit = player[curEnemy].unit; + for (i = 0; i < config.max_installations; i++, enemyUnit++) /* magnets push coptors */ + { + if (DE_isValidUnit(enemyUnit) + && enemyUnit->unitType == UNIT_HELI + && enemyUnit->isYInAir == true) + { + if ((curEnemy == PLAYER_RIGHT && player[curEnemy].unit[i].unitX + 11 < 318) + || (curEnemy == PLAYER_LEFT && player[curEnemy].unit[i].unitX > 1)) + { + enemyUnit->unitX -= 2 * direction; + } + } + } + magnet->ani_frame = 1; +} +void DE_RaiseAngle( struct destruct_unit_s * unit ) +{ + unit->angle += 0.01f; + if (unit->angle > M_PI_2 - 0.01f) + { + unit->angle = M_PI_2 - 0.01f; + } +} +void DE_LowerAngle( struct destruct_unit_s * unit ) +{ + unit->angle -= 0.01f; + if (unit->angle < 0) + { + unit->angle = 0; + } +} +void DE_RaisePower( struct destruct_unit_s * unit ) +{ + unit->power += 0.05f; + if (unit->power > 5) + { + unit->power = 5; + } +} +void DE_LowerPower( struct destruct_unit_s * unit ) +{ + unit->power -= 0.05f; + if (unit->power < 1) + { + unit->power = 1; + } +} + +/* DE_isValidUnit + * + * Returns true if the unit's health is above 0 and false + * otherwise. This mainly exists because the 'health' var + * serves two roles and that can get confusing. + */ +static inline bool DE_isValidUnit( struct destruct_unit_s * unit ) +{ + return(unit->health > 0); +} + + +bool DE_RunTickCheckEndgame( void ) +{ + if (player[PLAYER_LEFT].unitsRemaining == 0) + { + player[PLAYER_RIGHT].score += ModeScore[PLAYER_LEFT][world.destructMode]; + soundQueue[7] = V_CLEARED_PLATFORM; + return(true); + } + if (player[PLAYER_RIGHT].unitsRemaining == 0) + { + player[PLAYER_LEFT].score += ModeScore[PLAYER_RIGHT][world.destructMode]; + soundQueue[7] = V_CLEARED_PLATFORM; + return(true); + } + return(false); +} +void DE_RunTickPlaySounds( void ) +{ + unsigned int i, tempSampleIndex, tempVolume; + + + for (i = 0; i < COUNTOF(soundQueue); i++) + { + if (soundQueue[i] != S_NONE) + { + tempSampleIndex = soundQueue[i]; + if (i == 7) + { + tempVolume = fxPlayVol; + } + else + { + tempVolume = fxPlayVol / 2; + } + + JE_multiSamplePlay(digiFx[tempSampleIndex-1], fxSize[tempSampleIndex-1], i, tempVolume); + soundQueue[i] = S_NONE; + } + } +} + +void JE_pixCool( unsigned int x, unsigned int y, Uint8 c ) +{ + JE_pix(VGAScreen, x, y, c); + JE_pix(VGAScreen, x - 1, y, c - 2); + JE_pix(VGAScreen, x + 1, y, c - 2); + JE_pix(VGAScreen, x, y - 1, c - 2); + JE_pix(VGAScreen, x, y + 1, c - 2); +} +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/destruct.h b/alienblaster/project/jni/application/opentyrian/src/destruct.h new file mode 100644 index 000000000..9d1ab78aa --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/destruct.h @@ -0,0 +1,28 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DESTRUCT_H +#define DESTRUCT_H + +#include "opentyr.h" + +void JE_destructGame( void ); + +#endif /* DESTRUCT_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/editship.cpp b/alienblaster/project/jni/application/opentyrian/src/editship.cpp new file mode 100644 index 000000000..e0c5bd06e --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/editship.cpp @@ -0,0 +1,92 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "editship.h" +#include "file.h" +#include "opentyr.h" + +#define SAS (sizeof(JE_ShipsType) - 4) + +const JE_byte extraCryptKey[10] = { 58, 23, 16, 192, 254, 82, 113, 147, 62, 99 }; + +JE_boolean extraAvail; +JE_ShipsType extraShips; +void *extraShapes; +JE_word extraShapeSize; + +void JE_decryptShips( void ) +{ + JE_boolean correct = true; + JE_ShipsType s2; + JE_byte y; + + for (int x = SAS - 1; x >= 0; x--) + { + s2[x] = extraShips[x] ^ extraCryptKey[(x + 1) % 10]; + if (x > 0) + s2[x] ^= extraShips[x - 1]; + } /* <= Key Decryption Test (Reversed key) */ + + y = 0; + for (uint x = 0; x < SAS; x++) + y += s2[x]; + if (extraShips[SAS + 0] != y) + correct = false; + + y = 0; + for (uint x = 0; x < SAS; x++) + y -= s2[x]; + if (extraShips[SAS + 1] != y) + correct = false; + + y = 1; + for (uint x = 0; x < SAS; x++) + y = y * s2[x] + 1; + if (extraShips[SAS + 2] != y) + correct = false; + + y = 0; + for (uint x = 0; x < SAS; x++) + y ^= s2[x]; + if (extraShips[SAS + 3] != y) + correct = false; + + if (!correct) + exit(255); + + memcpy(extraShips, s2, sizeof(extraShips)); +} + +void JE_loadExtraShapes( void ) +{ + FILE *f = dir_fopen(get_user_directory(), "newsh$.shp", "rb"); + + if (f) + { + extraAvail = true; + extraShapeSize = ftell_eof(f) - sizeof(extraShips); + extraShapes = malloc(extraShapeSize); + efread(extraShapes, extraShapeSize, 1, f); + efread(extraShips, sizeof(extraShips), 1, f); + JE_decryptShips(); + fclose(f); + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/editship.h b/alienblaster/project/jni/application/opentyrian/src/editship.h new file mode 100644 index 000000000..4496fecc9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/editship.h @@ -0,0 +1,37 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef EDITSHIP_H +#define EDITSHIP_H + +#include "opentyr.h" + + +typedef JE_byte JE_ShipsType[154]; /* [1..154] */ + +extern JE_boolean extraAvail; +extern JE_ShipsType extraShips; +extern void *extraShapes; +extern JE_word extraShapeSize; + +void JE_decryptShips( void ); +void JE_loadExtraShapes( void ); + +#endif /* EDITSHIP_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/episodes.cpp b/alienblaster/project/jni/application/opentyrian/src/episodes.cpp new file mode 100644 index 000000000..f513281a3 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/episodes.cpp @@ -0,0 +1,267 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "episodes.h" +#include "file.h" +#include "lvllib.h" +#include "lvlmast.h" +#include "opentyr.h" + + +/* MAIN Weapons Data */ +JE_WeaponPortType weaponPort; +JE_WeaponType weapons; + +/* Items */ +JE_PowerType powerSys; +JE_ShipType ships; +JE_OptionType options[OPTION_NUM + 1]; /* [0..optionnum] */ +JE_ShieldType shields; +JE_SpecialType special; + +/* Enemy data */ +JE_EnemyDatType enemyDat; + +/* EPISODE variables */ +JE_byte initial_episode_num, episodeNum = 0; +JE_boolean episodeAvail[EPISODE_MAX]; /* [1..episodemax] */ +char episode_file[13], cube_file[13]; + +JE_longint episode1DataLoc; + +/* Tells the game whether the level currently loaded is a bonus level. */ +JE_boolean bonusLevel; + +/* Tells if the game jumped back to Episode 1 */ +JE_boolean jumpBackToEpisode1; + +void JE_loadItemDat( void ) +{ + FILE *f = NULL; + + if (episodeNum <= 3) + { + f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb"); + efread(&episode1DataLoc, sizeof(JE_longint), 1, f); + fseek(f, episode1DataLoc, SEEK_SET); + } + else + { + // episode 4 stores item data in the level file + f = dir_fopen_die(data_dir(), levelFile, "rb"); + fseek(f, lvlPos[lvlNum-1], SEEK_SET); + } + + JE_word itemNum[7]; /* [1..7] */ + efread(&itemNum, sizeof(JE_word), 7, f); + + for (int i = 0; i < WEAP_NUM + 1; ++i) + { + efread(&weapons[i].drain, sizeof(JE_word), 1, f); + efread(&weapons[i].shotrepeat, sizeof(JE_byte), 1, f); + efread(&weapons[i].multi, sizeof(JE_byte), 1, f); + efread(&weapons[i].weapani, sizeof(JE_word), 1, f); + efread(&weapons[i].max, sizeof(JE_byte), 1, f); + efread(&weapons[i].tx, sizeof(JE_byte), 1, f); + efread(&weapons[i].ty, sizeof(JE_byte), 1, f); + efread(&weapons[i].aim, sizeof(JE_byte), 1, f); + efread(&weapons[i].attack, sizeof(JE_byte), 8, f); + efread(&weapons[i].del, sizeof(JE_byte), 8, f); + efread(&weapons[i].sx, sizeof(JE_shortint), 8, f); + efread(&weapons[i].sy, sizeof(JE_shortint), 8, f); + efread(&weapons[i].bx, sizeof(JE_shortint), 8, f); + efread(&weapons[i].by, sizeof(JE_shortint), 8, f); + efread(&weapons[i].sg, sizeof(JE_word), 8, f); + efread(&weapons[i].acceleration, sizeof(JE_shortint), 1, f); + efread(&weapons[i].accelerationx, sizeof(JE_shortint), 1, f); + efread(&weapons[i].circlesize, sizeof(JE_byte), 1, f); + efread(&weapons[i].sound, sizeof(JE_byte), 1, f); + efread(&weapons[i].trail, sizeof(JE_byte), 1, f); + efread(&weapons[i].shipblastfilter, sizeof(JE_byte), 1, f); + } + + for (int i = 0; i < PORT_NUM + 1; ++i) + { + fseek(f, 1, SEEK_CUR); /* skip string length */ + efread(&weaponPort[i].name, 1, 30, f); + weaponPort[i].name[30] = '\0'; + efread(&weaponPort[i].opnum, sizeof(JE_byte), 1, f); + for (int j = 0; j < 2; ++j) + { + efread(&weaponPort[i].op[j], sizeof(JE_word), 11, f); + } + efread(&weaponPort[i].cost, sizeof(JE_word), 1, f); + efread(&weaponPort[i].itemgraphic, sizeof(JE_word), 1, f); + efread(&weaponPort[i].poweruse, sizeof(JE_word), 1, f); + } + + for (int i = 0; i < SPECIAL_NUM + 1; ++i) + { + fseek(f, 1, SEEK_CUR); /* skip string length */ + efread(&special[i].name, 1, 30, f); + special[i].name[30] = '\0'; + efread(&special[i].itemgraphic, sizeof(JE_word), 1, f); + efread(&special[i].pwr, sizeof(JE_byte), 1, f); + efread(&special[i].stype, sizeof(JE_byte), 1, f); + efread(&special[i].wpn, sizeof(JE_word), 1, f); + } + + for (int i = 0; i < POWER_NUM + 1; ++i) + { + fseek(f, 1, SEEK_CUR); /* skip string length */ + efread(&powerSys[i].name, 1, 30, f); + powerSys[i].name[30] = '\0'; + efread(&powerSys[i].itemgraphic, sizeof(JE_word), 1, f); + efread(&powerSys[i].power, sizeof(JE_shortint), 1, f); + efread(&powerSys[i].speed, sizeof(JE_byte), 1, f); + efread(&powerSys[i].cost, sizeof(JE_word), 1, f); + } + + for (int i = 0; i < SHIP_NUM + 1; ++i) + { + fseek(f, 1, SEEK_CUR); /* skip string length */ + efread(&ships[i].name, 1, 30, f); + ships[i].name[30] = '\0'; + efread(&ships[i].shipgraphic, sizeof(JE_word), 1, f); + efread(&ships[i].itemgraphic, sizeof(JE_word), 1, f); + efread(&ships[i].ani, sizeof(JE_byte), 1, f); + efread(&ships[i].spd, sizeof(JE_shortint), 1, f); + efread(&ships[i].dmg, sizeof(JE_byte), 1, f); + efread(&ships[i].cost, sizeof(JE_word), 1, f); + efread(&ships[i].bigshipgraphic, sizeof(JE_byte), 1, f); + } + + for (int i = 0; i < OPTION_NUM + 1; ++i) + { + fseek(f, 1, SEEK_CUR); /* skip string length */ + efread(&options[i].name, 1, 30, f); + options[i].name[30] = '\0'; + efread(&options[i].pwr, sizeof(JE_byte), 1, f); + efread(&options[i].itemgraphic, sizeof(JE_word), 1, f); + efread(&options[i].cost, sizeof(JE_word), 1, f); + efread(&options[i].tr, sizeof(JE_byte), 1, f); + efread(&options[i].option, sizeof(JE_byte), 1, f); + efread(&options[i].opspd, sizeof(JE_shortint), 1, f); + efread(&options[i].ani, sizeof(JE_byte), 1, f); + efread(&options[i].gr, sizeof(JE_word), 20, f); + efread(&options[i].wport, sizeof(JE_byte), 1, f); + efread(&options[i].wpnum, sizeof(JE_word), 1, f); + efread(&options[i].ammo, sizeof(JE_byte), 1, f); + efread(&options[i].stop, 1, 1, f); /* override sizeof(JE_boolean) */ + efread(&options[i].icongr, sizeof(JE_byte), 1, f); + } + + for (int i = 0; i < SHIELD_NUM + 1; ++i) + { + fseek(f, 1, SEEK_CUR); /* skip string length */ + efread(&shields[i].name, 1, 30, f); + shields[i].name[30] = '\0'; + efread(&shields[i].tpwr, sizeof(JE_byte), 1, f); + efread(&shields[i].mpwr, sizeof(JE_byte), 1, f); + efread(&shields[i].itemgraphic, sizeof(JE_word), 1, f); + efread(&shields[i].cost, sizeof(JE_word), 1, f); + } + + for (int i = 0; i < ENEMY_NUM + 1; ++i) + { + efread(&enemyDat[i].ani, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].tur, sizeof(JE_byte), 3, f); + efread(&enemyDat[i].freq, sizeof(JE_byte), 3, f); + efread(&enemyDat[i].xmove, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].ymove, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].xaccel, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].yaccel, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].xcaccel, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].ycaccel, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].startx, sizeof(JE_integer), 1, f); + efread(&enemyDat[i].starty, sizeof(JE_integer), 1, f); + efread(&enemyDat[i].startxc, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].startyc, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].armor, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].esize, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].egraphic, sizeof(JE_word), 20, f); + efread(&enemyDat[i].explosiontype, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].animate, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].shapebank, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].xrev, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].yrev, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].dgr, sizeof(JE_word), 1, f); + efread(&enemyDat[i].dlevel, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].dani, sizeof(JE_shortint), 1, f); + efread(&enemyDat[i].elaunchfreq, sizeof(JE_byte), 1, f); + efread(&enemyDat[i].elaunchtype, sizeof(JE_word), 1, f); + efread(&enemyDat[i].value, sizeof(JE_integer), 1, f); + efread(&enemyDat[i].eenemydie, sizeof(JE_word), 1, f); + } + + fclose(f); +} + +void JE_initEpisode( JE_byte newEpisode ) +{ + if (newEpisode == episodeNum) + return; + + episodeNum = newEpisode; + + sprintf(levelFile, "tyrian%d.lvl", episodeNum); + sprintf(cube_file, "cubetxt%d.dat", episodeNum); + sprintf(episode_file, "levels%d.dat", episodeNum); + + JE_analyzeLevel(); + JE_loadItemDat(); +} + +void JE_scanForEpisodes( void ) +{ + for (int i = 0; i < EPISODE_MAX; ++i) + { + char ep_file[20]; + snprintf(ep_file, sizeof(ep_file), "tyrian%d.lvl", i + 1); + episodeAvail[i] = dir_file_exists(data_dir(), ep_file); + } +} + +unsigned int JE_findNextEpisode( void ) +{ + unsigned int newEpisode = episodeNum; + + jumpBackToEpisode1 = false; + + while (true) + { + newEpisode++; + + if (newEpisode > EPISODE_MAX) + { + newEpisode = 1; + jumpBackToEpisode1 = true; + gameHasRepeated = true; + } + + if (episodeAvail[newEpisode-1] || newEpisode == episodeNum) + { + break; + } + } + + return newEpisode; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/episodes.h b/alienblaster/project/jni/application/opentyrian/src/episodes.h new file mode 100644 index 000000000..baf4bc60a --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/episodes.h @@ -0,0 +1,173 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef EPISODES_H +#define EPISODES_H + +#include "opentyr.h" + +#include "lvlmast.h" + + +/* Episodes and general data */ + +#define FIRST_LEVEL 1 +#define EPISODE_MAX 5 + +typedef struct +{ + JE_word drain; + JE_byte shotrepeat; + JE_byte multi; + JE_word weapani; + JE_byte max; + JE_byte tx, ty, aim; + JE_byte attack[8], del[8]; /* [1..8] */ + JE_shortint sx[8], sy[8]; /* [1..8] */ + JE_shortint bx[8], by[8]; /* [1..8] */ + JE_word sg[8]; /* [1..8] */ + JE_shortint acceleration, accelerationx; + JE_byte circlesize; + JE_byte sound; + JE_byte trail; + JE_byte shipblastfilter; +} JE_WeaponType[WEAP_NUM + 1]; /* [0..weapnum] */ + +typedef struct +{ + char name[31]; /* string [30] */ + JE_byte opnum; + JE_word op[2][11]; /* [1..2, 1..11] */ + JE_word cost; + JE_word itemgraphic; + JE_word poweruse; +} JE_WeaponPortType[PORT_NUM + 1]; /* [0..portnum] */ + +typedef struct +{ + char name[31]; /* string [30] */ + JE_word itemgraphic; + JE_byte power; + JE_shortint speed; + JE_word cost; +} JE_PowerType[POWER_NUM + 1]; /* [0..powernum] */ + +typedef struct +{ + char name[31]; /* string [30] */ + JE_word itemgraphic; + JE_byte pwr; + JE_byte stype; + JE_word wpn; +} JE_SpecialType[SPECIAL_NUM + 1]; /* [0..specialnum] */ + +typedef struct +{ + char name[31]; /* string [30] */ + JE_byte pwr; + JE_word itemgraphic; + JE_word cost; + JE_byte tr, option; + JE_shortint opspd; + JE_byte ani; + JE_word gr[20]; /* [1..20] */ + JE_byte wport; + JE_word wpnum; + JE_byte ammo; + JE_boolean stop; + JE_byte icongr; +} JE_OptionType; + +typedef struct +{ + char name[31]; /* string [30] */ + JE_byte tpwr; + JE_byte mpwr; + JE_word itemgraphic; + JE_word cost; +} JE_ShieldType[SHIELD_NUM + 1]; /* [0..shieldnum] */ + +typedef struct +{ + char name[31]; /* string [30] */ + JE_word shipgraphic; + JE_word itemgraphic; + JE_byte ani; + JE_shortint spd; + JE_byte dmg; + JE_word cost; + JE_byte bigshipgraphic; +} JE_ShipType[SHIP_NUM + 1]; /* [0..shipnum] */ + +/* EnemyData */ +typedef struct +{ + JE_byte ani; + JE_byte tur[3]; /* [1..3] */ + JE_byte freq[3]; /* [1..3] */ + JE_shortint xmove; + JE_shortint ymove; + JE_shortint xaccel; + JE_shortint yaccel; + JE_shortint xcaccel; + JE_shortint ycaccel; + JE_integer startx; + JE_integer starty; + JE_shortint startxc; + JE_shortint startyc; + JE_byte armor; + JE_byte esize; + JE_word egraphic[20]; /* [1..20] */ + JE_byte explosiontype; + JE_byte animate; /* 0:Not Yet 1:Always 2:When Firing Only */ + JE_byte shapebank; /* See LEVELMAK.DOC */ + JE_shortint xrev, yrev; + JE_word dgr; + JE_shortint dlevel; + JE_shortint dani; + JE_byte elaunchfreq; + JE_word elaunchtype; + JE_integer value; + JE_word eenemydie; +} JE_EnemyDatType[ENEMY_NUM + 1]; /* [0..enemynum] */ + +extern JE_WeaponPortType weaponPort; +extern JE_WeaponType weapons; +extern JE_PowerType powerSys; +extern JE_ShipType ships; +extern JE_OptionType options[OPTION_NUM + 1]; /* [0..optionnum] */ +extern JE_ShieldType shields; +extern JE_SpecialType special; +extern JE_EnemyDatType enemyDat; +extern JE_byte initial_episode_num, episodeNum; +extern JE_boolean episodeAvail[EPISODE_MAX]; + +extern char episode_file[13], cube_file[13]; + +extern JE_longint episode1DataLoc; +extern JE_boolean bonusLevel; +extern JE_boolean jumpBackToEpisode1; + +void JE_loadItemDat( void ); +void JE_initEpisode( JE_byte newEpisode ); +unsigned int JE_findNextEpisode( void ); +void JE_scanForEpisodes( void ); + +#endif /* EPISODES_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/file.cpp b/alienblaster/project/jni/application/opentyrian/src/file.cpp new file mode 100644 index 000000000..7020c048e --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/file.cpp @@ -0,0 +1,192 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "opentyr.h" + +#include "SDL.h" +#include + +const char *custom_data_dir = "."; + +// finds the Tyrian data directory +const char *data_dir( void ) +{ + const char *dirs[] = + { + custom_data_dir, + "data", +#ifdef TARGET_MACOSX + tyrian_game_folder(), +#endif + "/usr/share/opentyrian/data" + }; + + static const char *dir = NULL; + + if (dir != NULL) + return dir; + + for (uint i = 0; i < COUNTOF(dirs); ++i) + { + FILE *f = dir_fopen(dirs[i], "tyrian1.lvl", "rb"); + if (f) + { + fclose(f); + + dir = dirs[i]; + break; + } + } + + if (dir == NULL) // data not found + dir = ""; + + return dir; +} + +// prepend directory and fopen +FILE *dir_fopen( const char *dir, const char *file, const char *mode ) +{ + char *path = (char *)malloc(strlen(dir) + 1 + strlen(file) + 1); + sprintf(path, "%s/%s", dir, file); + + FILE *f = fopen(path, mode); + + free(path); + + return f; +} + +// warn when dir_fopen fails +FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode ) +{ + errno = 0; + + FILE *f = dir_fopen(dir, file, mode); + + if (!f) + fprintf(stderr, "warning: failed to open '%s': %s\n", file, strerror(errno)); + + return f; +} + +// die when dir_fopen fails +FILE *dir_fopen_die( const char *dir, const char *file, const char *mode ) +{ + errno = 0; + + FILE *f = dir_fopen(dir, file, mode); + + if (f == NULL) + { + fprintf(stderr, "error: failed to open '%s': %s\n", file, strerror(errno)); + fprintf(stderr, "error: One or more of the required Tyrian 2.1 data files could not be found.\n" + " Please read the README file.\n"); + exit(1); + } + + return f; +} + +// check if file can be opened for reading +bool dir_file_exists( const char *dir, const char *file ) +{ + FILE *f = dir_fopen(dir, file, "rb"); + if (f != NULL) + fclose(f); + return (f != NULL); +} + +// returns end-of-file position +long ftell_eof( FILE *f ) +{ + long pos = ftell(f); + + fseek(f, 0, SEEK_END); + long size = ftell(f); + + fseek(f, pos, SEEK_SET); + + return size; +} + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +// endian-swapping fread +size_t efread( void *buffer, size_t size, size_t num, FILE *stream ) +{ + size_t f = fread(buffer, size, num, stream); + + switch (size) + { + case 2: + for (size_t i = 0; i < num; i++) + ((Uint16 *)buffer)[i] = SDL_Swap16(((Uint16 *)buffer)[i]); + break; + case 4: + for (size_t i = 0; i < num; i++) + ((Uint32 *)buffer)[i] = SDL_Swap32(((Uint32 *)buffer)[i]); + break; + case 8: + for (size_t i = 0; i < num; i++) + ((Uint64 *)buffer)[i] = SDL_Swap64(((Uint64 *)buffer)[i]); + break; + default: + break; + } + + return f; +} + +// endian-swapping fwrite +size_t efwrite( void *buffer, size_t size, size_t num, FILE *stream ) +{ + void *swap_buffer; + + switch (size) + { + case 2: + swap_buffer = malloc(size * num); + for (size_t i = 0; i < num; i++) + ((Uint16 *)swap_buffer)[i] = SDL_SwapLE16(((Uint16 *)buffer)[i]); + break; + case 4: + swap_buffer = malloc(size * num); + for (size_t i = 0; i < num; i++) + ((Uint32 *)swap_buffer)[i] = SDL_SwapLE32(((Uint32 *)buffer)[i]); + break; + case 8: + swap_buffer = malloc(size * num); + for (size_t i = 0; i < num; i++) + ((Uint64 *)swap_buffer)[i] = SDL_SwapLE64(((Uint64 *)buffer)[i]); + break; + default: + swap_buffer = buffer; + break; + } + + size_t f = fwrite(swap_buffer, size, num, stream); + + if (swap_buffer != buffer) + free(swap_buffer); + + return f; +} +#endif + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/file.h b/alienblaster/project/jni/application/opentyrian/src/file.h new file mode 100644 index 000000000..089f24837 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/file.h @@ -0,0 +1,53 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef FILE_H +#define FILE_H + +#include "SDL_endian.h" +#include +#include + +extern const char *custom_data_dir; + +#ifdef TARGET_MACOSX +const char *tyrian_game_folder(); +#endif // TARGET_MACOSX + +const char *data_dir( void ); + +FILE *dir_fopen( const char *dir, const char *file, const char *mode ); +FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode ); +FILE *dir_fopen_die( const char *dir, const char *file, const char *mode ); + +bool dir_file_exists( const char *dir, const char *file ); + +long ftell_eof( FILE *f ); + +// endian-swapping fread/fwrite +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +size_t efread( void *buffer, size_t size, size_t num, FILE *stream ); +size_t efwrite( void *buffer, size_t size, size_t num, FILE *stream ); +#else +#define efread fread +#define efwrite fwrite +#endif + +#endif // FILE_H + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/fm_synth.cpp b/alienblaster/project/jni/application/opentyrian/src/fm_synth.cpp new file mode 100644 index 000000000..6c2ba9adc --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/fm_synth.cpp @@ -0,0 +1,54 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "fmopl.h" +#include "fm_synth.h" +#include "loudness.h" +#include "opentyr.h" + +const unsigned char op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12}; + +#define opl 0 + +void opl_update( OPLSAMPLE *buf, int samples ) +{ + YM3812UpdateOne(opl, buf, samples); +} + +void opl_init( void ) +{ + YM3812Init(1, 3579545, 11025 * OUTPUT_QUALITY); +} + +void opl_deinit( void ) +{ + YM3812Shutdown(); +} + +void opl_reset( void ) +{ + YM3812ResetChip(opl); +} + +void opl_write(int reg, int val) +{ + YM3812Write(opl, 0, reg); + YM3812Write(opl, 1, val); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/fm_synth.h b/alienblaster/project/jni/application/opentyrian/src/fm_synth.h new file mode 100644 index 000000000..835faee55 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/fm_synth.h @@ -0,0 +1,35 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef FM_SYNTH_H +#define FM_SYNTH_H + +#include "fmopl.h" +#include "opentyr.h" + +extern const unsigned char op_table[9]; /* the 9 operators as expected by the OPL2 */ + +void opl_update( OPLSAMPLE *buf, int samples ); +void opl_init( void ); +void opl_deinit( void ); +void opl_reset( void ); +void opl_write( int, int ); + +#endif /* FM_SYNTH_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/fmopl.cpp b/alienblaster/project/jni/application/opentyrian/src/fmopl.cpp new file mode 100644 index 000000000..6568973c4 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/fmopl.cpp @@ -0,0 +1,2400 @@ +/* +** +** File: fmopl.c - software implementation of FM sound generator +** types OPL and OPL2 +** +** Copyright (C) 2002,2003 Jarek Burczynski (bujar at mame dot net) +** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 0.70 +** + +Revision History: + +14-06-2003 Jarek Burczynski: + - implemented all of the status register flags in Y8950 emulation + - renamed Y8950SetDeltaTMemory() parameters from _rom_ to _mem_ since + they can be either RAM or ROM + +08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) + - corrected YM3526Read() to always set bit 2 and bit 1 + to HIGH state - identical to YM3812Read (verified on real YM3526) + +04-28-2002 Jarek Burczynski: + - binary exact Envelope Generator (verified on real YM3812); + compared to YM2151: the EG clock is equal to internal_clock, + rates are 2 times slower and volume resolution is one bit less + - modified interface functions (they no longer return pointer - + that's internal to the emulator now): + - new wrapper functions for OPLCreate: YM3526Init(), YM3812Init() and Y8950Init() + - corrected 'off by one' error in feedback calculations (when feedback is off) + - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) + - speeded up noise generator calculations (Nicola Salmoria) + +03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) + Complete rewrite (all verified on real YM3812): + - corrected sin_tab and tl_tab data + - corrected operator output calculations + - corrected waveform_select_enable register; + simply: ignore all writes to waveform_select register when + waveform_select_enable == 0 and do not change the waveform previously selected. + - corrected KSR handling + - corrected Envelope Generator: attack shape, Sustain mode and + Percussive/Non-percussive modes handling + - Envelope Generator rates are two times slower now + - LFO amplitude (tremolo) and phase modulation (vibrato) + - rhythm sounds phase generation + - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) + - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) + - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) + +12-28-2001 Acho A. Tang + - reflected Delta-T EOS status on Y8950 status port. + - fixed subscription range of attack/decay tables + + + To do: + add delay before key off in CSM mode (see CSMKeyControll) + verify volume of the FM part on the Y8950 +*/ + +#include +#include +#include +#include + +#include "fmopl.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + + + +/* output final shift */ +#if (OPL_SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} + + +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = acc_calc(lt); \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = rt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +/* #define LOG_CYM_FILE */ +#ifdef LOG_CYM_FILE + FILE * cymfile = NULL; +#endif + + + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* key scale level */ +/* table is 3dB/octave , DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define SC(x) ((UINT32)((x)/(0.1875/2.0))) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + /* OCT 1 */ + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + SC(0.000), SC(0.750), SC(1.125), SC(1.500), + SC(1.875), SC(2.250), SC(2.625), SC(3.000), + /* OCT 2 */ + SC(0.000), SC(0.000), SC(0.000), SC(0.000), + SC(0.000), SC(1.125), SC(1.875), SC(2.625), + SC(3.000), SC(3.750), SC(4.125), SC(4.500), + SC(4.875), SC(5.250), SC(5.625), SC(6.000), + /* OCT 3 */ + SC(0.000), SC(0.000), SC(0.000), SC(1.875), + SC(3.000), SC(4.125), SC(4.875), SC(5.625), + SC(6.000), SC(6.750), SC(7.125), SC(7.500), + SC(7.875), SC(8.250), SC(8.625), SC(9.000), + /* OCT 4 */ + SC(0.000), SC(0.000), SC(3.000), SC(4.875), + SC(6.000), SC(7.125), SC(7.875), SC(8.625), + SC(9.000), SC(9.750),SC(10.125),SC(10.500), + SC(10.875),SC(11.250),SC(11.625),SC(12.000), + /* OCT 5 */ + SC(0.000), SC(3.000), SC(6.000), SC(7.875), + SC(9.000),SC(10.125),SC(10.875),SC(11.625), + SC(12.000),SC(12.750),SC(13.125),SC(13.500), + SC(13.875),SC(14.250),SC(14.625),SC(15.000), + /* OCT 6 */ + SC(0.000), SC(6.000), SC(9.000),SC(10.875), + SC(12.000),SC(13.125),SC(13.875),SC(14.625), + SC(15.000),SC(15.750),SC(16.125),SC(16.500), + SC(16.875),SC(17.250),SC(17.625),SC(18.000), + /* OCT 7 */ + SC(0.000), SC(9.000),SC(12.000),SC(13.875), + SC(15.000),SC(16.125),SC(16.875),SC(17.625), + SC(18.000),SC(18.750),SC(19.125),SC(19.500), + SC(19.875),SC(20.250),SC(20.625),SC(21.000) +}; +#undef SC + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ +/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define SC(x) ((UINT32)((x)*2)) +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + SC(0.50), SC(1.00), SC(2.00), SC(3.00), SC(4.00), SC(5.00), SC(6.00), SC(7.00), + SC(8.00), SC(9.00),SC(10.00),SC(10.00),SC(12.00),SC(12.00),SC(15.00),SC(15.00) +}; +#undef SC + +/* TL_TAB_LEN is calculated as: +* 12 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (12*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>4) + +/* sin waveform table in 'decibel' scale */ +/* four waveforms on OPL2 type chips */ +static unsigned int sin_tab[SIN_LEN * 4]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (loosing precision is important) +*/ + +#define LFO_AM_TAB_ELEMENTS 210u + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM3812) */ +static const INT8 lfo_pm_table[8*8*2] = { + +/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +}; + + +/* lock level of common table */ +static int num_lock = 0; + + +static void *cur_chip = NULL; /* current chip pointer */ +static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; + +static signed int phase_modulation; /* phase modulation input (SLOT 2) */ +static signed int output[1]; + +#if BUILD_Y8950 +static INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ +#endif + +static UINT32 LFO_AM; +static INT32 LFO_PM; + + + +inline int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* status set and IRQ handling */ +inline void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + + +/* advance LFO to next sample */ +inline void advance_lfo(FM_OPL *OPL) +{ + UINT8 tmp; + + /* LFO */ + OPL->lfo_am_cnt += OPL->lfo_am_inc; + if (OPL->lfo_am_cnt >= (LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (OPL->lfo_am_depth) + LFO_AM = tmp; + else + LFO_AM = tmp>>2; + + OPL->lfo_pm_cnt += OPL->lfo_pm_inc; + LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; +} + +/* advance to next sample */ +inline void advance(FM_OPL *OPL) +{ + OPL_CH *CH; + OPL_SLOT *op; + int i; + + OPL->eg_timer += OPL->eg_timer_add; + + while (OPL->eg_timer >= OPL->eg_timer_overflow) + { + OPL->eg_timer -= OPL->eg_timer_overflow; + + OPL->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= (signed)op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } + } + } + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + OPL->noise_p += OPL->noise_f; + i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + OPL->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; + OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; + OPL->noise_rng >>= 1; + + i--; + } +} + + +inline signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +inline signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) + +/* calculate output */ +inline void OPL_CALC_CH( OPL_CH *CH ) +{ + OPL_SLOT *SLOT; + unsigned int env; + signed int out; + + phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + *SLOT->connect1 += SLOT->op1_out[0]; + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +inline void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) +{ + OPL_SLOT *SLOT; + signed int out; + unsigned int env; + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + phase_modulation = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + phase_modulation = SLOT->op1_out[0]; + /* else ignore output of operator 1 */ + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ + /* SD (16) channel 7->slot 1 */ + /* TOM (14) channel 8->slot 1 */ + /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ + + /* Envelope generation based on: */ + /* HH channel 7->slot1 */ + /* SD channel 7->slot2 */ + /* TOM channel 8->slot1 */ + /* TOP channel 8->slot2 */ + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(SLOT7_1); + if( env < ENV_QUIET ) + { + + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + output[0] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + output[0] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET ) + output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM3812) */ + env = volume_calc(SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + output[0] += op_calc(phase<wavetable) * 2; + } + +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 1; /* 12 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<12; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<12; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror("\n"); + #endif + } + /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + } + + for (i=0; i>1) ]; + + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ + /* abs(output only first quarter of the sinus waveform) */ + + if (i & (1<<(SIN_BITS-2)) ) + sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; + + /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); + logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); + logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ + } + /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ + + +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","wb"); +#endif + + return 1; +} + +static void OPLCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif +} + + + +static void OPL_initalize(FM_OPL *OPL) +{ + int i; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; +#if 0 + OPL->rate = (double)OPL->clock / 72.0; + OPL->freqbase = 1.0; +#endif + + /*logerror("freqbase=%f\n", OPL->freqbase);*/ + + /* Timer base time */ + OPL->TimerBase = 1.0 / ((double)OPL->clock / 72.0 ); + + /* make fnumber -> increment counter table */ + for( i=0 ; i < 1024 ; i++ ) + { + /* opn phase increment counter = 20bit */ + OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", + i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("FMOPL.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + OPL->lfo_am_inc = (UINT32)((1.0 / 64.0 ) * (1<freqbase); + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + OPL->lfo_pm_inc = (UINT32)((1.0 / 1024.0) * (1<freqbase); + + /*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + OPL->noise_f = (UINT32)((1.0 / 1.0) * (1<freqbase); + + OPL->eg_timer_add = (UINT32)((1<freqbase); + OPL->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ + +} + +inline void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* restart Phase Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ + SLOT->state = EG_ATT; + } + SLOT->key |= key_set; +} + +inline void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + } +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +inline void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +inline void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set attack rate & decay rate */ +inline void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +inline void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + + +/* write a value v to register r on OPL chip */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + unsigned int block_fnum; + double interval; + + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + +#ifdef LOG_CYM_FILE + if ((cymfile) && (r!=0) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + } +#endif + + + switch(r&0xe0) + { + case 0x00: /* 00-1f:control */ + switch(r&0x1f) + { + case 0x01: /* waveform select enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + /* do not change the waveform previously selected */ + } + break; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f); + } + else + { /* set IRQ mask ,timer enable*/ + OPL->st[0] = v&1; + OPL->st[1] = (v>>1)&1; + + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL, v & 0x78 ); + OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); + + /* timer 1 */ + if(OPL->st[0]) + { + OPL->TC[0]=OPL->T[0]*20; + interval = (double)OPL->T[0]*OPL->TimerBase; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); + } + /* timer 2 */ + if(OPL->st[1]) + { + OPL->TC[1]=OPL->T[1]*20; + interval =(double)OPL->T[1]*OPL->TimerBase; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); + } + } + break; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + else + logerror("Y8950: write unmapped KEYBOARD port\n"); + } + break; + case 0x07: /* DELTA-T control 1 : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; +#endif + case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */ +#endif + break; + +#if BUILD_Y8950 + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data write */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* ADPCM volume */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; + + case 0x15: /* DAC data high 8 bits (F7,F6...F2) */ + case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */ + case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */ + logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v); + break; + + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + break; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + break; +#endif + default: + printf("%s: write to unknown register: %02x\n", __FILE__, r); + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(OPL,slot,v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(OPL,slot,v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(OPL,slot,v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(OPL,slot,v); + break; + case 0xa0: + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + { + OPL->lfo_am_depth = v & 0x80; + OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; + + OPL->rhythm = v&0x3f; + + if(OPL->rhythm&0x20) + { + /* BD key on/off */ + if(v&0x10) + { + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); + } + else + { + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + else + { + /* BD key off */ + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + CH->block_fnum = block_fnum; + + CH->ksl_base = ksl_tab[block_fnum>>6]; + CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ + CH->kcode = (CH->block_fnum&0x1c00)>>9; + + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ + /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ + /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ + if (OPL->mode&0x40) + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + else + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output[0] : &phase_modulation; + break; + case 0xe0: /* waveform select */ + /* simply ignore write to the waveform select register if selecting not enabled in test register */ + if(OPL->wavesel) + { + slot = slot_array[r&0x1f]; + if(slot < 0) return; + CH = &OPL->P_CH[slot/2]; + + CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; + } + break; + } +} + +#ifdef LOG_CYM_FILE +static void cymfile_callback (int n) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +} +#endif + +/* lock/unlock for common table */ +static int OPL_LockTable(void) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + cur_chip = NULL; + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + +#ifdef LOG_CYM_FILE + cymfile = fopen("3812_.cym","wb"); + if (cymfile) + timer_pulse ( TIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/ + else + logerror("Could not create file 3812_.cym\n"); +#endif + + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + cur_chip = NULL; + OPLCloseTable(); + +#ifdef LOG_CYM_FILE + fclose (cymfile); + cymfile = NULL; +#endif + +} + +static void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + OPL->eg_timer = 0; + OPL->eg_cnt = 0; + + OPL->noise_rng = 1; /* noise shift register */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wavesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = &output_deltat[0]; + DELTAT->portshift = 5; + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,0); + } +#endif +} + +/* Create one of virtual YM3812/YM3526/Y8950 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static FM_OPL *OPLCreate(int type, int clock, int rate) +{ + char *ptr; + FM_OPL *OPL; + int state_size; + + if (OPL_LockTable() ==-1) return NULL; + + /* calculate OPL state size */ + state_size = sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + ptr = (char *)malloc(state_size); + + if (ptr==NULL) + return NULL; + + /* clear */ + memset(ptr,0,state_size); + + OPL = (FM_OPL *)ptr; + + ptr += sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) + { + OPL->deltat = (YM_DELTAT *)ptr; + } + ptr += sizeof(YM_DELTAT); +#endif + + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + + /* init global tables */ + OPL_initalize(OPL); + + return OPL; +} + +/* Destroy one of virtual YM3812 */ +static void OPLDestroy(FM_OPL *OPL) +{ + OPL_UnLockTable(); + free(OPL); +} + +/* Optional handlers */ + +static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) +{ + OPL->TimerHandler = TimerHandler; + OPL->TimerParam = channelOffset; +} +static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} + +static int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +static unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { + /* status port */ + + #if BUILD_Y8950 + + if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ + { + return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); + } + + #endif + if (OPL->st[0]) { + if (OPL->TC[0]) OPL->TC[0]--; + else { + OPL->TC[0]=OPL->T[0]*20; + OPL_STATUS_SET(OPL,0x40); + } + } + if (OPL->st[1]) { + if (OPL->TC[1]) OPL->TC[1]--; + else { + OPL->TC[1]=OPL->T[1]*20; + OPL_STATUS_SET(OPL,0x40); + } + } + return OPL->status & (OPL->statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + logerror("Y8950: read unmapped KEYBOARD port\n"); + } + return 0; + + case 0x0f: /* ADPCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + UINT8 val; + + val = YM_DELTAT_ADPCM_Read(OPL->deltat); + /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ + return val; + } + return 0; + + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + logerror("Y8950:read unmapped I/O port\n"); + } + return 0; + case 0x1a: /* PCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + logerror("Y8950 A/D convertion is accessed but not implemented !\n"); + return 0x80; /* 2's complement PCM data - result from A/D convertion */ + } + return 0; + } +#endif + + return 0xff; +} + +/* CSM Key Controll */ +inline void CSMKeyControll(OPL_CH *CH) +{ + FM_KEYON (&CH->SLOT[SLOT1], 4); + FM_KEYON (&CH->SLOT[SLOT2], 4); + + /* The key off should happen exactly one sample later - not implemented correctly yet */ + + FM_KEYOFF(&CH->SLOT[SLOT1], ~4); + FM_KEYOFF(&CH->SLOT[SLOT2], ~4); +} + + +static int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0; ch<9; ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ +/* if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); */ + return OPL->status>>7; +} + + +#define MAX_OPL_CHIPS 1 + + +#if (BUILD_YM3812) + +static FM_OPL *OPL_YM3812[MAX_OPL_CHIPS]; /* array of pointers to the YM3812's */ +static int YM3812NumChips = 0; /* number of chips */ + +int YM3812Init(int num, int clock, int rate) +{ + int i; + + if (YM3812NumChips) + return -1; /* duplicate init. */ + + YM3812NumChips = num; + + for (i = 0;i < YM3812NumChips; i++) + { + /* emulator create */ + OPL_YM3812[i] = OPLCreate(OPL_TYPE_YM3812,clock,rate); + if(OPL_YM3812[i] == NULL) + { + /* it's really bad - we run out of memeory */ + YM3812NumChips = 0; + return -1; + } + /* reset */ + YM3812ResetChip(i); + } + + return 0; +} + +void YM3812Shutdown(void) +{ + int i; + + for (i = 0;i < YM3812NumChips; i++) + { + /* emulator shutdown */ + OPLDestroy(OPL_YM3812[i]); + OPL_YM3812[i] = NULL; + } + YM3812NumChips = 0; +} +void YM3812ResetChip(int which) +{ + OPLResetChip(OPL_YM3812[which]); +} + +int YM3812Write(int which, int a, int v) +{ + return OPLWrite(OPL_YM3812[which], a, v); +} + +unsigned char YM3812Read(int which, int a) +{ + /* YM3812 always returns bit2 and bit1 in HIGH state */ + return OPLRead(OPL_YM3812[which], a) | 0x06 ; +} +int YM3812TimerOver(int which, int c) +{ + return OPLTimerOver(OPL_YM3812[which], c); +} + +void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) +{ + OPLSetTimerHandler(OPL_YM3812[which], TimerHandler, channelOffset); +} +void YM3812SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) +{ + OPLSetIRQHandler(OPL_YM3812[which], IRQHandler, param); +} +void YM3812SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPLSetUpdateHandler(OPL_YM3812[which], UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3812's +** +** 'which' is the virtual YM3812 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void YM3812UpdateOne(int which, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = OPL_YM3812[which]; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3812 */ + + + +#if (BUILD_YM3526) + +static FM_OPL *OPL_YM3526[MAX_OPL_CHIPS]; /* array of pointers to the YM3526's */ +static int YM3526NumChips = 0; /* number of chips */ + +int YM3526Init(int num, int clock, int rate) +{ + int i; + + if (YM3526NumChips) + return -1; /* duplicate init. */ + + YM3526NumChips = num; + + for (i = 0;i < YM3526NumChips; i++) + { + /* emulator create */ + OPL_YM3526[i] = OPLCreate(OPL_TYPE_YM3526,clock,rate); + if(OPL_YM3526[i] == NULL) + { + /* it's really bad - we run out of memeory */ + YM3526NumChips = 0; + return -1; + } + /* reset */ + YM3526ResetChip(i); + } + + return 0; +} + +void YM3526Shutdown(void) +{ + int i; + + for (i = 0;i < YM3526NumChips; i++) + { + /* emulator shutdown */ + OPLDestroy(OPL_YM3526[i]); + OPL_YM3526[i] = NULL; + } + YM3526NumChips = 0; +} +void YM3526ResetChip(int which) +{ + OPLResetChip(OPL_YM3526[which]); +} + +int YM3526Write(int which, int a, int v) +{ + return OPLWrite(OPL_YM3526[which], a, v); +} + +unsigned char YM3526Read(int which, int a) +{ + /* YM3526 always returns bit2 and bit1 in HIGH state */ + return OPLRead(OPL_YM3526[which], a) | 0x06 ; +} +int YM3526TimerOver(int which, int c) +{ + return OPLTimerOver(OPL_YM3526[which], c); +} + +void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) +{ + OPLSetTimerHandler(OPL_YM3526[which], TimerHandler, channelOffset); +} +void YM3526SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) +{ + OPLSetIRQHandler(OPL_YM3526[which], IRQHandler, param); +} +void YM3526SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPLSetUpdateHandler(OPL_YM3526[which], UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void YM3526UpdateOne(int which, INT16 *buffer, int length) +{ + FM_OPL *OPL = OPL_YM3526[which]; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3526 */ + + + + +#if BUILD_Y8950 + +static FM_OPL *OPL_Y8950[MAX_OPL_CHIPS]; /* array of pointers to the Y8950's */ +static int Y8950NumChips = 0; /* number of chips */ + +static void Y8950_deltat_status_set(UINT8 which, UINT8 changebits) +{ + OPL_STATUS_SET(OPL_Y8950[which], changebits); +} +static void Y8950_deltat_status_reset(UINT8 which, UINT8 changebits) +{ + OPL_STATUS_RESET(OPL_Y8950[which], changebits); +} + +int Y8950Init(int num, int clock, int rate) +{ + int i; + + if (Y8950NumChips) + return -1; /* duplicate init. */ + + Y8950NumChips = num; + + for (i = 0;i < Y8950NumChips; i++) + { + /* emulator create */ + OPL_Y8950[i] = OPLCreate(OPL_TYPE_Y8950,clock,rate); + if(OPL_Y8950[i] == NULL) + { + /* it's really bad - we run out of memeory */ + Y8950NumChips = 0; + return -1; + } + OPL_Y8950[i]->deltat->status_set_handler = Y8950_deltat_status_set; + OPL_Y8950[i]->deltat->status_reset_handler = Y8950_deltat_status_reset; + OPL_Y8950[i]->deltat->status_change_which_chip = i; + OPL_Y8950[i]->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */ + OPL_Y8950[i]->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */ + /* reset */ + Y8950ResetChip(i); + } + + return 0; +} + +void Y8950Shutdown(void) +{ + int i; + + for (i = 0;i < Y8950NumChips; i++) + { + /* emulator shutdown */ + OPLDestroy(OPL_Y8950[i]); + OPL_Y8950[i] = NULL; + } + Y8950NumChips = 0; +} +void Y8950ResetChip(int which) +{ + OPLResetChip(OPL_Y8950[which]); +} + +int Y8950Write(int which, int a, int v) +{ + return OPLWrite(OPL_Y8950[which], a, v); +} + +unsigned char Y8950Read(int which, int a) +{ + return OPLRead(OPL_Y8950[which], a); +} +int Y8950TimerOver(int which, int c) +{ + return OPLTimerOver(OPL_Y8950[which], c); +} + +void Y8950SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) +{ + OPLSetTimerHandler(OPL_Y8950[which], TimerHandler, channelOffset); +} +void Y8950SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) +{ + OPLSetIRQHandler(OPL_Y8950[which], IRQHandler, param); +} +void Y8950SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPLSetUpdateHandler(OPL_Y8950[which], UpdateHandler, param); +} + +void Y8950SetDeltaTMemory(int which, void * deltat_mem_ptr, int deltat_mem_size ) +{ + FM_OPL *OPL = OPL_Y8950[which]; + OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr); + OPL->deltat->memory_size = deltat_mem_size; +} + +/* +** Generate samples for one of the Y8950's +** +** 'which' is the virtual Y8950 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void Y8950UpdateOne(int which, INT16 *buffer, int length) +{ + int i; + FM_OPL *OPL = OPL_Y8950[which]; + UINT8 rhythm = OPL->rhythm&0x20; + YM_DELTAT *DELTAT = OPL->deltat; + OPLSAMPLE *buf = buffer; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + output_deltat[0] = 0; + + advance_lfo(OPL); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0] + (output_deltat[0]>>11); + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} + +void Y8950SetPortHandler(int which,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) +{ + FM_OPL *OPL = OPL_Y8950[which]; + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void Y8950SetKeyboardHandler(int which,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) +{ + FM_OPL *OPL = OPL_Y8950[which]; + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} + +#endif + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/fmopl.h b/alienblaster/project/jni/application/opentyrian/src/fmopl.h new file mode 100644 index 000000000..9787e4a46 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/fmopl.h @@ -0,0 +1,253 @@ +#ifndef __FMOPL_H_ +#define __FMOPL_H_ + +/* --- select emulation chips --- */ +#define BUILD_YM3812 1 /* (HAS_YM3812) */ +#define BUILD_YM3526 (HAS_YM3526) +#define BUILD_Y8950 (HAS_Y8950) + +/* select output bits size of output : 8 or 16 */ +#define OPL_SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef OSD_CPU_H +#define OSD_CPU_H +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +#if (OPL_SAMPLE_BITS==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_SAMPLE_BITS==8) +typedef INT8 OPLSAMPLE; +#endif + + +typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); +typedef void (*OPL_IRQHANDLER)(int param,int irq); +typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(int param); + + + +typedef struct{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect1; /* slot1 output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + unsigned int wavetable; +} OPL_SLOT; + +typedef struct{ + OPL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + /* FM channel slots */ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 wavesel; /* waveform select enable flag */ + + int T[2]; /* timer counters */ + int TC[2]; + UINT8 st[2]; /* timer enable */ + +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + + YM_DELTAT *deltat; + + /* Keyboard and I/O ports interface */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + int port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + int keyboard_param; +#endif + + /* external event callback handlers */ + OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ + int TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + int IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ + int UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time (==sampling time)*/ +} FM_OPL; + + + +#if BUILD_YM3812 + +int YM3812Init(int num, int clock, int rate); +void YM3812Shutdown(void); +void YM3812ResetChip(int which); +int YM3812Write(int which, int a, int v); +unsigned char YM3812Read(int which, int a); +int YM3812TimerOver(int which, int c); +void YM3812UpdateOne(int which, OPLSAMPLE *buffer, int length); + +void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); +void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); +void YM3812SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param); + +#endif + + +#if BUILD_YM3526 + +/* +** Initialize YM3526 emulator(s). +** +** 'num' is the number of virtual YM3526's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +int YM3526Init(int num, int clock, int rate); +/* shutdown the YM3526 emulators*/ +void YM3526Shutdown(void); +void YM3526ResetChip(int which); +int YM3526Write(int which, int a, int v); +unsigned char YM3526Read(int which, int a); +int YM3526TimerOver(int which, int c); +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void YM3526UpdateOne(int which, INT16 *buffer, int length); + +void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); +void YM3526SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); +void YM3526SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param); + +#endif + + +#if BUILD_Y8950 + +#include "ymdeltat.h" + +/* Y8950 port handlers */ +void Y8950SetPortHandler(int which, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, int param); +void Y8950SetKeyboardHandler(int which, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, int param); +void Y8950SetDeltaTMemory(int which, void * deltat_mem_ptr, int deltat_mem_size ); + +int Y8950Init (int num, int clock, int rate); +void Y8950Shutdown (void); +void Y8950ResetChip (int which); +int Y8950Write (int which, int a, int v); +unsigned char Y8950Read (int which, int a); +int Y8950TimerOver (int which, int c); +void Y8950UpdateOne (int which, INT16 *buffer, int length); + +void Y8950SetTimerHandler (int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); +void Y8950SetIRQHandler (int which, OPL_IRQHANDLER IRQHandler, int param); +void Y8950SetUpdateHandler (int which, OPL_UPDATEHANDLER UpdateHandler, int param); + +#endif + + +int limit( int val, int max, int min ); +void OPL_STATUS_SET(FM_OPL *OPL,int flag); +void OPL_STATUS_RESET(FM_OPL *OPL,int flag); +void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag); +void advance_lfo(FM_OPL *OPL); +void advance(FM_OPL *OPL); +signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab); +signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab); +void OPL_CALC_CH( OPL_CH *CH ); +void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ); +void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set); +void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr); +void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT); +void set_mul(FM_OPL *OPL,int slot,int v); +void set_ksl_tl(FM_OPL *OPL,int slot,int v); +void set_ar_dr(FM_OPL *OPL,int slot,int v); +void set_sl_rr(FM_OPL *OPL,int slot,int v); +void CSMKeyControll(OPL_CH *CH); + + +#endif + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/font.cpp b/alienblaster/project/jni/application/opentyrian/src/font.cpp new file mode 100644 index 000000000..afc9001e8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/font.cpp @@ -0,0 +1,171 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "font.h" +#include "fonthand.h" +#include "sprite.h" + +// like JE_dString() if (black == false && shadow_dist == 2 && hue == 15) +// like JE_textShade() with PART_SHADE if (black == true && shadow_dist == 1) +// like JE_outTextAndDarken() if (black == false && shadow_dist == 1) +// like JE_outTextAdjust() with shadow if (black == false && shadow_dist == 2) +void draw_font_hv_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist ) +{ + draw_font_dark(surface, x + shadow_dist, y + shadow_dist, text, font, alignment, black); + + draw_font_hv(surface, x, y, text, font, alignment, hue, value); +} + +// like JE_textShade() with FULL_SHADE if (black == true && shadow_dist == 1) +void draw_font_hv_full_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist ) +{ + draw_font_dark(surface, x, y - shadow_dist, text, font, alignment, black); + draw_font_dark(surface, x + shadow_dist, y, text, font, alignment, black); + draw_font_dark(surface, x, y + shadow_dist, text, font, alignment, black); + draw_font_dark(surface, x - shadow_dist, y, text, font, alignment, black); + + draw_font_hv(surface, x, y, text, font, alignment, hue, value); +} + +// like JE_outText() with (brightness >= 0) +// like JE_outTextAdjust() without shadow +void draw_font_hv( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value ) +{ + switch (alignment) + { + case left_aligned: + break; + case centered: + x -= JE_textWidth(text, font) / 2; + break; + case right_aligned: + x -= JE_textWidth(text, font); + break; + } + + bool highlight = false; + + for (; *text != '\0'; ++text) + { + int sprite_id = font_ascii[(unsigned char)*text]; + + switch (*text) + { + case ' ': + x += 6; + break; + + case '~': + highlight = !highlight; + if (highlight) + value += 4; + else + value -= 4; + break; + + default: + if (sprite_id != -1 && sprite_exists(font, sprite_id)) + { + blit_sprite_hv(surface, x, y, font, sprite_id, hue, value); + + x += sprite(font, sprite_id)->width + 1; + } + break; + } + } +} + +// like JE_outTextModify() +void draw_font_hv_blend( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value ) +{ + switch (alignment) + { + case left_aligned: + break; + case centered: + x -= JE_textWidth(text, font) / 2; + break; + case right_aligned: + x -= JE_textWidth(text, font); + break; + } + + for (; *text != '\0'; ++text) + { + int sprite_id = font_ascii[(unsigned char)*text]; + + switch (*text) + { + case ' ': + x += 6; + break; + + case '~': + break; + + default: + if (sprite_id != -1 && sprite_exists(font, sprite_id)) + { + blit_sprite_hv_blend(surface, x, y, font, sprite_id, hue, value); + + x += sprite(font, sprite_id)->width + 1; + } + break; + } + } +} + +// like JE_outText() with (brightness < 0) if (black == true) +void draw_font_dark( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, bool black ) +{ + switch (alignment) + { + case left_aligned: + break; + case centered: + x -= JE_textWidth(text, font) / 2; + break; + case right_aligned: + x -= JE_textWidth(text, font); + break; + } + + for (; *text != '\0'; ++text) + { + int sprite_id = font_ascii[(unsigned char)*text]; + + switch (*text) + { + case ' ': + x += 6; + break; + + case '~': + break; + + default: + if (sprite_id != -1 && sprite_exists(font, sprite_id)) + { + blit_sprite_dark(surface, x, y, font, sprite_id, black); + + x += sprite(font, sprite_id)->width + 1; + } + break; + } + } +} diff --git a/alienblaster/project/jni/application/opentyrian/src/font.h b/alienblaster/project/jni/application/opentyrian/src/font.h new file mode 100644 index 000000000..e1db04e92 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/font.h @@ -0,0 +1,48 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef FONT_H +#define FONT_H + +#include "SDL.h" +#include + +typedef enum +{ + large_font = 0, + normal_font = 1, + small_font = 2 +} +Font; + +typedef enum +{ + left_aligned, + centered, + right_aligned +} +FontAlignment; + +void draw_font_hv_shadow( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value, bool black, int shadow_dist ); +void draw_font_hv_full_shadow( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value, bool black, int shadow_dist ); + +void draw_font_hv( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value ); +void draw_font_hv_blend( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value ); +void draw_font_dark( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, bool black ); + +#endif // FONT_H diff --git a/alienblaster/project/jni/application/opentyrian/src/fonthand.cpp b/alienblaster/project/jni/application/opentyrian/src/fonthand.cpp new file mode 100644 index 000000000..a3e1e6a27 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/fonthand.cpp @@ -0,0 +1,333 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "fonthand.h" +#include "network.h" +#include "nortsong.h" +#include "nortvars.h" +#include "opentyr.h" +#include "params.h" +#include "sprite.h" +#include "vga256d.h" +#include "video.h" + +const int font_ascii[256] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 26, 33, 60, 61, 62, -1, 32, 64, 65, 63, 84, 29, 83, 28, 80, // !"#$%&'()*+,-./ + 79, 70, 71, 72, 73, 74, 75, 76, 77, 78, 31, 30, -1, 85, -1, 27, // 0123456789:;<=>? + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // @ABCDEFGHIJKLMNO + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 68, 82, 69, -1, -1, // PQRSTUVWXYZ[\]^_ + -1, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // `abcdefghijklmno + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 66, 81, 67, -1, -1, // pqrstuvwxyz{|}~⌂ + + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, // ÇüéâäàåçêëèïîìÄÅ + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, // ÉæÆôöòûùÿÖÜ¢£¥₧ƒ + 118, 119, 120, 121, 122, 123, 124, 125, 126, -1, -1, -1, -1, -1, -1, -1, // áíóúñѪº¿ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +/* shape constants included in newshape.h */ + +JE_integer defaultBrightness = -3; +JE_byte textGlowFont, textGlowBrightness = 6; + +JE_boolean levelWarningDisplay; +JE_byte levelWarningLines; +char levelWarningText[10][61]; /* [1..10] of string [60] */ +JE_boolean warningRed; + +JE_byte warningSoundDelay; +JE_word armorShipDelay; +JE_byte warningCol; +JE_shortint warningColChange; + +void JE_dString( SDL_Surface * screen, int x, int y, const char *s, unsigned int font ) +{ + int bright = 0; + + for (int i = 0; s[i] != '\0'; ++i) + { + int sprite_id = font_ascii[(unsigned char)s[i]]; + + switch (s[i]) + { + case ' ': + x += 6; + break; + + case '~': + bright = (bright == 0) ? 2 : 0; + break; + + default: + if (sprite_id != -1) + { + blit_sprite_dark(screen, x + 2, y + 2, font, sprite_id, false); + blit_sprite_hv_unsafe(screen, x, y, font, sprite_id, 0xf, defaultBrightness + bright); + + x += sprite(font, sprite_id)->width + 1; + } + break; + } + } +} + +int JE_fontCenter( const char *s, unsigned int font ) +{ + return 160 - (JE_textWidth(s, font) / 2); +} + +int JE_textWidth( const char *s, unsigned int font ) +{ + int x = 0; + + for (int i = 0; s[i] != '\0'; ++i) + { + int sprite_id = font_ascii[(unsigned char)s[i]]; + + if (s[i] == ' ') + x += 6; + else if (sprite_id != -1) + x += sprite(font, sprite_id)->width + 1; + } + + return x; +} + +void JE_textShade( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness, unsigned int shadetype ) +{ + switch (shadetype) + { + case PART_SHADE: + JE_outText(screen, x+1, y+1, s, 0, -1); + JE_outText(screen, x, y, s, colorbank, brightness); + break; + case FULL_SHADE: + JE_outText(screen, x-1, y, s, 0, -1); + JE_outText(screen, x+1, y, s, 0, -1); + JE_outText(screen, x, y-1, s, 0, -1); + JE_outText(screen, x, y+1, s, 0, -1); + JE_outText(screen, x, y, s, colorbank, brightness); + break; + case DARKEN: + JE_outTextAndDarken(screen, x+1, y+1, s, colorbank, brightness, TINY_FONT); + break; + case TRICK: + JE_outTextModify(screen, x, y, s, colorbank, brightness, TINY_FONT); + break; + } +} + +void JE_outText( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness ) +{ + int bright = 0; + + for (int i = 0; s[i] != '\0'; ++i) + { + int sprite_id = font_ascii[(unsigned char)s[i]]; + + switch (s[i]) + { + case ' ': + x += 6; + break; + + case '~': + bright = (bright == 0) ? 4 : 0; + break; + + default: + if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id)) + { + if (brightness >= 0) + blit_sprite_hv_unsafe(screen, x, y, TINY_FONT, sprite_id, colorbank, brightness + bright); + else + blit_sprite_dark(screen, x, y, TINY_FONT, sprite_id, true); + + x += sprite(TINY_FONT, sprite_id)->width + 1; + } + break; + } + } +} + +void JE_outTextModify( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, unsigned int brightness, unsigned int font ) +{ + for (int i = 0; s[i] != '\0'; ++i) + { + int sprite_id = font_ascii[(unsigned char)s[i]]; + + if (s[i] == ' ') + { + x += 6; + } + else if (sprite_id != -1) + { + blit_sprite_hv_blend(screen, x, y, font, sprite_id, filter, brightness); + + x += sprite(font, sprite_id)->width + 1; + } + } +} + +void JE_outTextAdjust( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, int brightness, unsigned int font, JE_boolean shadow ) +{ + int bright = 0; + + for (int i = 0; s[i] != '\0'; ++i) + { + int sprite_id = font_ascii[(unsigned char)s[i]]; + + switch (s[i]) + { + case ' ': + x += 6; + break; + + case '~': + bright = (bright == 0) ? 4 : 0; + break; + + default: + if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id)) + { + if (shadow) + blit_sprite_dark(screen, x + 2, y + 2, font, sprite_id, false); + blit_sprite_hv(screen, x, y, font, sprite_id, filter, brightness + bright); + + x += sprite(font, sprite_id)->width + 1; + } + break; + } + } +} + +void JE_outTextAndDarken( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, unsigned int brightness, unsigned int font ) +{ + int bright = 0; + + for (int i = 0; s[i] != '\0'; ++i) + { + int sprite_id = font_ascii[(unsigned char)s[i]]; + + switch (s[i]) + { + case ' ': + x += 6; + break; + + case '~': + bright = (bright == 0) ? 4 : 0; + break; + + default: + if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id)) + { + blit_sprite_dark(screen, x + 1, y + 1, font, sprite_id, false); + blit_sprite_hv_unsafe(screen, x, y, font, sprite_id, colorbank, brightness + bright); + + x += sprite(font, sprite_id)->width + 1; + } + break; + } + } +} + +void JE_updateWarning( SDL_Surface * screen ) +{ + if (delaycount2() == 0) + { /*Update Color Bars*/ + + warningCol += warningColChange; + if (warningCol > 14 * 16 + 10 || warningCol < 14 * 16 + 4) + { + warningColChange = -warningColChange; + } + fill_rectangle_xy(screen, 0, 0, 319, 5, warningCol); + fill_rectangle_xy(screen, 0, 194, 319, 199, warningCol); + JE_showVGA(); + + setjasondelay2(6); + + if (warningSoundDelay > 0) + { + warningSoundDelay--; + } + else + { + warningSoundDelay = 14; + JE_playSampleNum(17); + } + } +} + +void JE_outTextGlow( SDL_Surface * screen, int x, int y, const char *s ) +{ + JE_integer z; + JE_byte c = 15; + + if (warningRed) + { + c = 7; + } + + JE_outTextAdjust(screen, x - 1, y, s, 0, -12, textGlowFont, false); + JE_outTextAdjust(screen, x, y - 1, s, 0, -12, textGlowFont, false); + JE_outTextAdjust(screen, x + 1, y, s, 0, -12, textGlowFont, false); + JE_outTextAdjust(screen, x, y + 1, s, 0, -12, textGlowFont, false); + if (frameCountMax > 0) + for (z = 1; z <= 12; z++) + { + setjasondelay(frameCountMax); + JE_outTextAdjust(screen, x, y, s, c, z - 10, textGlowFont, false); + if (JE_anyButton()) + { + frameCountMax = 0; + } + + NETWORK_KEEP_ALIVE(); + + JE_showVGA(); + + wait_delay(); + } + for (z = (frameCountMax == 0) ? 6 : 12; z >= textGlowBrightness; z--) + { + setjasondelay(frameCountMax); + JE_outTextAdjust(screen, x, y, s, c, z - 10, textGlowFont, false); + if (JE_anyButton()) + { + frameCountMax = 0; + } + + NETWORK_KEEP_ALIVE(); + + JE_showVGA(); + + wait_delay(); + } + textGlowBrightness = 6; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/fonthand.h b/alienblaster/project/jni/application/opentyrian/src/fonthand.h new file mode 100644 index 000000000..a858dfac8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/fonthand.h @@ -0,0 +1,60 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef FONTHAND_H +#define FONTHAND_H + +#include "opentyr.h" + +#include "SDL.h" + +#define PART_SHADE 0 +#define FULL_SHADE 1 +#define DARKEN 2 +#define TRICK 3 +#define NO_SHADE 255 + +extern const int font_ascii[256]; + +extern JE_integer defaultBrightness; +extern JE_byte textGlowFont, textGlowBrightness; +extern JE_boolean levelWarningDisplay; +extern JE_byte levelWarningLines; +extern char levelWarningText[10][61]; +extern JE_boolean warningRed; +extern JE_byte warningSoundDelay; +extern JE_word armorShipDelay; +extern JE_byte warningCol; +extern JE_shortint warningColChange; + +void JE_dString( SDL_Surface * screen, int x, int y, const char *s, unsigned int font ); + +int JE_fontCenter( const char *s, unsigned int font ); +int JE_textWidth( const char *s, unsigned int font ); +void JE_textShade( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness, unsigned int shadetype ); +void JE_outText( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness ); +void JE_outTextModify( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, unsigned int brightness, unsigned int font ); +void JE_outTextAdjust( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, int brightness, unsigned int font, bool shadow ); +void JE_outTextAndDarken( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, unsigned int brightness, unsigned int font ); + +void JE_updateWarning( SDL_Surface * screen ); +void JE_outTextGlow( SDL_Surface * screen, int x, int y, const char *s ); + +#endif /* FONTHAND_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/game_menu.cpp b/alienblaster/project/jni/application/opentyrian/src/game_menu.cpp new file mode 100644 index 000000000..456ee6ac4 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/game_menu.cpp @@ -0,0 +1,3346 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "file.h" +#include "fonthand.h" +#include "game_menu.h" +#include "joystick.h" +#include "keyboard.h" +#include "loudness.h" +#include "mainint.h" +#include "mouse.h" +#include "musmast.h" +#include "network.h" +#include "nortsong.h" +#include "nortvars.h" +#include "params.h" +#include "pcxmast.h" +#include "picload.h" +#include "player.h" +#include "sprite.h" +#include "tyrian2.h" +#include "varz.h" +#include "vga256d.h" +#include "video.h" + +#include + +/*** Structs ***/ +struct cube_struct +{ + char title[81]; + char header[13]; + int face_sprite; + char text[90][36]; + int last_line; +}; + +/*** Globals ***/ +static int joystick_config = 0; // which joystick is being configured in menu + +static JE_word yLoc; +static JE_shortint yChg; +static int newPal, curPal, oldPal; +static JE_boolean quikSave; +static JE_byte oldMenu; +static JE_boolean backFromHelp; +static JE_integer lastDirection; +static JE_boolean firstMenu9, paletteChanged; +static JE_MenuChoiceType menuChoices; +static JE_integer col, colC; +static JE_byte lastCurSel; +static JE_integer curMenu; +static JE_byte curSel[MAX_MENU]; /* [1..maxmenu] */ +static JE_byte curItemType, curItem, cursor; +static JE_boolean leftPower, rightPower, rightPowerAfford; +static JE_byte currentCube; +static JE_boolean keyboardUsed; + +static JE_byte planetAni, planetAniWait; +static JE_byte currentDotNum, currentDotWait; +static JE_real navX, navY, newNavX, newNavY; +static JE_integer tempNavX, tempNavY; +static JE_byte planetDots[5]; /* [1..5] */ +static JE_integer planetDotX[5][10], planetDotY[5][10]; /* [1..5, 1..10] */ +static PlayerItems old_items[2]; // TODO: should not be global if possible + +static struct cube_struct cube[4]; + +static const JE_MenuChoiceType menuChoicesDefault = { 7, 9, 8, 0, 0, 11, (SAVE_FILES_NUM / 2) + 2, 0, 0, 6, 4, 6, 7, 5 }; +static const JE_byte menuEsc[MAX_MENU] = { 0, 1, 1, 1, 2, 3, 3, 1, 8, 0, 0, 11, 3, 0 }; +static const JE_byte itemAvailMap[7] = { 1, 2, 3, 9, 4, 6, 7 }; +static const JE_word planetX[21] = { 200, 150, 240, 300, 270, 280, 320, 260, 220, 150, 160, 210, 80, 240, 220, 180, 310, 330, 150, 240, 200 }; +static const JE_word planetY[21] = { 40, 90, 90, 80, 170, 30, 50, 130, 120, 150, 220, 200, 80, 50, 160, 10, 55, 55, 90, 90, 40 }; +static const uint cube_line_chars = sizeof(*cube->text) - 1; +static const uint cube_line_width = 150; + + +/*** Functions ***/ +static uint *playeritem_map( PlayerItems *items, uint i ) +{ + uint * const map[] = { &items->ship, &items->weapon[FRONT_WEAPON].id, &items->weapon[REAR_WEAPON].id, &items->shield, &items->generator, &items->sidekick[LEFT_SIDEKICK], &items->sidekick[RIGHT_SIDEKICK] }; + assert(i < COUNTOF(map)); + return map[i]; +} + + +JE_longint JE_cashLeft( void ) +{ + JE_longint tempL = player[0].cash; + JE_word itemNum = *playeritem_map(&player[0].items, curSel[1] - 2); + + tempL -= JE_getCost(curSel[1], itemNum); + + tempW = 0; + + switch (curSel[1]) + { + case 3: + case 4: + for (uint i = 1; i < player[0].items.weapon[curSel[1]-3].power; ++i) + { + tempW += weaponPort[itemNum].cost * i; + tempL -= tempW; + } + break; + } + + return tempL; +} + +void JE_itemScreen( void ) +{ + bool quit = false; + + /* SYN: Okay, here's the menu numbers. All are reindexed by -1 from the original code. + 0: full game menu + 1: upgrade ship main + 2: full game options + 3: play next level + 4: upgrade ship submenus + 5: keyboard settings + 6: load/save menu + 7: data cube menu + 8: read data cube + 9: 2 player arcade game menu + 10: 1 player arcade game menu + 11: network game options + 12: joystick settings + 13: super tyrian + */ + + free_sprite2s(&shapes6); + JE_loadCompShapes(&shapes6, '1'); // item sprites + + load_cubes(); + + VGAScreen = VGAScreenSeg; + + memcpy(menuChoices, menuChoicesDefault, sizeof(menuChoices)); + + play_song(songBuy); + + JE_loadPic(VGAScreen, 1, false); + + curPal = 1; + newPal = 0; + + JE_showVGA(); + + set_palette(colors, 0, 255); + + col = 1; + gameLoaded = false; + curItemType = 1; + cursor = 1; + curItem = 0; + + for (int x = 0; x < MAX_MENU; x++) + { + curSel[x] = 2; + } + + curMenu = 0; + + int temp_weapon_power[7]; // assumes there'll never be more than 6 weapons to choose from, 7th is "Done" + + /* JE: (* Check for where Pitems and Select match up - if no match then add to the itemavail list *) */ + for (int i = 0; i < 7; i++) + { + int item = *playeritem_map(&player[0].last_items, i); + + int slot = 0; + + for ( ; slot < itemAvailMax[itemAvailMap[i]-1]; ++slot) + { + if (itemAvail[itemAvailMap[i]-1][slot] == item) + break; + } + + if (slot == itemAvailMax[itemAvailMap[i]-1]) + { + itemAvail[itemAvailMap[i]-1][slot] = item; + itemAvailMax[itemAvailMap[i]-1]++; + } + } + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + keyboardUsed = false; + firstMenu9 = false; + backFromHelp = false; + + /* JE: Sort items in merchant inventory */ + for (int x = 0; x < 9; x++) + { + if (itemAvailMax[x] > 1) + { + for (temp = 0; temp < itemAvailMax[x] - 1; temp++) + { + for (temp2 = temp; temp2 < itemAvailMax[x]; temp2++) + { + if (itemAvail[x][temp] == 0 || (itemAvail[x][temp] > itemAvail[x][temp2] && itemAvail[x][temp2] != 0)) + { + temp3 = itemAvail[x][temp]; + itemAvail[x][temp] = itemAvail[x][temp2]; + itemAvail[x][temp2] = temp3; + } + } + } + } + } + + do + { + quit = false; + + JE_getShipInfo(); + + /* JE: If curMenu==1 and twoPlayerMode is on, then force move to menu 10 */ + if (curMenu == 0) + { + if (twoPlayerMode) + curMenu = 9; + + if (isNetworkGame || onePlayerAction) + curMenu = 10; + + if (superTyrian) + curMenu = 13; + } + + paletteChanged = false; + + leftPower = false; + rightPower = false; + + /* SYN: note reindexing... "firstMenu9" refers to Menu 8 here :( */ + if (curMenu != 8 || firstMenu9) + { + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + } + + defaultBrightness = -3; + + if (curMenu == 1 && (curSel[curMenu] == 3 || curSel[curMenu] == 4)) + { + // reset temp_weapon_power[] every time we select upgrading front or back + const uint item = player[0].items.weapon[curSel[1] - 3].id, + item_power = player[0].items.weapon[curSel[1] - 3].power, + i = curSel[1] - 2; // 1 or 2 (front or rear) + + // set power level of owned weapon + for (int slot = 0; slot < itemAvailMax[itemAvailMap[i]-1]; ++slot) + { + if (itemAvail[itemAvailMap[i]-1][slot] == item) + temp_weapon_power[slot] = item_power; + else + temp_weapon_power[slot] = 1; + } + + // set power level for "Done" + temp_weapon_power[itemAvailMax[itemAvailMap[i]-1]] = item_power; + } + + /* play next level menu */ + if (curMenu == 3) + { + planetAni = 0; + keyboardUsed = false; + currentDotNum = 0; + currentDotWait = 8; + planetAniWait = 3; + JE_updateNavScreen(); + } + + /* Draw menu title for everything but upgrade ship submenus */ + if (curMenu != 4) + { + JE_drawMenuHeader(); + } + + /* Draw menu choices for simple menus */ + if ((curMenu >= 0 && curMenu <= 3) || (curMenu >= 9 && curMenu <= 11) || curMenu == 13) + { + JE_drawMenuChoices(); + } + + /* Data cube icons */ + if (curMenu == 0) + { + for (int i = 1; i <= cubeMax; i++) + { + blit_sprite_dark(VGAScreen, 190 + i * 18 + 2, 37 + 1, OPTION_SHAPES, 34, false); + blit_sprite(VGAScreen, 190 + i * 18, 37, OPTION_SHAPES, 34); // data cube + } + } + + /* load/save menu */ + if (curMenu == 6) + { + int min, max; + + if (twoPlayerMode) + { + min = 13; + max = 24; + } + else + { + min = 2; + max = 13; + } + + for (int x = min; x <= max; x++) + { + /* Highlight if current selection */ + temp2 = (x - min + 2 == curSel[curMenu]) ? 15 : 28; + + /* Write save game slot */ + if (x == max) + strcpy(tempStr, miscText[6-1]); + else if (saveFiles[x-2].level == 0) + strcpy(tempStr, miscText[3-1]); + else + strcpy(tempStr, saveFiles[x-2].name); + + int tempY = 38 + (x - min)*11; + + JE_textShade(VGAScreen, 163, tempY, tempStr, temp2 / 16, temp2 % 16 - 8, DARKEN); + + /* If selected with keyboard, move mouse pointer to match? Or something. */ + if (x - min + 2 == curSel[curMenu]) + { + if (keyboardUsed) + set_mouse_position(305, 38 + (x - min) * 11); + } + + if (x < max) /* x == max isn't a save slot */ + { + /* Highlight if current selection */ + temp2 = (x - min + 2 == curSel[curMenu]) ? 252 : 250; + + if (saveFiles[x-2].level == 0) + { + strcpy(tempStr, "-----"); /* Empty save slot */ + } + else + { + char buf[20]; + + strcpy(tempStr, saveFiles[x-2].levelName); + + snprintf(buf, sizeof buf, "%s%d", miscTextB[1-1], saveFiles[x-2].episode); + JE_textShade(VGAScreen, 297, tempY, buf, temp2 / 16, temp2 % 16 - 8, DARKEN); + } + + JE_textShade(VGAScreen, 245, tempY, tempStr, temp2 / 16, temp2 % 16 - 8, DARKEN); + } + + JE_drawMenuHeader(); + } + } + + /* keyboard settings menu */ + if (curMenu == 5) + { + for (int x = 2; x <= 11; x++) + { + if (x == curSel[curMenu]) + { + temp2 = 15; + if (keyboardUsed) + set_mouse_position(305, 38 + (x - 2) * 12); + } + else + { + temp2 = 28; + } + + JE_textShade(VGAScreen, 166, 38 + (x - 2)*12, menuInt[curMenu + 1][x-1], temp2 / 16, temp2 % 16 - 8, DARKEN); + + if (x < 10) /* 10 = reset to defaults, 11 = done */ + { + temp2 = (x == curSel[curMenu]) ? 252 : 250; + JE_textShade(VGAScreen, 236, 38 + (x - 2)*12, SDL_GetKeyName(keySettings[x-2]), temp2 / 16, temp2 % 16 - 8, DARKEN); + } + } + + menuChoices[5] = 11; + } + + /* Joystick settings menu */ + if (curMenu == 12) + { + const char *menu_item[] = + { + "JOYSTICK", + "ANALOG AXES", + " SENSITIVITY", + " THRESHOLD", + menuInt[6][1], + menuInt[6][4], + menuInt[6][2], + menuInt[6][3], + menuInt[6][5], + menuInt[6][6], + menuInt[6][7], + menuInt[6][8], + "MENU", + "PAUSE", + menuInt[6][9], + menuInt[6][10] + }; + + for (uint i = 0; i < COUNTOF(menu_item); i++) + { + int temp = (i == curSel[curMenu] - 2u) ? 15 : 28; + + JE_textShade(VGAScreen, 166, 38 + i * 8, menu_item[i], temp / 16, temp % 16 - 8, DARKEN); + + temp = (i == curSel[curMenu] - 2u) ? 252 : 250; + + char value[30] = ""; + if (joysticks == 0 && i < 14) // no joysticks, everything disabled + { + sprintf(value, "-"); + } + else if (i == 0) // joystick number + { + sprintf(value, "%d", joystick_config + 1); + } + else if (i == 1) // joystick is analog + { + sprintf(value, "%s", joystick[joystick_config].analog ? "TRUE" : "FALSE"); + } + else if (i < 4) // joystick analog settings + { + if (!joystick[joystick_config].analog) + temp -= 3; + sprintf(value, "%d", i == 2 ? joystick[joystick_config].sensitivity : joystick[joystick_config].threshold); + } + else if (i < 14) // assignments + { + joystick_assignments_to_string(value, sizeof(value), joystick[joystick_config].assignment[i - 4]); + } + + JE_textShade(VGAScreen, 236, 38 + i * 8, value, temp / 16, temp % 16 - 8, DARKEN); + } + + menuChoices[curMenu] = COUNTOF(menu_item) + 1; + } + + /* Upgrade weapon submenus, with weapon sim */ + if (curMenu == 4) + { + /* Move cursor until we hit either "Done" or a weapon the player can afford */ + while (curSel[4] < menuChoices[4] && JE_getCost(curSel[1], itemAvail[itemAvailMap[curSel[1]-2]-1][curSel[4]-2]) > player[0].cash) + { + curSel[4] += lastDirection; + if (curSel[4] < 2) + curSel[4] = menuChoices[4]; + else if (curSel[4] > menuChoices[4]) + curSel[4] = 2; + } + + if (curSel[4] == menuChoices[4]) + { + /* If cursor on "Done", use previous weapon */ + *playeritem_map(&player[0].items, curSel[1] - 2) = *playeritem_map(&old_items[0], curSel[1] - 2); + } + else + { + /* Otherwise display the selected weapon */ + *playeritem_map(&player[0].items, curSel[1] - 2) = itemAvail[itemAvailMap[curSel[1]-2]-1][curSel[4]-2]; + } + + /* Get power level info for front and rear weapons */ + if ((curSel[1] == 3 && curSel[4] < menuChoices[4]) || (curSel[1] == 4 && curSel[4] < menuChoices[4]-1)) + { + const uint port = curSel[1] - 3, // 0 or 1 (front or back) + item_level = player[0].items.weapon[port].power; + + // calculate upgradeCost + JE_getCost(curSel[1], itemAvail[itemAvailMap[curSel[1]-2]-1][curSel[5]-2]); + + leftPower = item_level > 1; // can downgrade + rightPower = item_level < 11; // can upgrade + + if (rightPower) + rightPowerAfford = JE_cashLeft() >= upgradeCost; // can afford upgrade + } + else + { + /* Nothing else can be upgraded / downgraded */ + leftPower = false; + rightPower = false; + } + + /* submenu title e.g., "Left Sidekick" */ + JE_dString(VGAScreen, 74 + JE_fontCenter(menuInt[2][curSel[1]-1], FONT_SHAPES), 10, menuInt[2][curSel[1]-1], FONT_SHAPES); + + /* Iterate through all submenu options */ + for (tempW = 1; tempW < menuChoices[curMenu]; tempW++) + { + int tempY = 40 + (tempW-1) * 26; /* Calculate y position */ + uint temp_cost; + + /* Is this a item or None/DONE? */ + if (tempW < menuChoices[4] - 1) + { + /* Get base cost for choice */ + temp_cost = JE_getCost(curSel[1], itemAvail[itemAvailMap[curSel[1]-2]-1][tempW-1]); + } + else + { + /* "None" is free :) */ + temp_cost = 0; + } + + temp4 = (temp_cost > player[0].cash) ? 4 : 0; // can player afford current weapon at all + + temp = itemAvail[itemAvailMap[curSel[1]-2]-1][tempW-1]; /* Item ID */ + switch (curSel[1]-1) + { + case 1: /* ship */ + if (temp > 90) + { + snprintf(tempStr, sizeof(tempStr), "Custom Ship %d", temp - 90); + } else { + strcpy(tempStr, ships[temp].name); + } + break; + case 2: /* front and rear weapon */ + case 3: + strcpy(tempStr, weaponPort[temp].name); + break; + case 4: /* shields */ + strcpy(tempStr, shields[temp].name); + break; + case 5: /* generator */ + strcpy(tempStr, powerSys[temp].name); + break; + case 6: /* sidekicks */ + case 7: + strcpy(tempStr, options[temp].name); + break; + } + if (tempW == curSel[curMenu]-1) + { + if (keyboardUsed) + { + set_mouse_position(305, tempY + 10); + } + temp2 = 15; + } else { + temp2 = 28; + } + + JE_getShipInfo(); + + /* item-owned marker */ + if (temp == *playeritem_map(&old_items[0], curSel[1] - 2) && temp != 0 && tempW != menuChoices[curMenu]-1) + { + fill_rectangle_xy(VGAScreen, 160, tempY+7, 300, tempY+11, 227); + blit_sprite2(VGAScreen, 298, tempY+2, shapes6, 247); + } + + /* Draw DONE */ + if (tempW == menuChoices[curMenu]-1) + { + strcpy(tempStr, miscText[13]); + } + JE_textShade(VGAScreen, 185, tempY, tempStr, temp2 / 16, temp2 % 16 -8-temp4, DARKEN); + + /* Draw icon if not DONE. NOTE: None is a normal item with a blank icon. */ + if (tempW < menuChoices[curMenu]-1) + { + JE_drawItem(curSel[1]-1, temp, 160, tempY-4); + } + + /* Make selected text brigther */ + temp2 = (tempW == curSel[curMenu]-1) ? 15 : 28; + + /* Draw Cost: if it's not the DONE option */ + if (tempW != menuChoices[curMenu]-1) + { + char buf[20]; + + snprintf(buf, sizeof buf, "Cost: %d", temp_cost); + JE_textShade(VGAScreen, 187, tempY+10, buf, temp2 / 16, temp2 % 16 - 8 - temp4, DARKEN); + } + } + } /* /weapon upgrade */ + + /* Draw current money and shield/armor bars, when appropriate */ + /* YKS: Ouch */ + if (((curMenu <= 2 || curMenu == 5 || curMenu == 6 || curMenu >= 10) && !twoPlayerMode) || (curMenu == 4 && (curSel[1] >= 1 && curSel[1] <= 6))) + { + if (curMenu != 4) + { + char buf[20]; + + snprintf(buf, sizeof buf, "%lu", player[0].cash); + JE_textShade(VGAScreen, 65, 173, buf, 1, 6, DARKEN); + } + JE_barDrawShadow(VGAScreen, 42, 152, 3, 14, player[0].armor, 2, 13); + JE_barDrawShadow(VGAScreen, 104, 152, 2, 14, shields[player[0].items.shield].mpwr * 2, 2, 13); + } + + /* Draw crap on the left side of the screen, i.e. two player scores, ship graphic, etc. */ + if (((curMenu >= 0 && curMenu <= 2) || curMenu == 5 || curMenu == 6 || curMenu >= 9) || (curMenu == 4 && (curSel[1] == 2 || curSel[1] == 5))) + { + if (twoPlayerMode) + { + char buf[50]; + + for (uint i = 0; i < 2; ++i) + { + snprintf(buf, sizeof(buf), "%s %lu", miscText[40 + i], player[i].cash); + JE_textShade(VGAScreen, 25, 50 + 10 * i, buf, 15, 0, FULL_SHADE); + } + } + else if (superArcadeMode != SA_NONE || superTyrian) + { + helpBoxColor = 15; + helpBoxBrightness = 4; + if (!superTyrian) + JE_helpBox(VGAScreen, 35, 25, superShips[superArcadeMode], 18); + else + JE_helpBox(VGAScreen, 35, 25, superShips[SA+3], 18); + helpBoxBrightness = 1; + + JE_textShade(VGAScreen, 25, 50, superShips[SA+1], 15, 0, FULL_SHADE); + JE_helpBox(VGAScreen, 25, 60, weaponPort[player[0].items.weapon[FRONT_WEAPON].id].name, 22); + JE_textShade(VGAScreen, 25, 120, superShips[SA+2], 15, 0, FULL_SHADE); + JE_helpBox(VGAScreen, 25, 130, special[player[0].items.special].name, 22); + } + else + { + draw_ship_illustration(); + } + } + + /* Changing the volume? */ + if ((curMenu == 2) || (curMenu == 11)) + { + JE_barDrawShadow(VGAScreen, 225, 70, 1, 16, tyrMusicVolume / 12, 3, 13); + JE_barDrawShadow(VGAScreen, 225, 86, 1, 16, fxVolume / 12, 3, 13); + } + + /* 7 is data cubes menu, 8 is reading a data cube, "firstmenu9" refers to menu 8 because of reindexing */ + if (curMenu == 7 || ( curMenu == 8 && (firstMenu9 || backFromHelp) ) ) + { + firstMenu9 = false; + menuChoices[7] = cubeMax + 2; + fill_rectangle_xy(VGAScreen, 1, 1, 145, 170, 0); + + blit_sprite(VGAScreenSeg, 1, 1, OPTION_SHAPES, 20); /* Portrait area background */ + + if (curMenu == 7) + { + if (cubeMax == 0) + { + JE_helpBox(VGAScreen, 166, 80, miscText[16 - 1], 30); + tempW = 160; + temp2 = 252; + } + else + { + for (int x = 1; x <= cubeMax; x++) + { + JE_drawCube(VGAScreenSeg, 166, 38 + (x - 1) * 28, 13, 0); + if (x + 1 == curSel[curMenu]) + { + if (keyboardUsed) + set_mouse_position(305, 38 + (x - 1) * 28 + 6); + temp2 = 252; + } + else + { + temp2 = 250; + } + + helpBoxColor = temp2 / 16; + helpBoxBrightness = (temp2 % 16) - 8; + helpBoxShadeType = DARKEN; + JE_helpBox(VGAScreen, 192, 44 + (x - 1) * 28, cube[x - 1].title, 24); + } + int x = cubeMax + 1; + if (x + 1 == curSel[curMenu]) + { + if (keyboardUsed) + set_mouse_position(305, 38 + (x - 1) * 28 + 6); + temp2 = 252; + } + else + { + temp2 = 250; + } + tempW = 44 + (x - 1) * 28; + } + + JE_textShade(VGAScreen, 172, tempW, miscText[6 - 1], temp2 / 16, (temp2 % 16) - 8, DARKEN); + } + + if (curSel[7] < menuChoices[7]) + { + const int face_sprite = cube[curSel[7] - 2].face_sprite; + + if (face_sprite != -1) + { + const int face_x = 77 - (sprite(FACE_SHAPES, face_sprite)->width / 2), + face_y = 92 - (sprite(FACE_SHAPES, face_sprite)->height / 2); + + blit_sprite(VGAScreenSeg, face_x, face_y, FACE_SHAPES, face_sprite); // datacube face + + // modify pallete for face + paletteChanged = true; + temp2 = facepal[face_sprite]; + newPal = 0; + + for (temp = 1; temp <= 255 - (3 * 16); temp++) + colors[temp] = palettes[temp2][temp]; + } + } + } + + /* 2 player input devices */ + if (curMenu == 9) + { + for (uint i = 0; i < COUNTOF(inputDevice); i++) + { + if (inputDevice[i] > 2 + joysticks) + inputDevice[i] = inputDevice[i == 0 ? 1 : 0] == 1 ? 2 : 1; + + char temp[64]; + if (joysticks > 1 && inputDevice[i] > 2) + sprintf(temp, "%s %d", inputDevices[2], inputDevice[i] - 2); + else + sprintf(temp, "%s", inputDevices[inputDevice[i] - 1]); + JE_dString(VGAScreen, 186, 38 + 2 * (i + 1) * 16, temp, SMALL_FONT_SHAPES); + } + } + + /* JE: { - Step VI - Help text for current cursor location } */ + + flash = false; + + /* JE: {Reset player weapons} */ + memset(shotMultiPos, 0, sizeof(shotMultiPos)); + + JE_drawScore(); + + JE_drawMainMenuHelpText(); + + if (newPal > 0) /* can't reindex this :( */ + { + curPal = newPal; + memcpy(colors, palettes[newPal - 1], sizeof(colors)); + set_palette(palettes[newPal - 1], 0, 255); + newPal = 0; + } + + /* datacube title under face */ + if ( ( (curMenu == 7) || (curMenu == 8) ) && (curSel[7] < menuChoices[7]) ) + JE_textShade (VGAScreen, 75 - JE_textWidth(cube[curSel[7] - 2].header, TINY_FONT) / 2, 173, cube[curSel[7] - 2].header, 14, 3, DARKEN); + + /* SYN: Everything above was just drawing the screen. In the rest of it, we process + any user input (and do a few other things) */ + + /* SYN: Let's start by getting fresh events from SDL */ + service_SDL_events(true); + + if (constantPlay) + { + mainLevel = mapSection[mapPNum-1]; + jumpSection = true; + } + else + { + do + { + /* Inner loop -- this handles animations on menus that need them and handles + some keyboard events. Events it can't handle end the loop and fall through + to the main keyboard handler below. + + Also, I think all timing is handled in here. Somehow. */ + + NETWORK_KEEP_ALIVE(); + + mouseCursor = 0; + + col += colC; + if (col < -2 || col > 6) + { + colC = (-1 * colC); + } + + // data cube reading + if (curMenu == 8) + { + if (mouseX > 164 && mouseX < 299 && mouseY > 47 && mouseY < 153) + { + if (mouseY > 100) + mouseCursor = 2; + else + mouseCursor = 1; + } + + fill_rectangle_xy(VGAScreen, 160, 49, 310, 158, 228); + if (yLoc + yChg < 0) + { + yChg = 0; + yLoc = 0; + } + + yLoc += yChg; + temp = yLoc / 12; + temp2 = yLoc % 12; + tempW = 38 + 12 - temp2; + temp3 = cube[curSel[7] - 2].last_line; + + for (int x = temp + 1; x <= temp + 10; x++) + { + if (x <= temp3) + { + JE_outTextAndDarken(VGAScreen, 161, tempW, cube[curSel[7] - 2].text[x-1], 14, 3, TINY_FONT); + tempW += 12; + } + } + + fill_rectangle_xy(VGAScreen, 160, 39, 310, 48, 228); + fill_rectangle_xy(VGAScreen, 160, 157, 310, 166, 228); + + int percent_read = (cube[currentCube].last_line <= 9) + ? 100 + : (yLoc * 100) / ((cube[currentCube].last_line - 9) * 12); + + char buf[20]; + snprintf(buf, sizeof(buf), "%s %d%%", miscText[11], percent_read); + JE_outTextAndDarken(VGAScreen, 176, 160, buf, 14, 1, TINY_FONT); + + JE_dString(VGAScreen, 260, 160, miscText[12], SMALL_FONT_SHAPES); + + if (temp2 == 0) + yChg = 0; + + JE_mouseStart(); + + JE_showVGA(); + + if (backFromHelp) + { + fade_palette(colors, 10, 0, 255); + backFromHelp = false; + } + JE_mouseReplace(); + + setjasondelay(1); + } + else + { + /* current menu is not 8 (read data cube) */ + + if (curMenu == 3) + { + JE_updateNavScreen(); + JE_drawMainMenuHelpText(); + JE_drawMenuHeader(); + JE_drawMenuChoices(); + if (extraGame) + JE_dString(VGAScreen, 170, 140, miscText[68 - 1], FONT_SHAPES); + } + + if (curMenu == 7 && curSel[7] < menuChoices[7]) + { + /* Draw flashy cube */ + blit_sprite_hv_blend(VGAScreenSeg, 166, 38 + (curSel[7] - 2) * 28, OPTION_SHAPES, 25, 13, col); + } + + /* IF (curmenu = 5) AND (cursel [2] IN [3, 4, 6, 7, 8]) */ + if (curMenu == 4 && ( curSel[1] == 3 || curSel[1] == 4 || ( curSel[1] >= 6 && curSel[1] <= 8) ) ) + { + setjasondelay(3); + JE_weaponSimUpdate(); + JE_drawScore(); + service_SDL_events(false); + + if (newPal > 0) + { + curPal = newPal; + set_palette(palettes[newPal - 1], 0, 255); + newPal = 0; + } + + JE_mouseStart(); + + if (paletteChanged) + { + set_palette(colors, 0, 255); + paletteChanged = false; + } + + JE_showVGA(); /* SYN: This is where it updates the screen for the weapon sim */ + + if (backFromHelp) + { + fade_palette(colors, 10, 0, 255); + backFromHelp = false; + } + + JE_mouseReplace(); + + } else { /* current menu is anything but weapon sim or datacube */ + + setjasondelay(2); + + JE_drawScore(); + //JE_waitRetrace(); didn't do anything anyway? + + if (newPal > 0) + { + curPal = newPal; + set_palette(palettes[newPal - 1], 0, 255); + newPal = 0; + } + + JE_mouseStart(); + + if (paletteChanged) + { + set_palette(colors, 0, 255); + paletteChanged = false; + } + + JE_showVGA(); /* SYN: This is the where the screen updates for most menus */ + + JE_mouseReplace(); + + if (backFromHelp) + { + fade_palette(colors, 10, 0, 255); + backFromHelp = false; + } + + } + } + + wait_delay(); + + push_joysticks_as_keyboard(); + service_SDL_events(false); + mouseButton = JE_mousePosition(&mouseX, &mouseY); + inputDetected = newkey || mouseButton > 0; + + if (curMenu != 6) + { + if (keysactive[SDLK_s] && (keysactive[SDLK_LALT] || keysactive[SDLK_RALT]) ) + { + if (curMenu == 8 || curMenu == 7) + { + curMenu = 0; + } + quikSave = true; + oldMenu = curMenu; + curMenu = 6; + performSave = true; + newPal = 1; + oldPal = curPal; + } + if (keysactive[SDLK_l] && (keysactive[SDLK_LALT] || keysactive[SDLK_RALT]) ) + { + if (curMenu == 8 || curMenu == 7) + { + curMenu = 0; + } + quikSave = true; + oldMenu = curMenu; + curMenu = 6; + performSave = false; + newPal = 1; + oldPal = curPal; + } + } + + if (curMenu == 8) + { + if (mouseButton > 0 && mouseCursor >= 1) + { + inputDetected = false; + if (mouseCursor == 1) + { + yChg = -1; + } else { + yChg = 1; + } + } + + if (keysactive[SDLK_PAGEUP]) + { + yChg = -2; + inputDetected = false; + } + if (keysactive[SDLK_PAGEDOWN]) + { + yChg = 2; + inputDetected = false; + } + + bool joystick_up = false, joystick_down = false; + for (int j = 0; j < joysticks; j++) + { + joystick_up |= joystick[j].direction[0]; + joystick_down |= joystick[j].direction[2]; + } + + if (keysactive[SDLK_UP] || joystick_up) + { + yChg = -1; + inputDetected = false; + } + + if (keysactive[SDLK_DOWN] || joystick_down) + { + yChg = 1; + inputDetected = false; + } + + if (yChg < 0 && yLoc == 0) + { + yChg = 0; + } + if (yChg > 0 && (yLoc / 12) > cube[currentCube].last_line - 10) + { + yChg = 0; + } + } + + } while (!inputDetected); + } + + keyboardUsed = false; + + /* The rest of this just grabs input events, handles them, then proceeds on. */ + + if (mouseButton > 0) + { + lastDirection = 1; + + mouseButton = JE_mousePosition(&mouseX, &mouseY); + + if (curMenu == 7 && cubeMax == 0) + { + curMenu = 0; + JE_playSampleNum(S_SPRING); + newPal = 1; + JE_wipeKey(); + } + + if (curMenu == 8) + { + if ((mouseX > 258) && (mouseX < 290) && (mouseY > 159) && (mouseY < 171)) + { + curMenu = 7; + JE_playSampleNum(S_SPRING); + } + } + + if (curMenu == 2 || curMenu == 11) + { + if ((mouseX >= (225 - 4)) && (mouseY >= 70) && (mouseY <= 82)) + { + if (music_disabled) + { + music_disabled = false; + restart_song(); + } + + curSel[2] = 4; + + tyrMusicVolume = (mouseX - (225 - 4)) / 4 * 12; + if (tyrMusicVolume > 255) + tyrMusicVolume = 255; + } + + if ((mouseX >= (225 - 4)) && (mouseY >= 86) && (mouseY <= 98)) + { + samples_disabled = false; + + curSel[2] = 5; + + fxVolume = (mouseX - (225 - 4)) / 4 * 12; + if (fxVolume > 255) + fxVolume = 255; + } + + JE_calcFXVol(); + + set_volume(tyrMusicVolume, fxVolume); + + JE_playSampleNum(S_CURSOR); + } + + if ((mouseY > 20) && (mouseX > 170) && (mouseX < 308) && (curMenu != 8)) + { + const JE_byte mouseSelectionY[MAX_MENU] = { 16, 16, 16, 16, 26, 12, 11, 28, 0, 16, 16, 16, 8, 16 }; + + tempI = (mouseY - 38) / mouseSelectionY[curMenu]+2; + + if (curMenu == 9) + { + if (tempI > 5) + tempI--; + if (tempI > 3) + tempI--; + } + + if (curMenu == 0) + { + if (tempI > 7) + tempI = 7; + } + + // is play next level screen? + if (curMenu == 3) + { + if (tempI == menuChoices[curMenu] + 1) + tempI = menuChoices[curMenu]; + } + + if (tempI <= menuChoices[curMenu]) + { + if ((curMenu == 4) && (tempI == menuChoices[4])) + { + player[0].cash = JE_cashLeft(); + curMenu = 1; + JE_playSampleNum(S_ITEM); + } + else + { + JE_playSampleNum(S_CLICK); + if (curSel[curMenu] == tempI) + { + JE_menuFunction(curSel[curMenu]); + } + else + { + if ((curMenu == 5) && (JE_getCost(curSel[1], itemAvail[itemAvailMap[curSel[2]-1]][tempI-1]) > player[0].cash)) + { + JE_playSampleNum(S_CLINK); + } + else + { + if (curSel[1] == 4) + player[0].weapon_mode = 1; + + curSel[curMenu] = tempI; + } + + // in front or rear weapon upgrade screen? + if ((curMenu == 4) && ((curSel[1] == 3) || (curSel[1] == 4))) + player[0].items.weapon[curSel[1]-3].power = temp_weapon_power[curSel[4]-2]; + } + } + } + + wait_noinput(false, true, false); + } + + if ((curMenu == 4) && ((curSel[1] == 3) || (curSel[1] == 4))) + { + if ((mouseX >= 23) && (mouseX <= 36) && (mouseY >= 149) && (mouseY <= 168)) + { + JE_playSampleNum(S_CURSOR); + switch (curSel[1]) + { + case 3: + case 4: + if (leftPower) + player[0].items.weapon[curSel[1]-3].power = --temp_weapon_power[curSel[4]-2]; + else + JE_playSampleNum(S_CLINK); + + break; + } + wait_noinput(false, true, false); + } + + if ((mouseX >= 119) && (mouseX <= 131) && (mouseY >= 149) && (mouseY <= 168)) + { + JE_playSampleNum(S_CURSOR); + switch (curSel[1]) + { + case 3: + case 4: + if (rightPower && rightPowerAfford) + player[0].items.weapon[curSel[1]-3].power = ++temp_weapon_power[curSel[4]-2]; + else + JE_playSampleNum(S_CLINK); + + break; + } + wait_noinput(false, true, false); + } + } + } + else if (newkey) + { + switch (lastkey_sym) + { + case SDLK_SLASH: + // if in rear weapon upgrade screen + if ( (curMenu == 4) && (curSel[1] == 4)) + { + // cycle weapon modes + if (++player[0].weapon_mode > weaponPort[player[0].items.weapon[REAR_WEAPON].id].opnum) + player[0].weapon_mode = 1; + } + break; + + case SDLK_SPACE: + case SDLK_RETURN: + keyboardUsed = true; + + // if front or rear weapon, update "Done" power level + if (curMenu == 4 && (curSel[1] == 3 || curSel[1] == 4)) + temp_weapon_power[itemAvailMax[itemAvailMap[curSel[1]-2]-1]] = player[0].items.weapon[curSel[1]-3].power; + + JE_menuFunction(curSel[curMenu]); + break; + + case SDLK_ESCAPE: + keyboardUsed = true; + + JE_playSampleNum(S_SPRING); + if ( (curMenu == 6) && quikSave) + { + curMenu = oldMenu; + newPal = oldPal; + } + else if (menuEsc[curMenu] == 0) + { + if (JE_quitRequest()) + { + gameLoaded = true; + mainLevel = 0; + } + } + else + { + if (curMenu == 4) // leaving upgrade menu without buying + { + player[0].items = old_items[0]; + curSel[4] = lastCurSel; + player[0].cash = JE_cashLeft(); + } + + if (curMenu != 8) // not data cube + newPal = 1; + + curMenu = menuEsc[curMenu] - 1; + } + break; + + case SDLK_F1: + if (!isNetworkGame) + { + JE_helpSystem(2); + fade_black(10); + + play_song(songBuy); + + JE_loadPic(VGAScreen, 1, false); + newPal = 1; + + switch (curMenu) + { + case 3: + newPal = 18; + break; + case 7: + case 8: + break; + } + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + curPal = newPal; + memcpy(colors, palettes[newPal-1], sizeof(colors)); + JE_showVGA(); + newPal = 0; + backFromHelp = true; + } + break; + + case SDLK_UP: + keyboardUsed = true; + lastDirection = -1; + + if (curMenu != 8) // not data cube + JE_playSampleNum(S_CURSOR); + + curSel[curMenu]--; + if (curSel[curMenu] < 2) + curSel[curMenu] = menuChoices[curMenu]; + + // if in front or rear weapon upgrade screen + if (curMenu == 4 && (curSel[1] == 3 || curSel[1] == 4)) + { + player[0].items.weapon[curSel[1]-3].power = temp_weapon_power[curSel[4]-2]; + if (curSel[curMenu] == 4) + player[0].weapon_mode = 1; + } + + // if joystick config, skip disabled items when digital + if (curMenu == 12 && joysticks > 0 && !joystick[joystick_config].analog && curSel[curMenu] == 5) + curSel[curMenu] = 3; + + break; + + case SDLK_DOWN: + keyboardUsed = true; + lastDirection = 1; + + if (curMenu != 8) // not data cube + JE_playSampleNum(S_CURSOR); + + curSel[curMenu]++; + if (curSel[curMenu] > menuChoices[curMenu]) + curSel[curMenu] = 2; + + // if in front or rear weapon upgrade screen + if (curMenu == 4 && (curSel[1] == 3 || curSel[1] == 4)) + { + player[0].items.weapon[curSel[1]-3].power = temp_weapon_power[curSel[4]-2]; + if (curSel[curMenu] == 4) + player[0].weapon_mode = 1; + } + + // if in joystick config, skip disabled items when digital + if (curMenu == 12 && joysticks > 0 && !joystick[joystick_config].analog && curSel[curMenu] == 4) + curSel[curMenu] = 6; + + break; + + case SDLK_HOME: + if (curMenu == 8) // data cube + yLoc = 0; + break; + + case SDLK_END: + if (curMenu == 8) // data cube + yLoc = (cube[currentCube].last_line - 9) * 12; + break; + + case SDLK_LEFT: + if (curMenu == 12) // joystick settings menu + { + if (joysticks > 0) + { + switch (curSel[curMenu]) + { + case 2: + if (joystick_config == 0) + joystick_config = joysticks; + joystick_config--; + break; + case 3: + joystick[joystick_config].analog = !joystick[joystick_config].analog; + break; + case 4: + if (joystick[joystick_config].sensitivity == 0) + joystick[joystick_config].sensitivity = 10; + else + joystick[joystick_config].sensitivity--; + break; + case 5: + if (joystick[joystick_config].threshold == 0) + joystick[joystick_config].threshold = 10; + else + joystick[joystick_config].threshold--; + break; + default: + break; + } + } + } + + if (curMenu == 9) + { + switch (curSel[curMenu]) + { + case 3: + case 4: + JE_playSampleNum(S_CURSOR); + + int temp = curSel[curMenu] - 3; + do { + if (joysticks == 0) + { + inputDevice[temp == 0 ? 1 : 0] = inputDevice[temp]; // swap controllers + } + if (inputDevice[temp] <= 1) + { + inputDevice[temp] = 2 + joysticks; + } else { + inputDevice[temp]--; + } + } while (inputDevice[temp] == inputDevice[temp == 0 ? 1 : 0]); + break; + } + } + + if (curMenu == 2 || curMenu == 4 || curMenu == 11) + { + JE_playSampleNum(S_CURSOR); + } + + switch (curMenu) + { + case 2: + case 11: + switch (curSel[curMenu]) + { + case 4: + JE_changeVolume(&tyrMusicVolume, -12, &fxVolume, 0); + if (music_disabled) + { + music_disabled = false; + restart_song(); + } + break; + case 5: + JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, -12); + samples_disabled = false; + break; + } + break; + case 4: + switch (curSel[1]) + { + case 3: + case 4: + if (leftPower) + player[0].items.weapon[curSel[1]-3].power = --temp_weapon_power[curSel[4]-2]; + else + JE_playSampleNum(S_CLINK); + + break; + } + break; + } + break; + + case SDLK_RIGHT: + if (curMenu == 12) // joystick settings menu + { + if (joysticks > 0) + { + switch (curSel[curMenu]) + { + case 2: + joystick_config++; + joystick_config %= joysticks; + break; + case 3: + joystick[joystick_config].analog = !joystick[joystick_config].analog; + break; + case 4: + joystick[joystick_config].sensitivity++; + joystick[joystick_config].sensitivity %= 11; + break; + case 5: + joystick[joystick_config].threshold++; + joystick[joystick_config].threshold %= 11; + break; + default: + break; + } + } + } + + if (curMenu == 9) + { + switch (curSel[curMenu]) + { + case 3: + case 4: + JE_playSampleNum(S_CURSOR); + + int temp = curSel[curMenu] - 3; + do { + if (joysticks == 0) + { + inputDevice[temp == 0 ? 1 : 0] = inputDevice[temp]; // swap controllers + } + if (inputDevice[temp] >= 2 + joysticks) + { + inputDevice[temp] = 1; + } else { + inputDevice[temp]++; + } + } while (inputDevice[temp] == inputDevice[temp == 0 ? 1 : 0]); + break; + } + } + + if (curMenu == 2 || curMenu == 4 || curMenu == 11) + { + JE_playSampleNum(S_CURSOR); + } + + switch (curMenu) + { + case 2: + case 11: + switch (curSel[curMenu]) + { + case 4: + JE_changeVolume(&tyrMusicVolume, 12, &fxVolume, 0); + if (music_disabled) + { + music_disabled = false; + restart_song(); + } + break; + case 5: + JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, 12); + samples_disabled = false; + break; + } + break; + case 4: + switch (curSel[1]) + { + case 3: + case 4: + if (rightPower && rightPowerAfford) + player[0].items.weapon[curSel[1]-3].power = ++temp_weapon_power[curSel[4]-2]; + else + JE_playSampleNum(S_CLINK); + + break; + } + break; + } + break; + + default: + break; + } + } + + } while (!(quit || gameLoaded || jumpSection)); + + if (!quit && isNetworkGame) + { + JE_barShade(VGAScreen, 3, 3, 316, 196); + JE_barShade(VGAScreen, 1, 1, 318, 198); + JE_dString(VGAScreen, 10, 160, "Waiting for other player.", SMALL_FONT_SHAPES); + + network_prepare(PACKET_WAITING); + network_send(4); // PACKET_WAITING + + while (true) + { + service_SDL_events(false); + JE_showVGA(); + + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING) + { + network_update(); + break; + } + + network_update(); + network_check(); + + SDL_Delay(16); + } + + network_state_reset(); + } + + if (isNetworkGame) + { + while (!network_is_sync()) + { + service_SDL_events(false); + JE_showVGA(); + + network_check(); + SDL_Delay(16); + } + } + + if (gameLoaded) + fade_black(10); +} + +void draw_ship_illustration( void ) +{ + // full of evil hardcoding + + // ship + { + assert(player[0].items.ship > 0); + + const int sprite_id = (player[0].items.ship < COUNTOF(ships)) // shipedit ships get a default + ? ships[player[0].items.ship].bigshipgraphic - 1 + : 31; + + const int ship_x[6] = { 31, 0, 0, 0, 35, 31 }, + ship_y[6] = { 36, 0, 0, 0, 33, 35 }; + + const int x = ship_x[sprite_id - 27], + y = ship_y[sprite_id - 27]; + + blit_sprite(VGAScreenSeg, x, y, OPTION_SHAPES, sprite_id); + } + + // generator + { + assert(player[0].items.generator > 0 && player[0].items.generator < 7); + + const int sprite_id = (player[0].items.generator == 1) // generator 1 and generator 2 have the same sprite + ? player[0].items.generator + 15 + : player[0].items.generator + 14; + + const int generator_x[5] = { 62, 64, 67, 66, 63 }, + generator_y[5] = { 84, 85, 86, 84, 97 }; + const int x = generator_x[sprite_id - 16], + y = generator_y[sprite_id - 16]; + + blit_sprite(VGAScreenSeg, x, y, WEAPON_SHAPES, sprite_id); + } + + const int weapon_sprites[43] = + { + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 21, 5, 13, -1, 14, 15, 0, + 14, 9, 8, 2, 15, 0, 13, 0, 8, 8, + 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 1 + }; + + // front weapon + if (player[0].items.weapon[FRONT_WEAPON].id > 0) + { + const int front_weapon_xy_list[43] = + { + -1, 4, 9, 3, 8, 2, 5, 10, 1, -1, + -1, -1, -1, 7, 8, -1, -1, 0, -1, 4, + 0, -1, -1, 3, -1, 4, -1, 4, -1, -1, + -1, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 9 + }; + + const int front_weapon_x[12] = { 59, 66, 66, 54, 61, 51, 58, 51, 61, 52, 53, 58 }; + const int front_weapon_y[12] = { 38, 53, 41, 36, 48, 35, 41, 35, 53, 41, 39, 31 }; + const int x = front_weapon_x[front_weapon_xy_list[player[0].items.weapon[FRONT_WEAPON].id]], + y = front_weapon_y[front_weapon_xy_list[player[0].items.weapon[FRONT_WEAPON].id]]; + + blit_sprite(VGAScreenSeg, x, y, WEAPON_SHAPES, weapon_sprites[player[0].items.weapon[FRONT_WEAPON].id]); // ship illustration: front weapon + } + + // rear weapon + if (player[0].items.weapon[REAR_WEAPON].id > 0) + { + const int rear_weapon_xy_list[43] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, + 1, 2, 3, -1, 4, 5, -1, -1, 6, -1, + -1, 1, 0, -1, 6, -1, 5, -1, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -1, -1 + }; + + const int rear_weapon_x[7] = { 41, 27, 49, 43, 51, 39, 41 }; + const int rear_weapon_y[7] = { 92, 92, 113, 102, 97, 96, 76 }; + const int x = rear_weapon_x[rear_weapon_xy_list[player[0].items.weapon[REAR_WEAPON].id]], + y = rear_weapon_y[rear_weapon_xy_list[player[0].items.weapon[REAR_WEAPON].id]]; + + blit_sprite(VGAScreenSeg, x, y, WEAPON_SHAPES, weapon_sprites[player[0].items.weapon[REAR_WEAPON].id]); + } + + // sidekicks + JE_drawItem(6, player[0].items.sidekick[LEFT_SIDEKICK], 3, 84); + JE_drawItem(7, player[0].items.sidekick[RIGHT_SIDEKICK], 129, 84); + + // shield + blit_sprite_hv(VGAScreenSeg, 28, 23, OPTION_SHAPES, 26, 15, shields[player[0].items.shield].mpwr - 10); +} + +void load_cubes( void ) +{ + for (int cube_slot = 0; cube_slot < cubeMax; ++cube_slot) + { + memset(cube[cube_slot].text, 0, sizeof(cube->text)); + + load_cube(cube_slot, cubeList[cube_slot]); + } +} + +bool load_cube( int cube_slot, int cube_index ) +{ + FILE *f = dir_fopen_die(data_dir(), cube_file, "rb"); + + char buf[256]; + + // seek to the cube + while (cube_index > 0) + { + read_encrypted_pascal_string(buf, sizeof(buf), f); + if (buf[0] == '*') + --cube_index; + + if (feof(f)) + { + fclose(f); + + return false; + } + } + + str_pop_int(&buf[4], &cube[cube_slot].face_sprite); + --cube[cube_slot].face_sprite; + + read_encrypted_pascal_string(cube[cube_slot].title, sizeof(cube[cube_slot].title), f); + read_encrypted_pascal_string(cube[cube_slot].header, sizeof(cube[cube_slot].header), f); + + uint line = 0, line_chars = 0, line_width = 0; + + // for each line of decrypted text, split the line into words + // and add them individually to the lines of wrapped text + for (; ; ) + { + read_encrypted_pascal_string(buf, sizeof(buf), f); + + // end of data + if (feof(f) || buf[0] == '*') + break; + + // new paragraph + if (strlen(buf) == 0) + { + if (line_chars == 0) + line += 4; // subsequent new paragaphs indicate 4-line break + else + ++line; + line_chars = 0; + line_width = 0; + + continue; + } + + uint word_start = 0; + for (uint i = 0; ; ++i) + { + bool end_of_line = (buf[i] == '\0'), + end_of_word = end_of_line || (buf[i] == ' '); + + if (end_of_word) + { + buf[i] = '\0'; + + char *word = &buf[word_start]; + word_start = i + 1; + + uint word_chars = strlen(word), + word_width = JE_textWidth(word, TINY_FONT); + + // word won't fit; no can do + if (word_chars > cube_line_chars || word_width > cube_line_width) + break; + + bool prepend_space = true; + + line_chars += word_chars + (prepend_space ? 1 : 0); + line_width += word_width + (prepend_space ? 6 : 0); + + // word won't fit on current line; use next + if (line_chars > cube_line_chars || line_width > cube_line_width) + { + ++line; + line_chars = word_chars; + line_width = word_width; + + prepend_space = false; + } + + // append word + if (line < COUNTOF(cube->text)) + { + if (prepend_space) + strcat(cube[cube_slot].text[line], " "); + strcat(cube[cube_slot].text[line], word); + + // track last line with text + cube[cube_slot].last_line = line + 1; + } + } + + if (end_of_line) + break; + } + } + + fclose(f); + + return true; +} + +void JE_drawItem( JE_byte itemType, JE_word itemNum, JE_word x, JE_word y ) +{ + JE_word tempW = 0; + + if (itemNum > 0) + { + switch (itemType) + { + case 2: + case 3: + tempW = weaponPort[itemNum].itemgraphic; + break; + case 5: + tempW = powerSys[itemNum].itemgraphic; + break; + case 6: + case 7: + tempW = options[itemNum].itemgraphic; + break; + case 4: + tempW = shields[itemNum].itemgraphic; + break; + } + + if (itemType == 1) + { + if (itemNum > 90) + { + shipGrPtr = &shapes9; + shipGr = JE_SGr(itemNum - 90, &shipGrPtr); + blit_sprite2x2(VGAScreen, x, y, *shipGrPtr, shipGr); + } + else + { + blit_sprite2x2(VGAScreen, x, y, shapes9, ships[itemNum].shipgraphic); + } + } + else if (tempW > 0) + { + blit_sprite2x2(VGAScreen, x, y, shapes6, tempW); + } + } +} + +void JE_drawMenuHeader( void ) +{ + switch (curMenu) + { + case 8: + strcpy(tempStr, cube[curSel[7]-2].header); + break; + case 7: + strcpy(tempStr, menuInt[1][1]); + break; + case 6: + strcpy(tempStr, menuInt[3][performSave + 1]); + break; + default: + strcpy(tempStr, menuInt[curMenu + 1][0]); + break; + } + JE_dString(VGAScreen, 74 + JE_fontCenter(tempStr, FONT_SHAPES), 10, tempStr, FONT_SHAPES); +} + +void JE_drawMenuChoices( void ) +{ + JE_byte x; + char *str; + + for (x = 2; x <= menuChoices[curMenu]; x++) + { + int tempY = 38 + (x-1) * 16; + + if (curMenu == 0) + { + if (x == 7) + { + tempY += 16; + } + } + + if (curMenu == 9) + { + if (x > 3) + { + tempY += 16; + } + if (x > 4) + { + tempY += 16; + } + } + + if (!(curMenu == 3 && x == menuChoices[curMenu])) + { + tempY -= 16; + } + + str = (char *)malloc(strlen(menuInt[curMenu + 1][x-1])+2); + if (curSel[curMenu] == x) + { + str[0] = '~'; + strcpy(str+1, menuInt[curMenu + 1][x-1]); + } else { + strcpy(str, menuInt[curMenu + 1][x-1]); + } + JE_dString(VGAScreen, 166, tempY, str, SMALL_FONT_SHAPES); + free(str); + + if (keyboardUsed && curSel[curMenu] == x) + { + set_mouse_position(305, tempY + 6); + } + } +} + +void JE_updateNavScreen( void ) +{ + JE_byte x; + + /* minor issues: */ + /* TODO: The scroll to the new planet is too fast, I think */ + /* TODO: The starting coordinates for the scrolling effect may be wrong, the + yellowish planet below Tyrian isn't visible for as many frames as in the + original. */ + + tempNavX = roundf(navX); + tempNavY = roundf(navY); + fill_rectangle_xy(VGAScreen, 19, 16, 135, 169, 2); + JE_drawNavLines(true); + JE_drawNavLines(false); + JE_drawDots(); + + for (x = 0; x < 11; x++) + JE_drawPlanet(x); + + for (x = 0; x < menuChoices[3]-1; x++) + { + if (mapPlanet[x] > 11) + JE_drawPlanet(mapPlanet[x] - 1); + } + + if (mapOrigin > 11) + JE_drawPlanet(mapOrigin - 1); + + blit_sprite(VGAScreenSeg, 0, 0, OPTION_SHAPES, 28); // navigation screen interface + + if (curSel[3] < menuChoices[3]) + { + const unsigned int origin_x_offset = sprite(PLANET_SHAPES, PGR[mapOrigin-1]-1)->width / 2, + origin_y_offset = sprite(PLANET_SHAPES, PGR[mapOrigin-1]-1)->height / 2, + dest_x_offset = sprite(PLANET_SHAPES, PGR[mapPlanet[curSel[3]-2] - 1]-1)->width / 2, + dest_y_offset = sprite(PLANET_SHAPES, PGR[mapPlanet[curSel[3]-2] - 1]-1)->height / 2; + + newNavX = (planetX[mapOrigin-1] - origin_x_offset + + planetX[mapPlanet[curSel[3]-2] - 1] - dest_x_offset) / 2.0f; + newNavY = (planetY[mapOrigin-1] - origin_y_offset + + planetY[mapPlanet[curSel[3]-2] - 1] - dest_y_offset) / 2.0f; + } + + navX = navX + (newNavX - navX) / 2.0f; + navY = navY + (newNavY - navY) / 2.0f; + + if (abs(newNavX - navX) < 1) + navX = newNavX; + if (abs(newNavY - navY) < 1) + navY = newNavY; + + fill_rectangle_xy(VGAScreen, 314, 0, 319, 199, 230); + + if (planetAniWait > 0) + { + planetAniWait--; + } + else + { + planetAni++; + if (planetAni > 14) + planetAni = 0; + planetAniWait = 3; + } + + if (currentDotWait > 0) + { + currentDotWait--; + } + else + { + if (currentDotNum < planetDots[curSel[3]-2]) + currentDotNum++; + currentDotWait = 5; + } +} + +void JE_drawLines( SDL_Surface *surface, JE_boolean dark ) +{ + JE_byte x, y; + JE_integer tempX, tempY; + JE_integer tempX2, tempY2; + JE_word tempW, tempW2; + + tempX2 = -10; + tempY2 = 0; + + tempW = 0; + for (x = 0; x < 20; x++) + { + tempW += 15; + tempX = tempW - tempX2; + + if (tempX > 18 && tempX < 135) + { + if (dark) + { + JE_rectangle(surface, tempX + 1, 0, tempX + 1, 199, 32+3); + } else { + JE_rectangle(surface, tempX, 0, tempX, 199, 32+5); + } + } + } + + tempW = 0; + for (y = 0; y < 20; y++) + { + tempW += 15; + tempY = tempW - tempY2; + + if (tempY > 15 && tempY < 169) + { + if (dark) + { + JE_rectangle(surface, 0, tempY + 1, 319, tempY + 1, 32+3); + } else { + JE_rectangle(surface, 0, tempY, 319, tempY, 32+5); + } + + tempW2 = 0; + + for (x = 0; x < 20; x++) + { + tempW2 += 15; + tempX = tempW2 - tempX2; + if (tempX > 18 && tempX < 135) + { + JE_pix3(surface, tempX, tempY, 32+6); + } + } + } + } +} + +/* SYN: This was originally PROC drawlines... yes, there were two different procs called + drawlines in different scopes in the same file. Dammit, Jason, why do you do this to me? */ + +void JE_drawNavLines( JE_boolean dark ) +{ + JE_byte x, y; + JE_integer tempX, tempY; + JE_integer tempX2, tempY2; + JE_word tempW, tempW2; + + tempX2 = tempNavX >> 1; + tempY2 = tempNavY >> 1; + + tempW = 0; + for (x = 1; x <= 20; x++) + { + tempW += 15; + tempX = tempW - tempX2; + + if (tempX > 18 && tempX < 135) + { + if (dark) + JE_rectangle(VGAScreen, tempX + 1, 16, tempX + 1, 169, 1); + else + JE_rectangle(VGAScreen, tempX, 16, tempX, 169, 5); + } + } + + tempW = 0; + for (y = 1; y <= 20; y++) + { + tempW += 15; + tempY = tempW - tempY2; + + if (tempY > 15 && tempY < 169) + { + if (dark) + JE_rectangle(VGAScreen, 19, tempY + 1, 135, tempY + 1, 1); + else + JE_rectangle(VGAScreen, 8, tempY, 160, tempY, 5); + + tempW2 = 0; + + for (x = 0; x < 20; x++) + { + tempW2 += 15; + tempX = tempW2 - tempX2; + if (tempX > 18 && tempX < 135) + JE_pix3(VGAScreen, tempX, tempY, 7); + } + } + } +} + +void JE_drawDots( void ) +{ + JE_byte x, y; + JE_integer tempX, tempY; + + for (x = 0; x < mapPNum; x++) + { + for (y = 0; y < planetDots[x]; y++) + { + tempX = planetDotX[x][y] - tempNavX + 66 - 2; + tempY = planetDotY[x][y] - tempNavY + 85 - 2; + if (tempX > 0 && tempX < 140 && tempY > 0 && tempY < 168) + blit_sprite(VGAScreenSeg, tempX, tempY, OPTION_SHAPES, (x == curSel[3]-2 && y < currentDotNum) ? 30 : 29); // navigation dots + } + } +} + +void JE_drawPlanet( JE_byte planetNum ) +{ + JE_integer tempZ = PGR[planetNum]-1, + tempX = planetX[planetNum] + 66 - tempNavX - sprite(PLANET_SHAPES, tempZ)->width / 2, + tempY = planetY[planetNum] + 85 - tempNavY - sprite(PLANET_SHAPES, tempZ)->height / 2; + + if (tempX > -7 && tempX + sprite(PLANET_SHAPES, tempZ)->width < 170 && tempY > 0 && tempY < 160) + { + if (PAni[planetNum]) + tempZ += planetAni; + + blit_sprite_dark(VGAScreenSeg, tempX + 3, tempY + 3, PLANET_SHAPES, tempZ, false); + blit_sprite(VGAScreenSeg, tempX, tempY, PLANET_SHAPES, tempZ); // planets + } +} + +void JE_scaleBitmap( SDL_Surface *dst_bitmap, const SDL_Surface *src_bitmap, int x1, int y1, int x2, int y2 ) +{ + /* This function scales one screen and writes the result to another. + * The only code that calls it is the code run when you select 'ship + * specs' from the main menu. + * + * Originally this used fixed point math. I haven't seen that in ages :). + * But we're well past the point of needing that.*/ + + assert(src_bitmap != NULL && dst_bitmap != NULL); + assert(x1 >= 0 && y1 >= 0 && x2 < src_bitmap->pitch && y2 < src_bitmap->h); + + int w = x2 - x1 + 1, + h = y2 - y1 + 1; + float base_skip_w = src_bitmap->pitch / (float)w, + base_skip_h = src_bitmap->h / (float)h; + float cumulative_skip_w, cumulative_skip_h; + + + //Okay, it's time to loop through and add bits of A to a rectangle in B + Uint8 *dst = (Uint8 *)dst_bitmap->pixels; /* 8-bit specific */ + const Uint8 *src, *src_w; /* 8-bit specific */ + + dst += y1 * dst_bitmap->pitch + x1; + cumulative_skip_h = 0; + + for (int i = 0; i < h; i++) + { + //this sets src to the beginning of our desired line + src = src_w = (Uint8 *)(src_bitmap->pixels) + (src_bitmap->w * ((unsigned int)cumulative_skip_h)); + cumulative_skip_h += base_skip_h; + cumulative_skip_w = 0; + + for (int j = 0; j < w; j++) + { + //copy and move pointers + *dst = *src; + dst++; + + cumulative_skip_w += base_skip_w; + src = src_w + ((unsigned int)cumulative_skip_w); //value is floored + } + + dst += dst_bitmap->pitch - w; + } +} + +void JE_initWeaponView( void ) +{ + fill_rectangle_xy(VGAScreen, 8, 8, 144, 177, 0); + + player[0].sidekick[LEFT_SIDEKICK].x = 72 - 15; + player[0].sidekick[LEFT_SIDEKICK].y = 120; + player[0].sidekick[RIGHT_SIDEKICK].x = 72 + 15; + player[0].sidekick[RIGHT_SIDEKICK].y = 120; + + player[0].x = 72; + player[0].y = 110; + player[0].delta_x_shot_move = 0; + player[0].delta_y_shot_move = 0; + player[0].last_x_explosion_follow = 72; + player[0].last_y_explosion_follow = 110; + power = 500; + lastPower = 500; + + memset(shotAvail, 0, sizeof(shotAvail)); + + memset(shotRepeat, 1, sizeof(shotRepeat)); + memset(shotMultiPos, 0, sizeof(shotMultiPos)); + + JE_setupStars(); +} + +void JE_computeDots( void ) +{ + JE_integer tempX, tempY; + JE_longint distX, distY; + JE_byte x, y; + + for (x = 0; x < mapPNum; x++) + { + distX = (int)(planetX[mapPlanet[x]-1]) - (int)(planetX[mapOrigin-1]); + distY = (int)(planetY[mapPlanet[x]-1]) - (int)(planetY[mapOrigin-1]); + tempX = abs(distX) + abs(distY); + + if (tempX != 0) + { + planetDots[x] = roundf(sqrtf(sqrtf((distX * distX) + (distY * distY)))) - 1; + } else { + planetDots[x] = 0; + } + + if (planetDots[x] > 10) + { + planetDots[x] = 10; + } + + for (y = 0; y < planetDots[x]; y++) + { + tempX = JE_partWay(planetX[mapOrigin-1], planetX[mapPlanet[x]-1], planetDots[x], y); + tempY = JE_partWay(planetY[mapOrigin-1], planetY[mapPlanet[x]-1], planetDots[x], y); + /* ??? Why does it use temp? =P */ + planetDotX[x][y] = tempX; + planetDotY[x][y] = tempY; + } + } +} + +JE_integer JE_partWay( JE_integer start, JE_integer finish, JE_byte dots, JE_byte dist ) +{ + return (finish - start) / (dots + 2) * (dist + 1) + start; +} + +void JE_doShipSpecs( void ) +{ + /* This function is called whenever you select 'ship specs' in the + * game menu. It draws the nice green tech screen and scales it onto + * the main window. To do this we need two temp buffers, so we're going + * to use VGAScreen and game_screen for the purpose (making things more + * complex than they would be if we just malloc'd, but faster) + * + * Originally the whole system was pretty oddly designed. So I changed it. + * Currently drawFunkyScreen creates the image, scaleInPicture draws it, + * and doFunkyScreen ties everything together. Before it was more like + * an oddly designed, unreusable, global sharing hierarchy. */ + + //create the image we want + wait_noinput(true, true, true); + JE_drawShipSpecs(game_screen, VGAScreen2); + + //reset VGAScreen2, which we clobbered + JE_loadPic(VGAScreen2, 1, false); + + //draw it + JE_playSampleNum(16); + JE_scaleInPicture(VGAScreen, game_screen); + wait_input(true, true, true); +} + +void JE_drawMainMenuHelpText( void ) +{ + char tempStr[67]; + JE_byte temp; + + temp = curSel[curMenu] - 2; + if (curMenu == 12) // joystick settings menu help + { + int help[16] = { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 24, 11 }; + memcpy(tempStr, mainMenuHelp[help[curSel[curMenu] - 2]], sizeof(tempStr)); + } else if (curMenu < 3 || curMenu == 9 || curMenu > 10) { + memcpy(tempStr, mainMenuHelp[(menuHelp[curMenu][temp])-1], sizeof(tempStr)); + } else { + if (curMenu == 5 && curSel[5] == 10) + { + memcpy(tempStr, mainMenuHelp[25-1], sizeof(tempStr)); + } + else if (leftPower || rightPower) + { + memcpy(tempStr, mainMenuHelp[24-1], sizeof(tempStr)); + } + else if ( (temp == menuChoices[curMenu] - 1) || ( (curMenu == 7) && (cubeMax == 0) ) ) + { + memcpy(tempStr, mainMenuHelp[12-1], sizeof(tempStr)); + } + else + { + memcpy(tempStr, mainMenuHelp[17 + curMenu - 3], sizeof(tempStr)); + } + } + JE_textShade(VGAScreen, 10, 187, tempStr, 14, 1, DARKEN); +} + +JE_boolean JE_quitRequest( void ) +{ + bool quit_selected = true, done = false; + + JE_clearKeyboard(); + JE_wipeKey(); + wait_noinput(true, true, true); + + JE_barShade(VGAScreen, 65, 55, 255, 155); + + while (!done) + { + Uint8 col = 8; + int colC = 1; + + do + { + service_SDL_events(true); + setjasondelay(4); + + blit_sprite(VGAScreen, 50, 50, OPTION_SHAPES, 35); // message box + JE_textShade(VGAScreen, 70, 60, miscText[28], 0, 5, FULL_SHADE); + JE_helpBox(VGAScreen, 70, 90, miscText[30], 30); + + col += colC; + if (col > 8 || col < 2) + colC = -colC; + + int temp_x, temp_c; + + temp_x = 54 + 45 - (JE_textWidth(miscText[9], FONT_SHAPES) / 2); + temp_c = quit_selected ? col - 12 : -5; + + JE_outTextAdjust(VGAScreen, temp_x, 128, miscText[9], 15, temp_c, FONT_SHAPES, true); + + temp_x = 149 + 45 - (JE_textWidth(miscText[10], FONT_SHAPES) / 2); + temp_c = !quit_selected ? col - 12 : -5; + + JE_outTextAdjust(VGAScreen, temp_x, 128, miscText[10], 15, temp_c, FONT_SHAPES, true); + + if (has_mouse) + { + JE_mouseStart(); + JE_showVGA(); + JE_mouseReplace(); + } + else + { + JE_showVGA(); + } + + wait_delay(); + + push_joysticks_as_keyboard(); + service_SDL_events(false); + + } while (!newkey && !mousedown); + + if (mousedown) + { + if (lastmouse_y > 123 && lastmouse_y < 149) + { + if (lastmouse_x > 56 && lastmouse_x < 142) + { + quit_selected = true; + done = true; + } + else if (lastmouse_x > 151 && lastmouse_x < 237) + { + quit_selected = false; + done = true; + } + } + mousedown = false; + } + else if (newkey) + { + switch (lastkey_sym) + { + case SDLK_LEFT: + case SDLK_RIGHT: + case SDLK_TAB: + quit_selected = !quit_selected; + JE_playSampleNum(S_CURSOR); + break; + case SDLK_RETURN: + case SDLK_SPACE: + done = true; + break; + case SDLK_ESCAPE: + quit_selected = false; + done = true; + break; + default: + break; + } + } + } + + JE_playSampleNum(quit_selected ? S_SPRING : S_CLICK); + + if (isNetworkGame && quit_selected) + { + network_prepare(PACKET_QUIT); + network_send(4); // PACKET QUIT + + network_tyrian_halt(0, true); + } + + return quit_selected; +} + +void JE_genItemMenu( JE_byte itemNum ) +{ + menuChoices[4] = itemAvailMax[itemAvailMap[itemNum - 2] - 1] + 2; + + temp3 = 2; + temp2 = *playeritem_map(&player[0].items, itemNum - 2); + + strcpy(menuInt[5][0], menuInt[2][itemNum - 1]); + + for (tempW = 0; tempW < itemAvailMax[itemAvailMap[itemNum - 2] - 1]; tempW++) + { + temp = itemAvail[itemAvailMap[itemNum - 2] - 1][tempW]; + switch (itemNum) + { + case 2: + strcpy(tempStr, ships[temp].name); + break; + case 3: + case 4: + strcpy(tempStr, weaponPort[temp].name); + break; + case 5: + strcpy(tempStr, shields[temp].name); + break; + case 6: + strcpy(tempStr, powerSys[temp].name); + break; + case 7: + case 8: + strcpy(tempStr, options[temp].name); + break; + } + if (temp == temp2) + { + temp3 = tempW + 2; + } + strcpy(menuInt[5][tempW], tempStr); + } + + strcpy(menuInt[5][tempW], miscText[13]); + + curSel[4] = temp3; +} + +void JE_scaleInPicture( SDL_Surface *dst, const SDL_Surface *src ) +{ + for (int i = 2; i <= 160; i += 2) + { + if (JE_anyButton()) { break; } + + JE_scaleBitmap(dst, src, 160 - i, 0, 160 + i - 1, 100 + roundf(i * 0.625f) - 1); + JE_showVGA(); + + SDL_Delay(1); + } +} + + +void JE_drawScore( void ) +{ + char cl[24]; + if (curMenu == 4) + { + sprintf(cl, "%d", JE_cashLeft()); + JE_textShade(VGAScreen, 65, 173, cl, 1, 6, DARKEN); + } +} + +void JE_menuFunction( JE_byte select ) +{ + JE_byte x; + JE_word curSelect; + + col = 0; + colC = -1; + JE_playSampleNum(S_CLICK); + + curSelect = curSel[curMenu]; + + switch (curMenu) + { + case 0: //root menu + switch (select) + { + case 2: //cubes + curMenu = 7; + curSel[7] = 2; + break; + case 3: //shipspecs + JE_doShipSpecs(); + break; + case 4://upgradeship + curMenu = 1; + break; + case 5: //options + curMenu = 2; + break; + case 6: //nextlevel + curMenu = 3; + newPal = 18; + JE_computeDots(); + navX = planetX[mapOrigin - 1]; + navY = planetY[mapOrigin - 1]; + newNavX = navX; + newNavY = navY; + menuChoices[3] = mapPNum + 2; + curSel[3] = 2; + strcpy(menuInt[4][0], "Next Level"); + for (x = 0; x < mapPNum; x++) + { + temp = mapPlanet[x]; + strcpy(menuInt[4][x + 1], pName[temp - 1]); + } + strcpy(menuInt[4][x + 1], miscText[5]); + break; + case 7: //quit + if (JE_quitRequest()) + { + gameLoaded = true; + mainLevel = 0; + } + break; + } + break; + + case 1: //upgradeship + if (select == 9) //done + { + curMenu = 0; + } + else // selected item to upgrade + { + old_items[0] = player[0].items; + + lastDirection = 1; + JE_genItemMenu(select); + JE_initWeaponView(); + curMenu = 4; + lastCurSel = curSel[4]; + player[0].cash = player[0].cash * 2 - JE_cashLeft(); + } + break; + + case 2: //options + switch (select) + { + case 2: + curMenu = 6; + performSave = false; + quikSave = false; + break; + case 3: + curMenu = 6; + performSave = true; + quikSave = false; + break; + case 6: + curMenu = 12; + break; + case 7: + curMenu = 5; + break; + case 8: + curMenu = 0; + break; + } + break; + + case 3: //nextlevel + if (select == menuChoices[3]) //exit + { + curMenu = 0; + newPal = 1; + } else { + mainLevel = mapSection[curSelect - 2]; + jumpSection = true; + } + break; + + case 4: //buying + if (curSel[4] < menuChoices[4]) + { + // select done + curSel[4] = menuChoices[4]; + } + else // if done is selected + { + JE_playSampleNum(S_ITEM); + + player[0].cash = JE_cashLeft(); + curMenu = 1; + } + break; + + case 5: /* keyboard settings */ + if (curSelect == 10) /* reset to defaults */ + { + memcpy(keySettings, defaultKeySettings, sizeof(keySettings)); + } + else if (curSelect == 11) /* done */ + { + if (isNetworkGame || onePlayerAction) + { + curMenu = 11; + } else { + curMenu = 2; + } + } + else /* change key */ + { + temp2 = 254; + int tempY = 38 + (curSelect - 2) * 12; + JE_textShade(VGAScreen, 236, tempY, SDL_GetKeyName(keySettings[curSelect-2]), (temp2 / 16), (temp2 % 16) - 8, DARKEN); + JE_showVGA(); + + wait_noinput(true, true, true); + + col = 248; + colC = 1; + + do { + setjasondelay(1); + + col += colC; + if (col < 243 || col > 248) + { + colC *= -1; + } + JE_rectangle(VGAScreen, 230, tempY - 2, 300, tempY + 7, col); + + poll_joysticks(); + service_SDL_events(true); + + JE_showVGA(); + + wait_delay(); + } while (!newkey && !mousedown && !joydown); + + if (newkey) + { + // already used? then swap + for (uint i = 0; i < COUNTOF(keySettings); ++i) + { + if (keySettings[i] == lastkey_sym) + { + keySettings[i] = keySettings[curSelect-2]; + break; + } + } + + if (lastkey_sym != SDLK_ESCAPE && // reserved for menu + lastkey_sym != SDLK_F11 && // reserved for gamma + lastkey_sym != SDLK_s && // reserved for sample mute + lastkey_sym != SDLK_m && // reserved for music mute + lastkey_sym != SDLK_p) // reserved for pause + { + JE_playSampleNum(S_CLICK); + keySettings[curSelect-2] = lastkey_sym; + ++curSelect; + } + + JE_wipeKey(); + } + } + break; + + case 6: //save + if (curSelect == 13) + { + if (quikSave) + { + curMenu = oldMenu; + newPal = oldPal; + } else { + curMenu = 2; + } + } else { + if (twoPlayerMode) + { + temp = 11; + } else { + temp = 0; + } + JE_operation(curSelect - 1 + temp); + if (quikSave) + { + curMenu = oldMenu; + newPal = oldPal; + } + } + break; + + case 7: //cubes + if (curSelect == menuChoices[curMenu]) + { + curMenu = 0; + newPal = 1; + } else { + if (cubeMax > 0) + { + firstMenu9 = true; + curMenu = 8; + yLoc = 0; + yChg = 0; + currentCube = curSel[7] - 2; + } else { + curMenu = 0; + newPal = 1; + } + } + break; + + case 8: //cubes 2 + curMenu = 7; + break; + + case 9: //2player + switch (curSel[curMenu]) + { + case 2: + mainLevel = mapSection[mapPNum-1]; + jumpSection = true; + break; + case 3: + case 4: + JE_playSampleNum(S_CURSOR); + { + int temp = curSel[curMenu] - 3; + do { + if (joysticks == 0) + { + inputDevice[temp == 0 ? 1 : 0] = inputDevice[temp]; // swap controllers + } + if (inputDevice[temp] >= 2 + joysticks) + { + inputDevice[temp] = 1; + } else { + inputDevice[temp]++; + } + } while (inputDevice[temp] == inputDevice[temp == 0 ? 1 : 0]); + } + break; + case 5: + curMenu = 2; + break; + case 6: + if (JE_quitRequest()) + { + gameLoaded = true; + mainLevel = 0; + } + break; + } + break; + + case 10: //arcade + switch (curSel[curMenu]) + { + case 2: + mainLevel = mapSection[mapPNum-1]; + jumpSection = true; + break; + case 3: + curMenu = 2; + break; + case 4: + if (JE_quitRequest()) + { + gameLoaded = true; + mainLevel = 0; + } + break; + } + break; + + case 11: //dunno, possibly online multiplayer + switch (select) + { + case 2: + curMenu = 12; + break; + case 3: + curMenu = 5; + break; + case 6: + curMenu = 10; + break; + } + break; + + case 12: //joy + if (joysticks == 0 && select != 17) + break; + + switch (select) + { + case 2: + joystick_config++; + joystick_config %= joysticks; + break; + case 3: + joystick[joystick_config].analog = !joystick[joystick_config].analog; + break; + case 4: + if (joystick[joystick_config].analog) + { + joystick[joystick_config].sensitivity++; + joystick[joystick_config].sensitivity %= 11; + } + break; + case 5: + if (joystick[joystick_config].analog) + { + joystick[joystick_config].threshold++; + joystick[joystick_config].threshold %= 11; + } + break; + case 16: + reset_joystick_assignments(joystick_config); + break; + case 17: + if (isNetworkGame || onePlayerAction) + { + curMenu = 11; + } else { + curMenu = 2; + } + break; + default: + if (joysticks == 0) + break; + + // int temp = 254; + // JE_textShade(VGAScreen, 236, 38 + i * 8, value, temp / 16, temp % 16 - 8, DARKEN); + + JE_rectangle(VGAScreen, 235, 21 + select * 8, 310, 30 + select * 8, 248); + + Joystick_assignment temp; + if (detect_joystick_assignment(joystick_config, &temp)) + { + // if the detected assignment was already set, unset it + for (uint i = 0; i < COUNTOF(*joystick->assignment); i++) + { + if (joystick_assignment_cmp(&temp, &joystick[joystick_config].assignment[select - 6][i])) + { + joystick[joystick_config].assignment[select - 6][i].type = NONE; + goto joystick_assign_done; + } + } + + // if there is an empty assignment, set it + for (uint i = 0; i < COUNTOF(*joystick->assignment); i++) + { + if (joystick[joystick_config].assignment[select - 6][i].type == NONE) + { + joystick[joystick_config].assignment[select - 6][i] = temp; + goto joystick_assign_done; + } + } + + // if no assignments are empty, shift them all forward and set the last one + for (uint i = 0; i < COUNTOF(*joystick->assignment); i++) + { + if (i == COUNTOF(*joystick->assignment) - 1) + joystick[joystick_config].assignment[select - 6][i] = temp; + else + joystick[joystick_config].assignment[select - 6][i] = joystick[joystick_config].assignment[select - 6][i + 1]; + } + +joystick_assign_done: + curSelect++; + + poll_joysticks(); + } + } + break; + + case 13: //engage + switch (curSel[curMenu]) + { + case 2: + mainLevel = mapSection[mapPNum-1]; + jumpSection = true; + break; + case 3: + JE_doShipSpecs(); + break; + case 4: + curMenu = 2; + break; + case 5: + if (JE_quitRequest()) + { + if (isNetworkGame) + { + JE_tyrianHalt(0); + } + gameLoaded = true; + mainLevel = 0; + } + } + break; + } + + old_items[0] = player[0].items; +} + +void JE_drawShipSpecs( SDL_Surface * screen, SDL_Surface * temp_screen ) +{ + /* In this function we create our ship description image. + * + * We use a temp screen for convenience. Bad design maybe (Jason!), + * but it'll be okay (and the alternative is malloc/a large stack) */ + + int temp_x = 0, temp_y = 0, temp_index; + Uint8 *src, *dst; + + + //first, draw the text and other assorted flavoring. + JE_clr256(screen); + JE_drawLines(screen, true); + JE_drawLines(screen, false); + JE_rectangle(screen, 0, 0, 319, 199, 37); + JE_rectangle(screen, 1, 1, 318, 198, 35); + + verticalHeight = 9; + JE_outText(screen, 10, 2, ships[player[0].items.ship].name, 12, 3); + JE_helpBox(screen, 100, 20, shipInfo[player[0].items.ship-1][0], 40); + JE_helpBox(screen, 100, 100, shipInfo[player[0].items.ship-1][1], 40); + verticalHeight = 7; + + JE_outText(screen, JE_fontCenter(miscText[4], TINY_FONT), 190, miscText[4], 12, 2); + + + //now draw the green ship over that. + //This hardcoded stuff is for positioning our little ship graphic + if (player[0].items.ship > 90) + { + temp_index = 32; + } + else if (player[0].items.ship > 0) + { + temp_index = ships[player[0].items.ship].bigshipgraphic; + } + else + { + temp_index = ships[old_items[0].ship].bigshipgraphic; + } + + switch (temp_index) + { + case 32: + temp_x = 35; + temp_y = 33; + break; + case 28: + temp_x = 31; + temp_y = 36; + break; + case 33: + temp_x = 31; + temp_y = 35; + break; + default: + assert(0); + } + temp_x -= 30; + + + //draw the ship into our temp buffer. + JE_clr256(temp_screen); + blit_sprite(temp_screen, temp_x, temp_y, OPTION_SHAPES, temp_index - 1); // ship illustration + + /* But wait! Our ship is fully colored, not green! + * With a little work we could get the sprite dimensions and greenify + * the area it resides in. For now, let's just greenify the (almost + * entirely) black screen. + + * We can't work in place. In fact we'll need to overlay the result + * To avoid our temp screen dependence this has been rewritten to + * only write one line at a time.*/ + dst = (Uint8 *)screen->pixels; + src = (Uint8 *)temp_screen->pixels; + for (int y = 0; y < screen->h; y++) + { + for (int x = 0; x < screen->pitch; x++) + { + int avg = 0; + if (y > 0) + avg += *(src - screen->pitch) & 0x0f; + if (y < screen->h - 1) + avg += *(src + screen->pitch) & 0x0f; + if (x > 0) + avg += *(src - 1) & 0x0f; + if (x < screen->pitch - 1) + avg += *(src + 1) & 0x0f; + avg /= 4; + + if ((*src & 0x0f) > avg) + { + *dst = (*src & 0x0f) | 0xc0; + //} else { + // *dst = 0; + } + + src++; + dst++; + } + } +} + +void JE_weaponSimUpdate( void ) +{ + char buf[32]; + + JE_weaponViewFrame(); + + if ( (curSel[1] == 3 && curSel[4] < menuChoices[4]) || (curSel[1] == 4 && curSel[4] < menuChoices[4] - 1) ) + { + if (leftPower) + { + sprintf(buf, "%d", downgradeCost); + JE_outText(VGAScreen, 26, 137, buf, 1, 4); + } + else + { + blit_sprite(VGAScreenSeg, 24, 149, OPTION_SHAPES, 13); // downgrade disabled + } + + if (rightPower) + { + if (!rightPowerAfford) + { + sprintf(buf, "%d", upgradeCost); + JE_outText(VGAScreen, 108, 137, buf, 7, 4); + blit_sprite(VGAScreenSeg, 119, 149, OPTION_SHAPES, 14); // upgrade disabled + } + else + { + sprintf(buf, "%d", upgradeCost); + JE_outText(VGAScreen, 108, 137, buf, 1, 4); + } + } + else + { + blit_sprite(VGAScreenSeg, 119, 149, OPTION_SHAPES, 14); // upgrade disabled + } + + temp = player[0].items.weapon[curSel[1]-3].power; + + for (int x = 1; x <= temp; x++) + { + fill_rectangle_xy(VGAScreen, 39 + x * 6, 151, 39 + x * 6 + 4, 151, 251); + JE_pix(VGAScreen, 39 + x * 6, 151, 252); + fill_rectangle_xy(VGAScreen, 39 + x * 6, 152, 39 + x * 6 + 4, 164, 250); + fill_rectangle_xy(VGAScreen, 39 + x * 6, 165, 39 + x * 6 + 4, 165, 249); + } + + sprintf(buf, "POWER: %d", temp); + JE_outText(VGAScreen, 58, 137, buf, 15, 4); + } + else + { + leftPower = false; + rightPower = false; + blit_sprite(VGAScreenSeg, 20, 146, OPTION_SHAPES, 17); // hide power level interface + } + + JE_drawItem(1, player[0].items.ship, player[0].x - 5, player[0].y - 7); +} + +void JE_weaponViewFrame( void ) +{ + Uint8 *s; /* screen pointer, 8-bit specific */ + int i; + + fill_rectangle_xy(VGAScreen, 8, 8, 143, 182, 0); + + /* JE: (* Port Configuration Display *) + (* drawportconfigbuttons;*/ + + /*===========================STARS==========================*/ + /*DRAWSTARS*/ + + for (i = MAX_STARS; i--;) + { + s = (Uint8 *)VGAScreen->pixels; + + starDat[i].sLoc += starDat[i].sMov + VGAScreen->pitch; + + if (starDat[i].sLoc < 177 * VGAScreen->pitch) + { + if (*(s + starDat[i].sLoc) == 0) + *(s + starDat[i].sLoc) = starDat[i].sC; + if (starDat[i].sC - 4 >= 9 * 16) + { + if (*(s + starDat[i].sLoc + 1) == 0) + *(s + starDat[i].sLoc + 1) = starDat[i].sC - 4; + if (starDat[i].sLoc > 0 && *(s + starDat[i].sLoc - 1) == 0) + *(s + starDat[i].sLoc - 1) = starDat[i].sC - 4; + if (*(s + starDat[i].sLoc + VGAScreen->pitch) == 0) + *(s + starDat[i].sLoc + VGAScreen->pitch) = starDat[i].sC - 4; + if (starDat[i].sLoc >= VGAScreen->pitch && *(s + starDat[i].sLoc - VGAScreen->pitch) == 0) + *(s + starDat[i].sLoc - VGAScreen->pitch) = starDat[i].sC - 4; + } + } + } + + mouseX = player[0].x; + mouseY = player[0].y; + + // create shots in weapon simulator + for (uint i = 0; i < 2; ++i) + { + if (shotRepeat[i] > 0) + { + --shotRepeat[i]; + } + else + { + const uint item = player[0].items.weapon[i].id, + item_power = player[0].items.weapon[i].power - 1, + item_mode = (i == REAR_WEAPON) ? player[0].weapon_mode - 1 : 0; + + JE_initPlayerShot(item, i, player[0].x, player[0].y, mouseX, mouseY, weaponPort[item].op[item_mode][item_power], 1); + } + } + + if (options[player[0].items.sidekick[LEFT_SIDEKICK]].wport > 0) + { + if (shotRepeat[SHOT_LEFT_SIDEKICK] > 0) + { + --shotRepeat[SHOT_LEFT_SIDEKICK]; + } + else + { + const uint item = player[0].items.sidekick[LEFT_SIDEKICK]; + const int x = player[0].sidekick[LEFT_SIDEKICK].x, + y = player[0].sidekick[LEFT_SIDEKICK].y; + + JE_initPlayerShot(options[item].wport, SHOT_LEFT_SIDEKICK, x, y, mouseX, mouseY, options[item].wpnum, 1); + } + } + + if (options[player[0].items.sidekick[RIGHT_SIDEKICK]].tr == 2) + { + player[0].sidekick[RIGHT_SIDEKICK].x = player[0].x; + player[0].sidekick[RIGHT_SIDEKICK].y = MAX(10, player[0].y - 20); + } + else + { + player[0].sidekick[RIGHT_SIDEKICK].x = 72 + 15; + player[0].sidekick[RIGHT_SIDEKICK].y = 120; + } + + if (options[player[0].items.sidekick[RIGHT_SIDEKICK]].wport > 0) + { + if (shotRepeat[SHOT_RIGHT_SIDEKICK] > 0) + { + --shotRepeat[SHOT_RIGHT_SIDEKICK]; + } + else + { + const uint item = player[0].items.sidekick[RIGHT_SIDEKICK]; + const int x = player[0].sidekick[RIGHT_SIDEKICK].x, + y = player[0].sidekick[RIGHT_SIDEKICK].y; + + JE_initPlayerShot(options[item].wport, SHOT_RIGHT_SIDEKICK, x, y, mouseX, mouseY, options[item].wpnum, 1); + } + } + + /* Player Shot Images */ + for (int z = 0; z < MAX_PWEAPON; z++) + { + if (shotAvail[z] != 0) + { + shotAvail[z]--; + if (z != MAX_PWEAPON - 1) + { + playerShotData[z].shotXM += playerShotData[z].shotXC; + + if (playerShotData[z].shotXM <= 100) + playerShotData[z].shotX += playerShotData[z].shotXM; + + playerShotData[z].shotYM += playerShotData[z].shotYC; + playerShotData[z].shotY += playerShotData[z].shotYM; + + if (playerShotData[z].shotYM > 100) + { + playerShotData[z].shotY -= 120; + playerShotData[z].shotY += player[0].delta_y_shot_move; + } + + if (playerShotData[z].shotComplicated != 0) + { + playerShotData[z].shotDevX += playerShotData[z].shotDirX; + playerShotData[z].shotX += playerShotData[z].shotDevX; + + if (abs(playerShotData[z].shotDevX) == playerShotData[z].shotCirSizeX) + playerShotData[z].shotDirX = -playerShotData[z].shotDirX; + + playerShotData[z].shotDevY += playerShotData[z].shotDirY; + playerShotData[z].shotY += playerShotData[z].shotDevY; + + if (abs(playerShotData[z].shotDevY) == playerShotData[z].shotCirSizeY) + playerShotData[z].shotDirY = -playerShotData[z].shotDirY; + /*Double Speed Circle Shots - add a second copy of above loop*/ + } + + int tempShotX = playerShotData[z].shotX; + int tempShotY = playerShotData[z].shotY; + + if (playerShotData[z].shotX < 0 || playerShotData[z].shotX > 140 || + playerShotData[z].shotY < 0 || playerShotData[z].shotY > 170) + { + shotAvail[z] = 0; + goto draw_player_shot_loop_end; + } + +/* if (playerShotData[z].shotTrail != 255) + { + if (playerShotData[z].shotTrail == 98) + { + JE_setupExplosion(playerShotData[z].shotX - playerShotData[z].shotXM, playerShotData[z].shotY - playerShotData[z].shotYM, playerShotData[z].shotTrail); + } else { + JE_setupExplosion(playerShotData[z].shotX, playerShotData[z].shotY, playerShotData[z].shotTrail); + } + }*/ + + tempW = playerShotData[z].shotGr + playerShotData[z].shotAni; + if (++playerShotData[z].shotAni == playerShotData[z].shotAniMax) + playerShotData[z].shotAni = 0; + + if (tempW < 6000) + { + if (tempW > 1000) + tempW = tempW % 1000; + if (tempW > 500) + blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesW2, tempW - 500); + else + blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesC1, tempW); + } + } + +draw_player_shot_loop_end: + ; + } + } + + blit_sprite(VGAScreenSeg, 0, 0, OPTION_SHAPES, 12); // upgrade interface + + + /*========================Power Bar=========================*/ + + power += powerAdd; + if (power > 900) + power = 900; + + temp = power / 10; + + for (temp = 147 - temp; temp <= 146; temp++) + { + temp2 = 113 + (146 - temp) / 9 + 2; + temp3 = (temp + 1) % 6; + if (temp3 == 1) + temp2 += 3; + else if (temp3 != 0) + temp2 += 2; + + JE_pix(VGAScreen, 141, temp, temp2 - 3); + JE_pix(VGAScreen, 142, temp, temp2 - 3); + JE_pix(VGAScreen, 143, temp, temp2 - 2); + JE_pix(VGAScreen, 144, temp, temp2 - 1); + fill_rectangle_xy(VGAScreen, 145, temp, 149, temp, temp2); + + if (temp2 - 3 < 112) + temp2++; + } + + temp = 147 - (power / 10); + temp2 = 113 + (146 - temp) / 9 + 4; + + JE_pix(VGAScreen, 141, temp - 1, temp2 - 1); + JE_pix(VGAScreen, 142, temp - 1, temp2 - 1); + JE_pix(VGAScreen, 143, temp - 1, temp2 - 1); + JE_pix(VGAScreen, 144, temp - 1, temp2 - 1); + + fill_rectangle_xy(VGAScreen, 145, temp-1, 149, temp-1, temp2); + + lastPower = temp; + + //JE_waitFrameCount(); TODO: didn't do anything? +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/game_menu.h b/alienblaster/project/jni/application/opentyrian/src/game_menu.h new file mode 100644 index 000000000..99734d85c --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/game_menu.h @@ -0,0 +1,59 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef GAME_MENU_H +#define GAME_MENU_H + +#include "helptext.h" +#include "opentyr.h" + +typedef JE_byte JE_MenuChoiceType[MAX_MENU]; + +JE_longint JE_cashLeft( void ); +void JE_itemScreen( void ); + +void load_cubes( void ); +bool load_cube( int cube_slot, int cube_index ); + +void JE_drawItem( JE_byte itemType, JE_word itemNum, JE_word x, JE_word y ); +void JE_drawMenuHeader( void ); +void JE_drawMenuChoices( void ); +void JE_updateNavScreen( void ); +void JE_drawNavLines( JE_boolean dark ); +void JE_drawLines( SDL_Surface *surface, JE_boolean dark ); +void JE_drawDots( void ); +void JE_drawPlanet( JE_byte planetNum ); +void draw_ship_illustration( void ); +void JE_scaleBitmap( SDL_Surface *dst, const SDL_Surface *src, int x1, int y1, int x2, int y2 ); +void JE_initWeaponView( void ); +void JE_computeDots( void ); +JE_integer JE_partWay( JE_integer start, JE_integer finish, JE_byte dots, JE_byte dist ); +void JE_doShipSpecs( void ); +void JE_drawMainMenuHelpText( void ); +JE_boolean JE_quitRequest( void ); +void JE_genItemMenu( JE_byte itemnum ); +void JE_scaleInPicture( SDL_Surface *dst, const SDL_Surface *src ); +void JE_drawScore( void ); +void JE_menuFunction( JE_byte select ); +void JE_drawShipSpecs( SDL_Surface *, SDL_Surface * ); +void JE_weaponSimUpdate( void ); +void JE_weaponViewFrame( void ); + +#endif // GAME_MENU_H + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/helptext.cpp b/alienblaster/project/jni/application/opentyrian/src/helptext.cpp new file mode 100644 index 000000000..030e14716 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/helptext.cpp @@ -0,0 +1,383 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "episodes.h" +#include "file.h" +#include "fonthand.h" +#include "helptext.h" +#include "menus.h" +#include "opentyr.h" +#include "video.h" + +#include +#include + + +const JE_byte menuHelp[MAX_MENU][11] = /* [1..maxmenu, 1..11] */ +{ + { 1, 34, 2, 3, 4, 5, 0, 0, 0, 0, 0 }, + { 6, 7, 8, 9, 10, 11, 11, 12, 0, 0, 0 }, + { 13, 14, 15, 15, 16, 17, 12, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 4, 30, 30, 3, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 16, 17, 15, 15, 12, 0, 0, 0, 0, 0, 0 }, + { 31, 31, 31, 31, 32, 12, 0, 0, 0, 0, 0 }, + { 4, 34, 3, 5, 0, 0, 0, 0, 0, 0, 0 } +}; + +JE_byte verticalHeight = 7; +JE_byte helpBoxColor = 12; +JE_byte helpBoxBrightness = 1; +JE_byte helpBoxShadeType = FULL_SHADE; + +char helpTxt[MAX_HELP_MESSAGE][231]; /* [1..maxhelpmessage] of string [230]; */ +char pName[21][16]; /* [1..21] of string [15] */ +char miscText[68][42]; /* [1..68] of string [41] */ +char miscTextB[5][11]; /* [1..5] of string [10] */ +char keyName[8][18]; /* [1..8] of string [17] */ +char menuText[7][21]; /* [1..7] of string [20] */ +char outputs[9][31]; /* [1..9] of string [30] */ +char topicName[6][21]; /* [1..6] of string [20] */ +char mainMenuHelp[34][66]; +char inGameText[6][21]; /* [1..6] of string [20] */ +char detailLevel[6][13]; /* [1..6] of string [12] */ +char gameSpeedText[5][13]; /* [1..5] of string [12] */ +char inputDevices[3][13]; /* [1..3] of string [12] */ +char networkText[4][22]; /* [1..4] of string [20] */ +char difficultyNameB[11][21]; /* [0..9] of string [20] */ +char joyButtonNames[5][21]; /* [1..5] of string [20] */ +char superShips[11][26]; /* [0..10] of string [25] */ +char specialName[9][10]; /* [1..9] of string [9] */ +char destructHelp[25][22]; +char weaponNames[17][17]; /* [1..17] of string [16] */ +char destructModeName[DESTRUCT_MODES][13]; /* [1..destructmodes] of string [12] */ +char shipInfo[13][2][256]; +char menuInt[MAX_MENU + 1][11][18]; /* [0..maxmenu, 1..11] of string [17] */ + + +void decrypt_pascal_string( char *s, int len ) +{ + static const unsigned char crypt_key[] = { 204, 129, 63, 255, 71, 19, 25, 62, 1, 99 }; + + for (int i = len - 1; i >= 0; --i) + { + s[i] ^= crypt_key[i % sizeof(crypt_key)]; + if (i > 0) + s[i] ^= s[i - 1]; + } +} + +void read_encrypted_pascal_string( char *s, int size, FILE *f ) +{ + int len = getc(f); + if (len != EOF) + { + int skip = MAX((len + 1) - size, 0); + assert(skip == 0); + + len -= skip; + efread(s, 1, len, f); + if (size > 0) + s[len] = '\0'; + fseek(f, skip, SEEK_CUR); + + decrypt_pascal_string(s, len); + } +} + +void skip_pascal_string( FILE *f ) +{ + int len = getc(f); + fseek(f, len, SEEK_CUR); +} + +void JE_helpBox( SDL_Surface *screen, int x, int y, const char *message, unsigned int boxwidth ) +{ + JE_byte startpos, endpos, pos; + JE_boolean endstring; + + char substring[256]; + + if (strlen(message) == 0) + { + return; + } + + pos = 1; + endpos = 0; + endstring = false; + + do + { + startpos = endpos + 1; + + do + { + endpos = pos; + do + { + pos++; + if (pos == strlen(message)) + { + endstring = true; + if ((unsigned)(pos - startpos) < boxwidth) + { + endpos = pos + 1; + } + } + + } while (!(message[pos-1] == ' ' || endstring)); + + } while (!((unsigned)(pos - startpos) > boxwidth || endstring)); + + JE_textShade(screen, x, y, strnztcpy(substring, message + startpos - 1, endpos - startpos), helpBoxColor, helpBoxBrightness, helpBoxShadeType); + + y += verticalHeight; + + } while (!endstring); + + if (endpos != pos + 1) + { + JE_textShade(screen, x, y, message + endpos, helpBoxColor, helpBoxBrightness, helpBoxShadeType); + } + + helpBoxColor = 12; + helpBoxShadeType = FULL_SHADE; +} + +void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int messagenum, unsigned int boxwidth ) +{ + JE_helpBox(screen, x, y, helpTxt[messagenum-1], boxwidth); +} + +void JE_loadHelpText( void ) +{ + FILE *f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb"); + efread(&episode1DataLoc, sizeof(JE_longint), 1, f); + + /*Online Help*/ + skip_pascal_string(f); + for (int i = 0; i < MAX_HELP_MESSAGE; ++i) + read_encrypted_pascal_string(helpTxt[i], sizeof(helpTxt[i]), f); + skip_pascal_string(f); + + /*Planet names*/ + skip_pascal_string(f); + for (int i = 0; i < 21; ++i) + read_encrypted_pascal_string(pName[i], sizeof(pName[i]), f); + skip_pascal_string(f); + + /*Miscellaneous text*/ + skip_pascal_string(f); + for (int i = 0; i < 68; ++i) + read_encrypted_pascal_string(miscText[i], sizeof(miscText[i]), f); + skip_pascal_string(f); + + /*Little Miscellaneous text*/ + skip_pascal_string(f); + for (int i = 0; i < 5; ++i) + read_encrypted_pascal_string(miscTextB[i], sizeof(miscTextB[i]), f); + skip_pascal_string(f); + + /*Key names*/ + skip_pascal_string(f); + for (int i = 0; i < 11; ++i) + read_encrypted_pascal_string(menuInt[6][i], sizeof(menuInt[6][i]), f); + skip_pascal_string(f); + + /*Main Menu*/ + skip_pascal_string(f); + for (int i = 0; i < 7; ++i) + read_encrypted_pascal_string(menuText[i], sizeof(menuText[i]), f); + skip_pascal_string(f); + + /*Event text*/ + skip_pascal_string(f); + for (int i = 0; i < 9; ++i) + read_encrypted_pascal_string(outputs[i], sizeof(outputs[i]), f); + skip_pascal_string(f); + + /*Help topics*/ + skip_pascal_string(f); + for (int i = 0; i < 6; ++i) + read_encrypted_pascal_string(topicName[i], sizeof(topicName[i]), f); + skip_pascal_string(f); + + /*Main Menu Help*/ + skip_pascal_string(f); + for (int i = 0; i < 34; ++i) + read_encrypted_pascal_string(mainMenuHelp[i], sizeof(mainMenuHelp[i]), f); + skip_pascal_string(f); + + /*Menu 1 - Main*/ + skip_pascal_string(f); + for (int i = 0; i < 7; ++i) + read_encrypted_pascal_string(menuInt[1][i], sizeof(menuInt[1][i]), f); + skip_pascal_string(f); + + /*Menu 2 - Items*/ + skip_pascal_string(f); + for (int i = 0; i < 9; ++i) + read_encrypted_pascal_string(menuInt[2][i], sizeof(menuInt[2][i]), f); + skip_pascal_string(f); + + /*Menu 3 - Options*/ + skip_pascal_string(f); + for (int i = 0; i < 8; ++i) + read_encrypted_pascal_string(menuInt[3][i], sizeof(menuInt[3][i]), f); + skip_pascal_string(f); + + /*InGame Menu*/ + skip_pascal_string(f); + for (int i = 0; i < 6; ++i) + read_encrypted_pascal_string(inGameText[i], sizeof(inGameText[i]), f); + skip_pascal_string(f); + + /*Detail Level*/ + skip_pascal_string(f); + for (int i = 0; i < 6; ++i) + read_encrypted_pascal_string(detailLevel[i], sizeof(detailLevel[i]), f); + skip_pascal_string(f); + + /*Game speed text*/ + skip_pascal_string(f); + for (int i = 0; i < 5; ++i) + read_encrypted_pascal_string(gameSpeedText[i], sizeof(gameSpeedText[i]), f); + skip_pascal_string(f); + + // episode names + skip_pascal_string(f); + for (int i = 0; i <= 5; ++i) + read_encrypted_pascal_string(episode_name[i], sizeof(episode_name[i]), f); + skip_pascal_string(f); + + // difficulty names + skip_pascal_string(f); + for (int i = 0; i <= 6; ++i) + read_encrypted_pascal_string(difficulty_name[i], sizeof(difficulty_name[i]), f); + skip_pascal_string(f); + + // gameplay mode names + skip_pascal_string(f); + for (int i = 0; i <= 4; ++i) + read_encrypted_pascal_string(gameplay_name[i], sizeof(gameplay_name[i]), f); + skip_pascal_string(f); + + /*Menu 10 - 2Player Main*/ + skip_pascal_string(f); + for (int i = 0; i < 6; ++i) + read_encrypted_pascal_string(menuInt[10][i], sizeof(menuInt[10][i]), f); + skip_pascal_string(f); + + /*Input Devices*/ + skip_pascal_string(f); + for (int i = 0; i < 3; ++i) + read_encrypted_pascal_string(inputDevices[i], sizeof(inputDevices[i]), f); + skip_pascal_string(f); + + /*Network text*/ + skip_pascal_string(f); + for (int i = 0; i < 4; ++i) + read_encrypted_pascal_string(networkText[i], sizeof(networkText[i]), f); + skip_pascal_string(f); + + /*Menu 11 - 2Player Network*/ + skip_pascal_string(f); + for (int i = 0; i < 4; ++i) + read_encrypted_pascal_string(menuInt[11][i], sizeof(menuInt[11][i]), f); + skip_pascal_string(f); + + /*HighScore Difficulty Names*/ + skip_pascal_string(f); + for (int i = 0; i <= 10; ++i) + read_encrypted_pascal_string(difficultyNameB[i], sizeof(difficultyNameB[i]), f); + skip_pascal_string(f); + + /*Menu 12 - Network Options*/ + skip_pascal_string(f); + for (int i = 0; i < 6; ++i) + read_encrypted_pascal_string(menuInt[12][i], sizeof(menuInt[12][i]), f); + skip_pascal_string(f); + + /*Menu 13 - Joystick*/ + skip_pascal_string(f); + for (int i = 0; i < 7; ++i) + read_encrypted_pascal_string(menuInt[13][i], sizeof(menuInt[13][i]), f); + skip_pascal_string(f); + + /*Joystick Button Assignments*/ + skip_pascal_string(f); + for (int i = 0; i < 5; ++i) + read_encrypted_pascal_string(joyButtonNames[i], sizeof(joyButtonNames[i]), f); + skip_pascal_string(f); + + /*SuperShips - For Super Arcade Mode*/ + skip_pascal_string(f); + for (int i = 0; i <= 10; ++i) + read_encrypted_pascal_string(superShips[i], sizeof(superShips[i]), f); + skip_pascal_string(f); + + /*SuperShips - For Super Arcade Mode*/ + skip_pascal_string(f); + for (int i = 0; i < 9; ++i) + read_encrypted_pascal_string(specialName[i], sizeof(specialName[i]), f); + skip_pascal_string(f); + + /*Secret DESTRUCT game*/ + skip_pascal_string(f); + for (int i = 0; i < 25; ++i) + read_encrypted_pascal_string(destructHelp[i], sizeof(destructHelp[i]), f); + skip_pascal_string(f); + + /*Secret DESTRUCT weapons*/ + skip_pascal_string(f); + for (int i = 0; i < 17; ++i) + read_encrypted_pascal_string(weaponNames[i], sizeof(weaponNames[i]), f); + skip_pascal_string(f); + + /*Secret DESTRUCT modes*/ + skip_pascal_string(f); + for (int i = 0; i < DESTRUCT_MODES; ++i) + read_encrypted_pascal_string(destructModeName[i], sizeof(destructModeName[i]), f); + skip_pascal_string(f); + + /*NEW: Ship Info*/ + skip_pascal_string(f); + for (int i = 0; i < 13; ++i) + { + read_encrypted_pascal_string(shipInfo[i][0], sizeof(shipInfo[i][0]), f); + read_encrypted_pascal_string(shipInfo[i][1], sizeof(shipInfo[i][1]), f); + } + skip_pascal_string(f); + + /*Menu 12 - Network Options*/ + skip_pascal_string(f); + for (int i = 0; i < 5; ++i) + read_encrypted_pascal_string(menuInt[14][i], sizeof(menuInt[14][i]), f); + + fclose(f); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/helptext.h b/alienblaster/project/jni/application/opentyrian/src/helptext.h new file mode 100644 index 000000000..8da69119b --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/helptext.h @@ -0,0 +1,66 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef HELPTEXT_H +#define HELPTEXT_H + +#include "opentyr.h" + + +#define MAX_HELP_MESSAGE 39 +#define MAX_MENU 14 + +#define DESTRUCT_MODES 5 + +extern JE_byte verticalHeight; +extern JE_byte helpBoxColor, helpBoxBrightness, helpBoxShadeType; +extern char helpTxt[MAX_HELP_MESSAGE][231]; +extern char pName[21][16]; /* [1..21] of string [15] */ +extern char miscText[68][42]; /* [1..68] of string [41] */ +extern char miscTextB[5][11]; /* [1..5] of string [10] */ +extern char keyName[8][18]; /* [1..8] of string [17] */ +extern char menuText[7][21]; /* [1..7] of string [20] */ +extern char outputs[9][31]; /* [1..9] of string [30] */ +extern char topicName[6][21]; /* [1..6] of string [20] */ +extern char mainMenuHelp[34][66]; +extern char inGameText[6][21]; /* [1..6] of string [20] */ +extern char detailLevel[6][13]; /* [1..6] of string [12] */ +extern char gameSpeedText[5][13]; /* [1..5] of string [12] */ +extern char inputDevices[3][13]; /* [1..3] of string [12] */ +extern char networkText[4][22]; /* [1..4] of string [20] */ +extern char difficultyNameB[11][21]; /* [0..9] of string [20] */ +extern char joyButtonNames[5][21]; /* [1..5] of string [20] */ +extern char superShips[11][26]; /* [0..10] of string [25] */ +extern char specialName[9][10]; /* [1..9] of string [9] */ +extern char destructHelp[25][22]; +extern char weaponNames[17][17]; /* [1..17] of string [16] */ +extern char destructModeName[DESTRUCT_MODES][13]; /* [1..destructmodes] of string [12] */ +extern char shipInfo[13][2][256]; +extern char menuInt[MAX_MENU+1][11][18]; /* [0..maxmenu, 1..11] of string [17] */ +extern const JE_byte menuHelp[MAX_MENU][11]; /* [1..maxmenu, 1..11] */ + +void read_encrypted_pascal_string( char *s, int size, FILE *f ); +void skip_pascal_string( FILE *f ); + +void JE_helpBox( SDL_Surface *screen, int x, int y, const char *message, unsigned int boxwidth ); +void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int messagenum, unsigned int boxwidth ); +void JE_loadHelpText( void ); + +#endif /* HELPTEXT_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/hg_revision.h b/alienblaster/project/jni/application/opentyrian/src/hg_revision.h new file mode 100644 index 000000000..b723bbd3a --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/hg_revision.h @@ -0,0 +1,8 @@ +#ifndef HG_REVISION_H +#define HG_REVISION_H + +#ifndef HG_REV +#define HG_REV "8e4c1be1b53f default" +#endif + +#endif // HG_REVISION_H diff --git a/alienblaster/project/jni/application/opentyrian/src/joystick.cpp b/alienblaster/project/jni/application/opentyrian/src/joystick.cpp new file mode 100644 index 000000000..37c9f1f9c --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/joystick.cpp @@ -0,0 +1,659 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "cJSON.h" +#include "config.h" +#include "file.h" +#include "joystick.h" +#include "keyboard.h" +#include "nortsong.h" +#include "opentyr.h" +#include "params.h" +#include "varz.h" +#include "video.h" + +#include + +int joystick_axis_threshold( int j, int value ); +int check_assigned( SDL_Joystick *joystick_handle, const Joystick_assignment assignment[2] ); + +const char *assignment_to_code( const Joystick_assignment *assignment ); +void code_to_assignment( Joystick_assignment *assignment, const char *buffer ); + +int joystick_repeat_delay = 300; // milliseconds, repeat delay for buttons +bool joydown = false; // any joystick buttons down, updated by poll_joysticks() +bool ignore_joystick = false; + +int joysticks = 0; +Joystick *joystick = NULL; + +static const char joystick_cfg_version = 1; +static const int joystick_analog_max = 32767; + +// eliminates axis movement below the threshold +int joystick_axis_threshold( int j, int value ) +{ + assert(j < joysticks); + + bool negative = value < 0; + if (negative) + value = -value; + + if (value <= joystick[j].threshold * 1000) + return 0; + + value -= joystick[j].threshold * 1000; + + return negative ? -value : value; +} + +// converts joystick axis to sane Tyrian-usable value (based on sensitivity) +int joystick_axis_reduce( int j, int value ) +{ + assert(j < joysticks); + + value = joystick_axis_threshold(j, value); + + if (value == 0) + return 0; + + return value / (3000 - 200 * joystick[j].sensitivity); +} + +// converts analog joystick axes to an angle +// returns false if axes are centered (there is no angle) +bool joystick_analog_angle( int j, float *angle ) +{ + assert(j < joysticks); + + float x = joystick_axis_threshold(j, joystick[j].x), y = joystick_axis_threshold(j, joystick[j].y); + + if (x != 0) + { + *angle += atanf(-y / x); + *angle += (x < 0) ? -M_PI_2 : M_PI_2; + return true; + } + else if (y != 0) + { + *angle += y < 0 ? M_PI : 0; + return true; + } + + return false; +} + +/* gives back value 0..joystick_analog_max indicating that one of the assigned + * buttons has been pressed or that one of the assigned axes/hats has been moved + * in the assigned direction + */ +int check_assigned( SDL_Joystick *joystick_handle, const Joystick_assignment assignment[2] ) +{ + int result = 0; + + for (int i = 0; i < 2; i++) + { + int temp = 0; + + switch (assignment[i].type) + { + case NONE: + continue; + + case AXIS: + temp = SDL_JoystickGetAxis(joystick_handle, assignment[i].num); + + if (assignment[i].negative_axis) + temp = -temp; + break; + + case BUTTON: + temp = SDL_JoystickGetButton(joystick_handle, assignment[i].num) == 1 ? joystick_analog_max : 0; + break; + + case HAT: + temp = SDL_JoystickGetHat(joystick_handle, assignment[i].num); + + if (assignment[i].x_axis) + temp &= SDL_HAT_LEFT | SDL_HAT_RIGHT; + else + temp &= SDL_HAT_UP | SDL_HAT_DOWN; + + if (assignment[i].negative_axis) + temp &= SDL_HAT_LEFT | SDL_HAT_UP; + else + temp &= SDL_HAT_RIGHT | SDL_HAT_DOWN; + + temp = temp ? joystick_analog_max : 0; + break; + } + + if (temp > result) + result = temp; + } + + return result; +} + +// updates joystick state +void poll_joystick( int j ) +{ + assert(j < joysticks); + + if (joystick[j].handle == NULL) + return; + + SDL_JoystickUpdate(); + + // indicates that a direction/action was pressed since last poll + joystick[j].input_pressed = false; + + // indicates that an direction/action has been held long enough to fake a repeat press + bool repeat = joystick[j].joystick_delay < SDL_GetTicks(); + + // update direction state + for (uint d = 0; d < COUNTOF(joystick[j].direction); d++) + { + bool old = joystick[j].direction[d]; + + joystick[j].analog_direction[d] = check_assigned(joystick[j].handle, joystick[j].assignment[d]); + joystick[j].direction[d] = joystick[j].analog_direction[d] > (joystick_analog_max / 2); + joydown |= joystick[j].direction[d]; + + joystick[j].direction_pressed[d] = joystick[j].direction[d] && (!old || repeat); + joystick[j].input_pressed |= joystick[j].direction_pressed[d]; + } + + joystick[j].x = -joystick[j].analog_direction[3] + joystick[j].analog_direction[1]; + joystick[j].y = -joystick[j].analog_direction[0] + joystick[j].analog_direction[2]; + + // update action state + for (uint d = 0; d < COUNTOF(joystick[j].action); d++) + { + bool old = joystick[j].action[d]; + + joystick[j].action[d] = check_assigned(joystick[j].handle, joystick[j].assignment[d + COUNTOF(joystick[j].direction)]); + joydown |= joystick[j].action[d]; + + joystick[j].action_pressed[d] = joystick[j].action[d] && (!old || repeat); + joystick[j].input_pressed |= joystick[j].action_pressed[d]; + } + + joystick[j].confirm = joystick[j].action[0] || joystick[j].action[4]; + joystick[j].cancel = joystick[j].action[1] || joystick[j].action[5]; + + // if new input, reset press-repeat delay + if (joystick[j].input_pressed) + joystick[j].joystick_delay = SDL_GetTicks() + joystick_repeat_delay; +} + +// updates all joystick states +void poll_joysticks( void ) +{ + joydown = false; + + for (int j = 0; j < joysticks; j++) + poll_joystick(j); +} + +// sends SDL KEYDOWN and KEYUP events for a key +void push_key( SDLKey key ) +{ + SDL_Event e; + + memset(&e.key.keysym, 0, sizeof(e.key.keysym)); + + e.key.keysym.sym = key; + e.key.keysym.unicode = key; + + e.key.state = SDL_RELEASED; + + e.type = SDL_KEYDOWN; + SDL_PushEvent(&e); + + e.type = SDL_KEYUP; + SDL_PushEvent(&e); +} + +// helps us be lazy by pretending joysticks are a keyboard (useful for menus) +void push_joysticks_as_keyboard( void ) +{ + const SDLKey confirm = SDLK_RETURN, cancel = SDLK_ESCAPE; + const SDLKey direction[4] = { SDLK_UP, SDLK_RIGHT, SDLK_DOWN, SDLK_LEFT }; + + poll_joysticks(); + + for (int j = 0; j < joysticks; j++) + { + if (!joystick[j].input_pressed) + continue; + + if (joystick[j].confirm) + push_key(confirm); + if (joystick[j].cancel) + push_key(cancel); + + for (uint d = 0; d < COUNTOF(joystick[j].direction_pressed); d++) + { + if (joystick[j].direction_pressed[d]) + push_key(direction[d]); + } + } +} + +// initializes SDL joystick system and loads assignments for joysticks found +void init_joysticks( void ) +{ + if (ignore_joystick) + return; + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK)) + { + fprintf(stderr, "warning: failed to initialize joystick system: %s\n", SDL_GetError()); + ignore_joystick = true; + return; + } + + SDL_JoystickEventState(SDL_IGNORE); + + joysticks = SDL_NumJoysticks(); + joystick = (Joystick *)malloc(joysticks * sizeof(*joystick)); + + for (int j = 0; j < joysticks; j++) + { + memset(&joystick[j], 0, sizeof(*joystick)); + + joystick[j].handle = SDL_JoystickOpen(j); + if (joystick[j].handle != NULL) + { + printf("joystick detected: %s ", SDL_JoystickName(j)); + printf("(%d axes, %d buttons, %d hats)\n", + SDL_JoystickNumAxes(joystick[j].handle), + SDL_JoystickNumButtons(joystick[j].handle), + SDL_JoystickNumHats(joystick[j].handle)); + + if (!load_joystick_assignments(j)) + reset_joystick_assignments(j); + } + } + + if (joysticks == 0) + printf("no joysticks detected\n"); +} + +// deinitializes SDL joystick system and saves joystick assignments +void deinit_joysticks( void ) +{ + if (ignore_joystick) + return; + + for (int j = 0; j < joysticks; j++) + { + if (joystick[j].handle != NULL) + { + save_joystick_assignments(j); + SDL_JoystickClose(joystick[j].handle); + } + } + + free(joystick); + + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +} + +void reset_joystick_assignments( int j ) +{ + assert(j < joysticks); + + // defaults: first 2 axes, first hat, first 6 buttons + for (uint a = 0; a < COUNTOF(joystick[j].assignment); a++) + { + // clear assignments + for (uint i = 0; i < COUNTOF(joystick[j].assignment[a]); i++) + joystick[j].assignment[a][i].type = NONE; + + if (a < 4) + { + if (SDL_JoystickNumAxes(joystick[j].handle) >= 2) + { + joystick[j].assignment[a][0].type = AXIS; + joystick[j].assignment[a][0].num = (a + 1) % 2; + joystick[j].assignment[a][0].negative_axis = (a == 0 || a == 3); + } + + if (SDL_JoystickNumHats(joystick[j].handle) >= 1) + { + joystick[j].assignment[a][1].type = HAT; + joystick[j].assignment[a][1].num = 0; + joystick[j].assignment[a][1].x_axis = (a == 1 || a == 3); + joystick[j].assignment[a][1].negative_axis = (a == 0 || a == 3); + } + } + else + { + if (a - 4 < (unsigned)SDL_JoystickNumButtons(joystick[j].handle)) + { + joystick[j].assignment[a][0].type = BUTTON; + joystick[j].assignment[a][0].num = a - 4; + } + } + } + + joystick[j].analog = false; + joystick[j].sensitivity = 5; + joystick[j].threshold = 5; +} + +bool load_joystick_assignments( int j ) +{ + cJSON *root = load_json("joystick.conf"); + if (root == NULL) + return false; + + cJSON *config = cJSON_GetObjectItem(root, SDL_JoystickName(j)); + if (config == NULL) + { + cJSON_Delete(root); + return false; + } + + cJSON *setting; + + if ((setting = cJSON_GetObjectItem(config, "analog"))) + joystick[j].analog = (setting->type == cJSON_True); + + if ((setting = cJSON_GetObjectItem(config, "sensitivity"))) + joystick[j].sensitivity = setting->valueint; + + if ((setting = cJSON_GetObjectItem(config, "threshold"))) + joystick[j].threshold = setting->valueint; + + if ((setting = cJSON_GetObjectItem(config, "assignments"))) + { + for (uint i = 0; i < COUNTOF(joystick->assignment); ++i) + { + cJSON *assignments = cJSON_GetArrayItem(setting, i); + if (assignments == NULL) + break; + + for (uint k = 0; k < COUNTOF(*joystick->assignment); ++k) + { + cJSON *assignment = cJSON_GetArrayItem(assignments, k); + if (assignment) + code_to_assignment(&joystick[j].assignment[i][k], assignment->valuestring); + } + } + } + + cJSON_Delete(root); + + return true; +} + +bool save_joystick_assignments( int j ) +{ + cJSON *root = load_json("joystick.conf"); + if (root == NULL) + root = cJSON_CreateObject(); + + cJSON *config = cJSON_CreateOrGetObjectItem(root, SDL_JoystickName(j)); + cJSON_ForceType(config, cJSON_Object); + + cJSON *setting; + + setting = cJSON_CreateOrGetObjectItem(config, "analog"); + cJSON_SetBoolean(setting, joystick[j].analog); + + setting = cJSON_CreateOrGetObjectItem(config, "sensitivity"); + cJSON_SetNumber(setting, joystick[j].sensitivity); + + setting = cJSON_CreateOrGetObjectItem(config, "threshold"); + cJSON_SetNumber(setting, joystick[j].threshold); + + setting = cJSON_CreateOrGetObjectItem(config, "assignments"); + cJSON_ForceType(setting, cJSON_Array); + cJSON_ClearArray(setting); + + for (uint i = 0; i < COUNTOF(joystick->assignment); ++i) + { + cJSON *assignments; + cJSON_AddItemToArray(setting, assignments = cJSON_CreateArray()); + + for (uint k = 0; k < COUNTOF(*joystick->assignment); ++k) + { + if (joystick[j].assignment[i][k].type == NONE) + continue; + + cJSON_AddItemToArray(assignments, cJSON_CreateString(assignment_to_code(&joystick[j].assignment[i][k]))); + } + } + + save_json(root, "joystick.conf"); + + cJSON_Delete(root); + + return true; +} + +// fills buffer with comma separated list of assigned joystick functions +void joystick_assignments_to_string( char *buffer, size_t buffer_len, const Joystick_assignment *assignments ) +{ + strncpy(buffer, "", buffer_len); + + bool comma = false; + for (uint i = 0; i < COUNTOF(*joystick->assignment); ++i) + { + if (assignments[i].type == NONE) + continue; + + size_t len = snprintf(buffer, buffer_len, "%s%s", + comma ? ", " : "", + assignment_to_code(&assignments[i])); + buffer += len; + buffer_len -= len; + + comma = true; + } +} + +// reverse of assignment_to_code() +void code_to_assignment( Joystick_assignment *assignment, const char *buffer ) +{ + memset(assignment, 0, sizeof(*assignment)); + + char axis = 0, direction = 0; + + if (sscanf(buffer, " AX %d%c", &assignment->num, &direction) == 2) + assignment->type = AXIS; + else if (sscanf(buffer, " BTN %d", &assignment->num) == 1) + assignment->type = BUTTON; + else if (sscanf(buffer, " H %d%c%c", &assignment->num, &axis, &direction) == 3) + assignment->type = HAT; + + if (assignment->num == 0) + assignment->type = NONE; + else + --assignment->num; + + assignment->x_axis = (toupper(axis) == 'X'); + assignment->negative_axis = (toupper(direction) == '-'); +} + +/* gives the short (6 or less characters) identifier for a joystick assignment + * + * two of these per direction/action is all that can fit on the joystick config screen, + * assuming two digits for the axis/button/hat number + */ +const char *assignment_to_code( const Joystick_assignment *assignment ) +{ + static char name[7]; + + switch (assignment->type) + { + case NONE: + strcpy(name, ""); + break; + + case AXIS: + snprintf(name, sizeof(name), "AX %d%c", + assignment->num + 1, + assignment->negative_axis ? '-' : '+'); + break; + + case BUTTON: + snprintf(name, sizeof(name), "BTN %d", + assignment->num + 1); + break; + + case HAT: + snprintf(name, sizeof(name), "H %d%c%c", + assignment->num + 1, + assignment->x_axis ? 'X' : 'Y', + assignment->negative_axis ? '-' : '+'); + break; + } + + return name; +} + +// captures joystick input for configuring assignments +// returns false if non-joystick input was detected +// TODO: input from joystick other than the one being configured probably should not be ignored +bool detect_joystick_assignment( int j, Joystick_assignment *assignment ) +{ + // get initial joystick state to compare against to see if anything was pressed + + const int axes = SDL_JoystickNumAxes(joystick[j].handle); + Sint16 *axis = (Sint16 *)malloc(axes * sizeof(*axis)); + for (int i = 0; i < axes; i++) + axis[i] = SDL_JoystickGetAxis(joystick[j].handle, i); + + const int buttons = SDL_JoystickNumButtons(joystick[j].handle); + Uint8 *button = (Uint8 *)malloc(buttons * sizeof(*button)); + for (int i = 0; i < buttons; i++) + button[i] = SDL_JoystickGetButton(joystick[j].handle, i); + + const int hats = SDL_JoystickNumHats(joystick[j].handle); + Uint8 *hat = (Uint8 *)malloc(hats * sizeof(*hat)); + for (int i = 0; i < hats; i++) + hat[i] = SDL_JoystickGetHat(joystick[j].handle, i); + + bool detected = false; + + do + { + setjasondelay(1); + + SDL_JoystickUpdate(); + + for (int i = 0; i < axes; ++i) + { + Sint16 temp = SDL_JoystickGetAxis(joystick[j].handle, i); + + if (abs(temp - axis[i]) > joystick_analog_max * 2 / 3) + { + assignment->type = AXIS; + assignment->num = i; + assignment->negative_axis = temp < axis[i]; + detected = true; + break; + } + } + + for (int i = 0; i < buttons; ++i) + { + Uint8 new_button = SDL_JoystickGetButton(joystick[j].handle, i), + changed = button[i] ^ new_button; + + if (!changed) + continue; + + if (new_button == 0) // button was released + { + button[i] = new_button; + } + else // button was pressed + { + assignment->type = BUTTON; + assignment->num = i; + detected = true; + break; + } + } + + for (int i = 0; i < hats; ++i) + { + Uint8 new_hat = SDL_JoystickGetHat(joystick[j].handle, i), + changed = hat[i] ^ new_hat; + + if (!changed) + continue; + + if ((new_hat & changed) == SDL_HAT_CENTERED) // hat was centered + { + hat[i] = new_hat; + } + else + { + assignment->type = HAT; + assignment->num = i; + assignment->x_axis = changed & (SDL_HAT_LEFT | SDL_HAT_RIGHT); + assignment->negative_axis = changed & (SDL_HAT_LEFT | SDL_HAT_UP); + detected = true; + } + } + + service_SDL_events(true); + JE_showVGA(); + + wait_delay(); + } + while (!detected && !newkey && !newmouse); + + free(axis); + free(button); + free(hat); + + return detected; +} + +// compares relevant parts of joystick assignments for equality +bool joystick_assignment_cmp( const Joystick_assignment *a, const Joystick_assignment *b ) +{ + if (a->type == b->type) + { + switch (a->type) + { + case NONE: + return true; + case AXIS: + return (a->num == b->num) && + (a->negative_axis == b->negative_axis); + case BUTTON: + return (a->num == b->num); + case HAT: + return (a->num == b->num) && + (a->x_axis == b->x_axis) && + (a->negative_axis == b->negative_axis); + } + } + + return false; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/joystick.h b/alienblaster/project/jni/application/opentyrian/src/joystick.h new file mode 100644 index 000000000..e3e9bb92e --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/joystick.h @@ -0,0 +1,98 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef JOYSTICK_H +#define JOYSTICK_H + +#include "opentyr.h" + +#include "SDL.h" + +typedef enum +{ + NONE, + AXIS, + BUTTON, + HAT +} +Joystick_assignment_types; + +typedef struct +{ + Joystick_assignment_types type; + int num; + + // if hat + bool x_axis; // else y_axis + + // if hat or axis + bool negative_axis; // else positive +} +Joystick_assignment; + +typedef struct +{ + SDL_Joystick *handle; + + Joystick_assignment assignment[10][2]; // 0-3: directions, 4-9: actions + + bool analog; + int sensitivity, threshold; + + signed int x, y; + int analog_direction[4]; + bool direction[4], direction_pressed[4]; // up, right, down, left (_pressed, for emulating key presses) + + bool confirm, cancel; + bool action[6], action_pressed[6]; // fire, mode swap, left fire, right fire, menu, pause + + Uint32 joystick_delay; + bool input_pressed; +} +Joystick; + +extern int joystick_repeat_delay; +extern bool joydown; +extern bool ignore_joystick; +extern int joysticks; +extern Joystick *joystick; + +int joystick_axis_reduce( int j, int value ); +bool joystick_analog_angle( int j, float *angle ); + +void poll_joystick( int j ); +void poll_joysticks( void ); + +void push_key( SDLKey key ); +void push_joysticks_as_keyboard( void ); + +void init_joysticks( void ); +void deinit_joysticks( void ); + +void reset_joystick_assignments( int j ); +bool load_joystick_assignments( int j ); +bool save_joystick_assignments( int j ); + +void joystick_assignments_to_string( char *buffer, size_t buffer_len, const Joystick_assignment *assignments ); + +bool detect_joystick_assignment( int j, Joystick_assignment *assignment ); +bool joystick_assignment_cmp( const Joystick_assignment *, const Joystick_assignment * ); + +#endif /* JOYSTICK_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/jukebox.cpp b/alienblaster/project/jni/application/opentyrian/src/jukebox.cpp new file mode 100644 index 000000000..2cc162cbb --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/jukebox.cpp @@ -0,0 +1,201 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "font.h" +#include "joystick.h" +#include "jukebox.h" +#include "keyboard.h" +#include "lds_play.h" +#include "loudness.h" +#include "mtrand.h" +#include "nortsong.h" +#include "opentyr.h" +#include "palette.h" +#include "sprite.h" +#include "starlib.h" +#include "vga_palette.h" +#include "video.h" + +void jukebox( void ) +{ + bool trigger_quit = false, // true when user wants to quit + quitting = false; + + bool hide_text = false; + + bool fade_looped_songs = true, fading_song = false; + bool stopped = false; + + bool fx = false; + int fx_num = 0; + + int palette_fade_steps = 15; + + int diff[256][3]; + init_step_fade_palette(diff, vga_palette, 0, 255); + + JE_starlib_init(); + + int fade_volume = tyrMusicVolume; + + for (; ; ) + { + if (!stopped && !audio_disabled) + { + if (songlooped && fade_looped_songs) + fading_song = true; + + if (fading_song) + { + if (fade_volume > 5) + { + fade_volume -= 2; + } + else + { + fade_volume = tyrMusicVolume; + + fading_song = false; + } + + set_volume(fade_volume, fxVolume); + } + + if (!playing || (songlooped && fade_looped_songs && !fading_song)) + play_song(mt_rand() % MUSIC_NUM); + } + + setdelay(1); + + SDL_FillRect(VGAScreenSeg, NULL, 0); + + // starlib input needs to be rewritten + JE_starlib_main(); + + push_joysticks_as_keyboard(); + service_SDL_events(true); + + if (!hide_text) + { + char buffer[60]; + + if (fx) + snprintf(buffer, sizeof(buffer), "%d %s", fx_num + 1, soundTitle[fx_num]); + else + snprintf(buffer, sizeof(buffer), "%d %s", song_playing + 1, musicTitle[song_playing]); + + const int x = VGAScreen->w / 2; + + draw_font_hv(VGAScreen, x, 170, "Press ESC to quit the jukebox.", small_font, centered, 1, 0); + draw_font_hv(VGAScreen, x, 180, "Arrow keys change the song being played.", small_font, centered, 1, 0); + draw_font_hv(VGAScreen, x, 190, buffer, small_font, centered, 1, 4); + } + + if (palette_fade_steps > 0) + step_fade_palette(diff, palette_fade_steps--, 0, 255); + + JE_showVGA(); + + wait_delay(); + + // quit on mouse click + Uint16 x, y; + if (JE_mousePosition(&x, &y) > 0) + trigger_quit = true; + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_ESCAPE: // quit jukebox + case SDLK_q: + trigger_quit = true; + break; + + case SDLK_SPACE: + hide_text = !hide_text; + break; + + case SDLK_f: + fading_song = !fading_song; + break; + case SDLK_n: + fade_looped_songs = !fade_looped_songs; + break; + + case SDLK_SLASH: // switch to sfx mode + fx = !fx; + break; + case SDLK_COMMA: + if (fx && --fx_num < 0) + fx_num = SAMPLE_COUNT - 1; + break; + case SDLK_PERIOD: + if (fx && ++fx_num >= SAMPLE_COUNT) + fx_num = 0; + break; + case SDLK_SEMICOLON: + if (fx) + JE_playSampleNum(fx_num + 1); + break; + + case SDLK_LEFT: + case SDLK_UP: + play_song((song_playing > 0 ? song_playing : MUSIC_NUM) - 1); + stopped = false; + break; + case SDLK_RETURN: + case SDLK_RIGHT: + case SDLK_DOWN: + play_song((song_playing + 1) % MUSIC_NUM); + stopped = false; + break; + case SDLK_s: // stop song + stop_song(); + stopped = true; + break; + case SDLK_r: // restart song + restart_song(); + stopped = false; + break; + + default: + break; + } + } + + // user wants to quit, start fade-out + if (trigger_quit && !quitting) + { + palette_fade_steps = 15; + + SDL_Color black = { 0, 0, 0 }; + init_step_fade_solid(diff, black, 0, 255); + + quitting = true; + } + + // if fade-out finished, we can finally quit + if (quitting && palette_fade_steps == 0) + break; + } + + set_volume(tyrMusicVolume, fxVolume); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/jukebox.h b/alienblaster/project/jni/application/opentyrian/src/jukebox.h new file mode 100644 index 000000000..b858c5326 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/jukebox.h @@ -0,0 +1,28 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef JUKEBOX_H +#define JUKEBOX_H + +#include "opentyr.h" + +void jukebox( void ); + +#endif /* JUKEBOX_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/keyboard.cpp b/alienblaster/project/jni/application/opentyrian/src/keyboard.cpp new file mode 100644 index 000000000..0a819d8c5 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/keyboard.cpp @@ -0,0 +1,246 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "joystick.h" +#include "keyboard.h" +#include "network.h" +#include "opentyr.h" +#include "video.h" +#include "video_scale.h" + +#include "SDL.h" + + +JE_boolean ESCPressed; + +JE_boolean newkey, newmouse, keydown, mousedown; +SDLKey lastkey_sym; +SDLMod lastkey_mod; +unsigned char lastkey_char; +Uint8 lastmouse_but; +Uint16 lastmouse_x, lastmouse_y; +JE_boolean mouse_pressed[3] = {false, false, false}; +Uint16 mouse_x, mouse_y; + +int numkeys; +Uint8 *keysactive; + +#ifdef NDEBUG +bool input_grab_enabled = true, +#else +bool input_grab_enabled = false, +#endif + input_grabbed = false; + + +void flush_events_buffer( void ) +{ + SDL_Event ev; + + while (SDL_PollEvent(&ev)); +} + +void wait_input( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ) +{ + service_SDL_events(false); + while (!((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown))) + { + SDL_Delay(SDL_POLL_INTERVAL); + push_joysticks_as_keyboard(); + service_SDL_events(false); + + if (isNetworkGame) + network_check(); + } +} + +void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ) +{ + service_SDL_events(false); + while ((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown)) + { + SDL_Delay(SDL_POLL_INTERVAL); + poll_joysticks(); + service_SDL_events(false); + + if (isNetworkGame) + network_check(); + } +} + +void init_keyboard( void ) +{ + keysactive = SDL_GetKeyState(&numkeys); + SDL_EnableKeyRepeat(500, 60); + + newkey = newmouse = false; + keydown = mousedown = false; + + SDL_EnableUNICODE(1); +} + +void input_grab( void ) +{ +#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) || defined(ANDROID) + input_grabbed = true; +#else + input_grabbed = input_grab_enabled || fullscreen_enabled; +#endif + + SDL_ShowCursor(input_grabbed ? SDL_DISABLE : SDL_ENABLE); +#ifdef NDEBUG + SDL_WM_GrabInput(input_grabbed ? SDL_GRAB_ON : SDL_GRAB_OFF); +#endif +} + +JE_word JE_mousePosition( JE_word *mouseX, JE_word *mouseY ) +{ + service_SDL_events(false); + *mouseX = mouse_x; + *mouseY = mouse_y; + return mousedown ? lastmouse_but : 0; +} + +void set_mouse_position( int x, int y ) +{ + if (input_grabbed) + { + SDL_WarpMouse(x * scalers[scaler].width / vga_width, y * scalers[scaler].height / vga_height); + mouse_x = x; + mouse_y = y; + } +} + +void service_SDL_events( JE_boolean clear_new ) +{ + SDL_Event ev; + + if (clear_new) + newkey = newmouse = false; + + while (SDL_PollEvent(&ev)) + { + switch (ev.type) + { + case SDL_MOUSEMOTION: + mouse_x = ev.motion.x * vga_width / scalers[scaler].width; + mouse_y = ev.motion.y * vga_height / scalers[scaler].height; + break; + case SDL_KEYDOWN: + if (ev.key.keysym.mod & KMOD_CTRL) + { + /* emergency kill */ + if (ev.key.keysym.sym == SDLK_BACKSPACE) + { + puts("\n\n\nCtrl+Backspace pressed. Doing emergency quit.\n"); + SDL_Quit(); + exit(1); + } + + /* toggle input grab */ + if (ev.key.keysym.sym == SDLK_F10) + { + input_grab_enabled = !input_grab_enabled; + input_grab(); + break; + } + } + + if (ev.key.keysym.mod & KMOD_ALT) + { + /* toggle fullscreen */ + if (ev.key.keysym.sym == SDLK_RETURN) + { + if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state + !init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state + !init_scaler(scaler, fullscreen_enabled)) // revert on fail + { + exit(EXIT_FAILURE); + } + break; + } + + /* disable input grab and fullscreen */ + if (ev.key.keysym.sym == SDLK_TAB) + { + input_grab_enabled = false; + input_grab(); + + if (!init_scaler(scaler, false) && // try windowed + !init_any_scaler(false) && // try any scaler windowed + !init_scaler(scaler, fullscreen_enabled)) // revert on fail + { + exit(EXIT_FAILURE); + } + break; + } + } + + newkey = true; + lastkey_sym = ev.key.keysym.sym; + lastkey_mod = ev.key.keysym.mod; + lastkey_char = ev.key.keysym.unicode; + keydown = true; + return; + case SDL_KEYUP: + keydown = false; + return; + case SDL_MOUSEBUTTONDOWN: + if (!input_grabbed) + { + input_grab_enabled = !input_grab_enabled; + input_grab(); + break; + } + case SDL_MOUSEBUTTONUP: + if (ev.type == SDL_MOUSEBUTTONDOWN) + { + newmouse = true; + lastmouse_but = ev.button.button; + lastmouse_x = ev.button.x * vga_width / scalers[scaler].width; + lastmouse_y = ev.button.y * vga_height / scalers[scaler].height; + mousedown = true; + } + else + { + mousedown = false; + } + switch (ev.button.button) + { + case SDL_BUTTON_LEFT: + mouse_pressed[0] = mousedown; break; + case SDL_BUTTON_RIGHT: + mouse_pressed[1] = mousedown; break; + case SDL_BUTTON_MIDDLE: + mouse_pressed[2] = mousedown; break; + } + break; + case SDL_QUIT: + /* TODO: Call the cleanup code here. */ + exit(0); + break; + } + } +} + +void JE_clearKeyboard( void ) +{ + // /!\ Doesn't seems important. I think. D: +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/keyboard.h b/alienblaster/project/jni/application/opentyrian/src/keyboard.h new file mode 100644 index 000000000..4cd826f1d --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/keyboard.h @@ -0,0 +1,59 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include "opentyr.h" + +#include "SDL.h" + + +#define SDL_POLL_INTERVAL 5 + +extern JE_boolean ESCPressed; +extern JE_boolean newkey, newmouse, keydown, mousedown; +extern SDLKey lastkey_sym; +extern SDLMod lastkey_mod; +extern unsigned char lastkey_char; +extern Uint8 lastmouse_but; +extern Uint16 lastmouse_x, lastmouse_y; +extern JE_boolean mouse_pressed[3]; +extern Uint16 mouse_x, mouse_y; +extern int numkeys; +extern Uint8 *keysactive; + +extern bool input_grab_enabled, input_grabbed; + +void flush_events_buffer( void ); +void wait_input( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ); +void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ); +void init_keyboard( void ); +void input_grab( void ); +JE_word JE_mousePosition( JE_word *mouseX, JE_word *mouseY ); +void set_mouse_position( int x, int y ); + +void service_SDL_events( JE_boolean clear_new ); + +void sleep_game( void ); + +void JE_clearKeyboard( void ); + +#endif /* KEYBOARD_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/lds_play.cpp b/alienblaster/project/jni/application/opentyrian/src/lds_play.cpp new file mode 100644 index 000000000..91692e25a --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/lds_play.cpp @@ -0,0 +1,768 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "fm_synth.h" +#include "lds_play.h" +#include "loudness.h" +#include "opentyr.h" + +#include + +/* A substantial amount of this code has been copied and adapted from adplug. + Thanks, guys! Adplug is awesome! :D */ + +/* Note frequency table (16 notes / octave) */ +static const Uint16 frequency[(13 * 15) - 3] = { + 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 356, 357, 358, + 359, 361, 362, 363, 365, 366, 367, 369, 370, 371, 373, 374, 375, + 377, 378, 379, 381, 382, 384, 385, 386, 388, 389, 391, 392, 393, + 395, 396, 398, 399, 401, 402, 403, 405, 406, 408, 409, 411, 412, + 414, 415, 417, 418, 420, 421, 423, 424, 426, 427, 429, 430, 432, + 434, 435, 437, 438, 440, 442, 443, 445, 446, 448, 450, 451, 453, + 454, 456, 458, 459, 461, 463, 464, 466, 468, 469, 471, 473, 475, + 476, 478, 480, 481, 483, 485, 487, 488, 490, 492, 494, 496, 497, + 499, 501, 503, 505, 506, 508, 510, 512, 514, 516, 518, 519, 521, + 523, 525, 527, 529, 531, 533, 535, 537, 538, 540, 542, 544, 546, + 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 571, 573, + 575, 577, 579, 581, 583, 585, 587, 589, 591, 594, 596, 598, 600, + 602, 604, 607, 609, 611, 613, 615, 618, 620, 622, 624, 627, 629, + 631, 633, 636, 638, 640, 643, 645, 647, 650, 652, 654, 657, 659, + 662, 664, 666, 669, 671, 674, 676, 678, 681, 683 +}; + +/* Vibrato (sine) table */ +static const Uint8 vibtab[25 + (13 * 3)] = { + 0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162, + 171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247, + 250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236, + 231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131, + 120, 109, 98, 86, 74, 62, 50, 37, 25, 13 +}; + +/* Tremolo (sine * sine) table */ +static const Uint8 tremtab[128] = { + 0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47, + 52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134, + 140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208, + 213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251, + 253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245, + 243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193, + 188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115, + 109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29, + 25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0 +}; + +static const Uint16 maxsound = 0x3f, maxpos = 0xff; + +static SoundBank *soundbank = NULL; +static Channel channel[9]; +static Position *positions = NULL; + +static Uint8 fmchip[0xff], jumping, fadeonoff, allvolume, hardfade, tempo_now, pattplay, tempo, regbd, chandelay[9], mode, pattlen; +static Uint16 posplay, jumppos, speed; +static Uint16 *patterns = NULL; +static Uint16 numpatch, numposi, mainvolume; + +bool playing, songlooped; + +bool lds_load( FILE *f, unsigned int music_offset, unsigned int music_size ) +{ + SoundBank *sb; + + fseek(f, music_offset, SEEK_SET); + + /* load header */ + mode = fgetc(f); + if (mode > 2) + { + fprintf(stderr, "error: failed to load music\n"); + return false; + } + efread(&speed, 2, 1, f); + tempo = fgetc(f); + pattlen = fgetc(f); + for (unsigned int i = 0; i < 9; i++) + chandelay[i] = fgetc(f); + regbd = fgetc(f); + + /* load patches */ + efread(&numpatch, 2, 1, f); + + free(soundbank); + soundbank = (SoundBank *)malloc(sizeof(SoundBank) * numpatch); + + for (unsigned int i = 0; i < numpatch; i++) + { + sb = &soundbank[i]; + sb->mod_misc = fgetc(f); + sb->mod_vol = fgetc(f); + sb->mod_ad = fgetc(f); + sb->mod_sr = fgetc(f); + sb->mod_wave = fgetc(f); + sb->car_misc = fgetc(f); + sb->car_vol = fgetc(f); + sb->car_ad = fgetc(f); + sb->car_sr = fgetc(f); + sb->car_wave = fgetc(f); + sb->feedback = fgetc(f); + sb->keyoff = fgetc(f); + sb->portamento = fgetc(f); + sb->glide = fgetc(f); + sb->finetune = fgetc(f); + sb->vibrato = fgetc(f); + sb->vibdelay = fgetc(f); + sb->mod_trem = fgetc(f); + sb->car_trem = fgetc(f); + sb->tremwait = fgetc(f); + sb->arpeggio = fgetc(f); + for (unsigned int j = 0; j < 12; j++) + sb->arp_tab[j] = fgetc(f); + efread(&sb->start, 2, 1, f); + efread(&sb->size, 2, 1, f); + sb->fms = fgetc(f); + efread(&sb->transp, 2, 1, f); + sb->midinst = fgetc(f); + sb->midvelo = fgetc(f); + sb->midkey = fgetc(f); + sb->midtrans = fgetc(f); + sb->middum1 = fgetc(f); + sb->middum2 = fgetc(f); + } + + /* load positions */ + efread(&numposi, 2, 1, f); + + free(positions); + positions = (Position *)malloc(sizeof(Position) * 9 * numposi); + + for (unsigned int i = 0; i < numposi; i++) + { + for (unsigned int j = 0; j < 9; j++) + { + /* + * patnum is a pointer inside the pattern space, but patterns are 16bit + * word fields anyway, so it ought to be an even number (hopefully) and + * we can just divide it by 2 to get our array index of 16bit words. + */ + Uint16 temp; + efread(&temp, 2, 1, f); + positions[i * 9 + j].patnum = temp / 2; + positions[i * 9 + j].transpose = fgetc(f); + } + } + + /* load patterns */ + fseek(f, 2, SEEK_CUR); /* ignore # of digital sounds (dunno what this is for) */ + + unsigned int remaining = music_size - (ftell(f) - music_offset); + + free(patterns); + patterns = (Uint16 *)malloc(sizeof(Uint16) * (remaining / 2)); + + for (unsigned int i = 0; i < remaining / 2; i++) + efread(&patterns[i], 2, 1, f); + + lds_rewind(); + + return true; +} + +void lds_free( void ) +{ + free(soundbank); + soundbank = NULL; + + free(positions); + positions = NULL; + + free(patterns); + patterns = NULL; +} + +void lds_rewind( void ) +{ + int i; + + /* init all with 0 */ + tempo_now = 3; + playing = true; songlooped = false; + jumping = fadeonoff = allvolume = hardfade = pattplay = posplay = jumppos = mainvolume = 0; + memset(channel, 0, sizeof(channel)); + memset(fmchip, 0, sizeof(fmchip)); + + /* OPL2 init */ + opl_reset(); /* Reset OPL chip */ + opl_write(1, 0x20); + opl_write(8, 0); + opl_write(0xbd, regbd); + + for(i = 0; i < 9; i++) { + opl_write(0x20 + op_table[i], 0); + opl_write(0x23 + op_table[i], 0); + opl_write(0x40 + op_table[i], 0x3f); + opl_write(0x43 + op_table[i], 0x3f); + opl_write(0x60 + op_table[i], 0xff); + opl_write(0x63 + op_table[i], 0xff); + opl_write(0x80 + op_table[i], 0xff); + opl_write(0x83 + op_table[i], 0xff); + opl_write(0xe0 + op_table[i], 0); + opl_write(0xe3 + op_table[i], 0); + opl_write(0xa0 + i, 0); + opl_write(0xb0 + i, 0); + opl_write(0xc0 + i, 0); + } +} + +void lds_setregs(Uint8 reg, Uint8 val) +{ + if(fmchip[reg] == val) return; + + fmchip[reg] = val; + opl_write(reg, val); +} + +void lds_setregs_adv(Uint8 reg, Uint8 mask, Uint8 val) +{ + lds_setregs(reg, (fmchip[reg] & mask) | val); +} + +int lds_update( void ) +{ + Uint16 comword, freq, octave, chan, tune, wibc, tremc, arpreg; + int vbreak; + Uint8 level, regnum, comhi, comlo; + int i; + Channel *c; + + if(!playing) return false; + + /* handle fading */ + if(fadeonoff) + { + if(fadeonoff <= 128) { + if(allvolume > fadeonoff || allvolume == 0) + { + allvolume -= fadeonoff; + } else { + allvolume = 1; + fadeonoff = 0; + if(hardfade != 0) { + playing = false; + hardfade = 0; + for(i = 0; i < 9; i++) + { + channel[i].keycount = 1; + } + } + } + + } else { + if( (Uint8) ((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) + { + allvolume += 0x100 - fadeonoff; + } else { + allvolume = mainvolume; + fadeonoff = 0; + } + } + } + + /* handle channel delay */ + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + if(c->chancheat.chandelay) { + if(!(--c->chancheat.chandelay)) { + lds_playsound(c->chancheat.sound, chan, c->chancheat.high); + } + } + } + + /* handle notes */ + if(!tempo_now && positions) + { + vbreak = false; + for(chan = 0; chan < 9; chan++) + { + c = &channel[chan]; + if(!c->packwait) { + Uint16 patnum = positions[posplay * 9 + chan].patnum; + Uint8 transpose = positions[posplay * 9 + chan].transpose; + /*printf("> %p", positions);*/ + + comword = patterns[patnum + c->packpos]; + comhi = comword >> 8; comlo = comword & 0xff; + if(comword) { + if(comhi == 0x80) + { + c->packwait = comlo; + } else { + if(comhi >= 0x80) + { + switch(comhi) + { + case 0xff: + c->volcar = (((c->volcar & 0x3f) * comlo) >> 6) & 0x3f; + if(fmchip[0xc0 + chan] & 1) + c->volmod = (((c->volmod & 0x3f) * comlo) >> 6) & 0x3f; + break; + + case 0xfe: + tempo = comword & 0x3f; + break; + + case 0xfd: + c->nextvol = comlo; + break; + + case 0xfc: + playing = false; + /* in real player there's also full keyoff here, but we don't need it */ + break; + + case 0xfb: + c->keycount = 1; + break; + + case 0xfa: + vbreak = true; + jumppos = (posplay + 1) & maxpos; + break; + + case 0xf9: + vbreak = true; + jumppos = comlo & maxpos; + jumping = 1; + if(jumppos < posplay) + { + songlooped = true; + } + break; + + case 0xf8: + c->lasttune = 0; + break; + + case 0xf7: + c->vibwait = 0; + /* PASCAL: c->vibspeed = ((comlo >> 4) & 15) + 2; */ + c->vibspeed = (comlo >> 4) + 2; + c->vibrate = (comlo & 15) + 1; + break; + + case 0xf6: + c->glideto = comlo; + break; + + case 0xf5: + c->finetune = comlo; + break; + + case 0xf4: + if(!hardfade) + { + allvolume = mainvolume = comlo; + fadeonoff = 0; + } + break; + + case 0xf3: + if(!hardfade) + { + fadeonoff = comlo; + } + break; + + case 0xf2: + c->trmstay = comlo; + break; + + case 0xf1: /* panorama */ + + case 0xf0: /* progch */ + /* MIDI commands (unhandled) */ + /*AdPlug_LogWrite("CldsPlayer(): not handling MIDI command 0x%x, " + "value = 0x%x\n", comhi);*/ + break; + + default: + if(comhi < 0xa0) + { + c->glideto = comhi & 0x1f; + } else { + /*AdPlug_LogWrite("CldsPlayer(): unknown command 0x%x encountered!" + " value = 0x%x\n", comhi, comlo);*/ + } + break; + } + } else { + Uint8 sound; + Uint16 high; + Sint8 transp = transpose & 127; + /* + * Originally, in assembler code, the player first shifted + * logically left the transpose byte by 1 and then shifted + * arithmetically right the same byte to achieve the final, + * signed transpose value. Since we can't do arithmetic shifts + * in C, we just duplicate the 7th bit into the 8th one and + * discard the 8th one completely. + */ + + if(transpose & 64) + { + transp |= 128; + } + + if(transpose & 128) + { + sound = (comlo + transp) & maxsound; + high = comhi << 4; + } else { + sound = comlo & maxsound; + high = (comhi + transp) << 4; + } + + /* + PASCAL: + sound = comlo & maxsound; + high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; + */ + + if(!chandelay[chan]) { + lds_playsound(sound, chan, high); + } else { + c->chancheat.chandelay = chandelay[chan]; + c->chancheat.sound = sound; + c->chancheat.high = high; + } + } + } + } + + c->packpos++; + } else { + c->packwait--; + } + } + + tempo_now = tempo; + /* + The continue table is updated here, but this is only used in the + original player, which can be paused in the middle of a song and then + unpaused. Since AdPlug does all this for us automatically, we don't + have a continue table here. The continue table update code is noted + here for reference only. + + if(!pattplay) { + conttab[speed & maxcont].position = posplay & 0xff; + conttab[speed & maxcont].tempo = tempo; + } + */ + pattplay++; + if(vbreak) + { + pattplay = 0; + for(i = 0; i < 9; i++) + { + channel[i].packpos = channel[i].packwait = 0; + } + posplay = jumppos; + } else { + if(pattplay >= pattlen) { + pattplay = 0; + for(i = 0; i < 9; i++) + { + channel[i].packpos = channel[i].packwait = 0; + } + posplay = (posplay + 1) & maxpos; + } + } + } else { + tempo_now--; + } + + /* make effects */ + for(chan = 0; chan < 9; chan++) { + c = &channel[chan]; + regnum = op_table[chan]; + if(c->keycount > 0) { + if(c->keycount == 1) + lds_setregs_adv(0xb0 + chan, 0xdf, 0); + c->keycount--; + } + + /* arpeggio */ + if(c->arp_size == 0) + arpreg = 0; + else { + arpreg = c->arp_tab[c->arp_pos] << 4; + if(arpreg == 0x800) { + if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; + c->arp_size = 1; c->arp_pos = 0; + arpreg = c->arp_tab[0] << 4; + } + + if(c->arp_count == c->arp_speed) { + c->arp_pos++; + if(c->arp_pos >= c->arp_size) c->arp_pos = 0; + c->arp_count = 0; + } else + c->arp_count++; + } + + /* glide & portamento */ + if(c->lasttune && (c->lasttune != c->gototune)) { + if(c->lasttune > c->gototune) { + if(c->lasttune - c->gototune < c->portspeed) + c->lasttune = c->gototune; + else + c->lasttune -= c->portspeed; + } else { + if(c->gototune - c->lasttune < c->portspeed) + c->lasttune = c->gototune; + else + c->lasttune += c->portspeed; + } + + if(arpreg >= 0x800) + arpreg = c->lasttune - (arpreg ^ 0xff0) - 16; + else + arpreg += c->lasttune; + + freq = frequency[arpreg % (12 * 16)]; + octave = arpreg / (12 * 16) - 1; + lds_setregs(0xa0 + chan, freq & 0xff); + lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } else { + /* vibrato */ + if(!c->vibwait) { + if(c->vibrate) { + wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; + + if((c->vibcount & 0x40) == 0) + tune = c->lasttune + (wibc >> 8); + else + tune = c->lasttune - (wibc >> 8); + + if(arpreg >= 0x800) + tune = tune - (arpreg ^ 0xff0) - 16; + else + tune += arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + lds_setregs(0xa0 + chan, freq & 0xff); + lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + c->vibcount += c->vibspeed; + } else if(c->arp_size != 0) { /* no vibrato, just arpeggio */ + if(arpreg >= 0x800) + tune = c->lasttune - (arpreg ^ 0xff0) - 16; + else + tune = c->lasttune + arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + lds_setregs(0xa0 + chan, freq & 0xff); + lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } + } else { /* no vibrato, just arpeggio */ + c->vibwait--; + + if(c->arp_size != 0) { + if(arpreg >= 0x800) + tune = c->lasttune - (arpreg ^ 0xff0) - 16; + else + tune = c->lasttune + arpreg; + + freq = frequency[tune % (12 * 16)]; + octave = tune / (12 * 16) - 1; + lds_setregs(0xa0 + chan, freq & 0xff); + lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf); + } + } + } + + /* tremolo (modulator) */ + if(!c->trmwait) { + if(c->trmrate) { + tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; + if((tremc >> 8) <= (c->volmod & 0x3f)) + level = (c->volmod & 0x3f) - (tremc >> 8); + else + level = 0; + + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + lds_setregs_adv(0x40 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); + else + lds_setregs_adv(0x40 + regnum, 0xc0, level ^ 0x3f); + + c->trmcount += c->trmspeed; + } else if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + lds_setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + else + lds_setregs_adv(0x40 + regnum, 0xc0, (c->volmod ^ 0x3f) & 0x3f); + } else { + c->trmwait--; + if(allvolume != 0 && (fmchip[0xc0 + chan] & 1)) + lds_setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + } + + /* tremolo (carrier) */ + if(!c->trcwait) { + if(c->trcrate) { + tremc = tremtab[c->trccount & 0x7f] * c->trcrate; + if((tremc >> 8) <= (c->volcar & 0x3f)) + level = (c->volcar & 0x3f) - (tremc >> 8); + else + level = 0; + + if(allvolume != 0) + lds_setregs_adv(0x43 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f); + else + lds_setregs_adv(0x43 + regnum, 0xc0, level ^ 0x3f); + c->trccount += c->trcspeed; + } else if(allvolume != 0) + lds_setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + else + lds_setregs_adv(0x43 + regnum, 0xc0, (c->volcar ^ 0x3f) & 0x3f); + } else { + c->trcwait--; + if(allvolume != 0) + lds_setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f); + } + } + + return (!playing || songlooped) ? false : true; +} + +void lds_playsound(int inst_number, int channel_number, int tunehigh) +{ + Channel *c = &channel[channel_number]; /* current channel */ + SoundBank *i = &soundbank[inst_number]; /* current instrument */ + Uint32 regnum = op_table[channel_number]; /* channel's OPL2 register */ + Uint8 volcalc, octave; + Uint16 freq; + + /* set fine tune */ + tunehigh += ((i->finetune + c->finetune + 0x80) & 0xff) - 0x80; + + /* arpeggio handling */ + if(!i->arpeggio) { + Uint16 arpcalc = i->arp_tab[0] << 4; + + if(arpcalc > 0x800) + tunehigh = tunehigh - (arpcalc ^ 0xff0) - 16; + else + tunehigh += arpcalc; + } + + /* glide handling */ + if(c->glideto != 0) { + c->gototune = tunehigh; + c->portspeed = c->glideto; + c->glideto = c->finetune = 0; + return; + } + + /* set modulator registers */ + lds_setregs(0x20 + regnum, i->mod_misc); + volcalc = i->mod_vol; + if(!c->nextvol || !(i->feedback & 1)) + c->volmod = volcalc; + else + c->volmod = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); + + if((i->feedback & 1) == 1 && allvolume != 0) + lds_setregs(0x40 + regnum, ((c->volmod & 0xc0) | (((c->volmod & 0x3f) * allvolume) >> 8)) ^ 0x3f); + else + lds_setregs(0x40 + regnum, c->volmod ^ 0x3f); + lds_setregs(0x60 + regnum, i->mod_ad); + lds_setregs(0x80 + regnum, i->mod_sr); + lds_setregs(0xe0 + regnum, i->mod_wave); + + /* Set carrier registers */ + lds_setregs(0x23 + regnum, i->car_misc); + volcalc = i->car_vol; + if(!c->nextvol) + c->volcar = volcalc; + else + c->volcar = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6)); + + if(allvolume) + lds_setregs(0x43 + regnum, ((c->volcar & 0xc0) | (((c->volcar & 0x3f) * allvolume) >> 8)) ^ 0x3f); + else + lds_setregs(0x43 + regnum, c->volcar ^ 0x3f); + lds_setregs(0x63 + regnum, i->car_ad); + lds_setregs(0x83 + regnum, i->car_sr); + lds_setregs(0xe3 + regnum, i->car_wave); + lds_setregs(0xc0 + channel_number, i->feedback); + lds_setregs_adv(0xb0 + channel_number, 0xdf, 0); /* key off */ + + freq = frequency[tunehigh % (12 * 16)]; + octave = tunehigh / (12 * 16) - 1; + if(!i->glide) { + if(!i->portamento || !c->lasttune) { + lds_setregs(0xa0 + channel_number, freq & 0xff); + lds_setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); + c->lasttune = c->gototune = tunehigh; + } else { + c->gototune = tunehigh; + c->portspeed = i->portamento; + lds_setregs_adv(0xb0 + channel_number, 0xdf, 0x20); /* key on */ + } + } else { + lds_setregs(0xa0 + channel_number, freq & 0xff); + lds_setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8)); + c->lasttune = tunehigh; + c->gototune = tunehigh + ((i->glide + 0x80) & 0xff) - 0x80; /* set destination */ + c->portspeed = i->portamento; + } + + if(!i->vibrato) + c->vibwait = c->vibspeed = c->vibrate = 0; + else { + c->vibwait = i->vibdelay; + /* PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; */ + c->vibspeed = (i->vibrato >> 4) + 2; + c->vibrate = (i->vibrato & 15) + 1; + } + + if(!(c->trmstay & 0xf0)) { + c->trmwait = (i->tremwait & 0xf0) >> 3; + /* PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; */ + c->trmspeed = i->mod_trem >> 4; + c->trmrate = i->mod_trem & 15; + c->trmcount = 0; + } + + if(!(c->trmstay & 0x0f)) { + c->trcwait = (i->tremwait & 15) << 1; + /* PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; */ + c->trcspeed = i->car_trem >> 4; + c->trcrate = i->car_trem & 15; + c->trccount = 0; + } + + c->arp_size = i->arpeggio & 15; + c->arp_speed = i->arpeggio >> 4; + memcpy(c->arp_tab, i->arp_tab, 12); + c->keycount = i->keyoff; + c->nextvol = c->glideto = c->finetune = c->vibcount = c->arp_pos = c->arp_count = 0; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/lds_play.h b/alienblaster/project/jni/application/opentyrian/src/lds_play.h new file mode 100644 index 000000000..e8239c989 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/lds_play.h @@ -0,0 +1,73 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LDS_PLAY_H +#define LDS_PLAY_H + +#include "opentyr.h" + +extern bool playing, songlooped; + +int lds_update( void ); +bool lds_load( FILE *f, unsigned int music_offset, unsigned int music_size ); +void lds_free( void ); +void lds_rewind( void ); + +#define REFRESH 70.0f + +/*unsigned int getorders() { return numposi; } +unsigned int getorder() { return posplay; } +unsigned int getrow() { return pattplay; } +unsigned int getspeed() { return speed; } +unsigned int getinstruments() { return numpatch; }*/ + +typedef struct { + unsigned char mod_misc, mod_vol, mod_ad, mod_sr, mod_wave, + car_misc, car_vol, car_ad, car_sr, car_wave, feedback, keyoff, + portamento, glide, finetune, vibrato, vibdelay, mod_trem, car_trem, + tremwait, arpeggio, arp_tab[12]; + unsigned short start, size; + unsigned char fms; + unsigned short transp; + unsigned char midinst, midvelo, midkey, midtrans, middum1, middum2; +} SoundBank; + +typedef struct { + unsigned short gototune, lasttune, packpos; + unsigned char finetune, glideto, portspeed, nextvol, volmod, volcar, + vibwait, vibspeed, vibrate, trmstay, trmwait, trmspeed, trmrate, trmcount, + trcwait, trcspeed, trcrate, trccount, arp_size, arp_speed, keycount, + vibcount, arp_pos, arp_count, packwait, arp_tab[12]; + struct { + unsigned char chandelay, sound; + unsigned short high; + } chancheat; +} Channel; + +typedef struct { + unsigned short patnum; + unsigned char transpose; +} Position; + +void lds_playsound(int inst_number, int channel_number, int tunehigh); +void lds_setregs(unsigned char reg, unsigned char val); +void lds_setregs_adv(unsigned char reg, unsigned char mask, unsigned char val); + +#endif /* LDS_PLAY_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/loudness.cpp b/alienblaster/project/jni/application/opentyrian/src/loudness.cpp new file mode 100644 index 000000000..883a1f63f --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/loudness.cpp @@ -0,0 +1,293 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "fm_synth.h" +#include "lds_play.h" +#include "loudness.h" +#include "nortsong.h" +#include "opentyr.h" +#include "params.h" + +float music_volume = 0, sample_volume = 0; + +bool music_stopped = true; +unsigned int song_playing = 0; + +bool audio_disabled = false, music_disabled = false, samples_disabled = false; + +/* SYN: These shouldn't be used outside this file. Hands off! */ +FILE *music_file = NULL; +Uint32 *song_offset; +Uint16 song_count = 0; + + +SAMPLE_TYPE *channel_buffer[SFX_CHANNELS] = { NULL }; +SAMPLE_TYPE *channel_pos[SFX_CHANNELS] = { NULL }; +Uint32 channel_len[SFX_CHANNELS] = { 0 }; +Uint8 channel_vol[SFX_CHANNELS]; + +int sound_init_state = false; +int freq = 11025 * OUTPUT_QUALITY; + +static SDL_AudioCVT audio_cvt; // used for format conversion + +void audio_cb( void *userdata, unsigned char *feedme, int howmuch ); + +void load_song( unsigned int song_num ); + +bool init_audio( void ) +{ + if (audio_disabled) + return false; + + SDL_AudioSpec ask, got; + + ask.freq = freq; + ask.format = (BYTES_PER_SAMPLE == 2) ? AUDIO_S16SYS : AUDIO_S8; + ask.channels = 1; + ask.samples = 512; + ask.callback = audio_cb; + + printf("\trequested %d Hz, %d channels, %d samples\n", ask.freq, ask.channels, ask.samples); + + if (SDL_OpenAudio(&ask, &got) == -1) + { + fprintf(stderr, "error: failed to initialize SDL audio: %s\n", SDL_GetError()); + audio_disabled = true; + return false; + } + + printf("\tobtained %d Hz, %d channels, %d samples\n", got.freq, got.channels, got.samples); + + SDL_BuildAudioCVT(&audio_cvt, ask.format, ask.channels, ask.freq, got.format, got.channels, got.freq); + + opl_init(); + + SDL_PauseAudio(0); // unpause + + return true; +} + +void audio_cb( void *user_data, unsigned char *sdl_buffer, int howmuch ) +{ + (void)user_data; + + // prepare for conversion + howmuch /= audio_cvt.len_mult; + audio_cvt.buf = sdl_buffer; + audio_cvt.len = howmuch; + + static long ct = 0; + + SAMPLE_TYPE *feedme = (SAMPLE_TYPE *)sdl_buffer; + + if (!music_disabled && !music_stopped) + { + /* SYN: Simulate the fm synth chip */ + SAMPLE_TYPE *music_pos = feedme; + long remaining = howmuch / BYTES_PER_SAMPLE; + while (remaining > 0) + { + while (ct < 0) + { + ct += freq; + lds_update(); /* SYN: Do I need to use the return value for anything here? */ + } + /* SYN: Okay, about the calculations below. I still don't 100% get what's going on, but... + - freq is samples/time as output by SDL. + - REFRESH is how often the play proc would have been called in Tyrian. Standard speed is + 70Hz, which is the default value of 70.0f + - ct represents the margin between play time (representing # of samples) and tick speed of + the songs (70Hz by default). It keeps track of which one is ahead, because they don't + synch perfectly. */ + + /* set i to smaller of data requested by SDL and a value calculated from the refresh rate */ + long i = (long)((ct / REFRESH) + 4) & ~3; + i = (i > remaining) ? remaining : i; /* i should now equal the number of samples we get */ + opl_update((SAMPLE_TYPE *)music_pos, i); + music_pos += i; + remaining -= i; + ct -= (long)(REFRESH * i); + } + + /* Reduce the music volume. */ + int qu = howmuch / BYTES_PER_SAMPLE; + for (int smp = 0; smp < qu; smp++) + { + feedme[smp] *= music_volume; + } + } + + if (!samples_disabled) + { + /* SYN: Mix sound channels and shove into audio buffer */ + for (int ch = 0; ch < SFX_CHANNELS; ch++) + { + float volume = sample_volume * (channel_vol[ch] / (float)SFX_CHANNELS); + + /* SYN: Don't copy more data than is in the channel! */ + unsigned int qu = ((unsigned)howmuch > channel_len[ch] ? channel_len[ch] : (unsigned)howmuch) / BYTES_PER_SAMPLE; + for (unsigned int smp = 0; smp < qu; smp++) + { +#if (BYTES_PER_SAMPLE == 2) + Sint32 clip = (Sint32)feedme[smp] + (Sint32)(channel_pos[ch][smp] * volume); + feedme[smp] = (clip > 0x7fff) ? 0x7fff : (clip <= -0x8000) ? -0x8000 : (Sint16)clip; +#else /* BYTES_PER_SAMPLE */ + Sint16 clip = (Sint16)feedme[smp] + (Sint16)(channel_pos[ch][smp] * volume); + feedme[smp] = (clip > 0x7f) ? 0x7f : (clip <= -0x80) ? -0x80 : (Sint8)clip; +#endif /* BYTES_PER_SAMPLE */ + } + + channel_pos[ch] += qu; + channel_len[ch] -= qu * BYTES_PER_SAMPLE; + + /* SYN: If we've emptied a channel buffer, let's free the memory and clear the channel. */ + if (channel_len[ch] == 0) + { + free(channel_buffer[ch]); + channel_buffer[ch] = channel_pos[ch] = NULL; + } + } + } + + // do conversion + SDL_ConvertAudio(&audio_cvt); +} + +void deinit_audio( void ) +{ + if (audio_disabled) + return; + + SDL_PauseAudio(1); // pause + + SDL_CloseAudio(); + + for (unsigned int i = 0; i < SFX_CHANNELS; i++) + { + free(channel_buffer[i]); + channel_buffer[i] = channel_pos[i] = NULL; + channel_len[i] = 0; + } + + opl_deinit(); + + lds_free(); +} + + +void load_music( void ) +{ + if (music_file == NULL) + { + music_file = dir_fopen_die(data_dir(), "music.mus", "rb"); + + efread(&song_count, sizeof(song_count), 1, music_file); + + song_offset = (Uint32*)malloc((song_count + 1) * sizeof(song_offset)); + + efread(song_offset, 4, song_count, music_file); + song_offset[song_count] = ftell_eof(music_file); + } +} + +void load_song( unsigned int song_num ) +{ + if (audio_disabled) + return; + + SDL_LockAudio(); + + if (song_num < song_count) + { + unsigned int song_size = song_offset[song_num + 1] - song_offset[song_num]; + lds_load(music_file, song_offset[song_num], song_size); + } + else + { + fprintf(stderr, "warning: failed to load song %d\n", song_num + 1); + } + + SDL_UnlockAudio(); +} + +void play_song( unsigned int song_num ) +{ + if (song_num != song_playing) + { + load_song(song_num); + song_playing = song_num; + } + + music_stopped = false; +} + +void restart_song( void ) +{ + unsigned int temp = song_playing; + song_playing = -1; + play_song(temp); +} + +void stop_song( void ) +{ + music_stopped = true; +} + +void fade_song( void ) +{ + printf("TODO: %s\n", __FUNCTION__); +} + +void set_volume( unsigned int music, unsigned int sample ) +{ + music_volume = music * (1.5f / 255.0f); + sample_volume = sample * (1.0f / 255.0f); +} + +void JE_multiSamplePlay(JE_byte *buffer, JE_word size, JE_byte chan, JE_byte vol) +{ + if (audio_disabled || samples_disabled) + return; + + SDL_LockAudio(); + + free(channel_buffer[chan]); + + channel_len[chan] = size * BYTES_PER_SAMPLE * SAMPLE_SCALING; + channel_buffer[chan] = (OPLSAMPLE*)malloc(channel_len[chan]); + channel_pos[chan] = channel_buffer[chan]; + channel_vol[chan] = vol + 1; + + for (int i = 0; i < size; i++) + { + for (int ex = 0; ex < SAMPLE_SCALING; ex++) + { +#if (BYTES_PER_SAMPLE == 2) + channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i] << 8; +#else /* BYTES_PER_SAMPLE */ + channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i]; +#endif /* BYTES_PER_SAMPLE */ + } + } + + SDL_UnlockAudio(); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/loudness.h b/alienblaster/project/jni/application/opentyrian/src/loudness.h new file mode 100644 index 000000000..f3a5c9317 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/loudness.h @@ -0,0 +1,60 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LOUDNESS_H +#define LOUDNESS_H + +#include "fmopl.h" +#include "opentyr.h" + +#include "SDL.h" + +#define SFX_CHANNELS 8 + +#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) || defined(ANDROID) +#define OUTPUT_QUALITY 2 // 22 kHz +#else +#define OUTPUT_QUALITY 4 // 44 kHz +#endif + +#define SAMPLE_SCALING OUTPUT_QUALITY +#define SAMPLE_TYPE OPLSAMPLE +#define BYTES_PER_SAMPLE (OPL_SAMPLE_BITS / 8) + +extern float music_volume, sample_volume; + +extern unsigned int song_playing; + +extern bool audio_disabled, music_disabled, samples_disabled; + +bool init_audio( void ); +void deinit_audio( void ); + +void load_music( void ); +void play_song( unsigned int song_num ); +void restart_song( void ); +void stop_song( void ); +void fade_song( void ); + +void set_volume( unsigned int music, unsigned int sample ); + +void JE_multiSamplePlay(JE_byte *buffer, JE_word size, JE_byte chan, JE_byte vol); + +#endif /* LOUDNESS_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/lvllib.cpp b/alienblaster/project/jni/application/opentyrian/src/lvllib.cpp new file mode 100644 index 000000000..06c780fe8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/lvllib.cpp @@ -0,0 +1,42 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "lvllib.h" +#include "opentyr.h" + +JE_LvlPosType lvlPos; + +char levelFile[13]; /* string [12] */ +JE_word lvlNum; + +void JE_analyzeLevel( void ) +{ + FILE *f = dir_fopen_die(data_dir(), levelFile, "rb"); + + efread(&lvlNum, sizeof(JE_word), 1, f); + + for (int x = 0; x < lvlNum; x++) + efread(&lvlPos[x], sizeof(JE_longint), 1, f); + + lvlPos[lvlNum] = ftell_eof(f); + + fclose(f); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/lvllib.h b/alienblaster/project/jni/application/opentyrian/src/lvllib.h new file mode 100644 index 000000000..d6e3a7a62 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/lvllib.h @@ -0,0 +1,35 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LVLLIB_H +#define LVLLIB_H + +#include "opentyr.h" + + +typedef JE_longint JE_LvlPosType[43]; /* [1..42 + 1] */ + +extern JE_LvlPosType lvlPos; +extern char levelFile[13]; /* string [12] */ +extern JE_word lvlNum; + +void JE_analyzeLevel( void ); + +#endif /* LVLLIB_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/lvlmast.cpp b/alienblaster/project/jni/application/opentyrian/src/lvlmast.cpp new file mode 100644 index 000000000..57ef4a469 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/lvlmast.cpp @@ -0,0 +1,174 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "opentyr.h" +#include "lvlmast.h" + + +const JE_char shapeFile[34] = /* [1..34] */ +{ + '2', '4', '7', '8', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', '5', '#', 'V', '0', '@', '3', '^', '5', '9' +}; + +const char lvlFile[LVL_NUM][9] = /* [1..LVLnum] of string [8] */ +{ +/* 1*/ "ASTROID4", "MAINMAPE", +/* 2*/ "ASTROID5", "MAINMAPD", +/* 3*/ "ASTROID7", "MAINMAPC", +/* 4*/ "BUBBLES", "MAINMAPT", +/* 5*/ "DELI", "MAINMAPS", +/* 6*/ "MINES2", "MAINMAPQ", +/* 7*/ "MINES", "MAINMAPI", +/* 8*/ "SAVARA", "MAINMAPY", +/* 9*/ "TYRLEV", "MAINMAPZ", +/*10*/ "BONUS1-1", "MAINMAP0", +/*11*/ "HOLES", "MAINMAP8", +/*12*/ "SAVARA3", "MAINMAP3", +/*13*/ "DESERT", "MAINMAAA", +/*14*/ "WINDY", "MAINMAAB", +/*15*/ "TYRLEV3", "MAINMAPZ", +/*16*/ "UNDERTYR", "MAINMAAU", +/*17*/ "SAVARA5", "MAINMAAW", +/*18*/ "BEER", "MAINMAAX" +}; + +const char lvlFile2[LVL_NUM_2][9] = /* [1..LVLnum2] of string [8] */ +{ + "JUNGLE", "MAINMAPF", + "GIGER", "MAINMAPR", + "BONUS1-2", "MAINMAP0", + "ASTCITY2", "MAINMAP1", + "SPACEATK", "MAINMAPH", + "STATION", "MAINMAPV", + "GEMWAR", "MAINMAPH", + "MARKERS", "MAINMAPH", + "PATHS", "MAINMAPH", + "JUNGLE2", "MAINMAP5", + "JUNGLE3", "MAINMAP7", + "JUNGLE4", "MAINMAAP" +}; + +const char lvlFile3[LVL_NUM_3][9] = /* [1..LVLnum3] of string [8] */ +{ + "ICE", "MAINMAPX", + "ASTCITY", "MAINMAPP", + "MINES3", "MAINMAPO", + "TUNNEL", "MAINMAPW", + "DELI2", "MAINMAPU", /*Bonus 3*/ + "FLEET", "MAINMAPB", + "STARGATE", "MAINMAP2", /*Bubbly*/ + "TYRLEV2", "MAINMAPZ", + "TUNNEL2", "MAINMAPA", /*Tunnel*/ + "SAVARA2", "MAINMAPY", + "DELI3", "MAINMAPS", + "MACES", "MAINMAP9" /*Bonus Maces*/ +}; + +const char lvlFile4[LVL_NUM_4][9] = /* [1..LVLnum4] of string [8] */ +{ + "HARVEST", "MAINMAAC", /*Harvest World ooooo */ + "MAZE", "MAINMAAD", /*Windy 2 ooooo */ + "SAVARA4", "MAINMAAF", /*Savara IV ooooo */ + "DESERT3", "MAINMAAG", /*Desert ooooo */ + "LAVA1", "MAINMAAH", /*Lava Core ooooo */ + "LAVA2", "MAINMAAJ", /*Lava Center ooooo */ + "CORE", "MAINMAAI", /*Tec tiles ooooo */ + "ICE1", "MAINMAAK", /*Ice exit ooooo */ + "LAVA3", "MAINMAAL", /*Lava Exit ooooo */ + "DESERT4", "MAINMAAM", /*Desert Run ooooo */ + "TUNNEL3", "MAINMAAN", /*Secret Tunnel ooooo */ + "LAVA4", "MAINMAAO", /*Lava Run ooooo */ + "EYESPY", "MAINMAAQ", /*Giger Eye ooooo */ + "FLEET2", "MAINMAPH", /*Dread Not ooooo */ + "BRAIN", "MAINMAAR", /*Brainiac ooooo */ + "NOSE", "MAINMAAS", /*Nose ooooo */ + "DESERT5", "MAINMAAT", /*Time War ooooo */ + "GALAGA", "MAINMAAV", /*Galaga ooooo */ +/*19*/ "SAVARA6", "MAINMAAY", /*Savara Approach ooooo */ +/*20*/ "SPACEAT2", "MAINMABB" /*Camanis Go ooooo */ +}; + +const char lvlFile5[LVL_NUM_5][9] = /* [1..lvlnum5] of string [8] */ +{ +/* 1*/ "E5LVL01", "MAINMA51" /*FogWalls ----- */ +}; + +/*! JE_LvlPosType lvlPos;*/ + +/* + Episode 4 uses... + NEWSH(.SHP + NEWSH^.SHP + NEWSH7.SHP + NEWSHP.SHP + NEWSH&.SHP + NEWSHE.SHP + NEWSHV.SHP + NEWSH#.SHP + NEWSHJ.SHP + NEWSH{.SHP + NEWSHK.SHP + + SHAPESZ.DAT + SHAPESW.DAT + SHAPESX.DAT + SHAPES}.DAT +*/ + +/* +TYPE 5: Shape Files + + SHAPES1.DAT o - - - - Items + SHAPES3.DAT o - - - - Shots + SHAPES6.DAT o - - - - Explosions + SHAPES9.DAT o - - - - Player ships/options + + 1 SHAPES2.DAT - o - - - Tyrian ships + 2 SHAPES4.DAT - o - - - TyrianBoss + 3 SHAPES7.DAT - - - - - Iceships + 4 SHAPES8.DAT - - - - - Tunnel World + 5 SHAPESA.DAT o - - - - Mine Stuff + 6 SHAPESB.DAT - - - - - IceBoss + 7 SHAPESC.DAT - o - - - Deliani Stuff + 8 SHAPESD.DAT o - - - - Asteroid Stuff I + 9 SHAPESE.DAT - o - - - Tyrian Bonus Rock + Bubbles + 10 SHAPESF.DAT - o - - - Savara Stuff I + 11 SHAPESG.DAT - - - - - Giger Stuff + 12 SHAPESH.DAT - - - - - Giger Stuff + 13 SHAPESI.DAT - o - - - Savara Stuff II + Savara Boss + 14 SHAPESJ.DAT - - - - - Jungle Stuff + 15 SHAPESK.DAT - - - - - Snowballs + 16 SHAPESL.DAT - - - - o Satellites + 17 SHAPESM.DAT o - - - - Asteroid Stuff IV + 18 SHAPESN.DAT - - - - - Giger Boss + 19 SHAPESO.DAT - o - - - Savara Boss + 20 SHAPESP.DAT o - - - - Asteroid Stuff III + 21 SHAPESQ.DAT o - - - - Coins and Gems + 22 SHAPESR.DAT - - - - - TunnelWorld Boss + 23 SHAPESS.DAT o - - - - Asteroid Stuff II + 24 SHAPEST.DAT - o - - - Deli Boss + 25 SHAPESU.DAT - - - - - Deli Stuff II + 28 SHAPESV.DAT - - o - o Misc Stuff/Cars + 27 SHAPES#.DAT - - - o o Sawblades + 31 SHAPES(.DAT - - - - o Desert/Lava + + M 1 2 3 4 episode +*/ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/lvlmast.h b/alienblaster/project/jni/application/opentyrian/src/lvlmast.h new file mode 100644 index 000000000..1b0ef814b --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/lvlmast.h @@ -0,0 +1,49 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef LVLMAST_H +#define LVLMAST_H + +#include "opentyr.h" + + +#define EVENT_MAXIMUM 2500 + +#define WEAP_NUM 780 +#define PORT_NUM 42 +#define ARMOR_NUM 4 +#define POWER_NUM 6 +#define ENGINE_NUM 6 +#define OPTION_NUM 30 +#define SHIP_NUM 13 +#define SHIELD_NUM 10 +#define SPECIAL_NUM 46 + +#define ENEMY_NUM 850 + +#define LVL_NUM (18 * 2) +#define LVL_NUM_2 (12 * 2) +#define LVL_NUM_3 (12 * 2) +#define LVL_NUM_4 (20 * 2) +#define LVL_NUM_5 (1 * 2) + +extern const JE_char shapeFile[34]; /* [1..34] */ + +#endif /* LVLMAST_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/main.m b/alienblaster/project/jni/application/opentyrian/src/main.m new file mode 100644 index 000000000..c931961df --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/main.m @@ -0,0 +1,101 @@ +/* vim: set noet: + * + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2008 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "opentyr.h" + +#import +#import +#import + +// SDL_main.h (included by SDL.h) redefines main to SDL_main. As we are +// implementing the "real" main here we must undef this preprocessor symbol. +#undef main + +@interface TyrianStartupClass : NSObject +@end + +@implementation TyrianStartupClass + +- (void)awakeFromNib +{ + // Copied and modified from SDLMain.m from the "SDL Application" template + + NSArray *argv_objc = [[NSProcessInfo processInfo] arguments]; + int argc = [argv_objc count]; + char ** argv; + BOOL finderLaunch; + + if ( argc >= 2 && strncmp ([[argv_objc objectAtIndex:1] cString], "-psn", 4) == 0 ) { + argv = (char **) SDL_malloc(sizeof (char *) * 2); + argv[0] = (char *)[[argv_objc objectAtIndex:0] cString]; + argv[1] = NULL; + argc = 1; + finderLaunch = YES; + } else { + int i; + argv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i < argc; i++) { + argv[i] = (char *)[[argv_objc objectAtIndex:i] cString]; + } + finderLaunch = NO; + } + + NSLog(@"%@",argv_objc); + + SDL_main(argc, argv); +} +@end + +const char* tyrian_game_folder() +{ + return [[[[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent:@"data"] + stringByAppendingString:@"/"] + cStringUsingEncoding:NSASCIIStringEncoding]; +} + +const char* get_user_directory() +{ + // Get Application Support folder + NSArray* paths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, + NSUserDomainMask, YES); + if ([paths count] > 0) + { + NSString* path = [ + [paths objectAtIndex:0] + stringByAppendingPathComponent:@"OpenTyrian" + ]; + + // Create OpenTyrian if it doesn't already exist + [[NSFileManager defaultManager] + createDirectoryAtPath:path attributes:nil]; + + // The return value is expected to end with a / + return [[path stringByAppendingString:@"/"] cStringUsingEncoding:NSASCIIStringEncoding]; + } + + return ""; +} + +int main(int argc, char** argv) +{ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/alienblaster/project/jni/application/opentyrian/src/mainint.cpp b/alienblaster/project/jni/application/opentyrian/src/mainint.cpp new file mode 100644 index 000000000..ca3ed1a3f --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mainint.cpp @@ -0,0 +1,4561 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "backgrnd.h" +#include "config.h" +#include "editship.h" +#include "episodes.h" +#include "file.h" +#include "fonthand.h" +#include "helptext.h" +#include "helptext.h" +#include "joystick.h" +#include "keyboard.h" +#include "lds_play.h" +#include "loudness.h" +#include "mainint.h" +#include "menus.h" +#include "mouse.h" +#include "mtrand.h" +#include "network.h" +#include "nortsong.h" +#include "nortvars.h" +#include "opentyr.h" +#include "palette.h" +#include "params.h" +#include "pcxmast.h" +#include "picload.h" +#include "player.h" +#include "setup.h" +#include "sndmast.h" +#include "sprite.h" +#include "varz.h" +#include "vga256d.h" +#include "video.h" + +#include +#include + +bool button[4]; + +#define MAX_PAGE 8 +#define TOPICS 6 +const JE_byte topicStart[TOPICS] = { 0, 1, 2, 3, 7, 255 }; + +JE_shortint constantLastX; +JE_word textErase; +JE_word upgradeCost; +JE_word downgradeCost; +JE_boolean performSave; +JE_boolean jumpSection; +JE_boolean useLastBank; /* See if I want to use the last 16 colors for DisplayText */ + +bool pause_pressed = false, ingamemenu_pressed = false; + +/* Draws a message at the bottom text window on the playing screen */ +void JE_drawTextWindow( const char *text ) +{ + if (textErase > 0) // erase current text + blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36); // in-game text area + + textErase = 100; + JE_outText(VGAScreenSeg, 20, 190, text, 0, 4); +} + +void JE_outCharGlow( JE_word x, JE_word y, const char *s ) +{ + JE_integer maxloc, loc, z; + JE_shortint glowcol[60]; /* [1..60] */ + JE_shortint glowcolc[60]; /* [1..60] */ + JE_word textloc[60]; /* [1..60] */ + JE_byte bank; + + setjasondelay2(1); + + bank = (warningRed) ? 7 : ((useLastBank) ? 15 : 14); + + if (s[0] == '\0') + return; + + if (frameCountMax == 0) + { + JE_textShade(VGAScreen, x, y, s, bank, 0, PART_SHADE); + JE_showVGA(); + } + else + { + maxloc = strlen(s); + for (z = 0; z < 60; z++) + { + glowcol[z] = -8; + glowcolc[z] = 1; + } + + loc = x; + for (z = 0; z < maxloc; z++) + { + textloc[z] = loc; + + int sprite_id = font_ascii[(unsigned char)s[z]]; + + if (s[z] == ' ') + loc += 6; + else if (sprite_id != -1) + loc += sprite(TINY_FONT, sprite_id)->width + 1; + } + + for (loc = 0; (unsigned)loc < strlen(s) + 28; loc++) + { + if (!ESCPressed) + { + setjasondelay(frameCountMax); + + NETWORK_KEEP_ALIVE(); + + int sprite_id = -1; + + for (z = loc - 28; z <= loc; z++) + { + if (z >= 0 && z < maxloc) + { + sprite_id = font_ascii[(unsigned char)s[z]]; + + if (sprite_id != -1) + { + blit_sprite_hv(VGAScreen, textloc[z], y, TINY_FONT, sprite_id, bank, glowcol[z]); + + glowcol[z] += glowcolc[z]; + if (glowcol[z] > 9) + glowcolc[z] = -1; + } + } + } + if (sprite_id != -1 && --z < maxloc) + blit_sprite_dark(VGAScreen, textloc[z] + 1, y + 1, TINY_FONT, sprite_id, true); + + if (JE_anyButton()) + frameCountMax = 0; + + do + { + if (levelWarningDisplay) + JE_updateWarning(VGAScreen); + + SDL_Delay(16); + } + while (!(delaycount() == 0 || ESCPressed)); + + JE_showVGA(); + } + } + } +} + +void JE_drawPortConfigButtons( void ) // rear weapon pattern indicator +{ + if (twoPlayerMode) + return; + + if (player[0].weapon_mode == 1) + { + blit_sprite(VGAScreenSeg, 285, 44, OPTION_SHAPES, 18); // lit + blit_sprite(VGAScreenSeg, 302, 44, OPTION_SHAPES, 19); // unlit + } + else // == 2 + { + blit_sprite(VGAScreenSeg, 285, 44, OPTION_SHAPES, 19); // unlit + blit_sprite(VGAScreenSeg, 302, 44, OPTION_SHAPES, 18); // lit + } +} + +void JE_helpSystem( JE_byte startTopic ) +{ + JE_integer page, lastPage = 0; + JE_byte menu; + + page = topicStart[startTopic-1]; + + fade_black(10); + JE_loadPic(VGAScreen, 2, false); + + play_song(SONG_MAPVIEW); + + JE_showVGA(); + fade_palette(colors, 10, 0, 255); + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + do + { + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + temp2 = 0; + + for (temp = 0; temp < TOPICS; temp++) + { + if (topicStart[temp] <= page) + { + temp2 = temp; + } + } + + if (page > 0) + { + JE_char buf[128]; + + sprintf(buf, "%s %d", miscText[24], page-topicStart[temp2]+1); + JE_outText(VGAScreen, 10, 192, buf, 13, 5); + + sprintf(buf, "%s %d of %d", miscText[25], page, MAX_PAGE); + JE_outText(VGAScreen, 220, 192, buf, 13, 5); + + JE_dString(VGAScreen, JE_fontCenter(topicName[temp2], SMALL_FONT_SHAPES), 1, topicName[temp2], SMALL_FONT_SHAPES); + } + + menu = 0; + + helpBoxBrightness = 3; + verticalHeight = 8; + + switch (page) + { + case 0: + menu = 2; + if (lastPage == MAX_PAGE) + { + menu = TOPICS; + } + JE_dString(VGAScreen, JE_fontCenter(topicName[0], FONT_SHAPES), 30, topicName[0], FONT_SHAPES); + + do + { + for (temp = 1; temp <= TOPICS; temp++) + { + char buf[21+1]; + + if (temp == menu-1) + { + strcpy(buf+1, topicName[temp]); + buf[0] = '~'; + } else { + strcpy(buf, topicName[temp]); + } + + JE_dString(VGAScreen, JE_fontCenter(topicName[temp], SMALL_FONT_SHAPES), temp * 20 + 40, buf, SMALL_FONT_SHAPES); + } + + //JE_waitRetrace(); didn't do anything anyway? + JE_showVGA(); + + tempW = 0; + JE_textMenuWait(&tempW, false); + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + menu--; + if (menu < 2) + { + menu = TOPICS; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + menu++; + if (menu > TOPICS) + { + menu = 2; + } + JE_playSampleNum(S_CURSOR); + break; + default: + break; + } + } + } while (!(lastkey_sym == SDLK_ESCAPE || lastkey_sym == SDLK_RETURN)); + + if (lastkey_sym == SDLK_RETURN) + { + page = topicStart[menu-1]; + JE_playSampleNum(S_CLICK); + } + + break; + case 1: /* One-Player Menu */ + JE_HBox(VGAScreen, 10, 20, 2, 60); + JE_HBox(VGAScreen, 10, 50, 5, 60); + JE_HBox(VGAScreen, 10, 80, 21, 60); + JE_HBox(VGAScreen, 10, 110, 1, 60); + JE_HBox(VGAScreen, 10, 140, 28, 60); + break; + case 2: /* Two-Player Menu */ + JE_HBox(VGAScreen, 10, 20, 1, 60); + JE_HBox(VGAScreen, 10, 60, 2, 60); + JE_HBox(VGAScreen, 10, 100, 21, 60); + JE_HBox(VGAScreen, 10, 140, 28, 60); + break; + case 3: /* Upgrade Ship */ + JE_HBox(VGAScreen, 10, 20, 5, 60); + JE_HBox(VGAScreen, 10, 70, 6, 60); + JE_HBox(VGAScreen, 10, 110, 7, 60); + break; + case 4: + JE_HBox(VGAScreen, 10, 20, 8, 60); + JE_HBox(VGAScreen, 10, 55, 9, 60); + JE_HBox(VGAScreen, 10, 87, 10, 60); + JE_HBox(VGAScreen, 10, 120, 11, 60); + JE_HBox(VGAScreen, 10, 170, 13, 60); + break; + case 5: + JE_HBox(VGAScreen, 10, 20, 14, 60); + JE_HBox(VGAScreen, 10, 80, 15, 60); + JE_HBox(VGAScreen, 10, 120, 16, 60); + break; + case 6: + JE_HBox(VGAScreen, 10, 20, 17, 60); + JE_HBox(VGAScreen, 10, 40, 18, 60); + JE_HBox(VGAScreen, 10, 130, 20, 60); + break; + case 7: /* Options */ + JE_HBox(VGAScreen, 10, 20, 21, 60); + JE_HBox(VGAScreen, 10, 70, 22, 60); + JE_HBox(VGAScreen, 10, 110, 23, 60); + JE_HBox(VGAScreen, 10, 140, 24, 60); + break; + case 8: + JE_HBox(VGAScreen, 10, 20, 25, 60); + JE_HBox(VGAScreen, 10, 60, 26, 60); + JE_HBox(VGAScreen, 10, 100, 27, 60); + JE_HBox(VGAScreen, 10, 140, 28, 60); + JE_HBox(VGAScreen, 10, 170, 29, 60); + break; + } + + helpBoxBrightness = 1; + verticalHeight = 7; + + lastPage = page; + + if (menu == 0) + { + do { + setjasondelay(3); + + push_joysticks_as_keyboard(); + service_SDL_events(true); + + JE_showVGA(); + + wait_delay(); + } while (!newkey && !newmouse); + + wait_noinput(false, true, false); + + if (newmouse) + { + switch (lastmouse_but) + { + case SDL_BUTTON_LEFT: + lastkey_sym = SDLK_RIGHT; + break; + case SDL_BUTTON_RIGHT: + lastkey_sym = SDLK_LEFT; + break; + case SDL_BUTTON_MIDDLE: + lastkey_sym = SDLK_ESCAPE; + break; + } + do + { + service_SDL_events(false); + } while (mousedown); + newkey = true; + } + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_LEFT: + case SDLK_UP: + case SDLK_PAGEUP: + page--; + JE_playSampleNum(S_CURSOR); + break; + case SDLK_RIGHT: + case SDLK_DOWN: + case SDLK_PAGEDOWN: + case SDLK_RETURN: + case SDLK_SPACE: + if (page == MAX_PAGE) + { + page = 0; + } else { + page++; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_F1: + page = 0; + JE_playSampleNum(S_CURSOR); + break; + default: + break; + } + } + } + + if (page == 255) + { + lastkey_sym = SDLK_ESCAPE; + } + } while (lastkey_sym != SDLK_ESCAPE); +} + +// cost to upgrade a weapon power from power-1 (where power == 0 indicates an unupgraded weapon) +long weapon_upgrade_cost( long base_cost, unsigned int power ) +{ + assert(power <= 11); + + unsigned int temp = 0; + + // 0 1 3 6 10 15 21 29 ... + for (; power > 0; power--) + temp += power; + + return base_cost * temp; +} + +ulong JE_getCost( JE_byte itemType, JE_word itemNum ) +{ + long cost = 0; + + switch (itemType) + { + case 2: + cost = (itemNum > 90) ? 100 : ships[itemNum].cost; + break; + case 3: + case 4: + { + cost = weaponPort[itemNum].cost; + + const uint port = itemType - 3, + item_power = player[0].items.weapon[port].power - 1; + + downgradeCost = weapon_upgrade_cost(cost, item_power); + upgradeCost = weapon_upgrade_cost(cost, item_power + 1); + } + break; + case 5: + cost = shields[itemNum].cost; + break; + case 6: + cost = powerSys[itemNum].cost; + break; + case 7: + case 8: + cost = options[itemNum].cost; + break; + } + + return cost; +} + +void JE_loadScreen( void ) +{ + JE_boolean quit; + JE_byte sel, screen, min = 0, max = 0; + char *tempstr; + char *tempstr2; + JE_boolean mal_str = false; + int len; + + tempstr = NULL; + + free_sprite2s(&shapes6); + JE_loadCompShapes(&shapes6, '1'); // need arrow sprites + + fade_black(10); + JE_loadPic(VGAScreen, 2, false); + JE_showVGA(); + fade_palette(colors, 10, 0, 255); + + screen = 1; + sel = 1; + quit = false; + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + do + { + while (mousedown) + { + service_SDL_events(false); + tempX = mouse_x; + tempY = mouse_y; + } + + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + JE_dString(VGAScreen, JE_fontCenter(miscText[38 + screen - 1], FONT_SHAPES), 5, miscText[38 + screen - 1], FONT_SHAPES); + + switch (screen) + { + case 1: + min = 1; + max = 12; + break; + case 2: + min = 12; + max = 23; + } + + /* SYN: Go through text line by line */ + for (x = min; x <= max; x++) + { + tempY = 30 + (x - min) * 13; + + if (x == max) + { + /* Last line is return to main menu, not a save game */ + if (mal_str) + { + free(tempstr); + mal_str = false; + } + tempstr = miscText[34 - 1]; + + if (x == sel) /* Highlight if selected */ + { + temp2 = 254; + } else { + temp2 = 250; + } + } else { + if (x == sel) /* Highlight if selected */ + { + temp2 = 254; + } else { + temp2 = 250 - ((saveFiles[x - 1].level == 0) << 1); + } + + if (saveFiles[x - 1].level == 0) /* I think this means the save file is unused */ + { + if (mal_str) + { + free(tempstr); + mal_str = false; + } + tempstr = miscText[3 - 1]; + } else { + if (mal_str) + { + free(tempstr); + mal_str = false; + } + tempstr = saveFiles[x - 1].name; + } + } + + /* Write first column text */ + JE_textShade(VGAScreen, 10, tempY, tempstr, 13, (temp2 % 16) - 8, FULL_SHADE); + + if (x < max) /* Write additional columns for all but the last row */ + { + if (saveFiles[x - 1].level == 0) + { + if (mal_str) + { + free(tempstr); + } + tempstr = (char *)malloc(7); + mal_str = true; + strcpy(tempstr, "-----"); /* Unused save slot */ + } else { + tempstr = saveFiles[x - 1].levelName; + tempstr2 = (char *)malloc(5 + strlen(miscTextB[2-1])); + sprintf(tempstr2, "%s %d", miscTextB[2-1], saveFiles[x - 1].episode); + JE_textShade(VGAScreen, 250, tempY, tempstr2, 5, (temp2 % 16) - 8, FULL_SHADE); + free(tempstr2); + } + + len = strlen(miscTextB[3-1]) + 2 + strlen(tempstr); + tempstr2 = (char *)malloc(len); + sprintf(tempstr2, "%s %s", miscTextB[3 - 1], tempstr); + JE_textShade(VGAScreen, 120, tempY, tempstr2, 5, (temp2 % 16) - 8, FULL_SHADE); + free(tempstr2); + } + + } + + if (screen == 2) + { + blit_sprite2x2(VGAScreen, 90, 180, shapes6, 279); + } + if (screen == 1) + { + blit_sprite2x2(VGAScreen, 220, 180, shapes6, 281); + } + + helpBoxColor = 15; + JE_helpBox(VGAScreen, 110, 182, miscText[56-1], 25); + + JE_showVGA(); + + tempW = 0; + JE_textMenuWait(&tempW, false); + + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + sel--; + if (sel < min) + { + sel = max; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + sel++; + if (sel > max) + { + sel = min; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_LEFT: + case SDLK_RIGHT: + if (screen == 1) + { + screen = 2; + sel += 11; + } else { + screen = 1; + sel -= 11; + } + break; + case SDLK_RETURN: + if (sel < max) + { + if (saveFiles[sel - 1].level > 0) + { + JE_playSampleNum (S_SELECT); + performSave = false; + JE_operation(sel); + quit = true; + } else { + JE_playSampleNum (S_CLINK); + } + } else { + quit = true; + } + + + break; + case SDLK_ESCAPE: + quit = true; + break; + default: + break; + } + + } + } while (!quit); +} + +ulong JE_totalScore( const Player *this_player ) +{ + ulong temp = this_player->cash; + + temp += JE_getValue(2, this_player->items.ship); + temp += JE_getValue(3, this_player->items.weapon[FRONT_WEAPON].id); + temp += JE_getValue(4, this_player->items.weapon[REAR_WEAPON].id); + temp += JE_getValue(5, this_player->items.shield); + temp += JE_getValue(6, this_player->items.generator); + temp += JE_getValue(7, this_player->items.sidekick[LEFT_SIDEKICK]); + temp += JE_getValue(8, this_player->items.sidekick[RIGHT_SIDEKICK]); + + return temp; +} + +JE_longint JE_getValue( JE_byte itemType, JE_word itemNum ) +{ + long value = 0; + + switch (itemType) + { + case 2: + value = ships[itemNum].cost; + break; + case 3: + case 4: + { + const long base_value = weaponPort[itemNum].cost; + + // if two-player, use first player's front and second player's rear weapon + const uint port = itemType - 3; + const uint item_power = player[twoPlayerMode ? port : 0].items.weapon[port].power - 1; + + value = base_value; + for (unsigned int i = 1; i <= item_power; ++i) + value += weapon_upgrade_cost(base_value, i); + } + break; + case 5: + value = shields[itemNum].cost; + break; + case 6: + value = powerSys[itemNum].cost; + break; + case 7: + case 8: + value = options[itemNum].cost; + break; + } + + return value; +} + +void JE_nextEpisode( void ) +{ + strcpy(lastLevelName, "Completed"); + + if (episodeNum == initial_episode_num && !gameHasRepeated && episodeNum != 4 && + !isNetworkGame && !constantPlay) + { + JE_highScoreCheck(); + } + + unsigned int newEpisode = JE_findNextEpisode(); + + if (jumpBackToEpisode1) + { + // shareware version check + if (episodeNum == 1 && + !isNetworkGame && !constantPlay) + { + // JE_loadOrderingInfo(); + } + + if (episodeNum > 2 && + !constantPlay) + { + JE_playCredits(); + } + + // randomly give player the SuperCarrot + if ((mt_rand() % 6) == 0) + { + player[0].items.ship = 2; + player[0].items.weapon[FRONT_WEAPON].id = 23; + player[0].items.weapon[REAR_WEAPON].id = 24; + + for (uint i = 0; i < COUNTOF(player[0].items.weapon); ++i) + player[0].items.weapon[i].power = 1; + + player[1].items.weapon[REAR_WEAPON].id = 24; + + player[0].last_items = player[0].items; + } + } + + if (newEpisode != episodeNum) + JE_initEpisode(newEpisode); + + gameLoaded = true; + mainLevel = FIRST_LEVEL; + saveLevel = FIRST_LEVEL; + + play_song(26); + + JE_clr256(VGAScreen); + memcpy(colors, palettes[6-1], sizeof(colors)); + + JE_dString(VGAScreen, JE_fontCenter(episode_name[episodeNum], SMALL_FONT_SHAPES), 130, episode_name[episodeNum], SMALL_FONT_SHAPES); + JE_dString(VGAScreen, JE_fontCenter(miscText[5-1], SMALL_FONT_SHAPES), 185, miscText[5-1], SMALL_FONT_SHAPES); + + JE_showVGA(); + fade_palette(colors, 15, 0, 255); + + JE_wipeKey(); + if (!constantPlay) + { + do + { + NETWORK_KEEP_ALIVE(); + + SDL_Delay(16); + } while (!JE_anyButton()); + } + + fade_black(15); +} + +void JE_initPlayerData( void ) +{ + /* JE: New Game Items/Data */ + + player[0].items.ship = 1; // USP Talon + player[0].items.weapon[FRONT_WEAPON].id = 1; // Pulse Cannon + player[0].items.weapon[REAR_WEAPON].id = 0; // None + player[0].items.shield = 4; // Gencore High Energy Shield + player[0].items.generator = 2; // Advanced MR-12 + for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i) + player[0].items.sidekick[i] = 0; // None + player[0].items.special = 0; // None + + player[0].last_items = player[0].items; + + player[1].items = player[0].items; + player[1].items.weapon[REAR_WEAPON].id = 15; // Vulcan Cannon + player[1].items.sidekick_level = 101; // 101, 102, 103 + player[1].items.sidekick_series = 0; // None + + gameHasRepeated = false; + onePlayerAction = false; + superArcadeMode = SA_NONE; + superTyrian = false; + twoPlayerMode = false; + + secretHint = (mt_rand() % 3) + 1; + + for (uint p = 0; p < COUNTOF(player); ++p) + { + for (uint i = 0; i < COUNTOF(player->items.weapon); ++i) + { + player[p].items.weapon[i].power = 1; + } + + player[p].weapon_mode = 1; + player[p].armor = ships[player[p].items.ship].dmg; + + player[p].is_dragonwing = (p == 1); + player[p].lives = &player[p].items.weapon[p].power; + + } + + mainLevel = FIRST_LEVEL; + saveLevel = FIRST_LEVEL; + + strcpy(lastLevelName, miscText[19]); +} + +void JE_sortHighScores( void ) +{ + JE_byte x; + + temp = 0; + for (x = 0; x < 6; x++) + { + JE_sort(); + temp += 3; + } +} + +void JE_highScoreScreen( void ) +{ + int min = 1; + int max = 3; + + int x, z; + short int chg; + int quit; + char scoretemp[32]; + + free_sprite2s(&shapes6); + JE_loadCompShapes(&shapes6, '1'); // need arrow sprites + + fade_black(10); + JE_loadPic(VGAScreen, 2, false); + JE_showVGA(); + fade_palette(colors, 10, 0, 255); + + quit = false; + x = 1; + chg = 1; + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + do + { + if (episodeAvail[x-1]) + { + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + JE_dString(VGAScreen, JE_fontCenter(miscText[51 - 1], FONT_SHAPES), 03, miscText[51 - 1], FONT_SHAPES); + JE_dString(VGAScreen, JE_fontCenter(episode_name[x], SMALL_FONT_SHAPES), 30, episode_name[x], SMALL_FONT_SHAPES); + + /* Player 1 */ + temp = (x * 6) - 6; + + JE_dString(VGAScreen, JE_fontCenter(miscText[47 - 1], SMALL_FONT_SHAPES), 55, miscText[47 - 1], SMALL_FONT_SHAPES); + + for (z = 0; z < 3; z++) + { + temp5 = saveFiles[temp + z].highScoreDiff; + if (temp5 > 9) + { + saveFiles[temp + z].highScoreDiff = 0; + temp5 = 0; + } + sprintf(scoretemp, "~#%d:~ %d", z + 1, saveFiles[temp+z].highScore1); + JE_textShade(VGAScreen, 250, ((z+1) * 10) + 65 , difficultyNameB[temp5], 15, temp5 + ((JE_byte) (temp5 == 0)) - 1, FULL_SHADE); + JE_textShade(VGAScreen, 20, ((z+1) * 10) + 65 , scoretemp, 15, 0, FULL_SHADE); + JE_textShade(VGAScreen, 110, ((z+1) * 10) + 65 , saveFiles[temp + z].highScoreName, 15, 2, FULL_SHADE); + } + + /* Player 2 */ + temp += 3; + + JE_dString(VGAScreen, JE_fontCenter( miscText[48 - 1], SMALL_FONT_SHAPES), 120, miscText[48 - 1], SMALL_FONT_SHAPES); + + /*{ textshade(20,125,misctext[49],15,3,_FullShade); + textshade(80,125,misctext[50],15,3,_FullShade);}*/ + + for (z = 0; z < 3; z++) + { + temp5 = saveFiles[temp + z].highScoreDiff; + if (temp5 > 9) + { + saveFiles[temp + z].highScoreDiff = 0; + temp5 = 0; + } + sprintf(scoretemp, "~#%d:~ %d", z + 1, saveFiles[temp+z].highScore1); /* Not .highScore2 for some reason */ + JE_textShade(VGAScreen, 250, ((z+1) * 10) + 125 , difficultyNameB[temp5], 15, temp5 + ((JE_byte) (temp5 == 0)) - 1, FULL_SHADE); + JE_textShade(VGAScreen, 20, ((z+1) * 10) + 125 , scoretemp, 15, 0, FULL_SHADE); + JE_textShade(VGAScreen, 110, ((z+1) * 10) + 125 , saveFiles[temp + z].highScoreName, 15, 2, FULL_SHADE); + } + + if (x > 1) + { + blit_sprite2x2(VGAScreen, 90, 180, shapes6, 279); + } + + if ( ( (x < 2) && episodeAvail[2-1] ) || ( (x < 3) && episodeAvail[3-1] ) ) + { + blit_sprite2x2(VGAScreen, 220, 180, shapes6, 281); + } + + helpBoxColor = 15; + JE_helpBox(VGAScreen, 110, 182, miscText[57 - 1], 25); + + /* {Dstring(fontcenter(misctext[57],_SmallFontShapes),190,misctext[57],_SmallFontShapes);} */ + + JE_showVGA(); + + tempW = 0; + JE_textMenuWait(&tempW, false); + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_LEFT: + x--; + chg = -1; + break; + case SDLK_RIGHT: + x++; + chg = 1; + break; + default: + break; + } + } + + } else { + x += chg; + } + + x = ( x < min ) ? max : ( x > max ) ? min : x; + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_RETURN: + case SDLK_ESCAPE: + quit = true; + break; + default: + break; + } + } + + } while (!quit); + +} + +void JE_gammaCorrect_func( JE_byte *col, JE_real r ) +{ + int temp = roundf(*col * r); + if (temp > 255) + { + temp = 255; + } + *col = temp; +} + +void JE_gammaCorrect( Palette *colorBuffer, JE_byte gamma ) +{ + int x; + JE_real r = 1 + (JE_real)gamma / 10; + + for (x = 0; x < 256; x++) + { + JE_gammaCorrect_func(&(*colorBuffer)[x].r, r); + JE_gammaCorrect_func(&(*colorBuffer)[x].g, r); + JE_gammaCorrect_func(&(*colorBuffer)[x].b, r); + } +} + +JE_boolean JE_gammaCheck( void ) +{ + bool temp = keysactive[SDLK_F11] != 0; + if (temp) + { + keysactive[SDLK_F11] = false; + newkey = false; + gammaCorrection = (gammaCorrection + 1) % 4; + memcpy(colors, palettes[pcxpal[3-1]], sizeof(colors)); + JE_gammaCorrect(&colors, gammaCorrection); + set_palette(colors, 0, 255); + } + return temp; +} + +void JE_doInGameSetup( void ) +{ + haltGame = false; + + if (isNetworkGame) + { + network_prepare(PACKET_GAME_MENU); + network_send(4); // PACKET_GAME_MENU + + while (true) + { + service_SDL_events(false); + + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_MENU) + { + network_update(); + break; + } + + network_update(); + network_check(); + + SDL_Delay(16); + } + } + + if (yourInGameMenuRequest) + { + if (JE_inGameSetup()) + { + reallyEndLevel = true; + playerEndLevel = true; + } + quitRequested = false; + + keysactive[SDLK_ESCAPE] = false; + + if (isNetworkGame) + { + if (!playerEndLevel) + { + network_prepare(PACKET_WAITING); + network_send(4); // PACKET_WAITING + } else { + network_prepare(PACKET_GAME_QUIT); + network_send(4); // PACKET_GAMEQUIT + } + } + } + + if (isNetworkGame) + { + SDL_Surface *temp_surface = VGAScreen; + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + + if (!yourInGameMenuRequest) + { + JE_barShade(VGAScreen, 3, 60, 257, 80); /*Help Box*/ + JE_barShade(VGAScreen, 5, 62, 255, 78); + JE_dString(VGAScreen, 10, 65, "Other player in options menu.", SMALL_FONT_SHAPES); + JE_showVGA(); + + while (true) + { + service_SDL_events(false); + JE_showVGA(); + + if (packet_in[0]) + { + if (SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING) + { + network_check(); + break; + } else if (SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_QUIT) { + reallyEndLevel = true; + playerEndLevel = true; + + network_check(); + break; + } + } + + network_update(); + network_check(); + + SDL_Delay(16); + } + } else { + /* + JE_barShade(3, 160, 257, 180); /-*Help Box*-/ + JE_barShade(5, 162, 255, 178); + tempScreenSeg = VGAScreen; + JE_dString(VGAScreen, 10, 165, "Waiting for other player.", SMALL_FONT_SHAPES); + JE_showVGA(); + */ + } + + while (!network_is_sync()) + { + service_SDL_events(false); + + network_check(); + SDL_Delay(16); + } + + VGAScreen = temp_surface; /* side-effect of game_screen */ + } + + yourInGameMenuRequest = false; + + //skipStarShowVGA = true; +} + +JE_boolean JE_inGameSetup( void ) +{ + SDL_Surface *temp_surface = VGAScreen; + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + + JE_boolean returnvalue = false; + + const JE_byte help[6] /* [1..6] */ = {15, 15, 28, 29, 26, 27}; + JE_byte sel; + JE_boolean quit; + + bool first = true; + + //tempScreenSeg = VGAScreenSeg; /* ? should work as VGAScreen */ + + quit = false; + sel = 1; + + JE_barShade(VGAScreen, 3, 13, 217, 137); /*Main Box*/ + JE_barShade(VGAScreen, 5, 15, 215, 135); + + JE_barShade(VGAScreen, 3, 143, 257, 157); /*Help Box*/ + JE_barShade(VGAScreen, 5, 145, 255, 155); + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + do + { + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + for (x = 0; x < 6; x++) + { + JE_outTextAdjust(VGAScreen, 10, (x + 1) * 20, inGameText[x], 15, ((sel == x+1) << 1) - 4, SMALL_FONT_SHAPES, true); + } + + JE_outTextAdjust(VGAScreen, 120, 3 * 20, detailLevel[processorType-1], 15, ((sel == 3) << 1) - 4, SMALL_FONT_SHAPES, true); + JE_outTextAdjust(VGAScreen, 120, 4 * 20, gameSpeedText[gameSpeed-1], 15, ((sel == 4) << 1) - 4, SMALL_FONT_SHAPES, true); + + JE_outTextAdjust(VGAScreen, 10, 147, mainMenuHelp[help[sel-1]-1], 14, 6, TINY_FONT, true); + + JE_barDrawShadow(VGAScreen, 120, 20, 1, 16, tyrMusicVolume / 12, 3, 13); + JE_barDrawShadow(VGAScreen, 120, 40, 1, 16, fxVolume / 12, 3, 13); + + JE_showVGA(); + + if (first) + { + first = false; + wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead + } + + tempW = 0; + JE_textMenuWait(&tempW, true); + + if (inputDetected) + { + switch (lastkey_sym) + { + case SDLK_RETURN: + JE_playSampleNum(S_SELECT); + switch (sel) + { + case 1: + case 2: + case 3: + case 4: + sel = 5; + break; + case 5: + quit = true; + break; + case 6: + returnvalue = true; + quit = true; + if (constantPlay) + { + JE_tyrianHalt(0); + } + + if (isNetworkGame) + { /*Tell other computer to exit*/ + haltGame = true; + playerEndLevel = true; + } + break; + } + break; + case SDLK_ESCAPE: + quit = true; + JE_playSampleNum(S_SPRING); + break; + case SDLK_UP: + if (--sel < 1) + { + sel = 6; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + if (++sel > 6) + { + sel = 1; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_LEFT: + switch (sel) + { + case 1: + JE_changeVolume(&tyrMusicVolume, -12, &fxVolume, 0); + if (music_disabled) + { + music_disabled = false; + restart_song(); + } + break; + case 2: + JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, -12); + samples_disabled = false; + break; + case 3: + if (--processorType < 1) + { + processorType = 4; + } + JE_initProcessorType(); + JE_setNewGameSpeed(); + break; + case 4: + if (--gameSpeed < 1) + { + gameSpeed = 5; + } + JE_initProcessorType(); + JE_setNewGameSpeed(); + break; + } + if (sel < 5) + { + JE_playSampleNum(S_CURSOR); + } + break; + case SDLK_RIGHT: + switch (sel) + { + case 1: + JE_changeVolume(&tyrMusicVolume, 12, &fxVolume, 0); + if (music_disabled) + { + music_disabled = false; + restart_song(); + } + break; + case 2: + JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, 12); + samples_disabled = false; + break; + case 3: + if (++processorType > 4) + { + processorType = 1; + } + JE_initProcessorType(); + JE_setNewGameSpeed(); + break; + case 4: + if (++gameSpeed > 5) + { + gameSpeed = 1; + } + JE_initProcessorType(); + JE_setNewGameSpeed(); + break; + } + if (sel < 5) + { + JE_playSampleNum(S_CURSOR); + } + break; + case SDLK_w: + if (sel == 3) + { + processorType = 6; + JE_initProcessorType(); + } + default: + break; + } + } + + } while (!(quit || haltGame)); + + VGAScreen = temp_surface; /* side-effect of game_screen */ + + return returnvalue; +} + +void JE_inGameHelp( void ) +{ + SDL_Surface *temp_surface = VGAScreen; + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + + //tempScreenSeg = VGAScreenSeg; + + JE_clearKeyboard(); + JE_wipeKey(); + + JE_barShade(VGAScreen, 1, 1, 262, 182); /*Main Box*/ + JE_barShade(VGAScreen, 3, 3, 260, 180); + JE_barShade(VGAScreen, 5, 5, 258, 178); + JE_barShade(VGAScreen, 7, 7, 256, 176); + fill_rectangle_xy(VGAScreen, 9, 9, 254, 174, 0); + + if (twoPlayerMode) // Two-Player Help + { + helpBoxColor = 3; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 20, 4, 36, 50); + + // weapon help + blit_sprite(VGAScreenSeg, 2, 21, OPTION_SHAPES, 43); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 55, 20, 37, 40); + + // sidekick help + blit_sprite(VGAScreenSeg, 5, 36, OPTION_SHAPES, 41); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 40, 43, 34, 44); + + // sheild/armor help + blit_sprite(VGAScreenSeg, 2, 79, OPTION_SHAPES, 42); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 54, 84, 35, 40); + + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 5, 126, 38, 55); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 5, 160, 39, 55); + } + else + { + // power bar help + blit_sprite(VGAScreenSeg, 15, 5, OPTION_SHAPES, 40); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 40, 10, 31, 45); + + // weapon help + blit_sprite(VGAScreenSeg, 5, 37, OPTION_SHAPES, 39); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 40, 40, 32, 44); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 40, 60, 33, 44); + + // sidekick help + blit_sprite(VGAScreenSeg, 5, 98, OPTION_SHAPES, 41); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 40, 103, 34, 44); + + // shield/armor help + blit_sprite(VGAScreenSeg, 2, 138, OPTION_SHAPES, 42); + helpBoxColor = 5; + helpBoxBrightness = 3; + JE_HBox(VGAScreen, 54, 143, 35, 40); + } + + // "press a key" + blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36); // in-game text area + JE_outText(VGAScreenSeg, 120 - JE_textWidth(miscText[5-1], TINY_FONT) / 2 + 20, 190, miscText[5-1], 0, 4); + + JE_showVGA(); + + do + { + tempW = 0; + JE_textMenuWait(&tempW, true); + } + while (!inputDetected); + + textErase = 1; + + VGAScreen = temp_surface; +} + +void JE_highScoreCheck( void ) +{ + free_sprite2s(&shapes6); + JE_loadCompShapes(&shapes6, '1'); // need mouse cursor sprite + + Sint32 temp_score; + + for (int temp_p = 0; temp_p < (twoPlayerMode ? 2 : 1); ++temp_p) + { + JE_sortHighScores(); + + int p = temp_p; + + if (twoPlayerMode) + { + // ask for the highest scorer first + if (player[0].cash < player[1].cash) + p = (temp_p == 0) ? 1 : 0; + + temp_score = (p == 0) ? player[0].cash : player[1].cash; + } + else + { + // single player highscore includes cost of upgrades + temp_score = JE_totalScore(&player[0]); + } + + int slot; + const int first_slot = (initial_episode_num - 1) * 6 + (twoPlayerMode ? 3 : 0), + slot_limit = first_slot + 3; + + for (slot = first_slot; slot < slot_limit; ++slot) + { + if (temp_score > saveFiles[slot].highScore1) + break; + } + + // did you get a high score? + if (slot < slot_limit) + { + // shift down old scores + for (int i = slot_limit - 1; i > slot; --i) + { + saveFiles[i].highScore1 = saveFiles[i - 1].highScore1; + strcpy(saveFiles[i].highScoreName, saveFiles[i - 1].highScoreName); + } + + wait_noinput(false, true, false); + + JE_clr256(VGAScreen); + JE_showVGA(); + memcpy(colors, palettes[0], sizeof(colors)); + + play_song(33); + + { + /* Enter Thy name */ + + JE_byte flash = 8 * 16 + 10; + JE_boolean fadein = true; + JE_boolean quit = false, cancel = false; + char stemp[30], tempstr[30]; + char buffer[256]; + + strcpy(stemp, " "); + temp = 0; + + JE_barShade(VGAScreen, 65, 55, 255, 155); + + do + { + service_SDL_events(true); + + JE_dString(VGAScreen, JE_fontCenter(miscText[51], FONT_SHAPES), 3, miscText[51], FONT_SHAPES); + + temp3 = twoPlayerMode ? 58 + p : 53; + + JE_dString(VGAScreen, JE_fontCenter(miscText[temp3-1], SMALL_FONT_SHAPES), 30, miscText[temp3-1], SMALL_FONT_SHAPES); + + blit_sprite(VGAScreenSeg, 50, 50, OPTION_SHAPES, 35); // message box + + if (twoPlayerMode) + { + sprintf(buffer, "%s %s", miscText[48 + p], miscText[53]); + JE_textShade(VGAScreen, 60, 55, buffer, 11, 4, FULL_SHADE); + } + else + { + JE_textShade(VGAScreen, 60, 55, miscText[53], 11, 4, FULL_SHADE); + } + + sprintf(buffer, "%s %d", miscText[37], temp_score); + JE_textShade(VGAScreen, 70, 70, buffer, 11, 4, FULL_SHADE); + + do + { + flash = (flash == 8 * 16 + 10) ? 8 * 16 + 2 : 8 * 16 + 10; + temp3 = (temp3 == 6) ? 2 : 6; + + strncpy(tempstr, stemp, temp); + tempstr[temp] = '\0'; + JE_outText(VGAScreen, 65, 89, tempstr, 8, 3); + tempW = 65 + JE_textWidth(tempstr, TINY_FONT); + JE_barShade(VGAScreen, tempW + 2, 90, tempW + 6, 95); + fill_rectangle_xy(VGAScreen, tempW + 1, 89, tempW + 5, 94, flash); + + for (int i = 0; i < 14; i++) + { + setjasondelay(1); + + JE_mouseStart(); + JE_showVGA(); + if (fadein) + { + fade_palette(colors, 15, 0, 255); + fadein = false; + } + JE_mouseReplace(); + + push_joysticks_as_keyboard(); + service_wait_delay(); + + if (newkey || newmouse) + break; + } + + } while (!newkey && !newmouse); + + if (!playing) + play_song(31); + + if (mouseButton > 0) + { + if (mouseX > 56 && mouseX < 142 && mouseY > 123 && mouseY < 149) + { + quit = true; + } + else if (mouseX > 151 && mouseX < 237 && mouseY > 123 && mouseY < 149) + { + quit = true; + cancel = true; + } + } + else if (newkey) + { + bool validkey = false; + lastkey_char = toupper(lastkey_char); + switch(lastkey_char) + { + case ' ': + case '-': + case '.': + case ',': + case ':': + case '!': + case '?': + case '#': + case '@': + case '$': + case '%': + case '*': + case '(': + case ')': + case '/': + case '=': + case '+': + case '<': + case '>': + case ';': + case '"': + case '\'': + validkey = true; + default: + if (temp < 28 && (validkey || (lastkey_char >= 'A' && lastkey_char <= 'Z') || (lastkey_char >= '0' && lastkey_char <= '9'))) + { + stemp[temp] = lastkey_char; + temp++; + } + break; + case SDLK_BACKSPACE: + case SDLK_DELETE: + if (temp) + { + temp--; + stemp[temp] = ' '; + } + break; + case SDLK_ESCAPE: + quit = true; + cancel = true; + break; + case SDLK_RETURN: + quit = true; + break; + } + } + } + while (!quit); + + if (!cancel) + { + saveFiles[slot].highScore1 = temp_score; + strcpy(saveFiles[slot].highScoreName, stemp); + saveFiles[slot].highScoreDiff = difficultyLevel; + } + + fade_black(15); + JE_loadPic(VGAScreen, 2, false); + + JE_dString(VGAScreen, JE_fontCenter(miscText[50], FONT_SHAPES), 10, miscText[50], FONT_SHAPES); + JE_dString(VGAScreen, JE_fontCenter(episode_name[episodeNum], SMALL_FONT_SHAPES), 35, episode_name[episodeNum], SMALL_FONT_SHAPES); + + for (int i = first_slot; i < slot_limit; ++i) + { + if (i != slot) + { + sprintf(buffer, "~#%d:~ %d", (i - first_slot + 1), saveFiles[i].highScore1); + JE_textShade(VGAScreen, 20, ((i - first_slot + 1) * 12) + 65, buffer, 15, 0, FULL_SHADE); + JE_textShade(VGAScreen, 150, ((i - first_slot + 1) * 12) + 65, saveFiles[i].highScoreName, 15, 2, FULL_SHADE); + } + } + + JE_showVGA(); + + fade_palette(colors, 15, 0, 255); + + sprintf(buffer, "~#%d:~ %d", (slot - first_slot + 1), saveFiles[slot].highScore1); + + frameCountMax = 6; + textGlowFont = TINY_FONT; + + textGlowBrightness = 10; + JE_outTextGlow(VGAScreenSeg, 20, (slot - first_slot + 1) * 12 + 65, buffer); + textGlowBrightness = 10; + JE_outTextGlow(VGAScreenSeg, 150, (slot - first_slot + 1) * 12 + 65, saveFiles[slot].highScoreName); + textGlowBrightness = 10; + JE_outTextGlow(VGAScreenSeg, JE_fontCenter(miscText[4], TINY_FONT), 180, miscText[4]); + + JE_showVGA(); + + if (frameCountMax != 0) + wait_input(true, true, true); + + fade_black(15); + } + + } + } +} + +// increases game difficulty based on player's total score / total of players' scores +void adjust_difficulty( void ) +{ + const float score_multiplier[10] = + { + 0, // Wimp (doesn't exist) + 0.4f, // Easy + 0.8f, // Normal + 1.3f, // Hard + 1.6f, // Impossible + 2, // Insanity + 2, // Suicide + 3, // Maniacal + 3, // Zinglon + 3, // Nortaneous + }; + + assert(initialDifficulty > 0 && initialDifficulty < 10); + + const ulong score = twoPlayerMode ? (player[0].cash + player[1].cash) : JE_totalScore(&player[0]), + adjusted_score = roundf(score * score_multiplier[initialDifficulty]); + + uint new_difficulty = 0; + + if (twoPlayerMode) + { + if (adjusted_score < 10000) + new_difficulty = 1; // Easy + else if (adjusted_score < 20000) + new_difficulty = 2; // Normal + else if (adjusted_score < 50000) + new_difficulty = 3; // Hard + else if (adjusted_score < 80000) + new_difficulty = 4; // Impossible + else if (adjusted_score < 125000) + new_difficulty = 5; // Insanity + else if (adjusted_score < 200000) + new_difficulty = 6; // Suicide + else if (adjusted_score < 400000) + new_difficulty = 7; // Maniacal + else if (adjusted_score < 600000) + new_difficulty = 8; // Zinglon + else + new_difficulty = 9; // Nortaneous + } + else + { + if (adjusted_score < 40000) + new_difficulty = 1; // Easy + else if (adjusted_score < 70000) + new_difficulty = 2; // Normal + else if (adjusted_score < 150000) + new_difficulty = 3; // Hard + else if (adjusted_score < 300000) + new_difficulty = 4; // Impossible + else if (adjusted_score < 600000) + new_difficulty = 5; // Insanity + else if (adjusted_score < 1000000) + new_difficulty = 6; // Suicide + else if (adjusted_score < 2000000) + new_difficulty = 7; // Maniacal + else if (adjusted_score < 3000000) + new_difficulty = 8; // Zinglon + else + new_difficulty = 9; // Nortaneous + } + + difficultyLevel = MAX((unsigned)difficultyLevel, new_difficulty); +} + +bool load_next_demo( void ) +{ + if (++demo_num > 5) + demo_num = 1; + + char demo_filename[9]; + snprintf(demo_filename, sizeof(demo_filename), "demo.%d", demo_num); + demo_file = dir_fopen_die(data_dir(), demo_filename, "rb"); // TODO: only play demos from existing file (instead of dying) + + difficultyLevel = 2; + bonusLevelCurrent = false; + + Uint8 temp = fgetc(demo_file); + JE_initEpisode(temp); + efread(levelName, 1, 10, demo_file); levelName[10] = '\0'; + lvlFileNum = fgetc(demo_file); + + player[0].items.weapon[FRONT_WEAPON].id = fgetc(demo_file); + player[0].items.weapon[REAR_WEAPON].id = fgetc(demo_file); + player[0].items.super_arcade_mode = fgetc(demo_file); + player[0].items.sidekick[LEFT_SIDEKICK] = fgetc(demo_file); + player[0].items.sidekick[RIGHT_SIDEKICK] = fgetc(demo_file); + player[0].items.generator = fgetc(demo_file); + + player[0].items.sidekick_level = fgetc(demo_file); // could probably ignore + player[0].items.sidekick_series = fgetc(demo_file); // could probably ignore + + initial_episode_num = fgetc(demo_file); // could probably ignore + + player[0].items.shield = fgetc(demo_file); + player[0].items.special = fgetc(demo_file); + player[0].items.ship = fgetc(demo_file); + + for (uint i = 0; i < 2; ++i) + player[0].items.weapon[i].power = fgetc(demo_file); + + fseek(demo_file, 3, SEEK_CUR); + + levelSong = fgetc(demo_file); + + demo_keys_wait = 0; + demo_keys = next_demo_keys = 0; + + printf("loaded demo '%s'\n", demo_filename); + + return true; +} + +bool replay_demo_keys( void ) +{ + if (demo_keys_wait == 0) + if (read_demo_keys() == false) + return false; // no more keys + + if (demo_keys_wait > 0) + demo_keys_wait--; + + if (demo_keys & (1 << 0)) + player[0].y -= CURRENT_KEY_SPEED; + if (demo_keys & (1 << 1)) + player[0].y += CURRENT_KEY_SPEED; + + if (demo_keys & (1 << 2)) + player[0].x -= CURRENT_KEY_SPEED; + if (demo_keys & (1 << 3)) + player[0].x += CURRENT_KEY_SPEED; + + button[0] = (bool)(demo_keys & (1 << 4)); + button[3] = (bool)(demo_keys & (1 << 5)); + button[1] = (bool)(demo_keys & (1 << 6)); + button[2] = (bool)(demo_keys & (1 << 7)); + + return true; +} + +bool read_demo_keys( void ) +{ + demo_keys = next_demo_keys; + + efread(&demo_keys_wait, sizeof(Uint16), 1, demo_file); + demo_keys_wait = SDL_Swap16(demo_keys_wait); + + next_demo_keys = getc(demo_file); + + return !feof(demo_file); +} + +/*Street Fighter codes*/ +void JE_SFCodes( JE_byte playerNum_, JE_integer PX_, JE_integer PY_, JE_integer mouseX_, JE_integer mouseY_ ) +{ + JE_byte temp, temp2, temp3, temp4, temp5; + + uint ship = player[playerNum_-1].items.ship; + + /*Get direction*/ + if (playerNum_ == 2 && ship < 15) + { + ship = 0; + } + + if (ship < 15) + { + + temp2 = (mouseY_ > PY_) + /*UP*/ + (mouseY_ < PY_) + /*DOWN*/ + (PX_ < mouseX_) + /*LEFT*/ + (PX_ > mouseX_); /*RIGHT*/ + temp = (mouseY_ > PY_) * 1 + /*UP*/ + (mouseY_ < PY_) * 2 + /*DOWN*/ + (PX_ < mouseX_) * 3 + /*LEFT*/ + (PX_ > mouseX_) * 4; /*RIGHT*/ + + if (temp == 0) // no direction being pressed + { + if (!button[0]) // if fire button is released + { + temp = 9; + temp2 = 1; + } else { + temp2 = 0; + temp = 99; + } + } + + if (temp2 == 1) // if exactly one direction pressed or firebutton is released + { + temp += button[0] * 4; + + temp3 = superTyrian ? 21 : 3; + for (temp2 = 0; temp2 < temp3; temp2++) + { + + /*Use SuperTyrian ShipCombos or not?*/ + temp5 = superTyrian ? shipCombosB[temp2] : shipCombos[ship][temp2]; + + // temp5 == selected combo in ship + if (temp5 == 0) /* combo doesn't exists */ + { + // mark twiddles as cancelled/finished + SFCurrentCode[playerNum_-1][temp2] = 0; + } else { + // get next combo key + temp4 = keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]]; + + // correct key + if (temp4 == temp) + { + SFCurrentCode[playerNum_-1][temp2]++; + + temp4 = keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]]; + if (temp4 > 100 && temp4 <= 100 + SPECIAL_NUM) + { + SFCurrentCode[playerNum_-1][temp2] = 0; + SFExecuted[playerNum_-1] = temp4 - 100; + } + } else { + if ((temp != 9) && + (temp4 - 1) % 4 != (temp - 1) % 4 && + (SFCurrentCode[playerNum_-1][temp2] == 0 || + keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]-1] != temp)) + { + SFCurrentCode[playerNum_-1][temp2] = 0; + } + } + } + } + } + + } +} + +void JE_sort( void ) +{ + JE_byte a, b; + + for (a = 0; a < 2; a++) + { + for (b = a + 1; b < 3; b++) + { + if (saveFiles[temp + a].highScore1 < saveFiles[temp + b].highScore1) + { + JE_longint tempLI; + char tempStr[30]; + JE_byte tempByte; + + tempLI = saveFiles[temp + a].highScore1; + saveFiles[temp + a].highScore1 = saveFiles[temp + b].highScore1; + saveFiles[temp + b].highScore1 = tempLI; + + strcpy(tempStr, saveFiles[temp + a].highScoreName); + strcpy(saveFiles[temp + a].highScoreName, saveFiles[temp + b].highScoreName); + strcpy(saveFiles[temp + b].highScoreName, tempStr); + + tempByte = saveFiles[temp + a].highScoreDiff; + saveFiles[temp + a].highScoreDiff = saveFiles[temp + b].highScoreDiff; + saveFiles[temp + b].highScoreDiff = tempByte; + } + } + } +} + +void JE_playCredits( void ) +{ + const int lines_max = 132; + const int line_max_length = 65; + + char credstr[lines_max][line_max_length + 1]; + + int lines = 0; + + JE_byte currentpic = 0, fade = 0; + JE_shortint fadechg = 1; + JE_byte currentship = 0; + JE_integer shipx = 0, shipxwait = 0; + JE_shortint shipxc = 0, shipxca = 0; + + load_sprites_file(EXTRA_SHAPES, "estsc.shp"); + + setjasondelay2(1000); + + play_song(8); + + // load credits text + FILE *f = dir_fopen_die(data_dir(), "tyrian.cdt", "rb"); + for (lines = 0; !feof(f) && lines < lines_max; ++lines) + { + read_encrypted_pascal_string(credstr[lines], sizeof(credstr[lines]), f); + } + if (lines == lines_max) + --lines; + fclose(f); + + memcpy(colors, palettes[6-1], sizeof(colors)); + JE_clr256(VGAScreen); + JE_showVGA(); + fade_palette(colors, 2, 0, 255); + + //tempScreenSeg = VGAScreenSeg; + + const int ticks_max = lines * 20 * 3; + for (int ticks = 0; ticks < ticks_max; ++ticks) + { + setjasondelay(1); + JE_clr256(VGAScreen); + + blit_sprite_hv(VGAScreenSeg, 319 - sprite(EXTRA_SHAPES, currentpic)->width, 100 - (sprite(EXTRA_SHAPES, currentpic)->height / 2), EXTRA_SHAPES, currentpic, 0x0, fade - 15); + + fade += fadechg; + if (fade == 0 && fadechg == -1) + { + fadechg = 1; + ++currentpic; + if (currentpic >= sprite_table[EXTRA_SHAPES].count) + currentpic = 0; + } + if (fade == 15) + fadechg = 0; + + if (delaycount2() == 0) + { + fadechg = -1; + setjasondelay2(900); + } + + if (ticks % 200 == 0) + { + currentship = (mt_rand() % 11) + 1; + shipxwait = (mt_rand() % 80) + 10; + if ((mt_rand() % 2) == 1) + { + shipx = 1; + shipxc = 0; + shipxca = 1; + } + else + { + shipx = 900; + shipxc = 0; + shipxca = -1; + } + } + + shipxwait--; + if (shipxwait == 0) + { + if (shipx == 1 || shipx == 900) + shipxc = 0; + shipxca = -shipxca; + shipxwait = (mt_rand() % 40) + 15; + } + shipxc += shipxca; + shipx += shipxc; + if (shipx < 1) + { + shipx = 1; + shipxwait = 1; + } + if (shipx > 900) + { + shipx = 900; + shipxwait = 1; + } + tempI = shipxc * shipxc; + if (450 + tempI < 0 || 450 + tempI > 900) + { + if (shipxca < 0 && shipxc < 0) + shipxwait = 1; + if (shipxca > 0 && shipxc > 0) + shipxwait = 1; + } + + uint ship_sprite = ships[currentship].shipgraphic; + if (shipxc < -10) + ship_sprite -= (shipxc < -20) ? 4 : 2; + else if (shipxc > 10) + ship_sprite += (shipxc > 20) ? 4 : 2; + + blit_sprite2x2(VGAScreen, shipx / 40, 184 - (ticks % 200), shapes9, ship_sprite); + + const int bottom_line = (ticks / 3) / 20; + int y = 20 - ((ticks / 3) % 20); + + for (int line = bottom_line - 10; line < bottom_line; ++line) + { + if (line >= 0 && line < lines_max) + { + if (strcmp(&credstr[line][0], ".") != 0 && strlen(credstr[line])) + { + const Uint8 color = credstr[line][0] - 65; + const char *text = &credstr[line][1]; + + const int x = 110 - JE_textWidth(text, SMALL_FONT_SHAPES) / 2; + + JE_outTextAdjust(VGAScreen, x + abs((y / 18) % 4 - 2) - 1, y - 1, text, color, -8, SMALL_FONT_SHAPES, false); + JE_outTextAdjust(VGAScreen, x, y, text, color, -2, SMALL_FONT_SHAPES, false); + } + } + + y += 20; + } + + fill_rectangle_xy(VGAScreen, 0, 0, 319, 10, 0); + fill_rectangle_xy(VGAScreen, 0, 190, 319, 199, 0); + + if (currentpic == sprite_table[EXTRA_SHAPES].count - 1) + JE_outTextAdjust(VGAScreen, 5, 180, miscText[54], 2, -2, SMALL_FONT_SHAPES, false); // levels-in-episode + + if (bottom_line == lines_max - 8) + fade_song(); + + if (ticks == ticks_max - 1) + { + --ticks; + play_song(9); + } + + NETWORK_KEEP_ALIVE(); + + JE_showVGA(); + + wait_delay(); + + if (JE_anyButton()) + break; + } + + fade_black(10); + + free_sprites(EXTRA_SHAPES); +} + +void JE_endLevelAni( void ) +{ + JE_word x, y; + JE_byte temp; + char tempStr[256]; + + Sint8 i; + + if (!constantPlay) + { + // grant shipedit privileges + + // special + if (player[0].items.special < 21) + saveTemp[SAVE_FILES_SIZE + 81 + player[0].items.special] = 1; + + for (uint p = 0; p < COUNTOF(player); ++p) + { + // front, rear + for (uint i = 0; i < COUNTOF(player[p].items.weapon); ++i) + saveTemp[SAVE_FILES_SIZE + player[p].items.weapon[i].id] = 1; + + // options + for (uint i = 0; i < COUNTOF(player[p].items.sidekick); ++i) + saveTemp[SAVE_FILES_SIZE + 51 + player[p].items.sidekick[i]] = 1; + } + } + + adjust_difficulty(); + + player[0].last_items = player[0].items; + strcpy(lastLevelName, levelName); + + JE_wipeKey(); + frameCountMax = 4; + textGlowFont = SMALL_FONT_SHAPES; + + SDL_Color white = { 255, 255, 255 }; + set_colors(white, 254, 254); + + if (!levelTimer || levelTimerCountdown > 0 || !(episodeNum == 4)) + JE_playSampleNum(V_LEVEL_END); + else + play_song(21); + + if (bonusLevel) + { + JE_outTextGlow(VGAScreenSeg, 20, 20, miscText[17-1]); + } + else if (all_players_alive()) + { + sprintf(tempStr, "%s %s", miscText[27-1], levelName); // "Completed" + JE_outTextGlow(VGAScreenSeg, 20, 20, tempStr); + } + else + { + sprintf(tempStr, "%s %s", miscText[62-1], levelName); // "Exiting" + JE_outTextGlow(VGAScreenSeg, 20, 20, tempStr); + } + + if (twoPlayerMode) + { + for (uint i = 0; i < 2; ++i) + { + snprintf(tempStr, sizeof(tempStr), "%s %lu", miscText[40 + i], player[i].cash); + JE_outTextGlow(VGAScreenSeg, 30, 50 + 20 * i, tempStr); + } + } + else + { + sprintf(tempStr, "%s %lu", miscText[28-1], player[0].cash); + JE_outTextGlow(VGAScreenSeg, 30, 50, tempStr); + } + + temp = (totalEnemy == 0) ? 0 : roundf(enemyKilled * 100 / totalEnemy); + sprintf(tempStr, "%s %d%%", miscText[63-1], temp); + JE_outTextGlow(VGAScreenSeg, 40, 90, tempStr); + + if (!constantPlay) + editorLevel += temp / 5; + + if (!onePlayerAction && !twoPlayerMode) + { + JE_outTextGlow(VGAScreenSeg, 30, 120, miscText[4-1]); /*Cubes*/ + + if (cubeMax > 0) + { + if (cubeMax > 4) + cubeMax = 4; + + if (frameCountMax != 0) + frameCountMax = 1; + + for (temp = 1; temp <= cubeMax; temp++) + { + NETWORK_KEEP_ALIVE(); + + JE_playSampleNum(18); + x = 20 + 30 * temp; + y = 135; + JE_drawCube(VGAScreenSeg, x, y, 9, 0); + JE_showVGA(); + + for (i = -15; i <= 10; i++) + { + setjasondelay(frameCountMax); + + blit_sprite_hv(VGAScreenSeg, x, y, OPTION_SHAPES, 25, 0x9, i); + + if (JE_anyButton()) + frameCountMax = 0; + + JE_showVGA(); + + wait_delay(); + } + for (i = 10; i >= 0; i--) + { + setjasondelay(frameCountMax); + + blit_sprite_hv(VGAScreenSeg, x, y, OPTION_SHAPES, 25, 0x9, i); + + if (JE_anyButton()) + frameCountMax = 0; + + JE_showVGA(); + + wait_delay(); + } + } + } + else + { + JE_outTextGlow(VGAScreenSeg, 50, 135, miscText[15-1]); + } + + } + + if (frameCountMax != 0) + { + frameCountMax = 6; + temp = 1; + } else { + temp = 0; + } + temp2 = twoPlayerMode ? 150 : 160; + JE_outTextGlow(VGAScreenSeg, 90, temp2, miscText[5-1]); + + if (!constantPlay) + { + do + { + setjasondelay(1); + + NETWORK_KEEP_ALIVE(); + + wait_delay(); + } while (!(JE_anyButton() || (frameCountMax == 0 && temp == 1))); + } + + wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead + + fade_black(15); + JE_clr256(VGAScreen); +} + +void JE_drawCube( SDL_Surface * screen, JE_word x, JE_word y, JE_byte filter, JE_byte brightness ) +{ + blit_sprite_dark(screen, x + 4, y + 4, OPTION_SHAPES, 25, false); + blit_sprite_dark(screen, x + 3, y + 3, OPTION_SHAPES, 25, false); + blit_sprite_hv(screen, x, y, OPTION_SHAPES, 25, filter, brightness); +} + +void JE_handleChat( void ) +{ + // STUB(); Annoying piece of crap =P +} + +bool str_pop_int( char *str, int *val ) +{ + bool success = false; + + char buf[256]; + assert(strlen(str) < sizeof(buf)); + + // grab the value from str + char *end; + *val = strtol(str, &end, 10); + + if (end != str) + { + success = true; + + // shift the rest to the beginning + strcpy(buf, end); + strcpy(str, buf); + } + + return success; +} + +void JE_operation( JE_byte slot ) +{ + JE_byte flash; + char stemp[21]; + char tempStr[51]; + + if (!performSave) + { + if (saveFiles[slot-1].level > 0) + { + gameJustLoaded = true; + JE_loadGame(slot); + gameLoaded = true; + } + } + else if (slot % 11 != 0) + { + strcpy(stemp, " "); + memcpy(stemp, saveFiles[slot-1].name, strlen(saveFiles[slot-1].name)); + temp = strlen(stemp); + while (stemp[temp-1] == ' ' && --temp); + + flash = 8 * 16 + 10; + + wait_noinput(false, true, false); + + JE_barShade(VGAScreen, 65, 55, 255, 155); + + bool quit = false; + while (!quit) + { + service_SDL_events(true); + + blit_sprite(VGAScreen, 50, 50, OPTION_SHAPES, 35); // message box + + JE_textShade(VGAScreen, 60, 55, miscText[1-1], 11, 4, DARKEN); + JE_textShade(VGAScreen, 70, 70, levelName, 11, 4, DARKEN); + + do + { + flash = (flash == 8 * 16 + 10) ? 8 * 16 + 2 : 8 * 16 + 10; + temp3 = (temp3 == 6) ? 2 : 6; + + strcpy(tempStr, miscText[2-1]); + strncat(tempStr, stemp, temp); + JE_outText(VGAScreen, 65, 89, tempStr, 8, 3); + tempW = 65 + JE_textWidth(tempStr, TINY_FONT); + JE_barShade(VGAScreen, tempW + 2, 90, tempW + 6, 95); + fill_rectangle_xy(VGAScreen, tempW + 1, 89, tempW + 5, 94, flash); + + for (int i = 0; i < 14; i++) + { + setjasondelay(1); + + JE_mouseStart(); + JE_showVGA(); + JE_mouseReplace(); + + push_joysticks_as_keyboard(); + service_wait_delay(); + + if (newkey || newmouse) + break; + } + + } + while (!newkey && !newmouse); + + if (mouseButton > 0) + { + if (mouseX > 56 && mouseX < 142 && mouseY > 123 && mouseY < 149) + { + quit = true; + JE_saveGame(slot, stemp); + JE_playSampleNum(S_SELECT); + } + else if (mouseX > 151 && mouseX < 237 && mouseY > 123 && mouseY < 149) + { + quit = true; + JE_playSampleNum(S_SPRING); + } + } + else if (newkey) + { + bool validkey = false; + lastkey_char = toupper(lastkey_char); + switch (lastkey_char) + { + case ' ': + case '-': + case '.': + case ',': + case ':': + case '!': + case '?': + case '#': + case '@': + case '$': + case '%': + case '*': + case '(': + case ')': + case '/': + case '=': + case '+': + case '<': + case '>': + case ';': + case '"': + case '\'': + validkey = true; + default: + if (temp < 14 && (validkey || (lastkey_char >= 'A' && lastkey_char <= 'Z') || (lastkey_char >= '0' && lastkey_char <= '9'))) + { + JE_playSampleNum(S_CURSOR); + stemp[temp] = lastkey_char; + temp++; + } + break; + case SDLK_BACKSPACE: + case SDLK_DELETE: + if (temp) + { + temp--; + stemp[temp] = ' '; + JE_playSampleNum(S_CLICK); + } + break; + case SDLK_ESCAPE: + quit = true; + JE_playSampleNum(S_SPRING); + break; + case SDLK_RETURN: + quit = true; + JE_saveGame(slot, stemp); + JE_playSampleNum(S_SELECT); + break; + } + + } + } + } + + wait_noinput(false, true, false); +} + +void JE_inGameDisplays( void ) +{ + char stemp[21]; + char tempstr[256]; + + for (uint i = 0; i < ((twoPlayerMode && !galagaMode) ? 2 : 1); ++i) + { + snprintf(tempstr, sizeof(tempstr), "%lu", player[i].cash); + JE_textShade(VGAScreen, 30 + 200 * i, 175, tempstr, 2, 4, FULL_SHADE); + } + + /*Special Weapon?*/ + if (player[0].items.special > 0) + blit_sprite2x2(VGAScreen, 25, 1, eShapes6, special[player[0].items.special].itemgraphic); + + /*Lives Left*/ + if (onePlayerAction || twoPlayerMode) + { + for (int temp = 0; temp < (onePlayerAction ? 1 : 2); temp++) + { + const uint extra_lives = *player[temp].lives - 1; + + temp5 = (temp == 0 && player[0].items.special > 0) ? 35 : 15; + tempW = (temp == 0) ? 30: 270; + + if (extra_lives >= 5) + { + blit_sprite2(VGAScreen, tempW, temp5, shapes9, 285); + tempW = (temp == 0) ? 45 : 250; + sprintf(tempstr, "%d", extra_lives); + JE_textShade(VGAScreen, tempW, temp5 + 3, tempstr, 15, 1, FULL_SHADE); + } + else if (extra_lives >= 1) + { + for (uint i = 0; i < extra_lives; ++i) + { + blit_sprite2(VGAScreen, tempW, temp5, shapes9, 285); + + tempW += (temp == 0) ? 12 : -12; + } + } + + strcpy(stemp, (temp == 0) ? miscText[49-1] : miscText[50-1]); + if (isNetworkGame) + { + strcpy(stemp, JE_getName(temp+1)); + } + + tempW = (temp == 0) ? 28 : (285 - JE_textWidth(stemp, TINY_FONT)); + JE_textShade(VGAScreen, tempW, temp5 - 7, stemp, 2, 6, FULL_SHADE); + } + } + + /*Super Bombs!!*/ + for (uint i = 0; i < COUNTOF(player); ++i) + { + int x = (i == 0) ? 30 : 270; + + for (uint j = player[i].superbombs; j > 0; --j) + { + blit_sprite2(VGAScreen, x, 160, shapes9, 304); + x += (i == 0) ? 12 : -12; + } + } + + if (youAreCheating) + { + JE_outText(VGAScreen, 90, 170, "Cheaters always prosper.", 3, 4); + } +} + +void JE_mainKeyboardInput( void ) +{ + JE_gammaCheck(); + + /* { Network Request Commands } */ + + if (!isNetworkGame) + { + /* { Edited Ships } for Player 1 */ + if (extraAvail && keysactive[SDLK_TAB] && !isNetworkGame && !superTyrian) + { + for (x = SDLK_0; x <= SDLK_9; x++) + { + if (keysactive[x]) + { + int z = x == SDLK_0 ? 10 : x - SDLK_0; + player[0].items.ship = 90 + z; /*Ships*/ + z = (z - 1) * 15; + player[0].items.weapon[FRONT_WEAPON].id = extraShips[z + 1]; + player[0].items.weapon[REAR_WEAPON].id = extraShips[z + 2]; + player[0].items.special = extraShips[z + 3]; + player[0].items.sidekick[LEFT_SIDEKICK] = extraShips[z + 4]; + player[0].items.sidekick[RIGHT_SIDEKICK] = extraShips[z + 5]; + player[0].items.generator = extraShips[z + 6]; + /*Armor*/ + player[0].items.shield = extraShips[z + 8]; + memset(shotMultiPos, 0, sizeof(shotMultiPos)); + + if (player[0].weapon_mode > JE_portConfigs()) + player[0].weapon_mode = 1; + + tempW = player[0].armor; + JE_getShipInfo(); + if (player[0].armor > tempW && editShip1) + player[0].armor = tempW; + else + editShip1 = true; + + SDL_Surface *temp_surface = VGAScreen; + VGAScreen = VGAScreenSeg; + JE_wipeShieldArmorBars(); + JE_drawArmor(); + JE_drawShield(); + VGAScreen = temp_surface; + JE_drawOptions(); + + keysactive[x] = false; + } + } + } + + /* for Player 2 */ + if (extraAvail && keysactive[SDLK_CAPSLOCK] && !isNetworkGame && !superTyrian) + { + for (x = SDLK_0; x <= SDLK_9; x++) + { + if (keysactive[x]) + { + int z = x == SDLK_0 ? 10 : x - SDLK_0; + player[1].items.ship = 90 + z; + z = (z - 1) * 15; + player[1].items.weapon[FRONT_WEAPON].id = extraShips[z + 1]; + player[1].items.weapon[REAR_WEAPON].id = extraShips[z + 2]; + player[1].items.special = extraShips[z + 3]; + player[1].items.sidekick[LEFT_SIDEKICK] = extraShips[z + 4]; + player[1].items.sidekick[RIGHT_SIDEKICK] = extraShips[z + 5]; + player[1].items.generator = extraShips[z + 6]; + /*Armor*/ + player[1].items.shield = extraShips[z + 8]; + memset(shotMultiPos, 0, sizeof(shotMultiPos)); + + if (player[1].weapon_mode > JE_portConfigs()) + player[1].weapon_mode = 1; + + tempW = player[1].armor; + JE_getShipInfo(); + if (player[1].armor > tempW && editShip2) + player[1].armor = tempW; + else + editShip2 = true; + + SDL_Surface *temp_surface = VGAScreen; + VGAScreen = VGAScreenSeg; + JE_wipeShieldArmorBars(); + JE_drawArmor(); + JE_drawShield(); + VGAScreen = temp_surface; + JE_drawOptions(); + + keysactive[x] = false; + } + } + } + } + + /* { In-Game Help } */ + if (keysactive[SDLK_F1]) + { + if (isNetworkGame) + { + helpRequest = true; + } else { + JE_inGameHelp(); + skipStarShowVGA = true; + } + } + + /* {!Activate Nort Ship!} */ + if (keysactive[SDLK_F2] && keysactive[SDLK_F4] && keysactive[SDLK_F6] && keysactive[SDLK_F7] && + keysactive[SDLK_F9] && keysactive[SDLK_BACKSLASH] && keysactive[SDLK_SLASH]) + { + if (isNetworkGame) + { + nortShipRequest = true; + } else { + player[0].items.ship = 12; + player[0].items.special = 13; + player[0].items.weapon[REAR_WEAPON].id = 36; + shipGr = 1; + } + } + + /* {Cheating} */ + if (!isNetworkGame && !twoPlayerMode && !superTyrian && superArcadeMode == SA_NONE) + { + if (keysactive[SDLK_F2] && keysactive[SDLK_F3] && keysactive[SDLK_F6]) + { + youAreCheating = !youAreCheating; + keysactive[SDLK_F2] = false; + } + + if (keysactive[SDLK_F2] && keysactive[SDLK_F3] && (keysactive[SDLK_F4] || keysactive[SDLK_F5]) && !superTyrian) + { + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].armor = 0; + + youAreCheating = !youAreCheating; + JE_drawTextWindow(miscText[63-1]); + } + + if (constantPlay && keysactive[SDLK_c] && !superTyrian && superArcadeMode == SA_NONE) + { + youAreCheating = !youAreCheating; + keysactive[SDLK_c] = false; + } + } + + if (superTyrian) + { + youAreCheating = false; + } + + /* {Personal Commands} */ + + /* {DEBUG} */ + if (keysactive[SDLK_F10] && keysactive[SDLK_BACKSPACE]) + { + keysactive[SDLK_F10] = false; + debug = !debug; + + debugHist = 1; + debugHistCount = 1; + + /* YKS: clock ticks since midnight replaced by SDL_GetTicks */ + lastDebugTime = SDL_GetTicks(); + } + + /* {CHEAT-SKIP LEVEL} */ + if (keysactive[SDLK_F2] && keysactive[SDLK_F6] && (keysactive[SDLK_F7] || keysactive[SDLK_F8]) && !keysactive[SDLK_F9] + && !superTyrian && superArcadeMode == SA_NONE) + { + if (isNetworkGame) + { + skipLevelRequest = true; + } else { + levelTimer = true; + levelTimerCountdown = 0; + endLevel = true; + levelEnd = 40; + } + } + + /* pause game */ + pause_pressed = pause_pressed || keysactive[SDLK_p]; + + /* in-game setup */ + ingamemenu_pressed = ingamemenu_pressed || keysactive[SDLK_ESCAPE]; + + /* {MUTE SOUND} */ + if (keysactive[SDLK_s]) + { + keysactive[SDLK_s] = false; + + samples_disabled = !samples_disabled; + + JE_drawTextWindow(samples_disabled ? miscText[17] : miscText[18]); + } + + /* {MUTE MUSIC} */ + if (keysactive[SDLK_m]) + { + keysactive[SDLK_m] = false; + + music_disabled = !music_disabled; + if (!music_disabled) + restart_song(); + + JE_drawTextWindow(music_disabled ? miscText[35] : miscText[36]); + } + + if (keysactive[SDLK_BACKSPACE]) + { + /* toggle screenshot pause */ + if (keysactive[SDLK_NUMLOCK]) + { + superPause = !superPause; + } + + /* {SMOOTHIES} */ + if (keysactive[SDLK_F12] && keysactive[SDLK_SCROLLOCK]) + { + for (temp = SDLK_2; temp <= SDLK_9; temp++) + { + if (keysactive[temp]) + { + smoothies[temp-SDLK_2] = !smoothies[temp-SDLK_2]; + } + } + if (keysactive[SDLK_0]) + { + smoothies[8] = !smoothies[8]; + } + } else + + /* {CYCLE THROUGH FILTER COLORS} */ + if (keysactive[SDLK_MINUS]) + { + if (levelFilter == -99) + { + levelFilter = 0; + } else { + levelFilter++; + if (levelFilter == 16) + { + levelFilter = -99; + } + } + } else + + /* {HYPER-SPEED} */ + if (keysactive[SDLK_1]) + { + fastPlay++; + if (fastPlay > 2) + { + fastPlay = 0; + } + keysactive[SDLK_1] = false; + JE_setNewGameSpeed(); + } + + /* {IN-GAME RANDOM MUSIC SELECTION} */ + if (keysactive[SDLK_SCROLLOCK]) + { + play_song(mt_rand() % MUSIC_NUM); + } + } +} + +void JE_pauseGame( void ) +{ + JE_boolean done = false; + JE_word mouseX, mouseY; + + //tempScreenSeg = VGAScreenSeg; // sega000 + if (!superPause) + { + JE_dString(VGAScreenSeg, 120, 90, miscText[22], FONT_SHAPES); + + VGAScreen = VGAScreenSeg; + JE_showVGA(); + } + + set_volume(tyrMusicVolume / 2, fxVolume); + + if (isNetworkGame) + { + network_prepare(PACKET_GAME_PAUSE); + network_send(4); // PACKET_GAME_PAUSE + + while (true) + { + service_SDL_events(false); + + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_PAUSE) + { + network_update(); + break; + } + + network_update(); + network_check(); + + SDL_Delay(16); + } + } + + wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead + + do + { + setjasondelay(2); + + push_joysticks_as_keyboard(); + service_SDL_events(true); + + if ((newkey && lastkey_sym != SDLK_LCTRL && lastkey_sym != SDLK_RCTRL && lastkey_sym != SDLK_LALT && lastkey_sym != SDLK_RALT) + || JE_mousePosition(&mouseX, &mouseY) > 0) + { + if (isNetworkGame) + { + network_prepare(PACKET_WAITING); + network_send(4); // PACKET_WAITING + } + done = true; + } + + if (isNetworkGame) + { + network_check(); + + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING) + { + network_check(); + + done = true; + } + } + + wait_delay(); + } while (!done); + + if (isNetworkGame) + { + while (!network_is_sync()) + { + service_SDL_events(false); + + network_check(); + SDL_Delay(16); + } + } + + set_volume(tyrMusicVolume, fxVolume); + + //skipStarShowVGA = true; +} + +void JE_playerMovement( Player *this_player, + JE_byte inputDevice, + JE_byte playerNum_, + JE_word shipGr_, + Sprite2_array *shapes9ptr_, + JE_word *mouseX_, JE_word *mouseY_ ) +{ + JE_integer mouseXC, mouseYC; + JE_integer accelXC, accelYC; + + if (playerNum_ == 2 || !twoPlayerMode) + { + tempW = weaponPort[this_player->items.weapon[REAR_WEAPON].id].opnum; + + if (this_player->weapon_mode > tempW) + this_player->weapon_mode = 1; + } + + if (isNetworkGame && thisPlayerNum == playerNum_) + { + network_state_prepare(); + memset(&packet_state_out[0]->data[4], 0, 10); + } + +redo: + + if (isNetworkGame) + { + inputDevice = 0; + } + + mouseXC = 0; + mouseYC = 0; + accelXC = 0; + accelYC = 0; + + bool link_gun_analog = false; + float link_gun_angle = 0; + + /* Draw Player */ + if (!this_player->is_alive) + { + if (this_player->exploding_ticks > 0) + { + --this_player->exploding_ticks; + + if (levelEndFxWait > 0) + { + levelEndFxWait--; + } + else + { + levelEndFxWait = (mt_rand() % 6) + 3; + if ((mt_rand() % 3) == 1) + soundQueue[6] = S_EXPLOSION_9; + else + soundQueue[5] = S_EXPLOSION_11; + } + tempW = this_player->x + (mt_rand() % 32) - 16; + tempW2 = this_player->y + (mt_rand() % 32) - 16; + + JE_setupExplosionLarge(false, 0, this_player->x + (mt_rand() % 32) - 16, this_player->y + (mt_rand() % 32) - 16 + 7); + JE_setupExplosionLarge(false, 0, this_player->x, this_player->y + 7); + + if (levelEnd > 0) + levelEnd--; + } + else + { + if (twoPlayerMode || onePlayerAction) // if arcade mode + { + if (*this_player->lives > 1) // respawn if any extra lives + { + --(*this_player->lives); + + reallyEndLevel = false; + shotMultiPos[playerNum_-1] = 0; + calc_purple_balls_needed(this_player); + twoPlayerLinked = false; + if (galagaMode) + twoPlayerMode = false; + this_player->y = 160; + this_player->invulnerable_ticks = 100; + this_player->is_alive = true; + endLevel = false; + + if (galagaMode || episodeNum == 4) + this_player->armor = this_player->initial_armor; + else + this_player->armor = this_player->initial_armor / 2; + + if (galagaMode) + this_player->shield = 0; + else + this_player->shield = this_player->shield_max / 2; + + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + JE_drawArmor(); + JE_drawShield(); + VGAScreen = game_screen; /* side-effect of game_screen */ + goto redo; + } + else + { + if (galagaMode) + twoPlayerMode = false; + if (allPlayersGone && isNetworkGame) + reallyEndLevel = true; + } + + } + } + } + else if (constantDie) + { + // finished exploding? start dying again + if (this_player->exploding_ticks == 0) + { + this_player->shield = 0; + + if (this_player->armor > 0) + { + --this_player->armor; + } + else + { + this_player->is_alive = false; + this_player->exploding_ticks = 60; + levelEnd = 40; + } + + JE_wipeShieldArmorBars(); + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + JE_drawArmor(); + VGAScreen = game_screen; /* side-effect of game_screen */ + + // as if instant death weren't enough, player also gets infinite lives in order to enjoy an infinite number of deaths -_- + if (*player[0].lives < 11) + ++(*player[0].lives); + } + } + + + if (!this_player->is_alive) + { + explosionFollowAmountX = explosionFollowAmountY = 0; + return; + } + + if (!endLevel) + { + *mouseX_ = this_player->x; + *mouseY_ = this_player->y; + button[1-1] = false; + button[2-1] = false; + button[3-1] = false; + button[4-1] = false; + + /* --- Movement Routine Beginning --- */ + + if (!isNetworkGame || playerNum_ == thisPlayerNum) + { + if (endLevel) + { + this_player->y -= 2; + } + else + { + if (record_demo || play_demo) + inputDevice = 1; // keyboard is required device for demo recording + + // demo playback input + if (play_demo) + { + if (!replay_demo_keys()) + { + endLevel = true; + levelEnd = 40; + } + } + + /* joystick input */ + if ((inputDevice == 0 || inputDevice >= 3) && joysticks > 0) + { + int j = inputDevice == 0 ? 0 : inputDevice - 3; + int j_max = inputDevice == 0 ? joysticks : inputDevice - 3 + 1; + for (; j < j_max; j++) + { + poll_joystick(j); + + if (joystick[j].analog) + { + mouseXC += joystick_axis_reduce(j, joystick[j].x); + mouseYC += joystick_axis_reduce(j, joystick[j].y); + + link_gun_analog = joystick_analog_angle(j, &link_gun_angle); + } + else + { + this_player->x += joystick[j].direction[3] ? -CURRENT_KEY_SPEED : 0 + joystick[j].direction[1] ? CURRENT_KEY_SPEED : 0; + this_player->y += joystick[j].direction[0] ? -CURRENT_KEY_SPEED : 0 + joystick[j].direction[2] ? CURRENT_KEY_SPEED : 0; + } + + button[0] |= joystick[j].action[0]; + button[1] |= joystick[j].action[2]; + button[2] |= joystick[j].action[3]; + button[3] |= joystick[j].action_pressed[1]; + + ingamemenu_pressed |= joystick[j].action_pressed[4]; + pause_pressed |= joystick[j].action_pressed[5]; + } + } + + service_SDL_events(false); + + /* mouse input */ + if ((inputDevice == 0 || inputDevice == 2) && has_mouse) + { + button[0] |= mouse_pressed[0]; + button[1] |= mouse_pressed[1]; + button[2] |= mouse_has_three_buttons ? mouse_pressed[2] : mouse_pressed[1]; + + if (input_grabbed) + { + mouseXC += mouse_x - 159; + mouseYC += mouse_y - 100; + } + + if ((!isNetworkGame || playerNum_ == thisPlayerNum) + && (!galagaMode || (playerNum_ == 2 || !twoPlayerMode || player[1].exploding_ticks > 0))) + { + set_mouse_position(159, 100); + } + } + + /* keyboard input */ + if ((inputDevice == 0 || inputDevice == 1) && !play_demo) + { + if (keysactive[keySettings[0]]) + this_player->y -= CURRENT_KEY_SPEED; + if (keysactive[keySettings[1]]) + this_player->y += CURRENT_KEY_SPEED; + + if (keysactive[keySettings[2]]) + this_player->x -= CURRENT_KEY_SPEED; + if (keysactive[keySettings[3]]) + this_player->x += CURRENT_KEY_SPEED; + + button[0] = button[0] || keysactive[keySettings[4]]; + button[3] = button[3] || keysactive[keySettings[5]]; + button[1] = button[1] || keysactive[keySettings[6]]; + button[2] = button[2] || keysactive[keySettings[7]]; + + if (constantPlay) + { + for (unsigned int i = 0; i < 4; i++) + button[i] = true; + + ++this_player->y; + this_player->x += constantLastX; + } + + // TODO: check if demo recording still works + if (record_demo) + { + bool new_input = false; + + for (unsigned int i = 0; i < 8; i++) + { + bool temp = demo_keys & (1 << i); + if (temp != keysactive[keySettings[i]]) + new_input = true; + } + + demo_keys_wait++; + + if (new_input) + { + demo_keys_wait = SDL_Swap16(demo_keys_wait); + efwrite(&demo_keys_wait, sizeof(Uint16), 1, demo_file); + + demo_keys = 0; + for (unsigned int i = 0; i < 8; i++) + demo_keys |= keysactive[keySettings[i]] ? (1 << i) : 0; + + fputc(demo_keys, demo_file); + + demo_keys_wait = 0; + } + } + } + + if (smoothies[9-1]) + { + *mouseY_ = this_player->y - (*mouseY_ - this_player->y); + mouseYC = -mouseYC; + } + + accelXC += this_player->x - *mouseX_; + accelYC += this_player->y - *mouseY_; + + if (mouseXC > 30) + mouseXC = 30; + else if (mouseXC < -30) + mouseXC = -30; + if (mouseYC > 30) + mouseYC = 30; + else if (mouseYC < -30) + mouseYC = -30; + + if (mouseXC > 0) + this_player->x += (mouseXC + 3) / 4; + else if (mouseXC < 0) + this_player->x += (mouseXC - 3) / 4; + if (mouseYC > 0) + this_player->y += (mouseYC + 3) / 4; + else if (mouseYC < 0) + this_player->y += (mouseYC - 3) / 4; + + if (mouseXC > 3) + accelXC++; + else if (mouseXC < -2) + accelXC--; + if (mouseYC > 2) + accelYC++; + else if (mouseYC < -2) + accelYC--; + + } /*endLevel*/ + + if (isNetworkGame && playerNum_ == thisPlayerNum) + { + Uint16 buttons = 0; + for (int i = 4 - 1; i >= 0; i--) + { + buttons <<= 1; + buttons |= button[i]; + } + + SDLNet_Write16(this_player->x - *mouseX_, &packet_state_out[0]->data[4]); + SDLNet_Write16(this_player->y - *mouseY_, &packet_state_out[0]->data[6]); + SDLNet_Write16(accelXC, &packet_state_out[0]->data[8]); + SDLNet_Write16(accelYC, &packet_state_out[0]->data[10]); + SDLNet_Write16(buttons, &packet_state_out[0]->data[12]); + + this_player->x = *mouseX_; + this_player->y = *mouseY_; + + button[0] = false; + button[1] = false; + button[2] = false; + button[3] = false; + + accelXC = 0; + accelYC = 0; + } + } /*isNetworkGame*/ + + /* --- Movement Routine Ending --- */ + + moveOk = true; + + if (isNetworkGame && !network_state_is_reset()) + { + if (playerNum_ != thisPlayerNum) + { + if (thisPlayerNum == 2) + difficultyLevel = SDLNet_Read16(&packet_state_in[0]->data[16]); + + Uint16 buttons = SDLNet_Read16(&packet_state_in[0]->data[12]); + for (int i = 0; i < 4; i++) + { + button[i] = buttons & 1; + buttons >>= 1; + } + + this_player->x += (Sint16)SDLNet_Read16(&packet_state_in[0]->data[4]); + this_player->y += (Sint16)SDLNet_Read16(&packet_state_in[0]->data[6]); + accelXC = (Sint16)SDLNet_Read16(&packet_state_in[0]->data[8]); + accelYC = (Sint16)SDLNet_Read16(&packet_state_in[0]->data[10]); + } + else + { + Uint16 buttons = SDLNet_Read16(&packet_state_out[network_delay]->data[12]); + for (int i = 0; i < 4; i++) + { + button[i] = buttons & 1; + buttons >>= 1; + } + + this_player->x += (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[4]); + this_player->y += (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[6]); + accelXC = (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[8]); + accelYC = (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[10]); + } + } + + /*Street-Fighter codes*/ + JE_SFCodes(playerNum_, this_player->x, this_player->y, *mouseX_, *mouseY_); + + if (moveOk) + { + /* END OF MOVEMENT ROUTINES */ + + /*Linking Routines*/ + + if (twoPlayerMode && !twoPlayerLinked && this_player->x == *mouseX_ && this_player->y == *mouseY_ + && abs(player[0].x - player[1].x) < 8 && abs(player[0].y - player[1].y) < 8 + && player[0].is_alive && player[1].is_alive && !galagaMode) + { + twoPlayerLinked = true; + } + + if (playerNum_ == 1 && (button[3-1] || button[2-1]) && !galagaMode) + twoPlayerLinked = false; + + if (twoPlayerMode && twoPlayerLinked && playerNum_ == 2 + && (this_player->x != *mouseX_ || this_player->y != *mouseY_)) + { + if (button[0]) + { + if (link_gun_analog) + { + linkGunDirec = link_gun_angle; + } + else + { + JE_real tempR; + + if (abs(this_player->x - *mouseX_) > abs(this_player->y - *mouseY_)) + tempR = (this_player->x - *mouseX_ > 0) ? M_PI_2 : (M_PI + M_PI_2); + else + tempR = (this_player->y - *mouseY_ > 0) ? 0 : M_PI; + + if (fabsf(linkGunDirec - tempR) < 0.3f) + linkGunDirec = tempR; + else if (linkGunDirec < tempR && linkGunDirec - tempR > -3.24f) + linkGunDirec += 0.2f; + else if (linkGunDirec - tempR < M_PI) + linkGunDirec -= 0.2f; + else + linkGunDirec += 0.2f; + } + + if (linkGunDirec >= (2 * M_PI)) + linkGunDirec -= (2 * M_PI); + else if (linkGunDirec < 0) + linkGunDirec += (2 * M_PI); + } + else if (!galagaMode) + { + twoPlayerLinked = false; + } + } + } + } + + if (levelEnd > 0 && all_players_dead()) + reallyEndLevel = true; + + /* End Level Fade-Out */ + if (this_player->is_alive && endLevel) + { + if (levelEnd == 0) + { + reallyEndLevel = true; + } + else + { + this_player->y -= levelEndWarp; + if (this_player->y < -200) + reallyEndLevel = true; + + tempI = 1; + tempW2 = this_player->y; + tempI2 = abs(41 - levelEnd); + if (tempI2 > 20) + tempI2 = 20; + + for (int z = 1; z <= tempI2; z++) + { + tempW2 += tempI; + tempI++; + } + + for (int z = 1; z <= tempI2; z++) + { + tempW2 -= tempI; + tempI--; + if (tempW2 > 0 && tempW2 < 170) + { + if (shipGr_ == 0) + { + blit_sprite2x2(VGAScreen, this_player->x - 17, tempW2 - 7, *shapes9ptr_, 13); + blit_sprite2x2(VGAScreen, this_player->x + 7 , tempW2 - 7, *shapes9ptr_, 51); + } + else if (shipGr_ == 1) + { + blit_sprite2x2(VGAScreen, this_player->x - 17, tempW2 - 7, *shapes9ptr_, 220); + blit_sprite2x2(VGAScreen, this_player->x + 7 , tempW2 - 7, *shapes9ptr_, 222); + } + else + { + blit_sprite2x2(VGAScreen, this_player->x - 5, tempW2 - 7, *shapes9ptr_, shipGr_); + } + } + } + } + } + + if (play_demo) + JE_dString(VGAScreen, 115, 10, miscText[7], SMALL_FONT_SHAPES); // insert coin + + if (this_player->is_alive && !endLevel) + { + if (!twoPlayerLinked || playerNum_ < 2) + { + if (!twoPlayerMode || shipGr2 != 0) // if not dragonwing + { + if (this_player->sidekick[LEFT_SIDEKICK].style == 0) + { + this_player->sidekick[LEFT_SIDEKICK].x = *mouseX_ - 14; + this_player->sidekick[LEFT_SIDEKICK].y = *mouseY_; + } + + if (this_player->sidekick[RIGHT_SIDEKICK].style == 0) + { + this_player->sidekick[RIGHT_SIDEKICK].x = *mouseX_ + 16; + this_player->sidekick[RIGHT_SIDEKICK].y = *mouseY_; + } + } + + if (this_player->x_friction_ticks > 0) + { + --this_player->x_friction_ticks; + } + else + { + this_player->x_friction_ticks = 1; + + if (this_player->x_velocity < 0) + ++this_player->x_velocity; + else if (this_player->x_velocity > 0) + --this_player->x_velocity; + } + + if (this_player->y_friction_ticks > 0) + { + --this_player->y_friction_ticks; + } + else + { + this_player->y_friction_ticks = 2; + + if (this_player->y_velocity < 0) + ++this_player->y_velocity; + else if (this_player->y_velocity > 0) + --this_player->y_velocity; + } + + this_player->x_velocity += accelXC; + this_player->y_velocity += accelYC; + + this_player->x_velocity = MIN(MAX(-4, this_player->x_velocity), 4); + this_player->y_velocity = MIN(MAX(-4, this_player->y_velocity), 4); + + this_player->x += this_player->x_velocity; + this_player->y += this_player->y_velocity; + + // if player moved, add new ship x, y history entry + if (this_player->x - *mouseX_ != 0 || this_player->y - *mouseY_ != 0) + { + for (uint i = 1; i < COUNTOF(player->old_x); ++i) + { + this_player->old_x[i - 1] = this_player->old_x[i]; + this_player->old_y[i - 1] = this_player->old_y[i]; + } + this_player->old_x[COUNTOF(player->old_x) - 1] = this_player->x; + this_player->old_y[COUNTOF(player->old_x) - 1] = this_player->y; + } + } + else /*twoPlayerLinked*/ + { + if (shipGr_ == 0) + this_player->x = player[0].x - 1; + else + this_player->x = player[0].x; + this_player->y = player[0].y + 8; + + this_player->x_velocity = player[0].x_velocity; + this_player->y_velocity = 4; + + // turret direction marker/shield + shotMultiPos[SHOT_MISC] = 0; + JE_initPlayerShot(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec + 0.2f) * 26), this_player->y + roundf(cosf(linkGunDirec + 0.2f) * 26), *mouseX_, *mouseY_, 148, playerNum_); + shotMultiPos[SHOT_MISC] = 0; + JE_initPlayerShot(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec - 0.2f) * 26), this_player->y + roundf(cosf(linkGunDirec - 0.2f) * 26), *mouseX_, *mouseY_, 148, playerNum_); + shotMultiPos[SHOT_MISC] = 0; + JE_initPlayerShot(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec) * 26), this_player->y + roundf(cosf(linkGunDirec) * 26), *mouseX_, *mouseY_, 147, playerNum_); + + if (shotRepeat[SHOT_REAR] > 0) + { + --shotRepeat[SHOT_REAR]; + } + else if (button[1-1]) + { + shotMultiPos[SHOT_REAR] = 0; + JE_initPlayerShot(0, SHOT_REAR, this_player->x + 1 + roundf(sinf(linkGunDirec) * 20), this_player->y + roundf(cosf(linkGunDirec) * 20), *mouseX_, *mouseY_, linkGunWeapons[this_player->items.weapon[REAR_WEAPON].id-1], playerNum_); + playerShotData[b].shotXM = -roundf(sinf(linkGunDirec) * playerShotData[b].shotYM); + playerShotData[b].shotYM = -roundf(cosf(linkGunDirec) * playerShotData[b].shotYM); + + switch (this_player->items.weapon[REAR_WEAPON].id) + { + case 27: + case 32: + case 10: + temp = roundf(linkGunDirec * (16 / (2 * M_PI))); /*16 directions*/ + playerShotData[b].shotGr = linkMultiGr[temp]; + break; + case 28: + case 33: + case 11: + temp = roundf(linkGunDirec * (16 / (2 * M_PI))); /*16 directions*/ + playerShotData[b].shotGr = linkSonicGr[temp]; + break; + case 30: + case 35: + case 14: + if (linkGunDirec > M_PI_2 && linkGunDirec < M_PI + M_PI_2) + { + playerShotData[b].shotYC = 1; + } + break; + case 38: + case 22: + temp = roundf(linkGunDirec * (16 / (2 * M_PI))); /*16 directions*/ + playerShotData[b].shotGr = linkMult2Gr[temp]; + break; + } + } + } + } + + if (!endLevel) + { + if (this_player->x > 256) + { + this_player->x = 256; + constantLastX = -constantLastX; + } + if (this_player->x < 40) + { + this_player->x = 40; + constantLastX = -constantLastX; + } + + if (isNetworkGame && playerNum_ == 1) + { + if (this_player->y > 154) + this_player->y = 154; + } + else + { + if (this_player->y > 160) + this_player->y = 160; + } + + if (this_player->y < 10) + this_player->y = 10; + + tempI2 = this_player->x_velocity / 2; + tempI2 += (this_player->x - *mouseX_) / 6; + + if (tempI2 < -2) + tempI2 = -2; + else if (tempI2 > 2) + tempI2 = 2; + + tempI = tempI2 * 2 + shipGr_; + + explosionFollowAmountX = this_player->x - this_player->last_x_explosion_follow; + explosionFollowAmountY = this_player->y - this_player->last_y_explosion_follow; + + if (explosionFollowAmountY < 0) + explosionFollowAmountY = 0; + + this_player->last_x_explosion_follow = this_player->x; + this_player->last_y_explosion_follow = this_player->y; + + if (shipGr_ == 0) + { + if (background2) + { + blit_sprite2x2_darken(VGAScreen, this_player->x - 17 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, tempI + 13); + blit_sprite2x2_darken(VGAScreen, this_player->x + 7 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, tempI + 51); + if (superWild) + { + blit_sprite2x2_darken(VGAScreen, this_player->x - 16 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, tempI + 13); + blit_sprite2x2_darken(VGAScreen, this_player->x + 6 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, tempI + 51); + } + } + } + else if (shipGr_ == 1) + { + if (background2) + { + blit_sprite2x2_darken(VGAScreen, this_player->x - 17 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, 220); + blit_sprite2x2_darken(VGAScreen, this_player->x + 7 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, 222); + } + } + else + { + if (background2) + { + blit_sprite2x2_darken(VGAScreen, this_player->x - 5 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, tempI); + if (superWild) + { + blit_sprite2x2_darken(VGAScreen, this_player->x - 4 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, tempI); + } + } + } + + if (this_player->invulnerable_ticks > 0) + { + --this_player->invulnerable_ticks; + + if (shipGr_ == 0) + { + blit_sprite2x2_blend(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, tempI + 13); + blit_sprite2x2_blend(VGAScreen, this_player->x + 7 , this_player->y - 7, *shapes9ptr_, tempI + 51); + } + else if (shipGr_ == 1) + { + blit_sprite2x2_blend(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, 220); + blit_sprite2x2_blend(VGAScreen, this_player->x + 7 , this_player->y - 7, *shapes9ptr_, 222); + } + else + blit_sprite2x2_blend(VGAScreen, this_player->x - 5, this_player->y - 7, *shapes9ptr_, tempI); + } + else + { + if (shipGr_ == 0) + { + blit_sprite2x2(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, tempI + 13); + blit_sprite2x2(VGAScreen, this_player->x + 7, this_player->y - 7, *shapes9ptr_, tempI + 51); + } + else if (shipGr_ == 1) + { + blit_sprite2x2(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, 220); + blit_sprite2x2(VGAScreen, this_player->x + 7, this_player->y - 7, *shapes9ptr_, 222); + switch (tempI) + { + case 5: + blit_sprite2(VGAScreen, this_player->x - 17, this_player->y + 7, *shapes9ptr_, 40); + tempW = this_player->x - 7; + tempI2 = -2; + break; + case 3: + blit_sprite2(VGAScreen, this_player->x - 17, this_player->y + 7, *shapes9ptr_, 39); + tempW = this_player->x - 7; + tempI2 = -1; + break; + case 1: + tempI2 = 0; + break; + case -1: + blit_sprite2(VGAScreen, this_player->x + 19, this_player->y + 7, *shapes9ptr_, 58); + tempW = this_player->x + 9; + tempI2 = 1; + break; + case -3: + blit_sprite2(VGAScreen, this_player->x + 19, this_player->y + 7, *shapes9ptr_, 59); + tempW = this_player->x + 9; + tempI2 = 2; + break; + } + if (tempI2 != 0) // NortSparks + { + if (shotRepeat[SHOT_NORTSPARKS] > 0) + { + --shotRepeat[SHOT_NORTSPARKS]; + } + else + { + JE_initPlayerShot(0, SHOT_NORTSPARKS, tempW + (mt_rand() % 8) - 4, this_player->y + (mt_rand() % 8) - 4, *mouseX_, *mouseY_, 671, 1); + shotRepeat[SHOT_NORTSPARKS] = abs(tempI2) - 1; + } + } + } + else + blit_sprite2x2(VGAScreen, this_player->x - 5, this_player->y - 7, *shapes9ptr_, tempI); + } + } // !endLevel + + /*Options Location*/ + if (playerNum_ == 2 && shipGr_ == 0) // if dragonwing + { + if (this_player->sidekick[LEFT_SIDEKICK].style == 0) + { + this_player->sidekick[LEFT_SIDEKICK].x = this_player->x - 14 + tempI; + this_player->sidekick[LEFT_SIDEKICK].y = this_player->y; + } + + if (this_player->sidekick[RIGHT_SIDEKICK].style == 0) + { + this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x + 17 + tempI; + this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y; + } + } + + if (moveOk) + { + if (this_player->is_alive) + { + if (!endLevel) + { + this_player->delta_x_shot_move = this_player->x - this_player->last_x_shot_move; + this_player->delta_y_shot_move = this_player->y - this_player->last_y_shot_move; + + /* PLAYER SHOT Change */ + if (button[4-1]) + { + portConfigChange = true; + if (portConfigDone) + { + shotMultiPos[SHOT_REAR] = 0; + + if (superArcadeMode != SA_NONE && superArcadeMode <= SA_NORTSHIPZ) + { + shotMultiPos[SHOT_SPECIAL] = 0; + shotMultiPos[SHOT_SPECIAL2] = 0; + if (player[0].items.special == SASpecialWeapon[superArcadeMode-1]) + { + player[0].items.special = SASpecialWeaponB[superArcadeMode-1]; + this_player->weapon_mode = 2; + } + else + { + player[0].items.special = SASpecialWeapon[superArcadeMode-1]; + this_player->weapon_mode = 1; + } + } + else if (++this_player->weapon_mode > JE_portConfigs()) + this_player->weapon_mode = 1; + + JE_drawPortConfigButtons(); + portConfigDone = false; + } + } + + /* PLAYER SHOT Creation */ + + /*SpecialShot*/ + if (!galagaMode) + JE_doSpecialShot(playerNum_, &this_player->armor, &this_player->shield); + + /*Normal Main Weapons*/ + if (!(twoPlayerLinked && playerNum_ == 2)) + { + int min, max; + + if (!twoPlayerMode) + min = 1, max = 2; + else + min = max = playerNum_; + + for (temp = min - 1; temp < max; temp++) + { + const uint item = this_player->items.weapon[temp].id; + + if (item > 0) + { + if (shotRepeat[temp] > 0) + { + --shotRepeat[temp]; + } + else if (button[1-1]) + { + const uint item_power = galagaMode ? 0 : this_player->items.weapon[temp].power - 1, + item_mode = (temp == REAR_WEAPON) ? this_player->weapon_mode - 1 : 0; + + JE_initPlayerShot(item, temp, this_player->x, this_player->y, *mouseX_, *mouseY_, weaponPort[item].op[item_mode][item_power], playerNum_); + } + } + } + } + + /*Super Charge Weapons*/ + if (playerNum_ == 2) + { + + if (!twoPlayerLinked) + blit_sprite2(VGAScreen, this_player->x + (shipGr_ == 0) + 1, this_player->y - 13, eShapes6, 77 + chargeLevel + chargeGr * 19); + + if (chargeGrWait > 0) + { + chargeGrWait--; + } + else + { + chargeGr++; + if (chargeGr == 4) + chargeGr = 0; + chargeGrWait = 3; + } + + if (chargeLevel > 0) + { + fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 193); + } + + if (chargeWait > 0) + { + chargeWait--; + } + else + { + if (chargeLevel < chargeMax) + chargeLevel++; + + chargeWait = 28 - this_player->items.weapon[REAR_WEAPON].power * 2; + if (difficultyLevel > 3) + chargeWait -= 5; + } + + if (chargeLevel > 0) + fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 204); + + if (shotRepeat[SHOT_P2_CHARGE] > 0) + { + --shotRepeat[SHOT_P2_CHARGE]; + } + else if (button[1-1] && (!twoPlayerLinked || chargeLevel > 0)) + { + shotMultiPos[SHOT_P2_CHARGE] = 0; + JE_initPlayerShot(16, SHOT_P2_CHARGE, this_player->x, this_player->y, *mouseX_, *mouseY_, chargeGunWeapons[player[1].items.weapon[REAR_WEAPON].id-1] + chargeLevel, playerNum_); + + if (chargeLevel > 0) + fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 193); + + chargeLevel = 0; + chargeWait = 30 - this_player->items.weapon[REAR_WEAPON].power * 2; + } + } + + /*SUPER BOMB*/ + temp = playerNum_; + if (temp == 0) + temp = 1; /*Get whether player 1 or 2*/ + + if (player[temp-1].superbombs > 0) + { + if (shotRepeat[SHOT_P1_SUPERBOMB + temp-1] > 0) + { + --shotRepeat[SHOT_P1_SUPERBOMB + temp-1]; + } + else if (button[3-1] || button[2-1]) + { + --player[temp-1].superbombs; + shotMultiPos[SHOT_P1_SUPERBOMB + temp-1] = 0; + JE_initPlayerShot(16, SHOT_P1_SUPERBOMB + temp-1, this_player->x, this_player->y, *mouseX_, *mouseY_, 535, playerNum_); + } + } + + // sidekicks + + if (this_player->sidekick[LEFT_SIDEKICK].style == 4 && this_player->sidekick[RIGHT_SIDEKICK].style == 4) + optionSatelliteRotate += 0.2f; + else if (this_player->sidekick[LEFT_SIDEKICK].style == 4 || this_player->sidekick[RIGHT_SIDEKICK].style == 4) + optionSatelliteRotate += 0.15f; + + switch (this_player->sidekick[LEFT_SIDEKICK].style) + { + case 1: // trailing + case 3: + this_player->sidekick[LEFT_SIDEKICK].x = this_player->old_x[COUNTOF(player->old_x) / 2 - 1]; + this_player->sidekick[LEFT_SIDEKICK].y = this_player->old_y[COUNTOF(player->old_x) / 2 - 1]; + break; + case 2: // front-mounted + this_player->sidekick[LEFT_SIDEKICK].x = this_player->x; + this_player->sidekick[LEFT_SIDEKICK].y = MAX(10, this_player->y - 20); + break; + case 4: // orbitting + this_player->sidekick[LEFT_SIDEKICK].x = this_player->x + roundf(sinf(optionSatelliteRotate) * 20); + this_player->sidekick[LEFT_SIDEKICK].y = this_player->y + roundf(cosf(optionSatelliteRotate) * 20); + break; + } + + switch (this_player->sidekick[RIGHT_SIDEKICK].style) + { + case 4: // orbitting + this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x - roundf(sinf(optionSatelliteRotate) * 20); + this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y - roundf(cosf(optionSatelliteRotate) * 20); + break; + case 1: // trailing + case 3: + this_player->sidekick[RIGHT_SIDEKICK].x = this_player->old_x[0]; + this_player->sidekick[RIGHT_SIDEKICK].y = this_player->old_y[0]; + break; + case 2: // front-mounted + if (!optionAttachmentLinked) + { + this_player->sidekick[RIGHT_SIDEKICK].y += optionAttachmentMove / 2; + if (optionAttachmentMove >= -2) + { + if (optionAttachmentReturn) + temp = 2; + else + temp = 0; + + if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) + 5) + { + temp = 2; + optionAttachmentMove -= 1 + optionAttachmentReturn; + } + else if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) - 0) + { + temp = 3; + if (optionAttachmentMove > 0) + optionAttachmentMove--; + else + optionAttachmentMove++; + } + else if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) - 5) + { + temp = 2; + optionAttachmentMove++; + } + else if (optionAttachmentMove < 2 + optionAttachmentReturn * 4) + { + optionAttachmentMove += 1 + optionAttachmentReturn; + } + + if (optionAttachmentReturn) + temp = temp * 2; + if (abs(this_player->sidekick[RIGHT_SIDEKICK].x - this_player->x) < temp) + temp = 1; + + if (this_player->sidekick[RIGHT_SIDEKICK].x > this_player->x) + this_player->sidekick[RIGHT_SIDEKICK].x -= temp; + else if (this_player->sidekick[RIGHT_SIDEKICK].x < this_player->x) + this_player->sidekick[RIGHT_SIDEKICK].x += temp; + + if (abs(this_player->sidekick[RIGHT_SIDEKICK].y - (this_player->y - 20)) + abs(this_player->sidekick[RIGHT_SIDEKICK].x - this_player->x) < 8) + { + optionAttachmentLinked = true; + soundQueue[2] = S_CLINK; + } + + if (button[3-1]) + optionAttachmentReturn = true; + } + else // sidekick needs to catch up to player + { + optionAttachmentMove += 1 + optionAttachmentReturn; + JE_setupExplosion(this_player->sidekick[RIGHT_SIDEKICK].x + 1, this_player->sidekick[RIGHT_SIDEKICK].y + 10, 0, 0, false, false); + } + } + else + { + this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x; + this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y - 20; + if (button[3-1]) + { + optionAttachmentLinked = false; + optionAttachmentReturn = false; + optionAttachmentMove = -20; + soundQueue[3] = S_WEAPON_26; + } + } + + if (this_player->sidekick[RIGHT_SIDEKICK].y < 10) + this_player->sidekick[RIGHT_SIDEKICK].y = 10; + break; + } + + if (playerNum_ == 2 || !twoPlayerMode) // if player has sidekicks + { + for (uint i = 0; i < COUNTOF(player->items.sidekick); ++i) + { + uint shot_i = (i == 0) ? SHOT_LEFT_SIDEKICK : SHOT_RIGHT_SIDEKICK; + + JE_OptionType *this_option = &options[this_player->items.sidekick[i]]; + + // fire/refill sidekick + if (this_option->wport > 0) + { + if (shotRepeat[shot_i] > 0) + { + --shotRepeat[shot_i]; + } + else + { + const int ammo_max = this_player->sidekick[i].ammo_max; + + if (ammo_max > 0) // sidekick has limited ammo + { + if (this_player->sidekick[i].ammo_refill_ticks > 0) + { + --this_player->sidekick[i].ammo_refill_ticks; + } + else // refill one ammo + { + this_player->sidekick[i].ammo_refill_ticks = this_player->sidekick[i].ammo_refill_ticks_max; + + if (this_player->sidekick[i].ammo < ammo_max) + ++this_player->sidekick[i].ammo; + + // draw sidekick refill ammo gauge + const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i] + 13; + draw_segmented_gauge(VGAScreenSeg, 284, y, 112, 2, 2, MAX(1, ammo_max / 10), this_player->sidekick[i].ammo); + } + + if (button[1 + i] && this_player->sidekick[i].ammo > 0) + { + JE_initPlayerShot(this_option->wport, shot_i, this_player->sidekick[i].x, this_player->sidekick[i].y, *mouseX_, *mouseY_, this_option->wpnum + this_player->sidekick[i].charge, playerNum_); + + --this_player->sidekick[i].ammo; + if (this_player->sidekick[i].charge > 0) + { + shotMultiPos[shot_i] = 0; + this_player->sidekick[i].charge = 0; + } + this_player->sidekick[i].charge_ticks = 20; + this_player->sidekick[i].animation_enabled = true; + + // draw sidekick discharge ammo gauge + const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i] + 13; + fill_rectangle_xy(VGAScreenSeg, 284, y, 312, y + 2, 0); + draw_segmented_gauge(VGAScreenSeg, 284, y, 112, 2, 2, MAX(1, ammo_max / 10), this_player->sidekick[i].ammo); + } + } + else // has infinite ammo + { + if (button[0] || button[1 + i]) + { + JE_initPlayerShot(this_option->wport, shot_i, this_player->sidekick[i].x, this_player->sidekick[i].y, *mouseX_, *mouseY_, this_option->wpnum + this_player->sidekick[i].charge, playerNum_); + + if (this_player->sidekick[i].charge > 0) + { + shotMultiPos[shot_i] = 0; + this_player->sidekick[i].charge = 0; + } + this_player->sidekick[i].charge_ticks = 20; + this_player->sidekick[i].animation_enabled = true; + } + } + } + } + } + } // end of if player has sidekicks + } // !endLevel + } // this_player->is_alive + } // moveOK + + // draw sidekicks + if ((playerNum_ == 2 || !twoPlayerMode) && !endLevel) + { + for (uint i = 0; i < COUNTOF(this_player->sidekick); ++i) + { + JE_OptionType *this_option = &options[this_player->items.sidekick[i]]; + + if (this_option->option > 0) + { + if (this_player->sidekick[i].animation_enabled) + { + if (++this_player->sidekick[i].animation_frame >= this_option->ani) + { + this_player->sidekick[i].animation_frame = 0; + this_player->sidekick[i].animation_enabled = (this_option->option == 1); + } + } + + const int x = this_player->sidekick[i].x, + y = this_player->sidekick[i].y; + const uint sprite = this_option->gr[this_player->sidekick[i].animation_frame] + this_player->sidekick[i].charge; + + if (this_player->sidekick[i].style == 1 || this_player->sidekick[i].style == 2) + blit_sprite2x2(VGAScreen, x - 6, y, eShapes6, sprite); + else + blit_sprite2(VGAScreen, x, y, shapes9, sprite); + } + + if (--this_player->sidekick[i].charge_ticks == 0) + { + if (this_player->sidekick[i].charge < this_option->pwr) + ++this_player->sidekick[i].charge; + this_player->sidekick[i].charge_ticks = 20; + } + } + } +} + +void JE_mainGamePlayerFunctions( void ) +{ + /*PLAYER MOVEMENT/MOUSE ROUTINES*/ + + if (endLevel && levelEnd > 0) + { + levelEnd--; + levelEndWarp++; + } + + /*Reset Street-Fighter commands*/ + memset(SFExecuted, 0, sizeof(SFExecuted)); + + portConfigChange = false; + + if (twoPlayerMode) + { + JE_playerMovement(&player[0], + !galagaMode ? inputDevice[0] : 0, 1, shipGr, shipGrPtr, + &mouseX, &mouseY); + JE_playerMovement(&player[1], + !galagaMode ? inputDevice[1] : 0, 2, shipGr2, shipGr2ptr, + &mouseXB, &mouseYB); + } + else + { + JE_playerMovement(&player[0], + 0, 1, shipGr, shipGrPtr, + &mouseX, &mouseY); + } + + /* == Parallax Map Scrolling == */ + if (twoPlayerMode) + { + tempX = (player[0].x + player[1].x) / 2; + } else { + tempX = player[0].x; + } + + tempW = floorf((260.0f - (tempX - 36.0f)) / (260.0f - 36.0f) * (24.0f * 3.0f) - 1.0f); + mapX3Ofs = tempW; + mapX3Pos = mapX3Ofs % 24; + mapX3bpPos = 1 - (mapX3Ofs / 24); + + mapX2Ofs = (tempW * 2) / 3; + mapX2Pos = mapX2Ofs % 24; + mapX2bpPos = 1 - (mapX2Ofs / 24); + + oldMapXOfs = mapXOfs; + mapXOfs = mapX2Ofs / 2; + mapXPos = mapXOfs % 24; + mapXbpPos = 1 - (mapXOfs / 24); + + if (background3x1) + { + mapX3Ofs = mapXOfs; + mapX3Pos = mapXPos; + mapX3bpPos = mapXbpPos - 1; + } +} + +const char *JE_getName( JE_byte pnum ) +{ + if (pnum == thisPlayerNum && network_player_name[0] != '\0') + return network_player_name; + else if (network_opponent_name[0] != '\0') + return network_opponent_name; + + return miscText[47 + pnum]; +} + +void JE_playerCollide( Player *this_player, JE_byte playerNum_ ) +{ + char tempStr[256]; + + for (int z = 0; z < 100; z++) + { + if (enemyAvail[z] != 1) + { + tempI3 = enemy[z].ex + enemy[z].mapoffset; + + if (abs(this_player->x - tempI3) < 12 && abs(this_player->y - enemy[z].ey) < 14) + { /*Collide*/ + tempI4 = enemy[z].evalue; + if (tempI4 > 29999) + { + if (tempI4 == 30000) // spawn dragonwing in galaga mode, otherwise just a purple ball + { + this_player->cash += 100; + + if (!galagaMode) + { + handle_got_purple_ball(this_player); + } + else + { + // spawn the dragonwing? + if (twoPlayerMode) + this_player->cash += 2400; + twoPlayerMode = true; + twoPlayerLinked = true; + player[1].items.weapon[REAR_WEAPON].power = 1; + player[1].armor = 10; + player[1].is_alive = true; + } + enemyAvail[z] = 1; + soundQueue[7] = S_POWERUP; + } + else if (superArcadeMode != SA_NONE && tempI4 > 30000) + { + shotMultiPos[SHOT_FRONT] = 0; + shotRepeat[SHOT_FRONT] = 10; + + tempW = SAWeapon[superArcadeMode-1][tempI4 - 30000-1]; + + // if picked up already-owned weapon, power weapon up + if (tempW == player[0].items.weapon[FRONT_WEAPON].id) + { + this_player->cash += 1000; + power_up_weapon(this_player, FRONT_WEAPON); + } + // else weapon also gives purple ball + else + { + handle_got_purple_ball(this_player); + } + + player[0].items.weapon[FRONT_WEAPON].id = tempW; + this_player->cash += 200; + soundQueue[7] = S_POWERUP; + enemyAvail[z] = 1; + } + else if (tempI4 > 32100) + { + if (playerNum_ == 1) + { + this_player->cash += 250; + player[0].items.special = tempI4 - 32100; + shotMultiPos[SHOT_SPECIAL] = 0; + shotRepeat[SHOT_SPECIAL] = 10; + shotMultiPos[SHOT_SPECIAL2] = 0; + shotRepeat[SHOT_SPECIAL2] = 0; + + if (isNetworkGame) + sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], special[tempI4 - 32100].name); + else if (twoPlayerMode) + sprintf(tempStr, "%s %s", miscText[43-1], special[tempI4 - 32100].name); + else + sprintf(tempStr, "%s %s", miscText[64-1], special[tempI4 - 32100].name); + JE_drawTextWindow(tempStr); + soundQueue[7] = S_POWERUP; + enemyAvail[z] = 1; + } + } + else if (tempI4 > 32000) + { + if (playerNum_ == 2) + { + enemyAvail[z] = 1; + if (isNetworkGame) + sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], options[tempI4 - 32000].name); + else + sprintf(tempStr, "%s %s", miscText[44-1], options[tempI4 - 32000].name); + JE_drawTextWindow(tempStr); + + // if picked up a different sidekick than player already has, then reset sidekicks to least powerful, else power them up + if (tempI4 - 32000u != player[1].items.sidekick_series) + { + player[1].items.sidekick_series = tempI4 - 32000; + player[1].items.sidekick_level = 101; + } + else if (player[1].items.sidekick_level < 103) + { + ++player[1].items.sidekick_level; + } + + uint temp = player[1].items.sidekick_level - 100 - 1; + for (uint i = 0; i < COUNTOF(player[1].items.sidekick); ++i) + player[1].items.sidekick[i] = optionSelect[player[1].items.sidekick_series][temp][i]; + + + shotMultiPos[SHOT_LEFT_SIDEKICK] = 0; + shotMultiPos[SHOT_RIGHT_SIDEKICK] = 0; + JE_drawOptions(); + soundQueue[7] = S_POWERUP; + } + else if (onePlayerAction) + { + enemyAvail[z] = 1; + sprintf(tempStr, "%s %s", miscText[64-1], options[tempI4 - 32000].name); + JE_drawTextWindow(tempStr); + + for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i) + player[0].items.sidekick[i] = tempI4 - 32000; + shotMultiPos[SHOT_LEFT_SIDEKICK] = 0; + shotMultiPos[SHOT_RIGHT_SIDEKICK] = 0; + + JE_drawOptions(); + soundQueue[7] = S_POWERUP; + } + if (enemyAvail[z] == 1) + this_player->cash += 250; + } + else if (tempI4 > 31000) + { + this_player->cash += 250; + if (playerNum_ == 2) + { + if (isNetworkGame) + sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], weaponPort[tempI4 - 31000].name); + else + sprintf(tempStr, "%s %s", miscText[44-1], weaponPort[tempI4 - 31000].name); + JE_drawTextWindow(tempStr); + player[1].items.weapon[REAR_WEAPON].id = tempI4 - 31000; + shotMultiPos[SHOT_REAR] = 0; + enemyAvail[z] = 1; + soundQueue[7] = S_POWERUP; + } + else if (onePlayerAction) + { + sprintf(tempStr, "%s %s", miscText[64-1], weaponPort[tempI4 - 31000].name); + JE_drawTextWindow(tempStr); + player[0].items.weapon[REAR_WEAPON].id = tempI4 - 31000; + shotMultiPos[SHOT_REAR] = 0; + enemyAvail[z] = 1; + soundQueue[7] = S_POWERUP; + + if (player[0].items.weapon[REAR_WEAPON].power == 0) // does this ever happen? + player[0].items.weapon[REAR_WEAPON].power = 1; + } + } + else if (tempI4 > 30000) + { + if (playerNum_ == 1 && twoPlayerMode) + { + if (isNetworkGame) + sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], weaponPort[tempI4 - 30000].name); + else + sprintf(tempStr, "%s %s", miscText[43-1], weaponPort[tempI4 - 30000].name); + JE_drawTextWindow(tempStr); + player[0].items.weapon[FRONT_WEAPON].id = tempI4 - 30000; + shotMultiPos[SHOT_FRONT] = 0; + enemyAvail[z] = 1; + soundQueue[7] = S_POWERUP; + } + else if (onePlayerAction) + { + sprintf(tempStr, "%s %s", miscText[64-1], weaponPort[tempI4 - 30000].name); + JE_drawTextWindow(tempStr); + player[0].items.weapon[FRONT_WEAPON].id = tempI4 - 30000; + shotMultiPos[SHOT_FRONT] = 0; + enemyAvail[z] = 1; + soundQueue[7] = S_POWERUP; + } + + if (enemyAvail[z] == 1) + { + player[0].items.special = specialArcadeWeapon[tempI4 - 30000-1]; + if (player[0].items.special > 0) + { + shotMultiPos[SHOT_SPECIAL] = 0; + shotRepeat[SHOT_SPECIAL] = 0; + shotMultiPos[SHOT_SPECIAL2] = 0; + shotRepeat[SHOT_SPECIAL2] = 0; + } + this_player->cash += 250; + } + + } + } + else if (tempI4 > 20000) + { + if (twoPlayerLinked) + { + // share the armor evenly between linked players + for (uint i = 0; i < COUNTOF(player); ++i) + { + player[i].armor += (tempI4 - 20000) / COUNTOF(player); + if (player[i].armor > 28) + player[i].armor = 28; + } + } + else + { + this_player->armor += tempI4 - 20000; + if (this_player->armor > 28) + this_player->armor = 28; + } + enemyAvail[z] = 1; + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + JE_drawArmor(); + VGAScreen = game_screen; /* side-effect of game_screen */ + soundQueue[7] = S_POWERUP; + } + else if (tempI4 > 10000 && enemyAvail[z] == 2) + { + if (!bonusLevel) + { + play_song(30); /*Zanac*/ + bonusLevel = true; + nextLevel = tempI4 - 10000; + enemyAvail[z] = 1; + displayTime = 150; + } + } + else if (enemy[z].scoreitem) + { + enemyAvail[z] = 1; + soundQueue[7] = S_ITEM; + if (tempI4 == 1) + { + cubeMax++; + soundQueue[3] = V_DATA_CUBE; + } + else if (tempI4 == -1) // got front weapon powerup + { + if (isNetworkGame) + sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], miscText[45-1]); + else if (twoPlayerMode) + sprintf(tempStr, "%s %s", miscText[43-1], miscText[45-1]); + else + strcpy(tempStr, miscText[45-1]); + JE_drawTextWindow(tempStr); + + power_up_weapon(&player[0], FRONT_WEAPON); + soundQueue[7] = S_POWERUP; + } + else if (tempI4 == -2) // got rear weapon powerup + { + if (isNetworkGame) + sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], miscText[46-1]); + else if (twoPlayerMode) + sprintf(tempStr, "%s %s", miscText[44-1], miscText[46-1]); + else + strcpy(tempStr, miscText[46-1]); + JE_drawTextWindow(tempStr); + + power_up_weapon(twoPlayerMode ? &player[1] : &player[0], REAR_WEAPON); + soundQueue[7] = S_POWERUP; + } + else if (tempI4 == -3) + { + // picked up orbiting asteroid killer + shotMultiPos[SHOT_MISC] = 0; + JE_initPlayerShot(0, SHOT_MISC, this_player->x, this_player->y, mouseX, mouseY, 104, playerNum_); + shotAvail[z] = 0; + } + else if (tempI4 == -4) + { + if (player[playerNum_-1].superbombs < 10) + ++player[playerNum_-1].superbombs; + } + else if (tempI4 == -5) + { + player[0].items.weapon[FRONT_WEAPON].id = 25; // HOT DOG! + player[0].items.weapon[REAR_WEAPON].id = 26; + player[1].items.weapon[REAR_WEAPON].id = 26; + + player[0].last_items = player[0].items; + + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].weapon_mode = 1; + + memset(shotMultiPos, 0, sizeof(shotMultiPos)); + } + else if (twoPlayerLinked) + { + // players get equal share of pick-up cash when linked + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].cash += tempI4 / COUNTOF(player); + } + else + { + this_player->cash += tempI4; + } + JE_setupExplosion(tempI3, enemy[z].ey, 0, enemyDat[enemy[z].enemytype].explosiontype, true, false); + } + else if (this_player->invulnerable_ticks == 0 && enemyAvail[z] == 0 && + enemyDat[enemy[z].enemytype].explosiontype % 2 == 0) + { + + tempI3 = enemy[z].armorleft; + if (tempI3 > damageRate) + tempI3 = damageRate; + + JE_playerDamage(tempI3, this_player); + + // player ship gets push-back from collision + if (enemy[z].armorleft > 0) + { + this_player->x_velocity += (enemy[z].exc * enemy[z].armorleft) / 2; + this_player->y_velocity += (enemy[z].eyc * enemy[z].armorleft) / 2; + } + + tempI = enemy[z].armorleft; + if (tempI == 255) + tempI = 30000; + + temp = enemy[z].linknum; + if (temp == 0) + temp = 255; + + b = z; + + if (tempI > tempI2) + { + if (enemy[z].armorleft != 255) + enemy[z].armorleft -= tempI3; + soundQueue[5] = S_ENEMY_HIT; + } + else + { + for (temp2 = 0; temp2 < 100; temp2++) + { + if (enemyAvail[temp2] != 1) + { + temp3 = enemy[temp2].linknum; + if (temp2 == b || + (temp != 255 && + (temp == temp3 || temp - 100 == temp3 + || (temp3 > 40 && temp3 / 20 == temp / 20 && temp3 <= temp)))) + { + tempI3 = enemy[temp2].ex + enemy[temp2].mapoffset; + + enemy[temp2].linknum = 0; + + enemyAvail[temp2] = 1; + + if (enemyDat[enemy[temp2].enemytype].esize == 1) + { + JE_setupExplosionLarge(enemy[temp2].enemyground, enemy[temp2].explonum, tempI3, enemy[temp2].ey); + soundQueue[6] = S_EXPLOSION_9; + } + else + { + JE_setupExplosion(tempI3, enemy[temp2].ey, 0, 1, false, false); + soundQueue[5] = S_EXPLOSION_4; + } + } + } + } + enemyAvail[z] = 1; + } + } + } + + } + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/mainint.h b/alienblaster/project/jni/application/opentyrian/src/mainint.h new file mode 100644 index 000000000..abb6504a1 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mainint.h @@ -0,0 +1,94 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MAININT_H +#define MAININT_H + +#include "config.h" +#include "opentyr.h" +#include "palette.h" +#include "player.h" +#include "sprite.h" + +extern bool button[4]; // fire, left fire, right fire, mode swap + +extern JE_shortint constantLastX; +extern JE_word textErase; +extern JE_word upgradeCost; +extern JE_word downgradeCost; +extern JE_boolean performSave; +extern JE_boolean jumpSection; +extern JE_boolean useLastBank; + +extern bool pause_pressed, ingamemenu_pressed; + +/*void JE_textMenuWait ( JE_word waittime, JE_boolean dogamma );*/ + +void JE_drawTextWindow( const char *text ); +void JE_initPlayerData( void ); +void JE_highScoreScreen( void ); +void JE_gammaCorrect_func( JE_byte *col, JE_real r ); +void JE_gammaCorrect( Palette *colorBuffer, JE_byte gamma ); +JE_boolean JE_gammaCheck( void ); +/* void JE_textMenuWait( JE_word *waitTime, JE_boolean doGamma ); /!\ In setup.h */ +void JE_loadOrderingInfo( void ); +void JE_nextEpisode( void ); +void JE_helpSystem( JE_byte startTopic ); +void JE_doInGameSetup( void ); +JE_boolean JE_inGameSetup( void ); +void JE_inGameHelp( void ); +void JE_sortHighScores( void ); +void JE_highScoreCheck( void ); +void adjust_difficulty( void ); + +bool load_next_demo( void ); +bool replay_demo_keys( void ); +bool read_demo_keys( void ); + +void JE_SFCodes( JE_byte playerNum_, JE_integer PX_, JE_integer PY_, JE_integer mouseX_, JE_integer mouseY_ ); +void JE_sort( void ); + +long weapon_upgrade_cost( long base_cost, unsigned int power ); +ulong JE_getCost( JE_byte itemType, JE_word itemNum ); +JE_longint JE_getValue( JE_byte itemType, JE_word itemNum ); +ulong JE_totalScore( const Player * ); + +void JE_drawPortConfigButtons( void ); +void JE_outCharGlow( JE_word x, JE_word y, const char *s ); + +void JE_playCredits( void ); +void JE_endLevelAni( void ); +void JE_drawCube( SDL_Surface * screen, JE_word x, JE_word y, JE_byte filter, JE_byte brightness ); +void JE_handleChat( void ); +bool str_pop_int( char *str, int *val ); +void JE_loadScreen( void ); +void JE_operation( JE_byte slot ); +void JE_inGameDisplays( void ); +void JE_mainKeyboardInput( void ); +void JE_pauseGame( void ); + +void JE_playerMovement( Player *this_player, JE_byte inputDevice, JE_byte playerNum, JE_word shipGr, Sprite2_array *shapes9ptr_, JE_word *mouseX, JE_word *mouseY ); +void JE_mainGamePlayerFunctions( void ); +const char *JE_getName( JE_byte pnum ); + +void JE_playerCollide( Player *this_player, JE_byte playerNum ); + + +#endif /* MAININT_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/menus.cpp b/alienblaster/project/jni/application/opentyrian/src/menus.cpp new file mode 100644 index 000000000..fbd8adb9d --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/menus.cpp @@ -0,0 +1,269 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "episodes.h" +#include "fonthand.h" +#include "keyboard.h" +#include "menus.h" +#include "nortsong.h" +#include "opentyr.h" +#include "palette.h" +#include "picload.h" +#include "setup.h" +#include "sprite.h" +#include "video.h" + +char episode_name[6][31], difficulty_name[7][21], gameplay_name[5][26]; + +bool select_gameplay( void ) +{ + JE_loadPic(VGAScreen, 2, false); + JE_dString(VGAScreen, JE_fontCenter(gameplay_name[0], FONT_SHAPES), 20, gameplay_name[0], FONT_SHAPES); + + int gameplay = 1, + gameplay_max = 4; + + bool fade_in = true; + for (; ; ) + { + for (int i = 1; i <= gameplay_max; i++) + { + JE_outTextAdjust(VGAScreen, JE_fontCenter(gameplay_name[i], SMALL_FONT_SHAPES), i * 24 + 30, gameplay_name[i], 15, - 4 + (i == gameplay ? 2 : 0) - (i == 4 ? 4 : 0), SMALL_FONT_SHAPES, true); + } + JE_showVGA(); + + if (fade_in) + { + fade_palette(colors, 10, 0, 255); + fade_in = false; + } + + JE_word temp = 0; + JE_textMenuWait(&temp, false); + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + gameplay--; + if (gameplay < 1) + { + gameplay = gameplay_max; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + gameplay++; + if (gameplay > gameplay_max) + { + gameplay = 1; + } + JE_playSampleNum(S_CURSOR); + break; + + case SDLK_RETURN: + if (gameplay == 4) + { + JE_playSampleNum(S_SPRING); + /* TODO: NETWORK */ + fprintf(stderr, "error: networking via menu not implemented\n"); + break; + } + JE_playSampleNum(S_SELECT); + fade_black(10); + + onePlayerAction = (gameplay == 2); + twoPlayerMode = (gameplay == 3); + return true; + + case SDLK_ESCAPE: + JE_playSampleNum(S_SPRING); + /* fading handled elsewhere + fade_black(10); */ + + return false; + + default: + break; + } + } + } +} + +bool select_episode( void ) +{ + JE_loadPic(VGAScreen, 2, false); + JE_dString(VGAScreen, JE_fontCenter(episode_name[0], FONT_SHAPES), 20, episode_name[0], FONT_SHAPES); + + int episode = 1, + episode_max = EPISODE_MAX - 1; + + bool fade_in = true; + for (; ; ) + { + for (int i = 1; i <= episode_max; i++) + { + JE_outTextAdjust(VGAScreen, 20, i * 30 + 20, episode_name[i], 15, -4 + (i == episode ? 2 : 0) - (!episodeAvail[i - 1] ? 4 : 0), SMALL_FONT_SHAPES, true); + } + JE_showVGA(); + + if (fade_in) + { + fade_palette(colors, 10, 0, 255); + fade_in = false; + } + + JE_word temp = 0; + JE_textMenuWait(&temp, false); + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + episode--; + if (episode < 1) + { + episode = episode_max; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + episode++; + if (episode > episode_max) + { + episode = 1; + } + JE_playSampleNum(S_CURSOR); + break; + + case SDLK_RETURN: + if (!episodeAvail[episode - 1]) + { + JE_playSampleNum(S_SPRING); + break; + } + JE_playSampleNum(S_SELECT); + fade_black(10); + + JE_initEpisode(episode); + initial_episode_num = episodeNum; + return true; + + case SDLK_ESCAPE: + JE_playSampleNum(S_SPRING); + /* fading handled elsewhere + fade_black(10); */ + + return false; + + default: + break; + } + } + } +} + +bool select_difficulty( void ) +{ + JE_loadPic(VGAScreen, 2, false); + JE_dString(VGAScreen, JE_fontCenter(difficulty_name[0], FONT_SHAPES), 20, difficulty_name[0], FONT_SHAPES); + + difficultyLevel = 2; + int difficulty_max = 3; + + bool fade_in = true; + for (; ; ) + { + for (int i = 1; i <= difficulty_max; i++) + { + JE_outTextAdjust(VGAScreen, JE_fontCenter(difficulty_name[i], SMALL_FONT_SHAPES), i * 24 + 30, difficulty_name[i], 15, -4 + (i == difficultyLevel ? 2 : 0), SMALL_FONT_SHAPES, true); + } + JE_showVGA(); + + if (fade_in) + { + fade_palette(colors, 10, 0, 255); + fade_in = false; + } + + JE_word temp = 0; + JE_textMenuWait(&temp, false); + + if (SDL_GetModState() & KMOD_SHIFT) + { + if ((difficulty_max < 4 && keysactive[SDLK_g]) || + (difficulty_max == 4 && keysactive[SDLK_RIGHTBRACKET])) + { + difficulty_max++; + } + } else if (difficulty_max == 5 && keysactive[SDLK_l] && keysactive[SDLK_o] && keysactive[SDLK_r] && keysactive[SDLK_d]) { + difficulty_max++; + } + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + difficultyLevel--; + if (difficultyLevel < 1) + { + difficultyLevel = difficulty_max; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + difficultyLevel++; + if (difficultyLevel > difficulty_max) + { + difficultyLevel = 1; + } + JE_playSampleNum(S_CURSOR); + break; + + case SDLK_RETURN: + JE_playSampleNum(S_SELECT); + /* fading handled elsewhere + fade_black(10); */ + + if (difficultyLevel == 6) + { + difficultyLevel = 8; + } else if (difficultyLevel == 5) { + difficultyLevel = 6; + } + return true; + + case SDLK_ESCAPE: + JE_playSampleNum(S_SPRING); + /* fading handled elsewhere + fade_black(10); */ + + return false; + + default: + break; + } + } + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/menus.h b/alienblaster/project/jni/application/opentyrian/src/menus.h new file mode 100644 index 000000000..f0e747c54 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/menus.h @@ -0,0 +1,32 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MENUS_H +#define MENUS_H + +#include "opentyr.h" + +extern char episode_name[6][31], difficulty_name[7][21], gameplay_name[5][26]; + +bool select_gameplay( void ); +bool select_episode( void ); +bool select_difficulty( void ); + +#endif /* MENUS_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/mingw_fixes.cpp b/alienblaster/project/jni/application/opentyrian/src/mingw_fixes.cpp new file mode 100644 index 000000000..bc3d34025 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mingw_fixes.cpp @@ -0,0 +1,26 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "mingw_fixes.h" + +char *strchrnul( const char *s, int c ) +{ + for (; *s != c && *s != '\0'; ++s) + ; + return (char *)s; +} diff --git a/alienblaster/project/jni/application/opentyrian/src/mingw_fixes.h b/alienblaster/project/jni/application/opentyrian/src/mingw_fixes.h new file mode 100644 index 000000000..cb70b8ccf --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mingw_fixes.h @@ -0,0 +1,24 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MINGW_FIXES_H +#define MINGW_FIXES_H + +char *strchrnul( const char *s, int c ); + +#endif // MINGW_FIXES_H diff --git a/alienblaster/project/jni/application/opentyrian/src/mouse.cpp b/alienblaster/project/jni/application/opentyrian/src/mouse.cpp new file mode 100644 index 000000000..5d25cb743 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mouse.cpp @@ -0,0 +1,114 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "keyboard.h" +#include "nortvars.h" +#include "sprite.h" +#include "video.h" +#include "vga256d.h" + +#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) || defined(ANDROID) +bool has_mouse = false; +#else +bool has_mouse = true; +#endif +bool mouse_has_three_buttons = true; + +JE_word lastMouseX, lastMouseY; +JE_byte mouseCursor; +JE_word mouseX, mouseY, mouseButton; +JE_word mouseXB, mouseYB; + +JE_byte mouseGrabShape[24 * 28]; /* [1..24*28] */ + +void JE_drawShapeTypeOne( JE_word x, JE_word y, JE_byte *shape ) +{ + JE_word xloop = 0, yloop = 0; + JE_byte *p = shape; /* shape pointer */ + Uint8 *s; /* screen pointer, 8-bit specific */ + Uint8 *s_limit; /* buffer boundary */ + + s = (Uint8 *)VGAScreen->pixels; + s += y * VGAScreen->pitch + x; + + s_limit = (Uint8 *)VGAScreen->pixels; + s_limit += VGAScreen->h * VGAScreen->pitch; + + for (yloop = 0; yloop < 28; yloop++) + { + for (xloop = 0; xloop < 24; xloop++) + { + if (s >= s_limit) return; + *s = *p; + s++; p++; + } + s -= 24; + s += VGAScreen->pitch; + } +} + +void JE_grabShapeTypeOne( JE_word x, JE_word y, JE_byte *shape ) +{ + JE_word xloop = 0, yloop = 0; + JE_byte *p = shape; /* shape pointer */ + Uint8 *s; /* screen pointer, 8-bit specific */ + Uint8 *s_limit; /* buffer boundary */ + + s = (Uint8 *)VGAScreen->pixels; + s += y * VGAScreen->pitch + x; + + s_limit = (Uint8 *)VGAScreen->pixels; + s_limit += VGAScreen->h * VGAScreen->pitch; + + for (yloop = 0; yloop < 28; yloop++) + { + for (xloop = 0; xloop < 24; xloop++) + { + if (s >= s_limit) return; + *p = *s; + s++; p++; + } + s -= 24; + s += VGAScreen->pitch; + } +} + +void JE_mouseStart( void ) +{ + const JE_word mouseCursorGr[3] /* [1..3] */ = {273, 275, 277}; + + if (has_mouse) + { + service_SDL_events(false); + mouseButton = mousedown ? lastmouse_but : 0; /* incorrect, possibly unimportant */ + lastMouseX = MIN(mouse_x, 320 - 13); + lastMouseY = MIN(mouse_y, 200 - 16); + + JE_grabShapeTypeOne(lastMouseX, lastMouseY, mouseGrabShape); + + blit_sprite2x2(VGAScreen, lastMouseX, lastMouseY, shapes6, mouseCursorGr[mouseCursor]); + } +} + +void JE_mouseReplace( void ) +{ + if (has_mouse) + JE_drawShapeTypeOne(lastMouseX, lastMouseY, mouseGrabShape); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/mouse.h b/alienblaster/project/jni/application/opentyrian/src/mouse.h new file mode 100644 index 000000000..5e208add9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mouse.h @@ -0,0 +1,44 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MOUSE_H +#define MOUSE_H + +#include "opentyr.h" + +#include "SDL.h" + +extern bool has_mouse; +extern bool mouse_has_three_buttons; + +extern JE_word lastMouseX, lastMouseY; +extern JE_byte mouseCursor; +extern JE_word mouseX, mouseY, mouseButton; +extern JE_word mouseXB, mouseYB; + +extern JE_byte mouseGrabShape[24 * 28]; + +void JE_drawShapeTypeOne( JE_word x, JE_word y, JE_byte *shape ); +void JE_grabShapeTypeOne( JE_word x, JE_word y, JE_byte *shape ); + +void JE_mouseStart( void ); +void JE_mouseReplace( void ); + +#endif /* MOUSE_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/mtrand.cpp b/alienblaster/project/jni/application/opentyrian/src/mtrand.cpp new file mode 100644 index 000000000..fa09d07c8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mtrand.cpp @@ -0,0 +1,108 @@ +/* + Copyright (C) 1997--2004, Makoto Matsumoto, Takuji Nishimura, and + Eric Landry; All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + 3. The names of its contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) + + Reference: M. Matsumoto and T. Nishimura, "Mersenne Twister: + A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number + Generator", ACM Transactions on Modeling and Computer Simulation, + Vol. 8, No. 1, January 1998, pp 3--30. +*/ + +#include "mtrand.h" + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +static unsigned long x[N]; /* the array for the state vector */ +static unsigned long *p0, *p1, *pm; + +void mt_srand( unsigned long s ) +{ + int i; + + x[0] = s & 0xffffffffUL; + for (i = 1; i < N; ++i) { + x[i] = (1812433253UL * (x[i - 1] ^ (x[i - 1] >> 30)) + i) + & 0xffffffffUL; /* for >32 bit machines */ + } + p0 = x; + p1 = x + 1; + pm = x + M; +} + +/* generates a random number on the interval [0,0xffffffff] */ +unsigned long mt_rand( void ) +{ + unsigned long y; + + if (!p0) { + /* Default seed */ + mt_srand(5489UL); + } + /* Twisted feedback */ + y = *p0 = *pm++ ^ (((*p0 & UPPER_MASK) | (*p1 & LOWER_MASK)) >> 1) ^ ((~(*p1 & 1)+1) & MATRIX_A); + p0 = p1++; + if (pm == x + N) { + pm = x; + } + if (p1 == x + N) { + p1 = x; + } + /* Temper */ + y ^= y >> 11; + y ^= y << 7 & 0x9d2c5680UL; + y ^= y << 15 & 0xefc60000UL; + y ^= y >> 18; + return y; +} + +/* generates a random number on the interval [0,1]. */ +float mt_rand_1( void ) +{ + return ((float)mt_rand() / (float)MT_RAND_MAX); +} + +/* generates a random number on the interval [0,1). */ +float mt_rand_lt1( void ) +{ + /* MT_RAND_MAX must be a float before adding one to it! */ + return ((float)mt_rand() / ((float)MT_RAND_MAX + 1.0f)); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/mtrand.h b/alienblaster/project/jni/application/opentyrian/src/mtrand.h new file mode 100644 index 000000000..08ea121a8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/mtrand.h @@ -0,0 +1,31 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MTRAND_H +#define MTRAND_H + +#define MT_RAND_MAX 0xffffffffUL + +void mt_srand( unsigned long s ); +unsigned long mt_rand( void ); +float mt_rand_1( void ); +float mt_rand_lt1( void ); + +#endif /* MTRAND_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/musmast.cpp b/alienblaster/project/jni/application/opentyrian/src/musmast.cpp new file mode 100644 index 000000000..bfdb158ae --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/musmast.cpp @@ -0,0 +1,117 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "opentyr.h" +#include "musmast.h" + + +JE_byte songBuy; + +const char musicFile[MUSIC_NUM][13] = +{ + /* 1 */ "ASTEROI2.DAT", + /* 2 */ "ASTEROID.DAT", + /* 3 */ "BUY.DAT", + /* 4 */ "CAMANIS.DAT", + /* 5 */ "CAMANISE.DAT", + /* 6 */ "DELIANI.DAT", + /* 7 */ "DELIANI2.DAT", + /* 8 */ "ENDING1.DAT", + /* 9 */ "ENDING2.DAT", + /* 10 */ "ENDLEVEL.DAT", + /* 11 */ "GAMEOVER.DAT", + /* 12 */ "GRYPHON.DAT", + /* 13 */ "GRYPHONE.DAT", + /* 14 */ "GYGES.DAT", + /* 15 */ "GYGESE.DAT", + /* 16 */ "HALLOWS.DAT", + /* 17 */ "ZICA.DAT", + /* 18 */ "TYRSONG2.DAT", + /* 19 */ "LOUDNESS.DAT", + /* 20 */ "NAVC.DAT", + /* 21 */ "SAVARA.DAT", + /* 22 */ "SAVARAE.DAT", + /* 23 */ "SPACE1.DAT", + /* 24 */ "SPACE2.DAT", + /* 25 */ "STARENDB.DAT", + /* 26 */ "START5.DAT", + /* 27 */ "TALK.DAT", + /* 28 */ "TORM.DAT", + /* 29 */ "TRANSON.DAT", + /* 30 */ "TYRSONG.DAT", + /* 31 */ "ZANAC3.DAT", + /* 32 */ "ZANACS.DAT", + /* 33 */ "SAVARA2.DAT", + /* 34 */ "HISCORE.DAT", + /* 35 */ "TYR4-1.DAT", /* OMF */ + /* 36 */ "TYR4-3.DAT", /* SARAH */ + /* 37 */ "TYR4-2.DAT", /* MAGFIELD */ + /* 38 */ "TYR4-0.DAT", /* ROCKME */ + /* 39 */ "TYR4-4.DAT", /* quiet music */ + /* 40 */ "TYR4-5.DAT", /* piano */ + /* 41 */ "TYR-BEER.DAT" /* BEER */ +}; + +const char musicTitle[MUSIC_NUM][48] = +{ + "Asteroid Dance Part 2", + "Asteroid Dance Part 1", + "Buy/Sell Music", + "CAMANIS", + "CAMANISE", + "Deli Shop Quartet", + "Deli Shop Quartet No. 2", + "Ending Number 1", + "Ending Number 2", + "End of Level", + "Game Over Solo", + "Gryphons of the West", + "Somebody pick up the Gryphone", + "Gyges, Will You Please Help Me?", + "I speak Gygese", + "Halloween Ramble", + "Tunneling Trolls", + "Tyrian, The Level", + "The MusicMan", + "The Navigator", + "Come Back to Me, Savara", + "Come Back again to Savara", + "Space Journey 1", + "Space Journey 2", + "The final edge", + "START5", + "Parlance", + "Torm - The Gathering", + "TRANSON", + "Tyrian: The Song", + "ZANAC3", + "ZANACS", + "Return me to Savara", + "High Score Table", + "One Mustn't Fall", + "Sarah's Song", + "A Field for Mag", + "Rock Garden", + "Quest for Peace", + "Composition in Q", + "BEER" +}; + +JE_boolean musicFade; + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/musmast.h b/alienblaster/project/jni/application/opentyrian/src/musmast.h new file mode 100644 index 000000000..9d1c65633 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/musmast.h @@ -0,0 +1,42 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MUSMAST_H +#define MUSMAST_H + +#include "opentyr.h" + + +#define DEFAULT_SONG_BUY 2 +#define SONG_LEVELEND 9 +#define SONG_GAMEOVER 10 +#define SONG_MAPVIEW 19 +#define SONG_ENDGAME1 7 +#define SONG_ZANAC 31 +#define SONG_TITLE 29 + +#define MUSIC_NUM 41 + +extern JE_byte songBuy; +extern const char musicFile[MUSIC_NUM][13]; +extern const char musicTitle[MUSIC_NUM][48]; +extern JE_boolean musicFade; + +#endif /* MUSMAST_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/network.cpp b/alienblaster/project/jni/application/opentyrian/src/network.cpp new file mode 100644 index 000000000..374377d5a --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/network.cpp @@ -0,0 +1,788 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "episodes.h" +#include "fonthand.h" +#include "helptext.h" +#include "joystick.h" +#include "keyboard.h" +#include "mainint.h" +#include "network.h" +#include "nortvars.h" +#include "opentyr.h" +#include "picload.h" +#include "sprite.h" +#include "varz.h" +#include "video.h" + +#include "SDL.h" +#include "SDL_net.h" + +#include + +/* HERE BE DRAGONS! + * + * When I wrote this code I thought it was wonderful... that thought was very + * wrong. It works, but good luck understanding how... I don't anymore. + * + * Hopefully it'll be rewritten some day. + */ + +#define NET_VERSION 2 // increment whenever networking changes might create incompatability +#define NET_PORT 1333 // UDP + +#define NET_PACKET_SIZE 256 +#define NET_PACKET_QUEUE 16 + +#define NET_RETRY 640 // ticks to wait for packet acknowledgement before resending +#define NET_RESEND 320 // ticks to wait before requesting unreceived game packet +#define NET_KEEP_ALIVE 1600 // ticks to wait between keep-alive packets +#define NET_TIME_OUT 16000 // ticks to wait before considering connection dead + +bool isNetworkGame = false; +int network_delay = 1 + 1; // minimum is 1 + 0 + +char *network_opponent_host = NULL; + +Uint16 network_player_port = NET_PORT, + network_opponent_port = NET_PORT; + +static char empty_string[] = ""; +char *network_player_name = empty_string, + *network_opponent_name = empty_string; + +UDPsocket socket; +IPaddress ip; + +UDPpacket *packet_out_temp, *packet_temp; + +UDPpacket *packet_in[NET_PACKET_QUEUE] = { NULL }, + *packet_out[NET_PACKET_QUEUE] = { NULL }; + +Uint16 last_out_sync = 0, queue_in_sync = 0, queue_out_sync = 0, last_ack_sync = 0; +Uint32 last_in_tick = 0, last_out_tick = 0; + +UDPpacket *packet_state_in[NET_PACKET_QUEUE] = { NULL }, + *packet_state_in_xor[NET_PACKET_QUEUE] = { NULL }, + *packet_state_out[NET_PACKET_QUEUE] = { NULL }; + +Uint16 last_state_in_sync = 0, last_state_out_sync = 0; +Uint32 last_state_in_tick = 0; + +bool net_initialized = false; +static bool connected = false, quit = false; + + +uint thisPlayerNum = 0; /* Player number on this PC (1 or 2) */ + +JE_boolean haltGame = false; + +JE_boolean moveOk; + +/* Special Requests */ +JE_boolean pauseRequest, skipLevelRequest, helpRequest, nortShipRequest; +JE_boolean yourInGameMenuRequest, inGameMenuRequest; + +// prepare new packet for sending +void network_prepare( Uint16 type ) +{ + SDLNet_Write16(type, &packet_out_temp->data[0]); + SDLNet_Write16(last_out_sync, &packet_out_temp->data[2]); +} + +// send packet and place it in queue to be acknowledged +bool network_send( int len ) +{ + bool temp = network_send_no_ack(len); + + Uint16 i = last_out_sync - queue_out_sync; + if (i < NET_PACKET_QUEUE) + { + packet_out[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_copy(packet_out[i], packet_out_temp); + } else { + // connection is probably bad now + fprintf(stderr, "warning: outbound packet queue overflow\n"); + return false; + } + + last_out_sync++; + + if (network_is_sync()) + last_out_tick = SDL_GetTicks(); + + return temp; +} + +// send packet but don't expect acknoledgment of delivery +bool network_send_no_ack( int len ) +{ + packet_out_temp->len = len; + + if (!SDLNet_UDP_Send(socket, 0, packet_out_temp)) + { + printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); + return false; + } + + return true; +} + +// poll for new packets received, check that connection is alive, resend queued packets if necessary +int network_check( void ) +{ + if (!net_initialized) + return -1; + + if (connected) + { + // timeout + if (!network_is_alive()) + { + if (!quit) + network_tyrian_halt(2, false); + } + + // keep-alive + static Uint32 keep_alive_tick = 0; + if (SDL_GetTicks() - keep_alive_tick > NET_KEEP_ALIVE) + { + network_prepare(PACKET_KEEP_ALIVE); + network_send_no_ack(4); + + keep_alive_tick = SDL_GetTicks(); + } + } + + // retry + if (packet_out[0] && SDL_GetTicks() - last_out_tick > NET_RETRY) + { + if (!SDLNet_UDP_Send(socket, 0, packet_out[0])) + { + printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); + return -1; + } + + last_out_tick = SDL_GetTicks(); + } + + switch (SDLNet_UDP_Recv(socket, packet_temp)) + { + case -1: + printf("SDLNet_UDP_Recv: %s\n", SDL_GetError()); + return -1; + break; + case 0: + break; + default: + if (packet_temp->channel == 0 && packet_temp->len >= 4) + { + switch (SDLNet_Read16(&packet_temp->data[0])) + { + case PACKET_ACKNOWLEDGE: + if ((Uint16)(SDLNet_Read16(&packet_temp->data[2]) - last_ack_sync) < NET_PACKET_QUEUE) + { + last_ack_sync = SDLNet_Read16(&packet_temp->data[2]); + } + + { + Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_out_sync; + if (i < NET_PACKET_QUEUE) + { + if (packet_out[i]) + { + SDLNet_FreePacket(packet_out[i]); + packet_out[i] = NULL; + } + } + } + + // remove acknowledged packets from queue + while (packet_out[0] == NULL && (Uint16)(last_ack_sync - queue_out_sync) < NET_PACKET_QUEUE) + { + packets_shift_up(packet_out, NET_PACKET_QUEUE); + + queue_out_sync++; + } + + last_in_tick = SDL_GetTicks(); + break; + + case PACKET_CONNECT: + queue_in_sync = SDLNet_Read16(&packet_temp->data[2]); + + for (int i = 0; i < NET_PACKET_QUEUE; i++) + { + if (packet_in[i]) + { + SDLNet_FreePacket(packet_in[i]); + packet_in[i] = NULL; + } + } + + case PACKET_DETAILS: + case PACKET_WAITING: + case PACKET_BUSY: + case PACKET_GAME_QUIT: + case PACKET_GAME_PAUSE: + case PACKET_GAME_MENU: + { + Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_in_sync; + if (i < NET_PACKET_QUEUE) + { + if (packet_in[i] == NULL) + packet_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_copy(packet_in[i], packet_temp); + } else { + // inbound packet queue overflow/underflow + // under normal circumstances, this is okay + } + } + + network_acknowledge(SDLNet_Read16(&packet_temp->data[2])); + + case PACKET_KEEP_ALIVE: + last_in_tick = SDL_GetTicks(); + break; + + case PACKET_QUIT: + if (!quit) + { + network_prepare(PACKET_QUIT); + network_send(4); // PACKET_QUIT + } + + network_acknowledge(SDLNet_Read16(&packet_temp->data[2])); + + if (!quit) + network_tyrian_halt(1, true); + break; + + case PACKET_STATE: + // place packet in queue if within limits + { + Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1; + if (i < NET_PACKET_QUEUE) + { + if (packet_state_in[i] == NULL) + packet_state_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_copy(packet_state_in[i], packet_temp); + } + } + break; + + case PACKET_STATE_XOR: + // place packet in queue if within limits + { + Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1; + if (i < NET_PACKET_QUEUE) + { + if (packet_state_in_xor[i] == NULL) + { + packet_state_in_xor[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_copy(packet_state_in_xor[i], packet_temp); + } else if (SDLNet_Read16(&packet_state_in_xor[i]->data[0]) != PACKET_STATE_XOR) { + for (int j = 4; j < packet_state_in_xor[i]->len; j++) + packet_state_in_xor[i]->data[j] ^= packet_temp->data[j]; + SDLNet_Write16(PACKET_STATE_XOR, &packet_state_in_xor[i]->data[0]); + } + } + } + break; + + case PACKET_STATE_RESEND: + // resend requested state packet if still available + { + Uint16 i = last_state_out_sync - SDLNet_Read16(&packet_temp->data[2]); + if (i > 0 && i < NET_PACKET_QUEUE) + { + if (packet_state_out[i]) + { + if (!SDLNet_UDP_Send(socket, 0, packet_state_out[i])) + { + printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); + return -1; + } + } + } + } + break; + + default: + fprintf(stderr, "warning: bad packet %d received\n", SDLNet_Read16(&packet_temp->data[0])); + return 0; + break; + } + + return 1; + } + break; + } + + return 0; +} + +// send acknowledgement packet +int network_acknowledge( Uint16 sync ) +{ + SDLNet_Write16(PACKET_ACKNOWLEDGE, &packet_out_temp->data[0]); + SDLNet_Write16(sync, &packet_out_temp->data[2]); + network_send_no_ack(4); + + return 0; +} + +// discard working packet, now processing next packet in queue +bool network_update( void ) +{ + if (packet_in[0]) + { + packets_shift_up(packet_in, NET_PACKET_QUEUE); + + queue_in_sync++; + + return true; + } + + return false; +} + +// has opponent gotten all the packets we've sent? +bool network_is_sync( void ) +{ + return (queue_out_sync - last_ack_sync == 1); +} + +// activity lately? +bool network_is_alive( void ) +{ + return (SDL_GetTicks() - last_in_tick < NET_TIME_OUT || SDL_GetTicks() - last_state_in_tick < NET_TIME_OUT); +} + + +// prepare new state for sending +void network_state_prepare( void ) +{ + if (packet_state_out[0]) + { + fprintf(stderr, "warning: state packet overwritten (previous packet remains unsent)\n"); + } else { + packet_state_out[0] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_state_out[0]->len = 28; + } + + SDLNet_Write16(PACKET_STATE, &packet_state_out[0]->data[0]); + SDLNet_Write16(last_state_out_sync, &packet_state_out[0]->data[2]); + memset(&packet_state_out[0]->data[4], 0, 28 - 4); +} + +// send state packet, xor packet if applicable +int network_state_send( void ) +{ + if (!SDLNet_UDP_Send(socket, 0, packet_state_out[0])) + { + printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); + return -1; + } + + // send xor of last network_delay packets + if (network_delay > 1 && (last_state_out_sync + 1) % network_delay == 0 && packet_state_out[network_delay - 1] != NULL) + { + packet_copy(packet_temp, packet_state_out[0]); + SDLNet_Write16(PACKET_STATE_XOR, &packet_temp->data[0]); + for (int i = 1; i < network_delay; i++) + for (int j = 4; j < packet_temp->len; j++) + packet_temp->data[j] ^= packet_state_out[i]->data[j]; + + if (!SDLNet_UDP_Send(socket, 0, packet_temp)) + { + printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); + return -1; + } + } + + packets_shift_down(packet_state_out, NET_PACKET_QUEUE); + + last_state_out_sync++; + + return 0; +} + +// receive state packet, wait until received +bool network_state_update( void ) +{ + if (network_state_is_reset()) + { + return 0; + } else { + packets_shift_up(packet_state_in, NET_PACKET_QUEUE); + + packets_shift_up(packet_state_in_xor, NET_PACKET_QUEUE); + + last_state_in_sync++; + + // current xor packet index + int x = network_delay - (last_state_in_sync - 1) % network_delay - 1; + + // loop until needed packet is available + while (!packet_state_in[0]) + { + // xor the packet from thin air, if possible + if (packet_state_in_xor[x] && SDLNet_Read16(&packet_state_in_xor[x]->data[0]) == PACKET_STATE_XOR) + { + // check for all other required packets + bool okay = true; + for (int i = 1; i <= x; i++) + { + if (packet_state_in[i] == NULL) + { + okay = false; + break; + } + } + if (okay) + { + packet_state_in[0] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_copy(packet_state_in[0], packet_state_in_xor[x]); + for (int i = 1; i <= x; i++) + for (int j = 4; j < packet_state_in[0]->len; j++) + packet_state_in[0]->data[j] ^= packet_state_in[i]->data[j]; + break; + } + } + + static Uint32 resend_tick = 0; + if (SDL_GetTicks() - last_state_in_tick > NET_RESEND && SDL_GetTicks() - resend_tick > NET_RESEND) + { + SDLNet_Write16(PACKET_STATE_RESEND, &packet_out_temp->data[0]); + SDLNet_Write16(last_state_in_sync - 1, &packet_out_temp->data[2]); + network_send_no_ack(4); // PACKET_RESEND + + resend_tick = SDL_GetTicks(); + } + + if (network_check() == 0) + SDL_Delay(1); + } + + if (network_delay > 1) + { + // process the current in packet against the xor queue + if (packet_state_in_xor[x] == NULL) + { + packet_state_in_xor[x] = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_copy(packet_state_in_xor[x], packet_state_in[0]); + packet_state_in_xor[x]->status = 0; + } else { + for (int j = 4; j < packet_state_in_xor[x]->len; j++) + packet_state_in_xor[x]->data[j] ^= packet_state_in[0]->data[j]; + } + } + + last_state_in_tick = SDL_GetTicks(); + } + + return 1; +} + +// ignore first network_delay states of level +bool network_state_is_reset( void ) +{ + return (last_state_out_sync < network_delay); +} + +// reset queues for new level +void network_state_reset( void ) +{ + last_state_in_sync = last_state_out_sync = 0; + + for (int i = 0; i < NET_PACKET_QUEUE; i++) + { + if (packet_state_in[i]) + { + SDLNet_FreePacket(packet_state_in[i]); + packet_state_in[i] = NULL; + } + } + for (int i = 0; i < NET_PACKET_QUEUE; i++) + { + if (packet_state_in_xor[i]) + { + SDLNet_FreePacket(packet_state_in_xor[i]); + packet_state_in_xor[i] = NULL; + } + } + for (int i = 0; i < NET_PACKET_QUEUE; i++) + { + if (packet_state_out[i]) + { + SDLNet_FreePacket(packet_state_out[i]); + packet_state_out[i] = NULL; + } + } + + last_state_in_tick = SDL_GetTicks(); +} + + +// attempt to punch through firewall by firing off UDP packets at the opponent +// exchange game information +int network_connect( void ) +{ + SDLNet_ResolveHost(&ip, network_opponent_host, network_opponent_port); + + SDLNet_UDP_Bind(socket, 0, &ip); + + Uint16 episodes = 0, episodes_local = 0; + assert(EPISODE_MAX <= 16); + for (int i = EPISODE_MAX - 1; i >= 0; i--) + { + episodes <<= 1; + episodes |= (episodeAvail[i] != 0); + } + episodes_local = episodes; + + assert(NET_PACKET_SIZE - 12 >= 20 + 1); + if (strlen(network_player_name) > 20) + network_player_name[20] = '\0'; + +connect_reset: + network_prepare(PACKET_CONNECT); + SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]); + SDLNet_Write16(network_delay, &packet_out_temp->data[6]); + SDLNet_Write16(episodes_local, &packet_out_temp->data[8]); + SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]); + strcpy((char *)&packet_out_temp->data[12], network_player_name); + network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT + + // until opponent sends connect packet + while (true) + { + push_joysticks_as_keyboard(); + service_SDL_events(false); + + if (newkey && lastkey_sym == SDLK_ESCAPE) + network_tyrian_halt(0, false); + + // never timeout + last_in_tick = SDL_GetTicks(); + + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT) + break; + + network_update(); + network_check(); + + SDL_Delay(16); + } + +connect_again: + if (SDLNet_Read16(&packet_in[0]->data[4]) != NET_VERSION) + { + fprintf(stderr, "error: network version did not match opponent's\n"); + network_tyrian_halt(4, true); + } + if (SDLNet_Read16(&packet_in[0]->data[6]) != network_delay) + { + fprintf(stderr, "error: network delay did not match opponent's\n"); + network_tyrian_halt(5, true); + } + if (SDLNet_Read16(&packet_in[0]->data[10]) == thisPlayerNum) + { + fprintf(stderr, "error: player number conflicts with opponent's\n"); + network_tyrian_halt(6, true); + } + + episodes = SDLNet_Read16(&packet_in[0]->data[8]); + for (int i = 0; i < EPISODE_MAX; i++) { + episodeAvail[i] &= (episodes & 1); + episodes >>= 1; + } + + network_opponent_name = (char *)malloc(packet_in[0]->len - 12 + 1); + strcpy(network_opponent_name, (char *)&packet_in[0]->data[12]); + + network_update(); + + // until opponent has acknowledged + while (!network_is_sync()) + { + service_SDL_events(false); + + // got a duplicate packet; process it again (but why?) + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT) + goto connect_again; + + network_check(); + + // maybe opponent didn't get our packet + if (SDL_GetTicks() - last_out_tick > NET_RETRY) + goto connect_reset; + + SDL_Delay(16); + } + + // send another packet since sometimes the network syncs without both connect packets exchanged + // there should be a better way to handle this + network_prepare(PACKET_CONNECT); + SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]); + SDLNet_Write16(network_delay, &packet_out_temp->data[6]); + SDLNet_Write16(episodes_local, &packet_out_temp->data[8]); + SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]); + strcpy((char *)&packet_out_temp->data[12], network_player_name); + network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT + + connected = true; + + return 0; +} + +// something has gone wrong :( +void network_tyrian_halt( unsigned int err, bool attempt_sync ) +{ + const char *err_msg[] = { + "Quitting...", + "Other player quit the game.", + "Network connection was lost.", + "Network connection failed.", + "Network version mismatch.", + "Network delay mismatch.", + "Network player number conflict.", + }; + + quit = true; + + if (err >= COUNTOF(err_msg)) + err = 0; + + fade_black(10); + + VGAScreen = VGAScreenSeg; + + JE_loadPic(VGAScreen, 2, false); + JE_dString(VGAScreen, JE_fontCenter(err_msg[err], SMALL_FONT_SHAPES), 140, err_msg[err], SMALL_FONT_SHAPES); + + JE_showVGA(); + fade_palette(colors, 10, 0, 255); + + if (attempt_sync) + { + while (!network_is_sync() && network_is_alive()) + { + service_SDL_events(false); + + network_check(); + SDL_Delay(16); + } + } + + if (err) + { + while (!JE_anyButton()) + SDL_Delay(16); + } + + fade_black(10); + + SDLNet_Quit(); + + JE_tyrianHalt(5); +} + +int network_init( void ) +{ + printf("Initializing network...\n"); + + if (network_delay * 2 > NET_PACKET_QUEUE - 2) + { + fprintf(stderr, "error: network delay would overflow packet queue\n"); + return -4; + } + + if (SDLNet_Init() == -1) + { + fprintf(stderr, "error: SDLNet_Init: %s\n", SDLNet_GetError()); + return -1; + } + + socket = SDLNet_UDP_Open(network_player_port); + if (!socket) + { + fprintf(stderr, "error: SDLNet_UDP_Open: %s\n", SDLNet_GetError()); + return -2; + } + + packet_temp = SDLNet_AllocPacket(NET_PACKET_SIZE); + packet_out_temp = SDLNet_AllocPacket(NET_PACKET_SIZE); + + if (!packet_temp || !packet_out_temp) + { + printf("SDLNet_AllocPacket: %s\n", SDLNet_GetError()); + return -3; + } + + net_initialized = true; + + return 0; +} + +void packet_copy( UDPpacket *dst, UDPpacket *src ) +{ + void *temp = dst->data; + memcpy(dst, src, sizeof(*dst)); + dst->data = (Uint8*)temp; + memcpy(dst->data, src->data, src->len); +} + +void packets_shift_up( UDPpacket **packet, int max_packets ) +{ + if (packet[0]) + { + SDLNet_FreePacket(packet[0]); + } + for (int i = 0; i < max_packets - 1; i++) + { + packet[i] = packet[i + 1]; + } + packet[max_packets - 1] = NULL; +} + +void packets_shift_down( UDPpacket **packet, int max_packets ) +{ + if (packet[max_packets - 1]) + { + SDLNet_FreePacket(packet[max_packets - 1]); + } + for (int i = max_packets - 1; i > 0; i--) + { + packet[i] = packet[i - 1]; + } + packet[0] = NULL; +} + + +void JE_clearSpecialRequests( void ) +{ + pauseRequest = false; + inGameMenuRequest = false; + skipLevelRequest = false; + helpRequest = false; + nortShipRequest = false; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/network.h b/alienblaster/project/jni/application/opentyrian/src/network.h new file mode 100644 index 000000000..d6b075685 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/network.h @@ -0,0 +1,100 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef NETWORK_H +#define NETWORK_H + +#include "opentyr.h" + +#include "SDL.h" +#include "SDL_net.h" + + +#define PACKET_ACKNOWLEDGE 0x00 // +#define PACKET_KEEP_ALIVE 0x01 // + +#define PACKET_CONNECT 0x10 // version, delay, episodes, player_number, name +#define PACKET_DETAILS 0x11 // episode, difficulty + +#define PACKET_QUIT 0x20 // +#define PACKET_WAITING 0x21 // +#define PACKET_BUSY 0x22 // + +#define PACKET_GAME_QUIT 0x30 // +#define PACKET_GAME_PAUSE 0x31 // +#define PACKET_GAME_MENU 0x32 // + +#define PACKET_STATE_RESEND 0x40 // state_id +#define PACKET_STATE 0x41 // (not acknowledged) +#define PACKET_STATE_XOR 0x42 // (not acknowledged) + +extern bool isNetworkGame; +extern int network_delay; + +extern char *network_opponent_host; +extern Uint16 network_player_port, network_opponent_port; +extern char *network_player_name, *network_opponent_name; + +extern UDPpacket *packet_out_temp; +extern UDPpacket *packet_in[], *packet_out[], + *packet_state_in[], *packet_state_out[]; + +extern uint thisPlayerNum; +extern JE_boolean haltGame; +extern JE_boolean moveOk; +extern JE_boolean pauseRequest, skipLevelRequest, helpRequest, nortShipRequest; +extern JE_boolean yourInGameMenuRequest, inGameMenuRequest; +extern JE_boolean portConfigChange, portConfigDone; + + +void network_prepare( Uint16 type ); +bool network_send( int len ); +bool network_send_no_ack( int len ); + +int network_check( void ); +int network_acknowledge( Uint16 sync ); +bool network_update( void ); + +bool network_is_sync( void ); +bool network_is_alive( void ); + +void network_state_prepare( void ); +int network_state_send( void ); +bool network_state_update( void ); +bool network_state_is_reset( void ); +void network_state_reset( void ); + +int network_connect( void ); +void network_tyrian_halt( unsigned int err, bool attempt_sync ); + +int network_init( void ); + +void packet_copy( UDPpacket *dst, UDPpacket *src ); +void packets_shift_up( UDPpacket **packet, int max_packets ); +void packets_shift_down( UDPpacket **packet, int max_packets ); + +void JE_clearSpecialRequests( void ); + +#define NETWORK_KEEP_ALIVE() \ + if (isNetworkGame) \ + network_check(); + + +#endif /* NETWORK_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/nortsong.cpp b/alienblaster/project/jni/application/opentyrian/src/nortsong.cpp new file mode 100644 index 000000000..8a938ad2b --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/nortsong.cpp @@ -0,0 +1,225 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "joystick.h" +#include "keyboard.h" +#include "loudness.h" +#include "musmast.h" +#include "nortsong.h" +#include "opentyr.h" +#include "params.h" +#include "sndmast.h" +#include "vga256d.h" + +#include "SDL.h" + +Uint32 target, target2; + +JE_boolean notYetLoadedSound = true; + +JE_word frameCount, frameCount2, frameCountMax; + +JE_byte *digiFx[SAMPLE_COUNT] = { NULL }; /* [1..soundnum + 9] */ +JE_word fxSize[SAMPLE_COUNT]; /* [1..soundnum + 9] */ + +JE_word tyrMusicVolume, fxVolume; +JE_word fxPlayVol; +JE_word tempVolume; + +JE_word speed; /* JE: holds timer speed for 70Hz */ + +float jasondelay = 1000.0f / (1193180.0f / 0x4300); + +void setdelay( JE_byte delay ) +{ + target = (delay * 16) + SDL_GetTicks(); +} + +void setjasondelay( int delay ) +{ + target = SDL_GetTicks() + delay * jasondelay; +} + +void setjasondelay2( int delay ) +{ + target2 = SDL_GetTicks() + delay * jasondelay; +} + +int delaycount( void ) +{ + return (SDL_GetTicks() < target ? target - SDL_GetTicks() : 0); +} + +int delaycount2( void ) +{ + return (SDL_GetTicks() < target2 ? target2 - SDL_GetTicks() : 0); +} + +void wait_delay( void ) +{ + Sint32 delay = target - SDL_GetTicks(); + if (delay > 0) + SDL_Delay(delay); +} + +void service_wait_delay( void ) +{ + while (SDL_GetTicks() < target) + { + SDL_Delay(SDL_GetTicks() - target > SDL_POLL_INTERVAL ? SDL_POLL_INTERVAL : SDL_GetTicks() - target); + service_SDL_events(false); + } +} + +void wait_delayorinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ) +{ + service_SDL_events(true); + while (SDL_GetTicks() < target && !((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown))) + { + SDL_Delay(SDL_GetTicks() - target > SDL_POLL_INTERVAL ? SDL_POLL_INTERVAL : SDL_GetTicks() - target); + push_joysticks_as_keyboard(); + service_SDL_events(false); + } +} + +void JE_loadSndFile( const char *effects_sndfile, const char *voices_sndfile ) +{ + JE_byte y, z; + JE_word x; + JE_longint templ; + JE_longint sndPos[2][SAMPLE_COUNT + 1]; + JE_word sndNum; + + FILE *fi; + + /* SYN: Loading offsets into TYRIAN.SND */ + fi = dir_fopen_die(data_dir(), effects_sndfile, "rb"); + efread(&sndNum, sizeof(sndNum), 1, fi); + + for (x = 0; x < sndNum; x++) + { + efread(&sndPos[0][x], sizeof(sndPos[0][x]), 1, fi); + } + fseek(fi, 0, SEEK_END); + sndPos[1][sndNum] = ftell(fi); /* Store file size */ + + for (z = 0; z < sndNum; z++) + { + fseek(fi, sndPos[0][z], SEEK_SET); + fxSize[z] = (sndPos[0][z+1] - sndPos[0][z]); /* Store sample sizes */ + free(digiFx[z]); + digiFx[z] = (JE_byte*)malloc(fxSize[z]); + efread(digiFx[z], 1, fxSize[z], fi); /* JE: Load sample to buffer */ + } + + fclose(fi); + + /* SYN: Loading offsets into VOICES.SND */ + fi = dir_fopen_die(data_dir(), voices_sndfile, "rb"); + + efread(&sndNum, sizeof(sndNum), 1, fi); + + for (x = 0; x < sndNum; x++) + { + efread(&sndPos[1][x], sizeof(sndPos[1][x]), 1, fi); + } + fseek(fi, 0, SEEK_END); + sndPos[1][sndNum] = ftell(fi); /* Store file size */ + + z = SAMPLE_COUNT - 9; + + for (y = 0; y < sndNum; y++) + { + fseek(fi, sndPos[1][y], SEEK_SET); + + templ = (sndPos[1][y+1] - sndPos[1][y]) - 100; /* SYN: I'm not entirely sure what's going on here. */ + if (templ < 1) templ = 1; + fxSize[z + y] = templ; /* Store sample sizes */ + digiFx[z + y] = (JE_byte*)malloc(fxSize[z + y]); + efread(digiFx[z + y], 1, fxSize[z + y], fi); /* JE: Load sample to buffer */ + } + + fclose(fi); + + notYetLoadedSound = false; + +} + +void JE_playSampleNum( JE_byte samplenum ) +{ + JE_multiSamplePlay(digiFx[samplenum-1], fxSize[samplenum-1], 0, fxPlayVol); +} + +void JE_calcFXVol( void ) // TODO: not sure *exactly* what this does +{ + fxPlayVol = (fxVolume - 1) >> 5; +} + +void JE_setTimerInt( void ) +{ + jasondelay = 1000.0f / (1193180.0f / speed); +} + +void JE_resetTimerInt( void ) +{ + jasondelay = 1000.0f / (1193180.0f / 0x4300); +} + +void JE_changeVolume( JE_word *music, int music_delta, JE_word *sample, int sample_delta ) +{ + int music_temp = *music + music_delta, + sample_temp = *sample + sample_delta; + + if (music_delta) + { + if (music_temp > 255) + { + music_temp = 255; + JE_playSampleNum(S_CLINK); + } + else if (music_temp < 0) + { + music_temp = 0; + JE_playSampleNum(S_CLINK); + } + } + + if (sample_delta) + { + if (sample_temp > 255) + { + sample_temp = 255; + JE_playSampleNum(S_CLINK); + } + else if (sample_temp < 0) + { + sample_temp = 0; + JE_playSampleNum(S_CLINK); + } + } + + *music = music_temp; + *sample = sample_temp; + + JE_calcFXVol(); + + set_volume(*music, *sample); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/nortsong.h b/alienblaster/project/jni/application/opentyrian/src/nortsong.h new file mode 100644 index 000000000..57d8502e7 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/nortsong.h @@ -0,0 +1,65 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef NORTSONG_H +#define NORTSONG_H + +#include "opentyr.h" + +#include "musmast.h" +#include "sndmast.h" + +#include "SDL.h" + +extern Uint32 target, target2; + +extern JE_word frameCount, frameCount2, frameCountMax; + +extern JE_byte *digiFx[SAMPLE_COUNT]; +extern JE_word fxSize[SAMPLE_COUNT]; + +extern JE_word tyrMusicVolume, fxVolume; +extern JE_word fxPlayVol; +extern JE_word tempVolume; + +extern JE_word speed; + +extern float jasondelay; + +void setdelay( JE_byte delay ); +void setjasondelay( int delay ); +void setjasondelay2( int delay ); +int delaycount( void ); +int delaycount2( void ); + +void wait_delay( void ); +void service_wait_delay( void ); +void wait_delayorinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick ); + +void JE_resetTimerInt( void ); +void JE_setTimerInt( void ); + +void JE_calcFXVol( void ); +void JE_changeVolume( JE_word *music, int music_delta, JE_word *sample, int sample_delta ); + +void JE_loadSndFile( const char *effects_sndfile, const char *voices_sndfile ); +void JE_playSampleNum( JE_byte samplenum ); + +#endif /* NORTSONG_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/nortvars.cpp b/alienblaster/project/jni/application/opentyrian/src/nortvars.cpp new file mode 100644 index 000000000..0c709b425 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/nortvars.cpp @@ -0,0 +1,88 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "joystick.h" +#include "keyboard.h" +#include "nortvars.h" +#include "opentyr.h" +#include "vga256d.h" +#include "video.h" + +#include +#include + +JE_boolean inputDetected; + +JE_boolean JE_anyButton( void ) +{ + poll_joysticks(); + service_SDL_events(true); + return newkey || mousedown || joydown; +} + +void JE_dBar3( SDL_Surface *surface, JE_integer x, JE_integer y, JE_integer num, JE_integer col ) +{ + JE_byte z; + JE_byte zWait = 2; + + col += 2; + + for (z = 0; z <= num; z++) + { + JE_rectangle(surface, x, y - 1, x + 8, y, col); /* SEGa000 */ + if (zWait > 0) + { + zWait--; + } else { + col++; + zWait = 1; + } + y -= 2; + } +} + +void JE_barDrawShadow( SDL_Surface *surface, JE_word x, JE_word y, JE_word res, JE_word col, JE_word amt, JE_word xsize, JE_word ysize ) +{ + xsize--; + ysize--; + + for (int z = 1; z <= amt / res; z++) + { + JE_barShade(surface, x+2, y+2, x+xsize+2, y+ysize+2); + fill_rectangle_xy(surface, x, y, x+xsize, y+ysize, col+12); + fill_rectangle_xy(surface, x, y, x+xsize, y, col+13); + JE_pix(surface, x, y, col+15); + fill_rectangle_xy(surface, x, y+ysize, x+xsize, y+ysize, col+11); + x += xsize + 2; + } + + amt %= res; + if (amt > 0) + { + JE_barShade(surface, x+2, y+2, x+xsize+2, y+ysize+2); + fill_rectangle_xy(surface, x,y, x+xsize, y+ysize, col+(12 / res * amt)); + } +} + +void JE_wipeKey( void ) +{ + // /!\ Doesn't seems to affect anything. +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/nortvars.h b/alienblaster/project/jni/application/opentyrian/src/nortvars.h new file mode 100644 index 000000000..f4113d31d --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/nortvars.h @@ -0,0 +1,36 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef NORTVARS_H +#define NORTVARS_H + +#include "opentyr.h" + +extern JE_boolean inputDetected; + +JE_boolean JE_buttonPressed( void ); + +JE_boolean JE_anyButton( void ); + +void JE_dBar3( SDL_Surface *surface, JE_integer x, JE_integer y, JE_integer num, JE_integer col ); +void JE_barDrawShadow( SDL_Surface *surface, JE_word x, JE_word y, JE_word res, JE_word col, JE_word amt, JE_word xsize, JE_word ysize ); +void JE_wipeKey( void ); + +#endif /* NORTVARS_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/opentyr.cpp b/alienblaster/project/jni/application/opentyrian/src/opentyr.cpp new file mode 100644 index 000000000..c9c16f119 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/opentyr.cpp @@ -0,0 +1,349 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "destruct.h" +#include "editship.h" +#include "episodes.h" +#include "file.h" +#include "font.h" +#include "helptext.h" +#include "hg_revision.h" +#include "joystick.h" +#include "jukebox.h" +#include "keyboard.h" +#include "loudness.h" +#include "mainint.h" +#include "mtrand.h" +#include "musmast.h" +#include "network.h" +#include "nortsong.h" +#include "opentyr.h" +#include "params.h" +#include "picload.h" +#include "scroller.h" +#include "setup.h" +#include "sprite.h" +#include "tyrian2.h" +#include "xmas.h" +#include "varz.h" +#include "vga256d.h" +#include "video.h" +#include "video_scale.h" + +#include "SDL.h" + +#include +#include +#include +#include + +const char *opentyrian_str = "OpenTyrian", + *opentyrian_version = "Classic (" HG_REV ")"; +const char *opentyrian_menu_items[] = +{ + "About OpenTyrian", + "Toggle Fullscreen", + "Scaler: None", + /* "Play Destruct", */ + "Jukebox", + "Return to Main Menu" +}; + +/* zero-terminated strncpy */ +char *strnztcpy( char *to, const char *from, size_t count ) +{ + to[count] = '\0'; + return strncpy(to, from, count); +} + +void opentyrian_menu( void ) +{ + int sel = 0; + const int maxSel = COUNTOF(opentyrian_menu_items) - 1; + bool quit = false, fade_in = true; + + uint temp_scaler = scaler; + + fade_black(10); + JE_loadPic(VGAScreen, 13, false); + + draw_font_hv(VGAScreen, VGAScreen->w / 2, 5, opentyrian_str, large_font, centered, 15, -3); + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + JE_showVGA(); + + play_song(36); // A Field for Mag + + do + { + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + for (int i = 0; i <= maxSel; i++) + { + const char *text = opentyrian_menu_items[i]; + char buffer[100]; + + if (i == 2) /* Scaler */ + { + snprintf(buffer, sizeof(buffer), "Scaler: %s", scalers[temp_scaler].name); + text = buffer; + } + + draw_font_hv_shadow(VGAScreen, VGAScreen->w / 2, (i != maxSel) ? i * 16 + 32 : 118, text, normal_font, centered, 15, (i != sel) ? -4 : -2, false, 2); + } + + JE_showVGA(); + + if (fade_in) + { + fade_in = false; + fade_palette(colors, 20, 0, 255); + wait_noinput(true, false, false); + } + + tempW = 0; + JE_textMenuWait(&tempW, false); + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + sel--; + if (sel < 0) + { + sel = maxSel; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + sel++; + if (sel > maxSel) + { + sel = 0; + } + JE_playSampleNum(S_CURSOR); + break; + case SDLK_LEFT: + if (sel == 2) + { + do + { + if (temp_scaler == 0) + temp_scaler = scalers_count; + temp_scaler--; + } + while (!can_init_scaler(temp_scaler, fullscreen_enabled)); + JE_playSampleNum(S_CURSOR); + } + break; + case SDLK_RIGHT: + if (sel == 2) + { + do + { + temp_scaler++; + if (temp_scaler == scalers_count) + temp_scaler = 0; + } + while (!can_init_scaler(temp_scaler, fullscreen_enabled)); + JE_playSampleNum(S_CURSOR); + } + break; + case SDLK_RETURN: + switch (sel) + { + case 0: /* About */ + JE_playSampleNum(S_SELECT); + + scroller_sine(about_text); + + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + JE_showVGA(); + fade_in = true; + break; + case 1: /* Fullscreen */ + JE_playSampleNum(S_SELECT); + + if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state + !init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state + !init_scaler(scaler, fullscreen_enabled)) // revert on fail + { + exit(EXIT_FAILURE); + } + set_palette(colors, 0, 255); // for switching between 8 bpp scalers + break; + case 2: /* Scaler */ + JE_playSampleNum(S_SELECT); + + if (scaler != temp_scaler) + { + if (!init_scaler(temp_scaler, fullscreen_enabled) && // try new scaler + !init_scaler(temp_scaler, !fullscreen_enabled) && // try other fullscreen state + !init_scaler(scaler, fullscreen_enabled)) // revert on fail + { + exit(EXIT_FAILURE); + } + set_palette(colors, 0, 255); // for switching between 8 bpp scalers + } + break; + case 3: /* Jukebox */ + JE_playSampleNum(S_SELECT); + + fade_black(10); + jukebox(); + + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + JE_showVGA(); + fade_in = true; + break; + default: /* Return to main menu */ + quit = true; + JE_playSampleNum(S_SPRING); + break; + } + break; + case SDLK_ESCAPE: + quit = true; + JE_playSampleNum(S_SPRING); + break; + default: + break; + } + } + } while (!quit); +} + +int main( int argc, char *argv[] ) +{ + mt_srand(time(NULL)); + + printf("\nWelcome to... >> %s %s <<\n\n", opentyrian_str, opentyrian_version); + + printf("Copyright (C) 2007-2009 The OpenTyrian Development Team\n\n"); + + printf("This program comes with ABSOLUTELY NO WARRANTY.\n"); + printf("This is free software, and you are welcome to redistribute it\n"); + printf("under certain conditions. See the file GPL.txt for details.\n\n"); + + if (SDL_Init(0)) + { + printf("Failed to initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + JE_loadConfiguration(); + + xmas = xmas_time(); // arg handler may override + + JE_paramCheck(argc, argv); + + JE_scanForEpisodes(); + + init_video(); + init_keyboard(); + init_joysticks(); + printf("assuming mouse detected\n"); // SDL can't tell us if there isn't one + + if (xmas && (!dir_file_exists(data_dir(), "tyrianc.shp") || !dir_file_exists(data_dir(), "voicesc.snd"))) + { + xmas = false; + + fprintf(stderr, "warning: Christmas is missing.\n"); + } + + JE_loadPals(); + JE_loadMainShapeTables(xmas ? "tyrianc.shp" : "tyrian.shp"); + + if (xmas && !xmas_prompt()) + { + xmas = false; + + free_main_shape_tables(); + JE_loadMainShapeTables("tyrian.shp"); + } + + + /* Default Options */ + youAreCheating = false; + smoothScroll = true; + loadDestruct = false; + + if (!audio_disabled) + { + printf("initializing SDL audio...\n"); + + init_audio(); + + load_music(); + + JE_loadSndFile("tyrian.snd", xmas ? "voicesc.snd" : "voices.snd"); + } + else + { + printf("audio disabled\n"); + } + + if (record_demo) + printf("demo recording enabled (input limited to keyboard)\n"); + + JE_loadExtraShapes(); /*Editship*/ + + JE_loadHelpText(); + /*debuginfo("Help text complete");*/ + + if (isNetworkGame) + { + if (network_init()) + { + network_tyrian_halt(3, false); + } + } + +#ifdef NDEBUG + if (!isNetworkGame) + intro_logos(); +#endif + + for (; ; ) + { + JE_initPlayerData(); + JE_sortHighScores(); + + if (JE_titleScreen(true)) + break; // user quit from title screen + + if (loadDestruct) + { + JE_destructGame(); + loadDestruct = false; + } + else + { + JE_main(); + } + } + + JE_tyrianHalt(0); + + return 0; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/opentyr.h b/alienblaster/project/jni/application/opentyrian/src/opentyr.h new file mode 100644 index 000000000..7244f406e --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/opentyr.h @@ -0,0 +1,61 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef OPENTYR_H +#define OPENTYR_H + +#include "SDL_types.h" +#include +#include + +#define COUNTOF(x) ((unsigned)(sizeof(x) / sizeof *(x))) // use only on arrays! +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // pi +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 // pi/2 +#endif +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 // pi/4 +#endif + +typedef unsigned int uint; +typedef unsigned long ulong; + +// Pascal types, yuck. +typedef Sint32 JE_longint; +typedef Sint16 JE_integer; +typedef Sint8 JE_shortint; +typedef Uint16 JE_word; +typedef Uint8 JE_byte; +typedef bool JE_boolean; +typedef char JE_char; +typedef float JE_real; + +char *strnztcpy( char *to, const char *from, size_t count ); + +extern const char *opentyrian_str, *opentyrian_version; + +void opentyrian_menu( void ); + +#endif /* OPENTYR_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/palette.cpp b/alienblaster/project/jni/application/opentyrian/src/palette.cpp new file mode 100644 index 000000000..1a4b2d859 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/palette.cpp @@ -0,0 +1,214 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "nortsong.h" +#include "opentyr.h" +#include "palette.h" +#include "video.h" + +#include + +static Uint32 rgb_to_yuv( int r, int g, int b ); + +Palette palettes[23]; +int palette_count; + +static Palette palette; +Uint32 rgb_palette[256], yuv_palette[256]; + +Palette colors; + +void JE_loadPals( void ) +{ + FILE *f = dir_fopen_die(data_dir(), "palette.dat", "rb"); + + palette_count = ftell_eof(f) / (256 * 3); + assert(palette_count == 23); // game assumes 23 palettes + + for (int p = 0; p < palette_count; ++p) + { + for (int i = 0; i < 256; ++i) + { + palettes[p][i].r = getc(f) << 2; + palettes[p][i].g = getc(f) << 2; + palettes[p][i].b = getc(f) << 2; + } + } + + fclose(f); +} + +void set_palette( Palette colors, unsigned int first_color, unsigned int last_color ) +{ + SDL_Surface *const surface = SDL_GetVideoSurface(); + const uint bpp = surface->format->BitsPerPixel; + + for (uint i = first_color; i <= last_color; ++i) + { + palette[i] = colors[i]; + + if (bpp != 8) + { + rgb_palette[i] = SDL_MapRGB(surface->format, palette[i].r, palette[i].g, palette[i].b); + yuv_palette[i] = rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b); + } + } + + if (bpp == 8) + SDL_SetColors(surface, palette, first_color, last_color - first_color + 1); +} + +void set_colors( SDL_Color color, unsigned int first_color, unsigned int last_color ) +{ + SDL_Surface *const surface = SDL_GetVideoSurface(); + const uint bpp = surface->format->BitsPerPixel; + + for (uint i = first_color; i <= last_color; ++i) + { + palette[i] = color; + + if (bpp != 8) + { + rgb_palette[i] = SDL_MapRGB(surface->format, palette[i].r, palette[i].g, palette[i].b); + yuv_palette[i] = rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b); + } + } + + if (bpp == 8) + SDL_SetColors(surface, palette, first_color, last_color - first_color + 1); +} + +void init_step_fade_palette( int diff[256][3], Palette colors, unsigned int first_color, unsigned int last_color ) +{ + for (unsigned int i = first_color; i <= last_color; i++) + { + diff[i][0] = (int)colors[i].r - palette[i].r; + diff[i][1] = (int)colors[i].g - palette[i].g; + diff[i][2] = (int)colors[i].b - palette[i].b; + } +} + +void init_step_fade_solid( int diff[256][3], SDL_Color color, unsigned int first_color, unsigned int last_color ) +{ + for (unsigned int i = first_color; i <= last_color; i++) + { + diff[i][0] = (int)color.r - palette[i].r; + diff[i][1] = (int)color.g - palette[i].g; + diff[i][2] = (int)color.b - palette[i].b; + } +} + +void step_fade_palette( int diff[256][3], int steps, unsigned int first_color, unsigned int last_color ) +{ + assert(steps > 0); + + SDL_Surface *const surface = SDL_GetVideoSurface(); + const uint bpp = surface->format->BitsPerPixel; + + for (unsigned int i = first_color; i <= last_color; i++) + { + int delta[3] = { diff[i][0] / steps, diff[i][1] / steps, diff[i][2] / steps }; + + diff[i][0] -= delta[0]; + diff[i][1] -= delta[1]; + diff[i][2] -= delta[2]; + + palette[i].r += delta[0]; + palette[i].g += delta[1]; + palette[i].b += delta[2]; + + if (bpp != 8) + { + rgb_palette[i] = SDL_MapRGB(surface->format, palette[i].r, palette[i].g, palette[i].b); + yuv_palette[i] = rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b); + } + } + + if (bpp == 8) + SDL_SetColors(surface, palette, 0, 256); +} + + +void fade_palette( Palette colors, int steps, unsigned int first_color, unsigned int last_color ) +{ + assert(steps > 0); + + SDL_Surface *const surface = SDL_GetVideoSurface(); + const uint bpp = surface->format->BitsPerPixel; + + static int diff[256][3]; + init_step_fade_palette(diff, colors, first_color, last_color); + + for (; steps > 0; steps--) + { + setdelay(1); + + step_fade_palette(diff, steps, first_color, last_color); + + if (bpp != 8) + JE_showVGA(); + + wait_delay(); + } +} + +void fade_solid( SDL_Color color, int steps, unsigned int first_color, unsigned int last_color ) +{ + assert(steps > 0); + + SDL_Surface *const surface = SDL_GetVideoSurface(); + const uint bpp = surface->format->BitsPerPixel; + + static int diff[256][3]; + init_step_fade_solid(diff, color, first_color, last_color); + + for (; steps > 0; steps--) + { + setdelay(1); + + step_fade_palette(diff, steps, first_color, last_color); + + if (bpp != 8) + JE_showVGA(); + + wait_delay(); + } +} + +void fade_black( int steps ) +{ + SDL_Color black = { 0, 0, 0 }; + fade_solid(black, steps, 0, 255); +} + +void fade_white( int steps ) +{ + SDL_Color white = { 255, 255, 255 }; + fade_solid(white, steps, 0, 255); +} + +static Uint32 rgb_to_yuv( int r, int g, int b ) +{ + int y = (r + g + b) >> 2, + u = 128 + ((r - b) >> 2), + v = 128 + ((-r + 2 * g - b) >> 3); + return (y << 16) + (u << 8) + v; +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/palette.h b/alienblaster/project/jni/application/opentyrian/src/palette.h new file mode 100644 index 000000000..fbeae7e03 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/palette.h @@ -0,0 +1,52 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef PALETTE_H +#define PALETTE_H + +#include "opentyr.h" + +#include "SDL.h" + +typedef SDL_Color Palette[256]; + +extern Palette palettes[]; +extern int palette_count; + +extern Uint32 rgb_palette[256], yuv_palette[256]; + +extern Palette colors; // TODO: get rid of this + +void JE_loadPals( void ); + +void set_palette( Palette colors, unsigned int first_color, unsigned int last_color ); +void set_colors( SDL_Color color, unsigned int first_color, unsigned int last_color ); + +void init_step_fade_palette( int diff[256][3], Palette colors, unsigned int first_color, unsigned int last_color ); +void init_step_fade_solid( int diff[256][3], SDL_Color color, unsigned int first_color, unsigned int last_color ); +void step_fade_palette( int diff[256][3], int steps, unsigned int first_color, unsigned int last_color ); + +void fade_palette( Palette colors, int steps, unsigned int first_color, unsigned int last_color ); +void fade_solid( SDL_Color color, int steps, unsigned int first_color, unsigned int last_color ); + +void fade_black( int steps ); +void fade_white( int steps ); + +#endif /* PALETTE_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/params.cpp b/alienblaster/project/jni/application/opentyrian/src/params.cpp new file mode 100644 index 000000000..34e607241 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/params.cpp @@ -0,0 +1,268 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "arg_parse.h" +#include "file.h" +#include "joystick.h" +#include "loudness.h" +#include "network.h" +#include "opentyr.h" +#include "params.h" +#include "varz.h" +#include "xmas.h" + +#include +#include +#include +#include +#include + +JE_boolean richMode = false, constantPlay = false, constantDie = false; + +/* YKS: Note: LOOT cheat had non letters removed. */ +const char pars[][9] = { + "LOOT", "RECORD", "NOJOY", "CONSTANT", "DEATH", "NOSOUND", "NOXMAS", "YESXMAS" +}; + +void JE_paramCheck( int argc, char *argv[] ) +{ + const Options options[] = + { + { 'h', 'h', "help", false }, + + { 's', 's', "no-sound", false }, + { 'j', 'j', "no-joystick", false }, + { 'x', 'x', "no-xmas", false }, + + { 't', 't', "data", true }, + + { 'n', 'n', "net", true }, + { 256, 0, "net-player-name", true }, // TODO: no short codes because there should + { 257, 0, "net-player-number", true }, // be a menu for entering these in the future + { 'p', 'p', "net-port", true }, + { 'd', 'd', "net-delay", true }, + + { 'X', 'X', "xmas", false }, + { 'c', 'c', "constant", false }, + { 'k', 'k', "death", false }, + { 'r', 'r', "record", false }, + { 'l', 'l', "loot", false }, + + { 0, 0, NULL, false} + }; + Option option = { 0, NULL, 0 }; + + for (; ; ) + { + option = parse_args(argc, (const char **)argv, options); + + if (option.value == NOT_OPTION) + break; + + switch (option.value) + { + case INVALID_OPTION: + case AMBIGUOUS_OPTION: + case OPTION_MISSING_ARG: + fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); + exit(EXIT_FAILURE); + break; + + case 'h': + printf("Usage: %s [OPTION...]\n\n" + "Options:\n" + " -h, --help Show help about options\n\n" + " -s, --no-sound Disable audio\n" + " -j, --no-joystick Disable joystick/gamepad input\n" + " -x, --no-xmas Disable Christmas mode\n\n" + " -t, --data=DIR Set Tyrian data directory\n\n" + " -n, --net=HOST[:PORT] Start a networked game\n" + " --net-player-name=NAME Sets local player name in a networked game\n" + " --net-player-number=NUMBER Sets local player number in a networked game\n" + " (1 or 2)\n" + " -p, --net-port=PORT Local port to bind (default is 1333)\n" + " -d, --net-delay=FRAMES Set lag-compensation delay (default is 1)\n", argv[0]); + exit(0); + break; + + case 's': + // Disables sound/music usage + audio_disabled = true; + break; + + case 'j': + // Disables joystick detection + ignore_joystick = true; + break; + + case 'x': + xmas = false; + break; + + // set custom Tyrian data directory + case 't': + custom_data_dir = option.arg; + break; + + case 'n': + { + isNetworkGame = true; + + intptr_t temp = (intptr_t)strchr(option.arg, ':'); + if (temp) + { + temp -= (intptr_t)option.arg; + + int temp_port = atoi(&option.arg[temp + 1]); + if (temp_port > 0 && temp_port < 49152) + network_opponent_port = temp_port; + else + { + fprintf(stderr, "%s: error: invalid network port number\n", argv[0]); + exit(EXIT_FAILURE); + } + + network_opponent_host = (char *)malloc(temp + 1); + strnztcpy(network_opponent_host, option.arg, temp); + } + else + { + network_opponent_host = (char *)malloc(strlen(option.arg) + 1); + strcpy(network_opponent_host, option.arg); + } + } + break; + + case 256: // --net-player-name + network_player_name = (char *)malloc(strlen(option.arg) + 1); + strcpy(network_player_name, option.arg); + break; + + case 257: // --net-player-number + { + int temp = atoi(option.arg); + if (temp >= 1 && temp <= 2) + thisPlayerNum = temp; + else + { + fprintf(stderr, "%s: error: invalid network player number\n", argv[0]); + exit(EXIT_FAILURE); + } + break; + } + case 'p': + { + int temp = atoi(option.arg); + if (temp > 0 && temp < 49152) + network_player_port = temp; + else + { + fprintf(stderr, "%s: error: invalid network port number\n", argv[0]); + exit(EXIT_FAILURE); + } + break; + } + case 'd': + { + int temp; + if (sscanf(option.arg, "%d", &temp) == 1) + network_delay = 1 + temp; + else + { + fprintf(stderr, "%s: error: invalid network delay value\n", argv[0]); + exit(EXIT_FAILURE); + } + break; + } + case 'X': + xmas = true; + break; + + case 'c': + /* Constant play for testing purposes (C key activates invincibility) + This might be useful for publishers to see everything - especially + those who can't play it */ + constantPlay = true; + break; + + case 'k': + constantDie = true; + break; + + case 'r': + record_demo = true; + break; + + case 'l': + // Gives you mucho bucks + richMode = true; + break; + + default: + assert(false); + break; + } + } + + // legacy parameter support + for (int i = option.argn; i < argc; ++i) + { + for (uint j = 0; j < strlen(argv[i]); ++j) + argv[i][j] = toupper((unsigned char)argv[i][j]); + + for (uint j = 0; j < COUNTOF(pars); ++j) + { + if (strcmp(argv[i], pars[j]) == 0) + { + switch (j) + { + case 0: + richMode = true; + break; + case 1: + record_demo = true; + break; + case 2: + ignore_joystick = true; + break; + case 3: + constantPlay = true; + break; + case 4: + constantDie = true; + break; + case 5: + audio_disabled = true; + break; + case 6: + xmas = false; + break; + case 7: + xmas = true; + break; + + default: + assert(false); + break; + } + } + } + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/params.h b/alienblaster/project/jni/application/opentyrian/src/params.h new file mode 100644 index 000000000..29640aebb --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/params.h @@ -0,0 +1,30 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef PARAMS_H +#define PARAMS_H + +#include "opentyr.h" + +extern JE_boolean richMode, constantPlay, constantDie; + +void JE_paramCheck( int argc, char *argv[] ); + +#endif /* PARAMS_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/pcxload.cpp b/alienblaster/project/jni/application/opentyrian/src/pcxload.cpp new file mode 100644 index 000000000..fc3cdefe8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/pcxload.cpp @@ -0,0 +1,67 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "opentyr.h" +#include "palette.h" +#include "pcxload.h" +#include "video.h" + +void JE_loadPCX( const char *file ) // this is only meant to load tshp2.pcx +{ + Uint8 *s = (Uint8 *)VGAScreen->pixels; /* 8-bit specific */ + + FILE *f = dir_fopen_die(data_dir(), file, "rb"); + + fseek(f, -769, SEEK_END); + + if (fgetc(f) == 12) + { + for (int i = 0; i < 256; i++) + { + efread(&colors[i].r, 1, 1, f); + efread(&colors[i].g, 1, 1, f); + efread(&colors[i].b, 1, 1, f); + } + } + + fseek(f, 128, SEEK_SET); + + for (int i = 0; i < 320 * 200; ) + { + Uint8 p = fgetc(f); + if ((p & 0xc0) == 0xc0) + { + i += (p & 0x3f); + memset(s, fgetc(f), (p & 0x3f)); + s += (p & 0x3f); + } else { + i++; + *s = p; + s++; + } + if (i && (i % 320 == 0)) + { + s += VGAScreen->pitch - 320; + } + } + + fclose(f); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/pcxload.h b/alienblaster/project/jni/application/opentyrian/src/pcxload.h new file mode 100644 index 000000000..77da856ab --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/pcxload.h @@ -0,0 +1,28 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef PCXLOAD_H +#define PCXLOAD_H + +#include "opentyr.h" + +void JE_loadPCX( const char *file ); + +#endif /* PCXLOAD_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/pcxmast.cpp b/alienblaster/project/jni/application/opentyrian/src/pcxmast.cpp new file mode 100644 index 000000000..488a563b8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/pcxmast.cpp @@ -0,0 +1,49 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "opentyr.h" +#include "pcxmast.h" + + +const char *pcxfile[PCX_NUM] = /* [1..PCXnum] */ +{ + "INTSHPB.PCX", + "SETUP2.PCX", + "TYRPLAY.PCX", + "TYRLOG2.PCX", + "P1.PCX", + "TYRPLAY2.PCX", + "BUC4.PCX", + "GMOVR4a.PCX", + "GMOVR4b.PCX", + "EPICSKY.PCX", + "DESTRUCT.PCX", + "ECLIPSE.PCX", + "FIREPICA.PCX" +}; + +const JE_byte pcxpal[PCX_NUM] = /* [1..PCXnum] */ +{ 0, 7, 5, 8, 10, 5, 18, 19, 19, 20, 21, 22, 5}; + +/*FACEMAX*/ +const JE_byte facepal[12] = /* [1..12] */ +{ 1, 2, 3, 4, 6, 9, 11, 12, 16, 13, 14, 15}; + +JE_pcxpostype pcxpos; + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/pcxmast.h b/alienblaster/project/jni/application/opentyrian/src/pcxmast.h new file mode 100644 index 000000000..7881795e9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/pcxmast.h @@ -0,0 +1,36 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef PCXMAST_H +#define PCXMAST_H + +#include "opentyr.h" + + +#define PCX_NUM 13 + +typedef JE_longint JE_pcxpostype[PCX_NUM + 1]; /* [1..PCXnum + 1] */ + +extern const char *pcxfile[PCX_NUM]; /* [1..PCXnum] */ +extern const JE_byte pcxpal[PCX_NUM]; /* [1..PCXnum] */ +extern const JE_byte facepal[12]; /* [1..12] */ +extern JE_pcxpostype pcxpos; + +#endif /* PCXMAST_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/picload.cpp b/alienblaster/project/jni/application/opentyrian/src/picload.cpp new file mode 100644 index 000000000..68241fcce --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/picload.cpp @@ -0,0 +1,87 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "opentyr.h" +#include "palette.h" +#include "pcxmast.h" +#include "picload.h" +#include "video.h" + +#include + +void JE_loadPic(SDL_Surface *screen, JE_byte PCXnumber, JE_boolean storepal ) +{ + PCXnumber--; + + FILE *f = dir_fopen_die(data_dir(), "tyrian.pic", "rb"); + + static bool first = true; + if (first) + { + first = false; + + Uint16 temp; + efread(&temp, sizeof(Uint16), 1, f); + for (int i = 0; i < PCX_NUM; i++) + { + efread(&pcxpos[i], sizeof(JE_longint), 1, f); + } + + pcxpos[PCX_NUM] = ftell_eof(f); + } + + unsigned int size = pcxpos[PCXnumber + 1] - pcxpos[PCXnumber]; + Uint8 *buffer = (Uint8 *)malloc(size); + + fseek(f, pcxpos[PCXnumber], SEEK_SET); + efread(buffer, sizeof(Uint8), size, f); + fclose(f); + + Uint8 *p = buffer; + Uint8 *s; /* screen pointer, 8-bit specific */ + + s = (Uint8 *)screen->pixels; + + for (int i = 0; i < 320 * 200; ) + { + if ((*p & 0xc0) == 0xc0) + { + i += (*p & 0x3f); + memset(s, *(p + 1), (*p & 0x3f)); + s += (*p & 0x3f); p += 2; + } else { + i++; + *s = *p; + s++; p++; + } + if (i && (i % 320 == 0)) + { + s += screen->pitch - 320; + } + } + + free(buffer); + + memcpy(colors, palettes[pcxpal[PCXnumber]], sizeof(colors)); + + if (storepal) + set_palette(colors, 0, 255); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/picload.h b/alienblaster/project/jni/application/opentyrian/src/picload.h new file mode 100644 index 000000000..bd2745934 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/picload.h @@ -0,0 +1,28 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef PICLOAD_H +#define PICLOAD_H + +#include "opentyr.h" + +void JE_loadPic(SDL_Surface *screen, JE_byte PCXnumber, JE_boolean storepal ); + +#endif /* PICLOAD_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/player.cpp b/alienblaster/project/jni/application/opentyrian/src/player.cpp new file mode 100644 index 000000000..e8ab7f18d --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/player.cpp @@ -0,0 +1,55 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "player.h" + +Player player[2]; + +void calc_purple_balls_needed( Player *this_player ) +{ + static const uint purple_balls_required[12] = { 1, 1, 2, 4, 8, 12, 16, 20, 25, 30, 40, 50 }; + + this_player->purple_balls_needed = purple_balls_required[*this_player->lives]; +} + +bool power_up_weapon( Player *this_player, uint port ) +{ + const bool can_power_up = this_player->items.weapon[port].id != 0 && // not None + this_player->items.weapon[port].power < 11; // not at max power + if (can_power_up) + { + ++this_player->items.weapon[port].power; + shotMultiPos[port] = 0; // TODO: should be part of Player structure + + calc_purple_balls_needed(this_player); + } + else // cash consolation prize + { + this_player->cash += 1000; + } + + return can_power_up; +} + +void handle_got_purple_ball( Player *this_player ) +{ + if (this_player->purple_balls_needed > 1) + --this_player->purple_balls_needed; + else + power_up_weapon(this_player, this_player->is_dragonwing ? REAR_WEAPON : FRONT_WEAPON); +} diff --git a/alienblaster/project/jni/application/opentyrian/src/player.h b/alienblaster/project/jni/application/opentyrian/src/player.h new file mode 100644 index 000000000..ef060f4e8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/player.h @@ -0,0 +1,129 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef PLAYER_H +#define PLAYER_H + +#include "config.h" +#include "opentyr.h" + +enum +{ + FRONT_WEAPON = 0, + REAR_WEAPON = 1 +}; + +enum +{ + LEFT_SIDEKICK = 0, + RIGHT_SIDEKICK = 1 +}; + +typedef struct +{ + uint ship; + uint generator; + uint shield; + struct { uint id; uint power; } weapon[2]; + uint sidekick[2]; + uint special; + + // Dragonwing only: + // repeatedly collecting the same powerup gives a series of sidekick upgrades + uint sidekick_series; + uint sidekick_level; + + // Single-player only + uint super_arcade_mode; // stored as an item for compatibility :( +} +PlayerItems; + +typedef struct +{ + ulong cash; + + PlayerItems items, last_items; + + bool is_dragonwing; // i.e., is player 2 + uint *lives; + + // calculatable + uint shield_max; + uint initial_armor; + uint shot_hit_area_x, shot_hit_area_y; + + // state + bool is_alive; + uint invulnerable_ticks; // ticks until ship can be damaged + uint exploding_ticks; // ticks until ship done exploding + uint shield; + uint armor; + uint weapon_mode; + uint superbombs; + uint purple_balls_needed; + + int x, y; + int old_x[20], old_y[20]; + + int x_velocity, y_velocity; + uint x_friction_ticks, y_friction_ticks; // ticks until friction is applied + + int delta_x_shot_move, delta_y_shot_move; + + int last_x_shot_move, last_y_shot_move; + int last_x_explosion_follow, last_y_explosion_follow; + + struct + { + // calculatable + int ammo_max; + uint ammo_refill_ticks_max; + uint style; // affects movement and size + + // state + int x, y; + int ammo; + uint ammo_refill_ticks; + + bool animation_enabled; + uint animation_frame; + + uint charge; + uint charge_ticks; + } + sidekick[2]; +} +Player; + +extern Player player[2]; + +static inline bool all_players_dead( void ) +{ + return (!player[0].is_alive && (!twoPlayerMode || !player[1].is_alive)); +} + +static inline bool all_players_alive( void ) +{ + return (player[0].is_alive && (!twoPlayerMode || player[1].is_alive)); +} + +void calc_purple_balls_needed( Player * ); +bool power_up_weapon( Player *, uint port ); +void handle_got_purple_ball( Player * ); + +#endif // PLAYER_H diff --git a/alienblaster/project/jni/application/opentyrian/src/scroller.cpp b/alienblaster/project/jni/application/opentyrian/src/scroller.cpp new file mode 100644 index 000000000..62e39c8a4 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/scroller.cpp @@ -0,0 +1,313 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "font.h" +#include "joystick.h" +#include "jukebox.h" +#include "keyboard.h" +#include "loudness.h" +#include "mtrand.h" +#include "nortsong.h" +#include "nortvars.h" +#include "opentyr.h" +#include "palette.h" +#include "scroller.h" +#include "sprite.h" +#include "varz.h" +#include "vga256d.h" +#include "video.h" + +const struct about_text_type about_text[] = +{ + {0x30, "----- ~OpenTyrian~ -----"}, + {0x00, ""}, + {0x0b, "...eliminating Microsol,"}, + {0x0b, "one planet at a time..."}, + {0x00, ""}, + {0x00, ""}, + {0x30, "----- ~Developers~ -----"}, + {0x00, ""}, + {0x03, "Carl Reinke // Mindless"}, + {0x07, "Yuri Schlesner // yuriks"}, + {0x04, "Casey McCann // syntaxglitch"}, + {0x00, ""}, + {0x00, ""}, + {0x30, "----- ~Thanks~ -----"}, + {0x00, ""}, + {0x0e, "Thanks to everyone who has"}, + {0x0e, "assisted the developers by testing"}, + {0x0e, "the game and reporting bugs."}, + {0x00, ""}, + {0x00, ""}, + {0x05, "Thanks to ~MAME~ and ~DOSBox~"}, + {0x05, "for the FM emulator and"}, + {0x05, "~AdPlug~ for the Loudness code."}, + {0x00, ""}, + {0x00, ""}, + {0x32, "And special thanks to ~Jason Emery~"}, + {0x32, "for making all this possible"}, + {0x32, "by giving Tyrian to its fans."}, + {0x00, ""}, + {0x00, ""}, +/* {0x00, "This is line color test ~0~."}, + {0x01, "This is line color test ~1~."}, + {0x02, "This is line color test ~2~."}, + {0x03, "This is line color test ~3~."}, + {0x04, "This is line color test ~4~."}, + {0x05, "This is line color test ~5~."}, + {0x06, "This is line color test ~6~."}, + {0x07, "This is line color test ~7~."}, + {0x08, "This is line color test ~8~."}, + {0x09, "This is line color test ~9~."}, + {0x0a, "This is line color test ~A~."}, + {0x0b, "This is line color test ~B~."}, + {0x0c, "This is line color test ~C~."}, + {0x0d, "This is line color test ~D~."}, + {0x0e, "This is line color test ~E~."}, + {0x0f, "This is line color test ~F~."},*/ + {0x00, ""}, + {0x00, ""}, + {0x00, ""}, + {0x00, ""}, + {0x00, ""}, + {0x00, ""}, + {0x00, "Press a key to leave."}, + {0x00, NULL} +}; + +#define LINE_HEIGHT 15 + +#define MAX_BEER 5 +#define BEER_SHAPE 241 + +struct coin_def_type { + int shape_num; + int frame_count; + bool reverse_anim; +}; + +#define MAX_COINS 20 +struct coin_def_type coin_defs[] = +{ + {1, 6}, {7, 6}, {20, 6}, {26, 6}, // Coins + {14, 5, true}, {32, 5, true}, {51, 5, true} // Gems +}; + +/* Text is an array of strings terminated by a NULL */ +void scroller_sine( const struct about_text_type text[] ) +{ + bool ale = mt_rand() % 2; + + int visible_lines = vga_height / LINE_HEIGHT + 1; + int current_line = -visible_lines; + int y = 0; + bool fade_in = true; + + struct coin_type { int x, y, vel, type, cur_frame; bool backwards; } coins[MAX_COINS]; + struct { int x, y, ay, vx, vy; } beer[MAX_BEER]; + + if (ale) + { + memset(beer, 0, sizeof(beer)); + } else { + for (int i = 0; i < MAX_COINS; i++) + { + coins[i].x = mt_rand() % (vga_width - 12); + coins[i].y = mt_rand() % (vga_height - 20 - 14); + + coins[i].vel = (mt_rand() % 4) + 1; + coins[i].type = mt_rand() % COUNTOF(coin_defs); + coins[i].cur_frame = mt_rand() % coin_defs[coins[i].type].frame_count; + coins[i].backwards = false; + } + } + + fade_black(10); + + wait_noinput(true, true, true); + + play_song(40); // BEER + + while (!JE_anyButton()) + { + setdelay(3); + + JE_clr256(VGAScreen); + + if (!ale) + { + for (int i = 0; i < MAX_COINS/2; i++) + { + struct coin_type *coin = &coins[i]; + blit_sprite2(VGAScreen, coin->x, coin->y, eShapes5, coin_defs[coin->type].shape_num + coin->cur_frame); + } + } + + for (int i = 0; i < visible_lines; i++) + { + if (current_line + i >= 0) + { + if (text[current_line + i].text == NULL) + { + break; + } + + int line_x = VGAScreen->w / 2; + int line_y = i * LINE_HEIGHT - y; + + // smooths edges on sine-wave text + if (text[i + current_line].effect & 0x20) + { + draw_font_hv(VGAScreen, line_x + 1, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -10); + draw_font_hv(VGAScreen, line_x - 1, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -10); + } + + draw_font_hv(VGAScreen, line_x, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -4); + + if (text[i + current_line].effect & 0x10) + { + for (int j = 0; j < LINE_HEIGHT; j++) + { + if (line_y + j >= 10 && line_y + j <= vga_height - 10) + { + int waver = sinf((((line_y + j) / 2) % 10) / 5.0f * M_PI) * 3; + memmove(&((Uint8 *)VGAScreen->pixels)[VGAScreen->pitch * (line_y + j) + waver], + &((Uint8 *)VGAScreen->pixels)[VGAScreen->pitch * (line_y + j)], + VGAScreen->pitch); + } + } + } + } + } + + if (++y == LINE_HEIGHT) + { + y = 0; + + if (current_line < 0 || text[current_line].text != NULL) + ++current_line; + else + current_line = -visible_lines; + } + + if (!ale) + { + for (int i = MAX_COINS/2; i < MAX_COINS; i++) + { + struct coin_type *coin = &coins[i]; + blit_sprite2(VGAScreen, coin->x, coin->y, eShapes5, coin_defs[coin->type].shape_num + coin->cur_frame); + } + } + + fill_rectangle_xy(VGAScreen, 0, 0, vga_width - 1, 14, 0); + fill_rectangle_xy(VGAScreen, 0, vga_height - 14, vga_width - 1, vga_height - 1, 0); + + if (!ale) + { + for (int i = 0; i < MAX_COINS; i++) + { + struct coin_type *coin = &coins[i]; + + if (coin->backwards) + { + coin->cur_frame--; + } else { + coin->cur_frame++; + } + if (coin->cur_frame == coin_defs[coin->type].frame_count) + { + if (coin_defs[coin->type].reverse_anim) + { + coin->backwards = true; + coin->cur_frame -= 2; + } else { + coin->cur_frame = 0; + } + } + if (coin->cur_frame == -1) + { + coin->cur_frame = 1; + coin->backwards = false; + } + + coin->y += coin->vel; + if (coin->y > vga_height - 14) + { + coin->x = mt_rand() % (vga_width - 12); + coin->y = 0; + + coin->vel = (mt_rand() % 4) + 1; + coin->type = mt_rand() % COUNTOF(coin_defs); + coin->cur_frame = mt_rand() % coin_defs[coin->type].frame_count; + } + } + } else { + for (uint i = 0; i < COUNTOF(beer); i++) + { + while (beer[i].vx == 0) + { + beer[i].x = mt_rand() % (vga_width - 24); + beer[i].y = mt_rand() % (vga_height - 28 - 50); + + beer[i].vx = (mt_rand() % 5) - 2; + } + + beer[i].vy++; + + if (beer[i].x + beer[i].vx > vga_width - 24 || beer[i].x + beer[i].vx < 0) // check if the beer hit the sides + { + beer[i].vx = -beer[i].vx; + } + beer[i].x += beer[i].vx; + + if (beer[i].y + beer[i].vy > vga_height - 28) // check if the beer hit the bottom + { + if ((beer[i].vy) < 8) // make sure the beer bounces! + { + beer[i].vy += mt_rand() % 2; + } else if (beer[i].vy > 16) { // make sure the beer doesn't bounce too high + beer[i].vy = 16; + } + beer[i].vy = -beer[i].vy + (mt_rand() % 3 - 1); + + beer[i].x += (beer[i].vx > 0 ? 1 : -1) * (i % 2 ? 1 : -1); + } + beer[i].y += beer[i].vy; + + blit_sprite2x2(VGAScreen, beer[i].x, beer[i].y, eShapes5, BEER_SHAPE); + } + } + + JE_showVGA(); + + if (fade_in) + { + fade_in = false; + fade_palette(colors, 10, 0, 255); + + SDL_Color white = { 255, 255, 255 }; + set_colors(white, 254, 254); + } + + wait_delay(); + } + + fade_black(10); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/scroller.h b/alienblaster/project/jni/application/opentyrian/src/scroller.h new file mode 100644 index 000000000..e06702b99 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/scroller.h @@ -0,0 +1,33 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef SCROLLER_H +#define SCROLLER_H + +#include "opentyr.h" + +extern const struct about_text_type { + int effect; + const char *text; +} about_text[]; + +void scroller_sine( const struct about_text_type text[] ); + +#endif /* SCROLLER_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/setup.cpp b/alienblaster/project/jni/application/opentyrian/src/setup.cpp new file mode 100644 index 000000000..40450cb42 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/setup.cpp @@ -0,0 +1,96 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "joystick.h" +#include "keyboard.h" +#include "network.h" +#include "nortvars.h" +#include "opentyr.h" +#include "mainint.h" +#include "mouse.h" +#include "setup.h" +#include "video.h" + +#include "SDL.h" + +void JE_textMenuWait( JE_word *waitTime, JE_boolean doGamma ) +{ + set_mouse_position(160, 100); + + do + { + JE_showVGA(); + + push_joysticks_as_keyboard(); + service_SDL_events(true); + + if (doGamma) + JE_gammaCheck(); + + inputDetected = newkey | mousedown; + + if (lastkey_sym == SDLK_SPACE) + { + lastkey_sym = SDLK_RETURN; + } + + if (mousedown) + { + newkey = true; + lastkey_sym = SDLK_RETURN; + } + + if (has_mouse && input_grabbed) + { + if (abs(mouse_y - 100) > 10) + { + inputDetected = true; + if (mouse_y - 100 < 0) + { + lastkey_sym = SDLK_UP; + } else { + lastkey_sym = SDLK_DOWN; + } + newkey = true; + } + if (abs(mouse_x - 160) > 10) + { + inputDetected = true; + if (mouse_x - 160 < 0) + { + lastkey_sym = SDLK_LEFT; + } else { + lastkey_sym = SDLK_RIGHT; + } + newkey = true; + } + } + + NETWORK_KEEP_ALIVE(); + + SDL_Delay(16); + + if (*waitTime > 0) + { + (*waitTime)--; + } + } while (!(inputDetected || *waitTime == 1 || haltGame)); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/setup.h b/alienblaster/project/jni/application/opentyrian/src/setup.h new file mode 100644 index 000000000..c40b9976d --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/setup.h @@ -0,0 +1,28 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef SETUP_H +#define SETUP_H + +#include "opentyr.h" + +void JE_textMenuWait( JE_word *waitTime, JE_boolean doGamma ); + +#endif /* SETUP_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/sizebuf.cpp b/alienblaster/project/jni/application/opentyrian/src/sizebuf.cpp new file mode 100644 index 000000000..b32c4f0dc --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/sizebuf.cpp @@ -0,0 +1,222 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * This file is largely based on (and named after) a set of common reading/ + * writing functions used in Quake engines. Its purpose is to allow extraction + * of bytes, words, and dwords in a safe, endian adjused environment and should + * probably be used in any situation where checking for buffer overflows + * manually makes the code a godawful mess. + * + * Currently this is only used by the animation decoding. + * + * This file is written with the intention of being easily converted into a + * class capable of throwing exceptions if data is out of range. + * + * If an operation fails, subsequent operations will also fail. The sizebuf + * is assumed to be in an invalid state. This COULD be changed pretty easily + * and in normal Quake IIRC it is. But our MO is to bail on failure, not + * figure out what went wrong (making throws perfect). + */ + +#include "sizebuf.h" +#include + +#include "SDL_endian.h" + +/* Construct buffer with the passed array and size */ +void SZ_Init(sizebuf_t * sz, Uint8 * buf, unsigned int size) +{ + sz->data = buf; + sz->bufferLen = size; + sz->bufferPos = 0; + sz->error = false; +} +/* Check error flags */ +bool SZ_Error(sizebuf_t * sz) +{ + return(sz->error); +} +/* mimic memset */ +void SZ_Memset(sizebuf_t * sz, int value, size_t count) +{ + /* Do bounds checking before writing */ + if (sz->error || sz->bufferPos + count > sz->bufferLen) + { + sz->error = true; + return; + } + + /* Memset and increment pointer */ + memset(sz->data + sz->bufferPos, value, count); + sz->bufferPos += count; +} +/* Mimic memcpy. Two versions, one for buffers, one for sizebuf objects. + * Overload in C++. */ +void SZ_Memcpy(sizebuf_t * sz, const Uint8 * buf, size_t count) +{ + /* State checking */ + if (sz->error || sz->bufferPos + count > sz->bufferLen) + { + sz->error = true; + return; + } + + /* Memcpy & increment */ + memcpy(sz->data + sz->bufferPos, buf, count); + sz->bufferPos += count; +} +void SZ_Memcpy2(sizebuf_t * sz, sizebuf_t * bf, size_t count) +{ + /* State checking */ + if (sz->error || sz->bufferPos + count > sz->bufferLen) + { + sz->error = true; + return; + } + if (bf->error || bf->bufferPos + count > bf->bufferLen) + { + bf->error = true; + return; + } + + /* Memcpy & increment */ + memcpy(sz->data + sz->bufferPos, bf->data + bf->bufferPos, count); + sz->bufferPos += count; + bf->bufferPos += count; +} +/* Reposition buffer pointer */ +void SZ_Seek(sizebuf_t * sz, long count, int mode) +{ + /* Okay, it's reasonable to reset the error bool on seeking... */ + + switch(mode) + { + case SEEK_SET: + sz->bufferPos = count; + break; + case SEEK_CUR: + sz->bufferPos += count; + break; + case SEEK_END: + sz->bufferPos = sz->bufferLen - count; + break; + default: + assert(false); + } + + /* Check errors */ + if (sz->bufferPos > sz->bufferLen) + { + sz->error = true; + } else { + sz->error = false; + } +} +const Uint8 * SZ_GetCurBufferPtr (sizebuf_t * sz) +{ + return(sz->data); +} + +/* The code below makes use of pointer casts, similar to what is in efread. + * It's not the ONLY way to write ints to a stream, but it's probably the + * cleanest of the lot. Better to have it here than littered all over the code. + */ +void MSG_WriteByte(sizebuf_t * sz, unsigned int value) +{ + if (sz->error || sz->bufferPos + 1 > sz->bufferLen) + { + sz->error = true; + return; + } + + sz->data[sz->bufferPos] = value; + sz->bufferPos++; +} +void MSG_WriteWord(sizebuf_t * sz, unsigned int value) +{ + if (sz->error || sz->bufferPos + 2 > sz->bufferLen) + { + sz->error = true; + return; + } + + *((Uint16 *)(sz->data + sz->bufferPos)) = SDL_SwapLE16( ((Uint16)value) ); + sz->bufferPos += 2; +} +void MSG_WriteDWord(sizebuf_t * sz, unsigned int value) +{ + if (sz->error || sz->bufferPos + 4 > sz->bufferLen) + { + sz->error = true; + return; + } + + *((Uint32 *)(sz->data + sz->bufferPos)) = SDL_SwapLE32( ((Uint32)value) ); + sz->bufferPos += 4; +} + +unsigned int MSG_ReadByte(sizebuf_t * sz) +{ + unsigned int ret; + + + if (sz->error || sz->bufferPos + 1 > sz->bufferLen) + { + sz->error = true; + return(0); + } + + ret = sz->data[sz->bufferPos]; + sz->bufferPos += 1; + + return(ret); +} +unsigned int MSG_ReadWord(sizebuf_t * sz) +{ + unsigned int ret; + + + if (sz->error || sz->bufferPos + 2 > sz->bufferLen) + { + sz->error = true; + return(0); + } + + ret = SDL_SwapLE16(*((Uint16 *)(sz->data + sz->bufferPos))); + sz->bufferPos += 2; + + return(ret); +} +unsigned int MSG_ReadDWord(sizebuf_t * sz) +{ + unsigned int ret; + + + if (sz->error || sz->bufferPos + 4 > sz->bufferLen) + { + sz->error = true; + return(0); + } + + ret = SDL_SwapLE32(*((Uint32 *)(sz->data + sz->bufferPos))); + sz->bufferPos += 4; + + return(ret); +} diff --git a/alienblaster/project/jni/application/opentyrian/src/sizebuf.h b/alienblaster/project/jni/application/opentyrian/src/sizebuf.h new file mode 100644 index 000000000..f3d8003b4 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/sizebuf.h @@ -0,0 +1,50 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SIZEBUF_H +#define SIZEBUF_H + +#include "opentyr.h" + +typedef struct sizebuf_s +{ + Uint8 *data; + unsigned int bufferLen; + unsigned int bufferPos; + bool error; +} sizebuf_t; + +void SZ_Init ( sizebuf_t *, Uint8 *, unsigned int ); /* C style constructor */ +bool SZ_Error ( sizebuf_t * ); +void SZ_Memset ( sizebuf_t *, int, size_t ); /* memset with a sizebuf */ +void SZ_Memcpy ( sizebuf_t *, const Uint8 *, size_t ); /* memcpy with a normal buffer */ +void SZ_Memcpy2 ( sizebuf_t *, sizebuf_t *, size_t ); /* memcpy with a sizebuf */ +void SZ_Seek ( sizebuf_t *, long, int ); /* fseek with a sizebuf. */ + +const Uint8 * SZ_GetCurBufferPtr ( sizebuf_t * ); /* Mimic private member, const return */ + +void MSG_WriteByte ( sizebuf_t *, unsigned int ); +void MSG_WriteWord ( sizebuf_t *, unsigned int ); +void MSG_WriteDWord ( sizebuf_t *, unsigned int ); + +unsigned int MSG_ReadByte ( sizebuf_t * ); +unsigned int MSG_ReadWord ( sizebuf_t * ); +unsigned int MSG_ReadDWord ( sizebuf_t * ); + +#endif diff --git a/alienblaster/project/jni/application/opentyrian/src/sndmast.cpp b/alienblaster/project/jni/application/opentyrian/src/sndmast.cpp new file mode 100644 index 000000000..3fd7eb27b --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/sndmast.cpp @@ -0,0 +1,78 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "opentyr.h" +#include "sndmast.h" + + +const char soundTitle[SAMPLE_COUNT][9] = /* [1..soundnum + 9] of string [8] */ +{ + "SCALEDN2", /*1*/ + "F2", /*2*/ + "TEMP10", + "EXPLSM", + "PASS3", /*5*/ + "TEMP2", + "BYPASS1", + "EXP1RT", + "EXPLLOW", + "TEMP13", /*10*/ + "EXPRETAP", + "MT2BOOM", + "TEMP3", + "LAZB", /*28K*/ + "LAZGUN2", /*15*/ + "SPRING", + "WARNING", + "ITEM", + "HIT2", /*14K*/ + "MACHNGUN", /*20*/ + "HYPERD2", + "EXPLHUG", + "CLINK1", + "CLICK", + "SCALEDN1", /*25*/ + "TEMP11", + "TEMP16", + "SMALL1", + "POWERUP", + "VOICE1", + "VOICE2", + "VOICE3", + "VOICE4", + "VOICE5", + "VOICE6", + "VOICE7", + "VOICE8", + "VOICE9" +}; + +const JE_byte windowTextSamples[9] = /* [1..9] */ +{ + V_DANGER, + V_BOSS, + V_ENEMIES, + V_CLEARED_PLATFORM, + V_DANGER, + V_SPIKES, + V_ACCELERATE, + V_DANGER, + V_ENEMIES +}; + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/sndmast.h b/alienblaster/project/jni/application/opentyrian/src/sndmast.h new file mode 100644 index 000000000..74bb2920e --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/sndmast.h @@ -0,0 +1,76 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef SNDMAST_H +#define SNDMAST_H + +#include "opentyr.h" + +#define SAMPLE_COUNT 38 + + + +enum +{ + S_NONE = 0, + S_WEAPON_1, + S_WEAPON_2, + S_ENEMY_HIT, + S_EXPLOSION_4, + S_WEAPON_5, + S_WEAPON_6, + S_WEAPON_7, + S_SELECT, // S_EXPLOSION_8 + S_EXPLOSION_9, + S_WEAPON_10, + S_EXPLOSION_11, + S_EXPLOSION_12, + S_WEAPON_13, + S_WEAPON_14, + S_WEAPON_15, + S_SPRING, + S_WARNING, + S_ITEM, + S_HULL_HIT, + S_MACHINE_GUN, + S_SOUL_OF_ZINGLON, + S_EXPLOSION_22, + S_CLINK, + S_CLICK, + S_WEAPON_25, + S_WEAPON_26, + S_SHIELD_HIT, + S_CURSOR, + S_POWERUP, + V_CLEARED_PLATFORM, // 30 + V_BOSS, + V_ENEMIES, + V_GOOD_LUCK, + V_LEVEL_END, + V_DANGER, + V_SPIKES, + V_DATA_CUBE, + V_ACCELERATE +}; + +extern const char soundTitle[SAMPLE_COUNT][9]; +extern const JE_byte windowTextSamples[9]; + +#endif /* SNDMAST_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/sprite.cpp b/alienblaster/project/jni/application/opentyrian/src/sprite.cpp new file mode 100644 index 000000000..1a0c9f424 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/sprite.cpp @@ -0,0 +1,732 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "file.h" +#include "opentyr.h" +#include "sprite.h" +#include "video.h" + +#include + +Sprite_array sprite_table[SPRITE_TABLES_MAX]; + +Sprite2_array eShapes1, eShapes2, eShapes3, eShapes4, eShapes5, eShapes6; +Sprite2_array shapesC1, shapes6, shapes9, shapesW2; + +void load_sprites_file( unsigned int table, const char *filename ) +{ + free_sprites(table); + + FILE *f = dir_fopen_die(data_dir(), filename, "rb"); + + load_sprites(table, f); + + fclose(f); +} + +void load_sprites( unsigned int table, FILE *f ) +{ + free_sprites(table); + + Uint16 temp; + efread(&temp, sizeof(Uint16), 1, f); + + sprite_table[table].count = temp; + + for (unsigned int i = 0; i < sprite_table[table].count; ++i) + { + Sprite * const cur_sprite = sprite(table, i); + + if (!getc(f)) // sprite is empty + continue; + + efread(&cur_sprite->width, sizeof(Uint16), 1, f); + efread(&cur_sprite->height, sizeof(Uint16), 1, f); + efread(&cur_sprite->size, sizeof(Uint16), 1, f); + + cur_sprite->data = (Uint8 *)malloc(cur_sprite->size); + + efread(cur_sprite->data, sizeof(Uint8), cur_sprite->size, f); + } +} + +void free_sprites( unsigned int table ) +{ + for (unsigned int i = 0; i < sprite_table[table].count; ++i) + { + Sprite * const cur_sprite = sprite(table, i); + + cur_sprite->width = 0; + cur_sprite->height = 0; + cur_sprite->size = 0; + + free(cur_sprite->data); + cur_sprite->data = NULL; + } + + sprite_table[table].count = 0; +} + +// does not clip on left or right edges of surface +void blit_sprite( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index ) +{ + if (index >= sprite_table[table].count || !sprite_exists(table, index)) + { + assert(false); + return; + } + + const Sprite * const cur_sprite = sprite(table, index); + + const Uint8 *data = cur_sprite->data; + const Uint8 * const data_ul = data + cur_sprite->size; + + const unsigned int width = cur_sprite->width; + unsigned int x_offset = 0; + + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (; data < data_ul; ++data) + { + switch (*data) + { + case 255: // transparent pixels + data++; // next byte tells how many + pixels += *data; + x_offset += *data; + break; + + case 254: // next pixel row + pixels += width - x_offset; + x_offset = width; + break; + + case 253: // 1 transparent pixel + pixels++; + x_offset++; + break; + + default: // set a pixel + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = *data; + + pixels++; + x_offset++; + break; + } + if (x_offset >= width) + { + pixels += surface->pitch - x_offset; + x_offset = 0; + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite_blend( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index ) +{ + if (index >= sprite_table[table].count || !sprite_exists(table, index)) + { + assert(false); + return; + } + + const Sprite * const cur_sprite = sprite(table, index); + + const Uint8 *data = cur_sprite->data; + const Uint8 * const data_ul = data + cur_sprite->size; + + const unsigned int width = cur_sprite->width; + unsigned int x_offset = 0; + + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (; data < data_ul; ++data) + { + switch (*data) + { + case 255: // transparent pixels + data++; // next byte tells how many + pixels += *data; + x_offset += *data; + break; + + case 254: // next pixel row + pixels += width - x_offset; + x_offset = width; + break; + + case 253: // 1 transparent pixel + pixels++; + x_offset++; + break; + + default: // set a pixel + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2); + + pixels++; + x_offset++; + break; + } + if (x_offset >= width) + { + pixels += surface->pitch - x_offset; + x_offset = 0; + } + } +} + +// does not clip on left or right edges of surface +// unsafe because it doesn't check that value won't overflow into hue +// we can replace it when we know that we don't rely on that 'feature' +void blit_sprite_hv_unsafe( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ) +{ + if (index >= sprite_table[table].count || !sprite_exists(table, index)) + { + assert(false); + return; + } + + hue <<= 4; + + const Sprite * const cur_sprite = sprite(table, index); + + const Uint8 *data = cur_sprite->data; + const Uint8 * const data_ul = data + cur_sprite->size; + + const unsigned int width = cur_sprite->width; + unsigned int x_offset = 0; + + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (; data < data_ul; ++data) + { + switch (*data) + { + case 255: // transparent pixels + data++; // next byte tells how many + pixels += *data; + x_offset += *data; + break; + + case 254: // next pixel row + pixels += width - x_offset; + x_offset = width; + break; + + case 253: // 1 transparent pixel + pixels++; + x_offset++; + break; + + default: // set a pixel + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = hue | ((*data & 0x0f) + value); + + pixels++; + x_offset++; + break; + } + if (x_offset >= width) + { + pixels += surface->pitch - x_offset; + x_offset = 0; + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite_hv( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ) +{ + if (index >= sprite_table[table].count || !sprite_exists(table, index)) + { + assert(false); + return; + } + + hue <<= 4; + + const Sprite * const cur_sprite = sprite(table, index); + + const Uint8 *data = cur_sprite->data; + const Uint8 * const data_ul = data + cur_sprite->size; + + const unsigned int width = cur_sprite->width; + unsigned int x_offset = 0; + + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (; data < data_ul; ++data) + { + switch (*data) + { + case 255: // transparent pixels + data++; // next byte tells how many + pixels += *data; + x_offset += *data; + break; + + case 254: // next pixel row + pixels += width - x_offset; + x_offset = width; + break; + + case 253: // 1 transparent pixel + pixels++; + x_offset++; + break; + + default: // set a pixel + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + { + Uint8 temp_value = (*data & 0x0f) + value; + if (temp_value > 0xf) + temp_value = (temp_value >= 0x1f) ? 0x0 : 0xf; + + *pixels = hue | temp_value; + } + + pixels++; + x_offset++; + break; + } + if (x_offset >= width) + { + pixels += surface->pitch - x_offset; + x_offset = 0; + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite_hv_blend( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ) +{ + if (index >= sprite_table[table].count || !sprite_exists(table, index)) + { + assert(false); + return; + } + + hue <<= 4; + + const Sprite * const cur_sprite = sprite(table, index); + + const Uint8 *data = cur_sprite->data; + const Uint8 * const data_ul = data + cur_sprite->size; + + const unsigned int width = cur_sprite->width; + unsigned int x_offset = 0; + + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (; data < data_ul; ++data) + { + switch (*data) + { + case 255: // transparent pixels + data++; // next byte tells how many + pixels += *data; + x_offset += *data; + break; + + case 254: // next pixel row + pixels += width - x_offset; + x_offset = width; + break; + + case 253: // 1 transparent pixel + pixels++; + x_offset++; + break; + + default: // set a pixel + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + { + Uint8 temp_value = (*data & 0x0f) + value; + if (temp_value > 0xf) + temp_value = (temp_value >= 0x1f) ? 0x0 : 0xf; + + *pixels = hue | (((*pixels & 0x0f) + temp_value) / 2); + } + + pixels++; + x_offset++; + break; + } + if (x_offset >= width) + { + pixels += surface->pitch - x_offset; + x_offset = 0; + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite_dark( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, bool black ) +{ + if (index >= sprite_table[table].count || !sprite_exists(table, index)) + { + assert(false); + return; + } + + const Sprite * const cur_sprite = sprite(table, index); + + const Uint8 *data = cur_sprite->data; + const Uint8 * const data_ul = data + cur_sprite->size; + + const unsigned int width = cur_sprite->width; + unsigned int x_offset = 0; + + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + for (; data < data_ul; ++data) + { + switch (*data) + { + case 255: // transparent pixels + data++; // next byte tells how many + pixels += *data; + x_offset += *data; + break; + + case 254: // next pixel row + pixels += width - x_offset; + x_offset = width; + break; + + case 253: // 1 transparent pixel + pixels++; + x_offset++; + break; + + default: // set a pixel + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = black ? 0x00 : ((*pixels & 0xf0) | ((*pixels & 0x0f) / 2)); + + pixels++; + x_offset++; + break; + } + if (x_offset >= width) + { + pixels += surface->pitch - x_offset; + x_offset = 0; + } + } +} + + +void JE_loadCompShapes( Sprite2_array *sprite2s, char s ) +{ + char buffer[20]; + snprintf(buffer, sizeof(buffer), "newsh%c.shp", tolower((unsigned char)s)); + + FILE *f = dir_fopen_die(data_dir(), buffer, "rb"); + + sprite2s->size = ftell_eof(f); + + JE_loadCompShapesB(sprite2s, f); + + fclose(f); +} + +void JE_loadCompShapesB( Sprite2_array *sprite2s, FILE *f ) +{ + free_sprite2s(sprite2s); + + sprite2s->data = (Uint8 *)malloc(sizeof(Uint8) * sprite2s->size); + efread(sprite2s->data, sizeof(Uint8), sprite2s->size, f); +} + +void free_sprite2s( Sprite2_array *sprite2s ) +{ + free(sprite2s->data); + sprite2s->data = NULL; +} + +// does not clip on left or right edges of surface +void blit_sprite2( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index ) +{ + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]); + + for (; *data != 0x0f; ++data) + { + pixels += *data & 0x0f; // second nibble: transparent pixel count + unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count + + if (count == 0) // move to next pixel row + { + pixels += VGAScreen->pitch - 12; + } + else + { + while (count--) + { + ++data; + + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = *data; + + ++pixels; + } + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite2_blend( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index ) +{ + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]); + + for (; *data != 0x0f; ++data) + { + pixels += *data & 0x0f; // second nibble: transparent pixel count + unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count + + if (count == 0) // move to next pixel row + { + pixels += VGAScreen->pitch - 12; + } + else + { + while (count--) + { + ++data; + + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = (((*data & 0x0f) + (*pixels & 0x0f)) / 2) | (*data & 0xf0); + + ++pixels; + } + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite2_darken( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index ) +{ + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]); + + for (; *data != 0x0f; ++data) + { + pixels += *data & 0x0f; // second nibble: transparent pixel count + unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count + + if (count == 0) // move to next pixel row + { + pixels += VGAScreen->pitch - 12; + } + else + { + while (count--) + { + ++data; + + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = ((*pixels & 0x0f) / 2) + (*pixels & 0xf0); + + ++pixels; + } + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite2_filter( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index, Uint8 filter ) +{ + assert(surface->format->BitsPerPixel == 8); + Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x; + const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit + * const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit + + const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]); + + for (; *data != 0x0f; ++data) + { + pixels += *data & 0x0f; // second nibble: transparent pixel count + unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count + + if (count == 0) // move to next pixel row + { + pixels += VGAScreen->pitch - 12; + } + else + { + while (count--) + { + ++data; + + if (pixels >= pixels_ul) + return; + if (pixels >= pixels_ll) + *pixels = filter | (*data & 0x0f); + + ++pixels; + } + } + } +} + +// does not clip on left or right edges of surface +void blit_sprite2x2( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index ) +{ + blit_sprite2(surface, x, y, sprite2s, index); + blit_sprite2(surface, x + 12, y, sprite2s, index + 1); + blit_sprite2(surface, x, y + 14, sprite2s, index + 19); + blit_sprite2(surface, x + 12, y + 14, sprite2s, index + 20); +} + +// does not clip on left or right edges of surface +void blit_sprite2x2_blend( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index ) +{ + blit_sprite2_blend(surface, x, y, sprite2s, index); + blit_sprite2_blend(surface, x + 12, y, sprite2s, index + 1); + blit_sprite2_blend(surface, x, y + 14, sprite2s, index + 19); + blit_sprite2_blend(surface, x + 12, y + 14, sprite2s, index + 20); +} + +// does not clip on left or right edges of surface +void blit_sprite2x2_darken( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index ) +{ + blit_sprite2_darken(surface, x, y, sprite2s, index); + blit_sprite2_darken(surface, x + 12, y, sprite2s, index + 1); + blit_sprite2_darken(surface, x, y + 14, sprite2s, index + 19); + blit_sprite2_darken(surface, x + 12, y + 14, sprite2s, index + 20); +} + + +void JE_loadMainShapeTables( const char *shpfile ) +{ + const int SHP_NUM = 12; + + FILE *f = dir_fopen_die(data_dir(), shpfile, "rb"); + + JE_word shpNumb; + JE_longint shpPos[SHP_NUM + 1]; // +1 for storing file length + + efread(&shpNumb, sizeof(JE_word), 1, f); + assert(shpNumb + 1u <= COUNTOF(shpPos)); + + for (int i = 0; i < shpNumb; i++) + { + efread(&shpPos[i], sizeof(JE_longint), 1, f); + } + fseek(f, 0, SEEK_END); + shpPos[shpNumb] = ftell(f); + + int i; + // fonts, interface, option sprites + for (i = 0; i < 7; i++) + { + fseek(f, shpPos[i], SEEK_SET); + load_sprites(i, f); + } + + // player shot sprites + shapesC1.size = shpPos[i + 1] - shpPos[i]; + JE_loadCompShapesB(&shapesC1, f); + i++; + + // player ship sprites + shapes9.size = shpPos[i + 1] - shpPos[i]; + JE_loadCompShapesB(&shapes9 , f); + i++; + + // power-up sprites + eShapes6.size = shpPos[i + 1] - shpPos[i]; + JE_loadCompShapesB(&eShapes6, f); + i++; + + // coins, datacubes, etc sprites + eShapes5.size = shpPos[i + 1] - shpPos[i]; + JE_loadCompShapesB(&eShapes5, f); + i++; + + // more player shot sprites + shapesW2.size = shpPos[i + 1] - shpPos[i]; + JE_loadCompShapesB(&shapesW2, f); + + fclose(f); +} + +void free_main_shape_tables( void ) +{ + for (uint i = 0; i < COUNTOF(sprite_table); ++i) + free_sprites(i); + + free_sprite2s(&shapesC1); + free_sprite2s(&shapes9); + free_sprite2s(&eShapes6); + free_sprite2s(&eShapes5); + free_sprite2s(&shapesW2); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/sprite.h b/alienblaster/project/jni/application/opentyrian/src/sprite.h new file mode 100644 index 000000000..da9c18aaf --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/sprite.h @@ -0,0 +1,115 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef SPRITE_H +#define SPRITE_H + +#include "opentyr.h" + +#include "SDL.h" +#include + +#define FONT_SHAPES 0 +#define SMALL_FONT_SHAPES 1 +#define TINY_FONT 2 +#define PLANET_SHAPES 3 +#define FACE_SHAPES 4 +#define OPTION_SHAPES 5 /*Also contains help shapes*/ +#define WEAPON_SHAPES 6 +#define EXTRA_SHAPES 7 /*Used for Ending pics*/ + +#define SPRITE_TABLES_MAX 8 +#define SPRITES_PER_TABLE_MAX 151 + +typedef struct +{ + Uint16 width, height; + Uint16 size; + Uint8 *data; +} +Sprite; + +typedef struct +{ + unsigned int count; + Sprite sprite[SPRITES_PER_TABLE_MAX]; +} +Sprite_array; + +extern Sprite_array sprite_table[SPRITE_TABLES_MAX]; + +static inline Sprite *sprite( unsigned int table, unsigned int index ) +{ + assert(table < COUNTOF(sprite_table)); + assert(index < COUNTOF(sprite_table->sprite)); + return &sprite_table[table].sprite[index]; +} + +static inline bool sprite_exists( unsigned int table, unsigned int index ) +{ + return (sprite(table, index)->data != NULL); +} +static inline Uint16 get_sprite_width( unsigned int table, unsigned int index ) +{ + return (sprite_exists(table, index) ? sprite(table, index)->width : 0); +} +static inline Uint16 get_sprite_height( unsigned int table, unsigned int index ) +{ + return (sprite_exists(table, index) ? sprite(table, index)->height : 0); +} + +void load_sprites_file( unsigned table, const char *filename ); +void load_sprites( unsigned int table, FILE *f ); +void free_sprites( unsigned int table ); + +void blit_sprite( SDL_Surface *, int x, int y, unsigned int table, unsigned int index ); // JE_newDrawCShapeNum +void blit_sprite_blend( SDL_Surface *, int x, int y, unsigned int table, unsigned int index ); // JE_newDrawCShapeTrick +void blit_sprite_hv_unsafe( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ); // JE_newDrawCShapeBright +void blit_sprite_hv( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ); // JE_newDrawCShapeAdjust +void blit_sprite_hv_blend( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ); // JE_newDrawCShapeModify +void blit_sprite_dark( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, bool black ); // JE_newDrawCShapeDarken, JE_newDrawCShapeShadow + +typedef struct +{ + unsigned int size; + Uint8 *data; +} +Sprite2_array; + +extern Sprite2_array eShapes1, eShapes2, eShapes3, eShapes4, eShapes5, eShapes6; +extern Sprite2_array shapesC1, shapes6, shapes9, shapesW2; + +void JE_loadCompShapes( Sprite2_array *, JE_char s ); +void JE_loadCompShapesB( Sprite2_array *, FILE *f ); +void free_sprite2s( Sprite2_array * ); + +void blit_sprite2( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index ); +void blit_sprite2_blend( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index ); +void blit_sprite2_darken( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index ); +void blit_sprite2_filter( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index, Uint8 filter ); + +void blit_sprite2x2( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index ); +void blit_sprite2x2_blend( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index ); +void blit_sprite2x2_darken( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index ); + +void JE_loadMainShapeTables( const char *shpfile ); +void free_main_shape_tables( void ); + +#endif // SPRITE_H + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/starlib.cpp b/alienblaster/project/jni/application/opentyrian/src/starlib.cpp new file mode 100644 index 000000000..a6e292198 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/starlib.cpp @@ -0,0 +1,432 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "opentyr.h" +#include "starlib.h" + +#include "keyboard.h" +#include "mtrand.h" +#include "video.h" + +#include + +#define starlib_MAX_STARS 1000 +#define MAX_TYPES 14 + +struct JE_StarType +{ + JE_integer spX, spY, spZ; + JE_integer lastX, lastY; +}; + +static int tempX, tempY; +static JE_boolean run; +static struct JE_StarType star[starlib_MAX_STARS]; + +static JE_byte setup; +static JE_word stepCounter; + +static JE_word nsp2; +static JE_shortint nspVar2Inc; + +/* JE: new sprite pointer */ +static JE_real nsp; +static JE_real nspVarInc; +static JE_real nspVarVarInc; + +static JE_word changeTime; +static JE_boolean doChange; + +static JE_boolean grayB; + +static JE_integer starlib_speed; +static JE_shortint speedChange; + +static JE_byte pColor; + + +void JE_starlib_main( void ) +{ + int off; + JE_word i; + JE_integer tempZ; + JE_byte tempCol; + struct JE_StarType *stars; + Uint8 *surf; + + JE_wackyCol(); + + grayB = false; + + starlib_speed += speedChange; + + + for(stars = star, i = starlib_MAX_STARS; i > 0; stars++, i--) + { + /* Make a pointer to the screen... */ + surf = (Uint8 *)VGAScreen->pixels; + + /* Calculate the offset to where we wish to draw */ + off = (stars->lastX)+(stars->lastY)*320; + + + /* We don't want trails in our star field. Erase the old graphic */ + if (off >= 640 && off < (320*200)-640) + { + surf[off] = 0; /* Shade Level 0 */ + + surf[off-1] = 0; /* Shade Level 1, 2 */ + surf[off+1] = 0; + surf[off-2] = 0; + surf[off+2] = 0; + + surf[off-320] = 0; + surf[off+320] = 0; + surf[off-640] = 0; + surf[off+640] = 0; + } + + /* Move star */ + tempZ = stars->spZ; + tempX = (stars->spX / tempZ) + 160; + tempY = (stars->spY / tempZ) + 100; + tempZ -= starlib_speed; + + + /* If star is out of range, make a new one */ + if (tempZ <= 0 || + tempY == 0 || tempY > 198 || + tempX > 318 || tempX < 1) + { + stars->spZ = 500; + + JE_newStar(); + + stars->spX = tempX; + stars->spY = tempY; + } + else /* Otherwise, update & draw it */ + { + stars->lastX = tempX; + stars->lastY = tempY; + stars->spZ = tempZ; + + off = tempX+tempY*320; + + if (grayB) + { + tempCol = tempZ >> 1; + } else { + tempCol = pColor+((tempZ >> 4) & 31); + } + + /* Draw the pixel! */ + if (off >= 640 && off < (320*200)-640) + { + surf[off] = tempCol; + + tempCol += 72; + surf[off-1] = tempCol; + surf[off+1] = tempCol; + surf[off-320] = tempCol; + surf[off+320] = tempCol; + + tempCol += 72; + surf[off-2] = tempCol; + surf[off+2] = tempCol; + surf[off-640] = tempCol; + surf[off+640] = tempCol; + } + } + } + + if (newkey) + { + switch (toupper(lastkey_char)) + { + case '+': + starlib_speed++; + speedChange = 0; + break; + case '-': + starlib_speed--; + speedChange = 0; + break; + case '1': + JE_changeSetup(1); + break; + case '2': + JE_changeSetup(2); + break; + case '3': + JE_changeSetup(3); + break; + case '4': + JE_changeSetup(4); + break; + case '5': + JE_changeSetup(5); + break; + case '6': + JE_changeSetup(6); + break; + case '7': + JE_changeSetup(7); + break; + case '8': + JE_changeSetup(8); + break; + case '9': + JE_changeSetup(9); + break; + case '0': + JE_changeSetup(10); + break; + case '!': + JE_changeSetup(11); + break; + case '@': + JE_changeSetup(12); + break; + case '#': + JE_changeSetup(13); + break; + case '$': + JE_changeSetup(14); + break; + + case 'C': + JE_resetValues(); + break; + case 'S': + nspVarVarInc = mt_rand_1() * 0.01f - 0.005f; + break; + case 'X': + case 27: + run = false; + break; + case '[': + pColor--; + break; + case ']': + pColor++; + break; + case '{': + pColor -= 72; + break; + case '}': + pColor += 72; + break; + case '`': /* ` */ + doChange = !doChange; + break; + case 'P': + wait_noinput(true, false, false); + wait_input(true, false, false); + break; + default: + break; + } + } + + if (doChange) + { + stepCounter++; + if (stepCounter > changeTime) + { + JE_changeSetup(0); + } + } + + if ((mt_rand() % 1000) == 1) + { + nspVarVarInc = mt_rand_1() * 0.01f - 0.005f; + } + + nspVarInc += nspVarVarInc; +} + +void JE_wackyCol( void ) +{ + /* YKS: Does nothing */ +} + +void JE_starlib_init( void ) +{ + static JE_boolean initialized = false; + + if (!initialized) + { + initialized = true; + + JE_resetValues(); + JE_changeSetup(2); + doChange = true; + + /* RANDOMIZE; */ + for (int x = 0; x < starlib_MAX_STARS; x++) + { + star[x].spX = (mt_rand() % 64000) - 32000; + star[x].spY = (mt_rand() % 40000) - 20000; + star[x].spZ = x+1; + } + } +} + +void JE_resetValues( void ) +{ + nsp2 = 1; + nspVar2Inc = 1; + nspVarInc = 0.1f; + nspVarVarInc = 0.0001f; + nsp = 0; + pColor = 32; + starlib_speed = 2; + speedChange = 0; +} + +void JE_changeSetup( JE_byte setupType ) +{ + stepCounter = 0; + changeTime = (mt_rand() % 1000); + + if (setupType > 0) + { + setup = setupType; + } else { + setup = mt_rand() % (MAX_TYPES + 1); + } + + if (setup == 1) + { + nspVarInc = 0.1f; + } + if (nspVarInc > 2.2f) + { + nspVarInc = 0.1f; + } +} + +void JE_newStar( void ) +{ + if (setup == 0) + { + tempX = (mt_rand() % 64000) - 32000; + tempY = (mt_rand() % 40000) - 20000; + } else { + nsp = nsp + nspVarInc; /* YKS: < lol */ + switch (setup) + { + case 1: + tempX = (int)(sinf(nsp / 30) * 20000); + tempY = (mt_rand() % 40000) - 20000; + break; + case 2: + tempX = (int)(cosf(nsp) * 20000); + tempY = (int)(sinf(nsp) * 20000); + break; + case 3: + tempX = (int)(cosf(nsp * 15) * 100) * ((int)(nsp / 6) % 200); + tempY = (int)(sinf(nsp * 15) * 100) * ((int)(nsp / 6) % 200); + break; + case 4: + tempX = (int)(sinf(nsp / 60) * 20000); + tempY = (int)(cosf(nsp) * (int)(sinf(nsp / 200) * 300) * 100); + break; + case 5: + tempX = (int)(sinf(nsp / 2) * 20000); + tempY = (int)(cosf(nsp) * (int)(sinf(nsp / 200) * 300) * 100); + break; + case 6: + tempX = (int)(sinf(nsp) * 40000); + tempY = (int)(cosf(nsp) * 20000); + break; + case 8: + tempX = (int)(sinf(nsp / 2) * 40000); + tempY = (int)(cosf(nsp) * 20000); + break; + case 7: + tempX = mt_rand() % 65535; + if ((mt_rand() % 2) == 0) + { + tempY = (int)(cosf(nsp / 80) * 10000) + 15000; + } else { + tempY = 50000 - (int)(cosf(nsp / 80) * 13000); + } + break; + case 9: + nsp2 += nspVar2Inc; + if ((nsp2 == 65535) || (nsp2 == 0)) + { + nspVar2Inc = -nspVar2Inc; + } + tempX = (int)(cosf(sinf(nsp2 / 10.0f) + (nsp / 500)) * 32000); + tempY = (int)(sinf(cosf(nsp2 / 10.0f) + (nsp / 500)) * 30000); + break; + case 10: + nsp2 += nspVar2Inc; + if ((nsp2 == 65535) || (nsp2 == 0)) + { + nspVar2Inc = -nspVar2Inc; + } + tempX = (int)(cosf(sinf(nsp2 / 5.0f) + (nsp / 100)) * 32000); + tempY = (int)(sinf(cosf(nsp2 / 5.0f) + (nsp / 100)) * 30000); + break;; + case 11: + nsp2 += nspVar2Inc; + if ((nsp2 == 65535) || (nsp2 == 0)) + { + nspVar2Inc = -nspVar2Inc; + } + tempX = (int)(cosf(sinf(nsp2 / 1000.0f) + (nsp / 2)) * 32000); + tempY = (int)(sinf(cosf(nsp2 / 1000.0f) + (nsp / 2)) * 30000); + break; + case 12: + if (nsp != 0) + { + nsp2 += nspVar2Inc; + if ((nsp2 == 65535) || (nsp2 == 0)) + { + nspVar2Inc = -nspVar2Inc; + } + tempX = (int)(cosf(sinf(nsp2 / 2.0f) / (sqrtf(fabsf(nsp)) / 10.0f + 1) + (nsp2 / 100.0f)) * 32000); + tempY = (int)(sinf(cosf(nsp2 / 2.0f) / (sqrtf(fabsf(nsp)) / 10.0f + 1) + (nsp2 / 100.0f)) * 30000); + } + break; + case 13: + if (nsp != 0) + { + nsp2 += nspVar2Inc; + if ((nsp2 == 65535) || (nsp2 == 0)) + { + nspVar2Inc = -nspVar2Inc; + } + tempX = (int)(cosf(sinf(nsp2 / 10.0f) / 2 + (nsp / 20)) * 32000); + tempY = (int)(sinf(sinf(nsp2 / 11.0f) / 2 + (nsp / 20)) * 30000); + } + break; + case 14: + nsp2 += nspVar2Inc; + tempX = (int)((sinf(nsp) + cosf(nsp2 / 1000.0f) * 3) * 12000); + tempY = (int)(cosf(nsp) * 10000) + nsp2; + break; + } + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/starlib.h b/alienblaster/project/jni/application/opentyrian/src/starlib.h new file mode 100644 index 000000000..20859bd69 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/starlib.h @@ -0,0 +1,33 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef STARLIB_H +#define STARLIB_H + +#include "opentyr.h" + +void JE_starlib_main( void ); +void JE_wackyCol( void ); +void JE_starlib_init( void ); +void JE_resetValues( void ); +void JE_changeSetup( JE_byte setupType ); +void JE_newStar( void ); + +#endif /* STARLIB_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/tyrian2.cpp b/alienblaster/project/jni/application/opentyrian/src/tyrian2.cpp new file mode 100644 index 000000000..90cb6c29b --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/tyrian2.cpp @@ -0,0 +1,5307 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "animlib.h" +#include "backgrnd.h" +#include "episodes.h" +#include "file.h" +#include "font.h" +#include "fonthand.h" +#include "game_menu.h" +#include "joystick.h" +#include "keyboard.h" +#include "lds_play.h" +#include "loudness.h" +#include "lvllib.h" +#include "menus.h" +#include "mainint.h" +#include "mouse.h" +#include "mtrand.h" +#include "network.h" +#include "nortsong.h" +#include "nortvars.h" +#include "opentyr.h" +#include "params.h" +#include "pcxload.h" +#include "pcxmast.h" +#include "picload.h" +#include "setup.h" +#include "sprite.h" +#include "tyrian2.h" +#include "vga256d.h" +#include "video.h" + +#include +#include +#include +#include +#include +#include + +inline static void blit_enemy( SDL_Surface *surface, unsigned int i, signed int x_offset, signed int y_offset, signed int sprite_offset ); + +boss_bar_t boss_bar[2]; + +/* Level Event Data */ +JE_boolean quit, loadLevelOk; + +struct JE_EventRecType eventRec[EVENT_MAXIMUM]; /* [1..eventMaximum] */ +JE_word levelEnemyMax; +JE_word levelEnemyFrequency; +JE_word levelEnemy[40]; /* [1..40] */ + +char tempStr[31]; + +/* Data used for ItemScreen procedure to indicate items available */ +JE_byte itemAvail[9][10]; /* [1..9, 1..10] */ +JE_byte itemAvailMax[9]; /* [1..9] */ + +void JE_starShowVGA( void ) +{ + JE_byte *src; + Uint8 *s = NULL; /* screen pointer, 8-bit specific */ + + int x, y, lightx, lighty, lightdist; + + if (!playerEndLevel && !skipStarShowVGA) + { + + s = (Uint8 *)VGAScreenSeg->pixels; + + src = (JE_byte *)game_screen->pixels; + src += 24; + + if (smoothScroll != 0 /*&& thisPlayerNum != 2*/) + { + wait_delay(); + setjasondelay(frameCountMax); + } + + if (starShowVGASpecialCode == 1) + { + src += game_screen->pitch * 183; + for (y = 0; y < 184; y++) + { + memmove(s, src, 264); + s += VGAScreenSeg->pitch; + src -= game_screen->pitch; + } + } + else if (starShowVGASpecialCode == 2 && processorType >= 2) + { + lighty = 172 - player[0].y; + lightx = 281 - player[0].x; + + for (y = 184; y; y--) + { + if (lighty > y) + { + for (x = 320 - 56; x; x--) + { + *s = (*src & 0xf0) | ((*src >> 2) & 0x03); + s++; + src++; + } + } + else + { + for (x = 320 - 56; x; x--) + { + lightdist = abs(lightx - x) + lighty; + if (lightdist < y) + *s = *src; + else if (lightdist - y <= 5) + *s = (*src & 0xf0) | (((*src & 0x0f) + (3 * (5 - (lightdist - y)))) / 4); + else + *s = (*src & 0xf0) | ((*src & 0x0f) >> 2); + s++; + src++; + } + } + s += 56 + VGAScreenSeg->pitch - 320; + src += 56 + VGAScreenSeg->pitch - 320; + } + } + else + { + for (y = 0; y < 184; y++) + { + memmove(s, src, 264); + s += VGAScreenSeg->pitch; + src += game_screen->pitch; + } + } + JE_showVGA(); + } + + quitRequested = false; + skipStarShowVGA = false; +} + +inline static void blit_enemy( SDL_Surface *surface, unsigned int i, signed int x_offset, signed int y_offset, signed int sprite_offset ) +{ + const int x = enemy[i].ex + x_offset + tempMapXOfs, + y = enemy[i].ey + y_offset; + const unsigned int index = enemy[i].egr[enemy[i].enemycycle - 1] + sprite_offset; + + if (enemy[i].filter != 0) + blit_sprite2_filter(surface, x, y, *enemy[i].sprite2s, index, enemy[i].filter); + else + blit_sprite2(surface, x, y, *enemy[i].sprite2s, index); +} + +void JE_drawEnemy( int enemyOffset ) // actually does a whole lot more than just drawing +{ + player[0].x -= 25; + + for (int i = enemyOffset - 25; i < enemyOffset; i++) + { + if (enemyAvail[i] != 1) + { + enemy[i].mapoffset = tempMapXOfs; + + if (enemy[i].xaccel && enemy[i].xaccel - 89u > mt_rand() % 11) + { + if (player[0].x > enemy[i].ex) + { + if (enemy[i].exc < enemy[i].xaccel - 89) + enemy[i].exc++; + } + else + { + if (enemy[i].exc >= 0 || -enemy[i].exc < enemy[i].xaccel - 89) + enemy[i].exc--; + } + } + + if (enemy[i].yaccel && enemy[i].yaccel - 89u > mt_rand() % 11) + { + if (player[0].y > enemy[i].ey) + { + if (enemy[i].eyc < enemy[i].yaccel - 89) + enemy[i].eyc++; + } + else + { + if (enemy[i].eyc >= 0 || -enemy[i].eyc < enemy[i].yaccel - 89) + enemy[i].eyc--; + } + } + + if (enemy[i].ex + tempMapXOfs > -29 && enemy[i].ex + tempMapXOfs < 300) + { + if (enemy[i].aniactive == 1) + { + enemy[i].enemycycle++; + + if (enemy[i].enemycycle == enemy[i].animax) + enemy[i].aniactive = enemy[i].aniwhenfire; + else if (enemy[i].enemycycle > enemy[i].ani) + enemy[i].enemycycle = enemy[i].animin; + } + + if (enemy[i].egr[enemy[i].enemycycle - 1] == 999) + goto enemy_gone; + + if (enemy[i].size == 1) // 2x2 enemy + { + if (enemy[i].ey > -13) + { + blit_enemy(VGAScreen, i, -6, -7, 0); + blit_enemy(VGAScreen, i, 6, -7, 1); + } + if (enemy[i].ey > -26 && enemy[i].ey < 182) + { + blit_enemy(VGAScreen, i, -6, 7, 19); + blit_enemy(VGAScreen, i, 6, 7, 20); + } + } + else + { + if (enemy[i].ey > -13) + blit_enemy(VGAScreen, i, 0, 0, 0); + } + + enemy[i].filter = 0; + } + + if (enemy[i].excc) + { + if (--enemy[i].exccw <= 0) + { + if (enemy[i].exc == enemy[i].exrev) + { + enemy[i].excc = -enemy[i].excc; + enemy[i].exrev = -enemy[i].exrev; + enemy[i].exccadd = -enemy[i].exccadd; + } + else + { + enemy[i].exc += enemy[i].exccadd; + enemy[i].exccw = enemy[i].exccwmax; + if (enemy[i].exc == enemy[i].exrev) + { + enemy[i].excc = -enemy[i].excc; + enemy[i].exrev = -enemy[i].exrev; + enemy[i].exccadd = -enemy[i].exccadd; + } + } + } + } + + if (enemy[i].eycc) + { + if (--enemy[i].eyccw <= 0) + { + if (enemy[i].eyc == enemy[i].eyrev) + { + enemy[i].eycc = -enemy[i].eycc; + enemy[i].eyrev = -enemy[i].eyrev; + enemy[i].eyccadd = -enemy[i].eyccadd; + } + else + { + enemy[i].eyc += enemy[i].eyccadd; + enemy[i].eyccw = enemy[i].eyccwmax; + if (enemy[i].eyc == enemy[i].eyrev) + { + enemy[i].eycc = -enemy[i].eycc; + enemy[i].eyrev = -enemy[i].eyrev; + enemy[i].eyccadd = -enemy[i].eyccadd; + } + } + } + } + + enemy[i].ey += enemy[i].fixedmovey; + + enemy[i].ex += enemy[i].exc; + if (enemy[i].ex < -80 || enemy[i].ex > 340) + goto enemy_gone; + + enemy[i].ey += enemy[i].eyc; + if (enemy[i].ey < -112 || enemy[i].ey > 190) + goto enemy_gone; + + goto enemy_still_exists; + +enemy_gone: + /* enemy[i].egr[10] &= 0x00ff; madness? */ + enemyAvail[i] = 1; + goto draw_enemy_end; + +enemy_still_exists: + + /*X bounce*/ + if (enemy[i].ex <= enemy[i].xminbounce || enemy[i].ex >= enemy[i].xmaxbounce) + enemy[i].exc = -enemy[i].exc; + + /*Y bounce*/ + if (enemy[i].ey <= enemy[i].yminbounce || enemy[i].ey >= enemy[i].ymaxbounce) + enemy[i].eyc = -enemy[i].eyc; + + /* Evalue != 0 - score item at boundary */ + if (enemy[i].scoreitem) + { + if (enemy[i].ex < -5) + enemy[i].ex++; + if (enemy[i].ex > 245) + enemy[i].ex--; + } + + enemy[i].ey += tempBackMove; + + if (enemy[i].ex <= -24 || enemy[i].ex >= 296) + goto draw_enemy_end; + + tempX = enemy[i].ex; + tempY = enemy[i].ey; + + temp = enemy[i].enemytype; + + /* Enemy Shots */ + if (enemy[i].edamaged == 1) + goto draw_enemy_end; + + enemyOnScreen++; + + if (enemy[i].iced) + { + enemy[i].iced--; + if (enemy[i].enemyground != 0) + { + enemy[i].filter = 0x09; + } + goto draw_enemy_end; + } + + for (int j = 3; j > 0; j--) + { + if (enemy[i].freq[j-1]) + { + temp3 = enemy[i].tur[j-1]; + + if (--enemy[i].eshotwait[j-1] == 0 && temp3) + { + enemy[i].eshotwait[j-1] = enemy[i].freq[j-1]; + if (difficultyLevel > 2) + { + enemy[i].eshotwait[j-1] = (enemy[i].eshotwait[j-1] / 2) + 1; + if (difficultyLevel > 7) + enemy[i].eshotwait[j-1] = (enemy[i].eshotwait[j-1] / 2) + 1; + } + + if (galagaMode && (enemy[i].eyc == 0 || (mt_rand() % 400) >= galagaShotFreq)) + goto draw_enemy_end; + + switch (temp3) + { + case 252: /* Savara Boss DualMissile */ + if (enemy[i].ey > 20) + { + JE_setupExplosion(tempX - 8 + tempMapXOfs, tempY - 20 - backMove * 8, -2, 6, false, false); + JE_setupExplosion(tempX + 4 + tempMapXOfs, tempY - 20 - backMove * 8, -2, 6, false, false); + } + break; + case 251:; /* Suck-O-Magnet */ + { + const int attractivity = 4 - (abs(player[0].x - tempX) + abs(player[0].y - tempY)) / 100; + player[0].x_velocity += (player[0].x > tempX) ? -attractivity : attractivity; + } + break; + case 253: /* Left ShortRange Magnet */ + if (abs(player[0].x + 25 - 14 - tempX) < 24 && abs(player[0].y - tempY) < 28) + { + player[0].x_velocity += 2; + } + if (twoPlayerMode && + (abs(player[1].x - 14 - tempX) < 24 && abs(player[1].y - tempY) < 28)) + { + player[1].x_velocity += 2; + } + break; + case 254: /* Left ShortRange Magnet */ + if (abs(player[0].x + 25 - 14 - tempX) < 24 && abs(player[0].y - tempY) < 28) + { + player[0].x_velocity -= 2; + } + if (twoPlayerMode && + (abs(player[1].x - 14 - tempX) < 24 && abs(player[1].y - tempY) < 28)) + { + player[1].x_velocity -= 2; + } + break; + case 255: /* Magneto RePulse!! */ + if (difficultyLevel != 1) /*DIF*/ + { + if (j == 3) + { + enemy[i].filter = 0x70; + } + else + { + const int repulsivity = 4 - (abs(player[0].x - tempX) + abs(player[0].y - tempY)) / 20; + if (repulsivity > 0) + player[0].x_velocity += (player[0].x > tempX) ? repulsivity : -repulsivity; + } + } + break; + default: + /*Rot*/ + for (int tempCount = weapons[temp3].multi; tempCount > 0; tempCount--) + { + for (b = 0; b < ENEMY_SHOT_MAX; b++) + { + if (enemyShotAvail[b] == 1) + break; + } + if (b == ENEMY_SHOT_MAX) + goto draw_enemy_end; + + enemyShotAvail[b] = !enemyShotAvail[b]; + + if (weapons[temp3].sound > 0) + { + do + temp = mt_rand() % 8; + while (temp == 3); + soundQueue[temp] = weapons[temp3].sound; + } + + tempPos = weapons[temp3].max; + + if (enemy[i].aniactive == 2) + enemy[i].aniactive = 1; + + if (++enemy[i].eshotmultipos[j-1] > tempPos) + enemy[i].eshotmultipos[j-1] = 1; + + tempPos = enemy[i].eshotmultipos[j-1]; + + if (j == 1) + temp2 = 4; + + enemyShot[b].sx = tempX + weapons[temp3].bx[tempPos-1] + tempMapXOfs; + enemyShot[b].sy = tempY + weapons[temp3].by[tempPos-1]; + enemyShot[b].sdmg = weapons[temp3].attack[tempPos-1]; + enemyShot[b].tx = weapons[temp3].tx; + enemyShot[b].ty = weapons[temp3].ty; + enemyShot[b].duration = weapons[temp3].del[tempPos-1]; + enemyShot[b].animate = 0; + enemyShot[b].animax = weapons[temp3].weapani; + + enemyShot[b].sgr = weapons[temp3].sg[tempPos-1]; + switch (j) + { + case 1: + enemyShot[b].syc = weapons[temp3].acceleration; + enemyShot[b].sxc = weapons[temp3].accelerationx; + + enemyShot[b].sxm = weapons[temp3].sx[tempPos-1]; + enemyShot[b].sym = weapons[temp3].sy[tempPos-1]; + break; + case 3: + enemyShot[b].sxc = -weapons[temp3].acceleration; + enemyShot[b].syc = weapons[temp3].accelerationx; + + enemyShot[b].sxm = -weapons[temp3].sy[tempPos-1]; + enemyShot[b].sym = -weapons[temp3].sx[tempPos-1]; + break; + case 2: + enemyShot[b].sxc = weapons[temp3].acceleration; + enemyShot[b].syc = -weapons[temp3].acceleration; + + enemyShot[b].sxm = weapons[temp3].sy[tempPos-1]; + enemyShot[b].sym = -weapons[temp3].sx[tempPos-1]; + break; + } + + if (weapons[temp3].aim > 0) + { + temp4 = weapons[temp3].aim; + + /*DIF*/ + if (difficultyLevel > 2) + { + temp4 += difficultyLevel - 2; + } + + tempX2 = player[0].x; + tempY2 = player[0].y; + + if (twoPlayerMode) + { + // fire at live player(s) + if (player[0].is_alive && !player[1].is_alive) + temp = 0; + else if (player[1].is_alive && !player[0].is_alive) + temp = 1; + else + temp = mt_rand() % 2; + + if (temp == 1) + { + tempX2 = player[1].x - 25; + tempY2 = player[1].y; + } + } + + tempI = (tempX2 + 25) - tempX - tempMapXOfs - 4; + if (tempI == 0) + tempI++; + tempI2 = tempY2 - tempY; + if (tempI2 == 0) + tempI2++; + if (abs(tempI) > abs(tempI2)) + tempI3 = abs(tempI); + else + tempI3 = abs(tempI2); + enemyShot[b].sxm = roundf(((float)tempI / tempI3) * temp4); + enemyShot[b].sym = roundf(((float)tempI2 / tempI3) * temp4); + } + } + break; + } + } + } + } + + /* Enemy Launch Routine */ + if (enemy[i].launchfreq) + { + if (--enemy[i].launchwait == 0) + { + enemy[i].launchwait = enemy[i].launchfreq; + + if (enemy[i].launchspecial != 0) + { + /*Type 1 : Must be inline with player*/ + if (abs(enemy[i].ey - player[0].y) > 5) + goto draw_enemy_end; + } + + if (enemy[i].aniactive == 2) + { + enemy[i].aniactive = 1; + } + + if (enemy[i].launchtype == 0) + goto draw_enemy_end; + + tempW = enemy[i].launchtype; + JE_newEnemy(enemyOffset == 50 ? 75 : enemyOffset - 25); + + /*Launch Enemy Placement*/ + if (b > 0) + { + tempI = tempX; + tempI2 = tempY + enemyDat[enemy[b-1].enemytype].startyc; + if (enemy[b-1].size == 0) + { + tempI -= 0; + tempI2 -= 7; + } + if (enemy[b-1].launchtype > 0 && enemy[b-1].launchfreq == 0) + { + if (enemy[b-1].launchtype > 90) + { + tempI += mt_rand() % ((enemy[b-1].launchtype - 90) * 4) - (enemy[b-1].launchtype - 90) * 2; + } + else + { + tempI4 = (player[0].x + 25) - tempX - tempMapXOfs - 4; + if (tempI4 == 0) + tempI4++; + int tempI5 = player[0].y - tempY; + if (tempI5 == 0) + tempI5++; + if (abs(tempI4) > abs(tempI5)) + tempI3 = abs(tempI4); + else + tempI3 = abs(tempI5); + enemy[b-1].exc = roundf(((float)tempI4 / tempI3) * enemy[b-1].launchtype); + enemy[b-1].eyc = roundf(((float)tempI5 / tempI3) * enemy[b-1].launchtype); + } + } + + do + temp = mt_rand() % 8; + while (temp == 3); + soundQueue[temp] = randomEnemyLaunchSounds[(mt_rand() % 3)]; + + if (enemy[i].launchspecial == 1 + && enemy[i].linknum < 100) + { + enemy[b-1].linknum = enemy[i].linknum; + } + + enemy[b-1].ex = tempI; + enemy[b-1].ey = tempI2; + } + } + } + } +draw_enemy_end: + ; + } + + player[0].x += 25; +} + +void JE_main( void ) +{ + int i; + + Uint8 *s; /* screen pointer, 8-bit specific */ + + char buffer[256]; + + int lastEnemyOnScreen; + + /* NOTE: BEGIN MAIN PROGRAM HERE AFTER LOADING A GAME OR STARTING A NEW ONE */ + + /* ----------- GAME ROUTINES ------------------------------------- */ + /* We need to jump to the beginning to make space for the routines */ + /* --------------------------------------------------------------- */ + goto start_level_first; + + + /*------------------------------GAME LOOP-----------------------------------*/ + + + /* Startlevel is called after a previous level is over. If the first level + is started for a gaming session, startlevelfirst is called instead and + this code is skipped. The code here finishes the level and prepares for + the loadmap function. */ + +start_level: + + if (galagaMode) + twoPlayerMode = false; + + JE_clearKeyboard(); + + free_sprite2s(&eShapes1); + free_sprite2s(&eShapes2); + free_sprite2s(&eShapes3); + free_sprite2s(&eShapes4); + + /* Normal speed */ + if (fastPlay != 0) + { + smoothScroll = true; + speed = 0x4300; + JE_resetTimerInt(); + JE_setTimerInt(); + } + + if (play_demo || record_demo) + { + if (demo_file) + { + fclose(demo_file); + demo_file = NULL; + } + + if (play_demo) + { + stop_song(); + fade_black(10); + + wait_noinput(true, true, true); + } + } + + difficultyLevel = oldDifficultyLevel; /*Return difficulty to normal*/ + + if (!play_demo) + { + if ((!all_players_dead() || normalBonusLevelCurrent || bonusLevelCurrent) && !playerEndLevel) + { + mainLevel = nextLevel; + JE_endLevelAni(); + + fade_song(); + } + else + { + fade_song(); + fade_black(10); + + JE_loadGame(twoPlayerMode ? 22 : 11); + if (doNotSaveBackup) + { + superTyrian = false; + onePlayerAction = false; + player[0].items.super_arcade_mode = SA_NONE; + } + if (bonusLevelCurrent && !playerEndLevel) + { + mainLevel = nextLevel; + } + } + } + doNotSaveBackup = false; + + if (play_demo) + return; + +start_level_first: + + set_volume(tyrMusicVolume, fxVolume); + + endLevel = false; + reallyEndLevel = false; + playerEndLevel = false; + extraGame = false; + + doNotSaveBackup = false; + JE_loadMap(); + + if (mainLevel == 0) // if quit itemscreen + return; // back to titlescreen + + fade_song(); + + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].is_alive = true; + + oldDifficultyLevel = difficultyLevel; + if (episodeNum == 4) + difficultyLevel--; + if (difficultyLevel < 1) + difficultyLevel = 1; + + player[0].x = 100; + player[0].y = 180; + + player[1].x = 190; + player[1].y = 180; + + assert(COUNTOF(player->old_x) == COUNTOF(player->old_y)); + + for (uint i = 0; i < COUNTOF(player); ++i) + { + for (uint j = 0; j < COUNTOF(player->old_x); ++j) + { + player[i].old_x[j] = player[i].x - (19 - j); + player[i].old_y[j] = player[i].y - 18; + } + + player[i].last_x_shot_move = player[i].x; + player[i].last_y_shot_move = player[i].y; + } + + JE_loadPic(VGAScreen, twoPlayerMode ? 6 : 3, false); + + JE_drawOptions(); + + JE_outText(VGAScreen, 268, twoPlayerMode ? 76 : 118, levelName, 12, 4); + + JE_showVGA(); + JE_gammaCorrect(&colors, gammaCorrection); + fade_palette(colors, 50, 0, 255); + + free_sprite2s(&shapes6); + JE_loadCompShapes(&shapes6, '6'); // explosion sprites + + /* MAPX will already be set correctly */ + mapY = 300 - 8; + mapY2 = 600 - 8; + mapY3 = 600 - 8; + mapYPos = &megaData1.mainmap[mapY][0] - 1; + mapY2Pos = &megaData2.mainmap[mapY2][0] - 1; + mapY3Pos = &megaData3.mainmap[mapY3][0] - 1; + mapXPos = 0; + mapXOfs = 0; + mapX2Pos = 0; + mapX3Pos = 0; + mapX3Ofs = 0; + mapXbpPos = 0; + mapX2bpPos = 0; + mapX3bpPos = 0; + + map1YDelay = 1; + map1YDelayMax = 1; + map2YDelay = 1; + map2YDelayMax = 1; + + musicFade = false; + + backPos = 0; + backPos2 = 0; + backPos3 = 0; + power = 0; + starY = VGAScreen->pitch; + + /* Setup player ship graphics */ + JE_getShipInfo(); + tempI = (((player[0].x - mouseX) / 2) * 2) * 168; // is this used for anything? + + for (uint i = 0; i < COUNTOF(player); ++i) + { + player[i].x_velocity = 0; + player[i].y_velocity = 0; + + player[i].invulnerable_ticks = 100; + } + + newkey = newmouse = false; + + /* Initialize Level Data and Debug Mode */ + levelEnd = 255; + levelEndWarp = -4; + levelEndFxWait = 0; + warningCol = 120; + warningColChange = 1; + warningSoundDelay = 0; + armorShipDelay = 50; + + bonusLevel = false; + readyToEndLevel = false; + firstGameOver = true; + eventLoc = 1; + curLoc = 0; + backMove = 1; + backMove2 = 2; + backMove3 = 3; + explodeMove = 2; + enemiesActive = true; + for(temp = 0; temp < 3; temp++) + { + button[temp] = false; + } + stopBackgrounds = false; + stopBackgroundNum = 0; + background3x1 = false; + background3x1b = false; + background3over = 0; + background2over = 1; + topEnemyOver = false; + skyEnemyOverAll = false; + smallEnemyAdjust = false; + starActive = true; + enemyContinualDamage = false; + levelEnemyFrequency = 96; + quitRequested = false; + + for (unsigned int i = 0; i < COUNTOF(boss_bar); i++) + boss_bar[i].link_num = 0; + + forceEvents = false; /*Force events to continue if background movement = 0*/ + + uniqueEnemy = false; /*Look in MakeEnemy under shape bank*/ + + superEnemy254Jump = 0; /*When Enemy with PL 254 dies*/ + + /* Filter Status */ + filterActive = true; + filterFade = true; + filterFadeStart = false; + levelFilter = -99; + levelBrightness = -14; + levelBrightnessChg = 1; + + background2notTransparent = false; + + uint old_weapon_bar[2] = { 0, 0 }; // only redrawn when they change + + /* Initially erase power bars */ + lastPower = power / 10; + + /* Initial Text */ + JE_drawTextWindow(miscText[20]); + + /* Setup Armor/Shield Data */ + shieldWait = 1; + shieldT = shields[player[0].items.shield].tpwr * 20; + + for (uint i = 0; i < COUNTOF(player); ++i) + { + player[i].shield = shields[player[i].items.shield].mpwr; + player[i].shield_max = player[i].shield * 2; + } + + JE_drawShield(); + JE_drawArmor(); + + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].superbombs = 0; + + /* Set cubes to 0 */ + cubeMax = 0; + + /* Secret Level Display */ + flash = 0; + flashChange = 1; + displayTime = 0; + + play_song(levelSong - 1); + + JE_drawPortConfigButtons(); + + /* --- MAIN LOOP --- */ + + newkey = false; + + if (isNetworkGame) + { + JE_clearSpecialRequests(); + mt_srand(32402394); + } + + JE_setupStars(); + + JE_setNewGameSpeed(); + + /* JE_setVol(tyrMusicVolume, fxPlayVol >> 2); NOTE: MXD killed this because it was broken */ + + /*Save backup game*/ + if (!play_demo && !doNotSaveBackup) + { + temp = twoPlayerMode ? 22 : 11; + JE_saveGame(temp, "LAST LEVEL "); + } + + if (!play_demo && record_demo) + { + Uint8 new_demo_num = 0; + + do + { + sprintf(tempStr, "demorec.%d", new_demo_num++); + } + while (dir_file_exists(get_user_directory(), tempStr)); // until file doesn't exist + + demo_file = dir_fopen_warn(get_user_directory(), tempStr, "wb"); + if (!demo_file) + exit(1); + + efwrite(&episodeNum, 1, 1, demo_file); + efwrite(levelName, 1, 10, demo_file); + efwrite(&lvlFileNum, 1, 1, demo_file); + + fputc(player[0].items.weapon[FRONT_WEAPON].id, demo_file); + fputc(player[0].items.weapon[REAR_WEAPON].id, demo_file); + fputc(player[0].items.super_arcade_mode, demo_file); + fputc(player[0].items.sidekick[LEFT_SIDEKICK], demo_file); + fputc(player[0].items.sidekick[RIGHT_SIDEKICK], demo_file); + fputc(player[0].items.generator, demo_file); + + fputc(player[0].items.sidekick_level, demo_file); + fputc(player[0].items.sidekick_series, demo_file); + + fputc(initial_episode_num, demo_file); + + fputc(player[0].items.shield, demo_file); + fputc(player[0].items.special, demo_file); + fputc(player[0].items.ship, demo_file); + + for (uint i = 0; i < 2; ++i) + fputc(player[0].items.weapon[i].power, demo_file); + + for (uint i = 0; i < 3; ++i) + fputc(0, demo_file); + + efwrite(&levelSong, 1, 1, demo_file); + + demo_keys = 0; + demo_keys_wait = 0; + } + + twoPlayerLinked = false; + linkGunDirec = M_PI; + + for (uint i = 0; i < COUNTOF(player); ++i) + calc_purple_balls_needed(&player[i]); + + damageRate = 2; /*Normal Rate for Collision Damage*/ + + chargeWait = 5; + chargeLevel = 0; + chargeMax = 5; + chargeGr = 0; + chargeGrWait = 3; + + portConfigChange = false; + + /*Destruction Ratio*/ + totalEnemy = 0; + enemyKilled = 0; + + astralDuration = 0; + + superArcadePowerUp = 1; + + yourInGameMenuRequest = false; + + constantLastX = -1; + + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].exploding_ticks = 0; + + if (isNetworkGame) + { + JE_loadItemDat(); + } + + memset(enemyAvail, 1, sizeof(enemyAvail)); + for (uint i = 0; i < COUNTOF(enemyShotAvail); i++) + enemyShotAvail[i] = 1; + + /*Initialize Shots*/ + memset(playerShotData, 0, sizeof(playerShotData)); + memset(shotAvail, 0, sizeof(shotAvail)); + memset(shotMultiPos, 0, sizeof(shotMultiPos)); + memset(shotRepeat, 1, sizeof(shotRepeat)); + + memset(button, 0, sizeof(button)); + + memset(globalFlags, 0, sizeof(globalFlags)); + + memset(explosions, 0, sizeof(explosions)); + memset(rep_explosions, 0, sizeof(rep_explosions)); + + /* --- Clear Sound Queue --- */ + memset(soundQueue, 0, sizeof(soundQueue)); + soundQueue[3] = V_GOOD_LUCK; + + memset(enemyShapeTables, 0, sizeof(enemyShapeTables)); + memset(enemy, 0, sizeof(enemy)); + + memset(SFCurrentCode, 0, sizeof(SFCurrentCode)); + memset(SFExecuted, 0, sizeof(SFExecuted)); + + zinglonDuration = 0; + specialWait = 0; + nextSpecialWait = 0; + optionAttachmentMove = 0; /*Launch the Attachments!*/ + optionAttachmentLinked = true; + + editShip1 = false; + editShip2 = false; + + memset(smoothies, 0, sizeof(smoothies)); + + levelTimer = false; + randomExplosions = false; + + last_superpixel = 0; + memset(superpixels, 0, sizeof(superpixels)); + + returnActive = false; + + galagaShotFreq = 0; + + if (galagaMode) + { + difficultyLevel = 2; + } + galagaLife = 10000; + + JE_drawOptionLevel(); + + // keeps map from scrolling past the top + BKwrap1 = BKwrap1to = &megaData1.mainmap[1][0]; + BKwrap2 = BKwrap2to = &megaData2.mainmap[1][0]; + BKwrap3 = BKwrap3to = &megaData3.mainmap[1][0]; + +level_loop: + + //tempScreenSeg = game_screen; /* side-effect of game_screen */ + + if (isNetworkGame) + { + smoothies[9-1] = false; + smoothies[6-1] = false; + } else { + starShowVGASpecialCode = smoothies[9-1] + (smoothies[6-1] << 1); + } + + /*Background Wrapping*/ + if (mapYPos <= BKwrap1) + { + mapYPos = BKwrap1to; + } + if (mapY2Pos <= BKwrap2) + { + mapY2Pos = BKwrap2to; + } + if (mapY3Pos <= BKwrap3) + { + mapY3Pos = BKwrap3to; + } + + + allPlayersGone = all_players_dead() && + ((*player[0].lives == 1 && player[0].exploding_ticks == 0) || (!onePlayerAction && !twoPlayerMode)) && + ((*player[1].lives == 1 && player[1].exploding_ticks == 0) || !twoPlayerMode); + + + /*-----MUSIC FADE------*/ + if (musicFade) + { + if (tempVolume > 10) + { + tempVolume--; + set_volume(tempVolume, fxVolume); + } + else + { + musicFade = false; + } + } + + if (!allPlayersGone && levelEnd > 0 && endLevel) + { + play_song(9); + musicFade = false; + } + else if (!playing && firstGameOver) + { + play_song(levelSong - 1); + } + + + if (!endLevel) // draw HUD + { + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + + /*-----------------------Message Bar------------------------*/ + if (textErase > 0 && --textErase == 0) + blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36); // in-game message area + + /*------------------------Shield Gen-------------------------*/ + if (galagaMode) + { + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].shield = 0; + + // spawned dragonwing died :( + if (*player[1].lives == 0 || player[1].armor == 0) + twoPlayerMode = false; + + if (player[0].cash >= (unsigned)galagaLife) + { + soundQueue[6] = S_EXPLOSION_11; + soundQueue[7] = S_SOUL_OF_ZINGLON; + + if (*player[0].lives < 11) + ++(*player[0].lives); + else + player[0].cash += 1000; + + if (galagaLife == 10000) + galagaLife = 20000; + else + galagaLife += 25000; + } + } + else // not galagaMode + { + if (twoPlayerMode) + { + if (--shieldWait == 0) + { + shieldWait = 15; + + for (uint i = 0; i < COUNTOF(player); ++i) + { + if (player[i].shield < player[i].shield_max && player[i].is_alive) + ++player[i].shield; + } + + JE_drawShield(); + } + } + else if (player[0].is_alive && player[0].shield < player[0].shield_max && power > shieldT) + { + if (--shieldWait == 0) + { + shieldWait = 15; + + power -= shieldT; + + ++player[0].shield; + if (player[1].shield < player[0].shield_max) + ++player[1].shield; + + JE_drawShield(); + } + } + } + + /*---------------------Weapon Display-------------------------*/ + for (uint i = 0; i < 2; ++i) + { + uint item_power = player[twoPlayerMode ? i : 0].items.weapon[i].power; + + if (old_weapon_bar[i] != item_power) + { + old_weapon_bar[i] = item_power; + + int x = twoPlayerMode ? 286 : 289, + y = (i == 0) ? (twoPlayerMode ? 6 : 17) : (twoPlayerMode ? 100 : 38); + + fill_rectangle_xy(VGAScreenSeg, x, y, x + 1 + 10 * 2, y + 2, 0); + + for (uint j = 1; j <= item_power; ++j) + { + JE_rectangle(VGAScreen, x, y, x + 1, y + 2, 115 + j); /* SEGa000 */ + x += 2; + } + } + } + + /*------------------------Power Bar-------------------------*/ + if (twoPlayerMode || onePlayerAction) + { + power = 900; + } + else + { + power += powerAdd; + if (power > 900) + power = 900; + + temp = power / 10; + + if (temp != lastPower) + { + if (temp > lastPower) + fill_rectangle_xy(VGAScreenSeg, 269, 113 - 11 - temp, 276, 114 - 11 - lastPower, 113 + temp / 7); + else + fill_rectangle_xy(VGAScreenSeg, 269, 113 - 11 - lastPower, 276, 114 - 11 - temp, 0); + + lastPower = temp; + } + } + + oldMapX3Ofs = mapX3Ofs; + + enemyOnScreen = 0; + } + + /* use game_screen for all the generic drawing functions */ + VGAScreen = game_screen; + + /*---------------------------EVENTS-------------------------*/ + while (eventRec[eventLoc-1].eventtime <= curLoc && eventLoc <= maxEvent) + JE_eventSystem(); + + if (isNetworkGame && reallyEndLevel) + goto start_level; + + + /* SMOOTHIES! */ + JE_checkSmoothies(); + if (anySmoothies) + VGAScreen = VGAScreen2; // this makes things complicated, but we do it anyway :( + + /* --- BACKGROUNDS --- */ + /* --- BACKGROUND 1 --- */ + + if (forceEvents && !backMove) + curLoc++; + + if (map1YDelayMax > 1 && backMove < 2) + backMove = (map1YDelay == 1) ? 1 : 0; + + /*Draw background*/ + if (astralDuration == 0) + draw_background_1(VGAScreen); + else + JE_clr256(VGAScreen); + + /*Set Movement of background 1*/ + if (--map1YDelay == 0) + { + map1YDelay = map1YDelayMax; + + curLoc += backMove; + + backPos += backMove; + + if (backPos > 27) + { + backPos -= 28; + mapY--; + mapYPos -= 14; /*Map Width*/ + } + } + + /*---------------------------STARS--------------------------*/ + /* DRAWSTARS */ + if (starActive || astralDuration > 0) + { + s = (Uint8 *)VGAScreen->pixels; + + for (i = MAX_STARS; i--; ) + { + starDat[i].sLoc += starDat[i].sMov + starY; + if (starDat[i].sLoc < 177 * VGAScreen->pitch) + { + if (*(s + starDat[i].sLoc) == 0) + { + *(s + starDat[i].sLoc) = starDat[i].sC; + } + if (starDat[i].sC - 4 >= 9 * 16) + { + if (*(s + starDat[i].sLoc + 1) == 0) + { + *(s + starDat[i].sLoc + 1) = starDat[i].sC - 4; + } + if (starDat[i].sLoc > 0 && *(s + starDat[i].sLoc - 1) == 0) + { + *(s + starDat[i].sLoc - 1) = starDat[i].sC - 4; + } + if (*(s + starDat[i].sLoc + VGAScreen->pitch) == 0) + { + *(s + starDat[i].sLoc + VGAScreen->pitch) = starDat[i].sC - 4; + } + if (starDat[i].sLoc >= VGAScreen->pitch && *(s + starDat[i].sLoc - VGAScreen->pitch) == 0) + { + *(s + starDat[i].sLoc - VGAScreen->pitch) = starDat[i].sC - 4; + } + } + } + } + } + + if (processorType > 1 && smoothies[5-1]) + { + iced_blur_filter(game_screen, VGAScreen); + VGAScreen = game_screen; + } + + /*-----------------------BACKGROUNDS------------------------*/ + /*-----------------------BACKGROUND 2------------------------*/ + if (background2over == 3) + { + draw_background_2(VGAScreen); + background2 = true; + } + + if (background2over == 0) + { + if (!(smoothies[2-1] && processorType < 4) && !(smoothies[1-1] && processorType == 3)) + { + if (wild && !background2notTransparent) + draw_background_2_blend(VGAScreen); + else + draw_background_2(VGAScreen); + } + } + + if (smoothies[0] && processorType > 2 && smoothie_data[0] == 0) + { + lava_filter(game_screen, VGAScreen); + VGAScreen = game_screen; + } + if (smoothies[2-1] && processorType > 2) + { + water_filter(game_screen, VGAScreen); + VGAScreen = game_screen; + } + + /*-----------------------Ground Enemy------------------------*/ + lastEnemyOnScreen = enemyOnScreen; + + tempMapXOfs = mapXOfs; + tempBackMove = backMove; + JE_drawEnemy(50); + JE_drawEnemy(100); + + if (enemyOnScreen == 0 || enemyOnScreen == lastEnemyOnScreen) + { + if (stopBackgroundNum == 1) + stopBackgroundNum = 9; + } + + if (smoothies[0] && processorType > 2 && smoothie_data[0] > 0) + { + lava_filter(game_screen, VGAScreen); + VGAScreen = game_screen; + } + + if (superWild) + { + neat += 3; + JE_darkenBackground(neat); + } + + /*-----------------------BACKGROUNDS------------------------*/ + /*-----------------------BACKGROUND 2------------------------*/ + if (!(smoothies[2-1] && processorType < 4) && + !(smoothies[1-1] && processorType == 3)) + { + if (background2over == 1) + { + if (wild && !background2notTransparent) + draw_background_2_blend(VGAScreen); + else + draw_background_2(VGAScreen); + } + } + + if (superWild) + { + neat++; + JE_darkenBackground(neat); + } + + if (background3over == 2) + draw_background_3(VGAScreen); + + /* New Enemy */ + if (enemiesActive && mt_rand() % 100 > levelEnemyFrequency) + { + tempW = levelEnemy[mt_rand() % levelEnemyMax]; + if (tempW == 2) + soundQueue[3] = S_WEAPON_7; + JE_newEnemy(0); + } + + if (processorType > 1 && smoothies[3-1]) + { + iced_blur_filter(game_screen, VGAScreen); + VGAScreen = game_screen; + } + if (processorType > 1 && smoothies[4-1]) + { + blur_filter(game_screen, VGAScreen); + VGAScreen = game_screen; + } + + /* Draw Sky Enemy */ + if (!skyEnemyOverAll) + { + lastEnemyOnScreen = enemyOnScreen; + + tempMapXOfs = mapX2Ofs; + tempBackMove = 0; + JE_drawEnemy(25); + + if (enemyOnScreen == lastEnemyOnScreen) + { + if (stopBackgroundNum == 2) + stopBackgroundNum = 9; + } + } + + if (background3over == 0) + draw_background_3(VGAScreen); + + /* Draw Top Enemy */ + if (!topEnemyOver) + { + tempMapXOfs = (background3x1 == 0) ? oldMapX3Ofs : mapXOfs; + tempBackMove = backMove3; + JE_drawEnemy(75); + } + + /* Player Shot Images */ + for (int z = 0; z < MAX_PWEAPON; z++) + { + if (shotAvail[z] != 0) + { + bool is_special = false; + int tempShotX = 0, tempShotY = 0; + + shotAvail[z]--; + if (z != MAX_PWEAPON - 1) + { + + playerShotData[z].shotXM += playerShotData[z].shotXC; + playerShotData[z].shotX += playerShotData[z].shotXM; + tempI4 = playerShotData[z].shotXM; + + if (playerShotData[z].shotXM > 100) + { + if (playerShotData[z].shotXM == 101) + { + playerShotData[z].shotX -= 101; + playerShotData[z].shotX += player[playerShotData[z].playerNumber-1].delta_x_shot_move; + playerShotData[z].shotY += player[playerShotData[z].playerNumber-1].delta_y_shot_move; + } + else + { + playerShotData[z].shotX -= 120; + playerShotData[z].shotX += player[playerShotData[z].playerNumber-1].delta_x_shot_move; + } + } + + playerShotData[z].shotYM += playerShotData[z].shotYC; + playerShotData[z].shotY += playerShotData[z].shotYM; + + if (playerShotData[z].shotYM > 100) + { + playerShotData[z].shotY -= 120; + playerShotData[z].shotY += player[playerShotData[z].playerNumber-1].delta_y_shot_move; + } + + if (playerShotData[z].shotComplicated != 0) + { + playerShotData[z].shotDevX += playerShotData[z].shotDirX; + playerShotData[z].shotX += playerShotData[z].shotDevX; + + if (abs(playerShotData[z].shotDevX) == playerShotData[z].shotCirSizeX) + playerShotData[z].shotDirX = -playerShotData[z].shotDirX; + + playerShotData[z].shotDevY += playerShotData[z].shotDirY; + playerShotData[z].shotY += playerShotData[z].shotDevY; + + if (abs(playerShotData[z].shotDevY) == playerShotData[z].shotCirSizeY) + playerShotData[z].shotDirY = -playerShotData[z].shotDirY; + + /*Double Speed Circle Shots - add a second copy of above loop*/ + } + + tempShotX = playerShotData[z].shotX; + tempShotY = playerShotData[z].shotY; + + if (playerShotData[z].shotX < -34 || playerShotData[z].shotX > 290 || + playerShotData[z].shotY < -15 || playerShotData[z].shotY > 190) + { + shotAvail[z] = 0; + goto draw_player_shot_loop_end; + } + + if (playerShotData[z].shotTrail != 255) + { + if (playerShotData[z].shotTrail == 98) + JE_setupExplosion(playerShotData[z].shotX - playerShotData[z].shotXM, playerShotData[z].shotY - playerShotData[z].shotYM, 0, playerShotData[z].shotTrail, false, false); + else + JE_setupExplosion(playerShotData[z].shotX, playerShotData[z].shotY, 0, playerShotData[z].shotTrail, false, false); + } + + if (playerShotData[z].aimAtEnemy != 0) + { + if (--playerShotData[z].aimDelay == 0) + { + playerShotData[z].aimDelay = playerShotData[z].aimDelayMax; + + if (enemyAvail[playerShotData[z].aimAtEnemy] != 1) + { + if (playerShotData[z].shotX < enemy[playerShotData[z].aimAtEnemy].ex) + playerShotData[z].shotXM++; + else + playerShotData[z].shotXM--; + + if (playerShotData[z].shotY < enemy[playerShotData[z].aimAtEnemy].ey) + playerShotData[z].shotYM++; + else + playerShotData[z].shotYM--; + } + else + { + if (playerShotData[z].shotXM > 0) + playerShotData[z].shotXM++; + else + playerShotData[z].shotXM--; + } + } + } + + tempW = playerShotData[z].shotGr + playerShotData[z].shotAni; + if (++playerShotData[z].shotAni == playerShotData[z].shotAniMax) + playerShotData[z].shotAni = 0; + + tempI2 = playerShotData[z].shotDmg; + temp2 = playerShotData[z].shotBlastFilter; + chain = playerShotData[z].chainReaction; + playerNum = playerShotData[z].playerNumber; + + is_special = tempW > 60000; + + if (is_special) + { + blit_sprite_blend(VGAScreen, tempShotX+1, tempShotY, OPTION_SHAPES, tempW - 60001); + + tempX2 = sprite(OPTION_SHAPES, tempW - 60001)->width / 2; + tempY2 = sprite(OPTION_SHAPES, tempW - 60001)->height / 2; + } + else + { + if (tempW > 1000) + { + JE_doSP(tempShotX+1 + 6, tempShotY + 6, 5, 3, (tempW / 1000) << 4); + tempW = tempW % 1000; + } + if (tempW > 500) + { + if (background2 && tempShotY + shadowYDist < 190 && tempI4 < 100) + blit_sprite2_darken(VGAScreen, tempShotX+1, tempShotY + shadowYDist, shapesW2, tempW - 500); + blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesW2, tempW - 500); + } + else + { + if (background2 && tempShotY + shadowYDist < 190 && tempI4 < 100) + blit_sprite2_darken(VGAScreen, tempShotX+1, tempShotY + shadowYDist, shapesC1, tempW); + blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesC1, tempW); + } + } + } + + for (b = 0; b < 100; b++) + { + if (enemyAvail[b] == 0) + { + bool collided; + + if (z == MAX_PWEAPON - 1) + { + temp = 25 - abs(zinglonDuration - 25); + collided = abs(enemy[b].ex + enemy[b].mapoffset - (player[0].x + 7)) < temp; + temp2 = 9; + chain = 0; + tempI2 = 10; + } + else if (is_special) + { + collided = ((enemy[b].enemycycle == 0) && + (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX - tempX2) < (25 + tempX2)) && + (abs(enemy[b].ey - tempShotY - 12 - tempY2) < (29 + tempY2))) || + ((enemy[b].enemycycle > 0) && + (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX - tempX2) < (13 + tempX2)) && + (abs(enemy[b].ey - tempShotY - 6 - tempY2) < (15 + tempY2))); + } + else + { + collided = ((enemy[b].enemycycle == 0) && + (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX) < 25) && (abs(enemy[b].ey - tempShotY - 12) < 29)) || + ((enemy[b].enemycycle > 0) && + (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX) < 13) && (abs(enemy[b].ey - tempShotY - 6) < 15)); + } + + if (collided) + { + if (chain > 0) + { + shotMultiPos[SHOT_MISC] = 0; + JE_initPlayerShot(0, SHOT_MISC, tempShotX, tempShotY, mouseX, mouseY, chain, playerNum); + shotAvail[z] = 0; + goto draw_player_shot_loop_end; + } + + infiniteShot = false; + + if (tempI2 == 99) + { + tempI2 = 0; + doIced = 40; + enemy[b].iced = 40; + } + else + { + doIced = 0; + if (tempI2 >= 250) + { + tempI2 = tempI2 - 250; + infiniteShot = true; + } + } + + tempI = enemy[b].armorleft; + + temp = enemy[b].linknum; + if (temp == 0) + temp = 255; + + if (enemy[b].armorleft < 255) + { + for (unsigned int i = 0; i < COUNTOF(boss_bar); i++) + if (temp == boss_bar[i].link_num) + boss_bar[i].color = 6; + + if (enemy[b].enemyground) + enemy[b].filter = temp2; + + for (unsigned int e = 0; e < COUNTOF(enemy); e++) + { + if (enemy[e].linknum == temp && + enemyAvail[e] != 1 && + enemy[e].enemyground != 0) + { + if (doIced) + enemy[e].iced = doIced; + enemy[e].filter = temp2; + } + } + } + + if (tempI > tempI2) + { + if (z != MAX_PWEAPON - 1) + { + if (enemy[b].armorleft != 255) + { + enemy[b].armorleft -= tempI2; + JE_setupExplosion(tempShotX, tempShotY, 0, 0, false, false); + } + else + { + JE_doSP(tempShotX + 6, tempShotY + 6, tempI2 / 2 + 3, tempI2 / 4 + 2, temp2); + } + } + + soundQueue[5] = S_ENEMY_HIT; + + if ((tempI - tempI2 <= enemy[b].edlevel) && + ((!enemy[b].edamaged) ^ (enemy[b].edani < 0))) + { + + for (temp3 = 0; temp3 < 100; temp3++) + { + if (enemyAvail[temp3] != 1) + { + temp4 = enemy[temp3].linknum; + if ( + (temp3 == b) || + ( + (temp != 255) && + ( + ((enemy[temp3].edlevel > 0) && (temp4 == temp)) || + ( + (enemyContinualDamage && (temp - 100 == temp4)) || + ((temp4 > 40) && (temp4 / 20 == temp / 20) && (temp4 <= temp)) + ) + ) + ) + ) + { + enemy[temp3].enemycycle = 1; + + enemy[temp3].edamaged = !enemy[temp3].edamaged; + + if (enemy[temp3].edani != 0) + { + enemy[temp3].ani = abs(enemy[temp3].edani); + enemy[temp3].aniactive = 1; + enemy[temp3].animax = 0; + enemy[temp3].animin = enemy[temp3].edgr; + enemy[temp3].enemycycle = enemy[temp3].animin - 1; + + } + else if (enemy[temp3].edgr > 0) + { + enemy[temp3].egr[1-1] = enemy[temp3].edgr; + enemy[temp3].ani = 1; + enemy[temp3].aniactive = 0; + enemy[temp3].animax = 0; + enemy[temp3].animin = 1; + } + else + { + enemyAvail[temp3] = 1; + enemyKilled++; + } + + enemy[temp3].aniwhenfire = 0; + + if (enemy[temp3].armorleft > (unsigned char)enemy[temp3].edlevel) + enemy[temp3].armorleft = enemy[temp3].edlevel; + + tempX = enemy[temp3].ex + enemy[temp3].mapoffset; + tempY = enemy[temp3].ey; + + if (enemyDat[enemy[temp3].enemytype].esize != 1) + JE_setupExplosion(tempX, tempY - 6, 0, 1, false, false); + else + JE_setupExplosionLarge(enemy[temp3].enemyground, enemy[temp3].explonum / 2, tempX, tempY); + } + } + } + } + } + else + { + + if ((temp == 254) && (superEnemy254Jump > 0)) + JE_eventJump(superEnemy254Jump); + + for (temp2 = 0; temp2 < 100; temp2++) + { + if (enemyAvail[temp2] != 1) + { + temp3 = enemy[temp2].linknum; + if ((temp2 == b) || (temp == 254) || + ((temp != 255) && ((temp == temp3) || (temp - 100 == temp3) + || ((temp3 > 40) && (temp3 / 20 == temp / 20) && (temp3 <= temp))))) + { + + tempI3 = enemy[temp2].ex + enemy[temp2].mapoffset; + + if (enemy[temp2].special) + globalFlags[enemy[temp2].flagnum] = enemy[temp2].setto; + + if ((enemy[temp2].enemydie > 0) && + !((superArcadeMode != SA_NONE) && + (enemyDat[enemy[temp2].enemydie].value == 30000))) + { + int temp_b = b; + tempW = enemy[temp2].enemydie; + tempW2 = temp2 - (temp2 % 25); + if (enemyDat[tempW].value > 30000) + { + tempW2 = 0; + } + JE_newEnemy(tempW2); + if (b != 0) { + if ((superArcadeMode != SA_NONE) && (enemy[b-1].evalue > 30000)) + { + superArcadePowerUp++; + if (superArcadePowerUp > 5) + superArcadePowerUp = 1; + enemy[b-1].egr[1-1] = 5 + superArcadePowerUp * 2; + enemy[b-1].evalue = 30000 + superArcadePowerUp; + } + + if (enemy[b-1].evalue != 0) + enemy[b-1].scoreitem = true; + else + enemy[b-1].scoreitem = false; + + enemy[b-1].ex = enemy[temp2].ex; + enemy[b-1].ey = enemy[temp2].ey; + } + b = temp_b; + } + + if ((enemy[temp2].evalue > 0) && (enemy[temp2].evalue < 10000)) + { + if (enemy[temp2].evalue == 1) + { + cubeMax++; + } + else + { + // in galaga mode player 2 is sidekick, so give cash to player 1 + player[galagaMode ? 0 : playerNum - 1].cash += enemy[temp2].evalue; + } + } + + if ((enemy[temp2].edlevel == -1) && (temp == temp3)) + { + enemy[temp2].edlevel = 0; + enemyAvail[temp2] = 2; + enemy[temp2].egr[1-1] = enemy[temp2].edgr; + enemy[temp2].ani = 1; + enemy[temp2].aniactive = 0; + enemy[temp2].animax = 0; + enemy[temp2].animin = 1; + enemy[temp2].edamaged = true; + enemy[temp2].enemycycle = 1; + } else { + enemyAvail[temp2] = 1; + enemyKilled++; + } + + if (enemyDat[enemy[temp2].enemytype].esize == 1) + { + JE_setupExplosionLarge(enemy[temp2].enemyground, enemy[temp2].explonum, tempI3, enemy[temp2].ey); + soundQueue[6] = S_EXPLOSION_9; + } + else + { + JE_setupExplosion(tempI3, enemy[temp2].ey, 0, 1, false, false); + soundQueue[6] = S_SELECT; // S_EXPLOSION_8 + } + } + } + } + } + + if (infiniteShot) + { + tempI2 += 250; + } + else if (z != MAX_PWEAPON - 1) + { + if (tempI2 <= tempI) + { + shotAvail[z] = 0; + goto draw_player_shot_loop_end; + } + else + { + playerShotData[z].shotDmg -= tempI; + } + } + + } + } + } + +draw_player_shot_loop_end: + ; + } + } + + /* Player movement indicators for shots that track your ship */ + for (uint i = 0; i < COUNTOF(player); ++i) + { + player[i].last_x_shot_move = player[i].x; + player[i].last_y_shot_move = player[i].y; + } + + /*=================================*/ + /*=======Collisions Detection======*/ + /*=================================*/ + + for (uint i = 0; i < (twoPlayerMode ? 2 : 1); ++i) + if (player[i].is_alive && !endLevel) + JE_playerCollide(&player[i], i + 1); + + if (firstGameOver) + JE_mainGamePlayerFunctions(); /*--------PLAYER DRAW+MOVEMENT---------*/ + + if (!endLevel) + { /*MAIN DRAWING IS STOPPED STARTING HERE*/ + + /* Draw Enemy Shots */ + for (int z = 0; z < ENEMY_SHOT_MAX; z++) + { + if (enemyShotAvail[z] == 0) + { + enemyShot[z].sxm += enemyShot[z].sxc; + enemyShot[z].sx += enemyShot[z].sxm; + + if (enemyShot[z].tx != 0) + { + if (enemyShot[z].sx > player[0].x) + { + if (enemyShot[z].sxm > -enemyShot[z].tx) + { + enemyShot[z].sxm--; + } + } else { + if (enemyShot[z].sxm < enemyShot[z].tx) + { + enemyShot[z].sxm++; + } + } + } + + enemyShot[z].sym += enemyShot[z].syc; + enemyShot[z].sy += enemyShot[z].sym; + + if (enemyShot[z].ty != 0) + { + if (enemyShot[z].sy > player[0].y) + { + if (enemyShot[z].sym > -enemyShot[z].ty) + { + enemyShot[z].sym--; + } + } else { + if (enemyShot[z].sym < enemyShot[z].ty) + { + enemyShot[z].sym++; + } + } + } + + if (enemyShot[z].duration-- == 0 || enemyShot[z].sy > 190 || enemyShot[z].sy <= -14 || enemyShot[z].sx > 275 || enemyShot[z].sx <= 0) + { + enemyShotAvail[z] = true; + } + else // check if shot collided with player + { + for (uint i = 0; i < (twoPlayerMode ? 2 : 1); ++i) + { + if (player[i].is_alive && + enemyShot[z].sx > player[i].x - (signed)player[i].shot_hit_area_x && + enemyShot[z].sx < player[i].x + (signed)player[i].shot_hit_area_x && + enemyShot[z].sy > player[i].y - (signed)player[i].shot_hit_area_y && + enemyShot[z].sy < player[i].y + (signed)player[i].shot_hit_area_y) + { + tempX = enemyShot[z].sx; + tempY = enemyShot[z].sy; + temp = enemyShot[z].sdmg; + + enemyShotAvail[z] = true; + + JE_setupExplosion(tempX, tempY, 0, 0, false, false); + + if (player[i].invulnerable_ticks == 0) + { + if ((temp = JE_playerDamage(temp, &player[i])) > 0) + { + player[i].x_velocity += (enemyShot[z].sxm * temp) / 2; + player[i].y_velocity += (enemyShot[z].sym * temp) / 2; + } + } + + break; + } + } + + if (enemyShotAvail[z] == false) + { + if (enemyShot[z].animax != 0) + { + if (++enemyShot[z].animate >= enemyShot[z].animax) + enemyShot[z].animate = 0; + } + + if (enemyShot[z].sgr >= 500) + blit_sprite2(VGAScreen, enemyShot[z].sx, enemyShot[z].sy, shapesW2, enemyShot[z].sgr + enemyShot[z].animate - 500); + else + blit_sprite2(VGAScreen, enemyShot[z].sx, enemyShot[z].sy, shapesC1, enemyShot[z].sgr + enemyShot[z].animate); + } + } + + } + } + } + + if (background3over == 1) + draw_background_3(VGAScreen); + + /* Draw Top Enemy */ + if (topEnemyOver) + { + tempMapXOfs = (background3x1 == 0) ? oldMapX3Ofs : oldMapXOfs; + tempBackMove = backMove3; + JE_drawEnemy(75); + } + + /* Draw Sky Enemy */ + if (skyEnemyOverAll) + { + lastEnemyOnScreen = enemyOnScreen; + + tempMapXOfs = mapX2Ofs; + tempBackMove = 0; + JE_drawEnemy(25); + + if (enemyOnScreen == lastEnemyOnScreen) + { + if (stopBackgroundNum == 2) + stopBackgroundNum = 9; + } + } + + /*-------------------------- Sequenced Explosions -------------------------*/ + enemyStillExploding = false; + for (int i = 0; i < MAX_REPEATING_EXPLOSIONS; i++) + { + if (rep_explosions[i].ttl != 0) + { + enemyStillExploding = true; + + if (rep_explosions[i].delay > 0) + { + rep_explosions[i].delay--; + continue; + } + + rep_explosions[i].y += backMove2 + 1; + tempX = rep_explosions[i].x + (mt_rand() % 24) - 12; + tempY = rep_explosions[i].y + (mt_rand() % 27) - 24; + + if (rep_explosions[i].big) + { + JE_setupExplosionLarge(false, 2, tempX, tempY); + + if (rep_explosions[i].ttl == 1 || mt_rand() % 5 == 1) + soundQueue[7] = S_EXPLOSION_11; + else + soundQueue[6] = S_EXPLOSION_9; + + rep_explosions[i].delay = 4 + (mt_rand() % 3); + } + else + { + JE_setupExplosion(tempX, tempY, 0, 1, false, false); + + soundQueue[5] = S_EXPLOSION_4; + + rep_explosions[i].delay = 3; + } + + rep_explosions[i].ttl--; + } + } + + /*---------------------------- Draw Explosions ----------------------------*/ + for (int j = 0; j < MAX_EXPLOSIONS; j++) + { + if (explosions[j].ttl != 0) + { + if (explosions[j].fixed_position != true) + { + explosions[j].sprite++; + explosions[j].y += explodeMove; + } + else if (explosions[j].follow_player == true) + { + explosions[j].x += explosionFollowAmountX; + explosions[j].y += explosionFollowAmountY; + } + explosions[j].y += explosions[j].delta_y; + explosions[j].x += explosions[j].delta_x; + + if (explosions[j].y > 200 - 14) + { + explosions[j].ttl = 0; + } + else + { + if (explosionTransparent) + blit_sprite2_blend(VGAScreen, explosions[j].x, explosions[j].y, shapes6, explosions[j].sprite + 1); + else + blit_sprite2(VGAScreen, explosions[j].x, explosions[j].y, shapes6, explosions[j].sprite + 1); + + explosions[j].ttl--; + } + } + } + + if (!portConfigChange) + portConfigDone = true; + + + /*-----------------------BACKGROUNDS------------------------*/ + /*-----------------------BACKGROUND 2------------------------*/ + if (!(smoothies[2-1] && processorType < 4) && + !(smoothies[1-1] && processorType == 3)) + { + if (background2over == 2) + { + if (wild && !background2notTransparent) + draw_background_2_blend(VGAScreen); + else + draw_background_2(VGAScreen); + } + } + + /*-------------------------Warning---------------------------*/ + if ((player[0].is_alive && player[0].armor < 6) || + (twoPlayerMode && !galagaMode && player[1].is_alive && player[1].armor < 6)) + { + tempW2 = (player[0].is_alive && player[0].armor < 6) ? player[0].armor : player[1].armor; + + if (armorShipDelay > 0) + { + armorShipDelay--; + } + else + { + tempW = 560; + JE_newEnemy(50); + if (b > 0) + { + enemy[b-1].enemydie = 560 + (mt_rand() % 3) + 1; + enemy[b-1].eyc -= backMove3; + enemy[b-1].armorleft = 4; + } + armorShipDelay = 500; + } + + if ((player[0].is_alive && player[0].armor < 6 && (!isNetworkGame || thisPlayerNum == 1)) || + (twoPlayerMode && player[1].is_alive && player[1].armor < 6 && (!isNetworkGame || thisPlayerNum == 2))) + { + + tempW = tempW2 * 4 + 8; + if (warningSoundDelay > tempW) + warningSoundDelay = tempW; + + if (warningSoundDelay > 1) + { + warningSoundDelay--; + } + else + { + soundQueue[7] = S_WARNING; + warningSoundDelay = tempW; + } + + warningCol += warningColChange; + if (warningCol > 113 + (14 - (tempW2 * 2))) + { + warningColChange = -warningColChange; + warningCol = 113 + (14 - (tempW2 * 2)); + } + else if (warningCol < 113) + { + warningColChange = -warningColChange; + } + fill_rectangle_xy(VGAScreen, 24, 181, 138, 183, warningCol); + fill_rectangle_xy(VGAScreen, 175, 181, 287, 183, warningCol); + fill_rectangle_xy(VGAScreen, 24, 0, 287, 3, warningCol); + + JE_outText(VGAScreen, 140, 178, "WARNING", 7, (warningCol % 16) / 2); + + } + } + + /*------- Random Explosions --------*/ + if (randomExplosions && mt_rand() % 10 == 1) + JE_setupExplosionLarge(false, 20, mt_rand() % 280, mt_rand() % 180); + + /*=================================*/ + /*=======The Sound Routine=========*/ + /*=================================*/ + if (firstGameOver) + { + temp = 0; + for (temp2 = 0; temp2 < SFX_CHANNELS; temp2++) + { + if (soundQueue[temp2] != S_NONE) + { + temp = soundQueue[temp2]; + if (temp2 == 3) + temp3 = fxPlayVol; + else if (temp == 15) + temp3 = fxPlayVol / 4; + else /*Lightning*/ + temp3 = fxPlayVol / 2; + + JE_multiSamplePlay(digiFx[temp-1], fxSize[temp-1], temp2, temp3); + + soundQueue[temp2] = S_NONE; + } + } + } + + if (returnActive && enemyOnScreen == 0) + { + JE_eventJump(65535); + returnActive = false; + } + + /*------- DEbug ---------*/ + debugTime = SDL_GetTicks(); + tempW = lastmouse_but; + tempX = mouse_x; + tempY = mouse_y; + + if (debug) + { + strcpy(tempStr, ""); + for (temp = 0; temp < 9; temp++) + { + sprintf(tempStr, "%s%c", tempStr, smoothies[temp] + 48); + } + sprintf(buffer, "SM = %s", tempStr); + JE_outText(VGAScreen, 30, 70, buffer, 4, 0); + + sprintf(buffer, "Memory left = %d", -1); + JE_outText(VGAScreen, 30, 80, buffer, 4, 0); + sprintf(buffer, "Enemies onscreen = %d", enemyOnScreen); + JE_outText(VGAScreen, 30, 90, buffer, 6, 0); + + debugHist = debugHist + abs((JE_longint)debugTime - (JE_longint)lastDebugTime); + debugHistCount++; + sprintf(tempStr, "%2.3f", 1000.0f / roundf(debugHist / debugHistCount)); + sprintf(buffer, "X:%d Y:%-5d %s FPS %d %d %d %d", (mapX - 1) * 12 + player[0].x, curLoc, tempStr, player[0].x_velocity, player[0].y_velocity, player[0].x, player[0].y); + JE_outText(VGAScreen, 45, 175, buffer, 15, 3); + lastDebugTime = debugTime; + } + + if (displayTime > 0) + { + displayTime--; + JE_outTextAndDarken(VGAScreen, 90, 10, miscText[59], 15, (JE_byte)flash - 8, FONT_SHAPES); + flash += flashChange; + if (flash > 4 || flash == 0) + flashChange = -flashChange; + } + + /*Pentium Speed Mode?*/ + if (pentiumMode) + { + frameCountMax = (frameCountMax == 2) ? 3 : 2; + } + + /*-------- Level Timer ---------*/ + if (levelTimer && levelTimerCountdown > 0) + { + levelTimerCountdown--; + if (levelTimerCountdown == 0) + JE_eventJump(levelTimerJumpTo); + + if (levelTimerCountdown > 200) + { + if (levelTimerCountdown % 100 == 0) + soundQueue[7] = S_WARNING; + + if (levelTimerCountdown % 10 == 0) + soundQueue[6] = S_CLICK; + } + else if (levelTimerCountdown % 20 == 0) + { + soundQueue[7] = S_WARNING; + } + + JE_textShade (VGAScreen, 140, 6, miscText[66], 7, (levelTimerCountdown % 20) / 3, FULL_SHADE); + sprintf(buffer, "%.1f", levelTimerCountdown / 100.0f); + JE_dString (VGAScreen, 100, 2, buffer, SMALL_FONT_SHAPES); + } + + /*GAME OVER*/ + if (!constantPlay && !constantDie) + { + if (allPlayersGone) + { + if (player[0].exploding_ticks > 0 || player[1].exploding_ticks > 0) + { + if (galagaMode) + player[1].exploding_ticks = 0; + + musicFade = true; + } + else + { + if (play_demo || normalBonusLevelCurrent || bonusLevelCurrent) + reallyEndLevel = true; + else + JE_dString(VGAScreen, 120, 60, miscText[21], FONT_SHAPES); // game over + + set_mouse_position(159, 100); + if (firstGameOver) + { + if (!play_demo) + { + play_song(SONG_GAMEOVER); + set_volume(tyrMusicVolume, fxVolume); + } + firstGameOver = false; + } + + if (!play_demo) + { + push_joysticks_as_keyboard(); + service_SDL_events(true); + if ((newkey || button[0] || button[1] || button[2]) || newmouse) + { + reallyEndLevel = true; + } + } + + if (isNetworkGame) + reallyEndLevel = true; + } + } + } + + if (play_demo) // input kills demo + { + push_joysticks_as_keyboard(); + service_SDL_events(false); + + if (newkey || newmouse) + { + reallyEndLevel = true; + + stopped_demo = true; + } + } + else // input handling for pausing, menu, cheats + { + service_SDL_events(false); + + if (newkey) + { + skipStarShowVGA = false; + JE_mainKeyboardInput(); + newkey = false; + if (skipStarShowVGA) + goto level_loop; + } + + if (pause_pressed) + { + pause_pressed = false; + + if (isNetworkGame) + pauseRequest = true; + else + JE_pauseGame(); + } + + if (ingamemenu_pressed) + { + ingamemenu_pressed = false; + + if (isNetworkGame) + { + inGameMenuRequest = true; + } + else + { + yourInGameMenuRequest = true; + JE_doInGameSetup(); + skipStarShowVGA = true; + } + } + } + + /*Network Update*/ + if (isNetworkGame) + { + if (!reallyEndLevel) + { + Uint16 requests = (pauseRequest == true) | + (inGameMenuRequest == true) << 1 | + (skipLevelRequest == true) << 2 | + (nortShipRequest == true) << 3; + SDLNet_Write16(requests, &packet_state_out[0]->data[14]); + + SDLNet_Write16(difficultyLevel, &packet_state_out[0]->data[16]); + SDLNet_Write16(player[0].x, &packet_state_out[0]->data[18]); + SDLNet_Write16(player[1].x, &packet_state_out[0]->data[20]); + SDLNet_Write16(player[0].y, &packet_state_out[0]->data[22]); + SDLNet_Write16(player[1].y, &packet_state_out[0]->data[24]); + SDLNet_Write16(curLoc, &packet_state_out[0]->data[26]); + + network_state_send(); + + if (network_state_update()) + { + assert(SDLNet_Read16(&packet_state_in[0]->data[26]) == SDLNet_Read16(&packet_state_out[network_delay]->data[26])); + + requests = SDLNet_Read16(&packet_state_in[0]->data[14]) ^ SDLNet_Read16(&packet_state_out[network_delay]->data[14]); + if (requests & 1) + { + JE_pauseGame(); + } + if (requests & 2) + { + yourInGameMenuRequest = SDLNet_Read16(&packet_state_out[network_delay]->data[14]) & 2; + JE_doInGameSetup(); + yourInGameMenuRequest = false; + if (haltGame) + reallyEndLevel = true; + } + if (requests & 4) + { + levelTimer = true; + levelTimerCountdown = 0; + endLevel = true; + levelEnd = 40; + } + if (requests & 8) // nortship + { + player[0].items.ship = 12; + player[0].items.special = 13; + player[0].items.weapon[FRONT_WEAPON].id = 36; + player[0].items.weapon[REAR_WEAPON].id = 37; + shipGr = 1; + } + + for (int i = 0; i < 2; i++) + { + if (SDLNet_Read16(&packet_state_in[0]->data[18 + i * 2]) != SDLNet_Read16(&packet_state_out[network_delay]->data[18 + i * 2]) || SDLNet_Read16(&packet_state_in[0]->data[20 + i * 2]) != SDLNet_Read16(&packet_state_out[network_delay]->data[20 + i * 2])) + { + char temp[64]; + sprintf(temp, "Player %d is unsynchronized!", i + 1); + + JE_textShade(game_screen, 40, 110 + i * 10, temp, 9, 2, FULL_SHADE); + } + } + } + } + + JE_clearSpecialRequests(); + } + + /** Test **/ + JE_drawSP(); + + /*Filtration*/ + if (filterActive) + { + JE_filterScreen(levelFilter, levelBrightness); + } + + draw_boss_bar(); + + JE_inGameDisplays(); + + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + + JE_starShowVGA(); + + /*Start backgrounds if no enemies on screen + End level if number of enemies left to kill equals 0.*/ + if (stopBackgroundNum == 9 && backMove == 0 && !enemyStillExploding) + { + backMove = 1; + backMove2 = 2; + backMove3 = 3; + explodeMove = 2; + stopBackgroundNum = 0; + stopBackgrounds = false; + if (waitToEndLevel) + { + endLevel = true; + levelEnd = 40; + } + if (allPlayersGone) + { + reallyEndLevel = true; + } + } + + if (!endLevel && enemyOnScreen == 0) + { + if (readyToEndLevel && !enemyStillExploding) + { + if (levelTimerCountdown > 0) + { + levelTimer = false; + } + readyToEndLevel = false; + endLevel = true; + levelEnd = 40; + if (allPlayersGone) + { + reallyEndLevel = true; + } + } + if (stopBackgrounds) + { + stopBackgrounds = false; + backMove = 1; + backMove2 = 2; + backMove3 = 3; + explodeMove = 2; + } + } + + + /*Other Network Functions*/ + JE_handleChat(); + + if (reallyEndLevel) + { + goto start_level; + } + goto level_loop; +} + +/* --- Load Level/Map Data --- */ +void JE_loadMap( void ) +{ + JE_DanCShape shape; + + JE_word x, y; + JE_integer yy; + JE_word mapSh[3][128]; /* [1..3, 0..127] */ + JE_byte *ref[3][128]; /* [1..3, 0..127] */ + char s[256]; + + JE_byte mapBuf[15 * 600]; /* [1..15 * 600] */ + JE_word bufLoc; + + char buffer[256]; + int i; + Uint8 pic_buffer[320*200]; /* screen buffer, 8-bit specific */ + Uint8 *vga, *pic, *vga2; /* screen pointer, 8-bit specific */ + + lastCubeMax = cubeMax; + + /*Defaults*/ + songBuy = DEFAULT_SONG_BUY; /*Item Screen default song*/ + + /* Load LEVELS.DAT - Section = MAINLEVEL */ + saveLevel = mainLevel; + +new_game: + galagaMode = false; + useLastBank = false; + extraGame = false; + haltGame = false; + + gameLoaded = false; + + if (!play_demo) + { + do + { + FILE *ep_f = dir_fopen_die(data_dir(), episode_file, "rb"); + + jumpSection = false; + loadLevelOk = false; + + /* Seek Section # Mainlevel */ + int x = 0; + while (x < mainLevel) + { + read_encrypted_pascal_string(s, sizeof(s), ep_f); + if (s[0] == '*') + { + x++; + s[0] = ' '; + } + } + + ESCPressed = false; + + do + { + if (gameLoaded) + { + fclose(ep_f); + + if (mainLevel == 0) // if quit itemscreen + return; // back to title screen + else + goto new_game; + } + + strcpy(s, " "); + read_encrypted_pascal_string(s, sizeof(s), ep_f); + + if (s[0] == ']') + { + switch (s[1]) + { + case 'A': + JE_playAnim("tyrend.anm", 0, 7); + break; + + case 'G': + mapOrigin = atoi(strnztcpy(buffer, s + 4, 2)); + mapPNum = atoi(strnztcpy(buffer, s + 7, 1)); + for (i = 0; i < mapPNum; i++) + { + mapPlanet[i] = atoi(strnztcpy(buffer, s + 1 + (i + 1) * 8, 2)); + mapSection[i] = atoi(strnztcpy(buffer, s + 4 + (i + 1) * 8, 3)); + } + break; + + case '?': + temp = atoi(strnztcpy(buffer, s + 4, 2)); + for (i = 0; i < temp; i++) + { + cubeList[i] = atoi(strnztcpy(buffer, s + 3 + (i + 1) * 4, 3)); + } + if (cubeMax > temp) + cubeMax = temp; + break; + + case '!': + cubeMax = atoi(strnztcpy(buffer, s + 4, 2)); /*Auto set CubeMax*/ + break; + + case '+': + temp = atoi(strnztcpy(buffer, s + 4, 2)); + cubeMax += temp; + if (cubeMax > 4) + cubeMax = 4; + break; + + case 'g': + galagaMode = true; /*GALAGA mode*/ + + player[1].items = player[0].items; + player[1].items.weapon[REAR_WEAPON].id = 15; // Vulcan Cannon + for (uint i = 0; i < COUNTOF(player[1].items.sidekick); ++i) + player[1].items.sidekick[i] = 0; // None + break; + + case 'x': + extraGame = true; + break; + + case 'e': // ENGAGE mode, used for mini-games + doNotSaveBackup = true; + constantDie = false; + onePlayerAction = true; + superTyrian = true; + twoPlayerMode = false; + + player[0].cash = 0; + + player[0].items.ship = 13; // The Stalker 21.126 + player[0].items.weapon[FRONT_WEAPON].id = 39; // Atomic RailGun + player[0].items.weapon[REAR_WEAPON].id = 0; // None + for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i) + player[0].items.sidekick[i] = 0; // None + player[0].items.generator = 2; // Advanced MR-12 + player[0].items.shield = 4; // Advanced Integrity Field + player[0].items.special = 0; // None + + player[0].items.weapon[FRONT_WEAPON].power = 3; + player[0].items.weapon[REAR_WEAPON].power = 1; + break; + + case 'J': // section jump + temp = atoi(strnztcpy(buffer, s + 3, 3)); + mainLevel = temp; + jumpSection = true; + break; + + case '2': // two-player section jump + temp = atoi(strnztcpy(buffer, s + 3, 3)); + if (twoPlayerMode || onePlayerAction) + { + mainLevel = temp; + jumpSection = true; + } + break; + + case 'w': // Stalker 21.126 section jump + temp = atoi(strnztcpy(buffer, s + 3, 3)); /*Allowed to go to Time War?*/ + if (player[0].items.ship == 13) + { + mainLevel = temp; + jumpSection = true; + } + break; + + case 't': + temp = atoi(strnztcpy(buffer, s + 3, 3)); + if (levelTimer && levelTimerCountdown == 0) + { + mainLevel = temp; + jumpSection = true; + } + break; + + case 'l': + temp = atoi(strnztcpy(buffer, s + 3, 3)); + if (!all_players_alive()) + { + mainLevel = temp; + jumpSection = true; + } + break; + + case 's': + saveLevel = mainLevel; + break; /*store savepoint*/ + + case 'b': + if (twoPlayerMode) + { + temp = 22; + } else { + temp = 11; + } + JE_saveGame(11, "LAST LEVEL "); + break; + + case 'i': + temp = atoi(strnztcpy(buffer, s + 3, 3)); + songBuy = temp - 1; + break; + + case 'I': /*Load Items Available Information*/ + memset(&itemAvail, 0, sizeof(itemAvail)); + + for (int i = 0; i < 9; ++i) + { + read_encrypted_pascal_string(s, sizeof(s), ep_f); + + char buf[256]; + strncpy(buf, (strlen(s) > 8) ? s + 8 : "", sizeof(buf)); + + int j = 0, temp; + while (str_pop_int(buf, &temp)) + itemAvail[i][j++] = temp; + itemAvailMax[i] = j; + } + + JE_itemScreen(); + break; + + case 'L': + nextLevel = atoi(strnztcpy(buffer, s + 9, 3)); + strnztcpy(levelName, s + 13, 9); + levelSong = atoi(strnztcpy(buffer, s + 22, 2)); + if (nextLevel == 0) + { + nextLevel = mainLevel + 1; + } + lvlFileNum = atoi(strnztcpy(buffer, s + 25, 2)); + loadLevelOk = true; + bonusLevelCurrent = (strlen(s) > 28) & (s[28] == '$'); + normalBonusLevelCurrent = (strlen(s) > 27) & (s[27] == '$'); + gameJustLoaded = false; + break; + + case '@': + useLastBank = !useLastBank; + break; + + case 'Q': + ESCPressed = false; + temp = secretHint + (mt_rand() % 3) * 3; + + if (twoPlayerMode) + { + for (uint i = 0; i < 2; ++i) + snprintf(levelWarningText[i], sizeof(*levelWarningText), "%s %lu", miscText[40], player[i].cash); + strcpy(levelWarningText[2], ""); + levelWarningLines = 3; + } + else + { + sprintf(levelWarningText[0], "%s %lu", miscText[37], JE_totalScore(&player[0])); + strcpy(levelWarningText[1], ""); + levelWarningLines = 2; + } + + for (x = 0; x < temp - 1; x++) + { + do + read_encrypted_pascal_string(s, sizeof(s), ep_f); + while (s[0] != '#'); + } + + do + { + read_encrypted_pascal_string(s, sizeof(s), ep_f); + strcpy(levelWarningText[levelWarningLines], s); + levelWarningLines++; + } + while (s[0] != '#'); + levelWarningLines--; + + JE_wipeKey(); + frameCountMax = 4; + if (!constantPlay) + JE_displayText(); + + fade_black(15); + + JE_nextEpisode(); + + if (jumpBackToEpisode1 && !twoPlayerMode) + { + JE_loadPic(VGAScreen, 1, false); // huh? + JE_clr256(VGAScreen); + + if (superTyrian) + { + // if completed Zinglon's Revenge, show SuperTyrian and Destruct codes + // if completed SuperTyrian, show Nort-Ship Z code + superArcadeMode = (initialDifficulty == 8) ? 8 : 1; + } + + if (superArcadeMode < SA_ENGAGE) + { + if (SANextShip[superArcadeMode] == SA_ENGAGE) + { + sprintf(buffer, "%s %s", miscTextB[4], pName[0]); + JE_dString(VGAScreen, JE_fontCenter(buffer, FONT_SHAPES), 100, buffer, FONT_SHAPES); + + sprintf(buffer, "Or play... %s", specialName[7]); + JE_dString(VGAScreen, 80, 180, buffer, SMALL_FONT_SHAPES); + } + else + { + JE_dString(VGAScreen, JE_fontCenter(superShips[0], FONT_SHAPES), 30, superShips[0], FONT_SHAPES); + JE_dString(VGAScreen, JE_fontCenter(superShips[SANextShip[superArcadeMode]], SMALL_FONT_SHAPES), 100, superShips[SANextShip[superArcadeMode]], SMALL_FONT_SHAPES); + } + + if (SANextShip[superArcadeMode] < SA_NORTSHIPZ) + blit_sprite2x2(VGAScreen, 148, 70, shapes9, ships[SAShip[SANextShip[superArcadeMode]-1]].shipgraphic); + else if (SANextShip[superArcadeMode] == SA_NORTSHIPZ) + trentWin = true; + + sprintf(buffer, "Type %s at Title", specialName[SANextShip[superArcadeMode]-1]); + JE_dString(VGAScreen, JE_fontCenter(buffer, SMALL_FONT_SHAPES), 160, buffer, SMALL_FONT_SHAPES); + JE_showVGA(); + + fade_palette(colors, 50, 0, 255); + + if (!constantPlay) + wait_input(true, true, true); + } + + jumpSection = true; + + if (isNetworkGame) + JE_readTextSync(); + + if (superTyrian) + { + fade_black(10); + + // back to titlescreen + mainLevel = 0; + return; + } + } + break; + + case 'P': + if (!constantPlay) + { + tempX = atoi(strnztcpy(buffer, s + 3, 3)); + if (tempX > 900) + { + memcpy(colors, palettes[pcxpal[tempX-1 - 900]], sizeof(colors)); + JE_clr256(VGAScreen); + JE_showVGA(); + fade_palette(colors, 1, 0, 255); + } + else + { + if (tempX == 0) + JE_loadPCX("tshp2.pcx"); + else + JE_loadPic(VGAScreen, tempX, false); + + JE_showVGA(); + fade_palette(colors, 10, 0, 255); + } + } + break; + + case 'U': + if (!constantPlay) + { + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + tempX = atoi(strnztcpy(buffer, s + 3, 3)); + JE_loadPic(VGAScreen, tempX, false); + memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer)); + + service_SDL_events(true); + + for (int z = 0; z <= 199; z++) + { + if (!newkey) + { + vga = (Uint8 *)VGAScreen->pixels; + vga2 = (Uint8 *)VGAScreen2->pixels; + pic = pic_buffer + (199 - z) * 320; + + setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/ + + for (y = 0; y <= 199; y++) + { + if (y <= z) + { + memcpy(vga, pic, 320); + pic += 320; + } + else + { + memcpy(vga, vga2, VGAScreen->pitch); + vga2 += VGAScreen->pitch; + } + vga += VGAScreen->pitch; + } + + JE_showVGA(); + + if (isNetworkGame) + { + /* TODO: NETWORK */ + } + + service_wait_delay(); + } + } + + memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer)); + } + break; + + case 'V': + if (!constantPlay) + { + /* TODO: NETWORK */ + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + tempX = atoi(strnztcpy(buffer, s + 3, 3)); + JE_loadPic(VGAScreen, tempX, false); + memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer)); + + service_SDL_events(true); + for (int z = 0; z <= 199; z++) + { + if (!newkey) + { + vga = (Uint8 *)VGAScreen->pixels; + vga2 = (Uint8 *)VGAScreen2->pixels; + pic = pic_buffer; + + setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/ + + for (y = 0; y < 199; y++) + { + if (y <= 199 - z) + { + memcpy(vga, vga2, VGAScreen->pitch); + vga2 += VGAScreen->pitch; + } + else + { + memcpy(vga, pic, 320); + pic += 320; + } + vga += VGAScreen->pitch; + } + + JE_showVGA(); + + if (isNetworkGame) + { + /* TODO: NETWORK */ + } + + service_wait_delay(); + } + } + + memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer)); + } + break; + + case 'R': + if (!constantPlay) + { + /* TODO: NETWORK */ + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + tempX = atoi(strnztcpy(buffer, s + 3, 3)); + JE_loadPic(VGAScreen, tempX, false); + memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer)); + + service_SDL_events(true); + + for (int z = 0; z <= 318; z++) + { + if (!newkey) + { + vga = (Uint8 *)VGAScreen->pixels; + vga2 = (Uint8 *)VGAScreen2->pixels; + pic = pic_buffer; + + setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/ + + for(y = 0; y < 200; y++) + { + memcpy(vga, vga2 + z, 319 - z); + vga += 320 - z; + vga2 += VGAScreen2->pitch; + memcpy(vga, pic, z + 1); + vga += z; + pic += 320; + } + + JE_showVGA(); + + if (isNetworkGame) + { + /* TODO: NETWORK */ + } + + service_wait_delay(); + } + } + + memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer)); + } + break; + + case 'C': + if (!isNetworkGame) + { + fade_black(10); + } + JE_clr256(VGAScreen); + JE_showVGA(); + memcpy(colors, palettes[7], sizeof(colors)); + set_palette(colors, 0, 255); + break; + + case 'B': + if (!isNetworkGame) + { + fade_black(10); + } + break; + case 'F': + if (!isNetworkGame) + { + fade_white(100); + fade_black(30); + } + JE_clr256(VGAScreen); + JE_showVGA(); + break; + + case 'W': + if (!constantPlay) + { + if (!ESCPressed) + { + JE_wipeKey(); + warningCol = 14 * 16 + 5; + warningColChange = 1; + warningSoundDelay = 0; + levelWarningDisplay = (s[2] == 'y'); + levelWarningLines = 0; + frameCountMax = atoi(strnztcpy(buffer, s + 4, 2)); + setjasondelay2(6); + warningRed = frameCountMax / 10; + frameCountMax = frameCountMax % 10; + + do + { + read_encrypted_pascal_string(s, sizeof(s), ep_f); + + if (s[0] != '#') + { + strcpy(levelWarningText[levelWarningLines], s); + levelWarningLines++; + } + } + while (!(s[0] == '#')); + + JE_displayText(); + newkey = false; + } + } + break; + + case 'H': + if (initialDifficulty < 3) + { + mainLevel = atoi(strnztcpy(buffer, s + 4, 3)); + jumpSection = true; + } + break; + + case 'h': + if (initialDifficulty > 2) + { + read_encrypted_pascal_string(s, sizeof(s), ep_f); + } + break; + + case 'S': + if (isNetworkGame) + { + JE_readTextSync(); + } + break; + + case 'n': + ESCPressed = false; + break; + + case 'M': + temp = atoi(strnztcpy(buffer, s + 3, 3)); + play_song(temp - 1); + break; + } + } + + } while (!(loadLevelOk || jumpSection)); + + + fclose(ep_f); + + } while (!loadLevelOk); + } + + if (play_demo) + load_next_demo(); + else + fade_black(50); + + FILE *level_f = dir_fopen_die(data_dir(), levelFile, "rb"); + fseek(level_f, lvlPos[(lvlFileNum-1) * 2], SEEK_SET); + + fgetc(level_f); // char_mapFile + JE_char char_shapeFile = fgetc(level_f); + efread(&mapX, sizeof(JE_word), 1, level_f); + efread(&mapX2, sizeof(JE_word), 1, level_f); + efread(&mapX3, sizeof(JE_word), 1, level_f); + + efread(&levelEnemyMax, sizeof(JE_word), 1, level_f); + for (x = 0; x < levelEnemyMax; x++) + { + efread(&levelEnemy[x], sizeof(JE_word), 1, level_f); + } + + efread(&maxEvent, sizeof(JE_word), 1, level_f); + for (x = 0; x < maxEvent; x++) + { + efread(&eventRec[x].eventtime, sizeof(JE_word), 1, level_f); + efread(&eventRec[x].eventtype, sizeof(JE_byte), 1, level_f); + efread(&eventRec[x].eventdat, sizeof(JE_integer), 1, level_f); + efread(&eventRec[x].eventdat2, sizeof(JE_integer), 1, level_f); + efread(&eventRec[x].eventdat3, sizeof(JE_shortint), 1, level_f); + efread(&eventRec[x].eventdat5, sizeof(JE_shortint), 1, level_f); + efread(&eventRec[x].eventdat6, sizeof(JE_shortint), 1, level_f); + efread(&eventRec[x].eventdat4, sizeof(JE_byte), 1, level_f); + } + eventRec[x].eventtime = 65500; /*Not needed but just in case*/ + + /*debuginfo('Level loaded.');*/ + + /*debuginfo('Loading Map');*/ + + /* MAP SHAPE LOOKUP TABLE - Each map is directly after level */ + efread(mapSh, sizeof(JE_word), sizeof(mapSh) / sizeof(JE_word), level_f); + for (temp = 0; temp < 3; temp++) + { + for (temp2 = 0; temp2 < 128; temp2++) + { + mapSh[temp][temp2] = SDL_Swap16(mapSh[temp][temp2]); + } + } + + /* Read Shapes.DAT */ + sprintf(tempStr, "shapes%c.dat", tolower((unsigned char)char_shapeFile)); + FILE *shpFile = dir_fopen_die(data_dir(), tempStr, "rb"); + + for (int z = 0; z < 600; z++) + { + JE_boolean shapeBlank = fgetc(shpFile); + + if (shapeBlank) + memset(shape, 0, sizeof(shape)); + else + efread(shape, sizeof(JE_byte), sizeof(shape), shpFile); + + /* Match 1 */ + for (int x = 0; x <= 71; ++x) + { + if (mapSh[0][x] == z+1) + { + memcpy(megaData1.shapes[x].sh, shape, sizeof(JE_DanCShape)); + + ref[0][x] = (JE_byte *)megaData1.shapes[x].sh; + } + } + + /* Match 2 */ + for (int x = 0; x <= 71; ++x) + { + if (mapSh[1][x] == z+1) + { + if (x != 71 && !shapeBlank) + { + memcpy(megaData2.shapes[x].sh, shape, sizeof(JE_DanCShape)); + + y = 1; + for (yy = 0; yy < (24 * 28) >> 1; yy++) + if (shape[yy] == 0) + y = 0; + + megaData2.shapes[x].fill = y; + ref[1][x] = (JE_byte *)megaData2.shapes[x].sh; + } + else + { + ref[1][x] = NULL; + } + } + } + + /*Match 3*/ + for (int x = 0; x <= 71; ++x) + { + if (mapSh[2][x] == z+1) + { + if (x < 70 && !shapeBlank) + { + memcpy(megaData3.shapes[x].sh, shape, sizeof(JE_DanCShape)); + + y = 1; + for (yy = 0; yy < (24 * 28) >> 1; yy++) + if (shape[yy] == 0) + y = 0; + + megaData3.shapes[x].fill = y; + ref[2][x] = (JE_byte *)megaData3.shapes[x].sh; + } + else + { + ref[2][x] = NULL; + } + } + } + } + + fclose(shpFile); + + efread(mapBuf, sizeof(JE_byte), 14 * 300, level_f); + bufLoc = 0; /* MAP NUMBER 1 */ + for (y = 0; y < 300; y++) + { + for (x = 0; x < 14; x++) + { + megaData1.mainmap[y][x] = ref[0][mapBuf[bufLoc]]; + bufLoc++; + } + } + + efread(mapBuf, sizeof(JE_byte), 14 * 600, level_f); + bufLoc = 0; /* MAP NUMBER 2 */ + for (y = 0; y < 600; y++) + { + for (x = 0; x < 14; x++) + { + megaData2.mainmap[y][x] = ref[1][mapBuf[bufLoc]]; + bufLoc++; + } + } + + efread(mapBuf, sizeof(JE_byte), 15 * 600, level_f); + bufLoc = 0; /* MAP NUMBER 3 */ + for (y = 0; y < 600; y++) + { + for (x = 0; x < 15; x++) + { + megaData3.mainmap[y][x] = ref[2][mapBuf[bufLoc]]; + bufLoc++; + } + } + + fclose(level_f); + + /* Note: The map data is automatically calculated with the correct mapsh + value and then the pointer is calculated using the formula (MAPSH-1)*168. + Then, we'll automatically add S2Ofs to get the exact offset location into + the shape table! This makes it VERY FAST! */ + + /*debuginfo('Map file done.');*/ + /* End of find loop for LEVEL??.DAT */ +} + +bool JE_titleScreen( JE_boolean animate ) +{ + bool quit = false; + + const int menunum = 7; + + unsigned int arcade_code_i[SA_ENGAGE] = { 0 }; + + JE_word waitForDemo; + JE_byte menu = 0; + JE_boolean redraw = true, + fadeIn = false; + + JE_word temp; /* JE_byte temp; from varz.h will overflow in for loop */ + + play_demo = false; + stopped_demo = false; + + redraw = true; + fadeIn = false; + + gameLoaded = false; + jumpSection = false; + + if (isNetworkGame) + { + JE_loadPic(VGAScreen, 2, false); + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + JE_dString(VGAScreen, JE_fontCenter("Waiting for other player.", SMALL_FONT_SHAPES), 140, "Waiting for other player.", SMALL_FONT_SHAPES); + JE_showVGA(); + fade_palette(colors, 10, 0, 255); + + network_connect(); + + twoPlayerMode = true; + if (thisPlayerNum == 1) + { + fade_black(10); + + if (select_episode() && select_difficulty()) + { + initialDifficulty = difficultyLevel; + + difficultyLevel++; /*Make it one step harder for 2-player mode!*/ + + network_prepare(PACKET_DETAILS); + SDLNet_Write16(episodeNum, &packet_out_temp->data[4]); + SDLNet_Write16(difficultyLevel, &packet_out_temp->data[6]); + network_send(8); // PACKET_DETAILS + } + else + { + network_prepare(PACKET_QUIT); + network_send(4); // PACKET QUIT + + network_tyrian_halt(0, true); + } + } + else + { + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + JE_dString(VGAScreen, JE_fontCenter(networkText[4-1], SMALL_FONT_SHAPES), 140, networkText[4-1], SMALL_FONT_SHAPES); + JE_showVGA(); + + // until opponent sends details packet + while (true) + { + service_SDL_events(false); + JE_showVGA(); + + if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_DETAILS) + break; + + network_update(); + network_check(); + + SDL_Delay(16); + } + + JE_initEpisode(SDLNet_Read16(&packet_in[0]->data[4])); + difficultyLevel = SDLNet_Read16(&packet_in[0]->data[6]); + initialDifficulty = difficultyLevel - 1; + fade_black(10); + + network_update(); + } + + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].cash = 0; + + player[0].items.ship = 11; + + while (!network_is_sync()) + { + service_SDL_events(false); + JE_showVGA(); + + network_check(); + SDL_Delay(16); + } + } + else + { + do + { + defaultBrightness = -3; + + /* Animate instead of quickly fading in */ + if (redraw) + { + play_song(SONG_TITLE); + + menu = 0; + redraw = false; + if (animate) + { + if (fadeIn) + { + fade_black(10); + fadeIn = false; + } + + JE_loadPic(VGAScreen, 4, false); + + draw_font_hv_shadow(VGAScreen, 2, 192, opentyrian_version, small_font, left_aligned, 15, 0, false, 1); + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + + temp = moveTyrianLogoUp ? 62 : 4; + + blit_sprite(VGAScreenSeg, 11, temp, PLANET_SHAPES, 146); // tyrian logo + + JE_showVGA(); + + fade_palette(colors, 10, 0, 255 - 16); + + if (moveTyrianLogoUp) + { + for (temp = 61; temp >= 4; temp -= 2) + { + setjasondelay(2); + + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + blit_sprite(VGAScreenSeg, 11, temp, PLANET_SHAPES, 146); // tyrian logo + + JE_showVGA(); + + service_wait_delay(); + } + moveTyrianLogoUp = false; + } + + strcpy(menuText[4], opentyrian_str); // OpenTyrian override + + /* Draw Menu Text on Screen */ + for (int i = 0; i < menunum; ++i) + { + int x = VGAScreen->w / 2, y = 104 + i * 13; + + draw_font_hv(VGAScreen, x - 1, y - 1, menuText[i], normal_font, centered, 15, -10); + draw_font_hv(VGAScreen, x + 1, y + 1, menuText[i], normal_font, centered, 15, -10); + draw_font_hv(VGAScreen, x + 1, y - 1, menuText[i], normal_font, centered, 15, -10); + draw_font_hv(VGAScreen, x - 1, y + 1, menuText[i], normal_font, centered, 15, -10); + draw_font_hv(VGAScreen, x, y, menuText[i], normal_font, centered, 15, -3); + } + + JE_showVGA(); + + fade_palette(colors, 20, 255 - 16 + 1, 255); // fade in menu items + + memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); + } + } + + memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); + + // highlight selected menu item + draw_font_hv(VGAScreen, VGAScreen->w / 2, 104 + menu * 13, menuText[menu], normal_font, centered, 15, -1); + + JE_showVGA(); + + if (trentWin) + { + quit = true; + goto trentWinsGame; + } + + waitForDemo = 2000; + JE_textMenuWait(&waitForDemo, false); + + if (waitForDemo == 1) + play_demo = true; + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_UP: + if (menu == 0) + menu = menunum-1; + else + menu--; + JE_playSampleNum(S_CURSOR); + break; + case SDLK_DOWN: + if (menu == menunum-1) + menu = 0; + else + menu++; + JE_playSampleNum(S_CURSOR); + break; + default: + break; + } + } + + for (unsigned int i = 0; i < SA_ENGAGE; i++) + { + if (toupper(lastkey_char) == specialName[i][arcade_code_i[i]]) + arcade_code_i[i]++; + else + arcade_code_i[i] = 0; + + if (arcade_code_i[i] > 0 && arcade_code_i[i] == strlen(specialName[i])) + { + if (i+1 == SA_DESTRUCT) + { + loadDestruct = true; + } + else if (i+1 == SA_ENGAGE) + { + /* SuperTyrian */ + + JE_playSampleNum(V_DATA_CUBE); + JE_whoa(); + + initialDifficulty = keysactive[SDLK_SCROLLOCK] ? 6 : 8; + + JE_clr256(VGAScreen); + JE_outText(VGAScreen, 10, 10, "Cheat codes have been disabled.", 15, 4); + if (initialDifficulty == 8) + JE_outText(VGAScreen, 10, 20, "Difficulty level has been set to Lord of Game.", 15, 4); + else + JE_outText(VGAScreen, 10, 20, "Difficulty level has been set to Suicide.", 15, 4); + JE_outText(VGAScreen, 10, 30, "It is imperative that you discover the special codes.", 15, 4); + if (initialDifficulty == 8) + JE_outText(VGAScreen, 10, 40, "(Next time, for an easier challenge hold down SCROLL LOCK.)", 15, 4); + JE_outText(VGAScreen, 10, 60, "Prepare to play...", 15, 4); + + char buf[10+1+15+1]; + snprintf(buf, sizeof(buf), "%s %s", miscTextB[4], pName[0]); + JE_dString(VGAScreen, JE_fontCenter(buf, FONT_SHAPES), 110, buf, FONT_SHAPES); + + play_song(16); + JE_playSampleNum(V_DANGER); + JE_showVGA(); + + wait_noinput(true, true, true); + wait_input(true, true, true); + + JE_initEpisode(1); + constantDie = false; + superTyrian = true; + onePlayerAction = true; + gameLoaded = true; + difficultyLevel = initialDifficulty; + + player[0].cash = 0; + + player[0].items.ship = 13; // The Stalker 21.126 + player[0].items.weapon[FRONT_WEAPON].id = 39; // Atomic RailGun + } + else + { + player[0].items.ship = SAShip[i]; + + fade_black(10); + if (select_episode() && select_difficulty()) + { + /* Start special mode! */ + fade_black(10); + JE_loadPic(VGAScreen, 1, false); + JE_clr256(VGAScreen); + JE_dString(VGAScreen, JE_fontCenter(superShips[0], FONT_SHAPES), 30, superShips[0], FONT_SHAPES); + JE_dString(VGAScreen, JE_fontCenter(superShips[i+1], SMALL_FONT_SHAPES), 100, superShips[i+1], SMALL_FONT_SHAPES); + tempW = ships[player[0].items.ship].shipgraphic; + if (tempW != 1) + blit_sprite2x2(VGAScreen, 148, 70, shapes9, tempW); + + JE_showVGA(); + fade_palette(colors, 50, 0, 255); + + wait_input(true, true, true); + + twoPlayerMode = false; + onePlayerAction = true; + superArcadeMode = i+1; + gameLoaded = true; + initialDifficulty = ++difficultyLevel; + + player[0].cash = 0; + + player[0].items.weapon[FRONT_WEAPON].id = SAWeapon[i][0]; + player[0].items.special = SASpecialWeapon[i]; + if (superArcadeMode == SA_NORTSHIPZ) + { + for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i) + player[0].items.sidekick[i] = 24; // Companion Ship Quicksilver + } + } + else + { + redraw = true; + fadeIn = true; + } + } + newkey = false; + } + } + lastkey_char = '\0'; + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_ESCAPE: + quit = true; + break; + case SDLK_RETURN: + JE_playSampleNum(S_SELECT); + switch (menu) + { + case 0: /* New game */ + fade_black(10); + if (select_gameplay() && select_episode() && select_difficulty()) + { + gameLoaded = true; + + initialDifficulty = difficultyLevel; + + if (onePlayerAction) + { + player[0].cash = 0; + + player[0].items.ship = 8; + } + else if (twoPlayerMode) + { + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].cash = 0; + + player[0].items.ship = 11; + difficultyLevel++; + inputDevice[0] = 1; + inputDevice[1] = 2; + } + else if (richMode) + { + player[0].cash = 1000000; + } + else + { + ulong initial_cash[] = { 10000, 15000, 20000, 30000 }; + + assert(episodeNum >= 1 && episodeNum <= 4); + player[0].cash = initial_cash[episodeNum-1]; + } + } + fadeIn = true; + break; + case 1: /* Load game */ + JE_loadScreen(); + fadeIn = true; + break; + case 2: /* High scores */ + JE_highScoreScreen(); + fadeIn = true; + break; + case 3: /* Instructions */ + JE_helpSystem(1); + fadeIn = true; + break; + case 4: /* Ordering info, now OpenTyrian menu */ + opentyrian_menu(); + fadeIn = true; + break; + case 5: /* Demo */ + play_demo = true; + break; + case 6: /* Quit */ + quit = true; + break; + } + redraw = true; + break; + default: + break; + } + } + } + while (!(quit || gameLoaded || jumpSection || play_demo || loadDestruct)); + +trentWinsGame: + fade_black(15); + } + + return quit; +} + +void intro_logos( void ) +{ + SDL_FillRect(VGAScreen, NULL, 0); + + fade_white(50); + + JE_loadPic(VGAScreen, 10, false); + JE_showVGA(); + + fade_palette(colors, 50, 0, 255); + + setjasondelay(200); + wait_delayorinput(true, true, true); + + fade_black(10); + + JE_loadPic(VGAScreen, 12, false); + JE_showVGA(); + + fade_palette(colors, 10, 0, 255); + + setjasondelay(200); + wait_delayorinput(true, true, true); + + fade_black(10); +} + +void JE_readTextSync( void ) +{ + return; // this function seems to be unnecessary + + JE_clr256(VGAScreen); + JE_showVGA(); + JE_loadPic(VGAScreen, 1, true); + + JE_barShade(VGAScreen, 3, 3, 316, 196); + JE_barShade(VGAScreen, 1, 1, 318, 198); + JE_dString(VGAScreen, 10, 160, "Waiting for other player.", SMALL_FONT_SHAPES); + JE_showVGA(); + + /* TODO: NETWORK */ + + do + { + setjasondelay(2); + + /* TODO: NETWORK */ + + wait_delay(); + + } while (0 /* TODO: NETWORK */); +} + + +void JE_displayText( void ) +{ + /* Display Warning Text */ + tempY = 55; + if (warningRed) + { + tempY = 2; + } + for (temp = 0; temp < levelWarningLines; temp++) + { + if (!ESCPressed) + { + JE_outCharGlow(10, tempY, levelWarningText[temp]); + + if (haltGame) + { + JE_tyrianHalt(5); + } + + tempY += 10; + } + } + if (frameCountMax != 0) + { + frameCountMax = 6; + temp = 1; + } else { + temp = 0; + } + textGlowFont = TINY_FONT; + tempW = 184; + if (warningRed) + { + tempW = 7 * 16 + 6; + } + + JE_outCharGlow(JE_fontCenter(miscText[4], TINY_FONT), tempW, miscText[4]); + + do + { + if (levelWarningDisplay) + { + JE_updateWarning(VGAScreen); + } + + setjasondelay(1); + + NETWORK_KEEP_ALIVE(); + + wait_delay(); + + } while (!(JE_anyButton() || (frameCountMax == 0 && temp == 1) || ESCPressed)); + levelWarningDisplay = false; +} + +void JE_newEnemy( int enemyOffset ) +{ + b = 0; // stupid global + + for (int i = enemyOffset; i < enemyOffset + 25; i++) + { + if (enemyAvail[i] == 1) + { + b = i+1; + enemyAvail[b-1] = JE_makeEnemy(&enemy[b-1]); + break; + } + } +} + +uint JE_makeEnemy( struct JE_SingleEnemyType *enemy ) // tempW, uniqueEnemy, tempI2, b +{ + uint a; + + JE_byte temp; + int t = 0; + + if (superArcadeMode != SA_NONE && tempW == 534) + tempW = 533; + + enemyShapeTables[5-1] = 21; /*Coins&Gems*/ + enemyShapeTables[6-1] = 26; /*Two-Player Stuff*/ + + if (uniqueEnemy) + { + temp = tempI2; + uniqueEnemy = false; + } + else + { + temp = enemyDat[tempW].shapebank; + } + + for (uint i = 0; i < 6; ++i) + { + if (temp == enemyShapeTables[i]) + { + switch (i) + { + case 0: + enemy->sprite2s = &eShapes1; + break; + case 1: + enemy->sprite2s = &eShapes2; + break; + case 2: + enemy->sprite2s = &eShapes3; + break; + case 3: + enemy->sprite2s = &eShapes4; + break; + case 4: + enemy->sprite2s = &eShapes5; + break; + case 5: + enemy->sprite2s = &eShapes6; + break; + } + } + } + + enemy->enemydatofs = &enemyDat[tempW]; + + enemy->mapoffset = 0; + + for (uint i = 0; i < 3; ++i) + { + enemy->eshotmultipos[i] = 0; + } + + temp4 = enemyDat[tempW].explosiontype; + enemy->enemyground = ((temp4 & 0x01) == 0); + enemy->explonum = temp4 / 2; + + enemy->launchfreq = enemyDat[tempW].elaunchfreq; + enemy->launchwait = enemyDat[tempW].elaunchfreq; + enemy->launchtype = enemyDat[tempW].elaunchtype % 1000; + enemy->launchspecial = enemyDat[tempW].elaunchtype / 1000; + + enemy->xaccel = enemyDat[tempW].xaccel; + enemy->yaccel = enemyDat[tempW].yaccel; + + enemy->xminbounce = -10000; + enemy->xmaxbounce = 10000; + enemy->yminbounce = -10000; + enemy->ymaxbounce = 10000; + /*Far enough away to be impossible to reach*/ + + for (uint i = 0; i < 3; ++i) + { + enemy->tur[i] = enemyDat[tempW].tur[i]; + } + + enemy->ani = enemyDat[tempW].ani; + enemy->animin = 1; + + switch (enemyDat[tempW].animate) + { + case 0: + enemy->enemycycle = 1; + enemy->aniactive = 0; + enemy->animax = 0; + enemy->aniwhenfire = 0; + break; + case 1: + enemy->enemycycle = 0; + enemy->aniactive = 1; + enemy->animax = 0; + enemy->aniwhenfire = 0; + break; + case 2: + enemy->enemycycle = 1; + enemy->aniactive = 2; + enemy->animax = enemy->ani; + enemy->aniwhenfire = 2; + break; + } + + if (enemyDat[tempW].startxc != 0) + enemy->ex = enemyDat[tempW].startx + (mt_rand() % (enemyDat[tempW].startxc * 2)) - enemyDat[tempW].startxc + 1; + else + enemy->ex = enemyDat[tempW].startx + 1; + + if (enemyDat[tempW].startyc != 0) + enemy->ey = enemyDat[tempW].starty + (mt_rand() % (enemyDat[tempW].startyc * 2)) - enemyDat[tempW].startyc + 1; + else + enemy->ey = enemyDat[tempW].starty + 1; + + enemy->exc = enemyDat[tempW].xmove; + enemy->eyc = enemyDat[tempW].ymove; + enemy->excc = enemyDat[tempW].xcaccel; + enemy->eycc = enemyDat[tempW].ycaccel; + enemy->exccw = abs(enemy->excc); + enemy->exccwmax = enemy->exccw; + enemy->eyccw = abs(enemy->eycc); + enemy->eyccwmax = enemy->eyccw; + enemy->exccadd = (enemy->excc > 0) ? 1 : -1; + enemy->eyccadd = (enemy->eycc > 0) ? 1 : -1; + enemy->special = false; + enemy->iced = 0; + + if (enemyDat[tempW].xrev == 0) + enemy->exrev = 100; + else if (enemyDat[tempW].xrev == -99) + enemy->exrev = 0; + else + enemy->exrev = enemyDat[tempW].xrev; + + if (enemyDat[tempW].yrev == 0) + enemy->eyrev = 100; + else if (enemyDat[tempW].yrev == -99) + enemy->eyrev = 0; + else + enemy->eyrev = enemyDat[tempW].yrev; + + enemy->exca = (enemy->xaccel > 0) ? 1 : -1; + enemy->eyca = (enemy->yaccel > 0) ? 1 : -1; + + enemy->enemytype = tempW; + + for (uint i = 0; i < 3; ++i) + { + if (enemy->tur[i] == 252) + enemy->eshotwait[i] = 1; + else if (enemy->tur[i] > 0) + enemy->eshotwait[i] = 20; + else + enemy->eshotwait[i] = 255; + } + for (uint i = 0; i < 20; ++i) + enemy->egr[i] = enemyDat[tempW].egraphic[i]; + enemy->size = enemyDat[tempW].esize; + enemy->linknum = 0; + enemy->edamaged = enemyDat[tempW].dani < 0; + enemy->enemydie = enemyDat[tempW].eenemydie; + + enemy->freq[1-1] = enemyDat[tempW].freq[1-1]; + enemy->freq[2-1] = enemyDat[tempW].freq[2-1]; + enemy->freq[3-1] = enemyDat[tempW].freq[3-1]; + + enemy->edani = enemyDat[tempW].dani; + enemy->edgr = enemyDat[tempW].dgr; + enemy->edlevel = enemyDat[tempW].dlevel; + + enemy->fixedmovey = 0; + + enemy->filter = 0x00; + + if (enemyDat[tempW].value > 1 && enemyDat[tempW].value < 10000) + { + switch (difficultyLevel) + { + case -1: + case 0: + t = enemyDat[tempW].value * 0.75f; + break; + case 1: + case 2: + t = enemyDat[tempW].value; + break; + case 3: + t = enemyDat[tempW].value * 1.125f; + break; + case 4: + t = enemyDat[tempW].value * 1.5f; + break; + case 5: + t = enemyDat[tempW].value * 2; + break; + case 6: + t = enemyDat[tempW].value * 2.5f; + break; + case 7: + case 8: + t = enemyDat[tempW].value * 4; + break; + case 9: + case 10: + t = enemyDat[tempW].value * 8; + break; + } + if (t > 10000) + t = 10000; + enemy->evalue = t; + } + else + { + enemy->evalue = enemyDat[tempW].value; + } + + t = 1; + if (enemyDat[tempW].armor > 0) + { + if (enemyDat[tempW].armor != 255) + { + switch (difficultyLevel) + { + case -1: + case 0: + t = enemyDat[tempW].armor * 0.5f + 1; + break; + case 1: + t = enemyDat[tempW].armor * 0.75f + 1; + break; + case 2: + t = enemyDat[tempW].armor; + break; + case 3: + t = enemyDat[tempW].armor * 1.2f; + break; + case 4: + t = enemyDat[tempW].armor * 1.5f; + break; + case 5: + t = enemyDat[tempW].armor * 1.8f; + break; + case 6: + t = enemyDat[tempW].armor * 2; + break; + case 7: + t = enemyDat[tempW].armor * 3; + break; + case 8: + t = enemyDat[tempW].armor * 4; + break; + case 9: + case 10: + t = enemyDat[tempW].armor * 8; + break; + } + + if (t > 254) + { + t = 254; + } + } + else + { + t = 255; + } + + enemy->armorleft = t; + + a = 0; + enemy->scoreitem = false; + } + else + { + a = 2; + enemy->armorleft = 255; + if (enemy->evalue != 0) + enemy->scoreitem = true; + } + + if (!enemy->scoreitem) + { + totalEnemy++; /*Destruction ratio*/ + } + + /*The returning A value indicates what to set ENEMYAVAIL to */ + return a; +} + +void JE_createNewEventEnemy( JE_byte enemyTypeOfs, JE_word enemyOffset ) +{ + int i; + + b = 0; + + for(i = enemyOffset; i < enemyOffset + 25; i++) + { + if (enemyAvail[i] == 1) + { + b = i + 1; + break; + } + } + + if (b == 0) + { + return; + } + + tempW = eventRec[eventLoc-1].eventdat + enemyTypeOfs; + + enemyAvail[b-1] = JE_makeEnemy(&enemy[b-1]); + + if (eventRec[eventLoc-1].eventdat2 != -99) + { + switch (enemyOffset) + { + case 0: + enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24; + enemy[b-1].ey -= backMove2; + break; + case 25: + case 75: + enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24 - 12; + enemy[b-1].ey -= backMove; + break; + case 50: + if (background3x1) + { + enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24 - 12; + } else { + enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - mapX3 * 24 - 24 * 2 + 6; + } + enemy[b-1].ey -= backMove3; + + if (background3x1b) + { + enemy[b-1].ex -= 6; + } + break; + } + enemy[b-1].ey = -28; + if (background3x1b && enemyOffset == 50) + { + enemy[b-1].ey += 4; + } + } + + if (smallEnemyAdjust && enemy[b-1].size == 0) + { + enemy[b-1].ex -= 10; + enemy[b-1].ey -= 7; + } + + enemy[b-1].ey += eventRec[eventLoc-1].eventdat5; + enemy[b-1].eyc += eventRec[eventLoc-1].eventdat3; + enemy[b-1].linknum = eventRec[eventLoc-1].eventdat4; + enemy[b-1].fixedmovey = eventRec[eventLoc-1].eventdat6; +} + +void JE_eventJump( JE_word jump ) +{ + JE_word tempW; + + if (jump == 65535) + { + curLoc = returnLoc; + } + else + { + returnLoc = curLoc + 1; + curLoc = jump; + } + tempW = 0; + do + { + tempW++; + } + while (!(eventRec[tempW-1].eventtime >= curLoc)); + eventLoc = tempW - 1; +} + +JE_boolean JE_searchFor/*enemy*/( JE_byte PLType ) +{ + JE_boolean tempb = false; + JE_byte temp; + + for (temp = 0; temp < 100; temp++) + { + if (enemyAvail[temp] == 0 && enemy[temp].linknum == PLType) + { + temp5 = temp + 1; + if (galagaMode) + { + enemy[temp].evalue += enemy[temp].evalue; + } + tempb = true; + } + } + return tempb; +} + +void JE_eventSystem( void ) +{ + switch (eventRec[eventLoc-1].eventtype) + { + case 1: + starY = eventRec[eventLoc-1].eventdat * VGAScreen->pitch; + break; + + case 2: + map1YDelay = 1; + map1YDelayMax = 1; + map2YDelay = 1; + map2YDelayMax = 1; + + backMove = eventRec[eventLoc-1].eventdat; + backMove2 = eventRec[eventLoc-1].eventdat2; + + if (backMove2 > 0) + explodeMove = backMove2; + else + explodeMove = backMove; + + backMove3 = eventRec[eventLoc-1].eventdat3; + + if (backMove > 0) + stopBackgroundNum = 0; + break; + + case 3: + backMove = 1; + map1YDelay = 3; + map1YDelayMax = 3; + backMove2 = 1; + map2YDelay = 2; + map2YDelayMax = 2; + backMove3 = 1; + break; + + case 4: + stopBackgrounds = true; + switch (eventRec[eventLoc-1].eventdat) + { + case 0: + case 1: + stopBackgroundNum = 1; + break; + case 2: + stopBackgroundNum = 2; + break; + case 3: + stopBackgroundNum = 3; + break; + } + break; + + case 5: + if (enemyShapeTables[1-1] != eventRec[eventLoc-1].eventdat) + { + if (eventRec[eventLoc-1].eventdat > 0) + { + JE_loadCompShapes(&eShapes1, shapeFile[eventRec[eventLoc-1].eventdat -1]); /* Enemy Bank 1 */ + enemyShapeTables[1-1] = eventRec[eventLoc-1].eventdat; + } + else + { + free_sprite2s(&eShapes1); + enemyShapeTables[1-1] = 0; + } + } + if (enemyShapeTables[2-1] != eventRec[eventLoc-1].eventdat2) + { + if (eventRec[eventLoc-1].eventdat2 > 0) + { + JE_loadCompShapes(&eShapes2, shapeFile[eventRec[eventLoc-1].eventdat2-1]); /* Enemy Bank 2 */ + enemyShapeTables[2-1] = eventRec[eventLoc-1].eventdat2; + } + else + { + free_sprite2s(&eShapes2); + enemyShapeTables[2-1] = 0; + } + } + if (enemyShapeTables[3-1] != (unsigned char)eventRec[eventLoc-1].eventdat3) + { + if (eventRec[eventLoc-1].eventdat3 > 0) + { + JE_loadCompShapes(&eShapes3, shapeFile[eventRec[eventLoc-1].eventdat3-1]); /* Enemy Bank 3 */ + enemyShapeTables[3-1] = eventRec[eventLoc-1].eventdat3; + } + else + { + free_sprite2s(&eShapes3); + enemyShapeTables[3-1] = 0; + } + } + if (enemyShapeTables[4-1] != eventRec[eventLoc-1].eventdat4) + { + if (eventRec[eventLoc-1].eventdat4 > 0) + { + JE_loadCompShapes(&eShapes4, shapeFile[eventRec[eventLoc-1].eventdat4-1]); /* Enemy Bank 4 */ + enemyShapeTables[4-1] = eventRec[eventLoc-1].eventdat4; + enemyShapeTables[5-1] = 21; + } + else + { + free_sprite2s(&eShapes4); + enemyShapeTables[4-1] = 0; + } + } + break; + + case 6: /* Ground Enemy */ + JE_createNewEventEnemy(0, 25); + break; + + case 7: /* Top Enemy */ + JE_createNewEventEnemy(0, 50); + break; + + case 8: + starActive = false; + break; + + case 9: + starActive = true; + break; + + case 10: /* Ground Enemy 2 */ + JE_createNewEventEnemy(0, 75); + break; + + case 11: + if (allPlayersGone || eventRec[eventLoc-1].eventdat == 1) + reallyEndLevel = true; + else + if (!endLevel) + { + readyToEndLevel = false; + endLevel = true; + levelEnd = 40; + } + break; + + case 12: /* Custom 4x4 Ground Enemy */ + { + uint temp = 0; + switch (eventRec[eventLoc-1].eventdat6) + { + case 0: + case 1: + temp = 25; + break; + case 2: + temp = 0; + break; + case 3: + temp = 50; + break; + case 4: + temp = 75; + break; + } + eventRec[eventLoc-1].eventdat6 = 0; /* We use EVENTDAT6 for the background */ + JE_createNewEventEnemy(0, temp); + JE_createNewEventEnemy(1, temp); + enemy[b-1].ex += 24; + JE_createNewEventEnemy(2, temp); + enemy[b-1].ey -= 28; + JE_createNewEventEnemy(3, temp); + enemy[b-1].ex += 24; + enemy[b-1].ey -= 28; + break; + } + case 13: + enemiesActive = false; + break; + + case 14: + enemiesActive = true; + break; + + case 15: /* Sky Enemy */ + JE_createNewEventEnemy(0, 0); + break; + + case 16: + if (eventRec[eventLoc-1].eventdat > 9) + { + fprintf(stderr, "warning: event 16: bad event data\n"); + } + else + { + JE_drawTextWindow(outputs[eventRec[eventLoc-1].eventdat-1]); + soundQueue[3] = windowTextSamples[eventRec[eventLoc-1].eventdat-1]; + } + break; + + case 17: /* Ground Bottom */ + JE_createNewEventEnemy(0, 25); + if (b > 0) + { + enemy[b-1].ey = 190 + eventRec[eventLoc-1].eventdat5; + } + break; + + case 18: /* Sky Enemy on Bottom */ + JE_createNewEventEnemy(0, 0); + if (b > 0) + { + enemy[b-1].ey = 190 + eventRec[eventLoc-1].eventdat5; + } + break; + + case 19: /* Enemy Global Move */ + if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90) + { + temp2 = 1; + temp3 = 100; + temp4 = 0; + eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80]; + } + else + { + switch (eventRec[eventLoc-1].eventdat3) + { + case 0: + temp2 = 1; + temp3 = 100; + temp4 = 0; + break; + case 2: + temp2 = 1; + temp3 = 25; + temp4 = 1; + break; + case 1: + temp2 = 26; + temp3 = 50; + temp4 = 1; + break; + case 3: + temp2 = 51; + temp3 = 75; + temp4 = 1; + break; + case 99: + temp2 = 1; + temp3 = 100; + temp4 = 1; + break; + } + } + + for (temp = temp2-1; temp < temp3; temp++) + { + if (temp4 == 1 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + if (eventRec[eventLoc-1].eventdat != -99) + enemy[temp].exc = eventRec[eventLoc-1].eventdat; + + if (eventRec[eventLoc-1].eventdat2 != -99) + enemy[temp].eyc = eventRec[eventLoc-1].eventdat2; + + if (eventRec[eventLoc-1].eventdat6 != 0) + enemy[temp].fixedmovey = eventRec[eventLoc-1].eventdat6; + + if (eventRec[eventLoc-1].eventdat6 == -99) + enemy[temp].fixedmovey = 0; + + if (eventRec[eventLoc-1].eventdat5 > 0) + enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat5; + } + } + break; + + case 20: /* Enemy Global Accel */ + if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90) + eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80]; + + for (temp = 0; temp < 100; temp++) + { + if (enemyAvail[temp] != 1 + && (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4 || eventRec[eventLoc-1].eventdat4 == 0)) + { + if (eventRec[eventLoc-1].eventdat != -99) + { + enemy[temp].excc = eventRec[eventLoc-1].eventdat; + enemy[temp].exccw = abs(eventRec[eventLoc-1].eventdat); + enemy[temp].exccwmax = abs(eventRec[eventLoc-1].eventdat); + if (eventRec[eventLoc-1].eventdat > 0) + enemy[temp].exccadd = 1; + else + enemy[temp].exccadd = -1; + } + + if (eventRec[eventLoc-1].eventdat2 != -99) + { + enemy[temp].eycc = eventRec[eventLoc-1].eventdat2; + enemy[temp].eyccw = abs(eventRec[eventLoc-1].eventdat2); + enemy[temp].eyccwmax = abs(eventRec[eventLoc-1].eventdat2); + if (eventRec[eventLoc-1].eventdat2 > 0) + enemy[temp].eyccadd = 1; + else + enemy[temp].eyccadd = -1; + } + + if (eventRec[eventLoc-1].eventdat5 > 0) + { + enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat5; + } + if (eventRec[eventLoc-1].eventdat6 > 0) + { + enemy[temp].ani = eventRec[eventLoc-1].eventdat6; + enemy[temp].animin = eventRec[eventLoc-1].eventdat5; + enemy[temp].animax = 0; + enemy[temp].aniactive = 1; + } + } + } + break; + + case 21: + background3over = 1; + break; + + case 22: + background3over = 0; + break; + + case 23: /* Sky Enemy on Bottom */ + JE_createNewEventEnemy(0, 50); + if (b > 0) + enemy[b-1].ey = 180 + eventRec[eventLoc-1].eventdat5; + break; + + case 24: /* Enemy Global Animate */ + for (temp = 0; temp < 100; temp++) + { + if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + enemy[temp].aniactive = 1; + enemy[temp].aniwhenfire = 0; + if (eventRec[eventLoc-1].eventdat2 > 0) + { + enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat2; + enemy[temp].animin = enemy[temp].enemycycle; + } + else + { + enemy[temp].enemycycle = 0; + } + + if (eventRec[eventLoc-1].eventdat > 0) + enemy[temp].ani = eventRec[eventLoc-1].eventdat; + + if (eventRec[eventLoc-1].eventdat3 == 1) + { + enemy[temp].animax = enemy[temp].ani; + } + else if (eventRec[eventLoc-1].eventdat3 == 2) + { + enemy[temp].aniactive = 2; + enemy[temp].animax = enemy[temp].ani; + enemy[temp].aniwhenfire = 2; + } + } + } + break; + + case 25: /* Enemy Global Damage change */ + for (temp = 0; temp < 100; temp++) + { + if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + if (galagaMode) + enemy[temp].armorleft = roundf(eventRec[eventLoc-1].eventdat * (difficultyLevel / 2)); + else + enemy[temp].armorleft = eventRec[eventLoc-1].eventdat; + } + } + break; + + case 26: + smallEnemyAdjust = eventRec[eventLoc-1].eventdat; + break; + + case 27: /* Enemy Global AccelRev */ + if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90) + eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80]; + + for (temp = 0; temp < 100; temp++) + { + if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + if (eventRec[eventLoc-1].eventdat != -99) + enemy[temp].exrev = eventRec[eventLoc-1].eventdat; + if (eventRec[eventLoc-1].eventdat2 != -99) + enemy[temp].eyrev = eventRec[eventLoc-1].eventdat2; + if (eventRec[eventLoc-1].eventdat3 != 0 && eventRec[eventLoc-1].eventdat3 < 17) + enemy[temp].filter = eventRec[eventLoc-1].eventdat3; + } + } + break; + + case 28: + topEnemyOver = false; + break; + + case 29: + topEnemyOver = true; + break; + + case 30: + map1YDelay = 1; + map1YDelayMax = 1; + map2YDelay = 1; + map2YDelayMax = 1; + + backMove = eventRec[eventLoc-1].eventdat; + backMove2 = eventRec[eventLoc-1].eventdat2; + explodeMove = backMove2; + backMove3 = eventRec[eventLoc-1].eventdat3; + break; + + case 31: /* Enemy Fire Override */ + for (temp = 0; temp < 100; temp++) + { + if (eventRec[eventLoc-1].eventdat4 == 99 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + enemy[temp].freq[1-1] = eventRec[eventLoc-1].eventdat ; + enemy[temp].freq[2-1] = eventRec[eventLoc-1].eventdat2; + enemy[temp].freq[3-1] = eventRec[eventLoc-1].eventdat3; + for (temp2 = 0; temp2 < 3; temp2++) + { + enemy[temp].eshotwait[temp2] = 1; + } + if (enemy[temp].launchtype > 0) + { + enemy[temp].launchfreq = eventRec[eventLoc-1].eventdat5; + enemy[temp].launchwait = 1; + } + } + } + break; + + case 32: // create enemy + JE_createNewEventEnemy(0, 50); + if (b > 0) + enemy[b-1].ey = 190; + break; + + case 33: /* Enemy From other Enemies */ + if (!((eventRec[eventLoc-1].eventdat == 512 || eventRec[eventLoc-1].eventdat == 513) && (twoPlayerMode || onePlayerAction || superTyrian))) + { + if (superArcadeMode != SA_NONE) + { + if (eventRec[eventLoc-1].eventdat == 534) + eventRec[eventLoc-1].eventdat = 827; + } + else if (!superTyrian) + { + const uint lives = *player[0].lives; + + if (eventRec[eventLoc-1].eventdat == 533 && (lives == 11 || (mt_rand() % 15) < lives)) + { + // enemy will drop random special weapon + eventRec[eventLoc-1].eventdat = 829 + (mt_rand() % 6); + } + } + if (eventRec[eventLoc-1].eventdat == 534 && superTyrian) + eventRec[eventLoc-1].eventdat = 828 + superTyrianSpecials[mt_rand() % 4]; + + for (temp = 0; temp < 100; temp++) + { + if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + enemy[temp].enemydie = eventRec[eventLoc-1].eventdat; + } + } + break; + + case 34: /* Start Music Fade */ + if (firstGameOver) + { + musicFade = true; + tempVolume = tyrMusicVolume; + } + break; + + case 35: /* Play new song */ + if (firstGameOver) + { + play_song(eventRec[eventLoc-1].eventdat - 1); + set_volume(tyrMusicVolume, fxVolume); + } + musicFade = false; + break; + + case 36: + readyToEndLevel = true; + break; + + case 37: + levelEnemyFrequency = eventRec[eventLoc-1].eventdat; + break; + + case 38: + curLoc = eventRec[eventLoc-1].eventdat; + tempW2 = 1; + for (tempW = 0; tempW < maxEvent; tempW++) + { + if (eventRec[tempW].eventtime <= curLoc) + { + tempW2 = tempW+1 - 1; + } + } + eventLoc = tempW2; + break; + + case 39: /* Enemy Global Linknum Change */ + for (temp = 0; temp < 100; temp++) + { + if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat) + enemy[temp].linknum = eventRec[eventLoc-1].eventdat2; + } + break; + + case 40: /* Enemy Continual Damage */ + enemyContinualDamage = true; + break; + + case 41: + if (eventRec[eventLoc-1].eventdat == 0) + { + memset(enemyAvail, 1, sizeof(enemyAvail)); + } + else + { + for (x = 0; x <= 24; x++) + enemyAvail[x] = 1; + } + break; + + case 42: + background3over = 2; + break; + + case 43: + background2over = eventRec[eventLoc-1].eventdat; + break; + + case 44: + filterActive = (eventRec[eventLoc-1].eventdat > 0); + filterFade = (eventRec[eventLoc-1].eventdat == 2); + levelFilter = eventRec[eventLoc-1].eventdat2; + levelBrightness = eventRec[eventLoc-1].eventdat3; + levelFilterNew = eventRec[eventLoc-1].eventdat4; + levelBrightnessChg = eventRec[eventLoc-1].eventdat5; + filterFadeStart = (eventRec[eventLoc-1].eventdat6 == 0); + break; + + case 45: /* arcade-only enemy from other enemies */ + if (!superTyrian) + { + const uint lives = *player[0].lives; + + if (eventRec[eventLoc-1].eventdat == 533 && (lives == 11 || (mt_rand() % 15) < lives)) + { + eventRec[eventLoc-1].eventdat = 829 + (mt_rand() % 6); + } + if (twoPlayerMode || onePlayerAction) + { + for (temp = 0; temp < 100; temp++) + { + if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + enemy[temp].enemydie = eventRec[eventLoc-1].eventdat; + } + } + } + break; + + case 46: // change difficulty + if (eventRec[eventLoc-1].eventdat3 != 0) + damageRate = eventRec[eventLoc-1].eventdat3; + + if (eventRec[eventLoc-1].eventdat2 == 0 || twoPlayerMode || onePlayerAction) + { + difficultyLevel += eventRec[eventLoc-1].eventdat; + if (difficultyLevel < 1) + difficultyLevel = 1; + if (difficultyLevel > 10) + difficultyLevel = 10; + } + break; + + case 47: /* Enemy Global AccelRev */ + for (temp = 0; temp < 100; temp++) + { + if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + enemy[temp].armorleft = eventRec[eventLoc-1].eventdat; + } + break; + + case 48: /* Background 2 Cannot be Transparent */ + background2notTransparent = true; + break; + + case 49: + case 50: + case 51: + case 52: + tempDat2 = eventRec[eventLoc-1].eventdat; + eventRec[eventLoc-1].eventdat = 0; + tempDat = eventRec[eventLoc-1].eventdat3; + eventRec[eventLoc-1].eventdat3 = 0; + tempDat3 = eventRec[eventLoc-1].eventdat6; + eventRec[eventLoc-1].eventdat6 = 0; + tempI2 = tempDat; + enemyDat[0].armor = tempDat3; + enemyDat[0].egraphic[1-1] = tempDat2; + switch (eventRec[eventLoc-1].eventtype - 48) + { + case 1: + temp = 25; + break; + case 2: + temp = 0; + break; + case 3: + temp = 50; + break; + case 4: + temp = 75; + break; + } + uniqueEnemy = true; + JE_createNewEventEnemy(0, temp); + uniqueEnemy = false; + eventRec[eventLoc-1].eventdat = tempDat2; + eventRec[eventLoc-1].eventdat3 = tempDat; + eventRec[eventLoc-1].eventdat6 = tempDat3; + break; + + case 53: + forceEvents = (eventRec[eventLoc-1].eventdat != 99); + break; + + case 54: + JE_eventJump(eventRec[eventLoc-1].eventdat); + break; + + case 55: /* Enemy Global AccelRev */ + if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90) + eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80]; + + for (temp = 0; temp < 100; temp++) + { + if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + if (eventRec[eventLoc-1].eventdat != -99) + enemy[temp].xaccel = eventRec[eventLoc-1].eventdat; + if (eventRec[eventLoc-1].eventdat2 != -99) + enemy[temp].yaccel = eventRec[eventLoc-1].eventdat2; + } + } + break; + + case 56: /* Ground2 Bottom */ + JE_createNewEventEnemy(0, 75); + if (b > 0) + enemy[b-1].ey = 190; + break; + + case 57: + superEnemy254Jump = eventRec[eventLoc-1].eventdat; + break; + + case 60: /*Assign Special Enemy*/ + for (temp = 0; temp < 100; temp++) + { + if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + enemy[temp].special = true; + enemy[temp].flagnum = eventRec[eventLoc-1].eventdat; + enemy[temp].setto = (eventRec[eventLoc-1].eventdat2 == 1); + } + } + break; + + case 61: // if specific flag set to specific value, skip events + if (globalFlags[eventRec[eventLoc-1].eventdat] == eventRec[eventLoc-1].eventdat2) + eventLoc += eventRec[eventLoc-1].eventdat3; + break; + + case 62: /*Play sound effect*/ + soundQueue[3] = eventRec[eventLoc-1].eventdat; + break; + + case 63: // skip events if not in 2-player mode + if (!twoPlayerMode && !onePlayerAction) + eventLoc += eventRec[eventLoc-1].eventdat; + break; + + case 64: + if (!(eventRec[eventLoc-1].eventdat == 6 && twoPlayerMode && difficultyLevel > 2)) + { + smoothies[eventRec[eventLoc-1].eventdat-1] = eventRec[eventLoc-1].eventdat2; + temp = eventRec[eventLoc-1].eventdat; + if (temp == 5) + temp = 3; + smoothie_data[temp-1] = eventRec[eventLoc-1].eventdat3; + } + break; + + case 65: + background3x1 = (eventRec[eventLoc-1].eventdat == 0); + break; + + case 66: /*If not on this difficulty level or higher then...*/ + if (initialDifficulty <= eventRec[eventLoc-1].eventdat) + eventLoc += eventRec[eventLoc-1].eventdat2; + break; + + case 67: + levelTimer = (eventRec[eventLoc-1].eventdat == 1); + levelTimerCountdown = eventRec[eventLoc-1].eventdat3 * 100; + levelTimerJumpTo = eventRec[eventLoc-1].eventdat2; + break; + + case 68: + randomExplosions = (eventRec[eventLoc-1].eventdat == 1); + break; + + case 69: + for (uint i = 0; i < COUNTOF(player); ++i) + player[i].invulnerable_ticks = eventRec[eventLoc-1].eventdat; + break; + + case 70: + if (eventRec[eventLoc-1].eventdat2 == 0) + { /*1-10*/ + bool found = false; + + for (temp = 1; temp <= 19; temp++) + found |= JE_searchFor(temp); + + if (!found) + JE_eventJump(eventRec[eventLoc-1].eventdat); + } + else if (!JE_searchFor(eventRec[eventLoc-1].eventdat2) + && (eventRec[eventLoc-1].eventdat3 == 0 || !JE_searchFor(eventRec[eventLoc-1].eventdat3)) + && (eventRec[eventLoc-1].eventdat4 == 0 || !JE_searchFor(eventRec[eventLoc-1].eventdat4))) + { + JE_eventJump(eventRec[eventLoc-1].eventdat); + } + break; + + case 71: + if (((((intptr_t)mapYPos - (intptr_t)&megaData1.mainmap) / sizeof(JE_byte *)) * 2) <= (unsigned)eventRec[eventLoc-1].eventdat2) + { + JE_eventJump(eventRec[eventLoc-1].eventdat); + } + break; + + case 72: + background3x1b = (eventRec[eventLoc-1].eventdat == 1); + break; + + case 73: + skyEnemyOverAll = (eventRec[eventLoc-1].eventdat == 1); + break; + + case 74: /* Enemy Global BounceParams */ + for (temp = 0; temp < 100; temp++) + { + if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4) + { + if (eventRec[eventLoc-1].eventdat5 != -99) + enemy[temp].xminbounce = eventRec[eventLoc-1].eventdat5; + + if (eventRec[eventLoc-1].eventdat6 != -99) + enemy[temp].yminbounce = eventRec[eventLoc-1].eventdat6; + + if (eventRec[eventLoc-1].eventdat != -99) + enemy[temp].xmaxbounce = eventRec[eventLoc-1].eventdat; + + if (eventRec[eventLoc-1].eventdat2 != -99) + enemy[temp].ymaxbounce = eventRec[eventLoc-1].eventdat2; + } + } + break; + + case 75: + { + bool temp_no_clue = false; // TODO: figure out what this is doing + + for (temp = 0; temp < 100; temp++) + { + if (enemyAvail[temp] == 0 + && enemy[temp].eyc == 0 + && enemy[temp].linknum >= eventRec[eventLoc-1].eventdat + && enemy[temp].linknum <= eventRec[eventLoc-1].eventdat2) + { + temp_no_clue = true; + } + } + + if (temp_no_clue) + { + do + { + temp = (mt_rand() % (eventRec[eventLoc-1].eventdat2 + 1 - eventRec[eventLoc-1].eventdat)) + eventRec[eventLoc-1].eventdat; + } + while (!(JE_searchFor(temp) && enemy[temp5-1].eyc == 0)); + + newPL[eventRec[eventLoc-1].eventdat3 - 80] = temp; + } + else + { + newPL[eventRec[eventLoc-1].eventdat3 - 80] = 255; + if (eventRec[eventLoc-1].eventdat4 > 0) + { /*Skip*/ + curLoc = eventRec[eventLoc-1 + eventRec[eventLoc-1].eventdat4].eventtime - 1; + eventLoc += eventRec[eventLoc-1].eventdat4 - 1; + } + } + } + break; + + case 76: + returnActive = true; + break; + + case 77: + mapYPos = &megaData1.mainmap[0][0]; + mapYPos += eventRec[eventLoc-1].eventdat / 2; + if (eventRec[eventLoc-1].eventdat2 > 0) + { + mapY2Pos = &megaData2.mainmap[0][0]; + mapY2Pos += eventRec[eventLoc-1].eventdat2 / 2; + } + else + { + mapY2Pos = &megaData2.mainmap[0][0]; + mapY2Pos += eventRec[eventLoc-1].eventdat / 2; + } + break; + + case 78: + if (galagaShotFreq < 10) + galagaShotFreq++; + break; + + case 79: + boss_bar[0].link_num = eventRec[eventLoc-1].eventdat; + boss_bar[1].link_num = eventRec[eventLoc-1].eventdat2; + break; + + case 80: // skip events if in 2-player mode + if (twoPlayerMode) + eventLoc += eventRec[eventLoc-1].eventdat; + break; + + case 81: /*WRAP2*/ + BKwrap2 = &megaData2.mainmap[0][0]; + BKwrap2 += eventRec[eventLoc-1].eventdat / 2; + BKwrap2to = &megaData2.mainmap[0][0]; + BKwrap2to += eventRec[eventLoc-1].eventdat2 / 2; + break; + + case 82: /*Give SPECIAL WEAPON*/ + player[0].items.special = eventRec[eventLoc-1].eventdat; + shotMultiPos[SHOT_SPECIAL] = 0; + shotRepeat[SHOT_SPECIAL] = 0; + shotMultiPos[SHOT_SPECIAL2] = 0; + shotRepeat[SHOT_SPECIAL2] = 0; + break; + + default: + fprintf(stderr, "warning: event %d: unhandled event\n", eventRec[eventLoc-1].eventtype); + break; + } + + eventLoc++; +} + +void JE_whoa( void ) +{ + unsigned int i, j, color, offset, timer; + unsigned int screenSize, topBorder, bottomBorder; + Uint8 * TempScreen1, * TempScreen2, * TempScreenSwap; + + /* 'whoa' gets us that nifty screen fade used when you type in + * 'engage'. We need two temporary screen buffers (char arrays can + * work too, but these screens already exist) for our effect. + * This could probably be a lot more efficient (there's probably a + * way to get vgascreen as one of the temp buffers), but it's only called + * once so don't worry about it. */ + + TempScreen1 = (Uint8 *)game_screen->pixels; + TempScreen2 = (Uint8 *)VGAScreen2->pixels; + + screenSize = VGAScreenSeg->h * VGAScreenSeg->pitch; + topBorder = VGAScreenSeg->pitch * 4; /* Seems an arbitrary number of lines */ + bottomBorder = VGAScreenSeg->pitch * 7; + + /* Okay, one disadvantage to using other screens as temp buffers: they + * need to be the right size. I doubt they'l ever be anything but 320x200, + * but just in case, these asserts will clue in whoever stumbles across + * the problem. You can fix it with the stack or malloc. */ + assert( (unsigned)VGAScreen2->h * VGAScreen2->pitch >= screenSize + && (unsigned)game_screen->h * game_screen->pitch >= screenSize); + + + /* Clear the top and bottom borders. We don't want to process + * them and we don't want to draw them. */ + memset((Uint8 *)VGAScreenSeg->pixels, 0, topBorder); + memset((Uint8 *)VGAScreenSeg->pixels + screenSize - bottomBorder, 0, bottomBorder); + + /* Copy our test subject to one of the temporary buffers. Blank the other */ + memset(TempScreen1, 0, screenSize); + memcpy(TempScreen2, VGAScreenSeg->pixels, VGAScreenSeg->h * VGAScreenSeg->pitch); + + + service_SDL_events(true); + timer = 300; /* About 300 rounds is enough to make the screen mostly black */ + + do + { + setjasondelay(1); + + /* This gets us our 'whoa' effect with pixel bleeding magic. + * I'm willing to bet the guy who originally wrote the asm was goofing + * around on acid and thought this looked good enough to use. */ + for (i = screenSize - bottomBorder, j = topBorder / 2; i > 0; i--, j++) + { + offset = j + i/8192 - 4; + color = (TempScreen2[offset ] * 12 + + TempScreen1[offset-VGAScreenSeg->pitch] + + TempScreen1[offset-1 ] + + TempScreen1[offset+1 ] + + TempScreen1[offset+VGAScreenSeg->pitch]) / 16; + + TempScreen1[j] = color; + } + + /* Now copy that mess to the buffer. */ + memcpy((Uint8 *)VGAScreenSeg->pixels + topBorder, TempScreen1 + topBorder, screenSize - bottomBorder); + + JE_showVGA(); + + timer--; + wait_delay(); + + /* Flip the buffer. */ + TempScreenSwap = TempScreen1; + TempScreen1 = TempScreen2; + TempScreen2 = TempScreenSwap; + + } while (!(timer == 0 || JE_anyButton())); + + levelWarningLines = 4; +} + +void JE_barX( JE_word x1, JE_word y1, JE_word x2, JE_word y2, JE_byte col ) +{ + fill_rectangle_xy(VGAScreen, x1, y1, x2, y1, col + 1); + fill_rectangle_xy(VGAScreen, x1, y1 + 1, x2, y2 - 1, col ); + fill_rectangle_xy(VGAScreen, x1, y2, x2, y2, col - 1); +} + +void draw_boss_bar( void ) +{ + for (unsigned int b = 0; b < COUNTOF(boss_bar); b++) + { + if (boss_bar[b].link_num == 0) + continue; + + unsigned int armor = 256; // higher than armor max + + for (unsigned int e = 0; e < COUNTOF(enemy); e++) // find most damaged + { + if (enemyAvail[e] != 1 && enemy[e].linknum == boss_bar[b].link_num) + if (enemy[e].armorleft < armor) + armor = enemy[e].armorleft; + } + + if (armor > 255 || armor == 0) // boss dead? + boss_bar[b].link_num = 0; + else + boss_bar[b].armor = (armor == 255) ? 254 : armor; // 255 would make the bar too long + } + + unsigned int bars = (boss_bar[0].link_num != 0 ? 1 : 0) + + (boss_bar[1].link_num != 0 ? 1 : 0); + + // if only one bar left, make it the first one + if (bars == 1 && boss_bar[0].link_num == 0) + { + memcpy(&boss_bar[0], &boss_bar[1], sizeof(boss_bar_t)); + boss_bar[1].link_num = 0; + } + + for (unsigned int b = 0; b < bars; b++) + { + unsigned int x = (bars == 2) + ? ((b == 0) ? 125 : 185) + : ((levelTimer) ? 250 : 155); // level timer and boss bar would overlap + + JE_barX(x - 25, 7, x + 25, 12, 115); + JE_barX(x - (boss_bar[b].armor / 10), 7, x + (boss_bar[b].armor + 5) / 10, 12, 118 + boss_bar[b].color); + + if (boss_bar[b].color > 0) + boss_bar[b].color--; + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/tyrian2.h b/alienblaster/project/jni/application/opentyrian/src/tyrian2.h new file mode 100644 index 000000000..1361db7b9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/tyrian2.h @@ -0,0 +1,71 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TYRIAN2_H +#define TYRIAN2_H + +#include "opentyr.h" + +#include "varz.h" +#include "helptext.h" + +void intro_logos( void ); + +typedef struct +{ + Uint8 link_num; + Uint8 armor; + Uint8 color; +} +boss_bar_t; + +extern boss_bar_t boss_bar[2]; + +extern char tempStr[31]; +extern JE_byte itemAvail[9][10], itemAvailMax[9]; + +void JE_createNewEventEnemy( JE_byte enemytypeofs, JE_word enemyoffset ); + +void JE_doNetwork( void ); + +uint JE_makeEnemy( struct JE_SingleEnemyType *enemy ); + +void JE_eventJump( JE_word jump ); + +void JE_whoa( void ); + +void JE_barX ( JE_word x1, JE_word y1, JE_word x2, JE_word y2, JE_byte col ); + +void JE_newEnemy( int enemyOffset ); +void JE_drawEnemy( int enemyOffset ); +void JE_starShowVGA( void ); + +void JE_main( void ); +void JE_loadMap( void ); +bool JE_titleScreen( JE_boolean animate ); +void JE_readTextSync( void ); +void JE_displayText( void ); + +JE_boolean JE_searchFor( JE_byte PLType ); +void JE_eventSystem( void ); + +void draw_boss_bar( void ); + +#endif /* TYRIAN2_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/varz.cpp b/alienblaster/project/jni/application/opentyrian/src/varz.cpp new file mode 100644 index 000000000..44bfd1be8 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/varz.cpp @@ -0,0 +1,1412 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "editship.h" +#include "episodes.h" +#include "joystick.h" +#include "lds_play.h" +#include "loudness.h" +#include "mainint.h" +#include "mouse.h" +#include "mtrand.h" +#include "network.h" +#include "nortsong.h" +#include "nortvars.h" +#include "opentyr.h" +#include "sprite.h" +#include "varz.h" +#include "vga256d.h" +#include "video.h" + +JE_integer tempDat, tempDat2, tempDat3; + +const JE_byte SANextShip[SA + 2] /* [0..SA + 1] */ = { 3, 9, 6, 2, 5, 1, 4, 3, 7 }; // 0 -> 3 -> 2 -> 6 -> 4 -> 5 -> 1 -> 9 -> 7 +const JE_word SASpecialWeapon[SA] /* [1..SA] */ = { 7, 8, 9, 10, 11, 12, 13 }; +const JE_word SASpecialWeaponB[SA] /* [1..SA] */ = {37, 6, 15, 40, 16, 14, 41 }; +const JE_byte SAShip[SA] /* [1..SA] */ = { 3, 1, 5, 10, 2, 11, 12 }; +const JE_word SAWeapon[SA][5] /* [1..SA, 1..5] */ = +{ /* R Bl Bk G P */ + { 9, 31, 32, 33, 34 }, /* Stealth Ship */ + { 19, 8, 22, 41, 34 }, /* StormWind */ + { 27, 5, 20, 42, 31 }, /* Techno */ + { 15, 3, 28, 22, 12 }, /* Enemy */ + { 23, 35, 25, 14, 6 }, /* Weird */ + { 2, 5, 21, 4, 7 }, /* Unknown */ + { 40, 38, 37, 41, 36 } /* NortShip Z */ +}; + +const JE_byte specialArcadeWeapon[PORT_NUM] /* [1..Portnum] */ = +{ + 17,17,18,0,0,0,10,0,0,0,0,0,44,0,10,0,19,0,0,-0,0,0,0,0,0,0, + -0,0,0,0,45,0,0,0,0,0,0,0,0,0,0,0 +}; + +const JE_byte optionSelect[16][3][2] /* [0..15, 1..3, 1..2] */ = +{ /* MAIN OPT FRONT */ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { { 1, 1},{16,16},{30,30} }, /*Single Shot*/ + { { 2, 2},{29,29},{29,20} }, /*Dual Shot*/ + { { 3, 3},{21,21},{12, 0} }, /*Charge Cannon*/ + { { 4, 4},{18,18},{16,23} }, /*Vulcan*/ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { { 6, 6},{29,16},{ 0,22} }, /*Super Missile*/ + { { 7, 7},{19,19},{19,28} }, /*Atom Bomb*/ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { {10,10},{21,21},{21,27} }, /*Mini Missile*/ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { {13,13},{17,17},{13,26} }, /*MicroBomb*/ + { { 0, 0},{ 0, 0},{ 0, 0} }, /**/ + { {15,15},{15,16},{15,16} } /*Post-It*/ +}; + +const JE_word PGR[21] /* [1..21] */ = +{ + 4, + 1,2,3, + 41-21,57-21,73-21,89-21,105-21, + 121-21,137-21,153-21, + 151,151,151,151,73-21,73-21,1,2,4 + /*151,151,151*/ +}; +const JE_byte PAni[21] /* [1..21] */ = {1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1}; + +const JE_word linkGunWeapons[38] /* [1..38] */ = +{ + 0,0,0,0,0,0,0,0,444,445,446,447,0,448,449,0,0,0,0,0,450,451,0,506,0,564, + 445,446,447,448,449,445,446,447,448,449,450,451 +}; +const JE_word chargeGunWeapons[38] /* [1..38] */ = +{ + 0,0,0,0,0,0,0,0,476,458,464,482,0,488,470,0,0,0,0,0,494,500,0,528,0,558, + 458,458,458,458,458,458,458,458,458,458,458,458 +}; +const JE_word linkMultiGr[17] /* [0..16] */ = + {77,221,183,301,1,282,164,202,58,201,163,281,39,300,182,220,77}; +const JE_word linkSonicGr[17] /* [0..16] */ = + {85,242,131,303,47,284,150,223,66,224,149,283,9,302,130,243,85}; +const JE_word linkMult2Gr[17] /* [0..16] */ = + {78,299,295,297,2,278,276,280,59,279,275,277,40,296,294,298,78}; + +const JE_byte randomEnemyLaunchSounds[3] /* [1..3] */ = {13,6,26}; + +/* YKS: Twiddle cheat sheet: + * 1: UP + * 2: DOWN + * 3: LEFT + * 4: RIGHT + * 5: UP+FIRE + * 6: DOWN+FIRE + * 7: LEFT+FIRE + * 8: RIGHT+FIRE + * 9: Release all keys (directions and fire) + */ +const JE_byte keyboardCombos[26][8] /* [1..26, 1..8] */ = +{ + { 2, 1, 2, 5, 137, 0, 0, 0}, /*Invulnerability*/ + { 4, 3, 2, 5, 138, 0, 0, 0}, /*Atom Bomb*/ + { 3, 4, 6, 139, 0, 0, 0, 0}, /*Seeker Bombs*/ + { 2, 5, 142, 0, 0, 0, 0, 0}, /*Ice Blast*/ + { 6, 2, 6, 143, 0, 0, 0, 0}, /*Auto Repair*/ + { 6, 7, 5, 8, 6, 7, 5, 112 }, /*Spin Wave*/ + { 7, 8, 101, 0, 0, 0, 0, 0}, /*Repulsor*/ + { 1, 7, 6, 146, 0, 0, 0, 0}, /*Protron Field*/ + { 8, 6, 7, 1, 120, 0, 0, 0}, /*Minefield*/ + { 3, 6, 8, 5, 121, 0, 0, 0}, /*Post-It Blast*/ + { 1, 2, 7, 8, 119, 0, 0, 0}, /*Drone Ship - TBC*/ + { 3, 4, 3, 6, 123, 0, 0, 0}, /*Repair Player 2*/ + { 6, 7, 5, 8, 124, 0, 0, 0}, /*Super Bomb - TBC*/ + { 1, 6, 125, 0, 0, 0, 0, 0}, /*Hot Dog*/ + { 9, 5, 126, 0, 0, 0, 0, 0}, /*Lightning UP */ + { 1, 7, 127, 0, 0, 0, 0, 0}, /*Lightning UP+LEFT */ + { 1, 8, 128, 0, 0, 0, 0, 0}, /*Lightning UP+RIGHT*/ + { 9, 7, 129, 0, 0, 0, 0, 0}, /*Lightning LEFT */ + { 9, 8, 130, 0, 0, 0, 0, 0}, /*Lightning RIGHT*/ + { 4, 2, 3, 5, 131, 0, 0, 0}, /*Warfly */ + { 3, 1, 2, 8, 132, 0, 0, 0}, /*FrontBlaster */ + { 2, 4, 5, 133, 0, 0, 0, 0}, /*Gerund */ + { 3, 4, 2, 8, 134, 0, 0, 0}, /*FireBomb */ + { 1, 4, 6, 135, 0, 0, 0, 0}, /*Indigo */ + { 1, 3, 6, 137, 0, 0, 0, 0}, /*Invulnerability [easier] */ + { 1, 4, 3, 4, 7, 136, 0, 0} /*D-Media Protron Drone */ +}; + +const JE_byte shipCombosB[21] /* [1..21] */ = + {15,16,17,18,19,20,21,22,23,24, 7, 8, 5,25,14, 4, 6, 3, 9, 2,26}; + /*!! SUPER Tyrian !!*/ +const JE_byte superTyrianSpecials[4] /* [1..4] */ = {1,2,4,5}; + +const JE_byte shipCombos[14][3] /* [0..12, 1..3] */ = +{ + { 5, 4, 7}, /*2nd Player ship*/ + { 1, 2, 0}, /*USP Talon*/ + {14, 4, 0}, /*Super Carrot*/ + { 4, 5, 0}, /*Gencore Phoenix*/ + { 6, 5, 0}, /*Gencore Maelstrom*/ + { 7, 8, 0}, /*MicroCorp Stalker*/ + { 7, 9, 0}, /*MicroCorp Stalker-B*/ + {10, 3, 5}, /*Prototype Stalker-C*/ + { 5, 8, 9}, /*Stalker*/ + { 1, 3, 0}, /*USP Fang*/ + { 7,16,17}, /*U-Ship*/ + { 2,11,12}, /*1st Player ship*/ + { 3, 8,10}, /*Nort ship*/ + { 0, 0, 0} // Dummy entry added for Stalker 21.126 +}; + +/*Street-Fighter Commands*/ +JE_byte SFCurrentCode[2][21]; /* [1..2, 1..21] */ +JE_byte SFExecuted[2]; /* [1..2] */ + +/*Special General Data*/ +JE_byte lvlFileNum; +JE_word maxEvent, eventLoc; +/*JE_word maxenemies;*/ +JE_word tempBackMove, explodeMove; /*Speed of background movement*/ +JE_byte levelEnd; +JE_word levelEndFxWait; +JE_shortint levelEndWarp; +JE_boolean endLevel, reallyEndLevel, waitToEndLevel, playerEndLevel, + normalBonusLevelCurrent, bonusLevelCurrent, + smallEnemyAdjust, readyToEndLevel, quitRequested; + +JE_byte newPL[10]; /* [0..9] */ /*Eventsys event 75 parameter*/ +JE_word returnLoc; +JE_boolean returnActive; +JE_word galagaShotFreq; +JE_longint galagaLife; + +JE_boolean debug = false; /*Debug Mode*/ +Uint32 debugTime, lastDebugTime; +JE_longint debugHistCount; +JE_real debugHist; +JE_word curLoc; /*Current Pixel location of background 1*/ + +JE_boolean firstGameOver, gameLoaded, enemyStillExploding; + + +/* Destruction Ratio */ +JE_word totalEnemy; +JE_word enemyKilled; + +/* Shape/Map Data - All in one Segment! */ +struct JE_MegaDataType1 megaData1; +struct JE_MegaDataType2 megaData2; +struct JE_MegaDataType3 megaData3; + +/* Secret Level Display */ +JE_byte flash; +JE_shortint flashChange; +JE_byte displayTime; + +/* Demo Stuff */ +bool play_demo = false, record_demo = false, stopped_demo = false; +Uint8 demo_num = 0; +FILE *demo_file = NULL; + +Uint8 demo_keys, next_demo_keys; +Uint16 demo_keys_wait; + +/* Sound Effects Queue */ +JE_byte soundQueue[8]; /* [0..7] */ + +/*Level Event Data*/ +JE_boolean enemyContinualDamage; +JE_boolean enemiesActive; +JE_boolean forceEvents; +JE_boolean stopBackgrounds; +JE_byte stopBackgroundNum; +JE_byte damageRate; /*Rate at which a player takes damage*/ +JE_boolean background3x1; /*Background 3 enemies use Background 1 X offset*/ +JE_boolean background3x1b; /*Background 3 enemies moved 8 pixels left*/ + +JE_boolean levelTimer; +JE_word levelTimerCountdown; +JE_word levelTimerJumpTo; +JE_boolean randomExplosions; + +JE_boolean editShip1, editShip2; + +JE_boolean globalFlags[10]; /* [1..10] */ +JE_byte levelSong; + +/* DESTRUCT game */ +JE_boolean loadDestruct; + +/* MapView Data */ +JE_word mapOrigin, mapPNum; +JE_byte mapPlanet[5], mapSection[5]; /* [1..5] */ + +/* Interface Constants */ +JE_boolean moveTyrianLogoUp; +JE_boolean skipStarShowVGA; + +/*EnemyData*/ +JE_EnemyType enemy; +JE_EnemyAvailType enemyAvail; +JE_word enemyOffset; +JE_word enemyOnScreen; +JE_byte enemyShapeTables[6]; /* [1..6] */ +JE_boolean uniqueEnemy; +JE_word superEnemy254Jump; + +/*EnemyShotData*/ +JE_boolean fireButtonHeld; +JE_boolean enemyShotAvail[ENEMY_SHOT_MAX]; /* [1..Enemyshotmax] */ +EnemyShotType enemyShot[ENEMY_SHOT_MAX]; /* [1..Enemyshotmax] */ + +/* Player Shot Data */ +JE_byte zinglonDuration; +JE_byte astralDuration; +JE_word flareDuration; +JE_boolean flareStart; +JE_shortint flareColChg; +JE_byte specialWait; +JE_byte nextSpecialWait; +JE_boolean spraySpecial; +JE_byte doIced; +JE_boolean infiniteShot; + +PlayerShotDataType playerShotData[MAX_PWEAPON + 1]; /* [1..MaxPWeapon+1] */ + +JE_byte chain; + +/*PlayerData*/ +JE_boolean allPlayersGone; /*Both players dead and finished exploding*/ + +JE_byte shotAvail[MAX_PWEAPON]; /* [1..MaxPWeapon] */ /*0:Avail 1-255:Duration left*/ +const uint shadowYDist = 10; + +JE_real optionSatelliteRotate; + +JE_integer optionAttachmentMove; +JE_boolean optionAttachmentLinked, optionAttachmentReturn; + + +JE_byte chargeWait, chargeLevel, chargeMax, chargeGr, chargeGrWait; + +JE_word neat; + + +/*ExplosionData*/ +explosion_type explosions[MAX_EXPLOSIONS]; /* [1..ExplosionMax] */ +JE_integer explosionFollowAmountX, explosionFollowAmountY; + +/*Repeating Explosions*/ +rep_explosion_type rep_explosions[MAX_REPEATING_EXPLOSIONS]; /* [1..20] */ + +/*SuperPixels*/ +superpixel_type superpixels[MAX_SUPERPIXELS]; /* [0..MaxSP] */ +unsigned int last_superpixel; + +/*Temporary Numbers*/ +JE_integer tempI, tempI2, tempI3, tempI4; +JE_longint tempL; + +JE_byte temp, temp2, temp3, temp4, temp5, tempPos; +JE_word tempX, tempY, tempX2, tempY2; +JE_word tempW, tempW2; + +JE_boolean doNotSaveBackup; + +JE_word x, y; +JE_integer b; +JE_byte playerNum; + +JE_byte **BKwrap1to, **BKwrap2to, **BKwrap3to, + **BKwrap1, **BKwrap2, **BKwrap3; + +JE_shortint specialWeaponFilter, specialWeaponFreq; +JE_word specialWeaponWpn; +JE_boolean linkToPlayer; + +JE_word shipGr, shipGr2; +Sprite2_array *shipGrPtr, *shipGr2ptr; + +void JE_getShipInfo( void ) +{ + JE_boolean extraShip, extraShip2; + + shipGrPtr = &shapes9; + shipGr2ptr = &shapes9; + + powerAdd = powerSys[player[0].items.generator].power; + + extraShip = player[0].items.ship > 90; + if (extraShip) + { + JE_byte base = (player[0].items.ship - 91) * 15; + shipGr = JE_SGr(player[0].items.ship - 90, &shipGrPtr); + player[0].armor = extraShips[base + 7]; + } + else + { + shipGr = ships[player[0].items.ship].shipgraphic; + player[0].armor = ships[player[0].items.ship].dmg; + } + + extraShip2 = player[1].items.ship > 90; + if (extraShip2) + { + JE_byte base2 = (player[1].items.ship - 91) * 15; + shipGr2 = JE_SGr(player[1].items.ship - 90, &shipGr2ptr); + player[1].armor = extraShips[base2 + 7]; /* bug? */ + } + else + { + shipGr2 = 0; + player[1].armor = 10; + } + + for (uint i = 0; i < COUNTOF(player); ++i) + { + player[i].initial_armor = player[i].armor; + + + uint temp = ((i == 0 && extraShip) || + (i == 1 && extraShip2)) ? 2 : ships[player[i].items.ship].ani; + + if (temp == 0) + { + player[i].shot_hit_area_x = 12; + player[i].shot_hit_area_y = 10; + } + else + { + player[i].shot_hit_area_x = 11; + player[i].shot_hit_area_y = 14; + } + } +} + +JE_word JE_SGr( JE_word ship, Sprite2_array **ptr ) +{ + const JE_word GR[15] /* [1..15] */ = {233, 157, 195, 271, 81, 0, 119, 5, 43, 81, 119, 157, 195, 233, 271}; + + JE_word tempW = extraShips[(ship - 1) * 15]; + if (tempW > 7) + *ptr = (Sprite2_array*)extraShapes; + + return GR[tempW-1]; +} + +void JE_drawOptions( void ) +{ + SDL_Surface *temp_surface = VGAScreen; + VGAScreen = VGAScreenSeg; + + Player *this_player = &player[twoPlayerMode ? 1 : 0]; + + for (uint i = 0; i < COUNTOF(this_player->sidekick); ++i) + { + JE_OptionType *this_option = &options[this_player->items.sidekick[i]]; + + this_player->sidekick[i].ammo = + this_player->sidekick[i].ammo_max = this_option->ammo; + + this_player->sidekick[i].ammo_refill_ticks = + this_player->sidekick[i].ammo_refill_ticks_max = (105 - this_player->sidekick[i].ammo) * 4; + + this_player->sidekick[i].style = this_option->tr; + + this_player->sidekick[i].animation_enabled = (this_option->option == 1); + this_player->sidekick[i].animation_frame = 0; + + this_player->sidekick[i].charge = 0; + this_player->sidekick[i].charge_ticks = 20; + + + // draw initial sidekick HUD + const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i]; + + fill_rectangle_xy(VGAScreenSeg, 284, y, 284 + 28, y + 15, 0); + if (this_option->icongr > 0) + blit_sprite(VGAScreenSeg, 284, y, OPTION_SHAPES, this_option->icongr - 1); // sidekick HUD icon + draw_segmented_gauge(VGAScreenSeg, 284, y + 13, 112, 2, 2, MAX(1, this_player->sidekick[i].ammo_max / 10), this_player->sidekick[i].ammo); + } + + VGAScreen = temp_surface; + + JE_drawOptionLevel(); +} + +void JE_drawOptionLevel( void ) +{ + if (twoPlayerMode) + { + for (temp = 1; temp <= 3; temp++) + { + fill_rectangle_xy(VGAScreenSeg, 268, 127 + (temp - 1) * 6, 269, 127 + 3 + (temp - 1) * 6, 193 + ((player[1].items.sidekick_level - 100) == temp) * 11); + } + } +} + +void JE_tyrianHalt( JE_byte code ) +{ + deinit_audio(); + deinit_video(); + deinit_joysticks(); + + /* TODO: NETWORK */ + + free_main_shape_tables(); + + free_sprite2s(&shapes6); + + for (int i = 0; i < SAMPLE_COUNT; i++) + { + free(digiFx[i]); + } + + if (code != 9) + { + /* + TODO? + JE_drawANSI("exitmsg.bin"); + JE_gotoXY(1,22);*/ + + JE_saveConfiguration(); + } + + /* endkeyboard; */ + + if (code == 9) + { + /* OutputString('call=file0002.EXE' + #0'); TODO? */ + } + + if (code == 5) + { + code = 0; + } + + if (trentWin) + { + printf("\n" + "\n" + "\n" + "\n" + "Sleep well, Trent, you deserve the rest.\n" + "You now have permission to borrow my ship on your next mission.\n" + "\n" + "Also, you might want to try out the YESXMAS parameter.\n" + " Type: File0001 YESXMAS\n" + "\n" + "You'll need the 2.1 patch, though!\n" + "\n"); + } + + SDL_Quit(); + exit(code); +} + +void JE_initPlayerShot( JE_word portNum, uint shot_i, JE_word PX, JE_word PY, JE_word mouseX, JE_word mouseY, JE_word wpNum, JE_byte playerNum ) +{ + const JE_byte soundChannel[11] /* [1..11] */ = {0, 2, 4, 4, 2, 2, 5, 5, 1, 4, 1}; + + if (portNum <= PORT_NUM) + { + if (wpNum > 0 && wpNum <= WEAP_NUM) + { + if (power >= weaponPort[portNum].poweruse) + { + power -= weaponPort[portNum].poweruse; + + if (weapons[wpNum].sound > 0) + { + soundQueue[soundChannel[shot_i]] = weapons[wpNum].sound; + } + + /*Rot*/ + for (tempW = 1; tempW <= weapons[wpNum].multi; tempW++) + { + + for (b = 0; b < MAX_PWEAPON; b++) + { + if (shotAvail[b] == 0) + { + break; + } + } + if (b == MAX_PWEAPON) + { + return; + } + + if (shotMultiPos[shot_i] == weapons[wpNum].max || shotMultiPos[shot_i] > 8) + { + shotMultiPos[shot_i] = 1; + } else { + shotMultiPos[shot_i]++; + } + + playerShotData[b].chainReaction = 0; + + playerShotData[b].playerNumber = playerNum; + + playerShotData[b].shotAni = 0; + + playerShotData[b].shotComplicated = weapons[wpNum].circlesize != 0; + + if (weapons[wpNum].circlesize == 0) + { + playerShotData[b].shotDevX = 0; + playerShotData[b].shotDirX = 0; + playerShotData[b].shotDevY = 0; + playerShotData[b].shotDirY = 0; + playerShotData[b].shotCirSizeX = 0; + playerShotData[b].shotCirSizeY = 0; + } else { + temp2 = weapons[wpNum].circlesize; + + if (temp2 > 19) + { + temp3 = temp2 % 20; + playerShotData[b].shotCirSizeX = temp3; + playerShotData[b].shotDevX = temp3 >> 1; + + temp2 = temp2 / 20; + playerShotData[b].shotCirSizeY = temp2; + playerShotData[b].shotDevY = temp2 >> 1; + } else { + playerShotData[b].shotCirSizeX = temp2; + playerShotData[b].shotCirSizeY = temp2; + playerShotData[b].shotDevX = temp2 >> 1; + playerShotData[b].shotDevY = temp2 >> 1; + } + playerShotData[b].shotDirX = 1; + playerShotData[b].shotDirY = -1; + } + + playerShotData[b].shotTrail = weapons[wpNum].trail; + + if (weapons[wpNum].attack[shotMultiPos[shot_i]-1] > 99 && weapons[wpNum].attack[shotMultiPos[shot_i]-1] < 250) + { + playerShotData[b].chainReaction = weapons[wpNum].attack[shotMultiPos[shot_i]-1] - 100; + playerShotData[b].shotDmg = 1; + } else { + playerShotData[b].shotDmg = weapons[wpNum].attack[shotMultiPos[shot_i]-1]; + } + + playerShotData[b].shotBlastFilter = weapons[wpNum].shipblastfilter; + + tempI = weapons[wpNum].by[shotMultiPos[shot_i]-1]; + + /*Note: Only front selection used for player shots...*/ + + playerShotData[b].shotX = PX + weapons[wpNum].bx[shotMultiPos[shot_i]-1]; + + playerShotData[b].shotY = PY + tempI; + playerShotData[b].shotYC = -weapons[wpNum].acceleration; + playerShotData[b].shotXC = weapons[wpNum].accelerationx; + + playerShotData[b].shotXM = weapons[wpNum].sx[shotMultiPos[shot_i]-1]; + + temp2 = weapons[wpNum].del[shotMultiPos[shot_i]-1]; + + if (temp2 == 121) + { + playerShotData[b].shotTrail = 0; + temp2 = 255; + } + + playerShotData[b].shotGr = weapons[wpNum].sg[shotMultiPos[shot_i]-1]; + if (playerShotData[b].shotGr == 0) + { + shotAvail[b] = 0; + } else { + shotAvail[b] = temp2; + } + if (temp2 > 100 && temp2 < 120) + { + playerShotData[b].shotAniMax = (temp2 - 100 + 1); + } else { + playerShotData[b].shotAniMax = weapons[wpNum].weapani + 1; + } + + if (temp2 == 99 || temp2 == 98) + { + tempI = PX - mouseX; + if (tempI < -5) + { + tempI = -5; + } + if (tempI > 5) + { + tempI = 5; + } + playerShotData[b].shotXM += tempI; + } + + + if (temp2 == 99 || temp2 == 100) + { + tempI = PY - mouseY - weapons[wpNum].sy[shotMultiPos[shot_i]-1]; + if (tempI < -4) + { + tempI = -4; + } + if (tempI > 4) + { + tempI = 4; + } + playerShotData[b].shotYM = tempI; + } else { + if (weapons[wpNum].sy[shotMultiPos[shot_i]-1] == 98) + { + playerShotData[b].shotYM = 0; + playerShotData[b].shotYC = -1; + } else { + if (weapons[wpNum].sy[shotMultiPos[shot_i]-1] > 100) + { + playerShotData[b].shotYM = weapons[wpNum].sy[shotMultiPos[shot_i]-1]; + playerShotData[b].shotY -= player[playerShotData[b].playerNumber-1].delta_y_shot_move; + } else { + playerShotData[b].shotYM = -weapons[wpNum].sy[shotMultiPos[shot_i]-1]; + } + } + } + + if (weapons[wpNum].sx[shotMultiPos[shot_i]-1] > 100) + { + playerShotData[b].shotXM = weapons[wpNum].sx[shotMultiPos[shot_i]-1]; + playerShotData[b].shotX -= player[playerShotData[b].playerNumber-1].delta_x_shot_move; + if (playerShotData[b].shotXM == 101) + { + playerShotData[b].shotY -= player[playerShotData[b].playerNumber-1].delta_y_shot_move; + } + } + + + if (weapons[wpNum].aim > 5) /*Guided Shot*/ + { + uint best_dist = 65000; + temp3 = 0; + /*Find Closest Enemy*/ + for (x = 0; x < 100; x++) + { + if (enemyAvail[x] != 1 && !enemy[x].scoreitem) + { + y = abs(enemy[x].ex - playerShotData[b].shotX) + abs(enemy[x].ey - playerShotData[b].shotY); + if (y < best_dist) + { + best_dist = y; + temp3 = x + 1; + } + } + } + playerShotData[b].aimAtEnemy = temp3; + playerShotData[b].aimDelay = 5; + playerShotData[b].aimDelayMax = weapons[wpNum].aim - 5; + } + else + { + playerShotData[b].aimAtEnemy = 0; + } + + shotRepeat[shot_i] = weapons[wpNum].shotrepeat; + } + } + } + } +} + +void JE_specialComplete( JE_byte playerNum, JE_byte specialType ) +{ + nextSpecialWait = 0; + switch (special[specialType].stype) + { + /*Weapon*/ + case 1: + if (playerNum == 1) + JE_initPlayerShot(0, SHOT_SPECIAL2, player[0].x, player[0].y, mouseX, mouseY, special[specialType].wpn, playerNum); + else + JE_initPlayerShot(0, SHOT_SPECIAL2, player[1].x, player[1].y, mouseX, mouseY, special[specialType].wpn, playerNum); + + shotRepeat[SHOT_SPECIAL] = shotRepeat[SHOT_SPECIAL2]; + break; + /*Repulsor*/ + case 2: + for (temp = 0; temp < ENEMY_SHOT_MAX; temp++) + { + if (!enemyShotAvail[temp]) + { + if (player[0].x > enemyShot[temp].sx) + enemyShot[temp].sxm--; + else if (player[0].x < enemyShot[temp].sx) + enemyShot[temp].sxm++; + + if (player[0].y > enemyShot[temp].sy) + enemyShot[temp].sym--; + else if (player[0].y < enemyShot[temp].sy) + enemyShot[temp].sym++; + } + } + break; + /*Zinglon Blast*/ + case 3: + zinglonDuration = 50; + shotRepeat[SHOT_SPECIAL] = 100; + soundQueue[7] = S_SOUL_OF_ZINGLON; + break; + /*Attractor*/ + case 4: + for (temp = 0; temp < 100; temp++) + { + if (enemyAvail[temp] != 1 && enemy[temp].scoreitem + && enemy[temp].evalue != 0) + { + if (player[0].x > enemy[temp].ex) + enemy[temp].exc++; + else if (player[0].x < enemy[temp].ex) + enemy[temp].exc--; + + if (player[0].y > enemy[temp].ey) + enemy[temp].eyc++; + else if (player[0].y < enemy[temp].ey) + enemy[temp].eyc--; + } + } + break; + /*Flare*/ + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + if (flareDuration == 0) + flareStart = true; + + specialWeaponWpn = special[specialType].wpn; + linkToPlayer = false; + spraySpecial = false; + switch (special[specialType].stype) + { + case 5: + specialWeaponFilter = 7; + specialWeaponFreq = 2; + flareDuration = 50; + break; + case 6: + specialWeaponFilter = 1; + specialWeaponFreq = 7; + flareDuration = 200 + 25 * player[0].items.weapon[FRONT_WEAPON].power; + break; + case 7: + specialWeaponFilter = 3; + specialWeaponFreq = 3; + flareDuration = 50 + 10 * player[0].items.weapon[FRONT_WEAPON].power; + zinglonDuration = 50; + shotRepeat[SHOT_SPECIAL] = 100; + soundQueue[7] = S_SOUL_OF_ZINGLON; + break; + case 8: + specialWeaponFilter = -99; + specialWeaponFreq = 7; + flareDuration = 10 + player[0].items.weapon[FRONT_WEAPON].power; + break; + case 9: + specialWeaponFilter = -99; + specialWeaponFreq = 8; + flareDuration = 8 + 2 * player[0].items.weapon[FRONT_WEAPON].power; + linkToPlayer = true; + nextSpecialWait = special[specialType].pwr; + break; + case 10: + specialWeaponFilter = -99; + specialWeaponFreq = 8; + flareDuration = 14 + 4 * player[0].items.weapon[FRONT_WEAPON].power; + linkToPlayer = true; + break; + case 11: + specialWeaponFilter = -99; + specialWeaponFreq = special[specialType].pwr; + flareDuration = 10 + 10 * player[0].items.weapon[FRONT_WEAPON].power; + astralDuration = 20 + 10 * player[0].items.weapon[FRONT_WEAPON].power; + break; + case 16: + specialWeaponFilter = -99; + specialWeaponFreq = 8; + flareDuration = temp2 * 16 + 8; + linkToPlayer = true; + spraySpecial = true; + break; + } + break; + case 12: + player[playerNum-1].invulnerable_ticks = temp2 * 10; + + if (superArcadeMode > 0 && superArcadeMode <= SA) + { + shotRepeat[SHOT_SPECIAL] = 250; + JE_initPlayerShot(0, SHOT_SPECIAL2, player[0].x, player[0].y, mouseX, mouseY, 707, 1); + player[0].invulnerable_ticks = 100; + } + break; + case 13: + player[0].armor += temp2 / 4 + 1; + + soundQueue[3] = S_POWERUP; + break; + case 14: + player[1].armor += temp2 / 4 + 1; + + soundQueue[3] = S_POWERUP; + break; + + case 17: // spawn left or right sidekick + soundQueue[3] = S_POWERUP; + + if (player[0].items.sidekick[LEFT_SIDEKICK] == special[specialType].wpn) + { + player[0].items.sidekick[RIGHT_SIDEKICK] = special[specialType].wpn; + shotMultiPos[RIGHT_SIDEKICK] = 0; + } + else + { + player[0].items.sidekick[LEFT_SIDEKICK] = special[specialType].wpn; + shotMultiPos[LEFT_SIDEKICK] = 0; + } + + JE_drawOptions(); + break; + + case 18: // spawn right sidekick + player[0].items.sidekick[RIGHT_SIDEKICK] = special[specialType].wpn; + + JE_drawOptions(); + + soundQueue[4] = S_POWERUP; + + shotMultiPos[RIGHT_SIDEKICK] = 0; + break; + } +} + +void JE_doSpecialShot( JE_byte playerNum, uint *armor, uint *shield ) +{ + if (player[0].items.special > 0) + { + if (shotRepeat[SHOT_SPECIAL] == 0 && specialWait == 0 && flareDuration < 2 && zinglonDuration < 2) + blit_sprite2(VGAScreen, 47, 4, shapes9, 94); + else + blit_sprite2(VGAScreen, 47, 4, shapes9, 93); + } + + if (shotRepeat[SHOT_SPECIAL] > 0) + { + --shotRepeat[SHOT_SPECIAL]; + } + if (specialWait > 0) + { + specialWait--; + } + temp = SFExecuted[playerNum-1]; + if (temp > 0 && shotRepeat[SHOT_SPECIAL] == 0 && flareDuration == 0) + { + temp2 = special[temp].pwr; + + bool can_afford = true; + + if (temp2 > 0) + { + if (temp2 < 98) // costs some shield + { + if (*shield >= temp2) + *shield -= temp2; + else + can_afford = false; + } + else if (temp2 == 98) // costs all shield + { + if (*shield < 4) + can_afford = false; + temp2 = *shield; + *shield = 0; + } + else if (temp2 == 99) // costs half shield + { + temp2 = *shield / 2; + *shield = temp2; + } + else // costs some armor + { + temp2 -= 100; + if (*armor > temp2) + *armor -= temp2; + else + can_afford = false; + } + } + + shotMultiPos[SHOT_SPECIAL] = 0; + shotMultiPos[SHOT_SPECIAL2] = 0; + + if (can_afford) + JE_specialComplete(playerNum, temp); + + SFExecuted[playerNum-1] = 0; + + JE_wipeShieldArmorBars(); + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + JE_drawShield(); + JE_drawArmor(); + VGAScreen = game_screen; /* side-effect of game_screen */ + } + + if (playerNum == 1 && player[0].items.special > 0) + { /*Main Begin*/ + + if (superArcadeMode > 0 && (button[2-1] || button[3-1])) + { + fireButtonHeld = false; + } + if (!button[1-1] && !(superArcadeMode != SA_NONE && (button[2-1] || button[3-1]))) + { + fireButtonHeld = false; + } + else if (shotRepeat[SHOT_SPECIAL] == 0 && !fireButtonHeld && !(flareDuration > 0) && specialWait == 0) + { + fireButtonHeld = true; + JE_specialComplete(playerNum, player[0].items.special); + } + + } /*Main End*/ + + if (astralDuration > 0) + astralDuration--; + + shotAvail[MAX_PWEAPON-1] = 0; + if (flareDuration > 1) + { + if (specialWeaponFilter != -99) + { + if (levelFilter == -99 && levelBrightness == -99) + { + filterActive = false; + } + if (!filterActive) + { + levelFilter = specialWeaponFilter; + if (levelFilter == 7) + { + levelBrightness = 0; + } + filterActive = true; + } + + if (mt_rand() % 2 == 0) + flareColChg = -1; + else + flareColChg = 1; + + if (levelFilter == 7) + { + if (levelBrightness < -6) + { + flareColChg = 1; + } + if (levelBrightness > 6) + { + flareColChg = -1; + } + levelBrightness += flareColChg; + } + } + + if ((signed)(mt_rand() % 6) < specialWeaponFreq) + { + b = 0; + + if (linkToPlayer) + { + if (shotRepeat[SHOT_SPECIAL] == 0) + { + JE_initPlayerShot(0, SHOT_SPECIAL, player[0].x, player[0].y, mouseX, mouseY, specialWeaponWpn, playerNum); + } + } + else + { + JE_initPlayerShot(0, SHOT_SPECIAL, mt_rand() % 280, mt_rand() % 180, mouseX, mouseY, specialWeaponWpn, playerNum); + } + + if (spraySpecial && b > 0) + { + playerShotData[b].shotXM = (mt_rand() % 5) - 2; + playerShotData[b].shotYM = (mt_rand() % 5) - 2; + if (playerShotData[b].shotYM == 0) + { + playerShotData[b].shotYM++; + } + } + } + + flareDuration--; + if (flareDuration == 1) + { + specialWait = nextSpecialWait; + } + } + else if (flareStart) + { + flareStart = false; + shotRepeat[SHOT_SPECIAL] = linkToPlayer ? 15 : 200; + flareDuration = 0; + if (levelFilter == specialWeaponFilter) + { + levelFilter = -99; + levelBrightness = -99; + filterActive = false; + } + } + + if (zinglonDuration > 1) + { + temp = 25 - abs(zinglonDuration - 25); + + JE_barBright(VGAScreen, player[0].x + 7 - temp, 0, player[0].x + 7 + temp, 184); + JE_barBright(VGAScreen, player[0].x + 7 - temp - 2, 0, player[0].x + 7 + temp + 2, 184); + + zinglonDuration--; + if (zinglonDuration % 5 == 0) + { + shotAvail[MAX_PWEAPON-1] = 1; + } + } +} + +void JE_setupExplosion( signed int x, signed int y, signed int delta_y, unsigned int type, bool fixed_position, bool follow_player ) +{ + const struct { + JE_word sprite; + JE_byte ttl; + } explosion_data[53] /* [1..53] */ = { + { 144, 7 }, + { 120, 12 }, + { 190, 12 }, + { 209, 12 }, + { 152, 12 }, + { 171, 12 }, + { 133, 7 }, /*White Smoke*/ + { 1, 12 }, + { 20, 12 }, + { 39, 12 }, + { 58, 12 }, + { 110, 3 }, + { 76, 7 }, + { 91, 3 }, +/*15*/ { 227, 3 }, + { 230, 3 }, + { 233, 3 }, + { 252, 3 }, + { 246, 3 }, +/*20*/ { 249, 3 }, + { 265, 3 }, + { 268, 3 }, + { 271, 3 }, + { 236, 3 }, +/*25*/ { 239, 3 }, + { 242, 3 }, + { 261, 3 }, + { 274, 3 }, + { 277, 3 }, +/*30*/ { 280, 3 }, + { 299, 3 }, + { 284, 3 }, + { 287, 3 }, + { 290, 3 }, +/*35*/ { 293, 3 }, + { 165, 8 }, /*Coin Values*/ + { 184, 8 }, + { 203, 8 }, + { 222, 8 }, + { 168, 8 }, + { 187, 8 }, + { 206, 8 }, + { 225, 10 }, + { 169, 10 }, + { 188, 10 }, + { 207, 20 }, + { 226, 14 }, + { 170, 14 }, + { 189, 14 }, + { 208, 14 }, + { 246, 14 }, + { 227, 14 }, + { 265, 14 } + }; + + if (y > -16 && y < 190) + { + for (int i = 0; i < MAX_EXPLOSIONS; i++) + { + if (explosions[i].ttl == 0) + { + explosions[i].x = x; + explosions[i].y = y; + if (type == 6) + { + explosions[i].y += 12; + explosions[i].x += 2; + } else if (type == 98) + { + type = 6; + } + explosions[i].sprite = explosion_data[type].sprite; + explosions[i].ttl = explosion_data[type].ttl; + explosions[i].follow_player = follow_player; + explosions[i].fixed_position = fixed_position; + explosions[i].delta_x = 0; + explosions[i].delta_y = delta_y; + break; + } + } + } +} + +void JE_setupExplosionLarge( JE_boolean enemyGround, JE_byte exploNum, JE_integer x, JE_integer y ) +{ + if (y >= 0) + { + if (enemyGround) + { + JE_setupExplosion(x - 6, y - 14, 0, 2, false, false); + JE_setupExplosion(x + 6, y - 14, 0, 4, false, false); + JE_setupExplosion(x - 6, y, 0, 3, false, false); + JE_setupExplosion(x + 6, y, 0, 5, false, false); + } else { + JE_setupExplosion(x - 6, y - 14, 0, 7, false, false); + JE_setupExplosion(x + 6, y - 14, 0, 9, false, false); + JE_setupExplosion(x - 6, y, 0, 8, false, false); + JE_setupExplosion(x + 6, y, 0, 10, false, false); + } + + bool big; + + if (exploNum > 10) + { + exploNum -= 10; + big = true; + } + else + { + big = false; + } + + if (exploNum) + { + for (int i = 0; i < MAX_REPEATING_EXPLOSIONS; i++) + { + if (rep_explosions[i].ttl == 0) + { + rep_explosions[i].ttl = exploNum; + rep_explosions[i].delay = 2; + rep_explosions[i].x = x; + rep_explosions[i].y = y; + rep_explosions[i].big = big; + break; + } + } + } + } +} + +void JE_wipeShieldArmorBars( void ) +{ + if (!twoPlayerMode || galagaMode) + { + fill_rectangle_xy(VGAScreenSeg, 270, 137, 278, 194 - player[0].shield * 2, 0); + } + else + { + fill_rectangle_xy(VGAScreenSeg, 270, 60 - 44, 278, 60, 0); + fill_rectangle_xy(VGAScreenSeg, 270, 194 - 44, 278, 194, 0); + } + if (!twoPlayerMode || galagaMode) + { + fill_rectangle_xy(VGAScreenSeg, 307, 137, 315, 194 - player[0].armor * 2, 0); + } + else + { + fill_rectangle_xy(VGAScreenSeg, 307, 60 - 44, 315, 60, 0); + fill_rectangle_xy(VGAScreenSeg, 307, 194 - 44, 315, 194, 0); + } +} + +JE_byte JE_playerDamage( JE_byte temp, + Player *this_player ) +{ + int playerDamage = 0; + soundQueue[7] = S_SHIELD_HIT; + + /* Player Damage Routines */ + if (this_player->shield < temp) + { + playerDamage = temp; + temp -= this_player->shield; + this_player->shield = 0; + + if (temp > 0) + { + /*Through Shields - Now Armor */ + + if (this_player->armor < temp) + { + temp -= this_player->armor; + this_player->armor = 0; + + if (this_player->is_alive && !youAreCheating) + { + levelTimer = false; + this_player->is_alive = false; + this_player->exploding_ticks = 60; + levelEnd = 40; + tempVolume = tyrMusicVolume; + soundQueue[1] = S_EXPLOSION_22; + } + } + else + { + this_player->armor -= temp; + soundQueue[7] = S_HULL_HIT; + } + } + } + else + { + this_player->shield -= temp; + + JE_setupExplosion(this_player->x - 17, this_player->y - 12, 0, 14, false, !twoPlayerMode); + JE_setupExplosion(this_player->x - 5 , this_player->y - 12, 0, 15, false, !twoPlayerMode); + JE_setupExplosion(this_player->x + 7 , this_player->y - 12, 0, 16, false, !twoPlayerMode); + JE_setupExplosion(this_player->x + 19, this_player->y - 12, 0, 17, false, !twoPlayerMode); + + JE_setupExplosion(this_player->x - 17, this_player->y + 2, 0, 18, false, !twoPlayerMode); + JE_setupExplosion(this_player->x + 19, this_player->y + 2, 0, 19, false, !twoPlayerMode); + + JE_setupExplosion(this_player->x - 17, this_player->y + 16, 0, 20, false, !twoPlayerMode); + JE_setupExplosion(this_player->x - 5 , this_player->y + 16, 0, 21, false, !twoPlayerMode); + JE_setupExplosion(this_player->x + 7 , this_player->y + 16, 0, 22, false, !twoPlayerMode); + } + + JE_wipeShieldArmorBars(); + VGAScreen = VGAScreenSeg; /* side-effect of game_screen */ + JE_drawShield(); + JE_drawArmor(); + VGAScreen = game_screen; /* side-effect of game_screen */ + + return playerDamage; +} + +JE_word JE_portConfigs( void ) +{ + const uint player_index = twoPlayerMode ? 1 : 0; + return tempW = weaponPort[player[player_index].items.weapon[REAR_WEAPON].id].opnum; +} + +void JE_drawShield( void ) +{ + if (twoPlayerMode && !galagaMode) + { + for (uint i = 0; i < COUNTOF(player); ++i) + JE_dBar3(VGAScreen, 270, 60 + 134 * i, roundf(player[i].shield * 0.8f), 144); + } + else + { + JE_dBar3(VGAScreen, 270, 194, player[0].shield, 144); + if (player[0].shield != player[0].shield_max) + { + const uint y = 193 - (player[0].shield_max * 2); + JE_rectangle(VGAScreen, 270, y, 278, y, 68); /* SEGa000 */ + } + } +} + +void JE_drawArmor( void ) +{ + for (uint i = 0; i < COUNTOF(player); ++i) + if (player[i].armor > 28) + player[i].armor = 28; + + if (twoPlayerMode && !galagaMode) + { + for (uint i = 0; i < COUNTOF(player); ++i) + JE_dBar3(VGAScreen, 307, 60 + 134 * i, roundf(player[i].armor * 0.8f), 224); + } + else + { + JE_dBar3(VGAScreen, 307, 194, player[0].armor, 224); + } +} + +void JE_doSP( JE_word x, JE_word y, JE_word num, JE_byte explowidth, JE_byte color ) /* superpixels */ +{ + for (temp = 0; temp < num; temp++) + { + JE_real tempr = mt_rand_lt1() * (2 * M_PI); + signed int tempy = roundf(cosf(tempr) * mt_rand_1() * explowidth); + signed int tempx = roundf(sinf(tempr) * mt_rand_1() * explowidth); + + if (++last_superpixel >= MAX_SUPERPIXELS) + last_superpixel = 0; + superpixels[last_superpixel].x = tempx + x; + superpixels[last_superpixel].y = tempy + y; + superpixels[last_superpixel].delta_x = tempx; + superpixels[last_superpixel].delta_y = tempy + 1; + superpixels[last_superpixel].color = color; + superpixels[last_superpixel].z = 15; + } +} + +void JE_drawSP( void ) +{ + for (int i = MAX_SUPERPIXELS; i--; ) + { + if (superpixels[i].z) + { + superpixels[i].x += superpixels[i].delta_x; + superpixels[i].y += superpixels[i].delta_y; + + if (superpixels[i].x < (unsigned)VGAScreen->w && superpixels[i].y < (unsigned)VGAScreen->h) + { + Uint8 *s = (Uint8 *)VGAScreen->pixels; /* screen pointer, 8-bit specific */ + s += superpixels[i].y * VGAScreen->pitch; + s += superpixels[i].x; + + *s = (((*s & 0x0f) + superpixels[i].z) >> 1) + superpixels[i].color; + if (superpixels[i].x > 0) + *(s - 1) = (((*(s - 1) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color; + if (superpixels[i].x < VGAScreen->w - 1u) + *(s + 1) = (((*(s + 1) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color; + if (superpixels[i].y > 0) + *(s - VGAScreen->pitch) = (((*(s - VGAScreen->pitch) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color; + if (superpixels[i].y < VGAScreen->h - 1u) + *(s + VGAScreen->pitch) = (((*(s + VGAScreen->pitch) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color; + } + + superpixels[i].z--; + } + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/varz.h b/alienblaster/project/jni/application/opentyrian/src/varz.h new file mode 100644 index 000000000..c7aa7fada --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/varz.h @@ -0,0 +1,385 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef VARZ_H +#define VARZ_H + +#include "episodes.h" +#include "opentyr.h" +#include "player.h" +#include "sprite.h" + +#include + +#define SA 7 + +enum +{ + SA_NONE = 0, + SA_NORTSHIPZ = 7, + + // only used for code entry + SA_DESTRUCT = 8, + SA_ENGAGE = 9, + + // only used in pItems[P_SUPERARCADE] + SA_SUPERTYRIAN = 254, + SA_ARCADE = 255 +}; + +#define MAX_PWEAPON 81 /* 81*/ +#define ENEMY_SHOT_MAX 60 /* 60*/ + +#define CURRENT_KEY_SPEED 1 /*Keyboard/Joystick movement rate*/ + +#define MAX_EXPLOSIONS 200 +#define MAX_REPEATING_EXPLOSIONS 20 +#define MAX_SUPERPIXELS 101 + +struct JE_SingleEnemyType +{ + JE_byte fillbyte; + JE_integer ex, ey; /* POSITION */ + JE_shortint exc, eyc; /* CURRENT SPEED */ + JE_shortint exca, eyca; /* RANDOM ACCELERATION */ + JE_shortint excc, eycc; /* FIXED ACCELERATION WAITTIME */ + JE_shortint exccw, eyccw; + JE_byte armorleft; + JE_byte eshotwait[3], eshotmultipos[3]; /* [1..3] */ + JE_byte enemycycle; + JE_byte ani; + JE_word egr[20]; /* [1..20] */ + JE_byte size; + JE_byte linknum; + JE_byte aniactive; + JE_byte animax; + JE_byte aniwhenfire; + Sprite2_array *sprite2s; + JE_shortint exrev, eyrev; + JE_integer exccadd, eyccadd; + JE_byte exccwmax, eyccwmax; + void *enemydatofs; + JE_boolean edamaged; + JE_word enemytype; + JE_byte animin; + JE_word edgr; + JE_shortint edlevel; + JE_shortint edani; + JE_byte fill1; + JE_byte filter; + JE_integer evalue; + JE_integer fixedmovey; + JE_byte freq[3]; /* [1..3] */ + JE_byte launchwait; + JE_word launchtype; + JE_byte launchfreq; + JE_byte xaccel; + JE_byte yaccel; + JE_byte tur[3]; /* [1..3] */ + JE_word enemydie; /* Enemy created when this one dies */ + JE_boolean enemyground; + JE_byte explonum; + JE_word mapoffset; + JE_boolean scoreitem; + + JE_boolean special; + JE_byte flagnum; + JE_boolean setto; + + JE_byte iced; /*Duration*/ + + JE_byte launchspecial; + + JE_integer xminbounce; + JE_integer xmaxbounce; + JE_integer yminbounce; + JE_integer ymaxbounce; + JE_byte fill[3]; /* [1..3] */ +}; + +typedef struct JE_SingleEnemyType JE_MultiEnemyType[100]; /* [1..100] */ + +typedef JE_word JE_DanCShape[(24 * 28) / 2]; /* [1..(24*28) div 2] */ + +typedef JE_char JE_CharString[256]; /* [1..256] */ + +typedef JE_byte JE_Map1Buffer[24 * 28 * 13 * 4]; /* [1..24*28*13*4] */ + +typedef JE_byte *JE_MapType[300][14]; /* [1..300, 1..14] */ +typedef JE_byte *JE_MapType2[600][14]; /* [1..600, 1..14] */ +typedef JE_byte *JE_MapType3[600][15]; /* [1..600, 1..15] */ + +struct JE_EventRecType +{ + JE_word eventtime; + JE_byte eventtype; + JE_integer eventdat, eventdat2; + JE_shortint eventdat3, eventdat5, eventdat6; + JE_byte eventdat4; +}; + +struct JE_MegaDataType1 +{ + JE_MapType mainmap; + struct + { + JE_DanCShape sh; + } shapes[72]; /* [0..71] */ + JE_byte tempdat1; + /*JE_DanCShape filler;*/ +}; + +struct JE_MegaDataType2 +{ + JE_MapType2 mainmap; + struct + { + JE_byte nothing[3]; /* [1..3] */ + JE_byte fill; + JE_DanCShape sh; + } shapes[71]; /* [0..70] */ + JE_byte tempdat2; +}; + +struct JE_MegaDataType3 +{ + JE_MapType3 mainmap; + struct + { + JE_byte nothing[3]; /* [1..3] */ + JE_byte fill; + JE_DanCShape sh; + } shapes[70]; /* [0..69] */ + JE_byte tempdat3; +}; + +typedef JE_MultiEnemyType JE_EnemyType; +typedef JE_byte JE_EnemyAvailType[100]; /* [1..100] */ + +typedef struct { + JE_integer sx, sy; + JE_integer sxm, sym; + JE_shortint sxc, syc; + JE_byte tx, ty; + JE_word sgr; + JE_byte sdmg; + JE_byte duration; + JE_word animate; + JE_word animax; + JE_byte fill[12]; +} EnemyShotType; + +typedef struct { + JE_integer shotX, shotY, shotXM, shotYM, shotXC, shotYC; + JE_boolean shotComplicated; + JE_integer shotDevX, shotDirX, shotDevY, shotDirY, shotCirSizeX, shotCirSizeY; + JE_byte shotTrail; + JE_word shotGr, shotAni, shotAniMax; + Uint8 shotDmg; + JE_byte shotBlastFilter, chainReaction, playerNumber, aimAtEnemy, aimDelay, aimDelayMax; +} PlayerShotDataType; + +typedef struct { + unsigned int ttl; + signed int x, y; + signed int delta_x, delta_y; + bool fixed_position; + bool follow_player; + unsigned int sprite; +} explosion_type; + +typedef struct { + unsigned int delay; + unsigned int ttl; + unsigned int x, y; + bool big; +} rep_explosion_type; + +typedef struct { + unsigned int x, y, z; + signed int delta_x, delta_y; + Uint8 color; +} superpixel_type; + +extern JE_integer tempDat, tempDat2, tempDat3; +extern const JE_byte SANextShip[SA + 2]; +extern const JE_word SASpecialWeapon[SA]; +extern const JE_word SASpecialWeaponB[SA]; +extern const JE_byte SAShip[SA]; +extern const JE_word SAWeapon[SA][5]; +extern const JE_byte specialArcadeWeapon[PORT_NUM]; +extern const JE_byte optionSelect[16][3][2]; +extern const JE_word PGR[21]; +extern const JE_byte PAni[21]; +extern const JE_word linkGunWeapons[38]; +extern const JE_word chargeGunWeapons[38]; +extern const JE_word linkMultiGr[17]; +extern const JE_word linkSonicGr[17]; +extern const JE_word linkMult2Gr[17]; +extern const JE_byte randomEnemyLaunchSounds[3]; +extern const JE_byte keyboardCombos[26][8]; +extern const JE_byte shipCombosB[21]; +extern const JE_byte superTyrianSpecials[4]; +extern const JE_byte shipCombos[14][3]; +extern JE_byte SFCurrentCode[2][21]; +extern JE_byte SFExecuted[2]; +extern JE_byte lvlFileNum; +extern JE_word maxEvent, eventLoc; +extern JE_word tempBackMove, explodeMove; +extern JE_byte levelEnd; +extern JE_word levelEndFxWait; +extern JE_shortint levelEndWarp; +extern JE_boolean endLevel, reallyEndLevel, waitToEndLevel, playerEndLevel, normalBonusLevelCurrent, bonusLevelCurrent, smallEnemyAdjust, readyToEndLevel, quitRequested; +extern JE_byte newPL[10]; +extern JE_word returnLoc; +extern JE_boolean returnActive; +extern JE_word galagaShotFreq; +extern JE_longint galagaLife; +extern JE_boolean debug; +extern Uint32 debugTime, lastDebugTime; +extern JE_longint debugHistCount; +extern JE_real debugHist; +extern JE_word curLoc; +extern JE_boolean firstGameOver, gameLoaded, enemyStillExploding; +extern JE_word totalEnemy; +extern JE_word enemyKilled; +extern struct JE_MegaDataType1 megaData1; +extern struct JE_MegaDataType2 megaData2; +extern struct JE_MegaDataType3 megaData3; +extern JE_byte flash; +extern JE_shortint flashChange; +extern JE_byte displayTime; + +extern bool play_demo, record_demo, stopped_demo; +extern Uint8 demo_num; +extern FILE *demo_file; + +extern Uint8 demo_keys, next_demo_keys; +extern Uint16 demo_keys_wait; + +extern JE_byte soundQueue[8]; +extern JE_boolean enemyContinualDamage; +extern JE_boolean enemiesActive; +extern JE_boolean forceEvents; +extern JE_boolean stopBackgrounds; +extern JE_byte stopBackgroundNum; +extern JE_byte damageRate; +extern JE_boolean background3x1; +extern JE_boolean background3x1b; +extern JE_boolean levelTimer; +extern JE_word levelTimerCountdown; +extern JE_word levelTimerJumpTo; +extern JE_boolean randomExplosions; +extern JE_boolean editShip1, editShip2; +extern JE_boolean globalFlags[10]; +extern JE_byte levelSong; +extern JE_boolean loadDestruct; +extern JE_word mapOrigin, mapPNum; +extern JE_byte mapPlanet[5], mapSection[5]; +extern JE_boolean moveTyrianLogoUp; +extern JE_boolean skipStarShowVGA; +extern JE_EnemyType enemy; +extern JE_EnemyAvailType enemyAvail; +extern JE_word enemyOffset; +extern JE_word enemyOnScreen; +extern JE_byte enemyShapeTables[6]; +extern JE_boolean uniqueEnemy; +extern JE_word superEnemy254Jump; +extern explosion_type explosions[MAX_EXPLOSIONS]; +extern JE_integer explosionFollowAmountX, explosionFollowAmountY; +extern JE_boolean fireButtonHeld; +extern JE_boolean enemyShotAvail[ENEMY_SHOT_MAX]; +extern EnemyShotType enemyShot[ENEMY_SHOT_MAX]; +extern JE_byte zinglonDuration; +extern JE_byte astralDuration; +extern JE_word flareDuration; +extern JE_boolean flareStart; +extern JE_shortint flareColChg; +extern JE_byte specialWait; +extern JE_byte nextSpecialWait; +extern JE_boolean spraySpecial; +extern JE_byte doIced; +extern JE_boolean infiniteShot; +extern PlayerShotDataType playerShotData[MAX_PWEAPON + 1]; +extern JE_byte chain; +extern JE_boolean allPlayersGone; +extern JE_byte shotAvail[MAX_PWEAPON]; +extern const uint shadowYDist; +extern JE_real optionSatelliteRotate; +extern JE_integer optionAttachmentMove; +extern JE_boolean optionAttachmentLinked, optionAttachmentReturn; +extern JE_byte chargeWait, chargeLevel, chargeMax, chargeGr, chargeGrWait; +extern JE_word neat; +extern rep_explosion_type rep_explosions[MAX_REPEATING_EXPLOSIONS]; +extern superpixel_type superpixels[MAX_SUPERPIXELS]; +extern unsigned int last_superpixel; +extern JE_integer tempI, tempI2, tempI3, tempI4; +extern JE_longint tempL; +extern JE_byte temp, temp2, temp3, temp4, temp5, tempPos; +extern JE_word tempX, tempY, tempX2, tempY2; +extern JE_word tempW, tempW2; +extern JE_boolean doNotSaveBackup; +extern JE_word x, y; +extern JE_integer b; +extern JE_byte playerNum; +extern JE_byte **BKwrap1to, **BKwrap2to, **BKwrap3to, **BKwrap1, **BKwrap2, **BKwrap3; +extern JE_shortint specialWeaponFilter, specialWeaponFreq; +extern JE_word specialWeaponWpn; +extern JE_boolean linkToPlayer; +extern JE_word shipGr, shipGr2; +extern Sprite2_array *shipGrPtr, *shipGr2ptr; + +static const int hud_sidekick_y[2][2] = +{ + { 64, 82 }, // one player HUD + { 108, 126 }, // two player HUD +}; + +void JE_getShipInfo( void ); +JE_word JE_SGr( JE_word ship, Sprite2_array **ptr ); + +void JE_drawOptions( void ); + +void JE_tyrianHalt( JE_byte code ); /* This ends the game */ +void JE_initPlayerShot( JE_word portnum, uint shot_i, JE_word px, JE_word py, + JE_word mousex, JE_word mousey, + JE_word wpnum, JE_byte playernum ); +void JE_specialComplete( JE_byte playernum, JE_byte specialType ); +void JE_doSpecialShot( JE_byte playernum, uint *armor, uint *shield ); + +void JE_wipeShieldArmorBars( void ); +JE_byte JE_playerDamage( JE_byte temp, Player * ); + +void JE_setupExplosion( signed int x, signed int y, signed int delta_y, unsigned int type, bool fixed_position, bool follow_player ); +void JE_setupExplosionLarge( JE_boolean enemyground, JE_byte explonum, JE_integer x, JE_integer y ); + +void JE_drawShield( void ); +void JE_drawArmor( void ); + +JE_word JE_portConfigs( void ); + +/*SuperPixels*/ +void JE_doSP( JE_word x, JE_word y, JE_word num, JE_byte explowidth, JE_byte color ); +void JE_drawSP( void ); + +void JE_drawOptionLevel( void ); + + +#endif /* VARZ_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/vga256d.cpp b/alienblaster/project/jni/application/opentyrian/src/vga256d.cpp new file mode 100644 index 000000000..9918ebf05 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/vga256d.cpp @@ -0,0 +1,160 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "config.h" // For fullscreen stuff +#include "keyboard.h" +#include "opentyr.h" +#include "palette.h" +#include "vga256d.h" +#include "video.h" + +#include "SDL.h" +#include +#include +#include +#include +#include + +void JE_pix( SDL_Surface *surface, int x, int y, JE_byte c ) +{ + /* Bad things happen if we don't clip */ + if (x < surface->pitch && y < surface->h) + { + Uint8 *vga = (Uint8 *)surface->pixels; + vga[y * surface->pitch + x] = c; + } +} + +void JE_pix3( SDL_Surface *surface, int x, int y, JE_byte c ) +{ + /* Originally impemented as several direct accesses */ + JE_pix(surface, x, y, c); + JE_pix(surface, x - 1, y, c); + JE_pix(surface, x + 1, y, c); + JE_pix(surface, x, y - 1, c); + JE_pix(surface, x, y + 1, c); +} + +void JE_rectangle( SDL_Surface *surface, int a, int b, int c, int d, int e ) /* x1, y1, x2, y2, color */ +{ + if (a < surface->pitch && b < surface->h && + c < surface->pitch && d < surface->h) + { + Uint8 *vga = (Uint8 *)surface->pixels; + int i; + + /* Top line */ + memset(&vga[b * surface->pitch + a], e, c - a + 1); + + /* Bottom line */ + memset(&vga[d * surface->pitch + a], e, c - a + 1); + + /* Left line */ + for (i = (b + 1) * surface->pitch + a; i < (d * surface->pitch + a); i += surface->pitch) + { + vga[i] = e; + } + + /* Right line */ + for (i = (b + 1) * surface->pitch + c; i < (d * surface->pitch + c); i += surface->pitch) + { + vga[i] = e; + } + } else { + printf("!!! WARNING: Rectangle clipped: %d %d %d %d %d\n", a, b, c, d, e); + } +} + +void fill_rectangle_xy( SDL_Surface *surface, int x, int y, int x2, int y2, Uint8 color ) +{ + SDL_Rect rect = { x, y, x2 - x + 1, y2 - y + 1 }; + SDL_FillRect(surface, &rect, color); +} + +void JE_barShade( SDL_Surface *surface, int a, int b, int c, int d ) /* x1, y1, x2, y2 */ +{ + if (a < surface->pitch && b < surface->h && + c < surface->pitch && d < surface->h) + { + Uint8 *vga = (Uint8 *)surface->pixels; + int i, j, width; + + width = c - a + 1; + + for (i = b * surface->pitch + a; i <= d * surface->pitch + a; i += surface->pitch) + { + for (j = 0; j < width; j++) + { + vga[i + j] = ((vga[i + j] & 0x0F) >> 1) | (vga[i + j] & 0xF0); + } + } + } else { + printf("!!! WARNING: Darker Rectangle clipped: %d %d %d %d\n", a,b,c,d); + } +} + +void JE_barBright( SDL_Surface *surface, int a, int b, int c, int d ) /* x1, y1, x2, y2 */ +{ + if (a < surface->pitch && b < surface->h && + c < surface->pitch && d < surface->h) + { + Uint8 *vga = (Uint8 *)surface->pixels; + int i, j, width; + + width = c-a+1; + + for (i = b * surface->pitch + a; i <= d * surface->pitch + a; i += surface->pitch) + { + for (j = 0; j < width; j++) + { + JE_byte al, ah; + al = ah = vga[i + j]; + + ah &= 0xF0; + al = (al & 0x0F) + 2; + + if (al > 0x0F) + { + al = 0x0F; + } + + vga[i + j] = al + ah; + } + } + } else { + printf("!!! WARNING: Brighter Rectangle clipped: %d %d %d %d\n", a,b,c,d); + } +} + +void draw_segmented_gauge( SDL_Surface *surface, int x, int y, Uint8 color, uint segment_width, uint segment_height, uint segment_value, uint value ) +{ + assert(segment_width > 0 && segment_height > 0); + + const uint segments = value / segment_value, + partial_segment = value % segment_value; + + for (uint i = 0; i < segments; ++i) + { + fill_rectangle_hw(surface, x, y, segment_width, segment_height, color + 12); + x += segment_width + 1; + } + if (partial_segment > 0) + fill_rectangle_hw(surface, x, y, segment_width, segment_height, color + (12 * partial_segment / segment_value)); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/vga256d.h b/alienblaster/project/jni/application/opentyrian/src/vga256d.h new file mode 100644 index 000000000..80215d868 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/vga256d.h @@ -0,0 +1,43 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef VGA256D_H +#define VGA256D_H + +#include "opentyr.h" + +void JE_pix( SDL_Surface *surface, int x, int y, JE_byte c ); +void JE_pix3( SDL_Surface *surface, int x, int y, JE_byte c ); +void JE_rectangle( SDL_Surface *surface, int a, int b, int c, int d, int e ); + +void fill_rectangle_xy( SDL_Surface *, int x, int y, int x2, int y2, Uint8 color ); + +void JE_barShade( SDL_Surface *surface, int a, int b, int c, int d ); +void JE_barBright( SDL_Surface *surface, int a, int b, int c, int d ); + +static inline void fill_rectangle_hw( SDL_Surface *surface, int x, int y, uint h, uint w, Uint8 color ) +{ + SDL_Rect rect = { x, y, h, w }; + SDL_FillRect(surface, &rect, color); +} + +void draw_segmented_gauge( SDL_Surface *surface, int x, int y, Uint8 color, uint segment_width, uint segment_height, uint segment_value, uint value ); + +#endif /* VGA256D_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/vga_palette.cpp b/alienblaster/project/jni/application/opentyrian/src/vga_palette.cpp new file mode 100644 index 000000000..ce3cf6184 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/vga_palette.cpp @@ -0,0 +1,71 @@ +#include "vga_palette.h" + +// only used for the jukebox + +Palette vga_palette = +{ + { 0, 0, 0}, { 0, 0, 168}, { 0, 168, 0}, { 0, 168, 168}, + {168, 0, 0}, {168, 0, 168}, {168, 84, 0}, {168, 168, 168}, + { 84, 84, 84}, { 84, 84, 252}, { 84, 252, 84}, { 84, 252, 252}, + {252, 84, 84}, {252, 84, 252}, {252, 252, 84}, {252, 252, 252}, + { 0, 0, 0}, { 20, 20, 20}, { 32, 32, 32}, { 44, 44, 44}, + { 56, 56, 56}, { 68, 68, 68}, { 80, 80, 80}, { 96, 96, 96}, + {112, 112, 112}, {128, 128, 128}, {144, 144, 144}, {160, 160, 160}, + {180, 180, 180}, {200, 200, 200}, {224, 224, 224}, {252, 252, 252}, + { 0, 0, 252}, { 64, 0, 252}, {124, 0, 252}, {188, 0, 252}, + {252, 0, 252}, {252, 0, 188}, {252, 0, 124}, {252, 0, 64}, + {252, 0, 0}, {252, 64, 0}, {252, 124, 0}, {252, 188, 0}, + {252, 252, 0}, {188, 252, 0}, {124, 252, 0}, { 64, 252, 0}, + { 0, 252, 0}, { 0, 252, 64}, { 0, 252, 124}, { 0, 252, 188}, + { 0, 252, 252}, { 0, 188, 252}, { 0, 124, 252}, { 0, 64, 252}, + {124, 124, 252}, {156, 124, 252}, {188, 124, 252}, {220, 124, 252}, + {252, 124, 252}, {252, 124, 220}, {252, 124, 188}, {252, 124, 156}, + {252, 124, 124}, {252, 156, 124}, {252, 188, 124}, {252, 220, 124}, + {252, 252, 124}, {220, 252, 124}, {188, 252, 124}, {156, 252, 124}, + {124, 252, 124}, {124, 252, 156}, {124, 252, 188}, {124, 252, 220}, + {124, 252, 252}, {124, 220, 252}, {124, 188, 252}, {124, 156, 252}, + {180, 180, 252}, {196, 180, 252}, {216, 180, 252}, {232, 180, 252}, + {252, 180, 252}, {252, 180, 232}, {252, 180, 216}, {252, 180, 196}, + {252, 180, 180}, {252, 196, 180}, {252, 216, 180}, {252, 232, 180}, + {252, 252, 180}, {232, 252, 180}, {216, 252, 180}, {196, 252, 180}, + {180, 252, 180}, {180, 252, 196}, {180, 252, 216}, {180, 252, 232}, + {180, 252, 252}, {180, 232, 252}, {180, 216, 252}, {180, 196, 252}, + { 0, 0, 112}, { 28, 0, 112}, { 56, 0, 112}, { 84, 0, 112}, + {112, 0, 112}, {112, 0, 84}, {112, 0, 56}, {112, 0, 28}, + {112, 0, 0}, {112, 28, 0}, {112, 56, 0}, {112, 84, 0}, + {112, 112, 0}, { 84, 112, 0}, { 56, 112, 0}, { 28, 112, 0}, + { 0, 112, 0}, { 0, 112, 28}, { 0, 112, 56}, { 0, 112, 84}, + { 0, 112, 112}, { 0, 84, 112}, { 0, 56, 112}, { 0, 28, 112}, + { 56, 56, 112}, { 68, 56, 112}, { 84, 56, 112}, { 96, 56, 112}, + {112, 56, 112}, {112, 56, 96}, {112, 56, 84}, {112, 56, 68}, + {112, 56, 56}, {112, 68, 56}, {112, 84, 56}, {112, 96, 56}, + {112, 112, 56}, { 96, 112, 56}, { 84, 112, 56}, { 68, 112, 56}, + { 56, 112, 56}, { 56, 112, 68}, { 56, 112, 84}, { 56, 112, 96}, + { 56, 112, 112}, { 56, 96, 112}, { 56, 84, 112}, { 56, 68, 112}, + { 80, 80, 112}, { 88, 80, 112}, { 96, 80, 112}, {104, 80, 112}, + {112, 80, 112}, {112, 80, 104}, {112, 80, 96}, {112, 80, 88}, + {112, 80, 80}, {112, 88, 80}, {112, 96, 80}, {112, 104, 80}, + {112, 112, 80}, {104, 112, 80}, { 96, 112, 80}, { 88, 112, 80}, + { 80, 112, 80}, { 80, 112, 88}, { 80, 112, 96}, { 80, 112, 104}, + { 80, 112, 112}, { 80, 104, 112}, { 80, 96, 112}, { 80, 88, 112}, + { 0, 0, 64}, { 16, 0, 64}, { 32, 0, 64}, { 48, 0, 64}, + { 64, 0, 64}, { 64, 0, 48}, { 64, 0, 32}, { 64, 0, 16}, + { 64, 0, 0}, { 64, 16, 0}, { 64, 32, 0}, { 64, 48, 0}, + { 64, 64, 0}, { 48, 64, 0}, { 32, 64, 0}, { 16, 64, 0}, + { 0, 64, 0}, { 0, 64, 16}, { 0, 64, 32}, { 0, 64, 48}, + { 0, 64, 64}, { 0, 48, 64}, { 0, 32, 64}, { 0, 16, 64}, + { 32, 32, 64}, { 40, 32, 64}, { 48, 32, 64}, { 56, 32, 64}, + { 64, 32, 64}, { 64, 32, 56}, { 64, 32, 48}, { 64, 32, 40}, + { 64, 32, 32}, { 64, 40, 32}, { 64, 48, 32}, { 64, 56, 32}, + { 64, 64, 32}, { 56, 64, 32}, { 48, 64, 32}, { 40, 64, 32}, + { 32, 64, 32}, { 32, 64, 40}, { 32, 64, 48}, { 32, 64, 56}, + { 32, 64, 64}, { 32, 56, 64}, { 32, 48, 64}, { 32, 40, 64}, + { 44, 44, 64}, { 48, 44, 64}, { 52, 44, 64}, { 60, 44, 64}, + { 64, 44, 64}, { 64, 44, 60}, { 64, 44, 52}, { 64, 44, 48}, + { 64, 44, 44}, { 64, 48, 44}, { 64, 52, 44}, { 64, 60, 44}, + { 64, 64, 44}, { 60, 64, 44}, { 52, 64, 44}, { 48, 64, 44}, + { 44, 64, 44}, { 44, 64, 48}, { 44, 64, 52}, { 44, 64, 60}, + { 44, 64, 64}, { 44, 60, 64}, { 44, 52, 64}, { 44, 48, 64}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0} +}; diff --git a/alienblaster/project/jni/application/opentyrian/src/vga_palette.h b/alienblaster/project/jni/application/opentyrian/src/vga_palette.h new file mode 100644 index 000000000..19f28e3e9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/vga_palette.h @@ -0,0 +1,8 @@ +#ifndef VGA_PALETTE_H +#define VGA_PALETTE_H + +#include "palette.h" + +extern Palette vga_palette; + +#endif // VGA_PALETTE_H diff --git a/alienblaster/project/jni/application/opentyrian/src/video.cpp b/alienblaster/project/jni/application/opentyrian/src/video.cpp new file mode 100644 index 000000000..154aeddc9 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/video.cpp @@ -0,0 +1,187 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "keyboard.h" +#include "opentyr.h" +#include "palette.h" +#include "video.h" +#include "video_scale.h" + +#include +#include + +bool fullscreen_enabled = false; + +SDL_Surface *VGAScreen, *VGAScreenSeg; +SDL_Surface *VGAScreen2; +SDL_Surface *game_screen; + +static ScalerFunction scaler_function; + +void init_video( void ) +{ + if (SDL_WasInit(SDL_INIT_VIDEO)) + return; + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) + { + fprintf(stderr, "error: failed to initialize SDL video: %s\n", SDL_GetError()); + exit(1); + } + + SDL_WM_SetCaption("OpenTyrian", NULL); + + VGAScreen = VGAScreenSeg = SDL_CreateRGBSurface(SDL_SWSURFACE, vga_width, vga_height, 8, 0, 0, 0, 0); + VGAScreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, vga_width, vga_height, 8, 0, 0, 0, 0); + game_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, vga_width, vga_height, 8, 0, 0, 0, 0); + + SDL_FillRect(VGAScreen, NULL, 0); + + if (!init_scaler(scaler, fullscreen_enabled) && // try desired scaler and desired fullscreen state + !init_any_scaler(fullscreen_enabled) && // try any scaler in desired fullscreen state + !init_any_scaler(!fullscreen_enabled)) // try any scaler in other fullscreen state + { + exit(EXIT_FAILURE); + } +} + +int can_init_scaler( unsigned int new_scaler, bool fullscreen ) +{ + if (new_scaler >= scalers_count) + return false; + + int w = scalers[new_scaler].width, + h = scalers[new_scaler].height; + int flags = SDL_SWSURFACE | SDL_HWPALETTE | (fullscreen ? SDL_FULLSCREEN : 0); + + // test each bitdepth + for (uint bpp = 32; bpp > 0; bpp -= 8) + { + uint temp_bpp = SDL_VideoModeOK(w, h, bpp, flags); + + if ((temp_bpp == 32 && scalers[new_scaler].scaler32) || + (temp_bpp == 16 && scalers[new_scaler].scaler16) || + (temp_bpp == 8 && scalers[new_scaler].scaler8 )) + { + return temp_bpp; + } + else if (temp_bpp == 24 && scalers[new_scaler].scaler32) + { + // scalers don't support 24 bpp because it's a pain + // so let SDL handle the conversion + return 32; + } + } + + return 0; +} + +bool init_scaler( unsigned int new_scaler, bool fullscreen ) +{ + int w = scalers[new_scaler].width, + h = scalers[new_scaler].height; + int bpp = can_init_scaler(new_scaler, fullscreen); + int flags = SDL_SWSURFACE | SDL_HWPALETTE | (fullscreen ? SDL_FULLSCREEN : 0); + + if (bpp == 0) + return false; + + SDL_Surface *const surface = SDL_SetVideoMode(w, h, bpp, flags); + + if (surface == NULL) + { + fprintf(stderr, "error: failed to initialize video mode %dx%dx%d: %s\n", w, h, bpp, SDL_GetError()); + return false; + } + + w = surface->w; + h = surface->h; + bpp = surface->format->BitsPerPixel; + + printf("initialized video: %dx%dx%d\n", w, h, bpp); + + scaler = new_scaler; + fullscreen_enabled = fullscreen; + + switch (bpp) + { + case 32: + scaler_function = scalers[scaler].scaler32; + break; + case 16: + scaler_function = scalers[scaler].scaler16; + break; + case 8: + scaler_function = scalers[scaler].scaler8; + break; + default: + scaler_function = NULL; + break; + } + + if (scaler_function == NULL) + { + assert(false); + return false; + } + + input_grab(); + + JE_showVGA(); + + return true; +} + +bool init_any_scaler( bool fullscreen ) +{ + // attempts all scalers from last to first + for (int i = scalers_count - 1; i >= 0; --i) + if (init_scaler(i, fullscreen)) + return true; + + return false; +} + +void deinit_video( void ) +{ + SDL_FreeSurface(VGAScreenSeg); + SDL_FreeSurface(VGAScreen2); + SDL_FreeSurface(game_screen); + + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} + +void JE_clr256( SDL_Surface * screen) +{ + memset(screen->pixels, 0, screen->pitch * screen->h); +} +void JE_showVGA( void ) { scale_and_flip(VGAScreen); } + +void scale_and_flip( SDL_Surface *src_surface ) +{ + assert(src_surface->format->BitsPerPixel == 8); + + SDL_Surface *dst_surface = SDL_GetVideoSurface(); + + assert(scaler_function != NULL); + scaler_function(src_surface, dst_surface); + + SDL_Flip(dst_surface); +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/video.h b/alienblaster/project/jni/application/opentyrian/src/video.h new file mode 100644 index 000000000..f0bb35f4a --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/video.h @@ -0,0 +1,47 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef VIDEO_H +#define VIDEO_H + +#include "opentyr.h" + +#include "SDL.h" + +#define vga_width 320 +#define vga_height 200 + +extern bool fullscreen_enabled; + +extern SDL_Surface *VGAScreen, *VGAScreenSeg; +extern SDL_Surface *game_screen; +extern SDL_Surface *VGAScreen2; + +void init_video( void ); + +int can_init_scaler( unsigned int new_scaler, bool fullscreen ); +bool init_scaler( unsigned int new_scaler, bool fullscreen ); +bool init_any_scaler( bool fullscreen ); +void deinit_video( void ); +void JE_clr256( SDL_Surface * ); +void JE_showVGA( void ); +void scale_and_flip( SDL_Surface * ); + +#endif /* VIDEO_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/video_scale.cpp b/alienblaster/project/jni/application/opentyrian/src/video_scale.cpp new file mode 100644 index 000000000..ca1c0fbf2 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/video_scale.cpp @@ -0,0 +1,442 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2010 The OpenTyrian Development Team + * + * Scale2x, Scale3x + * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "video_scale.h" + +#include "palette.h" +#include "video.h" + +#include + +static void no_scale( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +static void nn_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +static void nn_16( SDL_Surface *src_surface, SDL_Surface *dst_surface ); + +static void scale2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +static void scale2x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +static void scale3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +static void scale3x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface ); + +void hq2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +void hq3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +void hq4x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); + +uint scaler; + +const struct Scalers scalers[] = +{ +#ifdef ANDROID + { vga_width, vga_height, no_scale, nn_16, nn_32, "None" }, +#endif +#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) + { 320, 240, no_scale, nn_16, nn_32, "None" }, +#else + { 1 * vga_width, 1 * vga_height, no_scale, nn_16, nn_32, "None" }, + { 2 * vga_width, 2 * vga_height, NULL, nn_16, nn_32, "2x" }, + { 2 * vga_width, 2 * vga_height, NULL, scale2x_16, scale2x_32, "Scale2x" }, + { 2 * vga_width, 2 * vga_height, NULL, NULL, hq2x_32, "hq2x" }, + { 3 * vga_width, 3 * vga_height, NULL, nn_16, nn_32, "3x" }, + { 3 * vga_width, 3 * vga_height, NULL, scale3x_16, scale3x_32, "Scale3x" }, + { 3 * vga_width, 3 * vga_height, NULL, NULL, hq3x_32, "hq3x" }, + { 4 * vga_width, 4 * vga_height, NULL, nn_16, nn_32, "4x" }, + { 4 * vga_width, 4 * vga_height, NULL, NULL, hq4x_32, "hq4x" }, +#endif +}; +const uint scalers_count = COUNTOF(scalers); + +void set_scaler_by_name( const char *name ) +{ + for (uint i = 0; i < scalers_count; ++i) + { + if (strcmp(name, scalers[i].name) == 0) + { + scaler = i; + break; + } + } +} + +#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) +#define VGA_CENTERED +#endif + +void no_scale( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, + *dst = (Uint8 *)dst_surface->pixels; + +#ifdef VGA_CENTERED + size_t blank = (dst_surface->h - src_surface->h) / 2 * dst_surface->pitch; + memset(dst, 0, blank); + dst += blank; +#endif + + memcpy(dst, src, src_surface->pitch * src_surface->h); + +#ifdef VGA_CENTERED + dst += src_surface->pitch * src_surface->h; + memset(dst, 0, blank); +#endif +} + + +void nn_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width, // src_surface->w + scale = dst_surface->w / width; + assert(scale == dst_surface->h / height); + +#ifdef VGA_CENTERED + size_t blank = (dst_surface->h - src_surface->h) / 2 * dst_surface->pitch; + memset(dst, 0, blank); + dst += blank; +#endif + + for (int y = height; y > 0; y--) + { + src_temp = src; + dst_temp = dst; + + for (int x = width; x > 0; x--) + { + for (int z = scale; z > 0; z--) + { + *(Uint32 *)dst = rgb_palette[*src]; + dst += dst_Bpp; + } + src++; + } + + src = src_temp + src_pitch; + dst = dst_temp + dst_pitch; + + for (int z = scale; z > 1; z--) + { + memcpy(dst, dst_temp, dst_pitch); + dst += dst_pitch; + } + } + +#ifdef VGA_CENTERED + memset(dst, 0, blank); +#endif +} + +void nn_16( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 2; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width, // src_surface->w + scale = dst_surface->w / width; + assert(scale == dst_surface->h / height); + +#ifdef VGA_CENTERED + size_t blank = (dst_surface->h - src_surface->h) / 2 * dst_surface->pitch; + memset(dst, 0, blank); + dst += blank; +#endif + + for (int y = height; y > 0; y--) + { + src_temp = src; + dst_temp = dst; + + for (int x = width; x > 0; x--) + { + for (int z = scale; z > 0; z--) + { + *(Uint16 *)dst = rgb_palette[*src]; + dst += dst_Bpp; + } + src++; + } + + src = src_temp + src_pitch; + dst = dst_temp + dst_pitch; + + for (int z = scale; z > 1; z--) + { + memcpy(dst, dst_temp, dst_pitch); + dst += dst_pitch; + } + } + +#ifdef VGA_CENTERED + memset(dst, 0, blank); +#endif +} + + +void scale2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint32 E0, E1, E2, E3, B, D, E, F, H; + for (int y = 0; y < height; y++) + { + src_temp = src; + dst_temp = dst; + + prevline = (y > 0) ? -src_pitch : 0; + nextline = (y < height - 1) ? src_pitch : 0; + + for (int x = 0; x < width; x++) + { + B = rgb_palette[*(src + prevline)]; + D = rgb_palette[*(x > 0 ? src - 1 : src)]; + E = rgb_palette[*src]; + F = rgb_palette[*(x < width - 1 ? src + 1 : src)]; + H = rgb_palette[*(src + nextline)]; + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = B == F ? F : E; + E2 = D == H ? D : E; + E3 = H == F ? F : E; + } else { + E0 = E1 = E2 = E3 = E; + } + + *(Uint32 *)dst = E0; + *(Uint32 *)(dst + dst_Bpp) = E1; + *(Uint32 *)(dst + dst_pitch) = E2; + *(Uint32 *)(dst + dst_pitch + dst_Bpp) = E3; + + src++; + dst += 2 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 2 * dst_pitch; + } +} + +void scale2x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 2; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint16 E0, E1, E2, E3, B, D, E, F, H; + for (int y = 0; y < height; y++) + { + src_temp = src; + dst_temp = dst; + + prevline = (y > 0) ? -src_pitch : 0; + nextline = (y < height - 1) ? src_pitch : 0; + + for (int x = 0; x < width; x++) + { + B = rgb_palette[*(src + prevline)]; + D = rgb_palette[*(x > 0 ? src - 1 : src)]; + E = rgb_palette[*src]; + F = rgb_palette[*(x < width - 1 ? src + 1 : src)]; + H = rgb_palette[*(src + nextline)]; + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = B == F ? F : E; + E2 = D == H ? D : E; + E3 = H == F ? F : E; + } else { + E0 = E1 = E2 = E3 = E; + } + + *(Uint16 *)dst = E0; + *(Uint16 *)(dst + dst_Bpp) = E1; + *(Uint16 *)(dst + dst_pitch) = E2; + *(Uint16 *)(dst + dst_pitch + dst_Bpp) = E3; + + src++; + dst += 2 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 2 * dst_pitch; + } +} + + +void scale3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint32 E0, E1, E2, E3, E4, E5, E6, E7, E8, A, B, C, D, E, F, G, H, I; + for (int y = 0; y < height; y++) + { + src_temp = src; + dst_temp = dst; + + prevline = (y > 0) ? -src_pitch : 0; + nextline = (y < height - 1) ? src_pitch : 0; + + for (int x = 0; x < width; x++) + { + A = rgb_palette[*(src + prevline - (x > 0 ? 1 : 0))]; + B = rgb_palette[*(src + prevline)]; + C = rgb_palette[*(src + prevline + (x < width - 1 ? 1 : 0))]; + D = rgb_palette[*(src - (x > 0 ? 1 : 0))]; + E = rgb_palette[*src]; + F = rgb_palette[*(src + (x < width - 1 ? 1 : 0))]; + G = rgb_palette[*(src + nextline - (x > 0 ? 1 : 0))]; + H = rgb_palette[*(src + nextline)]; + I = rgb_palette[*(src + nextline + (x < width - 1 ? 1 : 0))]; + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = (D == B && E != C) || (B == F && E != A) ? B : E; + E2 = B == F ? F : E; + E3 = (D == B && E != G) || (D == H && E != A) ? D : E; + E4 = E; + E5 = (B == F && E != I) || (H == F && E != C) ? F : E; + E6 = D == H ? D : E; + E7 = (D == H && E != I) || (H == F && E != G) ? H : E; + E8 = H == F ? F : E; + } else { + E0 = E1 = E2 = E3 = E4 = E5 = E6 = E7 = E8 = E; + } + + *(Uint32 *)dst = E0; + *(Uint32 *)(dst + dst_Bpp) = E1; + *(Uint32 *)(dst + 2 * dst_Bpp) = E2; + *(Uint32 *)(dst + dst_pitch) = E3; + *(Uint32 *)(dst + dst_pitch + dst_Bpp) = E4; + *(Uint32 *)(dst + dst_pitch + 2 * dst_Bpp) = E5; + *(Uint32 *)(dst + 2 * dst_pitch) = E6; + *(Uint32 *)(dst + 2 * dst_pitch + dst_Bpp) = E7; + *(Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp) = E8; + + src++; + dst += 3 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 3 * dst_pitch; + } +} + +void scale3x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 2; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint16 E0, E1, E2, E3, E4, E5, E6, E7, E8, A, B, C, D, E, F, G, H, I; + for (int y = 0; y < height; y++) + { + src_temp = src; + dst_temp = dst; + + prevline = (y > 0) ? -src_pitch : 0; + nextline = (y < height - 1) ? src_pitch : 0; + + for (int x = 0; x < width; x++) + { + A = rgb_palette[*(src + prevline - (x > 0 ? 1 : 0))]; + B = rgb_palette[*(src + prevline)]; + C = rgb_palette[*(src + prevline + (x < width - 1 ? 1 : 0))]; + D = rgb_palette[*(src - (x > 0 ? 1 : 0))]; + E = rgb_palette[*src]; + F = rgb_palette[*(src + (x < width - 1 ? 1 : 0))]; + G = rgb_palette[*(src + nextline - (x > 0 ? 1 : 0))]; + H = rgb_palette[*(src + nextline)]; + I = rgb_palette[*(src + nextline + (x < width - 1 ? 1 : 0))]; + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = (D == B && E != C) || (B == F && E != A) ? B : E; + E2 = B == F ? F : E; + E3 = (D == B && E != G) || (D == H && E != A) ? D : E; + E4 = E; + E5 = (B == F && E != I) || (H == F && E != C) ? F : E; + E6 = D == H ? D : E; + E7 = (D == H && E != I) || (H == F && E != G) ? H : E; + E8 = H == F ? F : E; + } else { + E0 = E1 = E2 = E3 = E4 = E5 = E6 = E7 = E8 = E; + } + + *(Uint16 *)dst = E0; + *(Uint16 *)(dst + dst_Bpp) = E1; + *(Uint16 *)(dst + 2 * dst_Bpp) = E2; + *(Uint16 *)(dst + dst_pitch) = E3; + *(Uint16 *)(dst + dst_pitch + dst_Bpp) = E4; + *(Uint16 *)(dst + dst_pitch + 2 * dst_Bpp) = E5; + *(Uint16 *)(dst + 2 * dst_pitch) = E6; + *(Uint16 *)(dst + 2 * dst_pitch + dst_Bpp) = E7; + *(Uint16 *)(dst + 2 * dst_pitch + 2 * dst_Bpp) = E8; + + src++; + dst += 3 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 3 * dst_pitch; + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/video_scale.h b/alienblaster/project/jni/application/opentyrian/src/video_scale.h new file mode 100644 index 000000000..27a014bd7 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/video_scale.h @@ -0,0 +1,43 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2010 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef VIDEO_SCALE_H +#define VIDEO_SCALE_H + +#include "opentyr.h" + +#include "SDL.h" + +typedef void (*ScalerFunction)( SDL_Surface *dst, SDL_Surface *src ); + +struct Scalers +{ + int width, height; + ScalerFunction scaler8, scaler16, scaler32; + const char *name; +}; + +extern uint scaler; +extern const struct Scalers scalers[]; +extern const uint scalers_count; + +void set_scaler_by_name( const char *name ); + +#endif /* VIDEO_SCALE_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/video_scale_hqNx.cpp b/alienblaster/project/jni/application/opentyrian/src/video_scale_hqNx.cpp new file mode 100644 index 000000000..e926a382f --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/video_scale_hqNx.cpp @@ -0,0 +1,11896 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2010 The OpenTyrian Development Team + * + * hq2x, hq3x, hq4x + * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "palette.h" +#include "video.h" + +void interp1(Uint32 *pc, Uint32 c1, Uint32 c2); +void interp2(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3); +void interp3(Uint32 *pc, Uint32 c1, Uint32 c2); +void interp4(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3); +void interp5(Uint32 *pc, Uint32 c1, Uint32 c2); +void interp6(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3); +void interp7(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3); +void interp8(Uint32 *pc, Uint32 c1, Uint32 c2); +void interp9(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3); +void interp10(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3); +bool diff(unsigned int w1, unsigned int w2); + +void hq2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +void hq3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); +void hq4x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ); + +static int YUV1, YUV2; +const int Ymask = 0x00FF0000; +const int Umask = 0x0000FF00; +const int Vmask = 0x000000FF; +const int trY = 0x00300000; +const int trU = 0x00000700; +const int trV = 0x00000006; + +inline void interp1(Uint32 *pc, Uint32 c1, Uint32 c2) +{ + *pc = (c1*3+c2) >> 2; +} + +inline void interp2(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3) +{ + *pc = (c1*2+c2+c3) >> 2; +} + +inline void interp3(Uint32 *pc, Uint32 c1, Uint32 c2) +{ + //*((int*)pc) = (c1*7+c2)/8; + + *((int*)pc) = ((((c1 & 0x00FF00)*7 + (c2 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*7 + (c2 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void interp4(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3) +{ + //*((int*)pc) = (c1*2+(c2+c3)*7)/16; + + *((int*)pc) = ((((c1 & 0x00FF00)*2 + ((c2 & 0x00FF00) + (c3 & 0x00FF00))*7 ) & 0x000FF000) + + (((c1 & 0xFF00FF)*2 + ((c2 & 0xFF00FF) + (c3 & 0xFF00FF))*7 ) & 0x0FF00FF0)) >> 4; +} + +inline void interp5(Uint32 *pc, Uint32 c1, Uint32 c2) +{ + *pc = (c1+c2) >> 1; +} + +inline void interp6(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3) +{ + //*pc = (c1*5+c2*2+c3)/8; + + *pc = ((((c1 & 0x00FF00)*5 + (c2 & 0x00FF00)*2 + (c3 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*5 + (c2 & 0xFF00FF)*2 + (c3 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void interp7(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3) +{ + //*pc = (c1*6+c2+c3)/8; + + *pc = ((((c1 & 0x00FF00)*6 + (c2 & 0x00FF00) + (c3 & 0x00FF00) ) & 0x0007F800) + + (((c1 & 0xFF00FF)*6 + (c2 & 0xFF00FF) + (c3 & 0xFF00FF) ) & 0x07F807F8)) >> 3; +} + +inline void interp8(Uint32 *pc, Uint32 c1, Uint32 c2) +{ + //*pc = (c1*5+c2*3)/8; + + *pc = ((((c1 & 0x00FF00)*5 + (c2 & 0x00FF00)*3 ) & 0x0007F800) + + (((c1 & 0xFF00FF)*5 + (c2 & 0xFF00FF)*3 ) & 0x07F807F8)) >> 3; +} + +inline void interp9(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3) +{ + //*pc = (c1*2+(c2+c3)*3)/8; + + *pc = ((((c1 & 0x00FF00)*2 + ((c2 & 0x00FF00) + (c3 & 0x00FF00))*3 ) & 0x0007F800) + + (((c1 & 0xFF00FF)*2 + ((c2 & 0xFF00FF) + (c3 & 0xFF00FF))*3 ) & 0x07F807F8)) >> 3; +} + +inline void interp10(Uint32 *pc, Uint32 c1, Uint32 c2, Uint32 c3) +{ + //*pc = (c1*14+c2+c3)/16; + + *pc = ((((c1 & 0x00FF00)*14 + (c2 & 0x00FF00) + (c3 & 0x00FF00) ) & 0x000FF000) + + (((c1 & 0xFF00FF)*14 + (c2 & 0xFF00FF) + (c3 & 0xFF00FF) ) & 0x0FF00FF0)) >> 4; +} + +inline bool diff(unsigned int w1, unsigned int w2) +{ + Uint32 YUV1 = yuv_palette[w1]; + Uint32 YUV2 = yuv_palette[w2]; + return ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ); +} + + +#define PIXEL00_0 *(Uint32 *)dst = c[5]; +#define PIXEL00_10 interp1((Uint32 *)dst, c[5], c[1]); +#define PIXEL00_11 interp1((Uint32 *)dst, c[5], c[4]); +#define PIXEL00_12 interp1((Uint32 *)dst, c[5], c[2]); +#define PIXEL00_20 interp2((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL00_21 interp2((Uint32 *)dst, c[5], c[1], c[2]); +#define PIXEL00_22 interp2((Uint32 *)dst, c[5], c[1], c[4]); +#define PIXEL00_60 interp6((Uint32 *)dst, c[5], c[2], c[4]); +#define PIXEL00_61 interp6((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL00_70 interp7((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL00_90 interp9((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL00_100 interp10((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL01_0 *(Uint32 *)(dst + dst_Bpp) = c[5]; +#define PIXEL01_10 interp1((Uint32 *)(dst + dst_Bpp), c[5], c[3]); +#define PIXEL01_11 interp1((Uint32 *)(dst + dst_Bpp), c[5], c[2]); +#define PIXEL01_12 interp1((Uint32 *)(dst + dst_Bpp), c[5], c[6]); +#define PIXEL01_20 interp2((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[6]); +#define PIXEL01_21 interp2((Uint32 *)(dst + dst_Bpp), c[5], c[3], c[6]); +#define PIXEL01_22 interp2((Uint32 *)(dst + dst_Bpp), c[5], c[3], c[2]); +#define PIXEL01_60 interp6((Uint32 *)(dst + dst_Bpp), c[5], c[6], c[2]); +#define PIXEL01_61 interp6((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[6]); +#define PIXEL01_70 interp7((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[6]); +#define PIXEL01_90 interp9((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[6]); +#define PIXEL01_100 interp10((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[6]); +#define PIXEL10_0 *(Uint32 *)(dst + dst_pitch) = c[5]; +#define PIXEL10_10 interp1((Uint32 *)(dst + dst_pitch), c[5], c[7]); +#define PIXEL10_11 interp1((Uint32 *)(dst + dst_pitch), c[5], c[8]); +#define PIXEL10_12 interp1((Uint32 *)(dst + dst_pitch), c[5], c[4]); +#define PIXEL10_20 interp2((Uint32 *)(dst + dst_pitch), c[5], c[8], c[4]); +#define PIXEL10_21 interp2((Uint32 *)(dst + dst_pitch), c[5], c[7], c[4]); +#define PIXEL10_22 interp2((Uint32 *)(dst + dst_pitch), c[5], c[7], c[8]); +#define PIXEL10_60 interp6((Uint32 *)(dst + dst_pitch), c[5], c[4], c[8]); +#define PIXEL10_61 interp6((Uint32 *)(dst + dst_pitch), c[5], c[8], c[4]); +#define PIXEL10_70 interp7((Uint32 *)(dst + dst_pitch), c[5], c[8], c[4]); +#define PIXEL10_90 interp9((Uint32 *)(dst + dst_pitch), c[5], c[8], c[4]); +#define PIXEL10_100 interp10((Uint32 *)(dst + dst_pitch), c[5], c[8], c[4]); +#define PIXEL11_0 *(Uint32 *)(dst + dst_pitch + dst_Bpp) = c[5]; +#define PIXEL11_10 interp1((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[9]); +#define PIXEL11_11 interp1((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[6]); +#define PIXEL11_12 interp1((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[8]); +#define PIXEL11_20 interp2((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[6], c[8]); +#define PIXEL11_21 interp2((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[9], c[8]); +#define PIXEL11_22 interp2((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[9], c[6]); +#define PIXEL11_60 interp6((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[8], c[6]); +#define PIXEL11_61 interp6((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[6], c[8]); +#define PIXEL11_70 interp7((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[6], c[8]); +#define PIXEL11_90 interp9((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[6], c[8]); +#define PIXEL11_100 interp10((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[6], c[8]); + +void hq2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint32 w[10]; + Uint32 c[10]; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (int j = 0; j < height; j++) + { + src_temp = src; + dst_temp = dst; + + prevline = (j > 0) ? -width : 0; + nextline = (j < height - 1) ? width : 0; + + for (int i = 0; i < width; i++) + { + w[2] = *(src + prevline); + w[5] = *src; + w[8] = *(src + nextline); + + if (i > 0) + { + w[1] = *(src + prevline - 1); + w[4] = *(src - 1); + w[7] = *(src + nextline - 1); + } else { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i < width - 1) + { + w[3] = *(src + prevline + 1); + w[6] = *(src + 1); + w[9] = *(src + nextline + 1); + } else { + w[3] = w[2]; + w[6] = w[5]; + w[9] = w[8]; + } + + int pattern = 0; + int flag = 1; + + YUV1 = yuv_palette[w[5]]; + + for (int k=1; k<=9; k++) + { + if (k==5) continue; + + if ( w[k] != w[5] ) + { + YUV2 = yuv_palette[w[k]]; + if ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) + pattern |= flag; + } + flag <<= 1; + } + + for (int k=1; k<=9; k++) + c[k] = rgb_palette[w[k]] & 0xfcfcfcfc; // hq2x has a nasty inability to accept more than 6 bits for each component + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_20 + PIXEL11_20 + break; + } + case 2: + case 34: + case 130: + case 162: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_20 + PIXEL11_20 + break; + } + case 16: + case 17: + case 48: + case 49: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_20 + PIXEL11_21 + break; + } + case 64: + case 65: + case 68: + case 69: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_21 + PIXEL11_22 + break; + } + case 8: + case 12: + case 136: + case 140: + { + PIXEL00_21 + PIXEL01_20 + PIXEL10_22 + PIXEL11_20 + break; + } + case 3: + case 35: + case 131: + case 163: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_20 + PIXEL11_20 + break; + } + case 6: + case 38: + case 134: + case 166: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + break; + } + case 20: + case 21: + case 52: + case 53: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_21 + break; + } + case 144: + case 145: + case 176: + case 177: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_20 + PIXEL11_12 + break; + } + case 192: + case 193: + case 196: + case 197: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_21 + PIXEL11_11 + break; + } + case 96: + case 97: + case 100: + case 101: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_22 + break; + } + case 40: + case 44: + case 168: + case 172: + { + PIXEL00_21 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + break; + } + case 9: + case 13: + case 137: + case 141: + { + PIXEL00_12 + PIXEL01_20 + PIXEL10_22 + PIXEL11_20 + break; + } + case 18: + case 50: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_20 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 80: + case 81: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_20 + } + break; + } + case 72: + case 76: + { + PIXEL00_21 + PIXEL01_20 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 10: + case 138: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_22 + PIXEL11_20 + break; + } + case 66: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_21 + PIXEL11_22 + break; + } + case 24: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_22 + PIXEL11_21 + break; + } + case 7: + case 39: + case 135: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + break; + } + case 148: + case 149: + case 180: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_12 + break; + } + case 224: + case 228: + case 225: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_11 + break; + } + case 41: + case 169: + case 45: + { + PIXEL00_12 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + break; + } + case 22: + case 54: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 208: + case 209: + { + PIXEL00_20 + PIXEL01_22 + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 104: + case 108: + { + PIXEL00_21 + PIXEL01_20 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 11: + case 139: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_22 + PIXEL11_20 + break; + } + case 19: + case 51: + { + if (diff(w[2], w[6])) + { + PIXEL00_11 + PIXEL01_10 + } + else + { + PIXEL00_60 + PIXEL01_90 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 146: + case 178: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_10 + PIXEL11_12 + } + else + { + PIXEL01_90 + PIXEL11_61 + } + PIXEL10_20 + break; + } + case 84: + case 85: + { + PIXEL00_20 + if (diff(w[6], w[8])) + { + PIXEL01_11 + PIXEL11_10 + } + else + { + PIXEL01_60 + PIXEL11_90 + } + PIXEL10_21 + break; + } + case 112: + case 113: + { + PIXEL00_20 + PIXEL01_22 + if (diff(w[6], w[8])) + { + PIXEL10_12 + PIXEL11_10 + } + else + { + PIXEL10_61 + PIXEL11_90 + } + break; + } + case 200: + case 204: + { + PIXEL00_21 + PIXEL01_20 + if (diff(w[8], w[4])) + { + PIXEL10_10 + PIXEL11_11 + } + else + { + PIXEL10_90 + PIXEL11_60 + } + break; + } + case 73: + case 77: + { + if (diff(w[8], w[4])) + { + PIXEL00_12 + PIXEL10_10 + } + else + { + PIXEL00_61 + PIXEL10_90 + } + PIXEL01_20 + PIXEL11_22 + break; + } + case 42: + case 170: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + PIXEL10_11 + } + else + { + PIXEL00_90 + PIXEL10_60 + } + PIXEL01_21 + PIXEL11_20 + break; + } + case 14: + case 142: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + PIXEL01_12 + } + else + { + PIXEL00_90 + PIXEL01_61 + } + PIXEL10_22 + PIXEL11_20 + break; + } + case 67: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_21 + PIXEL11_22 + break; + } + case 70: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_21 + PIXEL11_22 + break; + } + case 28: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_22 + PIXEL11_21 + break; + } + case 152: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_22 + PIXEL11_12 + break; + } + case 194: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_21 + PIXEL11_11 + break; + } + case 98: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_12 + PIXEL11_22 + break; + } + case 56: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_11 + PIXEL11_21 + break; + } + case 25: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_22 + PIXEL11_21 + break; + } + case 26: + case 31: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_22 + PIXEL11_21 + break; + } + case 82: + case 214: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 88: + case 248: + { + PIXEL00_21 + PIXEL01_22 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 74: + case 107: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 27: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + PIXEL10_22 + PIXEL11_21 + break; + } + case 86: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_21 + PIXEL11_10 + break; + } + case 216: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_10 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 106: + { + PIXEL00_10 + PIXEL01_21 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 30: + { + PIXEL00_10 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_22 + PIXEL11_21 + break; + } + case 210: + { + PIXEL00_22 + PIXEL01_10 + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 120: + { + PIXEL00_21 + PIXEL01_22 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 75: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_10 + PIXEL11_22 + break; + } + case 29: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_22 + PIXEL11_21 + break; + } + case 198: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_21 + PIXEL11_11 + break; + } + case 184: + { + PIXEL00_21 + PIXEL01_22 + PIXEL10_11 + PIXEL11_12 + break; + } + case 99: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_12 + PIXEL11_22 + break; + } + case 57: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_11 + PIXEL11_21 + break; + } + case 71: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_21 + PIXEL11_22 + break; + } + case 156: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_22 + PIXEL11_12 + break; + } + case 226: + { + PIXEL00_22 + PIXEL01_21 + PIXEL10_12 + PIXEL11_11 + break; + } + case 60: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_11 + PIXEL11_21 + break; + } + case 195: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_21 + PIXEL11_11 + break; + } + case 102: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_12 + PIXEL11_22 + break; + } + case 153: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_22 + PIXEL11_12 + break; + } + case 58: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 83: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 92: + { + PIXEL00_21 + PIXEL01_11 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 202: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_21 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_11 + break; + } + case 78: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_22 + break; + } + case 154: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_22 + PIXEL11_12 + break; + } + case 114: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 89: + { + PIXEL00_12 + PIXEL01_22 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 90: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 55: + case 23: + { + if (diff(w[2], w[6])) + { + PIXEL00_11 + PIXEL01_0 + } + else + { + PIXEL00_60 + PIXEL01_90 + } + PIXEL10_20 + PIXEL11_21 + break; + } + case 182: + case 150: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_0 + PIXEL11_12 + } + else + { + PIXEL01_90 + PIXEL11_61 + } + PIXEL10_20 + break; + } + case 213: + case 212: + { + PIXEL00_20 + if (diff(w[6], w[8])) + { + PIXEL01_11 + PIXEL11_0 + } + else + { + PIXEL01_60 + PIXEL11_90 + } + PIXEL10_21 + break; + } + case 241: + case 240: + { + PIXEL00_20 + PIXEL01_22 + if (diff(w[6], w[8])) + { + PIXEL10_12 + PIXEL11_0 + } + else + { + PIXEL10_61 + PIXEL11_90 + } + break; + } + case 236: + case 232: + { + PIXEL00_21 + PIXEL01_20 + if (diff(w[8], w[4])) + { + PIXEL10_0 + PIXEL11_11 + } + else + { + PIXEL10_90 + PIXEL11_60 + } + break; + } + case 109: + case 105: + { + if (diff(w[8], w[4])) + { + PIXEL00_12 + PIXEL10_0 + } + else + { + PIXEL00_61 + PIXEL10_90 + } + PIXEL01_20 + PIXEL11_22 + break; + } + case 171: + case 43: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL10_11 + } + else + { + PIXEL00_90 + PIXEL10_60 + } + PIXEL01_21 + PIXEL11_20 + break; + } + case 143: + case 15: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_12 + } + else + { + PIXEL00_90 + PIXEL01_61 + } + PIXEL10_22 + PIXEL11_20 + break; + } + case 124: + { + PIXEL00_21 + PIXEL01_11 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 203: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + PIXEL10_10 + PIXEL11_11 + break; + } + case 62: + { + PIXEL00_10 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 211: + { + PIXEL00_11 + PIXEL01_10 + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 118: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_12 + PIXEL11_10 + break; + } + case 217: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_10 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 110: + { + PIXEL00_10 + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 155: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + PIXEL10_22 + PIXEL11_12 + break; + } + case 188: + { + PIXEL00_21 + PIXEL01_11 + PIXEL10_11 + PIXEL11_12 + break; + } + case 185: + { + PIXEL00_12 + PIXEL01_22 + PIXEL10_11 + PIXEL11_12 + break; + } + case 61: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_11 + PIXEL11_21 + break; + } + case 157: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_22 + PIXEL11_12 + break; + } + case 103: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_12 + PIXEL11_22 + break; + } + case 227: + { + PIXEL00_11 + PIXEL01_21 + PIXEL10_12 + PIXEL11_11 + break; + } + case 230: + { + PIXEL00_22 + PIXEL01_12 + PIXEL10_12 + PIXEL11_11 + break; + } + case 199: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_21 + PIXEL11_11 + break; + } + case 220: + { + PIXEL00_21 + PIXEL01_11 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 158: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_22 + PIXEL11_12 + break; + } + case 234: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_21 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_11 + break; + } + case 242: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 59: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 121: + { + PIXEL00_12 + PIXEL01_22 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 87: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 79: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_22 + break; + } + case 122: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 94: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 218: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 91: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 229: + { + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_11 + break; + } + case 167: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + break; + } + case 173: + { + PIXEL00_12 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + break; + } + case 181: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_12 + break; + } + case 186: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_11 + PIXEL11_12 + break; + } + case 115: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 93: + { + PIXEL00_12 + PIXEL01_11 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 206: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_11 + break; + } + case 205: + case 201: + { + PIXEL00_12 + PIXEL01_20 + if (diff(w[8], w[4])) + { + PIXEL10_10 + } + else + { + PIXEL10_70 + } + PIXEL11_11 + break; + } + case 174: + case 46: + { + if (diff(w[4], w[2])) + { + PIXEL00_10 + } + else + { + PIXEL00_70 + } + PIXEL01_12 + PIXEL10_11 + PIXEL11_20 + break; + } + case 179: + case 147: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_10 + } + else + { + PIXEL01_70 + } + PIXEL10_20 + PIXEL11_12 + break; + } + case 117: + case 116: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_10 + } + else + { + PIXEL11_70 + } + break; + } + case 189: + { + PIXEL00_12 + PIXEL01_11 + PIXEL10_11 + PIXEL11_12 + break; + } + case 231: + { + PIXEL00_11 + PIXEL01_12 + PIXEL10_12 + PIXEL11_11 + break; + } + case 126: + { + PIXEL00_10 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 219: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + PIXEL10_10 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 125: + { + if (diff(w[8], w[4])) + { + PIXEL00_12 + PIXEL10_0 + } + else + { + PIXEL00_61 + PIXEL10_90 + } + PIXEL01_11 + PIXEL11_10 + break; + } + case 221: + { + PIXEL00_12 + if (diff(w[6], w[8])) + { + PIXEL01_11 + PIXEL11_0 + } + else + { + PIXEL01_60 + PIXEL11_90 + } + PIXEL10_10 + break; + } + case 207: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL01_12 + } + else + { + PIXEL00_90 + PIXEL01_61 + } + PIXEL10_10 + PIXEL11_11 + break; + } + case 238: + { + PIXEL00_10 + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_0 + PIXEL11_11 + } + else + { + PIXEL10_90 + PIXEL11_60 + } + break; + } + case 190: + { + PIXEL00_10 + if (diff(w[2], w[6])) + { + PIXEL01_0 + PIXEL11_12 + } + else + { + PIXEL01_90 + PIXEL11_61 + } + PIXEL10_11 + break; + } + case 187: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + PIXEL10_11 + } + else + { + PIXEL00_90 + PIXEL10_60 + } + PIXEL01_10 + PIXEL11_12 + break; + } + case 243: + { + PIXEL00_11 + PIXEL01_10 + if (diff(w[6], w[8])) + { + PIXEL10_12 + PIXEL11_0 + } + else + { + PIXEL10_61 + PIXEL11_90 + } + break; + } + case 119: + { + if (diff(w[2], w[6])) + { + PIXEL00_11 + PIXEL01_0 + } + else + { + PIXEL00_60 + PIXEL01_90 + } + PIXEL10_12 + PIXEL11_10 + break; + } + case 237: + case 233: + { + PIXEL00_12 + PIXEL01_20 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + PIXEL11_11 + break; + } + case 175: + case 47: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + PIXEL01_12 + PIXEL10_11 + PIXEL11_20 + break; + } + case 183: + case 151: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_20 + PIXEL11_12 + break; + } + case 245: + case 244: + { + PIXEL00_20 + PIXEL01_11 + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 250: + { + PIXEL00_10 + PIXEL01_10 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 123: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 95: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_10 + PIXEL11_10 + break; + } + case 222: + { + PIXEL00_10 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_10 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 252: + { + PIXEL00_21 + PIXEL01_11 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 249: + { + PIXEL00_12 + PIXEL01_22 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 235: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_21 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + PIXEL11_11 + break; + } + case 111: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_22 + break; + } + case 63: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_11 + PIXEL11_21 + break; + } + case 159: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_22 + PIXEL11_12 + break; + } + case 215: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_21 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 246: + { + PIXEL00_22 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 254: + { + PIXEL00_10 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 253: + { + PIXEL00_12 + PIXEL01_11 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 251: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + PIXEL01_10 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 239: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + PIXEL01_12 + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + PIXEL11_11 + break; + } + case 127: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_20 + } + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_20 + } + PIXEL11_10 + break; + } + case 191: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_11 + PIXEL11_12 + break; + } + case 223: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_20 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_10 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_20 + } + break; + } + case 247: + { + PIXEL00_11 + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + PIXEL10_12 + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + case 255: + { + if (diff(w[4], w[2])) + { + PIXEL00_0 + } + else + { + PIXEL00_100 + } + if (diff(w[2], w[6])) + { + PIXEL01_0 + } + else + { + PIXEL01_100 + } + if (diff(w[8], w[4])) + { + PIXEL10_0 + } + else + { + PIXEL10_100 + } + if (diff(w[6], w[8])) + { + PIXEL11_0 + } + else + { + PIXEL11_100 + } + break; + } + } + + src++; + dst += 2 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 2 * dst_pitch; + } +} + + +#define PIXEL00_1M interp1((Uint32 *)dst, c[5], c[1]); +#define PIXEL00_1U interp1((Uint32 *)dst, c[5], c[2]); +#define PIXEL00_1L interp1((Uint32 *)dst, c[5], c[4]); +#define PIXEL00_2 interp2((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL00_4 interp4((Uint32 *)dst, c[5], c[4], c[2]); +#define PIXEL00_5 interp5((Uint32 *)dst, c[4], c[2]); +#define PIXEL00_C *(Uint32 *)dst = c[5]; + +#define PIXEL01_1 interp1((Uint32 *)(dst + dst_Bpp), c[5], c[2]); +#define PIXEL01_3 interp3((Uint32 *)(dst + dst_Bpp), c[5], c[2]); +#define PIXEL01_6 interp1((Uint32 *)(dst + dst_Bpp), c[2], c[5]); +#define PIXEL01_C *(Uint32 *)(dst + dst_Bpp) = c[5]; + +#define PIXEL02_1M interp1((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[3]); +#define PIXEL02_1U interp1((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2]); +#define PIXEL02_1R interp1((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL02_2 interp2((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2], c[6]); +#define PIXEL02_4 interp4((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2], c[6]); +#define PIXEL02_5 interp5((Uint32 *)(dst + 2 * dst_Bpp), c[2], c[6]); +#define PIXEL02_C *(Uint32 *)(dst + 2 * dst_Bpp) = c[5]; + +#define PIXEL10_1 interp1((Uint32 *)(dst + dst_pitch), c[5], c[4]); +#define PIXEL10_3 interp3((Uint32 *)(dst + dst_pitch), c[5], c[4]); +#define PIXEL10_6 interp1((Uint32 *)(dst + dst_pitch), c[4], c[5]); +#define PIXEL10_C *(Uint32 *)(dst + dst_pitch) = c[5]; + +#define PIXEL11 *(Uint32 *)(dst + dst_pitch + dst_Bpp) = c[5]; + +#define PIXEL12_1 interp1((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL12_3 interp3((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL12_6 interp1((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[6], c[5]); +#define PIXEL12_C *(Uint32 *)(dst + dst_pitch + 2 * dst_Bpp) = c[5]; + +#define PIXEL20_1M interp1((Uint32 *)(dst + 2 * dst_pitch), c[5], c[7]); +#define PIXEL20_1D interp1((Uint32 *)(dst + 2 * dst_pitch), c[5], c[8]); +#define PIXEL20_1L interp1((Uint32 *)(dst + 2 * dst_pitch), c[5], c[4]); +#define PIXEL20_2 interp2((Uint32 *)(dst + 2 * dst_pitch), c[5], c[8], c[4]); +#define PIXEL20_4 interp4((Uint32 *)(dst + 2 * dst_pitch), c[5], c[8], c[4]); +#define PIXEL20_5 interp5((Uint32 *)(dst + 2 * dst_pitch), c[8], c[4]); +#define PIXEL20_C *(Uint32 *)(dst + 2 * dst_pitch) = c[5]; + +#define PIXEL21_1 interp1((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[5], c[8]); +#define PIXEL21_3 interp3((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[5], c[8]); +#define PIXEL21_6 interp1((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[8], c[5]); +#define PIXEL21_C *(Uint32 *)(dst + 2 * dst_pitch + dst_Bpp) = c[5]; + +#define PIXEL22_1M interp1((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[9]); +#define PIXEL22_1D interp1((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[8]); +#define PIXEL22_1R interp1((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL22_2 interp2((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[6], c[8]); +#define PIXEL22_4 interp4((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[6], c[8]); +#define PIXEL22_5 interp5((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[6], c[8]); +#define PIXEL22_C *(Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp) = c[5]; + +void hq3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint32 w[10]; + Uint32 c[10]; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (int j = 0; j < height; j++) + { + src_temp = src; + dst_temp = dst; + + prevline = (j > 0) ? -width : 0; + nextline = (j < height - 1) ? width : 0; + + for (int i = 0; i < width; i++) + { + w[2] = *(src + prevline); + w[5] = *src; + w[8] = *(src + nextline); + + if (i>0) + { + w[1] = *(src + prevline - 1); + w[4] = *(src - 1); + w[7] = *(src + nextline - 1); + } else { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i < width - 1) + { + w[3] = *(src + prevline + 1); + w[6] = *(src + 1); + w[9] = *(src + nextline + 1); + } else { + w[3] = w[2]; + w[6] = w[5]; + w[9] = w[8]; + } + + int pattern = 0; + int flag = 1; + + YUV1 = yuv_palette[w[5]]; + + for (int k=1; k<=9; k++) + { + if (k==5) continue; + + if ( w[k] != w[5] ) + { + YUV2 = yuv_palette[w[k]]; + if ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) + pattern |= flag; + } + flag <<= 1; + } + + for (int k=1; k<=9; k++) + c[k] = rgb_palette[w[k]] & 0xfcfcfcfc; // hq3x has a nasty inability to accept more than 6 bits for each component + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 2: + case 34: + case 130: + case 162: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 16: + case 17: + case 48: + case 49: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 64: + case 65: + case 68: + case 69: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 8: + case 12: + case 136: + case 140: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 3: + case 35: + case 131: + case 163: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 6: + case 38: + case 134: + case 166: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 20: + case 21: + case 52: + case 53: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 144: + case 145: + case 176: + case 177: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 192: + case 193: + case 196: + case 197: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 96: + case 97: + case 100: + case 101: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 40: + case 44: + case 168: + case 172: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 9: + case 13: + case 137: + case 141: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 18: + case 50: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_1M + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 80: + case 81: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_1M + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 72: + case 76: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_1M + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 10: + case 138: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 66: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 24: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 7: + case 39: + case 135: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 148: + case 149: + case 180: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 224: + case 228: + case 225: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 41: + case 169: + case 45: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 22: + case 54: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 208: + case 209: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 104: + case 108: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 11: + case 139: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 19: + case 51: + { + if (diff(w[2], w[6])) + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL12_C + } + else + { + PIXEL00_2 + PIXEL01_6 + PIXEL02_5 + PIXEL12_1 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 146: + case 178: + { + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_1M + PIXEL12_C + PIXEL22_1D + } + else + { + PIXEL01_1 + PIXEL02_5 + PIXEL12_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + break; + } + case 84: + case 85: + { + if (diff(w[6], w[8])) + { + PIXEL02_1U + PIXEL12_C + PIXEL21_C + PIXEL22_1M + } + else + { + PIXEL02_2 + PIXEL12_6 + PIXEL21_1 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + break; + } + case 112: + case 113: + { + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + } + else + { + PIXEL12_1 + PIXEL20_2 + PIXEL21_6 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + break; + } + case 200: + case 204: + { + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + } + else + { + PIXEL10_1 + PIXEL20_5 + PIXEL21_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + break; + } + case 73: + case 77: + { + if (diff(w[8], w[4])) + { + PIXEL00_1U + PIXEL10_C + PIXEL20_1M + PIXEL21_C + } + else + { + PIXEL00_2 + PIXEL10_6 + PIXEL20_5 + PIXEL21_1 + } + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + break; + } + case 42: + case 170: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + PIXEL01_C + PIXEL10_C + PIXEL20_1D + } + else + { + PIXEL00_5 + PIXEL01_1 + PIXEL10_6 + PIXEL20_2 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + break; + } + case 14: + case 142: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_C + } + else + { + PIXEL00_5 + PIXEL01_6 + PIXEL02_2 + PIXEL10_1 + } + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 67: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 70: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 28: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 152: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 194: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 98: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 56: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 25: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 26: + case 31: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 82: + case 214: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 88: + case 248: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 74: + case 107: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 27: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 86: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 216: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 106: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 30: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 210: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 120: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 75: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 29: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + break; + } + case 198: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 184: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 99: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 57: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 71: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 156: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 226: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 60: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 195: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 102: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 153: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 58: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 83: + { + PIXEL00_1L + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 92: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 202: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 78: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1M + break; + } + case 154: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 114: + { + PIXEL00_1M + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 89: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 90: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 55: + case 23: + { + if (diff(w[2], w[6])) + { + PIXEL00_1L + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL00_2 + PIXEL01_6 + PIXEL02_5 + PIXEL12_1 + } + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + break; + } + case 182: + case 150: + { + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + PIXEL22_1D + } + else + { + PIXEL01_1 + PIXEL02_5 + PIXEL12_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + break; + } + case 213: + case 212: + { + if (diff(w[6], w[8])) + { + PIXEL02_1U + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL02_2 + PIXEL12_6 + PIXEL21_1 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + break; + } + case 241: + case 240: + { + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL20_1L + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_1 + PIXEL20_2 + PIXEL21_6 + PIXEL22_5 + } + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + break; + } + case 236: + case 232: + { + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + PIXEL22_1R + } + else + { + PIXEL10_1 + PIXEL20_5 + PIXEL21_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + break; + } + case 109: + case 105: + { + if (diff(w[8], w[4])) + { + PIXEL00_1U + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL00_2 + PIXEL10_6 + PIXEL20_5 + PIXEL21_1 + } + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + break; + } + case 171: + case 43: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + PIXEL20_1D + } + else + { + PIXEL00_5 + PIXEL01_1 + PIXEL10_6 + PIXEL20_2 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + break; + } + case 143: + case 15: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL02_1R + PIXEL10_C + } + else + { + PIXEL00_5 + PIXEL01_6 + PIXEL02_2 + PIXEL10_1 + } + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + break; + } + case 124: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 203: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 62: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 211: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 118: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 217: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 110: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 155: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 188: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 185: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 61: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 157: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 103: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 227: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 230: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 199: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 220: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 158: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 234: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1R + break; + } + case 242: + { + PIXEL00_1M + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1L + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 59: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 121: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 87: + { + PIXEL00_1L + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 79: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1R + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1M + break; + } + case 122: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 94: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 218: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 91: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 229: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 167: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + break; + } + case 173: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 181: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 186: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 115: + { + PIXEL00_1L + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 93: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 206: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 205: + case 201: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_1M + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 174: + case 46: + { + if (diff(w[4], w[2])) + { + PIXEL00_1M + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 179: + case 147: + { + PIXEL00_1L + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_1M + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 117: + case 116: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_1M + } + else + { + PIXEL22_2 + } + break; + } + case 189: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 231: + { + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + break; + } + case 126: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 219: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL01_3 + PIXEL10_3 + } + PIXEL02_1M + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 125: + { + if (diff(w[8], w[4])) + { + PIXEL00_1U + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL00_2 + PIXEL10_6 + PIXEL20_5 + PIXEL21_1 + } + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + PIXEL22_1M + break; + } + case 221: + { + if (diff(w[6], w[8])) + { + PIXEL02_1U + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL02_2 + PIXEL12_6 + PIXEL21_1 + PIXEL22_5 + } + PIXEL00_1U + PIXEL01_1 + PIXEL10_C + PIXEL11 + PIXEL20_1M + break; + } + case 207: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL02_1R + PIXEL10_C + } + else + { + PIXEL00_5 + PIXEL01_6 + PIXEL02_2 + PIXEL10_1 + } + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + break; + } + case 238: + { + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + PIXEL22_1R + } + else + { + PIXEL10_1 + PIXEL20_5 + PIXEL21_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + break; + } + case 190: + { + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + PIXEL22_1D + } + else + { + PIXEL01_1 + PIXEL02_5 + PIXEL12_6 + PIXEL22_2 + } + PIXEL00_1M + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + break; + } + case 187: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + PIXEL20_1D + } + else + { + PIXEL00_5 + PIXEL01_1 + PIXEL10_6 + PIXEL20_2 + } + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL21_1 + PIXEL22_1D + break; + } + case 243: + { + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL20_1L + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_1 + PIXEL20_2 + PIXEL21_6 + PIXEL22_5 + } + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + break; + } + case 119: + { + if (diff(w[2], w[6])) + { + PIXEL00_1L + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL00_2 + PIXEL01_6 + PIXEL02_5 + PIXEL12_1 + } + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + break; + } + case 237: + case 233: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 175: + case 47: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + break; + } + case 183: + case 151: + { + PIXEL00_1L + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + break; + } + case 245: + case 244: + { + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 250: + { + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 123: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 95: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + break; + } + case 222: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 252: + { + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 249: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 235: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 111: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 63: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + break; + } + case 159: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + break; + } + case 215: + { + PIXEL00_1L + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 246: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 254: + { + PIXEL00_1M + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + } + else + { + PIXEL01_3 + PIXEL02_4 + } + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + } + else + { + PIXEL10_3 + PIXEL20_4 + } + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL21_3 + PIXEL22_2 + } + break; + } + case 253: + { + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 251: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + } + else + { + PIXEL00_4 + PIXEL01_3 + } + PIXEL02_1M + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL10_C + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL10_3 + PIXEL20_2 + PIXEL21_3 + } + if (diff(w[6], w[8])) + { + PIXEL12_C + PIXEL22_C + } + else + { + PIXEL12_3 + PIXEL22_4 + } + break; + } + case 239: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + if (diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + PIXEL22_1R + break; + } + case 127: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL01_C + PIXEL10_C + } + else + { + PIXEL00_2 + PIXEL01_3 + PIXEL10_3 + } + if (diff(w[2], w[6])) + { + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL02_4 + PIXEL12_3 + } + PIXEL11 + if (diff(w[8], w[4])) + { + PIXEL20_C + PIXEL21_C + } + else + { + PIXEL20_4 + PIXEL21_3 + } + PIXEL22_1M + break; + } + case 191: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + break; + } + case 223: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + PIXEL10_C + } + else + { + PIXEL00_4 + PIXEL10_3 + } + if (diff(w[2], w[6])) + { + PIXEL01_C + PIXEL02_C + PIXEL12_C + } + else + { + PIXEL01_3 + PIXEL02_2 + PIXEL12_3 + } + PIXEL11 + PIXEL20_1M + if (diff(w[6], w[8])) + { + PIXEL21_C + PIXEL22_C + } + else + { + PIXEL21_3 + PIXEL22_4 + } + break; + } + case 247: + { + PIXEL00_1L + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + case 255: + { + if (diff(w[4], w[2])) + { + PIXEL00_C + } + else + { + PIXEL00_2 + } + PIXEL01_C + if (diff(w[2], w[6])) + { + PIXEL02_C + } + else + { + PIXEL02_2 + } + PIXEL10_C + PIXEL11 + PIXEL12_C + if (diff(w[8], w[4])) + { + PIXEL20_C + } + else + { + PIXEL20_2 + } + PIXEL21_C + if (diff(w[6], w[8])) + { + PIXEL22_C + } + else + { + PIXEL22_2 + } + break; + } + } + + src++; + dst += 3 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 3 * dst_pitch; + } +} + + +#define PIXEL4_00_0 *(Uint32 *)(dst) = c[5]; +#define PIXEL4_00_11 interp1((Uint32 *)(dst), c[5], c[4]); +#define PIXEL4_00_12 interp1((Uint32 *)(dst), c[5], c[2]); +#define PIXEL4_00_20 interp2((Uint32 *)(dst), c[5], c[2], c[4]); +#define PIXEL4_00_50 interp5((Uint32 *)(dst), c[2], c[4]); +#define PIXEL4_00_80 interp8((Uint32 *)(dst), c[5], c[1]); +#define PIXEL4_00_81 interp8((Uint32 *)(dst), c[5], c[4]); +#define PIXEL4_00_82 interp8((Uint32 *)(dst), c[5], c[2]); +#define PIXEL4_01_0 *(Uint32 *)(dst + dst_Bpp) = c[5]; +#define PIXEL4_01_10 interp1((Uint32 *)(dst + dst_Bpp), c[5], c[1]); +#define PIXEL4_01_12 interp1((Uint32 *)(dst + dst_Bpp), c[5], c[2]); +#define PIXEL4_01_14 interp1((Uint32 *)(dst + dst_Bpp), c[2], c[5]); +#define PIXEL4_01_21 interp2((Uint32 *)(dst + dst_Bpp), c[2], c[5], c[4]); +#define PIXEL4_01_31 interp3((Uint32 *)(dst + dst_Bpp), c[5], c[4]); +#define PIXEL4_01_50 interp5((Uint32 *)(dst + dst_Bpp), c[2], c[5]); +#define PIXEL4_01_60 interp6((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[4]); +#define PIXEL4_01_61 interp6((Uint32 *)(dst + dst_Bpp), c[5], c[2], c[1]); +#define PIXEL4_01_82 interp8((Uint32 *)(dst + dst_Bpp), c[5], c[2]); +#define PIXEL4_01_83 interp8((Uint32 *)(dst + dst_Bpp), c[2], c[4]); +#define PIXEL4_02_0 *(Uint32 *)(dst + 2 * dst_Bpp) = c[5]; +#define PIXEL4_02_10 interp1((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[3]); +#define PIXEL4_02_11 interp1((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2]); +#define PIXEL4_02_13 interp1((Uint32 *)(dst + 2 * dst_Bpp), c[2], c[5]); +#define PIXEL4_02_21 interp2((Uint32 *)(dst + 2 * dst_Bpp), c[2], c[5], c[6]); +#define PIXEL4_02_32 interp3((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL4_02_50 interp5((Uint32 *)(dst + 2 * dst_Bpp), c[2], c[5]); +#define PIXEL4_02_60 interp6((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2], c[6]); +#define PIXEL4_02_61 interp6((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2], c[3]); +#define PIXEL4_02_81 interp8((Uint32 *)(dst + 2 * dst_Bpp), c[5], c[2]); +#define PIXEL4_02_83 interp8((Uint32 *)(dst + 2 * dst_Bpp), c[2], c[6]); +#define PIXEL4_03_0 *(Uint32 *)(dst + 3 * dst_Bpp) = c[5]; +#define PIXEL4_03_11 interp1((Uint32 *)(dst + 3 * dst_Bpp), c[5], c[2]); +#define PIXEL4_03_12 interp1((Uint32 *)(dst + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_03_20 interp2((Uint32 *)(dst + 3 * dst_Bpp), c[5], c[2], c[6]); +#define PIXEL4_03_50 interp5((Uint32 *)(dst + 3 * dst_Bpp), c[2], c[6]); +#define PIXEL4_03_80 interp8((Uint32 *)(dst + 3 * dst_Bpp), c[5], c[3]); +#define PIXEL4_03_81 interp8((Uint32 *)(dst + 3 * dst_Bpp), c[5], c[2]); +#define PIXEL4_03_82 interp8((Uint32 *)(dst + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_10_0 *(Uint32 *)(dst + dst_pitch) = c[5]; +#define PIXEL4_10_10 interp1((Uint32 *)(dst + dst_pitch ), c[5], c[1]); +#define PIXEL4_10_11 interp1((Uint32 *)(dst + dst_pitch ), c[5], c[4]); +#define PIXEL4_10_13 interp1((Uint32 *)(dst + dst_pitch ), c[4], c[5]); +#define PIXEL4_10_21 interp2((Uint32 *)(dst + dst_pitch ), c[4], c[5], c[2]); +#define PIXEL4_10_32 interp3((Uint32 *)(dst + dst_pitch ), c[5], c[2]); +#define PIXEL4_10_50 interp5((Uint32 *)(dst + dst_pitch ), c[4], c[5]); +#define PIXEL4_10_60 interp6((Uint32 *)(dst + dst_pitch ), c[5], c[4], c[2]); +#define PIXEL4_10_61 interp6((Uint32 *)(dst + dst_pitch ), c[5], c[4], c[1]); +#define PIXEL4_10_81 interp8((Uint32 *)(dst + dst_pitch ), c[5], c[4]); +#define PIXEL4_10_83 interp8((Uint32 *)(dst + dst_pitch ), c[4], c[2]); +#define PIXEL4_11_0 *(Uint32 *)(dst + dst_pitch + dst_Bpp) = c[5]; +#define PIXEL4_11_30 interp3((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[1]); +#define PIXEL4_11_31 interp3((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[4]); +#define PIXEL4_11_32 interp3((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[2]); +#define PIXEL4_11_70 interp7((Uint32 *)(dst + dst_pitch + dst_Bpp), c[5], c[4], c[2]); +#define PIXEL4_12_0 *(Uint32 *)(dst + dst_pitch + 2 * dst_Bpp) = c[5]; +#define PIXEL4_12_30 interp3((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[5], c[3]); +#define PIXEL4_12_31 interp3((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[5], c[2]); +#define PIXEL4_12_32 interp3((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL4_12_70 interp7((Uint32 *)(dst + dst_pitch + 2 * dst_Bpp), c[5], c[6], c[2]); +#define PIXEL4_13_0 *(Uint32 *)(dst + dst_pitch + 3 * dst_Bpp) = c[5]; +#define PIXEL4_13_10 interp1((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[5], c[3]); +#define PIXEL4_13_12 interp1((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_13_14 interp1((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[6], c[5]); +#define PIXEL4_13_21 interp2((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[6], c[5], c[2]); +#define PIXEL4_13_31 interp3((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[5], c[2]); +#define PIXEL4_13_50 interp5((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[6], c[5]); +#define PIXEL4_13_60 interp6((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[5], c[6], c[2]); +#define PIXEL4_13_61 interp6((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[5], c[6], c[3]); +#define PIXEL4_13_82 interp8((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_13_83 interp8((Uint32 *)(dst + dst_pitch + 3 * dst_Bpp), c[6], c[2]); +#define PIXEL4_20_0 *(Uint32 *)(dst + 2 * dst_pitch) = c[5]; +#define PIXEL4_20_10 interp1((Uint32 *)(dst + 2 * dst_pitch ), c[5], c[7]); +#define PIXEL4_20_12 interp1((Uint32 *)(dst + 2 * dst_pitch ), c[5], c[4]); +#define PIXEL4_20_14 interp1((Uint32 *)(dst + 2 * dst_pitch ), c[4], c[5]); +#define PIXEL4_20_21 interp2((Uint32 *)(dst + 2 * dst_pitch ), c[4], c[5], c[8]); +#define PIXEL4_20_31 interp3((Uint32 *)(dst + 2 * dst_pitch ), c[5], c[8]); +#define PIXEL4_20_50 interp5((Uint32 *)(dst + 2 * dst_pitch ), c[4], c[5]); +#define PIXEL4_20_60 interp6((Uint32 *)(dst + 2 * dst_pitch ), c[5], c[4], c[8]); +#define PIXEL4_20_61 interp6((Uint32 *)(dst + 2 * dst_pitch ), c[5], c[4], c[7]); +#define PIXEL4_20_82 interp8((Uint32 *)(dst + 2 * dst_pitch ), c[5], c[4]); +#define PIXEL4_20_83 interp8((Uint32 *)(dst + 2 * dst_pitch ), c[4], c[8]); +#define PIXEL4_21_0 *(Uint32 *)(dst + 2 * dst_pitch + dst_Bpp) = c[5]; +#define PIXEL4_21_30 interp3((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[5], c[7]); +#define PIXEL4_21_31 interp3((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[5], c[8]); +#define PIXEL4_21_32 interp3((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[5], c[4]); +#define PIXEL4_21_70 interp7((Uint32 *)(dst + 2 * dst_pitch + dst_Bpp), c[5], c[4], c[8]); +#define PIXEL4_22_0 *(Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp) = c[5]; +#define PIXEL4_22_30 interp3((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[9]); +#define PIXEL4_22_31 interp3((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL4_22_32 interp3((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[8]); +#define PIXEL4_22_70 interp7((Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp), c[5], c[6], c[8]); +#define PIXEL4_23_0 *(Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp) = c[5]; +#define PIXEL4_23_10 interp1((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[5], c[9]); +#define PIXEL4_23_11 interp1((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_23_13 interp1((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[6], c[5]); +#define PIXEL4_23_21 interp2((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[6], c[5], c[8]); +#define PIXEL4_23_32 interp3((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[5], c[8]); +#define PIXEL4_23_50 interp5((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[6], c[5]); +#define PIXEL4_23_60 interp6((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[5], c[6], c[8]); +#define PIXEL4_23_61 interp6((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[5], c[6], c[9]); +#define PIXEL4_23_81 interp8((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_23_83 interp8((Uint32 *)(dst + 2 * dst_pitch + 3 * dst_Bpp), c[6], c[8]); +#define PIXEL4_30_0 *(Uint32 *)(dst + 3 * dst_pitch) = c[5]; +#define PIXEL4_30_11 interp1((Uint32 *)(dst + 3 * dst_pitch ), c[5], c[8]); +#define PIXEL4_30_12 interp1((Uint32 *)(dst + 3 * dst_pitch ), c[5], c[4]); +#define PIXEL4_30_20 interp2((Uint32 *)(dst + 3 * dst_pitch ), c[5], c[8], c[4]); +#define PIXEL4_30_50 interp5((Uint32 *)(dst + 3 * dst_pitch ), c[8], c[4]); +#define PIXEL4_30_80 interp8((Uint32 *)(dst + 3 * dst_pitch ), c[5], c[7]); +#define PIXEL4_30_81 interp8((Uint32 *)(dst + 3 * dst_pitch ), c[5], c[8]); +#define PIXEL4_30_82 interp8((Uint32 *)(dst + 3 * dst_pitch ), c[5], c[4]); +#define PIXEL4_31_0 *(Uint32 *)(dst + 3 * dst_pitch + dst_Bpp) = c[5]; +#define PIXEL4_31_10 interp1((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[5], c[7]); +#define PIXEL4_31_11 interp1((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[5], c[8]); +#define PIXEL4_31_13 interp1((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[8], c[5]); +#define PIXEL4_31_21 interp2((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[8], c[5], c[4]); +#define PIXEL4_31_32 interp3((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[5], c[4]); +#define PIXEL4_31_50 interp5((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[8], c[5]); +#define PIXEL4_31_60 interp6((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[5], c[8], c[4]); +#define PIXEL4_31_61 interp6((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[5], c[8], c[7]); +#define PIXEL4_31_81 interp8((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[5], c[8]); +#define PIXEL4_31_83 interp8((Uint32 *)(dst + 3 * dst_pitch + dst_Bpp), c[8], c[4]); +#define PIXEL4_32_0 *(Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp) = c[5]; +#define PIXEL4_32_10 interp1((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[5], c[9]); +#define PIXEL4_32_12 interp1((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[5], c[8]); +#define PIXEL4_32_14 interp1((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[8], c[5]); +#define PIXEL4_32_21 interp2((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[8], c[5], c[6]); +#define PIXEL4_32_31 interp3((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[5], c[6]); +#define PIXEL4_32_50 interp5((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[8], c[5]); +#define PIXEL4_32_60 interp6((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[5], c[8], c[6]); +#define PIXEL4_32_61 interp6((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[5], c[8], c[9]); +#define PIXEL4_32_82 interp8((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[5], c[8]); +#define PIXEL4_32_83 interp8((Uint32 *)(dst + 3 * dst_pitch + 2 * dst_Bpp), c[8], c[6]); +#define PIXEL4_33_0 *(Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp) = c[5]; +#define PIXEL4_33_11 interp1((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_33_12 interp1((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[5], c[8]); +#define PIXEL4_33_20 interp2((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[5], c[8], c[6]); +#define PIXEL4_33_50 interp5((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[8], c[6]); +#define PIXEL4_33_80 interp8((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[5], c[9]); +#define PIXEL4_33_81 interp8((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[5], c[6]); +#define PIXEL4_33_82 interp8((Uint32 *)(dst + 3 * dst_pitch + 3 * dst_Bpp), c[5], c[8]); + +void hq4x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface ) +{ + Uint8 *src = (Uint8 *)src_surface->pixels, *src_temp, + *dst = (Uint8 *)dst_surface->pixels, *dst_temp; + int src_pitch = src_surface->pitch, + dst_pitch = dst_surface->pitch; + const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel + + const int height = vga_height, // src_surface->h + width = vga_width; // src_surface->w + + int prevline, nextline; + + Uint32 w[10]; + Uint32 c[10]; + + // +----+----+----+ + // | | | | + // | w1 | w2 | w3 | + // +----+----+----+ + // | | | | + // | w4 | w5 | w6 | + // +----+----+----+ + // | | | | + // | w7 | w8 | w9 | + // +----+----+----+ + + for (int j = 0; j < height; j++) + { + src_temp = src; + dst_temp = dst; + + prevline = (j > 0) ? -width : 0; + nextline = (j < height - 1) ? width : 0; + + for (int i = 0; i < width; i++) + { + w[2] = *(src + prevline); + w[5] = *src; + w[8] = *(src + nextline); + + if (i>0) + { + w[1] = *(src + prevline - 1); + w[4] = *(src - 1); + w[7] = *(src + nextline - 1); + } else { + w[1] = w[2]; + w[4] = w[5]; + w[7] = w[8]; + } + + if (i < width - 1) + { + w[3] = *(src + prevline + 1); + w[6] = *(src + 1); + w[9] = *(src + nextline + 1); + } else { + w[3] = w[2]; + w[6] = w[5]; + w[9] = w[8]; + } + + int pattern = 0; + int flag = 1; + + YUV1 = yuv_palette[w[5]]; + + for (int k=1; k<=9; k++) + { + if (k==5) continue; + + if ( w[k] != w[5] ) + { + YUV2 = yuv_palette[w[k]]; + if ( ( abs((YUV1 & Ymask) - (YUV2 & Ymask)) > trY ) || + ( abs((YUV1 & Umask) - (YUV2 & Umask)) > trU ) || + ( abs((YUV1 & Vmask) - (YUV2 & Vmask)) > trV ) ) + pattern |= flag; + } + flag <<= 1; + } + + for (int k=1; k<=9; k++) + c[k] = rgb_palette[w[k]] & 0xfcfcfcfc; // hq4x has a nasty inability to accept more than 6 bits for each component + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 2: + case 34: + case 130: + case 162: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 16: + case 17: + case 48: + case 49: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 64: + case 65: + case 68: + case 69: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 8: + case 12: + case 136: + case 140: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 3: + case 35: + case 131: + case 163: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 6: + case 38: + case 134: + case 166: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 20: + case 21: + case 52: + case 53: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 144: + case 145: + case 176: + case 177: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 192: + case 193: + case 196: + case 197: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 96: + case 97: + case 100: + case 101: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 40: + case 44: + case 168: + case 172: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 9: + case 13: + case 137: + case 141: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 18: + case 50: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_12_0 + PIXEL4_13_50 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 80: + case 81: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_61 + PIXEL4_21_30 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 72: + case 76: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_70 + PIXEL4_13_60 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_50 + PIXEL4_21_0 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 10: + case 138: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + PIXEL4_11_0 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 66: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 24: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 7: + case 39: + case 135: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 148: + case 149: + case 180: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 224: + case 228: + case 225: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 41: + case 169: + case 45: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 22: + case 54: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 208: + case 209: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 104: + case 108: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_70 + PIXEL4_13_60 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 11: + case 139: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 19: + case 51: + { + if (diff(w[2], w[6])) + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_00_12 + PIXEL4_01_14 + PIXEL4_02_83 + PIXEL4_03_50 + PIXEL4_12_70 + PIXEL4_13_21 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 146: + case 178: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_23_32 + PIXEL4_33_82 + } + else + { + PIXEL4_02_21 + PIXEL4_03_50 + PIXEL4_12_70 + PIXEL4_13_83 + PIXEL4_23_13 + PIXEL4_33_11 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + break; + } + case 84: + case 85: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + if (diff(w[6], w[8])) + { + PIXEL4_03_81 + PIXEL4_13_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_03_12 + PIXEL4_13_14 + PIXEL4_22_70 + PIXEL4_23_83 + PIXEL4_32_21 + PIXEL4_33_50 + } + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 112: + case 113: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_82 + PIXEL4_21_32 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_70 + PIXEL4_23_21 + PIXEL4_30_11 + PIXEL4_31_13 + PIXEL4_32_83 + PIXEL4_33_50 + } + break; + } + case 200: + case 204: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_70 + PIXEL4_13_60 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + } + else + { + PIXEL4_20_21 + PIXEL4_21_70 + PIXEL4_30_50 + PIXEL4_31_83 + PIXEL4_32_14 + PIXEL4_33_12 + } + PIXEL4_22_31 + PIXEL4_23_81 + break; + } + case 73: + case 77: + { + if (diff(w[8], w[4])) + { + PIXEL4_00_82 + PIXEL4_10_32 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_00_11 + PIXEL4_10_13 + PIXEL4_20_83 + PIXEL4_21_70 + PIXEL4_30_50 + PIXEL4_31_21 + } + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 42: + case 170: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_20_31 + PIXEL4_30_81 + } + else + { + PIXEL4_00_50 + PIXEL4_01_21 + PIXEL4_10_83 + PIXEL4_11_70 + PIXEL4_20_14 + PIXEL4_30_12 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 14: + case 142: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_50 + PIXEL4_01_83 + PIXEL4_02_13 + PIXEL4_03_11 + PIXEL4_10_21 + PIXEL4_11_70 + } + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 67: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 70: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 28: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 152: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 194: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 98: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 56: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 25: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 26: + case 31: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 82: + case 214: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 88: + case 248: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + break; + } + case 74: + case 107: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_61 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 27: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 86: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 216: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 106: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_61 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 30: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 210: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 120: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 75: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 29: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 198: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 184: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 99: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 57: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 71: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 156: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 226: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 60: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 195: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 102: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 153: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 58: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 83: + { + PIXEL4_00_81 + PIXEL4_01_31 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_20_61 + PIXEL4_21_30 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 92: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 202: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_61 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 78: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_12_32 + PIXEL4_13_82 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 154: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 114: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_20_82 + PIXEL4_21_32 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + PIXEL4_30_82 + PIXEL4_31_32 + break; + } + case 89: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 90: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 55: + case 23: + { + if (diff(w[2], w[6])) + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_12_0 + PIXEL4_13_0 + } + else + { + PIXEL4_00_12 + PIXEL4_01_14 + PIXEL4_02_83 + PIXEL4_03_50 + PIXEL4_12_70 + PIXEL4_13_21 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 182: + case 150: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_23_32 + PIXEL4_33_82 + } + else + { + PIXEL4_02_21 + PIXEL4_03_50 + PIXEL4_12_70 + PIXEL4_13_83 + PIXEL4_23_13 + PIXEL4_33_11 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + break; + } + case 213: + case 212: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + if (diff(w[6], w[8])) + { + PIXEL4_03_81 + PIXEL4_13_31 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_03_12 + PIXEL4_13_14 + PIXEL4_22_70 + PIXEL4_23_83 + PIXEL4_32_21 + PIXEL4_33_50 + } + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 241: + case 240: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_82 + PIXEL4_21_32 + if (diff(w[6], w[8])) + { + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_22_70 + PIXEL4_23_21 + PIXEL4_30_11 + PIXEL4_31_13 + PIXEL4_32_83 + PIXEL4_33_50 + } + break; + } + case 236: + case 232: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_70 + PIXEL4_13_60 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_30_0 + PIXEL4_31_0 + PIXEL4_32_31 + PIXEL4_33_81 + } + else + { + PIXEL4_20_21 + PIXEL4_21_70 + PIXEL4_30_50 + PIXEL4_31_83 + PIXEL4_32_14 + PIXEL4_33_12 + } + PIXEL4_22_31 + PIXEL4_23_81 + break; + } + case 109: + case 105: + { + if (diff(w[8], w[4])) + { + PIXEL4_00_82 + PIXEL4_10_32 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_00_11 + PIXEL4_10_13 + PIXEL4_20_83 + PIXEL4_21_70 + PIXEL4_30_50 + PIXEL4_31_21 + } + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 171: + case 43: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_20_31 + PIXEL4_30_81 + } + else + { + PIXEL4_00_50 + PIXEL4_01_21 + PIXEL4_10_83 + PIXEL4_11_70 + PIXEL4_20_14 + PIXEL4_30_12 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 143: + case 15: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_0 + PIXEL4_11_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_83 + PIXEL4_02_13 + PIXEL4_03_11 + PIXEL4_10_21 + PIXEL4_11_70 + } + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 124: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 203: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 62: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 211: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 118: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 217: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 110: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 155: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 188: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 185: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 61: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 157: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 103: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 227: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 230: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 199: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 220: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + break; + } + case 158: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_12_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 234: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_61 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 242: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_82 + PIXEL4_31_32 + break; + } + case 59: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_11_0 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 121: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 87: + { + PIXEL4_00_81 + PIXEL4_01_31 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_0 + PIXEL4_20_61 + PIXEL4_21_30 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 79: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_11_0 + PIXEL4_12_32 + PIXEL4_13_82 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 122: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 94: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_12_0 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 218: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + break; + } + case 91: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_11_0 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 229: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 167: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 173: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 181: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 186: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 115: + { + PIXEL4_00_81 + PIXEL4_01_31 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_20_82 + PIXEL4_21_32 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + PIXEL4_30_82 + PIXEL4_31_32 + break; + } + case 93: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + break; + } + case 206: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_12_32 + PIXEL4_13_82 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 205: + case 201: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + if (diff(w[8], w[4])) + { + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + } + else + { + PIXEL4_20_12 + PIXEL4_21_0 + PIXEL4_30_20 + PIXEL4_31_11 + } + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 174: + case 46: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_10_10 + PIXEL4_11_30 + } + else + { + PIXEL4_00_20 + PIXEL4_01_12 + PIXEL4_10_11 + PIXEL4_11_0 + } + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 179: + case 147: + { + PIXEL4_00_81 + PIXEL4_01_31 + if (diff(w[2], w[6])) + { + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + } + else + { + PIXEL4_02_11 + PIXEL4_03_20 + PIXEL4_12_0 + PIXEL4_13_12 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 117: + case 116: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_82 + PIXEL4_21_32 + if (diff(w[6], w[8])) + { + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + } + else + { + PIXEL4_22_0 + PIXEL4_23_11 + PIXEL4_32_12 + PIXEL4_33_20 + } + PIXEL4_30_82 + PIXEL4_31_32 + break; + } + case 189: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 231: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 126: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_0 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 219: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 125: + { + if (diff(w[8], w[4])) + { + PIXEL4_00_82 + PIXEL4_10_32 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_00_11 + PIXEL4_10_13 + PIXEL4_20_83 + PIXEL4_21_70 + PIXEL4_30_50 + PIXEL4_31_21 + } + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 221: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + if (diff(w[6], w[8])) + { + PIXEL4_03_81 + PIXEL4_13_31 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_03_12 + PIXEL4_13_14 + PIXEL4_22_70 + PIXEL4_23_83 + PIXEL4_32_21 + PIXEL4_33_50 + } + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 207: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_0 + PIXEL4_11_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_83 + PIXEL4_02_13 + PIXEL4_03_11 + PIXEL4_10_21 + PIXEL4_11_70 + } + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_31 + PIXEL4_23_81 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 238: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_32 + PIXEL4_13_82 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_30_0 + PIXEL4_31_0 + PIXEL4_32_31 + PIXEL4_33_81 + } + else + { + PIXEL4_20_21 + PIXEL4_21_70 + PIXEL4_30_50 + PIXEL4_31_83 + PIXEL4_32_14 + PIXEL4_33_12 + } + PIXEL4_22_31 + PIXEL4_23_81 + break; + } + case 190: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_23_32 + PIXEL4_33_82 + } + else + { + PIXEL4_02_21 + PIXEL4_03_50 + PIXEL4_12_70 + PIXEL4_13_83 + PIXEL4_23_13 + PIXEL4_33_11 + } + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + break; + } + case 187: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_20_31 + PIXEL4_30_81 + } + else + { + PIXEL4_00_50 + PIXEL4_01_21 + PIXEL4_10_83 + PIXEL4_11_70 + PIXEL4_20_14 + PIXEL4_30_12 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 243: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_82 + PIXEL4_21_32 + if (diff(w[6], w[8])) + { + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_22_70 + PIXEL4_23_21 + PIXEL4_30_11 + PIXEL4_31_13 + PIXEL4_32_83 + PIXEL4_33_50 + } + break; + } + case 119: + { + if (diff(w[2], w[6])) + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_12_0 + PIXEL4_13_0 + } + else + { + PIXEL4_00_12 + PIXEL4_01_14 + PIXEL4_02_83 + PIXEL4_03_50 + PIXEL4_12_70 + PIXEL4_13_21 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 237: + case 233: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_60 + PIXEL4_03_20 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_70 + PIXEL4_13_60 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_31 + PIXEL4_23_81 + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 175: + case 47: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_70 + PIXEL4_23_60 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_60 + PIXEL4_33_20 + break; + } + case 183: + case 151: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_60 + PIXEL4_21_70 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_20 + PIXEL4_31_60 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 245: + case 244: + { + PIXEL4_00_20 + PIXEL4_01_60 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_60 + PIXEL4_11_70 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + case 250: + { + PIXEL4_00_80 + PIXEL4_01_10 + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_30 + PIXEL4_13_10 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + break; + } + case 123: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_10 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 95: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_80 + PIXEL4_31_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 222: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 252: + { + PIXEL4_00_80 + PIXEL4_01_61 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_31 + PIXEL4_13_31 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + case 249: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_61 + PIXEL4_03_80 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + break; + } + case 235: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_61 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_31 + PIXEL4_23_81 + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 111: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_32 + PIXEL4_13_82 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_61 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 63: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_61 + PIXEL4_33_80 + break; + } + case 159: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_80 + PIXEL4_31_61 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 215: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_61 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 246: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_61 + PIXEL4_11_30 + PIXEL4_12_0 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + case 254: + { + PIXEL4_00_80 + PIXEL4_01_10 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_10 + PIXEL4_11_30 + PIXEL4_12_0 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + case 253: + { + PIXEL4_00_82 + PIXEL4_01_82 + PIXEL4_02_81 + PIXEL4_03_81 + PIXEL4_10_32 + PIXEL4_11_32 + PIXEL4_12_31 + PIXEL4_13_31 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_0 + PIXEL4_23_0 + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + case 251: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_10 + PIXEL4_03_80 + PIXEL4_11_0 + PIXEL4_12_30 + PIXEL4_13_10 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + break; + } + case 239: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + PIXEL4_02_32 + PIXEL4_03_82 + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_32 + PIXEL4_13_82 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_31 + PIXEL4_23_81 + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + PIXEL4_32_31 + PIXEL4_33_81 + break; + } + case 127: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + if (diff(w[2], w[6])) + { + PIXEL4_02_0 + PIXEL4_03_0 + PIXEL4_13_0 + } + else + { + PIXEL4_02_50 + PIXEL4_03_50 + PIXEL4_13_50 + } + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_0 + if (diff(w[8], w[4])) + { + PIXEL4_20_0 + PIXEL4_30_0 + PIXEL4_31_0 + } + else + { + PIXEL4_20_50 + PIXEL4_30_50 + PIXEL4_31_50 + } + PIXEL4_21_0 + PIXEL4_22_30 + PIXEL4_23_10 + PIXEL4_32_10 + PIXEL4_33_80 + break; + } + case 191: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_31 + PIXEL4_21_31 + PIXEL4_22_32 + PIXEL4_23_32 + PIXEL4_30_81 + PIXEL4_31_81 + PIXEL4_32_82 + PIXEL4_33_82 + break; + } + case 223: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + PIXEL4_01_0 + PIXEL4_10_0 + } + else + { + PIXEL4_00_50 + PIXEL4_01_50 + PIXEL4_10_50 + } + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_10 + PIXEL4_21_30 + PIXEL4_22_0 + if (diff(w[6], w[8])) + { + PIXEL4_23_0 + PIXEL4_32_0 + PIXEL4_33_0 + } + else + { + PIXEL4_23_50 + PIXEL4_32_50 + PIXEL4_33_50 + } + PIXEL4_30_80 + PIXEL4_31_10 + break; + } + case 247: + { + PIXEL4_00_81 + PIXEL4_01_31 + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_10_81 + PIXEL4_11_31 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_82 + PIXEL4_21_32 + PIXEL4_22_0 + PIXEL4_23_0 + PIXEL4_30_82 + PIXEL4_31_32 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + case 255: + { + if (diff(w[4], w[2])) + { + PIXEL4_00_0 + } + else + { + PIXEL4_00_20 + } + PIXEL4_01_0 + PIXEL4_02_0 + if (diff(w[2], w[6])) + { + PIXEL4_03_0 + } + else + { + PIXEL4_03_20 + } + PIXEL4_10_0 + PIXEL4_11_0 + PIXEL4_12_0 + PIXEL4_13_0 + PIXEL4_20_0 + PIXEL4_21_0 + PIXEL4_22_0 + PIXEL4_23_0 + if (diff(w[8], w[4])) + { + PIXEL4_30_0 + } + else + { + PIXEL4_30_20 + } + PIXEL4_31_0 + PIXEL4_32_0 + if (diff(w[6], w[8])) + { + PIXEL4_33_0 + } + else + { + PIXEL4_33_20 + } + break; + } + } + + src++; + dst += 4 * dst_Bpp; + } + + src = src_temp + src_pitch; + dst = dst_temp + 4 * dst_pitch; + } +} + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/opentyrian/src/xmas.cpp b/alienblaster/project/jni/application/opentyrian/src/xmas.cpp new file mode 100644 index 000000000..dba2de621 --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/xmas.cpp @@ -0,0 +1,99 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "font.h" +#include "keyboard.h" +#include "palette.h" +#include "setup.h" +#include "sprite.h" +#include "video.h" +#include "xmas.h" + +#include +#include + +bool xmas = false; + +bool xmas_time( void ) +{ + time_t now = time(NULL); + return localtime(&now)->tm_mon == 11; +} + +bool xmas_prompt( void ) +{ + const char *prompt[] = + { + "Christmas has been detected.", + "Activate Christmas?", + }; + const char *choice[] = + { + "Yes", + "No", + }; + + set_palette(palettes[0], 0, 255); + + for (uint i = 0; i < COUNTOF(prompt); ++i) + draw_font_hv(VGAScreen, 320 / 2, 85 + 15 * i, prompt[i], normal_font, centered, (i % 2) ? 2 : 4, -2); + + uint selection = 0; + + bool decided = false, quit = false; + while (!decided) + { + for (uint i = 0; i < COUNTOF(choice); ++i) + draw_font_hv(VGAScreen, 320 / 2 - 20 + 40 * i, 120, choice[i], normal_font, centered, 15, (selection == i) ? -2 : -4); + + JE_showVGA(); + + JE_word temp = 0; + JE_textMenuWait(&temp, false); + + if (newkey) + { + switch (lastkey_sym) + { + case SDLK_LEFT: + if (selection == 0) + selection = 2; + selection--; + break; + case SDLK_RIGHT: + selection++; + selection %= 2; + break; + + case SDLK_RETURN: + decided = true; + break; + case SDLK_ESCAPE: + decided = true; + quit = true; + break; + default: + break; + } + } + } + + fade_black(10); + + return (selection == 0 && quit == false); +} diff --git a/alienblaster/project/jni/application/opentyrian/src/xmas.h b/alienblaster/project/jni/application/opentyrian/src/xmas.h new file mode 100644 index 000000000..2376cc81a --- /dev/null +++ b/alienblaster/project/jni/application/opentyrian/src/xmas.h @@ -0,0 +1,31 @@ +/* + * OpenTyrian Classic: A modern cross-platform port of Tyrian + * Copyright (C) 2007-2009 The OpenTyrian Development Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef XMAS_H +#define XMAS_H + +#include + +extern bool xmas; + +bool xmas_time( void ); +bool xmas_prompt( void ); + +#endif /* XMAS_H */ + +// kate: tab-width 4; vim: set noet: diff --git a/alienblaster/project/jni/application/src b/alienblaster/project/jni/application/src index d69d77ceb..7fa7b8f4e 120000 --- a/alienblaster/project/jni/application/src +++ b/alienblaster/project/jni/application/src @@ -1 +1 @@ -jooleem_0.1.4 \ No newline at end of file +opentyrian \ No newline at end of file diff --git a/alienblaster/project/res/values/strings.xml b/alienblaster/project/res/values/strings.xml index daed1f911..bdeb1e31a 100644 --- a/alienblaster/project/res/values/strings.xml +++ b/alienblaster/project/res/values/strings.xml @@ -1,4 +1,4 @@ - Jooleem + OpenTyrian diff --git a/alienblaster/project/src/Accelerometer.java b/alienblaster/project/src/Accelerometer.java index 1407cae3c..a4f27d587 100644 --- a/alienblaster/project/src/Accelerometer.java +++ b/alienblaster/project/src/Accelerometer.java @@ -1,5 +1,5 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import android.app.Activity; import android.content.Context; diff --git a/alienblaster/project/src/Audio.java b/alienblaster/project/src/Audio.java index 3977b7b9e..3f92d3173 100644 --- a/alienblaster/project/src/Audio.java +++ b/alienblaster/project/src/Audio.java @@ -1,5 +1,5 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import android.app.Activity; diff --git a/alienblaster/project/src/DataDownloader.java b/alienblaster/project/src/DataDownloader.java index 79e64a3df..d7773d818 100644 --- a/alienblaster/project/src/DataDownloader.java +++ b/alienblaster/project/src/DataDownloader.java @@ -1,5 +1,5 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import android.app.Activity; import android.content.Context; diff --git a/alienblaster/project/src/GLSurfaceView_SDL.java b/alienblaster/project/src/GLSurfaceView_SDL.java index 05d9b2f11..b37c5722a 100644 --- a/alienblaster/project/src/GLSurfaceView_SDL.java +++ b/alienblaster/project/src/GLSurfaceView_SDL.java @@ -18,7 +18,7 @@ fixed with a hammer and rasp to work with libSDL port */ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import java.io.Writer; import java.util.ArrayList; diff --git a/alienblaster/project/src/Globals.java b/alienblaster/project/src/Globals.java index 0578cea52..9b36267ec 100644 --- a/alienblaster/project/src/Globals.java +++ b/alienblaster/project/src/Globals.java @@ -1,14 +1,14 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount anywhere -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import android.app.Activity; import android.content.Context; class Globals { - public static String ApplicationName = "Jooleem"; + public static String ApplicationName = "OpenTyrian"; // Should be zip file - public static String DataDownloadUrl = "http://sites.google.com/site/xpelyax/Home/jooleem_0.1.4_data.zip?attredirects=0%26d=1|http://sitesproxy.goapk.com/site/xpelyax/Home/jooleem_0.1.4_data.zip"; // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount + public static String DataDownloadUrl = "http://sites.google.com/site/xpelyax/Home/tyrian21-data.zip?attredirects=0%26d=1|http://sitesproxy.goapk.com/site/xpelyax/Home/tyrian21-data.zip"; // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount // Set DownloadToSdcard to true if your app data is bigger than 5 megabytes. // It will download app data to /sdcard/alienblaster then, @@ -25,10 +25,10 @@ class Globals { // Readme text to be shown on download page public static String ReadmeText = "^You may press \"Home\" now - the data will be downloaded in background".replace("^","\n"); - public static boolean AppUsesMouse = true; + public static boolean AppUsesMouse = false; // We have to use accelerometer as arrow keys - public static boolean AppNeedsArrowKeys = false; + public static boolean AppNeedsArrowKeys = true; public static boolean AppUsesJoystick = false; @@ -36,5 +36,5 @@ class Globals { } class LoadLibrary { - public LoadLibrary() { System.loadLibrary("sdl"); System.loadLibrary("sdl_mixer"); System.loadLibrary("sdl_image"); System.loadLibrary("sdl_ttf"); }; + public LoadLibrary() { System.loadLibrary("sdl"); System.loadLibrary("sdl_net"); }; } diff --git a/alienblaster/project/src/MainActivity.java b/alienblaster/project/src/MainActivity.java index 7933ce596..92091ad5c 100644 --- a/alienblaster/project/src/MainActivity.java +++ b/alienblaster/project/src/MainActivity.java @@ -1,5 +1,5 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import android.app.Activity; import android.content.Context; diff --git a/alienblaster/project/src/Settings.java b/alienblaster/project/src/Settings.java index 140b72702..3c1f388a1 100644 --- a/alienblaster/project/src/Settings.java +++ b/alienblaster/project/src/Settings.java @@ -1,5 +1,5 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import android.app.Activity; import android.content.Context; diff --git a/alienblaster/project/src/Video.java b/alienblaster/project/src/Video.java index 592005d21..6ecb6848e 100644 --- a/alienblaster/project/src/Video.java +++ b/alienblaster/project/src/Video.java @@ -1,5 +1,5 @@ // This string is autogenerated by ChangeAppSettings.sh, do not change spaces amount -package net.sourceforge.jooleem; +package com.googlecode.opentyrian; import javax.microedition.khronos.opengles.GL10; diff --git a/alienblaster/readme.txt b/alienblaster/readme.txt index 4f0e41a6f..3b4df9e1f 100644 --- a/alienblaster/readme.txt +++ b/alienblaster/readme.txt @@ -46,8 +46,9 @@ How to compile your own application When porting you own app, first of all ensure that your application supports native RGB_565 pixel format and AUDIO_S8 or AUDIO_S16 audio format (there is RGB_565 pixelformat even for OpenGL, not BGR_565 as all other OpenGL implementation have). -Colorkey images are supported using RGBA_5551 pixelformat with 1-bit alpha, -alpha surfaces have RGBA_4444 format. See file project/jni/application/alienblaster/SdlForwardCompat.h +Colorkey images are supported using RGBA_5551 pixelformat with 1-bit alpha (SDL does conversion internally, +for you they are just RGB_565 surfaces), alpha surfaces have RGBA_4444 format. +See file project/jni/application/alienblaster/SdlForwardCompat.h to learn how to make your application use SDL 1.3 instead of SDL 1.2 without much pain. HTC G1/Nexus One has native screen resolution 480x320, HTC Evo has 800x480, you may toggle automatic screen resizing in ChangeAppSettings.sh and draw to virtual 640x480 screen - @@ -56,6 +57,28 @@ SDL_ListModes()[0] will always return native screen resolution. Also make sure that your HW textures are not wider than 1024 pixels, or it will fail to allocate such texture on HTC G1. Software surfaces may be of any size of course (but you don't want to do expensive memcpy). +Alternatively, SDL 1.2 is available too, you may use it with SW video as usual, however if you want HW acceleration +there are few restrictions: you cannot currently blit SW surface to screen, it should be only HW surface, +also alpha-surfaces seem to not work (did not check it thoroughly) - you still can use per-surface alpha. +Basically your code should be like: + +// Init HW-accelerated video +SDL_SetVideoMode( 640, 480, 16, SDL_DOUBLEBUF | SDL_HWSURFACE ); +// Load graphics +SDL_Surface *sprite = IMG_Load( "sprite.png" ); +// Set pink color as transparent +SDL_SetColorKey( sprite, SDL_SRCCOLORKEY, SDL_MapRGB(sprite->format, 255, 0, 255) ); +// Create HW-accelerated surface +SDL_Surface * hwSprite = SDL_DisplayFormat(sprite); +// Set per-surface alpha, if necessary +SDL_SetAlpha( hwSprite, SDL_SRCALPHA, 128 ); +// Blit it in HW-accelerated way +SDL_BlitSurface(hwSprite, sourceRect, SDL_GetVideoSurface(), &targetRect); +// Wrong, blitting SW surfaces to screen not supported +SDL_BlitSurface(sprite, sourceRect, SDL_GetVideoSurface(), &targetRect); +// Wrong, copying from video surface not supported +SDL_BlitSurface(SDL_GetVideoSurface(), sourceRect, sprite, &targetRect); + To compile your own app, put your app sources into project/jni/application dir, and change symlink "src" to point to your app, then launch script ChangeAppSettings.sh - it will ask few questions and modify some Java code. The C++ files shall have .cpp extension to be compiled, rename them if necessary.