Revision 353ee6cd90b8e10ec132ce3d430319a7b29795f4 authored by Jonas Rembser on 17 April 2024, 17:24:06 UTC, committed by Jonas Rembser on 19 April 2024, 11:35:25 UTC
After commit a27e60a6d4f, it is not important anymore that only the
variables used by the expression are passed to RooFormula.

Removing the corresponding warnings helps to get rid of useless warnings
in the case where you want to try out variations of the formula that
omit certain terms, and in particular it helps in
`RooAbsData::reduce()`, where the formula is always passed all the
varaiables in the dataset, whether the reduction uses them or not.
1 parent 311b78e
Raw File
Tetris.cxx
// @(#)root/test:$Id$
// Author: Valeriy Onuchin & Fons Rademakers   04/10/98

///////////////////////////////////////////////////////////////////
//  ROOT implementation of the simple Tetris game
//  Layout and some hints were taken from Qt /examples/tetris
//
//  To run this game do the following:
//  $ root
//  root [0] gSystem.Load("libGpad")
//  root [1] gSystem.Load("Tetris")
//  root [2] Tetris t
//  <play game>
//  root [2] .q
//
///////////////////////////////////////////////////////////////////

#include <TVirtualX.h>
#include <TGClient.h>
#include <KeySymbols.h>
#include <TRootCanvas.h>
#include <TApplication.h>
#include <TList.h>
#include <snprintf.h>
#include "Tetris.h"

static Tetris *gTetris;                    // game manager

static const UInt_t gBoxPixelSize = 20;   // size of TetrisBox in pixels


ClassImp(Tetris);

///////////////////////////////////////////////////////////////////
//  TetrisBox - the main brick of the game
///////////////////////////////////////////////////////////////////
TetrisBox::TetrisBox(Int_t x, Int_t y, UInt_t type, TPad* pad) :
   TWbox(0,0,1,1,33,2,1)
{
   // Create brick

   fType = type;
   fPad  = pad;

   //-------  append box to pad
   SetBit(kMustCleanup);
   SetBit(kCanDelete);
   pad->GetListOfPrimitives()->Add(this);
   SetXY(x,y);
}

void TetrisBox::SetX(Int_t x)
{
   // Set X measured in boxes units

   // width in pixels of pad
   Float_t width  = (Float_t)fPad->XtoPixel(fPad->GetX2());

   Coord_t x1 = ((Float_t)x)*gBoxPixelSize/width;
   Coord_t x2 = ((Float_t)x+1)*gBoxPixelSize/width;

   SetX1(x1);
   SetX2(x2);
   fX = x;
}

void TetrisBox::SetY(Int_t y)
{
   // Set Y measured in boxes units

   // height in pixels of pad
   Float_t height = (Float_t)fPad->YtoPixel(fPad->GetY1());

   Coord_t y1 = ((Float_t)y)*gBoxPixelSize/height;
   Coord_t y2 = ((Float_t)y+1)*gBoxPixelSize/height;

   SetY1(y1);
   SetY2(y2);
   fY = y;
}

void TetrisBox::Paint(Option_t *option)
{
   // Paint box if it's not hidden.

   if (!IsHidden() && fPad) TWbox::Paint(option);
}

void TetrisBox::Erase()
{
   // erase box

   Double_t fX1sav = fX1;
   Double_t fY1sav = fY1;
   Double_t fX2sav = fX2;
   Double_t fY2sav = fY2;

   // erase 2 pix extra
   fX1 = fX1-fPad->PixeltoX(2);
   fY1 = fY1+fPad->PixeltoY(2);
   fX2 = fX2+fPad->PixeltoX(2);
   fY2 = fY2-fPad->PixeltoY(2);

   SetFillColor(fPad->GetFillColor());
   SetBorderMode(0);
   Paint();

   fX1 = fX1sav;
   fY1 = fY1sav;
   fX2 = fX2sav;
   fY2 = fY2sav;
}


