/* * game.cpp * * Copyright (C) 2001 Matt Ownby * * This file is part of DAPHNE, a laserdisc arcade game emulator * * DAPHNE 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. * * DAPHNE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // game.cpp // by Matt Ownby #ifdef WIN32 #pragma warning (disable:4100) // disable warning about unreferenced parameter // this doesn't disable the warnings I want disabled :( #pragma warning (disable:4244) // disable stupid warnings in MSVC's include files #pragma warning (disable:4511) #pragma warning (disable:4512) #pragma warning (disable:4663) #endif #include // for CRC checking #include // STL strings, useful to prevent buffer overrun #include "../daphne.h" // for get_quitflag() #include "../io/homedir.h" #include "../io/conout.h" #include "../io/error.h" #include "../io/unzip.h" #include "../io/mpo_fileio.h" #include "../io/mpo_mem.h" // for better malloc #include "../io/numstr.h" #include "../ldp-out/ldp.h" //#include "../cpu/cpu-debug.h" // for set_cpu_trace #include "../timer/timer.h" #include "../io/input.h" //#include "../io/sram.h" #include "../io/logger_console.h" // for writing to daphne_log.txt file #include "../video/video.h" // for get_screen #include "../video/palette.h" #include "game.h" #ifdef USE_OPENGL #ifdef MAC_OSX #include #else #include #endif #endif using namespace std; // for STL string to compile without problems ... /////////////////////////////////////////////////////////// #ifdef CPU_DEBUG // a generic example of how to setup debug names struct addr_name game_addr_names[] = { { "Start", 0x0000 }, { NULL, 0 } }; #endif // breaks cpu execution into trace mode from whichever point the program is at // This function is executed by typing "break" at the daphne console // This can't be part of the class because I can't figure out how to make it work =] void g_cpu_break (char *s) { // I put this here simply to get rid of warning messages if (s) { } #ifdef CPU_DEBUG // set_cpu_trace(1); #else printline("You have to compile with CPU_DEBUG defined to use the debugger!"); #endif } /////////////////////////////////////////////////////////// game::game() : m_game_paused(false), m_game_uses_video_overlay(true), // since most games do use video overlay, we'll default this to true m_overlay_size_is_dynamic(false), // the overlay size is usually static m_video_overlay_scaled(0), // " " " m_video_overlay_matrix(0), // m_video_screen_width(0), // m_video_screen_height(0), // m_video_screen_size(0), // m_bFullScale(false), // full-scale is disabled by default m_video_overlay_count(2), // default to double buffering because it is conservative m_active_video_overlay(0), // the first overlay (0) starts out as the active one m_finished_video_overlay(0), m_palette_color_count(0), // force game to specify this m_video_row_offset(0), // most games will want this to be 0 m_video_col_offset(0), // " " " m_video_overlay_width(0), // " " " m_video_overlay_height(0), // " " " m_video_overlay_needs_update(true), // it always needs to be updated the first time m_uVideoOverlayVisibleLines(240), // (480/2) for almost all games with overlay m_bMouseEnabled(false) // mouse is disabled for most games { memset(m_video_overlay, 0, sizeof(m_video_overlay)); // clear this structure so we can easily detect whether we are using video overlay or not m_uDiscFPKS = 0; m_disc_fps = 0.0; // m_disc_ms_per_frame = 0.0; m_game_type = GAME_UNDEFINED; m_game_issues = NULL; // assume game has no issues unless we specify some m_miceDetected = -1; m_bPauseKeyEnabled = true; #ifdef CPU_DEBUG addr_names = game_addr_names; #endif m_num_sounds = 0; m_cheat_requested = false; // no cheats until specifically requested m_shortgamename = "game"; // change this to match your game m_nvram_begin = NULL; m_nvram_size = 0; // no nvram by default m_EEPROM_9536 = false; m_rom_list = NULL; m_crc_disabled = false; m_prefer_samples = false; // default to emulated sound m_fastboot = false; m_pLogger = ConsoleLogger::GetInstance(); } game::~game() { // cleanup logger m_pLogger->DeleteInstance(); } // call this instead of init() directly to ensure that some universal stuff gets taken care of bool game::pre_init() { // compute integer values that we will actually use in practice // (floating point is too expensive on GP2X so we're eliminating it for recurring computations) if (m_disc_fps != 0.0) { m_uDiscFPKS = (unsigned int) ((m_disc_fps * 1000.0) + 0.5); // frames per kilosecond (same precision, but an int instead of a float) } /* // if we have nvram that we need to load if (m_nvram_size > 0) { if (m_EEPROM_9536) { string filename = m_nvram_filename; filename += ".gz"; // trail w/ gz since it'll be compressed sram_load(filename.c_str(), (unsigned char *) m_EEPROM_9536_begin, m_nvram_size); } else { string filename = m_shortgamename; filename += ".gz"; // trail w/ gz since it'll be compressed sram_load(filename.c_str(), m_nvram_begin, m_nvram_size); } } */ return init(); } // generic game initialization bool game::init() { bool result = true; // cpu_init(); return result; } // generic game start function. Starts the game playing (usually just begins executing the cpu(s) ) void game::start() { // cpu_execute(); } // call this instead of shutdown directly void game::pre_shutdown() { save_sram(); shutdown(); } // called to ensure sram is saved even if Daphne is terminated improperly void game::save_sram() { /* // if we have nvram that we need to save to disk if (m_nvram_size > 0) { if (m_EEPROM_9536) { string filename = m_nvram_filename; filename += ".gz"; // trail w/ gz since it'll be compressed sram_save(filename.c_str(), (unsigned char *) m_EEPROM_9536_begin, m_nvram_size); } else { string filename = m_shortgamename; filename += ".gz"; // trail w/ gz since it'll be compressed sram_save(filename.c_str(), m_nvram_begin, m_nvram_size); } } */ } // generic game shutdown function void game::shutdown() { // cpu_shutdown(); } // generic game reset function void game::reset() { // cpu_reset(); } // does anything special needed to send an IRQ void game::do_irq(unsigned int which_irq) { // get rid of warnings if (which_irq) { } printline("WARNING : Unhandled IRQ in generic game class! This is probably not what you want!"); } // does anything special needed to send an NMI void game::do_nmi() { printline("WARNING : Unhandled NMI in generic game class! This is probably not what you want!"); } // reads a byte from a 16-bit address space Uint8 game::cpu_mem_read(Uint16 addr) { // return m_cpumem[addr]; return 0; } // reads a byte from a 32-bit address space Uint8 game::cpu_mem_read(Uint32 addr) { // return m_cpumem[addr]; return 0; } // writes a byte to a 16-bit addresss space void game::cpu_mem_write(Uint16 addr, Uint8 value) { // m_cpumem[addr] = value; } // writes a byte to a 32-bit address space void game::cpu_mem_write(Uint32 addr, Uint8 value) { // m_cpumem[addr] = value; } // reads a byte from the cpu's port Uint8 game::port_read(Uint16 port) { char s[81] = { 0 }; port &= 0xFF; sprintf(s, "ERROR: CPU port %x read requested, but this function is unimplemented!", port); printline(s); return(0); } // writes a byte to the cpu's port void game::port_write(Uint16 port, Uint8 value) { char s[81] = { 0 }; port &= 0xFF; sprintf(s, "ERROR: CPU port %x write requested (value %x) but this function is unimplemented!", port, value); printline(s); } // notifies us of the new Program Counter (which most games usually don't care about) void game::update_pc(Uint32 new_pc) { // I put this here to get rid of warnings if (new_pc) { } } void game::input_enable(Uint8 input, int mouseID) { // get rid of warnings if (input) { } printline("Warning: generic input_enable function called, does nothing"); } void game::input_disable(Uint8 input, int mouseID) { // get rid of warnings if (input) { } printline("Warning: generic input_disable function called, does nothing"); } // Added by ScottD void game::OnMouseMotion(Uint16 x, Uint16 y, Sint16 xrel, Sint16 yrel, Uint16 mouseID) { // get rid of warnings if (x || y || xrel || yrel) { } printline("Warning: generic mouse_motion function called, does nothing"); } // by default, this is ignored, but it should be used by specific game drivers to stay in sync with the laserdisc void game::OnVblank() { } void game::OnLDV1000LineChange(bool bIsStatus, bool bIsEnabled) { // get rid of warnings if (bIsStatus || bIsEnabled) { } } // does any video initialization we might need // returns 'true' if the initialization was successful, false if it failed // It is good to use generic video init and shutdown functions because then we minimize the possibility of errors such as forgetting to call palette_shutdown bool game::video_init() { bool result = false; int index = 0; int w; int h; int x; int y; float dx; float dy; float srcx; float srcy; // set instance variables and local variables to the actual screen (or window) dimension m_video_screen_width = w = get_screen_blitter()->w; m_video_screen_height = h = get_screen_blitter()->h; // if this particular game uses video overlay (most do) if (m_game_uses_video_overlay) { // safety check, make sure variables are initialized like we expect them to be ... if ((m_video_overlay_width != 0) && (m_video_overlay_height != 0) && (m_palette_color_count != 0)) { result = true; // it's easier to assume true here and find out false, than the reverse if (m_bFullScale) { m_video_overlay_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0); // create an 8-bit surface // create matrix for scaling the overlay pixmap to the physical surface // - size of overlay pixmap m_video_overlay_width x m_video_overlay_height // - size of physical surface is get_screen()->w x get_screen()->h // - matrix is created as 2dimensional array of "long" values, with size of // the physical surface // each entry in the matrix holds an offset into the overlay pixmap array from // which the pixel is copied into to the corresponding surface pixmap if ( (m_video_overlay_matrix = (long*) MPO_MALLOC(sizeof(long)*w*h)) == NULL) { printline("MEM ERROR : malloc failed in video_init!"); return false; } /*endif*/ dx=(float)m_video_overlay_width/(float)w; // 256/640=0.4 dy=(float)m_video_overlay_height/(float)h; // 256/480=0.5333 srcx=0; srcy=0; for (y=0; yw*dst->h; Uint8* srcpixmap=(Uint8*)src->pixels; Uint8* dstpixmap=(Uint8*)dst->pixels; for (i=0; i= instead of >) if (m_active_video_overlay >= m_video_overlay_count) { m_active_video_overlay = 0; } video_repaint(); // call game-specific function to get palette refreshed m_video_overlay_needs_update = false; // game will need to set this value to true next time it becomes needful for us to redraw the screen // if we are in non-VLDP mode, then we can blit to the main surface right here, // otherwise we do nothing because the yuv_callback in ldp-vldp.cpp will take care of it if (!g_ldp->is_vldp()) { #ifdef USE_OPENGL // if we're not in OpenGL mode if (!get_use_opengl()) { #endif // If we're not scaling the video if (!m_bFullScale) { vid_blit(m_video_overlay[m_active_video_overlay], 0, 0); } else { // scale game graphics to the screen dimensions Scale(m_video_overlay[m_active_video_overlay], m_video_overlay_scaled, m_video_overlay_matrix); vid_blit(m_video_overlay_scaled, 0, 0); } /*endelse*/ #ifdef USE_OPENGL } // else we're using OpenGL else { vid_blank(); // openGL requires this if (!m_bFullScale) { SDL_Surface *srf = m_video_overlay[m_active_video_overlay]; // blit in the center of the screen vid_blit(srf, (m_video_screen_width >> 1) - (srf->w >> 1), (m_video_screen_height >> 1) - (srf->h >> 1)); } // else if 'fullscale' is enabled else { GLfloat fXScale = (GLfloat) m_video_screen_width / m_video_overlay_width; GLfloat fYScale = (GLfloat) m_video_screen_height / m_video_overlay_height; glPushMatrix(); glScalef(fXScale, fYScale, 1.0); // blit in the center of the screen SDL_Surface *srf = m_video_overlay[m_active_video_overlay]; vid_blit(srf, (m_video_screen_width >> 1) - (srf->w >> 1), (m_video_screen_height >> 1) - (srf->h >> 1)); glPopMatrix(); } } // end if using opengl #endif // USE_OPENGL vid_flip(); } // end if this isn't VLDP m_finished_video_overlay = m_active_video_overlay; } } // forces the video overlay to be redrawn to the screen // This is necessary when the screen has been clobbered (such as when the debug console is down) void game::video_force_blit() { // if the game uses a video overlay, we have to go through this video_blit routine to update a bunch of variables if (m_game_uses_video_overlay) { m_video_overlay_needs_update = true; video_blit(); } // otherwise we can just call video repaint directly else { video_repaint(); } } // sets up the game's palette, this is a game-specific function void game::palette_calculate() { SDL_Color temp_color = { 0 }; // fill color palette with sensible grey defaults for (int i = 0; i < m_palette_color_count; i++) { temp_color.r = (unsigned char) i; temp_color.g = (unsigned char) i; temp_color.b = (unsigned char) i; palette_set_color(i, temp_color); } } // redraws the current active video overlay buffer (but doesn't blit anything to the screen) // This is a game-specific function void game::video_repaint() { } void game::set_video_overlay_needs_update(bool value) { m_video_overlay_needs_update = value; } unsigned int game::get_video_overlay_height() { return m_video_overlay_height; } unsigned int game::get_video_overlay_width() { return m_video_overlay_width; } void game::set_prefer_samples(bool value) { m_prefer_samples = value; } void game::set_fastboot(bool value) { m_fastboot = value; } // generic preset function, does nothing void game::set_preset(int preset) { printline("NOTE: There are no presets defined for the game you have chosen!"); } // generic version function, does nothing void game::set_version(int version) { printline("NOTE: There are no alternate versions defined for the game you have chosen!"); } // returns false if there was an error trying to set the bank value (ie if the user requested an illegal bank) bool game::set_bank(unsigned char which_bank, unsigned char value) { bool result = false; // give them an error to help them troubleshoot any problem they are having with their command line printline("ERROR: The ability to set bank values is not supported in this game."); return result; } // this is called by cmdline.cpp if it gets any cmdline parameters that it doesn't recognize // returns true if this argument was recognized and processed, // or false is this argument wasn't recognized (and therefore the command line is bad on a whole) bool game::handle_cmdline_arg(const char *arg) { return false; // no extra arguments supported by default } // prevents daphne from verifying that the ROM images' CRC values are correct, useful when testing new ROMs void game::disable_crc() { m_crc_disabled = true; } // routine to load roms // returns true if there were no errors bool game::load_roms() { bool result = true; // we must assume result is true in case the game has no roms to load at all // if a rom list has been defined, then begin loading roms if (m_rom_list) { int index = 0; const struct rom_def *rom = &m_rom_list[0]; string opened_zip_name = ""; // the name of the zip file that we currently have open (if we have one open) unzFile zip_file = NULL; // pointer to open zip file (NULL if file is closed) // go until we get an error or we run out of roms to load do { string path, zip_path = ""; unsigned int crc = crc32(0L, Z_NULL, 0); // if this game explicitely specifies a subdirectory if (rom->dir) { path = rom->dir; zip_path = path + ".zip"; // append zip extension ... } // otherwise use shortgamename by default else { path = m_shortgamename; zip_path = path + ".zip"; // append zip extension ... } //Use homedir to locate the compressed rom zip_path = g_homedir.get_romfile(zip_path); // if we have not opened a ZIP file, or if we need to open a new zip file ... if ((!zip_file) || (zip_path.compare(opened_zip_name) != 0)) { // if we need to open a zip file ... if (!zip_file) { zip_file = unzOpen(zip_path.c_str()); } // we need to open a different zip file ... else { // string s = "Closing " + opened_zip_name + " and attempting to open " + zip_path; // just for debugging to make sure this is behaving properly unzClose(zip_file); zip_file = unzOpen(zip_path.c_str()); } // if we successfully opened the file ... if (zip_file) { opened_zip_name = zip_path; } } result = false; // if we have a zip file open, try to load the ROM from this file first ... if (zip_file) { result = load_compressed_rom(rom->filename, zip_file, rom->buf, rom->size); } // if we were unable to open the rom from a zip file, try to open it as an uncompressed file if (!result) { result = load_rom(rom->filename, path.c_str(), rom->buf, rom->size); } // if file was loaded and was proper length, check CRC if (result) { if (!m_crc_disabled) //skip if user doesn't care { crc = crc32(crc, rom->buf, rom->size); if (rom->crc32 == 0) //skip if crc is set to 0 (game driver doesn't care) { crc=0; } // if CRC's don't match if (crc != rom->crc32) { char s[160]; sprintf(s, "ROM CRC checked failed for %s, expected %x, got %x", rom->filename, rom->crc32, crc); printerror(s); // warn them about this disaster :) printline(s); } } } // if ROM could not be loaded else { string s = "ROM "; s += rom->filename; s += " couldn't be found in roms/"; s += path; s += "/, or in "; s += zip_path; printerror(s.c_str()); // if this game borrows roms from another game, point that out to the user to help // them troubleshoot if (rom->dir) { s = "NOTE : this ROM comes from the folder '"; s += rom->dir; s += "', which belongs to another game."; printline(s.c_str()); s = "You also NEED to get the ROMs for the game that uses the directory '"; s += rom->dir; s += "'."; printline(s.c_str()); } } index++; rom = &m_rom_list[index]; // move to next entry } while (result && rom->filename); // if we had a zip file open, close it now if (zip_file) { unzClose(zip_file); zip_file = NULL; } patch_roms(); } return(result); } // returns true if the file in question exists, and has the proper CRC32 // 'gamedir' is which rom directory (or .ZIP file) this file is expected to be in bool game::verify_required_file2(const char *filename, const char *gamedir, Uint32 filecrc32) { Uint8 *readme_test = NULL; bool passed_test = false; string path = "/"; path += gamedir; path += "/"; path += filename; // TRY UNCOMPRESSED FIRST string uncompressed_path = g_homedir.get_homedir(); uncompressed_path.append(path); struct mpo_io *io; io = mpo_open(uncompressed_path.c_str(), MPO_OPEN_READONLY); // if file is opened successfully if (io) { readme_test = new Uint8[io->size]; // allocate file buffer if (readme_test) { unsigned int crc = crc32(0L, Z_NULL, 0); // zlib crc32 // if we are able to read in mpo_read(readme_test, io->size, NULL, io); crc = crc32(crc, readme_test, io->size); // if the required file has been unaltered, allow user to continue //char s1[255]; //sprintf(s1,"CRC returns %d",crc); //printline(s1); // commenting this for now... --RDG //if (crc == filecrc32) { passed_test = true; } delete [] readme_test; // free allocated mem readme_test = NULL; } mpo_close(io); } return passed_test; } // loads size # of bytes from filename into buf // returns true if successful, or false if there was an error bool game::load_rom(const char *filename, Uint8 *buf, Uint32 size) { struct mpo_io *F; MPO_BYTES_READ bytes_read = 0; bool result = false; string fullpath = g_homedir.get_romfile(filename); // pathname to roms directory string s = ""; outstr("Loading "); outstr(fullpath.c_str()); outstr(" ... "); F = mpo_open(fullpath.c_str(), MPO_OPEN_READONLY); // if file was opened successfully if (F) { mpo_read(buf, size, &bytes_read, F); // if we read in the # of bytes we expected to if (bytes_read == size) { result = true; } // notify the user what the problem is else { s = "error in rom_load: expected " + numstr::ToStr(size) + " but only read " + numstr::ToStr((unsigned int) bytes_read); printline(s.c_str()); } mpo_close(F); } s = numstr::ToStr((unsigned int) bytes_read) + " bytes read into memory"; printline(s.c_str()); return(result); } // transition function ... bool game::load_rom(const char *filename, const char *directory, Uint8 *buf, Uint32 size) { string full_path = directory; full_path += "/"; full_path += filename; return load_rom(full_path.c_str(), buf, size); } // similar to load_rom except this function loads a rom image from a .zip file // the previously-opened zip file is indicated by 'opened_zip_file' // true is returned only if the rom was loaded, and it was the expected length bool game::load_compressed_rom(const char *filename, unzFile opened_zip_file, Uint8 *buf, Uint32 size) { bool result = false; outstr("Loading compressed ROM image "); outstr(filename); outstr("..."); // try to locate requested rom file inside .ZIP archive and proceed if successful // (the '2' indicates case-insensitivity) if (unzLocateFile(opened_zip_file, filename, 2) == UNZ_OK) { // try to open the current file that we've located if (unzOpenCurrentFile(opened_zip_file) == UNZ_OK) { // read this file Uint32 bytes_read = (Uint32) unzReadCurrentFile(opened_zip_file, buf, size); unzCloseCurrentFile(opened_zip_file); // if we read what we expected to read ... if (bytes_read == size) { char s[81]; sprintf(s, "%d bytes read.", bytes_read); printline(s); result = true; } else { printline("unexpected read result!"); } } else { printline("could not open current file!"); } } else { printline("file not found in .ZIP archive!"); } return result; } // modify roms (apply cheats, for example) after they are loaded // this can also be used for any post-rom-loading procedure, such as verifying the existence of readme files for DLE/SAE void game::patch_roms() { } // how many pixels down to shift video overlay int game::get_video_row_offset() { return m_video_row_offset; } // how many pixels to the right to shift video overlay int game::get_video_col_offset() { return m_video_col_offset; } unsigned game::get_video_visible_lines() { return m_uVideoOverlayVisibleLines; } SDL_Surface *game::get_video_overlay(int index) { SDL_Surface *result = NULL; // safety check if (index < m_video_overlay_count) { result = m_video_overlay[index]; } return result; } // gets surface that's being drawn SDL_Surface *game::get_active_video_overlay() { return m_video_overlay[m_active_video_overlay]; } // gets last surface to be completely drawn (so it can be displayed without worrying about tearing or flickering) SDL_Surface *game::get_finished_video_overlay() { return m_video_overlay[m_finished_video_overlay]; } // mainly used by ldp-vldp.cpp so it doesn't print a huge warning message if the overlay's size is dynamic bool game::is_overlay_size_dynamic() { return m_overlay_size_is_dynamic; } SDL_Surface *game::get_scaled_video_overlay() { return m_video_overlay_scaled; } bool game::IsFullScaleEnabled() { return m_bFullScale; } void game::SetFullScale(bool bEnabled) { m_bFullScale = bEnabled; } // end-add // enables a cheat (any cheat) in the current game. Unlimited lives is probably the most common. void game::enable_cheat() { m_cheat_requested = true; } unsigned int game::get_disc_fpks() { return m_uDiscFPKS; } // UPDATE : it's too expensive to use floating point on GP2X, so we are phasing this function out in // favor of integer operations. // returns how many ms per frame the disc runs at //double game::get_disc_ms_per_frame() //{ // return m_disc_ms_per_frame; //} Uint8 game::get_game_type() { return m_game_type; } Uint32 game::get_num_sounds() { return m_num_sounds; } const char *game::get_sound_name(int whichone) { return m_sound_name[whichone]; } // returns a string of text that explains the problems with the game OR else null if the game has no problems :) const char *game::get_issues() { return m_game_issues; } void game::set_issues(const char *issues) { m_game_issues = issues; } void game::toggle_game_pause() { // if the game is already paused ... if (m_game_paused) { // cpu_unpause(); g_ldp->pre_play(); m_game_paused = false; } // for now we will only support game pausing if the disc is playing else if (g_ldp->get_status() == LDP_PLAYING) { // char frame[6]; // Uint16 cur_frame = g_ldp->get_current_frame(); // cpu_pause(); g_ldp->pre_pause(); // If seek delay is enabled, we can't search here because the seek delay depends // upon the cpu running (ie pre_think getting called regularly) /* g_ldp->framenum_to_frame(cur_frame, frame); g_ldp->pre_search(frame, false); // pause the disc on the frame we think we're on (not the frame we're actually on) // wait for seek to complete // (using non-blocking seeking to avoid an extra cpu_pause) while (g_ldp->get_status() == LDP_SEARCHING) { make_delay(1); } */ m_game_paused = true; } } const char *game::get_shortgamename() { return m_shortgamename; } #ifdef CPU_DEBUG // returns either a name for the address or else NULL if no name exists // Used for debugging to improve readability (to assign function and variable names) const char *game::get_address_name(unsigned int addr) { const char *name = NULL; int i = 0; // loop until we've hit the end of our memory names or until we've found a match for (;;) { // if we're at the end of the list if (addr_names[i].name == NULL) { break; } else if (addr_names[i].address == addr) { name = addr_names[i].name; break; } i++; } return(name); } #endif // CPU_DEBUG bool game::get_mouse_enabled() { return m_bMouseEnabled; } void game::set_mouse_enabled(bool thisFlag) { m_bMouseEnabled = thisFlag; } int game::get_mice_detected() { return m_miceDetected; } void game::set_mice_detected(int thisMany) { m_miceDetected = thisMany; } bool game::get_pause_key_flag() { return m_bPauseKeyEnabled; } void game::set_pause_key_flag(bool thisBol) { m_bPauseKeyEnabled = thisBol; }