From 7f13ef4cd626db2985daa1d17c9face94e0e7998 Mon Sep 17 00:00:00 2001 From: Anna Ivanova Date: Thu, 11 Aug 2016 10:26:23 +0500 Subject: [PATCH] Initial commit. --- Crypto/build.xml | 73 + Crypto/nbproject/build-impl.xml | 1413 +++++++++++++++++ Crypto/nbproject/genfiles.properties | 8 + Crypto/nbproject/private/config.properties | 0 Crypto/nbproject/private/private.properties | 6 + Crypto/nbproject/private/private.xml | 7 + Crypto/nbproject/project.properties | 75 + Crypto/nbproject/project.xml | 15 + .../kalter/longflight/crypto/CIStream.java | 38 + .../code/kalter/longflight/crypto/Crypto.java | 33 + .../code/kalter/longflight/crypto/Random.java | 26 + README.MD | 3 + build.xml | 83 + nbproject/build-impl.xml | 1250 +++++++++++++++ nbproject/genfiles.properties | 8 + nbproject/private/private.properties | 8 + nbproject/private/private.xml | 7 + nbproject/project.properties | 106 ++ nbproject/project.xml | 10 + src/code/kalter/longflight/Animation.java | 166 ++ src/code/kalter/longflight/Area.java | 45 + src/code/kalter/longflight/Arrays.java | 25 + .../longflight/ByteArrayInputStream.java | 72 + .../longflight/ByteArrayOutputStream.java | 64 + src/code/kalter/longflight/Color.java | 20 + src/code/kalter/longflight/EventListener.java | 13 + src/code/kalter/longflight/FPS.java | 46 + src/code/kalter/longflight/Font.java | 127 ++ src/code/kalter/longflight/Loader.java | 71 + src/code/kalter/longflight/LongFlight.java | 140 ++ src/code/kalter/longflight/ObjectItem.java | 26 + src/code/kalter/longflight/Pointer.java | 59 + src/code/kalter/longflight/Quote.java | 25 + src/code/kalter/longflight/Sound.java | 85 + src/code/kalter/longflight/Sprite.java | 109 ++ src/code/kalter/longflight/StringReader.java | 70 + src/code/kalter/longflight/Time.java | 52 + .../kalter/longflight/crypto/CIStream.java | 37 + src/code/kalter/longflight/crypto/Random.java | 31 + src/code/kalter/longflight/game/Bullet.java | 98 ++ .../kalter/longflight/game/ColorEffect.java | 41 + src/code/kalter/longflight/game/Enemy.java | 232 +++ src/code/kalter/longflight/game/Gamer.java | 206 +++ .../longflight/game/bullet/Collisionable.java | 20 + .../kalter/longflight/game/bullet/Gun.java | 15 + .../longflight/game/explosion/Detonator.java | 11 + .../longflight/game/explosion/Explosion.java | 70 + .../kalter/longflight/game/ship/Ship.java | 17 + .../longflight/game/ship/ShipEnemy.java | 87 + .../longflight/game/ship/ShipGamer.java | 109 ++ src/code/kalter/longflight/rms/RMS.java | 50 + .../rms/RecordNotFoundException.java | 11 + src/code/kalter/longflight/screen/About.java | 139 ++ src/code/kalter/longflight/screen/Crash.java | 127 ++ .../kalter/longflight/screen/EnableSound.java | 213 +++ src/code/kalter/longflight/screen/Game.java | 345 ++++ .../kalter/longflight/screen/HighScore.java | 160 ++ .../kalter/longflight/screen/Loading.java | 99 ++ src/code/kalter/longflight/screen/Menu.java | 293 ++++ src/code/kalter/longflight/screen/Pause.java | 243 +++ src/code/kalter/longflight/screen/Screen.java | 143 ++ .../kalter/longflight/screen/SelectShip.java | 292 ++++ src/code/kalter/longflight/screen/Splash.java | 80 + src/code/kalter/longflight/space/Egg.java | 51 + src/code/kalter/longflight/space/Planet.java | 72 + src/code/kalter/longflight/space/Space.java | 56 + src/code/kalter/longflight/space/Star.java | 49 + src/code/kalter/longflight/space/Tile.java | 49 + src/gfx/about/window.png | Bin 0 -> 909 bytes src/gfx/awt/down_panel.png | 1 + src/gfx/awt/left_soft.png | 2 + src/gfx/awt/right_soft.png | Bin 0 -> 182 bytes src/gfx/boom.png | Bin 0 -> 3796 bytes src/gfx/bullet/0.png | 1 + src/gfx/bullet/1.png | 1 + src/gfx/crash/window.png | Bin 0 -> 740 bytes src/gfx/enable_sound/choise.png | Bin 0 -> 761 bytes src/gfx/enable_sound/window.png | Bin 0 -> 516 bytes src/gfx/font.png | Bin 0 -> 487 bytes src/gfx/game/down_panel.png | Bin 0 -> 163 bytes src/gfx/game/life.png | 1 + src/gfx/game/overheat.png | 1 + src/gfx/game/right_soft.png | 2 + src/gfx/game/up_panel.png | 1 + src/gfx/hscore/window.png | Bin 0 -> 516 bytes src/gfx/icon.png | Bin 0 -> 299 bytes src/gfx/loading/loading.png | 1 + src/gfx/menu/choise.png | Bin 0 -> 1569 bytes src/gfx/menu/window.png | Bin 0 -> 469 bytes src/gfx/pause/choise.png | Bin 0 -> 986 bytes src/gfx/pause/window.png | 1 + src/gfx/select_ship/frame.png | Bin 0 -> 130 bytes src/gfx/select_ship/lr_button.png | Bin 0 -> 167 bytes src/gfx/select_ship/window.png | Bin 0 -> 499 bytes src/gfx/ship/0.png | Bin 0 -> 2578 bytes src/gfx/ship/1.png | Bin 0 -> 2625 bytes src/gfx/ship/2.png | Bin 0 -> 2255 bytes src/gfx/ship/3.png | Bin 0 -> 2428 bytes src/gfx/ship/5.png | Bin 0 -> 499 bytes src/gfx/ship/nozzle.png | 1 + src/gfx/space/background.png | Bin 0 -> 11604 bytes src/gfx/space/planet/0.png | Bin 0 -> 4213 bytes src/gfx/space/planet/1.png | Bin 0 -> 3579 bytes src/gfx/space/planet/2.png | Bin 0 -> 5669 bytes src/gfx/space/planet/3.png | Bin 0 -> 8346 bytes src/gfx/space/planet/4.png | Bin 0 -> 6077 bytes src/gfx/splash/0.png | 1 + src/gfx/splash/1.png | Bin 0 -> 446 bytes src/quote.txt | 15 + src/song/iha.mid | Bin 0 -> 51929 bytes src/song/mobscene.mid | Bin 0 -> 31799 bytes src/song/monster.mid | Bin 0 -> 33698 bytes 112 files changed, 7859 insertions(+) create mode 100644 Crypto/build.xml create mode 100644 Crypto/nbproject/build-impl.xml create mode 100644 Crypto/nbproject/genfiles.properties create mode 100644 Crypto/nbproject/private/config.properties create mode 100644 Crypto/nbproject/private/private.properties create mode 100644 Crypto/nbproject/private/private.xml create mode 100644 Crypto/nbproject/project.properties create mode 100644 Crypto/nbproject/project.xml create mode 100644 Crypto/src/code/kalter/longflight/crypto/CIStream.java create mode 100644 Crypto/src/code/kalter/longflight/crypto/Crypto.java create mode 100644 Crypto/src/code/kalter/longflight/crypto/Random.java create mode 100644 README.MD create mode 100644 build.xml create mode 100644 nbproject/build-impl.xml create mode 100644 nbproject/genfiles.properties create mode 100644 nbproject/private/private.properties create mode 100644 nbproject/private/private.xml create mode 100644 nbproject/project.properties create mode 100644 nbproject/project.xml create mode 100644 src/code/kalter/longflight/Animation.java create mode 100644 src/code/kalter/longflight/Area.java create mode 100644 src/code/kalter/longflight/Arrays.java create mode 100644 src/code/kalter/longflight/ByteArrayInputStream.java create mode 100644 src/code/kalter/longflight/ByteArrayOutputStream.java create mode 100644 src/code/kalter/longflight/Color.java create mode 100644 src/code/kalter/longflight/EventListener.java create mode 100644 src/code/kalter/longflight/FPS.java create mode 100644 src/code/kalter/longflight/Font.java create mode 100644 src/code/kalter/longflight/Loader.java create mode 100644 src/code/kalter/longflight/LongFlight.java create mode 100644 src/code/kalter/longflight/ObjectItem.java create mode 100644 src/code/kalter/longflight/Pointer.java create mode 100644 src/code/kalter/longflight/Quote.java create mode 100644 src/code/kalter/longflight/Sound.java create mode 100644 src/code/kalter/longflight/Sprite.java create mode 100644 src/code/kalter/longflight/StringReader.java create mode 100644 src/code/kalter/longflight/Time.java create mode 100644 src/code/kalter/longflight/crypto/CIStream.java create mode 100644 src/code/kalter/longflight/crypto/Random.java create mode 100644 src/code/kalter/longflight/game/Bullet.java create mode 100644 src/code/kalter/longflight/game/ColorEffect.java create mode 100644 src/code/kalter/longflight/game/Enemy.java create mode 100644 src/code/kalter/longflight/game/Gamer.java create mode 100644 src/code/kalter/longflight/game/bullet/Collisionable.java create mode 100644 src/code/kalter/longflight/game/bullet/Gun.java create mode 100644 src/code/kalter/longflight/game/explosion/Detonator.java create mode 100644 src/code/kalter/longflight/game/explosion/Explosion.java create mode 100644 src/code/kalter/longflight/game/ship/Ship.java create mode 100644 src/code/kalter/longflight/game/ship/ShipEnemy.java create mode 100644 src/code/kalter/longflight/game/ship/ShipGamer.java create mode 100644 src/code/kalter/longflight/rms/RMS.java create mode 100644 src/code/kalter/longflight/rms/RecordNotFoundException.java create mode 100644 src/code/kalter/longflight/screen/About.java create mode 100644 src/code/kalter/longflight/screen/Crash.java create mode 100644 src/code/kalter/longflight/screen/EnableSound.java create mode 100644 src/code/kalter/longflight/screen/Game.java create mode 100644 src/code/kalter/longflight/screen/HighScore.java create mode 100644 src/code/kalter/longflight/screen/Loading.java create mode 100644 src/code/kalter/longflight/screen/Menu.java create mode 100644 src/code/kalter/longflight/screen/Pause.java create mode 100644 src/code/kalter/longflight/screen/Screen.java create mode 100644 src/code/kalter/longflight/screen/SelectShip.java create mode 100644 src/code/kalter/longflight/screen/Splash.java create mode 100644 src/code/kalter/longflight/space/Egg.java create mode 100644 src/code/kalter/longflight/space/Planet.java create mode 100644 src/code/kalter/longflight/space/Space.java create mode 100644 src/code/kalter/longflight/space/Star.java create mode 100644 src/code/kalter/longflight/space/Tile.java create mode 100644 src/gfx/about/window.png create mode 100644 src/gfx/awt/down_panel.png create mode 100644 src/gfx/awt/left_soft.png create mode 100644 src/gfx/awt/right_soft.png create mode 100644 src/gfx/boom.png create mode 100644 src/gfx/bullet/0.png create mode 100644 src/gfx/bullet/1.png create mode 100644 src/gfx/crash/window.png create mode 100644 src/gfx/enable_sound/choise.png create mode 100644 src/gfx/enable_sound/window.png create mode 100644 src/gfx/font.png create mode 100644 src/gfx/game/down_panel.png create mode 100644 src/gfx/game/life.png create mode 100644 src/gfx/game/overheat.png create mode 100644 src/gfx/game/right_soft.png create mode 100644 src/gfx/game/up_panel.png create mode 100644 src/gfx/hscore/window.png create mode 100644 src/gfx/icon.png create mode 100644 src/gfx/loading/loading.png create mode 100644 src/gfx/menu/choise.png create mode 100644 src/gfx/menu/window.png create mode 100644 src/gfx/pause/choise.png create mode 100644 src/gfx/pause/window.png create mode 100644 src/gfx/select_ship/frame.png create mode 100644 src/gfx/select_ship/lr_button.png create mode 100644 src/gfx/select_ship/window.png create mode 100644 src/gfx/ship/0.png create mode 100644 src/gfx/ship/1.png create mode 100644 src/gfx/ship/2.png create mode 100644 src/gfx/ship/3.png create mode 100644 src/gfx/ship/5.png create mode 100644 src/gfx/ship/nozzle.png create mode 100644 src/gfx/space/background.png create mode 100644 src/gfx/space/planet/0.png create mode 100644 src/gfx/space/planet/1.png create mode 100644 src/gfx/space/planet/2.png create mode 100644 src/gfx/space/planet/3.png create mode 100644 src/gfx/space/planet/4.png create mode 100644 src/gfx/splash/0.png create mode 100644 src/gfx/splash/1.png create mode 100644 src/quote.txt create mode 100644 src/song/iha.mid create mode 100644 src/song/mobscene.mid create mode 100644 src/song/monster.mid diff --git a/Crypto/build.xml b/Crypto/build.xml new file mode 100644 index 0000000..3ed3d73 --- /dev/null +++ b/Crypto/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project Crypto. + + + diff --git a/Crypto/nbproject/build-impl.xml b/Crypto/nbproject/build-impl.xml new file mode 100644 index 0000000..b6aec53 --- /dev/null +++ b/Crypto/nbproject/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Crypto/nbproject/genfiles.properties b/Crypto/nbproject/genfiles.properties new file mode 100644 index 0000000..652dcb1 --- /dev/null +++ b/Crypto/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=7f90a431 +build.xml.script.CRC32=a2c5abf7 +build.xml.stylesheet.CRC32=8064a381@1.75.2.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=7f90a431 +nbproject/build-impl.xml.script.CRC32=bbf0bcf8 +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/Crypto/nbproject/private/config.properties b/Crypto/nbproject/private/config.properties new file mode 100644 index 0000000..e69de29 diff --git a/Crypto/nbproject/private/private.properties b/Crypto/nbproject/private/private.properties new file mode 100644 index 0000000..845c36f --- /dev/null +++ b/Crypto/nbproject/private/private.properties @@ -0,0 +1,6 @@ +compile.on.save=true +do.depend=false +do.jar=true +javac.debug=true +javadoc.preview=true +user.properties.file=C:\\Users\\Kalter\\AppData\\Roaming\\NetBeans\\8.0.1\\build.properties diff --git a/Crypto/nbproject/private/private.xml b/Crypto/nbproject/private/private.xml new file mode 100644 index 0000000..6807a2b --- /dev/null +++ b/Crypto/nbproject/private/private.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Crypto/nbproject/project.properties b/Crypto/nbproject/project.properties new file mode 100644 index 0000000..c43d30e --- /dev/null +++ b/Crypto/nbproject/project.properties @@ -0,0 +1,75 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=Crypto +application.vendor=Kalter +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# \u0424\u0430\u0439\u043b\u044b \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 build.classes.dir, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0430\u0440\u0445\u0438\u0432\u0430 jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/Crypto.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.8 +javac.target=1.8 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=code.kalter.longflight.crypto.Crypto +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/Crypto/nbproject/project.xml b/Crypto/nbproject/project.xml new file mode 100644 index 0000000..7af0877 --- /dev/null +++ b/Crypto/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + Crypto + + + + + + + + + diff --git a/Crypto/src/code/kalter/longflight/crypto/CIStream.java b/Crypto/src/code/kalter/longflight/crypto/CIStream.java new file mode 100644 index 0000000..ded156e --- /dev/null +++ b/Crypto/src/code/kalter/longflight/crypto/CIStream.java @@ -0,0 +1,38 @@ +package code.kalter.longflight.crypto; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Шифровальный входной поток + * + * @author Kalter + */ +public class CIStream extends InputStream { + + private final InputStream istream; + private final Random random; + + public CIStream(InputStream istream, int key) { + this.istream = istream; + this.random = new Random(key); + } + + @Override + public int read() throws IOException { + int b = istream.read(); + b = (b << 4) | (b >> 4); + b ^= random.random(0xFF); + return b; + } + + @Override + public int available() throws IOException { + return istream.available(); + } + + @Override + public void close() throws IOException { + istream.close(); + } +} diff --git a/Crypto/src/code/kalter/longflight/crypto/Crypto.java b/Crypto/src/code/kalter/longflight/crypto/Crypto.java new file mode 100644 index 0000000..876384c --- /dev/null +++ b/Crypto/src/code/kalter/longflight/crypto/Crypto.java @@ -0,0 +1,33 @@ +package code.kalter.longflight.crypto; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Главный класс + * + * @author Kalter + */ +public class Crypto { + + public static void main(String[] args) throws IOException { + final String iname = args[0]; + final String oname = args[1]; + final int key = Integer.parseInt(args[2], 16); + try (InputStream fistream = new CIStream(new FileInputStream(iname), key); + OutputStream fostream = new FileOutputStream("_" + oname);) { + while (fistream.available() > 0) { + fostream.write(fistream.read()); + } + } catch (FileNotFoundException e) { + System.out.println("File not found"); + e.printStackTrace(); + } catch (IOException e) { + System.out.println("I/O error"); + } + } +} diff --git a/Crypto/src/code/kalter/longflight/crypto/Random.java b/Crypto/src/code/kalter/longflight/crypto/Random.java new file mode 100644 index 0000000..408bde0 --- /dev/null +++ b/Crypto/src/code/kalter/longflight/crypto/Random.java @@ -0,0 +1,26 @@ +package code.kalter.longflight.crypto; + +/** + * ГПСЧ + * + * @author Kalter + */ +public class Random { + + private int next; + + public Random(int next) { + this.next = next; + } + + public int random() { + next ^= (next << 13); + next ^= (next >>> 17); + next ^= (next << 5); + return Math.abs(next); + } + + public int random(int max) { + return random() % max; + } +} diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..2ba189e --- /dev/null +++ b/README.MD @@ -0,0 +1,3 @@ +Long Flight - game for Java ME + +All files *.png encrypted \ No newline at end of file diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..efaedac --- /dev/null +++ b/build.xml @@ -0,0 +1,83 @@ + + + + + + Builds, tests, and runs the project . + + + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..b42e8ce --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Classpath to J2ME Ant extension library (libs.j2me_ant_ext.classpath property) is not set. For example: location of mobility/modules/org-netbeans-mobility-antext.jar file in the IDE installation directory. + Platform home (platform.home property) is not set. Value of this property should be ${platform.active.description} emulator home directory location. + Platform boot classpath (platform.bootclasspath property) is not set. Value of this property should be ${platform.active.description} emulator boot classpath containing all J2ME classes provided by emulator. + Must set src.dir + Must set build.dir + Must set dist.dir + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set preprocessed.dir + + + + + + + + + + + + + + + + + + Must set build.classes.dir + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + Must set obfuscated.classes.dir + + + + Must set obfuscated.classes.dir + Must set obfuscator.srcjar + Must set obfuscator.destjar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set preverify.classes.dir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MicroEdition-Configuration: ${platform.configuration} + + MicroEdition-Configuration: ${platform.configuration} + + + + MicroEdition-Profile: ${platform.profile} + + MicroEdition-Profile: ${platform.profile} + + + + Must set dist.jad + + + + + + + + + + + + + + + + + + + + + + + + ${manifest.midlets}${evaluated.manifest.apipermissions}${evaluated.manifest.pushregistry}${manifest.others}${manifest.jad} + ${manifest.midlets}${evaluated.manifest.apipermissions}${evaluated.manifest.pushregistry}${manifest.others}${manifest.manifest} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Starting emulator with port number ${active.debug.port} + + + + + + + + + + + + + + + + + Starting emulator with port number ${active.debug.port} + + + + + + + + + + + + + + + + + Must set dist.javadoc.dir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${all.configurations} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Property deployment.${deployment.method}.scriptfile not set. The property should point to an Ant script providing ${deployment.method} deployment. + + + + + + + + Classpath to Ant Contrib library (libs.ant-contrib.classpath property) is not set. + + + + + + + + + Active project configuration: @{cfg} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Property build.root.dir is not set. By default its value should be \"build\". + Property dist.root.dir is not set. By default its value should be \"dist\". + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..6243a0e --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +build.xml.data.CRC32=df8d64c8 +build.xml.script.CRC32=06525edf +build.xml.stylesheet.CRC32=9c6a911d +nbproject/build-impl.xml.data.CRC32=df8d64c8 +nbproject/build-impl.xml.script.CRC32=f96173cd +nbproject/build-impl.xml.stylesheet.CRC32=051c3749 diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties new file mode 100644 index 0000000..4672260 --- /dev/null +++ b/nbproject/private/private.properties @@ -0,0 +1,8 @@ +#Sun, 11 Jan 2015 18:45:51 +0600 +app-version.autoincrement=true +config.active= +deployment.counter=601 +deployment.number=0.6.0 +javadoc.preview=true +netbeans.user=C\:\\Users\\Kalter\\AppData\\Roaming\\NetBeans\\8.0.1 +platform.apis.defaults=MMAPI-1.2,JSR238-1.0,J2ME-WS-1.0,JSR293-2.0,JSR82-1.1,JSR211-1.0,JSR234-1.0,JSR280-1.0,JSR75-1.0,JSR258-1.0,JSR226-1.0,JSR281-1.0,JSR256-1.2,JSR184-1.1,JSR239-1.0,JSR180-1.1.0,JSR253-1.0,JSR229-1.1,JSR177-1.0,WMA-1.1,WMA-2.0,JSR257-1.0,JSR179-1.0 diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml new file mode 100644 index 0000000..5af0ed1 --- /dev/null +++ b/nbproject/private/private.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..965e13f --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,106 @@ +abilities=ColorScreen,MIDP=2.1,ScreenHeight=320,JSR229=1.1,JSR226=1.0,JSR184=1.1,JSR82=1.1,JSR281=1.0,JSR180=1.1.0,JSR280=1.0,OBEX=1.0,SATSA=1.0,WMA=2.0,ScreenColorDepth=16,JSR238=1.0,JSR239=1.0,JSR258=1.0,JSR234=1.0,JSR179=1.0,JSR256=1.2,JSR257=1.0,JSR177=1.0,JSR211=1.0,CLDC=1.1.1,J2MEWS=1.0,ScreenWidth=240,JSR253=1.0,MMAPI=1.2,TouchScreen,JSR293=2.0,JSR172=1.0,JSR75=1.0, +all.configurations=\ +application.args= +application.description= +application.description.detail= +application.name= +application.vendor=Vendor +build.classes.dir=${build.dir}/compiled +build.classes.excludes=**/*.java,**/*.form,**/*.class,**/.nbintdb,**/*.mvd,**/*.wsclient,**/*.vmd +build.dir=build/${config.active} +build.root.dir=build +debug.level=debug +debugger.timeout= +deployment.copy.target=deploy +deployment.instance=default +deployment.jarurl=${dist.jar} +deployment.method=NONE +deployment.override.jarurl=false +dist.dir=dist/${config.active} +dist.jad=Long_Flight.jad +dist.jar=Long_Flight.jar +dist.javadoc.dir=${dist.dir}/doc +dist.root.dir=dist +extra.classpath= +file.reference.builtin.ks=${netbeans.user}/config/j2me/builtin.ks +filter.exclude.tests=false +filter.excludes= +filter.more.excludes=**/overview.html,**/package.html +filter.use.standard=true +jar.compress=false +javac.debug=true +javac.deprecation=false +javac.encoding=UTF-8 +javac.optimize=false +javac.source=1.3 +javac.target=1.3 +javadoc.author=false +javadoc.encoding= +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +libs.classpath= +main.class= +main.class.class=applet +manifest.apipermissions= +manifest.file=manifest.mf +manifest.is.liblet=false +manifest.jad= +manifest.manifest= +manifest.midlets=MIDlet-1: Long Flight,/gfx/icon.png,code.kalter.longflight.LongFlight\n +manifest.others=MIDlet-Vendor: Kalter\nMIDlet-Version: 1.0\nMIDlet-Name: Long Flight\n +manifest.pushregistry= +name=Long Flight +no.dependencies=false +nokiaS80.application.icon= +obfuscated.classes.dir=${build.dir}/obfuscated +obfuscation.custom= +obfuscation.level=0 +obfuscator.destjar=${build.dir}/obfuscated.jar +obfuscator.srcjar=${build.dir}/before-obfuscation.jar +platform.active=Oracle_Java_TM__Platform_Micro_Edition_SDK_3_0_5 +platform.active.description=Oracle Java(TM) Platform Micro Edition SDK 3.0.5 +platform.apis=WMA-1.1,WMA-2.0,MMAPI-1.2,JSR238-1.0,JSR211-1.0,JSR82-1.1,JSR177-1.0,JSR179-1.0,JSR234-1.0,JSR257-1.0,JSR281-1.0,J2ME-WS-1.0,JSR239-1.0,JSR293-2.0,JSR256-1.2,JSR253-1.0,JSR258-1.0,JSR229-1.1,JSR180-1.1.0,JSR226-1.0,JSR280-1.0,JSR75-1.0,JSR184-1.1 +platform.bootclasspath=${platform.home}/lib/jsr281_1.0.jar:${platform.home}/lib/jsr177_1.0.jar:${platform.home}/lib/jsr082_1.1.jar:${platform.home}/lib/jsr253_1.0.jar:${platform.home}/lib/jsr234_1.0.jar:${platform.home}/lib/jsr226_1.0.jar:${platform.home}/lib/jsr75_1.0.jar:${platform.home}/lib/jsr211_1.0.jar:${platform.home}/lib/jsr239_1.0.jar:${platform.home}/lib/jsr179_1.0.jar:${platform.home}/lib/jsr238_1.0.jar:${platform.home}/lib/jsr205_2.0.jar:${platform.home}/lib/jsr180_1.1.jar:${platform.home}/lib/jsr258_1.0.jar:${platform.home}/lib/jsr120_1.1.jar:${platform.home}/lib/jsr229_1.1.jar:${platform.home}/lib/jsr257_1.0.jar:${platform.home}/lib/jsr135_1.2.jar:${platform.home}/lib/jsr256_1.2.jar:${platform.home}/lib/jsr293_1.0.jar:${platform.home}/lib/jsr172_1.0.jar:${platform.home}/lib/jsr280_1.0.jar:${platform.home}/lib/jsr184_1.1.jar:${platform.home}/lib/midp_2.0.jar:${platform.home}/lib/cldc_1.1.jar +platform.configuration=CLDC-1.1 +platform.device=DefaultCldcPhone1 +platform.fat.jar=true +platform.profile=MIDP-2.0 +platform.trigger=CLDC +platform.type=UEI-1.0.1 +preprocessed.dir=${build.dir}/preprocessed +preverify.classes.dir=${build.dir}/preverified +preverify.sources.dir=${build.dir}/preverifysrc +resources.dir=resources +run.cmd.options= +run.jvmargs= +run.method=STANDARD +run.security.domain=trusted +run.use.security.domain=false +savaje.application.icon= +savaje.application.icon.focused= +savaje.application.icon.small= +savaje.application.uid=TBD +savaje.bundle.base= +savaje.bundle.debug=false +savaje.bundle.debug.port= +semc.application.caps= +semc.application.icon= +semc.application.icon.count= +semc.application.icon.splash= +semc.application.icon.splash.installonly=false +semc.application.uid=E4379672 +semc.certificate.path= +semc.private.key.password= +semc.private.key.path= +sign.alias=minimal +sign.enabled=false +sign.keystore=${file.reference.builtin.ks} +src.dir=src +use.emptyapis=true +use.preprocessor=true diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..7baa9cf --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,10 @@ + + + org.netbeans.modules.kjava.j2meproject + + + Long Flight + 1.6 + + + diff --git a/src/code/kalter/longflight/Animation.java b/src/code/kalter/longflight/Animation.java new file mode 100644 index 0000000..84f2a9c --- /dev/null +++ b/src/code/kalter/longflight/Animation.java @@ -0,0 +1,166 @@ +package code.kalter.longflight; + +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Реализация анимации: покадровая смена кадра из массива картинок за + * определённое время. Можно запустить как конечную анимацию, так и бесконечную + * + * @author KalterFive + */ +public class Animation { + + public static Animation createAnimation(String path, int width, + int deltaTime) throws IOException { + final Loader loader = Loader.getInstance(); + final Image image = loader.getImage(path); + return createAnimation(image, width, deltaTime); + } + + public static Animation createAnimation(String path, int width, int height, + int deltaTime) throws IOException { + final Loader loader = Loader.getInstance(); + final Image image = loader.getImage(path); + return createAnimation(image, width, height, deltaTime); + } + + public static Animation createAnimation(Image source, int width, + int deltaTime) { + final int height = source.getHeight(); + return createAnimation(source, width, height, deltaTime); + } + + public static Animation createAnimation(Image source, int width, int height, + int deltaTime) { + final Image[] still = new Image[source.getWidth() / width]; + for (int i = 0; i < still.length; i++) { + still[i] = Image.createImage(source, i * width, 0, + width, height, 0); + } + return createAnimation(still, width, height, deltaTime); + } + + public static Animation createAnimation(Image[] still, int deltaTime) { + int width = still[0].getWidth(); + int height = still[0].getHeight(); + for (int i = 1; i < still.length; i++) { + if (still[i].getWidth() > width) { + width = still[i].getWidth(); + } + if (still[i].getHeight() > height) { + height = still[i].getHeight(); + } + } + return createAnimation(still, width, height, deltaTime); + } + + public static Animation createAnimation(Image[] still, + int width, int height, int deltaTime) { + return new Animation(still, width, height, deltaTime); + } + + private final Image[] still; // кадры + private final int width; + private final int height; + //======================= + private long lastTime; // необходимо для засекания времени + private int deltaTime; // скорость смены кадров + //======================= + private int position; + private boolean animationLoop; + + private Animation(Image[] still, int width, int height, int deltaTime) { + this.still = still; + this.width = width; + this.height = height; + this.deltaTime = deltaTime; + lastTime = System.currentTimeMillis(); + position = 0; + animationLoop = true; + } + + public Image getStill(int index) { + if (index < 0) { + throw new IllegalArgumentException("index < 0"); + } + if (index >= still.length) { + throw new ArrayIndexOutOfBoundsException("i >= length"); + } + return still[index]; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getDeltaTime() { + return deltaTime; + } + + public void setDeltaTime(int deltaTime) { + if (deltaTime < 0) { + throw new IllegalArgumentException("delta time < 0"); + } + this.deltaTime = deltaTime; + } + + public int getPosition() { + return position; + } + + // использование нежелательно, но безопасно + public void setPosition(int position) { + if (position < 0) { + throw new IllegalArgumentException("index < 0"); + } + if (position >= still.length) { + throw new ArrayIndexOutOfBoundsException("i >= length"); + } + this.position = position; + } + + public void start() { + animationLoop = true; + position = 0; + } + + public void stop() { + animationLoop = false; + } + + public boolean getState() { + return animationLoop; + } + + public void nextToInfinity() { + final long time = System.currentTimeMillis() - lastTime; + if (time > deltaTime) { + lastTime = System.currentTimeMillis(); + if (++position >= still.length) { + start(); + } + } + } + + public void next() { + final long time = System.currentTimeMillis() - lastTime; + if (getState() && time > deltaTime) { + lastTime = System.currentTimeMillis(); + if (++position >= still.length) { + stop(); + } + } + } + + public void paint(Graphics graphics, int x, int y) { + if (animationLoop) { + graphics.drawImage(still[position], x, y, 0); + } + } +} diff --git a/src/code/kalter/longflight/Area.java b/src/code/kalter/longflight/Area.java new file mode 100644 index 0000000..2b0dcb5 --- /dev/null +++ b/src/code/kalter/longflight/Area.java @@ -0,0 +1,45 @@ +package code.kalter.longflight; + +/** + * Площадь прямоугольника + * + * @author KalterFive + */ +public class Area { + + private final int positionX; + private final int positionY; + private final int endPositionX; + private final int endPositionY; + + public Area(int positionX, int positionY, + int endPositionX, int endPositionY) { + this.positionX = positionX; + this.positionY = positionY; + this.endPositionX = endPositionX; + this.endPositionY = endPositionY; + } + + public boolean isEntry(int positionX, int positionY) { + return (positionX > this.positionX) + && (positionX < this.endPositionX) + && (positionY > this.positionY) + && (positionY < this.endPositionY); + } + + public int getPositionX() { + return positionX; + } + + public int getPositionY() { + return positionY; + } + + public int getEndPositionX() { + return endPositionX; + } + + public int getEndPositionY() { + return endPositionY; + } +} diff --git a/src/code/kalter/longflight/Arrays.java b/src/code/kalter/longflight/Arrays.java new file mode 100644 index 0000000..d73fd85 --- /dev/null +++ b/src/code/kalter/longflight/Arrays.java @@ -0,0 +1,25 @@ +package code.kalter.longflight; + +/** + * Некоторые полезные методы для работы с массивами + * + * @author KalterFive + */ +public class Arrays { + + public static void insertShiftRight(int[] array, int value, int position) { + for (int i = position; i < array.length; i++) { + swap(array, i, position); + } + array[position] = value; + } + + public static void swap(int[] array, int i, int j) { + int tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } + + private Arrays() { + } +} diff --git a/src/code/kalter/longflight/ByteArrayInputStream.java b/src/code/kalter/longflight/ByteArrayInputStream.java new file mode 100644 index 0000000..4a38c16 --- /dev/null +++ b/src/code/kalter/longflight/ByteArrayInputStream.java @@ -0,0 +1,72 @@ +package code.kalter.longflight; + +/** + * Удобное чтение разных типов с байтового массива + * + * @author KalterFive + */ +public class ByteArrayInputStream { + + private final byte[] array; + private int position; + + public ByteArrayInputStream(byte[] array) { + this.array = array; + position = 0; + } + + public byte readByte() { + return array[position++]; + } + + public short readShort() { + // AND для того, чтобы читать байт без знака + final short a = (short) (readByte() & 0x00FF); + final short b = (short) (readByte() & 0x00FF); + return (short) ((a << 8) | b); + } + + public int readInteger() { + final int a = readShort(); + final int b = readShort(); + return (int) ((a << 16) | b); + } + + public long readLong() { + final long a = readInteger(); + final long b = readInteger(); + return (long) ((a << 32) | b); + } + + public byte[] toByteArray(int size) { + final byte[] array = new byte[size]; + for (int i = 0; i < size; i++) { + array[i] = readByte(); + } + return array; + } + + public short[] toShortArray(int size) { + final short[] array = new short[size]; + for (int i = 0; i < size; i++) { + array[i] = readShort(); + } + return array; + } + + public int[] toIntArray(int size) { + final int[] array = new int[size]; + for (int i = 0; i < size; i++) { + array[i] = readInteger(); + } + return array; + } + + public long[] toLongArray(int size) { + final long[] array = new long[size]; + for (int i = 0; i < size; i++) { + array[i] = readLong(); + } + return array; + } +} diff --git a/src/code/kalter/longflight/ByteArrayOutputStream.java b/src/code/kalter/longflight/ByteArrayOutputStream.java new file mode 100644 index 0000000..35dc765 --- /dev/null +++ b/src/code/kalter/longflight/ByteArrayOutputStream.java @@ -0,0 +1,64 @@ +package code.kalter.longflight; + +/** + * Удобная запись разных типов в байтовый массив + * + * @author KalterFive + */ +public class ByteArrayOutputStream { + + private final byte[] array; + private int position; + + public ByteArrayOutputStream(int size) { + array = new byte[size]; + position = 0; + } + + public void writeByte(byte b) { + array[position++] = b; + } + + public void writeShort(short s) { + writeByte((byte) (s >> 8)); + writeByte((byte) s); + } + + public void writeInt(int i) { + writeShort((short) (i >> 16)); + writeShort((short) i); + } + + public void writeLong(long l) { + writeInt((int) (l >> 32)); + writeInt((int) l); + } + + public void writeByteArray(byte[] array, int length) { + for (int i = 0; i < length; i++) { + writeByte(array[i]); + } + } + + public void writeShortArray(short[] array, int length) { + for (int i = 0; i < length; i++) { + writeShort(array[i]); + } + } + + public void writeIntArray(int[] array, int length) { + for (int i = 0; i < length; i++) { + writeInt(array[i]); + } + } + + public void writeLongArray(long[] array, int length) { + for (int i = 0; i < length; i++) { + writeLong(array[i]); + } + } + + public byte[] toArray() { + return array; + } +} diff --git a/src/code/kalter/longflight/Color.java b/src/code/kalter/longflight/Color.java new file mode 100644 index 0000000..9440fa6 --- /dev/null +++ b/src/code/kalter/longflight/Color.java @@ -0,0 +1,20 @@ +package code.kalter.longflight; + +/** + * @author KalterFive + */ +public class Color { + + public static final int BLACK = 0x000000; + public static final int BLUE = 0x0000FF; + public static final int GREEN = 0x00FF00; + public static final int RED = 0xFF0000; + public static final int WHITE = 0xFFFFFF; + + public static int maskRGB(int r, int g, int b) { + return (r << 16) | (g << 8) | b; + } + + private Color() { + } +} diff --git a/src/code/kalter/longflight/EventListener.java b/src/code/kalter/longflight/EventListener.java new file mode 100644 index 0000000..f7c4ce9 --- /dev/null +++ b/src/code/kalter/longflight/EventListener.java @@ -0,0 +1,13 @@ +package code.kalter.longflight; + +/** + * Простое событие: событие и условие, при котором оно возбуждается + * + * @author KalterFive + */ +public interface EventListener { + + boolean is(); + + void event(); +} diff --git a/src/code/kalter/longflight/FPS.java b/src/code/kalter/longflight/FPS.java new file mode 100644 index 0000000..60b58e0 --- /dev/null +++ b/src/code/kalter/longflight/FPS.java @@ -0,0 +1,46 @@ +package code.kalter.longflight; + +/** + * Ограничитель кадров + * + * @author KalterFive + */ +public class FPS { + + private static FPS instance; + + public static FPS getInstance(int max) { + if (instance == null) { + instance = new FPS(max); + } + return instance; + } + + private long fpsTime; + private long fpsDt; + private int max; // кол-во кадров в секунду + + private FPS(int max) { + this.max = max; + this.fpsTime = System.currentTimeMillis(); + this.fpsDt = 1; + } + + // обновляет необходимые данные и возвращает текущий fps + public long process() { + long dt; + if ((dt = System.currentTimeMillis() - fpsTime) != 0) { + fpsDt = dt; + } + fpsTime = System.currentTimeMillis(); + return 1000 / fpsDt; + } + + // останавливает программу, пока скорость смены кадров больше заданной + public void max() { + long dt = System.currentTimeMillis() - fpsTime; + while (dt < max) { + dt = System.currentTimeMillis() - fpsTime; + } + } +} diff --git a/src/code/kalter/longflight/Font.java b/src/code/kalter/longflight/Font.java new file mode 100644 index 0000000..fe2655d --- /dev/null +++ b/src/code/kalter/longflight/Font.java @@ -0,0 +1,127 @@ +package code.kalter.longflight; + +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Костыль - и этим всё сказанно + * + * @author KalterFive + */ +public class Font { + + private static Font instance; + + public static Font getInstance() throws IOException { + if (instance == null) { + instance = new Font(); + } + return instance; + } + + private final Image[] ascii; + + private Font() throws IOException { + Image font = Loader.getInstance().getImage("/gfx/font.png"); + ascii = new Image[0x7F]; + int x = 0; + for (int i = 0x41; i <= 0x5A; i++, x += 5) { + ascii[i] = Image.createImage(font, x, 0, 5, 9, 0); + } + for (int i = 0x61; i <= 0x7A; i++, x += 5) { + ascii[i] = Image.createImage(font, x, 0, 5, 9, 0); + } + for (int i = 0x30; i <= 0x39; i++, x += 5) { + ascii[i] = Image.createImage(font, x, 0, 5, 9, 0); + } + ascii[0x21] = Image.createImage(font, x, 0, 5, 9, 0); + ascii[0x22] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x27] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x2C] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x2D] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x2E] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x3A] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x28] = Image.createImage(font, x += 5, 0, 5, 9, 0); + ascii[0x29] = Image.createImage(font, x += 5, 0, 4, 9, 0); + } + + public int getWidth(String text) { + return text.length() * 6; + } + + public void paint(Graphics graphics, String text, int x, int y) { + for (int i = 0, px = x; i < text.length(); i++) { + final char c = text.charAt(i); + switch (c) { + case '\r': + x = px; + break; + + case '\n': + y += 10; + break; + + case ' ': + x += 6; + break; + + default: + graphics.drawImage(ascii[c], x, y, 0); + x += 6; + break; + } + } + } + + public void paint(Graphics graphics, String text, + int x, int y, int width) { + String[] word = split(text); + int px = x; + for (int i = 0; i < word.length; i++) { + paint(graphics, word[i], px, y); + int length = (getWidth(word[i])) + 6; + if ((px += length) + length > width) { + px = x; + y += 10; + } + } + } + + public int getHeight(String text, int width) { + String[] word = split(text); + int result = 0; + for (int i = 0, x = 0; i < word.length; i++) { + int length = (getWidth(word[i])) + 6; + if ((x += length) + length > width) { + x = 0; + result += 10; + } + } + return result; + } + + private String[] split(String text) { + String[] result; + int length = 1; + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) == ' ') { + length++; + } + } + result = new String[length]; + StringBuffer word = new StringBuffer(); + int j = 0; + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c == ' ') { + result[j++] = word.toString(); + word = new StringBuffer(); + } else { + word.append(c); + } + } + result[j] = word.toString(); + return result; + } +} diff --git a/src/code/kalter/longflight/Loader.java b/src/code/kalter/longflight/Loader.java new file mode 100644 index 0000000..25f5c3a --- /dev/null +++ b/src/code/kalter/longflight/Loader.java @@ -0,0 +1,71 @@ +package code.kalter.longflight; + +import code.kalter.longflight.crypto.CIStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; +import javax.microedition.lcdui.Image; +import javax.microedition.media.Manager; +import javax.microedition.media.MediaException; +import javax.microedition.media.Player; + +/** + * Дабы избежать повторных загрузок из разных мест программы, а так же + * обеспечить загрузку с расшифкой создан это класс + * + * @author KalterFive + */ +public class Loader { + + private static final int KEY = 5; // шифровальный XOR ключ + + private static Loader instance; + + public static Loader getInstance() { + if (instance == null) { + instance = new Loader(); + } + return instance; + } + + private final Vector dump; // все успешно загруженные ресурсы + + private Loader() { + dump = new Vector(); + } + + public Object getObject(String path) { + Object result = null; + for (int i = 0; i < dump.size(); i++) { + ObjectItem item = (ObjectItem) dump.elementAt(i); + if (item.get(path) != null) { + result = item.get(path); + break; + } + } + return result; + } + + public Image getImage(String path) throws IOException { + Image result = (Image) getObject(path); + if (result == null) { + final InputStream istream = getClass().getResourceAsStream(path); + final InputStream cistream = new CIStream(istream, KEY); + result = Image.createImage(cistream); + cistream.close(); + dump.addElement(new ObjectItem(result, path)); + } + return result; + } + + public Player getPlayer(String path, String type) throws + IOException, MediaException { + Player result = (Player) getObject(path); + if (result == null) { + final InputStream iStream = getClass().getResourceAsStream(path); + result = Manager.createPlayer(iStream, type); + dump.addElement(new ObjectItem(result, path)); + } + return result; + } +} diff --git a/src/code/kalter/longflight/LongFlight.java b/src/code/kalter/longflight/LongFlight.java new file mode 100644 index 0000000..79a43d1 --- /dev/null +++ b/src/code/kalter/longflight/LongFlight.java @@ -0,0 +1,140 @@ +package code.kalter.longflight; + +import code.kalter.longflight.screen.About; +import code.kalter.longflight.screen.Crash; +import code.kalter.longflight.screen.EnableSound; +import code.kalter.longflight.screen.Game; +import code.kalter.longflight.screen.HighScore; +import code.kalter.longflight.screen.Loading; +import code.kalter.longflight.screen.Menu; +import code.kalter.longflight.screen.Pause; +import code.kalter.longflight.screen.Screen; +import code.kalter.longflight.screen.SelectShip; +import code.kalter.longflight.screen.Splash; +import java.io.IOException; +import javax.microedition.lcdui.Display; +import javax.microedition.media.MediaException; +import javax.microedition.midlet.MIDlet; + +/** + * Главный класс + * + * @author KalterFive + */ +public final class LongFlight extends MIDlet { + + public static LongFlight link; + + // screens + public static final int SPLASH = 0; + public static final int GAME = 1; + public static final int MENU = 2; + public static final int SELECT_SHIP = 3; + public static final int ABOUT = 4; + public static final int HIGH_SCORE = 5; + public static final int LOADING = 6; + public static final int PAUSE = 7; + public static final int ENABLE_SOUND = 8; + public static final int CRASH = 9; + + private Sound music; + private Screen[] screen; + private int screenID; + private int previosScreenID; + + public LongFlight() { + screenID = SPLASH; + link = this; + try { + screen = new Screen[]{ + new Splash(), + new Game(), + new Menu(), + new SelectShip(), + new About(), + new HighScore(), + new Loading(), + new Pause(), + new EnableSound(), + new Crash() + }; + } catch (Exception e) { + catchException(e); + } + } + + // override + public void startApp() { + Display.getDisplay(this).setCurrent(screen[ENABLE_SOUND]); + screen[ENABLE_SOUND].start(); + } + + // override + public void pauseApp() { + // TODO + } + + // override + public void destroyApp(boolean unconditional) { + try { + if (music != null) { + music.stop(); + } + } catch (MediaException e) { + catchException(e); + } + notifyDestroyed(); + } + + public void catchException(Exception e) { + if (screen != null) { + screen[screenID].stop(); + } + System.out.println(e.getMessage()); + e.printStackTrace(); + destroyApp(true); + } + + public void setScreen(int screenID) { + previosScreenID = this.screenID; + screen[this.screenID].stop(); + screen[screenID].start(); + this.screenID = screenID; + Display.getDisplay(this).setCurrent(screen[screenID]); + } + + // принудительно, то есть без остановки текущего + public void $setScreen(int screenID) { + previosScreenID = this.screenID; + screen[this.screenID = screenID].start(); + Display.getDisplay(this).setCurrent(screen[screenID]); + } + + public int getPreviosScreenID() { + return previosScreenID; + } + + // для облегчения жизни + public void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException interruptedException) { + catchException(interruptedException); + } + } + + public void playMusic() { + try { + music = new Sound() {{ + add("/song/monster.mid", "audio/midi"); + add("/song/mobscene.mid", "audio/midi"); + add("/song/iha.mid", "audio/midi"); + play(); + }}; + } catch (IOException e) { + catchException(e); + } catch (MediaException e) { + catchException(e); + } + } +} diff --git a/src/code/kalter/longflight/ObjectItem.java b/src/code/kalter/longflight/ObjectItem.java new file mode 100644 index 0000000..a452dad --- /dev/null +++ b/src/code/kalter/longflight/ObjectItem.java @@ -0,0 +1,26 @@ +package code.kalter.longflight; + +import java.io.IOException; + +/** + * Объект и путь к нему + * + * @author KalterFive + */ +public class ObjectItem { + + private final Object image; + private final String path; + + public ObjectItem(Object object, String path) throws IOException { + this.path = path; + this.image = object; + } + + public Object get(String path) { + if (this.path.equals(path)) { + return image; + } + return null; + } +} diff --git a/src/code/kalter/longflight/Pointer.java b/src/code/kalter/longflight/Pointer.java new file mode 100644 index 0000000..a343039 --- /dev/null +++ b/src/code/kalter/longflight/Pointer.java @@ -0,0 +1,59 @@ +package code.kalter.longflight; + +/** + * Координаты, нажатые и отпущенные на экране + * + * @author KalterFive + */ +public class Pointer { + + // нажатые координаты + private int xPressed; + private int yPressed; + + // отпущенные координаты + private int xReleased; + private int yReleased; + + public void setPressed(int xPressed, int yPressed) { + setXPressed(xPressed); + setYPressed(yPressed); + } + + public void setXPressed(int xPressed) { + this.xPressed = xPressed; + } + + public void setYPressed(int yPressed) { + this.yPressed = yPressed; + } + + public void setReleased(int xReleased, int yReleased) { + setXReleased(xReleased); + setYReleased(yReleased); + } + + public void setXReleased(int xReleased) { + this.xReleased = xReleased; + } + + public void setYReleased(int yReleased) { + this.yReleased = yReleased; + } + + public int getXPressed() { + return xPressed; + } + + public int getYPressed() { + return yPressed; + } + + public int getXReleased() { + return xReleased; + } + + public int getYReleased() { + return yReleased; + } +} diff --git a/src/code/kalter/longflight/Quote.java b/src/code/kalter/longflight/Quote.java new file mode 100644 index 0000000..e57a969 --- /dev/null +++ b/src/code/kalter/longflight/Quote.java @@ -0,0 +1,25 @@ +package code.kalter.longflight; + +/** + * Цитата и её автор + * + * @author KalterFive + */ +public class Quote { + + private final String quote; + private final String author; + + public Quote(String quote, String author) { + this.author = author; + this.quote = quote; + } + + public String getQuote() { + return quote; + } + + public String getAuthor() { + return "(c) " + author; + } +} diff --git a/src/code/kalter/longflight/Sound.java b/src/code/kalter/longflight/Sound.java new file mode 100644 index 0000000..9dbd3d3 --- /dev/null +++ b/src/code/kalter/longflight/Sound.java @@ -0,0 +1,85 @@ +package code.kalter.longflight; + +import java.io.IOException; +import java.util.Vector; +import javax.microedition.media.MediaException; +import javax.microedition.media.Player; +import javax.microedition.media.PlayerListener; + +/** + * Фоновая музыка: поочерёдное воспроизведение с цикличностью. Для создания + * необходимо применить трюк Double-Brace, где сначала нужно загрузить ресурсы, + * а после запустить + * + * @author KalterFive + */ +public class Sound { + + // вызывается для смены текущей мелодии + private final PlayerListener playerListener; + + { + playerListener = new PlayerListener() { + // override + public void playerUpdate(Player player, String event, + Object eventData) { + if (event.equals(PlayerListener.END_OF_MEDIA)) { + try { + player.stop(); + player.deallocate(); + play(); + } catch (MediaException e) { + LongFlight.link.catchException(e); + } + } + } + }; + } + + private final Vector dump; + private int active; + + public Sound() throws MediaException { + active = -1; + dump = new Vector(); + } + + // останавливает каждый плеер, освобождает ресурсы и закрывает + public void stop() throws MediaException { + for (int i = 0; i < dump.size(); i++) { + final Player player = (Player) dump.elementAt(i); + if (i == active) { + player.stop(); + player.deallocate(); + } + player.close(); + } + } + + /* + * Берёт из вектора следующий плеер, реализует, упреждает выборку, ставит + * воспроизведение на начало и включает + */ + protected void play() throws MediaException { + if (++active >= dump.size()) { + active = 0; + } + final Player player = (Player) dump.elementAt(active); + player.realize(); + player.prefetch(); + player.setMediaTime(0); + player.start(); + } + + // добавляет загруженный плеер в вектор - ничего более + protected void add(Player player) throws MediaException { + player.addPlayerListener(playerListener); + dump.addElement(player); + } + + protected void add(String path, String type) throws IOException, + MediaException { + final Loader loader = Loader.getInstance(); + add(loader.getPlayer(path, type)); + } +} diff --git a/src/code/kalter/longflight/Sprite.java b/src/code/kalter/longflight/Sprite.java new file mode 100644 index 0000000..bd05c7c --- /dev/null +++ b/src/code/kalter/longflight/Sprite.java @@ -0,0 +1,109 @@ +package code.kalter.longflight; + +import java.io.IOException; +import java.util.Vector; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Спрайт - основной графический элемент + * + * @author KalterFive + */ +public class Sprite { + + protected final Image image; + private int positionX; + private int positionY; + + // события + private Vector eventListener; + + public Sprite(Image image, int positionX, int positionY) { + this.image = image; + this.positionX = positionX; + this.positionY = positionY; + eventListener = new Vector(1); + } + + public Sprite(String path, int positionX, int positionY) + throws IOException { + this(Image.createImage(path), positionX, positionY); + } + + public void paint(Graphics graph) { + graph.drawImage(image, positionX, positionY, 0); + } + + public void addEvent(EventListener event) { + eventListener.addElement(event); + } + + // попытаться возбудить события + public void exciteEvent() { + for (int i = 0; i < eventListener.size(); i++) { + EventListener event = (EventListener) eventListener.elementAt(i); + if ((event != null) && (event.is())) { + event.event(); + } + } + } + + public EventListener getEvent(int number) + throws ArrayIndexOutOfBoundsException { + return (EventListener) eventListener.elementAt(number); + } + + // удалить событие без сдвига (то есть оnullить его) + public void removeEvent(int number) + throws ArrayIndexOutOfBoundsException { + eventListener.setElementAt(null, number); + } + + public boolean isEntrySet(int positionX, int positionY) { + return (positionX >= this.positionX) + && (positionX <= this.positionX + getWidth()) + && (positionY >= this.positionY) + && (positionY <= this.positionY + getHeight()); + } + + public void moveDown(int speed) { + positionY += speed; + } + + public void moveRight(int speed) { + positionX += speed; + } + + public void moveUp(int speed) { + moveDown(-speed); + } + + public void moveLeft(int speed) { + moveRight(-speed); + } + + public int getX() { + return positionX; + } + + public int getY() { + return positionY; + } + + public int getWidth() { + return image.getWidth(); + } + + public int getHeight() { + return image.getHeight(); + } + + protected void setX(int x) { + this.positionX = x; + } + + protected void setY(int y) { + this.positionY = y; + } +} diff --git a/src/code/kalter/longflight/StringReader.java b/src/code/kalter/longflight/StringReader.java new file mode 100644 index 0000000..4b8793c --- /dev/null +++ b/src/code/kalter/longflight/StringReader.java @@ -0,0 +1,70 @@ +package code.kalter.longflight; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Для удобного чтения строк и других типов из файла. Является не более, чем + * обёрткой для Inputstream + * + * @author KalterFive + */ +public class StringReader { + + private final InputStream inputStream; + + public StringReader(InputStream inputStream) { + this.inputStream = inputStream; + } + + public String nextString() throws IOException { + StringBuffer stringBuffer = new StringBuffer(); + int c = inputStream.read(); + while (c != '\r' && c != -1) { + stringBuffer.append((char) c); + c = inputStream.read(); + } + inputStream.read(); + return stringBuffer.toString(); + } + + // читает true or false + public boolean nextBool() throws IOException { + String line = nextString(); + if (line.equals("true")) { + return true; + } else if (line.equals("false")) { + return false; + } else { + throw new IllegalArgumentException(line); + } + } + + public byte nextByte() throws IOException { + return Byte.parseByte(nextString()); + } + + public short nextShort() throws IOException { + return Short.parseShort(nextString()); + } + + public int nextInt() throws IOException { + return Integer.parseInt(nextString()); + } + + public long nextLong() throws IOException { + return Long.parseLong(nextString()); + } + + public float nextFloat() throws IOException { + return Float.parseFloat(nextString()); + } + + public double nextDouble() throws IOException { + return Double.parseDouble(nextString()); + } + + public void close() throws IOException { + inputStream.close(); + } +} diff --git a/src/code/kalter/longflight/Time.java b/src/code/kalter/longflight/Time.java new file mode 100644 index 0000000..bed35f7 --- /dev/null +++ b/src/code/kalter/longflight/Time.java @@ -0,0 +1,52 @@ +package code.kalter.longflight; + +import java.util.Calendar; +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Класс, определяющий текущее время (используется для вывода даты на экране) + * + * @author KalterFive + */ +public class Time extends TimerTask { + + private static Time instance; + + public static Time getInstance(int step) { + if (instance == null) { + instance = new Time(step); + } + return instance; + } + + private final Timer updating; + private String time; + + // step - шаг обновления даты + private Time(int step) { + time = "Long Flight"; + updating = new Timer(); + updating.schedule(this, 0, step); + } + + // override + public void run() { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date(System.currentTimeMillis())); + int minute = calendar.get(Calendar.MINUTE); + int hour = calendar.get(Calendar.HOUR); + int ampm = calendar.get(Calendar.AM_PM); + int day = calendar.get(Calendar.DAY_OF_MONTH); + int month = calendar.get(Calendar.MONTH) + 1; + int year = calendar.get(Calendar.YEAR) + 1000; + time = hour + ":" + minute + " " + (ampm == 1 ? "AM" : "PM") + " " + + day + "." + month + "." + year; + } + + // override + public String toString() { + return time; + } +} diff --git a/src/code/kalter/longflight/crypto/CIStream.java b/src/code/kalter/longflight/crypto/CIStream.java new file mode 100644 index 0000000..894f5d2 --- /dev/null +++ b/src/code/kalter/longflight/crypto/CIStream.java @@ -0,0 +1,37 @@ +package code.kalter.longflight.crypto; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Шифровальный входной поток (обёртка для InputStream). Дешифровка: + * xor -> xchgb + * + * @author KalterFive + */ +public class CIStream extends InputStream { + + private final InputStream istream; + private final Random random; + + // key - ключ для ГПСЧ + public CIStream(InputStream istream, int key) { + this.istream = istream; + this.random = new Random(key); + } + + public int read() throws IOException { + int b = istream.read(); + b ^= random.random(0xFF); + b = (b << 4) | (b >> 4); + return b; + } + + public int available() throws IOException { + return istream.available(); + } + + public void close() throws IOException { + istream.close(); + } +} diff --git a/src/code/kalter/longflight/crypto/Random.java b/src/code/kalter/longflight/crypto/Random.java new file mode 100644 index 0000000..63555f6 --- /dev/null +++ b/src/code/kalter/longflight/crypto/Random.java @@ -0,0 +1,31 @@ +package code.kalter.longflight.crypto; + +/** + * Простой Генератор Псевдослучайных Чисел + * + * @author KalterFive + */ +public class Random { + + private int next; + + public Random(int next) { + this.next = next; + } + + public Random() { + this((int) System.currentTimeMillis()); + } + + public int random() { + next ^= (next << 13); + next ^= (next >>> 17); + next ^= (next << 5); + return Math.abs(next); + } + + // random от [0] до [max - 1] + public int random(int max) { + return random() % max; + } +} diff --git a/src/code/kalter/longflight/game/Bullet.java b/src/code/kalter/longflight/game/Bullet.java new file mode 100644 index 0000000..18fdda8 --- /dev/null +++ b/src/code/kalter/longflight/game/Bullet.java @@ -0,0 +1,98 @@ +package code.kalter.longflight.game; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.game.bullet.Collisionable; +import code.kalter.longflight.game.bullet.Gun; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Пули! + * + * @author KalterFive + */ +public class Bullet implements Gun { + + private final int SIZE = 128; + private final int screenH; + + private final Image[] gfx; + + private final int[] positionX; + private final int[] positionY; + private final int[] type; + + private Collisionable[] object; + + public Bullet(int screenH) throws IOException { + this.screenH = screenH; + positionX = new int[SIZE]; + positionY = new int[SIZE]; + type = new int[SIZE]; + Loader imageLoader = Loader.getInstance(); + gfx = new Image[]{ + imageLoader.getImage("/gfx/bullet/0.png"), + imageLoader.getImage("/gfx/bullet/1.png") + }; + } + + // магия - все пули исчезают + public void setNull() { + for (int i = 0; i < SIZE; i++) { + type[i] = NULL; + } + } + + public void setCollisionable(Collisionable[] object) { + this.object = object; + } + + public void update() { + for (int i = 0; i < SIZE; i++) { + if (type[i] == NULL) { + continue; + } + collision(i); + positionY[i] += (type[i] * 2 - 1) * 5; + if ((positionY[i] < -10) || (positionY[i] > screenH)) { + type[i] = NULL; + } + } + } + + public void paint(Graphics graphics) { + for (int i = 0; i < SIZE; i++) { + if (type[i] == NULL) { + continue; + } + graphics.drawImage(gfx[type[i]], positionX[i], positionY[i], 0); + } + } + + // override + public void fire(int type, int positionX, int positionY) { + for (int i = 0; i < SIZE; i++) { + if (this.type[i] != NULL) { + continue; + } + this.type[i] = type; + this.positionX[i] = positionX; + this.positionY[i] = positionY; + break; + } + } + + private void collision(int i) { + for (int j = 0; j < object.length; j++) { + if (type[i] == object[j].getType()) { + continue; + } + if (object[j].isCollisionOfBullet(positionX[i], positionY[i])) { + object[j].boomOfBullet(); + type[i] = NULL; + break; + } + } + } +} diff --git a/src/code/kalter/longflight/game/ColorEffect.java b/src/code/kalter/longflight/game/ColorEffect.java new file mode 100644 index 0000000..ea92234 --- /dev/null +++ b/src/code/kalter/longflight/game/ColorEffect.java @@ -0,0 +1,41 @@ +package code.kalter.longflight.game; + +import javax.microedition.lcdui.Graphics; + +/** + * Цветовой эффект при попадании пули в игрока + * + * @author KalterFive + */ +public class ColorEffect { + + private final int screenW; + private final int screenH; + + private final int color; + //========================== + private final int number; // количество кадров для рисования цветного экрана + private int count; // счётчик + //========================== + private boolean is; + + public ColorEffect(int color, int number, int screenW, int screenH) { + this.color = color; + this.number = number; + this.screenW = screenW; + this.screenH = screenH; + } + + public void activate() { + is = true; + count = 0; + } + + public void paint(Graphics graphics) { + if (is) { + graphics.setColor(color); + graphics.fillRect(0, 0, screenW, screenH); + is = ++count < number; + } + } +} diff --git a/src/code/kalter/longflight/game/Enemy.java b/src/code/kalter/longflight/game/Enemy.java new file mode 100644 index 0000000..3e879c1 --- /dev/null +++ b/src/code/kalter/longflight/game/Enemy.java @@ -0,0 +1,232 @@ +package code.kalter.longflight.game; + +import code.kalter.longflight.game.bullet.Collisionable; +import code.kalter.longflight.game.bullet.Gun; +import code.kalter.longflight.game.explosion.Detonator; +import code.kalter.longflight.game.ship.Ship; +import code.kalter.longflight.game.ship.ShipEnemy; +import java.io.IOException; +import java.util.Random; +import java.util.Timer; +import java.util.TimerTask; +import javax.microedition.lcdui.Graphics; + +/** + * Враги и всё связанное с ними + * + * @author KalterFive + */ +public class Enemy implements Collisionable { + + private static final int COUNT = 28; + + // специальное обозначение для несуществующего врага + private static final int NULL = 666; + + private final int screenW; + private final int screenH; + + private final Gamer gamer; + private final Detonator detonator; + private final ShipEnemy ship; + private final Gun gun; + private final Random random; + private Timer createEnemy; + + // enemy... + private final int[] x; + private final int[] y; + private final int[] type; + private final int[] life; + private final long[] lastFire; + + private int score; + private int numKill; + private int boom; // индекс врага, в которого попала пуля + + public Enemy(int screenW, int screenH, Gun gun, + Detonator detonator, Gamer gamer) throws IOException { + this.screenW = screenW; + this.screenH = screenH; + this.gun = gun; + this.detonator = detonator; + this.gamer = gamer; + ship = ShipEnemy.getInstance(); + random = new Random(); + x = new int[COUNT]; + y = new int[COUNT]; + type = new int[COUNT]; + life = new int[COUNT]; + lastFire = new long[COUNT]; + } + + // очистка всех врагов + public void setNull() { + for (int i = 0; i < COUNT; i++) { + type[i] = NULL; + } + numKill = score = 0; + } + + public void update() { + for (int i = 0; i < COUNT; i++) { + if (type[i] == NULL) { + continue; + } + switch (type[i]) { + case Ship.LAX: + aiLax(i); + break; + + case Ship.POWERFUL: + aiPowerful(i); + break; + + case Ship.UNIVERSAL: + aiUniversal(i); + break; + + case Ship.STRONG: + aiStrong(i); + break; + } + } + } + + public void paint(Graphics graphics) { + for (int i = 0; i < COUNT; i++) { + if (type[i] == NULL) { + continue; + } + graphics.drawImage(ship.getImage(type[i]), x[i], y[i], 0); + } + } + + // override + public boolean isCollisionOfBullet(int bx, int by) { + for (int i = 0; i < COUNT; i++) { + if (type[i] == NULL) { + continue; + } + if ((bx > x[i]) && (bx < x[i] + Ship.SIZE) + && (by > y[i]) && (by < y[i] + Ship.SIZE)) { + boom = i; + return true; + } + } + return false; + } + + // override + public void boomOfBullet() { + if (--life[boom] <= 0) { + numKill++; + score += (((type[boom] + 1) * 2) - 1); + type[boom] = NULL; + detonator.activate(x[boom], y[boom]); + } + } + + // override + public int getType() { + return Gun.ENEMY; + } + + public void activateCreator() { + createEnemy = new Timer(); + createEnemy.schedule(new TimerTask() { + // override + public void run() { + for (int i = 0; i < COUNT; i++) { + if (type[i] != NULL) { + continue; + } + int type = random.nextInt(numKill / 30 + 1); + Enemy.this.type[i] = type >= Ship.COUNT ? Ship.COUNT - 1 : type < 0 ? 0 : type; + life[i] = ship.getLife(Enemy.this.type[i]); + lastFire[i] = System.currentTimeMillis(); + x[i] = random.nextInt(screenW - Ship.SIZE); + y[i] = -Ship.SIZE; + break; + } + } + }, 2500, 2500); + } + + public void deactivateCreator() { + createEnemy.cancel(); + } + + public int getScore() { + return score; + } + + private void aiLax(int i) { + y[i] += ship.getSpeed(type[i]); + if (y[i] > screenH) { + type[i] = NULL; + } + if (y[i] > gamer.getY()) { + return; + } + fire(i); + if (x[i] > gamer.getX()) { + x[i] -= ship.getSpeed(type[i]) / 2; + } + if (x[i] < gamer.getX()) { + x[i] += ship.getSpeed(type[i]) / 2; + } + } + + private void aiPowerful(int i) { + y[i] += ship.getSpeed(type[i]); + if (y[i] > screenH) { + type[i] = NULL; + } + if (y[i] > gamer.getY()) { + return; + } + fire(i); + } + + private void aiUniversal(int i) { + if (y[i] < screenH / 3) { + y[i] += ship.getSpeed(type[i]); + } + fire(i); + if (x[i] > gamer.getX()) { + x[i] -= ship.getSpeed(type[i]) / 2; + } + if (x[i] < gamer.getX()) { + x[i] += ship.getSpeed(type[i]) / 2; + } + } + + private void aiStrong(int i) { + y[i] += ship.getSpeed(type[i]); + if (y[i] > screenH) { + type[i] = NULL; + } + if (y[i] > gamer.getY()) { + return; + } + if (x[i] > gamer.getX()) { + x[i] -= ship.getSpeed(type[i]); + } + if (x[i] < gamer.getX()) { + x[i] += ship.getSpeed(type[i]); + } + final int deltaX = Math.abs(x[i] - gamer.getX()); + if (deltaX < Ship.SIZE * 2) { + fire(i); + } + } + + private void fire(int i) { + if (System.currentTimeMillis() - lastFire[i] > ship.getDeltaFire(type[i])) { + gun.fire(Gun.ENEMY, x[i] + 4, y[i] + 38); + gun.fire(Gun.ENEMY, x[i] + 30, y[i] + 38); + lastFire[i] = System.currentTimeMillis(); + } + } +} diff --git a/src/code/kalter/longflight/game/Gamer.java b/src/code/kalter/longflight/game/Gamer.java new file mode 100644 index 0000000..1fbc72a --- /dev/null +++ b/src/code/kalter/longflight/game/Gamer.java @@ -0,0 +1,206 @@ +package code.kalter.longflight.game; + +import code.kalter.longflight.ByteArrayInputStream; +import code.kalter.longflight.Color; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.game.bullet.Collisionable; +import code.kalter.longflight.game.bullet.Gun; +import code.kalter.longflight.game.explosion.Detonator; +import code.kalter.longflight.game.ship.Ship; +import code.kalter.longflight.game.ship.ShipGamer; +import code.kalter.longflight.rms.RMS; +import code.kalter.longflight.screen.Game; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; +import javax.microedition.rms.RecordStoreException; + +/** + * Игрок, и всё связанное с ним + * + * @author KalterFive + */ +public class Gamer implements Collisionable { + + private final int screenW; + private final int screenH; + + private final Image nozzle; + + private final ColorEffect colorEffect; + private final Detonator detonator; + private final ShipGamer ship; + private final Gun gun; + private boolean alive; + private int overheat; + private int type; + private int life; + private int speedX; + private int speedY; + private int positionX; + private int positionY; + + private long lastFireTime; + + public Gamer(int screenW, int screenH, Gun gun, Detonator detonator) + throws IOException { + this.screenW = screenW; + this.screenH = screenH; + this.gun = gun; + this.detonator = detonator; + this.colorEffect = new ColorEffect(Color.WHITE, 2, screenW, screenH); + ship = ShipGamer.getInstance(); + Loader imageLoader = Loader.getInstance(); + nozzle = imageLoader.getImage("/gfx/ship/nozzle.png"); + } + + // ставим игрока на своё место + public void setNull() { + alive = true; + lastFireTime = System.currentTimeMillis(); + speedX = speedY = 0; + overheat = 0; + positionX = (screenW - Ship.SIZE) / 2; + positionY = screenH - 80; + try { + RMS rms = new RMS("longflight", true); + ByteArrayInputStream byteReader = rms.get(1); + type = byteReader.readByte(); + rms.close(); + } catch (RecordStoreException e) { + LongFlight.link.catchException(e); + } + life = ship.getLife(type); + } + + public void paint(Graphics graphics) { + if (alive) { + graphics.drawImage(ship.getImage(type), positionX, positionY, 0); + } + if (speedY < 0) { + graphics.drawImage(nozzle, positionX + 16, positionY + 36, 0); + } + colorEffect.paint(graphics); + } + + public void update() { + // охлаждение + overheat -= overheat > 0 ? 1 : 0; + + // перемещение + positionX += speedX / ship.getTime(type); + positionY += speedY / ship.getTime(type); + + // ограничение перемещения + // position x + if (positionX < 0) { + positionX = 0; + } else if (positionX > screenW - Ship.SIZE) { + positionX = screenW - Ship.SIZE; + } + // position y + if (positionY < 18) { + positionY = 18; + } else if (positionY > screenH - Ship.SIZE - 22) { + positionY = screenH - Ship.SIZE - 22; + } + + // ускорение стремится к нулю + speedX = speedX < 0 ? ++speedX : speedX > 0 ? --speedX : speedX; + speedY = speedY < 0 ? ++speedY : speedY > 0 ? --speedY : speedY; + } + + // override + public boolean isCollisionOfBullet(int bx, int by) { + return alive && bx > positionX && bx < positionX + Ship.SIZE && by > positionY && by < positionY + Ship.SIZE; + } + + // override + public void boomOfBullet() { + if (alive) { + colorEffect.activate(); + if (--life < 0) { + alive = false; + Game.link.stop(); + detonator.activate(positionX, positionY); + } + } + } + + // override + public int getType() { + return Gun.GAMER; + } + + public void moveLeft() { + speedX -= ship.getAcceleration(type); + if (speedX < (-ship.getVelocityMax(type))) { + speedX = (-ship.getVelocityMax(type)); + } + } + + public void moveRight() { + speedX += ship.getAcceleration(type); + if (speedX > ship.getVelocityMax(type)) { + speedX = ship.getVelocityMax(type); + } + } + + public void moveUp() { + speedY -= ship.getAcceleration(type); + if (speedY < (-ship.getVelocityMax(type))) { + speedY = (-ship.getVelocityMax(type)); + } + } + + public void moveDown() { + speedY += ship.getAcceleration(type); + if (speedY > ship.getVelocityMax(type)) { + speedY = ship.getVelocityMax(type); + } + } + + public void fire() { + overheat += overheat < 160 ? ship.getSpeedOverheat(type) : 0; + if (!isGetFire()) { + return; + } + gun.fire(Gun.GAMER, getX() + 4, getY()); + gun.fire(Gun.GAMER, getX() + 30, getY()); + } + + public int getX() { + return positionX; + } + + public int getY() { + return positionY; + } + + public int getSpeedX() { + return speedX; + } + + public int getSpeedY() { + return speedY; + } + + private boolean isGetFire() { + boolean result = false; + if (System.currentTimeMillis() - lastFireTime > ship.getDeltaFire(type)) { + lastFireTime = System.currentTimeMillis(); + result = true; + } + return result && overheat < 160; + } + + public int getLife() { + return life * 4; + } + + public int getOverheat() { + int result = overheat / 3; + return result > 48 ? 48 : result; + } +} diff --git a/src/code/kalter/longflight/game/bullet/Collisionable.java b/src/code/kalter/longflight/game/bullet/Collisionable.java new file mode 100644 index 0000000..b7d695b --- /dev/null +++ b/src/code/kalter/longflight/game/bullet/Collisionable.java @@ -0,0 +1,20 @@ +package code.kalter.longflight.game.bullet; + +/** + * Для проверки столновений пуль с объектами + * + * @author KalterFive + */ +public interface Collisionable { + + int UP = 0; + int DOWN = 1; + int LEFT = 2; + int RIGHT = 3; + + boolean isCollisionOfBullet(int x, int y); + + int getType(); + + void boomOfBullet(); +} diff --git a/src/code/kalter/longflight/game/bullet/Gun.java b/src/code/kalter/longflight/game/bullet/Gun.java new file mode 100644 index 0000000..4d4625a --- /dev/null +++ b/src/code/kalter/longflight/game/bullet/Gun.java @@ -0,0 +1,15 @@ +package code.kalter.longflight.game.bullet; + +/** + * Интерфейс для Bullet для стрельбы врагов + * + * @author KalterFive + */ +public interface Gun { + + int GAMER = 0; + int ENEMY = 1; + int NULL = 666; + + void fire(int t, int x, int y); +} diff --git a/src/code/kalter/longflight/game/explosion/Detonator.java b/src/code/kalter/longflight/game/explosion/Detonator.java new file mode 100644 index 0000000..10e23b2 --- /dev/null +++ b/src/code/kalter/longflight/game/explosion/Detonator.java @@ -0,0 +1,11 @@ +package code.kalter.longflight.game.explosion; + +/** + * Взрыватель! + * + * @author KalterFive + */ +public interface Detonator { + + void activate(int x, int y); +} diff --git a/src/code/kalter/longflight/game/explosion/Explosion.java b/src/code/kalter/longflight/game/explosion/Explosion.java new file mode 100644 index 0000000..7d82a2f --- /dev/null +++ b/src/code/kalter/longflight/game/explosion/Explosion.java @@ -0,0 +1,70 @@ +package code.kalter.longflight.game.explosion; + +import code.kalter.longflight.Animation; +import code.kalter.longflight.Loader; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Не приблежаться, рванёт! + * + * @author KalterFive + */ +public class Explosion implements Detonator { + + public static Explosion createExplosion(String path) throws IOException { + final Loader loader = Loader.getInstance(); + final Image image = loader.getImage(path); + return createExplosion(image); + } + + public static Explosion createExplosion(Image image) { + return new Explosion(image); + } + + private static final int MAX = 5; + private final Animation[] boom; + private final int[] positionX; + private final int[] positionY; + + // каждый кадр должен быть квадратным + private Explosion(Image explosion) { + boom = new Animation[MAX]; + positionX = new int[MAX]; + positionY = new int[MAX]; + for (int i = 0; i < MAX; i++) { + boom[i] = Animation.createAnimation(explosion, + explosion.getHeight(), 80); + } + } + + public void deactivateAll() { + for (int i = 0; i < boom.length; i++) { + boom[i].stop(); + } + } + + public void activate(int x, int y) { + for (int i = 0; i < boom.length; i++) { + if (!boom[i].getState()) { + boom[i].start(); + this.positionX[i] = x; + this.positionY[i] = y; + break; + } + } + } + + public void paint(Graphics graphics) { + for (int i = 0; i < boom.length; i++) { + boom[i].paint(graphics, positionX[i], positionY[i]); + } + } + + public void update() { + for (int i = 0; i < boom.length; i++) { + boom[i].next(); + } + } +} diff --git a/src/code/kalter/longflight/game/ship/Ship.java b/src/code/kalter/longflight/game/ship/Ship.java new file mode 100644 index 0000000..f01dbd6 --- /dev/null +++ b/src/code/kalter/longflight/game/ship/Ship.java @@ -0,0 +1,17 @@ +package code.kalter.longflight.game.ship; + +/** + * Основные константы: типы, количество типов, размер w|h квадратного (!) + * кораблика + * + * @author KalterFive + */ +public interface Ship { + + int COUNT = 4; + int SIZE = 40; + int LAX = 0; + int POWERFUL = 1; + int UNIVERSAL = 2; + int STRONG = 3; +} diff --git a/src/code/kalter/longflight/game/ship/ShipEnemy.java b/src/code/kalter/longflight/game/ship/ShipEnemy.java new file mode 100644 index 0000000..529cc54 --- /dev/null +++ b/src/code/kalter/longflight/game/ship/ShipEnemy.java @@ -0,0 +1,87 @@ +package code.kalter.longflight.game.ship; + +import code.kalter.longflight.Loader; +import java.io.IOException; +import javax.microedition.lcdui.Image; +import javax.microedition.lcdui.game.Sprite; + +/** + * Свойства всех корабликов врага + * + * @author KalterFive + */ +public class ShipEnemy implements Ship { + + private static ShipEnemy instance; + + public static ShipEnemy getInstance() throws IOException { + if (instance == null) { + instance = new ShipEnemy(); + } + return instance; + } + + private final int[] deltaFire; + private final int[] life; + private final int[] speed; + private final Image[] image; + + private ShipEnemy() throws IOException { + deltaFire = new int[4]; + life = new int[4]; + speed = new int[4]; + image = new Image[4]; + + Loader imageLoader = Loader.getInstance(); + + //TYPE: LAX + deltaFire[LAX] = 2000; + life[LAX] = 3; + speed[LAX] = 2; + image[LAX] = imageLoader.getImage("/gfx/ship/" + LAX + ".png"); + image[LAX] = Image.createImage(image[LAX], 0, 0, 40, 40, + Sprite.TRANS_MIRROR_ROT180); + + //TYPE: POWERFUL + deltaFire[POWERFUL] = 3000; + life[POWERFUL] = 6; + speed[POWERFUL] = 1; + image[POWERFUL] = imageLoader.getImage("/gfx/ship/" + POWERFUL + + ".png"); + image[POWERFUL] = Image.createImage(image[POWERFUL], 0, 0, 40, 40, + Sprite.TRANS_MIRROR_ROT180); + + //TYPE: UNIVERSAL + deltaFire[UNIVERSAL] = 3000; + life[UNIVERSAL] = 3; + speed[UNIVERSAL] = 2; + image[UNIVERSAL] = imageLoader.getImage("/gfx/ship/" + UNIVERSAL + + ".png"); + image[UNIVERSAL] = Image.createImage(image[UNIVERSAL], 0, 0, 40, 40, + Sprite.TRANS_MIRROR_ROT180); + + //TYPE: STRONG + deltaFire[STRONG] = 1500; + life[STRONG] = 6; + speed[STRONG] = 1; + image[STRONG] = imageLoader.getImage("/gfx/ship/" + STRONG + ".png"); + image[STRONG] = Image.createImage(image[STRONG], 0, 0, 40, 40, + Sprite.TRANS_MIRROR_ROT180); + } + + public int getDeltaFire(int type) { + return deltaFire[type]; + } + + public int getLife(int type) { + return life[type]; + } + + public int getSpeed(int type) { + return speed[type]; + } + + public Image getImage(int type) { + return image[type]; + } +} diff --git a/src/code/kalter/longflight/game/ship/ShipGamer.java b/src/code/kalter/longflight/game/ship/ShipGamer.java new file mode 100644 index 0000000..bcfc92d --- /dev/null +++ b/src/code/kalter/longflight/game/ship/ShipGamer.java @@ -0,0 +1,109 @@ +package code.kalter.longflight.game.ship; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import java.io.IOException; +import javax.microedition.lcdui.Image; + +/** + * Все свойства корабликов игрока + * + * @author KalterFive + */ +public class ShipGamer implements Ship { + + private static ShipGamer instance; + + public static ShipGamer getInstance() throws IOException { + if (instance == null) { + instance = new ShipGamer(); + } + return instance; + } + + private final int[] life; + private final int[] time; + private final int[] acceleration; + private final int[] velocityMax; + private final int[] deltaFire; + private final int[] speedOverheat; + private final Image[] image; + + public ShipGamer() throws IOException { + life = new int[COUNT]; + time = new int[COUNT]; + acceleration = new int[COUNT]; + velocityMax = new int[COUNT]; + deltaFire = new int[COUNT]; + speedOverheat = new int[COUNT]; + image = new Image[COUNT]; + + Loader imageLoader = Loader.getInstance(); + + //TYPE: LAX + life[LAX] = 3; + time[LAX] = 2; + acceleration[LAX] = 2; + velocityMax[LAX] = 6; + deltaFire[LAX] = 250; + speedOverheat[LAX] = 4; + image[LAX] = imageLoader.getImage("/gfx/ship/" + LAX + ".png"); + + //TYPE: POWERFUL + life[POWERFUL] = 10; + time[POWERFUL] = 2; + acceleration[POWERFUL] = 2; + velocityMax[POWERFUL] = 4; + deltaFire[POWERFUL] = 300; + speedOverheat[POWERFUL] = 4; + image[POWERFUL] = imageLoader.getImage("/gfx/ship/" + POWERFUL + + ".png"); + + //TYPE: UNIVERSAL + life[UNIVERSAL] = 5; + time[UNIVERSAL] = 2; + acceleration[UNIVERSAL] = 2; + velocityMax[UNIVERSAL] = 8; + deltaFire[UNIVERSAL] = 200; + speedOverheat[UNIVERSAL] = 4; + image[UNIVERSAL] = imageLoader.getImage("/gfx/ship/" + UNIVERSAL + + ".png"); + + //TYPE: STRONG + life[STRONG] = 6; + time[STRONG] = 4; + acceleration[STRONG] = 4; + velocityMax[STRONG] = 24; + deltaFire[STRONG] = 200; + speedOverheat[STRONG] = 4; + image[STRONG] = imageLoader.getImage("/gfx/ship/" + STRONG + ".png"); + } + + public int getLife(int type) { + return life[type]; + } + + public int getTime(int type) { + return time[type]; + } + + public int getAcceleration(int type) { + return acceleration[type]; + } + + public int getVelocityMax(int type) { + return velocityMax[type]; + } + + public int getDeltaFire(int type) { + return deltaFire[type]; + } + + public int getSpeedOverheat(int type) { + return speedOverheat[type]; + } + + public Image getImage(int type) { + return image[type]; + } +} diff --git a/src/code/kalter/longflight/rms/RMS.java b/src/code/kalter/longflight/rms/RMS.java new file mode 100644 index 0000000..c64d97a --- /dev/null +++ b/src/code/kalter/longflight/rms/RMS.java @@ -0,0 +1,50 @@ +package code.kalter.longflight.rms; + +import code.kalter.longflight.ByteArrayInputStream; +import code.kalter.longflight.ByteArrayOutputStream; +import javax.microedition.rms.InvalidRecordIDException; +import javax.microedition.rms.RecordStore; +import javax.microedition.rms.RecordStoreException; + +/** + * Удобная работа с RMS + * + * @author KalterFive + */ +public class RMS { + + public final RecordStore recordStore; + + public RMS(String name, boolean createIfRecordStoreNotFound) + throws RecordStoreException { + recordStore = RecordStore.openRecordStore(name, + createIfRecordStoreNotFound); + } + + public ByteArrayInputStream get(int id) throws RecordStoreException, + RecordNotFoundException { + if (recordStore.getNumRecords() < id) { + throw new RecordNotFoundException(); + } + return new ByteArrayInputStream(recordStore.getRecord(id)); + } + + /* + * Если запись с номером не будет найдена, то массив байтов запишется в + * новую запись, после последней + */ + public void put(int id, ByteArrayOutputStream bytes) + throws RecordStoreException { + final byte[] array = bytes.toArray(); + final int length = array.length; + try { + recordStore.setRecord(id, array, 0, length); + } catch (InvalidRecordIDException e) { + recordStore.addRecord(array, 0, length); + } + } + + public void close() throws RecordStoreException { + recordStore.closeRecordStore(); + } +} diff --git a/src/code/kalter/longflight/rms/RecordNotFoundException.java b/src/code/kalter/longflight/rms/RecordNotFoundException.java new file mode 100644 index 0000000..e0cc709 --- /dev/null +++ b/src/code/kalter/longflight/rms/RecordNotFoundException.java @@ -0,0 +1,11 @@ +package code.kalter.longflight.rms; + +import javax.microedition.rms.RecordStoreException; + +/** + * Формируется в случае, если в хранилище ну будет найдена искомая запись + * + * @author KalterFive + */ +public class RecordNotFoundException extends RecordStoreException { +} diff --git a/src/code/kalter/longflight/screen/About.java b/src/code/kalter/longflight/screen/About.java new file mode 100644 index 0000000..92ef50f --- /dev/null +++ b/src/code/kalter/longflight/screen/About.java @@ -0,0 +1,139 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import javax.microedition.lcdui.Image; + +/** + * Экран информации об игре + * + * @author Kalter + */ +public class About extends Screen { + + private final Sprite window; + private final Sprite leftSoft; + private final Sprite rightSoft; + private final Image downPanel; + + public About() throws IOException { + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/about/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + window.addEvent(new EventListener() { + // override + public boolean is() { + return window.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + setScreenMenu(); + } + }); + + // left soft + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + setScreenMenu(); + } + }); + + // right soft + Image rightSoftImage = loader.getImage("/gfx/awt/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + setScreenMenu(); + } + }); + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + } + + // override + public void start() { + setDate(39, screenH - 9); + super.start(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case FIRE: + keyCode = RIGHT_SOFT; + break; + } + switch (keyCode) { + case RIGHT_SOFT: + case LEFT_SOFT: + setScreenMenu(); + break; + } + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + leftSoft.exciteEvent(); + rightSoft.exciteEvent(); + window.exciteEvent(); + } + + private void setScreenMenu() { + LongFlight.link.setScreen(LongFlight.MENU); + } + + private void update() { + space.update(); + } + + private void paint() { + space.paint(graphics); + window.paint(graphics); + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(downPanel, i, screenH - 18, 0); + } + leftSoft.paint(graphics); + rightSoft.paint(graphics); + paintDate(); + flushGraphics(); + } +} diff --git a/src/code/kalter/longflight/screen/Crash.java b/src/code/kalter/longflight/screen/Crash.java new file mode 100644 index 0000000..0129813 --- /dev/null +++ b/src/code/kalter/longflight/screen/Crash.java @@ -0,0 +1,127 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import javax.microedition.lcdui.Image; + +/** + * Экран информации о уничтожении + * + * @author Kalter + */ +public class Crash extends Screen { + + private final Sprite window; + private final Sprite leftSoft; + private final Sprite rightSoft; + private final Image downPanel; + + public Crash() throws IOException { + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/crash/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + // здесь для окошка не обрабатываются события + + // right soft + Image rightSoftImage = loader.getImage("/gfx/awt/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + keyPressed(LEFT_SOFT); + } + }); + + //left soft + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + keyPressed(LEFT_SOFT); + } + }); + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + } + + // override + public void start() { + setDate(39, screenH - 9); + super.start(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case FIRE: + keyCode = LEFT_SOFT; + break; + } + switch (keyCode) { + case LEFT_SOFT: + case RIGHT_SOFT: + LongFlight.link.setScreen(LongFlight.MENU); + break; + } + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + window.exciteEvent(); + rightSoft.exciteEvent(); + leftSoft.exciteEvent(); + } + + private void update() { + space.update(); + Game.link.updateElements(); + } + + private void paint() { + space.paint(graphics); + Game.link.paintElements(graphics); + window.paint(graphics); + for (int i = 0; i < screenW; i += downPanel.getWidth()) { + graphics.drawImage(downPanel, i, screenH - downPanel.getHeight(), 0); + } + leftSoft.paint(graphics); + rightSoft.paint(graphics); + paintDate(); + flushGraphics(); + } +} diff --git a/src/code/kalter/longflight/screen/EnableSound.java b/src/code/kalter/longflight/screen/EnableSound.java new file mode 100644 index 0000000..b8b3773 --- /dev/null +++ b/src/code/kalter/longflight/screen/EnableSound.java @@ -0,0 +1,213 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import javax.microedition.lcdui.Image; + +/** + * Включение / не включение звука + * + * @author KalterFive + */ +public class EnableSound extends Screen { + + private static final int COUNT = 2; // of choise + + private static final int YES = 0; + private static final int NO = 1; + + private int position; + private final Sprite window; + private final Sprite leftSoft; + private final Sprite[] choise; + private final Sprite[] selectChoise; + private final Image downPanel; + + public EnableSound() throws IOException { + position = 0; + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/enable_sound/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + + // left panel + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + leftSoftPressed(); + } + }); + + // choises + Image choiseCrop = loader.getImage("/gfx/enable_sound/choise.png"); + choise = new Sprite[COUNT]; + selectChoise = new Sprite[COUNT]; + for (int i = 0; i < COUNT; i++) { + // choise + Image c = Image.createImage(choiseCrop, 0, i * 22, 102, 22, 0); + int choiseX = (screenW - 102) / 2; + int choiseY = window.getY() + 51 + i * 24; + choise[i] = new Sprite(c, choiseX, choiseY); + + // selectchoise + Image sc = Image.createImage(choiseCrop, 102, i * 22, 102, 22, 0); + int selectChoiseX = choise[i].getX(); + int selectChoiseY = choise[i].getY(); + selectChoise[i] = new Sprite(sc, selectChoiseX, selectChoiseY); + } + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + + // adding event listener for choise about of "yes" + choise[YES].addEvent(new EventListener() { + // override + public boolean is() { + return choise[YES].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + yes(); + } + }); + selectChoise[YES].addEvent(choise[YES].getEvent(0)); + + // adding event listener for choise about of "no" + choise[NO].addEvent(new EventListener() { + // override + public boolean is() { + return choise[NO].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + no(); + } + }); + selectChoise[NO].addEvent(choise[NO].getEvent(0)); + } + + // override + public void start() { + setDate(39, screenH - 9); + super.start(); + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + leftSoft.exciteEvent(); + choise[YES].exciteEvent(); + choise[NO].exciteEvent(); + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case UP: + upPressed(); + break; + + case DOWN: + downPressed(); + break; + + case FIRE: + firePressed(); + break; + } + switch (keyCode) { + case LEFT_SOFT: + leftSoftPressed(); + break; + } + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + LongFlight.link.setScreen(LongFlight.SPLASH); + } + + private void paint() { + space.paint(graphics); + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(downPanel, i, screenH - 18, 0); + } + paintDate(); + leftSoft.paint(graphics); + window.paint(graphics); + for (int i = 0; i < COUNT; i++) { + if (position == i) { + selectChoise[i].paint(graphics); + } else { + choise[i].paint(graphics); + } + } + flushGraphics(); + } + + private void update() { + space.update(); + } + + private void leftSoftPressed() { + firePressed(); + } + + private void upPressed() { + if (--position < 0) { + position = 0; + } + } + + private void downPressed() { + if (++position >= COUNT) { + position = COUNT - 1; + } + } + + private void firePressed() { + switch (position) { + case YES: + yes(); + break; + + case NO: + no(); + break; + } + } + + private void yes() { + choise[YES].removeEvent(0); + LongFlight.link.playMusic(); + stop(); + } + + private void no() { + stop(); + } +} diff --git a/src/code/kalter/longflight/screen/Game.java b/src/code/kalter/longflight/screen/Game.java new file mode 100644 index 0000000..905440c --- /dev/null +++ b/src/code/kalter/longflight/screen/Game.java @@ -0,0 +1,345 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.Arrays; +import code.kalter.longflight.ByteArrayOutputStream; +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import code.kalter.longflight.game.Bullet; +import code.kalter.longflight.game.Enemy; +import code.kalter.longflight.game.Gamer; +import code.kalter.longflight.game.bullet.Collisionable; +import code.kalter.longflight.game.explosion.Explosion; +import code.kalter.longflight.rms.RMS; +import code.kalter.longflight.rms.RecordNotFoundException; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; +import javax.microedition.rms.RecordStoreException; + +/** + * Игровой экран. Остаётся активным во время паузы и информации о уничтожении. В + * меню паузы происходит отрисовка элементов (см. метод + * paintElements), а в меню информации о уничтожении происходит и + * отрисовка (см. метод updateElements), и обновление, но без + * создания новых врагов + * + * @author KalterFive + */ +public class Game extends Screen { + + public static Game link; + + // keys + private boolean up; + private boolean down; + private boolean left; + private boolean right; + private boolean fire; + private boolean pointerPressed; + + private final Gamer gamer; + private final Bullet bullet; + private final Enemy enemy; + private final Explosion explosion; + + private final Sprite rightSoft; + private final Sprite lifeStatus; + private final Sprite overheatStatus; + private final Image downPanel; + private final Image upPanel; + + private boolean isPause; // для проверки на переход в меню паузы + + public Game() throws IOException { + explosion = Explosion.createExplosion("/gfx/boom.png"); + bullet = new Bullet(screenH); + gamer = new Gamer(screenW, screenH, bullet, explosion); + enemy = new Enemy(screenW, screenH, bullet, explosion, gamer); + bullet.setCollisionable(new Collisionable[]{gamer, enemy}); + + Loader loader = Loader.getInstance(); + + // right soft + Image rightSoftImage = loader.getImage("/gfx/game/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + rightSoftPressed(); + } + }); + + // life status + Image lifeStatusImage = loader.getImage("/gfx/game/life.png"); + int lifeStatusX = 2; + int lifeStatusY = screenH - 20; + lifeStatus = new Sprite(lifeStatusImage, lifeStatusX, lifeStatusY); + + // overheat status + Image overheatStatusImage = loader.getImage("/gfx/game/overheat.png"); + int overheatStatusX = screenW - overheatStatusImage.getWidth() - 2; + int overheatStatusY = screenH - 20; + overheatStatus = new Sprite(overheatStatusImage, + overheatStatusX, overheatStatusY); + + // up & down panel + downPanel = loader.getImage("/gfx/game/down_panel.png"); + upPanel = loader.getImage("/gfx/game/up_panel.png"); + + link = this; + } + + // override + public void start() { + try { + up = down = right = left = fire = pointerPressed = false; + enemy.activateCreator(); + if (isPause) { + isPause = false; + return; + } + explosion.deactivateAll(); + gamer.setNull(); + bullet.setNull(); + enemy.setNull(); + setDate(2, screenH - 9); + } catch (Exception e) { + LongFlight.link.catchException(e); + } finally { + isPause = false; + super.start(); + } + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + paint(); + checkKey(); + update(); + LongFlight.link.sleep(20); + fps.max(); + } + if (isPause) { + return; + } + LongFlight.link.$setScreen(LongFlight.CRASH); + } + + // override + public void keyPressed(int keyCode) { + switch (keyCode) { + case RIGHT_SOFT: + setPauseScreen(); + break; + } + switch (getGameAction(keyCode)) { + case UP: + up = true; + break; + + case DOWN: + down = true; + break; + + case LEFT: + left = true; + break; + + case RIGHT: + right = true; + break; + + case FIRE: + fire = true; + break; + } + } + + // override + public void keyReleased(int keyCode) { + switch (getGameAction(keyCode)) { + case UP: + up = false; + break; + + case DOWN: + down = false; + break; + + case LEFT: + left = false; + break; + + case RIGHT: + right = false; + break; + + case FIRE: + fire = false; + break; + } + } + + // override + public void pointerReleased(int x, int y) { + pointerPressed = false; + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + rightSoft.exciteEvent(); + pointerPressed = true; + } + + // override + public void stop() { + enemy.deactivateCreator(); + super.stop(); + } + + public Explosion getExplosion() { + return explosion; + } + + public void setNullPause() { + isPause = false; + } + + public void save() { + final int score = enemy.getScore(); + try { + final RMS rms = new RMS("longflight", true); + try { + final int[] record = rms.get(2).toIntArray(5); + for (int i = 0; i < 5; i++) { + if (score > record[i]) { + Arrays.insertShiftRight(record, score, i); + break; + } + } + saveRecord(rms, record); + } catch (RecordNotFoundException e) { + saveRecord(rms, new int[]{score, 0, 0, 0, 0}); + } + rms.close(); + } catch (RecordStoreException e) { + LongFlight.link.catchException(e); + } + } + + private void rightSoftPressed() { + setPauseScreen(); + } + + private void checkKey() { + if (pointerPressed) { + if (isPointerUp()) { + gamer.moveUp(); + } + if (isPointerDown()) { + gamer.moveDown(); + } + if (isPointerLeft()) { + gamer.moveLeft(); + } + if (isPointerRight()) { + gamer.moveRight(); + } + if (isPointerFire()) { + gamer.fire(); + } + } + if (up) { + gamer.moveUp(); + } + if (down) { + gamer.moveDown(); + } + if (left) { + gamer.moveLeft(); + } + if (right) { + gamer.moveRight(); + } + if (fire) { + gamer.fire(); + } + } + + private void update() { + updateElements(); + space.update(); + } + + private void paint() { + space.paint(graphics); + paintElements(graphics); + paintGui(); + flushGraphics(); + } + + public void updateElements() { + gamer.update(); + bullet.update(); + enemy.update(); + explosion.update(); + } + + public void paintElements(Graphics graphics) { + enemy.paint(graphics); + gamer.paint(graphics); + bullet.paint(graphics); + explosion.paint(graphics); + } + + private void paintGui() { + // up & down panel + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(upPanel, i, 0, 0); + graphics.drawImage(downPanel, i, screenH - 27, 0); + } + overheatStatus.paint(graphics); + lifeStatus.paint(graphics); + rightSoft.paint(graphics); + paintDate(); + + // score + font.paint(graphics, "Score: " + enemy.getScore(), 2, 2); + + // life + graphics.setColor(0xBF0B10); + graphics.fillRect(4, screenH - 19, gamer.getLife(), 2); + graphics.setColor(0x001A27); + graphics.fillRect(4 + gamer.getLife(), screenH - 19, 1, 2); + + // overheat + graphics.setColor(0xBFCA10); + graphics.fillRect(screenW - 52, screenH - 19, gamer.getOverheat(), 2); + graphics.setColor(0x001A27); + graphics.fillRect(screenW - 52 + gamer.getOverheat(), screenH - 19, + 1, 2); + } + + private void setPauseScreen() { + isPause = true; + LongFlight.link.setScreen(LongFlight.PAUSE); + } + + private void saveRecord(RMS rms, int[] record) throws RecordStoreException { + final ByteArrayOutputStream byteWriter = new ByteArrayOutputStream(20); + byteWriter.writeIntArray(record, 5); + rms.put(2, byteWriter); + } +} diff --git a/src/code/kalter/longflight/screen/HighScore.java b/src/code/kalter/longflight/screen/HighScore.java new file mode 100644 index 0000000..2cf419d --- /dev/null +++ b/src/code/kalter/longflight/screen/HighScore.java @@ -0,0 +1,160 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.ByteArrayInputStream; +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import code.kalter.longflight.rms.RMS; +import code.kalter.longflight.rms.RecordNotFoundException; +import java.io.IOException; +import javax.microedition.lcdui.Image; +import javax.microedition.rms.RecordStoreException; + +/** + * Экран отображения лучших рекордов + * + * @author KalterFive + */ +public class HighScore extends Screen { + + private String score; + private final Sprite window; + private final Sprite leftSoft; + private final Sprite rightSoft; + private final Image downPanel; + + public HighScore() throws IOException { + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/hscore/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + window.addEvent(new EventListener() { + // override + public boolean is() { + return window.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + setScreenMenu(); + } + }); + + // left soft + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + setScreenMenu(); + } + }); + + // right soft + Image rightSoftImage = loader.getImage("/gfx/awt/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + setScreenMenu(); + } + }); + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + } + + // override + public void start() { + score = ""; + try { + RMS rms = new RMS("longflight", true); + ByteArrayInputStream byteReader = rms.get(2); + rms.close(); + for (int i = 0; i < 5; i++) { + score += (i + 1) + ". " + byteReader.readInteger() + "\r\n"; + } + } catch (RecordNotFoundException e) { + for (int i = 0; i < 5; i++) { + score += (i + 1) + ". 0\r\n"; + } + } catch (RecordStoreException e) { + LongFlight.link.catchException(e); + } + setDate(39, screenH - 9); + super.start(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case FIRE: + keyCode = LEFT_SOFT; + break; + } + switch (keyCode) { + case LEFT_SOFT: + case RIGHT_SOFT: + setScreenMenu(); + break; + } + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + rightSoft.exciteEvent(); + leftSoft.exciteEvent(); + window.exciteEvent(); + } + + private void setScreenMenu() { + LongFlight.link.setScreen(LongFlight.MENU); + } + + private void update() { + space.update(); + } + + private void paint() { + space.paint(graphics); + window.paint(graphics); + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(downPanel, i, screenH - 18, 0); + } + leftSoft.paint(graphics); + rightSoft.paint(graphics); + font.paint(graphics, score, window.getX() + 10, window.getY() + 37); + paintDate(); + flushGraphics(); + } +} diff --git a/src/code/kalter/longflight/screen/Loading.java b/src/code/kalter/longflight/screen/Loading.java new file mode 100644 index 0000000..5309b6b --- /dev/null +++ b/src/code/kalter/longflight/screen/Loading.java @@ -0,0 +1,99 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Quote; +import code.kalter.longflight.Sprite; +import code.kalter.longflight.StringReader; +import java.io.IOException; +import java.io.InputStream; +import java.util.Random; +import javax.microedition.lcdui.Image; + +/** + * Фейковая загрузка + * + * @author KalterFive + */ +public class Loading extends Screen { + + private static final long SLEEP = 8000; + + private final int COUNT; // of quots + private final Quote[] quote; + + private final Sprite loading; + private int quoteID; + + private long lastTime; + + public Loading() throws IOException { + final InputStream file = getClass().getResourceAsStream("/quote.txt"); + final StringReader reader = new StringReader(file); + COUNT = reader.nextInt(); + quote = new Quote[COUNT]; + for (int i = 0; i < COUNT; i++) { + String q = reader.nextString(); // quote + String a = reader.nextString(); // author + quote[i] = new Quote(q, a); + } + reader.close(); + + Loader loader = Loader.getInstance(); + + // loading + Image loadingImage = loader.getImage("/gfx/loading/loading.png"); + int loadingX = screenW - loadingImage.getWidth(); + int loadingY = 15; + loading = new Sprite(loadingImage, loadingX, loadingY); + } + + // override + public void start() { + lastTime = System.currentTimeMillis(); + quoteID = new Random().nextInt(COUNT); + super.start(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + LongFlight.link.setScreen(LongFlight.GAME); + } + + private void update() { + if (System.currentTimeMillis() - lastTime > SLEEP) { + stop(); + } + } + + private void paint() { + // gfx + graphics.setColor(0x002C40); + graphics.fillRect(0, 0, screenW, screenH); + graphics.setColor(0x004C6F); + graphics.fillRect(0, 22, screenW, 2); + loading.paint(graphics); + + // quote + String quoteText = quote[quoteID].getQuote(); + int quoteX = 10; + int quoteY = 30; + int quoteHeight = screenW - 10; + font.paint(graphics, quoteText, quoteX, quoteY, quoteHeight); + + // author + String author = quote[quoteID].getAuthor(); + int authorX = 10; + int authorY = 18 + quoteY + font.getHeight(quoteText, quoteHeight); + int authorHeight = screenW - 10; + font.paint(graphics, author, authorX, authorY, authorHeight); + flushGraphics(); + } +} diff --git a/src/code/kalter/longflight/screen/Menu.java b/src/code/kalter/longflight/screen/Menu.java new file mode 100644 index 0000000..1cd9121 --- /dev/null +++ b/src/code/kalter/longflight/screen/Menu.java @@ -0,0 +1,293 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import javax.microedition.lcdui.Image; + +/** + * Экран главного меню + * + * @author KalterFive + */ +public class Menu extends Screen { + + private static final int COUNT_CHOISE = 3; + + private static final int FIGHT = 0; + private static final int HSCORE = 1; + private static final int ABOUT = 2; + + private final Sprite[] choise; + private final Sprite[] selectChoise; + private final Sprite window; + private final Sprite leftSoft; + private final Sprite rightSoft; + private final Image downPanel; + + private int position; + + public Menu() throws IOException { + position = 0; + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/menu/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + //===========================================================[Пасхалка] + window.addEvent(new EventListener() { + // override + public boolean is() { + return (getXReleased() > getXPressed()) + && (window.isEntrySet(getXPressed(), getYPressed())) + && (window.isEntrySet(getXReleased(), getYReleased())) + && (Math.abs(getXPressed() - getXReleased()) + > window.getWidth() / 2); + } + + // override + public void event() { + space.activateEgg(); + } + }); + + // left panel + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + leftSoftPressed(); + } + }); + + // right panel + Image rightSoftImage = loader.getImage("/gfx/awt/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + rightSoftPressed(); + } + }); + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + + // choises + Image choiseCrop = loader.getImage("/gfx/menu/choise.png"); + choise = new Sprite[COUNT_CHOISE]; + selectChoise = new Sprite[COUNT_CHOISE]; + for (int i = 0; i < COUNT_CHOISE; i++) { + // choise + Image c = Image.createImage(choiseCrop, 0, i * 22, 102, 22, 0); + int choiseX = (screenW - 102) / 2; + int choiseY = window.getY() + 34 + i * 24; + choise[i] = new Sprite(c, choiseX, choiseY); + + // selectchoise + Image sc = Image.createImage(choiseCrop, 102, i * 22, 102, 22, 0); + int selectChoiseX = choise[i].getX(); + int selectChoiseY = choise[i].getY(); + selectChoise[i] = new Sprite(sc, selectChoiseX, selectChoiseY); + } + + // adding event listener for choise about of "fight" + choise[FIGHT].addEvent(new EventListener() { + // override + public boolean is() { + return choise[FIGHT].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + position = FIGHT; + firePressed(); + } + }); + selectChoise[FIGHT].addEvent(choise[FIGHT].getEvent(0)); + + // adding event listener for choise about of "high score" + choise[HSCORE].addEvent(new EventListener() { + // override + public boolean is() { + return choise[HSCORE].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + position = HSCORE; + firePressed(); + } + }); + selectChoise[HSCORE].addEvent(choise[HSCORE].getEvent(0)); + + // adding event listener for choise about of "about" + choise[ABOUT].addEvent(new EventListener() { + // override + public boolean is() { + return choise[ABOUT].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + position = ABOUT; + firePressed(); + } + }); + selectChoise[ABOUT].addEvent(choise[ABOUT].getEvent(0)); + } + + // override + public void start() { + final int previosScreenID = LongFlight.link.getPreviosScreenID(); + if (previosScreenID == LongFlight.CRASH + || previosScreenID == LongFlight.PAUSE) { + Game.link.save(); + } + setDate(39, screenH - 9); + super.start(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case UP: + upPressed(); + break; + + case DOWN: + downPressed(); + break; + + case FIRE: + firePressed(); + break; + } + switch (keyCode) { + case RIGHT_SOFT: + rightSoftPressed(); + break; + + case LEFT_SOFT: + leftSoftPressed(); + break; + } + } + + // override + public void keyReleased(int keyCode) { + switch (keyCode) { + //=======================================================[Пасхалка] + case KEY_NUM0: + space.activateEgg(); + break; + } + } + + // override + public void pointerReleased(int x, int y) { + super.pointerReleased(x, y); + window.exciteEvent(); + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + rightSoft.exciteEvent(); + leftSoft.exciteEvent(); + choise[FIGHT].exciteEvent(); + choise[HSCORE].exciteEvent(); + choise[ABOUT].exciteEvent(); + } + + private void upPressed() { + position--; + if (position < 0) { + position = 0; + } + } + + private void downPressed() { + position++; + if (position >= COUNT_CHOISE) { + position = COUNT_CHOISE - 1; + } + } + + private void firePressed() { + leftSoftPressed(); + } + + private void rightSoftPressed() { + LongFlight.link.destroyApp(true); + } + + private void leftSoftPressed() { + switch (position) { + case FIGHT: + LongFlight.link.setScreen(LongFlight.SELECT_SHIP); + break; + + case HSCORE: + LongFlight.link.setScreen(LongFlight.HIGH_SCORE); + break; + + case ABOUT: + LongFlight.link.setScreen(LongFlight.ABOUT); + break; + } + } + + private void update() { + space.update(); + } + + private void paint() { + space.paint(graphics); + window.paint(graphics); + for (int i = 0; i < COUNT_CHOISE; i++) { + if (i == position) { + selectChoise[i].paint(graphics); + } else { + choise[i].paint(graphics); + } + } + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(downPanel, i, screenH - 18, 0); + } + leftSoft.paint(graphics); + rightSoft.paint(graphics); + paintDate(); + flushGraphics(); + } +} diff --git a/src/code/kalter/longflight/screen/Pause.java b/src/code/kalter/longflight/screen/Pause.java new file mode 100644 index 0000000..7a5e536 --- /dev/null +++ b/src/code/kalter/longflight/screen/Pause.java @@ -0,0 +1,243 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import javax.microedition.lcdui.Image; + +/** + * Специальный экран, предназначенный для временной задержки действующего экрана + * и одновременным контактом с пользователем. Жёстко привязан к игровому экрану + * + * @author KalterFive + */ +public class Pause extends Screen { + + private static final int COUNT = 2; //choise + + private static final int FIGHT = 0; + private static final int MENU = 1; + + private final Sprite[] choise; + private final Sprite[] selectChoise; + private final Sprite window; + private final Sprite leftSoft; + private final Sprite rightSoft; + private final Image downPanel; + + private int position; + + public Pause() throws IOException { + position = 0; + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/pause/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + + // right soft + Image rightSoftImage = loader.getImage("/gfx/awt/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + rightSoftPressed(); + } + }); + + // left soft + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + leftSoftPressed(); + } + }); + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + + // choises + Image choiseCrop = loader.getImage("/gfx/pause/choise.png"); + choise = new Sprite[COUNT]; + selectChoise = new Sprite[COUNT]; + for (int i = 0; i < COUNT; i++) { + // choise + Image c = Image.createImage(choiseCrop, 0, i * 22, 102, 22, 0); + int choiseX = (screenW - 102) / 2; + int choiseY = window.getY() + 34 + i * 24; + choise[i] = new Sprite(c, choiseX, choiseY); + + // selectchoise + Image sc = Image.createImage(choiseCrop, 102, i * 22, 102, 22, 0); + int selectChoiseX = choise[i].getX(); + int selectChoiseY = choise[i].getY(); + selectChoise[i] = new Sprite(sc, selectChoiseX, selectChoiseY); + } + + // adding event listener for choise about of "fight" + choise[FIGHT].addEvent(new EventListener() { + // override + public boolean is() { + return choise[FIGHT].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + position = FIGHT; + firePressed(); + } + }); + + // adding event listener for choise about of "menu" + choise[MENU].addEvent(new EventListener() { + // override + public boolean is() { + return choise[MENU].isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + position = MENU; + firePressed(); + } + }); + } + + //override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + } + + // override + public void start() { + setDate(39, screenH - 9); + super.start(); + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case UP: + upPressed(); + break; + + case DOWN: + downPressed(); + break; + + case FIRE: + firePressed(); + break; + } + switch (keyCode) { + case LEFT_SOFT: + leftSoftPressed(); + break; + + case RIGHT_SOFT: + rightSoftPressed(); + break; + } + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + leftSoft.exciteEvent(); + rightSoft.exciteEvent(); + choise[FIGHT].exciteEvent(); + choise[MENU].exciteEvent(); + } + + private void upPressed() { + if (--position < 0) { + position = 0; + } + } + + private void downPressed() { + if (++position >= COUNT) { + position = COUNT - 1; + } + } + + private void leftSoftPressed() { + firePressed(); + } + + private void rightSoftPressed() { + position = FIGHT; + firePressed(); + } + + private void firePressed() { + switch (position) { + case FIGHT: + LongFlight.link.setScreen(LongFlight.GAME); + break; + + case MENU: + Game.link.setNullPause(); + LongFlight.link.setScreen(LongFlight.MENU); + break; + } + } + + private void update() { + space.update(); + } + + private void paint() { + space.paint(graphics); + Game.link.paintElements(graphics); + window.paint(graphics); + paintChoise(); + paintDownPanel(); + leftSoft.paint(graphics); + rightSoft.paint(graphics); + paintDate(); + flushGraphics(); + } + + private void paintChoise() { + for (int i = 0; i < COUNT; i++) { + if (i == position) { + selectChoise[i].paint(graphics); + } else { + choise[i].paint(graphics); + } + } + } + + private void paintDownPanel() { + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(downPanel, i, screenH - 18, 0); + } + } +} diff --git a/src/code/kalter/longflight/screen/Screen.java b/src/code/kalter/longflight/screen/Screen.java new file mode 100644 index 0000000..012f043 --- /dev/null +++ b/src/code/kalter/longflight/screen/Screen.java @@ -0,0 +1,143 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.Area; +import code.kalter.longflight.FPS; +import code.kalter.longflight.Font; +import code.kalter.longflight.Pointer; +import code.kalter.longflight.Time; +import code.kalter.longflight.space.Space; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.game.GameCanvas; + +/** + * Абстрактный класс для всех экранов + * + * @author KalterFive + */ +public abstract class Screen extends GameCanvas implements Runnable { + + // софт-кнопки + public final int LEFT_SOFT = -6; + public final int RIGHT_SOFT = -7; + + // некоторые свойства, характерные каждому экрану + protected final Graphics graphics; + protected final FPS fps; + protected final Space space; + protected final Font font; + protected final int screenW; + protected final int screenH; + + // нажатие и области нажатия + private final Pointer pointer; + private final Area upArea; + private final Area downArea; + private final Area leftArea; + private final Area rightArea; + private final Area fireArea; + + // текущее время и его координаты + private final Time time; + private int timeXPosition; + private int timeYPosition; + + private Thread thread; + protected boolean gameLoop; + + public Screen() throws IOException { + super(false); + setFullScreenMode(true); + graphics = getGraphics(); + screenW = getWidth(); + screenH = getHeight(); + fps = FPS.getInstance(30); + space = Space.getInstance(screenW, screenH); + font = Font.getInstance(); + time = Time.getInstance(60000); + pointer = new Pointer(); + upArea = new Area(screenW / 3, 0, screenW - screenW / 3, screenH / 3); + downArea = new Area(screenW / 3, screenH - screenH / 3, + screenW - screenW / 3, screenH); + leftArea = new Area(0, 0, screenW / 3, screenH); + rightArea = new Area(screenW - screenW / 3, 0, screenW, screenH); + fireArea = new Area(screenW / 3, screenH / 3, + screenW - screenW / 3, screenH - screenH / 3); + } + + public void start() { + showNotify(); + space.paint(graphics); + gameLoop = true; + thread = new Thread(this); + thread.start(); + } + + public void stop() { + hideNotify(); + gameLoop = false; + } + + // override + public void pointerPressed(int x, int y) { + pointer.setPressed(x, y); + } + + // override + public void pointerReleased(int x, int y) { + pointer.setReleased(x, y); + } + + public final boolean getGameLoop() { + return gameLoop; + } + + public int getXPressed() { + return pointer.getXPressed(); + } + + public int getYPressed() { + return pointer.getYPressed(); + } + + public int getXReleased() { + return pointer.getXReleased(); + } + + public int getYReleased() { + return pointer.getYReleased(); + } + + public boolean isPointerUp() { + return isPointerArea(upArea); + } + + public boolean isPointerDown() { + return isPointerArea(downArea); + } + + public boolean isPointerLeft() { + return isPointerArea(leftArea); + } + + public boolean isPointerRight() { + return isPointerArea(rightArea); + } + + public boolean isPointerFire() { + return isPointerArea(fireArea); + } + + public boolean isPointerArea(Area area) { + return area.isEntry(pointer.getXPressed(), pointer.getYPressed()); + } + + protected final void setDate(int x, int y) { + this.timeXPosition = x; + this.timeYPosition = y; + } + + protected final void paintDate() { + font.paint(graphics, time.toString(), timeXPosition, timeYPosition); + } +} diff --git a/src/code/kalter/longflight/screen/SelectShip.java b/src/code/kalter/longflight/screen/SelectShip.java new file mode 100644 index 0000000..5af5185 --- /dev/null +++ b/src/code/kalter/longflight/screen/SelectShip.java @@ -0,0 +1,292 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.ByteArrayOutputStream; +import code.kalter.longflight.EventListener; +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import code.kalter.longflight.game.ship.Ship; +import code.kalter.longflight.game.ship.ShipGamer; +import code.kalter.longflight.rms.RMS; +import java.io.IOException; +import javax.microedition.lcdui.Image; +import javax.microedition.rms.RecordStoreException; + +/** + * Выбор кораблика + * + * @author KalterFive + */ +public class SelectShip extends Screen { + + private int position; + private final Sprite window; + private final Sprite frame; + private final Sprite leftSoft; + private final Sprite rightSoft; + private final Sprite[] leftButton; + private final Sprite[] rightButton; + private final Sprite[] ship; + private final Image downPanel; + + public SelectShip() throws IOException { + Loader loader = Loader.getInstance(); + + // window + Image windowImage = loader.getImage("/gfx/select_ship/window.png"); + int windowX = (screenW - windowImage.getWidth()) / 2; + int windowY = (screenH - windowImage.getHeight()) / 2; + window = new Sprite(windowImage, windowX, windowY); + window.addEvent(new EventListener() { + // override + public boolean is() { + return window.isEntrySet(getXPressed(), getYPressed()) + && getXPressed() == getXReleased() + && getYPressed() == getYReleased(); + } + + // override + public void event() { + firePressed(); + } + }); + window.addEvent(new EventListener() { + // override + public boolean is() { + return window.isEntrySet(getXPressed(), getYPressed()) + && window.isEntrySet(getXReleased(), getYReleased()) + && Math.abs(getXReleased() - getXPressed()) > 50 + && Math.abs(getYReleased() - getYPressed()) < 50; + } + + // override + public void event() { + if (getXPressed() < getXReleased()) { + leftPressed(); + } + if (getXPressed() > getXReleased()) { + rightPressed(); + } + } + }); + + // left soft + Image leftSoftImage = loader.getImage("/gfx/awt/left_soft.png"); + int leftSoftX = 0; + int leftSoftY = screenH - leftSoftImage.getHeight(); + leftSoft = new Sprite(leftSoftImage, leftSoftX, leftSoftY); + leftSoft.addEvent(new EventListener() { + // override + public boolean is() { + return leftSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + leftSoftPressed(); + } + }); + + // right soft + Image rightSoftImage = loader.getImage("/gfx/awt/right_soft.png"); + int rightSoftX = screenW - rightSoftImage.getWidth(); + int rightSoftY = screenH - rightSoftImage.getHeight(); + rightSoft = new Sprite(rightSoftImage, rightSoftX, rightSoftY); + rightSoft.addEvent(new EventListener() { + // override + public boolean is() { + return rightSoft.isEntrySet(getXPressed(), getYPressed()); + } + + // override + public void event() { + rightSoftPressed(); + } + }); + + // down panel + downPanel = loader.getImage("/gfx/awt/down_panel.png"); + + // frame + Image frameImage = loader.getImage("/gfx/select_ship/frame.png"); + int frameX = window.getX() + + (window.getWidth() - frameImage.getWidth()) / 2; + int frameY = window.getY() + 14 + + (window.getHeight() - frameImage.getHeight()) / 2; + frame = new Sprite(frameImage, frameX, frameY); + + // ships + ship = new Sprite[4]; + for (int i = 0; i < Ship.COUNT; i++) { + Image shipImage = ShipGamer.getInstance().getImage(i); + int shipX = frame.getX() + + (frame.getWidth() - shipImage.getWidth()) / 2; + int shipY = frame.getY() + + (frame.getHeight() - shipImage.getHeight()) / 2; + ship[i] = new Sprite(shipImage, shipX, shipY); + } + + // left / right buttons + Image button = loader.getImage("/gfx/select_ship/lr_button.png"); + leftButton = new Sprite[2]; + rightButton = new Sprite[2]; + + // left button + Image leftButtonImage = Image.createImage(button, 0, 0, 6, 11, 0); + int leftButtonX = window.getX() + 15; + int leftButtonY = frame.getY() + (frame.getHeight() - 11) / 2; + leftButton[0] = new Sprite(leftButtonImage, leftButtonX, leftButtonY); + + // select left button + Image selectLeftButtonImage = Image.createImage(button, 0, 11, + 6, 11, 0); + int selectLeftButtonX = leftButton[0].getX(); + int selectLeftButtonY = leftButton[0].getY(); + leftButton[1] = new Sprite(selectLeftButtonImage, + selectLeftButtonX, selectLeftButtonY); + + // right button + Image rightButtonImage = Image.createImage(button, 6, 0, 6, 11, 0); + int rightButtonX = window.getX() + window.getWidth() - 21; + int rightButtonY = frame.getY() + (frame.getHeight() - 11) / 2; + rightButton[0] = new Sprite(rightButtonImage, + rightButtonX, rightButtonY); + + // select right button + Image selectRightButtonImage = Image.createImage(button, 6, 11, + 6, 11, 0); + int selectRightButtonX = rightButton[0].getX(); + int selectRightButtonY = rightButton[0].getY(); + rightButton[1] = new Sprite(selectRightButtonImage, + selectRightButtonX, selectRightButtonY); + } + + // override + public void start() { + position = 0; + setDate(39, screenH - 9); + super.start(); + } + + // override + public void stop() { + super.stop(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + update(); + paint(); + LongFlight.link.sleep(20); + fps.max(); + } + } + + // override + public void keyPressed(int keyCode) { + switch (getGameAction(keyCode)) { + case LEFT: + leftPressed(); + break; + + case RIGHT: + rightPressed(); + break; + + case FIRE: + firePressed(); + break; + } + switch (keyCode) { + case RIGHT_SOFT: + rightSoftPressed(); + break; + + case LEFT_SOFT: + leftSoftPressed(); + break; + } + } + + // override + public void pointerPressed(int x, int y) { + super.pointerPressed(x, y); + rightSoft.exciteEvent(); + leftSoft.exciteEvent(); + } + + // override + public void pointerReleased(int x, int y) { + super.pointerReleased(x, y); + window.exciteEvent(); + } + + private void leftPressed() { + if (--position < 0) { + position = Ship.COUNT - 1; + } + } + + private void rightPressed() { + if (++position >= Ship.COUNT) { + position = 0; + } + } + + private void firePressed() { + leftSoftPressed(); + } + + private void rightSoftPressed() { + LongFlight.link.setScreen(LongFlight.MENU); + } + + private void leftSoftPressed() { + saveAndGoToFire(); + } + + private void update() { + space.update(); + } + + private void paint() { + space.paint(graphics); + window.paint(graphics); + frame.paint(graphics); + ship[position].paint(graphics); + int keyStates = getKeyStates(); + int li = 0; + if ((keyStates & LEFT_PRESSED) != 0) { + li = 1; + } + leftButton[li].paint(graphics); + int ri = 0; + if ((keyStates & RIGHT_PRESSED) != 0) { + ri = 1; + } + rightButton[ri].paint(graphics); + for (int i = 0; i < screenW; i += 128) { + graphics.drawImage(downPanel, i, screenH - 18, 0); + } + leftSoft.paint(graphics); + rightSoft.paint(graphics); + paintDate(); + flushGraphics(); + } + + private void saveAndGoToFire() { + try { + RMS rms = new RMS("longflight", true); + ByteArrayOutputStream data = new ByteArrayOutputStream(1); + data.writeByte((byte) position); + rms.put(1, data); + rms.close(); + } catch (RecordStoreException rse) { + LongFlight.link.catchException(rse); + } + space.deactivateEgg(); + LongFlight.link.setScreen(LongFlight.LOADING); + } +} diff --git a/src/code/kalter/longflight/screen/Splash.java b/src/code/kalter/longflight/screen/Splash.java new file mode 100644 index 0000000..4fb7ee2 --- /dev/null +++ b/src/code/kalter/longflight/screen/Splash.java @@ -0,0 +1,80 @@ +package code.kalter.longflight.screen; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import java.util.Random; +import javax.microedition.lcdui.Image; + +/** + * Сплэш + * + * @author KalterFive + */ +public class Splash extends Screen { + + private final Random random; + private final Sprite splash0; + private final Sprite splash1; + private long lastTime; + + public Splash() throws IOException { + random = new Random(); + Loader loader = Loader.getInstance(); + + // splash 0 + Image splash0Image = loader.getImage("/gfx/splash/0.png"); + int splash0X = (screenW - splash0Image.getWidth()) / 2; + int splash0Y = (screenH - splash0Image.getHeight()) / 2; + splash0 = new Sprite(splash0Image, splash0X, splash0Y); + + // splash 1 + Image splash1Image = loader.getImage("/gfx/splash/1.png"); + int splash1X = (screenW - splash1Image.getWidth()) / 2; + int splash1Y = (screenH - splash1Image.getHeight()) / 2; + splash1 = new Sprite(splash1Image, splash1X, splash1Y); + } + + // override + public void start() { + lastTime = System.currentTimeMillis(); + super.start(); + } + + // override + public void run() { + while (getGameLoop()) { + fps.process(); + space.update(); + space.paint(graphics); + long delta = System.currentTimeMillis() - lastTime; + + // painting splash 0 + if (delta < 4000) { + splash0.paint(graphics); + } + + // painting splash 1 + if (delta > 5000) { + splash1.paint(graphics); + } + + // painting white fucking effect + if ((delta > 4000) && (delta < 5000) || (delta > 9000)) { + int c = random.nextInt(2) * 255; + graphics.setColor((c << 16) | (c << 8) | c); + graphics.fillRect(0, 0, screenW, screenH); + } + + // set screen menu and stop painting splash + if (delta > 10000) { + LongFlight.link.setScreen(LongFlight.MENU); + } + + flushGraphics(); + LongFlight.link.sleep(20); + fps.max(); + } + } +} diff --git a/src/code/kalter/longflight/space/Egg.java b/src/code/kalter/longflight/space/Egg.java new file mode 100644 index 0000000..e2ced2a --- /dev/null +++ b/src/code/kalter/longflight/space/Egg.java @@ -0,0 +1,51 @@ +package code.kalter.longflight.space; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.Sprite; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Пасхалка + * + * @author KalterFive + */ +class Egg extends Sprite { + + private boolean alive; + private final int maxH; + + public Egg(String path, int screenW, int maxH) throws IOException { + this(Loader.getInstance().getImage(path), screenW, maxH); + } + + public Egg(Image image, int screenW, int maxH) { + super(image, (screenW - image.getWidth()) / 2, -image.getHeight()); + this.maxH = maxH; + } + + public void paint(Graphics graph) { + if (alive) { + super.paint(graph); + } + } + + public void upd() { + if (alive) { + moveDown(1); + if (getY() > maxH) { + deactivate(); + } + } + } + + public void activate() { + alive = true; + } + + public void deactivate() { + alive = false; + setY(-image.getHeight()); + } +} diff --git a/src/code/kalter/longflight/space/Planet.java b/src/code/kalter/longflight/space/Planet.java new file mode 100644 index 0000000..acb7583 --- /dev/null +++ b/src/code/kalter/longflight/space/Planet.java @@ -0,0 +1,72 @@ +package code.kalter.longflight.space; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import java.io.IOException; +import java.util.Random; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Генерация случайных планет + * + * @author KalterFive + */ +class Planet { + + private final int screenW; + private final int screenH; + private final int COUNT = 5; + + private final Random random; + private final Image[] planetGraphics; // все планеты + //======================= + private long lastTime; // для засекания времени + private long delay; // задержка для генерации планеты + //======================= + private int positionX; + private int positionY; + private int index; + + public Planet(int screenW, int screenH) throws IOException { + this.screenW = screenW; + this.screenH = screenH; + random = new Random(); + positionX = random.nextInt(screenW - 60); + positionY = -100; + index = random.nextInt(COUNT); + planetGraphics = new Image[COUNT]; + Loader iml = Loader.getInstance(); + for (int i = 0; i < COUNT; i++) { + planetGraphics[i] = iml.getImage("/gfx/space/planet/" + i + ".png"); + } + delay = random.nextInt(25000) + 10000; + lastTime = System.currentTimeMillis(); + } + + public void paint(Graphics graph) { + long delta = System.currentTimeMillis() - lastTime; + if (delta < delay) { + return; + } + graph.drawImage(planetGraphics[index], positionX, positionY, 0); + } + + public void upd() { + long delta = System.currentTimeMillis() - lastTime; + if (delta < delay) { + return; + } + if (positionY++ > screenH) { + newPlanet(); + } + } + + private void newPlanet() { + for (int i = index; i == index; index = random.nextInt(COUNT)); + delay = random.nextInt(25000) + 10000; + lastTime = System.currentTimeMillis(); + positionX = random.nextInt(screenW - 60); + positionY = -planetGraphics[index].getHeight(); + } +} diff --git a/src/code/kalter/longflight/space/Space.java b/src/code/kalter/longflight/space/Space.java new file mode 100644 index 0000000..58df58e --- /dev/null +++ b/src/code/kalter/longflight/space/Space.java @@ -0,0 +1,56 @@ +package code.kalter.longflight.space; + +import java.io.IOException; +import javax.microedition.lcdui.Graphics; + +/** + * Космос: звёзды, планеты и фон + * + * @author KalterFive + */ +public class Space { + + private static Space instance; + + public static Space getInstance(int screenW, int screenH) + throws IOException { + if (instance == null) { + instance = new Space(screenW, screenH); + } + return instance; + } + + private final Egg egg; + private final Tile tile; + private final Planet planet; + private final Star star; + + private Space(int screenW, int screenH) throws IOException { + egg = new Egg("/gfx/ship/5.png", screenW, screenH); + tile = new Tile("/gfx/space/background.png", screenW, screenH); + planet = new Planet(screenW, screenH); + star = new Star(screenW, screenH); + } + + public void paint(Graphics graphics) { + tile.paint(graphics); + planet.paint(graphics); + star.paint(graphics); + egg.paint(graphics); + } + + public void update() { + planet.upd(); + tile.upd(); + star.upd(); + egg.upd(); + } + + public void activateEgg() { + egg.activate(); + } + + public void deactivateEgg() { + egg.deactivate(); + } +} diff --git a/src/code/kalter/longflight/space/Star.java b/src/code/kalter/longflight/space/Star.java new file mode 100644 index 0000000..94100a3 --- /dev/null +++ b/src/code/kalter/longflight/space/Star.java @@ -0,0 +1,49 @@ +package code.kalter.longflight.space; + +import code.kalter.longflight.Color; +import java.util.Random; +import javax.microedition.lcdui.Graphics; + +/** + * Звёзды... + * + * @author KalterFive + */ +class Star { + + private final int screenH; + private final int COUNT; + private final int[] positionX; + private final int[] positionY; + private final int[] color; + + public Star(int screenW, int screenH) { + this.screenH = screenH; + Random random = new Random(); + COUNT = (screenH + screenW) / 3; + positionX = new int[COUNT]; + positionY = new int[COUNT]; + color = new int[COUNT]; + for (int i = 0; i < COUNT; i++) { + positionX[i] = random.nextInt(screenH); + positionY[i] = random.nextInt(screenW); + int a = random.nextInt(256); + color[i] = Color.maskRGB(a, a, a); + } + } + + public void paint(Graphics graphics) { + for (int i = 0; i < COUNT; i++) { + graphics.setColor(color[i]); + graphics.fillRect(positionX[i], positionY[i], 1, 1); + } + } + + public void upd() { + for (int i = 0; i < COUNT; i++) { + if ((positionY[i] += ((color[i] & 0x0000FF) / 50)) > screenH) { + positionY[i] = 0; + } + } + } +} diff --git a/src/code/kalter/longflight/space/Tile.java b/src/code/kalter/longflight/space/Tile.java new file mode 100644 index 0000000..99ab830 --- /dev/null +++ b/src/code/kalter/longflight/space/Tile.java @@ -0,0 +1,49 @@ +package code.kalter.longflight.space; + +import code.kalter.longflight.Loader; +import code.kalter.longflight.LongFlight; +import java.io.IOException; +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +/** + * Тайловый фон + * + * @author KalterFive + */ +class Tile { + + private final Image tile; + private final int screenW; + private final int screenH; + private final int widthOfTile; + private final int heightOfTile; + private int positionY; + + public Tile(Image tile, int screenW, int screenH) { + this.tile = tile; + this.screenW = screenW; + this.screenH = screenH; + this.widthOfTile = tile.getWidth(); + this.heightOfTile = tile.getHeight(); + this.positionY = -128; + } + + public Tile(String path, int screenW, int screenH) throws IOException { + this(Loader.getInstance().getImage(path), screenW, screenH); + } + + public void paint(Graphics graph) { + for (int x = 0; x < screenW; x += widthOfTile) { + for (int y = positionY; y < screenH; y += heightOfTile) { + graph.drawImage(tile, x, y, 0); + } + } + } + + public void upd() { + if ((positionY++) > 0) { + positionY = -128; + } + } +} diff --git a/src/gfx/about/window.png b/src/gfx/about/window.png new file mode 100644 index 0000000000000000000000000000000000000000..930c5b8becc20760823d3576b16f30da77b043ea GIT binary patch literal 909 zcmV;819JSrMZM#|g5|E_Ae4)4cU4h8#2CZYUp6vsf109F!}~TSaxIq0y)LW`3Gv+U zRDdQGrmm1|5wRVa`%h;U^JkRy&O+Gl5j}SnXaU5 zQ?LFciyjA?%tO2Q?6jsaY`7r7nQ9imv1sE#YdroCH7`CB-7}BR?MMAKk*tYZ#zrAO z2d|A>SGVJ^{_Lkt3y*o|F$F#QBwp04wbDz_6h)#7NTl&lD^fpKuA?(dF&i&7_)eN3 z);54y6a5@%UW*betXl)|u2fZNHouSzj&5vGEK3vKnrWEMlYAtPX4@pog+CZogjYeA zL^~k5{9810FC!r|)@Uz1{t~kl4JrJMrUg%^1D}`t^6`*Aaj@at{pF-?`?TP&jPnzY zv{F4y6w|q69Ofmu$^%m{zbPK@V(!Sl1lLRKDhqp;&-R84$la7?0YO(Qd+DEj?h0e> znlm>cy%0cjdwgjJ#D?qv&HHzd`Ria7C{iM(+%<{SUK!9s(S3|Hs$HG_>Ie_z^dCMg z_Ct@o+r?qWOi!S+_d(-8?iYq|DdP{aT-4P+ySZ*{;DQxCG_jNSn(Z6ElOzdbf)w+> zxpigYl4J)2o)AO%`pU5q&Kd-M2l^KUj)(zXywtqy2JD06Jcm1O*ie z=dj6F4X5tmM8VzG*CciKT@(t>S468SGz5a>B>M$J*HmwuITwMFP*5Hn$4S`IrihJI zAu(ZJ;^~YguAf?LG&FH%Z?wb_YWKDL6&6!i>TUK5EOqigX(8$Tev^$Xd6}E_xu92@ z+mIf3QE%v!ecid&xtOuiXT9ssrbVy0a6wxsSXM3=b)ax4Uz4^bve~S8XcGu0r3GK{ zJddp!?D8oXx^V=^czI9=5<*7KgBh0!78g#`j zmoi@~4g4w4;NF-SeJE6yFsZB})l;2ERNYV&h5E6O9t*iJ5^B1pHOL4Mqg$cYgbeBF jS}Lfoa=cZ^Lp!D^%0w$ca-aKrDxkWWzJ>X%tIzKpBNM&v literal 0 HcmV?d00001 diff --git a/src/gfx/awt/down_panel.png b/src/gfx/awt/down_panel.png new file mode 100644 index 0000000..13bbb3e --- /dev/null +++ b/src/gfx/awt/down_panel.png @@ -0,0 +1 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄŒÖ_6ånš¢R)Jér-¦‰½.¬ ñÜdTw禺úëL½`l'–-KÄCç¡»´áºüÞÉѳØç¬ë6xñ›\¨Aòײ|¬äk°%4ÎÆ"L›Å\TÐ/T/R(DàÎÈù‘½´ñVz`‘–kâÙC \ No newline at end of file diff --git a/src/gfx/awt/left_soft.png b/src/gfx/awt/left_soft.png new file mode 100644 index 0000000..138ef22 --- /dev/null +++ b/src/gfx/awt/left_soft.png @@ -0,0 +1,2 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄÖÖ_6®/š¢RÝ·Ógr-¦Ý,®ýŽ˜ô)ÒDïXú·C@ƒ*™P¤ãQÞÊfýȯcXØa£òª + àí¿®«¾ù^ï5¦eúl,¸ÕgÔ£L»–þ¤’ãcÓè—E¸ú\3Þ ©Zúü |CgôGƒZ ¡³åAT‹ iúëI²q­’ª[Ñßìß­¡å%#µËŸRÞÐh©:¡⠈.SiÆÎ¥Äa[ \ No newline at end of file diff --git a/src/gfx/awt/right_soft.png b/src/gfx/awt/right_soft.png new file mode 100644 index 0000000000000000000000000000000000000000..f76b196b2510f7df60445d8151f03ee64870a17f GIT binary patch literal 182 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 W8>%9Ov7$-j{WGN(6KV|wL`%XE33f>U literal 0 HcmV?d00001 diff --git a/src/gfx/enable_sound/choise.png b/src/gfx/enable_sound/choise.png new file mode 100644 index 0000000000000000000000000000000000000000..5af5060d6f1c908d1ee32abaeb97b6982473ad09 GIT binary patch literal 761 zcmVOtEsQ~Gy0ZYuJ=IaAz#cCCI+TjXlsi-^!LqzNn)~JM7<}~ zqs}Gr%uqxNX(0+z+HAKS?HfJtDX;FEzAt*!pA~Ibr z^qTGpSP4hfX{1t=gHoGBxmSZj{E63Y3=O4v;zf#FBmKpcilDyN0A2oAxywxtR^K0V zQhVgxQK;K$wvweM*yM$(#Fqv6J`IuzGS|VP^ z;EnZ##>32S$qta+a$BQ24~aIe1ClUZHEEu$ibgG1XzW*km%(;<+4+O2_15^xH-3h2 z)9L^;cu6H~ehF@p`;6BO&+m^#;pvN>o=~X)i5L#!b!`3Hg=GbYfRy3AE^{nrQ&A+@ zChp$E`Np#VbvS>is{n=uT1RUV1xjT{F$|_OT&y_1h%$keYzY9yP+#!dBC^;;O2p;$ zrS*gzJrO4pUMFm9CU$z1(uC++#nrGIC*>!%nT-Hz1h4HHN3tsSU`tK3e;QdX0~pO{ z7_~Q7JXPwwGs&4$XLIz-+19d(DpV&mwpAPP>Dy#E;$$?|phR)0j)rhyMVdQ}GHwVi zd-P!_9P?5RbEx2_;j~*~qdr7VO)NDXCHrB@wN-37^TekCZf)7yC9SA>@1BH*oQR#O z3J>Uc1|Vs(L$@dWWJg?NIMB|Y!802nzs2FB4dks=er0TZ8$1Z8gpb`b8%wSAq^DJk zgF1g3j;aK1YA(D9HQzo4&&bg(_+>AZ7=Zgppv^|L7peteGqM0B7RAo+20_g$-j|}W zi#e)BiKD45Csq^mWooi(a>b}|q1SPG!!A2HLN)dU(r;~P3o}utWD-vy)5q3c*ZKu1 rH&6AxWjY_He})7W(g;k9jjk0&WCZ@^a(ajI&wiY5gVT$>GpuRwKV@?P literal 0 HcmV?d00001 diff --git a/src/gfx/enable_sound/window.png b/src/gfx/enable_sound/window.png new file mode 100644 index 0000000000000000000000000000000000000000..ae07e42c2543034eee5b9ac4b5ddb5143e177ed6 GIT binary patch literal 516 zcmV+f0{i{KMZM#|g5|E_Ae4)4cU4h8#2CZYUp7*1f109Fu5JkTaxJzny)LW`3Gv+Y zT(Z{^Ci3$ZN{zvlNvH!Uj2NIFu%0xq7_m*un>`BHGvTAx(bVzzF!7v*s|`}x`UXq3 zv_~UU3=UNA+kiRnas;~V0v0Yk*Lin&re(mXThyR%)Fyn=W@_60V7>`KAVhpTzbyv3 zvDkHH$+bEj6l+9`DBBf;2YzslvX(jA)b&ziI?CnXpB4RW!UBj+%S#71T+}X9}Z^BH?R9W{35eMy1)= zFLH4GGk+Gx$RFCo*2X}(0J5uWA(raIh?N@MOP$==XE^y;8=sDNbnMz(sLP$Kf{2Iv zQSW=>+VghBhcEh*HDG58g4PCni9QuEGeK7Pn`)>`1L GJC`VJM+KPx literal 0 HcmV?d00001 diff --git a/src/gfx/font.png b/src/gfx/font.png new file mode 100644 index 0000000000000000000000000000000000000000..55258e67b751ae80d449b7d8a910db65b9386caa GIT binary patch literal 487 zcmVCTvm|xU>@8qIOSc{%O;)W#+1YMV7F_j1qxq>)92^L zTw$Ok(s8_@g;~D2lXj)JT^u-0NCmrRgbFbq9E}w?B*+kRg;iKMzCr|bi^>jl3g24@ zPg4!?fVmk%MrEB&cK-T)dz`WCSx)B*;SI6`T=1rE!`YQoZONRdq{*wp6hdYN!q&-3 zBbHRd?l-(0)0$yOB~CaV_A4O(qq&s&+T(&41^M#Sk5&Vr0a&u;^VhrZBGOewEc6C4 z_6@ic2jQ~@B;mOtV0^zTzN-l`GE#W-R5c8+Nc1Cg3a-->5;F&snxFD?I8bVSgt{a0 zskpme1Gl#QS7ff!B#0BK{y0YmQAKRNgd2PXH%x%-vRH<*-Y%aYlkylZ|9y0J(Cn@} zY;F9y3vBlP^+{t8ki>Gc4fGbe+PEWwF~L44BeYH3AeI^%>5|(eG^Y(4rNvqwfI%Ir d2m~S1nkjo;Up^TYdJoX_@{B)+mT;S;g3oRTaP_xzEF=Q6~TZ literal 0 HcmV?d00001 diff --git a/src/gfx/game/life.png b/src/gfx/game/life.png new file mode 100644 index 0000000..81daada --- /dev/null +++ b/src/gfx/game/life.png @@ -0,0 +1 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄÇÖ_6”n?š¢RH€ýšr-¦¾½.¬ ñ4/O;™‚ .2Îƛ§ÇøQª ±kæ@jOw’x¿—¬â-‹© ’Î<è#¯ \ No newline at end of file diff --git a/src/gfx/game/overheat.png b/src/gfx/game/overheat.png new file mode 100644 index 0000000..1e87607 --- /dev/null +++ b/src/gfx/game/overheat.png @@ -0,0 +1 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄÇÖ_6”n?š¢RH€ýšr-¦¾½.¬ ñ4/O;™‚ .2Îƛ§Ç1ÑYêè8Ðu(Ÿ’Õ@_8ÔË£X´¬â-‹© ’Î<è#¯ \ No newline at end of file diff --git a/src/gfx/game/right_soft.png b/src/gfx/game/right_soft.png new file mode 100644 index 0000000..7a5ac0a --- /dev/null +++ b/src/gfx/game/right_soft.png @@ -0,0 +1,2 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ĶÖ_6®/š¢R VÔr-¦Ý,®ýŽ˜ô)ÒDïXú·C@ƒ*™P¤ãQÞÊfýÈßcXØa"ò +¤æ­¿*ÄØʞ\áÄÖü‚`ÍZkí«•vX^L 7TE•6år)qÆÓºuû”6sû#,’ ´¯VÅ#¬ãƒx힎DÊÊÝ@j÷¢R*¯®t¿f˜/E_Á—«Ÿ˜ˆ.Sý~j¯y>¼ \ No newline at end of file diff --git a/src/gfx/game/up_panel.png b/src/gfx/game/up_panel.png new file mode 100644 index 0000000..e5a9a29 --- /dev/null +++ b/src/gfx/game/up_panel.png @@ -0,0 +1 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄŒÖ_6ånš¢R)Jér-¦™½.¬ ñÜdTw禺úëL½`l'–-KÄCç¡»´áºüÞÉÑdèçnҞb-›?ô6‚ÖÍ%§­"¿Ìc‚¨<¯DÁÿ3á1ÿ–sp?™Swm'»Í!ôåÆVz`VÛBw8£i \ No newline at end of file diff --git a/src/gfx/hscore/window.png b/src/gfx/hscore/window.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1612c86e24c1bbf9cce95913270530abda6f8c GIT binary patch literal 516 zcmV+f0{i{KMZM#|g5|E_Ae4)4cU4h8#2CZYUp6vsf109F!}~TSaxJzny)LW`3Gv+Y zoO9C^r}F!HNz~ApT5O6THaw?FpZ1b@@ts@-g%nS0uE6DPHLVlUe7z}Ot}r}Lg9K(d zOWu9Hw=&j*Tk+q7C z6NwNk`H>^jJ`;PvF+sS%iR3Qwc6ZCzl32V3d1S3+liPv-Qm^~wn^JE%5^jL-w zEswZ4)aT*jJY+wATa)cprPk6(cx-&5(L`U?Q~s0N2TV!dy!HtYf!&o9g}~xpoaM!T zI~#wgImYG(8n6Z5<3HBYv_26S3u9CwB?g^m7bs0z8FFCYgGxRj)BO1s??g$LvCBa# zkSenv`98+01Fk~7{8!vO0WoRSz!y>dWySc2+K(WKWP$nG=)!|*XFDQh>4mlk z7wF*BU+-q$7up$7rfk0r$+`57jdUU;4SjrC%xfW;`hNTKZJa-dW>eI)6D|p>)>`1L GJC`Wo+5;8< literal 0 HcmV?d00001 diff --git a/src/gfx/icon.png b/src/gfx/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5e63de5d5446bfd15c9ec2cc81acd171c62918d6 GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!GcfQS24TkI`72U@f)XXJ5hcO-X(i=}MX3x0iJ5sNdU>fO3MP66 zdL}|mOrL>j=6Jd|hIn{yJ+qOQi9vwb@LD3LT7vku_d9OIUQph-Q>oJC-u(ZY&fk3g zruduX?>Tdyzb=nC$~T)ceB`@Q-4&D%2W UC;d>`3v?%gr>mdKI;Vst03bbcf&c&j literal 0 HcmV?d00001 diff --git a/src/gfx/loading/loading.png b/src/gfx/loading/loading.png new file mode 100644 index 0000000..860069c --- /dev/null +++ b/src/gfx/loading/loading.png @@ -0,0 +1 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄÇÖ_6Tþ/š¢Rdf¡lr-¦ì,®ýŽ˜ô)‚£®Ú»4æ²@v‡Ý|.ŒÍ&P»íR#ËÏÒon#ŒöÏæ åÿ>¹E‚ÎÚϯèŒÐó°15ü*Œ]¿‚ÿg°?„'[Éê5xÏ#‰î‘ñÂ.„A(«  \ No newline at end of file diff --git a/src/gfx/menu/choise.png b/src/gfx/menu/choise.png new file mode 100644 index 0000000000000000000000000000000000000000..599d5f8cd3f6208e470e9c9762762e6fef9fc72c GIT binary patch literal 1569 zcmV++2HyF?MZM#|g5|E_Ae4)4cU4h8#284{UpC-wKboRaS?rPlaxJEu9#70{j<)XT z-ly*t=Zx}ZRK*j5klV>OtEsQ~Gy0ZYuJ=IaAz#cCCI+TjXlsi-^!LqzNn)~JM7<}~ zqs}Gr%uqxNX(0+z+HAKS?HfJtDX;FE&Y*hLwY<}PXZft?U4$l-U7 zq(km6LK+g)O|~i>Gu}1;qDRv106fye8@n><`Igb|Xa%vLPQEjD7+BYVfY{itEw~Ae zQ%IuLLg_*|qBXq#Vle@?=~oF<2u}9A^jVwi9`^$6fS`?*7P@~pR%GKzT%r7{*xeJJusd#n{RaXT zKNAmZQRz3fO(m=ESwSUxUhZZ}q%AVIcivd>C_vWsMKw`cQ|M^x{P*-51Flo}`D*vh zp892#KL3fTLf_m#1-Q@ZFD4(*{Kk(V1(8xi?=PVGJep*O8s_KB&AhT2rV(frF~Bsd zT;H;CcxBb~EzKXA@h*_{WseEa@EbR0brYmCd~PV7P)13FaA1xo{DA;sxn|2=_Qovj zk8B{*f9D9o@+pZo6r)PyAV!2#!Yf*^H@>&O3!CC6ZHYxzATrv{@Bp}Fb3Ah)rmxdq zTV{31*X;g4`7Wi@}E%#NWt zIN<>C+7&HC1fc{ zOCjfSt^?brP3Xbs6bBTbkdup@1&6D23+9JTk|i=Rx&e~eL@~y-W?_Jm?rR|06w?r( zOBDHmcWNg4Lqt$Uo|41a{O|7|{ee#zL#@a?knKXvlDo+?W%$R$GV~>+php*OMgst8 zRY+|2I}oj{vdRz!i-jxQ2%~&t;?+N5R9xD1qSHxC+FJ5|Bh1T- zm-Ad+{gEf$@?>(m@_dnIytYM!dr(vthMU(;a~flP;^sS4K&ZrSIZNUEZfJO@8D)`M z5qSLoMlQbpWA4RVbNB TQze>+=OD~poj|qhxltLp9MBf3 literal 0 HcmV?d00001 diff --git a/src/gfx/menu/window.png b/src/gfx/menu/window.png new file mode 100644 index 0000000000000000000000000000000000000000..f2b7b4eeec7b00e349c1432f92edc68c105ea133 GIT binary patch literal 469 zcmV;`0V@8&MZM#|g5|E_Ae4)4cU4h8#2CZYUp6vsf109F!}~TSaxJz+y)LW`3Gv*N z{j$RnCi46HOPAG&0cA3Q^mNZY*nFeYrE|z0-S<(nQ`uve(cHTZ_;nc=>#?fp{e7*Q1D}(|H?>*YH7=C0+!A>ZuWpDl(A_m@CaLNYQ+*XH(yD&&&=rrBURiJuaBjX z>w4b(eO}Zj+Nf;zqKsIQLNncid(~+9UYaMf_(J)b8O=%MHmZSu2eFxq-GKPX4vDc} zM$0ZZ;-!Nkp~U40U$AQmzddQ`wwH=CANPV1(Cy;zPD%D=CvXnuc}Q)|JmNQVlc9u# zZV@-li&=3)ikJHyEVfw2wHu#C=;3;UR{`yl?FkM(LTNe(GZT$w&H!1zovG~Vk7h(c z2~I|%x;7WqyDnANM0O@fy(51 zOD7qw>AoBT<|r5P{2#e!^Lop2z%%RD6kw@a+Ld*b)LT(I;2-%aGcISetqst_#zNPr z$~WrRbAWc^RSGtA^L{n?e{T_DrvV3U&55jCTJc>8>pvX+w#PGK8yUytYpaetlGrD- L$FT!@uWjNu&zJSI literal 0 HcmV?d00001 diff --git a/src/gfx/pause/choise.png b/src/gfx/pause/choise.png new file mode 100644 index 0000000000000000000000000000000000000000..05657a1eb67c59941116199cfc05ae58d9936bc0 GIT binary patch literal 986 zcmV<0110>zMZM#|g5|E_Ae4)4cU4h8#284{Up5AAKboRadINN$axJEu9#70{j<)XT z-ly*t=Zx}ZRK*j5klV>OtEsQ~Gy0ZYuJ=IaAz#cCCI+TjXlsi-^!LqzNn)~JM7<}~ zqs}Gr%uqxNX(0+z+HAKS?HfJtDX;FEu049yA> z+_RGro`&w|`LjUuyrxPpj+Oa;)J|$q_wH$VWP=S|fvi**Owz*V?^VIi`N*w`!&hN= zk%GfPSjT2k?H7)e=HS3TZ{~3~(9mvu8GYyy$}}E!=c zQIrhG!hi-;0nY5Gj^5iPk7F>gH%KMxf(4~SGqnKu#DfNh_Y2f0-E9gCq!^N@O5A5i z)o`1!0-@gxHbJ$`4;byi&&4+w_yGpJvs9cDo|$nnD=(TXhIEq%b&_>mb8naZkg+vD*%0t)vV_w)1v&{4L&f$&A6T&3rxdrj&oJh$#$x;tNv z^w(*h80pR*A`3y9TNNo(9-F2ui=e{Z+}&4-aIN5+f|zu;6JiV|kJi&+m+vNJ|BjJB z1_b9r4|c`888&GBQ3P8abx&O|>uhfcn<&OY^`9KM$rSkD8S_oe;ItWBsQgvh(!>Bl z^n*wVT{4=FJf|$v09`rnNU}s|rIc*YEFSyq%Y5dFMR8!CsLXifUar(NAPhe)iwnUP z?!)D~7`QM6cttkuH9QDn-_i5G-bI<);xPtnv|ow=ft}h~h>Ky$L5T<~G7ZM8T;h6I zrN;$sSogPrcvBi0i( zAD1o_wFAbc`BTC#u{!5#_rhH%Q)JZmqM+6T*kYX~loxpMra9{XFS~kKYpwN1t`5-= zJGgso9b%aN0Dp_}I7eur@yX#zWEN(;ZO2GEkC9^-GzvNMk0{}S7N);BCXJSW05hz~ Itxgnt6N63l?*IS* literal 0 HcmV?d00001 diff --git a/src/gfx/pause/window.png b/src/gfx/pause/window.png new file mode 100644 index 0000000..d6649e7 --- /dev/null +++ b/src/gfx/pause/window.png @@ -0,0 +1 @@ +ÂE½ãÀ‚å®â ”‹nwUQ?ÄÃÖ_6±nš¢RMin*r-¶”½.¬ ñÜô\°Ç&òóJÁ›:%1`§†âÄvå‹îCCÇܣʩ(Z”Î÷…ÙG‡~Á=+iŽjáÏ2Ù4ߓ/ð€Ê™¢.Û±2ÎöE[=!™1äóJÍÜ&8öµ,¹5îÞðpÁ€ÓŒn³Ÿ5ZYÓtØÀ±"I\y`dìþ½W°9ÂÏ$;n‡²óË·ƒò›ë*´jýÍ(Vd}•æz£›L*‡ò¿Ù¼Ü“pV¢ox­‘j:?}÷‚M(\cêÕ¤x%¤Ñä8‚+T-þ÷ô|'—¨,οkQ­›¬v.ÐÀ‹”&Y'PïLN•‡j¡aõ¼2sùA'²mʶx‰ÛŠ®³½-sH¨“³Ö‘ÆNÞ}SøV㊆˜*i½lDK,Ó÷f ÌH…±8Nan;!ñÏI³óŒ=ð§0q K•Îg¶ó]Eé¨Õ¿ÛD~M­lˆ!Ât´áâ. ®:Ì;kèÞ»T;ÎãSöe:eöc RA6`Ì(ƒK3 '½Û \ No newline at end of file diff --git a/src/gfx/select_ship/frame.png b/src/gfx/select_ship/frame.png new file mode 100644 index 0000000000000000000000000000000000000000..5442326d9b4fb24972a5a2a681646473cecb9fa6 GIT binary patch literal 130 zcmV-|0Db?$MZM#|g5|E_Ae4)4cU4h8#2Ba6UpD8?FPfrKCRTp)axJDzEUx_=j;v!T zLRIf&viicbdNYQ+Xln*CZ|%FhBv2&Io#!u-r&-Dy3U=qIqAB&I)@e&ui97%@d6 klzD?&#=lNUzJ>f0*cCBz+xeUxb&&3xo*lY%wY*+tE%k~)00000 literal 0 HcmV?d00001 diff --git a/src/gfx/select_ship/lr_button.png b/src/gfx/select_ship/lr_button.png new file mode 100644 index 0000000000000000000000000000000000000000..41fba6be57135a048be4d39f56998406d66ce579 GIT binary patch literal 167 zcmV;Y09gORMZM#|g5|E_Ae4)4cU4h8#27@@UpA#~f109FU%;<$axJE6y)LW`3GrK% zTX*LbXTJM*NJE7HPy$m5OB&y+hCi=RWth}@!YX7LFRxi;3O}F|CRwb`<~E(`p%B*& zIfJF&T_(65?@N@2_E;+U+nY`7Pt04@!l}Ba)xdp?8cFn!A|nH2WksKt$_XY2Iq3TN V@U1EPrxZYJ0if9UTccl)Nep%GQ40V7 literal 0 HcmV?d00001 diff --git a/src/gfx/select_ship/window.png b/src/gfx/select_ship/window.png new file mode 100644 index 0000000000000000000000000000000000000000..7c1c1052c89a28883837ea5f573225f58cd76c13 GIT binary patch literal 499 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 literal 0 HcmV?d00001 diff --git a/src/gfx/ship/3.png b/src/gfx/ship/3.png new file mode 100644 index 0000000000000000000000000000000000000000..2165ed71e70142590f5c5a672a1d6edf70764fc5 GIT binary patch literal 2428 zcmV-?34`{+MZM#|g5|E_Ae4)4cU4h8#25zFUp7W=f109F*sSvhaxJFJUw&*{j$9eh z@M!r)r~2k1M?r?JXlv#z`>9X$vs-^q3HLw;ycn2qT_Y^YrCOaDqIQqKTEoCg#;z5? z!7aXLlhj8GM!qZ}TzO}I*iw6%B|3a+3Ehhkiia*Onz#$But1`GN3?;q4iHVk~ zkN{`|i|N`>D(==0$Xyi%kj6ENw$5G-00qqx_(nRqI!5BWz!5TW&OfRG6sRRMt8XPo zYy*-k(f;;R04j{@;8H#coTK0SkEv+--Dsif%kWgPDd-LHkj?)-R$f;19aMFeQ=j)P zR1qPvi}8m6tB-{V_29it&9z^XIe`1$pCVVk>h2Z)4!_)Mt@9a+&eYy;|lj>ypIytLl=_bbBpwoGc6yd0H6y~|6!k=e zU(e3})tZytt>1_X84Hh7YZ36sF-Wy(+JV?&!kOviSxjD4TyQN^`77;TxReKMpx1B0 zyXkwm3^m%_P{WJYKSBwr+%^#6mUxD$;$<(UB=9wu?Kd||QBsBh-rwwg#@T1wCoFcT zYeThek*ik{br0LHsTKUHh9qT%H)=+3zfr%Y&<~}M>IX)8hLP_D{9Sc2Pa)4}AQu8OgFyH6E6)N`{;W2E#+2i5|2sJVQPef~4QXsSN z6kX8uk{dn|ud@5E^YLbrgp=e#z{m3QRofn$@s7|WHV^#Su)&!jW<|{#Tk_v?*Q>?9 z;efPCCiaBz!oA@rm~(nlA%X=f<-{-?lFIw)6GsD!isLg_cg?UViz4MI?S|aKEMfHl zM29$D&uIilLf`=WZ=Hk06@O#gzR4#6c*lg=zy`m)Oov=yRD~z{X*Z}oq#jU1YT}+j zJQRrcQSh)!Oa!{$@tf~CJ=7`xP_za*qCls259cgHhJzlsK{F+EZ-ot96ZVW1;}X|{ zf#J-lDrgnM{y$iZSf+mHO2RAK;b$l(UsC3d2dS=$FEzjWe}f>8tR|XiWM?;kN;*>H z57ZHZZ^!68bDeAxArtRWq^BaewI^JK7L!of{@1x3d+mC4BbwC)2y`DdiVT6t3p zwnnGi9|Du7hP|R($Q-Kb8945v4X=I`WGxZ;K}yR`)1cYdHJUdn#G*FpseF~NGpA?T zioOn#NlLzHzvCqMat!$(v+IOCbX}w6ltt)`rO!hi5jTXUa;2&wHymNo7O1Eea6|HprOe>i~08wqCe~<>QHdt-y z3s0QuxcmDZ4CqFUL|GC=B3J*!K2M(6ioAekY_#zD3|@$`1>L~vemfCvD@#|MaymA& z+R!I6EX?Tzb0r$Ejje#pOBX0~`K9)(b~`%i#E=K$2(Ee{$Vyz^sA8rY+^rMBcdLO*q=hk$#8?ZG5s30JIYdI!$ zGOe_nG!QR#nuo%N%~$<%trD^Hht<|&&w&J0J=@#jP_+q~2t*KV{4fiQ+ZXH`QT5Zo<# z5X&XDs1Zzw z@~X6^O8%n%Gf-3ibU6f*6^tji|G&qx>D3Eu_68VV)F_c_R;1+aO;m{;j6bqqt_8ua zEs#3#Ea~AJp_N(VpoD~Z8Wr4Hi*7~e@k4V0w&d9hs?tjZ3`7ZC%sk(ad51 literal 0 HcmV?d00001 diff --git a/src/gfx/ship/5.png b/src/gfx/ship/5.png new file mode 100644 index 0000000000000000000000000000000000000000..eaaa593b1be50e299f98bc94638a1afc9c7b699a GIT binary patch literal 499 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 Le1Bw;`nlx!3w%B- literal 0 HcmV?d00001 diff --git a/src/gfx/space/planet/1.png b/src/gfx/space/planet/1.png new file mode 100644 index 0000000000000000000000000000000000000000..621f67d90f9b90b34195c511ab3027aada4f9e04 GIT binary patch literal 3579 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 B2;l$# literal 0 HcmV?d00001 diff --git a/src/gfx/space/planet/2.png b/src/gfx/space/planet/2.png new file mode 100644 index 0000000000000000000000000000000000000000..4c40134d48593f59e78d01837789d06495c93fa0 GIT binary patch literal 5669 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 Lr9#fPv^mox7q0w@ literal 0 HcmV?d00001 diff --git a/src/gfx/space/planet/3.png b/src/gfx/space/planet/3.png new file mode 100644 index 0000000000000000000000000000000000000000..3e9d9a46ddbc2ace5091f688aa8590ca5cba1cc1 GIT binary patch literal 8346 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Ì=}«ÒWnñktçÂ_)EûqKìWž[>þ¦²œ³ÕÈ \ No newline at end of file diff --git a/src/gfx/splash/1.png b/src/gfx/splash/1.png new file mode 100644 index 0000000000000000000000000000000000000000..24b42a054f47ff55eed4663475f1d0d4d5cb1310 GIT binary patch literal 446 zcmV;v0YU!4MZM#|g5|E_Ae4)4cU4h8#26jcUpABeFPfrKW&&l=axJFpEUx_=j$8sM z2A(q+`qSpJK-E;dj9vyMl_bgeqwRED-Qxv-umX|iyeir4f+P9-`x6})$%{4a?z=8Q z7rY*%{LiR8x`EP15grjFZ*D=gGS)o?-Mu=UPR_AL2cPniQRMKvR}-0<4C_pewQr_9qSleH@}h7wm+c0>WpNf{zAr# ziVbObSPK)Tua#S|x5N+6(=WdX61aH`wT~9~C`FtWS_tKV3TFI*c^yV0zmO9+f0hAU z^-HT{FI!b!g7#}hXcK&66VMHp&y*{KVAa`#T-g6$$+Z6QeQ(M#$eR{lD`P@V>{58n zgvSC{|6=Z+YCFh|3L#kEowN~`!f52Ir&}KT{cry#R=(PK^kAScmw|Op1_KD&YQT1P oV~!UOx<~zhobGA=_30?qqnB~SBHp-kofjY1Pg%`5bCX|MIiK*`lK=n! literal 0 HcmV?d00001 diff --git a/src/quote.txt b/src/quote.txt new file mode 100644 index 0000000..a979271 --- /dev/null +++ b/src/quote.txt @@ -0,0 +1,15 @@ +7 +Happy new war! +... +Reactor.Core.destroy() +4 +The rocket took off perfectly. The only pity is landed on the wrong planet. +Wernher von Braun +Kalter +Five +Stuart needs "space" and "time", as if this were physics and not a human relationship. +Kathryn Stockett +That's one small step for a man, one giant leap for mankind. +Neil Armstrong +Every human has a finite number of heartbeats. I don't intent to waste any of mine. +Neil Armstrong diff --git a/src/song/iha.mid b/src/song/iha.mid new file mode 100644 index 0000000000000000000000000000000000000000..e00ea47b3cdb02ea8f9e9808b9e562310df18b50 GIT binary patch literal 51929 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 F^?$X$wjBTf literal 0 HcmV?d00001 diff --git a/src/song/mobscene.mid b/src/song/mobscene.mid new file mode 100644 index 0000000000000000000000000000000000000000..cd6956c6865fbf22242a7b193b7a038805405a42 GIT binary patch literal 31799 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 MG$8!AZw!I|19`TnFaQ7m literal 0 HcmV?d00001 -- 2.29.2