Juego Space Invader en asm

Iniciado por Meta, 4 Abril 2021, 10:25 AM

0 Miembros y 1 Visitante están viendo este tema.

Meta

Hola:

Quiero saber si este juego en asm se puede ejecutar en Visual studio bajo C++ nativo, ya que ejecutas asm también. Lo que no se hacerlo ya que no hago pruebas desde hace añazos.

¿Es posible ejecutarlo?



Código ASM.
Código (asm) [Seleccionar]
cXLimIzq       EQU  32                  ; X-Limite izquierda juego
  cXLimDer       EQU  320-cXLimIzq        ; X-Limite derecha juego
  cYLimSup       EQU  60                  ; Y-Limite superior juego
  cYLimInf       EQU  180                 ; Y-Limite inferior juego
  cIncYEDisp     EQU  1                   ; Y-incremento de los e-disparos
  cTamDefFig     EQU  7*2                 ; Los words que definen la figura
  cSepIniEDisp   EQU  4                   ; Separación inicial del disparo enemigo
  cColorEDisp    EQU  14                  ; Color del disparo enemigo
  cColorPDisp    EQU  7                   ; Color del disparo del jugador
  cFigAlto       EQU  7                   ; Altura de las figuras
  cFigAncho      EQU  16                  ; Anchura de las figuras
  cAncho         EQU  256                 ; Anchura de la pantalla de juego
  cAlto          EQU  cYLimInf-cYLimSup+1 ; Altura de la pantalla de juego
  cSepMargen     EQU  3                   ; Margen de separación con el borde
  cLinColor      EQU  6                   ; Color de la línea contenedora
  cFrecBomb      EQU  010h                ; Frecuencia con la que empiezan a caer bombas
  cNumEColumn    EQU  11                  ; Número de columnas de enemigos
  cNumEnemigos   EQU  5*cNumEColumn       ; Número de enemigos
  cDispEne       EQU  5                   ; Máximo num disparos x cada enemigo
  cNumDispEne    EQU  7;cDispEne*cNumEColumn; Máximo disparos activos enemigos
  cXESep         EQU  1                   ; X-separación entre enemigos
  cYESep         EQU  3                   ; Y-separación entre enemigos
  cXESup         EQU  (cAncho-((16+cXESep)*10+16))/2  ; X-inicial-superior enemigos
  cYESup         EQU  cYLimSup-cYLimSup   ; Y-superior enemigos
  cYPSup         EQU  cYLimInf-7-cYLimSup ; Y-superior player
  cXPIzq         EQU  0                   ; X-lim izquierda player
  cXPDcha        EQU  256-11              ; X-lim derecha player
  cTimePlayer    EQU  0                   ; Tiempo retardo movimiento player
  cTimeEnemigos  EQU  20                  ; Tiempo retardo movimiento enemigos
  cTimePDisp     EQU  0                   ; Tiempo retardo movimiento player-disparo
  cTimeEDisp     EQU  0                   ; Tiempo retardo movimiento enemigos-disparos
  cTimeESgteDisp EQU  10                  ; Tiempo retardo siguiente enemigos-disparos
  cChgTEnemigos  EQU  2                   ; Cada cuántos enemigos destruidos incrementan velocidad
  cFilasBaja     EQU  2                   ; Filas que bajan los enemigos cada vez
  cYTope         EQU  cYPSup-10           ; Tope superior que no pueden sobrepasar enemigos
  cSoyInmune     EQU  0                   ; 1-soy inmune, 0-no soy inmune
  cTAMTOT        EQU  1024*6              ; Este programa y su pila caben en 6Kb
  cnNotas        EQU  7+6+7+5

  TEnemigos   STRUC
    PosX    DW ?
    PosY    DW ?
    OldPosX DW ?
    Def     DW ?                          ; La dirección donde está definido
    Despl   DW ?                          ; El desplazamiento de offsets (+7?)
    Tipo    DB ?                          ; 1, 2, 3, 4, 5
    Color   DB ?
    Vida    DB ?
    Abajo   DB ?                          ; Sólo disparan los que estén abajo
  TEnemigos   ENDS

  TCabEDisp STRUC                         ; Estructura de la cabecera de los disparos enemigos
    DirDisp DW ?                          ; Dirección donde se encuentra el disparo
    Vida    DB ?                          ; ¿Está vivo?
  TCabEDisp ENDS

  TEDisparos   STRUC                      ; Disparos de los enemigos
    PosX    DW ?
    PosY    DW ?
    Def     DW ?                          ; Matriz de definición del disparo
    Despl   DW ?                          ;   junto con el desplazamiento de offsets (+7?)
    Color   DB ?
  TEDisparos   ENDS

  TPlayer   STRUC
    PosX    DW ?
    PosY    DW ?
    Def     DW ?                          ; La dirección donde está definido
    Color   DB ?
    Vida    DB ?
  TPlayer   ENDS

  TPDisparos   STRUC                      ; Disparos del jugador
    PosX    DW ?
    PosY    DW ?
    Def     DW ?
    Despl   DW ?                          ; El desplazamiento de offsets (+7?)
    Color   DB ?
    Vida    DB ?
  TPDisparos   ENDS

  TNota STRUC
    Frecuencia DW ?
    Duracion   DB ?
  TNota ENDS

  LTEnemigos   EQU SIZEOF TEnemigos
  LTEDisparos  EQU SIZEOF TEDisparos
  LTCabEDisp   EQU SIZEOF TCabEDisp
  LTPlayer     EQU SIZEOF TPlayer
  LTPDisparos  EQU SIZEOF TPDisparos
  LTNota       EQU SIZEOF TNota

  IF1
    INCLUDE ..\LIB\CtesGphM.inc           ; Constantes gráficas
    INCLUDE ..\LIB\GraphMM.inc            ; Incorporamos las macros gráficas
  ENDIF

