Get rid of the 'center' parameter for splashes. There were only 2 of almost 500 splas...
[Rockbox.git] / apps / plugins / pacbox / pacbox.c
blob3a5643010689d06f90095dc73ca102b76f6785cf
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Pacbox - a Pacman Emulator for Rockbox
12 * Based on PIE - Pacman Instructional Emulator
14 * Copyright (c) 1997-2003,2004 Alessandro Scotti
15 * http://www.ascotti.org/
17 * All files in this archive are subject to the GNU General Public License.
18 * See the file COPYING in the source tree root for full license agreement.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
25 #include "plugin.h"
26 #include "arcade.h"
27 #include "pacbox.h"
28 #include "pacbox_lcd.h"
29 #include "lib/configfile.h"
31 PLUGIN_HEADER
32 PLUGIN_IRAM_DECLARE
34 struct plugin_api* rb;
36 struct pacman_settings {
37 int difficulty;
38 int numlives;
39 int bonus;
40 int ghostnames;
41 int showfps;
44 static struct pacman_settings settings;
45 static struct pacman_settings old_settings;
47 #define SETTINGS_VERSION 1
48 #define SETTINGS_MIN_VERSION 1
49 #define SETTINGS_FILENAME "pacbox.cfg"
51 static char* difficulty_options[] = { "Normal", "Hard" };
52 static char* numlives_options[] = { "1", "2", "3", "5" };
53 static char* bonus_options[] = {"10000", "15000", "20000", "No Bonus"};
54 static char* ghostnames_options[] = {"Normal", "Alternate"};
55 static char* showfps_options[] = {"No", "Yes"};
57 static struct configdata config[] =
59 {TYPE_ENUM, 0, 2, &settings.difficulty, "Difficulty", difficulty_options, NULL},
60 {TYPE_ENUM, 0, 4, &settings.numlives, "Pacmen Per Game", numlives_options, NULL},
61 {TYPE_ENUM, 0, 4, &settings.bonus, "Bonus", bonus_options, NULL},
62 {TYPE_ENUM, 0, 2, &settings.ghostnames, "Ghost Names", ghostnames_options , NULL},
63 {TYPE_ENUM, 0, 2, &settings.showfps, "Show FPS", showfps_options, NULL},
66 static bool loadFile( const char * name, unsigned char * buf, int len )
68 char filename[MAX_PATH];
70 rb->snprintf(filename,sizeof(filename),"/.rockbox/pacman/%s",name);
72 int fd = rb->open( filename, O_RDONLY);
74 if( fd < 0 ) {
75 return false;
78 int n = rb->read( fd, buf, len);
80 rb->close( fd );
82 if( n != len ) {
83 return false;
86 return true;
89 static bool loadROMS( void )
91 bool romsLoaded = false;
93 romsLoaded = loadFile( "pacman.6e", ram_, 0x1000) &&
94 loadFile( "pacman.6f", ram_+0x1000, 0x1000) &&
95 loadFile( "pacman.6h", ram_+0x2000, 0x1000) &&
96 loadFile( "pacman.6j", ram_+0x3000, 0x1000) &&
97 loadFile( "pacman.5e", charset_rom_, 0x1000) &&
98 loadFile( "pacman.5f", spriteset_rom_, 0x1000);
100 if( romsLoaded ) {
101 decodeROMs();
102 reset_PacmanMachine();
105 return romsLoaded;
108 /* A buffer to render Pacman's 244x288 screen into */
109 static unsigned char video_buffer[ScreenWidth*ScreenHeight] __attribute__ ((aligned (16)));
111 static long start_time;
112 static long video_frames = 0;
114 static int dipDifficulty[] = { DipDifficulty_Normal, DipDifficulty_Hard };
115 static int dipLives[] = { DipLives_1, DipLives_2, DipLives_3, DipLives_5 };
116 static int dipBonus[] = { DipBonus_10000, DipBonus_15000, DipBonus_20000,
117 DipBonus_None };
118 static int dipGhostNames[] = { DipGhostNames_Normal, DipGhostNames_Alternate };
120 static int settings_to_dip(struct pacman_settings settings)
122 return ( DipPlay_OneCoinOneGame |
123 DipCabinet_Upright |
124 DipMode_Play |
125 DipRackAdvance_Off |
127 dipDifficulty[settings.difficulty] |
128 dipLives[settings.numlives] |
129 dipBonus[settings.bonus] |
130 dipGhostNames[settings.ghostnames]
134 static bool pacbox_menu(void)
136 int m;
137 int result;
138 int menu_quit=0;
139 int new_setting;
140 bool need_restart = false;
142 static const struct opt_items noyes[2] = {
143 { "No", -1 },
144 { "Yes", -1 },
147 static const struct opt_items difficulty_options[2] = {
148 { "Normal", -1 },
149 { "Harder", -1 },
152 static const struct opt_items numlives_options[4] = {
153 { "1", -1 },
154 { "2", -1 },
155 { "3", -1 },
156 { "5", -1 },
159 static const struct opt_items bonus_options[4] = {
160 { "10000 points", -1 },
161 { "15000 points", -1 },
162 { "20000 points", -1 },
163 { "No bonus", -1 },
166 static const struct opt_items ghostname_options[2] = {
167 { "Normal", -1 },
168 { "Alternate", -1 },
171 static const struct menu_item items[] = {
172 { "Difficulty", NULL },
173 { "Pacmen Per Game", NULL },
174 { "Bonus Life", NULL },
175 { "Ghost Names", NULL },
176 { "Display FPS", NULL },
177 { "Restart", NULL },
178 { "Quit", NULL },
181 m = rb->menu_init(items, sizeof(items) / sizeof(*items),
182 NULL, NULL, NULL, NULL);
184 rb->button_clear_queue();
186 while (!menu_quit) {
187 result=rb->menu_show(m);
189 switch(result)
191 case 0:
192 new_setting=settings.difficulty;
193 rb->set_option("Difficulty", &new_setting, INT,
194 difficulty_options , 2, NULL);
195 if (new_setting != settings.difficulty) {
196 settings.difficulty=new_setting;
197 need_restart=true;
199 break;
200 case 1:
201 new_setting=settings.numlives;
202 rb->set_option("Pacmen Per Game", &new_setting, INT,
203 numlives_options , 4, NULL);
204 if (new_setting != settings.numlives) {
205 settings.numlives=new_setting;
206 need_restart=true;
208 break;
209 case 2:
210 new_setting=settings.bonus;
211 rb->set_option("Bonus Life", &new_setting, INT,
212 bonus_options , 4, NULL);
213 if (new_setting != settings.bonus) {
214 settings.bonus=new_setting;
215 need_restart=true;
217 break;
218 case 3:
219 new_setting=settings.ghostnames;
220 rb->set_option("Ghost Names", &new_setting, INT,
221 ghostname_options , 2, NULL);
222 if (new_setting != settings.ghostnames) {
223 settings.ghostnames=new_setting;
224 need_restart=true;
226 break;
227 case 4: /* Show FPS */
228 rb->set_option("Display FPS",&settings.showfps,INT,
229 noyes, 2, NULL);
230 break;
231 case 5: /* Restart */
232 need_restart=true;
233 menu_quit=1;
234 break;
235 default:
236 menu_quit=1;
237 break;
241 rb->menu_exit(m);
243 if (need_restart) {
244 init_PacmanMachine(settings_to_dip(settings));
247 /* Possible results:
248 exit game
249 restart game
250 usb connected
252 return (result==6);
257 Runs the game engine for one frame.
259 static int gameProc( void )
261 int x;
262 int fps;
263 char str[80];
264 int status;
265 long end_time;
266 int frame_counter = 0;
267 int yield_counter = 0;
269 while (1)
271 /* Run the machine for one frame (1/60th second) */
272 run();
274 frame_counter++;
276 /* Check the button status */
277 status = rb->button_status();
279 #ifdef HAS_BUTTON_HOLD
280 if (rb->button_hold())
281 status = PACMAN_MENU;
282 #endif
284 if ((status & PACMAN_MENU) == PACMAN_MENU
285 #ifdef PACMAN_RC_MENU
286 || status == PACMAN_RC_MENU
287 #endif
289 end_time = *rb->current_tick;
290 x = pacbox_menu();
291 rb->lcd_clear_display();
292 #ifdef HAVE_REMOTE_LCD
293 rb->lcd_remote_clear_display();
294 rb->lcd_remote_update();
295 #endif
296 if (x == 1) { return 1; }
297 start_time += *rb->current_tick-end_time;
300 #ifdef PACMAN_HAS_REMOTE
301 setDeviceMode( Joy1_Left, (status & PACMAN_LEFT || status == PACMAN_RC_LEFT) ? DeviceOn : DeviceOff);
302 setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT || status == PACMAN_RC_RIGHT) ? DeviceOn : DeviceOff);
303 setDeviceMode( Joy1_Up, (status & PACMAN_UP || status == PACMAN_RC_UP) ? DeviceOn : DeviceOff);
304 setDeviceMode( Joy1_Down, (status & PACMAN_DOWN || status == PACMAN_RC_DOWN) ? DeviceOn : DeviceOff);
305 setDeviceMode( CoinSlot_1, (status & PACMAN_COIN || status == PACMAN_RC_COIN) ? DeviceOn : DeviceOff);
306 setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP || status == PACMAN_RC_1UP) ? DeviceOn : DeviceOff);
307 setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP || status == PACMAN_RC_2UP) ? DeviceOn : DeviceOff);
308 #else
309 setDeviceMode( Joy1_Left, (status & PACMAN_LEFT) ? DeviceOn : DeviceOff);
310 setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT) ? DeviceOn : DeviceOff);
311 setDeviceMode( Joy1_Up, (status & PACMAN_UP) ? DeviceOn : DeviceOff);
312 setDeviceMode( Joy1_Down, (status & PACMAN_DOWN) ? DeviceOn : DeviceOff);
313 setDeviceMode( CoinSlot_1, (status & PACMAN_COIN) ? DeviceOn : DeviceOff);
314 setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP) ? DeviceOn : DeviceOff);
315 #ifdef PACMAN_2UP
316 setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP) ? DeviceOn : DeviceOff);
317 #endif
318 #endif
320 /* We only update the screen every third frame - Pacman's native
321 framerate is 60fps, so we are attempting to display 20fps */
322 if (frame_counter == 60 / FPS) {
324 frame_counter = 0;
325 video_frames++;
327 yield_counter ++;
329 if (yield_counter == FPS) {
330 yield_counter = 0;
331 rb->yield ();
334 /* The following functions render the Pacman screen from the
335 contents of the video and color ram. We first update the
336 background, and then draw the Sprites on top.
339 renderBackground( video_buffer );
340 renderSprites( video_buffer );
342 blit_display(rb->lcd_framebuffer,video_buffer);
344 if (settings.showfps) {
345 fps = (video_frames*HZ*100) / (*rb->current_tick-start_time);
346 rb->snprintf(str,sizeof(str),"%d.%02d / %d fps ",
347 fps/100,fps%100,FPS);
348 rb->lcd_putsxy(0,0,str);
351 rb->lcd_update();
353 /* Keep the framerate at Pacman's 60fps */
354 end_time = start_time + (video_frames*HZ)/FPS;
355 while (TIME_BEFORE(*rb->current_tick,end_time)) {
356 rb->sleep(1);
360 return 0;
363 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
365 (void)parameter;
367 PLUGIN_IRAM_INIT(api)
368 rb = api;
370 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
371 rb->cpu_boost(true);
372 #endif
373 rb->lcd_set_backdrop(NULL);
374 rb->lcd_set_foreground(LCD_WHITE);
375 rb->lcd_set_background(LCD_BLACK);
376 rb->lcd_clear_display();
377 rb->lcd_update();
379 /* Set the default settings */
380 settings.difficulty = 0; /* Normal */
381 settings.numlives = 2; /* 3 lives */
382 settings.bonus = 0; /* 10000 points */
383 settings.ghostnames = 0; /* Normal names */
384 settings.showfps = 0; /* Do not show FPS */
386 configfile_init(rb);
388 if (configfile_load(SETTINGS_FILENAME, config,
389 sizeof(config)/sizeof(*config),
390 SETTINGS_MIN_VERSION
391 ) < 0)
393 /* If the loading failed, save a new config file (as the disk is
394 already spinning) */
395 configfile_save(SETTINGS_FILENAME, config,
396 sizeof(config)/sizeof(*config),
397 SETTINGS_VERSION);
400 /* Keep a copy of the saved version of the settings - so we can check if
401 the settings have changed when we quit */
402 old_settings = settings;
404 /* Initialise the hardware */
405 init_PacmanMachine(settings_to_dip(settings));
407 /* Load the romset */
408 if (loadROMS()) {
409 start_time = *rb->current_tick-1;
411 gameProc();
413 /* Save the user settings if they have changed */
414 if (rb->memcmp(&settings,&old_settings,sizeof(settings))!=0) {
415 rb->splash(0, "Saving settings...");
416 configfile_save(SETTINGS_FILENAME, config,
417 sizeof(config)/sizeof(*config),
418 SETTINGS_VERSION);
420 } else {
421 rb->splash(HZ*2, "No ROMs in /.rockbox/pacman/");
424 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
425 rb->cpu_boost(false);
426 #endif
428 return PLUGIN_OK;