diff --git a/build/graphics/poker.exe b/build/graphics/poker.exe index 6a31bf6..5e91e8b 100644 Binary files a/build/graphics/poker.exe and b/build/graphics/poker.exe differ diff --git a/poker.asm b/poker.asm index 4c5070b..3ebe31f 100644 --- a/poker.asm +++ b/poker.asm @@ -1935,7 +1935,7 @@ stage_test_loop: invoke TowerReportRoundOutcome, 1 ; 4. Check outcome state - cmp stageLoop, 10 + cmp stageLoop, 6 jae stage_check_champ cmp towerFloorState, TOWER_STATE_CLEAR diff --git a/poker.exe b/poker.exe index 6a31bf6..5e91e8b 100644 Binary files a/poker.exe and b/poker.exe differ diff --git a/poker.obj b/poker.obj index 169bba0..498d9ee 100644 Binary files a/poker.obj and b/poker.obj differ diff --git a/src_graphics/hell_tower.inc b/src_graphics/hell_tower.inc index 5fd3d83..b793816 100644 --- a/src_graphics/hell_tower.inc +++ b/src_graphics/hell_tower.inc @@ -1,599 +1,574 @@ -; --- hell_tower.inc: Implementation of Hell Tower (10-floor Boss Rush) --- -.code - -FreeTowerMinigameAssets PROC - call FreeBuckshotAssets3D - call FreeRussianAssets3D - call FreeCardTableAssets3D - call FreeNativeCoinArt3D - call FreeNativeWheelArt3D - ret -FreeTowerMinigameAssets ENDP - -InitHellTower3D PROC - call FreeTowerMinigameAssets - mov tournamentMode, 1 - mov towerStage, 1 - mov towerFloorState, TOWER_STATE_BRIEFING - mov towerAnimClock, 0 - mov towerCalloutAnim, 0 - - mov eax, towerFloorY[0] - mov towerCursorY, eax - mov towerCursorTargetY, eax - - invoke LoadAnimPack3D, OFFSET hellTowerMenuArt3D, OFFSET hellTowerMenuPath3D - - call StopTowerMusic - mov engineMode, MODE_HELL_TOWER - call ClearKeys3D - ret -InitHellTower3D ENDP - -TowerExitToHall PROC - call StopTowerMusic - call FreeTowerMinigameAssets - mov tournamentMode, 0 - mov engineMode, MODE_WALK - call ClearKeys3D - ret -TowerExitToHall ENDP - -TowerLaunchCurrentFloor PROC uses ebx esi edi - mov eax, towerStage - dec eax - cmp eax, 10 - jae @F - jmp launch_valid -@@: - xor eax, eax -launch_valid: - mov edx, towerFloorModes[eax*4] - mov towerCurrentGame, edx - mov towerFloorState, TOWER_STATE_IN_GAME - - ; Launch corresponding game - cmp edx, MODE_COIN - jne @F - call InitCoinGame - mov engineMode, MODE_COIN - jmp launch_done -@@: - cmp edx, MODE_DICE - jne @F - call InitDiceGame - mov engineMode, MODE_DICE - jmp launch_done -@@: - cmp edx, MODE_SKULLS - jne @F - call InitSkullsGame - mov engineMode, MODE_SKULLS - jmp launch_done -@@: - cmp edx, MODE_BLACKJACK - jne @F - call InitNativeBlackjack3D - mov engineMode, MODE_BLACKJACK - jmp launch_done -@@: - cmp edx, MODE_POKER - jne @F - call InitNativePoker3D - mov engineMode, MODE_POKER - jmp launch_done -@@: - cmp edx, MODE_RUSSIAN - jne @F - call InitRussianGame3D - mov engineMode, MODE_RUSSIAN - jmp launch_done -@@: - cmp edx, MODE_ROULETTE - jne @F - call InitNativeWheel3D - mov engineMode, MODE_ROULETTE - jmp launch_done -@@: - cmp edx, MODE_DURAK - jne @F - call InitNativeDurak3D - mov engineMode, MODE_DURAK - jmp launch_done -@@: - cmp edx, MODE_SKILL - jne @F - call InitSkillGame - mov engineMode, MODE_SKILL - jmp launch_done -@@: - cmp edx, MODE_BUCKSHOT - jne launch_done - call InitBuckshot3D - mov engineMode, MODE_BUCKSHOT - -launch_done: - call ClearKeys3D - ret -TowerLaunchCurrentFloor ENDP - -TowerReportRoundOutcome PROC uses eax outcome:DWORD - cmp tournamentMode, 1 - jne report_exit - mov eax, outcome - cmp eax, 1 - jne report_loss - - ; --- Victory --- - cmp towerStage, 10 - jae report_champion - - mov towerFloorState, TOWER_STATE_CLEAR - mov towerCalloutAnim, 0 - mov eax, towerStage - dec eax - cmp eax, 10 - jae @F - mov edx, towerFloorY[eax*4] - mov towerCursorTargetY, edx -@@: - invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1 - mov engineMode, MODE_HELL_TOWER - call ClearKeys3D - ret - -report_champion: - mov towerFloorState, TOWER_STATE_CHAMPION - mov eax, towerPrizeAmount - add bankroll, eax - invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1 - call SaveProgress3D - mov engineMode, MODE_HELL_TOWER - call ClearKeys3D - ret - -report_loss: - invoke TriggerCharmLossProtection, 0 - test eax, eax - jz @F - mov towerFloorState, TOWER_STATE_BRIEFING - invoke CopyString3D, OFFSET msgCharmTowerSave, OFFSET flashMessage - mov flashTimer, 140 - mov engineMode, MODE_HELL_TOWER - call ClearKeys3D - ret -@@: - mov towerFloorState, TOWER_STATE_DEFEAT - call StopTowerMusic - invoke PlayCasinoSound3D, OFFSET soundRoundLose, 0, 1 - mov engineMode, MODE_HELL_TOWER - call ClearKeys3D - ret - -report_exit: - ret -TowerReportRoundOutcome ENDP - -HandleHellTowerInput PROC - mov eax, towerFloorState - cmp eax, TOWER_STATE_BRIEFING - je input_briefing - cmp eax, TOWER_STATE_CLEAR - je input_clear - cmp eax, TOWER_STATE_DEFEAT - je input_defeat - cmp eax, TOWER_STATE_CHAMPION - je input_champion - ret - -input_briefing: - invoke Pressed3D, 1Bh ; ESC - test eax, eax - jz @F - call TowerExitToHall - ret -@@: - invoke Pressed3D, 20h ; SPACE - test eax, eax - jnz start_stage - invoke Pressed3D, 0Dh ; ENTER - test eax, eax - jnz start_stage - ret -start_stage: - call TowerLaunchCurrentFloor - ret - -input_clear: - invoke Pressed3D, 1Bh ; ESC - test eax, eax - jz @F - call TowerExitToHall - ret -@@: - invoke Pressed3D, 20h ; SPACE - test eax, eax - jnz advance_stage - invoke Pressed3D, 0Dh ; ENTER - test eax, eax - jnz advance_stage - ret -advance_stage: - inc towerStage - mov towerFloorState, TOWER_STATE_BRIEFING - mov towerCalloutAnim, 0 - mov eax, towerStage - dec eax - cmp eax, 10 - jae @F - mov edx, towerFloorY[eax*4] - mov towerCursorTargetY, edx -@@: - call ClearKeys3D - ret - -input_defeat: - invoke Pressed3D, 1Bh ; ESC - test eax, eax - jnz exit_to_hall - invoke Pressed3D, 20h ; SPACE - test eax, eax - jnz exit_to_hall - invoke Pressed3D, 0Dh ; ENTER - test eax, eax - jnz exit_to_hall - ret - -input_champion: - invoke Pressed3D, 1Bh ; ESC - test eax, eax - jnz exit_to_hall - invoke Pressed3D, 20h ; SPACE - test eax, eax - jnz exit_to_hall - invoke Pressed3D, 0Dh ; ENTER - test eax, eax - jnz exit_to_hall - ret - -exit_to_hall: - call TowerExitToHall - ret -HandleHellTowerInput ENDP - -RenderHellTower3D PROC uses ebx esi edi - local cardX:DWORD, cardY:DWORD, cardW:DWORD, cardH:DWORD - local currY:DWORD, tgtY:DWORD - - ; 1. Background: draw HellTower menu art if loaded, else fallback to maroon - cmp hellTowerMenuArt3D.pixels, 0 - je fallback_clear - - cmp hellTowerMenuArt3D.imageWidth, SCREEN_W - jne fallback_sprite - cmp hellTowerMenuArt3D.height, SCREEN_H - jne fallback_sprite - - mov esi, hellTowerMenuArt3D.pixels - lea edi, screenBuffer - mov ecx, SCREEN_SIZE - rep movsd - jmp bg_done - -fallback_sprite: - invoke DrawAnimSprite3D, OFFSET hellTowerMenuArt3D, 0, 0, 0, SCREEN_W, SCREEN_H - jmp bg_done - -fallback_clear: - lea edi, screenBuffer - mov ecx, SCREEN_SIZE - mov eax, 00100202h - rep stosd - -bg_done: - ; 2. Update towerAnimClock - inc towerAnimClock - - ; 3. Smooth cursor Y movement towards towerCursorTargetY (exponential damping) - mov eax, towerCursorTargetY - cmp eax, towerCursorY - je cursor_update_done - jg cursor_move_down - - ; Moving UP towards tower peak (target < current) - mov ecx, towerCursorY - sub ecx, eax - shr ecx, 2 - inc ecx - sub towerCursorY, ecx - mov eax, towerCursorTargetY - cmp towerCursorY, eax - jge cursor_update_done - mov towerCursorY, eax - jmp cursor_update_done - -cursor_move_down: - ; Moving DOWN towards tower base (target > current) - mov ecx, eax - sub ecx, towerCursorY - shr ecx, 2 - inc ecx - add towerCursorY, ecx - mov eax, towerCursorTargetY - cmp towerCursorY, eax - jle cursor_update_done - mov towerCursorY, eax - -cursor_update_done: - ; 4. Update sliding callout animation (0 to 100%) - cmp towerCalloutAnim, 100 - jge callout_step_done - add towerCalloutAnim, 10 - cmp towerCalloutAnim, 100 - jle callout_step_done - mov towerCalloutAnim, 100 -callout_step_done: - - ; 5. Calculate sliding callout card dimensions occupying free left space: - ; Max width = 206, fixed right bound = 214, top = 20, height = 208 - mov cardH, 208 - mov cardY, 20 - - ; cardW = 206 * towerCalloutAnim / 100 - mov eax, 206 - imul eax, towerCalloutAnim - xor edx, edx - mov ecx, 100 - div ecx - cmp eax, 10 - jae @F - mov eax, 10 -@@: - mov cardW, eax - - ; cardX = 214 - cardW - mov edx, 214 - sub edx, cardW - mov cardX, edx - - ; 6. Draw glowing cursor & indicator on the tower (Right side) - ; Indicator line from card right edge (214) to cursor on tower (X=224) - mov eax, towerCursorY - invoke DrawBox, 214, eax, 10, 2, 00FF4444h - - ; Cursor chevron/diamond at X=224 - mov eax, towerCursorY - sub eax, 3 - invoke DrawBoxBorder, 224, eax, 7, 7, 00FF3300h, 00FFDD44h, 1 - - ; Pulsing flame pip on the tower floor at X=234 - mov eax, towerAnimClock - and eax, 8 - jz pip_bright - mov edx, 00EE3300h - jmp pip_draw -pip_bright: - mov edx, 00FFAA22h -pip_draw: - mov eax, towerCursorY - sub eax, 2 - invoke DrawBox, 234, eax, 5, 5, edx - - ; 7. Draw Callout Box (outer and inner border with deep infernal tint) - invoke DrawBoxBorder, cardX, cardY, cardW, cardH, 00120202h, 00CC2222h, 2 - mov eax, cardX - add eax, 2 - mov edx, cardY - add edx, 2 - mov ecx, cardW - sub ecx, 4 - mov ebx, cardH - sub ebx, 4 - invoke DrawBoxBorder, eax, edx, ecx, ebx, 000C0202h, 00551111h, 1 - - ; Only render full content once card has slid out sufficiently (cardW >= 120) - cmp cardW, 120 - jb render_tower_done - - ; Header Banner: "ÊÀÇÈÍÎ 3D - ÀÄÑÊÀß ÁÀØÍß" - mov eax, cardX - add eax, 6 - mov ecx, cardW - sub ecx, 12 - invoke DrawBoxBorder, eax, 26, ecx, 18, 00220404h, 00FF4444h, 1 - mov eax, cardX - add eax, 12 - invoke DrawString8x8, eax, 31, OFFSET towerHeader, 00FFDD66h - - ; Floor indicator: "ÝÒÀÆ N / 10" - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 50, OFFSET towerFloorPrefix, 00FF6666h - invoke FormatNumber, towerStage, OFFSET hudNumBuffer - mov eax, cardX - add eax, 50 - invoke DrawString8x8, eax, 50, OFFSET hudNumBuffer, 00FFFFFFh - mov eax, cardX - add eax, 58 - invoke DrawString8x8, eax, 50, OFFSET towerOfTen, 00AAAAAAh - - ; Specific state content inside the card - mov eax, towerFloorState - cmp eax, TOWER_STATE_BRIEFING - je render_card_briefing - cmp eax, TOWER_STATE_CLEAR - je render_card_clear - cmp eax, TOWER_STATE_DEFEAT - je render_card_defeat - cmp eax, TOWER_STATE_CHAMPION - je render_card_champion - jmp render_tower_done - -render_card_briefing: - ; Boss & Game sub-card - mov eax, cardX - add eax, 6 - mov ecx, cardW - sub ecx, 12 - invoke DrawBoxBorder, eax, 64, ecx, 62, 001E0404h, 00881818h, 1 - - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 70, OFFSET towerEnemyLabel, 00FFAA55h - mov eax, towerStage - dec eax - mov edx, towerBossNames[eax*4] - mov eax, cardX - add eax, 56 - invoke DrawString8x8, eax, 70, edx, 00FFFFFFh - - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 84, OFFSET towerGameLabel, 00FFAA55h - mov eax, towerStage - dec eax - mov edx, towerGameNames[eax*4] - mov eax, cardX - add eax, 56 - invoke DrawString8x8, eax, 84, edx, 00FFDD66h - - mov eax, towerStage - dec eax - mov edx, towerDescriptions[eax*4] - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 100, edx, 00CCCCCCh - - ; Rules & warning - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 134, OFFSET towerRuleText, 00FFAA33h - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 148, OFFSET towerLossWarning, 00EE4444h - - ; Bankroll & Prize - mov eax, cardX - add eax, 10 - invoke DrawString8x8, eax, 164, OFFSET textBank3D, 00AAAAAAh - invoke FormatNumber, bankroll, OFFSET hudNumBuffer - mov eax, cardX - add eax, 56 - invoke DrawString8x8, eax, 164, OFFSET hudNumBuffer, 0066FF66h - - mov eax, cardX - add eax, 110 - invoke DrawString8x8, eax, 164, OFFSET towerPrizePrompt, 00FFAA55h - invoke FormatNumber, towerPrizeAmount, OFFSET hudNumBuffer - mov eax, cardX - add eax, 154 - invoke DrawString8x8, eax, 164, OFFSET hudNumBuffer, 00FFDD44h - - ; Action Buttons (Start & Escape) - mov eax, cardX - add eax, 8 - invoke DrawBoxBorder, eax, 186, 92, 22, 003D0C0Ch, 00FF4444h, 1 - mov eax, cardX - add eax, 14 - invoke DrawString8x8, eax, 193, OFFSET towerStartBtn, 00FFFFFFh - - mov eax, cardX - add eax, 106 - invoke DrawBoxBorder, eax, 186, 92, 22, 00220606h, 00882222h, 1 - mov eax, cardX - add eax, 114 - invoke DrawString8x8, eax, 193, OFFSET towerEscBtn, 00AAAAAAh - jmp render_tower_done - -render_card_clear: - mov eax, cardX - add eax, 8 - mov ecx, cardW - sub ecx, 16 - invoke DrawBoxBorder, eax, 74, ecx, 60, 00082208h, 0033CC33h, 2 - mov eax, cardX - add eax, 14 - invoke DrawString8x8, eax, 86, OFFSET towerClearTitle, 0066FF66h - mov eax, cardX - add eax, 14 - invoke DrawString8x8, eax, 108, OFFSET towerClearDesc, 00FFFFFFh - - mov eax, cardX - add eax, 18 - mov ecx, cardW - sub ecx, 36 - invoke DrawBoxBorder, eax, 186, ecx, 22, 00114411h, 0044FF44h, 1 - mov eax, cardX - add eax, 42 - invoke DrawString8x8, eax, 193, OFFSET towerNextBtn, 00FFFFFFh - jmp render_tower_done - -render_card_defeat: - mov eax, cardX - add eax, 8 - mov ecx, cardW - sub ecx, 16 - invoke DrawBoxBorder, eax, 74, ecx, 60, 002A0404h, 00FF2222h, 2 - mov eax, cardX - add eax, 14 - invoke DrawString8x8, eax, 86, OFFSET towerDefeatTitle, 00FF4444h - mov eax, cardX - add eax, 14 - invoke DrawString8x8, eax, 108, OFFSET towerDefeatDesc, 00FFFFFFh - - mov eax, cardX - add eax, 16 - mov ecx, cardW - sub ecx, 32 - invoke DrawBoxBorder, eax, 186, ecx, 22, 00441010h, 00FF4444h, 1 - mov eax, cardX - add eax, 22 - invoke DrawString8x8, eax, 193, OFFSET towerReturnBtn, 00FFFFFFh - jmp render_tower_done - -render_card_champion: - mov eax, cardX - add eax, 8 - mov ecx, cardW - sub ecx, 16 - invoke DrawBoxBorder, eax, 68, ecx, 72, 00332200h, 00FFD700h, 2 - mov eax, cardX - add eax, 12 - invoke DrawString8x8, eax, 78, OFFSET towerChampTitle, 00FFE066h - mov eax, cardX - add eax, 16 - invoke DrawString8x8, eax, 96, OFFSET towerChampSubtitle, 00FFFFFFh - mov eax, cardX - add eax, 14 - invoke DrawString8x8, eax, 116, OFFSET towerPrizeText, 0066FF66h - - mov eax, cardX - add eax, 16 - mov ecx, cardW - sub ecx, 32 - invoke DrawBoxBorder, eax, 186, ecx, 22, 00443300h, 00FFCC00h, 1 - mov eax, cardX - add eax, 22 - invoke DrawString8x8, eax, 193, OFFSET towerReturnBtn, 00FFFFFFh - -render_tower_done: - ret -RenderHellTower3D ENDP - -RenderTowerInGameBadge PROC - cmp tournamentMode, 1 - jne badge_done - cmp engineMode, MODE_HELL_TOWER - je badge_done - cmp engineMode, MODE_WALK - je badge_done - - invoke DrawBoxBorder, 4, 4, 96, 16, 00220404h, 00FF3333h, 1 - invoke DrawString8x8, 8, 8, OFFSET towerHudBadge, 00FFAA55h - invoke FormatNumber, towerStage, OFFSET hudNumBuffer - invoke DrawString8x8, 64, 8, OFFSET hudNumBuffer, 00FFFFFFh - invoke DrawString8x8, 72, 8, OFFSET towerHudOfTen, 00AAAAAAh - -badge_done: - ret -RenderTowerInGameBadge ENDP +; --- hell_tower.inc: Implementation of Hell Tower (6-floor Boss Rush) --- +.code + +FreeTowerMinigameAssets PROC + call FreeBuckshotAssets3D + call FreeRussianAssets3D + call FreeCardTableAssets3D + call FreeNativeCoinArt3D + call FreeNativeWheelArt3D + ret +FreeTowerMinigameAssets ENDP + +InitHellTower3D PROC + call FreeTowerMinigameAssets + mov tournamentMode, 1 + mov towerStage, 1 + mov towerFloorState, TOWER_STATE_BRIEFING + mov towerAnimClock, 0 + mov towerCalloutAnim, 0 + + mov eax, towerFloorY[0] + mov towerCursorY, eax + mov towerCursorTargetY, eax + + invoke LoadAnimPack3D, OFFSET hellTowerMenuArt3D, OFFSET hellTowerMenuPath3D + + call StopTowerMusic + mov engineMode, MODE_HELL_TOWER + call ClearKeys3D + ret +InitHellTower3D ENDP + +TowerExitToHall PROC + call StopTowerMusic + call FreeTowerMinigameAssets + mov tournamentMode, 0 + mov engineMode, MODE_WALK + call ClearKeys3D + ret +TowerExitToHall ENDP + +TowerLaunchCurrentFloor PROC uses ebx esi edi + mov eax, towerStage + dec eax + cmp eax, 6 + jae @F + jmp launch_valid +@@: + xor eax, eax +launch_valid: + mov edx, towerFloorModes[eax*4] + mov towerCurrentGame, edx + mov towerFloorState, TOWER_STATE_IN_GAME + + ; Launch corresponding game + cmp edx, MODE_COIN + jne @F + call InitCoinGame + mov engineMode, MODE_COIN + jmp launch_done +@@: + cmp edx, MODE_DICE + jne @F + call InitDiceGame + mov engineMode, MODE_DICE + jmp launch_done +@@: + cmp edx, MODE_BLACKJACK + jne @F + call InitNativeBlackjack3D + mov engineMode, MODE_BLACKJACK + jmp launch_done +@@: + cmp edx, MODE_RUSSIAN + jne @F + call InitRussianGame3D + mov engineMode, MODE_RUSSIAN + jmp launch_done +@@: + cmp edx, MODE_ROULETTE + jne @F + call InitNativeWheel3D + mov engineMode, MODE_ROULETTE + jmp launch_done +@@: + cmp edx, MODE_BUCKSHOT + jne launch_done + call InitBuckshot3D + mov engineMode, MODE_BUCKSHOT + +launch_done: + call ClearKeys3D + ret +TowerLaunchCurrentFloor ENDP + +TowerReportRoundOutcome PROC uses eax outcome:DWORD + cmp tournamentMode, 1 + jne report_exit + mov eax, outcome + cmp eax, 1 + jne report_loss + + ; --- Victory --- + cmp towerStage, 6 + jae report_champion + + mov towerFloorState, TOWER_STATE_CLEAR + mov towerCalloutAnim, 0 + mov eax, towerStage + dec eax + cmp eax, 6 + jae @F + mov edx, towerFloorY[eax*4] + mov towerCursorTargetY, edx +@@: + invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1 + mov engineMode, MODE_HELL_TOWER + call ClearKeys3D + ret + +report_champion: + mov towerFloorState, TOWER_STATE_CHAMPION + mov eax, towerPrizeAmount + add bankroll, eax + invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1 + call SaveProgress3D + mov engineMode, MODE_HELL_TOWER + call ClearKeys3D + ret + +report_loss: + invoke TriggerCharmLossProtection, 0 + test eax, eax + jz @F + mov towerFloorState, TOWER_STATE_BRIEFING + invoke CopyString3D, OFFSET msgCharmTowerSave, OFFSET flashMessage + mov flashTimer, 140 + mov engineMode, MODE_HELL_TOWER + call ClearKeys3D + ret +@@: + mov towerFloorState, TOWER_STATE_DEFEAT + call StopTowerMusic + invoke PlayCasinoSound3D, OFFSET soundRoundLose, 0, 1 + mov engineMode, MODE_HELL_TOWER + call ClearKeys3D + ret + +report_exit: + ret +TowerReportRoundOutcome ENDP + +HandleHellTowerInput PROC + mov eax, towerFloorState + cmp eax, TOWER_STATE_BRIEFING + je input_briefing + cmp eax, TOWER_STATE_CLEAR + je input_clear + cmp eax, TOWER_STATE_DEFEAT + je input_defeat + cmp eax, TOWER_STATE_CHAMPION + je input_champion + ret + +input_briefing: + invoke Pressed3D, 1Bh ; ESC + test eax, eax + jz @F + call TowerExitToHall + ret +@@: + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz start_stage + invoke Pressed3D, 0Dh ; ENTER + test eax, eax + jnz start_stage + ret +start_stage: + call TowerLaunchCurrentFloor + ret + +input_clear: + invoke Pressed3D, 1Bh ; ESC + test eax, eax + jz @F + call TowerExitToHall + ret +@@: + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz advance_stage + invoke Pressed3D, 0Dh ; ENTER + test eax, eax + jnz advance_stage + ret +advance_stage: + inc towerStage + mov towerFloorState, TOWER_STATE_BRIEFING + mov towerCalloutAnim, 0 + mov eax, towerStage + dec eax + cmp eax, 6 + jae @F + mov edx, towerFloorY[eax*4] + mov towerCursorTargetY, edx +@@: + call ClearKeys3D + ret + +input_defeat: + invoke Pressed3D, 1Bh ; ESC + test eax, eax + jnz exit_to_hall + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz exit_to_hall + invoke Pressed3D, 0Dh ; ENTER + test eax, eax + jnz exit_to_hall + ret + +input_champion: + invoke Pressed3D, 1Bh ; ESC + test eax, eax + jnz exit_to_hall + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz exit_to_hall + invoke Pressed3D, 0Dh ; ENTER + test eax, eax + jnz exit_to_hall + ret + +exit_to_hall: + call TowerExitToHall + ret +HandleHellTowerInput ENDP + +RenderHellTower3D PROC uses ebx esi edi + local cardX:DWORD, cardY:DWORD, cardW:DWORD, cardH:DWORD + local currY:DWORD, tgtY:DWORD + + ; 1. Background: draw HellTower menu art if loaded, else fallback to maroon + cmp hellTowerMenuArt3D.pixels, 0 + je fallback_clear + + cmp hellTowerMenuArt3D.imageWidth, SCREEN_W + jne fallback_sprite + cmp hellTowerMenuArt3D.height, SCREEN_H + jne fallback_sprite + + mov esi, hellTowerMenuArt3D.pixels + lea edi, screenBuffer + mov ecx, SCREEN_SIZE + rep movsd + jmp bg_done + +fallback_sprite: + invoke DrawAnimSprite3D, OFFSET hellTowerMenuArt3D, 0, 0, 0, SCREEN_W, SCREEN_H + jmp bg_done + +fallback_clear: + lea edi, screenBuffer + mov ecx, SCREEN_SIZE + mov eax, 00100202h + rep stosd + +bg_done: + ; 2. Update towerAnimClock + inc towerAnimClock + + ; 3. Smooth cursor Y movement towards towerCursorTargetY (exponential damping) + mov eax, towerCursorTargetY + cmp eax, towerCursorY + je cursor_update_done + jg cursor_move_down + + ; Moving UP towards tower peak (target < current) + mov ecx, towerCursorY + sub ecx, eax + shr ecx, 2 + inc ecx + sub towerCursorY, ecx + mov eax, towerCursorTargetY + cmp towerCursorY, eax + jge cursor_update_done + mov towerCursorY, eax + jmp cursor_update_done + +cursor_move_down: + ; Moving DOWN towards tower base (target > current) + mov ecx, eax + sub ecx, towerCursorY + shr ecx, 2 + inc ecx + add towerCursorY, ecx + mov eax, towerCursorTargetY + cmp towerCursorY, eax + jle cursor_update_done + mov towerCursorY, eax + +cursor_update_done: + ; 4. Update sliding callout animation (0 to 100%) + cmp towerCalloutAnim, 100 + jge callout_step_done + add towerCalloutAnim, 10 + cmp towerCalloutAnim, 100 + jle callout_step_done + mov towerCalloutAnim, 100 +callout_step_done: + + ; 5. Calculate sliding callout card dimensions occupying free left space: + ; Max width = 206, fixed right bound = 214, top = 16, height = 208 + mov cardH, 208 + mov cardY, 16 + + ; cardW = 206 * towerCalloutAnim / 100 + mov eax, 206 + imul eax, towerCalloutAnim + xor edx, edx + mov ecx, 100 + div ecx + cmp eax, 10 + jae @F + mov eax, 10 +@@: + mov cardW, eax + + ; cardX = 214 - cardW + mov edx, 214 + sub edx, cardW + mov cardX, edx + + ; 6. Draw glowing cursor & indicator on the tower (Right side) + ; Indicator line from card right edge (214) to cursor on tower (X=224) + mov eax, towerCursorY + invoke DrawBox, 214, eax, 10, 2, 00FF4444h + + ; Cursor chevron/diamond at X=224 + mov eax, towerCursorY + sub eax, 3 + invoke DrawBoxBorder, 224, eax, 7, 7, 00FF3300h, 00FFDD44h, 1 + + ; Pulsing flame pip on the tower floor at X=234 + mov eax, towerAnimClock + and eax, 8 + jz pip_bright + mov edx, 00EE3300h + jmp pip_draw +pip_bright: + mov edx, 00FFAA22h +pip_draw: + mov eax, towerCursorY + sub eax, 2 + invoke DrawBox, 234, eax, 5, 5, edx + + ; 7. Draw Callout Box (outer and inner border with deep infernal tint) + invoke DrawBoxBorder, cardX, cardY, cardW, cardH, 00120202h, 00CC2222h, 2 + mov eax, cardX + add eax, 2 + mov edx, cardY + add edx, 2 + mov ecx, cardW + sub ecx, 4 + mov ebx, cardH + sub ebx, 4 + invoke DrawBoxBorder, eax, edx, ecx, ebx, 000C0202h, 00551111h, 1 + + ; Only render full content once card has slid out sufficiently (cardW >= 120) + cmp cardW, 120 + jb render_tower_done + + ; Header Banner: "ÀÄÑÊÀß ÁÀØÍß" (Centered, NO "ÊÀÇÈÍÎ 3D") + mov eax, cardX + add eax, 6 + mov ecx, cardW + sub ecx, 12 + invoke DrawBoxBorder, eax, 22, ecx, 18, 00220404h, 00FF4444h, 1 + mov eax, cardX + add eax, 55 + invoke DrawString8x8, eax, 27, OFFSET towerHeader, 00FFDD66h + + ; Floor indicator: "ÝÒÀÆ N / 6" and Prize prompt + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 46, OFFSET towerFloorPrefix, 00FF6666h + invoke FormatNumber, towerStage, OFFSET hudNumBuffer + mov eax, cardX + add eax, 52 + invoke DrawString8x8, eax, 46, OFFSET hudNumBuffer, 00FFFFFFh + mov eax, cardX + add eax, 60 + invoke DrawString8x8, eax, 46, OFFSET towerOfTen, 00AAAAAAh + + mov eax, cardX + add eax, 105 + invoke DrawString8x8, eax, 46, OFFSET towerPrizePrompt, 00FFAA55h + invoke FormatNumber, towerPrizeAmount, OFFSET hudNumBuffer + mov eax, cardX + add eax, 149 + invoke DrawString8x8, eax, 46, OFFSET hudNumBuffer, 00FFDD44h + + ; Specific state content inside the card + mov eax, towerFloorState + cmp eax, TOWER_STATE_BRIEFING + je render_card_briefing + cmp eax, TOWER_STATE_CLEAR + je render_card_clear + cmp eax, TOWER_STATE_DEFEAT + je render_card_defeat + cmp eax, TOWER_STATE_CHAMPION + je render_card_champion + jmp render_tower_done + +render_card_briefing: + ; Boss & Game sub-card (Y = 60 to 130) + mov eax, cardX + add eax, 6 + mov ecx, cardW + sub ecx, 12 + invoke DrawBoxBorder, eax, 60, ecx, 70, 001E0404h, 00881818h, 1 + + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 66, OFFSET towerEnemyLabel, 00FFAA55h + mov eax, towerStage + dec eax + mov edx, towerBossNames[eax*4] + mov eax, cardX + add eax, 60 + invoke DrawString8x8, eax, 66, edx, 00FFFFFFh + + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 80, OFFSET towerGameLabel, 00FFAA55h + mov eax, towerStage + dec eax + mov edx, towerGameNames[eax*4] + mov eax, cardX + add eax, 60 + invoke DrawString8x8, eax, 80, edx, 00FFDD66h + + mov eax, towerStage + dec eax + mov edx, towerDescriptions[eax*4] + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 98, edx, 00CCCCCCh + + ; Rules & warning box (Y = 134 to 166) + mov eax, cardX + add eax, 6 + mov ecx, cardW + sub ecx, 12 + invoke DrawBoxBorder, eax, 134, ecx, 32, 00180303h, 00661111h, 1 + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 139, OFFSET towerRuleText, 00FFAA33h + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 151, OFFSET towerLossWarning, 00FF5555h + + ; Bankroll & Prize (Y = 172) + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 172, OFFSET textBank3D, 00AAAAAAh + invoke FormatNumber, bankroll, OFFSET hudNumBuffer + mov eax, cardX + add eax, 60 + invoke DrawString8x8, eax, 172, OFFSET hudNumBuffer, 0066FF66h + + ; Action Buttons (Y = 188 to 212) + mov eax, cardX + add eax, 6 + invoke DrawBoxBorder, eax, 188, 93, 24, 003D0C0Ch, 00FF4444h, 1 + mov eax, cardX + add eax, 12 + invoke DrawString8x8, eax, 196, OFFSET towerStartBtn, 00FFFFFFh + + mov eax, cardX + add eax, 107 + invoke DrawBoxBorder, eax, 188, 93, 24, 00220606h, 00882222h, 1 + mov eax, cardX + add eax, 113 + invoke DrawString8x8, eax, 196, OFFSET towerEscBtn, 00AAAAAAh + jmp render_tower_done + +render_card_clear: + mov eax, cardX + add eax, 6 + mov ecx, cardW + sub ecx, 12 + invoke DrawBoxBorder, eax, 62, ecx, 80, 00082208h, 0033CC33h, 2 + mov eax, cardX + add eax, 51 + invoke DrawString8x8, eax, 76, OFFSET towerClearTitle, 0066FF66h + mov eax, cardX + add eax, 47 + invoke DrawString8x8, eax, 96, OFFSET towerClearDesc, 00FFFFFFh + + mov eax, cardX + add eax, 18 + invoke DrawBoxBorder, eax, 176, 170, 26, 00114411h, 0044FF44h, 1 + mov eax, cardX + add eax, 47 + invoke DrawString8x8, eax, 184, OFFSET towerNextBtn, 00FFFFFFh + jmp render_tower_done + +render_card_defeat: + mov eax, cardX + add eax, 6 + mov ecx, cardW + sub ecx, 12 + invoke DrawBoxBorder, eax, 62, ecx, 80, 002A0404h, 00FF2222h, 2 + mov eax, cardX + add eax, 31 + invoke DrawString8x8, eax, 76, OFFSET towerDefeatTitle, 00FF4444h + mov eax, cardX + add eax, 27 + invoke DrawString8x8, eax, 98, OFFSET towerDefeatDesc, 00FFFFFFh + + mov eax, cardX + add eax, 18 + invoke DrawBoxBorder, eax, 176, 170, 26, 00441010h, 00FF4444h, 1 + mov eax, cardX + add eax, 31 + invoke DrawString8x8, eax, 184, OFFSET towerReturnBtn, 00FFFFFFh + jmp render_tower_done + +render_card_champion: + mov eax, cardX + add eax, 6 + mov ecx, cardW + sub ecx, 12 + invoke DrawBoxBorder, eax, 58, ecx, 92, 00332200h, 00FFD700h, 2 + mov eax, cardX + add eax, 43 + invoke DrawString8x8, eax, 70, OFFSET towerChampTitle, 00FFE066h + mov eax, cardX + add eax, 27 + invoke DrawString8x8, eax, 90, OFFSET towerChampSubtitle, 00FFFFFFh + mov eax, cardX + add eax, 19 + invoke DrawString8x8, eax, 114, OFFSET towerPrizeText, 0066FF66h + + mov eax, cardX + add eax, 18 + invoke DrawBoxBorder, eax, 176, 170, 26, 00443300h, 00FFCC00h, 1 + mov eax, cardX + add eax, 31 + invoke DrawString8x8, eax, 184, OFFSET towerReturnBtn, 00FFFFFFh + +render_tower_done: + ret +RenderHellTower3D ENDP + +RenderTowerInGameBadge PROC + cmp tournamentMode, 1 + jne badge_done + cmp engineMode, MODE_HELL_TOWER + je badge_done + cmp engineMode, MODE_WALK + je badge_done + + invoke DrawBoxBorder, 4, 4, 88, 16, 00220404h, 00FF3333h, 1 + invoke DrawString8x8, 8, 8, OFFSET towerHudBadge, 00FFAA55h + invoke FormatNumber, towerStage, OFFSET hudNumBuffer + invoke DrawString8x8, 64, 8, OFFSET hudNumBuffer, 00FFFFFFh + invoke DrawString8x8, 72, 8, OFFSET towerHudOfTen, 00AAAAAAh + +badge_done: + ret +RenderTowerInGameBadge ENDP diff --git a/src_graphics/hell_tower_data.inc b/src_graphics/hell_tower_data.inc index eda5e96..213e92a 100644 --- a/src_graphics/hell_tower_data.inc +++ b/src_graphics/hell_tower_data.inc @@ -1,94 +1,84 @@ -; --- hell_tower_data.inc: Data for Hell Tower 3D --- -MODE_HELL_TOWER equ 23 -TOWER_STATE_BRIEFING equ 0 -TOWER_STATE_IN_GAME equ 1 -TOWER_STATE_CLEAR equ 2 -TOWER_STATE_DEFEAT equ 3 -TOWER_STATE_CHAMPION equ 4 - -InitHellTower3D PROTO -TowerExitToHall PROTO -TowerReportRoundOutcome PROTO :DWORD -RenderTowerInGameBadge PROTO -ResolveHellAssetPath PROTO :DWORD, :DWORD -FreeTowerMinigameAssets PROTO - -.data -towerStage dd 1 -towerFloorState dd 0 -towerAnimClock dd 0 -towerCurrentGame dd 0 -towerPrizeAmount dd 66600 -towerHudText db 91,32,0 - -hellTowerMenuArt3D AnimPack3D <0> -hellTowerMenuPath3D db "assets\animations\hall\helltower-menu.bin",0 - -towerFloorY dd 205, 186, 167, 148, 129, 110, 91, 72, 53, 34 -towerCursorY dd 205 -towerCursorTargetY dd 205 -towerCalloutAnim dd 0 - -towerPrizePrompt db 202,211,216,58,32,36,0 ; "КУШ: $" - -towerFloorModes dd MODE_COIN, MODE_DICE, MODE_SKULLS, MODE_BLACKJACK, MODE_POKER, MODE_RUSSIAN, MODE_ROULETTE, MODE_DURAK, MODE_SKILL, MODE_BUCKSHOT - -towerBoss1 db 193,197,209,32,192,199,192,208,210,192,0 -towerBoss2 db 196,197,204,206,205,32,202,206,209,210,197,201,0 -towerBoss3 db 215,197,208,205,206,202,205,200,198,205,200,202,0 -towerBoss4 db 202,208,211,207,220,197,32,207,208,197,200,209,207,206,196,205,197,201,0 -towerBoss5 db 196,197,204,206,205,32,193,203,197,212,192,0 -towerBoss6 db 206,193,208,197,215,197,205,205,219,201,32,195,208,197,216,205,200,202,0 -towerBoss7 db 202,206,203,197,209,206,32,209,211,196,220,193,219,0 -towerBoss8 db 202,192,208,210,206,215,205,219,201,32,215,197,208,210,0 -towerBoss9 db 207,192,203,192,215,32,202,208,222,202,192,0 -towerBoss10 db 194,203,192,196,219,202,192,32,193,192,216,205,200,0 - -towerBossNames dd OFFSET towerBoss1, OFFSET towerBoss2, OFFSET towerBoss3, OFFSET towerBoss4, OFFSET towerBoss5, OFFSET towerBoss6, OFFSET towerBoss7, OFFSET towerBoss8, OFFSET towerBoss9, OFFSET towerBoss10 - -towerGame1 db 206,240,229,235,32,232,32,240,229,248,234,224,0 -towerGame2 db 202,238,241,242,232,0 -towerGame3 db 215,229,240,229,239,224,32,232,32,248,224,240,232,234,0 -towerGame4 db 50,49,32,47,32,206,247,234,238,0 -towerGame5 db 207,238,234,229,240,0 -towerGame6 db 208,243,241,241,234,224,255,32,240,243,235,229,242,234,224,0 -towerGame7 db 202,224,231,232,237,238,45,240,243,235,229,242,234,224,0 -towerGame8 db 196,243,240,224,234,0 -towerGame9 db 202,240,254,234,58,32,83,107,105,108,108,32,67,104,101,99,107,0 -towerGame10 db 66,117,99,107,115,104,111,116,32,82,111,117,108,101,116,116,101,0 - -towerGameNames dd OFFSET towerGame1, OFFSET towerGame2, OFFSET towerGame3, OFFSET towerGame4, OFFSET towerGame5, OFFSET towerGame6, OFFSET towerGame7, OFFSET towerGame8, OFFSET towerGame9, OFFSET towerGame10 - -towerDesc1 db 211,227,224,228,224,233,32,241,242,238,240,238,237,243,32,236,238,237,229,242,251,46,0 -towerDesc2 db 207,229,240,229,225,240,238,241,252,32,228,229,236,238,237,224,32,226,32,241,243,236,236,229,32,234,238,241,242,229,233,46,0 -towerDesc3 db 205,224,233,228,232,32,228,243,248,243,32,239,238,228,32,247,229,240,229,239,238,236,46,0 -towerDesc4 db 209,238,225,229,240,232,32,50,49,32,238,247,234,238,32,232,32,239,238,225,229,228,232,32,234,240,243,239,252,229,46,0 -towerDesc5 db 194,241,234,240,238,233,32,234,224,240,242,251,32,232,32,239,238,225,229,228,232,32,226,32,239,238,234,229,240,46,0 -towerDesc6 db 49,32,239,224,242,240,238,237,32,226,32,225,224,240,224,225,224,237,229,58,32,226,251,230,232,226,232,46,0 -towerDesc7 db 209,228,229,235,224,233,32,241,242,224,226,234,243,32,237,224,32,240,243,235,229,242,234,229,46,0 -towerDesc8 db 206,241,242,224,226,252,32,247,184,240,242,224,32,226,32,228,243,240,224,234,224,245,46,0 -towerDesc9 db 207,238,239,224,228,232,32,226,32,231,238,237,243,32,232,32,241,238,240,226,232,241,252,32,241,32,234,240,254,234,224,46,0 -towerDesc10 db 196,243,253,235,252,32,237,224,32,228,240,238,225,238,226,232,234,224,245,32,231,224,32,230,232,231,237,252,33,0 - -towerDescriptions dd OFFSET towerDesc1, OFFSET towerDesc2, OFFSET towerDesc3, OFFSET towerDesc4, OFFSET towerDesc5, OFFSET towerDesc6, OFFSET towerDesc7, OFFSET towerDesc8, OFFSET towerDesc9, OFFSET towerDesc10 - -towerHeader db 202,192,199,200,205,206,32,51,68,32,45,32,192,196,209,202,192,223,32,193,192,216,205,223,0 -towerFloorPrefix db 221,210,192,198,32,0 -towerOfTen db 32,47,32,49,48,0 -towerEnemyLabel db 194,208,192,195,58,32,0 -towerGameLabel db 200,195,208,192,58,32,0 -towerRuleText db 49,48,32,225,232,242,226,32,239,238,228,240,255,228,32,225,229,231,32,239,240,224,226,224,32,237,224,32,238,248,232,225,234,243,0 -towerLossWarning db 207,238,240,224,230,229,237,232,229,32,45,32,226,238,231,226,240,224,242,32,226,32,245,238,235,235,32,234,224,231,232,237,238,0 -towerStartBtn db 91,207,208,206,193,197,203,93,32,194,32,193,206,201,0 -towerEscBtn db 91,69,83,67,93,32,209,193,197,198,192,210,220,0 -towerClearTitle db 221,210,192,198,32,199,192,215,200,217,197,205,33,32,194,208,192,195,32,207,206,194,197,208,198,197,205,33,0 -towerClearDesc db 194,240,224,227,32,239,238,226,229,240,230,229,237,33,32,194,239,229,240,229,228,232,32,237,238,226,251,233,32,253,242,224,230,46,0 -towerNextBtn db 91,207,208,206,193,197,203,93,32,196,192,203,220,216,197,0 -towerDefeatTitle db 194,219,32,207,192,203,200,32,194,32,192,196,209,202,206,201,32,193,192,216,205,197,46,46,46,0 -towerDefeatDesc db 194,224,248,224,32,228,243,248,224,32,237,224,226,229,234,232,32,241,227,238,240,229,235,224,32,226,32,192,228,243,46,0 -towerReturnBtn db 91,207,208,206,193,197,203,32,47,32,69,83,67,93,32,194,32,213,206,203,203,32,202,192,199,200,205,206,0 -towerChampTitle db 210,208,200,211,204,212,33,32,192,196,209,202,192,223,32,193,192,216,205,223,32,207,206,202,206,208,197,205,192,33,0 -towerChampSubtitle db 194,219,32,45,32,215,197,204,207,200,206,205,32,192,196,209,202,206,201,32,193,192,216,205,200,33,0 -towerPrizeText db 209,211,207,197,208,207,208,200,199,58,32,43,36,54,54,44,54,48,48,32,194,32,193,192,205,202,208,206,203,203,33,0 -towerHudBadge db 193,192,216,205,223,58,32,0 -towerHudOfTen db 47,49,48,0 +; --- hell_tower_data.inc: Data for Hell Tower 3D (6 Floors) --- +MODE_HELL_TOWER equ 23 +TOWER_STATE_BRIEFING equ 0 +TOWER_STATE_IN_GAME equ 1 +TOWER_STATE_CLEAR equ 2 +TOWER_STATE_DEFEAT equ 3 +TOWER_STATE_CHAMPION equ 4 + +InitHellTower3D PROTO +TowerExitToHall PROTO +TowerReportRoundOutcome PROTO :DWORD +RenderTowerInGameBadge PROTO +ResolveHellAssetPath PROTO :DWORD, :DWORD +FreeTowerMinigameAssets PROTO + +.data +towerStage dd 1 +towerFloorState dd 0 +towerAnimClock dd 0 +towerCurrentGame dd 0 +towerPrizeAmount dd 66600 +towerHudText db 91,32,0 + +hellTowerMenuArt3D AnimPack3D <0> +hellTowerMenuPath3D db "assets\animations\hall\helltower-menu.bin",0 + +; 6 floors: 1=205, 2=174, 3=143, 4=112, 5=81, 6=50 +towerFloorY dd 205, 174, 143, 112, 81, 50 +towerCursorY dd 205 +towerCursorTargetY dd 205 +towerCalloutAnim dd 0 + +towerPrizePrompt db 202,211,216,58,32,36,0 + +towerFloorModes dd MODE_COIN, MODE_DICE, MODE_BLACKJACK, MODE_RUSSIAN, MODE_ROULETTE, MODE_BUCKSHOT + +towerBoss1 db 193,229,241,32,192,231,224,240,242,224,0 +towerBoss2 db 196,229,236,238,237,32,202,238,241,242,229,233,0 +towerBoss3 db 202,240,243,239,252,229,32,210,252,236,251,0 +towerBoss4 db 209,243,228,252,255,32,192,228,224,0 +towerBoss5 db 213,238,231,255,232,237,32,208,243,235,229,242,234,232,0 +towerBoss6 db 194,235,224,228,251,234,224,32,193,224,248,237,232,0 + +towerBossNames dd OFFSET towerBoss1, OFFSET towerBoss2, OFFSET towerBoss3, OFFSET towerBoss4, OFFSET towerBoss5, OFFSET towerBoss6 + +towerGame1 db 206,240,229,235,32,232,32,240,229,248,234,224,0 +towerGame2 db 202,238,241,242,232,0 +towerGame3 db 50,49,32,47,32,206,247,234,238,0 +towerGame4 db 208,243,241,241,234,224,255,32,240,243,235,229,242,234,224,0 +towerGame5 db 202,224,231,232,237,238,45,240,243,235,229,242,234,224,0 +towerGame6 db 66,117,99,107,115,104,111,116,32,82,111,117,108,101,116,116,101,0 + +towerGameNames dd OFFSET towerGame1, OFFSET towerGame2, OFFSET towerGame3, OFFSET towerGame4, OFFSET towerGame5, OFFSET towerGame6 + +towerDesc1 db 211,227,224,228,224,233,32,241,242,238,240,238,237,243,32,236,238,237,229,242,251,46,0 +towerDesc2 db 205,224,225,229,240,232,32,225,238,235,252,248,229,32,238,247,234,238,226,46,0 +towerDesc3 db 206,225,251,227,240,224,233,32,234,240,243,239,252,229,32,226,32,50,49,46,0 +towerDesc4 db 49,32,239,224,242,240,238,237,46,32,194,251,230,232,226,232,33,0 +towerDesc5 db 211,227,224,228,224,233,32,247,232,241,235,238,32,240,243,235,229,242,234,232,46,0 +towerDesc6 db 196,243,253,235,252,32,237,224,32,228,240,238,225,238,226,232,234,229,33,0 + +towerDescriptions dd OFFSET towerDesc1, OFFSET towerDesc2, OFFSET towerDesc3, OFFSET towerDesc4, OFFSET towerDesc5, OFFSET towerDesc6 + +towerHeader db 192,196,209,202,192,223,32,193,192,216,205,223,0 +towerFloorPrefix db 221,210,192,198,32,0 +towerOfTen db 32,47,32,54,0 +towerEnemyLabel db 194,208,192,195,58,32,0 +towerGameLabel db 200,195,208,192,58,32,0 +towerRuleText db 54,32,253,242,224,230,229,233,32,225,229,231,32,239,238,240,224,230,229,237,232,233,0 +towerLossWarning db 207,238,240,224,230,229,237,232,229,32,45,32,226,238,231,226,240,224,242,33,0 +towerStartBtn db 91,69,78,84,69,82,93,32,193,206,201,0 +towerEscBtn db 91,69,83,67,93,32,205,192,199,192,196,0 +towerClearTitle db 221,210,192,198,32,199,192,215,200,217,197,205,33,0 +towerClearDesc db 194,240,224,227,32,239,238,226,229,240,230,229,237,33,0 +towerNextBtn db 91,69,78,84,69,82,93,32,196,192,203,220,216,197,0 +towerDefeatTitle db 194,219,32,207,206,195,200,193,203,200,32,194,32,193,192,216,205,197,33,0 +towerDefeatDesc db 196,243,248,224,32,241,227,238,240,229,235,224,32,226,32,192,228,243,46,0 +towerReturnBtn db 91,69,83,67,93,32,194,32,213,206,203,203,32,202,192,199,200,205,206,0 +towerChampTitle db 193,192,216,205,223,32,207,206,202,206,208,197,205,192,33,0 +towerChampSubtitle db 194,251,32,45,32,194,235,224,228,251,234,224,32,193,224,248,237,232,33,0 +towerPrizeText db 202,211,216,58,32,43,36,54,54,44,54,48,48,32,194,32,193,192,205,202,33,0 +towerHudBadge db 193,192,216,205,223,58,32,0 +towerHudOfTen db 47,54,0 + diff --git a/tools/tests/render_hell_tower_preview.py b/tools/tests/render_hell_tower_preview.py index ca7b5e9..8b1aa4c 100644 --- a/tools/tests/render_hell_tower_preview.py +++ b/tools/tests/render_hell_tower_preview.py @@ -1,4 +1,4 @@ -"""Render full simulation of Hell Tower menu at floors 1, 5, 10.""" +"""Render simulation of Hell Tower with 6 floors and strict boundary checks.""" import struct from pathlib import Path from PIL import Image, ImageDraw, ImageFont @@ -7,109 +7,167 @@ ROOT = Path(__file__).resolve().parents[2] MENU_BIN = ROOT / "assets/animations/hall/helltower-menu.bin" ART_DIR = Path(r"C:\Users\IKER\.gemini\antigravity-cli\brain\c2d69e9d-8822-4f06-923a-36a9194468d6") -FLOOR_Y = [205, 186, 167, 148, 129, 110, 91, 72, 53, 34] +# 6 Floors Y in logical 320x240 coordinates +FLOOR_Y = [205, 174, 143, 112, 81, 50] BOSSES = [ - "БЕС АЗАРТА", "ДЕМОН КОСТЕЙ", "ЧЕРНОКНИЖНИК", "КРУПЬЕ ПРЕИСПОДНЕЙ", "ДЕМОН БЛЕФА", - "ОБРЕЧЕННЫЙ ГРЕШНИК", "КОЛЕСО СУДЬБЫ", "КАРТОЧНЫЙ ЧЕРТ", "ПАЛАЧ КРЮКА", "ВЛАДЫКА БАШНИ" + "Бес Азарта", + "Демон Костей", + "Крупье Тьмы", + "Судья Ада", + "Хозяин Рулетки", + "Владыка Башни" ] GAMES = [ - "Орел и решка", "Кости", "Черепа и шарик", "21 / Очко", "Покер", - "Русская рулетка", "Казино-рулетка", "Дурак", "Крюк: Skill Check", "Buckshot Roulette" + "Орел и решка", + "Кости", + "21 / Очко", + "Русская рулетка", + "Казино-рулетка", + "Buckshot Roulette" ] DESCS = [ "Угадай сторону монеты.", - "Перебрось демона в сумме костей.", - "Найди душу под черепом.", - "Собери 21 очко и победи крупье.", - "Вскрой карты и победи в покер.", - "1 патрон в барабане: выживи.", - "Сделай ставку на рулетке.", - "Оставь чёрта в дураках.", - "Попади в зону и сорвись с крюка.", - "Дуэль на дробовиках за жизнь!" + "Набери больше очков.", + "Обыграй крупье в 21.", + "1 патрон. Выживи!", + "Угадай число рулетки.", + "Дуэль на дробовике!" ] +SUB_NOTES = [ + "Один бросок решит все.", + "Бросай кости против беса.", + "Собери больше, но не перебор.", + "Крути барабан револьвера.", + "Ставь на черное или красное.", + "Заряжай картечь и стреляй!" +] -def render_menu_frame(stage: int, callout_anim: int = 100): - # 1. Load background from ANM1 pack +def render_menu_frame(stage: int, state: int = 0, callout_anim: int = 100): + # 1. Load background data = MENU_BIN.read_bytes() magic, w, h, frames, b_len = struct.unpack("<4sIIII", data[:20]) raw_bgra = data[20:20 + b_len] bg = Image.frombytes("RGBA", (w, h), raw_bgra, "raw", "BGRA") - - draw = ImageDraw.Draw(bg) - - floor_idx = stage - 1 + + # Scale down to 320x240 logical to replicate exact ASM blit logic + canvas = bg.resize((320, 240), Image.Resampling.LANCZOS) + draw = ImageDraw.Draw(canvas) + + floor_idx = max(0, min(5, stage - 1)) target_y = FLOOR_Y[floor_idx] - - # Calculate sliding card box + + # Sliding card dimensions card_h = 208 - card_y = 20 + card_y = 16 card_w = max(10, 206 * callout_anim // 100) card_x = 214 - card_w - - # Connector line + + # 1. Indicator line and cursor on tower draw.line([(214, target_y), (224, target_y)], fill=(255, 68, 68), width=2) - # Cursor chevron/diamond draw.rectangle([224, target_y - 3, 230, target_y + 3], fill=(255, 51, 0), outline=(255, 221, 68)) - # Pulsing flame pip draw.rectangle([234, target_y - 2, 238, target_y + 2], fill=(255, 170, 34)) - - # Outer and inner border of card + + # 2. Card outer/inner borders draw.rectangle([card_x, card_y, card_x + card_w, card_y + card_h], outline=(204, 34, 34), width=2) draw.rectangle([card_x + 2, card_y + 2, card_x + card_w - 2, card_y + card_h - 2], outline=(85, 17, 17), width=1) - + + inner_w = card_w - 12 + inner_x = card_x + 6 + if card_w >= 120: - # Header banner - draw.rectangle([card_x + 6, 26, card_x + card_w - 6, 44], fill=(34, 4, 4), outline=(255, 68, 68)) - draw.text((card_x + 12, 29), "КАЗИНО 3D - АДСКАЯ БАШНЯ", fill=(255, 221, 102)) + # Header banner: "АДСКАЯ БАШНЯ" (Centered, NO "КАЗИНО 3D") + hdr_w = len("АДСКАЯ БАШНЯ") * 8 + hdr_x = inner_x + (inner_w - hdr_w) // 2 + draw.rectangle([inner_x, 22, inner_x + inner_w, 40], fill=(34, 4, 4), outline=(255, 68, 68)) + draw.text((hdr_x, 26), "АДСКАЯ БАШНЯ", fill=(255, 221, 102)) + + # Floor & Bankroll / Prize indicator + draw.text((card_x + 12, 46), f"ЭТАЖ {stage} / 6", fill=(255, 102, 102)) + draw.text((card_x + 105, 46), "КУШ: $66,600", fill=(255, 221, 68)) + + if state == 0: # BRIEFING + # Subcard + draw.rectangle([inner_x, 60, inner_x + inner_w, 130], fill=(30, 4, 4), outline=(136, 24, 24)) + draw.text((card_x + 12, 66), f"ВРАГ: {BOSSES[floor_idx]}", fill=(255, 255, 255)) + draw.text((card_x + 12, 80), f"ИГРА: {GAMES[floor_idx]}", fill=(255, 221, 102)) + draw.text((card_x + 12, 96), DESCS[floor_idx], fill=(204, 204, 204)) + draw.text((card_x + 12, 112), SUB_NOTES[floor_idx], fill=(170, 170, 170)) + + # Rules & warning box + draw.rectangle([inner_x, 134, inner_x + inner_w, 166], fill=(24, 3, 3), outline=(102, 17, 17)) + draw.text((card_x + 12, 139), "6 этажей без поражений", fill=(255, 170, 51)) + draw.text((card_x + 12, 151), "Поражение - возврат!", fill=(255, 85, 85)) + + # Bank + draw.text((card_x + 12, 172), "БАНК: $10,000", fill=(102, 255, 102)) + draw.text((card_x + 115, 172), "НАГРАДА: +100%", fill=(255, 200, 50)) + + # Action Buttons + btn_w = 93 + draw.rectangle([inner_x, 188, inner_x + btn_w, 212], fill=(61, 12, 12), outline=(255, 68, 68)) + draw.text((inner_x + 12, 196), "[ENTER] БОЙ", fill=(255, 255, 255)) + + draw.rectangle([inner_x + 101, 188, inner_x + 101 + btn_w, 212], fill=(34, 6, 6), outline=(136, 34, 34)) + draw.text((inner_x + 113, 196), "[ESC] НАЗАД", fill=(170, 170, 170)) - # Floor indicator - draw.text((card_x + 10, 48), f"ЭТАЖ {stage} / 10", fill=(255, 102, 102)) + elif state == 2: # CLEAR + draw.rectangle([inner_x, 62, inner_x + inner_w, 142], fill=(8, 34, 8), outline=(51, 204, 51), width=2) + clr_w = len("ЭТАЖ ЗАЧИЩЕН!") * 8 + draw.text((inner_x + (inner_w - clr_w) // 2, 76), "ЭТАЖ ЗАЧИЩЕН!", fill=(102, 255, 102)) + sub_w = len("Враг повержен!") * 8 + draw.text((inner_x + (inner_w - sub_w) // 2, 96), "Враг повержен!", fill=(255, 255, 255)) + rwd_w = len("Путь наверх открыт!") * 8 + draw.text((inner_x + (inner_w - rwd_w) // 2, 116), "Путь наверх открыт!", fill=(255, 221, 102)) + + draw.rectangle([card_x + 18, 176, card_x + 188, 202], fill=(17, 68, 17), outline=(68, 255, 68)) + btn_w2 = len("[ENTER] ДАЛЬШЕ") * 8 + draw.text((card_x + 18 + (170 - btn_w2) // 2, 184), "[ENTER] ДАЛЬШЕ", fill=(255, 255, 255)) - # Boss & Game sub-card - draw.rectangle([card_x + 6, 64, card_x + card_w - 6, 126], fill=(30, 4, 4), outline=(136, 24, 24)) - draw.text((card_x + 10, 68), f"ВРАГ: {BOSSES[floor_idx]}", fill=(255, 255, 255)) - draw.text((card_x + 10, 82), f"ИГРА: {GAMES[floor_idx]}", fill=(255, 221, 102)) - draw.text((card_x + 10, 98), DESCS[floor_idx], fill=(204, 204, 204)) + elif state == 3: # DEFEAT + draw.rectangle([inner_x, 62, inner_x + inner_w, 142], fill=(42, 4, 4), outline=(255, 34, 34), width=2) + dft_w = len("ВЫ ПОГИБЛИ В БАШНЕ!") * 8 + draw.text((inner_x + (inner_w - dft_w) // 2, 76), "ВЫ ПОГИБЛИ В БАШНЕ!", fill=(255, 68, 68)) + sub_w = len("Душа сгорела в Аду.") * 8 + draw.text((inner_x + (inner_w - sub_w) // 2, 98), "Душа сгорела в Аду.", fill=(255, 255, 255)) + + draw.rectangle([card_x + 18, 176, card_x + 188, 202], fill=(68, 16, 16), outline=(255, 68, 68)) + btn_w2 = len("[ESC] В ХОЛЛ КАЗИНО") * 8 + draw.text((card_x + 18 + (170 - btn_w2) // 2, 184), "[ESC] В ХОЛЛ КАЗИНО", fill=(255, 255, 255)) - # Rules & warning - draw.text((card_x + 10, 132), "10 битв подряд без права на ошибку", fill=(255, 170, 51)) - draw.text((card_x + 10, 146), "Поражение - возврат в холл казино", fill=(238, 68, 68)) - - # Bankroll & Prize - draw.text((card_x + 10, 162), "БАНК: $10,000", fill=(102, 255, 102)) - draw.text((card_x + 110, 162), "КУШ: $66,600", fill=(255, 221, 68)) - - # Buttons - draw.rectangle([card_x + 8, 184, card_x + 100, 206], fill=(61, 12, 12), outline=(255, 68, 68)) - draw.text((card_x + 14, 191), "[ПРОБЕЛ] В БОЙ", fill=(255, 255, 255)) - - draw.rectangle([card_x + 106, 184, card_x + 198, 206], fill=(34, 6, 6), outline=(136, 34, 34)) - draw.text((card_x + 114, 191), "[ESC] СБЕЖАТЬ", fill=(170, 170, 170)) - - # Scale 2x for high quality artifact preview (640x480) - bg_hd = bg.resize((640, 480), Image.Resampling.NEAREST) - return bg_hd + elif state == 4: # CHAMPION + draw.rectangle([inner_x, 58, inner_x + inner_w, 150], fill=(51, 34, 0), outline=(255, 215, 0), width=2) + chm_w = len("БАШНЯ ПОКОРЕНА!") * 8 + draw.text((inner_x + (inner_w - chm_w) // 2, 70), "БАШНЯ ПОКОРЕНА!", fill=(255, 224, 102)) + sub_w = len("Вы - Владыка Башни!") * 8 + draw.text((inner_x + (inner_w - sub_w) // 2, 90), "Вы - Владыка Башни!", fill=(255, 255, 255)) + prz_w = len("КУШ: +$66,600 В БАНК!") * 8 + draw.text((inner_x + (inner_w - prz_w) // 2, 114), "КУШ: +$66,600 В БАНК!", fill=(102, 255, 102)) + + draw.rectangle([card_x + 18, 176, card_x + 188, 202], fill=(68, 51, 0), outline=(255, 204, 0)) + btn_w2 = len("[ESC] В ХОЛЛ КАЗИНО") * 8 + draw.text((card_x + 18 + (170 - btn_w2) // 2, 184), "[ESC] В ХОЛЛ КАЗИНО", fill=(255, 255, 255)) + # Scale 2x for full HD 640x480 preview + return canvas.resize((640, 480), Image.Resampling.NEAREST) def main(): ART_DIR.mkdir(parents=True, exist_ok=True) - f1 = render_menu_frame(1, 100) - f1.save(ART_DIR / "helltower_rendered_floor1.png") - print("[OK] Saved helltower_rendered_floor1.png") - - f5 = render_menu_frame(5, 100) - f5.save(ART_DIR / "helltower_rendered_floor5.png") - print("[OK] Saved helltower_rendered_floor5.png") - - f10 = render_menu_frame(10, 100) - f10.save(ART_DIR / "helltower_rendered_floor10.png") - print("[OK] Saved helltower_rendered_floor10.png") - + for st in range(1, 7): + im = render_menu_frame(st, state=0) + im.save(ART_DIR / f"helltower_6fl_floor{st}.png") + print(f"[OK] Saved helltower_6fl_floor{st}.png") + + clr = render_menu_frame(1, state=2) + clr.save(ART_DIR / "helltower_6fl_clear.png") + dft = render_menu_frame(1, state=3) + dft.save(ART_DIR / "helltower_6fl_defeat.png") + chp = render_menu_frame(6, state=4) + chp.save(ART_DIR / "helltower_6fl_champion.png") + print("All previews generated successfully!") if __name__ == "__main__": main() diff --git a/tools/tests/test_hell_tower_runthrough.py b/tools/tests/test_hell_tower_runthrough.py index 5caf65d..ee1d13b 100644 --- a/tools/tests/test_hell_tower_runthrough.py +++ b/tools/tests/test_hell_tower_runthrough.py @@ -1,4 +1,4 @@ -"""Automated smoke test for Hell Tower 10-floor run-through.""" +"""Automated smoke test for Hell Tower 6-floor run-through.""" import subprocess import sys from pathlib import Path @@ -22,13 +22,13 @@ def main(): print("[FAIL] Build failed:", build_res.stdout, build_res.stderr) return 1 - print("[3/4] Running Hell Tower 10-floor run-through...") + print("[3/4] Running Hell Tower 6-floor run-through...") run_res = subprocess.run([str(ROOT / "poker.exe")], cwd=ROOT, capture_output=True, timeout=15) print(f"Hell Tower test completed with exit code: {run_res.returncode}") if run_res.returncode != 0: print(f"[FAIL] Hell Tower run-through failed with code {run_res.returncode}") return run_res.returncode - print("[SUCCESS] All 10 floors of Hell Tower completed without errors or crashes!") + print("[SUCCESS] All 6 floors of Hell Tower completed without errors or crashes!") finally: print("[4/4] Restoring normal poker.asm and rebuilding...") restored = POKER_ASM.read_text(encoding="cp1251")