codigo SEGMENT PARA PUBLIC 'CODE'         ; Abre el segmento de código
  ASSUME CS:codigo, DS:codigo, ES:codigo, SS:codigo
  ORG 100h                                ; COM -> comienza en 100h
  Entrada PROC                            ; Abre el procedimiento
    ; *** Reasigna memoria
    MOV         SP, cTAMTOT               ; La base de la pila
    MOV         AH, 4Ah
    MOV         BX, cTAMTOT/16            ; Lo pasamos a párrafos
    INT         21h                       ; Redimensionamos el bloque de memoria
    JNC         $_Bien1
      MOV        AH, 9
      MOV        DX, OFFSET msg1
      INT        21h
      JMP        $_Salimos
    $_Bien1:
    CALL        VGAColor                  ; Comprobamos si existe VGA en color
    ; Reserva memoria para el búfer pant1
    MOV         BX, (cXLimDer-cXLimIzq+1)*(cYLimInf-cYLimSup+1)/16+1 ; En párrafos
    CALL        ResMem
    MOV         WORD PTR [ScrSeg], AX
    SetMode     13h                       ; Ponemos el modo gráfico
    CALL        DibMarco
    CALL        SaveValSPK
    CALL        Randomize
    CALL        SaveOldInt9h
    CALL        SetNewInt9h
    CALL        SaveOldInt1Ch
    CALL        SetNewInt1Ch
    CALL        IniCabEDisp
    CALL        ResetNivel                ; Inicializamos el nivel del juego
    $_Nueva_Partida:
    CALL        IniElementos              ; Inicializa valores en función de variables y constantes
    $_Main:
      CALL        GetPShoot               ; ¿Hemos pulsado ctrl?
      CALL        GetEShoot               ; ¿Debe disparar un enemigo?
      CALL        SetMotion               ; Movemos las piezas si toca
      JNC         $_Next0
        ; Si STC = 1 significa que los enemigos han llegado al nivel inferior: ganaron
        CALL        ResetNivel            ; Inicializamos el nivel del juego
        CALL        WaitUntilCtrl         ; Esperamos hasta Ctrl pulsado
        JMP         $_Nueva_Partida
      $_Next0:
      CMP         BYTE PTR [NumEnemigos], 0
      JA          $_Next1
        CALL        incNivel              ; Incrementamos el nivel del juego
        JMP         $_Nueva_Partida
      $_Next1:
      CMP         BYTE PTR [Player.Vida], 0
      JA          $_Next2
        CALL        ResetNivel            ; Inicializamos el nivel del juego
        CALL        WaitUntilCtrl         ; Esperamos hasta Ctrl pulsado
        JMP         $_Nueva_Partida
      $_Next2:
      CALL        ClearBuffer             ; Limpiamos el búfer
      CALL        DibujaEnemigos          ; Dibujamos los enemigos en el búfer
      CALL        DibujaJugador           ; Dibujamos el jugador en el búfer
      CALL        DibujaPDisparo          ; Dibujamos el disparo del jugador en búfer
      CALL        DibujaEDisparo          ; Dibujamos los disparos de los enemigos en búfer
      CALL        CheckPDEDColision       ; ¿El disparo del jugador alcanzo al de algun enemigo?
      CALL        CheckMPDColision        ; ¿El disparo del jugador alcanzo algun enemigo?
      CALL        CheckMEDColision        ; ¿El disparo de los enemigos alcanzaron al jugador?
      WRetrace    8                       ; Esperamos al final del retrazo
      MOV         AX, WORD PTR [ScrSeg]   ; Segmento Origen
      MOV         BX, __VgaSeg            ; Segmento destino: mem vídeo
      CALL        Copy64K                 ; Vuelca búfer en mem vídeo
      CMP         BYTE PTR [Escape], 1
    JNZ         $_Main
    SetMode     3h                        ; Volvemos al modo texto
    CALL        RestoreOldInt1Ch
    CALL        RestoreOldInt9h
    CALL        TurnOffSpk
    MOV         AX, WORD PTR [ScrSeg]     ; Libera memoria pantalla
    CALL        LibMem
    $_Salimos:
    ; Salimos al DOS
    MOV      AX, 4C00h                    ; Servicio 4Ch, mensaje 0
    INT      21h                          ; volvemos AL DOS
  Entrada ENDP                            ; cierra el procedimiento

  IF1
    INCLUDE  ..\LIB\VGA_M.inc             ; Incorporamos procedimientos
    INCLUDE  ..\LIB\SpcM.inc              ; Incorporamos procedimientos
  ENDIF

  ; ****************

  TurnOffSpk PROC
    ;  Propósito: Apaga el altavoz
    ;  Entrada  : Ninguna
    ;  Salida   : Ninguna
    ;  Destruye : AX
    MOV      AL, BYTE PTR [vbSpeaker]
    AND      AL, 11111100b                ; Apagamos y descconectamos el altavoz del canal 2 del PIT
    OUT      61h, AL
    RET
  TurnOffSpk ENDP

  SaveValSPK PROC
    ;  Propósito: Guarda el valor original del puerto 61h
    ;  Entrada  : Ninguna
    ;  Salida   : Ninguna
    ;  Destruye : AX
    IN       AL, 61h
    AND      AL, 11111100b
    MOV      BYTE PTR [vbSpeaker], AL
    RET
  SaveValSPK ENDP
 
  Frec_Periodo PROC
    ;  Propósito: Convertimos la frecuencia en período
    ;  Entrada  : CX: frecuencia
    ;  Salida   : DX: período
    ;  Destruye : AX, DX
    MOV      DX, 12h
    MOV      AX, 34DCh
    DIV      CX
    MOV      DX, AX                       ; Lo guardamos en DX
    RET
  Frec_Periodo ENDP
 
  PIT_REG_COMM PROC
    ;  Propósito: Le indicamos al PIT lo que vamos a hacer
    ;  Entrada  : DX:periodo
    ;  Salida   : Ninguna
    ;  Destruye : AX
    MOV      AL, 0B6h
    OUT      43h, AL
    MOV      AL, DL                       ; Pasamos el byte bajo del contador
    OUT      42h, AL
    MOV      AL, DH                       ; Y ahora el alto
    OUT      42h, AL
    RET
  PIT_REG_COMM ENDP

  SpkOn PROC
    ;  Propósito: Encendemos el altavoz con duración determinada
    ;  Entrada  : Ninguna
    ;  Salida   : Ninguna
    ;  Destruye : AX
    MOV      AL, BYTE PTR CS:[vbSpeaker]
    OR       AL, 3
    OUT      61h, AL
    RET
  SpkOn ENDP

  SpkOff PROC
    ;  Propósito: Encendemos el altavoz con duración determinada
    ;  Entrada  : Ninguna
    ;  Salida   : Ninguna
    ;  Destruye : AX
    MOV      AL, BYTE PTR CS:[vbSpeaker]
    AND      AL, 11111100b
    OUT      61h, AL
    RET
  SpkOff ENDP

  Sonido PROC
    ;  Propósito: Toca una nota en el altavoz del PC a través del PIT
    ;  Entrada  : CX:frecuencia
    ;  Salida   : Ninguna
    ;  Destruye : Ninguna
    .IF      CX == 0
      CALL     SpkOff
    .ELSE
      CALL     Frec_Periodo
      CALL     PIT_REG_COMM
      CALL     SpkOn
    .ENDIF
    RET
  Sonido ENDP
 
  ResetNota PROC
    ; Propósito: Recogemos los valores de la nueva nota en MNota
    ; entrada  : KeyTable
    ; salida   : KeyTable
    ; Destruye : AX
    PUSH      AX
    PUSH      BX
    MOV       BX, WORD PTR CS:[vwActual]
    MOV       AX, WORD PTR CS:[Notas1+BX]
    MOV       WORD PTR CS:[MNota.Frecuencia], AX
    MOV       AX, WORD PTR CS:[Notas1+BX+2]
    MOV       BYTE PTR CS:[MNota.Duracion], AL
    POP       BX
    POP       AX
    RET
  ResetNota ENDP

  ; ****************

  SaveOldInt1Ch PROC NEAR
    ; Propósito: Guarda la dirección de la antigua ISR de Int 1Ch
    ; entrada  : OldInt1Ch
    ; salida   : Ninguna
    ; Destruye : AX
    MOV       AX, 351Ch                   ; Obtiene la dirección de la
    INT       21h                         ;     interrupción 1Ch
    MOV       WORD PTR OldInt1Ch[2],ES    ; Guarda segmento
    MOV       WORD PTR OldInt1Ch[0],BX    ;     y dirección
    RET
  SaveOldInt1Ch ENDP

  RestoreOldInt1Ch PROC NEAR
    ; Propósito: Restaura la dirección de la antigua ISR de Int 1Ch
    ; entrada  : OldInt1Ch
    ; salida   : Ninguna
    ; Destruye : AX, DX
    PUSH      DS                          ; Guardamos DS
    LDS       DX, OldInt1Ch               ; Carga la dirección original
    MOV       AX, 251Ch                   ; Lo restaura a la tabla de vectores
    INT       21h
    POP       DS
    RET
  RestoreOldInt1Ch ENDP

  SetNewInt1Ch PROC NEAR
    ; Propósito: Establece la dirección de la nueva ISR para Int 1Ch
    ; entrada  : NuevaInt1Ch
    ; salida   : Ninguna
    ; Destruye : AX, DX
    MOV       DX, OFFSET NuevaInt1Ch      ; Carga la dirección de nueva rutina
    MOV       AX, 251Ch                   ; Establece la nueva interrupción
    INT       21h
    RET
  SetNewInt1Ch ENDP

  NuevaInt1Ch PROC FAR
    ; Propósito: Nueva ISR para la INT 1Ch, crea un retardo
    ; entrada  : Ninguna
    ; salida   : Ninguna
    ; Destruye : Ninguna
    PUSHF
    PUSH      AX
    PUSH      BX
    PUSH      CX
    PUSH      DX
    PUSH      DS
    PUSH      ES
    .IF       BYTE PTR CS:[vbEjecutando] == 1
      ; Si está sonando la nota
      DEC       BYTE PTR CS:[MNota.Duracion]            ; Decrementamos la duración
      .IF       BYTE PTR CS:[MNota.Duracion] == 0
        ; Si ya ha terminado la duración de la nota
        ADD       WORD PTR CS:[vwActual], 4             ; Incrementamos puntero a notas
        CALL      ResetNota                             ; Recogemos nueva nota
        .IF       WORD PTR CS:[vwActual] >= cnNotas*4
          ; Si ya hemos terminado todas las notas
          MOV       BYTE PTR CS:[vbEjecutando], 0       ; Marcamos que no tocamos
          MOV       WORD PTR CS:[vwActual], 0           ; Reseteamos el puntero a notas
          CALL      TurnOffSpk
        .ELSE
          ; Si todavía no hemos terminado todas las notas
          MOV       CX, WORD PTR CS:[MNota.Frecuencia]
          CALL      Sonido
        .ENDIF
      .ENDIF
    .ELSE
      ; Si no está sonando ninguna nota
      .IF       BYTE PTR CS:[vbEjecutar] == 1
        ; Si debemos ejecutar las notas
        .IF       WORD PTR CS:[vwActual] == 0
          ; Si estamos al inicio, reseteamos
          CALL      ResetNota
        .ENDIF
        .IF       BYTE PTR CS:[MNota.Duracion] != 0
          ; Si todavía dura la nota, la tocamos
          MOV       BYTE PTR CS:[vbEjecutando], 1       ; Marcamos para tocar
          MOV       CX, WORD PTR CS:[MNota.Frecuencia]
          CALL      Sonido
        .ENDIF
      .ENDIF
    .ENDIF
    CMP       BYTE PTR CS:[TimePlayer], 0
    JZ        $_Next1
      DEC       BYTE PTR CS:[TimePlayer]      ; Decrementamos el contador de pulsos
    $_Next1:
    CMP       BYTE PTR CS:[TimeEnemigos], 0
    JZ        $_Next2
      DEC       BYTE PTR CS:[TimeEnemigos]      ; Decrementamos el contador de pulsos
    $_Next2:
    CMP       BYTE PTR CS:[TimePDisp], 0
    JZ        $_Next3
      DEC       BYTE PTR CS:[TimePDisp]      ; Decrementamos el contador de pulsos
    $_Next3:
    CMP       BYTE PTR CS:[TimeEDisp], 0
    JZ        $_Next4
      DEC       BYTE PTR CS:[TimeEDisp]      ; Decrementamos el contador de pulsos
    $_Next4:
      CMP       BYTE PTR CS:[TimeESgteDisp], 0
      JZ        $_GT_Next5
        DEC       BYTE PTR CS:[TimeESgteDisp]   ; Retardo para el siguiente disparo de los enemigos
      $_GT_Next5:
    POP       ES
    POP       DS
    POP       DX
    POP       CX
    POP       BX
    POP       AX
    POPF
    JMP       [CS:OldInt1Ch]              ; Saltamos a la vieja rutina
  NuevaInt1Ch  ENDP

