1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
25 #include "lib/configfile.h"
26 #include "lib/helper.h"
27 #include "lib/playback_control.h"
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
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 #define QUIT BUTTON_POWER
75 #define ACTION BUTTON_SELECT
76 #define ACTIONTEXT "SELECT"
78 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
79 #define QUIT (BUTTON_HOME|BUTTON_REPEAT)
80 #define ACTION BUTTON_SELECT
81 #define ACTIONTEXT "SELECT"
83 #elif CONFIG_KEYPAD == GIGABEAT_PAD
84 #define QUIT BUTTON_MENU
85 #define ACTION BUTTON_SELECT
86 #define ACTIONTEXT "SELECT"
88 #elif CONFIG_KEYPAD == RECORDER_PAD
89 #define QUIT BUTTON_OFF
90 #define ACTION BUTTON_PLAY
91 #define ACTIONTEXT "PLAY"
93 #elif CONFIG_KEYPAD == ONDIO_PAD
94 #define QUIT BUTTON_OFF
95 #define ACTION BUTTON_UP
96 #define ACTION2 BUTTON_MENU
97 #define ACTIONTEXT "UP"
99 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
100 #define QUIT BUTTON_BACK
101 #define ACTION BUTTON_SELECT
102 #define ACTION2 BUTTON_MENU
103 #define ACTIONTEXT "SELECT"
105 #elif CONFIG_KEYPAD == MROBE100_PAD
106 #define QUIT BUTTON_POWER
107 #define ACTION BUTTON_SELECT
108 #define ACTIONTEXT "SELECT"
110 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
111 #define QUIT BUTTON_RC_REC
112 #define ACTION BUTTON_RC_PLAY
113 #define ACTION2 BUTTON_RC_MODE
114 #define ACTIONTEXT "PLAY"
116 #elif CONFIG_KEYPAD == COWOND2_PAD
117 #define QUIT BUTTON_POWER
119 #elif CONFIG_KEYPAD == IAUDIO67_PAD
120 #define QUIT BUTTON_POWER
121 #define ACTION BUTTON_PLAY
122 #define ACTION2 BUTTON_STOP
123 #define ACTIONTEXT "PLAY"
125 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
126 #define QUIT BUTTON_BACK
127 #define ACTION BUTTON_UP
128 #define ACTION2 BUTTON_MENU
129 #define ACTIONTEXT "UP"
131 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
132 #define QUIT BUTTON_POWER
133 #define ACTION BUTTON_MENU
134 #define ACTION2 BUTTON_SELECT
135 #define ACTIONTEXT "MENU"
137 #elif CONFIG_KEYPAD == ONDAVX747_PAD || CONFIG_KEYPAD == MROBE500_PAD
138 #define QUIT BUTTON_POWER
141 #error No keymap defined!
144 #ifdef HAVE_TOUCHSCREEN
146 #define QUIT BUTTON_TOPLEFT
149 #define ACTION BUTTON_BOTTOMLEFT
152 #define ACTION2 BUTTON_BOTTOMRIGHT
155 #define ACTIONTEXT "BOTTOMRIGHT"
159 #define NUMBER_OF_BLOCKS 8
160 #define NUMBER_OF_PARTICLES 3
161 #define MAX_TERRAIN_NODES 15
163 #define LEVEL_MODE_NORMAL 0
164 #define LEVEL_MODE_STEEP 1
167 #define CYCLETIME 100
168 static inline int SCALE(int x
)
170 return x
== 1 ? x
: x
>> 1;
179 /*Chopper's local variables to track the terrain position etc*/
180 static int chopCounter
;
181 static int iRotorOffset
;
184 static int iPlayerPosX
;
185 static int iPlayerPosY
;
186 static int iCameraPosX
;
187 static int iPlayerSpeedX
;
188 static int iPlayerSpeedY
;
189 static int iLastBlockPlacedPosX
;
190 static int iGravityTimerCountdown
;
191 static int iPlayerAlive
;
192 static int iLevelMode
;
193 static int blockh
,blockw
;
194 static int highscore
;
197 #define CFG_FILE "chopper.cfg"
198 #define MAX_POINTS 50000
199 static struct configdata config
[] =
201 {TYPE_INT
, 0, MAX_POINTS
, { .int_p
= &highscore
}, "highscore", NULL
}
234 struct CTerrainNode mNodes
[MAX_TERRAIN_NODES
];
236 int iLastNodePlacedPosX
;
239 struct CBlock mBlocks
[NUMBER_OF_BLOCKS
];
240 struct CParticle mParticles
[NUMBER_OF_PARTICLES
];
242 struct CTerrain mGround
;
243 struct CTerrain mRoof
;
245 /*Function declarations*/
246 static void chopDrawParticle(struct CParticle
*mParticle
);
247 static void chopDrawBlock(struct CBlock
*mBlock
);
248 static void chopRenderTerrain(struct CTerrain
*ter
);
249 void chopper_load(bool newgame
);
250 void cleanup_chopper(void);
252 static void chopDrawPlayer(int x
,int y
) /* These are SCREEN coords, not world!*/
256 rb
->lcd_set_foreground(LCD_RGBPACK(50,50,200));
258 rb
->lcd_set_foreground(LCD_DARKGRAY
);
260 rb
->lcd_fillrect(SCALE(x
+6), SCALE(y
+2), SCALE(12), SCALE(9));
261 rb
->lcd_fillrect(SCALE(x
-3), SCALE(y
+6), SCALE(20), SCALE(3));
264 rb
->lcd_set_foreground(LCD_RGBPACK(50,50,50));
266 rb
->lcd_set_foreground(LCD_DARKGRAY
);
268 rb
->lcd_fillrect(SCALE(x
+10), SCALE(y
), SCALE(2), SCALE(3));
269 rb
->lcd_fillrect(SCALE(x
+10), SCALE(y
), SCALE(1), SCALE(3));
272 rb
->lcd_set_foreground(LCD_RGBPACK(40,40,100));
274 rb
->lcd_set_foreground(LCD_BLACK
);
276 rb
->lcd_drawline(SCALE(x
), SCALE(y
+iRotorOffset
), SCALE(x
+20),
277 SCALE(y
-iRotorOffset
));
280 rb
->lcd_set_foreground(LCD_RGBPACK(20,20,50));
282 rb
->lcd_set_foreground(LCD_BLACK
);
284 rb
->lcd_fillrect(SCALE(x
- 2), SCALE(y
+ 5), SCALE(2), SCALE(5));
288 static void chopClearTerrain(struct CTerrain
*ter
)
290 ter
->iNodesCount
= 0;
294 int iR(int low
,int high
)
296 return low
+rb
->rand()%(high
-low
+1);
299 static void chopCopyTerrain(struct CTerrain
*src
, struct CTerrain
*dest
,
300 int xOffset
,int yOffset
)
304 while(i
< src
->iNodesCount
)
306 dest
->mNodes
[i
].x
= src
->mNodes
[i
].x
+ xOffset
;
307 dest
->mNodes
[i
].y
= src
->mNodes
[i
].y
+ yOffset
;
312 dest
->iNodesCount
= src
->iNodesCount
;
313 dest
->iLastNodePlacedPosX
= src
->iLastNodePlacedPosX
;
317 static void chopAddTerrainNode(struct CTerrain
*ter
, int x
, int y
)
321 if(ter
->iNodesCount
+ 1 >= MAX_TERRAIN_NODES
)
323 /* DEBUGF("ERROR: Not enough nodes!\n"); */
329 i
= ter
->iNodesCount
- 1;
331 ter
->mNodes
[i
].x
= x
;
334 ter
->iLastNodePlacedPosX
= x
;
338 static void chopTerrainNodeDeleteAndShift(struct CTerrain
*ter
,int nodeIndex
)
342 while( i
< ter
->iNodesCount
)
344 ter
->mNodes
[i
- 1] = ter
->mNodes
[i
];
353 int chopUpdateTerrainRecycling(struct CTerrain
*ter
)
358 while(i
< ter
->iNodesCount
)
361 if( iCameraPosX
> ter
->mNodes
[i
].x
)
364 chopTerrainNodeDeleteAndShift(ter
,i
);
366 iNewNodePos
= ter
->iLastNodePlacedPosX
+ 50;
372 if(iLevelMode
== LEVEL_MODE_STEEP
)
375 chopAddTerrainNode(ter
,iNewNodePos
,g
- iR(-v
,v
));
387 int chopTerrainHeightAtPoint(struct CTerrain
*ter
, int pX
)
390 int iNodeIndexOne
=0,iNodeIndexTwo
=0, h
, terY1
, terY2
, terX1
, terX2
, a
, b
;
394 for(i
=1;i
<MAX_TERRAIN_NODES
;i
++)
396 if(ter
->mNodes
[i
].x
> pX
)
398 iNodeIndexOne
= i
- 1;
404 iNodeIndexTwo
= iNodeIndexOne
+ 1;
405 terY1
= ter
->mNodes
[iNodeIndexOne
].y
;
406 terY2
= ter
->mNodes
[iNodeIndexTwo
].y
;
409 terX2
= ter
->mNodes
[iNodeIndexTwo
].x
- ter
->mNodes
[iNodeIndexOne
].x
;
411 pX
-= ter
->mNodes
[iNodeIndexOne
].x
;
424 int chopPointInTerrain(struct CTerrain
*ter
, int pX
, int pY
, int iTestType
)
426 int h
= chopTerrainHeightAtPoint(ter
, pX
);
434 static void chopAddBlock(int x
,int y
,int sx
,int sy
, int indexOverride
)
438 if(indexOverride
< 0)
440 while(mBlocks
[i
].bIsActive
&& i
< NUMBER_OF_BLOCKS
)
442 if(i
==NUMBER_OF_BLOCKS
)
444 DEBUGF("No blocks!\n");
451 mBlocks
[i
].bIsActive
= 1;
452 mBlocks
[i
].iWorldX
= x
;
453 mBlocks
[i
].iWorldY
= y
;
454 mBlocks
[i
].iSizeX
= sx
;
455 mBlocks
[i
].iSizeY
= sy
;
457 iLastBlockPlacedPosX
= x
;
460 static void chopAddParticle(int x
,int y
,int sx
,int sy
)
464 while(mParticles
[i
].bIsActive
&& i
< NUMBER_OF_PARTICLES
)
467 if(i
==NUMBER_OF_PARTICLES
)
470 mParticles
[i
].bIsActive
= 1;
471 mParticles
[i
].iWorldX
= x
;
472 mParticles
[i
].iWorldY
= y
;
473 mParticles
[i
].iSpeedX
= sx
;
474 mParticles
[i
].iSpeedY
= sy
;
477 static void chopGenerateBlockIfNeeded(void)
480 int DistSpeedX
= iPlayerSpeedX
* 5;
481 if(DistSpeedX
<200) DistSpeedX
= 200;
483 while(i
< NUMBER_OF_BLOCKS
)
485 if(!mBlocks
[i
].bIsActive
)
489 iX
= iLastBlockPlacedPosX
+ (350-DistSpeedX
);
493 sY
= blockh
+ iR(1,blockh
/3);
495 chopAddBlock(iX
,iY
,sX
,sY
,i
);
503 static int chopBlockCollideWithPlayer(struct CBlock
*mBlock
)
505 int px
= iPlayerPosX
;
506 int py
= iPlayerPosY
;
508 int x
= mBlock
->iWorldX
-17;
509 int y
= mBlock
->iWorldY
-11;
511 int x2
= x
+ mBlock
->iSizeX
+17;
512 int y2
= y
+ mBlock
->iSizeY
+11;
525 static int chopBlockOffscreen(struct CBlock
*mBlock
)
527 if(mBlock
->iWorldX
+ mBlock
->iSizeX
< iCameraPosX
)
533 static int chopParticleOffscreen(struct CParticle
*mParticle
)
535 if (mParticle
->iWorldX
< iCameraPosX
|| mParticle
->iWorldY
< 0 ||
536 mParticle
->iWorldY
> iScreenY
|| mParticle
->iWorldX
> iCameraPosX
+
545 static void chopKillPlayer(void)
549 for (i
= 0; i
< NUMBER_OF_PARTICLES
; i
++) {
550 mParticles
[i
].bIsActive
= 0;
551 chopAddParticle(iPlayerPosX
+ iR(0,20), iPlayerPosY
+ iR(0,20),
557 if (iPlayerAlive
== 0) {
558 rb
->lcd_set_drawmode(DRMODE_FG
);
560 rb
->lcd_set_foreground(LCD_LIGHTGRAY
);
562 rb
->splash(HZ
, "Game Over");
564 if (score
> highscore
) {
567 rb
->snprintf(scoretext
, sizeof(scoretext
), "New High Score: %d",
569 rb
->splash(HZ
*2, scoretext
);
572 rb
->splash(HZ
/4, "Press " ACTIONTEXT
" to continue");
575 rb
->lcd_set_drawmode(DRMODE_SOLID
);
578 button
= rb
->button_get(true);
585 button
= rb
->button_get(true);
586 if (button
== (ACTION
| BUTTON_REL
)
588 || button
== (ACTION2
| BUTTON_REL
)
603 static void chopDrawTheWorld(void)
607 while(i
< NUMBER_OF_BLOCKS
)
609 if(mBlocks
[i
].bIsActive
)
611 if(chopBlockOffscreen(&mBlocks
[i
]) == 1)
612 mBlocks
[i
].bIsActive
= 0;
614 chopDrawBlock(&mBlocks
[i
]);
622 while(i
< NUMBER_OF_PARTICLES
)
624 if(mParticles
[i
].bIsActive
)
626 if(chopParticleOffscreen(&mParticles
[i
]) == 1)
627 mParticles
[i
].bIsActive
= 0;
629 chopDrawParticle(&mParticles
[i
]);
635 chopRenderTerrain(&mGround
);
636 chopRenderTerrain(&mRoof
);
640 static void chopDrawParticle(struct CParticle
*mParticle
)
643 int iPosX
= (mParticle
->iWorldX
- iCameraPosX
);
644 int iPosY
= (mParticle
->iWorldY
);
646 rb
->lcd_set_foreground(LCD_RGBPACK(192,192,192));
648 rb
->lcd_set_foreground(LCD_LIGHTGRAY
);
650 rb
->lcd_fillrect(SCALE(iPosX
), SCALE(iPosY
), SCALE(3), SCALE(3));
654 static void chopDrawScene(void)
659 rb
->lcd_set_background(LCD_BLACK
);
661 rb
->lcd_set_background(LCD_WHITE
);
664 chopDrawPlayer(iPlayerPosX
- iCameraPosX
, iPlayerPosY
);
666 score
= -20 + iPlayerPosX
/3;
669 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
671 rb
->lcd_set_drawmode(DRMODE_FG
);
675 rb
->lcd_set_foreground(LCD_BLACK
);
677 rb
->lcd_set_foreground(LCD_WHITE
);
681 rb
->snprintf(s
, sizeof(s
), "Dist: %d", score
);
683 rb
->snprintf(s
, sizeof(s
), "Distance: %d", score
);
685 rb
->lcd_getstringsize(s
, &w
, NULL
);
686 rb
->lcd_putsxy(2, 2, s
);
687 if (score
< highscore
)
691 rb
->snprintf(s
, sizeof(s
), "Hi: %d", highscore
);
693 rb
->snprintf(s
, sizeof(s
), "Best: %d", highscore
);
695 rb
->lcd_getstringsize(s
, &w2
, NULL
);
696 if (LCD_WIDTH
- 2 - w2
> w
+ 2)
697 rb
->lcd_putsxy(LCD_WIDTH
- 2 - w2
, 2, s
);
699 rb
->lcd_set_drawmode(DRMODE_SOLID
);
705 static int chopMenuCb(int action
, const struct menu_item_ex
*this_item
)
707 if(action
== ACTION_REQUEST_MENUITEM
708 && !_ingame
&& ((intptr_t)this_item
)==0)
709 return ACTION_EXIT_MENUITEM
;
712 static int chopMenu(int menunum
)
716 bool menu_quit
= false;
718 static const struct opt_items levels
[2] = {
723 MENUITEM_STRINGLIST(menu
,"Chopper Menu",chopMenuCb
,
724 "Resume Game","Start New Game",
725 "Level","Playback Control","Quit");
726 _ingame
= (menunum
!=0);
728 #ifdef HAVE_LCD_COLOR
729 rb
->lcd_set_foreground(LCD_WHITE
);
730 rb
->lcd_set_background(LCD_BLACK
);
732 rb
->lcd_set_foreground(LCD_BLACK
);
733 rb
->lcd_set_background(LCD_WHITE
);
736 rb
->lcd_clear_display();
739 switch(rb
->do_menu(&menu
, &result
, NULL
, false))
741 case 0: /* Resume Game */
745 case 1: /* Start New Game */
751 rb
->set_option("Level", &iLevelMode
, INT
, levels
, 2, NULL
);
754 playback_control(NULL
);
760 case MENU_ATTACHED_USB
:
762 res
= PLUGIN_USB_CONNECTED
;
766 rb
->lcd_clear_display();
770 static int chopGameLoop(void)
772 int move_button
, ret
;
774 int end
, i
=0, bdelay
=0, last_button
=BUTTON_NONE
;
776 if (chopUpdateTerrainRecycling(&mGround
) == 1)
777 /* mirror the sky if we've changed the ground */
778 chopCopyTerrain(&mGround
, &mRoof
, 0, - ( (iScreenY
* 3) / 4));
788 end
= *rb
->current_tick
+ (CYCLETIME
* HZ
) / 1000;
790 if(chopUpdateTerrainRecycling(&mGround
) == 1)
791 /* mirror the sky if we've changed the ground */
792 chopCopyTerrain(&mGround
, &mRoof
, 0, - ( (iScreenY
* 3) / 4));
794 iRotorOffset
= iR(-1,1);
796 /* We need to have this here so particles move when we're dead */
798 for (i
=0; i
< NUMBER_OF_PARTICLES
; i
++)
799 if(mParticles
[i
].bIsActive
== 1)
801 mParticles
[i
].iWorldX
+= mParticles
[i
].iSpeedX
;
802 mParticles
[i
].iWorldY
+= mParticles
[i
].iSpeedY
;
805 rb
->lcd_clear_display();
806 /* Redraw the main window: */
810 iGravityTimerCountdown
--;
812 if(iGravityTimerCountdown
<= 0)
814 iGravityTimerCountdown
= 3;
815 chopAddParticle(iPlayerPosX
, iPlayerPosY
+5, 0, 0);
818 if(iLevelMode
== LEVEL_MODE_NORMAL
)
819 chopGenerateBlockIfNeeded();
822 move_button
=rb
->button_status();
823 if (rb
->button_get(false) == QUIT
) {
828 last_button
= BUTTON_NONE
;
829 move_button
= BUTTON_NONE
;
832 switch (move_button
) {
837 if (last_button
!= ACTION
839 && last_button
!= ACTION2
848 if (last_button
== ACTION
850 || last_button
== ACTION2
857 if (rb
->default_event_handler(move_button
) == SYS_USB_CONNECTED
)
858 return PLUGIN_USB_CONNECTED
;
861 last_button
= move_button
;
864 iPlayerSpeedY
= bdelay
;
866 } else if (bdelay
> 0) {
867 iPlayerSpeedY
= bdelay
;
871 iCameraPosX
= iPlayerPosX
- 25;
872 iPlayerPosX
+= iPlayerSpeedX
;
873 iPlayerPosY
+= iPlayerSpeedY
;
876 /* increase speed as we go along */
877 if (chopCounter
== 100){
882 if (iPlayerPosY
> iScreenY
-10 || iPlayerPosY
< -5 ||
883 chopPointInTerrain(&mGround
, iPlayerPosX
, iPlayerPosY
+ 10, 0) ||
884 chopPointInTerrain(&mRoof
, iPlayerPosX
,iPlayerPosY
, 1))
893 for (i
=0; i
< NUMBER_OF_BLOCKS
; i
++)
894 if(mBlocks
[i
].bIsActive
== 1)
895 if(chopBlockCollideWithPlayer(&mBlocks
[i
])) {
903 if (end
> *rb
->current_tick
)
904 rb
->sleep(end
-*rb
->current_tick
);
912 static void chopDrawBlock(struct CBlock
*mBlock
)
914 int iPosX
= (mBlock
->iWorldX
- iCameraPosX
);
915 int iPosY
= (mBlock
->iWorldY
);
917 rb
->lcd_set_foreground(LCD_RGBPACK(100,255,100));
919 rb
->lcd_set_foreground(LCD_BLACK
);
921 rb
->lcd_fillrect(SCALE(iPosX
), SCALE(iPosY
), SCALE(mBlock
->iSizeX
),
922 SCALE(mBlock
->iSizeY
));
926 static void chopRenderTerrain(struct CTerrain
*ter
)
934 if(ter
->mNodes
[0].y
< (LCD_HEIGHT
*SIZE
)/2)
937 ay
=(LCD_HEIGHT
*SIZE
);
939 while(i
< ter
->iNodesCount
&& oldx
< iScreenX
)
942 int x
= ter
->mNodes
[i
-1].x
- iCameraPosX
;
943 int y
= ter
->mNodes
[i
-1].y
;
945 int x2
= ter
->mNodes
[i
].x
- iCameraPosX
;
946 int y2
= ter
->mNodes
[i
].y
;
948 rb
->lcd_set_foreground(LCD_RGBPACK(100,255,100));
950 rb
->lcd_set_foreground(LCD_DARKGRAY
);
953 rb
->lcd_drawline(SCALE(x
), SCALE(y
), SCALE(x2
), SCALE(y2
));
955 xlcd_filltriangle(SCALE(x
), SCALE(y
), SCALE(x2
), SCALE(y2
),
956 SCALE(x2
), SCALE(ay
));
957 xlcd_filltriangle(SCALE(x
), SCALE(ay
), SCALE(x2
), SCALE(y2
),
958 SCALE(x2
), SCALE(ay
));
961 xlcd_filltriangle(SCALE(x
), SCALE(ay
), SCALE(x
), SCALE(y
),
962 SCALE(x2
), SCALE(y2
/ 2));
964 xlcd_filltriangle(SCALE(x
), SCALE(ay
), SCALE(x
), SCALE(y
),
965 SCALE(x2
), SCALE((LCD_HEIGHT
*SIZE
) -
966 ((LCD_HEIGHT
*SIZE
) - y2
) / 2));
975 void chopper_load(bool newgame
)
982 iScreenX
= LCD_WIDTH
* SIZE
;
983 iScreenY
= LCD_HEIGHT
* SIZE
;
984 blockh
= iScreenY
/ 5;
985 blockw
= iScreenX
/ 20;
991 iPlayerPosY
= (iScreenY
* 4) / 10;
992 iLastBlockPlacedPosX
= 0;
993 iGravityTimerCountdown
= 2;
999 for (i
=0; i
< NUMBER_OF_PARTICLES
; i
++)
1000 mParticles
[i
].bIsActive
= 0;
1002 for (i
=0; i
< NUMBER_OF_BLOCKS
; i
++)
1003 mBlocks
[i
].bIsActive
= 0;
1006 chopClearTerrain(&mGround
);
1008 for (i
=0; i
< MAX_TERRAIN_NODES
; i
++)
1009 chopAddTerrainNode(&mGround
,i
* 30,g
- iR(0,20));
1011 if (chopUpdateTerrainRecycling(&mGround
) == 1)
1012 /* mirror the sky if we've changed the ground */
1013 chopCopyTerrain(&mGround
, &mRoof
, 0, - ( (iScreenY
* 3) / 4));
1015 iLevelMode
= LEVEL_MODE_NORMAL
;
1016 if (iLevelMode
== LEVEL_MODE_NORMAL
)
1017 /* make it a bit more exciting, cause it's easy terrain... */
1021 /* this is the plugin entry point */
1022 enum plugin_status
plugin_start(const void* parameter
)
1027 rb
->lcd_setfont(FONT_SYSFIXED
);
1029 rb
->lcd_set_backdrop(NULL
);
1031 #ifdef HAVE_LCD_COLOR
1032 rb
->lcd_set_background(LCD_BLACK
);
1033 rb
->lcd_set_foreground(LCD_WHITE
);
1036 /* Turn off backlight timeout */
1037 backlight_force_on(); /* backlight control in lib/helper.c */
1039 rb
->srand( *rb
->current_tick
);
1041 configfile_load(CFG_FILE
, config
, 1, 0);
1044 ret
= chopGameLoop();
1046 configfile_save(CFG_FILE
, config
, 1, 0);
1048 rb
->lcd_setfont(FONT_UI
);
1049 /* Turn on backlight timeout (revert to settings) */
1050 backlight_use_settings(); /* backlight control in lib/helper.c */