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 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
75 #define QUIT BUTTON_POWER
76 #define ACTION BUTTON_SELECT
77 #define ACTIONTEXT "SELECT"
79 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
80 #define QUIT BUTTON_HOME
81 #define ACTION BUTTON_SELECT
82 #define ACTIONTEXT "SELECT"
84 #elif CONFIG_KEYPAD == GIGABEAT_PAD
85 #define QUIT BUTTON_MENU
86 #define ACTION BUTTON_SELECT
87 #define ACTIONTEXT "SELECT"
89 #elif CONFIG_KEYPAD == RECORDER_PAD
90 #define QUIT BUTTON_OFF
91 #define ACTION BUTTON_PLAY
92 #define ACTIONTEXT "PLAY"
94 #elif CONFIG_KEYPAD == ONDIO_PAD
95 #define QUIT BUTTON_OFF
96 #define ACTION BUTTON_UP
97 #define ACTION2 BUTTON_MENU
98 #define ACTIONTEXT "UP"
100 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD \
101 || CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
102 #define QUIT BUTTON_BACK
103 #define ACTION BUTTON_SELECT
104 #define ACTION2 BUTTON_MENU
105 #define ACTIONTEXT "SELECT"
107 #elif CONFIG_KEYPAD == MROBE100_PAD
108 #define QUIT BUTTON_POWER
109 #define ACTION BUTTON_SELECT
110 #define ACTIONTEXT "SELECT"
112 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
113 #define QUIT BUTTON_RC_REC
114 #define ACTION BUTTON_RC_PLAY
115 #define ACTION2 BUTTON_RC_MODE
116 #define ACTIONTEXT "PLAY"
118 #elif CONFIG_KEYPAD == COWON_D2_PAD
119 #define QUIT BUTTON_POWER
120 #define ACTION2 BUTTON_PLUS
122 #elif CONFIG_KEYPAD == IAUDIO67_PAD
123 #define QUIT BUTTON_POWER
124 #define ACTION BUTTON_PLAY
125 #define ACTION2 BUTTON_STOP
126 #define ACTIONTEXT "PLAY"
128 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
129 #define QUIT BUTTON_BACK
130 #define ACTION BUTTON_UP
131 #define ACTION2 BUTTON_MENU
132 #define ACTIONTEXT "UP"
134 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
135 #define QUIT BUTTON_POWER
136 #define ACTION BUTTON_MENU
137 #define ACTION2 BUTTON_SELECT
138 #define ACTIONTEXT "MENU"
140 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
141 #define QUIT BUTTON_POWER
142 #define ACTION BUTTON_MENU
143 #define ACTION2 BUTTON_PLAY
144 #define ACTIONTEXT "MENU"
146 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
147 #define QUIT BUTTON_POWER
148 #define ACTION BUTTON_MENU
149 #define ACTION2 BUTTON_PLAY
150 #define ACTIONTEXT "MENU"
152 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
153 CONFIG_KEYPAD == ONDAVX777_PAD || \
154 CONFIG_KEYPAD == MROBE500_PAD
155 #define QUIT BUTTON_POWER
157 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
158 #define QUIT BUTTON_LEFT
159 #define ACTION BUTTON_RIGHT
160 #define ACTIONTEXT "RIGHT"
162 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
163 #define QUIT BUTTON_REC
164 #define ACTION BUTTON_PLAY
165 #define ACTION2 BUTTON_UP
166 #define ACTIONTEXT "PLAY"
168 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
169 #define QUIT (BUTTON_REC|BUTTON_PLAY)
170 #define ACTION BUTTON_FUNC
171 #define ACTIONTEXT "FUNC"
173 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
174 #define QUIT (BUTTON_MENU|BUTTON_REPEAT)
175 #define ACTION BUTTON_ENTER
176 #define ACTIONTEXT "ENTER"
178 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
179 #define QUIT BUTTON_POWER
180 #define ACTION BUTTON_SELECT
181 #define ACTIONTEXT "SELECT"
183 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
184 (CONFIG_KEYPAD == HM801_PAD)
185 #define QUIT BUTTON_POWER
186 #define ACTION BUTTON_SELECT
187 #define ACTIONTEXT "SELECT"
189 #elif !defined(HAVE_TOUCHSCREEN)
190 #error No keymap defined!
193 #ifdef HAVE_TOUCHSCREEN
195 #define QUIT BUTTON_TOPLEFT
198 #define ACTION BUTTON_BOTTOMLEFT
201 #define ACTION2 BUTTON_BOTTOMRIGHT
204 #define ACTIONTEXT "BOTTOMRIGHT"
208 #define NUMBER_OF_BLOCKS 8
209 #define NUMBER_OF_PARTICLES 3
210 #define MAX_TERRAIN_NODES 15
212 #define LEVEL_MODE_NORMAL 0
213 #define LEVEL_MODE_STEEP 1
217 static inline int SCALE(int x
)
219 return x
== 1 ? x
: x
>> 1;
228 /* in 10 milisecond (ticks) */
229 #define CYCLETIME ((CYCLES*HZ)/1000)
231 /*Chopper's local variables to track the terrain position etc*/
232 static int chopCounter
;
233 static int iRotorOffset
;
236 static int iPlayerPosX
;
237 static int iPlayerPosY
;
238 static int iCameraPosX
;
239 static int iPlayerSpeedX
;
240 static int iPlayerSpeedY
;
241 static int iLastBlockPlacedPosX
;
242 static int iGravityTimerCountdown
;
243 static int iPlayerAlive
;
244 static int iLevelMode
, iCurrLevelMode
;
245 static int blockh
,blockw
;
246 static int highscore
;
249 #define CFG_FILE "chopper.cfg"
250 #define MAX_POINTS 50000
251 static struct configdata config
[] =
253 {TYPE_INT
, 0, MAX_POINTS
, { .int_p
= &highscore
}, "highscore", NULL
}
286 struct CTerrainNode mNodes
[MAX_TERRAIN_NODES
];
288 int iLastNodePlacedPosX
;
291 struct CBlock mBlocks
[NUMBER_OF_BLOCKS
];
292 struct CParticle mParticles
[NUMBER_OF_PARTICLES
];
294 struct CTerrain mGround
;
295 struct CTerrain mRoof
;
297 /*Function declarations*/
298 static void chopDrawParticle(struct CParticle
*mParticle
);
299 static void chopDrawBlock(struct CBlock
*mBlock
);
300 static void chopRenderTerrain(struct CTerrain
*ter
, bool isground
);
301 static void chopper_load(bool newgame
);
303 static void chopDrawPlayer(int x
,int y
) /* These are SCREEN coords, not world!*/
307 rb
->lcd_set_foreground(LCD_RGBPACK(50,50,200));
309 rb
->lcd_set_foreground(LCD_DARKGRAY
);
311 rb
->lcd_fillrect(SCALE(x
+6), SCALE(y
+2), SCALE(12), SCALE(9));
312 rb
->lcd_fillrect(SCALE(x
-3), SCALE(y
+6), SCALE(20), SCALE(3));
315 rb
->lcd_set_foreground(LCD_RGBPACK(50,50,50));
317 rb
->lcd_set_foreground(LCD_DARKGRAY
);
319 rb
->lcd_fillrect(SCALE(x
+10), SCALE(y
), SCALE(2), SCALE(3));
320 rb
->lcd_fillrect(SCALE(x
+10), SCALE(y
), SCALE(1), SCALE(3));
323 rb
->lcd_set_foreground(LCD_RGBPACK(40,40,100));
325 rb
->lcd_set_foreground(LCD_BLACK
);
327 rb
->lcd_drawline(SCALE(x
), SCALE(y
+iRotorOffset
), SCALE(x
+20),
328 SCALE(y
-iRotorOffset
));
331 rb
->lcd_set_foreground(LCD_RGBPACK(20,20,50));
333 rb
->lcd_set_foreground(LCD_BLACK
);
335 rb
->lcd_fillrect(SCALE(x
- 2), SCALE(y
+ 5), SCALE(2), SCALE(5));
339 static void chopClearTerrain(struct CTerrain
*ter
)
341 ter
->iNodesCount
= 0;
345 static int iR(int low
,int high
)
347 return low
+rb
->rand()%(high
-low
+1);
350 static void chopCopyTerrain(struct CTerrain
*src
, struct CTerrain
*dest
,
351 int xOffset
,int yOffset
)
355 while(i
< src
->iNodesCount
)
357 dest
->mNodes
[i
].x
= src
->mNodes
[i
].x
+ xOffset
;
358 dest
->mNodes
[i
].y
= src
->mNodes
[i
].y
+ yOffset
;
363 dest
->iNodesCount
= src
->iNodesCount
;
364 dest
->iLastNodePlacedPosX
= src
->iLastNodePlacedPosX
;
368 static void chopAddTerrainNode(struct CTerrain
*ter
, int x
, int y
)
372 if(ter
->iNodesCount
+ 1 >= MAX_TERRAIN_NODES
)
374 /* DEBUGF("ERROR: Not enough nodes!\n"); */
380 i
= ter
->iNodesCount
- 1;
382 ter
->mNodes
[i
].x
= x
;
385 ter
->iLastNodePlacedPosX
= x
;
389 static void chopTerrainNodeDeleteAndShift(struct CTerrain
*ter
,int nodeIndex
)
393 while( i
< ter
->iNodesCount
)
395 ter
->mNodes
[i
- 1] = ter
->mNodes
[i
];
404 static int chopUpdateTerrainRecycling(struct CTerrain
*ter
)
408 while(i
< ter
->iNodesCount
)
411 if( iCameraPosX
> ter
->mNodes
[i
].x
)
414 chopTerrainNodeDeleteAndShift(ter
,i
);
416 iNewNodePos
= ter
->iLastNodePlacedPosX
+ 50;
422 if(iCurrLevelMode
== LEVEL_MODE_STEEP
)
425 chopAddTerrainNode(ter
,iNewNodePos
,g
- iR(-v
,v
));
435 static int chopTerrainHeightAtPoint(struct CTerrain
*ter
, int pX
)
438 int iNodeIndexOne
=0,iNodeIndexTwo
=0, h
, terY1
, terY2
, terX2
, a
, b
;
442 for(i
=1;i
<MAX_TERRAIN_NODES
;i
++)
444 if(ter
->mNodes
[i
].x
> pX
)
446 iNodeIndexOne
= i
- 1;
452 iNodeIndexTwo
= iNodeIndexOne
+ 1;
453 terY1
= ter
->mNodes
[iNodeIndexOne
].y
;
454 terY2
= ter
->mNodes
[iNodeIndexTwo
].y
;
457 terX2
= ter
->mNodes
[iNodeIndexTwo
].x
- ter
->mNodes
[iNodeIndexOne
].x
;
459 pX
-= ter
->mNodes
[iNodeIndexOne
].x
;
472 static int chopPointInTerrain(struct CTerrain
*ter
, int pX
, int pY
, int iTestType
)
474 int h
= chopTerrainHeightAtPoint(ter
, pX
);
482 static void chopAddBlock(int x
,int y
,int sx
,int sy
, int indexOverride
)
486 if(indexOverride
< 0)
488 while(mBlocks
[i
].bIsActive
&& i
< NUMBER_OF_BLOCKS
)
490 if(i
==NUMBER_OF_BLOCKS
)
492 DEBUGF("No blocks!\n");
499 mBlocks
[i
].bIsActive
= 1;
500 mBlocks
[i
].iWorldX
= x
;
501 mBlocks
[i
].iWorldY
= y
;
502 mBlocks
[i
].iSizeX
= sx
;
503 mBlocks
[i
].iSizeY
= sy
;
505 iLastBlockPlacedPosX
= x
;
508 static void chopAddParticle(int x
,int y
,int sx
,int sy
)
512 while(mParticles
[i
].bIsActive
&& i
< NUMBER_OF_PARTICLES
)
515 if(i
==NUMBER_OF_PARTICLES
)
518 mParticles
[i
].bIsActive
= 1;
519 mParticles
[i
].iWorldX
= x
;
520 mParticles
[i
].iWorldY
= y
;
521 mParticles
[i
].iSpeedX
= sx
;
522 mParticles
[i
].iSpeedY
= sy
;
525 static void chopGenerateBlockIfNeeded(void)
528 int DistSpeedX
= iPlayerSpeedX
* 5;
529 if(DistSpeedX
<200) DistSpeedX
= 200;
531 while(i
< NUMBER_OF_BLOCKS
)
533 if(!mBlocks
[i
].bIsActive
)
537 iX
= iLastBlockPlacedPosX
+ (350-DistSpeedX
);
541 sY
= blockh
+ iR(1,blockh
/3);
543 chopAddBlock(iX
,iY
,sX
,sY
,i
);
551 static int chopBlockCollideWithPlayer(struct CBlock
*mBlock
)
553 int px
= iPlayerPosX
;
554 int py
= iPlayerPosY
;
556 int x
= mBlock
->iWorldX
-17;
557 int y
= mBlock
->iWorldY
-11;
559 int x2
= x
+ mBlock
->iSizeX
+17;
560 int y2
= y
+ mBlock
->iSizeY
+11;
573 static int chopBlockOffscreen(struct CBlock
*mBlock
)
575 if(mBlock
->iWorldX
+ mBlock
->iSizeX
< iCameraPosX
)
581 static int chopParticleOffscreen(struct CParticle
*mParticle
)
583 if (mParticle
->iWorldX
< iCameraPosX
|| mParticle
->iWorldY
< 0 ||
584 mParticle
->iWorldY
> iScreenY
|| mParticle
->iWorldX
> iCameraPosX
+
593 static void chopKillPlayer(void)
597 for (i
= 0; i
< NUMBER_OF_PARTICLES
; i
++) {
598 mParticles
[i
].bIsActive
= 0;
599 chopAddParticle(iPlayerPosX
+ iR(0,20), iPlayerPosY
+ iR(0,20),
605 if (iPlayerAlive
== 0) {
606 rb
->splash(HZ
, "Game Over");
608 if (score
> highscore
) {
611 rb
->snprintf(scoretext
, sizeof(scoretext
), "New High Score: %d",
613 rb
->splash(HZ
*2, scoretext
);
619 static void chopDrawTheWorld(void)
623 while(i
< NUMBER_OF_BLOCKS
)
625 if(mBlocks
[i
].bIsActive
)
627 if(chopBlockOffscreen(&mBlocks
[i
]) == 1)
628 mBlocks
[i
].bIsActive
= 0;
630 chopDrawBlock(&mBlocks
[i
]);
638 while(i
< NUMBER_OF_PARTICLES
)
640 if(mParticles
[i
].bIsActive
)
642 if(chopParticleOffscreen(&mParticles
[i
]) == 1)
643 mParticles
[i
].bIsActive
= 0;
645 chopDrawParticle(&mParticles
[i
]);
651 chopRenderTerrain(&mGround
, true);
652 chopRenderTerrain(&mRoof
, false);
656 static void chopDrawParticle(struct CParticle
*mParticle
)
659 int iPosX
= (mParticle
->iWorldX
- iCameraPosX
);
660 int iPosY
= (mParticle
->iWorldY
);
662 rb
->lcd_set_foreground(LCD_RGBPACK(192,192,192));
664 rb
->lcd_set_foreground(LCD_LIGHTGRAY
);
666 rb
->lcd_fillrect(SCALE(iPosX
), SCALE(iPosY
), SCALE(3), SCALE(3));
670 static void chopDrawScene(void)
675 rb
->lcd_set_background(LCD_BLACK
);
677 rb
->lcd_set_background(LCD_WHITE
);
679 rb
->lcd_clear_display();
681 chopDrawPlayer(iPlayerPosX
- iCameraPosX
, iPlayerPosY
);
683 score
= -20 + iPlayerPosX
/3;
686 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
688 rb
->lcd_set_drawmode(DRMODE_FG
);
692 rb
->lcd_set_foreground(LCD_BLACK
);
694 rb
->lcd_set_foreground(LCD_WHITE
);
698 rb
->snprintf(s
, sizeof(s
), "Dist: %d", score
);
700 rb
->snprintf(s
, sizeof(s
), "Distance: %d", score
);
702 rb
->lcd_getstringsize(s
, &w
, NULL
);
703 rb
->lcd_putsxy(2, 2, s
);
704 if (score
< highscore
)
708 rb
->snprintf(s
, sizeof(s
), "Hi: %d", highscore
);
710 rb
->snprintf(s
, sizeof(s
), "Best: %d", highscore
);
712 rb
->lcd_getstringsize(s
, &w2
, NULL
);
713 if (LCD_WIDTH
- 2 - w2
> w
+ 2)
714 rb
->lcd_putsxy(LCD_WIDTH
- 2 - w2
, 2, s
);
716 rb
->lcd_set_drawmode(DRMODE_SOLID
);
722 static int chopMenuCb(int action
, const struct menu_item_ex
*this_item
)
724 if(action
== ACTION_REQUEST_MENUITEM
725 && !_ingame
&& ((intptr_t)this_item
)==0)
726 return ACTION_EXIT_MENUITEM
;
729 static int chopMenu(int menunum
)
733 bool menu_quit
= false;
735 static const struct opt_items levels
[2] = {
740 MENUITEM_STRINGLIST(menu
,"Chopper Menu",chopMenuCb
,
741 "Resume Game","Start New Game",
742 "Level","Playback Control","Quit");
743 _ingame
= (menunum
!=0);
745 #ifdef HAVE_LCD_COLOR
746 rb
->lcd_set_foreground(LCD_WHITE
);
747 rb
->lcd_set_background(LCD_BLACK
);
749 rb
->lcd_set_foreground(LCD_BLACK
);
750 rb
->lcd_set_background(LCD_WHITE
);
753 rb
->lcd_clear_display();
754 rb
->button_clear_queue();
757 switch(rb
->do_menu(&menu
, &result
, NULL
, false))
759 case 0: /* Resume Game */
763 case 1: /* Start New Game */
769 rb
->set_option("Level", &iLevelMode
, INT
, levels
, 2, NULL
);
772 playback_control(NULL
);
778 case MENU_ATTACHED_USB
:
780 res
= PLUGIN_USB_CONNECTED
;
784 rb
->lcd_clear_display();
788 static int chopGameLoop(void)
790 int move_button
, ret
;
792 int end
, i
=0, bdelay
=0, last_button
=BUTTON_NONE
;
794 if (chopUpdateTerrainRecycling(&mGround
) == 1)
795 /* mirror the sky if we've changed the ground */
796 chopCopyTerrain(&mGround
, &mRoof
, 0, - ( (iScreenY
* 3) / 4));
806 end
= *rb
->current_tick
+ CYCLETIME
;
808 if(chopUpdateTerrainRecycling(&mGround
) == 1)
809 /* mirror the sky if we've changed the ground */
810 chopCopyTerrain(&mGround
, &mRoof
, 0, - ( (iScreenY
* 3) / 4));
812 iRotorOffset
= iR(-1,1);
814 /* We need to have this here so particles move when we're dead */
816 for (i
=0; i
< NUMBER_OF_PARTICLES
; i
++)
817 if(mParticles
[i
].bIsActive
== 1)
819 mParticles
[i
].iWorldX
+= mParticles
[i
].iSpeedX
;
820 mParticles
[i
].iWorldY
+= mParticles
[i
].iSpeedY
;
823 /* Redraw the main window: */
827 iGravityTimerCountdown
--;
829 if(iGravityTimerCountdown
<= 0)
831 iGravityTimerCountdown
= 3;
832 chopAddParticle(iPlayerPosX
, iPlayerPosY
+5, 0, 0);
835 if(iCurrLevelMode
== LEVEL_MODE_NORMAL
)
836 chopGenerateBlockIfNeeded();
839 move_button
=rb
->button_status();
840 if (rb
->button_get(false) == QUIT
) {
845 last_button
= BUTTON_NONE
;
846 move_button
= BUTTON_NONE
;
849 switch (move_button
) {
854 if (last_button
!= ACTION
856 && last_button
!= ACTION2
865 if (last_button
== ACTION
867 || last_button
== ACTION2
874 if (rb
->default_event_handler(move_button
) == SYS_USB_CONNECTED
)
875 return PLUGIN_USB_CONNECTED
;
878 last_button
= move_button
;
881 iPlayerSpeedY
= bdelay
;
883 } else if (bdelay
> 0) {
884 iPlayerSpeedY
= bdelay
;
888 iCameraPosX
= iPlayerPosX
- 25;
889 iPlayerPosX
+= iPlayerSpeedX
;
890 iPlayerPosY
+= iPlayerSpeedY
;
893 /* increase speed as we go along */
894 if (chopCounter
== 100){
899 if (iPlayerPosY
> iScreenY
-10 || iPlayerPosY
< -5 ||
900 chopPointInTerrain(&mGround
, iPlayerPosX
, iPlayerPosY
+ 10, 0) ||
901 chopPointInTerrain(&mRoof
, iPlayerPosX
,iPlayerPosY
, 1))
910 for (i
=0; i
< NUMBER_OF_BLOCKS
; i
++)
911 if(mBlocks
[i
].bIsActive
== 1)
912 if(chopBlockCollideWithPlayer(&mBlocks
[i
])) {
920 if (TIME_BEFORE(*rb
->current_tick
, end
))
921 rb
->sleep(end
- *rb
->current_tick
); /* wait until time is over */
929 static void chopDrawBlock(struct CBlock
*mBlock
)
931 int iPosX
= (mBlock
->iWorldX
- iCameraPosX
);
932 int iPosY
= (mBlock
->iWorldY
);
934 rb
->lcd_set_foreground(LCD_RGBPACK(100,255,100));
936 rb
->lcd_set_foreground(LCD_BLACK
);
938 rb
->lcd_fillrect(SCALE(iPosX
), SCALE(iPosY
), SCALE(mBlock
->iSizeX
),
939 SCALE(mBlock
->iSizeY
));
943 static void chopRenderTerrain(struct CTerrain
*ter
, bool isground
)
950 while(i
< ter
->iNodesCount
&& oldx
< iScreenX
)
953 int x
= ter
->mNodes
[i
-1].x
- iCameraPosX
;
954 int y
= ter
->mNodes
[i
-1].y
;
956 int x2
= ter
->mNodes
[i
].x
- iCameraPosX
;
957 int y2
= ter
->mNodes
[i
].y
;
961 if ((y
< y2
) != isground
)
972 rb
->lcd_set_foreground(LCD_RGBPACK(100,255,100));
974 rb
->lcd_set_foreground(LCD_DARKGRAY
);
977 rb
->lcd_drawline(SCALE(x
), SCALE(y
), SCALE(x2
), SCALE(y2
));
979 xlcd_filltriangle(SCALE(x
), SCALE(y
), SCALE(x2
), SCALE(y2
),
980 SCALE(ax
), SCALE(ay
));
985 y2
= (LCD_HEIGHT
*SIZE
);
993 rb
->lcd_fillrect(SCALE(x
), SCALE(y
), SCALE(x2
-x
)+1, SCALE(y2
-y
)+1);
1000 static void chopper_load(bool newgame
)
1007 iScreenX
= LCD_WIDTH
* SIZE
;
1008 iScreenY
= LCD_HEIGHT
* SIZE
;
1009 blockh
= iScreenY
/ 5;
1010 blockw
= iScreenX
/ 20;
1012 iCurrLevelMode
= iLevelMode
;
1017 iPlayerPosY
= (iScreenY
* 4) / 10;
1018 iLastBlockPlacedPosX
= 0;
1019 iGravityTimerCountdown
= 2;
1025 for (i
=0; i
< NUMBER_OF_PARTICLES
; i
++)
1026 mParticles
[i
].bIsActive
= 0;
1028 for (i
=0; i
< NUMBER_OF_BLOCKS
; i
++)
1029 mBlocks
[i
].bIsActive
= 0;
1032 chopClearTerrain(&mGround
);
1034 for (i
=0; i
< MAX_TERRAIN_NODES
; i
++)
1035 chopAddTerrainNode(&mGround
,i
* 30,g
- iR(0,20));
1037 if (chopUpdateTerrainRecycling(&mGround
) == 1)
1038 /* mirror the sky if we've changed the ground */
1039 chopCopyTerrain(&mGround
, &mRoof
, 0, - ( (iScreenY
* 3) / 4));
1041 if (iCurrLevelMode
== LEVEL_MODE_NORMAL
)
1042 /* make it a bit more exciting, cause it's easy terrain... */
1046 /* this is the plugin entry point */
1047 enum plugin_status
plugin_start(const void* parameter
)
1052 rb
->lcd_setfont(FONT_SYSFIXED
);
1054 rb
->lcd_set_backdrop(NULL
);
1056 #ifdef HAVE_LCD_COLOR
1057 rb
->lcd_set_background(LCD_BLACK
);
1058 rb
->lcd_set_foreground(LCD_WHITE
);
1061 /* Turn off backlight timeout */
1062 backlight_ignore_timeout();
1064 rb
->srand( *rb
->current_tick
);
1066 configfile_load(CFG_FILE
, config
, 1, 0);
1069 ret
= chopGameLoop();
1071 configfile_save(CFG_FILE
, config
, 1, 0);
1073 rb
->lcd_setfont(FONT_UI
);
1074 /* Turn on backlight timeout (revert to settings) */
1075 backlight_use_settings();