kolibrios-gitea/programs/games/bomber/bomber.asm
Andrew ed2e074b9f Update locale codes
- Fixes for new locale codes.
- Correct en_US translations.
- Some whitespace clean-up.
2024-06-07 10:39:27 +01:00

2370 lines
55 KiB
NASM
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;заголовок приложения
SK_SPACE equ 0x39
SK_CTRL equ 0x1D
SK_UP equ 0x48
SK_DOWN equ 0x50
SK_LEFT equ 0x4B
SK_RIGHT equ 0x4D
SK_ESC equ 0x01
INIT_PLANE_X equ 20
INIT_PLANE_Y equ 20
BACK_COLOR equ 0x9bcdfa
GROUND_COLOR equ 0x808080
BANG_COLOR equ 0xB0140E
ANIM_PLANE_BMP_PIXELS_COUNT equ 22*32*32
WINDOW_WIDTH equ 800
WINDOW_HEIGHT equ 600
GROUNG_HEIGHT equ 100
CITY_OFFSET equ (WINDOW_WIDTH-32*20)/2
MAX_BOMBS equ 8
GRAVY_ACCEL equ 1
BOMB_DELAY equ 12
MAX_LEVEL equ 5
ACKACK_BULLET_SPEED equ 17
BULLET_SIZE equ 7
MAX_SOUNDS equ 8
VOLUME_BOMBFLY equ 16
VOLUME_BOMBBANG equ 28
VOLUME_ACKACK equ 24
VOLUME_PLANE equ 48
VOLUME_ARW equ 16
use32 ; транслятор, использующий 32 разрядных команды
org 0x0 ; базовый адрес кода, всегда 0x0
db 'MENUET01' ; идентификатор исполняемого файла (8 байт)
dd 0x1 ; версия формата заголовка исполняемого файла
dd start ; адрес, на который система передаёт управление
; после загрузки приложения в память
dd i_end ; размер приложения
dd i_end ; Объем используемой памяти, для стека отведем 0х100 байт
dd i_end ; расположим позицию стека в области памяти, сразу за телом программы. Вершина стека в диапазоне памяти, указанном выше
dd 0x0, _s_current_dir ; указатель на строку с параметрами.
; если после запуска неравно нулю, приложение было
; запущено с параметрами из командной строки
; указатель на строку, в которую записан путь,
; откуда запущено приложение
;Область кода
;----------------- include -------------------------------------
include 'lang.inc' ; Language support for locales: ru_RU (CP866), en_US.
include 'ssmix.inc'
;---------------------------------------------------------------------------
;----------------------------- главный цикл --------------------------------
;---------------------------------------------------------------------------
align 4
start: ;Точка входа в программу
; режим клавиатуры: скан-коды
mov eax, 66
mov ebx, 1
mov ecx, 1
int 0x40
; инициализация кучи
mov eax, 68
mov ebx, 11
int 0x40
cmp eax, 1000000 ; куча нужна минимум на ~1000кб (это с запасом)
ja heap_ok
mov eax, -1
int 0x40 ; иначе закрываем все
heap_ok:
mov eax, bmp_plane
mov ebx, 736*32*3
call convert_bmp_backcolor
mov eax, bmp_bomb
mov ebx, 96*16*3
call convert_bmp_backcolor
mov eax, bmp_tile
mov ebx, 20*20*3
call convert_bmp_backcolor
mov eax, bmp_ackack
mov ebx, 40*20*3
call convert_bmp_backcolor
call read_sounds_file
call ssmix_init
mov [_game_state], 0
redraw_window:
call draw_window
cmp [_game_state], 0
jne still_no_intro
call draw_intro
still_no_intro:
still:
; обработка событий
mov eax,11
int 0x40
cmp eax,1
je redraw_window
cmp eax,2
je key
cmp eax,3
je close_button
; пауза
mov eax,5
mov ebx,1
int 0x40
mov eax, 26
mov ebx, 9
int 0x40
mov ebx, eax
sub eax, [_last_value_timecount]
cmp eax, [_delay]
jbe still
mov [_last_value_timecount], ebx
call timer_x2
call timer_x4
; проверка на игру
cmp [_game_state], 1
jne still_no_game
; вызов процедур игрового процесса
mov eax, [_plane_health]
cmp eax, 0
jle still_no_plane
call flight_control_plane
call plane_interaction
call draw_plane
still_no_plane:
call draw_plane_health
call bomb_proc
call bang_proc
call ground_draw
call city_draw
call ackack_draw
call ackack_bullet_proc
; таймер завершения игры
call game_over_timer
still_no_game:
jmp still
key: ; обработка нажатия клавиш
mov eax,2
int 0x40
push eax
key_SPACE:
cmp ah, SK_SPACE
jne key_SPACE_end
cmp [_game_state], 1
je key_SPACE_do_a_barrel_roll
key_SPACE_start_game: ; запуск игры
mov [_game_state], 1
call init_game_state
jmp key_SPACE_end
key_SPACE_do_a_barrel_roll: ; сделать бочку
mov eax, [_plane_state]
cmp eax, 0
je key_SPACE_do_a_barrel_roll_r
cmp eax, 1
je key_SPACE_do_a_barrel_roll_l
jmp key_SPACE_end
key_SPACE_do_a_barrel_roll_r:
mov eax,[_X_plane]
cmp eax, WINDOW_WIDTH-130-32
jg key_SPACE_end
mov [_plane_state], 4
mov [_plane_state_step], 0
jmp key_SPACE_end
key_SPACE_do_a_barrel_roll_l:
mov eax,[_X_plane]
cmp eax, 130
jl key_SPACE_end
mov [_plane_state], 5
mov [_plane_state_step], 0
key_SPACE_end:
pop eax
key_CTRL:
cmp ah, SK_CTRL
jne key_CTRL_end
call bomb_drop
key_CTRL_end:
key_UP:
cmp ah, SK_UP
jne key_UP_end
cmp [_game_state], 0
jne key_UP_end
mov ebx, [_level_num]
inc ebx
mov [_level_num], ebx
cmp ebx, MAX_LEVEL
jbe key_UP_no_max
mov [_level_num], MAX_LEVEL
key_UP_no_max:
call draw_level_num
key_UP_end:
key_DOWN:
cmp ah, SK_DOWN
jne key_DOWN_end
cmp [_game_state], 0
jne key_DOWN_end
mov ebx, [_level_num]
dec ebx
mov [_level_num], ebx
cmp ebx, 1
jae key_DOWN_no_min
mov [_level_num], 1
key_DOWN_no_min:
call draw_level_num
key_DOWN_end:
key_LEFT:
cmp ah, SK_LEFT
jne key_LEFT_end
cmp [_game_state], 0
jne key_LEFT_end
mov ebx, [_set_volume]
dec ebx
cmp ebx, 0
jge @f
mov ebx, 0
@@:
mov [_set_volume], ebx
shl ebx, 4
stdcall ssmix_setvolume, ebx, ebx
call draw_volume_num
key_LEFT_end:
key_RIGHT:
cmp ah, SK_RIGHT
jne key_RIGHT_end
cmp [_game_state], 0
jne key_RIGHT_end
mov ebx, [_set_volume]
inc ebx
cmp ebx, 8
jle @f
mov ebx, 8
@@:
mov [_set_volume], ebx
shl ebx, 4
stdcall ssmix_setvolume, ebx, ebx
call draw_volume_num
key_RIGHT_end:
key_ESC:
cmp ah, SK_ESC
jne key_ESC_end
jmp close_button
key_ESC_end:
jmp still
close_button: ; завершение работы
call ssmix_release
call sounds_free_memory
; закрыть приложение
mov eax, -1
int 0x40
;---------------------------------------------------------------------------
;----------------------------- подрограммы ---------------------------------
;---------------------------------------------------------------------------
convert_bmp_backcolor: ; eax - указаталь на начало данных, ebx - размер данных
push ecx
cbb_loop:
cmp ebx, 0
jle cbb_loop_end
mov ecx, [eax]
and ecx, 0x00FFFFFF
cmp ecx, 0x00FFFFFF
jne @f
mov ecx, BACK_COLOR
mov [eax], cl
shr ecx, 8
mov [eax+1], cl
shr ecx, 8
mov [eax+2], cl
@@:
add eax, 3
sub ebx, 3
jmp cbb_loop
cbb_loop_end:
pop ecx
ret
; чтение файла со звуками
read_sounds_file:
mov edi, _s_current_dir
mov al, 0
mov ecx, 4096
repne scasb
mov dword[edi-1], 'data'
mov dword[edi+3], '.bin'
mov [_flag_bomberdatabin_ok], 1
; прочитать из файла данных количество звуков
mov [_fi_func], 0
mov [_fi_pos], 8
mov [_fi_size], 4
mov [_fi_pbuff], _count_sounds
mov [_fi_pfilename], _s_current_dir
mov eax, 70
mov ebx, file_info
int 0x40
cmp ebx, -1
jne @f
mov [_flag_bomberdatabin_ok], 0
jmp .end
@@:
; прочитать данные о смещении и размере звуков в файле, и записать их (временно) в массив звуков
mov ecx, [_count_sounds]
shl ecx, 3
mov [_fi_func], 0
mov [_fi_pos], 12
mov [_fi_size], ecx
mov [_fi_pbuff], _array_sounds
mov [_fi_pfilename], _s_current_dir
mov eax, 70
mov ebx, file_info
int 0x40
; прочитать звуки в файле и записать их в память
mov ecx, [_count_sounds]
mov esi, _array_sounds
.loop:
push ecx
; подготовить данные информационной структуры для чтения из файла
mov [_fi_func], 0
mov eax, [esi]
mov [_fi_pos], eax
mov eax, [esi+4]
mov [_fi_size], eax
; выделить память под звук, получить указатель, и изменить данные в массиве звуков
mov ecx, [esi+4]
mov eax, 68
mov ebx, 12
int 0x40
mov [esi], eax
mov ecx, [esi+4]
add ecx, eax
mov [esi+4], ecx
; прочитать сэмпл из файла
mov [_fi_pbuff], eax
mov [_fi_pfilename], _s_current_dir
mov eax, 70
mov ebx, file_info
int 0x40
pop ecx
add esi, 8
dec ecx
jnz .loop
.end:
ret
sounds_free_memory:
mov ecx, [_count_sounds]
mov esi, _array_sounds
.loop:
push ecx
; выделить память под звук, получить указатель, и изменить данные в массиве звуков
mov eax, 68
mov ebx, 13
mov ecx, [esi]
int 0x40
pop ecx
add esi, 8
dec ecx
jnz .loop
ret
init_game_state: ; инициализация игровых данных
mov [_game_over_time], 0
mov [_X_plane], INIT_PLANE_X
mov [_Y_plane], INIT_PLANE_Y
mov [_VX_plane], 4
mov [_plane_state], 0
mov [_anim_pos_plane], 0
mov [_plane_health], 100
mov [_timer_x2], 0
mov [_timer_x4], 0
mov [_bomb_count], 0
mov [_bomb_delay_time], 0
mov [_addit_VY_plane], 0
mov [_flag_air_raid_warning], 0
call load_level
; инициализация массива взрывов
mov ebx, _bang_array
xor ecx, ecx
igs_bang_array_loop:
cmp ecx, MAX_BOMBS
jae igs_bang_array_loop_end
mov eax, -1
mov [ebx], eax
add ebx, 8
inc ecx
jmp igs_bang_array_loop
igs_bang_array_loop_end:
; инициализация массива зенитных снарядов
mov ebx, _ackack_bullet
xor ecx, ecx
igs_bullet_array_loop:
cmp ecx, 32
jae igs_bullet_array_loop_end
mov eax, 0
mov [ebx], eax
add ebx, 4
inc ecx
jmp igs_bullet_array_loop
igs_bullet_array_loop_end:
; очистить экран
call draw_window
;запустить звук пропелера
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_playtrack, [_array_sounds+8*((( 4 ))-1)], [_array_sounds+8*((( 4 ))-1)+4], VOLUME_PLANE, VOLUME_PLANE, SSMIX_CHANMODE_REPEAT
@@:
mov [_channel_sound_plane], eax
mov [_channel_sound_arw], -1
ret
game_over:
mov [_game_over_time], 30 ; задаем задержку на game over
;вывод текста GAME OVER
mov eax,4
mov ebx,(WINDOW_WIDTH/2 - 50)*65536 + 30
mov ecx,0x80000000
mov edx,_text_game_over
int 0x40
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_stoptrack, [_channel_sound_plane]
@@:
ret
game_over_timer: ; таймер завершения игры, создает небольшую паузу перед остановкой игры
mov ebx, [_game_over_time]
cmp ebx, 0
je got_end
dec ebx
mov [_game_over_time], ebx
cmp ebx, 0
jg got_end
mov [_game_state], 0
cmp [_flag_bomberdatabin_ok], 1
jne @f
call ssmix_stopalltracks
@@:
call draw_window
call draw_intro
got_end:
ret
next_level: ; следующий уровень
push eax
mov [_game_over_time], 1 ; быстренько завершим игру
mov eax, [_level_num] ; на следующий уровень
inc eax
cmp eax, MAX_LEVEL
jbe next_level_no_overmax
mov eax, MAX_LEVEL
next_level_no_overmax:
mov [_level_num], eax
pop eax
ret
check_level_complete: ; проверка на завершение уровня
push eax
push ebx
push ecx
push edx
mov edx, 0 ; флаг наличия строений в городе: 0 - нет строений, 1 - есть строения
mov ebx, _city
xor ecx, ecx
clc_loop:
cmp ecx, 32
jae clc_loop_end
xor eax, eax
mov ax, [ebx]
cmp eax, 0
je clc_no_buildings
mov edx, 1
jmp clc_loop_end
clc_no_buildings:
add ebx, 2
inc ecx
jmp clc_loop
clc_loop_end :
cmp edx, 0
jne clc_end
; уровень завершен - идем на посадку
;вывод текста LEVEL COMPLETE
mov eax,4
mov ebx,(WINDOW_WIDTH/2 - 70)*65536 + 30
mov ecx,0x80000000
mov edx,_text_level_complete
int 0x40
; быстрое снижение самолета
mov [_addit_VY_plane], 3 ; задать скорость быстрого снижения
; выключить сирену
call air_raid_warning_off
clc_end:
pop edx
pop ecx
pop ebx
pop eax
ret
draw_plane_health:
mov ebx, 5*0x00010000 + 100
mov ecx, 5*0x00010000 + 10
mov edx, 0x00000000
mov eax, 13
int 0x40
mov ebx, [_plane_health]
add ebx, 5*0x00010000
mov edx, 0x00008000
int 0x40
ret
air_raid_warning_on:
push eax
cmp [_flag_air_raid_warning], 1
je .end
mov [_flag_air_raid_warning], 1
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_playtrack, [_array_sounds+8*((( 5 ))-1)], [_array_sounds+8*((( 5 ))-1)+4], VOLUME_ARW, VOLUME_ARW, SSMIX_CHANMODE_REPEAT
@@:
mov [_channel_sound_arw], eax
.end:
pop eax
ret
air_raid_warning_off:
cmp [_flag_air_raid_warning], 0
je .end
mov [_flag_air_raid_warning], 0
cmp [_flag_bomberdatabin_ok], 1
jne .end
stdcall ssmix_stoptrack, [_channel_sound_arw]
.end:
ret
;======================================= САМОЛЕТ ======================================
flight_control_plane: ; процедура управления полетом самолета
mov eax,[_X_plane]
add eax, [_VX_plane]
mov [_X_plane], eax
cmp eax, WINDOW_WIDTH-60-32
jl fcp_set_utunr_rl
mov ebx, [_plane_state]
cmp ebx, 0
jne fcp_set_utunr_rl
mov [_plane_state],2
mov [_plane_state_step], 0
fcp_set_utunr_rl:
cmp eax, 60
jg fcp_set_utunr_lr
mov ebx, [_plane_state]
cmp ebx, 1
jne fcp_set_utunr_lr
mov [_plane_state],3
mov [_plane_state_step], 0
fcp_set_utunr_lr:
; далее код выполняется в 2 раза медленней
mov eax, [_timer_x2]
cmp eax, 0
jne fcp_timex2_end
mov eax, [_plane_state]
cmp eax, 2 ; если делаем разворот налево
jne fcp_uturn_rl_end
mov eax, [_plane_state_step]
mov ebx, 4
sub ebx, eax
mov [_VX_plane], ebx ; то расчитываем скорость исходя из текущего шага состояния
inc eax ; переходим на следующий шаг состояния
mov [_plane_state_step], eax
cmp eax, 9 ; проверяем, закончились ли шаги
jne fcp_uturn_rl_end
mov [_plane_state], 1 ; если да то переводим состояние на прямой полет
fcp_uturn_rl_end:
mov eax, [_plane_state]
cmp eax, 3 ; если делаем разворот направо
jne fcp_uturn_lr_end
mov eax, [_plane_state_step]
mov ebx, -4
add ebx, eax
mov [_VX_plane], ebx ; то расчитываем скорость исходя из текущего шага состояния
inc eax ; переходим на следующий шаг состояния
mov [_plane_state_step], eax
cmp eax, 9 ; проверяем, закончились ли шаги
jne fcp_uturn_lr_end
mov [_plane_state], 0 ; если да то переводим состояние на прямой полет
fcp_uturn_lr_end:
mov eax, [_plane_state]
cmp eax, 4 ; если делаем бочку вправо
jne fcp_barrel_r_end
mov eax, [_plane_state_step]
inc eax ; переходим на следующий шаг состояния
mov [_plane_state_step], eax
cmp eax, 8 ; проверяем, закончились ли шаги
jne fcp_barrel_r_end
mov [_plane_state], 0 ; если да то переводим состояние на прямой полет
fcp_barrel_r_end :
mov eax, [_plane_state]
cmp eax, 5 ; если делаем бочку влево
jne fcp_barrel_l_end
mov eax, [_plane_state_step]
inc eax ; переходим на следующий шаг состояния
mov [_plane_state_step], eax
cmp eax, 8 ; проверяем, закончились ли шаги
jne fcp_barrel_l_end
mov [_plane_state], 1 ; если да то переводим состояние на прямой полет
fcp_barrel_l_end:
call animation_plane
fcp_timex2_end:
; далее код выполняется в 4 раза медленней
mov eax, [_timer_x4]
cmp eax, 0
jne fcp_timex4_end
; медленное снижение самолета
mov eax,[_Y_plane]
add eax, 1
mov [_Y_plane], eax
fcp_timex4_end:
; быстрое снижение самолета
mov eax,[_Y_plane]
mov ebx,[_addit_VY_plane]
add eax, ebx
mov [_Y_plane], eax
; контроль высоты самолета, посадка
mov eax,[_Y_plane]
cmp eax, WINDOW_HEIGHT - GROUNG_HEIGHT - 32
jl fcp_end_plane_landing
mov [_addit_VY_plane], 0 ; прекратить быстрое снижение
mov ebx, [_plane_state]
cmp ebx, 6
je fcp_end_plane_landing
cmp ebx, 0
jne fcp_horiz_fly
mov [_plane_state], 6 ; режим посадки
;jmp fcp_end_plane_landing
fcp_horiz_fly:
mov eax, WINDOW_HEIGHT - GROUNG_HEIGHT - 32
fcp_end_plane_landing:
cmp eax, WINDOW_HEIGHT - GROUNG_HEIGHT - 32 + 6
jle fcp_no_plane_underground ; проверка на то, чтобы самолет не ушел "под землю"
mov eax, WINDOW_HEIGHT - GROUNG_HEIGHT - 32 + 6
mov ebx, [_X_plane]
cmp ebx, WINDOW_WIDTH - 60-32
jl fcp_no_end_level ; проверка на то, что докатился до конца посадочной полосы
; завершение уровня
call next_level ; переход на следующий уровень
fcp_no_end_level:
fcp_no_plane_underground:
mov [_Y_plane], eax
ret
animation_plane:
; анимация самолета
; полет вправо
mov eax, [_plane_state]
cmp eax, 0
jne ap_state0_end
mov [_anim_pos_plane], 0
ap_state0_end:
; полет влево
mov eax, [_plane_state]
cmp eax, 1
jne ap_state1_end
mov [_anim_pos_plane], 8
ap_state1_end:
; анимация для разворотов и бочек
mov eax, [_plane_state]
cmp eax, 5
ja ap_state2345_end
cmp eax, 2
jb ap_state2345_end
sub eax, 2
mov ebx, eax ; умножить eax на 9
shl eax, 3
add eax, ebx
add eax, [_plane_state_step] ; прибавить номер шага
shl eax, 2 ; умножить на 4
add eax, _anim_array_uturn_rl ; получается смещение для номера требуемого кадра
mov ebx, [eax]
mov [_anim_pos_plane], ebx ; здесь вытаскиваем сам номер
ap_state2345_end:
; посадка (только вправо)
mov eax, [_plane_state]
cmp eax, 6
jne ap_state6_end
mov [_anim_pos_plane], 22
ap_state6_end:
ret
draw_plane:
; стереть предыдущее изображение
mov eax, 13
mov ebx,[_last_XY_plane]
and ebx, 0xffff0000
add ebx, 32
mov ecx,[_last_XY_plane]
shl ecx, 16
add ecx, 32
mov edx, BACK_COLOR
int 0x40
; расчет адреса картинки исходя из номера кадра _anim_pos_plane
mov ebx, [_anim_pos_plane]
shl ebx, 10
mov eax, ebx
add ebx, eax
add ebx, eax
add ebx, bmp_plane
; подготовка координат
mov edx,[_X_plane]
shl edx, 16
add edx,[_Y_plane]
mov [_last_XY_plane], edx
; вывод картинки
mov eax,7
mov ecx,32*65536+32
int 0x40
ret
plane_interaction:
push eax
push ebx
push ecx
push edx
mov eax, [_X_plane]
mov ebx, [_Y_plane]
add ebx, 16
mov ecx, [_VX_plane]
cmp ecx, 0
jl pi_no_positive_vx
add eax, 32 ; здесь в зависимости от направления полета определяем точку взаимодействия с городом
pi_no_positive_vx:
; теперь в eax и ebx координаты X,Y точки взаимодействия самолета с городом
mov edx, eax
sub eax, CITY_OFFSET
; проверка на вылет за пределы города
cmp eax, 0
jl pi_out_of_city
cmp eax, 32*20
jg pi_out_of_city
; проверка на взаимодействие с городом
add eax, 10 ; делим координату X на 20
mov ecx, eax
shr eax, 4
shr ecx, 6
sub eax, ecx
shr ecx, 2
add eax, ecx
shr ecx, 2
sub eax, ecx
dec eax ; в eax номер столбца города по которому летит бомба
mov esi, eax
shl esi, 1
add esi, _city ; в esi указатель на высоту постройки в данном столбце
mov eax, edx
; теперь сравним координату Y вершины постройки с координатой Y точки взаимодействия самолета
xor ecx, ecx
mov cx, [esi]
mov edx, ecx
shl ecx, 4
shl edx, 2
add ecx, edx
mov edx, WINDOW_HEIGHT - GROUNG_HEIGHT
sub edx, ecx ; в edx координата Y вершины постройки
cmp ebx, edx
jl pi_no_crash
; если столкновение произошло
mov [_plane_health], 0
call bang_add ; делаем взрыв
call game_over ; завершение игры
pi_no_crash:
pi_out_of_city:
pop edx
pop ecx
pop ebx
pop eax
ret
; ================================== БОМБЫ ===========================================
bomb_drop: ; процедура "бросания бомбы". создает новую бомбу, задает для нее начальные параметры.
; проверка на здоровье самолета
mov eax, [_plane_health]
cmp eax, 0
jle bomb_drop_end
; проверить на допустимые состояния самолета (нельзя во время бочки)
mov eax, [_plane_state]
cmp eax, 3
ja bomb_drop_end
; проверить выдержан ли интервал времени между бросками
mov eax, [_bomb_delay_time]
cmp eax, 0
jne bomb_drop_end
mov [_bomb_delay_time], BOMB_DELAY
; собственно, бросаем бомбу
mov eax, [_bomb_count]
cmp eax, MAX_BOMBS-1
jae bomb_drop_end
inc eax
mov [_bomb_count], eax
dec eax
shl eax, 4
add eax, _bomb_array ; здесь в еах получили указатель на начало данных о бомбе
mov ebx, [_X_plane]
mov [eax], ebx ; задание координаты X
add eax, 4
mov ebx, [_Y_plane]
add ebx, 30
mov [eax], ebx ; задание координаты Y
add eax, 4
mov ebx, [_VX_plane]
cmp ebx, 0
jge bomb_drop_pos_dir_vx
bomb_drop_neg_dir_vx:
neg ebx
shr ebx, 1
neg ebx
jmp bomb_drop_dir_vx_end
bomb_drop_pos_dir_vx:
shr ebx, 1
bomb_drop_dir_vx_end:
mov [eax], ebx ; задание вектора скорости по X
add eax, 4
mov ebx, 0
mov [eax], ebx ; задание вектора скорости по Y
push ecx
mov ecx, [_bomb_count]
dec ecx
call bombfly_sound_start
pop ecx
bomb_drop_end:
ret
bomb_proc:
; таймер интервала между бросаниями бомб
mov eax, [_bomb_delay_time]
cmp eax, 0
je bomb_proc_delay_timer_end
dec eax
mov [_bomb_delay_time], eax
bomb_proc_delay_timer_end:
; обработка движения бомб
mov eax, [_bomb_count]
cmp eax, 0
je bomb_proc_end
xor ecx, ecx
bomb_proc_loop: ; цикл обработки падения бомб
cmp ecx, [_bomb_count]
jae bomb_proc_end
mov ebx, ecx
shl ebx, 4
add ebx, _bomb_array ; получили указатель на начало данных о бомбе
call bomb_hide ; стереть предыдущее значение
; обработка
; выполняется пересчет для скорости VY текущей бомбы
add ebx, 4*3
mov eax, [_timer_x2]
cmp eax, 0
jne bomb_proc_gravity_accel_end
mov eax, [ebx]
add eax, GRAVY_ACCEL
mov [ebx], eax
bomb_proc_gravity_accel_end:
; выполняется пересчет для координат X текущей бомбы
sub ebx, 4*3
mov eax, [ebx]
add ebx, 4*2
mov edx, [ebx]
add eax, edx
sub ebx, 4*2
mov [ebx], eax
push eax
; выполняется пересчет для координат Y текущей бомбы
add ebx, 4
mov eax, [ebx]
add ebx, 4*2
mov edx, [ebx]
add eax, edx
sub ebx, 4*2
mov [ebx], eax
push eax
; взаимодействие бомб с миром
sub ebx, 4
pop edx ; координата Y
pop eax ; координата X
; проверка на выход бомб за пределы игровой зоны, бомбы просто удаляются при вылете за границы
cmp eax, 10
jle bomb_proc_delete_bomb
cmp eax, WINDOW_WIDTH - 36
jge bomb_proc_delete_bomb
; проверка на взаимодейтсвие с миром
push eax
push ebx
mov ebx, edx
call bomb_check_detonation
cmp eax, 1
pop ebx
pop eax
je bomb_proc_interaction_with_world
cmp edx, WINDOW_HEIGHT - GROUNG_HEIGHT
jae bomb_proc_interaction_with_world
jmp bomb_proc_interaction_end
bomb_proc_interaction_with_world:
push eax
push ebx
mov ebx, edx
call bang_add
call air_raid_warning_on ; включение воздушной тревоги
pop ebx
pop eax
bomb_proc_delete_bomb:
call bomb_delete ; удаляем бомбу
dec ecx ; т.к. бомбы удалена - остаемся на том же номере бомбы
mov eax, [_bomb_count]
dec eax
mov [_bomb_count], eax ; уменьшаем количество бомб
jmp bomb_proc_draw_end ; не рисуем бомбу если удалили ее
bomb_proc_interaction_end:
call bomb_draw
bomb_proc_draw_end:
inc ecx
jmp bomb_proc_loop
bomb_proc_end:
ret
bomb_delete: ; удаление данных о бомбе, в есх номер удаляемой бомбы
push eax
push ebx
push ecx
push edx
call bombfly_sound_stop
inc ecx
bomb_delete_loop:
cmp ecx, [_bomb_count]
jae bomb_delete_loop_end
mov ebx, ecx
shl ebx, 4
add ebx, _bomb_array ; получили указатель на начало данных о бомбе
dec ecx
mov edx, ecx
shl edx, 4
add edx, _bomb_array ; получили указатель на начало данных о следующей бомбе
inc ecx
; перемещение данных о следующей бомбе на место предыдущей
mov eax, [ebx]
mov [edx], eax
add ebx,4
add edx,4
mov eax, [ebx]
mov [edx], eax
add ebx,4
add edx,4
mov eax, [ebx]
mov [edx], eax
add ebx,4
add edx,4
mov eax, [ebx]
mov [edx], eax
; переход к следующей бомбе
inc ecx
jmp bomb_delete_loop
bomb_delete_loop_end:
pop edx
pop ecx
pop ebx
pop eax
ret
bomb_hide: ; стереть бомбу с экрана, ebx - указатель на начало данных о бомбе
push eax
push ebx
push ecx
push edx
mov eax, 13
mov edx, ebx
mov ebx, [edx]
shl ebx, 16
add ebx, 16
add edx, 4
mov ecx, [edx]
shl ecx, 16
add ecx, 16
mov edx, BACK_COLOR
int 0x40
pop edx
pop ecx
pop ebx
pop eax
ret
bomb_draw: ; отрисовать бомбу, ebx - указатель на начало данных о бомбе
push eax
push ebx
push ecx
push edx
; получение в edx координат бомбы
mov edx, [ebx]
shl edx, 16
add ebx, 4
mov eax, [ebx]
add edx, eax
; получение указателя на картинку бомбы в ebx (сразу с выбором нужной картинки)
add ebx, 4
mov eax, [ebx] ; здесь в eax - горизонтальная скорость бомбы
add ebx, 4
mov ecx, [ebx] ; здесь в ecx - вертикальная скорость бомбы
xor ebx, ebx
cmp ecx, 3
jl bomb_draw_midspeed_end
inc ebx
bomb_draw_midspeed_end:
cmp ecx, 9
jl bomb_draw_highspeed_end
inc ebx
bomb_draw_highspeed_end:
cmp eax, 0
jge bomb_draw_left_dir_end
add ebx, 3
bomb_draw_left_dir_end:
; теперь в ebx номер картинки бомбы
shl ebx, 8
mov eax, ebx
add ebx, eax
add ebx, eax
add ebx, bmp_bomb ; теперь в ebx указатель на картинку бомбы
; вывод картинки
mov eax,7
mov ecx,16*65536+16
int 0x40
pop edx
pop ecx
pop ebx
pop eax
ret
; взаимодействие бомб с миром
bomb_check_detonation: ; проверить бомбу с координатами: eax - координата X, eab - координата Y
; и при необходимости провести нужные разрушения (или пустой взрыв)
; в eax вернуть результат события: 0 - ничего не произшло, 1 - произошел взрыв
; (корявая реализация)
push ecx
push edx
add eax, 8
add ebx, 8
sub eax, CITY_OFFSET
; проверка на вылет за пределы города
cmp eax, 0
jl bcd_out_of_city
cmp eax, 32*20
jg bcd_out_of_city
; проверка на взаимодействие с городом
add eax, 10 ; делим координату X на 20
mov ecx, eax
shr eax, 4
shr ecx, 6
sub eax, ecx
shr ecx, 2
add eax, ecx
shr ecx, 2
sub eax, ecx
dec eax ; в eax номер столбца города по которому летит бомба
mov esi, eax
shl esi, 1
add esi, _city ; в esi указатель на высоту постройки в данном столбце
mov edx, WINDOW_HEIGHT - GROUNG_HEIGHT
sub edx, ebx
mov ebx, edx
cmp ebx, 0
jg bcd_no_neg_value_Y
xor ecx, ecx
mov cx, [esi]
xor ebx, ebx
jmp bcd_damage ; наносим разрушения
bcd_no_neg_value_Y:
add ebx, 10 ; делим координату Y на 20
mov ecx, ebx
shr ebx, 4
shr ecx, 6
sub ebx, ecx
shr ecx, 2
add ebx, ecx
shr ecx, 2
sub ebx, ecx ; в ebx высота бомбы "в плитках" над поверхностью
xor ecx, ecx
mov cx, [esi]
cmp ebx, ecx ; проверка на попадание в строение
jg bcd_no_detonation
bcd_damage: ; разрушения
;разрушение столбика в который попала бомба
mov edx, ecx
mov ecx, ebx
sub ecx, 2
cmp ecx, 0 ; просто проверка на 0, чтоб не ушло в минус
jge bcd_no_neg_value_H
xor ecx, ecx
bcd_no_neg_value_H:
mov [esi], cx ; возврат значения высоты столбца после взрыва
; зачистка взорванной области
call clear_tiles
; проверка на попадание в зенитки
call ackack_check_bombing
; разрушение соседнего столбика слева
; на данный момент имеем: eax - номер центрального (центральный - это в который непосредственно попала бомба) столбика,
; ebx - высота попадания бомбы, ecx - новая высота центрального столбика, edx - прежняя высота центрального столбика,
; esi - указатель на значение высоты центрального столбика в массиве
dec eax
cmp eax, 0
jl bcd_damage_left_end
sub esi, 2
xor ecx, ecx
mov cx, [esi] ; в ecx высота левого столбика
mov edx, ecx
push ecx
sub ecx, ebx
inc ecx
cmp ecx, 2
pop ecx
ja bcd_damage_left_end ; условие |ecx-ebx|<=1
dec ecx
cmp ecx, 0 ; просто проверка на 0, чтоб не ушло в минус
jge bcd_no_neg_value_HL
xor ecx, ecx
bcd_no_neg_value_HL:
mov [esi], cx
call clear_tiles
; проверка на попадание в зенитки
call ackack_check_bombing
bcd_damage_left_end:
; разрушение соседнего столбика справа
; на данный момент имеем: eax - номер левого столбика,
; ebx - высота попадания бомбы, ecx - новая высота левого столбика, edx - прежняя высота левого столбика,
; esi - указатель на значение высоты левого столбика в массиве
inc eax
inc eax
cmp eax, 32
jge bcd_damage_right_end
add esi, 4
xor ecx, ecx
mov cx, [esi] ; в ecx высота правого столбика
mov edx, ecx
push ecx
sub ecx, ebx
inc ecx
cmp ecx, 2
pop ecx
ja bcd_damage_right_end ; условие |ecx-ebx|<=1
dec ecx
cmp ecx, 0 ; просто проверка на 0, чтоб не ушло в минус
jge bcd_no_neg_value_HR
xor ecx, ecx
bcd_no_neg_value_HR:
mov [esi], cx
call clear_tiles
; проверка на попадание в зенитки
call ackack_check_bombing
bcd_damage_right_end:
call check_level_complete
bcd_detonation:
mov eax, 1
jmp bcd_end
bcd_no_detonation:
mov eax, 0
jmp bcd_end
bcd_out_of_city:
mov eax, 1
cmp ebx, WINDOW_HEIGHT - GROUNG_HEIGHT
jge bcd_end
mov eax, 0
bcd_end:
pop edx
pop ecx
ret
bombfly_sound_start: ; ecx - номер бомбы в массиве
push eax ebx ecx
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_playtrack, [_array_sounds+8*((( 1 ))-1)], [_array_sounds+8*((( 1 ))-1)+4], VOLUME_BOMBFLY, VOLUME_BOMBFLY, SSMIX_CHANMODE_SINGLE_WITHOUT_RESET
@@:
mov ebx, ecx
shl ebx, 2
add ebx, _array_bombsoundchannels
mov [ebx], eax
pop ecx ebx eax
ret
bombfly_sound_stop: ; ecx - номер бомбы в массиве
push eax ebx ecx
mov ebx, ecx
shl ebx, 2
add ebx, _array_bombsoundchannels
mov eax, [ebx]
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_stoptrack, eax
@@:
inc ecx
.delete_loop:
cmp ecx, MAX_BOMBS
jae .delete_loop_end
mov ebx, ecx
shl ebx, 2
add ebx, _array_bombsoundchannels
mov eax, [ebx]
mov [ebx-4], eax
inc ecx
jmp .delete_loop
.delete_loop_end:
pop ecx ebx eax
ret
; ==================================== ВЗРЫВЫ =======================================
fill_circle:
; построение заполненного круга (алгоритм Брезенхема)
; входные параметры:
; eax - координата центра по X
; ebx - координата центра по Y
; ecx - радиус
; edx - цвет
mov edi, eax
mov esi, ebx
push edx ; цвет в стек
mov eax, ecx
shl eax, 1
mov edx, 3
sub edx, eax ; D:=3-2*R
xor ebx, ebx ; теперь в ebx будет коорд X, в ecx коорд Y, в edx переменная D, в eax - промежуточные данные
fc_loop:
cmp ebx, ecx
jg fc_loop_end
; отрисовка линиями
pop eax ; цвет из стека
push edx ; D в стек
mov edx, eax ; в edx - цвет
push ebx
push ecx
; рисуем первый отрезок
mov eax, edi
sub eax, ebx
shl eax, 16
add ebx, edi
add ebx, eax ; получили концы отрезка по х
add ecx, esi
mov eax, ecx
shl eax, 16
add ecx, eax ; получили концы отрезка по y
mov eax, 38
int 0x40
pop ecx
push ecx
; рисуем второй отрезок
mov eax, esi
sub eax, ecx
mov ecx, eax
shl eax, 16
add ecx, eax ; получили концы отрезка по y
mov eax, 38
int 0x40
pop ecx
pop ebx
push ecx
push ebx ; обратить внимание! порядок загрузки координат в стек поменялся!
; рисуем третий отрезок
mov eax, edi
sub eax, ecx
shl eax, 16
add ecx, edi
add ecx, eax
mov eax, ebx
mov ebx, ecx ; получили концы отрезка по х
mov ecx, eax ; внимание! в ecx - координата x
add ecx, esi
mov eax, ecx
shl eax, 16
add ecx, eax ; получили концы отрезка по y
mov eax, 38
int 0x40
pop ecx
push ecx
; рисуем четвертый отрезок
mov eax, esi
sub eax, ecx
mov ecx, eax
shl eax, 16
add ecx, eax ; получили концы отрезка по y
mov eax, 38
int 0x40
pop ebx
pop ecx
mov eax, edx ; в eax - цвет
pop edx ; D из стека
push eax ; цвет в стек
; переход в следующей точке
cmp edx, 0
jge fc_loop_D_more_0 ; если D<0
fc_loop_D_low_0: ; то
mov eax, ebx
shl eax, 2
add edx, eax
add edx, 4 ; D:=D+4*X+6
jmp fc_loop_cmpD_end
fc_loop_D_more_0: ; иначе
mov eax, ebx
sub eax, ecx
shl eax, 2
add edx, eax
add edx, 10 ; D:=D+4*(X-Y)+10
dec ecx
fc_loop_cmpD_end: ; конец если
inc ebx
jmp fc_loop
fc_loop_end:
pop edx ; цвет из стека
ret
bang_add: ; добавить взрыв от бомбы, eax - координата X, eab - координата Y
push eax
push ebx
push ecx
push edx
shl eax, 16
add eax, ebx
mov ebx, _bang_array
xor ecx, ecx
bang_add_loop:
cmp ecx, MAX_BOMBS
jae bang_add_loop_end
mov edx, [ebx]
cmp edx, -1
jne bang_add_loop_freecheck_end
mov edx, 5*65536 + 3
mov [ebx], edx
add ebx, 4
mov [ebx], eax
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_playtrack, [_array_sounds+8*((( 2 ))-1)], [_array_sounds+8*((( 2 ))-1)+4], VOLUME_BOMBBANG, VOLUME_BOMBBANG, SSMIX_CHANMODE_SINGLE
@@:
jmp bang_add_loop_end
bang_add_loop_freecheck_end:
add ebx, 8
inc ecx
jmp bang_add_loop
bang_add_loop_end:
pop edx
pop ecx
pop ebx
pop eax
ret
bang_proc:
mov ebx, _bang_array
xor ecx, ecx
bang_proc_loop:
cmp ecx, MAX_BOMBS
jae bang_proc_loop_end
; проверка на наличие взрыва
mov edx, [ebx]
cmp edx, -1
je bang_proc_loop_freecheck_end
; проверка на завершение взрыва
and edx, 0x0000FFFF
cmp edx, 0
jne bang_proc_loop_endcheck_end
; здесь пишем обработку завершения взрыва
push ebx
push ecx
mov ecx, [ebx]
shr ecx, 16
add ebx, 4
mov eax, [ebx]
mov ebx, eax
shr eax, 16
and ebx, 0x0000FFFF
mov edx, BACK_COLOR
call fill_circle
pop ecx
pop ebx
mov eax, -1
mov [ebx], eax
jmp bang_proc_loop_continue
bang_proc_loop_endcheck_end:
; здесь пишем обработку взрыва
push ebx
push ecx
; задаем радиус и считаем новый
mov eax, [ebx]
mov edx, eax
shr eax, 16
mov ecx, eax
and edx, 0x0000FFFF
mov eax, edx
shl eax, 3
add eax, ecx
shl eax, 16
dec edx
add eax, edx
mov [ebx], eax
; задаем координаты
add ebx, 4
mov eax, [ebx]
mov ebx, eax
shr eax, 16
and ebx, 0x0000FFFF
;задаем цвет
mov edx, BANG_COLOR
call fill_circle
pop ecx
pop ebx
bang_proc_loop_freecheck_end:
bang_proc_loop_continue:
add ebx, 8
inc ecx
jmp bang_proc_loop
bang_proc_loop_end:
ret
; ===================================== ЗЕНИТКИ =========================================
; управление зенитками, добавление зениток, отрисовка зениток, стрельба
ackack_draw: ; отрисовка зениток
mov ebx, _ackack
xor ecx, ecx
xor esi, esi ; флаг наличия хотя бы одной зенитки (действующей или в перспективе)
ackack_draw_loop:
cmp ecx, 32
jae ackack_draw_loop_end
xor eax, eax
mov ax, [ebx]
cmp eax, 1
jne ackack_draw_continue ; если значение текущей ячейки в массиве не 1 то не рисуем зенитку
push ebx
push ecx
; в ebx получаем указатель на высоту постройки
mov ebx, ecx
shl ebx, 1
add ebx, _city ; получили указатель на высоту постройки
xor eax, eax
mov ax, [ebx] ; получили высоту постройки
cmp eax, 0
jle ackack_draw_continue2 ; если постройки нет то не рисуем зенитку
mov esi, 1
call ackack_bullet_start
; отрисовка зенитки
mov ebx, bmp_ackack ; получили указатель на картинку
cmp edx, 0
je ackack_draw_no_start_bullet
add ebx, 20*20*3 ; картинка со треляющей зениткой
ackack_draw_no_start_bullet:
; формирование координат картинки в edx
mov edx, ecx
shl edx, 4
shl ecx, 2
add edx, ecx
add edx, CITY_OFFSET
shl edx, 16
mov ecx, eax
shl eax, 4
shl ecx, 2
add eax, ecx
mov ecx, WINDOW_HEIGHT-GROUNG_HEIGHT
sub ecx, eax
sub ecx, 20 ; подняли координату на плитку выше постройки
add edx, ecx ; получили координаты
mov ecx, 20*0x00010000 + 20 ; задали размер картинки
mov eax, 7
int 0x40 ; выводим картинку
ackack_draw_continue2:
pop ecx
pop ebx
ackack_draw_continue:
add ebx, 2
inc ecx
jmp ackack_draw_loop
ackack_draw_loop_end:
cmp esi, 0
jne @f
; выключить сирену
call air_raid_warning_off
@@:
ret
ackack_check_bombing: ; проверка на подрыв зениток бомбами : eax - номер столбца
push eax
push ebx
push ecx
push edx
; проверка на попадание в столбец зенитки
mov ebx, eax
shl ebx, 1
push ebx
add ebx, _ackack
mov edx, ebx ; запомним указатель состояния зенитки в edx
xor eax, eax
mov ax, [ebx] ; в eax получили состояние зенитки
cmp eax, 1
jne acb_no_bombing ; проверка на наличие зенитки в данном столбце
xor eax, eax
mov [ebx], ax ; убираем зенитку
call ackack_next_wave
acb_no_bombing:
; проверка на полное уничножение столбца
pop ebx
add ebx, _city
xor eax, eax
mov ax, [ebx] ; в eax получили состояние зенитки
cmp eax, 0
jg acb_no_destroy_building ; проверка на наличие постройки в столбце
xor eax, eax
mov [ebx], ax ; убираем зенитку даже в перспективе
acb_no_destroy_building:
pop edx
pop ecx
pop ebx
pop eax
ret
ackack_next_wave: ; новая волна зениток
push eax
push ebx
push ecx
push edx
anw_begin:
mov ebx, _ackack
xor ecx, ecx
xor edx, edx ; флаг контроля за зенитками
anw_loop:
cmp ecx, 32
jae anw_loop_end
xor eax, eax
mov ax, [ebx]
cmp eax, 1
jle anw_continue ; если значение текущей ячейки <=1 то пропускаем
dec eax
mov [ebx], ax
cmp eax, 1
jg anw_no_active_ackack ; если значение текущей ячейки в массиве >1 то пропускаем
mov edx, 1 ; показываем что есть действующая зенитка
jmp anw_continue
anw_no_active_ackack:
cmp edx, 1
je anw_continue ; если флага 1 то пропускаем
mov edx, 2
anw_continue:
add ebx, 2
inc ecx
jmp anw_loop
anw_loop_end:
cmp edx, 2
je anw_begin
pop edx
pop ecx
pop ebx
pop eax
ret
ackack_bullet_start: ; запуск снарядов (входные: eax - высота столбца, ecx - номер столбца;
; выходные: edx - флаг нового запуска (0-нет, 1 -да)
push eax
push ebx
push ecx
cmp [_flag_air_raid_warning], 1
jne abs_no_start_bullet
; в ebx получаем указатель на положение снаряда
mov edx, eax
mov ebx, ecx
shl ebx, 2
add ebx, _ackack_bullet ; получили указатель на положение снаряда
mov eax, [ebx] ; получили положение снаряда
cmp eax, 0
jne abs_no_start_bullet ; если не 0, то не запускаем новый
; запуск снаряда
mov eax, edx ; помещаем в eax высоту постройки
; считаем координату вершины
mov ecx, eax
shl eax, 4
shl ecx, 2
add eax, ecx
mov ecx, WINDOW_HEIGHT-GROUNG_HEIGHT
sub ecx, eax
sub ecx, 20+BULLET_SIZE ; подняли координату на плитку выше постройки + высота снаяряда (в ecx - начальная координата снаряда)
mov [ebx], ecx ; задали начальную координату снаряду
cmp [_flag_bomberdatabin_ok], 1
jne @f
stdcall ssmix_playtrack, [_array_sounds+8*((( 3 ))-1)], [_array_sounds+8*((( 3 ))-1)+4], VOLUME_ACKACK,VOLUME_ACKACK , SSMIX_CHANMODE_SINGLE
@@:
mov edx, 1
jmp abs_end_start_bullet
abs_no_start_bullet:
mov edx, 0
abs_end_start_bullet:
pop ecx
pop ebx
pop eax
ret
ackack_bullet_proc: ; процедура обработки и отрисовки снарядов
mov ebx, _ackack_bullet
xor ecx, ecx
abp_loop:
cmp ecx, 32
jae abp_loop_end
mov eax, [ebx]
cmp eax, 0
je abp_continue
jl abp_low_zero
push ebx
push ecx
; стирание старого изображения
mov ebx, ecx
shl ebx, 4
shl ecx, 2
add ebx, ecx
add ebx, CITY_OFFSET
add ebx, 7 ; смещение снаряда
mov edx, ebx
shl ebx, 16
add ebx, edx ; в ebx координаты начала и конца отрезка по оси X
mov ecx, eax
mov edx, ecx
add edx, BULLET_SIZE ; прибавили длину снаряда
shl ecx, 16
add ecx, edx ; в ebx координаты начала и конца отрезка по оси Y
mov edx, BACK_COLOR
mov eax, 38
int 0x40
add ebx, 0x00050005
int 0x40
pop ecx
pop ebx
push ebx
push ecx
mov eax, [ebx]
sub eax, ACKACK_BULLET_SPEED
mov [ebx], eax
cmp eax, 0
jle abp_end_draw_bullet
call ackack_bullet_interaction_check
cmp edx, 0
je abp_no_bullet_interaction ; если не было взаимодействие то рисуем снаряды
xor eax, eax
mov [ebx], eax
jmp abp_end_draw_bullet
abp_no_bullet_interaction:
; рисуем снаряды
mov ebx, ecx
shl ebx, 4
shl ecx, 2
add ebx, ecx
add ebx, CITY_OFFSET
add ebx, 7 ; смещение снаряда
mov edx, ebx
shl ebx, 16
add ebx, edx ; в ebx координаты начала и конца отрезка по оси X
mov ecx, eax
mov edx, ecx
add edx, BULLET_SIZE ; прибавили длину снаряда
shl ecx, 16
add ecx, edx ; в ebx координаты начала и конца отрезка по оси Y
mov edx, 0x00000000
mov eax, 38
int 0x40
add ebx, 0x00050005
int 0x40
abp_end_draw_bullet:
pop ecx
pop ebx
jmp abp_continue
abp_low_zero:
xor eax, eax
mov [ebx], eax
abp_continue:
add ebx, 4
inc ecx
jmp abp_loop
abp_loop_end:
ret
ackack_bullet_interaction_check: ; проверка взаимодействия снарядов
; (входные: eax - координата снаряда по Y, ecx - номер столбца;
; выходные: edx - флаг попадания (0-нет, 1 -да))
push eax
push ebx
push ecx
; если самолет делает бочку то пропускаем
mov ebx, [_plane_health]
cmp ebx, 0
jle abic_with_plane_no
mov ebx, [_plane_state]
cmp ebx, 4
je abic_with_plane_no
cmp ebx, 5
je abic_with_plane_no
; проверка на координаты
mov ebx, [_Y_plane]
cmp eax, ebx
jl abic_with_plane_no ; если сняряд выше координаты попадяния то пропускаем
add ebx, 20 ; в ebx - координата попадания в самолет
cmp eax, ebx
jg abic_with_plane_no ; если сняряд ниже координаты попадяния то пропускаем
; считаем координату X вершины
mov edx, ecx
shl edx, 4
shl ecx, 2
add ecx, edx
add ecx, CITY_OFFSET
add ecx, 7 ; в ecx - координата X левого снаряда
mov ebx, [_X_plane]
add ebx, 32
cmp ecx, ebx
jg abic_with_plane_no
mov ebx, [_X_plane]
add ecx, 5
cmp ecx, ebx
jl abic_with_plane_no
; есть попадание!!!
mov ebx, [_plane_health]
sub ebx, 20
mov [_plane_health], ebx
cmp ebx, 0 ; проверка на game over
jg abic_no_plane_crash
mov [_plane_health], 0
mov eax, [_X_plane]
mov ebx, [_Y_plane]
call bang_add ; делаем взрыв
call game_over ; завершение игры
abic_no_plane_crash:
mov edx, 1
jmp abic_with_plane_end
abic_with_plane_no:
mov edx, 0
abic_with_plane_end:
pop ecx
pop ebx
pop eax
ret
; ===================================== МИР =========================================
ground_draw:
mov eax, 13
mov ebx, 0*0x00010000 + (WINDOW_WIDTH-10)
mov ecx, (WINDOW_HEIGHT-GROUNG_HEIGHT)*0x00010000 + (GROUNG_HEIGHT-5-20)
mov edx, GROUND_COLOR
int 0x40
mov eax, 38
mov ebx, 0*0x00010000 + (WINDOW_WIDTH-10)
mov ecx, (WINDOW_HEIGHT-GROUNG_HEIGHT)*0x00010000 + (WINDOW_HEIGHT-GROUNG_HEIGHT)
mov edx, 0x000000
int 0x40
ret
city_draw: ; отрисовка города
mov ebx, _city
xor edx, edx
city_draw_loop:
cmp edx, 32
jae city_draw_loop_end
xor eax, eax
mov ax, [ebx]
push ebx
push edx
mov ebx, bmp_tile
city_draw_loop2:
cmp eax, 0
jle city_draw_loop2_end
push eax
push edx
; формирование координат картинки в edx
mov ecx, edx
shl edx, 4
shl ecx, 2
add edx, ecx
add edx, CITY_OFFSET
shl edx, 16
mov ecx, eax
shl eax, 4
shl ecx, 2
add eax, ecx
mov ecx, WINDOW_HEIGHT-GROUNG_HEIGHT
sub ecx, eax
add edx, ecx ; получили координаты
mov ecx, 20*0x00010000 + 20 ; задали размер картинки
mov eax, 7
int 0x40 ; выводим картинку
pop edx
pop eax
dec eax
jmp city_draw_loop2
city_draw_loop2_end:
pop edx
pop ebx
add ebx, 2
inc edx
jmp city_draw_loop
city_draw_loop_end:
ret
clear_tiles: ; зачистка взорванных плиток: eax - номер столбца, ecx - нижняя плитка из удаляемых, edx - верхняя плитка из удаляемых
push eax
push ebx
push ecx
push edx
; формирование координаты X угла прямоугольника
mov ebx, eax
shl eax, 4
shl ebx, 2
add eax, ebx
add eax, CITY_OFFSET
; формирование координаты Y1 нижнего края нижней плитки
mov ebx, ecx
shl ecx, 4
shl ebx, 2
add ecx, ebx
mov ebx, WINDOW_HEIGHT-GROUNG_HEIGHT
sub ebx, ecx
mov ecx, ebx
add ecx, 20
; формирование координаты Y2 верхнего края верхней плитки
mov ebx, edx
shl edx, 4
shl ebx, 2
add edx, ebx
mov ebx, WINDOW_HEIGHT-GROUNG_HEIGHT
sub ebx, edx
mov edx, ebx
sub edx, 20 ; чтоб и зенитки стирать, если они есть
; задание координаты прямоугольника по Y=Y2 и его высоты H=Y1-Y2
sub ecx, edx
shl edx, 16
add ecx, edx
; задание координаты прямоугольника по X и его ширины 20
shl eax, 16
add eax, 20
mov ebx, eax
; отрисовка прямоугольника цвета фона
mov eax, 13
mov edx, BACK_COLOR
int 0x40
pop edx
pop ecx
pop ebx
pop eax
ret
load_level: ; загрузка уровня, в eax номер загружаемого уровня
mov eax, [_level_num]
dec eax
shl eax, 7 ; умножить на размер данных для одного уровня (128 байт)
mov ebx, levels
add ebx, eax ; в ebx указатель на начало загружаемого уровня
mov edx, cur_level
mov ecx, 0
load_level_loop:
cmp ecx, 128/4
jae load_level_loop_end
mov eax, [ebx]
mov [edx], eax
add ebx, 4
add edx, 4
inc ecx
jmp load_level_loop
load_level_loop_end:
load_level_end:
ret
; =================================== РАЗНОЕ ========================================
timer_x4:
mov eax, [_timer_x4]
inc eax
mov [_timer_x4],eax
cmp eax, 4
ja timer_x4_do
jmp timer_x4_end
timer_x4_do:
mov [_timer_x4],0
timer_x4_end:
ret
timer_x2:
mov eax, [_timer_x2]
inc eax
mov [_timer_x2],eax
cmp eax, 2
ja timer_x2_do
jmp timer_x2_end
timer_x2_do:
mov [_timer_x2],0
timer_x2_end:
ret
draw_window: ; отрисовка окна
mov eax,12
mov ebx,1
int 0x40
mov eax,0
mov ebx,100*65536+WINDOW_WIDTH
mov ecx,100*65536+WINDOW_HEIGHT
mov edx,0x34000000+BACK_COLOR
mov edi,_window_caption
int 0x40
mov eax,12
mov ebx,2
int 0x40
ret
draw_intro:
;заголовок
mov eax,4
mov ebx,(WINDOW_WIDTH/2-80)*65536 + 60
mov ecx,0x80000000
mov edx,_text_intro_title
int 0x40
;описание игры
mov eax,4
mov ebx,(WINDOW_WIDTH/2-200)*65536 + 120
mov ecx,0x80000000
mov edx,_text_intro_description1
int 0x40
;клавиши управления
mov eax,4
mov ebx,(WINDOW_WIDTH/2-60)*65536 + 200
mov ecx,0x80000000
mov edx,_text_intro_key_controls
int 0x40
mov eax,4
mov ebx,(WINDOW_WIDTH/2-70)*65536 + 230
mov ecx,0x80000000
mov edx,_text_intro_key_ctrl
int 0x40
mov eax,4
mov ebx,(WINDOW_WIDTH/2-70)*65536 + 245
mov ecx,0x80000000
mov edx,_text_intro_key_space
int 0x40
; выбор уровня
mov eax,4
mov ebx,(WINDOW_WIDTH/2-175)*65536 + 300
mov ecx,0x80000000
mov edx,_text_intro_select_level
int 0x40
mov eax,4
mov ebx,(WINDOW_WIDTH/2-25)*65536 + 320
mov ecx,0x80000000
mov edx,_text_intro_level_num
int 0x40
call draw_level_num
; установка громкости
mov eax,4
mov ebx,(WINDOW_WIDTH/2-175)*65536 + 350
mov ecx,0x80000000
mov edx,_text_intro_set_volume
int 0x40
mov eax,4
mov ebx,(WINDOW_WIDTH/2-25)*65536 + 370
mov ecx,0x80000000
mov edx,_text_intro_volume_num
int 0x40
call draw_volume_num
; запуск игры и выход
mov eax,4
mov ebx,(WINDOW_WIDTH/2-80)*65536 + 400
mov ecx,0x80FF0000
mov edx,_text_intro_start_space
int 0x40
mov eax,4
mov ebx,(WINDOW_WIDTH/2-30)*65536 + 460
mov ecx,0x80000000
mov edx,_text_intro_exit_key
int 0x40
ret
draw_level_num:
mov eax, 13
mov ebx, (WINDOW_WIDTH/2+25)*0x00010000 + 30
mov ecx, 320*0x00010000 + 15
mov edx, BACK_COLOR
int 0x40
mov eax, 47
mov ebx, 0x80020000
mov ecx, [_level_num]
mov edx, (WINDOW_WIDTH/2+25)*65536 + 320
mov esi,0x00000000
int 0x40
ret
draw_volume_num:
mov eax, 13
mov ebx, (WINDOW_WIDTH/2+35)*0x00010000 + 30
mov ecx, 370*0x00010000 + 15
mov edx, BACK_COLOR
int 0x40
mov eax, 47
mov ebx, 0x80020000
mov ecx, [_set_volume]
mov edx, (WINDOW_WIDTH/2+35)*65536 + 370
mov esi,0x00000000
int 0x40
ret
;---------------------------------------------------------------------------
;-------------------------------- данные -----------------------------------
;---------------------------------------------------------------------------
_game_state dd ?
_delay dd 6
_timer_x2 dd ?
_timer_x4 dd ?
_game_over_time dd ?
_flag_air_raid_warning dd ?
_flag_bomberdatabin_ok dd ?
_last_value_timecount dd ?
_X_plane dd ?
_Y_plane dd ?
_last_XY_plane dd ?
_VX_plane dd ?
_addit_VY_plane dd ?
_plane_state dd ? ; 0 - полет направо, 1- полет налево, 2-разворот справа-налево, 3-разворот слева-направо, 4 - бочка вправо, 5 - бочка влево
_plane_state_step dd ? ; номер шага текущего состояния (нужно для синхнопизации с анимацией)
_plane_health dd ? ; здоровье самолета
_bomb_count dd ?
_bomb_array rd 4*MAX_BOMBS
_bomb_delay_time dd ? ; задержка времени на сброс бомбы
_bang_array rd 2*MAX_BOMBS
_anim_pos_plane dd ?
; последовательности картинок анимации
_anim_array_uturn_rl dd 0,1,2,3,4,5,6,7,8
_anim_array_uturn_lr dd 8,7,6,9,10,11,2,1,0
_anim_array_barrel_r dd 0,1,2,12,13,14,15,16,0
_anim_array_barrel_l dd 8,17,18,19,20,21,6,7,8
cur_level:
; массив, в котором храниться текущее состояние города. изначально в него загрузаются уровни
_city rw 32
; массив, в котором храниться текущее состояние зениток. изначально в него загрузаются уровни
_ackack rw 32
; массив, в котором хранятся значения текущих координа снарядов от зениток
_ackack_bullet rd 32
; номер текущего уровня
_level_num dd 1
; задание уровней: 32 числа означают высоту строений (высота "в квадратах") для _level?_city
; и порядок появления зениток для _level?_ackack
levels:
_level1_city dw 0, 0, 0, 6, 5, 6, 5, 6, 3, 3, 3, 3, 3, 6, 7, 8, 8, 7, 6, 3, 3, 3, 3, 3, 6, 5, 6, 5, 6, 0, 0, 0
_level1_ackack dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
_level2_city dw 0, 0, 0, 5, 5, 2, 5, 7, 7, 2, 7, 9, 9, 9, 2, 9, 9, 2, 9, 9, 9, 7, 2, 7, 7, 5, 2, 5, 5, 0, 0, 0
_level2_ackack dw 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0
_level3_city dw 0, 0, 0,12,12,12, 9, 9, 9,12,12,12, 9, 7, 5, 3, 3, 5, 7, 9,12,12,12, 9, 9, 9,12,12,12, 0, 0, 0
_level3_ackack dw 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 4, 0, 3, 0, 2, 1, 1, 2, 0, 3, 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0
_level4_city dw 0, 0, 0,12,12,12, 3,12,12,12, 3, 1, 1, 6,12,18, 18,12, 6, 1, 1, 3,12,12,12, 3,12,12,12, 0, 0, 0
_level4_ackack dw 0, 0, 0, 0, 5, 0, 1, 0, 0, 0, 1, 0, 3, 0, 0, 2, 6, 0, 0, 3, 0, 1, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0
_level5_city dw 0, 5,10,10,10,10,15,15,15,15,17,17,17,17, 1,15, 15, 1,17,17,17,17,15,15,15,15,10,10,10,10, 5, 0
_level5_ackack dw 0, 8, 0, 9, 9, 0, 3, 3, 3, 3, 0, 0, 0, 0, 5, 1, 2, 5, 0, 0, 0, 0, 4, 4, 4, 4, 0,10,10, 0, 7, 0
; звуки
_count_sounds dd ?
_array_sounds rd 2*MAX_SOUNDS
_channel_sound_plane dd ? ; номер канала звука пропелера самолета
_channel_sound_arw dd ? ; номер канала звука сирены
_array_bombsoundchannels rd MAX_BOMBS ; массив номеров звуковых каналов для бомб
_set_volume dd 8 ; громкость 0..8
; разное
_s_current_dir rb 4096 ; путь к исполняемому файлу
file_info: ; информационная структура для работы с файлами
_fi_func dd ?
_fi_pos dd ?
dd 0
_fi_size dd ?
_fi_pbuff dd ?
db 0
_fi_pfilename dd ?
if lang eq ru_RU
include 'lang-ru_RU.inc' ; Encoded as CP866
else ; Default to en_US
include 'lang-en_US.inc'
end if
bmp_plane:
file "plane.bmp":54
bmp_bomb:
file "bomb.bmp":54
bmp_tile:
file "tile.bmp":54
bmp_ackack:
file "ackack.bmp":54
align 16
rb 0x100 ; резерв памяти для стека.
i_end: