Author Topic: Simple hangman game  (Read 12455 times)

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Simple hangman game
« on: December 12, 2011, 08:43:37 AM »
This is a simple hangman game, nasmx version. Text labels have an annoying colorless defect, sorry. I cannot upload an icon, so, you can comment it from code. Sorry for inconvenients.

Code:
Code: [Select]
; ----------------------------------------------------------------------------
; -       TITULO  : Ejemplo de ventana en Windows W-NASM                     -
; -----                                                                  -----
; -       AUTOR   : Alfonso Víctor Caballero Hurtado                         -
; -----                                                                  -----
; -       VERSION : 1.0                                                      -
; -----                                                                  -----
; -      (c) 2010. Abre los Ojos al Ensamblador                              -
; ----------------------------------------------------------------------------

%include 'C:\Compila\NASMX\inc\nasmx.inc'              ; Incluímos
%include 'C:\Compila\NASMX\inc\win32\windows.inc'      ; Incluímos
%include 'C:\Compila\NASMX\inc\win32\kernel32.inc'     ; Importamos
%include 'C:\Compila\NASMX\inc\win32\user32.inc'       ; Importamos
%include 'C:\Compila\NASMX\inc\win32\gdi32.inc'        ; Importamos

cdWords        EQU  15          ; Número de palabras
cdXPos         EQU  28          ; Constante double X-Posición de la
cdYPos         EQU  100         ; Constante double Y-Posición de la ventana(esq sup izqda)
cdXSize        EQU  310         ; Constante double X-tamaño de la ventana
cdYSize        EQU  200         ; Constante double Y-tamaño de la ventana
cdColFondo     EQU  COLOR_BTNFACE + 1  ; Color de fondo de la ventana: gris de un botón de comando
cdVIcono       EQU  100         ; Icono de la ventana, véase Resource.H
cdVCursor      EQU  IDC_ARROW   ; Cursor para la ventana
cdVBarTipo     EQU  NULL        ; Normal, con icono
cdVBtnTipo     EQU  WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU    ; Normal sólo con botón cerrar
cdFXPos1       EQU  50
cdFYPos1       EQU  70
cdFXPos2       EQU  50
cdFYPos2       EQU  30
cdFSize        EQU  20          ; Tamaño del texto

entry Entrada

