summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZakk Roberts <midkay@rockbox.org>2007-01-31 00:46:32 +0000
committerZakk Roberts <midkay@rockbox.org>2007-01-31 00:46:32 +0000
commite50cc6c36949ef0662b68f605059431b42231346 (patch)
tree09ef0bea5e897ef1adda65ead814e96daf384ca4
parentfc1efc7b13674a6d3a6b21f634a1038197775a75 (diff)
downloadrockbox-e50cc6c36949ef0662b68f605059431b42231346.tar.gz
rockbox-e50cc6c36949ef0662b68f605059431b42231346.zip
FS #6243 - Invadrox, awesome Invaders clone by Albert Veli, supporting almost all bitmap LCD targets (but not Archos). Also resorted plugins/bitmaps/native/SOURCES (alphabetically).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12162 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/SOURCES4
-rw-r--r--apps/plugins/bitmaps/native/SOURCES322
-rw-r--r--apps/plugins/bitmaps/native/invadrox.160x128x2.bmpbin0 -> 934 bytes
-rw-r--r--apps/plugins/bitmaps/native/invadrox.176x132x16.bmpbin0 -> 938 bytes
-rw-r--r--apps/plugins/bitmaps/native/invadrox.320x240x16.bmpbin0 -> 1726 bytes
-rw-r--r--apps/plugins/bitmaps/native/invadrox_left.320x240x16.bmpbin0 -> 5830 bytes
-rw-r--r--apps/plugins/bitmaps/native/invadrox_logo.176x220x16.bmpbin0 -> 12886 bytes
-rw-r--r--apps/plugins/bitmaps/native/invadrox_logo.240x320x16.bmpbin0 -> 19766 bytes
-rw-r--r--apps/plugins/bitmaps/native/invadrox_right.320x240x16.bmpbin0 -> 5830 bytes
-rw-r--r--apps/plugins/invadrox.c1794
-rw-r--r--docs/CREDITS1
11 files changed, 1971 insertions, 150 deletions
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index d22b3af423..ec06f38eb3 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -47,6 +47,10 @@ blackjack.c
47bounce.c 47bounce.c
48bubbles.c 48bubbles.c
49 49
50#if (LCD_DEPTH >= 2) && !defined(IPOD_MINI) && !defined(IPOD_MINI2G) && !defined(IRIVER_H10_5GB)
51invadrox.c
52#endif
53
50#if LCD_WIDTH != 128 && !defined(SANSA_E200) 54#if LCD_WIDTH != 128 && !defined(SANSA_E200)
51/* These need adjusting for the iRiver if'p screen */ 55/* These need adjusting for the iRiver if'p screen */
52brickmania.c 56brickmania.c
diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES
index 97ddbcf47d..b336f407e4 100644
--- a/apps/plugins/bitmaps/native/SOURCES
+++ b/apps/plugins/bitmaps/native/SOURCES
@@ -1,5 +1,57 @@
1#ifdef HAVE_LCD_BITMAP 1#ifdef HAVE_LCD_BITMAP
2 2
3/* Brickmania */
4#if (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176) && (LCD_DEPTH == 16)
5#if (LCD_WIDTH == 320)
6brickmania_menu_bg.320x240x16.bmp
7brickmania_bricks.320x240x16.bmp
8brickmania_pads.320x240x16.bmp
9brickmania_break.320x240x16.bmp
10brickmania_powerups.320x240x16.bmp
11#else
12brickmania_menu_bg.220x176x16.bmp
13brickmania_bricks.220x176x16.bmp
14brickmania_pads.220x176x16.bmp
15brickmania_break.220x176x16.bmp
16brickmania_powerups.220x176x16.bmp
17#endif
18brickmania_ball.220x176x16.bmp
19brickmania_menu_items.220x176x16.bmp
20brickmania_gameover.220x176x16.bmp
21#elif (((LCD_WIDTH == 160) && (LCD_HEIGHT == 128)) || \
22 ((LCD_WIDTH == 138) && (LCD_HEIGHT == 110))) && (LCD_DEPTH == 2)
23brickmania_menu_items.160x128x2.bmp
24brickmania_ball.160x128x2.bmp
25#if (LCD_WIDTH == 160)
26brickmania_bricks.160x128x2.bmp
27#else
28brickmania_bricks.138x110x2.bmp
29#endif
30brickmania_gameover.160x128x2.bmp
31brickmania_menu_bg.160x128x2.bmp
32brickmania_pads.160x128x2.bmp
33brickmania_powerups.160x128x2.bmp
34brickmania_break.160x128x2.bmp
35#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 16)
36brickmania_menu_items.160x128x16.bmp
37brickmania_ball.160x128x16.bmp
38brickmania_bricks.160x128x16.bmp
39brickmania_gameover.160x128x16.bmp
40brickmania_menu_bg.160x128x16.bmp
41brickmania_pads.160x128x16.bmp
42brickmania_powerups.160x128x16.bmp
43brickmania_break.160x128x16.bmp
44#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) && (LCD_DEPTH == 16)
45brickmania_menu_items.176x132x16.bmp
46brickmania_ball.176x132x16.bmp
47brickmania_bricks.176x132x16.bmp
48brickmania_gameover.176x132x16.bmp
49brickmania_menu_bg.176x132x16.bmp
50brickmania_pads.176x132x16.bmp
51brickmania_powerups.176x132x16.bmp
52brickmania_break.176x132x16.bmp
53#endif
54
3/* Bubbles */ 55/* Bubbles */
4#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64) 56#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
5bubbles_emblem.112x64x1.bmp 57bubbles_emblem.112x64x1.bmp
@@ -51,6 +103,59 @@ chessbox_pieces.80x64x1.bmp
51chessbox_pieces.64x64x1.bmp 103chessbox_pieces.64x64x1.bmp
52#endif 104#endif
53 105
106/* Flipit */
107#ifdef HAVE_LCD_COLOR
108#if LCD_WIDTH >= 280 && LCD_HEIGHT >= 234
109flipit_cursor.56x56x16.bmp
110flipit_tokens.56x112x16.bmp
111#elif LCD_WIDTH >= 200 && LCD_HEIGHT >= 170
112flipit_cursor.40x40x16.bmp
113flipit_tokens.40x80x16.bmp
114#elif LCD_WIDTH >= 140 && LCD_HEIGHT >= 122
115flipit_cursor.28x28x16.bmp
116flipit_tokens.28x56x16.bmp
117#elif LCD_WIDTH >= 125 && LCD_HEIGHT >= 110
118flipit_cursor.25x25x16.bmp
119flipit_tokens.25x50x16.bmp
120#endif
121#elif LCD_DEPTH > 1 /* greyscale */
122#if LCD_WIDTH >= 140 && LCD_HEIGHT >= 122
123flipit_tokens.28x56x2.bmp
124#elif LCD_WIDTH >= 125 && LCD_HEIGHT >= 110
125flipit_tokens.25x50x2.bmp
126#endif
127#else /* monochrome */
128#if LCD_WIDTH >= 80 && LCD_HEIGHT >= 62
129flipit_tokens.16x26x1.bmp
130#endif
131#endif
132
133/* Invadrox */
134#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
135invadrox.320x240x16.bmp
136invadrox_left.320x240x16.bmp
137invadrox_right.320x240x16.bmp
138#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
139/* Use iPod Video character bitmap */
140invadrox.320x240x16.bmp
141#elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
142/* Use iPod Video character bitmap */
143invadrox.320x240x16.bmp
144invadrox_logo.240x320x16.bmp
145#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
146invadrox.176x132x16.bmp
147#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH >= 8)
148/* Use iPod Nano character bitmap */
149invadrox.176x132x16.bmp
150#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 2)
151/* Grayscale */
152invadrox.160x128x2.bmp
153#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
154/* Use iPod Nano character bitmap */
155invadrox.176x132x16.bmp
156invadrox_logo.176x220x16.bmp
157#endif
158
54/* Jewels */ 159/* Jewels */
55#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64) 160#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
56jewels.112x64x1.bmp 161jewels.112x64x1.bmp
@@ -76,6 +181,46 @@ jewels.320x240x16.bmp
76jewels.320x240x16.bmp 181jewels.320x240x16.bmp
77#endif 182#endif
78 183
184/* Minesweeper */
185#ifdef HAVE_LCD_COLOR
186#if ( LCD_HEIGHT * LCD_WIDTH ) / ( 16 * 16 ) >= 130
187minesweeper_tiles.16x16x24.bmp
188#else
189minesweeper_tiles.12x12x24.bmp
190#endif
191#elif LCD_DEPTH > 1
192minesweeper_tiles.12x12x2.bmp
193#else
194minesweeper_tiles.8x8x1.bmp
195#endif
196
197/* Rockblox */
198#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) && (LCD_DEPTH == 16)
199rockblox_background.320x240x16.bmp
200#elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320) && (LCD_DEPTH == 16)
201rockblox_background.240x320x16.bmp
202#elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176) && (LCD_DEPTH == 16)
203rockblox_background.220x176x16.bmp
204#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) && (LCD_DEPTH == 16)
205rockblox_background.176x132x16.bmp
206#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220) && (LCD_DEPTH == 16)
207rockblox_background.176x220x16.bmp
208#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH >= 16)
209rockblox_background.160x128x16.bmp
210#elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 16)
211rockblox_background.128x128x16.bmp
212#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 2)
213rockblox_background.160x128x2.bmp
214#elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110) && (LCD_DEPTH == 2)
215rockblox_background.138x110x2.bmp
216#endif
217
218/* Rockpaint */
219#ifdef HAVE_LCD_COLOR
220rockpaint.8x8x24.bmp
221rockpaint_hsvrgb.8x10x24.bmp
222#endif
223
79/* Snake2 */ 224/* Snake2 */
80#if (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) && (LCD_DEPTH >= 16) 225#if (LCD_WIDTH >= 320) && (LCD_HEIGHT >= 240) && (LCD_DEPTH >= 16)
81snake2_header1.320x240x16.bmp 226snake2_header1.320x240x16.bmp
@@ -129,60 +274,6 @@ sokoban_tiles.6x6.bmp
129sokoban_tiles.6x6x2.bmp 274sokoban_tiles.6x6x2.bmp
130#endif 275#endif
131 276
132/* Flip it */
133#ifdef HAVE_LCD_COLOR
134#if LCD_WIDTH >= 280 && LCD_HEIGHT >= 234
135flipit_cursor.56x56x16.bmp
136flipit_tokens.56x112x16.bmp
137#elif LCD_WIDTH >= 200 && LCD_HEIGHT >= 170
138flipit_cursor.40x40x16.bmp
139flipit_tokens.40x80x16.bmp
140#elif LCD_WIDTH >= 140 && LCD_HEIGHT >= 122
141flipit_cursor.28x28x16.bmp
142flipit_tokens.28x56x16.bmp
143#elif LCD_WIDTH >= 125 && LCD_HEIGHT >= 110
144flipit_cursor.25x25x16.bmp
145flipit_tokens.25x50x16.bmp
146#endif
147#elif LCD_DEPTH > 1 /* greyscale */
148#if LCD_WIDTH >= 140 && LCD_HEIGHT >= 122
149flipit_tokens.28x56x2.bmp
150#elif LCD_WIDTH >= 125 && LCD_HEIGHT >= 110
151flipit_tokens.25x50x2.bmp
152#endif
153#else /* monochrome */
154#if LCD_WIDTH >= 80 && LCD_HEIGHT >= 62
155flipit_tokens.16x26x1.bmp
156#endif
157#endif
158
159/* Star */
160#ifdef HAVE_LCD_COLOR
161#if LCD_WIDTH >= 320 && LCD_HEIGHT >= 188
162star_tiles.20x20.bmp
163#elif LCD_WIDTH >= 240 && LCD_HEIGHT >= 143
164star_tiles.15x15.bmp
165#elif LCD_WIDTH >= 208 && LCD_HEIGHT >= 125
166star_tiles.13x13.bmp
167#elif LCD_WIDTH >= 176 && LCD_HEIGHT >= 107
168star_tiles.11x11.bmp
169#elif LCD_WIDTH >= 160 && LCD_HEIGHT >= 98
170star_tiles.10x10.bmp
171#elif LCD_WIDTH >= 128 && LCD_HEIGHT >= 80
172star_tiles.8x8.bmp
173#endif
174#elif LCD_DEPTH > 1 /* grey */
175#if LCD_WIDTH >= 160 && LCD_HEIGHT >= 98
176star_tiles.10x10.grey.bmp
177#elif LCD_WIDTH >= 128 && LCD_HEIGHT >= 80
178star_tiles.8x8.grey.bmp
179#endif
180#else /* monochrome */
181#if LCD_WIDTH >= 112 && LCD_HEIGHT >= 62
182star_tiles.6x7.mono.bmp
183#endif
184#endif
185
186/* Solitaire */ 277/* Solitaire */
187#ifdef HAVE_LCD_COLOR 278#ifdef HAVE_LCD_COLOR
188#if LCD_WIDTH >= 320 279#if LCD_WIDTH >= 320
@@ -220,6 +311,33 @@ solitaire_suitsi.13x52x1.bmp
220#endif 311#endif
221#endif 312#endif
222 313
314/* Star */
315#ifdef HAVE_LCD_COLOR
316#if LCD_WIDTH >= 320 && LCD_HEIGHT >= 188
317star_tiles.20x20.bmp
318#elif LCD_WIDTH >= 240 && LCD_HEIGHT >= 143
319star_tiles.15x15.bmp
320#elif LCD_WIDTH >= 208 && LCD_HEIGHT >= 125
321star_tiles.13x13.bmp
322#elif LCD_WIDTH >= 176 && LCD_HEIGHT >= 107
323star_tiles.11x11.bmp
324#elif LCD_WIDTH >= 160 && LCD_HEIGHT >= 98
325star_tiles.10x10.bmp
326#elif LCD_WIDTH >= 128 && LCD_HEIGHT >= 80
327star_tiles.8x8.bmp
328#endif
329#elif LCD_DEPTH > 1 /* grey */
330#if LCD_WIDTH >= 160 && LCD_HEIGHT >= 98
331star_tiles.10x10.grey.bmp
332#elif LCD_WIDTH >= 128 && LCD_HEIGHT >= 80
333star_tiles.8x8.grey.bmp
334#endif
335#else /* monochrome */
336#if LCD_WIDTH >= 112 && LCD_HEIGHT >= 62
337star_tiles.6x7.mono.bmp
338#endif
339#endif
340
223/* Sudoku */ 341/* Sudoku */
224#if LCD_WIDTH >= LCD_HEIGHT 342#if LCD_WIDTH >= LCD_HEIGHT
225#if (LCD_WIDTH == 112) && (LCD_HEIGHT==64) && (LCD_DEPTH == 1) 343#if (LCD_WIDTH == 112) && (LCD_HEIGHT==64) && (LCD_DEPTH == 1)
@@ -269,100 +387,4 @@ sudoku_inverse.320x240x16.bmp
269#endif 387#endif
270#endif 388#endif
271 389
272/* Brickmania */
273
274#if (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176) && (LCD_DEPTH == 16)
275#if (LCD_WIDTH == 320)
276brickmania_menu_bg.320x240x16.bmp
277brickmania_bricks.320x240x16.bmp
278brickmania_pads.320x240x16.bmp
279brickmania_break.320x240x16.bmp
280brickmania_powerups.320x240x16.bmp
281#else
282brickmania_menu_bg.220x176x16.bmp
283brickmania_bricks.220x176x16.bmp
284brickmania_pads.220x176x16.bmp
285brickmania_break.220x176x16.bmp
286brickmania_powerups.220x176x16.bmp
287#endif
288brickmania_ball.220x176x16.bmp
289brickmania_menu_items.220x176x16.bmp
290brickmania_gameover.220x176x16.bmp
291
292#elif (((LCD_WIDTH == 160) && (LCD_HEIGHT == 128)) || \
293 ((LCD_WIDTH == 138) && (LCD_HEIGHT == 110))) && (LCD_DEPTH == 2)
294brickmania_menu_items.160x128x2.bmp
295brickmania_ball.160x128x2.bmp
296#if (LCD_WIDTH == 160)
297brickmania_bricks.160x128x2.bmp
298#else
299brickmania_bricks.138x110x2.bmp
300#endif
301brickmania_gameover.160x128x2.bmp
302brickmania_menu_bg.160x128x2.bmp
303brickmania_pads.160x128x2.bmp
304brickmania_powerups.160x128x2.bmp
305brickmania_break.160x128x2.bmp
306
307#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 16)
308brickmania_menu_items.160x128x16.bmp
309brickmania_ball.160x128x16.bmp
310brickmania_bricks.160x128x16.bmp
311brickmania_gameover.160x128x16.bmp
312brickmania_menu_bg.160x128x16.bmp
313brickmania_pads.160x128x16.bmp
314brickmania_powerups.160x128x16.bmp
315brickmania_break.160x128x16.bmp
316
317#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) && (LCD_DEPTH == 16)
318brickmania_menu_items.176x132x16.bmp
319brickmania_ball.176x132x16.bmp
320brickmania_bricks.176x132x16.bmp
321brickmania_gameover.176x132x16.bmp
322brickmania_menu_bg.176x132x16.bmp
323brickmania_pads.176x132x16.bmp
324brickmania_powerups.176x132x16.bmp
325brickmania_break.176x132x16.bmp
326
327#endif
328
329/* Rockblox */
330#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) && (LCD_DEPTH == 16)
331rockblox_background.320x240x16.bmp
332#elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320) && (LCD_DEPTH == 16)
333rockblox_background.240x320x16.bmp
334#elif (LCD_WIDTH >= 220) && (LCD_HEIGHT >= 176) && (LCD_DEPTH == 16)
335rockblox_background.220x176x16.bmp
336#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) && (LCD_DEPTH == 16)
337rockblox_background.176x132x16.bmp
338#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220) && (LCD_DEPTH == 16)
339rockblox_background.176x220x16.bmp
340#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH >= 16)
341rockblox_background.160x128x16.bmp
342#elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 16)
343rockblox_background.128x128x16.bmp
344#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) && (LCD_DEPTH == 2)
345rockblox_background.160x128x2.bmp
346#elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110) && (LCD_DEPTH == 2)
347rockblox_background.138x110x2.bmp
348#endif
349
350#ifdef HAVE_LCD_COLOR
351/* Rockpaint */
352rockpaint.8x8x24.bmp
353rockpaint_hsvrgb.8x10x24.bmp
354#endif
355
356#if defined( HAVE_LCD_COLOR )
357#if ( LCD_HEIGHT * LCD_WIDTH ) / ( 16 * 16 ) >= 130
358minesweeper_tiles.16x16x24.bmp
359#else
360minesweeper_tiles.12x12x24.bmp
361#endif
362#elif LCD_DEPTH > 1
363minesweeper_tiles.12x12x2.bmp
364#else
365minesweeper_tiles.8x8x1.bmp
366#endif
367
368#endif /* HAVE_LCD_BITMAP */ 390#endif /* HAVE_LCD_BITMAP */
diff --git a/apps/plugins/bitmaps/native/invadrox.160x128x2.bmp b/apps/plugins/bitmaps/native/invadrox.160x128x2.bmp
new file mode 100644
index 0000000000..4834c39c16
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox.160x128x2.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/invadrox.176x132x16.bmp b/apps/plugins/bitmaps/native/invadrox.176x132x16.bmp
new file mode 100644
index 0000000000..1c9631baa4
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox.176x132x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/invadrox.320x240x16.bmp b/apps/plugins/bitmaps/native/invadrox.320x240x16.bmp
new file mode 100644
index 0000000000..73fd916878
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox.320x240x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/invadrox_left.320x240x16.bmp b/apps/plugins/bitmaps/native/invadrox_left.320x240x16.bmp
new file mode 100644
index 0000000000..8111e4762c
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox_left.320x240x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/invadrox_logo.176x220x16.bmp b/apps/plugins/bitmaps/native/invadrox_logo.176x220x16.bmp
new file mode 100644
index 0000000000..687102ad7a
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox_logo.176x220x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/invadrox_logo.240x320x16.bmp b/apps/plugins/bitmaps/native/invadrox_logo.240x320x16.bmp
new file mode 100644
index 0000000000..72b0534056
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox_logo.240x320x16.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/native/invadrox_right.320x240x16.bmp b/apps/plugins/bitmaps/native/invadrox_right.320x240x16.bmp
new file mode 100644
index 0000000000..ceb21053ed
--- /dev/null
+++ b/apps/plugins/bitmaps/native/invadrox_right.320x240x16.bmp
Binary files differ
diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c
new file mode 100644
index 0000000000..befd91e5a7
--- /dev/null
+++ b/apps/plugins/invadrox.c
@@ -0,0 +1,1794 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2006 Albert Veli
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/* Improvised creds goes to:
21 *
22 * - Anders Clausen for ingeniously inventing the name Invadrox.
23 * - Linus Nielsen-Feltzing for patiently answering n00b questions.
24 */
25
26#include "plugin.h"
27#include "highscore.h"
28
29PLUGIN_HEADER
30
31/* Original graphics is only 1bpp so it should be portable
32 * to most targets. But for now, only support the simple ones.
33 */
34#ifndef HAVE_LCD_BITMAP
35 #error INVADROX: Unsupported LCD
36#endif
37
38#if (LCD_DEPTH < 2)
39 #error INVADROX: Unsupported LCD
40#endif
41
42/* #define DEBUG */
43#ifdef DEBUG
44#include <stdio.h>
45#define DBG(format, arg...) { printf("%s: " format, __FUNCTION__, ## arg); }
46#else
47#define DBG(format, arg...) {}
48#endif
49
50#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
51 (CONFIG_KEYPAD == IRIVER_H300_PAD)
52
53#define QUIT BUTTON_OFF
54#define LEFT BUTTON_LEFT
55#define RIGHT BUTTON_RIGHT
56#define FIRE BUTTON_SELECT
57
58#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
59
60#define QUIT BUTTON_POWER
61#define LEFT BUTTON_LEFT
62#define RIGHT BUTTON_RIGHT
63#define FIRE BUTTON_PLAY
64
65#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \
66 (CONFIG_KEYPAD == IPOD_4G_PAD)
67
68#define QUIT BUTTON_MENU
69#define LEFT BUTTON_LEFT
70#define RIGHT BUTTON_RIGHT
71#define FIRE BUTTON_SELECT
72
73#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
74
75#define QUIT BUTTON_POWER
76#define LEFT BUTTON_LEFT
77#define RIGHT BUTTON_RIGHT
78#define FIRE BUTTON_SELECT
79
80#elif CONFIG_KEYPAD == GIGABEAT_PAD
81
82#define QUIT BUTTON_A
83#define LEFT BUTTON_LEFT
84#define RIGHT BUTTON_RIGHT
85#define FIRE BUTTON_SELECT
86
87#elif CONFIG_KEYPAD == SANSA_E200_PAD
88
89#define QUIT BUTTON_POWER
90#define LEFT BUTTON_LEFT
91#define RIGHT BUTTON_RIGHT
92#define FIRE BUTTON_SELECT
93
94#elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
95
96/* TODO: Figure out which buttons to use for Tatung Elio TPJ-1022 */
97#define QUIT BUTTON_AB
98#define LEFT BUTTON_LEFT
99#define RIGHT BUTTON_RIGHT
100#define FIRE BUTTON_MENU
101
102#else
103 #error INVADROX: Unsupported keypad
104#endif
105
106
107#ifndef UNUSED
108#define UNUSED __attribute__ ((unused))
109#endif
110
111#ifndef ABS
112#define ABS(x) (((x) < 0) ? (-(x)) : (x))
113#endif
114
115
116/* Defines common to all models */
117#define UFO_Y (SCORENUM_Y + FONT_HEIGHT + ALIEN_HEIGHT)
118#define PLAYFIELD_Y (LCD_HEIGHT - SHIP_HEIGHT - 2)
119#define PLAYFIELD_WIDTH (LCD_WIDTH - 2 * PLAYFIELD_X)
120#define LEVEL_X (LCD_WIDTH - PLAYFIELD_X - LIVES_X - LEVEL_WIDTH - 2 * NUMBERS_WIDTH - 3 * NUM_SPACING)
121#define SHIP_MIN_X (PLAYFIELD_X + PLAYFIELD_WIDTH / 5 - SHIELD_WIDTH / 2 - SHIP_WIDTH)
122#define SHIP_MAX_X (PLAYFIELD_X + 4 * PLAYFIELD_WIDTH / 5 + SHIELD_WIDTH / 2)
123/* SCORE_Y = 0 for most targets. Gigabeat redefines it later. */
124#define SCORE_Y 0
125#define MAX_LIVES 8
126
127
128/* iPod Video defines */
129#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
130
131/* Original arcade game size 224x240, 1bpp with
132 * red overlay at top and green overlay at bottom.
133 *
134 * iPod Video: 320x240x16
135 * ======================
136 * X: 48p padding at left/right gives 224p playfield in middle.
137 * 10p "border" gives 204p actual playfield. UFO use full 224p.
138 * Y: Use full 240p.
139 *
140 * MAX_X = (204 - 12) / 2 - 1 = 95
141 *
142 * Y: Score text 7 0
143 * Space 10 7
144 * Score 7 17
145 * Space 8 24
146 * 3 Ufo 7 32
147 * 2 Space Aliens start at 32 + 3 * 8 = 56
148 * 0 aliens 9*8 56 -
149 * space ~7*8 128 | 18.75 aliens space between
150 * shield 2*8 182 | first alien and ship.
151 * space 8 198 | MAX_Y = 18
152 * ship 8 206 -
153 * space 2*8 214
154 * hline 1 230 - PLAYFIELD_Y
155 * bottom border 10 240
156 * Lives and Level goes inside bottom border
157 */
158
159#define ARCADISH_GRAPHICS
160#define PLAYFIELD_X 48
161#define SHIP_Y (PLAYFIELD_Y - 3 * SHIP_HEIGHT)
162#define ALIEN_START_Y (UFO_Y + 3 * ALIEN_HEIGHT)
163#define SCORENUM_X (PLAYFIELD_X + NUMBERS_WIDTH)
164#define SCORENUM_Y SCORE_Y + (2 * (FONT_HEIGHT + 1) + 1)
165#define HISCORE_X (LCD_WIDTH - PLAYFIELD_X - HISCORE_WIDTH)
166#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 1 - 6 * NUMBERS_WIDTH - 5 * NUM_SPACING)
167#define SHIELD_Y (PLAYFIELD_Y - 6 * SHIP_HEIGHT)
168#define LIVES_X 10
169#define MAX_X 95
170#define MAX_Y 18
171
172
173#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
174
175/* Sandisk Sansa e200: 176x220x16
176 * ==============================
177 * X: No padding. 8p border -> 160p playfield.
178 *
179 * 8p Aliens with 3p spacing -> 88 + 30 = 118p aliens block.
180 * (160 - 118) / 2 = 21 rounds for whole block (more than original)
181 * MAX_X = (160 - 8) / 2 - 1 = 75 rounds for single alien (less than original)
182 *
183 * LOGO 70 0
184 * Score text 5 70
185 * Space 5 75
186 * Y Score 5 80
187 * Space 10 85
188 * 2 Ufo 5 95
189 * 2 Space 10 100
190 * 0 aliens 9*5 110 -
191 * space ~7*5 155 | 18.6 aliens space between
192 * shield 2*5 188 | first alien and ship.
193 * space 5 198 | MAX_Y = 18
194 * ship 5 203 -
195 * space 5 208
196 * hline 1 213 PLAYFIELD_Y
197 * bottom border 6
198 * LCD_HEIGHT 220
199 * Lives and Level goes inside bottom border
200 */
201
202#define TINY_GRAPHICS
203#define PLAYFIELD_X 0
204#define SHIP_Y (PLAYFIELD_Y - 2 * SHIP_HEIGHT)
205#define SHIELD_Y (SHIP_Y - SHIP_HEIGHT - SHIELD_HEIGHT)
206#define ALIEN_START_Y (UFO_Y + 3 * SHIP_HEIGHT)
207/* Redefine SCORE_Y */
208#undef SCORE_Y
209#define SCORE_Y 70
210#define SCORENUM_X (PLAYFIELD_X + NUMBERS_WIDTH)
211#define SCORENUM_Y (SCORE_Y + 2 * FONT_HEIGHT)
212#define HISCORE_X (LCD_WIDTH - PLAYFIELD_X - HISCORE_WIDTH)
213#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 1 - 6 * NUMBERS_WIDTH - 5 * NUM_SPACING)
214#define LIVES_X 8
215#define MAX_X 75
216#define MAX_Y 18
217
218
219#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
220
221/* iPod Nano: 176x132x16
222 * ======================
223 * X: No padding. 8p border -> 160p playfield.
224 *
225 * LIVES_X 8
226 * ALIEN_WIDTH 8
227 * ALIEN_HEIGHT 5
228 * ALIEN_SPACING 3
229 * SHIP_WIDTH 10
230 * SHIP_HEIGHT 5
231 * FONT_HEIGHT 5
232 * UFO_WIDTH 10
233 * UFO_HEIGHT 5
234 * SHIELD_WIDTH 15
235 * SHIELD_HEIGHT 10
236 * MAX_X 75
237 * MAX_Y = 18
238 * ALIEN_START_Y (UFO_Y + 12)
239 *
240 * 8p Aliens with 3p spacing -> 88 + 30 = 118p aliens block.
241 * (160 - 118) / 2 = 21 rounds for whole block (more than original)
242 * MAX_X = (160 - 8) / 2 - 1 = 75 rounds for single alien (less than original)
243 *
244 * Y: Scoreline 5 0 (combine scoretext and numbers on same line)
245 * Space 5 5
246 * 1 Ufo 5 10
247 * 3 Space 7 15
248 * 2 aliens 9*5 22 -
249 * space ~7*5 67 | Just above 18 aliens space between
250 * shield 2*5 100 | first alien and ship.
251 * space 5 110 | MAX_Y = 18
252 * ship 5 115 -
253 * space 5 120
254 * hline 1 125 PLAYFIELD_Y
255 * bottom border 6 126
256 * LCD_HEIGHT 131
257 * Lives and Level goes inside bottom border
258 */
259
260#define TINY_GRAPHICS
261#define PLAYFIELD_X 0
262#define SHIP_Y (PLAYFIELD_Y - 2 * SHIP_HEIGHT)
263#define ALIEN_START_Y (UFO_Y + 12)
264#define SCORENUM_X (PLAYFIELD_X + SCORE_WIDTH + NUMBERS_WIDTH + NUM_SPACING)
265#define SCORENUM_Y SCORE_Y
266#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 4 * NUMBERS_WIDTH - 3 * NUM_SPACING)
267#define HISCORE_X (HISCORENUM_X - NUMBERS_WIDTH - NUM_SPACING - HISCORE_WIDTH)
268#define SHIELD_Y (SHIP_Y - SHIP_HEIGHT - SHIELD_HEIGHT)
269#define LIVES_X 8
270#define MAX_X 75
271#define MAX_Y 18
272
273#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
274
275/* iAudio X5, iRiver H10 20Gb, iPod 3g/4g: 160x128x16
276 * ======================================
277 * X: No padding. No border -> 160p playfield.
278 *
279 * LIVES_X 0
280 * ALIEN_WIDTH 8
281 * ALIEN_HEIGHT 5
282 * ALIEN_SPACING 3
283 * SHIP_WIDTH 10
284 * SHIP_HEIGHT 5
285 * FONT_HEIGHT 5
286 * UFO_WIDTH 10
287 * UFO_HEIGHT 5
288 * SHIELD_WIDTH 15
289 * SHIELD_HEIGHT 10
290 * MAX_X 75
291 * MAX_Y = 18
292 * ALIEN_START_Y (UFO_Y + 10)
293 *
294 * 8p Aliens with 3p spacing -> 88 + 30 = 118p aliens block.
295 * (160 - 118) / 2 = 21 rounds for whole block (more than original)
296 * MAX_X = (160 - 8) / 2 - 1 = 75 rounds for single alien (less than original)
297 *
298 * Y: Scoreline 5 0 (combine scoretext and numbers on same line)
299 * Space 5 5
300 * 1 Ufo 5 10
301 * 2 Space 5 15
302 * 8 aliens 9*5 20 -
303 * space ~6*5 65 | Just above 18 aliens space between
304 * shield 2*5 96 | first alien and ship.
305 * space 5 106 | MAX_Y = 18
306 * ship 5 111 -
307 * space 5 116
308 * hline 1 121 PLAYFIELD_Y
309 * bottom border 6 122
310 * LCD_HEIGHT 128
311 * Lives and Level goes inside bottom border
312 */
313
314#define TINY_GRAPHICS
315#define PLAYFIELD_X 0
316#define SHIP_Y (PLAYFIELD_Y - 2 * SHIP_HEIGHT)
317#define ALIEN_START_Y (UFO_Y + 10)
318#define SCORENUM_X (PLAYFIELD_X + SCORE_WIDTH + NUMBERS_WIDTH + NUM_SPACING)
319#define SCORENUM_Y SCORE_Y
320#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 4 * NUMBERS_WIDTH - 3 * NUM_SPACING)
321#define HISCORE_X (HISCORENUM_X - NUMBERS_WIDTH - NUM_SPACING - HISCORE_WIDTH)
322#define SHIELD_Y (SHIP_Y - SHIP_HEIGHT - SHIELD_HEIGHT)
323#define LIVES_X 0
324#define MAX_X 75
325#define MAX_Y 18
326
327
328#elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
329
330/* Gigabeat: 240x320x16
331 * ======================
332 * X: 8p padding at left/right gives 224p playfield in middle.
333 * 10p "border" gives 204p actual playfield. UFO use full 224p.
334 * Y: Use bottom 240p for playfield and top 80 pixels for logo.
335 *
336 * MAX_X = (204 - 12) / 2 - 1 = 95
337 *
338 * Y: Score text 7 0 + 80
339 * Space 10 7 + 80
340 * Score 7 17 + 80
341 * Space 8 24 + 80
342 * 3 Ufo 7 32 + 80
343 * 2 Space Aliens start at 32 + 3 * 8 = 56
344 * 0 aliens 9*8 56 -
345 * space ~7*8 128 | 18.75 aliens space between
346 * shield 2*8 182 | first alien and ship.
347 * space 8 198 | MAX_Y = 18
348 * ship 8 206 -
349 * space 2*8 214
350 * hline 1 230 310 - PLAYFIELD_Y
351 * bottom border 10 240 320
352 * Lives and Level goes inside bottom border
353 */
354
355#define ARCADISH_GRAPHICS
356#define PLAYFIELD_X 8
357#define SHIP_Y (PLAYFIELD_Y - 3 * SHIP_HEIGHT)
358#define ALIEN_START_Y (UFO_Y + 3 * ALIEN_HEIGHT)
359/* Redefine SCORE_Y */
360#undef SCORE_Y
361#define SCORE_Y 80
362#define SCORENUM_X (PLAYFIELD_X + NUMBERS_WIDTH)
363#define SCORENUM_Y SCORE_Y + (2 * (FONT_HEIGHT + 1) + 1)
364#define HISCORE_X (LCD_WIDTH - PLAYFIELD_X - HISCORE_WIDTH)
365#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 1 - 6 * NUMBERS_WIDTH - 5 * NUM_SPACING)
366#define SHIELD_Y (PLAYFIELD_Y - 6 * SHIP_HEIGHT)
367#define LIVES_X 10
368#define MAX_X 95
369#define MAX_Y 18
370
371#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
372
373/* TPJ1022, H300, iPod Color: 220x176x16
374 * ============================
375 * X: 0p padding at left/right gives 220p playfield in middle.
376 * 8p "border" gives 204p actual playfield. UFO use full 220p.
377 * Y: Use full 176p for playfield.
378 *
379 * MAX_X = (204 - 12) / 2 - 1 = 95
380 *
381 * Y: Score text 7 0
382 * Space 8 7
383 * 1 Ufo 7 15
384 * 7 Space Aliens start at 15 + 3 * 8 = 56
385 * 6 aliens 9*8 25 -
386 * space ~7*8 103 | 15.6 aliens space between
387 * shield 2*8 126 | first alien and ship.
388 * space 8 142 | MAX_Y = 15
389 * ship 8 150 -
390 * space 8 158
391 * hline 1 166 - PLAYFIELD_Y
392 * bottom border 10 176
393 * Lives and Level goes inside bottom border
394 */
395
396#define ARCADISH_GRAPHICS
397#define PLAYFIELD_X 0
398#define SHIP_Y (PLAYFIELD_Y - 2 * SHIP_HEIGHT)
399#define ALIEN_START_Y (UFO_Y + 10)
400#define SCORENUM_Y SCORE_Y
401#define SCORENUM_X (PLAYFIELD_X + SCORE_WIDTH + NUMBERS_WIDTH + NUM_SPACING)
402#define HISCORENUM_X (LCD_WIDTH - PLAYFIELD_X - 4 * NUMBERS_WIDTH - 3 * NUM_SPACING)
403#define HISCORE_X (HISCORENUM_X - NUMBERS_WIDTH - NUM_SPACING - HISCORE_WIDTH)
404#define SHIELD_Y (PLAYFIELD_Y - 5 * SHIP_HEIGHT)
405#define LIVES_X 8
406#define MAX_X 95
407#define MAX_Y 15
408
409#else
410 #error INVADROX: Unsupported LCD type
411#endif
412
413
414/* Defines common to each "graphic type" */
415#ifdef ARCADISH_GRAPHICS
416
417#define STRIDE 71
418#define SHIP_SRC_X 24
419#define SHIP_WIDTH 16
420#define SHIP_HEIGHT 8
421#define SHOT_HEIGHT 5
422#define ALIEN_WIDTH 12
423#define ALIEN_EXPLODE_SRC_X 52
424#define ALIEN_EXPLODE_SRC_Y 39
425#define ALIEN_EXPLODE_WIDTH 13
426#define ALIEN_EXPLODE_HEIGHT 7
427#define ALIEN_HEIGHT 8
428#define ALIEN_SPACING 4
429#define ALIEN_SPEED 2
430#define UFO_SRC_X 40
431#define UFO_WIDTH 16
432#define UFO_HEIGHT 7
433#define UFO_EXPLODE_WIDTH 21
434#define UFO_EXPLODE_HEIGHT 8
435#define UFO_SPEED 1
436#define FONT_HEIGHT 7
437#define LEVEL_SRC_Y 24
438#define LEVEL_WIDTH 37
439#define SCORE_SRC_X 24
440#define SCORE_SRC_Y 31
441#define SCORE_WIDTH 37
442#define HISCORE_WIDTH 61
443#define NUM_SPACING 3
444#define NUMBERS_SRC_Y 38
445#define NUMBERS_WIDTH 5
446#define SHIELD_SRC_X 40
447#define SHIELD_SRC_Y 15
448#define SHIELD_WIDTH 22
449#define SHIELD_HEIGHT 16
450#define FIRE_WIDTH 8
451#define FIRE_HEIGHT 8
452#define FIRE_SPEED 8
453#define BOMB_SRC_X 62
454#define BOMB_WIDTH 3
455#define BOMB_HEIGHT 7
456#define BOMB_SPEED 3
457#define ALIENS 11
458unsigned char fire_sprite[FIRE_HEIGHT] = {
459 (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (0 << 1) | 1,
460 (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (1 << 1) | 0,
461 (0 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 0,
462 (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 1,
463 (0 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 1,
464 (0 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 0,
465 (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (0 << 3) | (1 << 2) | (0 << 1) | 0,
466 (1 << 7) | (0 << 6) | (0 << 5) | (1 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | 1
467};
468
469#elif defined TINY_GRAPHICS
470
471#define STRIDE 53
472#define SHIP_SRC_X 16
473#define SHIP_WIDTH 10
474#define SHIP_HEIGHT 5
475#define SHOT_HEIGHT 4
476#define ALIEN_WIDTH 8
477#define ALIEN_HEIGHT 5
478#define ALIEN_EXPLODE_SRC_X 40
479#define ALIEN_EXPLODE_SRC_Y 26
480#define ALIEN_EXPLODE_WIDTH 10
481#define ALIEN_EXPLODE_HEIGHT 5
482#define ALIEN_SPACING 3
483#define ALIEN_SPEED 2
484#define UFO_SRC_X 26
485#define UFO_WIDTH 11
486#define UFO_HEIGHT 5
487#define UFO_EXPLODE_WIDTH 14
488#define UFO_EXPLODE_HEIGHT 5
489#define UFO_SPEED 1
490#define FONT_HEIGHT 5
491#define LEVEL_SRC_Y 15
492#define LEVEL_WIDTH 29
493#define NUMBERS_WIDTH 4
494#define NUM_SPACING 2
495#define SCORE_SRC_X 17
496#define SCORE_SRC_Y 20
497#define SCORE_WIDTH 28
498#define HISCORE_WIDTH 45
499#define NUMBERS_SRC_Y 25
500#define SHIELD_SRC_X 29
501#define SHIELD_SRC_Y 10
502#define SHIELD_WIDTH 15
503#define SHIELD_HEIGHT 10
504#define FIRE_WIDTH 6
505#define FIRE_HEIGHT 6
506#define FIRE_SPEED 6
507#define BOMB_SRC_X 44
508#define BOMB_WIDTH 3
509#define BOMB_HEIGHT 5
510#define BOMB_SPEED 2
511#define ALIENS 11
512unsigned char fire_sprite[FIRE_HEIGHT] = {
513 (1 << 5) | (0 << 4) | (0 << 3) | (1 << 2) | (0 << 1) | 1,
514 (0 << 5) | (1 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | 0,
515 (0 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 0,
516 (0 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | 1,
517 (0 << 5) | (1 << 4) | (0 << 3) | (0 << 2) | (1 << 1) | 0,
518 (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (0 << 1) | 1
519};
520
521#else
522 #error Graphic type not defined
523#endif
524
525
526/* Colors */
527#if (LCD_DEPTH >= 8)
528#define SLIME_GREEN LCD_RGBPACK(31, 254, 31)
529#define UFO_RED LCD_RGBPACK(254, 31, 31)
530#elif (LCD_DEPTH == 2)
531#define SLIME_GREEN LCD_LIGHTGRAY
532#define UFO_RED LCD_LIGHTGRAY
533#else
534#error LCD type not implemented yet
535#endif
536
537/* Alien states */
538#define DEAD 0
539#define ALIVE 1
540#define BOMBER 2
541
542/* Fire/bomb/ufo states */
543#define S_IDLE 0
544#define S_ACTIVE 1
545#define S_SHOWSCORE 2
546#define S_EXPLODE -9
547
548/* Fire/bomb targets */
549#define TARGET_TOP 0
550#define TARGET_SHIELD 1
551#define TARGET_SHIP 2
552#define TARGET_BOTTOM 3
553#define TARGET_UFO 4
554
555#define HISCOREFILE "/.rockbox/rocks/invadrox.high"
556
557
558/* The time (in ms) for one iteration through the game loop - decrease this
559 * to speed up the game - note that current_tick is (currently) only accurate
560 * to 10ms.
561 */
562#define CYCLETIME 40
563
564
565static struct plugin_api* rb;
566
567/* Physical x is at PLAYFIELD_X + LIVES_X + x * ALIEN_SPEED
568 * Physical y is at y * ALIEN_HEIGHT
569 */
570struct alien {
571 unsigned char x; /* x-coordinate (0 - 95) */
572 unsigned char y; /* y-coordinate (0 - 18) */
573 unsigned char type; /* 0 (Kang), 1 (Kodos), 2 (Serak) */
574 unsigned char state; /* Dead, alive or bomber */
575};
576
577/* Aliens box 5 rows * ALIENS aliens in each row */
578struct alien aliens[5 * ALIENS];
579
580#define MAX_BOMBS 4
581struct bomb {
582 int x, y;
583 unsigned char type;
584 unsigned char frame; /* Current animation frame */
585 unsigned char frames; /* Number of frames in animation */
586 unsigned char target; /* Remember target during explosion frames */
587 int state; /* 0 (IDLE) = inactive, 1 (FIRE) or negative, exploding */
588};
589struct bomb bombs[MAX_BOMBS];
590/* Increase max_bombs at higher levels */
591int max_bombs;
592
593/* Raw framebuffer value of shield/ship green color */
594fb_data screen_green, screen_white;
595
596/* For optimization, precalculate startoffset of each scanline */
597unsigned int ytab[LCD_HEIGHT];
598
599/* external bitmaps */
600extern const fb_data invadrox[];
601#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
602/* iPod Video only */
603extern const fb_data invadrox_left[];
604extern const fb_data invadrox_right[];
605#endif
606#if ((LCD_WIDTH == 240) && (LCD_HEIGHT == 320)) || ((LCD_WIDTH == 176) && (LCD_HEIGHT == 220))
607/* Gigabeat F, Sansa e200 */
608extern const fb_data invadrox_logo[];
609#endif
610
611
612int lives = 2;
613int score = 0;
614int scores[3] = { 30, 20, 10 };
615int level = 0;
616struct highscore hiscore;
617bool game_over = false;
618int ship_x, old_ship_x, ship_dir, ship_acc, max_ship_speed;
619int ship_frame, ship_frame_counter;
620bool ship_hit;
621int fire, fire_target, fire_x, fire_y;
622int curr_alien, aliens_paralyzed, gamespeed;
623int ufo_state, ufo_x;
624bool level_finished;
625bool aliens_down, aliens_right, hit_left_border, hit_right_border;
626
627
628/* No standard get_pixel function yet, use this hack instead */
629#if (LCD_DEPTH >= 8)
630
631inline fb_data get_pixel(int x, int y)
632{
633 return rb->lcd_framebuffer[ytab[y] + x];
634}
635
636#elif (LCD_DEPTH == 2)
637
638#if (LCD_PIXELFORMAT == HORIZONTAL_PACKING)
639static const unsigned char shifts[4] = {
640 6, 4, 2, 0
641};
642/* Horizontal packing */
643inline fb_data get_pixel(int x, int y)
644{
645 return (rb->lcd_framebuffer[ytab[y] + (x >> 2)] >> shifts[x & 3]) & 3;
646}
647#else
648/* Vertical packing */
649static const unsigned char shifts[4] = {
650 0, 2, 4, 6
651};
652inline fb_data get_pixel(int x, int y)
653{
654 return (rb->lcd_framebuffer[ytab[y] + x] >> shifts[y & 3]) & 3;
655}
656#endif /* Horizontal/Vertical packing */
657
658#else
659 #error get_pixel: pixelformat not implemented yet
660#endif
661
662
663/* Draw "digits" least significant digits of num at (x,y) */
664void draw_number(int x, int y, int num, int digits)
665{
666 int i;
667 int d;
668
669 for (i = digits - 1; i >= 0; i--) {
670 d = num % 10;
671 num = num / 10;
672 rb->lcd_bitmap_part(invadrox, d * NUMBERS_WIDTH, NUMBERS_SRC_Y,
673 STRIDE, x + i * (NUMBERS_WIDTH + NUM_SPACING), y,
674 NUMBERS_WIDTH, FONT_HEIGHT);
675 }
676 /* Update lcd */
677 rb->lcd_update_rect(x, y, 4 * NUMBERS_WIDTH + 3 * NUM_SPACING, FONT_HEIGHT);
678}
679
680
681inline void draw_score(void)
682{
683 draw_number(SCORENUM_X, SCORENUM_Y, score, 4);
684 if (score > hiscore.score) {
685 /* Draw new hiscore (same as score) */
686 draw_number(HISCORENUM_X, SCORENUM_Y, score, 4);
687 }
688}
689
690
691void draw_level(void)
692{
693 rb->lcd_bitmap_part(invadrox, 0, LEVEL_SRC_Y,
694 STRIDE, LEVEL_X, PLAYFIELD_Y + 2,
695 LEVEL_WIDTH, FONT_HEIGHT);
696 draw_number(LEVEL_X + LEVEL_WIDTH + 2 * NUM_SPACING, PLAYFIELD_Y + 2, level, 2);
697}
698
699
700void draw_lives(void)
701{
702 int i;
703 /* Lives num */
704 rb->lcd_bitmap_part(invadrox, lives * NUMBERS_WIDTH, NUMBERS_SRC_Y,
705 STRIDE, PLAYFIELD_X + LIVES_X, PLAYFIELD_Y + 2,
706 NUMBERS_WIDTH, FONT_HEIGHT);
707
708 /* Ships */
709 for (i = 0; i < (lives - 1); i++) {
710 rb->lcd_bitmap_part(invadrox, SHIP_SRC_X, 0, STRIDE,
711 PLAYFIELD_X + LIVES_X + SHIP_WIDTH + i * (SHIP_WIDTH + NUM_SPACING),
712 PLAYFIELD_Y + 1, SHIP_WIDTH, SHIP_HEIGHT);
713 }
714
715 /* Erase ship to the righ (if less than MAX_LIVES) */
716 if (lives < MAX_LIVES) {
717 rb->lcd_fillrect(PLAYFIELD_X + LIVES_X + SHIP_WIDTH + i * (SHIP_WIDTH + NUM_SPACING),
718 PLAYFIELD_Y + 1, SHIP_WIDTH, SHIP_HEIGHT);
719 }
720 /* Update lives (and level) part of screen */
721 rb->lcd_update_rect(PLAYFIELD_X + LIVES_X, PLAYFIELD_Y + 1,
722 PLAYFIELD_WIDTH - 2 * LIVES_X, MAX(FONT_HEIGHT + 1, SHIP_HEIGHT + 1));
723}
724
725
726inline void draw_aliens(void)
727{
728 int i;
729
730 for (i = 0; i < 5 * ALIENS; i++) {
731 rb->lcd_bitmap_part(invadrox, aliens[i].x & 1 ? ALIEN_WIDTH : 0, aliens[i].type * ALIEN_HEIGHT,
732 STRIDE, PLAYFIELD_X + LIVES_X + aliens[i].x * ALIEN_SPEED,
733 ALIEN_START_Y + aliens[i].y * ALIEN_HEIGHT,
734 ALIEN_WIDTH, ALIEN_HEIGHT);
735 }
736}
737
738
739/* Return false if there is no next alive alien (round is over) */
740inline bool next_alien(void)
741{
742 bool ret = true;
743
744 do {
745 curr_alien++;
746 if (curr_alien % ALIENS == 0) {
747 /* End of this row. Move up one row. */
748 curr_alien -= 2 * ALIENS;
749 if (curr_alien < 0) {
750 /* No more aliens in this round. */
751 curr_alien = 4 * ALIENS;
752 ret = false;
753 }
754 }
755 } while (aliens[curr_alien].state == DEAD && ret);
756
757 if (!ret) {
758 /* No more alive aliens. Round finished. */
759 if (hit_right_border) {
760 if (hit_left_border) {
761 DBG("ERROR: both left and right borders are set (%d)\n", curr_alien);
762 }
763 /* Move down-left next round */
764 aliens_right = false;
765 aliens_down = true;
766 hit_right_border = false;
767 } else if (hit_left_border) {
768 /* Move down-right next round */
769 aliens_right = true;
770 aliens_down = true;
771 hit_left_border = false;
772 } else {
773 /* Not left nor right. Set down to false. */
774 aliens_down = false;
775 }
776 }
777
778 return ret;
779}
780
781
782/* All aliens have been moved.
783 * Set curr_alien to first alive.
784 * Return false if no-one is left alive.
785 */
786bool first_alien(void)
787{
788 int i, y;
789
790 for (y = 4; y >= 0; y--) {
791 for (i = y * ALIENS; i < (y + 1) * ALIENS; i++) {
792 if (aliens[i].state != DEAD) {
793 curr_alien = i;
794 return true;
795 }
796 }
797 }
798
799 /* All aliens dead. */
800 level_finished = true;
801
802 return false;
803}
804
805
806bool move_aliens(void)
807{
808 int x, y, old_x, old_y;
809
810 /* Move current alien (curr_alien is pointing to a living alien) */
811
812 old_x = aliens[curr_alien].x;
813 old_y = aliens[curr_alien].y;
814
815 if (aliens_down) {
816 aliens[curr_alien].y++;
817 if (aliens[curr_alien].y == MAX_Y) {
818 /* Alien is at bottom. Game Over. */
819 DBG("Alien %d is at bottom. Game Over.\n", curr_alien);
820 game_over = true;
821 return false;
822 }
823 }
824
825 if (aliens_right) {
826 /* Moving right */
827 if (aliens[curr_alien].x < MAX_X) {
828 aliens[curr_alien].x++;
829 }
830
831 /* Now, after move, check if we hit the right border. */
832 if (aliens[curr_alien].x == MAX_X) {
833 hit_right_border = true;
834 }
835
836 } else {
837 /* Moving left */
838 if (aliens[curr_alien].x > 0) {
839 aliens[curr_alien].x--;
840 }
841
842 /* Now, after move, check if we hit the left border. */
843 if (aliens[curr_alien].x == 0) {
844 hit_left_border = true;
845 }
846 }
847
848 /* Erase old position */
849 x = PLAYFIELD_X + LIVES_X + old_x * ALIEN_SPEED;
850 y = ALIEN_START_Y + old_y * ALIEN_HEIGHT;
851 if (aliens[curr_alien].y != old_y) {
852 /* Moved in y-dir. Erase whole alien. */
853 rb->lcd_fillrect(x, y, ALIEN_WIDTH, ALIEN_HEIGHT);
854 } else {
855 if (aliens_right) {
856 /* Erase left edge */
857 rb->lcd_fillrect(x, y, ALIEN_SPEED, ALIEN_HEIGHT);
858 } else {
859 /* Erase right edge */
860 x += ALIEN_WIDTH - ALIEN_SPEED;
861 rb->lcd_fillrect(x, y, ALIEN_SPEED, ALIEN_HEIGHT);
862 }
863 }
864
865 /* Draw alien at new pos */
866 x = PLAYFIELD_X + LIVES_X + aliens[curr_alien].x * ALIEN_SPEED;
867 y = ALIEN_START_Y + aliens[curr_alien].y * ALIEN_HEIGHT;
868 rb->lcd_bitmap_part(invadrox,
869 aliens[curr_alien].x & 1 ? ALIEN_WIDTH : 0, aliens[curr_alien].type * ALIEN_HEIGHT,
870 STRIDE, x, y, ALIEN_WIDTH, ALIEN_HEIGHT);
871
872 if (!next_alien()) {
873 /* Round finished. Set curr_alien to first alive from bottom. */
874 if (!first_alien()) {
875 /* Should never happen. Taken care of in move_fire(). */
876 return false;
877 }
878 /* TODO: Play next background sound */
879 }
880
881 return true;
882}
883
884
885inline void draw_ship(void)
886{
887 /* Erase old ship */
888 if (old_ship_x < ship_x) {
889 /* Move right. Erase leftmost part of ship. */
890 rb->lcd_fillrect(old_ship_x, SHIP_Y, ship_x - old_ship_x, SHIP_HEIGHT);
891 } else if (old_ship_x > ship_x) {
892 /* Move left. Erase rightmost part of ship. */
893 rb->lcd_fillrect(ship_x + SHIP_WIDTH, SHIP_Y, old_ship_x - ship_x, SHIP_HEIGHT);
894 }
895
896 /* Draw ship */
897 rb->lcd_bitmap_part(invadrox, SHIP_SRC_X, ship_frame * SHIP_HEIGHT,
898 STRIDE, ship_x, SHIP_Y, SHIP_WIDTH, SHIP_HEIGHT);
899 if (ship_hit) {
900 /* Alternate between frame 1 and 2 during hit */
901 ship_frame_counter++;
902 if (ship_frame_counter > 2) {
903 ship_frame_counter = 0;
904 ship_frame++;
905 if (ship_frame > 2) {
906 ship_frame = 1;
907 }
908 }
909 }
910
911 /* Save ship_x for next time */
912 old_ship_x = ship_x;
913}
914
915
916inline void fire_alpha(int xc, int yc, fb_data color)
917{
918 int x, y;
919 unsigned char mask;
920
921 rb->lcd_set_foreground(color);
922
923 for (y = 0; y < FIRE_HEIGHT; y++) {
924 mask = 1 << (FIRE_WIDTH - 1);
925 for (x = -(FIRE_WIDTH / 2); x < (FIRE_WIDTH / 2); x++) {
926 if (fire_sprite[y] & mask) {
927 rb->lcd_drawpixel(xc + x, yc + y);
928 }
929 mask >>= 1;
930 }
931 }
932
933 rb->lcd_set_foreground(LCD_BLACK);
934}
935
936
937void move_fire(void)
938{
939 bool hit_green = false;
940 bool hit_white = false;
941 int i, j;
942 static int exploding_alien = -1;
943 fb_data pix;
944
945 if (fire == S_IDLE) {
946 return;
947 }
948
949 /* Alien hit. Wait until explosion is finished. */
950 if (aliens_paralyzed < 0) {
951 aliens_paralyzed++;
952 if (aliens_paralyzed == 0) {
953 /* Erase exploding_alien */
954 rb->lcd_fillrect(PLAYFIELD_X + LIVES_X + aliens[exploding_alien].x * ALIEN_SPEED,
955 ALIEN_START_Y + aliens[exploding_alien].y * ALIEN_HEIGHT,
956 ALIEN_EXPLODE_WIDTH, ALIEN_HEIGHT);
957 fire = S_IDLE;
958 /* Special case. We killed curr_alien. */
959 if (exploding_alien == curr_alien) {
960 if (!next_alien()) {
961 /* Round finished. Set curr_alien to first alive from bottom. */
962 first_alien();
963 }
964 }
965 }
966 return;
967 }
968
969 if (fire == S_ACTIVE) {
970
971 /* Erase */
972 rb->lcd_vline(fire_x, fire_y, fire_y + SHOT_HEIGHT);
973
974 /* Check top */
975 if (fire_y <= SCORENUM_Y + FONT_HEIGHT + 4) {
976
977 /* TODO: Play explode sound */
978
979 fire = S_EXPLODE;
980 fire_target = TARGET_TOP;
981 fire_alpha(fire_x, fire_y, UFO_RED);
982 return;
983 }
984
985 /* Move */
986 fire_y -= FIRE_SPEED;
987
988 /* Hit UFO? */
989 if (ufo_state == S_ACTIVE) {
990 if ((ABS(ufo_x + UFO_WIDTH / 2 - fire_x) <= UFO_WIDTH / 2) &&
991 (fire_y <= UFO_Y + UFO_HEIGHT)) {
992 ufo_state = S_EXPLODE;
993 fire = S_EXPLODE;
994 fire_target = TARGET_UFO;
995 /* Center explosion */
996 ufo_x -= (UFO_EXPLODE_WIDTH - UFO_WIDTH) / 2;
997 rb->lcd_bitmap_part(invadrox, UFO_SRC_X, UFO_HEIGHT,
998 STRIDE, ufo_x, UFO_Y - 1, UFO_EXPLODE_WIDTH, UFO_EXPLODE_HEIGHT);
999 return;
1000 }
1001 }
1002
1003 /* Hit bomb? (check position, not pixel value) */
1004 for (i = 0; i < max_bombs; i++) {
1005 if (bombs[i].state == S_ACTIVE) {
1006 /* Count as hit if within BOMB_WIDTH pixels */
1007 if ((ABS(bombs[i].x - fire_x) < BOMB_WIDTH) &&
1008 (fire_y - bombs[i].y < BOMB_HEIGHT)) {
1009 /* Erase bomb */
1010 rb->lcd_fillrect(bombs[i].x, bombs[i].y, BOMB_WIDTH, BOMB_HEIGHT);
1011 bombs[i].state = S_IDLE;
1012 /* Explode ship fire */
1013 fire = S_EXPLODE;
1014 fire_target = TARGET_SHIELD;
1015 fire_alpha(fire_x, fire_y, LCD_WHITE);
1016 return;
1017 }
1018 }
1019 }
1020
1021 /* Check for hit*/
1022 for (i = FIRE_SPEED; i >= 0; i--) {
1023 pix = get_pixel(fire_x, fire_y + i);
1024 if(pix == screen_white) {
1025 hit_white = true;
1026 fire_y += i;
1027 break;
1028 }
1029 if(pix == screen_green) {
1030 hit_green = true;
1031 fire_y += i;
1032 break;
1033 }
1034 }
1035
1036 if (hit_green) {
1037 /* Hit shield */
1038
1039 /* TODO: Play explode sound */
1040
1041 fire = S_EXPLODE;
1042 fire_target = TARGET_SHIELD;
1043 /* Center explosion around hit pixel */
1044 fire_y -= FIRE_HEIGHT / 2;
1045 fire_alpha(fire_x, fire_y, SLIME_GREEN);
1046 return;
1047 }
1048
1049 if (hit_white) {
1050
1051 /* Hit alien? */
1052 for (i = 0; i < 5 * ALIENS; i++) {
1053 if (aliens[i].state != DEAD &&
1054 (ABS(fire_x - (PLAYFIELD_X + LIVES_X + aliens[i].x * ALIEN_SPEED +
1055 ALIEN_WIDTH / 2)) <= ALIEN_WIDTH / 2) &&
1056 (ABS(fire_y - (ALIEN_START_Y + aliens[i].y * ALIEN_HEIGHT +
1057 ALIEN_HEIGHT / 2)) <= ALIEN_HEIGHT / 2)) {
1058
1059 /* TODO: play alien hit sound */
1060
1061 if (aliens[i].state == BOMBER) {
1062 /* Set (possible) alien above to bomber */
1063 for (j = i - ALIENS; j >= 0; j -= ALIENS) {
1064 if (aliens[j].state != DEAD) {
1065 /* printf("New bomber (%d, %d)\n", j % ALIENS, j / ALIENS); */
1066 aliens[j].state = BOMBER;
1067 break;
1068 }
1069 }
1070 }
1071 aliens[i].state = DEAD;
1072 exploding_alien = i;
1073 score += scores[aliens[i].type];
1074 draw_score();
1075 /* Update score part of screen */
1076 rb->lcd_update_rect(SCORENUM_X, SCORENUM_Y,
1077 PLAYFIELD_WIDTH - 2 * NUMBERS_WIDTH, FONT_HEIGHT);
1078
1079 /* Paralyze aliens S_EXPLODE frames */
1080 aliens_paralyzed = S_EXPLODE;
1081 rb->lcd_bitmap_part(invadrox, ALIEN_EXPLODE_SRC_X, ALIEN_EXPLODE_SRC_Y,
1082 STRIDE, PLAYFIELD_X + LIVES_X + aliens[i].x * ALIEN_SPEED,
1083 ALIEN_START_Y + aliens[i].y * ALIEN_HEIGHT,
1084 ALIEN_EXPLODE_WIDTH, ALIEN_EXPLODE_HEIGHT);
1085 /* Since alien is 1 pixel taller than explosion sprite, erase bottom line */
1086 rb->lcd_hline(PLAYFIELD_X + LIVES_X + aliens[i].x * ALIEN_SPEED,
1087 PLAYFIELD_X + LIVES_X + aliens[i].x * ALIEN_SPEED + ALIEN_WIDTH,
1088 ALIEN_START_Y + (aliens[i].y + 1) * ALIEN_HEIGHT - 1);
1089 return;
1090 }
1091 }
1092 }
1093
1094 /* Draw shot */
1095 rb->lcd_set_foreground(LCD_WHITE);
1096 rb->lcd_vline(fire_x, fire_y, fire_y + SHOT_HEIGHT);
1097 rb->lcd_set_foreground(LCD_BLACK);
1098 } else if (fire < S_IDLE) {
1099 /* Count up towards S_IDLE, then erase explosion */
1100 fire++;
1101 if (fire == S_IDLE) {
1102 /* Erase explosion */
1103 if (fire_target == TARGET_TOP) {
1104 rb->lcd_fillrect(fire_x - (FIRE_WIDTH / 2), fire_y, FIRE_WIDTH, FIRE_HEIGHT);
1105 } else if (fire_target == TARGET_SHIELD) {
1106 /* Draw explosion with black pixels */
1107 fire_alpha(fire_x, fire_y, LCD_BLACK);
1108 }
1109 }
1110 }
1111}
1112
1113
1114/* Return a BOMBER alien */
1115inline int random_bomber(void)
1116{
1117 int i, col;
1118
1119 /* TODO: Weigh higher probability near ship */
1120 col = rb->rand() % ALIENS;
1121 for (i = col + 4 * ALIENS; i >= 0; i -= ALIENS) {
1122 if (aliens[i].state == BOMBER) {
1123 return i;
1124 }
1125 }
1126
1127 /* No BOMBER found in this col */
1128
1129 for (i = 0; i < 5 * ALIENS; i++) {
1130 if (aliens[i].state == BOMBER) {
1131 return i;
1132 }
1133 }
1134
1135 /* No BOMBER found at all (error?) */
1136
1137 return -1;
1138}
1139
1140
1141inline void draw_bomb(int i)
1142{
1143 rb->lcd_bitmap_part(invadrox, BOMB_SRC_X + bombs[i].type * BOMB_WIDTH,
1144 bombs[i].frame * (BOMB_HEIGHT + 1),
1145 STRIDE, bombs[i].x, bombs[i].y,
1146 BOMB_WIDTH, BOMB_HEIGHT);
1147 /* Advance frame */
1148 bombs[i].frame++;
1149 if (bombs[i].frame == bombs[i].frames) {
1150 bombs[i].frame = 0;
1151 }
1152}
1153
1154
1155void move_bombs(void)
1156{
1157 int i, j, bomber;
1158 bool abort;
1159
1160 for (i = 0; i < max_bombs; i++) {
1161
1162 switch (bombs[i].state) {
1163
1164 case S_IDLE:
1165 if (ship_hit) {
1166 continue;
1167 }
1168 bomber = random_bomber();
1169 if (bomber < 0) {
1170 DBG("ERROR: No bomber available\n");
1171 continue;
1172 }
1173 /* x, y */
1174 bombs[i].x = PLAYFIELD_X + LIVES_X + aliens[bomber].x * ALIEN_SPEED + ALIEN_WIDTH / 2;
1175 bombs[i].y = ALIEN_START_Y + (aliens[bomber].y + 1) * ALIEN_HEIGHT;
1176
1177 /* Check for duplets in x and y direction */
1178 abort = false;
1179 for (j = i - 1; j >= 0; j--) {
1180 if ((bombs[j].state == S_ACTIVE) &&
1181 ((bombs[i].x == bombs[j].x) || (bombs[i].y == bombs[j].y))) {
1182 abort = true;
1183 break;
1184 }
1185 }
1186 if (abort) {
1187 /* Skip this one, continue with next bomb */
1188 /* printf("Bomb %d duplet of %d\n", i, j); */
1189 continue;
1190 }
1191
1192 /* Passed, set type */
1193 bombs[i].type = rb->rand() % 3;
1194 bombs[i].frame = 0;
1195 if (bombs[i].type == 0) {
1196 bombs[i].frames = 3;
1197 } else if (bombs[i].type == 1) {
1198 bombs[i].frames = 4;
1199 } else {
1200 bombs[i].frames = 6;
1201 }
1202
1203 /* Bombs away */
1204 bombs[i].state = S_ACTIVE;
1205 draw_bomb(i);
1206 continue;
1207
1208 break;
1209
1210 case S_ACTIVE:
1211 /* Erase old position */
1212 rb->lcd_fillrect(bombs[i].x, bombs[i].y, BOMB_WIDTH, BOMB_HEIGHT);
1213
1214 /* Move */
1215 bombs[i].y += BOMB_SPEED;
1216
1217 /* Check if bottom hit */
1218 if (bombs[i].y + BOMB_HEIGHT >= PLAYFIELD_Y) {
1219 bombs[i].y = PLAYFIELD_Y - FIRE_HEIGHT + 1;
1220 fire_alpha(bombs[i].x, bombs[i].y, LCD_WHITE);
1221 bombs[i].state = S_EXPLODE;
1222 bombs[i].target = TARGET_BOTTOM;
1223 break;
1224 }
1225
1226 /* Check for green (ship or shield) */
1227 for (j = BOMB_HEIGHT; j >= BOMB_HEIGHT - BOMB_SPEED; j--) {
1228 bombs[i].target = 0;
1229 if(get_pixel(bombs[i].x + BOMB_WIDTH / 2, bombs[i].y + j) == screen_green) {
1230 /* Move to hit pixel */
1231 bombs[i].x += BOMB_WIDTH / 2;
1232 bombs[i].y += j;
1233
1234 /* Check if ship is hit */
1235 if (bombs[i].y > SHIELD_Y + SHIELD_HEIGHT && bombs[i].y < PLAYFIELD_Y) {
1236
1237 /* TODO: play ship hit sound */
1238
1239 ship_hit = true;
1240 ship_frame = 1;
1241 ship_frame_counter = 0;
1242 bombs[i].state = S_EXPLODE * 4;
1243 bombs[i].target = TARGET_SHIP;
1244 rb->lcd_bitmap_part(invadrox, SHIP_SRC_X, 1 * SHIP_HEIGHT, STRIDE,
1245 ship_x, SHIP_Y, SHIP_WIDTH, SHIP_HEIGHT);
1246 break;
1247 }
1248 /* Shield hit */
1249 bombs[i].state = S_EXPLODE;
1250 bombs[i].target = TARGET_SHIELD;
1251 /* Center explosion around hit pixel in shield */
1252 bombs[i].y -= FIRE_HEIGHT / 2;
1253 fire_alpha(bombs[i].x, bombs[i].y, SLIME_GREEN);
1254 break;
1255 }
1256 }
1257
1258 if (bombs[i].target != 0) {
1259 /* Hit ship or shield, continue */
1260 continue;
1261 }
1262
1263 draw_bomb(i);
1264 break;
1265
1266 default:
1267 /* If we get here state should be < 0, exploding */
1268 bombs[i].state++;
1269 if (bombs[i].state == S_IDLE) {
1270 if (ship_hit) {
1271 /* Erase explosion */
1272 rb->lcd_fillrect(ship_x, SHIP_Y, SHIP_WIDTH, SHIP_HEIGHT);
1273 rb->lcd_update_rect(ship_x, SHIP_Y, SHIP_WIDTH, SHIP_HEIGHT);
1274 ship_hit = false;
1275 ship_frame = 0;
1276 ship_x = PLAYFIELD_X + 2 * LIVES_X;
1277 lives--;
1278 if (lives == 0) {
1279 game_over = true;
1280 return;
1281 }
1282 draw_lives();
1283 /* Sleep 1s to give player time to examine lives left */
1284 rb->sleep(HZ);
1285 }
1286 /* Erase explosion (even if ship hit, might be another bomb) */
1287 fire_alpha(bombs[i].x, bombs[i].y, LCD_BLACK);
1288 }
1289 break;
1290 }
1291 }
1292}
1293
1294
1295inline void move_ship(void)
1296{
1297 ship_dir += ship_acc;
1298 if (ship_dir > max_ship_speed) {
1299 ship_dir = max_ship_speed;
1300 }
1301 if (ship_dir < -max_ship_speed) {
1302 ship_dir = -max_ship_speed;
1303 }
1304 ship_x += ship_dir;
1305 if (ship_x < SHIP_MIN_X) {
1306 ship_x = SHIP_MIN_X;
1307 }
1308 if (ship_x > SHIP_MAX_X) {
1309 ship_x = SHIP_MAX_X;
1310 }
1311
1312 draw_ship();
1313}
1314
1315
1316/* Unidentified Flying Object */
1317void move_ufo(void)
1318{
1319 static int ufo_speed;
1320 static int counter;
1321 int mystery_score;
1322
1323 switch (ufo_state) {
1324
1325 case S_IDLE:
1326
1327 if (rb->rand() % 500 == 0) {
1328 /* Uh-oh, it's time to launch a mystery UFO */
1329
1330 /* TODO: Play UFO sound */
1331
1332 if (rb->rand() % 2) {
1333 ufo_speed = UFO_SPEED;
1334 ufo_x = PLAYFIELD_X;
1335 } else {
1336 ufo_speed = -UFO_SPEED;
1337 ufo_x = LCD_WIDTH - PLAYFIELD_X - UFO_WIDTH;
1338 }
1339 ufo_state = S_ACTIVE;
1340 /* UFO will be drawn next frame */
1341 }
1342 break;
1343
1344 case S_ACTIVE:
1345 /* Erase old pos */
1346 rb->lcd_fillrect(ufo_x, UFO_Y, UFO_WIDTH, UFO_HEIGHT);
1347 /* Move */
1348 ufo_x += ufo_speed;
1349 /* Check bounds */
1350 if (ufo_x < PLAYFIELD_X || ufo_x > LCD_WIDTH - PLAYFIELD_X - UFO_WIDTH) {
1351 ufo_state = S_IDLE;
1352 break;
1353 }
1354 /* Draw new pos */
1355 rb->lcd_bitmap_part(invadrox, UFO_SRC_X, 0,
1356 STRIDE, ufo_x, UFO_Y, UFO_WIDTH, UFO_HEIGHT);
1357 break;
1358
1359 case S_SHOWSCORE:
1360 counter++;
1361 if (counter == S_IDLE) {
1362 /* Erase mystery number */
1363 rb->lcd_fillrect(ufo_x, UFO_Y, 3 * NUMBERS_WIDTH + 2 * NUM_SPACING, FONT_HEIGHT);
1364 ufo_state = S_IDLE;
1365 }
1366 break;
1367
1368 default:
1369 /* Exploding */
1370 ufo_state++;
1371 if (ufo_state == S_IDLE) {
1372 /* Erase explosion */
1373 rb->lcd_fillrect(ufo_x, UFO_Y - 1, UFO_EXPLODE_WIDTH, UFO_EXPLODE_HEIGHT);
1374 ufo_state = S_SHOWSCORE;
1375 counter = S_EXPLODE * 4;
1376 /* Draw mystery_score, sleep, increase score and continue */
1377 mystery_score = 50 + (rb->rand() % 6) * 50;
1378 if (mystery_score < 100) {
1379 draw_number(ufo_x, UFO_Y, mystery_score, 2);
1380 } else {
1381 draw_number(ufo_x, UFO_Y, mystery_score, 3);
1382 }
1383 score += mystery_score;
1384 draw_score();
1385 }
1386 break;
1387 }
1388}
1389
1390
1391void draw_background(void)
1392{
1393
1394#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
1395 /* Erase background to black */
1396 rb->lcd_fillrect(PLAYFIELD_X, 0, PLAYFIELD_WIDTH, LCD_HEIGHT);
1397 /* Left and right bitmaps */
1398 rb->lcd_bitmap(invadrox_left, 0, 0, PLAYFIELD_X, LCD_HEIGHT);
1399 rb->lcd_bitmap(invadrox_right, LCD_WIDTH - PLAYFIELD_X, 0, PLAYFIELD_X, LCD_HEIGHT);
1400#else
1401 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1402#endif
1403
1404#if ((LCD_WIDTH == 240) && (LCD_HEIGHT == 320)) || ((LCD_WIDTH == 176) && (LCD_HEIGHT == 220))
1405 rb->lcd_bitmap(invadrox_logo, 0, 0, LCD_WIDTH, SCORE_Y);
1406#endif
1407
1408 rb->lcd_update();
1409}
1410
1411
1412void new_level(void)
1413{
1414 int i;
1415
1416 draw_background();
1417 /* Give an extra life for each new level */
1418 if (lives < MAX_LIVES) {
1419 lives++;
1420 }
1421 draw_lives();
1422
1423 /* Score */
1424 rb->lcd_bitmap_part(invadrox, SCORE_SRC_X, SCORE_SRC_Y,
1425 STRIDE, PLAYFIELD_X, SCORE_Y, SCORE_WIDTH, FONT_HEIGHT);
1426 /* Hi-score */
1427 rb->lcd_bitmap_part(invadrox, 0, SCORE_SRC_Y,
1428 STRIDE, HISCORE_X, SCORE_Y,
1429 HISCORE_WIDTH, FONT_HEIGHT);
1430 draw_score();
1431 draw_number(HISCORENUM_X, SCORENUM_Y, hiscore.score, 4);
1432
1433 level++;
1434 draw_level();
1435 level_finished = false;
1436
1437 ufo_state = S_IDLE;
1438
1439 /* Init alien positions and states */
1440 for (i = 0; i < 4 * ALIENS; i++) {
1441 aliens[i].x = 0 + (i % ALIENS) * ((ALIEN_WIDTH + ALIEN_SPACING) / ALIEN_SPEED);
1442 aliens[i].y = 2 * (i / ALIENS);
1443 aliens[i].state = ALIVE;
1444 }
1445 /* Last row, bombers */
1446 for (i = 4 * ALIENS; i < 5 * ALIENS; i++) {
1447 aliens[i].x = 0 + (i % ALIENS) * ((ALIEN_WIDTH + ALIEN_SPACING) / ALIEN_SPEED);
1448 aliens[i].y = 2 * (i / ALIENS);
1449 aliens[i].state = BOMBER;
1450 }
1451
1452 /* Init bombs to inactive (S_IDLE) */
1453 for (i = 0; i < MAX_BOMBS; i++) {
1454 bombs[i].state = S_IDLE;
1455 }
1456
1457 /* Start aliens closer to earth from level 2 */
1458 for (i = 0; i < 5 * ALIENS; i++) {
1459 if (level < 6) {
1460 aliens[i].y += level - 1;
1461 } else {
1462 aliens[i].y += 5;
1463 }
1464 }
1465
1466 /* Max concurrent bombs */
1467 max_bombs = 1;
1468
1469 gamespeed = 2;
1470
1471 if (level > 1) {
1472 max_bombs++;
1473 }
1474
1475 /* Increase speed */
1476 if (level > 2) {
1477 gamespeed++;
1478 }
1479
1480 if (level > 3) {
1481 max_bombs++;
1482 }
1483
1484 /* Increase speed more */
1485 if (level > 4) {
1486 gamespeed++;
1487 }
1488
1489 if (level > 5) {
1490 max_bombs++;
1491 }
1492
1493 /* 4 shields */
1494 for (i = 1; i <= 4; i++) {
1495 rb->lcd_bitmap_part(invadrox, SHIELD_SRC_X, SHIELD_SRC_Y, STRIDE,
1496 PLAYFIELD_X + i * PLAYFIELD_WIDTH / 5 - SHIELD_WIDTH / 2,
1497 SHIELD_Y, SHIELD_WIDTH, SHIELD_HEIGHT);
1498 }
1499
1500 /* Bottom line */
1501 rb->lcd_set_foreground(SLIME_GREEN);
1502 rb->lcd_hline(PLAYFIELD_X, LCD_WIDTH - PLAYFIELD_X, PLAYFIELD_Y);
1503 /* Restore foreground to black (for fast erase later). */
1504 rb->lcd_set_foreground(LCD_BLACK);
1505
1506 ship_x = PLAYFIELD_X + 2 * LIVES_X;
1507 if (level == 1) {
1508 old_ship_x = ship_x;
1509 }
1510 ship_dir = 0;
1511 ship_acc = 0;
1512 ship_frame = 0;
1513 ship_hit = false;
1514 fire = S_IDLE;
1515 /* Start moving the bottom row left to right */
1516 curr_alien = 4 * ALIENS;
1517 aliens_paralyzed = 0;
1518 aliens_right = true;
1519 aliens_down = false;
1520 hit_left_border = false;
1521 hit_right_border = false;
1522 /* TODO: Change max_ship_speed to 3 at higher levels */
1523 max_ship_speed = 2;
1524
1525 draw_aliens();
1526
1527 rb->lcd_update();
1528}
1529
1530
1531void init_invadrox(void)
1532{
1533 int i;
1534
1535 /* Seed random number generator with a "random" number */
1536 rb->srand(rb->get_time()->tm_sec + rb->get_time()->tm_min * 60);
1537
1538 /* Precalculate start of each scanline */
1539 for (i = 0; i < LCD_HEIGHT; i++) {
1540#if (LCD_DEPTH >= 8)
1541 ytab[i] = i * LCD_WIDTH;
1542#elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == HORIZONTAL_PACKING)
1543 ytab[i] = i * (LCD_WIDTH / 4);
1544#elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
1545 ytab[i] = (i / 4) * LCD_WIDTH;
1546#else
1547 #error pixelformat not implemented yet
1548#endif
1549 }
1550
1551 rb->lcd_set_background(LCD_BLACK);
1552 rb->lcd_set_foreground(LCD_BLACK);
1553
1554 highscore_init(rb);
1555 if (highscore_load(HISCOREFILE, &hiscore, 1) < 0) {
1556 /* Init hiscore to 0 */
1557 rb->strncpy(hiscore.name, "Invader", sizeof(hiscore.name));
1558 hiscore.score = 0;
1559 hiscore.level = 1;
1560 }
1561
1562 /* Init alien types in aliens array */
1563 for (i = 0; i < 1 * ALIENS; i++) {
1564 aliens[i].type = 0; /* Kang */
1565 }
1566 for (; i < 3 * ALIENS; i++) {
1567 aliens[i].type = 1; /* Kodos */
1568 }
1569 for (; i < 5 * ALIENS; i++) {
1570 aliens[i].type = 2; /* Serak */
1571 }
1572
1573
1574 /* Save screen white color */
1575 rb->lcd_set_foreground(LCD_WHITE);
1576 rb->lcd_drawpixel(0, 0);
1577 rb->lcd_update_rect(0, 0, 1, 1);
1578 screen_white = get_pixel(0, 0);
1579
1580 /* Save screen green color */
1581 rb->lcd_set_foreground(SLIME_GREEN);
1582 rb->lcd_drawpixel(0, 0);
1583 rb->lcd_update_rect(0, 0, 1, 1);
1584 screen_green = get_pixel(0, 0);
1585
1586 /* Restore black foreground */
1587 rb->lcd_set_foreground(LCD_BLACK);
1588
1589 new_level();
1590
1591 /* Flash score at start */
1592 for (i = 0; i < 5; i++) {
1593 rb->lcd_fillrect(SCORENUM_X, SCORENUM_Y,
1594 4 * NUMBERS_WIDTH + 3 * NUM_SPACING,
1595 FONT_HEIGHT);
1596 rb->lcd_update_rect(SCORENUM_X, SCORENUM_Y,
1597 4 * NUMBERS_WIDTH + 3 * NUM_SPACING,
1598 FONT_HEIGHT);
1599 rb->sleep(HZ / 10);
1600 draw_number(SCORENUM_X, SCORENUM_Y, score, 4);
1601 rb->sleep(HZ / 10);
1602 }
1603}
1604
1605
1606inline bool handle_buttons(void)
1607{
1608 static unsigned int oldbuttonstate IDATA_ATTR = 0;
1609
1610 unsigned int released, pressed, newbuttonstate;
1611
1612 if (ship_hit) {
1613 /* Don't allow ship movement during explosion */
1614 newbuttonstate = 0;
1615 } else {
1616 newbuttonstate = rb->button_status();
1617 }
1618 if(newbuttonstate == oldbuttonstate) {
1619 if (newbuttonstate == 0) {
1620 /* No button pressed. Stop ship. */
1621 ship_acc = 0;
1622 if (ship_dir > 0) {
1623 ship_dir--;
1624 }
1625 if (ship_dir < 0) {
1626 ship_dir++;
1627 }
1628 }
1629 /* return false; */
1630 goto check_usb;
1631 }
1632 released = ~newbuttonstate & oldbuttonstate;
1633 pressed = newbuttonstate & ~oldbuttonstate;
1634 oldbuttonstate = newbuttonstate;
1635 if (pressed) {
1636 if (pressed & LEFT) {
1637 if (ship_acc > -1) {
1638 ship_acc--;
1639 }
1640 }
1641 if (pressed & RIGHT) {
1642 if (ship_acc < 1) {
1643 ship_acc++;
1644 }
1645 }
1646 if (pressed & FIRE) {
1647 if (fire == S_IDLE) {
1648 /* Fire shot */
1649 fire_x = ship_x + SHIP_WIDTH / 2;
1650 fire_y = SHIP_Y - SHOT_HEIGHT;
1651 fire = S_ACTIVE;
1652 /* TODO: play fire sound */
1653 }
1654 }
1655#ifdef RC_QUIT
1656 if (pressed & RC_QUIT) {
1657 rb->splash(HZ * 1, true, "Quit");
1658 return true;
1659 }
1660#endif
1661 if (pressed & QUIT) {
1662 rb->splash(HZ * 1, true, "Quit");
1663 return true;
1664 }
1665 }
1666 if (released) {
1667 if ((released & LEFT)) {
1668 if (ship_acc < 1) {
1669 ship_acc++;
1670 }
1671 }
1672 if ((released & RIGHT)) {
1673 if (ship_acc > -1) {
1674 ship_acc--;
1675 }
1676 }
1677 }
1678
1679check_usb:
1680
1681 /* Quit if USB is connected */
1682 if (rb->button_get(false) == SYS_USB_CONNECTED) {
1683 return true;
1684 }
1685
1686 return false;
1687}
1688
1689
1690void game_loop(void)
1691{
1692 int i, end;
1693
1694 /* Print dimensions (just for debugging) */
1695 DBG("%03dx%03dx%02d\n", LCD_WIDTH, LCD_HEIGHT, LCD_DEPTH);
1696
1697 /* Init */
1698 init_invadrox();
1699
1700 while (1) {
1701 /* Convert CYCLETIME (in ms) to HZ */
1702 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1703
1704 if (handle_buttons()) {
1705 return;
1706 }
1707
1708 /* Animate */
1709 move_ship();
1710 move_fire();
1711
1712 /* Check if level is finished (marked by move_fire) */
1713 if (level_finished) {
1714 /* TODO: Play level finished sound */
1715 new_level();
1716 }
1717
1718 move_ufo();
1719
1720 /* Move aliens */
1721 if (!aliens_paralyzed && !ship_hit) {
1722 for (i = 0; i < gamespeed; i++) {
1723 if (!move_aliens()) {
1724 if (game_over) {
1725 return;
1726 }
1727 }
1728 }
1729 }
1730
1731 /* Move alien bombs */
1732 move_bombs();
1733 if (game_over) {
1734 return;
1735 }
1736
1737 /* Update "playfield" rect */
1738 rb->lcd_update_rect(PLAYFIELD_X, SCORENUM_Y + FONT_HEIGHT,
1739 PLAYFIELD_WIDTH,
1740 PLAYFIELD_Y + 1 - SCORENUM_Y - FONT_HEIGHT);
1741
1742 /* Wait until next frame */
1743 DBG("%d (%d)\n", end - *rb->current_tick, (CYCLETIME * HZ) / 1000);
1744 if (end > *rb->current_tick) {
1745 rb->sleep(end - *rb->current_tick);
1746 } else {
1747 rb->yield();
1748 }
1749
1750 } /* end while */
1751}
1752
1753
1754/* this is the plugin entry point */
1755enum plugin_status plugin_start(struct plugin_api* api, UNUSED void* parameter)
1756{
1757 rb = api;
1758
1759 rb->lcd_setfont(FONT_SYSFIXED);
1760 /* Permanently enable the backlight (unless the user has turned it off) */
1761 if (rb->global_settings->backlight_timeout > 0)
1762 rb->backlight_set_timeout(1);
1763
1764 /* now go ahead and have fun! */
1765 game_loop();
1766
1767 /* Game Over. */
1768 /* TODO: Play game over sound */
1769 rb->splash(HZ * 2, true, "Game Over");
1770 if (score > hiscore.score) {
1771 /* Save new hiscore */
1772 hiscore.score = score;
1773 hiscore.level = level;
1774 highscore_save(HISCOREFILE, &hiscore, 1);
1775 }
1776
1777 /* Restore user's original backlight setting */
1778 rb->lcd_setfont(FONT_UI);
1779 rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
1780
1781 return PLUGIN_OK;
1782}
1783
1784
1785
1786/**
1787 * GNU Emacs settings: Kernighan & Richie coding style with
1788 * 4 spaces indent and no tabs.
1789 * Local Variables:
1790 * c-file-style: "k&r"
1791 * c-basic-offset: 4
1792 * indent-tabs-mode: nil
1793 * End:
1794 */
diff --git a/docs/CREDITS b/docs/CREDITS
index d40e975988..63fa653575 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -267,3 +267,4 @@ Gary Allen
267John BouAntoun 267John BouAntoun
268Tomasz Mon 268Tomasz Mon
269Jakub Matoušek 269Jakub Matoušek
270Albert Veli