diff --git a/build/graphics/casino3d.inc b/build/graphics/casino3d.inc index 2165e88..e3d7728 100644 --- a/build/graphics/casino3d.inc +++ b/build/graphics/casino3d.inc @@ -207,6 +207,7 @@ szTitleShop db "[KAZIK 3D CASINO] - szTitleATM db "[KAZIK 3D CASINO] - БАНКОМАТ",0 szTitleTerminal db "[KAZIK 3D CASINO] - ТЕРМИНАЛ ИГРОКА",0 szTitleObserver db "[KAZIK 3D CASINO] - РЕЖИМ НАБЛЮДАТЕЛЯ (ИИ)",0 +textCabinetFooter db "[ ВЫХОД: ВВЕДИТЕ 0 / ВЫБЕРИТЕ 'N' ДЛЯ ВОЗВРАТА В ЗАЛ ]",0 msgDancerTipped db "Вы бросили $100 танцовщице! УДАЧА АКТИВИРОВАНА!",0 msgNeedMoney db "Недостаточно денег в кошельке!",0 @@ -2684,15 +2685,55 @@ interaction_done: ret CheckInteractions ENDP -; --- LaunchClassicGame: Открытие отдельного окна для классической версии игры --- +; --- RenderCabinetBezel: Отрисовка аркадного безеля терминала на 3D экране --- +RenderCabinetBezel PROC uses ebx esi edi, pTitle:DWORD + ; Затемняем 3D-зал в буфере кадра (делим яркость пополам) + mov ecx, SCREEN_SIZE + xor esi, esi +dim_bezel_loop: + mov eax, [screenBuffer + esi*4] + shr eax, 1 + and eax, 007F7F7Fh + mov [screenBuffer + esi*4], eax + inc esi + loop dim_bezel_loop + + ; Внешняя золотая рамка терминала + invoke DrawBoxBorder, 10, 14, 300, 212, 000C0E14h, 00D8BC6Ah, 2 + + ; Шапка терминала с названием игры + invoke DrawBox, 12, 16, 296, 16, 00221A10h + invoke DrawString8x8, 20, 20, pTitle, 00F5E2B0h + + ; Подвальная плашка с подсказкой по выходу + invoke DrawBox, 12, 210, 296, 14, 00141416h + invoke DrawString8x8, 20, 213, OFFSET textCabinetFooter, 00AAAAAAh + + ; Выводим кадр безеля в окно + call Present3D + ret +RenderCabinetBezel ENDP + +; --- LaunchClassicGame: Встраивание игры в UI терминала казино --- LaunchClassicGame PROC uses ebx esi edi, pGameProc:DWORD, gameId:DWORD, pTitle:DWORD - LOCAL rc3D[16]:BYTE + LOCAL rcClient[16]:BYTE + LOCAL ptScreen[8]:BYTE + LOCAL fontInfo[84]:BYTE LOCAL conWnd:DWORD LOCAL conW:DWORD, conH:DWORD, conX:DWORD, conY:DWORD + LOCAL viewW:DWORD, viewH:DWORD + LOCAL offsetX:DWORD, offsetY:DWORD mov eax, gameId mov currentGameId, eax + ; 1. Рисуем золотой безель терминала на 3D экране + cmp pTitle, 0 + je @F + invoke RenderCabinetBezel, pTitle +@@: + + ; 2. Выделяем консоль invoke AllocConsole test eax, eax jz launch_ret @@ -2712,25 +2753,125 @@ LaunchClassicGame PROC uses ebx esi edi, pGameProc:DWORD, gameId:DWORD, pTitle:D call EnableAnsi call ConfigureConsoleSize + ; 3. Настраиваем шрифт Consolas Bold 16pt + lea edi, fontInfo + xor eax, eax + mov ecx, 21 + rep stosd + mov dword ptr fontInfo[0], 84 ; cbSize + mov word ptr fontInfo[8], 0 ; dwFontSize.X + mov word ptr fontInfo[10], 16 ; dwFontSize.Y + mov dword ptr fontInfo[16], 700 ; FontWeight = FW_BOLD + mov word ptr fontInfo[20], 'C' + mov word ptr fontInfo[22], 'o' + mov word ptr fontInfo[24], 'n' + mov word ptr fontInfo[26], 's' + mov word ptr fontInfo[28], 'o' + mov word ptr fontInfo[30], 'l' + mov word ptr fontInfo[32], 'a' + mov word ptr fontInfo[34], 's' + mov word ptr fontInfo[36], 0 + lea eax, fontInfo + invoke SetCurrentConsoleFontEx, hOut, 0, eax + + ; 4. Получаем дескриптор окна консоли invoke GetConsoleWindow mov conWnd, eax test eax, eax jz run_game_body + ; 5. Снимаем системную рамку Windows и заголовок с кнопками закрытия/сворачивания + invoke GetWindowLongA, conWnd, -16 ; GWL_STYLE + and eax, NOT (00C00000h or 00040000h or 00080000h or 00010000h or 00020000h) + or eax, 80000000h ; WS_POPUP + invoke SetWindowLongA, conWnd, -16, eax + + ; Связываем как дочернее/принадлежащее окно к окну игры cmp h3DWnd, 0 je show_con_fallback + invoke SetWindowLongA, conWnd, -8, h3DWnd ; GWL_HWNDPARENT - lea eax, rc3D - invoke GetWindowRect, h3DWnd, eax - mov eax, dword ptr rc3D[0] - add eax, 40 + ; 6. Вычисляем точные координаты для посадки экрана внутрь безеля + lea eax, rcClient + invoke GetClientRect, h3DWnd, eax + mov esi, dword ptr rcClient[8] ; ширина клиентской области + mov edi, dword ptr rcClient[12] ; высота клиентской области + test esi, esi + jz show_con_fallback + test edi, edi + jz show_con_fallback + + ; Расчет вьюпорта 4:3 точно как в Present3D + mov viewW, esi + mov eax, esi + imul eax, 3 + shr eax, 2 + cmp eax, edi + jle calc_view_h + mov eax, edi + imul eax, 4 + xor edx, edx + mov ecx, 3 + div ecx + mov viewW, eax + mov eax, edi +calc_view_h: + mov viewH, eax + + mov ebx, esi + sub ebx, viewW + shr ebx, 1 + mov offsetX, ebx + + mov ebx, edi + sub ebx, viewH + shr ebx, 1 + mov offsetY, ebx + + ; Экранные координаты левого верхнего угла клиентской области + mov dword ptr ptScreen[0], 0 + mov dword ptr ptScreen[4], 0 + lea eax, ptScreen + invoke ClientToScreen, h3DWnd, eax + + ; conW = viewW * 280 / 320 (внутреннее окно безеля) + mov eax, viewW + imul eax, 280 + xor edx, edx + mov ecx, 320 + div ecx + mov conW, eax + + ; conH = viewH * 168 / 240 + mov eax, viewH + imul eax, 168 + xor edx, edx + mov ecx, 240 + div ecx + mov conH, eax + + ; conX = ptScreen.x + offsetX + (viewW * 20 / 320) + mov eax, viewW + imul eax, 20 + xor edx, edx + mov ecx, 320 + div ecx + add eax, offsetX + add eax, dword ptr ptScreen[0] mov conX, eax - mov eax, dword ptr rc3D[4] - add eax, 40 + + ; conY = ptScreen.y + offsetY + (viewH * 38 / 240) + mov eax, viewH + imul eax, 38 + xor edx, edx + mov ecx, 240 + div ecx + add eax, offsetY + add eax, dword ptr ptScreen[4] mov conY, eax - mov conW, 960 - mov conH, 680 - invoke SetWindowPos, conWnd, 0, conX, conY, conW, conH, 40h ; SWP_SHOWWINDOW + + ; Позиционируем безрамочный экран точно внутрь золотой рамки безеля + invoke SetWindowPos, conWnd, 0, conX, conY, conW, conH, 20h or 40h ; SWP_FRAMECHANGED | SWP_SHOWWINDOW jmp set_con_focus show_con_fallback: @@ -2740,12 +2881,15 @@ set_con_focus: invoke SetFocus, conWnd run_game_body: + ; Запуск оригинальной игры! call pGameProc + ; Закрываем консоль invoke FreeConsole mov hOut, 0 mov hIn, 0 + ; Возвращаем фокус в окно 3D игры cmp h3DWnd, 0 je cleanup_game_input invoke SetForegroundWindow, h3DWnd diff --git a/build/graphics/poker.asm b/build/graphics/poker.asm index 39bdc15..9592eb3 100644 --- a/build/graphics/poker.asm +++ b/build/graphics/poker.asm @@ -79,6 +79,8 @@ SetConsoleTitleA PROTO :DWORD GetWindowRect PROTO :DWORD, :DWORD SetWindowPos PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD SetFocus PROTO :DWORD +ClientToScreen PROTO :DWORD, :DWORD +SetCurrentConsoleFontEx PROTO :DWORD, :DWORD, :DWORD mciSendStringA PROTO :DWORD, :DWORD, :DWORD, :DWORD waveOutSetVolume PROTO :DWORD, :DWORD AnimFrameDelay PROTO :DWORD diff --git a/build/graphics/poker.exe b/build/graphics/poker.exe index 8e7557b..43286fd 100644 Binary files a/build/graphics/poker.exe and b/build/graphics/poker.exe differ diff --git a/casino3d.inc b/casino3d.inc index 2165e88..e3d7728 100644 --- a/casino3d.inc +++ b/casino3d.inc @@ -207,6 +207,7 @@ szTitleShop db "[KAZIK 3D CASINO] - szTitleATM db "[KAZIK 3D CASINO] - БАНКОМАТ",0 szTitleTerminal db "[KAZIK 3D CASINO] - ТЕРМИНАЛ ИГРОКА",0 szTitleObserver db "[KAZIK 3D CASINO] - РЕЖИМ НАБЛЮДАТЕЛЯ (ИИ)",0 +textCabinetFooter db "[ ВЫХОД: ВВЕДИТЕ 0 / ВЫБЕРИТЕ 'N' ДЛЯ ВОЗВРАТА В ЗАЛ ]",0 msgDancerTipped db "Вы бросили $100 танцовщице! УДАЧА АКТИВИРОВАНА!",0 msgNeedMoney db "Недостаточно денег в кошельке!",0 @@ -2684,15 +2685,55 @@ interaction_done: ret CheckInteractions ENDP -; --- LaunchClassicGame: Открытие отдельного окна для классической версии игры --- +; --- RenderCabinetBezel: Отрисовка аркадного безеля терминала на 3D экране --- +RenderCabinetBezel PROC uses ebx esi edi, pTitle:DWORD + ; Затемняем 3D-зал в буфере кадра (делим яркость пополам) + mov ecx, SCREEN_SIZE + xor esi, esi +dim_bezel_loop: + mov eax, [screenBuffer + esi*4] + shr eax, 1 + and eax, 007F7F7Fh + mov [screenBuffer + esi*4], eax + inc esi + loop dim_bezel_loop + + ; Внешняя золотая рамка терминала + invoke DrawBoxBorder, 10, 14, 300, 212, 000C0E14h, 00D8BC6Ah, 2 + + ; Шапка терминала с названием игры + invoke DrawBox, 12, 16, 296, 16, 00221A10h + invoke DrawString8x8, 20, 20, pTitle, 00F5E2B0h + + ; Подвальная плашка с подсказкой по выходу + invoke DrawBox, 12, 210, 296, 14, 00141416h + invoke DrawString8x8, 20, 213, OFFSET textCabinetFooter, 00AAAAAAh + + ; Выводим кадр безеля в окно + call Present3D + ret +RenderCabinetBezel ENDP + +; --- LaunchClassicGame: Встраивание игры в UI терминала казино --- LaunchClassicGame PROC uses ebx esi edi, pGameProc:DWORD, gameId:DWORD, pTitle:DWORD - LOCAL rc3D[16]:BYTE + LOCAL rcClient[16]:BYTE + LOCAL ptScreen[8]:BYTE + LOCAL fontInfo[84]:BYTE LOCAL conWnd:DWORD LOCAL conW:DWORD, conH:DWORD, conX:DWORD, conY:DWORD + LOCAL viewW:DWORD, viewH:DWORD + LOCAL offsetX:DWORD, offsetY:DWORD mov eax, gameId mov currentGameId, eax + ; 1. Рисуем золотой безель терминала на 3D экране + cmp pTitle, 0 + je @F + invoke RenderCabinetBezel, pTitle +@@: + + ; 2. Выделяем консоль invoke AllocConsole test eax, eax jz launch_ret @@ -2712,25 +2753,125 @@ LaunchClassicGame PROC uses ebx esi edi, pGameProc:DWORD, gameId:DWORD, pTitle:D call EnableAnsi call ConfigureConsoleSize + ; 3. Настраиваем шрифт Consolas Bold 16pt + lea edi, fontInfo + xor eax, eax + mov ecx, 21 + rep stosd + mov dword ptr fontInfo[0], 84 ; cbSize + mov word ptr fontInfo[8], 0 ; dwFontSize.X + mov word ptr fontInfo[10], 16 ; dwFontSize.Y + mov dword ptr fontInfo[16], 700 ; FontWeight = FW_BOLD + mov word ptr fontInfo[20], 'C' + mov word ptr fontInfo[22], 'o' + mov word ptr fontInfo[24], 'n' + mov word ptr fontInfo[26], 's' + mov word ptr fontInfo[28], 'o' + mov word ptr fontInfo[30], 'l' + mov word ptr fontInfo[32], 'a' + mov word ptr fontInfo[34], 's' + mov word ptr fontInfo[36], 0 + lea eax, fontInfo + invoke SetCurrentConsoleFontEx, hOut, 0, eax + + ; 4. Получаем дескриптор окна консоли invoke GetConsoleWindow mov conWnd, eax test eax, eax jz run_game_body + ; 5. Снимаем системную рамку Windows и заголовок с кнопками закрытия/сворачивания + invoke GetWindowLongA, conWnd, -16 ; GWL_STYLE + and eax, NOT (00C00000h or 00040000h or 00080000h or 00010000h or 00020000h) + or eax, 80000000h ; WS_POPUP + invoke SetWindowLongA, conWnd, -16, eax + + ; Связываем как дочернее/принадлежащее окно к окну игры cmp h3DWnd, 0 je show_con_fallback + invoke SetWindowLongA, conWnd, -8, h3DWnd ; GWL_HWNDPARENT - lea eax, rc3D - invoke GetWindowRect, h3DWnd, eax - mov eax, dword ptr rc3D[0] - add eax, 40 + ; 6. Вычисляем точные координаты для посадки экрана внутрь безеля + lea eax, rcClient + invoke GetClientRect, h3DWnd, eax + mov esi, dword ptr rcClient[8] ; ширина клиентской области + mov edi, dword ptr rcClient[12] ; высота клиентской области + test esi, esi + jz show_con_fallback + test edi, edi + jz show_con_fallback + + ; Расчет вьюпорта 4:3 точно как в Present3D + mov viewW, esi + mov eax, esi + imul eax, 3 + shr eax, 2 + cmp eax, edi + jle calc_view_h + mov eax, edi + imul eax, 4 + xor edx, edx + mov ecx, 3 + div ecx + mov viewW, eax + mov eax, edi +calc_view_h: + mov viewH, eax + + mov ebx, esi + sub ebx, viewW + shr ebx, 1 + mov offsetX, ebx + + mov ebx, edi + sub ebx, viewH + shr ebx, 1 + mov offsetY, ebx + + ; Экранные координаты левого верхнего угла клиентской области + mov dword ptr ptScreen[0], 0 + mov dword ptr ptScreen[4], 0 + lea eax, ptScreen + invoke ClientToScreen, h3DWnd, eax + + ; conW = viewW * 280 / 320 (внутреннее окно безеля) + mov eax, viewW + imul eax, 280 + xor edx, edx + mov ecx, 320 + div ecx + mov conW, eax + + ; conH = viewH * 168 / 240 + mov eax, viewH + imul eax, 168 + xor edx, edx + mov ecx, 240 + div ecx + mov conH, eax + + ; conX = ptScreen.x + offsetX + (viewW * 20 / 320) + mov eax, viewW + imul eax, 20 + xor edx, edx + mov ecx, 320 + div ecx + add eax, offsetX + add eax, dword ptr ptScreen[0] mov conX, eax - mov eax, dword ptr rc3D[4] - add eax, 40 + + ; conY = ptScreen.y + offsetY + (viewH * 38 / 240) + mov eax, viewH + imul eax, 38 + xor edx, edx + mov ecx, 240 + div ecx + add eax, offsetY + add eax, dword ptr ptScreen[4] mov conY, eax - mov conW, 960 - mov conH, 680 - invoke SetWindowPos, conWnd, 0, conX, conY, conW, conH, 40h ; SWP_SHOWWINDOW + + ; Позиционируем безрамочный экран точно внутрь золотой рамки безеля + invoke SetWindowPos, conWnd, 0, conX, conY, conW, conH, 20h or 40h ; SWP_FRAMECHANGED | SWP_SHOWWINDOW jmp set_con_focus show_con_fallback: @@ -2740,12 +2881,15 @@ set_con_focus: invoke SetFocus, conWnd run_game_body: + ; Запуск оригинальной игры! call pGameProc + ; Закрываем консоль invoke FreeConsole mov hOut, 0 mov hIn, 0 + ; Возвращаем фокус в окно 3D игры cmp h3DWnd, 0 je cleanup_game_input invoke SetForegroundWindow, h3DWnd diff --git a/poker.asm b/poker.asm index 39bdc15..9592eb3 100644 --- a/poker.asm +++ b/poker.asm @@ -79,6 +79,8 @@ SetConsoleTitleA PROTO :DWORD GetWindowRect PROTO :DWORD, :DWORD SetWindowPos PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD SetFocus PROTO :DWORD +ClientToScreen PROTO :DWORD, :DWORD +SetCurrentConsoleFontEx PROTO :DWORD, :DWORD, :DWORD mciSendStringA PROTO :DWORD, :DWORD, :DWORD, :DWORD waveOutSetVolume PROTO :DWORD, :DWORD AnimFrameDelay PROTO :DWORD diff --git a/poker.exe b/poker.exe index 8e7557b..43286fd 100644 Binary files a/poker.exe and b/poker.exe differ