[section .text]
  proc    Entrada
    invoke   GetModuleHandleA, dword NULL
    mov      [wc + WNDCLASSEX.hInstance], eax
    INVOKE   GetCommandLineA
    mov      [CommandLine], EAX
    invoke   WinMain, dword wc + WNDCLASSEX.hInstance, dword NULL, dword CommandLine, dword SW_SHOWNORMAL
    invoke   ExitProcess, dword NULL
    ret
  endproc
 
  proc    WinMain
    ;  Propósito: Inicializamos la ventana principal de la aplicación y captura errores, si los hubiere
    ;  Entrada  : hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
    ;  Salida   : Ninguna
    ;  Destruye : Ninguna
    ; Recogemos los parámetros
    hinst    argd        ; Current instance handle - enganche a la instancia actual
    hpinst   argd        ; Previous instance handle- enganche a la instancia previa
    cmdln    argd        ; Command line arguments  - argumentos de la línea de comandos
    dwshow   argd        ; Display style           - Estilo de despliegue

    invoke   LoadIconA, dword NULL, dword cdVIcono
    mov      edx, eax
    mov      eax, dword argv(hinst)
    mov      ebx, dword NombreClase
    mov      ecx, dword WndProc
    MOV      [wc + WNDCLASSEX.hbrBackground], dword cdColFondo  ; Color de fondo de la ventana
    mov      [wc + WNDCLASSEX.hInstance], eax
    mov      [wc + WNDCLASSEX.lpszClassName], ebx
    mov      [wc + WNDCLASSEX.lpfnWndProc], ecx
    mov      [wc + WNDCLASSEX.hIcon], edx
    mov      [wc + WNDCLASSEX.hIconSm], edx

    invoke   LoadCursorA, NULL, cdVCursor
    mov      [wc + WNDCLASSEX.hCursor], eax

    invoke   RegisterClassExA, dword wc
    test     eax, eax
    jz       L_Error

   invoke    CreateWindowExA, dword cdVBarTipo, dword NombreClase, dword MsgCabecera, dword cdVBtnTipo,dword cdXPos, dword cdYPos, dword cdXSize, dword cdYSize, dword NULL, dword NULL, dword [wc + WNDCLASSEX.hInstance], dword NULL
    test     eax, eax
    jz       L_Error
    mov      [hWnd], eax

    invoke   ShowWindow, dword hWnd, dword SW_SHOWNORMAL
    invoke   UpdateWindow, dword hWnd

    .msgloop:
        invoke   GetMessageA, dword message, dword NULL, dword NULL, dword NULL
        cmp      eax, dword 0
        je       end_loop
        invoke   TranslateMessage, dword message
        invoke   DispatchMessageA, dword message
    jmp      .msgloop

    L_Error:
      invoke    MessageBoxA, DWORD NULL, DWORD MsgError, NULL, DWORD MB_ICONERROR+MB_OK

    end_loop:

    mov      eax, dword [message + MSG.wParam]
    ret
  endproc

  proc    WndProc
    ;  Propósito: Procesa los mensajes provenientes de las ventanas
    ;  Entrada  : hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    ;  Salida   : Ninguna
    ;  Destruye : Ninguna
    ; Recogemos los parámetros
    hwnd    argd        ; Window handle
    umsg    argd        ; Window message
    wparam  argd        ; wParam
    lparam  argd        ; lParam

    mov     eax, argv(umsg)
    cmp     eax, dword WM_PAINT
    je      .wmpaint
    cmp     eax, dword WM_DESTROY
    je      .wmdestroy
    cmp     eax, dword WM_CHAR
    je      .wmchar
    cmp     eax, dword WM_CREATE
    je      .wmcreate
   
    .defwndproc:
        invoke  DefWindowProcA,dword argv(hwnd), dword argv(umsg), dword argv(wparam), dword argv(lparam)
        jmp     .finish
    .wmpaint:
        invoke   BeginPaint,dword argv(hwnd), ps
        mov      [hdc], eax
        ; Aquí dibujamos la palabra a descubrir
        invoke   SetBkColor,[ps+PAINTSTRUCT.hdc],dword 0         ; Color de fondo
        invoke   SetTextColor,[ps+PAINTSTRUCT.hdc],0FFFFFFh   ; Color del texto
        invoke   SelectObject, [hdc], [hGuessNFont]
        mov      [hGuessOFont], eax
        invoke   lstrlenA, MsgTexto2
        invoke   TextOutA, [hdc], cdFXPos2,cdFYPos2, MsgTexto2, eax
        ; Aquí ponemos lo que nos queda
        invoke   SetBkColor,[ps+PAINTSTRUCT.hdc],011A3FBh    ; Color de fondo
        invoke   SetTextColor,[ps+PAINTSTRUCT.hdc],0FFh      ; Color del texto
        invoke   SelectObject, [hdc], [hAttemNFont]
        mov      [hAttemOFont], eax
        invoke   lstrlenA, msgIntentos
        invoke   TextOutA, [hdc], cdFXPos1,cdFYPos1, msgIntentos, eax
        invoke   EndPaint,dword argv(hwnd),ps
        ; Aquí comprobamos qué tal ha ido la cosa
        or        byte [vbQueda], 0              ; ¿Quedan intentos?
        jnz       .Aciertos
          invoke    MessageBoxA,dword argv(hwnd),msgLoose,msgCabecera,MB_YESNO+MB_ICONERROR
          CMP      EAX, IDNO   ; yes->eax=6, no->eax=7
          JNE      .repetir
            jmp      .wmdestroy
        .Aciertos:
        mov       al, [vbAciertos]         ; ¿Hemos acertado todas las letras?
        cmp       byte [vdLong], al
        jnz       .finish
          invoke    MessageBoxA,dword argv(hwnd),msgSuccess,msgCabecera,MB_YESNO+MB_ICONEXCLAMATION
          CMP      EAX, IDNO   ; yes->eax=6, no->eax=7
          JNE      .repetir
            jmp      .wmdestroy
        jmp     .finish
    .wmchar:
        push      dword argv(wparam)
        pop       eax
        and       al, 1011111b     ; Lo convertimos a mayúsculas
        mov       BYTE [vbLetra], al
        invoke    chkLetrasUsadas  ; Comprobamos que no la hayamos usado ya
        JZ        .YaUsada
          invoke    chkLetra
        .YaUsada:
        invoke    SetWindowTextA,[vwdIntentos], msgUsedKeys  ; Con esto cambiamos el texto
        invoke    InvalidateRect, dword argv(hwnd), dword 0, 1
        jmp     .finish
    .wmcreate:
        invoke    GetTickCount
        mov       [seed], eax
        invoke    MakeFont,cdFSize,szCourierNew
        mov       [hGuessNFont], eax
        invoke    MakeFont,14,szVerdana
        mov       [hAttemNFont], eax
        ; Creamos el label de los intentos que quedan
        invoke   CreateWindowExA,dword 0,szStatic,msgUsedKeys,\
                 WS_CHILD + WS_VISIBLE + SS_CENTER,35, 90, 190, 30,\
                 dword argv(hwnd),500,[wc + WNDCLASSEX.hInstance],dword 0
        mov      [vwdIntentos], eax
        invoke   SendMessageA,eax,WM_SETFONT,dword 0,0
        ; Creamos el label del autor
        invoke   CreateWindowExA,dword 0,szStatic,msgAutor,\
                 WS_CHILD + WS_VISIBLE + SS_CENTER,15,120, 270, 70,\
                 dword argv(hwnd),500,[wc + WNDCLASSEX.hInstance],dword 0
        mov      [vwdAutor], eax
        invoke   SendMessageA,eax,WM_SETFONT,dword 0,0
        invoke    Inicializa, dword argv(hwnd)
        jmp     .finish
    .repetir:
        invoke    Inicializa, dword argv(hwnd)
        jmp     .finish
    .wmdestroy:
        invoke    DeleteObject, [hGuessNFont]
        invoke    DeleteObject, [hGuessOFont]
        invoke    DeleteObject, [hAttemNFont]
        invoke    DeleteObject, [hAttemOFont]
        invoke    PostQuitMessage,dword NULL
        xor       eax,eax
    .finish:
    ret
  endproc

  proc MakeFont ;pSize, pFontName
    pSize     argd
    pFontName argd
    invoke    CreateFontA, dword argv(pSize),0,0,0, FW_BOLD, FALSE,FALSE,FALSE, \
              ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, \
              DEFAULT_QUALITY, 18, dword argv(pFontName)
    ret
  endproc

  chkLetrasUsadas:
    ; Propósito: Comprobamos si ya se ha usado una letra, se guarda en matriz de usadas
    ; Entrada  : vbLetra
    ; Salida   : ZF:1 -> ya fue usada, ZF:0 -> no fue usada
    mov      al, byte [vbLetra]
    cmp      byte [vbContLetras], 0
    jnz      .Siguiente
      ; Si aún no hemos pulsado una tecla, es que no la hemos usado
      mov      byte [vsmLetras], al      ; Lo guardamos en la matriz de las letras
      inc      byte [vbContLetras]
      ; Devolvemos ZF=0
      jmp      @Exit
    .Siguiente:
      ; Si ya hemos usado algunas letras, vamos a ver si son de las ya usadas
      xor       ecx, ecx
      mov       cl, byte [vbContLetras]
      mov       ebx, ecx
      mov       edi, vsmLetras
      repne     scasb
      jz        @Exit                     ; Si lo hubiéramos encontrado, saltaríamos
        ; Si estamos aquí es porque no lo hemos encontrado, lo incorporamos
        mov       byte [vsmLetras+ebx], al     ; Lo guardamos en la matriz de las letras
        inc       byte [vbContLetras]
        ; Devolvemos ZF=0
    @Exit:
  ret

  chkLetra:
    ; Propósito: Busca la letra pulsada en toda la palabra
    ; Entrada  : vbLetra, vpPalabra: puntero a la palabra, vdLong: longitud palabra
    ; Salida   : Ninguna
    mov       ecx, dword [vdLong]
    mov       edi, dword [vpPalabra]
    mov       al, byte [vbLetra]
    mov       ah, 0              ; Suponemos que no hemos encontrado ninguna ocurrencia
    @RepetirBusqueda:
      repne     scasb
      jne       @NoEncontrado
        ; Si estamos aquí es porque hemos encontrado la letra en la palabra
        mov       ebx, dword [vdLong]
        sub       ebx, ecx
        dec       ebx
        shl       ebx, 1
        mov       byte [MsgTexto2+ebx], al
        inc       byte [vbAciertos]
        mov       ah, 1          ; Hemos encontrado al menos una ocurrencia
        jnz       @RepetirBusqueda
    @NoEncontrado:
      cmp       ah, 1
      jz        @fin
        dec       byte [vbQueda]
        invoke    ActualizaIntentos
    @fin:
  ret

  setWord:
    ; Propósito: Escoge una palabra de la lista que deberemos adivinar
    ; Entrada  : Ninguna
    ; Salida   : esi -> apunta a la palabra a adivinar
    mov       eax, cdWords
    invoke    Random             ; eax
    inc       eax
    mov       edx, eax
    mov       ecx, cdLonMatriz
    mov       edi, Palabras
    mov       al, 0
    @Bucle:
      mov       esi, edi
      dec       edx
      jz        @FinBucle
      repne     scasb
    jmp       @Bucle
    @FinBucle:
    mov       dword [vpPalabra], esi
    invoke    lstrlenA, esi
    mov       dword [vdLong], eax
    .Fin:
  ret

  ActualizaIntentos:
    ; Propósito: Actualizamos los intentos en msgIntentos
    ; Entrada  : vbQueda
    ; Salida   : Ninguna
    mov       al, [vbQueda]
    or        al, 30h
    mov       byte [msgIntentos+9], al
  ret

  proc Inicializa ;pWnd
    ; Propósito: Inicializa el juego
    ; Entrada  : Ninguna
    ; Salida   : Ninguna
    pWnd      argd
    mov       byte [vbContLetras], 0
    mov       byte [vbAciertos], 0
    mov       edi, vsmLetras       ; Inicializa matriz de teclas usadas
    mov       eax, 20202020h
    mov       ecx, 4
    rep       stosd
    invoke    setWord
    invoke    setMsgTexto
    mov       eax, [vdLong]
    shr       eax, 1
    mov       [vbQueda], al
    invoke    ActualizaIntentos
    invoke    SetWindowTextA,[vwdIntentos], msgUsedKeys  ; Con esto cambiamos el texto
    invoke    InvalidateRect, dword argv(pWnd), dword 0, 1
    ret
  endproc

  setMsgTexto:
    ; Propósito: Establecemos MsgTexto
    ; Entrada  : vdLong -> longitud de la palabra a adivinar
    ; Salida   : ninguna
    push       ecx
    push       esi
    push       edi
    mov        esi, vsGuion
    mov        ecx, dword [vdLong]
    mov        edi, MsgTexto2
    rep        movsw
    dec        edi
    mov        al, 0
    stosb
    pop        edi
    pop        esi
    pop        ecx
  ret

  proc Random
    ;  Propósito: Calculamos un número aleatorio en [0..eax-1] by Park Miller
    ;  Entrada  : eax
    ;  Salida   : eax
    ;  Destruye : Ninguna
    mov        ebx, eax
    mov        eax, dword [seed]   ; from M32lib/nrand.asm
    xor        edx, edx
    mov        ecx, 127773
    div        ecx
    mov        ecx, eax
    mov        eax, 16807
    mul        edx
    mov        edx, ecx
    mov        ecx, eax
    mov        eax, 2836
    mul        edx
    sub        ecx, eax
    xor        edx, edx
    mov        eax, ecx
    mov        dword [seed], ecx
    div        ebx;[base]
    mov        eax, edx
    ret
  endproc

