code police : fix some multiply defined variables
[kugel-rb.git] / apps / plugins / pacbox / pacbox.c
blobe5d3c225cefbf9658fb5d9e3ae272feca4a9135d
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 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
25 ****************************************************************************/
27 #include "plugin.h"
28 #include "arcade.h"
29 #include "pacbox.h"
30 #include "pacbox_lcd.h"
31 #include "lib/configfile.h"
32 #include "lib/oldmenuapi.h"
34 PLUGIN_HEADER
35 PLUGIN_IRAM_DECLARE
37 extern const struct plugin_api* rb;
39 struct pacman_settings {
40 int difficulty;
41 int numlives;
42 int bonus;
43 int ghostnames;
44 int showfps;
47 static struct pacman_settings settings;
48 static struct pacman_settings old_settings;
50 #define SETTINGS_VERSION 1
51 #define SETTINGS_MIN_VERSION 1
52 #define SETTINGS_FILENAME "pacbox.cfg"
54 static char* difficulty_options[] = { "Normal", "Hard" };
55 static char* numlives_options[] = { "1", "2", "3", "5" };
56 static char* bonus_options[] = {"10000", "15000", "20000", "No Bonus"};
57 static char* ghostnames_options[] = {"Normal", "Alternate"};
58 static char* showfps_options[] = {"No", "Yes"};
60 static struct configdata config[] =
62 {TYPE_ENUM, 0, 2, &settings.difficulty, "Difficulty", difficulty_options, NULL},
63 {TYPE_ENUM, 0, 4, &settings.numlives, "Pacmen Per Game", numlives_options, NULL},
64 {TYPE_ENUM, 0, 4, &settings.bonus, "Bonus", bonus_options, NULL},
65 {TYPE_ENUM, 0, 2, &settings.ghostnames, "Ghost Names", ghostnames_options , NULL},
66 {TYPE_ENUM, 0, 2, &settings.showfps, "Show FPS", showfps_options, NULL},
69 static bool loadFile( const char * name, unsigned char * buf, int len )
71 char filename[MAX_PATH];
73 rb->snprintf(filename,sizeof(filename), ROCKBOX_DIR "/pacman/%s",name);
75 int fd = rb->open( filename, O_RDONLY);
77 if( fd < 0 ) {
78 return false;
81 int n = rb->read( fd, buf, len);
83 rb->close( fd );
85 if( n != len ) {
86 return false;
89 return true;
92 static bool loadROMS( void )
94 bool romsLoaded = false;
96 romsLoaded = loadFile( "pacman.6e", ram_, 0x1000) &&
97 loadFile( "pacman.6f", ram_+0x1000, 0x1000) &&
98 loadFile( "pacman.6h", ram_+0x2000, 0x1000) &&
99 loadFile( "pacman.6j", ram_+0x3000, 0x1000) &&
100 loadFile( "pacman.5e", charset_rom_, 0x1000) &&
101 loadFile( "pacman.5f", spriteset_rom_, 0x1000);
103 if( romsLoaded ) {
104 decodeROMs();
105 reset_PacmanMachine();
108 return romsLoaded;
111 /* A buffer to render Pacman's 244x288 screen into */
112 static unsigned char video_buffer[ScreenWidth*ScreenHeight] __attribute__ ((aligned (16)));
114 static long start_time;
115 static long video_frames = 0;
117 static int dipDifficulty[] = { DipDifficulty_Normal, DipDifficulty_Hard };
118 static int dipLives[] = { DipLives_1, DipLives_2, DipLives_3, DipLives_5 };
119 static int dipBonus[] = { DipBonus_10000, DipBonus_15000, DipBonus_20000,
120 DipBonus_None };
121 static int dipGhostNames[] = { DipGhostNames_Normal, DipGhostNames_Alternate };
123 static int settings_to_dip(struct pacman_settings settings)
125 return ( DipPlay_OneCoinOneGame |
126 DipCabinet_Upright |
127 DipMode_Play |
128 DipRackAdvance_Off |
130 dipDifficulty[settings.difficulty] |
131 dipLives[settings.numlives] |
132 dipBonus[settings.bonus] |
133 dipGhostNames[settings.ghostnames]
137 static bool pacbox_menu(void)
139 int m;
140 int result;
141 int menu_quit=0;
142 int new_setting;
143 bool need_restart = false;
145 static const struct opt_items noyes[2] = {
146 { "No", -1 },
147 { "Yes", -1 },
150 static const struct opt_items difficulty_options[2] = {
151 { "Normal", -1 },
152 { "Harder", -1 },
155 static const struct opt_items numlives_options[4] = {
156 { "1", -1 },
157 { "2", -1 },
158 { "3", -1 },
159 { "5", -1 },
162 static const struct opt_items bonus_options[4] = {
163 { "10000 points", -1 },
164 { "15000 points", -1 },
165 { "20000 points", -1 },
166 { "No bonus", -1 },
169 static const struct opt_items ghostname_options[2] = {
170 { "Normal", -1 },
171 { "Alternate", -1 },
174 static const struct menu_item items[] = {
175 { "Difficulty", NULL },
176 { "Pacmen Per Game", NULL },
177 { "Bonus Life", NULL },
178 { "Ghost Names", NULL },
179 { "Display FPS", NULL },
180 { "Restart", NULL },
181 { "Quit", NULL },
184 m = menu_init(rb, items, sizeof(items) / sizeof(*items),
185 NULL, NULL, NULL, NULL);
187 rb->button_clear_queue();
189 while (!menu_quit) {
190 result=menu_show(m);
192 switch(result)
194 case 0:
195 new_setting=settings.difficulty;
196 rb->set_option("Difficulty", &new_setting, INT,
197 difficulty_options , 2, NULL);
198 if (new_setting != settings.difficulty) {
199 settings.difficulty=new_setting;
200 need_restart=true;
202 break;
203 case 1:
204 new_setting=settings.numlives;
205 rb->set_option("Pacmen Per Game", &new_setting, INT,
206 numlives_options , 4, NULL);
207 if (new_setting != settings.numlives) {
208 settings.numlives=new_setting;
209 need_restart=true;
211 break;
212 case 2:
213 new_setting=settings.bonus;
214 rb->set_option("Bonus Life", &new_setting, INT,
215 bonus_options , 4, NULL);
216 if (new_setting != settings.bonus) {
217 settings.bonus=new_setting;
218 need_restart=true;
220 break;
221 case 3:
222 new_setting=settings.ghostnames;
223 rb->set_option("Ghost Names", &new_setting, INT,
224 ghostname_options , 2, NULL);
225 if (new_setting != settings.ghostnames) {
226 settings.ghostnames=new_setting;
227 need_restart=true;
229 break;
230 case 4: /* Show FPS */
231 rb->set_option("Display FPS",&settings.showfps,INT,
232 noyes, 2, NULL);
233 break;
234 case 5: /* Restart */
235 need_restart=true;
236 menu_quit=1;
237 break;
238 default:
239 menu_quit=1;
240 break;
244 menu_exit(m);
246 if (need_restart) {
247 init_PacmanMachine(settings_to_dip(settings));
250 /* Possible results:
251 exit game
252 restart game
253 usb connected
255 return (result==6);
260 Runs the game engine for one frame.
262 static int gameProc( void )
264 int x;
265 int fps;
266 char str[80];
267 int status;
268 long end_time;
269 int frame_counter = 0;
270 int yield_counter = 0;
272 while (1)
274 /* Run the machine for one frame (1/60th second) */
275 run();
277 frame_counter++;
279 /* Check the button status */
280 status = rb->button_status();
282 #ifdef HAS_BUTTON_HOLD
283 if (rb->button_hold())
284 status = PACMAN_MENU;
285 #endif
287 if ((status & PACMAN_MENU) == PACMAN_MENU
288 #ifdef PACMAN_RC_MENU
289 || status == PACMAN_RC_MENU
290 #endif
292 end_time = *rb->current_tick;
293 x = pacbox_menu();
294 rb->lcd_clear_display();
295 #ifdef HAVE_REMOTE_LCD
296 rb->lcd_remote_clear_display();
297 rb->lcd_remote_update();
298 #endif
299 if (x == 1) { return 1; }
300 start_time += *rb->current_tick-end_time;
303 #ifdef PACMAN_HAS_REMOTE
304 setDeviceMode( Joy1_Left, (status & PACMAN_LEFT || status == PACMAN_RC_LEFT) ? DeviceOn : DeviceOff);
305 setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT || status == PACMAN_RC_RIGHT) ? DeviceOn : DeviceOff);
306 setDeviceMode( Joy1_Up, (status & PACMAN_UP || status == PACMAN_RC_UP) ? DeviceOn : DeviceOff);
307 setDeviceMode( Joy1_Down, (status & PACMAN_DOWN || status == PACMAN_RC_DOWN) ? DeviceOn : DeviceOff);
308 setDeviceMode( CoinSlot_1, (status & PACMAN_COIN || status == PACMAN_RC_COIN) ? DeviceOn : DeviceOff);
309 setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP || status == PACMAN_RC_1UP) ? DeviceOn : DeviceOff);
310 setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP || status == PACMAN_RC_2UP) ? DeviceOn : DeviceOff);
311 #else
312 setDeviceMode( Joy1_Left, (status & PACMAN_LEFT) ? DeviceOn : DeviceOff);
313 setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT) ? DeviceOn : DeviceOff);
314 setDeviceMode( Joy1_Up, (status & PACMAN_UP) ? DeviceOn : DeviceOff);
315 setDeviceMode( Joy1_Down, (status & PACMAN_DOWN) ? DeviceOn : DeviceOff);
316 setDeviceMode( CoinSlot_1, (status & PACMAN_COIN) ? DeviceOn : DeviceOff);
317 setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP) ? DeviceOn : DeviceOff);
318 #ifdef PACMAN_2UP
319 setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP) ? DeviceOn : DeviceOff);
320 #endif
321 #endif
323 /* We only update the screen every third frame - Pacman's native
324 framerate is 60fps, so we are attempting to display 20fps */
325 if (frame_counter == 60 / FPS) {
327 frame_counter = 0;
328 video_frames++;
330 yield_counter ++;
332 if (yield_counter == FPS) {
333 yield_counter = 0;
334 rb->yield ();
337 /* The following functions render the Pacman screen from the
338 contents of the video and color ram. We first update the
339 background, and then draw the Sprites on top.
342 renderBackground( video_buffer );
343 renderSprites( video_buffer );
345 blit_display(rb->lcd_framebuffer,video_buffer);
347 if (settings.showfps) {
348 fps = (video_frames*HZ*100) / (*rb->current_tick-start_time);
349 rb->snprintf(str,sizeof(str),"%d.%02d / %d fps ",
350 fps/100,fps%100,FPS);
351 rb->lcd_putsxy(0,0,str);
354 rb->lcd_update();
356 /* Keep the framerate at Pacman's 60fps */
357 end_time = start_time + (video_frames*HZ)/FPS;
358 while (TIME_BEFORE(*rb->current_tick,end_time)) {
359 rb->sleep(1);
363 return 0;
366 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
368 (void)parameter;
370 PLUGIN_IRAM_INIT(api)
371 rb = api;
373 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
374 rb->cpu_boost(true);
375 #endif
376 rb->lcd_set_backdrop(NULL);
377 rb->lcd_set_foreground(LCD_WHITE);
378 rb->lcd_set_background(LCD_BLACK);
379 rb->lcd_clear_display();
380 rb->lcd_update();
382 /* Set the default settings */
383 settings.difficulty = 0; /* Normal */
384 settings.numlives = 2; /* 3 lives */
385 settings.bonus = 0; /* 10000 points */
386 settings.ghostnames = 0; /* Normal names */
387 settings.showfps = 0; /* Do not show FPS */
389 configfile_init(rb);
391 if (configfile_load(SETTINGS_FILENAME, config,
392 sizeof(config)/sizeof(*config),
393 SETTINGS_MIN_VERSION
394 ) < 0)
396 /* If the loading failed, save a new config file (as the disk is
397 already spinning) */
398 configfile_save(SETTINGS_FILENAME, config,
399 sizeof(config)/sizeof(*config),
400 SETTINGS_VERSION);
403 /* Keep a copy of the saved version of the settings - so we can check if
404 the settings have changed when we quit */
405 old_settings = settings;
407 /* Initialise the hardware */
408 init_PacmanMachine(settings_to_dip(settings));
410 /* Load the romset */
411 if (loadROMS()) {
412 start_time = *rb->current_tick-1;
414 gameProc();
416 /* Save the user settings if they have changed */
417 if (rb->memcmp(&settings,&old_settings,sizeof(settings))!=0) {
418 rb->splash(0, "Saving settings...");
419 configfile_save(SETTINGS_FILENAME, config,
420 sizeof(config)/sizeof(*config),
421 SETTINGS_VERSION);
423 } else {
424 rb->splashf(HZ*2, "No ROMs in %s/pacman/", ROCKBOX_DIR);
427 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
428 rb->cpu_boost(false);
429 #endif
431 return PLUGIN_OK;