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