fix(audio,ui): eliminate gunshot sound bugs, implement rich custom 2.5D graphics for minigames, add visual test suite
This commit is contained in:
parent
50127c5a21
commit
b255493506
10 changed files with 3127 additions and 483 deletions
Binary file not shown.
1438
casino3d.inc
1438
casino3d.inc
File diff suppressed because it is too large
Load diff
BIN
docs/previews_minigames/coin_preview.png
Normal file
BIN
docs/previews_minigames/coin_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
docs/previews_minigames/dice_preview.png
Normal file
BIN
docs/previews_minigames/dice_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
BIN
docs/previews_minigames/skulls_preview.png
Normal file
BIN
docs/previews_minigames/skulls_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5 KiB |
BIN
docs/previews_minigames/test_basic.png
Normal file
BIN
docs/previews_minigames/test_basic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
poker.exe
BIN
poker.exe
Binary file not shown.
|
|
@ -43,6 +43,7 @@ Offline build tools that process raw images, generate lookup tables, and compose
|
|||
| `build_all_3d.py` | Python | Offline assembly file generator that synthesizes the complete `casino3d.inc` raycaster engine in CP1251. |
|
||||
| `generate_unified_casino3d.py` | Python | Alternative unified generator for `casino3d.inc` with full sprite definitions and game interaction hooks. |
|
||||
| `generate_casino3d.py`<br>`build_engine.py`<br>`make_casino3d.py` | Python | Lightweight orchestration scripts for triggering `casino3d.inc` regeneration in CP1251 encoding. |
|
||||
| `generate_rich_minigames.py` | Python | Patches `casino3d.inc` with rich, custom 2.5D graphics and fixed audio for Coin, Craps, and Skulls. |
|
||||
| `patch_poker_asm.py` | Python | Helper utility to patch `poker.asm` with 3D engine hooks, player save anchors, and mutex management. |
|
||||
|
||||
---
|
||||
|
|
@ -53,7 +54,9 @@ Verification scripts, simulation harnesses, and runtime helpers:
|
|||
|
||||
| Tool | Language | Purpose & Usage |
|
||||
|------|----------|-----------------|
|
||||
| `test_minigames_render.py` | Python (Pillow) | Visual simulation test suite that rasterizes 2.5D minigame UI frames and saves PNG previews to `docs/previews_minigames/`. Usage: `python tools/tests/test_minigames_render.py`. |
|
||||
| `simulate_render.py` | Python (Pillow) | Software CPU simulation of the 3D raycaster renderer. Reads `casino3d_data.inc` and texture binary, performs DDA raycasting, depth-sorting of 28 casino sprites, and saves the rendered view to `docs/render_view.png`. Usage: `python tools/tests/simulate_render.py`. |
|
||||
| `release_smoke_check.ps1` | PowerShell | Automated smoke test for release readiness: verifies file presence, launcher SHA-256 hashes, CP1251 source markers, and absence of deprecated assets. Usage: `powershell -File tools/tests/release_smoke_check.ps1`. |
|
||||
| `build_graphics.ps1` | PowerShell | Builds the Windows subsystem executable `build/graphics/poker.exe` using MASM32/MSVC toolchain. Usage: `powershell -File tools/tests/build_graphics.ps1`. |
|
||||
| `achievement_popup.bat` | Batch (CP1251) | Standalone console achievement notification popup called by `poker.exe`. Reads achievement text from `runtime/achievement.txt` and renders a decorative banner with rarity colors (COMMON, RARE, EPIC, LEGENDARY). |
|
||||
|
||||
|
|
|
|||
1790
tools/generators/generate_rich_minigames.py
Normal file
1790
tools/generators/generate_rich_minigames.py
Normal file
File diff suppressed because it is too large
Load diff
379
tools/tests/test_minigames_render.py
Normal file
379
tools/tests/test_minigames_render.py
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import math
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
OUTPUT_DIR = REPO_ROOT / 'docs' / 'previews_minigames'
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Parse font8x8.inc
|
||||
font_path = REPO_ROOT / 'font8x8.inc'
|
||||
font_bytes = bytearray(256 * 8)
|
||||
with open(font_path, 'r', encoding='latin1') as f:
|
||||
text = f.read()
|
||||
|
||||
import re
|
||||
matches = re.findall(r'0([0-9A-Fa-f]{2})h', text)
|
||||
for i, m in enumerate(matches[:256*8]):
|
||||
font_bytes[i] = int(m, 16)
|
||||
|
||||
SCREEN_W = 640
|
||||
SCREEN_H = 480
|
||||
|
||||
class RasterBuffer:
|
||||
def __init__(self):
|
||||
self.pixels = [(0, 0, 0)] * (SCREEN_W * SCREEN_H)
|
||||
|
||||
def to_rgb(self, c):
|
||||
# 0x00BBGGRR format
|
||||
r = c & 0xFF
|
||||
g = (c >> 8) & 0xFF
|
||||
b = (c >> 16) & 0xFF
|
||||
return (r, g, b)
|
||||
|
||||
def draw_box(self, x, y, w, h, color):
|
||||
px = x * 2
|
||||
py = y * 2
|
||||
pw = w * 2
|
||||
ph = h * 2
|
||||
rgb = self.to_rgb(color)
|
||||
for row in range(py, min(py + ph, SCREEN_H)):
|
||||
if row < 0:
|
||||
continue
|
||||
base = row * SCREEN_W
|
||||
for col in range(px, min(px + pw, SCREEN_W)):
|
||||
if col < 0:
|
||||
continue
|
||||
self.pixels[base + col] = rgb
|
||||
|
||||
def draw_box_border(self, x, y, w, h, fill_color, border_color, b_width):
|
||||
self.draw_box(x, y, w, h, border_color)
|
||||
self.draw_box(x + b_width, y + b_width, w - b_width * 2, h - b_width * 2, fill_color)
|
||||
|
||||
def draw_pixel(self, x, y, color):
|
||||
self.draw_box(x, y, 1, 1, color)
|
||||
|
||||
def draw_circle(self, cx, cy, radius, color):
|
||||
r_sq = radius * radius
|
||||
for dy in range(-radius, radius + 1):
|
||||
for dx in range(-radius, radius + 1):
|
||||
if dx * dx + dy * dy <= r_sq:
|
||||
self.draw_pixel(cx + dx, cy + dy, color)
|
||||
|
||||
def draw_char(self, x, y, ch, color):
|
||||
if isinstance(ch, str):
|
||||
try:
|
||||
code = ch.encode('cp1251')[0]
|
||||
except:
|
||||
code = ord(ch) & 0xFF
|
||||
else:
|
||||
code = ch & 0xFF
|
||||
|
||||
glyph_offset = code * 8
|
||||
for row in range(8):
|
||||
row_bits = font_bytes[glyph_offset + row]
|
||||
for col in range(8):
|
||||
if row_bits & (0x80 >> col):
|
||||
self.draw_pixel(x + col, y + row, color)
|
||||
|
||||
def draw_string(self, x, y, s, color):
|
||||
cur_x = x
|
||||
for ch in s:
|
||||
self.draw_char(cur_x, y, ch, color)
|
||||
cur_x += 8
|
||||
|
||||
def draw_keycap(self, x, y, text, is_active=False):
|
||||
w = len(text) * 8 + 8
|
||||
h = 13
|
||||
if is_active:
|
||||
border_c = 0x0000FFFF
|
||||
fill_c = 0x001B4B22
|
||||
txt_c = 0x0000FFFF
|
||||
else:
|
||||
border_c = 0x00606870
|
||||
fill_c = 0x001A1C22
|
||||
txt_c = 0x00D0D8E0
|
||||
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 + 4, cy + 1, 3, 4, 0x00FFFFFF)
|
||||
self.draw_box(x + 17, cy + 1, 3, 4, 0x00FFFFFF)
|
||||
|
||||
def draw_coin_ellipse(self, cx, cy, rx, ry, outer_color, inner_color, relief=0):
|
||||
if rx <= 0 or ry <= 0:
|
||||
return
|
||||
rx_sq = rx * rx
|
||||
ry_sq = ry * ry
|
||||
rx_ry_sq = rx_sq * ry_sq
|
||||
thresh_sq = (rx_ry_sq * 3) // 4
|
||||
for dy in range(-ry, ry + 1):
|
||||
cur_y = cy + dy
|
||||
for dx in range(-rx, rx + 1):
|
||||
cur_x = cx + dx
|
||||
val = dx * dx * ry_sq + dy * dy * rx_sq
|
||||
if val <= rx_ry_sq:
|
||||
if val >= thresh_sq:
|
||||
self.draw_pixel(cur_x, cur_y, outer_color)
|
||||
else:
|
||||
self.draw_pixel(cur_x, cur_y, inner_color)
|
||||
|
||||
if rx >= 14 and relief == 1:
|
||||
gold_dark = 0x00007A9A
|
||||
# Imperial Eagle
|
||||
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 - 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)
|
||||
self.draw_box(cx + 4, cy - 8, 7, 3, gold_dark)
|
||||
self.draw_box(cx + 4, cy - 5, 10, 3, gold_dark)
|
||||
self.draw_box(cx + 5, cy - 2, 7, 3, gold_dark)
|
||||
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'
|
||||
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 - 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_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_r = 3
|
||||
if val in [1, 3, 5]:
|
||||
self.draw_circle(x + size // 2, y + size // 2, pip_r, pip_c)
|
||||
self.draw_pixel(x + size // 2 - 1, y + size // 2 - 1, 0x00FFFFFF)
|
||||
if val >= 2:
|
||||
self.draw_circle(x + 9, y + 9, pip_r, pip_c)
|
||||
self.draw_circle(x + size - 10, y + size - 10, pip_r, pip_c)
|
||||
if val >= 4:
|
||||
self.draw_circle(x + size - 10, y + 9, pip_r, pip_c)
|
||||
self.draw_circle(x + 9, y + size - 10, pip_r, pip_c)
|
||||
if val == 6:
|
||||
self.draw_circle(x + 9, y + size // 2, pip_r, pip_c)
|
||||
self.draw_circle(x + size - 10, y + size // 2, pip_r, pip_c)
|
||||
|
||||
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)
|
||||
else:
|
||||
self.draw_box(x + 10, y + 42, 28, 2, 0x0012061A)
|
||||
|
||||
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(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)
|
||||
|
||||
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_pixel(cx - 2, cy - 2, 0x00FFFFFF)
|
||||
|
||||
def save(self, filename):
|
||||
img = Image.new('RGB', (SCREEN_W, SCREEN_H))
|
||||
img.putdata(self.pixels)
|
||||
out_path = OUTPUT_DIR / filename
|
||||
img.save(out_path)
|
||||
print(f"Saved {out_path}")
|
||||
|
||||
# ==============================================================================
|
||||
# 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)
|
||||
for cx in [12, 306]:
|
||||
for cy in [12, 226]:
|
||||
b.draw_box(cx, cy, 3, 3, 0x0000D7FF)
|
||||
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)
|
||||
for bx in range(24, 296, 12):
|
||||
b.draw_pixel(bx, 13, 0x0000FFFF)
|
||||
b.draw_pixel(bx, 36, 0x0000D7FF)
|
||||
|
||||
# Status meters
|
||||
b.draw_box_border(20, 44, 110, 18, 0x000A1A0E, 0x001A4B22, 1)
|
||||
b.draw_string(24, 49, 'БАНК: $12500', 0x0050FF50)
|
||||
b.draw_box_border(190, 44, 110, 18, 0x001A100A, 0x003A2814, 1)
|
||||
b.draw_string(194, 49, 'СТАВКА: $50 [W/S]', 0x0000D7FF)
|
||||
|
||||
# Center Dish
|
||||
b.draw_circle(160, 110, 46, 0x000090C0)
|
||||
b.draw_circle(160, 110, 44, 0x0000D7FF)
|
||||
b.draw_circle(160, 110, 41, 0x00180824)
|
||||
|
||||
# Coin at rest (Heads)
|
||||
b.draw_coin_ellipse(160, 110, 26, 26, 0x0000A0D0, 0x0000D7FF, relief=1)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# Streak
|
||||
b.draw_box_border(44, 154, 232, 20, 0x000E141E, 0x0000D7FF, 1)
|
||||
b.draw_string(52, 160, 'СЕРИЯ: [X] [X] [X] [ ] [ ] x4!', 0x0000FFFF)
|
||||
|
||||
# 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
|
||||
# ==============================================================================
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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')
|
||||
b.save(filename)
|
||||
|
||||
# ==============================================================================
|
||||
# 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)
|
||||
|
||||
# Header
|
||||
b.draw_box_border(24, 12, 272, 24, 0x0012081A, 0x0000D7FF, 2)
|
||||
b.draw_string(48, 20, '+ + + Н А П Ё Р С Т К И С К В Е Р Н Ы + + +', 0x0000FFFF)
|
||||
|
||||
# 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)
|
||||
|
||||
# Table Runner
|
||||
b.draw_box_border(16, 66, 288, 114, 0x001A0B25, 0x00452060, 1)
|
||||
|
||||
# Narrative banner
|
||||
b.draw_string(40, 74, 'СЛЕДИ ЗА ЗОЛОТЫМ ОКОМ СУДЬБЫ...', 0x0000FFFF)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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')
|
||||
b.save(filename)
|
||||
|
||||
if __name__ == '__main__':
|
||||
render_coin()
|
||||
render_dice()
|
||||
render_skulls()
|
||||
print("All 3 minigames previews rendered successfully!")
|
||||
Loading…
Add table
Reference in a new issue