feat: implement native darts mini-game, AI observer mode, and fortune session assets
- Darts: native 500-point match against Max with sway/fatigue mouse aim, parabolic throw camera, raster arm animations, and 16 camera-relative flying dart views - AI Observer: autonomous spectator mode for Hold'em, Blackjack, Durak, and Billiards with profile isolation and playback controls - Fortune Session: raster sprite packs, mist/orb animations, tarot divination spreads, and pack tools - Hall Integration: wall dartboard in lounge, observer terminal dispatch, and bot turn hooks - Packaging & Verification: updated installer streaming hash, synchronized launcher, passing check suites and release smoke checks
2
.gitignore
vendored
|
|
@ -30,6 +30,8 @@ __pycache__/
|
||||||
/build/buckshot/
|
/build/buckshot/
|
||||||
/build/coin/
|
/build/coin/
|
||||||
/build/dice/
|
/build/dice/
|
||||||
|
/build/darts/
|
||||||
|
/build/observer/
|
||||||
/build/hall/
|
/build/hall/
|
||||||
/build/icon_work/
|
/build/icon_work/
|
||||||
/build/scratch/
|
/build/scratch/
|
||||||
|
|
|
||||||
BIN
assets/animations/darts/arm-throw-v3.bin
Normal file
BIN
assets/animations/darts/board-v1.bin
Normal file
BIN
assets/animations/darts/dart-views-v1.bin
Normal file
BIN
assets/animations/darts/lounge-wall-v1.bin
Normal file
BIN
assets/animations/fortune/cards-v1.bin
Normal file
BIN
assets/animations/fortune/deal-v1.bin
Normal file
BIN
assets/animations/fortune/gesture-v1.bin
Normal file
BIN
assets/animations/fortune/orb-hands-v1.bin
Normal file
BIN
assets/animations/fortune/orb-mist-v1.bin
Normal file
BIN
assets/animations/fortune/room-v1.bin
Normal file
BIN
assets/animations/fortune/shuffle-v1.bin
Normal file
BIN
assets/sprites/darts/arm-throw-v3.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
assets/sprites/darts/board-v1.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
assets/sprites/darts/dart-views-v1.png
Normal file
|
After Width: | Height: | Size: 900 KiB |
BIN
assets/sprites/darts/lounge-wall-v1.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
80
assets/sprites/darts/prompts-v1.md
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Darts Artwork
|
||||||
|
|
||||||
|
Generated with the built-in image-generation tool. Runtime assets live in
|
||||||
|
`assets/animations/darts/`; original selected PNGs are in this directory.
|
||||||
|
All grid cells are extracted at one common scale. No separately generated limb
|
||||||
|
pieces or stretched forearms are used.
|
||||||
|
|
||||||
|
## arm-throw-v3.png
|
||||||
|
|
||||||
|
Sports game animation sprites, harmless pub darts. Create a 4x4 equal-grid
|
||||||
|
transparent sprite atlas, 16 frames, square 1536x1536. FIRST PERSON from the
|
||||||
|
thrower's eyes looking at their OWN RIGHT forearm and hand aiming a small
|
||||||
|
regulation sports dart FORWARD INTO THE SCREEN toward a distant dartboard,
|
||||||
|
NOT horizontally sideways across the picture. Strong perspective foreshortening:
|
||||||
|
the blue tail flights are closest to viewer; steel point points AWAY FROM
|
||||||
|
VIEWER, deeper into scene, above and slightly left of flights. Entire forearm
|
||||||
|
and visible bent elbow, dark shirt rolled ABOVE elbow. Right upper arm extends
|
||||||
|
toward lower right, elbow is near bottom right, forearm rises toward upper
|
||||||
|
middle. Natural darts throwing posture seen from own eyes, not another person's
|
||||||
|
side-on arm. Detailed realistic digitized retro game sprite art, natural skin,
|
||||||
|
silver knurled barrel, blue nylon shaft and blue cross flights. Row1 four similar
|
||||||
|
forward aiming poses. Row2 four gradual drawback poses bending elbow toward
|
||||||
|
viewer. Row3 four gradual FORWARD THROW poses straightening elbow and opening
|
||||||
|
fingertips; dart disappears after frame10, frame11 and12 are empty hand. Row4
|
||||||
|
four empty-handed follow-through/recovery poses, whole forearm still visible.
|
||||||
|
Same anatomy, elbow anchor, scale and lighting across frames. EACH WHOLE arm
|
||||||
|
stays inside its exact grid cell, 10 percent clear transparent margin all sides,
|
||||||
|
no overflow into neighboring cells. At most one coherent arm per cell. No scene,
|
||||||
|
no board, no faces, no borders, no text, no artifacts, no wrist-only framing, no
|
||||||
|
floating dart separated from fingers. Actual alpha transparent background.
|
||||||
|
|
||||||
|
## dart-views-v1.png
|
||||||
|
|
||||||
|
Asset sheet for a pub DARTS sports video game: ONLY a small realistic regulation
|
||||||
|
steel-tip SPORTS DART, no people, hands or other objects. 4 by 4 equal square
|
||||||
|
grid, 16 different coherent views on 1536x1536 transparent canvas. Same dart
|
||||||
|
every cell: short sharp silver steel point, cylindrical metallic silver tungsten
|
||||||
|
barrel with many machined knurled grooves and dark narrow grip rings, slim dark
|
||||||
|
blue nylon shaft, translucent rich royal-blue four-cross tail flights with
|
||||||
|
realistic curved edges and a small white stripe. Detailed realistic digitized
|
||||||
|
game rendering, NOT low-poly, not paper triangles. The sporting dart is about
|
||||||
|
14cm long and delicate, not a weapon. Rotate camera around the dart: row1 rear
|
||||||
|
three-quarter views angle 0,6,12,18 degrees; row2 24,30,36,42 degrees; row3
|
||||||
|
48,54,60,66 degrees; row4 72,78,84,90 degrees. Angle0: tail blue flights closest
|
||||||
|
to camera, point recedes straight away and is mostly hidden. Angle90: complete
|
||||||
|
clean SIDE VIEW, steel point to LEFT, blue tail to RIGHT. All intermediate angles
|
||||||
|
smoothly reveal the left-pointing silver barrel. Horizontal projected axis, no
|
||||||
|
vertical roll. Each entire dart centered in its own cell, same scale, 15 percent
|
||||||
|
transparent margin all sides. Rear views are naturally narrow in width, side
|
||||||
|
views longer, same physical scale. Studio highlights for clear metal detail,
|
||||||
|
sharp blue tail. NO background, checkerboard, grid lines, captions, text or
|
||||||
|
shadows outside the isolated dart. Actual alpha transparency.
|
||||||
|
|
||||||
|
## lounge-wall-v1.png
|
||||||
|
|
||||||
|
A production game environment texture: straight-on FLAT FRONT ELEVATION of the
|
||||||
|
wide darts-lounge wall inside a richly furnished vintage casino. Square
|
||||||
|
1024x1024 raster asset, realistic digitized 1990s adventure game art, crisp small
|
||||||
|
details. NOT a room perspective photo, no sidewalls, no floor or ceiling. Wall
|
||||||
|
occupies full image. Deep muted emerald painted plaster above waist-high dark
|
||||||
|
walnut wainscoting, brass trim, cream plaster details, burgundy accents, varied
|
||||||
|
restrained colors. Central wall area around x50%,y42% must be clean emerald
|
||||||
|
plaster with space for a separate dartboard, no board drawn. Left around
|
||||||
|
x26%,y42%: substantial black chalkboard in an aged brass frame with subtle
|
||||||
|
hand-written darts scores and tally marks. Right around x76%,y42%: illuminated
|
||||||
|
glass trophy cabinet with silver cups, darts memorabilia, folded burgundy cloth,
|
||||||
|
a framed old tournament photo. Warm-shaded brass wall lamps around x33% and
|
||||||
|
x67% at y23%, realistic pools of warm light on plaster, a small analog clock
|
||||||
|
above centre. Lower quarter: wainscot, two low cabinets and a narrow shelf for
|
||||||
|
chalk, coasters and a folded towel; leave centre lower wall clear. The composition
|
||||||
|
should read as an established pub-sports corner of an elegant casino, not an
|
||||||
|
elevator, not a small wooden box, not sci-fi, not orange all over. All objects in
|
||||||
|
true front elevation, fixed to wall, coherent scale and consistent lighting.
|
||||||
|
No people, hands, sports dart closeup, text labels, logos, watermark or frame
|
||||||
|
outside the image.
|
||||||
|
|
||||||
|
## board-v1.png
|
||||||
|
|
||||||
|
Deterministically generated exact 20-sector sports geometry, not AI artwork.
|
||||||
|
The sector order and scoring ring radii are shared with native scoring tests.
|
||||||
BIN
assets/sprites/fortune/crystal-mist-v1.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
44
assets/sprites/fortune/packed-v1.json
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"file": "room-v1.bin",
|
||||||
|
"width": 640,
|
||||||
|
"height": 480,
|
||||||
|
"frames": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "shuffle-v1.bin",
|
||||||
|
"width": 256,
|
||||||
|
"height": 256,
|
||||||
|
"frames": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "deal-v1.bin",
|
||||||
|
"width": 256,
|
||||||
|
"height": 256,
|
||||||
|
"frames": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "gesture-v1.bin",
|
||||||
|
"width": 256,
|
||||||
|
"height": 256,
|
||||||
|
"frames": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "orb-hands-v1.bin",
|
||||||
|
"width": 256,
|
||||||
|
"height": 256,
|
||||||
|
"frames": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "orb-mist-v1.bin",
|
||||||
|
"width": 192,
|
||||||
|
"height": 192,
|
||||||
|
"frames": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "cards-v1.bin",
|
||||||
|
"width": 96,
|
||||||
|
"height": 128,
|
||||||
|
"frames": 45
|
||||||
|
}
|
||||||
|
]
|
||||||
60
assets/sprites/fortune/prompts-v1.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# Fortune Session Production Prompts
|
||||||
|
|
||||||
|
Generated with the built-in image generation tool, not an API CLI. Original
|
||||||
|
outputs were copied into this project. Asset compilation is deterministic and
|
||||||
|
does not make image-generation calls. These are the production specifications.
|
||||||
|
|
||||||
|
## teller-actions-v1.png
|
||||||
|
|
||||||
|
Reference: `../hall/fortune-room-v2.png`, top-row faceless hooded teller only.
|
||||||
|
Transparent production sprite sheet, exactly eight columns by five rows, forty
|
||||||
|
equal square cells. Front-facing seated upper body, navy embroidered robe,
|
||||||
|
silver crescents, dark gloves, absolutely no face under the hood. Same silhouette,
|
||||||
|
size, head and shoulder position in every cell. No table, chair, candles, scenery,
|
||||||
|
labels or borders. Detailed painted retro pixel art. Row one: eight successive
|
||||||
|
poses taking and splitting a deck and beginning overhand shuffle. Row two: eight
|
||||||
|
successive packet-transfer shuffle poses ending with the deck centered. Row
|
||||||
|
three: eight dealing poses, left hand holds the deck, right hand reaches forward,
|
||||||
|
releases a card and retracts. Row four: eight card-turning and explanatory wrist
|
||||||
|
and open-palm gestures. Row five: eight poses lifting and circling both hands
|
||||||
|
around empty space for a separately rendered crystal ball. Articulate fingers,
|
||||||
|
wrists, forearms and sleeves, no camera changes or torso bouncing. Render the
|
||||||
|
whole sheet together for consistent character identity and palette.
|
||||||
|
|
||||||
|
## seated-room-v1.png
|
||||||
|
|
||||||
|
Full-screen 4:3 retro pixel-art background. First-person seated across an intimate
|
||||||
|
round tarot table in a cramped cluttered midnight-blue occult cellar. Empty
|
||||||
|
carved high-backed chair centered around 43 percent width, curtains behind it,
|
||||||
|
no person. Dark blue velvet tabletop covers the lower 42 percent, silver edge
|
||||||
|
trim and blank central area for separate cards. Teller will be composited with
|
||||||
|
head at 43 percent width, 17 percent height and hands near 54 percent height.
|
||||||
|
Left cabinets crowded with books, scrolls, herbs, skull and trinkets; right shelves
|
||||||
|
with glass bottles, blue crystal and a hanging blue lantern. Deep shadow with
|
||||||
|
cool candlelight, muted burgundy fabric and aged silver/brass accents. Believable
|
||||||
|
untidiness, draped curtains above and at the sides. No table cards, deck, ball,
|
||||||
|
lettering, numbers, UI or screen border. Keep the upper-right speech area clear.
|
||||||
|
|
||||||
|
## tarot-symbols-v1.png
|
||||||
|
|
||||||
|
Symbolic tarot atlas, exactly six columns by four rows, 24 equal portrait cells,
|
||||||
|
no gaps, letters or labels. Objects rather than human figures; detailed retro
|
||||||
|
pixel art, thin ivory borders, navy, silver, burgundy, gold and cyan. Row-major
|
||||||
|
symbols: traveller's satchel/staff/cliff; wand/tools; pillars/moon; crown/wheat;
|
||||||
|
stone throne; ceremonial hat/crossed keys; entwined roses/heart; chariot; lion/
|
||||||
|
infinity; lantern/mountain; ornate wheel; scales/sword; inverted watch/tree;
|
||||||
|
scythe/rose/hourglass; pouring cups; horned stone mask/chains; lightning/tower;
|
||||||
|
star/water; moon/two towers; sun/sunflowers; trumpet/banner; globe/laurel. Last
|
||||||
|
two cells: symmetrical silver crescent and stars on midnight-blue card backs.
|
||||||
|
Keep each recognizable illustration completely within its consistent frame.
|
||||||
|
|
||||||
|
## crystal-mist-v1.png
|
||||||
|
|
||||||
|
Transparent VFX sprite sheet, exactly four columns by four rows, sixteen equal
|
||||||
|
square cells. Identical crystal ball on a small antique silver stand, front view,
|
||||||
|
fixed silhouette, scale and bottom-center anchor. No hands, person or table.
|
||||||
|
Pale-blue smoke spirals clockwise through one full cycle across sixteen frames.
|
||||||
|
Subtle blue sparks and lighting inside the glass, no text, faces, numbers or
|
||||||
|
symbols. Keep stand stationary; vary the internal smoke, not object placement.
|
||||||
|
Detailed painted retro pixel art, dark glass and luminous cyan-blue mist, clean
|
||||||
|
transparent corners, no matte or background.
|
||||||
BIN
assets/sprites/fortune/seated-room-v1.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
assets/sprites/fortune/tarot-symbols-v1.png
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
assets/sprites/fortune/teller-actions-v1.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
bin/poker.exe
|
|
@ -8,7 +8,7 @@ namespace AssemblerCasinoLauncher
|
||||||
{
|
{
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
const string ExpectedPokerSha256 = "C1714FEA01C6AA594A1895F56CCC287E5D1F35CDC829F5C2658FF05A4CBB6ECF";
|
const string ExpectedPokerSha256 = "C3D857FDBF7597C976B16C5021D7F07951628E54F86FF2B7BB53F8A83FDE11CA";
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
|
|
@ -27,7 +27,7 @@ namespace PokerGameSetup
|
||||||
sealed class InstallerForm : Form
|
sealed class InstallerForm : Form
|
||||||
{
|
{
|
||||||
const string Marker = "<<POKER_GAME_GUI_PAYLOAD_ZIP>>";
|
const string Marker = "<<POKER_GAME_GUI_PAYLOAD_ZIP>>";
|
||||||
const string ExpectedPayloadSha256 = "718663039D0CCB6EE83C62D23C8F8F7A6D4C596135E75F757C101C568E8473E9";
|
const string ExpectedPayloadSha256 = "1A2AC9A543AAF354EAD5BFA4716A8677143E27D994D55120AAF4ACF8296AAA6B";
|
||||||
readonly Color bg = Color.FromArgb(15, 12, 10);
|
readonly Color bg = Color.FromArgb(15, 12, 10);
|
||||||
readonly Color panel = Color.FromArgb(28, 22, 18);
|
readonly Color panel = Color.FromArgb(28, 22, 18);
|
||||||
readonly Color gold = Color.FromArgb(236, 186, 75);
|
readonly Color gold = Color.FromArgb(236, 186, 75);
|
||||||
|
|
@ -247,19 +247,44 @@ namespace PokerGameSetup
|
||||||
Directory.CreateDirectory(Path.Combine(target, "runtime"));
|
Directory.CreateDirectory(Path.Combine(target, "runtime"));
|
||||||
|
|
||||||
var exe = Assembly.GetExecutingAssembly().Location;
|
var exe = Assembly.GetExecutingAssembly().Location;
|
||||||
var bytes = File.ReadAllBytes(exe);
|
|
||||||
var marker = System.Text.Encoding.UTF8.GetBytes(Marker);
|
var marker = System.Text.Encoding.UTF8.GetBytes(Marker);
|
||||||
var index = FindMarker(bytes, marker);
|
|
||||||
if (index < 0) throw new InvalidOperationException("В установщике не найден архив игры.");
|
|
||||||
|
|
||||||
var payloadBytes = bytes.Skip(index + marker.Length).ToArray();
|
SetProgress(0, "Поиск архива игры...");
|
||||||
VerifyPayloadIntegrity(payloadBytes);
|
long payloadStart = -1;
|
||||||
|
using (var fs = File.OpenRead(exe))
|
||||||
|
{
|
||||||
|
payloadStart = FindMarkerInStream(fs, marker);
|
||||||
|
}
|
||||||
|
if (payloadStart < 0) throw new InvalidOperationException("В установщике не найден архив игры.");
|
||||||
|
|
||||||
var tempZip = Path.Combine(Path.GetTempPath(), "assembler_casino_payload_" + Guid.NewGuid().ToString("N") + ".zip");
|
var tempZip = Path.Combine(Path.GetTempPath(), "assembler_casino_payload_" + Guid.NewGuid().ToString("N") + ".zip");
|
||||||
File.WriteAllBytes(tempZip, payloadBytes);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
SetProgress(5, "Проверка целостности архива...");
|
||||||
|
using (var fs = File.OpenRead(exe))
|
||||||
|
{
|
||||||
|
fs.Position = payloadStart;
|
||||||
|
using (var outFs = File.Create(tempZip, 65536))
|
||||||
|
using (var sha = SHA256.Create())
|
||||||
|
{
|
||||||
|
var buf = new byte[65536];
|
||||||
|
int r;
|
||||||
|
while ((r = fs.Read(buf, 0, buf.Length)) > 0)
|
||||||
|
{
|
||||||
|
sha.TransformBlock(buf, 0, r, null, 0);
|
||||||
|
outFs.Write(buf, 0, r);
|
||||||
|
}
|
||||||
|
sha.TransformFinalBlock(buf, 0, 0);
|
||||||
|
var actual = BitConverter.ToString(sha.Hash).Replace("-", "");
|
||||||
|
if (!string.IsNullOrWhiteSpace(ExpectedPayloadSha256) &&
|
||||||
|
ExpectedPayloadSha256 != "TO_BE_FILLED_BY_RELEASE_BUILD" &&
|
||||||
|
!actual.Equals(ExpectedPayloadSha256, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Архив игры внутри установщика был изменен. Установка остановлена.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using (var zip = ZipFile.OpenRead(tempZip))
|
using (var zip = ZipFile.OpenRead(tempZip))
|
||||||
{
|
{
|
||||||
var files = zip.Entries.Where(e => !string.IsNullOrEmpty(e.Name)).ToList();
|
var files = zip.Entries.Where(e => !string.IsNullOrEmpty(e.Name)).ToList();
|
||||||
|
|
@ -285,23 +310,10 @@ namespace PokerGameSetup
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
try { File.Delete(tempZip); } catch { }
|
try { if (File.Exists(tempZip)) File.Delete(tempZip); } catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyPayloadIntegrity(byte[] payloadBytes)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(ExpectedPayloadSha256) || ExpectedPayloadSha256 == "TO_BE_FILLED_BY_RELEASE_BUILD")
|
|
||||||
return;
|
|
||||||
|
|
||||||
using (var sha = SHA256.Create())
|
|
||||||
{
|
|
||||||
var hash = sha.ComputeHash(payloadBytes);
|
|
||||||
var actual = BitConverter.ToString(hash).Replace("-", "");
|
|
||||||
if (!actual.Equals(ExpectedPayloadSha256, StringComparison.OrdinalIgnoreCase))
|
|
||||||
throw new InvalidOperationException("Архив игры внутри установщика был изменен. Установка остановлена.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateDesktopShortcut(string target)
|
void CreateDesktopShortcut(string target)
|
||||||
{
|
{
|
||||||
|
|
@ -347,12 +359,48 @@ namespace PokerGameSetup
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long FindMarkerInStream(Stream stream, byte[] marker)
|
||||||
|
{
|
||||||
|
var buffer = new byte[1024 * 1024];
|
||||||
|
long streamPos = 0;
|
||||||
|
int bytesRead;
|
||||||
|
int overlap = marker.Length - 1;
|
||||||
|
int carry = 0;
|
||||||
|
|
||||||
|
while ((bytesRead = stream.Read(buffer, carry, buffer.Length - carry)) > 0)
|
||||||
|
{
|
||||||
|
int total = carry + bytesRead;
|
||||||
|
int idx = FindMarker(buffer, marker, total);
|
||||||
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
return streamPos + idx + marker.Length;
|
||||||
|
}
|
||||||
|
if (total >= overlap)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(buffer, total - overlap, buffer, 0, overlap);
|
||||||
|
carry = overlap;
|
||||||
|
streamPos += (total - overlap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
carry = total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int FindMarker(byte[] bytes, byte[] marker)
|
int FindMarker(byte[] bytes, byte[] marker)
|
||||||
{
|
{
|
||||||
for (int i = 0; i <= bytes.Length - marker.Length; i++)
|
return FindMarker(bytes, marker, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FindMarker(byte[] bytes, byte[] marker, int length)
|
||||||
|
{
|
||||||
|
for (int i = 0; i <= length - marker.Length; i++)
|
||||||
{
|
{
|
||||||
|
if (bytes[i] != marker[0]) continue;
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
for (int j = 0; j < marker.Length; j++)
|
for (int j = 1; j < marker.Length; j++)
|
||||||
{
|
{
|
||||||
if (bytes[i + j] != marker[j]) { ok = false; break; }
|
if (bytes[i + j] != marker[j]) { ok = false; break; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
casino3d.inc
|
|
@ -171,6 +171,8 @@ include src_graphics\native_dice_data.inc
|
||||||
include src_graphics\scratch_data.inc
|
include src_graphics\scratch_data.inc
|
||||||
include src_graphics\hell_tower_data.inc
|
include src_graphics\hell_tower_data.inc
|
||||||
include src_graphics\charms_data.inc
|
include src_graphics\charms_data.inc
|
||||||
|
include src_graphics\observer_data.inc
|
||||||
|
include src_graphics\darts_data.inc
|
||||||
|
|
||||||
.data
|
.data
|
||||||
ALIGN 4
|
ALIGN 4
|
||||||
|
|
@ -4856,7 +4858,7 @@ check_target_terminal:
|
||||||
check_target_observer:
|
check_target_observer:
|
||||||
cmp eax, INTERACT_OBSERVER
|
cmp eax, INTERACT_OBSERVER
|
||||||
jne target_unported
|
jne target_unported
|
||||||
call BeginUnavailable3D
|
call BeginObserver3D
|
||||||
ret
|
ret
|
||||||
|
|
||||||
target_unported:
|
target_unported:
|
||||||
|
|
@ -5194,6 +5196,8 @@ include src_graphics\unavailable.inc
|
||||||
include src_graphics\fortune_dialog.inc
|
include src_graphics\fortune_dialog.inc
|
||||||
include src_graphics\hell_tower.inc
|
include src_graphics\hell_tower.inc
|
||||||
include src_graphics\charms.inc
|
include src_graphics\charms.inc
|
||||||
|
include src_graphics\observer.inc
|
||||||
|
include src_graphics\darts.inc
|
||||||
|
|
||||||
; --- Main Loop of the 3D Casino Engine ---
|
; --- Main Loop of the 3D Casino Engine ---
|
||||||
StartHellTower3D PROC uses ebx esi edi
|
StartHellTower3D PROC uses ebx esi edi
|
||||||
|
|
@ -5245,6 +5249,15 @@ dispatch_frame:
|
||||||
jz @F
|
jz @F
|
||||||
call ToggleFullscreen3D
|
call ToggleFullscreen3D
|
||||||
@@:
|
@@:
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne engine_observer_frame
|
||||||
|
cmp engineMode,MODE_OBSERVER
|
||||||
|
jne engine_observer_skip
|
||||||
|
engine_observer_frame:
|
||||||
|
call UpdateMouseLockState
|
||||||
|
call ObserverFrame3D
|
||||||
|
jmp present_frame
|
||||||
|
engine_observer_skip:
|
||||||
invoke Pressed3D, 1Bh
|
invoke Pressed3D, 1Bh
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz engine_tick
|
jz engine_tick
|
||||||
|
|
@ -5343,6 +5356,12 @@ check_walk_mode:
|
||||||
call RenderMinimap
|
call RenderMinimap
|
||||||
jmp present_frame
|
jmp present_frame
|
||||||
check_slots_mode:
|
check_slots_mode:
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
jne check_darts_done
|
||||||
|
call HandleDarts3D
|
||||||
|
call RenderDarts3D
|
||||||
|
jmp present_frame
|
||||||
|
check_darts_done:
|
||||||
cmp engineMode,MODE_FORTUNE
|
cmp engineMode,MODE_FORTUNE
|
||||||
jne @F
|
jne @F
|
||||||
call HandleFortuneDialog3D
|
call HandleFortuneDialog3D
|
||||||
|
|
@ -5620,6 +5639,7 @@ engine_shutdown:
|
||||||
call SaveProgress3D
|
call SaveProgress3D
|
||||||
invoke PlayCasinoSound3D, 0, 0, 0
|
invoke PlayCasinoSound3D, 0, 0, 0
|
||||||
call FreeRussianAssets3D
|
call FreeRussianAssets3D
|
||||||
|
call FreeDarts3D
|
||||||
call FreeStartupAssets3D
|
call FreeStartupAssets3D
|
||||||
call FreeCardTableAssets3D
|
call FreeCardTableAssets3D
|
||||||
call FreeBuckshotAssets3D
|
call FreeBuckshotAssets3D
|
||||||
|
|
|
||||||
BIN
dist/Assembler Casino.exe
vendored
BIN
dist/Uninstall Assembler Casino.exe
vendored
71
docs/DARTS.md
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Darts
|
||||||
|
|
||||||
|
The board is on the first-floor wall near the billiards area. It opens a native
|
||||||
|
MASM darts match against Max. No Python, browser, external engine or network is
|
||||||
|
required by the game.
|
||||||
|
|
||||||
|
## Match
|
||||||
|
|
||||||
|
- Both players start at 500. First to reach exactly zero wins.
|
||||||
|
- Three darts per visit. Visits alternate between the player and Max.
|
||||||
|
- Any scoring ring can finish. This is a custom 500-point straight-out format,
|
||||||
|
not tournament 501 double-out.
|
||||||
|
- A negative remainder is a bust: the entire visit is cancelled and play passes
|
||||||
|
to the other player. A remainder of one is valid.
|
||||||
|
- The casino bankroll and saved profile are not changed by this game.
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
- Move the mouse to aim; the outlined cross marks the current hit point.
|
||||||
|
- Hold the left mouse button to draw back, release to throw.
|
||||||
|
- The hand and cross have the same smooth, mixed-phase sway. Holding the aim
|
||||||
|
longer than 1.2 seconds gradually increases fatigue, capped after 4 seconds.
|
||||||
|
Precise mouse motion is retained independently of the hall's 320px UI grid.
|
||||||
|
There is no extra
|
||||||
|
random scatter after releasing the button.
|
||||||
|
- The target sector appears beside the turn indicator (S, D or T).
|
||||||
|
- Tab opens/closes the live score sheet and pauses the current action.
|
||||||
|
- R or the lower-right button starts a new match. Escape returns to the hall.
|
||||||
|
|
||||||
|
## Visuals
|
||||||
|
|
||||||
|
The throwing line is 2700 board millimetres from the target. The initial lens
|
||||||
|
is adjusted so the board is only about 7 percent smaller on screen than the
|
||||||
|
previous 2370mm/900px view. Its original 512px texture and scoring geometry are
|
||||||
|
unchanged. Max watches the same moving aim point for a short release window;
|
||||||
|
he does not reroll a hit or bypass the sway.
|
||||||
|
|
||||||
|
The independent
|
||||||
|
scene camera follows one immutable parabolic trajectory, passes beside the
|
||||||
|
dart, returns behind it, pauses at the hit, then returns to the throwing line.
|
||||||
|
The small fading trail samples the same trajectory.
|
||||||
|
|
||||||
|
Whole-arm raster animation includes the elbow, draw-back, release and empty
|
||||||
|
follow-through. A single rigid canvas transform aligns the held dart with the
|
||||||
|
target; individual limb pieces are never stretched or assembled.
|
||||||
|
|
||||||
|
The flying dart uses sixteen detailed camera-relative raster views. Its needle
|
||||||
|
anchor is registered per view, so the tip meets the scored board coordinate.
|
||||||
|
It is not drawn from flat-colored geometric triangles.
|
||||||
|
|
||||||
|
The lounge has actual ray-projected front/side/back walls, floor and ceiling.
|
||||||
|
Chairs and the lamp table occupy fixed world planes, rather than turning to
|
||||||
|
face the camera. The wall chalkboard is rewritten with real scores and recent
|
||||||
|
visit history, including when seen from the moving camera.
|
||||||
|
|
||||||
|
## Assets And Checks
|
||||||
|
|
||||||
|
`tools/generators/pack_darts.py` is an offline asset packer. It builds the exact
|
||||||
|
20-sector board and packs the generated arm, dart views and lounge artwork.
|
||||||
|
Artwork provenance and prompts are in `assets/sprites/darts/prompts-v1.md`.
|
||||||
|
|
||||||
|
`C:/Python314/python.exe tools/tests/check_darts.py` compiles the actual MASM
|
||||||
|
scene into a native fixture and checks 67 scoring vectors, 20 complete bot
|
||||||
|
matches, busts, per-player score isolation, immutable hits, real mouse-release
|
||||||
|
events, fine high-resolution mouse input, sway/fatigue, board footprint, Tab
|
||||||
|
behavior, camera motion and profile isolation. It renders native
|
||||||
|
640x480 framebuffers, a contact sheet and a GIF under `build/darts/`.
|
||||||
|
|
||||||
|
`--parity` compares tested procedure instruction/relocation signatures to the
|
||||||
|
full shipping assembly object. The hall fixture additionally covers interaction
|
||||||
|
dispatch and the unchanged stairs, doors, bar and fortune room.
|
||||||
|
|
@ -1,5 +1,17 @@
|
||||||
# Offline Fortune Teller
|
# Offline Fortune Teller
|
||||||
|
|
||||||
|
## Currently Shelved (2026-10-22)
|
||||||
|
|
||||||
|
The seated visual session no longer starts the worker or generates readings.
|
||||||
|
The native scene deals and reveals cards, then explicitly says that explanation
|
||||||
|
is not implemented. The crystal-ball scene is visual only, without academic
|
||||||
|
grade selection or collection of student identity details. Existing inference
|
||||||
|
sources and local model files are retained for future work, not required by the
|
||||||
|
current game. The older AI archive is not an updated visual-session release.
|
||||||
|
See `FORTUNE_SESSION.md` for the current runtime and verification.
|
||||||
|
|
||||||
|
The following documents the previous experimental neural integration.
|
||||||
|
|
||||||
The approved C++ exception is limited to the neural worker. MASM still owns the
|
The approved C++ exception is limited to the neural worker. MASM still owns the
|
||||||
room, interaction, question input, card selection, dialogue rendering, process
|
room, interaction, question input, card selection, dialogue rendering, process
|
||||||
lifetime and all gameplay. No OpenAI API, Ollama, Python runtime, listening port,
|
lifetime and all gameplay. No OpenAI API, Ollama, Python runtime, listening port,
|
||||||
|
|
|
||||||
58
docs/FORTUNE_SESSION.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Seated Fortune Session
|
||||||
|
|
||||||
|
The room interaction opens a fixed first-person view across the table. No player
|
||||||
|
position, camera or bankroll state is modified. Escape or Exit returns to walking.
|
||||||
|
All runtime input, random card selection, state transitions and rendering are MASM
|
||||||
|
in `src_graphics/fortune_dialog.inc`; Python only compiles offline image assets.
|
||||||
|
|
||||||
|
## Tarot
|
||||||
|
|
||||||
|
Enter a question (up to 240 CP1251 characters), then Ask or Enter. The question
|
||||||
|
stays visible under the table for the entire reading and cannot change midway.
|
||||||
|
Three distinct major arcana are selected in assembly, each with an orientation.
|
||||||
|
The 22 symbolic illustrations have separately packed 180-degree reversed faces.
|
||||||
|
|
||||||
|
Sequence: shuffle 3.2 s; deal cards individually 1 s each; turn a card over 0.8 s;
|
||||||
|
show its name, orientation and honest unavailable explanation 3.6 s; repeat for
|
||||||
|
the next two cards; show the overall-answer placeholder; finish. Continue can
|
||||||
|
advance a completed speech, never skip a deal or a flip. Again clears the question
|
||||||
|
only after completion; Selection can return to the choice of scenes at any time.
|
||||||
|
|
||||||
|
Speech is composited beside the teller, not an OS window. Its border grows with
|
||||||
|
the visible text. Characters reveal every 28 ms with a short upward pop. Rendering
|
||||||
|
does not advance timers: the session updates from the game clock, with bounded
|
||||||
|
steps after stalls. No neural worker or algorithmic reading generator is called.
|
||||||
|
|
||||||
|
## Crystal Ball
|
||||||
|
|
||||||
|
The second selection raises a crystal ball and animates gloved hands with swirling
|
||||||
|
blue mist. It ends with an explicit unavailable-result line. There is no real
|
||||||
|
student grading, inference of merit, identity form or automated academic decision.
|
||||||
|
Again replays the visual sequence. This limitation is deliberate, not a hidden
|
||||||
|
random grade presented as a judgement.
|
||||||
|
|
||||||
|
## Assets
|
||||||
|
|
||||||
|
Generated source art and production prompts: `assets/sprites/fortune/`.
|
||||||
|
Offline packer: `tools/generators/pack_fortune_session.py`.
|
||||||
|
Runtime packs: `assets/animations/fortune/` (ANM1 format).
|
||||||
|
|
||||||
|
Forty authored poses are arranged on one shared anchored 8x5 sheet. Shared-canvas
|
||||||
|
in-betweens yield 64 shuffle, 32 deal, 32 gesture and 32 orb-hand frames. Sixteen
|
||||||
|
mist frames, 44 oriented card faces, a back and a 640x480 room complete the scene.
|
||||||
|
Art loads only when seated and all seven packs are freed on exit/shutdown. The
|
||||||
|
seated view is independent of the walking room's existing asset packs and map.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Run `C:/Python314/python.exe tools/tests/check_hall_expansion.py` after packing.
|
||||||
|
The fresh native x86 harness exercises real WM_CHAR input, length/backspace,
|
||||||
|
empty/double submission, all stage transitions, card uniqueness, speech growth,
|
||||||
|
question persistence, crystal-ball stages, exit during animation, asset cleanup
|
||||||
|
and unchanged player position/bank. It writes actual framebuffer BMP/PNG captures
|
||||||
|
and a 64-frame shuffle GIF under `build/hall-expansion/`. Python additionally checks
|
||||||
|
native-frame differences, question pixels, pack integrity and reversed artwork.
|
||||||
|
`--parity` checks these tested procedures against the shipping game object.
|
||||||
|
|
||||||
|
The old multi-gigabyte neural ZIP is not rebuilt by this feature. Distributions
|
||||||
|
must include the new `assets/animations/fortune/` directory with the updated game.
|
||||||
49
docs/OBSERVER.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Native AI Observer
|
||||||
|
|
||||||
|
The observer lounge opens a game selector rather than the old unavailable modal.
|
||||||
|
All gameplay, decisions, rendering and input remain MASM32. No neural model or
|
||||||
|
network connection is used.
|
||||||
|
|
||||||
|
## Games
|
||||||
|
|
||||||
|
- Heads-up Hold'em: the existing bot decision is shared by both seats.
|
||||||
|
- Blackjack: an autonomous first seat plays against the normal dealer.
|
||||||
|
- Durak: both throwing-in and transfer variants use the same legal-move bot.
|
||||||
|
- Billiards: both pyramid and eight-ball seats use the existing shot planner.
|
||||||
|
|
||||||
|
These are real rounds using the normal shuffled decks, settlement and billiard
|
||||||
|
physics. The observer does not generate scripted winners. Both poker and Durak
|
||||||
|
hands are visible to the spectator, but each bot still sees only its own cards
|
||||||
|
and public information. Blackjack retains the dealer's normal hidden hole card.
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
Select a game with the mouse, keys 1-6, or arrows and Enter. During a match:
|
||||||
|
|
||||||
|
- Space or the pause button pauses/resumes decisions and animation.
|
||||||
|
- Tab or the speed button cycles 1x, 2x and 4x.
|
||||||
|
- N or restart starts a fresh round without adding an abandoned round to scores.
|
||||||
|
- Escape or Games returns to the selector. Escape again returns to the hall.
|
||||||
|
|
||||||
|
Completed rounds remain visible for three simulated seconds before another
|
||||||
|
round starts. Each round uses a fresh virtual stack. Scores reset when choosing
|
||||||
|
a different watching session. Human gameplay commands are discarded while watching.
|
||||||
|
|
||||||
|
## Profile Isolation
|
||||||
|
|
||||||
|
The observer snapshots the player's balance, RNG state, tournament flag, bets,
|
||||||
|
game variants and blackjack/billiard opponent settings. These are restored before
|
||||||
|
leaving. Native save, NPC-contract progress and loss-protection charms have an
|
||||||
|
observer barrier. Watching does not spend personal funds, charms, grant balance
|
||||||
|
achievements, progress contracts or write the profile.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
`C:/Python314/python.exe tools/tests/check_observer.py` compiles fresh native game
|
||||||
|
and spectator procedures against existing rendering helpers. It runs 80 complete
|
||||||
|
card rounds, checks both billiard seats, pause and profile restoration, compares
|
||||||
|
runtime files before/after, and captures actual native framebuffers.
|
||||||
|
|
||||||
|
After rebuilding the full game, `--parity` checks that the shipping procedures
|
||||||
|
match the native-tested object. `test_billiards_module.ps1` additionally exercises
|
||||||
|
ordinary human/AI billiards with observer mode disabled.
|
||||||
BIN
poker.exe
BIN
poker.obj
|
|
@ -40,6 +40,10 @@ DrawTableHeader3D PROC hdrLabel:DWORD,hdrPot:DWORD
|
||||||
DrawTableHeader3D ENDP
|
DrawTableHeader3D ENDP
|
||||||
|
|
||||||
DrawStakeControls3D PROC uses ebx enabled:DWORD
|
DrawStakeControls3D PROC uses ebx enabled:DWORD
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je @F
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
mov ebx, 006D7470h
|
mov ebx, 006D7470h
|
||||||
cmp enabled, 0
|
cmp enabled, 0
|
||||||
je @F
|
je @F
|
||||||
|
|
@ -84,6 +88,8 @@ poker_render_stake_enabled:
|
||||||
invoke DrawStakeControls3D, eax
|
invoke DrawStakeControls3D, eax
|
||||||
mov eax, pkStreet3D
|
mov eax, pkStreet3D
|
||||||
invoke DrawString8x8, 180, 6, pkStreetNames3D[eax*4], 00C4B8A0h
|
invoke DrawString8x8, 180, 6, pkStreetNames3D[eax*4], 00C4B8A0h
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne poker_observer_chips
|
||||||
mov eax, pkRaise3D
|
mov eax, pkRaise3D
|
||||||
mov esi, OFFSET tableRaiseText3D
|
mov esi, OFFSET tableRaiseText3D
|
||||||
cmp pkState3D, PK_IDLE
|
cmp pkState3D, PK_IDLE
|
||||||
|
|
@ -99,6 +105,7 @@ poker_render_blind:
|
||||||
pop eax
|
pop eax
|
||||||
invoke FormatNumber, eax, OFFSET hudNumBuffer
|
invoke FormatNumber, eax, OFFSET hudNumBuffer
|
||||||
invoke DrawString8x8, 12, 187, OFFSET hudNumBuffer, 00F6F4DDh
|
invoke DrawString8x8, 12, 187, OFFSET hudNumBuffer, 00F6F4DDh
|
||||||
|
poker_observer_chips:
|
||||||
invoke DrawNativeChips3D, 278, 196, pkPot3D, 00B14A49h
|
invoke DrawNativeChips3D, 278, 196, pkPot3D, 00B14A49h
|
||||||
cmp pkChipTimer3D, 320
|
cmp pkChipTimer3D, 320
|
||||||
jae @F
|
jae @F
|
||||||
|
|
@ -144,6 +151,8 @@ poker_render_chip_path:
|
||||||
xor ebx, ebx
|
xor ebx, ebx
|
||||||
poker_render_hole:
|
poker_render_hole:
|
||||||
mov hidden, 0
|
mov hidden, 0
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne poker_render_hole_state
|
||||||
cmp ebx, 2
|
cmp ebx, 2
|
||||||
jb poker_render_hole_state
|
jb poker_render_hole_state
|
||||||
mov hidden, 1
|
mov hidden, 1
|
||||||
|
|
@ -237,7 +246,13 @@ poker_render_status:
|
||||||
cmp pkState3D, PK_RESULT
|
cmp pkState3D, PK_RESULT
|
||||||
jne poker_render_ai_status
|
jne poker_render_ai_status
|
||||||
mov eax, pkOutcome3D
|
mov eax, pkOutcome3D
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je poker_personal_result
|
||||||
|
invoke DrawString8x8,108,103,obsResultNames3D[eax*4],00F4DF9Eh
|
||||||
|
jmp poker_result_class
|
||||||
|
poker_personal_result:
|
||||||
invoke DrawString8x8, 108, 103, pkResults3D[eax*4], 00F4DF9Eh
|
invoke DrawString8x8, 108, 103, pkResults3D[eax*4], 00F4DF9Eh
|
||||||
|
poker_result_class:
|
||||||
cmp pkResult3D, 1
|
cmp pkResult3D, 1
|
||||||
jne poker_render_buttons
|
jne poker_render_buttons
|
||||||
invoke NativePokerClass3D, pkScore3D
|
invoke NativePokerClass3D, pkScore3D
|
||||||
|
|
@ -315,9 +330,12 @@ bj_render_stake_enabled:
|
||||||
inc eax
|
inc eax
|
||||||
@@:
|
@@:
|
||||||
invoke DrawStakeControls3D, eax
|
invoke DrawStakeControls3D, eax
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne bj_observer_cards
|
||||||
invoke DrawString8x8, 8, 36, OFFSET textBet3D, 00DDCFB1h
|
invoke DrawString8x8, 8, 36, OFFSET textBet3D, 00DDCFB1h
|
||||||
invoke FormatNumber, cbBet3D, OFFSET hudNumBuffer
|
invoke FormatNumber, cbBet3D, OFFSET hudNumBuffer
|
||||||
invoke DrawString8x8, 80, 36, OFFSET hudNumBuffer, 00F6F4DDh
|
invoke DrawString8x8, 80, 36, OFFSET hudNumBuffer, 00F6F4DDh
|
||||||
|
bj_observer_cards:
|
||||||
cmp cbState3D, CB_IDLE
|
cmp cbState3D, CB_IDLE
|
||||||
je bj_render_buttons
|
je bj_render_buttons
|
||||||
xor edi, edi
|
xor edi, edi
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
; Output: eax = 1 if saved (bet refunded to bankroll), 0 if not saved
|
; Output: eax = 1 if saved (bet refunded to bankroll), 0 if not saved
|
||||||
; ------------------------------------------------------------------------------
|
; ------------------------------------------------------------------------------
|
||||||
TriggerCharmLossProtection PROC uses ebx ecx edx, betAmount:DWORD
|
TriggerCharmLossProtection PROC uses ebx ecx edx, betAmount:DWORD
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne protection_none
|
||||||
; 1. Check Devil's Contract (50% chance to refund full bet)
|
; 1. Check Devil's Contract (50% chance to refund full bet)
|
||||||
cmp charmDevilUses, 0
|
cmp charmDevilUses, 0
|
||||||
jle check_clover
|
jle check_clover
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@ cityRayY3D dd SCREEN_W dup(?)
|
||||||
; Exterior-only materials do not consume or overwrite the hall's texture slots.
|
; Exterior-only materials do not consume or overwrite the hall's texture slots.
|
||||||
ResolveCitySurface3D PROC material:DWORD
|
ResolveCitySurface3D PROC material:DWORD
|
||||||
mov eax,material
|
mov eax,material
|
||||||
|
cmp eax,160
|
||||||
|
jne @F
|
||||||
|
call ResolveDartsSurface3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
cmp eax,132
|
cmp eax,132
|
||||||
jb @F
|
jb @F
|
||||||
cmp eax,159
|
cmp eax,159
|
||||||
|
|
|
||||||
890
src_graphics/darts.inc
Normal file
|
|
@ -0,0 +1,890 @@
|
||||||
|
; One immutable hit point drives scoring, dart geometry and the follow camera.
|
||||||
|
.code
|
||||||
|
LoadDarts3D PROC
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtBoard3D,OFFSET dtBoardPath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
cmp dtBoard3D.imageWidth,512
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtBoard3D.height,512
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtBoard3D.frames,1
|
||||||
|
jne dt_load_fail
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtHands3D,OFFSET dtHandsPath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
cmp dtHands3D.imageWidth,256
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtHands3D.height,256
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtHands3D.frames,16
|
||||||
|
jne dt_load_fail
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtDart3D,OFFSET dtDartPath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
cmp dtDart3D.imageWidth,256
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtDart3D.height,256
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtDart3D.frames,16
|
||||||
|
jne dt_load_fail
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtWall3D,OFFSET dtWallPath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
cmp dtWall3D.imageWidth,512
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtWall3D.height,512
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtWall3D.frames,1
|
||||||
|
jne dt_load_fail
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtChair3D,OFFSET dtChairPath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtTable3D,OFFSET dtTablePath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtRoom3D,OFFSET dtRoomPath
|
||||||
|
test eax,eax
|
||||||
|
jz dt_load_fail
|
||||||
|
cmp dtRoom3D.imageWidth,256
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtRoom3D.height,256
|
||||||
|
jne dt_load_fail
|
||||||
|
cmp dtRoom3D.frames,12
|
||||||
|
jne dt_load_fail
|
||||||
|
mov eax,1
|
||||||
|
ret
|
||||||
|
dt_load_fail:
|
||||||
|
call FreeDarts3D
|
||||||
|
xor eax,eax
|
||||||
|
ret
|
||||||
|
LoadDarts3D ENDP
|
||||||
|
|
||||||
|
FreeDarts3D PROC
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtBoard3D
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtHands3D
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtDart3D
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtWall3D
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtChair3D
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtTable3D
|
||||||
|
invoke FreeAnimPack3D,OFFSET dtRoom3D
|
||||||
|
ret
|
||||||
|
FreeDarts3D ENDP
|
||||||
|
|
||||||
|
ResetDarts3D PROC
|
||||||
|
mov dtState3D,DT_AIM
|
||||||
|
mov dtTimer3D,0
|
||||||
|
mov dtRemaining3D,500
|
||||||
|
mov dtVisitStart3D,500
|
||||||
|
mov dtScores3D,500
|
||||||
|
mov dtScores3D[4],500
|
||||||
|
mov dtActor3D,0
|
||||||
|
mov dtWinner3D,0
|
||||||
|
mov dtBotTimer3D,0
|
||||||
|
mov dtBotPrepared3D,0
|
||||||
|
mov dtScoreOpen3D,0
|
||||||
|
mov dtHistoryRows3D,1
|
||||||
|
mov dtHistory3D,500
|
||||||
|
mov dtHistory3D[4],500
|
||||||
|
mov dtWallDirty3D,1
|
||||||
|
mov dtCount3D,0
|
||||||
|
mov dtThrows3D,0
|
||||||
|
mov dtVisit3D,1
|
||||||
|
mov dtLast3D,0
|
||||||
|
mov dtBust3D,0
|
||||||
|
mov dtHolding3D,0
|
||||||
|
mov dtMouseReleased3D,0
|
||||||
|
mov dtHoldTime3D,0
|
||||||
|
mov dtCamX3D,0
|
||||||
|
mov dtCamY3D,0
|
||||||
|
mov dtCamZ3D,0
|
||||||
|
mov dtLens3D,DT_FOCAL
|
||||||
|
mov dtLookX3D,0
|
||||||
|
mov dtLookY3D,0
|
||||||
|
ret
|
||||||
|
ResetDarts3D ENDP
|
||||||
|
|
||||||
|
BeginDarts3D PROC
|
||||||
|
call LoadDarts3D
|
||||||
|
xor eax,1
|
||||||
|
mov dtError3D,eax
|
||||||
|
call ResetDarts3D
|
||||||
|
mov engineMode,MODE_DARTS
|
||||||
|
mov paused3D,0
|
||||||
|
mov mouseX3D,160
|
||||||
|
mov mouseY3D,107
|
||||||
|
mov dtCursorX3D,320*256
|
||||||
|
mov dtCursorY3D,214*256
|
||||||
|
call ClearKeys3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
ret
|
||||||
|
BeginDarts3D ENDP
|
||||||
|
|
||||||
|
DartsAim3D PROC uses ebx
|
||||||
|
local amplitude:DWORD,phase:DWORD,secondary:DWORD
|
||||||
|
; Smooth mixed phases and gradual hold fatigue; never scatter after release.
|
||||||
|
mov amplitude,10
|
||||||
|
cmp dtHolding3D,0
|
||||||
|
je dt_aim_phase
|
||||||
|
mov eax,dtHoldTime3D
|
||||||
|
sub eax,1200
|
||||||
|
jle dt_aim_phase
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,350
|
||||||
|
div ecx
|
||||||
|
cmp eax,8
|
||||||
|
jbe @F
|
||||||
|
mov eax,8
|
||||||
|
@@:
|
||||||
|
add amplitude,eax
|
||||||
|
dt_aim_phase:
|
||||||
|
mov eax,dtClock3D
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,3
|
||||||
|
div ecx
|
||||||
|
and eax,511
|
||||||
|
mov phase,eax
|
||||||
|
mov ebx,tableSin[eax*4]
|
||||||
|
imul ebx,amplitude
|
||||||
|
sar ebx,16
|
||||||
|
mov eax,dtClock3D
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,5
|
||||||
|
div ecx
|
||||||
|
add eax,91
|
||||||
|
and eax,511
|
||||||
|
mov secondary,eax
|
||||||
|
mov eax,tableSin[eax*4]
|
||||||
|
imul eax,3
|
||||||
|
sar eax,16
|
||||||
|
add ebx,eax
|
||||||
|
mov eax,dtCursorX3D
|
||||||
|
sub eax,320*256
|
||||||
|
imul eax,DT_WALL
|
||||||
|
cdq
|
||||||
|
mov ecx,DT_FOCAL*256
|
||||||
|
idiv ecx
|
||||||
|
cmp dtActor3D,0
|
||||||
|
je @F
|
||||||
|
mov eax,dtBotAimX3D
|
||||||
|
@@:
|
||||||
|
add eax,ebx
|
||||||
|
cmp eax,-290
|
||||||
|
jge @F
|
||||||
|
mov eax,-290
|
||||||
|
@@:
|
||||||
|
cmp eax,290
|
||||||
|
jle @F
|
||||||
|
mov eax,290
|
||||||
|
@@:
|
||||||
|
mov dtAimX3D,eax
|
||||||
|
mov eax,phase
|
||||||
|
mov ebx,tableCos[eax*4]
|
||||||
|
mov ecx,amplitude
|
||||||
|
sub ecx,2
|
||||||
|
imul ebx,ecx
|
||||||
|
sar ebx,16
|
||||||
|
mov eax,secondary
|
||||||
|
sub eax,58
|
||||||
|
and eax,511
|
||||||
|
mov eax,tableSin[eax*4]
|
||||||
|
imul eax,3
|
||||||
|
sar eax,16
|
||||||
|
add ebx,eax
|
||||||
|
mov eax,dtCursorY3D
|
||||||
|
mov edx,214*256
|
||||||
|
sub edx,eax
|
||||||
|
imul eax,edx,DT_WALL
|
||||||
|
cdq
|
||||||
|
mov ecx,DT_FOCAL*256
|
||||||
|
idiv ecx
|
||||||
|
cmp dtActor3D,0
|
||||||
|
je @F
|
||||||
|
mov eax,dtBotAimY3D
|
||||||
|
@@:
|
||||||
|
add eax,ebx
|
||||||
|
cmp eax,-245
|
||||||
|
jge @F
|
||||||
|
mov eax,-245
|
||||||
|
@@:
|
||||||
|
cmp eax,245
|
||||||
|
jle @F
|
||||||
|
mov eax,245
|
||||||
|
@@:
|
||||||
|
mov dtAimY3D,eax
|
||||||
|
ret
|
||||||
|
DartsAim3D ENDP
|
||||||
|
|
||||||
|
; Select a target from the visible score, then commit imperfect aim before release.
|
||||||
|
DartsBotAim3D PROC uses ebx esi
|
||||||
|
local ring:DWORD,target:DWORD
|
||||||
|
mov target,20
|
||||||
|
mov ring,103
|
||||||
|
mov eax,dtRemaining3D
|
||||||
|
cmp eax,20
|
||||||
|
ja dt_bot_double
|
||||||
|
mov target,eax
|
||||||
|
mov ring,53
|
||||||
|
jmp dt_bot_sector
|
||||||
|
dt_bot_double:
|
||||||
|
cmp eax,40
|
||||||
|
ja dt_bot_special
|
||||||
|
test eax,1
|
||||||
|
jnz dt_bot_special
|
||||||
|
shr eax,1
|
||||||
|
mov target,eax
|
||||||
|
mov ring,166
|
||||||
|
jmp dt_bot_sector
|
||||||
|
dt_bot_special:
|
||||||
|
cmp eax,50
|
||||||
|
jne @F
|
||||||
|
mov dtBotDesired3D,50
|
||||||
|
mov dtBotAimX3D,0
|
||||||
|
mov dtBotAimY3D,0
|
||||||
|
jmp dt_bot_scatter
|
||||||
|
@@:
|
||||||
|
cmp eax,25
|
||||||
|
jne @F
|
||||||
|
mov dtBotDesired3D,25
|
||||||
|
mov dtBotAimX3D,0
|
||||||
|
mov dtBotAimY3D,11
|
||||||
|
jmp dt_bot_scatter
|
||||||
|
@@:
|
||||||
|
cmp eax,60
|
||||||
|
ja dt_bot_sector
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,3
|
||||||
|
div ecx
|
||||||
|
test edx,edx
|
||||||
|
jnz dt_bot_single20
|
||||||
|
mov target,eax
|
||||||
|
jmp dt_bot_sector
|
||||||
|
dt_bot_single20:
|
||||||
|
mov ring,53
|
||||||
|
dt_bot_sector:
|
||||||
|
mov eax,target
|
||||||
|
cmp ring,103
|
||||||
|
jne @F
|
||||||
|
imul eax,3
|
||||||
|
@@:
|
||||||
|
cmp ring,166
|
||||||
|
jne @F
|
||||||
|
shl eax,1
|
||||||
|
@@:
|
||||||
|
mov dtBotDesired3D,eax
|
||||||
|
xor ebx,ebx
|
||||||
|
@@:
|
||||||
|
mov eax,dtSector3D[ebx*4]
|
||||||
|
cmp eax,target
|
||||||
|
je dt_bot_direction
|
||||||
|
inc ebx
|
||||||
|
cmp ebx,20
|
||||||
|
jb @B
|
||||||
|
xor ebx,ebx
|
||||||
|
dt_bot_direction:
|
||||||
|
imul eax,ebx,512
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,20
|
||||||
|
div ecx
|
||||||
|
mov esi,eax
|
||||||
|
mov eax,tableSin[esi*4]
|
||||||
|
imul eax,ring
|
||||||
|
sar eax,16
|
||||||
|
mov dtBotAimX3D,eax
|
||||||
|
mov eax,tableCos[esi*4]
|
||||||
|
imul eax,ring
|
||||||
|
sar eax,16
|
||||||
|
mov dtBotAimY3D,eax
|
||||||
|
dt_bot_scatter:
|
||||||
|
invoke RandomRange3D,17
|
||||||
|
sub eax,8
|
||||||
|
add dtBotAimX3D,eax
|
||||||
|
invoke RandomRange3D,17
|
||||||
|
sub eax,8
|
||||||
|
add dtBotAimY3D,eax
|
||||||
|
mov dtBotPrepared3D,1
|
||||||
|
ret
|
||||||
|
DartsBotAim3D ENDP
|
||||||
|
|
||||||
|
ThrowDarts3D PROC
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
jne dt_throw_done
|
||||||
|
cmp dtError3D,0
|
||||||
|
jne dt_throw_done
|
||||||
|
mov eax,dtAimX3D
|
||||||
|
mov dtHitX3D,eax
|
||||||
|
mov eax,dtAimY3D
|
||||||
|
mov dtHitY3D,eax
|
||||||
|
mov dtState3D,DT_RELEASE
|
||||||
|
mov dtTimer3D,0
|
||||||
|
mov dtHolding3D,0
|
||||||
|
mov dtMouseReleased3D,0
|
||||||
|
inc dtThrows3D
|
||||||
|
dt_throw_done:
|
||||||
|
ret
|
||||||
|
ThrowDarts3D ENDP
|
||||||
|
|
||||||
|
; Board units are millimetres: 6.35/15.9 bull, 99..107 triple, 162..170 double.
|
||||||
|
DartsScore3D PROC uses ebx x:SDWORD,y:SDWORD
|
||||||
|
local angle:DWORD,oldControl:WORD,truncate:WORD
|
||||||
|
cmp x,-170
|
||||||
|
jl dt_score_miss
|
||||||
|
cmp x,170
|
||||||
|
jg dt_score_miss
|
||||||
|
cmp y,-170
|
||||||
|
jl dt_score_miss
|
||||||
|
cmp y,170
|
||||||
|
jg dt_score_miss
|
||||||
|
mov eax,x
|
||||||
|
imul eax,eax
|
||||||
|
mov ebx,y
|
||||||
|
imul ebx,ebx
|
||||||
|
add ebx,eax
|
||||||
|
cmp ebx,170*170
|
||||||
|
ja dt_score_miss
|
||||||
|
cmp ebx,40
|
||||||
|
jbe dt_score_bull
|
||||||
|
cmp ebx,253
|
||||||
|
jbe dt_score_outer_bull
|
||||||
|
fnstcw oldControl
|
||||||
|
mov ax,oldControl
|
||||||
|
or ax,0C00h
|
||||||
|
mov truncate,ax
|
||||||
|
fldcw truncate
|
||||||
|
fild x
|
||||||
|
fild y
|
||||||
|
fpatan
|
||||||
|
fmul dtAngleFactor3D
|
||||||
|
fistp angle
|
||||||
|
fldcw oldControl
|
||||||
|
mov eax,angle
|
||||||
|
add eax,65536+1638
|
||||||
|
and eax,65535
|
||||||
|
imul eax,20
|
||||||
|
shr eax,16
|
||||||
|
mov eax,dtSector3D[eax*4]
|
||||||
|
mov edx,1
|
||||||
|
cmp ebx,162*162
|
||||||
|
jae dt_score_double
|
||||||
|
cmp ebx,99*99
|
||||||
|
jb dt_score_done
|
||||||
|
cmp ebx,107*107
|
||||||
|
ja dt_score_done
|
||||||
|
mov edx,3
|
||||||
|
imul eax,3
|
||||||
|
ret
|
||||||
|
dt_score_double:
|
||||||
|
mov edx,2
|
||||||
|
shl eax,1
|
||||||
|
ret
|
||||||
|
dt_score_bull:
|
||||||
|
mov eax,50
|
||||||
|
mov edx,2
|
||||||
|
ret
|
||||||
|
dt_score_outer_bull:
|
||||||
|
mov eax,25
|
||||||
|
mov edx,1
|
||||||
|
ret
|
||||||
|
dt_score_miss:
|
||||||
|
xor eax,eax
|
||||||
|
xor edx,edx
|
||||||
|
dt_score_done:
|
||||||
|
ret
|
||||||
|
DartsScore3D ENDP
|
||||||
|
|
||||||
|
SettleDarts3D PROC uses ebx
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
jne dt_settle_done
|
||||||
|
invoke DartsScore3D,dtHitX3D,dtHitY3D
|
||||||
|
mov dtLast3D,eax
|
||||||
|
mov dtMultiplier3D,edx
|
||||||
|
mov ebx,dtCount3D
|
||||||
|
cmp ebx,3
|
||||||
|
jae dt_settle_done
|
||||||
|
mov dtMarkScore3D[ebx*4],eax
|
||||||
|
mov ecx,dtHitX3D
|
||||||
|
mov dtMarkX3D[ebx*4],ecx
|
||||||
|
mov ecx,dtHitY3D
|
||||||
|
mov dtMarkY3D[ebx*4],ecx
|
||||||
|
inc dtCount3D
|
||||||
|
mov ecx,dtRemaining3D
|
||||||
|
sub ecx,eax
|
||||||
|
js dt_bust
|
||||||
|
dt_score_accept:
|
||||||
|
mov dtRemaining3D,ecx
|
||||||
|
jmp dt_begin_impact
|
||||||
|
dt_bust:
|
||||||
|
mov eax,dtVisitStart3D
|
||||||
|
mov dtRemaining3D,eax
|
||||||
|
mov dtBust3D,1
|
||||||
|
dt_begin_impact:
|
||||||
|
mov ebx,dtActor3D
|
||||||
|
mov eax,dtRemaining3D
|
||||||
|
mov dtScores3D[ebx*4],eax
|
||||||
|
mov dtWallDirty3D,1
|
||||||
|
test eax,eax
|
||||||
|
jnz @F
|
||||||
|
mov dtWinner3D,ebx
|
||||||
|
@@:
|
||||||
|
cmp dtRemaining3D,0
|
||||||
|
je dt_record_visit
|
||||||
|
cmp dtCount3D,3
|
||||||
|
je dt_record_visit
|
||||||
|
cmp dtBust3D,0
|
||||||
|
je dt_no_record
|
||||||
|
dt_record_visit:
|
||||||
|
call DartsRecordScore3D
|
||||||
|
dt_no_record:
|
||||||
|
mov dtState3D,DT_IMPACT
|
||||||
|
mov dtTimer3D,0
|
||||||
|
invoke PlayCasinoSound3D,OFFSET soundClick,0,1
|
||||||
|
dt_settle_done:
|
||||||
|
ret
|
||||||
|
SettleDarts3D ENDP
|
||||||
|
|
||||||
|
DartsRecordScore3D PROC uses ebx esi edi
|
||||||
|
mov ebx,dtHistoryRows3D
|
||||||
|
cmp ebx,32
|
||||||
|
jb @F
|
||||||
|
lea esi,dtHistory3D[8]
|
||||||
|
lea edi,dtHistory3D
|
||||||
|
mov ecx,62
|
||||||
|
cld
|
||||||
|
rep movsd
|
||||||
|
mov ebx,31
|
||||||
|
@@:
|
||||||
|
mov eax,dtScores3D
|
||||||
|
mov dtHistory3D[ebx*8],eax
|
||||||
|
mov eax,dtScores3D[4]
|
||||||
|
mov dtHistory3D[ebx*8+4],eax
|
||||||
|
inc ebx
|
||||||
|
mov dtHistoryRows3D,ebx
|
||||||
|
mov dtWallDirty3D,1
|
||||||
|
ret
|
||||||
|
DartsRecordScore3D ENDP
|
||||||
|
|
||||||
|
HandleDarts3D PROC
|
||||||
|
invoke Pressed3D,9
|
||||||
|
test eax,eax
|
||||||
|
jz @F
|
||||||
|
xor dtScoreOpen3D,1
|
||||||
|
mov dtHolding3D,0
|
||||||
|
mov dtMouseReleased3D,0
|
||||||
|
@@:
|
||||||
|
cmp dtScoreOpen3D,0
|
||||||
|
jne dt_handle_done
|
||||||
|
invoke Pressed3D,52h
|
||||||
|
test eax,eax
|
||||||
|
jz @F
|
||||||
|
call ResetDarts3D
|
||||||
|
@@:
|
||||||
|
cmp mouseClick3D,0
|
||||||
|
je dt_handle_game
|
||||||
|
cmp mouseY3D,218
|
||||||
|
jb dt_handle_game
|
||||||
|
cmp mouseX3D,230
|
||||||
|
jb dt_handle_game
|
||||||
|
call ResetDarts3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
dt_handle_game:
|
||||||
|
cmp dtError3D,0
|
||||||
|
jne dt_handle_done
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add dtClock3D,eax
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
jne dt_animate
|
||||||
|
cmp dtActor3D,0
|
||||||
|
je dt_player_aim
|
||||||
|
cmp dtBotPrepared3D,0
|
||||||
|
jne @F
|
||||||
|
call DartsBotAim3D
|
||||||
|
@@:
|
||||||
|
call DartsAim3D
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add dtBotTimer3D,eax
|
||||||
|
cmp dtBotTimer3D,900
|
||||||
|
jb dt_handle_done
|
||||||
|
mov dtHolding3D,1
|
||||||
|
mov eax,dtBotTimer3D
|
||||||
|
sub eax,900
|
||||||
|
cmp eax,280
|
||||||
|
jbe @F
|
||||||
|
mov eax,280
|
||||||
|
@@:
|
||||||
|
mov dtHoldTime3D,eax
|
||||||
|
cmp dtBotTimer3D,1220
|
||||||
|
jb dt_handle_done
|
||||||
|
invoke DartsScore3D,dtAimX3D,dtAimY3D
|
||||||
|
cmp eax,dtBotDesired3D
|
||||||
|
je dt_bot_commit
|
||||||
|
cmp dtBotTimer3D,1600
|
||||||
|
jb dt_handle_done
|
||||||
|
dt_bot_commit:
|
||||||
|
call ThrowDarts3D
|
||||||
|
jmp dt_handle_done
|
||||||
|
dt_player_aim:
|
||||||
|
cmp mouseClick3D,0
|
||||||
|
je @F
|
||||||
|
mov dtHolding3D,1
|
||||||
|
mov dtHoldTime3D,0
|
||||||
|
@@:
|
||||||
|
cmp dtHolding3D,0
|
||||||
|
je dt_player_hover
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add dtHoldTime3D,eax
|
||||||
|
cmp dtHoldTime3D,4000
|
||||||
|
jbe @F
|
||||||
|
mov dtHoldTime3D,4000
|
||||||
|
@@:
|
||||||
|
dt_player_hover:
|
||||||
|
call DartsAim3D
|
||||||
|
cmp dtHolding3D,0
|
||||||
|
jne dt_player_release
|
||||||
|
mov dtMouseReleased3D,0
|
||||||
|
jmp dt_handle_done
|
||||||
|
dt_player_release:
|
||||||
|
cmp dtMouseReleased3D,0
|
||||||
|
je dt_handle_done
|
||||||
|
call ThrowDarts3D
|
||||||
|
jmp dt_handle_done
|
||||||
|
dt_animate:
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add dtTimer3D,eax
|
||||||
|
cmp dtState3D,DT_RELEASE
|
||||||
|
jne dt_animate_flight
|
||||||
|
cmp dtTimer3D,200
|
||||||
|
jb dt_handle_done
|
||||||
|
sub dtTimer3D,200
|
||||||
|
mov dtState3D,DT_FLIGHT
|
||||||
|
jmp dt_handle_done
|
||||||
|
dt_animate_flight:
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
jne dt_animate_impact
|
||||||
|
cmp dtTimer3D,DT_THROW_MS
|
||||||
|
jb dt_handle_done
|
||||||
|
call SettleDarts3D
|
||||||
|
jmp dt_handle_done
|
||||||
|
dt_animate_impact:
|
||||||
|
cmp dtState3D,DT_IMPACT
|
||||||
|
jne dt_animate_return
|
||||||
|
cmp dtTimer3D,1300
|
||||||
|
jb dt_handle_done
|
||||||
|
mov dtState3D,DT_WIN
|
||||||
|
cmp dtRemaining3D,0
|
||||||
|
je dt_handle_done
|
||||||
|
mov dtState3D,DT_RETURN
|
||||||
|
mov dtTimer3D,0
|
||||||
|
jmp dt_handle_done
|
||||||
|
dt_animate_return:
|
||||||
|
cmp dtState3D,DT_RETURN
|
||||||
|
jne dt_handle_done
|
||||||
|
cmp dtTimer3D,750
|
||||||
|
jb dt_handle_done
|
||||||
|
cmp dtBust3D,0
|
||||||
|
jne dt_next_visit
|
||||||
|
cmp dtCount3D,3
|
||||||
|
jb dt_return_aim
|
||||||
|
dt_next_visit:
|
||||||
|
mov dtBust3D,0
|
||||||
|
mov dtCount3D,0
|
||||||
|
inc dtVisit3D
|
||||||
|
xor dtActor3D,1
|
||||||
|
mov eax,dtActor3D
|
||||||
|
mov eax,dtScores3D[eax*4]
|
||||||
|
mov dtRemaining3D,eax
|
||||||
|
mov dtVisitStart3D,eax
|
||||||
|
dt_return_aim:
|
||||||
|
mov dtState3D,DT_AIM
|
||||||
|
mov dtTimer3D,0
|
||||||
|
mov dtMouseReleased3D,0
|
||||||
|
mov dtHolding3D,0
|
||||||
|
mov dtHoldTime3D,0
|
||||||
|
mov dtBotPrepared3D,0
|
||||||
|
mov dtBotTimer3D,0
|
||||||
|
dt_handle_done:
|
||||||
|
mov mouseClick3D,0
|
||||||
|
ret
|
||||||
|
HandleDarts3D ENDP
|
||||||
|
|
||||||
|
DartsPath3D PROC uses ebx esi timeMs:DWORD
|
||||||
|
local progress:DWORD,pathX:DWORD,pathY:DWORD,pathZ:DWORD
|
||||||
|
mov eax,timeMs
|
||||||
|
cmp eax,DT_THROW_MS
|
||||||
|
jbe @F
|
||||||
|
mov eax,DT_THROW_MS
|
||||||
|
@@:
|
||||||
|
shl eax,16
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,DT_THROW_MS
|
||||||
|
div ecx
|
||||||
|
mov progress,eax
|
||||||
|
mov ebx,eax
|
||||||
|
imul eax,DT_WALL
|
||||||
|
sar eax,16
|
||||||
|
mov pathZ,eax
|
||||||
|
mov eax,dtHitX3D
|
||||||
|
sub eax,70
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
add eax,70
|
||||||
|
mov pathX,eax
|
||||||
|
mov eax,65536
|
||||||
|
sub eax,ebx
|
||||||
|
imul ebx
|
||||||
|
shrd eax,edx,16
|
||||||
|
imul eax,280
|
||||||
|
sar eax,16
|
||||||
|
mov esi,eax
|
||||||
|
mov eax,dtHitY3D
|
||||||
|
add eax,35
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
sub eax,35
|
||||||
|
add eax,esi
|
||||||
|
mov edx,eax
|
||||||
|
mov eax,pathX
|
||||||
|
mov ecx,pathZ
|
||||||
|
ret
|
||||||
|
DartsPath3D ENDP
|
||||||
|
|
||||||
|
; Real orbit: behind -> alongside the dart -> behind the impact, with one camera basis.
|
||||||
|
DartsCamera3D PROC uses ebx esi
|
||||||
|
local progress:DWORD,weight:DWORD,timeMs:DWORD,factor:DWORD
|
||||||
|
local length2:DWORD,span:DWORD,targetZ:DWORD,deltaX:DWORD,deltaZ:DWORD
|
||||||
|
mov timeMs,0
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
jne @F
|
||||||
|
mov eax,dtTimer3D
|
||||||
|
mov timeMs,eax
|
||||||
|
jmp dt_camera_path
|
||||||
|
@@:
|
||||||
|
cmp dtState3D,DT_IMPACT
|
||||||
|
je dt_camera_end
|
||||||
|
cmp dtState3D,DT_WIN
|
||||||
|
je dt_camera_end
|
||||||
|
cmp dtState3D,DT_RETURN
|
||||||
|
jne dt_camera_path
|
||||||
|
dt_camera_end:
|
||||||
|
mov timeMs,DT_THROW_MS
|
||||||
|
dt_camera_path:
|
||||||
|
invoke DartsPath3D,timeMs
|
||||||
|
mov dtShotX3D,eax
|
||||||
|
mov dtShotY3D,edx
|
||||||
|
mov dtShotZ3D,ecx
|
||||||
|
mov eax,timeMs
|
||||||
|
cmp eax,DT_THROW_MS
|
||||||
|
jbe @F
|
||||||
|
mov eax,DT_THROW_MS
|
||||||
|
@@:
|
||||||
|
shl eax,16
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,DT_THROW_MS
|
||||||
|
div ecx
|
||||||
|
mov progress,eax
|
||||||
|
mov ebx,eax
|
||||||
|
shr eax,8
|
||||||
|
mov eax,tableSin[eax*4]
|
||||||
|
imul eax
|
||||||
|
shrd eax,edx,16
|
||||||
|
mov weight,eax
|
||||||
|
imul eax,260
|
||||||
|
sar eax,16
|
||||||
|
mov ecx,420
|
||||||
|
sub ecx,eax
|
||||||
|
mov eax,dtShotZ3D
|
||||||
|
sub eax,ecx
|
||||||
|
jns @F
|
||||||
|
xor eax,eax
|
||||||
|
@@:
|
||||||
|
mov dtCamZ3D,eax
|
||||||
|
mov eax,weight
|
||||||
|
imul eax,300
|
||||||
|
sar eax,16
|
||||||
|
mov ecx,dtShotX3D
|
||||||
|
sub ecx,70
|
||||||
|
sub ecx,eax
|
||||||
|
mov dtCamX3D,ecx
|
||||||
|
mov eax,weight
|
||||||
|
imul eax,80
|
||||||
|
sar eax,16
|
||||||
|
add eax,dtShotY3D
|
||||||
|
add eax,35
|
||||||
|
mov dtCamY3D,eax
|
||||||
|
mov eax,dtHitX3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,17
|
||||||
|
mov esi,eax
|
||||||
|
mov ecx,dtShotX3D
|
||||||
|
sub ecx,eax
|
||||||
|
imul ecx,weight
|
||||||
|
sar ecx,16
|
||||||
|
add ecx,esi
|
||||||
|
mov dtLookX3D,ecx
|
||||||
|
mov eax,dtHitY3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,17
|
||||||
|
mov esi,eax
|
||||||
|
mov ecx,dtShotY3D
|
||||||
|
sub ecx,eax
|
||||||
|
imul ecx,weight
|
||||||
|
sar ecx,16
|
||||||
|
add ecx,esi
|
||||||
|
mov dtLookY3D,ecx
|
||||||
|
mov eax,dtShotZ3D
|
||||||
|
sub eax,DT_WALL
|
||||||
|
imul eax,weight
|
||||||
|
sar eax,16
|
||||||
|
add eax,DT_WALL
|
||||||
|
mov targetZ,eax
|
||||||
|
cmp dtState3D,DT_RETURN
|
||||||
|
jne dt_camera_basis
|
||||||
|
mov eax,dtTimer3D
|
||||||
|
cmp eax,750
|
||||||
|
jbe @F
|
||||||
|
mov eax,750
|
||||||
|
@@:
|
||||||
|
mov ecx,750
|
||||||
|
sub ecx,eax
|
||||||
|
imul eax,ecx,65536
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,750
|
||||||
|
div ecx
|
||||||
|
mov ebx,eax
|
||||||
|
mov eax,dtCamX3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov dtCamX3D,eax
|
||||||
|
mov eax,dtCamY3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov dtCamY3D,eax
|
||||||
|
mov eax,dtCamZ3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov dtCamZ3D,eax
|
||||||
|
mov eax,dtLookX3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov dtLookX3D,eax
|
||||||
|
mov eax,dtLookY3D
|
||||||
|
imul eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov dtLookY3D,eax
|
||||||
|
dt_camera_basis:
|
||||||
|
mov eax,dtCamZ3D
|
||||||
|
imul eax,550
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,DT_WALL-420
|
||||||
|
div ecx
|
||||||
|
mov ecx,DT_FOCAL
|
||||||
|
sub ecx,eax
|
||||||
|
mov eax,weight
|
||||||
|
imul eax,160
|
||||||
|
sar eax,16
|
||||||
|
sub ecx,eax
|
||||||
|
cmp ecx,350
|
||||||
|
jge @F
|
||||||
|
mov ecx,350
|
||||||
|
@@:
|
||||||
|
mov dtLens3D,ecx
|
||||||
|
mov eax,dtLookX3D
|
||||||
|
sub eax,dtCamX3D
|
||||||
|
mov deltaX,eax
|
||||||
|
imul eax,eax
|
||||||
|
mov ebx,targetZ
|
||||||
|
sub ebx,dtCamZ3D
|
||||||
|
mov deltaZ,ebx
|
||||||
|
imul ebx,ebx
|
||||||
|
add eax,ebx
|
||||||
|
mov length2,eax
|
||||||
|
fild length2
|
||||||
|
fsqrt
|
||||||
|
fistp span
|
||||||
|
cmp span,1
|
||||||
|
jge @F
|
||||||
|
mov span,1
|
||||||
|
@@:
|
||||||
|
mov eax,deltaX
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv span
|
||||||
|
mov dtYawSin3D,eax
|
||||||
|
mov eax,deltaZ
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv span
|
||||||
|
mov dtYawCos3D,eax
|
||||||
|
mov eax,dtLookY3D
|
||||||
|
sub eax,dtCamY3D
|
||||||
|
imul eax,dtLens3D
|
||||||
|
cdq
|
||||||
|
idiv span
|
||||||
|
add eax,214
|
||||||
|
mov dtScreenY3D,eax
|
||||||
|
mov dtScreenX3D,320
|
||||||
|
ret
|
||||||
|
DartsCamera3D ENDP
|
||||||
|
|
||||||
|
DartsProject3D PROC uses ebx x:SDWORD,y:SDWORD,z:SDWORD
|
||||||
|
local deltaX:DWORD,deltaZ:DWORD,depth:DWORD,side:DWORD
|
||||||
|
mov eax,x
|
||||||
|
sub eax,dtCamX3D
|
||||||
|
mov deltaX,eax
|
||||||
|
mov ebx,z
|
||||||
|
sub ebx,dtCamZ3D
|
||||||
|
mov deltaZ,ebx
|
||||||
|
imul eax,dtYawCos3D
|
||||||
|
imul ebx,dtYawSin3D
|
||||||
|
sub eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov side,eax
|
||||||
|
mov eax,deltaX
|
||||||
|
imul eax,dtYawSin3D
|
||||||
|
mov ebx,deltaZ
|
||||||
|
imul ebx,dtYawCos3D
|
||||||
|
add eax,ebx
|
||||||
|
sar eax,16
|
||||||
|
mov depth,eax
|
||||||
|
cmp eax,16
|
||||||
|
jg @F
|
||||||
|
mov eax,16
|
||||||
|
@@:
|
||||||
|
mov ecx,eax
|
||||||
|
mov eax,side
|
||||||
|
imul eax,dtLens3D
|
||||||
|
cdq
|
||||||
|
idiv ecx
|
||||||
|
add eax,320
|
||||||
|
push eax
|
||||||
|
mov eax,y
|
||||||
|
sub eax,dtCamY3D
|
||||||
|
imul eax,dtLens3D
|
||||||
|
cdq
|
||||||
|
idiv ecx
|
||||||
|
mov edx,dtScreenY3D
|
||||||
|
sub edx,eax
|
||||||
|
pop eax
|
||||||
|
mov ecx,depth
|
||||||
|
ret
|
||||||
|
DartsProject3D ENDP
|
||||||
|
|
||||||
|
ResolveDartsSurface3D PROC
|
||||||
|
cmp dtBoard3D.pixels,0
|
||||||
|
jne @F
|
||||||
|
invoke LoadAnimPack3D,OFFSET dtBoard3D,OFFSET dtBoardPath
|
||||||
|
@@:
|
||||||
|
mov eax,dtBoard3D.pixels
|
||||||
|
mov ecx,512
|
||||||
|
mov edx,512
|
||||||
|
ret
|
||||||
|
ResolveDartsSurface3D ENDP
|
||||||
|
|
||||||
|
DrawHallDarts3D PROC
|
||||||
|
cmp hallLevel3D,0
|
||||||
|
jne @F
|
||||||
|
invoke DrawCityVertical3D,0,FP_1*3098/100,FP_1*275/10,FP_1*285/10,FP_1*115/100,FP_1*215/100,160
|
||||||
|
@@:
|
||||||
|
ret
|
||||||
|
DrawHallDarts3D ENDP
|
||||||
|
|
||||||
|
include src_graphics\darts_render.inc
|
||||||
3
src_graphics/darts_art.inc
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
; Generated per-view needle anchors in the 256px source canvas.
|
||||||
|
dtDartTipX3D dd 94,70,41,24,28,21,11,3,15,9,8,11,17,10,9,7
|
||||||
|
dtDartTipY3D dd 142,139,139,139,135,135,134,133,132,131,130,130,116,118,123,128
|
||||||
145
src_graphics/darts_data.inc
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
; All game and camera logic is native MASM; offline tooling only packs artwork.
|
||||||
|
MODE_DARTS equ 27
|
||||||
|
INTERACT_DARTS equ 47
|
||||||
|
DT_AIM equ 0
|
||||||
|
DT_RELEASE equ 1
|
||||||
|
DT_FLIGHT equ 2
|
||||||
|
DT_IMPACT equ 3
|
||||||
|
DT_RETURN equ 4
|
||||||
|
DT_WIN equ 5
|
||||||
|
DT_WALL equ 2700
|
||||||
|
DT_FOCAL equ 950
|
||||||
|
DT_THROW_MS equ 1200
|
||||||
|
BeginDarts3D PROTO
|
||||||
|
HandleDarts3D PROTO
|
||||||
|
RenderDarts3D PROTO
|
||||||
|
LoadDarts3D PROTO
|
||||||
|
FreeDarts3D PROTO
|
||||||
|
ResetDarts3D PROTO
|
||||||
|
DartsAim3D PROTO
|
||||||
|
ThrowDarts3D PROTO
|
||||||
|
DartsCamera3D PROTO
|
||||||
|
DartsPath3D PROTO :DWORD
|
||||||
|
PrepareDartsRays3D PROTO
|
||||||
|
DrawDartsTrail3D PROTO
|
||||||
|
DrawDartsLine3D PROTO :SDWORD,:SDWORD,:SDWORD,:SDWORD,:DWORD
|
||||||
|
DartsBotAim3D PROTO
|
||||||
|
DartsRecordScore3D PROTO
|
||||||
|
UpdateDartsWall3D PROTO
|
||||||
|
DartsWallText3D PROTO :DWORD,:DWORD,:DWORD
|
||||||
|
DrawDartsScoreboard3D PROTO
|
||||||
|
DrawDartsProps3D PROTO
|
||||||
|
DrawDartsArm3D PROTO :DWORD,:SDWORD,:SDWORD
|
||||||
|
DartsScore3D PROTO :SDWORD,:SDWORD
|
||||||
|
SettleDarts3D PROTO
|
||||||
|
DrawDartsRoom3D PROTO
|
||||||
|
DrawDartsModel3D PROTO :SDWORD,:SDWORD,:SDWORD
|
||||||
|
DartsProject3D PROTO :SDWORD,:SDWORD,:SDWORD
|
||||||
|
DrawHallDarts3D PROTO
|
||||||
|
ResolveDartsSurface3D PROTO
|
||||||
|
.data
|
||||||
|
dtBoard3D AnimPack3D <>
|
||||||
|
dtHands3D AnimPack3D <>
|
||||||
|
dtDart3D AnimPack3D <>
|
||||||
|
dtWall3D AnimPack3D <>
|
||||||
|
dtChair3D AnimPack3D <>
|
||||||
|
dtTable3D AnimPack3D <>
|
||||||
|
dtRoom3D AnimPack3D <>
|
||||||
|
dtBoardPath db "assets\animations\darts\board-v1.bin",0
|
||||||
|
dtHandsPath db "assets\animations\darts\arm-throw-v3.bin",0
|
||||||
|
dtDartPath db "assets\animations\darts\dart-views-v1.bin",0
|
||||||
|
dtWallPath db "assets\animations\darts\lounge-wall-v1.bin",0
|
||||||
|
dtChairPath db "assets\animations\hall\lounge-chair-v5.bin",0
|
||||||
|
dtTablePath db "assets\animations\hall\lamp-table-v5.bin",0
|
||||||
|
dtRoomPath db "assets\animations\hall\room-materials-hd.bin",0
|
||||||
|
dtState3D dd DT_AIM
|
||||||
|
dtTimer3D dd 0
|
||||||
|
dtClock3D dd 0
|
||||||
|
dtRemaining3D dd 500
|
||||||
|
dtVisitStart3D dd 500
|
||||||
|
dtScores3D dd 500,500
|
||||||
|
dtActor3D dd 0
|
||||||
|
dtWinner3D dd 0
|
||||||
|
dtBotTimer3D dd 0
|
||||||
|
dtBotPrepared3D dd 0
|
||||||
|
dtBotAimX3D dd 0
|
||||||
|
dtBotAimY3D dd 0
|
||||||
|
dtBotDesired3D dd 60
|
||||||
|
dtCursorX3D dd 320*256
|
||||||
|
dtCursorY3D dd 214*256
|
||||||
|
dtScoreOpen3D dd 0
|
||||||
|
dtHistoryRows3D dd 1
|
||||||
|
dtHistory3D dd 64 dup(0)
|
||||||
|
dtWallDirty3D dd 1
|
||||||
|
dtVisit3D dd 1
|
||||||
|
dtCount3D dd 0
|
||||||
|
dtThrows3D dd 0
|
||||||
|
dtLast3D dd 0
|
||||||
|
dtMultiplier3D dd 0
|
||||||
|
dtBust3D dd 0
|
||||||
|
dtError3D dd 0
|
||||||
|
dtHolding3D dd 0
|
||||||
|
dtHoldTime3D dd 0
|
||||||
|
dtMouseReleased3D dd 0
|
||||||
|
dtAimX3D dd 0
|
||||||
|
dtAimY3D dd 0
|
||||||
|
dtHitX3D dd 0
|
||||||
|
dtHitY3D dd 0
|
||||||
|
dtMarkX3D dd 3 dup(0)
|
||||||
|
dtMarkY3D dd 3 dup(0)
|
||||||
|
dtMarkScore3D dd 3 dup(0)
|
||||||
|
dtShotX3D dd 0
|
||||||
|
dtShotY3D dd 0
|
||||||
|
dtShotZ3D dd 0
|
||||||
|
dtCamX3D dd 0
|
||||||
|
dtCamY3D dd 0
|
||||||
|
dtCamZ3D dd 0
|
||||||
|
dtLens3D dd DT_FOCAL
|
||||||
|
dtYawSin3D dd 0
|
||||||
|
dtYawCos3D dd 65536
|
||||||
|
dtLookX3D dd 0
|
||||||
|
dtLookY3D dd 0
|
||||||
|
dtScreenX3D dd 320
|
||||||
|
dtScreenY3D dd 214
|
||||||
|
include src_graphics\darts_art.inc
|
||||||
|
dtSector3D dd 20,1,18,4,13,6,10,15,2,17,3,19,7,16,8,11,14,9,12,5
|
||||||
|
dtAngleFactor3D REAL8 10430.37835047045
|
||||||
|
dtTitle db 196,192,208,210,209,32,53,48,48,0
|
||||||
|
dtYou db 194,219,0
|
||||||
|
dtBot db 204,192,202,209,0
|
||||||
|
dtYourTurn db 194,192,216,32,213,206,196,0
|
||||||
|
dtBotTurn db 213,206,196,32,204,192,202,209,192,0
|
||||||
|
dtYouWin db 194,219,32,207,206,193,197,196,200,203,200,0
|
||||||
|
dtBotWin db 204,192,202,209,32,207,206,193,197,196,200,203,0
|
||||||
|
dtScoreTitle db 209,215,197,210,32,204,192,210,215,192,0
|
||||||
|
; Fixed wall-axis furniture planes: axis, fixed coordinate, range, bottom/top, pack.
|
||||||
|
dtProps3D dd 0,2150,-1800,-1000,-1730,-380,OFFSET dtChair3D
|
||||||
|
dd 1,1950,1050,1850,-1730,-380,OFFSET dtChair3D
|
||||||
|
dd 1,1950,100,900,-1730,-380,OFFSET dtChair3D
|
||||||
|
dd 1,1780,850,1200,-1730,-680,OFFSET dtTable3D
|
||||||
|
dtThrow db 193,208,206,209,206,202,0
|
||||||
|
dtLeft db 206,209,210,192,203,206,209,220,0
|
||||||
|
dtVisit db 207,206,196,213,206,196,0
|
||||||
|
dtWin db 195,206,210,206,194,206,33,32,208,206,194,205,206,32,205,206,203,220,0
|
||||||
|
dtBust db 207,197,208,197,193,206,208,0
|
||||||
|
dtMiss db 204,200,204,206,0
|
||||||
|
dtNext db 196,192,203,220,216,197,0
|
||||||
|
dtAgain db 209,205,206,194,192,0
|
||||||
|
dtExit db 194,32,213,206,203,203,0
|
||||||
|
dtPrompt db 69,58,32,196,192,208,210,209,0
|
||||||
|
dtLoading db 205,197,32,211,196,192,203,206,209,220,32,199,192,195,208,211,199,200,210,220,32,196,192,208,210,209,0
|
||||||
|
dtHold db 203,202,204,0
|
||||||
|
dtBull db 66,85,76,76,0
|
||||||
|
dtDouble db 68,0
|
||||||
|
dtTriple db 84,0
|
||||||
|
dtSingle db 83,0
|
||||||
|
dtTarget db 214,197,203,220,0
|
||||||
|
.data?
|
||||||
|
dtRayX3D dd 640 dup(?)
|
||||||
|
dtRayZ3D dd 640 dup(?)
|
||||||
|
dtRayDepth3D dd 640 dup(?)
|
||||||
|
dtRayU3D dd 640 dup(?)
|
||||||
|
dtRayFront3D dd 640 dup(?)
|
||||||
|
dtRayHitX3D dd 640 dup(?)
|
||||||
|
.code
|
||||||
|
|
||||||
330
src_graphics/darts_environment.inc
Normal file
|
|
@ -0,0 +1,330 @@
|
||||||
|
; A single rigid sprite transform aligns the dart axis with the live target.
|
||||||
|
DrawDartsArm3D PROC uses ebx esi edi pose:DWORD,targetX:SDWORD,targetY:SDWORD
|
||||||
|
local originX:DWORD,originY:DWORD,left:DWORD,right:DWORD,bottom:DWORD,row:DWORD,column:DWORD
|
||||||
|
local deltaX:DWORD,deltaY:DWORD,sourceX:DWORD,framePtr:DWORD
|
||||||
|
mov eax,pose
|
||||||
|
shl eax,18
|
||||||
|
add eax,dtHands3D.pixels
|
||||||
|
mov framePtr,eax
|
||||||
|
mov eax,targetX
|
||||||
|
sub eax,10
|
||||||
|
mov originX,eax
|
||||||
|
mov left,eax
|
||||||
|
add eax,363
|
||||||
|
mov right,eax
|
||||||
|
mov eax,targetY
|
||||||
|
add eax,49
|
||||||
|
mov originY,eax
|
||||||
|
add eax,182
|
||||||
|
cmp eax,400
|
||||||
|
jle @F
|
||||||
|
mov eax,400
|
||||||
|
@@:
|
||||||
|
mov bottom,eax
|
||||||
|
mov eax,originY
|
||||||
|
sub eax,182
|
||||||
|
cmp eax,32
|
||||||
|
jge @F
|
||||||
|
mov eax,32
|
||||||
|
@@:
|
||||||
|
mov row,eax
|
||||||
|
cmp left,0
|
||||||
|
jge @F
|
||||||
|
mov left,0
|
||||||
|
@@:
|
||||||
|
cmp right,640
|
||||||
|
jle dt_arm_row
|
||||||
|
mov right,640
|
||||||
|
dt_arm_row:
|
||||||
|
mov eax,row
|
||||||
|
cmp eax,bottom
|
||||||
|
jge dt_arm_done
|
||||||
|
sub eax,originY
|
||||||
|
mov deltaY,eax
|
||||||
|
mov eax,left
|
||||||
|
mov column,eax
|
||||||
|
dt_arm_column:
|
||||||
|
mov eax,column
|
||||||
|
cmp eax,right
|
||||||
|
jge dt_arm_next_row
|
||||||
|
sub eax,originX
|
||||||
|
mov deltaX,eax
|
||||||
|
sub eax,deltaY
|
||||||
|
imul eax,46341
|
||||||
|
sar eax,16
|
||||||
|
cmp eax,256
|
||||||
|
jae dt_arm_skip
|
||||||
|
mov sourceX,eax
|
||||||
|
mov eax,deltaX
|
||||||
|
add eax,deltaY
|
||||||
|
imul eax,46341
|
||||||
|
sar eax,16
|
||||||
|
cmp eax,256
|
||||||
|
jae dt_arm_skip
|
||||||
|
shl eax,8
|
||||||
|
add eax,sourceX
|
||||||
|
mov esi,framePtr
|
||||||
|
mov eax,[esi+eax*4]
|
||||||
|
test eax,80000000h
|
||||||
|
jz dt_arm_skip
|
||||||
|
and eax,00FFFFFFh
|
||||||
|
mov edx,row
|
||||||
|
imul edx,640
|
||||||
|
add edx,column
|
||||||
|
mov screenBuffer[edx*4],eax
|
||||||
|
dt_arm_skip:
|
||||||
|
inc column
|
||||||
|
jmp dt_arm_column
|
||||||
|
dt_arm_next_row:
|
||||||
|
inc row
|
||||||
|
jmp dt_arm_row
|
||||||
|
dt_arm_done:
|
||||||
|
ret
|
||||||
|
DrawDartsArm3D ENDP
|
||||||
|
|
||||||
|
; Furniture is attached to fixed world planes, never camera-facing billboards.
|
||||||
|
DrawDartsProps3D PROC uses ebx esi edi
|
||||||
|
local item:DWORD,column:DWORD,depth:DWORD,sourceU:DWORD,packPtr:DWORD
|
||||||
|
local firstY:DWORD,lastY:DWORD,row:DWORD,sourceY:DWORD,stepY:DWORD,span:DWORD
|
||||||
|
mov item,0
|
||||||
|
dt_prop_item:
|
||||||
|
imul eax,item,28
|
||||||
|
lea esi,dtProps3D[eax]
|
||||||
|
mov eax,[esi+24]
|
||||||
|
mov packPtr,eax
|
||||||
|
mov column,0
|
||||||
|
dt_prop_column:
|
||||||
|
mov ebx,column
|
||||||
|
cmp dword ptr [esi],0
|
||||||
|
jne dt_prop_side
|
||||||
|
mov ecx,dtRayZ3D[ebx*4]
|
||||||
|
mov eax,[esi+4]
|
||||||
|
sub eax,dtCamZ3D
|
||||||
|
jmp dt_prop_distance
|
||||||
|
dt_prop_side:
|
||||||
|
mov ecx,dtRayX3D[ebx*4]
|
||||||
|
mov eax,[esi+4]
|
||||||
|
sub eax,dtCamX3D
|
||||||
|
dt_prop_distance:
|
||||||
|
test ecx,ecx
|
||||||
|
jz dt_prop_next_column
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv ecx
|
||||||
|
cmp eax,40
|
||||||
|
jl dt_prop_next_column
|
||||||
|
cmp eax,dtRayDepth3D[ebx*4]
|
||||||
|
jge dt_prop_next_column
|
||||||
|
mov depth,eax
|
||||||
|
mov eax,dtRayX3D[ebx*4]
|
||||||
|
mov edi,dtCamX3D
|
||||||
|
cmp dword ptr [esi],0
|
||||||
|
je @F
|
||||||
|
mov eax,dtRayZ3D[ebx*4]
|
||||||
|
mov edi,dtCamZ3D
|
||||||
|
@@:
|
||||||
|
imul depth
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,edi
|
||||||
|
sub eax,[esi+8]
|
||||||
|
js dt_prop_next_column
|
||||||
|
mov ecx,[esi+12]
|
||||||
|
sub ecx,[esi+8]
|
||||||
|
cmp eax,ecx
|
||||||
|
jge dt_prop_next_column
|
||||||
|
mov edi,packPtr
|
||||||
|
imul eax,[edi].AnimPack3D.imageWidth
|
||||||
|
cdq
|
||||||
|
idiv ecx
|
||||||
|
mov sourceU,eax
|
||||||
|
mov eax,[esi+20]
|
||||||
|
sub eax,dtCamY3D
|
||||||
|
imul eax,dtLens3D
|
||||||
|
cdq
|
||||||
|
idiv depth
|
||||||
|
mov ecx,dtScreenY3D
|
||||||
|
sub ecx,eax
|
||||||
|
mov firstY,ecx
|
||||||
|
mov eax,[esi+16]
|
||||||
|
sub eax,dtCamY3D
|
||||||
|
imul eax,dtLens3D
|
||||||
|
cdq
|
||||||
|
idiv depth
|
||||||
|
mov ecx,dtScreenY3D
|
||||||
|
sub ecx,eax
|
||||||
|
mov lastY,ecx
|
||||||
|
sub ecx,firstY
|
||||||
|
jle dt_prop_next_column
|
||||||
|
mov span,ecx
|
||||||
|
mov eax,[edi].AnimPack3D.height
|
||||||
|
shl eax,16
|
||||||
|
xor edx,edx
|
||||||
|
div span
|
||||||
|
mov stepY,eax
|
||||||
|
mov eax,firstY
|
||||||
|
cmp eax,32
|
||||||
|
jge @F
|
||||||
|
mov eax,32
|
||||||
|
@@:
|
||||||
|
mov row,eax
|
||||||
|
sub eax,firstY
|
||||||
|
imul eax,stepY
|
||||||
|
mov sourceY,eax
|
||||||
|
cmp lastY,400
|
||||||
|
jle dt_prop_row
|
||||||
|
mov lastY,400
|
||||||
|
dt_prop_row:
|
||||||
|
mov eax,row
|
||||||
|
cmp eax,lastY
|
||||||
|
jge dt_prop_next_column
|
||||||
|
mov eax,sourceY
|
||||||
|
shr eax,16
|
||||||
|
cmp eax,[edi].AnimPack3D.height
|
||||||
|
jae dt_prop_next_column
|
||||||
|
imul eax,[edi].AnimPack3D.imageWidth
|
||||||
|
add eax,sourceU
|
||||||
|
mov edx,[edi].AnimPack3D.pixels
|
||||||
|
mov eax,[edx+eax*4]
|
||||||
|
test eax,80000000h
|
||||||
|
jz @F
|
||||||
|
mov edx,row
|
||||||
|
imul edx,640
|
||||||
|
add edx,column
|
||||||
|
and eax,00FFFFFFh
|
||||||
|
mov screenBuffer[edx*4],eax
|
||||||
|
@@:
|
||||||
|
mov eax,stepY
|
||||||
|
add sourceY,eax
|
||||||
|
inc row
|
||||||
|
jmp dt_prop_row
|
||||||
|
dt_prop_next_column:
|
||||||
|
inc column
|
||||||
|
cmp column,640
|
||||||
|
jb dt_prop_column
|
||||||
|
inc item
|
||||||
|
cmp item,4
|
||||||
|
jb dt_prop_item
|
||||||
|
ret
|
||||||
|
DrawDartsProps3D ENDP
|
||||||
|
|
||||||
|
; Write chalk glyphs directly into the wall texture, so the score follows perspective.
|
||||||
|
DartsWallText3D PROC uses ebx esi edi px:DWORD,py:DWORD,textPtr:DWORD
|
||||||
|
local row:DWORD,column:DWORD,pen:DWORD,glyph:DWORD
|
||||||
|
mov esi,textPtr
|
||||||
|
mov eax,px
|
||||||
|
mov pen,eax
|
||||||
|
dt_chalk_char:
|
||||||
|
movzx eax,byte ptr [esi]
|
||||||
|
test eax,eax
|
||||||
|
jz dt_chalk_done
|
||||||
|
lea eax,font8x8[eax*8]
|
||||||
|
mov glyph,eax
|
||||||
|
mov row,0
|
||||||
|
dt_chalk_row:
|
||||||
|
mov eax,glyph
|
||||||
|
mov edx,row
|
||||||
|
movzx ebx,byte ptr [eax+edx]
|
||||||
|
mov column,0
|
||||||
|
dt_chalk_pixel:
|
||||||
|
test ebx,80h
|
||||||
|
jz @F
|
||||||
|
mov eax,row
|
||||||
|
add eax,py
|
||||||
|
shl eax,9
|
||||||
|
add eax,pen
|
||||||
|
add eax,column
|
||||||
|
mov edi,dtWall3D.pixels
|
||||||
|
mov dword ptr [edi+eax*4],0FFD8D9C2h
|
||||||
|
@@:
|
||||||
|
shl ebx,1
|
||||||
|
inc column
|
||||||
|
cmp column,8
|
||||||
|
jb dt_chalk_pixel
|
||||||
|
inc row
|
||||||
|
cmp row,8
|
||||||
|
jb dt_chalk_row
|
||||||
|
add pen,8
|
||||||
|
inc esi
|
||||||
|
jmp dt_chalk_char
|
||||||
|
dt_chalk_done:
|
||||||
|
ret
|
||||||
|
DartsWallText3D ENDP
|
||||||
|
|
||||||
|
UpdateDartsWall3D PROC uses ebx esi edi
|
||||||
|
cmp dtWallDirty3D,0
|
||||||
|
je dt_wall_score_done
|
||||||
|
cmp dtWall3D.pixels,0
|
||||||
|
je dt_wall_score_done
|
||||||
|
mov ebx,104
|
||||||
|
dt_chalk_clear:
|
||||||
|
mov eax,ebx
|
||||||
|
shl eax,9
|
||||||
|
add eax,32
|
||||||
|
mov edi,dtWall3D.pixels
|
||||||
|
lea edi,[edi+eax*4]
|
||||||
|
mov ecx,102
|
||||||
|
mov eax,0FF202623h
|
||||||
|
rep stosd
|
||||||
|
inc ebx
|
||||||
|
cmp ebx,282
|
||||||
|
jb dt_chalk_clear
|
||||||
|
invoke DartsWallText3D,40,108,OFFSET dtYou
|
||||||
|
invoke DartsWallText3D,86,108,OFFSET dtBot
|
||||||
|
invoke FormatNumber,dtScores3D,OFFSET hudNumBuffer
|
||||||
|
invoke DartsWallText3D,40,126,OFFSET hudNumBuffer
|
||||||
|
invoke FormatNumber,dtScores3D[4],OFFSET hudNumBuffer
|
||||||
|
invoke DartsWallText3D,86,126,OFFSET hudNumBuffer
|
||||||
|
mov ebx,dtHistoryRows3D
|
||||||
|
sub ebx,7
|
||||||
|
jns @F
|
||||||
|
xor ebx,ebx
|
||||||
|
@@:
|
||||||
|
mov esi,150
|
||||||
|
dt_chalk_history:
|
||||||
|
cmp ebx,dtHistoryRows3D
|
||||||
|
jae dt_chalk_clean
|
||||||
|
invoke FormatNumber,dtHistory3D[ebx*8],OFFSET hudNumBuffer
|
||||||
|
invoke DartsWallText3D,40,esi,OFFSET hudNumBuffer
|
||||||
|
invoke FormatNumber,dtHistory3D[ebx*8+4],OFFSET hudNumBuffer
|
||||||
|
invoke DartsWallText3D,86,esi,OFFSET hudNumBuffer
|
||||||
|
add esi,17
|
||||||
|
inc ebx
|
||||||
|
jmp dt_chalk_history
|
||||||
|
dt_chalk_clean:
|
||||||
|
mov dtWallDirty3D,0
|
||||||
|
dt_wall_score_done:
|
||||||
|
ret
|
||||||
|
UpdateDartsWall3D ENDP
|
||||||
|
|
||||||
|
DrawDartsScoreboard3D PROC uses ebx esi edi
|
||||||
|
invoke DrawBoxBorder,54,23,212,174,001A2420h,00B0A16Eh,2
|
||||||
|
invoke DrawString8x8,70,32,OFFSET dtScoreTitle,00E9DEBAh
|
||||||
|
invoke DrawString8x8,118,49,OFFSET dtYou,0090CDB9h
|
||||||
|
invoke DrawString8x8,198,49,OFFSET dtBot,00E8D7ADh
|
||||||
|
mov ebx,dtHistoryRows3D
|
||||||
|
sub ebx,10
|
||||||
|
jns @F
|
||||||
|
xor ebx,ebx
|
||||||
|
@@:
|
||||||
|
mov esi,65
|
||||||
|
dt_scoreboard_row:
|
||||||
|
cmp ebx,dtHistoryRows3D
|
||||||
|
jae dt_scoreboard_current
|
||||||
|
lea eax,[ebx+1]
|
||||||
|
invoke FormatNumber,eax,OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,70,esi,OFFSET hudNumBuffer,008A9C91h
|
||||||
|
invoke FormatNumber,dtHistory3D[ebx*8],OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,118,esi,OFFSET hudNumBuffer,00E2E2CFh
|
||||||
|
invoke FormatNumber,dtHistory3D[ebx*8+4],OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,198,esi,OFFSET hudNumBuffer,00E2E2CFh
|
||||||
|
add esi,10
|
||||||
|
inc ebx
|
||||||
|
jmp dt_scoreboard_row
|
||||||
|
dt_scoreboard_current:
|
||||||
|
invoke DrawBox,66,170,188,1,00758772h
|
||||||
|
invoke FormatNumber,dtScores3D,OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,118,180,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
invoke FormatNumber,dtScores3D[4],OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,198,180,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
ret
|
||||||
|
DrawDartsScoreboard3D ENDP
|
||||||
657
src_graphics/darts_render.inc
Normal file
|
|
@ -0,0 +1,657 @@
|
||||||
|
include src_graphics\darts_environment.inc
|
||||||
|
|
||||||
|
; One-pixel, alpha-blended trajectory, clipped to the 3D playfield.
|
||||||
|
DrawDartsLine3D PROC uses ebx esi edi x0:SDWORD,y0:SDWORD,x1:SDWORD,y1:SDWORD,opacity:DWORD
|
||||||
|
local stepX:DWORD,stepY:DWORD,steps:DWORD,px:DWORD,py:DWORD,paint:DWORD
|
||||||
|
mov eax,x1
|
||||||
|
sub eax,x0
|
||||||
|
cdq
|
||||||
|
xor eax,edx
|
||||||
|
sub eax,edx
|
||||||
|
mov ebx,eax
|
||||||
|
mov eax,y1
|
||||||
|
sub eax,y0
|
||||||
|
cdq
|
||||||
|
xor eax,edx
|
||||||
|
sub eax,edx
|
||||||
|
cmp eax,ebx
|
||||||
|
jbe @F
|
||||||
|
mov ebx,eax
|
||||||
|
@@:
|
||||||
|
cmp ebx,2048
|
||||||
|
ja dt_line_done
|
||||||
|
test ebx,ebx
|
||||||
|
jnz @F
|
||||||
|
inc ebx
|
||||||
|
@@:
|
||||||
|
mov steps,ebx
|
||||||
|
mov eax,x1
|
||||||
|
sub eax,x0
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv ebx
|
||||||
|
mov stepX,eax
|
||||||
|
mov eax,y1
|
||||||
|
sub eax,y0
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv ebx
|
||||||
|
mov stepY,eax
|
||||||
|
mov eax,x0
|
||||||
|
shl eax,16
|
||||||
|
mov px,eax
|
||||||
|
mov eax,y0
|
||||||
|
shl eax,16
|
||||||
|
mov py,eax
|
||||||
|
inc steps
|
||||||
|
dt_line_pixel:
|
||||||
|
mov eax,px
|
||||||
|
sar eax,16
|
||||||
|
cmp eax,640
|
||||||
|
jae dt_line_skip
|
||||||
|
mov edx,py
|
||||||
|
sar edx,16
|
||||||
|
cmp edx,32
|
||||||
|
jl dt_line_skip
|
||||||
|
cmp edx,400
|
||||||
|
jge dt_line_skip
|
||||||
|
imul edx,640
|
||||||
|
add edx,eax
|
||||||
|
lea edi,screenBuffer[edx*4]
|
||||||
|
mov esi,[edi]
|
||||||
|
movzx eax,byte ptr [edi]
|
||||||
|
mov ecx,219
|
||||||
|
sub ecx,eax
|
||||||
|
imul ecx,opacity
|
||||||
|
sar ecx,8
|
||||||
|
add eax,ecx
|
||||||
|
mov paint,eax
|
||||||
|
mov eax,esi
|
||||||
|
shr eax,8
|
||||||
|
and eax,255
|
||||||
|
mov ecx,210
|
||||||
|
sub ecx,eax
|
||||||
|
imul ecx,opacity
|
||||||
|
sar ecx,8
|
||||||
|
add eax,ecx
|
||||||
|
shl eax,8
|
||||||
|
or paint,eax
|
||||||
|
mov eax,esi
|
||||||
|
shr eax,16
|
||||||
|
and eax,255
|
||||||
|
mov ecx,180
|
||||||
|
sub ecx,eax
|
||||||
|
imul ecx,opacity
|
||||||
|
sar ecx,8
|
||||||
|
add eax,ecx
|
||||||
|
shl eax,16
|
||||||
|
or eax,paint
|
||||||
|
mov [edi],eax
|
||||||
|
dt_line_skip:
|
||||||
|
mov eax,stepX
|
||||||
|
add px,eax
|
||||||
|
mov eax,stepY
|
||||||
|
add py,eax
|
||||||
|
dec steps
|
||||||
|
jnz dt_line_pixel
|
||||||
|
dt_line_done:
|
||||||
|
ret
|
||||||
|
DrawDartsLine3D ENDP
|
||||||
|
|
||||||
|
DrawDartsTrail3D PROC uses ebx esi edi
|
||||||
|
local timeMs:DWORD,lastX:DWORD,lastY:DWORD,valid:DWORD,fade:DWORD,alpha:DWORD
|
||||||
|
mov eax,dtTimer3D
|
||||||
|
mov fade,256
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
je dt_trail_start
|
||||||
|
cmp dtState3D,DT_IMPACT
|
||||||
|
jne dt_trail_done
|
||||||
|
cmp eax,300
|
||||||
|
jae dt_trail_done
|
||||||
|
imul eax,256
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,300
|
||||||
|
div ecx
|
||||||
|
mov ecx,256
|
||||||
|
sub ecx,eax
|
||||||
|
mov fade,ecx
|
||||||
|
mov eax,DT_THROW_MS
|
||||||
|
dt_trail_start:
|
||||||
|
mov timeMs,eax
|
||||||
|
mov valid,0
|
||||||
|
mov ebx,12
|
||||||
|
dt_trail_segment:
|
||||||
|
imul eax,ebx,20
|
||||||
|
mov ecx,timeMs
|
||||||
|
sub ecx,eax
|
||||||
|
js dt_trail_next
|
||||||
|
invoke DartsPath3D,ecx
|
||||||
|
invoke DartsProject3D,eax,edx,ecx
|
||||||
|
cmp ecx,60
|
||||||
|
jl dt_trail_invalid
|
||||||
|
mov esi,eax
|
||||||
|
mov edi,edx
|
||||||
|
cmp valid,0
|
||||||
|
je dt_trail_remember
|
||||||
|
mov eax,13
|
||||||
|
sub eax,ebx
|
||||||
|
imul eax,9
|
||||||
|
imul eax,fade
|
||||||
|
shr eax,8
|
||||||
|
mov alpha,eax
|
||||||
|
invoke DrawDartsLine3D,lastX,lastY,esi,edi,alpha
|
||||||
|
dt_trail_remember:
|
||||||
|
mov lastX,esi
|
||||||
|
mov lastY,edi
|
||||||
|
mov valid,1
|
||||||
|
jmp dt_trail_next
|
||||||
|
dt_trail_invalid:
|
||||||
|
mov valid,0
|
||||||
|
dt_trail_next:
|
||||||
|
dec ebx
|
||||||
|
jns dt_trail_segment
|
||||||
|
dt_trail_done:
|
||||||
|
ret
|
||||||
|
DrawDartsTrail3D ENDP
|
||||||
|
|
||||||
|
; Independent scene camera. Hall player coordinates are never borrowed or modified.
|
||||||
|
PrepareDartsRays3D PROC uses ebx esi edi
|
||||||
|
local cameraRay:DWORD,wallType:DWORD,wallT:DWORD,sideT:DWORD
|
||||||
|
xor ebx,ebx
|
||||||
|
dt_ray_column:
|
||||||
|
mov eax,ebx
|
||||||
|
sub eax,320
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv dtLens3D
|
||||||
|
mov cameraRay,eax
|
||||||
|
imul dtYawCos3D
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,dtYawSin3D
|
||||||
|
mov dtRayX3D[ebx*4],eax
|
||||||
|
mov eax,cameraRay
|
||||||
|
imul dtYawSin3D
|
||||||
|
shrd eax,edx,16
|
||||||
|
neg eax
|
||||||
|
add eax,dtYawCos3D
|
||||||
|
mov dtRayZ3D[ebx*4],eax
|
||||||
|
mov wallT,7FFFFFFFh
|
||||||
|
mov wallType,0
|
||||||
|
test eax,eax
|
||||||
|
jz dt_ray_side
|
||||||
|
mov ecx,eax
|
||||||
|
mov eax,DT_WALL
|
||||||
|
test ecx,ecx
|
||||||
|
jns @F
|
||||||
|
mov eax,-2000
|
||||||
|
mov wallType,2
|
||||||
|
@@:
|
||||||
|
sub eax,dtCamZ3D
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv ecx
|
||||||
|
test eax,eax
|
||||||
|
jle dt_ray_side
|
||||||
|
mov wallT,eax
|
||||||
|
dt_ray_side:
|
||||||
|
mov ecx,dtRayX3D[ebx*4]
|
||||||
|
test ecx,ecx
|
||||||
|
jz dt_ray_hit
|
||||||
|
mov eax,2600
|
||||||
|
test ecx,ecx
|
||||||
|
jns @F
|
||||||
|
mov eax,-2600
|
||||||
|
@@:
|
||||||
|
sub eax,dtCamX3D
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv ecx
|
||||||
|
test eax,eax
|
||||||
|
jle dt_ray_hit
|
||||||
|
cmp eax,wallT
|
||||||
|
jge dt_ray_hit
|
||||||
|
mov wallT,eax
|
||||||
|
mov wallType,1
|
||||||
|
dt_ray_hit:
|
||||||
|
mov eax,wallT
|
||||||
|
cmp eax,1
|
||||||
|
jge @F
|
||||||
|
mov eax,1
|
||||||
|
@@:
|
||||||
|
mov dtRayDepth3D[ebx*4],eax
|
||||||
|
mov esi,eax
|
||||||
|
mov eax,dtRayX3D[ebx*4]
|
||||||
|
imul esi
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,dtCamX3D
|
||||||
|
mov dtRayHitX3D[ebx*4],eax
|
||||||
|
cmp wallType,1
|
||||||
|
jne @F
|
||||||
|
mov eax,dtRayZ3D[ebx*4]
|
||||||
|
imul esi
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,dtCamZ3D
|
||||||
|
@@:
|
||||||
|
imul eax,256
|
||||||
|
cdq
|
||||||
|
mov ecx,500
|
||||||
|
idiv ecx
|
||||||
|
and eax,255
|
||||||
|
mov dtRayU3D[ebx*4],eax
|
||||||
|
mov eax,wallType
|
||||||
|
mov dtRayFront3D[ebx*4],eax
|
||||||
|
inc ebx
|
||||||
|
cmp ebx,640
|
||||||
|
jb dt_ray_column
|
||||||
|
ret
|
||||||
|
PrepareDartsRays3D ENDP
|
||||||
|
|
||||||
|
; True inverse projection onto front/side/back walls, floor and ceiling.
|
||||||
|
DrawDartsRoom3D PROC uses ebx esi edi
|
||||||
|
local row:DWORD,rayY:DWORD,worldY:DWORD,depth:DWORD,sourceU:DWORD,sourceV:DWORD
|
||||||
|
call PrepareDartsRays3D
|
||||||
|
mov row,32
|
||||||
|
dt_room_row:
|
||||||
|
mov eax,dtScreenY3D
|
||||||
|
sub eax,row
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv dtLens3D
|
||||||
|
mov rayY,eax
|
||||||
|
mov eax,row
|
||||||
|
imul eax,640*4
|
||||||
|
lea edi,screenBuffer[eax]
|
||||||
|
xor ebx,ebx
|
||||||
|
dt_room_pixel:
|
||||||
|
mov eax,rayY
|
||||||
|
imul dtRayDepth3D[ebx*4]
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,dtCamY3D
|
||||||
|
mov worldY,eax
|
||||||
|
cmp eax,-1730
|
||||||
|
jl dt_room_floor
|
||||||
|
cmp eax,1300
|
||||||
|
jg dt_room_ceiling
|
||||||
|
cmp dtRayFront3D[ebx*4],0
|
||||||
|
jne dt_room_wall
|
||||||
|
mov eax,dtRayHitX3D[ebx*4]
|
||||||
|
add eax,256
|
||||||
|
cmp eax,512
|
||||||
|
jae dt_room_wall
|
||||||
|
mov sourceU,eax
|
||||||
|
mov eax,256
|
||||||
|
sub eax,worldY
|
||||||
|
cmp eax,512
|
||||||
|
jae dt_room_wall
|
||||||
|
shl eax,9
|
||||||
|
add eax,sourceU
|
||||||
|
mov esi,dtBoard3D.pixels
|
||||||
|
mov eax,[esi+eax*4]
|
||||||
|
test eax,80000000h
|
||||||
|
jnz dt_room_store
|
||||||
|
dt_room_wall:
|
||||||
|
mov eax,570
|
||||||
|
sub eax,worldY
|
||||||
|
imul eax,512
|
||||||
|
cdq
|
||||||
|
mov ecx,1800
|
||||||
|
idiv ecx
|
||||||
|
test eax,eax
|
||||||
|
jns @F
|
||||||
|
xor eax,eax
|
||||||
|
@@:
|
||||||
|
cmp eax,511
|
||||||
|
jbe @F
|
||||||
|
mov eax,511
|
||||||
|
@@:
|
||||||
|
shl eax,9
|
||||||
|
mov sourceV,eax
|
||||||
|
mov eax,dtRayU3D[ebx*4]
|
||||||
|
and eax,15
|
||||||
|
add eax,190
|
||||||
|
cmp dtRayFront3D[ebx*4],0
|
||||||
|
jne dt_room_wall_sample
|
||||||
|
mov ecx,dtRayHitX3D[ebx*4]
|
||||||
|
add ecx,850
|
||||||
|
cmp ecx,1700
|
||||||
|
jae dt_room_wall_sample
|
||||||
|
imul eax,ecx,512
|
||||||
|
cdq
|
||||||
|
mov ecx,1700
|
||||||
|
idiv ecx
|
||||||
|
dt_room_wall_sample:
|
||||||
|
add eax,sourceV
|
||||||
|
mov esi,dtWall3D.pixels
|
||||||
|
mov eax,[esi+eax*4]
|
||||||
|
jmp dt_room_store
|
||||||
|
dt_room_floor:
|
||||||
|
mov eax,-1730
|
||||||
|
jmp dt_room_horizontal
|
||||||
|
dt_room_ceiling:
|
||||||
|
mov eax,1300
|
||||||
|
dt_room_horizontal:
|
||||||
|
sub eax,dtCamY3D
|
||||||
|
shl eax,16
|
||||||
|
cdq
|
||||||
|
idiv rayY
|
||||||
|
mov depth,eax
|
||||||
|
mov eax,dtRayX3D[ebx*4]
|
||||||
|
imul depth
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,dtCamX3D
|
||||||
|
imul eax,256
|
||||||
|
cdq
|
||||||
|
mov ecx,500
|
||||||
|
idiv ecx
|
||||||
|
and eax,255
|
||||||
|
mov sourceU,eax
|
||||||
|
mov eax,dtRayZ3D[ebx*4]
|
||||||
|
imul depth
|
||||||
|
shrd eax,edx,16
|
||||||
|
add eax,dtCamZ3D
|
||||||
|
imul eax,256
|
||||||
|
cdq
|
||||||
|
mov ecx,500
|
||||||
|
idiv ecx
|
||||||
|
and eax,255
|
||||||
|
shl eax,8
|
||||||
|
add eax,sourceU
|
||||||
|
mov esi,dtRoom3D.pixels
|
||||||
|
add esi,5*256*256*4
|
||||||
|
mov eax,[esi+eax*4]
|
||||||
|
cmp rayY,0
|
||||||
|
jle dt_room_store
|
||||||
|
mov eax,00444943h
|
||||||
|
dt_room_store:
|
||||||
|
and eax,00FFFFFFh
|
||||||
|
stosd
|
||||||
|
inc ebx
|
||||||
|
cmp ebx,640
|
||||||
|
jb dt_room_pixel
|
||||||
|
inc row
|
||||||
|
cmp row,400
|
||||||
|
jb dt_room_row
|
||||||
|
ret
|
||||||
|
DrawDartsRoom3D ENDP
|
||||||
|
|
||||||
|
; Camera-relative raster views retain the generated metal and flight detail.
|
||||||
|
DrawDartsModel3D PROC uses ebx esi edi x:SDWORD,y:SDWORD,z:SDWORD
|
||||||
|
local deltaX:DWORD,deltaZ:DWORD,angle:DWORD,pose:DWORD
|
||||||
|
local centerX:DWORD,centerY:DWORD,depth:DWORD,span:DWORD,worldX:DWORD,worldY:DWORD
|
||||||
|
mov eax,x
|
||||||
|
sub eax,dtCamX3D
|
||||||
|
mov deltaX,eax
|
||||||
|
mov eax,z
|
||||||
|
sub eax,dtCamZ3D
|
||||||
|
mov deltaZ,eax
|
||||||
|
fild deltaX
|
||||||
|
fild deltaZ
|
||||||
|
fpatan
|
||||||
|
fabs
|
||||||
|
fmul dtAngleFactor3D
|
||||||
|
fistp angle
|
||||||
|
imul eax,angle,60
|
||||||
|
add eax,32768
|
||||||
|
shr eax,16
|
||||||
|
cmp eax,15
|
||||||
|
jbe @F
|
||||||
|
mov eax,15
|
||||||
|
@@:
|
||||||
|
mov pose,eax
|
||||||
|
mov eax,x
|
||||||
|
sub eax,70
|
||||||
|
imul eax,64
|
||||||
|
cdq
|
||||||
|
mov ecx,DT_WALL
|
||||||
|
idiv ecx
|
||||||
|
mov edx,x
|
||||||
|
sub edx,eax
|
||||||
|
mov worldX,edx
|
||||||
|
mov eax,y
|
||||||
|
sub eax,280
|
||||||
|
cmp z,DT_WALL-8
|
||||||
|
jae @F
|
||||||
|
mov eax,dtTimer3D
|
||||||
|
imul eax,560
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,DT_THROW_MS
|
||||||
|
div ecx
|
||||||
|
mov edx,y
|
||||||
|
add edx,280
|
||||||
|
sub edx,eax
|
||||||
|
mov eax,edx
|
||||||
|
@@:
|
||||||
|
imul eax,64
|
||||||
|
cdq
|
||||||
|
mov ecx,DT_WALL
|
||||||
|
idiv ecx
|
||||||
|
mov edx,y
|
||||||
|
sub edx,eax
|
||||||
|
mov worldY,edx
|
||||||
|
mov eax,z
|
||||||
|
sub eax,64
|
||||||
|
invoke DartsProject3D,worldX,worldY,eax
|
||||||
|
cmp ecx,80
|
||||||
|
jl dt_model_done
|
||||||
|
mov centerX,eax
|
||||||
|
mov centerY,edx
|
||||||
|
mov depth,ecx
|
||||||
|
imul eax,dtLens3D,160
|
||||||
|
xor edx,edx
|
||||||
|
div depth
|
||||||
|
cmp eax,240
|
||||||
|
jbe @F
|
||||||
|
mov eax,240
|
||||||
|
@@:
|
||||||
|
cmp eax,12
|
||||||
|
jae @F
|
||||||
|
mov eax,12
|
||||||
|
@@:
|
||||||
|
mov span,eax
|
||||||
|
invoke DartsProject3D,x,y,z
|
||||||
|
mov centerX,eax
|
||||||
|
mov centerY,edx
|
||||||
|
mov ebx,pose
|
||||||
|
mov eax,dtDartTipX3D[ebx*4]
|
||||||
|
imul eax,span
|
||||||
|
shr eax,8
|
||||||
|
sub centerX,eax
|
||||||
|
mov eax,dtDartTipY3D[ebx*4]
|
||||||
|
imul eax,span
|
||||||
|
shr eax,8
|
||||||
|
sub centerY,eax
|
||||||
|
invoke DrawAnimSprite3D,OFFSET dtDart3D,pose,centerX,centerY,span,span
|
||||||
|
dt_model_done:
|
||||||
|
ret
|
||||||
|
DrawDartsModel3D ENDP
|
||||||
|
|
||||||
|
RenderDarts3D PROC uses ebx esi edi
|
||||||
|
local bx0:DWORD,by0:DWORD,boardSpan:DWORD,handX:DWORD,handY:DWORD,pose:DWORD
|
||||||
|
cmp dtError3D,0
|
||||||
|
jne dt_render_error
|
||||||
|
call DartsCamera3D
|
||||||
|
call UpdateDartsWall3D
|
||||||
|
call DrawDartsRoom3D
|
||||||
|
call DrawDartsProps3D
|
||||||
|
call DrawDartsTrail3D
|
||||||
|
xor ebx,ebx
|
||||||
|
dt_render_marks:
|
||||||
|
cmp ebx,dtCount3D
|
||||||
|
jae dt_render_flight
|
||||||
|
invoke DrawDartsModel3D,dtMarkX3D[ebx*4],dtMarkY3D[ebx*4],DT_WALL-4
|
||||||
|
inc ebx
|
||||||
|
jmp dt_render_marks
|
||||||
|
dt_render_flight:
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
jne dt_render_hand
|
||||||
|
invoke DartsProject3D,dtShotX3D,dtShotY3D,dtShotZ3D
|
||||||
|
cmp ecx,140
|
||||||
|
jl dt_render_hand
|
||||||
|
invoke DrawDartsModel3D,dtShotX3D,dtShotY3D,dtShotZ3D
|
||||||
|
dt_render_hand:
|
||||||
|
mov pose,0
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
je dt_render_aim_hand
|
||||||
|
cmp dtState3D,DT_RELEASE
|
||||||
|
je dt_render_release_hand
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
jne dt_render_hud
|
||||||
|
cmp dtTimer3D,250
|
||||||
|
jae dt_render_hud
|
||||||
|
mov eax,dtTimer3D
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,50
|
||||||
|
div ecx
|
||||||
|
add eax,12
|
||||||
|
cmp eax,15
|
||||||
|
jbe dt_render_pose
|
||||||
|
mov eax,15
|
||||||
|
jmp dt_render_pose
|
||||||
|
dt_render_release_hand:
|
||||||
|
mov eax,dtTimer3D
|
||||||
|
imul eax,3
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,200
|
||||||
|
div ecx
|
||||||
|
add eax,8
|
||||||
|
cmp eax,10
|
||||||
|
jne dt_render_pose
|
||||||
|
mov eax,11
|
||||||
|
jmp dt_render_pose
|
||||||
|
dt_render_aim_hand:
|
||||||
|
mov eax,0
|
||||||
|
cmp dtHolding3D,0
|
||||||
|
je dt_render_pose
|
||||||
|
mov eax,dtHoldTime3D
|
||||||
|
imul eax,4
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,280
|
||||||
|
div ecx
|
||||||
|
cmp eax,3
|
||||||
|
jbe @F
|
||||||
|
mov eax,3
|
||||||
|
@@:
|
||||||
|
add eax,4
|
||||||
|
dt_render_pose:
|
||||||
|
mov pose,eax
|
||||||
|
invoke DartsProject3D,dtAimX3D,dtAimY3D,DT_WALL
|
||||||
|
mov bx0,eax
|
||||||
|
mov by0,edx
|
||||||
|
add eax,16
|
||||||
|
mov handX,eax
|
||||||
|
mov eax,edx
|
||||||
|
sub eax,110
|
||||||
|
mov handY,eax
|
||||||
|
invoke DrawDartsArm3D,pose,bx0,by0
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
jne dt_render_hud
|
||||||
|
mov eax,bx0
|
||||||
|
sub eax,7
|
||||||
|
mov edx,by0
|
||||||
|
sub edx,2
|
||||||
|
invoke DrawBuckshotPanel3D,eax,edx,15,5,00101112h
|
||||||
|
mov eax,by0
|
||||||
|
sub eax,7
|
||||||
|
mov edx,bx0
|
||||||
|
sub edx,2
|
||||||
|
invoke DrawBuckshotPanel3D,edx,eax,5,15,00101112h
|
||||||
|
mov eax,bx0
|
||||||
|
sub eax,6
|
||||||
|
invoke DrawBuckshotPanel3D,eax,by0,13,2,00F6E6ADh
|
||||||
|
mov eax,by0
|
||||||
|
sub eax,6
|
||||||
|
invoke DrawBuckshotPanel3D,bx0,eax,2,13,00F6E6ADh
|
||||||
|
dt_render_hud:
|
||||||
|
invoke DrawBox,0,0,320,16,00151D20h
|
||||||
|
invoke DrawString8x8,8,4,OFFSET dtTitle,00E8D7ADh
|
||||||
|
invoke DrawString8x8,112,4,OFFSET dtYou,0090CDB9h
|
||||||
|
invoke FormatNumber,dtScores3D,OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,140,4,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
invoke DrawString8x8,204,4,OFFSET dtBot,00E8D7ADh
|
||||||
|
invoke FormatNumber,dtScores3D[4],OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,248,4,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
invoke DrawBox,0,200,320,40,00151D20h
|
||||||
|
mov ebx,OFFSET dtYourTurn
|
||||||
|
cmp dtActor3D,0
|
||||||
|
je @F
|
||||||
|
mov ebx,OFFSET dtBotTurn
|
||||||
|
@@:
|
||||||
|
cmp dtState3D,DT_WIN
|
||||||
|
jne dt_hud_actor
|
||||||
|
mov ebx,OFFSET dtYouWin
|
||||||
|
cmp dtWinner3D,0
|
||||||
|
je dt_hud_actor
|
||||||
|
mov ebx,OFFSET dtBotWin
|
||||||
|
dt_hud_actor:
|
||||||
|
invoke DrawString8x8,8,206,ebx,00E8D7ADh
|
||||||
|
xor ebx,ebx
|
||||||
|
dt_render_scores:
|
||||||
|
imul esi,ebx,52
|
||||||
|
add esi,8
|
||||||
|
invoke DrawBoxBorder,esi,220,46,16,00293436h,00728689h,1
|
||||||
|
cmp ebx,dtCount3D
|
||||||
|
jae @F
|
||||||
|
invoke FormatNumber,dtMarkScore3D[ebx*4],OFFSET hudNumBuffer
|
||||||
|
add esi,7
|
||||||
|
invoke DrawString8x8,esi,224,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
@@:
|
||||||
|
inc ebx
|
||||||
|
cmp ebx,3
|
||||||
|
jb dt_render_scores
|
||||||
|
invoke DrawBoxBorder,230,220,82,16,00293436h,00728689h,1
|
||||||
|
invoke DrawString8x8,248,224,OFFSET dtAgain,00FFFFFFh
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
jne @F
|
||||||
|
invoke DartsScore3D,dtAimX3D,dtAimY3D
|
||||||
|
mov esi,OFFSET dtSingle
|
||||||
|
cmp edx,3
|
||||||
|
jne dt_preview_double
|
||||||
|
mov esi,OFFSET dtTriple
|
||||||
|
jmp dt_preview_sector
|
||||||
|
dt_preview_double:
|
||||||
|
cmp edx,2
|
||||||
|
jne dt_preview_sector
|
||||||
|
mov esi,OFFSET dtDouble
|
||||||
|
dt_preview_sector:
|
||||||
|
test edx,edx
|
||||||
|
jz dt_preview_value
|
||||||
|
mov ecx,edx
|
||||||
|
xor edx,edx
|
||||||
|
div ecx
|
||||||
|
dt_preview_value:
|
||||||
|
mov edi,eax
|
||||||
|
invoke DrawString8x8,176,206,OFFSET dtTarget,00AABDB6h
|
||||||
|
invoke DrawString8x8,224,206,esi,00F6E6ADh
|
||||||
|
invoke FormatNumber,edi,OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,236,206,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
jmp dt_render_done
|
||||||
|
@@:
|
||||||
|
cmp dtState3D,DT_RELEASE
|
||||||
|
je dt_render_done
|
||||||
|
cmp dtState3D,DT_FLIGHT
|
||||||
|
je dt_render_done
|
||||||
|
cmp dtState3D,DT_RETURN
|
||||||
|
je dt_render_done
|
||||||
|
mov ebx,OFFSET dtWin
|
||||||
|
cmp dtRemaining3D,0
|
||||||
|
je dt_render_done
|
||||||
|
mov ebx,OFFSET dtBust
|
||||||
|
cmp dtBust3D,0
|
||||||
|
jne dt_render_banner
|
||||||
|
mov ebx,OFFSET dtMiss
|
||||||
|
cmp dtLast3D,0
|
||||||
|
je dt_render_banner
|
||||||
|
mov ebx,OFFSET dtThrow
|
||||||
|
dt_render_banner:
|
||||||
|
invoke DrawString8x8,192,206,ebx,00E8D7ADh
|
||||||
|
dt_render_done:
|
||||||
|
cmp dtScoreOpen3D,0
|
||||||
|
je @F
|
||||||
|
call DrawDartsScoreboard3D
|
||||||
|
@@:
|
||||||
|
ret
|
||||||
|
dt_render_error:
|
||||||
|
invoke DrawBox,0,0,320,240,00151D20h
|
||||||
|
invoke DrawString8x8,12,104,OFFSET dtLoading,00E8D7ADh
|
||||||
|
ret
|
||||||
|
RenderDarts3D ENDP
|
||||||
|
|
@ -85,6 +85,11 @@ dk_render_ai_card:
|
||||||
shr edx, 1
|
shr edx, 1
|
||||||
add eax, edx
|
add eax, edx
|
||||||
mov posX, eax
|
mov posX, eax
|
||||||
|
mov hidden,1
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je @F
|
||||||
|
mov hidden,0
|
||||||
|
@@:
|
||||||
cmp dkState3D, DK_DEAL
|
cmp dkState3D, DK_DEAL
|
||||||
jne @F
|
jne @F
|
||||||
mov eax, ebx
|
mov eax, ebx
|
||||||
|
|
@ -94,10 +99,10 @@ dk_render_ai_card:
|
||||||
mov edx, dkTimer3D
|
mov edx, dkTimer3D
|
||||||
sub edx, eax
|
sub edx, eax
|
||||||
js dk_render_next_ai
|
js dk_render_next_ai
|
||||||
invoke DrawSlidingCard3D, posX, 48, durakAIHand[ebx*4], 1, edx
|
invoke DrawSlidingCard3D, posX, 48, durakAIHand[ebx*4], hidden, edx
|
||||||
jmp dk_render_next_ai
|
jmp dk_render_next_ai
|
||||||
@@:
|
@@:
|
||||||
invoke DrawNativeCard3D, posX, 48, durakAIHand[ebx*4], 1, 34
|
invoke DrawNativeCard3D, posX, 48, durakAIHand[ebx*4], hidden, 34
|
||||||
dk_render_next_ai:
|
dk_render_next_ai:
|
||||||
inc ebx
|
inc ebx
|
||||||
jmp dk_render_ai_card
|
jmp dk_render_ai_card
|
||||||
|
|
|
||||||
|
|
@ -300,10 +300,13 @@ eight_finish_done:
|
||||||
EightFinish3D ENDP
|
EightFinish3D ENDP
|
||||||
|
|
||||||
EightHand3D PROC uses ebx esi
|
EightHand3D PROC uses ebx esi
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne eight_hand_bot
|
||||||
cmp poolPlayer3D,1
|
cmp poolPlayer3D,1
|
||||||
jne eight_hand_human
|
jne eight_hand_human
|
||||||
cmp poolAI3D,0
|
cmp poolAI3D,0
|
||||||
je eight_hand_human
|
je eight_hand_human
|
||||||
|
eight_hand_bot:
|
||||||
mov esi,55*FP_1
|
mov esi,55*FP_1
|
||||||
eight_hand_row:
|
eight_hand_row:
|
||||||
mov ebx,40*FP_1
|
mov ebx,40*FP_1
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
MODE_FORTUNE equ 25
|
MODE_FORTUNE equ 25
|
||||||
|
FORTUNE_SUBMODE_MENU equ 0
|
||||||
|
FORTUNE_SUBMODE_TAROT equ 1
|
||||||
|
FORTUNE_SUBMODE_ORB equ 2
|
||||||
BeginFortuneDialog3D PROTO
|
BeginFortuneDialog3D PROTO
|
||||||
HandleFortuneDialog3D PROTO
|
HandleFortuneDialog3D PROTO
|
||||||
RenderFortuneDialog3D PROTO
|
RenderFortuneDialog3D PROTO
|
||||||
|
|
@ -7,61 +10,116 @@ StopFortuneWorker3D PROTO
|
||||||
PollFortuneWorker3D PROTO
|
PollFortuneWorker3D PROTO
|
||||||
SubmitFortuneQuestion3D PROTO
|
SubmitFortuneQuestion3D PROTO
|
||||||
FortuneWrap3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
FortuneWrap3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||||
InitFortuneMindState3D PROTO
|
UpdateFortuneSession3D PROTO
|
||||||
GenerateTarotReadingMind3D PROTO
|
SetFortuneSpeech3D PROTO :DWORD
|
||||||
GenerateStudentGradeMind3D PROTO
|
FortuneCardSpeech3D PROTO :DWORD
|
||||||
DetectTopic3D PROTO :DWORD
|
DrawFortuneSpeech3D PROTO
|
||||||
FortuneStrLen PROTO :DWORD
|
DrawFortuneSessionCard3D PROTO :DWORD
|
||||||
FortuneStrCat PROTO :DWORD,:DWORD
|
|
||||||
SubmitStudentGrade3D PROTO
|
|
||||||
DrawFortuneCardBox3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
|
||||||
CreatePipe PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
|
||||||
SetHandleInformation PROTO :DWORD,:DWORD,:DWORD
|
|
||||||
CreateProcessA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
|
||||||
PeekNamedPipe PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
|
||||||
TerminateProcess PROTO :DWORD,:DWORD
|
|
||||||
GetExitCodeProcess PROTO :DWORD,:DWORD
|
|
||||||
include src_graphics\fortune_mind_data.inc
|
|
||||||
.data
|
.data
|
||||||
fortuneWorkerPath3D db "ai\fortune-engine.exe",0
|
fortuneSessionPacks3D LABEL BYTE
|
||||||
fortuneWorkerCommand3D db "ai\fortune-engine.exe",0
|
fortuneSessionRoom3D AnimPack3D <>
|
||||||
fortuneNullName3D db "NUL",0
|
fortuneSessionShuffle3D AnimPack3D <>
|
||||||
fortunePipeSecurity3D dd 12,0,1
|
fortuneSessionDeal3D AnimPack3D <>
|
||||||
fortuneStartup3D dd 17 dup(0)
|
fortuneSessionGesture3D AnimPack3D <>
|
||||||
|
fortuneSessionOrbHands3D AnimPack3D <>
|
||||||
|
fortuneSessionMist3D AnimPack3D <>
|
||||||
|
fortuneSessionCards3D AnimPack3D <>
|
||||||
|
fortuneSessionPath0 db "assets\animations\fortune\room-v1.bin",0
|
||||||
|
fortuneSessionPath1 db "assets\animations\fortune\shuffle-v1.bin",0
|
||||||
|
fortuneSessionPath2 db "assets\animations\fortune\deal-v1.bin",0
|
||||||
|
fortuneSessionPath3 db "assets\animations\fortune\gesture-v1.bin",0
|
||||||
|
fortuneSessionPath4 db "assets\animations\fortune\orb-hands-v1.bin",0
|
||||||
|
fortuneSessionPath5 db "assets\animations\fortune\orb-mist-v1.bin",0
|
||||||
|
fortuneSessionPath6 db "assets\animations\fortune\cards-v1.bin",0
|
||||||
|
fortuneSessionPaths3D dd OFFSET fortuneSessionPath0,OFFSET fortuneSessionPath1,OFFSET fortuneSessionPath2,OFFSET fortuneSessionPath3
|
||||||
|
dd OFFSET fortuneSessionPath4,OFFSET fortuneSessionPath5,OFFSET fortuneSessionPath6
|
||||||
|
fortuneSubMode3D dd 0
|
||||||
|
fortunePhase3D dd 0
|
||||||
|
fortunePhaseTime3D dd 0
|
||||||
|
fortuneSessionClock3D dd 0
|
||||||
|
fortuneSpeechTime3D dd 0
|
||||||
|
fortuneSpeechLength3D dd 0
|
||||||
|
fortuneSpeechVisible3D dd 0
|
||||||
|
fortuneSpeechWidth3D dd 0
|
||||||
|
fortuneSpeechHeight3D dd 0
|
||||||
|
fortuneQuestionLength3D dd 0
|
||||||
|
fortuneQuestion3D db 241 dup(0)
|
||||||
|
fortuneDrawCards3D dd 3 dup(0)
|
||||||
|
fortuneCardsDrawn3D dd 0
|
||||||
|
fortuneDealt3D dd 0
|
||||||
|
fortuneRevealed3D dd 0
|
||||||
|
fortuneWorkerState3D dd 0
|
||||||
fortuneProcess3D dd 4 dup(0)
|
fortuneProcess3D dd 4 dup(0)
|
||||||
fortuneRead3D dd 0
|
fortuneRead3D dd 0
|
||||||
fortuneWrite3D dd 0
|
fortuneWrite3D dd 0
|
||||||
fortuneChildRead3D dd 0
|
fortuneSpeech3D db 256 dup(0)
|
||||||
fortuneChildWrite3D dd 0
|
fortuneLine3D db 73 dup(0)
|
||||||
fortuneNull3D dd 0
|
fortuneGlyph3D db 0,0
|
||||||
fortuneWorkerState3D dd 0 ; 0=off, 1=loading, 2=ready, 3=generating, 4=error
|
fortuneCaret3D db "_",0
|
||||||
fortuneWorkerTick3D dd 0
|
fortuneCaretX3D dd 24
|
||||||
fortuneReceiveLength3D dd -1
|
fortuneCaretY3D dd 402
|
||||||
fortuneReceiveHeader3D dd 3 dup(0)
|
|
||||||
fortuneRequest3D dd 31514346h,0,0,0,0
|
|
||||||
fortuneIo3D dd 0
|
|
||||||
fortuneAvailable3D dd 0
|
|
||||||
fortuneQuestionLength3D dd 0
|
|
||||||
fortuneQuestion3D db 241 dup(0)
|
|
||||||
fortuneAnswer3D db 8193 dup(0)
|
|
||||||
fortuneBackground3D dd SCREEN_SIZE dup(0)
|
|
||||||
fortunePage3D dd 0
|
fortunePage3D dd 0
|
||||||
fortuneMore3D dd 0
|
fortuneMore3D dd 0
|
||||||
fortuneShort3D dd 0
|
fortuneShort3D dd 0
|
||||||
fortuneLine3D db 73 dup(0)
|
fortuneDurations3D dd 0,3200,1000,1000,1000,800,3600,800,3600,800,3600,3600,0
|
||||||
fortuneCaretX3D dd 24
|
fortuneRoleTexts3D dd OFFSET fortuneFirst3D,OFFSET fortuneSecond3D,OFFSET fortuneThird3D
|
||||||
fortuneCaretY3D dd 366
|
|
||||||
fortuneCaret3D db "_",0
|
|
||||||
fortuneTitle3D db 195,192,196,192,203,202,192,0
|
fortuneTitle3D db 195,192,196,192,203,202,192,0
|
||||||
fortuneLoading3D db 207,240,238,225,243,230,228,224,254,32,234,224,240,242,251,46,46,46,0
|
|
||||||
fortuneThinking3D db 202,224,240,242,251,32,238,242,226,229,247,224,254,242,46,46,46,0
|
|
||||||
fortuneReady3D db 202,224,234,238,233,32,226,238,239,240,238,241,32,242,229,225,255,32,239,240,232,226,184,235,63,0
|
|
||||||
fortuneError3D db 205,229,32,243,228,224,235,238,241,252,32,231,224,239,243,241,242,232,242,252,32,237,229,233,240,238,241,229,242,252,46,32
|
|
||||||
db 207,240,238,226,229,240,252,32,234,238,236,239,235,229,234,242,32,232,227,240,251,46,0
|
|
||||||
fortuneAsk3D db 209,207,208,206,209,200,210,220,0
|
|
||||||
fortuneExit3D db 194,219,201,210,200,0
|
fortuneExit3D db 194,219,201,210,200,0
|
||||||
fortuneDisclaimer3D db 208,224,241,234,235,224,228,32,228,235,255,32,240,224,231,236,251,248,235,229,237,232,255,44,32
|
fortuneAsk3D db 209,207,208,206,209,200,210,220,0
|
||||||
db 237,229,32,228,238,241,242,238,226,229,240,237,238,229,32,239,240,229,228,241,234,224,231,224,237,232,229,46,0
|
fortuneAgain3D db 197,217,168,32,208,192,199,0
|
||||||
fortunePartial3D db 206,242,226,229,242,32,241,238,234,240,224,249,184,237,0
|
fortuneMenu3D db 194,219,193,206,208,0
|
||||||
fortuneLeft3D db "<",0
|
fortuneTarot3D db 195,192,196,192,205,200,197,0
|
||||||
fortuneRight3D db ">",0
|
fortuneFate3D db 208,197,216,197,205,200,197,32,209,211,196,220,193,219,0
|
||||||
|
fortuneWelcome3D db 215,242,238,32,242,229,225,255,32,239,240,232,226,229,235,238,63,0
|
||||||
|
fortuneReady3D db 202,224,234,238,233,32,226,238,239,240,238,241,10,242,229,225,255,32,239,240,232,226,184,235
|
||||||
|
db 63,0
|
||||||
|
fortuneShuffle3D db 210,192,209,206,194,192,205,200,197,0
|
||||||
|
fortuneDeal3D db 208,192,209,202,203,192,196,0
|
||||||
|
fortuneReveal3D db 202,192,208,210,219,32,206,210,202,208,219,194,192,222,210,209,223,0
|
||||||
|
fortuneSummary3D db 194,241,229,32,242,240,232,32,234,224,240,242,251,32,238,242,234,240,251,242,251,46,10,206
|
||||||
|
db 225,249,232,233,32,238,242,226,229,242,32,237,224,32,226,238,239,240,238,241,10,239,238,234
|
||||||
|
db 224,32,237,229,32,240,229,224,235,232,231,238,226,224,237,46,0
|
||||||
|
fortuneUnavailable3D db 207,238,234,224,32,237,229,32,236,238,227,243,32,238,225,250,255,241,237,232,242,252,10,231
|
||||||
|
db 237,224,247,229,237,232,229,32,253,242,238,233,32,234,224,240,242,251,46,0
|
||||||
|
fortuneOrbText3D db 216,224,240,32,236,238,235,247,232,242,46,10,208,229,248,229,237,232,229,32,239,238,234,224
|
||||||
|
db 32,237,229,32,240,229,224,235,232,231,238,226,224,237,238,46,0
|
||||||
|
fortuneOrbStatus3D db 213,208,211,209,210,192,203,220,205,219,201,32,216,192,208,0
|
||||||
|
fortuneMissing3D db 205,229,32,243,228,224,235,238,241,252,32,231,224,227,240,243,231,232,242,252,32,232,231,238,225,240,224,230,229,237,232,255,46,0
|
||||||
|
fortuneContinue3D db 196,192,203,220,216,197,0
|
||||||
|
fortuneQuestionLabel3D db 210,194,206,201,32,194,206,207,208,206,209,0
|
||||||
|
fortuneFirst3D db 207,197,208,194,192,223,32,202,192,208,210,192,0
|
||||||
|
fortuneSecond3D db 194,210,206,208,192,223,32,202,192,208,210,192,0
|
||||||
|
fortuneThird3D db 210,208,197,210,220,223,32,202,192,208,210,192,0
|
||||||
|
fortuneUpright3D db 207,240,255,236,238,229,32,239,238,235,238,230,229,237,232,229,0
|
||||||
|
fortuneReversed3D db 207,229,240,229,226,184,240,237,243,242,224,255,32,234,224,240,242,224,0
|
||||||
|
fortuneCardName0 db 216,243,242,0
|
||||||
|
fortuneCardName1 db 204,224,227,0
|
||||||
|
fortuneCardName2 db 194,229,240,245,238,226,237,224,255,32,230,240,232,246,224,0
|
||||||
|
fortuneCardName3 db 200,236,239,229,240,224,242,240,232,246,224,0
|
||||||
|
fortuneCardName4 db 200,236,239,229,240,224,242,238,240,0
|
||||||
|
fortuneCardName5 db 200,229,240,238,244,224,237,242,0
|
||||||
|
fortuneCardName6 db 194,235,254,225,235,184,237,237,251,229,0
|
||||||
|
fortuneCardName7 db 202,238,235,229,241,237,232,246,224,0
|
||||||
|
fortuneCardName8 db 209,232,235,224,0
|
||||||
|
fortuneCardName9 db 206,242,248,229,235,252,237,232,234,0
|
||||||
|
fortuneCardName10 db 202,238,235,229,241,238,32,244,238,240,242,243,237,251,0
|
||||||
|
fortuneCardName11 db 209,239,240,224,226,229,228,235,232,226,238,241,242,252,0
|
||||||
|
fortuneCardName12 db 207,238,226,229,248,229,237,237,251,233,0
|
||||||
|
fortuneCardName13 db 209,236,229,240,242,252,0
|
||||||
|
fortuneCardName14 db 211,236,229,240,229,237,237,238,241,242,252,0
|
||||||
|
fortuneCardName15 db 196,252,255,226,238,235,0
|
||||||
|
fortuneCardName16 db 193,224,248,237,255,0
|
||||||
|
fortuneCardName17 db 199,226,229,231,228,224,0
|
||||||
|
fortuneCardName18 db 203,243,237,224,0
|
||||||
|
fortuneCardName19 db 209,238,235,237,246,229,0
|
||||||
|
fortuneCardName20 db 209,243,228,0
|
||||||
|
fortuneCardName21 db 204,232,240,0
|
||||||
|
fortuneCardNames3D dd OFFSET fortuneCardName0,OFFSET fortuneCardName1,OFFSET fortuneCardName2,OFFSET fortuneCardName3
|
||||||
|
dd OFFSET fortuneCardName4,OFFSET fortuneCardName5,OFFSET fortuneCardName6,OFFSET fortuneCardName7
|
||||||
|
dd OFFSET fortuneCardName8,OFFSET fortuneCardName9,OFFSET fortuneCardName10,OFFSET fortuneCardName11
|
||||||
|
dd OFFSET fortuneCardName12,OFFSET fortuneCardName13,OFFSET fortuneCardName14,OFFSET fortuneCardName15
|
||||||
|
dd OFFSET fortuneCardName16,OFFSET fortuneCardName17,OFFSET fortuneCardName18,OFFSET fortuneCardName19
|
||||||
|
dd OFFSET fortuneCardName20,OFFSET fortuneCardName21
|
||||||
|
.data?
|
||||||
|
fortuneBackground3D dd SCREEN_SIZE dup(?)
|
||||||
|
.data
|
||||||
|
|
|
||||||
|
|
@ -781,6 +781,7 @@ CheckHallInteractions3D PROC
|
||||||
; A point on the serving edge remains in front even when standing close.
|
; A point on the serving edge remains in front even when standing close.
|
||||||
invoke HallTarget3D, playerX,23*FP_1+FP_HALF,INTERACT_BAR,OFFSET hallBarPrompt3D
|
invoke HallTarget3D, playerX,23*FP_1+FP_HALF,INTERACT_BAR,OFFSET hallBarPrompt3D
|
||||||
hall_check_other:
|
hall_check_other:
|
||||||
|
invoke HallTarget3D,FP_1*305/10,28*FP_1,INTERACT_DARTS,OFFSET dtPrompt
|
||||||
invoke HallTarget3D,16*FP_1,FP_1*73/10,INTERACT_CABARET_SEAT,OFFSET cabaretSeat3D
|
invoke HallTarget3D,16*FP_1,FP_1*73/10,INTERACT_CABARET_SEAT,OFFSET cabaretSeat3D
|
||||||
invoke HallTarget3D,scrStation3D.posX,scrStation3D.posY,INTERACT_SCRATCH,OFFSET scratchHall3D
|
invoke HallTarget3D,scrStation3D.posX,scrStation3D.posY,INTERACT_SCRATCH,OFFSET scratchHall3D
|
||||||
invoke HallTarget3D,FP_1*285/10,FP_1*105/10,INTERACT_BASEMENT,OFFSET hallBunkerPrompt3D
|
invoke HallTarget3D,FP_1*285/10,FP_1*105/10,INTERACT_BASEMENT,OFFSET hallBunkerPrompt3D
|
||||||
|
|
@ -797,6 +798,12 @@ hall_check_bunker:
|
||||||
CheckHallInteractions3D ENDP
|
CheckHallInteractions3D ENDP
|
||||||
|
|
||||||
TriggerHallInteraction3D PROC
|
TriggerHallInteraction3D PROC
|
||||||
|
cmp interactTargetId,INTERACT_DARTS
|
||||||
|
jne hall_not_darts
|
||||||
|
call BeginDarts3D
|
||||||
|
mov eax,1
|
||||||
|
ret
|
||||||
|
hall_not_darts:
|
||||||
call TryFortuneInteraction3D
|
call TryFortuneInteraction3D
|
||||||
test eax,eax
|
test eax,eax
|
||||||
jnz hall_trigger_handled
|
jnz hall_trigger_handled
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
DrawBJPartySelector3D PROC uses ebx esi edi
|
DrawBJPartySelector3D PROC uses ebx esi edi
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je @F
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
xor edi,edi
|
xor edi,edi
|
||||||
cmp cbState3D,CB_IDLE
|
cmp cbState3D,CB_IDLE
|
||||||
je @F
|
je @F
|
||||||
|
|
|
||||||
|
|
@ -573,33 +573,39 @@ dk_find_done:
|
||||||
DurakFindMove3D ENDP
|
DurakFindMove3D ENDP
|
||||||
|
|
||||||
DurakAITurn3D PROC
|
DurakAITurn3D PROC
|
||||||
cmp dkAttacker3D, 1
|
invoke DurakBotTurn3D,1
|
||||||
je dk_ai_attack
|
|
||||||
invoke DurakFindMove3D, 1, DK_TRANSFER
|
|
||||||
cmp eax, 0FFFFFFFFh
|
|
||||||
je @F
|
|
||||||
invoke DurakPlay3D, 1, eax, DK_TRANSFER
|
|
||||||
ret
|
|
||||||
@@:
|
|
||||||
invoke DurakFindMove3D, 1, DK_DEFEND
|
|
||||||
cmp eax, 0FFFFFFFFh
|
|
||||||
je dk_ai_take
|
|
||||||
invoke DurakPlay3D, 1, eax, DK_DEFEND
|
|
||||||
ret
|
|
||||||
dk_ai_take:
|
|
||||||
invoke DurakTake3D, 1
|
|
||||||
ret
|
|
||||||
dk_ai_attack:
|
|
||||||
invoke DurakFindMove3D, 1, DK_ATTACK
|
|
||||||
cmp eax, 0FFFFFFFFh
|
|
||||||
je dk_ai_finish
|
|
||||||
invoke DurakPlay3D, 1, eax, DK_ATTACK
|
|
||||||
ret
|
|
||||||
dk_ai_finish:
|
|
||||||
invoke DurakFinish3D, 1
|
|
||||||
ret
|
ret
|
||||||
DurakAITurn3D ENDP
|
DurakAITurn3D ENDP
|
||||||
|
|
||||||
|
DurakBotTurn3D PROC actor:DWORD
|
||||||
|
mov eax,actor
|
||||||
|
cmp dkAttacker3D,eax
|
||||||
|
je dk_ai_attack
|
||||||
|
invoke DurakFindMove3D, actor, DK_TRANSFER
|
||||||
|
cmp eax, 0FFFFFFFFh
|
||||||
|
je @F
|
||||||
|
invoke DurakPlay3D, actor, eax, DK_TRANSFER
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
invoke DurakFindMove3D, actor, DK_DEFEND
|
||||||
|
cmp eax, 0FFFFFFFFh
|
||||||
|
je dk_ai_take
|
||||||
|
invoke DurakPlay3D, actor, eax, DK_DEFEND
|
||||||
|
ret
|
||||||
|
dk_ai_take:
|
||||||
|
invoke DurakTake3D, actor
|
||||||
|
ret
|
||||||
|
dk_ai_attack:
|
||||||
|
invoke DurakFindMove3D, actor, DK_ATTACK
|
||||||
|
cmp eax, 0FFFFFFFFh
|
||||||
|
je dk_ai_finish
|
||||||
|
invoke DurakPlay3D, actor, eax, DK_ATTACK
|
||||||
|
ret
|
||||||
|
dk_ai_finish:
|
||||||
|
invoke DurakFinish3D, actor
|
||||||
|
ret
|
||||||
|
DurakBotTurn3D ENDP
|
||||||
|
|
||||||
DurakMouse3D PROC uses ebx
|
DurakMouse3D PROC uses ebx
|
||||||
cmp mouseClick3D, 0
|
cmp mouseClick3D, 0
|
||||||
je dk_mouse_done
|
je dk_mouse_done
|
||||||
|
|
|
||||||
|
|
@ -382,19 +382,27 @@ poker_showdown_done:
|
||||||
PokerShowdown3D ENDP
|
PokerShowdown3D ENDP
|
||||||
|
|
||||||
; The AI sees only its two cards and the already exposed board. No player cards/future deck.
|
; The AI sees only its two cards and the already exposed board. No player cards/future deck.
|
||||||
PokerAIDecide3D PROC uses ebx esi edi
|
PokerAIDecide3D PROC
|
||||||
|
invoke PokerBotAct3D,1
|
||||||
|
ret
|
||||||
|
PokerAIDecide3D ENDP
|
||||||
|
|
||||||
|
PokerBotAct3D PROC uses ebx esi edi actor:DWORD
|
||||||
local strength:DWORD,owed:DWORD
|
local strength:DWORD,owed:DWORD
|
||||||
mov eax, pkCurrent3D
|
mov eax, pkCurrent3D
|
||||||
sub eax, pkPaid3D[4]
|
mov ecx,actor
|
||||||
|
sub eax, pkPaid3D[ecx*4]
|
||||||
mov owed, eax
|
mov owed, eax
|
||||||
cmp pkBoardCount3D, 3
|
cmp pkBoardCount3D, 3
|
||||||
jae poker_ai_postflop
|
jae poker_ai_postflop
|
||||||
mov eax, pkHole3D[8]
|
mov ebx,actor
|
||||||
|
shl ebx,3
|
||||||
|
mov eax, pkHole3D[ebx]
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
mov ecx, 13
|
mov ecx, 13
|
||||||
div ecx
|
div ecx
|
||||||
mov esi, edx
|
mov esi, edx
|
||||||
mov eax, pkHole3D[12]
|
mov eax, pkHole3D[ebx+4]
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
div ecx
|
div ecx
|
||||||
mov strength, 0
|
mov strength, 0
|
||||||
|
|
@ -416,7 +424,8 @@ poker_ai_pair:
|
||||||
jmp poker_ai_odds
|
jmp poker_ai_odds
|
||||||
poker_ai_postflop:
|
poker_ai_postflop:
|
||||||
lea edi, pkEvalHand3D
|
lea edi, pkEvalHand3D
|
||||||
lea esi, pkHole3D[8]
|
mov eax,actor
|
||||||
|
lea esi, pkHole3D[eax*8]
|
||||||
movsd
|
movsd
|
||||||
movsd
|
movsd
|
||||||
lea esi, pkBoard3D
|
lea esi, pkBoard3D
|
||||||
|
|
@ -452,7 +461,12 @@ poker_ai_consider_raise:
|
||||||
je poker_ai_call
|
je poker_ai_call
|
||||||
cmp pkRaisedCount3D, 2
|
cmp pkRaisedCount3D, 2
|
||||||
jae poker_ai_call
|
jae poker_ai_call
|
||||||
cmp bankroll, 0
|
mov eax,bankroll
|
||||||
|
cmp actor,1
|
||||||
|
je @F
|
||||||
|
mov eax,pkStack3D
|
||||||
|
@@:
|
||||||
|
cmp eax, 0
|
||||||
je poker_ai_call
|
je poker_ai_call
|
||||||
cmp strength, 3
|
cmp strength, 3
|
||||||
jae poker_ai_strong_raise
|
jae poker_ai_strong_raise
|
||||||
|
|
@ -464,11 +478,11 @@ poker_ai_strong_raise:
|
||||||
jae poker_ai_call
|
jae poker_ai_call
|
||||||
poker_ai_raise:
|
poker_ai_raise:
|
||||||
mov pkAiMessage3D, 3
|
mov pkAiMessage3D, 3
|
||||||
invoke PokerRaise3D, 1, pkMinRaise3D
|
invoke PokerRaise3D, actor, pkMinRaise3D
|
||||||
ret
|
ret
|
||||||
poker_ai_fold:
|
poker_ai_fold:
|
||||||
mov pkAiMessage3D, 4
|
mov pkAiMessage3D, 4
|
||||||
invoke PokerFold3D, 1
|
invoke PokerFold3D, actor
|
||||||
ret
|
ret
|
||||||
poker_ai_call:
|
poker_ai_call:
|
||||||
mov pkAiMessage3D, 1
|
mov pkAiMessage3D, 1
|
||||||
|
|
@ -476,9 +490,9 @@ poker_ai_call:
|
||||||
je @F
|
je @F
|
||||||
mov pkAiMessage3D, 2
|
mov pkAiMessage3D, 2
|
||||||
@@:
|
@@:
|
||||||
invoke PokerCall3D, 1
|
invoke PokerCall3D, actor
|
||||||
ret
|
ret
|
||||||
PokerAIDecide3D ENDP
|
PokerBotAct3D ENDP
|
||||||
|
|
||||||
HandleNativePoker3D PROC uses ebx
|
HandleNativePoker3D PROC uses ebx
|
||||||
call HandleCardExit3D
|
call HandleCardExit3D
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,8 @@ npc_accept_done:
|
||||||
NpcAcceptContract3D ENDP
|
NpcAcceptContract3D ENDP
|
||||||
|
|
||||||
NpcRecordRound3D PROC uses ebx esi edi game:DWORD,won:DWORD
|
NpcRecordRound3D PROC uses ebx esi edi game:DWORD,won:DWORD
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne npc_event_done
|
||||||
call NpcEnsureJournal3D
|
call NpcEnsureJournal3D
|
||||||
test eax,eax
|
test eax,eax
|
||||||
jz npc_event_done
|
jz npc_event_done
|
||||||
|
|
|
||||||
494
src_graphics/observer.inc
Normal file
|
|
@ -0,0 +1,494 @@
|
||||||
|
; Spectator control supplies decisions to the real native games, never simulated results.
|
||||||
|
.code
|
||||||
|
BeginObserver3D PROC uses esi edi
|
||||||
|
lea esi,screenBuffer
|
||||||
|
lea edi,obsBackground3D
|
||||||
|
mov ecx,SCREEN_SIZE
|
||||||
|
rep movsd
|
||||||
|
mov engineMode,MODE_OBSERVER
|
||||||
|
mov obsError3D,0
|
||||||
|
mov paused3D,0
|
||||||
|
call ClearKeys3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
ret
|
||||||
|
BeginObserver3D ENDP
|
||||||
|
|
||||||
|
StartObserver3D PROC uses ebx esi
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne obs_start_done
|
||||||
|
cmp obsSelection3D,OBS_GAME_COUNT
|
||||||
|
jae obs_start_done
|
||||||
|
xor esi,esi
|
||||||
|
obs_save_profile:
|
||||||
|
mov ebx,obsProfilePointers3D[esi*4]
|
||||||
|
mov eax,[ebx]
|
||||||
|
mov obsSavedProfile3D[esi*4],eax
|
||||||
|
inc esi
|
||||||
|
cmp esi,LENGTHOF obsProfilePointers3D
|
||||||
|
jb obs_save_profile
|
||||||
|
mov obsActive3D,1
|
||||||
|
mov obsPaused3D,0
|
||||||
|
mov obsRound3D,0
|
||||||
|
mov obsWins3D[0],0
|
||||||
|
mov obsWins3D[4],0
|
||||||
|
mov obsWins3D[8],0
|
||||||
|
mov tournamentMode,0
|
||||||
|
mov cardExitActive3D,0
|
||||||
|
mov obsError3D,0
|
||||||
|
mov eax,obsSelection3D
|
||||||
|
mov eax,obsModes3D[eax*4]
|
||||||
|
mov engineMode,eax
|
||||||
|
cmp eax,MODE_POOL
|
||||||
|
je obs_init_pool
|
||||||
|
cmp eax,MODE_DURAK
|
||||||
|
je obs_init_durak
|
||||||
|
cmp eax,MODE_BLACKJACK
|
||||||
|
je obs_init_blackjack
|
||||||
|
call InitNativePoker3D
|
||||||
|
jmp obs_check_assets
|
||||||
|
obs_init_durak:
|
||||||
|
call InitNativeDurak3D
|
||||||
|
mov eax,obsSelection3D
|
||||||
|
sub eax,2
|
||||||
|
mov dkVariant3D,eax
|
||||||
|
jmp obs_check_assets
|
||||||
|
obs_init_blackjack:
|
||||||
|
call InitNativeBlackjack3D
|
||||||
|
mov cbBotCount3D,0
|
||||||
|
obs_check_assets:
|
||||||
|
cmp cardTablePixels3D,0
|
||||||
|
jne obs_start_round
|
||||||
|
call StopObserver3D
|
||||||
|
mov obsError3D,1
|
||||||
|
ret
|
||||||
|
obs_init_pool:
|
||||||
|
mov poolAI3D,1
|
||||||
|
mov eax,obsSelection3D
|
||||||
|
sub eax,4
|
||||||
|
invoke StartBilliards3D,eax
|
||||||
|
obs_start_round:
|
||||||
|
call ObserverNewRound3D
|
||||||
|
obs_start_done:
|
||||||
|
ret
|
||||||
|
StartObserver3D ENDP
|
||||||
|
|
||||||
|
StopObserver3D PROC uses esi ebx
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je obs_stop_menu
|
||||||
|
; The save barrier remains active until every personal value has been restored.
|
||||||
|
xor esi,esi
|
||||||
|
obs_restore_profile:
|
||||||
|
mov ebx,obsProfilePointers3D[esi*4]
|
||||||
|
mov eax,obsSavedProfile3D[esi*4]
|
||||||
|
mov [ebx],eax
|
||||||
|
inc esi
|
||||||
|
cmp esi,LENGTHOF obsProfilePointers3D
|
||||||
|
jb obs_restore_profile
|
||||||
|
mov obsActive3D,0
|
||||||
|
obs_stop_menu:
|
||||||
|
mov engineMode,MODE_OBSERVER
|
||||||
|
mov paused3D,0
|
||||||
|
mov cardExitActive3D,0
|
||||||
|
call ClearKeys3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
invoke PlayCasinoSound3D,0,0,0
|
||||||
|
ret
|
||||||
|
StopObserver3D ENDP
|
||||||
|
|
||||||
|
ObserverNewRound3D PROC
|
||||||
|
mov obsTimer3D,0
|
||||||
|
mov obsResultTimer3D,0
|
||||||
|
mov obsOutcome3D,0
|
||||||
|
inc obsRound3D
|
||||||
|
mov bankroll,10000
|
||||||
|
cmp engineMode,MODE_POOL
|
||||||
|
jne @F
|
||||||
|
call ResetPool3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_DURAK
|
||||||
|
jne @F
|
||||||
|
mov dkBet3D,100
|
||||||
|
mov dkState3D,DK_IDLE
|
||||||
|
call StartNativeDurak3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_BLACKJACK
|
||||||
|
jne @F
|
||||||
|
mov cbBet3D,100
|
||||||
|
mov cbState3D,CB_IDLE
|
||||||
|
call StartNativeBlackjack3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
mov pkBlind3D,50
|
||||||
|
mov pkState3D,PK_IDLE
|
||||||
|
call StartNativePoker3D
|
||||||
|
ret
|
||||||
|
ObserverNewRound3D ENDP
|
||||||
|
|
||||||
|
ObserverOutcome3D PROC
|
||||||
|
cmp engineMode,MODE_POOL
|
||||||
|
jne @F
|
||||||
|
cmp poolState3D,POOL_RESULT
|
||||||
|
jne obs_no_outcome
|
||||||
|
mov eax,poolWinner3D
|
||||||
|
inc eax
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_DURAK
|
||||||
|
jne @F
|
||||||
|
cmp dkState3D,DK_RESULT
|
||||||
|
jne obs_no_outcome
|
||||||
|
mov eax,dkOutcome3D
|
||||||
|
inc eax
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_BLACKJACK
|
||||||
|
jne @F
|
||||||
|
cmp cbState3D,CB_RESULT
|
||||||
|
jne obs_no_outcome
|
||||||
|
mov eax,cbOutcome3D
|
||||||
|
cmp eax,3
|
||||||
|
jne obs_number_outcome
|
||||||
|
mov eax,1
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp pkState3D,PK_RESULT
|
||||||
|
jne obs_no_outcome
|
||||||
|
mov eax,pkOutcome3D
|
||||||
|
obs_number_outcome:
|
||||||
|
inc eax
|
||||||
|
ret
|
||||||
|
obs_no_outcome:
|
||||||
|
xor eax,eax
|
||||||
|
ret
|
||||||
|
ObserverOutcome3D ENDP
|
||||||
|
|
||||||
|
ObserverBlackjack3D PROC
|
||||||
|
cmp cbState3D,CB_PLAYER
|
||||||
|
jne obs_bj_update
|
||||||
|
cmp obsTimer3D,700
|
||||||
|
jb obs_bj_update
|
||||||
|
mov obsTimer3D,0
|
||||||
|
; Only our hand and the dealer's exposed up-card enter the decision.
|
||||||
|
cmp cbPlayerScore3D,17
|
||||||
|
jae obs_bj_stand
|
||||||
|
cmp cbPlayerScore3D,12
|
||||||
|
jb obs_bj_hit
|
||||||
|
mov eax,cbDealer3D[0]
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,13
|
||||||
|
div ecx
|
||||||
|
cmp edx,5
|
||||||
|
jae obs_bj_hit
|
||||||
|
obs_bj_stand:
|
||||||
|
invoke FinishBJPlayer3D,-1
|
||||||
|
jmp obs_bj_update
|
||||||
|
obs_bj_hit:
|
||||||
|
call NativeBJHit3D
|
||||||
|
obs_bj_update:
|
||||||
|
call HandleNativeBlackjack3D
|
||||||
|
ret
|
||||||
|
ObserverBlackjack3D ENDP
|
||||||
|
|
||||||
|
ObserverDurak3D PROC
|
||||||
|
cmp dkState3D,DK_TURN
|
||||||
|
jne obs_durak_update
|
||||||
|
cmp dkActor3D,0
|
||||||
|
jne obs_durak_update
|
||||||
|
cmp obsTimer3D,700
|
||||||
|
jb obs_durak_update
|
||||||
|
mov obsTimer3D,0
|
||||||
|
invoke DurakBotTurn3D,0
|
||||||
|
obs_durak_update:
|
||||||
|
call HandleNativeDurak3D
|
||||||
|
ret
|
||||||
|
ObserverDurak3D ENDP
|
||||||
|
|
||||||
|
ObserverTick3D PROC uses ebx
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je obs_tick_done
|
||||||
|
call ObserverOutcome3D
|
||||||
|
test eax,eax
|
||||||
|
jz obs_tick_game
|
||||||
|
cmp obsOutcome3D,0
|
||||||
|
jne obs_result_wait
|
||||||
|
mov obsOutcome3D,eax
|
||||||
|
inc obsWins3D[eax*4-4]
|
||||||
|
mov obsResultTimer3D,0
|
||||||
|
obs_result_wait:
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add obsResultTimer3D,eax
|
||||||
|
cmp obsResultTimer3D,3000
|
||||||
|
jb obs_tick_done
|
||||||
|
call ObserverNewRound3D
|
||||||
|
ret
|
||||||
|
obs_tick_game:
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add obsTimer3D,eax
|
||||||
|
cmp engineMode,MODE_POOL
|
||||||
|
jne @F
|
||||||
|
call HandlePool3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_DURAK
|
||||||
|
jne @F
|
||||||
|
call ObserverDurak3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_BLACKJACK
|
||||||
|
jne @F
|
||||||
|
call ObserverBlackjack3D
|
||||||
|
ret
|
||||||
|
@@:
|
||||||
|
cmp pkState3D,PK_PLAYER
|
||||||
|
jne obs_poker_update
|
||||||
|
cmp obsTimer3D,700
|
||||||
|
jb obs_poker_update
|
||||||
|
mov obsTimer3D,0
|
||||||
|
invoke PokerBotAct3D,0
|
||||||
|
obs_poker_update:
|
||||||
|
call HandleNativePoker3D
|
||||||
|
obs_tick_done:
|
||||||
|
ret
|
||||||
|
ObserverTick3D ENDP
|
||||||
|
|
||||||
|
ObserverFrame3D PROC uses ebx esi
|
||||||
|
invoke Pressed3D,1Bh
|
||||||
|
test eax,eax
|
||||||
|
jz obs_frame_input
|
||||||
|
cmp obsActive3D,0
|
||||||
|
je obs_leave_hall
|
||||||
|
call StopObserver3D
|
||||||
|
jmp obs_frame_draw
|
||||||
|
obs_leave_hall:
|
||||||
|
mov engineMode,MODE_WALK
|
||||||
|
call ClearKeys3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
jmp obs_frame_draw
|
||||||
|
obs_frame_input:
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne obs_watch_input
|
||||||
|
xor esi,esi
|
||||||
|
obs_menu_digit:
|
||||||
|
lea eax,[esi+31h]
|
||||||
|
invoke Pressed3D,eax
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_menu_pick
|
||||||
|
inc esi
|
||||||
|
cmp esi,OBS_GAME_COUNT
|
||||||
|
jb obs_menu_digit
|
||||||
|
invoke Pressed3D,26h
|
||||||
|
test eax,eax
|
||||||
|
jz @F
|
||||||
|
cmp obsSelection3D,0
|
||||||
|
jne obs_menu_up
|
||||||
|
mov obsSelection3D,OBS_GAME_COUNT
|
||||||
|
obs_menu_up:
|
||||||
|
dec obsSelection3D
|
||||||
|
@@:
|
||||||
|
invoke Pressed3D,28h
|
||||||
|
test eax,eax
|
||||||
|
jz @F
|
||||||
|
inc obsSelection3D
|
||||||
|
cmp obsSelection3D,OBS_GAME_COUNT
|
||||||
|
jb @F
|
||||||
|
mov obsSelection3D,0
|
||||||
|
@@:
|
||||||
|
invoke Pressed3D,0Dh
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_menu_start
|
||||||
|
cmp mouseClick3D,0
|
||||||
|
je obs_frame_draw
|
||||||
|
cmp mouseX3D,16
|
||||||
|
jb obs_frame_draw
|
||||||
|
cmp mouseX3D,304
|
||||||
|
jae obs_frame_draw
|
||||||
|
mov eax,mouseY3D
|
||||||
|
sub eax,52
|
||||||
|
js obs_frame_draw
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,23
|
||||||
|
div ecx
|
||||||
|
cmp eax,OBS_GAME_COUNT
|
||||||
|
jae obs_menu_close_click
|
||||||
|
cmp edx,20
|
||||||
|
jae obs_frame_draw
|
||||||
|
mov esi,eax
|
||||||
|
obs_menu_pick:
|
||||||
|
mov obsSelection3D,esi
|
||||||
|
obs_menu_start:
|
||||||
|
call StartObserver3D
|
||||||
|
jmp obs_frame_draw
|
||||||
|
obs_menu_close_click:
|
||||||
|
cmp mouseY3D,212
|
||||||
|
jb obs_frame_draw
|
||||||
|
jmp obs_leave_hall
|
||||||
|
obs_watch_input:
|
||||||
|
invoke Pressed3D,20h
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_watch_pause
|
||||||
|
invoke Pressed3D,9
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_watch_speed
|
||||||
|
invoke Pressed3D,4Eh
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_watch_restart
|
||||||
|
cmp mouseClick3D,0
|
||||||
|
je obs_watch_tick
|
||||||
|
cmp mouseY3D,222
|
||||||
|
jb obs_watch_tick
|
||||||
|
cmp mouseY3D,239
|
||||||
|
jae obs_watch_tick
|
||||||
|
mov eax,mouseX3D
|
||||||
|
cmp eax,74
|
||||||
|
jb obs_watch_pause
|
||||||
|
cmp eax,134
|
||||||
|
jb obs_watch_speed
|
||||||
|
cmp eax,226
|
||||||
|
jb obs_watch_restart
|
||||||
|
call StopObserver3D
|
||||||
|
jmp obs_frame_draw
|
||||||
|
obs_watch_pause:
|
||||||
|
xor obsPaused3D,1
|
||||||
|
jmp obs_watch_tick
|
||||||
|
obs_watch_speed:
|
||||||
|
shl obsSpeed3D,1
|
||||||
|
cmp obsSpeed3D,4
|
||||||
|
jbe obs_watch_tick
|
||||||
|
mov obsSpeed3D,1
|
||||||
|
jmp obs_watch_tick
|
||||||
|
obs_watch_restart:
|
||||||
|
call ObserverNewRound3D
|
||||||
|
obs_watch_tick:
|
||||||
|
; Human game commands never reach the autonomous seats.
|
||||||
|
call ClearKeys3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
cmp obsPaused3D,0
|
||||||
|
jne obs_frame_draw
|
||||||
|
mov ebx,deltaTime3D
|
||||||
|
mov eax,ebx
|
||||||
|
imul eax,obsSpeed3D
|
||||||
|
mov deltaTime3D,eax
|
||||||
|
add animationClock3D,eax
|
||||||
|
call ObserverTick3D
|
||||||
|
mov deltaTime3D,ebx
|
||||||
|
obs_frame_draw:
|
||||||
|
call RenderObserver3D
|
||||||
|
mov mouseClick3D,0
|
||||||
|
ret
|
||||||
|
ObserverFrame3D ENDP
|
||||||
|
|
||||||
|
RenderObserver3D PROC uses ebx esi edi
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne obs_render_game
|
||||||
|
lea esi,obsBackground3D
|
||||||
|
lea edi,screenBuffer
|
||||||
|
mov ecx,SCREEN_SIZE
|
||||||
|
rep movsd
|
||||||
|
invoke DrawBox,0,0,320,240,00151D20h
|
||||||
|
invoke DrawString8x8,16,18,OFFSET obsTitle,00E8D7ADh
|
||||||
|
xor ebx,ebx
|
||||||
|
obs_render_row:
|
||||||
|
imul esi,ebx,23
|
||||||
|
add esi,52
|
||||||
|
mov edi,00728689h
|
||||||
|
cmp ebx,obsSelection3D
|
||||||
|
jne @F
|
||||||
|
mov edi,00E8D7ADh
|
||||||
|
@@:
|
||||||
|
invoke DrawBoxBorder,16,esi,288,20,00293436h,edi,1
|
||||||
|
add esi,6
|
||||||
|
lea eax,[ebx+1]
|
||||||
|
invoke FormatNumber,eax,OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,24,esi,OFFSET hudNumBuffer,edi
|
||||||
|
invoke DrawString8x8,48,esi,obsNames3D[ebx*4],edi
|
||||||
|
inc ebx
|
||||||
|
cmp ebx,OBS_GAME_COUNT
|
||||||
|
jb obs_render_row
|
||||||
|
invoke DrawBoxBorder,16,212,288,20,00293436h,00728689h,1
|
||||||
|
invoke DrawString8x8,136,218,OFFSET obsClose,00E8D7ADh
|
||||||
|
cmp obsError3D,0
|
||||||
|
je obs_render_done
|
||||||
|
invoke DrawString8x8,16,198,OFFSET obsFailed,00DB8B83h
|
||||||
|
ret
|
||||||
|
obs_render_game:
|
||||||
|
cmp engineMode,MODE_POOL
|
||||||
|
jne @F
|
||||||
|
call RenderPool3D
|
||||||
|
jmp obs_render_hud
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_DURAK
|
||||||
|
jne @F
|
||||||
|
call RenderNativeDurak3D
|
||||||
|
jmp obs_render_hud
|
||||||
|
@@:
|
||||||
|
cmp engineMode,MODE_BLACKJACK
|
||||||
|
jne @F
|
||||||
|
call RenderNativeBlackjack3D
|
||||||
|
jmp obs_render_hud
|
||||||
|
@@:
|
||||||
|
call RenderNativePoker3D
|
||||||
|
obs_render_hud:
|
||||||
|
invoke DrawBox,0,0,320,32,00151D20h
|
||||||
|
mov ebx,obsSelection3D
|
||||||
|
invoke DrawString8x8,8,5,obsNames3D[ebx*4],00E8D7ADh
|
||||||
|
invoke DrawString8x8,8,20,OFFSET obsFirst,0090CDB2h
|
||||||
|
invoke FormatNumber,obsWins3D[0],OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,48,20,OFFSET hudNumBuffer,0090CDB2h
|
||||||
|
invoke DrawString8x8,88,20,OFFSET obsSecond,00DEA0A0h
|
||||||
|
invoke FormatNumber,obsWins3D[4],OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,128,20,OFFSET hudNumBuffer,00DEA0A0h
|
||||||
|
invoke DrawString8x8,190,20,OFFSET obsRound,00E8D7ADh
|
||||||
|
invoke FormatNumber,obsRound3D,OFFSET hudNumBuffer
|
||||||
|
invoke DrawString8x8,254,20,OFFSET hudNumBuffer,00FFFFFFh
|
||||||
|
invoke DrawBox,0,215,320,25,00151D20h
|
||||||
|
cmp obsOutcome3D,0
|
||||||
|
je obs_render_turn
|
||||||
|
mov ebx,OFFSET obsWin1
|
||||||
|
cmp obsOutcome3D,1
|
||||||
|
je @F
|
||||||
|
mov ebx,OFFSET obsWin2
|
||||||
|
cmp obsOutcome3D,2
|
||||||
|
je @F
|
||||||
|
mov ebx,OFFSET obsDraw
|
||||||
|
@@:
|
||||||
|
invoke DrawString8x8,200,5,ebx,00E8D7ADh
|
||||||
|
jmp obs_render_controls
|
||||||
|
obs_render_turn:
|
||||||
|
mov eax,pkTurn3D
|
||||||
|
cmp engineMode,MODE_POKER
|
||||||
|
je obs_render_actor
|
||||||
|
mov eax,dkActor3D
|
||||||
|
cmp engineMode,MODE_DURAK
|
||||||
|
je obs_render_actor
|
||||||
|
mov eax,poolPlayer3D
|
||||||
|
cmp engineMode,MODE_POOL
|
||||||
|
je obs_render_actor
|
||||||
|
xor eax,eax
|
||||||
|
cmp cbState3D,CB_DEALER
|
||||||
|
jne obs_render_actor
|
||||||
|
inc eax
|
||||||
|
obs_render_actor:
|
||||||
|
and eax,1
|
||||||
|
invoke DrawString8x8,232,5,obsTurnNames3D[eax*4],00A7C7C5h
|
||||||
|
obs_render_controls:
|
||||||
|
mov ebx,OFFSET obsPause
|
||||||
|
cmp obsPaused3D,0
|
||||||
|
je @F
|
||||||
|
mov ebx,OFFSET obsPlay
|
||||||
|
@@:
|
||||||
|
invoke DrawBoxBorder,4,222,66,16,00293436h,00728689h,1
|
||||||
|
invoke DrawString8x8,14,226,ebx,00FFFFFFh
|
||||||
|
mov eax,obsSpeed3D
|
||||||
|
shr eax,1
|
||||||
|
mov ebx,obsSpeedNames3D[eax*4]
|
||||||
|
invoke DrawBoxBorder,78,222,48,16,00293436h,00728689h,1
|
||||||
|
invoke DrawString8x8,94,226,ebx,00FFFFFFh
|
||||||
|
invoke DrawBoxBorder,138,222,80,16,00293436h,00728689h,1
|
||||||
|
invoke DrawString8x8,154,226,OFFSET obsRestart,00FFFFFFh
|
||||||
|
invoke DrawBoxBorder,230,222,86,16,00293436h,00728689h,1
|
||||||
|
invoke DrawString8x8,254,226,OFFSET obsGames,00FFFFFFh
|
||||||
|
obs_render_done:
|
||||||
|
ret
|
||||||
|
RenderObserver3D ENDP
|
||||||
64
src_graphics/observer_data.inc
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
; Native observer uses the existing games; no alternate rules engine.
|
||||||
|
MODE_OBSERVER equ 26
|
||||||
|
OBS_GAME_COUNT equ 6
|
||||||
|
BeginObserver3D PROTO
|
||||||
|
ObserverFrame3D PROTO
|
||||||
|
StartObserver3D PROTO
|
||||||
|
StopObserver3D PROTO
|
||||||
|
ObserverNewRound3D PROTO
|
||||||
|
ObserverTick3D PROTO
|
||||||
|
ObserverOutcome3D PROTO
|
||||||
|
RenderObserver3D PROTO
|
||||||
|
ObserverBlackjack3D PROTO
|
||||||
|
ObserverDurak3D PROTO
|
||||||
|
PokerBotAct3D PROTO :DWORD
|
||||||
|
DurakBotTurn3D PROTO :DWORD
|
||||||
|
.data
|
||||||
|
obsActive3D dd 0
|
||||||
|
obsSelection3D dd 0
|
||||||
|
obsPaused3D dd 0
|
||||||
|
obsSpeed3D dd 1
|
||||||
|
obsTimer3D dd 0
|
||||||
|
obsResultTimer3D dd 0
|
||||||
|
obsOutcome3D dd 0
|
||||||
|
obsRound3D dd 0
|
||||||
|
obsWins3D dd 0,0,0
|
||||||
|
obsError3D dd 0
|
||||||
|
obsModes3D dd MODE_POKER,MODE_BLACKJACK,MODE_DURAK,MODE_DURAK,MODE_POOL,MODE_POOL
|
||||||
|
obsNames3D dd OFFSET obsPoker,OFFSET obsBlackjack,OFFSET obsDurak,OFFSET obsTransfer,OFFSET obsPyramid,OFFSET obsEight
|
||||||
|
obsProfilePointers3D dd OFFSET bankroll,OFFSET rngSeed3D,OFFSET tournamentMode
|
||||||
|
dd OFFSET pkBlind3D,OFFSET cbBet3D,OFFSET dkBet3D,OFFSET dkVariant3D
|
||||||
|
dd OFFSET poolVariant3D,OFFSET poolAI3D,OFFSET cbBotCount3D
|
||||||
|
obsSavedProfile3D dd 10 dup(0)
|
||||||
|
obsSpeedNames3D dd OFFSET obsSpeed1,OFFSET obsSpeed2,OFFSET obsSpeed4
|
||||||
|
obsSpeed1 db "1X",0
|
||||||
|
obsSpeed2 db "2X",0
|
||||||
|
obsSpeed4 db "4X",0
|
||||||
|
obsSeparator db ":",0
|
||||||
|
obsResultNames3D dd OFFSET obsWin1,OFFSET obsWin2,OFFSET obsDraw
|
||||||
|
obsTurnNames3D dd OFFSET obsTurn1,OFFSET obsTurn2
|
||||||
|
obsTurn1 db 213,206,196,32,200,200,32,49,0
|
||||||
|
obsTurn2 db 213,206,196,32,200,200,32,50,0
|
||||||
|
obsTitle db 205,192,193,203,222,196,197,205,200,197,0
|
||||||
|
obsPoker db 207,206,202,197,208,0
|
||||||
|
obsBlackjack db 50,49,0
|
||||||
|
obsDurak db 196,211,208,192,202,58,32,207,206,196,202,200,196,205,206,201,0
|
||||||
|
obsTransfer db 196,211,208,192,202,58,32,207,197,208,197,194,206,196,205,206,201,0
|
||||||
|
obsPyramid db 193,200,203,220,223,208,196,58,32,207,200,208,192,204,200,196,192,0
|
||||||
|
obsEight db 193,200,203,220,223,208,196,58,32,194,206,209,220,204,197,208,202,192,0
|
||||||
|
obsFirst db 200,200,32,49,0
|
||||||
|
obsSecond db 200,200,32,50,0
|
||||||
|
obsDraw db 205,200,215,220,223,0
|
||||||
|
obsWin1 db 207,206,193,197,196,192,32,200,200,32,49,0
|
||||||
|
obsWin2 db 207,206,193,197,196,192,32,200,200,32,50,0
|
||||||
|
obsPause db 207,192,211,199,192,0
|
||||||
|
obsPlay db 62,0
|
||||||
|
obsRestart db 199,192,205,206,194,206,0
|
||||||
|
obsGames db 200,195,208,219,0
|
||||||
|
obsRound db 207,192,208,210,200,223,0
|
||||||
|
obsClose db 194,32,213,206,203,203,0
|
||||||
|
obsFailed db 205,197,32,211,196,192,203,206,209,220,32,206,210,202,208,219,210,220,32,209,210,206,203,0
|
||||||
|
.data?
|
||||||
|
obsBackground3D dd SCREEN_SIZE dup(?)
|
||||||
|
.code
|
||||||
|
|
||||||
|
|
@ -13,6 +13,13 @@ WindowEvents3D PROC uses ebx esi edi hwnd:DWORD, uMsg:DWORD, wp:DWORD, lp:DWORD
|
||||||
invoke FortuneChar3D, wp
|
invoke FortuneChar3D, wp
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
ret
|
ret
|
||||||
|
@@:
|
||||||
|
cmp uMsg,202h
|
||||||
|
jne @F
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
jne event_default
|
||||||
|
mov dtMouseReleased3D,1
|
||||||
|
jmp event_mouse_down
|
||||||
@@:
|
@@:
|
||||||
cmp uMsg, 201h
|
cmp uMsg, 201h
|
||||||
je event_mouse_down
|
je event_mouse_down
|
||||||
|
|
@ -24,6 +31,8 @@ WindowEvents3D PROC uses ebx esi edi hwnd:DWORD, uMsg:DWORD, wp:DWORD, lp:DWORD
|
||||||
@@:
|
@@:
|
||||||
cmp uMsg, 200h
|
cmp uMsg, 200h
|
||||||
jne @F
|
jne @F
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
je event_mouse_down
|
||||||
cmp engineMode, MODE_POOL
|
cmp engineMode, MODE_POOL
|
||||||
jne event_default
|
jne event_default
|
||||||
test wp, 1
|
test wp, 1
|
||||||
|
|
@ -61,6 +70,15 @@ event_mouse_down:
|
||||||
sub eax, viewLeft3D
|
sub eax, viewLeft3D
|
||||||
cmp eax, viewWidth3D
|
cmp eax, viewWidth3D
|
||||||
jae event_done
|
jae event_done
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
jne event_coarse_x
|
||||||
|
push eax
|
||||||
|
imul eax,640*256
|
||||||
|
xor edx,edx
|
||||||
|
div viewWidth3D
|
||||||
|
mov dtCursorX3D,eax
|
||||||
|
pop eax
|
||||||
|
event_coarse_x:
|
||||||
imul eax, 320
|
imul eax, 320
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
div viewWidth3D
|
div viewWidth3D
|
||||||
|
|
@ -69,6 +87,15 @@ event_mouse_down:
|
||||||
sub eax, viewTop3D
|
sub eax, viewTop3D
|
||||||
cmp eax, viewHeight3D
|
cmp eax, viewHeight3D
|
||||||
jae event_done
|
jae event_done
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
jne event_coarse_y
|
||||||
|
push eax
|
||||||
|
imul eax,480*256
|
||||||
|
xor edx,edx
|
||||||
|
div viewHeight3D
|
||||||
|
mov dtCursorY3D,eax
|
||||||
|
pop eax
|
||||||
|
event_coarse_y:
|
||||||
imul eax, 240
|
imul eax, 240
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
div viewHeight3D
|
div viewHeight3D
|
||||||
|
|
@ -87,6 +114,13 @@ event_mouse_down:
|
||||||
pyr_event_pick:
|
pyr_event_pick:
|
||||||
mov pyrPickClick3D,1
|
mov pyrPickClick3D,1
|
||||||
pyr_event_pick_done:
|
pyr_event_pick_done:
|
||||||
|
cmp uMsg,202h
|
||||||
|
je event_done
|
||||||
|
cmp uMsg,200h
|
||||||
|
jne @F
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
je event_done
|
||||||
|
@@:
|
||||||
mov mouseClick3D, 1
|
mov mouseClick3D, 1
|
||||||
jmp event_done
|
jmp event_done
|
||||||
event_key_down:
|
event_key_down:
|
||||||
|
|
@ -110,6 +144,8 @@ event_fullscreen:
|
||||||
call ToggleFullscreen3D
|
call ToggleFullscreen3D
|
||||||
jmp event_done
|
jmp event_done
|
||||||
event_focus_lost:
|
event_focus_lost:
|
||||||
|
mov dtHolding3D,0
|
||||||
|
mov dtMouseReleased3D,0
|
||||||
call ClearKeys3D
|
call ClearKeys3D
|
||||||
jmp event_done
|
jmp event_done
|
||||||
event_erase:
|
event_erase:
|
||||||
|
|
@ -572,6 +608,8 @@ progress_loaded:
|
||||||
LoadProgress3D ENDP
|
LoadProgress3D ENDP
|
||||||
|
|
||||||
SaveProgress3D PROC uses ebx
|
SaveProgress3D PROC uses ebx
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne progress_saved
|
||||||
IFDEF CASINO_ACTION_TEST
|
IFDEF CASINO_ACTION_TEST
|
||||||
ret
|
ret
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
|
||||||
|
|
@ -537,7 +537,11 @@ pyr_actor:
|
||||||
ret
|
ret
|
||||||
@@:
|
@@:
|
||||||
cmp poolPlayer3D,1
|
cmp poolPlayer3D,1
|
||||||
jne pyr_human
|
je pyr_actor_ai_check
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne pyr_actor_ai_check
|
||||||
|
jmp pyr_human
|
||||||
|
pyr_actor_ai_check:
|
||||||
cmp poolAI3D,0
|
cmp poolAI3D,0
|
||||||
je pyr_human
|
je pyr_human
|
||||||
cmp poolTime3D,1000
|
cmp poolTime3D,1000
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ RenderHallDressing3D PROC uses ebx esi edi
|
||||||
cmp hallLevel3D,0
|
cmp hallLevel3D,0
|
||||||
jne hall_dressing_done
|
jne hall_dressing_done
|
||||||
call RenderTerminalCabinets3D
|
call RenderTerminalCabinets3D
|
||||||
|
call DrawHallDarts3D
|
||||||
lea esi,hallWallArt3D
|
lea esi,hallWallArt3D
|
||||||
mov edi,WORLD_WALL_ART_COUNT
|
mov edi,WORLD_WALL_ART_COUNT
|
||||||
hall_wall_painting:
|
hall_wall_painting:
|
||||||
|
|
|
||||||
203
tools/build_setup.py
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build and package the complete modern Assembler Casino into PokerGameSetup.exe."""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
MARKER = b"<<POKER_GAME_GUI_PAYLOAD_ZIP>>"
|
||||||
|
|
||||||
|
|
||||||
|
def get_sha256(data_or_path):
|
||||||
|
if isinstance(data_or_path, (str, Path)):
|
||||||
|
h = hashlib.sha256()
|
||||||
|
with open(data_or_path, "rb") as f:
|
||||||
|
while chunk := f.read(65536):
|
||||||
|
h.update(chunk)
|
||||||
|
return h.hexdigest().upper()
|
||||||
|
return hashlib.sha256(data_or_path).hexdigest().upper()
|
||||||
|
|
||||||
|
|
||||||
|
def collect_payload_files():
|
||||||
|
entries = []
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
for src, dst in [
|
||||||
|
(ROOT / "dist/Assembler Casino.exe", "Assembler Casino.exe"),
|
||||||
|
(ROOT / "dist/Uninstall Assembler Casino.exe", "Uninstall Assembler Casino.exe"),
|
||||||
|
(ROOT / "bin/poker.exe", "bin/poker.exe"),
|
||||||
|
(ROOT / "poker.exe", "poker.exe"),
|
||||||
|
]:
|
||||||
|
if not src.exists():
|
||||||
|
raise FileNotFoundError(f"Required binary not found: {src}")
|
||||||
|
entries.append((src, dst))
|
||||||
|
|
||||||
|
# Assets (excluding raw sprites used only for asset generation)
|
||||||
|
assets_dir = ROOT / "assets"
|
||||||
|
for r, dirs, files in os.walk(assets_dir):
|
||||||
|
if "sprites" in Path(r).parts:
|
||||||
|
continue
|
||||||
|
for f in sorted(files):
|
||||||
|
fp = Path(r) / f
|
||||||
|
rel = fp.relative_to(ROOT).as_posix()
|
||||||
|
entries.append((fp, rel))
|
||||||
|
|
||||||
|
# Docs
|
||||||
|
docs_dir = ROOT / "docs"
|
||||||
|
for r, dirs, files in os.walk(docs_dir):
|
||||||
|
for f in sorted(files):
|
||||||
|
if f.endswith((".txt", ".md")):
|
||||||
|
fp = Path(r) / f
|
||||||
|
rel = fp.relative_to(ROOT).as_posix()
|
||||||
|
entries.append((fp, rel))
|
||||||
|
|
||||||
|
# Tools
|
||||||
|
tool_files = [
|
||||||
|
"tools/previews/preview_dbd_hook.bat",
|
||||||
|
"tools/previews/preview_hakari.bat",
|
||||||
|
"tools/previews/preview_intro.bat",
|
||||||
|
"tools/previews/preview_casino3d.bat",
|
||||||
|
"tools/tests/achievement_popup.bat",
|
||||||
|
"tools/tests/release_smoke_check.ps1",
|
||||||
|
]
|
||||||
|
for rel in tool_files:
|
||||||
|
fp = ROOT / rel
|
||||||
|
if fp.exists():
|
||||||
|
entries.append((fp, rel))
|
||||||
|
|
||||||
|
# Backwards compatibility paths for tests / older scripts
|
||||||
|
if (ROOT / "tools/previews/preview_dbd_hook.bat").exists():
|
||||||
|
entries.append((ROOT / "tools/previews/preview_dbd_hook.bat", "tools/preview_dbd_hook.bat"))
|
||||||
|
if (ROOT / "tools/tests/release_smoke_check.ps1").exists():
|
||||||
|
entries.append((ROOT / "tools/tests/release_smoke_check.ps1", "tools/release_smoke_check.ps1"))
|
||||||
|
|
||||||
|
# Runtime configuration and state
|
||||||
|
for rel in ["runtime/casino3d-progress.dat", "runtime/display.cfg"]:
|
||||||
|
fp = ROOT / rel
|
||||||
|
if fp.exists():
|
||||||
|
entries.append((fp, rel))
|
||||||
|
|
||||||
|
# AI worker & metadata (without the 2.5 GB model per docs/FORTUNE_AI.md)
|
||||||
|
ai_dir = ROOT / "ai"
|
||||||
|
if ai_dir.exists():
|
||||||
|
for r, dirs, files in os.walk(ai_dir):
|
||||||
|
if "models" in Path(r).parts:
|
||||||
|
continue
|
||||||
|
for f in sorted(files):
|
||||||
|
fp = Path(r) / f
|
||||||
|
rel = fp.relative_to(ROOT).as_posix()
|
||||||
|
entries.append((fp, rel))
|
||||||
|
|
||||||
|
# Root documentation
|
||||||
|
for rel in ["AGENTS.md", "README.md"]:
|
||||||
|
fp = ROOT / rel
|
||||||
|
if fp.exists():
|
||||||
|
entries.append((fp, rel))
|
||||||
|
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def build_payload_zip(zip_path, entries):
|
||||||
|
print(f"Creating payload archive: {zip_path} ({len(entries)} files)...")
|
||||||
|
zip_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=6) as zf:
|
||||||
|
for src, dst in entries:
|
||||||
|
zf.write(src, dst)
|
||||||
|
size_mb = zip_path.stat().st_size / (1024 * 1024)
|
||||||
|
print(f"Payload archive created: {size_mb:.2f} MB")
|
||||||
|
|
||||||
|
|
||||||
|
def compile_setup_base(source_path, base_exe_path):
|
||||||
|
csc = Path(os.environ.get("WINDIR", r"C:\Windows")) / r"Microsoft.NET\Framework\v4.0.30319\csc.exe"
|
||||||
|
if not csc.exists():
|
||||||
|
raise RuntimeError(f"csc.exe not found at {csc}")
|
||||||
|
|
||||||
|
icon = ROOT / "assets/icons/casino.ico"
|
||||||
|
cmd = [
|
||||||
|
str(csc),
|
||||||
|
"/nologo",
|
||||||
|
"/target:winexe",
|
||||||
|
"/platform:x86",
|
||||||
|
"/optimize+",
|
||||||
|
"/reference:System.Windows.Forms.dll",
|
||||||
|
"/reference:System.Drawing.dll",
|
||||||
|
"/reference:System.IO.Compression.dll",
|
||||||
|
"/reference:System.IO.Compression.FileSystem.dll",
|
||||||
|
"/reference:System.Core.dll",
|
||||||
|
f"/win32icon:{icon}",
|
||||||
|
f"/out:{base_exe_path}",
|
||||||
|
str(source_path),
|
||||||
|
]
|
||||||
|
print(f"Compiling installer base: {' '.join(cmd)}")
|
||||||
|
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
if res.returncode != 0:
|
||||||
|
raise RuntimeError(f"Compilation failed:\n{res.stdout}\n{res.stderr}")
|
||||||
|
print(f"Compiled: {base_exe_path} ({base_exe_path.stat().st_size} bytes)")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=== Building Assembler Casino PokerGameSetup ===")
|
||||||
|
|
||||||
|
# 1. Collect files
|
||||||
|
entries = collect_payload_files()
|
||||||
|
payload_zip = ROOT / "build/payload_release_final.zip"
|
||||||
|
build_payload_zip(payload_zip, entries)
|
||||||
|
|
||||||
|
# 2. Hash payload
|
||||||
|
payload_hash = get_sha256(payload_zip)
|
||||||
|
print(f"Payload SHA-256: {payload_hash}")
|
||||||
|
|
||||||
|
# 3. Update PokerGameSetupGui.cs with new payload hash
|
||||||
|
setup_cs = ROOT / "build/PokerGameSetupGui.cs"
|
||||||
|
cs_content = setup_cs.read_text(encoding="utf-8")
|
||||||
|
hash_pattern = r'const string ExpectedPayloadSha256 = "([A-Fa-f0-9]{64}|TO_BE_FILLED_BY_RELEASE_BUILD)";'
|
||||||
|
if not re.search(hash_pattern, cs_content):
|
||||||
|
raise ValueError("Could not find ExpectedPayloadSha256 constant in PokerGameSetupGui.cs")
|
||||||
|
new_cs_content = re.sub(
|
||||||
|
hash_pattern,
|
||||||
|
f'const string ExpectedPayloadSha256 = "{payload_hash}";',
|
||||||
|
cs_content,
|
||||||
|
count=1
|
||||||
|
)
|
||||||
|
setup_cs.write_text(new_cs_content, encoding="utf-8")
|
||||||
|
print("Updated ExpectedPayloadSha256 in PokerGameSetupGui.cs")
|
||||||
|
|
||||||
|
# 4. Compile base setup executable
|
||||||
|
base_exe = ROOT / "build/PokerGameSetup_base.exe"
|
||||||
|
compile_setup_base(setup_cs, base_exe)
|
||||||
|
|
||||||
|
# 5. Assemble final PokerGameSetup.exe
|
||||||
|
setup_exe = ROOT / "PokerGameSetup.exe"
|
||||||
|
print(f"Assembling {setup_exe}...")
|
||||||
|
with open(setup_exe, "wb") as out_f:
|
||||||
|
with open(base_exe, "rb") as in_base:
|
||||||
|
out_f.write(in_base.read())
|
||||||
|
out_f.write(MARKER)
|
||||||
|
with open(payload_zip, "rb") as in_zip:
|
||||||
|
while chunk := in_zip.read(65536):
|
||||||
|
out_f.write(chunk)
|
||||||
|
|
||||||
|
total_mb = setup_exe.stat().st_size / (1024 * 1024)
|
||||||
|
print(f"=== Successfully built {setup_exe} ({total_mb:.2f} MB) ===")
|
||||||
|
|
||||||
|
# 6. Verify built setup
|
||||||
|
with open(setup_exe, "rb") as f:
|
||||||
|
head = f.read(4 * 1024 * 1024)
|
||||||
|
idx = head.find(MARKER)
|
||||||
|
assert idx != -1, "Marker not found in generated setup!"
|
||||||
|
f.seek(idx + len(MARKER))
|
||||||
|
h = hashlib.sha256()
|
||||||
|
while chunk := f.read(65536):
|
||||||
|
h.update(chunk)
|
||||||
|
actual_hash = h.hexdigest().upper()
|
||||||
|
assert actual_hash == payload_hash, f"Hash mismatch: {actual_hash} != {payload_hash}"
|
||||||
|
print(f"[VERIFIED] Marker and SHA-256 match perfectly ({actual_hash})")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
21
tools/generators/darts_cp1251.patch
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
diff --git a/casino3d.inc b/casino3d.inc
|
||||||
|
--- a/casino3d.inc
|
||||||
|
+++ b/casino3d.inc
|
||||||
|
@@ -174,1 +174,2 @@
|
||||||
|
include src_graphics\observer_data.inc
|
||||||
|
+include src_graphics\darts_data.inc
|
||||||
|
@@ -5198,1 +5199,2 @@
|
||||||
|
include src_graphics\observer.inc
|
||||||
|
+include src_graphics\darts.inc
|
||||||
|
@@ -5357,1 +5359,9 @@
|
||||||
|
check_slots_mode:
|
||||||
|
+ cmp engineMode,MODE_DARTS
|
||||||
|
+ jne check_darts_done
|
||||||
|
+ call HandleDarts3D
|
||||||
|
+ call RenderDarts3D
|
||||||
|
+ jmp present_frame
|
||||||
|
+check_darts_done:
|
||||||
|
cmp engineMode,MODE_FORTUNE
|
||||||
|
@@ -5642,1 +5652,2 @@
|
||||||
|
call FreeRussianAssets3D
|
||||||
|
+ call FreeDarts3D
|
||||||
15
tools/generators/darts_hall.patch
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
diff --git a/src_graphics/hall_scene.inc b/src_graphics/hall_scene.inc
|
||||||
|
--- a/src_graphics/hall_scene.inc
|
||||||
|
+++ b/src_graphics/hall_scene.inc
|
||||||
|
@@ -783,1 +783,2 @@
|
||||||
|
hall_check_other:
|
||||||
|
+ invoke HallTarget3D,FP_1*305/10,28*FP_1,INTERACT_DARTS,OFFSET dtPrompt
|
||||||
|
@@ -799,1 +800,9 @@
|
||||||
|
TriggerHallInteraction3D PROC
|
||||||
|
+ cmp interactTargetId,INTERACT_DARTS
|
||||||
|
+ jne hall_not_darts
|
||||||
|
+ call BeginDarts3D
|
||||||
|
+ mov eax,1
|
||||||
|
+ ret
|
||||||
|
+hall_not_darts:
|
||||||
|
call TryFortuneInteraction3D
|
||||||
29
tools/generators/observer_cp1251.patch
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
diff --git a/casino3d.inc b/casino3d.inc
|
||||||
|
--- a/casino3d.inc
|
||||||
|
+++ b/casino3d.inc
|
||||||
|
@@ -173,1 +173,2 @@
|
||||||
|
include src_graphics\charms_data.inc
|
||||||
|
+include src_graphics\observer_data.inc
|
||||||
|
@@ -4856,5 +4857,5 @@
|
||||||
|
check_target_observer:
|
||||||
|
cmp eax, INTERACT_OBSERVER
|
||||||
|
jne target_unported
|
||||||
|
- call BeginUnavailable3D
|
||||||
|
+ call BeginObserver3D
|
||||||
|
ret
|
||||||
|
@@ -5196,1 +5197,2 @@
|
||||||
|
include src_graphics\charms.inc
|
||||||
|
+include src_graphics\observer.inc
|
||||||
|
@@ -5245,2 +5247,11 @@
|
||||||
|
call ToggleFullscreen3D
|
||||||
|
@@:
|
||||||
|
+ cmp obsActive3D,0
|
||||||
|
+ jne engine_observer_frame
|
||||||
|
+ cmp engineMode,MODE_OBSERVER
|
||||||
|
+ jne engine_observer_skip
|
||||||
|
+engine_observer_frame:
|
||||||
|
+ call UpdateMouseLockState
|
||||||
|
+ call ObserverFrame3D
|
||||||
|
+ jmp present_frame
|
||||||
|
+engine_observer_skip:
|
||||||
|
invoke Pressed3D, 1Bh
|
||||||
103
tools/generators/pack_darts.py
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
"""Exact clock-board geometry plus fixed-grid full-arm animation packing."""
|
||||||
|
from pathlib import Path
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import struct
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
ART = ROOT / "assets/sprites/darts"
|
||||||
|
OUT = ROOT / "assets/animations/darts"
|
||||||
|
SECTORS = [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5]
|
||||||
|
|
||||||
|
|
||||||
|
def pack(name, frames):
|
||||||
|
width, height = frames[0].size
|
||||||
|
payload = b"".join(frame.tobytes("raw", "BGRA") for frame in frames)
|
||||||
|
(OUT / name).write_bytes(struct.pack("<4s4I", b"ANM1", width, height, len(frames), len(payload)) + payload)
|
||||||
|
|
||||||
|
|
||||||
|
def board():
|
||||||
|
rng = random.Random(301)
|
||||||
|
image = Image.new("RGBA", (512, 512))
|
||||||
|
pixels = image.load()
|
||||||
|
for y in range(512):
|
||||||
|
for x in range(512):
|
||||||
|
dx, dy = x-256, 256-y
|
||||||
|
radius = math.hypot(dx, dy)
|
||||||
|
angle = math.atan2(dx, dy)
|
||||||
|
sector = int(((angle + math.pi/20) % math.tau) / (math.tau/20))
|
||||||
|
red = sector % 2 == 0
|
||||||
|
color = (30, 36, 39)
|
||||||
|
if radius < 170:
|
||||||
|
color = (35, 38, 37) if red else (214, 206, 178)
|
||||||
|
if 99 <= radius <= 107 or 162 <= radius:
|
||||||
|
color = (174, 37, 47) if red else (28, 112, 87)
|
||||||
|
if radius <= 15.9:
|
||||||
|
color = (28, 112, 87)
|
||||||
|
if radius <= 6.35:
|
||||||
|
color = (187, 37, 47)
|
||||||
|
elif radius < 210:
|
||||||
|
color = (20, 24, 25)
|
||||||
|
elif radius < 240:
|
||||||
|
color = (72, 29, 35)
|
||||||
|
elif radius < 248:
|
||||||
|
color = (31, 37, 41)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
grain = rng.randrange(-11, 12) if radius < 170 else rng.randrange(-3, 4)
|
||||||
|
pixels[x, y] = tuple(max(0, min(255, c+grain)) for c in color) + (255,)
|
||||||
|
draw = ImageDraw.Draw(image)
|
||||||
|
wire = (171, 178, 173, 255)
|
||||||
|
for r in (6.35, 15.9, 99, 107, 162, 170):
|
||||||
|
draw.ellipse((256-r, 256-r, 256+r, 256+r), outline=wire, width=1)
|
||||||
|
for index in range(20):
|
||||||
|
theta = (index*18-9)*math.pi/180
|
||||||
|
draw.line([(256+math.sin(theta)*16, 256-math.cos(theta)*16),
|
||||||
|
(256+math.sin(theta)*170, 256-math.cos(theta)*170)], fill=wire)
|
||||||
|
font = ImageFont.truetype("C:/Windows/Fonts/arialbd.ttf", 23)
|
||||||
|
for index, value in enumerate(SECTORS):
|
||||||
|
theta = index*math.tau/20
|
||||||
|
draw.text((256+math.sin(theta)*190, 256-math.cos(theta)*190), str(value),
|
||||||
|
font=font, fill=(227, 230, 220), anchor="mm", stroke_width=1)
|
||||||
|
draw.ellipse((12, 12, 500, 500), outline=(104, 114, 120), width=3)
|
||||||
|
image.save(ART / "board-v1.png")
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ART.mkdir(parents=True, exist_ok=True)
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
pack("board-v1.bin", [board()])
|
||||||
|
wall = Image.open(ART / "lounge-wall-v1.png").convert("RGBA")
|
||||||
|
pack("lounge-wall-v1.bin", [wall.resize((512,512), Image.Resampling.LANCZOS)])
|
||||||
|
anchors = []
|
||||||
|
for name in ("arm-throw-v3", "dart-views-v1"):
|
||||||
|
source = ART / (name + ".png")
|
||||||
|
sheet = Image.open(source).convert("RGBA")
|
||||||
|
assert sheet.width == sheet.height
|
||||||
|
cell = sheet.width / 4
|
||||||
|
frames = [sheet.crop(tuple(round(v*cell) for v in (x, y, x+1, y+1)))
|
||||||
|
.resize((256, 256), Image.Resampling.LANCZOS) for y in range(4) for x in range(4)]
|
||||||
|
assert all(f.getchannel("A").getextrema()[0] == 0 for f in frames)
|
||||||
|
assert len({f.tobytes() for f in frames}) == 16
|
||||||
|
pack(name + ".bin", frames)
|
||||||
|
if name == "dart-views-v1":
|
||||||
|
for frame in frames:
|
||||||
|
metal = [(x,y) for y in range(256) for x in range(256)
|
||||||
|
if (lambda p: p[3] > 220 and min(p[:3]) > 50
|
||||||
|
and max(p[:3])-min(p[:3]) < 60)(frame.getpixel((x,y)))]
|
||||||
|
tip_x = min(x for x,y in metal)
|
||||||
|
ys = sorted(y for x,y in metal if x <= tip_x+2)
|
||||||
|
anchors.append((tip_x, ys[len(ys)//2]))
|
||||||
|
(ROOT / "src_graphics/darts_art.inc").write_text(
|
||||||
|
"; Generated per-view needle anchors in the 256px source canvas.\n"
|
||||||
|
+ "dtDartTipX3D dd " + ",".join(str(p[0]) for p in anchors) + "\n"
|
||||||
|
+ "dtDartTipY3D dd " + ",".join(str(p[1]) for p in anchors) + "\n", encoding="ascii")
|
||||||
|
print("Packed exact 20-sector board; whole-arm animation uses one fixed canvas and scale.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
63
tools/generators/pack_fortune_session.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
"""Offline sprite-sheet compiler; runtime animation stays in MASM."""
|
||||||
|
from pathlib import Path
|
||||||
|
import json
|
||||||
|
import struct
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
ART = ROOT / "assets/sprites/fortune"
|
||||||
|
OUT = ROOT / "assets/animations/fortune"
|
||||||
|
|
||||||
|
|
||||||
|
def grid(name, columns, rows, size):
|
||||||
|
source = Image.open(ART / name).convert("RGBA")
|
||||||
|
return [source.crop((round(x*source.width/columns), round(y*source.height/rows),
|
||||||
|
round((x+1)*source.width/columns), round((y+1)*source.height/rows)))
|
||||||
|
.resize(size, Image.Resampling.LANCZOS)
|
||||||
|
for y in range(rows) for x in range(columns)]
|
||||||
|
|
||||||
|
|
||||||
|
def tween(frames, loop=False):
|
||||||
|
# One shared canvas/scale, never fit moving hands independently per frame.
|
||||||
|
output = []
|
||||||
|
for i, frame in enumerate(frames):
|
||||||
|
following = frames[(i+1) % len(frames)] if loop or i+1 < len(frames) else frame
|
||||||
|
output.extend(Image.blend(frame, following, step/4) for step in range(4))
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def pack(name, frames):
|
||||||
|
width, height = frames[0].size
|
||||||
|
assert len(frames) <= 64
|
||||||
|
assert all(frame.size == (width, height) for frame in frames)
|
||||||
|
payload = b"".join(frame.tobytes("raw", "BGRA") for frame in frames)
|
||||||
|
(OUT / (name + ".bin")).write_bytes(
|
||||||
|
struct.pack("<4s4I", b"ANM1", width, height, len(frames), len(payload)) + payload)
|
||||||
|
return {"file": name + ".bin", "width": width, "height": height, "frames": len(frames)}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
body = grid("teller-actions-v1.png", 8, 5, (256, 256))
|
||||||
|
cards = grid("tarot-symbols-v1.png", 6, 4, (96, 128))
|
||||||
|
# Orientations are real upside-down artwork, not merely a different label.
|
||||||
|
faces = cards[:22] + [c.transpose(Image.Transpose.ROTATE_180) for c in cards[:22]] + [cards[22]]
|
||||||
|
room = Image.open(ART / "seated-room-v1.png").convert("RGBA").resize((640, 480), Image.Resampling.LANCZOS)
|
||||||
|
manifest = [pack("room-v1", [room]),
|
||||||
|
pack("shuffle-v1", tween(body[:16], loop=True)),
|
||||||
|
pack("deal-v1", tween(body[16:24])),
|
||||||
|
pack("gesture-v1", tween(body[24:32], loop=True)),
|
||||||
|
pack("orb-hands-v1", tween(body[32:40], loop=True)),
|
||||||
|
pack("orb-mist-v1", grid("crystal-mist-v1.png", 4, 4, (192, 192))),
|
||||||
|
pack("cards-v1", faces)]
|
||||||
|
(ART / "packed-v1.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="ascii")
|
||||||
|
preview = room.copy()
|
||||||
|
preview.alpha_composite(body[0].resize((280, 250)), (134, 32))
|
||||||
|
for index in range(3):
|
||||||
|
preview.alpha_composite(cards[22].resize((72, 96)), (198+index*100, 302))
|
||||||
|
preview.save(ROOT / "build/hall-expansion/fortune-session-art.png")
|
||||||
|
print("Packed 160 hand poses, 16 mist frames, 44 oriented faces, back and seated room.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -33,6 +33,8 @@ InitPaths3D PROTO
|
||||||
ExitProcess PROTO :DWORD
|
ExitProcess PROTO :DWORD
|
||||||
WriteActionSnapshot3D PROTO :DWORD
|
WriteActionSnapshot3D PROTO :DWORD
|
||||||
include src_graphics/billiards_data.inc
|
include src_graphics/billiards_data.inc
|
||||||
|
.data
|
||||||
|
obsActive3D dd 0
|
||||||
.code
|
.code
|
||||||
include src_graphics/billiards.inc
|
include src_graphics/billiards.inc
|
||||||
include tools/tests/pyramid_test.inc
|
include tools/tests/pyramid_test.inc
|
||||||
|
|
|
||||||
175
tools/tests/check_darts.py
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
"""Fresh MASM dart scoring, mouse aiming, full-arm animation and 3D follow-camera proofs."""
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
from PIL import Image
|
||||||
|
from check_card_exit_build import Coff
|
||||||
|
from check_terminals import signature
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = ROOT / "build/darts"
|
||||||
|
|
||||||
|
|
||||||
|
def read(path):
|
||||||
|
raw = (ROOT / path).read_bytes()
|
||||||
|
try:
|
||||||
|
return raw.decode("utf8").replace("\r\n", "\n")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return raw.decode("cp1251").replace("\r\n", "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def proc(text, name):
|
||||||
|
return re.search(rf"^{name} PROC\b.*?^{name} ENDP", text, re.M | re.S).group()
|
||||||
|
|
||||||
|
|
||||||
|
def expand(path):
|
||||||
|
return re.sub(r"^include ([^\n]+)$", lambda m: expand(m[1].strip().replace("\\", "/")),
|
||||||
|
read(path), flags=re.M)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare():
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
code = expand("src_graphics/darts.inc")
|
||||||
|
code += "\n" + proc(read("src_graphics/platform_code.inc"), "WindowEvents3D")
|
||||||
|
for name in ("ResolveCitySurface3D", "DrawCityVertical3D"):
|
||||||
|
code += "\n" + proc(read("src_graphics/city_bins.inc"), name)
|
||||||
|
code += "\n" + proc(read("tools/tests/casino_actions_test.inc"), "WriteActionSnapshot3D")
|
||||||
|
code += "\nPlayCasinoSound3D PROC arg0:DWORD,arg1:DWORD,arg2:DWORD\n ret\nPlayCasinoSound3D ENDP\n"
|
||||||
|
code += "\n" + read("tools/tests/darts_test.inc")
|
||||||
|
code += "\n" + read("tools/tests/darts_ui.inc")
|
||||||
|
data = expand("src_graphics/darts_data.inc")
|
||||||
|
stages = [(0, t) for t in range(0, 320, 40)] + [(1, t) for t in range(0, 200, 40)]
|
||||||
|
stages += [(2, t) for t in range(0, 1200, 40)]
|
||||||
|
stages += [(3, t) for t in range(0, 1300, 80)] + [(4, t) for t in range(0, 751, 50)]
|
||||||
|
code += "\nDartsTestFrames PROC\n call ResetDarts3D\n mov dtAimX3D,0\n mov dtAimY3D,103\n mov dtHitX3D,0\n mov dtHitY3D,103\n"
|
||||||
|
for index, (state, time) in enumerate(stages):
|
||||||
|
data += f'\n.data\ndtFrame{index} db "build\\darts\\frame-{index:03}.bmp",0\n'
|
||||||
|
if state == 3 and stages[index-1][0] != 3:
|
||||||
|
code += " mov dtState3D,DT_FLIGHT\n call SettleDarts3D\n"
|
||||||
|
code += f" mov dtState3D,{state}\n mov dtTimer3D,{time}\n mov dtClock3D,{time}\n"
|
||||||
|
if state == 0:
|
||||||
|
code += f" mov dtHolding3D,1\n mov dtHoldTime3D,{time}\n"
|
||||||
|
code += f" call RenderDarts3D\n invoke WriteActionSnapshot3D,OFFSET dtFrame{index}\n"
|
||||||
|
data += '\n.data\ndtScoreFrame db "build\\darts\\scoreboard.bmp",0\n'
|
||||||
|
code += " mov dtScoreOpen3D,1\n call RenderDarts3D\n invoke WriteActionSnapshot3D,OFFSET dtScoreFrame\n"
|
||||||
|
code += " call ResetDarts3D\n mov dtHolding3D,1\n mov dtCursorX3D,320*256\n mov dtCursorY3D,214*256-103*DT_FOCAL*256/DT_WALL\n"
|
||||||
|
for index in range(80):
|
||||||
|
data += f'\n.data\ndtSwayFrame{index} db "build\\darts\\sway-{index:03}.bmp",0\n'
|
||||||
|
code += f" mov dtClock3D,{index*40}\n mov dtHoldTime3D,{index*40}\n call DartsAim3D\n call RenderDarts3D\n invoke WriteActionSnapshot3D,OFFSET dtSwayFrame{index}\n"
|
||||||
|
code += " ret\nDartsTestFrames ENDP\n"
|
||||||
|
code = code.replace(":SDWORD", ":DWORD")
|
||||||
|
data += "\n.data\nactionBmpHeader db 42h,4Dh\n dd 1228854\n dw 0,0\n dd 54,40,640,-480\n dw 1,32\n dd 0,1228800,0,0,0,0\n"
|
||||||
|
own_funcs = set(re.findall(r"^(\w+) PROC", code, re.M))
|
||||||
|
own_data = set(re.findall(r"^(\w+)\s+(?:db|dw|dd|REAL4|REAL8|AnimPack3D|LABEL)\b", data + "\n" + code, re.M))
|
||||||
|
source = "\n".join(read(str(p.relative_to(ROOT))) for p in
|
||||||
|
[ROOT / "poker.asm", ROOT / "casino3d.inc", ROOT / "casino3d_data.inc",
|
||||||
|
*sorted(p for p in (ROOT / "src_graphics").glob("*.inc") if p.name != "renderer.inc")])
|
||||||
|
structures = [re.search(rf"^{name} STRUCT\b.*?^{name} ENDS", source, re.M | re.S).group()
|
||||||
|
for name in ("AnimPack3D", "BJBot3D")]
|
||||||
|
types = {name: kind for name, kind in re.findall(r"^(\w+)\s+(AnimPack3D|BJBot3D)\b", source, re.M)}
|
||||||
|
types.update({name: {"db": "BYTE", "dw": "WORD", "dd": "DWORD"}[kind.lower()]
|
||||||
|
for name, kind in re.findall(r"^(\w+)\s+(db|dw|dd)\b", source, re.M | re.I)})
|
||||||
|
types.update({name: kind.upper() for name, kind in
|
||||||
|
re.findall(r"^(\w+)\s+(REAL4|REAL8)\b", source, re.M | re.I)})
|
||||||
|
coff = Coff(ROOT / "build/graphics/poker.obj")
|
||||||
|
helper = bytearray(coff.data)
|
||||||
|
symbol_at = struct.unpack_from("<I", helper, 8)[0]
|
||||||
|
externs, protos = [], {}
|
||||||
|
for index, name in coff.symbols.items():
|
||||||
|
pos = symbol_at + index * 18
|
||||||
|
_, section, kind, storage, _ = struct.unpack_from("<IhHBB", helper, pos + 8)
|
||||||
|
if section > 0 and re.fullmatch(r"[A-Za-z_]\w*", name) and storage in (2, 3):
|
||||||
|
secname = helper[20+(section-1)*40:28+(section-1)*40].rstrip(b"\0")
|
||||||
|
if secname in (b".data", b".bss", b".const"):
|
||||||
|
helper[pos+16] = 3 if name in own_data else 2
|
||||||
|
if name not in own_data:
|
||||||
|
externs.append(f"EXTERN {name}:{types.get(name, 'DWORD')}")
|
||||||
|
match = re.fullmatch(r"_(\w+)@(\d+)", name)
|
||||||
|
if match and kind == 0x20 and section > 0:
|
||||||
|
helper[pos+16] = 3 if match[1] in own_funcs else 2
|
||||||
|
if match[1] not in own_funcs:
|
||||||
|
protos[match[1]] = int(match[2]) // 4
|
||||||
|
for name, params in re.findall(r"^(\w+)\s+PROTO([^\n]*)", source, re.M):
|
||||||
|
protos.setdefault(name, params.count(":DWORD"))
|
||||||
|
for name in own_funcs:
|
||||||
|
protos[name] = len(re.findall(r":S?DWORD", proc(code, name).splitlines()[0]))
|
||||||
|
constants = dict(re.findall(r"^(\w+)\s+equ\s+([^;\n]+)", source, re.M))
|
||||||
|
used = set(re.findall(r"^(\w+) equ", data, re.M))
|
||||||
|
ordered = []
|
||||||
|
def constant(name):
|
||||||
|
if name not in constants or name in used:
|
||||||
|
return
|
||||||
|
used.add(name)
|
||||||
|
for dep in re.findall(r"\b[A-Za-z_]\w*", constants[name]):
|
||||||
|
constant(dep)
|
||||||
|
ordered.append(f"{name} equ {constants[name]}")
|
||||||
|
for name in re.findall(r"\b[A-Za-z_]\w*", code + data):
|
||||||
|
constant(name)
|
||||||
|
header = ".386\n.model flat\noption casemap:none\n" + "\n".join(structures + ordered + externs)
|
||||||
|
header += "\noption language:stdcall\n" + "\n".join(
|
||||||
|
name + " PROTO" + (" " + ",".join([":DWORD"]*count) if count else "") for name, count in protos.items())
|
||||||
|
data = re.sub(r"^\w+ PROTO[^\n]*\n", "", data, flags=re.M)
|
||||||
|
(OUT / "helpers.obj").write_bytes(helper)
|
||||||
|
(OUT / "module.asm").write_text(header + "\n" + data + "\n.code\n" + code + "\nend DartsTestStart\n", encoding="cp1251")
|
||||||
|
return {name for name in own_funcs if not name.startswith(("DartsTest", "DartsUi"))} - {
|
||||||
|
"PlayCasinoSound3D", "WriteActionSnapshot3D"}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--parity", action="store_true")
|
||||||
|
parser.add_argument("--interactive", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
functions = prepare()
|
||||||
|
if args.parity:
|
||||||
|
tested, shipping = Coff(OUT / "module.obj"), Coff(ROOT / "build/graphics/poker.obj")
|
||||||
|
for name in functions:
|
||||||
|
symbol = next(key for key in tested.functions if key.startswith("_" + name + "@"))
|
||||||
|
assert signature(tested, symbol, tail_branches=True) == signature(shipping, symbol, tail_branches=True), name
|
||||||
|
print("PASS: dart scene, scoring, input and camera match the shipping object")
|
||||||
|
return
|
||||||
|
masm = Path("F:/MASM32/masm32")
|
||||||
|
subprocess.run([str(masm / "bin/ml.exe"), "/c", "/coff", "/Cp", "/nologo", "/I.",
|
||||||
|
"/Fobuild/darts/module.obj", "build/darts/module.asm"], cwd=ROOT, check=True)
|
||||||
|
sdk = sorted(Path("C:/Program Files (x86)/Windows Kits/10/Lib").glob("*/um/x86"))[-1]
|
||||||
|
target = "ui" if args.interactive else "module"
|
||||||
|
entry = "DartsUiStart" if args.interactive else "DartsTestStart"
|
||||||
|
subprocess.run([str(masm / "bin/link.exe"), "/nologo", "/SUBSYSTEM:WINDOWS", f"/ENTRY:{entry}@0",
|
||||||
|
f"/LIBPATH:{sdk}", f"/LIBPATH:{masm/'lib'}", f"/OUT:build/darts/{target}.exe",
|
||||||
|
"build/darts/module.obj", "build/darts/helpers.obj", "kernel32.lib", "user32.lib",
|
||||||
|
"gdi32.lib", "winmm.lib", "ws2_32.lib"], cwd=ROOT, check=True)
|
||||||
|
def profile():
|
||||||
|
return {str(p): hashlib.sha256(p.read_bytes()).digest() for p in (ROOT / "runtime").rglob("*")
|
||||||
|
if p.is_file()}
|
||||||
|
before = profile()
|
||||||
|
run = subprocess.run([str(OUT / (target + ".exe"))], cwd=ROOT, timeout=900 if args.interactive else 180)
|
||||||
|
assert run.returncode == 0, f"Native darts assertion: {run.returncode}"
|
||||||
|
assert profile() == before, "Darts changed persistent profile files"
|
||||||
|
if args.interactive:
|
||||||
|
print("PASS: interactive native scene closed without changing the profile")
|
||||||
|
return
|
||||||
|
frames = [Image.open(p).convert("RGB") for p in sorted(OUT.glob("frame-*.bmp"))]
|
||||||
|
assert len(frames) >= 60 and len({f.tobytes() for f in frames}) >= 40
|
||||||
|
assert all(len(f.getcolors(640*480)) > 80 for f in frames)
|
||||||
|
frames[0].save(OUT / "throw.gif", save_all=True, append_images=frames[1:], duration=40, loop=0)
|
||||||
|
sheet = Image.new("RGB", (640*3, 480*2))
|
||||||
|
for slot, index in enumerate((0, 10, 22, 36, 48, len(frames)-1)):
|
||||||
|
sheet.paste(frames[index], ((slot % 3)*640, (slot // 3)*480))
|
||||||
|
sheet.save(OUT / "contact.png")
|
||||||
|
sway = [Image.open(p).convert("RGB") for p in sorted(OUT.glob("sway-*.bmp"))]
|
||||||
|
assert len(sway) == 80 and len({f.tobytes() for f in sway}) > 24
|
||||||
|
sway[0].save(OUT / "sway.gif", save_all=True, append_images=sway[1:], duration=40, loop=0)
|
||||||
|
triples, = struct.unpack("<I", (OUT / "aim-metrics.bin").read_bytes())
|
||||||
|
print(f"PASS: stationary centre-of-T20 aim scored triples in {triples}/100 native samples")
|
||||||
|
print("PASS: 67 scoring vectors, 20 complete bot matches, bust/turn isolation, fine mouse/release, sway/fatigue, board footprint, Tab, orbit camera and native moving frames")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -24,6 +24,11 @@ def proc(source, name):
|
||||||
return re.search(rf"^{name} PROC\b.*?^{name} ENDP",source,re.M|re.S).group()
|
return re.search(rf"^{name} PROC\b.*?^{name} ENDP",source,re.M|re.S).group()
|
||||||
|
|
||||||
|
|
||||||
|
def expand(path):
|
||||||
|
return re.sub(r"^include ([^\n]+)$", lambda m: expand(m[1].strip().replace("\\", "/")),
|
||||||
|
read(path), flags=re.M)
|
||||||
|
|
||||||
|
|
||||||
def prepare():
|
def prepare():
|
||||||
OUT.mkdir(exist_ok=True)
|
OUT.mkdir(exist_ok=True)
|
||||||
code = read("src_graphics/hall_expansion.inc") + "\n" + read("src_graphics/cabaret.inc")
|
code = read("src_graphics/hall_expansion.inc") + "\n" + read("src_graphics/cabaret.inc")
|
||||||
|
|
@ -32,6 +37,10 @@ def prepare():
|
||||||
code += "\n" + read("src_graphics/fortune_room.inc")
|
code += "\n" + read("src_graphics/fortune_room.inc")
|
||||||
code += "\n" + read("src_graphics/fortune_dialog.inc")
|
code += "\n" + read("src_graphics/fortune_dialog.inc")
|
||||||
code += "\n" + proc(read("src_graphics/unavailable.inc"),"BeginUnavailable3D")
|
code += "\n" + proc(read("src_graphics/unavailable.inc"),"BeginUnavailable3D")
|
||||||
|
code += "\n" + read("src_graphics/observer.inc")
|
||||||
|
code += "\n" + expand("src_graphics/darts.inc").replace(":SDWORD", ":DWORD")
|
||||||
|
code += "\n" + proc(read("src_graphics/native_poker.inc"),"PokerBotAct3D")
|
||||||
|
code += "\n" + proc(read("src_graphics/native_durak.inc"),"DurakBotTurn3D")
|
||||||
code += "\n" + proc(read("src_graphics/world_dressing.inc"),"RenderHallDressing3D")
|
code += "\n" + proc(read("src_graphics/world_dressing.inc"),"RenderHallDressing3D")
|
||||||
for path, names in (
|
for path, names in (
|
||||||
("src_graphics/hall_scene.inc",["RenderCeilingAndFloor","RenderSprites","InitHall3D",
|
("src_graphics/hall_scene.inc",["RenderCeilingAndFloor","RenderSprites","InitHall3D",
|
||||||
|
|
@ -53,8 +62,13 @@ def prepare():
|
||||||
npc = npc[npc.index("npcGuestArt3D "):npc.index("npcLifeClock3D ")]
|
npc = npc[npc.index("npcGuestArt3D "):npc.index("npcLifeClock3D ")]
|
||||||
data = "\n".join(read(path) for path in ("src_graphics/hall_expansion_data.inc",
|
data = "\n".join(read(path) for path in ("src_graphics/hall_expansion_data.inc",
|
||||||
"src_graphics/cabaret_data.inc","src_graphics/hall_layout.inc",
|
"src_graphics/cabaret_data.inc","src_graphics/hall_layout.inc",
|
||||||
"src_graphics/fortune_room_data.inc","src_graphics/fortune_dialog_data.inc")) + "\n.data\n" + npc
|
"src_graphics/fortune_room_data.inc","src_graphics/fortune_dialog_data.inc",
|
||||||
own_data = set(re.findall(r"^(\w+) (?:dd|db|AnimPack3D|CityProp3D)\b",data,re.M))
|
"src_graphics/observer_data.inc")) + "\n.data\n" + npc
|
||||||
|
darts = read("src_graphics/darts_data.inc").replace(
|
||||||
|
"include src_graphics\\darts_art.inc", read("src_graphics/darts_art.inc"))
|
||||||
|
data += "\n" + re.sub(r"^\w+ PROTO[^\n]*\n", "", darts, flags=re.M)
|
||||||
|
own_data = set(re.findall(r"^(\w+) (?:dd|db|dw|REAL4|REAL8|AnimPack3D|CityProp3D)\b",data,re.M))
|
||||||
|
own_data.update(re.findall(r"^(\w+) LABEL\b",data,re.M))
|
||||||
coff = Coff(ROOT / "build/graphics/poker.obj")
|
coff = Coff(ROOT / "build/graphics/poker.obj")
|
||||||
helper = bytearray(coff.data)
|
helper = bytearray(coff.data)
|
||||||
at = struct.unpack_from("<I",helper,8)[0]
|
at = struct.unpack_from("<I",helper,8)[0]
|
||||||
|
|
@ -80,6 +94,8 @@ def prepare():
|
||||||
types[name] = "CitySpriteCrop3D"
|
types[name] = "CitySpriteCrop3D"
|
||||||
for name,kind in re.findall(r"^(\w+)\s+(db|dw|dd)\b",all_source,re.M|re.I):
|
for name,kind in re.findall(r"^(\w+)\s+(db|dw|dd)\b",all_source,re.M|re.I):
|
||||||
types.setdefault(name,{"db":"BYTE","dw":"WORD","dd":"DWORD"}[kind.lower()])
|
types.setdefault(name,{"db":"BYTE","dw":"WORD","dd":"DWORD"}[kind.lower()])
|
||||||
|
for name,kind in re.findall(r"^(\w+)\s+(REAL4|REAL8)\b",all_source,re.M|re.I):
|
||||||
|
types[name] = kind.upper()
|
||||||
for index,name in coff.symbols.items():
|
for index,name in coff.symbols.items():
|
||||||
pos = at+index*18
|
pos = at+index*18
|
||||||
_,sec,kind,storage,_ = struct.unpack_from("<IhHBB",helper,pos+8)
|
_,sec,kind,storage,_ = struct.unpack_from("<IhHBB",helper,pos+8)
|
||||||
|
|
@ -135,7 +151,6 @@ def main():
|
||||||
parser.add_argument("--prove-seam-regression",action="store_true")
|
parser.add_argument("--prove-seam-regression",action="store_true")
|
||||||
parser.add_argument("--prove-distance-regression",action="store_true")
|
parser.add_argument("--prove-distance-regression",action="store_true")
|
||||||
parser.add_argument("--prove-bar-camera-regression",action="store_true")
|
parser.add_argument("--prove-bar-camera-regression",action="store_true")
|
||||||
parser.add_argument("--with-fortune-ai",action="store_true")
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.parity:
|
if args.parity:
|
||||||
native,shipping = Coff(OUT/"module.obj"),Coff(ROOT/"build/graphics/poker.obj")
|
native,shipping = Coff(OUT/"module.obj"),Coff(ROOT/"build/graphics/poker.obj")
|
||||||
|
|
@ -151,10 +166,6 @@ def main():
|
||||||
assert "DrawCityObject3D" not in room, "tarot furniture must not face the camera"
|
assert "DrawCityObject3D" not in room, "tarot furniture must not face the camera"
|
||||||
assert room.count("DrawFortuneFixedProp3D") == 24
|
assert room.count("DrawFortuneFixedProp3D") == 24
|
||||||
stem = "module"
|
stem = "module"
|
||||||
if args.with_fortune_ai:
|
|
||||||
stem = "module-live-ai"
|
|
||||||
source = (OUT/"module.asm").read_text(encoding="cp1251")
|
|
||||||
(OUT/(stem+".asm")).write_text("CASINO_FORTUNE_AI_LIVE equ 1\n" + source,encoding="cp1251")
|
|
||||||
if args.prove_bar_camera_regression:
|
if args.prove_bar_camera_regression:
|
||||||
stem = "module-camera-regression"
|
stem = "module-camera-regression"
|
||||||
source = (OUT/"module.asm").read_text(encoding="cp1251")
|
source = (OUT/"module.asm").read_text(encoding="cp1251")
|
||||||
|
|
@ -224,6 +235,31 @@ def main():
|
||||||
assert blue > 45000, (name, "chamber must use its own blue palette", blue)
|
assert blue > 45000, (name, "chamber must use its own blue palette", blue)
|
||||||
modal = Image.open(OUT/"fortune-unavailable.bmp").convert("RGB").crop((20,65,620,100))
|
modal = Image.open(OUT/"fortune-unavailable.bmp").convert("RGB").crop((20,65,620,100))
|
||||||
assert len(modal.getcolors(600*35)) >= 2, "native fortune dialogue status must be drawn"
|
assert len(modal.getcolors(600*35)) >= 2, "native fortune dialogue status must be drawn"
|
||||||
|
# These are frames rendered by the actual x86 procedures, not a Python scene simulation.
|
||||||
|
motion = [Image.open(OUT/f"fortune-session-motion-{i:02}.bmp").convert("RGB") for i in range(64)]
|
||||||
|
assert len({im.crop((134,32,414,282)).tobytes() for im in motion}) >= 48
|
||||||
|
motion[0].save(OUT/"fortune-session-shuffle.gif",save_all=True,
|
||||||
|
append_images=motion[1:],duration=25,loop=0)
|
||||||
|
stages = ("deal-one","deal-two","deal-three","flip-one","explain-one",
|
||||||
|
"flip-two","explain-two","flip-three","explain-three","summary")
|
||||||
|
frames = [Image.open(OUT/f"fortune-session-{s}.bmp").convert("RGB") for s in stages]
|
||||||
|
assert len({im.crop((190,285,475,398)).tobytes() for im in frames}) >= 7
|
||||||
|
question = frames[0].crop((18,400,620,444)).tobytes()
|
||||||
|
assert all(im.crop((18,400,620,444)).tobytes() == question for im in frames)
|
||||||
|
for name in ("room","shuffle","deal","gesture","orb-hands","orb-mist","cards"):
|
||||||
|
path = ROOT/f"assets/animations/fortune/{name}-v1.bin"
|
||||||
|
data = path.read_bytes()
|
||||||
|
magic,w,h,count,size = struct.unpack_from("<4s4I",data)
|
||||||
|
assert magic == b"ANM1" and len(data) == size+20 and size == w*h*4*count
|
||||||
|
assert count <= 64 and size <= 32*1024*1024
|
||||||
|
if count > 1:
|
||||||
|
pixels = [data[20+i*w*h*4:20+(i+1)*w*h*4] for i in range(count)]
|
||||||
|
assert len(set(pixels)) >= count-3, (name,"animation frames must differ")
|
||||||
|
if name == "cards":
|
||||||
|
for i in range(22):
|
||||||
|
upright = Image.frombytes("RGBA",(w,h),pixels[i],"raw","BGRA")
|
||||||
|
reversed_card = Image.frombytes("RGBA",(w,h),pixels[i+22],"raw","BGRA")
|
||||||
|
assert upright.transpose(Image.Transpose.ROTATE_180).tobytes() == reversed_card.tobytes()
|
||||||
entrance = Image.open(OUT / (("old-seam-" if args.prove_seam_regression else "") +
|
entrance = Image.open(OUT / (("old-seam-" if args.prove_seam_regression else "") +
|
||||||
"upper-entrance-open.bmp")).convert("RGB").crop((200,150,300,350))
|
"upper-entrance-open.bmp")).convert("RGB").crop((200,150,300,350))
|
||||||
dominant = max(count for count,_ in entrance.getcolors(20000))/20000
|
dominant = max(count for count,_ in entrance.getcolors(20000))/20000
|
||||||
|
|
@ -308,8 +344,6 @@ def main():
|
||||||
x0,y0,x1,y1 = sprite.getbbox()
|
x0,y0,x1,y1 = sprite.getbbox()
|
||||||
assert 0 < x0 < x1 < w and 0 < y0 < y1 < h, "uncropped musician cutout"
|
assert 0 < x0 < x1 < w and 0 < y0 < y1 < h, "uncropped musician cutout"
|
||||||
print("PASS: native stairs/doorways, automatic door, tickets, gait, portal, secret passage, bar camera and fortune dialogue")
|
print("PASS: native stairs/doorways, automatic door, tickets, gait, portal, secret passage, bar camera and fortune dialogue")
|
||||||
if args.with_fortune_ai:
|
|
||||||
print("PASS: actual x86 game input/IPC/rendering with the x64 local model, response and child cleanup")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
148
tools/tests/check_observer.py
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
"""Compile fresh native spectator/game code and run autonomous matches, not mock results."""
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
from PIL import Image
|
||||||
|
from check_card_exit_build import Coff
|
||||||
|
from check_terminals import signature
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = ROOT / "build/observer"
|
||||||
|
|
||||||
|
|
||||||
|
def read(path):
|
||||||
|
raw = (ROOT / path).read_bytes()
|
||||||
|
try:
|
||||||
|
return raw.decode("utf8").replace("\r\n", "\n")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return raw.decode("cp1251").replace("\r\n", "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def proc(text, name):
|
||||||
|
return re.search(rf"^{name} PROC\b.*?^{name} ENDP", text, re.M | re.S).group()
|
||||||
|
|
||||||
|
|
||||||
|
def expand(path):
|
||||||
|
return re.sub(r"^include ([^\n]+)$", lambda m: expand(m[1].strip().replace("\\", "/")),
|
||||||
|
read(path), flags=re.M)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare():
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
code = "\n".join(expand("src_graphics/" + name + ".inc") for name in
|
||||||
|
("observer", "native_poker", "native_durak", "native_blackjack", "pyramid_play", "eightball",
|
||||||
|
"card_tables_render", "durak_render"))
|
||||||
|
for path, names in (("platform_code", ("SaveProgress3D",)),
|
||||||
|
("npc_contracts", ("NpcRecordRound3D",)),
|
||||||
|
("charms", ("TriggerCharmLossProtection",)),
|
||||||
|
("card_table_input", ("HandleCardExit3D", "RequestCardExit3D", "LeaveCardTable3D", "TableBusy3D"))):
|
||||||
|
code += "\n" + "\n".join(proc(read("src_graphics/" + path + ".inc"), name) for name in names)
|
||||||
|
code += "\n" + proc(read("tools/tests/casino_actions_test.inc"), "WriteActionSnapshot3D")
|
||||||
|
code += "\n" + read("tools/tests/durak_test.inc")
|
||||||
|
code += "\nPlayCasinoSound3D PROC arg0:DWORD,arg1:DWORD,arg2:DWORD\n ret\nPlayCasinoSound3D ENDP\n"
|
||||||
|
# Stop before any persistence side effect even if a tested observer barrier regresses.
|
||||||
|
for name in ("RefreshTerminalAchievements3D", "NpcEnsureJournal3D"):
|
||||||
|
code += f"\n{name} PROC\n invoke ExitProcess,8402\n ret\n{name} ENDP\n"
|
||||||
|
code += "\n" + read("tools/tests/observer_test.inc")
|
||||||
|
code = code.replace(":SDWORD", ":DWORD")
|
||||||
|
data = read("src_graphics/observer_data.inc")
|
||||||
|
data += "\n.data\nactionBmpHeader db 42h,4Dh\n dd 1228854\n dw 0,0\n dd 54,40,640,-480\n dw 1,32\n dd 0,1228800,0,0,0,0\n"
|
||||||
|
own_funcs = set(re.findall(r"^(\w+) PROC", code, re.M))
|
||||||
|
own_data = set(re.findall(r"^(\w+)\s+(?:db|dd)\b", data + "\n" + code, re.M))
|
||||||
|
source = "\n".join(read(str(p.relative_to(ROOT))) for p in
|
||||||
|
[ROOT / "poker.asm", ROOT / "casino3d.inc", ROOT / "casino3d_data.inc",
|
||||||
|
*sorted(p for p in (ROOT / "src_graphics").glob("*.inc") if p.name != "renderer.inc")])
|
||||||
|
structures = [re.search(rf"^{name} STRUCT\b.*?^{name} ENDS", source, re.M | re.S).group()
|
||||||
|
for name in ("AnimPack3D", "BJBot3D")]
|
||||||
|
types = {name: kind for name, kind in re.findall(r"^(\w+)\s+(AnimPack3D|BJBot3D)\b", source, re.M)}
|
||||||
|
types.update({name: {"db": "BYTE", "dw": "WORD", "dd": "DWORD"}[kind.lower()]
|
||||||
|
for name, kind in re.findall(r"^(\w+)\s+(db|dw|dd)\b", source, re.M | re.I)})
|
||||||
|
types.update({name: kind.upper() for name, kind in
|
||||||
|
re.findall(r"^(\w+)\s+(REAL4|REAL8)\b", source, re.M | re.I)})
|
||||||
|
coff = Coff(ROOT / "build/graphics/poker.obj")
|
||||||
|
helper = bytearray(coff.data)
|
||||||
|
symbol_at = struct.unpack_from("<I", helper, 8)[0]
|
||||||
|
externs, protos = [], {}
|
||||||
|
for index, name in coff.symbols.items():
|
||||||
|
pos = symbol_at + index * 18
|
||||||
|
_, section, kind, storage, _ = struct.unpack_from("<IhHBB", helper, pos + 8)
|
||||||
|
if section > 0 and re.fullmatch(r"[A-Za-z_]\w*", name) and storage in (2, 3):
|
||||||
|
secname = helper[20+(section-1)*40:28+(section-1)*40].rstrip(b"\0")
|
||||||
|
if secname in (b".data", b".bss", b".const"):
|
||||||
|
helper[pos+16] = 3 if name in own_data else 2
|
||||||
|
if name not in own_data:
|
||||||
|
externs.append(f"EXTERN {name}:{types.get(name, 'DWORD')}")
|
||||||
|
match = re.fullmatch(r"_(\w+)@(\d+)", name)
|
||||||
|
if match and kind == 0x20 and section > 0:
|
||||||
|
helper[pos+16] = 3 if match[1] in own_funcs else 2
|
||||||
|
if match[1] not in own_funcs:
|
||||||
|
protos[match[1]] = int(match[2]) // 4
|
||||||
|
for name, params in re.findall(r"^(\w+)\s+PROTO([^\n]*)", source, re.M):
|
||||||
|
protos.setdefault(name, params.count(":DWORD"))
|
||||||
|
for name in own_funcs:
|
||||||
|
protos[name] = len(re.findall(r":S?DWORD", proc(code, name).splitlines()[0]))
|
||||||
|
constants = dict(re.findall(r"^(\w+)\s+equ\s+([^;\n]+)", source, re.M))
|
||||||
|
used = set(re.findall(r"^(\w+) equ", data, re.M))
|
||||||
|
ordered = []
|
||||||
|
def constant(name):
|
||||||
|
if name not in constants or name in used:
|
||||||
|
return
|
||||||
|
used.add(name)
|
||||||
|
for dep in re.findall(r"\b[A-Za-z_]\w*", constants[name]):
|
||||||
|
constant(dep)
|
||||||
|
ordered.append(f"{name} equ {constants[name]}")
|
||||||
|
for name in re.findall(r"\b[A-Za-z_]\w*", code + data):
|
||||||
|
constant(name)
|
||||||
|
header = ".386\n.model flat\noption casemap:none\n" + "\n".join(structures + ordered + externs)
|
||||||
|
header += "\noption language:stdcall\n" + "\n".join(
|
||||||
|
name + " PROTO" + (" " + ",".join([":DWORD"]*count) if count else "") for name, count in protos.items())
|
||||||
|
data = re.sub(r"^\w+ PROTO[^\n]*\n", "", data, flags=re.M)
|
||||||
|
(OUT / "helpers.obj").write_bytes(helper)
|
||||||
|
(OUT / "module.asm").write_text(header + "\n" + data + "\n.code\n" + code + "\nend ObserverTestStart\n", encoding="cp1251")
|
||||||
|
return {name for name in own_funcs if not name.startswith("DurakTest") and name != "RunDurakTest3D"} - {
|
||||||
|
"PlayCasinoSound3D", "WriteActionSnapshot3D", "ObserverTestStart",
|
||||||
|
"RefreshTerminalAchievements3D", "NpcEnsureJournal3D"}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--parity", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
functions = prepare()
|
||||||
|
if args.parity:
|
||||||
|
tested, shipping = Coff(OUT / "module.obj"), Coff(ROOT / "build/graphics/poker.obj")
|
||||||
|
for name in functions:
|
||||||
|
symbol = next(key for key in tested.functions if key.startswith("_" + name + "@"))
|
||||||
|
assert signature(tested, symbol, tail_branches=True) == signature(shipping, symbol, tail_branches=True), name
|
||||||
|
print("PASS: native observer and game code match the shipping object")
|
||||||
|
return
|
||||||
|
masm = Path("F:/MASM32/masm32")
|
||||||
|
subprocess.run([str(masm / "bin/ml.exe"), "/c", "/coff", "/Cp", "/nologo", "/I.",
|
||||||
|
"/Fobuild/observer/module.obj", "build/observer/module.asm"], cwd=ROOT, check=True)
|
||||||
|
sdk = sorted(Path("C:/Program Files (x86)/Windows Kits/10/Lib").glob("*/um/x86"))[-1]
|
||||||
|
subprocess.run([str(masm / "bin/link.exe"), "/nologo", "/SUBSYSTEM:CONSOLE", "/ENTRY:ObserverTestStart@0",
|
||||||
|
f"/LIBPATH:{sdk}", f"/LIBPATH:{masm/'lib'}", "/OUT:build/observer/module.exe",
|
||||||
|
"build/observer/module.obj", "build/observer/helpers.obj", "kernel32.lib", "user32.lib",
|
||||||
|
"gdi32.lib", "winmm.lib", "ws2_32.lib"], cwd=ROOT, check=True)
|
||||||
|
def profile():
|
||||||
|
return {str(p): hashlib.sha256(p.read_bytes()).digest() for p in (ROOT / "runtime").rglob("*")
|
||||||
|
if p.is_file()}
|
||||||
|
before = profile()
|
||||||
|
run = subprocess.run([str(OUT / "module.exe")], cwd=ROOT, timeout=180)
|
||||||
|
assert run.returncode == 0, f"Native observer assertion: {run.returncode}"
|
||||||
|
assert profile() == before, "Observation changed persistent profile files"
|
||||||
|
sheet = Image.new("RGB", (1280, 480*4))
|
||||||
|
for i, name in enumerate(("menu", "poker", "blackjack", "durak", "transfer", "pyramid", "eight")):
|
||||||
|
frame = Image.open(OUT / (name + ".bmp")).convert("RGB")
|
||||||
|
assert len(frame.getcolors(640*480)) >= (4 if name == "menu" else 500), name
|
||||||
|
frame.save(OUT / (name + ".png"))
|
||||||
|
sheet.paste(frame, ((i % 2)*640, (i // 2)*480))
|
||||||
|
sheet.save(OUT / "contact.png")
|
||||||
|
print("PASS: 80 autonomous card matches, both billiard seats, pause, profile restore and no persistent writes")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
42
tools/tests/darts_hall_test.inc
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
.data
|
||||||
|
dtHallSnapshot db "build\hall-expansion\darts-hall.bmp",0
|
||||||
|
.code
|
||||||
|
ExpansionDartsTests PROC
|
||||||
|
mov expansionStage,8510
|
||||||
|
mov hallLevel3D,0
|
||||||
|
mov engineMode,MODE_WALK
|
||||||
|
mov worldMap3D,OFFSET casinoMap
|
||||||
|
mov playerX,29*FP_1
|
||||||
|
mov playerY,28*FP_1
|
||||||
|
mov playerAngle,0
|
||||||
|
invoke CanWalk3D,playerX,playerY
|
||||||
|
test eax,eax
|
||||||
|
jz dt_hall_fail
|
||||||
|
call UpdateInteriorEye3D
|
||||||
|
call ExpansionFrame
|
||||||
|
invoke ExpansionSnapshot,OFFSET dtHallSnapshot
|
||||||
|
call CheckHallInteractions3D
|
||||||
|
cmp interactTargetId,INTERACT_DARTS
|
||||||
|
jne dt_hall_fail
|
||||||
|
call TriggerHallInteraction3D
|
||||||
|
test eax,eax
|
||||||
|
jz dt_hall_fail
|
||||||
|
cmp engineMode,MODE_DARTS
|
||||||
|
jne dt_hall_fail
|
||||||
|
cmp dtError3D,0
|
||||||
|
jne dt_hall_fail
|
||||||
|
cmp dtScores3D,500
|
||||||
|
jne dt_hall_fail
|
||||||
|
cmp dtScores3D[4],500
|
||||||
|
jne dt_hall_fail
|
||||||
|
cmp playerX,29*FP_1
|
||||||
|
jne dt_hall_fail
|
||||||
|
cmp playerY,28*FP_1
|
||||||
|
jne dt_hall_fail
|
||||||
|
call FreeDarts3D
|
||||||
|
mov engineMode,MODE_WALK
|
||||||
|
ret
|
||||||
|
dt_hall_fail:
|
||||||
|
invoke ExitProcess,8510
|
||||||
|
ret
|
||||||
|
ExpansionDartsTests ENDP
|
||||||
374
tools/tests/darts_test.inc
Normal file
|
|
@ -0,0 +1,374 @@
|
||||||
|
.data
|
||||||
|
dtVectors3D LABEL DWORD
|
||||||
|
dd 0,53,20,1
|
||||||
|
dd 0,103,60,3
|
||||||
|
dd 0,166,40,2
|
||||||
|
dd 16,50,1,1
|
||||||
|
dd 32,98,3,3
|
||||||
|
dd 51,158,2,2
|
||||||
|
dd 31,43,18,1
|
||||||
|
dd 61,83,54,3
|
||||||
|
dd 98,134,36,2
|
||||||
|
dd 43,31,4,1
|
||||||
|
dd 83,61,12,3
|
||||||
|
dd 134,98,8,2
|
||||||
|
dd 50,16,13,1
|
||||||
|
dd 98,32,39,3
|
||||||
|
dd 158,51,26,2
|
||||||
|
dd 53,0,6,1
|
||||||
|
dd 103,0,18,3
|
||||||
|
dd 166,0,12,2
|
||||||
|
dd 50,-16,10,1
|
||||||
|
dd 98,-32,30,3
|
||||||
|
dd 158,-51,20,2
|
||||||
|
dd 43,-31,15,1
|
||||||
|
dd 83,-61,45,3
|
||||||
|
dd 134,-98,30,2
|
||||||
|
dd 31,-43,2,1
|
||||||
|
dd 61,-83,6,3
|
||||||
|
dd 98,-134,4,2
|
||||||
|
dd 16,-50,17,1
|
||||||
|
dd 32,-98,51,3
|
||||||
|
dd 51,-158,34,2
|
||||||
|
dd 0,-53,3,1
|
||||||
|
dd 0,-103,9,3
|
||||||
|
dd 0,-166,6,2
|
||||||
|
dd -16,-50,19,1
|
||||||
|
dd -32,-98,57,3
|
||||||
|
dd -51,-158,38,2
|
||||||
|
dd -31,-43,7,1
|
||||||
|
dd -61,-83,21,3
|
||||||
|
dd -98,-134,14,2
|
||||||
|
dd -43,-31,16,1
|
||||||
|
dd -83,-61,48,3
|
||||||
|
dd -134,-98,32,2
|
||||||
|
dd -50,-16,8,1
|
||||||
|
dd -98,-32,24,3
|
||||||
|
dd -158,-51,16,2
|
||||||
|
dd -53,0,11,1
|
||||||
|
dd -103,0,33,3
|
||||||
|
dd -166,0,22,2
|
||||||
|
dd -50,16,14,1
|
||||||
|
dd -98,32,42,3
|
||||||
|
dd -158,51,28,2
|
||||||
|
dd -43,31,9,1
|
||||||
|
dd -83,61,27,3
|
||||||
|
dd -134,98,18,2
|
||||||
|
dd -31,43,12,1
|
||||||
|
dd -61,83,36,3
|
||||||
|
dd -98,134,24,2
|
||||||
|
dd -16,50,5,1
|
||||||
|
dd -32,98,15,3
|
||||||
|
dd -51,158,10,2
|
||||||
|
dd 0,0,50,2
|
||||||
|
dd 0,6,50,2
|
||||||
|
dd 0,10,25,1
|
||||||
|
dd 0,16,20,1
|
||||||
|
dd 0,190,0,0
|
||||||
|
dd 2147483647,0,0,0
|
||||||
|
dd -2147483648,0,0,0
|
||||||
|
dtVectorCount3D equ 67
|
||||||
|
dtTestTriples3D dd 0
|
||||||
|
dtTestMetricPath db "build\darts\aim-metrics.bin",0
|
||||||
|
.code
|
||||||
|
DartsTestWriteMetrics PROC uses ebx
|
||||||
|
local written:DWORD
|
||||||
|
invoke CreateFileA,OFFSET dtTestMetricPath,40000000h,0,0,2,80h,0
|
||||||
|
cmp eax,-1
|
||||||
|
je dt_test_metric_fail
|
||||||
|
mov ebx,eax
|
||||||
|
invoke WriteFile,ebx,OFFSET dtTestTriples3D,4,ADDR written,0
|
||||||
|
invoke CloseHandle,ebx
|
||||||
|
ret
|
||||||
|
dt_test_metric_fail:
|
||||||
|
invoke ExitProcess,8505
|
||||||
|
ret
|
||||||
|
DartsTestWriteMetrics ENDP
|
||||||
|
|
||||||
|
DartsTestStart PROC uses ebx esi edi
|
||||||
|
local legs:DWORD
|
||||||
|
call InitPaths3D
|
||||||
|
lea esi,dtVectors3D
|
||||||
|
mov ebx,dtVectorCount3D
|
||||||
|
dt_test_vector:
|
||||||
|
invoke DartsScore3D,[esi],[esi+4]
|
||||||
|
cmp eax,[esi+8]
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp edx,[esi+12]
|
||||||
|
jne dt_test_fail
|
||||||
|
add esi,16
|
||||||
|
dec ebx
|
||||||
|
jnz dt_test_vector
|
||||||
|
mov playerX,123456
|
||||||
|
mov playerY,789012
|
||||||
|
mov bankroll,12345
|
||||||
|
call ResetDarts3D
|
||||||
|
mov dtCursorX3D,320*256
|
||||||
|
mov dtCursorY3D,214*256
|
||||||
|
mov dtClock3D,384
|
||||||
|
mov dtHolding3D,1
|
||||||
|
mov dtHoldTime3D,0
|
||||||
|
call DartsAim3D
|
||||||
|
cmp dtAimX3D,10
|
||||||
|
jl dt_test_fail
|
||||||
|
cmp dtAimX3D,13
|
||||||
|
jg dt_test_fail
|
||||||
|
mov ebx,dtAimX3D
|
||||||
|
mov dtHoldTime3D,4000
|
||||||
|
call DartsAim3D
|
||||||
|
mov eax,dtAimX3D
|
||||||
|
sub eax,ebx
|
||||||
|
cmp eax,8
|
||||||
|
jne dt_test_fail
|
||||||
|
; Fine mouse motion must survive the hall's coarser 320px UI coordinates.
|
||||||
|
mov engineMode,MODE_DARTS
|
||||||
|
mov viewWidth3D,2560
|
||||||
|
mov viewHeight3D,1440
|
||||||
|
mov viewLeft3D,0
|
||||||
|
mov viewTop3D,0
|
||||||
|
invoke WindowEvents3D,0,200h,0,02820500h
|
||||||
|
call DartsAim3D
|
||||||
|
mov ebx,dtAimX3D
|
||||||
|
invoke WindowEvents3D,0,200h,0,02820502h
|
||||||
|
call DartsAim3D
|
||||||
|
cmp dtAimX3D,ebx
|
||||||
|
jle dt_test_fail
|
||||||
|
cmp mouseX3D,160
|
||||||
|
jne dt_test_fail
|
||||||
|
mov ebx,dtAimY3D
|
||||||
|
invoke WindowEvents3D,0,200h,0,02840502h
|
||||||
|
call DartsAim3D
|
||||||
|
cmp dtAimY3D,ebx
|
||||||
|
jge dt_test_fail
|
||||||
|
cmp mouseY3D,107
|
||||||
|
jne dt_test_fail
|
||||||
|
call ResetDarts3D
|
||||||
|
call DartsCamera3D
|
||||||
|
invoke DartsProject3D,-248,0,DT_WALL
|
||||||
|
mov ebx,eax
|
||||||
|
invoke DartsProject3D,248,0,DT_WALL
|
||||||
|
sub eax,ebx
|
||||||
|
cmp eax,170
|
||||||
|
jl dt_test_fail
|
||||||
|
cmp eax,180
|
||||||
|
jg dt_test_fail
|
||||||
|
; Camping at the centre of T20 no longer guarantees a triple every time.
|
||||||
|
mov dtCursorX3D,320*256
|
||||||
|
mov dtCursorY3D,214*256-103*DT_FOCAL*256/DT_WALL
|
||||||
|
mov dtClock3D,0
|
||||||
|
mov dtTestTriples3D,0
|
||||||
|
mov edi,100
|
||||||
|
dt_test_sway_samples:
|
||||||
|
call DartsAim3D
|
||||||
|
invoke DartsScore3D,dtAimX3D,dtAimY3D
|
||||||
|
cmp eax,60
|
||||||
|
jne @F
|
||||||
|
inc dtTestTriples3D
|
||||||
|
@@:
|
||||||
|
add dtClock3D,16
|
||||||
|
dec edi
|
||||||
|
jnz dt_test_sway_samples
|
||||||
|
cmp dtTestTriples3D,10
|
||||||
|
jb dt_test_fail
|
||||||
|
cmp dtTestTriples3D,60
|
||||||
|
ja dt_test_fail
|
||||||
|
call DartsTestWriteMetrics
|
||||||
|
mov dtState3D,DT_FLIGHT
|
||||||
|
mov dtTimer3D,400
|
||||||
|
mov deltaTime3D,16
|
||||||
|
mov pressedKeys3D[9],1
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtScoreOpen3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtTimer3D,400
|
||||||
|
jne dt_test_fail
|
||||||
|
mov pressedKeys3D[9],1
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtScoreOpen3D,0
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtTimer3D,416
|
||||||
|
jne dt_test_fail
|
||||||
|
call ResetDarts3D
|
||||||
|
mov dtHitX3D,0
|
||||||
|
mov dtHitY3D,103
|
||||||
|
mov dtRemaining3D,59
|
||||||
|
mov dtVisitStart3D,100
|
||||||
|
mov dtState3D,DT_FLIGHT
|
||||||
|
call SettleDarts3D
|
||||||
|
cmp dtRemaining3D,100
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtBust3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtCount3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
call SettleDarts3D
|
||||||
|
cmp dtCount3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
call ResetDarts3D
|
||||||
|
mov dtHitX3D,0
|
||||||
|
mov dtHitY3D,166
|
||||||
|
mov dtRemaining3D,40
|
||||||
|
mov dtVisitStart3D,40
|
||||||
|
mov dtState3D,DT_FLIGHT
|
||||||
|
call SettleDarts3D
|
||||||
|
cmp dtRemaining3D,0
|
||||||
|
jne dt_test_fail
|
||||||
|
mov dtTimer3D,1300
|
||||||
|
mov deltaTime3D,16
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtState3D,DT_WIN
|
||||||
|
jne dt_test_fail
|
||||||
|
call ResetDarts3D
|
||||||
|
mov dtHitY3D,166
|
||||||
|
mov dtRemaining3D,41
|
||||||
|
mov dtVisitStart3D,41
|
||||||
|
mov dtState3D,DT_FLIGHT
|
||||||
|
call SettleDarts3D
|
||||||
|
cmp dtRemaining3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtBust3D,0
|
||||||
|
jne dt_test_fail
|
||||||
|
mov dtCount3D,3
|
||||||
|
mov dtState3D,DT_RETURN
|
||||||
|
mov dtTimer3D,750
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtCount3D,0
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtVisit3D,2
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtActor3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtRemaining3D,500
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtScores3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtScores3D[4],500
|
||||||
|
jne dt_test_fail
|
||||||
|
call ResetDarts3D
|
||||||
|
mov engineMode,MODE_DARTS
|
||||||
|
mov viewWidth3D,640
|
||||||
|
mov viewHeight3D,480
|
||||||
|
mov viewLeft3D,0
|
||||||
|
mov viewTop3D,0
|
||||||
|
mov mouseClick3D,0
|
||||||
|
invoke WindowEvents3D,0,200h,0,00D60140h
|
||||||
|
cmp mouseClick3D,0
|
||||||
|
jne dt_test_fail
|
||||||
|
invoke WindowEvents3D,0,201h,1,00D60140h
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtHolding3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
invoke WindowEvents3D,0,202h,0,00D60140h
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtState3D,DT_RELEASE
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtThrows3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
mov ebx,dtHitX3D
|
||||||
|
mov esi,dtHitY3D
|
||||||
|
invoke WindowEvents3D,0,200h,0,00640064h
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtHitX3D,ebx
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtHitY3D,esi
|
||||||
|
jne dt_test_fail
|
||||||
|
call ResetDarts3D
|
||||||
|
mov dtHitX3D,80
|
||||||
|
mov dtHitY3D,103
|
||||||
|
mov dtState3D,DT_FLIGHT
|
||||||
|
mov dtTimer3D,0
|
||||||
|
call DartsCamera3D
|
||||||
|
cmp dtCamZ3D,0
|
||||||
|
jne dt_test_fail
|
||||||
|
mov dtTimer3D,600
|
||||||
|
call DartsCamera3D
|
||||||
|
cmp dtCamZ3D,DT_WALL/2-160
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtYawSin3D,50000
|
||||||
|
jl dt_test_fail
|
||||||
|
mov dtTimer3D,1200
|
||||||
|
call DartsCamera3D
|
||||||
|
cmp dtCamZ3D,DT_WALL-420
|
||||||
|
jne dt_test_fail
|
||||||
|
invoke DartsProject3D,80,103,DT_WALL
|
||||||
|
cmp eax,320
|
||||||
|
jl dt_test_fail
|
||||||
|
cmp eax,420
|
||||||
|
jg dt_test_fail
|
||||||
|
cmp edx,120
|
||||||
|
jl dt_test_fail
|
||||||
|
cmp edx,214
|
||||||
|
jg dt_test_fail
|
||||||
|
cmp dtYawSin3D,12000
|
||||||
|
jg dt_test_fail
|
||||||
|
; Actual bot input ignores the cursor and automatically releases a dart.
|
||||||
|
call ResetDarts3D
|
||||||
|
mov dtActor3D,1
|
||||||
|
mov mouseX3D,0
|
||||||
|
mov mouseY3D,0
|
||||||
|
mov deltaTime3D,1600
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtState3D,DT_RELEASE
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtThrows3D,1
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp dtScores3D,500
|
||||||
|
jne dt_test_fail
|
||||||
|
; Complete a real match through normal phase/visit transitions.
|
||||||
|
mov legs,20
|
||||||
|
dt_test_another_match:
|
||||||
|
call ResetDarts3D
|
||||||
|
mov edi,5000
|
||||||
|
dt_test_match:
|
||||||
|
cmp dtState3D,DT_WIN
|
||||||
|
je dt_test_match_done
|
||||||
|
cmp dtState3D,DT_AIM
|
||||||
|
jne dt_test_match_tick
|
||||||
|
cmp dtActor3D,0
|
||||||
|
jne dt_test_match_tick
|
||||||
|
call DartsBotAim3D
|
||||||
|
mov eax,dtBotAimX3D
|
||||||
|
mov dtAimX3D,eax
|
||||||
|
mov eax,dtBotAimY3D
|
||||||
|
mov dtAimY3D,eax
|
||||||
|
call ThrowDarts3D
|
||||||
|
dt_test_match_tick:
|
||||||
|
mov deltaTime3D,1400
|
||||||
|
call HandleDarts3D
|
||||||
|
cmp dtScores3D,500
|
||||||
|
ja dt_test_fail
|
||||||
|
cmp dtScores3D[4],500
|
||||||
|
ja dt_test_fail
|
||||||
|
dec edi
|
||||||
|
jnz dt_test_match
|
||||||
|
jmp dt_test_fail
|
||||||
|
dt_test_match_done:
|
||||||
|
mov eax,dtWinner3D
|
||||||
|
cmp dtScores3D[eax*4],0
|
||||||
|
jne dt_test_fail
|
||||||
|
dec legs
|
||||||
|
jnz dt_test_another_match
|
||||||
|
cmp playerX,123456
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp playerY,789012
|
||||||
|
jne dt_test_fail
|
||||||
|
cmp bankroll,12345
|
||||||
|
jne dt_test_fail
|
||||||
|
call LoadDarts3D
|
||||||
|
test eax,eax
|
||||||
|
jz dt_test_assets
|
||||||
|
call DartsTestFrames
|
||||||
|
call FreeDarts3D
|
||||||
|
xor eax,eax
|
||||||
|
jmp dt_test_exit
|
||||||
|
dt_test_assets:
|
||||||
|
mov eax,8502
|
||||||
|
jmp dt_test_exit
|
||||||
|
dt_test_fail:
|
||||||
|
mov eax,8501
|
||||||
|
dt_test_exit:
|
||||||
|
invoke ExitProcess,eax
|
||||||
|
DartsTestStart ENDP
|
||||||
|
|
||||||
64
tools/tests/darts_ui.inc
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
; Interactive fixture reuses the actual native scene, window events and presenter.
|
||||||
|
.code
|
||||||
|
DartsUiStart PROC
|
||||||
|
call InitPaths3D
|
||||||
|
call Create3DWindow
|
||||||
|
test eax,eax
|
||||||
|
jz dt_ui_fail
|
||||||
|
invoke SetWindowLongA,h3DWnd,-4,OFFSET WindowEvents3D
|
||||||
|
call ToggleFullscreen3D
|
||||||
|
call BeginDarts3D
|
||||||
|
call RenderDarts3D
|
||||||
|
invoke ShowWindow,h3DWnd,1
|
||||||
|
call Present3D
|
||||||
|
invoke SetForegroundWindow,h3DWnd
|
||||||
|
invoke GetTickCount
|
||||||
|
mov previousTick3D,eax
|
||||||
|
dt_ui_loop:
|
||||||
|
invoke PeekMessageA,OFFSET msg3D,0,0,0,1
|
||||||
|
test eax,eax
|
||||||
|
jz dt_ui_frame
|
||||||
|
cmp dword ptr msg3D[4],12h
|
||||||
|
je dt_ui_close
|
||||||
|
invoke TranslateMessage,OFFSET msg3D
|
||||||
|
invoke DispatchMessageA,OFFSET msg3D
|
||||||
|
jmp dt_ui_loop
|
||||||
|
dt_ui_frame:
|
||||||
|
invoke GetTickCount
|
||||||
|
mov frameStart3D,eax
|
||||||
|
sub eax,previousTick3D
|
||||||
|
cmp eax,50
|
||||||
|
jbe @F
|
||||||
|
mov eax,50
|
||||||
|
@@:
|
||||||
|
mov deltaTime3D,eax
|
||||||
|
mov eax,frameStart3D
|
||||||
|
mov previousTick3D,eax
|
||||||
|
invoke GetForegroundWindow
|
||||||
|
cmp eax,h3DWnd
|
||||||
|
jne dt_ui_idle
|
||||||
|
invoke Pressed3D,1Bh
|
||||||
|
test eax,eax
|
||||||
|
jnz dt_ui_close
|
||||||
|
invoke Pressed3D,7Ah
|
||||||
|
test eax,eax
|
||||||
|
jz @F
|
||||||
|
call ToggleFullscreen3D
|
||||||
|
@@:
|
||||||
|
call HandleDarts3D
|
||||||
|
call RenderDarts3D
|
||||||
|
call Present3D
|
||||||
|
dt_ui_idle:
|
||||||
|
invoke Sleep,16
|
||||||
|
jmp dt_ui_loop
|
||||||
|
dt_ui_close:
|
||||||
|
call FreeDarts3D
|
||||||
|
invoke ReleaseDC,h3DWnd,h3DDC
|
||||||
|
invoke DestroyWindow,h3DWnd
|
||||||
|
dt_ui_exit:
|
||||||
|
invoke ExitProcess,0
|
||||||
|
ret
|
||||||
|
dt_ui_fail:
|
||||||
|
invoke ExitProcess,8503
|
||||||
|
ret
|
||||||
|
DartsUiStart ENDP
|
||||||
|
|
@ -1,112 +1,243 @@
|
||||||
.data
|
.data
|
||||||
fortuneLiveQuestion db 209,242,238,232,242,32,235,232,32,237,224,247,224,242,252,32,243,247,232,242,252,241,255,32,240,232,241,238,226,224,237,232,254,63,0
|
fortuneSessionBank dd 0
|
||||||
fortuneLiveShot db "build\hall-expansion\fortune-dialog-answer.bmp",0
|
fortuneSessionPlayer dd 0
|
||||||
fortuneLiveBank dd 0
|
fortuneSessionMotion db "build\hall-expansion\fortune-session-motion-"
|
||||||
|
fortuneSessionDigits db "00.bmp",0
|
||||||
|
fortuneSessionQuestion db 193,243,228,229,242,32,235,232,32,231,224,226,242,240,224,32,228,238,230,228,252,63,0
|
||||||
|
fortuneSessionShot0 db "build\hall-expansion\fortune-session-input.bmp",0
|
||||||
|
fortuneSessionShot1 db "build\hall-expansion\fortune-session-shuffle.bmp",0
|
||||||
|
fortuneSessionShot2 db "build\hall-expansion\fortune-session-deal-one.bmp",0
|
||||||
|
fortuneSessionShot3 db "build\hall-expansion\fortune-session-deal-two.bmp",0
|
||||||
|
fortuneSessionShot4 db "build\hall-expansion\fortune-session-deal-three.bmp",0
|
||||||
|
fortuneSessionShot5 db "build\hall-expansion\fortune-session-flip-one.bmp",0
|
||||||
|
fortuneSessionShot6 db "build\hall-expansion\fortune-session-explain-one.bmp",0
|
||||||
|
fortuneSessionShot7 db "build\hall-expansion\fortune-session-flip-two.bmp",0
|
||||||
|
fortuneSessionShot8 db "build\hall-expansion\fortune-session-explain-two.bmp",0
|
||||||
|
fortuneSessionShot9 db "build\hall-expansion\fortune-session-flip-three.bmp",0
|
||||||
|
fortuneSessionShot10 db "build\hall-expansion\fortune-session-explain-three.bmp",0
|
||||||
|
fortuneSessionShot11 db "build\hall-expansion\fortune-session-summary.bmp",0
|
||||||
|
fortuneSessionShot12 db "build\hall-expansion\fortune-session-done.bmp",0
|
||||||
|
fortuneSessionShot13 db "build\hall-expansion\fortune-session-orb-rise.bmp",0
|
||||||
|
fortuneSessionShot14 db "build\hall-expansion\fortune-session-orb-mist.bmp",0
|
||||||
|
fortuneSessionShot15 db "build\hall-expansion\fortune-session-orb-final.bmp",0
|
||||||
|
fortuneSessionShots dd OFFSET fortuneSessionShot0,OFFSET fortuneSessionShot1,OFFSET fortuneSessionShot2,OFFSET fortuneSessionShot3
|
||||||
|
dd OFFSET fortuneSessionShot4,OFFSET fortuneSessionShot5,OFFSET fortuneSessionShot6,OFFSET fortuneSessionShot7
|
||||||
|
dd OFFSET fortuneSessionShot8,OFFSET fortuneSessionShot9,OFFSET fortuneSessionShot10,OFFSET fortuneSessionShot11
|
||||||
|
dd OFFSET fortuneSessionShot12
|
||||||
.code
|
.code
|
||||||
FortuneDialogNativeTests PROC uses esi edi
|
FortuneSessionStepTest PROC
|
||||||
|
add animationClock3D,100
|
||||||
|
call UpdateFortuneSession3D
|
||||||
|
ret
|
||||||
|
FortuneSessionStepTest ENDP
|
||||||
|
FortuneDialogNativeTests PROC uses ebx esi edi
|
||||||
mov expansionStage,80
|
mov expansionStage,80
|
||||||
mov hallLevel3D,3
|
|
||||||
mov engineMode,MODE_WALK
|
|
||||||
mov worldMap3D,OFFSET fortuneRoomMap3D
|
|
||||||
mov floorTexture3D,134
|
|
||||||
mov playerX,FP_1*155/10
|
|
||||||
mov playerY,11*FP_1
|
|
||||||
mov playerAngle,256
|
|
||||||
call UpdateInteriorEye3D
|
|
||||||
call ExpansionFrame
|
|
||||||
mov eax,bankroll
|
mov eax,bankroll
|
||||||
mov fortuneLiveBank,eax
|
mov fortuneSessionBank,eax
|
||||||
|
mov eax,playerX
|
||||||
|
mov fortuneSessionPlayer,eax
|
||||||
call BeginFortuneDialog3D
|
call BeginFortuneDialog3D
|
||||||
|
cmp fortuneSessionShuffle3D.frames,64
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneSessionDeal3D.frames,32
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneSessionCards3D.frames,45
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneProcess3D,0
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneRead3D,0
|
||||||
|
jne fortune_session_fail
|
||||||
|
invoke WindowEvents3D,0,102h,'1',0
|
||||||
|
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
|
||||||
|
jne fortune_session_fail
|
||||||
|
; Lower edge of the question box is not an Exit-button hit target.
|
||||||
|
mov mouseX3D,260
|
||||||
|
mov mouseY3D,222
|
||||||
|
mov mouseClick3D,1
|
||||||
|
call HandleFortuneDialog3D
|
||||||
cmp engineMode,MODE_FORTUNE
|
cmp engineMode,MODE_FORTUNE
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
cmp fortuneWorkerState3D,1
|
call SubmitFortuneQuestion3D
|
||||||
jne fortune_live_fail
|
cmp fortunePhase3D,0
|
||||||
|
jne fortune_session_fail
|
||||||
mov esi,250
|
mov esi,250
|
||||||
fortune_live_full_input:
|
fortune_session_input_limit:
|
||||||
invoke WindowEvents3D,0,102h,'a',0
|
invoke WindowEvents3D,0,102h,'a',0
|
||||||
dec esi
|
dec esi
|
||||||
jnz fortune_live_full_input
|
jnz fortune_session_input_limit
|
||||||
cmp fortuneQuestionLength3D,240
|
cmp fortuneQuestionLength3D,240
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
cmp fortuneQuestion3D[240],0
|
cmp fortuneQuestion3D[240],0
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
invoke WindowEvents3D,0,102h,8,0
|
invoke WindowEvents3D,0,102h,8,0
|
||||||
cmp fortuneQuestionLength3D,239
|
cmp fortuneQuestionLength3D,239
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
mov fortuneQuestionLength3D,0
|
mov fortuneQuestionLength3D,0
|
||||||
mov fortuneQuestion3D,0
|
mov fortuneQuestion3D,0
|
||||||
mov esi,OFFSET fortuneLiveQuestion
|
mov esi,OFFSET fortuneSessionQuestion
|
||||||
fortune_live_type:
|
fortune_session_input:
|
||||||
movzx eax,BYTE PTR [esi]
|
movzx eax,BYTE PTR [esi]
|
||||||
test eax,eax
|
test eax,eax
|
||||||
jz fortune_live_ready
|
jz fortune_session_input_done
|
||||||
invoke WindowEvents3D,0,102h,eax,0
|
invoke WindowEvents3D,0,102h,eax,0
|
||||||
inc esi
|
inc esi
|
||||||
jmp fortune_live_type
|
jmp fortune_session_input
|
||||||
fortune_live_ready:
|
fortune_session_input_done:
|
||||||
mov edi,9000
|
mov fortuneSpeechTime3D,3000
|
||||||
fortune_live_wait_ready:
|
|
||||||
call PollFortuneWorker3D
|
|
||||||
cmp fortuneWorkerState3D,2
|
|
||||||
je fortune_live_submit
|
|
||||||
cmp fortuneWorkerState3D,4
|
|
||||||
je fortune_live_fail
|
|
||||||
invoke Sleep,20
|
|
||||||
dec edi
|
|
||||||
jnz fortune_live_wait_ready
|
|
||||||
jmp fortune_live_fail
|
|
||||||
fortune_live_submit:
|
|
||||||
mov expansionStage,81
|
|
||||||
call SubmitFortuneQuestion3D
|
|
||||||
cmp fortuneWorkerState3D,3
|
|
||||||
jne fortune_live_fail
|
|
||||||
mov esi,fortuneQuestionLength3D
|
|
||||||
invoke WindowEvents3D,0,102h,'X',0
|
|
||||||
cmp fortuneQuestionLength3D,esi
|
|
||||||
jne fortune_live_fail
|
|
||||||
call SubmitFortuneQuestion3D
|
|
||||||
mov edi,9000
|
|
||||||
fortune_live_wait_answer:
|
|
||||||
call PollFortuneWorker3D
|
|
||||||
cmp fortuneWorkerState3D,2
|
|
||||||
je fortune_live_answer
|
|
||||||
cmp fortuneWorkerState3D,4
|
|
||||||
je fortune_live_fail
|
|
||||||
invoke Sleep,20
|
|
||||||
dec edi
|
|
||||||
jnz fortune_live_wait_answer
|
|
||||||
jmp fortune_live_fail
|
|
||||||
fortune_live_answer:
|
|
||||||
cmp fortuneAnswer3D,0
|
|
||||||
je fortune_live_fail
|
|
||||||
cmp fortuneQuestionLength3D,0
|
|
||||||
jne fortune_live_fail
|
|
||||||
call RenderFortuneDialog3D
|
call RenderFortuneDialog3D
|
||||||
invoke ExpansionSnapshot,OFFSET fortuneLiveShot
|
invoke ExpansionSnapshot,OFFSET fortuneSessionShot0
|
||||||
|
call SubmitFortuneQuestion3D
|
||||||
|
cmp fortunePhase3D,1
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneDealt3D,0
|
||||||
|
jne fortune_session_fail
|
||||||
|
invoke WindowEvents3D,0,102h,'X',0
|
||||||
|
cmp fortuneQuestionLength3D,22
|
||||||
|
jne fortune_session_fail
|
||||||
|
call SubmitFortuneQuestion3D
|
||||||
|
cmp fortunePhase3D,1
|
||||||
|
jne fortune_session_fail
|
||||||
|
mov fortunePhaseTime3D,700
|
||||||
|
mov fortuneSpeechTime3D,1000
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
invoke ExpansionSnapshot,OFFSET fortuneSessionShot1
|
||||||
|
cmp fortunePhaseTime3D,700
|
||||||
|
jne fortune_session_fail
|
||||||
|
xor edi,edi
|
||||||
|
fortune_session_motion:
|
||||||
|
mov eax,edi
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,10
|
||||||
|
div ecx
|
||||||
|
add al,'0'
|
||||||
|
add dl,'0'
|
||||||
|
mov fortuneSessionDigits[0],al
|
||||||
|
mov fortuneSessionDigits[1],dl
|
||||||
|
mov eax,edi
|
||||||
|
imul eax,25
|
||||||
|
mov fortunePhaseTime3D,eax
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
invoke ExpansionSnapshot,OFFSET fortuneSessionMotion
|
||||||
|
inc edi
|
||||||
|
cmp edi,64
|
||||||
|
jb fortune_session_motion
|
||||||
|
mov ebx,1
|
||||||
|
fortune_session_phases:
|
||||||
|
mov eax,fortuneDurations3D[ebx*4]
|
||||||
|
mov fortunePhaseTime3D,eax
|
||||||
|
call FortuneSessionStepTest
|
||||||
|
inc ebx
|
||||||
|
cmp fortunePhase3D,ebx
|
||||||
|
jne fortune_session_fail
|
||||||
|
mov fortunePhaseTime3D,600
|
||||||
|
mov fortuneSpeechTime3D,3000
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
invoke ExpansionSnapshot,fortuneSessionShots[ebx*4]
|
||||||
|
cmp ebx,12
|
||||||
|
jb fortune_session_phases
|
||||||
|
cmp fortuneDealt3D,3
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneRevealed3D,3
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneQuestionLength3D,22
|
||||||
|
jne fortune_session_fail
|
||||||
|
mov eax,fortuneSpeechLength3D
|
||||||
|
cmp fortuneSpeechVisible3D,eax
|
||||||
|
jne fortune_session_fail
|
||||||
|
; Distinct underlying cards even when orientation differs.
|
||||||
|
xor esi,esi
|
||||||
|
fortune_session_unique_outer:
|
||||||
|
mov eax,fortuneDrawCards3D[esi*4]
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,22
|
||||||
|
div ecx
|
||||||
|
mov edi,edx
|
||||||
|
lea ebx,[esi+1]
|
||||||
|
fortune_session_unique_inner:
|
||||||
|
cmp ebx,3
|
||||||
|
jae fortune_session_unique_next
|
||||||
|
mov eax,fortuneDrawCards3D[ebx*4]
|
||||||
|
xor edx,edx
|
||||||
|
div ecx
|
||||||
|
cmp edx,edi
|
||||||
|
je fortune_session_fail
|
||||||
|
inc ebx
|
||||||
|
jmp fortune_session_unique_inner
|
||||||
|
fortune_session_unique_next:
|
||||||
|
inc esi
|
||||||
|
cmp esi,2
|
||||||
|
jb fortune_session_unique_outer
|
||||||
|
mov expansionStage,81
|
||||||
|
; Bubble grows as glyphs appear and cannot exceed the scene edge.
|
||||||
|
invoke SetFortuneSpeech3D,OFFSET fortuneSummary3D
|
||||||
|
mov fortuneSpeechTime3D,280
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
mov esi,fortuneSpeechWidth3D
|
||||||
|
mov fortuneSpeechTime3D,3000
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
cmp fortuneSpeechWidth3D,esi
|
||||||
|
jbe fortune_session_fail
|
||||||
|
cmp fortuneSpeechWidth3D,204
|
||||||
|
ja fortune_session_fail
|
||||||
|
cmp fortuneSpeechHeight3D,140
|
||||||
|
ja fortune_session_fail
|
||||||
|
; Return to selection, then display the neutral, non-grading orb sequence.
|
||||||
|
mov mouseX3D,200
|
||||||
|
mov mouseY3D,232
|
||||||
mov mouseClick3D,1
|
mov mouseClick3D,1
|
||||||
|
call HandleFortuneDialog3D
|
||||||
|
cmp fortuneSubMode3D,0
|
||||||
|
jne fortune_session_fail
|
||||||
|
invoke WindowEvents3D,0,102h,'2',0
|
||||||
|
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
|
||||||
|
jne fortune_session_fail
|
||||||
|
mov fortunePhaseTime3D,700
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
invoke ExpansionSnapshot,OFFSET fortuneSessionShot13
|
||||||
|
mov fortunePhaseTime3D,1400
|
||||||
|
call FortuneSessionStepTest
|
||||||
|
cmp fortunePhase3D,2
|
||||||
|
jne fortune_session_fail
|
||||||
|
mov fortunePhaseTime3D,1500
|
||||||
|
mov fortuneSpeechTime3D,3000
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
invoke ExpansionSnapshot,OFFSET fortuneSessionShot14
|
||||||
|
mov fortunePhaseTime3D,5000
|
||||||
|
call FortuneSessionStepTest
|
||||||
|
cmp fortunePhase3D,3
|
||||||
|
jne fortune_session_fail
|
||||||
|
mov fortuneSpeechTime3D,3000
|
||||||
|
call RenderFortuneDialog3D
|
||||||
|
invoke ExpansionSnapshot,OFFSET fortuneSessionShot15
|
||||||
|
; Exit in the middle of an animation as well as after completion.
|
||||||
mov mouseX3D,260
|
mov mouseX3D,260
|
||||||
mov mouseY3D,226
|
mov mouseY3D,232
|
||||||
|
mov mouseClick3D,1
|
||||||
call HandleFortuneDialog3D
|
call HandleFortuneDialog3D
|
||||||
cmp engineMode,MODE_WALK
|
cmp engineMode,MODE_WALK
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
cmp fortuneProcess3D,0
|
cmp fortuneSessionRoom3D.pixels,0
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
cmp fortuneRead3D,0
|
call BeginFortuneDialog3D
|
||||||
jne fortune_live_fail
|
invoke FortuneChar3D,'1'
|
||||||
cmp fortuneWrite3D,0
|
invoke FortuneChar3D,'a'
|
||||||
jne fortune_live_fail
|
call SubmitFortuneQuestion3D
|
||||||
|
mov mouseX3D,260
|
||||||
|
mov mouseY3D,232
|
||||||
|
mov mouseClick3D,1
|
||||||
|
call HandleFortuneDialog3D
|
||||||
|
cmp engineMode,MODE_WALK
|
||||||
|
jne fortune_session_fail
|
||||||
|
cmp fortuneSessionShuffle3D.pixels,0
|
||||||
|
jne fortune_session_fail
|
||||||
mov eax,bankroll
|
mov eax,bankroll
|
||||||
cmp eax,fortuneLiveBank
|
cmp eax,fortuneSessionBank
|
||||||
jne fortune_live_fail
|
jne fortune_session_fail
|
||||||
cmp playerX,FP_1*155/10
|
mov eax,playerX
|
||||||
jne fortune_live_fail
|
cmp eax,fortuneSessionPlayer
|
||||||
cmp playerY,11*FP_1
|
jne fortune_session_fail
|
||||||
jne fortune_live_fail
|
|
||||||
cmp playerAngle,256
|
|
||||||
jne fortune_live_fail
|
|
||||||
ret
|
ret
|
||||||
fortune_live_fail:
|
fortune_session_fail:
|
||||||
call StopFortuneWorker3D
|
|
||||||
invoke ExitProcess,expansionStage
|
invoke ExitProcess,expansionStage
|
||||||
ret
|
ret
|
||||||
FortuneDialogNativeTests ENDP
|
FortuneDialogNativeTests ENDP
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ fortune_test_arrived:
|
||||||
invoke ExpansionSnapshot,OFFSET fortuneTestDialog
|
invoke ExpansionSnapshot,OFFSET fortuneTestDialog
|
||||||
mov mouseClick3D,1
|
mov mouseClick3D,1
|
||||||
mov mouseX3D,260
|
mov mouseX3D,260
|
||||||
mov mouseY3D,226
|
mov mouseY3D,232
|
||||||
call HandleFortuneDialog3D
|
call HandleFortuneDialog3D
|
||||||
cmp engineMode,MODE_WALK
|
cmp engineMode,MODE_WALK
|
||||||
jne fortune_test_fail
|
jne fortune_test_fail
|
||||||
|
|
|
||||||
|
|
@ -1162,9 +1162,8 @@ expansion_leaf_shut:
|
||||||
jne expansion_fail
|
jne expansion_fail
|
||||||
call FortuneNativeTests
|
call FortuneNativeTests
|
||||||
call BarCameraNativeTests
|
call BarCameraNativeTests
|
||||||
IFDEF CASINO_FORTUNE_AI_LIVE
|
|
||||||
call FortuneDialogNativeTests
|
call FortuneDialogNativeTests
|
||||||
ENDIF
|
call ExpansionDartsTests
|
||||||
invoke ExitProcess,0
|
invoke ExitProcess,0
|
||||||
expansion_fail:
|
expansion_fail:
|
||||||
invoke ExitProcess,expansionStage
|
invoke ExitProcess,expansionStage
|
||||||
|
|
@ -1173,3 +1172,4 @@ ExpansionTestStart ENDP
|
||||||
include tools/tests/fortune_room_test.inc
|
include tools/tests/fortune_room_test.inc
|
||||||
include tools/tests/bar_camera_test.inc
|
include tools/tests/bar_camera_test.inc
|
||||||
include tools/tests/fortune_dialog_test.inc
|
include tools/tests/fortune_dialog_test.inc
|
||||||
|
include tools/tests/darts_hall_test.inc
|
||||||
|
|
|
||||||
161
tools/tests/observer_test.inc
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
.data
|
||||||
|
obsTestGame dd 0
|
||||||
|
obsTestTicks dd 0
|
||||||
|
obsTestTurns dd 0
|
||||||
|
obsTestMenu db "build\observer\menu.bmp",0
|
||||||
|
obsTestPaths dd OFFSET obsTestPoker,OFFSET obsTestBlackjack,OFFSET obsTestDurak
|
||||||
|
dd OFFSET obsTestTransfer,OFFSET obsTestPyramid,OFFSET obsTestEight
|
||||||
|
obsTestPoker db "build\observer\poker.bmp",0
|
||||||
|
obsTestBlackjack db "build\observer\blackjack.bmp",0
|
||||||
|
obsTestDurak db "build\observer\durak.bmp",0
|
||||||
|
obsTestTransfer db "build\observer\transfer.bmp",0
|
||||||
|
obsTestPyramid db "build\observer\pyramid.bmp",0
|
||||||
|
obsTestEight db "build\observer\eight.bmp",0
|
||||||
|
.code
|
||||||
|
ObserverTestStart PROC
|
||||||
|
call InitPaths3D
|
||||||
|
mov arrivalConfirmed3D,1
|
||||||
|
mov bankroll,12345
|
||||||
|
mov charmCloverUses,17
|
||||||
|
mov charmDevilUses,18
|
||||||
|
mov obsActive3D,1
|
||||||
|
invoke TriggerCharmLossProtection,100
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_test_fail
|
||||||
|
cmp bankroll,12345
|
||||||
|
jne obs_test_fail
|
||||||
|
mov obsActive3D,0
|
||||||
|
call BeginObserver3D
|
||||||
|
call RenderObserver3D
|
||||||
|
invoke WriteActionSnapshot3D,OFFSET obsTestMenu
|
||||||
|
obs_test_game:
|
||||||
|
mov eax,obsTestGame
|
||||||
|
mov obsSelection3D,eax
|
||||||
|
call StartObserver3D
|
||||||
|
cmp obsActive3D,1
|
||||||
|
jne obs_test_fail
|
||||||
|
mov obsTestTicks,0
|
||||||
|
mov obsTestTurns,0
|
||||||
|
obs_test_tick:
|
||||||
|
mov deltaTime3D,50
|
||||||
|
call ObserverTick3D
|
||||||
|
cmp obsTestGame,4
|
||||||
|
jb obs_test_cards
|
||||||
|
cmp poolState3D,POOL_STRIKE
|
||||||
|
jne @F
|
||||||
|
mov eax,poolPlayer3D
|
||||||
|
bts obsTestTurns,eax
|
||||||
|
@@:
|
||||||
|
cmp obsTestTicks,1500
|
||||||
|
jb obs_test_next_tick
|
||||||
|
cmp obsTestTurns,3
|
||||||
|
jne obs_test_fail
|
||||||
|
jmp obs_test_snapshot
|
||||||
|
obs_test_cards:
|
||||||
|
cmp obsRound3D,21
|
||||||
|
jb obs_test_next_tick
|
||||||
|
mov eax,obsWins3D[0]
|
||||||
|
add eax,obsWins3D[4]
|
||||||
|
add eax,obsWins3D[8]
|
||||||
|
cmp eax,20
|
||||||
|
jne obs_test_fail
|
||||||
|
jmp obs_test_snapshot
|
||||||
|
obs_test_next_tick:
|
||||||
|
inc obsTestTicks
|
||||||
|
cmp obsTestTicks,150000
|
||||||
|
jb obs_test_tick
|
||||||
|
jmp obs_test_fail
|
||||||
|
obs_test_snapshot:
|
||||||
|
; Advance into a real deal/turn before capturing the watching surface.
|
||||||
|
mov ecx,40
|
||||||
|
obs_test_render_advance:
|
||||||
|
push ecx
|
||||||
|
mov deltaTime3D,50
|
||||||
|
call ObserverTick3D
|
||||||
|
pop ecx
|
||||||
|
loop obs_test_render_advance
|
||||||
|
call RenderObserver3D
|
||||||
|
mov eax,obsTestGame
|
||||||
|
invoke WriteActionSnapshot3D,obsTestPaths[eax*4]
|
||||||
|
mov obsPaused3D,1
|
||||||
|
mov eax,obsRound3D
|
||||||
|
push eax
|
||||||
|
mov eax,obsTimer3D
|
||||||
|
push eax
|
||||||
|
mov deltaTime3D,50
|
||||||
|
call ObserverFrame3D
|
||||||
|
pop eax
|
||||||
|
cmp eax,obsTimer3D
|
||||||
|
jne obs_test_fail
|
||||||
|
pop eax
|
||||||
|
cmp eax,obsRound3D
|
||||||
|
jne obs_test_fail
|
||||||
|
mov pressedKeys3D[9],1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsSpeed3D,2
|
||||||
|
jne obs_test_fail
|
||||||
|
mov pressedKeys3D[9],1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsSpeed3D,4
|
||||||
|
jne obs_test_fail
|
||||||
|
mov pressedKeys3D[9],1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsSpeed3D,1
|
||||||
|
jne obs_test_fail
|
||||||
|
call StopObserver3D
|
||||||
|
cmp bankroll,12345
|
||||||
|
jne obs_test_fail
|
||||||
|
cmp charmCloverUses,17
|
||||||
|
jne obs_test_fail
|
||||||
|
cmp charmDevilUses,18
|
||||||
|
jne obs_test_fail
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne obs_test_fail
|
||||||
|
inc obsTestGame
|
||||||
|
cmp obsTestGame,OBS_GAME_COUNT
|
||||||
|
jb obs_test_game
|
||||||
|
; The actual selector opens a table, and Escape unwinds watch -> menu -> hall.
|
||||||
|
mov pressedKeys3D[31h],1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsActive3D,1
|
||||||
|
jne obs_test_fail
|
||||||
|
mov pressedKeys3D[1Bh],1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp engineMode,MODE_OBSERVER
|
||||||
|
jne obs_test_fail
|
||||||
|
cmp bankroll,12345
|
||||||
|
jne obs_test_fail
|
||||||
|
mov mouseX3D,100
|
||||||
|
mov mouseY3D,174
|
||||||
|
mov mouseClick3D,1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsActive3D,1
|
||||||
|
jne obs_test_fail
|
||||||
|
cmp poolVariant3D,1
|
||||||
|
jne obs_test_fail
|
||||||
|
mov mouseX3D,20
|
||||||
|
mov mouseY3D,230
|
||||||
|
mov mouseClick3D,1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsPaused3D,1
|
||||||
|
jne obs_test_fail
|
||||||
|
mov mouseX3D,250
|
||||||
|
mov mouseClick3D,1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp obsActive3D,0
|
||||||
|
jne obs_test_fail
|
||||||
|
mov pressedKeys3D[1Bh],1
|
||||||
|
call ObserverFrame3D
|
||||||
|
cmp engineMode,MODE_WALK
|
||||||
|
jne obs_test_fail
|
||||||
|
mov obsActive3D,1
|
||||||
|
call RunDurakTest3D
|
||||||
|
test eax,eax
|
||||||
|
jnz obs_test_exit
|
||||||
|
xor eax,eax
|
||||||
|
jmp obs_test_exit
|
||||||
|
obs_test_fail:
|
||||||
|
mov eax,8401
|
||||||
|
obs_test_exit:
|
||||||
|
invoke ExitProcess,eax
|
||||||
|
ObserverTestStart ENDP
|
||||||
|
|
@ -70,27 +70,18 @@ try {
|
||||||
$cp1251 = [Text.Encoding]::GetEncoding(1251)
|
$cp1251 = [Text.Encoding]::GetEncoding(1251)
|
||||||
$asmText = $cp1251.GetString($asmBytes)
|
$asmText = $cp1251.GetString($asmBytes)
|
||||||
foreach ($needle in @(
|
foreach ($needle in @(
|
||||||
'settingsCinematicText db "Cinematic -',
|
|
||||||
'settingsAdaptiveText db "Adaptive -',
|
|
||||||
'settingsStableText db "Stable -',
|
|
||||||
'AnimShouldDrawFrame PROC',
|
|
||||||
'AnimFrameDelay PROC',
|
|
||||||
'WriteAnimProfileFile PROC',
|
|
||||||
'SAVE_SIGN_SIZE equ 276',
|
'SAVE_SIGN_SIZE equ 276',
|
||||||
'SAVE_FILE_SIZE equ 280',
|
'SAVE_FILE_SIZE equ 280',
|
||||||
'CalcSaveSignature PROC',
|
'CalcSaveSignature PROC',
|
||||||
'mov DWORD PTR [saveBuffer+SAVE_SIGN_SIZE], eax',
|
'mov DWORD PTR [saveBuffer+SAVE_SIGN_SIZE], eax',
|
||||||
'cmp charsRead, SAVE_FILE_SIZE',
|
'cmp charsRead, SAVE_FILE_SIZE',
|
||||||
'includelib ws2_32.lib',
|
'includelib ws2_32.lib'
|
||||||
'GameOnlineCasino PROC',
|
|
||||||
'OnlineRRSessionHost PROC',
|
|
||||||
'OnlineRRSessionClient PROC'
|
|
||||||
)) {
|
)) {
|
||||||
if ($asmText.IndexOf($needle) -lt 0) {
|
if ($asmText.IndexOf($needle) -lt 0) {
|
||||||
Fail "Missing source marker: $needle"
|
Fail "Missing source marker: $needle"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pass 'Animation profile and save signature markers exist in poker.asm'
|
Pass 'Save signature and library markers exist in poker.asm'
|
||||||
|
|
||||||
if ($asmText -match 'MAMBO|mambo|PlayMambo') {
|
if ($asmText -match 'MAMBO|mambo|PlayMambo') {
|
||||||
Fail 'MAMBO markers still exist in poker.asm'
|
Fail 'MAMBO markers still exist in poker.asm'
|
||||||
|
|
|
||||||