[section .bss]
  CommandLine   resd    1
  seed          resd    1                          ;2037280626
  vbContLetras  resb    1                          ; Contador de letras pulsadas
  vbAciertos    resb    1                          ; Contador de letras acertadas
  vbLetra       resb    1                          ; Letra pulsada
  vpPalabra     resd    1                          ; Puntero a la palabra a buscar
  vbQueda       resb    1                          ; Intentos que quedan
  hdc           resd    1
  hGuessNFont   resd    1
  hGuessOFont   resd    1
  hAttemNFont   resd    1
  hAttemOFont   resd    1
  vdLong        resd    1
  vwdIntentos   resd    1
  vwdAutor      resd    1
  hWnd          resd    1

[section .data]
  szStatic      db    'STATIC', 0
  MsgCabecera   db    'Hangman. 100% NASM(X) code',0
  NombreClase   db    'EXP01',0
  msgCabecera   db    'Information', 0
  msgSuccess    db    'You win. Play again?', 0
  msgLoose      db    'You loose. Play again?', 0
  MsgError      db    'Initial load failed.',0
  msgIntentos   db    'You have 0 attempts yet', 0
  msgAutor      db    '(c) Abre los Ojos al Ensamblador', 13, 10
                db    'http://www.abreojosensamblador.net', 0
  vsGuion       db    '_ '
  MsgTexto2     db    '                          ',0
  msgUsedKeys   db    'Used keys: '
  vsmLetras:    times 17  db 0    ; Matriz que recoge las letras pulsadas
  szCourierNew  DB    "Courier New",0
  szVerdana     DB    "Verdana",0
  Palabras      DB    "HELLO",     0, "FANTASTIC", 0, "ENCOURAGE", 0
                DB    "RECTANGLE", 0, "SMALL",     0, "SQUALL",    0
                DB    "PAUNCH",    0, "FLAUNT",    0, "ESCAPE",    0
                DB    "AWARE",     0, "GALORE",    0, "SPREAD",    0
                DB    "STRAIGHT",  0, "FRIGHT",    0, "ACUSE",     0
  cdLonMatriz   equ   $-Palabras
 
  ps:
    istruc PAINTSTRUCT
    iend
   
    wc:
    istruc WNDCLASSEX
        at WNDCLASSEX.cbSize,          dd    WNDCLASSEX_size
        at WNDCLASSEX.style,           dd    CS_VREDRAW + CS_HREDRAW
        at WNDCLASSEX.lpfnWndProc,     dd    NULL
        at WNDCLASSEX.cbClsExtra,      dd    NULL
        at WNDCLASSEX.cbWndExtra,      dd    NULL
        at WNDCLASSEX.hInstance,       dd    NULL
        at WNDCLASSEX.hIcon,           dd    NULL
        at WNDCLASSEX.hCursor,         dd    NULL
        at WNDCLASSEX.hbrBackground,   dd    cdColFondo
        at WNDCLASSEX.lpszMenuName,    dd    NULL
        at WNDCLASSEX.lpszClassName,   dd    NULL
        at WNDCLASSEX.hIconSm,         dd    NULL
    iend

    message:
    istruc MSG
        at MSG.hwnd,                   dd    NULL
        at MSG.message,                dd    NULL
        at MSG.wParam,                 dd    NULL
        at MSG.lParam,                 dd    NULL
        at MSG.time,                   dd    NULL
        at MSG.pt,                     dd    NULL
    iend