TopInvader1             DW      0c00h,1e00h,2d00h,3f00h,1200h,2100h,1200h
;   0c00   0000110000000000
;   1e00   0001111000000000
;   2d00   0010110100000000
;   3f00   0011111100000000
;   1200   0001001000000000
;   2100   0010000100000000
;   1200   0001001000000000
TopInvader2             DW      0c00h,1e00h,2d00h,3f00h,1200h,2100h,4080h
;   0c00   0000110000000000
;   1e00   0001111000000000
;   2d00   0010110100000000
;   3f00   0011111100000000
;   1200   0001001000000000
;   2100   0010000100000000
;   4080   0100000010000000
MiddleInvader1          DW      2100h,9e40h,0ad40h,7f80h,3f00h,2100h,4080h
MiddleInvader2          DW      2100h,1e00h,2d00h,7f80h,0bf40h,0a140h,1200h
BottomInvader1          DW      01e00h,7f80h,0ccc0h,0ffc0h,2100h,4c80h,2100h
BottomInvader2          DW      01e00h,7f80h,0ccc0h,0ffc0h,2100h,4c80h,8040h
PlayersShip             DW      0400h,0e00h,7fc0h,0ffe0h,0ffe0h,0ffe0h,0000h
;   0400   0000010000000000
;   0e00   0000111000000000
;   7fc0   0111111111000000
;   ffe0   1111111111100000
;   ffe0   1111111111100000
;   ffe0   1111111111100000
;   0000   0000000000000000
TwistedMissile1         DW      0000h,0000h,0000h,0800h,0400h,0800h,0400h
;   0000   0000000000000000
;   0000   0000000000000000
;   0000   0000000000000000
;   0800   0000100000000000
;   0400   0000010000000000
;   0800   0000100000000000
;   0400   0000010000000000
TwistedMissile2         DW      0000h,0000h,0000h,0400h,0800h,0400h,0800h
StraightMissile         DW      0000h,0000h,0000h,0400h,0400h,0400h,0400h

  MEnemigos  TEnemigos  cNumEnemigos DUP (<>)    ; Enemigos sin inicializar
  MCabEDisp  TCabEDisp  cNumDispEne  DUP (<>)    ; Disparos de los enemigos
