blob: 16860f9d2546e5c03aff7f1f3db1948f183ce2e0 [file] [log] [blame]
Dave Chapmana8145842006-03-11 15:44:35 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Pacbox - a Pacman Emulator for Rockbox
11 *
12 * Based on PIE - Pacman Instructional Emulator
13 *
14 * Copyright (c) 1997-2003,2004 Alessandro Scotti
15 * http://www.ascotti.org/
16 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000017 * 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.
Dave Chapmana8145842006-03-11 15:44:35 +000021 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
25 ****************************************************************************/
26
27#include "plugin.h"
28#include "arcade.h"
Dave Chapmanad8b24d2006-03-13 01:42:11 +000029#include "pacbox.h"
30#include "pacbox_lcd.h"
Dave Chapman2390f002006-03-15 17:32:18 +000031#include "lib/configfile.h"
Jonathan Gordon77a458a2007-05-08 11:55:43 +000032#include "lib/oldmenuapi.h"
Dave Chapmana8145842006-03-11 15:44:35 +000033
34PLUGIN_HEADER
Michael Sevakisacc29d92006-11-18 02:18:29 +000035PLUGIN_IRAM_DECLARE
Dave Chapmana8145842006-03-11 15:44:35 +000036
Steve Bavin65265772008-05-13 09:57:56 +000037const struct plugin_api* rb;
Dave Chapmana8145842006-03-11 15:44:35 +000038
Dave Chapmana8145842006-03-11 15:44:35 +000039struct pacman_settings {
40 int difficulty;
41 int numlives;
42 int bonus;
43 int ghostnames;
44 int showfps;
45};
46
Dave Chapman2390f002006-03-15 17:32:18 +000047static struct pacman_settings settings;
48static struct pacman_settings old_settings;
Dave Chapmana8145842006-03-11 15:44:35 +000049
Dave Chapman2390f002006-03-15 17:32:18 +000050#define SETTINGS_VERSION 1
51#define SETTINGS_MIN_VERSION 1
52#define SETTINGS_FILENAME "pacbox.cfg"
53
54static char* difficulty_options[] = { "Normal", "Hard" };
55static char* numlives_options[] = { "1", "2", "3", "5" };
56static char* bonus_options[] = {"10000", "15000", "20000", "No Bonus"};
57static char* ghostnames_options[] = {"Normal", "Alternate"};
58static char* showfps_options[] = {"No", "Yes"};
59
60static struct configdata config[] =
61{
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},
67};
68
69static bool loadFile( const char * name, unsigned char * buf, int len )
Dave Chapmana8145842006-03-11 15:44:35 +000070{
71 char filename[MAX_PATH];
72
Nils Wallménius04b34352007-09-10 09:46:36 +000073 rb->snprintf(filename,sizeof(filename), ROCKBOX_DIR "/pacman/%s",name);
Dave Chapmana8145842006-03-11 15:44:35 +000074
75 int fd = rb->open( filename, O_RDONLY);
76
77 if( fd < 0 ) {
78 return false;
79 }
80
81 int n = rb->read( fd, buf, len);
82
83 rb->close( fd );
84
85 if( n != len ) {
86 return false;
87 }
88
89 return true;
90}
91
Dave Chapman2390f002006-03-15 17:32:18 +000092static bool loadROMS( void )
Dave Chapmana8145842006-03-11 15:44:35 +000093{
94 bool romsLoaded = false;
95
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);
102
103 if( romsLoaded ) {
104 decodeROMs();
105 reset_PacmanMachine();
106 }
107
108 return romsLoaded;
109}
110
111/* A buffer to render Pacman's 244x288 screen into */
Dave Chapman03627e02006-03-18 09:14:10 +0000112static unsigned char video_buffer[ScreenWidth*ScreenHeight] __attribute__ ((aligned (16)));
Dave Chapmana8145842006-03-11 15:44:35 +0000113
Dave Chapman2390f002006-03-15 17:32:18 +0000114static long start_time;
115static long video_frames = 0;
Dave Chapmana8145842006-03-11 15:44:35 +0000116
Dave Chapman2390f002006-03-15 17:32:18 +0000117static int dipDifficulty[] = { DipDifficulty_Normal, DipDifficulty_Hard };
118static int dipLives[] = { DipLives_1, DipLives_2, DipLives_3, DipLives_5 };
119static int dipBonus[] = { DipBonus_10000, DipBonus_15000, DipBonus_20000,
120 DipBonus_None };
121static int dipGhostNames[] = { DipGhostNames_Normal, DipGhostNames_Alternate };
Dave Chapmana8145842006-03-11 15:44:35 +0000122
Dave Chapman2390f002006-03-15 17:32:18 +0000123static int settings_to_dip(struct pacman_settings settings)
Dave Chapmana8145842006-03-11 15:44:35 +0000124{
125 return ( DipPlay_OneCoinOneGame |
126 DipCabinet_Upright |
127 DipMode_Play |
128 DipRackAdvance_Off |
129
130 dipDifficulty[settings.difficulty] |
131 dipLives[settings.numlives] |
132 dipBonus[settings.bonus] |
133 dipGhostNames[settings.ghostnames]
134 );
135}
136
Dave Chapman2390f002006-03-15 17:32:18 +0000137static bool pacbox_menu(void)
Dave Chapmana8145842006-03-11 15:44:35 +0000138{
139 int m;
140 int result;
141 int menu_quit=0;
142 int new_setting;
143 bool need_restart = false;
144
145 static const struct opt_items noyes[2] = {
Marcoen Hirschbergd24ed992006-08-11 12:48:36 +0000146 { "No", -1 },
147 { "Yes", -1 },
Dave Chapmana8145842006-03-11 15:44:35 +0000148 };
149
150 static const struct opt_items difficulty_options[2] = {
Marcoen Hirschbergd24ed992006-08-11 12:48:36 +0000151 { "Normal", -1 },
152 { "Harder", -1 },
Dave Chapmana8145842006-03-11 15:44:35 +0000153 };
154
155 static const struct opt_items numlives_options[4] = {
Marcoen Hirschbergd24ed992006-08-11 12:48:36 +0000156 { "1", -1 },
157 { "2", -1 },
158 { "3", -1 },
159 { "5", -1 },
Dave Chapmana8145842006-03-11 15:44:35 +0000160 };
161
162 static const struct opt_items bonus_options[4] = {
Marcoen Hirschbergd24ed992006-08-11 12:48:36 +0000163 { "10000 points", -1 },
164 { "15000 points", -1 },
165 { "20000 points", -1 },
166 { "No bonus", -1 },
Dave Chapmana8145842006-03-11 15:44:35 +0000167 };
168
169 static const struct opt_items ghostname_options[2] = {
Marcoen Hirschbergd24ed992006-08-11 12:48:36 +0000170 { "Normal", -1 },
171 { "Alternate", -1 },
Dave Chapmana8145842006-03-11 15:44:35 +0000172 };
173
174 static const struct menu_item items[] = {
Marcoen Hirschbergd24ed992006-08-11 12:48:36 +0000175 { "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 },
Dave Chapmana8145842006-03-11 15:44:35 +0000182 };
183
Jonathan Gordon77a458a2007-05-08 11:55:43 +0000184 m = menu_init(rb, items, sizeof(items) / sizeof(*items),
Dave Chapmanad8b24d2006-03-13 01:42:11 +0000185 NULL, NULL, NULL, NULL);
Dave Chapmana8145842006-03-11 15:44:35 +0000186
187 rb->button_clear_queue();
188
189 while (!menu_quit) {
Jonathan Gordon77a458a2007-05-08 11:55:43 +0000190 result=menu_show(m);
Dave Chapmana8145842006-03-11 15:44:35 +0000191
192 switch(result)
193 {
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;
201 }
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;
210 }
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;
219 }
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;
228 }
229 break;
230 case 4: /* Show FPS */
Dave Chapman2390f002006-03-15 17:32:18 +0000231 rb->set_option("Display FPS",&settings.showfps,INT,
232 noyes, 2, NULL);
Dave Chapmana8145842006-03-11 15:44:35 +0000233 break;
234 case 5: /* Restart */
235 need_restart=true;
236 menu_quit=1;
237 break;
238 default:
239 menu_quit=1;
240 break;
241 }
242 }
243
Jonathan Gordon77a458a2007-05-08 11:55:43 +0000244 menu_exit(m);
Dave Chapmana8145842006-03-11 15:44:35 +0000245
246 if (need_restart) {
247 init_PacmanMachine(settings_to_dip(settings));
248 }
249
250 /* Possible results:
251 exit game
252 restart game
253 usb connected
254 */
255 return (result==6);
256}
257
258
259/*
260 Runs the game engine for one frame.
261*/
Dave Chapman2390f002006-03-15 17:32:18 +0000262static int gameProc( void )
Dave Chapmana8145842006-03-11 15:44:35 +0000263{
Dave Chapmanad8b24d2006-03-13 01:42:11 +0000264 int x;
Dave Chapmana8145842006-03-11 15:44:35 +0000265 int fps;
266 char str[80];
267 int status;
268 long end_time;
Dave Chapman1a0e8852006-03-20 23:01:28 +0000269 int frame_counter = 0;
270 int yield_counter = 0;
Dave Chapmana8145842006-03-11 15:44:35 +0000271
Dave Chapman1a0e8852006-03-20 23:01:28 +0000272 while (1)
273 {
274 /* Run the machine for one frame (1/60th second) */
275 run();
Dave Chapmana8145842006-03-11 15:44:35 +0000276
Dave Chapman1a0e8852006-03-20 23:01:28 +0000277 frame_counter++;
Dave Chapmana8145842006-03-11 15:44:35 +0000278
Dave Chapman1a0e8852006-03-20 23:01:28 +0000279 /* Check the button status */
280 status = rb->button_status();
Dave Chapmana10e5312006-03-16 23:21:47 +0000281
Shachar Liberman5360df92006-07-30 03:10:09 +0000282#ifdef HAS_BUTTON_HOLD
283 if (rb->button_hold())
284 status = PACMAN_MENU;
285#endif
286
Dave Chapman1a0e8852006-03-20 23:01:28 +0000287 if ((status & PACMAN_MENU) == PACMAN_MENU
Dave Chapman03627e02006-03-18 09:14:10 +0000288#ifdef PACMAN_RC_MENU
Dave Chapman1a0e8852006-03-20 23:01:28 +0000289 || status == PACMAN_RC_MENU
Dave Chapman03627e02006-03-18 09:14:10 +0000290#endif
Dave Chapman1a0e8852006-03-20 23:01:28 +0000291 ) {
292 end_time = *rb->current_tick;
293 x = pacbox_menu();
294 rb->lcd_clear_display();
Dave Chapmana8145842006-03-11 15:44:35 +0000295#ifdef HAVE_REMOTE_LCD
Dave Chapman1a0e8852006-03-20 23:01:28 +0000296 rb->lcd_remote_clear_display();
297 rb->lcd_remote_update();
Dave Chapmana8145842006-03-11 15:44:35 +0000298#endif
Dave Chapman1a0e8852006-03-20 23:01:28 +0000299 if (x == 1) { return 1; }
300 start_time += *rb->current_tick-end_time;
301 }
Dave Chapmana8145842006-03-11 15:44:35 +0000302
Dave Chapman03627e02006-03-18 09:14:10 +0000303#ifdef PACMAN_HAS_REMOTE
Dave Chapman1a0e8852006-03-20 23:01:28 +0000304 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);
Dave Chapman03627e02006-03-18 09:14:10 +0000311#else
Dave Chapman1a0e8852006-03-20 23:01:28 +0000312 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);
Dave Chapmana8145842006-03-11 15:44:35 +0000318#ifdef PACMAN_2UP
Dave Chapman1a0e8852006-03-20 23:01:28 +0000319 setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP) ? DeviceOn : DeviceOff);
Dave Chapmana8145842006-03-11 15:44:35 +0000320#endif
Dave Chapman03627e02006-03-18 09:14:10 +0000321#endif
Dave Chapmana8145842006-03-11 15:44:35 +0000322
Dave Chapman1a0e8852006-03-20 23:01:28 +0000323 /* 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) {
Dave Chapmana8145842006-03-11 15:44:35 +0000326
Dave Chapman1a0e8852006-03-20 23:01:28 +0000327 frame_counter = 0;
328 video_frames++;
Dave Chapmana8145842006-03-11 15:44:35 +0000329
Dave Chapman1a0e8852006-03-20 23:01:28 +0000330 yield_counter ++;
Dave Chapmana8145842006-03-11 15:44:35 +0000331
Dave Chapman1a0e8852006-03-20 23:01:28 +0000332 if (yield_counter == FPS) {
333 yield_counter = 0;
334 rb->yield ();
335 }
336
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.
340 */
Dave Chapmanad8b24d2006-03-13 01:42:11 +0000341
Dave Chapman1a0e8852006-03-20 23:01:28 +0000342 renderBackground( video_buffer );
343 renderSprites( video_buffer );
Dave Chapmana8145842006-03-11 15:44:35 +0000344
Dave Chapman1a0e8852006-03-20 23:01:28 +0000345 blit_display(rb->lcd_framebuffer,video_buffer);
Dave Chapmana8145842006-03-11 15:44:35 +0000346
Dave Chapman1a0e8852006-03-20 23:01:28 +0000347 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);
352 }
Dave Chapmana8145842006-03-11 15:44:35 +0000353
Dave Chapman1a0e8852006-03-20 23:01:28 +0000354 rb->lcd_update();
355
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);
360 }
Dave Chapmana8145842006-03-11 15:44:35 +0000361 }
Dave Chapmana8145842006-03-11 15:44:35 +0000362 }
Dave Chapmana8145842006-03-11 15:44:35 +0000363 return 0;
364}
365
Steve Bavin65265772008-05-13 09:57:56 +0000366enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
Dave Chapmana8145842006-03-11 15:44:35 +0000367{
368 (void)parameter;
Dave Chapmana8145842006-03-11 15:44:35 +0000369
Tomasz Malesinski80da8b12006-11-26 18:31:41 +0000370 PLUGIN_IRAM_INIT(api)
Dave Chapmana8145842006-03-11 15:44:35 +0000371 rb = api;
372
Dave Chapmana8145842006-03-11 15:44:35 +0000373#ifdef HAVE_ADJUSTABLE_CPU_FREQ
374 rb->cpu_boost(true);
375#endif
Karl Kurbjund6b0c972006-11-15 06:14:27 +0000376 rb->lcd_set_backdrop(NULL);
Dave Chapmana8145842006-03-11 15:44:35 +0000377 rb->lcd_set_foreground(LCD_WHITE);
378 rb->lcd_set_background(LCD_BLACK);
379 rb->lcd_clear_display();
380 rb->lcd_update();
381
Dave Chapman2390f002006-03-15 17:32:18 +0000382 /* Set the default settings */
Dave Chapmana8145842006-03-11 15:44:35 +0000383 settings.difficulty = 0; /* Normal */
384 settings.numlives = 2; /* 3 lives */
385 settings.bonus = 0; /* 10000 points */
386 settings.ghostnames = 0; /* Normal names */
Dave Chapman7a10c082006-03-13 01:52:11 +0000387 settings.showfps = 0; /* Do not show FPS */
Dave Chapmana8145842006-03-11 15:44:35 +0000388
Dave Chapman2390f002006-03-15 17:32:18 +0000389 configfile_init(rb);
390
391 if (configfile_load(SETTINGS_FILENAME, config,
392 sizeof(config)/sizeof(*config),
393 SETTINGS_MIN_VERSION
394 ) < 0)
395 {
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);
401 }
402
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;
406
Dave Chapmana8145842006-03-11 15:44:35 +0000407 /* Initialise the hardware */
408 init_PacmanMachine(settings_to_dip(settings));
409
410 /* Load the romset */
411 if (loadROMS()) {
412 start_time = *rb->current_tick-1;
Dave Chapman1a0e8852006-03-20 23:01:28 +0000413
414 gameProc();
Dave Chapman2390f002006-03-15 17:32:18 +0000415
416 /* Save the user settings if they have changed */
417 if (rb->memcmp(&settings,&old_settings,sizeof(settings))!=0) {
Jens Arnold4d6374c2007-03-16 21:56:08 +0000418 rb->splash(0, "Saving settings...");
Dave Chapman2390f002006-03-15 17:32:18 +0000419 configfile_save(SETTINGS_FILENAME, config,
420 sizeof(config)/sizeof(*config),
421 SETTINGS_VERSION);
422 }
Dave Chapmana8145842006-03-11 15:44:35 +0000423 } else {
Nils Wallménius04b34352007-09-10 09:46:36 +0000424 rb->splash(HZ*2, "No ROMs in %s/pacman/", ROCKBOX_DIR);
Dave Chapmana8145842006-03-11 15:44:35 +0000425 }
426
427#ifdef HAVE_ADJUSTABLE_CPU_FREQ
428 rb->cpu_boost(false);
429#endif
430
431 return PLUGIN_OK;
432}