diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..381146e
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/README b/README
new file mode 100644
index 0000000..9c2c966
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+
+The Android port of the Frozen Bubble game. Developed with SDK v. 1.1_r1.
+The code is based on the Java version of Frozen Bubble created by Glenn
+Sanson. The original Frozen Bubble was created by Guillaume Cottenceau
+(programming), Alexis Younes and Amaury Amblard-Ladurantie (artwork) and
+Matthias Le Bidan (soundtrack).
+
+The Android port, just like the original Frozen Bubble, is covered by
+GNU GPL v2.
diff --git a/assets/levels.txt b/assets/levels.txt
new file mode 100644
index 0000000..7eb0100
--- /dev/null
+++ b/assets/levels.txt
@@ -0,0 +1,1099 @@
+6 6 4 4 2 2 3 3
+ 6 6 4 4 2 2 3
+2 2 3 3 6 6 4 4
+ 2 3 3 6 6 4 4
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 7 7 7 7 7 7 -
+ - 1 1 1 1 1 -
+- - 2 2 2 2 - -
+ - - - 2 - - -
+- - - 2 2 - - -
+ - - - 5 - - -
+- - - 5 5 - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - 7 - - 7 - -
+ - - 7 1 7 - -
+- - - 1 2 - - -
+ - - 1 2 1 - -
+- - - 2 5 - - -
+ - - 3 5 3 - -
+- - - 5 3 - - -
+ - - - 3 - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 0 0 - - -
+ - - 5 0 1 - -
+- - 3 5 1 6 - -
+ - 4 3 - 6 7 -
+- 7 4 - - 7 4 -
+ 6 7 - - - 4 3
+1 6 - - - - 3 5
+ 1 - - - - - 5
+- - - - - - - -
+ - - - - - - -
+
+- - 0 0 0 0 - -
+ - 0 1 1 1 0 -
+- 0 1 0 0 1 0 -
+ - 0 1 1 1 0 -
+- - 0 0 0 0 - -
+ - - 7 - 7 - -
+- - 7 7 7 7 - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 4 4 4 6 6 6 -
+ 4 - - - - - 6
+- 4 - - - - 6 -
+ 4 2 3 1 2 3 6
+- 3 1 2 3 1 2 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 4 4 4 6 6 6 -
+ 4 - - - - - 6
+- 4 - - - - 6 -
+ 4 2 3 1 2 3 6
+- 3 1 2 3 1 2 -
+ - 2 3 1 2 3 -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 0 0 - - 2 2 -
+ - 5 - - - 3 -
+- 0 - - - 6 - -
+ - 3 - - - 0 -
+- 4 - - - 5 - -
+ - 2 - - - 3 -
+- 2 - - - 1 - -
+ - 3 - - - 4 -
+- - - - - - - -
+ - - - - - - -
+
+3 - - - - - - 3
+ 6 3 2 4 6 3 2
+4 - - - - - - 4
+ 2 4 6 3 2 4 6
+- - - 6 - - - -
+ - - - 3 - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 2 - 1 - 1 - 2
+ 1 2 - 2 1 - 1
+1 - 1 - 2 - 2 -
+ 2 1 - 1 2 - 2
+- 2 - 2 - 2 - 2
+ 1 2 - 2 1 - 1
+1 - 1 - 2 - 1 -
+ 2 2 - 1 1 - 2
+- 2 - 1 - 1 - 1
+ - - - - - - -
+
+- 7 7 - - 5 5 -
+ 1 - - - - - 4
+2 1 - - - - 4 3
+ 2 - - - - - 3
+1 2 - - - - 3 4
+ 1 - - - - - 4
+7 1 - - - - 4 5
+ 7 7 - - - 5 5
+- - - - - - - -
+ - - - - - - -
+
+7 7 - - - - 5 5
+ 1 5 - - - 7 4
+2 1 - - - - 4 3
+ 2 - - - - - 3
+1 5 - - - - 7 4
+ 1 - - - - - 4
+7 1 - - - - 4 5
+ 7 5 - - - 7 5
+- - - - - - - -
+ - - - - - - -
+
+- - - 0 0 - - -
+ - - 5 0 1 - -
+- - 3 5 1 6 - -
+ - 4 3 2 6 2 -
+- 7 4 7 2 2 4 -
+ 6 7 7 3 3 4 3
+1 6 1 1 1 3 3 5
+ 1 1 - - - - 5
+- - - - - - - -
+ - - - - - - -
+
+- - 0 - - 0 - -
+ - 3 3 - 3 3 -
+- 0 2 0 0 2 0 -
+ - 3 3 - 3 3 -
+- - 0 - - 0 - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 1 1 - - -
+ - - 2 2 2 - -
+- - 3 3 3 3 - -
+ - 4 4 4 4 4 -
+- 5 5 5 5 5 5 -
+ - - - 6 - - -
+- - - 7 7 - - -
+ - - - 0 - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 2 5 - - -
+ - 4 3 - - - -
+6 7 - 5 2 - - -
+ - - - - 3 4 -
+- - - 2 5 - 7 6
+ - 4 3 - - - -
+6 7 - 5 2 - - -
+ - - - - 3 4 -
+- - - - - - 7 6
+ - - - - - - -
+
+- - - 5 5 - - -
+ - - - 3 - - -
+- - - 1 - - - -
+ - - - 7 - - -
+- - - 2 - - - -
+ - - - 4 - - -
+- - - 5 - - - -
+ - - - 3 - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 0 1 - - -
+ - - 0 2 7 7 -
+- - - 0 1 7 - -
+ - 0 0 0 0 - -
+- 0 0 0 1 1 - -
+ 0 0 0 1 1 1 -
+- 0 0 1 1 1 - -
+ - 0 0 0 7 7 -
+- - 7 7 - - - -
+ - - - - - - -
+
+- 1 - - - - - -
+ 1 - - - - - -
+- 2 3 4 7 6 5 -
+ - - - - - - 1
+- - - - - - 1 -
+ - 2 3 4 7 6 -
+- 1 - - - - - -
+ 1 - - - - - -
+- 2 3 4 7 6 5 -
+ - - - - - - -
+
+- 6 - - - - - -
+ 5 - - - - - -
+2 3 4 7 6 5 2 3
+ - - - - - - 4
+- - - - - - 7 -
+ - 4 3 2 5 6 -
+- 7 - - - - - -
+ 6 - - - - - -
+5 2 3 4 7 6 5 -
+ - - - - - - -
+
+3 2 1 0 0 1 2 3
+ 3 2 1 0 1 2 3
+4 3 2 1 1 2 3 4
+ 4 3 2 1 2 3 4
+5 4 3 2 2 3 4 5
+ 5 4 3 2 3 4 5
+6 5 4 3 3 4 5 6
+ 6 5 4 3 4 5 6
+7 6 5 4 4 5 6 7
+ - - - - - - -
+
+- - - 5 5 - - -
+ - - - 3 - - -
+- - - 2 4 - - -
+ - - - 6 - - -
+- - - 2 4 - - -
+ - 2 - 5 - 4 -
+1 0 1 0 1 0 1 0
+ 3 - 3 - 2 - 6
+- - - - - - - -
+ - - - - - - -
+
+- - - - 1 - - -
+ 7 4 3 5 - - -
+6 - - 1 - - - -
+ - - - 5 3 4 7
+6 - - - 1 - - 6
+ 7 4 3 5 - - -
+- - - 1 - - - 6
+ - - - 5 3 4 7
+- - - - - - - -
+ - - - - - - -
+
+- - - - 7 3 6 -
+ - - 3 7 3 6 3
+- - 5 7 3 6 3 -
+ - 6 7 3 6 7 -
+- 7 7 3 6 1 - -
+ 3 7 3 6 3 - -
+5 6 2 7 1 - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+5 - - - - - - 5
+ 5 - 6 6 6 - 5
+- 5 4 - - 4 5 -
+ - 3 - - - 3 -
+- 6 0 - - 0 6 -
+ - 3 - - - 3 -
+- - 4 - - 4 - -
+ - - 6 6 6 - -
+- - - - - - - -
+ - - - - - - -
+
+- 7 0 - - 0 7 -
+ 7 - 0 - 0 - 7
+7 1 - 0 0 - 1 7
+ 7 1 2 0 2 1 7
+7 6 3 2 2 3 6 7
+ 7 - 3 2 3 - 7
+- 7 7 3 3 7 7 -
+ - - - 3 - - -
+- - - - - - - -
+ - - - - - - -
+
+- 3 - 1 - 7 - 6
+ 5 - 7 - 7 - 6
+6 - 0 - 5 - 3 -
+ - 2 - 1 - 5 -
+- 4 - 3 - 4 - -
+ 2 - 3 - 2 - -
+- - 4 - 6 - - -
+ - - - 5 - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - - 1 - - -
+ - - - - 3 - -
+6 1 3 1 2 1 4 1
+ - - - - 6 - -
+- - - 4 1 - - -
+ - - 1 - 3 - -
+- - - 2 1 - - -
+ - - - - 4 - -
+- - - 6 1 - - -
+ - - - 6 - - -
+
+- - - 5 4 - - -
+ - - 4 1 0 - -
+- - - 2 3 - - -
+ - 1 4 - 2 2 -
+- 3 1 2 5 1 4 -
+ - 4 2 - 0 4 -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - - 1 - - -
+ - - - 1 - - -
+- 2 - - 1 - 5 -
+ 5 - - 1 - - 0
+- 6 - - 1 - 4 -
+ - 0 - 1 - 5 -
+- - 5 5 0 1 - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 6 3 - - -
+ - - 3 2 6 - -
+- - 2 6 3 2 - -
+ - 6 3 2 6 3 -
+- 3 2 6 3 2 6 -
+ 2 6 3 2 6 3 2
+6 3 2 6 3 2 6 3
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+6 6 6 6 6 6 6 6
+ 4 - - - - - -
+- 3 2 5 7 6 4 3
+ - 5 - - - - -
+- - 7 6 4 3 2 5
+ - - 4 - - - -
+- - - 3 2 5 7 6
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+1 - 7 - - 6 - 2
+ 6 - 1 - 6 1 3
+- 4 - 7 2 - 7 -
+ 2 7 - - - 4 -
+6 - 3 5 0 2 - 7
+ 1 - - - - - 1
+- 1 4 5 7 5 1 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+6 6 6 - - 6 6 6
+ - - 6 - 6 - -
+- - 2 3 3 2 - -
+ - 3 - 5 - 3 -
+- - 5 3 3 5 - -
+ - - 6 1 6 - -
+- 4 2 - - 2 4 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 5 5 - - -
+ - - 5 - - - -
+- 3 4 6 6 - - 5
+ 3 3 4 6 5 - 5
+3 2 3 6 6 5 5 -
+ 3 3 4 6 5 - 5
+- 3 4 6 6 - - 5
+ - - 5 - - - -
+- - - 5 5 - - -
+ - - - - - - -
+
+1 - - - - - - 1
+ 1 - 2 2 2 - 1
+- 1 2 3 3 2 1 -
+ 6 2 3 - 3 2 6
+6 2 3 - - 3 2 6
+ 6 2 3 - 3 2 6
+3 3 3 7 7 3 3 3
+ 0 5 0 2 0 5 0
+- - - - - - - -
+ - - - - - - -
+
+- - 7 7 7 - - -
+ - 7 2 2 7 - -
+- 7 5 5 5 7 - -
+ 7 7 7 7 7 7 -
+- - 6 - 6 - - -
+ - 6 - - 6 - -
+- 6 4 4 - 6 4 4
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 3 3 - 3 3 3 -
+ 3 7 5 4 6 5 3
+1 3 3 3 - 3 3 1
+ 2 1 2 1 2 1 2
+1 3 3 - 3 3 3 1
+ 3 5 6 4 5 7 3
+2 3 3 3 - 3 3 2
+ 1 1 2 2 2 1 1
+- - - - - - - -
+ - - - - - - -
+
+- 6 5 - - - - -
+ 3 1 3 - - - -
+- 5 6 - - - - -
+ - - 5 3 - - -
+- - 6 1 6 - - -
+ - - 3 5 - - -
+- - - - 3 6 - -
+ - - - 5 6 5 -
+- - - - 6 3 - -
+ - - - - - - -
+
+6 3 7 4 5 1 6 3
+ 5 1 6 3 7 4 5
+6 3 7 4 5 1 6 3
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - - - - 4 4
+ - - 7 7 7 4 4
+- - - - - - 4 4
+ - 1 - - - 7 -
+- 1 1 - - 7 - -
+ 3 3 3 - 7 - -
+3 - 2 3 3 3 - 3
+ - 2 - 3 - 3 3
+- 2 - - - - - -
+ - - - - - - -
+
+- - 4 - - - - -
+ - 7 4 - - - -
+- - 7 4 - - - -
+ - 4 7 4 - - -
+1 1 1 1 1 1 1 -
+ 1 2 1 2 1 1 -
+2 2 2 2 2 2 2 2
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+0 - - - - - - 6
+ 6 1 4 3 7 5 0
+0 - - - - - - 6
+ 6 1 4 3 7 5 0
+0 - - - - - - 6
+ 6 1 4 3 7 5 0
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+3 3 4 6 6 4 3 3
+ 0 3 4 6 4 3 1
+5 1 3 4 4 3 0 1
+ 0 1 3 4 3 1 0
+2 1 6 3 3 0 0 1
+ 0 3 4 3 6 1 5
+6 1 2 6 4 0 0 2
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+6 6 - - - - 4 4
+ 4 0 - - - 3 6
+0 6 - - - - 4 2
+ 7 - - - - - 7
+4 4 - - - - 5 6
+ 6 4 7 7 5 6 4
+- 7 6 4 6 4 7 -
+ - 0 - 7 - 7 -
+- - - - - - - -
+ - - - - - - -
+
+- 5 - - - - 4 -
+ - 5 - - - 4 -
+- - 5 6 6 4 - -
+ - - 2 - 2 - -
+0 0 6 - - 6 1 1
+ - - 2 - 2 - -
+- - 7 6 6 3 - -
+ - 7 - - - 3 -
+- 7 - - - - 3 -
+ - - - - - - -
+
+- 6 - - - - 2 -
+ 1 7 1 1 1 3 1
+- - 4 1 1 4 - -
+ - 1 3 1 7 1 -
+- - - 2 6 - - -
+ - - 1 5 1 - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+7 7 7 7 7 7 7 7
+ 7 - - - - - 7
+7 - - 2 0 5 2 2
+ 7 - - - 0 3 6
+7 - - - - - 4 0
+ 5 5 - - - - -
+4 3 6 2 - - - -
+ 0 2 0 4 - - -
+- - - - - - - -
+ - - - - - - -
+
+- - 1 - - 1 - -
+ - 4 - - 5 - -
+- 7 - - 1 1 1 -
+ 6 - - - - 7 -
+1 1 1 1 - 4 - -
+ - - 5 - - - -
+- - 0 - - - - -
+ - 3 - - - - -
+- 1 - - - - - -
+ - - - - - - -
+
+- 7 7 - - 7 7 -
+ 6 - 4 - 4 - 6
+5 - - 3 3 - - 5
+ 6 - - - - - 6
+- 7 - - - - 7 -
+ - 4 - - - 4 -
+- - 3 - - 3 - -
+ - - 2 - 2 - -
+- - - 5 5 - - -
+ - - - - - - -
+
+- 0 0 - - 0 0 -
+ 7 4 6 6 6 4 3
+5 6 6 6 2 6 6 3
+ 7 4 6 6 6 4 3
+- 0 0 - - 0 0 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - - - 7 7 7
+ - - - - 2 7 7
+- 0 7 7 7 - 7 7
+ 6 7 7 7 - - -
+6 - - - 7 7 7 7
+ 6 - - - - - -
+4 2 2 2 4 - 3 -
+ 4 4 4 4 3 3 3
+- - - - - - - -
+ - - - - - - -
+
+4 - - 7 - 6 - 7
+ 7 6 7 - - 7 4
+- - 7 - - 7 - -
+ - 0 0 0 0 0 3
+- - 0 2 2 0 6 4
+ - - 0 0 0 1 3
+- - - 0 0 - 3 4
+ - - - 6 - 5 6
+- - - - - - 1 0
+ - - - - - - -
+
+- 5 - - - - 5 -
+ 0 - - 0 - - 0
+0 0 0 2 2 0 0 0
+ 0 - - 0 - - 0
+- 7 - 3 - - 7 -
+ - - 3 6 - - -
+- - - 6 - - - -
+ - 3 6 - - - -
+- 3 - - - - - -
+ - - - - - - -
+
+- - - 6 5 - - -
+ - - 2 6 3 - -
+- - 5 4 7 1 - -
+ - 6 2 2 3 4 -
+- - 3 7 3 6 - -
+ - - 1 3 2 - -
+- - - 4 5 - - -
+ - - - 4 - - -
+- - - - - - - -
+ - - - - - - -
+
+7 7 - 2 2 - 6 6
+ 6 - - 6 - - 3
+2 - - 1 - - 2 -
+ 5 - - 3 - - 2
+1 - - 2 - - 1 -
+ 5 - - 2 - - 2
+6 - - 1 - - 7 -
+ 5 - - 5 - - 4
+- - - - - - - -
+ - - - - - - -
+
+- - - 6 6 - - -
+ - 0 4 4 4 0 -
+- - - 6 6 - - -
+ - - 2 7 2 - -
+- - - 6 6 - - -
+ - 0 5 5 5 0 -
+- - - 3 3 - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - 4 1 3 - - -
+ - 1 - - 1 - -
+- - 4 1 3 4 1 -
+ - 1 3 4 - - 4
+- 3 - - 3 4 1 -
+ - 1 3 4 1 3 -
+- - 4 1 - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 6 4 - 3 2 5 -
+ 0 - - - - - 1
+- 2 3 5 - 4 6 -
+ 0 - - - - - 1
+- 4 6 - 2 5 3 -
+ 0 - - - - - 1
+- 5 2 3 - 4 6 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 6 6 - - -
+ - - 7 6 4 - -
+- 2 1 7 4 1 3 -
+ 2 1 1 1 1 1 3
+- 2 2 2 3 3 3 -
+ - - - 5 - - -
+- - - 2 3 - - -
+ - - - 5 - - -
+- - 2 2 3 3 - -
+ - - - - - - -
+
+4 - 5 - - 3 - 6
+ 2 - 3 - 2 - 4
+4 - - 1 0 - - 6
+ 6 - 2 3 5 - 4
+4 - - 0 1 - - 6
+ 2 - 5 - 3 - 4
+4 - 3 - - 2 - 6
+ 6 - - - - - 4
+- - - - - - - -
+ - - - - - - -
+
+2 6 0 5 5 1 3 4
+ 1 - - 2 - - 0
+4 - - 3 6 - - 2
+ - - - 0 - - -
+- - - 1 4 - - -
+ - - - 2 - - -
+- - - 6 3 - - -
+ - - - 5 - - -
+- - - 4 1 - - -
+ - - - - - - -
+
+- - - - 5 1 1 3
+ 0 5 1 0 5 3 3
+5 1 0 5 1 0 5 1
+ 0 5 1 0 5 1 6
+- - - - 1 6 5 1
+ - - - - 5 1 6
+- - - - 1 0 5 1
+ - - - - 5 1 0
+- - - - - - - -
+ - - - - - - -
+
+- 0 7 3 - - 2 2
+ - 0 7 3 - - 2
+- 0 7 3 - - 2 2
+ - 0 7 3 - 3 1
+- 0 7 3 - 6 4 5
+ - 0 7 3 - 7 0
+- 0 7 3 - 2 3 4
+ - 0 7 3 - 5 6
+- - - - - 7 0 1
+ - - - - - - -
+
+- - - 7 7 7 7 -
+ 3 4 5 - - - 7
+2 - - - - - - 3
+ 7 - - - - - 4
+7 - - - 3 4 5 6
+ 7 - - 2 0 1 2
+6 - - - 3 4 5 6
+ 0 1 - - - - -
+2 3 4 - - - - -
+ 5 6 0 - - - -
+
+- 7 - - - - 2 -
+ 1 1 - - - 3 3
+- 2 - - - - 4 -
+ 3 3 - - - 5 5
+- 4 - - - - 6 -
+ 5 5 - - - 1 1
+- 6 - - - - 7 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 4 - - - - 4 -
+ 2 - - 1 - - 2
+5 - - 0 0 - - 5
+ 5 - - 1 - - 6
+- 4 2 7 7 5 4 -
+ - - - 6 - - -
+- - - 3 3 - - -
+ - - - 7 - - -
+- - - - - - - -
+ - - - - - - -
+
+- 1 - - 2 3 4 -
+ 2 - - 3 0 4 -
+4 - - 2 3 1 - -
+ 3 - 4 3 0 - -
+4 - - 2 5 1 - -
+ 3 - 4 5 0 4 -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+2 - - 1 1 - - 2
+ 2 - 3 3 3 - 2
+- 2 - 4 4 - 2 -
+ - 7 7 0 7 7 -
+- - - 4 4 - - -
+ - - 5 7 5 - -
+6 3 2 6 4 2 3 6
+ 5 - - - - - 1
+- - - - - - - -
+ - - - - - - -
+
+4 2 3 5 7 1 3 6
+ 1 - - 1 - - 1
+3 0 1 3 2 4 3 5
+ 4 - - 4 - - 4
+- 5 - - 5 - - 5
+ 0 3 2 0 4 5 0
+- 6 - - 6 - - 6
+ 7 - - 7 - - 7
+- - - - - - - -
+ - - - - - - -
+
+- 5 4 - 1 1 - -
+ 5 - 4 1 - 1 -
+0 - - - - - 0 -
+ 0 6 4 - - 4 2
+- 4 3 5 2 6 3 6
+ - 2 6 - - 5 4
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 6 6 - - -
+ - - 5 5 4 - -
+- - 1 6 6 4 - -
+ - 1 7 2 5 3 -
+- 2 7 2 1 5 3 -
+ 2 1 3 1 4 2 7
+- 3 1 3 4 2 7 -
+ - 3 5 5 6 6 -
+- - - - - - - -
+ - - - - - - -
+
+- - 7 3 - - - -
+ - 1 7 6 - - -
+- 3 7 5 1 5 - -
+ 7 7 0 2 4 0 4
+7 1 4 6 5 6 5 7
+ 1 7 7 1 7 7 1
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - 1 - - 1 - -
+ - 5 6 1 5 6 -
+- 1 1 2 2 1 1 -
+ 4 7 1 0 1 7 4
+- 3 7 5 7 5 3 -
+ - 1 1 1 1 1 -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+4 - - - 5 - - 4
+ 6 6 7 6 - 4 5
+4 2 7 5 2 2 6 4
+ - - 4 1 - 5 2
+- 5 2 7 7 - 7 4
+ 4 6 5 4 - 4 2
+- - - 4 - 4 1 -
+ 0 0 0 5 - - -
+- - - - 0 0 0 0
+ - - - - - - -
+
+1 - - - 0 0 - -
+ 2 - - 0 1 0 -
+3 - - 0 2 2 0 -
+ 4 - 0 1 1 1 0
+5 - - 0 4 4 0 -
+ 6 - - 4 4 4 -
+7 - - - 4 4 - -
+ - - - 0 1 0 -
+- - - 0 1 1 0 -
+ - - - - - - -
+
+- - 3 - - 1 7 -
+ - 7 4 - - 4 3
+1 - - 0 2 0 - -
+ 5 4 - 3 - - -
+4 - 3 6 1 1 6 -
+ - 1 - - 4 - 1
+- 7 5 - - - 3 -
+ - - 3 - - - -
+- - - - - - - -
+ - - - - - - -
+
+1 - - - 1 - - -
+ 2 - - - 2 - -
+- 3 - - 3 3 - -
+ - 4 - 4 - 4 -
+- 5 - - 5 5 - -
+ 6 - - 7 1 7 -
+7 - - - 6 6 - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+2 - - 6 - 2 5 1
+ 5 - 4 - 4 - 4
+6 - - 3 - - - 3
+ 4 2 0 - - - 5
+- - - 6 - 3 6 -
+ - - 5 - 5 - -
+- - - 3 - 4 2 5
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+6 - - - 4 - - 3
+ 0 3 - - 6 - 0
+- - 7 - 1 - 3 -
+ 7 - 4 7 - 2 -
+5 2 3 2 1 6 - 3
+ - - 0 4 3 5 4
+- 7 6 - - 0 - -
+ 4 3 - - - 4 2
+0 - - - - - 6 -
+ - - - - - - -
+
+6 1 2 5 1 6 3 0
+ - - - - - - 4
+0 5 2 7 1 6 2 -
+ 3 - - - - - -
+6 7 6 4 0 5 2 6
+ - - - - - - 1
+6 1 4 0 6 2 3 -
+ 0 - - - - - -
+- 0 4 5 3 7 6 0
+ - - - - - - -
+
+- - - 0 1 - - -
+ - - 0 7 0 - -
+- - 1 2 2 0 - -
+ - 0 7 0 7 0 -
+- 6 - 7 7 - 6 -
+ 4 1 6 6 6 4 1
+- 5 - 7 7 - 5 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 5 6 - - -
+ - - 3 3 3 - -
+- - 7 5 3 7 - -
+ - 3 - 6 - 3 -
+2 - - 3 7 - - 1
+ 2 2 - 3 - 1 1
+- 0 2 5 6 1 0 -
+ - - - 3 - - -
+- - - 3 7 - - -
+ - - - - - - -
+
+- 6 - - - - 2 -
+ - 2 6 0 6 0 -
+- 0 - - - - - -
+ 6 - - - - - -
+- 3 3 2 0 6 0 0
+ - 6 - - - - 0
+- - - 6 0 2 6 -
+ - 2 0 - - - -
+- - - - - - - -
+ - - - - - - -
+
+0 7 - - - - - -
+ 1 5 - - - - -
+7 2 5 - - - - -
+ 6 3 4 - - - -
+5 5 4 4 - - - -
+ 3 3 5 3 - - -
+1 2 2 5 3 - - -
+ 1 0 0 7 6 - -
+3 3 5 5 7 6 - -
+ - - - - - - -
+
+- - 2 6 6 2 - -
+ - 2 1 1 0 2 -
+- 2 3 2 2 0 2 -
+ 2 3 2 5 2 7 2
+2 4 2 5 2 7 2 0
+ 2 4 2 6 6 2 0
+- 2 5 2 2 2 7 2
+ - 2 5 6 6 7 2
+- - 2 2 2 2 2 -
+ - - - - - - -
+
+- - 0 - - 0 - -
+ 1 0 0 1 0 0 1
+1 7 7 5 5 7 7 1
+ 3 2 - 2 - 2 3
+3 7 - 6 6 - 7 3
+ 7 - - 6 - - 7
+4 4 5 - - 5 4 4
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 6 3 - - 3 6 -
+ 6 - 2 - 2 - 6
+2 - 0 1 1 0 - 2
+ 5 0 - 7 - 0 5
+- 5 - 6 6 - 5 -
+ 7 1 4 - 4 1 7
+7 - 4 - - 4 - 7
+ 2 0 - - - 0 2
+- 2 - - - - 2 -
+ - - - - - - -
+
+6 1 - - - - 4 0
+ 2 7 5 5 5 7 3
+6 1 - - - - 4 0
+ 2 5 7 7 7 5 3
+6 1 - - - - 4 0
+ 2 0 6 6 6 0 3
+6 1 - - - - 4 0
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+5 - - 1 1 - - 5
+ 5 - 4 - 4 - 5
+- 2 4 - - 4 2 -
+ 7 2 - - - 2 7
+0 - 0 4 4 0 - 0
+ 7 2 - - - 2 7
+- 2 3 - - 3 2 -
+ 5 - 3 - 3 - 5
+5 - - 6 6 - - 5
+ - - - - - - -
+
+2 2 - - - - 5 5
+ 5 - - - - - 2
+5 - - - - - - 2
+ 1 - 1 5 1 - 3
+5 2 5 3 1 2 5 2
+ 2 0 5 - 2 0 5
+- 3 7 - - 3 7 -
+ - - 2 0 5 - -
+- - - - - - - -
+ - - - - - - -
+
+0 6 5 2 3 4 1 7
+ - - - - 1 - -
+- - - 1 1 - - -
+ - - 1 - - - -
+7 1 4 3 2 5 6 0
+ - - - - 1 - -
+- - - 1 1 - - -
+ - - 1 - - - -
+0 6 5 2 3 4 1 7
+ - - - - - - -
+
+- - 1 - - 1 - -
+ - 2 4 - 2 4 -
+- 2 3 6 5 3 2 -
+ - 6 5 - 6 5 -
+- - - 7 7 - - -
+ - - - 7 - - -
+1 - - 7 7 - - 3
+ 2 - - 7 - - 2
+- 3 4 5 6 4 1 -
+ - - - - - - -
+
+1 - - 2 2 - - 2
+ 1 3 7 3 7 4 2
+- 1 6 - - 6 2 -
+ 6 - 7 3 7 - 6
+- 4 2 - - 1 3 -
+ - - 2 6 1 - -
+- 4 3 3 4 4 3 -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- - - 5 6 - - -
+ - - - 3 - - -
+- - - 1 2 - - -
+ - - - 4 - - -
+- - - 5 7 - - -
+ - - - 2 - - -
+6 5 4 3 2 1 7 5
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+- 0 - 1 - 2 - -
+ - 4 - 5 - 6 -
+- 7 - 0 - 2 - -
+ - 6 - 3 - 6 -
+- 1 - 1 - 2 - -
+ - 3 - 5 - 0 -
+- 2 - 4 - 6 - -
+ - 3 - 6 - 7 -
+- - - - - - - -
+ - - - - - - -
+
+1 1 2 2 3 3 4 4
+ 5 5 6 7 6 5 5
+6 4 3 3 2 2 1 6
+ 4 6 5 7 6 3 1
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+7 4 - 1 2 - 4 7
+ 5 5 - 2 - 4 4
+- 5 - 7 7 - 4 -
+ 1 0 6 7 6 0 2
+- 2 - 5 3 - 1 -
+ 1 1 - - - 2 2
+6 1 4 - - 4 2 6
+ 5 3 - - - 3 5
+- - - - - - - -
+ - - - - - - -
+
+1 5 1 0 0 1 5 1
+ 1 2 5 - 5 2 1
+3 6 1 2 2 1 6 3
+ 4 3 4 - 4 3 4
+3 4 6 5 5 6 4 3
+ 0 2 3 - 3 2 0
+2 3 1 5 5 1 3 2
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
+
+3 0 2 7 5 7 6 5
+ 6 - 1 - 2 - 1
+- 6 4 0 3 4 5 -
+ - 5 - 1 - 4 -
+- 7 3 5 6 5 3 -
+ 1 - 2 - 4 - 2
+6 4 4 6 6 5 5 1
+ - - - - - - -
+- - - - - - - -
+ - - - - - - -
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..05dd141
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Creating output directories if needed...
+
+
+
+
+
+
+ Generating R.java / Manifest.java from the resources...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compiling aidl files into Java classes...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Converting compiled files and external libraries into ${outdir}/${dex-file}...
+
+
+
+
+
+
+
+
+
+
+ Packaging resources and assets...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging resources...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging ${out-debug-package}, and signing it with a debug key...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging ${out-unsigned-package} for release...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ It will need to be signed with jarsigner before being published.
+
+
+
+
+ Installing ${out-debug-package} onto default emulator...
+
+
+
+
+
+
+
+ Installing ${out-debug-package} onto default emulator...
+
+
+
+
+
+
+
+
+
+ Uninstalling ${application-package} from the default emulator...
+
+
+
+
+
+
+
diff --git a/default.properties b/default.properties
new file mode 100644
index 0000000..e3b90ac
--- /dev/null
+++ b/default.properties
@@ -0,0 +1,5 @@
+# This file is automatically generated by activitycreator.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# Instead customize values in a "build.properties" file.
+
+sdk-folder=/home/pfedor/android/android-sdk-linux_x86-1.1_r1
diff --git a/res/drawable/background.jpg b/res/drawable/background.jpg
new file mode 100644
index 0000000..ae18a7d
Binary files /dev/null and b/res/drawable/background.jpg differ
diff --git a/res/drawable/bubble_1.gif b/res/drawable/bubble_1.gif
new file mode 100644
index 0000000..d258264
Binary files /dev/null and b/res/drawable/bubble_1.gif differ
diff --git a/res/drawable/bubble_2.gif b/res/drawable/bubble_2.gif
new file mode 100644
index 0000000..ccd2bd8
Binary files /dev/null and b/res/drawable/bubble_2.gif differ
diff --git a/res/drawable/bubble_3.gif b/res/drawable/bubble_3.gif
new file mode 100644
index 0000000..36913d2
Binary files /dev/null and b/res/drawable/bubble_3.gif differ
diff --git a/res/drawable/bubble_4.gif b/res/drawable/bubble_4.gif
new file mode 100644
index 0000000..c1c98fd
Binary files /dev/null and b/res/drawable/bubble_4.gif differ
diff --git a/res/drawable/bubble_5.gif b/res/drawable/bubble_5.gif
new file mode 100644
index 0000000..4ff0cae
Binary files /dev/null and b/res/drawable/bubble_5.gif differ
diff --git a/res/drawable/bubble_6.gif b/res/drawable/bubble_6.gif
new file mode 100644
index 0000000..5430781
Binary files /dev/null and b/res/drawable/bubble_6.gif differ
diff --git a/res/drawable/bubble_7.gif b/res/drawable/bubble_7.gif
new file mode 100644
index 0000000..3887368
Binary files /dev/null and b/res/drawable/bubble_7.gif differ
diff --git a/res/drawable/bubble_8.gif b/res/drawable/bubble_8.gif
new file mode 100644
index 0000000..cb71b26
Binary files /dev/null and b/res/drawable/bubble_8.gif differ
diff --git a/res/drawable/bubble_blink.gif b/res/drawable/bubble_blink.gif
new file mode 100644
index 0000000..5789eba
Binary files /dev/null and b/res/drawable/bubble_blink.gif differ
diff --git a/res/drawable/bubble_colourblind_1.gif b/res/drawable/bubble_colourblind_1.gif
new file mode 100644
index 0000000..0f393b7
Binary files /dev/null and b/res/drawable/bubble_colourblind_1.gif differ
diff --git a/res/drawable/bubble_colourblind_2.gif b/res/drawable/bubble_colourblind_2.gif
new file mode 100644
index 0000000..4c6a536
Binary files /dev/null and b/res/drawable/bubble_colourblind_2.gif differ
diff --git a/res/drawable/bubble_colourblind_3.gif b/res/drawable/bubble_colourblind_3.gif
new file mode 100644
index 0000000..cfd4750
Binary files /dev/null and b/res/drawable/bubble_colourblind_3.gif differ
diff --git a/res/drawable/bubble_colourblind_4.gif b/res/drawable/bubble_colourblind_4.gif
new file mode 100644
index 0000000..18d9347
Binary files /dev/null and b/res/drawable/bubble_colourblind_4.gif differ
diff --git a/res/drawable/bubble_colourblind_5.gif b/res/drawable/bubble_colourblind_5.gif
new file mode 100644
index 0000000..2944c45
Binary files /dev/null and b/res/drawable/bubble_colourblind_5.gif differ
diff --git a/res/drawable/bubble_colourblind_6.gif b/res/drawable/bubble_colourblind_6.gif
new file mode 100644
index 0000000..1ab1a04
Binary files /dev/null and b/res/drawable/bubble_colourblind_6.gif differ
diff --git a/res/drawable/bubble_colourblind_7.gif b/res/drawable/bubble_colourblind_7.gif
new file mode 100644
index 0000000..d7fa59b
Binary files /dev/null and b/res/drawable/bubble_colourblind_7.gif differ
diff --git a/res/drawable/bubble_colourblind_8.gif b/res/drawable/bubble_colourblind_8.gif
new file mode 100644
index 0000000..3c07d1f
Binary files /dev/null and b/res/drawable/bubble_colourblind_8.gif differ
diff --git a/res/drawable/bubble_font.gif b/res/drawable/bubble_font.gif
new file mode 100644
index 0000000..219447a
Binary files /dev/null and b/res/drawable/bubble_font.gif differ
diff --git a/res/drawable/close_eyes.gif b/res/drawable/close_eyes.gif
new file mode 100644
index 0000000..731fbf1
Binary files /dev/null and b/res/drawable/close_eyes.gif differ
diff --git a/res/drawable/compressor.gif b/res/drawable/compressor.gif
new file mode 100644
index 0000000..0439126
Binary files /dev/null and b/res/drawable/compressor.gif differ
diff --git a/res/drawable/compressor_body.png b/res/drawable/compressor_body.png
new file mode 100644
index 0000000..7435095
Binary files /dev/null and b/res/drawable/compressor_body.png differ
diff --git a/res/drawable/fixed_1.gif b/res/drawable/fixed_1.gif
new file mode 100644
index 0000000..59b0bf1
Binary files /dev/null and b/res/drawable/fixed_1.gif differ
diff --git a/res/drawable/fixed_2.gif b/res/drawable/fixed_2.gif
new file mode 100644
index 0000000..85ede39
Binary files /dev/null and b/res/drawable/fixed_2.gif differ
diff --git a/res/drawable/fixed_3.gif b/res/drawable/fixed_3.gif
new file mode 100644
index 0000000..8bdb605
Binary files /dev/null and b/res/drawable/fixed_3.gif differ
diff --git a/res/drawable/fixed_4.gif b/res/drawable/fixed_4.gif
new file mode 100644
index 0000000..caa4135
Binary files /dev/null and b/res/drawable/fixed_4.gif differ
diff --git a/res/drawable/fixed_5.gif b/res/drawable/fixed_5.gif
new file mode 100644
index 0000000..0a3e735
Binary files /dev/null and b/res/drawable/fixed_5.gif differ
diff --git a/res/drawable/fixed_6.gif b/res/drawable/fixed_6.gif
new file mode 100644
index 0000000..c9d8e3b
Binary files /dev/null and b/res/drawable/fixed_6.gif differ
diff --git a/res/drawable/frozen_1.gif b/res/drawable/frozen_1.gif
new file mode 100644
index 0000000..db9004c
Binary files /dev/null and b/res/drawable/frozen_1.gif differ
diff --git a/res/drawable/frozen_2.gif b/res/drawable/frozen_2.gif
new file mode 100644
index 0000000..48e6d31
Binary files /dev/null and b/res/drawable/frozen_2.gif differ
diff --git a/res/drawable/frozen_3.gif b/res/drawable/frozen_3.gif
new file mode 100644
index 0000000..9008c93
Binary files /dev/null and b/res/drawable/frozen_3.gif differ
diff --git a/res/drawable/frozen_4.gif b/res/drawable/frozen_4.gif
new file mode 100644
index 0000000..a265c41
Binary files /dev/null and b/res/drawable/frozen_4.gif differ
diff --git a/res/drawable/frozen_5.gif b/res/drawable/frozen_5.gif
new file mode 100644
index 0000000..3c2d770
Binary files /dev/null and b/res/drawable/frozen_5.gif differ
diff --git a/res/drawable/frozen_6.gif b/res/drawable/frozen_6.gif
new file mode 100644
index 0000000..464b1f2
Binary files /dev/null and b/res/drawable/frozen_6.gif differ
diff --git a/res/drawable/frozen_7.gif b/res/drawable/frozen_7.gif
new file mode 100644
index 0000000..1887dd0
Binary files /dev/null and b/res/drawable/frozen_7.gif differ
diff --git a/res/drawable/frozen_8.gif b/res/drawable/frozen_8.gif
new file mode 100644
index 0000000..c945977
Binary files /dev/null and b/res/drawable/frozen_8.gif differ
diff --git a/res/drawable/hurry.gif b/res/drawable/hurry.gif
new file mode 100644
index 0000000..93fa1b5
Binary files /dev/null and b/res/drawable/hurry.gif differ
diff --git a/res/drawable/launcher.png b/res/drawable/launcher.png
new file mode 100644
index 0000000..6bb009f
Binary files /dev/null and b/res/drawable/launcher.png differ
diff --git a/res/drawable/life.gif b/res/drawable/life.gif
new file mode 100644
index 0000000..488cb2f
Binary files /dev/null and b/res/drawable/life.gif differ
diff --git a/res/drawable/lose_panel.jpg b/res/drawable/lose_panel.jpg
new file mode 100644
index 0000000..9f242f5
Binary files /dev/null and b/res/drawable/lose_panel.jpg differ
diff --git a/res/drawable/penguins.jpg b/res/drawable/penguins.jpg
new file mode 100644
index 0000000..4ac14f7
Binary files /dev/null and b/res/drawable/penguins.jpg differ
diff --git a/res/drawable/splash.jpg b/res/drawable/splash.jpg
new file mode 100644
index 0000000..d56c7bf
Binary files /dev/null and b/res/drawable/splash.jpg differ
diff --git a/res/drawable/void_panel.jpg b/res/drawable/void_panel.jpg
new file mode 100644
index 0000000..243a2de
Binary files /dev/null and b/res/drawable/void_panel.jpg differ
diff --git a/res/drawable/win_panel.jpg b/res/drawable/win_panel.jpg
new file mode 100644
index 0000000..c282460
Binary files /dev/null and b/res/drawable/win_panel.jpg differ
diff --git a/res/layout/main.xml b/res/layout/main.xml
new file mode 100644
index 0000000..d1cfbde
--- /dev/null
+++ b/res/layout/main.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/res/raw/applause.ogg b/res/raw/applause.ogg
new file mode 100644
index 0000000..7924944
Binary files /dev/null and b/res/raw/applause.ogg differ
diff --git a/res/raw/destroy_group.ogg b/res/raw/destroy_group.ogg
new file mode 100644
index 0000000..2c102d7
Binary files /dev/null and b/res/raw/destroy_group.ogg differ
diff --git a/res/raw/hurry.ogg b/res/raw/hurry.ogg
new file mode 100644
index 0000000..b30926f
Binary files /dev/null and b/res/raw/hurry.ogg differ
diff --git a/res/raw/launch.ogg b/res/raw/launch.ogg
new file mode 100644
index 0000000..179067f
Binary files /dev/null and b/res/raw/launch.ogg differ
diff --git a/res/raw/lose.ogg b/res/raw/lose.ogg
new file mode 100644
index 0000000..75fb078
Binary files /dev/null and b/res/raw/lose.ogg differ
diff --git a/res/raw/newroot_solo.ogg b/res/raw/newroot_solo.ogg
new file mode 100644
index 0000000..1cc35c8
Binary files /dev/null and b/res/raw/newroot_solo.ogg differ
diff --git a/res/raw/noh.ogg b/res/raw/noh.ogg
new file mode 100644
index 0000000..ad16948
Binary files /dev/null and b/res/raw/noh.ogg differ
diff --git a/res/raw/rebound.ogg b/res/raw/rebound.ogg
new file mode 100644
index 0000000..8789420
Binary files /dev/null and b/res/raw/rebound.ogg differ
diff --git a/res/raw/stick.ogg b/res/raw/stick.ogg
new file mode 100644
index 0000000..237dfef
Binary files /dev/null and b/res/raw/stick.ogg differ
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..eedbfb3
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,14 @@
+
+
+ FrozenBubble
+ New Game
+ Colorblind Mode On
+ Colorblind Mode Off
+ Fullscreen On
+ Fullscreen Off
+ Sound On
+ Sound Off
+ About Frozen Bubble
+ Don't Rush Me
+ Rush Me
+
diff --git a/src/org/jfedor/frozenbubble/BmpWrap.java b/src/org/jfedor/frozenbubble/BmpWrap.java
new file mode 100644
index 0000000..53751ff
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/BmpWrap.java
@@ -0,0 +1,68 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Bitmap;
+
+// Various classes take arguments of this type during construction. We need
+// one level of indirection in case we want to swap the images from under them
+// (e.g., to resize them when the surface resolution changes.) We couldn't
+// do it if references to Bitmap were kept directly everywhere since you can't
+// overwrite an Android Bitmap in place (or at least I haven't found how to
+// do it.)
+class BmpWrap {
+ BmpWrap(int id)
+ {
+ this.id = id;
+ }
+
+ public Bitmap bmp;
+ // Image id used for saving and restoring the image sprites.
+ public int id;
+}
diff --git a/src/org/jfedor/frozenbubble/BubbleFont.java b/src/org/jfedor/frozenbubble/BubbleFont.java
new file mode 100644
index 0000000..9406bba
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/BubbleFont.java
@@ -0,0 +1,126 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+public class BubbleFont {
+ private char[] characters = {
+ '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*',
+ '+', ',', '-', '.', '/', '0', '1', '2', '3', '4',
+ '5', '6', '7', '8', '9', ':', ';', '<', '=', '>',
+ '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '{',
+ '}', '[', ']', ' ', '\\', ' ', ' '};
+
+ private int[] position = {
+ 0, 9, 16, 31, 39, 54, 69, 73, 80, 88, 96, 116, 121, 131,
+ 137, 154, 165, 175, 187, 198, 210, 223, 234, 246, 259,
+ 271, 276, 282, 293, 313, 324, 336, 351, 360, 370, 381,
+ 390, 402, 411, 421, 435, 446, 459, 472, 483, 495, 508,
+ 517, 527, 538, 552, 565, 578, 589, 602, 616, 631, 645,
+ 663, 684, 700, 716, 732, 748, 764, 780, 796, 812 };
+
+ public int SEPARATOR_WIDTH = 1;
+ public int SPACE_CHAR_WIDTH = 6;
+
+ private BmpWrap fontMap;
+ private Rect clipRect;
+
+ public BubbleFont(BmpWrap fontMap)
+ {
+ this.fontMap = fontMap;
+ clipRect = new Rect();
+ }
+
+ public final void print(String s, int x, int y, Canvas canvas,
+ double scale, int dx, int dy)
+ {
+ int len = s.length();
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ x += paintChar(c, x, y, canvas, scale, dx, dy);
+ }
+ }
+
+ public final int paintChar(char c, int x, int y, Canvas canvas,
+ double scale, int dx, int dy)
+ {
+ if (c == ' ') {
+ return SPACE_CHAR_WIDTH + SEPARATOR_WIDTH;
+ }
+ int index = getCharIndex(c);
+ if (index == -1) {
+ return 0;
+ }
+ int imageWidth = position[index+1]-position[index];
+
+ clipRect.left = x;
+ clipRect.right = x + imageWidth;
+ clipRect.top = y;
+ clipRect.bottom = y + 22;
+ Sprite.drawImageClipped(fontMap, x - position[index], y, clipRect,
+ canvas, scale, dx, dy);
+
+ return imageWidth + SEPARATOR_WIDTH;
+ }
+
+ private final int getCharIndex(char c)
+ {
+ for (int i=0 ; i
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import java.util.Random;
+import android.os.Bundle;
+
+public class BubbleManager
+{
+ int bubblesLeft;
+ BmpWrap[] bubbles;
+ int[] countBubbles;
+
+ public BubbleManager(BmpWrap[] bubbles)
+ {
+ this.bubbles = bubbles;
+ this.countBubbles = new int[bubbles.length];
+ this.bubblesLeft = 0;
+ }
+
+ public void saveState(Bundle map)
+ {
+ map.putInt("BubbleManager-bubblesLeft", bubblesLeft);
+ map.putIntArray("BubbleManager-countBubbles", countBubbles);
+ }
+
+ public void restoreState(Bundle map)
+ {
+ bubblesLeft = map.getInt("BubbleManager-bubblesLeft");
+ countBubbles = map.getIntArray("BubbleManager-countBubbles");
+ }
+
+ public void addBubble(BmpWrap bubble)
+ {
+ countBubbles[findBubble(bubble)]++;
+ bubblesLeft++;
+ }
+
+ public void removeBubble(BmpWrap bubble)
+ {
+ countBubbles[findBubble(bubble)]--;
+ bubblesLeft--;
+ }
+
+ public int countBubbles()
+ {
+ return bubblesLeft;
+ }
+
+ public int nextBubbleIndex(Random rand)
+ {
+ int select = rand.nextInt() % bubbles.length;
+
+ if (select < 0)
+ {
+ select = -select;
+ }
+
+ int count = -1;
+ int position = -1;
+
+ while (count != select)
+ {
+ position++;
+
+ if (position == bubbles.length)
+ {
+ position = 0;
+ }
+
+ if (countBubbles[position] != 0)
+ {
+ count++;
+ }
+ }
+
+ return position;
+ }
+
+ public BmpWrap nextBubble(Random rand)
+ {
+ return bubbles[nextBubbleIndex(rand)];
+ }
+
+ private int findBubble(BmpWrap bubble)
+ {
+ for (int i=0 ; i
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import java.util.Vector;
+import java.util.Random;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+
+public class BubbleSprite extends Sprite
+{
+ private static double FALL_SPEED = 1.;
+ private static double MAX_BUBBLE_SPEED = 8.;
+ private static double MINIMUM_DISTANCE = 841.;
+
+ private int color;
+ private BmpWrap bubbleFace;
+ private BmpWrap bubbleBlindFace;
+ private BmpWrap frozenFace;
+ private BmpWrap bubbleBlink;
+ private BmpWrap[] bubbleFixed;
+ private FrozenGame frozen;
+ private BubbleManager bubbleManager;
+ private double moveX, moveY;
+ private double realX, realY;
+
+ private boolean fixed;
+ private boolean blink;
+ private boolean released;
+
+ private boolean checkJump;
+ private boolean checkFall;
+
+ private int fixedAnim;
+
+ private SoundManager soundManager;
+
+ public void saveState(Bundle map, Vector savedSprites) {
+ if (getSavedId() != -1) {
+ return;
+ }
+ super.saveState(map, savedSprites);
+ map.putInt(String.format("%d-color", getSavedId()), color);
+ map.putDouble(String.format("%d-moveX", getSavedId()), moveX);
+ map.putDouble(String.format("%d-moveY", getSavedId()), moveY);
+ map.putDouble(String.format("%d-realX", getSavedId()), realX);
+ map.putDouble(String.format("%d-realY", getSavedId()), realY);
+ map.putBoolean(String.format("%d-fixed", getSavedId()), fixed);
+ map.putBoolean(String.format("%d-blink", getSavedId()), blink);
+ map.putBoolean(String.format("%d-released", getSavedId()), released);
+ map.putBoolean(String.format("%d-checkJump", getSavedId()), checkJump);
+ map.putBoolean(String.format("%d-checkFall", getSavedId()), checkFall);
+ map.putInt(String.format("%d-fixedAnim", getSavedId()), fixedAnim);
+ map.putBoolean(String.format("%d-frozen", getSavedId()),
+ bubbleFace == frozenFace ? true : false);
+ }
+
+ public int getTypeId()
+ {
+ return Sprite.TYPE_BUBBLE;
+ }
+
+ public BubbleSprite(Rect area, int color, double moveX, double moveY,
+ double realX, double realY, boolean fixed, boolean blink,
+ boolean released, boolean checkJump, boolean checkFall,
+ int fixedAnim, BmpWrap bubbleFace,
+ BmpWrap bubbleBlindFace, BmpWrap frozenFace,
+ BmpWrap[] bubbleFixed, BmpWrap bubbleBlink,
+ BubbleManager bubbleManager, SoundManager soundManager,
+ FrozenGame frozen)
+ {
+ super(area);
+ this.color = color;
+ this.moveX = moveX;
+ this.moveY = moveY;
+ this.realX = realX;
+ this.realY = realY;
+ this.fixed = fixed;
+ this.blink = blink;
+ this.released = released;
+ this.checkJump = checkJump;
+ this.checkFall = checkFall;
+ this.fixedAnim = fixedAnim;
+ this.bubbleFace = bubbleFace;
+ this.bubbleBlindFace = bubbleBlindFace;
+ this.frozenFace = frozenFace;
+ this.bubbleFixed = bubbleFixed;
+ this.bubbleBlink = bubbleBlink;
+ this.bubbleManager = bubbleManager;
+ this.soundManager = soundManager;
+ this.frozen = frozen;
+ }
+
+ public BubbleSprite(Rect area, int direction, int color, BmpWrap bubbleFace,
+ BmpWrap bubbleBlindFace, BmpWrap frozenFace,
+ BmpWrap[] bubbleFixed, BmpWrap bubbleBlink,
+ BubbleManager bubbleManager, SoundManager soundManager,
+ FrozenGame frozen)
+ {
+ super(area);
+
+ this.color = color;
+ this.bubbleFace = bubbleFace;
+ this.bubbleBlindFace = bubbleBlindFace;
+ this.frozenFace = frozenFace;
+ this.bubbleFixed = bubbleFixed;
+ this.bubbleBlink = bubbleBlink;
+ this.bubbleManager = bubbleManager;
+ this.soundManager = soundManager;
+ this.frozen = frozen;
+
+ this.moveX = MAX_BUBBLE_SPEED * -Math.cos(direction * Math.PI / 40.);
+ this.moveY = MAX_BUBBLE_SPEED * -Math.sin(direction * Math.PI / 40.);
+ this.realX = area.left;
+ this.realY = area.top;
+
+ fixed = false;
+ fixedAnim = -1;
+ }
+
+ public BubbleSprite(Rect area, int color, BmpWrap bubbleFace,
+ BmpWrap bubbleBlindFace, BmpWrap frozenFace,
+ BmpWrap bubbleBlink, BubbleManager bubbleManager,
+ SoundManager soundManager, FrozenGame frozen)
+ {
+ super(area);
+
+ this.color = color;
+ this.bubbleFace = bubbleFace;
+ this.bubbleBlindFace = bubbleBlindFace;
+ this.frozenFace = frozenFace;
+ this.bubbleBlink = bubbleBlink;
+ this.bubbleManager = bubbleManager;
+ this.soundManager = soundManager;
+ this.frozen = frozen;
+
+ this.realX = area.left;
+ this.realY = area.top;
+
+ fixed = true;
+ fixedAnim = -1;
+ bubbleManager.addBubble(bubbleFace);
+ }
+
+ Point currentPosition()
+ {
+ int posY = (int)Math.floor((realY-28.-frozen.getMoveDown())/28.);
+ int posX = (int)Math.floor((realX-174.)/32. + 0.5*(posY%2));
+
+ if (posX>7) {
+ posX = 7;
+ }
+
+ if (posX<0) {
+ posX = 0;
+ }
+
+ if (posY<0) {
+ posY = 0;
+ }
+
+ return new Point(posX, posY);
+ }
+
+ public void removeFromManager()
+ {
+ bubbleManager.removeBubble(bubbleFace);
+ }
+
+ public boolean fixed()
+ {
+ return fixed;
+ }
+
+ public boolean checked()
+ {
+ return checkFall;
+ }
+
+ public boolean released()
+ {
+ return released;
+ }
+
+ public void moveDown()
+ {
+ if (fixed) {
+ realY += 28.;
+ }
+
+ super.absoluteMove(new Point((int)realX, (int)realY));
+ }
+
+ public void move()
+ {
+ realX += moveX;
+
+ if (realX>=414.) {
+ moveX = -moveX;
+ realX += (414. - realX);
+ soundManager.playSound(FrozenBubble.SOUND_REBOUND);
+ } else if (realX<=190.) {
+ moveX = -moveX;
+ realX += (190. - realX);
+ soundManager.playSound(FrozenBubble.SOUND_REBOUND);
+ }
+
+ realY += moveY;
+
+ Point currentPosition = currentPosition();
+ Vector neighbors = getNeighbors(currentPosition);
+
+ if (checkCollision(neighbors) || realY < 44.+frozen.getMoveDown()) {
+ realX = 190.+currentPosition.x*32-(currentPosition.y%2)*16;
+ realY = 44.+currentPosition.y*28+frozen.getMoveDown();
+
+ fixed = true;
+
+ Vector checkJump = new Vector();
+ this.checkJump(checkJump, neighbors);
+
+ BubbleSprite[][] grid = frozen.getGrid();
+
+ if (checkJump.size() >= 3) {
+ released = true;
+
+ for (int i=0 ; i0) {
+ current.removeFromManager();
+ }
+ grid[currentPoint.x][currentPoint.y] = null;
+ }
+
+ for (int i=0 ; i<8 ; i++) {
+ if (grid[i][0] != null) {
+ grid[i][0].checkFall();
+ }
+ }
+
+ for (int i=0 ; i<8 ; i++) {
+ for (int j=0 ; j<12 ; j++) {
+ if (grid[i][j] != null) {
+ if (!grid[i][j].checked()) {
+ frozen.addFallingBubble(grid[i][j]);
+ grid[i][j].removeFromManager();
+ grid[i][j] = null;
+ }
+ }
+ }
+ }
+
+ soundManager.playSound(FrozenBubble.SOUND_DESTROY);
+ } else {
+ bubbleManager.addBubble(bubbleFace);
+ grid[currentPosition.x][currentPosition.y] = this;
+ moveX = 0.;
+ moveY = 0.;
+ fixedAnim = 0;
+ soundManager.playSound(FrozenBubble.SOUND_STICK);
+ }
+ }
+
+ super.absoluteMove(new Point((int)realX, (int)realY));
+ }
+
+ Vector getNeighbors(Point p)
+ {
+ BubbleSprite[][] grid = frozen.getGrid();
+
+ Vector list = new Vector();
+
+ if ((p.y % 2) == 0) {
+ if (p.x > 0) {
+ list.addElement(grid[p.x-1][p.y]);
+ }
+
+ if (p.x < 7) {
+ list.addElement(grid[p.x+1][p.y]);
+
+ if (p.y > 0) {
+ list.addElement(grid[p.x][p.y-1]);
+ list.addElement(grid[p.x+1][p.y-1]);
+ }
+
+ if (p.y < 12) {
+ list.addElement(grid[p.x][p.y+1]);
+ list.addElement(grid[p.x+1][p.y+1]);
+ }
+ } else {
+ if (p.y > 0) {
+ list.addElement(grid[p.x][p.y-1]);
+ }
+
+ if (p.y < 12) {
+ list.addElement(grid[p.x][p.y+1]);
+ }
+ }
+ } else {
+ if (p.x < 7) {
+ list.addElement(grid[p.x+1][p.y]);
+ }
+
+ if (p.x > 0) {
+ list.addElement(grid[p.x-1][p.y]);
+
+ if (p.y > 0) {
+ list.addElement(grid[p.x][p.y-1]);
+ list.addElement(grid[p.x-1][p.y-1]);
+ }
+
+ if (p.y < 12) {
+ list.addElement(grid[p.x][p.y+1]);
+ list.addElement(grid[p.x-1][p.y+1]);
+ }
+ } else {
+ if (p.y > 0) {
+ list.addElement(grid[p.x][p.y-1]);
+ }
+
+ if (p.y < 12) {
+ list.addElement(grid[p.x][p.y+1]);
+ }
+ }
+ }
+
+ return list;
+ }
+
+ void checkJump(Vector jump, BmpWrap compare)
+ {
+ if (checkJump) {
+ return;
+ }
+ checkJump = true;
+
+ if (this.bubbleFace == compare) {
+ checkJump(jump, this.getNeighbors(this.currentPosition()));
+ }
+ }
+
+ void checkJump(Vector jump, Vector neighbors)
+ {
+ jump.addElement(this);
+
+ for (int i=0 ; i= 680.) {
+ frozen.deleteJumpingBubble(this);
+ }
+ }
+
+ public void fall()
+ {
+ if (fixed) {
+ moveY = frozen.getRandom().nextDouble()* 5.;
+ }
+
+ fixed = false;
+
+ moveY += FALL_SPEED;
+ realY += moveY;
+
+ super.absoluteMove(new Point((int)realX, (int)realY));
+
+ if (realY >= 680.) {
+ frozen.deleteFallingBubble(this);
+ }
+ }
+
+ public void blink()
+ {
+ blink = true;
+ }
+
+ public void frozenify()
+ {
+ changeSpriteArea(new Rect(getSpritePosition().x-1, getSpritePosition().y-1,
+ 34, 42));
+ bubbleFace = frozenFace;
+ }
+
+ public final void paint(Canvas c, double scale, int dx, int dy)
+ {
+ checkJump = false;
+ checkFall = false;
+
+ Point p = getSpritePosition();
+
+ if (blink && bubbleFace != frozenFace) {
+ blink = false;
+ drawImage(bubbleBlink, p.x, p.y, c, scale, dx, dy);
+ } else {
+ if (FrozenBubble.getMode() == FrozenBubble.GAME_NORMAL ||
+ bubbleFace == frozenFace) {
+ drawImage(bubbleFace, p.x, p.y, c, scale, dx, dy);
+ } else {
+ drawImage(bubbleBlindFace, p.x, p.y, c, scale, dx, dy);
+ }
+ }
+
+ if (fixedAnim != -1) {
+ drawImage(bubbleFixed[fixedAnim], p.x, p.y, c, scale, dx, dy);
+ fixedAnim++;
+ if (fixedAnim == 6) {
+ fixedAnim = -1;
+ }
+ }
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/Compressor.java b/src/org/jfedor/frozenbubble/Compressor.java
new file mode 100644
index 0000000..8110dad
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/Compressor.java
@@ -0,0 +1,98 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.util.Log;
+
+public class Compressor {
+ private BmpWrap compressorHead;
+ private BmpWrap compressor;
+ int steps;
+
+ public Compressor(BmpWrap compressorHead, BmpWrap compressor)
+ {
+ this.compressorHead = compressorHead;
+ this.compressor = compressor;
+ this.steps = 0;
+ }
+
+ public void saveState(Bundle map)
+ {
+ map.putInt("compressor-steps", steps);
+ }
+
+ public void restoreState(Bundle map)
+ {
+ steps = map.getInt("compressor-steps");
+ }
+
+ public void moveDown() {
+ steps++;
+ }
+
+ public void paint(Canvas c, double scale, int dx, int dy)
+ {
+ for (int i = 0; i < steps; i++) {
+ c.drawBitmap(compressor.bmp,
+ (float)(235 * scale + dx),
+ (float)((28 * i - 4) * scale + dy),
+ null);
+ c.drawBitmap(compressor.bmp,
+ (float)(391 * scale + dx),
+ (float)((28 * i - 4) * scale + dy),
+ null);
+ }
+ c.drawBitmap(compressorHead.bmp,
+ (float)(160 * scale + dx),
+ (float)((-7 + 28 * steps) * scale + dy),
+ null);
+ }
+};
diff --git a/src/org/jfedor/frozenbubble/FrozenBubble.java b/src/org/jfedor/frozenbubble/FrozenBubble.java
new file mode 100644
index 0000000..5f0cc62
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/FrozenBubble.java
@@ -0,0 +1,299 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+// This file is derived from the LunarLander.java file which is part of
+// the Lunar Lander game included with Android documentation. The copyright
+// notice for the Lunar Lander is reproduced below.
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.Window;
+import android.view.WindowManager;
+
+import android.util.Log;
+
+import org.jfedor.frozenbubble.GameView;
+import org.jfedor.frozenbubble.GameView.GameThread;
+
+public class FrozenBubble extends Activity
+{
+ public final static int SOUND_WON = 0;
+ public final static int SOUND_LOST = 1;
+ public final static int SOUND_LAUNCH = 2;
+ public final static int SOUND_DESTROY = 3;
+ public final static int SOUND_REBOUND = 4;
+ public final static int SOUND_STICK = 5;
+ public final static int SOUND_HURRY = 6;
+ public final static int SOUND_NEWROOT = 7;
+ public final static int SOUND_NOH = 8;
+ public final static int NUM_SOUNDS = 9;
+
+ public final static int GAME_NORMAL = 0;
+ public final static int GAME_COLORBLIND = 1;
+
+ public final static int MENU_NEW_GAME = 1;
+ public final static int MENU_COLORBLIND_MODE_ON = 2;
+ public final static int MENU_COLORBLIND_MODE_OFF = 3;
+ public final static int MENU_FULLSCREEN_ON = 4;
+ public final static int MENU_FULLSCREEN_OFF = 5;
+ public final static int MENU_SOUND_ON = 6;
+ public final static int MENU_SOUND_OFF = 7;
+ public final static int MENU_DONT_RUSH_ME = 8;
+ public final static int MENU_RUSH_ME = 9;
+ public final static int MENU_ABOUT = 10;
+
+ private static int gameMode = GAME_NORMAL;
+ private static boolean soundOn = true;
+ private static boolean dontRushMe = false;
+
+ private boolean fullscreen = true;
+
+ private GameThread mGameThread;
+ private GameView mGameView;
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ super.onCreateOptionsMenu(menu);
+ menu.add(0, MENU_NEW_GAME, 0, R.string.menu_new_game);
+ menu.add(0, MENU_COLORBLIND_MODE_ON, 0,
+ R.string.menu_colorblind_mode_on);
+ menu.add(0, MENU_COLORBLIND_MODE_OFF, 0,
+ R.string.menu_colorblind_mode_off);
+ menu.add(0, MENU_FULLSCREEN_ON, 0, R.string.menu_fullscreen_on);
+ menu.add(0, MENU_FULLSCREEN_OFF, 0, R.string.menu_fullscreen_off);
+ menu.add(0, MENU_SOUND_ON, 0, R.string.menu_sound_on);
+ menu.add(0, MENU_SOUND_OFF, 0, R.string.menu_sound_off);
+ menu.add(0, MENU_DONT_RUSH_ME, 0, R.string.menu_dont_rush_me);
+ menu.add(0, MENU_RUSH_ME, 0, R.string.menu_rush_me);
+ menu.add(0, MENU_ABOUT, 0, R.string.menu_about);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu)
+ {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(MENU_SOUND_ON).setVisible(!getSoundOn());
+ menu.findItem(MENU_SOUND_OFF).setVisible(getSoundOn());
+ menu.findItem(MENU_COLORBLIND_MODE_ON).setVisible(
+ getMode() == GAME_NORMAL);
+ menu.findItem(MENU_COLORBLIND_MODE_OFF).setVisible(
+ getMode() != GAME_NORMAL);
+ menu.findItem(MENU_FULLSCREEN_ON).setVisible(!fullscreen);
+ menu.findItem(MENU_FULLSCREEN_OFF).setVisible(fullscreen);
+ menu.findItem(MENU_DONT_RUSH_ME).setVisible(!getDontRushMe());
+ menu.findItem(MENU_RUSH_ME).setVisible(getDontRushMe());
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ switch (item.getItemId()) {
+ case MENU_NEW_GAME:
+ mGameThread.newGame();
+ return true;
+ case MENU_COLORBLIND_MODE_ON:
+ setMode(GAME_COLORBLIND);
+ return true;
+ case MENU_COLORBLIND_MODE_OFF:
+ setMode(GAME_NORMAL);
+ return true;
+ case MENU_FULLSCREEN_ON:
+ fullscreen = true;
+ setFullscreen();
+ return true;
+ case MENU_FULLSCREEN_OFF:
+ fullscreen = false;
+ setFullscreen();
+ return true;
+ case MENU_SOUND_ON:
+ setSoundOn(true);
+ return true;
+ case MENU_SOUND_OFF:
+ setSoundOn(false);
+ return true;
+ case MENU_ABOUT:
+ mGameView.getThread().setState(GameView.GameThread.STATE_ABOUT);
+ return true;
+ case MENU_DONT_RUSH_ME:
+ setDontRushMe(true);
+ return true;
+ case MENU_RUSH_ME:
+ setDontRushMe(false);
+ return true;
+ }
+ return false;
+ }
+
+ private void setFullscreen()
+ {
+ if (fullscreen) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ getWindow().clearFlags(
+ WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ } else {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ getWindow().addFlags(
+ WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ }
+ mGameView.requestLayout();
+ }
+
+ public synchronized static void setMode(int newMode)
+ {
+ gameMode = newMode;
+ }
+
+ public synchronized static int getMode()
+ {
+ return gameMode;
+ }
+
+ public synchronized static boolean getSoundOn()
+ {
+ return soundOn;
+ }
+
+ public synchronized static void setSoundOn(boolean so)
+ {
+ soundOn = so;
+ }
+
+ public synchronized static boolean getDontRushMe()
+ {
+ return dontRushMe;
+ }
+
+ public synchronized static void setDontRushMe(boolean dont)
+ {
+ dontRushMe = dont;
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ if (savedInstanceState != null) {
+ Log.i("frozen-bubble", "FrozenBubble.onCreate(...)");
+ } else {
+ Log.i("frozen-bubble", "FrozenBubble.onCreate(null)");
+ }
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.main);
+ mGameView = (GameView)findViewById(R.id.game);
+ mGameThread = mGameView.getThread();
+
+ if (savedInstanceState != null) {
+ mGameThread.restoreState(savedInstanceState);
+ }
+ mGameView.requestFocus();
+ setFullscreen();
+ }
+
+ /**
+ * Invoked when the Activity loses user focus.
+ */
+ @Override
+ protected void onPause() {
+ Log.i("frozen-bubble", "FrozenBubble.onPause()");
+ super.onPause();
+ mGameView.getThread().pause();
+ }
+
+ @Override
+ protected void onStop() {
+ Log.i("frozen-bubble", "FrozenBubble.onStop()");
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.i("frozen-bubble", "FrozenBubble.onDestroy()");
+ super.onDestroy();
+ if (mGameView != null) {
+ mGameView.cleanUp();
+ }
+ mGameView = null;
+ mGameThread = null;
+ }
+
+ /**
+ * Notification that something is about to happen, to give the Activity a
+ * chance to save state.
+ *
+ * @param outState a Bundle into which this Activity should save its state
+ */
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ Log.i("frozen-bubble", "FrozenBubble.onSaveInstanceState()");
+ // Just have the View's thread save its state into our Bundle.
+ super.onSaveInstanceState(outState);
+ mGameThread.saveState(outState);
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/FrozenGame.java b/src/org/jfedor/frozenbubble/FrozenGame.java
new file mode 100644
index 0000000..8f10b78
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/FrozenGame.java
@@ -0,0 +1,758 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.Log;
+import java.util.Vector;
+import java.util.Random;
+
+public class FrozenGame extends GameScreen {
+ public final static int HORIZONTAL_MOVE = 0;
+ public final static int FIRE = 1;
+
+ public final static int KEY_UP = 38;
+ public final static int KEY_LEFT = 37;
+ public final static int KEY_RIGHT = 39;
+ public final static int KEY_SHIFT = 16;
+
+ public static String PARAMETER_PLAYER = "player";
+ public static String PARAMETER_OFFLINE = "offline";
+
+ // Change mode (normal/colorblind)
+ public final static int KEY_M = 77;
+ // Toggle sound on/off
+ public final static int KEY_S = 83;
+
+ boolean modeKeyPressed, soundKeyPressed;
+
+ boolean levelCompleted = false;
+
+ BmpWrap background;
+ BmpWrap[] bubbles;
+ BmpWrap[] bubblesBlind;
+ BmpWrap[] frozenBubbles;
+ BmpWrap[] targetedBubbles;
+ Random random;
+
+ LaunchBubbleSprite launchBubble;
+ double launchBubblePosition;
+
+ PenguinSprite penguin;
+ Compressor compressor;
+
+ ImageSprite nextBubble;
+ int currentColor, nextColor;
+
+ BubbleSprite movingBubble;
+ BubbleManager bubbleManager;
+ LevelManager levelManager;
+ // TODO
+ //HighscoreManager highscoreManager;
+
+ Vector jumping;
+ Vector falling;
+
+ BubbleSprite[][] bubblePlay;
+
+ int fixedBubbles;
+ double moveDown;
+
+ BmpWrap gameWon, gameLost;
+
+ int nbBubbles;
+
+ BmpWrap bubbleBlink;
+ int blinkDelay;
+
+ ImageSprite hurrySprite;
+ int hurryTime;
+
+ SoundManager soundManager;
+
+ boolean readyToFire;
+ boolean endOfGame;
+ boolean frozenify;
+ int frozenifyX, frozenifyY;
+
+ Drawable launcher;
+ BmpWrap penguins;
+
+ public FrozenGame(BmpWrap background_arg,
+ BmpWrap[] bubbles_arg,
+ BmpWrap[] bubblesBlind_arg,
+ BmpWrap[] frozenBubbles_arg,
+ BmpWrap[] targetedBubbles_arg,
+ BmpWrap bubbleBlink_arg,
+ BmpWrap gameWon_arg,
+ BmpWrap gameLost_arg,
+ BmpWrap hurry_arg,
+ BmpWrap penguins_arg,
+ BmpWrap compressorHead_arg,
+ BmpWrap compressor_arg,
+ Drawable launcher_arg,
+ SoundManager soundManager_arg,
+ LevelManager levelManager_arg)
+ {
+ random = new Random(System.currentTimeMillis());
+ launcher = launcher_arg;
+ penguins = penguins_arg;
+ background = background_arg;
+ bubbles = bubbles_arg;
+ bubblesBlind = bubblesBlind_arg;
+ frozenBubbles = frozenBubbles_arg;
+ targetedBubbles = targetedBubbles_arg;
+ bubbleBlink = bubbleBlink_arg;
+ gameWon = gameWon_arg;
+ gameLost = gameLost_arg;
+ soundManager = soundManager_arg;
+ levelManager = levelManager_arg;
+
+ launchBubblePosition = 20;
+
+ penguin = new PenguinSprite(penguins_arg, random);
+ this.addSprite(penguin);
+ compressor = new Compressor(compressorHead_arg, compressor_arg);
+
+ hurrySprite = new ImageSprite(new Rect(203, 265, 203 + 240, 265 + 90),
+ hurry_arg);
+
+ jumping = new Vector();
+ falling = new Vector();
+
+ bubblePlay = new BubbleSprite[8][13];
+
+ bubbleManager = new BubbleManager(bubbles);
+ byte[][] currentLevel = levelManager.getCurrentLevel();
+
+ if (currentLevel == null) {
+ Log.i("frozen-bubble", "Level not available.");
+ return;
+ }
+
+ for (int j=0 ; j<12 ; j++) {
+ for (int i=j%2 ; i<8 ; i++) {
+ if (currentLevel[i][j] != -1) {
+ BubbleSprite newOne = new BubbleSprite(
+ new Rect(190+i*32-(j%2)*16, 44+j*28, 32, 32),
+ currentLevel[i][j],
+ bubbles[currentLevel[i][j]], bubblesBlind[currentLevel[i][j]],
+ frozenBubbles[currentLevel[i][j]], bubbleBlink, bubbleManager,
+ soundManager, this);
+ bubblePlay[i][j] = newOne;
+ this.addSprite(newOne);
+ }
+ }
+ }
+
+ currentColor = bubbleManager.nextBubbleIndex(random);
+ nextColor = bubbleManager.nextBubbleIndex(random);
+
+ if (FrozenBubble.getMode() == FrozenBubble.GAME_NORMAL) {
+ nextBubble = new ImageSprite(new Rect(302, 440, 302 + 32, 440 + 32),
+ bubbles[nextColor]);
+ } else {
+ nextBubble = new ImageSprite(new Rect(302, 440, 302 + 32, 440 + 32),
+ bubblesBlind[nextColor]);
+ }
+ this.addSprite(nextBubble);
+
+ launchBubble = new LaunchBubbleSprite(currentColor,
+ (int)launchBubblePosition,
+ launcher, bubbles, bubblesBlind);
+
+ this.spriteToBack(launchBubble);
+
+ nbBubbles = 0;
+ }
+
+ public void saveState(Bundle map) {
+ Vector savedSprites = new Vector();
+ saveSprites(map, savedSprites);
+ for (int i = 0; i < jumping.size(); i++) {
+ ((Sprite)jumping.elementAt(i)).saveState(map, savedSprites);
+ map.putInt(String.format("jumping-%d", i),
+ ((Sprite)jumping.elementAt(i)).getSavedId());
+ }
+ map.putInt("numJumpingSprites", jumping.size());
+ for (int i = 0; i < falling.size(); i++) {
+ ((Sprite)falling.elementAt(i)).saveState(map, savedSprites);
+ map.putInt(String.format("falling-%d", i),
+ ((Sprite)falling.elementAt(i)).getSavedId());
+ }
+ map.putInt("numFallingSprites", falling.size());
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 13; j++) {
+ if (bubblePlay[i][j] != null) {
+ bubblePlay[i][j].saveState(map, savedSprites);
+ map.putInt(String.format("play-%d-%d", i, j),
+ bubblePlay[i][j].getSavedId());
+ } else {
+ map.putInt(String.format("play-%d-%d", i, j), -1);
+ }
+ }
+ }
+ launchBubble.saveState(map, savedSprites);
+ map.putInt("launchBubbleId", launchBubble.getSavedId());
+ map.putDouble("launchBubblePosition", launchBubblePosition);
+ penguin.saveState(map, savedSprites);
+ compressor.saveState(map);
+ map.putInt("penguinId", penguin.getSavedId());
+ nextBubble.saveState(map, savedSprites);
+ map.putInt("nextBubbleId", nextBubble.getSavedId());
+ map.putInt("currentColor", currentColor);
+ map.putInt("nextColor", nextColor);
+ if (movingBubble != null) {
+ movingBubble.saveState(map, savedSprites);
+ map.putInt("movingBubbleId", movingBubble.getSavedId());
+ } else {
+ map.putInt("movingBubbleId", -1);
+ }
+ bubbleManager.saveState(map);
+ map.putInt("fixedBubbles", fixedBubbles);
+ map.putDouble("moveDown", moveDown);
+ map.putInt("nbBubbles", nbBubbles);
+ map.putInt("blinkDelay", blinkDelay);
+ hurrySprite.saveState(map, savedSprites);
+ map.putInt("hurryId", hurrySprite.getSavedId());
+ map.putInt("hurryTime", hurryTime);
+ map.putBoolean("readyToFire", readyToFire);
+ map.putBoolean("endOfGame", endOfGame);
+ map.putBoolean("frozenify", frozenify);
+ map.putInt("frozenifyX", frozenifyX);
+ map.putInt("frozenifyY", frozenifyY);
+
+ map.putInt("numSavedSprites", savedSprites.size());
+
+ for (int i = 0; i < savedSprites.size(); i++) {
+ ((Sprite)savedSprites.elementAt(i)).clearSavedId();
+ }
+ }
+
+ private Sprite restoreSprite(Bundle map, Vector imageList, int i)
+ {
+ int left = map.getInt(String.format("%d-left", i));
+ int right = map.getInt(String.format("%d-right", i));
+ int top = map.getInt(String.format("%d-top", i));
+ int bottom = map.getInt(String.format("%d-bottom", i));
+ int type = map.getInt(String.format("%d-type", i));
+ if (type == Sprite.TYPE_BUBBLE) {
+ int color = map.getInt(String.format("%d-color", i));
+ double moveX = map.getDouble(String.format("%d-moveX", i));
+ double moveY = map.getDouble(String.format("%d-moveY", i));
+ double realX = map.getDouble(String.format("%d-realX", i));
+ double realY = map.getDouble(String.format("%d-realY", i));
+ boolean fixed = map.getBoolean(String.format("%d-fixed", i));
+ boolean blink = map.getBoolean(String.format("%d-blink", i));
+ boolean released = map.getBoolean(String.format("%d-released", i));
+ boolean checkJump = map.getBoolean(String.format("%d-checkJump", i));
+ boolean checkFall = map.getBoolean(String.format("%d-checkFall", i));
+ int fixedAnim = map.getInt(String.format("%d-fixedAnim", i));
+ boolean frozen = map.getBoolean(String.format("%d-frozen", i));
+ return new BubbleSprite(new Rect(left, top, right, bottom),
+ color, moveX, moveY, realX, realY,
+ fixed, blink, released, checkJump, checkFall,
+ fixedAnim,
+ (frozen ? frozenBubbles[color] : bubbles[color]),
+ bubblesBlind[color],
+ frozenBubbles[color],
+ targetedBubbles, bubbleBlink,
+ bubbleManager, soundManager, this);
+ } else if (type == Sprite.TYPE_IMAGE) {
+ int imageId = map.getInt(String.format("%d-imageId", i));
+ return new ImageSprite(new Rect(left, top, right, bottom),
+ (BmpWrap)imageList.elementAt(imageId));
+ } else if (type == Sprite.TYPE_LAUNCH_BUBBLE) {
+ int currentColor = map.getInt(String.format("%d-currentColor", i));
+ int currentDirection = map.getInt(String.format("%d-currentDirection",
+ i));
+ return new LaunchBubbleSprite(currentColor, currentDirection,
+ launcher, bubbles, bubblesBlind);
+ } else if (type == Sprite.TYPE_PENGUIN) {
+ int currentPenguin = map.getInt(String.format("%d-currentPenguin", i));
+ int count = map.getInt(String.format("%d-count", i));
+ int finalState = map.getInt(String.format("%d-finalState", i));
+ int nextPosition = map.getInt(String.format("%d-nextPosition", i));
+ return new PenguinSprite(penguins, random, currentPenguin, count,
+ finalState, nextPosition);
+ } else {
+ Log.e("frozen-bubble", "Unrecognized sprite type: " + type);
+ return null;
+ }
+ }
+
+ public void restoreState(Bundle map, Vector imageList)
+ {
+ Vector savedSprites = new Vector();
+ int numSavedSprites = map.getInt("numSavedSprites");
+ for (int i = 0; i < numSavedSprites; i++) {
+ savedSprites.addElement(restoreSprite(map, imageList, i));
+ }
+
+ restoreSprites(map, savedSprites);
+ jumping = new Vector();
+ int numJumpingSprites = map.getInt("numJumpingSprites");
+ for (int i = 0; i < numJumpingSprites; i++) {
+ int spriteIdx = map.getInt(String.format("jumping-%d", i));
+ jumping.addElement(savedSprites.elementAt(spriteIdx));
+ }
+ falling = new Vector();
+ int numFallingSprites = map.getInt("numFallingSprites");
+ for (int i = 0; i < numFallingSprites; i++) {
+ int spriteIdx = map.getInt(String.format("falling-%d", i));
+ falling.addElement(savedSprites.elementAt(spriteIdx));
+ }
+ bubblePlay = new BubbleSprite[8][13];
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 13; j++) {
+ int spriteIdx = map.getInt(String.format("play-%d-%d", i, j));
+ if (spriteIdx != -1) {
+ bubblePlay[i][j] = (BubbleSprite)savedSprites.elementAt(spriteIdx);
+ } else {
+ bubblePlay[i][j] = null;
+ }
+ }
+ }
+ int launchBubbleId = map.getInt("launchBubbleId");
+ launchBubble = (LaunchBubbleSprite)savedSprites.elementAt(launchBubbleId);
+ launchBubblePosition = map.getDouble("launchBubblePosition");
+ int penguinId = map.getInt("penguinId");
+ penguin = (PenguinSprite)savedSprites.elementAt(penguinId);
+ compressor.restoreState(map);
+ int nextBubbleId = map.getInt("nextBubbleId");
+ nextBubble = (ImageSprite)savedSprites.elementAt(nextBubbleId);
+ currentColor = map.getInt("currentColor");
+ nextColor = map.getInt("nextColor");
+ int movingBubbleId = map.getInt("movingBubbleId");
+ if (movingBubbleId == -1) {
+ movingBubble = null;
+ } else {
+ movingBubble = (BubbleSprite)savedSprites.elementAt(movingBubbleId);
+ }
+ bubbleManager.restoreState(map);
+ fixedBubbles = map.getInt("fixedBubbles");
+ moveDown = map.getDouble("moveDown");
+ nbBubbles = map.getInt("nbBubbles");
+ blinkDelay = map.getInt("blinkDelay");
+ int hurryId = map.getInt("hurryId");
+ hurrySprite = (ImageSprite)savedSprites.elementAt(hurryId);
+ hurryTime = map.getInt("hurryTime");
+ readyToFire = map.getBoolean("readyToFire");
+ endOfGame = map.getBoolean("endOfGame");
+ frozenify = map.getBoolean("frozenify");
+ frozenifyX = map.getInt("frozenifyX");
+ frozenifyY = map.getInt("frozenifyY");
+ }
+
+ private void initFrozenify()
+ {
+ ImageSprite freezeLaunchBubble =
+ new ImageSprite(new Rect(301, 389, 34, 42),
+ frozenBubbles[currentColor]);
+ ImageSprite freezeNextBubble =
+ new ImageSprite(new Rect(301, 439, 34, 42), frozenBubbles[nextColor]);
+
+ this.addSprite(freezeLaunchBubble);
+ this.addSprite(freezeNextBubble);
+
+ frozenifyX = 7;
+ frozenifyY = 12;
+
+ frozenify = true;
+ }
+
+ private void frozenify()
+ {
+ frozenifyX--;
+ if (frozenifyX < 0) {
+ frozenifyX = 7;
+ frozenifyY--;
+
+ if (frozenifyY<0) {
+ frozenify = false;
+ this.addSprite(new ImageSprite(new Rect(152, 190, 337, 116), gameLost));
+ soundManager.playSound(FrozenBubble.SOUND_NOH);
+
+ return;
+ }
+ }
+
+ while (bubblePlay[frozenifyX][frozenifyY] == null && frozenifyY >=0) {
+ frozenifyX--;
+ if (frozenifyX < 0) {
+ frozenifyX = 7;
+ frozenifyY--;
+
+ if (frozenifyY<0) {
+ frozenify = false;
+ this.addSprite(new ImageSprite(new Rect(152, 190, 337, 116),
+ gameLost));
+ soundManager.playSound(FrozenBubble.SOUND_NOH);
+
+ return;
+ }
+ }
+ }
+
+ this.spriteToBack(bubblePlay[frozenifyX][frozenifyY]);
+ bubblePlay[frozenifyX][frozenifyY].frozenify();
+
+ this.spriteToBack(launchBubble);
+ }
+
+ public BubbleSprite[][] getGrid()
+ {
+ return bubblePlay;
+ }
+
+ public void addFallingBubble(BubbleSprite sprite)
+ {
+ spriteToFront(sprite);
+ falling.addElement(sprite);
+ }
+
+ public void deleteFallingBubble(BubbleSprite sprite)
+ {
+ removeSprite(sprite);
+ falling.removeElement(sprite);
+ }
+
+ public void addJumpingBubble(BubbleSprite sprite)
+ {
+ spriteToFront(sprite);
+ jumping.addElement(sprite);
+ }
+
+ public void deleteJumpingBubble(BubbleSprite sprite)
+ {
+ removeSprite(sprite);
+ jumping.removeElement(sprite);
+ }
+
+ public Random getRandom()
+ {
+ return random;
+ }
+
+ public double getMoveDown()
+ {
+ return moveDown;
+ }
+
+ private int nextColor()
+ {
+ int nextColor = random.nextInt() % 8;
+
+ if (nextColor<0) {
+ return -nextColor;
+ }
+
+ return nextColor;
+ }
+
+ private void sendBubblesDown()
+ {
+ soundManager.playSound(FrozenBubble.SOUND_NEWROOT);
+
+ for (int i=0 ; i<8 ; i++) {
+ for (int j=0 ; j<12 ; j++) {
+ if (bubblePlay[i][j] != null) {
+ bubblePlay[i][j].moveDown();
+
+ if (bubblePlay[i][j].getSpritePosition().y>=380) {
+ penguin.updateState(PenguinSprite.STATE_GAME_LOST);
+ endOfGame = true;
+ initFrozenify();
+
+ soundManager.playSound(FrozenBubble.SOUND_LOST);
+ }
+ }
+ }
+ }
+
+ moveDown += 28.;
+ compressor.moveDown();
+ }
+
+ private void blinkLine(int number)
+ {
+ int move = number % 2;
+ int column = (number+1) >> 1;
+
+ for (int i=move ; i<13 ; i++) {
+ if (bubblePlay[column][i] != null) {
+ bubblePlay[column][i].blink();
+ }
+ }
+ }
+
+ public boolean play(boolean key_left, boolean key_right, boolean key_fire,
+ double trackball_dx, double touch_dx)
+ {
+ int[] move = new int[2];
+
+ if (key_left && !key_right) {
+ move[HORIZONTAL_MOVE] = KEY_LEFT;
+ } else if (key_right && !key_left) {
+ move[HORIZONTAL_MOVE] = KEY_RIGHT;
+ } else {
+ move[HORIZONTAL_MOVE] = 0;
+ }
+ if (key_fire) {
+ move[FIRE] = KEY_UP;
+ } else {
+ move[FIRE] = 0;
+ }
+
+ if (move[FIRE] == 0) {
+ readyToFire = true;
+ }
+
+ if (FrozenBubble.getDontRushMe()) {
+ hurryTime = 1;
+ }
+
+ if (endOfGame) {
+ if (move[FIRE] == KEY_UP && readyToFire) {
+ if (levelCompleted) {
+ levelManager.goToNextLevel();
+ }
+ return true;
+ } else {
+ penguin.updateState(PenguinSprite.STATE_VOID);
+
+ if (frozenify) {
+ frozenify();
+ }
+ }
+ } else {
+ if (move[FIRE] == KEY_UP || hurryTime > 480) {
+ if (movingBubble == null && readyToFire) {
+ nbBubbles++;
+
+ movingBubble = new BubbleSprite(new Rect(302, 390, 32, 32),
+ (int)launchBubblePosition,
+ currentColor,
+ bubbles[currentColor],
+ bubblesBlind[currentColor],
+ frozenBubbles[currentColor],
+ targetedBubbles, bubbleBlink,
+ bubbleManager, soundManager, this);
+ this.addSprite(movingBubble);
+
+ currentColor = nextColor;
+ nextColor = bubbleManager.nextBubbleIndex(random);
+
+ if (FrozenBubble.getMode() == FrozenBubble.GAME_NORMAL) {
+ nextBubble.changeImage(bubbles[nextColor]);
+ } else {
+ nextBubble.changeImage(bubblesBlind[nextColor]);
+ }
+ launchBubble.changeColor(currentColor);
+ penguin.updateState(PenguinSprite.STATE_FIRE);
+
+ soundManager.playSound(FrozenBubble.SOUND_LAUNCH);
+
+ readyToFire = false;
+ hurryTime = 0;
+ removeSprite(hurrySprite);
+ } else {
+ penguin.updateState(PenguinSprite.STATE_VOID);
+ }
+ } else {
+ double dx = 0;
+ if (move[HORIZONTAL_MOVE] == KEY_LEFT) {
+ dx -= 1;
+ }
+ if (move[HORIZONTAL_MOVE] == KEY_RIGHT) {
+ dx += 1;
+ }
+ dx += trackball_dx;
+ dx += touch_dx;
+ launchBubblePosition += dx;
+ if (launchBubblePosition < 1) {
+ launchBubblePosition = 1;
+ }
+ if (launchBubblePosition > 39) {
+ launchBubblePosition = 39;
+ }
+ launchBubble.changeDirection((int)launchBubblePosition);
+ if (dx < 0) {
+ penguin.updateState(PenguinSprite.STATE_TURN_LEFT);
+ } else if (dx > 0) {
+ penguin.updateState(PenguinSprite.STATE_TURN_RIGHT);
+ } else {
+ penguin.updateState(PenguinSprite.STATE_VOID);
+ }
+ }
+ }
+
+ if (movingBubble != null) {
+ movingBubble.move();
+ if (movingBubble.fixed()) {
+ if (movingBubble.getSpritePosition().y>=380 &&
+ !movingBubble.released()) {
+ penguin.updateState(PenguinSprite.STATE_GAME_LOST);
+ endOfGame = true;
+ initFrozenify();
+
+ soundManager.playSound(FrozenBubble.SOUND_LOST);
+ } else if (bubbleManager.countBubbles() == 0) {
+ penguin.updateState(PenguinSprite.STATE_GAME_WON);
+ this.addSprite(new ImageSprite(new Rect(152, 190, 337, 116),
+ gameWon));
+ // TODO
+ //highscoreManager.endLevel(nbBubbles);
+ levelCompleted = true;
+ endOfGame = true;
+
+ soundManager.playSound(FrozenBubble.SOUND_WON);
+ } else {
+ fixedBubbles++;
+ blinkDelay = 0;
+
+ if (fixedBubbles == 8) {
+ fixedBubbles = 0;
+ sendBubblesDown();
+ }
+ }
+ movingBubble = null;
+ }
+
+ if (movingBubble != null) {
+ movingBubble.move();
+ if (movingBubble.fixed()) {
+ if (movingBubble.getSpritePosition().y>=380 &&
+ !movingBubble.released()) {
+ penguin.updateState(PenguinSprite.STATE_GAME_LOST);
+ endOfGame = true;
+ initFrozenify();
+
+ soundManager.playSound(FrozenBubble.SOUND_LOST);
+ } else if (bubbleManager.countBubbles() == 0) {
+ penguin.updateState(PenguinSprite.STATE_GAME_WON);
+ this.addSprite(new ImageSprite(new Rect(152, 190,
+ 152 + 337, 190 + 116),
+ gameWon));
+ // TODO
+ //highscoreManager.endLevel(nbBubbles);
+ endOfGame = true;
+ levelCompleted = true;
+ soundManager.playSound(FrozenBubble.SOUND_WON);
+ } else {
+ fixedBubbles++;
+ blinkDelay = 0;
+
+ if (fixedBubbles == 8) {
+ fixedBubbles = 0;
+ sendBubblesDown();
+ }
+ }
+ movingBubble = null;
+ }
+ }
+ }
+
+ if (movingBubble == null && !endOfGame) {
+ hurryTime++;
+
+ if (hurryTime>=240) {
+ if (hurryTime % 40 == 10) {
+ addSprite(hurrySprite);
+ soundManager.playSound(FrozenBubble.SOUND_HURRY);
+ } else if (hurryTime % 40 == 35) {
+ removeSprite(hurrySprite);
+ }
+ }
+ }
+
+ if (fixedBubbles == 6) {
+ if (blinkDelay < 15) {
+ blinkLine(blinkDelay);
+ }
+
+ blinkDelay++;
+ if (blinkDelay == 40) {
+ blinkDelay = 0;
+ }
+ } else if (fixedBubbles == 7) {
+ if (blinkDelay < 15) {
+ blinkLine(blinkDelay);
+ }
+
+ blinkDelay++;
+ if (blinkDelay == 25) {
+ blinkDelay = 0;
+ }
+ }
+
+ for (int i=0 ; i
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import java.util.Vector;
+import android.graphics.Canvas;
+import android.os.Bundle;
+
+public abstract class GameScreen
+{
+ private Vector sprites;
+
+ public final void saveSprites(Bundle map, Vector savedSprites)
+ {
+ for (int i = 0; i < sprites.size(); i++) {
+ ((Sprite)sprites.elementAt(i)).saveState(map, savedSprites);
+ map.putInt(String.format("game-%d", i),
+ ((Sprite)sprites.elementAt(i)).getSavedId());
+ }
+ map.putInt("numGameSprites", sprites.size());
+ }
+
+ public final void restoreSprites(Bundle map, Vector savedSprites)
+ {
+ sprites = new Vector();
+ int numSprites = map.getInt("numGameSprites");
+ for (int i = 0; i < numSprites; i++) {
+ int spriteIdx = map.getInt(String.format("game-%d", i));
+ sprites.addElement(savedSprites.elementAt(spriteIdx));
+ }
+ }
+
+ public GameScreen()
+ {
+ sprites = new Vector();
+ }
+
+ public final void addSprite(Sprite sprite)
+ {
+ sprites.removeElement(sprite);
+ sprites.addElement(sprite);
+ }
+
+ public final void removeSprite(Sprite sprite)
+ {
+ sprites.removeElement(sprite);
+ }
+
+ public final void spriteToBack(Sprite sprite)
+ {
+ sprites.removeElement(sprite);
+ sprites.insertElementAt(sprite,0);
+ }
+
+ public final void spriteToFront(Sprite sprite)
+ {
+ sprites.removeElement(sprite);
+ sprites.addElement(sprite);
+ }
+
+ public void paint(Canvas c, double scale, int dx, int dy) {
+ for (int i = 0; i < sprites.size(); i++) {
+ ((Sprite)sprites.elementAt(i)).paint(c, scale, dx, dy);
+ }
+ }
+
+ public abstract boolean play(boolean key_left, boolean key_right,
+ boolean key_fire, double trackball_dx,
+ double touch_dx);
+}
diff --git a/src/org/jfedor/frozenbubble/GameView.java b/src/org/jfedor/frozenbubble/GameView.java
new file mode 100644
index 0000000..78f785d
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/GameView.java
@@ -0,0 +1,920 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+// This file is derived from the LunarView.java file which is part of
+// the Lunar Lander game included with Android documentation. The copyright
+// notice for the Lunar Lander is reproduced below.
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.jfedor.frozenbubble;
+
+import java.io.InputStream;
+import java.io.IOException;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.MotionEvent;
+import java.util.Vector;
+
+import android.util.Log;
+
+class GameView extends SurfaceView implements SurfaceHolder.Callback {
+ class GameThread extends Thread {
+ private static final int FRAME_DELAY = 40;
+
+ public static final int STATE_RUNNING = 1;
+ public static final int STATE_PAUSE = 2;
+ public static final int STATE_ABOUT = 4;
+
+ public static final int GAMEFIELD_WIDTH = 320;
+ public static final int GAMEFIELD_HEIGHT = 480;
+ public static final int EXTENDED_GAMEFIELD_WIDTH = 640;
+
+ private static final double TRACKBALL_COEFFICIENT = 5;
+ private static final double TOUCH_COEFFICIENT = 0.2;
+ private static final double TOUCH_FIRE_Y_THRESHOLD = 378;
+
+ private int mCanvasHeight = 1;
+ private int mCanvasWidth = 1;
+ private long mLastTime;
+ private int mMode;
+ private boolean mRun = false;
+
+ private boolean mLeft = false;
+ private boolean mRight = false;
+ private boolean mUp = false;
+ private boolean mFire = false;
+ private boolean mWasLeft = false;
+ private boolean mWasRight = false;
+ private boolean mWasFire = false;
+ private boolean mWasUp = false;
+ private double mTrackballDX = 0;
+ private double mTouchDX = 0;
+ private double mTouchLastX;
+ private boolean mTouchFire = false;
+
+ private SurfaceHolder mSurfaceHolder;
+ private boolean mSurfaceOK = false;
+
+ private double mDisplayScale;
+ private int mDisplayDX;
+ private int mDisplayDY;
+
+ private FrozenGame mFrozenGame;
+
+ private boolean mImagesReady = false;
+
+ private Bitmap mBackgroundOrig;
+ private Bitmap[] mBubblesOrig;
+ private Bitmap[] mBubblesBlindOrig;
+ private Bitmap[] mFrozenBubblesOrig;
+ private Bitmap[] mTargetedBubblesOrig;
+ private Bitmap mBubbleBlinkOrig;
+ private Bitmap mGameWonOrig;
+ private Bitmap mGameLostOrig;
+ private Bitmap mHurryOrig;
+ private Bitmap mPenguinsOrig;
+ private Bitmap mCompressorHeadOrig;
+ private Bitmap mCompressorOrig;
+ private Bitmap mLifeOrig;
+ private Bitmap mFontImageOrig;
+ private BmpWrap mBackground;
+ private BmpWrap[] mBubbles;
+ private BmpWrap[] mBubblesBlind;
+ private BmpWrap[] mFrozenBubbles;
+ private BmpWrap[] mTargetedBubbles;
+ private BmpWrap mBubbleBlink;
+ private BmpWrap mGameWon;
+ private BmpWrap mGameLost;
+ private BmpWrap mHurry;
+ private BmpWrap mPenguins;
+ private BmpWrap mCompressorHead;
+ private BmpWrap mCompressor;
+ private BmpWrap mLife;
+ private BmpWrap mFontImage;
+ // Launcher has to be a drawable, not a bitmap, because we rotate it.
+ private Drawable mLauncher;
+ private SoundManager mSoundManager;
+ private LevelManager mLevelManager;
+ private BubbleFont mFont;
+
+ Vector mImageList;
+
+ private BmpWrap NewBmpWrap()
+ {
+ int new_img_id = mImageList.size();
+ BmpWrap new_img = new BmpWrap(new_img_id);
+ mImageList.addElement(new_img);
+ return new_img;
+ }
+
+ public GameThread(SurfaceHolder surfaceHolder) {
+ Log.i("frozen-bubble", "GameThread()");
+ mSurfaceHolder = surfaceHolder;
+ Resources res = mContext.getResources();
+ setState(STATE_PAUSE);
+
+ mBackgroundOrig =
+ BitmapFactory.decodeResource(res, R.drawable.background);
+ mBubblesOrig = new Bitmap[8];
+ mBubblesOrig[0] = BitmapFactory.decodeResource(res, R.drawable.bubble_1);
+ mBubblesOrig[1] = BitmapFactory.decodeResource(res, R.drawable.bubble_2);
+ mBubblesOrig[2] = BitmapFactory.decodeResource(res, R.drawable.bubble_3);
+ mBubblesOrig[3] = BitmapFactory.decodeResource(res, R.drawable.bubble_4);
+ mBubblesOrig[4] = BitmapFactory.decodeResource(res, R.drawable.bubble_5);
+ mBubblesOrig[5] = BitmapFactory.decodeResource(res, R.drawable.bubble_6);
+ mBubblesOrig[6] = BitmapFactory.decodeResource(res, R.drawable.bubble_7);
+ mBubblesOrig[7] = BitmapFactory.decodeResource(res, R.drawable.bubble_8);
+ mBubblesBlindOrig = new Bitmap[8];
+ mBubblesBlindOrig[0] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_1);
+ mBubblesBlindOrig[1] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_2);
+ mBubblesBlindOrig[2] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_3);
+ mBubblesBlindOrig[3] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_4);
+ mBubblesBlindOrig[4] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_5);
+ mBubblesBlindOrig[5] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_6);
+ mBubblesBlindOrig[6] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_7);
+ mBubblesBlindOrig[7] = BitmapFactory.decodeResource(
+ res, R.drawable.bubble_colourblind_8);
+ mFrozenBubblesOrig = new Bitmap[8];
+ mFrozenBubblesOrig[0] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_1);
+ mFrozenBubblesOrig[1] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_2);
+ mFrozenBubblesOrig[2] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_3);
+ mFrozenBubblesOrig[3] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_4);
+ mFrozenBubblesOrig[4] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_5);
+ mFrozenBubblesOrig[5] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_6);
+ mFrozenBubblesOrig[6] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_7);
+ mFrozenBubblesOrig[7] = BitmapFactory.decodeResource(
+ res, R.drawable.frozen_8);
+ mTargetedBubblesOrig = new Bitmap[6];
+ mTargetedBubblesOrig[0] = BitmapFactory.decodeResource(
+ res, R.drawable.fixed_1);
+ mTargetedBubblesOrig[1] = BitmapFactory.decodeResource(
+ res, R.drawable.fixed_2);
+ mTargetedBubblesOrig[2] = BitmapFactory.decodeResource(
+ res, R.drawable.fixed_3);
+ mTargetedBubblesOrig[3] = BitmapFactory.decodeResource(
+ res, R.drawable.fixed_4);
+ mTargetedBubblesOrig[4] = BitmapFactory.decodeResource(
+ res, R.drawable.fixed_5);
+ mTargetedBubblesOrig[5] = BitmapFactory.decodeResource(
+ res, R.drawable.fixed_6);
+ mBubbleBlinkOrig =
+ BitmapFactory.decodeResource(res, R.drawable.bubble_blink);
+ mGameWonOrig = BitmapFactory.decodeResource(res, R.drawable.win_panel);
+ mGameLostOrig = BitmapFactory.decodeResource(res, R.drawable.lose_panel);
+ mHurryOrig = BitmapFactory.decodeResource(res, R.drawable.hurry);
+ mPenguinsOrig = BitmapFactory.decodeResource(res, R.drawable.penguins);
+ mCompressorHeadOrig =
+ BitmapFactory.decodeResource(res, R.drawable.compressor);
+ mCompressorOrig =
+ BitmapFactory.decodeResource(res, R.drawable.compressor_body);
+ mLifeOrig = BitmapFactory.decodeResource(res, R.drawable.life);
+ mFontImageOrig =
+ BitmapFactory.decodeResource(res, R.drawable.bubble_font);
+
+ mImageList = new Vector();
+
+ mBackground = NewBmpWrap();
+ mBubbles = new BmpWrap[8];
+ for (int i = 0; i < mBubbles.length; i++) {
+ mBubbles[i] = NewBmpWrap();
+ }
+ mBubblesBlind = new BmpWrap[8];
+ for (int i = 0; i < mBubblesBlind.length; i++) {
+ mBubblesBlind[i] = NewBmpWrap();
+ }
+ mFrozenBubbles = new BmpWrap[8];
+ for (int i = 0; i < mFrozenBubbles.length; i++) {
+ mFrozenBubbles[i] = NewBmpWrap();
+ }
+ mTargetedBubbles = new BmpWrap[6];
+ for (int i = 0; i < mTargetedBubbles.length; i++) {
+ mTargetedBubbles[i] = NewBmpWrap();
+ }
+ mBubbleBlink = NewBmpWrap();
+ mGameWon = NewBmpWrap();
+ mGameLost = NewBmpWrap();
+ mHurry = NewBmpWrap();
+ mPenguins = NewBmpWrap();
+ mCompressorHead = NewBmpWrap();
+ mCompressor = NewBmpWrap();
+ mLife = NewBmpWrap();
+ mFontImage = NewBmpWrap();
+
+ mFont = new BubbleFont(mFontImage);
+ mLauncher = res.getDrawable(R.drawable.launcher);
+
+ mSoundManager = new SoundManager(mContext);
+
+ try {
+ InputStream is = mContext.getAssets().open("levels.txt");
+ int size = is.available();
+ byte[] levels = new byte[size];
+ is.read(levels);
+ is.close();
+ mLevelManager = new LevelManager(levels);
+ } catch (IOException e) {
+ // Should never happen.
+ throw new RuntimeException(e);
+ }
+
+ mFrozenGame = new FrozenGame(mBackground, mBubbles, mBubblesBlind,
+ mFrozenBubbles, mTargetedBubbles,
+ mBubbleBlink, mGameWon, mGameLost,
+ mHurry, mPenguins, mCompressorHead,
+ mCompressor, mLauncher,
+ mSoundManager, mLevelManager);
+ }
+
+ private void scaleFrom(BmpWrap image, Bitmap bmp)
+ {
+ if (image.bmp != null && image.bmp != bmp) {
+ image.bmp.recycle();
+ }
+
+ if (mDisplayScale > 0.99999 && mDisplayScale < 1.00001) {
+ image.bmp = bmp;
+ return;
+ }
+ int dstWidth = (int)(bmp.getWidth() * mDisplayScale);
+ int dstHeight = (int)(bmp.getHeight() * mDisplayScale);
+ image.bmp = Bitmap.createScaledBitmap(bmp, dstWidth, dstHeight, true);
+ }
+
+ private void resizeBitmaps()
+ {
+ Log.i("frozen-bubble", "resizeBitmaps()");
+ scaleFrom(mBackground, mBackgroundOrig);
+ for (int i = 0; i < mBubblesOrig.length; i++) {
+ scaleFrom(mBubbles[i], mBubblesOrig[i]);
+ }
+ for (int i = 0; i < mBubblesBlind.length; i++) {
+ scaleFrom(mBubblesBlind[i], mBubblesBlindOrig[i]);
+ }
+ for (int i = 0; i < mFrozenBubbles.length; i++) {
+ scaleFrom(mFrozenBubbles[i], mFrozenBubblesOrig[i]);
+ }
+ for (int i = 0; i < mTargetedBubbles.length; i++) {
+ scaleFrom(mTargetedBubbles[i], mTargetedBubblesOrig[i]);
+ }
+ scaleFrom(mBubbleBlink, mBubbleBlinkOrig);
+ scaleFrom(mGameWon, mGameWonOrig);
+ scaleFrom(mGameLost, mGameLostOrig);
+ scaleFrom(mHurry, mHurryOrig);
+ scaleFrom(mPenguins, mPenguinsOrig);
+ scaleFrom(mCompressorHead, mCompressorHeadOrig);
+ scaleFrom(mCompressor, mCompressorOrig);
+ scaleFrom(mLife, mLifeOrig);
+ scaleFrom(mFontImage, mFontImageOrig);
+ Log.i("frozen-bubble", "resizeBitmaps done.");
+ mImagesReady = true;
+ }
+
+ public void pause()
+ {
+ synchronized (mSurfaceHolder) {
+ if (mMode == STATE_RUNNING) {
+ setState(STATE_PAUSE);
+ }
+ }
+ }
+
+ public void newGame()
+ {
+ synchronized (mSurfaceHolder) {
+ mLevelManager.goToFirstLevel();
+ mFrozenGame = new FrozenGame(mBackground, mBubbles, mBubblesBlind,
+ mFrozenBubbles, mTargetedBubbles,
+ mBubbleBlink, mGameWon, mGameLost,
+ mHurry, mPenguins, mCompressorHead,
+ mCompressor, mLauncher,
+ mSoundManager, mLevelManager);
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ while (mRun) {
+ long now = System.currentTimeMillis();
+ long delay = FRAME_DELAY + mLastTime - now;
+ if (delay > 0) {
+ try{
+ sleep(delay);
+ } catch (InterruptedException e) {}
+ }
+ mLastTime = now;
+ Canvas c = null;
+ try {
+ if (surfaceOK()) {
+ c = mSurfaceHolder.lockCanvas(null);
+ if (c != null) {
+ synchronized (mSurfaceHolder) {
+ if (mRun) {
+ if (mMode == STATE_ABOUT) {
+ drawAboutScreen(c);
+ } else {
+ if (mMode == STATE_RUNNING) {
+ updateGameState();
+ }
+ doDraw(c);
+ }
+ }
+ }
+ }
+ }
+ } finally {
+ // do this in a finally so that if an exception is thrown
+ // during the above, we don't leave the Surface in an
+ // inconsistent state
+ if (c != null) {
+ mSurfaceHolder.unlockCanvasAndPost(c);
+ }
+ }
+ }
+ }
+
+ /**
+ * Dump game state to the provided Bundle. Typically called when the
+ * Activity is being suspended.
+ *
+ * @return Bundle with this view's state
+ */
+ public Bundle saveState(Bundle map) {
+ synchronized (mSurfaceHolder) {
+ if (map != null) {
+ mFrozenGame.saveState(map);
+ mLevelManager.saveState(map);
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Restores game state from the indicated Bundle. Typically called when
+ * the Activity is being restored after having been previously
+ * destroyed.
+ *
+ * @param savedState Bundle containing the game state
+ */
+ public synchronized void restoreState(Bundle map) {
+ synchronized (mSurfaceHolder) {
+ setState(STATE_PAUSE);
+ mFrozenGame.restoreState(map, mImageList);
+ mLevelManager.restoreState(map);
+ }
+ }
+
+ public void setRunning(boolean b) {
+ mRun = b;
+ }
+
+ public void setState(int mode) {
+ synchronized (mSurfaceHolder) {
+ mMode = mode;
+ }
+ }
+
+ public void setSurfaceOK(boolean ok)
+ {
+ synchronized (mSurfaceHolder) {
+ mSurfaceOK = ok;
+ }
+ }
+
+ public boolean surfaceOK()
+ {
+ synchronized (mSurfaceHolder) {
+ return mSurfaceOK;
+ }
+ }
+
+ public void setSurfaceSize(int width, int height)
+ {
+ synchronized (mSurfaceHolder) {
+ mCanvasWidth = width;
+ mCanvasHeight = height;
+ if (width / height >= GAMEFIELD_WIDTH / GAMEFIELD_HEIGHT) {
+ mDisplayScale = 1.0 * height / GAMEFIELD_HEIGHT;
+ mDisplayDX =
+ (int)((width - mDisplayScale * EXTENDED_GAMEFIELD_WIDTH) / 2);
+ mDisplayDY = 0;
+ } else {
+ mDisplayScale = 1.0 * width / GAMEFIELD_WIDTH;
+ mDisplayDX = (int)(-mDisplayScale *
+ (EXTENDED_GAMEFIELD_WIDTH - GAMEFIELD_WIDTH) / 2);
+ mDisplayDY = (int)((height - mDisplayScale * GAMEFIELD_HEIGHT) / 2);
+ }
+ resizeBitmaps();
+ }
+ }
+
+ boolean doKeyDown(int keyCode, KeyEvent msg)
+ {
+ synchronized (mSurfaceHolder) {
+ if (mMode != STATE_RUNNING) {
+ setState(STATE_RUNNING);
+ }
+
+ if (mMode == STATE_RUNNING) {
+ Log.i("frozen-bubble", "STATE RUNNING");
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+ mLeft = true;
+ mWasLeft = true;
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ mRight = true;
+ mWasRight = true;
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ mFire = true;
+ mWasFire = true;
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+ mUp = true;
+ mWasUp = true;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ boolean doKeyUp(int keyCode, KeyEvent msg)
+ {
+ synchronized (mSurfaceHolder) {
+ if (mMode == STATE_RUNNING) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+ mLeft = false;
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ mRight = false;
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ mFire = false;
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+ mUp = false;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ boolean doTrackballEvent(MotionEvent event)
+ {
+ synchronized (mSurfaceHolder) {
+ if (mMode != STATE_RUNNING) {
+ setState(STATE_RUNNING);
+ }
+
+ if (mMode == STATE_RUNNING) {
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ mTrackballDX += event.getX() * TRACKBALL_COEFFICIENT;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private double xFromScr(float x)
+ {
+ return (x - mDisplayDX) / mDisplayScale;
+ }
+
+ private double yFromScr(float y)
+ {
+ return (y - mDisplayDY) / mDisplayScale;
+ }
+
+ boolean doTouchEvent(MotionEvent event)
+ {
+ synchronized (mSurfaceHolder) {
+ if (mMode != STATE_RUNNING) {
+ setState(STATE_RUNNING);
+ }
+
+ double x = xFromScr(event.getX());
+ double y = yFromScr(event.getY());
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (y < TOUCH_FIRE_Y_THRESHOLD) {
+ mTouchFire = true;
+ }
+ mTouchLastX = x;
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (y >= TOUCH_FIRE_Y_THRESHOLD) {
+ mTouchDX = (x - mTouchLastX) * TOUCH_COEFFICIENT;
+ }
+ mTouchLastX = x;
+ }
+ return true;
+ }
+ }
+
+ private void drawBackground(Canvas c)
+ {
+ Sprite.drawImage(mBackground, 0, 0, c, mDisplayScale,
+ mDisplayDX, mDisplayDY);
+ }
+
+ private void drawLevelNumber(Canvas canvas)
+ {
+ int y = 433;
+ int x;
+ int level = mLevelManager.getLevelIndex();
+ if (level < 10) {
+ x = 185;
+ mFont.paintChar(Character.forDigit(level, 10), x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ } else if (level < 100) {
+ x = 178;
+ x += mFont.paintChar(Character.forDigit(level / 10, 10), x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ mFont.paintChar(Character.forDigit(level % 10, 10), x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ } else {
+ x = 173;
+ x += mFont.paintChar(Character.forDigit(level / 100, 10), x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ level -= 100 * (level / 100);
+ x += mFont.paintChar(Character.forDigit(level / 10, 10), x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ mFont.paintChar(Character.forDigit(level % 10, 10), x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ }
+ }
+
+ private void drawAboutScreen(Canvas canvas)
+ {
+ canvas.drawRGB(0, 0, 0);
+ int x = 168;
+ int y = 20;
+ int ysp = 26;
+ int indent = 10;
+ mFont.print("original frozen bubble:", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("guillaume cottenceau", x + indent, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("alexis younes", x + indent, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("amaury amblard-ladurantie", x + indent, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("matthias le bidan", x + indent, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ y += ysp;
+ mFont.print("java version:", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("glenn sanson", x + indent, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ y += ysp;
+ mFont.print("android port:", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("aleksander fedorynski", x + indent, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += 2 * ysp;
+ mFont.print("android port source code", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("is available at:", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("http://code.google.com", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ y += ysp;
+ mFont.print("/p/frozenbubbleandroid", x, y, canvas,
+ mDisplayScale, mDisplayDX, mDisplayDY);
+ }
+
+ private void doDraw(Canvas canvas)
+ {
+ //Log.i("frozen-bubble", "doDraw()");
+ if (!mImagesReady) {
+ Log.i("frozen-bubble", "!mImagesReady, returning");
+ return;
+ }
+ if (mDisplayDX > 0 || mDisplayDY > 0) {
+ Log.i("frozen-bubble", "Drawing black background.");
+ canvas.drawRGB(0, 0, 0);
+ }
+ drawBackground(canvas);
+ drawLevelNumber(canvas);
+ mFrozenGame.paint(canvas, mDisplayScale, mDisplayDX, mDisplayDY);
+ }
+
+ private void updateGameState() {
+ if (mFrozenGame.play(mLeft || mWasLeft, mRight || mWasRight,
+ mFire || mUp || mWasFire || mWasUp || mTouchFire,
+ mTrackballDX, mTouchDX)) {
+ // Lost or won. Need to start over. The level is already
+ // incremented if this was a win.
+ mFrozenGame = new FrozenGame(mBackground, mBubbles, mBubblesBlind,
+ mFrozenBubbles, mTargetedBubbles,
+ mBubbleBlink, mGameWon, mGameLost,
+ mHurry, mPenguins, mCompressorHead,
+ mCompressor, mLauncher, mSoundManager,
+ mLevelManager);
+ }
+ mWasLeft = false;
+ mWasRight = false;
+ mWasFire = false;
+ mWasUp = false;
+ mTrackballDX = 0;
+ mTouchFire = false;
+ mTouchDX = 0;
+ }
+
+ public void cleanUp() {
+ synchronized (mSurfaceHolder) {
+ // I don't really understand why all this is necessary.
+ // I used to get a crash (an out-of-memory error) once every six or
+ // seven times I started the game. I googled the error and someone
+ // said you have to call recycle() on all the bitmaps and set
+ // the pointers to null to facilitate garbage collection. So I did
+ // and the crashes went away.
+ mImagesReady = false;
+ boolean imagesScaled = (mBackgroundOrig == mBackground.bmp);
+ mBackgroundOrig.recycle();
+ mBackgroundOrig = null;
+ for (int i = 0; i < mBubblesOrig.length; i++) {
+ mBubblesOrig[i].recycle();
+ mBubblesOrig[i] = null;
+ }
+ mBubblesOrig = null;
+ for (int i = 0; i < mBubblesBlindOrig.length; i++) {
+ mBubblesBlindOrig[i].recycle();
+ mBubblesBlindOrig[i] = null;
+ }
+ mBubblesBlindOrig = null;
+ for (int i = 0; i < mFrozenBubblesOrig.length; i++) {
+ mFrozenBubblesOrig[i].recycle();
+ mFrozenBubblesOrig[i] = null;
+ }
+ mFrozenBubblesOrig = null;
+ for (int i = 0; i < mTargetedBubblesOrig.length; i++) {
+ mTargetedBubblesOrig[i].recycle();
+ mTargetedBubblesOrig[i] = null;
+ }
+ mTargetedBubblesOrig = null;
+ mBubbleBlinkOrig.recycle();
+ mBubbleBlinkOrig = null;
+ mGameWonOrig.recycle();
+ mGameWonOrig = null;
+ mGameLostOrig.recycle();
+ mGameLostOrig = null;
+ mHurryOrig.recycle();
+ mHurryOrig = null;
+ mPenguinsOrig.recycle();
+ mPenguinsOrig = null;
+ mCompressorHeadOrig.recycle();
+ mCompressorHeadOrig = null;
+ mCompressorOrig.recycle();
+ mCompressorOrig = null;
+ mLifeOrig.recycle();
+ mLifeOrig = null;
+
+ if (imagesScaled) {
+ mBackground.bmp.recycle();
+ for (int i = 0; i < mBubbles.length; i++) {
+ mBubbles[i].bmp.recycle();
+ }
+ for (int i = 0; i < mBubblesBlind.length; i++) {
+ mBubblesBlind[i].bmp.recycle();
+ }
+ for (int i = 0; i < mFrozenBubbles.length; i++) {
+ mFrozenBubbles[i].bmp.recycle();
+ }
+ for (int i = 0; i < mTargetedBubbles.length; i++) {
+ mTargetedBubbles[i].bmp.recycle();
+ }
+ mBubbleBlink.bmp.recycle();
+ mGameWon.bmp.recycle();
+ mGameLost.bmp.recycle();
+ mHurry.bmp.recycle();
+ mPenguins.bmp.recycle();
+ mCompressorHead.bmp.recycle();
+ mCompressor.bmp.recycle();
+ mLife.bmp.recycle();
+ }
+ mBackground.bmp = null;
+ mBackground = null;
+ for (int i = 0; i < mBubbles.length; i++) {
+ mBubbles[i].bmp = null;
+ mBubbles[i] = null;
+ }
+ mBubbles = null;
+ for (int i = 0; i < mBubblesBlind.length; i++) {
+ mBubblesBlind[i].bmp = null;
+ mBubblesBlind[i] = null;
+ }
+ mBubblesBlind = null;
+ for (int i = 0; i < mFrozenBubbles.length; i++) {
+ mFrozenBubbles[i].bmp = null;
+ mFrozenBubbles[i] = null;
+ }
+ mFrozenBubbles = null;
+ for (int i = 0; i < mTargetedBubbles.length; i++) {
+ mTargetedBubbles[i].bmp = null;
+ mTargetedBubbles[i] = null;
+ }
+ mTargetedBubbles = null;
+ mBubbleBlink.bmp = null;
+ mBubbleBlink = null;
+ mGameWon.bmp = null;
+ mGameWon = null;
+ mGameLost.bmp = null;
+ mGameLost = null;
+ mHurry.bmp = null;
+ mHurry = null;
+ mPenguins.bmp = null;
+ mPenguins = null;
+ mCompressorHead.bmp = null;
+ mCompressorHead = null;
+ mCompressor.bmp = null;
+ mCompressor = null;
+ mLife.bmp = null;
+ mLife = null;
+
+ mImageList = null;
+ mSoundManager.cleanUp();
+ mSoundManager = null;
+ mLevelManager = null;
+ mFrozenGame = null;
+ }
+ }
+ }
+
+ private Context mContext;
+ private GameThread thread;
+
+ public GameView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ Log.i("frozen-bubble", "GameView constructor");
+
+ mContext = context;
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+
+ thread = new GameThread(holder);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+
+ thread.setRunning(true);
+ thread.start();
+ }
+
+ public GameThread getThread() {
+ return thread;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent msg) {
+ //Log.i("frozen-bubble", "GameView.onKeyDown()");
+ return thread.doKeyDown(keyCode, msg);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent msg) {
+ //Log.i("frozen-bubble", "GameView.onKeyUp()");
+ return thread.doKeyUp(keyCode, msg);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ //Log.i("frozen-bubble", "event.getX(): " + event.getX());
+ //Log.i("frozen-bubble", "event.getY(): " + event.getY());
+ return thread.doTrackballEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return thread.doTouchEvent(event);
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ Log.i("frozen-bubble", "GameView.onWindowFocusChanged()");
+ if (!hasWindowFocus) {
+ thread.pause();
+ }
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ Log.i("frozen-bubble", "GameView.surfaceChanged");
+ thread.setSurfaceSize(width, height);
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.i("frozen-bubble", "GameView.surfaceCreated()");
+ thread.setSurfaceOK(true);
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.i("frozen-bubble", "GameView.surfaceDestroyed()");
+ thread.setSurfaceOK(false);
+ }
+
+ public void cleanUp() {
+ Log.i("frozen-bubble", "GameView.cleanUp()");
+ thread.cleanUp();
+ mContext = null;
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/ImageSprite.java b/src/org/jfedor/frozenbubble/ImageSprite.java
new file mode 100644
index 0000000..371d075
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/ImageSprite.java
@@ -0,0 +1,91 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import java.util.Vector;
+
+public class ImageSprite extends Sprite
+{
+ private BmpWrap displayedImage;
+
+ public ImageSprite(Rect area, BmpWrap img)
+ {
+ super(area);
+
+ this.displayedImage = img;
+ }
+
+ public void saveState(Bundle map, Vector savedSprites) {
+ if (getSavedId() != -1) {
+ return;
+ }
+ super.saveState(map, savedSprites);
+ map.putInt(String.format("%d-imageId", getSavedId()), displayedImage.id);
+ }
+
+ public int getTypeId()
+ {
+ return Sprite.TYPE_IMAGE;
+ }
+
+ public void changeImage(BmpWrap img)
+ {
+ this.displayedImage = img;
+ }
+
+ public final void paint(Canvas c, double scale, int dx, int dy)
+ {
+ Point p = super.getSpritePosition();
+ drawImage(displayedImage, p.x, p.y, c, scale, dx, dy);
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/LaunchBubbleSprite.java b/src/org/jfedor/frozenbubble/LaunchBubbleSprite.java
new file mode 100644
index 0000000..82db9ce
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/LaunchBubbleSprite.java
@@ -0,0 +1,124 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import java.util.Vector;
+
+public class LaunchBubbleSprite extends Sprite
+{
+ private int currentColor;
+ private int currentDirection;
+ private Drawable launcher;
+ private BmpWrap[] bubbles;
+ private BmpWrap[] colorblindBubbles;
+
+ public LaunchBubbleSprite(int initialColor, int initialDirection,
+ Drawable launcher,
+ BmpWrap[] bubbles, BmpWrap[] colorblindBubbles)
+ {
+ super(new Rect(276, 362, 276 + 86, 362 + 76));
+
+ currentColor = initialColor;
+ currentDirection = initialDirection;
+ this.launcher = launcher;
+ this.bubbles = bubbles;
+ this.colorblindBubbles = colorblindBubbles;
+ }
+
+ public void saveState(Bundle map, Vector saved_sprites) {
+ if (getSavedId() != -1) {
+ return;
+ }
+ super.saveState(map, saved_sprites);
+ map.putInt(String.format("%d-currentColor", getSavedId()), currentColor);
+ map.putInt(String.format("%d-currentDirection", getSavedId()),
+ currentDirection);
+ }
+
+ public int getTypeId()
+ {
+ return Sprite.TYPE_LAUNCH_BUBBLE;
+ }
+
+ public void changeColor(int newColor)
+ {
+ currentColor = newColor;
+ }
+
+ public void changeDirection(int newDirection)
+ {
+ currentDirection = newDirection;
+ }
+
+ public final void paint(Canvas c, double scale, int dx, int dy)
+ {
+ if (FrozenBubble.getMode() == FrozenBubble.GAME_NORMAL) {
+ drawImage(bubbles[currentColor], 302, 390, c, scale, dx, dy);
+ } else {
+ drawImage(colorblindBubbles[currentColor], 302, 390, c, scale, dx, dy);
+ }
+
+ // Draw the scaled and rotated launcher.
+ c.save();
+ int xCenter = 318;
+ int yCenter = 406;
+ c.rotate((float)(0.025 * 180 * (currentDirection - 20)),
+ (float)(xCenter * scale + dx), (float)(yCenter * scale + dy));
+ launcher.setBounds((int)((xCenter - 50) * scale + dx),
+ (int)((yCenter - 50) * scale + dy),
+ (int)((xCenter + 50) * scale + dx),
+ (int)((yCenter + 50) * scale + dy));
+ launcher.draw(c);
+ c.restore();
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/LevelManager.java b/src/org/jfedor/frozenbubble/LevelManager.java
new file mode 100644
index 0000000..36dee79
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/LevelManager.java
@@ -0,0 +1,177 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.os.Bundle;
+import java.util.Vector;
+
+public class LevelManager
+{
+ private int currentLevel;
+ private Vector levelList;
+
+ public void saveState(Bundle map)
+ {
+ map.putInt("LevelManager-currentLevel", currentLevel);
+ }
+
+ public void restoreState(Bundle map)
+ {
+ currentLevel = map.getInt("LevelManager-currentLevel");
+ }
+
+ public LevelManager(byte[] levels)
+ {
+ String allLevels = new String(levels);
+
+ currentLevel = 0;
+ levelList = new Vector();
+
+ int nextLevel = allLevels.indexOf("\n\n");
+ if (nextLevel == -1 && allLevels.trim().length() != 0)
+ {
+ nextLevel = allLevels.length();
+ }
+
+ while (nextLevel != -1)
+ {
+ String currentLevel = allLevels.substring(0, nextLevel).trim();
+
+ levelList.addElement(getLevel(currentLevel));
+
+ allLevels = allLevels.substring(nextLevel).trim();
+
+ if (allLevels.length() == 0)
+ {
+ nextLevel = -1;
+ }
+ else
+ {
+ nextLevel = allLevels.indexOf("\n\n");
+
+ if (nextLevel == -1)
+ {
+ nextLevel = allLevels.length();
+ }
+ }
+ }
+ }
+
+ private byte[][] getLevel(String data)
+ {
+ byte[][] temp = new byte[8][12];
+
+ for (int j=0 ; j<12 ; j++)
+ {
+ for (int i=0 ; i<8 ; i++)
+ {
+ temp[i][j] = -1;
+ }
+ }
+
+ int tempX = 0;
+ int tempY = 0;
+
+ for (int i=0 ; i= 48 && data.charAt(i) <= 55)
+ {
+ temp[tempX][tempY] = (byte)(data.charAt(i) - 48);
+ tempX++;
+ }
+ else if (data.charAt(i) == 45)
+ {
+ temp[tempX][tempY] = -1;
+ tempX++;
+ }
+
+ if (tempX == 8)
+ {
+ tempY++;
+
+ if (tempY == 12)
+ {
+ return temp;
+ }
+
+ tempX = tempY % 2;
+ }
+ }
+
+ return temp;
+ }
+
+ public byte[][] getCurrentLevel()
+ {
+ if (currentLevel < levelList.size())
+ {
+ return (byte[][])levelList.elementAt(currentLevel);
+ }
+
+ return null;
+ }
+
+ public void goToNextLevel()
+ {
+ currentLevel++;
+ if (currentLevel >= levelList.size()) {
+ currentLevel = 0;
+ }
+ }
+
+ public void goToFirstLevel()
+ {
+ currentLevel = 0;
+ }
+
+ public int getLevelIndex()
+ {
+ return currentLevel+1;
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/PenguinSprite.java b/src/org/jfedor/frozenbubble/PenguinSprite.java
new file mode 100644
index 0000000..9b598d3
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/PenguinSprite.java
@@ -0,0 +1,188 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Bundle;
+import java.util.Random;
+import java.util.Vector;
+
+public class PenguinSprite extends Sprite
+{
+ public final static int STATE_TURN_LEFT = 0;
+ public final static int STATE_TURN_RIGHT = 1;
+ public final static int STATE_FIRE = 2;
+ public final static int STATE_VOID = 3;
+ public final static int STATE_GAME_WON = 4;
+ public final static int STATE_GAME_LOST = 5;
+
+ public final static int[][] LOST_SEQUENCE =
+ {{1,0}, {2,8}, {3,9}, {4,10}, {5,11}, {6,12}, {7,13}, {5,14}};
+ public final static int[][] WON_SEQUENCE =
+ {{1,0}, {2,7}, {3,6}, {4,15}, {5,16}, {6,17}, {7,18}, {4,19}};
+
+ private BmpWrap spritesImage;
+
+ private int currentPenguin;
+
+ private int count;
+
+ private Random rand;
+
+ private int finalState;
+ private int nextPosition;
+
+ public PenguinSprite(BmpWrap sprites, Random rand)
+ {
+ super(new Rect(360, 436, 360 + 57, 435 + 45));
+
+ this.spritesImage = sprites;
+ this.rand = rand;
+
+ currentPenguin = 0;
+
+ finalState = STATE_VOID;
+ nextPosition = 0;
+ }
+
+ public PenguinSprite(BmpWrap sprites, Random rand,
+ int currentPenguin, int count,
+ int finalState, int nextPosition)
+ {
+ super(new Rect(360, 436, 360 + 57, 435 + 45));
+
+ this.spritesImage = sprites;
+ this.rand = rand;
+ this.currentPenguin = currentPenguin;
+ this.count = count;
+ this.finalState = finalState;
+ this.nextPosition = nextPosition;
+ }
+
+ public void saveState(Bundle map, Vector saved_sprites) {
+ if (getSavedId() != -1) {
+ return;
+ }
+ super.saveState(map, saved_sprites);
+ map.putInt(String.format("%d-currentPenguin", getSavedId()),
+ currentPenguin);
+ map.putInt(String.format("%d-count", getSavedId()), count);
+ map.putInt(String.format("%d-finalState", getSavedId()), finalState);
+ map.putInt(String.format("%d-nextPosition", getSavedId()), nextPosition);
+ }
+
+ public int getTypeId()
+ {
+ return Sprite.TYPE_PENGUIN;
+ }
+
+ public void updateState(int state)
+ {
+ if (finalState != STATE_VOID) {
+ count++;
+
+ if (count % 6 == 0) {
+ if (finalState == STATE_GAME_LOST) {
+ currentPenguin = LOST_SEQUENCE[nextPosition][1];
+ nextPosition = LOST_SEQUENCE[nextPosition][0];
+ } else if (finalState == STATE_GAME_WON) {
+ currentPenguin = WON_SEQUENCE[nextPosition][1];
+ nextPosition = WON_SEQUENCE[nextPosition][0];
+ }
+ }
+ } else {
+ count++;
+
+ switch(state) {
+ case STATE_TURN_LEFT :
+ count = 0;
+ currentPenguin = 3;
+ break;
+ case STATE_TURN_RIGHT :
+ count = 0;
+ currentPenguin = 2;
+ break;
+ case STATE_FIRE :
+ count = 0;
+ currentPenguin = 1;
+ break;
+ case STATE_VOID :
+ if (currentPenguin<4 || currentPenguin>7) {
+ currentPenguin = 0;
+ }
+ break;
+ case STATE_GAME_WON :
+ case STATE_GAME_LOST :
+ count = 0;
+ finalState = state;
+ currentPenguin = 0;
+ return;
+ }
+
+ if (count>100) {
+ currentPenguin = 7;
+ } else if (count % 15 == 0 && count>25) {
+ currentPenguin = (rand.nextInt() % 3)+4;
+ if (currentPenguin < 4) {
+ currentPenguin = 0;
+ }
+ }
+ }
+ }
+
+ public void paint(Canvas c, double scale, int dx, int dy)
+ {
+ Rect r = this.getSpriteArea();
+ drawImageClipped(spritesImage,
+ 360 - (currentPenguin % 4) * 57,
+ 435 - (currentPenguin / 4) * 45,
+ r, c, scale, dx, dy);
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/R.java b/src/org/jfedor/frozenbubble/R.java
new file mode 100644
index 0000000..d168c81
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/R.java
@@ -0,0 +1,89 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package org.jfedor.frozenbubble;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class drawable {
+ public static final int background=0x7f020000;
+ public static final int bubble_1=0x7f020001;
+ public static final int bubble_2=0x7f020002;
+ public static final int bubble_3=0x7f020003;
+ public static final int bubble_4=0x7f020004;
+ public static final int bubble_5=0x7f020005;
+ public static final int bubble_6=0x7f020006;
+ public static final int bubble_7=0x7f020007;
+ public static final int bubble_8=0x7f020008;
+ public static final int bubble_blink=0x7f020009;
+ public static final int bubble_colourblind_1=0x7f02000a;
+ public static final int bubble_colourblind_2=0x7f02000b;
+ public static final int bubble_colourblind_3=0x7f02000c;
+ public static final int bubble_colourblind_4=0x7f02000d;
+ public static final int bubble_colourblind_5=0x7f02000e;
+ public static final int bubble_colourblind_6=0x7f02000f;
+ public static final int bubble_colourblind_7=0x7f020010;
+ public static final int bubble_colourblind_8=0x7f020011;
+ public static final int bubble_font=0x7f020012;
+ public static final int close_eyes=0x7f020013;
+ public static final int compressor=0x7f020014;
+ public static final int compressor_body=0x7f020015;
+ public static final int fixed_1=0x7f020016;
+ public static final int fixed_2=0x7f020017;
+ public static final int fixed_3=0x7f020018;
+ public static final int fixed_4=0x7f020019;
+ public static final int fixed_5=0x7f02001a;
+ public static final int fixed_6=0x7f02001b;
+ public static final int frozen_1=0x7f02001c;
+ public static final int frozen_2=0x7f02001d;
+ public static final int frozen_3=0x7f02001e;
+ public static final int frozen_4=0x7f02001f;
+ public static final int frozen_5=0x7f020020;
+ public static final int frozen_6=0x7f020021;
+ public static final int frozen_7=0x7f020022;
+ public static final int frozen_8=0x7f020023;
+ public static final int hurry=0x7f020024;
+ public static final int launcher=0x7f020025;
+ public static final int life=0x7f020026;
+ public static final int lose_panel=0x7f020027;
+ public static final int penguins=0x7f020028;
+ public static final int splash=0x7f020029;
+ public static final int void_panel=0x7f02002a;
+ public static final int win_panel=0x7f02002b;
+ }
+ public static final class id {
+ public static final int game=0x7f060000;
+ }
+ public static final class layout {
+ public static final int main=0x7f030000;
+ }
+ public static final class raw {
+ public static final int applause=0x7f040000;
+ public static final int destroy_group=0x7f040001;
+ public static final int hurry=0x7f040002;
+ public static final int launch=0x7f040003;
+ public static final int lose=0x7f040004;
+ public static final int newroot_solo=0x7f040005;
+ public static final int noh=0x7f040006;
+ public static final int rebound=0x7f040007;
+ public static final int stick=0x7f040008;
+ }
+ public static final class string {
+ public static final int app_name=0x7f050000;
+ public static final int menu_about=0x7f050008;
+ public static final int menu_colorblind_mode_off=0x7f050003;
+ public static final int menu_colorblind_mode_on=0x7f050002;
+ public static final int menu_dont_rush_me=0x7f050009;
+ public static final int menu_fullscreen_off=0x7f050005;
+ public static final int menu_fullscreen_on=0x7f050004;
+ public static final int menu_new_game=0x7f050001;
+ public static final int menu_rush_me=0x7f05000a;
+ public static final int menu_sound_off=0x7f050007;
+ public static final int menu_sound_on=0x7f050006;
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/SoundManager.java b/src/org/jfedor/frozenbubble/SoundManager.java
new file mode 100644
index 0000000..36d743d
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/SoundManager.java
@@ -0,0 +1,97 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.SoundPool;
+
+public class SoundManager
+{
+ private SoundPool soundPool;
+ private int[] sm;
+ Context context;
+
+ public SoundManager(Context context) {
+ this.context = context;
+ soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
+ sm = new int[FrozenBubble.NUM_SOUNDS];
+ sm[FrozenBubble.SOUND_WON] = soundPool.load(context, R.raw.applause, 1);
+ sm[FrozenBubble.SOUND_LOST] = soundPool.load(context, R.raw.lose, 1);
+ sm[FrozenBubble.SOUND_LAUNCH] = soundPool.load(context, R.raw.launch, 1);
+ sm[FrozenBubble.SOUND_DESTROY] =
+ soundPool.load(context, R.raw.destroy_group, 1);
+ sm[FrozenBubble.SOUND_REBOUND] =
+ soundPool.load(context, R.raw.rebound, 1);
+ sm[FrozenBubble.SOUND_STICK] = soundPool.load(context, R.raw.stick, 1);
+ sm[FrozenBubble.SOUND_HURRY] = soundPool.load(context, R.raw.hurry, 1);
+ sm[FrozenBubble.SOUND_NEWROOT] =
+ soundPool.load(context, R.raw.newroot_solo, 1);
+ sm[FrozenBubble.SOUND_NOH] = soundPool.load(context, R.raw.noh, 1);
+ }
+
+ public final void playSound(int sound) {
+ if (FrozenBubble.getSoundOn()) {
+ AudioManager mgr = (AudioManager)context.getSystemService(
+ Context.AUDIO_SERVICE);
+ float streamVolumeCurrent =
+ mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
+ float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ float volume = streamVolumeCurrent / streamVolumeMax;
+ soundPool.play(sm[sound], volume, volume, 1, 0, 1f);
+ }
+ }
+
+ public final void cleanUp() {
+ sm = null;
+ context = null;
+ soundPool.release();
+ soundPool = null;
+ }
+}
diff --git a/src/org/jfedor/frozenbubble/Sprite.java b/src/org/jfedor/frozenbubble/Sprite.java
new file mode 100644
index 0000000..b189297
--- /dev/null
+++ b/src/org/jfedor/frozenbubble/Sprite.java
@@ -0,0 +1,155 @@
+/*
+ * [[ Frozen-Bubble ]]
+ *
+ * Copyright (c) 2000-2003 Guillaume Cottenceau.
+ * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
+ *
+ * This code is distributed under the GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Artwork:
+ * Alexis Younes <73lab at free.fr>
+ * (everything but the bubbles)
+ * Amaury Amblard-Ladurantie
+ * (the bubbles)
+ *
+ * Soundtrack:
+ * Matthias Le Bidan
+ * (the three musics and all the sound effects)
+ *
+ * Design & Programming:
+ * Guillaume Cottenceau
+ * (design and manage the project, whole Perl sourcecode)
+ *
+ * Java version:
+ * Glenn Sanson
+ * (whole Java sourcecode, including JIGA classes
+ * http://glenn.sanson.free.fr/jiga/)
+ *
+ * Android port:
+ * Pawel Aleksander Fedorynski
+ *
+ * [[ http://glenn.sanson.free.fr/fb/ ]]
+ * [[ http://www.frozen-bubble.org/ ]]
+ */
+
+package org.jfedor.frozenbubble;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Bundle;
+import java.util.Vector;
+
+public abstract class Sprite
+{
+ public static int TYPE_BUBBLE = 1;
+ public static int TYPE_IMAGE = 2;
+ public static int TYPE_LAUNCH_BUBBLE = 3;
+ public static int TYPE_PENGUIN = 4;
+
+ private Rect spriteArea;
+ private int saved_id;
+
+ public Sprite(Rect spriteArea)
+ {
+ this.spriteArea = spriteArea;
+ saved_id = -1;
+ }
+
+ public void saveState(Bundle map, Vector saved_sprites)
+ {
+ if (saved_id != -1) {
+ return;
+ }
+ saved_id = saved_sprites.size();
+ saved_sprites.addElement(this);
+ map.putInt(String.format("%d-left", saved_id), spriteArea.left);
+ map.putInt(String.format("%d-right", saved_id), spriteArea.right);
+ map.putInt(String.format("%d-top", saved_id), spriteArea.top);
+ map.putInt(String.format("%d-bottom", saved_id), spriteArea.bottom);
+ map.putInt(String.format("%d-type", saved_id), getTypeId());
+ }
+
+ public final int getSavedId()
+ {
+ return saved_id;
+ }
+
+ public final void clearSavedId()
+ {
+ saved_id = -1;
+ }
+
+ public abstract int getTypeId();
+
+ public void changeSpriteArea(Rect newArea)
+ {
+ spriteArea = newArea;
+ }
+
+ public final void relativeMove(Point p)
+ {
+ spriteArea = new Rect(spriteArea);
+ spriteArea.offset(p.x, p.y);
+ }
+
+ public final void relativeMove(int x, int y)
+ {
+ spriteArea = new Rect(spriteArea);
+ spriteArea.offset(x, y);
+ }
+
+ public final void absoluteMove(Point p)
+ {
+ spriteArea = new Rect(spriteArea);
+ spriteArea.offsetTo(p.x, p.y);
+ }
+
+ public final Point getSpritePosition()
+ {
+ return new Point(spriteArea.left, spriteArea.top);
+ }
+
+ public final Rect getSpriteArea()
+ {
+ return spriteArea;
+ }
+
+ public static void drawImage(BmpWrap image, int x, int y,
+ Canvas c, double scale, int dx, int dy)
+ {
+ c.drawBitmap(image.bmp, (float)(x * scale + dx), (float)(y * scale + dy),
+ null);
+ }
+
+ public static void drawImageClipped(BmpWrap image, int x, int y, Rect clipr,
+ Canvas c, double scale, int dx, int dy)
+ {
+ c.save(Canvas.CLIP_SAVE_FLAG);
+ c.clipRect((float)(clipr.left * scale + dx),
+ (float)(clipr.top * scale + dy),
+ (float)(clipr.right * scale + dx),
+ (float)(clipr.bottom * scale + dy),
+ Region.Op.REPLACE);
+ c.drawBitmap(image.bmp, (float)(x * scale + dx), (float)(y * scale + dy),
+ null);
+ c.restore();
+ }
+
+ public abstract void paint(Canvas c, double scale, int dx, int dy);
+}