From b1cd66b32253acfa82fef98a63cf1a676aed7a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A4=D0=B5=D0=B4=D0=BE?= =?UTF-8?q?=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 30 Sep 2026 21:17:07 +0300 Subject: [PATCH] fix(ui,audio): eliminate cyan color bug, restore authentic IBM VGA Cyrillic font, implement native 2.5D Skill Check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix Little-Endian DIB color inversion (0000FFFFh/0000D7FFh -> 00FFFF00h/00FFD700h) restoring luxurious Gold, Emerald Felt, and Crimson Red palettes across the entire game - Extract authentic IBM VGA 8x8 font from app866.fon fixing Cyrillic glyph distortion ('М', 'Л', 'П', 'Д') - Implement native in-engine 2.5D Dead by Daylight Skill Check (MODE_SKILL) eliminating external console popups - Fix audio mappings to dedicated minigame sounds with zero gunshots outside Russian roulette - Update visual rasterization test suite and verified 640x480 preview renders --- build/graphics/poker.exe | Bin 212992 -> 214016 bytes casino3d.inc | 2525 +++++++++--------- docs/previews_minigames/coin_preview.png | Bin 6011 -> 6611 bytes docs/previews_minigames/dice_preview.png | Bin 5522 -> 5326 bytes docs/previews_minigames/skill_preview.png | Bin 0 -> 4920 bytes docs/previews_minigames/skulls_preview.png | Bin 5121 -> 5346 bytes font8x8.inc | 506 ++-- poker.exe | Bin 212992 -> 214016 bytes tools/generators/generate_clean_font.py | 45 + tools/generators/generate_rich_minigames.py | 2650 ++++++++++--------- tools/tests/test_minigames_render.py | 368 +-- 11 files changed, 3289 insertions(+), 2805 deletions(-) create mode 100644 docs/previews_minigames/skill_preview.png create mode 100644 tools/generators/generate_clean_font.py diff --git a/build/graphics/poker.exe b/build/graphics/poker.exe index dfd78203aba6ff9ae84ab0eb5f0c7b3c1f4b7f06..f8df6dc3d870ef90b3a5a7113a6b9afafec83769 100644 GIT binary patch delta 21226 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 diff --git a/casino3d.inc b/casino3d.inc index 549c02a..5c4ee4d 100644 --- a/casino3d.inc +++ b/casino3d.inc @@ -115,6 +115,7 @@ MODE_ATM equ 5 MODE_COIN equ 6 MODE_DICE equ 7 MODE_SKULLS equ 8 +MODE_SKILL equ 9 WS_OVERLAPPEDWINDOW equ 00CF0000h SW_SHOW equ 5 @@ -283,31 +284,30 @@ roulWinningNum dd 0 roulPayout dd 0 roulOutcomeMsg db 64 dup(0) -; --- Native 2.5D Coin Flip Game --- +coinRxAnimTable db 26, 22, 16, 6, 16, 22, 26, 22, 16, 6 + +; --- Native 2.5D Coin Flip --- coin3d_bet dd 50 -coin3d_side dd 1 ; 1 = Îð¸ë, 2 = Ðåøêà +coin3d_choice dd 1 ; 1 = Îð¸ë, 2 = Ðåøêà coin3d_state dd 0 ; 0 = Idle, 1 = Flipping, 2 = Result coin3d_timer dd 0 coin3d_result dd 1 ; 1 = Îð¸ë, 2 = Ðåøêà coin3d_streak dd 0 coin3d_win dd 0 -coinRxAnimTable db 26, 22, 16, 6, 16, 22, 26, 22, 16, 6 - -; --- Native 2.5D Coin Flip --- -textCoinTitle db "* * * Ç Î Ë Î Ò À ß Ì Î Í Å Ò À * * *",0 +textCoinTitle db "* * * Ç Î Ë Î Ò À ß Ì Î Í Å Ò À * * *",0 textCoinHeads db "ÎШË",0 textCoinTails db "ÐÅØÊÀ",0 -textCoinStreak db "ÑÅÐÈß: ",0 textCoinSide1 db "[1] ÎШË",0 textCoinSide2 db "[2] ÐÅØÊÀ",0 textCoinFlipping db "ÌÎÍÅÒÀ  ÏÎ˨ÒÅ...",0 -textCoinWin db "ÂÛÈÃÐÛØ: +$",0 -textCoinLose db "ÍÅ ÓÃÀÄÀË!",0 -textCoinKey1 db "1:ÎШË",0 -textCoinKey2 db "2:ÐÅØÊÀ",0 -textCoinKeySpace db "ÏÐÎÁÅË:ÁÐÎÑÎÊ",0 -textCoinStreakFmt db "ÑÅÐÈß: [X] [X] [X] [ ] [ ] x4!",0 +textCoinWin db "ÏÎÁÅÄÀ: +$",0 +textCoinLose db "ÍÅ ÓÃÀÄÀËÈ!",0 +textCoinStreakFmt db "ÑÅÐÈß ÏÎÁÅÄ: x",0 +textCoinSelected db "ÂÛÁÐÀÍÎ",0 +textCoinKey1 db "[1] ÎШË",0 +textCoinKey2 db "[2] ÐÅØÊÀ",0 +textCoinKeySpace db "[SPACE]",0 ; --- Native 2.5D Dice Game --- dice3d_bet dd 50 @@ -319,12 +319,11 @@ dice3d_val2 dd 6 dice3d_sum dd 10 dice3d_win dd 0 -textDiceTitle db "=== G R A N D C R A P S ===",0 -textDiceSubtitle db "[ PASS LINE ] [ ANY CRAPS ]",0 +textDiceTitle db "=== G R A N D C R A P S ===",0 textDiceEven db "[1] רÒ",0 textDiceOdd db "[2] ÍÅ×ÅÒ",0 -textDiceEvenNums db "2 4 6 8 10",0 -textDiceOddNums db "3 5 7 9 11",0 +textDiceEvenNums db " 2 4 6 8 10 ",0 +textDiceOddNums db " 3 5 7 9 11 ",0 textDiceSumHdr db "ÑÓÌÌÀ: ",0 textDicePlus db " + ",0 textDiceEqual db " = ",0 @@ -334,9 +333,9 @@ textDiceRolling db " textDiceWin db "ÂÛÈÃÐÛØ: +$",0 textDiceWinMult db "! (x2)",0 textDiceLose db "ÏÐÎÈÃÐÛØ!",0 -textDiceKey1 db "1:רÒ",0 -textDiceKey2 db "2:ÍÅ×ÅÒ",0 -textDiceKeySpace db "ÏÐÎÁÅË:ÁÐÎÑÎÊ",0 +textDiceKey1 db "[1] רÒ",0 +textDiceKey2 db "[2] ÍÅ×ÅÒ",0 +textDiceKeySpace db "[SPACE]",0 ; --- Native 2.5D Skulls Game --- skulls3d_bet dd 50 @@ -349,21 +348,51 @@ skulls3d_swapPair0 dd 0 skulls3d_swapPair1 dd 1 skulls3d_swapPair2 dd 2 -textSkullsTitle db "+ + + Í À Ï ¨ Ð Ñ Ò Ê È + + +",0 +textSkullsTitle db "* * * Í À Ï ¨ Ð Ñ Ò Ê È * * *",0 textSkullsPhase0 db "ÄÅËÀÉ ÑÒÀÂÊÓ È ÆÌÈ [ÏÐÎÁÅË]",0 textSkullsPhase1 db "ÑÌÎÒÐÈ, ÃÄÅ ÇÎËÎÒÎÉ ØÀÐ...",0 textSkullsPhase2 db "ÊÐÓ×Ó, ÂÅÐ×Ó, ÇÀÏÓÒÀÒÜ ÕÎ×Ó...",0 textSkullsPhase3 db "ÃÄÅ ØÀÐ? ÂÛÁÈÐÀÉ: [1], [2] ÈËÈ [3]!",0 -textSkullsWin db "ÂÅÐÍÎ! ÂÛÏËÀÒÀ x3! +$",0 +textSkullsWin db "ÂÛÈÃÐÛØ: +$",0 +textSkullsWinMult db "! (x3) ÂÛ ÓÃÀÄÀËÈ!",0 textSkullsLose db "ÌÈÌÎ! ØÀÐ ÁÛË Â ÄÐÓÃÎÌ ÌÅÑÒÅ!",0 textSkullsAgain db "[ÏÐÎÁÅË] - ÑÛÃÐÀÒÜ ÅÙ¨ ÐÀÇ",0 -textSkullsKey1 db "1:ÊÓÁÎÊ",0 -textSkullsKey2 db "2:ÊÓÁÎÊ",0 -textSkullsKey3 db "3:ÊÓÁÎÊ",0 -textSkullsKeySpace db "ÏÐÎÁÅË",0 +textSkullsKey1 db "[1]",0 +textSkullsKey2 db "[2]",0 +textSkullsKey3 db "[3]",0 +textSkullsKeySpace db "[SPACE] ÑÒÀÐÒ",0 + +; --- Native 2.5D Skill Check (Dead by Daylight Survivor Check) --- +skill3d_bet dd 50 +skill3d_state dd 0 ; 0=Ready, 1=Active, 2=Hit Result, 3=Miss Result, 4=Escaped, 5=Defeated +skill3d_timer dd 0 +skill3d_needle dd 55 ; Needle X (52..268) +skill3d_speed dd 4 +skill3d_dir dd 1 ; 1=Right, -1=Left +skill3d_zone_start dd 140 +skill3d_zone_width dd 48 +skill3d_great_start dd 176 +skill3d_great_width dd 12 +skill3d_hits dd 0 +skill3d_misses dd 0 +skill3d_last_result dd 0 +skill3d_win_amount dd 0 + +textSkillTitle db "=== S K I L L C H E C K ===",0 +textSkillHitsHdr db "ÕÈÒ: ",0 +textSkillMissHdr db "ÏÐÎÌÀÕ: ",0 +textSkillReadyMsg db "ÍÀÆÌÈÒÅ [ÏÐÎÁÅË] ÄËß ÑÒÀÐÒÀ",0 +textSkillPrompt db "ÍÀÆÌÈÒÅ [ÏÐÎÁÅË]  ÇÎÍÅ!",0 +textSkillHitMsg db "ÕÈÒ! ÒÎ×ÍÎÅ ÏÎÏÀÄÀÍÈÅ!",0 +textSkillGreatMsg db "ÎÒËÈ×ÍÎ! GREAT SKILL CHECK! +ÁÎÍÓÑ!",0 +textSkillMissMsg db "ÏÐÎÌÀÕ! ÒÐÅÂÎÃÀ!",0 +textSkillEscape db "ÏÎÁÅà ÓÑÏÅØÅÍ! ÂÛÈÃÐÛØ: +$",0 +textSkillLost db "ÂÛ ÏÎÉÌÀÍÛ! ÏÐÎÈÃÐÛØ ÑÒÀÂÊÈ!",0 +textSkillKeySpace db "[SPACE] ÐÅÀÊÖÈß",0 +textSkillKeyBet db "[ÂÂÅÐÕ/ÂÍÈÇ]",0 ; --- Shared UI Strings --- -textKeyEsc db "ESC",0 +textKeyEsc db "[ESC]",0 textBankPrompt db "ÁÀÍÊ: $",0 textBetPrompt db "ÑÒÀÂÊÀ: $",0 textBetHint db " [W/S]",0 @@ -1604,7 +1633,7 @@ RenderMinimap PROC uses ebx esi edi mov radarY, 20 mov radarSize, 44 - invoke DrawBoxBorder, radarX, radarY, radarSize, radarSize, 00101510h, 0000D7FFh, 1 + invoke DrawBoxBorder, radarX, radarY, radarSize, radarSize, 00101510h, 00FFD700h, 1 ; Draw Sprites on radar xor esi, esi @@ -1646,7 +1675,7 @@ draw_player_radar: shr eax, 5 add eax, radarY - invoke DrawCircle, ebx, eax, 2, 000000FFh + invoke DrawCircle, ebx, eax, 2, 00FF2020h ret RenderMinimap ENDP @@ -1724,11 +1753,11 @@ HandleSlotsInput ENDP RenderSlotsGame PROC uses ebx esi edi ; Cabinet Background (Dark Cherry Wood & Gold) invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00150A10h - invoke DrawBoxBorder, 10, 10, 300, 220, 00251015h, 0000D7FFh, 3 + invoke DrawBoxBorder, 10, 10, 300, 220, 00251015h, 00FFD700h, 3 ; Illuminated Top Marquee - invoke DrawBoxBorder, 25, 20, 270, 32, 000A0505h, 0000FFFFh, 2 - invoke DrawString8x8, 55, 32, OFFSET textSlots3D, 0000D7FFh + invoke DrawBoxBorder, 25, 20, 270, 32, 000A0505h, 00FFFF00h, 2 + invoke DrawString8x8, 55, 32, OFFSET textSlots3D, 00FFD700h ; Spinning Animation Logic cmp slotSpinState, 1 @@ -1825,21 +1854,21 @@ draw_reels: call DrawReelSymbolAt3 ; Bottom Control Panel - invoke DrawBoxBorder, 20, 165, 280, 58, 00151515h, 0000D7FFh, 1 + invoke DrawBoxBorder, 20, 165, 280, 58, 00151515h, 00FFD700h, 1 - invoke DrawString8x8, 28, 172, OFFSET textBank3D, 0000D7FFh + invoke DrawString8x8, 28, 172, OFFSET textBank3D, 00FFD700h invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 00FFFF00h - invoke DrawString8x8, 175, 172, OFFSET textBet3D, 0000D7FFh + invoke DrawString8x8, 175, 172, OFFSET textBet3D, 00FFD700h invoke FormatNumber, slotBet, OFFSET hudNumBuffer invoke DrawString8x8, 240, 172, OFFSET hudNumBuffer, 0050FF50h cmp slotWinAmount, 0 jle draw_slot_ctrls - invoke DrawString8x8, 28, 187, OFFSET strWin, 0000FFFFh + invoke DrawString8x8, 28, 187, OFFSET strWin, 00FFFF00h invoke FormatNumber, slotWinAmount, OFFSET hudNumBuffer - invoke DrawString8x8, 110, 187, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 110, 187, OFFSET hudNumBuffer, 00FFFF00h draw_slot_ctrls: invoke DrawString8x8, 28, 204, OFFSET textSlotsKeys3D, 00A0A0A0h @@ -1849,7 +1878,7 @@ RenderSlotsGame ENDP DrawReelSymbolAt1 PROC cmp eax, 0 jne @F - invoke DrawString8x8, 52, 105, OFFSET sym7, 000000FFh + invoke DrawString8x8, 52, 105, OFFSET sym7, 00FF2020h ret @@: cmp eax, 1 @@ -1859,7 +1888,7 @@ DrawReelSymbolAt1 PROC @@: cmp eax, 2 jne @F - invoke DrawString8x8, 52, 105, OFFSET symBell, 0000D7FFh + invoke DrawString8x8, 52, 105, OFFSET symBell, 00FFD700h ret @@: cmp eax, 3 @@ -1877,14 +1906,14 @@ DrawReelSymbolAt1 PROC invoke DrawString8x8, 52, 105, OFFSET symGem, 00FFFF00h ret @@: - invoke DrawString8x8, 52, 105, OFFSET symCrown, 0000D7FFh + invoke DrawString8x8, 52, 105, OFFSET symCrown, 00FFD700h ret DrawReelSymbolAt1 ENDP DrawReelSymbolAt2 PROC cmp eax, 0 jne @F - invoke DrawString8x8, 135, 105, OFFSET sym7, 000000FFh + invoke DrawString8x8, 135, 105, OFFSET sym7, 00FF2020h ret @@: cmp eax, 1 @@ -1894,7 +1923,7 @@ DrawReelSymbolAt2 PROC @@: cmp eax, 2 jne @F - invoke DrawString8x8, 135, 105, OFFSET symBell, 0000D7FFh + invoke DrawString8x8, 135, 105, OFFSET symBell, 00FFD700h ret @@: cmp eax, 3 @@ -1912,14 +1941,14 @@ DrawReelSymbolAt2 PROC invoke DrawString8x8, 135, 105, OFFSET symGem, 00FFFF00h ret @@: - invoke DrawString8x8, 135, 105, OFFSET symCrown, 0000D7FFh + invoke DrawString8x8, 135, 105, OFFSET symCrown, 00FFD700h ret DrawReelSymbolAt2 ENDP DrawReelSymbolAt3 PROC cmp eax, 0 jne @F - invoke DrawString8x8, 218, 105, OFFSET sym7, 000000FFh + invoke DrawString8x8, 218, 105, OFFSET sym7, 00FF2020h ret @@: cmp eax, 1 @@ -1929,7 +1958,7 @@ DrawReelSymbolAt3 PROC @@: cmp eax, 2 jne @F - invoke DrawString8x8, 218, 105, OFFSET symBell, 0000D7FFh + invoke DrawString8x8, 218, 105, OFFSET symBell, 00FFD700h ret @@: cmp eax, 3 @@ -1947,7 +1976,7 @@ DrawReelSymbolAt3 PROC invoke DrawString8x8, 218, 105, OFFSET symGem, 00FFFF00h ret @@: - invoke DrawString8x8, 218, 105, OFFSET symCrown, 0000D7FFh + invoke DrawString8x8, 218, 105, OFFSET symCrown, 00FFD700h ret DrawReelSymbolAt3 ENDP @@ -2211,13 +2240,13 @@ CalcDealerBJScore ENDP RenderBlackjackGame PROC uses ebx esi edi ; Emerald Felt Table Background invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 000A3015h - invoke DrawBoxBorder, 10, 10, 300, 220, 000D4018h, 0000D7FFh, 3 + invoke DrawBoxBorder, 10, 10, 300, 220, 000D4018h, 00FFD700h, 3 ; Dealer Area Top - invoke DrawString8x8, 25, 20, OFFSET textBJ3D, 0000D7FFh + invoke DrawString8x8, 25, 20, OFFSET textBJ3D, 00FFD700h invoke DrawString8x8, 25, 35, OFFSET textDealer3D, 00FFFFFFh invoke FormatNumber, bjDealerScore, OFFSET hudNumBuffer - invoke DrawString8x8, 120, 35, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 120, 35, OFFSET hudNumBuffer, 00FFFF00h ; Dealer Cards xor esi, esi @@ -2283,10 +2312,10 @@ draw_player_cards: draw_bj_footer: ; Footer Status & Controls - invoke DrawBoxBorder, 20, 182, 280, 42, 00102010h, 0000D7FFh, 1 + invoke DrawBoxBorder, 20, 182, 280, 42, 00102010h, 00FFD700h, 1 cmp BYTE PTR [bjOutcomeMsg], 0 je draw_bj_controls - invoke DrawString8x8, 28, 188, OFFSET bjOutcomeMsg, 0000FFFFh + invoke DrawString8x8, 28, 188, OFFSET bjOutcomeMsg, 00FFFF00h invoke DrawString8x8, 28, 204, OFFSET textNext3D, 00A0A0A0h ret @@ -2354,13 +2383,13 @@ HandleRouletteInput ENDP RenderRouletteGame PROC uses ebx esi edi ; Table felt background invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00151525h - invoke DrawBoxBorder, 10, 10, 300, 220, 00201525h, 0000D7FFh, 3 + invoke DrawBoxBorder, 10, 10, 300, 220, 00201525h, 00FFD700h, 3 ; 2.5D Rotating Wheel on Left invoke DrawCircle, 85, 110, 65, 00102550h - invoke DrawCircle, 85, 110, 60, 0000D7FFh + invoke DrawCircle, 85, 110, 60, 00FFD700h invoke DrawCircle, 85, 110, 52, 00101010h - invoke DrawCircle, 85, 110, 22, 0000D7FFh ; Center brass turret + invoke DrawCircle, 85, 110, 22, 00FFD700h ; Center brass turret ; Spinning Wheel / Ball Logic cmp roulState, 1 @@ -2488,32 +2517,32 @@ draw_roul_ball: ; Highlight Active Bet cmp roulBetType, 1 jne @F - invoke DrawBoxBorder, 173, 23, 129, 32, 0, 0000FFFFh, 2 + invoke DrawBoxBorder, 173, 23, 129, 32, 0, 00FFFF00h, 2 @@: cmp roulBetType, 2 jne @F - invoke DrawBoxBorder, 173, 58, 129, 32, 0, 0000FFFFh, 2 + invoke DrawBoxBorder, 173, 58, 129, 32, 0, 00FFFF00h, 2 @@: cmp roulBetType, 3 jne @F - invoke DrawBoxBorder, 173, 93, 129, 32, 0, 0000FFFFh, 2 + invoke DrawBoxBorder, 173, 93, 129, 32, 0, 00FFFF00h, 2 @@: cmp roulBetType, 4 jne @F - invoke DrawBoxBorder, 173, 128, 64, 30, 0, 0000FFFFh, 2 + invoke DrawBoxBorder, 173, 128, 64, 30, 0, 00FFFF00h, 2 @@: cmp roulBetType, 5 jne draw_ro_footer - invoke DrawBoxBorder, 238, 128, 64, 30, 0, 0000FFFFh, 2 + invoke DrawBoxBorder, 238, 128, 64, 30, 0, 00FFFF00h, 2 draw_ro_footer: - invoke DrawBoxBorder, 20, 180, 280, 42, 00101015h, 0000D7FFh, 1 + invoke DrawBoxBorder, 20, 180, 280, 42, 00101015h, 00FFD700h, 1 cmp roulState, 2 jne @F - invoke DrawString8x8, 28, 186, OFFSET textResult3D, 0000D7FFh + invoke DrawString8x8, 28, 186, OFFSET textResult3D, 00FFD700h invoke FormatNumber, roulWinningNum, OFFSET hudNumBuffer - invoke DrawString8x8, 85, 186, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 85, 186, OFFSET hudNumBuffer, 00FFFF00h invoke DrawString8x8, 130, 186, OFFSET roulOutcomeMsg, 0050FF50h @@: invoke DrawString8x8, 28, 202, OFFSET textSpin3D, 00A0A0A0h @@ -2603,25 +2632,25 @@ HandleShopInput ENDP RenderShopGame PROC invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00150A0Ah - invoke DrawBoxBorder, 10, 10, 300, 220, 00251515h, 0000D7FFh, 3 - invoke DrawString8x8, 25, 20, OFFSET textShop3D, 0000D7FFh + invoke DrawBoxBorder, 10, 10, 300, 220, 00251515h, 00FFD700h, 3 + invoke DrawString8x8, 25, 20, OFFSET textShop3D, 00FFD700h invoke DrawBoxBorder, 20, 40, 280, 32, 001A1010h, 00FFFFFFh, 1 - invoke DrawString8x8, 28, 46, OFFSET textItem1_3D, 0000FFFFh + invoke DrawString8x8, 28, 46, OFFSET textItem1_3D, 00FFFF00h invoke DrawString8x8, 28, 58, OFFSET textShopHint3D, 00A0A0A0h invoke DrawBoxBorder, 20, 80, 280, 32, 001A1010h, 00FFFFFFh, 1 - invoke DrawString8x8, 28, 86, OFFSET textItem2_3D, 0000FFFFh + invoke DrawString8x8, 28, 86, OFFSET textItem2_3D, 00FFFF00h invoke DrawString8x8, 28, 98, OFFSET textShopHint3D, 00A0A0A0h invoke DrawBoxBorder, 20, 120, 280, 32, 001A1010h, 00FFFFFFh, 1 - invoke DrawString8x8, 28, 126, OFFSET textItem3_3D, 0000FFFFh + invoke DrawString8x8, 28, 126, OFFSET textItem3_3D, 00FFFF00h invoke DrawString8x8, 28, 138, OFFSET textShopHint3D, 00A0A0A0h - invoke DrawBoxBorder, 20, 165, 280, 55, 00100A0Ah, 0000D7FFh, 1 - invoke DrawString8x8, 28, 172, OFFSET textBank3D, 0000D7FFh + invoke DrawBoxBorder, 20, 165, 280, 55, 00100A0Ah, 00FFD700h, 1 + invoke DrawString8x8, 28, 172, OFFSET textBank3D, 00FFD700h invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 00FFFF00h cmp BYTE PTR [shopMsg], 0 je @F @@ -2650,76 +2679,80 @@ RenderATMGame PROC ret RenderATMGame ENDP +; ============================================================================== ; ============================================================================== ; ============================================================================== ; SHARED RICH UI PROCEDURES ; ============================================================================== DrawKeycap3D PROC uses ebx esi edi, x:DWORD, y:DWORD, strPtr:DWORD, isActive:DWORD - LOCAL capW:DWORD - ; Compute string length + local keyW:DWORD mov esi, strPtr xor ecx, ecx -@@: +keycap_len: mov al, [esi+ecx] test al, al - jz @F + jz keycap_len_done inc ecx - jmp @B -@@: - shl ecx, 3 ; length * 8 - add ecx, 8 ; padding 8px - mov capW, ecx + jmp keycap_len +keycap_len_done: + shl ecx, 3 + add ecx, 8 + mov keyW, ecx ; Drop shadow + mov eax, y + add eax, 2 + invoke DrawBox, x, eax, keyW, 13, 0008080Ch + + ; Border and Fill + cmp isActive, 0 + je keycap_inactive + mov eax, 00FFFF00h ; Bright Yellow active border + mov edx, 001B4B22h ; Casino Green active fill + mov ebx, 00FFFF00h ; Bright Yellow active text + jmp keycap_draw_box +keycap_inactive: + mov eax, 00606870h ; Slate inactive border + mov edx, 001A1C22h ; Charcoal inactive fill + mov ebx, 00D0D8E0h ; Silver inactive text + +keycap_draw_box: + push ebx + invoke DrawBoxBorder, x, y, keyW, 13, edx, eax, 1 + pop ebx + + ; Text label mov eax, x + add eax, 4 mov edx, y - add edx, 2 - invoke DrawBox, eax, edx, capW, 13, 0008080Ch + add edx, 3 + invoke DrawString8x8, eax, edx, strPtr, ebx - ; Body & Border - mov eax, 00606870h ; default border - mov edx, 001A1C22h ; default fill - cmp isActive, 0 - je @F - mov eax, 0000FFFFh ; active gold border - mov edx, 001B4B22h ; active dark green fill -@@: - invoke DrawBoxBorder, x, y, capW, 13, edx, eax, 1 - - ; String text - mov eax, 00D0D8E0h - cmp isActive, 0 - je @F - mov eax, 0000FFFFh -@@: - mov edx, x - add edx, 4 - mov ecx, y - add ecx, 3 - invoke DrawString8x8, edx, ecx, strPtr, eax - mov eax, capW + mov eax, keyW + add eax, 4 ret DrawKeycap3D ENDP DrawChipStack PROC uses ebx esi edi, x:DWORD, y:DWORD, chipCount:DWORD + mov edi, chipCount xor esi, esi chip_loop: - cmp esi, chipCount + cmp esi, edi jge chip_done mov eax, esi - shl eax, 2 ; esi * 4 + shl eax, 2 mov edx, y - sub edx, eax ; cy = y - esi*4 + sub edx, eax ; Shadow mov eax, x add eax, 2 mov ecx, edx add ecx, 5 - invoke DrawBox, eax, ecx, 20, 2, 00041006h + invoke DrawBox, eax, ecx, 20, 2, 00061004h - ; Chip body - invoke DrawBoxBorder, x, edx, 24, 6, 001515B8h, 00FFFFFFh, 1 + ; Red Clay Chip body with white rim + invoke DrawBoxBorder, x, edx, 24, 6, 00B81515h, 00FFFFFFh, 1 ; White stripe inlays mov eax, x @@ -2727,8 +2760,11 @@ chip_loop: mov ecx, edx add ecx, 1 invoke DrawBox, eax, ecx, 3, 4, 00FFFFFFh + mov eax, x add eax, 17 + mov ecx, edx + add ecx, 1 invoke DrawBox, eax, ecx, 3, 4, 00FFFFFFh inc esi @@ -2737,624 +2773,565 @@ chip_done: ret DrawChipStack ENDP -; ============================================================================== -; IN-ENGINE 2.5D MINI-GAME: COIN FLIP (ÌÎÍÅÒÊÀ) -; ============================================================================== DrawDetailedCoin PROC uses ebx esi edi, cxVal:DWORD, cyVal:DWORD, rxVal:DWORD, ryVal:DWORD, outerColor:DWORD, innerColor:DWORD, reliefType:DWORD - LOCAL curDY:DWORD, curDX:DWORD, rxSq:DWORD, rySq:DWORD, rxRySq:DWORD, threshSq:DWORD - cmp rxVal, 0 - jle coin_draw_ret - cmp ryVal, 0 - jle coin_draw_ret + local rxSq:DWORD + local rySq:DWORD + local rxRySq:DWORD + local threshSq:DWORD + local curDy:DWORD + local curDx:DWORD + local curX:DWORD + local curY:DWORD mov eax, rxVal - imul eax, eax + cmp eax, 0 + jle coin_draw_done + mov eax, ryVal + cmp eax, 0 + jle coin_draw_done + + mov eax, rxVal + imul eax, rxVal mov rxSq, eax mov eax, ryVal - imul eax, eax + imul eax, ryVal mov rySq, eax - mov eax, rxSq - imul eax, rySq + imul eax, rxSq mov rxRySq, eax - mov eax, rxRySq + ; 3/4 threshold for rim bevel + mov ecx, 3 + imul eax, ecx shr eax, 2 - imul eax, 3 mov threshSq, eax + ; Scan rows mov eax, ryVal neg eax - mov curDY, eax - -coin_y_loop: - mov eax, curDY + mov curDy, eax +coin_row_loop: + mov eax, curDy cmp eax, ryVal - jg check_coin_relief + jg coin_relief_check + mov edx, cyVal + add edx, curDy + mov curY, edx + + ; Scan columns mov eax, rxVal neg eax - mov curDX, eax - -coin_x_loop: - mov eax, curDX + mov curDx, eax +coin_col_loop: + mov eax, curDx cmp eax, rxVal - jg next_coin_y + jg coin_col_next_row - mov eax, curDX - imul eax, eax + mov ecx, cxVal + add ecx, curDx + mov curX, ecx + + ; val = dx*dx*rySq + dy*dy*rxSq + mov eax, curDx + imul eax, curDx imul eax, rySq - mov ebx, curDY - imul ebx, ebx - imul ebx, rxSq + mov ebx, eax + + mov eax, curDy + imul eax, curDy + imul eax, rxSq add eax, ebx + cmp eax, rxRySq - jg next_coin_x + ja coin_pixel_outside - mov ecx, innerColor cmp eax, threshSq - jb @F - mov ecx, outerColor -@@: - mov eax, cxVal - add eax, curDX - mov edx, cyVal - add edx, curDY - invoke DrawPixel, eax, edx, ecx + jb coin_draw_inner + invoke DrawPixel, curX, curY, outerColor + jmp coin_pixel_outside +coin_draw_inner: + invoke DrawPixel, curX, curY, innerColor -next_coin_x: - inc curDX - jmp coin_x_loop +coin_pixel_outside: + inc curDx + jmp coin_col_loop -next_coin_y: - inc curDY - jmp coin_y_loop +coin_col_next_row: + inc curDy + jmp coin_row_loop -check_coin_relief: +coin_relief_check: cmp rxVal, 14 - jl coin_draw_ret - cmp reliefType, 1 - je draw_eagle_relief - cmp reliefType, 2 - je draw_wreath_relief - jmp coin_draw_ret + jl coin_draw_done -draw_eagle_relief: - ; Crown + cmp reliefType, 1 + je coin_draw_eagle + cmp reliefType, 2 + je coin_draw_numeral + jmp coin_draw_done + +coin_draw_eagle: + ; Imperial Eagle relief (Dark Gold 009A7A00h / Bright 00FFD700h) mov eax, cxVal sub eax, 3 mov edx, cyVal sub edx, 14 - invoke DrawBox, eax, edx, 7, 2, 00007A9Ah + invoke DrawBox, eax, edx, 7, 2, 009A7A00h + mov eax, cxVal sub eax, 4 mov edx, cyVal sub edx, 12 - invoke DrawBox, eax, edx, 9, 2, 00007A9Ah + invoke DrawBox, eax, edx, 9, 2, 009A7A00h - ; Body & Head mov eax, cxVal sub eax, 2 mov edx, cyVal sub edx, 9 - invoke DrawBox, eax, edx, 5, 12, 00007A9Ah + invoke DrawBox, eax, edx, 5, 12, 009A7A00h + mov eax, cxVal - dec eax + sub eax, 1 mov edx, cyVal sub edx, 8 - invoke DrawBox, eax, edx, 3, 10, 0000D7FFh + invoke DrawBox, eax, edx, 3, 10, 00FFD700h - ; Wings mov eax, cxVal sub eax, 10 mov edx, cyVal sub edx, 8 - invoke DrawBox, eax, edx, 7, 3, 00007A9Ah + invoke DrawBox, eax, edx, 7, 3, 009A7A00h + mov eax, cxVal sub eax, 13 mov edx, cyVal sub edx, 5 - invoke DrawBox, eax, edx, 10, 3, 00007A9Ah + invoke DrawBox, eax, edx, 10, 3, 009A7A00h + mov eax, cxVal sub eax, 11 mov edx, cyVal sub edx, 2 - invoke DrawBox, eax, edx, 7, 3, 00007A9Ah + invoke DrawBox, eax, edx, 7, 3, 009A7A00h mov eax, cxVal add eax, 4 mov edx, cyVal sub edx, 8 - invoke DrawBox, eax, edx, 7, 3, 00007A9Ah + invoke DrawBox, eax, edx, 7, 3, 009A7A00h + mov eax, cxVal add eax, 4 mov edx, cyVal sub edx, 5 - invoke DrawBox, eax, edx, 10, 3, 00007A9Ah + invoke DrawBox, eax, edx, 10, 3, 009A7A00h + mov eax, cxVal add eax, 5 mov edx, cyVal sub edx, 2 - invoke DrawBox, eax, edx, 7, 3, 00007A9Ah + invoke DrawBox, eax, edx, 7, 3, 009A7A00h - ; Tail mov eax, cxVal sub eax, 4 mov edx, cyVal add edx, 4 - invoke DrawBox, eax, edx, 9, 3, 00007A9Ah + invoke DrawBox, eax, edx, 9, 3, 009A7A00h + mov eax, cxVal sub eax, 3 mov edx, cyVal add edx, 7 - invoke DrawBox, eax, edx, 7, 3, 00007A9Ah - jmp coin_draw_ret + invoke DrawBox, eax, edx, 7, 3, 009A7A00h + jmp coin_draw_done -draw_wreath_relief: - ; Roman numeral 'I' +coin_draw_numeral: + ; Roman numeral 'I' & laurel mov eax, cxVal sub eax, 5 mov edx, cyVal sub edx, 10 - invoke DrawBox, eax, edx, 11, 3, 00007A9Ah + invoke DrawBox, eax, edx, 11, 3, 009A7A00h + mov eax, cxVal sub eax, 2 mov edx, cyVal sub edx, 7 - invoke DrawBox, eax, edx, 5, 14, 00007A9Ah + invoke DrawBox, eax, edx, 5, 14, 009A7A00h + mov eax, cxVal - dec eax + sub eax, 1 mov edx, cyVal sub edx, 6 - invoke DrawBox, eax, edx, 3, 12, 0000D7FFh + invoke DrawBox, eax, edx, 3, 12, 00FFD700h + mov eax, cxVal sub eax, 6 mov edx, cyVal add edx, 7 - invoke DrawBox, eax, edx, 13, 3, 00007A9Ah + invoke DrawBox, eax, edx, 13, 3, 009A7A00h - ; Laurel dots left & right + ; Laurel dots mov eax, cxVal sub eax, 12 mov edx, cyVal - sub edx, 10 - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah + sub edx, 8 + invoke DrawBox, eax, edx, 2, 2, 009A7A00h + mov eax, cxVal add eax, 11 mov edx, cyVal - sub edx, 10 - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah + sub edx, 8 + invoke DrawBox, eax, edx, 2, 2, 009A7A00h mov eax, cxVal sub eax, 12 mov edx, cyVal - sub edx, 5 - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah + invoke DrawBox, eax, edx, 2, 2, 009A7A00h + mov eax, cxVal add eax, 11 mov edx, cyVal - sub edx, 5 - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah + invoke DrawBox, eax, edx, 2, 2, 009A7A00h mov eax, cxVal sub eax, 12 mov edx, cyVal - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah + add edx, 8 + invoke DrawBox, eax, edx, 2, 2, 009A7A00h + mov eax, cxVal add eax, 11 mov edx, cyVal - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah + add edx, 8 + invoke DrawBox, eax, edx, 2, 2, 009A7A00h - mov eax, cxVal - sub eax, 12 - mov edx, cyVal - add edx, 5 - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah - mov eax, cxVal - add eax, 11 - mov edx, cyVal - add edx, 5 - invoke DrawBox, eax, edx, 2, 2, 00007A9Ah - -coin_draw_ret: +coin_draw_done: ret DrawDetailedCoin ENDP +; ============================================================================== +; IN-ENGINE 2.5D MINI-GAME: COIN FLIP +; ============================================================================== InitCoinGame PROC mov coin3d_state, 0 mov coin3d_timer, 0 + mov coin3d_streak, 0 mov coin3d_win, 0 - cmp coin3d_bet, 10 - jge @F - mov coin3d_bet, 50 -@@: ret InitCoinGame ENDP HandleCoinInput PROC + cmp coin3d_state, 0 + je coin_handle_idle cmp coin3d_state, 1 - je coin_input_done - - invoke Pressed3D, 20h ; SPACE -> Flip! - test eax, eax - jz check_coin_side - mov eax, bankroll - cmp eax, coin3d_bet - jl coin_no_cash - sub eax, coin3d_bet - mov bankroll, eax - mov coin3d_state, 1 - mov coin3d_timer, 0 - mov coin3d_win, 0 - invoke PlaySoundA, OFFSET soundCoin, 0, 1 - jmp coin_input_done - -coin_no_cash: - invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage - mov flashTimer, 60 - invoke PlaySoundA, OFFSET soundClick, 0, 1 - jmp coin_input_done - -check_coin_side: - invoke Pressed3D, 31h ; '1' - test eax, eax - jz @F - mov coin3d_side, 1 - invoke PlaySoundA, OFFSET soundClick, 0, 1 -@@: - invoke Pressed3D, 32h ; '2' - test eax, eax - jz check_coin_bet_adjust - mov coin3d_side, 2 - invoke PlaySoundA, OFFSET soundClick, 0, 1 - -check_coin_bet_adjust: - invoke Pressed3D, 26h ; UP - test eax, eax - jnz coin_inc_bet - invoke Pressed3D, 57h ; W - test eax, eax - jz check_coin_bet_down -coin_inc_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp coin3d_bet, 500 - jge coin_input_done - cmp coin3d_bet, 250 - jge coin_set_500 - cmp coin3d_bet, 100 - jge coin_set_250 - cmp coin3d_bet, 50 - jge coin_set_100 - cmp coin3d_bet, 25 - jge coin_set_50 - jmp coin_set_25 -coin_set_500: - mov coin3d_bet, 500 - jmp coin_input_done -coin_set_250: - mov coin3d_bet, 250 - jmp coin_input_done -coin_set_100: - mov coin3d_bet, 100 - jmp coin_input_done -coin_set_50: - mov coin3d_bet, 50 - jmp coin_input_done -coin_set_25: - mov coin3d_bet, 25 - jmp coin_input_done - -check_coin_bet_down: - invoke Pressed3D, 28h ; DOWN - test eax, eax - jnz coin_dec_bet - invoke Pressed3D, 53h ; S - test eax, eax - jz coin_input_done -coin_dec_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp coin3d_bet, 25 - jle coin_set_10 - cmp coin3d_bet, 50 - jle coin_set_25 - cmp coin3d_bet, 100 - jle coin_set_50 - cmp coin3d_bet, 250 - jle coin_set_100 - mov coin3d_bet, 250 - jmp coin_input_done -coin_set_10: - mov coin3d_bet, 10 - -coin_input_done: + je coin_handle_flipping + cmp coin3d_state, 2 + je coin_handle_result ret -HandleCoinInput ENDP -RenderCoinGame PROC uses ebx esi edi - LOCAL cyVal:DWORD, rxVal:DWORD, curX:DWORD +coin_handle_idle: + invoke Pressed3D, 26h ; UP + test eax, eax + jnz coin_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz coin_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz coin_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz coin_bet_down + invoke Pressed3D, 31h ; '1' + test eax, eax + jnz coin_pick_1 + invoke Pressed3D, 32h ; '2' + test eax, eax + jnz coin_pick_2 + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz coin_start_flip + ret - ; Cabinet Bezel (Mahogany wood & leather) - invoke DrawBox, 0, 0, 320, 240, 00060914h - invoke DrawBoxBorder, 6, 6, 308, 228, 000F1522h, 001B2E48h, 3 - - ; Corner Brass Rivets - invoke DrawBox, 12, 12, 3, 3, 0000D7FFh - invoke DrawPixel, 13, 13, 00FFFFFFh - invoke DrawBox, 306, 12, 3, 3, 0000D7FFh - invoke DrawPixel, 307, 13, 00FFFFFFh - invoke DrawBox, 12, 226, 3, 3, 0000D7FFh - invoke DrawPixel, 13, 227, 00FFFFFFh - invoke DrawBox, 306, 226, 3, 3, 0000D7FFh - invoke DrawPixel, 307, 227, 00FFFFFFh - - ; Illuminated Marquee Header - invoke DrawBoxBorder, 24, 12, 272, 26, 000A101Ch, 0000D7FFh, 2 - invoke DrawString8x8, 48, 21, OFFSET textCoinTitle, 0000FFFFh - - ; Bulb lights on marquee border - mov curX, 28 -coin_bulbs: - cmp curX, 292 - jge coin_meters - invoke DrawPixel, curX, 13, 0000FFFFh - invoke DrawPixel, curX, 36, 0000D7FFh - add curX, 12 - jmp coin_bulbs - -coin_meters: - ; Status Meters: Bank & Bet - invoke DrawBoxBorder, 20, 44, 114, 18, 000A1A0Eh, 001A4B22h, 1 - invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 0050FF50h - invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 0050FF50h - - invoke DrawBoxBorder, 186, 44, 114, 18, 001A100Ah, 003A2814h, 1 - invoke DrawString8x8, 190, 49, OFFSET textBetPrompt, 0000D7FFh - invoke FormatNumber, coin3d_bet, OFFSET hudNumBuffer - invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 0000D7FFh - invoke DrawString8x8, 278, 49, OFFSET textBetHint, 00808080h - - ; Center Velvet Platter - invoke DrawCircle, 160, 110, 46, 000090C0h - invoke DrawCircle, 160, 110, 44, 0000D7FFh - invoke DrawCircle, 160, 110, 41, 00180824h - - ; Selection Podiums: [1] ÎÐ¨Ë - mov eax, 00121620h - mov edx, 00404855h - mov ecx, 0090A0B0h - cmp coin3d_side, 1 - jne @F - mov eax, 001C3822h - mov edx, 0000FFFFh - mov ecx, 0000FFFFh +coin_bet_up: + mov eax, coin3d_bet + add eax, 50 + cmp eax, bankroll + jle @F + mov eax, bankroll @@: - push ecx - invoke DrawBoxBorder, 20, 72, 76, 52, eax, edx, 2 - pop ecx - invoke DrawString8x8, 28, 78, OFFSET textCoinSide1, ecx - invoke DrawDetailedCoin, 58, 106, 12, 12, 0000A0D0h, 0000D7FFh, 1 - - ; Selection Podiums: [2] ÐÅØÊÀ - mov eax, 00121620h - mov edx, 00404855h - mov ecx, 0090A0B0h - cmp coin3d_side, 2 - jne @F - mov eax, 001C3822h - mov edx, 0000FFFFh - mov ecx, 0000FFFFh + cmp eax, 5000 + jle @F + mov eax, 5000 @@: - push ecx - invoke DrawBoxBorder, 224, 72, 76, 52, eax, edx, 2 - pop ecx - invoke DrawString8x8, 232, 78, OFFSET textCoinSide2, ecx - invoke DrawDetailedCoin, 262, 106, 12, 12, 000080A0h, 0000B0D0h, 2 + mov coin3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - ; Flipping animation logic - cmp coin3d_state, 1 - jne coin_at_rest +coin_bet_down: + mov eax, coin3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov coin3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - inc coin3d_timer +coin_pick_1: + mov coin3d_choice, 1 + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - ; Parabolic toss: cy = 110 - (t * (40 - t)) / 14 - mov eax, coin3d_timer - mov ecx, 40 - sub ecx, eax - imul eax, ecx - xor edx, edx - mov ecx, 14 - div ecx - mov edx, 110 - sub edx, eax - mov cyVal, edx +coin_pick_2: + mov coin3d_choice, 2 + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - ; Width rx from lookup table: (t % 10) - mov eax, coin3d_timer - xor edx, edx - mov ecx, 10 - div ecx - movzx eax, BYTE PTR [coinRxAnimTable + edx] - mov rxVal, eax +coin_start_flip: + mov eax, coin3d_bet + cmp eax, bankroll + jle @F + mov eax, bankroll + mov coin3d_bet, eax + test eax, eax + jz coin_done +@@: + mov eax, coin3d_bet + sub bankroll, eax + mov coin3d_state, 1 + mov coin3d_timer, 40 + invoke PlaySoundA, OFFSET soundCoin, 0, 1 + ret - invoke DrawDetailedCoin, 160, cyVal, rxVal, 26, 0000A0D0h, 0000D7FFh, 0 - invoke DrawString8x8, 88, 160, OFFSET textCoinFlipping, 0000FFFFh - - cmp coin3d_timer, 40 - jl coin_draw_controls - - ; Flip complete! - mov coin3d_state, 2 +coin_handle_flipping: + dec coin3d_timer + cmp coin3d_timer, 0 + jg coin_done invoke RandomRange3D, 2 inc eax mov coin3d_result, eax - - mov eax, coin3d_result - cmp eax, coin3d_side + mov edx, coin3d_choice + cmp eax, edx jne coin_flip_lost ; Won! + inc coin3d_streak mov eax, coin3d_bet shl eax, 1 - mov coin3d_win, eax add bankroll, eax - inc coin3d_streak - cmp coin3d_streak, 3 - jl @F - invoke PlaySoundA, OFFSET soundVictory, 0, 1 - jmp coin_draw_controls -@@: + mov coin3d_win, eax + mov coin3d_state, 2 invoke PlaySoundA, OFFSET soundCoinDing, 0, 1 - jmp coin_draw_controls + ret coin_flip_lost: mov coin3d_streak, 0 mov coin3d_win, 0 + mov coin3d_state, 2 invoke PlaySoundA, OFFSET soundLose, 0, 1 - jmp coin_draw_controls + ret -coin_at_rest: - ; Draw coin resting in velvet dish - mov edx, coin3d_side +coin_handle_result: + invoke Pressed3D, 20h + test eax, eax + jz coin_done + mov coin3d_state, 0 + invoke PlaySoundA, OFFSET soundClick, 0, 1 +coin_done: + ret +HandleCoinInput ENDP + +RenderCoinGame PROC uses ebx esi edi + local cyVal:DWORD + local rxVal:DWORD + local kx:DWORD + + ; Background & Cabinet border + invoke DrawBox, 0, 0, 320, 240, 00140906h + invoke DrawBoxBorder, 6, 6, 308, 228, 0022150Fh, 00482E1Bh, 3 + + ; Header + invoke DrawBoxBorder, 20, 12, 280, 26, 001C100Ah, 00FFD700h, 2 + invoke DrawString8x8, 44, 21, OFFSET textCoinTitle, 00FFFF00h + + ; Corner rivets + invoke DrawBox, 12, 12, 3, 3, 00FFD700h + invoke DrawBox, 306, 12, 3, 3, 00FFD700h + invoke DrawBox, 12, 226, 3, 3, 00FFD700h + invoke DrawBox, 306, 226, 3, 3, 00FFD700h + + ; Status meters + invoke DrawBoxBorder, 20, 44, 110, 18, 000E1A0Ah, 00224B1Ah, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch + invoke FormatNumber, bankroll, OFFSET hudNumBuffer + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch + + invoke DrawBoxBorder, 190, 44, 110, 18, 001A100Ah, 003A2814h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h + invoke FormatNumber, coin3d_bet, OFFSET hudNumBuffer + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h + + ; Left: Heads + cmp coin3d_choice, 1 + jne coin_left_inactive + invoke DrawBoxBorder, 20, 72, 76, 68, 00101828h, 00FFFF00h, 2 + invoke DrawString8x8, 30, 78, OFFSET textCoinSide1, 00FFFF00h + invoke DrawDetailedCoin, 58, 106, 14, 14, 00D0A000h, 00FFD700h, 1 + invoke DrawString8x8, 24, 126, OFFSET textCoinSelected, 003CFF3Ch + jmp coin_right_side +coin_left_inactive: + invoke DrawBoxBorder, 20, 72, 76, 68, 000A101Ch, 00404855h, 1 + invoke DrawString8x8, 30, 78, OFFSET textCoinSide1, 00D0D8E0h + invoke DrawDetailedCoin, 58, 106, 14, 14, 009A7A00h, 00D0A000h, 1 + +coin_right_side: + ; Right: Tails + cmp coin3d_choice, 2 + jne coin_right_inactive + invoke DrawBoxBorder, 224, 72, 76, 68, 00101828h, 00FFFF00h, 2 + invoke DrawString8x8, 234, 78, OFFSET textCoinSide2, 00FFFF00h + invoke DrawDetailedCoin, 262, 106, 14, 14, 00D0A000h, 00FFD700h, 2 + invoke DrawString8x8, 228, 126, OFFSET textCoinSelected, 003CFF3Ch + jmp coin_center_area +coin_right_inactive: + invoke DrawBoxBorder, 224, 72, 76, 68, 000A101Ch, 00404855h, 1 + invoke DrawString8x8, 234, 78, OFFSET textCoinSide2, 00D0D8E0h + invoke DrawDetailedCoin, 262, 106, 14, 14, 009A7A00h, 00D0A000h, 2 + +coin_center_area: + ; Center spotlight + invoke DrawCircle, 160, 110, 48, 00121620h + invoke DrawCircle, 160, 110, 44, 00FFD700h + invoke DrawCircle, 160, 110, 42, 000E141Eh + + cmp coin3d_state, 1 + je coin_render_flipping cmp coin3d_state, 2 - jne @F - mov edx, coin3d_result -@@: - invoke DrawDetailedCoin, 160, 110, 26, 26, 0000A0D0h, 0000D7FFh, edx + je coin_render_result - ; Outcome / Streak Display - cmp coin3d_state, 2 - jne coin_show_streak + ; Idle coin + invoke DrawDetailedCoin, 160, 110, 26, 26, 00D0A000h, 00FFD700h, coin3d_choice + jmp coin_render_keys - cmp coin3d_win, 0 - je coin_show_lose - invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 0050FF50h, 1 - invoke DrawString8x8, 64, 160, OFFSET textCoinWin, 0050FF50h +coin_render_flipping: + mov eax, coin3d_timer + and eax, 7 + movzx eax, byte ptr [coinRxAnimTable + eax] + mov rxVal, eax + invoke DrawDetailedCoin, 160, 110, rxVal, 26, 00D0A000h, 00FFD700h, 0 + invoke DrawString8x8, 88, 160, OFFSET textCoinFlipping, 00FFFF00h + jmp coin_render_keys + +coin_render_result: + invoke DrawDetailedCoin, 160, 110, 26, 26, 00D0A000h, 00FFD700h, coin3d_result + mov eax, coin3d_result + cmp eax, coin3d_choice + jne coin_render_loss_msg + + ; Win banner + invoke DrawBoxBorder, 44, 154, 232, 22, 000E141Eh, 003CFF3Ch, 1 + invoke DrawString8x8, 64, 161, OFFSET textCoinWin, 003CFF3Ch invoke FormatNumber, coin3d_win, OFFSET hudNumBuffer - invoke DrawString8x8, 152, 160, OFFSET hudNumBuffer, 0050FF50h - jmp coin_draw_controls + invoke DrawString8x8, 152, 161, OFFSET hudNumBuffer, 003CFF3Ch + jmp coin_render_keys -coin_show_lose: - invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 000000FFh, 1 - invoke DrawString8x8, 114, 160, OFFSET textCoinLose, 008080FFh - jmp coin_draw_controls +coin_render_loss_msg: + invoke DrawBoxBorder, 44, 154, 232, 22, 000E141Eh, 00C81414h, 1 + invoke DrawString8x8, 114, 161, OFFSET textCoinLose, 00FF6464h -coin_show_streak: - invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 0000D7FFh, 1 - invoke DrawString8x8, 52, 160, OFFSET textCoinStreakFmt, 0000FFFFh - -coin_draw_controls: - ; Keycaps Control Bar - invoke DrawBox, 16, 194, 288, 1, 001E2E40h - - mov eax, 0 - cmp coin3d_side, 1 +coin_render_keys: + mov kx, 16 + xor eax, eax + cmp coin3d_choice, 1 sete al - invoke DrawKeycap3D, 22, 202, OFFSET textCoinKey1, eax + invoke DrawKeycap3D, kx, 192, OFFSET textCoinKey1, eax + add kx, eax - mov eax, 0 - cmp coin3d_side, 2 + xor eax, eax + cmp coin3d_choice, 2 sete al - invoke DrawKeycap3D, 88, 202, OFFSET textCoinKey2, eax + invoke DrawKeycap3D, kx, 192, OFFSET textCoinKey2, eax + add kx, eax - invoke DrawKeycap3D, 160, 202, OFFSET textCoinKeySpace, 1 - invoke DrawKeycap3D, 274, 202, OFFSET textKeyEsc, 0 + invoke DrawKeycap3D, kx, 192, OFFSET textCoinKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 ret RenderCoinGame ENDP ; ============================================================================== -; IN-ENGINE 2.5D MINI-GAME: DICE / CRAPS (ÊÎÑÒÈ) +; IN-ENGINE 2.5D MINI-GAME: CRAPS / DICE ; ============================================================================== DrawCrapsDie PROC uses ebx esi edi, x:DWORD, y:DWORD, sizeVal:DWORD, valNum:DWORD - ; Drop shadow on green felt + ; Drop shadow mov eax, x add eax, 3 mov edx, y add edx, sizeVal - invoke DrawBox, eax, edx, sizeVal, 3, 00031408h + invoke DrawBox, eax, edx, sizeVal, 3, 00081403h + mov eax, x add eax, sizeVal mov edx, y add edx, 3 - invoke DrawBox, eax, edx, 3, sizeVal, 00031408h + invoke DrawBox, eax, edx, 3, sizeVal, 00081403h - ; Ivory body & dark border - invoke DrawBoxBorder, x, y, sizeVal, sizeVal, 00F0F4FAh, 00353540h, 1 - - ; Bevel highlight top & left - mov eax, sizeVal - sub eax, 2 - mov edx, x + ; Ivory body & bevel + invoke DrawBoxBorder, x, y, sizeVal, sizeVal, 00FAF4F0h, 00403535h, 1 + mov eax, x + inc eax + mov edx, y inc edx - mov ecx, y - inc ecx - invoke DrawBox, edx, ecx, eax, 1, 00FFFFFFh - invoke DrawBox, edx, ecx, 1, eax, 00FFFFFFh - - ; Bevel shadow bottom & right - mov edx, x - inc edx - mov ecx, y - add ecx, sizeVal + mov ecx, sizeVal sub ecx, 2 - invoke DrawBox, edx, ecx, eax, 1, 00C0C6D0h - mov edx, x - add edx, sizeVal - sub edx, 2 - mov ecx, y - inc ecx - invoke DrawBox, edx, ecx, 1, eax, 00C0C6D0h + invoke DrawBox, eax, edx, ecx, 1, 00FFFFFFh + invoke DrawBox, eax, edx, 1, ecx, 00FFFFFFh - ; Casino Ruby Red circular pips (radius 3) - cmp valNum, 1 - je draw_die_c - cmp valNum, 3 - je draw_die_c - cmp valNum, 5 - je draw_die_c - jmp check_die_pips_corners - -draw_die_c: + ; Ruby pips (00C81515h) + mov eax, valNum + test al, 1 + jz @F + ; Center pip mov eax, x add eax, 18 mov edx, y add edx, 18 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h dec eax dec edx invoke DrawPixel, eax, edx, 00FFFFFFh - -check_die_pips_corners: +@@: cmp valNum, 2 jl die_pips_done mov eax, x add eax, 9 mov edx, y add edx, 9 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h mov eax, x - add eax, sizeVal - sub eax, 10 + add eax, 27 mov edx, y - add edx, sizeVal - sub edx, 10 - invoke DrawCircle, eax, edx, 3, 001515C8h + add edx, 27 + invoke DrawCircle, eax, edx, 3, 00C81515h cmp valNum, 4 jl die_pips_done mov eax, x - add eax, sizeVal - sub eax, 10 + add eax, 27 mov edx, y add edx, 9 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h mov eax, x add eax, 9 mov edx, y - add edx, sizeVal - sub edx, 10 - invoke DrawCircle, eax, edx, 3, 001515C8h + add edx, 27 + invoke DrawCircle, eax, edx, 3, 00C81515h cmp valNum, 6 jl die_pips_done @@ -3362,13 +3339,12 @@ check_die_pips_corners: add eax, 9 mov edx, y add edx, 18 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h mov eax, x - add eax, sizeVal - sub eax, 10 + add eax, 27 mov edx, y add edx, 18 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h die_pips_done: ret @@ -3378,328 +3354,274 @@ InitDiceGame PROC mov dice3d_state, 0 mov dice3d_timer, 0 mov dice3d_win, 0 - cmp dice3d_bet, 10 - jge @F - mov dice3d_bet, 50 -@@: ret InitDiceGame ENDP HandleDiceInput PROC + cmp dice3d_state, 0 + je dice_handle_idle cmp dice3d_state, 1 - je dice_input_done + je dice_handle_rolling + cmp dice3d_state, 2 + je dice_handle_result + ret - invoke Pressed3D, 20h ; SPACE -> Roll! +dice_handle_idle: + invoke Pressed3D, 26h ; UP test eax, eax - jz check_dice_choice + jnz dice_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz dice_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz dice_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz dice_bet_down + invoke Pressed3D, 31h ; '1' + test eax, eax + jnz dice_pick_1 + invoke Pressed3D, 32h ; '2' + test eax, eax + jnz dice_pick_2 + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz dice_start_roll + ret + +dice_bet_up: + mov eax, dice3d_bet + add eax, 50 + cmp eax, bankroll + jle @F mov eax, bankroll - cmp eax, dice3d_bet - jl dice_no_cash - sub eax, dice3d_bet - mov bankroll, eax - mov dice3d_state, 1 - mov dice3d_timer, 0 - mov dice3d_win, 0 - invoke PlaySoundA, OFFSET soundCards, 0, 1 - jmp dice_input_done - -dice_no_cash: - invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage - mov flashTimer, 60 +@@: + cmp eax, 5000 + jle @F + mov eax, 5000 +@@: + mov dice3d_bet, eax invoke PlaySoundA, OFFSET soundClick, 0, 1 - jmp dice_input_done + ret -check_dice_choice: - invoke Pressed3D, 31h ; '1' - test eax, eax - jz @F +dice_bet_down: + mov eax, dice3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov dice3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +dice_pick_1: mov dice3d_choice, 1 invoke PlaySoundA, OFFSET soundClick, 0, 1 -@@: - invoke Pressed3D, 32h ; '2' - test eax, eax - jz check_dice_bet_adjust + ret + +dice_pick_2: mov dice3d_choice, 2 invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret -check_dice_bet_adjust: - invoke Pressed3D, 26h ; UP +dice_start_roll: + mov eax, dice3d_bet + cmp eax, bankroll + jle @F + mov eax, bankroll + mov dice3d_bet, eax test eax, eax - jnz dice_inc_bet - invoke Pressed3D, 57h ; W + jz dice_done +@@: + mov eax, dice3d_bet + sub bankroll, eax + mov dice3d_state, 1 + mov dice3d_timer, 35 + invoke PlaySoundA, OFFSET soundCards, 0, 1 + ret + +dice_handle_rolling: + dec dice3d_timer + cmp dice3d_timer, 0 + jg dice_randomize_tumble + + ; Roll finished! + invoke RandomRange3D, 6 + inc eax + mov dice3d_val1, eax + invoke RandomRange3D, 6 + inc eax + mov dice3d_val2, eax + + mov edx, dice3d_val1 + add edx, eax + mov dice3d_sum, edx + + ; Parity check + mov eax, edx + and eax, 1 + jnz dice_sum_is_odd + ; Even + mov eax, 1 + jmp dice_check_win +dice_sum_is_odd: + mov eax, 2 + +dice_check_win: + cmp eax, dice3d_choice + jne dice_roll_lost + + ; Won! + mov eax, dice3d_bet + shl eax, 1 + add bankroll, eax + mov dice3d_win, eax + mov dice3d_state, 2 + invoke PlaySoundA, OFFSET soundVictory, 0, 1 + ret + +dice_roll_lost: + mov dice3d_win, 0 + mov dice3d_state, 2 + invoke PlaySoundA, OFFSET soundLose, 0, 1 + ret + +dice_randomize_tumble: + invoke RandomRange3D, 6 + inc eax + mov dice3d_val1, eax + invoke RandomRange3D, 6 + inc eax + mov dice3d_val2, eax + ret + +dice_handle_result: + invoke Pressed3D, 20h test eax, eax - jz check_dice_bet_down -dice_inc_bet: + jz dice_done + mov dice3d_state, 0 invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp dice3d_bet, 500 - jge dice_input_done - cmp dice3d_bet, 250 - jge dice_set_500 - cmp dice3d_bet, 100 - jge dice_set_250 - cmp dice3d_bet, 50 - jge dice_set_100 - cmp dice3d_bet, 25 - jge dice_set_50 - jmp dice_set_25 -dice_set_500: - mov dice3d_bet, 500 - jmp dice_input_done -dice_set_250: - mov dice3d_bet, 250 - jmp dice_input_done -dice_set_100: - mov dice3d_bet, 100 - jmp dice_input_done -dice_set_50: - mov dice3d_bet, 50 - jmp dice_input_done -dice_set_25: - mov dice3d_bet, 25 - jmp dice_input_done - -check_dice_bet_down: - invoke Pressed3D, 28h ; DOWN - test eax, eax - jnz dice_dec_bet - invoke Pressed3D, 53h ; S - test eax, eax - jz dice_input_done -dice_dec_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp dice3d_bet, 25 - jle dice_set_10 - cmp dice3d_bet, 50 - jle dice_set_25 - cmp dice3d_bet, 100 - jle dice_set_50 - cmp dice3d_bet, 250 - jle dice_set_100 - mov dice3d_bet, 250 - jmp dice_input_done -dice_set_10: - mov dice3d_bet, 10 - -dice_input_done: +dice_done: ret HandleDiceInput ENDP RenderDiceGame PROC uses ebx esi edi - LOCAL d1X:DWORD, d1Y:DWORD, d2X:DWORD, d2Y:DWORD, bxX:DWORD + local kx:DWORD - ; Craps Emerald Felt & Oak Armrest - invoke DrawBox, 0, 0, 320, 240, 00082E12h - invoke DrawBoxBorder, 4, 4, 312, 232, 00093816h, 00122244h, 3 - invoke DrawBoxBorder, 8, 8, 304, 224, 000A3F19h, 0005140Ah, 2 + ; Mahogany frame & Deep Felt Green table + invoke DrawBox, 0, 0, 320, 240, 00140906h + invoke DrawBoxBorder, 6, 6, 308, 228, 000A3816h, 00FFD700h, 2 - ; Pyramidal diamond craps backboard texture - mov bxX, 12 -craps_bumper: - cmp bxX, 308 - jge craps_felt_markings - mov eax, bxX - add eax, 4 - invoke DrawBox, eax, 11, 4, 4, 00041006h - mov eax, bxX - add eax, 5 - invoke DrawPixel, eax, 12, 000F4820h - add bxX, 12 - jmp craps_bumper + ; Header + invoke DrawBoxBorder, 20, 12, 280, 26, 00072E13h, 00FFD700h, 2 + invoke DrawString8x8, 48, 21, OFFSET textDiceTitle, 00FFFF00h -craps_felt_markings: - ; Table Markings printed in gold directly on felt - invoke DrawString8x8, 72, 20, OFFSET textDiceTitle, 0000D7FFh - invoke DrawString8x8, 68, 32, OFFSET textDiceSubtitle, 0000B0A0h - - ; Meters: Bank & Bet - invoke DrawBoxBorder, 16, 46, 108, 16, 0006240Eh, 000E5022h, 1 - invoke DrawString8x8, 20, 50, OFFSET textBankPrompt, 0050FF50h + ; Status + invoke DrawBoxBorder, 20, 44, 110, 18, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 68, 50, OFFSET hudNumBuffer, 0050FF50h + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch - invoke DrawBoxBorder, 196, 46, 108, 16, 0006240Eh, 000E5022h, 1 - invoke DrawString8x8, 200, 50, OFFSET textBetPrompt, 0000D7FFh + invoke DrawBoxBorder, 190, 44, 110, 18, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h invoke FormatNumber, dice3d_bet, OFFSET hudNumBuffer - invoke DrawString8x8, 264, 50, OFFSET hudNumBuffer, 0000D7FFh + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h - ; Betting Zone Left: [1] ×¨Ò - mov eax, 00073014h - mov edx, 001A602Ah - mov ecx, 0080B090h + ; [1] ×¨Ò cmp dice3d_choice, 1 - jne @F - mov eax, 000B441Dh - mov edx, 0000FFFFh - mov ecx, 0000FFFFh -@@: - push ecx - invoke DrawBoxBorder, 16, 68, 88, 54, eax, edx, 2 - pop ecx - invoke DrawString8x8, 24, 74, OFFSET textDiceEven, ecx - invoke DrawString8x8, 20, 86, OFFSET textDiceEvenNums, 0000D7FFh - cmp dice3d_choice, 1 - jne @F - invoke DrawChipStack, 48, 110, 4 -@@: + jne dice_even_inactive + invoke DrawBoxBorder, 16, 70, 88, 48, 00072E13h, 00FFFF00h, 2 + invoke DrawString8x8, 30, 76, OFFSET textDiceEven, 00FFFF00h + invoke DrawString8x8, 22, 90, OFFSET textDiceEvenNums, 00FFD700h + invoke DrawString8x8, 26, 104, OFFSET textCoinSelected, 003CFF3Ch + jmp dice_odd_side +dice_even_inactive: + invoke DrawBoxBorder, 16, 70, 88, 48, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 30, 76, OFFSET textDiceEven, 00D0D8E0h + invoke DrawString8x8, 22, 90, OFFSET textDiceEvenNums, 0080B090h - ; Betting Zone Right: [2] ÍÅ×ÅÒ - mov eax, 00073014h - mov edx, 001A602Ah - mov ecx, 0080B090h +dice_odd_side: + ; [2] ÍÅ×ÅÒ cmp dice3d_choice, 2 - jne @F - mov eax, 000B441Dh - mov edx, 0000FFFFh - mov ecx, 0000FFFFh -@@: - push ecx - invoke DrawBoxBorder, 216, 68, 88, 54, eax, edx, 2 - pop ecx - invoke DrawString8x8, 224, 74, OFFSET textDiceOdd, ecx - invoke DrawString8x8, 224, 86, OFFSET textDiceOddNums, 00508060h - cmp dice3d_choice, 2 - jne @F - invoke DrawChipStack, 248, 110, 4 -@@: + jne dice_odd_inactive + invoke DrawBoxBorder, 216, 70, 88, 48, 00072E13h, 00FFFF00h, 2 + invoke DrawString8x8, 226, 76, OFFSET textDiceOdd, 00FFFF00h + invoke DrawString8x8, 224, 90, OFFSET textDiceOddNums, 00FFD700h + invoke DrawString8x8, 226, 104, OFFSET textCoinSelected, 003CFF3Ch + jmp dice_center_cubes +dice_odd_inactive: + invoke DrawBoxBorder, 216, 70, 88, 48, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 226, 76, OFFSET textDiceOdd, 00D0D8E0h + invoke DrawString8x8, 224, 90, OFFSET textDiceOddNums, 0080B090h - ; Center Dice Field - invoke DrawBoxBorder, 112, 68, 96, 54, 00072E13h, 00145826h, 1 +dice_center_cubes: + ; 2 Dice in center + invoke DrawCrapsDie, 116, 76, 36, dice3d_val1 + invoke DrawCrapsDie, 168, 76, 36, dice3d_val2 - ; Rolling Animation Logic cmp dice3d_state, 1 - jne dice_at_rest - - inc dice3d_timer - - ; Tumbling jitter offsets - mov eax, dice3d_timer - and eax, 3 - sub eax, 1 - - mov edx, 120 - add edx, eax - mov d1X, edx - mov edx, 76 - sub edx, eax - mov d1Y, edx - - mov edx, 164 - sub edx, eax - mov d2X, edx - mov edx, 78 - add edx, eax - mov d2Y, edx - - test dice3d_timer, 1 - jz @F - invoke RandomRange3D, 6 - inc eax - mov dice3d_val1, eax - invoke RandomRange3D, 6 - inc eax - mov dice3d_val2, eax -@@: - invoke DrawCrapsDie, d1X, d1Y, 36, dice3d_val1 - invoke DrawCrapsDie, d2X, d2Y, 36, dice3d_val2 - invoke DrawString8x8, 76, 138, OFFSET textDiceRolling, 0000FFFFh - - cmp dice3d_timer, 36 - jl dice_draw_controls - - ; Settle dice! - mov dice3d_state, 2 - invoke RandomRange3D, 6 - inc eax - mov dice3d_val1, eax - invoke RandomRange3D, 6 - inc eax - mov dice3d_val2, eax - - mov eax, dice3d_val1 - add eax, dice3d_val2 - mov dice3d_sum, eax - - ; Check choice vs sum parity - mov eax, dice3d_sum - test eax, 1 - jz dice_sum_is_even - - ; Odd - cmp dice3d_choice, 2 - je dice_roll_won - jmp dice_roll_lost - -dice_sum_is_even: - cmp dice3d_choice, 1 - je dice_roll_won - -dice_roll_lost: - mov dice3d_win, 0 - invoke PlaySoundA, OFFSET soundLose, 0, 1 - jmp dice_draw_controls - -dice_roll_won: - mov eax, dice3d_bet - shl eax, 1 - mov dice3d_win, eax - add bankroll, eax - invoke PlaySoundA, OFFSET soundVictory, 0, 1 - jmp dice_draw_controls - -dice_at_rest: - invoke DrawCrapsDie, 120, 76, 36, dice3d_val1 - invoke DrawCrapsDie, 164, 76, 36, dice3d_val2 - + je dice_render_rolling cmp dice3d_state, 2 - jne dice_draw_controls + je dice_render_result + jmp dice_render_keys - ; Scoreboard Plaque - invoke DrawBoxBorder, 36, 130, 248, 30, 00051D0Ch, 0000D7FFh, 1 - invoke DrawString8x8, 44, 135, OFFSET textDiceSumHdr, 0000D7FFh +dice_render_rolling: + invoke DrawString8x8, 76, 138, OFFSET textDiceRolling, 00FFFF00h + jmp dice_render_keys + +dice_render_result: + invoke DrawBoxBorder, 36, 130, 248, 36, 00072E13h, 00FFD700h, 1 + invoke DrawString8x8, 44, 135, OFFSET textDiceSumHdr, 00FFD700h invoke FormatNumber, dice3d_val1, OFFSET hudNumBuffer - invoke DrawString8x8, 100, 135, OFFSET hudNumBuffer, 00FFFFFFh - invoke DrawString8x8, 110, 135, OFFSET textDicePlus, 0000D7FFh + invoke DrawString8x8, 92, 135, OFFSET hudNumBuffer, 00FFFF00h + invoke DrawString8x8, 110, 135, OFFSET textDicePlus, 00FFD700h invoke FormatNumber, dice3d_val2, OFFSET hudNumBuffer - invoke DrawString8x8, 134, 135, OFFSET hudNumBuffer, 00FFFFFFh - invoke DrawString8x8, 144, 135, OFFSET textDiceEqual, 0000D7FFh + invoke DrawString8x8, 126, 135, OFFSET hudNumBuffer, 00FFFF00h + invoke DrawString8x8, 144, 135, OFFSET textDiceEqual, 00FFD700h invoke FormatNumber, dice3d_sum, OFFSET hudNumBuffer - invoke DrawString8x8, 168, 135, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 168, 135, OFFSET hudNumBuffer, 00FFFF00h mov eax, dice3d_sum - test eax, 1 - jnz @F - invoke DrawString8x8, 186, 135, OFFSET textDiceEvenResult, 0080FF80h - jmp dice_show_win_msg -@@: - invoke DrawString8x8, 186, 135, OFFSET textDiceOddResult, 00FF8080h + and eax, 1 + jnz dice_render_odd_res + invoke DrawString8x8, 186, 135, OFFSET textDiceEvenResult, 003CFF3Ch + jmp dice_render_outcome +dice_render_odd_res: + invoke DrawString8x8, 186, 135, OFFSET textDiceOddResult, 003CFF3Ch -dice_show_win_msg: - cmp dice3d_win, 0 - je dice_show_loss - invoke DrawString8x8, 68, 147, OFFSET textDiceWin, 0050FF50h +dice_render_outcome: + mov eax, dice3d_win + test eax, eax + jz dice_render_loss_outcome + invoke DrawString8x8, 68, 150, OFFSET textDiceWin, 003CFF3Ch invoke FormatNumber, dice3d_win, OFFSET hudNumBuffer - invoke DrawString8x8, 156, 147, OFFSET hudNumBuffer, 0050FF50h - invoke DrawString8x8, 188, 147, OFFSET textDiceWinMult, 0050FF50h - jmp dice_draw_controls + invoke DrawString8x8, 156, 150, OFFSET hudNumBuffer, 003CFF3Ch + invoke DrawString8x8, 188, 150, OFFSET textDiceWinMult, 003CFF3Ch + jmp dice_render_keys -dice_show_loss: - invoke DrawString8x8, 116, 147, OFFSET textDiceLose, 008080FFh +dice_render_loss_outcome: + invoke DrawString8x8, 116, 150, OFFSET textDiceLose, 00FF6464h -dice_draw_controls: - invoke DrawBox, 16, 188, 288, 1, 00104820h - - mov eax, 0 +dice_render_keys: + mov kx, 16 + xor eax, eax cmp dice3d_choice, 1 sete al - invoke DrawKeycap3D, 20, 198, OFFSET textDiceKey1, eax + invoke DrawKeycap3D, kx, 192, OFFSET textDiceKey1, eax + add kx, eax - mov eax, 0 + xor eax, eax cmp dice3d_choice, 2 sete al - invoke DrawKeycap3D, 82, 198, OFFSET textDiceKey2, eax + invoke DrawKeycap3D, kx, 192, OFFSET textDiceKey2, eax + add kx, eax - invoke DrawKeycap3D, 160, 198, OFFSET textDiceKeySpace, 1 - invoke DrawKeycap3D, 274, 198, OFFSET textKeyEsc, 0 + invoke DrawKeycap3D, kx, 192, OFFSET textDiceKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 ret RenderDiceGame ENDP @@ -3707,138 +3629,133 @@ RenderDiceGame ENDP ; IN-ENGINE 2.5D MINI-GAME: SKULLS & CUPS (ÍÀϨÐÑÒÊÈ) ; ============================================================================== DrawGlowingOrb PROC uses ebx esi edi, cxVal:DWORD, cyVal:DWORD - invoke DrawCircle, cxVal, cyVal, 14, 00081E2Eh - invoke DrawCircle, cxVal, cyVal, 11, 00103A58h - invoke DrawCircle, cxVal, cyVal, 8, 001A588Ah - invoke DrawCircle, cxVal, cyVal, 6, 0000B0E0h - invoke DrawCircle, cxVal, cyVal, 4, 0000E0FFh + invoke DrawCircle, cxVal, cyVal, 14, 002E1E08h + invoke DrawCircle, cxVal, cyVal, 11, 00583A10h + invoke DrawCircle, cxVal, cyVal, 8, 008A581Ah + invoke DrawCircle, cxVal, cyVal, 6, 00D0B000h + invoke DrawCircle, cxVal, cyVal, 4, 00FFE000h mov eax, cxVal dec eax mov edx, cyVal dec edx - invoke DrawCircle, eax, edx, 2, 00A0FFFFh - mov eax, cxVal - sub eax, 2 - mov edx, cyVal - sub edx, 2 + invoke DrawCircle, eax, edx, 2, 00FFFF80h + dec eax + dec edx invoke DrawPixel, eax, edx, 00FFFFFFh ret DrawGlowingOrb ENDP DrawGothicCup PROC uses ebx esi edi, x:DWORD, y:DWORD, cupId:DWORD, isLifted:DWORD, hasBall:DWORD - LOCAL liftY:DWORD + local liftY:DWORD mov eax, y cmp isLifted, 0 je @F - sub eax, 28 + sub eax, 36 @@: mov liftY, eax - ; Drop shadow on purple velvet + ; Drop shadow cmp isLifted, 0 - jne @F + jne cup_shadow_lifted mov eax, x add eax, 6 mov edx, y add edx, 42 - invoke DrawBox, eax, edx, 36, 4, 000A0410h - jmp draw_cup_body -@@: + invoke DrawBox, eax, edx, 36, 4, 0010040Ah + jmp cup_ball_check +cup_shadow_lifted: mov eax, x add eax, 10 mov edx, y add edx, 42 - invoke DrawBox, eax, edx, 28, 2, 0012061Ah + invoke DrawBox, eax, edx, 28, 2, 001A0612h - ; Draw orb if lifted and has ball +cup_ball_check: + cmp isLifted, 0 + je cup_body_draw cmp hasBall, 0 - je draw_cup_body + je cup_body_draw mov eax, x add eax, 24 mov edx, y add edx, 26 invoke DrawGlowingOrb, eax, edx -draw_cup_body: - ; Base +cup_body_draw: + ; Base pedestal mov eax, x add eax, 6 mov edx, liftY add edx, 36 - invoke DrawBoxBorder, eax, edx, 36, 6, 00221A30h, 0000B0D0h, 1 + invoke DrawBoxBorder, eax, edx, 36, 6, 00301A22h, 00D0B000h, 1 ; Stem mov eax, x add eax, 18 mov edx, liftY add edx, 28 - invoke DrawBox, eax, edx, 12, 8, 00332545h + invoke DrawBox, eax, edx, 12, 8, 00452533h mov eax, x add eax, 22 - mov edx, liftY - add edx, 28 - invoke DrawBox, eax, edx, 4, 8, 0055406Eh + invoke DrawBox, eax, edx, 4, 8, 006E4055h - ; Bowl + ; Goblet Bowl mov eax, x add eax, 8 mov edx, liftY add edx, 8 - invoke DrawBoxBorder, eax, edx, 32, 20, 002D1E40h, 0000D7FFh, 1 + invoke DrawBoxBorder, eax, edx, 32, 20, 00401E2Dh, 00FFD700h, 1 + mov eax, x add eax, 14 mov edx, liftY add edx, 10 - invoke DrawBox, eax, edx, 6, 16, 00503570h + invoke DrawBox, eax, edx, 6, 16, 00703550h mov eax, x add eax, 17 - mov edx, liftY - add edx, 10 - invoke DrawBox, eax, edx, 3, 16, 007850A0h + invoke DrawBox, eax, edx, 3, 16, 00A05078h - ; Flared Rim + ; Golden Rim mov eax, x add eax, 4 mov edx, liftY add edx, 2 - invoke DrawBoxBorder, eax, edx, 40, 7, 00150A20h, 0000FFFFh, 1 + invoke DrawBoxBorder, eax, edx, 40, 7, 00200A15h, 00FFFF00h, 1 mov eax, x add eax, 12 mov edx, liftY add edx, 4 - invoke DrawBox, eax, edx, 16, 2, 0000FFFFh + invoke DrawBox, eax, edx, 16, 2, 00FFFF00h - ; Skull Insignia on Bowl + ; Skull face emblem mov eax, x add eax, 21 mov edx, liftY add edx, 12 - invoke DrawBox, eax, edx, 6, 5, 0000D7FFh + invoke DrawBox, eax, edx, 6, 5, 00FFD700h mov eax, x add eax, 22 mov edx, liftY add edx, 17 - invoke DrawBox, eax, edx, 4, 3, 0000D7FFh + invoke DrawBox, eax, edx, 4, 3, 00FFD700h mov eax, x add eax, 22 mov edx, liftY add edx, 14 - invoke DrawPixel, eax, edx, 00150A20h + invoke DrawPixel, eax, edx, 00200A15h mov eax, x add eax, 24 - mov edx, liftY - add edx, 14 - invoke DrawPixel, eax, edx, 00150A20h + invoke DrawPixel, eax, edx, 00200A15h - ; Cup ID Badge + ; Cup number label mov eax, x add eax, 21 mov edx, liftY add edx, 24 mov ecx, cupId - add ecx, '0' - invoke DrawChar8x8, eax, edx, ecx, 0000FFFFh + add ecx, '1' + invoke DrawChar8x8, eax, edx, ecx, 00FFFF00h ret DrawGothicCup ENDP @@ -3846,445 +3763,657 @@ InitSkullsGame PROC mov skulls3d_state, 0 mov skulls3d_timer, 0 mov skulls3d_win, 0 - cmp skulls3d_bet, 10 - jge @F - mov skulls3d_bet, 50 -@@: invoke RandomRange3D, 3 mov skulls3d_ballPos, eax + mov skulls3d_choice, 1 ret InitSkullsGame ENDP FinalizeSkullsGuess PROC uses ebx - mov skulls3d_state, 4 mov eax, skulls3d_choice cmp eax, skulls3d_ballPos - jne skulls_guess_lost + jne skulls_guess_wrong - ; Won 3x! + ; Won! 3x payout mov eax, skulls3d_bet imul eax, 3 - mov skulls3d_win, eax add bankroll, eax - invoke PlaySoundA, OFFSET soundVictory, 0, 1 + mov skulls3d_win, eax + mov skulls3d_state, 4 + invoke PlaySoundA, OFFSET soundJackpot, 0, 1 ret -skulls_guess_lost: +skulls_guess_wrong: mov skulls3d_win, 0 + mov skulls3d_state, 4 invoke PlaySoundA, OFFSET soundLose, 0, 1 ret FinalizeSkullsGuess ENDP HandleSkullsInput PROC + cmp skulls3d_state, 0 + je skulls_handle_idle cmp skulls3d_state, 1 - je skulls_input_done + je skulls_handle_show cmp skulls3d_state, 2 - je skulls_input_done - + je skulls_handle_shuffle cmp skulls3d_state, 3 - je check_skulls_pick + je skulls_handle_pick + cmp skulls3d_state, 4 + je skulls_handle_reveal + ret - ; State 0 or 4: Can start new round or adjust bet - invoke Pressed3D, 20h ; SPACE +skulls_handle_idle: + invoke Pressed3D, 26h ; UP test eax, eax - jz check_skulls_bet_adjust + jnz skulls_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz skulls_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz skulls_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz skulls_bet_down + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz skulls_start_game + ret +skulls_bet_up: + mov eax, skulls3d_bet + add eax, 50 + cmp eax, bankroll + jle @F mov eax, bankroll - cmp eax, skulls3d_bet - jl skulls_no_cash - sub eax, skulls3d_bet - mov bankroll, eax +@@: + cmp eax, 5000 + jle @F + mov eax, 5000 +@@: + mov skulls3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret +skulls_bet_down: + mov eax, skulls3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov skulls3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skulls_start_game: + mov eax, skulls3d_bet + cmp eax, bankroll + jle @F + mov eax, bankroll + mov skulls3d_bet, eax + test eax, eax + jz skulls_done +@@: + mov eax, skulls3d_bet + sub bankroll, eax invoke RandomRange3D, 3 mov skulls3d_ballPos, eax - - invoke RandomRange3D, 3 - mov skulls3d_swapPair0, eax - invoke RandomRange3D, 3 - mov skulls3d_swapPair1, eax - invoke RandomRange3D, 3 - mov skulls3d_swapPair2, eax - mov skulls3d_state, 1 - mov skulls3d_timer, 0 - mov skulls3d_win, 0 + mov skulls3d_timer, 45 invoke PlaySoundA, OFFSET soundShuffle, 0, 1 - jmp skulls_input_done + ret -skulls_no_cash: - invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage - mov flashTimer, 60 - invoke PlaySoundA, OFFSET soundClick, 0, 1 - jmp skulls_input_done +skulls_handle_show: + dec skulls3d_timer + cmp skulls3d_timer, 0 + jg skulls_done + mov skulls3d_state, 2 + mov skulls3d_timer, 60 + invoke PlaySoundA, OFFSET soundShuffle, 0, 1 + ret -check_skulls_pick: - invoke Pressed3D, 31h ; '1' +skulls_handle_shuffle: + dec skulls3d_timer + cmp skulls3d_timer, 0 + jg skulls_done + invoke RandomRange3D, 3 + mov skulls3d_ballPos, eax + mov skulls3d_state, 3 + ret + +skulls_handle_pick: + invoke Pressed3D, 31h ; '1' test eax, eax - jz @F + jnz skulls_pick_1 + invoke Pressed3D, 32h ; '2' + test eax, eax + jnz skulls_pick_2 + invoke Pressed3D, 33h ; '3' + test eax, eax + jnz skulls_pick_3 + ret + +skulls_pick_1: mov skulls3d_choice, 0 call FinalizeSkullsGuess - jmp skulls_input_done -@@: - invoke Pressed3D, 32h ; '2' - test eax, eax - jz @F + ret + +skulls_pick_2: mov skulls3d_choice, 1 call FinalizeSkullsGuess - jmp skulls_input_done -@@: - invoke Pressed3D, 33h ; '3' - test eax, eax - jz skulls_input_done + ret + +skulls_pick_3: mov skulls3d_choice, 2 call FinalizeSkullsGuess - jmp skulls_input_done + ret -check_skulls_bet_adjust: - invoke Pressed3D, 26h ; UP +skulls_handle_reveal: + invoke Pressed3D, 20h test eax, eax - jnz skulls_inc_bet - invoke Pressed3D, 57h ; W - test eax, eax - jz check_skulls_bet_down -skulls_inc_bet: + jz skulls_done + mov skulls3d_state, 0 invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp skulls3d_bet, 500 - jge skulls_input_done - cmp skulls3d_bet, 250 - jge skulls_set_500 - cmp skulls3d_bet, 100 - jge skulls_set_250 - cmp skulls3d_bet, 50 - jge skulls_set_100 - cmp skulls3d_bet, 25 - jge skulls_set_50 - jmp skulls_set_25 -skulls_set_500: - mov skulls3d_bet, 500 - jmp skulls_input_done -skulls_set_250: - mov skulls3d_bet, 250 - jmp skulls_input_done -skulls_set_100: - mov skulls3d_bet, 100 - jmp skulls_input_done -skulls_set_50: - mov skulls3d_bet, 50 - jmp skulls_input_done -skulls_set_25: - mov skulls3d_bet, 25 - jmp skulls_input_done - -check_skulls_bet_down: - invoke Pressed3D, 28h ; DOWN - test eax, eax - jnz skulls_dec_bet - invoke Pressed3D, 53h ; S - test eax, eax - jz skulls_input_done -skulls_dec_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp skulls3d_bet, 25 - jle skulls_set_10 - cmp skulls3d_bet, 50 - jle skulls_set_25 - cmp skulls3d_bet, 100 - jle skulls_set_50 - cmp skulls3d_bet, 250 - jle skulls_set_100 - mov skulls3d_bet, 250 - jmp skulls_input_done -skulls_set_10: - mov skulls3d_bet, 10 - -skulls_input_done: +skulls_done: ret HandleSkullsInput ENDP RenderSkullsGame PROC uses ebx esi edi - LOCAL passTick:DWORD, curPair:DWORD, swapSlotA:DWORD, swapSlotB:DWORD - LOCAL xA:DWORD, xB:DWORD, curXA:DWORD, curXB:DWORD, curYA:DWORD, curYB:DWORD - LOCAL distX:DWORD, dxVal:DWORD, archY:DWORD + local kx:DWORD - ; Dark Gothic Tavern Table with Royal Velvet - invoke DrawBox, 0, 0, 320, 240, 000D0612h - invoke DrawBoxBorder, 4, 4, 312, 232, 00160B20h, 00321845h, 3 - invoke DrawBoxBorder, 8, 8, 304, 224, 00220F30h, 0000D7FFh, 1 + ; Mahogany & Gothic Purple table + invoke DrawBox, 0, 0, 320, 240, 00140906h + invoke DrawBoxBorder, 6, 6, 308, 228, 00300F22h, 00FFD700h, 2 ; Header - invoke DrawBoxBorder, 24, 12, 272, 24, 0012081Ah, 0000D7FFh, 2 - invoke DrawString8x8, 64, 20, OFFSET textSkullsTitle, 0000FFFFh + invoke DrawBoxBorder, 20, 12, 280, 26, 001A0812h, 00FFD700h, 2 + invoke DrawString8x8, 40, 21, OFFSET textSkullsTitle, 00FFFF00h - ; Meters: Bank & Bet - invoke DrawBoxBorder, 20, 42, 114, 16, 000D0616h, 00401858h, 1 - invoke DrawString8x8, 24, 46, OFFSET textBankPrompt, 0050FF50h + ; Status + invoke DrawBoxBorder, 20, 44, 110, 18, 001A0812h, 00452033h, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 72, 46, OFFSET hudNumBuffer, 0050FF50h + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch - invoke DrawBoxBorder, 186, 42, 114, 16, 000D0616h, 00401858h, 1 - invoke DrawString8x8, 190, 46, OFFSET textBetPrompt, 0000D7FFh + invoke DrawBoxBorder, 190, 44, 110, 18, 001A0812h, 00452033h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h invoke FormatNumber, skulls3d_bet, OFFSET hudNumBuffer - invoke DrawString8x8, 254, 46, OFFSET hudNumBuffer, 0000D7FFh + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h - ; Velvet Table Runner - invoke DrawBoxBorder, 16, 64, 288, 120, 001A0B25h, 00452060h, 1 - - ; Dispatch based on phase + ; Subtitle phase prompts + cmp skulls3d_state, 0 + jne @F + invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase0, 00FFD700h + jmp skulls_render_cups +@@: cmp skulls3d_state, 1 - je skulls_render_phase1 + jne @F + invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase1, 00FFFF00h + jmp skulls_render_cups +@@: cmp skulls3d_state, 2 - je skulls_render_phase2 + jne @F + invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase2, 00FFFF00h + jmp skulls_render_cups +@@: cmp skulls3d_state, 3 - je skulls_render_phase3 - cmp skulls3d_state, 4 - je skulls_render_phase4 - - ; Phase 0: Idle / Betting - invoke DrawString8x8, 56, 70, OFFSET textSkullsPhase0, 0000D7FFh - invoke DrawGothicCup, 48, 108, 1, 0, 0 - invoke DrawGothicCup, 136, 108, 2, 0, 0 - invoke DrawGothicCup, 224, 108, 3, 0, 0 - jmp skulls_draw_controls - -skulls_render_phase1: - inc skulls3d_timer - invoke DrawString8x8, 56, 70, OFFSET textSkullsPhase1, 0000FFFFh - - ; Draw cups with ballPos cup lifted - mov eax, 0 - cmp skulls3d_ballPos, 0 - sete al - invoke DrawGothicCup, 48, 108, 1, eax, eax - - mov eax, 0 - cmp skulls3d_ballPos, 1 - sete al - invoke DrawGothicCup, 136, 108, 2, eax, eax - - mov eax, 0 - cmp skulls3d_ballPos, 2 - sete al - invoke DrawGothicCup, 224, 108, 3, eax, eax - - cmp skulls3d_timer, 40 - jl skulls_draw_controls - - ; Start Phase 2 (Shuffle) - mov skulls3d_state, 2 - mov skulls3d_timer, 0 - invoke PlaySoundA, OFFSET soundShuffle, 0, 1 - jmp skulls_draw_controls - -skulls_render_phase2: - inc skulls3d_timer - - mov eax, skulls3d_timer - cmp eax, 20 - jbe pass_0 - cmp eax, 40 - jbe pass_1 - sub eax, 41 - mov passTick, eax - mov eax, skulls3d_swapPair2 - mov curPair, eax - jmp setup_pass_pair - -pass_0: - dec eax - mov passTick, eax - mov eax, skulls3d_swapPair0 - mov curPair, eax - jmp setup_pass_pair - -pass_1: - sub eax, 21 - mov passTick, eax - mov eax, skulls3d_swapPair1 - mov curPair, eax - -setup_pass_pair: - cmp curPair, 1 - je pair_1 - cmp curPair, 2 - je pair_2 - mov swapSlotA, 0 - mov swapSlotB, 1 - mov xA, 48 - mov xB, 136 - jmp calc_swap_coords -pair_1: - mov swapSlotA, 1 - mov swapSlotB, 2 - mov xA, 136 - mov xB, 224 - jmp calc_swap_coords -pair_2: - mov swapSlotA, 0 - mov swapSlotB, 2 - mov xA, 48 - mov xB, 224 - -calc_swap_coords: - mov eax, xB - sub eax, xA - mov distX, eax - - mov eax, distX - imul eax, passTick - xor edx, edx - mov ecx, 20 - div ecx - mov dxVal, eax - - mov eax, xA - add eax, dxVal - mov curXA, eax - - mov eax, xB - sub eax, dxVal - mov curXB, eax - - ; Arch height: archY = (t * (20 - t)) / 25 - mov eax, passTick - mov ecx, 20 - sub ecx, eax - imul eax, ecx - xor edx, edx - mov ecx, 25 - div ecx - mov archY, eax - - mov edx, 108 - sub edx, archY - mov curYA, edx ; upper arc - - mov edx, 108 - add edx, archY - mov curYB, edx ; lower arc - - invoke DrawString8x8, 56, 70, OFFSET textSkullsPhase2, 0000FFFFh - - ; Depth sorted rendering: Background cup (upper arc) draws FIRST, Foreground cup (lower arc) draws OVER it! - invoke DrawGothicCup, curXA, curYA, 1, 0, 0 - invoke DrawGothicCup, curXB, curYB, 2, 0, 0 - - ; Draw remaining static cup - cmp curPair, 1 - je draw_stat_0 - cmp curPair, 2 - je draw_stat_1 - invoke DrawGothicCup, 224, 108, 3, 0, 0 - jmp check_pass_finish -draw_stat_0: - invoke DrawGothicCup, 48, 108, 1, 0, 0 - jmp check_pass_finish -draw_stat_1: - invoke DrawGothicCup, 136, 108, 2, 0, 0 - -check_pass_finish: - cmp skulls3d_timer, 20 - je do_pass_swap - cmp skulls3d_timer, 40 - je do_pass_swap - cmp skulls3d_timer, 60 - je do_pass_swap - jmp skulls_draw_controls - -do_pass_swap: - ; Update ballPos if involved in swap - mov eax, skulls3d_ballPos - cmp eax, swapSlotA - jne check_swap_b - mov eax, swapSlotB - mov skulls3d_ballPos, eax - jmp ball_swap_done -check_swap_b: - cmp eax, swapSlotB - jne ball_swap_done - mov eax, swapSlotA - mov skulls3d_ballPos, eax - -ball_swap_done: - invoke PlaySoundA, OFFSET soundShuffle, 0, 1 - - cmp skulls3d_timer, 60 - jl skulls_draw_controls - - ; Shuffle complete -> Move to Pick phase - mov skulls3d_state, 3 - mov skulls3d_timer, 0 - jmp skulls_draw_controls - -skulls_render_phase3: - invoke DrawString8x8, 40, 70, OFFSET textSkullsPhase3, 0000FFFFh - invoke DrawGothicCup, 48, 108, 1, 0, 0 - invoke DrawGothicCup, 136, 108, 2, 0, 0 - invoke DrawGothicCup, 224, 108, 3, 0, 0 - jmp skulls_draw_controls - -skulls_render_phase4: - ; Reveal phase - cmp skulls3d_win, 0 - je skulls_show_loss - invoke DrawString8x8, 48, 70, OFFSET textSkullsWin, 0050FF50h + jne @F + invoke DrawString8x8, 40, 62, OFFSET textSkullsPhase3, 00FFFF00h + jmp skulls_render_cups +@@: + ; Reveal outcome + mov eax, skulls3d_win + test eax, eax + jz skulls_show_loss_text + invoke DrawString8x8, 40, 62, OFFSET textSkullsWin, 003CFF3Ch invoke FormatNumber, skulls3d_win, OFFSET hudNumBuffer - invoke DrawString8x8, 216, 70, OFFSET hudNumBuffer, 0050FF50h - jmp skulls_p4_cups + invoke DrawString8x8, 136, 62, OFFSET hudNumBuffer, 003CFF3Ch + invoke DrawString8x8, 168, 62, OFFSET textSkullsWinMult, 003CFF3Ch + jmp skulls_render_cups -skulls_show_loss: - invoke DrawString8x8, 40, 70, OFFSET textSkullsLose, 008080FFh +skulls_show_loss_text: + invoke DrawString8x8, 40, 62, OFFSET textSkullsLose, 00FF6464h -skulls_p4_cups: - ; Draw chosen cup lifted - mov eax, 0 - cmp skulls3d_choice, 0 - sete al +skulls_render_cups: + ; Draw Cup 1 (X=36, Y=114) + mov ebx, 0 mov edx, 0 + cmp skulls3d_state, 1 + jne @F + cmp skulls3d_ballPos, 0 + jne @F + mov ebx, 1 + mov edx, 1 +@@: + cmp skulls3d_state, 4 + jne @F + cmp skulls3d_choice, 0 + sete bl cmp skulls3d_ballPos, 0 sete dl - invoke DrawGothicCup, 48, 108, 1, eax, edx +@@: + invoke DrawGothicCup, 36, 114, 0, ebx, edx - mov eax, 0 - cmp skulls3d_choice, 1 - sete al + ; Draw Cup 2 (X=136, Y=114) + mov ebx, 0 mov edx, 0 + cmp skulls3d_state, 1 + jne @F + cmp skulls3d_ballPos, 1 + jne @F + mov ebx, 1 + mov edx, 1 +@@: + cmp skulls3d_state, 4 + jne @F + cmp skulls3d_choice, 1 + sete bl cmp skulls3d_ballPos, 1 sete dl - invoke DrawGothicCup, 136, 108, 2, eax, edx +@@: + invoke DrawGothicCup, 136, 114, 1, ebx, edx - mov eax, 0 - cmp skulls3d_choice, 2 - sete al + ; Draw Cup 3 (X=236, Y=114) + mov ebx, 0 mov edx, 0 + cmp skulls3d_state, 1 + jne @F + cmp skulls3d_ballPos, 2 + jne @F + mov ebx, 1 + mov edx, 1 +@@: + cmp skulls3d_state, 4 + jne @F + cmp skulls3d_choice, 2 + sete bl cmp skulls3d_ballPos, 2 sete dl - invoke DrawGothicCup, 224, 108, 3, eax, edx +@@: + invoke DrawGothicCup, 236, 114, 2, ebx, edx - invoke DrawString8x8, 64, 168, OFFSET textSkullsAgain, 0000D7FFh + ; Cup selection indicators + invoke DrawString8x8, 54, 168, OFFSET textSkullsKey1, 00D0D8E0h + invoke DrawString8x8, 150, 168, OFFSET textSkullsKey2, 00D0D8E0h + invoke DrawString8x8, 250, 168, OFFSET textSkullsKey3, 00D0D8E0h -skulls_draw_controls: - invoke DrawBox, 16, 190, 288, 1, 003A1850h - - mov eax, 0 + ; Keycaps + mov kx, 16 + xor eax, eax cmp skulls3d_choice, 0 sete al - invoke DrawKeycap3D, 18, 200, OFFSET textSkullsKey1, eax + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey1, eax + add kx, eax - mov eax, 0 + xor eax, eax cmp skulls3d_choice, 1 sete al - invoke DrawKeycap3D, 82, 200, OFFSET textSkullsKey2, eax + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey2, eax + add kx, eax - mov eax, 0 + xor eax, eax cmp skulls3d_choice, 2 sete al - invoke DrawKeycap3D, 146, 200, OFFSET textSkullsKey3, eax + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey3, eax + add kx, eax - invoke DrawKeycap3D, 212, 200, OFFSET textSkullsKeySpace, 1 - invoke DrawKeycap3D, 274, 200, OFFSET textKeyEsc, 0 + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 ret RenderSkullsGame ENDP +; ============================================================================== +; IN-ENGINE 2.5D MINI-GAME: SKILL CHECK (DEAD BY DAYLIGHT SURVIVOR CHECK) +; ============================================================================== +InitSkillGame PROC + mov skill3d_state, 0 + mov skill3d_timer, 0 + mov skill3d_hits, 0 + mov skill3d_misses, 0 + mov skill3d_needle, 55 + mov skill3d_speed, 4 + mov skill3d_dir, 1 + mov skill3d_last_result, 0 + mov skill3d_win_amount, 0 + + ; Randomize initial zone: 80 + RandomRange(90) -> 80..170 + invoke RandomRange3D, 90 + add eax, 80 + mov skill3d_zone_start, eax + + ; Great zone: start + 20 + RandomRange(12) + invoke RandomRange3D, 12 + add eax, skill3d_zone_start + add eax, 20 + mov skill3d_great_start, eax + ret +InitSkillGame ENDP + +HandleSkillInput PROC uses ebx esi + mov eax, skill3d_state + cmp eax, 0 + je skill_handle_ready + cmp eax, 1 + je skill_handle_active + cmp eax, 2 + je skill_handle_round_wait + cmp eax, 3 + je skill_handle_round_wait + cmp eax, 4 + je skill_handle_end_wait + cmp eax, 5 + je skill_handle_end_wait + ret + +skill_handle_ready: + invoke Pressed3D, 26h ; UP + test eax, eax + jnz skill_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz skill_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz skill_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz skill_bet_down + jmp skill_check_start + +skill_bet_up: + mov eax, skill3d_bet + add eax, 50 + cmp eax, bankroll + jle @F + mov eax, bankroll +@@: + cmp eax, 5000 + jle @F + mov eax, 5000 +@@: + mov skill3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skill_bet_down: + mov eax, skill3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov skill3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skill_check_start: + invoke Pressed3D, 20h ; SPACE + test eax, eax + jz skill_input_done + + ; Deduct bet on game start if beginning of run + mov eax, skill3d_hits + or eax, skill3d_misses + jnz @F + mov eax, skill3d_bet + cmp eax, bankroll + jle skill_has_funds + mov eax, bankroll + mov skill3d_bet, eax + test eax, eax + jz skill_input_done +skill_has_funds: + mov eax, skill3d_bet + sub bankroll, eax +@@: + mov skill3d_state, 1 + mov skill3d_needle, 55 + mov skill3d_dir, 1 + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skill_handle_active: + ; Move needle smoothly + mov eax, skill3d_needle + mov edx, skill3d_speed + cmp skill3d_dir, 1 + je skill_move_right + sub eax, edx + cmp eax, 52 + jge skill_update_needle + mov eax, 52 + mov skill3d_dir, 1 + jmp skill_update_needle +skill_move_right: + add eax, edx + cmp eax, 268 + jle skill_update_needle + mov eax, 268 + mov skill3d_dir, -1 +skill_update_needle: + mov skill3d_needle, eax + + ; Check SPACE pressed (Reaction Hit Attempt!) + invoke Pressed3D, 20h + test eax, eax + jz skill_input_done + + ; Is needle in Great Sweet Spot? + mov eax, skill3d_needle + mov edx, skill3d_great_start + cmp eax, edx + jl check_success_zone + add edx, skill3d_great_width + cmp eax, edx + jg check_success_zone + + ; GREAT HIT! + mov skill3d_last_result, 2 + add skill3d_hits, 2 + mov skill3d_state, 2 + mov skill3d_timer, 40 + invoke PlaySoundA, OFFSET soundCoinDing, 0, 1 + jmp skill_check_finish_round + +check_success_zone: + mov eax, skill3d_needle + mov edx, skill3d_zone_start + cmp eax, edx + jl skill_was_miss + add edx, skill3d_zone_width + cmp eax, edx + jg skill_was_miss + + ; NORMAL HIT! + mov skill3d_last_result, 1 + inc skill3d_hits + mov skill3d_state, 2 + mov skill3d_timer, 40 + invoke PlaySoundA, OFFSET soundVictory, 0, 1 + jmp skill_check_finish_round + +skill_was_miss: + ; MISS! + mov skill3d_last_result, 0 + inc skill3d_misses + mov skill3d_state, 3 + mov skill3d_timer, 45 + invoke PlaySoundA, OFFSET soundLose, 0, 1 + +skill_check_finish_round: + cmp skill3d_hits, 5 + jge skill_game_escaped + cmp skill3d_misses, 3 + jge skill_game_lost + ret + +skill_game_escaped: + mov skill3d_state, 4 + mov skill3d_timer, 0 + ; Payout: 3x total return (+$2x bet profit) + mov eax, skill3d_bet + imul eax, 3 + add bankroll, eax + mov eax, skill3d_bet + shl eax, 1 + mov skill3d_win_amount, eax + invoke PlaySoundA, OFFSET soundJackpot, 0, 1 + ret + +skill_game_lost: + mov skill3d_state, 5 + mov skill3d_timer, 0 + invoke PlaySoundA, OFFSET soundLose, 0, 1 + ret + +skill_handle_round_wait: + dec skill3d_timer + cmp skill3d_timer, 0 + jg skill_input_done + + ; Next round setup + invoke RandomRange3D, 90 + add eax, 80 + mov skill3d_zone_start, eax + + invoke RandomRange3D, 12 + add eax, skill3d_zone_start + add eax, 20 + mov skill3d_great_start, eax + + mov eax, skill3d_hits + shr eax, 1 + add eax, 4 + mov skill3d_speed, eax + mov skill3d_state, 1 + ret + +skill_handle_end_wait: + invoke Pressed3D, 20h + test eax, eax + jz skill_input_done + call InitSkillGame + ret + +skill_input_done: + ret +HandleSkillInput ENDP + +RenderSkillGame PROC uses ebx esi edi + local kx:DWORD + local tx:DWORD + + ; Industrial Steel bezel + invoke DrawBox, 0, 0, 320, 240, 00121416h + invoke DrawBoxBorder, 6, 6, 308, 228, 001A1D20h, 00FFD700h, 2 + + ; Header + invoke DrawBoxBorder, 20, 12, 280, 26, 00121418h, 00FFD700h, 2 + invoke DrawString8x8, 40, 21, OFFSET textSkillTitle, 00FFFF00h + + ; Status + invoke DrawBoxBorder, 20, 44, 110, 18, 00121418h, 002A3540h, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch + invoke FormatNumber, bankroll, OFFSET hudNumBuffer + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch + + invoke DrawBoxBorder, 190, 44, 110, 18, 00121418h, 002A3540h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h + invoke FormatNumber, skill3d_bet, OFFSET hudNumBuffer + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h + + ; Survivor Progress + invoke DrawString8x8, 24, 70, OFFSET textSkillHitsHdr, 003CFF3Ch + invoke FormatNumber, skill3d_hits, OFFSET hudNumBuffer + invoke DrawString8x8, 64, 70, OFFSET hudNumBuffer, 003CFF3Ch + + invoke DrawString8x8, 180, 70, OFFSET textSkillMissHdr, 00FF6464h + invoke FormatNumber, skill3d_misses, OFFSET hudNumBuffer + invoke DrawString8x8, 240, 70, OFFSET hudNumBuffer, 00FF6464h + + ; Dial Frame (Track: X=50..270, Y=102..134) + invoke DrawBoxBorder, 50, 102, 220, 32, 000F1114h, 00404855h, 2 + + ; Calibrated ticks + mov tx, 60 +skill_ticks_loop: + cmp tx, 260 + jge skill_draw_zones + invoke DrawBox, tx, 104, 1, 6, 00303845h + invoke DrawBox, tx, 126, 1, 6, 00303845h + add tx, 12 + jmp skill_ticks_loop + +skill_draw_zones: + ; Normal Success Zone (Green) + invoke DrawBoxBorder, skill3d_zone_start, 106, skill3d_zone_width, 24, 00155020h, 003CFF3Ch, 1 + + ; Great Zone (Gold) + invoke DrawBoxBorder, skill3d_great_start, 106, skill3d_great_width, 24, 00FFD700h, 00FFFF00h, 1 + + ; Pointer / Needle at skill3d_needle + mov eax, skill3d_needle + dec eax + invoke DrawBox, eax, 98, 3, 40, 00FFFFFFh + mov eax, skill3d_needle + sub eax, 2 + invoke DrawBox, eax, 96, 5, 2, 00FF3030h + invoke DrawBox, eax, 138, 5, 2, 00FF3030h + + ; Center prompts / outcome + cmp skill3d_state, 0 + jne @F + invoke DrawString8x8, 52, 150, OFFSET textSkillReadyMsg, 00FFD700h + invoke DrawString8x8, 76, 166, OFFSET textSkillPrompt, 00D0D8E0h + jmp skill_render_keys +@@: + cmp skill3d_state, 1 + jne @F + invoke DrawString8x8, 76, 150, OFFSET textSkillPrompt, 00FFFF00h + jmp skill_render_keys +@@: + cmp skill3d_state, 2 + jne @F + cmp skill3d_last_result, 2 + jne skill_normal_hit_text + invoke DrawString8x8, 36, 150, OFFSET textSkillGreatMsg, 00FFFF00h + jmp skill_render_keys +skill_normal_hit_text: + invoke DrawString8x8, 64, 150, OFFSET textSkillHitMsg, 003CFF3Ch + jmp skill_render_keys +@@: + cmp skill3d_state, 3 + jne @F + invoke DrawString8x8, 88, 150, OFFSET textSkillMissMsg, 00FF6464h + jmp skill_render_keys +@@: + cmp skill3d_state, 4 + jne @F + invoke DrawString8x8, 48, 150, OFFSET textSkillEscape, 003CFF3Ch + invoke FormatNumber, skill3d_win_amount, OFFSET hudNumBuffer + invoke DrawString8x8, 240, 150, OFFSET hudNumBuffer, 003CFF3Ch + invoke DrawString8x8, 64, 166, OFFSET textSkullsAgain, 00FFD700h + jmp skill_render_keys +@@: + invoke DrawString8x8, 44, 150, OFFSET textSkillLost, 00FF6464h + invoke DrawString8x8, 64, 166, OFFSET textSkullsAgain, 00FFD700h + +skill_render_keys: + mov kx, 16 + invoke DrawKeycap3D, kx, 192, OFFSET textSkillKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textSkillKeyBet, 0 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 + ret +RenderSkillGame ENDP + HandlePlayerInput PROC uses ebx esi edi local speed:DWORD local nextX:DWORD @@ -4721,7 +4850,8 @@ check_target_coin: check_target_skill: cmp eax, INTERACT_SKILL_CHECK jne check_target_buckshot - invoke LaunchClassicGame, OFFSET GameSkillCheck, 11, OFFSET szTitleSkillCheck + call InitSkillGame + mov engineMode, MODE_SKILL ret check_target_buckshot: @@ -5119,6 +5249,11 @@ leave_table: je engine_tick cmp skulls3d_state, 2 je engine_tick + cmp engineMode, MODE_SKILL + jne @F + cmp skill3d_state, 1 + je engine_tick +@@: mov engineMode, MODE_WALK engine_tick: cmp paused3D, 0 @@ -5181,10 +5316,16 @@ check_dice_mode: jmp present_frame check_skulls_mode: cmp engineMode, MODE_SKULLS - jne present_frame + jne check_skill_mode call HandleSkullsInput call RenderSkullsGame jmp present_frame +check_skill_mode: + cmp engineMode, MODE_SKILL + jne present_frame + call HandleSkillInput + call RenderSkillGame + jmp present_frame draw_pause: invoke DrawBoxBorder, 65, 75, 190, 85, 00151C21h, 00D8BC6Ah, 2 invoke DrawString8x8, 86, 88, OFFSET textPause3D, 00FFFFFFh diff --git a/docs/previews_minigames/coin_preview.png b/docs/previews_minigames/coin_preview.png index 64d7668e1831608c5e9cab0c927d727a35e61890..c7c1fcdc0d7fa3e31753923ccbd5512b673ea70d 100644 GIT binary patch literal 6611 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 Ibqu)jUsk@me*gdg diff --git a/docs/previews_minigames/dice_preview.png b/docs/previews_minigames/dice_preview.png index a9758b68feb850049f8c7dbc756065b1f955addc..a2c279a47e5abfc3949350a859941e1a89b91218 100644 GIT binary patch literal 5326 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 KN#oALr~VB?V_dTU literal 5522 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 diff --git a/docs/previews_minigames/skill_preview.png b/docs/previews_minigames/skill_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..9be703a112a01b64c3b3864d1199d951f70d88c1 GIT binary patch literal 4920 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 literal 0 HcmV?d00001 diff --git a/docs/previews_minigames/skulls_preview.png b/docs/previews_minigames/skulls_preview.png index 400d5bdcb76465dd02c535379fac83ad436feeb4..9f7f77ce4374f729da784e2e234466f8895f47eb 100644 GIT binary patch literal 5346 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 diff --git a/tools/generators/generate_clean_font.py b/tools/generators/generate_clean_font.py new file mode 100644 index 0000000..9bc7e8d --- /dev/null +++ b/tools/generators/generate_clean_font.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +""" +Generate 100% authentic, pixel-perfect 8x8 IBM VGA bitmap font for CP1251 in font8x8.inc. +Extracts official IBM VGA 8x8 font resources directly from C:\\Windows\\Fonts\\app866.fon, +mapping CP1251 characters to the corresponding CP866 Cyrillic glyphs. +""" +import struct +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] +FONT_INC = REPO_ROOT / 'font8x8.inc' + +# Load authentic 8x8 font from app866.fon (Resource at offset 8784: 8x8, 256 glyphs) +with open('C:/Windows/Fonts/app866.fon', 'rb') as f: + fon_data = f.read() + +font_res = fon_data[8784:8784+3211] +raw_glyphs = {} +for ch in range(256): + entry_off = 0x76 + ch * 4 + w, off = struct.unpack(' Flip! - test eax, eax - jz check_coin_side - mov eax, bankroll - cmp eax, coin3d_bet - jl coin_no_cash - sub eax, coin3d_bet - mov bankroll, eax - mov coin3d_state, 1 - mov coin3d_timer, 0 - mov coin3d_win, 0 - invoke PlaySoundA, OFFSET soundCoin, 0, 1 - jmp coin_input_done - -coin_no_cash: - invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage - mov flashTimer, 60 - invoke PlaySoundA, OFFSET soundClick, 0, 1 - jmp coin_input_done - -check_coin_side: - invoke Pressed3D, 31h ; '1' - test eax, eax - jz @F - mov coin3d_side, 1 - invoke PlaySoundA, OFFSET soundClick, 0, 1 -@@: - invoke Pressed3D, 32h ; '2' - test eax, eax - jz check_coin_bet_adjust - mov coin3d_side, 2 - invoke PlaySoundA, OFFSET soundClick, 0, 1 - -check_coin_bet_adjust: - invoke Pressed3D, 26h ; UP - test eax, eax - jnz coin_inc_bet - invoke Pressed3D, 57h ; W - test eax, eax - jz check_coin_bet_down -coin_inc_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp coin3d_bet, 500 - jge coin_input_done - cmp coin3d_bet, 250 - jge coin_set_500 - cmp coin3d_bet, 100 - jge coin_set_250 - cmp coin3d_bet, 50 - jge coin_set_100 - cmp coin3d_bet, 25 - jge coin_set_50 - jmp coin_set_25 -coin_set_500: - mov coin3d_bet, 500 - jmp coin_input_done -coin_set_250: - mov coin3d_bet, 250 - jmp coin_input_done -coin_set_100: - mov coin3d_bet, 100 - jmp coin_input_done -coin_set_50: - mov coin3d_bet, 50 - jmp coin_input_done -coin_set_25: - mov coin3d_bet, 25 - jmp coin_input_done - -check_coin_bet_down: - invoke Pressed3D, 28h ; DOWN - test eax, eax - jnz coin_dec_bet - invoke Pressed3D, 53h ; S - test eax, eax - jz coin_input_done -coin_dec_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp coin3d_bet, 25 - jle coin_set_10 - cmp coin3d_bet, 50 - jle coin_set_25 - cmp coin3d_bet, 100 - jle coin_set_50 - cmp coin3d_bet, 250 - jle coin_set_100 - mov coin3d_bet, 250 - jmp coin_input_done -coin_set_10: - mov coin3d_bet, 10 - -coin_input_done: + je coin_handle_flipping + cmp coin3d_state, 2 + je coin_handle_result ret -HandleCoinInput ENDP -RenderCoinGame PROC uses ebx esi edi - LOCAL cyVal:DWORD, rxVal:DWORD, curX:DWORD +coin_handle_idle: + invoke Pressed3D, 26h ; UP + test eax, eax + jnz coin_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz coin_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz coin_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz coin_bet_down + invoke Pressed3D, 31h ; '1' + test eax, eax + jnz coin_pick_1 + invoke Pressed3D, 32h ; '2' + test eax, eax + jnz coin_pick_2 + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz coin_start_flip + ret - ; Cabinet Bezel (Mahogany wood & leather) - invoke DrawBox, 0, 0, 320, 240, 00060914h - invoke DrawBoxBorder, 6, 6, 308, 228, 000F1522h, 001B2E48h, 3 - - ; Corner Brass Rivets - invoke DrawBox, 12, 12, 3, 3, 0000D7FFh - invoke DrawPixel, 13, 13, 00FFFFFFh - invoke DrawBox, 306, 12, 3, 3, 0000D7FFh - invoke DrawPixel, 307, 13, 00FFFFFFh - invoke DrawBox, 12, 226, 3, 3, 0000D7FFh - invoke DrawPixel, 13, 227, 00FFFFFFh - invoke DrawBox, 306, 226, 3, 3, 0000D7FFh - invoke DrawPixel, 307, 227, 00FFFFFFh - - ; Illuminated Marquee Header - invoke DrawBoxBorder, 24, 12, 272, 26, 000A101Ch, 0000D7FFh, 2 - invoke DrawString8x8, 48, 21, OFFSET textCoinTitle, 0000FFFFh - - ; Bulb lights on marquee border - mov curX, 28 -coin_bulbs: - cmp curX, 292 - jge coin_meters - invoke DrawPixel, curX, 13, 0000FFFFh - invoke DrawPixel, curX, 36, 0000D7FFh - add curX, 12 - jmp coin_bulbs - -coin_meters: - ; Status Meters: Bank & Bet - invoke DrawBoxBorder, 20, 44, 114, 18, 000A1A0Eh, 001A4B22h, 1 - invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 0050FF50h - invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 0050FF50h - - invoke DrawBoxBorder, 186, 44, 114, 18, 001A100Ah, 003A2814h, 1 - invoke DrawString8x8, 190, 49, OFFSET textBetPrompt, 0000D7FFh - invoke FormatNumber, coin3d_bet, OFFSET hudNumBuffer - invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 0000D7FFh - invoke DrawString8x8, 278, 49, OFFSET textBetHint, 00808080h - - ; Center Velvet Platter - invoke DrawCircle, 160, 110, 46, 000090C0h - invoke DrawCircle, 160, 110, 44, 0000D7FFh - invoke DrawCircle, 160, 110, 41, 00180824h - - ; Selection Podiums: [1] ОРÐ�Л - mov eax, 00121620h - mov edx, 00404855h - mov ecx, 0090A0B0h - cmp coin3d_side, 1 - jne @F - mov eax, 001C3822h - mov edx, 0000FFFFh - mov ecx, 0000FFFFh +coin_bet_up: + mov eax, coin3d_bet + add eax, 50 + cmp eax, bankroll + jle @F + mov eax, bankroll @@: - push ecx - invoke DrawBoxBorder, 20, 72, 76, 52, eax, edx, 2 - pop ecx - invoke DrawString8x8, 28, 78, OFFSET textCoinSide1, ecx - invoke DrawDetailedCoin, 58, 106, 12, 12, 0000A0D0h, 0000D7FFh, 1 - - ; Selection Podiums: [2] РЕШКÐ� - mov eax, 00121620h - mov edx, 00404855h - mov ecx, 0090A0B0h - cmp coin3d_side, 2 - jne @F - mov eax, 001C3822h - mov edx, 0000FFFFh - mov ecx, 0000FFFFh + cmp eax, 5000 + jle @F + mov eax, 5000 @@: - push ecx - invoke DrawBoxBorder, 224, 72, 76, 52, eax, edx, 2 - pop ecx - invoke DrawString8x8, 232, 78, OFFSET textCoinSide2, ecx - invoke DrawDetailedCoin, 262, 106, 12, 12, 000080A0h, 0000B0D0h, 2 + mov coin3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - ; Flipping animation logic - cmp coin3d_state, 1 - jne coin_at_rest +coin_bet_down: + mov eax, coin3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov coin3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - inc coin3d_timer +coin_pick_1: + mov coin3d_choice, 1 + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - ; Parabolic toss: cy = 110 - (t * (40 - t)) / 14 - mov eax, coin3d_timer - mov ecx, 40 - sub ecx, eax - imul eax, ecx - xor edx, edx - mov ecx, 14 - div ecx - mov edx, 110 - sub edx, eax - mov cyVal, edx +coin_pick_2: + mov coin3d_choice, 2 + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret - ; Width rx from lookup table: (t % 10) - mov eax, coin3d_timer - xor edx, edx - mov ecx, 10 - div ecx - movzx eax, BYTE PTR [coinRxAnimTable + edx] - mov rxVal, eax +coin_start_flip: + mov eax, coin3d_bet + cmp eax, bankroll + jle @F + mov eax, bankroll + mov coin3d_bet, eax + test eax, eax + jz coin_done +@@: + mov eax, coin3d_bet + sub bankroll, eax + mov coin3d_state, 1 + mov coin3d_timer, 40 + invoke PlaySoundA, OFFSET soundCoin, 0, 1 + ret - invoke DrawDetailedCoin, 160, cyVal, rxVal, 26, 0000A0D0h, 0000D7FFh, 0 - invoke DrawString8x8, 88, 160, OFFSET textCoinFlipping, 0000FFFFh - - cmp coin3d_timer, 40 - jl coin_draw_controls - - ; Flip complete! - mov coin3d_state, 2 +coin_handle_flipping: + dec coin3d_timer + cmp coin3d_timer, 0 + jg coin_done invoke RandomRange3D, 2 inc eax mov coin3d_result, eax - - mov eax, coin3d_result - cmp eax, coin3d_side + mov edx, coin3d_choice + cmp eax, edx jne coin_flip_lost ; Won! + inc coin3d_streak mov eax, coin3d_bet shl eax, 1 - mov coin3d_win, eax add bankroll, eax - inc coin3d_streak - cmp coin3d_streak, 3 - jl @F - invoke PlaySoundA, OFFSET soundVictory, 0, 1 - jmp coin_draw_controls -@@: + mov coin3d_win, eax + mov coin3d_state, 2 invoke PlaySoundA, OFFSET soundCoinDing, 0, 1 - jmp coin_draw_controls + ret coin_flip_lost: mov coin3d_streak, 0 mov coin3d_win, 0 + mov coin3d_state, 2 invoke PlaySoundA, OFFSET soundLose, 0, 1 - jmp coin_draw_controls + ret -coin_at_rest: - ; Draw coin resting in velvet dish - mov edx, coin3d_side +coin_handle_result: + invoke Pressed3D, 20h + test eax, eax + jz coin_done + mov coin3d_state, 0 + invoke PlaySoundA, OFFSET soundClick, 0, 1 +coin_done: + ret +HandleCoinInput ENDP + +RenderCoinGame PROC uses ebx esi edi + local cyVal:DWORD + local rxVal:DWORD + local kx:DWORD + + ; Background & Cabinet border + invoke DrawBox, 0, 0, 320, 240, 00140906h + invoke DrawBoxBorder, 6, 6, 308, 228, 0022150Fh, 00482E1Bh, 3 + + ; Header + invoke DrawBoxBorder, 20, 12, 280, 26, 001C100Ah, 00FFD700h, 2 + invoke DrawString8x8, 44, 21, OFFSET textCoinTitle, 00FFFF00h + + ; Corner rivets + invoke DrawBox, 12, 12, 3, 3, 00FFD700h + invoke DrawBox, 306, 12, 3, 3, 00FFD700h + invoke DrawBox, 12, 226, 3, 3, 00FFD700h + invoke DrawBox, 306, 226, 3, 3, 00FFD700h + + ; Status meters + invoke DrawBoxBorder, 20, 44, 110, 18, 000E1A0Ah, 00224B1Ah, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch + invoke FormatNumber, bankroll, OFFSET hudNumBuffer + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch + + invoke DrawBoxBorder, 190, 44, 110, 18, 001A100Ah, 003A2814h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h + invoke FormatNumber, coin3d_bet, OFFSET hudNumBuffer + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h + + ; Left: Heads + cmp coin3d_choice, 1 + jne coin_left_inactive + invoke DrawBoxBorder, 20, 72, 76, 68, 00101828h, 00FFFF00h, 2 + invoke DrawString8x8, 30, 78, OFFSET textCoinSide1, 00FFFF00h + invoke DrawDetailedCoin, 58, 106, 14, 14, 00D0A000h, 00FFD700h, 1 + invoke DrawString8x8, 24, 126, OFFSET textCoinSelected, 003CFF3Ch + jmp coin_right_side +coin_left_inactive: + invoke DrawBoxBorder, 20, 72, 76, 68, 000A101Ch, 00404855h, 1 + invoke DrawString8x8, 30, 78, OFFSET textCoinSide1, 00D0D8E0h + invoke DrawDetailedCoin, 58, 106, 14, 14, 009A7A00h, 00D0A000h, 1 + +coin_right_side: + ; Right: Tails + cmp coin3d_choice, 2 + jne coin_right_inactive + invoke DrawBoxBorder, 224, 72, 76, 68, 00101828h, 00FFFF00h, 2 + invoke DrawString8x8, 234, 78, OFFSET textCoinSide2, 00FFFF00h + invoke DrawDetailedCoin, 262, 106, 14, 14, 00D0A000h, 00FFD700h, 2 + invoke DrawString8x8, 228, 126, OFFSET textCoinSelected, 003CFF3Ch + jmp coin_center_area +coin_right_inactive: + invoke DrawBoxBorder, 224, 72, 76, 68, 000A101Ch, 00404855h, 1 + invoke DrawString8x8, 234, 78, OFFSET textCoinSide2, 00D0D8E0h + invoke DrawDetailedCoin, 262, 106, 14, 14, 009A7A00h, 00D0A000h, 2 + +coin_center_area: + ; Center spotlight + invoke DrawCircle, 160, 110, 48, 00121620h + invoke DrawCircle, 160, 110, 44, 00FFD700h + invoke DrawCircle, 160, 110, 42, 000E141Eh + + cmp coin3d_state, 1 + je coin_render_flipping cmp coin3d_state, 2 - jne @F - mov edx, coin3d_result -@@: - invoke DrawDetailedCoin, 160, 110, 26, 26, 0000A0D0h, 0000D7FFh, edx + je coin_render_result - ; Outcome / Streak Display - cmp coin3d_state, 2 - jne coin_show_streak + ; Idle coin + invoke DrawDetailedCoin, 160, 110, 26, 26, 00D0A000h, 00FFD700h, coin3d_choice + jmp coin_render_keys - cmp coin3d_win, 0 - je coin_show_lose - invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 0050FF50h, 1 - invoke DrawString8x8, 64, 160, OFFSET textCoinWin, 0050FF50h +coin_render_flipping: + mov eax, coin3d_timer + and eax, 7 + movzx eax, byte ptr [coinRxAnimTable + eax] + mov rxVal, eax + invoke DrawDetailedCoin, 160, 110, rxVal, 26, 00D0A000h, 00FFD700h, 0 + invoke DrawString8x8, 88, 160, OFFSET textCoinFlipping, 00FFFF00h + jmp coin_render_keys + +coin_render_result: + invoke DrawDetailedCoin, 160, 110, 26, 26, 00D0A000h, 00FFD700h, coin3d_result + mov eax, coin3d_result + cmp eax, coin3d_choice + jne coin_render_loss_msg + + ; Win banner + invoke DrawBoxBorder, 44, 154, 232, 22, 000E141Eh, 003CFF3Ch, 1 + invoke DrawString8x8, 64, 161, OFFSET textCoinWin, 003CFF3Ch invoke FormatNumber, coin3d_win, OFFSET hudNumBuffer - invoke DrawString8x8, 152, 160, OFFSET hudNumBuffer, 0050FF50h - jmp coin_draw_controls + invoke DrawString8x8, 152, 161, OFFSET hudNumBuffer, 003CFF3Ch + jmp coin_render_keys -coin_show_lose: - invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 000000FFh, 1 - invoke DrawString8x8, 114, 160, OFFSET textCoinLose, 008080FFh - jmp coin_draw_controls +coin_render_loss_msg: + invoke DrawBoxBorder, 44, 154, 232, 22, 000E141Eh, 00C81414h, 1 + invoke DrawString8x8, 114, 161, OFFSET textCoinLose, 00FF6464h -coin_show_streak: - invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 0000D7FFh, 1 - invoke DrawString8x8, 52, 160, OFFSET textCoinStreakFmt, 0000FFFFh - -coin_draw_controls: - ; Keycaps Control Bar - invoke DrawBox, 16, 194, 288, 1, 001E2E40h - - mov eax, 0 - cmp coin3d_side, 1 +coin_render_keys: + mov kx, 16 + xor eax, eax + cmp coin3d_choice, 1 sete al - invoke DrawKeycap3D, 22, 202, OFFSET textCoinKey1, eax + invoke DrawKeycap3D, kx, 192, OFFSET textCoinKey1, eax + add kx, eax - mov eax, 0 - cmp coin3d_side, 2 + xor eax, eax + cmp coin3d_choice, 2 sete al - invoke DrawKeycap3D, 88, 202, OFFSET textCoinKey2, eax + invoke DrawKeycap3D, kx, 192, OFFSET textCoinKey2, eax + add kx, eax - invoke DrawKeycap3D, 160, 202, OFFSET textCoinKeySpace, 1 - invoke DrawKeycap3D, 274, 202, OFFSET textKeyEsc, 0 + invoke DrawKeycap3D, kx, 192, OFFSET textCoinKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 ret RenderCoinGame ENDP ; ============================================================================== -; IN-ENGINE 2.5D MINI-GAME: DICE / CRAPS (КОСТИ) +; IN-ENGINE 2.5D MINI-GAME: CRAPS / DICE ; ============================================================================== DrawCrapsDie PROC uses ebx esi edi, x:DWORD, y:DWORD, sizeVal:DWORD, valNum:DWORD - ; Drop shadow on green felt + ; Drop shadow mov eax, x add eax, 3 mov edx, y add edx, sizeVal - invoke DrawBox, eax, edx, sizeVal, 3, 00031408h + invoke DrawBox, eax, edx, sizeVal, 3, 00081403h + mov eax, x add eax, sizeVal mov edx, y add edx, 3 - invoke DrawBox, eax, edx, 3, sizeVal, 00031408h + invoke DrawBox, eax, edx, 3, sizeVal, 00081403h - ; Ivory body & dark border - invoke DrawBoxBorder, x, y, sizeVal, sizeVal, 00F0F4FAh, 00353540h, 1 - - ; Bevel highlight top & left - mov eax, sizeVal - sub eax, 2 - mov edx, x + ; Ivory body & bevel + invoke DrawBoxBorder, x, y, sizeVal, sizeVal, 00FAF4F0h, 00403535h, 1 + mov eax, x + inc eax + mov edx, y inc edx - mov ecx, y - inc ecx - invoke DrawBox, edx, ecx, eax, 1, 00FFFFFFh - invoke DrawBox, edx, ecx, 1, eax, 00FFFFFFh - - ; Bevel shadow bottom & right - mov edx, x - inc edx - mov ecx, y - add ecx, sizeVal + mov ecx, sizeVal sub ecx, 2 - invoke DrawBox, edx, ecx, eax, 1, 00C0C6D0h - mov edx, x - add edx, sizeVal - sub edx, 2 - mov ecx, y - inc ecx - invoke DrawBox, edx, ecx, 1, eax, 00C0C6D0h + invoke DrawBox, eax, edx, ecx, 1, 00FFFFFFh + invoke DrawBox, eax, edx, 1, ecx, 00FFFFFFh - ; Casino Ruby Red circular pips (radius 3) - cmp valNum, 1 - je draw_die_c - cmp valNum, 3 - je draw_die_c - cmp valNum, 5 - je draw_die_c - jmp check_die_pips_corners - -draw_die_c: + ; Ruby pips (00C81515h) + mov eax, valNum + test al, 1 + jz @F + ; Center pip mov eax, x add eax, 18 mov edx, y add edx, 18 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h dec eax dec edx invoke DrawPixel, eax, edx, 00FFFFFFh - -check_die_pips_corners: +@@: cmp valNum, 2 jl die_pips_done mov eax, x add eax, 9 mov edx, y add edx, 9 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h mov eax, x - add eax, sizeVal - sub eax, 10 + add eax, 27 mov edx, y - add edx, sizeVal - sub edx, 10 - invoke DrawCircle, eax, edx, 3, 001515C8h + add edx, 27 + invoke DrawCircle, eax, edx, 3, 00C81515h cmp valNum, 4 jl die_pips_done mov eax, x - add eax, sizeVal - sub eax, 10 + add eax, 27 mov edx, y add edx, 9 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h mov eax, x add eax, 9 mov edx, y - add edx, sizeVal - sub edx, 10 - invoke DrawCircle, eax, edx, 3, 001515C8h + add edx, 27 + invoke DrawCircle, eax, edx, 3, 00C81515h cmp valNum, 6 jl die_pips_done @@ -855,13 +836,12 @@ check_die_pips_corners: add eax, 9 mov edx, y add edx, 18 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h mov eax, x - add eax, sizeVal - sub eax, 10 + add eax, 27 mov edx, y add edx, 18 - invoke DrawCircle, eax, edx, 3, 001515C8h + invoke DrawCircle, eax, edx, 3, 00C81515h die_pips_done: ret @@ -871,328 +851,274 @@ InitDiceGame PROC mov dice3d_state, 0 mov dice3d_timer, 0 mov dice3d_win, 0 - cmp dice3d_bet, 10 - jge @F - mov dice3d_bet, 50 -@@: ret InitDiceGame ENDP HandleDiceInput PROC + cmp dice3d_state, 0 + je dice_handle_idle cmp dice3d_state, 1 - je dice_input_done + je dice_handle_rolling + cmp dice3d_state, 2 + je dice_handle_result + ret - invoke Pressed3D, 20h ; SPACE -> Roll! +dice_handle_idle: + invoke Pressed3D, 26h ; UP test eax, eax - jz check_dice_choice + jnz dice_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz dice_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz dice_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz dice_bet_down + invoke Pressed3D, 31h ; '1' + test eax, eax + jnz dice_pick_1 + invoke Pressed3D, 32h ; '2' + test eax, eax + jnz dice_pick_2 + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz dice_start_roll + ret + +dice_bet_up: + mov eax, dice3d_bet + add eax, 50 + cmp eax, bankroll + jle @F mov eax, bankroll - cmp eax, dice3d_bet - jl dice_no_cash - sub eax, dice3d_bet - mov bankroll, eax - mov dice3d_state, 1 - mov dice3d_timer, 0 - mov dice3d_win, 0 - invoke PlaySoundA, OFFSET soundCards, 0, 1 - jmp dice_input_done - -dice_no_cash: - invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage - mov flashTimer, 60 +@@: + cmp eax, 5000 + jle @F + mov eax, 5000 +@@: + mov dice3d_bet, eax invoke PlaySoundA, OFFSET soundClick, 0, 1 - jmp dice_input_done + ret -check_dice_choice: - invoke Pressed3D, 31h ; '1' - test eax, eax - jz @F +dice_bet_down: + mov eax, dice3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov dice3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +dice_pick_1: mov dice3d_choice, 1 invoke PlaySoundA, OFFSET soundClick, 0, 1 -@@: - invoke Pressed3D, 32h ; '2' - test eax, eax - jz check_dice_bet_adjust + ret + +dice_pick_2: mov dice3d_choice, 2 invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret -check_dice_bet_adjust: - invoke Pressed3D, 26h ; UP +dice_start_roll: + mov eax, dice3d_bet + cmp eax, bankroll + jle @F + mov eax, bankroll + mov dice3d_bet, eax test eax, eax - jnz dice_inc_bet - invoke Pressed3D, 57h ; W + jz dice_done +@@: + mov eax, dice3d_bet + sub bankroll, eax + mov dice3d_state, 1 + mov dice3d_timer, 35 + invoke PlaySoundA, OFFSET soundCards, 0, 1 + ret + +dice_handle_rolling: + dec dice3d_timer + cmp dice3d_timer, 0 + jg dice_randomize_tumble + + ; Roll finished! + invoke RandomRange3D, 6 + inc eax + mov dice3d_val1, eax + invoke RandomRange3D, 6 + inc eax + mov dice3d_val2, eax + + mov edx, dice3d_val1 + add edx, eax + mov dice3d_sum, edx + + ; Parity check + mov eax, edx + and eax, 1 + jnz dice_sum_is_odd + ; Even + mov eax, 1 + jmp dice_check_win +dice_sum_is_odd: + mov eax, 2 + +dice_check_win: + cmp eax, dice3d_choice + jne dice_roll_lost + + ; Won! + mov eax, dice3d_bet + shl eax, 1 + add bankroll, eax + mov dice3d_win, eax + mov dice3d_state, 2 + invoke PlaySoundA, OFFSET soundVictory, 0, 1 + ret + +dice_roll_lost: + mov dice3d_win, 0 + mov dice3d_state, 2 + invoke PlaySoundA, OFFSET soundLose, 0, 1 + ret + +dice_randomize_tumble: + invoke RandomRange3D, 6 + inc eax + mov dice3d_val1, eax + invoke RandomRange3D, 6 + inc eax + mov dice3d_val2, eax + ret + +dice_handle_result: + invoke Pressed3D, 20h test eax, eax - jz check_dice_bet_down -dice_inc_bet: + jz dice_done + mov dice3d_state, 0 invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp dice3d_bet, 500 - jge dice_input_done - cmp dice3d_bet, 250 - jge dice_set_500 - cmp dice3d_bet, 100 - jge dice_set_250 - cmp dice3d_bet, 50 - jge dice_set_100 - cmp dice3d_bet, 25 - jge dice_set_50 - jmp dice_set_25 -dice_set_500: - mov dice3d_bet, 500 - jmp dice_input_done -dice_set_250: - mov dice3d_bet, 250 - jmp dice_input_done -dice_set_100: - mov dice3d_bet, 100 - jmp dice_input_done -dice_set_50: - mov dice3d_bet, 50 - jmp dice_input_done -dice_set_25: - mov dice3d_bet, 25 - jmp dice_input_done - -check_dice_bet_down: - invoke Pressed3D, 28h ; DOWN - test eax, eax - jnz dice_dec_bet - invoke Pressed3D, 53h ; S - test eax, eax - jz dice_input_done -dice_dec_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp dice3d_bet, 25 - jle dice_set_10 - cmp dice3d_bet, 50 - jle dice_set_25 - cmp dice3d_bet, 100 - jle dice_set_50 - cmp dice3d_bet, 250 - jle dice_set_100 - mov dice3d_bet, 250 - jmp dice_input_done -dice_set_10: - mov dice3d_bet, 10 - -dice_input_done: +dice_done: ret HandleDiceInput ENDP RenderDiceGame PROC uses ebx esi edi - LOCAL d1X:DWORD, d1Y:DWORD, d2X:DWORD, d2Y:DWORD, bxX:DWORD + local kx:DWORD - ; Craps Emerald Felt & Oak Armrest - invoke DrawBox, 0, 0, 320, 240, 00082E12h - invoke DrawBoxBorder, 4, 4, 312, 232, 00093816h, 00122244h, 3 - invoke DrawBoxBorder, 8, 8, 304, 224, 000A3F19h, 0005140Ah, 2 + ; Mahogany frame & Deep Felt Green table + invoke DrawBox, 0, 0, 320, 240, 00140906h + invoke DrawBoxBorder, 6, 6, 308, 228, 000A3816h, 00FFD700h, 2 - ; Pyramidal diamond craps backboard texture - mov bxX, 12 -craps_bumper: - cmp bxX, 308 - jge craps_felt_markings - mov eax, bxX - add eax, 4 - invoke DrawBox, eax, 11, 4, 4, 00041006h - mov eax, bxX - add eax, 5 - invoke DrawPixel, eax, 12, 000F4820h - add bxX, 12 - jmp craps_bumper + ; Header + invoke DrawBoxBorder, 20, 12, 280, 26, 00072E13h, 00FFD700h, 2 + invoke DrawString8x8, 48, 21, OFFSET textDiceTitle, 00FFFF00h -craps_felt_markings: - ; Table Markings printed in gold directly on felt - invoke DrawString8x8, 72, 20, OFFSET textDiceTitle, 0000D7FFh - invoke DrawString8x8, 68, 32, OFFSET textDiceSubtitle, 0000B0A0h - - ; Meters: Bank & Bet - invoke DrawBoxBorder, 16, 46, 108, 16, 0006240Eh, 000E5022h, 1 - invoke DrawString8x8, 20, 50, OFFSET textBankPrompt, 0050FF50h + ; Status + invoke DrawBoxBorder, 20, 44, 110, 18, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 68, 50, OFFSET hudNumBuffer, 0050FF50h + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch - invoke DrawBoxBorder, 196, 46, 108, 16, 0006240Eh, 000E5022h, 1 - invoke DrawString8x8, 200, 50, OFFSET textBetPrompt, 0000D7FFh + invoke DrawBoxBorder, 190, 44, 110, 18, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h invoke FormatNumber, dice3d_bet, OFFSET hudNumBuffer - invoke DrawString8x8, 264, 50, OFFSET hudNumBuffer, 0000D7FFh + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h - ; Betting Zone Left: [1] ЧÐ�Т - mov eax, 00073014h - mov edx, 001A602Ah - mov ecx, 0080B090h + ; [1] ЧÐ�Т cmp dice3d_choice, 1 - jne @F - mov eax, 000B441Dh - mov edx, 0000FFFFh - mov ecx, 0000FFFFh -@@: - push ecx - invoke DrawBoxBorder, 16, 68, 88, 54, eax, edx, 2 - pop ecx - invoke DrawString8x8, 24, 74, OFFSET textDiceEven, ecx - invoke DrawString8x8, 20, 86, OFFSET textDiceEvenNums, 0000D7FFh - cmp dice3d_choice, 1 - jne @F - invoke DrawChipStack, 48, 110, 4 -@@: + jne dice_even_inactive + invoke DrawBoxBorder, 16, 70, 88, 48, 00072E13h, 00FFFF00h, 2 + invoke DrawString8x8, 30, 76, OFFSET textDiceEven, 00FFFF00h + invoke DrawString8x8, 22, 90, OFFSET textDiceEvenNums, 00FFD700h + invoke DrawString8x8, 26, 104, OFFSET textCoinSelected, 003CFF3Ch + jmp dice_odd_side +dice_even_inactive: + invoke DrawBoxBorder, 16, 70, 88, 48, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 30, 76, OFFSET textDiceEven, 00D0D8E0h + invoke DrawString8x8, 22, 90, OFFSET textDiceEvenNums, 0080B090h - ; Betting Zone Right: [2] Ð�ЕЧЕТ - mov eax, 00073014h - mov edx, 001A602Ah - mov ecx, 0080B090h +dice_odd_side: + ; [2] Ð�ЕЧЕТ cmp dice3d_choice, 2 - jne @F - mov eax, 000B441Dh - mov edx, 0000FFFFh - mov ecx, 0000FFFFh -@@: - push ecx - invoke DrawBoxBorder, 216, 68, 88, 54, eax, edx, 2 - pop ecx - invoke DrawString8x8, 224, 74, OFFSET textDiceOdd, ecx - invoke DrawString8x8, 224, 86, OFFSET textDiceOddNums, 00508060h - cmp dice3d_choice, 2 - jne @F - invoke DrawChipStack, 248, 110, 4 -@@: + jne dice_odd_inactive + invoke DrawBoxBorder, 216, 70, 88, 48, 00072E13h, 00FFFF00h, 2 + invoke DrawString8x8, 226, 76, OFFSET textDiceOdd, 00FFFF00h + invoke DrawString8x8, 224, 90, OFFSET textDiceOddNums, 00FFD700h + invoke DrawString8x8, 226, 104, OFFSET textCoinSelected, 003CFF3Ch + jmp dice_center_cubes +dice_odd_inactive: + invoke DrawBoxBorder, 216, 70, 88, 48, 00072E13h, 001B4B22h, 1 + invoke DrawString8x8, 226, 76, OFFSET textDiceOdd, 00D0D8E0h + invoke DrawString8x8, 224, 90, OFFSET textDiceOddNums, 0080B090h - ; Center Dice Field - invoke DrawBoxBorder, 112, 68, 96, 54, 00072E13h, 00145826h, 1 +dice_center_cubes: + ; 2 Dice in center + invoke DrawCrapsDie, 116, 76, 36, dice3d_val1 + invoke DrawCrapsDie, 168, 76, 36, dice3d_val2 - ; Rolling Animation Logic cmp dice3d_state, 1 - jne dice_at_rest - - inc dice3d_timer - - ; Tumbling jitter offsets - mov eax, dice3d_timer - and eax, 3 - sub eax, 1 - - mov edx, 120 - add edx, eax - mov d1X, edx - mov edx, 76 - sub edx, eax - mov d1Y, edx - - mov edx, 164 - sub edx, eax - mov d2X, edx - mov edx, 78 - add edx, eax - mov d2Y, edx - - test dice3d_timer, 1 - jz @F - invoke RandomRange3D, 6 - inc eax - mov dice3d_val1, eax - invoke RandomRange3D, 6 - inc eax - mov dice3d_val2, eax -@@: - invoke DrawCrapsDie, d1X, d1Y, 36, dice3d_val1 - invoke DrawCrapsDie, d2X, d2Y, 36, dice3d_val2 - invoke DrawString8x8, 76, 138, OFFSET textDiceRolling, 0000FFFFh - - cmp dice3d_timer, 36 - jl dice_draw_controls - - ; Settle dice! - mov dice3d_state, 2 - invoke RandomRange3D, 6 - inc eax - mov dice3d_val1, eax - invoke RandomRange3D, 6 - inc eax - mov dice3d_val2, eax - - mov eax, dice3d_val1 - add eax, dice3d_val2 - mov dice3d_sum, eax - - ; Check choice vs sum parity - mov eax, dice3d_sum - test eax, 1 - jz dice_sum_is_even - - ; Odd - cmp dice3d_choice, 2 - je dice_roll_won - jmp dice_roll_lost - -dice_sum_is_even: - cmp dice3d_choice, 1 - je dice_roll_won - -dice_roll_lost: - mov dice3d_win, 0 - invoke PlaySoundA, OFFSET soundLose, 0, 1 - jmp dice_draw_controls - -dice_roll_won: - mov eax, dice3d_bet - shl eax, 1 - mov dice3d_win, eax - add bankroll, eax - invoke PlaySoundA, OFFSET soundVictory, 0, 1 - jmp dice_draw_controls - -dice_at_rest: - invoke DrawCrapsDie, 120, 76, 36, dice3d_val1 - invoke DrawCrapsDie, 164, 76, 36, dice3d_val2 - + je dice_render_rolling cmp dice3d_state, 2 - jne dice_draw_controls + je dice_render_result + jmp dice_render_keys - ; Scoreboard Plaque - invoke DrawBoxBorder, 36, 130, 248, 30, 00051D0Ch, 0000D7FFh, 1 - invoke DrawString8x8, 44, 135, OFFSET textDiceSumHdr, 0000D7FFh +dice_render_rolling: + invoke DrawString8x8, 76, 138, OFFSET textDiceRolling, 00FFFF00h + jmp dice_render_keys + +dice_render_result: + invoke DrawBoxBorder, 36, 130, 248, 36, 00072E13h, 00FFD700h, 1 + invoke DrawString8x8, 44, 135, OFFSET textDiceSumHdr, 00FFD700h invoke FormatNumber, dice3d_val1, OFFSET hudNumBuffer - invoke DrawString8x8, 100, 135, OFFSET hudNumBuffer, 00FFFFFFh - invoke DrawString8x8, 110, 135, OFFSET textDicePlus, 0000D7FFh + invoke DrawString8x8, 92, 135, OFFSET hudNumBuffer, 00FFFF00h + invoke DrawString8x8, 110, 135, OFFSET textDicePlus, 00FFD700h invoke FormatNumber, dice3d_val2, OFFSET hudNumBuffer - invoke DrawString8x8, 134, 135, OFFSET hudNumBuffer, 00FFFFFFh - invoke DrawString8x8, 144, 135, OFFSET textDiceEqual, 0000D7FFh + invoke DrawString8x8, 126, 135, OFFSET hudNumBuffer, 00FFFF00h + invoke DrawString8x8, 144, 135, OFFSET textDiceEqual, 00FFD700h invoke FormatNumber, dice3d_sum, OFFSET hudNumBuffer - invoke DrawString8x8, 168, 135, OFFSET hudNumBuffer, 0000FFFFh + invoke DrawString8x8, 168, 135, OFFSET hudNumBuffer, 00FFFF00h mov eax, dice3d_sum - test eax, 1 - jnz @F - invoke DrawString8x8, 186, 135, OFFSET textDiceEvenResult, 0080FF80h - jmp dice_show_win_msg -@@: - invoke DrawString8x8, 186, 135, OFFSET textDiceOddResult, 00FF8080h + and eax, 1 + jnz dice_render_odd_res + invoke DrawString8x8, 186, 135, OFFSET textDiceEvenResult, 003CFF3Ch + jmp dice_render_outcome +dice_render_odd_res: + invoke DrawString8x8, 186, 135, OFFSET textDiceOddResult, 003CFF3Ch -dice_show_win_msg: - cmp dice3d_win, 0 - je dice_show_loss - invoke DrawString8x8, 68, 147, OFFSET textDiceWin, 0050FF50h +dice_render_outcome: + mov eax, dice3d_win + test eax, eax + jz dice_render_loss_outcome + invoke DrawString8x8, 68, 150, OFFSET textDiceWin, 003CFF3Ch invoke FormatNumber, dice3d_win, OFFSET hudNumBuffer - invoke DrawString8x8, 156, 147, OFFSET hudNumBuffer, 0050FF50h - invoke DrawString8x8, 188, 147, OFFSET textDiceWinMult, 0050FF50h - jmp dice_draw_controls + invoke DrawString8x8, 156, 150, OFFSET hudNumBuffer, 003CFF3Ch + invoke DrawString8x8, 188, 150, OFFSET textDiceWinMult, 003CFF3Ch + jmp dice_render_keys -dice_show_loss: - invoke DrawString8x8, 116, 147, OFFSET textDiceLose, 008080FFh +dice_render_loss_outcome: + invoke DrawString8x8, 116, 150, OFFSET textDiceLose, 00FF6464h -dice_draw_controls: - invoke DrawBox, 16, 188, 288, 1, 00104820h - - mov eax, 0 +dice_render_keys: + mov kx, 16 + xor eax, eax cmp dice3d_choice, 1 sete al - invoke DrawKeycap3D, 20, 198, OFFSET textDiceKey1, eax + invoke DrawKeycap3D, kx, 192, OFFSET textDiceKey1, eax + add kx, eax - mov eax, 0 + xor eax, eax cmp dice3d_choice, 2 sete al - invoke DrawKeycap3D, 82, 198, OFFSET textDiceKey2, eax + invoke DrawKeycap3D, kx, 192, OFFSET textDiceKey2, eax + add kx, eax - invoke DrawKeycap3D, 160, 198, OFFSET textDiceKeySpace, 1 - invoke DrawKeycap3D, 274, 198, OFFSET textKeyEsc, 0 + invoke DrawKeycap3D, kx, 192, OFFSET textDiceKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 ret RenderDiceGame ENDP @@ -1200,138 +1126,133 @@ RenderDiceGame ENDP ; IN-ENGINE 2.5D MINI-GAME: SKULLS & CUPS (Ð�Ð�ПÐ�РСТКИ) ; ============================================================================== DrawGlowingOrb PROC uses ebx esi edi, cxVal:DWORD, cyVal:DWORD - invoke DrawCircle, cxVal, cyVal, 14, 00081E2Eh - invoke DrawCircle, cxVal, cyVal, 11, 00103A58h - invoke DrawCircle, cxVal, cyVal, 8, 001A588Ah - invoke DrawCircle, cxVal, cyVal, 6, 0000B0E0h - invoke DrawCircle, cxVal, cyVal, 4, 0000E0FFh + invoke DrawCircle, cxVal, cyVal, 14, 002E1E08h + invoke DrawCircle, cxVal, cyVal, 11, 00583A10h + invoke DrawCircle, cxVal, cyVal, 8, 008A581Ah + invoke DrawCircle, cxVal, cyVal, 6, 00D0B000h + invoke DrawCircle, cxVal, cyVal, 4, 00FFE000h mov eax, cxVal dec eax mov edx, cyVal dec edx - invoke DrawCircle, eax, edx, 2, 00A0FFFFh - mov eax, cxVal - sub eax, 2 - mov edx, cyVal - sub edx, 2 + invoke DrawCircle, eax, edx, 2, 00FFFF80h + dec eax + dec edx invoke DrawPixel, eax, edx, 00FFFFFFh ret DrawGlowingOrb ENDP DrawGothicCup PROC uses ebx esi edi, x:DWORD, y:DWORD, cupId:DWORD, isLifted:DWORD, hasBall:DWORD - LOCAL liftY:DWORD + local liftY:DWORD mov eax, y cmp isLifted, 0 je @F - sub eax, 28 + sub eax, 36 @@: mov liftY, eax - ; Drop shadow on purple velvet + ; Drop shadow cmp isLifted, 0 - jne @F + jne cup_shadow_lifted mov eax, x add eax, 6 mov edx, y add edx, 42 - invoke DrawBox, eax, edx, 36, 4, 000A0410h - jmp draw_cup_body -@@: + invoke DrawBox, eax, edx, 36, 4, 0010040Ah + jmp cup_ball_check +cup_shadow_lifted: mov eax, x add eax, 10 mov edx, y add edx, 42 - invoke DrawBox, eax, edx, 28, 2, 0012061Ah + invoke DrawBox, eax, edx, 28, 2, 001A0612h - ; Draw orb if lifted and has ball +cup_ball_check: + cmp isLifted, 0 + je cup_body_draw cmp hasBall, 0 - je draw_cup_body + je cup_body_draw mov eax, x add eax, 24 mov edx, y add edx, 26 invoke DrawGlowingOrb, eax, edx -draw_cup_body: - ; Base +cup_body_draw: + ; Base pedestal mov eax, x add eax, 6 mov edx, liftY add edx, 36 - invoke DrawBoxBorder, eax, edx, 36, 6, 00221A30h, 0000B0D0h, 1 + invoke DrawBoxBorder, eax, edx, 36, 6, 00301A22h, 00D0B000h, 1 ; Stem mov eax, x add eax, 18 mov edx, liftY add edx, 28 - invoke DrawBox, eax, edx, 12, 8, 00332545h + invoke DrawBox, eax, edx, 12, 8, 00452533h mov eax, x add eax, 22 - mov edx, liftY - add edx, 28 - invoke DrawBox, eax, edx, 4, 8, 0055406Eh + invoke DrawBox, eax, edx, 4, 8, 006E4055h - ; Bowl + ; Goblet Bowl mov eax, x add eax, 8 mov edx, liftY add edx, 8 - invoke DrawBoxBorder, eax, edx, 32, 20, 002D1E40h, 0000D7FFh, 1 + invoke DrawBoxBorder, eax, edx, 32, 20, 00401E2Dh, 00FFD700h, 1 + mov eax, x add eax, 14 mov edx, liftY add edx, 10 - invoke DrawBox, eax, edx, 6, 16, 00503570h + invoke DrawBox, eax, edx, 6, 16, 00703550h mov eax, x add eax, 17 - mov edx, liftY - add edx, 10 - invoke DrawBox, eax, edx, 3, 16, 007850A0h + invoke DrawBox, eax, edx, 3, 16, 00A05078h - ; Flared Rim + ; Golden Rim mov eax, x add eax, 4 mov edx, liftY add edx, 2 - invoke DrawBoxBorder, eax, edx, 40, 7, 00150A20h, 0000FFFFh, 1 + invoke DrawBoxBorder, eax, edx, 40, 7, 00200A15h, 00FFFF00h, 1 mov eax, x add eax, 12 mov edx, liftY add edx, 4 - invoke DrawBox, eax, edx, 16, 2, 0000FFFFh + invoke DrawBox, eax, edx, 16, 2, 00FFFF00h - ; Skull Insignia on Bowl + ; Skull face emblem mov eax, x add eax, 21 mov edx, liftY add edx, 12 - invoke DrawBox, eax, edx, 6, 5, 0000D7FFh + invoke DrawBox, eax, edx, 6, 5, 00FFD700h mov eax, x add eax, 22 mov edx, liftY add edx, 17 - invoke DrawBox, eax, edx, 4, 3, 0000D7FFh + invoke DrawBox, eax, edx, 4, 3, 00FFD700h mov eax, x add eax, 22 mov edx, liftY add edx, 14 - invoke DrawPixel, eax, edx, 00150A20h + invoke DrawPixel, eax, edx, 00200A15h mov eax, x add eax, 24 - mov edx, liftY - add edx, 14 - invoke DrawPixel, eax, edx, 00150A20h + invoke DrawPixel, eax, edx, 00200A15h - ; Cup ID Badge + ; Cup number label mov eax, x add eax, 21 mov edx, liftY add edx, 24 mov ecx, cupId - add ecx, '0' - invoke DrawChar8x8, eax, edx, ecx, 0000FFFFh + add ecx, '1' + invoke DrawChar8x8, eax, edx, ecx, 00FFFF00h ret DrawGothicCup ENDP @@ -1339,452 +1260,757 @@ InitSkullsGame PROC mov skulls3d_state, 0 mov skulls3d_timer, 0 mov skulls3d_win, 0 - cmp skulls3d_bet, 10 - jge @F - mov skulls3d_bet, 50 -@@: invoke RandomRange3D, 3 mov skulls3d_ballPos, eax + mov skulls3d_choice, 1 ret InitSkullsGame ENDP FinalizeSkullsGuess PROC uses ebx - mov skulls3d_state, 4 mov eax, skulls3d_choice cmp eax, skulls3d_ballPos - jne skulls_guess_lost + jne skulls_guess_wrong - ; Won 3x! + ; Won! 3x payout mov eax, skulls3d_bet imul eax, 3 - mov skulls3d_win, eax add bankroll, eax - invoke PlaySoundA, OFFSET soundVictory, 0, 1 + mov skulls3d_win, eax + mov skulls3d_state, 4 + invoke PlaySoundA, OFFSET soundJackpot, 0, 1 ret -skulls_guess_lost: +skulls_guess_wrong: mov skulls3d_win, 0 + mov skulls3d_state, 4 invoke PlaySoundA, OFFSET soundLose, 0, 1 ret FinalizeSkullsGuess ENDP HandleSkullsInput PROC + cmp skulls3d_state, 0 + je skulls_handle_idle cmp skulls3d_state, 1 - je skulls_input_done + je skulls_handle_show cmp skulls3d_state, 2 - je skulls_input_done - + je skulls_handle_shuffle cmp skulls3d_state, 3 - je check_skulls_pick + je skulls_handle_pick + cmp skulls3d_state, 4 + je skulls_handle_reveal + ret - ; State 0 or 4: Can start new round or adjust bet - invoke Pressed3D, 20h ; SPACE +skulls_handle_idle: + invoke Pressed3D, 26h ; UP test eax, eax - jz check_skulls_bet_adjust + jnz skulls_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz skulls_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz skulls_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz skulls_bet_down + invoke Pressed3D, 20h ; SPACE + test eax, eax + jnz skulls_start_game + ret +skulls_bet_up: + mov eax, skulls3d_bet + add eax, 50 + cmp eax, bankroll + jle @F mov eax, bankroll - cmp eax, skulls3d_bet - jl skulls_no_cash - sub eax, skulls3d_bet - mov bankroll, eax +@@: + cmp eax, 5000 + jle @F + mov eax, 5000 +@@: + mov skulls3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret +skulls_bet_down: + mov eax, skulls3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov skulls3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skulls_start_game: + mov eax, skulls3d_bet + cmp eax, bankroll + jle @F + mov eax, bankroll + mov skulls3d_bet, eax + test eax, eax + jz skulls_done +@@: + mov eax, skulls3d_bet + sub bankroll, eax invoke RandomRange3D, 3 mov skulls3d_ballPos, eax - - invoke RandomRange3D, 3 - mov skulls3d_swapPair0, eax - invoke RandomRange3D, 3 - mov skulls3d_swapPair1, eax - invoke RandomRange3D, 3 - mov skulls3d_swapPair2, eax - mov skulls3d_state, 1 - mov skulls3d_timer, 0 - mov skulls3d_win, 0 + mov skulls3d_timer, 45 invoke PlaySoundA, OFFSET soundShuffle, 0, 1 - jmp skulls_input_done + ret -skulls_no_cash: - invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage - mov flashTimer, 60 - invoke PlaySoundA, OFFSET soundClick, 0, 1 - jmp skulls_input_done +skulls_handle_show: + dec skulls3d_timer + cmp skulls3d_timer, 0 + jg skulls_done + mov skulls3d_state, 2 + mov skulls3d_timer, 60 + invoke PlaySoundA, OFFSET soundShuffle, 0, 1 + ret -check_skulls_pick: - invoke Pressed3D, 31h ; '1' +skulls_handle_shuffle: + dec skulls3d_timer + cmp skulls3d_timer, 0 + jg skulls_done + invoke RandomRange3D, 3 + mov skulls3d_ballPos, eax + mov skulls3d_state, 3 + ret + +skulls_handle_pick: + invoke Pressed3D, 31h ; '1' test eax, eax - jz @F + jnz skulls_pick_1 + invoke Pressed3D, 32h ; '2' + test eax, eax + jnz skulls_pick_2 + invoke Pressed3D, 33h ; '3' + test eax, eax + jnz skulls_pick_3 + ret + +skulls_pick_1: mov skulls3d_choice, 0 call FinalizeSkullsGuess - jmp skulls_input_done -@@: - invoke Pressed3D, 32h ; '2' - test eax, eax - jz @F + ret + +skulls_pick_2: mov skulls3d_choice, 1 call FinalizeSkullsGuess - jmp skulls_input_done -@@: - invoke Pressed3D, 33h ; '3' - test eax, eax - jz skulls_input_done + ret + +skulls_pick_3: mov skulls3d_choice, 2 call FinalizeSkullsGuess - jmp skulls_input_done + ret -check_skulls_bet_adjust: - invoke Pressed3D, 26h ; UP +skulls_handle_reveal: + invoke Pressed3D, 20h test eax, eax - jnz skulls_inc_bet - invoke Pressed3D, 57h ; W - test eax, eax - jz check_skulls_bet_down -skulls_inc_bet: + jz skulls_done + mov skulls3d_state, 0 invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp skulls3d_bet, 500 - jge skulls_input_done - cmp skulls3d_bet, 250 - jge skulls_set_500 - cmp skulls3d_bet, 100 - jge skulls_set_250 - cmp skulls3d_bet, 50 - jge skulls_set_100 - cmp skulls3d_bet, 25 - jge skulls_set_50 - jmp skulls_set_25 -skulls_set_500: - mov skulls3d_bet, 500 - jmp skulls_input_done -skulls_set_250: - mov skulls3d_bet, 250 - jmp skulls_input_done -skulls_set_100: - mov skulls3d_bet, 100 - jmp skulls_input_done -skulls_set_50: - mov skulls3d_bet, 50 - jmp skulls_input_done -skulls_set_25: - mov skulls3d_bet, 25 - jmp skulls_input_done - -check_skulls_bet_down: - invoke Pressed3D, 28h ; DOWN - test eax, eax - jnz skulls_dec_bet - invoke Pressed3D, 53h ; S - test eax, eax - jz skulls_input_done -skulls_dec_bet: - invoke PlaySoundA, OFFSET soundClick, 0, 1 - cmp skulls3d_bet, 25 - jle skulls_set_10 - cmp skulls3d_bet, 50 - jle skulls_set_25 - cmp skulls3d_bet, 100 - jle skulls_set_50 - cmp skulls3d_bet, 250 - jle skulls_set_100 - mov skulls3d_bet, 250 - jmp skulls_input_done -skulls_set_10: - mov skulls3d_bet, 10 - -skulls_input_done: +skulls_done: ret HandleSkullsInput ENDP RenderSkullsGame PROC uses ebx esi edi - LOCAL passTick:DWORD, curPair:DWORD, swapSlotA:DWORD, swapSlotB:DWORD - LOCAL xA:DWORD, xB:DWORD, curXA:DWORD, curXB:DWORD, curYA:DWORD, curYB:DWORD - LOCAL distX:DWORD, dxVal:DWORD, archY:DWORD + local kx:DWORD - ; Dark Gothic Tavern Table with Royal Velvet - invoke DrawBox, 0, 0, 320, 240, 000D0612h - invoke DrawBoxBorder, 4, 4, 312, 232, 00160B20h, 00321845h, 3 - invoke DrawBoxBorder, 8, 8, 304, 224, 00220F30h, 0000D7FFh, 1 + ; Mahogany & Gothic Purple table + invoke DrawBox, 0, 0, 320, 240, 00140906h + invoke DrawBoxBorder, 6, 6, 308, 228, 00300F22h, 00FFD700h, 2 ; Header - invoke DrawBoxBorder, 24, 12, 272, 24, 0012081Ah, 0000D7FFh, 2 - invoke DrawString8x8, 64, 20, OFFSET textSkullsTitle, 0000FFFFh + invoke DrawBoxBorder, 20, 12, 280, 26, 001A0812h, 00FFD700h, 2 + invoke DrawString8x8, 40, 21, OFFSET textSkullsTitle, 00FFFF00h - ; Meters: Bank & Bet - invoke DrawBoxBorder, 20, 42, 114, 16, 000D0616h, 00401858h, 1 - invoke DrawString8x8, 24, 46, OFFSET textBankPrompt, 0050FF50h + ; Status + invoke DrawBoxBorder, 20, 44, 110, 18, 001A0812h, 00452033h, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch invoke FormatNumber, bankroll, OFFSET hudNumBuffer - invoke DrawString8x8, 72, 46, OFFSET hudNumBuffer, 0050FF50h + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch - invoke DrawBoxBorder, 186, 42, 114, 16, 000D0616h, 00401858h, 1 - invoke DrawString8x8, 190, 46, OFFSET textBetPrompt, 0000D7FFh + invoke DrawBoxBorder, 190, 44, 110, 18, 001A0812h, 00452033h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h invoke FormatNumber, skulls3d_bet, OFFSET hudNumBuffer - invoke DrawString8x8, 254, 46, OFFSET hudNumBuffer, 0000D7FFh + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h - ; Velvet Table Runner - invoke DrawBoxBorder, 16, 64, 288, 120, 001A0B25h, 00452060h, 1 - - ; Dispatch based on phase + ; Subtitle phase prompts + cmp skulls3d_state, 0 + jne @F + invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase0, 00FFD700h + jmp skulls_render_cups +@@: cmp skulls3d_state, 1 - je skulls_render_phase1 + jne @F + invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase1, 00FFFF00h + jmp skulls_render_cups +@@: cmp skulls3d_state, 2 - je skulls_render_phase2 + jne @F + invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase2, 00FFFF00h + jmp skulls_render_cups +@@: cmp skulls3d_state, 3 - je skulls_render_phase3 - cmp skulls3d_state, 4 - je skulls_render_phase4 - - ; Phase 0: Idle / Betting - invoke DrawString8x8, 56, 70, OFFSET textSkullsPhase0, 0000D7FFh - invoke DrawGothicCup, 48, 108, 1, 0, 0 - invoke DrawGothicCup, 136, 108, 2, 0, 0 - invoke DrawGothicCup, 224, 108, 3, 0, 0 - jmp skulls_draw_controls - -skulls_render_phase1: - inc skulls3d_timer - invoke DrawString8x8, 56, 70, OFFSET textSkullsPhase1, 0000FFFFh - - ; Draw cups with ballPos cup lifted - mov eax, 0 - cmp skulls3d_ballPos, 0 - sete al - invoke DrawGothicCup, 48, 108, 1, eax, eax - - mov eax, 0 - cmp skulls3d_ballPos, 1 - sete al - invoke DrawGothicCup, 136, 108, 2, eax, eax - - mov eax, 0 - cmp skulls3d_ballPos, 2 - sete al - invoke DrawGothicCup, 224, 108, 3, eax, eax - - cmp skulls3d_timer, 40 - jl skulls_draw_controls - - ; Start Phase 2 (Shuffle) - mov skulls3d_state, 2 - mov skulls3d_timer, 0 - invoke PlaySoundA, OFFSET soundShuffle, 0, 1 - jmp skulls_draw_controls - -skulls_render_phase2: - inc skulls3d_timer - - mov eax, skulls3d_timer - cmp eax, 20 - jbe pass_0 - cmp eax, 40 - jbe pass_1 - sub eax, 41 - mov passTick, eax - mov eax, skulls3d_swapPair2 - mov curPair, eax - jmp setup_pass_pair - -pass_0: - dec eax - mov passTick, eax - mov eax, skulls3d_swapPair0 - mov curPair, eax - jmp setup_pass_pair - -pass_1: - sub eax, 21 - mov passTick, eax - mov eax, skulls3d_swapPair1 - mov curPair, eax - -setup_pass_pair: - cmp curPair, 1 - je pair_1 - cmp curPair, 2 - je pair_2 - mov swapSlotA, 0 - mov swapSlotB, 1 - mov xA, 48 - mov xB, 136 - jmp calc_swap_coords -pair_1: - mov swapSlotA, 1 - mov swapSlotB, 2 - mov xA, 136 - mov xB, 224 - jmp calc_swap_coords -pair_2: - mov swapSlotA, 0 - mov swapSlotB, 2 - mov xA, 48 - mov xB, 224 - -calc_swap_coords: - mov eax, xB - sub eax, xA - mov distX, eax - - mov eax, distX - imul eax, passTick - xor edx, edx - mov ecx, 20 - div ecx - mov dxVal, eax - - mov eax, xA - add eax, dxVal - mov curXA, eax - - mov eax, xB - sub eax, dxVal - mov curXB, eax - - ; Arch height: archY = (t * (20 - t)) / 25 - mov eax, passTick - mov ecx, 20 - sub ecx, eax - imul eax, ecx - xor edx, edx - mov ecx, 25 - div ecx - mov archY, eax - - mov edx, 108 - sub edx, archY - mov curYA, edx ; upper arc - - mov edx, 108 - add edx, archY - mov curYB, edx ; lower arc - - invoke DrawString8x8, 56, 70, OFFSET textSkullsPhase2, 0000FFFFh - - ; Depth sorted rendering: Background cup (upper arc) draws FIRST, Foreground cup (lower arc) draws OVER it! - invoke DrawGothicCup, curXA, curYA, 1, 0, 0 - invoke DrawGothicCup, curXB, curYB, 2, 0, 0 - - ; Draw remaining static cup - cmp curPair, 1 - je draw_stat_0 - cmp curPair, 2 - je draw_stat_1 - invoke DrawGothicCup, 224, 108, 3, 0, 0 - jmp check_pass_finish -draw_stat_0: - invoke DrawGothicCup, 48, 108, 1, 0, 0 - jmp check_pass_finish -draw_stat_1: - invoke DrawGothicCup, 136, 108, 2, 0, 0 - -check_pass_finish: - cmp skulls3d_timer, 20 - je do_pass_swap - cmp skulls3d_timer, 40 - je do_pass_swap - cmp skulls3d_timer, 60 - je do_pass_swap - jmp skulls_draw_controls - -do_pass_swap: - ; Update ballPos if involved in swap - mov eax, skulls3d_ballPos - cmp eax, swapSlotA - jne check_swap_b - mov eax, swapSlotB - mov skulls3d_ballPos, eax - jmp ball_swap_done -check_swap_b: - cmp eax, swapSlotB - jne ball_swap_done - mov eax, swapSlotA - mov skulls3d_ballPos, eax - -ball_swap_done: - invoke PlaySoundA, OFFSET soundShuffle, 0, 1 - - cmp skulls3d_timer, 60 - jl skulls_draw_controls - - ; Shuffle complete -> Move to Pick phase - mov skulls3d_state, 3 - mov skulls3d_timer, 0 - jmp skulls_draw_controls - -skulls_render_phase3: - invoke DrawString8x8, 40, 70, OFFSET textSkullsPhase3, 0000FFFFh - invoke DrawGothicCup, 48, 108, 1, 0, 0 - invoke DrawGothicCup, 136, 108, 2, 0, 0 - invoke DrawGothicCup, 224, 108, 3, 0, 0 - jmp skulls_draw_controls - -skulls_render_phase4: - ; Reveal phase - cmp skulls3d_win, 0 - je skulls_show_loss - invoke DrawString8x8, 48, 70, OFFSET textSkullsWin, 0050FF50h + jne @F + invoke DrawString8x8, 40, 62, OFFSET textSkullsPhase3, 00FFFF00h + jmp skulls_render_cups +@@: + ; Reveal outcome + mov eax, skulls3d_win + test eax, eax + jz skulls_show_loss_text + invoke DrawString8x8, 40, 62, OFFSET textSkullsWin, 003CFF3Ch invoke FormatNumber, skulls3d_win, OFFSET hudNumBuffer - invoke DrawString8x8, 216, 70, OFFSET hudNumBuffer, 0050FF50h - jmp skulls_p4_cups + invoke DrawString8x8, 136, 62, OFFSET hudNumBuffer, 003CFF3Ch + invoke DrawString8x8, 168, 62, OFFSET textSkullsWinMult, 003CFF3Ch + jmp skulls_render_cups -skulls_show_loss: - invoke DrawString8x8, 40, 70, OFFSET textSkullsLose, 008080FFh +skulls_show_loss_text: + invoke DrawString8x8, 40, 62, OFFSET textSkullsLose, 00FF6464h -skulls_p4_cups: - ; Draw chosen cup lifted - mov eax, 0 - cmp skulls3d_choice, 0 - sete al +skulls_render_cups: + ; Draw Cup 1 (X=36, Y=114) + mov ebx, 0 mov edx, 0 + cmp skulls3d_state, 1 + jne @F + cmp skulls3d_ballPos, 0 + jne @F + mov ebx, 1 + mov edx, 1 +@@: + cmp skulls3d_state, 4 + jne @F + cmp skulls3d_choice, 0 + sete bl cmp skulls3d_ballPos, 0 sete dl - invoke DrawGothicCup, 48, 108, 1, eax, edx +@@: + invoke DrawGothicCup, 36, 114, 0, ebx, edx - mov eax, 0 - cmp skulls3d_choice, 1 - sete al + ; Draw Cup 2 (X=136, Y=114) + mov ebx, 0 mov edx, 0 + cmp skulls3d_state, 1 + jne @F + cmp skulls3d_ballPos, 1 + jne @F + mov ebx, 1 + mov edx, 1 +@@: + cmp skulls3d_state, 4 + jne @F + cmp skulls3d_choice, 1 + sete bl cmp skulls3d_ballPos, 1 sete dl - invoke DrawGothicCup, 136, 108, 2, eax, edx +@@: + invoke DrawGothicCup, 136, 114, 1, ebx, edx - mov eax, 0 - cmp skulls3d_choice, 2 - sete al + ; Draw Cup 3 (X=236, Y=114) + mov ebx, 0 mov edx, 0 + cmp skulls3d_state, 1 + jne @F + cmp skulls3d_ballPos, 2 + jne @F + mov ebx, 1 + mov edx, 1 +@@: + cmp skulls3d_state, 4 + jne @F + cmp skulls3d_choice, 2 + sete bl cmp skulls3d_ballPos, 2 sete dl - invoke DrawGothicCup, 224, 108, 3, eax, edx +@@: + invoke DrawGothicCup, 236, 114, 2, ebx, edx - invoke DrawString8x8, 64, 168, OFFSET textSkullsAgain, 0000D7FFh + ; Cup selection indicators + invoke DrawString8x8, 54, 168, OFFSET textSkullsKey1, 00D0D8E0h + invoke DrawString8x8, 150, 168, OFFSET textSkullsKey2, 00D0D8E0h + invoke DrawString8x8, 250, 168, OFFSET textSkullsKey3, 00D0D8E0h -skulls_draw_controls: - invoke DrawBox, 16, 190, 288, 1, 003A1850h - - mov eax, 0 + ; Keycaps + mov kx, 16 + xor eax, eax cmp skulls3d_choice, 0 sete al - invoke DrawKeycap3D, 18, 200, OFFSET textSkullsKey1, eax + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey1, eax + add kx, eax - mov eax, 0 + xor eax, eax cmp skulls3d_choice, 1 sete al - invoke DrawKeycap3D, 82, 200, OFFSET textSkullsKey2, eax + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey2, eax + add kx, eax - mov eax, 0 + xor eax, eax cmp skulls3d_choice, 2 sete al - invoke DrawKeycap3D, 146, 200, OFFSET textSkullsKey3, eax + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey3, eax + add kx, eax - invoke DrawKeycap3D, 212, 200, OFFSET textSkullsKeySpace, 1 - invoke DrawKeycap3D, 274, 200, OFFSET textKeyEsc, 0 + invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 ret RenderSkullsGame ENDP +; ============================================================================== +; IN-ENGINE 2.5D MINI-GAME: SKILL CHECK (DEAD BY DAYLIGHT SURVIVOR CHECK) +; ============================================================================== +InitSkillGame PROC + mov skill3d_state, 0 + mov skill3d_timer, 0 + mov skill3d_hits, 0 + mov skill3d_misses, 0 + mov skill3d_needle, 55 + mov skill3d_speed, 4 + mov skill3d_dir, 1 + mov skill3d_last_result, 0 + mov skill3d_win_amount, 0 + + ; Randomize initial zone: 80 + RandomRange(90) -> 80..170 + invoke RandomRange3D, 90 + add eax, 80 + mov skill3d_zone_start, eax + + ; Great zone: start + 20 + RandomRange(12) + invoke RandomRange3D, 12 + add eax, skill3d_zone_start + add eax, 20 + mov skill3d_great_start, eax + ret +InitSkillGame ENDP + +HandleSkillInput PROC uses ebx esi + mov eax, skill3d_state + cmp eax, 0 + je skill_handle_ready + cmp eax, 1 + je skill_handle_active + cmp eax, 2 + je skill_handle_round_wait + cmp eax, 3 + je skill_handle_round_wait + cmp eax, 4 + je skill_handle_end_wait + cmp eax, 5 + je skill_handle_end_wait + ret + +skill_handle_ready: + invoke Pressed3D, 26h ; UP + test eax, eax + jnz skill_bet_up + invoke Pressed3D, 57h ; 'W' + test eax, eax + jnz skill_bet_up + invoke Pressed3D, 28h ; DOWN + test eax, eax + jnz skill_bet_down + invoke Pressed3D, 53h ; 'S' + test eax, eax + jnz skill_bet_down + jmp skill_check_start + +skill_bet_up: + mov eax, skill3d_bet + add eax, 50 + cmp eax, bankroll + jle @F + mov eax, bankroll +@@: + cmp eax, 5000 + jle @F + mov eax, 5000 +@@: + mov skill3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skill_bet_down: + mov eax, skill3d_bet + sub eax, 50 + cmp eax, 50 + jge @F + mov eax, 50 +@@: + mov skill3d_bet, eax + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skill_check_start: + invoke Pressed3D, 20h ; SPACE + test eax, eax + jz skill_input_done + + ; Deduct bet on game start if beginning of run + mov eax, skill3d_hits + or eax, skill3d_misses + jnz @F + mov eax, skill3d_bet + cmp eax, bankroll + jle skill_has_funds + mov eax, bankroll + mov skill3d_bet, eax + test eax, eax + jz skill_input_done +skill_has_funds: + mov eax, skill3d_bet + sub bankroll, eax +@@: + mov skill3d_state, 1 + mov skill3d_needle, 55 + mov skill3d_dir, 1 + invoke PlaySoundA, OFFSET soundClick, 0, 1 + ret + +skill_handle_active: + ; Move needle smoothly + mov eax, skill3d_needle + mov edx, skill3d_speed + cmp skill3d_dir, 1 + je skill_move_right + sub eax, edx + cmp eax, 52 + jge skill_update_needle + mov eax, 52 + mov skill3d_dir, 1 + jmp skill_update_needle +skill_move_right: + add eax, edx + cmp eax, 268 + jle skill_update_needle + mov eax, 268 + mov skill3d_dir, -1 +skill_update_needle: + mov skill3d_needle, eax + + ; Check SPACE pressed (Reaction Hit Attempt!) + invoke Pressed3D, 20h + test eax, eax + jz skill_input_done + + ; Is needle in Great Sweet Spot? + mov eax, skill3d_needle + mov edx, skill3d_great_start + cmp eax, edx + jl check_success_zone + add edx, skill3d_great_width + cmp eax, edx + jg check_success_zone + + ; GREAT HIT! + mov skill3d_last_result, 2 + add skill3d_hits, 2 + mov skill3d_state, 2 + mov skill3d_timer, 40 + invoke PlaySoundA, OFFSET soundCoinDing, 0, 1 + jmp skill_check_finish_round + +check_success_zone: + mov eax, skill3d_needle + mov edx, skill3d_zone_start + cmp eax, edx + jl skill_was_miss + add edx, skill3d_zone_width + cmp eax, edx + jg skill_was_miss + + ; NORMAL HIT! + mov skill3d_last_result, 1 + inc skill3d_hits + mov skill3d_state, 2 + mov skill3d_timer, 40 + invoke PlaySoundA, OFFSET soundVictory, 0, 1 + jmp skill_check_finish_round + +skill_was_miss: + ; MISS! + mov skill3d_last_result, 0 + inc skill3d_misses + mov skill3d_state, 3 + mov skill3d_timer, 45 + invoke PlaySoundA, OFFSET soundLose, 0, 1 + +skill_check_finish_round: + cmp skill3d_hits, 5 + jge skill_game_escaped + cmp skill3d_misses, 3 + jge skill_game_lost + ret + +skill_game_escaped: + mov skill3d_state, 4 + mov skill3d_timer, 0 + ; Payout: 3x total return (+$2x bet profit) + mov eax, skill3d_bet + imul eax, 3 + add bankroll, eax + mov eax, skill3d_bet + shl eax, 1 + mov skill3d_win_amount, eax + invoke PlaySoundA, OFFSET soundJackpot, 0, 1 + ret + +skill_game_lost: + mov skill3d_state, 5 + mov skill3d_timer, 0 + invoke PlaySoundA, OFFSET soundLose, 0, 1 + ret + +skill_handle_round_wait: + dec skill3d_timer + cmp skill3d_timer, 0 + jg skill_input_done + + ; Next round setup + invoke RandomRange3D, 90 + add eax, 80 + mov skill3d_zone_start, eax + + invoke RandomRange3D, 12 + add eax, skill3d_zone_start + add eax, 20 + mov skill3d_great_start, eax + + mov eax, skill3d_hits + shr eax, 1 + add eax, 4 + mov skill3d_speed, eax + mov skill3d_state, 1 + ret + +skill_handle_end_wait: + invoke Pressed3D, 20h + test eax, eax + jz skill_input_done + call InitSkillGame + ret + +skill_input_done: + ret +HandleSkillInput ENDP + +RenderSkillGame PROC uses ebx esi edi + local kx:DWORD + local tx:DWORD + + ; Industrial Steel bezel + invoke DrawBox, 0, 0, 320, 240, 00121416h + invoke DrawBoxBorder, 6, 6, 308, 228, 001A1D20h, 00FFD700h, 2 + + ; Header + invoke DrawBoxBorder, 20, 12, 280, 26, 00121418h, 00FFD700h, 2 + invoke DrawString8x8, 40, 21, OFFSET textSkillTitle, 00FFFF00h + + ; Status + invoke DrawBoxBorder, 20, 44, 110, 18, 00121418h, 002A3540h, 1 + invoke DrawString8x8, 24, 49, OFFSET textBankPrompt, 003CFF3Ch + invoke FormatNumber, bankroll, OFFSET hudNumBuffer + invoke DrawString8x8, 72, 49, OFFSET hudNumBuffer, 003CFF3Ch + + invoke DrawBoxBorder, 190, 44, 110, 18, 00121418h, 002A3540h, 1 + invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h + invoke FormatNumber, skill3d_bet, OFFSET hudNumBuffer + invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h + + ; Survivor Progress + invoke DrawString8x8, 24, 70, OFFSET textSkillHitsHdr, 003CFF3Ch + invoke FormatNumber, skill3d_hits, OFFSET hudNumBuffer + invoke DrawString8x8, 64, 70, OFFSET hudNumBuffer, 003CFF3Ch + + invoke DrawString8x8, 180, 70, OFFSET textSkillMissHdr, 00FF6464h + invoke FormatNumber, skill3d_misses, OFFSET hudNumBuffer + invoke DrawString8x8, 240, 70, OFFSET hudNumBuffer, 00FF6464h + + ; Dial Frame (Track: X=50..270, Y=102..134) + invoke DrawBoxBorder, 50, 102, 220, 32, 000F1114h, 00404855h, 2 + + ; Calibrated ticks + mov tx, 60 +skill_ticks_loop: + cmp tx, 260 + jge skill_draw_zones + invoke DrawBox, tx, 104, 1, 6, 00303845h + invoke DrawBox, tx, 126, 1, 6, 00303845h + add tx, 12 + jmp skill_ticks_loop + +skill_draw_zones: + ; Normal Success Zone (Green) + invoke DrawBoxBorder, skill3d_zone_start, 106, skill3d_zone_width, 24, 00155020h, 003CFF3Ch, 1 + + ; Great Zone (Gold) + invoke DrawBoxBorder, skill3d_great_start, 106, skill3d_great_width, 24, 00FFD700h, 00FFFF00h, 1 + + ; Pointer / Needle at skill3d_needle + mov eax, skill3d_needle + dec eax + invoke DrawBox, eax, 98, 3, 40, 00FFFFFFh + mov eax, skill3d_needle + sub eax, 2 + invoke DrawBox, eax, 96, 5, 2, 00FF3030h + invoke DrawBox, eax, 138, 5, 2, 00FF3030h + + ; Center prompts / outcome + cmp skill3d_state, 0 + jne @F + invoke DrawString8x8, 52, 150, OFFSET textSkillReadyMsg, 00FFD700h + invoke DrawString8x8, 76, 166, OFFSET textSkillPrompt, 00D0D8E0h + jmp skill_render_keys +@@: + cmp skill3d_state, 1 + jne @F + invoke DrawString8x8, 76, 150, OFFSET textSkillPrompt, 00FFFF00h + jmp skill_render_keys +@@: + cmp skill3d_state, 2 + jne @F + cmp skill3d_last_result, 2 + jne skill_normal_hit_text + invoke DrawString8x8, 36, 150, OFFSET textSkillGreatMsg, 00FFFF00h + jmp skill_render_keys +skill_normal_hit_text: + invoke DrawString8x8, 64, 150, OFFSET textSkillHitMsg, 003CFF3Ch + jmp skill_render_keys +@@: + cmp skill3d_state, 3 + jne @F + invoke DrawString8x8, 88, 150, OFFSET textSkillMissMsg, 00FF6464h + jmp skill_render_keys +@@: + cmp skill3d_state, 4 + jne @F + invoke DrawString8x8, 48, 150, OFFSET textSkillEscape, 003CFF3Ch + invoke FormatNumber, skill3d_win_amount, OFFSET hudNumBuffer + invoke DrawString8x8, 240, 150, OFFSET hudNumBuffer, 003CFF3Ch + invoke DrawString8x8, 64, 166, OFFSET textSkullsAgain, 00FFD700h + jmp skill_render_keys +@@: + invoke DrawString8x8, 44, 150, OFFSET textSkillLost, 00FF6464h + invoke DrawString8x8, 64, 166, OFFSET textSkullsAgain, 00FFD700h + +skill_render_keys: + mov kx, 16 + invoke DrawKeycap3D, kx, 192, OFFSET textSkillKeySpace, 1 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textSkillKeyBet, 0 + add kx, eax + + invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0 + ret +RenderSkillGame ENDP + """ raw_content = raw_content[:pos_games_start] + new_games_code.encode('cp1251') + raw_content[pos_player_input:] -print("[OK] Replaced games implementation block with rich 2.5D procedures") +print("[OK] Replaced procedural drawing and games code") -# Write out patched casino3d.inc +# 6. Update Trigger3DInteraction for INTERACT_SKILL_CHECK +old_skill_trigger = b"""check_target_skill: + cmp eax, INTERACT_SKILL_CHECK + jne check_target_buckshot + invoke LaunchClassicGame, OFFSET GameSkillCheck, 11, OFFSET szTitleSkillCheck + ret""" + +new_skill_trigger = b"""check_target_skill: + cmp eax, INTERACT_SKILL_CHECK + jne check_target_buckshot + call InitSkillGame + mov engineMode, MODE_SKILL + ret""" + +if old_skill_trigger in raw_content: + raw_content = raw_content.replace(old_skill_trigger, new_skill_trigger) + print("[OK] Updated Trigger3DInteraction for INTERACT_SKILL_CHECK") +else: + print("[WARN] old_skill_trigger pattern not found verbatim") + +# 7. Update leave_table: for MODE_SKILL +old_leave = b""" cmp skulls3d_state, 1 + je engine_tick + cmp skulls3d_state, 2 + je engine_tick + mov engineMode, MODE_WALK""" + +new_leave = b""" cmp skulls3d_state, 1 + je engine_tick + cmp skulls3d_state, 2 + je engine_tick + cmp engineMode, MODE_SKILL + jne @F + cmp skill3d_state, 1 + je engine_tick +@@: + mov engineMode, MODE_WALK""" + +if old_leave in raw_content: + raw_content = raw_content.replace(old_leave, new_leave) + print("[OK] Updated leave_table: for MODE_SKILL") +else: + print("[WARN] old_leave pattern not found verbatim") + +# 8. Update engine_loop dispatch for MODE_SKILL +old_dispatch = b"""check_skulls_mode: + cmp engineMode, MODE_SKULLS + jne present_frame + call HandleSkullsInput + call RenderSkullsGame + jmp present_frame""" + +new_dispatch = b"""check_skulls_mode: + cmp engineMode, MODE_SKULLS + jne check_skill_mode + call HandleSkullsInput + call RenderSkullsGame + jmp present_frame +check_skill_mode: + cmp engineMode, MODE_SKILL + jne present_frame + call HandleSkillInput + call RenderSkillGame + jmp present_frame""" + +if old_dispatch in raw_content: + raw_content = raw_content.replace(old_dispatch, new_dispatch) + print("[OK] Updated engine_loop dispatch for MODE_SKILL") +else: + print("[WARN] old_dispatch pattern not found verbatim") + +# 9. Global replacement of reversed cyan color constants to proper 00RRGGBBh +color_replacements = [ + (b'0000FFFFh', b'00FFFF00h'), # Cyan -> Pure Yellow + (b'0000D7FFh', b'00FFD700h'), # Sky Blue -> Pure Gold + (b'0000A0D0h', b'00D0A000h'), # Amber Gold + (b'0000E0FFh', b'00FFE000h'), # Bright Amber + (b'00007A9Ah', b'009A7A00h'), # Bronze / Dark Gold + (b'000080A0h', b'00A08000h'), + (b'0000B0D0h', b'00D0B000h'), + (b'0000B0E0h', b'00E0B000h'), + (b'000000FFh', b'00FF2020h'), # Pure Blue -> Bright Ruby Red + (b'008080FFh', b'00FF6464h'), # Light Periwinkle -> Soft Coral Red + (b'001515B8h', b'00B81515h'), # Blue chip -> Red Clay Casino Chip + (b'001515C8h', b'00C81515h'), # Blue pips -> Ruby Red Dice Pips +] + +for old_c, new_c in color_replacements: + count = raw_content.count(old_c) + if count > 0: + raw_content = raw_content.replace(old_c, new_c) + print(f"[OK] Replaced {old_c.decode('ascii')} -> {new_c.decode('ascii')} ({count} occurrences)") + +# Write back to casino3d.inc with open(CASINO_INC, 'wb') as f: f.write(raw_content) -print(f"[SUCCESS] casino3d.inc patched successfully! New byte length: {len(raw_content)}") +print(f"[SUCCESS] casino3d.inc successfully patched! ({len(raw_content)} bytes)") diff --git a/tools/tests/test_minigames_render.py b/tools/tests/test_minigames_render.py index e4fbd5e..170a5b3 100644 --- a/tools/tests/test_minigames_render.py +++ b/tools/tests/test_minigames_render.py @@ -1,4 +1,13 @@ # -*- coding: utf-8 -*- +""" +Visual simulation & rasterization test for 2.5D Casino Minigames. +Renders pixel-perfect 640x480 (320x240 upscaled 2x) PNG previews of: +- Coin Flip (Монетка) +- Craps / Dice (КоÑ�ти) +- Skulls & Cups (Ð�апёрÑ�тки) +- Dead by Daylight Skill Check (Проверка реакции) +Uses authentic IBM VGA 8x8 font and correct 0x00RRGGBB Little-Endian DIB color space. +""" import math from pathlib import Path from PIL import Image @@ -26,10 +35,14 @@ class RasterBuffer: self.pixels = [(0, 0, 0)] * (SCREEN_W * SCREEN_H) def to_rgb(self, c): - # 0x00BBGGRR format - r = c & 0xFF + # 0x00RRGGBB format: + # In x86 Little-Endian StretchDIBits (BI_RGB 32-bit): + # byte 0 = Blue (c & 0xFF) + # byte 1 = Green ((c >> 8) & 0xFF) + # byte 2 = Red ((c >> 16) & 0xFF) + r = (c >> 16) & 0xFF g = (c >> 8) & 0xFF - b = (c >> 16) & 0xFF + b = c & 0xFF return (r, g, b) def draw_box(self, x, y, w, h, color): @@ -65,7 +78,7 @@ class RasterBuffer: if isinstance(ch, str): try: code = ch.encode('cp1251')[0] - except: + except Exception: code = ord(ch) & 0xFF else: code = ch & 0xFF @@ -87,25 +100,23 @@ class RasterBuffer: w = len(text) * 8 + 8 h = 13 if is_active: - border_c = 0x0000FFFF - fill_c = 0x001B4B22 - txt_c = 0x0000FFFF + border_c = 0x00FFFF00 # Bright Yellow border + fill_c = 0x001B4B22 # Casino Green fill + txt_c = 0x00FFFF00 # Bright Yellow text else: - border_c = 0x00606870 - fill_c = 0x001A1C22 - txt_c = 0x00D0D8E0 + border_c = 0x00606870 # Slate border + fill_c = 0x001A1C22 # Charcoal fill + txt_c = 0x00D0D8E0 # Silver text self.draw_box(x, y + 2, w, h, 0x0008080C) # shadow self.draw_box_border(x, y, w, h, fill_c, border_c, 1) self.draw_string(x + 4, y + 3, text, txt_c) return w + 4 def draw_chip_stack(self, x, y, count=3): - # Draw stack of 3D casino clay chips for i in range(count): cy = y - i * 4 - self.draw_box(x + 2, cy + 5, 20, 2, 0x00041006) # shadow - self.draw_box_border(x, cy, 24, 6, 0x001515B8, 0x00FFFFFF, 1) - # white stripe inlays + self.draw_box(x + 2, cy + 5, 20, 2, 0x00061004) # shadow + self.draw_box_border(x, cy, 24, 6, 0x00B81515, 0x00FFFFFF, 1) # Red chip self.draw_box(x + 4, cy + 1, 3, 4, 0x00FFFFFF) self.draw_box(x + 17, cy + 1, 3, 4, 0x00FFFFFF) @@ -128,12 +139,13 @@ class RasterBuffer: self.draw_pixel(cur_x, cur_y, inner_color) if rx >= 14 and relief == 1: - gold_dark = 0x00007A9A - # Imperial Eagle + gold_dark = 0x009A7A00 # Dark Gold relief + gold_bright = 0x00FFD700 + # Double-headed imperial eagle relief self.draw_box(cx - 3, cy - 14, 7, 2, gold_dark) self.draw_box(cx - 4, cy - 12, 9, 2, gold_dark) self.draw_box(cx - 2, cy - 9, 5, 12, gold_dark) - self.draw_box(cx - 1, cy - 8, 3, 10, 0x0000D7FF) + self.draw_box(cx - 1, cy - 8, 3, 10, gold_bright) self.draw_box(cx - 10, cy - 8, 7, 3, gold_dark) self.draw_box(cx - 13, cy - 5, 10, 3, gold_dark) self.draw_box(cx - 11, cy - 2, 7, 3, gold_dark) @@ -143,29 +155,30 @@ class RasterBuffer: self.draw_box(cx - 4, cy + 4, 9, 3, gold_dark) self.draw_box(cx - 3, cy + 7, 7, 3, gold_dark) elif rx >= 14 and relief == 2: - gold_dark = 0x00007A9A - # Roman numeral 'I' + gold_dark = 0x009A7A00 + gold_bright = 0x00FFD700 + # Roman numeral 'I' & laurel crown self.draw_box(cx - 5, cy - 10, 11, 3, gold_dark) self.draw_box(cx - 2, cy - 7, 5, 14, gold_dark) - self.draw_box(cx - 1, cy - 6, 3, 12, 0x0000D7FF) + self.draw_box(cx - 1, cy - 6, 3, 12, gold_bright) self.draw_box(cx - 6, cy + 7, 13, 3, gold_dark) for w_dy in [-10, -5, 0, 5, 9]: self.draw_box(cx - 12, cy + w_dy, 2, 2, gold_dark) self.draw_box(cx + 11, cy + w_dy, 2, 2, gold_dark) def draw_craps_die(self, x, y, size, val): - self.draw_box(x + 3, y + size, size, 3, 0x00031408) - self.draw_box(x + size, y + 3, 3, size, 0x00031408) - body_color = 0x00F0F4FA - bevel_color = 0x00C0C6D0 - border_color = 0x00353540 + self.draw_box(x + 3, y + size, size, 3, 0x00081403) + self.draw_box(x + size, y + 3, 3, size, 0x00081403) + body_color = 0x00FAF4F0 + bevel_color = 0x00D0C6C0 + border_color = 0x00403535 self.draw_box_border(x, y, size, size, body_color, border_color, 1) self.draw_box(x + 1, y + 1, size - 2, 1, 0x00FFFFFF) self.draw_box(x + 1, y + 1, 1, size - 2, 0x00FFFFFF) self.draw_box(x + 1, y + size - 2, size - 2, 1, bevel_color) self.draw_box(x + size - 2, y + 1, 1, size - 2, bevel_color) - pip_c = 0x001515C8 + pip_c = 0x00C81515 # Red ruby pips pip_r = 3 if val in [1, 3, 5]: self.draw_circle(x + size // 2, y + size // 2, pip_r, pip_c) @@ -183,35 +196,36 @@ class RasterBuffer: def draw_gothic_cup(self, x, y, cup_id, is_lifted=False, has_ball=False): lift_y = y - 36 if is_lifted else y if not is_lifted: - self.draw_box(x + 6, y + 42, 36, 4, 0x000A0410) + self.draw_box(x + 6, y + 42, 36, 4, 0x0010040A) else: - self.draw_box(x + 10, y + 42, 28, 2, 0x0012061A) + self.draw_box(x + 10, y + 42, 28, 2, 0x001A0612) if is_lifted and has_ball: self.draw_glowing_orb(x + 24, y + 26) - self.draw_box_border(x + 6, lift_y + 36, 36, 6, 0x00221A30, 0x0000B0D0, 1) - self.draw_box(x + 18, lift_y + 28, 12, 8, 0x00332545) - self.draw_box(x + 22, lift_y + 28, 4, 8, 0x0055406E) - self.draw_box_border(x + 8, lift_y + 8, 32, 20, 0x002D1E40, 0x0000D7FF, 1) - self.draw_box(x + 14, lift_y + 10, 6, 16, 0x00503570) - self.draw_box(x + 17, lift_y + 10, 3, 16, 0x007850A0) - self.draw_box_border(x + 4, lift_y + 2, 40, 7, 0x00150A20, 0x0000FFFF, 1) - self.draw_box(x + 12, lift_y + 4, 16, 2, 0x0000FFFF) + self.draw_box_border(x + 6, lift_y + 36, 36, 6, 0x00301A22, 0x00D0B000, 1) + self.draw_box(x + 18, lift_y + 28, 12, 8, 0x00452533) + self.draw_box(x + 22, lift_y + 28, 4, 8, 0x006E4055) + self.draw_box_border(x + 8, lift_y + 8, 32, 20, 0x00401E2D, 0x00FFD700, 1) + self.draw_box(x + 14, lift_y + 10, 6, 16, 0x00703550) + self.draw_box(x + 17, lift_y + 10, 3, 16, 0x00A05078) + self.draw_box_border(x + 4, lift_y + 2, 40, 7, 0x00200A15, 0x00FFFF00, 1) + self.draw_box(x + 12, lift_y + 4, 16, 2, 0x00FFFF00) - self.draw_box(x + 21, lift_y + 12, 6, 5, 0x0000D7FF) - self.draw_box(x + 22, lift_y + 17, 4, 3, 0x0000D7FF) - self.draw_pixel(x + 22, lift_y + 14, 0x00150A20) - self.draw_pixel(x + 24, lift_y + 14, 0x00150A20) - self.draw_string(x + 21, lift_y + 24, str(cup_id), 0x0000FFFF) + # Skull face relief on goblet + self.draw_box(x + 21, lift_y + 12, 6, 5, 0x00FFD700) + self.draw_box(x + 22, lift_y + 17, 4, 3, 0x00FFD700) + self.draw_pixel(x + 22, lift_y + 14, 0x00200A15) + self.draw_pixel(x + 24, lift_y + 14, 0x00200A15) + self.draw_string(x + 21, lift_y + 24, str(cup_id), 0x00FFFF00) def draw_glowing_orb(self, cx, cy): - self.draw_circle(cx, cy, 14, 0x00081E2E) - self.draw_circle(cx, cy, 11, 0x00103A58) - self.draw_circle(cx, cy, 8, 0x001A588A) - self.draw_circle(cx, cy, 6, 0x0000B0E0) - self.draw_circle(cx, cy, 4, 0x0000E0FF) - self.draw_circle(cx - 1, cy - 1, 2, 0x00A0FFFF) + self.draw_circle(cx, cy, 14, 0x002E1E08) + self.draw_circle(cx, cy, 11, 0x00583A10) + self.draw_circle(cx, cy, 8, 0x008A581A) + self.draw_circle(cx, cy, 6, 0x00D0B000) + self.draw_circle(cx, cy, 4, 0x00FFE000) + self.draw_circle(cx - 1, cy - 1, 2, 0x00FFFF80) self.draw_pixel(cx - 2, cy - 2, 0x00FFFFFF) def save(self, filename): @@ -222,158 +236,216 @@ class RasterBuffer: print(f"Saved {out_path}") # ============================================================================== -# 1. RENDER COIN GAME +# 1. RENDER COIN GAME (Монетка) # ============================================================================== def render_coin(filename='coin_preview.png'): b = RasterBuffer() - b.draw_box(0, 0, 320, 240, 0x00060914) # Mahogany cabinet - b.draw_box_border(6, 6, 308, 228, 0x000F1522, 0x001B2E48, 3) + b.draw_box(0, 0, 320, 240, 0x00140906) # Mahogany cabinet + b.draw_box_border(6, 6, 308, 228, 0x0022150F, 0x00482E1B, 3) for cx in [12, 306]: for cy in [12, 226]: - b.draw_box(cx, cy, 3, 3, 0x0000D7FF) + b.draw_box(cx, cy, 3, 3, 0x00FFD700) b.draw_pixel(cx + 1, cy + 1, 0x00FFFFFF) - b.draw_box_border(20, 12, 280, 26, 0x000A101C, 0x0000D7FF, 2) - b.draw_string(44, 21, '*** З О Л О Т Ð� Я М О Ð� Е Т Ð� ***', 0x0000FFFF) + b.draw_box_border(20, 12, 280, 26, 0x001C100A, 0x00FFD700, 2) + b.draw_string(44, 21, '* * * З О Л О Т Ð� Я М О Ð� Е Т Ð� * * *', 0x00FFFF00) for bx in range(24, 296, 12): - b.draw_pixel(bx, 13, 0x0000FFFF) - b.draw_pixel(bx, 36, 0x0000D7FF) + b.draw_pixel(bx, 13, 0x00FFFF00) + b.draw_pixel(bx, 36, 0x00FFD700) # Status meters - b.draw_box_border(20, 44, 110, 18, 0x000A1A0E, 0x001A4B22, 1) - b.draw_string(24, 49, 'БÐ�Ð�К: $12500', 0x0050FF50) + b.draw_box_border(20, 44, 110, 18, 0x000E1A0A, 0x00224B1A, 1) + b.draw_string(24, 49, 'БÐ�Ð�К: $12500', 0x003CFF3C) b.draw_box_border(190, 44, 110, 18, 0x001A100A, 0x003A2814, 1) - b.draw_string(194, 49, 'СТÐ�ВКÐ�: $50 [W/S]', 0x0000D7FF) + b.draw_string(194, 49, 'СТÐ�ВКÐ�: $250', 0x00FFD700) - # Center Dish - b.draw_circle(160, 110, 46, 0x000090C0) - b.draw_circle(160, 110, 44, 0x0000D7FF) - b.draw_circle(160, 110, 41, 0x00180824) + # Side indicators + # Left: Heads (Selected) + b.draw_box(20, 72, 76, 68, 0x000A101C) + b.draw_box_border(20, 72, 76, 68, 0x00101828, 0x00FFFF00, 2) + b.draw_string(30, 78, '[1] ОРÐ�Л', 0x00FFFF00) + b.draw_coin_ellipse(58, 106, 14, 14, 0x00D0A000, 0x00FFD700, 1) + b.draw_string(24, 126, 'ВЫБРÐ�Ð�О', 0x003CFF3C) - # Coin at rest (Heads) - b.draw_coin_ellipse(160, 110, 26, 26, 0x0000A0D0, 0x0000D7FF, relief=1) + # Right: Tails + b.draw_box(224, 72, 76, 68, 0x000A101C) + b.draw_box_border(224, 72, 76, 68, 0x00101828, 0x00404855, 1) + b.draw_string(234, 78, '[2] РЕШКÐ�', 0x00D0D8E0) + b.draw_coin_ellipse(262, 106, 14, 14, 0x00A08000, 0x00D0B000, 2) - # Left: [1] ОРЕЛ (Active) - b.draw_box_border(20, 72, 76, 52, 0x001C3822, 0x0000FFFF, 2) - b.draw_string(28, 78, '[1] ОРÐ�Л', 0x0000FFFF) - b.draw_coin_ellipse(58, 106, 12, 12, 0x0000A0D0, 0x0000D7FF, relief=1) + # Center coin spotlight + b.draw_circle(160, 110, 48, 0x00121620) + b.draw_circle(160, 110, 44, 0x00FFD700) + b.draw_circle(160, 110, 42, 0x000E141E) + b.draw_coin_ellipse(160, 110, 26, 26, 0x00D0A000, 0x00FFD700, 1) - # Right: [2] РЕШКÐ� - b.draw_box_border(224, 72, 76, 52, 0x00121620, 0x00404855, 1) - b.draw_string(232, 78, '[2] РЕШКÐ�', 0x0090A0B0) - b.draw_coin_ellipse(262, 106, 12, 12, 0x000080A0, 0x0000B0D0, relief=2) + # Result Banner + b.draw_box_border(44, 154, 232, 22, 0x000E141E, 0x003CFF3C, 1) + b.draw_string(60, 161, 'ПОБЕДÐ�: +$500! СЕРИЯ x3', 0x003CFF3C) - # Streak - b.draw_box_border(44, 154, 232, 20, 0x000E141E, 0x0000D7FF, 1) - b.draw_string(52, 160, 'СЕРИЯ: [X] [X] [X] [ ] [ ] x4!', 0x0000FFFF) + # Bottom Keycaps + kx = 16 + kx += b.draw_keycap(kx, 192, '[1] ОРÐ�Л', is_active=True) + kx += b.draw_keycap(kx, 192, '[2] РЕШКÐ�', is_active=False) + kx += b.draw_keycap(kx, 192, '[SPACE]', is_active=True) + b.draw_keycap(kx, 192, '[ESC]', is_active=False) - # Keycaps - b.draw_box(16, 194, 288, 1, 0x001E2E40) - b.draw_keycap(22, 202, '1:ОРÐ�Л', is_active=True) - b.draw_keycap(88, 202, '2:РЕШКÐ�') - b.draw_keycap(160, 202, 'ПРОБЕЛ:БРОСОК', is_active=True) - b.draw_keycap(274, 202, 'ESC') b.save(filename) # ============================================================================== -# 2. RENDER DICE GAME +# 2. RENDER DICE GAME (КоÑ�ти) # ============================================================================== def render_dice(filename='dice_preview.png'): b = RasterBuffer() - # Emerald felt - b.draw_box(0, 0, 320, 240, 0x00082E12) - # Oak wood border & leather bumper - b.draw_box_border(4, 4, 312, 232, 0x00093816, 0x00122244, 3) - b.draw_box_border(8, 8, 304, 224, 0x000A3F19, 0x0005140A, 2) - - # Pyramidal backboard rubber diamond texture along top - for bx in range(12, 308, 12): - b.draw_box(bx + 4, 11, 4, 4, 0x00041006) - b.draw_pixel(bx + 5, 12, 0x000F4820) + b.draw_box(0, 0, 320, 240, 0x00140906) # Mahogany frame + b.draw_box_border(6, 6, 308, 228, 0x000A3816, 0x00FFD700, 2) # Deep Green Felt # Header - b.draw_string(48, 20, '==== G R A N D C R A P S T A B L E ====', 0x0000D7FF) - b.draw_string(72, 32, '[ PASS LINE ] [ ANY CRAPS ]', 0x0000B0A0) + b.draw_box_border(20, 12, 280, 26, 0x00072E13, 0x00FFD700, 2) + b.draw_string(48, 21, '=== G R A N D C R A P S ===', 0x00FFFF00) # Status - b.draw_box_border(16, 46, 100, 16, 0x0006240E, 0x000E5022, 1) - b.draw_string(20, 50, 'БÐ�Ð�К: $12500', 0x0050FF50) - b.draw_box_border(204, 46, 100, 16, 0x0006240E, 0x000E5022, 1) - b.draw_string(208, 50, 'СТÐ�ВКÐ�: $50 [W/S]', 0x0000D7FF) + b.draw_box_border(20, 44, 110, 18, 0x00072E13, 0x001B4B22, 1) + b.draw_string(24, 49, 'БÐ�Ð�К: $12500', 0x003CFF3C) + b.draw_box_border(190, 44, 110, 18, 0x00072E13, 0x001B4B22, 1) + b.draw_string(194, 49, 'СТÐ�ВКÐ�: $100', 0x00FFD700) - # Betting Zones - # Left: [1] ЧЕТ (Active with chip stack!) - b.draw_box_border(16, 68, 88, 54, 0x000B441D, 0x0000FFFF, 2) - b.draw_string(24, 74, '[1] ЧÐ�Т', 0x0000FFFF) - b.draw_string(20, 86, '2 4 6 8 10 12', 0x0000D7FF) - b.draw_chip_stack(48, 110, count=4) + # Betting Pass Lines + # [1] ЧÐ�Т + b.draw_box_border(16, 70, 88, 48, 0x00072E13, 0x00FFFF00, 2) + b.draw_string(30, 76, '[1] ЧÐ�Т', 0x00FFFF00) + b.draw_string(22, 90, ' 2 4 6 8 10 ', 0x00FFD700) + b.draw_string(26, 104, 'ВЫБРÐ�Ð�О', 0x003CFF3C) - # Right: [2] Ð�ЕЧЕТ - b.draw_box_border(216, 68, 88, 54, 0x00073014, 0x001A602A, 1) - b.draw_string(224, 74, '[2] Ð�ЕЧЕТ', 0x0080B090) - b.draw_string(222, 86, '3 5 7 9 11', 0x00508060) + # [2] Ð�ЕЧЕТ + b.draw_box_border(216, 70, 88, 48, 0x00072E13, 0x001B4B22, 1) + b.draw_string(226, 76, '[2] Ð�ЕЧЕТ', 0x00D0D8E0) + b.draw_string(224, 90, ' 3 5 7 9 11 ', 0x0080B090) - # Center Dice Field - b.draw_box_border(112, 68, 96, 54, 0x00072E13, 0x00145826, 1) - # Draw Two Precision Dice - b.draw_craps_die(120, 76, 36, 4) - b.draw_craps_die(164, 76, 36, 6) + # Center Craps Table: 2 Dice + b.draw_craps_die(116, 80, 36, 4) + b.draw_craps_die(168, 76, 36, 6) - # Score Plaque - b.draw_box_border(36, 130, 248, 30, 0x00051D0C, 0x0000D7FF, 1) - b.draw_string(44, 135, 'СУММÐ�: 4 + 6 = 10 (ЧÐ�Т)', 0x0000FFFF) - b.draw_string(68, 147, 'ВЫИГРЫШ: +$100! (x2)', 0x0050FF50) + # Sum & Result + b.draw_box_border(36, 132, 248, 36, 0x00072E13, 0x00FFD700, 1) + b.draw_string(48, 138, 'СУММÐ�: 4 + 6 = 10 (ЧÐ�Т)', 0x00FFFF00) + b.draw_string(68, 152, 'ВЫИГРЫШ: +$200! (x2)', 0x003CFF3C) # Keycaps - b.draw_box(16, 188, 288, 1, 0x00104820) - b.draw_keycap(20, 198, '1:ЧÐ�Т', is_active=True) - b.draw_keycap(82, 198, '2:Ð�ЕЧЕТ') - b.draw_keycap(160, 198, 'ПРОБЕЛ:БРОСОК', is_active=True) - b.draw_keycap(274, 198, 'ESC') + kx = 16 + kx += b.draw_keycap(kx, 192, '[1] ЧÐ�Т', is_active=True) + kx += b.draw_keycap(kx, 192, '[2] Ð�ЕЧЕТ', is_active=False) + kx += b.draw_keycap(kx, 192, '[SPACE]', is_active=True) + b.draw_keycap(kx, 192, '[ESC]', is_active=False) + b.save(filename) # ============================================================================== -# 3. RENDER SKULLS GAME +# 3. RENDER SKULLS GAME (Ð�апёрÑ�тки) # ============================================================================== def render_skulls(filename='skulls_preview.png'): b = RasterBuffer() - # Dark gothic table with purple velvet - b.draw_box(0, 0, 320, 240, 0x000D0612) - b.draw_box_border(4, 4, 312, 232, 0x00160B20, 0x00321845, 3) - b.draw_box_border(8, 8, 304, 224, 0x00220F30, 0x0000D7FF, 1) + b.draw_box(0, 0, 320, 240, 0x00140906) + b.draw_box_border(6, 6, 308, 228, 0x00300F22, 0x00FFD700, 2) # Gothic Purple # Header - b.draw_box_border(24, 12, 272, 24, 0x0012081A, 0x0000D7FF, 2) - b.draw_string(48, 20, '+ + + Ð� Ð� П Ð� Р С Т К И С К Ð’ Е Р Ð� Ы + + +', 0x0000FFFF) + b.draw_box_border(20, 12, 280, 26, 0x001A0812, 0x00FFD700, 2) + b.draw_string(44, 21, '* * * Ð� Ð� П Ð� Р С Т К И * * *', 0x00FFFF00) # Status - b.draw_box_border(20, 42, 110, 16, 0x000D0616, 0x00401858, 1) - b.draw_string(24, 46, 'БÐ�Ð�К: $12500', 0x0050FF50) - b.draw_box_border(190, 42, 110, 16, 0x000D0616, 0x00401858, 1) - b.draw_string(194, 46, 'СТÐ�ВКÐ�: $50 [W/S]', 0x0000D7FF) + b.draw_box_border(20, 44, 110, 18, 0x001A0812, 0x00452033, 1) + b.draw_string(24, 49, 'БÐ�Ð�К: $12500', 0x003CFF3C) + b.draw_box_border(190, 44, 110, 18, 0x001A0812, 0x00452033, 1) + b.draw_string(194, 49, 'СТÐ�ВКÐ�: $300', 0x00FFD700) - # Table Runner - b.draw_box_border(16, 66, 288, 114, 0x001A0B25, 0x00452060, 1) + # Subtitle + b.draw_string(40, 62, 'ВЫИГРЫШ: +$900! (x3) ВЫ УГÐ�ДÐ�ЛИ!', 0x003CFF3C) - # Narrative banner - b.draw_string(40, 74, 'СЛЕДИ ЗÐ� ЗОЛОТЫМ ОКОМ СУДЬБЫ...', 0x0000FFFF) + # 3 Cups: Cup 2 lifted revealing gold ball + b.draw_gothic_cup(36, 114, 1, is_lifted=False, has_ball=False) + b.draw_gothic_cup(136, 114, 2, is_lifted=True, has_ball=True) + b.draw_gothic_cup(236, 114, 3, is_lifted=False, has_ball=False) - # Draw 3 Gothic Cups (Cup 2 is lifted revealing glowing orb!) - b.draw_gothic_cup(48, 100, 1, is_lifted=False) - b.draw_gothic_cup(136, 100, 2, is_lifted=True, has_ball=True) - b.draw_gothic_cup(224, 100, 3, is_lifted=False) + # Selection indicators + b.draw_string(54, 168, '[ 1 ]', 0x00D0D8E0) + b.draw_string(150, 168, '[ 2 ]', 0x00FFFF00) + b.draw_string(250, 168, '[ 3 ]', 0x00D0D8E0) # Keycaps - b.draw_box(16, 190, 288, 1, 0x003A1850) - b.draw_keycap(18, 200, '1:КУБОК') - b.draw_keycap(82, 200, '2:КУБОК', is_active=True) - b.draw_keycap(146, 200, '3:КУБОК') - b.draw_keycap(212, 200, 'ПРОБЕЛ', is_active=True) - b.draw_keycap(274, 200, 'ESC') + kx = 16 + kx += b.draw_keycap(kx, 192, '[1]', is_active=False) + kx += b.draw_keycap(kx, 192, '[2]', is_active=True) + kx += b.draw_keycap(kx, 192, '[3]', is_active=False) + kx += b.draw_keycap(kx, 192, '[SPACE] СТÐ�РТ', is_active=True) + b.draw_keycap(kx, 192, '[ESC]', is_active=False) + + b.save(filename) + +# ============================================================================== +# 4. RENDER SKILL CHECK GAME (Dead by Daylight Survivor Check) +# ============================================================================== +def render_skill(filename='skill_preview.png'): + b = RasterBuffer() + # Industrial survivor steel bezel + b.draw_box(0, 0, 320, 240, 0x00121416) + b.draw_box_border(6, 6, 308, 228, 0x001A1D20, 0x00FFD700, 2) + + # Header + b.draw_box_border(20, 12, 280, 26, 0x00121418, 0x00FFD700, 2) + b.draw_string(44, 21, '* * * Ð� Ð� П Ð� Р С Т К И * * *', 0x00FFFF00) + + # Status + b.draw_box_border(20, 44, 110, 18, 0x00121418, 0x002A3540, 1) + b.draw_string(24, 49, 'БÐ�Ð�К: $12500', 0x003CFF3C) + b.draw_box_border(190, 44, 110, 18, 0x00121418, 0x002A3540, 1) + b.draw_string(194, 49, 'СТÐ�ВКÐ�: $200', 0x00FFD700) + + # Survivor progress + b.draw_string(24, 70, 'ХИТ: 3 / 5', 0x003CFF3C) + b.draw_string(180, 70, 'ПРОМÐ�Ð¥: 1 / 3', 0x00FF6464) + + # Tension Dial / Track: X=50 to 270, Y=100 to 134 + track_x = 50 + track_y = 102 + track_w = 220 + track_h = 32 + + # Outer frame + b.draw_box_border(track_x, track_y, track_w, track_h, 0x000F1114, 0x00404855, 2) + + # Calibrated ticks + for tx in range(track_x + 10, track_x + track_w - 10, 12): + b.draw_box(tx, track_y + 2, 1, 6, 0x00303845) + b.draw_box(tx, track_y + track_h - 8, 1, 6, 0x00303845) + + # Normal Success Zone (Green): X=150 to 198 (48px) + b.draw_box_border(150, track_y + 4, 48, track_h - 8, 0x00155020, 0x003CFF3C, 1) + + # Great / Perfect Sweet Spot (Gold): X=186 to 198 (12px) + b.draw_box_border(186, track_y + 4, 12, track_h - 8, 0x00FFD700, 0x00FFFF00, 1) + b.draw_string(156, track_y + 10, 'HIT!', 0x003CFF3C) + + # Needle at X=190 (Inside Great Zone!) + needle_x = 190 + b.draw_box(needle_x - 1, track_y - 4, 3, track_h + 8, 0x00FFFFFF) + b.draw_box(needle_x - 2, track_y - 6, 5, 2, 0x00FF3030) + b.draw_box(needle_x - 2, track_y + track_h + 4, 5, 2, 0x00FF3030) + + # Prompt text + b.draw_string(52, 150, 'ОТЛИЧÐ�О! GREAT SKILL CHECK!', 0x00FFFF00) + b.draw_string(76, 166, 'Ð�Ð�ЖМИТЕ [ПРОБЕЛ] Ð’ ЗОÐ�Е', 0x00D0D8E0) + + # Bottom Keycaps + kx = 16 + kx += b.draw_keycap(kx, 192, '[SPACE] РЕÐ�КЦИЯ', is_active=True) + kx += b.draw_keycap(kx, 192, '[ВВЕРХ/Ð’Ð�ИЗ]', is_active=False) + b.draw_keycap(kx, 192, '[ESC]', is_active=False) + b.save(filename) if __name__ == '__main__': render_coin() render_dice() render_skulls() - print("All 3 minigames previews rendered successfully!") + render_skill() + print("[ALL DONE] All 4 previews successfully generated!")