Click here to Skip to main content
15,885,869 members
Articles / Desktop Programming / WTL
Article

Nura Quadris – The Time Killer Computer Game

Rate me:
Please Sign up or sign in to vote.
3.55/5 (7 votes)
25 Feb 2008CPOL21 min read 40.1K   635   15   6
A different take on a familiar game
NuraQuadris1.gif

Contents

  1. Introduction
    1. The name of Nura Quadris
    2. The rules of Nura Quadris
    3. The features of Nura Quadris
    4. The usage of Nura Quadris
  2. Background
  3. The source code
  4. Environment
  5. Using the code
    1. Entire Structure
    2. The Classes CMainFrame and CQuadrisWTLView
    3. The Class QuadrisWindowWTL
    4. The user-defined Message NM_QUADRIS (= UM_QUADRIS) of QuadrisWindowWTL
    5. The Class NextWindow
    6. The Class QuadrisCore
  6. How to support Win95, Win98, Win98SE and WinME
  7. How to embed a help function
  8. Points of Interest
  9. Quadris Customizer
  10. Acknowledgement

Introduction

The name of Nura Quadris

Nura Quadris is a computer game where user must stack bricks and fill a whole row or rows to clear them. We call it "Quadris" when we clear four rows at once like we call "strike" in bowling when we hit all the pins at once. Nura is my wife's name. So, I named my program Nura Quadris. Nur means light in Arabic, and -a is a feminine suffix, so that Nura can mean bright lady. It is a very popular Arabic name of women in Middle East.

The Rules of Nura Quadris

The rules of Nura Quadris are same as the rules of the normal Quadris game. The rule is as follows:

  1. A brick is made of four blocks.
  2. When a brick falls down, you shall turn it and/or shift it left or right in order to make it fit to stacked bricks before it lands on the stacked bricks.
  3. When it lands on the stacked bricks, if whole a row or rows are fully filled, the filled row(s) will be cleared and the brick(s) stacked on the cleared row(s) will come down to fill the empty row(s).
  4. Then, a new brick will fall down.

The Features of Nura Quadris

  1. It automatically detects the language of Windows, and shows all the instructions in either Korean or English. If your Windows is Korean Windows, it will have Korean mode, but if it is non-Korean Windows, it will have English mode. However, you can customize Nura Quadris into your language by using NuraQuadris.ini. You can generate NuraQuadris.ini by using QuadrisCustomizer.exe. I will introduce QuadrisCustomizer.exe later.
  2. It has the option to show a helping grid. The default is showing no grid.
  3. It has the option to make sounds. The default is making sounds.
  4. It has the option to show a next brick in advance. The default is showing a next brick in advance.
  5. Before you start the game, if you press the key 'F1', you can get help-information. If you press the key 'F12', an About-message box will pop up. You can see simple information about Nura Quadris there.

The Usage of Nura Quadris

  1. To start the game, click the button "Start".
  2. During the game, if you want to cancel the game, click the button "Cancel".
  3. During the game, if you want to pause the game, click the button "Pause". And then, if you want to continue the game again, click the button "Continue".
  4. If you want helping grid, check "Grid" option.
  5. If you do not want sound, check "Mute" option.
  6. Press Up-arrow key to rotate the brick.
  7. Press Left-arrow key to shift the brick left.
  8. Press Right-arrow key to shift the brick right.
  9. Press Down-arrow key to move the brick down faster.
  10. Press Space-bar key to drop down the brick to the bottom.

Background

It includes five things: a Quadris engine, a control-like window, a next window, a view window and a skin window. I will give some brief descriptions about those things in this article. I used a design pattern: the Bridge Pattern (exactly speaking, a modified version of the Bridge Pattern), but I would not explain about design pattern here.

The Source Code

This source code uses the WTL library. The source code includes four projects: QuadrisCore, QuadrisWindowWTL, NuraQuadris (in the QuadrisWTL folder), and QuadrisCustomizer. The project QuadrisCore is the library of the Quadris engine. QuadrisWindowWTL is the control-like window of the Quadris window for WTL. The project NuraQuadris is the executable project which is actually a Quadris game program. But, it does not use the library of Quadris window but, here to make things simple, uses the sources of Quadris window and Quadris core directly. Finally, the project QuadrisCustomizer is the executable project which is a language customizer for NuraQuadris.

Environment

