Code:
const int IR_LAYER = 7; // Layer to draw on - should be 6 or 7
const int IR_FGCOLOR = 1; // Text color
const int IR_BGCOLOR = 0; // Text background color
const int IR_POINTERTILE = 20500;
const int IR_POINTERCSET = 7;
// No need to change these
const int IRIDX_STATE = 0;
const int IRIDX_ARRAYDONECOUNTER = 1;
const int IRIDX_SCRIPTDONECOUNTER = 2;
const int IRIDX_RECORD = 3;
const int IRIDX_STOP = 4;
const int IRIDX_REPLAY = 5;
const int IRIDX_WRITEARRAYS = 6;
const int IRIDX_WRITESCRIPT = 7;
const int IRIDX_DONE = 8;
const int IRST_INACTIVE = 0;
const int IRST_RECORDING = 1;
ffc script InputRecorder
{
void run(bool noDelay)
{
// You shouldn't need to make these bigger, but you can.
int inputArr[2048];
int pressArr[2048];
int lengths[2];
int recordText[]="Record";
int stopText[]="Stop";
int replayText[]="Replay";
int arrayText[]="Write arrays to allegro.log";
int scriptText[]="Write script to allegro.log";
int doneText[]="Done!";
bool ignoreClick=false; // There's no Link->PressMouseB, so...
// Store the pointers for Wait()
this->Misc[IRIDX_RECORD]=recordText;
this->Misc[IRIDX_STOP]=stopText;
this->Misc[IRIDX_REPLAY]=replayText;
this->Misc[IRIDX_WRITEARRAYS]=arrayText;
this->Misc[IRIDX_WRITESCRIPT]=scriptText;
this->Misc[IRIDX_DONE]=doneText;
Game->ClickToFreezeEnabled=false;
while(true)
{
// This is the inactive loop; other states
// are in separate functions.
if(Link->InputMouseB)
{
if(!ignoreClick)
{
ignoreClick=true;
// Determine which button was clicked based on the mouse's
// Y position. The X position is ignored.
if(Link->InputMouseY>=-48 && Link->InputMouseY<=-37)
{
// Record
this->Misc[IRIDX_STATE]=IRST_RECORDING;
RecordInput(this, inputArr, pressArr, lengths, noDelay==0);
this->Misc[IRIDX_STATE]=IRST_INACTIVE;
}
else if(Link->InputMouseY>=-36 && Link->InputMouseY<=-25)
{
// Replay
ReplayInput(inputArr, pressArr);
}
else if(Link->InputMouseY>=-24 && Link->InputMouseY<=-13)
{
// Write arrays
if(this->Misc[IRIDX_ARRAYDONECOUNTER]<=0)
{
WriteArrays(inputArr, pressArr, lengths[0], lengths[1], 0);
this->Misc[IRIDX_ARRAYDONECOUNTER]=120;
}
}
else if(Link->InputMouseY>=-12 && Link->InputMouseY<=-1)
{
// Write script
if(this->Misc[IRIDX_SCRIPTDONECOUNTER]<=0)
{
WriteScript(inputArr, pressArr, lengths[0], lengths[1]);
this->Misc[IRIDX_SCRIPTDONECOUNTER]=120;
}
}
}
}
else if(ignoreClick)
ignoreClick=false;
Wait(this);
}
}
void RecordInput(ffc this, int inputArr, int pressArr, int lengths, bool waitForInput)
{
bool ignoreClick=true; // The button will be down initially
if(waitForInput)
{
// Don't start recording until a key is pressed.
while(GetInput()==0)
{
if(Link->InputMouseB)
{
if(!ignoreClick)
{
// Clicked stop already? Return without changing anything.
return;
}
}
else if(ignoreClick)
ignoreClick=false;
Wait(this);
}
}
// Clear whatever was in the arrays before
for(int i=SizeOfArray(inputArr)-1; i>=0; i--)
inputArr[i]=0;
for(int i=SizeOfArray(pressArr)-1; i>=0; i--)
pressArr[i]=0;
// Initial values are a little weird. That's to make the first time
// through the loop set things correctly.
int currInput=GetInput();
int currPress=GetPressed();
int prevInput=currInput;
int prevPress=currPress;
int inputCounter=0;
int pressCounter=0;
int inputPtr=0;
int pressPtr=0;
while(true)
{
currInput=GetInput();
currPress=GetPressed();
if(currInput==prevInput)
inputCounter++;
else
{
// Input has changed; record the previous state and duration
inputArr[inputPtr]=prevInput;
inputArr[inputPtr+1]=inputCounter;
inputPtr+=2;
prevInput=currInput;
inputCounter=1;
}
if(currPress==prevPress)
pressCounter++;
else
{
// Input has changed; record the previous state and duration
pressArr[pressPtr]=prevPress;
pressArr[pressPtr+1]=pressCounter;
pressPtr+=2;
prevPress=currPress;
pressCounter=1;
}
Wait(this);
// Check if the stop button was clicked...
if(Link->InputMouseB)
{
if(!ignoreClick)
{
ignoreClick=true;
if(Link->InputMouseY>=-48 && Link->InputMouseY<=-37)
{
// Record any keys held when the button was clicked
if(currInput!=0)
{
inputArr[inputPtr]=currInput;
inputArr[inputPtr+1]=inputCounter;
inputPtr+=2;
}
if(currPress!=0)
{
pressArr[pressPtr]=currPress;
pressArr[pressPtr+1]=pressCounter;
pressPtr+=2;
}
lengths[0]=inputPtr;
lengths[1]=pressPtr;
return;
}
}
}
else if(ignoreClick)
ignoreClick=false;
}
}
void WriteArrays(int inputArr, int pressArr, int inputLength, int pressLength, int indentation)
{
int inputText[]="int inputArr[] = { ";
int pressText[]="int pressArr[] = { ";
int commaFmt[]="%d, ";
int endFmt[]="%d };\n";
int space[]=" ";
int i;
TraceNL();
for(i=0; i<indentation; i++)
TraceS(space);
TraceS(inputText);
for(i=0; i<inputLength; i++)
{
if(i<inputLength-1)
printf(commaFmt, inputArr[i]);
else
printf(endFmt, inputArr[i]);
}
for(i=0; i<indentation; i++)
TraceS(space);
TraceS(pressText);
for(i=0; i<pressLength; i++)
{
if(i<pressLength-1)
printf(commaFmt, pressArr[i]);
else
printf(endFmt, pressArr[i]);
}
TraceNL();
}
void WriteScript(int inputArr, int pressArr, int inputLength, int pressLength)
{
int scriptNameFmt[]="ReplayInput_%d_%X";
int scriptPart1[]="ffc script ";
int scriptPart2[]="\n{\n void run()\n {";
int scriptPart3[]=" ReplayInput(inputArr, pressArr);\n }\n}\n";
TraceNL();
TraceS(scriptPart1);
printf(scriptNameFmt, Game->GetCurMap(), Game->GetCurScreen());
printf(scriptPart2);
WriteArrays(inputArr, pressArr, inputLength, pressLength, 8);
printf(scriptPart3);
TraceNL();
}
// Draws the strings and pointer, then calls Waitframe()
void Wait(ffc this)
{
if(this->Misc[IRIDX_STATE]==IRST_INACTIVE)
{
Screen->DrawString(IR_LAYER, 8, -46, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_RECORD], OP_OPAQUE);
Screen->DrawString(IR_LAYER, 8, -34, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_REPLAY], OP_OPAQUE);
if(this->Misc[IRIDX_ARRAYDONECOUNTER]<=0)
Screen->DrawString(IR_LAYER, 8, -22, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_WRITEARRAYS], OP_OPAQUE);
else
{
Screen->DrawString(IR_LAYER, 8, -22, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_DONE], OP_OPAQUE);
this->Misc[IRIDX_ARRAYDONECOUNTER]--;
}
if(this->Misc[IRIDX_SCRIPTDONECOUNTER]<=0)
Screen->DrawString(IR_LAYER, 8, -10, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_WRITESCRIPT], OP_OPAQUE);
else
{
Screen->DrawString(IR_LAYER, 8, -10, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_DONE], OP_OPAQUE);
this->Misc[IRIDX_SCRIPTDONECOUNTER]--;
}
}
else // Recording
{
Screen->DrawString(IR_LAYER, 8, -46, FONT_Z1, IR_FGCOLOR, IR_BGCOLOR, TF_NORMAL, this->Misc[IRIDX_STOP], OP_OPAQUE);
}
Screen->FastTile(IR_LAYER, Link->InputMouseX, Link->InputMouseY, IR_POINTERTILE, IR_POINTERCSET, OP_OPAQUE);
Waitframe();
}
}