/******************************************************************************/
// SIMPLE INPUT RECORD/PLAYBACK
// (c) 2015 Brian Provinciano
//
// You are free to use this code for your own purposes, no strings attached.
//
// This is a very basic sample to record and playback button input. 
// It's most useful when activated on startup, deactivated on shutdown for
// global button recording/playback. 
// 
// For details on more advanced implementations, see my GDC 2015 session:
// -> Automated Testing and Instant Replays in Retro City Rampage
// The slides and full video will be available on the GDC Vault at a later date.
/******************************************************************************/
/******************************************************************************/
// wrap it so it can be conditionally compiled in.
// for example, set INPUTREPLAY_CAN_RECORD to 1 to play the game and record the input, set it to 0 when done
// INPUTREPLAY_CAN_RECORD takes priority over INPUTREPLAY_CAN_PLAYBACK
#define INPUTREPLAY_CAN_PLAYBACK	1
#define INPUTREPLAY_CAN_RECORD		1
#define INPUTREPLAY_INCLUDED		(INPUTREPLAY_CAN_PLAYBACK || INPUTREPLAY_CAN_RECORD)
/******************************************************************************/
#if INPUTREPLAY_INCLUDED
#define INPUT_BUTTONS_TOTAL	32		// up to 32
#define MAX_REC_LEN			0x8000	// the buffer size for storing RLE compressed button input (x each button)
/******************************************************************************/
typedef struct 
{
	unsigned short *rledata;
	unsigned short rlepos;
	unsigned short datalen;
	unsigned short currentrun;
} ButtonRec;
/******************************************************************************/
// if INPUTREPLAY_CAN_RECORD, as soon as this class is instanced, it will automatically record when instanced/created.
// statically creating this as a global will blanket the entire play session
//
// if INPUTREPLAY_CAN_PLAYBACK, playback will begin as soon as LoadFile() is used
//
class SimpleInputRec
{
	unsigned int	m_buttonstate;
	ButtonRec		m_buttons[INPUT_BUTTONS_TOTAL];
	bool			m_bRecording;
	unsigned char*	m_data;
public:
	SimpleInputRec()
	: m_buttonstate(0)
	, m_data(NULL)
	, m_bRecording(true)
	{
	}
	~SimpleInputRec()
	{
		if(m_data)
		{
#if INPUTREPLAY_CAN_RECORD
			WriteToFile();
#endif
			delete[] m_data;
		}
	}
	
	// run each frame before the game uses the live button input. 
	// when recording, it saves the live input
	// during playback, it overwrites the live input 
	void Update(bool bForce = false);
	
	// to start a playback
#if INPUTREPLAY_CAN_PLAYBACK
	bool LoadFile(KSTR szfilename);
#endif
	// to finish recording
#if INPUTREPLAY_CAN_RECORD
	void WriteToFile();
#endif
};
/******************************************************************************/
void SimpleInputRec::Update(bool bForce)
{
#if INPUTREPLAY_CAN_RECORD
	if(m_bRecording)
	{
		unsigned int newbuttons = nesinput.buttons;
		// allocate and initialize
		if(!m_data)
		{
			m_data = new unsigned char[INPUT_BUTTONS_TOTAL * MAX_REC_LEN * 2];
			unsigned short* dataptr = (unsigned short*)m_data;
			for(int i=0; i>i)&1;
					btn.rledata[btn.rlepos++] = (bit<<15) | btn.currentrun;
				}
				btn.currentrun = bForce? 0 : 1;
			}
			else
			{
				++btn.currentrun;
			}
		}
		m_buttonstate = newbuttons;
	}
#endif
#if INPUTREPLAY_CAN_PLAYBACK
	if(!m_bRecording)
	{
		bool bIsRunning = false;
		for(int i=0; i>15)&1)<> 8, f);
			}
			for(int i=0; i