merge: integrate bowling and rebuild launchers
BIN
assets/animations/bowling/bowlers-v1.bin
Normal file
BIN
assets/animations/bowling/materials-v1.bin
Normal file
BIN
assets/animations/bowling/seated-v1.bin
Normal file
BIN
assets/animations/characters/cast-v1.bin
Normal file
BIN
assets/sprites/bowling/bowler-man-v1.png
Normal file
|
After Width: | Height: | Size: 986 KiB |
BIN
assets/sprites/bowling/bowler-woman-v1.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/sprites/bowling/bowling-preview.png
Normal file
|
After Width: | Height: | Size: 567 KiB |
BIN
assets/sprites/bowling/materials-v1.png
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
244
assets/sprites/bowling/packed-v1.json
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
{
|
||||
"materials": [
|
||||
256,
|
||||
256,
|
||||
14
|
||||
],
|
||||
"bowlers": [
|
||||
256,
|
||||
256,
|
||||
64
|
||||
],
|
||||
"seated": [
|
||||
256,
|
||||
256,
|
||||
8
|
||||
],
|
||||
"lanes": 8,
|
||||
"active_lanes": [
|
||||
0,
|
||||
3,
|
||||
6
|
||||
],
|
||||
"room": [
|
||||
30,
|
||||
30,
|
||||
6
|
||||
],
|
||||
"props": 80,
|
||||
"collisions": [
|
||||
[
|
||||
2.3800000000000003,
|
||||
5.52,
|
||||
27.48,
|
||||
28.720000000000002
|
||||
],
|
||||
[
|
||||
3.18,
|
||||
4.72,
|
||||
26.529999999999998,
|
||||
27.42
|
||||
],
|
||||
[
|
||||
3.4000000000000004,
|
||||
4.5,
|
||||
24.63,
|
||||
26.17
|
||||
],
|
||||
[
|
||||
6.18,
|
||||
9.32,
|
||||
27.48,
|
||||
28.720000000000002
|
||||
],
|
||||
[
|
||||
6.98,
|
||||
8.52,
|
||||
26.529999999999998,
|
||||
27.42
|
||||
],
|
||||
[
|
||||
7.2,
|
||||
8.3,
|
||||
24.63,
|
||||
26.17
|
||||
],
|
||||
[
|
||||
9.98,
|
||||
13.120000000000001,
|
||||
27.48,
|
||||
28.720000000000002
|
||||
],
|
||||
[
|
||||
10.780000000000001,
|
||||
12.32,
|
||||
26.529999999999998,
|
||||
27.42
|
||||
],
|
||||
[
|
||||
11.0,
|
||||
12.100000000000001,
|
||||
24.63,
|
||||
26.17
|
||||
],
|
||||
[
|
||||
13.779999999999998,
|
||||
16.919999999999998,
|
||||
27.48,
|
||||
28.720000000000002
|
||||
],
|
||||
[
|
||||
14.579999999999998,
|
||||
16.119999999999997,
|
||||
26.529999999999998,
|
||||
27.42
|
||||
],
|
||||
[
|
||||
14.799999999999997,
|
||||
15.899999999999999,
|
||||
24.63,
|
||||
26.17
|
||||
],
|
||||
[
|
||||
20.83,
|
||||
23.17,
|
||||
11.08,
|
||||
12.92
|
||||
],
|
||||
[
|
||||
20.729999999999997,
|
||||
23.270000000000003,
|
||||
12.930000000000001,
|
||||
14.17
|
||||
],
|
||||
[
|
||||
20.83,
|
||||
23.17,
|
||||
17.08,
|
||||
18.92
|
||||
],
|
||||
[
|
||||
20.729999999999997,
|
||||
23.270000000000003,
|
||||
18.93,
|
||||
20.17
|
||||
],
|
||||
[
|
||||
25.83,
|
||||
28.17,
|
||||
11.08,
|
||||
12.92
|
||||
],
|
||||
[
|
||||
25.729999999999997,
|
||||
28.270000000000003,
|
||||
12.930000000000001,
|
||||
14.17
|
||||
],
|
||||
[
|
||||
25.83,
|
||||
28.17,
|
||||
17.08,
|
||||
18.92
|
||||
],
|
||||
[
|
||||
25.729999999999997,
|
||||
28.270000000000003,
|
||||
18.93,
|
||||
20.17
|
||||
],
|
||||
[
|
||||
23.83,
|
||||
30.17,
|
||||
4.33,
|
||||
5.67
|
||||
],
|
||||
[
|
||||
23.83,
|
||||
30.17,
|
||||
0.9799999999999999,
|
||||
1.6199999999999999
|
||||
],
|
||||
[
|
||||
24.75,
|
||||
25.25,
|
||||
6.53,
|
||||
7.03
|
||||
],
|
||||
[
|
||||
26.75,
|
||||
27.25,
|
||||
6.53,
|
||||
7.03
|
||||
],
|
||||
[
|
||||
28.75,
|
||||
29.25,
|
||||
6.53,
|
||||
7.03
|
||||
],
|
||||
[
|
||||
18.93,
|
||||
19.470000000000002,
|
||||
0.83,
|
||||
24.970000000000002
|
||||
]
|
||||
],
|
||||
"seats": [
|
||||
[
|
||||
3.95,
|
||||
28.0,
|
||||
384
|
||||
],
|
||||
[
|
||||
7.75,
|
||||
28.0,
|
||||
384
|
||||
],
|
||||
[
|
||||
11.55,
|
||||
28.0,
|
||||
384
|
||||
],
|
||||
[
|
||||
15.349999999999998,
|
||||
28.0,
|
||||
384
|
||||
],
|
||||
[
|
||||
22,
|
||||
13.450000000000001,
|
||||
384
|
||||
],
|
||||
[
|
||||
22,
|
||||
19.45,
|
||||
384
|
||||
],
|
||||
[
|
||||
27,
|
||||
13.450000000000001,
|
||||
384
|
||||
],
|
||||
[
|
||||
27,
|
||||
19.45,
|
||||
384
|
||||
],
|
||||
[
|
||||
25,
|
||||
6.8,
|
||||
384
|
||||
],
|
||||
[
|
||||
27,
|
||||
6.8,
|
||||
384
|
||||
],
|
||||
[
|
||||
29,
|
||||
6.8,
|
||||
384
|
||||
]
|
||||
]
|
||||
}
|
||||
BIN
assets/sprites/bowling/seated-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
3008
assets/sprites/characters/cast-v1.json
Normal file
18
assets/sprites/characters/generation-v1.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"mode": "built-in imagegen",
|
||||
"reference": "person-00-source-v1.png (style/layout only for other identities)",
|
||||
"prompt_template": "Production 2.5D game sprite sheet, exactly 32 full-body poses of ONE IDENTICAL adult PERSON in exactly 8 columns by 4 rows. Transparent alpha background, no scenery, text, grid lines or chairs. Reference image is STYLE/LAYOUT ONLY, create the NEW character described. Photorealistic painted adventure-game sprite style, crisp realistic anatomy, natural proportions, neutral soft lighting. Full shoes and head visible in every cell, with empty margins. Same face, hairstyle, body and costume throughout. Character: DESCRIPTION. Keep one physical scale and a shared feet baseline per row; seated figures must be naturally shorter, not enlarged. Row 1 left to right: front idle; front talking gesture; front drinking a small glass; seated idle knees bent feet on floor; seated talking; seated drinking; halfway lowering to a chair (no chair); bending to pick up a blue bowling ball. Row 2: six chronological full gait-cycle frames walking TOWARD camera, then standing BACK view, then celebrating. Row 3: six chronological full gait-cycle frames walking AWAY from camera, then three-quarter rear view holding a blue bowling ball ready, then full-body bowling backswing. Row 4: six chronological full gait-cycle frames walking RIGHT in profile, then full-body low UNDERARM bowling release with an empty throwing hand (no detached ball), then bowling follow-through. Exactly 8 figures per row. All limbs connected, no duplicates or cell overlaps. Not cartoon, not pixel art.",
|
||||
"characters": [
|
||||
"32-year-old slim man, neatly combed short black hair, clean shaven, open navy blazer, ivory shirt, burgundy trousers, brown leather loafers",
|
||||
"29-year-old slim woman, auburn bob haircut, emerald trouser suit, ivory blouse, black flat loafers",
|
||||
"55-year-old stocky bald man with prominent dark moustache, burgundy waistcoat, white shirt sleeves rolled to elbows, charcoal trousers, brown leather shoes",
|
||||
"64-year-old woman, aged face, silver short wavy bob, plum cardigan, pearl-gray blouse, dark teal calf-length skirt, black comfortable flat shoes and pearl necklace",
|
||||
"40-year-old Black man, dark brown skin, short tight curls and trimmed beard, athletic medium build, gray rolled-sleeve shirt, cobalt trousers, dark leather sneakers",
|
||||
"36-year-old woman with olive skin and long dark hair in one braid, coral blouse, charcoal tailored trousers and black flat loafers",
|
||||
"25-year-old slender man with dark round glasses, wavy chestnut hair, mustard knitted sweater over a white collar, navy chinos, white sneakers",
|
||||
"45-year-old woman with short black pixie haircut, silver-gray tailored jacket over burgundy top, navy trousers, black flats",
|
||||
"68-year-old silver-haired man with short neat beard, olive blazer over a burgundy turtleneck, charcoal trousers, black loafers",
|
||||
"26-year-old woman with shoulder-length curly brown hair, cobalt-blue long-sleeve belted jumpsuit, white flat sneakers"
|
||||
],
|
||||
"note": "First five sheets used the same 32-pose layout and original equivalent character-specific briefs; full original raster sheets are retained. Whole sheets, not independently generated action frames."
|
||||
}
|
||||
BIN
assets/sprites/characters/person-00-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
assets/sprites/characters/person-00-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 577 KiB |
BIN
assets/sprites/characters/person-00-source-v1.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/sprites/characters/person-00-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 542 KiB |
BIN
assets/sprites/characters/person-00-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/sprites/characters/person-01-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 305 KiB |
BIN
assets/sprites/characters/person-01-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 627 KiB |
BIN
assets/sprites/characters/person-01-source-v1.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/sprites/characters/person-01-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 611 KiB |
BIN
assets/sprites/characters/person-01-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/person-02-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 365 KiB |
BIN
assets/sprites/characters/person-02-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 773 KiB |
BIN
assets/sprites/characters/person-02-source-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/characters/person-02-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 719 KiB |
BIN
assets/sprites/characters/person-02-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/person-03-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 344 KiB |
BIN
assets/sprites/characters/person-03-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 686 KiB |
BIN
assets/sprites/characters/person-03-source-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/characters/person-03-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 692 KiB |
BIN
assets/sprites/characters/person-03-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/person-04-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 335 KiB |
BIN
assets/sprites/characters/person-04-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 712 KiB |
BIN
assets/sprites/characters/person-04-source-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/characters/person-04-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 661 KiB |
BIN
assets/sprites/characters/person-04-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/person-05-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 302 KiB |
BIN
assets/sprites/characters/person-05-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 634 KiB |
BIN
assets/sprites/characters/person-05-source-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/characters/person-05-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 594 KiB |
BIN
assets/sprites/characters/person-05-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/sprites/characters/person-06-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 317 KiB |
BIN
assets/sprites/characters/person-06-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 654 KiB |
BIN
assets/sprites/characters/person-06-source-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/characters/person-06-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 641 KiB |
BIN
assets/sprites/characters/person-06-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/person-07-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 278 KiB |
BIN
assets/sprites/characters/person-07-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 586 KiB |
BIN
assets/sprites/characters/person-07-source-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/characters/person-07-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 578 KiB |
BIN
assets/sprites/characters/person-07-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/sprites/characters/person-08-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 316 KiB |
BIN
assets/sprites/characters/person-08-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 658 KiB |
BIN
assets/sprites/characters/person-08-source-v1.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/sprites/characters/person-08-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 627 KiB |
BIN
assets/sprites/characters/person-08-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/person-09-motion-v1.gif
Normal file
|
After Width: | Height: | Size: 331 KiB |
BIN
assets/sprites/characters/person-09-normalized-v1.png
Normal file
|
After Width: | Height: | Size: 729 KiB |
BIN
assets/sprites/characters/person-09-source-v1.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
assets/sprites/characters/person-09-walk-normalized-v2.png
Normal file
|
After Width: | Height: | Size: 679 KiB |
BIN
assets/sprites/characters/person-09-walk-source-v2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/sprites/characters/roster-v1.png
Normal file
|
After Width: | Height: | Size: 221 KiB |
76
assets/sprites/characters/walking-generation-v2.json
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"mode": "built-in imagegen",
|
||||
"prompt": "Create production walking sprites of the EXACT referenced bald moustached stocky man (burgundy vest, white rolled sleeves, charcoal pants, brown shoes). Replace the broken same-leg poses with a real walk. TRANSPARENT background, 3 rows x 4 columns, 12 full body cutouts. ROW1 FRONT view. ROW2 REAR view. ROW3 RIGHT-facing SIDE view. COLUMN1: wide stride contact, LEFT leg forward, RIGHT leg back. COLUMN2: narrow PASSING pose, feet nearly together under hips, RIGHT KNEE lifted/bent to step through. COLUMN3: wide stride contact, RIGHT leg forward, LEFT leg back, counter-swing opposite arm. COLUMN4: narrow PASSING pose, LEFT KNEE lifted/bent stepping through. This is a chronological animation cycle: wide, narrow, wide opposite, narrow opposite. Especially in side row columns2 and4 MUST have legs CLOSE TOGETHER under the hips, NOT another wide stride. Preserve this man's recognizable identity and clothing, fixed head size, entire head and shoes visible, aligned floor in each row. No idle/talk/ball poses, no panels, no text. 1536x1024 canvas.",
|
||||
"characters": [
|
||||
{
|
||||
"id": 0,
|
||||
"description": "slim black-haired man navy blazer ivory shirt burgundy trousers brown loafers",
|
||||
"source": "person-00-source-v1.png",
|
||||
"output": "person-00-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-b25bc01c-dc99-4912-b299-5b5718f9716a.png"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"description": "auburn bob-haired woman emerald trouser suit ivory blouse black flats",
|
||||
"source": "person-01-source-v1.png",
|
||||
"output": "person-01-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-43e73f66-1c2d-4c65-aad4-c51e8d905e24.png"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"description": "older stocky bald moustached man burgundy waistcoat white rolled-sleeve shirt charcoal trousers brown shoes",
|
||||
"source": "person-02-source-v1.png",
|
||||
"output": "person-02-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-19b83697-2a18-4cc9-a8a3-b3e8a1b0251b.png"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"description": "silver bob-haired older woman plum cardigan teal knee-length skirt pearl necklace black flats",
|
||||
"source": "person-03-source-v1.png",
|
||||
"output": "person-03-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-35140d2f-0648-4075-a44c-18e736db4df5.png"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"description": "dark-skinned bearded man gray rolled-sleeve shirt cobalt trousers dark sneakers",
|
||||
"source": "person-04-source-v1.png",
|
||||
"output": "person-04-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-8f98702f-5ee4-492d-8fad-153b3b854507.png"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"description": "dark-braided woman coral blouse charcoal trousers black loafers",
|
||||
"source": "person-05-source-v1.png",
|
||||
"output": "person-05-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-89ab73fb-b907-4d67-af08-4f2c99617719.png"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"description": "young wavy-haired man glasses mustard sweater navy chinos white sneakers",
|
||||
"source": "person-06-source-v1.png",
|
||||
"output": "person-06-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-037ccc00-51c1-4b3b-9802-47d6cf38cf3f.png"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"description": "black pixie-haired woman gray jacket burgundy top navy trousers black flats",
|
||||
"source": "person-07-source-v1.png",
|
||||
"output": "person-07-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-3d667111-3659-4d90-83ba-3e3788c5dad3.png"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"description": "silver-haired bearded man olive blazer burgundy turtleneck charcoal trousers dark shoes",
|
||||
"source": "person-08-source-v1.png",
|
||||
"output": "person-08-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-a6c66cea-f171-4d99-a7b3-fd957fabcaaa.png"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"description": "curly-haired woman cobalt belted jumpsuit white sneakers",
|
||||
"source": "person-09-source-v1.png",
|
||||
"output": "person-09-walk-source-v2.png",
|
||||
"generated": "C:\\Users\\user\\.codex\\generated_images\\019e0a0d-b269-7211-8574-91b6289060a2\\exec-feafc4a0-9339-457f-b4f7-18aacd013ad5.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
bin/poker.exe
|
|
@ -8,7 +8,7 @@ namespace AssemblerCasinoLauncher
|
|||
{
|
||||
static class Program
|
||||
{
|
||||
const string ExpectedPokerSha256 = "25A3ED73CF72140CEE3DB0637E857191F6885C2BC5C9A0D0D2835CAE5F134CEB";
|
||||
const string ExpectedPokerSha256 = "755067F511E82184081FE3D06391FCF872EC058AB224CA6ED8C1DB0A2990E1BA";
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
|
|
|
|||
|
|
@ -5353,6 +5353,8 @@ check_walk_mode:
|
|||
; The roof owns all planes/depth; an indoor prepass would be discarded.
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
je walk_world_ready
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
je walk_world_ready
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
|
|
|
|||
BIN
dist/Assembler Casino.exe
vendored
63
docs/BOWLING.md
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Bowling Lounge
|
||||
|
||||
The bowling lounge is a walkable room, not a player-controlled bowling minigame.
|
||||
Enter through the wide opening in the north wall of the main casino, near the
|
||||
slot-machine side of the hall. Walk through to enter or leave; no interaction
|
||||
button or timed stair/elevator animation is used.
|
||||
|
||||
## Room
|
||||
|
||||
- Eight lanes with wooden approaches, gutters, ten pins and overhead displays.
|
||||
- Three occupied lanes and five free lanes.
|
||||
- Paired sofas, ball returns, dining booths, a staffed bar and circulating guests.
|
||||
- All ten visitors use the shared character cast, including seated, drinking,
|
||||
walking, pick-up, throwing and return animations. See `SHARED_CHARACTERS.md`.
|
||||
- E sits on an available lounge seat or gets up. W/S also gets up.
|
||||
- The bar uses the existing drink purchase flow and restores the room camera.
|
||||
|
||||
All room geometry, rendering, input, scoring and visitor simulation run in MASM.
|
||||
Furniture is built from fixed world-space surfaces, not rotating room billboards.
|
||||
Human sprites retain the game's existing 2.5D presentation.
|
||||
|
||||
## Simulation
|
||||
|
||||
Each occupied lane owns a timer, rack mask, two players, frame counters and roll
|
||||
history. The sequence is pick-up, approach/release, ball travel, pin impact,
|
||||
pinsetter sweep, return and a pause before the next attempt/player.
|
||||
Scoreboards use native ten-frame bowling scoring, including strike/spare bonuses
|
||||
and tenth-frame bonus balls. These exhibition games do not change the bankroll.
|
||||
|
||||
The room owns its random state; visitor games do not consume the casino RNG.
|
||||
Simulation pauses when the player is in an unrelated room. Artwork is loaded on
|
||||
the first visible entrance/visit, retained for subsequent visits and freed with
|
||||
the other hall assets. No city mesh or rooftop OpenGL pass is used here.
|
||||
|
||||
## Sources And Rebuild
|
||||
|
||||
- `src_graphics/bowling*.inc`: native room and lane simulation.
|
||||
- `tools/generators/pack_bowling.py`: offline atlas packing, frame normalization,
|
||||
in-between frames and furniture/collision tables.
|
||||
- `assets/sprites/bowling/`: retained image-generation sources.
|
||||
- `assets/animations/bowling/`: packed shipping assets.
|
||||
|
||||
Image-generation source briefs: twelve bowling-room material swatches (maple,
|
||||
teal/coral textile, acoustic panels, mural, marble, metal and ball-return front);
|
||||
a whole-body male approach/underarm-release/pick-up sequence; the corresponding
|
||||
female bowler sequence; four distinct seated adult visitors in idle and
|
||||
conversation/drinking poses. The edited female sheet preserves transparency.
|
||||
These are original generated assets, not extracted FNAF artwork.
|
||||
|
||||
Run the offline packer with Python, then build the MASM executable normally.
|
||||
|
||||
## Checks
|
||||
|
||||
`tools/tests/check_hall_expansion.py --bowling-only` compiles fresh assembly and
|
||||
checks entrance visibility, walkable access, both room transitions, lane/furniture
|
||||
collision, sitting/restoration, 600 simulated seconds of lane lifecycles, perfect
|
||||
game/all-spare/open-frame score vectors, and captures room/throw screenshots.
|
||||
The complete hall suite includes the same bowling checks alongside existing
|
||||
stairs, doors, rooftop, fortune-room, bar and cabaret regressions. `--parity`
|
||||
compares the tested procedures with the shipping assembly object.
|
||||
|
||||
Screenshots are native framebuffer captures, not a substitute for final manual
|
||||
playtesting on the target laptop.
|
||||
77
docs/SHARED_CHARACTERS.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Shared Visitor Cast
|
||||
|
||||
Ten generated adult visitors now share one identity-locked animation system in
|
||||
the main casino, upper lounge, rooftop and bowling room. Dealers, bartenders and
|
||||
stage performers remain separate job-specific characters.
|
||||
|
||||
## Identity And Animation
|
||||
|
||||
Each identity owns a fixed block of 100 slots in `cast-v1.bin`. Changing an action
|
||||
never selects a different character block. The renderer chooses front, back,
|
||||
left or right gait from actual movement relative to the camera. Walk frames are
|
||||
distance-driven and stop when movement stops.
|
||||
|
||||
The block contains idle, conversation, drinking, seated idle/conversation/drinking,
|
||||
four gait directions, sitting down, standing up (reverse of sitting), picking up
|
||||
a ball, underarm throw/follow-through and celebration. Idle slots deliberately
|
||||
hold a stable pose. Optical-flow in-betweens are generated offline, not by the
|
||||
game. These remain 2.5D sprites, not skeletal 3D humans.
|
||||
|
||||
All states use the same physical canvas, scale and foot anchor. Seated sprites
|
||||
are shorter poses on that canvas, not separately enlarged portraits. A walking
|
||||
casino visitor pauses movement while standing up from a chair.
|
||||
|
||||
The canvas height is 1.3 world units (192:224 aspect), calibrated against the
|
||||
hall's 1.05-unit standing eye height. The former 1.95-unit canvas made visitors
|
||||
oversized compared with the camera, staff and furniture.
|
||||
|
||||
Walking uses replacement `person-*-walk-source-v2.png` sheets with contact and
|
||||
passing poses in front, rear and right profile. The left profile is mirrored.
|
||||
Each sheet has a common scale and ground anchor. The generator records these
|
||||
crops in the cast manifest; `walking-generation-v2.json` records built-in image
|
||||
generation provenance. Non-walking actions retain their original source art.
|
||||
|
||||
Bowling uses three occupied lanes with six persistent players. Four other
|
||||
identities occupy the restaurant/bar, giving ten distinct visitors without
|
||||
duplicating an active bowler as a seated stranger. Players walk to the ball,
|
||||
pick it up, throw, return, sit and alternate turns while keeping their identity.
|
||||
|
||||
The historical twelve-slot NPC journal is preserved for save compatibility;
|
||||
its appearance mapping resolves to the ten shared visual identities.
|
||||
|
||||
## Assets
|
||||
|
||||
- `assets/sprites/characters/person-00-source-v1.png` through `person-09-source-v1.png`:
|
||||
original full sheets generated with built-in imagegen.
|
||||
- `assets/sprites/characters/generation-v1.json`: generation brief and identities.
|
||||
- `assets/sprites/characters/cast-v1.json`: action offsets, source crops and scale.
|
||||
- `assets/sprites/characters/roster-v1.png`: normalized cast preview.
|
||||
- `assets/sprites/characters/person-*-motion-v1.gif`: motion review previews.
|
||||
- `assets/animations/characters/cast-v1.bin`: native ANM1 shipping pack.
|
||||
|
||||
`tools/generators/pack_character_cast.py` rebuilds the pack from retained project
|
||||
sources. It isolates silhouettes with alpha, handles extra generated walking
|
||||
poses, normalizes each identity once and creates intermediate frames.
|
||||
|
||||
The raw pack uses about 164 MiB of process RAM and is loaded once, shared by all
|
||||
locations, then released with the hall. It is CPU sprite data, not a separate
|
||||
texture allocation per location. The ordinary animation-loader limits remain
|
||||
unchanged; only this exact cast pointer, dimensions, count, payload and file size
|
||||
can use the larger pack. No Python, neural model or network is used at runtime.
|
||||
|
||||
## Verification
|
||||
|
||||
`tools/tests/character_cast_test.inc` executes the native state resolver for all
|
||||
ten identities and twelve states, checks identity boundaries and stable scale,
|
||||
and captures sixty native poses plus eighty native walking frames.
|
||||
`tools/tests/check_character_cast.py` checks
|
||||
distinct identities, four animated gait directions, mirrored profile frames,
|
||||
seated proportions, transparent borders, unclipped feet and throw progression.
|
||||
It also checks native eye-level body scale and a substantial difference between
|
||||
wide contact and narrow passing foot spans. Distinct pixel hashes alone did not
|
||||
catch the old sheets' repeated leading-leg poses.
|
||||
The full hall regression includes room navigation, roof, bars, doors and stairs.
|
||||
Shipping/tested assembly parity is checked separately.
|
||||
|
||||
The older guest and bowling source packs are retained as historical assets;
|
||||
the visitor renderers no longer load or use them.
|
||||
BIN
poker.exe
254
src_graphics/bowling.inc
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
; Native room, automatic lane simulation and full-body visitors; no AI service.
|
||||
InitBowling3D PROC uses esi edi
|
||||
mov bwClock3D,-1
|
||||
mov bwMonitorClock3D,-1
|
||||
mov bwSeat3D,0
|
||||
xor esi,esi
|
||||
bw_init_lane:
|
||||
mov bwState3D[esi*4],0
|
||||
imul eax,esi,349
|
||||
mov bwTime3D[esi*4],eax
|
||||
mov bwTurn3D[esi*4],0
|
||||
mov bwBall3D[esi*4],0
|
||||
mov bwRack3D[esi*4],1023
|
||||
mov bwHit3D[esi*4],0
|
||||
mov bwNewRack3D[esi*4],0
|
||||
mov bwFrameDone3D[esi*4],0
|
||||
inc esi
|
||||
cmp esi,BW_LANES
|
||||
jb bw_init_lane
|
||||
lea edi,bwFrames3D
|
||||
xor eax,eax
|
||||
mov ecx,16
|
||||
rep stosd
|
||||
lea edi,bwRollCount3D
|
||||
mov ecx,16
|
||||
rep stosd
|
||||
lea edi,bwScores3D
|
||||
mov ecx,16
|
||||
rep stosd
|
||||
ret
|
||||
InitBowling3D ENDP
|
||||
|
||||
LoadBowling3D PROC
|
||||
cmp bwArt3D.pixels,0
|
||||
jne bw_load_done
|
||||
invoke LoadAnimPack3D,OFFSET bwArt3D,OFFSET bwArtPath3D
|
||||
invoke ValidateCityPack3D,OFFSET bwArt3D,256,256,14
|
||||
call LoadCharacterCast3D
|
||||
call RefreshBowlingMonitors3D
|
||||
bw_load_done:
|
||||
ret
|
||||
LoadBowling3D ENDP
|
||||
|
||||
FreeBowling3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET bwArt3D
|
||||
invoke FreeAnimPack3D,OFFSET bwMotionArt3D
|
||||
invoke FreeAnimPack3D,OFFSET bwSeatedArt3D
|
||||
ret
|
||||
FreeBowling3D ENDP
|
||||
|
||||
ResolveBowlingSurface3D PROC material:DWORD
|
||||
mov eax,material
|
||||
cmp eax,252
|
||||
jne @F
|
||||
mov eax,OFFSET bwSignPixels3D
|
||||
mov ecx,128
|
||||
mov edx,16
|
||||
ret
|
||||
@@:
|
||||
cmp eax,244
|
||||
jb bw_material_atlas
|
||||
sub eax,244
|
||||
cmp eax,7
|
||||
ja bw_material_missing
|
||||
shl eax,15
|
||||
add eax,OFFSET bwMonitors3D
|
||||
mov ecx,128
|
||||
mov edx,64
|
||||
ret
|
||||
bw_material_atlas:
|
||||
sub eax,BW_MATERIAL
|
||||
cmp eax,13
|
||||
ja bw_material_missing
|
||||
cmp bwArt3D.pixels,0
|
||||
je bw_material_missing
|
||||
shl eax,18
|
||||
add eax,bwArt3D.pixels
|
||||
mov ecx,256
|
||||
mov edx,256
|
||||
ret
|
||||
bw_material_missing:
|
||||
xor eax,eax
|
||||
ret
|
||||
ResolveBowlingSurface3D ENDP
|
||||
|
||||
BowlingTravel3D PROC
|
||||
cmp engineMode,MODE_WALK
|
||||
jne bw_travel_done
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
je bw_travel_out
|
||||
cmp hallLevel3D,0
|
||||
jne bw_travel_done
|
||||
cmp playerX,3*FP_1
|
||||
jb bw_travel_done
|
||||
cmp playerX,7*FP_1
|
||||
ja bw_travel_done
|
||||
cmp playerY,FP_1*15/10
|
||||
jae bw_travel_done
|
||||
add playerX,12*FP_1
|
||||
add playerY,29*FP_1
|
||||
mov hallLevel3D,HALL_BOWLING
|
||||
mov worldMap3D,OFFSET bwMap3D
|
||||
mov floorTexture3D,231
|
||||
call LoadBowling3D
|
||||
call BowlingEye3D
|
||||
ret
|
||||
bw_travel_out:
|
||||
cmp playerY,FP_1*305/10
|
||||
jbe bw_travel_done
|
||||
cmp playerX,15*FP_1
|
||||
jb bw_travel_done
|
||||
cmp playerX,19*FP_1
|
||||
ja bw_travel_done
|
||||
sub playerX,12*FP_1
|
||||
sub playerY,29*FP_1
|
||||
mov hallLevel3D,0
|
||||
mov worldMap3D,OFFSET casinoMap
|
||||
mov floorTexture3D,100
|
||||
mov bwSeat3D,0
|
||||
mov viewCeiling3D,FP_1*5/2
|
||||
mov viewEye3D,HALL_STANDING_EYE
|
||||
bw_travel_done:
|
||||
ret
|
||||
BowlingTravel3D ENDP
|
||||
|
||||
BowlingEye3D PROC
|
||||
mov viewHorizon3D,HALF_H
|
||||
mov viewCeiling3D,6*FP_1
|
||||
mov viewEye3D,HALL_STANDING_EYE
|
||||
cmp bwSeat3D,0
|
||||
je @F
|
||||
mov viewEye3D,FP_1*12/10
|
||||
@@:
|
||||
ret
|
||||
BowlingEye3D ENDP
|
||||
|
||||
BowlingCanWalk3D PROC uses esi edi px:DWORD,py:DWORD
|
||||
cmp bwSeat3D,0
|
||||
jne bw_walk_block
|
||||
cmp px,FP_1*12/10
|
||||
jb bw_walk_block
|
||||
cmp px,FP_1*308/10
|
||||
ja bw_walk_block
|
||||
cmp py,FP_1*12/10
|
||||
jb bw_walk_block
|
||||
cmp py,FP_1*308/10
|
||||
ja bw_walk_block
|
||||
cmp px,19*FP_1
|
||||
jae bw_walk_furniture
|
||||
cmp px,2*FP_1
|
||||
jb bw_walk_furniture
|
||||
cmp px,FP_1*173/10
|
||||
ja bw_walk_furniture
|
||||
cmp py,FP_1*223/10
|
||||
jb bw_walk_block
|
||||
bw_walk_furniture:
|
||||
lea esi,bwCollision3D
|
||||
mov edi,BOWL_COLLISION_COUNT
|
||||
bw_walk_prop:
|
||||
mov eax,px
|
||||
cmp eax,[esi]
|
||||
jb bw_walk_next
|
||||
cmp eax,[esi+4]
|
||||
ja bw_walk_next
|
||||
mov eax,py
|
||||
cmp eax,[esi+8]
|
||||
jb bw_walk_next
|
||||
cmp eax,[esi+12]
|
||||
jbe bw_walk_block
|
||||
bw_walk_next:
|
||||
add esi,16
|
||||
dec edi
|
||||
jnz bw_walk_prop
|
||||
mov eax,1
|
||||
ret
|
||||
bw_walk_block:
|
||||
xor eax,eax
|
||||
ret
|
||||
BowlingCanWalk3D ENDP
|
||||
|
||||
CheckBowlingInteractions3D PROC uses esi edi
|
||||
cmp bwSeat3D,0
|
||||
je bw_check_seats
|
||||
mov interactTargetId,INTERACT_BOWL_SEAT
|
||||
mov interactPromptPtr,OFFSET bwStandPrompt3D
|
||||
ret
|
||||
bw_check_seats:
|
||||
lea esi,bwSeats3D
|
||||
xor edi,edi
|
||||
bw_check_seat:
|
||||
cmp edi,4
|
||||
jb bw_check_available_seat
|
||||
cmp edi,9
|
||||
jne bw_check_next_seat
|
||||
bw_check_available_seat:
|
||||
mov interactTargetId,0
|
||||
invoke HallTarget3D,[esi],[esi+4],INTERACT_BOWL_SEAT,OFFSET bwSeatPrompt3D
|
||||
cmp interactTargetId,INTERACT_BOWL_SEAT
|
||||
jne @F
|
||||
mov bwSeatTarget3D,edi
|
||||
ret
|
||||
@@:
|
||||
bw_check_next_seat:
|
||||
add esi,12
|
||||
inc edi
|
||||
cmp edi,BOWL_SEAT_COUNT
|
||||
jb bw_check_seat
|
||||
invoke HallTarget3D,27*FP_1,FP_1*59/10,INTERACT_BAR,OFFSET bwBarName3D
|
||||
ret
|
||||
CheckBowlingInteractions3D ENDP
|
||||
|
||||
TryBowlingInteraction3D PROC uses esi
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne bw_try_none
|
||||
cmp interactTargetId,INTERACT_BOWL_SEAT
|
||||
jne bw_try_none
|
||||
cmp bwSeat3D,0
|
||||
jne bw_try_stand
|
||||
mov eax,playerX
|
||||
mov bwReturnX3D,eax
|
||||
mov eax,playerY
|
||||
mov bwReturnY3D,eax
|
||||
mov eax,playerAngle
|
||||
mov bwReturnAngle3D,eax
|
||||
mov esi,bwSeatTarget3D
|
||||
imul esi,12
|
||||
mov eax,bwSeats3D[esi]
|
||||
mov playerX,eax
|
||||
mov eax,bwSeats3D[esi+4]
|
||||
mov playerY,eax
|
||||
mov eax,bwSeats3D[esi+8]
|
||||
mov playerAngle,eax
|
||||
mov bwSeat3D,1
|
||||
jmp bw_try_handled
|
||||
bw_try_stand:
|
||||
mov eax,bwReturnX3D
|
||||
mov playerX,eax
|
||||
mov eax,bwReturnY3D
|
||||
mov playerY,eax
|
||||
mov eax,bwReturnAngle3D
|
||||
mov playerAngle,eax
|
||||
mov bwSeat3D,0
|
||||
bw_try_handled:
|
||||
call BowlingEye3D
|
||||
call ClearKeys3D
|
||||
mov eax,1
|
||||
ret
|
||||
bw_try_none:
|
||||
xor eax,eax
|
||||
ret
|
||||
TryBowlingInteraction3D ENDP
|
||||
|
||||
include src_graphics\bowling_simulation.inc
|
||||
include src_graphics\bowling_render.inc
|
||||
98
src_graphics/bowling_data.inc
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
HALL_BOWLING equ 5
|
||||
INTERACT_BOWL_SEAT equ 53
|
||||
INTERACT_BOWL_WATCH equ 54
|
||||
BW_MATERIAL equ 230
|
||||
BW_LAST_MATERIAL equ 252
|
||||
BW_LANES equ 8
|
||||
BW_LANE_STEP equ FP_1*19/10
|
||||
InitBowling3D PROTO
|
||||
LoadBowling3D PROTO
|
||||
FreeBowling3D PROTO
|
||||
ResolveBowlingSurface3D PROTO :DWORD
|
||||
UpdateBowling3D PROTO
|
||||
BowlingTravel3D PROTO
|
||||
BowlingEye3D PROTO
|
||||
BowlingCanWalk3D PROTO :DWORD,:DWORD
|
||||
CheckBowlingInteractions3D PROTO
|
||||
TryBowlingInteraction3D PROTO
|
||||
RenderBowling3D PROTO
|
||||
RenderBowlingEntrance3D PROTO
|
||||
RenderBowlingPlanes3D PROTO
|
||||
RenderBowlingLanes3D PROTO
|
||||
RenderBowlingVisitors3D PROTO
|
||||
DrawBowlingPin3D PROTO :DWORD,:DWORD,:DWORD
|
||||
DrawBowlingBall3D PROTO :DWORD,:DWORD,:DWORD
|
||||
BowlingImpact3D PROTO :DWORD
|
||||
BowlingRegisterRoll3D PROTO :DWORD,:DWORD
|
||||
BowlingScore3D PROTO :DWORD
|
||||
BowlingMonitorText3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
RefreshBowlingMonitors3D PROTO
|
||||
.data
|
||||
bwArt3D AnimPack3D <>
|
||||
bwMotionArt3D AnimPack3D <>
|
||||
bwSeatedArt3D AnimPack3D <>
|
||||
bwArtPath3D db "assets\animations\bowling\materials-v1.bin",0
|
||||
bwMotionPath3D db "assets\animations\bowling\bowlers-v1.bin",0
|
||||
bwSeatedPath3D db "assets\animations\bowling\seated-v1.bin",0
|
||||
bwEntrancePrompt3D db 193,206,211,203,200,205,195,0
|
||||
bwExitPrompt3D db 202,192,199,200,205,206,0
|
||||
bwSeatPrompt3D db 207,208,200,209,197,209,210,220,0
|
||||
bwStandPrompt3D db 194,209,210,192,210,220,0
|
||||
bwWatchPrompt3D db 205,192,193,203,222,196,192,210,220,32,199,192,32,200,195,208,206,201,0
|
||||
bwBarName3D db 193,192,208,32,193,206,211,203,200,205,195,192,0
|
||||
bwLaneWord3D db "LANE ",0
|
||||
bwPlayerA3D db "A",0
|
||||
bwPlayerB3D db "B",0
|
||||
bwFreeText3D db "FREE",0
|
||||
bwFrameText3D db "FRAME",0
|
||||
bwPhaseTexts3D dd OFFSET bwRestText3D,OFFSET bwPickText3D,OFFSET bwThrowText3D
|
||||
dd OFFSET bwRollText3D,OFFSET bwSweepText3D,OFFSET bwReturnText3D,OFFSET bwRestText3D
|
||||
bwRestText3D db "NEXT PLAYER",0
|
||||
bwPickText3D db "READY",0
|
||||
bwThrowText3D db "APPROACH",0
|
||||
bwRollText3D db "BALL IN PLAY",0
|
||||
bwSweepText3D db "PINSETTER",0
|
||||
bwReturnText3D db "BALL RETURN",0
|
||||
bwSignText3D db "BOWLING",0
|
||||
bwLoungeText3D db "LOUNGE",0
|
||||
bwEightText3D db "8 LANES",0
|
||||
bwClock3D dd -1
|
||||
bwMonitorClock3D dd -1
|
||||
bwRng3D dd 312871
|
||||
bwSeat3D dd 0
|
||||
bwSeatTarget3D dd 0
|
||||
bwWatchLane3D dd 0
|
||||
bwReturnX3D dd 0
|
||||
bwReturnY3D dd 0
|
||||
bwReturnAngle3D dd 0
|
||||
bwBusy3D dd 1,0,0,1,0,0,1,0
|
||||
bwCharacterIds3D dd 0,1,6,7,8,9,2,3,6,7,8,9,4,5,6,7
|
||||
bwState3D dd BW_LANES dup(0)
|
||||
bwTime3D dd BW_LANES dup(0)
|
||||
bwTurn3D dd BW_LANES dup(0)
|
||||
bwBall3D dd BW_LANES dup(0)
|
||||
bwFirstHit3D dd BW_LANES dup(0)
|
||||
bwRack3D dd BW_LANES dup(1023)
|
||||
bwHit3D dd BW_LANES dup(0)
|
||||
bwAim3D dd BW_LANES dup(0)
|
||||
bwNewRack3D dd BW_LANES dup(0)
|
||||
bwFrameDone3D dd BW_LANES dup(0)
|
||||
bwFrames3D dd 16 dup(0)
|
||||
bwRollCount3D dd 16 dup(0)
|
||||
bwScores3D dd 16 dup(0)
|
||||
bwRolls3D dd 16*24 dup(0)
|
||||
bwPinX3D dd 0,-FP_1*16/100,FP_1*16/100,-FP_1*32/100,0,FP_1*32/100
|
||||
dd -FP_1*48/100,-FP_1*16/100,FP_1*16/100,FP_1*48/100
|
||||
bwPinY3D dd FP_1*47/10,FP_1*44/10,FP_1*44/10
|
||||
dd FP_1*41/10,FP_1*41/10,FP_1*41/10
|
||||
dd FP_1*38/10,FP_1*38/10,FP_1*38/10,FP_1*38/10
|
||||
bwVisitorX3D dd 22*FP_1,27*FP_1,25*FP_1,29*FP_1,25*FP_1,27*FP_1,29*FP_1
|
||||
bwVisitorY3D dd FP_1*134/10,FP_1*194/10,FP_1*68/10,FP_1*68/10
|
||||
dd FP_1*68/10,FP_1*68/10,FP_1*68/10
|
||||
bwActor3D CityProp3D <0,0,FP_1*19/10,FP_1*19/10,0,OFFSET bwMotionArt3D>
|
||||
bwSmallActor3D CityProp3D <0,0,FP_1*135/100,FP_1*135/100,0,OFFSET bwSeatedArt3D>
|
||||
.data?
|
||||
bwMonitors3D dd BW_LANES*128*64 dup(?)
|
||||
bwSignPixels3D dd 128*64 dup(?)
|
||||
.code
|
||||
include src_graphics\bowling_layout.inc
|
||||
159
src_graphics/bowling_layout.inc
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
; Generated by pack_bowling.py.
|
||||
BOWL_PROP_COUNT equ 80
|
||||
.data
|
||||
bwProps3D LABEL DWORD
|
||||
dd 167117,350618,1812070,1871053,5243,19661,236
|
||||
dd 173670,344064,1813381,1865155,19661,26214,235
|
||||
dd 167117,350618,1861222,1875640,19661,55706,235
|
||||
dd 167117,177603,1812070,1871053,19661,36700,240
|
||||
dd 340132,350618,1812070,1871053,19661,36700,240
|
||||
dd 219546,298189,1749811,1785856,24904,30147,237
|
||||
dd 251003,266732,1759642,1772749,0,26214,238
|
||||
dd 233964,283771,1625293,1703936,3277,40632,236
|
||||
dd 237240,280494,1628570,1690829,40632,47186,238
|
||||
dd 416154,599654,1812070,1871053,5243,19661,236
|
||||
dd 422707,593101,1813381,1865155,19661,26214,235
|
||||
dd 416154,599654,1861222,1875640,19661,55706,235
|
||||
dd 416154,426639,1812070,1871053,19661,36700,240
|
||||
dd 589169,599654,1812070,1871053,19661,36700,240
|
||||
dd 468582,547226,1749811,1785856,24904,30147,237
|
||||
dd 500040,515768,1759642,1772749,0,26214,238
|
||||
dd 483000,532808,1625293,1703936,3277,40632,236
|
||||
dd 486277,529531,1628570,1690829,40632,47186,238
|
||||
dd 665190,848691,1812070,1871053,5243,19661,236
|
||||
dd 671744,842138,1813381,1865155,19661,26214,235
|
||||
dd 665190,848691,1861222,1875640,19661,55706,235
|
||||
dd 665190,675676,1812070,1871053,19661,36700,240
|
||||
dd 838205,848691,1812070,1871053,19661,36700,240
|
||||
dd 717619,796262,1749811,1785856,24904,30147,237
|
||||
dd 749076,764805,1759642,1772749,0,26214,238
|
||||
dd 732037,781844,1625293,1703936,3277,40632,236
|
||||
dd 735314,778568,1628570,1690829,40632,47186,238
|
||||
dd 914227,1097728,1812070,1871053,5243,19661,236
|
||||
dd 920781,1091174,1813381,1865155,19661,26214,235
|
||||
dd 914227,1097728,1861222,1875640,19661,55706,235
|
||||
dd 914227,924713,1812070,1871053,19661,36700,240
|
||||
dd 1087242,1097728,1812070,1871053,19661,36700,240
|
||||
dd 966656,1045299,1749811,1785856,24904,30147,237
|
||||
dd 998113,1013842,1759642,1772749,0,26214,238
|
||||
dd 981074,1030881,1625293,1703936,3277,40632,236
|
||||
dd 984351,1027604,1628570,1690829,40632,47186,238
|
||||
dd 1376256,1507328,737280,835584,31457,36045,237
|
||||
dd 1435238,1448346,779878,792986,0,32113,238
|
||||
dd 1369702,1513882,858522,917504,5243,19661,236
|
||||
dd 1376256,1507328,859832,911606,19661,26214,235
|
||||
dd 1369702,1513882,907674,922092,19661,55706,235
|
||||
dd 1369702,1380188,858522,917504,19661,36700,240
|
||||
dd 1503396,1513882,858522,917504,19661,36700,240
|
||||
dd 1376256,1507328,1130496,1228800,31457,36045,237
|
||||
dd 1435238,1448346,1173094,1186202,0,32113,238
|
||||
dd 1369702,1513882,1251738,1310720,5243,19661,236
|
||||
dd 1376256,1507328,1253048,1304822,19661,26214,235
|
||||
dd 1369702,1513882,1300890,1315308,19661,55706,235
|
||||
dd 1369702,1380188,1251738,1310720,19661,36700,240
|
||||
dd 1503396,1513882,1251738,1310720,19661,36700,240
|
||||
dd 1703936,1835008,737280,835584,31457,36045,237
|
||||
dd 1762918,1776026,779878,792986,0,32113,238
|
||||
dd 1697382,1841562,858522,917504,5243,19661,236
|
||||
dd 1703936,1835008,859832,911606,19661,26214,235
|
||||
dd 1697382,1841562,907674,922092,19661,55706,235
|
||||
dd 1697382,1707868,858522,917504,19661,36700,240
|
||||
dd 1831076,1841562,858522,917504,19661,36700,240
|
||||
dd 1703936,1835008,1130496,1228800,31457,36045,237
|
||||
dd 1762918,1776026,1173094,1186202,0,32113,238
|
||||
dd 1697382,1841562,1251738,1310720,5243,19661,236
|
||||
dd 1703936,1835008,1253048,1304822,19661,26214,235
|
||||
dd 1697382,1841562,1300890,1315308,19661,55706,235
|
||||
dd 1697382,1707868,1251738,1310720,19661,36700,240
|
||||
dd 1831076,1841562,1251738,1310720,19661,36700,240
|
||||
dd 1572864,1966080,294912,360448,0,68813,236
|
||||
dd 1566310,1972634,288358,367002,68813,76022,237
|
||||
dd 1572864,1966080,75366,95027,0,203162,236
|
||||
dd 1572864,1966080,75366,117965,58982,64225,238
|
||||
dd 1572864,1966080,75366,117965,111411,116654,238
|
||||
dd 1572864,1966080,75366,117965,163840,169083,238
|
||||
dd 1633157,1643643,439091,449577,0,52429,238
|
||||
dd 1618739,1658061,425984,465306,52429,58982,240
|
||||
dd 1764229,1774715,439091,449577,0,52429,238
|
||||
dd 1749811,1789133,425984,465306,52429,58982,240
|
||||
dd 1895301,1905787,439091,449577,0,52429,238
|
||||
dd 1880883,1920205,425984,465306,52429,58982,240
|
||||
dd 1251738,1264845,65536,1625293,0,58982,236
|
||||
dd 1248461,1268122,65536,1625293,58982,65536,238
|
||||
dd 75366,114688,131072,176947,0,183501,233
|
||||
dd 1192755,1232077,131072,176947,0,183501,233
|
||||
BOWL_COLLISION_COUNT equ 26
|
||||
bwCollision3D LABEL DWORD
|
||||
dd 155976,361759,1800929,1882194
|
||||
dd 208404,309330,1738670,1796997
|
||||
dd 222822,294912,1614152,1715077
|
||||
dd 405012,610796,1800929,1882194
|
||||
dd 457441,558367,1738670,1796997
|
||||
dd 471859,543949,1614152,1715077
|
||||
dd 654049,859832,1800929,1882194
|
||||
dd 706478,807404,1738670,1796997
|
||||
dd 720896,792986,1614152,1715077
|
||||
dd 903086,1108869,1800929,1882194
|
||||
dd 955515,1056440,1738670,1796997
|
||||
dd 969933,1042022,1614152,1715077
|
||||
dd 1365115,1518469,726139,846725
|
||||
dd 1358561,1525023,847380,928645
|
||||
dd 1365115,1518469,1119355,1239941
|
||||
dd 1358561,1525023,1240596,1321861
|
||||
dd 1692795,1846149,726139,846725
|
||||
dd 1686241,1852703,847380,928645
|
||||
dd 1692795,1846149,1119355,1239941
|
||||
dd 1686241,1852703,1240596,1321861
|
||||
dd 1561723,1977221,283771,371589
|
||||
dd 1561723,1977221,64225,106168
|
||||
dd 1622016,1654784,427950,460718
|
||||
dd 1753088,1785856,427950,460718
|
||||
dd 1884160,1916928,427950,460718
|
||||
dd 1240596,1275986,54395,1636434
|
||||
BOWL_SEAT_COUNT equ 11
|
||||
bwSeats3D LABEL DWORD
|
||||
dd 258867,1835008,384
|
||||
dd 507904,1835008,384
|
||||
dd 756941,1835008,384
|
||||
dd 1005978,1835008,384
|
||||
dd 1441792,881459,384
|
||||
dd 1441792,1274675,384
|
||||
dd 1769472,881459,384
|
||||
dd 1769472,1274675,384
|
||||
dd 1638400,445645,384
|
||||
dd 1769472,445645,384
|
||||
dd 1900544,445645,384
|
||||
bwMap3D LABEL BYTE
|
||||
db 232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232
|
||||
db 232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232
|
||||
.code
|
||||
678
src_graphics/bowling_render.inc
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
RenderBowlingPlanes3D PROC uses ebx esi edi
|
||||
local row:DWORD,depth:DWORD,wx:DWORD,wy:DWORD,stepX:DWORD,stepY:DWORD
|
||||
local base:DWORD,tile:DWORD,ceiling:DWORD,color:DWORD,shade:DWORD
|
||||
mov eax,bwArt3D.pixels
|
||||
test eax,eax
|
||||
jz bw_planes_done
|
||||
mov base,eax
|
||||
mov row,0
|
||||
xor edi,edi
|
||||
bw_planes_row:
|
||||
mov ceiling,0
|
||||
mov eax,row
|
||||
sub eax,viewHorizon3D
|
||||
jns bw_planes_floor
|
||||
neg eax
|
||||
mov ecx,eax
|
||||
mov eax,viewCeiling3D
|
||||
sub eax,viewEye3D
|
||||
mov ceiling,1
|
||||
jmp bw_planes_depth
|
||||
bw_planes_floor:
|
||||
inc eax
|
||||
mov ecx,eax
|
||||
mov eax,viewEye3D
|
||||
bw_planes_depth:
|
||||
imul eax,SCREEN_H
|
||||
cdq
|
||||
idiv ecx
|
||||
mov depth,eax
|
||||
shr eax,16
|
||||
imul eax,3
|
||||
mov ecx,250
|
||||
sub ecx,eax
|
||||
cmp ecx,160
|
||||
jae @F
|
||||
mov ecx,160
|
||||
@@:
|
||||
cmp ceiling,0
|
||||
je @F
|
||||
sub ecx,65
|
||||
@@:
|
||||
mov shade,ecx
|
||||
mov eax,depth
|
||||
imul cityRayX3D[0]
|
||||
shrd eax,edx,16
|
||||
add eax,playerX
|
||||
mov wx,eax
|
||||
mov eax,depth
|
||||
imul cityRayY3D[0]
|
||||
shrd eax,edx,16
|
||||
add eax,playerY
|
||||
mov wy,eax
|
||||
mov eax,depth
|
||||
imul playerPlaneX
|
||||
shrd eax,edx,16
|
||||
shl eax,1
|
||||
cdq
|
||||
mov ecx,SCREEN_W
|
||||
idiv ecx
|
||||
mov stepX,eax
|
||||
mov eax,depth
|
||||
imul playerPlaneY
|
||||
shrd eax,edx,16
|
||||
shl eax,1
|
||||
cdq
|
||||
idiv ecx
|
||||
mov stepY,eax
|
||||
mov esi,SCREEN_W
|
||||
bw_planes_pixel:
|
||||
mov tile,1
|
||||
cmp ceiling,0
|
||||
jne bw_planes_ceiling_tile
|
||||
cmp wx,FP_1*205/100
|
||||
jl bw_planes_sample
|
||||
cmp wx,FP_1*1725/100
|
||||
jge bw_planes_sample
|
||||
cmp wy,FP_1*255/10
|
||||
jg bw_planes_sample
|
||||
mov tile,0
|
||||
cmp wy,FP_1*225/10
|
||||
jg bw_planes_sample
|
||||
mov eax,wx
|
||||
sub eax,FP_1*205/100
|
||||
cdq
|
||||
mov ecx,BW_LANE_STEP
|
||||
idiv ecx
|
||||
cmp edx,FP_1*18/100
|
||||
jb bw_planes_gutter
|
||||
cmp edx,FP_1*172/100
|
||||
jbe bw_planes_sample
|
||||
bw_planes_gutter:
|
||||
mov tile,3
|
||||
jmp bw_planes_sample
|
||||
bw_planes_ceiling_tile:
|
||||
mov tile,3
|
||||
bw_planes_sample:
|
||||
cmp ceiling,0
|
||||
je bw_planes_texture
|
||||
mov eax,0021262Bh
|
||||
mov edx,wx
|
||||
and edx,1FFFFh
|
||||
cmp edx,1800
|
||||
jb bw_planes_ceiling_seam
|
||||
mov edx,wy
|
||||
and edx,1FFFFh
|
||||
cmp edx,1800
|
||||
jae bw_planes_shade
|
||||
bw_planes_ceiling_seam:
|
||||
mov eax,0014181Ch
|
||||
jmp bw_planes_shade
|
||||
bw_planes_texture:
|
||||
mov eax,wy
|
||||
sar eax,9
|
||||
and eax,255
|
||||
shl eax,8
|
||||
mov edx,wx
|
||||
sar edx,9
|
||||
and edx,255
|
||||
add eax,edx
|
||||
mov ebx,tile
|
||||
shl ebx,18
|
||||
add ebx,base
|
||||
mov eax,[ebx+eax*4]
|
||||
bw_planes_shade:
|
||||
mov color,eax
|
||||
movzx eax,al
|
||||
imul eax,shade
|
||||
shr eax,8
|
||||
mov ebx,eax
|
||||
mov eax,color
|
||||
shr eax,8
|
||||
and eax,255
|
||||
imul eax,shade
|
||||
and eax,0FF00h
|
||||
or ebx,eax
|
||||
mov eax,color
|
||||
shr eax,16
|
||||
and eax,255
|
||||
imul eax,shade
|
||||
and eax,0FF00h
|
||||
shl eax,8
|
||||
or eax,ebx
|
||||
mov screenBuffer[edi],eax
|
||||
mov eax,depth
|
||||
mov cityDepthBuffer3D[edi],eax
|
||||
mov eax,stepX
|
||||
add wx,eax
|
||||
mov eax,stepY
|
||||
add wy,eax
|
||||
add edi,4
|
||||
dec esi
|
||||
jnz bw_planes_pixel
|
||||
inc row
|
||||
cmp row,SCREEN_H
|
||||
jb bw_planes_row
|
||||
bw_planes_done:
|
||||
ret
|
||||
RenderBowlingPlanes3D ENDP
|
||||
|
||||
DrawBowlingBall3D PROC uses ebx esi x:DWORD,y:DWORD,mat:DWORD
|
||||
invoke DrawRoofEllipsoid3D,x,y,FP_1*135/1000,FP_1*12/100,FP_1*12/100,FP_1*12/100,mat
|
||||
ret
|
||||
DrawBowlingBall3D ENDP
|
||||
|
||||
DrawBowlingPin3D PROC uses ebx esi edi lane:DWORD,pin:DWORD,centre:DWORD
|
||||
local x:DWORD,y:DWORD,t:DWORD,z:DWORD,ry:DWORD,rz:DWORD,headY:DWORD,headZ:DWORD
|
||||
mov esi,lane
|
||||
mov edi,pin
|
||||
mov eax,bwPinX3D[edi*4]
|
||||
add eax,centre
|
||||
mov x,eax
|
||||
mov eax,bwPinY3D[edi*4]
|
||||
mov y,eax
|
||||
mov z,FP_1*15/100
|
||||
mov ry,FP_1/10
|
||||
mov rz,FP_1*13/100
|
||||
mov headY,eax
|
||||
mov headZ,FP_1*34/100
|
||||
mov ecx,edi
|
||||
mov ebx,1
|
||||
shl ebx,cl
|
||||
test bwRack3D[esi*4],ebx
|
||||
jz bw_pin_done
|
||||
cmp bwState3D[esi*4],4
|
||||
jne bw_pin_draw
|
||||
test bwHit3D[esi*4],ebx
|
||||
jz bw_pin_draw
|
||||
cmp bwTime3D[esi*4],1200
|
||||
ja bw_pin_done
|
||||
mov eax,bwTime3D[esi*4]
|
||||
imul edx,edi,23
|
||||
sub eax,edx
|
||||
jle bw_pin_draw
|
||||
cmp eax,500
|
||||
jbe @F
|
||||
mov eax,500
|
||||
@@:
|
||||
mov t,eax
|
||||
imul eax,FP_1*7/100
|
||||
cdq
|
||||
mov ecx,500
|
||||
idiv ecx
|
||||
sub z,eax
|
||||
sub rz,eax
|
||||
mov eax,t
|
||||
imul eax,FP_1*14/100
|
||||
cdq
|
||||
idiv ecx
|
||||
add ry,eax
|
||||
mov eax,t
|
||||
imul eax,FP_1*30/100
|
||||
cdq
|
||||
idiv ecx
|
||||
sub headY,eax
|
||||
mov eax,t
|
||||
imul eax,FP_1*24/100
|
||||
cdq
|
||||
idiv ecx
|
||||
sub headZ,eax
|
||||
bw_pin_draw:
|
||||
invoke DrawRoofEllipsoid3D,x,y,z,FP_1/10,ry,rz,239
|
||||
invoke DrawRoofEllipsoid3D,x,headY,headZ,FP_1*65/1000,FP_1*65/1000,FP_1*6/100,239
|
||||
mov eax,z
|
||||
add eax,rz
|
||||
invoke DrawRoofEllipsoid3D,x,headY,eax,FP_1*45/1000,FP_1*45/1000,FP_1*25/1000,240
|
||||
bw_pin_done:
|
||||
ret
|
||||
DrawBowlingPin3D ENDP
|
||||
|
||||
RenderBowlingLanes3D PROC uses ebx esi edi
|
||||
local centre:DWORD,lo:DWORD,hi:DWORD,time:DWORD,ballX:DWORD,ballY:DWORD,mat:DWORD
|
||||
local monitorLo:DWORD,monitorHi:DWORD
|
||||
xor esi,esi
|
||||
bw_render_lane:
|
||||
imul eax,esi,BW_LANE_STEP
|
||||
add eax,3*FP_1
|
||||
mov centre,eax
|
||||
sub eax,FP_1*83/100
|
||||
mov lo,eax
|
||||
add eax,FP_1*166/100
|
||||
mov hi,eax
|
||||
invoke DrawRoofSolid3D,lo,hi,FP_1*16/10,FP_1*29/10,0,FP_1*17/10,233
|
||||
invoke DrawCityVertical3D,1,FP_1*291/100,lo,hi,FP_1*13/10,FP_1*18/10,234
|
||||
mov eax,centre
|
||||
sub eax,FP_1*65/100
|
||||
mov ebx,centre
|
||||
add ebx,FP_1*65/100
|
||||
mov monitorLo,eax
|
||||
mov monitorHi,ebx
|
||||
invoke DrawRoofSolid3D,eax,ebx,FP_1*216/10,FP_1*219/10,FP_1*29/10,FP_1*38/10,238
|
||||
lea edx,[esi+244]
|
||||
invoke DrawCityVertical3D,1,FP_1*2191/100,monitorLo,monitorHi,3*FP_1,FP_1*37/10,edx
|
||||
mov eax,centre
|
||||
sub eax,FP_1*4/100
|
||||
mov ebx,centre
|
||||
add ebx,FP_1*4/100
|
||||
invoke DrawRoofSolid3D,eax,ebx,FP_1*217/10,FP_1*218/10,FP_1*38/10,6*FP_1,238
|
||||
xor edi,edi
|
||||
bw_render_pin:
|
||||
invoke DrawBowlingPin3D,esi,edi,centre
|
||||
inc edi
|
||||
cmp edi,10
|
||||
jb bw_render_pin
|
||||
cmp bwBusy3D[esi*4],0
|
||||
je bw_render_lane_next
|
||||
mov time,-1
|
||||
cmp bwState3D[esi*4],2
|
||||
jne @F
|
||||
mov eax,bwTime3D[esi*4]
|
||||
sub eax,1800
|
||||
js bw_render_lane_next
|
||||
mov time,eax
|
||||
@@:
|
||||
cmp bwState3D[esi*4],3
|
||||
jne @F
|
||||
mov eax,bwTime3D[esi*4]
|
||||
add eax,600
|
||||
mov time,eax
|
||||
@@:
|
||||
cmp time,-1
|
||||
je bw_render_sweeper
|
||||
mov eax,time
|
||||
imul bwAim3D[esi*4]
|
||||
mov ecx,3000
|
||||
idiv ecx
|
||||
add eax,centre
|
||||
mov ballX,eax
|
||||
mov eax,time
|
||||
imul eax,FP_1*183/10
|
||||
cdq
|
||||
idiv ecx
|
||||
mov edx,FP_1*225/10
|
||||
sub edx,eax
|
||||
mov ballY,edx
|
||||
mov mat,242
|
||||
cmp bwTurn3D[esi*4],0
|
||||
je @F
|
||||
mov mat,243
|
||||
@@:
|
||||
invoke DrawBowlingBall3D,ballX,ballY,mat
|
||||
bw_render_sweeper:
|
||||
cmp bwState3D[esi*4],4
|
||||
jne bw_render_lane_next
|
||||
mov eax,bwTime3D[esi*4]
|
||||
cmp eax,700
|
||||
jb bw_render_lane_next
|
||||
sub eax,700
|
||||
cmp eax,1000
|
||||
jbe @F
|
||||
mov eax,1000
|
||||
@@:
|
||||
imul eax,2*FP_1
|
||||
cdq
|
||||
mov ecx,1000
|
||||
idiv ecx
|
||||
mov ebx,5*FP_1
|
||||
sub ebx,eax
|
||||
mov eax,ebx
|
||||
add eax,FP_1/8
|
||||
invoke DrawRoofSolid3D,lo,hi,ebx,eax,FP_1/5,FP_1*35/100,243
|
||||
bw_render_lane_next:
|
||||
inc esi
|
||||
cmp esi,BW_LANES
|
||||
jb bw_render_lane
|
||||
ret
|
||||
RenderBowlingLanes3D ENDP
|
||||
|
||||
BowlingHome3D PROC lane:DWORD,owner:DWORD
|
||||
mov eax,lane
|
||||
shr eax,1
|
||||
imul eax,FP_1*38/10
|
||||
add eax,FP_1*395/100
|
||||
sub eax,FP_1*65/100
|
||||
test lane,1
|
||||
jz @F
|
||||
add eax,FP_1*9/10
|
||||
@@:
|
||||
cmp owner,0
|
||||
je @F
|
||||
add eax,FP_1*55/100
|
||||
@@:
|
||||
ret
|
||||
BowlingHome3D ENDP
|
||||
|
||||
RenderBowlingVisitors3D PROC uses ebx esi edi
|
||||
local centre:DWORD,homeX:DWORD,person:DWORD,phase:DWORD,t:DWORD
|
||||
local action:DWORD,clock:DWORD,vx:DWORD,vy:DWORD
|
||||
xor esi,esi
|
||||
bw_cast_lane:
|
||||
cmp bwBusy3D[esi*4],0
|
||||
je bw_cast_lane_next
|
||||
imul eax,esi,BW_LANE_STEP
|
||||
add eax,3*FP_1
|
||||
mov centre,eax
|
||||
invoke BowlingHome3D,esi,bwTurn3D[esi*4]
|
||||
mov homeX,eax
|
||||
mov bwActor3D.posX,eax
|
||||
mov bwActor3D.posY,FP_1*279/10
|
||||
lea ebx,[esi*2]
|
||||
add ebx,bwTurn3D[esi*4]
|
||||
mov eax,bwCharacterIds3D[ebx*4]
|
||||
mov person,eax
|
||||
mov eax,bwState3D[esi*4]
|
||||
mov phase,eax
|
||||
mov eax,bwTime3D[esi*4]
|
||||
mov t,eax
|
||||
mov clock,eax
|
||||
mov action,CAST_SEAT_TALK
|
||||
mov vx,0
|
||||
mov vy,0
|
||||
cmp phase,0
|
||||
jne bw_cast_not_rest
|
||||
cmp eax,1500
|
||||
jb bw_cast_draw
|
||||
sub clock,1500
|
||||
mov action,CAST_STAND_UP
|
||||
jmp bw_cast_draw
|
||||
bw_cast_not_rest:
|
||||
cmp phase,6
|
||||
jne bw_cast_not_seat
|
||||
cmp eax,800
|
||||
jae bw_cast_draw
|
||||
mov action,CAST_SIT_DOWN
|
||||
jmp bw_cast_draw
|
||||
bw_cast_not_seat:
|
||||
cmp phase,1
|
||||
jne bw_cast_not_pick
|
||||
cmp eax,1800
|
||||
jae bw_cast_pick
|
||||
mov action,CAST_WALK
|
||||
mov vy,-FP_1
|
||||
mov eax,centre
|
||||
sub eax,homeX
|
||||
mov vx,eax
|
||||
imul t
|
||||
mov ecx,1800
|
||||
idiv ecx
|
||||
add eax,homeX
|
||||
mov bwActor3D.posX,eax
|
||||
mov eax,t
|
||||
imul eax,FP_1*24/10
|
||||
cdq
|
||||
idiv ecx
|
||||
mov clock,eax
|
||||
mov edx,FP_1*279/10
|
||||
sub edx,eax
|
||||
mov bwActor3D.posY,edx
|
||||
jmp bw_cast_draw
|
||||
bw_cast_pick:
|
||||
mov eax,centre
|
||||
mov bwActor3D.posX,eax
|
||||
mov bwActor3D.posY,FP_1*255/10
|
||||
mov action,CAST_PICK_UP
|
||||
sub clock,1800
|
||||
jmp bw_cast_draw
|
||||
bw_cast_not_pick:
|
||||
mov eax,centre
|
||||
mov bwActor3D.posX,eax
|
||||
mov bwActor3D.posY,FP_1*226/10
|
||||
mov action,CAST_IDLE
|
||||
cmp phase,2
|
||||
jne bw_cast_not_throw
|
||||
mov action,CAST_THROW
|
||||
mov eax,t
|
||||
imul eax,FP_1*29/10
|
||||
cdq
|
||||
mov ecx,2400
|
||||
idiv ecx
|
||||
mov edx,FP_1*255/10
|
||||
sub edx,eax
|
||||
mov bwActor3D.posY,edx
|
||||
jmp bw_cast_draw
|
||||
bw_cast_not_throw:
|
||||
cmp phase,3
|
||||
jne @F
|
||||
mov action,CAST_THROW
|
||||
mov clock,2300
|
||||
@@:
|
||||
cmp phase,4
|
||||
jne bw_cast_not_impact
|
||||
cmp bwHit3D[esi*4],0
|
||||
je bw_cast_draw
|
||||
mov action,CAST_CHEER
|
||||
jmp bw_cast_draw
|
||||
bw_cast_not_impact:
|
||||
cmp phase,5
|
||||
jne bw_cast_draw
|
||||
mov action,CAST_WALK
|
||||
mov vy,FP_1
|
||||
mov eax,homeX
|
||||
sub eax,centre
|
||||
mov vx,eax
|
||||
imul t
|
||||
mov ecx,3600
|
||||
idiv ecx
|
||||
add eax,centre
|
||||
mov bwActor3D.posX,eax
|
||||
mov eax,t
|
||||
imul eax,FP_1*53/10
|
||||
cdq
|
||||
idiv ecx
|
||||
mov clock,eax
|
||||
add eax,FP_1*226/10
|
||||
mov bwActor3D.posY,eax
|
||||
bw_cast_draw:
|
||||
invoke ConfigureCharacter3D,OFFSET bwActor3D,person,action,clock,vx,vy
|
||||
invoke DrawCityObject3D,OFFSET bwActor3D,0
|
||||
; The other member of this lane keeps their own identity and their own seat.
|
||||
mov eax,bwTurn3D[esi*4]
|
||||
xor eax,1
|
||||
mov edi,eax
|
||||
invoke BowlingHome3D,esi,edi
|
||||
mov bwSmallActor3D.posX,eax
|
||||
mov bwSmallActor3D.posY,FP_1*279/10
|
||||
lea ebx,[esi*2]
|
||||
add ebx,edi
|
||||
invoke ConfigureCharacter3D,OFFSET bwSmallActor3D,bwCharacterIds3D[ebx*4],CAST_SEAT_DRINK,animationClock3D,0,0
|
||||
invoke DrawCityObject3D,OFFSET bwSmallActor3D,0
|
||||
bw_cast_lane_next:
|
||||
inc esi
|
||||
cmp esi,BW_LANES
|
||||
jb bw_cast_lane
|
||||
; Four other visitors occupy the dining/bar area; ten visitors, no body doubles.
|
||||
xor esi,esi
|
||||
bw_cast_dining:
|
||||
mov eax,bwVisitorX3D[esi*4]
|
||||
mov bwSmallActor3D.posX,eax
|
||||
mov eax,bwVisitorY3D[esi*4]
|
||||
mov bwSmallActor3D.posY,eax
|
||||
lea edi,[esi+6]
|
||||
invoke ConfigureCharacter3D,OFFSET bwSmallActor3D,edi,CAST_SEAT_TALK,animationClock3D,0,0
|
||||
cmp esi,2
|
||||
jb @F
|
||||
add bwSmallActor3D.groundZ,FP_1/4
|
||||
@@:
|
||||
invoke DrawCityObject3D,OFFSET bwSmallActor3D,0
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb bw_cast_dining
|
||||
mov bwActor3D.posX,27*FP_1
|
||||
mov bwActor3D.posY,3*FP_1
|
||||
mov bwActor3D.asset,OFFSET hallBartender3D
|
||||
mov bwActor3D.worldW,FP_1
|
||||
mov bwActor3D.worldH,FP_1
|
||||
mov bwActor3D.groundZ,FP_1*9/10
|
||||
mov eax,animationClock3D
|
||||
shr eax,9
|
||||
and eax,7
|
||||
cmp engineMode,MODE_BAR
|
||||
jne bw_bartender_ready
|
||||
xor eax,eax
|
||||
cmp barPhase3D,1
|
||||
jne @F
|
||||
mov eax,barTime3D
|
||||
xor edx,edx
|
||||
mov ecx,375
|
||||
div ecx
|
||||
cmp eax,7
|
||||
jbe @F
|
||||
mov eax,7
|
||||
@@:
|
||||
mov ecx,barSelection3D
|
||||
shl ecx,3
|
||||
add eax,ecx
|
||||
bw_bartender_ready:
|
||||
mov bwActor3D.frame,eax
|
||||
invoke DrawCityObject3D,OFFSET bwActor3D,0
|
||||
ret
|
||||
RenderBowlingVisitors3D ENDP
|
||||
|
||||
RenderBowlingEntrance3D PROC
|
||||
cmp portalRendering3D,0
|
||||
jne bw_entrance_done
|
||||
cmp hallLevel3D,0
|
||||
jne bw_entrance_done
|
||||
cmp playerY,FP_1*15/10
|
||||
jbe bw_entrance_done
|
||||
invoke DrawInteriorView3D,1,FP_1*15/10,3*FP_1,7*FP_1,0,FP_1*205/100,12*FP_1,29*FP_1,0,OFFSET bwMap3D,MODE_WALK,HALL_BOWLING,231,0
|
||||
invoke DrawCityVertical3D,1,FP_1*151/100,3*FP_1,7*FP_1,FP_1*205/100,FP_1*246/100,252
|
||||
bw_entrance_done:
|
||||
ret
|
||||
RenderBowlingEntrance3D ENDP
|
||||
|
||||
RenderBowlingDetails3D PROC uses ebx esi edi
|
||||
local centerX:DWORD,x0:DWORD,x1:DWORD,centerY:DWORD
|
||||
xor esi,esi
|
||||
bw_detail_return:
|
||||
imul eax,esi,FP_1*38/10
|
||||
add eax,FP_1*395/100
|
||||
mov centerX,eax
|
||||
sub eax,FP_1*32/100
|
||||
mov x0,eax
|
||||
add eax,FP_1*64/100
|
||||
mov x1,eax
|
||||
invoke DrawCityVertical3D,1,26*FP_1+512,x0,x1,FP_1/20,FP_1*62/100,241
|
||||
xor edi,edi
|
||||
bw_detail_rack_ball:
|
||||
mov eax,centerX
|
||||
imul edx,edi,FP_1*23/100
|
||||
add eax,edx
|
||||
sub eax,FP_1*23/100
|
||||
mov ebx,242
|
||||
test edi,1
|
||||
jz @F
|
||||
mov ebx,243
|
||||
@@:
|
||||
invoke DrawRoofEllipsoid3D,eax,FP_1*254/10,FP_1*84/100,FP_1*11/100,FP_1*11/100,FP_1*11/100,ebx
|
||||
mov eax,centerX
|
||||
imul edx,edi,FP_1*23/100
|
||||
add eax,edx
|
||||
sub eax,FP_1*23/100
|
||||
sub eax,FP_1*35/1000
|
||||
invoke DrawRoofEllipsoid3D,eax,FP_1*25494/1000,FP_1*905/1000,FP_1*14/1000,FP_1*14/1000,FP_1*14/1000,233
|
||||
mov eax,centerX
|
||||
imul edx,edi,FP_1*23/100
|
||||
add eax,edx
|
||||
sub eax,FP_1*195/1000
|
||||
invoke DrawRoofEllipsoid3D,eax,FP_1*25494/1000,FP_1*905/1000,FP_1*14/1000,FP_1*14/1000,FP_1*14/1000,233
|
||||
inc edi
|
||||
cmp edi,3
|
||||
jb bw_detail_rack_ball
|
||||
mov eax,centerX
|
||||
sub eax,FP_1*27/100
|
||||
invoke DrawRoofEllipsoid3D,eax,27*FP_1,FP_1*49/100,FP_1*16/100,FP_1*16/100,FP_1*2/100,239
|
||||
mov eax,centerX
|
||||
add eax,FP_1*29/100
|
||||
invoke DrawRoofEllipsoid3D,eax,27*FP_1,FP_1*58/100,FP_1*5/100,FP_1*5/100,FP_1*12/100,243
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb bw_detail_return
|
||||
xor esi,esi
|
||||
bw_detail_dining:
|
||||
mov eax,esi
|
||||
and eax,1
|
||||
imul eax,5*FP_1
|
||||
add eax,22*FP_1
|
||||
mov centerX,eax
|
||||
mov eax,esi
|
||||
shr eax,1
|
||||
imul eax,6*FP_1
|
||||
add eax,12*FP_1
|
||||
mov centerY,eax
|
||||
mov eax,centerX
|
||||
sub eax,FP_1*45/100
|
||||
invoke DrawRoofEllipsoid3D,eax,centerY,FP_1*58/100,FP_1*22/100,FP_1*22/100,FP_1*2/100,239
|
||||
mov eax,centerX
|
||||
add eax,FP_1*55/100
|
||||
invoke DrawRoofEllipsoid3D,eax,centerY,FP_1*69/100,FP_1*6/100,FP_1*6/100,FP_1*14/100,243
|
||||
invoke DrawRoofEllipsoid3D,centerX,centerY,FP_1*63/100,FP_1*7/100,FP_1*7/100,FP_1*8/100,242
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb bw_detail_dining
|
||||
ret
|
||||
RenderBowlingDetails3D ENDP
|
||||
|
||||
RenderBowling3D PROC uses ebx esi edi
|
||||
local lo:DWORD,hi:DWORD
|
||||
call UpdateBowling3D
|
||||
call LoadBowling3D
|
||||
call PrepareCityRays3D
|
||||
lea edi,zBuffer
|
||||
mov eax,7FFFFFFFh
|
||||
mov ecx,SCREEN_W
|
||||
rep stosd
|
||||
call RenderBowlingPlanes3D
|
||||
xor esi,esi
|
||||
bw_room_walls:
|
||||
imul eax,esi,3*FP_1
|
||||
add eax,FP_1
|
||||
mov lo,eax
|
||||
add eax,3*FP_1
|
||||
mov hi,eax
|
||||
invoke DrawCityVertical3D,0,FP_1,lo,hi,0,6*FP_1,232
|
||||
invoke DrawCityVertical3D,0,31*FP_1,lo,hi,0,6*FP_1,232
|
||||
mov ebx,234
|
||||
cmp esi,6
|
||||
jb @F
|
||||
mov ebx,232
|
||||
@@:
|
||||
invoke DrawCityVertical3D,1,FP_1,lo,hi,0,6*FP_1,ebx
|
||||
invoke DrawCityVertical3D,1,31*FP_1,lo,hi,0,6*FP_1,232
|
||||
inc esi
|
||||
cmp esi,10
|
||||
jb bw_room_walls
|
||||
invoke DrawCityVertical3D,0,FP_1*101/100,FP_1,31*FP_1,FP_1*45/10,FP_1*455/100,242
|
||||
invoke DrawCityVertical3D,0,FP_1*3099/100,FP_1,31*FP_1,FP_1*45/10,FP_1*455/100,243
|
||||
lea esi,bwProps3D
|
||||
mov edi,BOWL_PROP_COUNT
|
||||
bw_room_prop:
|
||||
invoke DrawRoofSolid3D,[esi],[esi+4],[esi+8],[esi+12],[esi+16],[esi+20],[esi+24]
|
||||
add esi,28
|
||||
dec edi
|
||||
jnz bw_room_prop
|
||||
; Bottle shelves occupy only the wall behind the counter.
|
||||
invoke DrawCityVertical3D,1,FP_1*146/100,24*FP_1,30*FP_1,FP_1,3*FP_1,ROOF_BOTTLES
|
||||
call RenderBowlingDetails3D
|
||||
xor esi,esi
|
||||
bw_room_lights:
|
||||
imul eax,esi,4*FP_1
|
||||
add eax,3*FP_1
|
||||
mov ebx,eax
|
||||
add ebx,FP_1*22/10
|
||||
invoke DrawCityHorizontal3D,eax,ebx,6*FP_1,FP_1*62/10,FP_1*55/10,242
|
||||
invoke DrawCityHorizontal3D,eax,ebx,16*FP_1,FP_1*162/10,FP_1*55/10,243
|
||||
inc esi
|
||||
cmp esi,7
|
||||
jb bw_room_lights
|
||||
call RefreshBowlingMonitors3D
|
||||
call RenderBowlingLanes3D
|
||||
call RenderBowlingVisitors3D
|
||||
cmp portalRendering3D,0
|
||||
jne bw_room_done
|
||||
cmp playerY,FP_1*305/10
|
||||
jae bw_room_done
|
||||
invoke DrawInteriorView3D,1,FP_1*305/10,15*FP_1,19*FP_1,0,FP_1*24/10,-12*FP_1,-29*FP_1,0,OFFSET casinoMap,MODE_WALK,0,100,0
|
||||
bw_room_done:
|
||||
ret
|
||||
RenderBowling3D ENDP
|
||||
391
src_graphics/bowling_simulation.inc
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
BowlingScore3D PROC uses ebx esi edi owner:DWORD
|
||||
local frame:DWORD,roll:DWORD,total:DWORD,available:DWORD
|
||||
mov ebx,owner
|
||||
mov eax,bwRollCount3D[ebx*4]
|
||||
mov available,eax
|
||||
imul ebx,96
|
||||
lea esi,bwRolls3D[ebx]
|
||||
mov frame,0
|
||||
mov roll,0
|
||||
mov total,0
|
||||
bw_score_frame:
|
||||
mov edi,roll
|
||||
cmp edi,available
|
||||
jae bw_score_done
|
||||
mov eax,[esi+edi*4]
|
||||
add total,eax
|
||||
cmp eax,10
|
||||
je bw_score_strike
|
||||
inc edi
|
||||
cmp edi,available
|
||||
jae bw_score_done
|
||||
add eax,[esi+edi*4]
|
||||
mov edx,[esi+edi*4]
|
||||
add total,edx
|
||||
inc edi
|
||||
cmp eax,10
|
||||
jne bw_score_advance_two
|
||||
cmp edi,available
|
||||
jae bw_score_advance_two
|
||||
mov eax,[esi+edi*4]
|
||||
add total,eax
|
||||
bw_score_advance_two:
|
||||
add roll,2
|
||||
jmp bw_score_advance_frame
|
||||
bw_score_strike:
|
||||
inc edi
|
||||
cmp edi,available
|
||||
jae bw_score_advance_one
|
||||
mov eax,[esi+edi*4]
|
||||
add total,eax
|
||||
inc edi
|
||||
cmp edi,available
|
||||
jae bw_score_advance_one
|
||||
mov eax,[esi+edi*4]
|
||||
add total,eax
|
||||
bw_score_advance_one:
|
||||
inc roll
|
||||
bw_score_advance_frame:
|
||||
inc frame
|
||||
cmp frame,10
|
||||
jb bw_score_frame
|
||||
bw_score_done:
|
||||
mov ebx,owner
|
||||
mov eax,total
|
||||
mov bwScores3D[ebx*4],eax
|
||||
ret
|
||||
BowlingScore3D ENDP
|
||||
|
||||
BowlingRegisterRoll3D PROC uses ebx esi edi lane:DWORD,hit:DWORD
|
||||
mov esi,lane
|
||||
lea ebx,[esi*2]
|
||||
add ebx,bwTurn3D[esi*4]
|
||||
mov edi,bwRollCount3D[ebx*4]
|
||||
cmp edi,21
|
||||
jae bw_register_done
|
||||
imul eax,ebx,96
|
||||
lea edi,[eax+edi*4]
|
||||
mov eax,hit
|
||||
mov bwRolls3D[edi],eax
|
||||
inc bwRollCount3D[ebx*4]
|
||||
invoke BowlingScore3D,ebx
|
||||
mov bwNewRack3D[esi*4],0
|
||||
mov bwFrameDone3D[esi*4],0
|
||||
cmp bwBall3D[esi*4],0
|
||||
jne bw_register_after_first
|
||||
mov eax,hit
|
||||
mov bwFirstHit3D[esi*4],eax
|
||||
cmp eax,10
|
||||
jne bw_register_next_ball
|
||||
cmp bwFrames3D[ebx*4],9
|
||||
jb bw_register_complete
|
||||
mov bwNewRack3D[esi*4],1
|
||||
jmp bw_register_next_ball
|
||||
bw_register_after_first:
|
||||
cmp bwFrames3D[ebx*4],9
|
||||
jb bw_register_complete
|
||||
cmp bwBall3D[esi*4],2
|
||||
jae bw_register_complete
|
||||
mov eax,bwFirstHit3D[esi*4]
|
||||
add eax,hit
|
||||
cmp eax,10
|
||||
jb bw_register_complete
|
||||
cmp bwFirstHit3D[esi*4],10
|
||||
jne bw_register_bonus_rack
|
||||
cmp hit,10
|
||||
jne bw_register_next_ball
|
||||
bw_register_bonus_rack:
|
||||
mov bwNewRack3D[esi*4],1
|
||||
bw_register_next_ball:
|
||||
inc bwBall3D[esi*4]
|
||||
ret
|
||||
bw_register_complete:
|
||||
inc bwFrames3D[ebx*4]
|
||||
mov bwNewRack3D[esi*4],1
|
||||
mov bwFrameDone3D[esi*4],1
|
||||
mov bwBall3D[esi*4],0
|
||||
bw_register_done:
|
||||
ret
|
||||
BowlingRegisterRoll3D ENDP
|
||||
|
||||
BowlingImpact3D PROC uses ebx esi edi lane:DWORD
|
||||
local pinMask:DWORD,count:DWORD
|
||||
mov esi,lane
|
||||
mov pinMask,0
|
||||
mov count,0
|
||||
mov eax,bwAim3D[esi*4]
|
||||
test eax,eax
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,FP_1*68/100
|
||||
ja bw_impact_finish
|
||||
xor edi,edi
|
||||
bw_impact_pin:
|
||||
mov ecx,edi
|
||||
mov ebx,1
|
||||
shl ebx,cl
|
||||
test bwRack3D[esi*4],ebx
|
||||
jz bw_impact_next
|
||||
mov eax,bwPinX3D[edi*4]
|
||||
sub eax,bwAim3D[esi*4]
|
||||
test eax,eax
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,FP_1*44/100
|
||||
ja bw_impact_next
|
||||
or pinMask,ebx
|
||||
inc count
|
||||
bw_impact_next:
|
||||
inc edi
|
||||
cmp edi,10
|
||||
jb bw_impact_pin
|
||||
mov eax,bwAim3D[esi*4]
|
||||
add eax,FP_1*18/100
|
||||
cmp eax,FP_1*36/100
|
||||
ja bw_impact_finish
|
||||
; A central pocket can propagate through the complete rack.
|
||||
test bwRng3D,3
|
||||
jz bw_impact_finish
|
||||
mov eax,bwRack3D[esi*4]
|
||||
mov pinMask,eax
|
||||
mov count,0
|
||||
@@:
|
||||
test eax,eax
|
||||
jz bw_impact_finish
|
||||
lea edx,[eax-1]
|
||||
and eax,edx
|
||||
inc count
|
||||
jmp @B
|
||||
bw_impact_finish:
|
||||
mov eax,pinMask
|
||||
mov bwHit3D[esi*4],eax
|
||||
invoke BowlingRegisterRoll3D,esi,count
|
||||
ret
|
||||
BowlingImpact3D ENDP
|
||||
|
||||
UpdateBowling3D PROC uses ebx esi edi
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
je bw_update_active
|
||||
cmp hallLevel3D,0
|
||||
jne bw_update_done
|
||||
cmp playerY,10*FP_1
|
||||
ja bw_update_done
|
||||
cmp playerX,10*FP_1
|
||||
ja bw_update_done
|
||||
bw_update_active:
|
||||
mov eax,animationClock3D
|
||||
cmp eax,bwClock3D
|
||||
je bw_update_done
|
||||
mov bwClock3D,eax
|
||||
cmp bwSeat3D,0
|
||||
je bw_update_lanes
|
||||
cmp keys3D[57h],0
|
||||
jne bw_update_stand
|
||||
cmp keys3D[53h],0
|
||||
je bw_update_lanes
|
||||
bw_update_stand:
|
||||
mov interactTargetId,INTERACT_BOWL_SEAT
|
||||
call TryBowlingInteraction3D
|
||||
bw_update_lanes:
|
||||
xor esi,esi
|
||||
bw_update_lane:
|
||||
cmp bwBusy3D[esi*4],0
|
||||
je bw_update_next
|
||||
mov eax,deltaTime3D
|
||||
add bwTime3D[esi*4],eax
|
||||
mov eax,bwState3D[esi*4]
|
||||
cmp eax,0
|
||||
je bw_update_rest
|
||||
cmp eax,1
|
||||
je bw_update_pick
|
||||
cmp eax,2
|
||||
je bw_update_throw
|
||||
cmp eax,3
|
||||
je bw_update_roll
|
||||
cmp eax,4
|
||||
je bw_update_sweep
|
||||
cmp eax,5
|
||||
je bw_update_return
|
||||
cmp bwTime3D[esi*4],4000
|
||||
jb bw_update_next
|
||||
cmp bwFrameDone3D[esi*4],0
|
||||
je bw_update_new_approach
|
||||
xor bwTurn3D[esi*4],1
|
||||
lea ebx,[esi*2]
|
||||
add ebx,bwTurn3D[esi*4]
|
||||
cmp bwFrames3D[ebx*4],10
|
||||
jb bw_update_new_approach
|
||||
xor bwTurn3D[esi*4],1
|
||||
lea ebx,[esi*2]
|
||||
add ebx,bwTurn3D[esi*4]
|
||||
cmp bwFrames3D[ebx*4],10
|
||||
jb bw_update_new_approach
|
||||
; Both games finished: start a new pair without affecting the casino bankroll.
|
||||
lea ebx,[esi*8]
|
||||
mov bwFrames3D[ebx],0
|
||||
mov bwFrames3D[ebx+4],0
|
||||
mov bwRollCount3D[ebx],0
|
||||
mov bwRollCount3D[ebx+4],0
|
||||
mov bwScores3D[ebx],0
|
||||
mov bwScores3D[ebx+4],0
|
||||
bw_update_new_approach:
|
||||
mov bwState3D[esi*4],0
|
||||
jmp bw_update_reset_timer
|
||||
bw_update_rest:
|
||||
cmp bwTime3D[esi*4],2300
|
||||
jb bw_update_next
|
||||
mov bwState3D[esi*4],1
|
||||
jmp bw_update_reset_timer
|
||||
bw_update_pick:
|
||||
cmp bwTime3D[esi*4],2700
|
||||
jb bw_update_next
|
||||
mov bwState3D[esi*4],2
|
||||
mov eax,bwRng3D
|
||||
imul eax,1664525
|
||||
add eax,1013904223
|
||||
mov bwRng3D,eax
|
||||
shr eax,16
|
||||
xor edx,edx
|
||||
mov ecx,171
|
||||
div ecx
|
||||
sub edx,85
|
||||
imul eax,edx,FP_1
|
||||
cdq
|
||||
mov ecx,100
|
||||
idiv ecx
|
||||
mov bwAim3D[esi*4],eax
|
||||
jmp bw_update_reset_timer
|
||||
bw_update_throw:
|
||||
cmp bwTime3D[esi*4],2400
|
||||
jb bw_update_next
|
||||
mov bwState3D[esi*4],3
|
||||
jmp bw_update_reset_timer
|
||||
bw_update_roll:
|
||||
cmp bwTime3D[esi*4],2400
|
||||
jb bw_update_next
|
||||
invoke BowlingImpact3D,esi
|
||||
mov bwState3D[esi*4],4
|
||||
jmp bw_update_reset_timer
|
||||
bw_update_sweep:
|
||||
cmp bwTime3D[esi*4],1800
|
||||
jb bw_update_next
|
||||
mov eax,bwHit3D[esi*4]
|
||||
not eax
|
||||
and bwRack3D[esi*4],eax
|
||||
mov bwHit3D[esi*4],0
|
||||
mov bwState3D[esi*4],5
|
||||
jmp bw_update_reset_timer
|
||||
bw_update_return:
|
||||
cmp bwTime3D[esi*4],3600
|
||||
jb bw_update_next
|
||||
cmp bwNewRack3D[esi*4],0
|
||||
je @F
|
||||
mov bwRack3D[esi*4],1023
|
||||
@@:
|
||||
mov bwState3D[esi*4],6
|
||||
bw_update_reset_timer:
|
||||
mov bwTime3D[esi*4],0
|
||||
bw_update_next:
|
||||
inc esi
|
||||
cmp esi,BW_LANES
|
||||
jb bw_update_lane
|
||||
bw_update_done:
|
||||
ret
|
||||
UpdateBowling3D ENDP
|
||||
|
||||
BowlingMonitorText3D PROC uses ebx esi edi target:DWORD,x:DWORD,y:DWORD,value:DWORD,color:DWORD
|
||||
local row:DWORD,bits:DWORD,atX:DWORD
|
||||
mov esi,value
|
||||
mov eax,x
|
||||
mov atX,eax
|
||||
bw_monitor_char:
|
||||
movzx eax,BYTE PTR [esi]
|
||||
test eax,eax
|
||||
jz bw_monitor_text_done
|
||||
cmp atX,120
|
||||
ja bw_monitor_text_done
|
||||
lea ebx,font8x8[eax*8]
|
||||
mov row,0
|
||||
bw_monitor_row:
|
||||
mov ecx,row
|
||||
movzx eax,BYTE PTR [ebx+ecx]
|
||||
mov bits,eax
|
||||
mov eax,row
|
||||
add eax,y
|
||||
shl eax,7
|
||||
add eax,atX
|
||||
lea edi,[eax*4]
|
||||
add edi,target
|
||||
mov ecx,8
|
||||
bw_monitor_pixel:
|
||||
test bits,80h
|
||||
jz @F
|
||||
mov eax,color
|
||||
stosd
|
||||
jmp bw_monitor_pixel_next
|
||||
@@:
|
||||
add edi,4
|
||||
bw_monitor_pixel_next:
|
||||
shl bits,1
|
||||
dec ecx
|
||||
jnz bw_monitor_pixel
|
||||
inc row
|
||||
cmp row,8
|
||||
jb bw_monitor_row
|
||||
inc esi
|
||||
add atX,8
|
||||
jmp bw_monitor_char
|
||||
bw_monitor_text_done:
|
||||
ret
|
||||
BowlingMonitorText3D ENDP
|
||||
|
||||
RefreshBowlingMonitors3D PROC uses ebx esi edi
|
||||
local target:DWORD,number[16]:BYTE
|
||||
mov eax,animationClock3D
|
||||
shr eax,8
|
||||
cmp eax,bwMonitorClock3D
|
||||
je bw_monitors_done
|
||||
mov bwMonitorClock3D,eax
|
||||
lea edi,bwSignPixels3D
|
||||
mov eax,0FF10282Fh
|
||||
mov ecx,128*64
|
||||
rep stosd
|
||||
invoke BowlingMonitorText3D,OFFSET bwSignPixels3D,36,4,OFFSET bwSignText3D,0FF55D9CFh
|
||||
xor esi,esi
|
||||
bw_monitor_lane:
|
||||
mov eax,esi
|
||||
shl eax,15
|
||||
add eax,OFFSET bwMonitors3D
|
||||
mov target,eax
|
||||
mov edi,eax
|
||||
mov eax,0FF101F27h
|
||||
mov ecx,128*64
|
||||
rep stosd
|
||||
invoke BowlingMonitorText3D,target,8,5,OFFSET bwLaneWord3D,0FF55D9CFh
|
||||
lea ebx,[esi+1]
|
||||
invoke FormatNumber,ebx,ADDR number
|
||||
invoke BowlingMonitorText3D,target,52,5,ADDR number,0FFFFFFFFh
|
||||
cmp bwBusy3D[esi*4],0
|
||||
jne bw_monitor_scores
|
||||
invoke BowlingMonitorText3D,target,36,30,OFFSET bwFreeText3D,0FF55D9CFh
|
||||
jmp bw_monitor_advance
|
||||
bw_monitor_scores:
|
||||
invoke BowlingMonitorText3D,target,8,21,OFFSET bwPlayerA3D,0FFFF9F89h
|
||||
invoke BowlingMonitorText3D,target,70,21,OFFSET bwPlayerB3D,0FF55D9CFh
|
||||
lea ebx,[esi*8]
|
||||
invoke FormatNumber,bwScores3D[ebx],ADDR number
|
||||
invoke BowlingMonitorText3D,target,8,33,ADDR number,0FFFFFFFFh
|
||||
invoke FormatNumber,bwScores3D[ebx+4],ADDR number
|
||||
invoke BowlingMonitorText3D,target,70,33,ADDR number,0FFFFFFFFh
|
||||
mov eax,bwState3D[esi*4]
|
||||
mov eax,bwPhaseTexts3D[eax*4]
|
||||
invoke BowlingMonitorText3D,target,8,51,eax,0FFFFBF70h
|
||||
bw_monitor_advance:
|
||||
inc esi
|
||||
cmp esi,BW_LANES
|
||||
jb bw_monitor_lane
|
||||
bw_monitors_done:
|
||||
ret
|
||||
RefreshBowlingMonitors3D ENDP
|
||||
170
src_graphics/character_cast.inc
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
LoadCharacterCast3D PROC
|
||||
cmp characterCast3D.pixels,0
|
||||
jne cast_loaded
|
||||
invoke LoadAnimPack3D,OFFSET characterCast3D,OFFSET characterCastPath3D
|
||||
invoke ValidateCityPack3D,OFFSET characterCast3D,192,224,CAST_COUNT*CAST_STRIDE
|
||||
cast_loaded:
|
||||
ret
|
||||
LoadCharacterCast3D ENDP
|
||||
|
||||
FreeCharacterCast3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET characterCast3D
|
||||
ret
|
||||
FreeCharacterCast3D ENDP
|
||||
|
||||
; Identity chooses a fixed block. Action and camera-relative facing stay in it.
|
||||
; Walking clocks are travelled distance, not wall time, so feet stop with the body.
|
||||
ConfigureCharacter3D PROC uses ebx esi edi object:DWORD,identity:DWORD,action:DWORD,clock:DWORD,velocityX:DWORD,velocityY:DWORD
|
||||
local base:DWORD,offsetFrame:DWORD,dot:DWORD,cross:DWORD,sideMagnitude:DWORD
|
||||
call LoadCharacterCast3D
|
||||
mov esi,object
|
||||
mov eax,identity
|
||||
xor edx,edx
|
||||
mov ecx,CAST_COUNT
|
||||
div ecx
|
||||
mov characterLastId3D,edx
|
||||
imul eax,edx,CAST_STRIDE
|
||||
mov base,eax
|
||||
mov eax,action
|
||||
cmp eax,CAST_WALK
|
||||
jbe @F
|
||||
xor eax,eax
|
||||
@@:
|
||||
mov characterLastAction3D,eax
|
||||
mov edi,eax
|
||||
mov eax,characterOffsets3D[eax*4]
|
||||
mov offsetFrame,eax
|
||||
cmp edi,CAST_WALK
|
||||
je cast_walk
|
||||
cmp edi,CAST_THROW
|
||||
je cast_throw
|
||||
cmp edi,CAST_SIT_DOWN
|
||||
je cast_transition
|
||||
cmp edi,CAST_STAND_UP
|
||||
je cast_transition
|
||||
cmp edi,CAST_PICK_UP
|
||||
je cast_pickup
|
||||
mov eax,clock
|
||||
xor edx,edx
|
||||
mov ecx,180
|
||||
div ecx
|
||||
and eax,3
|
||||
jmp cast_frame_ready
|
||||
cast_throw:
|
||||
mov ecx,100
|
||||
mov ebx,23
|
||||
jmp cast_clamped_time
|
||||
cast_pickup:
|
||||
mov ecx,112
|
||||
mov ebx,7
|
||||
jmp cast_clamped_time
|
||||
cast_transition:
|
||||
mov ecx,100
|
||||
mov ebx,7
|
||||
cast_clamped_time:
|
||||
mov eax,clock
|
||||
xor edx,edx
|
||||
div ecx
|
||||
cmp eax,ebx
|
||||
jbe @F
|
||||
mov eax,ebx
|
||||
@@:
|
||||
cmp edi,CAST_STAND_UP
|
||||
jne cast_frame_ready
|
||||
neg eax
|
||||
add eax,7
|
||||
jmp cast_frame_ready
|
||||
cast_walk:
|
||||
mov eax,velocityX
|
||||
imul playerDirX
|
||||
shrd eax,edx,16
|
||||
mov dot,eax
|
||||
mov eax,velocityY
|
||||
imul playerDirY
|
||||
shrd eax,edx,16
|
||||
add dot,eax
|
||||
mov eax,velocityY
|
||||
imul playerDirX
|
||||
shrd eax,edx,16
|
||||
mov cross,eax
|
||||
mov eax,velocityX
|
||||
imul playerDirY
|
||||
shrd eax,edx,16
|
||||
sub cross,eax
|
||||
mov eax,cross
|
||||
cdq
|
||||
xor eax,edx
|
||||
sub eax,edx
|
||||
mov sideMagnitude,eax
|
||||
mov eax,dot
|
||||
cmp eax,sideMagnitude
|
||||
jg cast_walk_back
|
||||
neg eax
|
||||
cmp eax,sideMagnitude
|
||||
jg cast_walk_front
|
||||
mov offsetFrame,40
|
||||
cmp cross,0
|
||||
jge cast_walk_phase
|
||||
mov offsetFrame,48
|
||||
jmp cast_walk_phase
|
||||
cast_walk_back:
|
||||
mov offsetFrame,32
|
||||
jmp cast_walk_phase
|
||||
cast_walk_front:
|
||||
mov offsetFrame,24
|
||||
cast_walk_phase:
|
||||
mov eax,clock
|
||||
xor edx,edx
|
||||
mov ecx,FP_1*3/32
|
||||
div ecx
|
||||
and eax,7
|
||||
cast_frame_ready:
|
||||
add eax,offsetFrame
|
||||
add eax,base
|
||||
mov characterLastFrame3D,eax
|
||||
mov [esi].CityProp3D.frame,eax
|
||||
mov [esi].CityProp3D.asset,OFFSET characterCast3D
|
||||
mov [esi].CityProp3D.worldW,CAST_WIDTH
|
||||
mov [esi].CityProp3D.worldH,CAST_HEIGHT
|
||||
mov [esi].CityProp3D.groundZ,-CAST_HEIGHT*4/224
|
||||
ret
|
||||
ConfigureCharacter3D ENDP
|
||||
|
||||
ConfigureRoofVisitor3D PROC uses ebx esi edi slot:DWORD
|
||||
local phase:DWORD,clock:DWORD,vx:DWORD,vy:DWORD
|
||||
mov esi,slot
|
||||
mov phase,CAST_TALK
|
||||
mov eax,roofGuestClock3D
|
||||
mov clock,eax
|
||||
shr eax,12
|
||||
add eax,esi
|
||||
and eax,1
|
||||
jz @F
|
||||
mov phase,CAST_DRINK
|
||||
@@:
|
||||
mov vx,0
|
||||
mov vy,0
|
||||
cmp roofGuestMoving3D[esi*4],0
|
||||
je cast_roof_ready
|
||||
mov phase,CAST_WALK
|
||||
mov eax,roofGuestDistance3D[esi*4]
|
||||
mov clock,eax
|
||||
mov eax,roofGuestDir3D[esi*4]
|
||||
cmp eax,0
|
||||
jne @F
|
||||
mov vx,FP_1
|
||||
jmp cast_roof_ready
|
||||
@@:
|
||||
cmp eax,1
|
||||
jne @F
|
||||
mov vx,-FP_1
|
||||
jmp cast_roof_ready
|
||||
@@:
|
||||
mov vy,FP_1
|
||||
cmp eax,2
|
||||
je cast_roof_ready
|
||||
mov vy,-FP_1
|
||||
cast_roof_ready:
|
||||
invoke ConfigureCharacter3D,OFFSET roofActor3D,roofGuestIdentity3D[esi*4],phase,clock,vx,vy
|
||||
ret
|
||||
ConfigureRoofVisitor3D ENDP
|
||||
30
src_graphics/character_cast_data.inc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
CAST_COUNT equ 10
|
||||
CAST_STRIDE equ 100
|
||||
CAST_IDLE equ 0
|
||||
CAST_TALK equ 1
|
||||
CAST_DRINK equ 2
|
||||
CAST_SEAT equ 3
|
||||
CAST_SEAT_TALK equ 4
|
||||
CAST_SEAT_DRINK equ 5
|
||||
CAST_SIT_DOWN equ 6
|
||||
CAST_STAND_UP equ 7
|
||||
CAST_PICK_UP equ 8
|
||||
CAST_THROW equ 9
|
||||
CAST_CHEER equ 10
|
||||
CAST_WALK equ 11
|
||||
; The hall eye height is 1.05 units. A 1.3-unit canvas puts faces at eye level.
|
||||
CAST_HEIGHT equ FP_1*13/10
|
||||
CAST_WIDTH equ CAST_HEIGHT*192/224
|
||||
LoadCharacterCast3D PROTO
|
||||
FreeCharacterCast3D PROTO
|
||||
ConfigureCharacter3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
ConfigureRoofVisitor3D PROTO :DWORD
|
||||
.data
|
||||
characterCast3D AnimPack3D <>
|
||||
characterCastPath3D db "assets\animations\characters\cast-v1.bin",0
|
||||
characterOffsets3D dd 0,4,8,12,16,20,56,56,64,72,96,24
|
||||
characterLastId3D dd 0
|
||||
characterLastAction3D dd 0
|
||||
characterLastFrame3D dd 0
|
||||
roofGuestIdentity3D dd 0,4,2,1,3,5,6,7
|
||||
.code
|
||||
|
|
@ -5,6 +5,13 @@ cityRayY3D dd SCREEN_W dup(?)
|
|||
; Exterior-only materials do not consume or overwrite the hall's texture slots.
|
||||
ResolveCitySurface3D PROC material:DWORD
|
||||
mov eax,material
|
||||
cmp eax,BW_MATERIAL
|
||||
jb @F
|
||||
cmp eax,BW_LAST_MATERIAL
|
||||
ja @F
|
||||
invoke ResolveBowlingSurface3D,material
|
||||
ret
|
||||
@@:
|
||||
cmp eax,MATERIAL_JACKBOX_FRONT
|
||||
jb @F
|
||||
cmp eax,MATERIAL_JACKBOX_BACK
|
||||
|
|
@ -187,7 +194,10 @@ city_vertical_setup:
|
|||
mov column, 0
|
||||
mov endColumn,SCREEN_W
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
je city_vertical_clip
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne city_vertical_column
|
||||
city_vertical_clip:
|
||||
mov eax,coordinate
|
||||
mov edx,loBound
|
||||
cmp axis,0
|
||||
|
|
@ -469,7 +479,10 @@ city_horizontal_next_corner:
|
|||
cmp corner, 4
|
||||
jb city_horizontal_corner
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
je city_horizontal_check_visible
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
city_horizontal_check_visible:
|
||||
cmp visibleCorners,0
|
||||
je city_horizontal_done
|
||||
@@:
|
||||
|
|
|
|||
|
|
@ -197,6 +197,13 @@ ShadeCityGround3D ENDP
|
|||
|
||||
; Bright warm panes and lantern glass emit light; dark windows/brick do not.
|
||||
IsCityEmissive3D PROC uses ebx rgb:DWORD,material:DWORD
|
||||
cmp material,242
|
||||
jb @F
|
||||
cmp material,BW_LAST_MATERIAL
|
||||
ja @F
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp cityLighting3D, 0
|
||||
je city_not_emissive
|
||||
mov eax, material
|
||||
|
|
|
|||
|
|
@ -170,4 +170,6 @@ include src_graphics\fortune_room_data.inc
|
|||
include src_graphics\fortune_dialog_data.inc
|
||||
include src_graphics\cabaret_data.inc
|
||||
include src_graphics\rooftop_data.inc
|
||||
include src_graphics\bowling_data.inc
|
||||
include src_graphics\character_cast_data.inc
|
||||
.code
|
||||
|
|
|
|||
|
|
@ -194,6 +194,10 @@ interior_begin_finish:
|
|||
BeginWalkableStairs3D ENDP
|
||||
|
||||
UpdateInteriorTravel3D PROC
|
||||
call BowlingTravel3D
|
||||
call UpdateBowling3D
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
je interior_travel_done
|
||||
call UpdateRoof3D
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
je interior_travel_done
|
||||
|
|
@ -413,6 +417,11 @@ UpdateInteriorEye3D PROC
|
|||
je UpdateStairHeight3D
|
||||
cmp engineMode,MODE_WALK
|
||||
jne interior_eye_done
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
call BowlingEye3D
|
||||
ret
|
||||
@@:
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
jne @F
|
||||
call UpdateRoofEye3D
|
||||
|
|
@ -746,7 +755,6 @@ upper_draw_portal:
|
|||
div ecx
|
||||
mov upperLever3D.frame,eax
|
||||
invoke DrawCityObject3D,OFFSET upperLever3D,0
|
||||
mov upperGuest3D.asset,OFFSET npcGuestArt3D
|
||||
xor esi,esi
|
||||
upper_draw_guest:
|
||||
mov eax,upperGuestX3D[esi*4]
|
||||
|
|
@ -754,7 +762,10 @@ upper_draw_guest:
|
|||
mov eax,upperGuestY3D[esi*4]
|
||||
mov upperGuest3D.posY,eax
|
||||
mov eax,upperGuestFrame3D[esi*4]
|
||||
mov upperGuest3D.frame,eax
|
||||
xor edx,edx
|
||||
mov ecx,6
|
||||
div ecx
|
||||
invoke ConfigureCharacter3D,OFFSET upperGuest3D,eax,CAST_SEAT_TALK,animationClock3D,0,0
|
||||
invoke DrawCityObject3D,OFFSET upperGuest3D,0
|
||||
inc esi
|
||||
cmp esi,3
|
||||
|
|
|
|||
|
|
@ -357,6 +357,7 @@ hall_sprites_done:
|
|||
RenderSprites ENDP
|
||||
|
||||
InitHall3D PROC uses esi edi
|
||||
call InitBowling3D
|
||||
call InitRoof3D
|
||||
lea esi, hallLayout3D
|
||||
lea edi, casinoMap
|
||||
|
|
@ -419,12 +420,7 @@ LoadHallAssets3D PROC
|
|||
invoke ValidateCityPack3D, OFFSET cabaretPianoArt3D,384,256,4
|
||||
invoke LoadAnimPack3D, OFFSET cabaretGuitarArt3D, OFFSET cabaretGuitarPath3D
|
||||
invoke ValidateCityPack3D, OFFSET cabaretGuitarArt3D,160,256,4
|
||||
invoke LoadAnimPack3D, OFFSET npcGuestArt3D, OFFSET npcGuestPath3D
|
||||
invoke ValidateCityPack3D, OFFSET npcGuestArt3D,128,224,36
|
||||
invoke LoadAnimPack3D, OFFSET npcWalkArt3D, OFFSET npcWalkPath3D
|
||||
invoke ValidateCityPack3D, OFFSET npcWalkArt3D,128,224,48
|
||||
invoke LoadAnimPack3D, OFFSET npcWalkLeftArt3D, OFFSET npcWalkLeftPath3D
|
||||
invoke ValidateCityPack3D, OFFSET npcWalkLeftArt3D,128,224,48
|
||||
call LoadCharacterCast3D
|
||||
invoke LoadAnimPack3D, OFFSET basementDoorArt3D, OFFSET basementDoorPath3D
|
||||
invoke ValidateCityPack3D, OFFSET basementDoorArt3D,256,512,18
|
||||
call LoadWorldDressing3D
|
||||
|
|
@ -498,6 +494,8 @@ hall_load_sign:
|
|||
LoadHallAssets3D ENDP
|
||||
|
||||
FreeHallAssets3D PROC
|
||||
call FreeCharacterCast3D
|
||||
call FreeBowling3D
|
||||
call FreeRoofAssets3D
|
||||
call FreeFortuneArt3D
|
||||
invoke FreeAnimPack3D, OFFSET upperMaterialArt3D
|
||||
|
|
@ -603,6 +601,11 @@ surface_missing:
|
|||
ResolveWorldSurface3D ENDP
|
||||
|
||||
RenderHall3D PROC uses ebx esi
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
call RenderBowling3D
|
||||
ret
|
||||
@@:
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
jne @F
|
||||
call RenderRoof3D
|
||||
|
|
@ -795,6 +798,11 @@ hall_target_done:
|
|||
HallTarget3D ENDP
|
||||
|
||||
CheckHallInteractions3D PROC
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
call CheckBowlingInteractions3D
|
||||
ret
|
||||
@@:
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
jne @F
|
||||
call CheckRoofInteractions3D
|
||||
|
|
@ -840,6 +848,9 @@ hall_check_bunker:
|
|||
CheckHallInteractions3D ENDP
|
||||
|
||||
TriggerHallInteraction3D PROC
|
||||
call TryBowlingInteraction3D
|
||||
test eax,eax
|
||||
jnz hall_trigger_handled
|
||||
cmp interactTargetId,INTERACT_JACKBOX
|
||||
jne @F
|
||||
call BeginJackbox3D
|
||||
|
|
@ -1027,13 +1038,21 @@ RenderBar3D PROC uses ebx
|
|||
jne @F
|
||||
mov playerX,15*FP_1
|
||||
mov playerY,FP_1*63/10
|
||||
@@:
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
mov playerX,27*FP_1
|
||||
mov playerY,FP_1*66/10
|
||||
@@:
|
||||
mov viewHorizon3D, HALF_H
|
||||
mov viewEye3D, HALL_STANDING_EYE
|
||||
call UpdateCamera3D
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
je bar_world_ready
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
bar_world_ready:
|
||||
call RenderHall3D
|
||||
cmp barPhase3D, 0
|
||||
jne bar_active_scene
|
||||
|
|
@ -1060,6 +1079,10 @@ bar_draw_title:
|
|||
cmp hallLevel3D,HALL_ROOF
|
||||
jne @F
|
||||
mov eax,OFFSET roofBarName3D
|
||||
@@:
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
mov eax,OFFSET bwBarName3D
|
||||
@@:
|
||||
invoke DrawString8x8, 18,15,eax,00E7CA88h
|
||||
cmp barPhase3D, 2
|
||||
|
|
@ -1148,6 +1171,11 @@ city_world_guard_right:
|
|||
RenderCityGuards3D ENDP
|
||||
|
||||
CanWalkHall3D PROC uses esi ebx px:DWORD,py:DWORD
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne @F
|
||||
invoke BowlingCanWalk3D,px,py
|
||||
ret
|
||||
@@:
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
jne @F
|
||||
invoke RoofCanWalk3D,px,py
|
||||
|
|
@ -1466,6 +1494,8 @@ include src_graphics\world_dressing.inc
|
|||
include src_graphics\terminal.inc
|
||||
include src_graphics\hall_expansion.inc
|
||||
include src_graphics\rooftop.inc
|
||||
include src_graphics\bowling.inc
|
||||
include src_graphics\character_cast.inc
|
||||
include src_graphics\steel_door.inc
|
||||
include src_graphics\interior_portals.inc
|
||||
include src_graphics\fortune_room.inc
|
||||
|
|
|
|||
|
|
@ -118,6 +118,10 @@ portal_mask_next:
|
|||
mov oldLevel,eax
|
||||
mov eax,targetLevel
|
||||
mov hallLevel3D,eax
|
||||
cmp eax,HALL_BOWLING
|
||||
jne @F
|
||||
mov viewCeiling3D,6*FP_1
|
||||
@@:
|
||||
mov eax,floorTexture3D
|
||||
mov oldFloor,eax
|
||||
mov eax,targetFloor
|
||||
|
|
@ -128,10 +132,13 @@ portal_mask_next:
|
|||
mov stairRoute3D,eax
|
||||
mov portalRendering3D,1
|
||||
call UpdateCamera3D
|
||||
cmp targetLevel,HALL_BOWLING
|
||||
je portal_target_world_ready
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
call RenderSprites
|
||||
portal_target_world_ready:
|
||||
call RenderHall3D
|
||||
mov portalRendering3D,0
|
||||
mov eax,oldX
|
||||
|
|
@ -198,6 +205,10 @@ RenderInteriorViews3D PROC
|
|||
cmp portalRendering3D,0
|
||||
jne interior_views_done
|
||||
mov portalPixelsWritten3D,0
|
||||
cmp hallLevel3D,0
|
||||
jne @F
|
||||
call RenderBowlingEntrance3D
|
||||
@@:
|
||||
cmp hallLevel3D,3
|
||||
je RenderFortuneViews3D
|
||||
cmp engineMode,MODE_STAIRS
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ npc_life_init:
|
|||
mov npcWalkDistance3D[esi*4],0
|
||||
mov npcWalkVelocityX3D[esi*4],0
|
||||
mov npcWalkVelocityY3D[esi*4],0
|
||||
mov npcRise3D[esi*4],0
|
||||
mov eax,npcStartDest3D[esi*4]
|
||||
mov npcLife3D[ebx].destination,eax
|
||||
imul edi,esi,SIZEOF NpcMindEntity
|
||||
|
|
@ -31,6 +32,7 @@ npc_life_init:
|
|||
jne npc_life_init_next
|
||||
@@:
|
||||
mov npcLife3D[ebx].state,NPC_SIT
|
||||
mov npcLife3D[ebx].poseClock,0
|
||||
npc_life_init_next:
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
|
|
@ -352,6 +354,7 @@ npc_move_arrived:
|
|||
@@:
|
||||
mov npcLife3D[ebx].state,NPC_SIT
|
||||
mov npcLife3D[ebx].remaining,12000
|
||||
mov npcLife3D[ebx].poseClock,0
|
||||
jmp npc_move_done
|
||||
npc_move_blocked:
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
|
|
@ -410,6 +413,13 @@ npc_update_person:
|
|||
add npcLife3D[ebx].poseClock,eax
|
||||
cmp npcLife3D[ebx].state,NPC_WALK
|
||||
jne npc_update_wait
|
||||
cmp npcRise3D[esi*4],0
|
||||
je npc_update_move
|
||||
sub npcRise3D[esi*4],eax
|
||||
ja npc_update_sync
|
||||
mov npcRise3D[esi*4],0
|
||||
jmp npc_update_sync
|
||||
npc_update_move:
|
||||
invoke NpcMove3D,esi,milliseconds
|
||||
jmp npc_update_sync
|
||||
npc_update_wait:
|
||||
|
|
@ -433,12 +443,19 @@ npc_update_choose:
|
|||
mov eax,npcVisitRoute3D[edx*4]
|
||||
mov destination,eax
|
||||
inc npcLife3D[ebx].routeStep
|
||||
mov npcRise3D[esi*4],0
|
||||
cmp npcLife3D[ebx].state,NPC_SIT
|
||||
jne @F
|
||||
mov npcRise3D[esi*4],800
|
||||
@@:
|
||||
invoke NpcPlanPath3D,esi,destination
|
||||
test eax,eax
|
||||
jz npc_update_retry
|
||||
mov npcLife3D[ebx].state,NPC_WALK
|
||||
mov npcLife3D[ebx].poseClock,0
|
||||
jmp npc_update_sync
|
||||
npc_update_retry:
|
||||
mov npcRise3D[esi*4],0
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
mov npcLife3D[ebx].remaining,1000
|
||||
npc_update_sync:
|
||||
|
|
@ -461,6 +478,7 @@ npc_update_done:
|
|||
UpdateNpcLife3D ENDP
|
||||
|
||||
RenderNpcLife3D PROC uses ebx esi edi
|
||||
local castId:DWORD,castAction:DWORD,castClock:DWORD,slot:DWORD
|
||||
cmp npcLifeReady3D,1
|
||||
jne npc_draw_done
|
||||
xor esi,esi
|
||||
|
|
@ -501,55 +519,39 @@ npc_draw_person:
|
|||
mov npcSprite3D.posX,eax
|
||||
mov eax,casinoNpcs3D[edi].posY
|
||||
mov npcSprite3D.posY,eax
|
||||
mov npcSprite3D.worldW,FP_1*3/5
|
||||
mov npcSprite3D.worldH,FP_1*6/5
|
||||
mov npcSprite3D.groundZ,-FP_1*6/5*4/224
|
||||
mov npcSprite3D.asset,OFFSET npcGuestArt3D
|
||||
cmp npcGuestArt3D.pixels,0
|
||||
je npc_draw_next
|
||||
mov eax,npcLife3D[ebx].identity
|
||||
mov eax,npcGuestAppearance3D[eax*4]
|
||||
imul eax,6
|
||||
mov npcSprite3D.frame,eax
|
||||
mov castId,eax
|
||||
mov castAction,CAST_TALK
|
||||
mov eax,npcLife3D[ebx].poseClock
|
||||
mov castClock,eax
|
||||
mov eax,npcDrawOrder3D[esi*4]
|
||||
mov slot,eax
|
||||
cmp npcLife3D[ebx].state,NPC_SIT
|
||||
jne npc_draw_walk
|
||||
add npcSprite3D.frame,5
|
||||
; Seated pose is already shorter within the same foot-anchored canvas.
|
||||
mov npcSprite3D.worldW,FP_1*3/5
|
||||
mov npcSprite3D.worldH,FP_1*6/5
|
||||
mov castAction,CAST_SEAT_TALK
|
||||
cmp castClock,800
|
||||
jae npc_draw_sprite
|
||||
mov castAction,CAST_SIT_DOWN
|
||||
jmp npc_draw_sprite
|
||||
npc_draw_walk:
|
||||
cmp npcLife3D[ebx].state,NPC_WALK
|
||||
jne npc_draw_sprite
|
||||
cmp npcWalkArt3D.pixels,0
|
||||
je npc_draw_sprite
|
||||
mov npcSprite3D.asset,OFFSET npcWalkArt3D
|
||||
mov npcSprite3D.groundZ,0
|
||||
mov eax,npcLife3D[ebx].identity
|
||||
mov eax,npcGuestAppearance3D[eax*4]
|
||||
shl eax,3
|
||||
mov npcSprite3D.frame,eax
|
||||
mov ebx,npcDrawOrder3D[esi*4]
|
||||
mov ebx,slot
|
||||
cmp npcRise3D[ebx*4],0
|
||||
je npc_draw_moving
|
||||
mov castAction,CAST_STAND_UP
|
||||
mov eax,800
|
||||
sub eax,npcRise3D[ebx*4]
|
||||
mov castClock,eax
|
||||
jmp npc_draw_sprite
|
||||
npc_draw_moving:
|
||||
mov castAction,CAST_WALK
|
||||
mov eax,npcWalkDistance3D[ebx*4]
|
||||
xor edx,edx
|
||||
mov ecx,FP_1*3/32
|
||||
div ecx
|
||||
and eax,7
|
||||
add npcSprite3D.frame,eax
|
||||
; Match the drawn facing to the actual camera-relative direction of travel.
|
||||
mov eax,npcWalkVelocityY3D[ebx*4]
|
||||
imul playerDirX
|
||||
shrd eax,edx,16
|
||||
mov edi,eax
|
||||
mov eax,npcWalkVelocityX3D[ebx*4]
|
||||
imul playerDirY
|
||||
shrd eax,edx,16
|
||||
sub edi,eax
|
||||
jns npc_draw_sprite
|
||||
cmp npcWalkLeftArt3D.pixels,0
|
||||
je npc_draw_sprite
|
||||
mov npcSprite3D.asset,OFFSET npcWalkLeftArt3D
|
||||
mov castClock,eax
|
||||
npc_draw_sprite:
|
||||
mov ebx,slot
|
||||
invoke ConfigureCharacter3D,OFFSET npcSprite3D,castId,castAction,castClock,npcWalkVelocityX3D[ebx*4],npcWalkVelocityY3D[ebx*4]
|
||||
invoke DrawCityObject3D,OFFSET npcSprite3D,0
|
||||
npc_draw_next:
|
||||
inc esi
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ npcWalkLeftPath3D db "assets\animations\hall\guest-walk-left-v2.bin",0
|
|||
npcWalkDistance3D dd NPC_LIFE_COUNT dup(0)
|
||||
npcWalkVelocityX3D dd NPC_LIFE_COUNT dup(0)
|
||||
npcWalkVelocityY3D dd NPC_LIFE_COUNT dup(0)
|
||||
; The two rotations share six appearances, with a mixed cast on every visit.
|
||||
npcGuestAppearance3D dd 0,2,4,1,3,5,2,0,4,1,3,5
|
||||
; Keep the twelve-slot historical journal, but resolve every appearance to the shared ten.
|
||||
npcRise3D dd NPC_LIFE_COUNT dup(0)
|
||||
npcGuestAppearance3D dd 0,2,4,1,3,5,6,8,0,7,9,2
|
||||
npcGuestNames3D dd OFFSET npcName0,OFFSET npcName1,OFFSET npcName2,OFFSET npcGuestAnna3D
|
||||
dd OFFSET npcGuestMarina3D,OFFSET npcGuestVera3D,OFFSET npcName6,OFFSET npcName7
|
||||
dd OFFSET npcName8,OFFSET npcGuestOlga3D,OFFSET npcGuestDaria3D,OFFSET npcName11
|
||||
|
|
|
|||
|
|
@ -1117,50 +1117,7 @@ roof_guest_draw:
|
|||
mov roofActor3D.posX,eax
|
||||
mov eax,roofGuestY3D[esi*4]
|
||||
mov roofActor3D.posY,eax
|
||||
mov eax,roofGuestFrame3D[esi*4]
|
||||
mov roofActor3D.frame,eax
|
||||
mov roofActor3D.asset,OFFSET npcGuestArt3D
|
||||
cmp roofGuestMoving3D[esi*4],0
|
||||
je roof_guest_idle
|
||||
cmp npcWalkArt3D.pixels,0
|
||||
je roof_guest_idle
|
||||
xor edx,edx
|
||||
mov ecx,6
|
||||
div ecx
|
||||
shl eax,3
|
||||
mov ebx,eax
|
||||
mov eax,roofGuestDistance3D[esi*4]
|
||||
xor edx,edx
|
||||
mov ecx,FP_1*3/32
|
||||
div ecx
|
||||
and eax,7
|
||||
add eax,ebx
|
||||
mov roofActor3D.frame,eax
|
||||
mov roofActor3D.asset,OFFSET npcWalkArt3D
|
||||
mov eax,roofGuestDir3D[esi*4]
|
||||
mov ecx,playerDirY
|
||||
neg ecx
|
||||
cmp eax,0
|
||||
je roof_guest_facing
|
||||
neg ecx
|
||||
cmp eax,1
|
||||
je roof_guest_facing
|
||||
mov ecx,playerDirX
|
||||
cmp eax,2
|
||||
je roof_guest_facing
|
||||
neg ecx
|
||||
roof_guest_facing:
|
||||
test ecx,ecx
|
||||
jns roof_guest_draw_sprite
|
||||
mov roofActor3D.asset,OFFSET npcWalkLeftArt3D
|
||||
jmp roof_guest_draw_sprite
|
||||
roof_guest_idle:
|
||||
mov eax,roofGuestClock3D
|
||||
shr eax,10
|
||||
add eax,esi
|
||||
and eax,1
|
||||
add roofActor3D.frame,eax
|
||||
roof_guest_draw_sprite:
|
||||
invoke ConfigureRoofVisitor3D,esi
|
||||
invoke DrawCityObject3D,OFFSET roofActor3D,0
|
||||
inc esi
|
||||
cmp esi,ROOF_GUEST_COUNT
|
||||
|
|
|
|||
|
|
@ -93,11 +93,24 @@ LoadAnimPack3D PROC uses ebx esi edi pack:DWORD,path:DWORD
|
|||
mov ecx, [esi].AnimPack3D.frames
|
||||
test ecx, ecx
|
||||
jz anim_close_failure
|
||||
cmp esi,OFFSET characterCast3D
|
||||
jne anim_regular_pack
|
||||
; Only the fixed, shared cast may exceed the ordinary 64-frame/32-MiB cap.
|
||||
cmp [esi].AnimPack3D.imageWidth,192
|
||||
jne anim_close_failure
|
||||
cmp [esi].AnimPack3D.height,224
|
||||
jne anim_close_failure
|
||||
cmp ecx,CAST_COUNT*CAST_STRIDE
|
||||
jne anim_close_failure
|
||||
mov eax,192*224*CAST_COUNT*CAST_STRIDE*4
|
||||
jmp anim_check_payload
|
||||
anim_regular_pack:
|
||||
cmp ecx, 64
|
||||
ja anim_close_failure
|
||||
imul eax, ecx
|
||||
cmp eax, 32*1024*1024
|
||||
ja anim_close_failure
|
||||
anim_check_payload:
|
||||
cmp eax, [esi].AnimPack3D.bytes
|
||||
jne anim_close_failure
|
||||
invoke GetFileSize, ebx, 0
|
||||
|
|
|
|||
141
tools/generators/pack_bowling.py
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
"""Offline bowling art, furniture and collision data. Runtime is native MASM."""
|
||||
from pathlib import Path
|
||||
import json
|
||||
import struct
|
||||
import cv2
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
ART = ROOT/'assets/sprites/bowling'
|
||||
OUT = ROOT/'assets/animations/bowling'
|
||||
|
||||
|
||||
def pack(name, frames):
|
||||
w,h = frames[0].size
|
||||
data = b''.join(f.tobytes('raw','BGRA') for f in frames)
|
||||
(OUT/name).write_bytes(struct.pack('<4s4I',b'ANM1',w,h,len(frames),len(data))+data)
|
||||
|
||||
|
||||
def cells(name, columns, rows, seated=False):
|
||||
source = Image.open(ART/name).convert('RGBA')
|
||||
frames = []
|
||||
for y in range(rows):
|
||||
for x in range(columns):
|
||||
cell = source.crop((round(x*source.width/columns),round(y*source.height/rows),
|
||||
round((x+1)*source.width/columns),round((y+1)*source.height/rows)))
|
||||
a = np.asarray(cell).copy()
|
||||
a[:,:,3] = np.where(a[:,:,3] >= 128,255,0)
|
||||
# Keep the actor, not detached released balls or neighbour-cell fragments.
|
||||
if not seated:
|
||||
count,labels,stats,_ = cv2.connectedComponentsWithStats((a[:,:,3]>0).astype(np.uint8))
|
||||
keep = 1+int(np.argmax(stats[1:,cv2.CC_STAT_AREA]))
|
||||
a[:,:,3] = np.where(labels == keep,255,0)
|
||||
cell = Image.fromarray(a)
|
||||
frames.append(cell)
|
||||
scale = min(240/max(f.getbbox()[3]-f.getbbox()[1] for f in frames),
|
||||
248/max(f.width for f in frames))
|
||||
result = []
|
||||
for cell in frames:
|
||||
box = cell.getbbox()
|
||||
resized = cell.resize((round(cell.width*scale),round(cell.height*scale)),Image.Resampling.LANCZOS)
|
||||
frame = Image.new('RGBA',(256,256))
|
||||
frame.paste(resized,((256-resized.width)//2,250-round(box[3]*scale)))
|
||||
result.append(frame)
|
||||
return result
|
||||
|
||||
|
||||
def tween(a,b,t):
|
||||
a,b = np.asarray(a),np.asarray(b)
|
||||
ga,gb = cv2.cvtColor(a,cv2.COLOR_RGBA2GRAY),cv2.cvtColor(b,cv2.COLOR_RGBA2GRAY)
|
||||
fa = cv2.calcOpticalFlowFarneback(ga,gb,None,.5,4,25,4,5,1.2,0)
|
||||
fb = cv2.calcOpticalFlowFarneback(gb,ga,None,.5,4,25,4,5,1.2,0)
|
||||
xy = np.mgrid[:256,:256][::-1].transpose(1,2,0).astype(np.float32)
|
||||
wa = cv2.remap(a,xy-fa*t,None,cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT)
|
||||
wb = cv2.remap(b,xy-fb*(1-t),None,cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT)
|
||||
return Image.fromarray(np.clip(wa*(1-t)+wb*t,0,255).astype(np.uint8))
|
||||
|
||||
|
||||
def main():
|
||||
OUT.mkdir(parents=True,exist_ok=True)
|
||||
source = Image.open(ART/'materials-v1.png').convert('RGBA')
|
||||
materials = [source.crop((round(x*source.width/4),round(y*source.height/3),
|
||||
round((x+1)*source.width/4),round((y+1)*source.height/3)))
|
||||
.resize((256,256),Image.Resampling.LANCZOS) for y in range(3) for x in range(4)]
|
||||
materials += [Image.new('RGBA',(256,256),(40,210,208,255)),
|
||||
Image.new('RGBA',(256,256),(229,79,65,255))]
|
||||
pack('materials-v1.bin',materials)
|
||||
man,woman = cells('bowler-man-v1.png',4,4),cells('bowler-woman-v1.png',4,2)
|
||||
actors = []
|
||||
for poses in (man,woman):
|
||||
motion = []
|
||||
for a,b in zip(poses[:7],poses[1:8]):
|
||||
motion += [a,tween(a,b,1/3),tween(a,b,2/3)]
|
||||
motion += [poses[7]]*3
|
||||
extras = poses[8:16] if len(poses) == 16 else [poses[0]]*4+[poses[7]]*4
|
||||
actors += motion+extras
|
||||
pack('bowlers-v1.bin',actors)
|
||||
pack('seated-v1.bin',cells('seated-v1.png',4,2,True))
|
||||
preview = Image.new('RGBA',(8*256,2*256))
|
||||
for i,f in enumerate(actors[:24:3]+actors[32:56:3]):
|
||||
preview.paste(f,((i%8)*256,(i//8)*256))
|
||||
preview.save(ART/'bowling-preview.png')
|
||||
props,collisions,seats = [],[],[]
|
||||
def box(a,b,c,d,e,f,m,solid=False):
|
||||
props.append((a,b,c,d,e,f,m))
|
||||
if solid:
|
||||
collisions.append((a-.17,b+.17,c-.17,d+.17))
|
||||
def sofa(x,y,w=2.8):
|
||||
box(x-w/2,x+w/2,y-.45,y+.45,.08,.3,236,True)
|
||||
box(x-w/2+.1,x+w/2-.1,y-.43,y+.36,.3,.4,235)
|
||||
box(x-w/2,x+w/2,y+.3,y+.52,.3,.85,235)
|
||||
for dx in (-w/2,w/2-.16):
|
||||
box(x+dx,x+dx+.16,y-.45,y+.45,.3,.56,240)
|
||||
seats.append((x,y-.1,384))
|
||||
for pair in range(4):
|
||||
x = 3.95+3.8*pair
|
||||
sofa(x,28.1)
|
||||
box(x-.6,x+.6,26.7,27.25,.38,.46,237,True)
|
||||
box(x-.12,x+.12,26.85,27.05,0,.4,238)
|
||||
box(x-.38,x+.38,24.8,26,.05,.62,236,True)
|
||||
box(x-.33,x+.33,24.85,25.8,.62,.72,238)
|
||||
for x in (22,27):
|
||||
for y in (12,18):
|
||||
box(x-1,x+1,y-.75,y+.75,.48,.55,237,True)
|
||||
box(x-.1,x+.1,y-.1,y+.1,0,.49,238)
|
||||
sofa(x,y+1.55,2.2)
|
||||
box(24,30,4.5,5.5,0,1.05,236,True)
|
||||
box(23.9,30.1,4.4,5.6,1.05,1.16,237)
|
||||
box(24,30,1.15,1.45,0,3.1,236,True)
|
||||
for z in (.9,1.7,2.5):
|
||||
box(24,30,1.15,1.8,z,z+.08,238)
|
||||
for x in (25,27,29):
|
||||
box(x-.08,x+.08,6.7,6.86,0,.8,238,True)
|
||||
box(x-.3,x+.3,6.5,7.1,.8,.9,240)
|
||||
seats.append((x,6.8,384))
|
||||
box(19.1,19.3,1,24.8,0,.9,236,True)
|
||||
box(19.05,19.35,1,24.8,.9,1,238)
|
||||
# Floor-standing speakers and the pinsetter housings have real side/back faces.
|
||||
for x in (1.45,18.5):
|
||||
box(x-.3,x+.3,2,2.7,0,2.8,233)
|
||||
data = ['; Generated by pack_bowling.py.','BOWL_PROP_COUNT equ '+str(len(props)),'.data',
|
||||
'bwProps3D LABEL DWORD']
|
||||
for p in props:
|
||||
data.append(' dd '+','.join(str(round(v*65536)) for v in p[:6])+','+str(p[6]))
|
||||
data += ['BOWL_COLLISION_COUNT equ '+str(len(collisions)),'bwCollision3D LABEL DWORD']
|
||||
data += [' dd '+','.join(str(round(v*65536)) for v in p) for p in collisions]
|
||||
data += ['BOWL_SEAT_COUNT equ '+str(len(seats)),'bwSeats3D LABEL DWORD']
|
||||
data += [' dd '+','.join([str(round(p[0]*65536)),str(round(p[1]*65536)),str(p[2])]) for p in seats]
|
||||
room = [[232 if x in (0,31) or y in (0,31) else 0 for x in range(32)] for y in range(32)]
|
||||
data += ['bwMap3D LABEL BYTE']
|
||||
data += [' db '+','.join(map(str,row)) for row in room]
|
||||
data += ['.code']
|
||||
(ROOT/'src_graphics/bowling_layout.inc').write_text('\n'.join(data)+'\n',encoding='ascii')
|
||||
(ART/'packed-v1.json').write_text(json.dumps({'materials':[256,256,14],
|
||||
'bowlers':[256,256,64],'seated':[256,256,8],'lanes':8,'active_lanes':[0,3,6],
|
||||
'room':[30,30,6],'props':len(props),'collisions':collisions,'seats':seats},indent=2)+'\n')
|
||||
print('Packed bowling:',len(props),'solid prop parts, 64 whole-body motion frames, 8 seated poses')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
203
tools/generators/pack_character_cast.py
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
"""Offline normalization of the ten shared, identity-locked visitor sheets."""
|
||||
from pathlib import Path
|
||||
import json
|
||||
import struct
|
||||
import cv2
|
||||
import numpy as np
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
ART = ROOT / 'assets/sprites/characters'
|
||||
OUT = ROOT / 'assets/animations/characters'
|
||||
GENERATED = Path.home()/'.codex/generated_images/019e0a0d-b269-7211-8574-91b6289060a2'
|
||||
SOURCES = [
|
||||
'9d00967e-d22f-43e4-95eb-703f2483d9de', '2ffe5ab3-4c2d-4eaf-beee-7e0c61d55391',
|
||||
'870dca7b-988c-4cba-8555-ecdb4874fd50', 'd2bc0f10-dd34-4dfe-a9be-41593724845d',
|
||||
'a1e8be10-a51c-4c00-b509-993d98fd893a', 'b2fb75d3-169f-479e-b2f6-c8ade1d332b9',
|
||||
'28ab7bb4-a834-48a8-b348-9242957ff8d0', '4dd13bb9-5536-4a1c-99fd-ff24419e3977',
|
||||
'7d44d86f-8047-467f-9321-cb7d2c9980f6', '850f855a-e2d6-469c-844b-afe8756ed291',
|
||||
]
|
||||
DESCRIPTIONS = [
|
||||
'Black-haired man, navy blazer, ivory shirt, burgundy trousers, brown loafers',
|
||||
'Auburn-bob woman, emerald trouser suit, ivory blouse, black flats',
|
||||
'Older stocky bald man, moustache, burgundy waistcoat, white rolled sleeves',
|
||||
'Silver-bob older woman, plum cardigan, teal skirt, pearl necklace',
|
||||
'Dark-skinned bearded man, gray shirt, cobalt trousers, dark sneakers',
|
||||
'Dark-braided woman, coral blouse, charcoal trousers, black loafers',
|
||||
'Young wavy-haired man, glasses, mustard sweater, navy chinos, white sneakers',
|
||||
'Black-pixie woman, gray jacket, burgundy top, navy trousers, black flats',
|
||||
'Silver-haired bearded man, olive blazer, burgundy turtleneck, charcoal trousers',
|
||||
'Curly-haired woman, cobalt belted jumpsuit, white sneakers',
|
||||
]
|
||||
W,H,STRIDE = 192,224,100
|
||||
ACTIONS = {'idle':(0,4), 'talk':(4,4), 'drink':(8,4), 'seat':(12,4),
|
||||
'seat_talk':(16,4), 'seat_drink':(20,4), 'walk_front':(24,8),
|
||||
'walk_back':(32,8), 'walk_right':(40,8), 'walk_left':(48,8),
|
||||
'sit_down':(56,8), 'pick_up':(64,8), 'throw':(72,24), 'cheer':(96,4)}
|
||||
|
||||
|
||||
def isolate_rows(source):
|
||||
a = np.asarray(source.convert('RGBA')).copy()
|
||||
mask = (a[:,:,3] >= 220).astype(np.uint8)
|
||||
projection = mask.sum(axis=1)
|
||||
bounds = [0]
|
||||
for i in range(1,4):
|
||||
middle = a.shape[0]*i//4
|
||||
radius = a.shape[0]//24
|
||||
choices = np.arange(middle-radius,middle+radius+1)
|
||||
cost = projection[choices]+abs(choices-middle)*.15
|
||||
bounds.append(int(choices[np.argmin(cost)]))
|
||||
bounds.append(a.shape[0])
|
||||
poses, boxes = [],[]
|
||||
for row,(top,bottom) in enumerate(zip(bounds,bounds[1:])):
|
||||
band = mask[top:bottom]
|
||||
_,labels,stats,_ = cv2.connectedComponentsWithStats(band)
|
||||
parts = [(i,s) for i,s in enumerate(stats[1:],1)
|
||||
if s[cv2.CC_STAT_AREA] > 650 and s[cv2.CC_STAT_HEIGHT] > (bottom-top)*.35]
|
||||
parts.sort(key=lambda p:p[1][0]+p[1][2]/2)
|
||||
if row == 3 and len(parts) > 8:
|
||||
walking = parts[:-2]
|
||||
parts = [walking[round(i*(len(walking)-1)/5)] for i in range(6)]+parts[-2:]
|
||||
assert len(parts) == 8,(row,len(parts),stats.tolist())
|
||||
for label,s in parts:
|
||||
x,y,w,h,_ = map(int,s)
|
||||
crop = a[top+y:top+y+h,x:x+w].copy()
|
||||
crop[:,:,3] = np.where(labels[y:y+h,x:x+w] == label,255,0)
|
||||
poses.append(Image.fromarray(crop))
|
||||
boxes.append([x,top+y,w,h])
|
||||
reference_height = float(np.median([poses[i].height for i in [0,*range(8,14),*range(16,22)]]))
|
||||
scale = min(202/reference_height,184/max(p.width for p in poses))
|
||||
result = []
|
||||
for pose in poses:
|
||||
size = tuple(max(1,round(v*scale)) for v in pose.size)
|
||||
pose = pose.resize(size,Image.Resampling.LANCZOS)
|
||||
frame = Image.new('RGBA',(W,H))
|
||||
frame.alpha_composite(pose,((W-size[0])//2,220-size[1]))
|
||||
result.append(frame)
|
||||
return result,{'row_boundaries':bounds,'boxes':boxes,'scale':scale,'foot_anchor':[W//2,220]}
|
||||
|
||||
|
||||
def sequence(poses,keys,count,loop=False):
|
||||
frames = []
|
||||
arrays = [np.asarray(poses[k]) for k in keys]
|
||||
xy = np.mgrid[:H,:W][::-1].transpose(1,2,0).astype(np.float32)
|
||||
pairs = list(zip(arrays,arrays[1:]+arrays[:1])) if loop else list(zip(arrays,arrays[1:]))
|
||||
flows = []
|
||||
for a,b in pairs:
|
||||
ga,gb = cv2.cvtColor(a,cv2.COLOR_RGBA2GRAY),cv2.cvtColor(b,cv2.COLOR_RGBA2GRAY)
|
||||
fa = cv2.calcOpticalFlowFarneback(ga,gb,None,.5,3,19,3,5,1.2,0)
|
||||
fb = cv2.calcOpticalFlowFarneback(gb,ga,None,.5,3,19,3,5,1.2,0)
|
||||
# The support plane is invariant; flow must not drag shoes off the canvas.
|
||||
vertical = np.clip((H-12-xy[:,:,1])/36,0,1)
|
||||
horizontal = np.clip(np.minimum(xy[:,:,0],W-1-xy[:,:,0])/12,0,1)
|
||||
for flow in (fa,fb):
|
||||
flow[:,:,1] *= vertical
|
||||
flow[:,:,0] *= horizontal
|
||||
flows.append((fa,fb))
|
||||
for i in range(count):
|
||||
position = i*len(pairs)/(count if loop else count-1)
|
||||
at = min(int(position),len(pairs)-1)
|
||||
t = min(position-at,1)
|
||||
a,b = pairs[at]
|
||||
if t < .001:
|
||||
frames.append(Image.fromarray(a)); continue
|
||||
if t > .999:
|
||||
frames.append(Image.fromarray(b)); continue
|
||||
fa,fb = flows[at]
|
||||
wa = cv2.remap(a,xy-fa*t,None,cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT)
|
||||
wb = cv2.remap(b,xy-fb*(1-t),None,cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT)
|
||||
# Warp one intact pose: crossfading disjoint hands creates extra ghost arms.
|
||||
mix = (wa if t < .5 else wb).copy()
|
||||
mix[:,:,3] = np.where(mix[:,:,3] >= 128,255,0)
|
||||
frames.append(Image.fromarray(mix))
|
||||
return frames
|
||||
|
||||
|
||||
def walking_poses(source, standing_height):
|
||||
"""Crop the replacement contact/passing sheets, sharing one scale per sheet."""
|
||||
a = np.asarray(source.convert('RGBA')).copy()
|
||||
mask = (a[:,:,3] >= 220).astype(np.uint8)
|
||||
projection = mask.sum(axis=1)
|
||||
bounds = [0]
|
||||
for row in (1,2):
|
||||
middle = a.shape[0]*row//3
|
||||
choices = np.arange(middle-a.shape[0]//30,middle+a.shape[0]//30+1)
|
||||
bounds.append(int(choices[np.argmin(projection[choices]+abs(choices-middle)*.2)]))
|
||||
bounds.append(a.shape[0])
|
||||
crops, boxes = [], []
|
||||
for top,bottom in zip(bounds,bounds[1:]):
|
||||
_,labels,stats,_ = cv2.connectedComponentsWithStats(mask[top:bottom])
|
||||
parts = [(i,s) for i,s in enumerate(stats[1:],1)
|
||||
if s[cv2.CC_STAT_AREA] > 650 and s[cv2.CC_STAT_HEIGHT] > (bottom-top)*.5]
|
||||
parts.sort(key=lambda p:p[1][0]+p[1][2]/2)
|
||||
assert len(parts) == 4, ('walking row',top,len(parts))
|
||||
for label,s in parts:
|
||||
x,y,w,h,_ = map(int,s)
|
||||
crop = a[top+y:top+y+h,x:x+w].copy()
|
||||
crop[:,:,3] = np.where(labels[y:y+h,x:x+w] == label,255,0)
|
||||
crops.append(Image.fromarray(crop))
|
||||
boxes.append([x,top+y,w,h])
|
||||
scale = min(standing_height/float(np.median([p.height for p in crops])),
|
||||
184/max(p.width for p in crops),214/max(p.height for p in crops))
|
||||
poses = []
|
||||
for crop in crops:
|
||||
size = tuple(max(1,round(v*scale)) for v in crop.size)
|
||||
crop = crop.resize(size,Image.Resampling.LANCZOS)
|
||||
frame = Image.new('RGBA',(W,H))
|
||||
frame.alpha_composite(crop,((W-size[0])//2,220-size[1]))
|
||||
poses.append(frame)
|
||||
return poses, {'row_boundaries':bounds,'boxes':boxes,'scale':scale}
|
||||
|
||||
|
||||
def main():
|
||||
ART.mkdir(parents=True,exist_ok=True)
|
||||
OUT.mkdir(parents=True,exist_ok=True)
|
||||
metadata,roster = [],Image.new('RGBA',(W*10,H),(22,27,31,255))
|
||||
with (OUT/'cast-v1.bin').open('wb') as target:
|
||||
target.write(struct.pack('<4s4I',b'ANM1',W,H,10*STRIDE,10*STRIDE*W*H*4))
|
||||
for identity,source_id in enumerate(SOURCES):
|
||||
path = ART/f'person-{identity:02}-source-v1.png'
|
||||
if not path.exists():
|
||||
path.write_bytes((GENERATED/f'exec-{source_id}.png').read_bytes())
|
||||
poses,info = isolate_rows(Image.open(path))
|
||||
frames = [poses[0]]*4
|
||||
for keys in ([0,1,0],[0,2,0]):
|
||||
frames += sequence(poses,keys,4)
|
||||
frames += [poses[3]]*4
|
||||
for keys in ([3,4,3],[3,5,3]):
|
||||
frames += sequence(poses,keys,4)
|
||||
walk_path = ART/f'person-{identity:02}-walk-source-v2.png'
|
||||
walk,walk_info = walking_poses(Image.open(walk_path),poses[0].getbbox()[3]-poses[0].getbbox()[1])
|
||||
info['walking_v2'] = {'source':walk_path.name,**walk_info}
|
||||
front = sequence(walk,list(range(4)),8,True)
|
||||
back = sequence(walk,list(range(4,8)),8,True)
|
||||
right = sequence(walk,list(range(8,12)),8,True)
|
||||
walk_contact = Image.new('RGBA',(W*8,H*4),(22,27,31,255))
|
||||
for index,frame in enumerate(front+back+right+[ImageOps.mirror(f) for f in right]):
|
||||
walk_contact.alpha_composite(frame,((index%8)*W,(index//8)*H))
|
||||
walk_contact.save(ART/f'person-{identity:02}-walk-normalized-v2.png')
|
||||
frames += front+back+right+[ImageOps.mirror(f) for f in right]
|
||||
frames += sequence(poses,[0,6,3],8)
|
||||
frames += sequence(poses,[0,7,22],8)
|
||||
frames += sequence(poses,[22,23,30,31],24)
|
||||
frames += sequence(poses,[0,15,0],4)
|
||||
assert len(frames) == STRIDE
|
||||
for frame in frames:
|
||||
target.write(frame.tobytes('raw','BGRA'))
|
||||
roster.alpha_composite(poses[0],(identity*W,0))
|
||||
contact = Image.new('RGBA',(W*8,H*4),(22,27,31,255))
|
||||
for i,frame in enumerate(poses):
|
||||
contact.alpha_composite(frame,((i%8)*W,(i//8)*H))
|
||||
contact.save(ART/f'person-{identity:02}-normalized-v1.png')
|
||||
motion = front+back+right+frames[56:96]
|
||||
motion[0].save(ART/f'person-{identity:02}-motion-v1.gif',save_all=True,
|
||||
append_images=motion[1:],duration=100,loop=0,disposal=2)
|
||||
metadata.append({'id':identity,'description':DESCRIPTIONS[identity],**info})
|
||||
print('Packed shared character',identity,flush=True)
|
||||
roster.save(ART/'roster-v1.png')
|
||||
(ART/'cast-v1.json').write_text(json.dumps({'dimensions':[W,H],'characters':metadata,
|
||||
'stride':STRIDE,'actions':ACTIONS,'generation':'built-in imagegen; one identity-locked full sheet per person'},indent=2)+'\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
240
tools/tests/bowling_test.inc
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
.data
|
||||
bwTestEntrance db "build\hall-expansion\bowling-entrance.bmp",0
|
||||
bwTestOverview db "build\hall-expansion\bowling-overview.bmp",0
|
||||
bwTestRestaurant db "build\hall-expansion\bowling-restaurant.bmp",0
|
||||
bwTestLanes db "build\hall-expansion\bowling-lanes.bmp",0
|
||||
bwTestBar db "build\hall-expansion\bowling-bar.bmp",0
|
||||
bwTestExit db "build\hall-expansion\bowling-exit.bmp",0
|
||||
bwTestThrow0 db "build\hall-expansion\bowling-throw-0.bmp",0
|
||||
bwTestThrow1 db "build\hall-expansion\bowling-throw-1.bmp",0
|
||||
bwTestThrow2 db "build\hall-expansion\bowling-throw-2.bmp",0
|
||||
bwTestThrow3 db "build\hall-expansion\bowling-throw-3.bmp",0
|
||||
bwTestThrowPaths dd OFFSET bwTestThrow0,OFFSET bwTestThrow1,OFFSET bwTestThrow2,OFFSET bwTestThrow3
|
||||
.code
|
||||
BowlingNativeTests PROC uses ebx esi edi
|
||||
local bank:DWORD
|
||||
mov expansionStage,120
|
||||
mov eax,bankroll
|
||||
mov bank,eax
|
||||
call InitBowling3D
|
||||
call LoadBowling3D
|
||||
cmp bwArt3D.frames,14
|
||||
jne bw_test_fail
|
||||
mov expansionStage,131
|
||||
cmp characterCast3D.frames,CAST_COUNT*CAST_STRIDE
|
||||
jne bw_test_fail
|
||||
mov expansionStage,132
|
||||
; Standard ten-frame scoring vectors, including tenth-frame bonuses.
|
||||
lea edi,bwRolls3D
|
||||
mov eax,10
|
||||
mov ecx,12
|
||||
rep stosd
|
||||
mov bwRollCount3D,12
|
||||
invoke BowlingScore3D,0
|
||||
cmp eax,300
|
||||
jne bw_test_fail
|
||||
lea edi,bwRolls3D
|
||||
mov eax,5
|
||||
mov ecx,21
|
||||
rep stosd
|
||||
mov bwRollCount3D,21
|
||||
invoke BowlingScore3D,0
|
||||
cmp eax,150
|
||||
jne bw_test_fail
|
||||
lea edi,bwRolls3D
|
||||
mov eax,1
|
||||
mov ecx,20
|
||||
rep stosd
|
||||
mov bwRollCount3D,20
|
||||
invoke BowlingScore3D,0
|
||||
cmp eax,20
|
||||
jne bw_test_fail
|
||||
call InitBowling3D
|
||||
invoke BowlingRegisterRoll3D,0,5
|
||||
cmp bwBall3D,1
|
||||
jne bw_test_fail
|
||||
cmp bwFrames3D,0
|
||||
jne bw_test_fail
|
||||
invoke BowlingRegisterRoll3D,0,5
|
||||
cmp bwFrames3D,1
|
||||
jne bw_test_fail
|
||||
cmp bwFrameDone3D,1
|
||||
jne bw_test_fail
|
||||
call InitBowling3D
|
||||
mov bwFrames3D,9
|
||||
invoke BowlingRegisterRoll3D,0,10
|
||||
cmp bwBall3D,1
|
||||
jne bw_test_fail
|
||||
invoke BowlingRegisterRoll3D,0,10
|
||||
cmp bwBall3D,2
|
||||
jne bw_test_fail
|
||||
invoke BowlingRegisterRoll3D,0,10
|
||||
cmp bwFrames3D,10
|
||||
jne bw_test_fail
|
||||
mov expansionStage,121
|
||||
call InitBowling3D
|
||||
mov hallLevel3D,0
|
||||
mov engineMode,MODE_WALK
|
||||
mov worldMap3D,OFFSET casinoMap
|
||||
mov playerX,5*FP_1
|
||||
mov playerY,5*FP_1
|
||||
mov playerAngle,384
|
||||
call UpdateInteriorEye3D
|
||||
mov esi,5*FP_1
|
||||
bw_test_entrance_walk:
|
||||
invoke CanWalk3D,5*FP_1,esi
|
||||
test eax,eax
|
||||
jz bw_test_fail
|
||||
sub esi,FP_1/10
|
||||
cmp esi,FP_1*14/10
|
||||
jae bw_test_entrance_walk
|
||||
call ExpansionFrame
|
||||
invoke ExpansionSnapshot,OFFSET bwTestEntrance
|
||||
cmp portalPixelsWritten3D,1000
|
||||
jb bw_test_fail
|
||||
mov expansionStage,125
|
||||
mov playerY,FP_1*14/10
|
||||
call BowlingTravel3D
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
jne bw_test_fail
|
||||
cmp playerX,17*FP_1
|
||||
jne bw_test_fail
|
||||
cmp playerY,FP_1*304/10
|
||||
jne bw_test_fail
|
||||
cmp viewCeiling3D,6*FP_1
|
||||
jne bw_test_fail
|
||||
mov expansionStage,126
|
||||
invoke CanWalk3D,18*FP_1,25*FP_1
|
||||
test eax,eax
|
||||
jz bw_test_fail
|
||||
invoke CanWalk3D,8*FP_1,10*FP_1
|
||||
test eax,eax
|
||||
jnz bw_test_fail
|
||||
invoke CanWalk3D,22*FP_1,12*FP_1
|
||||
test eax,eax
|
||||
jnz bw_test_fail
|
||||
mov expansionStage,122
|
||||
mov esi,12000
|
||||
bw_test_simulate:
|
||||
mov deltaTime3D,50
|
||||
add animationClock3D,50
|
||||
call UpdateBowling3D
|
||||
xor edi,edi
|
||||
bw_test_bounds:
|
||||
cmp bwRollCount3D[edi*4],21
|
||||
ja bw_test_fail
|
||||
cmp bwFrames3D[edi*4],10
|
||||
ja bw_test_fail
|
||||
cmp bwScores3D[edi*4],300
|
||||
ja bw_test_fail
|
||||
inc edi
|
||||
cmp edi,16
|
||||
jb bw_test_bounds
|
||||
dec esi
|
||||
jnz bw_test_simulate
|
||||
mov expansionStage,123
|
||||
mov playerX,17*FP_1
|
||||
mov playerY,FP_1*301/10
|
||||
mov playerAngle,350
|
||||
call UpdateInteriorEye3D
|
||||
call UpdateCamera3D
|
||||
call RenderBowling3D
|
||||
invoke ExpansionSnapshot,OFFSET bwTestOverview
|
||||
mov playerX,18*FP_1
|
||||
mov playerY,24*FP_1
|
||||
mov playerAngle,330
|
||||
call UpdateCamera3D
|
||||
call RenderBowling3D
|
||||
invoke ExpansionSnapshot,OFFSET bwTestLanes
|
||||
mov playerX,21*FP_1
|
||||
mov playerY,26*FP_1
|
||||
mov playerAngle,420
|
||||
call UpdateCamera3D
|
||||
call RenderBowling3D
|
||||
invoke ExpansionSnapshot,OFFSET bwTestRestaurant
|
||||
mov playerX,23*FP_1
|
||||
mov playerY,8*FP_1
|
||||
mov playerAngle,420
|
||||
call UpdateCamera3D
|
||||
call RenderBowling3D
|
||||
invoke ExpansionSnapshot,OFFSET bwTestBar
|
||||
mov expansionStage,124
|
||||
mov playerX,6*FP_1
|
||||
mov playerY,FP_1*277/10
|
||||
mov playerAngle,350
|
||||
mov bwState3D,2
|
||||
xor esi,esi
|
||||
bw_test_throw_frames:
|
||||
imul eax,esi,650
|
||||
mov bwTime3D,eax
|
||||
call UpdateCamera3D
|
||||
call RenderBowling3D
|
||||
invoke ExpansionSnapshot,bwTestThrowPaths[esi*4]
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb bw_test_throw_frames
|
||||
mov bwSeatTarget3D,0
|
||||
mov interactTargetId,INTERACT_BOWL_SEAT
|
||||
call TryBowlingInteraction3D
|
||||
cmp bwSeat3D,1
|
||||
jne bw_test_fail
|
||||
cmp viewEye3D,FP_1*12/10
|
||||
jne bw_test_fail
|
||||
mov interactTargetId,INTERACT_BOWL_SEAT
|
||||
call TryBowlingInteraction3D
|
||||
cmp bwSeat3D,0
|
||||
jne bw_test_fail
|
||||
cmp playerX,6*FP_1
|
||||
jne bw_test_fail
|
||||
mov expansionStage,127
|
||||
mov edi,4
|
||||
bw_test_bar_visits:
|
||||
mov engineMode,MODE_BAR
|
||||
mov barPhase3D,0
|
||||
invoke BuyBarDrink3D,2
|
||||
call RenderBar3D
|
||||
cmp playerX,6*FP_1
|
||||
jne bw_test_fail
|
||||
cmp playerY,FP_1*277/10
|
||||
jne bw_test_fail
|
||||
cmp playerAngle,350
|
||||
jne bw_test_fail
|
||||
mov deltaTime3D,3000
|
||||
call HandleBar3D
|
||||
call RenderBar3D
|
||||
mov deltaTime3D,2400
|
||||
call HandleBar3D
|
||||
mov engineMode,MODE_WALK
|
||||
call UpdateInteriorEye3D
|
||||
cmp viewEye3D,HALL_STANDING_EYE
|
||||
jne bw_test_fail
|
||||
cmp viewCeiling3D,6*FP_1
|
||||
jne bw_test_fail
|
||||
dec edi
|
||||
jnz bw_test_bar_visits
|
||||
mov expansionStage,124
|
||||
mov playerX,17*FP_1
|
||||
mov playerY,29*FP_1
|
||||
mov playerAngle,128
|
||||
call UpdateCamera3D
|
||||
call RenderBowling3D
|
||||
invoke ExpansionSnapshot,OFFSET bwTestExit
|
||||
mov playerY,FP_1*306/10
|
||||
call BowlingTravel3D
|
||||
cmp hallLevel3D,0
|
||||
jne bw_test_fail
|
||||
cmp playerX,5*FP_1
|
||||
jne bw_test_fail
|
||||
cmp playerY,FP_1*16/10
|
||||
jne bw_test_fail
|
||||
mov eax,bankroll
|
||||
cmp eax,bank
|
||||
jne bw_test_fail
|
||||
mov engineMode,MODE_WALK
|
||||
call ClearKeys3D
|
||||
call CharacterCastNativeTests
|
||||
ret
|
||||
bw_test_fail:
|
||||
invoke ExitProcess,expansionStage
|
||||
ret
|
||||
BowlingNativeTests ENDP
|
||||
267
tools/tests/character_cast_test.inc
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
.data
|
||||
castTestObject CityProp3D <16*FP_1,16*FP_1,CAST_WIDTH,CAST_HEIGHT,0,OFFSET characterCast3D>
|
||||
castTestActions dd CAST_IDLE,CAST_WALK,CAST_WALK,CAST_SEAT_DRINK,CAST_PICK_UP,CAST_THROW
|
||||
castTestClocks dd 0,FP_1*9/32,FP_1*9/32,360,700,1800
|
||||
castPath0_0 db "build\hall-expansion\cast-0-0.bmp",0
|
||||
castPath0_1 db "build\hall-expansion\cast-0-1.bmp",0
|
||||
castPath0_2 db "build\hall-expansion\cast-0-2.bmp",0
|
||||
castPath0_3 db "build\hall-expansion\cast-0-3.bmp",0
|
||||
castPath0_4 db "build\hall-expansion\cast-0-4.bmp",0
|
||||
castPath0_5 db "build\hall-expansion\cast-0-5.bmp",0
|
||||
castPath1_0 db "build\hall-expansion\cast-1-0.bmp",0
|
||||
castPath1_1 db "build\hall-expansion\cast-1-1.bmp",0
|
||||
castPath1_2 db "build\hall-expansion\cast-1-2.bmp",0
|
||||
castPath1_3 db "build\hall-expansion\cast-1-3.bmp",0
|
||||
castPath1_4 db "build\hall-expansion\cast-1-4.bmp",0
|
||||
castPath1_5 db "build\hall-expansion\cast-1-5.bmp",0
|
||||
castPath2_0 db "build\hall-expansion\cast-2-0.bmp",0
|
||||
castPath2_1 db "build\hall-expansion\cast-2-1.bmp",0
|
||||
castPath2_2 db "build\hall-expansion\cast-2-2.bmp",0
|
||||
castPath2_3 db "build\hall-expansion\cast-2-3.bmp",0
|
||||
castPath2_4 db "build\hall-expansion\cast-2-4.bmp",0
|
||||
castPath2_5 db "build\hall-expansion\cast-2-5.bmp",0
|
||||
castPath3_0 db "build\hall-expansion\cast-3-0.bmp",0
|
||||
castPath3_1 db "build\hall-expansion\cast-3-1.bmp",0
|
||||
castPath3_2 db "build\hall-expansion\cast-3-2.bmp",0
|
||||
castPath3_3 db "build\hall-expansion\cast-3-3.bmp",0
|
||||
castPath3_4 db "build\hall-expansion\cast-3-4.bmp",0
|
||||
castPath3_5 db "build\hall-expansion\cast-3-5.bmp",0
|
||||
castPath4_0 db "build\hall-expansion\cast-4-0.bmp",0
|
||||
castPath4_1 db "build\hall-expansion\cast-4-1.bmp",0
|
||||
castPath4_2 db "build\hall-expansion\cast-4-2.bmp",0
|
||||
castPath4_3 db "build\hall-expansion\cast-4-3.bmp",0
|
||||
castPath4_4 db "build\hall-expansion\cast-4-4.bmp",0
|
||||
castPath4_5 db "build\hall-expansion\cast-4-5.bmp",0
|
||||
castPath5_0 db "build\hall-expansion\cast-5-0.bmp",0
|
||||
castPath5_1 db "build\hall-expansion\cast-5-1.bmp",0
|
||||
castPath5_2 db "build\hall-expansion\cast-5-2.bmp",0
|
||||
castPath5_3 db "build\hall-expansion\cast-5-3.bmp",0
|
||||
castPath5_4 db "build\hall-expansion\cast-5-4.bmp",0
|
||||
castPath5_5 db "build\hall-expansion\cast-5-5.bmp",0
|
||||
castPath6_0 db "build\hall-expansion\cast-6-0.bmp",0
|
||||
castPath6_1 db "build\hall-expansion\cast-6-1.bmp",0
|
||||
castPath6_2 db "build\hall-expansion\cast-6-2.bmp",0
|
||||
castPath6_3 db "build\hall-expansion\cast-6-3.bmp",0
|
||||
castPath6_4 db "build\hall-expansion\cast-6-4.bmp",0
|
||||
castPath6_5 db "build\hall-expansion\cast-6-5.bmp",0
|
||||
castPath7_0 db "build\hall-expansion\cast-7-0.bmp",0
|
||||
castPath7_1 db "build\hall-expansion\cast-7-1.bmp",0
|
||||
castPath7_2 db "build\hall-expansion\cast-7-2.bmp",0
|
||||
castPath7_3 db "build\hall-expansion\cast-7-3.bmp",0
|
||||
castPath7_4 db "build\hall-expansion\cast-7-4.bmp",0
|
||||
castPath7_5 db "build\hall-expansion\cast-7-5.bmp",0
|
||||
castPath8_0 db "build\hall-expansion\cast-8-0.bmp",0
|
||||
castPath8_1 db "build\hall-expansion\cast-8-1.bmp",0
|
||||
castPath8_2 db "build\hall-expansion\cast-8-2.bmp",0
|
||||
castPath8_3 db "build\hall-expansion\cast-8-3.bmp",0
|
||||
castPath8_4 db "build\hall-expansion\cast-8-4.bmp",0
|
||||
castPath8_5 db "build\hall-expansion\cast-8-5.bmp",0
|
||||
castPath9_0 db "build\hall-expansion\cast-9-0.bmp",0
|
||||
castPath9_1 db "build\hall-expansion\cast-9-1.bmp",0
|
||||
castPath9_2 db "build\hall-expansion\cast-9-2.bmp",0
|
||||
castPath9_3 db "build\hall-expansion\cast-9-3.bmp",0
|
||||
castPath9_4 db "build\hall-expansion\cast-9-4.bmp",0
|
||||
castPath9_5 db "build\hall-expansion\cast-9-5.bmp",0
|
||||
castTestPaths LABEL DWORD
|
||||
dd OFFSET castPath0_0,OFFSET castPath0_1,OFFSET castPath0_2,OFFSET castPath0_3,OFFSET castPath0_4,OFFSET castPath0_5
|
||||
dd OFFSET castPath1_0,OFFSET castPath1_1,OFFSET castPath1_2,OFFSET castPath1_3,OFFSET castPath1_4,OFFSET castPath1_5
|
||||
dd OFFSET castPath2_0,OFFSET castPath2_1,OFFSET castPath2_2,OFFSET castPath2_3,OFFSET castPath2_4,OFFSET castPath2_5
|
||||
dd OFFSET castPath3_0,OFFSET castPath3_1,OFFSET castPath3_2,OFFSET castPath3_3,OFFSET castPath3_4,OFFSET castPath3_5
|
||||
dd OFFSET castPath4_0,OFFSET castPath4_1,OFFSET castPath4_2,OFFSET castPath4_3,OFFSET castPath4_4,OFFSET castPath4_5
|
||||
dd OFFSET castPath5_0,OFFSET castPath5_1,OFFSET castPath5_2,OFFSET castPath5_3,OFFSET castPath5_4,OFFSET castPath5_5
|
||||
dd OFFSET castPath6_0,OFFSET castPath6_1,OFFSET castPath6_2,OFFSET castPath6_3,OFFSET castPath6_4,OFFSET castPath6_5
|
||||
dd OFFSET castPath7_0,OFFSET castPath7_1,OFFSET castPath7_2,OFFSET castPath7_3,OFFSET castPath7_4,OFFSET castPath7_5
|
||||
dd OFFSET castPath8_0,OFFSET castPath8_1,OFFSET castPath8_2,OFFSET castPath8_3,OFFSET castPath8_4,OFFSET castPath8_5
|
||||
dd OFFSET castPath9_0,OFFSET castPath9_1,OFFSET castPath9_2,OFFSET castPath9_3,OFFSET castPath9_4,OFFSET castPath9_5
|
||||
castWalk0_0 db "build\hall-expansion\cast-walk-0-0.bmp",0
|
||||
castWalk0_1 db "build\hall-expansion\cast-walk-0-1.bmp",0
|
||||
castWalk0_2 db "build\hall-expansion\cast-walk-0-2.bmp",0
|
||||
castWalk0_3 db "build\hall-expansion\cast-walk-0-3.bmp",0
|
||||
castWalk0_4 db "build\hall-expansion\cast-walk-0-4.bmp",0
|
||||
castWalk0_5 db "build\hall-expansion\cast-walk-0-5.bmp",0
|
||||
castWalk0_6 db "build\hall-expansion\cast-walk-0-6.bmp",0
|
||||
castWalk0_7 db "build\hall-expansion\cast-walk-0-7.bmp",0
|
||||
castWalk1_0 db "build\hall-expansion\cast-walk-1-0.bmp",0
|
||||
castWalk1_1 db "build\hall-expansion\cast-walk-1-1.bmp",0
|
||||
castWalk1_2 db "build\hall-expansion\cast-walk-1-2.bmp",0
|
||||
castWalk1_3 db "build\hall-expansion\cast-walk-1-3.bmp",0
|
||||
castWalk1_4 db "build\hall-expansion\cast-walk-1-4.bmp",0
|
||||
castWalk1_5 db "build\hall-expansion\cast-walk-1-5.bmp",0
|
||||
castWalk1_6 db "build\hall-expansion\cast-walk-1-6.bmp",0
|
||||
castWalk1_7 db "build\hall-expansion\cast-walk-1-7.bmp",0
|
||||
castWalk2_0 db "build\hall-expansion\cast-walk-2-0.bmp",0
|
||||
castWalk2_1 db "build\hall-expansion\cast-walk-2-1.bmp",0
|
||||
castWalk2_2 db "build\hall-expansion\cast-walk-2-2.bmp",0
|
||||
castWalk2_3 db "build\hall-expansion\cast-walk-2-3.bmp",0
|
||||
castWalk2_4 db "build\hall-expansion\cast-walk-2-4.bmp",0
|
||||
castWalk2_5 db "build\hall-expansion\cast-walk-2-5.bmp",0
|
||||
castWalk2_6 db "build\hall-expansion\cast-walk-2-6.bmp",0
|
||||
castWalk2_7 db "build\hall-expansion\cast-walk-2-7.bmp",0
|
||||
castWalk3_0 db "build\hall-expansion\cast-walk-3-0.bmp",0
|
||||
castWalk3_1 db "build\hall-expansion\cast-walk-3-1.bmp",0
|
||||
castWalk3_2 db "build\hall-expansion\cast-walk-3-2.bmp",0
|
||||
castWalk3_3 db "build\hall-expansion\cast-walk-3-3.bmp",0
|
||||
castWalk3_4 db "build\hall-expansion\cast-walk-3-4.bmp",0
|
||||
castWalk3_5 db "build\hall-expansion\cast-walk-3-5.bmp",0
|
||||
castWalk3_6 db "build\hall-expansion\cast-walk-3-6.bmp",0
|
||||
castWalk3_7 db "build\hall-expansion\cast-walk-3-7.bmp",0
|
||||
castWalk4_0 db "build\hall-expansion\cast-walk-4-0.bmp",0
|
||||
castWalk4_1 db "build\hall-expansion\cast-walk-4-1.bmp",0
|
||||
castWalk4_2 db "build\hall-expansion\cast-walk-4-2.bmp",0
|
||||
castWalk4_3 db "build\hall-expansion\cast-walk-4-3.bmp",0
|
||||
castWalk4_4 db "build\hall-expansion\cast-walk-4-4.bmp",0
|
||||
castWalk4_5 db "build\hall-expansion\cast-walk-4-5.bmp",0
|
||||
castWalk4_6 db "build\hall-expansion\cast-walk-4-6.bmp",0
|
||||
castWalk4_7 db "build\hall-expansion\cast-walk-4-7.bmp",0
|
||||
castWalk5_0 db "build\hall-expansion\cast-walk-5-0.bmp",0
|
||||
castWalk5_1 db "build\hall-expansion\cast-walk-5-1.bmp",0
|
||||
castWalk5_2 db "build\hall-expansion\cast-walk-5-2.bmp",0
|
||||
castWalk5_3 db "build\hall-expansion\cast-walk-5-3.bmp",0
|
||||
castWalk5_4 db "build\hall-expansion\cast-walk-5-4.bmp",0
|
||||
castWalk5_5 db "build\hall-expansion\cast-walk-5-5.bmp",0
|
||||
castWalk5_6 db "build\hall-expansion\cast-walk-5-6.bmp",0
|
||||
castWalk5_7 db "build\hall-expansion\cast-walk-5-7.bmp",0
|
||||
castWalk6_0 db "build\hall-expansion\cast-walk-6-0.bmp",0
|
||||
castWalk6_1 db "build\hall-expansion\cast-walk-6-1.bmp",0
|
||||
castWalk6_2 db "build\hall-expansion\cast-walk-6-2.bmp",0
|
||||
castWalk6_3 db "build\hall-expansion\cast-walk-6-3.bmp",0
|
||||
castWalk6_4 db "build\hall-expansion\cast-walk-6-4.bmp",0
|
||||
castWalk6_5 db "build\hall-expansion\cast-walk-6-5.bmp",0
|
||||
castWalk6_6 db "build\hall-expansion\cast-walk-6-6.bmp",0
|
||||
castWalk6_7 db "build\hall-expansion\cast-walk-6-7.bmp",0
|
||||
castWalk7_0 db "build\hall-expansion\cast-walk-7-0.bmp",0
|
||||
castWalk7_1 db "build\hall-expansion\cast-walk-7-1.bmp",0
|
||||
castWalk7_2 db "build\hall-expansion\cast-walk-7-2.bmp",0
|
||||
castWalk7_3 db "build\hall-expansion\cast-walk-7-3.bmp",0
|
||||
castWalk7_4 db "build\hall-expansion\cast-walk-7-4.bmp",0
|
||||
castWalk7_5 db "build\hall-expansion\cast-walk-7-5.bmp",0
|
||||
castWalk7_6 db "build\hall-expansion\cast-walk-7-6.bmp",0
|
||||
castWalk7_7 db "build\hall-expansion\cast-walk-7-7.bmp",0
|
||||
castWalk8_0 db "build\hall-expansion\cast-walk-8-0.bmp",0
|
||||
castWalk8_1 db "build\hall-expansion\cast-walk-8-1.bmp",0
|
||||
castWalk8_2 db "build\hall-expansion\cast-walk-8-2.bmp",0
|
||||
castWalk8_3 db "build\hall-expansion\cast-walk-8-3.bmp",0
|
||||
castWalk8_4 db "build\hall-expansion\cast-walk-8-4.bmp",0
|
||||
castWalk8_5 db "build\hall-expansion\cast-walk-8-5.bmp",0
|
||||
castWalk8_6 db "build\hall-expansion\cast-walk-8-6.bmp",0
|
||||
castWalk8_7 db "build\hall-expansion\cast-walk-8-7.bmp",0
|
||||
castWalk9_0 db "build\hall-expansion\cast-walk-9-0.bmp",0
|
||||
castWalk9_1 db "build\hall-expansion\cast-walk-9-1.bmp",0
|
||||
castWalk9_2 db "build\hall-expansion\cast-walk-9-2.bmp",0
|
||||
castWalk9_3 db "build\hall-expansion\cast-walk-9-3.bmp",0
|
||||
castWalk9_4 db "build\hall-expansion\cast-walk-9-4.bmp",0
|
||||
castWalk9_5 db "build\hall-expansion\cast-walk-9-5.bmp",0
|
||||
castWalk9_6 db "build\hall-expansion\cast-walk-9-6.bmp",0
|
||||
castWalk9_7 db "build\hall-expansion\cast-walk-9-7.bmp",0
|
||||
castWalkPaths LABEL DWORD
|
||||
dd OFFSET castWalk0_0,OFFSET castWalk0_1,OFFSET castWalk0_2,OFFSET castWalk0_3,OFFSET castWalk0_4,OFFSET castWalk0_5,OFFSET castWalk0_6,OFFSET castWalk0_7
|
||||
dd OFFSET castWalk1_0,OFFSET castWalk1_1,OFFSET castWalk1_2,OFFSET castWalk1_3,OFFSET castWalk1_4,OFFSET castWalk1_5,OFFSET castWalk1_6,OFFSET castWalk1_7
|
||||
dd OFFSET castWalk2_0,OFFSET castWalk2_1,OFFSET castWalk2_2,OFFSET castWalk2_3,OFFSET castWalk2_4,OFFSET castWalk2_5,OFFSET castWalk2_6,OFFSET castWalk2_7
|
||||
dd OFFSET castWalk3_0,OFFSET castWalk3_1,OFFSET castWalk3_2,OFFSET castWalk3_3,OFFSET castWalk3_4,OFFSET castWalk3_5,OFFSET castWalk3_6,OFFSET castWalk3_7
|
||||
dd OFFSET castWalk4_0,OFFSET castWalk4_1,OFFSET castWalk4_2,OFFSET castWalk4_3,OFFSET castWalk4_4,OFFSET castWalk4_5,OFFSET castWalk4_6,OFFSET castWalk4_7
|
||||
dd OFFSET castWalk5_0,OFFSET castWalk5_1,OFFSET castWalk5_2,OFFSET castWalk5_3,OFFSET castWalk5_4,OFFSET castWalk5_5,OFFSET castWalk5_6,OFFSET castWalk5_7
|
||||
dd OFFSET castWalk6_0,OFFSET castWalk6_1,OFFSET castWalk6_2,OFFSET castWalk6_3,OFFSET castWalk6_4,OFFSET castWalk6_5,OFFSET castWalk6_6,OFFSET castWalk6_7
|
||||
dd OFFSET castWalk7_0,OFFSET castWalk7_1,OFFSET castWalk7_2,OFFSET castWalk7_3,OFFSET castWalk7_4,OFFSET castWalk7_5,OFFSET castWalk7_6,OFFSET castWalk7_7
|
||||
dd OFFSET castWalk8_0,OFFSET castWalk8_1,OFFSET castWalk8_2,OFFSET castWalk8_3,OFFSET castWalk8_4,OFFSET castWalk8_5,OFFSET castWalk8_6,OFFSET castWalk8_7
|
||||
dd OFFSET castWalk9_0,OFFSET castWalk9_1,OFFSET castWalk9_2,OFFSET castWalk9_3,OFFSET castWalk9_4,OFFSET castWalk9_5,OFFSET castWalk9_6,OFFSET castWalk9_7
|
||||
.code
|
||||
CharacterCastNativeTests PROC uses ebx esi edi
|
||||
local phase:DWORD,time:DWORD,vx:DWORD,vy:DWORD
|
||||
mov expansionStage,130
|
||||
call LoadCharacterCast3D
|
||||
cmp characterCast3D.frames,CAST_COUNT*CAST_STRIDE
|
||||
jne cast_test_fail
|
||||
cmp npcGuestArt3D.pixels,0
|
||||
jne cast_test_fail
|
||||
cmp npcWalkArt3D.pixels,0
|
||||
jne cast_test_fail
|
||||
cmp npcWalkLeftArt3D.pixels,0
|
||||
jne cast_test_fail
|
||||
cmp bwMotionArt3D.pixels,0
|
||||
jne cast_test_fail
|
||||
cmp bwSeatedArt3D.pixels,0
|
||||
jne cast_test_fail
|
||||
mov playerX,16*FP_1
|
||||
mov playerY,20*FP_1
|
||||
mov playerAngle,384
|
||||
mov viewEye3D,HALL_STANDING_EYE
|
||||
mov viewHorizon3D,HALF_H
|
||||
call UpdateCamera3D
|
||||
xor esi,esi
|
||||
mov phase,0
|
||||
cast_test_identity:
|
||||
xor edi,edi
|
||||
cast_test_action:
|
||||
invoke ConfigureCharacter3D,OFFSET castTestObject,esi,edi,99999,FP_1,0
|
||||
mov eax,castTestObject.frame
|
||||
xor edx,edx
|
||||
mov ecx,CAST_STRIDE
|
||||
div ecx
|
||||
cmp eax,esi
|
||||
jne cast_test_fail
|
||||
cmp castTestObject.asset,OFFSET characterCast3D
|
||||
jne cast_test_fail
|
||||
cmp castTestObject.worldH,CAST_HEIGHT
|
||||
jne cast_test_fail
|
||||
inc edi
|
||||
cmp edi,12
|
||||
jb cast_test_action
|
||||
xor edi,edi
|
||||
cast_test_picture:
|
||||
invoke DrawBox,0,0,SCREEN_W,SCREEN_H,001C2228h
|
||||
lea edi,zBuffer
|
||||
mov eax,7FFFFFFFh
|
||||
mov ecx,SCREEN_W
|
||||
rep stosd
|
||||
lea edi,cityDepthBuffer3D
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep stosd
|
||||
mov edi,phase
|
||||
mov eax,castTestActions[edi*4]
|
||||
mov time,eax
|
||||
mov vx,0
|
||||
mov vy,0
|
||||
cmp edi,1
|
||||
jne @F
|
||||
mov vy,-FP_1
|
||||
@@:
|
||||
cmp edi,2
|
||||
jne @F
|
||||
mov vx,FP_1
|
||||
@@:
|
||||
invoke ConfigureCharacter3D,OFFSET castTestObject,esi,time,castTestClocks[edi*4],vx,vy
|
||||
invoke DrawCityObject3D,OFFSET castTestObject,0
|
||||
imul ebx,esi,6
|
||||
add ebx,phase
|
||||
invoke ExpansionSnapshot,castTestPaths[ebx*4]
|
||||
inc phase
|
||||
cmp phase,6
|
||||
jb cast_test_picture
|
||||
mov phase,0
|
||||
cast_test_walking:
|
||||
invoke DrawBox,0,0,SCREEN_W,SCREEN_H,001C2228h
|
||||
lea edi,zBuffer
|
||||
mov eax,7FFFFFFFh
|
||||
mov ecx,SCREEN_W
|
||||
rep stosd
|
||||
lea edi,cityDepthBuffer3D
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep stosd
|
||||
imul eax,phase,FP_1*3/32
|
||||
invoke ConfigureCharacter3D,OFFSET castTestObject,esi,CAST_WALK,eax,FP_1,0
|
||||
invoke DrawCityObject3D,OFFSET castTestObject,0
|
||||
imul ebx,esi,8
|
||||
add ebx,phase
|
||||
invoke ExpansionSnapshot,castWalkPaths[ebx*4]
|
||||
inc phase
|
||||
cmp phase,8
|
||||
jb cast_test_walking
|
||||
inc esi
|
||||
mov phase,0
|
||||
cmp esi,CAST_COUNT
|
||||
jb cast_test_identity
|
||||
ret
|
||||
cast_test_fail:
|
||||
invoke ExitProcess,expansionStage
|
||||
ret
|
||||
CharacterCastNativeTests ENDP
|
||||
63
tools/tests/check_character_cast.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"""Shared sprite invariants and real MASM framebuffer captures."""
|
||||
from pathlib import Path
|
||||
import json
|
||||
import struct
|
||||
from PIL import Image, ImageChops
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUT = ROOT/'build/hall-expansion'
|
||||
|
||||
|
||||
def check():
|
||||
manifest = json.loads((ROOT/'assets/sprites/characters/cast-v1.json').read_text())
|
||||
raw = (ROOT/'assets/animations/characters/cast-v1.bin').read_bytes()
|
||||
magic,w,h,count,size = struct.unpack_from('<4s4I',raw)
|
||||
assert (magic,w,h,count) == (b'ANM1',192,224,1000)
|
||||
assert size == len(raw)-20 == w*h*count*4
|
||||
assert len(manifest['characters']) == 10 and manifest['stride'] == 100
|
||||
def frame(n):
|
||||
offset = 20+n*w*h*4
|
||||
return Image.frombytes('RGBA',(w,h),raw[offset:offset+w*h*4],'raw','BGRA')
|
||||
assert len({frame(i*100).tobytes() for i in range(10)}) == 10
|
||||
roster = Image.new('RGB',(320*5,240*2),(28,34,40))
|
||||
for identity in range(10):
|
||||
start = identity*100
|
||||
standing = frame(start).getbbox()
|
||||
seated = frame(start+12).getbbox()
|
||||
assert seated[3]-seated[1] < (standing[3]-standing[1])*.87,(identity,'seated body resized')
|
||||
for offset in range(100):
|
||||
box = frame(start+offset).getbbox()
|
||||
assert box and box[0] > 0 and box[2] < w and box[3] <= 222,(identity,offset,box)
|
||||
for direction in (24,32,40,48):
|
||||
poses = [frame(start+direction+i) for i in range(8)]
|
||||
assert len({p.crop((0,120,w,h)).tobytes() for p in poses}) == 8,(identity,direction,'frozen legs')
|
||||
# Distinct hashes alone missed the old repeated wide-stride source poses.
|
||||
spans = []
|
||||
for index in range(8):
|
||||
box = frame(start+40+index).getchannel('A').crop((0,180,w,h)).getbbox()
|
||||
spans.append(box[2]-box[0])
|
||||
assert max(spans)-min(spans) > 55,(identity,'missing passing pose',spans)
|
||||
for i in range(8):
|
||||
assert frame(start+40+i).transpose(Image.Transpose.FLIP_LEFT_RIGHT).tobytes() == frame(start+48+i).tobytes()
|
||||
assert len({frame(start+72+i).tobytes() for i in range(24)}) >= 20
|
||||
for action in range(6):
|
||||
native = Image.open(OUT/f'cast-{identity}-{action}.bmp').convert('RGB')
|
||||
bg = Image.new('RGB',native.size,(28,34,40))
|
||||
assert ImageChops.difference(native,bg).getbbox(),(identity,action,'blank native pose')
|
||||
if action == 0:
|
||||
box = ImageChops.difference(native,bg).getbbox()
|
||||
assert 100 <= box[3]-box[1] <= 170 and 215 <= box[1] <= 250,(identity,'visitor scale',box)
|
||||
native.save(OUT/f'cast-{identity}-{action}.png')
|
||||
if action == 0:
|
||||
native = native.resize((320,240),Image.Resampling.LANCZOS)
|
||||
roster.paste(native,((identity%5)*320,(identity//5)*240))
|
||||
walking = [Image.open(OUT/f'cast-walk-{identity}-{phase}.bmp').convert('RGB') for phase in range(8)]
|
||||
assert len({im.tobytes() for im in walking}) == 8,(identity,'native frozen gait')
|
||||
walking[0].save(OUT/f'cast-walk-{identity}.gif',save_all=True,
|
||||
append_images=walking[1:],duration=110,loop=0)
|
||||
roster.save(OUT/'cast-native-roster.png')
|
||||
print('PASS: ten identities, contact/passing gait, eye-level scale, 60 poses and 80 native walking frames')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
check()
|
||||
|
|
@ -8,6 +8,7 @@ import subprocess
|
|||
from PIL import Image, ImageStat, ImageChops
|
||||
from check_card_exit_build import Coff
|
||||
from check_terminals import signature
|
||||
from check_character_cast import check as check_character_cast
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUT = ROOT / "build/hall-expansion"
|
||||
|
|
@ -38,6 +39,9 @@ def prepare():
|
|||
code += "\n" + read("src_graphics/fortune_room.inc")
|
||||
code += "\n" + read("src_graphics/fortune_dialog.inc")
|
||||
code += "\n" + expand("src_graphics/rooftop.inc")
|
||||
code += "\n" + expand("src_graphics/bowling.inc")
|
||||
code += "\n" + read("src_graphics/character_cast.inc")
|
||||
code += "\n" + proc(read("src_graphics/scene_animation.inc"),"LoadAnimPack3D")
|
||||
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")
|
||||
|
|
@ -65,7 +69,8 @@ def prepare():
|
|||
data = "\n".join(expand(path) for path in ("src_graphics/hall_expansion_data.inc",
|
||||
"src_graphics/cabaret_data.inc","src_graphics/hall_layout.inc",
|
||||
"src_graphics/fortune_room_data.inc","src_graphics/fortune_dialog_data.inc",
|
||||
"src_graphics/observer_data.inc","src_graphics/rooftop_data.inc")) + "\n.data\n" + npc
|
||||
"src_graphics/observer_data.inc","src_graphics/rooftop_data.inc",
|
||||
"src_graphics/bowling_data.inc","src_graphics/character_cast_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)
|
||||
|
|
@ -205,9 +210,48 @@ def check_rooftop_navigation():
|
|||
print(f"PASS: dense rooftop, {count} seats, {len(reached)} connected native walk points, lift/bar return and camera restore")
|
||||
|
||||
|
||||
def check_bowling_room():
|
||||
for name, count in (("materials",14),):
|
||||
raw = (ROOT/f"assets/animations/bowling/{name}-v1.bin").read_bytes()
|
||||
magic,w,h,frames,payload = struct.unpack_from("<4s4I",raw)
|
||||
assert (magic,w,h,frames) == (b"ANM1",256,256,count)
|
||||
assert len(raw) == payload+20 and payload == w*h*frames*4
|
||||
layout = json.loads((ROOT/"assets/sprites/bowling/packed-v1.json").read_text())
|
||||
def clear(x,y):
|
||||
if not (1.2 <= x <= 30.8 and 1.2 <= y <= 30.8):
|
||||
return False
|
||||
if 2 <= x <= 17.3 and y < 22.3:
|
||||
return False
|
||||
return not any(a <= x <= b and c <= y <= d for a,b,c,d in layout["collisions"])
|
||||
start = (68,120)
|
||||
reached,pending = {start},[start]
|
||||
while pending:
|
||||
x,y = pending.pop()
|
||||
for a,b in ((x-1,y),(x+1,y),(x,y-1),(x,y+1)):
|
||||
if (a,b) not in reached and clear(a/4,b/4):
|
||||
reached.add((a,b))
|
||||
pending.append((a,b))
|
||||
for x,y in ((18,24),(27,6),(22,10.5),(27,16.5)):
|
||||
assert (int(x*4),int(y*4)) in reached,(x,y,"disconnected room area")
|
||||
for i in (0,1,2,3,9):
|
||||
x,y,_ = layout["seats"][i]
|
||||
assert any((a/4-x)**2+(b/4-y)**2 < 1.8**2 for a,b in reached),(i,"unreachable seat")
|
||||
captures = []
|
||||
for path in OUT.glob("bowling-*.bmp"):
|
||||
im = Image.open(path).convert("RGB")
|
||||
assert max(ImageStat.Stat(im).stddev) > 20,(path,"blank room capture")
|
||||
im.save(path.with_suffix('.png'))
|
||||
captures.append(path)
|
||||
throws = [Image.open(OUT/f"bowling-throw-{i}.bmp").tobytes() for i in range(4)]
|
||||
assert len(set(throws)) == 4,"whole-body throw must visibly progress"
|
||||
assert len(captures) >= 10
|
||||
print(f"PASS: eight bowling lanes, {len(reached)} connected walk points, reachable bar/dining/seats, native throw and room captures")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--parity",action="store_true")
|
||||
parser.add_argument("--bowling-only",action="store_true")
|
||||
parser.add_argument("--prove-alpha-regression",action="store_true")
|
||||
parser.add_argument("--prove-seam-regression",action="store_true")
|
||||
parser.add_argument("--prove-distance-regression",action="store_true")
|
||||
|
|
@ -231,6 +275,14 @@ def main():
|
|||
assert "DrawCityObject3D" not in room, "tarot furniture must not face the camera"
|
||||
assert room.count("DrawFortuneFixedProp3D") == 24
|
||||
stem = "module"
|
||||
if args.bowling_only:
|
||||
stem = "module-bowling"
|
||||
source = (OUT/"module.asm").read_text(encoding="cp1251")
|
||||
source = source.replace("include tools/tests/hall_expansion_test.inc",
|
||||
expand("tools/tests/hall_expansion_test.inc"))
|
||||
source = source.replace(" call LoadHallAssets3D\n cmp characterCast3D.pixels,0",
|
||||
" call LoadHallAssets3D\n call BowlingNativeTests\n invoke ExitProcess,0\n cmp characterCast3D.pixels,0")
|
||||
(OUT/(stem+".asm")).write_text(source,encoding="cp1251")
|
||||
if args.prove_fate_anchor_regression:
|
||||
stem = "module-fate-anchor-regression"
|
||||
source = (OUT/"module.asm").read_text(encoding="cp1251")
|
||||
|
|
@ -282,10 +334,17 @@ def main():
|
|||
f"/Fobuild/hall-expansion/{stem}.obj",f"build/hall-expansion/{stem}.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:ExpansionTestStart@0",
|
||||
f"/MAP:build/hall-expansion/{stem}.map",
|
||||
f"/LIBPATH:{sdk}",f"/LIBPATH:{masm/'lib'}",f"/OUT:build/hall-expansion/{stem}.exe",
|
||||
f"build/hall-expansion/{stem}.obj","build/hall-expansion/helpers.obj",
|
||||
"kernel32.lib","user32.lib","gdi32.lib","winmm.lib","ws2_32.lib"],cwd=ROOT,check=True)
|
||||
result = subprocess.run([str(OUT/(stem+".exe"))],cwd=ROOT,timeout=360)
|
||||
if args.bowling_only:
|
||||
assert result.returncode == 0,result.returncode
|
||||
check_bowling_room()
|
||||
check_character_cast()
|
||||
print("PASS: native bowling entrance, collisions, seating, scoring, lane lifecycles and captured room/throw frames")
|
||||
return
|
||||
if args.prove_fate_anchor_regression:
|
||||
assert result.returncode == 81,result.returncode
|
||||
print("PASS: restoring fixed screen coordinates fails the native crystal-ball tracking assertions")
|
||||
|
|
@ -305,6 +364,8 @@ def main():
|
|||
assert result.returncode == 0,f"native case {result.returncode}"
|
||||
if not args.prove_seam_regression:
|
||||
check_rooftop_navigation()
|
||||
check_bowling_room()
|
||||
check_character_cast()
|
||||
closed = Image.open(OUT/"fortune-closed.bmp").tobytes()
|
||||
opened = Image.open(OUT/"fortune-open.bmp").tobytes()
|
||||
assert closed != opened, "secret panel must visibly reveal the stairwell"
|
||||
|
|
@ -457,10 +518,7 @@ def main():
|
|||
pull = Image.open(OUT/"lever-mid-pull.bmp").crop((200,330,250,480)).tobytes()
|
||||
release = Image.open(OUT/"lever-mid-release.bmp").crop((200,330,250,480)).tobytes()
|
||||
assert pull != release, "left handle must visibly return while right remains enabled"
|
||||
for name,expected in (("guest-cast-v1.bin",(128,224,36)),
|
||||
("guest-walk-v2.bin",(128,224,48)),
|
||||
("guest-walk-left-v2.bin",(128,224,48)),
|
||||
("basement-door-v2.bin",(256,512,18)),
|
||||
for name,expected in (("basement-door-v2.bin",(256,512,18)),
|
||||
("cabaret-ensemble-v1.bin",(160,256,12)),
|
||||
("cabaret-piano-v1.bin",(384,256,4)),
|
||||
("cabaret-guitar-v1.bin",(160,256,4)),
|
||||
|
|
@ -477,17 +535,6 @@ def main():
|
|||
assert magic == b"ANM1" and (w,h,count) == expected
|
||||
assert size == w*h*count*4 == len(raw)-20
|
||||
frames = [raw[20+i*w*h*4:20+(i+1)*w*h*4] for i in range(count)]
|
||||
if name == "guest-cast-v1.bin":
|
||||
assert len(set(frames[::6])) == 6, "all six guest appearances must differ"
|
||||
if name == "guest-walk-v2.bin":
|
||||
for appearance in range(6):
|
||||
poses = [Image.frombytes("RGBA",(w,h),frame,"raw","BGRA")
|
||||
for frame in frames[appearance*8:appearance*8+8]]
|
||||
assert len({pose.crop((0,120,128,224)).tobytes() for pose in poses}) == 8
|
||||
assert all(pose.getbbox()[3] == 224 for pose in poses), "supporting foot must touch baseline"
|
||||
mirrored = (ROOT / "assets/animations/hall/guest-walk-left-v2.bin").read_bytes()[20:]
|
||||
assert all(Image.frombytes("RGBA",(w,h),frames[i],"raw","BGRA").transpose(
|
||||
Image.Transpose.FLIP_LEFT_RIGHT).tobytes("raw","BGRA") == mirrored[i*w*h*4:(i+1)*w*h*4] for i in range(48))
|
||||
if name == "basement-door-v2.bin":
|
||||
assert len(set(frames[:17])) == 17, "separate rotating handwheel phases"
|
||||
assert all(frame[:200*256*4] == frames[0][:200*256*4] for frame in frames[:17]), "leaf stays rigid while unlocking"
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ ExpansionFrame PROC
|
|||
call UpdateCamera3D
|
||||
cmp hallLevel3D,HALL_ROOF
|
||||
je expansion_world_ready
|
||||
cmp hallLevel3D,HALL_BOWLING
|
||||
je expansion_world_ready
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
|
|
@ -140,11 +142,9 @@ ExpansionTestStart PROC
|
|||
call InitializeCasinoSprites3D
|
||||
call InitHall3D
|
||||
call LoadHallAssets3D
|
||||
cmp npcGuestArt3D.pixels,0
|
||||
cmp characterCast3D.pixels,0
|
||||
je expansion_fail
|
||||
cmp npcWalkArt3D.frames,48
|
||||
jne expansion_fail
|
||||
cmp npcWalkLeftArt3D.frames,48
|
||||
cmp characterCast3D.frames,CAST_COUNT*CAST_STRIDE
|
||||
jne expansion_fail
|
||||
cmp basementDoorArt3D.frames,18
|
||||
jne expansion_fail
|
||||
|
|
@ -898,6 +898,7 @@ expansion_gait_hide:
|
|||
jb expansion_gait_hide
|
||||
mov npcLife3D.state,NPC_WALK
|
||||
mov npcLife3D.identity,0
|
||||
mov npcRise3D,0
|
||||
mov casinoNpcs3D.posX,FP_1*165/10
|
||||
mov casinoNpcs3D.posY,FP_1*175/10
|
||||
mov npcWalkVelocityX3D,FP_1
|
||||
|
|
@ -916,6 +917,7 @@ expansion_gait_frame:
|
|||
call PrepareCityDepth3D
|
||||
call RenderNpcLife3D
|
||||
mov eax,npcSprite3D.frame
|
||||
sub eax,40
|
||||
cmp eax,esi
|
||||
jne expansion_fail
|
||||
invoke ExpansionSnapshot,expansionGaitPaths[esi*4]
|
||||
|
|
@ -925,7 +927,9 @@ expansion_gait_frame:
|
|||
mov npcWalkVelocityX3D,-FP_1
|
||||
call PrepareCityDepth3D
|
||||
call RenderNpcLife3D
|
||||
cmp npcSprite3D.asset,OFFSET npcWalkLeftArt3D
|
||||
cmp npcSprite3D.asset,OFFSET characterCast3D
|
||||
jne expansion_fail
|
||||
cmp npcSprite3D.frame,55
|
||||
jne expansion_fail
|
||||
mov expansionStage,32
|
||||
mov engineMode,MODE_STAIRS
|
||||
|
|
@ -1170,6 +1174,7 @@ expansion_leaf_shut:
|
|||
call FortuneDialogNativeTests
|
||||
call ExpansionDartsTests
|
||||
call RoofNativeTests
|
||||
call BowlingNativeTests
|
||||
invoke ExitProcess,0
|
||||
expansion_fail:
|
||||
invoke ExitProcess,expansionStage
|
||||
|
|
@ -1180,3 +1185,5 @@ include tools/tests/bar_camera_test.inc
|
|||
include tools/tests/fortune_dialog_test.inc
|
||||
include tools/tests/darts_hall_test.inc
|
||||
include tools/tests/rooftop_test.inc
|
||||
include tools/tests/bowling_test.inc
|
||||
include tools/tests/character_cast_test.inc
|
||||
|
|
|
|||