summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2007-02-16 01:23:48 +0000
committerDave Chapman <dave@dchapman.com>2007-02-16 01:23:48 +0000
commite3e58b9a07a61c8da31e44a04954d43194448090 (patch)
tree1a0f7d05976dc13ec8b01f2d31bc69f019df4f8a /apps/plugins
parent1ea4f0d4eb6a1252c4319ef362eff90c416d51d5 (diff)
downloadrockbox-e3e58b9a07a61c8da31e44a04954d43194448090.tar.gz
rockbox-e3e58b9a07a61c8da31e44a04954d43194448090.zip
FS #5535 - Chopper game ported from IPL by Ben Basha. This commit is chopper_with_menu_api.diff with some changes by me: fixed the bug with the unmatching calls to menu_init() and menu_quit() (causing freezes after game #6); added keymappings for the sansa, gigabeat, Ondio and Archos Recorders; and changes to work with mono LCDs. This should now run on all targets with bitmapped LCDs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12326 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/chopper.c945
2 files changed, 946 insertions, 0 deletions
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index ec06f38eb3..56f845a6dd 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -57,6 +57,7 @@ brickmania.c
57#endif 57#endif
58calculator.c 58calculator.c
59chip8.c 59chip8.c
60chopper.c
60demystify.c 61demystify.c
61jewels.c 62jewels.c
62minesweeper.c 63minesweeper.c
diff --git a/apps/plugins/chopper.c b/apps/plugins/chopper.c
new file mode 100644
index 0000000000..5c52c91466
--- /dev/null
+++ b/apps/plugins/chopper.c
@@ -0,0 +1,945 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Originally by Joshua Oreman, improved by Prashant Varanasi
11 * Ported to Rockbox by Ben Basha (Paprica)
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21#include "plugin.h"
22#include "xlcd.h"
23#include "configfile.h"
24
25PLUGIN_HEADER
26
27/*Still To do:*/
28/* - Make original speed and further increases in speed depend more on screen size*/
29/* - attempt to make the tunnels get narrower as the game goes on*/
30/* - make the chopper look better, maybe a picture, and scale according to screen size*/
31/* - use textures for the color screens for background and terrain, eg stars on background*/
32/* - allow choice of different levels [later: different screen themes]*/
33/* - better high score handling, improved screen etc. */
34
35#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
36
37#define QUIT BUTTON_OFF
38#define ACTION BUTTON_UP
39#define ACTION2 BUTTON_SELECT
40
41#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \
42 (CONFIG_KEYPAD == IPOD_4G_PAD)
43
44#define QUIT BUTTON_MENU
45#define ACTION BUTTON_SELECT
46
47#elif CONFIG_KEYPAD == IAUDIO_X5_PAD /* grayscale at the moment */
48
49#define QUIT BUTTON_POWER
50#define ACTION BUTTON_SELECT
51
52#elif CONFIG_KEYPAD == IRIVER_H10_PAD
53#define QUIT BUTTON_POWER
54#define ACTION BUTTON_RIGHT
55
56#elif CONFIG_KEYPAD == SANSA_E200_PAD
57#define QUIT BUTTON_POWER
58#define ACTION BUTTON_SELECT
59
60#elif CONFIG_KEYPAD == GIGABEAT_PAD
61#define QUIT BUTTON_MENU
62#define ACTION BUTTON_SELECT
63
64#elif CONFIG_KEYPAD == RECORDER_PAD
65#define QUIT BUTTON_OFF
66#define ACTION BUTTON_PLAY
67
68#elif CONFIG_KEYPAD == ONDIO_PAD
69#define QUIT BUTTON_MENU
70#define ACTION BUTTON_RIGHT
71
72#else
73#error Unsupported keypad
74#endif
75
76static struct plugin_api* rb;
77
78#define NUMBER_OF_BLOCKS 8
79#define NUMBER_OF_PARTICLES 3
80#define MAX_TERRAIN_NODES 15
81
82#define LEVEL_MODE_NORMAL 0
83#define LEVEL_MODE_STEEP 1
84
85#define CYCLETIME 60
86
87/*Chopper's local variables to track the terrain position etc*/
88static int chopCounter;
89static int iRotorOffset;
90static int iScreenX;
91static int iScreenY;
92static int iPlayerPosX;
93static int iPlayerPosY;
94static int iCameraPosX;
95static int iPlayerSpeedX;
96static int iPlayerSpeedY;
97static int iLastBlockPlacedPosX;
98static int iGravityTimerCountdown;
99static int iPlayerAlive;
100static int iLevelMode;
101static int blockh,blockw;
102static int highscore;
103static int score;
104
105#define CFG_FILE "chopper.cfg"
106#define MAX_POINTS 50000
107static struct configdata config[] =
108{
109 {TYPE_INT, 0, MAX_POINTS, &highscore, "highscore", NULL, NULL}
110};
111
112struct CBlock
113{
114 int iWorldX;
115 int iWorldY;
116
117 int iSizeX;
118 int iSizeY;
119
120 int bIsActive;
121};
122
123struct CParticle
124{
125 int iWorldX;
126 int iWorldY;
127
128 int iSpeedX;
129 int iSpeedY;
130
131 int bIsActive;
132};
133
134struct CTerrainNode
135{
136 int x;
137 int y;
138};
139
140struct CTerrain
141{
142 struct CTerrainNode mNodes[MAX_TERRAIN_NODES];
143 int iNodesCount;
144 int iLastNodePlacedPosX;
145};
146
147struct CBlock mBlocks[NUMBER_OF_BLOCKS];
148struct CParticle mParticles[NUMBER_OF_PARTICLES];
149
150struct CTerrain mGround;
151struct CTerrain mRoof;
152
153/*Function declarations*/
154static void chopDrawParticle(struct CParticle *mParticle);
155static void chopDrawBlock(struct CBlock *mBlock);
156static void chopRenderTerrain(struct CTerrain *ter);
157void chopper_load(bool newgame);
158void cleanup_chopper(void);
159
160
161static void chopDrawPlayer(int x,int y) /* These are SCREEN coords, not world! */
162{
163
164#if LCD_DEPTH > 2
165 rb->lcd_set_foreground(LCD_RGBPACK(50,50,200));
166#elif LCD_DEPTH == 2
167 rb->lcd_set_foreground(LCD_DARKGRAY);
168#endif
169 rb->lcd_fillrect(x+6, y+2, 12, 9);
170 rb->lcd_fillrect(x-3, y+6, 20, 3);
171
172#if LCD_DEPTH > 2
173 rb->lcd_set_foreground(LCD_RGBPACK(50,50,50));
174#elif LCD_DEPTH == 2
175 rb->lcd_set_foreground(LCD_DARKGRAY);
176#endif
177 rb->lcd_fillrect(x+10, y, 2, 3);
178 rb->lcd_fillrect(x+10, y, 1, 3);
179
180#if LCD_DEPTH > 2
181 rb->lcd_set_foreground(LCD_RGBPACK(30,30,30));
182#elif LCD_DEPTH == 2
183 rb->lcd_set_foreground(LCD_BLACK);
184#endif
185 rb->lcd_drawline(x, y+iRotorOffset, x+20, y-iRotorOffset);
186
187#if LCD_DEPTH > 2
188 rb->lcd_set_foreground(LCD_RGBPACK(10,10,10));
189#elif LCD_DEPTH == 2
190 rb->lcd_set_foreground(LCD_BLACK);
191#endif
192 rb->lcd_fillrect(x - 2, y + 5, 2, 5);
193
194}
195
196
197
198static void chopClearTerrain(struct CTerrain *ter)
199{
200 ter->iNodesCount = -1;
201}
202
203
204int iR(int low,int high)
205{
206 return low+rb->rand()%(high-low+1);
207}
208
209
210static void chopCopyTerrain(struct CTerrain *src, struct CTerrain *dest,
211 int xOffset,int yOffset)
212{
213 int i=0;
214
215 while(i < src->iNodesCount)
216 {
217 dest->mNodes[i].x = src->mNodes[i].x + xOffset;
218 dest->mNodes[i].y = src->mNodes[i].y + yOffset;
219
220 i++;
221 }
222
223 dest->iNodesCount = src->iNodesCount;
224 dest->iLastNodePlacedPosX = src->iLastNodePlacedPosX;
225
226}
227
228
229static void chopAddTerrainNode(struct CTerrain *ter, int x, int y)
230{
231 int i=0;
232
233 if(ter->iNodesCount + 1 >= MAX_TERRAIN_NODES)
234 {
235 /* DEBUGF("ERROR: Not enough nodes!\n"); */
236 return;
237 }
238
239 ter->iNodesCount++;
240
241 i = ter->iNodesCount - 1;
242
243 ter->mNodes[i].x = x;
244 ter->mNodes[i].y= y;
245
246 ter->iLastNodePlacedPosX = x;
247
248}
249
250
251static void chopTerrainNodeDeleteAndShift(struct CTerrain *ter,int nodeIndex)
252{
253 int i=nodeIndex;
254
255 while( i < ter->iNodesCount )
256 {
257 ter->mNodes[i - 1] = ter->mNodes[i];
258 i++;
259 }
260
261 ter->iNodesCount--;
262
263
264}
265
266int chopUpdateTerrainRecycling(struct CTerrain *ter)
267{
268 int i=1;
269 int ret = 0;
270 int iNewNodePos,g,v;
271 while(i < ter->iNodesCount)
272 {
273
274 if( iCameraPosX > ter->mNodes[i].x)
275 {
276
277 chopTerrainNodeDeleteAndShift(ter,i);
278
279 iNewNodePos = ter->iLastNodePlacedPosX + 50;
280 g = iScreenY - 10;
281
282 v = 3*iPlayerSpeedX;
283 if(v>50)
284 v=50;
285 if(iLevelMode == LEVEL_MODE_STEEP)
286 v*=5;
287
288 chopAddTerrainNode(ter,iNewNodePos,g - iR(-v,v));
289 ret=1;
290
291 }
292
293 i++;
294
295 }
296
297 return 1;
298}
299
300int chopTerrainHeightAtPoint(struct CTerrain *ter, int pX)
301{
302
303 int iNodeIndexOne=0,iNodeIndexTwo=0, h, terY1, terY2, terX1, terX2, a, b;
304 float c,d;
305
306 int i=0;
307 for(i=1;i<MAX_TERRAIN_NODES;i++)
308 {
309 if(ter->mNodes[i].x > pX)
310 {
311 iNodeIndexOne = i - 1;
312 break;
313 }
314
315 }
316
317 iNodeIndexTwo = iNodeIndexOne + 1;
318 terY1 = ter->mNodes[iNodeIndexOne].y;
319 terY2 = ter->mNodes[iNodeIndexTwo].y;
320
321 terX1 = 0;
322 terX2 = ter->mNodes[iNodeIndexTwo].x - ter->mNodes[iNodeIndexOne].x;
323
324 pX-= ter->mNodes[iNodeIndexOne].x;
325
326 a = terY2 - terY1;
327 b = terX2;
328 c = pX;
329 d = (c/b) * a;
330
331 h = d + terY1;
332
333 return h;
334
335}
336
337
338int chopPointInTerrain(struct CTerrain *ter, int pX, int pY, int iTestType)
339{
340 int h = chopTerrainHeightAtPoint(ter, pX);
341
342 if(iTestType == 0)
343 return (pY > h);
344 else
345 return (pY < h);
346}
347
348
349static void chopAddBlock(int x,int y,int sx,int sy, int indexOverride)
350{
351 int i=0;
352
353 if(indexOverride < 0)
354 {
355 while(mBlocks[i].bIsActive && i < NUMBER_OF_BLOCKS)
356 i++;
357 if(i==NUMBER_OF_BLOCKS)
358 {
359 DEBUGF("No blocks!\n");
360 return;
361 }
362 }
363 else
364 i = indexOverride;
365
366 mBlocks[i].bIsActive = 1;
367 mBlocks[i].iWorldX = x;
368 mBlocks[i].iWorldY = y;
369 mBlocks[i].iSizeX = sx;
370 mBlocks[i].iSizeY = sy;
371
372 iLastBlockPlacedPosX = x;
373}
374
375static void chopAddParticle(int x,int y,int sx,int sy)
376{
377 int i=0;
378
379 while(mParticles[i].bIsActive && i < NUMBER_OF_PARTICLES)
380 i++;
381
382 if(i==NUMBER_OF_BLOCKS)
383 return;
384
385 mParticles[i].bIsActive = 1;
386 mParticles[i].iWorldX = x;
387 mParticles[i].iWorldY = y;
388 mParticles[i].iSpeedX = sx;
389 mParticles[i].iSpeedY = sy;
390
391}
392
393static void chopGenerateBlockIfNeeded(void)
394{
395 int i=0;
396 int DistSpeedX = iPlayerSpeedX * 5;
397 if(DistSpeedX<200) DistSpeedX = 200;
398
399 while(i < NUMBER_OF_BLOCKS)
400 {
401 if(!mBlocks[i].bIsActive)
402 {
403 int iX,iY,sX,sY;
404
405 iX = iLastBlockPlacedPosX + (350-DistSpeedX);
406 sX = blockw;
407
408 iY = iR(0,iScreenY);
409 sY = blockh + iR(1,blockh/3);
410
411 chopAddBlock(iX,iY,sX,sY,i);
412 }
413
414 i++;
415 }
416
417}
418
419static int chopBlockCollideWithPlayer(struct CBlock *mBlock)
420{
421 int px = iPlayerPosX;
422 int py = iPlayerPosY;
423
424 int x = mBlock->iWorldX-17;
425 int y = mBlock->iWorldY-11;
426
427 int x2 = x + mBlock->iSizeX+17;
428 int y2 = y + mBlock->iSizeY+11;
429
430 if(px>x && px<x2)
431 {
432 if(py>y && py<y2)
433 {
434 return 1;
435 }
436 }
437
438 return 0;
439}
440
441static int chopBlockOffscreen(struct CBlock *mBlock)
442{
443 if(mBlock->iWorldX + mBlock->iSizeX < iCameraPosX)
444 return 1;
445 else
446 return 0;
447}
448
449static int chopParticleOffscreen(struct CParticle *mParticle)
450{
451 if (mParticle->iWorldX < iCameraPosX || mParticle->iWorldY < 0 ||
452 mParticle->iWorldY > iScreenY || mParticle->iWorldX > iCameraPosX +
453 iScreenX)
454 {
455 return 1;
456 }
457 else
458 return 0;
459}
460
461static void checkHighScore(void)
462{
463 if (score > highscore) {
464 char scoretext[30];
465 int w;
466 highscore = score;
467 rb->snprintf(scoretext, sizeof(scoretext), "New High Score: %d",
468 highscore);
469 rb->lcd_getstringsize(scoretext, &w, NULL);
470 rb->lcd_putsxy(LCD_WIDTH/2 - w/2 ,LCD_HEIGHT/2 + 20, scoretext);
471 }
472}
473
474static void chopKillPlayer(void)
475{
476 int w, i, button;
477 for (i = 0; i < NUMBER_OF_PARTICLES; i++) {
478 mParticles[i].bIsActive = 0;
479 chopAddParticle(iPlayerPosX + iR(0,20), iPlayerPosY + iR(0,20),
480 iR(-2,2), iR(-2,2));
481 }
482
483 iPlayerAlive--;
484
485 if (iPlayerAlive == 0) {
486 rb->lcd_set_drawmode(DRMODE_FG);
487#if LCD_DEPTH >= 2
488 rb->lcd_set_foreground(LCD_BLACK);
489#endif
490 checkHighScore();
491
492 rb->lcd_getstringsize("Game Over", &w, NULL);
493 rb->lcd_putsxy(LCD_WIDTH/2 - w/2 ,LCD_HEIGHT/2 - 20, "Game Over");
494 rb->lcd_getstringsize("Press action to continue", &w, NULL);
495 rb->lcd_putsxy(LCD_WIDTH/2 - w/2 ,LCD_HEIGHT/2,
496 "Press action to continue");
497 rb->lcd_update();
498
499 rb->lcd_set_drawmode(DRMODE_SOLID);
500
501 rb->sleep(HZ * 0.5);
502
503 while (true) {
504 button = rb->button_get(true);
505 if (button == ACTION
506#ifdef ACTION2
507 || button == ACTION2
508#endif
509 ) {
510 while (true) {
511 button = rb->button_get(true);
512 if (button == (ACTION | BUTTON_REL)
513#ifdef ACTION2
514 || button == (ACTION2 | BUTTON_REL)
515#endif
516 ) {
517 chopper_load(true);
518 return;
519 }
520 }
521 }
522 }
523
524 } else
525 chopper_load(false);
526
527}
528
529
530static void chopDrawTheWorld(void)
531{
532 int i=0;
533
534 while(i < NUMBER_OF_BLOCKS)
535 {
536 if(mBlocks[i].bIsActive)
537 {
538 if(chopBlockOffscreen(&mBlocks[i]) == 1)
539 mBlocks[i].bIsActive = 0;
540 else
541 chopDrawBlock(&mBlocks[i]);
542 }
543
544 i++;
545 }
546
547 i=0;
548
549 while(i < NUMBER_OF_PARTICLES)
550 {
551 if(mParticles[i].bIsActive)
552 {
553 if(chopParticleOffscreen(&mParticles[i]) == 1)
554 mParticles[i].bIsActive = 0;
555 else
556 chopDrawParticle(&mParticles[i]);
557 }
558
559 i++;
560 }
561
562 chopRenderTerrain(&mGround);
563 chopRenderTerrain(&mRoof);
564
565}
566
567
568static void chopDrawParticle(struct CParticle *mParticle)
569{
570
571 int iPosX = (mParticle->iWorldX - iCameraPosX);
572 int iPosY = (mParticle->iWorldY);
573#if LCD_DEPTH > 2
574 rb->lcd_set_foreground(LCD_RGBPACK(150,150,150));
575#elif LCD_DEPTH == 2
576 rb->lcd_set_foreground(LCD_LIGHTGRAY);
577#endif
578 rb->lcd_fillrect(iPosX, iPosY, 3, 3);
579
580}
581
582static void chopDrawScene(void)
583{
584 char s[30];
585 int w;
586#if LCD_DEPTH > 2
587 rb->lcd_set_background(LCD_RGBPACK(145,197,255));
588#elif LCD_DEPTH == 2
589 rb->lcd_set_background(LCD_WHITE);
590#endif
591 rb->lcd_clear_display();
592
593 chopDrawTheWorld();
594 chopDrawPlayer(iPlayerPosX - iCameraPosX, iPlayerPosY);
595
596 score = -20 + iPlayerPosX/3;
597 rb->lcd_set_drawmode(DRMODE_FG);
598#if LCD_DEPTH > 2
599 rb->lcd_set_foreground(LCD_RGBPACK(20,20,20));
600#elif LCD_DEPTH == 2
601 rb->lcd_set_foreground(LCD_WHITE);
602#endif
603 rb->snprintf(s, sizeof(s), "Distance: %d", score);
604 rb->lcd_putsxy(2, 2, s);
605 rb->snprintf(s, sizeof(s), "Best: %d", highscore);
606 rb->lcd_getstringsize(s, &w, NULL);
607 rb->lcd_putsxy(LCD_WIDTH - 2 - w, 2, s);
608 rb->lcd_set_drawmode(DRMODE_SOLID);
609
610 rb->lcd_update();
611}
612
613static int chopMenu(int menunum)
614{
615 int m;
616 int result;
617 int res = 0;
618 bool menu_quit = false;
619
620 static const struct menu_item items[] = {
621 { "Start New Game", NULL },
622 { "Resume Game", NULL },
623 { "Level", NULL },
624 { "Help", NULL },
625 { "Quit", NULL },
626 };
627
628 static const struct opt_items levels[2] = {
629 { "Normal", -1 },
630 { "Steep", -1 },
631 };
632
633 m = rb->menu_init(items, sizeof(items) / sizeof(*items),
634 NULL, NULL, NULL, NULL);
635
636 while (!menu_quit) {
637 result=rb->menu_show(m);
638 switch (result)
639 {
640 case 0: /* Start New Game */
641 menu_quit=true;
642 chopper_load(true);
643 res = -1;
644 break;
645 case 1: /* Resume Game */
646 if(menunum==1) {
647 menu_quit=true;
648 res = -1;
649 } else if(menunum==0){
650 rb->splash(HZ, true, "No game to resume");
651 }
652 break;
653 case 2:
654 rb->set_option("Level", &iLevelMode, INT, levels, 2, NULL);
655 break;
656 case 3:
657 rb->splash(HZ, true, "NOT AVAILABLE");
658 break;
659 case 4:
660 menu_quit=true;
661 res = PLUGIN_OK;
662 break;
663 case MENU_ATTACHED_USB:
664 menu_quit=true;
665 res = PLUGIN_USB_CONNECTED;
666 break;
667 }
668 }
669 rb->lcd_clear_display();
670 rb->menu_exit(m);
671 return res;
672}
673
674static int chopGameLoop(void)
675{
676 int move_button, ret;
677 bool exit=false;
678 int end, i=0, bdelay=0, last_button=BUTTON_NONE;
679
680 if (chopUpdateTerrainRecycling(&mGround) == 1)
681 /* mirror the sky if we've changed the ground */
682 chopCopyTerrain(&mGround, &mRoof, 0, -( iScreenY * 0.75));
683
684 ret = chopMenu(0);
685 if (ret != -1)
686 return PLUGIN_OK;
687
688 chopDrawScene();
689
690 while (!exit) {
691
692 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
693
694 if(chopUpdateTerrainRecycling(&mGround) == 1)
695 /* mirror the sky if we've changed the ground */
696 chopCopyTerrain(&mGround, &mRoof, 0, -( iScreenY * 0.75));
697
698 iRotorOffset = iR(-1,1);
699
700 /* We need to have this here so particles move when we're dead */
701
702 for (i=0; i < NUMBER_OF_PARTICLES; i++)
703 if(mParticles[i].bIsActive == 1)
704 {
705 mParticles[i].iWorldX += mParticles[i].iSpeedX;
706 mParticles[i].iWorldY += mParticles[i].iSpeedY;
707 }
708
709 /* Redraw the main window: */
710 chopDrawScene();
711
712
713 iGravityTimerCountdown--;
714
715 if(iGravityTimerCountdown <= 0)
716 {
717 iGravityTimerCountdown = 3;
718 chopAddParticle(iPlayerPosX, iPlayerPosY+5, 0, 0);
719 }
720
721 if(iLevelMode == LEVEL_MODE_NORMAL)
722 chopGenerateBlockIfNeeded();
723
724
725 move_button=rb->button_status();
726 if (rb->button_get(false) == QUIT) {
727 ret = chopMenu(1);
728 if (ret != -1)
729 return PLUGIN_OK;
730 bdelay = 0;
731 last_button = BUTTON_NONE;
732 move_button = BUTTON_NONE;
733 }
734
735 switch (move_button) {
736 case ACTION:
737#ifdef ACTION2
738 case ACTION2:
739#endif
740 if (last_button != ACTION
741#ifdef ACTION2
742 && last_button != ACTION2
743#endif
744 )
745 bdelay = -2;
746 if (bdelay == 0)
747 iPlayerSpeedY = -3;
748 break;
749
750 default:
751 if (last_button == ACTION
752#ifdef ACTION2
753 || last_button == ACTION2
754#endif
755 )
756 bdelay = 3;
757 if (bdelay == 0)
758 iPlayerSpeedY = 4;
759
760 if (rb->default_event_handler(move_button) == SYS_USB_CONNECTED)
761 return PLUGIN_USB_CONNECTED;
762 break;
763 }
764 last_button = move_button;
765
766 if (bdelay < 0) {
767 iPlayerSpeedY = bdelay;
768 bdelay++;
769 } else if (bdelay > 0) {
770 iPlayerSpeedY = bdelay;
771 bdelay--;
772 }
773
774 iCameraPosX = iPlayerPosX - 25;
775 iPlayerPosX += iPlayerSpeedX;
776 iPlayerPosY += iPlayerSpeedY;
777
778 chopCounter++;
779 /* increase speed as we go along */
780 if (chopCounter == 100){
781 iPlayerSpeedX++;
782 chopCounter=0;
783 }
784
785 if (iPlayerPosY > iScreenY-10 || iPlayerPosY < -5 ||
786 chopPointInTerrain(&mGround, iPlayerPosX, iPlayerPosY + 10, 0) ||
787 chopPointInTerrain(&mRoof, iPlayerPosX ,iPlayerPosY, 1))
788 {
789 chopKillPlayer();
790 chopDrawScene();
791 ret = chopMenu(0);
792 if (ret != -1)
793 return ret;
794 }
795
796 for (i=0; i < NUMBER_OF_BLOCKS; i++)
797 if(mBlocks[i].bIsActive == 1)
798 if(chopBlockCollideWithPlayer(&mBlocks[i])) {
799 chopKillPlayer();
800 chopDrawScene();
801 ret = chopMenu(0);
802 if (ret != -1)
803 return ret;
804 }
805
806 if (end > *rb->current_tick)
807 rb->sleep(end-*rb->current_tick);
808 else
809 rb->yield();
810
811 }
812 return PLUGIN_OK;
813}
814
815static void chopDrawBlock(struct CBlock *mBlock)
816{
817 int iPosX = (mBlock->iWorldX - iCameraPosX);
818 int iPosY = (mBlock->iWorldY);
819#if LCD_DEPTH > 2
820 rb->lcd_set_foreground(LCD_RGBPACK(30,30,30));
821#elif LCD_DEPTH == 2
822 rb->lcd_set_foreground(LCD_BLACK);
823#endif
824 rb->lcd_fillrect(iPosX, iPosY, mBlock->iSizeX,
825 mBlock->iSizeY);
826}
827
828
829static void chopRenderTerrain(struct CTerrain *ter)
830{
831
832 int i=1;
833
834 int oldx=0;
835
836 int ay=0;
837 if(ter->mNodes[0].y < LCD_HEIGHT/2)
838 ay=0;
839 else
840 ay=LCD_HEIGHT;
841
842 while(i < ter->iNodesCount && oldx < LCD_WIDTH)
843 {
844
845 int x = ter->mNodes[i-1].x - iCameraPosX;
846 int y = ter->mNodes[i-1].y;
847
848 int x2 = ter->mNodes[i].x - iCameraPosX;
849 int y2 = ter->mNodes[i].y;
850#if LCD_DEPTH > 2
851 rb->lcd_set_foreground(LCD_RGBPACK(50,100,250));
852#elif LCD_DEPTH == 2
853 rb->lcd_set_foreground(LCD_DARKGRAY);
854#endif
855
856 rb->lcd_drawline(x, y, x2, y2);
857 xlcd_filltriangle(x, y, x2, y2, x2, ay);
858 xlcd_filltriangle(x, ay, x2, y2, x2, ay);
859 if (ay == 0)
860 xlcd_filltriangle(x, ay, x, y, x2, y2 / 2);
861 else
862 xlcd_filltriangle(x, ay, x, y, x2, LCD_HEIGHT - (LCD_HEIGHT - y2) / 2);
863
864 oldx = x;
865 i++;
866
867 }
868
869}
870
871void chopper_load(bool newgame)
872{
873
874 int i;
875 int g;
876
877 if (newgame) {
878 iScreenX = LCD_WIDTH;
879 iScreenY = LCD_HEIGHT;
880 blockh = 0.2*iScreenY;
881 blockw = 0.04*iScreenX;
882 iPlayerAlive = 1;
883 score = 0;
884 }
885 iRotorOffset = 0;
886 iPlayerPosX = 60;
887 iPlayerPosY = iScreenY * 0.4;
888 iLastBlockPlacedPosX = 0;
889 iGravityTimerCountdown = 2;
890 chopCounter = 0;
891 iPlayerSpeedX = 3;
892 iPlayerSpeedY = 0;
893 iCameraPosX = 30;
894
895 for (i=0; i < NUMBER_OF_PARTICLES; i++)
896 mParticles[i].bIsActive = 0;
897
898 for (i=0; i < NUMBER_OF_BLOCKS; i++)
899 mBlocks[i].bIsActive = 0;
900
901 g = iScreenY - 10;
902 chopClearTerrain(&mGround);
903
904 for (i=0; i < MAX_TERRAIN_NODES; i++)
905 chopAddTerrainNode(&mGround,i * 30,g - iR(0,20));
906
907 if (chopUpdateTerrainRecycling(&mGround) == 1)
908 /* mirror the sky if we've changed the ground */
909 chopCopyTerrain(&mGround, &mRoof, 0, -( iScreenY * 0.75));
910
911 iLevelMode = LEVEL_MODE_NORMAL;
912 if (iLevelMode == LEVEL_MODE_NORMAL)
913 /* make it a bit more exciting, cause it's easy terrain... */
914 iPlayerSpeedX *= 2;
915}
916
917/* this is the plugin entry point */
918enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
919{
920 (void)parameter;
921 rb = api;
922 int ret;
923
924 rb->lcd_setfont(FONT_SYSFIXED);
925 /* Permanently enable the backlight (unless the user has turned it off) */
926 if (rb->global_settings->backlight_timeout > 0)
927 rb->backlight_set_timeout(1);
928
929 rb->srand( *rb->current_tick );
930
931 xlcd_init(rb);
932 configfile_init(rb);
933 configfile_load(CFG_FILE, config, 1, 0);
934
935 chopper_load(true);
936 ret = chopGameLoop();
937
938 configfile_save(CFG_FILE, config, 1, 0);
939
940 /* Restore user's original backlight setting */
941 rb->lcd_setfont(FONT_UI);
942 rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
943
944 return ret;
945}