Don't rebuild the dependency file on 'make reconf'. Build type and target won't chang...
[kugel-rb.git] / apps / plugins / chopper.c
blob15333c4a99a058c025b309b839fb2db84d88bdd6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
10 * Originally by Joshua Oreman, improved by Prashant Varanasi
11 * Ported to Rockbox by Ben Basha (Paprica)
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include "plugin.h"
24 #include "lib/xlcd.h"
25 #include "lib/configfile.h"
26 #include "lib/helper.h"
27 #include "lib/playback_control.h"
29 PLUGIN_HEADER
32 Still To do:
33 - Make original speed and further increases in speed depend more on screen size
34 - attempt to make the tunnels get narrower as the game goes on
35 - make the chopper look better, maybe a picture, and scale according
36 to screen size
37 - use textures for the color screens for background and terrain,
38 eg stars on background
39 - allow choice of different levels [later: different screen themes]
40 - better high score handling, improved screen etc.
43 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
45 #define QUIT BUTTON_OFF
46 #define ACTION BUTTON_UP
47 #define ACTION2 BUTTON_SELECT
48 #define ACTIONTEXT "SELECT"
50 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
52 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
54 #define QUIT BUTTON_MENU
55 #define ACTION BUTTON_SELECT
56 #define ACTIONTEXT "SELECT"
58 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD /* grayscale at the moment */
60 #define QUIT BUTTON_POWER
61 #define ACTION BUTTON_UP
62 #define ACTION2 BUTTON_SELECT
63 #define ACTIONTEXT "SELECT"
65 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
66 #define QUIT BUTTON_POWER
67 #define ACTION BUTTON_RIGHT
68 #define ACTIONTEXT "RIGHT"
70 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
71 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
72 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
73 (CONFIG_KEYPAD == SANSA_M200_PAD) || \
74 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
75 #define QUIT BUTTON_POWER
76 #define ACTION BUTTON_SELECT
77 #define ACTIONTEXT "SELECT"
79 #elif CONFIG_KEYPAD == GIGABEAT_PAD
80 #define QUIT BUTTON_MENU
81 #define ACTION BUTTON_SELECT
82 #define ACTIONTEXT "SELECT"
84 #elif CONFIG_KEYPAD == RECORDER_PAD
85 #define QUIT BUTTON_OFF
86 #define ACTION BUTTON_PLAY
87 #define ACTIONTEXT "PLAY"
89 #elif CONFIG_KEYPAD == ONDIO_PAD
90 #define QUIT BUTTON_OFF
91 #define ACTION BUTTON_UP
92 #define ACTION2 BUTTON_MENU
93 #define ACTIONTEXT "UP"
95 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
96 #define QUIT BUTTON_BACK
97 #define ACTION BUTTON_SELECT
98 #define ACTION2 BUTTON_MENU
99 #define ACTIONTEXT "SELECT"
101 #elif CONFIG_KEYPAD == MROBE100_PAD
102 #define QUIT BUTTON_POWER
103 #define ACTION BUTTON_SELECT
104 #define ACTIONTEXT "SELECT"
106 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
107 #define QUIT BUTTON_RC_REC
108 #define ACTION BUTTON_RC_PLAY
109 #define ACTION2 BUTTON_RC_MODE
110 #define ACTIONTEXT "PLAY"
112 #elif CONFIG_KEYPAD == COWOND2_PAD
113 #define QUIT BUTTON_POWER
115 #elif CONFIG_KEYPAD == IAUDIO67_PAD
116 #define QUIT BUTTON_POWER
117 #define ACTION BUTTON_PLAY
118 #define ACTION2 BUTTON_STOP
119 #define ACTIONTEXT "PLAY"
121 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
122 #define QUIT BUTTON_BACK
123 #define ACTION BUTTON_UP
124 #define ACTION2 BUTTON_MENU
125 #define ACTIONTEXT "UP"
127 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
128 #define QUIT BUTTON_POWER
129 #define ACTION BUTTON_MENU
130 #define ACTION2 BUTTON_SELECT
131 #define ACTIONTEXT "MENU"
133 #else
134 #error No keymap defined!
135 #endif
137 #ifdef HAVE_TOUCHSCREEN
138 #ifndef QUIT
139 #define QUIT BUTTON_TOPLEFT
140 #endif
141 #ifndef ACTION
142 #define ACTION BUTTON_BOTTOMLEFT
143 #endif
144 #ifndef ACTION2
145 #define ACTION2 BUTTON_BOTTOMRIGHT
146 #endif
147 #ifndef ACTIONTEXT
148 #define ACTIONTEXT "BOTTOMRIGHT"
149 #endif
150 #endif
152 #define NUMBER_OF_BLOCKS 8
153 #define NUMBER_OF_PARTICLES 3
154 #define MAX_TERRAIN_NODES 15
156 #define LEVEL_MODE_NORMAL 0
157 #define LEVEL_MODE_STEEP 1
159 #if LCD_WIDTH <= 112
160 #define CYCLETIME 100
161 #define SCALE(x) ((x)==1 ? (x) : ((x) >> 1))
162 #define SIZE 2
163 #else
164 #define CYCLETIME 60
165 #define SCALE(x) (x)
166 #define SIZE 1
167 #endif
169 /*Chopper's local variables to track the terrain position etc*/
170 static int chopCounter;
171 static int iRotorOffset;
172 static int iScreenX;
173 static int iScreenY;
174 static int iPlayerPosX;
175 static int iPlayerPosY;
176 static int iCameraPosX;
177 static int iPlayerSpeedX;
178 static int iPlayerSpeedY;
179 static int iLastBlockPlacedPosX;
180 static int iGravityTimerCountdown;
181 static int iPlayerAlive;
182 static int iLevelMode;
183 static int blockh,blockw;
184 static int highscore;
185 static int score;
187 #define CFG_FILE "chopper.cfg"
188 #define MAX_POINTS 50000
189 static struct configdata config[] =
191 {TYPE_INT, 0, MAX_POINTS, { .int_p = &highscore }, "highscore", NULL}
194 struct CBlock
196 int iWorldX;
197 int iWorldY;
199 int iSizeX;
200 int iSizeY;
202 int bIsActive;
205 struct CParticle
207 int iWorldX;
208 int iWorldY;
210 int iSpeedX;
211 int iSpeedY;
213 int bIsActive;
216 struct CTerrainNode
218 int x;
219 int y;
222 struct CTerrain
224 struct CTerrainNode mNodes[MAX_TERRAIN_NODES];
225 int iNodesCount;
226 int iLastNodePlacedPosX;
229 struct CBlock mBlocks[NUMBER_OF_BLOCKS];
230 struct CParticle mParticles[NUMBER_OF_PARTICLES];
232 struct CTerrain mGround;
233 struct CTerrain mRoof;
235 /*Function declarations*/
236 static void chopDrawParticle(struct CParticle *mParticle);
237 static void chopDrawBlock(struct CBlock *mBlock);
238 static void chopRenderTerrain(struct CTerrain *ter);
239 void chopper_load(bool newgame);
240 void cleanup_chopper(void);
242 static void chopDrawPlayer(int x,int y) /* These are SCREEN coords, not world!*/
245 #if LCD_DEPTH > 2
246 rb->lcd_set_foreground(LCD_RGBPACK(50,50,200));
247 #elif LCD_DEPTH == 2
248 rb->lcd_set_foreground(LCD_DARKGRAY);
249 #endif
250 rb->lcd_fillrect(SCALE(x+6), SCALE(y+2), SCALE(12), SCALE(9));
251 rb->lcd_fillrect(SCALE(x-3), SCALE(y+6), SCALE(20), SCALE(3));
253 #if LCD_DEPTH > 2
254 rb->lcd_set_foreground(LCD_RGBPACK(50,50,50));
255 #elif LCD_DEPTH == 2
256 rb->lcd_set_foreground(LCD_DARKGRAY);
257 #endif
258 rb->lcd_fillrect(SCALE(x+10), SCALE(y), SCALE(2), SCALE(3));
259 rb->lcd_fillrect(SCALE(x+10), SCALE(y), SCALE(1), SCALE(3));
261 #if LCD_DEPTH > 2
262 rb->lcd_set_foreground(LCD_RGBPACK(40,40,100));
263 #elif LCD_DEPTH == 2
264 rb->lcd_set_foreground(LCD_BLACK);
265 #endif
266 rb->lcd_drawline(SCALE(x), SCALE(y+iRotorOffset), SCALE(x+20),
267 SCALE(y-iRotorOffset));
269 #if LCD_DEPTH > 2
270 rb->lcd_set_foreground(LCD_RGBPACK(20,20,50));
271 #elif LCD_DEPTH == 2
272 rb->lcd_set_foreground(LCD_BLACK);
273 #endif
274 rb->lcd_fillrect(SCALE(x - 2), SCALE(y + 5), SCALE(2), SCALE(5));
278 static void chopClearTerrain(struct CTerrain *ter)
280 ter->iNodesCount = 0;
284 int iR(int low,int high)
286 return low+rb->rand()%(high-low+1);
289 static void chopCopyTerrain(struct CTerrain *src, struct CTerrain *dest,
290 int xOffset,int yOffset)
292 int i=0;
294 while(i < src->iNodesCount)
296 dest->mNodes[i].x = src->mNodes[i].x + xOffset;
297 dest->mNodes[i].y = src->mNodes[i].y + yOffset;
299 i++;
302 dest->iNodesCount = src->iNodesCount;
303 dest->iLastNodePlacedPosX = src->iLastNodePlacedPosX;
307 static void chopAddTerrainNode(struct CTerrain *ter, int x, int y)
309 int i=0;
311 if(ter->iNodesCount + 1 >= MAX_TERRAIN_NODES)
313 /* DEBUGF("ERROR: Not enough nodes!\n"); */
314 return;
317 ter->iNodesCount++;
319 i = ter->iNodesCount - 1;
321 ter->mNodes[i].x = x;
322 ter->mNodes[i].y= y;
324 ter->iLastNodePlacedPosX = x;
328 static void chopTerrainNodeDeleteAndShift(struct CTerrain *ter,int nodeIndex)
330 int i=nodeIndex;
332 while( i < ter->iNodesCount )
334 ter->mNodes[i - 1] = ter->mNodes[i];
335 i++;
338 ter->iNodesCount--;
343 int chopUpdateTerrainRecycling(struct CTerrain *ter)
345 int i=1;
346 int ret = 0;
347 int iNewNodePos,g,v;
348 while(i < ter->iNodesCount)
351 if( iCameraPosX > ter->mNodes[i].x)
354 chopTerrainNodeDeleteAndShift(ter,i);
356 iNewNodePos = ter->iLastNodePlacedPosX + 50;
357 g = iScreenY - 10;
359 v = 3*iPlayerSpeedX;
360 if(v>50)
361 v=50;
362 if(iLevelMode == LEVEL_MODE_STEEP)
363 v*=5;
365 chopAddTerrainNode(ter,iNewNodePos,g - iR(-v,v));
366 ret=1;
370 i++;
374 return 1;
377 int chopTerrainHeightAtPoint(struct CTerrain *ter, int pX)
380 int iNodeIndexOne=0,iNodeIndexTwo=0, h, terY1, terY2, terX1, terX2, a, b;
381 float c,d;
383 int i=0;
384 for(i=1;i<MAX_TERRAIN_NODES;i++)
386 if(ter->mNodes[i].x > pX)
388 iNodeIndexOne = i - 1;
389 break;
394 iNodeIndexTwo = iNodeIndexOne + 1;
395 terY1 = ter->mNodes[iNodeIndexOne].y;
396 terY2 = ter->mNodes[iNodeIndexTwo].y;
398 terX1 = 0;
399 terX2 = ter->mNodes[iNodeIndexTwo].x - ter->mNodes[iNodeIndexOne].x;
401 pX-= ter->mNodes[iNodeIndexOne].x;
403 a = terY2 - terY1;
404 b = terX2;
405 c = pX;
406 d = (c/b) * a;
408 h = d + terY1;
410 return h;
414 int chopPointInTerrain(struct CTerrain *ter, int pX, int pY, int iTestType)
416 int h = chopTerrainHeightAtPoint(ter, pX);
418 if(iTestType == 0)
419 return (pY > h);
420 else
421 return (pY < h);
424 static void chopAddBlock(int x,int y,int sx,int sy, int indexOverride)
426 int i=0;
428 if(indexOverride < 0)
430 while(mBlocks[i].bIsActive && i < NUMBER_OF_BLOCKS)
431 i++;
432 if(i==NUMBER_OF_BLOCKS)
434 DEBUGF("No blocks!\n");
435 return;
438 else
439 i = indexOverride;
441 mBlocks[i].bIsActive = 1;
442 mBlocks[i].iWorldX = x;
443 mBlocks[i].iWorldY = y;
444 mBlocks[i].iSizeX = sx;
445 mBlocks[i].iSizeY = sy;
447 iLastBlockPlacedPosX = x;
450 static void chopAddParticle(int x,int y,int sx,int sy)
452 int i=0;
454 while(mParticles[i].bIsActive && i < NUMBER_OF_PARTICLES)
455 i++;
457 if(i==NUMBER_OF_PARTICLES)
458 return;
460 mParticles[i].bIsActive = 1;
461 mParticles[i].iWorldX = x;
462 mParticles[i].iWorldY = y;
463 mParticles[i].iSpeedX = sx;
464 mParticles[i].iSpeedY = sy;
467 static void chopGenerateBlockIfNeeded(void)
469 int i=0;
470 int DistSpeedX = iPlayerSpeedX * 5;
471 if(DistSpeedX<200) DistSpeedX = 200;
473 while(i < NUMBER_OF_BLOCKS)
475 if(!mBlocks[i].bIsActive)
477 int iX,iY,sX,sY;
479 iX = iLastBlockPlacedPosX + (350-DistSpeedX);
480 sX = blockw;
482 iY = iR(0,iScreenY);
483 sY = blockh + iR(1,blockh/3);
485 chopAddBlock(iX,iY,sX,sY,i);
488 i++;
493 static int chopBlockCollideWithPlayer(struct CBlock *mBlock)
495 int px = iPlayerPosX;
496 int py = iPlayerPosY;
498 int x = mBlock->iWorldX-17;
499 int y = mBlock->iWorldY-11;
501 int x2 = x + mBlock->iSizeX+17;
502 int y2 = y + mBlock->iSizeY+11;
504 if(px>x && px<x2)
506 if(py>y && py<y2)
508 return 1;
512 return 0;
515 static int chopBlockOffscreen(struct CBlock *mBlock)
517 if(mBlock->iWorldX + mBlock->iSizeX < iCameraPosX)
518 return 1;
519 else
520 return 0;
523 static int chopParticleOffscreen(struct CParticle *mParticle)
525 if (mParticle->iWorldX < iCameraPosX || mParticle->iWorldY < 0 ||
526 mParticle->iWorldY > iScreenY || mParticle->iWorldX > iCameraPosX +
527 iScreenX)
529 return 1;
531 else
532 return 0;
535 static void chopKillPlayer(void)
537 int i, button;
539 for (i = 0; i < NUMBER_OF_PARTICLES; i++) {
540 mParticles[i].bIsActive = 0;
541 chopAddParticle(iPlayerPosX + iR(0,20), iPlayerPosY + iR(0,20),
542 iR(-2,2), iR(-2,2));
545 iPlayerAlive--;
547 if (iPlayerAlive == 0) {
548 rb->lcd_set_drawmode(DRMODE_FG);
549 #if LCD_DEPTH >= 2
550 rb->lcd_set_foreground(LCD_LIGHTGRAY);
551 #endif
552 rb->splash(HZ, "Game Over");
554 if (score > highscore) {
555 char scoretext[30];
556 highscore = score;
557 rb->snprintf(scoretext, sizeof(scoretext), "New High Score: %d",
558 highscore);
559 rb->splash(HZ*2, scoretext);
562 rb->splash(HZ/4, "Press " ACTIONTEXT " to continue");
563 rb->lcd_update();
565 rb->lcd_set_drawmode(DRMODE_SOLID);
567 while (true) {
568 button = rb->button_get(true);
569 if (button == ACTION
570 #ifdef ACTION2
571 || button == ACTION2
572 #endif
574 while (true) {
575 button = rb->button_get(true);
576 if (button == (ACTION | BUTTON_REL)
577 #ifdef ACTION2
578 || button == (ACTION2 | BUTTON_REL)
579 #endif
581 chopper_load(true);
582 return;
588 } else
589 chopper_load(false);
593 static void chopDrawTheWorld(void)
595 int i=0;
597 while(i < NUMBER_OF_BLOCKS)
599 if(mBlocks[i].bIsActive)
601 if(chopBlockOffscreen(&mBlocks[i]) == 1)
602 mBlocks[i].bIsActive = 0;
603 else
604 chopDrawBlock(&mBlocks[i]);
607 i++;
610 i=0;
612 while(i < NUMBER_OF_PARTICLES)
614 if(mParticles[i].bIsActive)
616 if(chopParticleOffscreen(&mParticles[i]) == 1)
617 mParticles[i].bIsActive = 0;
618 else
619 chopDrawParticle(&mParticles[i]);
622 i++;
625 chopRenderTerrain(&mGround);
626 chopRenderTerrain(&mRoof);
630 static void chopDrawParticle(struct CParticle *mParticle)
633 int iPosX = (mParticle->iWorldX - iCameraPosX);
634 int iPosY = (mParticle->iWorldY);
635 #if LCD_DEPTH > 2
636 rb->lcd_set_foreground(LCD_RGBPACK(192,192,192));
637 #elif LCD_DEPTH == 2
638 rb->lcd_set_foreground(LCD_LIGHTGRAY);
639 #endif
640 rb->lcd_fillrect(SCALE(iPosX), SCALE(iPosY), SCALE(3), SCALE(3));
644 static void chopDrawScene(void)
646 char s[30];
647 int w;
648 #if LCD_DEPTH > 2
649 rb->lcd_set_background(LCD_BLACK);
650 #elif LCD_DEPTH == 2
651 rb->lcd_set_background(LCD_WHITE);
652 #endif
653 rb->lcd_clear_display();
655 chopDrawTheWorld();
656 chopDrawPlayer(iPlayerPosX - iCameraPosX, iPlayerPosY);
658 score = -20 + iPlayerPosX/3;
660 #if LCD_DEPTH == 1
661 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
662 #else
663 rb->lcd_set_drawmode(DRMODE_FG);
664 #endif
666 #if LCD_DEPTH > 2
667 rb->lcd_set_foreground(LCD_BLACK);
668 #elif LCD_DEPTH == 2
669 rb->lcd_set_foreground(LCD_WHITE);
670 #endif
672 #if LCD_WIDTH <= 128
673 rb->snprintf(s, sizeof(s), "Dist: %d", score);
674 #else
675 rb->snprintf(s, sizeof(s), "Distance: %d", score);
676 #endif
677 rb->lcd_getstringsize(s, &w, NULL);
678 rb->lcd_putsxy(2, 2, s);
679 if (score < highscore)
681 int w2;
682 #if LCD_WIDTH <= 128
683 rb->snprintf(s, sizeof(s), "Hi: %d", highscore);
684 #else
685 rb->snprintf(s, sizeof(s), "Best: %d", highscore);
686 #endif
687 rb->lcd_getstringsize(s, &w2, NULL);
688 if (LCD_WIDTH - 2 - w2 > w + 2)
689 rb->lcd_putsxy(LCD_WIDTH - 2 - w2, 2, s);
691 rb->lcd_set_drawmode(DRMODE_SOLID);
693 rb->lcd_update();
696 static int chopMenu(int menunum)
698 int result = (menunum==0)?0:1;
699 int res = 0;
700 bool menu_quit = false;
702 static const struct opt_items levels[2] = {
703 { "Normal", -1 },
704 { "Steep", -1 },
707 MENUITEM_STRINGLIST(menu,"Chopper Menu",NULL,"Start New Game","Resume Game",
708 "Level","Playback Control","Quit");
710 #ifdef HAVE_LCD_COLOR
711 rb->lcd_set_foreground(LCD_WHITE);
712 rb->lcd_set_background(LCD_BLACK);
713 #elif LCD_DEPTH == 2
714 rb->lcd_set_foreground(LCD_BLACK);
715 rb->lcd_set_background(LCD_WHITE);
716 #endif
718 rb->lcd_clear_display();
720 while (!menu_quit) {
721 switch(rb->do_menu(&menu, &result, NULL, false))
723 case 0: /* Start New Game */
724 menu_quit=true;
725 chopper_load(true);
726 res = -1;
727 break;
728 case 1: /* Resume Game */
729 if(menunum==1) {
730 menu_quit=true;
731 res = -1;
732 } else if(menunum==0){
733 rb->splash(HZ, "No game to resume");
735 break;
736 case 2:
737 rb->set_option("Level", &iLevelMode, INT, levels, 2, NULL);
738 break;
739 case 3:
740 playback_control(NULL);
741 break;
742 case 4:
743 menu_quit=true;
744 res = PLUGIN_OK;
745 break;
746 case MENU_ATTACHED_USB:
747 menu_quit=true;
748 res = PLUGIN_USB_CONNECTED;
749 break;
752 rb->lcd_clear_display();
753 return res;
756 static int chopGameLoop(void)
758 int move_button, ret;
759 bool exit=false;
760 int end, i=0, bdelay=0, last_button=BUTTON_NONE;
762 if (chopUpdateTerrainRecycling(&mGround) == 1)
763 /* mirror the sky if we've changed the ground */
764 chopCopyTerrain(&mGround, &mRoof, 0, - ( (iScreenY * 3) / 4));
766 ret = chopMenu(0);
767 if (ret != -1)
768 return PLUGIN_OK;
770 chopDrawScene();
772 while (!exit) {
774 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
776 if(chopUpdateTerrainRecycling(&mGround) == 1)
777 /* mirror the sky if we've changed the ground */
778 chopCopyTerrain(&mGround, &mRoof, 0, - ( (iScreenY * 3) / 4));
780 iRotorOffset = iR(-1,1);
782 /* We need to have this here so particles move when we're dead */
784 for (i=0; i < NUMBER_OF_PARTICLES; i++)
785 if(mParticles[i].bIsActive == 1)
787 mParticles[i].iWorldX += mParticles[i].iSpeedX;
788 mParticles[i].iWorldY += mParticles[i].iSpeedY;
791 /* Redraw the main window: */
792 chopDrawScene();
795 iGravityTimerCountdown--;
797 if(iGravityTimerCountdown <= 0)
799 iGravityTimerCountdown = 3;
800 chopAddParticle(iPlayerPosX, iPlayerPosY+5, 0, 0);
803 if(iLevelMode == LEVEL_MODE_NORMAL)
804 chopGenerateBlockIfNeeded();
807 move_button=rb->button_status();
808 if (rb->button_get(false) == QUIT) {
809 ret = chopMenu(1);
810 if (ret != -1)
811 return PLUGIN_OK;
812 bdelay = 0;
813 last_button = BUTTON_NONE;
814 move_button = BUTTON_NONE;
817 switch (move_button) {
818 case ACTION:
819 #ifdef ACTION2
820 case ACTION2:
821 #endif
822 if (last_button != ACTION
823 #ifdef ACTION2
824 && last_button != ACTION2
825 #endif
827 bdelay = -2;
828 if (bdelay == 0)
829 iPlayerSpeedY = -3;
830 break;
832 default:
833 if (last_button == ACTION
834 #ifdef ACTION2
835 || last_button == ACTION2
836 #endif
838 bdelay = 3;
839 if (bdelay == 0)
840 iPlayerSpeedY = 4;
842 if (rb->default_event_handler(move_button) == SYS_USB_CONNECTED)
843 return PLUGIN_USB_CONNECTED;
844 break;
846 last_button = move_button;
848 if (bdelay < 0) {
849 iPlayerSpeedY = bdelay;
850 bdelay++;
851 } else if (bdelay > 0) {
852 iPlayerSpeedY = bdelay;
853 bdelay--;
856 iCameraPosX = iPlayerPosX - 25;
857 iPlayerPosX += iPlayerSpeedX;
858 iPlayerPosY += iPlayerSpeedY;
860 chopCounter++;
861 /* increase speed as we go along */
862 if (chopCounter == 100){
863 iPlayerSpeedX++;
864 chopCounter=0;
867 if (iPlayerPosY > iScreenY-10 || iPlayerPosY < -5 ||
868 chopPointInTerrain(&mGround, iPlayerPosX, iPlayerPosY + 10, 0) ||
869 chopPointInTerrain(&mRoof, iPlayerPosX ,iPlayerPosY, 1))
871 chopKillPlayer();
872 chopDrawScene();
873 ret = chopMenu(0);
874 if (ret != -1)
875 return ret;
878 for (i=0; i < NUMBER_OF_BLOCKS; i++)
879 if(mBlocks[i].bIsActive == 1)
880 if(chopBlockCollideWithPlayer(&mBlocks[i])) {
881 chopKillPlayer();
882 chopDrawScene();
883 ret = chopMenu(0);
884 if (ret != -1)
885 return ret;
888 if (end > *rb->current_tick)
889 rb->sleep(end-*rb->current_tick);
890 else
891 rb->yield();
894 return PLUGIN_OK;
897 static void chopDrawBlock(struct CBlock *mBlock)
899 int iPosX = (mBlock->iWorldX - iCameraPosX);
900 int iPosY = (mBlock->iWorldY);
901 #if LCD_DEPTH > 2
902 rb->lcd_set_foreground(LCD_RGBPACK(100,255,100));
903 #elif LCD_DEPTH == 2
904 rb->lcd_set_foreground(LCD_BLACK);
905 #endif
906 rb->lcd_fillrect(SCALE(iPosX), SCALE(iPosY), SCALE(mBlock->iSizeX),
907 SCALE(mBlock->iSizeY));
911 static void chopRenderTerrain(struct CTerrain *ter)
914 int i=1;
916 int oldx=0;
918 int ay=0;
919 if(ter->mNodes[0].y < (LCD_HEIGHT*SIZE)/2)
920 ay=0;
921 else
922 ay=(LCD_HEIGHT*SIZE);
924 while(i < ter->iNodesCount && oldx < iScreenX)
927 int x = ter->mNodes[i-1].x - iCameraPosX;
928 int y = ter->mNodes[i-1].y;
930 int x2 = ter->mNodes[i].x - iCameraPosX;
931 int y2 = ter->mNodes[i].y;
932 #if LCD_DEPTH > 2
933 rb->lcd_set_foreground(LCD_RGBPACK(100,255,100));
934 #elif LCD_DEPTH == 2
935 rb->lcd_set_foreground(LCD_DARKGRAY);
936 #endif
938 rb->lcd_drawline(SCALE(x), SCALE(y), SCALE(x2), SCALE(y2));
940 xlcd_filltriangle(SCALE(x), SCALE(y), SCALE(x2), SCALE(y2),
941 SCALE(x2), SCALE(ay));
942 xlcd_filltriangle(SCALE(x), SCALE(ay), SCALE(x2), SCALE(y2),
943 SCALE(x2), SCALE(ay));
945 if (ay == 0)
946 xlcd_filltriangle(SCALE(x), SCALE(ay), SCALE(x), SCALE(y),
947 SCALE(x2), SCALE(y2 / 2));
948 else
949 xlcd_filltriangle(SCALE(x), SCALE(ay), SCALE(x), SCALE(y),
950 SCALE(x2), SCALE((LCD_HEIGHT*SIZE) -
951 ((LCD_HEIGHT*SIZE) - y2) / 2));
953 oldx = x;
954 i++;
960 void chopper_load(bool newgame)
963 int i;
964 int g;
966 if (newgame) {
967 iScreenX = LCD_WIDTH * SIZE;
968 iScreenY = LCD_HEIGHT * SIZE;
969 blockh = iScreenY / 5;
970 blockw = iScreenX / 20;
971 iPlayerAlive = 1;
972 score = 0;
974 iRotorOffset = 0;
975 iPlayerPosX = 60;
976 iPlayerPosY = (iScreenY * 4) / 10;
977 iLastBlockPlacedPosX = 0;
978 iGravityTimerCountdown = 2;
979 chopCounter = 0;
980 iPlayerSpeedX = 3;
981 iPlayerSpeedY = 0;
982 iCameraPosX = 30;
984 for (i=0; i < NUMBER_OF_PARTICLES; i++)
985 mParticles[i].bIsActive = 0;
987 for (i=0; i < NUMBER_OF_BLOCKS; i++)
988 mBlocks[i].bIsActive = 0;
990 g = iScreenY - 10;
991 chopClearTerrain(&mGround);
993 for (i=0; i < MAX_TERRAIN_NODES; i++)
994 chopAddTerrainNode(&mGround,i * 30,g - iR(0,20));
996 if (chopUpdateTerrainRecycling(&mGround) == 1)
997 /* mirror the sky if we've changed the ground */
998 chopCopyTerrain(&mGround, &mRoof, 0, - ( (iScreenY * 3) / 4));
1000 iLevelMode = LEVEL_MODE_NORMAL;
1001 if (iLevelMode == LEVEL_MODE_NORMAL)
1002 /* make it a bit more exciting, cause it's easy terrain... */
1003 iPlayerSpeedX *= 2;
1006 /* this is the plugin entry point */
1007 enum plugin_status plugin_start(const void* parameter)
1009 (void)parameter;
1010 int ret;
1012 rb->lcd_setfont(FONT_SYSFIXED);
1013 #if LCD_DEPTH > 1
1014 rb->lcd_set_backdrop(NULL);
1015 #endif
1016 #ifdef HAVE_LCD_COLOR
1017 rb->lcd_set_background(LCD_BLACK);
1018 rb->lcd_set_foreground(LCD_WHITE);
1019 #endif
1021 /* Turn off backlight timeout */
1022 backlight_force_on(); /* backlight control in lib/helper.c */
1024 rb->srand( *rb->current_tick );
1026 configfile_load(CFG_FILE, config, 1, 0);
1028 chopper_load(true);
1029 ret = chopGameLoop();
1031 configfile_save(CFG_FILE, config, 1, 0);
1033 rb->lcd_setfont(FONT_UI);
1034 /* Turn on backlight timeout (revert to settings) */
1035 backlight_use_settings(); /* backlight control in lib/helper.c */
1037 return ret;