Resources:
Code: [Select]
#define IDR_VERSION1 1
#define MAIN_ICON 100
#define BUTTON_ICON 101
#define WINDOW_ICON 102

LANGUAGE 10,1

IDR_VERSION1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEOS 0x00000004
FILETYPE 0x00000000
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "FFFF0000"
    BEGIN
      VALUE "FileVersion", "1.0.0.0\0"
      VALUE "ProductVersion", "1.0.0.0\0"
      VALUE "CompanyName", "Abre los Ojos al Ensamblador\0"
      VALUE "FileDescription", "Simple Hangman Game\0"
      VALUE "InternalName", "HangWN01\0"
      VALUE "LegalCopyright", "All rights reserved\0"
      VALUE "OriginalFilename", "HangWN01.exe\0"
      VALUE "ProductName", "HangWN01\0"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0xFFFF, 0x0000
  END
END

MAIN_ICON ICON DISCARDABLE "../Ico/Lazo.ico"

Batch process to compile:
Code: [Select]
del HangWN01.exe
C:\Compila\NASMX\bin\nasm -f win32 HangWN01.ASM -o HangWN01.obj
C:\Compila\NASMX\bin\GoRC.exe /r=HangWN01.res HangWN01.rc
C:\Compila\NASMX\bin\GoLink.exe /entry _main HangWN01.obj HangWN01.res kernel32.dll user32.dll gdi32.dll
del *.obj
del *.bak


Greetings from Madrid.

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Simple hangman game
« Reply #1 on: December 12, 2011, 01:29:13 PM »
Excellent!  Now, a request: I notice you using the older syntax - can you rework it a bit using the latest NASMX release?   ( ie: using LOCALS/ENDLOCALS; removing ARGD and using proc parameters; and finally using things like PROTO and ptrdiff_t ).
Let me know if you have any troubles.
Thank you and keep up the good work!  8)

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Simple hangman game
« Reply #2 on: December 12, 2011, 04:27:23 PM »
Thank you, Rob. Interesting exercise   ::). Well, I hope this will be ok:

Code:
Code: [Select]
; ----------------------------------------------------------------------------
; -       TITULO  : Ejemplo de ventana en Windows W-NASM(X) v1.0             -
; -----                                                                  -----
; -       AUTOR   : Alfonso Víctor Caballero Hurtado                         -
; -----                                                                  -----
; -       VERSION : 1.0                                                      -
; -----                                                                  -----
; -      (c) 2010. Abre los Ojos al Ensamblador                              -
; ----------------------------------------------------------------------------

%include 'windemos.inc'

cdWords        EQU  15          ; Número de palabras
cdXPos         EQU  28          ; Constante double X-Posición de la
cdYPos         EQU  100         ; Constante double Y-Posición de la ventana(esq sup izqda)
cdXSize        EQU  310         ; Constante double X-tamaño de la ventana
cdYSize        EQU  200         ; Constante double Y-tamaño de la ventana
cdColFondo     EQU  COLOR_BTNFACE + 1  ; Color de fondo de la ventana: gris de un botón de comando
cdVIcono       EQU  100         ; Icono de la ventana, véase Resource.H
cdVCursor      EQU  IDC_ARROW   ; Cursor para la ventana
cdVBarTipo     EQU  NULL        ; Normal, con icono
cdVBtnTipo     EQU  WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU    ; Normal sólo con botón cerrar
cdFXPos1       EQU  50
cdFYPos1       EQU  70
cdFXPos2       EQU  50
cdFYPos2       EQU  30
cdFSize        EQU  20          ; Tamaño del texto

entry Entrada

  proto WinMain, ptrdiff_t hinst, ptrdiff_t hpinst, ptrdiff_t cmdln, dword dwshow
  proto WndProc, ptrdiff_t hwnd, size_t umsg, size_t wparam, size_t lparam
  proto MakeFont, ptrdiff_t pSize, ptrdiff_t pFontName
  proto chkLetra
  proto setWord
  proto ActualizaIntentos
  proto Inicializa, ptrdiff_t pWnd
  proto setMsgTexto
  proto Random

[section .code]
  proc    Entrada, ptrdiff_t argcount, ptrdiff_t cmdline
    locals   none
    invoke   GetModuleHandleA, dword NULL
    mov      ptrdiff_t [wc + WNDCLASSEX.hInstance], eax
    INVOKE   GetCommandLineA
    mov      [CommandLine], EAX
    invoke   WinMain, dword wc + WNDCLASSEX.hInstance, dword NULL, dword CommandLine, dword SW_SHOWNORMAL
    invoke   ExitProcess, dword NULL
    ret
  endproc
 
  proc    WinMain, ptrdiff_t hinst, ptrdiff_t hpinst, ptrdiff_t cmdln, dword dwshow
    ;  Propósito: Inicializamos la ventana principal de la aplicación y captura errores, si los hubiere
    ;  Entrada  : hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
    ;  Salida   : Ninguna
    ;  Destruye : Ninguna
    locals  none

    invoke   LoadIcon, dword NULL, dword cdVIcono
    mov      edx, eax
    mov      eax, ptrdiff_t [argv(.hinst)]
    mov      ebx, dword NombreClase
    mov      ecx, dword WndProc
    MOV      ptrdiff_t [wc + WNDCLASSEX.hbrBackground], dword cdColFondo  ; Color de fondo de la ventana
    mov      ptrdiff_t [wc + WNDCLASSEX.hInstance], eax
    mov      ptrdiff_t [wc + WNDCLASSEX.lpszClassName], ebx
    mov      ptrdiff_t [wc + WNDCLASSEX.lpfnWndProc], ecx
    mov      ptrdiff_t [wc + WNDCLASSEX.hIcon], edx
    mov      ptrdiff_t [wc + WNDCLASSEX.hIconSm], edx

    ; invoke   LoadCursor, NULL, cdVCursor
    ; mov      ptrdiff_t [wc + WNDCLASSEX.hCursor], eax

    invoke   RegisterClassEx, dword wc
    test     eax, eax
    jz       L_Error

   invoke    CreateWindowEx, dword cdVBarTipo, dword NombreClase, dword MsgCabecera, dword cdVBtnTipo,dword cdXPos, dword cdYPos, dword cdXSize, dword cdYSize, dword NULL, dword NULL, ptrdiff_t  [wc + WNDCLASSEX.hInstance], dword NULL
    test     eax, eax
    jz       L_Error
    mov      [hWnd], eax

    invoke   ShowWindow, dword hWnd, dword [argv(.dwshow)]
    invoke   UpdateWindow, dword hWnd

    .msgloop:
        invoke   GetMessage, dword message, dword NULL, dword NULL, dword NULL
        cmp      eax, dword 0
        je       end_loop
        invoke   TranslateMessage, dword message
        invoke   DispatchMessage, dword message
    jmp      .msgloop

    L_Error:
      invoke    MessageBox, DWORD NULL, DWORD MsgError, NULL, DWORD MB_ICONERROR+MB_OK

    end_loop:

    mov      eax, dword [message + MSG.wParam]
    ret
  endproc

  proc    WndProc, ptrdiff_t hwnd, size_t umsg, size_t wparam, size_t lparam
    ;  Propósito: Procesa los mensajes provenientes de las ventanas
    ;  Entrada  : hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    ;  Salida   : Ninguna
    ;  Destruye : Ninguna
    locals  none

    mov     eax, size_t [argv(.umsg)]
    cmp     eax, dword WM_PAINT
    je      .wmpaint
    cmp     eax, dword WM_DESTROY
    je      .wmdestroy
    cmp     eax, dword WM_CHAR
    je      .wmchar
    cmp     eax, dword WM_CREATE
    je      .wmcreate
   
    .defwndproc:
        invoke  DefWindowProc,size_t [argv(.hwnd)], size_t [argv(.umsg)], size_t [argv(.wparam)], size_t [argv(.lparam)]
        jmp     .finish
    .wmpaint:
        invoke   BeginPaint,size_t [argv(.hwnd)], ps
        mov      [hdc], eax
        ; Aquí dibujamos la palabra a descubrir
        invoke   SetBkColor,ptrdiff_t [ps+PAINTSTRUCT.hdc],dword 0         ; Color de fondo
        invoke   SetTextColor,ptrdiff_t [ps+PAINTSTRUCT.hdc],0FFFFFFh   ; Color del texto
        invoke   SelectObject, [hdc], [hGuessNFont]
        mov      [hGuessOFont], eax
        invoke   lstrlenA, MsgTexto2
        invoke   TextOutA, [hdc], cdFXPos2,cdFYPos2, MsgTexto2, eax
        ; Aquí ponemos lo que nos queda
        invoke   SetBkColor,ptrdiff_t [ps+PAINTSTRUCT.hdc],011A3FBh    ; Color de fondo
        invoke   SetTextColor,ptrdiff_t [ps+PAINTSTRUCT.hdc],0FFh      ; Color del texto
        invoke   SelectObject, [hdc], [hAttemNFont]
        mov      [hAttemOFont], eax
        invoke   lstrlenA, msgIntentos
        invoke   TextOutA, [hdc], cdFXPos1,cdFYPos1, msgIntentos, eax
        invoke   EndPaint, size_t [argv(.hwnd)],ps
        ; Aquí comprobamos qué tal ha ido la cosa
        or        byte [vbQueda], 0              ; ¿Quedan intentos?
        jnz       .Aciertos
          invoke    MessageBox,size_t [argv(.hwnd)],msgLoose,msgCabecera,MB_YESNO+MB_ICONERROR
          CMP      EAX, IDNO   ; yes->eax=6, no->eax=7
          JNE      .repetir
            jmp      .wmdestroy
        .Aciertos:
        mov       al, [vbAciertos]         ; ¿Hemos acertado todas las letras?
        cmp       byte [vdLong], al
        jnz       .finish
          invoke    MessageBoxA,size_t [argv(.hwnd)],msgSuccess,msgCabecera,MB_YESNO+MB_ICONEXCLAMATION
          CMP      EAX, IDNO   ; yes->eax=6, no->eax=7
          JNE      .repetir
            jmp      .wmdestroy
        jmp     .finish
    .wmchar:
        push      size_t [argv(.wparam)]
        pop       eax
        and       al, 1011111b     ; Lo convertimos a mayúsculas
        mov       BYTE [vbLetra], al
        invoke    chkLetrasUsadas  ; Comprobamos que no la hayamos usado ya
        JZ        .YaUsada
          invoke    chkLetra
        .YaUsada:
        invoke    SetWindowText,[vwdIntentos], msgUsedKeys  ; Con esto cambiamos el texto
        invoke    InvalidateRect, size_t [argv(.hwnd)], dword 0, 1
        jmp     .finish
    .wmcreate:
        invoke    GetTickCount
        mov       [seed], eax
        invoke    MakeFont,cdFSize,szCourierNew
        mov       [hGuessNFont], eax
        invoke    MakeFont,14,szVerdana
        mov       [hAttemNFont], eax
        ; Creamos el label de los intentos que quedan
        invoke   CreateWindowEx,dword 0,szStatic,msgUsedKeys,\
                 WS_CHILD + WS_VISIBLE + SS_CENTER,35, 90, 190, 30,\
                 size_t [argv(.hwnd)],500,ptrdiff_t [wc + WNDCLASSEX.hInstance],dword 0
        mov      [vwdIntentos], eax
        invoke   SendMessage,eax,WM_SETFONT,dword 0,0
        ; Creamos el label del autor
        invoke   CreateWindowEx,dword 0,szStatic,msgAutor,\
                 WS_CHILD + WS_VISIBLE + SS_CENTER,15,120, 270, 70,\
                 size_t [argv(.hwnd)],500,ptrdiff_t [wc + WNDCLASSEX.hInstance],dword 0
        mov      [vwdAutor], eax
        invoke   SendMessage,eax,WM_SETFONT,dword 0,0
        invoke    Inicializa, size_t [argv(.hwnd)]
        jmp     .finish
    .repetir:
        invoke    Inicializa, size_t [argv(.hwnd)]
        jmp     .finish
    .wmdestroy:
        invoke    DeleteObject, [hGuessNFont]
        invoke    DeleteObject, [hGuessOFont]
        invoke    DeleteObject, [hAttemNFont]
        invoke    DeleteObject, [hAttemOFont]
        invoke    PostQuitMessage,dword NULL
        xor       eax,eax
    .finish:
    ret
  endproc

  proc MakeFont, ptrdiff_t pSize, ptrdiff_t pFontName
    ; Propósito: crea fuente
    locals  none
    invoke    CreateFont, size_t [argv(.pSize)],0,0,0, FW_BOLD, FALSE,FALSE,FALSE, \
              ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, \
              DEFAULT_QUALITY, 18, size_t [argv(.pFontName)]
    ret
  endproc

  chkLetrasUsadas:
    ; Propósito: Comprobamos si ya se ha usado una letra, se guarda en matriz de usadas
    ; Entrada  : vbLetra
    ; Salida   : ZF:1 -> ya fue usada, ZF:0 -> no fue usada
    mov      al, byte [vbLetra]
    cmp      byte [vbContLetras], 0
    jnz      .Siguiente
      ; Si aún no hemos pulsado una tecla, es que no la hemos usado
      mov      byte [vsmLetras], al      ; Lo guardamos en la matriz de las letras
      inc      byte [vbContLetras]
      ; Devolvemos ZF=0
      jmp      @Exit
    .Siguiente:
      ; Si ya hemos usado algunas letras, vamos a ver si son de las ya usadas
      xor       ecx, ecx
      mov       cl, byte [vbContLetras]
      mov       ebx, ecx
      mov       edi, vsmLetras
      repne     scasb
      jz        @Exit                     ; Si lo hubiéramos encontrado, saltaríamos
        ; Si estamos aquí es porque no lo hemos encontrado, lo incorporamos
        mov       byte [vsmLetras+ebx], al     ; Lo guardamos en la matriz de las letras
        inc       byte [vbContLetras]
        ; Devolvemos ZF=0
    @Exit:
  ret

  proc chkLetra
    ; Propósito: Busca la letra pulsada en toda la palabra
    ; Entrada  : vbLetra, vpPalabra: puntero a la palabra, vdLong: longitud palabra
    ; Salida   : Ninguna
    locals    none
    mov       ecx, dword [vdLong]
    mov       edi, dword [vpPalabra]
    mov       al, byte [vbLetra]
    mov       ah, 0              ; Suponemos que no hemos encontrado ninguna ocurrencia
    @RepetirBusqueda:
      repne     scasb
      jne       @NoEncontrado
        ; Si estamos aquí es porque hemos encontrado la letra en la palabra
        mov       ebx, dword [vdLong]
        sub       ebx, ecx
        dec       ebx
        shl       ebx, 1
        mov       byte [MsgTexto2+ebx], al
        inc       byte [vbAciertos]
        mov       ah, 1          ; Hemos encontrado al menos una ocurrencia
        jnz       @RepetirBusqueda
    @NoEncontrado:
      cmp       ah, 1
      jz        @fin
        dec       byte [vbQueda]
        invoke    ActualizaIntentos
    @fin:
    ret
  endproc

  proc setWord
    ; Propósito: Escoge una palabra de la lista que deberemos adivinar
    ; Entrada  : Ninguna
    ; Salida   : esi -> apunta a la palabra a adivinar
    locals    none
    mov       eax, cdWords
    invoke    Random             ; eax
    inc       eax
    mov       edx, eax
    mov       ecx, cdLonMatriz
    mov       edi, Palabras
    mov       al, 0
    @Bucle:
      mov       esi, edi
      dec       edx
      jz        @FinBucle
      repne     scasb
    jmp       @Bucle
    @FinBucle:
    mov       dword [vpPalabra], esi
    invoke    lstrlenA, esi
    mov       dword [vdLong], eax
    .Fin:
    ret
  endproc

  proc ActualizaIntentos
    ; Propósito: Actualizamos los intentos en msgIntentos
    ; Entrada  : vbQueda
    ; Salida   : Ninguna
    locals    none
    mov       al, [vbQueda]
    or        al, 30h
    mov       byte [msgIntentos+9], al
    ret
  endproc

  proc Inicializa, ptrdiff_t pWnd
    ; Propósito: Inicializa el juego
    ; Entrada  : Ninguna
    ; Salida   : Ninguna
    locals    none
    mov       byte [vbContLetras], 0
    mov       byte [vbAciertos], 0
    mov       edi, vsmLetras       ; Inicializa matriz de teclas usadas
    mov       eax, 20202020h
    mov       ecx, 4
    rep       stosd
    invoke    setWord
    invoke    setMsgTexto
    mov       eax, [vdLong]
    shr       eax, 1
    mov       [vbQueda], al
    invoke    ActualizaIntentos
    invoke    SetWindowTextA,[vwdIntentos], msgUsedKeys  ; Con esto cambiamos el texto
    invoke    InvalidateRect, size_t [argv(.pWnd)], dword 0, 1
    ret
  endproc

  proc setMsgTexto
    ; Propósito: Establecemos MsgTexto
    ; Entrada  : vdLong -> longitud de la palabra a adivinar
    ; Salida   : ninguna
    locals     none
    push       ecx
    push       esi
    push       edi
    mov        esi, vsGuion
    mov        ecx, dword [vdLong]
    mov        edi, MsgTexto2
    rep        movsw
    dec        edi
    mov        al, 0
    stosb
    pop        edi
    pop        esi
    pop        ecx
    ret
  endproc

  proc Random
    ;  Propósito: Calculamos un número aleatorio en [0..eax-1] by Park Miller
    ;  Entrada  : eax
    ;  Salida   : eax
    ;  Destruye : Ninguna
    locals     none
    mov        ebx, eax
    mov        eax, dword [seed]   ; from M32lib/nrand.asm
    xor        edx, edx
    mov        ecx, 127773
    div        ecx
    mov        ecx, eax
    mov        eax, 16807
    mul        edx
    mov        edx, ecx
    mov        ecx, eax
    mov        eax, 2836
    mul        edx
    sub        ecx, eax
    xor        edx, edx
    mov        eax, ecx
    mov        dword [seed], ecx
    div        ebx;[base]
    mov        eax, edx
    ret
  endproc

