#include <cassert>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
#include "AtariVox.hxx"
#include "Booster.hxx"
#include "Cart.hxx"
#include "Console.hxx"
#include "Control.hxx"
#include "Driving.hxx"
#include "Event.hxx"
#include "Joystick.hxx"
#include "Keyboard.hxx"
#include "M6502Hi.hxx"
#include "M6502Low.hxx"
#include "M6532.hxx"
#include "MediaSrc.hxx"
#include "Paddles.hxx"
#include "Props.hxx"
#include "PropsSet.hxx"
#include "Settings.hxx"
#include "Sound.hxx"
#include "Switches.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "OSystem.hxx"
#include "Version.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Debugger.hxx"
#endif
#ifdef CHEATCODE_SUPPORT
#include "CheatManager.hxx"
#endif
using namespace std;
#include "../common/Log.hpp"
Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
: myOSystem(osystem),
myProperties(props),
myUserPaletteDefined(false)
{
myControllers[0] = 0;
myControllers[1] = 0;
myMediaSource = 0;
mySwitches = 0;
mySystem = 0;
myEvent = 0;
myEvent = myOSystem->event();
const string& left = myProperties.get(Controller_Left);
const string& right = myProperties.get(Controller_Right);
int leftPort, rightPort;
if(myProperties.get(Console_SwapPorts) == "NO")
{
leftPort = 0; rightPort = 1;
}
else
{
leftPort = 1; rightPort = 0;
}
bool swapPaddles = myProperties.get(Controller_SwapPaddles) == "YES";
if(left == "BOOSTER-GRIP")
{
myControllers[leftPort] = new BoosterGrip(Controller::Left, *myEvent);
}
else if(left == "DRIVING")
{
myControllers[leftPort] = new Driving(Controller::Left, *myEvent);
}
else if((left == "KEYBOARD") || (left == "KEYPAD"))
{
myControllers[leftPort] = new Keyboard(Controller::Left, *myEvent);
}
else if(left == "PADDLES")
{
myControllers[leftPort] = new Paddles(Controller::Left, *myEvent, swapPaddles);
}
else
{
myControllers[leftPort] = new Joystick(Controller::Left, *myEvent);
}
if(right == "BOOSTER-GRIP")
{
myControllers[rightPort] = new BoosterGrip(Controller::Right, *myEvent);
}
else if(right == "DRIVING")
{
myControllers[rightPort] = new Driving(Controller::Right, *myEvent);
}
else if((right == "KEYBOARD") || (right == "KEYPAD"))
{
myControllers[rightPort] = new Keyboard(Controller::Right, *myEvent);
}
else if(right == "PADDLES")
{
myControllers[rightPort] = new Paddles(Controller::Right, *myEvent, swapPaddles);
}
#ifdef ATARIVOX_SUPPORT
else if(right == "ATARIVOX")
{
myControllers[rightPort] = new AtariVox(Controller::Right, *myEvent);
}
#endif
else
{
myControllers[rightPort] = new Joystick(Controller::Right, *myEvent);
}
mySwitches = new Switches(*myEvent, myProperties);
mySystem = new System();
myControllers[0]->setSystem(mySystem);
myControllers[1]->setSystem(mySystem);
M6502* m6502;
if(myOSystem->settings().getString("cpu") == "low") {
m6502 = new M6502Low(1);
}
else {
m6502 = new M6502High(1);
}
#ifdef DEBUGGER_SUPPORT
m6502->attach(myOSystem->debugger());
#endif
M6532* m6532 = new M6532(*this);
TIA *tia = new TIA(*this, myOSystem->settings());
tia->setSound(myOSystem->sound());
mySystem->attach(m6502);
mySystem->attach(m6532);
mySystem->attach(tia);
mySystem->attach(cart);
myMediaSource = tia;
myCart = cart;
myRiot = m6532;
ostringstream buf;
buf << " Cart Name: " << myProperties.get(Cartridge_Name) << endl
<< " Cart MD5: " << myProperties.get(Cartridge_MD5) << endl;
myDisplayFormat = myProperties.get(Display_Format);
buf << " Display Format: " << myDisplayFormat;
if(myDisplayFormat == "AUTO-DETECT" ||
myOSystem->settings().getBool("rominfo"))
{
mySystem->reset();
int palCount = 0;
for(int i = 0; i < 60; ++i)
{
myMediaSource->update();
if(i >= 30 && myMediaSource->scanlines() > 285)
++palCount;
}
myDisplayFormat = (palCount >= 15) ? "PAL" : "NTSC";
if(myProperties.get(Display_Format) == "AUTO-DETECT")
buf << " ==> " << myDisplayFormat;
}
buf << endl << cart->about();
if((myDisplayFormat == "PAL" || myDisplayFormat == "SECAM") &&
myProperties.get(Display_Height) == "210")
myProperties.set(Display_Height, "250");
mySystem->reset();
myAboutString = buf.str();
}
Console::~Console()
{
delete mySystem;
delete mySwitches;
delete myControllers[0];
delete myControllers[1];
}
void Console::toggleFormat()
{
int framerate = 60;
if(myDisplayFormat == "NTSC")
{
myDisplayFormat = "PAL";
myProperties.set(Display_Format, myDisplayFormat);
mySystem->reset();
framerate = 50;
}
else if(myDisplayFormat == "PAL")
{
myDisplayFormat = "PAL60";
myProperties.set(Display_Format, myDisplayFormat);
mySystem->reset();
framerate = 60;
}
else if(myDisplayFormat == "PAL60")
{
myDisplayFormat = "SECAM";
myProperties.set(Display_Format, myDisplayFormat);
mySystem->reset();
framerate = 50;
}
else if(myDisplayFormat == "SECAM")
{
myDisplayFormat = "NTSC";
myProperties.set(Display_Format, myDisplayFormat);
mySystem->reset();
framerate = 60;
}
myOSystem->colourPalette().setPalette(myOSystem->settings().getString("palette"), myDisplayFormat);
myOSystem->setFramerate(framerate);
myOSystem->sound().setFrameRate(framerate);
}
void Console::togglePalette()
{
string palette, message;
palette = myOSystem->settings().getString("palette");
if(palette == "standard") {
palette = "z26";
message = "Z26 palette";
}
else if(palette == "z26") {
if(myUserPaletteDefined)
{
palette = "user";
message = "User-defined palette";
}
else
{
palette = "standard";
message = "Standard Stella palette";
}
}
else if(palette == "user") {
palette = "standard";
message = "Standard Stella palette";
}
else {
palette = "standard";
message = "Standard Stella palette";
}
myOSystem->settings().setString("palette", palette);
myOSystem->colourPalette().setPalette(palette, myDisplayFormat);
}
void Console::togglePhosphor()
{
}
void Console::setProperties(const Properties& props)
{
myProperties = props;
}
void Console::initializeVideo(bool full)
{
if(full)
{
string title = string("Stella ") + STELLA_VERSION +
": \"" + myProperties.get(Cartridge_Name) + "\"";
}
myOSystem->colourPalette().setPalette(myOSystem->settings().getString("palette"), myDisplayFormat);
myOSystem->setFramerate(getFrameRate());
}
void Console::initializeAudio()
{
const string& sound = myProperties.get(Cartridge_Sound);
uInt32 channels = (sound == "STEREO" ? 2 : 1);
myOSystem->sound().close();
myOSystem->sound().setChannels(channels);
myOSystem->sound().setFrameRate(getFrameRate());
myOSystem->sound().initialize();
}
void Console::fry() const
{
for (int ZPmem=0; ZPmem<0x100; ZPmem += myOSystem->rng().next() % 4)
mySystem->poke(ZPmem, mySystem->peek(ZPmem) & (uInt8)myOSystem->rng().next() % 256);
}
void Console::changeYStart(int direction)
{
Int32 ystart = atoi(myProperties.get(Display_YStart).c_str());
ostringstream strval;
string message;
if(direction == +1) {
ystart++;
if(ystart > 64)
{
return;
}
}
else if(direction == -1) {
ystart--;
if(ystart < 0)
{
return;
}
}
else
return;
strval << ystart;
myProperties.set(Display_YStart, strval.str());
((TIA*)myMediaSource)->frameReset();
message = "YStart ";
message += strval.str();
}
void Console::changeHeight(int direction)
{
Int32 height = atoi(myProperties.get(Display_Height).c_str());
ostringstream strval;
string message;
if(direction == +1) {
height++;
if(height > 256)
{
return;
}
}
else if(direction == -1) {
height--;
if(height < 200)
{
return;
}
}
else
return;
strval << height;
myProperties.set(Display_Height, strval.str());
((TIA*)myMediaSource)->frameReset();
initializeVideo();
message = "Height ";
message += strval.str();
}
void Console::toggleTIABit(TIA::TIABit bit, const string& bitname, bool show) const
{
bool result = ((TIA*)myMediaSource)->toggleBit(bit);
string message = bitname + (result ? " enabled" : " disabled");
}
void Console::enableBits(bool enable) const
{
((TIA*)myMediaSource)->enableBits(enable);
string message = string("TIA bits") + (enable ? " enabled" : " disabled");
}
uInt32 Console::getFrameRate() const
{
int framerate = myOSystem->settings().getInt("framerate");
if(framerate == -1)
{
if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60")
framerate = 60;
else if(myDisplayFormat == "PAL" || myDisplayFormat == "SECAM")
framerate = 50;
else
framerate = 60;
}
return framerate;
}
Console::Console(const Console& console)
: myOSystem(console.myOSystem)
{
assert(false);
}
Console& Console::operator = (const Console&)
{
assert(false);
return *this;
}