Nura Quadris was created with VC++ .NET 2003 Standard Edition SP1 (hereinafter, referred to as VC++ 7.1) with WTL 8.0. You can get WTL 8.0 from here unless the website is changed. It was mainly tested under Windows XP SP2, Windows 2000 SP4 and Windows 98 SE. To compile the source code, you need to have WTL installed. Also, it can be compiled with either VC++ 2005 Express Edition (hereinafter, referred to as VC++ 8.0X) or VC++ 2008 Express Edition (hereinafter, referred to as VC++ 9.0X). Of course, you have to take some steps before compiling it. It is disclosed here about using VC++ 8.0X for Windows programming, and here about WTL installation for VC++ 8.0X. To use WTL 8.0 for VC++ 9.0X by creating WTL-App wizzard in VC++ 9.0X, put setup90x.js in the folder "AppWiz" of installed WTL 8.0 and use it, which I created by tweaking setup80x.js. To make it be able to be compiled with VC++ 8.0X or VC++ 9.0X which uses ATL 3.0, I made ATLVersion.h and included it in stdafx.h. Quadris.sln is for VC++ 7.1 while Quadris2008.sln is for VC++ 9.0X. QuadrisWTL.vcproj is for VC++ 7.1 while QuadrisWTL2008.vcproj is for VC++ 9.0X. All the file name conventions for solution files (*.sln) and project files (*.vcproj) are the same as the above examples.

Using the Code

Entire Structure

I have mentioned that Nura Quadris consists of five parts: a Quadris engine, a control-like window, a next window, a view window and a skin window. The skin window is a SDI application framework itself, and it contains a view window as its child window. The skin window is implemented by a class CMainFrame. The view window contains the control-like window and the next window as its child windows, and it is implemented by a class CQuadrisWTLView. The control-like window is the Quadris game window itself, and is implemented by the class QuadrisWindowWTL. The reason why I call this window control-like window is that this window is not actually a control but it functions as a control. The control-like window contains the Quadris engine. The Quadris engine is implemented by the classes QuadrisCore. The next window is the window which shows the next brick in advance while the Quadris game is going on, and is implemented by the class NextWindow.

The Classes CMainFrame and CQuadrisWTLView

The class CMainFrame and CQuadrisWTLView are provided by the WTL-App Wizard, and I coded on them. CQuadrisWTLView receives the user-defined message NM_QUADRIS (in this case, UM_QUADRIS) from QuadrisWindowWTL. Its member function OnQuadrisMessage will deal with the message UM_QUADRIS. The following code is related with the processing of the user-defined message UM_QUADRIS.

C++
LRESULT CQuadrisWTLView::OnQuadrisMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
    case TN_NEXT:       OnNext(lParam);             break;
    case TN_PURGE:      OnPurge((int) lParam);      break;
    case TN_FINISH:     OnFinish((int) lParam);     break;
    //case TN_LEVEL:        break;
    //case TN_PAUSE:        break;
    //case TN_CONTINUE:     break;
    //case TN_START:        break;
    //case TN_STOP:         break;
    //case TN_GRID:         break;
    //case TN_SOUND:        break;
    }

    return 0;
}

void CQuadrisWTLView::OnPurge (int lines)
{
    TCHAR    str[STRINGMAX];
    _stprintf(str, m_strScore, m_pQuadris->GetScore());
    m_Score.SetWindowText(str);
}

void CQuadrisWTLView::OnFinish (int score)
{
    m_Start.ShowWindow(SW_SHOW);
    m_Cancel.ShowWindow(SW_HIDE);
    m_Pause.ShowWindow(SW_HIDE);
    m_Continue.ShowWindow(SW_HIDE);

    m_pNext->PostMessage(UM_QUADRIS, TN_FINISH, (LPARAM) score);
}

void CQuadrisWTLView::OnNext (LPARAM lParam)
{
    m_pNext->PostMessage(UM_QUADRIS, TN_NEXT, lParam);
}

It also receives instructions from users through push buttons and check buttons. If you want to set the language to be English regardless the system language of your Windows, uncomment the statements of line 62 in stdafx.h in the folder QuadrisWTL, as follows:

#define Quadris_LANG   LANG_ENGLISH

The Class QuadrisWindowWTL

It uses a user-defined message: NM_QUADRIS (exactly speaking, m_Message or UM_QUADRIS, in this case). QuadrisWindowWTL sends NM_QUADRIS to QuadrisWTLView whenever a new brick falls and/or whenever fully filled row(s) is/are cleared. It will also send NM_QUADRIS to QuadrisWTLView when the game is over. To avoid message conflicts in QuadrisWTLView, the constructor of QuadrisWindowWTL can receive a different value for the user-defined message of NM_QUADRIS as a parameter and keep it in m_Message. QuadrisWindowWTL is very loosely bound to QuadrisWTLView. The public member functions of QuadrisWindowWTL are as follows:

C++
class QuadrisWindowWTL : public CWindowImpl<QuadrisWindowWTL>
{
    ...
public:
    QuadrisWindowWTL (UINT message = NM_QUADRIS, bool bAuto = true);
    QuadrisWindowWTL (UINT message, int lang, bool bAuto);
    virtual ~QuadrisWindowWTL (void);
    ...
    inline bool Start (void)        { return StartStop(true); }
    inline bool Stop (void)         { return StartStop(false); }
    inline bool Pause (void)        { return PauseContinue(true); }
    inline bool Continue (void)     { return PauseContinue(false); }
    inline int GetScore (void)      { return m_pQuadris->GetScore(); }
    inline int GetLevel (void)      { return m_Level; }
    inline void SetGrid (bool bGrid = true)     { m_bGrid = bGrid; }
    inline void SetSound (bool bSound = true)   { m_bSound = bSound; }
    inline int GetSpeed (void)      { return m_Interval; }
    bool SetSpeed (int interval);

    // The reason why there is no function Create (..., const RECT* pRect, ...)
    // or Create (..., const POINT* pPt, ...) is to prevent a null pointer parameter.
    HWND Create (HWND hParentWnd, int x, int y, UINT nID);
    HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);
    HWND Create (HWND hParentWnd, int x, int y, int nWidth, int nHeight, UINT nID);
    HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
    HWND Create (HWND hParentWnd, int x, int y,
                    DWORD dwStyle, DWORD dwExStyle, UINT nID);
    HWND Create (HWND hParentWnd, const POINT& pt,
                    DWORD dwStyle, DWORD dwExStyle, UINT nID);
    HWND Create (HWND hParentWnd, int x, int y, int nWidth, int nHeight,
                    DWORD dwStyle, DWORD dwExStyle, UINT nID);
    HWND Create (HWND hParentWnd, const RECT& rect,
                    DWORD dwStyle, DWORD dwExStyle, UINT nID);

    // The reason why there is no function Move (..., const RECT* pRect, ...)
    // or Move (..., const POINT* pPt, ...) is to prevent a null pointer parameter.
    BOOL Move (int x, int y, BOOL bRepaint = TRUE);
    BOOL Move (POINT& pt, BOOL bRepaint = TRUE);
    BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);
    BOOL Move (RECT& rect, BOOL bRepaint = TRUE);
    ...
}

QuadrisWindowWTL (UINT message = NM_QUADRIS, bool bAuto = true);

  • It is a constructor.
  • The first parameter message is the message which QuadrisWindowWTL will sent to the parent window. To avoid message conflict, you can give a different value for the message. The default is NM_QUADRIS.
  • The second parameter is whether it deals with the end process by itself or not. If the second parameter bAuto is set to be true, it would not send NM_QUADRIS (or the message you gave) to the parent window and it will deal with the end process. The default is true.
  • Language will be automatically chosen according to the default system language of Windows.

QuadrisWindowWTL (UINT message, int lang, bool bAuto);

  • It is another constructor.
  • The first and third parameters are the same as described above.
  • The second parameter lang is for the language. If you set it to be LANG_ENGLISH, it will use Korean regardless of the default language of Windows.

inline bool Start (void);

  • It makes the Quadris game start.
  • The return value is true when the game starts, and is false when it fails.

inline bool Stop (void);

  • It makes the Quadris game stop.
  • The return value is true when the game stops, and is false when it fails.

inline bool Pause (void);

  • It makes the Quadris game pause.
  • The return value is true when the game is paused and is false when it fails.

inline bool Continue (void);

  • It makes the Quadris game continue.
  • The return value is true when the game is continued and is false when it fails.

inline int GetScore (void);

  • It gives the current score of Quadris game.
  • The return value is the current score.

inline int GetLevel (void);

  • It gives the current level of Quadris game.
  • The return value is the current level.

inline void SetGrid (bool bGrid = true);

  • It determines whether the Quadris Window have helping grids or not.
  • If the parameter bGrid is true, the Quadris Window will have helping grids. If the parameter bGrid is false, the Quadris Window will have no helping grids.

inline void SetSound (bool bSound = true);

  • It determines whether the Quadris Window makes effect sounds.
  • If the parameter bSound is true, the Quadris Window will make effect sounds. If he parameter bSound is false, the Quadris Window will not make effect sounds.

inline int GetSpeed (void);

  • It gives the current speed of Quadris game.
  • The return value is the current speed.

bool SetSpeed (int interval);

  • It sets the speed.
  • The parameter interval is the interval between moving. It is in the unit of milliseconds.

HWND Create (HWND hParentWnd, const RECT& rect, DWORD dwStyle, DWORD dwExStyle, UINT nID);

  • It creates Quadris control-like Window. Its window class name is Quadris_CLASS, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
  • The return value is the window handle to the Quadris window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter rect is the reference to the rectangle of the Quadris window.
  • The third parameter dwStyle is the window style of the Quadris window.
  • The fourth parameter dwExStyle is the extended window style of the Quadris window.
  • The fifth parameter nID is the ID given to the Quadris window.

HWND Create (HWND hParentWnd, const POINT& pt, DWORD dwStyle, DWORD dwExStyle, UINT nID);

  • It creates the Quadris control-like Window. Its window class name is Quadris_CLASS, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
  • The return value is the window handle to the Quadris window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter pt is the reference to the left-top point of the Quadris window. Its width and height will be both determined to be 400 pixels.
  • The third parameter dwStyle is the window style of the Quadris window.
  • The fourth parameter dwExStyle is the extended window style of the Quadris window.
  • The fifth parameter nID is the ID given to the Quadris window.

HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);

  • It creates the Quadris control-like Window. Its window class name is Quadris_CLASS, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
  • The return value is the window handle to the Quadris window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter rect is the reference to the rectangle of the Quadris window.
  • The third parameter nID is the ID given to the Quadris window.
  • The style and the extended style of the Quadris window are both NULL, by default.

HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);

  • It creates Quadris control-like Window. Its window class name is Quadris_CLASS, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
  • The return value is the window handle to the Quadris window.
  • The first parameter hParentWnd is the window handle to its parent window.
  • The second parameter pt is the reference to the left-top point of the Quadris window. Its width and height will be both determined to be 400 pixels.
  • The third parameter nID is the ID given to the Quadris window.
  • The style and the extended style of the Quadris window are both NULL, by default.

BOOL Move (int x, int y, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first and second parameters x and y are the left-top position of the Quadris window.
  • The third parameter bRepaint is related to whether the Quadris window will be redrawn when it moves. If bRepaint is true, the Quadris window will be redrawn. If bRepaint is false, the Quadris window will not be redrawn. The default of bRepaint is true.
  • The width and height of the Quadris window will be retained as before.

BOOL Move (POINT& pt, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first parameter pt is the left-top position of the Quadris window.
  • The second parameter bRepaint is related to whether the Quadris window will be redrawn when it moves. If bRepaint is true, the Quadris window will be redrawn. If bRepaint is false, the Quadris window will not be redrawn. The default of bRepaint is true.
  • The width and height of the Quadris window will be retained as before.

BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first, second, third, and fourth parameters x, y, nWidth, nHeight are the Quadris window's position.
  • The fifth parameter bRepaint is related to whether the Quadris window will be redrawn when it moves. If bRepaint is true, the Quadris window will be redrawn. If bRepaint is false, the Quadris window will not be redrawn. The default of bRepaint is true.

BOOL Move (RECT& rect, BOOL bRepaint = TRUE);

  • It moves the window to the specified position.
  • The return value is true if it succeeds, and false if it fails.
  • The first parameter rect is the reference to the Quadris window's position.
  • The second parameter bRepaint is related to whether the Quadris window will be redrawn when it moves. If bRepaint is true, the Quadris window will be redrawn. If bRepaint is false, the Quadris window will not be redrawn. The default of bRepaint is true.

The patterns of Create(...) and Move(...) are the same as those of Nura Tritris. I prefer these patterns of the functions Create(...) and Move(...).

The User-Defined Message NM_QUADRIS (= UM_QUADRIS) of QuadrisWindowWTL

The user-defined message NM_QUADRIS (= UM_QUADRIS in this case) has WPARAM as a notice code and LPARAM as the information related with the notice code. The notice codes are defined in QuadrisWindowWTL.h. The notice code is as follows:

<< Table of User-defined Message NM_QUADRIS (= UM_QUADRIS) >>

WPARAM (notice code)

LPARAM

Description

TN_FINISH

Score

To inform of the end of game

TN_NEXT

HDC for Next window to do double buffering

To inform of the next brick

TN_PURGE

The number of purged lines

To inform of clearing line(s)

TN_LEVEL

New level

Reserved for the future

TN_START

Not determined yet

Reserved for the future

TN_STOP

Not determined yet

Reserved for the future

TN_PAUSE

Not determined yet

Reserved for the future

TN_CONTINUE

Not determined yet

Reserved for the future

TN_GRID

Not determined yet

Reserved for the future

TN_SOUND

Not determined yet

Reserved for the future

TN_SHOWNEXT

Not determined yet

Reserved for the future

The Class NextWindow

It is the window to show the next brick. It receives a user-defined messages: NM_QUADRIS (exactly speaking, m_Message or UM_QUADRIS, in this case). If QuadrisWindowWTL sends NM_QUADRIS with the notice code TN_NEXT or TN_FINISH as WPARAM to QuadrisWTLView, QuadrisWTLView sends them to NextWindow. This is the way in which two different windows QuadrisWindowWTL and NextWindow communicate with each other. NextWindow shows the next brick by StretchBlt(...) using a handle to Device Context (HDC) which is passed through LPARAM. See LRESULT NextWindow::OnPaint(...). The related source of NextWindow is as follows:

C++
LRESULT NextWindow::OnQuadrisMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
    case TN_NEXT:   OnNext((HDC) lParam);   break;
    case TN_FINISH: OnFinish();             break;
    }

    return 0;
}

void NextWindow::OnNext (HDC hDC)
{
    m_hDC = hDC;
    Invalidate();
}

void NextWindow::OnFinish (void)
{
    m_hDC = NULL;
    Invalidate();
}

LRESULT NextWindow::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (!m_hDC)
    {
        SetMsgHandled(FALSE);
        return 0;
    }

    CPaintDC    dc(m_hWnd);
    CRect       rc;

    GetClientRect(rc);
    dc.StretchBlt(0, 0, rc.Width(), rc.Height(), m_hDC,
                  0, 0, Quadris_NEXTBMWIDTH, Quadris_NEXTBMHEIGHT, SRCCOPY);

    return 0;
}

The handle to Device Context (HDC) which is passed through LPARAM has been already prepared by QuadrisWindowWTL::DrawNext(void). The functions Create(...) and Move(...) have the same patterns as those of QuadrisWindowWTL.

The Class QuadrisCore

Quadris algorithm is such a famous algorithm that I do not have to explain all the member functions. Instead, I would explain the usage of the public member functions of QuadrisCore.

C++
class QuadrisCore
{
    ...
public:
   QuadrisCore (int width, int height, int colors);
   ~QuadrisCore (void);

    inline char GetBoard (int x, int y)      { return Board(x, y); }
    inline LOCATION GetCurLoc ()    { return m_Pos; }
    inline int GetScore ()          { return m_Score; }
    inline int GetCurCol ()         { return m_CurCol; }
    inline int GetNextCol ()        { return m_NextCol; }
    inline int GetLoopStep ()       { return (int) m_LoopStep; }
    inline BLOCK* GetCurBrick ()    { return (BLOCK*) &m_Brick[m_CurBrick]; }
    inline BLOCK* GetNextBrick ()   { return (BLOCK*) &m_Brick[m_NextBrick]; }

    void InitGame (void);
    bool RotateBrick (bool bClockwise = true);
    bool ShiftLeft (void);
    bool ShiftRight (void);
    bool ShiftDown (void);
    void PullDown (void);
    bool Shuffle (void);
    int Loop ();
};

QuadrisCore (int width, int height, int colors);

  • It is a constructor.
  • The first parameter width is the width of the inside of the Quadris board.
  • The second parameter height is the height of the inside of the Quadris board.
  • The third parameter colors is the number of the colours of the bricks.

inline char GetBoard (int x, int y);

  • It gives one cell of the Quadris board.
  • The first parameter x is x-coordinate.
  • The second parameter y is y-coordinate.
  • The return value is one of WALL (= -1), BLANK (= 0) and BRICK (= 1, 2, ...).

inline LOCATION GetCurLoc () ;

  • It gives the current position of a falling brick.
  • The return value is the current position of the falling brick in the form of struct LOCATION. struct LOCATION is as follows:
  • C++
    struct LOCATION
    {
        char    x, y;
    
        LOCATION (void)    {}
        LOCATION (char xx, char yy) : x(xx), y(yy) {}
        LOCATION operator+ (LOCATION loc)   { return LOCATION(x + loc.x, y + loc.y); }
        LOCATION operator- (LOCATION loc)   { return LOCATION(x - loc.x, y - loc.y); }
        LOCATION operator+= (LOCATION loc)  { x += loc.x; y += loc.y; return *this; }
        LOCATION operator-= (LOCATION loc)  { x -= loc.x; y -= loc.y; return *this; }
    };
    

inline int GetScore ();

  • It gives the current score.

inline int GetCurCol ();

  • It gives the colour of the current falling brick.
  • The return value is 1 ~ colors which is the third parameter of constructor.

inline int GetNextCol ();

  • It gives the colour of the next waiting brick.
  • The return value is 1 ~ colors which is the third parameter of constructor.

inline int GetLoopStep ();

  • It gives the current loop step.
  • The return value is one of QUADRIS_LOOPNEW, QUADRIS_LOOPFALL, QUADRIS_LOOPUPDATE, QUADRIS_LOOPCLEAR, QUADRIS_LOOPPURGE, and QUADRIS_LOOPEND.

inline BLOCK* GetCurBrick ();

  • It gives the set of four blocks of the current falling brick.
  • The return value is the array which has four elements of struct BLOCK. the struct BLOCK is as follows:
  • typedef LOCATION    BLOCK;
    

inline BLOCK* GetNextBrick ();

  • It gives the set of four blocks of the next waiting brick.
  • The return value is the array which has four elements of struct BLOCK.

void InitGame (void);

  • It initializes all the variables and initiates the Quadris game.

bool RotateBrick (bool bClockwise = true);

  • It rotate the current brick.
  • The parameter bClockwise determines the rotation direction. If bClockwise is true, it rotates clockwise. If bClockwise is false, it rotates counterclockwise.
  • The return value is true if the brick rotated while the return value is false if the brick did not rotate.

bool ShiftLeft (void);

  • It moves the brick left.
  • The return value is true if the brick moved left while the return value is false if the brick did not move left.

bool ShiftRight (void);

  • It moves the brick right.
  • The return value is true if the brick moved right while the return value is false if the brick did not move right.

bool ShiftDown (void);

  • It moves the brick right.
  • The return value is true if the brick moved down while the return value is false if the brick did not move down. If the return value is false, it means that the brick landed.

void PullDown (void);

  • It drop the brick down quickly.

bool Shuffle (void);

  • It moves the stacked bricks left or right.
  • The return value is true if it moved. The return value is false if it did not move.

int Loop ();

  • It makes the Quadris go by one step.
  • The return value is the next step status. It is one of QUADRIS_LOOPNEW, QUADRIS_LOOPFALL, QUADRIS_LOOPUPDATE, QUADRIS_LOOPCLEAR, QUADRIS_LOOPPURGE, and QUADRIS_LOOPEND.

How to Support Win95, Win98, Win98SE and WinME

If this project is compiled with the setting of UNICODE characterset, it will not work under Win95, Win98, Win98SE and WinME. For future expandability, however, it is better compiled with the setting of a UNICODE characterset. Then, how can we get the benefit of UNICODE and support old versions of Windows? We can use Microsoft Layer for Unicode on Windows 95/98/Me Systems. You can download MSLU from here if the site is not changed. To use MSLU, you need to link unicows.lib to your project by clicking project > properties > configuration properties > linker > input > additional dependencies and writing "unicows.lib". Of course, unicows.dll should be in the same folder of NuraQuadris.exe when NuraQuadris.exe is executed under an old version of windows. Finally, you need also to include ForWin98.c in your project or just insert the following statement in stdafx.cpp.

#include "ForWin98.c"

How to Embed a Help Function

I used HTML help. You can download the HTML help 1.4 SDK here if the site is not changed. You need to link htmlhelp.lib to your project by by clicking project > properties > configuration properties > linker > input > additional dependencies and writing "htmlhelp.lib". Of course, you need to make compiled HTML help file such as Quadris.chm beforehand and put it in the same folder of NuraQuadris.exe. I would not explain how to make compiled HTML help file here but you can learn it from htmlhelp.chm which will be included in the file you will download here if the site is not changed. The following source shows how to use function HtmlHelp(...) as an example. Don't forget include htmlhelp.h as follows.