[section .bss]
  CommandLine:   reserve(ptrdiff_t)  1
  seed:          reserve(ptrdiff_t)  1          ;2037280626
  vbContLetras:  reserve(ptrdiff_t)  1          ; Contador de letras pulsadas
  vbAciertos:    reserve(ptrdiff_t)  1          ; Contador de letras acertadas
  vbLetra:       reserve(ptrdiff_t)  1          ; Letra pulsada
  vpPalabra:     reserve(ptrdiff_t)  1          ; Puntero a la palabra a buscar
  vbQueda:       reserve(ptrdiff_t)  1          ; Intentos que quedan
  hdc:           reserve(ptrdiff_t)  1
  hGuessNFont:   reserve(ptrdiff_t)  1
  hGuessOFont:   reserve(ptrdiff_t)  1
  hAttemNFont:   reserve(ptrdiff_t)  1
  hAttemOFont:   reserve(ptrdiff_t)  1
  vdLong:        reserve(ptrdiff_t)  1
  vwdIntentos:   reserve(ptrdiff_t)  1
  vwdAutor:      reserve(ptrdiff_t)  1
  hWnd:          reserve(ptrdiff_t)  1

[section .data]
  szStatic:     declare(NASMX_TCHAR) NASMX_TEXT("STATIC"), 0
  MsgCabecera:  declare(NASMX_TCHAR) NASMX_TEXT("Hangman. 100% NASM(X) code"),0
  NombreClase:  declare(NASMX_TCHAR) NASMX_TEXT("EXP01"),0
  msgCabecera:  declare(NASMX_TCHAR) NASMX_TEXT("Information"), 0
  msgSuccess:   declare(NASMX_TCHAR) NASMX_TEXT("You win. Play again?"), 0
  msgLoose:     declare(NASMX_TCHAR) NASMX_TEXT("You loose. Play again?"), 0
  MsgError:     declare(NASMX_TCHAR) NASMX_TEXT("Initial load failed."),0
  msgIntentos:  declare(NASMX_TCHAR) NASMX_TEXT("You have 0 attempts yet"), 0
  msgAutor:     declare(NASMX_TCHAR) NASMX_TEXT("(c) Abre los Ojos al Ensamblador"), 13, 10
                declare(NASMX_TCHAR) NASMX_TEXT("http://www.abreojosensamblador.net"), 0
  vsGuion:      declare(NASMX_TCHAR) NASMX_TEXT("_ ")
  MsgTexto2:    declare(NASMX_TCHAR) NASMX_TEXT("                          "),0
  msgUsedKeys:  declare(NASMX_TCHAR) NASMX_TEXT("Used keys: ")
  vsmLetras:    times 17  db 0    ; Matriz que recoge las letras pulsadas
  szCourierNew: declare(NASMX_TCHAR) NASMX_TEXT("Courier New"),0
  szVerdana:    declare(NASMX_TCHAR) NASMX_TEXT("Verdana"),0
  Palabras      DB    "HELLO",     0, "FANTASTIC", 0, "ENCOURAGE", 0
                DB    "RECTANGLE", 0, "SMALL",     0, "SQUALL",    0
                DB    "PAUNCH",    0, "FLAUNT",    0, "ESCAPE",    0
                DB    "AWARE",     0, "GALORE",    0, "SPREAD",    0
                DB    "STRAIGHT",  0, "FRIGHT",    0, "ACUSE",     0
  cdLonMatriz   equ   $-Palabras
 
  NASMX_ISTRUC ps, PAINTSTRUCT
      NASMX_AT hdc,         NULL
      NASMX_AT fErase,      NULL
      NASMX_ISTRUC rcPaint, RECT
          NASMX_AT left,    NULL
          NASMX_AT top,     NULL
          NASMX_AT right,   NULL
          NASMX_AT bottom,  NULL
      NASMX_IENDSTRUC
      NASMX_AT fRestore,    NULL
      NASMX_AT fIncUpdate,  NULL
      NASMX_AT rgbReserved, NULL
  NASMX_IENDSTRUC
   
  NASMX_ISTRUC wc, WNDCLASSEX
      NASMX_AT cbSize,        sizeof(WNDCLASSEX)
      NASMX_AT style,         CS_VREDRAW + CS_HREDRAW
      NASMX_AT lpfnWndProc,   NULL
      NASMX_AT cbClsExtra,    NULL
      NASMX_AT cbWndExtra,    NULL
      NASMX_AT hInstance,     NULL
      NASMX_AT hIcon,         NULL
      NASMX_AT hCursor,       NULL
      NASMX_AT hbrBackground, COLOR_BTNFACE + 1
      NASMX_AT lpszMenuName,  NULL
      NASMX_AT lpszClassName, NULL
      NASMX_AT hIconSm,       NULL
  NASMX_IENDSTRUC

  NASMX_ISTRUC message, MSG
      NASMX_AT hwnd,     NULL
      NASMX_AT message,  NULL
      NASMX_AT wParam,   NULL
      NASMX_AT lParam,   NULL
      NASMX_AT time,     NULL
      NASMX_ISTRUC pt, POINT
          NASMX_AT x,       NULL
          NASMX_AT y,       NULL
      NASMX_IENDSTRUC
  NASMX_IENDSTRUC


