>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 俄羅斯方塊 by Originality
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap : none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定義
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include rgame.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代碼段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 定時(shí)器測(cè)試
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DwonTest proc _hWnd, _uMsg, _idEvent, _dwTime

    pushad
 
    mov    eax, curState
    .if    eax        ;下落結(jié)束
     
        mov    curState, 0
        invoke    InitControl1
     
    .else
     
        invoke    Control1Down
     
    .endif
 
    popad
    ret

DwonTest endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口過程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain proc uses ebx edi esi hWnd, uMsg, wParam, lParam
    local    @stPs : PAINTSTRUCT
    local    @stRect : RECT
    local    @hDc

    mov    eax, uMsg
;********************************************************************
    .if    eax == WM_PAINT 
 
        invoke    BeginPaint, hWnd, addr @stPs
        invoke    InitContainer
        invoke    ShowControl, 1
        invoke    Control1Down
        invoke     EndPaint, hWnd, addr @stPs     

    .elseif    eax == WM_CREATE
         
        invoke    GetDC, hWnd
        mov    hGame, eax
        ;【此處定時(shí)器為測(cè)試所用】
        invoke    SetTimer, NULL, NULL, 1000, offset DwonTest

    .elseif    eax == WM_CLOSE
         
        invoke    ReleaseDC, hWnd, hGame
        invoke     DestroyWindow, hWinMain
        invoke     PostQuitMessage, NULL
         
    .elseif    eax == WM_SIZE
     
        invoke    ValidateRect, hWnd, offset gameArea

    .else
         
        invoke     DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
         
    .endif
;********************************************************************
        xor    eax, eax
        ret

_ProcWinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
    local    @stWndClass : WNDCLASSEX
    local    @stMsg : MSG

    invoke     GetModuleHandle, NULL            ;獲得應(yīng)用程序?qū)嵗?br>    mov    hInstance, eax                ;實(shí)例保存在全局變量中
    invoke     RtlZeroMemory, addr @stWndClass, sizeof @stWndClass    ;以0填充WNDCLASSEX結(jié)構(gòu)體

********************************************************************
; 注冊(cè)窗口類
;********************************************************************
    invoke     LoadCursor, 0, IDC_ARROW            ;獲取光標(biāo)句柄
    mov    @stWndClass.hCursor, eax            ;設(shè)置光標(biāo) 
    push    hInstance             
    pop    @stWndClass.hInstance            ;保存應(yīng)用程序?qū)嵗?br>    mov    @stWndClass.cbSize, sizeof WNDCLASSEX    ;保存結(jié)構(gòu)體大小
    mov    @stWndClass.style, CS_HREDRAW or CS_VREDRAW    ;設(shè)置窗體樣式
    mov    @stWndClass.lpfnWndProc, offset _ProcWinMain    ;保存回調(diào)函數(shù)
    mov    @stWndClass.hbrBackground, COLOR_WINDOW + 3    ;設(shè)置窗體背景色
    mov    @stWndClass.lpszClassName, offset szClassName    ;保存窗體類名
    invoke     RegisterClassEx, addr @stWndClass        ;注冊(cè)窗口類
;********************************************************************
; 建立并顯示窗口
;********************************************************************
    invoke     CreateWindowEx, WS_EX_TOOLWINDOW, offset szClassName, offset szCaptionMain,\
                   WS_OVERLAPPEDWINDOW,\
                   100, 100, 400, 456,\
                   NULL, NULL, hInstance, NULL            ;建立窗口
    mov    hWinMain, eax                    ;保存窗口句柄 
    invoke     ShowWindow, hWinMain, SW_SHOWNORMAL        ;顯示窗口
    invoke     UpdateWindow, hWinMain                ;更新窗口
;********************************************************************
; 消息循環(huán)
;********************************************************************
    .while    TRUE                        ;消息循環(huán)
         
        invoke     GetMessage, addr @stMsg, NULL, 0, 0        ;獲取消息并填充MSG結(jié)構(gòu)體
     
            .break .if    eax == 0                ;判斷是否退出
            invoke     TranslateMessage, addr @stMsg        ;消息裝換
            invoke     DispatchMessage, addr @stMsg        ;分發(fā)消息
         
        .endw
        ret

_WinMain endp

;********************************************************************
; 初始化游戲容器
;********************************************************************
InitContainer proc
    local @lpRect : RECT
 
    pushad
 
    ;建立游戲容器邊框
    invoke    CreatePen, PS_SOLID, 5, 8000FFh
    push    eax
    invoke    SelectObject, hGame, eax
    invoke    DeleteObject, eax
    pop    eax
    invoke    FrameRect, hGame, offset gameArea,  eax
 
    popad
    ret

InitContainer endp

;********************************************************************
; 顯示方塊控件
; type:控件類型1為4格橫條,2為田字形,3..4..
;********************************************************************
ShowControl proc cType : DWORD

    pushad
 
    .if    cType == 1    ;4格橫條■■■■
     
        invoke    InitControl1
     
    .endif
 
    popad
    ret
 
ShowControl endp

;********************************************************************
; 初始化■■■■圖形
;********************************************************************
InitControl1 proc

    pushad
 
    ;設(shè)置方塊顏色
    invoke    SetColor, 0FF80FFh, 400040h
    ;創(chuàng)建方塊并排列方塊
    mov    ecx, 60        ;左上角起始位置
    mov    edx, 90        ;右下角起始位置
    xor    esi, esi
    lea    ebx, curControl
@@:
    cmp    ecx, 180
    jz    @F        ;4個(gè)方塊都初始化完畢
    push    ebx
    push    ecx
    push    edx
    invoke    Rectangle, hGame, ecx, 5, edx, 30
    pop    edx
    pop    ecx
    pop    ebx
    mov    [ebx + esi], ecx
    push    topSpace
    pop    DWORD ptr [ebx + esi + 4]
    add    esi, 8
    add    ecx, 30
    add    edx, 30
    jmp    @B
 
@@:

    popad
    ret

InitControl1 endp

;********************************************************************
; 設(shè)置方塊顏色
;********************************************************************
SetColor proc color : DWORD, pColor : DWORD

    pushad
 
    invoke    CreatePen, PS_SOLID, 1, pColor
    invoke    SelectObject, hGame, eax
    invoke    DeleteObject, eax
    invoke    CreateSolidBrush, color
    invoke    SelectObject, hGame, eax
    invoke    DeleteObject, eax
 
    popad
    ret

SetColor endp

;********************************************************************
; ■■■■圖形向下走動(dòng)
;********************************************************************
Control1Down proc

    pushad
 
    invoke    IsDownEnd
    .if     eax == 1    ;下面有障礙,改變狀態(tài)為創(chuàng)建新的方塊并保存當(dāng)前方塊在容器中的位置
     
        mov    curState, 1
        invoke    ChangeAreaState
        invoke    RtlZeroMemory, offset curControl, sizeof curControl
        popad
        ret

    .endif 
 
    ;如果下面不是障礙,則■■■■向下走動(dòng)
    lea    edx, curControl
    xor    ecx, ecx
@@:
    cmp    ecx, 4
    jz    @F
    ;覆蓋原有的方塊
    push    ecx
    invoke    SetColor, 0h, 0h
    mov    eax, [edx + ecx * 8 + 4]
    mov    ebx, 30
    add    ebx, eax    ;ebx右下角y坐標(biāo)
    mov    eax, [edx + ecx * 8]
    add    eax, 30        ;eax為右下角x坐標(biāo)
    push    eax        ;保存右下角坐標(biāo)
    push    ebx
    push    edx
    invoke    Rectangle, hGame, [edx + ecx * 8], [edx + ecx * 8 + 4], eax, ebx
    pop    edx
 
    ;生成新的方塊
    invoke    SetColor, 0FF80FFh, 400040h
    pop    ebx
    pop    eax
    pop    ecx 
    add     DWORD ptr [edx + ecx * 8 + 4], 30
    add    ebx, 30
    push    ecx
    push    edx
    invoke    Rectangle, hGame, [edx + ecx * 8], [edx + ecx * 8 + 4], eax, ebx
    pop    edx
    pop    ecx
    inc    ecx
    jmp    @B