///////////////////////////////////////////////////////////////////
//  TetrisPiece - tetris piece is set of up to 4 TetrisBoxes
///////////////////////////////////////////////////////////////////
static Int_t gPieceTypes[10][4][2] = {
                                      {{-1,1},   //   *
                                       {-1,0},   //   * *
                                       { 0,0},   //     *
                                       { 0,-1}},

                                      {{ 1, 1},  //    *
                                       { 1, 0},  //  * *
                                       { 0, 0},  //  *
                                       { 0,-1}},

                                      {{ 0, 1},  //   *
                                       { 0, 0},  //   *
                                       { 0,-1},  //   *
                                       { 0,-2}}, //   *

                                      {{ 0, 1},  //    *
                                       { 1, 0},  //  * * *
                                       { 0, 0},
                                       { -1,0}},

                                      {{ 1, 1},  //  * *
                                       { 0, 1},  //  * *
                                       { 1, 0},  //
                                       { 0, 0}}, //

                                      {{ 0, 1},   //   *
                                       { 0, 0},   //   *
                                       { 0,-1},   // * *
                                       { -1,-1}},

                                      {{ 0, 1},   //  *
                                       { 0, 0},   //  *
                                       { 0,-1},   //  * *
                                       { 1,-1}},

                                      {{ 0, 1},    // *
                                       { 0, 1},    //      hidden
                                       { 0, 1},    //      hidden
                                       { 0, 1}},   //      hidden

                                      {{ 0, 1},   //  *
                                       { 0, 0},   //  *
                                       { 0, 1},   //       hidden
                                       { 0, 0}},  //       hidden

                                      {{ 0, 1},   //   *
                                       { 0, 0},   //   *
                                       { 0,-1},   //   *
                                       { 0, 0}}}; //       hidden

static Color_t gPieceColors[10] = { 2,3,4,5,6,7,13,9,28,41 };


TetrisPiece::~TetrisPiece()
{
   // Clean up piece.

   for (int i = 0; i < 4; i++) delete fBoxes[i];
}

void TetrisPiece::Initialize(UInt_t type, TPad* pad)
{
   for (int i = 0; i < 4; i++) fBoxes[i] = new TetrisBox(0,0,0,pad);
   fX = 0;
   fY = 0;
   SetType(type);
}

void TetrisPiece::SetType(UInt_t type)
{
   // re-initialization

   if (type < 1 || type > 10)
      type = 9;

   for (int i = 0 ; i < 4 ; i++) {
      fBoxes[i]->SetType(type);
      fBoxes[i]->SetFillColor(gPieceColors[type-1]);
      fBoxes[i]->SetX(gPieceTypes[type-1][i][0]+fX);
      fBoxes[i]->SetY(gPieceTypes[type-1][i][1]+fY);
   }
   HideSomeBoxes(type);
   fType = type;
}

void TetrisPiece::HideSomeBoxes(UInt_t type)
{
   // Make invisible some boxes for 1,2,3 length pieces

   switch(type) {
      case 8:  fBoxes[1]->Hide();
      case 9:  fBoxes[2]->Hide();
      case 10: fBoxes[3]->Hide();
      default: return;
   }
}

Bool_t TetrisPiece::RotateRight()
{
   // Rotate anticlockwise  around (fX,fY) point

   // don't rotate square pieces
   if (GetType() == 5 || GetType() == 8) return kFALSE;

   Int_t tmp;

   for (int i = 0 ; i < 4 ; i++) {
      tmp = GetXx(i);
      SetXx(i,-GetYy(i));
      SetYy(i,tmp);
   }
   return kTRUE;
}

Bool_t TetrisPiece::RotateLeft()
{
   // Rotate clockwise  around (fX,fY) point

   // don't rotate square pieces
   if (GetType() == 5 || GetType() == 8) return kFALSE;

   Int_t tmp;

   for (int i = 0 ; i < 4 ; i++) {
      tmp = GetXx(i);
      SetXx(i,GetYy(i));
      SetYy(i,-tmp);
   }
   return kTRUE;
}

void  TetrisPiece::Hide()
{
   // Hide this piece

   for (int i = 0 ; i < 4 ; i++) {
      fBoxes[i]->Hide();
   }
}

void  TetrisPiece::Show()
{
   // Show this piece

   for (int i = 0 ; i < 4 ; i++) {
      fBoxes[i]->SetType(fType);
   }
   HideSomeBoxes(fType);
}

