Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Pacbox - a Pacman Emulator for Rockbox
- *
- * Based on PIE - Pacman Instructional Emulator
- *
- * Copyright (c) 1997-2003,2004 Alessandro Scotti
- * http://www.ascotti.org/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
- #include "plugin.h"
- #include "arcade.h"
- #include "pacbox.h"
- #include "pacbox_lcd.h"
- #include "wsg3.h"
- #include "lib/configfile.h"
- #include "lib/playback_control.h"
- struct pacman_settings {
- int difficulty;
- int numlives;
- int bonus;
- int ghostnames;
- int showfps;
- int sound;
- int ai;
- };
- static struct pacman_settings settings;
- static struct pacman_settings old_settings;
- static bool sound_playing = false;
- #define SETTINGS_VERSION 2
- #define SETTINGS_MIN_VERSION 2
- #define SETTINGS_FILENAME "pacbox.cfg"
- static char* difficulty_options[] = { "Normal", "Hard" };
- static char* numlives_options[] = { "1", "2", "3", "5" };
- static char* bonus_options[] = {"10000", "15000", "20000", "No Bonus"};
- static char* ghostnames_options[] = {"Normal", "Alternate"};
- static char* yesno_options[] = {"No", "Yes"};
- static unsigned char ai_direction[19][150] = /* level turn directions */
- {
- {2,1,3,1,2,0,3,0,3,1,3,1,3,0,3,0,3,0,2,0,2,0,2,1,3,1,2,0,2,1,3,1,3,0,1,3,0,3,1,2,1,3,1,3,0,3,0,2,1} /* (first half of) first level */
- };
- static unsigned char ai_location[19][150] = /* level turn locations */
- {
- {0,52,58,57,61,34,60,37,57,41,58,43,61,46,61,49,57,52,54,51,51,42,48,38,52,43,55,39,54,34,55,34,58,37,47,52,41,51,49,52,48,55,52,58,55,57,57,54,54}
- };
- static struct configdata config[] =
- {
- {TYPE_ENUM, 0, 2, { .int_p = &settings.difficulty }, "Difficulty",
- difficulty_options},
- {TYPE_ENUM, 0, 4, { .int_p = &settings.numlives }, "Pacmen Per Game",
- numlives_options},
- {TYPE_ENUM, 0, 4, { .int_p = &settings.bonus }, "Bonus", bonus_options},
- {TYPE_ENUM, 0, 2, { .int_p = &settings.ghostnames }, "Ghost Names",
- ghostnames_options},
- {TYPE_ENUM, 0, 2, { .int_p = &settings.showfps }, "Show FPS",
- yesno_options},
- {TYPE_ENUM, 0, 2, { .int_p = &settings.sound }, "Sound",
- yesno_options},
- {TYPE_ENUM, 0, 2, { .int_p = &settings.ai }, "AI",
- yesno_options},
- };
- static bool loadFile( const char * name, unsigned char * buf, int len )
- {
- char filename[MAX_PATH];
- rb->snprintf(filename,sizeof(filename), ROCKBOX_DIR "/pacman/%s",name);
- int fd = rb->open( filename, O_RDONLY);
- if( fd < 0 ) {
- return false;
- }
- int n = rb->read( fd, buf, len);
- rb->close( fd );
- if( n != len ) {
- return false;
- }
- return true;
- }
- static bool loadROMS( void )
- {
- bool romsLoaded = false;
- romsLoaded = loadFile( "pacman.6e", ram_, 0x1000) &&
- loadFile( "pacman.6f", ram_+0x1000, 0x1000) &&
- loadFile( "pacman.6h", ram_+0x2000, 0x1000) &&
- loadFile( "pacman.6j", ram_+0x3000, 0x1000) &&
- loadFile( "pacman.5e", charset_rom_, 0x1000) &&
- loadFile( "pacman.5f", spriteset_rom_, 0x1000);
- if( romsLoaded ) {
- decodeROMs();
- reset_PacmanMachine();
- }
- return romsLoaded;
- }
- /* A buffer to render Pacman's 244x288 screen into */
- static unsigned char video_buffer[ScreenWidth*ScreenHeight] __attribute__ ((aligned (16)));
- static long start_time;
- static long video_frames = 0;
- static int dipDifficulty[] = { DipDifficulty_Normal, DipDifficulty_Hard };
- static int dipLives[] = { DipLives_1, DipLives_2, DipLives_3, DipLives_5 };
- static int dipBonus[] = { DipBonus_10000, DipBonus_15000, DipBonus_20000,
- DipBonus_None };
- static int dipGhostNames[] = { DipGhostNames_Normal, DipGhostNames_Alternate };
- static int settings_to_dip(struct pacman_settings settings)
- {
- return ( DipPlay_OneCoinOneGame |
- DipCabinet_Upright |
- DipMode_Play |
- DipRackAdvance_Off |
- dipDifficulty[settings.difficulty] |
- dipLives[settings.numlives] |
- dipBonus[settings.bonus] |
- dipGhostNames[settings.ghostnames]
- );
- }
- static bool pacbox_menu(void)
- {
- int selected=0;
- int result;
- int menu_quit=0;
- int new_setting;
- bool need_restart = false;
- static const struct opt_items noyes[2] = {
- { "No", -1 },
- { "Yes", -1 },
- };
- static const struct opt_items difficulty_options[2] = {
- { "Normal", -1 },
- { "Harder", -1 },
- };
- static const struct opt_items numlives_options[4] = {
- { "1", -1 },
- { "2", -1 },
- { "3", -1 },
- { "5", -1 },
- };
- static const struct opt_items bonus_options[4] = {
- { "10000 points", -1 },
- { "15000 points", -1 },
- { "20000 points", -1 },
- { "No bonus", -1 },
- };
- static const struct opt_items ghostname_options[2] = {
- { "Normal", -1 },
- { "Alternate", -1 },
- };
- enum
- {
- PBMI_DIFFICULTY = 0,
- PBMI_PACMEN_PER_GAME,
- PBMI_BONUS_LIFE,
- PBMI_GHOST_NAMES,
- PBMI_DISPLAY_FPS,
- PBMI_SOUND,
- PBMI_AI,
- PBMI_RESTART,
- PBMI_QUIT,
- };
- MENUITEM_STRINGLIST(menu, "Pacbox Menu", NULL,
- "Difficulty", "Pacmen Per Game", "Bonus Life",
- "Ghost Names", "Display FPS", "Sound", "AI",
- "Restart", "Quit");
- rb->button_clear_queue();
- #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
- rb->lcd_set_mode(LCD_MODE_RGB565);
- #endif
- while (!menu_quit) {
- result=rb->do_menu(&menu, &selected, NULL, false);
- switch(result)
- {
- case PBMI_DIFFICULTY:
- new_setting=settings.difficulty;
- rb->set_option("Difficulty", &new_setting, INT,
- difficulty_options , 2, NULL);
- if (new_setting != settings.difficulty) {
- settings.difficulty=new_setting;
- need_restart=true;
- }
- break;
- case PBMI_PACMEN_PER_GAME:
- new_setting=settings.numlives;
- rb->set_option("Pacmen Per Game", &new_setting, INT,
- numlives_options , 4, NULL);
- if (new_setting != settings.numlives) {
- settings.numlives=new_setting;
- need_restart=true;
- }
- break;
- case PBMI_BONUS_LIFE:
- new_setting=settings.bonus;
- rb->set_option("Bonus Life", &new_setting, INT,
- bonus_options , 4, NULL);
- if (new_setting != settings.bonus) {
- settings.bonus=new_setting;
- need_restart=true;
- }
- break;
- case PBMI_GHOST_NAMES:
- new_setting=settings.ghostnames;
- rb->set_option("Ghost Names", &new_setting, INT,
- ghostname_options , 2, NULL);
- if (new_setting != settings.ghostnames) {
- settings.ghostnames=new_setting;
- need_restart=true;
- }
- break;
- case PBMI_DISPLAY_FPS:
- rb->set_option("Display FPS",&settings.showfps,INT,
- noyes, 2, NULL);
- break;
- case PBMI_SOUND:
- rb->set_option("Sound",&settings.sound, INT,
- noyes, 2, NULL);
- break;
- case PBMI_AI:
- rb->set_option("AI",&settings.ai, INT,
- noyes, 2, NULL);
- break;
- case PBMI_RESTART:
- need_restart=true;
- menu_quit=1;
- break;
- default:
- menu_quit=1;
- break;
- }
- }
- #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
- rb->lcd_set_mode(LCD_MODE_PAL256);
- #endif
- if (need_restart) {
- init_PacmanMachine(settings_to_dip(settings));
- }
- /* Possible results:
- exit game
- restart game
- usb connected
- */
- return (result==PBMI_QUIT);
- }
- /* Sound is emulated in ISR context, so not much is done per sound frame */
- #define NBSAMPLES 128
- static uint32_t sound_buf[NBSAMPLES];
- #if CONFIG_CPU == MCF5249
- /* Not enough to put this in IRAM */
- static int16_t raw_buf[NBSAMPLES];
- #else
- static int16_t raw_buf[NBSAMPLES] IBSS_ATTR;
- #endif
- /*
- Audio callback
- */
- static void get_more(const void **start, size_t *size)
- {
- int32_t *out, *outend;
- int16_t *raw;
- /* Emulate the audio for the current register settings */
- playSound(raw_buf, NBSAMPLES);
- out = sound_buf;
- outend = out + NBSAMPLES;
- raw = raw_buf;
- /* Convert to stereo */
- do
- {
- uint32_t sample = (uint16_t)*raw++;
- *out++ = sample | (sample << 16);
- }
- while (out < outend);
- *start = sound_buf;
- *size = NBSAMPLES*sizeof(sound_buf[0]);
- }
- /*
- Start the sound emulation
- */
- static void start_sound(void)
- {
- int sr_index;
- if (sound_playing)
- return;
- #ifndef PLUGIN_USE_IRAM
- /* Ensure control of PCM - stopping music isn't obligatory */
- rb->plugin_get_audio_buffer(NULL);
- #endif
- /* Get the closest rate >= to what is preferred */
- sr_index = rb->round_value_to_list32(PREFERRED_SAMPLING_RATE,
- rb->hw_freq_sampr, HW_NUM_FREQ, false);
- if (rb->hw_freq_sampr[sr_index] < PREFERRED_SAMPLING_RATE
- && sr_index > 0)
- {
- /* Round up */
- sr_index--;
- }
- wsg3_set_sampling_rate(rb->hw_freq_sampr[sr_index]);
- rb->pcm_set_frequency(rb->hw_freq_sampr[sr_index]);
- rb->pcm_play_data(get_more, NULL, NULL, 0);
- sound_playing = true;
- }
- /*
- Stop the sound emulation
- */
- static void stop_sound(void)
- {
- if (!sound_playing)
- return;
- rb->pcm_play_stop();
- rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
- sound_playing = false;
- }
- /* invincibility */
- void hack(void)
- {
- ram_[0x1774] = 0x32;
- ram_[0x1775] = 0x3C;
- ram_[0x1776] = 0xE0;
- ram_[0x1777] = 0xC3;
- ram_[0x3CDF] = 0x04;
- ram_[0x3CEA] = 0x20;
- ram_[0x3CE1] = 0xA7;
- ram_[0x3CE2] = 0x00;
- ram_[0x3CE3] = 0x17;
- ram_[0x3CE4] = 0x64;
- ram_[0x3CE5] = 0xC3;
- ram_[0x3CE6] = 0xAF;
- ram_[0x3CE7] = 0x17;
- ram_[0x3CE8] = 0x77;
- ram_[0x3CE9] = 0xC3;
- ram_[0x3CEA] = 0xAF;
- }
- /* blank controls */
- void clear_joystick(void)
- {
- setDeviceMode( Joy1_Left, DeviceOff);
- setDeviceMode( Joy1_Right, DeviceOff);
- setDeviceMode( Joy1_Up, DeviceOff);
- setDeviceMode( Joy1_Down, DeviceOff);
- }
- /*
- Make turns automatically
- */
- unsigned char ai( unsigned char turn )
- {
- int status;
- unsigned char position; /* pac-mans current position */
- unsigned char levels[255] = {0,1,2, }; /* table of level to map correspondences */
- unsigned char level = levels[ram_[0x4E13]-1]; /* current game level */
- /* AI cannot start in middle of a level */
- if( turn > 200)
- {
- rb->splash(HZ/2, "AI will engage at next level start");
- return 0;
- }
- if( turn == 0)
- {
- if( ram_[0x4E0E] == 0)
- {
- turn++;
- }
- }
- if(turn != 0)
- {
- /* set which axis to look for pac-man along */
- position = ram_[0x4D3A];
- if( ai_direction[level][turn-1] < 2)
- {
- position = ram_[0x4D39];
- }
- /*move joystick if necessary */
- if( position == ai_location[level][turn] )
- {
- switch(ai_direction[level][turn])
- {
- case 0:
- clear_joystick();
- setDeviceMode( Joy1_Up, DeviceOn);
- break;
- case 1:
- clear_joystick();
- setDeviceMode( Joy1_Down, DeviceOn);
- break;
- case 2:
- clear_joystick();
- setDeviceMode( Joy1_Right, DeviceOn);
- break;
- case 3:
- clear_joystick();
- setDeviceMode( Joy1_Left, DeviceOn);
- break;
- }
- turn++;
- }
- }
- /* reset turn counter on level end */
- if(ram_[0x4E0E] == 254)
- {
- return 1;
- }
- /* Check the button status */
- status = rb->button_status();
- /*handle buttons if AI is off */
- if(!turn || (turn == 1))
- {
- #ifdef PACMAN_HAS_REMOTE
- setDeviceMode( Joy1_Left, (status & PACMAN_LEFT || status == PACMAN_RC_LEFT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT || status == PACMAN_RC_RIGHT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Up, (status & PACMAN_UP || status == PACMAN_RC_UP) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Down, (status & PACMAN_DOWN || status == PACMAN_RC_DOWN) ? DeviceOn : DeviceOff);
- setDeviceMode( CoinSlot_1, (status & PACMAN_COIN || status == PACMAN_RC_COIN) ? DeviceOn : DeviceOff);
- setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP || status == PACMAN_RC_1UP) ? DeviceOn : DeviceOff);
- setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP || status == PACMAN_RC_2UP) ? DeviceOn : DeviceOff);
- #else
- setDeviceMode( Joy1_Left, (status & PACMAN_LEFT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Up, (status & PACMAN_UP) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Down, (status & PACMAN_DOWN) ? DeviceOn : DeviceOff);
- setDeviceMode( CoinSlot_1, (status & PACMAN_COIN) ? DeviceOn : DeviceOff);
- setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP) ? DeviceOn : DeviceOff);
- #ifdef PACMAN_2UP
- setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP) ? DeviceOn : DeviceOff);
- #endif
- #endif
- }//else
- //hack();
- //rb->debugf("x = %d \n",ram_[0x4D3A]);
- //rb->debugf("y = %d \n",ram_[0x4D39]);
- return turn;
- }
- /*
- Runs the game engine for one frame.
- */
- static int gameProc( void )
- {
- int fps;
- int status;
- long end_time;
- int frame_counter = 0;
- int yield_counter = 0;
- unsigned char turn = 250;
- if (settings.sound)
- start_sound();
- while (1)
- {
- /* Run the machine for one frame (1/60th second) */
- run();
- frame_counter++;
- /* Check the button status */
- status = rb->button_status();
- #ifdef HAS_BUTTON_HOLD
- if (rb->button_hold())
- status = PACMAN_MENU;
- #endif
- if ((status & PACMAN_MENU) == PACMAN_MENU
- #ifdef PACMAN_RC_MENU
- || status == PACMAN_RC_MENU
- #endif
- ) {
- bool menu_res;
- end_time = *rb->current_tick;
- stop_sound();
- menu_res = pacbox_menu();
- rb->lcd_clear_display();
- #ifdef HAVE_REMOTE_LCD
- rb->lcd_remote_clear_display();
- rb->lcd_remote_update();
- #endif
- if (menu_res)
- return 1;
- if (settings.sound)
- start_sound();
- start_time += *rb->current_tick-end_time;
- }
- if(!settings.ai)
- {
- #ifdef PACMAN_HAS_REMOTE
- setDeviceMode( Joy1_Left, (status & PACMAN_LEFT || status == PACMAN_RC_LEFT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT || status == PACMAN_RC_RIGHT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Up, (status & PACMAN_UP || status == PACMAN_RC_UP) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Down, (status & PACMAN_DOWN || status == PACMAN_RC_DOWN) ? DeviceOn : DeviceOff);
- setDeviceMode( CoinSlot_1, (status & PACMAN_COIN || status == PACMAN_RC_COIN) ? DeviceOn : DeviceOff);
- setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP || status == PACMAN_RC_1UP) ? DeviceOn : DeviceOff);
- setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP || status == PACMAN_RC_2UP) ? DeviceOn : DeviceOff);
- #else
- setDeviceMode( Joy1_Left, (status & PACMAN_LEFT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Up, (status & PACMAN_UP) ? DeviceOn : DeviceOff);
- setDeviceMode( Joy1_Down, (status & PACMAN_DOWN) ? DeviceOn : DeviceOff);
- setDeviceMode( CoinSlot_1, (status & PACMAN_COIN) ? DeviceOn : DeviceOff);
- setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP) ? DeviceOn : DeviceOff);
- #ifdef PACMAN_2UP
- setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP) ? DeviceOn : DeviceOff);
- #endif
- #endif
- }
- /* run ai */
- if (settings.ai)
- turn = ai(turn);
- /* We only update the screen every third frame - Pacman's native
- framerate is 60fps, so we are attempting to display 20fps */
- if (frame_counter == 60 / FPS) {
- frame_counter = 0;
- video_frames++;
- yield_counter ++;
- if (yield_counter == FPS) {
- yield_counter = 0;
- rb->yield ();
- }
- /* The following functions render the Pacman screen from the
- contents of the video and color ram. We first update the
- background, and then draw the Sprites on top.
- */
- renderBackground( video_buffer );
- renderSprites( video_buffer );
- #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
- rb->lcd_blit_pal256( video_buffer, 0, 0, XOFS, YOFS,
- ScreenWidth, ScreenHeight);
- #else
- blit_display(rb->lcd_framebuffer,video_buffer);
- #endif
- if (settings.showfps) {
- fps = (video_frames*HZ*100) / (*rb->current_tick-start_time);
- rb->lcd_putsxyf(0,0,"%d.%02d / %d fps ",fps/100,fps%100,FPS);
- }
- #if !defined(HAVE_LCD_MODES) || \
- defined(HAVE_LCD_MODES) && !(HAVE_LCD_MODES & LCD_MODE_PAL256)
- rb->lcd_update();
- #endif
- /* Keep the framerate at Pacman's 60fps */
- end_time = start_time + (video_frames*HZ)/FPS;
- while (TIME_BEFORE(*rb->current_tick,end_time)) {
- rb->sleep(1);
- }
- }
- }
- stop_sound();
- return 0;
- }
- enum plugin_status plugin_start(const void* parameter)
- {
- (void)parameter;
- #ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(true);
- #endif
- rb->lcd_set_backdrop(NULL);
- rb->lcd_set_foreground(LCD_WHITE);
- rb->lcd_set_background(LCD_BLACK);
- rb->lcd_clear_display();
- rb->lcd_update();
- /* Set the default settings */
- settings.difficulty = 0; /* Normal */
- settings.numlives = 2; /* 3 lives */
- settings.bonus = 0; /* 10000 points */
- settings.ghostnames = 0; /* Normal names */
- settings.showfps = 0; /* Do not show FPS */
- settings.sound = 0; /* Sound off by default */
- settings.ai = 0; /* AI off by default */
- if (configfile_load(SETTINGS_FILENAME, config,
- sizeof(config)/sizeof(*config),
- SETTINGS_MIN_VERSION
- ) < 0)
- {
- /* If the loading failed, save a new config file (as the disk is
- already spinning) */
- configfile_save(SETTINGS_FILENAME, config,
- sizeof(config)/sizeof(*config),
- SETTINGS_VERSION);
- }
- /* Keep a copy of the saved version of the settings - so we can check if
- the settings have changed when we quit */
- old_settings = settings;
- /* Initialise the hardware */
- init_PacmanMachine(settings_to_dip(settings));
- #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
- rb->lcd_set_mode(LCD_MODE_PAL256);
- #endif
- /* Load the romset */
- if (loadROMS()) {
- start_time = *rb->current_tick-1;
- gameProc();
- /* Save the user settings if they have changed */
- if (rb->memcmp(&settings,&old_settings,sizeof(settings))!=0) {
- rb->splash(0, "Saving settings...");
- configfile_save(SETTINGS_FILENAME, config,
- sizeof(config)/sizeof(*config),
- SETTINGS_VERSION);
- }
- } else {
- rb->splashf(HZ*2, "No ROMs in %s/pacman/", ROCKBOX_DIR);
- }
- #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
- rb->lcd_set_mode(LCD_MODE_RGB565);
- #endif
- #ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(false);
- #endif
- return PLUGIN_OK;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement