diff --git a/docs/index.html b/docs/index.html index a4505b190..634d9b31c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1887,6 +1887,42 @@ Shift-Cmd + n + + Toggle TIA Player0 collisions + Shift-Alt + z + TODO + + + + Toggle TIA Player1 collisions + Shift-Alt + x + TODO + + + + Toggle TIA Missile0 collisions + Shift-Alt + c + TODO + + + + Toggle TIA Missile1 collisions + Shift-Alt + v + TODO + + + + Toggle TIA Ball collisions + Shift-Alt + b + TODO + + + + Toggle TIA Playfield collisions + Shift-Alt + n + TODO + + Toggle TIA HMOVE blanks Alt + m @@ -1910,6 +1946,18 @@ Alt + / Shift-Cmd + / + + + Turn all TIA collisions off + Shift-Alt + . + TODO + + + + Turn all TIA collisions on + Shift-Alt + / + TODO +

Other Keys (cannot be remapped, except those marked with '*')

diff --git a/src/common/Version.hxx b/src/common/Version.hxx index ee34b0a41..d46f1cce3 100644 --- a/src/common/Version.hxx +++ b/src/common/Version.hxx @@ -19,7 +19,7 @@ #ifndef VERSION_HXX #define VERSION_HXX -#define STELLA_BASE_VERSION "3.0" +#define STELLA_BASE_VERSION "3.1_svn" #ifdef NIGHTLY_BUILD #define STELLA_VERSION STELLA_BASE_VERSION "pre-" NIGHTLY_BUILD diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 385b0210b..5ccf725b7 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -794,6 +794,14 @@ void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const myOSystem->frameBuffer().showMessage(message); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show) const +{ + bool result = myTIA->toggleCollision(bit); + string message = bitname + (result ? " collision enabled" : " collsion disabled"); + myOSystem->frameBuffer().showMessage(message); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleHMOVE() const { @@ -811,6 +819,14 @@ void Console::enableBits(bool enable) const myOSystem->frameBuffer().showMessage(message); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::enableCollisions(bool enable) const +{ + myTIA->enableCollisions(enable); + string message = string("TIA collisions") + (enable ? " enabled" : " disabled"); + myOSystem->frameBuffer().showMessage(message); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleFixedColors() const { diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 4eb131bfc..3d5c54b47 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -265,6 +265,17 @@ class Console : public Serializable void toggleHMOVE() const; void enableBits(bool enable) const; + /** + Toggles the TIA collisions specified in the method name. + */ + void toggleP0Collision() const { toggleTIACollision(P0Bit, "P0"); } + void toggleP1Collision() const { toggleTIACollision(P1Bit, "P1"); } + void toggleM0Collision() const { toggleTIACollision(M0Bit, "M0"); } + void toggleM1Collision() const { toggleTIACollision(M1Bit, "M1"); } + void toggleBLCollision() const { toggleTIACollision(BLBit, "BL"); } + void togglePFCollision() const { toggleTIACollision(PFBit, "PF"); } + void enableCollisions(bool enable) const; + /** Toggles the TIA 'fixed debug colors' mode. */ @@ -296,6 +307,7 @@ class Console : public Serializable const uInt32* getPalette(int direction) const; void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; + void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; private: // Pointer to the osystem object diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index da5cade39..f70c3d2db 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -369,27 +369,45 @@ void EventHandler::poll(uInt64 time) break; case SDLK_z: - myOSystem->console().toggleP0Bit(); + if(mod & KMOD_SHIFT) + myOSystem->console().toggleP0Collision(); + else + myOSystem->console().toggleP0Bit(); break; case SDLK_x: - myOSystem->console().toggleP1Bit(); + if(mod & KMOD_SHIFT) + myOSystem->console().toggleP1Collision(); + else + myOSystem->console().toggleP1Bit(); break; case SDLK_c: - myOSystem->console().toggleM0Bit(); + if(mod & KMOD_SHIFT) + myOSystem->console().toggleM0Collision(); + else + myOSystem->console().toggleM0Bit(); break; case SDLK_v: - myOSystem->console().toggleM1Bit(); + if(mod & KMOD_SHIFT) + myOSystem->console().toggleM1Collision(); + else + myOSystem->console().toggleM1Bit(); break; case SDLK_b: - myOSystem->console().toggleBLBit(); + if(mod & KMOD_SHIFT) + myOSystem->console().toggleBLCollision(); + else + myOSystem->console().toggleBLBit(); break; case SDLK_n: - myOSystem->console().togglePFBit(); + if(mod & KMOD_SHIFT) + myOSystem->console().togglePFCollision(); + else + myOSystem->console().togglePFBit(); break; case SDLK_m: @@ -401,11 +419,17 @@ void EventHandler::poll(uInt64 time) break; case SDLK_PERIOD: - myOSystem->console().enableBits(false); + if(mod & KMOD_SHIFT) + myOSystem->console().enableCollisions(false); + else + myOSystem->console().enableBits(false); break; case SDLK_SLASH: - myOSystem->console().enableBits(true); + if(mod & KMOD_SHIFT) + myOSystem->console().enableCollisions(true); + else + myOSystem->console().enableBits(true); break; case SDLK_p: // Alt-p toggles phosphor effect diff --git a/src/emucore/StateManager.cxx b/src/emucore/StateManager.cxx index 73abbf2af..355d6d280 100644 --- a/src/emucore/StateManager.cxx +++ b/src/emucore/StateManager.cxx @@ -28,8 +28,8 @@ #include "StateManager.hxx" -#define STATE_HEADER "03000000state" -#define MOVIE_HEADER "03000000movie" +#define STATE_HEADER "03000100state" +#define MOVIE_HEADER "03000100movie" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager::StateManager(OSystem* osystem) diff --git a/src/emucore/TIA.cxx b/src/emucore/TIA.cxx index 143120ae4..d33dd2d6f 100644 --- a/src/emucore/TIA.cxx +++ b/src/emucore/TIA.cxx @@ -125,7 +125,7 @@ void TIA::reset() // Currently no objects are enabled or selectively disabled myEnabledObjects = 0; - myDisabledObjects = 0; + myDisabledObjects = 0xFF; myAllowHMOVEBlanks = true; // Some default values for the registers @@ -144,6 +144,7 @@ void TIA::reset() myHMP0 = myHMP1 = myHMM0 = myHMM1 = myHMBL = 0; myVDELP0 = myVDELP1 = myVDELBL = myRESMP0 = myRESMP1 = false; myCollision = 0; + myCollisionEnabledMask = 0xFFFFFFFF; myPOSP0 = myPOSP1 = myPOSM0 = myPOSM1 = myPOSBL = 0; // Some default values for the "current" variables @@ -360,6 +361,7 @@ bool TIA::save(Serializer& out) const out.putBool(myRESMP0); out.putBool(myRESMP1); out.putInt(myCollision); + out.putInt(myCollisionEnabledMask); out.putByte((char)myCurrentGRP0); out.putByte((char)myCurrentGRP1); @@ -468,6 +470,7 @@ bool TIA::load(Serializer& in) myRESMP0 = in.getBool(); myRESMP1 = in.getBool(); myCollision = (uInt16) in.getInt(); + myCollisionEnabledMask = in.getInt(); myCurrentGRP0 = (uInt8) in.getByte(); myCurrentGRP1 = (uInt8) in.getByte(); @@ -742,6 +745,49 @@ bool TIA::toggleBit(TIABit b, uInt8 mode) return on; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::enableCollisions(bool mode) +{ + toggleCollision(P0Bit, mode ? 1 : 0); + toggleCollision(P1Bit, mode ? 1 : 0); + toggleCollision(M0Bit, mode ? 1 : 0); + toggleCollision(M1Bit, mode ? 1 : 0); + toggleCollision(BLBit, mode ? 1 : 0); + toggleCollision(PFBit, mode ? 1 : 0); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool TIA::toggleCollision(TIABit b, uInt8 mode) +{ + uInt16 enabled = myCollisionEnabledMask >> 16; + + // If mode is 0 or 1, use it as a boolean (off or on) + // Otherwise, flip the state + bool on = (mode == 0 || mode == 1) ? bool(mode) : !(enabled & b); + if(on) enabled |= b; + else enabled &= ~b; + + // Assume all collisions are on, then selectively turn the desired ones off + uInt16 mask = 0xffff; + if(!(enabled & P0Bit)) + mask &= ~(Cx_M0P0 | Cx_M1P0 | Cx_P0PF | Cx_P0BL | Cx_P0P1); + if(!(enabled & P1Bit)) + mask &= ~(Cx_M0P1 | Cx_M1P1 | Cx_P1PF | Cx_P1BL | Cx_P0P1); + if(!(enabled & M0Bit)) + mask &= ~(Cx_M0P0 | Cx_M0P1 | Cx_M0PF | Cx_M0BL | Cx_M0M1); + if(!(enabled & M1Bit)) + mask &= ~(Cx_M1P0 | Cx_M1P1 | Cx_M1PF | Cx_M1BL | Cx_M0M1); + if(!(enabled & BLBit)) + mask &= ~(Cx_P0BL | Cx_P1BL | Cx_M0BL | Cx_M1BL | Cx_BLPF); + if(!(enabled & PFBit)) + mask &= ~(Cx_P0PF | Cx_P1PF | Cx_M0PF | Cx_M1PF | Cx_BLPF); + + // Now combine the masks + myCollisionEnabledMask = (enabled << 16) | mask; + + return on; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleHMOVEBlank() { @@ -965,22 +1011,48 @@ void TIA::updateFrame(Int32 clock) // simulates the behaviour as visually seen in the aforementioned // ROMs. Other ROMs may break this simulation; more testing is // required to figure out what's really going on here. - if(myHMM0mmr && myPOSM0 % 4 == 3) + if(myHMM0mmr) { - // Stretch this missle so it's 4 pixels wide, with the 3rd pixel - // blanked out; this is indicated by using a size of '4' - myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03] - [myNUSIZ0 & 0x07][4][160 - (myPOSM0 & 0xFC)]; + switch(myPOSM0 % 4) + { + case 3: + // Stretch this missle so it's 2 pixels wide and shifted one + // pixel to the left + myCurrentM0Mask = &TIATables::MxMask[(myPOSM0-1) & 0x03] + [myNUSIZ0 & 0x07][((myNUSIZ0 & 0x30) >> 4)|1][160 - ((myPOSM0-1) & 0xFC)]; + break; + case 2: + // Missle is disabled on this line + myCurrentM0Mask = &TIATables::DisabledMask[0]; + break; + default: + myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03] + [myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)]; + break; + } } else myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03] [myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)]; - if(myHMM1mmr && myPOSM1 % 4 == 3) + if(myHMM1mmr) { - // Stretch this missle so it's 4 pixels wide, with the 3rd pixel - // blanked out; this is indicated by using a size of '4' - myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03] - [myNUSIZ1 & 0x07][4][160 - (myPOSM1 & 0xFC)]; + switch(myPOSM1 % 4) + { + case 3: + // Stretch this missle so it's 2 pixels wide and shifted one + // pixel to the left + myCurrentM1Mask = &TIATables::MxMask[(myPOSM1-1) & 0x03] + [myNUSIZ1 & 0x07][((myNUSIZ1 & 0x30) >> 4)|1][160 - ((myPOSM1-1) & 0xFC)]; + break; + case 2: + // Missle is disabled on this line + myCurrentM1Mask = &TIATables::DisabledMask[0]; + break; + default: + myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03] + [myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)]; + break; + } } else myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03] @@ -1089,46 +1161,47 @@ uInt8 TIA::peek(uInt16 addr) updateFrame(mySystem->cycles() * 3); uInt8 value = 0x00; + uInt16 collision = myCollision & (uInt16)myCollisionEnabledMask; switch(addr & 0x000f) { case CXM0P: - value = ((myCollision & Cx_M0P1) ? 0x80 : 0x00) | - ((myCollision & Cx_M0P0) ? 0x40 : 0x00); + value = ((collision & Cx_M0P1) ? 0x80 : 0x00) | + ((collision & Cx_M0P0) ? 0x40 : 0x00); break; case CXM1P: - value = ((myCollision & Cx_M1P0) ? 0x80 : 0x00) | - ((myCollision & Cx_M1P1) ? 0x40 : 0x00); + value = ((collision & Cx_M1P0) ? 0x80 : 0x00) | + ((collision & Cx_M1P1) ? 0x40 : 0x00); break; case CXP0FB: - value = ((myCollision & Cx_P0PF) ? 0x80 : 0x00) | - ((myCollision & Cx_P0BL) ? 0x40 : 0x00); + value = ((collision & Cx_P0PF) ? 0x80 : 0x00) | + ((collision & Cx_P0BL) ? 0x40 : 0x00); break; case CXP1FB: - value = ((myCollision & Cx_P1PF) ? 0x80 : 0x00) | - ((myCollision & Cx_P1BL) ? 0x40 : 0x00); + value = ((collision & Cx_P1PF) ? 0x80 : 0x00) | + ((collision & Cx_P1BL) ? 0x40 : 0x00); break; case CXM0FB: - value = ((myCollision & Cx_M0PF) ? 0x80 : 0x00) | - ((myCollision & Cx_M0BL) ? 0x40 : 0x00); + value = ((collision & Cx_M0PF) ? 0x80 : 0x00) | + ((collision & Cx_M0BL) ? 0x40 : 0x00); break; case CXM1FB: - value = ((myCollision & Cx_M1PF) ? 0x80 : 0x00) | - ((myCollision & Cx_M1BL) ? 0x40 : 0x00); + value = ((collision & Cx_M1PF) ? 0x80 : 0x00) | + ((collision & Cx_M1BL) ? 0x40 : 0x00); break; case CXBLPF: - value = (myCollision & Cx_BLPF) ? 0x80 : 0x00; + value = (collision & Cx_BLPF) ? 0x80 : 0x00; break; case CXPPMM: - value = ((myCollision & Cx_P0P1) ? 0x80 : 0x00) | - ((myCollision & Cx_M0M1) ? 0x40 : 0x00); + value = ((collision & Cx_P0P1) ? 0x80 : 0x00) | + ((collision & Cx_M0M1) ? 0x40 : 0x00); break; case INPT0: @@ -1345,9 +1418,6 @@ void TIA::poke(uInt16 addr, uInt8 value) if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79)) myCurrentPFMask = TIATables::PFMask[myCTRLPF & 0x01]; - myCurrentBLMask = &TIATables::BLMask[myPOSBL & 0x03] - [(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)]; - break; } diff --git a/src/emucore/TIA.hxx b/src/emucore/TIA.hxx index c34fe3a48..8fc529621 100644 --- a/src/emucore/TIA.hxx +++ b/src/emucore/TIA.hxx @@ -249,14 +249,16 @@ class TIA : public Device bool scanlinePos(uInt16& x, uInt16& y) const; /** - Enables/disables all TIABit bits. + Enables/disables all TIABit bits. Note that disabling a graphical + object also disables its collisions. @param mode Whether to enable or disable all bits */ void enableBits(bool mode); /** - Enables/disable/toggle the specified TIA bit. + Enables/disable/toggle the specified TIA bit. Note that disabling a + graphical object also disables its collisions. @param mode 1/0 indicates on/off, and values greater than 1 mean flip the bit from its current state @@ -265,6 +267,23 @@ class TIA : public Device */ bool toggleBit(TIABit b, uInt8 mode = 2); + /** + Enables/disables all TIABit collisions. + + @param mode Whether to enable or disable all collisions + */ + void enableCollisions(bool mode); + + /** + Enables/disable/toggle the specified TIA bit collision. + + @param mode 1/0 indicates on/off, and values greater than 1 mean + flip the collision from its current state + + @return Whether the collision was enabled or disabled + */ + bool toggleCollision(TIABit b, uInt8 mode = 2); + /** Toggle the display of HMOVE blanks. @@ -452,6 +471,15 @@ class TIA : public Device uInt16 myCollision; // Collision register + // Determines whether specified collisions are enabled or disabled + // The lower 16 bits are and'ed with the collision register to mask out + // any collisions we don't want to be processed + // The upper 16 bits are used to store which objects is currently + // enabled or disabled + // This is necessary since there are 15 collision combinations which + // are controlled by 6 objects + uInt32 myCollisionEnabledMask; + // Note that these position registers contain the color clock // on which the object's serial output should begin (0 to 159) Int16 myPOSP0; // Player 0 position register