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?
(http://abreojosensamblador.epizy.com/Productos/AOE/Imags/Cap35/Fig_35_01.png)
Código ASM.
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.
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.