@@:
 
    popad
    ret

Control1Down endp

;********************************************************************
; 保存當(dāng)前方塊在容器中的狀態(tài)
;********************************************************************
ChangeAreaState proc
 
    pushad
 
    ;計(jì)算區(qū)域單元坐標(biāo)
    lea    ebx, curControl
    xor    ecx, ecx
@@:
    cmp    ecx, 4
    jz    @F
 
    ;計(jì)算二維x坐標(biāo)
    invoke    CalculatePos, [ebx + ecx * 8 ], [ebx + ecx * 8 + 4], 1
    mov    esi, eax
 
    ;計(jì)算二維y坐標(biāo)
    invoke    CalculatePos, [ebx + ecx * 8 ], [ebx + ecx * 8 + 4], 2
    mov    edi, eax
 
    ;設(shè)置區(qū)域更新,更新的坐標(biāo)位置(eax + esi * 4 * 8 + edi * 4)
    lea    eax, area
    push    eax
    xchg    edi, eax
    mov    edi, 8
    mul    edi
    add    esi, eax
    pop    eax
    mov    DWORD ptr [eax + esi * 4], 1    ;設(shè)置當(dāng)前位置已經(jīng)被填充
    inc    ecx
    jmp    @B
@@: 

    popad
    ret
 
ChangeAreaState endp

;********************************************************************
; 根據(jù)頂角計(jì)算二維坐標(biāo)
; left, top:頂角像素
; posType:1表示計(jì)算x坐標(biāo),2表示計(jì)算y坐標(biāo)
; eax返回二維坐標(biāo)
;********************************************************************
CalculatePos proc left : DWORD, top :DWORD, posType : DWORD
    local @ret : DWORD
    pushad
  
    mov    edx, left  
    add    edx, rectArea ;右下角x坐標(biāo)
  
    mov    ecx, top
    add    ecx, rectArea ;右下角y坐標(biāo)
  
    .if    posType == 1
      
        mov    eax, edx
        mov    ebx, 30
        xor    edx, edx
        div    ebx
      
    .elseif
      
        mov    eax, ecx
        sub    eax, topSpace
        mov    ecx, 30
        xor    edx, edx
        div    ecx
      
    .endif
    mov    @ret, eax
    popad
    mov    eax, @ret
    dec    eax
    ret

CalculatePos endp

;********************************************************************
; 判斷下面是否有障礙
; 返回值::eax為1表示下落完畢,為0表示未完畢
;********************************************************************
IsDownEnd proc

    pushad
  
    lea    ebx, curControl
    xor    ecx, ecx
@@:
    cmp    ecx, 4
    jz    @F
  
    ;計(jì)算二維x坐標(biāo)
    invoke    CalculatePos, [ebx + ecx * 8 ], [ebx + ecx * 8 + 4], 1
    mov    esi, eax
  
    ;計(jì)算二維y坐標(biāo)
    invoke    CalculatePos, [ebx + ecx * 8 ], [ebx + ecx * 8 + 4], 2
    mov    edi, eax
    inc    edi
  
    ;設(shè)置區(qū)域更新,更新的坐標(biāo)位置(eax + esi * 4 * 8 + edi * 4)
    lea    eax, area
    push    eax
    xchg    edi, eax
    mov    edi, 8
    mul    edi
    add    esi, eax
    pop    eax
    mov    edx, [eax + esi * 4]
    .if    edx == 1
      
        popad
        mov    eax, 1
        ret
      
    .endif
    inc    ecx
    jmp    @B
@@:  
  
    popad
    xor    eax, eax
    ret

IsDownEnd endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
    call    _WinMain
    invoke     ExitProcess, NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start