C++
#include <htmlhelp.h>

    ...

LRESULT CQuadrisWTLView::OnHelp (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
//  LPHELPINFO lpHelpInfo = (LPHELPINFO) lParam;

    HWND    help = HtmlHelp(m_hWnd, m_strHelp, HH_DISPLAY_TOPIC, NULL);
 
    if (!help)
        help = HtmlHelp(m_hWnd, m_strHelpDef, HH_DISPLAY_TOPIC, NULL);
 
    if (help)
        CWindow(help).CenterWindow(m_hWnd);
    else
        OnAppAbout();
    return TRUE;
}

Points of Interest

VC++ 8.0X and VC++ 9.0X use ATL 3.0, while VC++ 7.1 uses ATL 7.1. Although both use the same WTL 8.0, the source for VC++ 7.1 is not compatible with VC++ 8.0X. So, in order to make it able to be compiled with VC++ 8.0X or VC++ 9.0X, though it was developed with VC++ 7.1 (ATL 7.1), I made ATLVersion.h and included it in stdafx.h. ATLVersion.h is the same file as that of Nura Tritris. In this project, ATLVersion.h works very well, but I do not think that it works for all the projects written for VC++ 7.1 to be able to be compiled with VC++ 8.0X and VC++ 9.0X very well. If there is anyone who is interested in downward compatibility of ATL, I want to encourage him or her to improve ATLVersion.h.

I also made ATLWinPlus.hpp and ATLCrackPlus.hpp to improve the effeciency of message map. If you have a look at the sources of ATLWinPlus.hpp and ATLCrackPlus.hpp, you can easily understand them. If you can't trust ATLWinPlus.hpp and ATLCrackPlus.hpp, comment the statements of line 54 in stdafx.h in the folder QuadrisWTL, as follows:

//#define ATL_PLUS_MSG

Quadris Customizer

NuraQuadris2.gif

I would not explain the source code of this QuadrisCustomizer. Instead, I would introduce how to use this utility program. If you run this program and translate all the messages into your language in the corresponding edit windows and save it, you can get a NuraQuadris.ini. If you put it in the same folder in which NuraQuadris.exe exists, NuraQuadris.exe will use NuraQuadris.ini to make all messages in your language. Also, you can save as a different name such as NuraQuadrisRussian.ini. It would not work as itself for NuraQuadris.exe but you can keep it as a specific language pack for NuraQuadris.

Acknowledgement

I want to thank Michael Dunn for his excellent articles on WTL for MFC programmers. I learned a lot about WTL from his article. His articles can be found here. I want to also thank Sergey Solozhentsev for his great work on the WTL Helper and the WTL Wizards. You can get his WTL Helper here and here, and its manual here and here. Do not be confused. His WTL Wizards are different from the normal WTL App Wizard which can be installed with setup71.js, for instance. His WTL Wizards support a split window framework as well. You can also get his WTL Wizards here and its manual here. It provides me with a lot of convenience when I code using WTL. Most of all, I really appreciate God and my wife Nura. He gave me her, and she is always on my side and is my firm supporter.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Korea (Republic of) Korea (Republic of)
I like programming.
I am teaching at AUCA (American University of Central Asia) now.

Comments and Discussions

 
QuestionAre you able to do "What's This" HtmlHelp popups in a CFormView? Pin
Member 345539813-Nov-08 8:14
Member 345539813-Nov-08 8:14 
AnswerRe: Are you able to do "What's This" HtmlHelp popups in a CFormView? [modified] Pin
PARK Youngho13-Nov-08 22:04
PARK Youngho13-Nov-08 22:04 
GeneralGood work! Pin
wtwhite4-Mar-08 1:14
wtwhite4-Mar-08 1:14 
GeneralLet me get this right, Pin
fresi26-Feb-08 0:57
fresi26-Feb-08 0:57 
GeneralRe: Let me get this right, Pin
john wallis26-Feb-08 11:51
john wallis26-Feb-08 11:51 
JokeRe: Let me get this right, Pin
AspDotNetDev1-Sep-09 22:21
protectorAspDotNetDev1-Sep-09 22:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.