KAZIK/tools/generators/generate_rich_minigames.py

1790 lines
46 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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

# -*- coding: utf-8 -*-
"""
Generator script to patch casino3d.inc with rich, custom 2.5D graphics
and fixed audio for Coin Flip, Craps/Dice, and Skulls & Cups.
"""
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
CASINO_INC = REPO_ROOT / 'casino3d.inc'
# Read original casino3d.inc
with open(CASINO_INC, 'rb') as f:
raw_content = f.read()
# 1. Fix Audio Declarations (around line 150)
old_audio_block = (
b'soundCoin db "assets\\audio\\\xc7\xe2\xee\xed \xef\xe0\xe4\xe0\xfe\xf9\xe5\xe9 \xec\xee\xed\xe5\xf2\xfb.wav",0\r\n'
b'soundCards db "assets\\audio\\playing_cards_deck_flick_through_001_20485.wav",0\r\n'
b'soundRoulette db "assets\\audio\\roulette-wheel-throw-2.wav",0\r\n'
b'soundJackpot db "assets\\audio\\\xc4\xe6\xe5\xea\xef\xee\xf2.wav",0\r\n'
b'soundClick db "assets\\audio\\b05e1ac8be34248.wav",0'
)
new_audio_block = (
b'soundCoin db "assets\\audio\\\xc7\xe2\xf3\xea \xec\xee\xed\xe5\xf2\xfb \xe1\xf0\xee\xf8\xe5\xed\xed\xee\xe9 \xe2 \xe2\xee\xe7\xe4\xf3\xf5 \xe8 \xf3\xef\xe0\xe2\xf8\xe5\xe9 \xed\xe0 \xef\xee\xe2\xe5\xf0\xf5\xed\xee\xf1\xf2\xfc.wav",0\r\n'
b'soundCoinDing db "assets\\audio\\\xc7\xe2\xf3\xea \xec\xee\xed\xe5\xf2\xfb \xe2 \xe8\xe3\xf0\xe5 Ultrakill.wav",0\r\n'
b'soundCards db "assets\\audio\\playing_cards_deck_flick_through_001_20485.wav",0\r\n'
b'soundRoulette db "assets\\audio\\roulette-wheel-throw-2.wav",0\r\n'
b'soundJackpot db "assets\\audio\\\xc4\xe6\xfd\xea \xef\xee\xf2.wav",0\r\n'
b'soundVictory db "assets\\audio\\victory-tf2.wav",0\r\n'
b'soundClick db "assets\\audio\\revolverdryfirec.wav",0\r\n'
b'soundShuffle db "assets\\audio\\moving-stone.wav",0\r\n'
b'soundLose db "assets\\audio\\\xcf\xf0\xee\xe8\xe3\xf0\xfb\xf8.wav",0'
)
if old_audio_block in raw_content:
raw_content = raw_content.replace(old_audio_block, new_audio_block, 1)
print("[OK] Replaced audio block (removed gunshots, fixed real sound paths)")
else:
print("[WARN] Audio block pattern not found verbatim, checking sub-patterns...")
if b'soundClick db "assets\\audio\\b05e1ac8be34248.wav",0' in raw_content:
raw_content = raw_content.replace(
b'soundClick db "assets\\audio\\b05e1ac8be34248.wav",0',
b'soundClick db "assets\\audio\\revolverdryfirec.wav",0\r\n'
b'soundShuffle db "assets\\audio\\moving-stone.wav",0\r\n'
b'soundLose db "assets\\audio\\\xcf\xf0\xee\xe8\xe3\xf0\xfb\xf8.wav",0\r\n'
b'soundVictory db "assets\\audio\\victory-tf2.wav",0\r\n'
b'soundCoinDing db "assets\\audio\\\xc7\xe2\xf3\xea \xec\xee\xed\xe5\xf2\xfb \xe2 \xe8\xe3\xf0\xe5 Ultrakill.wav",0'
)
print("[OK] Replaced soundClick and added soundShuffle / soundLose")
# 2. Update string constants (around line 290)
# Find start of coinRxAnimTable and end before shopMsg
pos_coin_table = raw_content.find(b'coinRxAnimTable db')
pos_shop_msg = raw_content.find(b'shopMsg db 128 dup(0)')
assert pos_coin_table != -1 and pos_shop_msg != -1, "Could not locate text strings section"
new_strings_text = """coinRxAnimTable db 26, 22, 16, 6, 16, 22, 26, 22, 16, 6
; --- Native 2.5D Coin Flip ---
textCoinTitle db "* * * \xc7 \xce \xcb \xce \xd2 \xc0 \xdf \xcc \xce \xcd \xc5 \xd2 \xc0 * * *",0
textCoinHeads db "\xce\xd0\xa8\xcb",0
textCoinTails db "\xd0\xc5\xd8\xca\xc0",0
textCoinStreak db "\xd1\xc5\xd0\xc8\xdf: ",0
textCoinSide1 db "[1] \xce\xd0\xa8\xcb",0
textCoinSide2 db "[2] \xd0\xc5\xd8\xca\xc0",0
textCoinFlipping db "\xcc\xce\xcd\xc5\xd2\xc0 \xc2 \xcf\xce\xcb\xa8\xd2\xc5...",0
textCoinWin db "\xc2\xdb\xc8\xc3\xd0\xdb\xd8: +$",0
textCoinLose db "\xcd\xc5 \xd3\xc3\xc0\xc4\xc0\xcb!",0
textCoinKey1 db "1:\xce\xd0\xa8\xcb",0
textCoinKey2 db "2:\xd0\xc5\xd8\xca\xc0",0
textCoinKeySpace db "\xcf\xd0\xce\xc1\xc5\xcb:\xc1\xd0\xce\xd1\xce\xca",0
textCoinStreakFmt db "\xd1\xc5\xd0\xc8\xdf: [X] [X] [X] [ ] [ ] x4!",0
; --- Native 2.5D Dice Game ---
dice3d_bet dd 50
dice3d_choice dd 1 ; 1 = \xd7\xb8\xf2, 2 = \xcd\xe5\xf7\xe5\xf2
dice3d_state dd 0 ; 0 = Idle, 1 = Rolling, 2 = Result
dice3d_timer dd 0
dice3d_val1 dd 4
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
textDiceEven db "[1] \xd7\xa8\xd2",0
textDiceOdd db "[2] \xcd\xc5\xd7\xc5\xd2",0
textDiceEvenNums db "2 4 6 8 10",0
textDiceOddNums db "3 5 7 9 11",0
textDiceSumHdr db "\xd1\xd3\xcc\xcc\xc0: ",0
textDicePlus db " + ",0
textDiceEqual db " = ",0
textDiceEvenResult db " (\xd7\xa8\xd2)",0
textDiceOddResult db " (\xcd\xc5\xd7\xc5\xd2)",0
textDiceRolling db "\xca\xce\xd1\xd2\xc8 \xcb\xc5\xd2\xdf\xd2 \xcf\xce \xd1\xd3\xca\xcd\xd3...",0
textDiceWin db "\xc2\xdb\xc8\xc3\xd0\xdb\xd8: +$",0
textDiceWinMult db "! (x2)",0
textDiceLose db "\xcf\xd0\xce\xc8\xc3\xd0\xdb\xd8!",0
textDiceKey1 db "1:\xd7\xa8\xd2",0
textDiceKey2 db "2:\xcd\xc5\xd7\xc5\xd2",0
textDiceKeySpace db "\xcf\xd0\xce\xc1\xc5\xcb:\xc1\xd0\xce\xd1\xce\xca",0
; --- Native 2.5D Skulls Game ---
skulls3d_bet dd 50
skulls3d_state dd 0 ; 0 = Idle, 1 = Show ball, 2 = Shuffle, 3 = Pick, 4 = Reveal
skulls3d_timer dd 0
skulls3d_ballPos dd 1 ; 0, 1, 2
skulls3d_choice dd 1 ; 0, 1, 2
skulls3d_win dd 0
skulls3d_swapPair0 dd 0
skulls3d_swapPair1 dd 1
skulls3d_swapPair2 dd 2
textSkullsTitle db "+ + + \xcd \xc0 \xcf \xa8 \xd0 \xd1 \xd2 \xca \xc8 + + +",0
textSkullsPhase0 db "\xc4\xc5\xcb\xc0\xc9 \xd1\xd2\xc0\xc2\xca\xd3 \xc8 \xc6\xcc\xc8 [\xcf\xd0\xce\xc1\xc5\xcb]",0
textSkullsPhase1 db "\xd1\xcc\xce\xd2\xd0\xc8, \xc3\xc4\xc5 \xc7\xce\xcb\xce\xd2\xce\xc9 \xd8\xc0\xd0...",0
textSkullsPhase2 db "\xca\xd0\xd3\xd7\xd3, \xc2\xc5\xd0\xd7\xd3, \xc7\xc0\xcf\xd3\xd2\xc0\xd2\xdc \xd5\xce\xd7\xd3...",0
textSkullsPhase3 db "\xc3\xc4\xc5 \xd8\xc0\xd0? \xc2\xdb\xc1\xc8\xd0\xc0\xc9: [1], [2] \xc8\xcb\xc8 [3]!",0
textSkullsWin db "\xc2\xc5\xd0\xcd\xce! \xc2\xdb\xcf\xcb\xc0\xd2\xc0 x3! +$",0
textSkullsLose db "\xcc\xc8\xcc\xce! \xd8\xc0\xd0 \xc1\xdb\xcb \xc2 \xc4\xd0\xd3\xc3\xce\xcc \xcc\xc5\xd1\xd2\xc5!",0
textSkullsAgain db "[\xcf\xd0\xce\xc1\xc5\xcb] - \xd1\xdb\xc3\xd0\xc0\xd2\xdc \xc5\xd9\xa8 \xd0\xc0\xc7",0
textSkullsKey1 db "1:\xca\xd3\xc1\xce\xca",0
textSkullsKey2 db "2:\xca\xd3\xc1\xce\xca",0
textSkullsKey3 db "3:\xca\xd3\xc1\xce\xca",0
textSkullsKeySpace db "\xcf\xd0\xce\xc1\xc5\xcb",0
; --- Shared UI Strings ---
textKeyEsc db "ESC",0
textBankPrompt db "\xc1\xc0\xcd\xca: $",0
textBetPrompt db "\xd1\xd2\xc0\xc2\xca\xc0: $",0
textBetHint db " [W/S]",0
"""
raw_content = raw_content[:pos_coin_table] + new_strings_text.encode('latin1') + raw_content[pos_shop_msg:]
print("[OK] Replaced string constants section with rich game strings")
# 3. Replace procedural drawing and rendering block
# Find start of '; IN-ENGINE 2.5D MINI-GAME: COIN FLIP' and end before 'HandlePlayerInput PROC'
pos_games_start = raw_content.find(b'; IN-ENGINE 2.5D MINI-GAME: COIN FLIP')
pos_player_input = raw_content.find(b'HandlePlayerInput PROC')
assert pos_games_start != -1 and pos_player_input != -1, "Could not locate games procedures section"
new_games_code = r"""; ==============================================================================
; SHARED RICH UI PROCEDURES
; ==============================================================================
DrawKeycap3D PROC uses ebx esi edi, x:DWORD, y:DWORD, strPtr:DWORD, isActive:DWORD
LOCAL capW:DWORD
; Compute string length
mov esi, strPtr
xor ecx, ecx
@@:
mov al, [esi+ecx]
test al, al
jz @F
inc ecx
jmp @B
@@:
shl ecx, 3 ; length * 8
add ecx, 8 ; padding 8px
mov capW, ecx
; Drop shadow
mov eax, x
mov edx, y
add edx, 2
invoke DrawBox, eax, edx, capW, 13, 0008080Ch
; 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
ret
DrawKeycap3D ENDP
DrawChipStack PROC uses ebx esi edi, x:DWORD, y:DWORD, chipCount:DWORD
xor esi, esi
chip_loop:
cmp esi, chipCount
jge chip_done
mov eax, esi
shl eax, 2 ; esi * 4
mov edx, y
sub edx, eax ; cy = y - esi*4
; Shadow
mov eax, x
add eax, 2
mov ecx, edx
add ecx, 5
invoke DrawBox, eax, ecx, 20, 2, 00041006h
; Chip body
invoke DrawBoxBorder, x, edx, 24, 6, 001515B8h, 00FFFFFFh, 1
; White stripe inlays
mov eax, x
add eax, 4
mov ecx, edx
add ecx, 1
invoke DrawBox, eax, ecx, 3, 4, 00FFFFFFh
mov eax, x
add eax, 17
invoke DrawBox, eax, ecx, 3, 4, 00FFFFFFh
inc esi
jmp chip_loop
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
mov eax, rxVal
imul eax, eax
mov rxSq, eax
mov eax, ryVal
imul eax, eax
mov rySq, eax
mov eax, rxSq
imul eax, rySq
mov rxRySq, eax
mov eax, rxRySq
shr eax, 2
imul eax, 3
mov threshSq, eax
mov eax, ryVal
neg eax
mov curDY, eax
coin_y_loop:
mov eax, curDY
cmp eax, ryVal
jg check_coin_relief
mov eax, rxVal
neg eax
mov curDX, eax
coin_x_loop:
mov eax, curDX
cmp eax, rxVal
jg next_coin_y
mov eax, curDX
imul eax, eax
imul eax, rySq
mov ebx, curDY
imul ebx, ebx
imul ebx, rxSq
add eax, ebx
cmp eax, rxRySq
jg next_coin_x
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
next_coin_x:
inc curDX
jmp coin_x_loop
next_coin_y:
inc curDY
jmp coin_y_loop
check_coin_relief:
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
draw_eagle_relief:
; Crown
mov eax, cxVal
sub eax, 3
mov edx, cyVal
sub edx, 14
invoke DrawBox, eax, edx, 7, 2, 00007A9Ah
mov eax, cxVal
sub eax, 4
mov edx, cyVal
sub edx, 12
invoke DrawBox, eax, edx, 9, 2, 00007A9Ah
; Body & Head
mov eax, cxVal
sub eax, 2
mov edx, cyVal
sub edx, 9
invoke DrawBox, eax, edx, 5, 12, 00007A9Ah
mov eax, cxVal
dec eax
mov edx, cyVal
sub edx, 8
invoke DrawBox, eax, edx, 3, 10, 0000D7FFh
; Wings
mov eax, cxVal
sub eax, 10
mov edx, cyVal
sub edx, 8
invoke DrawBox, eax, edx, 7, 3, 00007A9Ah
mov eax, cxVal
sub eax, 13
mov edx, cyVal
sub edx, 5
invoke DrawBox, eax, edx, 10, 3, 00007A9Ah
mov eax, cxVal
sub eax, 11
mov edx, cyVal
sub edx, 2
invoke DrawBox, eax, edx, 7, 3, 00007A9Ah
mov eax, cxVal
add eax, 4
mov edx, cyVal
sub edx, 8
invoke DrawBox, eax, edx, 7, 3, 00007A9Ah
mov eax, cxVal
add eax, 4
mov edx, cyVal
sub edx, 5
invoke DrawBox, eax, edx, 10, 3, 00007A9Ah
mov eax, cxVal
add eax, 5
mov edx, cyVal
sub edx, 2
invoke DrawBox, eax, edx, 7, 3, 00007A9Ah
; Tail
mov eax, cxVal
sub eax, 4
mov edx, cyVal
add edx, 4
invoke DrawBox, eax, edx, 9, 3, 00007A9Ah
mov eax, cxVal
sub eax, 3
mov edx, cyVal
add edx, 7
invoke DrawBox, eax, edx, 7, 3, 00007A9Ah
jmp coin_draw_ret
draw_wreath_relief:
; Roman numeral 'I'
mov eax, cxVal
sub eax, 5
mov edx, cyVal
sub edx, 10
invoke DrawBox, eax, edx, 11, 3, 00007A9Ah
mov eax, cxVal
sub eax, 2
mov edx, cyVal
sub edx, 7
invoke DrawBox, eax, edx, 5, 14, 00007A9Ah
mov eax, cxVal
dec eax
mov edx, cyVal
sub edx, 6
invoke DrawBox, eax, edx, 3, 12, 0000D7FFh
mov eax, cxVal
sub eax, 6
mov edx, cyVal
add edx, 7
invoke DrawBox, eax, edx, 13, 3, 00007A9Ah
; Laurel dots left & right
mov eax, cxVal
sub eax, 12
mov edx, cyVal
sub edx, 10
invoke DrawBox, eax, edx, 2, 2, 00007A9Ah
mov eax, cxVal
add eax, 11
mov edx, cyVal
sub edx, 10
invoke DrawBox, eax, edx, 2, 2, 00007A9Ah
mov eax, cxVal
sub eax, 12
mov edx, cyVal
sub edx, 5
invoke DrawBox, eax, edx, 2, 2, 00007A9Ah
mov eax, cxVal
add eax, 11
mov edx, cyVal
sub edx, 5
invoke DrawBox, eax, edx, 2, 2, 00007A9Ah
mov eax, cxVal
sub eax, 12
mov edx, cyVal
invoke DrawBox, eax, edx, 2, 2, 00007A9Ah
mov eax, cxVal
add eax, 11
mov edx, cyVal
invoke DrawBox, eax, edx, 2, 2, 00007A9Ah
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:
ret
DrawDetailedCoin ENDP
InitCoinGame PROC
mov coin3d_state, 0
mov coin3d_timer, 0
mov coin3d_win, 0
cmp coin3d_bet, 10
jge @F
mov coin3d_bet, 50
@@:
ret
InitCoinGame ENDP
HandleCoinInput PROC
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:
ret
HandleCoinInput ENDP
RenderCoinGame PROC uses ebx esi edi
LOCAL cyVal:DWORD, rxVal:DWORD, curX:DWORD
; 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
@@:
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
@@:
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
; Flipping animation logic
cmp coin3d_state, 1
jne coin_at_rest
inc coin3d_timer
; 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
; 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
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
invoke RandomRange3D, 2
inc eax
mov coin3d_result, eax
mov eax, coin3d_result
cmp eax, coin3d_side
jne coin_flip_lost
; Won!
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
@@:
invoke PlaySoundA, OFFSET soundCoinDing, 0, 1
jmp coin_draw_controls
coin_flip_lost:
mov coin3d_streak, 0
mov coin3d_win, 0
invoke PlaySoundA, OFFSET soundLose, 0, 1
jmp coin_draw_controls
coin_at_rest:
; Draw coin resting in velvet dish
mov edx, coin3d_side
cmp coin3d_state, 2
jne @F
mov edx, coin3d_result
@@:
invoke DrawDetailedCoin, 160, 110, 26, 26, 0000A0D0h, 0000D7FFh, edx
; Outcome / Streak Display
cmp coin3d_state, 2
jne coin_show_streak
cmp coin3d_win, 0
je coin_show_lose
invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 0050FF50h, 1
invoke DrawString8x8, 64, 160, OFFSET textCoinWin, 0050FF50h
invoke FormatNumber, coin3d_win, OFFSET hudNumBuffer
invoke DrawString8x8, 152, 160, OFFSET hudNumBuffer, 0050FF50h
jmp coin_draw_controls
coin_show_lose:
invoke DrawBoxBorder, 44, 154, 232, 20, 000E141Eh, 000000FFh, 1
invoke DrawString8x8, 114, 160, OFFSET textCoinLose, 008080FFh
jmp coin_draw_controls
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
sete al
invoke DrawKeycap3D, 22, 202, OFFSET textCoinKey1, eax
mov eax, 0
cmp coin3d_side, 2
sete al
invoke DrawKeycap3D, 88, 202, OFFSET textCoinKey2, eax
invoke DrawKeycap3D, 160, 202, OFFSET textCoinKeySpace, 1
invoke DrawKeycap3D, 274, 202, OFFSET textKeyEsc, 0
ret
RenderCoinGame ENDP
; ==============================================================================
; IN-ENGINE 2.5D MINI-GAME: DICE / CRAPS (КОСТИ)
; ==============================================================================
DrawCrapsDie PROC uses ebx esi edi, x:DWORD, y:DWORD, sizeVal:DWORD, valNum:DWORD
; Drop shadow on green felt
mov eax, x
add eax, 3
mov edx, y
add edx, sizeVal
invoke DrawBox, eax, edx, sizeVal, 3, 00031408h
mov eax, x
add eax, sizeVal
mov edx, y
add edx, 3
invoke DrawBox, eax, edx, 3, sizeVal, 00031408h
; 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
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
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
; 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:
mov eax, x
add eax, 18
mov edx, y
add edx, 18
invoke DrawCircle, eax, edx, 3, 001515C8h
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
mov eax, x
add eax, sizeVal
sub eax, 10
mov edx, y
add edx, sizeVal
sub edx, 10
invoke DrawCircle, eax, edx, 3, 001515C8h
cmp valNum, 4
jl die_pips_done
mov eax, x
add eax, sizeVal
sub eax, 10
mov edx, y
add edx, 9
invoke DrawCircle, eax, edx, 3, 001515C8h
mov eax, x
add eax, 9
mov edx, y
add edx, sizeVal
sub edx, 10
invoke DrawCircle, eax, edx, 3, 001515C8h
cmp valNum, 6
jl die_pips_done
mov eax, x
add eax, 9
mov edx, y
add edx, 18
invoke DrawCircle, eax, edx, 3, 001515C8h
mov eax, x
add eax, sizeVal
sub eax, 10
mov edx, y
add edx, 18
invoke DrawCircle, eax, edx, 3, 001515C8h
die_pips_done:
ret
DrawCrapsDie ENDP
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, 1
je dice_input_done
invoke Pressed3D, 20h ; SPACE -> Roll!
test eax, eax
jz check_dice_choice
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
invoke PlaySoundA, OFFSET soundClick, 0, 1
jmp dice_input_done
check_dice_choice:
invoke Pressed3D, 31h ; '1'
test eax, eax
jz @F
mov dice3d_choice, 1
invoke PlaySoundA, OFFSET soundClick, 0, 1
@@:
invoke Pressed3D, 32h ; '2'
test eax, eax
jz check_dice_bet_adjust
mov dice3d_choice, 2
invoke PlaySoundA, OFFSET soundClick, 0, 1
check_dice_bet_adjust:
invoke Pressed3D, 26h ; UP
test eax, eax
jnz dice_inc_bet
invoke Pressed3D, 57h ; W
test eax, eax
jz check_dice_bet_down
dice_inc_bet:
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:
ret
HandleDiceInput ENDP
RenderDiceGame PROC uses ebx esi edi
LOCAL d1X:DWORD, d1Y:DWORD, d2X:DWORD, d2Y:DWORD, bxX: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
; 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
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
invoke FormatNumber, bankroll, OFFSET hudNumBuffer
invoke DrawString8x8, 68, 50, OFFSET hudNumBuffer, 0050FF50h
invoke DrawBoxBorder, 196, 46, 108, 16, 0006240Eh, 000E5022h, 1
invoke DrawString8x8, 200, 50, OFFSET textBetPrompt, 0000D7FFh
invoke FormatNumber, dice3d_bet, OFFSET hudNumBuffer
invoke DrawString8x8, 264, 50, OFFSET hudNumBuffer, 0000D7FFh
; Betting Zone Left: [1] ЧЁТ
mov eax, 00073014h
mov edx, 001A602Ah
mov ecx, 0080B090h
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
@@:
; Betting Zone Right: [2] НЕЧЕТ
mov eax, 00073014h
mov edx, 001A602Ah
mov ecx, 0080B090h
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
@@:
; Center Dice Field
invoke DrawBoxBorder, 112, 68, 96, 54, 00072E13h, 00145826h, 1
; 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
cmp dice3d_state, 2
jne dice_draw_controls
; Scoreboard Plaque
invoke DrawBoxBorder, 36, 130, 248, 30, 00051D0Ch, 0000D7FFh, 1
invoke DrawString8x8, 44, 135, OFFSET textDiceSumHdr, 0000D7FFh
invoke FormatNumber, dice3d_val1, OFFSET hudNumBuffer
invoke DrawString8x8, 100, 135, OFFSET hudNumBuffer, 00FFFFFFh
invoke DrawString8x8, 110, 135, OFFSET textDicePlus, 0000D7FFh
invoke FormatNumber, dice3d_val2, OFFSET hudNumBuffer
invoke DrawString8x8, 134, 135, OFFSET hudNumBuffer, 00FFFFFFh
invoke DrawString8x8, 144, 135, OFFSET textDiceEqual, 0000D7FFh
invoke FormatNumber, dice3d_sum, OFFSET hudNumBuffer
invoke DrawString8x8, 168, 135, OFFSET hudNumBuffer, 0000FFFFh
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
dice_show_win_msg:
cmp dice3d_win, 0
je dice_show_loss
invoke DrawString8x8, 68, 147, OFFSET textDiceWin, 0050FF50h
invoke FormatNumber, dice3d_win, OFFSET hudNumBuffer
invoke DrawString8x8, 156, 147, OFFSET hudNumBuffer, 0050FF50h
invoke DrawString8x8, 188, 147, OFFSET textDiceWinMult, 0050FF50h
jmp dice_draw_controls
dice_show_loss:
invoke DrawString8x8, 116, 147, OFFSET textDiceLose, 008080FFh
dice_draw_controls:
invoke DrawBox, 16, 188, 288, 1, 00104820h
mov eax, 0
cmp dice3d_choice, 1
sete al
invoke DrawKeycap3D, 20, 198, OFFSET textDiceKey1, eax
mov eax, 0
cmp dice3d_choice, 2
sete al
invoke DrawKeycap3D, 82, 198, OFFSET textDiceKey2, eax
invoke DrawKeycap3D, 160, 198, OFFSET textDiceKeySpace, 1
invoke DrawKeycap3D, 274, 198, OFFSET textKeyEsc, 0
ret
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
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 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
mov eax, y
cmp isLifted, 0
je @F
sub eax, 28
@@:
mov liftY, eax
; Drop shadow on purple velvet
cmp isLifted, 0
jne @F
mov eax, x
add eax, 6
mov edx, y
add edx, 42
invoke DrawBox, eax, edx, 36, 4, 000A0410h
jmp draw_cup_body
@@:
mov eax, x
add eax, 10
mov edx, y
add edx, 42
invoke DrawBox, eax, edx, 28, 2, 0012061Ah
; Draw orb if lifted and has ball
cmp hasBall, 0
je draw_cup_body
mov eax, x
add eax, 24
mov edx, y
add edx, 26
invoke DrawGlowingOrb, eax, edx
draw_cup_body:
; Base
mov eax, x
add eax, 6
mov edx, liftY
add edx, 36
invoke DrawBoxBorder, eax, edx, 36, 6, 00221A30h, 0000B0D0h, 1
; Stem
mov eax, x
add eax, 18
mov edx, liftY
add edx, 28
invoke DrawBox, eax, edx, 12, 8, 00332545h
mov eax, x
add eax, 22
mov edx, liftY
add edx, 28
invoke DrawBox, eax, edx, 4, 8, 0055406Eh
; Bowl
mov eax, x
add eax, 8
mov edx, liftY
add edx, 8
invoke DrawBoxBorder, eax, edx, 32, 20, 002D1E40h, 0000D7FFh, 1
mov eax, x
add eax, 14
mov edx, liftY
add edx, 10
invoke DrawBox, eax, edx, 6, 16, 00503570h
mov eax, x
add eax, 17
mov edx, liftY
add edx, 10
invoke DrawBox, eax, edx, 3, 16, 007850A0h
; Flared Rim
mov eax, x
add eax, 4
mov edx, liftY
add edx, 2
invoke DrawBoxBorder, eax, edx, 40, 7, 00150A20h, 0000FFFFh, 1
mov eax, x
add eax, 12
mov edx, liftY
add edx, 4
invoke DrawBox, eax, edx, 16, 2, 0000FFFFh
; Skull Insignia on Bowl
mov eax, x
add eax, 21
mov edx, liftY
add edx, 12
invoke DrawBox, eax, edx, 6, 5, 0000D7FFh
mov eax, x
add eax, 22
mov edx, liftY
add edx, 17
invoke DrawBox, eax, edx, 4, 3, 0000D7FFh
mov eax, x
add eax, 22
mov edx, liftY
add edx, 14
invoke DrawPixel, eax, edx, 00150A20h
mov eax, x
add eax, 24
mov edx, liftY
add edx, 14
invoke DrawPixel, eax, edx, 00150A20h
; Cup ID Badge
mov eax, x
add eax, 21
mov edx, liftY
add edx, 24
mov ecx, cupId
add ecx, '0'
invoke DrawChar8x8, eax, edx, ecx, 0000FFFFh
ret
DrawGothicCup ENDP
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
ret
InitSkullsGame ENDP
FinalizeSkullsGuess PROC uses ebx
mov skulls3d_state, 4
mov eax, skulls3d_choice
cmp eax, skulls3d_ballPos
jne skulls_guess_lost
; Won 3x!
mov eax, skulls3d_bet
imul eax, 3
mov skulls3d_win, eax
add bankroll, eax
invoke PlaySoundA, OFFSET soundVictory, 0, 1
ret
skulls_guess_lost:
mov skulls3d_win, 0
invoke PlaySoundA, OFFSET soundLose, 0, 1
ret
FinalizeSkullsGuess ENDP
HandleSkullsInput PROC
cmp skulls3d_state, 1
je skulls_input_done
cmp skulls3d_state, 2
je skulls_input_done
cmp skulls3d_state, 3
je check_skulls_pick
; State 0 or 4: Can start new round or adjust bet
invoke Pressed3D, 20h ; SPACE
test eax, eax
jz check_skulls_bet_adjust
mov eax, bankroll
cmp eax, skulls3d_bet
jl skulls_no_cash
sub eax, skulls3d_bet
mov 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
invoke PlaySoundA, OFFSET soundShuffle, 0, 1
jmp skulls_input_done
skulls_no_cash:
invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage
mov flashTimer, 60
invoke PlaySoundA, OFFSET soundClick, 0, 1
jmp skulls_input_done
check_skulls_pick:
invoke Pressed3D, 31h ; '1'
test eax, eax
jz @F
mov skulls3d_choice, 0
call FinalizeSkullsGuess
jmp skulls_input_done
@@:
invoke Pressed3D, 32h ; '2'
test eax, eax
jz @F
mov skulls3d_choice, 1
call FinalizeSkullsGuess
jmp skulls_input_done
@@:
invoke Pressed3D, 33h ; '3'
test eax, eax
jz skulls_input_done
mov skulls3d_choice, 2
call FinalizeSkullsGuess
jmp skulls_input_done
check_skulls_bet_adjust:
invoke Pressed3D, 26h ; UP
test eax, eax
jnz skulls_inc_bet
invoke Pressed3D, 57h ; W
test eax, eax
jz check_skulls_bet_down
skulls_inc_bet:
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:
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
; 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
; Header
invoke DrawBoxBorder, 24, 12, 272, 24, 0012081Ah, 0000D7FFh, 2
invoke DrawString8x8, 64, 20, OFFSET textSkullsTitle, 0000FFFFh
; Meters: Bank & Bet
invoke DrawBoxBorder, 20, 42, 114, 16, 000D0616h, 00401858h, 1
invoke DrawString8x8, 24, 46, OFFSET textBankPrompt, 0050FF50h
invoke FormatNumber, bankroll, OFFSET hudNumBuffer
invoke DrawString8x8, 72, 46, OFFSET hudNumBuffer, 0050FF50h
invoke DrawBoxBorder, 186, 42, 114, 16, 000D0616h, 00401858h, 1
invoke DrawString8x8, 190, 46, OFFSET textBetPrompt, 0000D7FFh
invoke FormatNumber, skulls3d_bet, OFFSET hudNumBuffer
invoke DrawString8x8, 254, 46, OFFSET hudNumBuffer, 0000D7FFh
; Velvet Table Runner
invoke DrawBoxBorder, 16, 64, 288, 120, 001A0B25h, 00452060h, 1
; Dispatch based on phase
cmp skulls3d_state, 1
je skulls_render_phase1
cmp skulls3d_state, 2
je skulls_render_phase2
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
invoke FormatNumber, skulls3d_win, OFFSET hudNumBuffer
invoke DrawString8x8, 216, 70, OFFSET hudNumBuffer, 0050FF50h
jmp skulls_p4_cups
skulls_show_loss:
invoke DrawString8x8, 40, 70, OFFSET textSkullsLose, 008080FFh
skulls_p4_cups:
; Draw chosen cup lifted
mov eax, 0
cmp skulls3d_choice, 0
sete al
mov edx, 0
cmp skulls3d_ballPos, 0
sete dl
invoke DrawGothicCup, 48, 108, 1, eax, edx
mov eax, 0
cmp skulls3d_choice, 1
sete al
mov edx, 0
cmp skulls3d_ballPos, 1
sete dl
invoke DrawGothicCup, 136, 108, 2, eax, edx
mov eax, 0
cmp skulls3d_choice, 2
sete al
mov edx, 0
cmp skulls3d_ballPos, 2
sete dl
invoke DrawGothicCup, 224, 108, 3, eax, edx
invoke DrawString8x8, 64, 168, OFFSET textSkullsAgain, 0000D7FFh
skulls_draw_controls:
invoke DrawBox, 16, 190, 288, 1, 003A1850h
mov eax, 0
cmp skulls3d_choice, 0
sete al
invoke DrawKeycap3D, 18, 200, OFFSET textSkullsKey1, eax
mov eax, 0
cmp skulls3d_choice, 1
sete al
invoke DrawKeycap3D, 82, 200, OFFSET textSkullsKey2, eax
mov eax, 0
cmp skulls3d_choice, 2
sete al
invoke DrawKeycap3D, 146, 200, OFFSET textSkullsKey3, eax
invoke DrawKeycap3D, 212, 200, OFFSET textSkullsKeySpace, 1
invoke DrawKeycap3D, 274, 200, OFFSET textKeyEsc, 0
ret
RenderSkullsGame 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")
# Write out patched 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)}")