1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
30 #include "pacbox_lcd.h"
31 #include "lib/configfile.h"
32 #include "lib/oldmenuapi.h"
37 extern const struct plugin_api
* rb
;
39 struct pacman_settings
{
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
);
81 int n
= rb
->read( fd
, buf
, len
);
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);
105 reset_PacmanMachine();
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
,
121 static int dipGhostNames
[] = { DipGhostNames_Normal
, DipGhostNames_Alternate
};
123 static int settings_to_dip(struct pacman_settings settings
)
125 return ( DipPlay_OneCoinOneGame
|
130 dipDifficulty
[settings
.difficulty
] |
131 dipLives
[settings
.numlives
] |
132 dipBonus
[settings
.bonus
] |
133 dipGhostNames
[settings
.ghostnames
]
137 static bool pacbox_menu(void)
143 bool need_restart
= false;
145 static const struct opt_items noyes
[2] = {
150 static const struct opt_items difficulty_options
[2] = {
155 static const struct opt_items numlives_options
[4] = {
162 static const struct opt_items bonus_options
[4] = {
163 { "10000 points", -1 },
164 { "15000 points", -1 },
165 { "20000 points", -1 },
169 static const struct opt_items ghostname_options
[2] = {
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
},
184 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
),
185 NULL
, NULL
, NULL
, NULL
);
187 rb
->button_clear_queue();
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
;
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
;
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
;
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
;
230 case 4: /* Show FPS */
231 rb
->set_option("Display FPS",&settings
.showfps
,INT
,
234 case 5: /* Restart */
247 init_PacmanMachine(settings_to_dip(settings
));
260 Runs the game engine for one frame.
262 static int gameProc( void )
269 int frame_counter
= 0;
270 int yield_counter
= 0;
274 /* Run the machine for one frame (1/60th second) */
279 /* Check the button status */
280 status
= rb
->button_status();
282 #ifdef HAS_BUTTON_HOLD
283 if (rb
->button_hold())
284 status
= PACMAN_MENU
;
287 if ((status
& PACMAN_MENU
) == PACMAN_MENU
288 #ifdef PACMAN_RC_MENU
289 || status
== PACMAN_RC_MENU
292 end_time
= *rb
->current_tick
;
294 rb
->lcd_clear_display();
295 #ifdef HAVE_REMOTE_LCD
296 rb
->lcd_remote_clear_display();
297 rb
->lcd_remote_update();
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
);
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
);
319 setDeviceMode( Key_TwoPlayers
, (status
& PACMAN_2UP
) ? DeviceOn
: DeviceOff
);
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
) {
332 if (yield_counter
== FPS
) {
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
);
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
)) {
366 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
370 PLUGIN_IRAM_INIT(api
)
373 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
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();
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 */
391 if (configfile_load(SETTINGS_FILENAME
, config
,
392 sizeof(config
)/sizeof(*config
),
396 /* If the loading failed, save a new config file (as the disk is
398 configfile_save(SETTINGS_FILENAME
, config
,
399 sizeof(config
)/sizeof(*config
),
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 */
412 start_time
= *rb
->current_tick
-1;
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
),
424 rb
->splashf(HZ
*2, "No ROMs in %s/pacman/", ROCKBOX_DIR
);
427 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
428 rb
->cpu_boost(false);