Resources (maybe you want comment icon line):
Code: [Select]
#define IDR_VERSION1 1
#define MAIN_ICON 100
#define BUTTON_ICON 101
#define WINDOW_ICON 102

LANGUAGE 10,1

IDR_VERSION1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEOS 0x00000004
FILETYPE 0x00000000
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "FFFF0000"
    BEGIN
      VALUE "FileVersion", "1.0.0.0\0"
      VALUE "ProductVersion", "1.0.0.0\0"
      VALUE "CompanyName", "Abre los Ojos al Ensamblador\0"
      VALUE "FileDescription", "Simple Hangman Game\0"
      VALUE "InternalName", "HangWN01\0"
      VALUE "LegalCopyright", "All rights reserved\0"
      VALUE "OriginalFilename", "HangWN01.exe\0"
      VALUE "ProductName", "HangWN01\0"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0xFFFF, 0x0000
  END
END

MAIN_ICON ICON DISCARDABLE "../Ico/Lazo.ico"


Batch to compile code:
Code: [Select]
del HangWN01.exe
D:\Alfonso\Utiles\nasmx-1.0\bin\nasm -f win32 HangWN01.ASM -o HangWN01.obj
D:\Alfonso\Utiles\nasmx-1.0\bin\GoRC.exe /r=HangWN01.res HangWN01.rc
D:\Alfonso\Utiles\nasmx-1.0\bin\GoLink.exe /entry _main HangWN01.obj HangWN01.res kernel32.dll user32.dll gdi32.dll
del *.obj
del *.bak


