KAZIK/tools/generators/generate_rich_minigames.py
Игорь Федосеев b1cd66b322 fix(ui,audio): eliminate cyan color bug, restore authentic IBM VGA Cyrillic font, implement native 2.5D Skill Check
- 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
2026-09-30 21:17:07 +03:00

2016 lines
51 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,
fixed audio, authentic palette (00RRGGBBh Little-Endian DIB), and native 2.5D minigames:
- Coin Flip (Монетка)
- Grand Craps / Dice (Кости)
- Gothic Skulls & Cups (Напёрстки)
- Dead by Daylight Skill Check (Проверка реакции)
"""
import shutil
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
CASINO_INC = REPO_ROOT / 'casino3d.inc'
BACKUP_INC = REPO_ROOT / 'backups' / 'casino3d_before_full_fix.inc'
# 1. Back up casino3d.inc
BACKUP_INC.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(CASINO_INC, BACKUP_INC)
print(f"[OK] Backed up casino3d.inc to {BACKUP_INC}")
with open(CASINO_INC, 'rb') as f:
raw_content = f.read()
# 2. Add MODE_SKILL equ 9
if b'MODE_SKILL equ 9' not in raw_content:
raw_content = raw_content.replace(
b'MODE_SKULLS equ 8',
b'MODE_SKULLS equ 8\r\nMODE_SKILL equ 9'
)
print("[OK] Added MODE_SKILL equ 9")
# 3. Audio block replacement
old_audio = (
b'soundClick db "assets\\audio\\b05e1ac8be34248.wav",0'
)
if old_audio in raw_content:
new_audio = (
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'
)
raw_content = raw_content.replace(old_audio, new_audio)
print("[OK] Replaced audio definitions")
# 4. Strings and variables section replacement
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 = """coinRxAnimTable db 26, 22, 16, 6, 16, 22, 26, 22, 16, 6
; --- Native 2.5D Coin Flip ---
coin3d_bet dd 50
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
textCoinTitle db "* * * З О Л О Т А Я М О Н Е Т А * * *",0
textCoinHeads db "ОРЁЛ",0
textCoinTails db "РЕШКА",0
textCoinSide1 db "[1] ОРЁЛ",0
textCoinSide2 db "[2] РЕШКА",0
textCoinFlipping db "МОНЕТА В ПОЛЁТЕ...",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
dice3d_choice dd 1 ; 1 = Чёт, 2 = Нечет
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
textDiceEven db "[1] ЧЁТ",0
textDiceOdd db "[2] НЕЧЕТ",0
textDiceEvenNums db "2 4 6 8 10 12",0
textDiceOddNums db "3 5 7 9 11",0
textDiceSumHdr db "СУММА: ",0
textDicePlus db " + ",0
textDiceEqual db " = ",0
textDiceEvenResult db " (ЧЁТ)",0
textDiceOddResult db " (НЕЧЕТ)",0
textDiceRolling db "КОСТИ ЛЕТЯТ ПО СУКНУ...",0
textDiceWin db "ВЫИГРЫШ: +$",0
textDiceWinMult db "! (x2)",0
textDiceLose db "ПРОИГРЫШ!",0
textDiceKey1 db "[1] ЧЁТ",0
textDiceKey2 db "[2] НЕЧЕТ",0
textDiceKeySpace db "[SPACE] БРОСОК",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 "* * * Н А П Ё Р С Т К И : Ч Е Р Е П А * * *",0
textSkullsPhase0 db "ДЕЛАЙ СТАВКУ И ЖМИ [ПРОБЕЛ]",0
textSkullsPhase1 db "СМОТРИ, ГДЕ ЗОЛОТОЙ ШАР...",0
textSkullsPhase2 db "КРУЧУ, ВЕРЧУ, ЗАПУТАТЬ ХОЧУ...",0
textSkullsPhase3 db "ГДЕ ШАР? ВЫБИРАЙ: [1], [2] ИЛИ [3]!",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 "[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
textBankPrompt db "БАНК: $",0
textBetPrompt db "СТАВКА: $",0
textBetHint db " [W/S]",0
"""
raw_content = raw_content[:pos_coin_table] + new_strings.encode('cp1251') + raw_content[pos_shop_msg:]
print("[OK] Replaced strings and variables")
# 5. Replace minigame procedural drawing & game logic
pos_games_start = raw_content.find(b'; ==============================================================================\r\n; SHARED RICH UI PROCEDURES')
if pos_games_start == -1:
pos_games_start = raw_content.find(b'; SHARED RICH UI PROCEDURES')
if pos_games_start == -1:
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 keyW:DWORD
mov esi, strPtr
xor ecx, ecx
keycap_len:
mov al, [esi+ecx]
test al, al
jz keycap_len_done
inc 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, 3
invoke DrawString8x8, eax, edx, strPtr, ebx
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, edi
jge chip_done
mov eax, esi
shl eax, 2
mov edx, y
sub edx, eax
; Shadow
mov eax, x
add eax, 2
mov ecx, edx
add ecx, 5
invoke DrawBox, eax, ecx, 20, 2, 00061004h
; Red Clay Chip body with white rim
invoke DrawBoxBorder, x, edx, 24, 6, 00B81515h, 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
mov ecx, edx
add ecx, 1
invoke DrawBox, eax, ecx, 3, 4, 00FFFFFFh
inc esi
jmp chip_loop
chip_done:
ret
DrawChipStack ENDP
DrawDetailedCoin PROC uses ebx esi edi, cxVal:DWORD, cyVal:DWORD, rxVal:DWORD, ryVal:DWORD, outerColor:DWORD, innerColor:DWORD, reliefType:DWORD
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
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, ryVal
mov rySq, eax
imul eax, rxSq
mov rxRySq, eax
; 3/4 threshold for rim bevel
mov ecx, 3
imul eax, ecx
shr eax, 2
mov threshSq, eax
; Scan rows
mov eax, ryVal
neg eax
mov curDy, eax
coin_row_loop:
mov eax, curDy
cmp eax, ryVal
jg coin_relief_check
mov edx, cyVal
add edx, curDy
mov curY, edx
; Scan columns
mov eax, rxVal
neg eax
mov curDx, eax
coin_col_loop:
mov eax, curDx
cmp eax, rxVal
jg coin_col_next_row
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, eax
mov eax, curDy
imul eax, curDy
imul eax, rxSq
add eax, ebx
cmp eax, rxRySq
ja coin_pixel_outside
cmp eax, threshSq
jb coin_draw_inner
invoke DrawPixel, curX, curY, outerColor
jmp coin_pixel_outside
coin_draw_inner:
invoke DrawPixel, curX, curY, innerColor
coin_pixel_outside:
inc curDx
jmp coin_col_loop
coin_col_next_row:
inc curDy
jmp coin_row_loop
coin_relief_check:
cmp rxVal, 14
jl coin_draw_done
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, 009A7A00h
mov eax, cxVal
sub eax, 4
mov edx, cyVal
sub edx, 12
invoke DrawBox, eax, edx, 9, 2, 009A7A00h
mov eax, cxVal
sub eax, 2
mov edx, cyVal
sub edx, 9
invoke DrawBox, eax, edx, 5, 12, 009A7A00h
mov eax, cxVal
sub eax, 1
mov edx, cyVal
sub edx, 8
invoke DrawBox, eax, edx, 3, 10, 00FFD700h
mov eax, cxVal
sub eax, 10
mov edx, cyVal
sub edx, 8
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, 009A7A00h
mov eax, cxVal
sub eax, 11
mov edx, cyVal
sub edx, 2
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, 009A7A00h
mov eax, cxVal
add eax, 4
mov edx, cyVal
sub edx, 5
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, 009A7A00h
mov eax, cxVal
sub eax, 4
mov edx, cyVal
add edx, 4
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, 009A7A00h
jmp coin_draw_done
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, 009A7A00h
mov eax, cxVal
sub eax, 2
mov edx, cyVal
sub edx, 7
invoke DrawBox, eax, edx, 5, 14, 009A7A00h
mov eax, cxVal
sub eax, 1
mov edx, cyVal
sub edx, 6
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, 009A7A00h
; Laurel dots
mov eax, cxVal
sub eax, 12
mov edx, cyVal
sub edx, 8
invoke DrawBox, eax, edx, 2, 2, 009A7A00h
mov eax, cxVal
add eax, 11
mov edx, cyVal
sub edx, 8
invoke DrawBox, eax, edx, 2, 2, 009A7A00h
mov eax, cxVal
sub eax, 12
mov edx, cyVal
invoke DrawBox, eax, edx, 2, 2, 009A7A00h
mov eax, cxVal
add eax, 11
mov edx, cyVal
invoke DrawBox, eax, edx, 2, 2, 009A7A00h
mov eax, cxVal
sub eax, 12
mov edx, cyVal
add edx, 8
invoke DrawBox, eax, edx, 2, 2, 009A7A00h
mov eax, cxVal
add eax, 11
mov edx, cyVal
add edx, 8
invoke DrawBox, eax, edx, 2, 2, 009A7A00h
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
ret
InitCoinGame ENDP
HandleCoinInput PROC
cmp coin3d_state, 0
je coin_handle_idle
cmp coin3d_state, 1
je coin_handle_flipping
cmp coin3d_state, 2
je coin_handle_result
ret
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
coin_bet_up:
mov eax, coin3d_bet
add eax, 50
cmp eax, bankroll
jle @F
mov eax, bankroll
@@:
cmp eax, 5000
jle @F
mov eax, 5000
@@:
mov coin3d_bet, eax
invoke PlaySoundA, OFFSET soundClick, 0, 1
ret
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
coin_pick_1:
mov coin3d_choice, 1
invoke PlaySoundA, OFFSET soundClick, 0, 1
ret
coin_pick_2:
mov coin3d_choice, 2
invoke PlaySoundA, OFFSET soundClick, 0, 1
ret
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
coin_handle_flipping:
dec coin3d_timer
cmp coin3d_timer, 0
jg coin_done
invoke RandomRange3D, 2
inc eax
mov coin3d_result, eax
mov edx, coin3d_choice
cmp eax, edx
jne coin_flip_lost
; Won!
inc coin3d_streak
mov eax, coin3d_bet
shl eax, 1
add bankroll, eax
mov coin3d_win, eax
mov coin3d_state, 2
invoke PlaySoundA, OFFSET soundCoinDing, 0, 1
ret
coin_flip_lost:
mov coin3d_streak, 0
mov coin3d_win, 0
mov coin3d_state, 2
invoke PlaySoundA, OFFSET soundLose, 0, 1
ret
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
je coin_render_result
; Idle coin
invoke DrawDetailedCoin, 160, 110, 26, 26, 00D0A000h, 00FFD700h, coin3d_choice
jmp coin_render_keys
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, 161, OFFSET hudNumBuffer, 003CFF3Ch
jmp coin_render_keys
coin_render_loss_msg:
invoke DrawBoxBorder, 44, 154, 232, 22, 000E141Eh, 00C81414h, 1
invoke DrawString8x8, 114, 161, OFFSET textCoinLose, 00FF6464h
coin_render_keys:
mov kx, 16
xor eax, eax
cmp coin3d_choice, 1
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textCoinKey1, eax
add kx, eax
xor eax, eax
cmp coin3d_choice, 2
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textCoinKey2, eax
add kx, eax
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: CRAPS / DICE
; ==============================================================================
DrawCrapsDie PROC uses ebx esi edi, x:DWORD, y:DWORD, sizeVal:DWORD, valNum:DWORD
; Drop shadow
mov eax, x
add eax, 3
mov edx, y
add edx, sizeVal
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, 00081403h
; Ivory body & bevel
invoke DrawBoxBorder, x, y, sizeVal, sizeVal, 00FAF4F0h, 00403535h, 1
mov eax, x
inc eax
mov edx, y
inc edx
mov ecx, sizeVal
sub ecx, 2
invoke DrawBox, eax, edx, ecx, 1, 00FFFFFFh
invoke DrawBox, eax, edx, 1, ecx, 00FFFFFFh
; 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, 00C81515h
dec eax
dec edx
invoke DrawPixel, eax, edx, 00FFFFFFh
@@:
cmp valNum, 2
jl die_pips_done
mov eax, x
add eax, 9
mov edx, y
add edx, 9
invoke DrawCircle, eax, edx, 3, 00C81515h
mov eax, x
add eax, 27
mov edx, y
add edx, 27
invoke DrawCircle, eax, edx, 3, 00C81515h
cmp valNum, 4
jl die_pips_done
mov eax, x
add eax, 27
mov edx, y
add edx, 9
invoke DrawCircle, eax, edx, 3, 00C81515h
mov eax, x
add eax, 9
mov edx, y
add edx, 27
invoke DrawCircle, eax, edx, 3, 00C81515h
cmp valNum, 6
jl die_pips_done
mov eax, x
add eax, 9
mov edx, y
add edx, 18
invoke DrawCircle, eax, edx, 3, 00C81515h
mov eax, x
add eax, 27
mov edx, y
add edx, 18
invoke DrawCircle, eax, edx, 3, 00C81515h
die_pips_done:
ret
DrawCrapsDie ENDP
InitDiceGame PROC
mov dice3d_state, 0
mov dice3d_timer, 0
mov dice3d_win, 0
ret
InitDiceGame ENDP
HandleDiceInput PROC
cmp dice3d_state, 0
je dice_handle_idle
cmp dice3d_state, 1
je dice_handle_rolling
cmp dice3d_state, 2
je dice_handle_result
ret
dice_handle_idle:
invoke Pressed3D, 26h ; UP
test eax, eax
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, 5000
jle @F
mov eax, 5000
@@:
mov dice3d_bet, eax
invoke PlaySoundA, OFFSET soundClick, 0, 1
ret
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
ret
dice_pick_2:
mov dice3d_choice, 2
invoke PlaySoundA, OFFSET soundClick, 0, 1
ret
dice_start_roll:
mov eax, dice3d_bet
cmp eax, bankroll
jle @F
mov eax, bankroll
mov dice3d_bet, eax
test eax, eax
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 dice_done
mov dice3d_state, 0
invoke PlaySoundA, OFFSET soundClick, 0, 1
dice_done:
ret
HandleDiceInput ENDP
RenderDiceGame PROC uses ebx esi edi
local kx:DWORD
; Mahogany frame & Deep Felt Green table
invoke DrawBox, 0, 0, 320, 240, 00140906h
invoke DrawBoxBorder, 6, 6, 308, 228, 000A3816h, 00FFD700h, 2
; Header
invoke DrawBoxBorder, 20, 12, 280, 26, 00072E13h, 00FFD700h, 2
invoke DrawString8x8, 48, 21, OFFSET textDiceTitle, 00FFFF00h
; Status
invoke DrawBoxBorder, 20, 44, 110, 18, 00072E13h, 001B4B22h, 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, 00072E13h, 001B4B22h, 1
invoke DrawString8x8, 194, 49, OFFSET textBetPrompt, 00FFD700h
invoke FormatNumber, dice3d_bet, OFFSET hudNumBuffer
invoke DrawString8x8, 254, 49, OFFSET hudNumBuffer, 00FFD700h
; [1] ЧЁТ
cmp dice3d_choice, 1
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
dice_odd_side:
; [2] НЕЧЕТ
cmp dice3d_choice, 2
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
dice_center_cubes:
; 2 Dice in center
invoke DrawCrapsDie, 116, 76, 36, dice3d_val1
invoke DrawCrapsDie, 168, 76, 36, dice3d_val2
cmp dice3d_state, 1
je dice_render_rolling
cmp dice3d_state, 2
je dice_render_result
jmp dice_render_keys
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, 92, 135, OFFSET hudNumBuffer, 00FFFF00h
invoke DrawString8x8, 110, 135, OFFSET textDicePlus, 00FFD700h
invoke FormatNumber, dice3d_val2, OFFSET hudNumBuffer
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, 00FFFF00h
mov eax, dice3d_sum
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_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, 150, OFFSET hudNumBuffer, 003CFF3Ch
invoke DrawString8x8, 188, 150, OFFSET textDiceWinMult, 003CFF3Ch
jmp dice_render_keys
dice_render_loss_outcome:
invoke DrawString8x8, 116, 150, OFFSET textDiceLose, 00FF6464h
dice_render_keys:
mov kx, 16
xor eax, eax
cmp dice3d_choice, 1
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textDiceKey1, eax
add kx, eax
xor eax, eax
cmp dice3d_choice, 2
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textDiceKey2, eax
add kx, eax
invoke DrawKeycap3D, kx, 192, OFFSET textDiceKeySpace, 1
add kx, eax
invoke DrawKeycap3D, kx, 192, 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, 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, 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
mov eax, y
cmp isLifted, 0
je @F
sub eax, 36
@@:
mov liftY, eax
; Drop shadow
cmp isLifted, 0
jne cup_shadow_lifted
mov eax, x
add eax, 6
mov edx, y
add edx, 42
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, 001A0612h
cup_ball_check:
cmp isLifted, 0
je cup_body_draw
cmp hasBall, 0
je cup_body_draw
mov eax, x
add eax, 24
mov edx, y
add edx, 26
invoke DrawGlowingOrb, eax, edx
cup_body_draw:
; Base pedestal
mov eax, x
add eax, 6
mov edx, liftY
add edx, 36
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, 00452533h
mov eax, x
add eax, 22
invoke DrawBox, eax, edx, 4, 8, 006E4055h
; Goblet Bowl
mov eax, x
add eax, 8
mov edx, liftY
add edx, 8
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, 00703550h
mov eax, x
add eax, 17
invoke DrawBox, eax, edx, 3, 16, 00A05078h
; Golden Rim
mov eax, x
add eax, 4
mov edx, liftY
add edx, 2
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, 00FFFF00h
; Skull face emblem
mov eax, x
add eax, 21
mov edx, liftY
add edx, 12
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, 00FFD700h
mov eax, x
add eax, 22
mov edx, liftY
add edx, 14
invoke DrawPixel, eax, edx, 00200A15h
mov eax, x
add eax, 24
invoke DrawPixel, eax, edx, 00200A15h
; Cup number label
mov eax, x
add eax, 21
mov edx, liftY
add edx, 24
mov ecx, cupId
add ecx, '1'
invoke DrawChar8x8, eax, edx, ecx, 00FFFF00h
ret
DrawGothicCup ENDP
InitSkullsGame PROC
mov skulls3d_state, 0
mov skulls3d_timer, 0
mov skulls3d_win, 0
invoke RandomRange3D, 3
mov skulls3d_ballPos, eax
mov skulls3d_choice, 1
ret
InitSkullsGame ENDP
FinalizeSkullsGuess PROC uses ebx
mov eax, skulls3d_choice
cmp eax, skulls3d_ballPos
jne skulls_guess_wrong
; Won! 3x payout
mov eax, skulls3d_bet
imul eax, 3
add bankroll, eax
mov skulls3d_win, eax
mov skulls3d_state, 4
invoke PlaySoundA, OFFSET soundJackpot, 0, 1
ret
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_handle_show
cmp skulls3d_state, 2
je skulls_handle_shuffle
cmp skulls3d_state, 3
je skulls_handle_pick
cmp skulls3d_state, 4
je skulls_handle_reveal
ret
skulls_handle_idle:
invoke Pressed3D, 26h ; UP
test eax, eax
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, 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
mov skulls3d_state, 1
mov skulls3d_timer, 45
invoke PlaySoundA, OFFSET soundShuffle, 0, 1
ret
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
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
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
ret
skulls_pick_2:
mov skulls3d_choice, 1
call FinalizeSkullsGuess
ret
skulls_pick_3:
mov skulls3d_choice, 2
call FinalizeSkullsGuess
ret
skulls_handle_reveal:
invoke Pressed3D, 20h
test eax, eax
jz skulls_done
mov skulls3d_state, 0
invoke PlaySoundA, OFFSET soundClick, 0, 1
skulls_done:
ret
HandleSkullsInput ENDP
RenderSkullsGame PROC uses ebx esi edi
local kx:DWORD
; Mahogany & Gothic Purple table
invoke DrawBox, 0, 0, 320, 240, 00140906h
invoke DrawBoxBorder, 6, 6, 308, 228, 00300F22h, 00FFD700h, 2
; Header
invoke DrawBoxBorder, 20, 12, 280, 26, 001A0812h, 00FFD700h, 2
invoke DrawString8x8, 40, 21, OFFSET textSkullsTitle, 00FFFF00h
; 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, 49, OFFSET hudNumBuffer, 003CFF3Ch
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, 49, OFFSET hudNumBuffer, 00FFD700h
; Subtitle phase prompts
cmp skulls3d_state, 0
jne @F
invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase0, 00FFD700h
jmp skulls_render_cups
@@:
cmp skulls3d_state, 1
jne @F
invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase1, 00FFFF00h
jmp skulls_render_cups
@@:
cmp skulls3d_state, 2
jne @F
invoke DrawString8x8, 56, 62, OFFSET textSkullsPhase2, 00FFFF00h
jmp skulls_render_cups
@@:
cmp skulls3d_state, 3
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, 136, 62, OFFSET hudNumBuffer, 003CFF3Ch
invoke DrawString8x8, 168, 62, OFFSET textSkullsWinMult, 003CFF3Ch
jmp skulls_render_cups
skulls_show_loss_text:
invoke DrawString8x8, 40, 62, OFFSET textSkullsLose, 00FF6464h
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, 36, 114, 0, ebx, edx
; 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, 114, 1, ebx, edx
; 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, 236, 114, 2, ebx, edx
; Cup selection indicators
invoke DrawString8x8, 54, 168, OFFSET textSkullsKey1, 00D0D8E0h
invoke DrawString8x8, 150, 168, OFFSET textSkullsKey2, 00D0D8E0h
invoke DrawString8x8, 250, 168, OFFSET textSkullsKey3, 00D0D8E0h
; Keycaps
mov kx, 16
xor eax, eax
cmp skulls3d_choice, 0
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey1, eax
add kx, eax
xor eax, eax
cmp skulls3d_choice, 1
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey2, eax
add kx, eax
xor eax, eax
cmp skulls3d_choice, 2
sete al
invoke DrawKeycap3D, kx, 192, OFFSET textSkullsKey3, eax
add kx, eax
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 procedural drawing and games code")
# 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 successfully patched! ({len(raw_content)} bytes)")