void  TetrisPiece::SetX(Int_t x)
{
   // Change of X position of the whole piece

   for (int i = 0 ; i < 4 ; i++) SetX(i,x+GetXx(i));
   fX = x;
}

void TetrisPiece::SetY(Int_t y)
{
   // Change of Y position of the whole piece

   for (int i = 0 ; i < 4 ; i++) SetY(i,y+GetYy(i));
   fY = y;
}

void TetrisPiece::SetXY(Int_t x,Int_t y)
{
   // Change of X,Y position of the whole piece

   for (int i = 0 ; i < 4 ; i++) {
      SetX(i,x+GetXx(i));
      SetY(i,y+GetYy(i));
   }
   fX = x;
   fY = y;
}


///////////////////////////////////////////////////////////////////
//  CurrentPiece =  TetrisPiece + TTimer = live TetrisPiece
///////////////////////////////////////////////////////////////////
CurrentPiece::CurrentPiece(UInt_t type,TetrisBoard* board) :
   TetrisPiece(type,board), TTimer(1000,kTRUE)
{
   // Initialize new piece

   fBoard = board;

   Int_t line      = fBoard->GetHeight()-2;
   Int_t xPosition = fBoard->GetWidth()/2;

   SetXY(xPosition,line);

   if (!CanMoveTo(xPosition,line))    { gTetris->StopGame(); return; }

   fBoard->Modified();
   fBoard->Update();
   fBoard->SetDropped(kFALSE);
   SetSpeed();       // set speed of moving according to game level
   Start();          // add this timer to sytem timers list = start moving
}

void CurrentPiece::MoveTo(int x, int y)
{
   // Move this to (x,y) and  draw it there

   Erase();
   SetXY(x,y);            // set new coordinates
   fBoard->Modified();    // drawing
   fBoard->Update();
}

Bool_t CurrentPiece::CanMoveTo(int x, int y)
{
   // Can move this piece to (x,y)?

   Bool_t return_value;

   int  savX = fX;
   int  savY = fY;

   SetXY(x,y);                    // set new coordinates
   return_value = CanPosition();  // if inside board and no non-zero squares underneath
   SetXY(savX,savY);              // go back

   return return_value;
}

Bool_t CurrentPiece::CanPosition()
{
   // Check if piece position is allowed

   int x, y;

   for (int i = 0 ; i < 4 ; i++) {
      GetXY(i,x,y);      // coordinates of piece boxes at test position
      if (x < 0 || x >= fBoard->GetWidth()  ||
          y < 0 || y >= fBoard->GetHeight() ||
          !fBoard->IsEmpty(x,y))          return kFALSE;
   }
   return kTRUE;      // Inside board and no non-zero squares underneath.
}

Bool_t CurrentPiece::RotateRight()
{
   // Rotate clockwise. Returns kTRUE if succeeded.

   Bool_t return_value;

   Erase();
   TetrisPiece::RotateRight();
   return_value = CanPosition();
   if (!return_value) TetrisPiece::RotateLeft();    // rotate back

   fBoard->Modified();    // drawing
   fBoard->Update();
   return return_value;
}

Bool_t CurrentPiece::RotateLeft()
{
   // Rotate anti clockwise. Returns kTRUE if succeeded.

   Bool_t return_value;

   Erase();
   TetrisPiece::RotateLeft();
   return_value = CanPosition();
   if (!return_value) TetrisPiece::RotateRight();     // rotate back

   fBoard->Modified();    // drawing
   fBoard->Update();
   return return_value;
}

Bool_t CurrentPiece::OneLineDown()
{
   // Move one line down. Returns kTRUE if succeeded.

   int y = GetY();
   int x = GetX();

   y--;
   if (!CanMoveTo(x,y))  return kFALSE;

   MoveTo(x,y);
   return kTRUE;
}

Bool_t CurrentPiece::DropDown()
{
   // Move the piece to lowest allowed line. Returns kTRUE if succeeded.

   int y = GetY();
   int x = GetX();
   int dropHeight = 0;

   while (CanMoveTo(x,--y)) dropHeight++;  //  find lower allowed line

   y++;
   MoveTo(x,y);         //  .. and move to
   Stop();              //  stop moving
   fBoard->PieceDropped(this, dropHeight);
   return kTRUE;
}

Bool_t CurrentPiece::MoveLeft(int steps)
{
   // Move piece to the left. Return kTRUE if succeeded.

   int y = GetY();
   int x = GetX();

   while(steps) {
      if (!CanMoveTo(--x ,y)) return kFALSE;  // can't move
      MoveTo(x,y);
      steps--;
   }
   return kTRUE;
}

Bool_t CurrentPiece::MoveRight(int steps)
{
   // Move piece to the right. Return kTRUE if succeeded.

   int y = GetY();
   int x = GetX();

   while(steps) {
      if (!CanMoveTo(++x,y)) return kFALSE;  // can't move
      MoveTo(x,y);
      steps--;
   }
   return kTRUE;
}

Bool_t CurrentPiece::Notify()
{
   // Actions after time out.

   if (OneLineDown()) {
      TTimer::Reset();
      return kFALSE;
   } else {
      Stop();                        // stop moving
      fBoard->PieceDropped(this,0);  // piece can't move -> stop moving update state of TetrisBoard
      return kTRUE;
  }
}

void CurrentPiece::SetSpeed()
{
   // Set speed according to level.

   const Int_t factor = 2;
   SetTime(1000/(1 + gTetris->GetLevel()*factor));
}

void  CurrentPiece::Paint(Option_t*)
{
   // Paint it in fBoard.

   TPad* padsav = (TPad*)TVirtualPad::Pad();
   fBoard->cd();

   for (int i = 0 ; i < 4 ; i++) {
      fBoxes[i]->SetBorderMode(1);
      fBoxes[i]->SetFillColor(gPieceColors[fType-1]);
      fBoxes[i]->Paint();
   }
   padsav->cd();
}

void CurrentPiece::Erase()
{
   // Erase = paint with the same FillColor as fBoard has

   TPad* padsav = (TPad*)TVirtualPad::Pad();
   fBoard->cd();

   for (int i = 0 ; i < 4 ; i++) {
      fBoxes[i]->Erase();
   }
   padsav->cd();
}


///////////////////////////////////////////////////////////////////
//  Game  board
///////////////////////////////////////////////////////////////////
TetrisBoard::TetrisBoard(Float_t xlow, Float_t ylow,Float_t xup,Float_t yup) :
   TPad("tetris_board","Tetris Board",xlow,ylow,xup,yup,17,4,-1)
{
   // Game board constructor.

   fWidth  = (int)(fMother->XtoAbsPixel(GetX2())*(xup-xlow))/gBoxPixelSize;
   fHeight = (int)(fMother->YtoAbsPixel(GetY1())*(yup-ylow))/gBoxPixelSize;
   Double_t box = fMother->PixeltoX(gBoxPixelSize);
   Double_t xx = xlow + box*fWidth;

   if (xx<xup) {
      xx += fMother->PixeltoX(1);
      SetPad(xlow, ylow, xx, yup);
   }

   fBoard = new TetrisBoxPtr[fWidth*fHeight];
   fFilledLines = 0;
   Clear();
}

void TetrisBoard::Clear(Option_t *)
{
   // Delete/clear all objects.

   GetListOfPrimitives()->Delete();   // delete all object in this pad (including TetrisPiece)

   for (int i = 0; i < fWidth; i++)
      for (int j = 0; j < fHeight; j++)
         Board(i,j) = 0;              // clear board map

   fIsDropped = kTRUE;
}

void TetrisBoard::Hide()
{
   // Hide all objects.

   TetrisBox *box;
   TIter nextin(GetListOfPrimitives());

   while ((box = (TetrisBox*)nextin())) box->Hide();
   Modified();
   Update();
}

void TetrisBoard::Show()
{
   // Show all objects

   TetrisBox *box;
   TIter nextin(GetListOfPrimitives());

   while ((box = (TetrisBox*)nextin())) box->Show();
   Modified();
   Update();
}

Bool_t TetrisBoard::IsFullLine(Int_t line)
{
   // Check if line is full.

   Bool_t return_value = kTRUE;

   for (int i = 0; i < fWidth; i++)
      return_value = return_value && !IsEmpty(i,line);

   return return_value;
}

Bool_t TetrisBoard::IsEmptyLine(Int_t line)
{
   // Check if line is empty

   Bool_t return_value = kTRUE;

   for (int i = 0; i < fWidth; i++)
      return_value = return_value && IsEmpty(i,line);

   return return_value;
}

void TetrisBoard::RemoveLine(Int_t line)
{
   // Remove all TetrisBoxes of the line

   for (int i=0; i<fWidth; i++) {
      if (Board(i,line))  // when you delete TObject it's also removed from Pad
      delete Board(i,line);

      Board(i,line) = 0;
   }
}

void TetrisBoard::MoveOneLineDown(Int_t line)
{
   // All  boxes of this line move to (line-1)

   if (!line) return;   // don't move line==0

   for (int i = 0; i < fWidth; i++) {
      if (!IsEmpty(i,line)) {
         Board(i,line)->MoveOneLineDown();     // change  position of Boxes
         Board(i,line-1) = Board(i,line);      // remapping
      }
      Board(i,line)=0;   // this line become empty
   }
   Modified();
   Update();
}

void TetrisBoard::RemoveFullLines()
{
   // Remove full lines

   for (int i = 0; i < fFilledLines; i++) {
      while (IsFullLine(i)) {
         RemoveLine(i);
         gTetris->UpdateLinesRemoved();
         AllAboveLinesDown(i);
         fFilledLines--;
      }
   }
}

void  TetrisBoard::GluePiece(TetrisPiece* piece)
{
   // Add pointers to piece boxes to fBoard::fBoard

   int x,y;
   TetrisBox *box;

   for (int i = 0 ; i < 4 ; i++) {
     piece->GetXY(i,x,y);
     box = piece->GetTetrisBox(i);
     if (box->IsHidden()) { delete  box; continue;}     // delete hidden boxes
     Board(x,y) = piece->GetTetrisBox(i);     // add pointers to piece boxes to board map
     if (y>fFilledLines) fFilledLines = y+1;  // update number of non empty lines
   }
}

void TetrisBoard::PieceDropped(TetrisPiece* piece, int height)
{
   // Actions after piece was droped

   Int_t add2score = height*gTetris->GetLevel() + 10;    // update score policy (could be modified)

   fIsDropped = kTRUE;
   GluePiece(piece);
   RemoveFullLines();
   //Print();             // possible printig of board map on the terminal

   gTetris->UpdatePiecesDropped();
   gTetris->UpdateScore(add2score);
   gTetris->CreateNewPiece();        // create new CurrentPiece
   fIsDropped = kFALSE;
}

void TetrisBoard::Print(const char *) const
{
   // Used for testing

   printf("\n");

   for (int j = fHeight-1; j > -1; j--) {
      for (int i = 0; i < fWidth; i++)
         ((TetrisBoard*)this)->IsEmpty(i,j) ? printf("|   ") : printf("| * ") ;
      printf("|\n");
   }
}

void TetrisBoard::PaintModified()
{
   // Overload this method to acelerate graphics
   // (do not draw tens of heap boxes while current box is moving)

   if (!fIsDropped && gTetris->IsGameOn() && !gTetris->IsPaused())
      gTetris->fCurrentPiece->Paint();
   else
      TPad::PaintModified();
}

///////////////////////////////////////////////////////////////////
//  NextPiecePad
//  used to show next piece.
///////////////////////////////////////////////////////////////////
NextPiecePad::NextPiecePad(Float_t xlow, Float_t ylow, Float_t xup, Float_t yup)
   : TPad("next_piece","Next Piece Pad",xlow,ylow,xup,yup,17,4,-1)
{
   // Next piece pad ctor.

   fPiece = new TetrisPiece(this);
   fPiece->Hide();        // hide piece at start

   // (how to get pixel size?)
   Int_t x = (int)(fMother->XtoAbsPixel(GetX2())*(xup-xlow))/gBoxPixelSize/2;
   Int_t y = (int)(fMother->YtoAbsPixel(GetY1())*(yup-ylow))/gBoxPixelSize/2;

   fPiece->SetXY(x,y);    // move to the center of pad
   Modified(kTRUE);
   Update();
}


///////////////////////////////////////////////////////////////////
//  PauseButton - push button
//  ExecuteEvent mehtod used to pause the game
///////////////////////////////////////////////////////////////////
PauseButton::PauseButton(Float_t xlow, Float_t ylow, Float_t xup, Float_t yup) :
   TButton("Pause"," ",xlow,ylow,xup,yup)
{
   // Pause button constructor

   SetBorderSize(5);     //  decoration stuff....
   SetTextSize(0.45);
   SetFillColor(42);
}

void PauseButton::ExecuteEvent(Int_t event, Int_t, Int_t)
{
   // Action after mouse click

   if (event == kButton1Up) {
      IsPressed() ? gTetris->Continue() :  gTetris->Pause();
      Modified(kTRUE);
   }
}


///////////////////////////////////////////////////////////////////
//  QuitButton - push button
//  ExecuteEvent mehtod used to quit the game
///////////////////////////////////////////////////////////////////
QuitButton::QuitButton(Float_t xlow, Float_t ylow, Float_t xup, Float_t yup) :
   TButton("Quit"," ",xlow,ylow,xup,yup)
{
   // Quit button constructor

   SetBorderSize(5);   //  decoration stuff....
   SetTextSize(0.45);
   SetFillColor(42);
}

void QuitButton::ExecuteEvent(Int_t event, Int_t, Int_t)
{
   // Action after mouse click

   if (event == kButton1Up) gTetris->Quit();
}


///////////////////////////////////////////////////////////////////
//  NewGameButton - push button
//  ExecuteEvent mehtod used to start new game the game
///////////////////////////////////////////////////////////////////
NewGameButton::NewGameButton(Float_t xlow, Float_t ylow, Float_t xup, Float_t yup)
   : TButton("New Game"," ",xlow,ylow,xup,yup)
{
   // New game button constructor

   SetBorderSize(5);
   SetTextSize(0.45);
   SetFillColor(42);
}

void NewGameButton::ExecuteEvent(Int_t event, Int_t, Int_t)
{
   // Ation after mouse click

   if (event == kButton1Up) {
      gTetris->NewGame();      // always starts new game
      Modified(kTRUE);
   }
}


///////////////////////////////////////////////////////////////////
//  InfoPad -
///////////////////////////////////////////////////////////////////
InfoPad::InfoPad(const char* title, Float_t xlow, Float_t ylow, Float_t xup, Float_t yup)
   : TPad("info_pad",title,xlow,ylow,xup,yup,17,4,-1), TAttText(22,0,2,71,0.65)
{
   // InfoPad constructor

   SetBit(kCanDelete);

   TText *text = new TText(xlow,yup,title);   // draw title of the information pad
   text->SetTextSize(0.45*(yup-ylow));
   text->SetY(yup+0.2*text->GetTextSize());
   fMother->GetListOfPrimitives()->Add(text);

   text = new TText(0.5,0.5,"0");          // this text used to display fValue
   GetListOfPrimitives()->Add(text);

   fValue = 0;
   Modified(kTRUE);
   Update();
}

void InfoPad::PaintModified()
{
   // Actions after pad was modified (resize event, user's Modified(kTRUE) ...)

   char    str[40];

   snprintf(str,40,"%d",fValue);

   TObject *obj = GetListOfPrimitives()->First();

   if (obj && obj->InheritsFrom("TText")) {
      TText *text = (TText*)obj;
      text->SetTitle(str);                // set title according to fValue

      text->SetTextSize(GetTextSize());
      text->SetTextFont(GetTextFont());
      text->SetTextAlign(GetTextAlign());
      text->SetTextColor(GetTextColor());
      text->SetTextAngle(GetTextAngle());
      text->TAttText::Modify();

      text->SetX(0.5);        // draw centered
      text->SetY(0.5);
   }
   TPad::PaintModified();
}


///////////////////////////////////////////////////////////////////
//  KeyHandler - virtual frame used to catch and handle key events
///////////////////////////////////////////////////////////////////
KeyHandler::KeyHandler() : TGFrame(gClient->GetRoot(),0,0)
{
   // Key handler constructor.

   // get main frame of Tetris canvas
   TRootCanvas *main_frame = (TRootCanvas*)(gTetris->GetCanvasImp());

   // bind arrow keys and space-bar key
   main_frame->BindKey((const TGWindow*)this, gVirtualX->KeysymToKeycode(kKey_Up),    0);
   main_frame->BindKey((const TGWindow*)this, gVirtualX->KeysymToKeycode(kKey_Left),  0);
   main_frame->BindKey((const TGWindow*)this, gVirtualX->KeysymToKeycode(kKey_Right), 0);
   main_frame->BindKey((const TGWindow*)this, gVirtualX->KeysymToKeycode(kKey_Down),  0);
   main_frame->BindKey((const TGWindow*)this, gVirtualX->KeysymToKeycode(kKey_Space), 0);
}

KeyHandler::~KeyHandler()
{
   // Cleanup key handler.

   // get main frame of Tetris canvas
   TRootCanvas *main_frame = (TRootCanvas*)(gTetris->GetCanvasImp());

   // remove binding of arrow keys and space-bar key
   main_frame->RemoveBind(this, gVirtualX->KeysymToKeycode(kKey_Up),    0);
   main_frame->RemoveBind(this, gVirtualX->KeysymToKeycode(kKey_Left),  0);
   main_frame->RemoveBind(this, gVirtualX->KeysymToKeycode(kKey_Right), 0);
   main_frame->RemoveBind(this, gVirtualX->KeysymToKeycode(kKey_Down),  0);
   main_frame->RemoveBind(this, gVirtualX->KeysymToKeycode(kKey_Space), 0);
   // restore key auto repeat functionality, was turned off in TGMainFrame::HandleKey()
   gVirtualX->SetKeyAutoRepeat(kTRUE);
}


Bool_t KeyHandler::HandleKey(Event_t *event)
{
   // Handle arrow and spacebar keys

   char tmp[2];
   UInt_t keysym;

   gVirtualX->LookupString(event, tmp, sizeof(tmp), keysym);

   if (event->fType == kGKeyPress) {
      switch ((EKeySym)keysym) {
         case kKey_Left:
            gTetris->MoveLeft();
            break;
         case kKey_Right:
            gTetris->MoveRight();
            break;
         case kKey_Down:
            gTetris->RotateRight();
            break;
         case kKey_Up:
            gTetris->RotateLeft();
            break;
         case kKey_Space:
            gTetris->DropDown();
            break;
         default:
            return kTRUE;
      }
   }
   return kTRUE;
}

///////////////////////////////////////////////////////////////////
//  UpdateLevelTimer
///////////////////////////////////////////////////////////////////
UpdateLevelTimer::UpdateLevelTimer(ULong_t time) : TTimer(time,kTRUE)
{
   // Update level timer constructor

   SetBit(kCanDelete);   // delete this when gTetris is deleted
   gTetris->GetListOfPrimitives()->Add(this);
}

Bool_t UpdateLevelTimer::Notify()
{
   // Actions after time out

   if (!gTetris->IsGameOn()) {
      Remove();
      return kTRUE;
   }
   gTetris->UpdateLevel();
   TTimer::Reset();
   return kFALSE;
}


///////////////////////////////////////////////////////////////////
//   Tetris =  Game manager
///////////////////////////////////////////////////////////////////
Tetris::Tetris() :
   TCanvas("Tetris","Have a little fun with ROOT!",200,200,700,500)
{
   // Tetris constructor

   gTetris = this;

   fCurrentPiece = 0;

   //-----------  play board ------------
   fBoard            = new  TetrisBoard(0.35,0.05,0.7,0.95);
   fBoard->Draw();

   // ----------  info pads -------------
   fNextPiece        =  new  NextPiecePad(0.05,0.65,0.25,0.95);
   fNextPiece->Draw();

   fLinesRemoved     =  new  InfoPad("Lines Removed",0.75,0.8,0.95,0.9);
   fLinesRemoved->Draw();

   fLevel            =  new  InfoPad("Level",0.75,0.6,0.95,0.7);
   fLevel->Draw();

   fScore            =  new  InfoPad("Score",0.75,0.4,0.95,0.5);
   fScore->Draw();

   //------------ buttons ----------------
   fNewGame          =  new  NewGameButton(0.05,0.05,0.25,0.15);
   fNewGame->Draw();

   fQuit             =  new  QuitButton(0.05,0.2,0.25,0.3);
   fQuit->Draw();

   fPause            =  new  PauseButton(0.05,0.35,0.25,0.45);
   fPause->Draw();

   fPiecesDropped = 0;
   SetFillColor(21);

   fKeyHandler = new KeyHandler();
   fUpdateLevelTimer = new UpdateLevelTimer(60000);  // every  minute
   SetFixedSize();
   Update();
   PrintHelpInfo();
   fEditable = kFALSE;
}