Finally, you'll probably need this last file in order to achive compile. Beware with compiler paths...
Windemos.inc:

Code: [Select]
Code should go here, but an error has taked effect:
The following error or errors occurred while posting this message:
The message exceeds the maximum allowed length (20000 characters).

Regards

Offline avcaballero

  • Full Member
  • **
  • Posts: 132
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Simple hangman game
« Reply #3 on: December 12, 2011, 04:48:12 PM »
Excuse me, let's see if this works:

You should see if you have next lines in your windemos.inc:

Code: [Select]
%define DEFAULT_PITCH 0
%define PROOF_QUALITY 2
%define CLIP_DEFAULT_PRECIS 0
%define OUT_TT_PRECIS 4
%define DEFAULT_CHARSET 1
%define FF_DONTCARE 0
%define DEFAULT_QUALITY 0
%define OUT_DEFAULT_PRECIS 0
%define ANSI_CHARSET 0
%define FW_NORMAL 400
%define FW_BOLD 700
%define SRCCOPY 0CC0020h
%define BM_GETIMAGE 0F6h
%define BM_SETIMAGE 0F7h
%define WM_CHARTOITEM 2Fh
%define MB_YESNO 4h
%define WM_CHARTOITEM 2Fh
%define IDNO 7
%define WM_CHAR 102h
%define IDC_ARROW  32512
%define WS_DLGFRAME 400000h
%define WM_CLOSE 10h
%define WM_PAINT 0Fh
%define DT_CENTER 1
%define WM_SETFONT 30h
NASMX_STRUC PAINTSTRUCT
    NASMX_RESERVE hdc,         ptrdiff_t, 1
    NASMX_RESERVE fErase,      int32_t, 1
NASMX_STRUC rcPaint, RECT
NASMX_RESERVE left,    int32_t, 1
NASMX_RESERVE top,     int32_t, 1
NASMX_RESERVE right,   int32_t, 1
NASMX_RESERVE bottom,  int32_t, 1
NASMX_ENDSTRUC
    NASMX_RESERVE fRestore,    int32_t, 1
    NASMX_RESERVE fIncUpdate,  int32_t, 1
    NASMX_RESERVE rgbReserved, int8_t, 32
NASMX_ENDSTRUC

IMPORT LoadCursorA, 8
IMPORT GetCommandLineA, 0
IMPORT lstrlenA, 4
IMPORT GetTickCount, 0

IMPORT LoadBitmapA, 8
IMPORT LoadBitmapW, 8
IMPORT LoadCursorA, 8
%define LoadCursor LoadCursorA
IMPORT SetWindowTextA, 8
%define SetWindowText SetWindowTextA
IMPORT InvalidateRect, 12


;/////////////////////////////////////////////////////
;// GDI32.INC ANSI PROTOTYPES
;/////////////////////////////////////////////////////
IMPORT DeleteObject, 4
IMPORT CreateFontA, 56
%define CreateFont CreateFontA
IMPORT SetTextColor, 8
IMPORT SelectObject, 8
IMPORT ExtTextOutA, 32
IMPORT SetBkColor, 8
IMPORT TextOutA, 20
IMPORT CreateCompatibleDC, 4
IMPORT BitBlt, 36
IMPORT DeleteDC, 4

I guess this is all, only putting them in their respectives sections in order to be clear: user32, gdi32, etc.

Regards from Madrid.