;   align 16
;   db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1             ;16
  MEDisparos TEDisparos cNumDispEne  DUP (<>)    ; Disparos de los enemigos
  Player     TPlayer    <>                       ; Jugador sin inicializar
  MPDisparos TPDisparos <>                       ; Disparos de los enemigos

  vbSpeaker    DB   ?
  vbEjecutar   DB   1                     ; Lo definimos indicando que suenen las notas
  vbEjecutando DB   0
  vwActual     DW   0
  Notas1       DW   262, 3, 330, 3, 349, 3, 392, 3, 349, 3, 294, 3, 0, 8     ; 7
               DW   262, 3, 330, 3, 349, 3, 392, 3, 349, 3,   0, 8           ; 6
               DW   262, 3, 330, 3, 349, 3, 392, 3, 349, 3, 294, 3, 0, 8     ; 7
               DW   330, 3, 349, 3, 330, 3, 262, 3, 262, 3                   ; 5
  MNota        TNota  <>

msg1           DB  "Error al REDIMENSIONAR memoria$"
msg2           DB  "Error al RESERVAR memoria$"
msg3           DB  "Error al LIBERAR memoria$"
msgAOE         DB  "(c)Abre los ojos al ensamblador", 13, 10
               DB  "Ejemplo de space invaders$"
