/*
    CaPriCe Forever - Amstrad CPC 464/664/6128 emulator
    Copyright (C) 2014-2017 by Frédéric Coste

    This program 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 3 of the License, or
    (at your option) any later version.

    This program 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, see <http://www.gnu.org/licenses/>.
*/


#include <vcl.h>
#include <tchar.h>
#pragma hdrstop
#include "TFormCheatScripts.h"
#include "TFormMain.h"
#include "..\Cheat\TCheatActionKeyDown.h"
#include "..\Cheat\TCheatActionKeyUp.h"
#include "..\Cheat\TCheatActionWait.h"
#include "..\Cheat\TCheatActionPoke.h"
#include "..\Cheat\TCheatActionExit.h"
#include "..\Cheat\TCheatActionDiff.h"
#include "..\Cheat\TCheatActionEqual.h"
#include "..\Cheat\TCheatActionSwapDrives.h"
#include "..\Cheat\TCheatActionFlipSides.h"
#include "..\Cheat\TCheatActionPause.h"
#include "..\Cheat\TCheatActionEnd.h"
#include "..\Cheat\TCheatActionReset.h"
#include "..\Cheat\TCheatActionDriveA.h"
#include "..\Cheat\TCheatActionDriveB.h"
#include "..\Cheat\TCheatActionTape.h"
#include "..\Cheat\TCheatActionTapePlay.h"
#include "..\Cheat\TCheatActionTapeStop.h"
#include "..\Cheat\TCheatActionEjectA.h"
#include "..\Cheat\TCheatActionEjectB.h"
#include "..\Cheat\TCheatActionScreenDiff.h"
#include "..\Cheat\TCheatActionDriveAWP.h"
#include "..\Cheat\TCheatActionDriveBWP.h"
#include "..\Cheat\TCheatActionTapeMotor.h"
#include "..\Cheat\TCheatActionMF2Stop.h"
#include "..\Cheat\TCheatActionMF2Reset.h"
#include "..\Cheat\TCheatActionCopyFile.h"
#include "..\Cheat\TCheatActionMouse.h"
#include "..\Cheat\TCheatActionMousePosition.h"
#include "..\Cheat\TCheatActionMouseDown.h"
#include "..\Cheat\TCheatActionMouseUp.h"
#include "..\Cheat\TCheatActionWinKeyDown.h"
#include "..\Cheat\TCheatActionWinKeyUp.h"
#include "..\Cheat\TCheatActionResumeScriptReset.h"
#include "..\Cheat\TCheatActionPressedKeysCount.h"
#include "..\Cheat\TCheatActionCPCKeyPressed.h"
#include "..\Cheat\TCheatActionRefreshDisplay.h"
#include "..\Cheat\TCheatActionKeyShiftPressed.h"
#include "..\Cheat\TCheatActionKeyCtrlPressed.h"
#include "..\Cheat\TCheatActionNoPrinter.h"
#include "..\Cheat\TCheatActionNoTape.h"
#include "..\Cheat\TCheatActionAutotype.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"


//=================================
// Options

//=================================


#define SCRIPTS_FILTER              "Cheat scripts (.script)|*.script|"

#define SCRIPTS_FILENAME            "Scripts.txt"

#define SCRIPT_EXT                  "*.script"


// Actions
#define ACTION_WINKEYDOWN           "winkeydown="
#define ACTION_WINKEYUP             "winkeyup="
#define ACTION_KEYDOWN              "keydown="
#define ACTION_KEYUP                "keyup="
#define ACTION_WAIT                 "wait="
#define ACTION_POKE                 "poke="
#define ACTION_EXIT                 "exit="
#define ACTION_DIFF                 "diff="
#define ACTION_EQUAL                "equal="
#define ACTION_SWAPDRIVES           "swapdrives"
#define ACTION_FLIPSIDES            "flipsides"
#define ACTION_PAUSE                "pause"
#define ACTION_END                  "end"
#define ACTION_RESET                "reset"
#define ACTION_DRIVEA               "drivea="
#define ACTION_DRIVEB               "driveb="
#define ACTION_DRIVEA_WP            "drivea_wp="
#define ACTION_DRIVEB_WP            "driveb_wp="
#define ACTION_TAPE                 "tape="
#define ACTION_TAPEPLAY             "tapeplay"
#define ACTION_TAPESTOP             "tapestop"
#define ACTION_TAPEMOTOR            "tapemotor="
#define ACTION_SCREENDIFF           "screendiff="
#define ACTION_MF2STOP              "mf2stop"
#define ACTION_MF2RESET             "mf2reset"
#define ACTION_EJECTA               "ejecta"
#define ACTION_EJECTB               "ejectb"
#define ACTION_COPYFILE             "copyfile="
#define ACTION_MOUSE                "mouse="
#define ACTION_MOUSE_POS            "mousepos="
#define ACTION_MOUSE_DOWN           "mousedown="
#define ACTION_MOUSE_UP             "mouseup="
#define ACTION_RESUMESCRIPTRESET    "resumescriptatreset"
#define ACTION_PRESSEDKEYSCOUNT     "pressedkeyscount="
#define ACTION_CPCKEYPRESSED        "cpckeypressed="
#define ACTION_REFRESHDISPLAY       "refreshdisplay"
#define ACTION_KEYSHIFTPRESSED      "keyshiftpressed="
#define ACTION_KEYCTRLPRESSED       "keyctrlpressed="
#define ACTION_NOPRINTER            "noprinter"
#define ACTION_NOTAPE               "notape"
#define ACTION_AUTOTYPE             "autotype="