void Tetris::PrintHelpInfo()
{
   // Prints help info

   printf("\n\n\n");
   printf("             Move   Piece Left     ---------     left-arrow\n");
   printf("             Move   Piece Right    ---------     right-arrow\n");
   printf("             Rotate Piece          ---------     up/down-arrow \n");
   printf("             Drop   Piece Down     ---------     space-bar\n");
   printf("\n\n\n");
}

void Tetris::CreateNewPiece()
{
   // Create  current and next pieces

   UInt_t type = fNextPiece->GetPiece()->GetType();
   fNextPiece->NewPiece();
   fCurrentPiece = new CurrentPiece(type,fBoard);
}

void Tetris::SetFixedSize()
{
   // Set size of canvas

   ((TRootCanvas*)fCanvasImp)->SetWMSizeHints(fCw,fCh+20,fCw,fCh,0,0);
}

void Tetris::Quit()
{
   // Stop game and delete canvas (i.e. tetris itself)

   delete fKeyHandler; fKeyHandler = 0;
   StopGame();
   ((TRootCanvas*)fCanvasImp)->CloseWindow();
}

void Tetris::NewGame()
{
   // Start new game

   gVirtualX->SetInputFocus(((TRootCanvas*)fCanvasImp)->GetId());

   if (IsGameOn()) StopGame();       // stop privious game
   fScore->Reset();
   fLinesRemoved->Reset();
   fPiecesDropped = 0;
   SetLevel(1);
   fUpdateLevelTimer->Start();
   fBoard->Clear();
   fNewGame->SetPressed(kTRUE);
   CreateNewPiece();                 // start game
}

void Tetris::StopGame()
{
   // Stop the game

   fUpdateLevelTimer->Stop();
   if (fCurrentPiece) fCurrentPiece->Stop();
   fNewGame->SetPressed(kFALSE);
   fPause->SetPressed(kFALSE);
}

void Tetris::Pause()
{
   // Pause the game

   if (!IsGameOn())  return;
   if (fCurrentPiece) fCurrentPiece->Stop();
   fPause->SetPressed(kTRUE);
   fBoard->Hide();
}

void  Tetris::Continue()
{
   // Continue the game

   if (!IsGameOn()) return;
   fBoard->Show();
   fPause->SetPressed(kFALSE);
   if (fCurrentPiece) fCurrentPiece->Start();
}

void Tetris::MoveLeft()
{
   // Move pice to the left

   if (!IsGameOn() || IsPaused() || IsWaiting())  return;
   fCurrentPiece->MoveLeft();
}

void Tetris::MoveRight()
{
   // Move piece to the right

   if (!IsGameOn() || IsPaused() || IsWaiting())  return;
   fCurrentPiece->MoveRight();
}

void Tetris::DropDown()
{
   // Drop piece down

   if (!IsGameOn() || IsPaused() || IsWaiting())  return;
   fCurrentPiece->DropDown();
}

void Tetris::RotateRight()
{
   // Rotate piece right

   if (!IsGameOn() || IsPaused() || IsWaiting())  return;
   fCurrentPiece->RotateRight();
 }

void Tetris::RotateLeft()
{
   // Rotate piece left

   if (!IsGameOn() || IsPaused() || IsWaiting())  return;
   fCurrentPiece->RotateLeft();
 }

void Tetris::SetLevel(int level)
{
   // Set difficulty level

   fLevel->SetValue(level);
   if (fCurrentPiece) fCurrentPiece->SetSpeed();
}
back to top