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 * 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 ****************************************************************************/
28 #include "pacbox_lcd.h"
29 #include "lib/configfile.h"
34 struct plugin_api
* rb
;
36 struct pacman_settings
{
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
);
78 int n
= rb
->read( fd
, buf
, len
);
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);
102 reset_PacmanMachine();
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
,
118 static int dipGhostNames
[] = { DipGhostNames_Normal
, DipGhostNames_Alternate
};
120 static int settings_to_dip(struct pacman_settings settings
)
122 return ( DipPlay_OneCoinOneGame
|
127 dipDifficulty
[settings
.difficulty
] |
128 dipLives
[settings
.numlives
] |
129 dipBonus
[settings
.bonus
] |
130 dipGhostNames
[settings
.ghostnames
]
134 static bool pacbox_menu(void)
140 bool need_restart
= false;
142 static const struct opt_items noyes
[2] = {
147 static const struct opt_items difficulty_options
[2] = {
152 static const struct opt_items numlives_options
[4] = {
159 static const struct opt_items bonus_options
[4] = {
160 { "10000 points", -1 },
161 { "15000 points", -1 },
162 { "20000 points", -1 },
166 static const struct opt_items ghostname_options
[2] = {
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
},
181 m
= rb
->menu_init(items
, sizeof(items
) / sizeof(*items
),
182 NULL
, NULL
, NULL
, NULL
);
184 rb
->button_clear_queue();
187 result
=rb
->menu_show(m
);
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
;
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
;
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
;
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
;
227 case 4: /* Show FPS */
228 rb
->set_option("Display FPS",&settings
.showfps
,INT
,
231 case 5: /* Restart */
244 init_PacmanMachine(settings_to_dip(settings
));
257 Runs the game engine for one frame.
259 static int gameProc( void )
266 int frame_counter
= 0;
267 int yield_counter
= 0;
271 /* Run the machine for one frame (1/60th second) */
276 /* Check the button status */
277 status
= rb
->button_status();
279 #ifdef HAS_BUTTON_HOLD
280 if (rb
->button_hold())
281 status
= PACMAN_MENU
;
284 if ((status
& PACMAN_MENU
) == PACMAN_MENU
285 #ifdef PACMAN_RC_MENU
286 || status
== PACMAN_RC_MENU
289 end_time
= *rb
->current_tick
;
291 rb
->lcd_clear_display();
292 #ifdef HAVE_REMOTE_LCD
293 rb
->lcd_remote_clear_display();
294 rb
->lcd_remote_update();
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
);
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
);
316 setDeviceMode( Key_TwoPlayers
, (status
& PACMAN_2UP
) ? DeviceOn
: DeviceOff
);
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
) {
329 if (yield_counter
== FPS
) {
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
);
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
)) {
363 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
367 PLUGIN_IRAM_INIT(api
)
370 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
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();
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 */
388 if (configfile_load(SETTINGS_FILENAME
, config
,
389 sizeof(config
)/sizeof(*config
),
393 /* If the loading failed, save a new config file (as the disk is
395 configfile_save(SETTINGS_FILENAME
, config
,
396 sizeof(config
)/sizeof(*config
),
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 */
409 start_time
= *rb
->current_tick
-1;
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
),
421 rb
->splash(HZ
*2, "No ROMs in /.rockbox/pacman/");
424 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
425 rb
->cpu_boost(false);