TFormCheatScripts *FormCheatScripts;
//---------------------------------------------------------------------------
__fastcall TFormCheatScripts::TFormCheatScripts(TComponent* Owner)
  : TForm(Owner)
{
  mSettingsP = NULL;
  mListActions = new TList();

  mExecuteInProgress = false;

	AnsiString InstructionsFilename = ExtractFilePath(Application->ExeName) + SCRIPTS_FILENAME;
	if (FileExists(InstructionsFilename) == true)
  {
		MemoInstructions->Lines->LoadFromFile(InstructionsFilename);
  }
  else
  {
    TabSheetInstructions->TabVisible = false;
  }

  // Apply theme
  Font->Name = "Amstrad CPC464 Regular";
  Font->Size = 6;
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::FormDestroy(TObject *Sender)
{
  // Reset list of actions
  while (mListActions->Count)
  {
    delete ((TCheatAction*)mListActions->Items[0]);
    mListActions->Delete(0);
  }
  delete mListActions;

  if (FormMain)
  {
    FormMain->UnsubscribeToCPCEvents(OnCPCEvent);
  }

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::FormShow(TObject *Sender)
{
  if (FormMain == NULL)
  {
    Close();
    return;
  }

	FormMain->OnCheatScriptsFormShow();

	if (PanelButtonExecute->Visible == true)
	{
		UpdateScriptsList();
	}

	if (mSettingsP)
	{
		mSettingsP->CheatScriptsFormVisible = true;
	}

	NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::FormHide(TObject *Sender)
{
	if (FormMain != NULL)
	{
		FormMain->OnCheatScriptsFormHide();
	}

	if (mSettingsP)
  {
    mSettingsP->CheatScriptsFormVisible = false;
  }


  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::SetSettings(TSettings* Value)
{
  mSettingsP = Value;

  if (    (mSettingsP->CheatScriptsFormLeft != 0)
       || (mSettingsP->CheatScriptsFormTop != 0)
       || (mSettingsP->CheatScriptsFormWidth != 0)
       || (mSettingsP->CheatScriptsFormHeight != 0) )
  {
    Position = poDesigned;
    Left = mSettingsP->CheatScriptsFormLeft;
    Top = mSettingsP->CheatScriptsFormTop;
    Width = mSettingsP->CheatScriptsFormWidth;
    Height = mSettingsP->CheatScriptsFormHeight;
  }

  ShowHint = mSettingsP->ShowHints;

	// Apply theme
	Color = mSettingsP->ThemeBackgroundColor;
	Font->Color = mSettingsP->ThemeText1Color;
	LabelSelectedScript->Font->Color = mSettingsP->ThemeText2Color;
	ListBoxScripts->Color = mSettingsP->ThemeBackgroundColor;
	ListBoxScripts->Font->Color = mSettingsP->ThemeText1Color;
	// DO not apply theme color to MemoCode as caret is not visible enough
	//MemoCode->Font->Color = mSettingsP->ThemeText1Color;
	MemoInstructions->Font->Color = mSettingsP->ThemeText1Color;

	for (int Loop=0; Loop < ComponentCount; Loop++)
	{
		if (Components[Loop]->Name.Pos("GroupBox") == 1)
		{
			((TGroupBox*)Components[Loop])->Font->Color = mSettingsP->ThemeText2Color;
		}
		else if (Components[Loop]->Name.Pos("Label") == 1)
		{
			((TLabel*)Components[Loop])->Font->Color = mSettingsP->ThemeText1Color;
		}
		else if (Components[Loop]->Name.Pos("PanelButton") == 1)
		{
			((TPanel*)Components[Loop])->Color = mSettingsP->ThemeButtonColor;
			((TPanel*)Components[Loop])->Font->Color = mSettingsP->ThemeButtonTextColor;
		}

		// Refresh display
		if ( (Visible == true) && (((TControl*)Components[Loop])->Visible == true) )
		{
			((TControl*)Components[Loop])->Invalidate();
		}
	}

  if (mSettingsP->HideAll == false)
  {
    Visible = mSettingsP->CheatScriptsFormVisible;
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::FormResize(TObject *Sender)
{
	if ( (Visible == true) && (mSettingsP) )
	{
		mSettingsP->CheatScriptsFormWidth = Width;
		mSettingsP->CheatScriptsFormHeight = Height;
	}

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TFormCheatScripts::WMMove(TMessage &Message)
{
	if ( (Visible == true) && (mSettingsP) )
  {
    mSettingsP->CheatScriptsFormLeft = Left;
    mSettingsP->CheatScriptsFormTop = Top;
  }

  NOT_USED(Message);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::UpdateScriptsList(void)
{
  AnsiString Path = mSettingsP->CheatScriptsDirectory;

  TStringList* FileList = new TStringList();

  // First add folders
  TSearchRec sr;
  /*if (FindFirst(Path + "*.*", faDirectory, sr) == 0)
  {
    do
    {
      if (sr.Attr & faDirectory)
      {
        if (sr.Name != ".")
        {
          FileList->Add("\\" + sr.Name);
        }
      }
    }
    while (FindNext(sr) == 0);
    FindClose(sr);
  }*/
  // Add all supported script files
  if (FindFirst(Path + SCRIPT_EXT, faAnyFile, sr) == 0)
  {
    do
    {
      FileList->Add(sr.Name);
    }
    while (FindNext(sr) == 0);
    FindClose(sr);
  }

  // Display scripts files
  FileList->Sort();
  ListBoxScripts->Clear();
  ListBoxScripts->Items->AddStrings(FileList);

  // Select first script
  if (ListBoxScripts->Items->Count)
  {
    ListBoxScripts->ItemIndex = 0;
    LoadScript(ListBoxScripts->Items->Strings[ListBoxScripts->ItemIndex]);
    PanelButtonDelete->Visible = true;
    PageControl->ActivePage = TabSheetScripts;
  }
  else
  {
    PanelButtonDelete->Visible = false;
    PageControl->ActivePage = TabSheetCode;
    mSelectedScriptFilename = "";
    LabelSelectedScript->Caption = "";
  }

  delete FileList;
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::LoadScript(AnsiString Filename)
{
  AnsiString FullFilename = mSettingsP->CheatScriptsDirectory + Filename;

  MemoCode->Lines->LoadFromFile(FullFilename);
  mSelectedScriptFilename = FullFilename;

  // Update "Selected script"
  LabelSelectedScript->Caption = Filename;
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::PanelButtonNewClick(TObject *Sender)
{
  // Select Code page
  PageControl->ActivePage = TabSheetCode;

  ListBoxScripts->ItemIndex = -1;

  MemoCode->Clear();
  MemoCode->SetFocus();

  // Update "Selected script"
  PanelButtonDelete->Visible = false;
  mSelectedScriptFilename = "";
  LabelSelectedScript->Caption = "";

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::PanelButtonSaveClick(TObject *Sender)
{
  SaveDialog->InitialDir = mSettingsP->CheatScriptsDirectory;
  SaveDialog->Filter = SCRIPTS_FILTER;
  SaveDialog->DefaultExt = SCRIPT_EXT;
  SaveDialog->FileName = (mSelectedScriptFilename.IsEmpty() == false) ? mSelectedScriptFilename : AnsiString("New");

  if (SaveDialog->Execute() == true)
  {
    MemoCode->Lines->SaveToFile(SaveDialog->FileName);
    UpdateScriptsList();

    // Select filename
    ListBoxScripts->ItemIndex = ListBoxScripts->Items->IndexOf(ExtractFileName(SaveDialog->FileName));
    LoadScript(ListBoxScripts->Items->Strings[ListBoxScripts->ItemIndex]);
  }

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::PanelButtonDeleteClick(TObject *Sender)
{
  if (Application->MessageBox(_T("Are you sure to delete selected file ?"),
                              _T("Delete script"),
                              MB_YESNO | MB_DEFBUTTON2) == ID_YES)
  {
    DeleteFile(mSelectedScriptFilename);
    UpdateScriptsList();
  }

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::PanelButtonExecuteClick(TObject *Sender)
{
  if (mExecuteInProgress == false)
  {
    mExecuteInProgress = true;
    ExecuteScript();
  }
  else
  {
    mExecuteInProgress = false;
    StopScript();
  }

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


bool __fastcall TFormCheatScripts::OnCPCEvent(tULong Condition, tNativeCPC* NativeCPC)
{
  bool Pause = NativeCPC->paused;

  if ((Condition & EC_CYCLE_COUNT) == 0)
    return Pause;

  if (mListActions->Count == 0)
    return Pause;

  if (mCurrentActionIndex >= mListActions->Count)
    return Pause;

  // Execute actions
  TCheatAction* Action = (TCheatAction*)mListActions->Items[mCurrentActionIndex];
  while (Action != NULL)
  {
    Action->Execute(NativeCPC);
    if (Action->IsFinished() == true)
    {
      // By default, Go to next action
      mCurrentActionIndex++;

      // Jump to another action ?      
      if (Action->NextAction().IsEmpty() == false)
      {
        AnsiString NextActionLabel = Action->NextAction();
        for (int Loop=0; Loop < mListActions->Count; Loop++)
        {
          TCheatAction* NextAction = (TCheatAction*)mListActions->Items[Loop];
          if (NextAction->Label == NextActionLabel)
          {
            // Jump to this action
            mCurrentActionIndex = Loop;
            break;
          }
        }
      }

      // Still actions ?
      if ( (mCurrentActionIndex < mListActions->Count)
           && (Action->IsScriptTerminated() == false) )
      {
        // Start next action
        Action = (TCheatAction*)mListActions->Items[mCurrentActionIndex];
        Action->Start(FormMain->NativeCPC);
      }
      else
      {
        // Terminate execution
        FormMain->UnsubscribeToCPCEvents(OnCPCEvent);
        mExecuteInProgress = false;
        PanelButtonExecute->Color = mSettingsP->ThemeButtonColor;
        PanelButtonExecute->Font->Color = mSettingsP->ThemeButtonTextColor;
        Action = NULL;
      }
    }
    else
    {
      Action = NULL;
    }
  }

  return Pause;
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::ListBoxScriptsClick(TObject *Sender)
{
  LoadScript(ListBoxScripts->Items->Strings[ListBoxScripts->ItemIndex]);

  NOT_USED(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::ListBoxScriptsDblClick(TObject *Sender)
{
  LoadScript(ListBoxScripts->Items->Strings[ListBoxScripts->ItemIndex]);
  PanelButtonExecute->OnClick(Sender);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::ExecuteScript(AnsiString Filename)
{
  UpdateScriptsList();
  ListBoxScripts->ItemIndex = ListBoxScripts->Items->IndexOf(Filename);
  if (ListBoxScripts->ItemIndex != -1)
  {
    LoadScript(ListBoxScripts->Items->Strings[ListBoxScripts->ItemIndex]);
    PanelButtonExecute->OnClick(NULL);
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::StopCurrentScript(void)
{
  // Terminate execution
	FormMain->UnsubscribeToCPCEvents(OnCPCEvent);

	StopScript();
}
//---------------------------------------------------------------------------

void __fastcall TFormCheatScripts::PageControlDrawTab(TCustomTabControl *Control,
          int TabIndex, const TRect &Rect, bool Active)
{
  TCanvas* Canvas = PageControl->Canvas;

  if (Active == true)
  {
    Canvas->Font->Color = mSettingsP->ThemeText2Color;
  }

  // Get sheet corresponding to TabIndex
  int TabCount=0;
  TTabSheet* Sheet = NULL;
  for (int Loop=0; Loop < PageControl->PageCount; Loop++)
  {
    if (PageControl->Pages[Loop]->TabVisible == true)
    {
      if (TabCount == TabIndex)
      {
        Sheet = PageControl->Pages[Loop];
        break;
      }

      TabCount++;
    }
  }

  // Draw tab
  Canvas->FillRect(Rect);
  AnsiString Text = Sheet->Caption;
  int TextWidth = Canvas->TextWidth(Text);
  int TextHeight = Canvas->TextHeight(Text);
  int TextPosX = (Rect.Width() - TextWidth) / 2;
  int TextPosY = (PageControl->TabHeight - TextHeight) / 2;
  Canvas->TextOut(Rect.Left+TextPosX, Rect.Top+TextPosY, Text);

  NOT_USED(Control);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::PanelButtonMouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
  ((TPanel*)Sender)->Color = mSettingsP->ThemeButtonTextColor;
  ((TPanel*)Sender)->Font->Color = mSettingsP->ThemeButtonColor;

  NOT_USED(Button);
  NOT_USED(Shift);
  NOT_USED(X);
  NOT_USED(Y);
}
//---------------------------------------------------------------------------

void __fastcall TFormCheatScripts::PanelButtonMouseUp(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
  ((TPanel*)Sender)->Color = mSettingsP->ThemeButtonColor;
  ((TPanel*)Sender)->Font->Color = mSettingsP->ThemeButtonTextColor;

  NOT_USED(Button);
  NOT_USED(Shift);
  NOT_USED(X);
  NOT_USED(Y);
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::ExecuteScript(void)
{
  // Reset list of actions
  while (mListActions->Count)
  {
    delete ((TCheatAction*)mListActions->Items[0]);
    mListActions->Delete(0);
  }
  mListActions->Clear();


  if (PageControl->ActivePage == TabSheetScripts)
  {
    // Load script
    AnsiString Filename = mSettingsP->CheatScriptsDirectory
                          + ListBoxScripts->Items->Strings[ListBoxScripts->ItemIndex];

    MemoCode->Clear();

    if (FileExists(Filename) == true)
    {
      MemoCode->Lines->LoadFromFile(Filename);
    }
  }

  //
  // Prepare list of actions
  //
  AnsiString Label = "";
  for (int Loop=0; Loop < MemoCode->Lines->Count; Loop++)
  {
    AnsiString Command = MemoCode->Lines->Strings[Loop].Trim();
    AnsiString LowerCommand = Command.LowerCase();

		int CommentPos = Command.Pos(";");
		if (CommentPos == 0)
		{
			CommentPos = Command.Length();
		}

		TCheatAction* NewAction;
		int CommandPos;

		NewAction = NULL;

		// LABEL
		if (Command.Pos(":") == 1)
		{
			Label = Command.SubString(2, Command.Length()-1);
		}
		// WIN KEY DOWN Action
		// Should be tested before ACTION_KEYDOWN
		else if ((CommandPos = LowerCommand.Pos(ACTION_WINKEYDOWN)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionWinKeyDown(Command);
			}
		}
		// WIN KEY UP Action
		// Should be tested before ACTION_KEYUP
		else if ((CommandPos = LowerCommand.Pos(ACTION_WINKEYUP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionWinKeyUp(Command);
			}
		}
		// KEY DOWN Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_KEYDOWN)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionKeyDown(Command);
			}
		}
		// KEY UP Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_KEYUP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionKeyUp(Command);
			}
		}
		// WAIT Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_WAIT)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionWait(Command);
			}
		}
		// POKE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_POKE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionPoke(Command);
			}
		}
		// EXIT Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_EXIT)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionExit(Command);
			}
		}
		// SCREENDIFF Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_SCREENDIFF)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionScreenDiff(Command);
			}
		}
		// DIFF Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_DIFF)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionDiff(Command);
			}
		}
		// EQUAL Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_EQUAL)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionEqual(Command);
			}
		}
		// SWAPDRIVES Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_SWAPDRIVES)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionSwapDrives(Command);
			}
		}
		// FLIPSIDES Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_FLIPSIDES)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionFlipSides(Command);
			}
		}
		// PAUSE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_PAUSE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionPause(Command);
			}
		}
		// END Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_END)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionEnd();
			}
		}
		// Resume script at reset
		// Should be placed before RESET
		else if ((CommandPos = LowerCommand.Pos(ACTION_RESUMESCRIPTRESET)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionResumeScriptReset(Command);
			}
		}
		// RESET Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_RESET)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionReset();
			}
		}
		// DRIVEA Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_DRIVEA)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionDriveA(Command);
			}
		}
		// DRIVEB Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_DRIVEB)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionDriveB(Command);
			}
		}
		// DRIVE A WRITE PROTECTION
		else if ((CommandPos = LowerCommand.Pos(ACTION_DRIVEA_WP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionDriveAWP(Command);
			}
		}
		// DRIVE B WRITE PROTECTION
		else if ((CommandPos = LowerCommand.Pos(ACTION_DRIVEB_WP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionDriveBWP(Command);
			}
		}
		// TAPE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_TAPE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionTape(Command);
			}
		}
		// TAPEPLAY Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_TAPEPLAY)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionTapePlay(Command);
			}
		}
		// TAPESTOP Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_TAPESTOP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionTapeStop(Command);
			}
		}
		// TAPE MOTOR
		else if ((CommandPos = LowerCommand.Pos(ACTION_TAPEMOTOR)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionTapeMotor(Command);
			}
		}
		// MF2 STOP
		else if ((CommandPos = LowerCommand.Pos(ACTION_MF2STOP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionMF2Stop(Command);
			}
		}
		// MF2 RESET
		else if ((CommandPos = LowerCommand.Pos(ACTION_MF2RESET)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionMF2Reset(Command);
			}
		}
		// EJECTA Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_EJECTA)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionEjectA(Command);
			}
		}
		// EJECTB Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_EJECTB)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionEjectB(Command);
			}
		}
		// COPYFILE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_COPYFILE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionCopyFile(Command);
			}
		}
		// MOUSE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_MOUSE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionMouse(Command);
			}
		}
		// MOUSE_POS Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_MOUSE_POS)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionMousePosition(Command);
			}
		}
		// MOUSE_DOWN Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_MOUSE_DOWN)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionMouseDown(Command);
			}
		}
		// MOUSE_UP Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_MOUSE_UP)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionMouseUp(Command);
			}
		}
		// ACTION_PRESSEDKEYSCOUNT Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_PRESSEDKEYSCOUNT)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionPressedKeysCount(Command);
			}
		}
		// ACTION_CPCKEYPRESSED Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_CPCKEYPRESSED)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionCPCKeyPressed(Command);
			}
		}
		// ACTION_REFRESHDISPLAY Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_REFRESHDISPLAY)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionRefreshDisplay(Command);
			}
		}
		// ACTION_KEYSHIFTPRESSED Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_KEYSHIFTPRESSED)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionKeyShiftPressed(Command);
			}
		}
		// ACTION_KEYCTRLPRESSED Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_KEYCTRLPRESSED)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionKeyCtrlPressed(Command);
			}
		}
		// ACTION_NOPRINTER Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_NOPRINTER)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionNoPrinter(Command);
			}
		}
		// ACTION_NOTAPE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_NOTAPE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionNoTape(Command);
			}
		}
		// ACTION_AUTOTYPE Action
		else if ((CommandPos = LowerCommand.Pos(ACTION_AUTOTYPE)) > 0)
		{
			if (CommandPos < CommentPos)
			{
				NewAction = (TCheatAction*) new TCheatActionAutotype(Command);
			}
		}
		else
		{
		}

    // Only add valid action
    if (NewAction)
    {
      if (NewAction->Valid == true)
      {
        mListActions->Add((void*)NewAction);
        // Affect Label
        NewAction->Label = Label;
        Label = "";
      }
      else
      {
        delete NewAction;
      }
    }
  }

  // Add empty action for last label
  if (Label.IsEmpty() == false)
  {
    TCheatAction* NewAction = new TCheatAction();
    NewAction->Label = Label;
    mListActions->Add((void*)NewAction);
  }

  if (mListActions->Count)
  {
    // Start execution
    mCurrentActionIndex = 0;
    TCheatAction* Action = (TCheatAction*)mListActions->Items[mCurrentActionIndex];
    Action->Start(FormMain->NativeCPC);

    FormMain->SubscribeToCPCEvents(OnCPCEvent);

    PanelButtonExecute->Color = mSettingsP->ThemeButtonTextColor;
    PanelButtonExecute->Font->Color = mSettingsP->ThemeButtonColor;
  }
}
//---------------------------------------------------------------------------


void __fastcall TFormCheatScripts::StopScript(void)
{
  // Reset list of actions
  while (mListActions->Count)
  {
    delete ((TCheatAction*)mListActions->Items[0]);
    mListActions->Delete(0);
  }
  mListActions->Clear();

  PanelButtonExecute->Color = mSettingsP->ThemeButtonColor;
  PanelButtonExecute->Font->Color = mSettingsP->ThemeButtonTextColor;
}
//---------------------------------------------------------------------------