msgExito       DB  "Enhorabuena, has salvado al planeta Tierra$"
msgFracaso     DB  "Por tu impericia la Tierra ha sido destruida$"
msgBlanco      DB  "                                            $"
NumEnemigos    DB  ?                      ; Número de enemigos que quedan
OldInt9h       DD  ?                      ; Dirección antigua de Int 9h
OldInt1Ch      DD  ?                      ; Dirección antigua de Int 1Ch
ScrSeg         DW  ?                      ; Segmento del búfer de pantalla
DirEnemigos    DW  ?                      ; Dirección del mvto de los enemigos
DesplDefFig    DW  ?                      ; Para pintar el mvto de la figura
TimePlayer     DB  ?                      ; Retardo para el mvto del jugador
TimeEnemigos   DB  ?                      ; Retardo para el mvto de los enemigos
TimePDisp      DB  ?                      ; Retardo para el mvto disparo jugador
TimeEDisp      DB  ?                      ; Retardo para el mvto disparo enemigos
TimeESgteDisp  DB  ?                      ; Retardo para el siguiente disparo enemigos
vNextTEnemigos DB  ?                      ; Siguiente retardo de los enemigos
TicksReloj     DD  ?                      ; Ticks de reloj
ActFrecBomb    DB  ?                      ; Frecuencia actual disparos enemigos (cambia)
NumEColumn     DW  ?                      ; Número de columnas de enemigos que quedan
ChgTEnemigos   DB  ?                      ; Cada cuantos enemigos muertos incr su velocidad
vSoyInmune     DB  cSoyInmune             ; Ser o no ser inmune
; Datos modificados en cada nivel
vYESup         DW  ?                      ; X-inicial-superior de los enemigos
; Datos que modifica la nueva ISR del teclado
PlayerLeft     DB  0
PlayerRight    DB  0
PlayerFire     DB  0
Escape         DB  0

codigo ENDS
END Entrada


Más códigos aquí.
http://abreojosensamblador.epizy.com/?Tarea=1&SubTarea=35&i=1

Gracias.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eternal Idol

Si tuvieras los archivos .INC deberias ser capaz de ensamblarlo desde linea de comandos con el ml.exe ... esto es codigo de 16 bits para MS-DOS.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón